bgp_open(struct bgp_proto *p)
{
/* Interface-patterned listening sockets are created from the
- * interface notifier. By default, listen to nothing. */
- if (p->cf->ipatt)
+ * interface notifier. By default, listen to nothing.
+ *
+ * Also dynamically spawned protocol do not need a listening socket,
+ * they already have their parent's one. */
+ if (p->cf->ipatt || p->cf->c.parent)
return 0;
- /* We assume that cf->iface is defined iff cf->local_ip is link-local */
+ /* Set parameters of the listening socket
+ *
+ * If strict_bind is set, we need local_ip and maybe also iface. Mandatory if
+ * local_ip is link-local. If strict_bind is not set, we bind to all addresses
+ * of that family and match the local IP later when accepting the connection. */
+
struct bgp_listen_request *req = mb_allocz(p->p.pool, sizeof *req);
- req->params = (struct bgp_socket_params) {
- .iface = p->cf->strict_bind ? p->cf->iface : NULL,
- .vrf = p->p.vrf,
- .addr = p->cf->strict_bind && ipa_nonzero(p->cf->local_ip) ? p->cf->local_ip :
- (p->ipv4 ? IPA_NONE4 : IPA_NONE6),
- .port = p->cf->local_port,
- .flags = p->cf->free_bind ? SKF_FREEBIND : 0,
- };
+ struct bgp_socket_params *par = &req->params;
- par->addr = p->cf->strict_bind ? p->cf->local_ip :
+ par->iface = p->cf->strict_bind ? p->cf->iface : NULL;
+ par->vrf = p->p.vrf;
++ par->addr = p->cf->strict_bind && ipa_nonzero(p->cf->local_ip) ? p->cf->local_ip :
+ (p->ipv4 ? IPA_NONE4 : IPA_NONE6);
+ par->port = p->cf->local_port;
+ par->flags = p->cf->free_bind ? SKF_FREEBIND : 0;
+
+ /* Set parameters of the accepted socket */
+ req->local_ip = p->cf->local_ip;
+ req->iface = p->cf->iface;
+ req->remote_ip = p->remote_ip;
+ req->remote_range = p->cf->remote_range;
+
+ /* Initialize the incoming socket queue */
+ init_list(&req->incoming_sockets);
+
+ BGP_TRACE(D_EVENTS, "Requesting listen socket at %I%J port %u", req->params.addr, req->params.iface, req->params.port);
+
+ if (bgp_is_dynamic(p))
+ callback_init(&req->incoming_connection, bgp_incoming_connection_dynamic, &main_birdloop);
+ else
+ callback_init(&req->incoming_connection, bgp_incoming_connection_single, p->p.loop);
+
+ req->p = p;
return bgp_listen_open(p, req);
}
pxlen = net_pxlen(p->cf->remote_range);
}
- int rv = 0;
- struct bgp_listen_request *blr; node *nxt;
+ /* Set/reset the MD5 password at all listening sockets */
- struct bgp_listen_request *blr; node *nxt;
+ int rv;
++ struct bgp_listen_request *blr, *failed = NULL; node *nxt;
WALK_LIST2(blr, nxt, p->listen, pn)
+ BGP_SOCKET_LOCKED(blr->sock, bs)
{
- rv = sk_set_md5_auth(blr->sock->sk,
- p->cf->local_ip, prefix, pxlen, p->cf->iface,
- enable ? p->cf->password : NULL, p->cf->setkey);
+ rv = sk_set_md5_auth(bs->sk,
+ p->cf->local_ip, prefix, pxlen, p->cf->iface,
+ enable ? p->cf->password : NULL, p->cf->setkey);
if (rv < 0)
- {
- sk_log_error(blr->sock->sk, p->p.name);
-
- /* When disabling, just continue, there is nothing to salvage */
- if (!enable)
- continue;
+ sk_log_error(bs->sk, p->p.name);
+ }
- return rv;
- /* Trying to rewind from the listening sockets */
- struct bgp_listen_request *failed = blr;
- bool emsg = false;
- WALK_LIST2(blr, nxt, p->listen, pn)
++ if (failed && enable)
++ {
++ /* Trying to rewind from the listening sockets */
++ bool emsg = false;
++ WALK_LIST2(blr, nxt, p->listen, pn)
++ BGP_SOCKET_LOCKED(blr->sock, bs)
+ {
+ if (blr == failed)
- break;
++ continue;
+
- int rrv = sk_set_md5_auth(blr->sock->sk,
++ int rrv = sk_set_md5_auth(bs->sk,
+ p->cf->local_ip, prefix, pxlen, p->cf->iface,
+ NULL, p->cf->setkey);
+
+ if (rrv < 0)
+ {
+ if (!emsg)
+ {
+ log(L_ERR "%s: Trying to rewind MD5 auth failed as well.");
+ emsg = true;
+ }
+
- sk_log_error(blr->sock->sk, p->p.name);
++ sk_log_error(bs->sk, p->p.name);
+ }
+ }
+
- /* One socket failed while enabling, the whole protocol failed. */
- return rv;
- }
++ /* One socket failed while enabling, the whole protocol failed. */
++ return -1;
+ }
}
return 0;
/* Just pass remote_ip to bgp_init() */
struct bgp_config *cf = SKIP_BACK(struct bgp_config, c, sym->proto);
cf->remote_ip = sk->daddr;
+ cf->local_ip = sk->saddr;
cf->iface = sk->iface;
+ cf->ipatt = NULL;
- struct bgp_proto *p = SKIP_BACK(struct bgp_proto, p, proto_spawn(sym->proto, 0));
+ /* Create the protocol disabled initially */
+ SKIP_BACK_DECLARE(struct bgp_proto, p, p, proto_spawn(sym->proto, 1));
+
+ /* Pass the socket */
p->postponed_sk = sk;
- rmove(sk, p->p.pool);
- return 0;
+ /* And enable the protocol */
+ proto_enable(&p->p);
}
void
/* sk->iface is valid only if src or dst address is link-local */
int link = ipa_is_link_local(sk->saddr) || ipa_is_link_local(sk->daddr);
- WALK_LIST(p, proto_list)
- if ((p->p.proto == &proto_bgp) &&
- (ipa_equal(p->remote_ip, sk->daddr) || bgp_is_dynamic(p)) &&
- (!p->cf->remote_range || ipa_in_netX(sk->daddr, p->cf->remote_range)) &&
- (p->p.vrf == sk->vrf) &&
- (p->cf->local_port == sk->sport) &&
- (!link || (p->cf->iface == sk->iface) || p->cf->ipatt && sk->iface && iface_patt_match(p->cf->ipatt, sk->iface, NULL)) &&
- (ipa_zero(p->cf->local_ip) || ipa_equal(p->cf->local_ip, sk->saddr)))
+ struct bgp_listen_request *req; node *nxt;
+ WALK_LIST2(req, nxt, bs->requests, sn)
+ {
+ if ((ipa_equal(req->remote_ip, sk->daddr) || bgp_is_dynamic(req)) &&
+ (!req->remote_range || ipa_in_netX(sk->daddr, req->remote_range)) &&
+ (req->params.vrf == sk->vrf) &&
+ (req->params.port == sk->sport) &&
- (!link || (req->iface == sk->iface)) &&
++ (!link || (req->iface == sk->iface) || req->ipatt && sk->iface && iface_patt_match(req->ipatt, sk->iface, NULL)) &&
+ (ipa_zero(req->local_ip) || ipa_equal(req->local_ip, sk->saddr)))
{
- best = p;
+ /* Non-dynamic protocol instance matched */
+ if (!bgp_is_dynamic(req))
+ return req;
- if (!bgp_is_dynamic(p))
- break;
+ best = req;
}
+ }
return best;
}
proto_add_channel(P, &cc->c);
/* Add MPLS channel */
- proto_configure_channel(P, &P->mpls_channel, proto_cf_mpls_channel(CF));
+ proto_configure_mpls_channel(P, CF, RTS_BGP);
+
- init_list(&p->listen);
-
+ /* Export public info */
+ ea_list *pes = p->p.ea_state;
+ ea_set_attr(&pes, EA_LITERAL_STORE_ADATA(&ea_bgp_rem_ip, 0, &cf->remote_ip, sizeof(ip_addr)));
+ ea_set_attr(&pes, EA_LITERAL_EMBEDDED(&ea_bgp_peer_type, 0, cf->peer_type));
+ ea_set_attr(&pes, EA_LITERAL_EMBEDDED(&ea_bgp_loc_as, 0, cf->local_as));
+ ea_set_attr(&pes, EA_LITERAL_EMBEDDED(&ea_bgp_rem_as, 0, cf->remote_as));
+ proto_announce_state_later(&p->p, pes);
+
+ p->tbf_mem = (struct tbf) TBF_DEFAULT_LOG_LIMITS;
return P;
}