(ECN) field in the IP header; if this value matches then forward the packet
according to the nexthop(s) specified.
+
+.. clicmd:: set queue-id (1-65535)
+
+ Set the egress port queue identifier for matched packets. The Linux Kernel
+ provider does not currently support packet mangling, so this field will be
+ ignored unless another provider is used.
+
+.. clicmd:: set pcp (0-7)
+
+ Set the 802.1Q priority code point (PCP) for matched packets. A PCP of zero
+ is the defaul (nominally, "best effort"). The Linux Kernel provider does not
+ currently support packet mangling, so this field will be ignored unless
+ another provider is used.
+
+.. clicmd:: set vlan (1-4094)
+
+ Set the VLAN tag for matched packets. Identifiers 0 and 4095 are reserved.
+ The Linux Kernel provider does not currently support packet mangling, so
+ this field will be ignored unless another provider is used.
+
+.. clicmd:: strip vlan
+
+ Strip inner vlan tags from matched packets. The Linux Kernel provider does not currently support packet mangling, so this field will be ignored unless another provider is used. It is invalid to specify both a `strip` and `set
+ vlan` action.
+
.. clicmd:: set nexthop-group NAME
Use the nexthop-group NAME as the place to forward packets when the match
#define PBR_FILTER_SRC_PORT_RANGE (1 << 6)
#define PBR_FILTER_DST_PORT_RANGE (1 << 7)
#define PBR_FILTER_DSFIELD (1 << 8)
-#define PBR_FILTER_IP_PROTOCOL (1 << 9)
+#define PBR_FILTER_IP_PROTOCOL (1 << 9)
#define PBR_DSFIELD_DSCP (0xfc) /* Upper 6 bits of DS field: DSCP */
#define PBR_DSFIELD_ECN (0x03) /* Lower 2 bits of DS field: BCN */
* the user criteria may directly point to a table too.
*/
struct pbr_action {
+ /* VLAN */
+ uint8_t pcp;
+ uint16_t vlan_id;
+ uint16_t vlan_flags;
+
+ uint32_t queue_id;
+
uint32_t table;
};
}
static const char *const pbr_map_reason_str[] = {
- "Invalid NH-group", "Invalid NH", "No Nexthops",
- "Both NH and NH-Group", "Invalid Src or Dst", "Invalid VRF",
- "Deleting Sequence",
+ "Invalid NH-group", "Invalid NH", "No Nexthops",
+ "Both NH and NH-Group", "Invalid Src or Dst", "Invalid VRF",
+ "Both VLAN Set and Strip", "Deleting Sequence",
};
void pbr_map_reason_string(unsigned int reason, char *buf, int size)
pbrms->seqno = seqno;
pbrms->ruleno = pbr_nht_get_next_rule(seqno);
pbrms->parent = pbrm;
+
+ pbrms->action_vlan_id = 0;
+ pbrms->action_vlan_flags = 0;
+ pbrms->action_pcp = 0;
+
+ pbrms->action_queue_id = PBR_MAP_UNDEFINED_QUEUE_ID;
+
pbrms->reason =
PBR_MAP_INVALID_EMPTY |
PBR_MAP_INVALID_NO_NEXTHOPS;
static void pbr_map_sequence_check_not_empty(struct pbr_map_sequence *pbrms)
{
- if (!pbrms->src && !pbrms->dst && !pbrms->mark && !pbrms->dsfield)
+ if (!pbrms->src && !pbrms->dst && !pbrms->mark && !pbrms->dsfield
+ && !pbrms->action_vlan_id && !pbrms->action_vlan_flags
+ && !pbrms->action_pcp
+ && pbrms->action_queue_id == PBR_MAP_UNDEFINED_QUEUE_ID)
pbrms->reason |= PBR_MAP_INVALID_EMPTY;
}
+static void pbr_map_sequence_check_vlan_actions(struct pbr_map_sequence *pbrms)
+{
+ /* The set vlan tag action does the following:
+ * 1. If the frame is untagged, it tags the frame with the
+ * configured VLAN ID.
+ * 2. If the frame is tagged, if replaces the tag.
+ *
+ * The strip vlan action removes any inner tag, so it is invalid to
+ * specify both a set and strip action.
+ */
+ if ((pbrms->action_vlan_id != 0) && (pbrms->action_vlan_flags != 0))
+ pbrms->reason |= PBR_MAP_INVALID_SET_STRIP_VLAN;
+}
+
+
/*
* Checks to see if we think that the pbmrs is valid. If we think
* the config is valid return true.
static void pbr_map_sequence_check_valid(struct pbr_map_sequence *pbrms)
{
pbr_map_sequence_check_nexthops_valid(pbrms);
-
+ pbr_map_sequence_check_vlan_actions(pbrms);
pbr_map_sequence_check_not_empty(pbrms);
}
uint8_t dsfield;
uint32_t mark;
+ /*
+ * Actions
+ */
+ uint8_t action_pcp;
+ uint8_t action_vlan_id;
+#define PBR_MAP_STRIP_INNER_ANY (1 << 0)
+ uint8_t action_vlan_flags;
+
+#define PBR_MAP_UNDEFINED_QUEUE_ID 0
+ uint32_t action_queue_id;
+
/*
* Family of the src/dst. Needed when deleting since we clear them
*/
#define PBR_MAP_INVALID_BOTH_NHANDGRP (1 << 3)
#define PBR_MAP_INVALID_EMPTY (1 << 4)
#define PBR_MAP_INVALID_VRF (1 << 5)
+#define PBR_MAP_INVALID_SET_STRIP_VLAN (1 << 6)
uint64_t reason;
QOBJ_FIELDS;
pbrms->nhs_installed = false;
}
+
+DEFPY(pbr_map_action_queue_id, pbr_map_action_queue_id_cmd,
+ "[no] set queue-id <(1-65535)$queue_id>",
+ NO_STR
+ "Set the rest of the command\n"
+ "Set based on egress port queue id\n"
+ "A valid value in range 1..65535 \n")
+{
+ struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
+
+ if (!no)
+ pbrms->action_queue_id = queue_id;
+ else if ((uint32_t)queue_id == pbrms->action_queue_id)
+ pbrms->action_queue_id = PBR_MAP_UNDEFINED_QUEUE_ID;
+
+ pbr_map_check(pbrms, true);
+
+ return CMD_SUCCESS;
+}
+
+DEFPY(pbr_map_action_pcp, pbr_map_action_pcp_cmd, "[no] set pcp <(0-7)$pcp>",
+ NO_STR
+ "Set the rest of the command\n"
+ "Set based on 802.1p Priority Code Point (PCP) value\n"
+ "A valid value in range 0..7\n")
+{
+ struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
+
+ if (!no)
+ pbrms->action_pcp = pcp;
+ else if (pcp == pbrms->action_pcp)
+ pbrms->action_pcp = 0;
+
+ pbr_map_check(pbrms, true);
+
+ return CMD_SUCCESS;
+}
+
+DEFPY(pbr_map_action_vlan_id, pbr_map_action_vlan_id_cmd,
+ "[no] set vlan <(1-4094)$vlan_id>",
+ NO_STR
+ "Set the rest of the command\n"
+ "Set action for VLAN tagging\n"
+ "A valid value in range 1..4094\n")
+{
+ struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
+
+ if (!no)
+ pbrms->action_vlan_id = vlan_id;
+ else if (pbrms->action_vlan_id == vlan_id)
+ pbrms->action_vlan_id = 0;
+
+ pbr_map_check(pbrms, true);
+
+ return CMD_SUCCESS;
+}
+
+DEFPY(pbr_map_action_strip_vlan, pbr_map_action_strip_vlan_cmd,
+ "[no] strip vlan",
+ NO_STR
+ "Strip the vlan tags from frame\n"
+ "Strip any inner vlan tag \n")
+{
+ struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
+
+ if (!no)
+ pbrms->action_vlan_flags = PBR_MAP_STRIP_INNER_ANY;
+ else
+ pbrms->action_vlan_flags = 0;
+
+ pbr_map_check(pbrms, true);
+
+ return CMD_SUCCESS;
+}
+
+
DEFPY(pbr_map_nexthop_group, pbr_map_nexthop_group_cmd,
"set nexthop-group NHGNAME$name",
"Set for the PBR-MAP\n"
if (pbrms->mark)
vty_out(vty, " MARK Match: %u\n", pbrms->mark);
+ if (pbrms->action_queue_id != PBR_MAP_UNDEFINED_QUEUE_ID)
+ vty_out(vty, " Set Queue ID %u\n",
+ pbrms->action_queue_id);
+
+ if (pbrms->action_vlan_id != 0)
+ vty_out(vty, " Set VLAN ID %u\n", pbrms->action_vlan_id);
+ if (pbrms->action_vlan_flags == PBR_MAP_STRIP_INNER_ANY)
+ vty_out(vty, " Strip VLAN ID\n");
+ if (pbrms->action_pcp)
+ vty_out(vty, " Set PCP %u\n", pbrms->action_pcp);
+
+
if (pbrms->nhgrp_name) {
vty_out(vty, " Nexthop-Group: %s\n", pbrms->nhgrp_name);
if (pbrms->mark)
vty_out(vty, " match mark %u\n", pbrms->mark);
+
+ if (pbrms->action_queue_id != PBR_MAP_UNDEFINED_QUEUE_ID)
+ vty_out(vty, " set queue-id %d\n", pbrms->action_queue_id);
+
+ if (pbrms->action_pcp)
+ vty_out(vty, " set pcp %d\n", pbrms->action_pcp);
+
+ if (pbrms->action_vlan_id)
+ vty_out(vty, " set vlan %u\n", pbrms->action_vlan_id);
+
+ if (pbrms->action_vlan_flags == PBR_MAP_STRIP_INNER_ANY)
+ vty_out(vty, " strip vlan any\n");
+
if (pbrms->vrf_unchanged)
vty_out(vty, " set vrf unchanged\n");
install_element(PBRMAP_NODE, &pbr_map_match_dscp_cmd);
install_element(PBRMAP_NODE, &pbr_map_match_ecn_cmd);
install_element(PBRMAP_NODE, &pbr_map_match_mark_cmd);
+ install_element(PBRMAP_NODE, &pbr_map_action_queue_id_cmd);
+ install_element(PBRMAP_NODE, &pbr_map_action_strip_vlan_cmd);
+ install_element(PBRMAP_NODE, &pbr_map_action_vlan_id_cmd);
+ install_element(PBRMAP_NODE, &pbr_map_action_pcp_cmd);
install_element(PBRMAP_NODE, &pbr_map_nexthop_group_cmd);
install_element(PBRMAP_NODE, &no_pbr_map_nexthop_group_cmd);
install_element(PBRMAP_NODE, &pbr_map_nexthop_cmd);
stream_putc(s, pbrms->dsfield);
stream_putl(s, pbrms->mark);
+ stream_putl(s, pbrms->action_queue_id);
+
+ stream_putw(s, pbrms->action_vlan_id);
+ stream_putw(s, pbrms->action_vlan_flags);
+ stream_putw(s, pbrms->action_pcp);
+
if (pbrms->vrf_unchanged || pbrms->vrf_lookup)
pbr_encode_pbr_map_sequence_vrf(s, pbrms, ifp);
else if (pbrms->nhgrp_name)
STREAM_GETW(s, zpr.rule.filter.dst_port);
STREAM_GETC(s, zpr.rule.filter.dsfield);
STREAM_GETL(s, zpr.rule.filter.fwmark);
+
+ STREAM_GETL(s, zpr.rule.action.queue_id);
+ STREAM_GETW(s, zpr.rule.action.vlan_id);
+ STREAM_GETW(s, zpr.rule.action.vlan_flags);
+ STREAM_GETW(s, zpr.rule.action.pcp);
+
STREAM_GETL(s, zpr.rule.action.table);
STREAM_GET(ifname, s, INTERFACE_NAMSIZ);
struct prefix src_ip;
struct prefix dst_ip;
uint8_t ip_proto;
+
+ uint8_t action_pcp;
+ uint16_t action_vlan_id;
+ uint16_t action_vlan_flags;
+
+ uint32_t action_queue_id;
+
char ifname[INTERFACE_NAMSIZ + 1];
};
dplane_rule->ip_proto = rule->rule.filter.ip_proto;
prefix_copy(&(dplane_rule->dst_ip), &rule->rule.filter.dst_ip);
prefix_copy(&(dplane_rule->src_ip), &rule->rule.filter.src_ip);
+
+ dplane_rule->action_pcp = rule->rule.action.pcp;
+ dplane_rule->action_vlan_flags = rule->rule.action.vlan_flags;
+ dplane_rule->action_vlan_id = rule->rule.action.vlan_id;
+ dplane_rule->action_queue_id = rule->rule.action.queue_id;
+
strlcpy(dplane_rule->ifname, rule->ifname, INTERFACE_NAMSIZ);
}