]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Merge commit '48bad6834' into 299-mq-bgp-async-listen
authorMaria Matejka <mq@ucw.cz>
Thu, 13 Nov 2025 16:56:28 +0000 (17:56 +0100)
committerMaria Matejka <mq@ucw.cz>
Thu, 13 Nov 2025 16:56:28 +0000 (17:56 +0100)
1  2 
proto/bgp/bgp.c
proto/bgp/bgp.h

diff --cc proto/bgp/bgp.c
index 0147b6f3d78e85533222b3773f8fa107f455ef92,9c50f2d6ee08becc8489dd6b62bd9ae5aebb4e95..bf8fced6a9004e121ba70301393576244006013e
@@@ -197,43 -160,24 +197,46 @@@ static in
  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);
  }
  
@@@ -868,20 -762,51 +871,49 @@@ bgp_setup_auth(struct bgp_proto *p, in
        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;
@@@ -1175,16 -1073,15 +1207,18 @@@ bgp_spawn(struct bgp_proto *pp, struct 
    /* 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
@@@ -1945,23 -1763,20 +1979,23 @@@ bgp_find_proto(struct bgp_socket_privat
    /* 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;
  }
@@@ -2826,20 -2439,8 +2861,18 @@@ bgp_init(struct proto_config *CF
      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;
  }
  
diff --cc proto/bgp/bgp.h
index 0fd50db9960eb163200159490c5c0b7cb9f30d0e,7e70d745b95a2aaea545fea734a7a87c3c29d29b..05795b952cf8c8a36b210f8b90af63b029441774
@@@ -377,39 -361,11 +378,40 @@@ struct bgp_conn 
    uint hold_time, keepalive_time, send_hold_time;     /* Times calculated from my and neighbor's requirements */
  };
  
 +struct bgp_conn_sk_ad {
 +  adata ad;
 +  ip_addr saddr;
 +  ip_addr daddr;
 +  int sport;
 +  int dport;
 +};
 +
 +struct bgp_session_close_ad {
 +  adata ad;
 +  int notify_code;
 +  int notify_subcode;
 +  u8 last_error_class;
 +  byte data[0];
 +};
 +
 +struct bgp_incoming_socket {
 +  node n;             /* Node in bgp_listen_request -> incoming_sockets */
 +  sock *sk;           /* The actual socket */
 +};
 +
  struct bgp_listen_request {
 -  node sn;                            /* Node in bgp_socket list */
 -  node pn;                            /* Node in bgp_proto list */
 -  struct bgp_socket *sock;            /* Assigned socket */
 -  struct bgp_socket_params params;
 +  node pn;                            /* Node in bgp_proto listen list */
 +  node sn;                            /* Node in bgp_socket requests list */
 +  bgp_socket *sock;                   /* Assigned socket */
 +  struct bgp_socket_params params;    /* Listening socket parameters */
 +  ip_addr local_ip;                   /* Local IP address to match */
 +  struct iface *iface;                        /* Local interface to match */
++  struct iface_patt *ipatt;           /* Interface pattern for dynamic strict bind */
 +  ip_addr remote_ip;                  /* Remote IP address to match */
 +  const net_addr *remote_range;               /* Remote IP range to match */
 +  list incoming_sockets;              /* Accepted sockets matched to this request */
 +  callback incoming_connection;               /* Callback for incoming connection */
 +  struct bgp_proto *p;                        /* Requesting protocol */
  };
  
  struct bgp_proto {