Index: net/if.c =================================================================== RCS file: /cvs/src/sys/net/if.c,v retrieving revision 1.571 diff -u -p -r1.571 if.c --- net/if.c 9 Jan 2019 01:14:21 -0000 1.571 +++ net/if.c 2 Feb 2019 09:56:31 -0000 @@ -391,6 +391,8 @@ if_idxmap_remove(struct ifnet *ifp) refcnt_finalize(&ifp->if_refcnt, "ifidxrm"); } +# + void if_ifp_dtor(void *null, void *ifp) { @@ -2143,6 +2145,26 @@ ifioctl(struct socket *so, u_long cmd, c NET_UNLOCK(); break; + case SIOCSETLABEL: + case SIOCDELLABEL: + case SIOCSPWE3CTRLWORD: + case SIOCSPWE3FAT: + case SIOCSPWE3NEIGHBOR: + case SIOCDPWE3NEIGHBOR: + if ((error = suser(p)) != 0) + break; + /* FALLTHROUGH */ + case SIOCGETLABEL: + case SIOCGPWE3CTRLWORD: + case SIOCGPWE3NEIGHBOR: + case SIOCGPWE3FAT: + if_ref(ifp); + KERNEL_UNLOCK(); + error = ((*ifp->if_ioctl)(ifp, cmd, data)); + KERNEL_LOCK(); + if_put(ifp); + break; + case SIOCSETKALIVE: case SIOCDIFPHYADDR: case SIOCSLIFPHYADDR: @@ -2884,6 +2906,12 @@ ifa_print_all(void) printf(" on %s\n", ifp->if_xname); } } +} + +unsigned long * +if_idxmap_map(void) +{ + return (srp_get_locked(&if_idxmap.map)); } #endif /* DDB */ Index: net/if_bridge.c =================================================================== RCS file: /cvs/src/sys/net/if_bridge.c,v retrieving revision 1.318 diff -u -p -r1.318 if_bridge.c --- net/if_bridge.c 23 Jan 2019 15:27:08 -0000 1.318 +++ net/if_bridge.c 2 Feb 2019 09:56:31 -0000 @@ -311,13 +311,7 @@ bridge_ioctl(struct ifnet *ifp, u_long c error = ifpromisc(ifs, 1); if (error != 0) break; - } -#if NMPW > 0 - else if (ifs->if_type == IFT_MPLSTUNNEL) { - /* Nothing needed */ - } -#endif /* NMPW */ - else { + } else { error = EINVAL; break; } @@ -367,8 +361,7 @@ bridge_ioctl(struct ifnet *ifp, u_long c error = ENOENT; break; } - if (ifs->if_type != IFT_ETHER && - ifs->if_type != IFT_MPLSTUNNEL) { + if (ifs->if_type != IFT_ETHER) { error = EINVAL; break; } @@ -805,15 +798,7 @@ bridge_output(struct ifnet *ifp, struct (bif->bif_flags & IFBIF_STP) && (bif->bif_state == BSTP_IFSTATE_DISCARDING)) continue; -#if NMPW > 0 - /* - * Split horizon: avoid broadcasting messages from - * wire to another wire. - */ - if (ifp->if_type == IFT_MPLSTUNNEL && - dst_if->if_type == IFT_MPLSTUNNEL) - continue; -#endif /* NMPW */ + if ((bif->bif_flags & IFBIF_DISCOVER) == 0 && (m->m_flags & (M_BCAST | M_MCAST)) == 0) continue; @@ -1275,16 +1260,6 @@ bridge_broadcast(struct bridge_softc *sc if (bridge_localbroadcast(dst_if, eh, m)) sc->sc_if.if_oerrors++; - -#if NMPW > 0 - /* - * Split horizon: avoid broadcasting messages from wire to - * another wire. - */ - if (ifp->if_type == IFT_MPLSTUNNEL && - dst_if->if_type == IFT_MPLSTUNNEL) - continue; -#endif /* NMPW */ /* If last one, reuse the passed-in mbuf */ if (SLIST_NEXT(bif, bif_next) == NULL) { Index: net/if_mpip.c =================================================================== RCS file: net/if_mpip.c diff -N net/if_mpip.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ net/if_mpip.c 2 Feb 2019 09:56:31 -0000 @@ -0,0 +1,721 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2015 Rafael Zalamena + * Copyright (c) 2019 David Gwynne + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "bpfilter.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#ifdef INET6 +#include +#endif + +#include + +#if NBPFILTER > 0 +#include +#endif /* NBPFILTER */ + +struct mpip_neighbor { + struct shim_hdr n_rshim; + struct sockaddr_storage n_nexthop; +}; + +struct mpip_softc { + struct ifnet sc_if; + uint32_t sc_flow; /* xor for mbuf flowid */ + + struct ifaddr sc_ifa; + struct sockaddr_mpls sc_smpls; /* Local label */ + struct mpip_neighbor *sc_neighbor; + struct rwlock sc_cfg_lock; + + unsigned int sc_cword; /* control word */ + unsigned int sc_fword; /* flow-aware transport */ + int sc_ttl; +}; + +void mpipattach(int); +int mpip_clone_create(struct if_clone *, int); +int mpip_clone_destroy(struct ifnet *); +int mpip_ioctl(struct ifnet *, u_long, caddr_t); +int mpip_output(struct ifnet *, struct mbuf *, struct sockaddr *, + struct rtentry *); +void mpip_start(struct ifnet *); + +struct if_clone mpip_cloner = + IF_CLONE_INITIALIZER("mpip", mpip_clone_create, mpip_clone_destroy); + +void +mpipattach(int n) +{ + if_clone_attach(&mpip_cloner); +} + +int +mpip_clone_create(struct if_clone *ifc, int unit) +{ + struct mpip_softc *sc; + struct ifnet *ifp; + + sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK|M_CANFAIL|M_ZERO); + if (sc == NULL) + return (ENOMEM); + + sc->sc_neighbor = 0; + sc->sc_cword = 0; /* default to no control word */ + sc->sc_fword = 0; /* both sides have to agree on FAT first */ + sc->sc_flow = arc4random() & 0xfffff; + sc->sc_smpls.smpls_len = sizeof(sc->sc_smpls); + sc->sc_smpls.smpls_family = AF_MPLS; + sc->sc_ttl = -1; + + rw_init(&sc->sc_cfg_lock, "mpipcfg"); + + ifp = &sc->sc_if; + snprintf(ifp->if_xname, sizeof(ifp->if_xname), "%s%d", + ifc->ifc_name, unit); + ifp->if_softc = sc; + ifp->if_type = IFT_TUNNEL; + ifp->if_flags = IFF_POINTOPOINT | IFF_MULTICAST; + ifp->if_xflags = IFXF_CLONED; + ifp->if_ioctl = mpip_ioctl; + ifp->if_output = mpip_output; + ifp->if_start = mpip_start; + ifp->if_rtrequest = p2p_rtrequest; + ifp->if_mtu = 1500; + ifp->if_hardmtu = 65535; + IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN); + + if_attach(ifp); + if_counters_alloc(ifp); + if_alloc_sadl(ifp); + +#if NBPFILTER > 0 + bpfattach(&ifp->if_bpf, ifp, DLT_LOOP, sizeof(uint32_t)); +#endif + + sc->sc_ifa.ifa_ifp = ifp; + sc->sc_ifa.ifa_addr = sdltosa(ifp->if_sadl); + + return (0); +} + +int +mpip_clone_destroy(struct ifnet *ifp) +{ + struct mpip_softc *sc = ifp->if_softc; + + ifp->if_flags &= ~IFF_RUNNING; /* XXX locking */ + + rw_enter_write(&sc->sc_cfg_lock); + if (sc->sc_smpls.smpls_label) { + rt_ifa_del(&sc->sc_ifa, RTF_LOCAL | RTF_MPLS, + smplstosa(&sc->sc_smpls)); + } + + if_detach(ifp); + rw_exit_write(&sc->sc_cfg_lock); + + free(sc->sc_neighbor, M_DEVBUF, sizeof(*sc->sc_neighbor)); + free(sc, M_DEVBUF, sizeof(*sc)); + + return (0); +} + +static int +mpip_set_label(struct mpip_softc *sc, struct ifreq *ifr) +{ + struct shim_hdr label; + uint32_t shim; + int error; + + error = copyin(ifr->ifr_data, &label, sizeof(label)); + if (error != 0) + return (error); + + if (label.shim_label > MPLS_LABEL_MAX || + label.shim_label <= MPLS_LABEL_RESERVED_MAX) + return (EINVAL); + + shim = MPLS_LABEL2SHIM(label.shim_label); + + error = rw_enter(&sc->sc_cfg_lock, RW_WRITE|RW_INTR); + if (error != 0) + return (error); + + if (sc->sc_smpls.smpls_label == shim) + goto exit; + + if (sc->sc_smpls.smpls_label != MPLS_LABEL2SHIM(0)) { + rt_ifa_del(&sc->sc_ifa, RTF_MPLS | RTF_LOCAL, + smplstosa(&sc->sc_smpls)); + } + + sc->sc_smpls.smpls_label = shim; + error = rt_ifa_add(&sc->sc_ifa, RTF_MPLS | RTF_LOCAL, + smplstosa(&sc->sc_smpls)); + if (error) { + sc->sc_smpls.smpls_label = MPLS_LABEL2SHIM(0); + goto exit; + } + +exit: + rw_exit(&sc->sc_cfg_lock); + + return (error); +} + +static int +mpip_get_label(struct mpip_softc *sc, struct ifreq *ifr) +{ + struct shim_hdr label; + int error; + + error = rw_enter(&sc->sc_cfg_lock, RW_READ|RW_INTR); + if (error != 0) + return (error); + + label.shim_label = MPLS_SHIM2LABEL(sc->sc_smpls.smpls_label); + + rw_exit(&sc->sc_cfg_lock); + + if (label.shim_label == MPLS_LABEL2SHIM(0)) + return (EADDRNOTAVAIL); + + return (copyout(&label, ifr->ifr_data, sizeof(label))); +} + +static int +mpip_del_label(struct mpip_softc *sc) +{ + int error; + + error = rw_enter(&sc->sc_cfg_lock, RW_WRITE|RW_INTR); + if (error != 0) + return (error); + + if (sc->sc_smpls.smpls_label != MPLS_LABEL2SHIM(0)) { + rt_ifa_del(&sc->sc_ifa, RTF_MPLS | RTF_LOCAL, + smplstosa(&sc->sc_smpls)); + } + + sc->sc_smpls.smpls_label = MPLS_LABEL2SHIM(0); + + rw_exit(&sc->sc_cfg_lock); + + return (0); +} + +static int +mpip_set_neighbor(struct mpip_softc *sc, struct if_laddrreq *req) +{ + struct mpip_neighbor *n, *o; + struct sockaddr *sa = (struct sockaddr *)&req->addr; + struct sockaddr_mpls *smpls = (struct sockaddr_mpls *)&req->dstaddr; + uint32_t label; + int error; + + if (smpls->smpls_family != AF_MPLS) + return (EINVAL); + label = smpls->smpls_label; + if (label > MPLS_LABEL_MAX || label <= MPLS_LABEL_RESERVED_MAX) + return (EINVAL); + + switch (sa->sa_family) { + case AF_INET: { + struct sockaddr_in *sin = (struct sockaddr_in *)sa; + + if (in_nullhost(sin->sin_addr) || + IN_MULTICAST(sin->sin_addr.s_addr)) + return (EINVAL); + + break; + } +#ifdef INET6 + case AF_INET6: { + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; + + if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) || + IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) + return (EINVAL); + + /* check scope */ + + break; + } +#endif + default: + return (EAFNOSUPPORT); + } + + n = malloc(sizeof(*n), M_DEVBUF, M_WAITOK|M_CANFAIL|M_ZERO); + if (n == NULL) + return (ENOMEM); + + n->n_rshim.shim_label = MPLS_LABEL2SHIM(label); + n->n_nexthop = req->addr; + + error = rw_enter(&sc->sc_cfg_lock, RW_WRITE | RW_INTR); + if (error != 0) + return (error); + + o = sc->sc_neighbor; + sc->sc_neighbor = n; + + rw_exit(&sc->sc_cfg_lock); + + ifq_barrier(&sc->sc_if.if_snd); + + if (o != NULL) + free(o, M_DEVBUF, sizeof(*o)); + + return (0); +} + +static int +mpip_get_neighbor(struct mpip_softc *sc, struct if_laddrreq *req) +{ + struct mpip_neighbor n, *o; + struct sockaddr_mpls *smpls = (struct sockaddr_mpls *)&req->dstaddr; + int error; + + error = rw_enter(&sc->sc_cfg_lock, RW_READ | RW_INTR); + if (error != 0) + return (error); + + o = sc->sc_neighbor; + if (o) + n = *o; + + rw_exit(&sc->sc_cfg_lock); + + if (o == NULL) + return (EADDRNOTAVAIL); + + smpls->smpls_len = sizeof(*smpls); + smpls->smpls_family = AF_MPLS; + smpls->smpls_label = MPLS_SHIM2LABEL(o->n_rshim.shim_label); + + req->addr = o->n_nexthop; + + return (0); +} + +static int +mpip_del_neighbor(struct mpip_softc *sc, struct ifreq *req) +{ + struct mpip_neighbor *o; + int error; + + error = rw_enter(&sc->sc_cfg_lock, RW_WRITE | RW_INTR); + if (error != 0) + return (error); + + o = sc->sc_neighbor; + sc->sc_neighbor = NULL; + + rw_exit(&sc->sc_cfg_lock); + + ifq_barrier(&sc->sc_if.if_snd); + + if (o != NULL) + free(o, M_DEVBUF, sizeof(*o)); + + return (0); +} + +int +mpip_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) +{ + struct mpip_softc *sc = ifp->if_softc; + struct ifreq *ifr = (struct ifreq *)data; + int error = 0; + + switch (cmd) { + case SIOCSIFADDR: + break; + case SIOCSIFFLAGS: + if ((ifp->if_flags & IFF_UP)) + ifp->if_flags |= IFF_RUNNING; + else + ifp->if_flags &= ~IFF_RUNNING; + break; + case SIOCSIFMTU: + if (ifr->ifr_mtu < 60 || /* XXX */ + ifr->ifr_mtu > 65536) /* XXX */ + error = EINVAL; + else + ifp->if_mtu = ifr->ifr_mtu; + break; + + case SIOCGPWE3: + ifr->ifr_pwe3 = IF_PWE3_IP; + break; + case SIOCSPWE3CTRLWORD: + sc->sc_cword = ifr->ifr_pwe3 ? 1 : 0; + break; + case SIOCGPWE3CTRLWORD: + ifr->ifr_pwe3 = sc->sc_cword; + break; + case SIOCSPWE3FAT: + sc->sc_fword = ifr->ifr_pwe3 ? 1 : 0; + break; + case SIOCGPWE3FAT: + ifr->ifr_pwe3 = sc->sc_fword; + break; + + case SIOCSETLABEL: + error = mpip_set_label(sc, ifr); + break; + case SIOCGETLABEL: + error = mpip_get_label(sc, ifr); + break; + case SIOCDELLABEL: + error = mpip_del_label(sc); + break; + + case SIOCSPWE3NEIGHBOR: + error = mpip_set_neighbor(sc, (struct if_laddrreq *)data); + break; + case SIOCGPWE3NEIGHBOR: + error = mpip_get_neighbor(sc, (struct if_laddrreq *)data); + break; + case SIOCDPWE3NEIGHBOR: + error = mpip_del_neighbor(sc, ifr); + break; + + case SIOCSLIFPHYTTL: + if (ifr->ifr_ttl != -1 && + (ifr->ifr_ttl < 1 || ifr->ifr_ttl > 0xff)) { + error = EINVAL; + break; + } + + /* commit */ + sc->sc_ttl = ifr->ifr_ttl; + break; + + case SIOCGLIFPHYTTL: + ifr->ifr_ttl = sc->sc_ttl; + break; + + + case SIOCADDMULTI: + case SIOCDELMULTI: + break; + + default: + error = ENOTTY; + break; + } + + return (error); +} + +static void +mpip_input(struct mpip_softc *sc, struct mbuf *m) +{ + struct ifnet *ifp = &sc->sc_if; + uint32_t shim; + struct mbuf *n; + uint8_t ttl; + void (*input)(struct ifnet *, struct mbuf *); + + if (!ISSET(ifp->if_flags, IFF_RUNNING)) + goto drop; + + shim = *mtod(m, uint32_t *); + m_adj(m, sizeof(shim)); + + ttl = ntohl(shim & MPLS_TTL_MASK); + + if (sc->sc_fword) { + uint32_t label; + + if (MPLS_BOS_ISSET(shim)) + goto drop; + + if (m->m_len < sizeof(shim)) { + m = m_pullup(m, sizeof(shim)); + if (m == NULL) + return; + } + + shim = *mtod(m, uint32_t *); + if (!MPLS_BOS_ISSET(shim)) + goto drop; + + label = MPLS_SHIM2LABEL(shim); + if (label <= MPLS_LABEL_RESERVED_MAX) { + counters_inc(ifp->if_counters, ifc_noproto); /* ? */ + goto drop; + } + + label -= MPLS_LABEL_RESERVED_MAX + 1; + label ^= sc->sc_flow; + m->m_pkthdr.ph_flowid = M_FLOWID_VALID | label; + + m_adj(m, sizeof(shim)); + } else if (!MPLS_BOS_ISSET(shim)) + goto drop; + + if (sc->sc_cword) { + if (m->m_len < sizeof(shim)) { + m = m_pullup(m, sizeof(shim)); + if (m == NULL) + return; + } + shim = *mtod(m, uint32_t *); + + /* + * The first 4 bits identifies that this packet is a + * control word. If the control word is configured and + * we received an IP datagram we shall drop it. + */ + if (shim & CW_ZERO_MASK) { + counters_inc(ifp->if_counters, ifc_ierrors); + goto drop; + } + + /* We don't support fragmentation just yet. */ + if (shim & CW_FRAG_MASK) { + counters_inc(ifp->if_counters, ifc_ierrors); + goto drop; + } + + m_adj(m, sizeof(shim)); + } + + n = m; + while (n->m_len == 0) { + n = n->m_next; + if (n == NULL) + goto drop; + } + + switch (*mtod(n, uint8_t *) >> 4) { + case 4: + if (sc->sc_ttl == -1) { + m = mpls_ip_adjttl(m, ttl); + if (m == NULL) + return; + } + input = ipv4_input; + m->m_pkthdr.ph_family = AF_INET; + break; +#ifdef INET6 + case 6: + if (sc->sc_ttl == -1) { + m = mpls_ip6_adjttl(m, ttl); + if (m == NULL) + return; + } + input = ipv6_input; + m->m_pkthdr.ph_family = AF_INET6; + break; +#endif /* INET6 */ + default: + counters_inc(ifp->if_counters, ifc_noproto); + goto drop; + } + + m->m_pkthdr.ph_ifidx = ifp->if_index; + m->m_pkthdr.ph_rtableid = ifp->if_rdomain; + +#if NBPFILTER > 0 + { + caddr_t if_bpf = ifp->if_bpf; + if (if_bpf) { + bpf_mtap_af(if_bpf, m->m_pkthdr.ph_family, + m, BPF_DIRECTION_IN); + } + } +#endif + + (*input)(ifp, m); + return; +drop: + m_freem(m); +} + +int +mpip_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, + struct rtentry *rt) +{ + struct mpip_softc *sc = ifp->if_softc; + int error; + + if (dst->sa_family == AF_LINK && + rt != NULL && ISSET(rt->rt_flags, RTF_LOCAL)) { + mpip_input(sc, m); + return (0); + } + + if (!ISSET(ifp->if_flags, IFF_RUNNING)) { + error = ENETDOWN; + goto drop; + } + + switch (dst->sa_family) { + case AF_INET: +#ifdef INET6 + case AF_INET6: +#endif + break; + default: + error = EAFNOSUPPORT; + goto drop; + } + + m->m_pkthdr.ph_family = dst->sa_family; + + error = if_enqueue(ifp, m); + if (error) + counters_inc(ifp->if_counters, ifc_oerrors); + return (error); + +drop: + m_freem(m); + return (error); +} + +void +mpip_start(struct ifnet *ifp) +{ + struct mpip_softc *sc = ifp->if_softc; + struct mpip_neighbor *n = sc->sc_neighbor; + struct rtentry *rt; + struct ifnet *ifp0; + struct mbuf *m; + uint32_t shim; + struct sockaddr_mpls smpls = { + .smpls_len = sizeof(smpls), + .smpls_family = AF_MPLS, + }; + uint32_t bos; + uint8_t ttl; + + if (!ISSET(ifp->if_flags, IFF_RUNNING) || n == NULL) { + IFQ_PURGE(&ifp->if_snd); + return; + } + + rt = rtalloc(sstosa(&n->n_nexthop), RT_RESOLVE, 0); + if (!rtisvalid(rt)) { + IFQ_PURGE(&ifp->if_snd); + goto rtfree; + } + + ifp0 = if_get(rt->rt_ifidx); + if (ifp0 == NULL) { + IFQ_PURGE(&ifp->if_snd); + goto rtfree; + } + + while ((m = ifq_dequeue(&ifp->if_snd)) != NULL) { +#if NBPFILTER > 0 + caddr_t if_bpf = sc->sc_if.if_bpf; + if (if_bpf) { + bpf_mtap_af(if_bpf, m->m_pkthdr.ph_family, + m, BPF_DIRECTION_OUT); + } +#endif /* NBPFILTER */ + + if (sc->sc_ttl == -1) { + switch (m->m_pkthdr.ph_family) { + case AF_INET: { + struct ip *ip; + ip = mtod(m, struct ip *); + ttl = ip->ip_ttl; + break; + } +#ifdef INET6 + case AF_INET6: { + struct ip6_hdr *ip6; + ip6 = mtod(m, struct ip6_hdr *); + ttl = ip6->ip6_hlim; + break; + } +#endif + default: + unhandled_af(m->m_pkthdr.ph_family); + } + } else + ttl = mpls_defttl; + + if (sc->sc_cword) { + m = m_prepend(m, sizeof(shim), M_NOWAIT); + if (m == NULL) + continue; + + *mtod(m, uint32_t *) = 0; + } + + bos = MPLS_BOS_MASK; + + if (sc->sc_fword) { + uint32_t flow = 0; + m = m_prepend(m, sizeof(shim), M_NOWAIT); + if (m == NULL) + continue; + + if (ISSET(m->m_pkthdr.ph_flowid, M_FLOWID_VALID)) + flow = m->m_pkthdr.ph_flowid & M_FLOWID_MASK; + flow ^= sc->sc_flow; + flow += MPLS_LABEL_RESERVED_MAX + 1; + + shim = htonl(1) & MPLS_TTL_MASK; + shim |= htonl(flow << MPLS_LABEL_OFFSET) & + MPLS_LABEL_MASK; + shim |= bos; + *mtod(m, uint32_t *) = shim; + + bos = 0; + } + + m = m_prepend(m, sizeof(shim), M_NOWAIT); + if (m == NULL) + continue; + + shim = htonl(ttl) & MPLS_TTL_MASK; + shim |= n->n_rshim.shim_label; + shim |= bos; + *mtod(m, uint32_t *) = shim; + + mpls_output(ifp0, m, (struct sockaddr *)&smpls, rt); + } + + if_put(ifp0); +rtfree: + rtfree(rt); +} Index: net/route.c =================================================================== RCS file: /cvs/src/sys/net/route.c,v retrieving revision 1.379 diff -u -p -r1.379 route.c --- net/route.c 23 Nov 2018 16:24:11 -0000 1.379 +++ net/route.c 2 Feb 2019 09:56:31 -0000 @@ -1042,7 +1042,7 @@ rt_ifa_add(struct ifaddr *ifa, int flags memset(&info, 0, sizeof(info)); info.rti_ifa = ifa; - info.rti_flags = flags | RTF_MPATH; + info.rti_flags = flags; info.rti_info[RTAX_DST] = dst; if (flags & RTF_LLINFO) info.rti_info[RTAX_GATEWAY] = sdltosa(ifp->if_sadl); Index: netinet/in.c =================================================================== RCS file: /cvs/src/sys/netinet/in.c,v retrieving revision 1.160 diff -u -p -r1.160 in.c --- netinet/in.c 11 Jul 2018 21:18:23 -0000 1.160 +++ netinet/in.c 2 Feb 2019 09:56:31 -0000 @@ -694,7 +694,7 @@ in_purgeaddr(struct ifaddr *ifa) int in_addhost(struct in_ifaddr *ia, struct sockaddr_in *dst) { - return rt_ifa_add(&ia->ia_ifa, RTF_HOST, sintosa(dst)); + return rt_ifa_add(&ia->ia_ifa, RTF_HOST | RTF_MPATH, sintosa(dst)); } int @@ -712,12 +712,13 @@ in_insert_prefix(struct in_ifaddr *ia) struct ifaddr *ifa = &ia->ia_ifa; int error; - error = rt_ifa_add(ifa, RTF_CLONING | RTF_CONNECTED, ifa->ifa_addr); + error = rt_ifa_add(ifa, RTF_CLONING | RTF_CONNECTED | RTF_MPATH, + ifa->ifa_addr); if (error) return (error); if (ia->ia_broadaddr.sin_addr.s_addr != 0) - error = rt_ifa_add(ifa, RTF_HOST | RTF_BROADCAST, + error = rt_ifa_add(ifa, RTF_HOST | RTF_BROADCAST | RTF_MPATH, ifa->ifa_broadaddr); return (error); Index: netinet/ip_mroute.c =================================================================== RCS file: /cvs/src/sys/netinet/ip_mroute.c,v retrieving revision 1.123 diff -u -p -r1.123 ip_mroute.c --- netinet/ip_mroute.c 10 Oct 2018 11:46:59 -0000 1.123 +++ netinet/ip_mroute.c 2 Feb 2019 09:56:31 -0000 @@ -1308,7 +1308,7 @@ rt_mcast_add(struct ifnet *ifp, struct s return (NULL); } - rv = rt_ifa_add(ifa, RTF_HOST | RTF_MULTICAST, group); + rv = rt_ifa_add(ifa, RTF_HOST | RTF_MULTICAST | RTF_MPATH, group); if (rv != 0) { DPRINTF("rt_ifa_add failed (%d)", rv); return (NULL); Index: netinet6/in6.c =================================================================== RCS file: /cvs/src/sys/netinet6/in6.c,v retrieving revision 1.228 diff -u -p -r1.228 in6.c --- netinet6/in6.c 5 Oct 2018 07:06:09 -0000 1.228 +++ netinet6/in6.c 2 Feb 2019 09:56:31 -0000 @@ -376,7 +376,8 @@ in6_ioctl_change_ifaddr(u_long cmd, cadd break; /* No need to install a connected route. */ } - error = rt_ifa_add(&ia6->ia_ifa, RTF_CLONING | RTF_CONNECTED, + error = rt_ifa_add(&ia6->ia_ifa, + RTF_CLONING | RTF_CONNECTED | RTF_MPATH, ia6->ia_ifa.ifa_addr); if (error) { in6_purgeaddr(&ia6->ia_ifa); @@ -982,7 +983,8 @@ in6_ifinit(struct ifnet *ifp, struct in6 if ((ifp->if_flags & IFF_POINTOPOINT) && plen == 128 && ia6->ia_dstaddr.sin6_family == AF_INET6) { ifa = &ia6->ia_ifa; - error = rt_ifa_add(ifa, RTF_HOST, ifa->ifa_dstaddr); + error = rt_ifa_add(ifa, RTF_HOST | RTF_MPATH, + ifa->ifa_dstaddr); if (error != 0) return (error); ia6->ia_flags |= IFA_ROUTE; Index: netinet6/in6_ifattach.c =================================================================== RCS file: /cvs/src/sys/netinet6/in6_ifattach.c,v retrieving revision 1.111 diff -u -p -r1.111 in6_ifattach.c --- netinet6/in6_ifattach.c 5 Oct 2018 07:06:09 -0000 1.111 +++ netinet6/in6_ifattach.c 2 Feb 2019 09:56:31 -0000 @@ -374,7 +374,7 @@ in6_ifattach_linklocal(struct ifnet *ifp return (0); /* No need to install a connected route. */ } - flags = RTF_CONNECTED; + flags = RTF_CONNECTED | RTF_MPATH; if ((ifp->if_flags & IFF_POINTOPOINT) == 0) flags |= RTF_CLONING;