This splits up the mpw config ioctl so the same functionality is
implemented in a bunch of smaller and more specific ioctls. This
simplifies configuration of an interface cos you can incrementally
configure it instead of having to line up all the bits correctly for the
jumbo ioctl.

It also allows extra functionality to be added incrementally in the
future. For example, this adds the ability to configure Flow-Aware
Transport for mpw via the SIOCSPWE3FAT and SIOCGPWE3FAT ioctls.

Another benefit is that this shrinks ifconfig output. Currently ifconfig
mpw0 looks like this:

mpw0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500
        lladdr fe:e1:ba:d0:93:1a
        index 10 priority 0 llprio 3
        encapsulation-type ethernet, control-word
        mpls label: local 16 remote 16
        neighbor: 192.168.0.27
        groups: mpw
        inet 100.64.100.2 netmask 0xffffff00 broadcast 100.64.100.255

After this I can make it look like this:

mpw0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500
        lladdr fe:e1:ba:d0:93:1a
        index 10 priority 0 llprio 3
        mpls: label 16 pwe3 remote label 16 on 192.168.0.27 cw nofat
        groups: mpw
        inet 100.64.100.2 netmask 0xffffff00 broadcast 100.64.100.255

The ifconfig bits aren't built when SMALL, so this doesn't impact
install media.

Lastly, this let's the PWE3 ioctls run without locks. Gotta start
somewhere right?

As discussed with claudio@ at a2k19, I have written a driver for an IP
pseudowire interface called mpip(4). It uses these same ioctls for it's
configuration.

ok?

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    20 Feb 2019 03:29:05 -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', 210, struct ifreq)
+#define SIOCGPWE3CTRLWORD      _IOWR('i', 210, struct ifreq)
+#define SIOCSPWE3FAT           _IOW('i', 211, struct ifreq)
+#define SIOCGPWE3FAT           _IOWR('i', 211, struct ifreq)
+#define SIOCSPWE3NEIGHBOR      _IOW('i', 212, struct if_laddrreq)
+#define SIOCGPWE3NEIGHBOR      _IOWR('i', 212, struct if_laddrreq)
+#define SIOCDPWE3NEIGHBOR      _IOW('i', 212, 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        20 Feb 2019 03:29:05 -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);
+               break;
+
        case SIOCSETKALIVE:
        case SIOCDIFPHYADDR:
        case SIOCSLIFPHYADDR:
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    20 Feb 2019 03:29:05 -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,8 +61,7 @@ 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 +98,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",
@@ -142,46 +147,320 @@ mpw_clone_destroy(struct ifnet *ifp)
        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;
 
+       NET_ASSERT_UNLOCKED();
+
        rw_assert_wrlock(&sc->sc_lock);
        if (sc->sc_dead)
                return (ENXIO);
 
        if (sc->sc_smpls.smpls_label) {
+               NET_LOCK();
                rt_ifa_del(&sc->sc_ifa, RTF_MPLS|RTF_LOCAL,
                    smplstosa(&sc->sc_smpls), sc->sc_rdomain);
+               NET_UNLOCK();
        }
 
        sc->sc_smpls.smpls_label = label;
        sc->sc_rdomain = rdomain;
 
+       NET_LOCK();
        error = rt_ifa_add(&sc->sc_ifa, RTF_MPLS|RTF_LOCAL,
            smplstosa(&sc->sc_smpls), sc->sc_rdomain);
+       NET_UNLOCK();
        if (error != 0)
                sc->sc_smpls.smpls_label = 0;
 
        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;
+       int error;
+
+       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);
+       }
+
+       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;
+
+       error = rw_enter(&sc->sc_lock, RW_WRITE | RW_INTR);
+       if (error != 0)
+               return (error);
+
+       if (sc->sc_dead)
+               goto dead;
+               
+       o = sc->sc_neighbor;
+       sc->sc_neighbor = n;
+
+       rw_exit(&sc->sc_lock);
+
+       NET_ASSERT_UNLOCKED();
+       ifq_barrier(&sc->sc_if.if_snd);
+
+       free(o, M_DEVBUF, sizeof(*o));
+
+       return (0);
+
+dead:
+       rw_exit(&sc->sc_lock);
+       return (ENXIO);
+}
+
+static int
+mpw_get_neighbor(struct mpw_softc *sc, struct if_laddrreq *req)
+{
+       struct mpw_neighbor n, *o;
+       struct sockaddr_mpls *smpls = (struct sockaddr_mpls *)&req->dstaddr;
+       int error;
+
+       error = rw_enter(&sc->sc_lock, RW_READ | RW_INTR);
+       if (error != 0)
+               return (error);
+
+       o = sc->sc_neighbor;
+       if (o)
+               n = *o;
+
+       rw_exit(&sc->sc_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
+mpw_del_neighbor(struct mpw_softc *sc)
+{
+       struct mpw_neighbor *o;
+       int error;
+
+       error = rw_enter(&sc->sc_lock, RW_WRITE | RW_INTR);
+       if (error != 0)
+               return (error);
+
+       if (sc->sc_dead)
+               goto dead;
+
+       o = sc->sc_neighbor;
+       sc->sc_neighbor = NULL;
+
+       rw_exit(&sc->sc_lock);
+
+       ifq_barrier(&sc->sc_if.if_snd);
+
+       free(o, M_DEVBUF, sizeof(*o));
+
+       return (0);
+
+dead:
+       rw_exit(&sc->sc_lock);
+       return (ENXIO);
+}
+
+static int
+mpw_set_label(struct mpw_softc *sc, const struct shim_hdr *label)
+{
+       uint32_t shim;
+       int error;
+
+       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);
+
+       error = rw_enter(&sc->sc_lock, RW_WRITE|RW_INTR);
+       if (error != 0)
+               return (error);
+
+       error = mpw_set_route(sc, shim, sc->sc_rdomain);
+       rw_exit(&sc->sc_lock);
+
+       return (error);
+}
+
+static int
+mpw_get_label(struct mpw_softc *sc, struct ifreq *ifr)
+{
+       struct shim_hdr label;
+       int error;
+
+       error = rw_enter(&sc->sc_lock, RW_READ|RW_INTR);
+       if (error != 0)
+               return (error);
+
+       label.shim_label = MPLS_SHIM2LABEL(sc->sc_smpls.smpls_label);
+       rw_exit(&sc->sc_lock);
+
+       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)
+{
+       int error;
+
+       error = rw_enter(&sc->sc_lock, RW_WRITE|RW_INTR);
+       if (error != 0)
+               return (error);
+
+       if (sc->sc_smpls.smpls_label != MPLS_LABEL2SHIM(0)) {
+               NET_LOCK();
+               rt_ifa_del(&sc->sc_ifa, RTF_MPLS | RTF_LOCAL,
+                   smplstosa(&sc->sc_smpls), 0);
+               NET_UNLOCK();
+       }
+
+       sc->sc_smpls.smpls_label = MPLS_LABEL2SHIM(0);
+       
+       rw_exit(&sc->sc_lock);
+
+       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;
+       int error;
+
+       memset(&imr, 0, sizeof(imr));
+       imr.imr_flags = sc->sc_cword ? IMR_FLAG_CONTROLWORD : 0;
+       imr.imr_type = sc->sc_type;
+
+       rw_enter_read(&sc->sc_lock);
+       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;
+       }
+       rw_exit_read(&sc->sc_lock);
+
+       error = copyout(&imr, ifr->ifr_data, sizeof(imr));
+       if (error != 0)
+               return (error);
+
+       return (0);
+}
+
 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 +473,47 @@ 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;
-                       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);
+               NET_ASSERT_LOCKED();
+               NET_UNLOCK();
+               error = mpw_set_label(sc, &shim);
+               NET_LOCK();
                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:
@@ -299,7 +526,7 @@ mpw_ioctl(struct ifnet *ifp, u_long cmd,
                }
                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);
@@ -440,20 +667,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 +744,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    20 Feb 2019 03:29:05 -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

Reply via email to