On Wed, Jan 18, 2023 at 05:53:10PM +0100, Theo Buehler wrote:
> On Wed, Jan 18, 2023 at 05:37:37PM +0100, Claudio Jeker wrote:
> > On Wed, Jan 18, 2023 at 05:18:58PM +0100, Theo Buehler wrote:
> > > On Wed, Jan 18, 2023 at 02:46:19PM +0100, Claudio Jeker wrote:
> > > > This is the next step in vstate cleanup.
> > > > Since the vstate is now part of struct filterstate use that information
> > > > instead of passing an explicit vstate to the various update functions.
> > > 
> > > It took me a moment to understand that rde_filterstate_clean() does not
> > > zero the vstate, so the changes in rde_update.c preserve behavior.
> > > That's not super intuitive to me, but if that's bound to stay this way,
> > 
> > Uhm, now I'm a bit confused. Where is the vstate used after calling
> > rde_filterstate_clean()? I did not spot that issue in rde_update.c
> > I think we could zero everyting in the filterstate during clean. Just to
> > be sure.
> 
> It is super confusing. For example in up_generate_addpath() it starts
> with:
> 
>               rde_filterstate_prep(&state, new);
> 
> After this, state.vstate == prefix_roa_vstate(new).
> 
>               if (rde_filter(rules, peer, prefix_peer(new), &addr,
>                   prefixlen, &state) == ACTION_DENY) {
>                       rde_filterstate_clean(&state);
>                       continue;
>               }
> 
>               if (up_enforce_open_policy(peer, &state)) {
>                       rde_filterstate_clean(&state);
>                       continue;
>               }
> 
>               /* from here on we know this is an update */
>               p = prefix_adjout_get(peer, new->path_id_tx, &addr, prefixlen);
> 
>               up_prep_adjout(peer, &state, addr.aid);
> 
> None of the above code touches state.vstate.
> 
>               prefix_adjout_update(p, peer, &state, &addr,
>                   prefixlen, new->path_id_tx);
> 
> and here you dropped the prefix_roa_vstate(new) argument that is now
> taken from state, which is correct.

Agreed.
 
> 
> In up_generate_update() I think there's something wrong.
> 
> Again, the vstate is copied from new at the start
> 
>               rde_filterstate_prep(&state, new);
> 
> then new may or may not change over the next few lines, and the two
> rde_filterstate_clean(&state) before prefix_adjout_update() don't
> change state's vstate, and state.vstate may or may not match
> prefix_adjout_update(new).

But those calls have either a break or continue, so either the loop is
exited or restarted (depending on PEERFLAG_EVALUATE_ALL).
So there should be no way to go from a rde_filterstate_clean(&state) to
prefix_adjout_update(new).

There is a missing rde_filterstate_clean(&state) in up_generate_update().
                if (up_enforce_open_policy(peer, &state)) {
                        rde_filterstate_clean(&state);
                        if (peer->flags & PEERFLAG_EVALUATE_ALL) {
                                new = TAILQ_NEXT(new, entry.list.rib);
                                if (new != NULL && prefix_eligible(new))
                                        continue;
                        }
                        break;
                }

                /* check if this was actually a withdraw */
                if (need_withdraw)
>>>>>>>> here the filterstate is leaked, which is bad.
                        break;

                /* from here on we know this is an update */

                up_prep_adjout(peer, &state, addr.aid);
                prefix_adjout_update(p, peer, &state, &addr,
                    new->pt->prefixlen, new->path_id_tx);
                rde_filterstate_clean(&state);

Below a diff that fixes the extra leak.
-- 
:wq Claudio

Index: rde.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/rde.c,v
retrieving revision 1.588
diff -u -p -r1.588 rde.c
--- rde.c       18 Jan 2023 13:20:00 -0000      1.588
+++ rde.c       18 Jan 2023 17:20:10 -0000
@@ -1744,7 +1744,7 @@ rde_update_update(struct rde_peer *peer,
 
        /* add original path to the Adj-RIB-In */
        if (prefix_update(rib_byid(RIB_ADJ_IN), peer, path_id, path_id_tx,
-           in, prefix, prefixlen, in->vstate) == 1)
+           in, prefix, prefixlen) == 1)
                peer->prefix_cnt++;
 
        /* max prefix checker */
@@ -1772,7 +1772,7 @@ rde_update_update(struct rde_peer *peer,
                            &state.nexthop->exit_nexthop, prefix,
                            prefixlen);
                        prefix_update(rib, peer, path_id, path_id_tx, &state,
-                           prefix, prefixlen, in->vstate);
+                           prefix, prefixlen);
                } else if (prefix_withdraw(rib, peer, path_id, prefix,
                    prefixlen)) {
                        rde_update_log(wmsg, i, peer,
@@ -3847,8 +3847,7 @@ rde_softreconfig_in(struct rib_entry *re
                                /* update Local-RIB */
                                prefix_update(rib, peer, p->path_id,
                                    p->path_id_tx, &state,
-                                   &prefix, pt->prefixlen,
-                                   prefix_roa_vstate(p));
+                                   &prefix, pt->prefixlen);
                        } else if (action == ACTION_DENY) {
                                /* remove from Local-RIB */
                                prefix_withdraw(rib, peer, p->path_id, &prefix,
@@ -3986,8 +3985,7 @@ rde_roa_softreload(struct rib_entry *re,
                                /* update Local-RIB */
                                prefix_update(rib, peer, p->path_id,
                                    p->path_id_tx, &state,
-                                   &prefix, pt->prefixlen,
-                                   prefix_roa_vstate(p));
+                                   &prefix, pt->prefixlen);
                        } else if (action == ACTION_DENY) {
                                /* remove from Local-RIB */
                                prefix_withdraw(rib, peer, p->path_id, &prefix,
@@ -4187,7 +4185,6 @@ network_add(struct network_config *nc, s
        struct filter_set_head  *vpnset = NULL;
        struct in_addr           prefix4;
        struct in6_addr          prefix6;
-       uint8_t                  vstate;
        uint16_t                 i;
        uint32_t                 path_id_tx;
 
@@ -4249,14 +4246,16 @@ network_add(struct network_config *nc, s
                rde_apply_set(vpnset, peerself, peerself, state,
                    nc->prefix.aid);
 
+       path_id_tx = pathid_assign(peerself, 0, &nc->prefix, nc->prefixlen);
+
 #if NOTYET
-       state.aspath.aspa_state = ASPA_NEVER_KNOWN;
+       state->aspath.aspa_state = ASPA_NEVER_KNOWN;
 #endif
-       vstate = rde_roa_validity(&rde_roa, &nc->prefix,
+       state->vstate = rde_roa_validity(&rde_roa, &nc->prefix,
            nc->prefixlen, aspath_origin(state->aspath.aspath));
-       path_id_tx = pathid_assign(peerself, 0, &nc->prefix, nc->prefixlen);
+
        if (prefix_update(rib_byid(RIB_ADJ_IN), peerself, 0, path_id_tx,
-           state, &nc->prefix, nc->prefixlen, vstate) == 1)
+           state, &nc->prefix, nc->prefixlen) == 1)
                peerself->prefix_cnt++;
        for (i = RIB_LOC_START; i < rib_size; i++) {
                struct rib *rib = rib_byid(i);
@@ -4266,7 +4265,7 @@ network_add(struct network_config *nc, s
                    state->nexthop ? &state->nexthop->exit_nexthop : NULL,
                    &nc->prefix, nc->prefixlen);
                prefix_update(rib, peerself, 0, path_id_tx, state, &nc->prefix,
-                   nc->prefixlen, vstate);
+                   nc->prefixlen);
        }
        filterset_free(&nc->attrset);
 }
Index: rde.h
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/rde.h,v
retrieving revision 1.279
diff -u -p -r1.279 rde.h
--- rde.h       17 Jan 2023 16:09:01 -0000      1.279
+++ rde.h       17 Jan 2023 16:09:50 -0000
@@ -624,14 +624,12 @@ struct prefix     *prefix_adjout_lookup(stru
                    int);
 struct prefix  *prefix_adjout_next(struct rde_peer *, struct prefix *);
 int             prefix_update(struct rib *, struct rde_peer *, uint32_t,
-                   uint32_t, struct filterstate *, struct bgpd_addr *,
-                   int, uint8_t);
+                   uint32_t, struct filterstate *, struct bgpd_addr *, int);
 int             prefix_withdraw(struct rib *, struct rde_peer *, uint32_t,
                    struct bgpd_addr *, int);
 void            prefix_add_eor(struct rde_peer *, uint8_t);
 void            prefix_adjout_update(struct prefix *, struct rde_peer *,
-                   struct filterstate *, struct bgpd_addr *, int,
-                   uint32_t, uint8_t);
+                   struct filterstate *, struct bgpd_addr *, int, uint32_t);
 void            prefix_adjout_withdraw(struct prefix *);
 void            prefix_adjout_destroy(struct prefix *);
 void            prefix_adjout_dump(struct rde_peer *, void *,
Index: rde_rib.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/rde_rib.c,v
retrieving revision 1.251
diff -u -p -r1.251 rde_rib.c
--- rde_rib.c   28 Dec 2022 21:30:16 -0000      1.251
+++ rde_rib.c   12 Jan 2023 17:37:15 -0000
@@ -955,7 +955,7 @@ prefix_adjout_match(struct rde_peer *pee
 int
 prefix_update(struct rib *rib, struct rde_peer *peer, uint32_t path_id,
     uint32_t path_id_tx, struct filterstate *state, struct bgpd_addr *prefix,
-    int prefixlen, uint8_t vstate)
+    int prefixlen)
 {
        struct rde_aspath       *asp, *nasp = &state->aspath;
        struct rde_community    *comm, *ncomm = &state->communities;
@@ -973,7 +973,7 @@ prefix_update(struct rib *rib, struct rd
                    path_compare(nasp, prefix_aspath(p)) == 0) {
                        /* no change, update last change */
                        p->lastchange = getmonotime();
-                       p->validation_state = vstate;
+                       p->validation_state = state->vstate;
                        return (0);
                }
        }
@@ -997,11 +997,11 @@ prefix_update(struct rib *rib, struct rd
        /* If the prefix was found move it else add it to the RIB. */
        if (p != NULL)
                return (prefix_move(p, peer, asp, comm, state->nexthop,
-                   state->nhflags, vstate));
+                   state->nhflags, state->vstate));
        else
                return (prefix_add(prefix, prefixlen, rib, peer, path_id,
                    path_id_tx, asp, comm, state->nexthop, state->nhflags,
-                   vstate));
+                   state->vstate));
 }
 
 /*
@@ -1123,7 +1123,7 @@ prefix_add_eor(struct rde_peer *peer, ui
 void
 prefix_adjout_update(struct prefix *p, struct rde_peer *peer,
     struct filterstate *state, struct bgpd_addr *prefix, int prefixlen,
-    uint32_t path_id_tx, uint8_t vstate)
+    uint32_t path_id_tx)
 {
        struct rde_aspath *asp;
        struct rde_community *comm;
@@ -1160,7 +1160,7 @@ prefix_adjout_update(struct prefix *p, s
                    prefix_communities(p)) &&
                    path_compare(&state->aspath, prefix_aspath(p)) == 0) {
                        /* nothing changed */
-                       p->validation_state = vstate;
+                       p->validation_state = state->vstate;
                        p->lastchange = getmonotime();
                        p->flags &= ~PREFIX_FLAG_STALE;
                        return;
@@ -1205,7 +1205,7 @@ prefix_adjout_update(struct prefix *p, s
        }
 
        prefix_link(p, NULL, p->pt, peer, 0, p->path_id_tx, asp, comm,
-           state->nexthop, state->nhflags, vstate);
+           state->nexthop, state->nhflags, state->vstate);
        peer->prefix_out_cnt++;
 
        if (p->flags & PREFIX_FLAG_MASK)
Index: rde_update.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/rde_update.c,v
retrieving revision 1.151
diff -u -p -r1.151 rde_update.c
--- rde_update.c        12 Jan 2023 17:35:51 -0000      1.151
+++ rde_update.c        18 Jan 2023 16:39:58 -0000
@@ -199,15 +199,16 @@ up_generate_updates(struct filter_head *
                }
 
                /* check if this was actually a withdraw */
-               if (need_withdraw)
+               if (need_withdraw) {
+                       rde_filterstate_clean(&state);
                        break;
+               }
 
                /* from here on we know this is an update */
 
                up_prep_adjout(peer, &state, addr.aid);
                prefix_adjout_update(p, peer, &state, &addr,
-                   new->pt->prefixlen, new->path_id_tx,
-                   prefix_roa_vstate(new));
+                   new->pt->prefixlen, new->path_id_tx);
                rde_filterstate_clean(&state);
 
                /* max prefix checker outbound */
@@ -337,8 +338,7 @@ up_generate_addpath(struct filter_head *
 
                up_prep_adjout(peer, &state, addr.aid);
                prefix_adjout_update(p, peer, &state, &addr,
-                   new->pt->prefixlen, new->path_id_tx,
-                   prefix_roa_vstate(new));
+                   new->pt->prefixlen, new->path_id_tx);
                rde_filterstate_clean(&state);
 
                /* max prefix checker outbound */
@@ -441,7 +441,7 @@ up_generate_addpath_all(struct filter_he
 
                up_prep_adjout(peer, &state, addr.aid);
                prefix_adjout_update(p, peer, &state, &addr,
-                   prefixlen, new->path_id_tx, prefix_roa_vstate(new));
+                   prefixlen, new->path_id_tx);
                rde_filterstate_clean(&state);
 
                /* max prefix checker outbound */
@@ -509,7 +509,7 @@ up_generate_default(struct filter_head *
        }
 
        up_prep_adjout(peer, &state, addr.aid);
-       prefix_adjout_update(p, peer, &state, &addr, 0, 0, ROA_NOTFOUND);
+       prefix_adjout_update(p, peer, &state, &addr, 0, 0);
        rde_filterstate_clean(&state);
 
        /* max prefix checker outbound */
@@ -1028,7 +1028,6 @@ up_dump_attrnlri(u_char *buf, int len, s
                goto done;
 
        rde_filterstate_prep(&state, p);
-
        r = up_generate_attr(buf + 2, len - 2, peer, &state, AID_INET);
        rde_filterstate_clean(&state);
        if (r == -1) {

Reply via email to