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