Page MenuHomeFreeBSD

D801.id16498.diff
No OneTemporary

D801.id16498.diff

Index: sbin/ifconfig/ifconfig.8
===================================================================
--- sbin/ifconfig/ifconfig.8
+++ sbin/ifconfig/ifconfig.8
@@ -2521,6 +2521,29 @@
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
Index: sbin/ifconfig/ifvlan.c
===================================================================
--- sbin/ifconfig/ifvlan.c
+++ sbin/ifconfig/ifvlan.c
@@ -1,6 +1,10 @@
/*
- * Copyright (c) 1999
- * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved.
+ * Copyright (c) 1999 Bill Paul <wpaul@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 @@
{
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 @@
}
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 @@
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),
Index: sbin/pfctl/parse.y
===================================================================
--- sbin/pfctl/parse.y
+++ sbin/pfctl/parse.y
@@ -37,6 +37,8 @@
#include <sys/sysctl.h>
#endif
#include <net/if.h>
+#include <net/ethernet.h>
+#include <net/if_vlan_var.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
@@ -241,6 +243,11 @@
u_int8_t match_tag_not;
u_int rtableid;
struct {
+ uint8_t pcp[2];
+ uint8_t op;
+ uint8_t setpcp;
+ } ieee8021q_pcp;
+ struct {
struct node_host *addr;
u_int16_t port;
} divert;
@@ -457,6 +464,7 @@
%token STICKYADDRESS MAXSRCSTATES MAXSRCNODES SOURCETRACK GLOBAL RULE
%token MAXSRCCONN MAXSRCCONNRATE OVERLOAD FLUSH SLOPPY
%token TAGGED TAG IFBOUND FLOATING STATEPOLICY STATEDEFAULTS ROUTE SETTOS
+%token IEEE8021QPCP IEEE8021QSETPCP
%token DIVERTTO DIVERTREPLY
%token <v.string> STRING
%token <v.number> NUMBER
@@ -881,6 +889,11 @@
YYERROR;
}
+ r.ieee8021q_pcp.pcp[0] = $9.ieee8021q_pcp.pcp[0];
+ r.ieee8021q_pcp.pcp[1] = $9.ieee8021q_pcp.pcp[1];
+ r.ieee8021q_pcp.op = $9.ieee8021q_pcp.op;
+ r.ieee8021q_pcp.setpcp = $9.ieee8021q_pcp.setpcp;
+
if ($9.match_tag)
if (strlcpy(r.match_tagname, $9.match_tag,
PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
@@ -2014,6 +2027,11 @@
r.prob = $9.prob;
r.rtableid = $9.rtableid;
+ r.ieee8021q_pcp.pcp[0] = $9.ieee8021q_pcp.pcp[0];
+ r.ieee8021q_pcp.pcp[1] = $9.ieee8021q_pcp.pcp[1];
+ r.ieee8021q_pcp.op = $9.ieee8021q_pcp.op;
+ r.ieee8021q_pcp.setpcp = $9.ieee8021q_pcp.setpcp;
+
r.af = $6;
if ($9.tag)
if (strlcpy(r.tagname, $9.tag,
@@ -2490,6 +2508,98 @@
if (filter_opts.prob == 0)
filter_opts.prob = 1;
}
+ | IEEE8021QPCP STRING {
+ u_int pcp;
+
+ /*
+ * XXXRW: More complete set of operations, similar to
+ * ports.
+ */
+ if (!strcmp($2, "be"))
+ pcp = IEEE8021Q_PCP_BE;
+ else if (!strcmp($2, "bk"))
+ pcp = IEEE8021Q_PCP_BK;
+ else if (!strcmp($2, "ee"))
+ pcp = IEEE8021Q_PCP_EE;
+ else if (!strcmp($2, "ca"))
+ pcp = IEEE8021Q_PCP_CA;
+ else if (!strcmp($2, "vi"))
+ pcp = IEEE8021Q_PCP_VI;
+ else if (!strcmp($2, "vo"))
+ pcp = IEEE8021Q_PCP_VO;
+ else if (!strcmp($2, "ic"))
+ pcp = IEEE8021Q_PCP_IC;
+ else if (!strcmp($2, "nc"))
+ pcp = IEEE8021Q_PCP_NC;
+ else
+ pcp = 8; /* flag bad argument */
+ if (pcp > 7) {
+ yyerror("invalid ieee8021q_pcp value %s", $2);
+ free($2);
+ YYERROR;
+ }
+ free($2);
+ filter_opts.ieee8021q_pcp.pcp[0] = pcp;
+ filter_opts.ieee8021q_pcp.pcp[1] = 0;
+ filter_opts.ieee8021q_pcp.op = PF_OP_EQ;
+ }
+ | IEEE8021QPCP number {
+ u_int pcp;
+
+ pcp = $2;
+ if (pcp > 7) {
+ yyerror("invalid ieee8021q_pcp value %u", pcp);
+ YYERROR;
+ }
+ filter_opts.ieee8021q_pcp.pcp[0] = pcp;
+ filter_opts.ieee8021q_pcp.pcp[1] = 0;
+ filter_opts.ieee8021q_pcp.op = PF_OP_EQ;
+ }
+ | IEEE8021QSETPCP STRING {
+ u_int pcp;
+
+ /*
+ * XXXRW: More complete set of operations, similar to
+ * ports.
+ */
+ if (!strcmp($2, "be"))
+ pcp = IEEE8021Q_PCP_BE;
+ else if (!strcmp($2, "bk"))
+ pcp = IEEE8021Q_PCP_BK;
+ else if (!strcmp($2, "ee"))
+ pcp = IEEE8021Q_PCP_EE;
+ else if (!strcmp($2, "ca"))
+ pcp = IEEE8021Q_PCP_CA;
+ else if (!strcmp($2, "vi"))
+ pcp = IEEE8021Q_PCP_VI;
+ else if (!strcmp($2, "vo"))
+ pcp = IEEE8021Q_PCP_VO;
+ else if (!strcmp($2, "ic"))
+ pcp = IEEE8021Q_PCP_IC;
+ else if (!strcmp($2, "nc"))
+ pcp = IEEE8021Q_PCP_NC;
+ else
+ pcp = 8; /* flag bad argument */
+ if (pcp > 7) {
+ yyerror("invalid ieee8021q_setpcp value %s",
+ $2);
+ free($2);
+ YYERROR;
+ }
+ free($2);
+ filter_opts.ieee8021q_pcp.setpcp = pcp | SETPCP_VALID;
+ }
+ | IEEE8021QSETPCP number {
+ u_int pcp;
+
+ pcp = $2;
+ if (pcp > 7) {
+ yyerror("invalid ieee8021q_setpcp value %u",
+ pcp);
+ YYERROR;
+ }
+ filter_opts.ieee8021q_pcp.setpcp = pcp | SETPCP_VALID;
+ }
| RTABLE NUMBER {
if ($2 < 0 || $2 > rt_tableid_max()) {
yyerror("invalid rtable id");
@@ -5392,6 +5502,8 @@
{ "hostid", HOSTID},
{ "icmp-type", ICMPTYPE},
{ "icmp6-type", ICMP6TYPE},
+ { "ieee8021q-pcp", IEEE8021QPCP},
+ { "ieee8021q-setpcp", IEEE8021QSETPCP},
{ "if-bound", IFBOUND},
{ "in", IN},
{ "include", INCLUDE},
Index: sbin/pfctl/pfctl_parser.c
===================================================================
--- sbin/pfctl/pfctl_parser.c
+++ sbin/pfctl/pfctl_parser.c
@@ -40,6 +40,8 @@
#include <sys/param.h>
#include <sys/proc.h>
#include <net/if.h>
+#include <net/ethernet.h>
+#include <net/if_vlan_var.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
@@ -65,6 +67,8 @@
void print_op (u_int8_t, const char *, const char *);
void print_port (u_int8_t, u_int16_t, u_int16_t, const char *, int);
void print_ugid (u_int8_t, unsigned, unsigned, const char *, unsigned);
+void print_ieee8021q_pcp (u_int8_t, uint8_t, uint8_t);
+void print_ieee8021q_setpcp (u_int8_t);
void print_flags (u_int8_t);
void print_fromto(struct pf_rule_addr *, pf_osfp_t,
struct pf_rule_addr *, u_int8_t, u_int8_t, int, int);
@@ -345,6 +349,47 @@
print_op(op, a1, a2);
}
+static const char *
+ieee8021q_pcp_name(u_int8_t pcp)
+{
+ const char *s;
+
+ if (pcp == IEEE8021Q_PCP_BE)
+ s = "be";
+ else if (pcp == IEEE8021Q_PCP_BK)
+ s = "bk";
+ else if (pcp == IEEE8021Q_PCP_EE)
+ s = "ee";
+ else if (pcp == IEEE8021Q_PCP_CA)
+ s = "ca";
+ else if (pcp == IEEE8021Q_PCP_VI)
+ s = "vi";
+ else if (pcp == IEEE8021Q_PCP_VO)
+ s = "vo";
+ else if (pcp == IEEE8021Q_PCP_IC)
+ s = "ic";
+ else if (pcp == IEEE8021Q_PCP_NC)
+ s = "nc";
+ else
+ s = "??";
+ return (s);
+}
+
+ void
+print_ieee8021q_pcp(u_int8_t op, u_int8_t pcp0, u_int8_t pcp1)
+{
+
+ printf(" ieee8021q-pcp");
+ print_op(op, ieee8021q_pcp_name(pcp0), ieee8021q_pcp_name(pcp1));
+}
+
+void
+print_ieee8021q_setpcp(u_int8_t pcp)
+{
+
+ printf(" ieee8021q-setpcp %s", ieee8021q_pcp_name(pcp));
+}
+
void
print_flags(u_int8_t f)
{
@@ -999,6 +1044,13 @@
}
if (r->rtableid != -1)
printf(" rtable %u", r->rtableid);
+ if (r->ieee8021q_pcp.op != 0)
+ print_ieee8021q_pcp(r->ieee8021q_pcp.op,
+ r->ieee8021q_pcp.pcp[0], r->ieee8021q_pcp.pcp[1]);
+ if (r->ieee8021q_pcp.setpcp & SETPCP_VALID)
+ print_ieee8021q_setpcp(r->ieee8021q_pcp.setpcp &
+ SETPCP_PCP_MASK);
+
if (r->divert.port) {
#ifdef __FreeBSD__
printf(" divert-to %u", ntohs(r->divert.port));
Index: share/man/man4/vlan.4
===================================================================
--- share/man/man4/vlan.4
+++ share/man/man4/vlan.4
@@ -203,5 +203,3 @@
.Sh SEE ALSO
.Xr ifconfig 8 ,
.Xr sysctl 8
-.Sh BUGS
-No 802.1Q features except VLAN tagging are implemented.
Index: sys/net/if.h
===================================================================
--- sys/net/if.h
+++ sys/net/if.h
@@ -393,6 +393,7 @@
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 @@
#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) \
Index: sys/net/if_vlan.c
===================================================================
--- sys/net/if_vlan.c
+++ sys/net/if_vlan.c
@@ -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 @@
#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 @@
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 @@
#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 @@
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 @@
}
/*
+ * 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 @@
{
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 @@
* 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 @@
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 @@
* 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 @@
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 @@
}
}
+ 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 @@
}
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_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 @@
}
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 @@
}
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;
Index: sys/net/if_vlan_var.h
===================================================================
--- sys/net/if_vlan_var.h
+++ sys/net/if_vlan_var.h
@@ -73,6 +73,23 @@
#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 @@
* 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); \
Index: sys/net/pfvar.h
===================================================================
--- sys/net/pfvar.h
+++ sys/net/pfvar.h
@@ -329,6 +329,14 @@
u_int8_t op;
};
+struct pf_rule_ieee8021q_pcp {
+ u_int8_t pcp[2];
+ u_int8_t op;
+#define SETPCP_VALID 0x80 /* Set if PCP value in field is valid. */
+#define SETPCP_PCP_MASK 0x07 /* Mask to retrieve pcp if SETPCP_VALID. */
+ u_int8_t setpcp;
+};
+
struct pf_rule_addr {
struct pf_addr_wrap addr;
u_int16_t port[2];
@@ -518,6 +526,7 @@
u_int32_t max_states;
u_int32_t max_src_nodes;
u_int32_t max_src_states;
+ struct pf_rule_ieee8021q_pcp ieee8021q_pcp;
u_int32_t max_src_conn;
struct {
u_int32_t limit;
@@ -1595,6 +1604,8 @@
int pf_match_addr_range(struct pf_addr *, struct pf_addr *,
struct pf_addr *, sa_family_t);
int pf_match_port(u_int8_t, u_int16_t, u_int16_t, u_int16_t);
+int pf_match_ieee8021q_pcp(u_int8_t, u_int8_t, u_int8_t, struct mbuf *);
+int pf_ieee8021q_setpcp(struct mbuf *m, struct pf_rule *r);
void pf_normalize_init(void);
void pf_normalize_cleanup(void);
Index: sys/netpfil/pf/pf.c
===================================================================
--- sys/netpfil/pf/pf.c
+++ sys/netpfil/pf/pf.c
@@ -63,6 +63,8 @@
#include <net/if.h>
#include <net/if_var.h>
#include <net/if_types.h>
+#include <net/ethernet.h>
+#include <net/if_vlan_var.h>
#include <net/route.h>
#include <net/radix_mpath.h>
#include <net/vnet.h>
@@ -2445,6 +2447,26 @@
pf_send(pfse);
}
+int
+pf_ieee8021q_setpcp(struct mbuf *m, struct pf_rule *r)
+{
+ struct m_tag *mtag;
+
+ KASSERT(r->ieee8021q_pcp.setpcp & SETPCP_VALID,
+ ("%s with invalid setpcp", __func__));
+
+ mtag = m_tag_locate(m, MTAG_8021Q, MTAG_8021Q_PCP_OUT, NULL);
+ if (mtag == NULL) {
+ mtag = m_tag_alloc(MTAG_8021Q, MTAG_8021Q_PCP_OUT,
+ sizeof(uint8_t), M_NOWAIT);
+ if (mtag == NULL)
+ return (ENOMEM);
+ m_tag_prepend(m, mtag);
+ }
+ *(uint8_t *)(mtag + 1) = (r->ieee8021q_pcp.setpcp & SETPCP_PCP_MASK);
+ return (0);
+}
+
static void
pf_send_icmp(struct mbuf *m, u_int8_t type, u_int8_t code, sa_family_t af,
struct pf_rule *r)
@@ -2618,6 +2640,36 @@
return (pf_match(op, a1, a2, p));
}
+int
+pf_match_ieee8021q_pcp(u_int8_t op, u_int8_t pcp1, u_int8_t pcp2,
+ struct mbuf *m)
+{
+ struct m_tag *mtag;
+ uint8_t mpcp;
+
+ /*
+ * Packets without 802.1q headers are treated as having a PCP of 0
+ * (best effort).
+ */
+ mtag = m_tag_locate(m, MTAG_8021Q, MTAG_8021Q_PCP_IN, NULL);
+ if (mtag != NULL)
+ mpcp = *(uint8_t *)(mtag + 1);
+ else
+ mpcp = IEEE8021Q_PCP_BE;
+
+ /*
+ * 802.1q uses a non-traditional ordering, in which 1 < 0, allowing
+ * default 0-tagged ("best effort") traffic to take precedence over
+ * 1-tagged ("background") traffic. Renumber both PCP arguments
+ * before making a comparison so that we can use boring arithmetic
+ * operators.
+ */
+ pcp1 = ((pcp1 == 0) ? 1 : ((pcp1 == 1) ? 0 : pcp1));
+ pcp2 = ((pcp2 == 0) ? 1 : ((pcp2 == 1) ? 0 : pcp2));
+ mpcp = ((mpcp == 0) ? 1 : ((mpcp == 1) ? 0 : mpcp));
+ return (pf_match(op, pcp1, pcp2, mpcp));
+}
+
static int
pf_match_uid(u_int8_t op, uid_t a1, uid_t a2, uid_t u)
{
@@ -3317,6 +3369,10 @@
!pf_match_gid(r->gid.op, r->gid.gid[0], r->gid.gid[1],
pd->lookup.gid))
r = TAILQ_NEXT(r, entries);
+ else if (r->ieee8021q_pcp.op &&
+ !pf_match_ieee8021q_pcp(r->ieee8021q_pcp.op,
+ r->ieee8021q_pcp.pcp[0], r->ieee8021q_pcp.pcp[1], m))
+ r = TAILQ_NEXT(r, entries);
else if (r->prob &&
r->prob <= arc4random())
r = TAILQ_NEXT(r, entries);
@@ -3779,6 +3835,10 @@
pd->proto == IPPROTO_ICMPV6) &&
(r->type || r->code))
r = TAILQ_NEXT(r, entries);
+ else if (r->ieee8021q_pcp.op &&
+ !pf_match_ieee8021q_pcp(r->ieee8021q_pcp.op,
+ r->ieee8021q_pcp.pcp[0], r->ieee8021q_pcp.pcp[1], m))
+ r = TAILQ_NEXT(r, entries);
else if (r->prob && r->prob <=
(arc4random() % (UINT_MAX - 1) + 1))
r = TAILQ_NEXT(r, entries);
@@ -6008,6 +6068,14 @@
if (r->rtableid >= 0)
M_SETFIB(m, r->rtableid);
+ if ((r->ieee8021q_pcp.setpcp & SETPCP_VALID) &&
+ pf_ieee8021q_setpcp(m, r)) {
+ action = PF_DROP;
+ REASON_SET(&reason, PFRES_MEMORY);
+ log = 1;
+ DPFPRINTF(PF_DEBUG_MISC,
+ ("pf: failed to allocate 802.1q mtag\n"));
+
#ifdef ALTQ
if (action == PF_PASS && r->qid) {
if (pd.pf_mtag == NULL &&
@@ -6454,6 +6522,15 @@
if (r->rtableid >= 0)
M_SETFIB(m, r->rtableid);
+ if ((r->ieee8021q_pcp.setpcp & SETPCP_VALID) &&
+ pf_ieee8021q_setpcp(m, r)) {
+ action = PF_DROP;
+ REASON_SET(&reason, PFRES_MEMORY);
+ log = 1;
+ DPFPRINTF(PF_DEBUG_MISC,
+ ("pf: failed to allocate 802.1q mtag\n"));
+ }
+
#ifdef ALTQ
if (action == PF_PASS && r->qid) {
if (pd.pf_mtag == NULL &&
Index: sys/sys/priv.h
===================================================================
--- sys/sys/priv.h
+++ sys/sys/priv.h
@@ -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.

File Metadata

Mime Type
text/plain
Expires
Sun, Jan 18, 8:37 PM (17 h, 14 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
27718253
Default Alt Text
D801.id16498.diff (23 KB)

Event Timeline