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>
This commit is contained in:
Wesley Coakley 2020-06-24 05:37:06 -04:00
parent 01f23affdb
commit 116b86bdb9
4 changed files with 101 additions and 8 deletions

View 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)

View 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;

View 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);

View 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);