Assign a local path_id to all prefixes
authorclaudio <claudio@openbsd.org>
Fri, 8 Jul 2022 08:11:25 +0000 (08:11 +0000)
committerclaudio <claudio@openbsd.org>
Fri, 8 Jul 2022 08:11:25 +0000 (08:11 +0000)
For add-path a unique path_id needs to be assigne to all prefixes.
Use a random number since the RFC explicitly mentions that there is no
meaning what the value means. The local path_id is inherited to all
the RIBs. Adj-RIB-Out handling is not yet down.
OK tb@

usr.sbin/bgpd/rde.c
usr.sbin/bgpd/rde.h
usr.sbin/bgpd/rde_rib.c

index 4a1c515..0e34027 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: rde.c,v 1.551 2022/07/07 13:55:52 claudio Exp $ */
+/*     $OpenBSD: rde.c,v 1.552 2022/07/08 08:11:25 claudio Exp $ */
 
 /*
  * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -1600,6 +1600,46 @@ done:
        rde_filterstate_clean(&state);
 }
 
+/*
+ * Check if path_id is already in use.
+ */
+static int
+pathid_conflict(struct rib_entry *re, uint32_t pathid)
+{
+       struct prefix *p;
+
+       if (re == NULL)
+               return 0;
+
+       TAILQ_FOREACH(p, &re->prefix_h, entry.list.rib)
+               if (p->path_id_tx == pathid)
+                       return 1;
+       return 0;
+}
+
+static uint32_t
+pathid_assign(struct rde_peer *peer, uint32_t path_id,
+    struct bgpd_addr *prefix, uint8_t prefixlen)
+{
+       struct rib_entry *re;
+       struct prefix *p = NULL;
+       uint32_t path_id_tx;
+
+       /* Assign a send side path_id to all paths */
+       re = rib_get(rib_byid(RIB_ADJ_IN), prefix, prefixlen);
+       if (re != NULL)
+               p = prefix_bypeer(re, peer, path_id);
+       if (p != NULL)
+               path_id_tx = p->path_id_tx;
+       else {
+               do {
+                       /* assign new local path_id */
+                       path_id_tx = arc4random();
+               } while (pathid_conflict(re, path_id_tx));
+       }
+       return path_id_tx;
+}
+
 int
 rde_update_update(struct rde_peer *peer, uint32_t path_id,
     struct filterstate *in, struct bgpd_addr *prefix, uint8_t prefixlen)
@@ -1608,15 +1648,18 @@ rde_update_update(struct rde_peer *peer, uint32_t path_id,
        enum filter_actions      action;
        uint8_t                  vstate;
        uint16_t                 i;
+       uint32_t                 path_id_tx;
        const char              *wmsg = "filtered, withdraw";
 
        peer->prefix_rcvd_update++;
        vstate = rde_roa_validity(&rde_roa, prefix, prefixlen,
            aspath_origin(in->aspath.aspath));
 
+       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, in,
-           prefix, prefixlen, vstate) == 1)
+       if (prefix_update(rib_byid(RIB_ADJ_IN), peer, path_id, path_id_tx,
+           in, prefix, prefixlen, vstate) == 1)
                peer->prefix_cnt++;
 
        /* max prefix checker */
@@ -1644,8 +1687,8 @@ rde_update_update(struct rde_peer *peer, uint32_t path_id,
                        rde_update_log("update", i, peer,
                            &state.nexthop->exit_nexthop, prefix,
                            prefixlen);
-                       prefix_update(rib, peer, path_id, &state, prefix,
-                           prefixlen, vstate);
+                       prefix_update(rib, peer, path_id, path_id_tx, &state,
+                           prefix, prefixlen, vstate);
                } else if (prefix_withdraw(rib, peer, path_id, prefix,
                    prefixlen)) {
                        rde_update_log(wmsg, i, peer,
@@ -3719,7 +3762,8 @@ rde_softreconfig_in(struct rib_entry *re, void *bula)
 
                        if (action == ACTION_ALLOW) {
                                /* update Local-RIB */
-                               prefix_update(rib, peer, p->path_id, &state,
+                               prefix_update(rib, peer, p->path_id,
+                                   p->path_id_tx, &state,
                                    &prefix, pt->prefixlen,
                                    p->validation_state);
                        } else if (action == ACTION_DENY) {
@@ -3858,7 +3902,8 @@ rde_roa_softreload(struct rib_entry *re, void *bula)
 
                        if (action == ACTION_ALLOW) {
                                /* update Local-RIB */
-                               prefix_update(rib, peer, p->path_id, &state,
+                               prefix_update(rib, peer, p->path_id,
+                                   p->path_id_tx, &state,
                                    &prefix, pt->prefixlen,
                                    p->validation_state);
                        } else if (action == ACTION_DENY) {
@@ -4026,6 +4071,7 @@ network_add(struct network_config *nc, struct filterstate *state)
        struct in6_addr          prefix6;
        uint8_t                  vstate;
        uint16_t                 i;
+       uint32_t                 path_id_tx;
 
        if (nc->rd != 0) {
                SIMPLEQ_FOREACH(vpn, &conf->l3vpns, entry) {
@@ -4087,8 +4133,9 @@ network_add(struct network_config *nc, struct filterstate *state)
 
        vstate = rde_roa_validity(&rde_roa, &nc->prefix,
            nc->prefixlen, aspath_origin(state->aspath.aspath));
-       if (prefix_update(rib_byid(RIB_ADJ_IN), peerself, 0, state, &nc->prefix,
-           nc->prefixlen, vstate) == 1)
+       path_id_tx = pathid_assign(peerself, 0, &nc->prefix, nc->prefixlen);
+       if (prefix_update(rib_byid(RIB_ADJ_IN), peerself, 0, path_id_tx,
+           state, &nc->prefix, nc->prefixlen, vstate) == 1)
                peerself->prefix_cnt++;
        for (i = RIB_LOC_START; i < rib_size; i++) {
                struct rib *rib = rib_byid(i);
@@ -4097,7 +4144,7 @@ network_add(struct network_config *nc, struct filterstate *state)
                rde_update_log("announce", i, peerself,
                    state->nexthop ? &state->nexthop->exit_nexthop : NULL,
                    &nc->prefix, nc->prefixlen);
-               prefix_update(rib, peerself, 0, state, &nc->prefix,
+               prefix_update(rib, peerself, 0, path_id_tx, state, &nc->prefix,
                    nc->prefixlen, vstate);
        }
        filterset_free(&nc->attrset);
index af61093..56c567f 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: rde.h,v 1.256 2022/07/07 12:16:04 claudio Exp $ */
+/*     $OpenBSD: rde.h,v 1.257 2022/07/08 08:11:25 claudio Exp $ */
 
 /*
  * Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org> and
@@ -611,7 +611,8 @@ struct prefix       *prefix_adjout_lookup(struct rde_peer *, struct bgpd_addr *,
                     int);
 struct prefix  *prefix_adjout_next(struct rde_peer *, struct prefix *);
 int             prefix_update(struct rib *, struct rde_peer *, uint32_t,
-                    struct filterstate *, struct bgpd_addr *, int, uint8_t);
+                    uint32_t, struct filterstate *, struct bgpd_addr *,
+                    int, uint8_t);
 int             prefix_withdraw(struct rib *, struct rde_peer *, uint32_t,
                    struct bgpd_addr *, int);
 void            prefix_add_eor(struct rde_peer *, uint8_t);
index 6977578..69db4e8 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: rde_rib.c,v 1.238 2022/05/23 13:40:12 deraadt Exp $ */
+/*     $OpenBSD: rde_rib.c,v 1.239 2022/07/08 08:11:25 claudio Exp $ */
 
 /*
  * Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org>
@@ -842,7 +842,7 @@ path_put(struct rde_aspath *asp)
 /* prefix specific functions */
 
 static int     prefix_add(struct bgpd_addr *, int, struct rib *,
-                   struct rde_peer *, uint32_t, struct rde_aspath *,
+                   struct rde_peer *, uint32_t, uint32_t, struct rde_aspath *,
                    struct rde_community *, struct nexthop *,
                    uint8_t, uint8_t);
 static int     prefix_move(struct prefix *, struct rde_peer *,
@@ -850,7 +850,7 @@ static int  prefix_move(struct prefix *, struct rde_peer *,
                    struct nexthop *, uint8_t, uint8_t);
 
 static void    prefix_link(struct prefix *, struct rib_entry *,
-                    struct pt_entry *, struct rde_peer *, uint32_t,
+                    struct pt_entry *, struct rde_peer *, uint32_t, uint32_t,
                     struct rde_aspath *, struct rde_community *,
                     struct nexthop *, uint8_t, uint8_t);
 static void    prefix_unlink(struct prefix *);
@@ -1001,8 +1001,8 @@ prefix_adjout_match(struct rde_peer *peer, struct bgpd_addr *addr)
  */
 int
 prefix_update(struct rib *rib, struct rde_peer *peer, uint32_t path_id,
-    struct filterstate *state, struct bgpd_addr *prefix, int prefixlen,
-    uint8_t vstate)
+    uint32_t path_id_tx, struct filterstate *state, struct bgpd_addr *prefix,
+    int prefixlen, uint8_t vstate)
 {
        struct rde_aspath       *asp, *nasp = &state->aspath;
        struct rde_community    *comm, *ncomm = &state->communities;
@@ -1012,6 +1012,8 @@ prefix_update(struct rib *rib, struct rde_peer *peer, uint32_t path_id,
         * First try to find a prefix in the specified RIB.
         */
        if ((p = prefix_get(rib, peer, path_id, prefix, prefixlen)) != NULL) {
+               if (path_id_tx != p->path_id_tx)
+                       fatalx("path_id mismatch");
                if (prefix_nexthop(p) == state->nexthop &&
                    prefix_nhflags(p) == state->nhflags &&
                    communities_equal(ncomm, prefix_communities(p)) &&
@@ -1044,8 +1046,9 @@ prefix_update(struct rib *rib, struct rde_peer *peer, uint32_t path_id,
                return (prefix_move(p, peer, asp, comm, state->nexthop,
                    state->nhflags, vstate));
        else
-               return (prefix_add(prefix, prefixlen, rib, peer, path_id, asp,
-                   comm, state->nexthop, state->nhflags, vstate));
+               return (prefix_add(prefix, prefixlen, rib, peer, path_id,
+                   path_id_tx, asp, comm, state->nexthop, state->nhflags,
+                   vstate));
 }
 
 /*
@@ -1053,9 +1056,9 @@ prefix_update(struct rib *rib, struct rde_peer *peer, uint32_t path_id,
  */
 static int
 prefix_add(struct bgpd_addr *prefix, int prefixlen, struct rib *rib,
-    struct rde_peer *peer, uint32_t path_id, struct rde_aspath *asp,
-    struct rde_community *comm, struct nexthop *nexthop, uint8_t nhflags,
-    uint8_t vstate)
+    struct rde_peer *peer, uint32_t path_id, uint32_t path_id_tx,
+    struct rde_aspath *asp, struct rde_community *comm,
+    struct nexthop *nexthop, uint8_t nhflags, uint8_t vstate)
 {
        struct prefix           *p;
        struct rib_entry        *re;
@@ -1065,8 +1068,8 @@ prefix_add(struct bgpd_addr *prefix, int prefixlen, struct rib *rib,
                re = rib_add(rib, prefix, prefixlen);
 
        p = prefix_alloc();
-       prefix_link(p, re, re->prefix, peer, path_id, asp, comm, nexthop,
-           nhflags, vstate);
+       prefix_link(p, re, re->prefix, peer, path_id, path_id_tx, asp, comm,
+           nexthop, nhflags, vstate);
 
        /* add possible pftable reference form aspath */
        if (asp && asp->pftableid)
@@ -1094,8 +1097,8 @@ prefix_move(struct prefix *p, struct rde_peer *peer,
 
        /* add new prefix node */
        np = prefix_alloc();
-       prefix_link(np, prefix_re(p), p->pt, peer, p->path_id, asp, comm,
-           nexthop, nhflags, vstate);
+       prefix_link(np, prefix_re(p), p->pt, peer, p->path_id, p->path_id_tx,
+           asp, comm, nexthop, nhflags, vstate);
 
        /* add possible pftable reference from new aspath */
        if (asp && asp->pftableid)
@@ -1232,8 +1235,8 @@ prefix_adjout_update(struct rde_peer *peer, struct filterstate *state,
                comm = communities_link(&state->communities);
        }
 
-       prefix_link(p, NULL, p->pt, peer, 0, asp, comm, state->nexthop,
-           state->nhflags, vstate);
+       prefix_link(p, NULL, p->pt, peer, 0, /* XXX */ 0, asp, comm,
+           state->nexthop, state->nhflags, vstate);
        peer->prefix_out_cnt++;
 
        if (p->flags & PREFIX_FLAG_MASK)
@@ -1549,9 +1552,9 @@ prefix_destroy(struct prefix *p)
  */
 static void
 prefix_link(struct prefix *p, struct rib_entry *re, struct pt_entry *pt,
-    struct rde_peer *peer, uint32_t path_id, struct rde_aspath *asp,
-    struct rde_community *comm, struct nexthop *nexthop, uint8_t nhflags,
-    uint8_t vstate)
+    struct rde_peer *peer, uint32_t path_id, uint32_t path_id_tx,
+    struct rde_aspath *asp, struct rde_community *comm,
+    struct nexthop *nexthop, uint8_t nhflags, uint8_t vstate)
 {
        if (re)
                p->entry.list.re = re;
@@ -1560,6 +1563,7 @@ prefix_link(struct prefix *p, struct rib_entry *re, struct pt_entry *pt,
        p->peer = peer;
        p->pt = pt_ref(pt);
        p->path_id = path_id;
+       p->path_id_tx = path_id_tx;
        p->validation_state = vstate;
        p->nhflags = nhflags;
        p->nexthop = nexthop_ref(nexthop);