jsg@ pointed out that stsp sniped the ioctl numbers i was using. this diff moves them into 220-212.
On Wed, Feb 20, 2019 at 01:33:00PM +1000, David Gwynne wrote: > 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 04:35:42 -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 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); + 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 04:35:42 -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 04:35:42 -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