From: Wesley Coakley Date: Wed, 24 Jun 2020 09:37:06 +0000 (-0400) Subject: pbrd: dscp interpret standard codepoints X-Git-Tag: base_7.5~160^2~2 X-Git-Url: https://git.puffer.fish/?a=commitdiff_plain;h=116b86bdb9ecff4567b2a300e1cf8cf148b89103;p=matthieu%2Ffrr.git 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 --- 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);