Claudio Jeker([email protected]) on 2018.10.31 16:24:49 +0100:
> This diff introduces a real Adj-RIB-Out. It is the minimal change to
> introduce the new RIB. This removes the update_rib introduced before 6.4
> lock because that is now replaced with a real RIB.
> The code used by bgpctl show rib is now a fair amount easier since now one
> RIB runner can be used for all cases.
> path_update() is now returning if a prefix was not modified which is
> needed in the update path to suppress unneeded updates.
> The softreconfig out case becomes simpler because there is no more the
> need to run with both filters and check results.
> Last the shutdown code of the RDE had to be adjusted a bit to still work
> with the Adj-RIB-Out.
>
> This may cause memory consumption to go up but my testing has shown that
> the result is actually not significant. Needs the commits from earlier
> today to apply.
> --
> :wq Claudio
i dont see a problem with the diff other than the memory usage (and denis
remarks).
so if we decide that the memory is worth it, ok benno@
not sure if double the usage is acceptable though.
> Index: rde.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/bgpd/rde.c,v
> retrieving revision 1.444
> diff -u -p -r1.444 rde.c
> --- rde.c 31 Oct 2018 14:50:07 -0000 1.444
> +++ rde.c 31 Oct 2018 15:09:39 -0000
> @@ -1395,7 +1395,7 @@ rde_update_update(struct rde_peer *peer,
>
> /* add original path to the Adj-RIB-In */
> if (path_update(&ribs[RIB_ADJ_IN].rib, peer, in, prefix, prefixlen,
> - vstate))
> + vstate) == 1)
> peer->prefix_cnt++;
>
> /* max prefix checker */
> @@ -2124,16 +2124,17 @@ rde_reflector(struct rde_peer *peer, str
> * control specific functions
> */
> static void
> -rde_dump_rib_as(struct prefix *p, struct rde_aspath *asp,
> - struct nexthop *nexthop, pid_t pid, int flags)
> +rde_dump_rib_as(struct prefix *p, struct rde_aspath *asp, pid_t pid, int
> flags)
> {
> struct ctl_show_rib rib;
> struct ibuf *wbuf;
> struct attr *a;
> + struct nexthop *nexthop;
> void *bp;
> time_t staletime;
> u_int8_t l;
>
> + nexthop = prefix_nexthop(p);
> bzero(&rib, sizeof(rib));
> rib.lastchange = p->lastchange;
> rib.local_pref = asp->lpref;
> @@ -2208,70 +2209,37 @@ rde_dump_rib_as(struct prefix *p, struct
> }
>
> static void
> -rde_dump_filterout(struct rde_peer *peer, struct prefix *p,
> - struct ctl_show_rib_request *req)
> -{
> - struct filterstate state;
> - enum filter_actions a;
> -
> - if (up_test_update(peer, p) != 1)
> - return;
> -
> - rde_filterstate_prep(&state, prefix_aspath(p), prefix_nexthop(p),
> - prefix_nhflags(p));
> - a = rde_filter(out_rules, peer, p, &state);
> -
> - if (a == ACTION_ALLOW)
> - rde_dump_rib_as(p, &state.aspath, state.nexthop, req->pid,
> - req->flags);
> -
> - rde_filterstate_clean(&state);
> -}
> -
> -static void
> rde_dump_filter(struct prefix *p, struct ctl_show_rib_request *req)
> {
> - struct rde_peer *peer;
> struct rde_aspath *asp;
>
> - if (req->flags & F_CTL_ADJ_OUT) {
> - if (p->re->active != p)
> - /* only consider active prefix */
> - return;
> - if (req->peerid) {
> - if ((peer = peer_get(req->peerid)) != NULL)
> - rde_dump_filterout(peer, p, req);
> - return;
> - }
> - } else {
> - asp = prefix_aspath(p);
> - if (req->peerid && req->peerid != prefix_peer(p)->conf.id)
> - return;
> - if ((req->flags & F_CTL_ACTIVE) && p->re->active != p)
> - return;
> - if ((req->flags & F_CTL_INVALID) &&
> - (asp->flags & F_ATTR_PARSE_ERR) == 0)
> - return;
> - if (req->type == IMSG_CTL_SHOW_RIB_AS &&
> - !aspath_match(asp->aspath->data, asp->aspath->len,
> - &req->as, 0))
> - return;
> - if (req->type == IMSG_CTL_SHOW_RIB_COMMUNITY &&
> - !community_match(asp, req->community.as,
> - req->community.type))
> - return;
> - if (req->type == IMSG_CTL_SHOW_RIB_EXTCOMMUNITY &&
> - !community_ext_match(asp, &req->extcommunity, 0))
> - return;
> - if (req->type == IMSG_CTL_SHOW_RIB_LARGECOMMUNITY &&
> - !community_large_match(asp, req->large_community.as,
> - req->large_community.ld1, req->large_community.ld2))
> - return;
> - if (!ovs_match(p, req->flags))
> - return;
> - rde_dump_rib_as(p, asp, prefix_nexthop(p), req->pid,
> - req->flags);
> - }
> + if (req->peerid && req->peerid != prefix_peer(p)->conf.id)
> + return;
> +
> + asp = prefix_aspath(p);
> + if ((req->flags & F_CTL_ACTIVE) && p->re->active != p)
> + return;
> + if ((req->flags & F_CTL_INVALID) &&
> + (asp->flags & F_ATTR_PARSE_ERR) == 0)
> + return;
> + if (req->type == IMSG_CTL_SHOW_RIB_AS &&
> + !aspath_match(asp->aspath->data, asp->aspath->len,
> + &req->as, 0))
> + return;
> + if (req->type == IMSG_CTL_SHOW_RIB_COMMUNITY &&
> + !community_match(asp, req->community.as,
> + req->community.type))
> + return;
> + if (req->type == IMSG_CTL_SHOW_RIB_EXTCOMMUNITY &&
> + !community_ext_match(asp, &req->extcommunity, 0))
> + return;
> + if (req->type == IMSG_CTL_SHOW_RIB_LARGECOMMUNITY &&
> + !community_large_match(asp, req->large_community.as,
> + req->large_community.ld1, req->large_community.ld2))
> + return;
> + if (!ovs_match(p, req->flags))
> + return;
> + rde_dump_rib_as(p, asp, req->pid, req->flags);
> }
>
> static void
> @@ -2342,6 +2310,8 @@ rde_dump_ctx_new(struct ctl_show_rib_req
> }
> if (req->flags & (F_CTL_ADJ_IN | F_CTL_INVALID)) {
> rid = RIB_ADJ_IN;
> + } else if (req->flags & F_CTL_ADJ_OUT) {
> + rid = RIB_ADJ_OUT;
> } else if ((rid = rib_find(req->rib)) == RIB_NOTFOUND) {
> log_warnx("rde_dump_ctx_new: no such rib %s", req->rib);
> error = CTL_RES_NOSUCHPEER;
> @@ -2591,6 +2561,19 @@ rde_up_dump_upcall(struct rib_entry *re,
> }
>
> static void
> +rde_up_flush_upcall(struct rib_entry *re, void *ptr)
> +{
> + struct rde_peer *peer = ptr;
> + struct prefix *p, *np;
> +
> + LIST_FOREACH_SAFE(p, &re->prefix_h, rib_l, np) {
> + if (peer != prefix_peer(p))
> + continue;
> + up_generate_updates(out_rules, peer, NULL, p);
> + }
> +}
> +
> +static void
> rde_up_dump_done(void *ptr, u_int8_t aid)
> {
> struct rde_peer *peer = ptr;
> @@ -2805,6 +2788,8 @@ rde_reload_done(void)
> u_int16_t rid;
> int reload = 0;
>
> + softreconfig = 0;
> +
> /* first merge the main config */
> if ((conf->flags & BGPD_FLAG_NO_EVALUATE) &&
> (nconf->flags & BGPD_FLAG_NO_EVALUATE) == 0) {
> @@ -2887,11 +2872,16 @@ rde_reload_done(void)
> char *p = log_fmt_peer(&peer->conf);
> log_debug("rib change: reloading peer %s", p);
> free(p);
> - up_withdraw_all(peer);
> peer->loc_rib_id = rib_find(peer->conf.rib);
> if (peer->loc_rib_id == RIB_NOTFOUND)
> fatalx("King Bula's peer met an unknown RIB");
> peer->reconf_rib = 1;
> + softreconfig++;
> + if (rib_dump_new(RIB_ADJ_OUT, AID_UNSPEC,
> + RDE_RUNNER_ROUNDS, peer, rde_up_flush_upcall,
> + rde_softreconfig_in_done, NULL) == -1)
> + fatal("%s: rib_dump_new", __func__);
> + log_peer_info(&peer->conf, "flushing Adj-RIB-Out");
> continue;
> }
> if (!rde_filter_equal(out_rules, out_rules_tmp, peer)) {
> @@ -2941,14 +2931,13 @@ rde_reload_done(void)
> }
> log_info("RDE reconfigured");
>
> - softreconfig = 0;
> if (reload > 0) {
> - log_info("running softreconfig in");
> softreconfig++;
> if (rib_dump_new(RIB_ADJ_IN, AID_UNSPEC,
> RDE_RUNNER_ROUNDS, &ribs[RIB_ADJ_IN], rde_softreconfig_in,
> rde_softreconfig_in_done, NULL) == -1)
> fatal("%s: rib_dump_new", __func__);
> + log_info("running softreconfig in");
> } else {
> rde_softreconfig_in_done(NULL, AID_UNSPEC);
> }
> @@ -3113,61 +3102,18 @@ rde_softreconfig_in(struct rib_entry *re
> }
>
> static void
> -rde_softreconfig_out_peer(struct rib_entry *re, struct rde_peer *peer)
> -{
> - struct filterstate ostate, nstate;
> - struct bgpd_addr addr;
> - struct prefix *p = re->active;
> - struct pt_entry *pt;
> - enum filter_actions oa, na;
> -
> - pt = re->prefix;
> - pt_getaddr(pt, &addr);
> -
> - if (up_test_update(peer, p) != 1)
> - return;
> -
> - rde_filterstate_prep(&ostate, prefix_aspath(p), prefix_nexthop(p),
> - prefix_nhflags(p));
> - rde_filterstate_prep(&nstate, prefix_aspath(p), prefix_nexthop(p),
> - prefix_nhflags(p));
> - oa = rde_filter(out_rules_tmp, peer, p, &ostate);
> - na = rde_filter(out_rules, peer, p, &nstate);
> -
> - /* go through all 4 possible combinations */
> - /* if (oa == ACTION_DENY && na == ACTION_DENY) */
> - /* nothing todo */
> - if (oa == ACTION_DENY && na == ACTION_ALLOW) {
> - /* send update */
> - up_rib_add(peer, re);
> - up_generate(peer, &nstate, &addr, pt->prefixlen);
> - } else if (oa == ACTION_ALLOW && na == ACTION_DENY) {
> - /* send withdraw */
> - up_rib_remove(peer, re);
> - up_generate(peer, NULL, &addr, pt->prefixlen);
> - } else if (oa == ACTION_ALLOW && na == ACTION_ALLOW) {
> - /* send update if anything changed */
> - if (nstate.nhflags != ostate.nhflags ||
> - nstate.nexthop != ostate.nexthop ||
> - path_compare(&nstate.aspath, &ostate.aspath) != 0)
> - up_generate(peer, &nstate, &addr, pt->prefixlen);
> - }
> -
> - rde_filterstate_clean(&ostate);
> - rde_filterstate_clean(&nstate);
> -}
> -
> -static void
> rde_softreconfig_out(struct rib_entry *re, void *bula)
> {
> + struct prefix *new = re->active;
> struct rde_peer *peer;
>
> - if (re->active == NULL)
> + if (new == NULL)
> return;
>
> LIST_FOREACH(peer, &peerlist, peer_l) {
> if (peer->loc_rib_id == re->rib_id && peer->reconf_out)
> - rde_softreconfig_out_peer(re, peer);
> + /* Regenerate all updates. */
> + up_generate_updates(out_rules, peer, new, new);
> }
> }
>
> @@ -3687,7 +3633,7 @@ network_add(struct network_config *nc, i
> vstate = rde_roa_validity(&conf->rde_roa, &nc->prefix,
> nc->prefixlen, asp->source_as);
> if (path_update(&ribs[RIB_ADJ_IN].rib, peerself, &state, &nc->prefix,
> - nc->prefixlen, vstate))
> + nc->prefixlen, vstate) == 1)
> peerself->prefix_cnt++;
> for (i = RIB_LOC_START; i < rib_size; i++) {
> if (!rib_valid(i))
> @@ -3835,21 +3781,20 @@ rde_shutdown(void)
> * rde_shutdown depends on this.
> */
>
> - /*
> - * All peers go down
> - */
> + /* Frist all peers go down */
> for (i = 0; i <= peertable.peer_hashmask; i++)
> while ((p = LIST_FIRST(&peertable.peer_hashtbl[i])) != NULL)
> peer_down(p->conf.id);
>
> + /* then since decision process is off, kill RIB_ADJ_OUT */
> + rib_free(rib_byid(RIB_ADJ_OUT));
> +
> /* free filters */
> filterlist_free(out_rules);
> - for (i = 0; i < rib_size; i++) {
> - if (!rib_valid(i))
> - continue;
> - filterlist_free(ribs[i].in_rules);
> - }
> + filterlist_free(out_rules_tmp);
>
> + /* now check everything */
> + rib_shutdown();
> nexthop_shutdown();
> path_shutdown();
> aspath_shutdown();
> Index: rde.h
> ===================================================================
> RCS file: /cvs/src/usr.sbin/bgpd/rde.h,v
> retrieving revision 1.201
> diff -u -p -r1.201 rde.h
> --- rde.h 31 Oct 2018 14:50:07 -0000 1.201
> +++ rde.h 31 Oct 2018 15:09:39 -0000
> @@ -79,7 +79,6 @@ LIST_HEAD(attr_list, attr);
> LIST_HEAD(aspath_head, rde_aspath);
> RB_HEAD(uptree_prefix, update_prefix);
> RB_HEAD(uptree_attr, update_attr);
> -RB_HEAD(uptree_rib, update_rib);
>
> TAILQ_HEAD(uplist_prefix, update_prefix);
> TAILQ_HEAD(uplist_attr, update_attr);
> @@ -91,7 +90,6 @@ struct rde_peer {
> struct bgpd_addr remote_addr;
> struct bgpd_addr local_v4_addr;
> struct bgpd_addr local_v6_addr;
> - struct uptree_rib up_rib;
> struct uptree_prefix up_prefix;
> struct uptree_attr up_attrs;
> struct uplist_attr updates[AID_MAX];
> @@ -440,6 +438,7 @@ struct rib *rib_byid(u_int16_t);
> u_int16_t rib_find(char *);
> struct rib_desc *rib_desc(struct rib *);
> void rib_free(struct rib *);
> +void rib_shutdown(void);
> struct rib_entry *rib_get(struct rib *, struct bgpd_addr *, int);
> struct rib_entry *rib_lookup(struct rib *, struct bgpd_addr *);
> int rib_dump_pending(void);
> Index: rde_rib.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/bgpd/rde_rib.c,v
> retrieving revision 1.184
> diff -u -p -r1.184 rde_rib.c
> --- rde_rib.c 31 Oct 2018 14:50:07 -0000 1.184
> +++ rde_rib.c 31 Oct 2018 15:09:39 -0000
> @@ -216,6 +216,21 @@ rib_free(struct rib *rib)
> bzero(rd, sizeof(struct rib_desc));
> }
>
> +void
> +rib_shutdown(void)
> +{
> + u_int16_t id;
> +
> + for (id = 0; id < rib_size; id++) {
> + if (!rib_valid(id))
> + continue;
> + if (!RB_EMPTY(rib_tree(&ribs[id].rib)))
> + log_warnx("%s: rib %s is not empty", __func__,
> + ribs[id].name);
> + rib_free(&ribs[id].rib);
> + }
> +}
> +
> struct rib_entry *
> rib_get(struct rib *rib, struct bgpd_addr *prefix, int prefixlen)
> {
> @@ -553,6 +568,11 @@ path_hash_stats(struct rde_hashstats *hs
> }
> }
>
> +/*
> + * Update a prefix belonging to a possible new aspath.
> + * Return 1 if prefix was newly added, 0 if it was just changed or 2 if no
> + * change happened at all.
> + */
> int
> path_update(struct rib *rib, struct rde_peer *peer, struct filterstate
> *state,
> struct bgpd_addr *prefix, int prefixlen, u_int8_t vstate)
> @@ -575,7 +595,7 @@ path_update(struct rib *rib, struct rde_
> /* no change, update last change */
> p->lastchange = time(NULL);
> p->validation_state = vstate;
> - return (0);
> + return (2);
> }
> }
>
> Index: rde_update.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/bgpd/rde_update.c,v
> retrieving revision 1.102
> diff -u -p -r1.102 rde_update.c
> --- rde_update.c 24 Oct 2018 08:26:37 -0000 1.102
> +++ rde_update.c 31 Oct 2018 15:09:39 -0000
> @@ -53,15 +53,9 @@ struct update_attr {
> u_int16_t mpattr_len;
> };
>
> -struct update_rib {
> - RB_ENTRY(update_rib) entry;
> - struct rib_entry *re;
> -};
> -
> void up_clear(struct uplist_attr *, struct uplist_prefix *);
> int up_prefix_cmp(struct update_prefix *, struct update_prefix *);
> int up_attr_cmp(struct update_attr *, struct update_attr *);
> -int up_rib_cmp(struct update_rib *, struct update_rib *);
> int up_add(struct rde_peer *, struct update_prefix *, struct update_attr *);
>
> RB_PROTOTYPE(uptree_prefix, update_prefix, entry, up_prefix_cmp)
> @@ -70,9 +64,6 @@ RB_GENERATE(uptree_prefix, update_prefix
> RB_PROTOTYPE(uptree_attr, update_attr, entry, up_attr_cmp)
> RB_GENERATE(uptree_attr, update_attr, entry, up_attr_cmp)
>
> -RB_PROTOTYPE(uptree_rib, update_rib, entry, up_rib_cmp)
> -RB_GENERATE(uptree_rib, update_rib, entry, up_rib_cmp)
> -
> SIPHASH_KEY uptree_key;
>
> void
> @@ -86,7 +77,6 @@ up_init(struct rde_peer *peer)
> }
> RB_INIT(&peer->up_prefix);
> RB_INIT(&peer->up_attrs);
> - RB_INIT(&peer->up_rib);
> peer->up_pcnt = 0;
> peer->up_acnt = 0;
> peer->up_nlricnt = 0;
> @@ -120,7 +110,6 @@ up_clear(struct uplist_attr *updates, st
> void
> up_down(struct rde_peer *peer)
> {
> - struct update_rib *ur, *nur;
> u_int8_t i;
>
> for (i = 0; i < AID_MAX; i++)
> @@ -128,10 +117,6 @@ up_down(struct rde_peer *peer)
>
> RB_INIT(&peer->up_prefix);
> RB_INIT(&peer->up_attrs);
> - RB_FOREACH_SAFE(ur, uptree_rib, &peer->up_rib, nur) {
> - RB_REMOVE(uptree_rib, &peer->up_rib, ur);
> - free(ur);
> - }
>
> peer->up_pcnt = 0;
> peer->up_acnt = 0;
> @@ -210,58 +195,6 @@ up_attr_cmp(struct update_attr *a, struc
> }
>
> int
> -up_rib_cmp(struct update_rib *a, struct update_rib *b)
> -{
> - if (a->re != b->re)
> - return (a->re > b->re ? 1 : -1);
> - return 0;
> -}
> -
> -int
> -up_rib_remove(struct rde_peer *peer, struct rib_entry *re)
> -{
> - struct update_rib *ur, u;
> - u.re = re;
> -
> - ur = RB_FIND(uptree_rib, &peer->up_rib, &u);
> - if (ur != NULL) {
> - RB_REMOVE(uptree_rib, &peer->up_rib, ur);
> - free(ur);
> - return 1;
> - } else
> - return 0;
> -}
> -
> -void
> -up_rib_add(struct rde_peer *peer, struct rib_entry *re)
> -{
> - struct update_rib *ur;
> -
> - if ((ur = calloc(1, sizeof(*ur))) == NULL)
> - fatal("%s", __func__);
> - ur->re = re;
> -
> - if (RB_INSERT(uptree_rib, &peer->up_rib, ur) != NULL)
> - free(ur);
> -}
> -
> -void
> -up_withdraw_all(struct rde_peer *peer)
> -{
> - struct bgpd_addr addr;
> - struct update_rib *ur, *nur;
> -
> - RB_FOREACH_SAFE(ur, uptree_rib, &peer->up_rib, nur) {
> - RB_REMOVE(uptree_rib, &peer->up_rib, ur);
> -
> - /* withdraw prefix */
> - pt_getaddr(ur->re->prefix, &addr);
> - up_generate(peer, NULL, &addr, ur->re->prefix->prefixlen);
> - free(ur);
> - }
> -}
> -
> -int
> up_add(struct rde_peer *peer, struct update_prefix *p, struct update_attr *a)
> {
> struct update_attr *na = NULL;
> @@ -473,14 +406,16 @@ up_generate_updates(struct filter_head *
>
> if (new == NULL) {
> withdraw:
> - if (up_test_update(peer, old) != 1)
> - return;
> -
> - if (!up_rib_remove(peer, old->re))
> + if (old == NULL)
> return;
>
> /* withdraw prefix */
> pt_getaddr(old->re->prefix, &addr);
> + if (prefix_remove(&ribs[RIB_ADJ_OUT].rib, peer, &addr,
> + old->re->prefix->prefixlen) == 0) {
> + /* not in table, no need to send withdraw */
> + return;
> + }
> up_generate(peer, NULL, &addr, old->re->prefix->prefixlen);
> } else {
> switch (up_test_update(peer, new)) {
> @@ -500,8 +435,12 @@ withdraw:
> }
>
> pt_getaddr(new->re->prefix, &addr);
> - up_generate(peer, &state, &addr, new->re->prefix->prefixlen);
> - up_rib_add(peer, new->re);
> + if (path_update(&ribs[RIB_ADJ_OUT].rib, peer, &state, &addr,
> + new->re->prefix->prefixlen, prefix_vstate(new)) != 2) {
> + /* only send update if path changed */
> + up_generate(peer, &state, &addr,
> + new->re->prefix->prefixlen);
> + }
>
> rde_filterstate_clean(&state);
> }
>