Author: araujo
Date: Mon Jun  6 09:51:58 2016
New Revision: 301496
URL: https://svnweb.freebsd.org/changeset/base/301496

Log:
  Add support to priority code point (PCP) that is an 3-bit field
  which refers to IEEE 802.1p class of service and maps to the frame
  priority level.
  
  Values in order of priority are: 1 (Background (lowest)),
  0 (Best effort (default)), 2 (Excellent effort),
  3 (Critical applications), 4 (Video, < 100ms latency),
  5 (Video, < 10ms latency), 6 (Internetwork control) and
  7 (Network control (highest)).
  
  Example of usage:
  root# ifconfig em0.1 create
  root# ifconfig em0.1 vlanpcp 3
  
  Note:
  The review D801 includes the pf(4) part, but as discussed with kristof,
  we won't commit the pf(4) bits for now.
  The credits of the original code is from rwatson.
  
  Differential Revision:        https://reviews.freebsd.org/D801
  Reviewed by:  gnn, adrian, loos
  Discussed with: rwatson, glebius, kristof
  Tested by:    many including Matthew Grooms <mgrooms__shrew.net>
  Obtained from:        pfSense
  Relnotes:     Yes

Modified:
  head/sbin/ifconfig/ifconfig.8
  head/sbin/ifconfig/ifvlan.c
  head/share/man/man4/vlan.4
  head/sys/net/if.h
  head/sys/net/if_vlan.c
  head/sys/net/if_vlan_var.h
  head/sys/sys/priv.h

Modified: head/sbin/ifconfig/ifconfig.8
==============================================================================
--- head/sbin/ifconfig/ifconfig.8       Mon Jun  6 09:30:31 2016        
(r301495)
+++ head/sbin/ifconfig/ifconfig.8       Mon Jun  6 09:51:58 2016        
(r301496)
@@ -2614,6 +2614,29 @@ Note that
 and
 .Cm vlandev
 must both be set at the same time.
+.It Cm vlanpcp Ar priority_code_point
+Priority code point 
+.Pq Dv PCP
+is an 3-bit field which refers to the IEEE 802.1p
+class of service and maps to the frame priority level.
+.Pp
+Values in order of priority are:
+.Cm 1 
+.Pq Dv Background (lowest) ,
+.Cm 0
+.Pq Dv Best effort (default) ,
+.Cm 2
+.Pq Dv Excellent effort ,
+.Cm 3
+.Pq Dv Critical applications ,
+.Cm 4
+.Pq Dv Video, < 100ms latency ,
+.Cm 5
+.Pq Dv Video, < 10ms latency ,
+.Cm 6
+.Pq Dv Internetwork control ,
+.Cm 7
+.Pq Dv Network control (highest) .
 .It Cm vlandev Ar iface
 Associate the physical interface
 .Ar iface

Modified: head/sbin/ifconfig/ifvlan.c
==============================================================================
--- head/sbin/ifconfig/ifvlan.c Mon Jun  6 09:30:31 2016        (r301495)
+++ head/sbin/ifconfig/ifvlan.c Mon Jun  6 09:51:58 2016        (r301496)
@@ -1,6 +1,10 @@
 /*
- * Copyright (c) 1999
- *     Bill Paul <wp...@ctr.columbia.edu>.  All rights reserved.
+ * Copyright (c) 1999 Bill Paul <wp...@ctr.columbia.edu>
+ * Copyright (c) 2012 ADARA Networks, Inc.
+ * All rights reserved.
+  *
+ * Portions of this software were developed by Robert N. M. Watson under
+ * contract to ADARA Networks, Inc.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -78,10 +82,14 @@ vlan_status(int s)
 {
        struct vlanreq          vreq;
 
-       if (getvlan(s, &ifr, &vreq) != -1)
-               printf("\tvlan: %d parent interface: %s\n",
-                   vreq.vlr_tag, vreq.vlr_parent[0] == '\0' ?
-                   "<none>" : vreq.vlr_parent);
+       if (getvlan(s, &ifr, &vreq) == -1)
+               return;
+       printf("\tvlan: %d", vreq.vlr_tag);
+       if (ioctl(s, SIOCGVLANPCP, (caddr_t)&ifr) != -1)
+               printf(" vlanpcp: %u", ifr.ifr_vlan_pcp);
+       printf(" parent interface: %s", vreq.vlr_parent[0] == '\0' ?
+           "<none>" : vreq.vlr_parent);
+       printf("\n");
 }
 
 static void
@@ -149,6 +157,22 @@ DECL_CMD_FUNC(setvlandev, val, d)
 }
 
 static
+DECL_CMD_FUNC(setvlanpcp, val, d)
+{
+       u_long ul;
+       char *endp;
+
+       ul = strtoul(val, &endp, 0);
+       if (*endp != '\0')
+               errx(1, "invalid value for vlanpcp");
+       if (ul > 7)
+               errx(1, "value for vlanpcp out of range");
+       ifr.ifr_vlan_pcp = ul;
+       if (ioctl(s, SIOCSVLANPCP, (caddr_t)&ifr) == -1)
+               err(1, "SIOCSVLANPCP");
+}
+
+static
 DECL_CMD_FUNC(unsetvlandev, val, d)
 {
        struct vlanreq          vreq;
@@ -169,6 +193,7 @@ DECL_CMD_FUNC(unsetvlandev, val, d)
 static struct cmd vlan_cmds[] = {
        DEF_CLONE_CMD_ARG("vlan",                       setvlantag),
        DEF_CLONE_CMD_ARG("vlandev",                    setvlandev),
+       DEF_CMD_ARG("vlanpcp",                          setvlanpcp),
        /* NB: non-clone cmds */
        DEF_CMD_ARG("vlan",                             setvlantag),
        DEF_CMD_ARG("vlandev",                          setvlandev),

Modified: head/share/man/man4/vlan.4
==============================================================================
--- head/share/man/man4/vlan.4  Mon Jun  6 09:30:31 2016        (r301495)
+++ head/share/man/man4/vlan.4  Mon Jun  6 09:51:58 2016        (r301496)
@@ -203,5 +203,3 @@ can be corrected manually if used in con
 .Sh SEE ALSO
 .Xr ifconfig 8 ,
 .Xr sysctl 8
-.Sh BUGS
-No 802.1Q features except VLAN tagging are implemented.

Modified: head/sys/net/if.h
==============================================================================
--- head/sys/net/if.h   Mon Jun  6 09:30:31 2016        (r301495)
+++ head/sys/net/if.h   Mon Jun  6 09:51:58 2016        (r301496)
@@ -393,6 +393,7 @@ struct      ifreq {
                caddr_t ifru_data;
                int     ifru_cap[2];
                u_int   ifru_fib;
+               u_char  ifru_vlan_pcp;
        } ifr_ifru;
 #define        ifr_addr        ifr_ifru.ifru_addr      /* address */
 #define        ifr_dstaddr     ifr_ifru.ifru_dstaddr   /* other end of p-to-p 
link */
@@ -410,6 +411,7 @@ struct      ifreq {
 #define        ifr_curcap      ifr_ifru.ifru_cap[1]    /* current capabilities 
*/
 #define        ifr_index       ifr_ifru.ifru_index     /* interface index */
 #define        ifr_fib         ifr_ifru.ifru_fib       /* interface fib */
+#define        ifr_vlan_pcp    ifr_ifru.ifru_vlan_pcp  /* VLAN priority */
 };
 
 #define        _SIZEOF_ADDR_IFREQ(ifr) \

Modified: head/sys/net/if_vlan.c
==============================================================================
--- head/sys/net/if_vlan.c      Mon Jun  6 09:30:31 2016        (r301495)
+++ head/sys/net/if_vlan.c      Mon Jun  6 09:51:58 2016        (r301496)
@@ -1,5 +1,9 @@
 /*-
  * Copyright 1998 Massachusetts Institute of Technology
+ * Copyright 2012 ADARA Networks, Inc.
+ *
+ * Portions of this software were developed by Robert N. M. Watson under
+ * contract to ADARA Networks, Inc.
  *
  * Permission to use, copy, modify, and distribute this software and
  * its documentation for any purpose and without fee is hereby
@@ -29,8 +33,7 @@
 
 /*
  * if_vlan.c - pseudo-device driver for IEEE 802.1Q virtual LANs.
- * Might be extended some day to also handle IEEE 802.1p priority
- * tagging.  This is sort of sneaky in the implementation, since
+ * This is sort of sneaky in the implementation, since
  * we need to pretend to be enough of an Ethernet implementation
  * to make arp work.  The way we do this is by telling everyone
  * that we are an Ethernet, and then catch the packets that
@@ -52,6 +55,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/mbuf.h>
 #include <sys/module.h>
 #include <sys/rmlock.h>
+#include <sys/priv.h>
 #include <sys/queue.h>
 #include <sys/socket.h>
 #include <sys/sockio.h>
@@ -114,6 +118,8 @@ struct      ifvlan {
                int     ifvm_mintu;     /* min transmission unit */
                uint16_t ifvm_proto;    /* encapsulation ethertype */
                uint16_t ifvm_tag;      /* tag to apply on packets leaving if */
+               uint16_t ifvm_vid;      /* VLAN ID */
+               uint8_t ifvm_pcp;       /* Priority Code Point (PCP). */
        }       ifv_mib;
        SLIST_HEAD(, vlan_mc_entry) vlan_mc_listhead;
 #ifndef VLAN_ARRAY
@@ -121,7 +127,9 @@ struct      ifvlan {
 #endif
 };
 #define        ifv_proto       ifv_mib.ifvm_proto
-#define        ifv_vid         ifv_mib.ifvm_tag
+#define        ifv_tag         ifv_mib.ifvm_tag
+#define        ifv_vid         ifv_mib.ifvm_vid
+#define        ifv_pcp         ifv_mib.ifvm_pcp
 #define        ifv_encaplen    ifv_mib.ifvm_encaplen
 #define        ifv_mtufudge    ifv_mib.ifvm_mtufudge
 #define        ifv_mintu       ifv_mib.ifvm_mintu
@@ -147,6 +155,15 @@ static VNET_DEFINE(int, soft_pad);
 SYSCTL_INT(_net_link_vlan, OID_AUTO, soft_pad, CTLFLAG_RW | CTLFLAG_VNET,
     &VNET_NAME(soft_pad), 0, "pad short frames before tagging");
 
+/*
+ * For now, make preserving PCP via an mbuf tag optional, as it increases
+ * per-packet memory allocations and frees.  In the future, it would be
+ * preferable to reuse ether_vtag for this, or similar.
+ */
+static int vlan_mtag_pcp = 0;
+SYSCTL_INT(_net_link_vlan, OID_AUTO, mtag_pcp, CTLFLAG_RW, &vlan_mtag_pcp, 0,
+       "Retain VLAN PCP information as packets are passed up the stack");
+
 static const char vlanname[] = "vlan";
 static MALLOC_DEFINE(M_VLAN, vlanname, "802.1Q Virtual LAN Interface");
 
@@ -697,6 +714,16 @@ vlan_devat(struct ifnet *ifp, uint16_t v
 }
 
 /*
+ * Recalculate the cached VLAN tag exposed via the MIB.
+ */
+static void
+vlan_tag_recalculate(struct ifvlan *ifv)
+{
+
+       ifv->ifv_tag = EVL_MAKETAG(ifv->ifv_vid, ifv->ifv_pcp, 0);
+}
+
+/*
  * VLAN support can be loaded as a module.  The only place in the
  * system that's intimately aware of this is ether_input.  We hook
  * into this code through vlan_input_p which is defined there and
@@ -1009,6 +1036,8 @@ vlan_transmit(struct ifnet *ifp, struct 
 {
        struct ifvlan *ifv;
        struct ifnet *p;
+       struct m_tag *mtag;
+       uint16_t tag;
        int error, len, mcast;
 
        ifv = ifp->if_softc;
@@ -1064,11 +1093,16 @@ vlan_transmit(struct ifnet *ifp, struct 
         * knows how to find the VLAN tag to use, so we attach a
         * packet tag that holds it.
         */
+       if (vlan_mtag_pcp && (mtag = m_tag_locate(m, MTAG_8021Q,
+           MTAG_8021Q_PCP_OUT, NULL)) != NULL)
+               tag = EVL_MAKETAG(ifv->ifv_vid, *(uint8_t *)(mtag + 1), 0);
+       else
+              tag = ifv->ifv_tag;
        if (p->if_capenable & IFCAP_VLAN_HWTAGGING) {
-               m->m_pkthdr.ether_vtag = ifv->ifv_vid;
+               m->m_pkthdr.ether_vtag = tag;
                m->m_flags |= M_VLANTAG;
        } else {
-               m = ether_vlanencap(m, ifv->ifv_vid);
+               m = ether_vlanencap(m, tag);
                if (m == NULL) {
                        if_printf(ifp, "unable to prepend VLAN header\n");
                        if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
@@ -1103,7 +1137,8 @@ vlan_input(struct ifnet *ifp, struct mbu
        struct ifvlantrunk *trunk = ifp->if_vlantrunk;
        struct ifvlan *ifv;
        TRUNK_LOCK_READER;
-       uint16_t vid;
+       struct m_tag *mtag;
+       uint16_t vid, tag;
 
        KASSERT(trunk != NULL, ("%s: no trunk", __func__));
 
@@ -1112,7 +1147,7 @@ vlan_input(struct ifnet *ifp, struct mbu
                 * Packet is tagged, but m contains a normal
                 * Ethernet frame; the tag is stored out-of-band.
                 */
-               vid = EVL_VLANOFTAG(m->m_pkthdr.ether_vtag);
+               tag = m->m_pkthdr.ether_vtag;
                m->m_flags &= ~M_VLANTAG;
        } else {
                struct ether_vlan_header *evl;
@@ -1128,7 +1163,7 @@ vlan_input(struct ifnet *ifp, struct mbu
                                return;
                        }
                        evl = mtod(m, struct ether_vlan_header *);
-                       vid = EVL_VLANOFTAG(ntohs(evl->evl_tag));
+                       tag = ntohs(evl->evl_tag);
 
                        /*
                         * Remove the 802.1q header by copying the Ethernet
@@ -1152,6 +1187,8 @@ vlan_input(struct ifnet *ifp, struct mbu
                }
        }
 
+       vid = EVL_VLANOFTAG(tag);
+
        TRUNK_RLOCK(trunk);
        ifv = vlan_gethash(trunk, vid);
        if (ifv == NULL || !UP_AND_RUNNING(ifv->ifv_ifp)) {
@@ -1162,6 +1199,28 @@ vlan_input(struct ifnet *ifp, struct mbu
        }
        TRUNK_RUNLOCK(trunk);
 
+       if (vlan_mtag_pcp) {
+               /*
+                * While uncommon, it is possible that we will find a 802.1q
+                * packet encapsulated inside another packet that also had an
+                * 802.1q header.  For example, ethernet tunneled over IPSEC
+                * arriving over ethernet.  In that case, we replace the
+                * existing 802.1q PCP m_tag value.
+                */
+               mtag = m_tag_locate(m, MTAG_8021Q, MTAG_8021Q_PCP_IN, NULL);
+               if (mtag == NULL) {
+                       mtag = m_tag_alloc(MTAG_8021Q, MTAG_8021Q_PCP_IN,
+                           sizeof(uint8_t), M_NOWAIT);
+                       if (mtag == NULL) {
+                               m_freem(m);
+                               if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
+                               return;
+                       }
+                       m_tag_prepend(m, mtag);
+               }
+               *(uint8_t *)(mtag + 1) = EVL_PRIOFTAG(tag);
+       }
+
        m->m_pkthdr.rcvif = ifv->ifv_ifp;
        if_inc_counter(ifv->ifv_ifp, IFCOUNTER_IPACKETS, 1);
 
@@ -1201,7 +1260,7 @@ vlan_config(struct ifvlan *ifv, struct i
                vlan_inithash(trunk);
                VLAN_LOCK();
                if (p->if_vlantrunk != NULL) {
-                       /* A race that that is very unlikely to be hit. */
+                       /* A race that is very unlikely to be hit. */
                        vlan_freehash(trunk);
                        free(trunk, M_VLAN);
                        goto exists;
@@ -1218,6 +1277,8 @@ exists:
        }
 
        ifv->ifv_vid = vid;     /* must set this before vlan_inshash() */
+       ifv->ifv_pcp = 0;       /* Default: best effort delivery. */
+       vlan_tag_recalculate(ifv);
        error = vlan_inshash(trunk, ifv);
        if (error)
                goto done;
@@ -1705,6 +1766,34 @@ vlan_ioctl(struct ifnet *ifp, u_long cmd
                }
                break;
 
+       case SIOCGVLANPCP:
+#ifdef VIMAGE
+               if (ifp->if_vnet != ifp->if_home_vnet) {
+                       error = EPERM;
+                       break;
+               }
+#endif
+               ifr->ifr_vlan_pcp = ifv->ifv_pcp;
+               break;
+
+       case SIOCSVLANPCP:
+#ifdef VIMAGE
+               if (ifp->if_vnet != ifp->if_home_vnet) {
+                       error = EPERM;
+                       break;
+               }
+#endif
+               error = priv_check(curthread, PRIV_NET_SETVLANPCP);
+               if (error)
+                       break;
+               if (ifr->ifr_vlan_pcp > 7) {
+                       error = EINVAL;
+                       break;
+               }
+               ifv->ifv_pcp = ifr->ifr_vlan_pcp;
+               vlan_tag_recalculate(ifv);
+               break;
+
        default:
                error = EINVAL;
                break;

Modified: head/sys/net/if_vlan_var.h
==============================================================================
--- head/sys/net/if_vlan_var.h  Mon Jun  6 09:30:31 2016        (r301495)
+++ head/sys/net/if_vlan_var.h  Mon Jun  6 09:51:58 2016        (r301496)
@@ -73,6 +73,23 @@ struct       vlanreq {
 #define        SIOCSETVLAN     SIOCSIFGENERIC
 #define        SIOCGETVLAN     SIOCGIFGENERIC
 
+#define        SIOCGVLANPCP    _IOWR('i', 152, struct ifreq)   /* Get VLAN PCP 
*/
+#define        SIOCSVLANPCP     _IOW('i', 153, struct ifreq)   /* Set VLAN PCP 
*/
+
+/*
+ * Names for 802.1q priorities ("802.1p").  Notice that in this scheme,
+ * (0 < 1), allowing default 0-tagged traffic to take priority over background
+ * tagged traffic.
+ */
+#define        IEEE8021Q_PCP_BK        1       /* Background (lowest) */
+#define        IEEE8021Q_PCP_BE        0       /* Best effort (default) */
+#define        IEEE8021Q_PCP_EE        2       /* Excellent effort */
+#define        IEEE8021Q_PCP_CA        3       /* Critical applications */
+#define        IEEE8021Q_PCP_VI        4       /* Video, < 100ms latency */
+#define        IEEE8021Q_PCP_VO        5       /* Video, < 10ms latency */
+#define        IEEE8021Q_PCP_IC        6       /* Internetwork control */
+#define        IEEE8021Q_PCP_NC        7       /* Network control (highest) */
+
 #ifdef _KERNEL
 /*
  * Drivers that are capable of adding and removing the VLAN header
@@ -110,6 +127,16 @@ struct     vlanreq {
  * if_capabilities.
  */
 
+/*
+ * The 802.1q code may also tag mbufs with the PCP (priority) field for use in
+ * other layers of the stack, in which case an m_tag will be used.  This is
+ * semantically quite different from use of the ether_vtag field, which is
+ * defined only between the device driver and VLAN layer.
+ */
+#define        MTAG_8021Q              1326104895
+#define        MTAG_8021Q_PCP_IN       0               /* Input priority. */
+#define        MTAG_8021Q_PCP_OUT      1               /* Output priority. */
+
 #define        VLAN_CAPABILITIES(_ifp) do {                            \
        if ((_ifp)->if_vlantrunk != NULL)                       \
                (*vlan_trunk_cap_p)(_ifp);                      \

Modified: head/sys/sys/priv.h
==============================================================================
--- head/sys/sys/priv.h Mon Jun  6 09:30:31 2016        (r301495)
+++ head/sys/sys/priv.h Mon Jun  6 09:51:58 2016        (r301496)
@@ -342,6 +342,7 @@
 #define        PRIV_NET_SETIFDESCR     418     /* Set interface description. */
 #define        PRIV_NET_SETIFFIB       419     /* Set interface fib. */
 #define        PRIV_NET_VXLAN          420     /* Administer vxlan. */
+#define        PRIV_NET_SETVLANPCP     421     /* Set VLAN priority. */
 
 /*
  * 802.11-related privileges.
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to