diff options
| author | G. Paul Ziemba <paulz@labn.net> | 2023-08-01 11:00:52 -0700 |
|---|---|---|
| committer | G. Paul Ziemba <paulz@labn.net> | 2023-08-09 12:11:43 -0700 |
| commit | ba240bcfa3762158eaa548906ba9c306d96fe5d1 (patch) | |
| tree | c37a9c88c752ad6ec7ff215dd727856a2ed6e165 /pbrd | |
| parent | 887367a01c0e978e992935ae93f3df4e3c1bd86c (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.c | 7 | ||||
| -rw-r--r-- | pbrd/pbr_map.h | 9 | ||||
| -rw-r--r-- | pbrd/pbr_vty.c | 310 | ||||
| -rw-r--r-- | pbrd/pbr_zebra.c | 9 |
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; |
