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"); > >