From 01f23affdb68d0117d0f2be652eebd835bdbc13e Mon Sep 17 00:00:00 2001 From: Wesley Coakley Date: Wed, 17 Jun 2020 20:20:05 -0400 Subject: [PATCH 1/4] 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 Signed-off-by: Saurav Kumar Paul --- doc/user/pbr.rst | 12 ++++++++ lib/pbr.h | 7 +++++ pbrd/pbr_map.c | 2 +- pbrd/pbr_map.h | 1 + pbrd/pbr_vty.c | 67 ++++++++++++++++++++++++++++++++++++++++++++ pbrd/pbr_zebra.c | 1 + zebra/rule_netlink.c | 31 ++++++++++++-------- zebra/zapi_msg.c | 4 +++ zebra/zebra_dplane.c | 16 +++++++++++ zebra/zebra_dplane.h | 2 ++ zebra/zebra_pbr.h | 2 ++ 11 files changed, 132 insertions(+), 13 deletions(-) diff --git a/doc/user/pbr.rst b/doc/user/pbr.rst index 149949e863..a483f17c79 100644 --- a/doc/user/pbr.rst +++ b/doc/user/pbr.rst @@ -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 diff --git a/lib/pbr.h b/lib/pbr.h index cf6ac41d32..fd183d7115 100644 --- a/lib/pbr.h +++ b/lib/pbr.h @@ -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; }; diff --git a/pbrd/pbr_map.c b/pbrd/pbr_map.c index edc3f1d8da..3a3bea349f 100644 --- a/pbrd/pbr_map.c +++ b/pbrd/pbr_map.c @@ -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; } diff --git a/pbrd/pbr_map.h b/pbrd/pbr_map.h index 41f1703954..fb8c6bf032 100644 --- a/pbrd/pbr_map.h +++ b/pbrd/pbr_map.h @@ -89,6 +89,7 @@ struct pbr_map_sequence { */ struct prefix *src; struct prefix *dst; + uint8_t dsfield; uint32_t mark; /* diff --git a/pbrd/pbr_vty.c b/pbrd/pbr_vty.c index cd9096cbc8..9472503238 100644 --- a/pbrd/pbr_vty.c +++ b/pbrd/pbr_vty.c @@ -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); diff --git a/pbrd/pbr_zebra.c b/pbrd/pbr_zebra.c index de2a99e269..d0099a46e3 100644 --- a/pbrd/pbr_zebra.c +++ b/pbrd/pbr_zebra.c @@ -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) diff --git a/zebra/rule_netlink.c b/zebra/rule_netlink.c index b7be398506..f0cfe64b0f 100644 --- a/zebra/rule_netlink.c +++ b/zebra/rule_netlink.c @@ -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 diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index dc7c595d26..daf08e96a0 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -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; diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c index e34b6f23ff..7657ae8dc5 100644 --- a/zebra/zebra_dplane.c +++ b/zebra/zebra_dplane.c @@ -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); } diff --git a/zebra/zebra_dplane.h b/zebra/zebra_dplane.h index 8e873886df..0fa21f620d 100644 --- a/zebra/zebra_dplane.h +++ b/zebra/zebra_dplane.h @@ -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 * diff --git a/zebra/zebra_pbr.h b/zebra/zebra_pbr.h index 4bc0f40037..dd2d7a190d 100644 --- a/zebra/zebra_pbr.h +++ b/zebra/zebra_pbr.h @@ -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) From 116b86bdb9ecff4567b2a300e1cf8cf148b89103 Mon Sep 17 00:00:00 2001 From: Wesley Coakley Date: Wed, 24 Jun 2020 05:37:06 -0400 Subject: [PATCH 2/4] pbrd: dscp interpret standard codepoints Matching by dscp may now also be specified by its standard codepoint (provided it has one), such as `cf0` or `af11`. Signed-off-by: Wesley Coakley --- doc/user/pbr.rst | 8 ++++++-- pbrd/pbr_map.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++++ pbrd/pbr_map.h | 2 ++ pbrd/pbr_vty.c | 46 +++++++++++++++++++++++++++++++++++------ 4 files changed, 101 insertions(+), 8 deletions(-) diff --git a/doc/user/pbr.rst b/doc/user/pbr.rst index a483f17c79..99ef258cb2 100644 --- a/doc/user/pbr.rst +++ b/doc/user/pbr.rst @@ -123,11 +123,15 @@ 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) +.. clicmd:: match dscp (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. + according to the nexthop(s) specified. The passed DSCP value may also be a + standard name for a differentiated service code point like cs0 or af11. + + You may only specify one dscp per route map sequence; to match on multiple + dscp values you will need to create several sequences, one for each value. .. clicmd:: match ecn (0-3) diff --git a/pbrd/pbr_map.c b/pbrd/pbr_map.c index 3a3bea349f..2f801bd74d 100644 --- a/pbrd/pbr_map.c +++ b/pbrd/pbr_map.c @@ -444,6 +444,59 @@ static void pbr_map_add_interfaces(struct pbr_map *pbrm) } } +/* Decodes a standardized DSCP into its representative value */ +uint8_t pbr_map_decode_dscp_enum(const char *name) +{ + /* Standard Differentiated Services Field Codepoints */ + if (!strcmp(name, "cs0")) + return 0; + if (!strcmp(name, "cs1")) + return 8; + if (!strcmp(name, "cs2")) + return 16; + if (!strcmp(name, "cs3")) + return 24; + if (!strcmp(name, "cs4")) + return 32; + if (!strcmp(name, "cs5")) + return 40; + if (!strcmp(name, "cs6")) + return 48; + if (!strcmp(name, "cs7")) + return 56; + if (!strcmp(name, "af11")) + return 10; + if (!strcmp(name, "af12")) + return 12; + if (!strcmp(name, "af13")) + return 14; + if (!strcmp(name, "af21")) + return 18; + if (!strcmp(name, "af22")) + return 20; + if (!strcmp(name, "af23")) + return 22; + if (!strcmp(name, "af31")) + return 26; + if (!strcmp(name, "af32")) + return 28; + if (!strcmp(name, "af33")) + return 30; + if (!strcmp(name, "af41")) + return 34; + if (!strcmp(name, "af42")) + return 36; + if (!strcmp(name, "af43")) + return 38; + if (!strcmp(name, "ef")) + return 46; + if (!strcmp(name, "voice-admit")) + return 44; + + /* No match? Error out */ + return -1; +} + struct pbr_map_sequence *pbrms_get(const char *name, uint32_t seqno) { struct pbr_map *pbrm; diff --git a/pbrd/pbr_map.h b/pbrd/pbr_map.h index fb8c6bf032..05b8d407df 100644 --- a/pbrd/pbr_map.h +++ b/pbrd/pbr_map.h @@ -169,6 +169,8 @@ extern void pbr_map_add_interface(struct pbr_map *pbrm, struct interface *ifp); extern void pbr_map_interface_delete(struct pbr_map *pbrm, struct interface *ifp); +extern uint8_t pbr_map_decode_dscp_enum(const char *name); + /* Update maps installed on interface */ extern void pbr_map_policy_interface_update(const struct interface *ifp, bool state_up); diff --git a/pbrd/pbr_vty.c b/pbrd/pbr_vty.c index 9472503238..37095625fd 100644 --- a/pbrd/pbr_vty.c +++ b/pbrd/pbr_vty.c @@ -184,21 +184,57 @@ DEFPY(pbr_map_match_dst, pbr_map_match_dst_cmd, } DEFPY(pbr_map_match_dscp, pbr_map_match_dscp_cmd, - "[no] match dscp (0-63)$dscp", + "[no] match dscp DSCP$dscp", NO_STR "Match the rest of the command\n" "Match based on IP DSCP field\n" - "Differentiated Service Code Point\n") + "DSCP value (below 64) or standard codepoint name\n") { struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence); + char dscpname[100]; + uint8_t rawDscp; + + /* Discriminate dscp enums (cs0, cs1 etc.) and numbers */ + bool isANumber = true; + for (int i = 0; i < (int)strlen(dscp); i++) { + /* Letters are not numbers */ + if (!isdigit(dscp[i])) + isANumber = false; + + /* Lowercase the dscp enum (if needed) */ + if (isupper(dscp[i])) + dscpname[i] = tolower(dscp[i]); + else + dscpname[i] = dscp[i]; + } + dscpname[strlen(dscp)] = '\0'; + + if (isANumber) { + /* dscp passed is a regular number */ + long dscpAsNum = strtol(dscp, NULL, 0); + + if (dscpAsNum > PBR_DSFIELD_DSCP >> 2) { + /* Refuse to install on overflow */ + vty_out(vty, "dscp (%s) must be less than 64\n", dscp); + return CMD_WARNING_CONFIG_FAILED; + } + rawDscp = dscpAsNum; + } else { + /* check dscp if it is an enum like cs0 */ + rawDscp = pbr_map_decode_dscp_enum(dscpname); + if (rawDscp > PBR_DSFIELD_DSCP) { + vty_out(vty, "Invalid dscp value: %s\n", dscpname); + return CMD_WARNING_CONFIG_FAILED; + } + } if (!no) { - if (((pbrms->dsfield & PBR_DSFIELD_DSCP) >> 2) == dscp) + if (((pbrms->dsfield & PBR_DSFIELD_DSCP) >> 2) == rawDscp) return CMD_SUCCESS; /* Set the DSCP bits of the DSField */ pbrms->dsfield = - (pbrms->dsfield & ~PBR_DSFIELD_DSCP) | (dscp << 2); + (pbrms->dsfield & ~PBR_DSFIELD_DSCP) | (rawDscp << 2); } else { pbrms->dsfield &= ~PBR_DSFIELD_DSCP; } @@ -614,8 +650,6 @@ static void vty_show_pbrms(struct vty *vty, 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); From d301f1532093100299d87b772d94aededc1875f9 Mon Sep 17 00:00:00 2001 From: Wesley Coakley Date: Mon, 13 Jul 2020 12:26:03 -0400 Subject: [PATCH 3/4] pbrd: expose dscp & ecn to json for `show pbr map` Signed-off-by: Wesley Coakley --- pbrd/pbr_vty.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pbrd/pbr_vty.c b/pbrd/pbr_vty.c index 37095625fd..a73d885ea6 100644 --- a/pbrd/pbr_vty.c +++ b/pbrd/pbr_vty.c @@ -744,6 +744,12 @@ static void vty_json_pbrms(json_object *j, struct vty *vty, prefix2str(pbrms->dst, buf, sizeof(buf))); if (pbrms->mark) json_object_int_add(jpbrm, "matchMark", pbrms->mark); + if (pbrms->dsfield & PBR_DSFIELD_DSCP) + json_object_int_add(jpbrm, "matchDscp", + (pbrms->dsfield & PBR_DSFIELD_DSCP) >> 2); + if (pbrms->dsfield & PBR_DSFIELD_ECN) + json_object_int_add(jpbrm, "matchEcn", + pbrms->dsfield & PBR_DSFIELD_ECN); json_object_array_add(j, jpbrm); } From 44025159215212df2b9f21451d49edc109a61dbe Mon Sep 17 00:00:00 2001 From: Wesley Coakley Date: Mon, 13 Jul 2020 14:45:29 -0400 Subject: [PATCH 4/4] tests: expand pbr-topo1 to cover DSCP & ECN Signed-off-by: Wesley Coakley --- tests/topotests/pbr-topo1/r1/pbr-map.json | 26 +++++++++++++++++++++++ tests/topotests/pbr-topo1/r1/pbrd.conf | 10 +++++++++ 2 files changed, 36 insertions(+) diff --git a/tests/topotests/pbr-topo1/r1/pbr-map.json b/tests/topotests/pbr-topo1/r1/pbr-map.json index f0738dc540..bfa0ecb849 100644 --- a/tests/topotests/pbr-topo1/r1/pbr-map.json +++ b/tests/topotests/pbr-topo1/r1/pbr-map.json @@ -62,6 +62,32 @@ }, "matchDst":"dead:beef::\/64", "matchMark":314159 + }, + { + "sequenceNumber":15, + "vrfUnchanged":false, + "installed":true, + "installedReason":"Valid", + "nexthopGroup":{ + "name":"ASAKUSA15", + "installed":true, + "installedInternally":1 + }, + "matchDst":"dead:beef::/64", + "matchDscp":10 + }, + { + "sequenceNumber":20, + "vrfUnchanged":false, + "installed":true, + "installedReason":"Valid", + "nexthopGroup":{ + "name":"ASAKUSA20", + "installed":true, + "installedInternally":1 + }, + "matchDst":"dead:beef::/64", + "matchEcn":1 } ] }, diff --git a/tests/topotests/pbr-topo1/r1/pbrd.conf b/tests/topotests/pbr-topo1/r1/pbrd.conf index 298cba2860..45cb7656ab 100644 --- a/tests/topotests/pbr-topo1/r1/pbrd.conf +++ b/tests/topotests/pbr-topo1/r1/pbrd.conf @@ -73,6 +73,16 @@ pbr-map ASAKUSA seq 10 match mark 314159 set nexthop c0ff:ee::1 ! +pbr-map ASAKUSA seq 15 + match dst-ip dead:beef::/64 + match dscp af11 + set nexthop c0ff:ee::1 +! +pbr-map ASAKUSA seq 20 + match dst-ip dead:beef::/64 + match ecn 1 + set nexthop c0ff:ee::1 +! # Interface policies int r1-eth1 pbr-policy EVA