summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/user/pbr.rst52
-rw-r--r--lib/pbr.h16
-rw-r--r--lib/zclient.c79
-rw-r--r--pbrd/pbr_map.c7
-rw-r--r--pbrd/pbr_map.h9
-rw-r--r--pbrd/pbr_vty.c310
-rw-r--r--pbrd/pbr_zebra.c9
-rw-r--r--tests/topotests/pbr_topo1/test_pbr_topo1.py27
-rw-r--r--zebra/zebra_pbr.c25
9 files changed, 521 insertions, 13 deletions
diff --git a/doc/user/pbr.rst b/doc/user/pbr.rst
index 4d90f5cb6f..d0513018e3 100644
--- a/doc/user/pbr.rst
+++ b/doc/user/pbr.rst
@@ -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
diff --git a/lib/pbr.h b/lib/pbr.h
index ae01ae7978..c514cc2a65 100644
--- 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 */
};
/*
diff --git a/lib/zclient.c b/lib/zclient.c
index 97c829c90d..e40725826a 100644
--- a/lib/zclient.c
+++ b/lib/zclient.c
@@ -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);
diff --git a/pbrd/pbr_map.c b/pbrd/pbr_map.c
index 30148fe093..6b81e1058e 100644
--- a/pbrd/pbr_map.c
+++ b/pbrd/pbr_map.c
@@ -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 |
diff --git a/pbrd/pbr_map.h b/pbrd/pbr_map.h
index 700bc93f72..61577e4076 100644
--- a/pbrd/pbr_map.h
+++ b/pbrd/pbr_map.h
@@ -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;
diff --git a/pbrd/pbr_vty.c b/pbrd/pbr_vty.c
index 0d8fa6939a..0d6e1afd5b 100644
--- a/pbrd/pbr_vty.c
+++ b/pbrd/pbr_vty.c
@@ -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")
{
@@ -674,6 +687,237 @@ check:
}
/***********************************************************************
+ * 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);
diff --git a/pbrd/pbr_zebra.c b/pbrd/pbr_zebra.c
index 66148c630d..35c771469c 100644
--- a/pbrd/pbr_zebra.c
+++ b/pbrd/pbr_zebra.c
@@ -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;
diff --git a/tests/topotests/pbr_topo1/test_pbr_topo1.py b/tests/topotests/pbr_topo1/test_pbr_topo1.py
index ad096fa14e..2b437170ff 100644
--- a/tests/topotests/pbr_topo1/test_pbr_topo1.py
+++ b/tests/topotests/pbr_topo1/test_pbr_topo1.py
@@ -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$"},
]
diff --git a/zebra/zebra_pbr.c b/zebra/zebra_pbr.c
index 7560071e59..5124768a7c 100644
--- a/zebra/zebra_pbr.c
+++ b/zebra/zebra_pbr.c
@@ -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",