On Fri, Dec 28, 2018 at 05:21:02PM +0100, Denis Fondras wrote:
> On Fri, Dec 28, 2018 at 03:15:35PM +0100, Claudio Jeker wrote:
> > >  /*
> > >   * This function will have undefined behaviour if the passed in 
> > > prefixlen is
> > > - * to large for the respective bgpd_addr address family.
> > > + * too large for the respective bgpd_addr address family.
> > >   */
> > >  int
> > >  prefix_compare(const struct bgpd_addr *a, const struct bgpd_addr *b,
> > > @@ -620,6 +695,8 @@ prefix_compare(const struct bgpd_addr *a
> > >           }
> > >           return (0);
> > >   case AID_VPN_IPv4:
> > > +         if (prefixlen == 0)
> > > +                 return (0);
> > 
> > I think this is not right. If at all then this check should happen after
> > checking the RD for equality. Else two different VPN default routes (with
> > different RD value) would be conidered the same.
> > 
> > >           if (prefixlen > 32)
> > >                   return (-1);
> > >           if (betoh64(a->vpn4.rd) > betoh64(b->vpn4.rd))
> > > @@ -637,6 +714,34 @@ prefix_compare(const struct bgpd_addr *a
> > >                   return (-1);
> > >           return (memcmp(a->vpn4.labelstack, b->vpn4.labelstack,
> > >               a->vpn4.labellen));
> > > + case AID_VPN_IPv6:
> > > +         if (prefixlen == 0)
> > > +                 return (0);
> > 
> > See above.
> > 
> > > +         if (prefixlen > 128)
> > > +                 return (-1);
> > > +         for (i = 0; i < prefixlen / 8; i++)
> > > +                 if (a->vpn6.addr.s6_addr[i] != b->vpn6.addr.s6_addr[i])
> > > +                         return (a->vpn6.addr.s6_addr[i] -
> > > +                             b->vpn6.addr.s6_addr[i]);
> > > +         i = prefixlen % 8;
> > > +         if (i) {
> > > +                 m = 0xff00 >> i;
> > > +                 if ((a->vpn6.addr.s6_addr[prefixlen / 8] & m) !=
> > > +                     (b->vpn6.addr.s6_addr[prefixlen / 8] & m))
> > > +                         return ((a->vpn6.addr.s6_addr[prefixlen / 8] &
> > > +                             m) - (b->vpn6.addr.s6_addr[prefixlen / 8] &
> > > +                             m));
> > > +         }
> > > +         if (betoh64(a->vpn6.rd) > betoh64(b->vpn6.rd))
> > > +                 return (1);
> > > +         if (betoh64(a->vpn6.rd) < betoh64(b->vpn6.rd))
> > > +                 return (-1);
> > 
> > I would check the RD first like it is done in the AID_VPN_IPv4 case.
> > Then address and then labelstack.
> > 
> > > +         if (a->vpn6.labellen > b->vpn6.labellen)
> > > +                 return (1);
> > > +         if (a->vpn6.labellen < b->vpn6.labellen)
> > > +                 return (-1);
> > > +         return (memcmp(a->vpn6.labelstack, b->vpn6.labelstack,
> > > +             a->vpn6.labellen));
> > >   }
> > >   return (-1);
> > >  }
> > > 
> > 
> > The diff is OK apart from that bit in prefix_compare().
> > 
> 
> Thank you for the comments.
> I removed the "if (prefixlen == 0)". I added it because it was missing but I 
> did
> not think it was on purpose. I also reordered the tests as you suggest. I 
> copied
> the order of up_prefix_cmp() (rd, address then labelstack) and updated
> pt_prefix_cmp() as well.

Not fully conviced about the pt_prefix_cmp() change but lets go with it
now. My reason for not being convinced is that until now the show rib
output would be sorted by address first. So the same prefix in multiple RD
would group by prefix. Now with your change the prefixes will be grouped
by RD. Since I'm not a big user of MPLS VPN I don't mind this change.

Diff is OK claudio@

 
> Index: bgpd.h
> ===================================================================
> RCS file: /cvs/src/usr.sbin/bgpd/bgpd.h,v
> retrieving revision 1.360
> diff -u -p -r1.360 bgpd.h
> --- bgpd.h    27 Dec 2018 20:23:24 -0000      1.360
> +++ bgpd.h    28 Dec 2018 16:00:23 -0000
> @@ -154,7 +154,8 @@ extern const struct aid aid_vals[];
>  #define      AID_INET        1
>  #define      AID_INET6       2
>  #define      AID_VPN_IPv4    3
> -#define      AID_MAX         4
> +#define      AID_VPN_IPv6    4
> +#define      AID_MAX         5
>  #define      AID_MIN         1       /* skip AID_UNSPEC since that is a 
> dummy */
>  
>  #define AID_VALS     {                                       \
> @@ -162,14 +163,16 @@ extern const struct aid aid_vals[];
>       { AFI_UNSPEC, AF_UNSPEC, SAFI_NONE, "unspec"},          \
>       { AFI_IPv4, AF_INET, SAFI_UNICAST, "IPv4 unicast" },    \
>       { AFI_IPv6, AF_INET6, SAFI_UNICAST, "IPv6 unicast" },   \
> -     { AFI_IPv4, AF_INET, SAFI_MPLSVPN, "IPv4 vpn" }         \
> +     { AFI_IPv4, AF_INET, SAFI_MPLSVPN, "IPv4 vpn" },        \
> +     { AFI_IPv6, AF_INET6, SAFI_MPLSVPN, "IPv6 vpn" }        \
>  }
>  
>  #define AID_PTSIZE   {                               \
>       0,                                              \
>       sizeof(struct pt_entry4),                       \
>       sizeof(struct pt_entry6),                       \
> -     sizeof(struct pt_entry_vpn4)                    \
> +     sizeof(struct pt_entry_vpn4),                   \
> +     sizeof(struct pt_entry_vpn6)                    \
>  }
>  
>  struct vpn4_addr {
> @@ -181,6 +184,15 @@ struct vpn4_addr {
>       u_int8_t        pad2;
>  };
>  
> +struct vpn6_addr {
> +     u_int64_t       rd;
> +     struct in6_addr addr;
> +     u_int8_t        labelstack[21]; /* max that makes sense */
> +     u_int8_t        labellen;
> +     u_int8_t        pad1;
> +     u_int8_t        pad2;
> +};
> +
>  #define BGP_MPLS_BOS 0x01
>  
>  struct bgpd_addr {
> @@ -188,6 +200,7 @@ struct bgpd_addr {
>               struct in_addr          v4;
>               struct in6_addr         v6;
>               struct vpn4_addr        vpn4;
> +             struct vpn6_addr        vpn6;
>               /* maximum size for a prefix is 256 bits */
>               u_int8_t                addr8[32];
>               u_int16_t               addr16[16];
> @@ -198,6 +211,7 @@ struct bgpd_addr {
>  #define      v4      ba.v4
>  #define      v6      ba.v6
>  #define      vpn4    ba.vpn4
> +#define      vpn6    ba.vpn6
>  #define      addr8   ba.addr8
>  #define      addr16  ba.addr16
>  #define      addr32  ba.addr32
> @@ -598,6 +612,7 @@ struct kroute {
>  struct kroute6 {
>       struct in6_addr prefix;
>       struct in6_addr nexthop;
> +     u_int32_t       mplslabel;
>       u_int16_t       flags;
>       u_int16_t       labelid;
>       u_short         ifindex;
> @@ -1258,6 +1273,8 @@ int              nlri_get_prefix(u_char *, u_int16_
>  int           nlri_get_prefix6(u_char *, u_int16_t, struct bgpd_addr *,
>                    u_int8_t *);
>  int           nlri_get_vpn4(u_char *, u_int16_t, struct bgpd_addr *,
> +                  u_int8_t *, int);
> +int           nlri_get_vpn6(u_char *, u_int16_t, struct bgpd_addr *,
>                    u_int8_t *, int);
>  int           prefix_compare(const struct bgpd_addr *,
>                   const struct bgpd_addr *, int);
> Index: kroute.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/bgpd/kroute.c,v
> retrieving revision 1.226
> diff -u -p -r1.226 kroute.c
> --- kroute.c  6 Dec 2018 13:04:40 -0000       1.226
> +++ kroute.c  28 Dec 2018 16:00:23 -0000
> @@ -93,9 +93,11 @@ struct ktable      *ktable_get(u_int);
>  int  kr4_change(struct ktable *, struct kroute_full *, u_int8_t);
>  int  kr6_change(struct ktable *, struct kroute_full *, u_int8_t);
>  int  krVPN4_change(struct ktable *, struct kroute_full *, u_int8_t);
> +int  krVPN6_change(struct ktable *, struct kroute_full *, u_int8_t);
>  int  kr4_delete(struct ktable *, struct kroute_full *, u_int8_t);
>  int  kr6_delete(struct ktable *, struct kroute_full *, u_int8_t);
>  int  krVPN4_delete(struct ktable *, struct kroute_full *, u_int8_t);
> +int  krVPN6_delete(struct ktable *, struct kroute_full *, u_int8_t);
>  void kr_net_delete(struct network *);
>  struct network *kr_net_match(struct ktable *, struct kroute *);
>  struct network *kr_net_match6(struct ktable *, struct kroute6 *);
> @@ -475,6 +477,8 @@ kr_change(u_int rtableid, struct kroute_
>               return (kr6_change(kt, kl, fib_prio));
>       case AID_VPN_IPv4:
>               return (krVPN4_change(kt, kl, fib_prio));
> +     case AID_VPN_IPv6:
> +             return (krVPN6_change(kt, kl, fib_prio));
>       }
>       log_warnx("%s: not handled AID", __func__);
>       return (-1);
> @@ -669,6 +673,81 @@ krVPN4_change(struct ktable *kt, struct 
>  }
>  
>  int
> +krVPN6_change(struct ktable *kt, struct kroute_full *kl, u_int8_t fib_prio)
> +{
> +     struct kroute6_node     *kr6;
> +     struct in6_addr          lo6 = IN6ADDR_LOOPBACK_INIT;
> +     int                      action = RTM_ADD;
> +     u_int32_t                mplslabel = 0;
> +     u_int16_t                labelid;
> +
> +     if ((kr6 = kroute6_find(kt, &kl->prefix.vpn6.addr, kl->prefixlen,
> +         fib_prio)) != NULL)
> +             action = RTM_CHANGE;
> +
> +     /* nexthop to loopback -> ignore silently */
> +     if (IN6_IS_ADDR_LOOPBACK(&kl->nexthop.v6))
> +             return (0);
> +
> +     /* only single MPLS label are supported for now */
> +     if (kl->prefix.vpn6.labellen != 3) {
> +             log_warnx("%s: %s/%u has not a single label", __func__,
> +                 log_addr(&kl->prefix), kl->prefixlen);
> +             return (0);
> +     }
> +     mplslabel = (kl->prefix.vpn6.labelstack[0] << 24) |
> +         (kl->prefix.vpn6.labelstack[1] << 16) |
> +         (kl->prefix.vpn6.labelstack[2] << 8);
> +     mplslabel = htonl(mplslabel);
> +
> +     /* for blackhole and reject routes nexthop needs to be ::1 */
> +     if (kl->flags & (F_BLACKHOLE|F_REJECT))
> +             bcopy(&lo6, &kl->nexthop.v6, sizeof(kl->nexthop.v6));
> +
> +     labelid = rtlabel_name2id(kl->label);
> +
> +     if (action == RTM_ADD) {
> +             if ((kr6 = calloc(1, sizeof(struct kroute6_node))) == NULL) {
> +                     log_warn("%s", __func__);
> +                     return (-1);
> +             }
> +             memcpy(&kr6->r.prefix, &kl->prefix.vpn6.addr,
> +                 sizeof(struct in6_addr));
> +             kr6->r.prefixlen = kl->prefixlen;
> +             memcpy(&kr6->r.nexthop, &kl->nexthop.v6,
> +                 sizeof(struct in6_addr));
> +             kr6->r.flags = kl->flags | F_BGPD_INSERTED | F_MPLS;
> +             kr6->r.priority = fib_prio;
> +             kr6->r.labelid = labelid;
> +             kr6->r.mplslabel = mplslabel;
> +
> +             if (kroute6_insert(kt, kr6) == -1) {
> +                     free(kr6);
> +                     return (-1);
> +             }
> +     } else {
> +             kr6->r.mplslabel = mplslabel;
> +             memcpy(&kr6->r.nexthop, &kl->nexthop.v6,
> +                 sizeof(struct in6_addr));
> +             rtlabel_unref(kr6->r.labelid);
> +             kr6->r.labelid = labelid;
> +             if (kl->flags & F_BLACKHOLE)
> +                     kr6->r.flags |= F_BLACKHOLE;
> +             else
> +                     kr6->r.flags &= ~F_BLACKHOLE;
> +             if (kl->flags & F_REJECT)
> +                     kr6->r.flags |= F_REJECT;
> +             else
> +                     kr6->r.flags &= ~F_REJECT;
> +     }
> +
> +     if (send_rt6msg(kr_state.fd, action, kt, &kr6->r, fib_prio) == -1)
> +             return (-1);
> +
> +     return (0);
> +}
> +
> +int
>  kr_delete(u_int rtableid, struct kroute_full *kl, u_int8_t fib_prio)
>  {
>       struct ktable           *kt;
> @@ -684,6 +763,8 @@ kr_delete(u_int rtableid, struct kroute_
>               return (kr6_delete(kt, kl, fib_prio));
>       case AID_VPN_IPv4:
>               return (krVPN4_delete(kt, kl, fib_prio));
> +     case AID_VPN_IPv6:
> +             return (krVPN6_delete(kt, kl, fib_prio));
>       }
>       log_warnx("%s: not handled AID", __func__);
>       return (-1);
> @@ -758,6 +839,29 @@ krVPN4_delete(struct ktable *kt, struct 
>       return (0);
>  }
>  
> +int
> +krVPN6_delete(struct ktable *kt, struct kroute_full *kl, u_int8_t fib_prio)
> +{
> +     struct kroute6_node     *kr6;
> +
> +     if ((kr6 = kroute6_find(kt, &kl->prefix.vpn6.addr, kl->prefixlen,
> +         fib_prio)) == NULL)
> +             return (0);
> +
> +     if (!(kr6->r.flags & F_BGPD_INSERTED))
> +             return (0);
> +
> +     if (send_rt6msg(kr_state.fd, RTM_DELETE, kt, &kr6->r, fib_prio) == -1)
> +             return (-1);
> +
> +     rtlabel_unref(kr6->r.labelid);
> +
> +     if (kroute6_remove(kt, kr6) == -1)
> +             return (-1);
> +
> +     return (0);
> +}
> +
>  void
>  kr_shutdown(u_int8_t fib_prio, u_int rdomain)
>  {
> @@ -2723,13 +2827,18 @@ int
>  send_rt6msg(int fd, int action, struct ktable *kt, struct kroute6 *kroute,
>      u_int8_t fib_prio)
>  {
> -     struct iovec            iov[5];
> +     struct iovec            iov[7];
>       struct rt_msghdr        hdr;
>       struct pad {
>               struct sockaddr_in6     addr;
>               char                    pad[sizeof(long)];
>       } prefix, nexthop, mask;
> +     struct {
> +             struct sockaddr_dl      dl;
> +             char                    pad[sizeof(long)];
> +     }                       ifp;
>       struct sockaddr_rtlabel label;
> +     struct sockaddr_mpls    mpls;
>       int                     iovcnt = 0;
>  
>       if (!kt->fib_sync)
> @@ -2792,6 +2901,34 @@ send_rt6msg(int fd, int action, struct k
>       /* adjust iovec */
>       iov[iovcnt].iov_base = &mask;
>       iov[iovcnt++].iov_len = ROUNDUP(sizeof(struct sockaddr_in6));
> +
> +     if (kt->ifindex) {
> +             memset(&ifp, 0, sizeof(ifp));
> +             ifp.dl.sdl_len = sizeof(struct sockaddr_dl);
> +             ifp.dl.sdl_family = AF_LINK;
> +             ifp.dl.sdl_index = kt->ifindex;
> +             hdr.rtm_addrs |= RTA_IFP;
> +             hdr.rtm_msglen += ROUNDUP(sizeof(struct sockaddr_dl));
> +             iov[iovcnt].iov_base = &ifp;
> +             iov[iovcnt++].iov_len = ROUNDUP(sizeof(struct sockaddr_dl));
> +     }
> +
> +     if (kroute->flags & F_MPLS) {
> +             memset(&mpls, 0, sizeof(mpls));
> +             mpls.smpls_len = sizeof(mpls);
> +             mpls.smpls_family = AF_MPLS;
> +             mpls.smpls_label = kroute->mplslabel;
> +             /* adjust header */
> +             hdr.rtm_flags |= RTF_MPLS;
> +             hdr.rtm_mpls = MPLS_OP_PUSH;
> +             hdr.rtm_addrs |= RTA_SRC;
> +             hdr.rtm_msglen += ROUNDUP(sizeof(struct sockaddr_mpls));
> +             /* clear gateway flag since this is for mpe(4) */
> +             hdr.rtm_flags &= ~RTF_GATEWAY;
> +             /* adjust iovec */
> +             iov[iovcnt].iov_base = &mpls;
> +             iov[iovcnt++].iov_len = ROUNDUP(sizeof(struct sockaddr_mpls));
> +     }
>  
>       if (kroute->labelid) {
>               bzero(&label, sizeof(label));
> Index: mrt.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/bgpd/mrt.c,v
> retrieving revision 1.87
> diff -u -p -r1.87 mrt.c
> --- mrt.c     24 Oct 2018 08:26:37 -0000      1.87
> +++ mrt.c     28 Dec 2018 16:00:23 -0000
> @@ -222,6 +222,15 @@ mrt_attr_dump(struct ibuf *buf, struct r
>                       DUMP_NLONG(nhbuf, 0);
>                       DUMP_NLONG(nhbuf, nexthop->v4.s_addr);
>                       break;
> +             case AID_VPN_IPv6:
> +                     DUMP_BYTE(nhbuf, sizeof(u_int64_t) +
> +                         sizeof(struct in6_addr));
> +                     DUMP_NLONG(nhbuf, 0);   /* set RD to 0 */
> +                     DUMP_NLONG(nhbuf, 0);
> +                     if (ibuf_add(nhbuf, &nexthop->v6,
> +                         sizeof(struct in6_addr)) == -1) {
> +                     }
> +                     break;
>               }
>               if (!v2)
>                       DUMP_BYTE(nhbuf, 0);
> Index: parse.y
> ===================================================================
> RCS file: /cvs/src/usr.sbin/bgpd/parse.y,v
> retrieving revision 1.367
> diff -u -p -r1.367 parse.y
> --- parse.y   28 Dec 2018 14:28:52 -0000      1.367
> +++ parse.y   28 Dec 2018 16:00:23 -0000
> @@ -3974,6 +3974,7 @@ merge_prefixspec(struct filter_prefix *p
>               max_len = 32;
>               break;
>       case AID_INET6:
> +     case AID_VPN_IPv6:
>               max_len = 128;
>               break;
>       }
> Index: printconf.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/bgpd/printconf.c,v
> retrieving revision 1.125
> diff -u -p -r1.125 printconf.c
> --- printconf.c       19 Dec 2018 15:26:42 -0000      1.125
> +++ printconf.c       28 Dec 2018 16:00:23 -0000
> @@ -67,6 +67,7 @@ print_prefix(struct filter_prefix *p)
>               max_len = 32;
>               break;
>       case AID_INET6:
> +     case AID_VPN_IPv6:
>               max_len = 128;
>               break;
>       case AID_UNSPEC:
> Index: rde.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/bgpd/rde.c,v
> retrieving revision 1.455
> diff -u -p -r1.455 rde.c
> --- rde.c     26 Dec 2018 13:24:28 -0000      1.455
> +++ rde.c     28 Dec 2018 16:00:23 -0000
> @@ -1240,6 +1240,23 @@ rde_update_dispatch(struct imsg *imsg)
>                               rde_update_withdraw(peer, &prefix, prefixlen);
>                       }
>                       break;
> +             case AID_VPN_IPv6:
> +                     while (mplen > 0) {
> +                             if ((pos = nlri_get_vpn6(mpp, mplen,
> +                                 &prefix, &prefixlen, 1)) == -1) {
> +                                     log_peer_warnx(&peer->conf,
> +                                         "bad VPNv6 withdraw prefix");
> +                                     rde_update_err(peer, ERR_UPDATE,
> +                                         ERR_UPD_OPTATTR, mpa.unreach,
> +                                         mpa.unreach_len);
> +                                     goto done;
> +                             }
> +                             mpp += pos;
> +                             mplen -= pos;
> +
> +                             rde_update_withdraw(peer, &prefix, prefixlen);
> +                     }
> +                     break;
>               default:
>                       /* silently ignore unsupported multiprotocol AF */
>                       break;
> @@ -1363,6 +1380,25 @@ rde_update_dispatch(struct imsg *imsg)
>                                       goto done;
>                       }
>                       break;
> +             case AID_VPN_IPv6:
> +                     while (mplen > 0) {
> +                             if ((pos = nlri_get_vpn6(mpp, mplen,
> +                                 &prefix, &prefixlen, 0)) == -1) {
> +                                     log_peer_warnx(&peer->conf,
> +                                         "bad VPNv6 nlri prefix");
> +                                     rde_update_err(peer, ERR_UPDATE,
> +                                         ERR_UPD_OPTATTR,
> +                                         mpa.reach, mpa.reach_len);
> +                                     goto done;
> +                             }
> +                             mpp += pos;
> +                             mplen -= pos;
> +
> +                             if (rde_update_update(peer, &state, &prefix,
> +                                 prefixlen) == -1)
> +                                     goto done;
> +                     }
> +                     break;
>               default:
>                       /* silently ignore unsupported multiprotocol AF */
>                       break;
> @@ -1904,6 +1940,16 @@ rde_get_mp_nexthop(u_char *data, u_int16
>               }
>               memcpy(&nexthop.v6.s6_addr, data, 16);
>               break;
> +     case AID_VPN_IPv6:
> +             if (nhlen != 24) {
> +                     log_warnx("bad multiprotocol nexthop, bad size %d",
> +                         nhlen);
> +                     return (-1);
> +             }
> +             memcpy(&nexthop.v6, data + sizeof(u_int64_t),
> +                 sizeof(nexthop.v6));
> +             nexthop.aid = AID_INET6;
> +             break;
>       case AID_VPN_IPv4:
>               /*
>                * Neither RFC4364 nor RFC3107 specify the format of the
> @@ -2352,6 +2398,7 @@ rde_dump_ctx_new(struct ctl_show_rib_req
>                       hostplen = 32;
>                       break;
>               case AID_INET6:
> +             case AID_VPN_IPv6:
>                       hostplen = 128;
>                       break;
>               default:
> @@ -2517,6 +2564,7 @@ rde_send_kroute(struct rib *rib, struct 
>  
>       switch (addr.aid) {
>       case AID_VPN_IPv4:
> +     case AID_VPN_IPv6:
>               if (!(rib->flags & F_RIB_LOCAL))
>                       /* not Loc-RIB, no update for VPNs */
>                       break;
> @@ -3643,6 +3691,7 @@ network_add(struct network_config *nc, i
>       struct rde_aspath       *asp;
>       struct filter_set_head  *vpnset = NULL;
>       in_addr_t                prefix4;
> +     struct in6_addr          prefix6;
>       u_int8_t                 vstate;
>       u_int16_t                i;
>  
> @@ -3667,6 +3716,24 @@ network_add(struct network_config *nc, i
>                               nc->prefix.vpn4.labelstack[2] |= BGP_MPLS_BOS;
>                               vpnset = &rd->export;
>                               break;
> +                     case AID_INET6:
> +                             memcpy(&prefix6, &nc->prefix.v6.s6_addr,
> +                                 sizeof(struct in6_addr));
> +                             memset(&nc->prefix, 0, sizeof(nc->prefix));
> +                             nc->prefix.aid = AID_VPN_IPv6;
> +                             nc->prefix.vpn6.rd = rd->rd;
> +                             memcpy(&nc->prefix.vpn6.addr.s6_addr, &prefix6,
> +                                 sizeof(struct in6_addr));
> +                             nc->prefix.vpn6.labellen = 3;
> +                             nc->prefix.vpn6.labelstack[0] =
> +                                 (rd->label >> 12) & 0xff;
> +                             nc->prefix.vpn6.labelstack[1] =
> +                                 (rd->label >> 4) & 0xff;
> +                             nc->prefix.vpn6.labelstack[2] =
> +                                 (rd->label << 4) & 0xf0;
> +                             nc->prefix.vpn6.labelstack[2] |= BGP_MPLS_BOS;
> +                             vpnset = &rd->export;
> +                             break;
>                       default:
>                               log_warnx("unable to VPNize prefix");
>                               filterset_free(&nc->attrset);
> @@ -3724,6 +3791,7 @@ network_delete(struct network_config *nc
>  {
>       struct rdomain  *rd;
>       in_addr_t        prefix4;
> +     struct in6_addr  prefix6;
>       u_int32_t        flags = F_PREFIX_ANNOUNCED;
>       u_int32_t        i;
>  
> @@ -3749,6 +3817,23 @@ network_delete(struct network_config *nc
>                               nc->prefix.vpn4.labelstack[2] =
>                                   (rd->label << 4) & 0xf0;
>                               nc->prefix.vpn4.labelstack[2] |= BGP_MPLS_BOS;
> +                             break;
> +                     case AID_INET6:
> +                             memcpy(&prefix6, &nc->prefix.v6.s6_addr,
> +                                 sizeof(struct in6_addr));
> +                             memset(&nc->prefix, 0, sizeof(nc->prefix));
> +                             nc->prefix.aid = AID_VPN_IPv6;
> +                             nc->prefix.vpn6.rd = rd->rd;
> +                             memcpy(&nc->prefix.vpn6.addr.s6_addr, &prefix6,
> +                                 sizeof(struct in6_addr));
> +                             nc->prefix.vpn6.labellen = 3;
> +                             nc->prefix.vpn6.labelstack[0] =
> +                                 (rd->label >> 12) & 0xff;
> +                             nc->prefix.vpn6.labelstack[1] =
> +                                 (rd->label >> 4) & 0xff;
> +                             nc->prefix.vpn6.labelstack[2] =
> +                                 (rd->label << 4) & 0xf0;
> +                             nc->prefix.vpn6.labelstack[2] |= BGP_MPLS_BOS;
>                               break;
>                       default:
>                               log_warnx("unable to VPNize prefix");
> Index: rde.h
> ===================================================================
> RCS file: /cvs/src/usr.sbin/bgpd/rde.h,v
> retrieving revision 1.206
> diff -u -p -r1.206 rde.h
> --- rde.h     19 Dec 2018 15:26:42 -0000      1.206
> +++ rde.h     28 Dec 2018 16:00:23 -0000
> @@ -282,6 +282,19 @@ struct pt_entry_vpn4 {
>       u_int8_t                         pad2;
>  };
>  
> +struct pt_entry_vpn6 {
> +     RB_ENTRY(pt_entry)               pt_e;
> +     u_int8_t                         aid;
> +     u_int8_t                         prefixlen;
> +     u_int16_t                        refcnt;
> +     struct in6_addr                  prefix6;
> +     u_int64_t                        rd;
> +     u_int8_t                         labelstack[21];
> +     u_int8_t                         labellen;
> +     u_int8_t                         pad1;
> +     u_int8_t                         pad2;
> +};
> +
>  struct prefix {
>       LIST_ENTRY(prefix)               rib_l, nexthop_l;
>       struct rib_entry                *re;
> Index: rde_prefix.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/bgpd/rde_prefix.c,v
> retrieving revision 1.34
> diff -u -p -r1.34 rde_prefix.c
> --- rde_prefix.c      4 Sep 2018 12:00:29 -0000       1.34
> +++ rde_prefix.c      28 Dec 2018 16:00:23 -0000
> @@ -90,6 +90,16 @@ pt_getaddr(struct pt_entry *pte, struct 
>                   ((struct pt_entry_vpn4 *)pte)->labelstack,
>                   addr->vpn4.labellen);
>               break;
> +     case AID_VPN_IPv6:
> +             memcpy(&addr->vpn6.addr,
> +                 &((struct pt_entry_vpn6 *)pte)->prefix6,
> +                 sizeof(addr->vpn6.addr));
> +             addr->vpn6.rd = ((struct pt_entry_vpn6 *)pte)->rd;
> +             addr->vpn6.labellen = ((struct pt_entry_vpn6 *)pte)->labellen;
> +             memcpy(addr->vpn6.labelstack,
> +                 ((struct pt_entry_vpn6 *)pte)->labelstack,
> +                 addr->vpn6.labellen);
> +             break;
>       default:
>               fatalx("pt_getaddr: unknown af");
>       }
> @@ -101,6 +111,7 @@ pt_fill(struct bgpd_addr *prefix, int pr
>       static struct pt_entry4         pte4;
>       static struct pt_entry6         pte6;
>       static struct pt_entry_vpn4     pte_vpn4;
> +     static struct pt_entry_vpn6     pte_vpn6;
>  
>       switch (prefix->aid) {
>       case AID_INET:
> @@ -132,6 +143,19 @@ pt_fill(struct bgpd_addr *prefix, int pr
>               memcpy(pte_vpn4.labelstack, prefix->vpn4.labelstack,
>                   prefix->vpn4.labellen);
>               return ((struct pt_entry *)&pte_vpn4);
> +     case AID_VPN_IPv6:
> +             memset(&pte_vpn6, 0, sizeof(pte_vpn6));
> +             pte_vpn6.aid = prefix->aid;
> +             if (prefixlen > 128)
> +                     fatalx("pt_get: bad IPv6 prefixlen");
> +             inet6applymask(&pte_vpn6.prefix6, &prefix->vpn6.addr,
> +                 prefixlen);
> +             pte_vpn6.prefixlen = prefixlen;
> +             pte_vpn6.rd = prefix->vpn6.rd;
> +             pte_vpn6.labellen = prefix->vpn6.labellen;
> +             memcpy(pte_vpn6.labelstack, prefix->vpn6.labelstack,
> +                 prefix->vpn6.labellen);
> +             return ((struct pt_entry *)&pte_vpn6);
>       default:
>               fatalx("pt_fill: unknown af");
>       }
> @@ -183,6 +207,7 @@ pt_lookup(struct bgpd_addr *addr)
>               i = 32;
>               break;
>       case AID_INET6:
> +     case AID_VPN_IPv6:
>               i = 128;
>               break;
>       default:
> @@ -202,6 +227,7 @@ pt_prefix_cmp(const struct pt_entry *a, 
>       const struct pt_entry4          *a4, *b4;
>       const struct pt_entry6          *a6, *b6;
>       const struct pt_entry_vpn4      *va4, *vb4;
> +     const struct pt_entry_vpn6      *va6, *vb6;
>       int                              i;
>  
>       if (a->aid > b->aid)
> @@ -239,6 +265,10 @@ pt_prefix_cmp(const struct pt_entry *a, 
>       case AID_VPN_IPv4:
>               va4 = (const struct pt_entry_vpn4 *)a;
>               vb4 = (const struct pt_entry_vpn4 *)b;
> +             if (betoh64(va4->rd) > betoh64(vb4->rd))
> +                     return (1);
> +             if (betoh64(va4->rd) < betoh64(vb4->rd))
> +                     return (-1);
>               if (ntohl(va4->prefix4.s_addr) > ntohl(vb4->prefix4.s_addr))
>                       return (1);
>               if (ntohl(va4->prefix4.s_addr) < ntohl(vb4->prefix4.s_addr))
> @@ -247,9 +277,23 @@ pt_prefix_cmp(const struct pt_entry *a, 
>                       return (1);
>               if (va4->prefixlen < vb4->prefixlen)
>                       return (-1);
> -             if (betoh64(va4->rd) > betoh64(vb4->rd))
> +             return (0);
> +     case AID_VPN_IPv6:
> +             va6 = (const struct pt_entry_vpn6 *)a;
> +             vb6 = (const struct pt_entry_vpn6 *)b;
> +             if (betoh64(va6->rd) > betoh64(vb6->rd))
>                       return (1);
> -             if (betoh64(va4->rd) < betoh64(vb4->rd))
> +             if (betoh64(va6->rd) < betoh64(vb6->rd))
> +                     return (-1);
> +             i = memcmp(&va6->prefix6, &vb6->prefix6,
> +                 sizeof(struct in6_addr));
> +             if (i > 0)
> +                     return (1);
> +             if (i < 0)
> +                     return (-1);
> +             if (va6->prefixlen > vb6->prefixlen)
> +                     return (1);
> +             if (va6->prefixlen < vb6->prefixlen)
>                       return (-1);
>               return (0);
>       default:
> Index: rde_rib.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/bgpd/rde_rib.c,v
> retrieving revision 1.187
> diff -u -p -r1.187 rde_rib.c
> --- rde_rib.c 11 Dec 2018 09:02:14 -0000      1.187
> +++ rde_rib.c 28 Dec 2018 16:00:23 -0000
> @@ -264,6 +264,7 @@ rib_lookup(struct rib *rib, struct bgpd_
>               }
>               break;
>       case AID_INET6:
> +     case AID_VPN_IPv6:
>               for (i = 128; i >= 0; i--) {
>                       re = rib_get(rib, addr, i);
>                       if (re != NULL)
> @@ -1017,6 +1018,34 @@ prefix_write(u_char *buf, int len, struc
>               buf += sizeof(prefix->vpn4.rd);
>               memcpy(buf, &prefix->vpn4.addr, PREFIX_SIZE(plen) - 1);
>               return (totlen);
> +     case AID_VPN_IPv6:
> +             totlen = PREFIX_SIZE(plen) + sizeof(prefix->vpn6.rd);
> +             plen += sizeof(prefix->vpn6.rd) * 8;
> +             if (withdraw) {
> +                     /* withdraw have one compat label as placeholder */
> +                     totlen += 3;
> +                     plen += 3 * 8;
> +             } else {
> +                     totlen += prefix->vpn6.labellen;
> +                     plen += prefix->vpn6.labellen * 8;
> +             }
> +             if (totlen > len)
> +                     return (-1);
> +             *buf++ = plen;
> +             if (withdraw) {
> +                     /* magic compatibility label as per rfc8277 */
> +                     *buf++ = 0x80;
> +                     *buf++ = 0x0;
> +                     *buf++ = 0x0;
> +             } else  {
> +                     memcpy(buf, &prefix->vpn6.labelstack,
> +                         prefix->vpn6.labellen);
> +                     buf += prefix->vpn6.labellen;
> +             }
> +             memcpy(buf, &prefix->vpn6.rd, sizeof(prefix->vpn6.rd));
> +             buf += sizeof(prefix->vpn6.rd);
> +             memcpy(buf, &prefix->vpn6.addr, PREFIX_SIZE(plen) - 1);
> +             return (totlen);
>       default:
>               return (-1);
>       }
> @@ -1036,6 +1065,10 @@ prefix_writebuf(struct ibuf *buf, struct
>       case AID_VPN_IPv4:
>               totlen = PREFIX_SIZE(plen) + sizeof(prefix->vpn4.rd) +
>                   prefix->vpn4.labellen;
> +             break;
> +     case AID_VPN_IPv6:
> +             totlen = PREFIX_SIZE(plen) + sizeof(prefix->vpn6.rd) +
> +                 prefix->vpn6.labellen;
>               break;
>       default:
>               return (-1);
> Index: rde_update.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/bgpd/rde_update.c,v
> retrieving revision 1.106
> diff -u -p -r1.106 rde_update.c
> --- rde_update.c      19 Dec 2018 15:26:42 -0000      1.106
> +++ rde_update.c      28 Dec 2018 16:00:23 -0000
> @@ -184,6 +184,27 @@ up_prefix_cmp(struct update_prefix *a, s
>                       return (1);
>               return (memcmp(a->prefix.vpn4.labelstack,
>                   b->prefix.vpn4.labelstack, a->prefix.vpn4.labellen));
> +     case AID_VPN_IPv6:
> +             if (betoh64(a->prefix.vpn6.rd) < betoh64(b->prefix.vpn6.rd))
> +                     return (-1);
> +             if (betoh64(a->prefix.vpn6.rd) > betoh64(b->prefix.vpn6.rd))
> +                     return (1);
> +             i = memcmp(&a->prefix.vpn6.addr, &b->prefix.vpn6.addr,
> +                 sizeof(struct in6_addr));
> +             if (i > 0)
> +                     return (1);
> +             if (i < 0)
> +                     return (-1);
> +             if (a->prefixlen < b->prefixlen)
> +                     return (-1);
> +             if (a->prefixlen > b->prefixlen)
> +                     return (1);
> +             if (a->prefix.vpn6.labellen < b->prefix.vpn6.labellen)
> +                     return (-1);
> +             if (a->prefix.vpn6.labellen > b->prefix.vpn6.labellen)
> +                     return (1);
> +             return (memcmp(a->prefix.vpn6.labelstack,
> +                 b->prefix.vpn6.labelstack, a->prefix.vpn6.labellen));
>       default:
>               fatalx("up_prefix_cmp: unknown af");
>       }
> @@ -745,6 +766,68 @@ up_generate_mp_reach(struct rde_peer *pe
>                       /* ebgp multihop */
>                       memcpy(&upa->mpattr[12], &peer->local_v4_addr.v4,
>                           sizeof(struct in_addr));
> +             return (0);
> +     case AID_VPN_IPv6:
> +             upa->mpattr_len = 29; /* AFI + SAFI + NH LEN + NH + Reserved */
> +             upa->mpattr = calloc(upa->mpattr_len, 1);
> +             if (upa->mpattr == NULL)
> +                     fatal("up_generate_mp_reach");
> +             if (aid2afi(aid, &tmp, &upa->mpattr[2]))
> +                     fatalx("up_generate_mp_reachi: bad AID");
> +             tmp = htons(tmp);
> +             memcpy(upa->mpattr, &tmp, sizeof(tmp));
> +             upa->mpattr[3] = sizeof(u_int64_t) + sizeof(struct in6_addr);
> +             upa->mpattr[28] = 0; /* Reserved must be 0 */
> +
> +             /* nexthop dance see also up_get_nexthop() */
> +             if (state->nhflags & NEXTHOP_NOMODIFY) {
> +                     /* no modify flag set */
> +                     if (state->nexthop == NULL)
> +                             memcpy(&upa->mpattr[12],
> +                                 &peer->local_v6_addr.v6,
> +                                 sizeof(struct in6_addr));
> +                     else
> +                             memcpy(&upa->mpattr[12],
> +                                 &state->nexthop->exit_nexthop.v6,
> +                                 sizeof(struct in6_addr));
> +             } else if (state->nhflags & NEXTHOP_SELF)
> +                     memcpy(&upa->mpattr[12], &peer->local_v6_addr.v6,
> +                         sizeof(struct in6_addr));
> +             else if (!peer->conf.ebgp) {
> +                     /* ibgp */
> +                     if (state->nexthop == NULL ||
> +                         (state->nexthop->exit_nexthop.aid == AID_INET6 &&
> +                         !memcmp(&state->nexthop->exit_nexthop.v6,
> +                         &peer->remote_addr.v6, sizeof(struct in6_addr))))
> +                             memcpy(&upa->mpattr[12],
> +                                 &peer->local_v6_addr.v6,
> +                                 sizeof(struct in6_addr));
> +                     else
> +                             memcpy(&upa->mpattr[12],
> +                                 &state->nexthop->exit_nexthop.v6,
> +                                 sizeof(struct in6_addr));
> +             } else if (peer->conf.distance == 1) {
> +                     /* ebgp directly connected */
> +                     if (state->nexthop != NULL &&
> +                         state->nexthop->flags & NEXTHOP_CONNECTED)
> +                             if (prefix_compare(&peer->remote_addr,
> +                                 &state->nexthop->nexthop_net,
> +                                 state->nexthop->nexthop_netlen) == 0) {
> +                                     /*
> +                                     * nexthop and peer are in the same
> +                                     * subnet
> +                                     */
> +                                     memcpy(&upa->mpattr[12],
> +                                         &state->nexthop->exit_nexthop.v6,
> +                                         sizeof(struct in6_addr));
> +                                     return (0);
> +                             }
> +                     memcpy(&upa->mpattr[12], &peer->local_v6_addr.v6,
> +                         sizeof(struct in6_addr));
> +             } else
> +                     /* ebgp multihop */
> +                     memcpy(&upa->mpattr[12], &peer->local_v6_addr.v6,
> +                         sizeof(struct in6_addr));
>               return (0);
>       default:
>               break;
> Index: util.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/bgpd/util.c,v
> retrieving revision 1.41
> diff -u -p -r1.41 util.c
> --- util.c    11 Dec 2018 09:02:14 -0000      1.41
> +++ util.c    28 Dec 2018 16:00:23 -0000
> @@ -39,8 +39,8 @@ const char  *aspath_delim(u_int8_t, int);
>  const char *
>  log_addr(const struct bgpd_addr *addr)
>  {
> -     static char     buf[48];
> -     char            tbuf[16];
> +     static char     buf[74];
> +     char            tbuf[40];
>  
>       switch (addr->aid) {
>       case AID_INET:
> @@ -56,6 +56,13 @@ log_addr(const struct bgpd_addr *addr)
>               snprintf(buf, sizeof(buf), "%s %s", log_rd(addr->vpn4.rd),
>                  tbuf);
>               return (buf);
> +     case AID_VPN_IPv6:
> +             if (inet_ntop(aid2af(addr->aid), &addr->vpn6.addr, tbuf,
> +                 sizeof(tbuf)) == NULL)
> +                     return ("?");
> +             snprintf(buf, sizeof(buf), "%s %s", log_rd(addr->vpn6.rd),
> +                 tbuf);
> +             return (buf);
>       }
>       return ("???");
>  }
> @@ -575,9 +582,77 @@ nlri_get_vpn4(u_char *p, u_int16_t len, 
>       return (plen + rv);
>  }
>  
> +int
> +nlri_get_vpn6(u_char *p, u_int16_t len, struct bgpd_addr *prefix,
> +    u_int8_t *prefixlen, int withdraw)
> +{
> +     int             rv, done = 0;
> +     u_int8_t        pfxlen;
> +     u_int16_t       plen;
> +
> +     if (len < 1)
> +             return (-1);
> +
> +     memcpy(&pfxlen, p, 1);
> +     p += 1;
> +     plen = 1;
> +
> +     memset(prefix, 0, sizeof(struct bgpd_addr));
> +
> +     /* label stack */
> +     do {
> +             if (len - plen < 3 || pfxlen < 3 * 8)
> +                     return (-1);
> +             if (prefix->vpn6.labellen + 3U >
> +                 sizeof(prefix->vpn6.labelstack))
> +                     return (-1);
> +             if (withdraw) {
> +                     /* on withdraw ignore the labelstack all together */
> +                     plen += 3;
> +                     pfxlen -= 3 * 8;
> +                     break;
> +             }
> +
> +             prefix->vpn6.labelstack[prefix->vpn6.labellen++] = *p++;
> +             prefix->vpn6.labelstack[prefix->vpn6.labellen++] = *p++;
> +             prefix->vpn6.labelstack[prefix->vpn6.labellen] = *p++;
> +             if (prefix->vpn6.labelstack[prefix->vpn6.labellen] &
> +                 BGP_MPLS_BOS)
> +                     done = 1;
> +             prefix->vpn6.labellen++;
> +             plen += 3;
> +             pfxlen -= 3 * 8;
> +     } while (!done);
> +
> +     /* RD */
> +     if (len - plen < (int)sizeof(u_int64_t) ||
> +         pfxlen < sizeof(u_int64_t) * 8)
> +             return (-1);
> +
> +     memcpy(&prefix->vpn6.rd, p, sizeof(u_int64_t));
> +     pfxlen -= sizeof(u_int64_t) * 8;
> +     p += sizeof(u_int64_t);
> +     plen += sizeof(u_int64_t);
> +
> +     /* prefix */
> +     prefix->aid = AID_VPN_IPv6;
> +     *prefixlen = pfxlen;
> +
> +     if (pfxlen > 128)
> +             return (-1);
> +
> +     if ((rv = extract_prefix(p, len, &prefix->vpn6.addr,
> +         pfxlen, sizeof(prefix->vpn6.addr))) == -1)
> +             return (-1);
> +
> +     return (plen + rv);
> +}
> +
> +
> +
>  /*
>   * This function will have undefined behaviour if the passed in prefixlen is
> - * to large for the respective bgpd_addr address family.
> + * too large for the respective bgpd_addr address family.
>   */
>  int
>  prefix_compare(const struct bgpd_addr *a, const struct bgpd_addr *b,
> @@ -637,6 +712,32 @@ prefix_compare(const struct bgpd_addr *a
>                       return (-1);
>               return (memcmp(a->vpn4.labelstack, b->vpn4.labelstack,
>                   a->vpn4.labellen));
> +     case AID_VPN_IPv6:
> +             if (prefixlen > 128)
> +                     return (-1);
> +             if (betoh64(a->vpn6.rd) > betoh64(b->vpn6.rd))
> +                     return (1);
> +             if (betoh64(a->vpn6.rd) < betoh64(b->vpn6.rd))
> +                     return (-1);
> +             for (i = 0; i < prefixlen / 8; i++)
> +                     if (a->vpn6.addr.s6_addr[i] != b->vpn6.addr.s6_addr[i])
> +                             return (a->vpn6.addr.s6_addr[i] -
> +                                 b->vpn6.addr.s6_addr[i]);
> +             i = prefixlen % 8;
> +             if (i) {
> +                     m = 0xff00 >> i;
> +                     if ((a->vpn6.addr.s6_addr[prefixlen / 8] & m) !=
> +                         (b->vpn6.addr.s6_addr[prefixlen / 8] & m))
> +                             return ((a->vpn6.addr.s6_addr[prefixlen / 8] &
> +                                 m) - (b->vpn6.addr.s6_addr[prefixlen / 8] &
> +                                 m));
> +             }
> +             if (a->vpn6.labellen > b->vpn6.labellen)
> +                     return (1);
> +             if (a->vpn6.labellen < b->vpn6.labellen)
> +                     return (-1);
> +             return (memcmp(a->vpn6.labelstack, b->vpn6.labelstack,
> +                 a->vpn6.labellen));
>       }
>       return (-1);
>  }
> 

-- 
:wq Claudio

Reply via email to