Claudio Jeker([email protected]) 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);
> }
>
>