On Tue, Dec 18, 2018 at 12:13:38PM +0100, Denis Fondras wrote:
> Here is a serie of diffs to enable MPLSv6, MPLS transport over IPv6.
> 
> Second diff : add support for IPv6 MPLS routes exchange with bgpd(8).
> 
> (***********************************)
> pe1# cat /etc/hostname.mpe0                                                   
>  
> rdomain 2
> mplslabel 42
> inet6 2001:db8::2/128
> up
> (***********************************)
> pe1# cat /etc/hostname.vio0                                                   
>  
> rdomain 2
> inet6 2001:db8::2 126
> up
> (***********************************)
> pe1# cat /etc/hostname.vio1                                                   
>  
> mpls
> inet6 2001:db8:1::2 126
> up
> (***********************************)
> pe1# cat /etc/hostname.lo0                                                    
>  
> inet6 2001:db8:fffe::1 128
> up
> (***********************************)
> pe1# cat /etc/bgpd.conf                                                       
>  
> router-id 10.0.0.2
> AS 65530
> 
> rdomain 2 {
>   descr "CUSTOMER1"
>   rd 65530:2
>   import-target rt 65530:2
>   export-target rt 65530:2
>   depend on mpe0
>   network inet connected
>   network inet6 connected
> }
> group "ibgp" {
>   announce IPv4 vpn
>   announce IPv4 unicast
>   announce IPv6 vpn
>   announce IPv6 unicast
>   remote-as 65530
>   neighbor 10.255.254.2 {
>     local-address 10.255.254.1
>     descr PE2v4
>     down
>   }
>   neighbor 2001:db8:fffe::2 {
>     local-address 2001:db8:fffe::1
>     descr PE2v6
>   }
> }
> allow from ibgp
> allow to ibgp
> (***********************************)
> pe1# bgpctl sh rib                                                            
>                                                         
> flags: * = Valid, > = Selected, I = via IBGP, A = Announced,
>        S = Stale, E = Error
> origin validation state: N = not-found, V = valid, ! = invalid
> origin: i = IGP, e = EGP, ? = Incomplete
> 
> flags ovs destination          gateway          lpref   med aspath origin     
>                                                         
> AI*>    N rd 65530:2 2001:db8::/126 rd 0:0 ::          100     0 i
> I*>     N rd 65530:2 2001:db8:ffff::/126 2001:db8:fffe::2    100     0 i      
>     
> (***********************************)
> pe2# tcpdump -n -i vio1 mpls
> tcpdump: listening on vio1, link-type EN10MB
> 08:13:01.870005 MPLS(label 42, exp 0, ttl 62) 2001:db8::1 > 2001:db8:ffff::1: 
> icmp6: echo request                                     
> 08:13:01.870882 MPLS(label 26, exp 0, ttl 63) MPLS(label 42, exp 0, ttl 63) 
> 2001:db8:ffff::1 > 2001:db8::1: icmp6: echo reply         
> 08:13:02.362564 MPLS(label 42, exp 0, ttl 62) 2001:db8::1 > 2001:db8:ffff::1: 
> icmp6: echo request                                     
> 08:13:02.363173 MPLS(label 26, exp 0, ttl 63) MPLS(label 42, exp 0, ttl 63) 
> 2001:db8:ffff::1 > 2001:db8::1: icmp6: echo reply         
> 08:13:02.865183 MPLS(label 42, exp 0, ttl 62) 2001:db8::1 > 2001:db8:ffff::1: 
> icmp6: echo request
> (***********************************)
> 
> We can only exchange MPLS routes with the same address family as the
> transport AF.
> 
> Unfortunately I don't have gear to test interoperability. It seems there is 
> very
> few support that.  Has anyone access to such hardware ?


I don't think I have capable hardware but diff looks good apart from one
small thing at the end.
 
> Index: bgpd/bgpd.h
> ===================================================================
> RCS file: /cvs/src/usr.sbin/bgpd/bgpd.h,v
> retrieving revision 1.357
> diff -u -p -r1.357 bgpd.h
> --- bgpd/bgpd.h       11 Dec 2018 09:02:14 -0000      1.357
> +++ bgpd/bgpd.h       18 Dec 2018 11:04:07 -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
> @@ -597,6 +611,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;
> @@ -1270,6 +1285,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: bgpd/kroute.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/bgpd/kroute.c,v
> retrieving revision 1.226
> diff -u -p -r1.226 kroute.c
> --- bgpd/kroute.c     6 Dec 2018 13:04:40 -0000       1.226
> +++ bgpd/kroute.c     18 Dec 2018 11:04:07 -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: bgpd/mrt.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/bgpd/mrt.c,v
> retrieving revision 1.87
> diff -u -p -r1.87 mrt.c
> --- bgpd/mrt.c        24 Oct 2018 08:26:37 -0000      1.87
> +++ bgpd/mrt.c        18 Dec 2018 11:04:07 -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: bgpd/parse.y
> ===================================================================
> RCS file: /cvs/src/usr.sbin/bgpd/parse.y,v
> retrieving revision 1.365
> diff -u -p -r1.365 parse.y
> --- bgpd/parse.y      6 Dec 2018 12:38:01 -0000       1.365
> +++ bgpd/parse.y      18 Dec 2018 11:04:07 -0000
> @@ -3952,6 +3952,7 @@ merge_prefixspec(struct filter_prefix *p
>               max_len = 32;
>               break;
>       case AID_INET6:
> +     case AID_VPN_IPv6:
>               max_len = 128;
>               break;
>       }
> Index: bgpd/printconf.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/bgpd/printconf.c,v
> retrieving revision 1.124
> diff -u -p -r1.124 printconf.c
> --- bgpd/printconf.c  28 Nov 2018 08:32:27 -0000      1.124
> +++ bgpd/printconf.c  18 Dec 2018 11:04:07 -0000
> @@ -69,6 +69,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: bgpd/rde.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/bgpd/rde.c,v
> retrieving revision 1.452
> diff -u -p -r1.452 rde.c
> --- bgpd/rde.c        11 Dec 2018 09:02:14 -0000      1.452
> +++ bgpd/rde.c        18 Dec 2018 11:04:07 -0000
> @@ -1236,6 +1236,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;
> @@ -1359,6 +1376,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;
> @@ -1900,6 +1936,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
> @@ -2346,6 +2392,7 @@ rde_dump_ctx_new(struct ctl_show_rib_req
>                       hostplen = 32;
>                       break;
>               case AID_INET6:
> +             case AID_VPN_IPv6:
>                       hostplen = 128;
>                       break;
>               default:
> @@ -2484,6 +2531,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;
> @@ -3610,6 +3658,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;
>  
> @@ -3634,6 +3683,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);
> @@ -3691,6 +3758,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;
>  
> @@ -3716,6 +3784,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: bgpd/rde.h
> ===================================================================
> RCS file: /cvs/src/usr.sbin/bgpd/rde.h,v
> retrieving revision 1.205
> diff -u -p -r1.205 rde.h
> --- bgpd/rde.h        17 Dec 2018 11:24:30 -0000      1.205
> +++ bgpd/rde.h        18 Dec 2018 11:04:07 -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: bgpd/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
> --- bgpd/rde_prefix.c 4 Sep 2018 12:00:29 -0000       1.34
> +++ bgpd/rde_prefix.c 18 Dec 2018 11:04:07 -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)
> @@ -250,6 +276,24 @@ pt_prefix_cmp(const struct pt_entry *a, 
>               if (betoh64(va4->rd) > betoh64(vb4->rd))
>                       return (1);
>               if (betoh64(va4->rd) < betoh64(vb4->rd))
> +                     return (-1);
> +             return (0);
> +     case AID_VPN_IPv6:
> +             va6 = (const struct pt_entry_vpn6 *)a;
> +             vb6 = (const struct pt_entry_vpn6 *)b;
> +             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);
> +             if (betoh64(va6->rd) > betoh64(vb6->rd))
> +                     return (1);
> +             if (betoh64(va6->rd) < betoh64(vb6->rd))
>                       return (-1);
>               return (0);
>       default:
> Index: bgpd/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
> --- bgpd/rde_rib.c    11 Dec 2018 09:02:14 -0000      1.187
> +++ bgpd/rde_rib.c    18 Dec 2018 11:04:07 -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: bgpd/rde_update.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/bgpd/rde_update.c,v
> retrieving revision 1.105
> diff -u -p -r1.105 rde_update.c
> --- bgpd/rde_update.c 29 Nov 2018 12:10:51 -0000      1.105
> +++ bgpd/rde_update.c 18 Dec 2018 11:04:07 -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: bgpd/util.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/bgpd/util.c,v
> retrieving revision 1.41
> diff -u -p -r1.41 util.c
> --- bgpd/util.c       11 Dec 2018 09:02:14 -0000      1.41
> +++ bgpd/util.c       18 Dec 2018 11:04:07 -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,
> @@ -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().

-- 
:wq Claudio

Reply via email to