the mpls exp bits are now defined as a prio field, but we don't have support for that currently.
this lets the mpls tunnelling interfaces configure the use of the exp fields for prio with the same machinery used for all the other tunnel interfaces. the interfaces default to using 0 for the value which keeps it compat. other values can be configured with ifconfig like normal tunnel interfaces. ok? meh? nah? Index: if_mpe.c =================================================================== RCS file: /cvs/src/sys/net/if_mpe.c,v retrieving revision 1.90 diff -u -p -r1.90 if_mpe.c --- if_mpe.c 2 Apr 2019 10:52:33 -0000 1.90 +++ if_mpe.c 14 Apr 2019 06:49:56 -0000 @@ -55,6 +55,7 @@ struct mpe_softc { struct ifnet sc_if; /* the interface */ + int sc_txhprio; unsigned int sc_rdomain; struct ifaddr sc_ifa; struct sockaddr_mpls sc_smpls; @@ -121,6 +122,7 @@ mpe_clone_create(struct if_clone *ifc, i bpfattach(&ifp->if_bpf, ifp, DLT_LOOP, sizeof(u_int32_t)); #endif + sc->sc_txhprio = 0; sc->sc_rdomain = 0; sc->sc_ifa.ifa_ifp = ifp; sc->sc_ifa.ifa_addr = sdltosa(ifp->if_sadl); @@ -210,10 +212,13 @@ int mpe_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, struct rtentry *rt) { + struct mpe_softc *sc; struct rt_mpls *rtmpls; struct shim_hdr shim; int error; + int txprio; uint8_t ttl = mpls_defttl; + uint8_t tos, prio; size_t ttloff; socklen_t slen; @@ -243,15 +248,22 @@ mpe_output(struct ifnet *ifp, struct mbu error = 0; switch (dst->sa_family) { - case AF_INET: + case AF_INET: { + struct ip *ip = mtod(m, struct ip *); + tos = ip->ip_tos; ttloff = offsetof(struct ip, ip_ttl); slen = sizeof(struct sockaddr_in); break; + } #ifdef INET6 - case AF_INET6: + case AF_INET6: { + struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); + uint32_t flow = bemtoh32(&ip6->ip6_flow); + tos = flow >> 20; ttloff = offsetof(struct ip6_hdr, ip6_hlim); slen = sizeof(struct sockaddr_in6); break; + } #endif default: m_freem(m); @@ -263,7 +275,23 @@ mpe_output(struct ifnet *ifp, struct mbu ttl = *(mtod(m, uint8_t *) + ttloff); } - shim.shim_label = rtmpls->mpls_label | MPLS_BOS_MASK | htonl(ttl); + sc = ifp->if_softc; + txprio = sc->sc_txhprio; + + switch (txprio) { + case IF_HDRPRIO_PACKET: + prio = m->m_pkthdr.pf.prio; + break; + case IF_HDRPRIO_PAYLOAD: + prio = IFQ_TOS2PRIO(tos); + break; + default: + prio = txprio; + break; + } + + shim.shim_label = rtmpls->mpls_label | htonl(prio << MPLS_EXP_OFFSET) | + MPLS_BOS_MASK | htonl(ttl); m = m_prepend(m, sizeof(shim), M_NOWAIT); if (m == NULL) { @@ -278,7 +306,7 @@ mpe_output(struct ifnet *ifp, struct mbu goto out; } memcpy(mtod(m, struct sockaddr *), rt->rt_gateway, slen); - mtod(m, struct sockaddr *)->sa_len = slen; /* to be sure */ + mtod(m, struct sockaddr *)->sa_len = slen; /* to be sure */ m->m_pkthdr.ph_family = dst->sa_family; @@ -387,6 +415,22 @@ mpe_ioctl(struct ifnet *ifp, u_long cmd, break; case SIOCGLIFPHYRTABLE: ifr->ifr_rdomainid = sc->sc_rdomain; + break; + + case SIOCSTXHPRIO: + if (ifr->ifr_hdrprio == IF_HDRPRIO_PACKET || + ifr->ifr_hdrprio == IF_HDRPRIO_PAYLOAD) + ; + else if (ifr->ifr_hdrprio > IF_HDRPRIO_MAX || + ifr->ifr_hdrprio < IF_HDRPRIO_MIN) { + error = EINVAL; + break; + } + + sc->sc_txhprio = ifr->ifr_hdrprio; + break; + case SIOCGTXHPRIO: + ifr->ifr_hdrprio = sc->sc_txhprio; break; default: Index: if_mpip.c =================================================================== RCS file: /cvs/src/sys/net/if_mpip.c,v retrieving revision 1.4 diff -u -p -r1.4 if_mpip.c --- if_mpip.c 2 Apr 2019 10:50:16 -0000 1.4 +++ if_mpip.c 14 Apr 2019 06:49:56 -0000 @@ -55,6 +55,7 @@ struct mpip_softc { unsigned int sc_dead; uint32_t sc_flow; /* xor for mbuf flowid */ + int sc_txhprio; struct ifaddr sc_ifa; struct sockaddr_mpls sc_smpls; /* Local label */ unsigned int sc_rdomain; @@ -92,6 +93,7 @@ mpip_clone_create(struct if_clone *ifc, if (sc == NULL) return (ENOMEM); + sc->sc_txhprio = 0; 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 */ @@ -415,6 +417,22 @@ mpip_ioctl(struct ifnet *ifp, u_long cmd ifr->ifr_ttl = sc->sc_ttl; break; + case SIOCSTXHPRIO: + if (ifr->ifr_hdrprio == IF_HDRPRIO_PACKET || + ifr->ifr_hdrprio == IF_HDRPRIO_PAYLOAD) + ; + else if (ifr->ifr_hdrprio > IF_HDRPRIO_MAX || + ifr->ifr_hdrprio < IF_HDRPRIO_MIN) { + error = EINVAL; + break; + } + + sc->sc_txhprio = ifr->ifr_hdrprio; + break; + case SIOCGTXHPRIO: + ifr->ifr_hdrprio = sc->sc_txhprio; + break; + case SIOCADDMULTI: case SIOCDELMULTI: break; @@ -611,8 +629,9 @@ mpip_start(struct ifnet *ifp) .smpls_len = sizeof(smpls), .smpls_family = AF_MPLS, }; - uint32_t bos; - uint8_t ttl; + int txprio = sc->sc_txhprio; + uint32_t exp, bos; + uint8_t tos, prio, ttl; if (!ISSET(ifp->if_flags, IFF_RUNNING) || n == NULL) { IFQ_PURGE(&ifp->if_snd); @@ -662,6 +681,40 @@ mpip_start(struct ifnet *ifp) } else ttl = mpls_defttl; + switch (txprio) { + case IF_HDRPRIO_PACKET: + prio = m->m_pkthdr.pf.prio; + break; + case IF_HDRPRIO_PAYLOAD: + switch (m->m_pkthdr.ph_family) { + case AF_INET: { + struct ip *ip; + ip = mtod(m, struct ip *); + tos = ip->ip_tos; + break; + } +#ifdef INET6 + case AF_INET6: { + struct ip6_hdr *ip6; + uint32_t flow; + ip6 = mtod(m, struct ip6_hdr *); + flow = bemtoh32(&ip6->ip6_flow); + tos = flow >> 20; + break; + } +#endif + default: + unhandled_af(m->m_pkthdr.ph_family); + } + + prio = IFQ_TOS2PRIO(tos); + break; + default: + prio = txprio; + break; + } + exp = htonl(prio << MPLS_EXP_OFFSET); + if (sc->sc_cword) { m = m_prepend(m, sizeof(shim), M_NOWAIT); if (m == NULL) @@ -686,7 +739,7 @@ mpip_start(struct ifnet *ifp) shim = htonl(1) & MPLS_TTL_MASK; shim |= htonl(flow << MPLS_LABEL_OFFSET) & MPLS_LABEL_MASK; - shim |= bos; + shim |= exp | bos; *mtod(m, uint32_t *) = shim; bos = 0; @@ -698,7 +751,7 @@ mpip_start(struct ifnet *ifp) shim = htonl(ttl) & MPLS_TTL_MASK; shim |= n->n_rshim.shim_label; - shim |= bos; + shim |= exp | bos; *mtod(m, uint32_t *) = shim; m->m_pkthdr.ph_rtableid = sc->sc_rdomain; Index: if_mpw.c =================================================================== RCS file: /cvs/src/sys/net/if_mpw.c,v retrieving revision 1.49 diff -u -p -r1.49 if_mpw.c --- if_mpw.c 2 Apr 2019 10:50:16 -0000 1.49 +++ if_mpw.c 14 Apr 2019 06:49:56 -0000 @@ -53,6 +53,7 @@ struct mpw_softc { struct arpcom sc_ac; #define sc_if sc_ac.ac_if + int sc_txhprio; unsigned int sc_rdomain; struct ifaddr sc_ifa; struct sockaddr_mpls sc_smpls; /* Local label */ @@ -117,6 +118,7 @@ mpw_clone_create(struct if_clone *ifc, i if_attach(ifp); ether_ifattach(ifp); + sc->sc_txhprio = 0; sc->sc_rdomain = 0; sc->sc_ifa.ifa_ifp = ifp; sc->sc_ifa.ifa_addr = sdltosa(ifp->if_sadl); @@ -465,6 +467,21 @@ mpw_ioctl(struct ifnet *ifp, u_long cmd, ifr->ifr_rdomainid = sc->sc_rdomain; break; + case SIOCSTXHPRIO: + if (ifr->ifr_hdrprio == IF_HDRPRIO_PACKET) + ; + else if (ifr->ifr_hdrprio > IF_HDRPRIO_MAX || + ifr->ifr_hdrprio < IF_HDRPRIO_MIN) { + error = EINVAL; + break; + } + + sc->sc_txhprio = ifr->ifr_hdrprio; + break; + case SIOCGTXHPRIO: + ifr->ifr_hdrprio = sc->sc_txhprio; + break; + case SIOCADDMULTI: case SIOCDELMULTI: break; @@ -605,7 +622,9 @@ mpw_start(struct ifnet *ifp) .smpls_len = sizeof(smpls), .smpls_family = AF_MPLS, }; - uint32_t bos; + int txprio = sc->sc_txhprio; + uint8_t prio; + uint32_t exp, bos; n = sc->sc_neighbor; if (!ISSET(ifp->if_flags, IFF_RUNNING) || @@ -652,6 +671,16 @@ mpw_start(struct ifnet *ifp) memset(shim, 0, sizeof(*shim)); } + switch (txprio) { + case IF_HDRPRIO_PACKET: + prio = m->m_pkthdr.pf.prio; + break; + default: + prio = txprio; + break; + } + exp = htonl(prio << MPLS_EXP_OFFSET); + bos = MPLS_BOS_MASK; if (sc->sc_fword) { uint32_t flow = sc->sc_flow; @@ -665,7 +694,7 @@ mpw_start(struct ifnet *ifp) shim = mtod(m0, struct shim_hdr *); shim->shim_label = htonl(1) & MPLS_TTL_MASK; - shim->shim_label = MPLS_LABEL2SHIM(flow) | bos; + shim->shim_label = MPLS_LABEL2SHIM(flow) | exp | bos; bos = 0; } @@ -676,7 +705,7 @@ mpw_start(struct ifnet *ifp) shim = mtod(m0, struct shim_hdr *); shim->shim_label = htonl(mpls_defttl) & MPLS_TTL_MASK; - shim->shim_label |= n->n_rshim.shim_label | bos; + shim->shim_label |= n->n_rshim.shim_label | exp | bos; m0->m_pkthdr.ph_rtableid = sc->sc_rdomain; CLR(m0->m_flags, M_BCAST|M_MCAST);