]> git.puffer.fish Git - mirror/frr.git/commitdiff
pbrd: dscp interpret standard codepoints
authorWesley Coakley <wcoakley@nvidia.com>
Wed, 24 Jun 2020 09:37:06 +0000 (05:37 -0400)
committerWesley Coakley <wcoakley@nvidia.com>
Wed, 15 Jul 2020 16:59:36 +0000 (12:59 -0400)
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>
doc/user/pbr.rst
pbrd/pbr_map.c
pbrd/pbr_map.h
pbrd/pbr_vty.c

index a483f17c79fb20a1bd4808ef323d7cc53a5487b5..99ef258cb21cc876648a55ef8cca6dc2dc68864c 100644 (file)
@@ -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)
 
index 3a3bea349f725290c5ca55f5f6f04725d61a0acf..2f801bd74d3ded1534df12a1594d0b66207c3478 100644 (file)
@@ -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;
index fb8c6bf032bd5cf009b06299ba9aea8ab0ed6c5d..05b8d407dfbddffa2f96fbd027a689fde65c124c 100644 (file)
@@ -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);
index 9472503238ce47113a326c4751bad10aea4b74ee..37095625fdbb9d1d78fda072e1e1187ba82835a8 100644 (file)
@@ -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);