mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-15 13:27:53 +00:00
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:
parent
01f23affdb
commit
116b86bdb9
@ -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)
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user