summaryrefslogtreecommitdiff
path: root/pbrd
diff options
context:
space:
mode:
authorG. Paul Ziemba <paulz@labn.net>2023-08-01 11:00:52 -0700
committerG. Paul Ziemba <paulz@labn.net>2023-08-09 12:11:43 -0700
commitba240bcfa3762158eaa548906ba9c306d96fe5d1 (patch)
treec37a9c88c752ad6ec7ff215dd727856a2ed6e165 /pbrd
parent887367a01c0e978e992935ae93f3df4e3c1bd86c (diff)
pbrd: add packet mangling actions (src/dst ip-addr/port, dscp, ecn)
Signed-off-by: G. Paul Ziemba <paulz@labn.net>
Diffstat (limited to 'pbrd')
-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
4 files changed, 330 insertions, 5 deletions
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;