lib: zapi PBR common encode/decode

bgpd, pbrd: use common pbr encoder
    zebra: use common pbr decoder
    tests: pbr_topo1: check more filter fields

    Purpose:
	1. Reduce likelihood of zapi format mismatches when adding
	   PBR fields due to multiple parallel encoder implementations
	2. Encourage common PBR structure usage among various daemons
	3. Reduce coding errors via explicit per-field enable flags

Signed-off-by: G. Paul Ziemba <paulz@labn.net>
This commit is contained in:
G. Paul Ziemba 2023-07-17 09:31:06 -07:00
parent 46b47720a2
commit 580a98b798
6 changed files with 294 additions and 193 deletions

View File

@ -2712,17 +2712,20 @@ static void bgp_encode_pbr_rule_action(struct stream *s,
struct bgp_pbr_action *pbra,
struct bgp_pbr_rule *pbr)
{
struct prefix pfx;
uint8_t fam = AF_INET;
char ifname[INTERFACE_NAMSIZ];
struct pbr_rule r;
if (pbra->nh.type == NEXTHOP_TYPE_IPV6)
fam = AF_INET6;
stream_putl(s, 0); /* seqno unused */
/*
* Convert to canonical form
*/
memset(&r, 0, sizeof(r));
/* r.seq unused */
if (pbr)
stream_putl(s, pbr->priority);
else
stream_putl(s, 0);
r.priority = pbr->priority;
/* ruleno unused - priority change
* ruleno permits distinguishing various FS PBR entries
* - FS PBR entries based on ipset/iptables
@ -2730,56 +2733,37 @@ static void bgp_encode_pbr_rule_action(struct stream *s,
* the latter may contain default routing information injected by FS
*/
if (pbr)
stream_putl(s, pbr->unique);
r.unique = pbr->unique;
else
stream_putl(s, pbra->unique);
r.unique = pbra->unique;
stream_putl(s, 0); /* filter_bm placeholder */
stream_putc(s, 0); /* ip protocol being used */
if (pbr && pbr->flags & MATCH_IP_SRC_SET)
memcpy(&pfx, &(pbr->src), sizeof(struct prefix));
else {
memset(&pfx, 0, sizeof(pfx));
pfx.family = fam;
/* filter */
if (pbr && pbr->flags & MATCH_IP_SRC_SET) {
SET_FLAG(r.filter.filter_bm, PBR_FILTER_SRC_IP);
r.filter.src_ip = pbr->src;
} else {
/* ??? */
r.filter.src_ip.family = fam;
}
stream_putc(s, pfx.family);
stream_putc(s, pfx.prefixlen);
stream_put(s, &pfx.u.prefix, prefix_blen(&pfx));
stream_putw(s, 0); /* src port */
if (pbr && pbr->flags & MATCH_IP_DST_SET)
memcpy(&pfx, &(pbr->dst), sizeof(struct prefix));
else {
memset(&pfx, 0, sizeof(pfx));
pfx.family = fam;
if (pbr && pbr->flags & MATCH_IP_DST_SET) {
SET_FLAG(r.filter.filter_bm, PBR_FILTER_DST_IP);
r.filter.dst_ip = pbr->dst;
} else {
/* ??? */
r.filter.dst_ip.family = fam;
}
/* src_port, dst_port, pcp, dsfield not used */
if (!pbr) {
SET_FLAG(r.filter.filter_bm, PBR_FILTER_FWMARK);
r.filter.fwmark = pbra->fwmark;
}
stream_putc(s, pfx.family);
stream_putc(s, pfx.prefixlen);
stream_put(s, &pfx.u.prefix, prefix_blen(&pfx));
stream_putw(s, 0); /* dst port */
SET_FLAG(r.action.flags, PBR_ACTION_TABLE); /* always valid */
r.action.table = pbra->table_id;
stream_putc(s, 0); /* filter dsfield */
/* if pbr present, fwmark is not used */
if (pbr)
stream_putl(s, 0);
else
stream_putl(s, pbra->fwmark); /* filter fwmark */
stream_putc(s, 0); /* pcp filter */
stream_putw(s, 0); /* pcp action */
stream_putw(s, 0); /* vlan_id filter */
stream_putw(s, 0); /* vlan_flags filter */
stream_putw(s, 0); /* vlan_id action */
stream_putw(s, 0); /* vlan_flags action */
stream_putl(s, 0); /* queue id action */
stream_putl(s, pbra->table_id); /* table action */
memset(ifname, 0, sizeof(ifname));
stream_put(s, ifname, INTERFACE_NAMSIZ); /* ifname unused */
zapi_pbr_rule_encode(s, &r);
}
static void bgp_encode_pbr_ipset_match(struct stream *s,
@ -3545,11 +3529,9 @@ void bgp_send_pbr_rule_action(struct bgp_pbr_action *pbra,
zclient_create_header(s,
install ? ZEBRA_RULE_ADD : ZEBRA_RULE_DELETE,
VRF_DEFAULT);
stream_putl(s, 1); /* send one pbr action */
bgp_encode_pbr_rule_action(s, pbra, pbr);
stream_putw_at(s, 0, stream_get_endp(s));
if ((zclient_send_message(zclient) != ZCLIENT_SEND_FAILURE)
&& install) {
if (!pbr)

View File

@ -85,14 +85,23 @@ struct pbr_filter {
* the user criteria may directly point to a table too.
*/
struct pbr_action {
uint32_t flags;
#define PBR_ACTION_TABLE (1 << 0)
#define PBR_ACTION_QUEUE_ID (1 << 1)
#define PBR_ACTION_PCP (1 << 2)
#define PBR_ACTION_VLAN_ID (1 << 3)
#define PBR_ACTION_VLAN_FLAGS (1 << 4)
uint32_t table;
uint32_t queue_id;
/* VLAN */
uint8_t pcp;
uint16_t vlan_id;
uint16_t vlan_flags;
uint32_t queue_id;
uint32_t table;
};
/*
@ -146,8 +155,8 @@ struct pbr_rule {
#define MATCH_FLOW_LABEL_SET (1 << 12)
#define MATCH_FLOW_LABEL_INVERSE_SET (1 << 13)
extern int zapi_pbr_rule_encode(uint8_t cmd, struct stream *s,
struct pbr_rule *zrule);
extern int zapi_pbr_rule_encode(struct stream *s, struct pbr_rule *r);
extern bool zapi_pbr_rule_decode(struct stream *s, struct pbr_rule *r);
#ifdef __cplusplus
}

View File

@ -1611,30 +1611,105 @@ static void zapi_encode_prefix(struct stream *s, struct prefix *p,
stream_put(s, &p->u.prefix, prefix_blen(p));
}
int zapi_pbr_rule_encode(uint8_t cmd, struct stream *s, struct pbr_rule *zrule)
static bool zapi_decode_prefix(struct stream *s, struct prefix *p)
{
stream_reset(s);
zclient_create_header(s, cmd, zrule->vrf_id);
STREAM_GETC(s, p->family);
STREAM_GETC(s, p->prefixlen);
STREAM_GET(&(p->u.prefix), s, prefix_blen(p));
return true;
stream_failure:
return false;
}
/*
* Encode filter subsection of pbr_rule
*/
static void zapi_pbr_rule_filter_encode(struct stream *s, struct pbr_filter *f)
{
assert(f->src_ip.family == f->dst_ip.family);
assert((AF_INET == f->src_ip.family) || (AF_INET6 == f->src_ip.family));
stream_putl(s, f->filter_bm);
stream_putc(s, f->ip_proto);
/* addresses */
zapi_encode_prefix(s, &f->src_ip, f->src_ip.family);
zapi_encode_prefix(s, &f->dst_ip, f->dst_ip.family);
/* port numbers */
stream_putw(s, f->src_port);
stream_putw(s, f->dst_port);
/* vlan */
stream_putc(s, f->pcp);
stream_putw(s, f->vlan_id);
stream_putw(s, f->vlan_flags);
stream_putc(s, f->dsfield);
stream_putl(s, f->fwmark);
}
static bool zapi_pbr_rule_filter_decode(struct stream *s, struct pbr_filter *f)
{
STREAM_GETL(s, f->filter_bm);
STREAM_GETC(s, f->ip_proto);
if (!zapi_decode_prefix(s, &(f->src_ip)))
goto stream_failure;
if (!zapi_decode_prefix(s, &(f->dst_ip)))
goto stream_failure;
STREAM_GETW(s, f->src_port);
STREAM_GETW(s, f->dst_port);
STREAM_GETC(s, f->pcp);
STREAM_GETW(s, f->vlan_id);
STREAM_GETW(s, f->vlan_flags);
STREAM_GETC(s, f->dsfield);
STREAM_GETL(s, f->fwmark);
return true;
stream_failure:
return false;
}
static void zapi_pbr_rule_action_encode(struct stream *s, struct pbr_action *a)
{
stream_putl(s, a->flags);
stream_putl(s, a->table);
stream_putl(s, a->queue_id);
stream_putc(s, a->pcp);
stream_putw(s, a->vlan_id);
stream_putw(s, a->vlan_flags);
}
static bool zapi_pbr_rule_action_decode(struct stream *s, struct pbr_action *a)
{
STREAM_GETL(s, a->flags);
STREAM_GETL(s, a->table);
STREAM_GETL(s, a->queue_id);
STREAM_GETC(s, a->pcp);
STREAM_GETW(s, a->vlan_id);
STREAM_GETW(s, a->vlan_flags);
return true;
stream_failure:
return false;
}
int zapi_pbr_rule_encode(struct stream *s, struct pbr_rule *r)
{
/*
* We are sending one item at a time at the moment
* PBR record count is always 1
*/
stream_putl(s, 1);
stream_putl(s, zrule->seq);
stream_putl(s, zrule->priority);
stream_putl(s, zrule->unique);
stream_putl(s, r->seq);
stream_putl(s, r->priority);
stream_putl(s, r->unique);
zapi_encode_prefix(s, &(zrule->filter.src_ip),
zrule->filter.src_ip.family);
stream_putw(s, zrule->filter.src_port); /* src port */
zapi_encode_prefix(s, &(zrule->filter.dst_ip),
zrule->filter.src_ip.family);
stream_putw(s, zrule->filter.dst_port); /* dst port */
stream_putw(s, zrule->filter.fwmark); /* fwmark */
zapi_pbr_rule_filter_encode(s, &(r->filter));
zapi_pbr_rule_action_encode(s, &(r->action));
stream_putl(s, zrule->action.table);
stream_put(s, zrule->ifname, INTERFACE_NAMSIZ);
stream_put(s, r->ifname, INTERFACE_NAMSIZ);
/* Put length at the first point of the stream. */
stream_putw_at(s, 0, stream_get_endp(s));
@ -1642,6 +1717,28 @@ int zapi_pbr_rule_encode(uint8_t cmd, struct stream *s, struct pbr_rule *zrule)
return 0;
}
bool zapi_pbr_rule_decode(struct stream *s, struct pbr_rule *r)
{
/* NB caller has already read 4-byte rule count */
memset(r, 0, sizeof(*r));
STREAM_GETL(s, r->seq);
STREAM_GETL(s, r->priority);
STREAM_GETL(s, r->unique);
if (!zapi_pbr_rule_filter_decode(s, &(r->filter)))
goto stream_failure;
if (!zapi_pbr_rule_action_decode(s, &(r->action)))
goto stream_failure;
STREAM_GET(r->ifname, s, INTERFACE_NAMSIZ);
return true;
stream_failure:
return false;
}
int zapi_tc_qdisc_encode(uint8_t cmd, struct stream *s, struct tc_qdisc *qdisc)
{
stream_reset(s);

View File

@ -483,27 +483,9 @@ void pbr_send_rnh(struct nexthop *nhop, bool reg)
}
}
static void pbr_encode_pbr_map_sequence_prefix(struct stream *s,
struct prefix *p,
unsigned char family)
{
struct prefix any;
if (!p) {
memset(&any, 0, sizeof(any));
any.family = family;
p = &any;
}
stream_putc(s, p->family);
stream_putc(s, p->prefixlen);
stream_put(s, &p->u.prefix, prefix_blen(p));
}
static void
pbr_encode_pbr_map_sequence_vrf(struct stream *s,
const struct pbr_map_sequence *pbrms,
const struct interface *ifp)
static uint32_t pbr_map_sequence_vrf(const struct pbr_map_sequence *pbrms,
const struct interface *ifp)
{
struct pbr_vrf *pbr_vrf;
@ -514,66 +496,130 @@ pbr_encode_pbr_map_sequence_vrf(struct stream *s,
if (!pbr_vrf) {
DEBUGD(&pbr_dbg_zebra, "%s: VRF not found", __func__);
return;
return 0;
}
stream_putl(s, pbr_vrf->vrf->data.l.table_id);
return pbr_vrf->vrf->data.l.table_id;
}
/*
* 230716 gpz note: it would be worthwhile for pbrd to represent
* its rules internally using the lib/pbr.h structures to help
* move toward a more common structure across pbrd, bgpd, and zebra.
*/
static bool pbr_encode_pbr_map_sequence(struct stream *s,
struct pbr_map_sequence *pbrms,
struct interface *ifp)
{
unsigned char family;
struct pbr_rule r;
uint8_t family;
/*
* There seems to be some effort in pbr_vty.c to keep the three
* copies of "family" equal. Not sure if the reason goes beyond
* ensuring consistency in ZAPI encoding. In any case, it might
* be handled better as an internal matter for the encoder (TBD).
*/
family = AF_INET;
if (pbrms->family)
family = pbrms->family;
stream_putl(s, pbrms->seqno);
stream_putl(s, pbrms->ruleno);
stream_putl(s, pbrms->unique);
if (pbrms->src)
assert(family == pbrms->src->family);
if (pbrms->dst)
assert(family == pbrms->dst->family);
stream_putl(s, pbrms->filter_bm);
/*
* Convert struct pbr_map_sequence to canonical form
*/
memset(&r, 0, sizeof(r));
r.seq = pbrms->seqno;
r.priority = pbrms->ruleno;
r.unique = pbrms->unique;
stream_putc(s, pbrms->ip_proto); /* The ip_proto */
pbr_encode_pbr_map_sequence_prefix(s, pbrms->src, family);
stream_putw(s, pbrms->src_prt);
pbr_encode_pbr_map_sequence_prefix(s, pbrms->dst, family);
stream_putw(s, pbrms->dst_prt);
stream_putc(s, pbrms->dsfield);
stream_putl(s, pbrms->mark);
/* PCP */
if (CHECK_FLAG(pbrms->filter_bm, PBR_FILTER_PCP))
stream_putc(s, pbrms->match_pcp);
/* filter */
r.filter.filter_bm = pbrms->filter_bm;
if (pbrms->src)
r.filter.src_ip = *pbrms->src;
else
stream_putc(s, 0);
stream_putw(s, pbrms->action_pcp);
/* VLAN */
stream_putw(s, pbrms->match_vlan_id);
stream_putw(s, pbrms->match_vlan_flags);
r.filter.src_ip.family = family;
if (pbrms->dst)
r.filter.dst_ip = *pbrms->dst;
else
r.filter.dst_ip.family = family;
r.filter.src_port = pbrms->src_prt;
r.filter.dst_port = pbrms->dst_prt;
r.filter.pcp = pbrms->match_pcp;
r.filter.vlan_id = pbrms->match_vlan_id;
r.filter.vlan_flags = pbrms->match_vlan_flags;
r.filter.dsfield = pbrms->dsfield;
r.filter.fwmark = pbrms->mark;
r.filter.ip_proto = pbrms->ip_proto;
stream_putw(s, pbrms->action_vlan_id);
stream_putw(s, pbrms->action_vlan_flags);
stream_putl(s, pbrms->action_queue_id);
/*
* Fix up filter flags for now, since PBRD doesn't maintain
* them yet (aside from PBR_FILTER_PCP)
*/
if (!is_default_prefix(&r.filter.src_ip))
SET_FLAG(r.filter.filter_bm, PBR_FILTER_SRC_IP);
if (!is_default_prefix(&r.filter.dst_ip))
SET_FLAG(r.filter.filter_bm, PBR_FILTER_DST_IP);
if (r.filter.src_port)
SET_FLAG(r.filter.filter_bm, PBR_FILTER_SRC_PORT);
if (r.filter.dst_port)
SET_FLAG(r.filter.filter_bm, PBR_FILTER_DST_PORT);
if (r.filter.vlan_id)
SET_FLAG(r.filter.filter_bm, PBR_FILTER_VLAN_ID);
if (r.filter.vlan_flags)
SET_FLAG(r.filter.filter_bm, PBR_FILTER_VLAN_FLAGS);
if (r.filter.dsfield)
SET_FLAG(r.filter.filter_bm, PBR_FILTER_DSFIELD);
if (r.filter.fwmark)
SET_FLAG(r.filter.filter_bm, PBR_FILTER_FWMARK);
if (r.filter.ip_proto)
SET_FLAG(r.filter.filter_bm, PBR_FILTER_IP_PROTOCOL);
/* if the user does not use the command "set vrf name |unchanged"
/* actions */
/*
* PBR should maintain its own set of action flags that we
* can copy here instead of trying to infer from magic values.
*/
SET_FLAG(r.action.flags, PBR_ACTION_TABLE); /* always valid */
if (PBR_MAP_UNDEFINED_QUEUE_ID != pbrms->action_queue_id)
SET_FLAG(r.action.flags, PBR_ACTION_QUEUE_ID);
if (0 != pbrms->action_pcp)
SET_FLAG(r.action.flags, PBR_ACTION_PCP);
if (0 != pbrms->action_vlan_id)
SET_FLAG(r.action.flags, PBR_ACTION_VLAN_ID);
if (0 != pbrms->action_vlan_flags)
SET_FLAG(r.action.flags, PBR_ACTION_VLAN_FLAGS);
/*
* if the user does not use the command "set vrf name unchanged"
* then pbr_encode_pbr_map_sequence_vrf will not be called
*/
/* these statement get a table id */
if (pbrms->vrf_unchanged || pbrms->vrf_lookup)
pbr_encode_pbr_map_sequence_vrf(s, pbrms, ifp);
r.action.table = pbr_map_sequence_vrf(pbrms, ifp);
else if (pbrms->nhgrp_name)
stream_putl(s, pbr_nht_get_table(pbrms->nhgrp_name));
r.action.table = pbr_nht_get_table(pbrms->nhgrp_name);
else if (pbrms->nhg)
stream_putl(s, pbr_nht_get_table(pbrms->internal_nhg_name));
r.action.table = pbr_nht_get_table(pbrms->internal_nhg_name);
else {
/* Not valid for install without table */
return false;
}
stream_put(s, ifp->name, INTERFACE_NAMSIZ);
r.action.queue_id = pbrms->action_queue_id;
r.action.pcp = pbrms->action_pcp;
r.action.vlan_id = pbrms->action_vlan_id;
r.action.vlan_flags = pbrms->action_vlan_flags;
strlcpy(r.ifname, ifp->name, sizeof(r.ifname));
zapi_pbr_rule_encode(s, &r);
return true;
}
@ -607,11 +653,6 @@ bool pbr_send_pbr_map(struct pbr_map_sequence *pbrms,
install ? ZEBRA_RULE_ADD : ZEBRA_RULE_DELETE,
VRF_DEFAULT);
/*
* We are sending one item at a time at the moment
*/
stream_putl(s, 1);
DEBUGD(&pbr_dbg_zebra, "%s: %s %s seq %u %d %s %u", __func__,
install ? "Installing" : "Deleting", pbrm->name, pbrms->seqno,
install, pmi->ifp->name, pmi->delete);

View File

@ -181,8 +181,10 @@ def test_pbr_data():
#
#
# tm: must-match pattern
# tN: must Not match pattern
# c: command
# cDN: omit default destination IP address (special case)
# tm: must-match pattern
# tN: must Not match pattern
#
# Note we are searching amid a bunch of other rules, so these elements
# should be unique.
@ -199,6 +201,27 @@ ftest = [
{"c": "match vlan untagged", "tm": r"VLAN Flags Match: untagged$"},
{"c": "match vlan untagged-or-zero", "tm": r"VLAN Flags Match: untagged-or-zero$"},
{"c": "no match vlan tagged", "tN": r"VLAN Flags Match:"},
{"c": "match src-ip 37.49.22.0/24", "tm": r"SRC IP Match: 37.49.22.0/24$"},
{"c": "no match src-ip 37.49.22.0/24", "tN": r"SRC IP Match: 37.49.22.0/24$"},
{"c": "match dst-ip 38.41.29.0/25", "cDN": "foo", "tm": r"DST IP Match: 38.41.29.0/25$"},
{"c": "no match dst-ip 38.41.29.0/25", "tN": r"DST IP Match: 38.41.29.0/25$"},
{"c": "match src-port 117", "tm": r"SRC Port Match: 117$"},
{"c": "no match src-port 117", "tN": r"SRC Port Match: 117$"},
{"c": "match dst-port 119", "tm": r"DST Port Match: 119$"},
{"c": "no match dst-port 119", "tN": r"DST Port Match: 119$"},
{"c": "match dscp cs3", "tm": r"DSCP Match: 24$"},
{"c": "no match dscp cs3", "tN": r"DSCP Match: 24$"},
{"c": "match ecn 2", "tm": r"ECN Match: 2$"},
{"c": "no match ecn 2", "tN": r"ECN Match: 2$"},
{"c": "match mark 337", "tm": r"MARK Match: 337$"},
{"c": "no match mark 337", "tN": r"MARK Match: 337$"},
]
@ -233,6 +256,9 @@ def test_pbr_fields():
logger.info("Verifying PBR rule fields")
# uncomment for manual interaction
# tgen.cli()
tag = "field"
router_list = tgen.routers().values()
@ -240,8 +266,12 @@ def test_pbr_fields():
for t in ftest:
# send field-setting command
# always have a match dst-ip to satisfy rule non-empty check
vcmd = "c t\npbr-map ASAKUSA seq 100\n{}\nmatch dst-ip 9.9.9.9/32\nset nexthop-group A\nend\nend".format(
t["c"]
if "cDN" in t:
match_dstip = ""
else:
match_dstip = "match dst-ip 9.9.9.9/32\n"
vcmd = "c t\npbr-map ASAKUSA seq 100\n{}\n{}set nexthop-group A\nend\nend".format(
t["c"], match_dstip
)
router.vtysh_multicmd(vcmd)

View File

@ -3184,7 +3184,6 @@ static inline void zread_rule(ZAPI_HANDLER_ARGS)
struct zebra_pbr_rule zpr;
struct stream *s;
uint32_t total, i;
char ifname[INTERFACE_NAMSIZ + 1] = {};
s = msg;
STREAM_GETL(s, total);
@ -3194,68 +3193,11 @@ static inline void zread_rule(ZAPI_HANDLER_ARGS)
zpr.sock = client->sock;
zpr.rule.vrf_id = hdr->vrf_id;
STREAM_GETL(s, zpr.rule.seq);
STREAM_GETL(s, zpr.rule.priority);
STREAM_GETL(s, zpr.rule.unique);
STREAM_GETL(s, zpr.rule.filter.filter_bm);
if (!zapi_pbr_rule_decode(s, &zpr.rule))
goto stream_failure;
STREAM_GETC(s, zpr.rule.filter.ip_proto);
STREAM_GETC(s, zpr.rule.filter.src_ip.family);
STREAM_GETC(s, zpr.rule.filter.src_ip.prefixlen);
STREAM_GET(&zpr.rule.filter.src_ip.u.prefix, s,
prefix_blen(&zpr.rule.filter.src_ip));
STREAM_GETW(s, zpr.rule.filter.src_port);
STREAM_GETC(s, zpr.rule.filter.dst_ip.family);
STREAM_GETC(s, zpr.rule.filter.dst_ip.prefixlen);
STREAM_GET(&zpr.rule.filter.dst_ip.u.prefix, s,
prefix_blen(&zpr.rule.filter.dst_ip));
STREAM_GETW(s, zpr.rule.filter.dst_port);
STREAM_GETC(s, zpr.rule.filter.dsfield);
STREAM_GETL(s, zpr.rule.filter.fwmark);
STREAM_GETC(s, zpr.rule.filter.pcp);
STREAM_GETW(s, zpr.rule.action.pcp);
STREAM_GETW(s, zpr.rule.filter.vlan_id);
STREAM_GETW(s, zpr.rule.filter.vlan_flags);
STREAM_GETW(s, zpr.rule.action.vlan_id);
STREAM_GETW(s, zpr.rule.action.vlan_flags);
STREAM_GETL(s, zpr.rule.action.queue_id);
STREAM_GETL(s, zpr.rule.action.table);
STREAM_GET(ifname, s, INTERFACE_NAMSIZ);
strlcpy(zpr.ifname, ifname, sizeof(zpr.ifname));
strlcpy(zpr.rule.ifname, ifname, sizeof(zpr.rule.ifname));
if (!is_default_prefix(&zpr.rule.filter.src_ip))
zpr.rule.filter.filter_bm |= PBR_FILTER_SRC_IP;
if (!is_default_prefix(&zpr.rule.filter.dst_ip))
zpr.rule.filter.filter_bm |= PBR_FILTER_DST_IP;
if (zpr.rule.filter.src_port)
zpr.rule.filter.filter_bm |= PBR_FILTER_SRC_PORT;
if (zpr.rule.filter.dst_port)
zpr.rule.filter.filter_bm |= PBR_FILTER_DST_PORT;
if (zpr.rule.filter.dsfield)
zpr.rule.filter.filter_bm |= PBR_FILTER_DSFIELD;
if (zpr.rule.filter.ip_proto)
zpr.rule.filter.filter_bm |= PBR_FILTER_IP_PROTOCOL;
if (zpr.rule.filter.fwmark)
zpr.rule.filter.filter_bm |= PBR_FILTER_FWMARK;
/* NB PBR_FILTER_PCP should already be set by sender */
if (zpr.rule.filter.vlan_flags)
zpr.rule.filter.filter_bm |= PBR_FILTER_VLAN_FLAGS;
if (zpr.rule.filter.vlan_id)
zpr.rule.filter.filter_bm |= PBR_FILTER_VLAN_ID;
strlcpy(zpr.ifname, zpr.rule.ifname, sizeof(zpr.ifname));
if (!(zpr.rule.filter.src_ip.family == AF_INET
|| zpr.rule.filter.src_ip.family == AF_INET6)) {