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);

Reply via email to