On Fri, Aug 06, 2021 at 08:34:18PM +0200, Sebastian Benoit wrote:
> Claudio Jeker(cje...@diehard.n-r-g.com) on 2021.08.04 17:55:45 +0200:
> > On Fri, Jul 30, 2021 at 12:02:12PM +0200, Claudio Jeker wrote:
> > > This diff implements the bit to support the receive side of
> > > RFC7911 - Advertisement of Multiple Paths in BGP.
> > > 
> > > I did some basic tests and it works for me. People running route
> > > collectors should give this a try. The interaction of Add-Path and bgpctl
> > > probably needs some work. Also the MRT dumper needs to be updated to
> > > support RFC8050. I have a partial diff for that ready as well.
> > > 
> > > Sending out multiple paths will follow in a later step since that is a
> > > bit more complex. I still need to decide how stable I want to make the
> > > assigned path_ids for the multiple paths and then changes to the decision
> > > process and adjrib-out are required to allow multipe paths there.
> > 
> > Updated diff that includes some minimal support for bgpctl.
> > This add 'bgpctl show rib nei foo path-id 42' as a way to limit which
> > paths to show. Now the RFC itself is very flexible in how path-ids are
> > assigned (it is possible that different prefixes have different path-ids)
> > but the assumtion is that most systems assign path-id in a stable way and
> > so it makes sense to allow to filter on path-id.
> > Apart from that not much changed.
> 
> ok benno@

Thanks a lot :)
 
> Only one thing, I worry that using this while the sending side is not working 
> can lead to
> blackholing of prefixes.
> 

Add-path allows for send / recv to be independent and so this is would me
more of a common issue with add-path. In general having more paths to
select from should help to stop oscilation (e.g. with route reflectors)
but I think this is frequently used to collect routes and still get full
views. Not sure if blackholing is possible (in the end there are more
routes to select from available) but route loops could be an issue.

By default add-path is disabled and that will remain. I agree that
operators need to evaluate carefully what add-path will give them.

Also plan is to finish the MRT support for add-path and then work on
add-path send. So this should arrive soon as well :)

-- 
:wq Claudio

> > 
> > -- 
> > :wq Claudio
> > 
> > Index: bgpctl/bgpctl.8
> > ===================================================================
> > RCS file: /cvs/src/usr.sbin/bgpctl/bgpctl.8,v
> > retrieving revision 1.99
> > diff -u -p -r1.99 bgpctl.8
> > --- bgpctl/bgpctl.8 16 Jun 2021 16:24:12 -0000      1.99
> > +++ bgpctl/bgpctl.8 4 Aug 2021 13:15:53 -0000
> > @@ -348,6 +348,13 @@ Show RIB memory statistics.
> >  Show only entries from the specified peer.
> >  .It Cm neighbor group Ar description
> >  Show only entries from the specified peer group.
> > +.It Cm path-id Ar pathid
> > +Show only entries which match the specified
> > +.Ar pathid .
> > +Must be used together with either
> > +.Cm neighbor
> > +or
> > +.Cm out .
> >  .It Cm peer-as Ar as
> >  Show all entries with
> >  .Ar as
> > Index: bgpctl/bgpctl.c
> > ===================================================================
> > RCS file: /cvs/src/usr.sbin/bgpctl/bgpctl.c,v
> > retrieving revision 1.272
> > diff -u -p -r1.272 bgpctl.c
> > --- bgpctl/bgpctl.c 2 Aug 2021 16:51:39 -0000       1.272
> > +++ bgpctl/bgpctl.c 4 Aug 2021 15:54:25 -0000
> > @@ -249,6 +249,7 @@ main(int argc, char *argv[])
> >             ribreq.neighbor = neighbor;
> >             strlcpy(ribreq.rib, res->rib, sizeof(ribreq.rib));
> >             ribreq.aid = res->aid;
> > +           ribreq.path_id = res->pathid;
> >             ribreq.flags = res->flags;
> >             imsg_compose(ibuf, type, 0, 0, -1, &ribreq, sizeof(ribreq));
> >             break;
> > Index: bgpctl/parser.c
> > ===================================================================
> > RCS file: /cvs/src/usr.sbin/bgpctl/parser.c,v
> > retrieving revision 1.106
> > diff -u -p -r1.106 parser.c
> > --- bgpctl/parser.c 16 Feb 2021 08:30:21 -0000      1.106
> > +++ bgpctl/parser.c 4 Aug 2021 13:08:31 -0000
> > @@ -61,7 +61,8 @@ enum token_type {
> >     RD,
> >     FAMILY,
> >     RTABLE,
> > -   FILENAME
> > +   FILENAME,
> > +   PATHID,
> >  };
> >  
> >  struct token {
> > @@ -114,6 +115,7 @@ static const struct token t_log[];
> >  static const struct token t_fib_table[];
> >  static const struct token t_show_fib_table[];
> >  static const struct token t_communication[];
> > +static const struct token t_show_rib_path[];
> >  
> >  static const struct token t_main[] = {
> >     { KEYWORD,      "reload",       RELOAD,         t_communication},
> > @@ -178,10 +180,11 @@ static const struct token t_show_rib[] =
> >     { FLAG,         "in",           F_CTL_ADJ_IN,   t_show_rib},
> >     { FLAG,         "out",          F_CTL_ADJ_OUT,  t_show_rib},
> >     { KEYWORD,      "neighbor",     NONE,           t_show_rib_neigh},
> > +   { KEYWORD,      "ovs",          NONE,           t_show_ovs},
> > +   { KEYWORD,      "path-id",      NONE,           t_show_rib_path},
> >     { KEYWORD,      "table",        NONE,           t_show_rib_rib},
> >     { KEYWORD,      "summary",      SHOW_SUMMARY,   t_show_summary},
> >     { KEYWORD,      "memory",       SHOW_RIB_MEM,   NULL},
> > -   { KEYWORD,      "ovs",          NONE,           t_show_ovs},
> >     { FAMILY,       "",             NONE,           t_show_rib},
> >     { PREFIX,       "",             NONE,           t_show_prefix},
> >     { ENDTOKEN,     "",             NONE,           NULL}
> > @@ -479,6 +482,11 @@ static const struct token t_show_fib_tab
> >     { ENDTOKEN,     "",                     NONE,   NULL}
> >  };
> >  
> > +static const struct token t_show_rib_path[] = {
> > +   { PATHID,       "",             NONE,   t_show_rib},
> > +   { ENDTOKEN,     "",             NONE,   NULL}
> > +};
> > +
> >  static struct parse_result res;
> >  
> >  const struct token *match_token(int *argc, char **argv[],
> > @@ -748,6 +756,7 @@ match_token(int *argc, char **argv[], co
> >             case PREPSELF:
> >             case WEIGHT:
> >             case RTABLE:
> > +           case PATHID:
> >                     if (word != NULL && wordlen > 0 &&
> >                         parse_number(word, &res, table[i].type)) {
> >                             match++;
> > @@ -863,6 +872,7 @@ show_valid_args(const struct token table
> >             case PREPNBR:
> >             case PREPSELF:
> >             case WEIGHT:
> > +           case PATHID:
> >                     fprintf(stderr, "  <number>\n");
> >                     break;
> >             case RTABLE:
> > @@ -1019,9 +1029,16 @@ parse_number(const char *word, struct pa
> >             errx(1, "number is %s: %s", errstr, word);
> >  
> >     /* number was parseable */
> > -   if (type == RTABLE) {
> > +   switch (type) {
> > +   case RTABLE:
> >             r->rtableid = uval;
> >             return (1);
> > +   case PATHID:
> > +           r->pathid = uval;
> > +           r->flags |= F_CTL_HAS_PATHID;
> > +           return (1);
> > +   default:
> > +           break;
> >     }
> >  
> >     if ((fs = calloc(1, sizeof(struct filter_set))) == NULL)
> > Index: bgpctl/parser.h
> > ===================================================================
> > RCS file: /cvs/src/usr.sbin/bgpctl/parser.h,v
> > retrieving revision 1.40
> > diff -u -p -r1.40 parser.h
> > --- bgpctl/parser.h 16 Feb 2021 08:30:21 -0000      1.40
> > +++ bgpctl/parser.h 4 Aug 2021 13:08:11 -0000
> > @@ -71,9 +71,10 @@ struct parse_result {
> >     u_int64_t                rd;
> >     int                      flags;
> >     int                      is_group;
> > -   u_int8_t                 validation_state;
> >     u_int                    rtableid;
> > +   u_int32_t                pathid;
> >     enum actions             action;
> > +   u_int8_t                 validation_state;
> >     u_int8_t                 prefixlen;
> >     u_int8_t                 aid;
> >     int                      mrtfd;
> > Index: bgpd/bgpd.conf.5
> > ===================================================================
> > RCS file: /cvs/src/usr.sbin/bgpd/bgpd.conf.5,v
> > retrieving revision 1.212
> > diff -u -p -r1.212 bgpd.conf.5
> > --- bgpd/bgpd.conf.5        13 Jul 2021 08:44:18 -0000      1.212
> > +++ bgpd/bgpd.conf.5        4 Aug 2021 15:53:42 -0000
> > @@ -809,6 +809,17 @@ The default is
> >  for the same address family of the session.
> >  .Pp
> >  .It Xo
> > +.Ic announce add-path recv
> > +.Pq Ic yes Ns | Ns Ic no
> > +.Xc
> > +If set to
> > +.Ic yes ,
> > +the receive add-path capability is announced which allows reception of 
> > multiple
> > +paths per prefix.
> > +The default is
> > +.Ic no .
> > +.Pp
> > +.It Xo
> >  .Ic announce as-4byte
> >  .Pq Ic yes Ns | Ns Ic no
> >  .Xc
> > Index: bgpd/bgpd.h
> > ===================================================================
> > RCS file: /cvs/src/usr.sbin/bgpd/bgpd.h,v
> > retrieving revision 1.416
> > diff -u -p -r1.416 bgpd.h
> > --- bgpd/bgpd.h     27 Jul 2021 07:32:08 -0000      1.416
> > +++ bgpd/bgpd.h     4 Aug 2021 13:07:11 -0000
> > @@ -95,6 +95,7 @@
> >  #define    F_CTL_OVS_INVALID       0x100000
> >  #define    F_CTL_OVS_NOTFOUND      0x200000
> >  #define    F_CTL_NEIGHBORS         0x400000 /* only used by bgpctl */
> > +#define    F_CTL_HAS_PATHID        0x800000 /* only set on requests */
> >  
> >  #define CTASSERT(x)        extern char  _ctassert[(x) ? 1 : -1 ] \
> >                         __attribute__((__unused__))
> > @@ -891,9 +892,10 @@ struct ctl_show_rib_request {
> >     struct filter_as        as;
> >     struct community        community;
> >     u_int32_t               flags;
> > -   u_int8_t                validation_state;
> > +   u_int32_t               path_id;
> >     pid_t                   pid;
> >     enum imsg_type          type;
> > +   u_int8_t                validation_state;
> >     u_int8_t                prefixlen;
> >     u_int8_t                aid;
> >  };
> > Index: bgpd/parse.y
> > ===================================================================
> > RCS file: /cvs/src/usr.sbin/bgpd/parse.y,v
> > retrieving revision 1.417
> > diff -u -p -r1.417 parse.y
> > --- bgpd/parse.y    17 Jun 2021 16:05:26 -0000      1.417
> > +++ bgpd/parse.y    22 Jun 2021 10:48:50 -0000
> > @@ -204,7 +204,8 @@ typedef struct {
> >  %token     GROUP NEIGHBOR NETWORK
> >  %token     EBGP IBGP
> >  %token     LOCALAS REMOTEAS DESCR LOCALADDR MULTIHOP PASSIVE MAXPREFIX 
> > RESTART
> > -%token     ANNOUNCE CAPABILITIES REFRESH AS4BYTE CONNECTRETRY ENHANCED
> > +%token     ANNOUNCE CAPABILITIES REFRESH AS4BYTE CONNECTRETRY ENHANCED 
> > ADDPATH
> > +%token     SEND RECV
> >  %token     DEMOTE ENFORCE NEIGHBORAS ASOVERRIDE REFLECTOR DEPEND DOWN
> >  %token     DUMP IN OUT SOCKET RESTRICTED
> >  %token     LOG TRANSPARENT
> > @@ -1455,6 +1456,16 @@ peeropts     : REMOTEAS as4number    {
> >             | ANNOUNCE AS4BYTE yesno {
> >                     curpeer->conf.capabilities.as4byte = $3;
> >             }
> > +           | ANNOUNCE ADDPATH RECV yesno {
> > +                   int8_t *ap = curpeer->conf.capabilities.add_path;
> > +                   u_int8_t i;
> > +
> > +                   for (i = 0; i < AID_MAX; i++)
> > +                           if ($4)
> > +                                   *ap++ |= CAPA_AP_RECV;
> > +                           else
> > +                                   *ap++ &= ~CAPA_AP_RECV;
> > +           }
> >             | EXPORT NONE {
> >                     curpeer->conf.export_type = EXPORT_NONE;
> >             }
> > @@ -2878,6 +2889,7 @@ lookup(char *s)
> >             { "AS",                 AS},
> >             { "IPv4",               IPV4},
> >             { "IPv6",               IPV6},
> > +           { "add-path",           ADDPATH},
> >             { "ah",                 AH},
> >             { "allow",              ALLOW},
> >             { "announce",           ANNOUNCE},
> > @@ -2965,6 +2977,7 @@ lookup(char *s)
> >             { "quick",              QUICK},
> >             { "rd",                 RD},
> >             { "rde",                RDE},
> > +           { "recv",               RECV},
> >             { "refresh",            REFRESH },
> >             { "reject",             REJECT},
> >             { "remote-as",          REMOTEAS},
> > @@ -2978,6 +2991,7 @@ lookup(char *s)
> >             { "rtlabel",            RTLABEL},
> >             { "rtr",                RTR},
> >             { "self",               SELF},
> > +           { "send",               SEND},
> >             { "set",                SET},
> >             { "socket",             SOCKET },
> >             { "source-as",          SOURCEAS},
> > Index: bgpd/rde.c
> > ===================================================================
> > RCS file: /cvs/src/usr.sbin/bgpd/rde.c,v
> > retrieving revision 1.531
> > diff -u -p -r1.531 rde.c
> > --- bgpd/rde.c      27 Jul 2021 07:50:01 -0000      1.531
> > +++ bgpd/rde.c      4 Aug 2021 15:31:02 -0000
> > @@ -50,10 +50,10 @@ void             rde_dispatch_imsg_parent(struct i
> >  void                rde_dispatch_imsg_rtr(struct imsgbuf *);
> >  void                rde_dispatch_imsg_peer(struct rde_peer *, void *);
> >  void                rde_update_dispatch(struct rde_peer *, struct imsg *);
> > -int                 rde_update_update(struct rde_peer *, struct 
> > filterstate *,
> > +int                 rde_update_update(struct rde_peer *, u_int32_t,
> > +                     struct filterstate *, struct bgpd_addr *, u_int8_t);
> > +void                rde_update_withdraw(struct rde_peer *, u_int32_t,
> >                  struct bgpd_addr *, u_int8_t);
> > -void                rde_update_withdraw(struct rde_peer *, struct 
> > bgpd_addr *,
> > -                u_int8_t);
> >  int                 rde_attr_parse(u_char *, u_int16_t, struct rde_peer *,
> >                  struct filterstate *, struct mpattr *);
> >  int                 rde_attr_add(struct filterstate *, u_char *, 
> > u_int16_t);
> > @@ -1183,7 +1183,7 @@ rde_update_dispatch(struct rde_peer *pee
> >     u_int16_t                attrpath_len;
> >     u_int16_t                nlri_len;
> >     u_int8_t                 aid, prefixlen, safi, subtype;
> > -   u_int32_t                fas;
> > +   u_int32_t                fas, pathid;
> >  
> >     p = imsg->data;
> >  
> > @@ -1288,6 +1288,21 @@ rde_update_dispatch(struct rde_peer *pee
> >                     goto done;
> >             }
> >  
> > +           if (peer_has_add_path(peer, AID_INET, CAPA_AP_RECV)) {
> > +                   if (len <= sizeof(pathid)) {
> > +                           log_peer_warnx(&peer->conf,
> > +                               "bad withdraw prefix");
> > +                           rde_update_err(peer, ERR_UPDATE,
> > +                               ERR_UPD_NETWORK, NULL, 0);
> > +                           goto done;
> > +                   }
> > +                   memcpy(&pathid, p, sizeof(pathid));
> > +                   pathid = ntohl(pathid);
> > +                   p += sizeof(pathid);
> > +                   len -= sizeof(pathid);
> > +           } else
> > +                   pathid = 0;
> > +
> >             if ((pos = nlri_get_prefix(p, len, &prefix,
> >                 &prefixlen)) == -1) {
> >                     /*
> > @@ -1302,7 +1317,7 @@ rde_update_dispatch(struct rde_peer *pee
> >             p += pos;
> >             len -= pos;
> >  
> > -           rde_update_withdraw(peer, &prefix, prefixlen);
> > +           rde_update_withdraw(peer, pathid, &prefix, prefixlen);
> >     }
> >  
> >     /* withdraw MP_UNREACH_NLRI if available */
> > @@ -1339,6 +1354,23 @@ rde_update_dispatch(struct rde_peer *pee
> >             }
> >  
> >             while (mplen > 0) {
> > +                   if (peer_has_add_path(peer, aid, CAPA_AP_RECV)) {
> > +                           if (mplen <= sizeof(pathid)) {
> > +                                   log_peer_warnx(&peer->conf,
> > +                                       "bad %s withdraw prefix",
> > +                                       aid2str(aid));
> > +                                   rde_update_err(peer, ERR_UPDATE,
> > +                                       ERR_UPD_OPTATTR,
> > +                                       mpa.unreach, mpa.unreach_len);
> > +                                   goto done;
> > +                           }
> > +                           memcpy(&pathid, mpp, sizeof(pathid));
> > +                           pathid = ntohl(pathid);
> > +                           mpp += sizeof(pathid);
> > +                           mplen -= sizeof(pathid);
> > +                   } else
> > +                           pathid = 0;
> > +
> >                     switch (aid) {
> >                     case AID_INET6:
> >                             if ((pos = nlri_get_prefix6(mpp, mplen,
> > @@ -1381,7 +1413,7 @@ rde_update_dispatch(struct rde_peer *pee
> >                     mpp += pos;
> >                     mplen -= pos;
> >  
> > -                   rde_update_withdraw(peer, &prefix, prefixlen);
> > +                   rde_update_withdraw(peer, pathid, &prefix, prefixlen);
> >             }
> >  
> >             if ((state.aspath.flags & ~F_ATTR_MP_UNREACH) == 0)
> > @@ -1401,6 +1433,21 @@ rde_update_dispatch(struct rde_peer *pee
> >                     goto done;
> >             }
> >  
> > +           if (peer_has_add_path(peer, AID_INET, CAPA_AP_RECV)) {
> > +                   if (nlri_len <= sizeof(pathid)) {
> > +                           log_peer_warnx(&peer->conf,
> > +                               "bad nlri prefix");
> > +                           rde_update_err(peer, ERR_UPDATE,
> > +                               ERR_UPD_NETWORK, NULL, 0);
> > +                           goto done;
> > +                   }
> > +                   memcpy(&pathid, p, sizeof(pathid));
> > +                   pathid = ntohl(pathid);
> > +                   p += sizeof(pathid);
> > +                   nlri_len -= sizeof(pathid);
> > +           } else
> > +                   pathid = 0;
> > +
> >             if ((pos = nlri_get_prefix(p, nlri_len, &prefix,
> >                 &prefixlen)) == -1) {
> >                     log_peer_warnx(&peer->conf, "bad nlri prefix");
> > @@ -1411,7 +1458,8 @@ rde_update_dispatch(struct rde_peer *pee
> >             p += pos;
> >             nlri_len -= pos;
> >  
> > -           if (rde_update_update(peer, &state, &prefix, prefixlen) == -1)
> > +           if (rde_update_update(peer, pathid, &state,
> > +               &prefix, prefixlen) == -1)
> >                     goto done;
> >  
> >     }
> > @@ -1456,6 +1504,22 @@ rde_update_dispatch(struct rde_peer *pee
> >             mplen -= pos;
> >  
> >             while (mplen > 0) {
> > +                   if (peer_has_add_path(peer, aid, CAPA_AP_RECV)) {
> > +                           if (mplen <= sizeof(pathid)) {
> > +                                   log_peer_warnx(&peer->conf,
> > +                                       "bad %s nlri prefix", aid2str(aid));
> > +                                   rde_update_err(peer, ERR_UPDATE,
> > +                                       ERR_UPD_OPTATTR,
> > +                                       mpa.reach, mpa.reach_len);
> > +                                   goto done;
> > +                           }
> > +                           memcpy(&pathid, mpp, sizeof(pathid));
> > +                           pathid = ntohl(pathid);
> > +                           mpp += sizeof(pathid);
> > +                           mplen -= sizeof(pathid);
> > +                   } else
> > +                           pathid = 0;
> > +
> >                     switch (aid) {
> >                     case AID_INET6:
> >                             if ((pos = nlri_get_prefix6(mpp, mplen,
> > @@ -1498,7 +1562,7 @@ rde_update_dispatch(struct rde_peer *pee
> >                     mpp += pos;
> >                     mplen -= pos;
> >  
> > -                   if (rde_update_update(peer, &state,
> > +                   if (rde_update_update(peer, pathid, &state,
> >                         &prefix, prefixlen) == -1)
> >                             goto done;
> >             }
> > @@ -1509,8 +1573,8 @@ done:
> >  }
> >  
> >  int
> > -rde_update_update(struct rde_peer *peer, struct filterstate *in,
> > -    struct bgpd_addr *prefix, u_int8_t prefixlen)
> > +rde_update_update(struct rde_peer *peer, u_int32_t path_id,
> > +    struct filterstate *in, struct bgpd_addr *prefix, u_int8_t prefixlen)
> >  {
> >     struct filterstate       state;
> >     enum filter_actions      action;
> > @@ -1523,8 +1587,8 @@ rde_update_update(struct rde_peer *peer,
> >         aspath_origin(in->aspath.aspath));
> >  
> >     /* add original path to the Adj-RIB-In */
> > -   if (prefix_update(rib_byid(RIB_ADJ_IN), peer, in, prefix, prefixlen,
> > -       vstate) == 1)
> > +   if (prefix_update(rib_byid(RIB_ADJ_IN), peer, path_id, in,
> > +       prefix, prefixlen, vstate) == 1)
> >             peer->prefix_cnt++;
> >  
> >     /* max prefix checker */
> > @@ -1552,9 +1616,9 @@ rde_update_update(struct rde_peer *peer,
> >                     rde_update_log("update", i, peer,
> >                         &state.nexthop->exit_nexthop, prefix,
> >                         prefixlen);
> > -                   prefix_update(rib, peer, &state, prefix,
> > +                   prefix_update(rib, peer, path_id, &state, prefix,
> >                         prefixlen, vstate);
> > -           } else if (prefix_withdraw(rib, peer, prefix,
> > +           } else if (prefix_withdraw(rib, peer, path_id, prefix,
> >                 prefixlen)) {
> >                     rde_update_log(wmsg, i, peer,
> >                         NULL, prefix, prefixlen);
> > @@ -1567,8 +1631,8 @@ rde_update_update(struct rde_peer *peer,
> >  }
> >  
> >  void
> > -rde_update_withdraw(struct rde_peer *peer, struct bgpd_addr *prefix,
> > -    u_int8_t prefixlen)
> > +rde_update_withdraw(struct rde_peer *peer, u_int32_t path_id,
> > +    struct bgpd_addr *prefix, u_int8_t prefixlen)
> >  {
> >     u_int16_t i;
> >  
> > @@ -1576,13 +1640,14 @@ rde_update_withdraw(struct rde_peer *pee
> >             struct rib *rib = rib_byid(i);
> >             if (rib == NULL)
> >                     continue;
> > -           if (prefix_withdraw(rib, peer, prefix, prefixlen))
> > +           if (prefix_withdraw(rib, peer, path_id, prefix, prefixlen))
> >                     rde_update_log("withdraw", i, peer, NULL, prefix,
> >                         prefixlen);
> >     }
> >  
> >     /* remove original path form the Adj-RIB-In */
> > -   if (prefix_withdraw(rib_byid(RIB_ADJ_IN), peer, prefix, prefixlen))
> > +   if (prefix_withdraw(rib_byid(RIB_ADJ_IN), peer, path_id,
> > +       prefix, prefixlen))
> >             peer->prefix_cnt--;
> >  
> >     peer->prefix_rcvd_withdraw++;
> > @@ -2292,28 +2357,31 @@ rde_reflector(struct rde_peer *peer, str
> >   * control specific functions
> >   */
> >  static void
> > -rde_dump_rib_as(struct prefix *p, struct rde_aspath *asp, pid_t pid, int 
> > flags)
> > +rde_dump_rib_as(struct prefix *p, struct rde_aspath *asp, pid_t pid, int 
> > flags,
> > +    int adjout)
> >  {
> >     struct ctl_show_rib      rib;
> >     struct ibuf             *wbuf;
> >     struct attr             *a;
> >     struct nexthop          *nexthop;
> >     struct rib_entry        *re;
> > +   struct rde_peer         *peer;
> >     void                    *bp;
> >     time_t                   staletime;
> >     size_t                   aslen;
> >     u_int8_t                 l;
> >  
> >     nexthop = prefix_nexthop(p);
> > +   peer = prefix_peer(p);
> >     bzero(&rib, sizeof(rib));
> >     rib.age = getmonotime() - p->lastchange;
> >     rib.local_pref = asp->lpref;
> >     rib.med = asp->med;
> >     rib.weight = asp->weight;
> > -   strlcpy(rib.descr, prefix_peer(p)->conf.descr, sizeof(rib.descr));
> > -   memcpy(&rib.remote_addr, &prefix_peer(p)->remote_addr,
> > +   strlcpy(rib.descr, peer->conf.descr, sizeof(rib.descr));
> > +   memcpy(&rib.remote_addr, &peer->remote_addr,
> >         sizeof(rib.remote_addr));
> > -   rib.remote_id = prefix_peer(p)->remote_bgpid;
> > +   rib.remote_id = peer->remote_bgpid;
> >     if (nexthop != NULL) {
> >             memcpy(&rib.true_nexthop, &nexthop->true_nexthop,
> >                 sizeof(rib.true_nexthop));
> > @@ -2334,7 +2402,7 @@ rde_dump_rib_as(struct prefix *p, struct
> >     re = prefix_re(p);
> >     if (re != NULL && re->active == p)
> >             rib.flags |= F_PREF_ACTIVE;
> > -   if (!prefix_peer(p)->conf.ebgp)
> > +   if (!peer->conf.ebgp)
> >             rib.flags |= F_PREF_INTERNAL;
> >     if (asp->flags & F_PREFIX_ANNOUNCED)
> >             rib.flags |= F_PREF_ANNOUNCE;
> > @@ -2344,9 +2412,20 @@ rde_dump_rib_as(struct prefix *p, struct
> >             rib.flags &= ~F_PREF_ELIGIBLE;
> >     if (asp->flags & F_ATTR_PARSE_ERR)
> >             rib.flags |= F_PREF_INVALID;
> > -   staletime = prefix_peer(p)->staletime[p->pt->aid];
> > +   staletime = peer->staletime[p->pt->aid];
> >     if (staletime && p->lastchange <= staletime)
> >             rib.flags |= F_PREF_STALE;
> > +   if (!adjout) {
> > +           if (peer_has_add_path(peer, p->pt->aid, CAPA_AP_RECV)) {
> > +                   rib.path_id = p->path_id;
> > +                   rib.flags |= F_PREF_PATH_ID;
> > +           }
> > +   } else {
> > +           if (peer_has_add_path(peer, p->pt->aid, CAPA_AP_SEND)) {
> > +                   rib.path_id = 0;        /* XXX add-path send */
> > +                   rib.flags |= F_PREF_PATH_ID;
> > +           }
> > +   }
> >     aslen = aspath_length(asp->aspath);
> >  
> >     if ((wbuf = imsg_create(ibuf_se_ctl, IMSG_CTL_SHOW_RIB, 0, pid,
> > @@ -2411,7 +2490,7 @@ rde_match_peer(struct rde_peer *p, struc
> >  }
> >  
> >  static void
> > -rde_dump_filter(struct prefix *p, struct ctl_show_rib_request *req)
> > +rde_dump_filter(struct prefix *p, struct ctl_show_rib_request *req, int 
> > adjout)
> >  {
> >     struct rde_aspath       *asp;
> >     struct rib_entry        *re;
> > @@ -2428,6 +2507,12 @@ rde_dump_filter(struct prefix *p, struct
> >     if ((req->flags & F_CTL_INVALID) &&
> >         (asp->flags & F_ATTR_PARSE_ERR) == 0)
> >             return;
> > +   /*
> > +    * XXX handle out specially since then we want to match against our
> > +    * path ids.
> > +    */
> > +   if ((req->flags & F_CTL_HAS_PATHID) && req->path_id != p->path_id)
> > +           return;
> >     if (req->as.type != AS_UNDEF &&
> >         !aspath_match(asp->aspath, &req->as, 0))
> >             return;
> > @@ -2438,7 +2523,7 @@ rde_dump_filter(struct prefix *p, struct
> >     }
> >     if (!ovs_match(p, req->flags))
> >             return;
> > -   rde_dump_rib_as(p, asp, req->pid, req->flags);
> > +   rde_dump_rib_as(p, asp, req->pid, req->flags, adjout);
> >  }
> >  
> >  static void
> > @@ -2448,7 +2533,7 @@ rde_dump_upcall(struct rib_entry *re, vo
> >     struct prefix           *p;
> >  
> >     LIST_FOREACH(p, &re->prefix_h, entry.list.rib)
> > -           rde_dump_filter(p, &ctx->req);
> > +           rde_dump_filter(p, &ctx->req, 0);
> >  }
> >  
> >  static void
> > @@ -2469,14 +2554,14 @@ rde_dump_prefix_upcall(struct rib_entry 
> >             if (!prefix_compare(&ctx->req.prefix, &addr,
> >                 ctx->req.prefixlen))
> >                     LIST_FOREACH(p, &re->prefix_h, entry.list.rib)
> > -                           rde_dump_filter(p, &ctx->req);
> > +                           rde_dump_filter(p, &ctx->req, 0);
> >     } else {
> >             if (ctx->req.prefixlen < pt->prefixlen)
> >                     return;
> >             if (!prefix_compare(&addr, &ctx->req.prefix,
> >                 pt->prefixlen))
> >                     LIST_FOREACH(p, &re->prefix_h, entry.list.rib)
> > -                           rde_dump_filter(p, &ctx->req);
> > +                           rde_dump_filter(p, &ctx->req, 0);
> >     }
> >  }
> >  
> > @@ -2487,7 +2572,7 @@ rde_dump_adjout_upcall(struct prefix *p,
> >  
> >     if (p->flags & (PREFIX_FLAG_WITHDRAW | PREFIX_FLAG_DEAD))
> >             return;
> > -   rde_dump_filter(p, &ctx->req);
> > +   rde_dump_filter(p, &ctx->req, 1);
> >  }
> >  
> >  static void
> > @@ -2507,13 +2592,13 @@ rde_dump_adjout_prefix_upcall(struct pre
> >                     return;
> >             if (!prefix_compare(&ctx->req.prefix, &addr,
> >                 ctx->req.prefixlen))
> > -                   rde_dump_filter(p, &ctx->req);
> > +                   rde_dump_filter(p, &ctx->req, 1);
> >     } else {
> >             if (ctx->req.prefixlen < p->pt->prefixlen)
> >                     return;
> >             if (!prefix_compare(&addr, &ctx->req.prefix,
> >                 p->pt->prefixlen))
> > -                   rde_dump_filter(p, &ctx->req);
> > +                   rde_dump_filter(p, &ctx->req, 1);
> >     }
> >  }
> >  
> > @@ -3580,11 +3665,12 @@ rde_softreconfig_in(struct rib_entry *re
> >  
> >                     if (action == ACTION_ALLOW) {
> >                             /* update Local-RIB */
> > -                           prefix_update(rib, peer, &state, &prefix,
> > -                               pt->prefixlen, p->validation_state);
> > +                           prefix_update(rib, peer, p->path_id, &state,
> > +                               &prefix, pt->prefixlen,
> > +                               p->validation_state);
> >                     } else if (action == ACTION_DENY) {
> >                             /* remove from Local-RIB */
> > -                           prefix_withdraw(rib, peer, &prefix,
> > +                           prefix_withdraw(rib, peer, p->path_id, &prefix,
> >                                 pt->prefixlen);
> >                     }
> >  
> > @@ -3724,11 +3810,12 @@ rde_roa_softreload(struct rib_entry *re,
> >  
> >                     if (action == ACTION_ALLOW) {
> >                             /* update Local-RIB */
> > -                           prefix_update(rib, peer, &state, &prefix,
> > -                               pt->prefixlen, p->validation_state);
> > +                           prefix_update(rib, peer, p->path_id, &state,
> > +                               &prefix, pt->prefixlen,
> > +                               p->validation_state);
> >                     } else if (action == ACTION_DENY) {
> >                             /* remove from Local-RIB */
> > -                           prefix_withdraw(rib, peer, &prefix,
> > +                           prefix_withdraw(rib, peer, p->path_id, &prefix,
> >                                 pt->prefixlen);
> >                     }
> >  
> > @@ -3952,7 +4039,7 @@ network_add(struct network_config *nc, s
> >  
> >     vstate = rde_roa_validity(&rde_roa, &nc->prefix,
> >         nc->prefixlen, aspath_origin(state->aspath.aspath));
> > -   if (prefix_update(rib_byid(RIB_ADJ_IN), peerself, state, &nc->prefix,
> > +   if (prefix_update(rib_byid(RIB_ADJ_IN), peerself, 0, state, &nc->prefix,
> >         nc->prefixlen, vstate) == 1)
> >             peerself->prefix_cnt++;
> >     for (i = RIB_LOC_START; i < rib_size; i++) {
> > @@ -3962,7 +4049,7 @@ network_add(struct network_config *nc, s
> >             rde_update_log("announce", i, peerself,
> >                 state->nexthop ? &state->nexthop->exit_nexthop : NULL,
> >                 &nc->prefix, nc->prefixlen);
> > -           prefix_update(rib, peerself, state, &nc->prefix,
> > +           prefix_update(rib, peerself, 0, state, &nc->prefix,
> >                 nc->prefixlen, vstate);
> >     }
> >     filterset_free(&nc->attrset);
> > @@ -4022,12 +4109,12 @@ network_delete(struct network_config *nc
> >             struct rib *rib = rib_byid(i);
> >             if (rib == NULL)
> >                     continue;
> > -           if (prefix_withdraw(rib, peerself, &nc->prefix,
> > +           if (prefix_withdraw(rib, peerself, 0, &nc->prefix,
> >                 nc->prefixlen))
> >                     rde_update_log("withdraw announce", i, peerself,
> >                         NULL, &nc->prefix, nc->prefixlen);
> >     }
> > -   if (prefix_withdraw(rib_byid(RIB_ADJ_IN), peerself, &nc->prefix,
> > +   if (prefix_withdraw(rib_byid(RIB_ADJ_IN), peerself, 0, &nc->prefix,
> >         nc->prefixlen))
> >             peerself->prefix_cnt--;
> >  }
> > @@ -4074,7 +4161,7 @@ network_flush_upcall(struct rib_entry *r
> >     u_int32_t i;
> >     u_int8_t prefixlen;
> >  
> > -   p = prefix_bypeer(re, peerself);
> > +   p = prefix_bypeer(re, peerself, 0);
> >     if (p == NULL)
> >             return;
> >     if ((prefix_aspath(p)->flags & F_ANN_DYNAMIC) != F_ANN_DYNAMIC)
> > @@ -4087,12 +4174,12 @@ network_flush_upcall(struct rib_entry *r
> >             struct rib *rib = rib_byid(i);
> >             if (rib == NULL)
> >                     continue;
> > -           if (prefix_withdraw(rib, peerself, &addr, prefixlen) == 1)
> > +           if (prefix_withdraw(rib, peerself, 0, &addr, prefixlen) == 1)
> >                     rde_update_log("flush announce", i, peerself,
> >                         NULL, &addr, prefixlen);
> >     }
> >  
> > -   if (prefix_withdraw(rib_byid(RIB_ADJ_IN), peerself, &addr,
> > +   if (prefix_withdraw(rib_byid(RIB_ADJ_IN), peerself, 0, &addr,
> >         prefixlen) == 1)
> >             peerself->prefix_cnt--;
> >  }
> > Index: bgpd/rde.h
> > ===================================================================
> > RCS file: /cvs/src/usr.sbin/bgpd/rde.h,v
> > retrieving revision 1.241
> > diff -u -p -r1.241 rde.h
> > --- bgpd/rde.h      27 Jul 2021 07:50:02 -0000      1.241
> > +++ bgpd/rde.h      30 Jul 2021 09:16:53 -0000
> > @@ -329,6 +329,8 @@ struct prefix {
> >     struct rde_peer                 *peer;
> >     struct nexthop                  *nexthop;       /* may be NULL */
> >     time_t                           lastchange;
> > +   u_int32_t                        path_id;
> > +   u_int32_t                        path_id_tx;
> >     u_int8_t                         validation_state;
> >     u_int8_t                         nhflags;
> >     u_int8_t                         eor;
> > @@ -386,6 +388,7 @@ int             rde_match_peer(struct rde_peer *, s
> >  
> >  /* rde_peer.c */
> >  int                 peer_has_as4byte(struct rde_peer *);
> > +int                 peer_has_add_path(struct rde_peer *, u_int8_t, int);
> >  int                 peer_accept_no_as_set(struct rde_peer *);
> >  void                peer_init(u_int32_t);
> >  void                peer_shutdown(void);
> > @@ -577,13 +580,13 @@ void           path_clean(struct rde_aspath *);
> >  void                path_put(struct rde_aspath *);
> >  
> >  #define    PREFIX_SIZE(x)  (((x) + 7) / 8 + 1)
> > -struct prefix      *prefix_get(struct rib *, struct rde_peer *,
> > +struct prefix      *prefix_get(struct rib *, struct rde_peer *, u_int32_t,
> >                 struct bgpd_addr *, int);
> >  struct prefix      *prefix_lookup(struct rde_peer *, struct bgpd_addr *, 
> > int);
> >  struct prefix      *prefix_match(struct rde_peer *, struct bgpd_addr *);
> > -int                 prefix_update(struct rib *, struct rde_peer *,
> > +int                 prefix_update(struct rib *, struct rde_peer *, 
> > u_int32_t,
> >                  struct filterstate *, struct bgpd_addr *, int, u_int8_t);
> > -int                 prefix_withdraw(struct rib *, struct rde_peer *,
> > +int                 prefix_withdraw(struct rib *, struct rde_peer *, 
> > u_int32_t,
> >                 struct bgpd_addr *, int);
> >  void                prefix_add_eor(struct rde_peer *, u_int8_t);
> >  int                 prefix_adjout_update(struct rde_peer *, struct 
> > filterstate *,
> > @@ -598,7 +601,8 @@ int              prefix_dump_new(struct rde_peer *,
> >                 void (*)(void *, u_int8_t), int (*)(void *));
> >  int                 prefix_write(u_char *, int, struct bgpd_addr *, 
> > u_int8_t, int);
> >  int                 prefix_writebuf(struct ibuf *, struct bgpd_addr *, 
> > u_int8_t);
> > -struct prefix      *prefix_bypeer(struct rib_entry *, struct rde_peer *);
> > +struct prefix      *prefix_bypeer(struct rib_entry *, struct rde_peer *,
> > +               u_int32_t);
> >  void                prefix_destroy(struct prefix *);
> >  void                prefix_relink(struct prefix *, struct rde_aspath *, 
> > int);
> >  
> > Index: bgpd/rde_decide.c
> > ===================================================================
> > RCS file: /cvs/src/usr.sbin/bgpd/rde_decide.c,v
> > retrieving revision 1.85
> > diff -u -p -r1.85 rde_decide.c
> > --- bgpd/rde_decide.c       4 May 2021 09:21:05 -0000       1.85
> > +++ bgpd/rde_decide.c       22 Jun 2021 16:52:02 -0000
> > @@ -281,6 +281,13 @@ prefix_cmp(struct prefix *p1, struct pre
> >     if (i > 0)
> >             return -1;
> >  
> > +   /* XXX RFC7911 does not specify this but it is needed. */
> > +   /* 13. lowest path identifier wins */
> > +   if (p1->path_id < p2->path_id)
> > +           return 1;
> > +   if (p1->path_id > p2->path_id)
> > +           return -1;
> > +
> >     fatalx("Uh, oh a politician in the decision process");
> >  }
> >  
> > Index: bgpd/rde_peer.c
> > ===================================================================
> > RCS file: /cvs/src/usr.sbin/bgpd/rde_peer.c,v
> > retrieving revision 1.11
> > diff -u -p -r1.11 rde_peer.c
> > --- bgpd/rde_peer.c 17 Jun 2021 16:05:26 -0000      1.11
> > +++ bgpd/rde_peer.c 22 Jun 2021 14:47:42 -0000
> > @@ -54,6 +54,14 @@ peer_has_as4byte(struct rde_peer *peer)
> >  }
> >  
> >  int
> > +peer_has_add_path(struct rde_peer *peer, u_int8_t aid, int mode)
> > +{
> > +   if (aid > AID_MAX)
> > +           return 0;
> > +   return (peer->capa.add_path[aid] & mode);
> > +}
> > +
> > +int
> >  peer_accept_no_as_set(struct rde_peer *peer)
> >  {
> >     return (peer->flags & PEERFLAG_NO_AS_SET);
> > @@ -250,7 +258,8 @@ peer_flush_upcall(struct rib_entry *re, 
> >                     struct rib *rib = rib_byid(i);
> >                     if (rib == NULL)
> >                             continue;
> > -                   rp = prefix_get(rib, peer, &addr, prefixlen);
> > +                   rp = prefix_get(rib, peer, p->path_id,
> > +                        &addr, prefixlen);
> >                     if (rp) {
> >                             asp = prefix_aspath(rp);
> >                             if (asp && asp->pftableid)
> > @@ -264,7 +273,6 @@ peer_flush_upcall(struct rib_entry *re, 
> >  
> >             prefix_destroy(p);
> >             peer->prefix_cnt--;
> > -           break;  /* optimization, only one match per peer possible */
> >     }
> >  }
> >  
> > Index: bgpd/rde_rib.c
> > ===================================================================
> > RCS file: /cvs/src/usr.sbin/bgpd/rde_rib.c,v
> > retrieving revision 1.223
> > diff -u -p -r1.223 rde_rib.c
> > --- bgpd/rde_rib.c  27 Jul 2021 07:50:02 -0000      1.223
> > +++ bgpd/rde_rib.c  30 Jul 2021 09:37:10 -0000
> > @@ -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 *, struct rde_aspath *,
> > +               struct rde_peer *, u_int32_t, struct rde_aspath *,
> >                 struct rde_community *, struct nexthop *,
> >                 u_int8_t, u_int8_t);
> >  static int prefix_move(struct prefix *, struct rde_peer *,
> > @@ -850,7 +850,7 @@ static int      prefix_move(struct prefix *, 
> >                 struct nexthop *, u_int8_t, u_int8_t);
> >  
> >  static void        prefix_link(struct prefix *, struct rib_entry *,
> > -                struct rde_peer *, struct rde_aspath *,
> > +                struct rde_peer *, u_int32_t, struct rde_aspath *,
> >                  struct rde_community *, struct nexthop *,
> >                  u_int8_t, u_int8_t);
> >  static void        prefix_unlink(struct prefix *);
> > @@ -876,12 +876,14 @@ prefix_cmp(struct prefix *a, struct pref
> >             return (a->nexthop > b->nexthop ? 1 : -1);
> >     if (a->nhflags != b->nhflags)
> >             return (a->nhflags > b->nhflags ? 1 : -1);
> > +   /* XXX path_id ??? */
> >     return pt_prefix_cmp(a->pt, b->pt);
> >  }
> >  
> >  static inline int
> >  prefix_index_cmp(struct prefix *a, struct prefix *b)
> >  {
> > +   /* XXX path_id ??? */
> >     return pt_prefix_cmp(a->pt, b->pt);
> >  }
> >  
> > @@ -892,15 +894,15 @@ RB_GENERATE_STATIC(prefix_index, prefix,
> >   * search for specified prefix of a peer. Returns NULL if not found.
> >   */
> >  struct prefix *
> > -prefix_get(struct rib *rib, struct rde_peer *peer, struct bgpd_addr 
> > *prefix,
> > -    int prefixlen)
> > +prefix_get(struct rib *rib, struct rde_peer *peer, u_int32_t path_id,
> > +    struct bgpd_addr *prefix, int prefixlen)
> >  {
> >     struct rib_entry        *re;
> >  
> >     re = rib_get(rib, prefix, prefixlen);
> >     if (re == NULL)
> >             return (NULL);
> > -   return (prefix_bypeer(re, peer));
> > +   return (prefix_bypeer(re, peer, path_id));
> >  }
> >  
> >  /*
> > @@ -954,8 +956,9 @@ prefix_match(struct rde_peer *peer, stru
> >   * Return 1 if prefix was newly added, 0 if it was just changed.
> >   */
> >  int
> > -prefix_update(struct rib *rib, struct rde_peer *peer, struct filterstate 
> > *state,
> > -    struct bgpd_addr *prefix, int prefixlen, u_int8_t vstate)
> > +prefix_update(struct rib *rib, struct rde_peer *peer, u_int32_t path_id,
> > +    struct filterstate *state, struct bgpd_addr *prefix, int prefixlen,
> > +    u_int8_t vstate)
> >  {
> >     struct rde_aspath       *asp, *nasp = &state->aspath;
> >     struct rde_community    *comm, *ncomm = &state->communities;
> > @@ -964,7 +967,7 @@ prefix_update(struct rib *rib, struct rd
> >     /*
> >      * First try to find a prefix in the specified RIB.
> >      */
> > -   if ((p = prefix_get(rib, peer, prefix, prefixlen)) != NULL) {
> > +   if ((p = prefix_get(rib, peer, path_id, prefix, prefixlen)) != NULL) {
> >             if (prefix_nexthop(p) == state->nexthop &&
> >                 prefix_nhflags(p) == state->nhflags &&
> >                 communities_equal(ncomm, prefix_communities(p)) &&
> > @@ -997,8 +1000,8 @@ prefix_update(struct rib *rib, struct rd
> >             return (prefix_move(p, peer, asp, comm, state->nexthop,
> >                 state->nhflags, vstate));
> >     else
> > -           return (prefix_add(prefix, prefixlen, rib, peer, asp, comm,
> > -               state->nexthop, state->nhflags, vstate));
> > +           return (prefix_add(prefix, prefixlen, rib, peer, path_id, asp,
> > +               comm, state->nexthop, state->nhflags, vstate));
> >  }
> >  
> >  /*
> > @@ -1006,8 +1009,9 @@ prefix_update(struct rib *rib, struct rd
> >   */
> >  static int
> >  prefix_add(struct bgpd_addr *prefix, int prefixlen, struct rib *rib,
> > -    struct rde_peer *peer, struct rde_aspath *asp, struct rde_community 
> > *comm,
> > -    struct nexthop *nexthop, u_int8_t nhflags, u_int8_t vstate)
> > +    struct rde_peer *peer, u_int32_t path_id, struct rde_aspath *asp,
> > +    struct rde_community *comm, struct nexthop *nexthop, u_int8_t nhflags,
> > +    u_int8_t vstate)
> >  {
> >     struct prefix           *p;
> >     struct rib_entry        *re;
> > @@ -1017,7 +1021,7 @@ prefix_add(struct bgpd_addr *prefix, int
> >             re = rib_add(rib, prefix, prefixlen);
> >  
> >     p = prefix_alloc();
> > -   prefix_link(p, re, peer, asp, comm, nexthop, nhflags, vstate);
> > +   prefix_link(p, re, peer, path_id, asp, comm, nexthop, nhflags, vstate);
> >     return (1);
> >  }
> >  
> > @@ -1045,6 +1049,7 @@ prefix_move(struct prefix *p, struct rde
> >     np->peer = peer;
> >     np->entry.list.re = prefix_re(p);
> >     np->pt = p->pt; /* skip refcnt update since ref is moved */
> > +   np->path_id = p->path_id;
> >     np->validation_state = vstate;
> >     np->nhflags = nhflags;
> >     np->nexthop = nexthop_ref(nexthop);
> > @@ -1086,13 +1091,13 @@ prefix_move(struct prefix *p, struct rde
> >   * or pt_entry -- become empty remove them too.
> >   */
> >  int
> > -prefix_withdraw(struct rib *rib, struct rde_peer *peer,
> > +prefix_withdraw(struct rib *rib, struct rde_peer *peer, u_int32_t path_id,
> >      struct bgpd_addr *prefix, int prefixlen)
> >  {
> >     struct prefix           *p;
> >     struct rde_aspath       *asp;
> >  
> > -   p = prefix_get(rib, peer, prefix, prefixlen);
> > +   p = prefix_get(rib, peer, path_id, prefix, prefixlen);
> >     if (p == NULL)          /* Got a dummy withdrawn request. */
> >             return (0);
> >  
> > @@ -1487,12 +1492,12 @@ prefix_writebuf(struct ibuf *buf, struct
> >   * belonging to the peer peer. Returns NULL if no match found.
> >   */
> >  struct prefix *
> > -prefix_bypeer(struct rib_entry *re, struct rde_peer *peer)
> > +prefix_bypeer(struct rib_entry *re, struct rde_peer *peer, u_int32_t 
> > path_id)
> >  {
> >     struct prefix   *p;
> >  
> >     LIST_FOREACH(p, &re->prefix_h, entry.list.rib)
> > -           if (prefix_peer(p) == peer)
> > +           if (prefix_peer(p) == peer && p->path_id == path_id)
> >                     return (p);
> >     return (NULL);
> >  }
> > @@ -1544,7 +1549,7 @@ prefix_destroy(struct prefix *p)
> >   */
> >  static void
> >  prefix_link(struct prefix *p, struct rib_entry *re, struct rde_peer *peer,
> > -    struct rde_aspath *asp, struct rde_community *comm,
> > +    u_int32_t path_id, struct rde_aspath *asp, struct rde_community *comm,
> >      struct nexthop *nexthop, u_int8_t nhflags, u_int8_t vstate)
> >  {
> >     if (p->flags & PREFIX_FLAG_ADJOUT)
> > @@ -1555,6 +1560,7 @@ prefix_link(struct prefix *p, struct rib
> >     p->communities = communities_ref(comm);
> >     p->peer = peer;
> >     p->pt = pt_ref(re->prefix);
> > +   p->path_id = path_id;
> >     p->validation_state = vstate;
> >     p->nhflags = nhflags;
> >     p->nexthop = nexthop_ref(nexthop);
> > Index: bgpd/rde_update.c
> > ===================================================================
> > RCS file: /cvs/src/usr.sbin/bgpd/rde_update.c,v
> > retrieving revision 1.130
> > diff -u -p -r1.130 rde_update.c
> > --- bgpd/rde_update.c       17 Jun 2021 08:14:50 -0000      1.130
> > +++ bgpd/rde_update.c       22 Jun 2021 10:10:07 -0000
> > @@ -625,9 +625,18 @@ up_dump_prefix(u_char *buf, int len, str
> >  {
> >     struct prefix   *p, *np;
> >     struct bgpd_addr addr;
> > +   u_int32_t        pathid;
> >     int              r, wpos = 0, done = 0;
> >  
> >     RB_FOREACH_SAFE(p, prefix_tree, prefix_head, np) {
> > +           if (peer_has_add_path(peer, p->pt->aid, CAPA_AP_SEND)) {
> > +                   if (len <= wpos + (int)sizeof(pathid))
> > +                           break;
> > +                   /* XXX add-path send side */
> > +                   pathid = 0;
> > +                   memcpy(buf + wpos, &pathid, sizeof(pathid));
> > +                   wpos += sizeof(pathid);
> > +           }
> >             pt_getaddr(p->pt, &addr);
> >             if ((r = prefix_write(buf + wpos, len - wpos,
> >                 &addr, p->pt->prefixlen, withdraw)) == -1)
> > 
> 

Reply via email to