diff --git a/lib/libpfctl/libpfctl.h b/lib/libpfctl/libpfctl.h --- a/lib/libpfctl/libpfctl.h +++ b/lib/libpfctl/libpfctl.h @@ -96,6 +96,8 @@ /* Action */ char qname[PF_QNAME_SIZE]; char tagname[PF_TAG_NAME_SIZE]; + uint16_t dnpipe; + uint32_t dnflags; uint8_t action; TAILQ_ENTRY(pfctl_eth_rule) entries; diff --git a/lib/libpfctl/libpfctl.c b/lib/libpfctl/libpfctl.c --- a/lib/libpfctl/libpfctl.c +++ b/lib/libpfctl/libpfctl.c @@ -603,6 +603,9 @@ strlcpy(rule->tagname, nvlist_get_string(nvl, "tagname"), PF_TAG_NAME_SIZE); + rule->dnpipe = nvlist_get_number(nvl, "dnpipe"); + rule->dnflags = nvlist_get_number(nvl, "dnflags"); + rule->action = nvlist_get_number(nvl, "action"); } @@ -709,6 +712,9 @@ nvlist_add_string(nvl, "qname", r->qname); nvlist_add_string(nvl, "tagname", r->tagname); + nvlist_add_number(nvl, "dnpipe", r->dnpipe); + nvlist_add_number(nvl, "dnflags", r->dnflags); + nvlist_add_number(nvl, "action", r->action); packed = nvlist_pack(nvl, &size); diff --git a/sbin/pfctl/parse.y b/sbin/pfctl/parse.y --- a/sbin/pfctl/parse.y +++ b/sbin/pfctl/parse.y @@ -1200,6 +1200,8 @@ memcpy(&r.tagname, $8.tag, sizeof(r.tagname)); if ($8.queues.qname != NULL) memcpy(&r.qname, $8.queues.qname, sizeof(r.qname)); + r.dnpipe = $8.dnpipe; + r.dnflags = $8.free_flags; expand_eth_rule(&r, $5, $6); } @@ -1229,6 +1231,14 @@ | TAG string { filter_opts.tag = $2; } + | DNPIPE number { + filter_opts.dnpipe = $2; + filter_opts.free_flags |= PFRULE_DN_IS_PIPE; + } + | DNQUEUE number { + filter_opts.dnpipe = $2; + filter_opts.free_flags |= PFRULE_DN_IS_QUEUE; + } ; scrubrule : scrubaction dir logquick interface af proto fromto scrub_opts diff --git a/sbin/pfctl/pfctl_parser.c b/sbin/pfctl/pfctl_parser.c --- a/sbin/pfctl/pfctl_parser.c +++ b/sbin/pfctl/pfctl_parser.c @@ -747,6 +747,10 @@ printf(" queue %s", r->qname); if (r->tagname[0]) printf(" tag %s", r->tagname); + if (r->dnpipe) + printf(" %s %d", + r->dnflags & PFRULE_DN_IS_PIPE ? "dnpipe" : "dnqueue", + r->dnpipe); } void diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h --- a/sys/net/pfvar.h +++ b/sys/net/pfvar.h @@ -617,6 +617,8 @@ char tagname[PF_TAG_NAME_SIZE]; uint16_t tag; uint8_t action; + uint16_t dnpipe; + uint32_t dnflags; }; TAILQ_HEAD(pf_keth_rules, pf_keth_rule); diff --git a/sys/netpfil/pf/pf.c b/sys/netpfil/pf/pf.c --- a/sys/netpfil/pf/pf.c +++ b/sys/netpfil/pf/pf.c @@ -3813,6 +3813,22 @@ mtag->qid = r->qid; } + /* Dummynet */ + if (r->dnpipe) { + /** While dummynet supports handling Ethernet packets directly + * it still wants some L3/L4 information, and we're not set up + * to provide that here. Instead we'll do what we do for ALTQ + * and merely mark the packet with the dummynet queue/pipe number. + **/ + mtag = pf_get_mtag(m); + if (mtag == NULL) { + counter_u64_add(V_pf_status.counters[PFRES_MEMORY], 1); + return (PF_DROP); + } + mtag->dnpipe = r->dnpipe; + mtag->dnflags = r->dnflags; + } + action = r->action; return (action); @@ -6515,8 +6531,13 @@ { int dndir = r->direction; - if (s && dndir == PF_INOUT) + if (s && dndir == PF_INOUT) { dndir = s->direction; + } else if (dndir == PF_INOUT) { + /* Assume primary direction. Happens when we've set dnpipe in + * the ethernet level code. */ + dndir = dir; + } memset(dnflow, 0, sizeof(*dnflow)); @@ -6541,7 +6562,7 @@ } dnflow->rule.info |= IPFW_IS_DUMMYNET; - if (r->free_flags & PFRULE_DN_IS_PIPE) + if (r->free_flags & PFRULE_DN_IS_PIPE || pd->act.flags & PFRULE_DN_IS_PIPE) dnflow->rule.info |= IPFW_IS_PIPE; dnflow->f_id.proto = pd->proto; @@ -6635,6 +6656,11 @@ memset(&pd, 0, sizeof(pd)); pd.pf_mtag = pf_find_mtag(m); + if (pd.pf_mtag && pd.pf_mtag->dnpipe) { + pd.act.dnpipe = pd.pf_mtag->dnpipe; + pd.act.flags = pd.pf_mtag->dnflags; + } + if (ip_dn_io_ptr != NULL && pd.pf_mtag != NULL && pd.pf_mtag->flags & PF_TAG_DUMMYNET) { /* Dummynet re-injects packets after they've @@ -7134,6 +7160,11 @@ memset(&pd, 0, sizeof(pd)); pd.pf_mtag = pf_find_mtag(m); + if (pd.pf_mtag && pd.pf_mtag->dnpipe) { + pd.act.dnpipe = pd.pf_mtag->dnpipe; + pd.act.flags = pd.pf_mtag->dnflags; + } + if (ip_dn_io_ptr != NULL && pd.pf_mtag != NULL && pd.pf_mtag->flags & PF_TAG_DUMMYNET) { pd.pf_mtag->flags &= ~PF_TAG_DUMMYNET; diff --git a/sys/netpfil/pf/pf_mtag.h b/sys/netpfil/pf/pf_mtag.h --- a/sys/netpfil/pf/pf_mtag.h +++ b/sys/netpfil/pf/pf_mtag.h @@ -52,6 +52,8 @@ u_int16_t tag; /* tag id */ u_int8_t flags; u_int8_t routed; + u_int16_t dnpipe; + u_int32_t dnflags; }; static __inline struct pf_mtag * diff --git a/sys/netpfil/pf/pf_nv.c b/sys/netpfil/pf/pf_nv.c --- a/sys/netpfil/pf/pf_nv.c +++ b/sys/netpfil/pf/pf_nv.c @@ -1081,6 +1081,9 @@ nvlist_add_string(nvl, "qname", krule->qname); nvlist_add_string(nvl, "tagname", krule->tagname); + nvlist_add_number(nvl, "dnpipe", krule->dnpipe); + nvlist_add_number(nvl, "dnflags", krule->dnflags); + nvlist_add_number(nvl, "action", krule->action); return (nvl); @@ -1090,7 +1093,7 @@ pf_nveth_rule_to_keth_rule(const nvlist_t *nvl, struct pf_keth_rule *krule) { - int error; + int error = 0; bzero(krule, sizeof(*krule)); @@ -1119,6 +1122,9 @@ PFNV_CHK(pf_nvstring(nvl, "tagname", krule->tagname, sizeof(krule->tagname))); + PFNV_CHK(pf_nvuint16_opt(nvl, "dnpipe", &krule->dnpipe, 0)); + PFNV_CHK(pf_nvuint32_opt(nvl, "dnflags", &krule->dnflags, 0)); + PFNV_CHK(pf_nvuint8(nvl, "action", &krule->action)); if (krule->action != PF_PASS && krule->action != PF_DROP)