Skip to content

Commit

Permalink
pbrd: dscp interpret standard codepoints
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Wesley Coakley committed Jul 15, 2020
1 parent 01f23af commit 116b86b
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 8 deletions.
8 changes: 6 additions & 2 deletions doc/user/pbr.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
53 changes: 53 additions & 0 deletions pbrd/pbr_map.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 2 additions & 0 deletions pbrd/pbr_map.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
46 changes: 40 additions & 6 deletions pbrd/pbr_vty.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down Expand Up @@ -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);

Expand Down

0 comments on commit 116b86b

Please sign in to comment.