forked from Mirror/frr
pbrd, zebra, lib: DSCP / ECN-based PBR Matching
Extend PBR maps to discriminate by Differentiated Services Code Point and / or Explicit Congestion Notification fields. These fields are used in the IP header for classifying network traffic. 0 1 2 3 4 5 6 7 +-----+-----+-----+-----+-----+-----+-----+-----+ | DS FIELD, DSCP | ECN FIELD | +-----+-----+-----+-----+-----+-----+-----+-----+ DSCP: differentiated services codepoint ECN: Explicit Congestion Notification Signed-off-by: Wesley Coakley <wcoakley@nvidia.com> Signed-off-by: Saurav Kumar Paul <saurav@cumulusnetworks.com>
This commit is contained in:
parent
9a4dee5c35
commit
01f23affdb
|
@ -123,6 +123,18 @@ end destination.
|
|||
on another platform it will be denied. This mark translates to the
|
||||
underlying `ip rule .... fwmark XXXX` command.
|
||||
|
||||
.. clicmd:: match dscp (0-63)
|
||||
|
||||
Match packets according to the specified differentiated services code point
|
||||
(DSCP) in the IP header; if this value matches then forward the packet
|
||||
according to the nexthop(s) specified.
|
||||
|
||||
.. clicmd:: match ecn (0-3)
|
||||
|
||||
Match packets according to the specified explicit congestion notification
|
||||
(ECN) field in the IP header; if this value matches then forward the packet
|
||||
according to the nexthop(s) specified.
|
||||
|
||||
.. clicmd:: set nexthop-group NAME
|
||||
|
||||
Use the nexthop-group NAME as the place to forward packets when the match
|
||||
|
|
|
@ -49,6 +49,10 @@ struct pbr_filter {
|
|||
#define PBR_FILTER_PROTO (1 << 5)
|
||||
#define PBR_FILTER_SRC_PORT_RANGE (1 << 6)
|
||||
#define PBR_FILTER_DST_PORT_RANGE (1 << 7)
|
||||
#define PBR_FILTER_DSFIELD (1 << 8)
|
||||
|
||||
#define PBR_DSFIELD_DSCP (0xfc) /* Upper 6 bits of DS field: DSCP */
|
||||
#define PBR_DSFIELD_ECN (0x03) /* Lower 2 bits of DS field: BCN */
|
||||
|
||||
/* Source and Destination IP address with masks. */
|
||||
struct prefix src_ip;
|
||||
|
@ -58,6 +62,9 @@ struct pbr_filter {
|
|||
uint16_t src_port;
|
||||
uint16_t dst_port;
|
||||
|
||||
/* Filter by Differentiated Services field */
|
||||
uint8_t dsfield; /* DSCP (6 bits) & ECN (2 bits) */
|
||||
|
||||
/* Filter with fwmark */
|
||||
uint32_t fwmark;
|
||||
};
|
||||
|
|
|
@ -547,7 +547,7 @@ pbr_map_sequence_check_nexthops_valid(struct pbr_map_sequence *pbrms)
|
|||
|
||||
static void pbr_map_sequence_check_not_empty(struct pbr_map_sequence *pbrms)
|
||||
{
|
||||
if (!pbrms->src && !pbrms->dst && !pbrms->mark)
|
||||
if (!pbrms->src && !pbrms->dst && !pbrms->mark && !pbrms->dsfield)
|
||||
pbrms->reason |= PBR_MAP_INVALID_EMPTY;
|
||||
}
|
||||
|
||||
|
|
|
@ -89,6 +89,7 @@ struct pbr_map_sequence {
|
|||
*/
|
||||
struct prefix *src;
|
||||
struct prefix *dst;
|
||||
uint8_t dsfield;
|
||||
uint32_t mark;
|
||||
|
||||
/*
|
||||
|
|
|
@ -183,6 +183,55 @@ DEFPY(pbr_map_match_dst, pbr_map_match_dst_cmd,
|
|||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFPY(pbr_map_match_dscp, pbr_map_match_dscp_cmd,
|
||||
"[no] match dscp (0-63)$dscp",
|
||||
NO_STR
|
||||
"Match the rest of the command\n"
|
||||
"Match based on IP DSCP field\n"
|
||||
"Differentiated Service Code Point\n")
|
||||
{
|
||||
struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
|
||||
|
||||
if (!no) {
|
||||
if (((pbrms->dsfield & PBR_DSFIELD_DSCP) >> 2) == dscp)
|
||||
return CMD_SUCCESS;
|
||||
|
||||
/* Set the DSCP bits of the DSField */
|
||||
pbrms->dsfield =
|
||||
(pbrms->dsfield & ~PBR_DSFIELD_DSCP) | (dscp << 2);
|
||||
} else {
|
||||
pbrms->dsfield &= ~PBR_DSFIELD_DSCP;
|
||||
}
|
||||
|
||||
pbr_map_check(pbrms, true);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFPY(pbr_map_match_ecn, pbr_map_match_ecn_cmd,
|
||||
"[no] match ecn (0-3)$ecn",
|
||||
NO_STR
|
||||
"Match the rest of the command\n"
|
||||
"Match based on IP ECN field\n"
|
||||
"Explicit Congestion Notification\n")
|
||||
{
|
||||
struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
|
||||
|
||||
if (!no) {
|
||||
if ((pbrms->dsfield & PBR_DSFIELD_ECN) == ecn)
|
||||
return CMD_SUCCESS;
|
||||
|
||||
/* Set the ECN bits of the DSField */
|
||||
pbrms->dsfield = (pbrms->dsfield & ~PBR_DSFIELD_ECN) | ecn;
|
||||
} else {
|
||||
pbrms->dsfield &= ~PBR_DSFIELD_ECN;
|
||||
}
|
||||
|
||||
pbr_map_check(pbrms, true);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFPY(pbr_map_match_mark, pbr_map_match_mark_cmd,
|
||||
"[no] match mark (1-4294967295)$mark",
|
||||
NO_STR
|
||||
|
@ -559,6 +608,14 @@ static void vty_show_pbrms(struct vty *vty,
|
|||
if (pbrms->dst)
|
||||
vty_out(vty, " DST Match: %s\n",
|
||||
prefix2str(pbrms->dst, buf, sizeof(buf)));
|
||||
if (pbrms->dsfield & PBR_DSFIELD_DSCP)
|
||||
vty_out(vty, " DSCP Match: %u\n",
|
||||
(pbrms->dsfield & PBR_DSFIELD_DSCP) >> 2);
|
||||
if (pbrms->dsfield & PBR_DSFIELD_ECN)
|
||||
vty_out(vty, " ECN Match: %u\n",
|
||||
pbrms->dsfield & PBR_DSFIELD_ECN);
|
||||
if (pbrms->dsfield)
|
||||
vty_out(vty, " DSField Match: %u\n", (pbrms->dsfield));
|
||||
if (pbrms->mark)
|
||||
vty_out(vty, " MARK Match: %u\n", pbrms->mark);
|
||||
|
||||
|
@ -946,6 +1003,14 @@ static int pbr_vty_map_config_write_sequence(struct vty *vty,
|
|||
vty_out(vty, " match dst-ip %s\n",
|
||||
prefix2str(pbrms->dst, buff, sizeof(buff)));
|
||||
|
||||
if (pbrms->dsfield & PBR_DSFIELD_DSCP)
|
||||
vty_out(vty, " match dscp %u\n",
|
||||
(pbrms->dsfield & PBR_DSFIELD_DSCP) >> 2);
|
||||
|
||||
if (pbrms->dsfield & PBR_DSFIELD_ECN)
|
||||
vty_out(vty, " match ecn %u\n",
|
||||
pbrms->dsfield & PBR_DSFIELD_ECN);
|
||||
|
||||
if (pbrms->mark)
|
||||
vty_out(vty, " match mark %u\n", pbrms->mark);
|
||||
|
||||
|
@ -1026,6 +1091,8 @@ void pbr_vty_init(void)
|
|||
install_element(INTERFACE_NODE, &pbr_policy_cmd);
|
||||
install_element(PBRMAP_NODE, &pbr_map_match_src_cmd);
|
||||
install_element(PBRMAP_NODE, &pbr_map_match_dst_cmd);
|
||||
install_element(PBRMAP_NODE, &pbr_map_match_dscp_cmd);
|
||||
install_element(PBRMAP_NODE, &pbr_map_match_ecn_cmd);
|
||||
install_element(PBRMAP_NODE, &pbr_map_match_mark_cmd);
|
||||
install_element(PBRMAP_NODE, &pbr_map_nexthop_group_cmd);
|
||||
install_element(PBRMAP_NODE, &no_pbr_map_nexthop_group_cmd);
|
||||
|
|
|
@ -536,6 +536,7 @@ static void pbr_encode_pbr_map_sequence(struct stream *s,
|
|||
stream_putw(s, 0); /* src port */
|
||||
pbr_encode_pbr_map_sequence_prefix(s, pbrms->dst, family);
|
||||
stream_putw(s, 0); /* dst port */
|
||||
stream_putc(s, pbrms->dsfield);
|
||||
stream_putl(s, pbrms->mark);
|
||||
|
||||
if (pbrms->vrf_unchanged || pbrms->vrf_lookup)
|
||||
|
|
|
@ -58,10 +58,12 @@
|
|||
* Returns -1 on failure, 0 when the msg doesn't fit entirely in the buffer
|
||||
* or the number of bytes written to buf.
|
||||
*/
|
||||
static ssize_t netlink_rule_msg_encode(
|
||||
int cmd, const struct zebra_dplane_ctx *ctx, uint32_t filter_bm,
|
||||
uint32_t priority, uint32_t table, const struct prefix *src_ip,
|
||||
const struct prefix *dst_ip, uint32_t fwmark, void *buf, size_t buflen)
|
||||
static ssize_t
|
||||
netlink_rule_msg_encode(int cmd, const struct zebra_dplane_ctx *ctx,
|
||||
uint32_t filter_bm, uint32_t priority, uint32_t table,
|
||||
const struct prefix *src_ip,
|
||||
const struct prefix *dst_ip, uint32_t fwmark,
|
||||
uint8_t dsfield, void *buf, size_t buflen)
|
||||
{
|
||||
uint8_t protocol = RTPROT_ZEBRA;
|
||||
int family;
|
||||
|
@ -122,6 +124,10 @@ static ssize_t netlink_rule_msg_encode(
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* dsfield, if specified */
|
||||
if (filter_bm & PBR_FILTER_DSFIELD)
|
||||
req->frh.tos = dsfield;
|
||||
|
||||
/* Route table to use to forward, if filter criteria matches. */
|
||||
if (table < 256)
|
||||
req->frh.table = table;
|
||||
|
@ -145,16 +151,15 @@ static ssize_t netlink_rule_msg_encode(
|
|||
/* Install or uninstall specified rule for a specific interface.
|
||||
* Form netlink message and ship it.
|
||||
*/
|
||||
static int
|
||||
netlink_rule_update_internal(int cmd, const struct zebra_dplane_ctx *ctx,
|
||||
uint32_t filter_bm, uint32_t priority,
|
||||
uint32_t table, const struct prefix *src_ip,
|
||||
const struct prefix *dst_ip, uint32_t fwmark)
|
||||
static int netlink_rule_update_internal(
|
||||
int cmd, const struct zebra_dplane_ctx *ctx, uint32_t filter_bm,
|
||||
uint32_t priority, uint32_t table, const struct prefix *src_ip,
|
||||
const struct prefix *dst_ip, uint32_t fwmark, uint8_t dsfield)
|
||||
{
|
||||
char buf[NL_PKT_BUF_SIZE];
|
||||
|
||||
netlink_rule_msg_encode(cmd, ctx, filter_bm, priority, table, src_ip,
|
||||
dst_ip, fwmark, buf, sizeof(buf));
|
||||
dst_ip, fwmark, dsfield, buf, sizeof(buf));
|
||||
return netlink_talk_info(netlink_talk_filter, (void *)&buf,
|
||||
dplane_ctx_get_ns(ctx), 0);
|
||||
}
|
||||
|
@ -188,7 +193,8 @@ enum zebra_dplane_result kernel_pbr_rule_update(struct zebra_dplane_ctx *ctx)
|
|||
dplane_ctx_rule_get_priority(ctx),
|
||||
dplane_ctx_rule_get_table(ctx), dplane_ctx_rule_get_src_ip(ctx),
|
||||
dplane_ctx_rule_get_dst_ip(ctx),
|
||||
dplane_ctx_rule_get_fwmark(ctx));
|
||||
dplane_ctx_rule_get_fwmark(ctx),
|
||||
dplane_ctx_rule_get_dsfield(ctx));
|
||||
|
||||
/**
|
||||
* Delete the old one.
|
||||
|
@ -203,7 +209,8 @@ enum zebra_dplane_result kernel_pbr_rule_update(struct zebra_dplane_ctx *ctx)
|
|||
dplane_ctx_rule_get_old_table(ctx),
|
||||
dplane_ctx_rule_get_old_src_ip(ctx),
|
||||
dplane_ctx_rule_get_old_dst_ip(ctx),
|
||||
dplane_ctx_rule_get_old_fwmark(ctx));
|
||||
dplane_ctx_rule_get_old_fwmark(ctx),
|
||||
dplane_ctx_rule_get_old_dsfield(ctx));
|
||||
|
||||
|
||||
return (ret == 0 ? ZEBRA_DPLANE_REQUEST_SUCCESS
|
||||
|
|
|
@ -2526,6 +2526,7 @@ static inline void zread_rule(ZAPI_HANDLER_ARGS)
|
|||
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_GETL(s, zpr.rule.action.table);
|
||||
STREAM_GETL(s, zpr.rule.ifindex);
|
||||
|
@ -2556,6 +2557,9 @@ static inline void zread_rule(ZAPI_HANDLER_ARGS)
|
|||
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.fwmark)
|
||||
zpr.rule.filter.filter_bm |= PBR_FILTER_FWMARK;
|
||||
|
||||
|
|
|
@ -204,6 +204,7 @@ struct dplane_ctx_rule {
|
|||
/* Filter criteria */
|
||||
uint32_t filter_bm;
|
||||
uint32_t fwmark;
|
||||
uint8_t dsfield;
|
||||
struct prefix src_ip;
|
||||
struct prefix dst_ip;
|
||||
};
|
||||
|
@ -1676,6 +1677,20 @@ uint32_t dplane_ctx_rule_get_old_fwmark(const struct zebra_dplane_ctx *ctx)
|
|||
return ctx->u.rule.old.fwmark;
|
||||
}
|
||||
|
||||
uint8_t dplane_ctx_rule_get_dsfield(const struct zebra_dplane_ctx *ctx)
|
||||
{
|
||||
DPLANE_CTX_VALID(ctx);
|
||||
|
||||
return ctx->u.rule.new.dsfield;
|
||||
}
|
||||
|
||||
uint8_t dplane_ctx_rule_get_old_dsfield(const struct zebra_dplane_ctx *ctx)
|
||||
{
|
||||
DPLANE_CTX_VALID(ctx);
|
||||
|
||||
return ctx->u.rule.old.dsfield;
|
||||
}
|
||||
|
||||
const struct prefix *
|
||||
dplane_ctx_rule_get_src_ip(const struct zebra_dplane_ctx *ctx)
|
||||
{
|
||||
|
@ -2129,6 +2144,7 @@ static void dplane_ctx_rule_init_single(struct dplane_ctx_rule *dplane_rule,
|
|||
|
||||
dplane_rule->filter_bm = rule->rule.filter.filter_bm;
|
||||
dplane_rule->fwmark = rule->rule.filter.fwmark;
|
||||
dplane_rule->dsfield = rule->rule.filter.dsfield;
|
||||
prefix_copy(&(dplane_rule->dst_ip), &rule->rule.filter.dst_ip);
|
||||
prefix_copy(&(dplane_rule->src_ip), &rule->rule.filter.src_ip);
|
||||
}
|
||||
|
|
|
@ -412,6 +412,8 @@ uint32_t dplane_ctx_rule_get_filter_bm(const struct zebra_dplane_ctx *ctx);
|
|||
uint32_t dplane_ctx_rule_get_old_filter_bm(const struct zebra_dplane_ctx *ctx);
|
||||
uint32_t dplane_ctx_rule_get_fwmark(const struct zebra_dplane_ctx *ctx);
|
||||
uint32_t dplane_ctx_rule_get_old_fwmark(const struct zebra_dplane_ctx *ctx);
|
||||
uint8_t dplane_ctx_rule_get_dsfield(const struct zebra_dplane_ctx *ctx);
|
||||
uint8_t dplane_ctx_rule_get_old_dsfield(const struct zebra_dplane_ctx *ctx);
|
||||
const struct prefix *
|
||||
dplane_ctx_rule_get_src_ip(const struct zebra_dplane_ctx *ctx);
|
||||
const struct prefix *
|
||||
|
|
|
@ -54,6 +54,8 @@ struct zebra_pbr_rule {
|
|||
(r->rule.filter.filter_bm & PBR_FILTER_SRC_PORT)
|
||||
#define IS_RULE_FILTERING_ON_DST_PORT(r) \
|
||||
(r->rule.filter.filter_bm & PBR_FILTER_DST_PORT)
|
||||
#define IS_RULE_FILTERING_ON_DSFIELD(r) \
|
||||
(r->rule.filter.filter_bm & PBR_FILTER_DSFIELD)
|
||||
#define IS_RULE_FILTERING_ON_FWMARK(r) \
|
||||
(r->rule.filter.filter_bm & PBR_FILTER_FWMARK)
|
||||
|
||||
|
|
Loading…
Reference in a new issue