diff options
author | kp <kp@FreeBSD.org> | 2016-06-17 18:21:55 +0000 |
---|---|---|
committer | kp <kp@FreeBSD.org> | 2016-06-17 18:21:55 +0000 |
commit | b06d3a64e7ac5d5033eced5e6cc06e9fc2371915 (patch) | |
tree | 513dc21f57cd1bcfc5d1de31452d9f22ae3093ff /sys/netpfil/pf | |
parent | f2d255a0a1535a8148b544aca5623d02e67c0098 (diff) | |
download | FreeBSD-src-b06d3a64e7ac5d5033eced5e6cc06e9fc2371915.zip FreeBSD-src-b06d3a64e7ac5d5033eced5e6cc06e9fc2371915.tar.gz |
pf: Filter on and set vlan PCP values
Adopt the OpenBSD syntax for setting and filtering on VLAN PCP values. This
introduces two new keywords: 'set prio' to set the PCP value, and 'prio' to
filter on it.
Reviewed by: allanjude, araujo
Approved by: re (gjb)
Obtained from: OpenBSD (mostly)
Differential Revision: https://reviews.freebsd.org/D6786
Diffstat (limited to 'sys/netpfil/pf')
-rw-r--r-- | sys/netpfil/pf/pf.c | 72 | ||||
-rw-r--r-- | sys/netpfil/pf/pf_ioctl.c | 4 |
2 files changed, 75 insertions, 1 deletions
diff --git a/sys/netpfil/pf/pf.c b/sys/netpfil/pf/pf.c index a35f9e4..02fc7f0 100644 --- a/sys/netpfil/pf/pf.c +++ b/sys/netpfil/pf/pf.c @@ -63,6 +63,7 @@ __FBSDID("$FreeBSD$"); #include <net/if.h> #include <net/if_var.h> #include <net/if_types.h> +#include <net/if_vlan_var.h> #include <net/route.h> #include <net/radix_mpath.h> #include <net/vnet.h> @@ -2445,6 +2446,45 @@ pf_send_tcp(struct mbuf *replyto, const struct pf_rule *r, sa_family_t af, pf_send(pfse); } +static int +pf_ieee8021q_setpcp(struct mbuf *m, u_int8_t prio) +{ + struct m_tag *mtag; + + KASSERT(prio <= PF_PRIO_MAX, + ("%s with invalid pcp", __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) = prio; + return (0); +} + +static int +pf_match_ieee8021q_pcp(u_int8_t prio, struct mbuf *m) +{ + struct m_tag *mtag; + u_int8_t mpcp; + + mtag = m_tag_locate(m, MTAG_8021Q, MTAG_8021Q_PCP_IN, NULL); + if (mtag == NULL) + return (0); + + if (prio == PF_PRIO_ZERO) + prio = 0; + + mpcp = *(uint8_t *)(mtag + 1); + + return (mpcp == prio); +} + static void pf_send_icmp(struct mbuf *m, u_int8_t type, u_int8_t code, sa_family_t af, struct pf_rule *r) @@ -3317,6 +3357,9 @@ pf_test_rule(struct pf_rule **rm, struct pf_state **sm, int direction, !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->prio && + !pf_match_ieee8021q_pcp(r->prio, m)) + r = TAILQ_NEXT(r, entries); else if (r->prob && r->prob <= arc4random()) r = TAILQ_NEXT(r, entries); @@ -3779,6 +3822,9 @@ pf_test_fragment(struct pf_rule **rm, int direction, struct pfi_kif *kif, pd->proto == IPPROTO_ICMPV6) && (r->type || r->code)) r = TAILQ_NEXT(r, entries); + else if (r->prio && + !pf_match_ieee8021q_pcp(r->prio, m)) + r = TAILQ_NEXT(r, entries); else if (r->prob && r->prob <= (arc4random() % (UINT_MAX - 1) + 1)) r = TAILQ_NEXT(r, entries); @@ -6003,6 +6049,18 @@ done: if (r->rtableid >= 0) M_SETFIB(m, r->rtableid); + if (r->scrub_flags & PFSTATE_SETPRIO) { + if (pd.tos & IPTOS_LOWDELAY) + pqid = 1; + if (pf_ieee8021q_setpcp(m, r->set_prio[pqid])) { + 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 && @@ -6176,7 +6234,7 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0, struct inpcb *inp) struct pf_state *s = NULL; struct pf_ruleset *ruleset = NULL; struct pf_pdesc pd; - int off, terminal = 0, dirndx, rh_cnt = 0; + int off, terminal = 0, dirndx, rh_cnt = 0, pqid = 0; int fwdir = dir; M_ASSERTPKTHDR(m); @@ -6449,6 +6507,18 @@ done: if (r->rtableid >= 0) M_SETFIB(m, r->rtableid); + if (r->scrub_flags & PFSTATE_SETPRIO) { + if (pd.tos & IPTOS_LOWDELAY) + pqid = 1; + if (pf_ieee8021q_setpcp(m, r->set_prio[pqid])) { + 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 && diff --git a/sys/netpfil/pf/pf_ioctl.c b/sys/netpfil/pf/pf_ioctl.c index 83eabcd..3291c9b 100644 --- a/sys/netpfil/pf/pf_ioctl.c +++ b/sys/netpfil/pf/pf_ioctl.c @@ -1242,6 +1242,10 @@ pfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td error = ENOMEM; if (pf_anchor_setup(rule, ruleset, pr->anchor_call)) error = EINVAL; + if (rule->scrub_flags & PFSTATE_SETPRIO && + (rule->set_prio[0] > PF_PRIO_MAX || + rule->set_prio[1] > PF_PRIO_MAX)) + error = EINVAL; TAILQ_FOREACH(pa, &V_pf_pabuf, entries) if (pa->addr.type == PF_ADDR_TABLE) { pa->addr.p.tbl = pfr_attach_table(ruleset, |