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)
}
}
+/* 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;
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);
}
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;
}
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);