On Mon, Feb 25, 2019 at 03:28:58PM +1000, David Gwynne wrote: > On Mon, Feb 25, 2019 at 10:37:40AM +1000, David Gwynne wrote: > > > > > > > On 22 Feb 2019, at 05:01, Martin Pieuchot <m...@openbsd.org> wrote: > > > > > > On 21/02/19(Thu) 07:35, David Gwynne wrote: > > >>> On 20 Feb 2019, at 11:21 pm, Martin Pieuchot <m...@openbsd.org> wrote: > > >>> > > >>> On 20/02/19(Wed) 14:44, David Gwynne wrote: > > >>>> Index: sys/net/if.c > > >>>> =================================================================== > > >>>> RCS file: /cvs/src/sys/net/if.c,v > > >>>> retrieving revision 1.571 > > >>>> diff -u -p -r1.571 if.c > > >>>> --- sys/net/if.c 9 Jan 2019 01:14:21 -0000 1.571 > > >>>> +++ sys/net/if.c 20 Feb 2019 04:35:42 -0000 > > >>>> @@ -2143,6 +2143,25 @@ ifioctl(struct socket *so, u_long cmd, c > > >>>> NET_UNLOCK(); > > >>>> break; > > >>>> > > >>>> + case SIOCSETMPWCFG: > > >>>> + case SIOCSPWE3CTRLWORD: > > >>>> + case SIOCSPWE3FAT: > > >>>> + case SIOCSPWE3NEIGHBOR: > > >>>> + case SIOCDPWE3NEIGHBOR: > > >>>> + if ((error = suser(p)) != 0) > > >>>> + break; > > >>>> + /* FALLTHROUGH */ > > >>>> + case SIOCGETMPWCFG: > > >>>> + case SIOCGPWE3CTRLWORD: > > >>>> + case SIOCGPWE3FAT: > > >>>> + case SIOCGPWE3NEIGHBOR: > > >>>> + if_ref(ifp); > > >>>> + KERNEL_UNLOCK(); > > >>>> + error = ((*ifp->if_ioctl)(ifp, cmd, data)); > > >>>> + KERNEL_LOCK(); > > >>>> + if_put(ifp); > > >>> > > >>> Why are you referencing the `ifp' and grabbing the KERNEL_LOCK() > > >>> (recursively)? > > >> > > >> ifioctl gets the ifp pointer from ifunit, which doesn't increase the ref > > >> count for you. I'm giving up kernel lock around the pwe3 ioctl calls > > >> into the driver, not taking them harder. Taking the ifp ref there > > >> guarantees the interface will stay alive^Wallocated over those calls. > > > > > > It feels premature to me, well I'm confused. None of the other ioctl > > > handlers do that. The KERNEL_LOCK() is still held in ifioctl() which > > > guarantees serialization. If any of the ioctl(2) calls is going to sleep, > > > thus releasing the lock, then I'd suggest to grab the NET_RLOCK() here > > > instead. It still guarantees serialization of network ioctls w/ regard > > > to detach. > > > > > > Note that I'll be delighted if you want to remove/push down the NET_LOCK() > > > from this code path, but can we keep the handlers coherent? > > > > > > Even if we're using refcounting, don't we want to serialize all network > > > ioctl(2)s? If we're not using the NET_LOCK() for this, can this new lock > > > guarantee that that `ifp' isn't going away? Or do you have a better > > > idea? > > > > The network stack implicitly taking locks is hurting me way more > > than it's helping me at the moment, particularly the net lock, so > > I would like to spend some time narrowing that down. If the consensus > > is that it's too much risk for drivers to keep themselves consistent > > then I'd argue for a per ifp rwlock that the ifioctl code could > > take and release. > > > > Do you want me to do that for the pwe3 ioctls? There's a small > > number of MPLS interfaces, so they'd be good for a test run. > > > > ifunit() is notionally like if_get except it doesn't give you a > > reference. You have to be holding a lock that prevents the interface > > being removed from the list if you're calling ifunit. The code > > doesn't make it clear whether the lock you need to be holding is > > the kernel lock or the net lock, but the kernel lock is empirically > > good enough. If you give up that lock while holding the ifp, you > > need to account for your reference to it. > > deraadt@ talked me down from giving up KERNEL_LOCK. so this is what > the diff would be like if the interface had a lock and it was taken > around the mpls ioctls. > > my opinion on the pros and cons of this is: > > pro: it keeps the individual driver state consistent cos changes > are serialised by the lock. this means you don't have to think too > hard about the driver locking against itself. > > pro: it allows fear free use of ifq_barrier. ifq_barrier cannot deadlock > if the caller isn't holding NET_LOCK. this is the big win because it > supports the model where the ioctl can coordinate with the running stack > by publishing a change and then inserting a barrier to ensure the old > state is no longer in use. without this the ioctl will have to give > up the implicit NET_LOCK it has. > > con: only the mpls/pwe3 ioctls are covered. but i have to start > somewhere, right?
actually, now i have my head around the clone destroy stuff i can (ab)use the net lock. this should be more acceptable to everyone. Index: sys/sys/sockio.h =================================================================== RCS file: /cvs/src/sys/sys/sockio.h,v retrieving revision 1.79 diff -u -p -r1.79 sockio.h --- sys/sys/sockio.h 23 Jan 2019 08:23:18 -0000 1.79 +++ sys/sys/sockio.h 25 Feb 2019 09:58:15 -0000 @@ -143,6 +143,7 @@ #define SIOCSSPPPPARAMS _IOW('i', 147, struct ifreq) /* set pppoe params */ #define SIOCGSPPPPARAMS _IOWR('i', 148, struct ifreq) /* get pppoe params */ +#define SIOCDELLABEL _IOW('i', 151, struct ifreq) /* del MPLS label */ #define SIOCGPWE3 _IOWR('i', 152, struct ifreq) /* get MPLS PWE3 cap */ #define SIOCSETLABEL _IOW('i', 153, struct ifreq) /* set MPLS label */ #define SIOCGETLABEL _IOW('i', 154, struct ifreq) /* get MPLS label */ @@ -204,6 +205,14 @@ #define SIOCSLIFPHYECN _IOW('i', 199, struct ifreq) /* set ecn copying */ #define SIOCGLIFPHYECN _IOWR('i', 200, struct ifreq) /* get ecn copying */ + +#define SIOCSPWE3CTRLWORD _IOW('i', 220, struct ifreq) +#define SIOCGPWE3CTRLWORD _IOWR('i', 220, struct ifreq) +#define SIOCSPWE3FAT _IOW('i', 221, struct ifreq) +#define SIOCGPWE3FAT _IOWR('i', 221, struct ifreq) +#define SIOCSPWE3NEIGHBOR _IOW('i', 222, struct if_laddrreq) +#define SIOCGPWE3NEIGHBOR _IOWR('i', 222, struct if_laddrreq) +#define SIOCDPWE3NEIGHBOR _IOW('i', 222, struct ifreq) #define SIOCSVH _IOWR('i', 245, struct ifreq) /* set carp param */ #define SIOCGVH _IOWR('i', 246, struct ifreq) /* get carp param */ Index: sys/net/if.c =================================================================== RCS file: /cvs/src/sys/net/if.c,v retrieving revision 1.571 diff -u -p -r1.571 if.c --- sys/net/if.c 9 Jan 2019 01:14:21 -0000 1.571 +++ sys/net/if.c 25 Feb 2019 09:58:15 -0000 @@ -2159,6 +2159,12 @@ ifioctl(struct socket *so, u_long cmd, c case SIOCSIFPAIR: case SIOCSIFPARENT: case SIOCDIFPARENT: + case SIOCSETMPWCFG: + case SIOCSETLABEL: + case SIOCSPWE3CTRLWORD: + case SIOCSPWE3FAT: + case SIOCSPWE3NEIGHBOR: + case SIOCDPWE3NEIGHBOR: if ((error = suser(p)) != 0) break; /* FALLTHROUGH */ Index: sys/net/if_mpw.c =================================================================== RCS file: /cvs/src/sys/net/if_mpw.c,v retrieving revision 1.44 diff -u -p -r1.44 if_mpw.c --- sys/net/if_mpw.c 20 Feb 2019 01:04:53 -0000 1.44 +++ sys/net/if_mpw.c 25 Feb 2019 09:58:15 -0000 @@ -44,6 +44,11 @@ #include <net/if_vlan_var.h> #endif +struct mpw_neighbor { + struct shim_hdr n_rshim; + struct sockaddr_storage n_nexthop; +}; + struct mpw_softc { struct arpcom sc_ac; #define sc_if sc_ac.ac_if @@ -56,10 +61,8 @@ struct mpw_softc { unsigned int sc_fword; uint32_t sc_flow; uint32_t sc_type; - struct shim_hdr sc_rshim; - struct sockaddr_storage sc_nexthop; + struct mpw_neighbor *sc_neighbor; - struct rwlock sc_lock; unsigned int sc_dead; }; @@ -94,6 +97,7 @@ mpw_clone_create(struct if_clone *ifc, i return (ENOMEM); sc->sc_flow = arc4random(); + sc->sc_neighbor = NULL; ifp = &sc->sc_if; snprintf(ifp->if_xname, sizeof(ifp->if_xname), "%s%d", @@ -108,7 +112,6 @@ mpw_clone_create(struct if_clone *ifc, i IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN); ether_fakeaddr(ifp); - rw_init(&sc->sc_lock, ifp->if_xname); sc->sc_dead = 0; if_attach(ifp); @@ -128,31 +131,32 @@ mpw_clone_destroy(struct ifnet *ifp) { struct mpw_softc *sc = ifp->if_softc; + NET_LOCK(); ifp->if_flags &= ~IFF_RUNNING; - - rw_enter_write(&sc->sc_lock); sc->sc_dead = 1; if (sc->sc_smpls.smpls_label) { rt_ifa_del(&sc->sc_ifa, RTF_MPLS|RTF_LOCAL, smplstosa(&sc->sc_smpls), sc->sc_rdomain); } - rw_exit_write(&sc->sc_lock); + NET_UNLOCK(); + + ifq_barrier(&ifp->if_snd); ether_ifdetach(ifp); if_detach(ifp); + free(sc->sc_neighbor, M_DEVBUF, sizeof(*sc->sc_neighbor)); free(sc, M_DEVBUF, sizeof(*sc)); return (0); } int -mpw_set_label(struct mpw_softc *sc, uint32_t label, unsigned int rdomain) +mpw_set_route(struct mpw_softc *sc, uint32_t label, unsigned int rdomain) { int error; - rw_assert_wrlock(&sc->sc_lock); if (sc->sc_dead) return (ENXIO); @@ -172,16 +176,224 @@ mpw_set_label(struct mpw_softc *sc, uint return (error); } +static int +mpw_set_neighbor(struct mpw_softc *sc, const struct if_laddrreq *req) +{ + struct mpw_neighbor *n, *o; + const struct sockaddr_storage *ss; + const struct sockaddr_mpls *smpls; + uint32_t label; + + smpls = (const struct sockaddr_mpls *)&req->dstaddr; + + if (smpls->smpls_family != AF_MPLS) + return (EINVAL); + label = smpls->smpls_label; + if (label > MPLS_LABEL_MAX || label <= MPLS_LABEL_RESERVED_MAX) + return (EINVAL); + + ss = &req->addr; + switch (ss->ss_family) { + case AF_INET: { + const struct sockaddr_in *sin = + (const struct sockaddr_in *)ss; + + if (in_nullhost(sin->sin_addr) || + IN_MULTICAST(sin->sin_addr.s_addr)) + return (EINVAL); + + break; + } +#ifdef INET6 + case AF_INET6: { + const struct sockaddr_in6 *sin6 = + (const struct sockaddr_in6 *)ss; + + if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) || + IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) + return (EINVAL); + + /* check scope */ + + break; + } +#endif + default: + return (EAFNOSUPPORT); + } + + if (sc->sc_dead) + return (ENXIO); + + 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 = *ss; + + o = sc->sc_neighbor; + sc->sc_neighbor = n; + + NET_UNLOCK(); + ifq_barrier(&sc->sc_if.if_snd); + NET_LOCK(); + + free(o, M_DEVBUF, sizeof(*o)); + + return (0); +} + +static int +mpw_get_neighbor(struct mpw_softc *sc, struct if_laddrreq *req) +{ + struct sockaddr_mpls *smpls = (struct sockaddr_mpls *)&req->dstaddr; + struct mpw_neighbor *n = sc->sc_neighbor; + + if (n == NULL) + return (EADDRNOTAVAIL); + + smpls->smpls_len = sizeof(*smpls); + smpls->smpls_family = AF_MPLS; + smpls->smpls_label = MPLS_SHIM2LABEL(n->n_rshim.shim_label); + + req->addr = n->n_nexthop; + + return (0); +} + +static int +mpw_del_neighbor(struct mpw_softc *sc) +{ + struct mpw_neighbor *o; + + if (sc->sc_dead) + return (ENXIO); + + o = sc->sc_neighbor; + sc->sc_neighbor = NULL; + + NET_UNLOCK(); + ifq_barrier(&sc->sc_if.if_snd); + NET_LOCK(); + + free(o, M_DEVBUF, sizeof(*o)); + + return (0); +} + +static int +mpw_set_label(struct mpw_softc *sc, const struct shim_hdr *label) +{ + uint32_t shim; + + if (label->shim_label > MPLS_LABEL_MAX || + label->shim_label <= MPLS_LABEL_RESERVED_MAX) + return (EINVAL); + + shim = MPLS_LABEL2SHIM(label->shim_label); + if (sc->sc_smpls.smpls_label == shim) + return (0); + + return (mpw_set_route(sc, shim, sc->sc_rdomain)); +} + +static int +mpw_get_label(struct mpw_softc *sc, struct ifreq *ifr) +{ + struct shim_hdr label; + + label.shim_label = MPLS_SHIM2LABEL(sc->sc_smpls.smpls_label); + if (label.shim_label == MPLS_LABEL2SHIM(0)) + return (EADDRNOTAVAIL); + + return (copyout(&label, ifr->ifr_data, sizeof(label))); +} + +static int +mpw_del_label(struct mpw_softc *sc) +{ + if (sc->sc_dead) + return (ENXIO); + + if (sc->sc_smpls.smpls_label != MPLS_LABEL2SHIM(0)) { + rt_ifa_del(&sc->sc_ifa, RTF_MPLS | RTF_LOCAL, + smplstosa(&sc->sc_smpls), 0); + } + + sc->sc_smpls.smpls_label = MPLS_LABEL2SHIM(0); + + return (0); +} + +static int +mpw_set_config(struct mpw_softc *sc, const struct ifreq *ifr) +{ + struct ifmpwreq imr; + struct if_laddrreq req; + struct sockaddr_mpls *smpls; + struct sockaddr_in *sin; + int error; + + error = copyin(ifr->ifr_data, &imr, sizeof(imr)); + if (error != 0) + return (error); + + /* Teardown all configuration if got no nexthop */ + sin = (struct sockaddr_in *)&imr.imr_nexthop; + if (sin->sin_addr.s_addr == 0) { + mpw_del_label(sc); + mpw_del_neighbor(sc); + sc->sc_cword = 0; + sc->sc_type = 0; + return (0); + } + + error = mpw_set_label(sc, &imr.imr_lshim); + if (error != 0) + return (error); + + smpls = (struct sockaddr_mpls *)&req.dstaddr; + smpls->smpls_family = AF_MPLS; + smpls->smpls_label = imr.imr_rshim.shim_label; + req.addr = imr.imr_nexthop; + + error = mpw_set_neighbor(sc, &req); + if (error != 0) + return (error); + + sc->sc_cword = ISSET(imr.imr_flags, IMR_FLAG_CONTROLWORD); + sc->sc_type = imr.imr_type; + + return (0); +} + +static int +mpw_get_config(struct mpw_softc *sc, const struct ifreq *ifr) +{ + struct ifmpwreq imr; + + memset(&imr, 0, sizeof(imr)); + imr.imr_flags = sc->sc_cword ? IMR_FLAG_CONTROLWORD : 0; + imr.imr_type = sc->sc_type; + + imr.imr_lshim.shim_label = MPLS_SHIM2LABEL(sc->sc_smpls.smpls_label); + if (sc->sc_neighbor) { + imr.imr_rshim.shim_label = + MPLS_SHIM2LABEL(sc->sc_neighbor->n_rshim.shim_label); + imr.imr_nexthop = sc->sc_neighbor->n_nexthop; + } + + return (copyout(&imr, ifr->ifr_data, sizeof(imr))); +} + int mpw_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) { struct ifreq *ifr = (struct ifreq *) data; struct mpw_softc *sc = ifp->if_softc; struct shim_hdr shim; - struct sockaddr_in *sin; - struct sockaddr_in *sin_nexthop; int error = 0; - struct ifmpwreq imr; switch (cmd) { case SIOCSIFFLAGS: @@ -194,99 +406,45 @@ mpw_ioctl(struct ifnet *ifp, u_long cmd, case SIOCGPWE3: ifr->ifr_pwe3 = IF_PWE3_ETHERNET; 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 SIOCSPWE3NEIGHBOR: + error = mpw_set_neighbor(sc, (struct if_laddrreq *)data); + break; + case SIOCGPWE3NEIGHBOR: + error = mpw_get_neighbor(sc, (struct if_laddrreq *)data); + break; + case SIOCDPWE3NEIGHBOR: + error = mpw_del_neighbor(sc); + break; case SIOCGETLABEL: - shim.shim_label = MPLS_SHIM2LABEL(sc->sc_smpls.smpls_label); - error = copyout(&shim, ifr->ifr_data, sizeof(shim)); + error = mpw_get_label(sc, ifr); break; case SIOCSETLABEL: - if ((error = copyin(ifr->ifr_data, &shim, sizeof(shim)))) - break; - if (shim.shim_label > MPLS_LABEL_MAX || - shim.shim_label <= MPLS_LABEL_RESERVED_MAX) { - error = EINVAL; + error = copyin(ifr->ifr_data, &shim, sizeof(shim)); + if (error != 0) break; - } - shim.shim_label = MPLS_LABEL2SHIM(shim.shim_label); - rw_enter_write(&sc->sc_lock); - if (sc->sc_smpls.smpls_label != shim.shim_label) { - error = mpw_set_label(sc, shim.shim_label, - sc->sc_rdomain); - } - rw_exit_write(&sc->sc_lock); + error = mpw_set_label(sc, &shim); break; case SIOCSETMPWCFG: - error = suser(curproc); - if (error != 0) - break; - - error = copyin(ifr->ifr_data, &imr, sizeof(imr)); - if (error != 0) - break; - - /* Teardown all configuration if got no nexthop */ - sin = (struct sockaddr_in *) &imr.imr_nexthop; - if (sin->sin_addr.s_addr == 0) { - if (rt_ifa_del(&sc->sc_ifa, RTF_MPLS|RTF_LOCAL, - smplstosa(&sc->sc_smpls), 0) == 0) - sc->sc_smpls.smpls_label = 0; - - memset(&sc->sc_rshim, 0, sizeof(sc->sc_rshim)); - memset(&sc->sc_nexthop, 0, sizeof(sc->sc_nexthop)); - sc->sc_cword = 0; - sc->sc_type = 0; - break; - } - - /* Validate input */ - if (sin->sin_family != AF_INET || - imr.imr_lshim.shim_label > MPLS_LABEL_MAX || - imr.imr_lshim.shim_label <= MPLS_LABEL_RESERVED_MAX || - imr.imr_rshim.shim_label > MPLS_LABEL_MAX || - imr.imr_rshim.shim_label <= MPLS_LABEL_RESERVED_MAX) { - error = EINVAL; - break; - } - - /* Setup labels and create inbound route */ - imr.imr_lshim.shim_label = - MPLS_LABEL2SHIM(imr.imr_lshim.shim_label); - imr.imr_rshim.shim_label = - MPLS_LABEL2SHIM(imr.imr_rshim.shim_label); - - rw_enter_write(&sc->sc_lock); - if (sc->sc_smpls.smpls_label != imr.imr_lshim.shim_label) { - error = mpw_set_label(sc, imr.imr_lshim.shim_label, - sc->sc_rdomain); - } - rw_exit_write(&sc->sc_lock); - if (error != 0) - break; - - /* Apply configuration */ - sc->sc_cword = ISSET(imr.imr_flags, IMR_FLAG_CONTROLWORD); - sc->sc_type = imr.imr_type; - sc->sc_rshim.shim_label = imr.imr_rshim.shim_label; - - memset(&sc->sc_nexthop, 0, sizeof(sc->sc_nexthop)); - sin_nexthop = (struct sockaddr_in *) &sc->sc_nexthop; - sin_nexthop->sin_family = sin->sin_family; - sin_nexthop->sin_len = sizeof(struct sockaddr_in); - sin_nexthop->sin_addr.s_addr = sin->sin_addr.s_addr; + error = mpw_set_config(sc, ifr); break; case SIOCGETMPWCFG: - imr.imr_flags = sc->sc_cword ? IMR_FLAG_CONTROLWORD : 0; - imr.imr_type = sc->sc_type; - imr.imr_lshim.shim_label = - MPLS_SHIM2LABEL(sc->sc_smpls.smpls_label); - imr.imr_rshim.shim_label = - MPLS_SHIM2LABEL(sc->sc_rshim.shim_label); - memcpy(&imr.imr_nexthop, &sc->sc_nexthop, - sizeof(imr.imr_nexthop)); - - error = copyout(&imr, ifr->ifr_data, sizeof(imr)); + error = mpw_get_config(sc, ifr); break; case SIOCSLIFPHYRTABLE: @@ -297,18 +455,15 @@ mpw_ioctl(struct ifnet *ifp, u_long cmd, error = EINVAL; break; } - rw_enter_write(&sc->sc_lock); if (sc->sc_rdomain != ifr->ifr_rdomainid) { - error = mpw_set_label(sc, sc->sc_smpls.smpls_label, + error = mpw_set_route(sc, sc->sc_smpls.smpls_label, ifr->ifr_rdomainid); } - rw_exit_write(&sc->sc_lock); break; case SIOCGLIFPHYRTABLE: ifr->ifr_rdomainid = sc->sc_rdomain; break; - case SIOCADDMULTI: case SIOCDELMULTI: break; @@ -440,20 +595,22 @@ mpw_start(struct ifnet *ifp) struct ifnet *ifp0; struct mbuf *m, *m0; struct shim_hdr *shim; + struct mpw_neighbor *n; struct sockaddr_mpls smpls = { .smpls_len = sizeof(smpls), .smpls_family = AF_MPLS, }; uint32_t bos; + n = sc->sc_neighbor; if (!ISSET(ifp->if_flags, IFF_RUNNING) || - sc->sc_rshim.shim_label == 0 || - sc->sc_type == IMR_TYPE_NONE) { + sc->sc_type == IMR_TYPE_NONE || + n == NULL) { IFQ_PURGE(&ifp->if_snd); return; } - rt = rtalloc(sstosa(&sc->sc_nexthop), RT_RESOLVE, sc->sc_rdomain); + rt = rtalloc(sstosa(&n->n_nexthop), RT_RESOLVE, sc->sc_rdomain); if (!rtisvalid(rt)) { IFQ_PURGE(&ifp->if_snd); goto rtfree; @@ -515,7 +672,7 @@ mpw_start(struct ifnet *ifp) shim = mtod(m0, struct shim_hdr *); shim->shim_label = htonl(mpls_defttl) & MPLS_TTL_MASK; - shim->shim_label |= sc->sc_rshim.shim_label | bos; + shim->shim_label |= n->n_rshim.shim_label | bos; m0->m_pkthdr.ph_rtableid = ifp->if_rdomain; Index: sbin/ifconfig/ifconfig.c =================================================================== RCS file: /cvs/src/sbin/ifconfig/ifconfig.c,v retrieving revision 1.392 diff -u -p -r1.392 ifconfig.c --- sbin/ifconfig/ifconfig.c 19 Feb 2019 08:12:30 -0000 1.392 +++ sbin/ifconfig/ifconfig.c 25 Feb 2019 09:58:15 -0000 @@ -242,7 +242,14 @@ void clone_create(const char *, int); void clone_destroy(const char *, int); void unsetmediaopt(const char *, int); void setmediainst(const char *, int); -void setmpelabel(const char *, int); +void setmplslabel(const char *, int); +void unsetmplslabel(const char *, int); +void setpwe3cw(const char *, int); +void unsetpwe3cw(const char *, int); +void setpwe3fat(const char *, int); +void unsetpwe3fat(const char *, int); +void setpwe3neighbor(const char *, const char *); +void unsetpwe3neighbor(const char *, int); void process_mpw_commands(void); void setmpwencap(const char *, int); void setmpwlabel(const char *, const char *); @@ -251,7 +258,7 @@ void setmpwcontrolword(const char *, int void setvlantag(const char *, int); void setvlandev(const char *, int); void unsetvlandev(const char *, int); -void mpe_status(void); +void mpls_status(void); void mpw_status(void); void setrdomain(const char *, int); void unsetrdomain(const char *, int); @@ -457,7 +464,14 @@ const struct cmd { { "-staticarp", -IFF_STATICARP, 0, setifflags }, { "mpls", IFXF_MPLS, 0, setifxflags }, { "-mpls", -IFXF_MPLS, 0, setifxflags }, - { "mplslabel", NEXTARG, 0, setmpelabel }, + { "mplslabel", NEXTARG, 0, setmplslabel }, + { "-mplslabel", 0, 0, unsetmplslabel }, + { "pwecw", 0, 0, setpwe3cw }, + { "-pwecw", 0, 0, unsetpwe3cw }, + { "pwefat", 0, 0, setpwe3fat }, + { "-pwefat", 0, 0, unsetpwe3fat }, + { "pweneighbor", NEXTARG2, 0, NULL, setpwe3neighbor }, + { "-pweneighbor", 0, 0, unsetpwe3neighbor }, { "mpwlabel", NEXTARG2, 0, NULL, setmpwlabel }, { "neighbor", NEXTARG, 0, setmpwneighbor }, { "controlword", 1, 0, setmpwcontrolword }, @@ -3293,7 +3307,7 @@ status(int link, struct sockaddr_dl *sdl pfsync_status(); pppoe_status(); sppp_status(); - mpe_status(); + mpls_status(); mpw_status(); pflow_status(); umb_status(); @@ -3821,16 +3835,97 @@ delvnetflowid(const char *ignored, int a } void -mpe_status(void) +pwe3_neighbor(void) +{ + const char *prefix = "pwe3 remote label"; + struct if_laddrreq req; + char hbuf[NI_MAXHOST]; + struct sockaddr_mpls *smpls; + int error; + + memset(&req, 0, sizeof(req)); + if (strlcpy(req.iflr_name, name, sizeof(req.iflr_name)) >= + sizeof(req.iflr_name)) + errx(1, "pwe3 neighbor: name is too long"); + + if (ioctl(s, SIOCGPWE3NEIGHBOR, &req) == -1) { + if (errno != EADDRNOTAVAIL) + return; + + printf(" %s (unset)", prefix); + return; + } + + if (req.dstaddr.ss_family != AF_MPLS) { + warnc(EPFNOSUPPORT, "pwe3 neighbor"); + return; + } + smpls = (struct sockaddr_mpls *)&req.dstaddr; + + error = getnameinfo((struct sockaddr *)&req.addr, sizeof(req.addr), + hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST); + if (error != 0) { + warnx("%s: %s", prefix, gai_strerror(error)); + return; + } + + printf(" %s %u on %s", prefix, smpls->smpls_label, hbuf); +} + +void +pwe3_cword(void) +{ + struct ifreq req; + + memset(&req, 0, sizeof(req)); + if (strlcpy(req.ifr_name, name, sizeof(req.ifr_name)) >= + sizeof(req.ifr_name)) + errx(1, "pwe3 control word: name is too long"); + + if (ioctl(s, SIOCGPWE3CTRLWORD, &req) == -1) { + return; + } + + printf(" %s", req.ifr_pwe3 ? "cw" : "nocw"); +} + +void +pwe3_fword(void) +{ + struct ifreq req; + + memset(&req, 0, sizeof(req)); + if (strlcpy(req.ifr_name, name, sizeof(req.ifr_name)) >= + sizeof(req.ifr_name)) + errx(1, "pwe3 control word: name is too long"); + + if (ioctl(s, SIOCGPWE3FAT, &req) == -1) + return; + + printf(" %s", req.ifr_pwe3 ? "fat" : "nofat"); +} + +void +mpls_status(void) { struct shim_hdr shim; bzero(&shim, sizeof(shim)); ifr.ifr_data = (caddr_t)&shim; - if (ioctl(s, SIOCGETLABEL , (caddr_t)&ifr) == -1) - return; - printf("\tmpls label: %d\n", shim.shim_label); + if (ioctl(s, SIOCGETLABEL, (caddr_t)&ifr) == -1) { + if (errno != EADDRNOTAVAIL) + return; + + printf("\tmpls: label (unset)"); + } else + printf("\tmpls: label %u", shim.shim_label); + + pwe3_neighbor(); + pwe3_cword(); + pwe3_fword(); + + printf("\n"); } void @@ -3885,7 +3980,7 @@ mpw_status(void) /* ARGSUSED */ void -setmpelabel(const char *val, int d) +setmplslabel(const char *val, int d) { struct shim_hdr shim; const char *estr; @@ -3898,6 +3993,114 @@ setmpelabel(const char *val, int d) errx(1, "mpls label %s is %s", val, estr); if (ioctl(s, SIOCSETLABEL, (caddr_t)&ifr) == -1) warn("SIOCSETLABEL"); +} + +void +unsetmplslabel(const char *val, int d) +{ + struct ifreq req; + + memset(&req, 0, sizeof(req)); + if (strlcpy(req.ifr_name, name, sizeof(req.ifr_name)) >= + sizeof(req.ifr_name)) + errx(1, "interface name is too long"); + + if (ioctl(s, SIOCDELLABEL, (caddr_t)&ifr) == -1) + warn("-mplslabel"); +} + +void +setpwe3(unsigned long cmd, const char *cmdname, int value) +{ + struct ifreq req; + + memset(&req, 0, sizeof(req)); + if (strlcpy(req.ifr_name, name, sizeof(req.ifr_name)) >= + sizeof(req.ifr_name)) + errx(1, "interface name is too long"); + + req.ifr_pwe3 = value; + + if (ioctl(s, cmd, &req) == -1) + warn("%s", cmdname); +} + +void +setpwe3cw(const char *val, int d) +{ + setpwe3(SIOCSPWE3CTRLWORD, "pwecw", 1); +} + +void +unsetpwe3cw(const char *val, int d) +{ + setpwe3(SIOCSPWE3CTRLWORD, "-pwecw", 0); +} + +void +setpwe3fat(const char *val, int d) +{ + setpwe3(SIOCSPWE3FAT, "pwefat", 1); +} + +void +unsetpwe3fat(const char *val, int d) +{ + setpwe3(SIOCSPWE3FAT, "-pwefat", 0); +} + +void +setpwe3neighbor(const char *label, const char *neighbor) +{ + struct if_laddrreq req; + struct addrinfo hints, *res; + struct sockaddr_mpls *smpls = (struct sockaddr_mpls *)&req.dstaddr;; + const char *errstr; + int error; + + memset(&req, 0, sizeof(req)); + if (strlcpy(req.iflr_name, name, sizeof(req.iflr_name)) >= + sizeof(req.iflr_name)) + errx(1, "interface name is too long"); + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + error = getaddrinfo(neighbor, NULL, &hints, &res); + if (error != 0) + errx(1, "pweneighbor %s: %s", neighbor, gai_strerror(error)); + + smpls->smpls_len = sizeof(*smpls); + smpls->smpls_family = AF_MPLS; + smpls->smpls_label = strtonum(label, + (MPLS_LABEL_RESERVED_MAX + 1), MPLS_LABEL_MAX, &errstr); + if (errstr != NULL) + errx(1, "pweneighbor: invalid label: %s", errstr); + + + if (res->ai_addrlen > sizeof(req.addr)) + errx(1, "pweneighbors: unexpected socklen"); + + memcpy(&req.addr, res->ai_addr, res->ai_addrlen); + + freeaddrinfo(res); + + if (ioctl(s, SIOCSPWE3NEIGHBOR, &req) == -1) + warn("pweneighbor"); +} + +void +unsetpwe3neighbor(const char *val, int d) +{ + struct ifreq req; + + memset(&req, 0, sizeof(req)); + if (strlcpy(req.ifr_name, name, sizeof(req.ifr_name)) >= + sizeof(req.ifr_name)) + errx(1, "interface name is too long"); + + if (ioctl(s, SIOCDPWE3NEIGHBOR, &req) == -1) + warn("-pweneighbor"); } void