From: G. Paul Ziemba Date: Tue, 1 Aug 2023 18:00:52 +0000 (-0700) Subject: pbrd: add packet mangling actions (src/dst ip-addr/port, dscp, ecn) X-Git-Tag: base_9.1~162^2 X-Git-Url: https://git.puffer.fish/?a=commitdiff_plain;h=ba240bcfa3762158eaa548906ba9c306d96fe5d1;p=matthieu%2Ffrr.git pbrd: add packet mangling actions (src/dst ip-addr/port, dscp, ecn) Signed-off-by: G. Paul Ziemba --- 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 ![$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 ![$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 ![$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 ![$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",