Claudio Jeker(cje...@diehard.n-r-g.com) on 2022.09.01 12:04:03 +0200: > Convert the rde_peer hash table to an RB tree. This is a bit more complex > because rde_peer list is used in a lot of places. As a bonus use > peer_foreach in mrt.c to write the table v2 peer header (this needs a > special callback struct because two values need to be passed to the > callback). > > The rest of the code is mostly a simple conversion. Only peer_match > required to be adjusted because the code is now able to use peer_get() > to find the start point. > -- > :wq Claudio
ok benno@ > > Index: mrt.c > =================================================================== > RCS file: /cvs/src/usr.sbin/bgpd/mrt.c,v > retrieving revision 1.109 > diff -u -p -r1.109 mrt.c > --- mrt.c 17 Aug 2022 15:15:26 -0000 1.109 > +++ mrt.c 1 Sep 2022 00:25:24 -0000 > @@ -783,14 +783,33 @@ fail: > return (-1); > } > > +struct cb_arg { > + struct ibuf *buf; > + int nump; > +}; > + > +static void > +mrt_dump_v2_hdr_peer(struct rde_peer *peer, void *arg) > +{ > + struct cb_arg *a = arg; > + > + if (a->nump == -1) > + return; > + peer->mrt_idx = a->nump; > + if (mrt_dump_peer(a->buf, peer) == -1) { > + a->nump = -1; > + return; > + } > + a->nump++; > +} > + > int > -mrt_dump_v2_hdr(struct mrt *mrt, struct bgpd_config *conf, > - struct rde_peer_head *ph) > +mrt_dump_v2_hdr(struct mrt *mrt, struct bgpd_config *conf) > { > - struct rde_peer *peer; > struct ibuf *buf, *hbuf = NULL; > size_t len, off; > uint16_t nlen, nump; > + struct cb_arg arg; > > if ((buf = ibuf_dynamic(0, UINT_MAX)) == NULL) { > log_warn("%s: ibuf_dynamic", __func__); > @@ -812,14 +831,13 @@ mrt_dump_v2_hdr(struct mrt *mrt, struct > log_warn("%s: ibuf_reserve error", __func__); > goto fail; > } > - nump = 0; > - LIST_FOREACH(peer, ph, peer_l) { > - peer->mrt_idx = nump; > - if (mrt_dump_peer(buf, peer) == -1) > - goto fail; > - nump++; > - } > - nump = htons(nump); > + arg.nump = 0; > + arg.buf = buf; > + peer_foreach(mrt_dump_v2_hdr_peer, &arg); > + if (arg.nump == -1) > + goto fail; > + > + nump = htons(arg.nump); > memcpy(ibuf_seek(buf, off, sizeof(nump)), &nump, sizeof(nump)); > > len = ibuf_size(buf); > Index: rde.c > =================================================================== > RCS file: /cvs/src/usr.sbin/bgpd/rde.c,v > retrieving revision 1.573 > diff -u -p -r1.573 rde.c > --- rde.c 31 Aug 2022 15:51:44 -0000 1.573 > +++ rde.c 1 Sep 2022 08:29:31 -0000 > @@ -114,8 +114,8 @@ struct rde_memstats rdemem; > int softreconfig; > static int rde_eval_all; > > -extern struct rde_peer_head peerlist; > -extern struct rde_peer *peerself; > +extern struct peer_tree peertable; > +extern struct rde_peer *peerself; > > struct rde_dump_ctx { > LIST_ENTRY(rde_dump_ctx) entry; > @@ -145,8 +145,6 @@ rde_sighdlr(int sig) > } > } > > -uint32_t peerhashsize = 1024; > - > void > rde_main(int debug, int verbose) > { > @@ -194,7 +192,7 @@ rde_main(int debug, int verbose) > > /* initialize the RIB structures */ > pt_init(); > - peer_init(peerhashsize); > + peer_init(); > > /* make sure the default RIBs are setup */ > rib_new("Adj-RIB-In", 0, F_RIB_NOFIB | F_RIB_NOEVALUATE); > @@ -2982,7 +2980,7 @@ rde_dump_mrt_new(struct mrt *mrt, pid_t > } > > if (ctx->mrt.type == MRT_TABLE_DUMP_V2) > - mrt_dump_v2_hdr(&ctx->mrt, conf, &peerlist); > + mrt_dump_v2_hdr(&ctx->mrt, conf); > > if (rib_dump_new(rid, AID_UNSPEC, CTL_MSG_HIGH_MARK, &ctx->mrt, > mrt_dump_upcall, rde_mrt_done, rde_mrt_throttled) == -1) > @@ -3105,7 +3103,7 @@ rde_update_queue_pending(void) > if (ibuf_se && ibuf_se->w.queued >= SESS_MSG_HIGH_MARK) > return 0; > > - LIST_FOREACH(peer, &peerlist, peer_l) { > + RB_FOREACH(peer, peer_tree, &peertable) { > if (peer->conf.id == 0) > continue; > if (peer->state != PEER_UP) > @@ -3131,7 +3129,7 @@ rde_update_queue_runner(void) > len = sizeof(queue_buf) - MSGSIZE_HEADER; > do { > sent = 0; > - LIST_FOREACH(peer, &peerlist, peer_l) { > + RB_FOREACH(peer, peer_tree, &peertable) { > if (peer->conf.id == 0) > continue; > if (peer->state != PEER_UP) > @@ -3189,7 +3187,7 @@ rde_update6_queue_runner(uint8_t aid) > /* first withdraws ... */ > do { > sent = 0; > - LIST_FOREACH(peer, &peerlist, peer_l) { > + RB_FOREACH(peer, peer_tree, &peertable) { > if (peer->conf.id == 0) > continue; > if (peer->state != PEER_UP) > @@ -3214,7 +3212,7 @@ rde_update6_queue_runner(uint8_t aid) > max = RDE_RUNNER_ROUNDS / 2; > do { > sent = 0; > - LIST_FOREACH(peer, &peerlist, peer_l) { > + RB_FOREACH(peer, peer_tree, &peertable) { > if (peer->conf.id == 0) > continue; > if (peer->state != PEER_UP) > @@ -3447,7 +3445,7 @@ rde_reload_done(void) > rde_eval_all = 0; > > /* check if filter changed */ > - LIST_FOREACH(peer, &peerlist, peer_l) { > + RB_FOREACH(peer, peer_tree, &peertable) { > if (peer->conf.id == 0) /* ignore peerself */ > continue; > peer->reconf_out = 0; > @@ -3533,7 +3531,7 @@ rde_reload_done(void) > break; > case RECONF_RELOAD: > if (rib_update(rib)) { > - LIST_FOREACH(peer, &peerlist, peer_l) { > + RB_FOREACH(peer, peer_tree, &peertable) { > /* ignore peerself */ > if (peer->conf.id == 0) > continue; > @@ -3644,7 +3642,7 @@ rde_softreconfig_in_done(void *arg, uint > } > } > > - LIST_FOREACH(peer, &peerlist, peer_l) { > + RB_FOREACH(peer, peer_tree, &peertable) { > uint8_t aid; > > if (peer->reconf_out) { > Index: rde.h > =================================================================== > RCS file: /cvs/src/usr.sbin/bgpd/rde.h,v > retrieving revision 1.268 > diff -u -p -r1.268 rde.h > --- rde.h 31 Aug 2022 14:29:36 -0000 1.268 > +++ rde.h 1 Sep 2022 08:16:31 -0000 > @@ -70,15 +70,13 @@ struct rib { > * How do we identify peers between the session handler and the rde? > * Currently I assume that we can do that with the neighbor_ip... > */ > -LIST_HEAD(rde_peer_head, rde_peer); > -LIST_HEAD(attr_list, attr); > +RB_HEAD(peer_tree, rde_peer); > RB_HEAD(prefix_tree, prefix); > RB_HEAD(prefix_index, prefix); > struct iq; > > struct rde_peer { > - LIST_ENTRY(rde_peer) hash_l; /* hash list over all peers */ > - LIST_ENTRY(rde_peer) peer_l; /* list of all peers */ > + RB_ENTRY(rde_peer) entry; > SIMPLEQ_HEAD(, iq) imsg_queue; > struct peer_config conf; > struct bgpd_addr remote_addr; > @@ -375,8 +373,7 @@ extern struct rde_memstats rdemem; > > /* prototypes */ > /* mrt.c */ > -int mrt_dump_v2_hdr(struct mrt *, struct bgpd_config *, > - struct rde_peer_head *); > +int mrt_dump_v2_hdr(struct mrt *, struct bgpd_config *); > void mrt_dump_upcall(struct rib_entry *, void *); > > /* rde.c */ > @@ -404,7 +401,7 @@ int peer_has_as4byte(struct rde_peer * > int peer_has_add_path(struct rde_peer *, uint8_t, int); > int peer_has_open_policy(struct rde_peer *, uint8_t *); > int peer_accept_no_as_set(struct rde_peer *); > -void peer_init(uint32_t); > +void peer_init(void); > void peer_shutdown(void); > void peer_foreach(void (*)(struct rde_peer *, void *), void *); > struct rde_peer *peer_get(uint32_t); > @@ -422,6 +419,8 @@ void peer_imsg_push(struct rde_peer *, > int peer_imsg_pop(struct rde_peer *, struct imsg *); > int peer_imsg_pending(void); > void peer_imsg_flush(struct rde_peer *); > + > +RB_PROTOTYPE(peer_tree, rde_peer, entry, peer_cmp); > > /* rde_attr.c */ > int attr_write(void *, uint16_t, uint8_t, uint8_t, void *, > Index: rde_peer.c > =================================================================== > RCS file: /cvs/src/usr.sbin/bgpd/rde_peer.c,v > retrieving revision 1.22 > diff -u -p -r1.22 rde_peer.c > --- rde_peer.c 26 Aug 2022 14:10:52 -0000 1.22 > +++ rde_peer.c 1 Sep 2022 09:44:57 -0000 > @@ -26,15 +26,7 @@ > #include "bgpd.h" > #include "rde.h" > > -struct peer_table { > - struct rde_peer_head *peer_hashtbl; > - uint32_t peer_hashmask; > -} peertable; > - > -#define PEER_HASH(x) \ > - &peertable.peer_hashtbl[(x) & peertable.peer_hashmask] > - > -struct rde_peer_head peerlist; > +struct peer_tree peertable; > struct rde_peer *peerself; > > CTASSERT(sizeof(peerself->recv_eor) * 8 > AID_MAX); > @@ -82,22 +74,11 @@ peer_accept_no_as_set(struct rde_peer *p > } > > void > -peer_init(uint32_t hashsize) > +peer_init(void) > { > struct peer_config pc; > - uint32_t hs, i; > - > - for (hs = 1; hs < hashsize; hs <<= 1) > - ; > - peertable.peer_hashtbl = calloc(hs, sizeof(struct rde_peer_head)); > - if (peertable.peer_hashtbl == NULL) > - fatal("peer_init"); > - > - for (i = 0; i < hs; i++) > - LIST_INIT(&peertable.peer_hashtbl[i]); > - LIST_INIT(&peerlist); > > - peertable.peer_hashmask = hs - 1; > + RB_INIT(&peertable); > > memset(&pc, 0, sizeof(pc)); > snprintf(pc.descr, sizeof(pc.descr), "LOCAL"); > @@ -110,13 +91,8 @@ peer_init(uint32_t hashsize) > void > peer_shutdown(void) > { > - uint32_t i; > - > - for (i = 0; i <= peertable.peer_hashmask; i++) > - if (!LIST_EMPTY(&peertable.peer_hashtbl[i])) > - log_warnx("peer_free: free non-free table"); > - > - free(peertable.peer_hashtbl); > + if (!RB_EMPTY(&peertable)) > + log_warnx("%s: free non-free table", __func__); > } > > /* > @@ -127,7 +103,7 @@ peer_foreach(void (*callback)(struct rde > { > struct rde_peer *peer, *np; > > - LIST_FOREACH_SAFE(peer, &peerlist, peer_l, np) > + RB_FOREACH_SAFE(peer, peer_tree, &peertable, np) > callback(peer, arg); > } > > @@ -137,16 +113,10 @@ peer_foreach(void (*callback)(struct rde > struct rde_peer * > peer_get(uint32_t id) > { > - struct rde_peer_head *head; > - struct rde_peer *peer; > + struct rde_peer needle; > > - head = PEER_HASH(id); > - > - LIST_FOREACH(peer, head, hash_l) { > - if (peer->conf.id == id) > - return (peer); > - } > - return (NULL); > + needle.conf.id = id; > + return RB_FIND(peer_tree, &peertable, &needle); > } > > /* > @@ -157,28 +127,18 @@ peer_get(uint32_t id) > struct rde_peer * > peer_match(struct ctl_neighbor *n, uint32_t peerid) > { > - struct rde_peer_head *head; > struct rde_peer *peer; > - uint32_t i = 0; > > - if (peerid != 0) > - i = peerid & peertable.peer_hashmask; > + if (peerid != 0) { > + peer = peer_get(peerid); > + if (peer) > + peer = RB_NEXT(peer_tree, &peertable, peer); > + } else > + peer = RB_MIN(peer_tree, &peertable); > > - while (i <= peertable.peer_hashmask) { > - head = &peertable.peer_hashtbl[i]; > - LIST_FOREACH(peer, head, hash_l) { > - /* skip peers until peerid is found */ > - if (peerid == peer->conf.id) { > - peerid = 0; > - continue; > - } > - if (peerid != 0) > - continue; > - > - if (rde_match_peer(peer, n)) > - return (peer); > - } > - i++; > + for (; peer != NULL; peer = RB_NEXT(peer_tree, &peertable, peer)) { > + if (rde_match_peer(peer, n)) > + return (peer); > } > return (NULL); > } > @@ -186,7 +146,6 @@ peer_match(struct ctl_neighbor *n, uint3 > struct rde_peer * > peer_add(uint32_t id, struct peer_config *p_conf) > { > - struct rde_peer_head *head; > struct rde_peer *peer; > > if ((peer = peer_get(id))) { > @@ -209,14 +168,24 @@ peer_add(uint32_t id, struct peer_config > peer->flags = peer->conf.flags; > SIMPLEQ_INIT(&peer->imsg_queue); > > - head = PEER_HASH(id); > - > - LIST_INSERT_HEAD(head, peer, hash_l); > - LIST_INSERT_HEAD(&peerlist, peer, peer_l); > + if (RB_INSERT(peer_tree, &peertable, peer) != NULL) > + fatalx("rde peer table corrupted"); > > return (peer); > } > > +static inline int > +peer_cmp(struct rde_peer *a, struct rde_peer *b) > +{ > + if (a->conf.id > b->conf.id) > + return 1; > + if (a->conf.id < b->conf.id) > + return -1; > + return 0; > +} > + > +RB_GENERATE(peer_tree, rde_peer, entry, peer_cmp); > + > static void > peer_generate_update(struct rde_peer *peer, uint16_t rib_id, > struct prefix *new, struct prefix *old, enum eval_mode mode) > @@ -276,7 +245,7 @@ rde_generate_updates(struct rib *rib, st > if (old == NULL && new == NULL) > return; > > - LIST_FOREACH(peer, &peerlist, peer_l) > + RB_FOREACH(peer, peer_tree, &peertable) > peer_generate_update(peer, rib->id, new, old, mode); > } > > @@ -475,8 +444,7 @@ peer_down(struct rde_peer *peer, void *b > peer->prefix_cnt = 0; > peer->prefix_out_cnt = 0; > > - LIST_REMOVE(peer, hash_l); > - LIST_REMOVE(peer, peer_l); > + RB_REMOVE(peer_tree, &peertable, peer); > free(peer); > } > >