summaryrefslogtreecommitdiffstats
path: root/pbrd
diff options
context:
space:
mode:
authorWesley Coakley <wcoakley@nvidia.com>2020-06-24 11:37:06 +0200
committerWesley Coakley <wcoakley@nvidia.com>2020-07-15 18:59:36 +0200
commit116b86bdb9ecff4567b2a300e1cf8cf148b89103 (patch)
treecfc7803d5c8302397a8f2739f4968f22c66ec4f2 /pbrd
parentpbrd, zebra, lib: DSCP / ECN-based PBR Matching (diff)
downloadfrr-116b86bdb9ecff4567b2a300e1cf8cf148b89103.tar.xz
frr-116b86bdb9ecff4567b2a300e1cf8cf148b89103.zip
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 <wcoakley@nvidia.com>
Diffstat (limited to 'pbrd')
-rw-r--r--pbrd/pbr_map.c53
-rw-r--r--pbrd/pbr_map.h2
-rw-r--r--pbrd/pbr_vty.c46
3 files changed, 95 insertions, 6 deletions
diff --git a/pbrd/pbr_map.c b/pbrd/pbr_map.c
index 3a3bea349..2f801bd74 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 fb8c6bf03..05b8d407d 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 947250323..37095625f 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);