diff options
author | G. Paul Ziemba <paulz@labn.net> | 2023-07-31 06:33:10 +0200 |
---|---|---|
committer | G. Paul Ziemba <paulz@labn.net> | 2023-08-09 21:11:35 +0200 |
commit | 887367a01c0e978e992935ae93f3df4e3c1bd86c (patch) | |
tree | 533826535f9359febf6b935fb6ee44b63121c63a /pbrd | |
parent | pbrd: add explicit 'family' field for rules (diff) | |
download | frr-887367a01c0e978e992935ae93f3df4e3c1bd86c.tar.xz frr-887367a01c0e978e992935ae93f3df4e3c1bd86c.zip |
pbrd: use flags to indicate active fields
Before now, PBRD used non-zero values to imply that a rule's
match or action field was active. This approach was getting
cumbersome for fields where 0 is a valid active value and
various field-specific magic values had to be used.
This commit changes PBRD to use a flag bit per field to
indicate that the field is active.
Signed-off-by: G. Paul Ziemba <paulz@labn.net>
Diffstat (limited to 'pbrd')
-rw-r--r-- | pbrd/pbr_map.c | 77 | ||||
-rw-r--r-- | pbrd/pbr_map.h | 26 | ||||
-rw-r--r-- | pbrd/pbr_nht.c | 2 | ||||
-rw-r--r-- | pbrd/pbr_vty.c | 802 | ||||
-rw-r--r-- | pbrd/pbr_zebra.c | 38 |
5 files changed, 602 insertions, 343 deletions
diff --git a/pbrd/pbr_map.c b/pbrd/pbr_map.c index 758e08b56..30148fe09 100644 --- a/pbrd/pbr_map.c +++ b/pbrd/pbr_map.c @@ -105,38 +105,6 @@ static bool pbrms_is_installed(const struct pbr_map_sequence *pbrms, return false; } -void pbr_set_match_clause_for_pcp(struct pbr_map_sequence *pbrms, bool set, - uint8_t pcp) -{ - bool changed = false; - - if (set) { - if (!CHECK_FLAG(pbrms->filter_bm, PBR_FILTER_PCP) || - (pcp != pbrms->match_pcp)) { - SET_FLAG(pbrms->filter_bm, PBR_FILTER_PCP); - pbrms->match_pcp = pcp; - changed = true; - } - } else { - if (CHECK_FLAG(pbrms->filter_bm, PBR_FILTER_PCP)) { - UNSET_FLAG(pbrms->filter_bm, PBR_FILTER_PCP); - changed = true; - } - } - if (changed) - pbr_map_check(pbrms, true); -} - -void pbr_set_match_clause_for_vlan(struct pbr_map_sequence *pbrms, - uint16_t vlan_id, uint16_t vlan_flags) -{ - if (pbrms) { - pbrms->match_vlan_id = vlan_id; - pbrms->match_vlan_flags = vlan_flags; - pbr_map_check(pbrms, true); - } -} - /* If any sequence is installed on the interface, assume installed */ static bool pbr_map_interface_is_installed(const struct pbr_map *pbrm, @@ -562,14 +530,6 @@ struct pbr_map_sequence *pbrms_get(const char *name, uint32_t seqno) pbrms->ruleno = pbr_nht_get_next_rule(seqno); pbrms->parent = pbrm; - pbrms->match_vlan_id = 0; - pbrms->match_vlan_flags = 0; - pbrms->match_pcp = 0; - - pbrms->action_vlan_id = 0; - pbrms->action_vlan_flags = 0; - pbrms->action_pcp = 0; - pbrms->action_queue_id = PBR_MAP_UNDEFINED_QUEUE_ID; pbrms->reason = @@ -634,13 +594,35 @@ pbr_map_sequence_check_nexthops_valid(struct pbr_map_sequence *pbrms) static void pbr_map_sequence_check_not_empty(struct pbr_map_sequence *pbrms) { - if (!pbrms->src && !pbrms->dst && !pbrms->mark && !pbrms->dsfield && - !CHECK_FLAG(pbrms->filter_bm, PBR_FILTER_PCP) && - !pbrms->action_pcp && !pbrms->match_vlan_id && - !pbrms->match_vlan_flags && !pbrms->action_vlan_id && - !pbrms->action_vlan_flags && - pbrms->action_queue_id == PBR_MAP_UNDEFINED_QUEUE_ID) + /* clang-format off */ + if ( + !CHECK_FLAG(pbrms->filter_bm, ( + PBR_FILTER_SRC_IP | + PBR_FILTER_DST_IP | + PBR_FILTER_SRC_PORT | + PBR_FILTER_DST_PORT | + + PBR_FILTER_IP_PROTOCOL | + PBR_FILTER_DSCP | + PBR_FILTER_ECN | + + PBR_FILTER_FWMARK | + PBR_FILTER_PCP | + PBR_FILTER_VLAN_ID | + PBR_FILTER_VLAN_FLAGS + )) && + !CHECK_FLAG(pbrms->action_bm, ( + + PBR_ACTION_PCP | + PBR_ACTION_VLAN_ID | + PBR_ACTION_VLAN_STRIP_INNER_ANY | + + PBR_ACTION_QUEUE_ID + )) + ) { pbrms->reason |= PBR_MAP_INVALID_EMPTY; + } + /* clang-format on */ } static void pbr_map_sequence_check_vlan_actions(struct pbr_map_sequence *pbrms) @@ -653,7 +635,8 @@ static void pbr_map_sequence_check_vlan_actions(struct pbr_map_sequence *pbrms) * The strip vlan action removes any inner tag, so it is invalid to * specify both a set and strip action. */ - if ((pbrms->action_vlan_id != 0) && (pbrms->action_vlan_flags != 0)) + if (CHECK_FLAG(pbrms->action_bm, PBR_ACTION_VLAN_ID) && + (CHECK_FLAG(pbrms->action_bm, PBR_ACTION_VLAN_STRIP_INNER_ANY))) pbrms->reason |= PBR_MAP_INVALID_SET_STRIP_VLAN; } diff --git a/pbrd/pbr_map.h b/pbrd/pbr_map.h index 3afb19956..700bc93f7 100644 --- a/pbrd/pbr_map.h +++ b/pbrd/pbr_map.h @@ -3,7 +3,9 @@ * PBR-map Header * Copyright (C) 2018 Cumulus Networks, Inc. * Donald Sharp - * Copyright (c) 2023 LabN Consulting, L.L.C. + * Portions: + * Copyright (c) 2023 LabN Consulting, L.L.C. + * Copyright (c) 2021 The MITRE Corporation */ #ifndef __PBR_MAP_H__ #define __PBR_MAP_H__ @@ -54,6 +56,14 @@ struct pbr_map_interface { bool delete; }; +enum pbr_forwarding_type { + PBR_FT_UNSPEC = 0, + PBR_FT_VRF_UNCHANGED, + PBR_FT_SETVRF, + PBR_FT_NEXTHOP_GROUP, + PBR_FT_NEXTHOP_SINGLE, +}; + struct pbr_map_sequence { struct pbr_map *parent; @@ -109,14 +119,19 @@ struct pbr_map_sequence { * Action fields *****************************************************************/ + /* + * same bit definitions as in lib/pbr.h + */ + uint32_t action_bm; + uint8_t action_pcp; uint8_t action_vlan_id; -#define PBR_MAP_STRIP_INNER_ANY (1 << 0) - uint8_t action_vlan_flags; #define PBR_MAP_UNDEFINED_QUEUE_ID 0 uint32_t action_queue_id; + enum pbr_forwarding_type forwarding_type; + /* * Use interface's vrf. */ @@ -233,9 +248,4 @@ extern void pbr_map_check_vrf_nh_group_change(const char *nh_group, extern void pbr_map_check_interface_nh_group_change(const char *nh_group, struct interface *ifp, ifindex_t oldifindex); -extern void pbr_set_match_clause_for_vlan(struct pbr_map_sequence *pbrms, - uint16_t vlan_id, - uint16_t vlan_flags); -extern void pbr_set_match_clause_for_pcp(struct pbr_map_sequence *pbrms, - bool set, uint8_t pcp); #endif diff --git a/pbrd/pbr_nht.c b/pbrd/pbr_nht.c index 405a2d658..4f7882fb2 100644 --- a/pbrd/pbr_nht.c +++ b/pbrd/pbr_nht.c @@ -549,6 +549,7 @@ void pbr_nht_set_seq_nhg(struct pbr_map_sequence *pbrms, const char *name) return; pbrms->nhgrp_name = XSTRDUP(MTYPE_TMP, name); + pbrms->forwarding_type = PBR_FT_NEXTHOP_GROUP; nhgc = nhgc_find(name); if (!nhgc) @@ -572,6 +573,7 @@ void pbr_nht_add_individual_nexthop(struct pbr_map_sequence *pbrms, MTYPE_TMP, pbr_nht_nexthop_make_name(pbrms->parent->name, PBR_NHC_NAMELEN, pbrms->seqno, buf)); + pbrms->forwarding_type = PBR_FT_NEXTHOP_SINGLE; nh = nexthop_new(); memcpy(nh, nhop, sizeof(*nh)); diff --git a/pbrd/pbr_vty.c b/pbrd/pbr_vty.c index cffd3794c..0d8fa6939 100644 --- a/pbrd/pbr_vty.c +++ b/pbrd/pbr_vty.c @@ -132,10 +132,78 @@ DEFUN_NOSH(no_pbr_map, * pbrms/rule Match L3 Fields ***********************************************************************/ +/* + * Address Family Matters + * + * Linux Kernel constraints + * ------------------------ + * The underlying linux kernel dataplane requires that rules be + * installed into an IPv4-specific or an IPv6-specific database. + * + * Not only do we need to designate an address-family for rule + * installation, but we ALSO must have the same address-family + * available to be able to delete the rule from the correct kernel + * database. + * + * Determining the address-family + * ------------------------------ + * In the current code, we do our best to infer the correct family + * from any configured IP-address match or set clauses in a rule. + * Absent any of those fields, the NHT code also tries to glean the + * address family from resolved nexthops or nexthop-groups. All of + * those opportunistic address-family determinations are stored in + * the "family" field of struct pbr_map_sequence. + * + * This "family" field value is needed particularly when deleting + * a rule piece-by-piece because at the end, the match/set fields + * will be empty. Maybe it would be possible to handle this issue + * as an internal zebra matter in the future. + * + * We also attempt to maintain address-family consistency among the + * various configured fields in a rule. So far, these fields are + * src/dst IP-address match/set values. + * + * It is probably possible to perform the same address-family check in + * the CLI for single nexthops (set nexthop A.B.C.D|X:X::X:X) but the + * address-family is not immediately available for nexthop-groups. + * In both the single-nexthop and nexthop-group, the NHT resolution code + * sets the "family" field of struct pbr_map_sequence asynchronously. + * + * There isn't currently any flagging of rules that have a consistent + * set of src/dst IP-address match/set values but an asynchronously-resolved + * nexthop-group that has a different address-family. + * + * The match/set IP-address handlers below blindly set "family"; it's + * probably possible to wrongly set "family" to, e.g., IPv4 this way after + * a v6 NHG has been resolved and break rule removal. It's not clear + * how to best address this potential issue. + */ +static bool pbr_family_consistent(struct pbr_map_sequence *pbrms, + uint8_t family, uint32_t skip_filter_bm, + uint32_t skip_action_bm, const char **msg) +{ + uint32_t filter_bm = pbrms->filter_bm & ~skip_filter_bm; + + if (CHECK_FLAG(filter_bm, PBR_FILTER_SRC_IP) && + (family != pbrms->src->family)) { + if (msg) + *msg = "match src-ip"; + return false; + } + if (CHECK_FLAG(filter_bm, PBR_FILTER_DST_IP) && + (family != pbrms->dst->family)) { + if (msg) + *msg = "match dst-ip"; + return false; + } + return true; +} + + /* clang-format off */ DEFPY (pbr_map_match_src, pbr_map_match_src_cmd, - "[no] match src-ip <A.B.C.D/M|X:X::X:X/M>$prefix", + "[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" @@ -144,28 +212,37 @@ DEFPY (pbr_map_match_src, { /* 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 (pbrms->dst && prefix->family != pbrms->dst->family) { - vty_out(vty, "Cannot mismatch families within match src/dst\n"); - return CMD_WARNING_CONFIG_FAILED; + if (no) { + if (!CHECK_FLAG(pbrms->filter_bm, PBR_FILTER_SRC_IP)) + return CMD_SUCCESS; + prefix_free(&pbrms->src); + UNSET_FLAG(pbrms->filter_bm, PBR_FILTER_SRC_IP); + goto check; } + assert(prefix); + if (!pbr_family_consistent(pbrms, prefix->family, PBR_FILTER_SRC_IP, 0, + &fmsg)) { + vty_out(vty, "Address family mismatch (%s)\n", fmsg); + return CMD_WARNING_CONFIG_FAILED; + } pbrms->family = prefix->family; - if (!no) { - if (pbrms->src) { - if (prefix_same(pbrms->src, prefix)) - return CMD_SUCCESS; - } else - pbrms->src = prefix_new(); - - prefix_copy(pbrms->src, prefix); + if (CHECK_FLAG(pbrms->filter_bm, PBR_FILTER_SRC_IP)) { + if (prefix_same(pbrms->src, prefix)) + return CMD_SUCCESS; } else - prefix_free(&pbrms->src); + pbrms->src = prefix_new(); + + prefix_copy(pbrms->src, prefix); + SET_FLAG(pbrms->filter_bm, PBR_FILTER_SRC_IP); +check: pbr_map_check(pbrms, true); return CMD_SUCCESS; @@ -174,7 +251,7 @@ DEFPY (pbr_map_match_src, /* clang-format off */ DEFPY (pbr_map_match_dst, pbr_map_match_dst_cmd, - "[no] match dst-ip <A.B.C.D/M|X:X::X:X/M>$prefix", + "[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" @@ -183,27 +260,37 @@ DEFPY (pbr_map_match_dst, { /* 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 (pbrms->src && prefix->family != pbrms->src->family) { - vty_out(vty, "Cannot mismatch families within match src/dst\n"); + if (no) { + if (!CHECK_FLAG(pbrms->filter_bm, PBR_FILTER_DST_IP)) + return CMD_SUCCESS; + prefix_free(&pbrms->dst); + UNSET_FLAG(pbrms->filter_bm, PBR_FILTER_DST_IP); + goto check; + } + + assert(prefix); + if (!pbr_family_consistent(pbrms, prefix->family, PBR_FILTER_DST_IP, 0, + &fmsg)) { + vty_out(vty, "Address family mismatch (%s)\n", fmsg); return CMD_WARNING_CONFIG_FAILED; } pbrms->family = prefix->family; - if (!no) { - if (pbrms->dst) { - if (prefix_same(pbrms->dst, prefix)) - return CMD_SUCCESS; - } else - pbrms->dst = prefix_new(); - - prefix_copy(pbrms->dst, prefix); + if (CHECK_FLAG(pbrms->filter_bm, PBR_FILTER_DST_IP)) { + if (prefix_same(pbrms->dst, prefix)) + return CMD_SUCCESS; } else - prefix_free(&pbrms->dst); + pbrms->dst = prefix_new(); + prefix_copy(pbrms->dst, prefix); + SET_FLAG(pbrms->filter_bm, PBR_FILTER_DST_IP); + +check: pbr_map_check(pbrms, true); return CMD_SUCCESS; @@ -212,7 +299,7 @@ DEFPY (pbr_map_match_dst, /* clang-format off */ DEFPY (pbr_map_match_ip_proto, pbr_map_match_ip_proto_cmd, - "[no] match ip-protocol PROTO$ip_proto", + "[no] match ip-protocol ![PROTO$ip_proto]", NO_STR "Match the rest of the command\n" "Choose an ip-protocol\n" @@ -220,37 +307,39 @@ DEFPY (pbr_map_match_ip_proto, { /* clang-format on */ struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence); - struct protoent *p; + struct protoent *p = NULL; if (!pbrms) return CMD_WARNING_CONFIG_FAILED; - if (!no) { - if (!ip_proto) { - vty_out(vty, "Unable to convert (null) to proto id\n"); - return CMD_WARNING; - } + if (no) { + if (!CHECK_FLAG(pbrms->filter_bm, PBR_FILTER_IP_PROTOCOL)) + return CMD_SUCCESS; + UNSET_FLAG(pbrms->filter_bm, PBR_FILTER_IP_PROTOCOL); + goto check; + } + if (ip_proto) p = getprotobyname(ip_proto); - if (!p) { - vty_out(vty, "Unable to convert %s to proto id\n", - ip_proto); - return CMD_WARNING; - } - pbrms->ip_proto = p->p_proto; - } else - pbrms->ip_proto = 0; + if (!ip_proto || !p) { + vty_out(vty, "Unable to convert %s to proto id\n", + (ip_proto ? ip_proto : "(null)")); + return CMD_WARNING_CONFIG_FAILED; + } - pbr_map_check(pbrms, true); + pbrms->ip_proto = p->p_proto; + SET_FLAG(pbrms->filter_bm, PBR_FILTER_IP_PROTOCOL); +check: + pbr_map_check(pbrms, true); return CMD_SUCCESS; } /* clang-format off */ DEFPY (pbr_map_match_src_port, pbr_map_match_src_port_cmd, - "[no] match src-port (1-65535)$port", + "[no] match src-port ![(1-65535)$port]", NO_STR "Match the rest of the command\n" "Choose the source port to use\n" @@ -262,23 +351,29 @@ DEFPY (pbr_map_match_src_port, if (!pbrms) return CMD_WARNING_CONFIG_FAILED; - if (!no) { - if (pbrms->src_prt == port) + if (no) { + if (!CHECK_FLAG(pbrms->filter_bm, PBR_FILTER_SRC_PORT)) return CMD_SUCCESS; - else - pbrms->src_prt = port; - } else - pbrms->src_prt = 0; + UNSET_FLAG(pbrms->filter_bm, PBR_FILTER_SRC_PORT); + goto check; + } - pbr_map_check(pbrms, true); + if (CHECK_FLAG(pbrms->filter_bm, PBR_FILTER_SRC_PORT) && + (pbrms->src_prt == port)) { + return CMD_SUCCESS; + } + pbrms->src_prt = port; + SET_FLAG(pbrms->filter_bm, PBR_FILTER_SRC_PORT); +check: + pbr_map_check(pbrms, true); return CMD_SUCCESS; } /* clang-format off */ DEFPY (pbr_map_match_dst_port, pbr_map_match_dst_port_cmd, - "[no] match dst-port (1-65535)$port", + "[no] match dst-port ![(1-65535)$port]", NO_STR "Match the rest of the command\n" "Choose the destination port to use\n" @@ -290,23 +385,29 @@ DEFPY (pbr_map_match_dst_port, if (!pbrms) return CMD_WARNING_CONFIG_FAILED; - if (!no) { - if (pbrms->dst_prt == port) + if (no) { + if (!CHECK_FLAG(pbrms->filter_bm, PBR_FILTER_DST_PORT)) return CMD_SUCCESS; - else - pbrms->dst_prt = port; - } else - pbrms->dst_prt = 0; + UNSET_FLAG(pbrms->filter_bm, PBR_FILTER_DST_PORT); + goto check; + } - pbr_map_check(pbrms, true); + if (CHECK_FLAG(pbrms->filter_bm, PBR_FILTER_DST_PORT) && + (pbrms->dst_prt == port)) { + return CMD_SUCCESS; + } + pbrms->dst_prt = port; + SET_FLAG(pbrms->filter_bm, PBR_FILTER_DST_PORT); +check: + pbr_map_check(pbrms, true); return CMD_SUCCESS; } /* clang-format off */ DEFPY (pbr_map_match_dscp, pbr_map_match_dscp_cmd, - "[no] match dscp DSCP$dscp", + "[no] match dscp ![DSCP$dscp]", NO_STR "Match the rest of the command\n" "Match based on IP DSCP field\n" @@ -314,68 +415,52 @@ DEFPY (pbr_map_match_dscp, { /* clang-format on */ struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence); - char dscpname[100]; - uint8_t rawDscp; if (!pbrms) return CMD_WARNING_CONFIG_FAILED; - /* Discriminate dscp enums (cs0, cs1 etc.) and numbers */ - bool isANumber = true; - for (int i = 0; i < (int)strlen(dscp); i++) { - /* Letters are not numbers */ - if (!isdigit(dscp[i])) - isANumber = false; - - /* Lowercase the dscp enum (if needed) */ - if (isupper(dscp[i])) - dscpname[i] = tolower(dscp[i]); - else - dscpname[i] = dscp[i]; + if (no) { + if (!CHECK_FLAG(pbrms->filter_bm, PBR_FILTER_DSCP)) + return CMD_SUCCESS; + UNSET_FLAG(pbrms->filter_bm, PBR_FILTER_DSCP); + pbrms->dsfield &= ~PBR_DSFIELD_DSCP; + goto check; } - dscpname[strlen(dscp)] = '\0'; - if (isANumber) { - /* dscp passed is a regular number */ - long dscpAsNum = strtol(dscp, NULL, 0); + unsigned long ul_dscp; + char *pend; + uint8_t raw_dscp; - if (dscpAsNum > PBR_DSFIELD_DSCP >> 2) { - /* Refuse to install on overflow */ - vty_out(vty, "dscp (%s) must be less than 64\n", dscp); - return CMD_WARNING_CONFIG_FAILED; - } - rawDscp = dscpAsNum; - } else { - /* check dscp if it is an enum like cs0 */ - rawDscp = pbr_map_decode_dscp_enum(dscpname); - if (rawDscp > PBR_DSFIELD_DSCP) { - vty_out(vty, "Invalid dscp value: %s\n", dscpname); - return CMD_WARNING_CONFIG_FAILED; - } + 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 (!no) { - if (((pbrms->dsfield & PBR_DSFIELD_DSCP) >> 2) == rawDscp) - return CMD_SUCCESS; - - /* Set the DSCP bits of the DSField */ - pbrms->dsfield = - (pbrms->dsfield & ~PBR_DSFIELD_DSCP) | (rawDscp << 2); - SET_FLAG(pbrms->filter_bm, PBR_FILTER_DSCP); - } else { - pbrms->dsfield &= ~PBR_DSFIELD_DSCP; - UNSET_FLAG(pbrms->filter_bm, PBR_FILTER_DSCP); + if (CHECK_FLAG(pbrms->filter_bm, PBR_FILTER_DSCP) && + (((pbrms->dsfield & PBR_DSFIELD_DSCP) >> 2) == raw_dscp)) { + return CMD_SUCCESS; } - pbr_map_check(pbrms, true); + /* Set the DSCP bits of the DSField */ + pbrms->dsfield = (pbrms->dsfield & ~PBR_DSFIELD_DSCP) | (raw_dscp << 2); + SET_FLAG(pbrms->filter_bm, PBR_FILTER_DSCP); +check: + pbr_map_check(pbrms, true); return CMD_SUCCESS; } /* clang-format off */ DEFPY (pbr_map_match_ecn, pbr_map_match_ecn_cmd, - "[no] match ecn (0-3)$ecn", + "[no] match ecn ![(0-3)$ecn]", NO_STR "Match the rest of the command\n" "Match based on IP ECN field\n" @@ -387,20 +472,25 @@ DEFPY (pbr_map_match_ecn, if (!pbrms) return CMD_WARNING_CONFIG_FAILED; - if (!no) { - if ((pbrms->dsfield & PBR_DSFIELD_ECN) == ecn) + if (no) { + if (!CHECK_FLAG(pbrms->filter_bm, PBR_FILTER_ECN)) return CMD_SUCCESS; - - /* Set the ECN bits of the DSField */ - pbrms->dsfield = (pbrms->dsfield & ~PBR_DSFIELD_ECN) | ecn; - SET_FLAG(pbrms->filter_bm, PBR_FILTER_ECN); - } else { - pbrms->dsfield &= ~PBR_DSFIELD_ECN; UNSET_FLAG(pbrms->filter_bm, PBR_FILTER_ECN); + pbrms->dsfield &= ~PBR_DSFIELD_ECN; + goto check; } - pbr_map_check(pbrms, true); + if (CHECK_FLAG(pbrms->filter_bm, PBR_FILTER_ECN) && + ((pbrms->dsfield & PBR_DSFIELD_ECN) == ecn)) { + return CMD_SUCCESS; + } + /* Set the ECN bits of the DSField */ + pbrms->dsfield = (pbrms->dsfield & ~PBR_DSFIELD_ECN) | ecn; + SET_FLAG(pbrms->filter_bm, PBR_FILTER_ECN); + +check: + pbr_map_check(pbrms, true); return CMD_SUCCESS; } @@ -409,7 +499,9 @@ DEFPY (pbr_map_match_ecn, ***********************************************************************/ /* clang-format off */ -DEFPY (pbr_map_match_pcp, pbr_map_match_pcp_cmd, "[no] match pcp <(0-7)$pcp>", +DEFPY (pbr_map_match_pcp, + pbr_map_match_pcp_cmd, + "[no] match pcp ![(0-7)$pcp]", NO_STR "Match spec follows\n" "Match based on 802.1p Priority Code Point (PCP) value\n" @@ -418,16 +510,33 @@ DEFPY (pbr_map_match_pcp, pbr_map_match_pcp_cmd, "[no] match pcp <(0-7)$pcp>", /* clang-format on */ struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence); - if (pbrms) - pbr_set_match_clause_for_pcp(pbrms, !no, pcp); + if (!pbrms) + return CMD_WARNING_CONFIG_FAILED; + if (no) { + if (!CHECK_FLAG(pbrms->filter_bm, PBR_FILTER_PCP)) + return CMD_SUCCESS; + UNSET_FLAG(pbrms->filter_bm, PBR_FILTER_PCP); + goto check; + } + + if (CHECK_FLAG(pbrms->filter_bm, PBR_FILTER_PCP) && + (pbrms->match_pcp == pcp)) { + return CMD_SUCCESS; + } + + pbrms->match_pcp = pcp; + SET_FLAG(pbrms->filter_bm, PBR_FILTER_PCP); + +check: + pbr_map_check(pbrms, true); return CMD_SUCCESS; } /* clang-format off */ DEFPY (pbr_map_match_vlan_id, pbr_map_match_vlan_id_cmd, - "[no] match vlan <(1-4094)$vlan_id>", + "[no] match vlan ![(1-4094)$vlan_id]", NO_STR "Match spec follows\n" "Match based on VLAN ID\n" @@ -436,19 +545,31 @@ DEFPY (pbr_map_match_vlan_id, /* clang-format on */ struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence); - if (pbrms) { - if (!no) { - pbr_set_match_clause_for_vlan(pbrms, vlan_id, 0); - } else { - /* if the user previously set a vlan_id value */ - if (pbrms->match_vlan_id != 0) { - if (vlan_id == pbrms->match_vlan_id) { - pbr_set_match_clause_for_vlan(pbrms, 0, - 0); - } - } - } + if (!pbrms) + return CMD_WARNING_CONFIG_FAILED; + + if (no) { + if (!CHECK_FLAG(pbrms->filter_bm, PBR_FILTER_VLAN_ID)) + return CMD_SUCCESS; + UNSET_FLAG(pbrms->filter_bm, PBR_FILTER_VLAN_ID); + goto check; } + + if (CHECK_FLAG(pbrms->filter_bm, PBR_FILTER_VLAN_ID) && + (pbrms->match_vlan_id == vlan_id)) { + return CMD_SUCCESS; + } + + /* + * Maintaining previous behavior: setting a vlan_id match + * automatically clears any vlan_flags matching. + */ + UNSET_FLAG(pbrms->filter_bm, PBR_FILTER_VLAN_FLAGS); + SET_FLAG(pbrms->filter_bm, PBR_FILTER_VLAN_ID); + pbrms->match_vlan_id = vlan_id; + +check: + pbr_map_check(pbrms, true); return CMD_SUCCESS; } @@ -465,26 +586,45 @@ DEFPY (pbr_map_match_vlan_tag, { /* clang-format on */ struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence); + uint16_t vlan_flags; if (!pbrms) - return CMD_WARNING; - - if (!no) { - assert(tag_type); - if (strmatch(tag_type, "tagged")) { - pbr_set_match_clause_for_vlan(pbrms, 0, - PBR_VLAN_FLAGS_TAGGED); - } else if (strmatch(tag_type, "untagged")) { - pbr_set_match_clause_for_vlan(pbrms, 0, - PBR_VLAN_FLAGS_UNTAGGED); - } else if (strmatch(tag_type, "untagged-or-zero")) { - pbr_set_match_clause_for_vlan(pbrms, 0, - PBR_VLAN_FLAGS_UNTAGGED_0); - } - } else { - pbr_set_match_clause_for_vlan(pbrms, 0, PBR_VLAN_FLAGS_NO_WILD); + return CMD_WARNING_CONFIG_FAILED; + + if (no) { + if (!CHECK_FLAG(pbrms->filter_bm, PBR_FILTER_VLAN_FLAGS)) + return CMD_SUCCESS; + UNSET_FLAG(pbrms->filter_bm, PBR_FILTER_VLAN_FLAGS); + goto check; } + assert(tag_type); + if (strmatch(tag_type, "tagged")) + vlan_flags = PBR_VLAN_FLAGS_TAGGED; + else if (strmatch(tag_type, "untagged")) + vlan_flags = PBR_VLAN_FLAGS_UNTAGGED; + else if (strmatch(tag_type, "untagged-or-zero")) + vlan_flags = PBR_VLAN_FLAGS_UNTAGGED_0; + else { + vty_out(vty, "unknown vlan flag\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + if (CHECK_FLAG(pbrms->filter_bm, PBR_FILTER_VLAN_FLAGS) && + (pbrms->match_vlan_flags == vlan_flags)) { + return CMD_SUCCESS; + } + + /* + * Maintaining previous behavior: setting a vlan_flags match + * automatically clears any vlan_id matching. + */ + UNSET_FLAG(pbrms->filter_bm, PBR_FILTER_VLAN_ID); + SET_FLAG(pbrms->filter_bm, PBR_FILTER_VLAN_FLAGS); + pbrms->match_vlan_flags = vlan_flags; + +check: + pbr_map_check(pbrms, true); return CMD_SUCCESS; } @@ -495,7 +635,7 @@ DEFPY (pbr_map_match_vlan_tag, /* clang-format off */ DEFPY (pbr_map_match_mark, pbr_map_match_mark_cmd, - "[no] match mark (1-4294967295)$mark", + "[no] match mark ![(1-4294967295)$mark]", NO_STR "Match the rest of the command\n" "Choose the mark value to use\n" @@ -512,15 +652,22 @@ DEFPY (pbr_map_match_mark, return CMD_WARNING_CONFIG_FAILED; #endif - if (!no) { - if (pbrms->mark) - if (pbrms->mark == (uint32_t)mark) - return CMD_SUCCESS; + if (no) { + if (!CHECK_FLAG(pbrms->filter_bm, PBR_FILTER_FWMARK)) + return CMD_SUCCESS; + UNSET_FLAG(pbrms->filter_bm, PBR_FILTER_FWMARK); + goto check; + } - pbrms->mark = (uint32_t)mark; - } else - pbrms->mark = 0; + if (CHECK_FLAG(pbrms->filter_bm, PBR_FILTER_FWMARK) && + (pbrms->mark == (uint32_t)mark)) { + return CMD_SUCCESS; + } + pbrms->mark = (uint32_t)mark; + SET_FLAG(pbrms->filter_bm, PBR_FILTER_FWMARK); + +check: pbr_map_check(pbrms, true); return CMD_SUCCESS; @@ -533,7 +680,7 @@ DEFPY (pbr_map_match_mark, /* clang-format off */ DEFPY (pbr_map_action_queue_id, pbr_map_action_queue_id_cmd, - "[no] set queue-id <(1-65535)$queue_id>", + "[no] set queue-id ![(1-65535)$queue_id]", NO_STR "Set the rest of the command\n" "Set based on egress port queue id\n" @@ -545,13 +692,22 @@ DEFPY (pbr_map_action_queue_id, if (!pbrms) return CMD_WARNING_CONFIG_FAILED; - if (!no) - pbrms->action_queue_id = queue_id; - else if ((uint32_t)queue_id == pbrms->action_queue_id) - pbrms->action_queue_id = PBR_MAP_UNDEFINED_QUEUE_ID; + if (no) { + if (!CHECK_FLAG(pbrms->action_bm, PBR_ACTION_QUEUE_ID)) + return CMD_SUCCESS; + UNSET_FLAG(pbrms->action_bm, PBR_ACTION_QUEUE_ID); + goto check; + } - pbr_map_check(pbrms, true); + if (CHECK_FLAG(pbrms->action_bm, PBR_ACTION_QUEUE_ID) && + (pbrms->action_queue_id == (uint32_t)queue_id)) { + return CMD_SUCCESS; + } + pbrms->action_queue_id = (uint32_t)queue_id; + SET_FLAG(pbrms->action_bm, PBR_ACTION_QUEUE_ID); +check: + pbr_map_check(pbrms, true); return CMD_SUCCESS; } @@ -563,7 +719,7 @@ DEFPY (pbr_map_action_queue_id, /* clang-format off */ DEFPY (pbr_map_action_pcp, pbr_map_action_pcp_cmd, - "[no] set pcp <(0-7)$pcp>", + "[no] set pcp ![(0-7)$pcp]", NO_STR "Set the rest of the command\n" "Set based on 802.1p Priority Code Point (PCP) value\n" @@ -575,20 +731,30 @@ DEFPY (pbr_map_action_pcp, if (!pbrms) return CMD_WARNING_CONFIG_FAILED; - if (!no) - pbrms->action_pcp = pcp; - else if (pcp == pbrms->action_pcp) - pbrms->action_pcp = 0; + if (no) { + if (!CHECK_FLAG(pbrms->action_bm, PBR_ACTION_PCP)) + return CMD_SUCCESS; + UNSET_FLAG(pbrms->action_bm, PBR_ACTION_PCP); + goto check; + } - pbr_map_check(pbrms, true); + if (CHECK_FLAG(pbrms->action_bm, PBR_ACTION_PCP) && + pbrms->action_pcp == pcp) { + return CMD_SUCCESS; + } + + pbrms->action_pcp = pcp; + SET_FLAG(pbrms->action_bm, PBR_ACTION_PCP); +check: + pbr_map_check(pbrms, true); return CMD_SUCCESS; } /* clang-format off */ DEFPY (pbr_map_action_vlan_id, pbr_map_action_vlan_id_cmd, - "[no] set vlan <(1-4094)$vlan_id>", + "[no] set vlan ![(1-4094)$vlan_id]", NO_STR "Set the rest of the command\n" "Set action for VLAN tagging\n" @@ -600,13 +766,27 @@ DEFPY (pbr_map_action_vlan_id, if (!pbrms) return CMD_WARNING_CONFIG_FAILED; - if (!no) - pbrms->action_vlan_id = vlan_id; - else if (pbrms->action_vlan_id == vlan_id) - pbrms->action_vlan_id = 0; + if (no) { + if (!CHECK_FLAG(pbrms->action_bm, PBR_ACTION_VLAN_ID)) + return CMD_SUCCESS; + UNSET_FLAG(pbrms->action_bm, PBR_ACTION_VLAN_ID); + goto check; + } - pbr_map_check(pbrms, true); + if (CHECK_FLAG(pbrms->action_bm, PBR_ACTION_VLAN_ID) && + (pbrms->action_vlan_id == vlan_id)) { + return CMD_SUCCESS; + } + + /* + * Setting a vlan_id action automatically clears any strip-inner action + */ + pbrms->action_vlan_id = vlan_id; + UNSET_FLAG(pbrms->action_bm, PBR_ACTION_VLAN_STRIP_INNER_ANY); + SET_FLAG(pbrms->action_bm, PBR_ACTION_VLAN_ID); +check: + pbr_map_check(pbrms, true); return CMD_SUCCESS; } @@ -616,7 +796,7 @@ DEFPY (pbr_map_action_strip_vlan, "[no] strip vlan", NO_STR "Strip the vlan tags from frame\n" - "Strip any inner vlan tag \n") + "Strip any inner vlan tag\n") { /* clang-format on */ struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence); @@ -624,13 +804,24 @@ DEFPY (pbr_map_action_strip_vlan, if (!pbrms) return CMD_WARNING_CONFIG_FAILED; - if (!no) - pbrms->action_vlan_flags = PBR_MAP_STRIP_INNER_ANY; - else - pbrms->action_vlan_flags = 0; + if (no) { + if (!CHECK_FLAG(pbrms->action_bm, + PBR_ACTION_VLAN_STRIP_INNER_ANY)) + return CMD_SUCCESS; + UNSET_FLAG(pbrms->action_bm, PBR_ACTION_VLAN_STRIP_INNER_ANY); + goto check; + } + if (CHECK_FLAG(pbrms->action_bm, PBR_ACTION_VLAN_STRIP_INNER_ANY)) + return CMD_SUCCESS; - pbr_map_check(pbrms, true); + /* + * Setting a strip-inner action automatically clears any vlan_id action + */ + UNSET_FLAG(pbrms->action_bm, PBR_ACTION_VLAN_ID); + SET_FLAG(pbrms->action_bm, PBR_ACTION_VLAN_STRIP_INNER_ANY); +check: + pbr_map_check(pbrms, true); return CMD_SUCCESS; } @@ -668,6 +859,8 @@ static void pbrms_clear_set_config(struct pbr_map_sequence *pbrms) pbrms_clear_set_nexthop_config(pbrms); pbrms->nhs_installed = false; + + pbrms->forwarding_type = PBR_FT_UNSPEC; } @@ -904,10 +1097,11 @@ DEFPY(pbr_map_vrf, pbr_map_vrf_cmd, /* * If an equivalent set vrf * exists, just return success. */ - if (vrf_name && pbrms->vrf_lookup - && strncmp(pbrms->vrf_name, vrf_name, sizeof(pbrms->vrf_name)) == 0) + if ((pbrms->forwarding_type == PBR_FT_SETVRF) && + strncmp(pbrms->vrf_name, vrf_name, sizeof(pbrms->vrf_name)) == 0) return CMD_SUCCESS; - else if (!vrf_name && pbrms->vrf_unchanged) /* Unchanged already set */ + else if (!vrf_name && (pbrms->forwarding_type == PBR_FT_VRF_UNCHANGED)) + /* Unchanged already set */ return CMD_SUCCESS; if (vrf_name && !pbr_vrf_lookup_by_name(vrf_name)) { @@ -920,9 +1114,12 @@ DEFPY(pbr_map_vrf, pbr_map_vrf_cmd, if (vrf_name) { pbrms->vrf_lookup = true; + pbrms->forwarding_type = PBR_FT_SETVRF; strlcpy(pbrms->vrf_name, vrf_name, sizeof(pbrms->vrf_name)); - } else + } else { + pbrms->forwarding_type = PBR_FT_VRF_UNCHANGED; pbrms->vrf_unchanged = true; + } pbr_map_check(pbrms, true); @@ -1066,56 +1263,77 @@ static void vty_show_pbrms(struct vty *vty, pbrms->installed ? "yes" : "no", pbrms->reason ? rbuf : "Valid"); - if (pbrms->ip_proto) { + /* match clauses first */ + + if (CHECK_FLAG(pbrms->filter_bm, PBR_FILTER_IP_PROTOCOL)) { struct protoent *p; p = getprotobynumber(pbrms->ip_proto); vty_out(vty, " IP Protocol Match: %s\n", p->p_name); } - if (pbrms->src) + if (CHECK_FLAG(pbrms->filter_bm, PBR_FILTER_SRC_IP)) vty_out(vty, " SRC IP Match: %pFX\n", pbrms->src); - if (pbrms->dst) + if (CHECK_FLAG(pbrms->filter_bm, PBR_FILTER_DST_IP)) vty_out(vty, " DST IP Match: %pFX\n", pbrms->dst); - if (pbrms->src_prt) + + if (CHECK_FLAG(pbrms->filter_bm, PBR_FILTER_SRC_PORT)) vty_out(vty, " SRC Port Match: %u\n", pbrms->src_prt); - if (pbrms->dst_prt) + if (CHECK_FLAG(pbrms->filter_bm, PBR_FILTER_DST_PORT)) vty_out(vty, " DST Port Match: %u\n", pbrms->dst_prt); - if (pbrms->dsfield & PBR_DSFIELD_DSCP) + if (CHECK_FLAG(pbrms->filter_bm, PBR_FILTER_DSCP)) vty_out(vty, " DSCP Match: %u\n", (pbrms->dsfield & PBR_DSFIELD_DSCP) >> 2); - if (pbrms->dsfield & PBR_DSFIELD_ECN) + if (CHECK_FLAG(pbrms->filter_bm, PBR_FILTER_ECN)) vty_out(vty, " ECN Match: %u\n", pbrms->dsfield & PBR_DSFIELD_ECN); - if (pbrms->mark) + + if (CHECK_FLAG(pbrms->filter_bm, PBR_FILTER_FWMARK)) vty_out(vty, " MARK Match: %u\n", pbrms->mark); if (CHECK_FLAG(pbrms->filter_bm, PBR_FILTER_PCP)) vty_out(vty, " PCP Match: %d\n", pbrms->match_pcp); - if (pbrms->match_vlan_id != 0) + if (CHECK_FLAG(pbrms->filter_bm, PBR_FILTER_VLAN_ID)) vty_out(vty, " Match VLAN ID: %u\n", pbrms->match_vlan_id); - if (pbrms->match_vlan_flags == PBR_VLAN_FLAGS_TAGGED) - vty_out(vty, " Match VLAN tagged frames\n"); - if (pbrms->match_vlan_flags == PBR_VLAN_FLAGS_UNTAGGED) - vty_out(vty, " Match VLAN untagged frames\n"); - if (pbrms->match_vlan_flags == PBR_VLAN_FLAGS_UNTAGGED_0) - vty_out(vty, " Match VLAN untagged or ID 0\n"); - - if (pbrms->action_queue_id != PBR_MAP_UNDEFINED_QUEUE_ID) + if (CHECK_FLAG(pbrms->filter_bm, PBR_FILTER_VLAN_FLAGS)) { + if (pbrms->match_vlan_flags == PBR_VLAN_FLAGS_TAGGED) + vty_out(vty, " Match VLAN tagged frames\n"); + if (pbrms->match_vlan_flags == PBR_VLAN_FLAGS_UNTAGGED) + vty_out(vty, " Match VLAN untagged frames\n"); + if (pbrms->match_vlan_flags == PBR_VLAN_FLAGS_UNTAGGED_0) + vty_out(vty, " Match VLAN untagged or ID 0\n"); + } + + /* set actions */ + + + if (CHECK_FLAG(pbrms->action_bm, PBR_ACTION_QUEUE_ID)) vty_out(vty, " Set Queue ID: %u\n", pbrms->action_queue_id); - if (pbrms->action_vlan_id != 0) + if (CHECK_FLAG(pbrms->action_bm, PBR_ACTION_VLAN_ID)) vty_out(vty, " Set VLAN ID %u\n", pbrms->action_vlan_id); - if (pbrms->action_vlan_flags == PBR_MAP_STRIP_INNER_ANY) + if (CHECK_FLAG(pbrms->action_bm, PBR_ACTION_VLAN_STRIP_INNER_ANY)) vty_out(vty, " Strip VLAN ID\n"); - if (pbrms->action_pcp) + if (CHECK_FLAG(pbrms->action_bm, PBR_ACTION_PCP)) vty_out(vty, " Set PCP %u\n", pbrms->action_pcp); - if (pbrms->nhgrp_name) { + switch (pbrms->forwarding_type) { + case PBR_FT_UNSPEC: + vty_out(vty, " Nexthop-Group: Unknown Installed: no\n"); + break; + case PBR_FT_VRF_UNCHANGED: + vty_out(vty, " VRF Unchanged (use interface vrf)\n"); + break; + case PBR_FT_SETVRF: + assert(pbrms->vrf_name); + vty_out(vty, " VRF Lookup: %s\n", pbrms->vrf_name); + break; + case PBR_FT_NEXTHOP_GROUP: + assert(pbrms->nhgrp_name); vty_out(vty, " Nexthop-Group: %s\n", pbrms->nhgrp_name); if (detail) @@ -1129,8 +1347,9 @@ static void vty_show_pbrms(struct vty *vty, pbr_nht_get_installed(pbrms->nhgrp_name) ? "yes" : "no", pbr_nht_get_table(pbrms->nhgrp_name)); - - } else if (pbrms->nhg) { + break; + case PBR_FT_NEXTHOP_SINGLE: + assert(pbrms->internal_nhg_name); vty_out(vty, " "); pbrms_nexthop_group_write_individual_nexthop(vty, pbrms); if (detail) @@ -1145,13 +1364,7 @@ static void vty_show_pbrms(struct vty *vty, ? "yes" : "no", pbr_nht_get_table(pbrms->internal_nhg_name)); - - } else if (pbrms->vrf_unchanged) { - vty_out(vty, " VRF Unchanged (use interface vrf)\n"); - } else if (pbrms->vrf_lookup) { - vty_out(vty, " VRF Lookup: %s\n", pbrms->vrf_name); - } else { - vty_out(vty, " Nexthop-Group: Unknown Installed: no\n"); + break; } } @@ -1178,7 +1391,18 @@ static void vty_json_pbrms(json_object *j, struct vty *vty, json_object_string_add(jpbrm, "installedReason", pbrms->reason ? rbuf : "Valid"); - if (nhg_name) { + switch (pbrms->forwarding_type) { + case PBR_FT_UNSPEC: + break; + case PBR_FT_VRF_UNCHANGED: + break; + case PBR_FT_SETVRF: + assert(pbrms->vrf_name); + json_object_string_add(jpbrm, "vrfName", pbrms->vrf_name); + break; + case PBR_FT_NEXTHOP_GROUP: + case PBR_FT_NEXTHOP_SINGLE: + assert(nhg_name); nexthop_group = json_object_new_object(); json_object_int_add(nexthop_group, "tableId", @@ -1190,24 +1414,74 @@ static void vty_json_pbrms(json_object *j, struct vty *vty, pbrms->nhs_installed); json_object_object_add(jpbrm, "nexthopGroup", nexthop_group); + break; } - if (pbrms->vrf_lookup) - json_object_string_add(jpbrm, "vrfName", pbrms->vrf_name); - if (pbrms->src) + /* + * Match clauses + */ + + /* IP Header */ + if (CHECK_FLAG(pbrms->filter_bm, PBR_FILTER_IP_PROTOCOL)) + json_object_int_add(jpbrm, "matchIpProtocol", pbrms->ip_proto); + if (CHECK_FLAG(pbrms->filter_bm, PBR_FILTER_SRC_IP)) json_object_string_addf(jpbrm, "matchSrc", "%pFX", pbrms->src); - if (pbrms->dst) + if (CHECK_FLAG(pbrms->filter_bm, PBR_FILTER_DST_IP)) json_object_string_addf(jpbrm, "matchDst", "%pFX", pbrms->dst); - if (pbrms->mark) - json_object_int_add(jpbrm, "matchMark", pbrms->mark); - if (pbrms->dsfield & PBR_DSFIELD_DSCP) + if (CHECK_FLAG(pbrms->filter_bm, PBR_FILTER_SRC_PORT)) + json_object_int_add(jpbrm, "matchSrcPort", pbrms->src_prt); + if (CHECK_FLAG(pbrms->filter_bm, PBR_FILTER_DST_PORT)) + json_object_int_add(jpbrm, "matchDstPort", pbrms->dst_prt); + + if (CHECK_FLAG(pbrms->filter_bm, PBR_FILTER_DSCP)) json_object_int_add(jpbrm, "matchDscp", (pbrms->dsfield & PBR_DSFIELD_DSCP) >> 2); - if (pbrms->dsfield & PBR_DSFIELD_ECN) + if (CHECK_FLAG(pbrms->filter_bm, PBR_FILTER_ECN)) json_object_int_add(jpbrm, "matchEcn", pbrms->dsfield & PBR_DSFIELD_ECN); + /* L2 headers */ + if (CHECK_FLAG(pbrms->filter_bm, PBR_FILTER_PCP)) + json_object_int_add(jpbrm, "matchPcp", pbrms->match_pcp); + if (CHECK_FLAG(pbrms->filter_bm, PBR_FILTER_VLAN_ID)) + json_object_int_add(jpbrm, "matchVlanId", pbrms->match_vlan_id); + if (CHECK_FLAG(pbrms->filter_bm, PBR_FILTER_VLAN_FLAGS)) { + const char *p = "?"; + + if (pbrms->match_vlan_flags == PBR_VLAN_FLAGS_TAGGED) + p = "tagged"; + if (pbrms->match_vlan_flags == PBR_VLAN_FLAGS_UNTAGGED) + p = "untagged"; + if (pbrms->match_vlan_flags == PBR_VLAN_FLAGS_UNTAGGED_0) + p = "untagged-or-0"; + + json_object_string_addf(jpbrm, "matchVlanFlags", "%s", p); + } + + /* meta */ + if (CHECK_FLAG(pbrms->filter_bm, PBR_FILTER_FWMARK)) + json_object_int_add(jpbrm, "matchMark", pbrms->mark); + + /* + * action clauses + */ + + + /* L2 header fields */ + if (CHECK_FLAG(pbrms->action_bm, PBR_ACTION_VLAN_STRIP_INNER_ANY)) + json_object_boolean_true_add(jpbrm, "actionVlanStripInnerAny"); + if (CHECK_FLAG(pbrms->action_bm, PBR_ACTION_VLAN_ID)) + json_object_int_add(jpbrm, "actionSetVlanId", + pbrms->action_vlan_id); + if (CHECK_FLAG(pbrms->action_bm, PBR_ACTION_PCP)) + json_object_int_add(jpbrm, "actionSetPcp", pbrms->action_pcp); + + /* meta */ + if (CHECK_FLAG(pbrms->action_bm, PBR_ACTION_QUEUE_ID)) + json_object_int_add(jpbrm, "actionSetQueueId", + pbrms->action_queue_id); + json_object_array_add(j, jpbrm); } @@ -1473,71 +1747,86 @@ static int pbr_vty_map_config_write_sequence(struct vty *vty, { vty_out(vty, "pbr-map %s seq %u\n", pbrm->name, pbrms->seqno); - if (pbrms->src) + if (CHECK_FLAG(pbrms->filter_bm, PBR_FILTER_IP_PROTOCOL)) { + struct protoent *p; + + p = getprotobynumber(pbrms->ip_proto); + vty_out(vty, " match ip-protocol %s\n", p->p_name); + } + + if (CHECK_FLAG(pbrms->filter_bm, PBR_FILTER_SRC_IP)) vty_out(vty, " match src-ip %pFX\n", pbrms->src); - if (pbrms->dst) + if (CHECK_FLAG(pbrms->filter_bm, PBR_FILTER_DST_IP)) vty_out(vty, " match dst-ip %pFX\n", pbrms->dst); - if (pbrms->src_prt) + if (CHECK_FLAG(pbrms->filter_bm, PBR_FILTER_SRC_PORT)) vty_out(vty, " match src-port %u\n", pbrms->src_prt); - if (pbrms->dst_prt) + if (CHECK_FLAG(pbrms->filter_bm, PBR_FILTER_DST_PORT)) vty_out(vty, " match dst-port %u\n", pbrms->dst_prt); - if (pbrms->ip_proto) { - struct protoent *p; - - p = getprotobynumber(pbrms->ip_proto); - vty_out(vty, " match ip-protocol %s\n", p->p_name); - } - - if (pbrms->dsfield & PBR_DSFIELD_DSCP) + if (CHECK_FLAG(pbrms->filter_bm, PBR_FILTER_DSCP)) vty_out(vty, " match dscp %u\n", (pbrms->dsfield & PBR_DSFIELD_DSCP) >> 2); - if (pbrms->dsfield & PBR_DSFIELD_ECN) + if (CHECK_FLAG(pbrms->filter_bm, PBR_FILTER_ECN)) vty_out(vty, " match ecn %u\n", pbrms->dsfield & PBR_DSFIELD_ECN); - if (pbrms->mark) - vty_out(vty, " match mark %u\n", pbrms->mark); if (CHECK_FLAG(pbrms->filter_bm, PBR_FILTER_PCP)) vty_out(vty, " match pcp %d\n", pbrms->match_pcp); - if ((pbrms->match_vlan_id) && - (pbrms->match_vlan_flags == PBR_VLAN_FLAGS_NO_WILD)) + /* L2 headers */ + if (CHECK_FLAG(pbrms->filter_bm, PBR_FILTER_VLAN_ID)) vty_out(vty, " match vlan %u\n", pbrms->match_vlan_id); - if (pbrms->match_vlan_flags == PBR_VLAN_FLAGS_TAGGED) - vty_out(vty, " match vlan tagged\n"); - if (pbrms->match_vlan_flags == PBR_VLAN_FLAGS_UNTAGGED) - vty_out(vty, " match vlan untagged\n"); - if (pbrms->match_vlan_flags == PBR_VLAN_FLAGS_UNTAGGED_0) - vty_out(vty, " match vlan untagged-or-zero\n"); - - if (pbrms->action_queue_id != PBR_MAP_UNDEFINED_QUEUE_ID) - vty_out(vty, " set queue-id %d\n", pbrms->action_queue_id); + if (CHECK_FLAG(pbrms->filter_bm, PBR_FILTER_VLAN_FLAGS)) { + if (pbrms->match_vlan_flags == PBR_VLAN_FLAGS_TAGGED) + vty_out(vty, " match vlan tagged\n"); + if (pbrms->match_vlan_flags == PBR_VLAN_FLAGS_UNTAGGED) + vty_out(vty, " match vlan untagged\n"); + if (pbrms->match_vlan_flags == PBR_VLAN_FLAGS_UNTAGGED_0) + vty_out(vty, " match vlan untagged-or-zero\n"); + } - if (pbrms->action_pcp) - vty_out(vty, " set pcp %d\n", pbrms->action_pcp); + /* meta */ + if (CHECK_FLAG(pbrms->filter_bm, PBR_FILTER_FWMARK)) + vty_out(vty, " match mark %u\n", pbrms->mark); - if (pbrms->action_vlan_id) - vty_out(vty, " set vlan %u\n", pbrms->action_vlan_id); + /* + * action clauses + */ - if (pbrms->action_vlan_flags == PBR_MAP_STRIP_INNER_ANY) + /* L2 header fields */ + if (CHECK_FLAG(pbrms->action_bm, PBR_ACTION_VLAN_STRIP_INNER_ANY)) vty_out(vty, " strip vlan any\n"); + if (CHECK_FLAG(pbrms->action_bm, PBR_ACTION_VLAN_ID)) + vty_out(vty, " set vlan %u\n", pbrms->action_vlan_id); + if (CHECK_FLAG(pbrms->action_bm, PBR_ACTION_PCP)) + vty_out(vty, " set pcp %d\n", pbrms->action_pcp); - if (pbrms->vrf_unchanged) - vty_out(vty, " set vrf unchanged\n"); + /* meta */ + if (CHECK_FLAG(pbrms->action_bm, PBR_ACTION_QUEUE_ID)) + vty_out(vty, " set queue-id %d\n", pbrms->action_queue_id); - if (pbrms->vrf_lookup) + switch (pbrms->forwarding_type) { + case PBR_FT_UNSPEC: + break; + case PBR_FT_VRF_UNCHANGED: + vty_out(vty, " set vrf unchanged\n"); + break; + case PBR_FT_SETVRF: + assert(pbrms->vrf_name); vty_out(vty, " set vrf %s\n", pbrms->vrf_name); - - if (pbrms->nhgrp_name) + break; + case PBR_FT_NEXTHOP_GROUP: + assert(pbrms->nhgrp_name); vty_out(vty, " set nexthop-group %s\n", pbrms->nhgrp_name); - - if (pbrms->nhg) { + break; + case PBR_FT_NEXTHOP_SINGLE: + assert(pbrms->nhg); vty_out(vty, " set "); pbrms_nexthop_group_write_individual_nexthop(vty, pbrms); + break; } vty_out(vty, "exit\n"); @@ -1605,6 +1894,7 @@ void pbr_vty_init(void) install_element(CONFIG_NODE, &pbr_set_table_range_cmd); install_element(CONFIG_NODE, &no_pbr_set_table_range_cmd); install_element(INTERFACE_NODE, &pbr_policy_cmd); + install_element(PBRMAP_NODE, &pbr_map_match_ip_proto_cmd); install_element(PBRMAP_NODE, &pbr_map_match_src_port_cmd); install_element(PBRMAP_NODE, &pbr_map_match_dst_port_cmd); diff --git a/pbrd/pbr_zebra.c b/pbrd/pbr_zebra.c index adcf449cf..66148c630 100644 --- a/pbrd/pbr_zebra.c +++ b/pbrd/pbr_zebra.c @@ -564,44 +564,18 @@ static bool pbr_encode_pbr_map_sequence(struct stream *s, r.filter.fwmark = pbrms->mark; r.filter.ip_proto = pbrms->ip_proto; - /* - * Fix up filter flags for now, since PBRD doesn't maintain - * them yet (aside from PBR_FILTER_PCP) - */ - if (!is_default_prefix(&r.filter.src_ip)) - SET_FLAG(r.filter.filter_bm, PBR_FILTER_SRC_IP); - if (!is_default_prefix(&r.filter.dst_ip)) - SET_FLAG(r.filter.filter_bm, PBR_FILTER_DST_IP); - if (r.filter.src_port) - SET_FLAG(r.filter.filter_bm, PBR_FILTER_SRC_PORT); - if (r.filter.dst_port) - SET_FLAG(r.filter.filter_bm, PBR_FILTER_DST_PORT); - if (r.filter.vlan_id) - SET_FLAG(r.filter.filter_bm, PBR_FILTER_VLAN_ID); - if (r.filter.vlan_flags) - SET_FLAG(r.filter.filter_bm, PBR_FILTER_VLAN_FLAGS); - if (r.filter.dsfield) - SET_FLAG(r.filter.filter_bm, PBR_FILTER_DSFIELD); - if (r.filter.fwmark) - SET_FLAG(r.filter.filter_bm, PBR_FILTER_FWMARK); - if (r.filter.ip_proto) - SET_FLAG(r.filter.filter_bm, PBR_FILTER_IP_PROTOCOL); + r.filter.filter_bm = pbrms->filter_bm; /* actions */ + SET_FLAG(r.action.flags, PBR_ACTION_TABLE); /* always valid */ + /* * PBR should maintain its own set of action flags that we * can copy here instead of trying to infer from magic values. */ - SET_FLAG(r.action.flags, PBR_ACTION_TABLE); /* always valid */ - if (pbrms->action_queue_id != PBR_MAP_UNDEFINED_QUEUE_ID) - SET_FLAG(r.action.flags, PBR_ACTION_QUEUE_ID); - if (pbrms->action_pcp != 0) - SET_FLAG(r.action.flags, PBR_ACTION_PCP); - if (pbrms->action_vlan_id != 0) - SET_FLAG(r.action.flags, PBR_ACTION_VLAN_ID); - if (pbrms->action_vlan_flags != 0) - SET_FLAG(r.action.flags, PBR_ACTION_VLAN_FLAGS); + + r.action.flags = pbrms->action_bm; /* * if the user does not use the command "set vrf name unchanged" @@ -619,9 +593,9 @@ static bool pbr_encode_pbr_map_sequence(struct stream *s, } r.action.queue_id = pbrms->action_queue_id; + r.action.pcp = pbrms->action_pcp; r.action.vlan_id = pbrms->action_vlan_id; - r.action.vlan_flags = pbrms->action_vlan_flags; strlcpy(r.ifname, ifp->name, sizeof(r.ifname)); |