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
* 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;
- }
- 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 */
+ /* filter */
- 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_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;
+ }
+ 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 */
-
- 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 */
+ SET_FLAG(r.action.flags, PBR_ACTION_TABLE); /* always valid */
+ r.action.table = pbra->table_id;
- 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,
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)
* 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;
};
/*
#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
}
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));
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);
}
}
-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;
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);
-
- stream_putl(s, pbrms->filter_bm);
-
- 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);
+ if (pbrms->src)
+ assert(family == pbrms->src->family);
+ if (pbrms->dst)
+ assert(family == pbrms->dst->family);
+
+ /*
+ * 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;
+
+ /* filter */
+ r.filter.filter_bm = pbrms->filter_bm;
+ if (pbrms->src)
+ r.filter.src_ip = *pbrms->src;
+ else
+ r.filter.src_ip.family = family;
+ if (pbrms->dst)
+ r.filter.dst_ip = *pbrms->dst;
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.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);
+
+ /* actions */
- /* if the user does not use the command "set vrf name |unchanged"
- * then pbr_encode_pbr_map_sequence_vrf will not be called
+ /*
+ * 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);
- /* these statement get a table id */
+ /*
+ * if the user does not use the command "set vrf name unchanged"
+ * then pbr_encode_pbr_map_sequence_vrf will not be called
+ */
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;
}
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);
#
#
-# 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.
{"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$"},
]
logger.info("Verifying PBR rule fields")
+ # uncomment for manual interaction
+ # tgen.cli()
+
tag = "field"
router_list = tgen.routers().values()
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)
struct zebra_pbr_rule zpr;
struct stream *s;
uint32_t total, i;
- char ifname[INTERFACE_NAMSIZ + 1] = {};
s = msg;
STREAM_GETL(s, total);
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);
-
- 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 (!zapi_pbr_rule_decode(s, &zpr.rule))
+ goto stream_failure;
- 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)) {