On Mon, Sep 19, 2022 at 05:44:30PM +0200, Claudio Jeker wrote:
> When running on busy bgpd servers with many clients the function
> pathid_assign() consumes a lot of CPU time. The code does a lookup which
> often fails and then walks the list of prefixes. In the end this is
> results in two list walks.
> 
> This complicated dance is only needed for peers that use add-path but
> regular peers can skip this by assigning a per peer path_id instead.
> To make this work even path_id_txs are for regular peers while the
> add-path peers use even numbers. 
> 
> This should help route collectors and route reflectors that receive the
> same route many times from different sources. At least as long as these
> peers don't use add-path.

ok

Some small suggestions inline.

> -- 
> :wq Claudio
> 
> Index: rde.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/bgpd/rde.c,v
> retrieving revision 1.576
> diff -u -p -r1.576 rde.c
> --- rde.c     12 Sep 2022 10:03:17 -0000      1.576
> +++ rde.c     19 Sep 2022 15:29:19 -0000
> @@ -1607,28 +1607,38 @@ pathid_conflict(struct rib_entry *re, ui
>       return 0;
>  }
>  
> +/*
> + * Assign a send side path_id to all paths.
> + */
>  static uint32_t
>  pathid_assign(struct rde_peer *peer, uint32_t path_id,
>      struct bgpd_addr *prefix, uint8_t prefixlen)
>  {
>       struct rib_entry *re;
> -     struct prefix *p = NULL;
>       uint32_t path_id_tx;
>  
> -     /*
> -      * Assign a send side path_id to all paths.
> -      */
> +     /* If peer has no add-path use the per peer path_id */
> +     if (!peer_has_add_path(peer, prefix->aid, CAPA_AP_RECV))
> +             return peer->path_id_tx;
> +
> +     /* peer uses add-path, therefor new path_ids need to be assigned */

therefore

>       re = rib_get(rib_byid(RIB_ADJ_IN), prefix, prefixlen);
> -     if (re != NULL)
> +     if (re != NULL) {
> +             struct prefix *p;
> +
>               p = prefix_bypeer(re, peer, path_id);
> -     if (p != NULL)
> -             path_id_tx = p->path_id_tx;
> -     else {
> -             do {
> -                     /* assign new local path_id */
> -                     path_id_tx = arc4random();
> -             } while (pathid_conflict(re, path_id_tx));
> +             if (p != NULL)
> +                     return p->path_id_tx;
>       }
> +
> +     do {
> +             /*
> +              * Assign new local path_id, must be an odd number.
> +              * Even numbers are used by the per peer path_id_tx.
> +              */
> +             path_id_tx = (arc4random() << 1) | 1;

I would omit the left shift and just set the lowest bit to 1:

                path_id_tx = arc4random() | 1;

> +     } while (pathid_conflict(re, path_id_tx));
> +
>       return path_id_tx;
>  }
>  
> Index: rde.h
> ===================================================================
> RCS file: /cvs/src/usr.sbin/bgpd/rde.h,v
> retrieving revision 1.271
> diff -u -p -r1.271 rde.h
> --- rde.h     12 Sep 2022 10:03:17 -0000      1.271
> +++ rde.h     19 Sep 2022 15:15:12 -0000
> @@ -99,6 +99,7 @@ struct rde_peer {
>       uint32_t                         remote_bgpid; /* host byte order! */
>       uint32_t                         up_nlricnt;
>       uint32_t                         up_wcnt;
> +     uint32_t                         path_id_tx;
>       enum peer_state                  state;
>       enum export_type                 export_type;
>       uint16_t                         loc_rib_id;
> Index: rde_peer.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/bgpd/rde_peer.c,v
> retrieving revision 1.23
> diff -u -p -r1.23 rde_peer.c
> --- rde_peer.c        1 Sep 2022 13:23:24 -0000       1.23
> +++ rde_peer.c        19 Sep 2022 15:26:34 -0000
> @@ -168,6 +168,22 @@ peer_add(uint32_t id, struct peer_config
>       peer->flags = peer->conf.flags;
>       SIMPLEQ_INIT(&peer->imsg_queue);
>  
> +     /* assign random unique transmit path id */
> +     do {
> +             struct rde_peer *p;
> +             int conflict = 0;

Perhaps explain the left shift with a comment matching the one in
pathid_assign().

> +
> +             peer->path_id_tx = arc4random() << 1;
> +             RB_FOREACH(p, peer_tree, &peertable) {
> +                     if (p->path_id_tx == peer->path_id_tx) {
> +                             conflict = 1;
> +                             break;
> +                     }
> +             }
> +             if (!conflict)
> +                     break;
> +     } while (1);

I'd make conflict a variable of function scope and set it to 0 at the
start of the loop.  Then you can drop the if (!conflict) check and do

        } while (conflict);

> +
>       if (RB_INSERT(peer_tree, &peertable, peer) != NULL)
>               fatalx("rde peer table corrupted");
>  
> 

Reply via email to