]> git.puffer.fish Git - matthieu/frr.git/commitdiff
pbrd: add vlan actions to vty
authorEli Baum <ebaum@mitre.org>
Tue, 5 Oct 2021 13:06:49 +0000 (09:06 -0400)
committerEli Baum <ebaum@mitre.org>
Thu, 7 Oct 2021 13:14:59 +0000 (09:14 -0400)
Signed-off-by: Eli Baum <ebaum@mitre.org>
doc/user/pbr.rst
lib/pbr.h
pbrd/pbr_map.c
pbrd/pbr_map.h
pbrd/pbr_vty.c
pbrd/pbr_zebra.c
zebra/zapi_msg.c
zebra/zebra_dplane.c

index e59ed10896a0f8433ed982dda23ceb7e85caad9e..29567bb709f6a989e06a74c8f5f60f622f68689a 100644 (file)
@@ -154,6 +154,31 @@ end destination.
    (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
index cef1d9d380a44cf2632ed1e880ef0a7120ea2de9..b14ba07503bbb41d0e33449bc792821a69751f10 100644 (file)
--- a/lib/pbr.h
+++ b/lib/pbr.h
@@ -50,7 +50,7 @@ struct pbr_filter {
 #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 */
@@ -83,6 +83,13 @@ struct pbr_filter {
  * 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;
 };
 
index 053b7363a30964ff0b49aaa9f5fa320b90cf2c00..03e6bacf1e4967cabfd4229089ccc1b8912cbdcf 100644 (file)
@@ -178,9 +178,9 @@ static void pbr_map_pbrms_uninstall(struct pbr_map_sequence *pbrms)
 }
 
 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)
@@ -539,6 +539,13 @@ struct pbr_map_sequence *pbrms_get(const char *name, uint32_t seqno)
                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;
@@ -601,10 +608,28 @@ pbr_map_sequence_check_nexthops_valid(struct pbr_map_sequence *pbrms)
 
 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.
@@ -612,7 +637,7 @@ static void pbr_map_sequence_check_not_empty(struct pbr_map_sequence *pbrms)
 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);
 }
 
index 694b915f484de2297d469abddcc98a5a68aac09c..3527523fc16243dfd6eb2c4c210999d44f4283db 100644 (file)
@@ -103,6 +103,17 @@ struct pbr_map_sequence {
        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
         */
@@ -158,6 +169,7 @@ struct pbr_map_sequence {
 #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;
index d083b9d2b0f4c282bbb64c268832dbeb13a5dbb5..8a4132642de7171b693626ffbe318fc82b7c9bee 100644 (file)
@@ -407,6 +407,82 @@ static void pbrms_clear_set_config(struct pbr_map_sequence *pbrms)
        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"
@@ -764,6 +840,18 @@ static void vty_show_pbrms(struct vty *vty,
        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);
 
@@ -1170,6 +1258,19 @@ static int pbr_vty_map_config_write_sequence(struct vty *vty,
        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");
 
@@ -1257,6 +1358,10 @@ void pbr_vty_init(void)
        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);
index 28def509d5eb518c626bb8aeb829edab8cbbdec7..47d82950e7edfcaeb32fad4c07e82af9a1e0f789 100644 (file)
@@ -542,6 +542,12 @@ static void pbr_encode_pbr_map_sequence(struct stream *s,
        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)
index 496849251a4a394aa1e4d7a5c7593bf6882eab4f..b125897fc45d8eeabb24464ef9c0b6f612a3910c 100644 (file)
@@ -3198,6 +3198,12 @@ static inline void zread_rule(ZAPI_HANDLER_ARGS)
                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);
 
index ab06ea643807acd9664e7bf5a6947a8f808972f8..9e9844390d0fae039ae1d688565035cbde675d60 100644 (file)
@@ -261,6 +261,13 @@ struct dplane_ctx_rule {
        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];
 };
 
@@ -2770,6 +2777,12 @@ static void dplane_ctx_rule_init_single(struct dplane_ctx_rule *dplane_rule,
        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);
 }