]> git.puffer.fish Git - mirror/frr.git/commitdiff
pbrd: add packet mangling actions (src/dst ip-addr/port, dscp, ecn) 14126/head
authorG. Paul Ziemba <paulz@labn.net>
Tue, 1 Aug 2023 18:00:52 +0000 (11:00 -0700)
committerG. Paul Ziemba <paulz@labn.net>
Wed, 9 Aug 2023 19:11:43 +0000 (12:11 -0700)
Signed-off-by: G. Paul Ziemba <paulz@labn.net>
doc/user/pbr.rst
lib/pbr.h
lib/zclient.c
pbrd/pbr_map.c
pbrd/pbr_map.h
pbrd/pbr_vty.c
pbrd/pbr_zebra.c
tests/topotests/pbr_topo1/test_pbr_topo1.py
zebra/zebra_pbr.c

index 4d90f5cb6f91a6b45af421c2af7cd0bc33fa1fc3..d0513018e33c1e7d8b28b55e00843c209021d275 100644 (file)
@@ -215,6 +215,58 @@ specified in the rule are also applied to the packet.
    so this field will be ignored unless another dataplane provider is used.
    It is invalid to specify both a `strip` and `set vlan` action.
 
+.. clicmd:: set src-ip [A.B.C.D/M|X:X::X:X/M]
+
+   Action:
+   Set the source IP address of matched packets, possibly using a mask `M`.
+   The Linux Kernel dataplane provider does not currently support
+   packet mangling,
+   so this field will be ignored unless another dataplane provider is used.
+
+.. clicmd:: set dst-ip [A.B.C.D/M|X:X::X:X/M]
+
+   Action:
+   set the destination IP address of matched packets, possibly using a mask
+   `M`.
+   The Linux Kernel dataplane provider does not currently support
+   packet mangling,
+   so this field will be ignored unless another dataplane provider is used.
+
+.. clicmd:: set src-port (1-65535)
+
+   Action:
+   set the source port of matched packets. Note that this action only makes
+   sense with layer 4 protocols that use ports, such as TCP, UDP, and SCTP.
+   The Linux Kernel dataplane provider does not currently support
+   packet mangling,
+   so this field will be ignored unless another dataplane provider is used.
+
+.. clicmd:: set dst-port (1-65535)
+
+   Action:
+   set the destination port of matched packets. Note that this action only
+   makes sense with layer 4 protocols that use ports, such as TCP, UDP, and
+   SCTP.
+   The Linux Kernel dataplane provider does not currently support
+   packet mangling,
+   so this field will be ignored unless another dataplane provider is used.
+
+.. clicmd:: set dscp DSCP
+
+   Action:
+   set the differentiated services code point (DSCP) of matched packets.
+   The Linux Kernel dataplane provider does not currently support
+   this action,
+   so this field will be ignored unless another dataplane provider is used.
+
+.. clicmd:: set ecn (0-3)
+
+   Action:
+   set the explicit congestion notification (ECN) of matched packets.
+   The Linux Kernel dataplane provider does not currently support
+   this action,
+   so this field will be ignored unless another dataplane provider is used.
+
 .. clicmd:: show pbr map [NAME] [detail|json]
 
    Display pbr maps either all or by ``NAME``. If ``detail`` is set, it will
index ae01ae7978714a88d4f25c323d2e247dc3d2e4b9..c514cc2a65215843a38feaaf90aa7ce148d11f16 100644 (file)
--- a/lib/pbr.h
+++ b/lib/pbr.h
@@ -93,6 +93,12 @@ struct pbr_action {
 #define PBR_ACTION_PCP                 (1 << 2)
 #define PBR_ACTION_VLAN_ID             (1 << 3)
 #define PBR_ACTION_VLAN_STRIP_INNER_ANY (1 << 4)
+#define PBR_ACTION_SRC_IP              (1 << 5)
+#define PBR_ACTION_DST_IP              (1 << 6)
+#define PBR_ACTION_SRC_PORT            (1 << 7)
+#define PBR_ACTION_DST_PORT            (1 << 8)
+#define PBR_ACTION_DSCP                        (1 << 9)
+#define PBR_ACTION_ECN                 (1 << 10)
 
        uint32_t table;
        uint32_t queue_id;
@@ -101,7 +107,17 @@ struct pbr_action {
        uint8_t pcp;
        uint16_t vlan_id;
 
+       /* Source and Destination IP addresses */
+       union sockunion src_ip;
+       union sockunion dst_ip;
 
+       /* Source and Destination layer 4 (TCP/UDP/etc.) port numbers */
+       uint32_t src_port;
+       uint32_t dst_port;
+
+       /* Differentiated Services field  */
+       uint8_t dscp; /* stored here already shifted to upper 6 bits */
+       uint8_t ecn;  /* stored here as lower 2 bits */
 };
 
 /*
index 97c829c90d8aafb88ac7517b8014833fc2e256d5..e40725826ad5786c2a8c69586b9cc51a6bf62175 100644 (file)
@@ -1622,6 +1622,47 @@ stream_failure:
        return false;
 }
 
+static void zapi_encode_sockunion(struct stream *s, const union sockunion *su)
+{
+       int family = sockunion_family(su);
+       size_t addrlen = family2addrsize(family);
+
+       /*
+        * Must know length to encode
+        */
+       assert(addrlen);
+
+       stream_putc(s, (uint8_t)family);
+
+       stream_write(s, sockunion_get_addr(su), addrlen);
+}
+
+static bool zapi_decode_sockunion(struct stream *s, union sockunion *su)
+{
+       uint8_t family;
+       size_t addrlen;
+       uint8_t buf[sizeof(union sockunion)];
+
+       memset(su, 0, sizeof(*su));
+
+       STREAM_GETC(s, family);
+       sockunion_family(su) = family;
+
+       addrlen = family2addrsize(family);
+       if (!addrlen)
+               return false;
+
+       if (addrlen > sizeof(buf))
+               return false;
+
+       STREAM_GET(buf, s, addrlen);
+       sockunion_set(su, family, buf, addrlen);
+       return true;
+
+stream_failure:
+       return false;
+}
+
 /*
  * Encode filter subsection of pbr_rule
  */
@@ -1719,6 +1760,21 @@ static void zapi_pbr_rule_action_encode(struct stream *s, struct pbr_action *a)
        if (CHECK_FLAG(a->flags, PBR_ACTION_QUEUE_ID))
                stream_putl(s, a->queue_id);
 
+       /* L3 */
+       if (CHECK_FLAG(a->flags, PBR_ACTION_SRC_IP))
+               zapi_encode_sockunion(s, &a->src_ip);
+       if (CHECK_FLAG(a->flags, PBR_ACTION_DST_IP))
+               zapi_encode_sockunion(s, &a->dst_ip);
+       if (CHECK_FLAG(a->flags, PBR_ACTION_SRC_PORT))
+               stream_putw(s, a->src_port);
+       if (CHECK_FLAG(a->flags, PBR_ACTION_DST_PORT))
+               stream_putw(s, a->dst_port);
+
+       if (CHECK_FLAG(a->flags, PBR_ACTION_DSCP))
+               stream_putc(s, a->dscp & PBR_DSFIELD_DSCP);
+       if (CHECK_FLAG(a->flags, PBR_ACTION_ECN))
+               stream_putc(s, a->ecn & PBR_DSFIELD_ECN);
+
        /* L2 */
        if (CHECK_FLAG(a->flags, PBR_ACTION_PCP))
                stream_putc(s, a->pcp);
@@ -1735,6 +1791,29 @@ static bool zapi_pbr_rule_action_decode(struct stream *s, struct pbr_action *a)
        if (CHECK_FLAG(a->flags, PBR_ACTION_QUEUE_ID))
                STREAM_GETL(s, a->queue_id);
 
+       /* L3 */
+       if (CHECK_FLAG(a->flags, PBR_ACTION_SRC_IP)) {
+               if (!zapi_decode_sockunion(s, &(a->src_ip)))
+                       goto stream_failure;
+       }
+       if (CHECK_FLAG(a->flags, PBR_ACTION_DST_IP))
+               if (!zapi_decode_sockunion(s, &(a->dst_ip)))
+                       goto stream_failure;
+
+       if (CHECK_FLAG(a->flags, PBR_ACTION_SRC_PORT))
+               STREAM_GETW(s, a->src_port);
+       if (CHECK_FLAG(a->flags, PBR_ACTION_DST_PORT))
+               STREAM_GETW(s, a->dst_port);
+
+       if (CHECK_FLAG(a->flags, PBR_ACTION_DSCP)) {
+               STREAM_GETC(s, a->dscp);
+               a->dscp &= PBR_DSFIELD_DSCP;
+       }
+       if (CHECK_FLAG(a->flags, PBR_ACTION_ECN)) {
+               STREAM_GETC(s, a->ecn);
+               a->ecn &= PBR_DSFIELD_ECN;
+       }
+
        /* L2 */
        if (CHECK_FLAG(a->flags, PBR_ACTION_PCP))
                STREAM_GETC(s, a->pcp);
index 30148fe0931ef171bf45abb3b211b0c2cae521e4..6b81e1058e424bf80c8f7314f13f43a737bc80ca 100644 (file)
@@ -612,6 +612,13 @@ static void pbr_map_sequence_check_not_empty(struct pbr_map_sequence *pbrms)
                        PBR_FILTER_VLAN_FLAGS
                )) &&
                !CHECK_FLAG(pbrms->action_bm, (
+                       PBR_ACTION_SRC_IP |
+                       PBR_ACTION_DST_IP |
+                       PBR_ACTION_SRC_PORT |
+                       PBR_ACTION_DST_PORT |
+
+                       PBR_ACTION_DSCP |
+                       PBR_ACTION_ECN |
 
                        PBR_ACTION_PCP |
                        PBR_ACTION_VLAN_ID |
index 700bc93f724f4af8275a37a4d33ffe7d6de4e6d1..61577e40769bda6e48a2c42d4fac3a48e18b2b9b 100644 (file)
@@ -124,6 +124,15 @@ struct pbr_map_sequence {
         */
        uint32_t action_bm;
 
+       union sockunion action_src;
+       union sockunion action_dst;
+
+       uint16_t action_src_port;
+       uint16_t action_dst_port;
+
+       uint8_t action_dscp;
+       uint8_t action_ecn;
+
        uint8_t action_pcp;
        uint8_t action_vlan_id;
 
index 0d8fa6939aa4a0816528c49081d691bf681de4cf..0d6e1afd5b054e91a0cc0459b2a66176baf1c87e 100644 (file)
@@ -183,6 +183,7 @@ static bool pbr_family_consistent(struct pbr_map_sequence *pbrms,
                                  uint32_t skip_action_bm, const char **msg)
 {
        uint32_t filter_bm = pbrms->filter_bm & ~skip_filter_bm;
+       uint32_t action_bm = pbrms->action_bm & ~skip_action_bm;
 
        if (CHECK_FLAG(filter_bm, PBR_FILTER_SRC_IP) &&
            (family != pbrms->src->family)) {
@@ -196,6 +197,18 @@ static bool pbr_family_consistent(struct pbr_map_sequence *pbrms,
                        *msg = "match dst-ip";
                return false;
        }
+       if (CHECK_FLAG(action_bm, PBR_ACTION_SRC_IP) &&
+           (family != sockunion_family(&pbrms->action_src))) {
+               if (msg)
+                       *msg = "set src-ip";
+               return false;
+       }
+       if (CHECK_FLAG(filter_bm, PBR_ACTION_DST_IP) &&
+           (family != sockunion_family(&pbrms->action_dst))) {
+               if (msg)
+                       *msg = "set dst-ip";
+               return false;
+       }
        return true;
 }
 
@@ -206,7 +219,7 @@ DEFPY  (pbr_map_match_src,
        "[no] match src-ip ![<A.B.C.D/M|X:X::X:X/M>$prefix]",
        NO_STR
        "Match the rest of the command\n"
-       "Choose the src ip or ipv6 prefix to use\n"
+       "Choose the src ipv4 or ipv6 prefix to use\n"
        "v4 Prefix\n"
        "v6 Prefix\n")
 {
@@ -254,7 +267,7 @@ DEFPY  (pbr_map_match_dst,
        "[no] match dst-ip ![<A.B.C.D/M|X:X::X:X/M>$prefix]",
        NO_STR
        "Match the rest of the command\n"
-       "Choose the dst ip or ipv6 prefix to use\n"
+       "Choose the dst ipv4 or ipv6 prefix to use\n"
        "v4 Prefix\n"
        "v6 Prefix\n")
 {
@@ -673,6 +686,237 @@ check:
        return CMD_SUCCESS;
 }
 
+/***********************************************************************
+ *             pbrms/rule Action Set L3 Fields
+ ***********************************************************************/
+
+/* clang-format off */
+DEFPY  (pbr_map_action_src,
+       pbr_map_action_src_cmd,
+       "[no] set src-ip ![<A.B.C.D|X:X::X:X>$su]",
+       NO_STR
+       "Set command\n"
+       "Set the src ipv4 or ipv6 prefix\n"
+       "v4 Prefix\n"
+       "v6 Prefix\n")
+{
+       /* clang-format on */
+       struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
+       const char *fmsg = NULL;
+
+       if (!pbrms)
+               return CMD_WARNING_CONFIG_FAILED;
+
+       if (no) {
+               if (!CHECK_FLAG(pbrms->action_bm, PBR_ACTION_SRC_IP))
+                       return CMD_SUCCESS;
+               UNSET_FLAG(pbrms->action_bm, PBR_ACTION_SRC_IP);
+               goto check;
+       }
+
+       assert(su);
+       if (!pbr_family_consistent(pbrms, sockunion_family(su),
+                                  PBR_ACTION_SRC_IP, 0, &fmsg)) {
+               vty_out(vty, "Address family mismatch (%s)\n", fmsg);
+               return CMD_WARNING_CONFIG_FAILED;
+       }
+       pbrms->family = sockunion_family(su);
+
+       if (CHECK_FLAG(pbrms->action_bm, PBR_ACTION_SRC_IP) &&
+           (sockunion_same(&pbrms->action_src, su))) {
+               return CMD_SUCCESS;
+       }
+       pbrms->action_src = *su;
+       SET_FLAG(pbrms->action_bm, PBR_ACTION_SRC_IP);
+
+check:
+       pbr_map_check(pbrms, true);
+       return CMD_SUCCESS;
+}
+
+/* clang-format off */
+DEFPY  (pbr_map_action_dst,
+       pbr_map_action_dst_cmd,
+       "[no] set dst-ip ![<A.B.C.D|X:X::X:X>$su]",
+       NO_STR
+       "Set command\n"
+       "Set the dst ipv4 or ipv6 prefix\n"
+       "v4 Prefix\n"
+       "v6 Prefix\n")
+{
+       /* clang-format on */
+       struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
+       const char *fmsg = NULL;
+
+       if (!pbrms)
+               return CMD_WARNING_CONFIG_FAILED;
+
+       if (no) {
+               if (!CHECK_FLAG(pbrms->action_bm, PBR_ACTION_DST_IP))
+                       return CMD_SUCCESS;
+               UNSET_FLAG(pbrms->action_bm, PBR_ACTION_DST_IP);
+               goto check;
+       }
+
+       assert(su);
+       if (!pbr_family_consistent(pbrms, sockunion_family(su),
+                                  PBR_ACTION_DST_IP, 0, &fmsg)) {
+               vty_out(vty, "Address family mismatch (%s)\n", fmsg);
+               return CMD_WARNING_CONFIG_FAILED;
+       }
+       pbrms->family = sockunion_family(su);
+
+       if (CHECK_FLAG(pbrms->action_bm, PBR_ACTION_DST_IP) &&
+           (sockunion_same(&pbrms->action_dst, su))) {
+               return CMD_SUCCESS;
+       }
+       pbrms->action_dst = *su;
+       SET_FLAG(pbrms->action_bm, PBR_ACTION_DST_IP);
+
+check:
+       pbr_map_check(pbrms, true);
+       return CMD_SUCCESS;
+}
+
+/* clang-format off */
+DEFPY  (pbr_map_action_src_port,
+       pbr_map_action_src_port_cmd,
+       "[no] set src-port ![(1-65535)$port]",
+       NO_STR
+       "Set command\n"
+       "Set Source Port\n"
+       "The Source Port\n")
+{
+       /* clang-format on */
+       struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
+
+       if (no) {
+               if (!CHECK_FLAG(pbrms->action_bm, PBR_ACTION_SRC_PORT))
+                       return CMD_SUCCESS;
+               UNSET_FLAG(pbrms->action_bm, PBR_ACTION_SRC_PORT);
+               goto check;
+       }
+
+       if (CHECK_FLAG(pbrms->action_bm, PBR_ACTION_SRC_PORT) &&
+           (pbrms->action_src_port == port))
+               return CMD_SUCCESS;
+
+       pbrms->action_src_port = port;
+       SET_FLAG(pbrms->action_bm, PBR_ACTION_SRC_PORT);
+
+check:
+       pbr_map_check(pbrms, true);
+       return CMD_SUCCESS;
+}
+
+/* clang-format off */
+DEFPY  (pbr_map_action_dst_port,
+       pbr_map_action_dst_port_cmd,
+       "[no] set dst-port ![(1-65535)$port]",
+       NO_STR
+       "Set command\n"
+       "Set Destination Port\n"
+       "The Destination Port\n")
+{
+       /* clang-format on */
+       struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
+
+       if (no) {
+               if (!CHECK_FLAG(pbrms->action_bm, PBR_ACTION_DST_PORT))
+                       return CMD_SUCCESS;
+               UNSET_FLAG(pbrms->action_bm, PBR_ACTION_DST_PORT);
+               goto check;
+       }
+       if (CHECK_FLAG(pbrms->action_bm, PBR_ACTION_DST_PORT) &&
+           (pbrms->action_dst_port == port))
+               return CMD_SUCCESS;
+
+       SET_FLAG(pbrms->action_bm, PBR_ACTION_DST_PORT);
+       pbrms->action_dst_port = port;
+
+check:
+       pbr_map_check(pbrms, true);
+       return CMD_SUCCESS;
+}
+
+/* clang-format off */
+DEFPY  (pbr_map_action_dscp,
+       pbr_map_action_dscp_cmd,
+       "[no] set dscp ![DSCP$dscp]",
+       NO_STR
+       "Set command\n"
+       "Set IP DSCP field\n"
+       "DSCP numeric value (0-63) or standard codepoint name\n")
+{
+       /* clang-format on */
+       struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
+
+       if (no) {
+               if (!CHECK_FLAG(pbrms->action_bm, PBR_ACTION_DSCP))
+                       return CMD_SUCCESS;
+               UNSET_FLAG(pbrms->action_bm, PBR_ACTION_DSCP);
+               goto check;
+       }
+
+       unsigned long ul_dscp;
+       char *pend;
+       uint8_t raw_dscp;
+
+       assert(dscp);
+       ul_dscp = strtol(dscp, &pend, 0);
+       if (*pend)
+               raw_dscp = pbr_map_decode_dscp_enum(dscp);
+       else
+               raw_dscp = ul_dscp << 2;
+
+       if (raw_dscp > PBR_DSFIELD_DSCP) {
+               vty_out(vty, "Invalid dscp value: %s%s\n", dscp,
+                       (pend ? "" : " (numeric value must be in range 0-63)"));
+               return CMD_WARNING_CONFIG_FAILED;
+       }
+       if (CHECK_FLAG(pbrms->action_bm, PBR_ACTION_DSCP) &&
+           (pbrms->action_dscp == raw_dscp)) {
+               return CMD_SUCCESS;
+       }
+       SET_FLAG(pbrms->action_bm, PBR_ACTION_DSCP);
+       pbrms->action_dscp = raw_dscp;
+
+check:
+       pbr_map_check(pbrms, true);
+       return CMD_SUCCESS;
+}
+
+/* clang-format off */
+DEFPY  (pbr_map_action_ecn,
+       pbr_map_action_ecn_cmd,
+       "[no] set ecn ![(0-3)$ecn]",
+       NO_STR
+       "Set command\n"
+       "Set IP ECN field\n"
+       "Explicit Congestion Notification value\n")
+{
+       /* clang-format on */
+       struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
+
+       if (no) {
+               if (!CHECK_FLAG(pbrms->action_bm, PBR_ACTION_ECN))
+                       return CMD_SUCCESS;
+               UNSET_FLAG(pbrms->action_bm, PBR_ACTION_ECN);
+               goto check;
+       }
+       if (CHECK_FLAG(pbrms->action_bm, PBR_ACTION_ECN) &&
+           (pbrms->action_ecn == ecn)) {
+               return CMD_SUCCESS;
+       }
+       SET_FLAG(pbrms->action_bm, PBR_ACTION_ECN);
+       pbrms->action_ecn = ecn;
+
+check:
+       pbr_map_check(pbrms, true);
+       return CMD_SUCCESS;
+}
+
+
 /***********************************************************************
  *             pbrms/rule Action Set Meta
  ***********************************************************************/
@@ -1308,10 +1552,22 @@ static void vty_show_pbrms(struct vty *vty,
 
        /* set actions */
 
+       if (CHECK_FLAG(pbrms->action_bm, PBR_ACTION_SRC_IP))
+               vty_out(vty, "        Set SRC IP: %pSU\n", &pbrms->action_src);
+       if (CHECK_FLAG(pbrms->action_bm, PBR_ACTION_DST_IP))
+               vty_out(vty, "        Set DST IP: %pSU\n", &pbrms->action_dst);
 
-       if (CHECK_FLAG(pbrms->action_bm, PBR_ACTION_QUEUE_ID))
-               vty_out(vty, "        Set Queue ID: %u\n",
-                       pbrms->action_queue_id);
+       if (CHECK_FLAG(pbrms->action_bm, PBR_ACTION_SRC_PORT))
+               vty_out(vty, "        Set Src port: %u\n",
+                       pbrms->action_src_port);
+       if (CHECK_FLAG(pbrms->action_bm, PBR_ACTION_DST_PORT))
+               vty_out(vty, "        Set Dst port: %u\n",
+                       pbrms->action_dst_port);
+
+       if (CHECK_FLAG(pbrms->action_bm, PBR_ACTION_DSCP))
+               vty_out(vty, "        Set DSCP: %u\n", (pbrms->action_dscp) >> 2);
+       if (CHECK_FLAG(pbrms->action_bm, PBR_ACTION_ECN))
+               vty_out(vty, "        Set ECN: %u\n", pbrms->action_ecn);
 
        if (CHECK_FLAG(pbrms->action_bm, PBR_ACTION_VLAN_ID))
                vty_out(vty, "        Set VLAN ID %u\n", pbrms->action_vlan_id);
@@ -1320,6 +1576,10 @@ static void vty_show_pbrms(struct vty *vty,
        if (CHECK_FLAG(pbrms->action_bm, PBR_ACTION_PCP))
                vty_out(vty, "        Set PCP %u\n", pbrms->action_pcp);
 
+       if (CHECK_FLAG(pbrms->action_bm, PBR_ACTION_QUEUE_ID))
+               vty_out(vty, "        Set Queue ID: %u\n",
+                       pbrms->action_queue_id);
+
 
        switch (pbrms->forwarding_type) {
        case PBR_FT_UNSPEC:
@@ -1467,6 +1727,25 @@ static void vty_json_pbrms(json_object *j, struct vty *vty,
         * action clauses
         */
 
+       /* IP header fields */
+       if (CHECK_FLAG(pbrms->action_bm, PBR_ACTION_SRC_IP))
+               json_object_string_addf(jpbrm, "actionSetSrcIpAddr", "%pSU",
+                                       &pbrms->action_src);
+       if (CHECK_FLAG(pbrms->action_bm, PBR_ACTION_DST_IP))
+               json_object_string_addf(jpbrm, "actionSetDstIpAddr", "%pSU",
+                                       &pbrms->action_dst);
+
+       if (CHECK_FLAG(pbrms->action_bm, PBR_ACTION_SRC_PORT))
+               json_object_int_add(jpbrm, "actionSetSrcPort",
+                                   pbrms->action_src_port);
+       if (CHECK_FLAG(pbrms->action_bm, PBR_ACTION_DST_PORT))
+               json_object_int_add(jpbrm, "actionSetDstPort",
+                                   pbrms->action_dst_port);
+       if (CHECK_FLAG(pbrms->action_bm, PBR_ACTION_DSCP))
+               json_object_int_add(jpbrm, "actionSetDscp",
+                                   pbrms->action_dscp >> 2);
+       if (CHECK_FLAG(pbrms->action_bm, PBR_ACTION_ECN))
+               json_object_int_add(jpbrm, "actionSetEcn", pbrms->action_ecn);
 
        /* L2 header fields */
        if (CHECK_FLAG(pbrms->action_bm, PBR_ACTION_VLAN_STRIP_INNER_ANY))
@@ -1796,6 +2075,19 @@ static int pbr_vty_map_config_write_sequence(struct vty *vty,
         * action clauses
         */
 
+       if (CHECK_FLAG(pbrms->action_bm, PBR_ACTION_SRC_IP))
+               vty_out(vty, " set src-ip %pSU\n", &pbrms->action_src);
+       if (CHECK_FLAG(pbrms->action_bm, PBR_ACTION_DST_IP))
+               vty_out(vty, " set dst-ip %pSU\n", &pbrms->action_dst);
+       if (CHECK_FLAG(pbrms->action_bm, PBR_ACTION_SRC_PORT))
+               vty_out(vty, " set src-port %d\n", pbrms->action_src_port);
+       if (CHECK_FLAG(pbrms->action_bm, PBR_ACTION_DST_PORT))
+               vty_out(vty, " set dst-port %d\n", pbrms->action_dst_port);
+       if (CHECK_FLAG(pbrms->action_bm, PBR_ACTION_DSCP))
+               vty_out(vty, " set dscp %u\n", (pbrms->action_dscp) >> 2);
+       if (CHECK_FLAG(pbrms->action_bm, PBR_ACTION_ECN))
+               vty_out(vty, " set ecn %u\n", pbrms->action_ecn);
+
        /* L2 header fields */
        if (CHECK_FLAG(pbrms->action_bm, PBR_ACTION_VLAN_STRIP_INNER_ANY))
                vty_out(vty, " strip vlan any\n");
@@ -1906,10 +2198,18 @@ void pbr_vty_init(void)
        install_element(PBRMAP_NODE, &pbr_map_match_vlan_tag_cmd);
        install_element(PBRMAP_NODE, &pbr_map_match_pcp_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_action_src_cmd);
+       install_element(PBRMAP_NODE, &pbr_map_action_dst_cmd);
+       install_element(PBRMAP_NODE, &pbr_map_action_dscp_cmd);
+       install_element(PBRMAP_NODE, &pbr_map_action_ecn_cmd);
+       install_element(PBRMAP_NODE, &pbr_map_action_src_port_cmd);
+       install_element(PBRMAP_NODE, &pbr_map_action_dst_port_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 66148c630dd22205f08bd2c585fb4f7917b1a353..35c771469c1979508e48a2ecee9b6aee2cfe4fa7 100644 (file)
@@ -594,6 +594,15 @@ static bool pbr_encode_pbr_map_sequence(struct stream *s,
 
        r.action.queue_id = pbrms->action_queue_id;
 
+       r.action.src_ip = pbrms->action_src;
+       r.action.dst_ip = pbrms->action_dst;
+
+       r.action.src_port = pbrms->action_src_port;
+       r.action.dst_port = pbrms->action_dst_port;
+
+       r.action.dscp = pbrms->action_dscp;
+       r.action.ecn = pbrms->action_ecn;
+
        r.action.pcp = pbrms->action_pcp;
        r.action.vlan_id = pbrms->action_vlan_id;
 
index ad096fa14eae041ef45d580aa0a56f6cf8c7e510..2b437170ff5eb96d0cb5242be2cf906195a6f00e 100644 (file)
@@ -201,27 +201,38 @@ ftest = [
     {"c": "match vlan untagged", "tm": r"VLAN Flags Match: untagged$"},
     {"c": "match vlan untagged-or-zero", "tm": r"VLAN Flags Match: untagged-or-zero$"},
     {"c": "no match vlan tagged", "tN": r"VLAN Flags Match:"},
-
     {"c": "match src-ip 37.49.22.0/24", "tm": r"SRC IP Match: 37.49.22.0/24$"},
     {"c": "no match src-ip 37.49.22.0/24", "tN": r"SRC IP Match: 37.49.22.0/24$"},
-
-    {"c": "match dst-ip 38.41.29.0/25", "cDN": "foo", "tm": r"DST IP Match: 38.41.29.0/25$"},
+    {
+        "c": "match dst-ip 38.41.29.0/25",
+        "cDN": "foo",
+        "tm": r"DST IP Match: 38.41.29.0/25$",
+    },
     {"c": "no match dst-ip 38.41.29.0/25", "tN": r"DST IP Match: 38.41.29.0/25$"},
-
     {"c": "match src-port 117", "tm": r"SRC Port Match: 117$"},
     {"c": "no match src-port 117", "tN": r"SRC Port Match: 117$"},
-
     {"c": "match dst-port 119", "tm": r"DST Port Match: 119$"},
     {"c": "no match dst-port 119", "tN": r"DST Port Match: 119$"},
-
     {"c": "match dscp cs3", "tm": r"DSCP Match: 24$"},
     {"c": "no match dscp cs3", "tN": r"DSCP Match: 24$"},
-
     {"c": "match ecn 2", "tm": r"ECN Match: 2$"},
     {"c": "no match ecn 2", "tN": r"ECN Match: 2$"},
-
     {"c": "match mark 337", "tm": r"MARK Match: 337$"},
     {"c": "no match mark 337", "tN": r"MARK Match: 337$"},
+    {"c": "set src-ip 44.100.1.1", "tm": r"Set SRC IP: 44.100.1.1$"},
+    {"c": "no set src-ip 44.100.1.1", "tN": r"Set SRC IP: 44.100.1.1$"},
+    {"c": "set dst-ip 44.105.1.1", "tm": r"Set DST IP: 44.105.1.1$"},
+    {"c": "no set dst-ip 44.105.1.1", "tN": r"Set DST IP: 44.105.1.1$"},
+    {"c": "set src-port 41", "tm": r"Set SRC PORT: 41$"},
+    {"c": "no set src-port 41", "tN": r"Set SRC PORT: 41$"},
+    {"c": "set dst-port 43", "tm": r"Set DST PORT: 43$"},
+    {"c": "no set dst-port 43", "tN": r"Set DST PORT: 43$"},
+    {"c": "set dscp 24", "tm": r"Set DSCP: 24$"},
+    {"c": "no set dscp 24", "tN": r"Set DSCP: 24$"},
+    {"c": "set dscp cs7", "tm": r"Set DSCP: 14$"},
+    {"c": "no set dscp cs7", "tN": r"Set DSCP: 14$"},
+    {"c": "set ecn 1", "tm": r"Set ECN: 1$"},
+    {"c": "no set ecn 1", "tN": r"Set ECN: 1$"},
 ]
 
 
index 7560071e59fd4d021f8450f70909098db476593b..5124768a7c50e4ebf4111a9db07dc61271559d62 100644 (file)
@@ -507,6 +507,7 @@ void zebra_pbr_show_rule_unit(struct zebra_pbr_rule *rule, struct vty *vty)
 {
        struct pbr_rule *prule = &rule->rule;
        struct zebra_pbr_action *zaction = &rule->action;
+       struct pbr_action *pa = &prule->action;
 
        vty_out(vty, "Rules if %s\n", rule->ifname);
        vty_out(vty, "  Seq %u pri %u\n", prule->seq, prule->priority);
@@ -548,6 +549,30 @@ void zebra_pbr_show_rule_unit(struct zebra_pbr_rule *rule, struct vty *vty)
                vty_out(vty, "\n");
        }
 
+       if (CHECK_FLAG(pa->flags, PBR_ACTION_ECN))
+               vty_out(vty, "  Action: Set ECN: %u\n", pa->ecn);
+       if (CHECK_FLAG(pa->flags, PBR_ACTION_DSCP))
+               vty_out(vty, "  Action: Set DSCP: %u\n", pa->dscp >> 2);
+
+       if (CHECK_FLAG(pa->flags, PBR_ACTION_SRC_IP))
+               vty_out(vty, "  Action: Set SRC IP: %pSU\n", &pa->src_ip);
+       if (CHECK_FLAG(pa->flags, PBR_ACTION_DST_IP))
+               vty_out(vty, "  Action: Set DST IP: %pSU\n", &pa->dst_ip);
+       if (CHECK_FLAG(pa->flags, PBR_ACTION_SRC_PORT))
+               vty_out(vty, "  Action: Set SRC PORT: %u\n", pa->src_port);
+       if (CHECK_FLAG(pa->flags, PBR_ACTION_DST_PORT))
+               vty_out(vty, "  Action: Set DST PORT: %u\n", pa->dst_port);
+
+       if (CHECK_FLAG(pa->flags, PBR_ACTION_QUEUE_ID))
+               vty_out(vty, "  Action: Set Queue ID: %u\n", pa->queue_id);
+
+       if (CHECK_FLAG(pa->flags, PBR_ACTION_PCP))
+               vty_out(vty, "  Action: Set PCP: %u\n", pa->pcp);
+       if (CHECK_FLAG(pa->flags, PBR_ACTION_VLAN_ID))
+               vty_out(vty, "  Action: Set VLAN ID: %u\n", pa->vlan_id);
+       if (CHECK_FLAG(pa->flags, PBR_ACTION_VLAN_STRIP_INNER_ANY))
+               vty_out(vty, "  Action: Strip VLAN ID\n");
+
        vty_out(vty, "  Tableid: %u\n", prule->action.table);
        if (zaction->afi == AFI_IP)
                vty_out(vty, "  Action: nh: %pI4 intf: %s\n",