Claudio Jeker([email protected]) on 2018.09.27 18:12:43 +0200:
> On Thu, Sep 27, 2018 at 04:41:22PM +0200, Claudio Jeker wrote:
> > Some people noticed that routes get stuck or to be more precise that
> > withdraws are not sent to peers in some cases. Until now bgpd did not
> > really track what was announced and what not (there is no real
> > Adj-RIB-Out) and instead tried to figure out if it should or should not
> > send the withdraw. With the increased filtering we try to push this fails
> > more often and the result is rather terrible.
> > Instead now introduce minimal tracking of announced prefixes. This adds a
> > per peer RB tree that tracks what was sent out as UPDATE. This can be
> > considered a minimal Adj-RIB-Out.
>
> As usual once you send it out you realize that something is missing.
> I first only looked at callers of up_generate_updates() but then I double
> checked the sofftreconfig out handler and noticed that we need the same
> magic there too (else the accouting is getting off).
> The following diff does this now as well. Double checked all other
> up_generate() users as well.
this is ok benno@
> :wq Claudio
>
> Index: rde.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/bgpd/rde.c,v
> retrieving revision 1.427
> diff -u -p -r1.427 rde.c
> --- rde.c 25 Sep 2018 08:08:38 -0000 1.427
> +++ rde.c 27 Sep 2018 15:49:42 -0000
> @@ -3147,9 +3147,11 @@ rde_softreconfig_out_peer(struct rib_ent
> /* 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 */
> @@ -3197,6 +3199,7 @@ rde_softreconfig_unload_peer(struct rib_
> prefix_nhflags(p));
> if (rde_filter(out_rules_tmp, peer, p, &ostate) != ACTION_DENY) {
> /* send withdraw */
> + up_rib_remove(peer, re);
> up_generate(peer, NULL, &addr, pt->prefixlen);
> }
> rde_filterstate_clean(&ostate);
> Index: rde.h
> ===================================================================
> RCS file: /cvs/src/usr.sbin/bgpd/rde.h,v
> retrieving revision 1.193
> diff -u -p -r1.193 rde.h
> --- rde.h 20 Sep 2018 11:45:59 -0000 1.193
> +++ rde.h 27 Sep 2018 15:48:02 -0000
> @@ -55,6 +55,7 @@ LIST_HEAD(aspath_head, rde_aspath);
> TAILQ_HEAD(aspath_queue, rde_aspath);
> RB_HEAD(uptree_prefix, update_prefix);
> RB_HEAD(uptree_attr, update_attr);
> +RB_HEAD(uptree_rib, update_rib);
>
> struct rib_desc;
> struct rib;
> @@ -70,6 +71,7 @@ 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];
> @@ -566,6 +568,8 @@ int nexthop_compare(struct nexthop *,
> /* rde_update.c */
> void up_init(struct rde_peer *);
> void up_down(struct rde_peer *);
> +int up_rib_remove(struct rde_peer *, struct rib_entry *);
> +void up_rib_add(struct rde_peer *, struct rib_entry *);
> int up_test_update(struct rde_peer *, struct prefix *);
> int up_generate(struct rde_peer *, struct filterstate *,
> struct bgpd_addr *, u_int8_t);
> Index: rde_update.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/bgpd/rde_update.c,v
> retrieving revision 1.99
> diff -u -p -r1.99 rde_update.c
> --- rde_update.c 18 Sep 2018 16:54:01 -0000 1.99
> +++ rde_update.c 27 Sep 2018 15:51:22 -0000
> @@ -53,9 +53,15 @@ 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)
> @@ -64,6 +70,9 @@ 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
> @@ -77,6 +86,7 @@ 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;
> @@ -110,13 +120,18 @@ up_clear(struct uplist_attr *updates, st
> void
> up_down(struct rde_peer *peer)
> {
> - u_int8_t i;
> + struct update_rib *ur, *nur;
> + u_int8_t i;
>
> for (i = 0; i < AID_MAX; i++)
> up_clear(&peer->updates[i], &peer->withdraws[i]);
>
> 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;
> @@ -195,6 +210,42 @@ 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);
> +}
> +
> +int
> up_add(struct rde_peer *peer, struct update_prefix *p, struct update_attr *a)
> {
> struct update_attr *na = NULL;
> @@ -409,11 +460,11 @@ withdraw:
> if (up_test_update(peer, old) != 1)
> return;
>
> - pt_getaddr(old->re->prefix, &addr);
> - if (rde_filter(rules, peer, old, NULL) == ACTION_DENY)
> + if (!up_rib_remove(peer, old->re))
> return;
>
> /* withdraw prefix */
> + pt_getaddr(old->re->prefix, &addr);
> up_generate(peer, NULL, &addr, old->re->prefix->prefixlen);
> } else {
> switch (up_test_update(peer, new)) {
> @@ -433,8 +484,8 @@ withdraw:
> }
>
> pt_getaddr(new->re->prefix, &addr);
> - up_generate(peer, &state, &addr,
> - new->re->prefix->prefixlen);
> + up_generate(peer, &state, &addr, new->re->prefix->prefixlen);
> + up_rib_add(peer, new->re);
>
> rde_filterstate_clean(&state);
> }
>