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