diff options
author | David Gwynne <dlg@cvs.openbsd.org> | 2019-01-23 23:08:39 +0000 |
---|---|---|
committer | David Gwynne <dlg@cvs.openbsd.org> | 2019-01-23 23:08:39 +0000 |
commit | 5a4bf8b3547bae0e56ab27cbe970b3da4a5f0e72 (patch) | |
tree | df8c2f138cae00eb061c717b12929181818f5ec7 /sys/net/if_mpw.c | |
parent | 32229ab68967ba7a664f364ac7705625332ac9c2 (diff) |
rework mpw to be an actual ethernet interface.
this will allow for a lot of special casing in places like vlan and
bridge to go away since mpw will do all the same things as any other
ethernet tunnel. another benefit is you can run stuff directly on
the mpw interface to interact with the pseudowire, rather than
requiring a bridge and vether interface. this is like what juniper
calls Pseudowire Service Interfaces.
the caveat is that the implicit vlan or svlan tagging that mpw did
in ethernet-tagged mode now has to be done by hand. however, there
is some indication that different vendors pick different types of
tags, ie, one uses vlan tags and another uses svlan, so being able
to configure the right one has value. it is also possible you would
want to bridge the entire tag stack to another site, so being able
to bridge mpw without it playing with the tags can be useful.
because the if_type on mpw changes from IFT_MPLSTUNNEL to IFT_ETHER,
the semantic used to handle incoming packets in mpls_input is
changed. instead of mpls_input pushing the packets into mpw based
on the if_type being IFT_MPLSTUNNEL, mpw now adds an RTF_LOCAL route
to the mpls table. mpls_input falls through to "outputting" the
packet to mpw_output, which then uses the RTF_LOCAL flag to decide
to input to mpw_input and then ether_input. this semantic will be
applied to mpe soon, which removes all the interface special casing
in mpls_input. the if_type change also means mpw implements the
SIOCGPWE3 ioctl so ldpd can still figure out that the interface is
a pseudowire.
ok claudio@
Diffstat (limited to 'sys/net/if_mpw.c')
-rw-r--r-- | sys/net/if_mpw.c | 159 |
1 files changed, 48 insertions, 111 deletions
diff --git a/sys/net/if_mpw.c b/sys/net/if_mpw.c index 972f0693923..1aea90ebc26 100644 --- a/sys/net/if_mpw.c +++ b/sys/net/if_mpw.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_mpw.c,v 1.24 2018/02/19 08:59:52 mpi Exp $ */ +/* $OpenBSD: if_mpw.c,v 1.25 2019/01/23 23:08:38 dlg Exp $ */ /* * Copyright (c) 2015 Rafael Zalamena <rzalamena@openbsd.org> @@ -45,15 +45,16 @@ #endif struct mpw_softc { - struct ifnet sc_if; + struct arpcom sc_ac; +#define sc_if sc_ac.ac_if - struct ifaddr sc_ifa; - struct sockaddr_mpls sc_smpls; /* Local label */ + struct ifaddr sc_ifa; + struct sockaddr_mpls sc_smpls; /* Local label */ - uint32_t sc_flags; - uint32_t sc_type; - struct shim_hdr sc_rshim; - struct sockaddr_storage sc_nexthop; + uint32_t sc_flags; + uint32_t sc_type; + struct shim_hdr sc_rshim; + struct sockaddr_storage sc_nexthop; }; void mpwattach(int); @@ -63,7 +64,6 @@ int mpw_ioctl(struct ifnet *, u_long, caddr_t); int mpw_output(struct ifnet *, struct mbuf *, struct sockaddr *, struct rtentry *); void mpw_start(struct ifnet *); -int mpw_input(struct ifnet *, struct mbuf *, void *); #if NVLAN > 0 struct mbuf *mpw_vlan_handle(struct mbuf *, struct mpw_softc *); #endif /* NVLAN */ @@ -85,32 +85,25 @@ mpw_clone_create(struct if_clone *ifc, int unit) sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK|M_ZERO); ifp = &sc->sc_if; - snprintf(ifp->if_xname, sizeof(ifp->if_xname), "mpw%d", unit); + snprintf(ifp->if_xname, sizeof(ifp->if_xname), "%s%d", + ifc->ifc_name, unit); ifp->if_softc = sc; - ifp->if_mtu = ETHERMTU; - ifp->if_flags = IFF_POINTOPOINT; + ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; ifp->if_xflags = IFXF_CLONED; ifp->if_ioctl = mpw_ioctl; ifp->if_output = mpw_output; ifp->if_start = mpw_start; - ifp->if_type = IFT_MPLSTUNNEL; - ifp->if_hdrlen = ETHER_HDR_LEN; IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN); + ether_fakeaddr(ifp); if_attach(ifp); - if_alloc_sadl(ifp); + ether_ifattach(ifp); sc->sc_ifa.ifa_ifp = ifp; sc->sc_ifa.ifa_addr = sdltosa(ifp->if_sadl); sc->sc_smpls.smpls_len = sizeof(sc->sc_smpls); sc->sc_smpls.smpls_family = AF_MPLS; - if_ih_insert(ifp, mpw_input, NULL); - -#if NBPFILTER > 0 - bpfattach(&ifp->if_bpf, ifp, DLT_EN10MB, ETHER_HDR_LEN); -#endif /* NBFILTER */ - return (0); } @@ -126,23 +119,15 @@ mpw_clone_destroy(struct ifnet *ifp) smplstosa(&sc->sc_smpls)); } - if_ih_remove(ifp, mpw_input, NULL); - + ether_ifdetach(ifp); if_detach(ifp); + free(sc, M_DEVBUF, sizeof(*sc)); return (0); } int -mpw_input(struct ifnet *ifp, struct mbuf *m, void *cookie) -{ - /* Don't have local broadcast. */ - m_freem(m); - return (1); -} - -int mpw_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) { struct ifreq *ifr = (struct ifreq *) data; @@ -168,6 +153,10 @@ mpw_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) ifp->if_flags &= ~IFF_RUNNING; break; + case SIOCGPWE3: + ifr->ifr_pwe3 = IF_PWE3_ETHERNET; + break; + case SIOCSETMPWCFG: error = suser(curproc); if (error != 0) @@ -213,7 +202,7 @@ mpw_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) smplstosa(&sc->sc_smpls)); sc->sc_smpls.smpls_label = imr.imr_lshim.shim_label; - error = rt_ifa_add(&sc->sc_ifa, RTF_MPLS, + error = rt_ifa_add(&sc->sc_ifa, RTF_MPLS|RTF_LOCAL, smplstosa(&sc->sc_smpls)); if (error != 0) { sc->sc_smpls.smpls_label = 0; @@ -249,27 +238,30 @@ mpw_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) error = copyout(&imr, ifr->ifr_data, sizeof(imr)); break; + case SIOCADDMULTI: + case SIOCDELMULTI: + break; + default: - error = ENOTTY; + error = ether_ioctl(ifp, &sc->sc_ac, cmd, data); break; } return (error); } -int -mpw_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *sa, - struct rtentry *rt) +static void +mpw_input(struct mpw_softc *sc, struct mbuf *m) { - struct mpw_softc *sc = ifp->if_softc; struct mbuf_list ml = MBUF_LIST_INITIALIZER(); - struct ether_header *eh, ehc; + struct ifnet *ifp = &sc->sc_if; struct shim_hdr *shim; - if (sc->sc_type == IMR_TYPE_NONE) { - m_freem(m); - return (EHOSTUNREACH); - } + if (!ISSET(ifp->if_flags, IFF_RUNNING)) + goto drop; + + if (sc->sc_type == IMR_TYPE_NONE) + goto drop; if (sc->sc_flags & IMR_FLAG_CONTROLWORD) { shim = mtod(m, struct shim_hdr *); @@ -282,78 +274,37 @@ mpw_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *sa, */ if (shim->shim_label & CW_ZERO_MASK) { ifp->if_ierrors++; - m_freem(m); - return (EINVAL); + goto drop; } /* We don't support fragmentation just yet. */ if (shim->shim_label & CW_FRAG_MASK) { ifp->if_ierrors++; - m_freem(m); - return (EINVAL); + goto drop; } } - if (sc->sc_type == IMR_TYPE_ETHERNET_TAGGED) { - m_copydata(m, 0, sizeof(ehc), (caddr_t) &ehc); - m_adj(m, ETHER_HDR_LEN); - - /* Ethernet tagged expects at least 2 VLANs */ - if (ntohs(ehc.ether_type) != ETHERTYPE_QINQ) { - ifp->if_ierrors++; - m_freem(m); - return (EINVAL); - } - - /* Remove dummy VLAN and update ethertype */ - if (EVL_VLANOFTAG(*mtod(m, uint16_t *)) == 0) { - m_adj(m, EVL_ENCAPLEN); - ehc.ether_type = htons(ETHERTYPE_VLAN); - } - - M_PREPEND(m, sizeof(*eh), M_NOWAIT); - if (m == NULL) - return (ENOMEM); - - eh = mtod(m, struct ether_header *); - memcpy(eh, &ehc, sizeof(*eh)); - } - ml_enqueue(&ml, m); if_input(ifp, &ml); - - return (0); + return; +drop: + m_freem(m); } -#if NVLAN > 0 -extern void vlan_start(struct ifqueue *); - -/* - * This routine handles VLAN tag reinsertion in packets flowing through - * the pseudowire. Also it does the necessary modifications to the VLANs - * to respect the RFC. - */ -struct mbuf * -mpw_vlan_handle(struct mbuf *m, struct mpw_softc *sc) +int +mpw_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, + struct rtentry *rt) { - struct ifnet *ifp; - struct ifvlan *ifv; - - uint16_t type = ETHERTYPE_QINQ; - uint16_t tag = 0; + struct mpw_softc *sc = ifp->if_softc; - ifp = if_get(m->m_pkthdr.ph_ifidx); - if (ifp != NULL && ifp->if_qstart == vlan_start && - ISSET(ifp->if_flags, IFF_RUNNING)) { - ifv = ifp->if_softc; - type = ifv->ifv_type; - tag = ifv->ifv_tag; + if (dst->sa_family == AF_LINK && + rt != NULL && ISSET(rt->rt_flags, RTF_LOCAL)) { + mpw_input(sc, m); + return (0); } - if_put(ifp); - return (vlan_inject(m, type, tag)); + return (ether_output(ifp, m, dst, rt)); } -#endif /* NVLAN */ void mpw_start(struct ifnet *ifp) @@ -397,20 +348,6 @@ mpw_start(struct ifnet *ifp) bpf_mtap(sc->sc_if.if_bpf, m, BPF_DIRECTION_OUT); #endif /* NBPFILTER */ - if (sc->sc_type == IMR_TYPE_ETHERNET_TAGGED) { - #if NVLAN > 0 - m = mpw_vlan_handle(m, sc); - if (m == NULL) { - ifp->if_oerrors++; - continue; - } - #else - /* Ethernet tagged doesn't work without VLANs'*/ - m_freem(m); - continue; - #endif /* NVLAN */ - } - if (sc->sc_flags & IMR_FLAG_CONTROLWORD) { M_PREPEND(m, sizeof(*shim), M_NOWAIT); if (m == NULL) |