Here is a serie of diffs to enable MPLSv6, MPLS transport over IPv6. First diff : allow mpe(4) to handle IPv6 trafic.
Index: net/if_ethersubr.c =================================================================== RCS file: /cvs/src/sys/net/if_ethersubr.c,v retrieving revision 1.255 diff -u -p -r1.255 if_ethersubr.c --- net/if_ethersubr.c 12 Dec 2018 05:38:26 -0000 1.255 +++ net/if_ethersubr.c 18 Dec 2018 11:03:33 -0000 @@ -246,18 +246,28 @@ ether_resolve(struct ifnet *ifp, struct sizeof(eh->ether_dhost)); break; #ifdef INET6 +do_v6: case AF_INET6: error = nd6_resolve(ifp, rt, m, dst, eh->ether_dhost); if (error) return (error); break; #endif +do_v4: case AF_INET: - case AF_MPLS: error = arpresolve(ifp, rt, m, dst, eh->ether_dhost); if (error) return (error); break; + case AF_MPLS: + switch (rt->rt_gateway->sa_family) { + case AF_INET: + goto do_v4; +#ifdef INET6 + case AF_INET6: + goto do_v6; +#endif + } default: senderr(EHOSTUNREACH); } Index: net/if_mpe.c =================================================================== RCS file: /cvs/src/sys/net/if_mpe.c,v retrieving revision 1.64 diff -u -p -r1.64 if_mpe.c --- net/if_mpe.c 9 Jan 2018 15:24:24 -0000 1.64 +++ net/if_mpe.c 18 Dec 2018 11:03:33 -0000 @@ -85,7 +85,7 @@ mpe_clone_create(struct if_clone *ifc, i mpeif->sc_unit = unit; ifp = &mpeif->sc_if; snprintf(ifp->if_xname, sizeof ifp->if_xname, "mpe%d", unit); - ifp->if_flags = IFF_POINTOPOINT; + ifp->if_flags = IFF_POINTOPOINT|IFF_MULTICAST; ifp->if_xflags = IFXF_CLONED; ifp->if_softc = mpeif; ifp->if_mtu = MPE_MTU; @@ -157,6 +157,16 @@ mpestart(struct ifnet *ifp0) sizeof(in_addr_t)); m_adj(m, sizeof(in_addr_t)); break; +#ifdef INET6 + case AF_INET6: + memset(sa, 0, sizeof(struct sockaddr_in6)); + satosin6(sa)->sin6_family = af; + satosin6(sa)->sin6_len = sizeof(struct sockaddr_in6); + bcopy(mtod(m, caddr_t), &satosin6(sa)->sin6_addr, + sizeof(struct in6_addr)); + m_adj(m, sizeof(struct in6_addr)); + break; +#endif default: m_freem(m); continue; @@ -204,6 +214,9 @@ mpeoutput(struct ifnet *ifp, struct mbuf int error; int off; in_addr_t addr; +#ifdef INET6 + struct in6_addr addr6; +#endif u_int8_t op = 0; #ifdef DIAGNOSTIC @@ -251,6 +264,39 @@ mpeoutput(struct ifnet *ifp, struct mbuf m_copyback(m, sizeof(sa_family_t), sizeof(in_addr_t), &addr, M_NOWAIT); break; +#ifdef INET6 + case AF_INET6: + if (!rt || !(rt->rt_flags & RTF_MPLS)) { + m_freem(m); + error = ENETUNREACH; + goto out; + } + shim.shim_label = ((struct rt_mpls *)rt->rt_llinfo)->mpls_label; + shim.shim_label |= MPLS_BOS_MASK; + op = ((struct rt_mpls *)rt->rt_llinfo)->mpls_operation; + if (op != MPLS_OP_PUSH) { + m_freem(m); + error = ENETUNREACH; + goto out; + } + if (mpls_mapttl_ip) { + struct ip6_hdr *ip6; + ip6 = mtod(m, struct ip6_hdr *); + shim.shim_label |= htonl(ip6->ip6_hops) & MPLS_TTL_MASK; + } else + shim.shim_label |= htonl(mpls_defttl) & MPLS_TTL_MASK; + off = sizeof(sa_family_t) + sizeof(struct in6_addr); + M_PREPEND(m, sizeof(shim) + off, M_DONTWAIT); + if (m == NULL) { + error = ENOBUFS; + goto out; + } + *mtod(m, sa_family_t *) = AF_INET6; + addr6 = satosin6(rt->rt_gateway)->sin6_addr; + m_copyback(m, sizeof(sa_family_t), sizeof(struct in6_addr), + &addr6, M_NOWAIT); + break; +#endif default: m_freem(m); error = EPFNOSUPPORT; @@ -354,6 +400,9 @@ mpeioctl(struct ifnet *ifp, u_long cmd, } /* return with ENOTTY so that the parent handler finishes */ return (ENOTTY); + case SIOCADDMULTI: + case SIOCDELMULTI: + break; default: return (ENOTTY); } Index: netinet/icmp6.h =================================================================== RCS file: /cvs/src/sys/netinet/icmp6.h,v retrieving revision 1.47 diff -u -p -r1.47 icmp6.h --- netinet/icmp6.h 8 Aug 2017 18:15:58 -0000 1.47 +++ netinet/icmp6.h 18 Dec 2018 11:03:33 -0000 @@ -610,16 +610,17 @@ struct rtentry; struct rttimer; struct in6_multi; -void icmp6_init(void); -void icmp6_paramerror(struct mbuf *, int); -void icmp6_error(struct mbuf *, int, int, int); -int icmp6_input(struct mbuf **, int *, int, int); -void icmp6_fasttimo(void); -void icmp6_reflect(struct mbuf *, size_t); -void icmp6_prepare(struct mbuf *); -void icmp6_redirect_input(struct mbuf *, int); -void icmp6_redirect_output(struct mbuf *, struct rtentry *); -int icmp6_sysctl(int *, u_int, void *, size_t *, void *, size_t); +void icmp6_init(void); +void icmp6_paramerror(struct mbuf *, int); +struct mbuf *icmp6_do_error(struct mbuf *, int, int, int); +void icmp6_error(struct mbuf *, int, int, int); +int icmp6_input(struct mbuf **, int *, int, int); +void icmp6_fasttimo(void); +int icmp6_reflect(struct mbuf *, size_t, u_int32_t); +void icmp6_prepare(struct mbuf *); +void icmp6_redirect_input(struct mbuf *, int); +void icmp6_redirect_output(struct mbuf *, struct rtentry *); +int icmp6_sysctl(int *, u_int, void *, size_t *, void *, size_t); struct ip6ctlparam; void icmp6_mtudisc_update(struct ip6ctlparam *, int); Index: netinet6/icmp6.c =================================================================== RCS file: /cvs/src/sys/netinet6/icmp6.c,v retrieving revision 1.228 diff -u -p -r1.228 icmp6.c --- netinet6/icmp6.c 10 Dec 2018 23:00:01 -0000 1.228 +++ netinet6/icmp6.c 18 Dec 2018 11:03:33 -0000 @@ -102,6 +102,10 @@ #include <net/pfvar.h> #endif +#ifdef MPLS +#include <netmpls/mpls.h> +#endif + struct cpumem *icmp6counters; extern int icmp6errppslim; @@ -231,11 +235,8 @@ icmp6_mtudisc_callback_register(void (*f LIST_INSERT_HEAD(&icmp6_mtudisc_callbacks, mc, mc_list); } -/* - * Generate an error packet of type error in response to bad IP6 packet. - */ -void -icmp6_error(struct mbuf *m, int type, int code, int param) +struct mbuf * +icmp6_do_error(struct mbuf *m, int type, int code, int param) { struct ip6_hdr *oip6, *nip6; struct icmp6_hdr *icmp6; @@ -250,8 +251,9 @@ icmp6_error(struct mbuf *m, int type, in if (m->m_len < sizeof(struct ip6_hdr)) { m = m_pullup(m, sizeof(struct ip6_hdr)); - if (m == NULL) - return; + if (m == NULL) { + return (NULL); + } } oip6 = mtod(m, struct ip6_hdr *); @@ -294,7 +296,7 @@ icmp6_error(struct mbuf *m, int type, in sizeof(*icp)); if (icp == NULL) { icmp6stat_inc(icp6s_tooshort); - return; + return (NULL); } if (icp->icmp6_type < ICMP6_ECHO_REQUEST || icp->icmp6_type == ND_REDIRECT) { @@ -334,7 +336,7 @@ icmp6_error(struct mbuf *m, int type, in m = m_pullup(m, preplen); if (m == NULL) { nd6log((LOG_DEBUG, "ENOBUFS in icmp6_error %d\n", __LINE__)); - return; + return (NULL); } nip6 = mtod(m, struct ip6_hdr *); @@ -361,18 +363,33 @@ icmp6_error(struct mbuf *m, int type, in m->m_pkthdr.ph_ifidx = 0; icmp6stat_inc(icp6s_outhist + type); - icmp6_reflect(m, sizeof(struct ip6_hdr)); /* header order: IPv6 - ICMPv6 */ - return; + return (m); freeit: /* * If we can't tell wheter or not we can generate ICMP6, free it. */ - m_freem(m); + return(m_freem(m)); } /* + * Generate an error packet of type error in response to bad IP6 packet. + */ +void +icmp6_error(struct mbuf *m, int type, int code, int param) +{ + struct mbuf *n; + + n = icmp6_do_error(m, type, code, param); + if (n != NULL) { + /* header order: IPv6 - ICMPv6 */ + if (!icmp6_reflect(n, sizeof(struct ip6_hdr), -1)) + ip6_send(n); + } +} + +/* * Process a received ICMP6 message. */ int @@ -597,7 +614,8 @@ icmp6_input(struct mbuf **mp, int *offp, nicmp6->icmp6_code = 0; icmp6stat_inc(icp6s_reflect); icmp6stat_inc(icp6s_outhist + ICMP6_ECHO_REPLY); - icmp6_reflect(n, noff); + if (!icmp6_reflect(n, noff, -1)) + ip6_send(n); } if (!m) goto freeit; @@ -1030,15 +1048,17 @@ icmp6_mtudisc_update(struct ip6ctlparam * Reflect the ip6 packet back to the source. * OFF points to the icmp6 header, counted from the top of the mbuf. */ -void -icmp6_reflect(struct mbuf *m, size_t off) +int +icmp6_reflect(struct mbuf *m, size_t off, u_int32_t mpls_label) { struct rtentry *rt = NULL; struct ip6_hdr *ip6; struct icmp6_hdr *icmp6; struct in6_addr t, *src = NULL; struct sockaddr_in6 sa6_src, sa6_dst; + struct in6_ifaddr *ia6; u_int rtableid; + char addr[INET6_ADDRSTRLEN]; CTASSERT(sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr) <= MHLEN); @@ -1051,8 +1071,10 @@ icmp6_reflect(struct mbuf *m, size_t off goto bad; } - if (m->m_pkthdr.ph_loopcnt++ >= M_MAXLOOP) - goto bad; + if (m->m_pkthdr.ph_loopcnt++ >= M_MAXLOOP) { + m_freem(m); + return (ELOOP); + } rtableid = m->m_pkthdr.ph_rtableid; m_resethdr(m); m->m_pkthdr.ph_rtableid = rtableid; @@ -1071,7 +1093,7 @@ icmp6_reflect(struct mbuf *m, size_t off l = sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr); if (m->m_len < l) { if ((m = m_pullup(m, l)) == NULL) - return; + return (EMSGSIZE); } memcpy(mtod(m, caddr_t), &nip6, sizeof(nip6)); } else /* off == sizeof(struct ip6_hdr) */ { @@ -1079,7 +1101,7 @@ icmp6_reflect(struct mbuf *m, size_t off l = sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr); if (m->m_len < l) { if ((m = m_pullup(m, l)) == NULL) - return; + return (EMSGSIZE); } } ip6 = mtod(m, struct ip6_hdr *); @@ -1094,8 +1116,8 @@ icmp6_reflect(struct mbuf *m, size_t off ip6->ip6_dst = ip6->ip6_src; /* - * XXX: make sure to embed scope zone information, using - * already embedded IDs or the received interface (if any). + * XXX: make sure to embed scope zone information, using already + * embedded IDs or the received interface (if any). * Note that rcvif may be NULL. * TODO: scoped routing case (XXX). */ @@ -1107,39 +1129,23 @@ icmp6_reflect(struct mbuf *m, size_t off sa6_dst.sin6_family = AF_INET6; sa6_dst.sin6_len = sizeof(sa6_dst); sa6_dst.sin6_addr = t; + +#ifdef MPLS + if (mpls_label != -1) { + struct sockaddr_mpls sa_mpls, *smpls; + /* set ip6_src to something usable, based on the MPLS label */ + bzero(&sa_mpls, sizeof(sa_mpls)); + smpls = &sa_mpls; + smpls->smpls_family = AF_MPLS; + smpls->smpls_len = sizeof(*smpls); + smpls->smpls_label = mpls_label; - /* - * If the incoming packet was addressed directly to us (i.e. unicast), - * use dst as the src for the reply. - * The IN6_IFF_TENTATIVE|IN6_IFF_DUPLICATED case would be VERY rare, - * but is possible (for example) when we encounter an error while - * forwarding procedure destined to a duplicated address of ours. - */ - rt = rtalloc(sin6tosa(&sa6_dst), 0, rtableid); - if (rtisvalid(rt) && ISSET(rt->rt_flags, RTF_LOCAL) && - !ISSET(ifatoia6(rt->rt_ifa)->ia6_flags, - IN6_IFF_ANYCAST|IN6_IFF_TENTATIVE|IN6_IFF_DUPLICATED)) { - src = &t; - } - rtfree(rt); - rt = NULL; - - if (src == NULL) { - struct in6_ifaddr *ia6; - - /* - * This case matches to multicasts, our anycast, or unicasts - * that we do not own. Select a source address based on the - * source address of the erroneous packet. - */ - rt = rtalloc(sin6tosa(&sa6_src), RT_RESOLVE, rtableid); + rt = rtalloc(smplstosa(smpls), RT_RESOLVE, rtableid); if (!rtisvalid(rt)) { - char addr[INET6_ADDRSTRLEN]; - nd6log((LOG_DEBUG, "%s: source can't be determined: dst=%s\n", __func__, inet_ntop(AF_INET6, &sa6_src.sin6_addr, - addr, sizeof(addr)))); + addr, sizeof(addr)))); rtfree(rt); goto bad; } @@ -1149,6 +1155,48 @@ icmp6_reflect(struct mbuf *m, size_t off if (src == NULL) src = &ifatoia6(rt->rt_ifa)->ia_addr.sin6_addr; } +#endif + if (src == NULL) { + /* + * If the incoming packet was addressed directly to us (i.e. + * unicast), use dst as the src for the reply. The + * IN6_IFF_TENTATIVE|IN6_IFF_DUPLICATED case would be VERY rare, + * but is possible (for example) when we encounter an error + * while forwarding procedure destined to a duplicated address + * of ours. + */ + rt = rtalloc(sin6tosa(&sa6_dst), 0, rtableid); + if (rtisvalid(rt) && ISSET(rt->rt_flags, RTF_LOCAL) && + !ISSET(ifatoia6(rt->rt_ifa)->ia6_flags, + IN6_IFF_ANYCAST|IN6_IFF_TENTATIVE|IN6_IFF_DUPLICATED)) { + src = &t; + } + rtfree(rt); + rt = NULL; + + if (src == NULL) { + /* + * This case matches to multicasts, our anycast, or + * unicasts that we do not own. Select a source address + * based on the source address of the erroneous packet. + */ + rt = rtalloc(sin6tosa(&sa6_src), RT_RESOLVE, rtableid); + if (!rtisvalid(rt)) { + nd6log((LOG_DEBUG, + "%s: source can't be determined: dst=%s\n", + __func__, inet_ntop(AF_INET6, + &sa6_src.sin6_addr, addr, sizeof(addr)))); + rtfree(rt); + goto bad; + } + ia6 = in6_ifawithscope(rt->rt_ifa->ifa_ifp, &t, + rtableid); + if (ia6 != NULL) + src = &ia6->ia_addr.sin6_addr; + if (src == NULL) + src = &ifatoia6(rt->rt_ifa)->ia_addr.sin6_addr; + } + } ip6->ip6_src = *src; rtfree(rt); @@ -1167,13 +1215,11 @@ icmp6_reflect(struct mbuf *m, size_t off */ m->m_flags &= ~(M_BCAST|M_MCAST); - - ip6_send(m); - return; + return (0); bad: m_freem(m); - return; + return (EHOSTUNREACH); } void Index: netmpls/mpls_input.c =================================================================== RCS file: /cvs/src/sys/netmpls/mpls_input.c,v retrieving revision 1.68 diff -u -p -r1.68 mpls_input.c --- netmpls/mpls_input.c 12 Jan 2018 06:57:56 -0000 1.68 +++ netmpls/mpls_input.c 18 Dec 2018 11:03:33 -0000 @@ -36,6 +36,8 @@ #ifdef INET6 #include <netinet/ip6.h> +#include <netinet6/ip6_var.h> +#include <netinet/icmp6.h> #endif /* INET6 */ #include <netmpls/mpls.h> @@ -200,8 +202,19 @@ do_v6: #if NMPE > 0 if (ifp->if_type == IFT_MPLS) { smpls = satosmpls(rt_key(rt)); - mpe_input(m, ifp, smpls, ttl); - goto done; + if (m->m_len < sizeof(u_char) && + (m = m_pullup(m, sizeof(u_char))) == NULL) + return; + switch (*mtod(m, u_char *) >> 4) { + case IPVERSION: + mpe_input(m, ifp, smpls, ttl); + goto done; +#ifdef INET6 + case IPV6_VERSION >> 4: + mpe_input6(m, ifp, smpls, ttl); + goto done; +#endif + } } #endif if (ifp->if_type == IFT_MPLSTUNNEL) { @@ -345,6 +358,9 @@ mpls_do_error(struct mbuf *m, int type, struct icmp *icp; struct ip *ip; int nstk, error; +#ifdef INET6 + struct ip6_hdr *ip6; +#endif for (nstk = 0; nstk < MPLS_INKERNEL_LOOP_MAX; nstk++) { if (m->m_len < sizeof(*shim) && @@ -419,6 +435,21 @@ mpls_do_error(struct mbuf *m, int type, break; #ifdef INET6 case IPV6_VERSION >> 4: + m = icmp6_do_error(m, ICMP6_TIME_EXCEEDED, + ICMP6_TIME_EXCEED_TRANSIT, 0); + if (m == NULL) + return (NULL); + + error = icmp6_reflect(m, sizeof(struct ip6_hdr), + shim->shim_label & MPLS_LABEL_MASK); + if (error) + return (NULL); + + ip6 = mtod(m, struct ip6_hdr *); + ip6->ip6_plen = htons(m->m_pkthdr.len - sizeof(struct ip6_hdr)); + m->m_pkthdr.csum_flags |= M_ICMP_CSUM_OUT; + in6_proto_cksum_out(m, NULL); + break; #endif default: m_freem(m);