Index: lib/libpfctl/libpfctl.h =================================================================== --- lib/libpfctl/libpfctl.h +++ 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; Index: lib/libpfctl/libpfctl.c =================================================================== --- lib/libpfctl/libpfctl.c +++ lib/libpfctl/libpfctl.c @@ -596,6 +596,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"); } @@ -702,6 +705,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); Index: sbin/pfctl/parse.y =================================================================== --- sbin/pfctl/parse.y +++ 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 Index: sbin/pfctl/pfctl_parser.c =================================================================== --- sbin/pfctl/pfctl_parser.c +++ 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 Index: sys/net/pfvar.h =================================================================== --- sys/net/pfvar.h +++ sys/net/pfvar.h @@ -615,6 +615,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); Index: sys/netpfil/pf/pf.c =================================================================== --- sys/netpfil/pf/pf.c +++ sys/netpfil/pf/pf.c @@ -3687,6 +3687,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); @@ -6391,8 +6407,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)); @@ -6417,7 +6438,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; @@ -6512,6 +6533,11 @@ 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; + } + PF_RULES_RLOCK(); if ((__predict_false(ip_divert_ptr != NULL) || ip_dn_io_ptr != NULL) && @@ -6996,6 +7022,11 @@ if (pd.pf_mtag && pd.pf_mtag->flags & PF_TAG_GENERATED) return (PF_PASS); + if (pd.pf_mtag && pd.pf_mtag->dnpipe) { + pd.act.dnpipe = pd.pf_mtag->dnpipe; + pd.act.flags = pd.pf_mtag->dnflags; + } + kif = (struct pfi_kkif *)ifp->if_pf_kif; if (kif == NULL) { DPFPRINTF(PF_DEBUG_URGENT, @@ -7286,7 +7317,7 @@ pd.act.dnpipe = s->dnpipe; pd.act.dnrpipe = s->dnrpipe; pd.act.flags = s->state_flags; - } else { + } else if (r->dnpipe || r->dnrpipe) { pd.act.dnpipe = r->dnpipe; pd.act.dnrpipe = r->dnrpipe; pd.act.flags = r->free_flags; Index: sys/netpfil/pf/pf_mtag.h =================================================================== --- sys/netpfil/pf/pf_mtag.h +++ 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 * Index: sys/netpfil/pf/pf_nv.c =================================================================== --- sys/netpfil/pf/pf_nv.c +++ sys/netpfil/pf/pf_nv.c @@ -1064,6 +1064,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); @@ -1073,7 +1076,7 @@ pf_nvl_to_keth_rule(const nvlist_t *nvl, struct pf_keth_rule *krule) { - int error; + int error = 0; bzero(krule, sizeof(*krule)); @@ -1118,9 +1121,13 @@ strlcpy(krule->tagname, nvlist_get_string(nvl, "tagname"), PF_TAG_NAME_SIZE); + PFNV_CHK(pf_nvuint16_opt(nvl, "dnpipe", &krule->dnpipe, 0)); + PFNV_CHK(pf_nvuint32_opt(nvl, "dnflags", &krule->dnflags, 0)); + if (! nvlist_exists_number(nvl, "action")) return (EBADMSG); krule->action = nvlist_get_number(nvl, "action"); - return (0); +errout: + return (error); }