Hi, I am trying to make IPv6 over VPLS. I updated ldpd(8) to install MPLS route for IPv6 nexthop. I can see the routes but when pinging the destination I get "No route to host". Can someone give me a pointer for the next step ?
Thank you in advance, Denis * Without the patch : mpls1# route -n show Routing tables Internet: Destination Gateway Flags Refs Use Mtu Prio Iface [...] 172.16.0/24 192.168.150.139 UGT 0 6 - 32 vio0 Internet6: Destination Gateway Flags Refs Use Mtu Prio Iface [...] 2001:db8::/64 fe80::fcd8:d9ff:fe57:bd48%vio0 UG 0 4 - 32 vio0 2001:db8:1::/64 2001:db8:1::1 UCn 0 0 - 4 vether0 2001:db8:1::1 fe:e1:ba:d0:89:89 UHLl 0 76 - 1 vether0 2001:db8:fffe::/64 fe80::fcd8:d9ff:fe57:bd48%vio0 UG 1 6 - 32 vio0 2001:db8:ffff::/64 2001:db8:ffff::1 UCn 1 2 - 4 vio0 2001:db8:ffff::/64 link#1 UC 0 0 - 32 vio0 2001:db8:ffff::1 9e:21:8a:77:cd:cc UHLl 0 1511 - 1 vio0 2001:db8:ffff::2 fe:d8:d9:57:bd:48 UHLc 0 257 - 3 vio0 MPLS: In label Out label Op Gateway Flags Refs Use Mtu Prio Interface 17 - POP 192.168.150.139 UGT 0 0 - 32 vio0 18 16 SWAP 192.168.150.139 UGT 0 0 - 32 vio0 mpls1# route get 2001:db8::/64 route to: 2001:db8:: destination: 2001:db8:: mask: ffff:ffff:ffff:ffff:: gateway: fe80::fcd8:d9ff:fe57:bd48%vio0 interface: vio0 if address: fe80::9c21:8aff:fe77:cdcc%vio0 priority: 32 (ospf) flags: <UP,GATEWAY,DONE> use mtu expire 4 0 0 mpls1# ping6 2001:db8::1 PING 2001:db8::1 (2001:db8::1): 56 data bytes 64 bytes from 2001:db8::1: icmp_seq=0 hlim=63 time=1.039 ms 64 bytes from 2001:db8::1: icmp_seq=1 hlim=63 time=1.037 ms ^C --- 2001:db8::1 ping statistics --- 2 packets transmitted, 2 packets received, 0.0% packet loss round-trip min/avg/max/std-dev = 1.037/1.038/1.039/0.001 ms * With the patch : mpls1# route -n show Routing tables Internet: Destination Gateway Flags Refs Use Mtu Prio Iface [...] 172.16.0/24 192.168.150.139 UGT 0 6 - 32 vio0 Internet6: Destination Gateway Flags Refs Use Mtu Prio Iface [...] 2001:db8::/64 fe80::fcd8:d9ff:fe57:bd48%vio0 UGT 0 4 - 32 vio0 2001:db8:1::/64 2001:db8:1::1 UCn 0 0 - 4 vether0 2001:db8:1::1 fe:e1:ba:d0:89:89 UHLl 0 76 - 1 vether0 2001:db8:fffe::/64 fe80::fcd8:d9ff:fe57:bd48%vio0 UG 2 7 - 32 vio0 2001:db8:ffff::/64 2001:db8:ffff::1 UCn 1 2 - 4 vio0 2001:db8:ffff::/64 link#1 UC 0 0 - 32 vio0 2001:db8:ffff::1 9e:21:8a:77:cd:cc UHLl 0 1526 - 1 vio0 2001:db8:ffff::2 fe:d8:d9:57:bd:48 UHLc 0 281 - 3 vio0 MPLS: In label Out label Op Gateway Flags Refs Use Mtu Prio Interface 17 - POP 192.168.150.139 UGT 0 0 - 32 vio0 18 16 SWAP 192.168.150.139 UGT 0 0 - 32 vio0 19 18 SWAP fe80::fcd8:d9ff:fe57:bd48%vio0 UGT 0 0 - 32 vio0 20 - POP fe80::fcd8:d9ff:fe57:bd48%vio0 UGT 0 0 - 32 vio0 21 - LOCAL ::1%3 UGT 0 0 32768 8 lo0 22 - LOCAL ::1%3 UGT 0 0 32768 8 lo0 23 - LOCAL ::1%3 UGT 0 0 32768 8 lo0 24 - LOCAL ::1%3 UGT 0 0 32768 8 lo0 mpls1# route get 2001:db8::/64 route to: 2001:db8:: destination: 2001:db8:: mask: ffff:ffff:ffff:ffff:: gateway: fe80::fcd8:d9ff:fe57:bd48%vio0 interface: vio0 if address: fe80::9c21:8aff:fe77:cdcc%vio0 mpls label: PUSH 18 priority: 32 (ospf) flags: <UP,GATEWAY,DONE,MPLS> use mtu expire 4 0 0 sockaddrs: <DST,GATEWAY,NETMASK,IFP,IFA,SRC> mpls1# ping6 2001:db8::1 PING 2001:db8::1 (2001:db8::1): 56 data bytes ping6: sendmsg: No route to host ping: wrote 2001:db8::1 64 chars, ret=-1 ping6: sendmsg: No route to host ping: wrote 2001:db8::1 64 chars, ret=-1 ping6: sendmsg: No route to host ping: wrote 2001:db8::1 64 chars, ret=-1 ^C --- 2001:db8::1 ping statistics --- 3 packets transmitted, 0 packets received, 100.0% packet loss * Patch : Index: kroute.c =================================================================== RCS file: /cvs/src/usr.sbin/ldpd/kroute.c,v retrieving revision 1.66 diff -u -p -r1.66 kroute.c --- kroute.c 24 Jul 2017 11:00:01 -0000 1.66 +++ kroute.c 27 Dec 2017 12:48:59 -0000 @@ -259,7 +259,7 @@ kr_change(struct kroute *kr) if (ldp_addrisset(kn->r.af, &kn->r.nexthop) && kn->r.remote_label != NO_LABEL) { - if (send_rtmsg(kr_state.fd, RTM_CHANGE, &kn->r, AF_INET) == -1) + if (send_rtmsg(kr_state.fd, RTM_CHANGE, &kn->r, kn->r.af) == -1) return (-1); } @@ -305,7 +305,7 @@ kr_delete(struct kroute *kr) kn->r.remote_label = NO_LABEL; if (update && - send_rtmsg(kr_state.fd, RTM_CHANGE, &kn->r, AF_INET) == -1) + send_rtmsg(kr_state.fd, RTM_CHANGE, &kn->r, kn->r.af) == -1) return (-1); return (0); @@ -346,7 +346,7 @@ kr_fib_couple(void) if (ldp_addrisset(kn->r.af, &kn->r.nexthop) && kn->r.remote_label != NO_LABEL) { send_rtmsg(kr_state.fd, RTM_CHANGE, - &kn->r, AF_INET); + &kn->r, kn->r.af); } } } @@ -387,7 +387,7 @@ kr_fib_decouple(void) rl = kn->r.remote_label; kn->r.remote_label = NO_LABEL; send_rtmsg(kr_state.fd, RTM_CHANGE, - &kn->r, AF_INET); + &kn->r, kn->r.af); kn->r.remote_label = rl; } } @@ -1311,6 +1311,145 @@ send_rtmsg_v4(int fd, int action, struct static int send_rtmsg_v6(int fd, int action, struct kroute *kr, int family) { + struct iovec iov[5]; + struct rt_msghdr hdr; + struct sockaddr_mpls label_in, label_out; + struct sockaddr_in6 dst, mask, nexthop; + int iovcnt = 0; + + if (kr_state.fib_sync == 0) + return (0); + + /* + * Reserved labels (implicit and explicit NULL) should not be added + * to the FIB. + */ + if (family == AF_MPLS && kr->local_label < MPLS_LABEL_RESERVED_MAX) + return (0); + + /* initialize header */ + memset(&hdr, 0, sizeof(hdr)); + hdr.rtm_version = RTM_VERSION; + + hdr.rtm_type = action; + hdr.rtm_flags = RTF_UP; + hdr.rtm_fmask = RTF_MPLS; + hdr.rtm_seq = kr_state.rtseq++; /* overflow doesn't matter */ + hdr.rtm_msglen = sizeof(hdr); + hdr.rtm_hdrlen = sizeof(struct rt_msghdr); + hdr.rtm_priority = kr->priority; + hdr.rtm_tableid = kr_state.rdomain; /* rtableid */ + /* adjust iovec */ + iov[iovcnt].iov_base = &hdr; + iov[iovcnt++].iov_len = sizeof(hdr); + + if (family == AF_MPLS) { + memset(&label_in, 0, sizeof(label_in)); + label_in.smpls_len = sizeof(label_in); + label_in.smpls_family = AF_MPLS; + label_in.smpls_label = + htonl(kr->local_label << MPLS_LABEL_OFFSET); + /* adjust header */ + hdr.rtm_flags |= RTF_MPLS | RTF_MPATH; + hdr.rtm_addrs |= RTA_DST; + hdr.rtm_msglen += sizeof(label_in); + /* adjust iovec */ + iov[iovcnt].iov_base = &label_in; + iov[iovcnt++].iov_len = sizeof(label_in); + } else { + memset(&dst, 0, sizeof(dst)); + dst.sin6_len = sizeof(dst); + dst.sin6_family = AF_INET6; + dst.sin6_addr = kr->prefix.v6; + /* adjust header */ + hdr.rtm_addrs |= RTA_DST; + hdr.rtm_msglen += ROUNDUP(sizeof(dst)); + /* adjust iovec */ + iov[iovcnt].iov_base = &dst; + iov[iovcnt++].iov_len = ROUNDUP(sizeof(dst)); + } + + memset(&nexthop, 0, sizeof(nexthop)); + nexthop.sin6_len = sizeof(nexthop); + nexthop.sin6_family = AF_INET6; + nexthop.sin6_addr = kr->nexthop.v6; + nexthop.sin6_scope_id = kr->ifindex; + /* + * XXX we should set the sin6_scope_id but the kernel + * XXX does not expect it that way. It must be fiddled + * XXX into the sin6_addr. Welcome to the typical + * XXX IPv6 insanity and all without wine bottles. + */ + embedscope(&nexthop); + + /* adjust header */ + hdr.rtm_flags |= RTF_GATEWAY; + hdr.rtm_addrs |= RTA_GATEWAY; + hdr.rtm_msglen += ROUNDUP(sizeof(nexthop)); + /* adjust iovec */ + iov[iovcnt].iov_base = &nexthop; + iov[iovcnt++].iov_len = ROUNDUP(sizeof(nexthop)); + + if (family == AF_INET6) { + memset(&mask, 0, sizeof(mask)); + mask.sin6_len = sizeof(mask); + mask.sin6_family = AF_INET6; + mask.sin6_addr = *prefixlen2mask6(kr->prefixlen); + /* adjust header */ + if (kr->prefixlen == 128) + hdr.rtm_flags |= RTF_HOST; + hdr.rtm_addrs |= RTA_NETMASK; + hdr.rtm_msglen += ROUNDUP(sizeof(mask)); + /* adjust iovec */ + iov[iovcnt].iov_base = &mask; + iov[iovcnt++].iov_len = ROUNDUP(sizeof(mask)); + } + + /* If action is RTM_DELETE we have to get rid of MPLS infos */ + if (kr->remote_label != NO_LABEL && action != RTM_DELETE) { + memset(&label_out, 0, sizeof(label_out)); + label_out.smpls_len = sizeof(label_out); + label_out.smpls_family = AF_MPLS; + label_out.smpls_label = + htonl(kr->remote_label << MPLS_LABEL_OFFSET); + /* adjust header */ + hdr.rtm_addrs |= RTA_SRC; + hdr.rtm_flags |= RTF_MPLS; + hdr.rtm_msglen += sizeof(label_out); + /* adjust iovec */ + iov[iovcnt].iov_base = &label_out; + iov[iovcnt++].iov_len = sizeof(label_out); + + if (kr->remote_label == MPLS_LABEL_IMPLNULL) { + if (family == AF_MPLS) + hdr.rtm_mpls = MPLS_OP_POP; + else + return (0); + } else { + if (family == AF_MPLS) + hdr.rtm_mpls = MPLS_OP_SWAP; + else + hdr.rtm_mpls = MPLS_OP_PUSH; + } + } + + retry: + if (writev(fd, iov, iovcnt) == -1) { + if (errno == ESRCH) { + if (hdr.rtm_type == RTM_CHANGE && family == AF_MPLS) { + hdr.rtm_type = RTM_ADD; + goto retry; + } else if (hdr.rtm_type == RTM_DELETE) { + log_info("route %s/%u vanished before delete", + log_addr(kr->af, &kr->prefix), kr->prefixlen); + return (-1); + } + } + log_warn("%s action %u, af %s, prefix %s/%u", __func__, + hdr.rtm_type, af_name(family), log_addr(kr->af, &kr->prefix), + kr->prefixlen); + return (-1); + } return (0); }