This diff adds the reload logic and rewrites larger parts of what was
already there to have ASPA validation in the RDE.

The main reason this diff is so large is that the ASPA state cache on
struct rde_aspath needs to be afi/aid and role independent. So I changed
the aspa functions to be role and aid independent which results in a lot
of churn.

The code now uses rde_aspa_validity() with the cache in rde_aspath to
figure out if a prefix is ASPA valid, invalid or unknown.
rde_aspa_validity() is cheap since it just checks various bits to decide.
The cache is updated by checking a generation counter that is increased
during reload. This is done since the tables are walked by prefix and not
by ASPATH.

There is still no filter syntax available to deny aspa invalid routes but
that will follow soon.

The diff includes bgpd, bgpctl and regress test changes. There is a lot of
churn in regress test because of bgpctl output changes.
-- 
:wq Claudio

Index: usr.sbin/bgpd/bgpd.h
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/bgpd.h,v
retrieving revision 1.458
diff -u -p -r1.458 bgpd.h
--- usr.sbin/bgpd/bgpd.h        17 Jan 2023 16:09:01 -0000      1.458
+++ usr.sbin/bgpd/bgpd.h        20 Jan 2023 08:18:06 -0000
@@ -840,7 +840,8 @@ struct ctl_show_rib {
        uint32_t                flags;
        uint8_t                 prefixlen;
        uint8_t                 origin;
-       uint8_t                 validation_state;
+       uint8_t                 roa_validation_state;
+       uint8_t                 aspa_validation_state;
        int8_t                  dmetric;
        /* plus an aspath */
 };
Index: usr.sbin/bgpd/rde.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/rde.c,v
retrieving revision 1.589
diff -u -p -r1.589 rde.c
--- usr.sbin/bgpd/rde.c 18 Jan 2023 17:40:17 -0000      1.589
+++ usr.sbin/bgpd/rde.c 20 Jan 2023 10:56:39 -0000
@@ -61,7 +61,7 @@ uint8_t                rde_attr_missing(struct rde_as
 int             rde_get_mp_nexthop(u_char *, uint16_t, uint8_t,
                    struct filterstate *);
 void            rde_as4byte_fixup(struct rde_peer *, struct rde_aspath *);
-uint8_t                 rde_aspa_validation(struct rde_peer *, struct 
rde_aspath *,
+uint8_t                 rde_aspa_validity(struct rde_peer *, struct rde_aspath 
*,
                    uint8_t);
 void            rde_reflector(struct rde_peer *, struct rde_aspath *);
 
@@ -82,8 +82,9 @@ static void    rde_softreconfig_in(struct 
 static void     rde_softreconfig_sync_reeval(struct rib_entry *, void *);
 static void     rde_softreconfig_sync_fib(struct rib_entry *, void *);
 static void     rde_softreconfig_sync_done(void *, uint8_t);
-static void     rde_roa_reload(void);
-static void     rde_aspa_reload(void);
+static void     rde_rpki_reload(void);
+static int      rde_roa_reload(void);
+static int      rde_aspa_reload(void);
 int             rde_update_queue_pending(void);
 void            rde_update_queue_runner(void);
 void            rde_update6_queue_runner(uint8_t);
@@ -111,6 +112,7 @@ static struct imsgbuf               *ibuf_main;
 static struct bgpd_config      *conf, *nconf;
 static struct rde_prefixset     rde_roa, roa_new;
 static struct rde_aspa         *rde_aspa, *aspa_new;
+static uint8_t                  rde_aspa_generation;
 
 volatile sig_atomic_t   rde_quit = 0;
 struct filter_head     *out_rules, *out_rules_tmp;
@@ -1162,8 +1164,8 @@ rde_dispatch_imsg_rtr(struct imsgbuf *ib
                        break;
                case IMSG_RECONF_DONE:
                        /* end of update */
-                       rde_roa_reload();
-                       rde_aspa_reload();
+                       if (rde_roa_reload() + rde_aspa_reload() != 0)
+                               rde_rpki_reload();
                        break;
                }
                imsg_free(&imsg);
@@ -1364,6 +1366,14 @@ rde_update_dispatch(struct rde_peer *pee
                        state.aspath.flags |= F_ATTR_LOOP;
 
                rde_reflector(peer, &state.aspath);
+
+               /* Cache aspa lookup for all updates from ebgp sessions. */
+               if (state.aspath.flags & F_ATTR_ASPATH &&
+                   peer->conf.ebgp) {
+                       aspa_validation(rde_aspa, state.aspath.aspath,
+                           &state.aspath.aspa_state);
+                       state.aspath.aspa_generation = rde_aspa_generation;
+               }
        }
 
        p = imsg->data;
@@ -1525,10 +1535,6 @@ rde_update_dispatch(struct rde_peer *pee
                            NULL, 0);
                        goto done;
                }
-#if NOTYET
-               state.aspath.aspa_state = rde_aspa_validation(peer,
-                   &state.aspath, AID_INET);
-#endif
        }
        while (nlri_len > 0) {
                if (peer_has_add_path(peer, AID_INET, CAPA_AP_RECV)) {
@@ -1601,10 +1607,6 @@ rde_update_dispatch(struct rde_peer *pee
                mpp += pos;
                mplen -= pos;
 
-#if NOTYET
-               state.aspath.aspa_state = rde_aspa_validation(peer,
-                   &state.aspath, aid);
-#endif
                while (mplen > 0) {
                        if (peer_has_add_path(peer, aid, CAPA_AP_RECV)) {
                                if (mplen <= sizeof(pathid)) {
@@ -1732,16 +1734,19 @@ rde_update_update(struct rde_peer *peer,
 {
        struct filterstate       state;
        enum filter_actions      action;
-       uint16_t                 i;
        uint32_t                 path_id_tx;
+       uint16_t                 i;
+       uint8_t                  roa_state, aspa_state;
        const char              *wmsg = "filtered, withdraw";
 
        peer->prefix_rcvd_update++;
-       in->vstate = rde_roa_validity(&rde_roa, prefix, prefixlen,
+
+       roa_state = rde_roa_validity(&rde_roa, prefix, prefixlen,
            aspath_origin(in->aspath.aspath));
+       aspa_state = rde_aspa_validity(peer, &in->aspath, prefix->aid);
+       rde_filterstate_set_vstate(in, roa_state, aspa_state);
 
        path_id_tx = pathid_assign(peer, path_id, prefix, prefixlen);
-
        /* 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) == 1)
@@ -1779,7 +1784,6 @@ rde_update_update(struct rde_peer *peer,
                            NULL, prefix, prefixlen);
                }
 
-               /* clear state */
                rde_filterstate_clean(&state);
        }
        return (0);
@@ -2472,7 +2476,7 @@ rde_as4byte_fixup(struct rde_peer *peer,
 
 
 uint8_t
-rde_aspa_validation(struct rde_peer *peer, struct rde_aspath *asp, uint8_t aid)
+rde_aspa_validity(struct rde_peer *peer, struct rde_aspath *asp, uint8_t aid)
 {
        if (!peer->conf.ebgp)   /* ASPA is only performed on ebgp sessions */
                return ASPA_NEVER_KNOWN;
@@ -2489,7 +2493,8 @@ rde_aspa_validation(struct rde_peer *pee
         */
 
        /* skip neighbor-as check for transparent RS sessions */
-       if (peer->conf.role != ROLE_RS_CLIENT) {
+       if (peer->role != ROLE_RS_CLIENT &&
+           peer->conf.enforce_as != ENFORCE_AS_ON) {
                uint32_t fas;
 
                fas = aspath_neighbor(asp->aspath);
@@ -2498,7 +2503,24 @@ rde_aspa_validation(struct rde_peer *pee
        }
 #endif
 
-       return aspa_validation(rde_aspa, peer->conf.role, asp->aspath, aid);
+       /* if no role is set, the outcome is unknown */
+       if (peer->role == ROLE_NONE)
+               return ASPA_UNKNOWN;
+
+       switch (aid) {
+       case AID_INET:
+               if (peer->role != ROLE_CUSTOMER)
+                       return asp->aspa_state.onlyup_v4;
+               else
+                       return asp->aspa_state.downup_v4;
+       case AID_INET6:
+               if (peer->role != ROLE_CUSTOMER)
+                       return asp->aspa_state.onlyup_v6;
+               else
+                       return asp->aspa_state.downup_v6;
+       default:
+               return ASPA_NEVER_KNOWN;        /* not reachable */
+       }
 }
 
 /*
@@ -2605,7 +2627,8 @@ rde_dump_rib_as(struct prefix *p, struct
        pt_getaddr(p->pt, &rib.prefix);
        rib.prefixlen = p->pt->prefixlen;
        rib.origin = asp->origin;
-       rib.validation_state = prefix_roa_vstate(p);
+       rib.roa_validation_state = prefix_roa_vstate(p);
+       rib.aspa_validation_state = prefix_aspa_vstate(p);
        rib.dmetric = p->dmetric;
        rib.flags = 0;
        if (!adjout) {
@@ -3580,6 +3603,13 @@ rde_reload_done(void)
                        /* add-path send needs rde_eval_all */
                        rde_eval_all = 1;
                }
+               if (peer->role != peer->conf.role) {
+                       if (reload == 0)
+                               log_debug("peer role change: "
+                                   "reloading Adj-RIB-In");
+                       peer->role = peer->conf.role;
+                       reload++;
+               }
                peer->export_type = peer->conf.export_type;
                peer->flags = peer->conf.flags;
                if (peer->flags & PEERFLAG_EVALUATE_ALL)
@@ -3820,6 +3850,7 @@ rde_softreconfig_in(struct rib_entry *re
        enum filter_actions      action;
        struct bgpd_addr         prefix;
        uint16_t                 i;
+       uint8_t                  aspa_vstate;
 
        pt = re->prefix;
        pt_getaddr(pt, &prefix);
@@ -3827,6 +3858,13 @@ rde_softreconfig_in(struct rib_entry *re
                asp = prefix_aspath(p);
                peer = prefix_peer(p);
 
+               /* possible role change update ASPA validation state */
+               if (prefix_aspa_vstate(p) == ASPA_NEVER_KNOWN)
+                       aspa_vstate = ASPA_NEVER_KNOWN;
+               else
+                       aspa_vstate = rde_aspa_validity(peer, asp, pt->aid);
+               prefix_set_vstate(p, prefix_roa_vstate(p), aspa_vstate);
+
                /* skip announced networks, they are never filtered */
                if (asp->flags & F_PREFIX_ANNOUNCED)
                        continue;
@@ -3942,7 +3980,7 @@ rde_softreconfig_sync_done(void *arg, ui
  * so this runs outside of the softreconfig handlers.
  */
 static void
-rde_roa_softreload(struct rib_entry *re, void *bula)
+rde_rpki_softreload(struct rib_entry *re, void *bula)
 {
        struct filterstate       state;
        struct rib              *rib;
@@ -3952,7 +3990,7 @@ rde_roa_softreload(struct rib_entry *re,
        struct rde_aspath       *asp;
        enum filter_actions      action;
        struct bgpd_addr         prefix;
-       uint8_t                  vstate;
+       uint8_t                  roa_vstate, aspa_vstate;
        uint16_t                 i;
 
        pt = re->prefix;
@@ -3962,12 +4000,26 @@ rde_roa_softreload(struct rib_entry *re,
                peer = prefix_peer(p);
 
                /* ROA validation state update */
-               vstate = rde_roa_validity(&rde_roa,
+               roa_vstate = rde_roa_validity(&rde_roa,
                    &prefix, pt->prefixlen, aspath_origin(asp->aspath));
-               if (vstate == prefix_roa_vstate(p))
+
+               /* ASPA validation state update (if needed) */
+               if (prefix_aspa_vstate(p) == ASPA_NEVER_KNOWN) {
+                       aspa_vstate = ASPA_NEVER_KNOWN;
+               } else {
+                       if (asp->aspa_generation != rde_aspa_generation) {
+                               asp->aspa_generation = rde_aspa_generation;
+                               aspa_validation(rde_aspa, asp->aspath,
+                                   &asp->aspa_state);
+                       }
+                       aspa_vstate = rde_aspa_validity(peer, asp, pt->aid);
+               }
+
+               if (roa_vstate == prefix_roa_vstate(p) &&
+                   aspa_vstate == prefix_aspa_vstate(p))
                        continue;
-               p->validation_state = vstate;
 
+               prefix_set_vstate(p, roa_vstate, aspa_vstate);
                /* skip announced networks, they are never filtered */
                if (asp->flags & F_PREFIX_ANNOUNCED)
                        continue;
@@ -3997,25 +4049,39 @@ rde_roa_softreload(struct rib_entry *re,
        }
 }
 
-static int roa_update_pending;
-static int aspa_update_pending;
+static int rpki_update_pending;
 
 static void
-rde_roa_softreload_done(void *arg, uint8_t aid)
+rde_rpki_softreload_done(void *arg, uint8_t aid)
 {
        /* the roa update is done */
-       log_info("ROA softreload done");
-       roa_update_pending = 0;
+       log_info("RPKI softreload done");
+       rpki_update_pending = 0;
 }
 
 static void
+rde_rpki_reload(void)
+{
+       if (rpki_update_pending) {
+               log_info("RPKI softreload skipped, old still running");
+               return;
+       }
+
+       rpki_update_pending = 1;
+       if (rib_dump_new(RIB_ADJ_IN, AID_UNSPEC, RDE_RUNNER_ROUNDS,
+           rib_byid(RIB_ADJ_IN), rde_rpki_softreload,
+           rde_rpki_softreload_done, NULL) == -1)
+               fatal("%s: rib_dump_new", __func__);
+}
+
+static int
 rde_roa_reload(void)
 {
        struct rde_prefixset roa_old;
 
-       if (roa_update_pending) {
-               log_info("ROA softreload skipped, old still running");
-               return;
+       if (rpki_update_pending) {
+               trie_free(&roa_new.th); /* can't use new roa table */
+               return 1;               /* force call to rde_rpki_reload */
        }
 
        roa_old = rde_roa;
@@ -4026,28 +4092,25 @@ rde_roa_reload(void)
        if (trie_equal(&rde_roa.th, &roa_old.th)) {
                rde_roa.lastchange = roa_old.lastchange;
                trie_free(&roa_old.th); /* old roa no longer needed */
-               return;
+               return 0;
        }
 
        rde_roa.lastchange = getmonotime();
-       trie_free(&roa_old.th); /* old roa no longer needed */
+       trie_free(&roa_old.th);         /* old roa no longer needed */
 
        log_debug("ROA change: reloading Adj-RIB-In");
-       roa_update_pending = 1;
-       if (rib_dump_new(RIB_ADJ_IN, AID_UNSPEC, RDE_RUNNER_ROUNDS,
-           rib_byid(RIB_ADJ_IN), rde_roa_softreload,
-           rde_roa_softreload_done, NULL) == -1)
-               fatal("%s: rib_dump_new", __func__);
+       return 1;
 }
 
-static void
+static int
 rde_aspa_reload(void)
 {
        struct rde_aspa *aspa_old;
 
-       if (aspa_update_pending) {
-               log_info("ASPA softreload skipped, old still running");
-               return;
+       if (rpki_update_pending) {
+               aspa_table_free(aspa_new);      /* can't use new aspa table */
+               aspa_new = NULL;
+               return 1;                       /* rpki_client_relaod warns */
        }
 
        aspa_old = rde_aspa;
@@ -4058,12 +4121,13 @@ rde_aspa_reload(void)
        if (aspa_table_equal(rde_aspa, aspa_old)) {
                aspa_table_unchanged(rde_aspa, aspa_old);
                aspa_table_free(aspa_old);      /* old aspa no longer needed */
-               return;
+               return 0;
        }
 
-       aspa_table_free(aspa_old);      /* old aspa no longer needed */
+       aspa_table_free(aspa_old);              /* old aspa no longer needed */
        log_debug("ASPA change: reloading Adj-RIB-In");
-       /* XXX MISSING */
+       rde_aspa_generation++;
+       return 1;
 }
 
 /*
@@ -4185,8 +4249,9 @@ network_add(struct network_config *nc, s
        struct filter_set_head  *vpnset = NULL;
        struct in_addr           prefix4;
        struct in6_addr          prefix6;
-       uint16_t                 i;
        uint32_t                 path_id_tx;
+       uint16_t                 i;
+       uint8_t                  vstate;
 
        if (nc->rd != 0) {
                SIMPLEQ_FOREACH(vpn, &conf->l3vpns, entry) {
@@ -4246,14 +4311,11 @@ 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;
-#endif
-       state->vstate = rde_roa_validity(&rde_roa, &nc->prefix,
-           nc->prefixlen, aspath_origin(state->aspath.aspath));
+       vstate = rde_roa_validity(&rde_roa, &nc->prefix, nc->prefixlen,
+           aspath_origin(state->aspath.aspath));
+       rde_filterstate_set_vstate(state, vstate, ASPA_NEVER_KNOWN);
 
+       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) == 1)
                peerself->prefix_cnt++;
Index: usr.sbin/bgpd/rde.h
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/rde.h,v
retrieving revision 1.280
diff -u -p -r1.280 rde.h
--- usr.sbin/bgpd/rde.h 18 Jan 2023 17:40:17 -0000      1.280
+++ usr.sbin/bgpd/rde.h 20 Jan 2023 10:37:23 -0000
@@ -102,6 +102,7 @@ struct rde_peer {
        uint32_t                         path_id_tx;
        enum peer_state                  state;
        enum export_type                 export_type;
+       enum role                        role;
        uint16_t                         loc_rib_id;
        uint16_t                         short_as;
        uint16_t                         mrt_idx;
@@ -114,6 +115,12 @@ struct rde_peer {
 };
 
 struct rde_aspa;
+struct rde_aspa_state {
+       uint8_t         onlyup_v4;
+       uint8_t         downup_v4;
+       uint8_t         onlyup_v6;
+       uint8_t         downup_v6;
+};
 
 #define AS_SET                 1
 #define AS_SEQUENCE            2
@@ -218,6 +225,7 @@ struct rde_aspath {
        RB_ENTRY(rde_aspath)             entry;
        struct attr                     **others;
        struct aspath                   *aspath;
+       struct rde_aspa_state            aspa_state;
        int                              refcnt;
        uint32_t                         flags;         /* internally used */
        uint32_t                         med;           /* multi exit disc */
@@ -227,7 +235,7 @@ struct rde_aspath {
        uint16_t                         pftableid;     /* pf table id */
        uint8_t                          origin;
        uint8_t                          others_len;
-       uint8_t                          aspa_state;
+       uint8_t                          aspa_generation;
 };
 
 enum nexthop_state {
@@ -538,6 +546,7 @@ void        rde_apply_set(struct filter_set_hea
 void   rde_filterstate_init(struct filterstate *);
 void   rde_filterstate_prep(struct filterstate *, struct prefix *);
 void   rde_filterstate_copy(struct filterstate *, struct filterstate *);
+void   rde_filterstate_set_vstate(struct filterstate *, uint8_t, uint8_t);
 void   rde_filterstate_clean(struct filterstate *);
 int    rde_filter_equal(struct filter_head *, struct filter_head *,
            struct rde_peer *);
@@ -692,6 +701,19 @@ prefix_roa_vstate(struct prefix *p)
        return (p->validation_state & ROA_MASK);
 }
 
+static inline uint8_t
+prefix_aspa_vstate(struct prefix *p)
+{
+       return (p->validation_state >> 4);
+}
+
+static inline void
+prefix_set_vstate(struct prefix *p, uint8_t roa_vstate, uint8_t aspa_vstate)
+{
+       p->validation_state = roa_vstate & ROA_MASK;
+       p->validation_state |= aspa_vstate << 4;
+}
+
 static inline struct rib_entry *
 prefix_re(struct prefix *p)
 {
@@ -731,8 +753,8 @@ int          up_dump_attrnlri(u_char *, int, st
 int             up_dump_mp_reach(u_char *, int, struct rde_peer *, uint8_t);
 
 /* rde_aspa.c */
-uint8_t                 aspa_validation(struct rde_aspa *, enum role, struct 
aspath *,
-                   uint8_t);
+void            aspa_validation(struct rde_aspa *, struct aspath *,
+                   struct rde_aspa_state *);
 struct rde_aspa        *aspa_table_prep(uint32_t, size_t);
 void            aspa_add_set(struct rde_aspa *, uint32_t, const uint32_t *,
                    uint32_t, const uint32_t *);
@@ -743,5 +765,6 @@ int          aspa_table_equal(const struct rde_
                    const struct rde_aspa *);
 void            aspa_table_unchanged(struct rde_aspa *,
                    const struct rde_aspa *);
+void            aspa_table_set_generation(struct rde_aspa *, uint8_t);
 
 #endif /* __RDE_H__ */
Index: usr.sbin/bgpd/rde_aspa.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/rde_aspa.c,v
retrieving revision 1.2
diff -u -p -r1.2 rde_aspa.c
--- usr.sbin/bgpd/rde_aspa.c    17 Jan 2023 16:09:01 -0000      1.2
+++ usr.sbin/bgpd/rde_aspa.c    20 Jan 2023 10:59:54 -0000
@@ -23,11 +23,12 @@
 #include "bgpd.h"
 #include "rde.h"
 
-enum cp_res {
-       UNKNOWN = -1,
-       NOT_PROVIDER = 0,
-       PROVIDER = 1,
-};
+#define        UNKNOWN         0x0
+#define        NOT_PROVIDER    0x1
+#define        PROVIDER        0x2
+
+#define        CP(x, y)        (x | (y << 4))
+#define        CP_GET(x, i)    ((x >> (i * 4)) & 0xf)
 
 struct rde_aspa_set {
        uint32_t                 as;
@@ -49,8 +50,8 @@ struct rde_aspa {
        uint32_t                  maxset;
        struct rde_aspa_set      *sets;
        uint32_t                 *data;
-       size_t                    maxdata;
-       size_t                    curdata;
+       size_t                    maxdata;
+       size_t                    curdata;
        uint32_t                  curset;
        time_t                    lastchange;
 };
@@ -109,43 +110,34 @@ aspa_lookup(struct rde_aspa *ra, uint32_
  * Returns UNKNOWN if cas is not in the ra table or the aid is out of range.
  * Returns PROVIDER if pas is registered for cas for the specified aid.
  * Retruns NOT_PROVIDER otherwise.
+ * The returned value includes the result for both IPv4 and IPv6 and needs
+ * to be looked at with CP_GET.
  * This function is called very frequently and needs to be fast.
  */
-static enum cp_res
-aspa_cp_lookup(struct rde_aspa *ra, uint32_t cas, uint32_t pas, uint8_t aid)
+static uint8_t
+aspa_cp_lookup(struct rde_aspa *ra, uint32_t cas, uint32_t pas)
 {
        struct rde_aspa_set *aspa;
-       uint32_t i, mask;
-
-       switch (aid) {
-       case AID_INET:
-               mask = 0x1;
-               break;
-       case AID_INET6:
-               mask = 0x2;
-               break;
-       default:
-               return UNKNOWN;
-       }
+       uint32_t i;
 
        aspa = aspa_lookup(ra, cas);
        if (aspa == NULL)
-               return UNKNOWN;
+               return CP(UNKNOWN, UNKNOWN);
 
        if (aspa->num < 16) {
                for (i = 0; i < aspa->num; i++) {
                        if (aspa->pas[i] == pas)
                                break;
                        if (aspa->pas[i] > pas)
-                               return NOT_PROVIDER;
+                               return CP(NOT_PROVIDER, NOT_PROVIDER);
                }
                if (i == aspa->num)
-                       return NOT_PROVIDER;
+                       return CP(NOT_PROVIDER, NOT_PROVIDER);
        } else {
                uint32_t lim, x;
                for (i = 0, lim = aspa->num; lim != 0; lim /= 2) {
                        x = lim / 2;
-                       i += x; 
+                       i += x;
                        if (aspa->pas[i] == pas) {
                                break;
                        } else if (aspa->pas[i] < pas) {
@@ -158,14 +150,21 @@ aspa_cp_lookup(struct rde_aspa *ra, uint
                        }
                }
                if (lim == 0)
-                       return NOT_PROVIDER;
+                       return CP(NOT_PROVIDER, NOT_PROVIDER);
        }
 
        if (aspa->pas_aid == NULL)
-               return PROVIDER;
-       if (aspa->pas_aid[i / 16] & (mask << ((i % 16) * 2)))
-               return PROVIDER;
-       return NOT_PROVIDER;
+               return CP(PROVIDER, PROVIDER);
+       switch (aspa->pas_aid[i / 16] >> ((i % 16) * 2) & 0x3) {
+       case 0x1:
+               return CP(PROVIDER, NOT_PROVIDER);
+       case 0x2:
+               return CP(NOT_PROVIDER, PROVIDER);
+       case 0x3:
+               return CP(PROVIDER, PROVIDER);
+       default:
+               fatalx("impossible state in aspa_cp_lookup");
+       }
 }
 
 /*
@@ -182,22 +181,21 @@ aspa_cp_lookup(struct rde_aspa *ra, uint
  * Returns 0 on success and -1 if a AS_SET is encountered.
  */
 static int
-aspa_check_aspath(struct rde_aspa *ra, struct aspath *a, int check_downramp,
-    uint8_t aid, struct aspa_state *s)
+aspa_check_aspath(struct rde_aspa *ra, struct aspath *a, struct aspa_state *s)
 {
        uint8_t         *seg;
+       int              afi;
        uint32_t         as, prevas = 0;
        uint16_t         len, seg_size;
-       uint8_t          i, seg_type, seg_len;
-       enum cp_res      r;
+       uint8_t          i, r, seg_type, seg_len;
 
-       memset(s, 0, sizeof(*s));
-       /* the neighbor-as itself is by definition valid */ 
-       s->ndown_p = 1;
+       /* the neighbor-as itself is by definition valid */
+       s[0].ndown_p = 1;
+       s[1].ndown_p = 1;
 
        /*
         * Walk aspath and validate if necessary both up- and down-ramp.
-        * If an AS_SET is found the result is immediatly ASPA_INVALID.
+        * If an AS_SET is found return -1 to indicate failure.
         */
        seg = aspath_dump(a);
        len = aspath_length(a);
@@ -206,7 +204,7 @@ aspa_check_aspath(struct rde_aspa *ra, s
                seg_len = seg[1];
                seg_size = 2 + sizeof(uint32_t) * seg_len;
 
-               if (seg_type == AS_SET)
+               if (seg_type != AS_SEQUENCE)
                        return -1;
 
                for (i = 0; i < seg_len; i++) {
@@ -215,52 +213,59 @@ aspa_check_aspath(struct rde_aspa *ra, s
                        if (as == prevas)
                                continue; /* skip prepends */
 
-                       s->nhops++;
-                       if (prevas != 0) {
-                               if (check_downramp) {
-                                       /*
-                                        * down-ramp check, remember the
-                                        * left-most unknown or not-provider
-                                        * node and the right-most provider node
-                                        * for which all nodes before are valid.
-                                        */
-                                       r = aspa_cp_lookup(ra, prevas, as, aid);
-                                       switch (r) {
-                                       case UNKNOWN:
-                                               if (s->ndown_u == 0)
-                                                       s->ndown_u = s->nhops;
-                                               break;
-                                       case PROVIDER:
-                                               if (s->ndown_p + 1 == s->nhops)
-                                                       s->ndown_p = s->nhops;
-                                               break;
-                                       case NOT_PROVIDER:
-                                               if (s->ndown_np == 0)
-                                                       s->ndown_np = s->nhops;
-                                               break;
-                                       }
+                       s[0].nhops++;
+                       s[1].nhops++;
+                       if (prevas == 0) {
+                               prevas = as; /* skip left-most AS */
+                               continue;
+                       }
+
+                       /*
+                        * down-ramp check, remember the
+                        * left-most unknown or not-provider
+                        * node and the right-most provider node
+                        * for which all nodes before are valid.
+                        */
+                       r = aspa_cp_lookup(ra, prevas, as);
+                       for (afi = 0; afi < 2; afi++) {
+                               switch (CP_GET(r, afi)) {
+                               case UNKNOWN:
+                                       if (s[afi].ndown_u == 0)
+                                               s[afi].ndown_u = s[afi].nhops;
+                                       break;
+                               case PROVIDER:
+                                       if (s[afi].ndown_p + 1 == s[afi].nhops)
+                                               s[afi].ndown_p = s[afi].nhops;
+                                       break;
+                               case NOT_PROVIDER:
+                                       if (s[afi].ndown_np == 0)
+                                               s[afi].ndown_np = s[afi].nhops;
+                                       break;
                                }
-                               /*
-                                * up-ramp check, remember the right-most
-                                * unknown and not-provider node and the
-                                * left-most provider node for which all nodes
-                                * after are valid.
-                                * We recorde the nhops value of prevas,
-                                * that's why the use of nhops - 1.
-                                */
-                               r = aspa_cp_lookup(ra, as, prevas, aid);
-                               switch (r) {
+                       }
+
+                       /*
+                        * up-ramp check, remember the right-most
+                        * unknown and not-provider node and the
+                        * left-most provider node for which all nodes
+                        * after are valid.
+                        * We recorde the nhops value of prevas,
+                        * that's why the use of nhops - 1.
+                        */
+                       r = aspa_cp_lookup(ra, as, prevas);
+                       for (afi = 0; afi < 2; afi++) {
+                               switch (CP_GET(r, afi)) {
                                case UNKNOWN:
-                                       s->nup_p = 0;
-                                       s->nup_u = s->nhops - 1;
+                                       s[afi].nup_p = 0;
+                                       s[afi].nup_u = s[afi].nhops - 1;
                                        break;
                                case PROVIDER:
-                                       if (s->nup_p == 0)
-                                               s->nup_p = s->nhops - 1;
+                                       if (s[afi].nup_p == 0)
+                                               s[afi].nup_p = s[afi].nhops - 1;
                                        break;
                                case NOT_PROVIDER:
-                                       s->nup_p = 0;
-                                       s->nup_np = s->nhops - 1;
+                                       s[afi].nup_p = 0;
+                                       s[afi].nup_np = s[afi].nhops - 1;
                                        break;
                                }
                        }
@@ -268,70 +273,85 @@ aspa_check_aspath(struct rde_aspa *ra, s
                }
        }
 
-       /* the source-as itself is by definition valid */ 
-       if (s->nup_p == 0)
-               s->nup_p = s->nhops;
+       /* the source-as itself is by definition valid */
+       if (s[0].nup_p == 0)
+               s[0].nup_p = s[0].nhops;
+       if (s[1].nup_p == 0)
+               s[1].nup_p = s[1].nhops;
        return 0;
 }
 
 /*
+ * Set the two possible aspa outcomes for up-ramp only and up/down ramp
+ * in the vstate array.
+ */
+static void
+aspa_check_finalize(struct aspa_state *state, uint8_t *onlyup, uint8_t *downup)
+{
+       /*
+        * Just an up-ramp:
+        * if a check returned NOT_PROVIDER then the result is invalid.
+        * if a check returned UNKNOWN then the result is unknown.
+        * else path is valid.
+        */
+       if (state->nup_np != 0)
+               *onlyup = ASPA_INVALID;
+       else if (state->nup_u != 0)
+               *onlyup = ASPA_UNKNOWN;
+       else
+               *onlyup = ASPA_VALID;
+
+       /*
+        * Both up-ramp and down-ramp:
+        * if nhops <= 2 the result is valid.
+        * if there is less than one AS hop between up-ramp and
+        *   down-ramp then the result is valid.
+        * if not-provider nodes for both ramps exist and they
+        *   do not overlap the path is invalid.
+        * else the path is unknown.
+        */
+       if (state->nhops <= 2)
+               *downup = ASPA_VALID;
+       else if (state->nup_p - state->ndown_p <= 1)
+               *downup = ASPA_VALID;
+       else if (state->nup_np != 0 && state->ndown_np != 0 &&
+           state->nup_np - state->ndown_np >= 0)
+               *downup = ASPA_INVALID;
+       else
+               *downup = ASPA_UNKNOWN;
+}
+
+/*
  * Validate an aspath against the aspa_set *ra.
  * Returns ASPA_VALID if the aspath is valid, ASPA_UNKNOWN if the
  * aspath contains hops with unknown relation and invalid for
  * empty aspaths, aspath with AS_SET and aspaths that fail validation.
  */
-uint8_t
-aspa_validation(struct rde_aspa *ra, enum role role, struct aspath *a,
-    uint8_t aid)
+void
+aspa_validation(struct rde_aspa *ra, struct aspath *a,
+    struct rde_aspa_state *vstate)
 {
-       struct aspa_state       state;
+       struct aspa_state state[2] = { 0 };
 
        /* no aspa table, evrything is unknown */
-       if (ra == NULL)
-               return ASPA_UNKNOWN;
+       if (ra == NULL) {
+               memset(vstate, ASPA_UNKNOWN, 4);
+               return;
+       }
 
        /* empty ASPATHs are always invalid */
-       if (aspath_length(a) == 0)
-               return ASPA_INVALID;
+       if (aspath_length(a) == 0) {
+               memset(vstate, ASPA_INVALID, 4);
+               return;
+       }
 
-       /* if no role is set, the outcome is unknown */
-       if (role == ROLE_NONE)
-               return ASPA_UNKNOWN;
-               
-       if (aspa_check_aspath(ra, a, role == ROLE_CUSTOMER, aid, &state) == -1)
-               return ASPA_INVALID;
-
-       if (role != ROLE_CUSTOMER) {
-               /*
-                * Just an up-ramp:
-                * if a check returned NOT_PROVIDER then the result is invalid.
-                * if a check returned UNKNOWN then the result is unknown.
-                * else path is valid.
-                */
-               if (state.nup_np != 0)
-                       return ASPA_INVALID;
-               if (state.nup_u != 0)
-                       return ASPA_UNKNOWN;
-               return ASPA_VALID;
-       } else {
-               /*
-                * Both up-ramp and down-ramp:
-                * if nhops <= 2 the result is valid.
-                * if there is less than one AS hop between up-ramp and
-                *   down-ramp then the result is valid.
-                * if not-provider nodes for both ramps exist and they
-                *   do not overlap the path is invalid.
-                * else the path is unknown.
-                */
-               if (state.nhops <= 2)
-                       return ASPA_VALID;
-               if (state.nup_p - state.ndown_p <= 1)
-                       return ASPA_VALID;
-               if (state.nup_np != 0 && state.ndown_np != 0 &&
-                   state.nup_np - state.ndown_np >= 0)
-                       return ASPA_INVALID;
-               return ASPA_UNKNOWN;
+       if (aspa_check_aspath(ra, a, state) == -1) {
+               memset(vstate, ASPA_INVALID, 4);
+               return;
        }
+
+       aspa_check_finalize(state, &vstate->onlyup_v4, &vstate->downup_v4);
+       aspa_check_finalize(state + 1, &vstate->onlyup_v6, &vstate->downup_v6);
 }
 
 /*
@@ -364,7 +384,7 @@ aspa_table_prep(uint32_t entries, size_t
 
        if ((ra->data = malloc(datasize)) == NULL)
                fatal("aspa table prep");
-               
+
        ra->mask = hsize - 1;
        ra->maxset = entries;
        ra->maxdata = datasize / sizeof(ra->data[0]);
Index: usr.sbin/bgpd/rde_filter.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/rde_filter.c,v
retrieving revision 1.131
diff -u -p -r1.131 rde_filter.c
--- usr.sbin/bgpd/rde_filter.c  12 Jan 2023 17:35:51 -0000      1.131
+++ usr.sbin/bgpd/rde_filter.c  20 Jan 2023 08:18:06 -0000
@@ -448,18 +448,37 @@ rde_filterstate_set(struct filterstate *
        state->vstate = vstate;
 }
 
+/*
+ * Build a filterstate based on the prefix p.
+ */
 void
 rde_filterstate_prep(struct filterstate *state, struct prefix *p)
 {
        rde_filterstate_set(state, prefix_aspath(p), prefix_communities(p),
-           prefix_nexthop(p), prefix_nhflags(p), prefix_roa_vstate(p));
+           prefix_nexthop(p), prefix_nhflags(p), p->validation_state);
 }
 
+/*
+ * Copy a filterstate to a new filterstate.
+ */
 void
 rde_filterstate_copy(struct filterstate *state, struct filterstate *src)
 {
        rde_filterstate_set(state, &src->aspath, &src->communities,
            src->nexthop, src->nhflags, src->vstate);
+}
+
+/*
+ * Set the vstate based on the aspa_state and the supplied roa vstate.
+ * This function must be called after rde_filterstate_init().
+ * rde_filterstate_prep() and rde_filterstate_copy() set the right vstate.
+ */
+void
+rde_filterstate_set_vstate(struct filterstate *state, uint8_t roa_vstate,
+    uint8_t aspa_state)
+{
+       state->vstate = aspa_state << 4;
+       state->vstate |= roa_vstate & ROA_MASK;
 }
 
 void
Index: usr.sbin/bgpd/rde_peer.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/rde_peer.c,v
retrieving revision 1.26
diff -u -p -r1.26 rde_peer.c
--- usr.sbin/bgpd/rde_peer.c    18 Jan 2023 13:20:01 -0000      1.26
+++ usr.sbin/bgpd/rde_peer.c    20 Jan 2023 10:04:38 -0000
@@ -166,6 +166,7 @@ peer_add(uint32_t id, struct peer_config
                fatalx("King Bula's new peer met an unknown RIB");
        peer->state = PEER_NONE;
        peer->eval = peer->conf.eval;
+       peer->role = peer->conf.role;
        peer->export_type = peer->conf.export_type;
        peer->flags = peer->conf.flags;
        SIMPLEQ_INIT(&peer->imsg_queue);
Index: usr.sbin/bgpd/rde_rib.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/rde_rib.c,v
retrieving revision 1.253
diff -u -p -r1.253 rde_rib.c
--- usr.sbin/bgpd/rde_rib.c     20 Jan 2023 10:28:22 -0000      1.253
+++ usr.sbin/bgpd/rde_rib.c     20 Jan 2023 10:28:48 -0000
@@ -636,6 +636,8 @@ path_compare(struct rde_aspath *a, struc
        if (a->pftableid < b->pftableid)
                return (-1);
 
+       /* no need to check aspa_state or aspa_generation */
+
        r = aspath_compare(a->aspath, b->aspath);
        if (r > 0)
                return (1);
Index: usr.sbin/bgpd/rde_update.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/rde_update.c,v
retrieving revision 1.152
diff -u -p -r1.152 rde_update.c
--- usr.sbin/bgpd/rde_update.c  18 Jan 2023 17:40:17 -0000      1.152
+++ usr.sbin/bgpd/rde_update.c  20 Jan 2023 08:18:06 -0000
@@ -486,9 +486,7 @@ up_generate_default(struct filter_head *
        asp = &state.aspath;
        asp->aspath = aspath_get(NULL, 0);
        asp->origin = ORIGIN_IGP;
-#ifdef NOTYET
-       asp->aspa_state = ASPA_NEVER_KNOWN;
-#endif
+       rde_filterstate_set_vstate(&state, ROA_NOTFOUND, ASPA_NEVER_KNOWN);
        /* the other default values are OK, nexthop is once again NULL */
 
        /*
Index: usr.sbin/bgpctl/bgpctl.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpctl/bgpctl.c,v
retrieving revision 1.288
diff -u -p -r1.288 bgpctl.c
--- usr.sbin/bgpctl/bgpctl.c    17 Jan 2023 16:09:34 -0000      1.288
+++ usr.sbin/bgpctl/bgpctl.c    20 Jan 2023 09:06:13 -0000
@@ -772,6 +772,19 @@ fmt_ovs(uint8_t validation_state, int su
 }
 
 const char *
+fmt_avs(uint8_t validation_state, int sum)
+{
+       switch (validation_state) {
+       case ASPA_INVALID:
+               return (sum ? "!" : "invalid");
+       case ASPA_VALID:
+               return (sum ? "V" : "valid");
+       default:
+               return (sum ? "?" : "unknown");
+       }
+}
+
+const char *
 fmt_mem(long long num)
 {
        static char     buf[16];
Index: usr.sbin/bgpctl/bgpctl.h
===================================================================
RCS file: /cvs/src/usr.sbin/bgpctl/bgpctl.h,v
retrieving revision 1.18
diff -u -p -r1.18 bgpctl.h
--- usr.sbin/bgpctl/bgpctl.h    9 Nov 2022 14:20:11 -0000       1.18
+++ usr.sbin/bgpctl/bgpctl.h    20 Jan 2023 09:06:13 -0000
@@ -50,6 +50,7 @@ const char    *fmt_fib_flags(uint16_t);
 const char     *fmt_origin(uint8_t, int);
 const char     *fmt_flags(uint32_t, int);
 const char     *fmt_ovs(uint8_t, int);
+const char     *fmt_avs(uint8_t, int);
 const char     *fmt_auth_method(enum auth_method);
 const char     *fmt_mem(long long);
 const char     *fmt_errstr(uint8_t, uint8_t);
Index: usr.sbin/bgpctl/output.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpctl/output.c,v
retrieving revision 1.33
diff -u -p -r1.33 output.c
--- usr.sbin/bgpctl/output.c    17 Jan 2023 16:09:34 -0000      1.33
+++ usr.sbin/bgpctl/output.c    20 Jan 2023 09:06:13 -0000
@@ -71,9 +71,11 @@ show_head(struct parse_result *res)
                    "       S = Stale, E = Error\n");
                printf("origin validation state: "
                    "N = not-found, V = valid, ! = invalid\n");
+               printf("aspa validation state: "
+                   "? = unknown, V = valid, ! = invalid\n");
                printf("origin: i = IGP, e = EGP, ? = Incomplete\n\n");
                printf("%-5s %3s %-20s %-15s  %5s %5s %s\n",
-                   "flags", "ovs", "destination", "gateway", "lpref", "med",
+                   "flags", "vs", "destination", "gateway", "lpref", "med",
                    "aspath origin");
                break;
        case SHOW_SET:
@@ -918,8 +920,9 @@ show_rib_brief(struct ctl_show_rib *r, u
 
        if (asprintf(&p, "%s/%u", log_addr(&r->prefix), r->prefixlen) == -1)
                err(1, NULL);
-       printf("%s %3s %-20s %-15s %5u %5u ",
-           fmt_flags(r->flags, 1), fmt_ovs(r->validation_state, 1), p,
+       printf("%s %s-%s %-20s %-15s %5u %5u ",
+           fmt_flags(r->flags, 1), fmt_ovs(r->roa_validation_state, 1),
+           fmt_avs(r->aspa_validation_state, 1), p,
            log_addr(&r->exit_nexthop), r->local_pref, r->med);
        free(p);
 
@@ -961,8 +964,9 @@ show_rib_detail(struct ctl_show_rib *r, 
 
        printf("    Origin %s, metric %u, localpref %u, weight %u, ovs %s, ",
            fmt_origin(r->origin, 0), r->med, r->local_pref, r->weight,
-           fmt_ovs(r->validation_state, 0));
-       printf("%s", fmt_flags(r->flags, 0));
+           fmt_ovs(r->roa_validation_state, 0));
+       printf("avs %s, %s", fmt_avs(r->roa_validation_state, 0),
+           fmt_flags(r->flags, 0));
 
        printf("%c    Last update: %s ago%c", EOL0(flag0),
            fmt_timeframe(r->age), EOL0(flag0));
Index: usr.sbin/bgpctl/output_json.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpctl/output_json.c,v
retrieving revision 1.28
diff -u -p -r1.28 output_json.c
--- usr.sbin/bgpctl/output_json.c       17 Jan 2023 16:09:34 -0000      1.28
+++ usr.sbin/bgpctl/output_json.c       20 Jan 2023 09:06:13 -0000
@@ -894,7 +894,8 @@ json_rib(struct ctl_show_rib *r, u_char 
                json_do_bool("announced", 1);
 
        /* various attribibutes */
-       json_do_printf("ovs", "%s", fmt_ovs(r->validation_state, 0));
+       json_do_printf("ovs", "%s", fmt_ovs(r->roa_validation_state, 0));
+       json_do_printf("avs", "%s", fmt_avs(r->aspa_validation_state, 0));
        json_do_printf("origin", "%s", fmt_origin(r->origin, 0));
        json_do_uint("metric", r->med);
        json_do_uint("localpref", r->local_pref);
Index: regress/usr.sbin/bgpd/integrationtests/eval_all.test1.ok
===================================================================
RCS file: /cvs/src/regress/usr.sbin/bgpd/integrationtests/eval_all.test1.ok,v
retrieving revision 1.2
diff -u -p -r1.2 eval_all.test1.ok
--- regress/usr.sbin/bgpd/integrationtests/eval_all.test1.ok    22 Jun 2021 
17:57:07 -0000      1.2
+++ regress/usr.sbin/bgpd/integrationtests/eval_all.test1.ok    19 Jan 2023 
10:34:34 -0000
@@ -2,19 +2,19 @@
 BGP routing table entry for 10.0.1.0/24
     64500 64502 101 101 101
     Nexthop 10.12.57.3 (via 10.12.57.3) Neighbor 10.12.57.4 (10.12.57.4)
-    Origin IGP, metric 0, localpref 100, weight 0, ovs not-found, external, 
valid
+    Origin IGP, metric 0, localpref 100, weight 0, ovs not-found, avs unknown, 
external, valid
 
 BGP routing table entry for 10.12.1.0/24
     64500 64501
     Nexthop 10.12.57.2 (via 10.12.57.2) Neighbor 10.12.57.4 (10.12.57.4)
-    Origin IGP, metric 0, localpref 100, weight 0, ovs not-found, external, 
valid
+    Origin IGP, metric 0, localpref 100, weight 0, ovs not-found, avs unknown, 
external, valid
 
 BGP routing table entry for 10.12.2.0/24
     64500 64502
     Nexthop 10.12.57.3 (via 10.12.57.3) Neighbor 10.12.57.4 (10.12.57.4)
-    Origin IGP, metric 0, localpref 100, weight 0, ovs not-found, external, 
valid
+    Origin IGP, metric 0, localpref 100, weight 0, ovs not-found, avs unknown, 
external, valid
 
 BGP routing table entry for 10.12.1.0/24
     64500 64501
     Nexthop 10.12.57.2 (via 10.12.57.2) Neighbor 10.12.57.5 (10.12.57.5)
-    Origin IGP, metric 0, localpref 100, weight 0, ovs not-found, external, 
valid
+    Origin IGP, metric 0, localpref 100, weight 0, ovs not-found, avs unknown, 
external, valid
Index: regress/usr.sbin/bgpd/integrationtests/eval_all.test2.ok
===================================================================
RCS file: /cvs/src/regress/usr.sbin/bgpd/integrationtests/eval_all.test2.ok,v
retrieving revision 1.2
diff -u -p -r1.2 eval_all.test2.ok
--- regress/usr.sbin/bgpd/integrationtests/eval_all.test2.ok    22 Jun 2021 
17:57:07 -0000      1.2
+++ regress/usr.sbin/bgpd/integrationtests/eval_all.test2.ok    19 Jan 2023 
10:34:40 -0000
@@ -2,9 +2,9 @@
 BGP routing table entry for 10.12.1.0/24
     64500 64501
     Nexthop 10.12.57.2 (via 10.12.57.2) Neighbor 10.12.57.4 (10.12.57.4)
-    Origin IGP, metric 0, localpref 100, weight 0, ovs not-found, external, 
valid
+    Origin IGP, metric 0, localpref 100, weight 0, ovs not-found, avs unknown, 
external, valid
 
 BGP routing table entry for 10.12.1.0/24
     64500 64501
     Nexthop 10.12.57.2 (via 10.12.57.2) Neighbor 10.12.57.5 (10.12.57.5)
-    Origin IGP, metric 0, localpref 100, weight 0, ovs not-found, external, 
valid
+    Origin IGP, metric 0, localpref 100, weight 0, ovs not-found, avs unknown, 
external, valid
Index: regress/usr.sbin/bgpd/integrationtests/eval_all.test4.ok
===================================================================
RCS file: /cvs/src/regress/usr.sbin/bgpd/integrationtests/eval_all.test4.ok,v
retrieving revision 1.2
diff -u -p -r1.2 eval_all.test4.ok
--- regress/usr.sbin/bgpd/integrationtests/eval_all.test4.ok    22 Jun 2021 
17:57:07 -0000      1.2
+++ regress/usr.sbin/bgpd/integrationtests/eval_all.test4.ok    19 Jan 2023 
10:34:49 -0000
@@ -2,29 +2,29 @@
 BGP routing table entry for 10.0.1.0/24
     64500 64502 101 101 101
     Nexthop 10.12.57.3 (via 10.12.57.3) Neighbor 10.12.57.4 (10.12.57.4)
-    Origin IGP, metric 0, localpref 100, weight 0, ovs not-found, external, 
valid
+    Origin IGP, metric 0, localpref 100, weight 0, ovs not-found, avs unknown, 
external, valid
 
 BGP routing table entry for 10.12.1.0/24
     64500 64501
     Nexthop 10.12.57.2 (via 10.12.57.2) Neighbor 10.12.57.4 (10.12.57.4)
-    Origin IGP, metric 0, localpref 100, weight 0, ovs not-found, external, 
valid
+    Origin IGP, metric 0, localpref 100, weight 0, ovs not-found, avs unknown, 
external, valid
 
 BGP routing table entry for 10.12.2.0/24
     64500 64502
     Nexthop 10.12.57.3 (via 10.12.57.3) Neighbor 10.12.57.4 (10.12.57.4)
-    Origin IGP, metric 0, localpref 100, weight 0, ovs not-found, external, 
valid
+    Origin IGP, metric 0, localpref 100, weight 0, ovs not-found, avs unknown, 
external, valid
 
 BGP routing table entry for 10.0.1.0/24
     64500 64502 101 101 101
     Nexthop 10.12.57.3 (via 10.12.57.3) Neighbor 10.12.57.5 (10.12.57.5)
-    Origin IGP, metric 0, localpref 100, weight 0, ovs not-found, external, 
valid
+    Origin IGP, metric 0, localpref 100, weight 0, ovs not-found, avs unknown, 
external, valid
 
 BGP routing table entry for 10.12.1.0/24
     64500 64501
     Nexthop 10.12.57.2 (via 10.12.57.2) Neighbor 10.12.57.5 (10.12.57.5)
-    Origin IGP, metric 0, localpref 100, weight 0, ovs not-found, external, 
valid
+    Origin IGP, metric 0, localpref 100, weight 0, ovs not-found, avs unknown, 
external, valid
 
 BGP routing table entry for 10.12.2.0/24
     64500 64502
     Nexthop 10.12.57.3 (via 10.12.57.3) Neighbor 10.12.57.5 (10.12.57.5)
-    Origin IGP, metric 0, localpref 100, weight 0, ovs not-found, external, 
valid
+    Origin IGP, metric 0, localpref 100, weight 0, ovs not-found, avs unknown, 
external, valid
Index: regress/usr.sbin/bgpd/integrationtests/exabgp.med.ok
===================================================================
RCS file: /cvs/src/regress/usr.sbin/bgpd/integrationtests/exabgp.med.ok,v
retrieving revision 1.2
diff -u -p -r1.2 exabgp.med.ok
--- regress/usr.sbin/bgpd/integrationtests/exabgp.med.ok        7 Jul 2022 
13:40:27 -0000       1.2
+++ regress/usr.sbin/bgpd/integrationtests/exabgp.med.ok        19 Jan 2023 
10:30:52 -0000
@@ -1,9 +1,10 @@
 flags: * = Valid, > = Selected, I = via IBGP, A = Announced,
        S = Stale, E = Error
 origin validation state: N = not-found, V = valid, ! = invalid
+aspa validation state: ? = unknown, V = valid, ! = invalid
 origin: i = IGP, e = EGP, ? = Incomplete
 
-flags ovs destination          gateway          lpref   med aspath origin
-*>      N 10.12.1.0/24         10.12.57.3        100   100 64502 64510 i
-*m      N 10.12.1.0/24         10.12.57.4        100    50 64501 64510 i
-*       N 10.12.1.0/24         10.12.57.2        100   100 64501 64510 i
+flags  vs destination          gateway          lpref   med aspath origin
+*>    N-? 10.12.1.0/24         10.12.57.3        100   100 64502 64510 i
+*m    N-? 10.12.1.0/24         10.12.57.4        100    50 64501 64510 i
+*     N-? 10.12.1.0/24         10.12.57.2        100   100 64501 64510 i
Index: regress/usr.sbin/bgpd/integrationtests/exabgp.med_2.ok
===================================================================
RCS file: /cvs/src/regress/usr.sbin/bgpd/integrationtests/exabgp.med_2.ok,v
retrieving revision 1.2
diff -u -p -r1.2 exabgp.med_2.ok
--- regress/usr.sbin/bgpd/integrationtests/exabgp.med_2.ok      7 Jul 2022 
13:40:27 -0000       1.2
+++ regress/usr.sbin/bgpd/integrationtests/exabgp.med_2.ok      19 Jan 2023 
10:31:09 -0000
@@ -1,8 +1,9 @@
 flags: * = Valid, > = Selected, I = via IBGP, A = Announced,
        S = Stale, E = Error
 origin validation state: N = not-found, V = valid, ! = invalid
+aspa validation state: ? = unknown, V = valid, ! = invalid
 origin: i = IGP, e = EGP, ? = Incomplete
 
-flags ovs destination          gateway          lpref   med aspath origin
-*>      N 10.12.1.0/24         10.12.57.2        100   100 64501 64510 i
-*m      N 10.12.1.0/24         10.12.57.3        100   100 64502 64510 i
+flags  vs destination          gateway          lpref   med aspath origin
+*>    N-? 10.12.1.0/24         10.12.57.2        100   100 64501 64510 i
+*m    N-? 10.12.1.0/24         10.12.57.3        100   100 64502 64510 i
Index: regress/usr.sbin/bgpd/integrationtests/maxcomm.ok
===================================================================
RCS file: /cvs/src/regress/usr.sbin/bgpd/integrationtests/maxcomm.ok,v
retrieving revision 1.1
diff -u -p -r1.1 maxcomm.ok
--- regress/usr.sbin/bgpd/integrationtests/maxcomm.ok   31 May 2022 09:50:26 
-0000      1.1
+++ regress/usr.sbin/bgpd/integrationtests/maxcomm.ok   19 Jan 2023 10:27:32 
-0000
@@ -1,25 +1,26 @@
 flags: * = Valid, > = Selected, I = via IBGP, A = Announced,
        S = Stale, E = Error
 origin validation state: N = not-found, V = valid, ! = invalid
+aspa validation state: ? = unknown, V = valid, ! = invalid
 origin: i = IGP, e = EGP, ? = Incomplete
 
-flags ovs destination          gateway          lpref   med aspath origin
-*>      N 10.12.0.0/24         10.12.57.2        100     0 4200000002 i
-*>      N 10.12.1.0/24         10.12.57.2        100     1 4200000002 i
-*>      N 10.12.2.0/24         10.12.57.2        100     1 4200000002 i
-*>      N 10.12.3.0/24         10.12.57.2        100     3 4200000002 i
-*>      N 10.12.4.0/24         10.12.57.2        100     3 4200000002 i
-*>      N 10.13.0.0/24         10.12.57.2        100     0 4200000002 i
-*>      N 10.13.1.0/24         10.12.57.2        100    10 4200000002 i
-*>      N 10.13.2.0/24         10.12.57.2        100    10 4200000002 i
-*>      N 10.13.3.0/24         10.12.57.2        100    30 4200000002 i
-*>      N 10.13.4.0/24         10.12.57.2        100    30 4200000002 i
-*>      N 10.14.0.0/24         10.12.57.2        100     0 4200000002 i
-*>      N 10.14.1.0/24         10.12.57.2        100   100 4200000002 i
-*>      N 10.14.2.0/24         10.12.57.2        100   100 4200000002 i
-*>      N 10.14.3.0/24         10.12.57.2        100   300 4200000002 i
-*>      N 10.14.4.0/24         10.12.57.2        100   300 4200000002 i
-*>      N 10.15.0.0/24         10.12.57.2        100     0 4200000002 i
-*>      N 10.15.1.0/24         10.12.57.2        100   111 4200000002 i
-*>      N 10.15.2.0/24         10.12.57.2        100  1111 4200000002 i
-*>      N 10.15.3.0/24         10.12.57.2        100  1333 4200000002 i
+flags  vs destination          gateway          lpref   med aspath origin
+*>    N-? 10.12.0.0/24         10.12.57.2        100     0 4200000002 i
+*>    N-? 10.12.1.0/24         10.12.57.2        100     1 4200000002 i
+*>    N-? 10.12.2.0/24         10.12.57.2        100     1 4200000002 i
+*>    N-? 10.12.3.0/24         10.12.57.2        100     3 4200000002 i
+*>    N-? 10.12.4.0/24         10.12.57.2        100     3 4200000002 i
+*>    N-? 10.13.0.0/24         10.12.57.2        100     0 4200000002 i
+*>    N-? 10.13.1.0/24         10.12.57.2        100    10 4200000002 i
+*>    N-? 10.13.2.0/24         10.12.57.2        100    10 4200000002 i
+*>    N-? 10.13.3.0/24         10.12.57.2        100    30 4200000002 i
+*>    N-? 10.13.4.0/24         10.12.57.2        100    30 4200000002 i
+*>    N-? 10.14.0.0/24         10.12.57.2        100     0 4200000002 i
+*>    N-? 10.14.1.0/24         10.12.57.2        100   100 4200000002 i
+*>    N-? 10.14.2.0/24         10.12.57.2        100   100 4200000002 i
+*>    N-? 10.14.3.0/24         10.12.57.2        100   300 4200000002 i
+*>    N-? 10.14.4.0/24         10.12.57.2        100   300 4200000002 i
+*>    N-? 10.15.0.0/24         10.12.57.2        100     0 4200000002 i
+*>    N-? 10.15.1.0/24         10.12.57.2        100   111 4200000002 i
+*>    N-? 10.15.2.0/24         10.12.57.2        100  1111 4200000002 i
+*>    N-? 10.15.3.0/24         10.12.57.2        100  1333 4200000002 i
Index: regress/usr.sbin/bgpd/integrationtests/mrt-table-mp.ok
===================================================================
RCS file: /cvs/src/regress/usr.sbin/bgpd/integrationtests/mrt-table-mp.ok,v
retrieving revision 1.3
diff -u -p -r1.3 mrt-table-mp.ok
--- regress/usr.sbin/bgpd/integrationtests/mrt-table-mp.ok      9 Oct 2022 
05:54:40 -0000       1.3
+++ regress/usr.sbin/bgpd/integrationtests/mrt-table-mp.ok      19 Jan 2023 
10:21:00 -0000
@@ -2,67 +2,67 @@
 BGP routing table entry for 192.0.2.0/24
     4200000001 4200000001 4200000001 4200000001 4200000001
     Nexthop 1.2.3.4 (via 1.2.3.4) Neighbor 0.0.0.0 (0.0.0.0)
-    Origin EGP, metric 42, localpref 15, weight 0, ovs not-found, external
+    Origin EGP, metric 42, localpref 15, weight 0, ovs not-found, avs unknown, 
external
 
 BGP routing table entry for 198.51.100.0/24
     Nexthop 0.0.0.0 (via 0.0.0.0) Neighbor 0.0.0.0 (0.0.0.0)
-    Origin IGP, metric 0, localpref 100, weight 0, ovs not-found, external
+    Origin IGP, metric 0, localpref 100, weight 0, ovs not-found, avs unknown, 
external
     Communities: 42:1 GRACEFUL_SHUTDOWN
     Ext. Communities: ovs invalid rt 127.0.0.1:15
     Large Communities: 4200000001:2:4200000001 4200000001:42:1
 
 BGP routing table entry for 203.0.113.0/24
     Nexthop 0.0.0.0 (via 0.0.0.0) Neighbor 0.0.0.0 (0.0.0.0)
-    Origin IGP, metric 0, localpref 100, weight 0, ovs not-found, external
+    Origin IGP, metric 0, localpref 100, weight 0, ovs not-found, avs unknown, 
external
 
 BGP routing table entry for 2001:db8:1::/48
     4200000001 4200000001 4200000001 4200000001 4200000001
     Nexthop 2001:db8:42::1 (via 2001:db8:42::1) Neighbor :: (0.0.0.0)
-    Origin EGP, metric 42, localpref 15, weight 0, ovs not-found, external
+    Origin EGP, metric 42, localpref 15, weight 0, ovs not-found, avs unknown, 
external
 
 BGP routing table entry for 2001:db8:2::/48
     Nexthop :: (via ::) Neighbor :: (0.0.0.0)
-    Origin IGP, metric 0, localpref 100, weight 0, ovs not-found, external
+    Origin IGP, metric 0, localpref 100, weight 0, ovs not-found, avs unknown, 
external
     Communities: 42:1 GRACEFUL_SHUTDOWN
     Ext. Communities: ovs invalid rt 127.0.0.1:15
     Large Communities: 4200000001:2:4200000001 4200000001:42:1
 
 BGP routing table entry for 2001:db8:3::/48
     Nexthop :: (via ::) Neighbor :: (0.0.0.0)
-    Origin IGP, metric 0, localpref 100, weight 0, ovs not-found, external
+    Origin IGP, metric 0, localpref 100, weight 0, ovs not-found, avs unknown, 
external
 
 BGP routing table entry for rd 4200000001:1 192.0.2.0/24
     4200000001 4200000001 4200000001 4200000001 4200000001
     Nexthop rd 0:0 0.0.0.0 (via rd 0:0 0.0.0.0) Neighbor 0.0.0.0 (0.0.0.0)
-    Origin EGP, metric 42, localpref 15, weight 0, ovs not-found, external
+    Origin EGP, metric 42, localpref 15, weight 0, ovs not-found, avs unknown, 
external
     Ext. Communities: rt 4200000001:42
 
 BGP routing table entry for rd 4200000001:1 198.51.100.0/24
     Nexthop rd 0:0 0.0.0.0 (via rd 0:0 0.0.0.0) Neighbor 0.0.0.0 (0.0.0.0)
-    Origin IGP, metric 0, localpref 100, weight 0, ovs not-found, external
+    Origin IGP, metric 0, localpref 100, weight 0, ovs not-found, avs unknown, 
external
     Communities: 42:1 GRACEFUL_SHUTDOWN
     Ext. Communities: ovs invalid rt 127.0.0.1:15 rt 4200000001:42
     Large Communities: 4200000001:2:42 4200000001:42:1
 
 BGP routing table entry for rd 4200000001:1 203.0.113.0/24
     Nexthop rd 0:0 0.0.0.0 (via rd 0:0 0.0.0.0) Neighbor 0.0.0.0 (0.0.0.0)
-    Origin IGP, metric 0, localpref 100, weight 0, ovs not-found, external
+    Origin IGP, metric 0, localpref 100, weight 0, ovs not-found, avs unknown, 
external
     Ext. Communities: rt 4200000001:42
 
 BGP routing table entry for rd 4200000001:1 2001:db8:1::/48
     4200000001 4200000001 4200000001 4200000001 4200000001
     Nexthop rd 0:0 :: (via rd 0:0 ::) Neighbor :: (0.0.0.0)
-    Origin EGP, metric 42, localpref 15, weight 0, ovs not-found, external
+    Origin EGP, metric 42, localpref 15, weight 0, ovs not-found, avs unknown, 
external
     Ext. Communities: rt 4200000001:42
 
 BGP routing table entry for rd 4200000001:1 2001:db8:2::/48
     Nexthop rd 0:0 :: (via rd 0:0 ::) Neighbor :: (0.0.0.0)
-    Origin IGP, metric 0, localpref 100, weight 0, ovs not-found, external
+    Origin IGP, metric 0, localpref 100, weight 0, ovs not-found, avs unknown, 
external
     Communities: 42:1 GRACEFUL_SHUTDOWN
     Ext. Communities: ovs invalid rt 127.0.0.1:15 rt 4200000001:42
     Large Communities: 4200000001:2:42 4200000001:42:1
 
 BGP routing table entry for rd 4200000001:1 2001:db8:3::/48
     Nexthop rd 0:0 :: (via rd 0:0 ::) Neighbor :: (0.0.0.0)
-    Origin IGP, metric 0, localpref 100, weight 0, ovs not-found, external
+    Origin IGP, metric 0, localpref 100, weight 0, ovs not-found, avs unknown, 
external
     Ext. Communities: rt 4200000001:42
Index: regress/usr.sbin/bgpd/integrationtests/mrt-table-v2.ok
===================================================================
RCS file: /cvs/src/regress/usr.sbin/bgpd/integrationtests/mrt-table-v2.ok,v
retrieving revision 1.3
diff -u -p -r1.3 mrt-table-v2.ok
--- regress/usr.sbin/bgpd/integrationtests/mrt-table-v2.ok      9 Oct 2022 
05:54:40 -0000       1.3
+++ regress/usr.sbin/bgpd/integrationtests/mrt-table-v2.ok      19 Jan 2023 
10:21:13 -0000
@@ -2,67 +2,67 @@
 BGP routing table entry for 192.0.2.0/24
     4200000001 4200000001 4200000001 4200000001 4200000001
     Nexthop 1.2.3.4 (via 1.2.3.4) Neighbor 0.0.0.0 (42.0.0.1)
-    Origin EGP, metric 42, localpref 15, weight 0, ovs not-found, external
+    Origin EGP, metric 42, localpref 15, weight 0, ovs not-found, avs unknown, 
external
 
 BGP routing table entry for 198.51.100.0/24
     Nexthop 0.0.0.0 (via 0.0.0.0) Neighbor 0.0.0.0 (42.0.0.1)
-    Origin IGP, metric 0, localpref 100, weight 0, ovs not-found, external
+    Origin IGP, metric 0, localpref 100, weight 0, ovs not-found, avs unknown, 
external
     Communities: 42:1 GRACEFUL_SHUTDOWN
     Ext. Communities: ovs invalid rt 127.0.0.1:15
     Large Communities: 4200000001:2:4200000001 4200000001:42:1
 
 BGP routing table entry for 203.0.113.0/24
     Nexthop 0.0.0.0 (via 0.0.0.0) Neighbor 0.0.0.0 (42.0.0.1)
-    Origin IGP, metric 0, localpref 100, weight 0, ovs not-found, external
+    Origin IGP, metric 0, localpref 100, weight 0, ovs not-found, avs unknown, 
external
 
 BGP routing table entry for 2001:db8:1::/48
     4200000001 4200000001 4200000001 4200000001 4200000001
     Nexthop 2001:db8:42::1 (via 2001:db8:42::1) Neighbor 0.0.0.0 (42.0.0.1)
-    Origin EGP, metric 42, localpref 15, weight 0, ovs not-found, external
+    Origin EGP, metric 42, localpref 15, weight 0, ovs not-found, avs unknown, 
external
 
 BGP routing table entry for 2001:db8:2::/48
     Nexthop :: (via ::) Neighbor 0.0.0.0 (42.0.0.1)
-    Origin IGP, metric 0, localpref 100, weight 0, ovs not-found, external
+    Origin IGP, metric 0, localpref 100, weight 0, ovs not-found, avs unknown, 
external
     Communities: 42:1 GRACEFUL_SHUTDOWN
     Ext. Communities: ovs invalid rt 127.0.0.1:15
     Large Communities: 4200000001:2:4200000001 4200000001:42:1
 
 BGP routing table entry for 2001:db8:3::/48
     Nexthop :: (via ::) Neighbor 0.0.0.0 (42.0.0.1)
-    Origin IGP, metric 0, localpref 100, weight 0, ovs not-found, external
+    Origin IGP, metric 0, localpref 100, weight 0, ovs not-found, avs unknown, 
external
 
 BGP routing table entry for rd 4200000001:1 192.0.2.0/24
     4200000001 4200000001 4200000001 4200000001 4200000001
     Nexthop rd 0:0 0.0.0.0 (via rd 0:0 0.0.0.0) Neighbor 0.0.0.0 (42.0.0.1)
-    Origin EGP, metric 42, localpref 15, weight 0, ovs not-found, external
+    Origin EGP, metric 42, localpref 15, weight 0, ovs not-found, avs unknown, 
external
     Ext. Communities: rt 4200000001:42
 
 BGP routing table entry for rd 4200000001:1 198.51.100.0/24
     Nexthop rd 0:0 0.0.0.0 (via rd 0:0 0.0.0.0) Neighbor 0.0.0.0 (42.0.0.1)
-    Origin IGP, metric 0, localpref 100, weight 0, ovs not-found, external
+    Origin IGP, metric 0, localpref 100, weight 0, ovs not-found, avs unknown, 
external
     Communities: 42:1 GRACEFUL_SHUTDOWN
     Ext. Communities: ovs invalid rt 127.0.0.1:15 rt 4200000001:42
     Large Communities: 4200000001:2:42 4200000001:42:1
 
 BGP routing table entry for rd 4200000001:1 203.0.113.0/24
     Nexthop rd 0:0 0.0.0.0 (via rd 0:0 0.0.0.0) Neighbor 0.0.0.0 (42.0.0.1)
-    Origin IGP, metric 0, localpref 100, weight 0, ovs not-found, external
+    Origin IGP, metric 0, localpref 100, weight 0, ovs not-found, avs unknown, 
external
     Ext. Communities: rt 4200000001:42
 
 BGP routing table entry for rd 4200000001:1 2001:db8:1::/48
     4200000001 4200000001 4200000001 4200000001 4200000001
     Nexthop rd 0:0 :: (via rd 0:0 ::) Neighbor 0.0.0.0 (42.0.0.1)
-    Origin EGP, metric 42, localpref 15, weight 0, ovs not-found, external
+    Origin EGP, metric 42, localpref 15, weight 0, ovs not-found, avs unknown, 
external
     Ext. Communities: rt 4200000001:42
 
 BGP routing table entry for rd 4200000001:1 2001:db8:2::/48
     Nexthop rd 0:0 :: (via rd 0:0 ::) Neighbor 0.0.0.0 (42.0.0.1)
-    Origin IGP, metric 0, localpref 100, weight 0, ovs not-found, external
+    Origin IGP, metric 0, localpref 100, weight 0, ovs not-found, avs unknown, 
external
     Communities: 42:1 GRACEFUL_SHUTDOWN
     Ext. Communities: ovs invalid rt 127.0.0.1:15 rt 4200000001:42
     Large Communities: 4200000001:2:42 4200000001:42:1
 
 BGP routing table entry for rd 4200000001:1 2001:db8:3::/48
     Nexthop rd 0:0 :: (via rd 0:0 ::) Neighbor 0.0.0.0 (42.0.0.1)
-    Origin IGP, metric 0, localpref 100, weight 0, ovs not-found, external
+    Origin IGP, metric 0, localpref 100, weight 0, ovs not-found, avs unknown, 
external
     Ext. Communities: rt 4200000001:42
Index: regress/usr.sbin/bgpd/integrationtests/mrt-table.ok
===================================================================
RCS file: /cvs/src/regress/usr.sbin/bgpd/integrationtests/mrt-table.ok,v
retrieving revision 1.2
diff -u -p -r1.2 mrt-table.ok
--- regress/usr.sbin/bgpd/integrationtests/mrt-table.ok 9 Oct 2022 05:54:40 
-0000       1.2
+++ regress/usr.sbin/bgpd/integrationtests/mrt-table.ok 19 Jan 2023 10:21:24 
-0000
@@ -2,31 +2,31 @@
 BGP routing table entry for 192.0.2.0/24
     4200000001 4200000001 4200000001 4200000001 4200000001
     Nexthop 1.2.3.4 (via 1.2.3.4) Neighbor 0.0.0.0 (0.0.0.0)
-    Origin EGP, metric 42, localpref 15, weight 0, ovs not-found, external
+    Origin EGP, metric 42, localpref 15, weight 0, ovs not-found, avs unknown, 
external
 
 BGP routing table entry for 198.51.100.0/24
     Nexthop 0.0.0.0 (via 0.0.0.0) Neighbor 0.0.0.0 (0.0.0.0)
-    Origin IGP, metric 0, localpref 100, weight 0, ovs not-found, external
+    Origin IGP, metric 0, localpref 100, weight 0, ovs not-found, avs unknown, 
external
     Communities: 42:1 GRACEFUL_SHUTDOWN
     Ext. Communities: ovs invalid rt 127.0.0.1:15
     Large Communities: 4200000001:2:4200000001 4200000001:42:1
 
 BGP routing table entry for 203.0.113.0/24
     Nexthop 0.0.0.0 (via 0.0.0.0) Neighbor 0.0.0.0 (0.0.0.0)
-    Origin IGP, metric 0, localpref 100, weight 0, ovs not-found, external
+    Origin IGP, metric 0, localpref 100, weight 0, ovs not-found, avs unknown, 
external
 
 BGP routing table entry for 2001:db8:1::/48
     4200000001 4200000001 4200000001 4200000001 4200000001
     Nexthop 2001:db8:42::1 (via 2001:db8:42::1) Neighbor :: (0.0.0.0)
-    Origin EGP, metric 42, localpref 15, weight 0, ovs not-found, external
+    Origin EGP, metric 42, localpref 15, weight 0, ovs not-found, avs unknown, 
external
 
 BGP routing table entry for 2001:db8:2::/48
     Nexthop :: (via ::) Neighbor :: (0.0.0.0)
-    Origin IGP, metric 0, localpref 100, weight 0, ovs not-found, external
+    Origin IGP, metric 0, localpref 100, weight 0, ovs not-found, avs unknown, 
external
     Communities: 42:1 GRACEFUL_SHUTDOWN
     Ext. Communities: ovs invalid rt 127.0.0.1:15
     Large Communities: 4200000001:2:4200000001 4200000001:42:1
 
 BGP routing table entry for 2001:db8:3::/48
     Nexthop :: (via ::) Neighbor :: (0.0.0.0)
-    Origin IGP, metric 0, localpref 100, weight 0, ovs not-found, external
+    Origin IGP, metric 0, localpref 100, weight 0, ovs not-found, avs unknown, 
external
Index: regress/usr.sbin/bgpd/unittests/rde_aspa_test.c
===================================================================
RCS file: /cvs/src/regress/usr.sbin/bgpd/unittests/rde_aspa_test.c,v
retrieving revision 1.3
diff -u -p -r1.3 rde_aspa_test.c
--- regress/usr.sbin/bgpd/unittests/rde_aspa_test.c     17 Jan 2023 16:11:52 
-0000      1.3
+++ regress/usr.sbin/bgpd/unittests/rde_aspa_test.c     20 Jan 2023 10:45:30 
-0000
@@ -38,8 +38,7 @@ struct aspa_test_set {
 struct cp_test {
        uint32_t        customeras;
        uint32_t        provideras;
-       uint8_t         aid;
-       enum cp_res     expected_result;
+       uint8_t         expected_result;
 };
 
 struct aspath_test {
@@ -52,7 +51,6 @@ struct aspa_test {
        const uint32_t  *aspath;
        uint32_t         aspathcnt;
        enum role        role;
-       uint8_t          aid;
        uint8_t          expected_result;
 };
 
@@ -111,73 +109,65 @@ struct aspa_test_set testset[] = {
            60, 65, 70, 75, 80, 81, 82, 83, 87, 90 }, 30, NULL },
        /* extra test for AFI check */
        { 196618, (const uint32_t []){ 1, 2, 3, 4 }, 4,
-           (const uint32_t []){ 0x39 }},
+           (const uint32_t []){ 0xf9 }},
 };
 
 struct cp_test cp_testset[] = {
-       { 1, 2, AID_VPN_IPv4, UNKNOWN },
-       { 1, 4, AID_VPN_IPv6, UNKNOWN },
+       { 6, 1, CP(UNKNOWN, UNKNOWN) },
+       { 42, 1, CP(UNKNOWN, UNKNOWN) },
 
-       { 6, 1, AID_INET, UNKNOWN },
-       { 42, 1, AID_INET, UNKNOWN },
-
-       { 1, 2, AID_INET, NOT_PROVIDER },
-       { 1, 3, AID_INET, NOT_PROVIDER },
-       { 1, 7, AID_INET, NOT_PROVIDER },
-       { 5, 2, AID_INET, NOT_PROVIDER },
-       { 5, 16, AID_INET, NOT_PROVIDER },
-       { 5, 18, AID_INET, NOT_PROVIDER },
-       { 5, 24, AID_INET, NOT_PROVIDER },
-       { 5, 26, AID_INET, NOT_PROVIDER },
-       { 8, 2, AID_INET, NOT_PROVIDER },
-       { 9, 5, AID_INET, NOT_PROVIDER },
-       { 27, 13, AID_INET, NOT_PROVIDER },
-       { 27, 15, AID_INET, NOT_PROVIDER },
-
-       { 1, 4, AID_INET, PROVIDER },
-       { 1, 5, AID_INET, PROVIDER },
-       { 1, 6, AID_INET, PROVIDER },
-       { 2, 10, AID_INET, PROVIDER },
-       { 2, 11, AID_INET, PROVIDER },
-       { 9, 2, AID_INET, PROVIDER },
-       { 27, 14, AID_INET, PROVIDER },
+       { 1, 2, CP(NOT_PROVIDER, NOT_PROVIDER) },
+       { 1, 3, CP(NOT_PROVIDER, NOT_PROVIDER) },
+       { 1, 7, CP(NOT_PROVIDER, NOT_PROVIDER) },
+       { 5, 2, CP(NOT_PROVIDER, NOT_PROVIDER) },
+       { 5, 16, CP(NOT_PROVIDER, NOT_PROVIDER) },
+       { 5, 18, CP(NOT_PROVIDER, NOT_PROVIDER) },
+       { 5, 24, CP(NOT_PROVIDER, NOT_PROVIDER) },
+       { 5, 26, CP(NOT_PROVIDER, NOT_PROVIDER) },
+       { 8, 2, CP(NOT_PROVIDER, NOT_PROVIDER) },
+       { 9, 5, CP(NOT_PROVIDER, NOT_PROVIDER) },
+       { 27, 13, CP(NOT_PROVIDER, NOT_PROVIDER) },
+       { 27, 15, CP(NOT_PROVIDER, NOT_PROVIDER) },
+
+       { 1, 4, CP(PROVIDER, PROVIDER) },
+       { 1, 5, CP(PROVIDER, PROVIDER) },
+       { 1, 6, CP(PROVIDER, PROVIDER) },
+       { 2, 10, CP(PROVIDER, PROVIDER) },
+       { 2, 11, CP(PROVIDER, PROVIDER) },
+       { 9, 2, CP(PROVIDER, PROVIDER) },
+       { 27, 14, CP(PROVIDER, PROVIDER) },
 
        /* per AID tests */
-       { 196618, 1, AID_INET, PROVIDER },
-       { 196618, 1, AID_INET6, NOT_PROVIDER },
-       { 196618, 2, AID_INET, NOT_PROVIDER },
-       { 196618, 2, AID_INET6, PROVIDER },
-       { 196618, 3, AID_INET, PROVIDER },
-       { 196618, 3, AID_INET6, PROVIDER },
-       { 196618, 4, AID_INET, NOT_PROVIDER },
-       { 196618, 4, AID_INET6, NOT_PROVIDER },
-       { 196618, 5, AID_INET, NOT_PROVIDER },
-       { 196618, 5, AID_INET6, NOT_PROVIDER },
+       { 196618, 1, CP(PROVIDER, NOT_PROVIDER) },
+       { 196618, 2, CP(NOT_PROVIDER, PROVIDER) },
+       { 196618, 3, CP(PROVIDER, PROVIDER) },
+       { 196618, 4, CP(PROVIDER, PROVIDER) },
+       { 196618, 5, CP(NOT_PROVIDER, NOT_PROVIDER) },
 
        /* big provider set test */
-       { 65000, 1, AID_INET, NOT_PROVIDER },
-       { 65000, 2, AID_INET, NOT_PROVIDER },
-       { 65000, 3, AID_INET, PROVIDER },
-       { 65000, 4, AID_INET, NOT_PROVIDER },
-       { 65000, 5, AID_INET, PROVIDER },
-       { 65000, 15, AID_INET, PROVIDER },
-       { 65000, 19, AID_INET, NOT_PROVIDER },
-       { 65000, 20, AID_INET, PROVIDER },
-       { 65000, 21, AID_INET, PROVIDER },
-       { 65000, 22, AID_INET, PROVIDER },
-       { 65000, 23, AID_INET, PROVIDER },
-       { 65000, 24, AID_INET, PROVIDER },
-       { 65000, 25, AID_INET, PROVIDER },
-       { 65000, 26, AID_INET, NOT_PROVIDER },
-       { 65000, 85, AID_INET, NOT_PROVIDER },
-       { 65000, 86, AID_INET, NOT_PROVIDER },
-       { 65000, 87, AID_INET, PROVIDER },
-       { 65000, 88, AID_INET, NOT_PROVIDER },
-       { 65000, 89, AID_INET, NOT_PROVIDER },
-       { 65000, 90, AID_INET, PROVIDER },
-       { 65000, 91, AID_INET, NOT_PROVIDER },
-       { 65000, 92, AID_INET, NOT_PROVIDER },
-       { 65000, 6666, AID_INET, NOT_PROVIDER },
+       { 65000, 1, CP(NOT_PROVIDER, NOT_PROVIDER) },
+       { 65000, 2, CP(NOT_PROVIDER, NOT_PROVIDER) },
+       { 65000, 3, CP(PROVIDER, PROVIDER) },
+       { 65000, 4, CP(NOT_PROVIDER, NOT_PROVIDER) },
+       { 65000, 5, CP(PROVIDER, PROVIDER) },
+       { 65000, 15, CP(PROVIDER, PROVIDER) },
+       { 65000, 19, CP(NOT_PROVIDER, NOT_PROVIDER) },
+       { 65000, 20, CP(PROVIDER, PROVIDER) },
+       { 65000, 21, CP(PROVIDER, PROVIDER) },
+       { 65000, 22, CP(PROVIDER, PROVIDER) },
+       { 65000, 23, CP(PROVIDER, PROVIDER) },
+       { 65000, 24, CP(PROVIDER, PROVIDER) },
+       { 65000, 25, CP(PROVIDER, PROVIDER) },
+       { 65000, 26, CP(NOT_PROVIDER, NOT_PROVIDER) },
+       { 65000, 85, CP(NOT_PROVIDER, NOT_PROVIDER) },
+       { 65000, 86, CP(NOT_PROVIDER, NOT_PROVIDER) },
+       { 65000, 87, CP(PROVIDER, PROVIDER) },
+       { 65000, 88, CP(NOT_PROVIDER, NOT_PROVIDER) },
+       { 65000, 89, CP(NOT_PROVIDER, NOT_PROVIDER) },
+       { 65000, 90, CP(PROVIDER, PROVIDER) },
+       { 65000, 91, CP(NOT_PROVIDER, NOT_PROVIDER) },
+       { 65000, 92, CP(NOT_PROVIDER, NOT_PROVIDER) },
+       { 65000, 6666, CP(NOT_PROVIDER, NOT_PROVIDER) },
 };
 
 struct aspath_test     aspath_testset[] = {
@@ -225,198 +215,161 @@ struct aspath_test      aspath_testset[] = {
  */
 struct aspa_test       aspa_testset[] = {
        /* empty ASPATH are invalid by default */
-       { (const uint32_t []) { }, 0, ROLE_CUSTOMER, AID_INET, ASPA_INVALID },
-       { (const uint32_t []) { }, 0, ROLE_PROVIDER, AID_INET, ASPA_INVALID },
-       { (const uint32_t []) { }, 0, ROLE_RS, AID_INET, ASPA_INVALID },
-       { (const uint32_t []) { }, 0, ROLE_RS_CLIENT, AID_INET, ASPA_INVALID },
-       { (const uint32_t []) { }, 0, ROLE_PEER, AID_INET, ASPA_INVALID },
-
-       { (const uint32_t []) { 2 }, 1, ROLE_RS_CLIENT, AID_INET, ASPA_VALID },
-       { (const uint32_t []) { 2 }, 1, ROLE_PEER, AID_INET, ASPA_VALID },
-
-       { (const uint32_t []) { 3 }, 1, ROLE_PROVIDER, AID_INET, ASPA_VALID },
-       { (const uint32_t []) { 4 }, 1, ROLE_CUSTOMER, AID_INET, ASPA_VALID },
-       { (const uint32_t []) { 5 }, 1, ROLE_CUSTOMER, AID_INET, ASPA_VALID },
-       { (const uint32_t []) { 6 }, 1, ROLE_CUSTOMER, AID_INET, ASPA_VALID },
-
-       { (const uint32_t []) { 7 }, 1, ROLE_PROVIDER, AID_INET, ASPA_VALID },
-       { (const uint32_t []) { 7 }, 1, ROLE_PEER, AID_INET, ASPA_VALID },
-       { (const uint32_t []) { 7 }, 1, ROLE_RS_CLIENT, AID_INET, ASPA_VALID },
-
-       { (const uint32_t []) { 2, 8 }, 2, ROLE_PEER, AID_INET, ASPA_INVALID },
-       { (const uint32_t []) { 2, 8 }, 2, ROLE_RS_CLIENT, AID_INET,
-           ASPA_INVALID },
-
-       { (const uint32_t []) { 2, 9 }, 2, ROLE_PEER, AID_INET, ASPA_VALID },
-       { (const uint32_t []) { 2, 9 }, 2, ROLE_RS_CLIENT, AID_INET,
-           ASPA_VALID },
-
-       { (const uint32_t []) { 2, 10 }, 2, ROLE_PEER, AID_INET, ASPA_INVALID },
-       { (const uint32_t []) { 2, 10 }, 2, ROLE_RS_CLIENT, AID_INET,
-           ASPA_INVALID },
-
-       { (const uint32_t []) { 2, 11 }, 2, ROLE_PEER, AID_INET, ASPA_VALID },
-       { (const uint32_t []) { 2, 11 }, 2, ROLE_RS_CLIENT, AID_INET,
-           ASPA_VALID },
-
-       { (const uint32_t []) { 3, 8 }, 2, ROLE_PROVIDER, AID_INET,
-           ASPA_INVALID },
-       { (const uint32_t []) { 3, 12 }, 2, ROLE_PROVIDER, AID_INET,
-           ASPA_VALID },
-       { (const uint32_t []) { 3, 13 }, 2, ROLE_PROVIDER, AID_INET,
-           ASPA_INVALID },
-       { (const uint32_t []) { 3, 14 }, 2, ROLE_PROVIDER, AID_INET,
-           ASPA_VALID },
-
-       { (const uint32_t []) { 4, 8 }, 2, ROLE_CUSTOMER, AID_INET,
-           ASPA_VALID },
-       { (const uint32_t []) { 4, 15 }, 2, ROLE_CUSTOMER, AID_INET,
-           ASPA_VALID },
-       { (const uint32_t []) { 4, 16 }, 2, ROLE_CUSTOMER, AID_INET,
-           ASPA_VALID },
-       { (const uint32_t []) { 4, 24 }, 2, ROLE_CUSTOMER, AID_INET,
-           ASPA_VALID },
-
-       { (const uint32_t []) { 5, 8 }, 2, ROLE_CUSTOMER, AID_INET,
-           ASPA_VALID },
-       { (const uint32_t []) { 5, 17 }, 2, ROLE_CUSTOMER, AID_INET,
-           ASPA_VALID },
-       { (const uint32_t []) { 5, 25 }, 2, ROLE_CUSTOMER, AID_INET,
-           ASPA_VALID },
-       { (const uint32_t []) { 5, 26 }, 2, ROLE_CUSTOMER, AID_INET,
-           ASPA_VALID },
-
-       { (const uint32_t []) { 6, 18 }, 2, ROLE_CUSTOMER, AID_INET,
-           ASPA_VALID },
-       { (const uint32_t []) { 6, 19 }, 2, ROLE_CUSTOMER, AID_INET,
-           ASPA_VALID },
-
-       { (const uint32_t []) { 7, 19 }, 2, ROLE_PROVIDER, AID_INET,
-           ASPA_UNKNOWN },
-       { (const uint32_t []) { 7, 19 }, 2, ROLE_PEER, AID_INET,
-           ASPA_UNKNOWN },
-       { (const uint32_t []) { 7, 19 }, 2, ROLE_RS_CLIENT, AID_INET,
-           ASPA_UNKNOWN },
-       { (const uint32_t []) { 7, 21 }, 2, ROLE_PROVIDER, AID_INET,
-           ASPA_INVALID },
-       { (const uint32_t []) { 7, 21 }, 2, ROLE_PEER, AID_INET,
-           ASPA_INVALID },
-       { (const uint32_t []) { 7, 21 }, 2, ROLE_RS_CLIENT, AID_INET,
-           ASPA_INVALID },
-
-       { (const uint32_t []) { 6, 19, 20 }, 3, ROLE_CUSTOMER, AID_INET,
-           ASPA_VALID },
-       { (const uint32_t []) { 20, 19, 6 }, 3, ROLE_CUSTOMER, AID_INET,
-           ASPA_VALID },
-
-       { (const uint32_t []) { 3, 14, 25 }, 3, ROLE_PROVIDER, AID_INET,
-           ASPA_INVALID },
-       { (const uint32_t []) { 3, 14, 19 }, 3, ROLE_PROVIDER, AID_INET,
-           ASPA_UNKNOWN },
-       { (const uint32_t []) { 3, 14, 19 }, 3, ROLE_PEER, AID_INET,
-           ASPA_UNKNOWN },
-       { (const uint32_t []) { 3, 14, 19 }, 3, ROLE_RS_CLIENT, AID_INET,
-           ASPA_UNKNOWN },
-       { (const uint32_t []) { 3, 14, 21 }, 3, ROLE_PROVIDER, AID_INET,
-           ASPA_INVALID },
-       { (const uint32_t []) { 3, 14, 21 }, 3, ROLE_PEER, AID_INET,
-           ASPA_INVALID },
-       { (const uint32_t []) { 3, 14, 21 }, 3, ROLE_RS_CLIENT, AID_INET,
-           ASPA_INVALID },
-       { (const uint32_t []) { 3, 14, 27 }, 3, ROLE_PROVIDER, AID_INET,
-           ASPA_VALID },
-       { (const uint32_t []) { 3, 14, 27 }, 3, ROLE_PEER, AID_INET,
-           ASPA_VALID },
-       { (const uint32_t []) { 3, 14, 27 }, 3, ROLE_RS_CLIENT, AID_INET,
-           ASPA_VALID },
+       { (const uint32_t []) { }, 0, ROLE_CUSTOMER, ASPA_INVALID },
+       { (const uint32_t []) { }, 0, ROLE_PROVIDER, ASPA_INVALID },
+       { (const uint32_t []) { }, 0, ROLE_RS, ASPA_INVALID },
+       { (const uint32_t []) { }, 0, ROLE_RS_CLIENT, ASPA_INVALID },
+       { (const uint32_t []) { }, 0, ROLE_PEER, ASPA_INVALID },
+
+       { (const uint32_t []) { 2 }, 1, ROLE_RS_CLIENT, ASPA_VALID },
+       { (const uint32_t []) { 2 }, 1, ROLE_PEER, ASPA_VALID },
+
+       { (const uint32_t []) { 3 }, 1, ROLE_PROVIDER, ASPA_VALID },
+       { (const uint32_t []) { 4 }, 1, ROLE_CUSTOMER, ASPA_VALID },
+       { (const uint32_t []) { 5 }, 1, ROLE_CUSTOMER, ASPA_VALID },
+       { (const uint32_t []) { 6 }, 1, ROLE_CUSTOMER, ASPA_VALID },
+
+       { (const uint32_t []) { 7 }, 1, ROLE_PROVIDER, ASPA_VALID },
+       { (const uint32_t []) { 7 }, 1, ROLE_PEER, ASPA_VALID },
+       { (const uint32_t []) { 7 }, 1, ROLE_RS_CLIENT, ASPA_VALID },
+
+       { (const uint32_t []) { 2, 8 }, 2, ROLE_PEER, ASPA_INVALID },
+       { (const uint32_t []) { 2, 8 }, 2, ROLE_RS_CLIENT, ASPA_INVALID },
+
+       { (const uint32_t []) { 2, 9 }, 2, ROLE_PEER, ASPA_VALID },
+       { (const uint32_t []) { 2, 9 }, 2, ROLE_RS_CLIENT, ASPA_VALID },
+
+       { (const uint32_t []) { 2, 10 }, 2, ROLE_PEER, ASPA_INVALID },
+       { (const uint32_t []) { 2, 10 }, 2, ROLE_RS_CLIENT, ASPA_INVALID },
+
+       { (const uint32_t []) { 2, 11 }, 2, ROLE_PEER, ASPA_VALID },
+       { (const uint32_t []) { 2, 11 }, 2, ROLE_RS_CLIENT, ASPA_VALID },
+
+       { (const uint32_t []) { 3, 8 }, 2, ROLE_PROVIDER, ASPA_INVALID },
+       { (const uint32_t []) { 3, 12 }, 2, ROLE_PROVIDER, ASPA_VALID },
+       { (const uint32_t []) { 3, 13 }, 2, ROLE_PROVIDER, ASPA_INVALID },
+       { (const uint32_t []) { 3, 14 }, 2, ROLE_PROVIDER, ASPA_VALID },
+
+       { (const uint32_t []) { 4, 8 }, 2, ROLE_CUSTOMER, ASPA_VALID },
+       { (const uint32_t []) { 4, 15 }, 2, ROLE_CUSTOMER, ASPA_VALID },
+       { (const uint32_t []) { 4, 16 }, 2, ROLE_CUSTOMER, ASPA_VALID },
+       { (const uint32_t []) { 4, 24 }, 2, ROLE_CUSTOMER, ASPA_VALID },
+
+       { (const uint32_t []) { 5, 8 }, 2, ROLE_CUSTOMER, ASPA_VALID },
+       { (const uint32_t []) { 5, 17 }, 2, ROLE_CUSTOMER, ASPA_VALID },
+       { (const uint32_t []) { 5, 25 }, 2, ROLE_CUSTOMER, ASPA_VALID },
+       { (const uint32_t []) { 5, 26 }, 2, ROLE_CUSTOMER, ASPA_VALID },
+
+       { (const uint32_t []) { 6, 18 }, 2, ROLE_CUSTOMER, ASPA_VALID },
+       { (const uint32_t []) { 6, 19 }, 2, ROLE_CUSTOMER, ASPA_VALID },
+
+       { (const uint32_t []) { 7, 19 }, 2, ROLE_PROVIDER, ASPA_UNKNOWN },
+       { (const uint32_t []) { 7, 19 }, 2, ROLE_PEER, ASPA_UNKNOWN },
+       { (const uint32_t []) { 7, 19 }, 2, ROLE_RS_CLIENT, ASPA_UNKNOWN },
+       { (const uint32_t []) { 7, 21 }, 2, ROLE_PROVIDER, ASPA_INVALID },
+       { (const uint32_t []) { 7, 21 }, 2, ROLE_PEER, ASPA_INVALID },
+       { (const uint32_t []) { 7, 21 }, 2, ROLE_RS_CLIENT, ASPA_INVALID },
+
+       { (const uint32_t []) { 6, 19, 20 }, 3, ROLE_CUSTOMER, ASPA_VALID },
+       { (const uint32_t []) { 20, 19, 6 }, 3, ROLE_CUSTOMER, ASPA_VALID },
+
+       { (const uint32_t []) { 3, 14, 25 }, 3, ROLE_PROVIDER, ASPA_INVALID },
+       { (const uint32_t []) { 3, 14, 19 }, 3, ROLE_PROVIDER, ASPA_UNKNOWN },
+       { (const uint32_t []) { 3, 14, 19 }, 3, ROLE_PEER, ASPA_UNKNOWN },
+       { (const uint32_t []) { 3, 14, 19 }, 3, ROLE_RS_CLIENT, ASPA_UNKNOWN },
+       { (const uint32_t []) { 3, 14, 21 }, 3, ROLE_PROVIDER, ASPA_INVALID },
+       { (const uint32_t []) { 3, 14, 21 }, 3, ROLE_PEER, ASPA_INVALID },
+       { (const uint32_t []) { 3, 14, 21 }, 3, ROLE_RS_CLIENT, ASPA_INVALID },
+       { (const uint32_t []) { 3, 14, 27 }, 3, ROLE_PROVIDER, ASPA_VALID },
+       { (const uint32_t []) { 3, 14, 27 }, 3, ROLE_PEER, ASPA_VALID },
+       { (const uint32_t []) { 3, 14, 27 }, 3, ROLE_RS_CLIENT, ASPA_VALID },
        
-       { (const uint32_t []) { 7, 19, 22, 21 }, 4, ROLE_PROVIDER, AID_INET,
+       { (const uint32_t []) { 7, 19, 22, 21 }, 4, ROLE_PROVIDER,
            ASPA_INVALID },
-       { (const uint32_t []) { 7, 19, 22, 21 }, 4, ROLE_PEER, AID_INET,
-           ASPA_INVALID },
-       { (const uint32_t []) { 7, 19, 22, 21 }, 4, ROLE_RS_CLIENT, AID_INET,
+       { (const uint32_t []) { 7, 19, 22, 21 }, 4, ROLE_PEER, ASPA_INVALID },
+       { (const uint32_t []) { 7, 19, 22, 21 }, 4, ROLE_RS_CLIENT,
            ASPA_INVALID },
 
-       { (const uint32_t []) { 6, 19, 22, 23 }, 4, ROLE_CUSTOMER, AID_INET,
+       { (const uint32_t []) { 6, 19, 22, 23 }, 4, ROLE_CUSTOMER,
            ASPA_UNKNOWN },
 
        { (const uint32_t []) { 1, 5, 17, 13, 3, 14, 27 }, 7, ROLE_CUSTOMER,
-           AID_INET, ASPA_VALID },
+           ASPA_VALID },
        { (const uint32_t []) { 27, 14, 3, 13, 17, 5, 1 }, 7, ROLE_CUSTOMER,
-           AID_INET, ASPA_VALID },
+           ASPA_VALID },
 
        { (const uint32_t []) { 27, 14, 3, 6, 7, 19, 17, 5, 1 }, 9,
-           ROLE_CUSTOMER, AID_INET, ASPA_INVALID },
+           ROLE_CUSTOMER, ASPA_INVALID },
        { (const uint32_t []) { 27, 14, 3, 7, 19, 6, 1, 5, 17 }, 9,
-           ROLE_CUSTOMER, AID_INET, ASPA_UNKNOWN },
+           ROLE_CUSTOMER, ASPA_UNKNOWN },
 
        /* check L < K (ramps overlap) */
        { (const uint32_t []) { 201, 202, 203, 103, 102, 101 }, 6,
-           ROLE_CUSTOMER, AID_INET, ASPA_VALID },
+           ROLE_CUSTOMER, ASPA_VALID },
        { (const uint32_t []) { 101, 102, 103, 203, 202, 201 }, 6,
-           ROLE_CUSTOMER, AID_INET, ASPA_VALID },
+           ROLE_CUSTOMER, ASPA_VALID },
 
        /* check L == K (ramps touch) 203 ?> 111 <? 103 */
        { (const uint32_t []) { 201, 202, 203, 111, 103, 102, 101 }, 7,
-           ROLE_CUSTOMER, AID_INET, ASPA_VALID },
+           ROLE_CUSTOMER, ASPA_VALID },
        { (const uint32_t []) { 101, 102, 103, 111, 203, 202, 201 }, 7,
-           ROLE_CUSTOMER, AID_INET, ASPA_VALID },
+           ROLE_CUSTOMER, ASPA_VALID },
        /* check L == K (ramps touch) 203 -> 111 <- 103 */
        { (const uint32_t []) { 201, 202, 203, 112, 103, 102, 101 }, 7,
-           ROLE_CUSTOMER, AID_INET, ASPA_VALID },
+           ROLE_CUSTOMER, ASPA_VALID },
        { (const uint32_t []) { 101, 102, 103, 112, 203, 202, 201 }, 7,
-           ROLE_CUSTOMER, AID_INET, ASPA_VALID },
+           ROLE_CUSTOMER, ASPA_VALID },
 
        /* check L - K == 1 (204 ?? 104) */
        { (const uint32_t []) { 201, 202, 204, 104, 102, 101 }, 6,
-           ROLE_CUSTOMER, AID_INET, ASPA_VALID },
+           ROLE_CUSTOMER, ASPA_VALID },
        /* check L - K == 1 (204 -? 105) */
        { (const uint32_t []) { 201, 202, 204, 105, 102, 101 }, 6,
-           ROLE_CUSTOMER, AID_INET, ASPA_VALID },
+           ROLE_CUSTOMER, ASPA_VALID },
        /* check L - K == 1 (205 ?- 104) */
        { (const uint32_t []) { 201, 202, 205, 104, 102, 101 }, 6,
-           ROLE_CUSTOMER, AID_INET, ASPA_VALID },
+           ROLE_CUSTOMER, ASPA_VALID },
        /* check L - K == 1 (205 -- 105) */
        { (const uint32_t []) { 201, 202, 205, 105, 102, 101 }, 6,
-           ROLE_CUSTOMER, AID_INET, ASPA_VALID },
+           ROLE_CUSTOMER, ASPA_VALID },
 
        /* check L - K == 2 invalid cases (205 ?- 111 -? 105) */
        { (const uint32_t []) { 201, 202, 205, 111, 105, 102, 101 }, 7,
-           ROLE_CUSTOMER, AID_INET, ASPA_INVALID },
+           ROLE_CUSTOMER, ASPA_INVALID },
        /* check L - K == 2 invalid cases (205 -- 112 -- 105) */
        { (const uint32_t []) { 201, 202, 205, 112, 105, 102, 101 }, 7,
-           ROLE_CUSTOMER, AID_INET, ASPA_INVALID },
+           ROLE_CUSTOMER, ASPA_INVALID },
        /* check L - K == 2 invalid cases (205 <- 113 -> 105) */
        { (const uint32_t []) { 201, 202, 205, 113, 105, 102, 101 }, 7,
-           ROLE_CUSTOMER, AID_INET, ASPA_INVALID },
+           ROLE_CUSTOMER, ASPA_INVALID },
 
        /* check L - K == 2 unknown cases (205 ?- 111 ?? 104) */
        { (const uint32_t []) { 201, 202, 205, 111, 104, 102, 101 }, 7,
-           ROLE_CUSTOMER, AID_INET, ASPA_UNKNOWN },
+           ROLE_CUSTOMER, ASPA_UNKNOWN },
        /* check L - K == 2 unknown cases (204 ?? 111 -? 105) */
        { (const uint32_t []) { 201, 202, 204, 111, 105, 102, 101 }, 7,
-           ROLE_CUSTOMER, AID_INET, ASPA_UNKNOWN },
+           ROLE_CUSTOMER, ASPA_UNKNOWN },
        /* check L - K == 2 unknown cases (204 ?? 111 ?? 104) */
        { (const uint32_t []) { 201, 202, 204, 111, 104, 102, 101 }, 7,
-           ROLE_CUSTOMER, AID_INET, ASPA_UNKNOWN },
+           ROLE_CUSTOMER, ASPA_UNKNOWN },
        /* check L - K == 2 unknown cases (205 -- 112 ?- 104) */
        { (const uint32_t []) { 201, 202, 205, 112, 104, 102, 101 }, 7,
-           ROLE_CUSTOMER, AID_INET, ASPA_UNKNOWN },
+           ROLE_CUSTOMER, ASPA_UNKNOWN },
        /* check L - K == 2 unknown cases (204 -? 112 -- 105) */
        { (const uint32_t []) { 201, 202, 204, 112, 105, 102, 101 }, 7,
-           ROLE_CUSTOMER, AID_INET, ASPA_UNKNOWN },
+           ROLE_CUSTOMER, ASPA_UNKNOWN },
        /* check L - K == 2 unknown cases (204 -? 112 ?- 104) */
        { (const uint32_t []) { 201, 202, 204, 112, 104, 102, 101 }, 7,
-           ROLE_CUSTOMER, AID_INET, ASPA_UNKNOWN },
+           ROLE_CUSTOMER, ASPA_UNKNOWN },
        /* check L - K == 2 unknown cases (205 <- 113 ?> 104) */
        { (const uint32_t []) { 201, 202, 205, 113, 104, 102, 101 }, 7,
-           ROLE_CUSTOMER, AID_INET, ASPA_UNKNOWN },
+           ROLE_CUSTOMER, ASPA_UNKNOWN },
        /* check L - K == 2 unknown cases (204 <? 113 -> 105) */
        { (const uint32_t []) { 201, 202, 204, 113, 105, 102, 101 }, 7,
-           ROLE_CUSTOMER, AID_INET, ASPA_UNKNOWN },
+           ROLE_CUSTOMER, ASPA_UNKNOWN },
        /* check L - K == 2 unknown cases (204 <? 113 ?> 104) */
        { (const uint32_t []) { 201, 202, 204, 113, 104, 102, 101 }, 7,
-           ROLE_CUSTOMER, AID_INET, ASPA_UNKNOWN },
+           ROLE_CUSTOMER, ASPA_UNKNOWN },
 };
 
 static struct rde_aspa *
@@ -443,6 +396,21 @@ load_test_set(struct aspa_test_set *test
        return aspa;
 }
 
+static uint8_t
+vstate_for_role(struct rde_aspa_state *vstate, enum role role)
+{
+       if (vstate->onlyup_v4 != vstate->onlyup_v6 ||
+           vstate->downup_v4 != vstate->downup_v6) {
+               printf("failed: vstate differ per AID ");
+                       return 0xff;
+       }
+
+       if (role != ROLE_CUSTOMER) {
+               return (vstate->onlyup_v4);
+       } else {
+               return (vstate->downup_v4);
+       }
+}
 
 int
 main(int argc, char **argv)
@@ -464,9 +432,9 @@ main(int argc, char **argv)
 
        printf("testing aspa_cp_lookup: ");
        for (i = 0; i < num_cp; i++) {
-               enum cp_res r;
+               uint8_t r;
                r = aspa_cp_lookup(aspa, cp_testset[i].customeras,
-                   cp_testset[i].provideras, cp_testset[i].aid);
+                   cp_testset[i].provideras);
 
                if (cp_testset[i].expected_result != r) {
                        printf("failed: cp_testset[%zu]: "
@@ -483,12 +451,13 @@ main(int argc, char **argv)
 
        printf("testing aspa_check_aspath: ");
        for (i = 0; i < num_aspath; i++) {
-               struct aspa_state st, revst;
+               struct aspa_state st[2], revst;
                struct aspath *a;
 
+               memset(st, 0, sizeof(st));
                a = build_aspath(aspath_testset[i].aspath,
                    aspath_testset[i].aspathcnt, 0);
-               if (aspa_check_aspath(aspa, a, 1, AID_INET, &st) == -1) {
+               if (aspa_check_aspath(aspa, a, st) == -1) {
                        printf("failed: aspath_testset[%zu]: "
                            "aspath %s got -1\n", i,
                            print_aspath(aspath_testset[i].aspath,
@@ -496,20 +465,30 @@ main(int argc, char **argv)
                        aspath_failed = 1;
                }
 
-               if (memcmp(&aspath_testset[i].state, &st, sizeof(st))) {
+               if (memcmp(&aspath_testset[i].state, st, sizeof(*st))) {
                        printf("failed: aspath_testset[%zu]: aspath %s "
                            "bad state", i,
                            print_aspath(aspath_testset[i].aspath,
                            aspath_testset[i].aspathcnt));
-                       print_state(&aspath_testset[i].state, &st);
+                       print_state(&aspath_testset[i].state, st);
+                       printf("\n");
+                       aspath_failed = 1;
+               }
+               if (memcmp(&aspath_testset[i].state, st + 1, sizeof(*st))) {
+                       printf("failed: aspath_testset[%zu]: aspath %s "
+                           "bad state AID_INET6", i,
+                           print_aspath(aspath_testset[i].aspath,
+                           aspath_testset[i].aspathcnt));
+                       print_state(&aspath_testset[i].state, st + 1);
                        printf("\n");
                        aspath_failed = 1;
                }
                free(a);
 
+               memset(st, 0, sizeof(st));
                a = build_aspath(aspath_testset[i].aspath,
                    aspath_testset[i].aspathcnt, 1);
-               if (aspa_check_aspath(aspa, a, 1, AID_INET, &st) == -1) {
+               if (aspa_check_aspath(aspa, a, st) == -1) {
                        printf("failed: reverse aspath_testset[%zu]: "
                            "aspath %s got -1\n", i,
                            print_aspath(aspath_testset[i].aspath,
@@ -518,12 +497,21 @@ main(int argc, char **argv)
                }
 
                reverse_state(&aspath_testset[i].state, &revst);
-               if (memcmp(&revst, &st, sizeof(st))) {
+               if (memcmp(&revst, st, sizeof(*st))) {
                        printf("failed: reverse aspath_testset[%zu]: aspath %s "
                            "bad state", i,
                            print_aspath(aspath_testset[i].aspath,
                            aspath_testset[i].aspathcnt));
-                       print_state(&revst, &st);
+                       print_state(&revst, st);
+                       printf("\n");
+                       aspath_failed = 1;
+               }
+               if (memcmp(&revst, st + 1, sizeof(*st))) {
+                       printf("failed: reverse aspath_testset[%zu]: aspath %s "
+                           "bad state AID_INET6", i,
+                           print_aspath(aspath_testset[i].aspath,
+                           aspath_testset[i].aspathcnt));
+                       print_state(&revst, st + 1);
                        printf("\n");
                        aspath_failed = 1;
                }
@@ -535,12 +523,14 @@ main(int argc, char **argv)
        printf("testing aspa_validation: ");
        for (i = 0; i < num_aspa; i++) {
                struct aspath *a;
+               struct rde_aspa_state vstate;
                uint8_t rv;
 
                a = build_aspath(aspa_testset[i].aspath,
                    aspa_testset[i].aspathcnt, 0);
-               rv = aspa_validation(aspa, aspa_testset[i].role, a,
-                   aspa_testset[i].aid);
+               aspa_validation(aspa, a, &vstate);
+
+               rv = vstate_for_role(&vstate, aspa_testset[i].role);
 
                if (aspa_testset[i].expected_result != rv) {
                        printf("failed: aspa_testset[%zu]: aspath %s role %d "

Reply via email to