summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bgpd/bgp_attr.c158
-rw-r--r--bgpd/bgp_evpn.c5
-rw-r--r--bgpd/bgp_evpn_vty.c23
-rw-r--r--bgpd/bgp_mplsvpn.c59
-rw-r--r--bgpd/bgp_route.c363
-rw-r--r--bgpd/bgp_route.h14
-rw-r--r--bgpd/bgp_vty.c2
-rw-r--r--bgpd/bgp_zebra.c1
-rw-r--r--doc/developer/workflow.rst7
-rw-r--r--doc/user/pbr.rst71
-rw-r--r--doc/user/zebra.rst9
-rw-r--r--eigrpd/eigrp_hello.c2
-rw-r--r--eigrpd/eigrp_update.c4
-rw-r--r--lib/bfd.c4
-rw-r--r--lib/event.c11
-rw-r--r--lib/frrevent.h7
-rw-r--r--lib/nexthop_group.c1
-rw-r--r--lib/pbr.h37
-rw-r--r--lib/wheel.c2
-rw-r--r--lib/zclient.c197
-rw-r--r--ospf6d/ospf6_interface.c18
-rw-r--r--ospf6d/ospf6_intra.h11
-rw-r--r--ospf6d/ospf6_lsa.c2
-rw-r--r--ospf6d/ospf6_lsdb.c2
-rw-r--r--ospf6d/ospf6_message.c18
-rw-r--r--ospf6d/ospf6_nssa.c2
-rw-r--r--ospfd/ospf_ism.h2
-rw-r--r--ospfd/ospf_lsa.c2
-rw-r--r--ospfd/ospf_nsm.h2
-rw-r--r--pbrd/pbr_map.c84
-rw-r--r--pbrd/pbr_map.h35
-rw-r--r--pbrd/pbr_nht.c2
-rw-r--r--pbrd/pbr_vty.c1506
-rw-r--r--pbrd/pbr_zebra.c61
-rw-r--r--pimd/pim6_mld.c6
-rw-r--r--pimd/pim_msg.c27
-rw-r--r--pimd/pim_nht.c41
-rw-r--r--pimd/pim_upstream.c1
-rw-r--r--pimd/pim_vxlan.c36
-rw-r--r--pimd/pim_vxlan.h3
-rw-r--r--tests/lib/test_segv.c2
-rw-r--r--tests/topotests/bgp_evpn_mh/leaf1/evpn.conf21
-rw-r--r--tests/topotests/bgp_evpn_mh/leaf1/pim.conf26
-rw-r--r--tests/topotests/bgp_evpn_mh/leaf1/zebra.conf30
-rw-r--r--tests/topotests/bgp_evpn_mh/leaf2/evpn.conf21
-rw-r--r--tests/topotests/bgp_evpn_mh/leaf2/pim.conf20
-rw-r--r--tests/topotests/bgp_evpn_mh/leaf2/zebra.conf24
-rw-r--r--tests/topotests/bgp_evpn_mh/spine1/evpn.conf12
-rw-r--r--tests/topotests/bgp_evpn_mh/spine1/pim.conf12
-rw-r--r--tests/topotests/bgp_evpn_mh/spine1/zebra.conf12
-rw-r--r--tests/topotests/bgp_evpn_mh/spine2/evpn.conf12
-rw-r--r--tests/topotests/bgp_evpn_mh/spine2/pim.conf7
-rw-r--r--tests/topotests/bgp_evpn_mh/spine2/zebra.conf14
-rw-r--r--tests/topotests/bgp_evpn_mh/test_evpn_mh.py79
-rw-r--r--tests/topotests/bgp_evpn_mh/torm11/pim.conf6
-rw-r--r--tests/topotests/bgp_evpn_mh/torm12/pim.conf6
-rw-r--r--tests/topotests/bgp_evpn_mh/torm21/pim.conf6
-rw-r--r--tests/topotests/bgp_evpn_mh/torm22/pim.conf6
-rw-r--r--tests/topotests/pbr_topo1/test_pbr_topo1.py27
-rw-r--r--tests/topotests/static_routing_mpls/r1/zebra.conf16
-rw-r--r--tests/topotests/static_routing_mpls/r2/zebra.conf18
-rw-r--r--tests/topotests/static_routing_mpls/test_static_routing_mpls.py139
-rw-r--r--yang/frr-zebra.yang6
-rw-r--r--zebra/interface.c26
-rw-r--r--zebra/redistribute.c7
-rw-r--r--zebra/rule_netlink.c4
-rw-r--r--zebra/zapi_msg.c27
-rw-r--r--zebra/zebra_fpm_netlink.c2
-rw-r--r--zebra/zebra_gr.c3
-rw-r--r--zebra/zebra_nb.c7
-rw-r--r--zebra/zebra_nb.h2
-rw-r--r--zebra/zebra_nb_config.c44
-rw-r--r--zebra/zebra_nhg.c3
-rw-r--r--zebra/zebra_pbr.c29
-rw-r--r--zebra/zebra_pbr.h2
-rw-r--r--zebra/zebra_routemap.c158
-rw-r--r--zebra/zebra_routemap.h26
77 files changed, 2540 insertions, 1160 deletions
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c
index d31e266c95..e07af4ab03 100644
--- a/bgpd/bgp_attr.c
+++ b/bgpd/bgp_attr.c
@@ -3507,27 +3507,6 @@ enum bgp_attr_parse_ret bgp_attr_parse(struct peer *peer, struct attr *attr,
else
length = stream_getc(BGP_INPUT(peer));
- /* If any attribute appears more than once in the UPDATE
- message, then the Error Subcode is set to Malformed Attribute
- List. */
-
- if (CHECK_BITMAP(seen, type)) {
- flog_warn(
- EC_BGP_ATTRIBUTE_REPEATED,
- "%s: error BGP attribute type %d appears twice in a message",
- peer->host, type);
-
- bgp_notify_send(peer, BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_MAL_ATTR);
- ret = BGP_ATTR_PARSE_ERROR;
- goto done;
- }
-
- /* Set type to bitmap to check duplicate attribute. `type' is
- unsigned char so it never overflow bitmap range. */
-
- SET_BITMAP(seen, type);
-
/* Overflow check. */
attr_endp = BGP_INPUT_PNT(peer) + length;
@@ -3537,50 +3516,107 @@ enum bgp_attr_parse_ret bgp_attr_parse(struct peer *peer, struct attr *attr,
"%s: BGP type %d length %d is too large, attribute total length is %d. attr_endp is %p. endp is %p",
peer->host, type, length, size, attr_endp,
endp);
- /*
- * RFC 4271 6.3
- * If any recognized attribute has an Attribute
- * Length that conflicts with the expected length
- * (based on the attribute type code), then the
- * Error Subcode MUST be set to Attribute Length
- * Error. The Data field MUST contain the erroneous
- * attribute (type, length, and value).
- * ----------
- * We do not currently have a good way to determine the
- * length of the attribute independent of the length
- * received in the message. Instead we send the
- * minimum between the amount of data we have and the
- * amount specified by the attribute length field.
- *
- * Instead of directly passing in the packet buffer and
- * offset we use the stream_get* functions to read into
- * a stack buffer, since they perform bounds checking
- * and we are working with untrusted data.
- */
- unsigned char ndata[peer->max_packet_size];
- memset(ndata, 0x00, sizeof(ndata));
- size_t lfl =
- CHECK_FLAG(flag, BGP_ATTR_FLAG_EXTLEN) ? 2 : 1;
- /* Rewind to end of flag field */
- stream_rewind_getp(BGP_INPUT(peer), (1 + lfl));
- /* Type */
- stream_get(&ndata[0], BGP_INPUT(peer), 1);
- /* Length */
- stream_get(&ndata[1], BGP_INPUT(peer), lfl);
- /* Value */
- size_t atl = attr_endp - startp;
- size_t ndl = MIN(atl, STREAM_READABLE(BGP_INPUT(peer)));
- stream_get(&ndata[lfl + 1], BGP_INPUT(peer), ndl);
- bgp_notify_send_with_data(
- peer, BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, ndata,
- ndl + lfl + 1);
+ /* Only relax error handling for eBGP peers */
+ if (peer->sort != BGP_PEER_EBGP) {
+ /*
+ * RFC 4271 6.3
+ * If any recognized attribute has an Attribute
+ * Length that conflicts with the expected length
+ * (based on the attribute type code), then the
+ * Error Subcode MUST be set to Attribute Length
+ * Error. The Data field MUST contain the erroneous
+ * attribute (type, length, and value).
+ * ----------
+ * We do not currently have a good way to determine the
+ * length of the attribute independent of the length
+ * received in the message. Instead we send the
+ * minimum between the amount of data we have and the
+ * amount specified by the attribute length field.
+ *
+ * Instead of directly passing in the packet buffer and
+ * offset we use the stream_get* functions to read into
+ * a stack buffer, since they perform bounds checking
+ * and we are working with untrusted data.
+ */
+ unsigned char ndata[peer->max_packet_size];
+
+ memset(ndata, 0x00, sizeof(ndata));
+ size_t lfl =
+ CHECK_FLAG(flag, BGP_ATTR_FLAG_EXTLEN) ? 2 : 1;
+ /* Rewind to end of flag field */
+ stream_rewind_getp(BGP_INPUT(peer), (1 + lfl));
+ /* Type */
+ stream_get(&ndata[0], BGP_INPUT(peer), 1);
+ /* Length */
+ stream_get(&ndata[1], BGP_INPUT(peer), lfl);
+ /* Value */
+ size_t atl = attr_endp - startp;
+ size_t ndl = MIN(atl, STREAM_READABLE(BGP_INPUT(peer)));
+
+ stream_get(&ndata[lfl + 1], BGP_INPUT(peer), ndl);
+
+ bgp_notify_send_with_data(
+ peer, BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, ndata,
+ ndl + lfl + 1);
+
+ ret = BGP_ATTR_PARSE_ERROR;
+ goto done;
+ } else {
+ /* Handling as per RFC7606 section 4, treat-as-withdraw approach
+ * must be followed when the total attribute length is in conflict
+ * with the enclosed path attribute length.
+ */
+ flog_warn(
+ EC_BGP_ATTRIBUTE_PARSE_WITHDRAW,
+ "%s: Attribute %s, parse error - treating as withdrawal",
+ peer->host, lookup_msg(attr_str, type, NULL));
+ ret = BGP_ATTR_PARSE_WITHDRAW;
+ stream_forward_getp(BGP_INPUT(peer), endp - BGP_INPUT_PNT(peer));
+ goto done;
+ }
+ }
- ret = BGP_ATTR_PARSE_ERROR;
- goto done;
+ /* If attribute appears more than once in the UPDATE message,
+ * for MP_REACH_NLRI & MP_UNREACH_NLRI attributes
+ * the Error Subcode is set to Malformed Attribute List.
+ * For all other attributes, all the occurances of the attribute
+ * other than the first occurence is discarded. (RFC7606 3g)
+ */
+
+ if (CHECK_BITMAP(seen, type)) {
+ /* Only relax error handling for eBGP peers */
+ if (peer->sort != BGP_PEER_EBGP ||
+ type == BGP_ATTR_MP_REACH_NLRI || type == BGP_ATTR_MP_UNREACH_NLRI) {
+ flog_warn(
+ EC_BGP_ATTRIBUTE_REPEATED,
+ "%s: error BGP attribute type %d appears twice in a message",
+ peer->host, type);
+
+ bgp_notify_send(peer, BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_MAL_ATTR);
+ ret = BGP_ATTR_PARSE_ERROR;
+ goto done;
+ } else {
+ flog_warn(
+ EC_BGP_ATTRIBUTE_REPEATED,
+ "%s: error BGP attribute type %d appears twice in a message - discard attribute",
+ peer->host, type);
+ /* Adjust the stream getp to the end of the attribute, in case we
+ * haven't read all the attributes.
+ */
+ stream_set_getp(BGP_INPUT(peer),
+ (startp - STREAM_DATA(BGP_INPUT(peer))) + (attr_endp - startp));
+ continue;
+ }
}
+ /* Set type to bitmap to check duplicate attribute. `type' is
+ unsigned char so it never overflow bitmap range. */
+
+ SET_BITMAP(seen, type);
+
struct bgp_attr_parser_args attr_args = {
.peer = peer,
.length = length,
diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c
index 35f2438929..3442eee1e1 100644
--- a/bgpd/bgp_evpn.c
+++ b/bgpd/bgp_evpn.c
@@ -3757,8 +3757,11 @@ static int install_uninstall_routes_for_vrf(struct bgp *bgp_vrf, int install)
pi = pi->next) {
ret = bgp_evpn_route_entry_install_if_vrf_match(
bgp_vrf, pi, install);
- if (ret)
+ if (ret) {
+ bgp_dest_unlock_node(rd_dest);
+ bgp_dest_unlock_node(dest);
return ret;
+ }
}
}
}
diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c
index 8b4f4509ae..2f158ab1be 100644
--- a/bgpd/bgp_evpn_vty.c
+++ b/bgpd/bgp_evpn_vty.c
@@ -2081,12 +2081,12 @@ DEFUN(evpnrt5_network,
int idx_ethtag = 5;
int idx_routermac = 13;
- return bgp_static_set_safi(
- AFI_L2VPN, SAFI_EVPN, vty, argv[idx_ipv4_prefixlen]->arg,
- argv[idx_route_distinguisher]->arg, argv[idx_label]->arg, NULL,
- BGP_EVPN_IP_PREFIX_ROUTE, argv[idx_esi]->arg,
- argv[idx_gwip]->arg, argv[idx_ethtag]->arg,
- argv[idx_routermac]->arg);
+ return bgp_static_set(vty, false, argv[idx_ipv4_prefixlen]->arg,
+ argv[idx_route_distinguisher]->arg,
+ argv[idx_label]->arg, AFI_L2VPN, SAFI_EVPN, NULL,
+ 0, 0, BGP_EVPN_IP_PREFIX_ROUTE,
+ argv[idx_esi]->arg, argv[idx_gwip]->arg,
+ argv[idx_ethtag]->arg, argv[idx_routermac]->arg);
}
/* For testing purpose, static route of EVPN RT-5. */
@@ -2113,11 +2113,12 @@ DEFUN(no_evpnrt5_network,
int idx_ethtag = 6;
int idx_esi = 10;
int idx_gwip = 12;
- return bgp_static_unset_safi(
- AFI_L2VPN, SAFI_EVPN, vty, argv[idx_ipv4_prefixlen]->arg,
- argv[idx_ext_community]->arg, argv[idx_label]->arg,
- BGP_EVPN_IP_PREFIX_ROUTE, argv[idx_esi]->arg,
- argv[idx_gwip]->arg, argv[idx_ethtag]->arg);
+
+ return bgp_static_set(vty, true, argv[idx_ipv4_prefixlen]->arg,
+ argv[idx_ext_community]->arg,
+ argv[idx_label]->arg, AFI_L2VPN, SAFI_EVPN, NULL,
+ 0, 0, BGP_EVPN_IP_PREFIX_ROUTE, argv[idx_esi]->arg,
+ argv[idx_gwip]->arg, argv[idx_ethtag]->arg, NULL);
}
static void evpn_import_rt_delete_auto(struct bgp *bgp, struct bgpevpn *vpn)
diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c
index ad66720512..3ecb72b4ef 100644
--- a/bgpd/bgp_mplsvpn.c
+++ b/bgpd/bgp_mplsvpn.c
@@ -3011,10 +3011,11 @@ DEFUN (vpnv4_network,
int idx_ipv4_prefixlen = 1;
int idx_ext_community = 3;
int idx_label = 5;
- return bgp_static_set_safi(
- AFI_IP, SAFI_MPLS_VPN, vty, argv[idx_ipv4_prefixlen]->arg,
- argv[idx_ext_community]->arg, argv[idx_label]->arg, NULL, 0,
- NULL, NULL, NULL, NULL);
+
+ return bgp_static_set(vty, false, argv[idx_ipv4_prefixlen]->arg,
+ argv[idx_ext_community]->arg,
+ argv[idx_label]->arg, AFI_IP, SAFI_MPLS_VPN, NULL,
+ 0, 0, 0, NULL, NULL, NULL, NULL);
}
DEFUN (vpnv4_network_route_map,
@@ -3033,11 +3034,12 @@ DEFUN (vpnv4_network_route_map,
int idx_ipv4_prefixlen = 1;
int idx_ext_community = 3;
int idx_label = 5;
- int idx_word_2 = 7;
- return bgp_static_set_safi(
- AFI_IP, SAFI_MPLS_VPN, vty, argv[idx_ipv4_prefixlen]->arg,
- argv[idx_ext_community]->arg, argv[idx_label]->arg,
- argv[idx_word_2]->arg, 0, NULL, NULL, NULL, NULL);
+ int idx_rmap = 7;
+
+ return bgp_static_set(vty, false, argv[idx_ipv4_prefixlen]->arg,
+ argv[idx_ext_community]->arg, argv[idx_label]->arg,
+ AFI_IP, SAFI_MPLS_VPN, argv[idx_rmap]->arg, 0, 0,
+ 0, NULL, NULL, NULL, NULL);
}
/* For testing purpose, static route of MPLS-VPN. */
@@ -3056,10 +3058,11 @@ DEFUN (no_vpnv4_network,
int idx_ipv4_prefixlen = 2;
int idx_ext_community = 4;
int idx_label = 6;
- return bgp_static_unset_safi(AFI_IP, SAFI_MPLS_VPN, vty,
- argv[idx_ipv4_prefixlen]->arg,
- argv[idx_ext_community]->arg,
- argv[idx_label]->arg, 0, NULL, NULL, NULL);
+
+ return bgp_static_set(vty, true, argv[idx_ipv4_prefixlen]->arg,
+ argv[idx_ext_community]->arg,
+ argv[idx_label]->arg, AFI_IP, SAFI_MPLS_VPN, NULL,
+ 0, 0, 0, NULL, NULL, NULL, NULL);
}
DEFUN (vpnv6_network,
@@ -3078,17 +3081,20 @@ DEFUN (vpnv6_network,
int idx_ipv6_prefix = 1;
int idx_ext_community = 3;
int idx_label = 5;
- int idx_word_2 = 7;
+ int idx_rmap = 7;
+
if (argc == 8)
- return bgp_static_set_safi(
- AFI_IP6, SAFI_MPLS_VPN, vty, argv[idx_ipv6_prefix]->arg,
- argv[idx_ext_community]->arg, argv[idx_label]->arg,
- argv[idx_word_2]->arg, 0, NULL, NULL, NULL, NULL);
+ return bgp_static_set(vty, false, argv[idx_ipv6_prefix]->arg,
+ argv[idx_ext_community]->arg,
+ argv[idx_label]->arg, AFI_IP6,
+ SAFI_MPLS_VPN, argv[idx_rmap]->arg, 0, 0,
+ 0, NULL, NULL, NULL, NULL);
else
- return bgp_static_set_safi(
- AFI_IP6, SAFI_MPLS_VPN, vty, argv[idx_ipv6_prefix]->arg,
- argv[idx_ext_community]->arg, argv[idx_label]->arg,
- NULL, 0, NULL, NULL, NULL, NULL);
+ return bgp_static_set(vty, false, argv[idx_ipv6_prefix]->arg,
+ argv[idx_ext_community]->arg,
+ argv[idx_label]->arg, AFI_IP6,
+ SAFI_MPLS_VPN, NULL, 0, 0, 0, NULL, NULL,
+ NULL, NULL);
}
/* For testing purpose, static route of MPLS-VPN. */
@@ -3107,10 +3113,11 @@ DEFUN (no_vpnv6_network,
int idx_ipv6_prefix = 2;
int idx_ext_community = 4;
int idx_label = 6;
- return bgp_static_unset_safi(AFI_IP6, SAFI_MPLS_VPN, vty,
- argv[idx_ipv6_prefix]->arg,
- argv[idx_ext_community]->arg,
- argv[idx_label]->arg, 0, NULL, NULL, NULL);
+
+ return bgp_static_set(vty, true, argv[idx_ipv6_prefix]->arg,
+ argv[idx_ext_community]->arg,
+ argv[idx_label]->arg, AFI_IP6, SAFI_MPLS_VPN,
+ NULL, 0, 0, 0, NULL, NULL, NULL, NULL);
}
int bgp_show_mpls_vpn(struct vty *vty, afi_t afi, struct prefix_rd *prd,
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index e104aac870..457db79c43 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -6571,16 +6571,23 @@ void bgp_static_withdraw(struct bgp *bgp, const struct prefix *p, afi_t afi,
/* Configure static BGP network. When user don't run zebra, static
route should be installed as valid. */
-static int bgp_static_set(struct vty *vty, const char *negate,
- const char *ip_str, afi_t afi, safi_t safi,
- const char *rmap, int backdoor, uint32_t label_index)
+int bgp_static_set(struct vty *vty, bool negate, const char *ip_str,
+ const char *rd_str, const char *label_str, afi_t afi,
+ safi_t safi, const char *rmap, int backdoor,
+ uint32_t label_index, int evpn_type, const char *esi,
+ const char *gwip, const char *ethtag, const char *routermac)
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
int ret;
struct prefix p;
struct bgp_static *bgp_static;
+ struct prefix_rd prd;
+ struct bgp_dest *pdest;
struct bgp_dest *dest;
+ struct bgp_table *table;
uint8_t need_update = 0;
+ mpls_label_t label = MPLS_INVALID_LABEL;
+ struct prefix gw_ip;
/* Convert IP prefix string to struct prefix. */
ret = str2prefix(ip_str, &p);
@@ -6595,8 +6602,69 @@ static int bgp_static_set(struct vty *vty, const char *negate,
apply_mask(&p);
- if (negate) {
+ if (afi == AFI_L2VPN &&
+ (bgp_build_evpn_prefix(evpn_type, ethtag != NULL ? atol(ethtag) : 0,
+ &p))) {
+ vty_out(vty, "%% L2VPN prefix could not be forged\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ if (safi == SAFI_MPLS_VPN || safi == SAFI_EVPN) {
+ ret = str2prefix_rd(rd_str, &prd);
+ if (!ret) {
+ vty_out(vty, "%% Malformed rd\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ if (label_str) {
+ unsigned long label_val;
+
+ label_val = strtoul(label_str, NULL, 10);
+ encode_label(label_val, &label);
+ }
+ }
+
+ if (safi == SAFI_EVPN) {
+ if (esi && str2esi(esi, NULL) == 0) {
+ vty_out(vty, "%% Malformed ESI\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+ if (routermac && prefix_str2mac(routermac, NULL) == 0) {
+ vty_out(vty, "%% Malformed Router MAC\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+ if (gwip) {
+ memset(&gw_ip, 0, sizeof(gw_ip));
+ ret = str2prefix(gwip, &gw_ip);
+ if (!ret) {
+ vty_out(vty, "%% Malformed GatewayIp\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+ if ((gw_ip.family == AF_INET &&
+ is_evpn_prefix_ipaddr_v6((struct prefix_evpn *)&p)) ||
+ (gw_ip.family == AF_INET6 &&
+ is_evpn_prefix_ipaddr_v4(
+ (struct prefix_evpn *)&p))) {
+ vty_out(vty,
+ "%% GatewayIp family differs with IP prefix\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+ }
+ }
+ if (safi == SAFI_MPLS_VPN || safi == SAFI_EVPN) {
+ pdest = bgp_node_get(bgp->route[afi][safi],
+ (struct prefix *)&prd);
+ if (!bgp_dest_has_bgp_path_info_data(pdest))
+ bgp_dest_set_bgp_table_info(pdest,
+ bgp_table_init(bgp, afi,
+ safi));
+ table = bgp_dest_get_bgp_table_info(pdest);
+ } else {
+ table = bgp->route[afi][safi];
+ }
+
+ if (negate) {
/* Set BGP static route configuration. */
dest = bgp_node_lookup(bgp->route[afi][safi], &p);
@@ -6606,36 +6674,37 @@ static int bgp_static_set(struct vty *vty, const char *negate,
}
bgp_static = bgp_dest_get_bgp_static_info(dest);
+ if (bgp_static) {
+ if ((label_index != BGP_INVALID_LABEL_INDEX) &&
+ (label_index != bgp_static->label_index)) {
+ vty_out(vty,
+ "%% label-index doesn't match static route\n");
+ bgp_dest_unlock_node(dest);
+ return CMD_WARNING_CONFIG_FAILED;
+ }
- if ((label_index != BGP_INVALID_LABEL_INDEX)
- && (label_index != bgp_static->label_index)) {
- vty_out(vty,
- "%% label-index doesn't match static route\n");
- bgp_dest_unlock_node(dest);
- return CMD_WARNING_CONFIG_FAILED;
- }
+ if ((rmap && bgp_static->rmap.name) &&
+ strcmp(rmap, bgp_static->rmap.name)) {
+ vty_out(vty,
+ "%% route-map name doesn't match static route\n");
+ bgp_dest_unlock_node(dest);
+ return CMD_WARNING_CONFIG_FAILED;
+ }
- if ((rmap && bgp_static->rmap.name)
- && strcmp(rmap, bgp_static->rmap.name)) {
- vty_out(vty,
- "%% route-map name doesn't match static route\n");
- bgp_dest_unlock_node(dest);
- return CMD_WARNING_CONFIG_FAILED;
- }
+ /* Update BGP RIB. */
+ if (!bgp_static->backdoor)
+ bgp_static_withdraw(bgp, &p, afi, safi, NULL);
- /* Update BGP RIB. */
- if (!bgp_static->backdoor)
- bgp_static_withdraw(bgp, &p, afi, safi, NULL);
+ /* Clear configuration. */
+ bgp_static_free(bgp_static);
+ }
- /* Clear configuration. */
- bgp_static_free(bgp_static);
bgp_dest_set_bgp_static_info(dest, NULL);
bgp_dest_unlock_node(dest);
bgp_dest_unlock_node(dest);
} else {
+ dest = bgp_node_get(table, &p);
- /* Set BGP static route configuration. */
- dest = bgp_node_get(bgp->route[afi][safi], &p);
bgp_static = bgp_dest_get_bgp_static_info(dest);
if (bgp_static) {
/* Configuration change. */
@@ -6681,6 +6750,8 @@ static int bgp_static_set(struct vty *vty, const char *negate,
bgp_static->igpmetric = 0;
bgp_static->igpnexthop.s_addr = INADDR_ANY;
bgp_static->label_index = label_index;
+ bgp_static->label = label;
+ bgp_static->prd = prd;
if (rmap) {
XFREE(MTYPE_ROUTE_MAP_NAME,
@@ -6694,6 +6765,26 @@ static int bgp_static_set(struct vty *vty, const char *negate,
route_map_counter_increment(
bgp_static->rmap.map);
}
+
+ if (safi == SAFI_EVPN) {
+ if (esi) {
+ bgp_static->eth_s_id =
+ XCALLOC(MTYPE_ATTR,
+ sizeof(esi_t));
+ str2esi(esi, bgp_static->eth_s_id);
+ }
+ if (routermac) {
+ bgp_static->router_mac =
+ XCALLOC(MTYPE_ATTR,
+ ETH_ALEN + 1);
+ (void)prefix_str2mac(routermac,
+ bgp_static->router_mac);
+ }
+ if (gwip)
+ prefix_copy(&bgp_static->gatewayIp,
+ &gw_ip);
+ }
+
bgp_dest_set_bgp_static_info(dest, bgp_static);
}
@@ -6888,205 +6979,6 @@ void bgp_purge_static_redist_routes(struct bgp *bgp)
bgp_purge_af_static_redist_routes(bgp, afi, safi);
}
-/*
- * gpz 110624
- * Currently this is used to set static routes for VPN and ENCAP.
- * I think it can probably be factored with bgp_static_set.
- */
-int bgp_static_set_safi(afi_t afi, safi_t safi, struct vty *vty,
- const char *ip_str, const char *rd_str,
- const char *label_str, const char *rmap_str,
- int evpn_type, const char *esi, const char *gwip,
- const char *ethtag, const char *routermac)
-{
- VTY_DECLVAR_CONTEXT(bgp, bgp);
- int ret;
- struct prefix p;
- struct prefix_rd prd;
- struct bgp_dest *pdest;
- struct bgp_dest *dest;
- struct bgp_table *table;
- struct bgp_static *bgp_static;
- mpls_label_t label = MPLS_INVALID_LABEL;
- struct prefix gw_ip;
-
- /* validate ip prefix */
- ret = str2prefix(ip_str, &p);
- if (!ret) {
- vty_out(vty, "%% Malformed prefix\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
- apply_mask(&p);
- if ((afi == AFI_L2VPN)
- && (bgp_build_evpn_prefix(evpn_type,
- ethtag != NULL ? atol(ethtag) : 0, &p))) {
- vty_out(vty, "%% L2VPN prefix could not be forged\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
-
- ret = str2prefix_rd(rd_str, &prd);
- if (!ret) {
- vty_out(vty, "%% Malformed rd\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
-
- if (label_str) {
- unsigned long label_val;
- label_val = strtoul(label_str, NULL, 10);
- encode_label(label_val, &label);
- }
-
- if (safi == SAFI_EVPN) {
- if (esi && str2esi(esi, NULL) == 0) {
- vty_out(vty, "%% Malformed ESI\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
- if (routermac && prefix_str2mac(routermac, NULL) == 0) {
- vty_out(vty, "%% Malformed Router MAC\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
- if (gwip) {
- memset(&gw_ip, 0, sizeof(gw_ip));
- ret = str2prefix(gwip, &gw_ip);
- if (!ret) {
- vty_out(vty, "%% Malformed GatewayIp\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
- if ((gw_ip.family == AF_INET
- && is_evpn_prefix_ipaddr_v6(
- (struct prefix_evpn *)&p))
- || (gw_ip.family == AF_INET6
- && is_evpn_prefix_ipaddr_v4(
- (struct prefix_evpn *)&p))) {
- vty_out(vty,
- "%% GatewayIp family differs with IP prefix\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
- }
- }
- pdest = bgp_node_get(bgp->route[afi][safi], (struct prefix *)&prd);
- if (!bgp_dest_has_bgp_path_info_data(pdest))
- bgp_dest_set_bgp_table_info(pdest,
- bgp_table_init(bgp, afi, safi));
- table = bgp_dest_get_bgp_table_info(pdest);
-
- dest = bgp_node_get(table, &p);
-
- if (bgp_dest_has_bgp_path_info_data(dest)) {
- vty_out(vty, "%% Same network configuration exists\n");
- bgp_dest_unlock_node(dest);
- } else {
- /* New configuration. */
- bgp_static = bgp_static_new();
- bgp_static->backdoor = 0;
- bgp_static->valid = 0;
- bgp_static->igpmetric = 0;
- bgp_static->igpnexthop.s_addr = INADDR_ANY;
- bgp_static->label = label;
- bgp_static->prd = prd;
-
- bgp_static->prd_pretty = XSTRDUP(MTYPE_BGP, rd_str);
-
- if (rmap_str) {
- XFREE(MTYPE_ROUTE_MAP_NAME, bgp_static->rmap.name);
- route_map_counter_decrement(bgp_static->rmap.map);
- bgp_static->rmap.name =
- XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap_str);
- bgp_static->rmap.map =
- route_map_lookup_by_name(rmap_str);
- route_map_counter_increment(bgp_static->rmap.map);
- }
-
- if (safi == SAFI_EVPN) {
- if (esi) {
- bgp_static->eth_s_id =
- XCALLOC(MTYPE_ATTR,
- sizeof(esi_t));
- str2esi(esi, bgp_static->eth_s_id);
- }
- if (routermac) {
- bgp_static->router_mac =
- XCALLOC(MTYPE_ATTR, ETH_ALEN + 1);
- (void)prefix_str2mac(routermac,
- bgp_static->router_mac);
- }
- if (gwip)
- prefix_copy(&bgp_static->gatewayIp, &gw_ip);
- }
- bgp_dest_set_bgp_static_info(dest, bgp_static);
-
- bgp_static->valid = 1;
- bgp_static_update(bgp, &p, bgp_static, afi, safi);
- }
-
- return CMD_SUCCESS;
-}
-
-/* Configure static BGP network. */
-int bgp_static_unset_safi(afi_t afi, safi_t safi, struct vty *vty,
- const char *ip_str, const char *rd_str,
- const char *label_str, int evpn_type, const char *esi,
- const char *gwip, const char *ethtag)
-{
- VTY_DECLVAR_CONTEXT(bgp, bgp);
- int ret;
- struct prefix p;
- struct prefix_rd prd;
- struct bgp_dest *pdest;
- struct bgp_dest *dest;
- struct bgp_table *table;
- struct bgp_static *bgp_static;
- mpls_label_t label = MPLS_INVALID_LABEL;
-
- /* Convert IP prefix string to struct prefix. */
- ret = str2prefix(ip_str, &p);
- if (!ret) {
- vty_out(vty, "%% Malformed prefix\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
- apply_mask(&p);
- if ((afi == AFI_L2VPN)
- && (bgp_build_evpn_prefix(evpn_type,
- ethtag != NULL ? atol(ethtag) : 0, &p))) {
- vty_out(vty, "%% L2VPN prefix could not be forged\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
- ret = str2prefix_rd(rd_str, &prd);
- if (!ret) {
- vty_out(vty, "%% Malformed rd\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
-
- if (label_str) {
- unsigned long label_val;
- label_val = strtoul(label_str, NULL, 10);
- encode_label(label_val, &label);
- }
-
- pdest = bgp_node_get(bgp->route[afi][safi], (struct prefix *)&prd);
- if (!bgp_dest_has_bgp_path_info_data(pdest))
- bgp_dest_set_bgp_table_info(pdest,
- bgp_table_init(bgp, afi, safi));
- else
- bgp_dest_unlock_node(pdest);
- table = bgp_dest_get_bgp_table_info(pdest);
-
- dest = bgp_node_lookup(table, &p);
-
- if (dest) {
- bgp_static_withdraw(bgp, &p, afi, safi, &prd);
-
- bgp_static = bgp_dest_get_bgp_static_info(dest);
- bgp_static_free(bgp_static);
- bgp_dest_set_bgp_static_info(dest, NULL);
- bgp_dest_unlock_node(dest);
- bgp_dest_unlock_node(dest);
- } else
- vty_out(vty, "%% Can't find the route\n");
-
- return CMD_SUCCESS;
-}
-
static int bgp_table_map_set(struct vty *vty, afi_t afi, safi_t safi,
const char *rmap_name)
{
@@ -7192,10 +7084,13 @@ DEFPY(bgp_network,
}
}
- return bgp_static_set(
- vty, no, address_str ? addr_prefix_str : prefix_str, AFI_IP,
- bgp_node_safi(vty), map_name, backdoor ? 1 : 0,
- label_index ? (uint32_t)label_index : BGP_INVALID_LABEL_INDEX);
+ return bgp_static_set(vty, no,
+ address_str ? addr_prefix_str : prefix_str, NULL,
+ NULL, AFI_IP, bgp_node_safi(vty), map_name,
+ backdoor ? 1 : 0,
+ label_index ? (uint32_t)label_index
+ : BGP_INVALID_LABEL_INDEX,
+ 0, NULL, NULL, NULL, NULL);
}
DEFPY(ipv6_bgp_network,
@@ -7210,9 +7105,11 @@ DEFPY(ipv6_bgp_network,
"Label index to associate with the prefix\n"
"Label index value\n")
{
- return bgp_static_set(
- vty, no, prefix_str, AFI_IP6, bgp_node_safi(vty), map_name, 0,
- label_index ? (uint32_t)label_index : BGP_INVALID_LABEL_INDEX);
+ return bgp_static_set(vty, no, prefix_str, NULL, NULL, AFI_IP6,
+ bgp_node_safi(vty), map_name, 0,
+ label_index ? (uint32_t)label_index
+ : BGP_INVALID_LABEL_INDEX,
+ 0, NULL, NULL, NULL, NULL);
}
static struct bgp_aggregate *bgp_aggregate_new(void)
@@ -13457,7 +13354,7 @@ static int bgp_table_stats_single(struct vty *vty, struct bgp *bgp, afi_t afi,
memset(&ts, 0, sizeof(ts));
ts.table = bgp->rib[afi][safi];
- event_execute(bm->master, bgp_table_stats_walker, &ts, 0);
+ event_execute(bm->master, bgp_table_stats_walker, &ts, 0, NULL);
for (i = 0; i < BGP_STATS_MAX; i++) {
if ((!json && !table_stats_strs[i][TABLE_STATS_IDX_VTY])
@@ -13814,7 +13711,7 @@ static int bgp_peer_counts(struct vty *vty, struct peer *peer, afi_t afi,
* stats for the thread-walk (i.e. ensure this can't be blamed on
* on just vty_read()).
*/
- event_execute(bm->master, bgp_peer_count_walker, &pcounts, 0);
+ event_execute(bm->master, bgp_peer_count_walker, &pcounts, 0, NULL);
if (use_json) {
json_object_string_add(json, "prefixCountsFor", peer->host);
diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h
index 0a6f535b22..f424e6d286 100644
--- a/bgpd/bgp_route.h
+++ b/bgpd/bgp_route.h
@@ -762,14 +762,12 @@ extern void bgp_static_update(struct bgp *bgp, const struct prefix *p,
extern void bgp_static_withdraw(struct bgp *bgp, const struct prefix *p,
afi_t afi, safi_t safi, struct prefix_rd *prd);
-extern int bgp_static_set_safi(afi_t afi, safi_t safi, struct vty *vty,
- const char *, const char *, const char *,
- const char *, int, const char *, const char *,
- const char *, const char *);
-
-extern int bgp_static_unset_safi(afi_t afi, safi_t safi, struct vty *,
- const char *, const char *, const char *, int,
- const char *, const char *, const char *);
+extern int bgp_static_set(struct vty *vty, bool negate, const char *ip_str,
+ const char *rd_str, const char *label_str, afi_t afi,
+ safi_t safi, const char *rmap, int backdoor,
+ uint32_t label_index, int evpn_type, const char *esi,
+ const char *gwip, const char *ethtag,
+ const char *routermac);
/* this is primarily for MPLS-VPN */
extern void bgp_update(struct peer *peer, const struct prefix *p,
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index 573abf0cda..9c09ca0efd 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -7607,7 +7607,7 @@ DEFUN (bgp_set_route_map_delay_timer,
if (!rmap_delay_timer && bm->t_rmap_update) {
EVENT_OFF(bm->t_rmap_update);
event_execute(bm->master, bgp_route_map_update_timer,
- NULL, 0);
+ NULL, 0, NULL);
}
return CMD_SUCCESS;
} else {
diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c
index ea7168f749..21ccbebe67 100644
--- a/bgpd/bgp_zebra.c
+++ b/bgpd/bgp_zebra.c
@@ -2760,6 +2760,7 @@ static void bgp_encode_pbr_rule_action(struct stream *s,
else
r.unique = pbra->unique;
+ r.family = fam;
/* filter */
diff --git a/doc/developer/workflow.rst b/doc/developer/workflow.rst
index 6efe5f42f6..5199d42db3 100644
--- a/doc/developer/workflow.rst
+++ b/doc/developer/workflow.rst
@@ -761,6 +761,13 @@ following requirements have achieved consensus:
tools can catch uninitialized value use that would otherwise be suppressed by
the (incorrect) zero initialization.
+- Usage of ``system()`` or other c library routines that cause signals to
+ possibly be ignored are not allowed. This includes the ``fork()`` and
+ ``execXX`` call patterns, which is actually what system() does underneath
+ the covers. This pattern causes the system shutdown to never work properly
+ as the SIGINT sent is never received. It is better to just prohibit code
+ that does this instead of having to debug shutdown issues again.
+
Other than these specific rules, coding practices from the Linux kernel as
well as CERT or MISRA C guidelines may provide useful input on safe C code.
However, these rules are not applied as-is; some of them expressly collide
diff --git a/doc/user/pbr.rst b/doc/user/pbr.rst
index 17f3504898..d0513018e3 100644
--- a/doc/user/pbr.rst
+++ b/doc/user/pbr.rst
@@ -161,6 +161,26 @@ specified in the rule are also applied to the packet.
VLAN-matching facilities,
so this field will be ignored unless other dataplane providers are used.
+.. clicmd:: set nexthop-group NAME
+
+ Action:
+ forward the packet using nexthop-group NAME.
+
+.. clicmd:: set nexthop [A.B.C.D|X:X::X:XX|blackhole] [interface] [nexthop-vrf NAME]
+
+ Action:
+ forward the packet using the specified single nexthop.
+ If `blackhole`, packets will be sent to a blackhole route and dropped.
+
+.. clicmd:: set vrf unchanged|NAME
+
+ Action:
+ If set to ``unchanged``, the rule will use the vrf table the interface
+ is in as its lookup.
+ If set to NAME, the rule will use that vrf table as its lookup.
+
+ Not supported with NETNS VRF backend.
+
.. clicmd:: set queue-id (1-65535)
Action:
@@ -195,24 +215,57 @@ 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 nexthop-group NAME
+.. clicmd:: set src-ip [A.B.C.D/M|X:X::X:X/M]
Action:
- forward the packet using nexthop-group NAME.
+ 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 nexthop [A.B.C.D|X:X::X:XX] [interface] [nexthop-vrf NAME]
+.. clicmd:: set dst-ip [A.B.C.D/M|X:X::X:X/M]
Action:
- forward the packet using the specified single nexthop.
+ 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 vrf unchanged|NAME
+.. clicmd:: set src-port (1-65535)
Action:
- If set to ``unchanged``, the rule will use the vrf table the interface
- is in as its lookup.
- If set to NAME, the rule will use that vrf table as its lookup.
+ 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.
- Not supported with NETNS VRF backend.
+.. 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]
diff --git a/doc/user/zebra.rst b/doc/user/zebra.rst
index 32de3e908f..39add2235f 100644
--- a/doc/user/zebra.rst
+++ b/doc/user/zebra.rst
@@ -163,12 +163,13 @@ Standard Commands
Set description for the interface.
-.. clicmd:: mpls enable
+.. clicmd:: mpls <enable|disable>
- Enable or disable mpls kernel processing on the interface, for linux. Interfaces
+ Choose mpls kernel processing value on the interface, for linux. Interfaces
configured with mpls will not automatically turn on if mpls kernel modules do not
- happen to be loaded. This command will fail on 3.X linux kernels and does not
- work on non-linux systems at all.
+ happen to be loaded. This command will fail on 3.X linux kernels and does not
+ work on non-linux systems at all. 'enable' and 'disable' will respectively turn
+ on and off mpls on the given interface.
.. clicmd:: multicast
diff --git a/eigrpd/eigrp_hello.c b/eigrpd/eigrp_hello.c
index 662c750e96..ee0e2451a2 100644
--- a/eigrpd/eigrp_hello.c
+++ b/eigrpd/eigrp_hello.c
@@ -772,7 +772,7 @@ void eigrp_hello_send(struct eigrp_interface *ei, uint8_t flags,
if (ei->eigrp->t_write == NULL) {
if (flags & EIGRP_HELLO_GRACEFUL_SHUTDOWN) {
event_execute(master, eigrp_write, ei->eigrp,
- ei->eigrp->fd);
+ ei->eigrp->fd, NULL);
} else {
event_add_write(master, eigrp_write, ei->eigrp,
ei->eigrp->fd,
diff --git a/eigrpd/eigrp_update.c b/eigrpd/eigrp_update.c
index a056267bf7..74f573d9d8 100644
--- a/eigrpd/eigrp_update.c
+++ b/eigrpd/eigrp_update.c
@@ -913,7 +913,7 @@ void eigrp_update_send_GR_thread(struct event *thread)
/* if it wasn't last chunk, schedule this thread again */
if (nbr->nbr_gr_packet_type != EIGRP_PACKET_PART_LAST) {
- event_execute(master, eigrp_update_send_GR_thread, nbr, 0);
+ event_execute(master, eigrp_update_send_GR_thread, nbr, 0, NULL);
}
}
@@ -979,7 +979,7 @@ void eigrp_update_send_GR(struct eigrp_neighbor *nbr, enum GR_type gr_type,
/* indicate, that this is first GR Update packet chunk */
nbr->nbr_gr_packet_type = EIGRP_PACKET_PART_FIRST;
/* execute packet sending in thread */
- event_execute(master, eigrp_update_send_GR_thread, nbr, 0);
+ event_execute(master, eigrp_update_send_GR_thread, nbr, 0, NULL);
}
/**
diff --git a/lib/bfd.c b/lib/bfd.c
index cc6d09a60f..8c3246ff9a 100644
--- a/lib/bfd.c
+++ b/lib/bfd.c
@@ -541,7 +541,7 @@ static void _bfd_sess_remove(struct bfd_session_params *bsp)
/* Send request to remove any session. */
bsp->lastev = BSE_UNINSTALL;
- event_execute(bsglobal.tm, _bfd_sess_send, bsp, 0);
+ event_execute(bsglobal.tm, _bfd_sess_send, bsp, 0, NULL);
}
void bfd_sess_free(struct bfd_session_params **bsp)
@@ -894,7 +894,7 @@ int zclient_bfd_session_replay(ZAPI_CALLBACK_ARGS)
/* Ask for installation. */
bsp->lastev = BSE_INSTALL;
- event_execute(bsglobal.tm, _bfd_sess_send, bsp, 0);
+ event_execute(bsglobal.tm, _bfd_sess_send, bsp, 0, NULL);
}
return 0;
diff --git a/lib/event.c b/lib/event.c
index 14b1564a2f..4b4ca9d7ea 100644
--- a/lib/event.c
+++ b/lib/event.c
@@ -1475,9 +1475,9 @@ void event_cancel(struct event **thread)
cr->thread = *thread;
listnode_add(master->cancel_req, cr);
do_event_cancel(master);
- }
- *thread = NULL;
+ *thread = NULL;
+ }
}
/**
@@ -2050,10 +2050,15 @@ void event_call(struct event *thread)
/* Execute thread */
void _event_execute(const struct xref_eventsched *xref, struct event_loop *m,
- void (*func)(struct event *), void *arg, int val)
+ void (*func)(struct event *), void *arg, int val,
+ struct event **eref)
{
struct event *thread;
+ /* Cancel existing scheduled task TODO -- nice to do in 1 lock cycle */
+ if (eref)
+ event_cancel(eref);
+
/* Get or allocate new thread to execute. */
frr_with_mutex (&m->mtx) {
thread = thread_get(m, EVENT_EVENT, func, arg, xref);
diff --git a/lib/frrevent.h b/lib/frrevent.h
index 2b0c52bb51..fe33ffd1f2 100644
--- a/lib/frrevent.h
+++ b/lib/frrevent.h
@@ -195,7 +195,7 @@ struct cpu_event_history {
_xref_t_a(timer_tv, TIMER, m, f, a, v, t)
#define event_add_event(m, f, a, v, t) _xref_t_a(event, EVENT, m, f, a, v, t)
-#define event_execute(m, f, a, v) \
+#define event_execute(m, f, a, v, p) \
({ \
static const struct xref_eventsched _xref __attribute__( \
(used)) = { \
@@ -205,7 +205,7 @@ struct cpu_event_history {
.event_type = EVENT_EXECUTE, \
}; \
XREF_LINK(_xref.xref); \
- _event_execute(&_xref, m, f, a, v); \
+ _event_execute(&_xref, m, f, a, v, p); \
}) /* end */
/* Prototypes. */
@@ -241,7 +241,8 @@ extern void _event_add_event(const struct xref_eventsched *xref,
extern void _event_execute(const struct xref_eventsched *xref,
struct event_loop *master,
- void (*fn)(struct event *), void *arg, int val);
+ void (*fn)(struct event *), void *arg, int val,
+ struct event **eref);
extern void event_cancel(struct event **event);
extern void event_cancel_async(struct event_loop *m, struct event **eptr,
diff --git a/lib/nexthop_group.c b/lib/nexthop_group.c
index 0613fc6736..25370eba48 100644
--- a/lib/nexthop_group.c
+++ b/lib/nexthop_group.c
@@ -1047,6 +1047,7 @@ void nexthop_group_write_nexthop_simple(struct vty *vty,
vty_out(vty, "%pI6 %s", &nh->gate.ipv6, ifname);
break;
case NEXTHOP_TYPE_BLACKHOLE:
+ vty_out(vty, "%s", "drop");
break;
}
}
diff --git a/lib/pbr.h b/lib/pbr.h
index 1a3d562ed9..c514cc2a65 100644
--- a/lib/pbr.h
+++ b/lib/pbr.h
@@ -34,17 +34,18 @@ struct pbr_filter {
#define PBR_FILTER_SRC_PORT (1 << 2)
#define PBR_FILTER_DST_PORT (1 << 3)
#define PBR_FILTER_FWMARK (1 << 4)
-#define PBR_FILTER_PROTO (1 << 5)
+#define PBR_FILTER_IP_PROTOCOL (1 << 5)
#define PBR_FILTER_SRC_PORT_RANGE (1 << 6)
#define PBR_FILTER_DST_PORT_RANGE (1 << 7)
-#define PBR_FILTER_DSFIELD (1 << 8)
-#define PBR_FILTER_IP_PROTOCOL (1 << 9)
+#define PBR_FILTER_DSCP (1 << 8)
+#define PBR_FILTER_ECN (1 << 9)
#define PBR_FILTER_PCP (1 << 10)
#define PBR_FILTER_VLAN_FLAGS (1 << 11)
#define PBR_FILTER_VLAN_ID (1 << 12)
#define PBR_DSFIELD_DSCP (0xfc) /* Upper 6 bits of DS field: DSCP */
#define PBR_DSFIELD_ECN (0x03) /* Lower 2 bits of DS field: BCN */
+
#define PBR_PCP (0x07) /* 3-bit value 0..7 for prioritization*/
#define PBR_VLAN_FLAGS_NO_WILD 0
@@ -56,7 +57,7 @@ struct pbr_filter {
struct prefix src_ip;
struct prefix dst_ip;
- /* Source and Destination higher-layer (TCP/UDP) port numbers */
+ /* Source and Destination layer 4 (TCP/UDP/etc.) port numbers */
uint16_t src_port;
uint16_t dst_port;
@@ -87,11 +88,17 @@ struct pbr_filter {
struct pbr_action {
uint32_t flags;
-#define PBR_ACTION_TABLE (1 << 0)
-#define PBR_ACTION_QUEUE_ID (1 << 1)
-#define PBR_ACTION_PCP (1 << 2)
-#define PBR_ACTION_VLAN_ID (1 << 3)
-#define PBR_ACTION_VLAN_FLAGS (1 << 4)
+#define PBR_ACTION_TABLE (1 << 0)
+#define PBR_ACTION_QUEUE_ID (1 << 1)
+#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;
@@ -99,9 +106,18 @@ struct pbr_action {
/* VLAN */
uint8_t pcp;
uint16_t vlan_id;
- uint16_t vlan_flags;
+ /* 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 */
};
/*
@@ -113,6 +129,7 @@ struct pbr_action {
*/
struct pbr_rule {
vrf_id_t vrf_id;
+ uint8_t family; /* netlink: select which rule database */
uint32_t seq;
uint32_t priority;
diff --git a/lib/wheel.c b/lib/wheel.c
index e17995c64a..2520e81d49 100644
--- a/lib/wheel.c
+++ b/lib/wheel.c
@@ -57,7 +57,7 @@ static void wheel_timer_thread(struct event *t)
wheel = EVENT_ARG(t);
- event_execute(wheel->master, wheel_timer_thread_helper, wheel, 0);
+ event_execute(wheel->master, wheel_timer_thread_helper, wheel, 0, NULL);
}
struct timer_wheel *wheel_init(struct event_loop *master, int period,
diff --git a/lib/zclient.c b/lib/zclient.c
index 294a78feb0..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
*/
@@ -1631,40 +1672,79 @@ static void zapi_pbr_rule_filter_encode(struct stream *s, struct pbr_filter *f)
assert((f->src_ip.family == AF_INET) || (f->src_ip.family == AF_INET6));
stream_putl(s, f->filter_bm);
- stream_putc(s, f->ip_proto);
+
+ if (CHECK_FLAG(f->filter_bm, PBR_FILTER_IP_PROTOCOL))
+ stream_putc(s, f->ip_proto);
/* addresses */
- zapi_encode_prefix(s, &f->src_ip, f->src_ip.family);
- zapi_encode_prefix(s, &f->dst_ip, f->dst_ip.family);
+ if (CHECK_FLAG(f->filter_bm, PBR_FILTER_SRC_IP))
+ zapi_encode_prefix(s, &f->src_ip, f->src_ip.family);
+ if (CHECK_FLAG(f->filter_bm, PBR_FILTER_DST_IP))
+ zapi_encode_prefix(s, &f->dst_ip, f->dst_ip.family);
/* port numbers */
- stream_putw(s, f->src_port);
- stream_putw(s, f->dst_port);
+ if (CHECK_FLAG(f->filter_bm, PBR_FILTER_SRC_PORT))
+ stream_putw(s, f->src_port);
+ if (CHECK_FLAG(f->filter_bm, PBR_FILTER_DST_PORT))
+ stream_putw(s, f->dst_port);
+
+ if (CHECK_FLAG(f->filter_bm, PBR_FILTER_DSCP))
+ stream_putc(s, f->dsfield & PBR_DSFIELD_DSCP);
+ if (CHECK_FLAG(f->filter_bm, PBR_FILTER_ECN))
+ stream_putc(s, f->dsfield & PBR_DSFIELD_ECN);
/* vlan */
- stream_putc(s, f->pcp);
- stream_putw(s, f->vlan_id);
- stream_putw(s, f->vlan_flags);
+ if (CHECK_FLAG(f->filter_bm, PBR_FILTER_PCP))
+ stream_putc(s, f->pcp);
+ if (CHECK_FLAG(f->filter_bm, PBR_FILTER_VLAN_ID))
+ stream_putw(s, f->vlan_id);
+ if (CHECK_FLAG(f->filter_bm, PBR_FILTER_VLAN_FLAGS))
+ stream_putw(s, f->vlan_flags);
+
- stream_putc(s, f->dsfield);
- stream_putl(s, f->fwmark);
+ if (CHECK_FLAG(f->filter_bm, PBR_FILTER_FWMARK))
+ stream_putl(s, f->fwmark);
}
static bool zapi_pbr_rule_filter_decode(struct stream *s, struct pbr_filter *f)
{
+ uint8_t dscp = 0;
+ uint8_t ecn = 0;
+
STREAM_GETL(s, f->filter_bm);
- STREAM_GETC(s, f->ip_proto);
- if (!zapi_decode_prefix(s, &(f->src_ip)))
- goto stream_failure;
- if (!zapi_decode_prefix(s, &(f->dst_ip)))
- goto stream_failure;
- STREAM_GETW(s, f->src_port);
- STREAM_GETW(s, f->dst_port);
- STREAM_GETC(s, f->pcp);
- STREAM_GETW(s, f->vlan_id);
- STREAM_GETW(s, f->vlan_flags);
- STREAM_GETC(s, f->dsfield);
- STREAM_GETL(s, f->fwmark);
+
+ if (CHECK_FLAG(f->filter_bm, PBR_FILTER_IP_PROTOCOL))
+ STREAM_GETC(s, f->ip_proto);
+
+ if (CHECK_FLAG(f->filter_bm, PBR_FILTER_SRC_IP))
+ if (!zapi_decode_prefix(s, &(f->src_ip)))
+ goto stream_failure;
+ if (CHECK_FLAG(f->filter_bm, PBR_FILTER_DST_IP))
+ if (!zapi_decode_prefix(s, &(f->dst_ip)))
+ goto stream_failure;
+
+ if (CHECK_FLAG(f->filter_bm, PBR_FILTER_SRC_PORT))
+ STREAM_GETW(s, f->src_port);
+ if (CHECK_FLAG(f->filter_bm, PBR_FILTER_DST_PORT))
+ STREAM_GETW(s, f->dst_port);
+
+ if (CHECK_FLAG(f->filter_bm, PBR_FILTER_DSCP))
+ STREAM_GETC(s, dscp);
+ if (CHECK_FLAG(f->filter_bm, PBR_FILTER_ECN))
+ STREAM_GETC(s, ecn);
+ f->dsfield = (dscp & PBR_DSFIELD_DSCP) | (ecn & PBR_DSFIELD_ECN);
+
+ /* vlan */
+ if (CHECK_FLAG(f->filter_bm, PBR_FILTER_PCP))
+ STREAM_GETC(s, f->pcp);
+ if (CHECK_FLAG(f->filter_bm, PBR_FILTER_VLAN_ID))
+ STREAM_GETW(s, f->vlan_id);
+ if (CHECK_FLAG(f->filter_bm, PBR_FILTER_VLAN_FLAGS))
+ STREAM_GETW(s, f->vlan_flags);
+
+ if (CHECK_FLAG(f->filter_bm, PBR_FILTER_FWMARK))
+ STREAM_GETL(s, f->fwmark);
+
return true;
stream_failure:
@@ -1674,21 +1754,72 @@ stream_failure:
static void zapi_pbr_rule_action_encode(struct stream *s, struct pbr_action *a)
{
stream_putl(s, a->flags);
- stream_putl(s, a->table);
- stream_putl(s, a->queue_id);
- stream_putc(s, a->pcp);
- stream_putw(s, a->vlan_id);
- stream_putw(s, a->vlan_flags);
+
+ if (CHECK_FLAG(a->flags, PBR_ACTION_TABLE))
+ stream_putl(s, a->table);
+ 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);
+ if (CHECK_FLAG(a->flags, PBR_ACTION_VLAN_ID))
+ stream_putw(s, a->vlan_id);
}
static bool zapi_pbr_rule_action_decode(struct stream *s, struct pbr_action *a)
{
STREAM_GETL(s, a->flags);
- STREAM_GETL(s, a->table);
- STREAM_GETL(s, a->queue_id);
- STREAM_GETC(s, a->pcp);
- STREAM_GETW(s, a->vlan_id);
- STREAM_GETW(s, a->vlan_flags);
+
+ if (CHECK_FLAG(a->flags, PBR_ACTION_TABLE))
+ STREAM_GETL(s, a->table);
+ 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);
+ if (CHECK_FLAG(a->flags, PBR_ACTION_VLAN_ID))
+ STREAM_GETW(s, a->vlan_id);
+
return true;
stream_failure:
@@ -1702,6 +1833,7 @@ int zapi_pbr_rule_encode(struct stream *s, struct pbr_rule *r)
*/
stream_putl(s, 1);
+ stream_putc(s, r->family);
stream_putl(s, r->seq);
stream_putl(s, r->priority);
stream_putl(s, r->unique);
@@ -1723,6 +1855,7 @@ bool zapi_pbr_rule_decode(struct stream *s, struct pbr_rule *r)
memset(r, 0, sizeof(*r));
+ STREAM_GETC(s, r->family);
STREAM_GETL(s, r->seq);
STREAM_GETL(s, r->priority);
STREAM_GETL(s, r->unique);
diff --git a/ospf6d/ospf6_interface.c b/ospf6d/ospf6_interface.c
index 0fb3d29e25..a20ddf6c10 100644
--- a/ospf6d/ospf6_interface.c
+++ b/ospf6d/ospf6_interface.c
@@ -309,7 +309,7 @@ void ospf6_interface_disable(struct ospf6_interface *oi)
{
SET_FLAG(oi->flag, OSPF6_INTERFACE_DISABLE);
- event_execute(master, interface_down, oi, 0);
+ event_execute(master, interface_down, oi, 0, NULL);
ospf6_lsdb_remove_all(oi->lsdb);
ospf6_lsdb_remove_all(oi->lsdb_self);
@@ -387,9 +387,9 @@ void ospf6_interface_state_update(struct interface *ifp)
if (if_is_operative(ifp)
&& (ospf6_interface_get_linklocal_address(oi->interface)
|| if_is_loopback(oi->interface)))
- event_execute(master, interface_up, oi, 0);
+ event_execute(master, interface_up, oi, 0, NULL);
else
- event_execute(master, interface_down, oi, 0);
+ event_execute(master, interface_down, oi, 0, NULL);
return;
}
@@ -2584,8 +2584,8 @@ DEFUN (ipv6_ospf6_network,
}
/* Reset the interface */
- event_execute(master, interface_down, oi, 0);
- event_execute(master, interface_up, oi, 0);
+ event_execute(master, interface_down, oi, 0, NULL);
+ event_execute(master, interface_up, oi, 0, NULL);
return CMD_SUCCESS;
}
@@ -2620,8 +2620,8 @@ DEFUN (no_ipv6_ospf6_network,
oi->type = type;
/* Reset the interface */
- event_execute(master, interface_down, oi, 0);
- event_execute(master, interface_up, oi, 0);
+ event_execute(master, interface_down, oi, 0, NULL);
+ event_execute(master, interface_up, oi, 0, NULL);
return CMD_SUCCESS;
}
@@ -2844,8 +2844,8 @@ void ospf6_interface_clear(struct interface *ifp)
zlog_debug("Interface %s: clear by reset", ifp->name);
/* Reset the interface */
- event_execute(master, interface_down, oi, 0);
- event_execute(master, interface_up, oi, 0);
+ event_execute(master, interface_down, oi, 0, NULL);
+ event_execute(master, interface_up, oi, 0, NULL);
}
/* Clear interface */
diff --git a/ospf6d/ospf6_intra.h b/ospf6d/ospf6_intra.h
index 0f286f0ab1..7d154cb4c6 100644
--- a/ospf6d/ospf6_intra.h
+++ b/ospf6d/ospf6_intra.h
@@ -181,20 +181,21 @@ struct ospf6_intra_prefix_lsa {
do { \
if (CHECK_FLAG((oa)->flag, OSPF6_AREA_ENABLE)) \
event_execute(master, ospf6_router_lsa_originate, oa, \
- 0); \
+ 0, NULL); \
} while (0)
#define OSPF6_NETWORK_LSA_EXECUTE(oi) \
do { \
EVENT_OFF((oi)->thread_network_lsa); \
- event_execute(master, ospf6_network_lsa_originate, oi, 0); \
+ event_execute(master, ospf6_network_lsa_originate, oi, 0, \
+ NULL); \
} while (0)
#define OSPF6_LINK_LSA_EXECUTE(oi) \
do { \
if (!CHECK_FLAG((oi)->flag, OSPF6_INTERFACE_DISABLE)) \
event_execute(master, ospf6_link_lsa_originate, oi, \
- 0); \
+ 0, NULL); \
} while (0)
#define OSPF6_INTRA_PREFIX_LSA_EXECUTE_TRANSIT(oi) \
@@ -202,13 +203,13 @@ struct ospf6_intra_prefix_lsa {
EVENT_OFF((oi)->thread_intra_prefix_lsa); \
event_execute(master, \
ospf6_intra_prefix_lsa_originate_transit, oi, \
- 0); \
+ 0, NULL); \
} while (0)
#define OSPF6_AS_EXTERN_LSA_EXECUTE(oi) \
do { \
EVENT_OFF((oi)->thread_as_extern_lsa); \
- event_execute(master, ospf6_orig_as_external_lsa, oi, 0); \
+ event_execute(master, ospf6_orig_as_external_lsa, oi, 0, NULL);\
} while (0)
/* Function Prototypes */
diff --git a/ospf6d/ospf6_lsa.c b/ospf6d/ospf6_lsa.c
index e745c6c577..bc39579653 100644
--- a/ospf6d/ospf6_lsa.c
+++ b/ospf6d/ospf6_lsa.c
@@ -333,7 +333,7 @@ void ospf6_lsa_premature_aging(struct ospf6_lsa *lsa)
ospf6_flood_clear(lsa);
lsa->header->age = htons(OSPF_LSA_MAXAGE);
- event_execute(master, ospf6_lsa_expire, lsa, 0);
+ event_execute(master, ospf6_lsa_expire, lsa, 0, NULL);
}
/* check which is more recent. if a is more recent, return -1;
diff --git a/ospf6d/ospf6_lsdb.c b/ospf6d/ospf6_lsdb.c
index 355860f6b1..c9cbdf8e92 100644
--- a/ospf6d/ospf6_lsdb.c
+++ b/ospf6d/ospf6_lsdb.c
@@ -398,7 +398,7 @@ int ospf6_lsdb_maxage_remover(struct ospf6_lsdb *lsdb)
ospf6_lsa_checksum(lsa->header);
EVENT_OFF(lsa->refresh);
- event_execute(master, ospf6_lsa_refresh, lsa, 0);
+ event_execute(master, ospf6_lsa_refresh, lsa, 0, NULL);
} else {
zlog_debug("calling ospf6_lsdb_remove %s", lsa->name);
ospf6_lsdb_remove(lsa, lsdb);
diff --git a/ospf6d/ospf6_message.c b/ospf6d/ospf6_message.c
index e9b19ea0a6..07da9a5ec1 100644
--- a/ospf6d/ospf6_message.c
+++ b/ospf6d/ospf6_message.c
@@ -535,9 +535,9 @@ static void ospf6_hello_recv(struct in6_addr *src, struct in6_addr *dst,
oi->hello_in++;
/* Execute neighbor events */
- event_execute(master, hello_received, on, 0);
+ event_execute(master, hello_received, on, 0, NULL);
if (twoway)
- event_execute(master, twoway_received, on, 0);
+ event_execute(master, twoway_received, on, 0, NULL);
else {
if (OSPF6_GR_IS_ACTIVE_HELPER(on)) {
if (IS_DEBUG_OSPF6_GR)
@@ -553,7 +553,7 @@ static void ospf6_hello_recv(struct in6_addr *src, struct in6_addr *dst,
* receives one_way hellow when it acts as HELPER for
* that specific neighbor.
*/
- event_execute(master, oneway_received, on, 0);
+ event_execute(master, oneway_received, on, 0, NULL);
}
}
@@ -624,7 +624,7 @@ static void ospf6_dbdesc_recv_master(struct ospf6_header *oh,
return;
case OSPF6_NEIGHBOR_INIT:
- event_execute(master, twoway_received, on, 0);
+ event_execute(master, twoway_received, on, 0, NULL);
if (on->state != OSPF6_NEIGHBOR_EXSTART) {
if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
zlog_debug(
@@ -640,7 +640,7 @@ static void ospf6_dbdesc_recv_master(struct ospf6_header *oh,
&& !CHECK_FLAG(dbdesc->bits, OSPF6_DBDESC_IBIT)
&& ntohl(dbdesc->seqnum) == on->dbdesc_seqnum) {
/* execute NegotiationDone */
- event_execute(master, negotiation_done, on, 0);
+ event_execute(master, negotiation_done, on, 0, NULL);
/* Record neighbor options */
memcpy(on->options, dbdesc->options,
@@ -828,7 +828,7 @@ static void ospf6_dbdesc_recv_slave(struct ospf6_header *oh,
return;
case OSPF6_NEIGHBOR_INIT:
- event_execute(master, twoway_received, on, 0);
+ event_execute(master, twoway_received, on, 0, NULL);
if (on->state != OSPF6_NEIGHBOR_EXSTART) {
if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
zlog_debug(
@@ -855,7 +855,7 @@ static void ospf6_dbdesc_recv_slave(struct ospf6_header *oh,
on->dbdesc_seqnum = ntohl(dbdesc->seqnum);
/* schedule NegotiationDone */
- event_execute(master, negotiation_done, on, 0);
+ event_execute(master, negotiation_done, on, 0, NULL);
/* Record neighbor options */
memcpy(on->options, dbdesc->options,
@@ -2436,7 +2436,7 @@ void ospf6_dbdesc_send_newone(struct event *thread)
event_add_event(master, exchange_done, on, 0,
&on->thread_exchange_done);
- event_execute(master, ospf6_dbdesc_send, on, 0);
+ event_execute(master, ospf6_dbdesc_send, on, 0, NULL);
}
static uint16_t ospf6_make_lsreq(struct ospf6_neighbor *on, struct stream *s)
@@ -2623,7 +2623,7 @@ static void ospf6_send_lsupdate(struct ospf6_neighbor *on,
* it will schedule itself again.
*/
event_cancel(&ospf6->t_write);
- event_execute(master, ospf6_write, ospf6, 0);
+ event_execute(master, ospf6_write, ospf6, 0, NULL);
} else
OSPF6_MESSAGE_WRITE_ON(oi);
}
diff --git a/ospf6d/ospf6_nssa.c b/ospf6d/ospf6_nssa.c
index e7a10eba41..405ae90528 100644
--- a/ospf6d/ospf6_nssa.c
+++ b/ospf6d/ospf6_nssa.c
@@ -1436,7 +1436,7 @@ DEFPY (no_area_nssa_range,
SET_FLAG(range->flag, OSPF6_ROUTE_REMOVE);
/* Redo summaries if required */
- event_execute(master, ospf6_abr_task_timer, ospf6, 0);
+ event_execute(master, ospf6_abr_task_timer, ospf6, 0, NULL);
}
ospf6_route_remove(range, oa->nssa_range_table);
diff --git a/ospfd/ospf_ism.h b/ospfd/ospf_ism.h
index 426dda7733..bbb059c789 100644
--- a/ospfd/ospf_ism.h
+++ b/ospfd/ospf_ism.h
@@ -69,7 +69,7 @@
/* Macro for OSPF execute event. */
#define OSPF_ISM_EVENT_EXECUTE(I, E) \
- event_execute(master, ospf_ism_event, (I), (E))
+ event_execute(master, ospf_ism_event, (I), (E), NULL)
/* Prototypes. */
extern void ospf_ism_event(struct event *thread);
diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c
index 7ef9834274..e47f832728 100644
--- a/ospfd/ospf_lsa.c
+++ b/ospfd/ospf_lsa.c
@@ -3780,7 +3780,7 @@ void ospf_flush_self_originated_lsas_now(struct ospf *ospf)
*/
if (ospf->t_maxage != NULL) {
EVENT_OFF(ospf->t_maxage);
- event_execute(master, ospf_maxage_lsa_remover, ospf, 0);
+ event_execute(master, ospf_maxage_lsa_remover, ospf, 0, NULL);
}
return;
diff --git a/ospfd/ospf_nsm.h b/ospfd/ospf_nsm.h
index 9973b4870d..82e17208aa 100644
--- a/ospfd/ospf_nsm.h
+++ b/ospfd/ospf_nsm.h
@@ -49,7 +49,7 @@
/* Macro for OSPF NSM execute event. */
#define OSPF_NSM_EVENT_EXECUTE(N, E) \
- event_execute(master, ospf_nsm_event, (N), (E))
+ event_execute(master, ospf_nsm_event, (N), (E), NULL)
/* Prototypes. */
extern void ospf_nsm_event(struct event *e);
diff --git a/pbrd/pbr_map.c b/pbrd/pbr_map.c
index 758e08b565..6b81e1058e 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,42 @@ 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_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 |
+ 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 +642,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 3afb199565..61577e4076 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,28 @@ struct pbr_map_sequence {
* Action fields
*****************************************************************/
+ /*
+ * same bit definitions as in lib/pbr.h
+ */
+ 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;
-#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 +257,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 405a2d6588..4f7882fb22 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 8e9673482e..0d6e1afd5b 100644
--- a/pbrd/pbr_vty.c
+++ b/pbrd/pbr_vty.c
@@ -29,89 +29,60 @@
#include "pbrd/pbr_vty_clippy.c"
/* clang-format off */
-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"
- "PCP value to match\n")
+DEFPY (pbr_set_table_range,
+ pbr_set_table_range_cmd,
+ "pbr table range (10000-4294966272)$lb (10000-4294966272)$ub",
+ PBR_STR
+ "Set table ID range\n"
+ "Set table ID range\n"
+ "Lower bound for table ID range\n"
+ "Upper bound for table ID range\n")
{
/* clang-format on */
- struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
+ /* upper bound is 2^32 - 2^10 */
+ int ret = CMD_WARNING;
+ const int minrange = 1000;
- if (pbrms)
- pbr_set_match_clause_for_pcp(pbrms, !no, pcp);
+ /* validate given bounds */
+ if (lb > ub)
+ vty_out(vty, "%% Lower bound must be less than upper bound\n");
+ else if (ub - lb < minrange)
+ vty_out(vty, "%% Range breadth must be at least %d\n", minrange);
+ else {
+ ret = CMD_SUCCESS;
+ pbr_nht_set_tableid_range((uint32_t)lb, (uint32_t)ub);
+ }
- return CMD_SUCCESS;
+ return ret;
}
/* clang-format off */
-DEFPY(pbr_map_match_vlan_id, pbr_map_match_vlan_id_cmd,
- "[no] match vlan <(1-4094)$vlan_id>",
- NO_STR
- "Match spec follows\n"
- "Match based on VLAN ID\n"
- "VLAN ID to match\n")
+DEFPY (no_pbr_set_table_range,
+ no_pbr_set_table_range_cmd,
+ "no pbr table range [(10000-4294966272)$lb (10000-4294966272)$ub]",
+ NO_STR
+ PBR_STR
+ "Set table ID range\n"
+ "Set table ID range\n"
+ "Lower bound for table ID range\n"
+ "Upper bound for table ID range\n")
{
/* 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);
- }
- }
- }
- }
+ pbr_nht_set_tableid_range(PBR_NHT_DEFAULT_LOW_TABLEID,
+ PBR_NHT_DEFAULT_HIGH_TABLEID);
return CMD_SUCCESS;
}
/* clang-format off */
-DEFPY(pbr_map_match_vlan_tag, pbr_map_match_vlan_tag_cmd,
- "[no] match vlan ![<tagged|untagged|untagged-or-zero>$tag_type]",
- NO_STR
- "Match the rest of the command\n"
- "Match based on VLAN tagging\n"
- "Match all tagged frames\n"
- "Match all untagged frames\n"
- "Match untagged frames, or tagged frames with id zero\n")
-{
- /* clang-format on */
- struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
-
- 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_SUCCESS;
-}
-
-DEFUN_NOSH(pbr_map, pbr_map_cmd, "pbr-map PBRMAP seq (1-700)",
+DEFUN_NOSH(pbr_map,
+ pbr_map_cmd,
+ "pbr-map PBRMAP seq (1-700)",
"Create pbr-map or enter pbr-map command mode\n"
"The name of the PBR MAP\n"
"Sequence to insert in existing pbr-map entry\n"
"Sequence number\n")
{
+ /* clang-format on */
const char *pbrm_name = argv[1]->arg;
uint32_t seqno = atoi(argv[3]->arg);
struct pbr_map_sequence *pbrms;
@@ -122,13 +93,17 @@ DEFUN_NOSH(pbr_map, pbr_map_cmd, "pbr-map PBRMAP seq (1-700)",
return CMD_SUCCESS;
}
-DEFUN_NOSH(no_pbr_map, no_pbr_map_cmd, "no pbr-map PBRMAP [seq (1-700)]",
+/* clang-format off */
+DEFUN_NOSH(no_pbr_map,
+ no_pbr_map_cmd,
+ "no pbr-map PBRMAP [seq (1-700)]",
NO_STR
"Delete pbr-map\n"
"The name of the PBR MAP\n"
"Sequence to delete from existing pbr-map entry\n"
"Sequence number\n")
{
+ /* clang-format on */
const char *pbrm_name = argv[2]->arg;
uint32_t seqno = 0;
struct pbr_map *pbrm = pbrm_find(pbrm_name);
@@ -153,301 +128,533 @@ DEFUN_NOSH(no_pbr_map, no_pbr_map_cmd, "no pbr-map PBRMAP [seq (1-700)]",
return CMD_SUCCESS;
}
-DEFPY(pbr_set_table_range,
- pbr_set_table_range_cmd,
- "pbr table range (10000-4294966272)$lb (10000-4294966272)$ub",
- PBR_STR
- "Set table ID range\n"
- "Set table ID range\n"
- "Lower bound for table ID range\n"
- "Upper bound for table ID range\n")
-{
- /* upper bound is 2^32 - 2^10 */
- int ret = CMD_WARNING;
- const int minrange = 1000;
+/***********************************************************************
+ * pbrms/rule Match L3 Fields
+ ***********************************************************************/
- /* validate given bounds */
- if (lb > ub)
- vty_out(vty, "%% Lower bound must be less than upper bound\n");
- else if (ub - lb < minrange)
- vty_out(vty, "%% Range breadth must be at least %d\n", minrange);
- else {
- ret = CMD_SUCCESS;
- pbr_nht_set_tableid_range((uint32_t) lb, (uint32_t) ub);
+/*
+ * 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;
+ uint32_t action_bm = pbrms->action_bm & ~skip_action_bm;
+
+ if (CHECK_FLAG(filter_bm, PBR_FILTER_SRC_IP) &&
+ (family != pbrms->src->family)) {
+ if (msg)
+ *msg = "match src-ip";
+ return false;
}
-
- return ret;
+ if (CHECK_FLAG(filter_bm, PBR_FILTER_DST_IP) &&
+ (family != pbrms->dst->family)) {
+ if (msg)
+ *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;
}
-DEFPY(no_pbr_set_table_range, no_pbr_set_table_range_cmd,
- "no pbr table range [(10000-4294966272)$lb (10000-4294966272)$ub]",
- NO_STR
- PBR_STR
- "Set table ID range\n"
- "Set table ID range\n"
- "Lower bound for table ID range\n"
- "Upper bound for table ID range\n")
-{
- pbr_nht_set_tableid_range(PBR_NHT_DEFAULT_LOW_TABLEID,
- PBR_NHT_DEFAULT_HIGH_TABLEID);
- return CMD_SUCCESS;
-}
-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",
+/* 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_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")
{
+ /* 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;
}
-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",
+/* 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_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")
{
+ /* 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");
- return CMD_WARNING_CONFIG_FAILED;
+ 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;
}
-DEFPY(pbr_map_match_ip_proto, pbr_map_match_ip_proto_cmd,
- "[no] match ip-protocol PROTO$ip_proto",
- NO_STR
- "Match the rest of the command\n"
- "Choose an ip-protocol\n"
- "Protocol name\n")
+/* clang-format off */
+DEFPY (pbr_map_match_ip_proto,
+ pbr_map_match_ip_proto_cmd,
+ "[no] match ip-protocol ![PROTO$ip_proto]",
+ NO_STR
+ "Match the rest of the command\n"
+ "Choose an ip-protocol\n"
+ "Protocol name\n")
{
+ /* 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;
}
-DEFPY(pbr_map_match_src_port, pbr_map_match_src_port_cmd,
- "[no] match src-port (1-65535)$port",
- NO_STR
- "Match the rest of the command\n"
- "Choose the source port to use\n"
- "The Source Port\n")
+/* clang-format off */
+DEFPY (pbr_map_match_src_port,
+ pbr_map_match_src_port_cmd,
+ "[no] match src-port ![(1-65535)$port]",
+ NO_STR
+ "Match the rest of the command\n"
+ "Choose the source port to use\n"
+ "The Source Port\n")
{
+ /* clang-format on */
struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
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;
}
-DEFPY(pbr_map_match_dst_port, pbr_map_match_dst_port_cmd,
- "[no] match dst-port (1-65535)$port",
- NO_STR
- "Match the rest of the command\n"
- "Choose the destination port to use\n"
- "The Destination Port\n")
+/* clang-format off */
+DEFPY (pbr_map_match_dst_port,
+ pbr_map_match_dst_port_cmd,
+ "[no] match dst-port ![(1-65535)$port]",
+ NO_STR
+ "Match the rest of the command\n"
+ "Choose the destination port to use\n"
+ "The Destination Port\n")
{
+ /* clang-format on */
struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
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;
}
-DEFPY(pbr_map_match_dscp, pbr_map_match_dscp_cmd,
- "[no] match dscp DSCP$dscp",
- NO_STR
- "Match the rest of the command\n"
- "Match based on IP DSCP field\n"
- "DSCP value (below 64) or standard codepoint name\n")
+/* clang-format off */
+DEFPY (pbr_map_match_dscp,
+ pbr_map_match_dscp_cmd,
+ "[no] match dscp ![DSCP$dscp]",
+ NO_STR
+ "Match the rest of the command\n"
+ "Match based on IP DSCP field\n"
+ "DSCP value (below 64) or standard codepoint name\n")
{
+ /* 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)
+ if (CHECK_FLAG(pbrms->filter_bm, PBR_FILTER_DSCP) &&
+ (((pbrms->dsfield & PBR_DSFIELD_DSCP) >> 2) == raw_dscp)) {
+ return CMD_SUCCESS;
+ }
+
+ /* 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_STR
+ "Match the rest of the command\n"
+ "Match based on IP ECN field\n"
+ "Explicit Congestion Notification\n")
+{
+ /* clang-format on */
+ struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
+
+ if (!pbrms)
+ return CMD_WARNING_CONFIG_FAILED;
+
+ if (no) {
+ if (!CHECK_FLAG(pbrms->filter_bm, PBR_FILTER_ECN))
return CMD_SUCCESS;
+ UNSET_FLAG(pbrms->filter_bm, PBR_FILTER_ECN);
+ pbrms->dsfield &= ~PBR_DSFIELD_ECN;
+ goto check;
+ }
- /* Set the DSCP bits of the DSField */
- pbrms->dsfield =
- (pbrms->dsfield & ~PBR_DSFIELD_DSCP) | (rawDscp << 2);
- } else {
- pbrms->dsfield &= ~PBR_DSFIELD_DSCP;
+ 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;
+}
+
+/***********************************************************************
+ * pbrms/rule Match L2 fields
+ ***********************************************************************/
+
+/* clang-format off */
+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"
+ "PCP value to match\n")
+{
+ /* clang-format on */
+ struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
+
+ 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;
}
-DEFPY(pbr_map_match_ecn, pbr_map_match_ecn_cmd,
- "[no] match ecn (0-3)$ecn",
- NO_STR
- "Match the rest of the command\n"
- "Match based on IP ECN field\n"
- "Explicit Congestion Notification\n")
+/* clang-format off */
+DEFPY (pbr_map_match_vlan_id,
+ pbr_map_match_vlan_id_cmd,
+ "[no] match vlan ![(1-4094)$vlan_id]",
+ NO_STR
+ "Match spec follows\n"
+ "Match based on VLAN ID\n"
+ "VLAN ID to match\n")
{
+ /* clang-format on */
struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
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_VLAN_ID))
return CMD_SUCCESS;
+ UNSET_FLAG(pbrms->filter_bm, PBR_FILTER_VLAN_ID);
+ goto check;
+ }
- /* Set the ECN bits of the DSField */
- pbrms->dsfield = (pbrms->dsfield & ~PBR_DSFIELD_ECN) | ecn;
- } else {
- pbrms->dsfield &= ~PBR_DSFIELD_ECN;
+ 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;
+}
+
+/* clang-format off */
+DEFPY (pbr_map_match_vlan_tag,
+ pbr_map_match_vlan_tag_cmd,
+ "[no] match vlan ![<tagged|untagged|untagged-or-zero>$tag_type]",
+ NO_STR
+ "Match the rest of the command\n"
+ "Match based on VLAN tagging\n"
+ "Match all tagged frames\n"
+ "Match all untagged frames\n"
+ "Match untagged frames, or tagged frames with id zero\n")
+{
+ /* clang-format on */
+ struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
+ uint16_t vlan_flags;
+
+ if (!pbrms)
+ 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;
}
-DEFPY(pbr_map_match_mark, pbr_map_match_mark_cmd,
- "[no] match mark (1-4294967295)$mark",
+/***********************************************************************
+ * pbrms/rule Match meta
+ ***********************************************************************/
+
+/* clang-format off */
+DEFPY (pbr_map_match_mark,
+ pbr_map_match_mark_cmd,
+ "[no] match mark ![(1-4294967295)$mark]",
NO_STR
"Match the rest of the command\n"
"Choose the mark value to use\n"
"mark\n")
{
+ /* clang-format on */
struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
if (!pbrms)
@@ -458,139 +665,450 @@ DEFPY(pbr_map_match_mark, pbr_map_match_mark_cmd,
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;
}
-static void pbrms_clear_set_vrf_config(struct pbr_map_sequence *pbrms)
+/***********************************************************************
+ * 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")
{
- if (pbrms->vrf_lookup || pbrms->vrf_unchanged) {
- pbr_map_delete_vrf(pbrms);
- pbrms->vrf_name[0] = '\0';
- pbrms->vrf_lookup = false;
- pbrms->vrf_unchanged = false;
+ /* 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;
}
-static void pbrms_clear_set_nhg_config(struct pbr_map_sequence *pbrms)
+/* 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")
{
- if (pbrms->nhgrp_name)
- pbr_map_delete_nexthops(pbrms);
+ /* 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;
}
-static void pbrms_clear_set_nexthop_config(struct pbr_map_sequence *pbrms)
+/* 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")
{
- if (pbrms->nhg)
- pbr_nht_delete_individual_nexthop(pbrms);
+ /* 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;
}
-static void pbrms_clear_set_config(struct pbr_map_sequence *pbrms)
+/* 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")
{
- pbrms_clear_set_vrf_config(pbrms);
- pbrms_clear_set_nhg_config(pbrms);
- pbrms_clear_set_nexthop_config(pbrms);
+ /* clang-format on */
+ struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
- pbrms->nhs_installed = false;
+ 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);
-DEFPY(pbr_map_action_queue_id, pbr_map_action_queue_id_cmd,
- "[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"
- "A valid value in range 1..65535 \n")
+ 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
+ ***********************************************************************/
+
+/* clang-format off */
+DEFPY (pbr_map_action_queue_id,
+ pbr_map_action_queue_id_cmd,
+ "[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"
+ "A valid value in range 1..65535 \n")
{
+ /* clang-format on */
struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
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;
}
-DEFPY(pbr_map_action_pcp, pbr_map_action_pcp_cmd, "[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"
- "A valid value in range 0..7\n")
+
+/***********************************************************************
+ * pbrms/rule Action Set L2 Fields
+ ***********************************************************************/
+
+/* clang-format off */
+DEFPY (pbr_map_action_pcp,
+ pbr_map_action_pcp_cmd,
+ "[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"
+ "A valid value in range 0..7\n")
{
+ /* clang-format on */
struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
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;
+ }
+
+ if (CHECK_FLAG(pbrms->action_bm, PBR_ACTION_PCP) &&
+ pbrms->action_pcp == pcp) {
+ return CMD_SUCCESS;
+ }
- pbr_map_check(pbrms, true);
+ pbrms->action_pcp = pcp;
+ SET_FLAG(pbrms->action_bm, PBR_ACTION_PCP);
+check:
+ pbr_map_check(pbrms, true);
return CMD_SUCCESS;
}
-DEFPY(pbr_map_action_vlan_id, pbr_map_action_vlan_id_cmd,
- "[no] set vlan <(1-4094)$vlan_id>",
- NO_STR
- "Set the rest of the command\n"
- "Set action for VLAN tagging\n"
- "A valid value in range 1..4094\n")
+/* clang-format off */
+DEFPY (pbr_map_action_vlan_id,
+ pbr_map_action_vlan_id_cmd,
+ "[no] set vlan ![(1-4094)$vlan_id]",
+ NO_STR
+ "Set the rest of the command\n"
+ "Set action for VLAN tagging\n"
+ "A valid value in range 1..4094\n")
{
+ /* clang-format on */
struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
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;
}
-DEFPY(pbr_map_action_strip_vlan, pbr_map_action_strip_vlan_cmd,
- "[no] strip vlan",
- NO_STR
- "Strip the vlan tags from frame\n"
- "Strip any inner vlan tag \n")
+/* clang-format off */
+DEFPY (pbr_map_action_strip_vlan,
+ pbr_map_action_strip_vlan_cmd,
+ "[no] strip vlan",
+ NO_STR
+ "Strip the vlan tags from frame\n"
+ "Strip any inner vlan tag\n")
{
+ /* clang-format on */
struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
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;
}
+/***********************************************************************
+ * pbrms/rule Action Forwarding
+ ***********************************************************************/
+
+static void pbrms_clear_set_vrf_config(struct pbr_map_sequence *pbrms)
+{
+ if (pbrms->vrf_lookup || pbrms->vrf_unchanged) {
+ pbr_map_delete_vrf(pbrms);
+ pbrms->vrf_name[0] = '\0';
+ pbrms->vrf_lookup = false;
+ pbrms->vrf_unchanged = false;
+ }
+}
+
+static void pbrms_clear_set_nhg_config(struct pbr_map_sequence *pbrms)
+{
+ if (pbrms->nhgrp_name)
+ pbr_map_delete_nexthops(pbrms);
+}
+
+static void pbrms_clear_set_nexthop_config(struct pbr_map_sequence *pbrms)
+{
+ if (pbrms->nhg)
+ pbr_nht_delete_individual_nexthop(pbrms);
+}
+
+static void pbrms_clear_set_config(struct pbr_map_sequence *pbrms)
+{
+ pbrms_clear_set_vrf_config(pbrms);
+ pbrms_clear_set_nhg_config(pbrms);
+ pbrms_clear_set_nexthop_config(pbrms);
+
+ pbrms->nhs_installed = false;
+
+ pbrms->forwarding_type = PBR_FT_UNSPEC;
+}
+
+
+
DEFPY(pbr_map_nexthop_group, pbr_map_nexthop_group_cmd,
"set nexthop-group NHGNAME$name",
"Set for the PBR-MAP\n"
@@ -641,22 +1159,27 @@ DEFPY(no_pbr_map_nexthop_group, no_pbr_map_nexthop_group_cmd,
return CMD_SUCCESS;
}
-DEFPY(pbr_map_nexthop, pbr_map_nexthop_cmd,
- "set nexthop\
+/* clang-format off */
+DEFPY (pbr_map_nexthop,
+ pbr_map_nexthop_cmd,
+ "set nexthop\
<\
<A.B.C.D|X:X::X:X>$addr [INTERFACE$intf]\
|INTERFACE$intf\
+ |blackhole$bh\
>\
[nexthop-vrf NAME$vrf_name]",
- "Set for the PBR-MAP\n"
- "Specify one of the nexthops in this map\n"
- "v4 Address\n"
- "v6 Address\n"
- "Interface to use\n"
- "Interface to use\n"
- "If the nexthop is in a different vrf tell us\n"
- "The nexthop-vrf Name\n")
+ "Set for the PBR-MAP\n"
+ "Specify one of the nexthops in this map\n"
+ "v4 Address\n"
+ "v6 Address\n"
+ "Interface to use\n"
+ "Interface to use\n"
+ "Blackhole route\n"
+ "If the nexthop is in a different vrf tell us\n"
+ "The nexthop-vrf Name\n")
{
+ /* clang-format on */
struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
struct vrf *vrf;
struct nexthop nhop;
@@ -738,8 +1261,11 @@ DEFPY(pbr_map_nexthop, pbr_map_nexthop_cmd,
nhop.type = NEXTHOP_TYPE_IPV6;
}
}
- } else
+ } else if (bh) {
+ nhop.type = NEXTHOP_TYPE_BLACKHOLE;
+ } else {
nhop.type = NEXTHOP_TYPE_IFINDEX;
+ }
if (pbrms->nhg)
nh = nexthop_exists(pbrms->nhg, &nhop);
@@ -768,23 +1294,28 @@ done:
return CMD_SUCCESS;
}
-DEFPY(no_pbr_map_nexthop, no_pbr_map_nexthop_cmd,
- "no set nexthop\
+/* clang-format off */
+DEFPY (no_pbr_map_nexthop,
+ no_pbr_map_nexthop_cmd,
+ "no set nexthop\
[<\
<A.B.C.D|X:X::X:X>$addr [INTERFACE$intf]\
|INTERFACE$intf\
+ |blackhole$bh\
>\
[nexthop-vrf NAME$vrf_name]]",
- NO_STR
- "Set for the PBR-MAP\n"
- "Specify one of the nexthops in this map\n"
- "v4 Address\n"
- "v6 Address\n"
- "Interface to use\n"
- "Interface to use\n"
- "If the nexthop is in a different vrf tell us\n"
- "The nexthop-vrf Name\n")
+ NO_STR
+ "Set for the PBR-MAP\n"
+ "Specify one of the nexthops in this map\n"
+ "v4 Address\n"
+ "v6 Address\n"
+ "Interface to use\n"
+ "Interface to use\n"
+ "Blackhole route\n"
+ "If the nexthop is in a different vrf tell us\n"
+ "The nexthop-vrf Name\n")
{
+ /* clang-format on */
struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
if (!pbrms)
@@ -810,10 +1341,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)) {
@@ -826,9 +1358,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);
@@ -853,13 +1388,19 @@ DEFPY(no_pbr_map_vrf, no_pbr_map_vrf_cmd,
return CMD_SUCCESS;
}
-DEFPY (pbr_policy,
+/***********************************************************************
+ * Policy
+ ***********************************************************************/
+
+/* clang-format off */
+DEFPY (pbr_policy,
pbr_policy_cmd,
"[no] pbr-policy PBRMAP$mapname",
NO_STR
"Policy to use\n"
"Name of the pbr-map to apply\n")
{
+ /* clang-format on */
VTY_DECLVAR_CONTEXT(interface, ifp);
struct pbr_map *pbrm, *old_pbrm;
struct pbr_interface *pbr_ifp = ifp->info;
@@ -966,56 +1507,93 @@ 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)
- vty_out(vty, " Set Queue ID: %u\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 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_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: %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 (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 (CHECK_FLAG(pbrms->action_bm, PBR_ACTION_QUEUE_ID))
+ vty_out(vty, " Set Queue ID: %u\n",
+ pbrms->action_queue_id);
- 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)
@@ -1029,8 +1607,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)
@@ -1045,13 +1624,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;
}
}
@@ -1078,7 +1651,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",
@@ -1090,24 +1674,93 @@ 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
+ */
+
+ /* 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))
+ 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);
}
@@ -1373,71 +2026,99 @@ 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)
+ 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");
+ 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");
@@ -1505,6 +2186,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);
@@ -1516,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 030c4c1114..35c771469c 100644
--- a/pbrd/pbr_zebra.c
+++ b/pbrd/pbr_zebra.c
@@ -517,10 +517,14 @@ static bool pbr_encode_pbr_map_sequence(struct stream *s,
uint8_t family;
/*
- * There seems to be some effort in pbr_vty.c to keep the three
- * copies of "family" equal. Not sure if the reason goes beyond
- * ensuring consistency in ZAPI encoding. In any case, it might
- * be handled better as an internal matter for the encoder (TBD).
+ * Opportunistic address family field is set when any of the IP
+ * address match/set fields is set, or when a NH/NHG is resolved.
+ * The value is needed by zebra for the underlying netlink
+ * messaging, particularly in delete operations, because it
+ * selects the rule database (IPv4 vs. IPv6).
+ *
+ * Historically the value has been encoded into any unused
+ * "match src/dst address" fields and picked off in zebra.
*/
family = AF_INET;
if (pbrms->family)
@@ -539,6 +543,8 @@ static bool pbr_encode_pbr_map_sequence(struct stream *s,
r.priority = pbrms->ruleno;
r.unique = pbrms->unique;
+ r.family = pbrms->family;
+
/* filter */
r.filter.filter_bm = pbrms->filter_bm;
if (pbrms->src)
@@ -558,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"
@@ -613,9 +593,18 @@ 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;
- r.action.vlan_flags = pbrms->action_vlan_flags;
strlcpy(r.ifname, ifp->name, sizeof(r.ifname));
diff --git a/pimd/pim6_mld.c b/pimd/pim6_mld.c
index ed9967e7a8..20ef9216a9 100644
--- a/pimd/pim6_mld.c
+++ b/pimd/pim6_mld.c
@@ -1367,7 +1367,7 @@ static void gm_bump_querier(struct gm_if *gm_ifp)
gm_ifp->n_startup = gm_ifp->cur_qrv;
- event_execute(router->master, gm_t_query, gm_ifp, 0);
+ event_execute(router->master, gm_t_query, gm_ifp, 0, NULL);
}
static void gm_t_other_querier(struct event *t)
@@ -1380,7 +1380,7 @@ static void gm_t_other_querier(struct event *t)
gm_ifp->querier = pim_ifp->ll_lowest;
gm_ifp->n_startup = gm_ifp->cur_qrv;
- event_execute(router->master, gm_t_query, gm_ifp, 0);
+ event_execute(router->master, gm_t_query, gm_ifp, 0, NULL);
}
static void gm_handle_query(struct gm_if *gm_ifp,
@@ -2267,7 +2267,7 @@ static void gm_update_ll(struct interface *ifp)
return;
gm_ifp->n_startup = gm_ifp->cur_qrv;
- event_execute(router->master, gm_t_query, gm_ifp, 0);
+ event_execute(router->master, gm_t_query, gm_ifp, 0, NULL);
}
void gm_ifp_update(struct interface *ifp)
diff --git a/pimd/pim_msg.c b/pimd/pim_msg.c
index 5d1f08314b..6814798bf5 100644
--- a/pimd/pim_msg.c
+++ b/pimd/pim_msg.c
@@ -196,7 +196,32 @@ size_t pim_msg_get_jp_group_size(struct list *sources)
__func__, up->sg_str);
for (ALL_LIST_ELEMENTS_RO(up->sources, up_node, child)) {
- if (!PIM_UPSTREAM_FLAG_TEST_USE_RPT(child->flags)) {
+ /*
+ * PIM VXLAN is weird
+ * It auto creates the S,G and populates a bunch
+ * of flags that make it look like a SPT prune should
+ * be sent. But this regularly scheduled join
+ * for the *,G in the VXLAN setup can happen at
+ * scheduled times *before* the null register
+ * is received by the RP to cause it to initiate
+ * the S,G joins toward the source. Let's just
+ * assume that if this is a SRC VXLAN ORIG route
+ * and no actual ifchannels( joins ) have been
+ * created then do not send the embedded prune
+ * Why you may ask? Well if the prune is S,G
+ * RPT Prune is received *before* the join
+ * from the RP( if it flows to this routers
+ * upstream interface ) then we'll just wisely
+ * create a mroute with an empty oil on
+ * the upstream intermediate router preventing
+ * packets from flowing to the RP
+ */
+ if (PIM_UPSTREAM_FLAG_TEST_SRC_VXLAN_ORIG(child->flags) &&
+ listcount(child->ifchannels) == 0) {
+ if (PIM_DEBUG_PIM_PACKETS)
+ zlog_debug("%s: %s Vxlan originated S,G route with no ifchannels, not adding prune to compound message",
+ __func__, child->sg_str);
+ } else if (!PIM_UPSTREAM_FLAG_TEST_USE_RPT(child->flags)) {
/* If we are using SPT and the SPT and RPT IIFs
* are different we can prune the source off
* of the RPT.
diff --git a/pimd/pim_nht.c b/pimd/pim_nht.c
index 5f0f2a5933..4e8e5f0df7 100644
--- a/pimd/pim_nht.c
+++ b/pimd/pim_nht.c
@@ -31,6 +31,8 @@
#include "pim_zlookup.h"
#include "pim_rp.h"
#include "pim_addr.h"
+#include "pim_register.h"
+#include "pim_vxlan.h"
/**
* pim_sendmsg_zebra_rnh -- Format and send a nexthop register/Unregister
@@ -399,17 +401,28 @@ static void pim_update_rp_nh(struct pim_instance *pim,
{
struct listnode *node = NULL;
struct rp_info *rp_info = NULL;
+ struct interface *ifp;
/*Traverse RP list and update each RP Nexthop info */
for (ALL_LIST_ELEMENTS_RO(pnc->rp_list, node, rp_info)) {
if (pim_rpf_addr_is_inaddr_any(&rp_info->rp))
continue;
+ ifp = rp_info->rp.source_nexthop.interface;
// Compute PIM RPF using cached nexthop
if (!pim_ecmp_nexthop_lookup(pim, &rp_info->rp.source_nexthop,
rp_info->rp.rpf_addr,
&rp_info->group, 1))
pim_rp_nexthop_del(rp_info);
+
+ /*
+ * If we transition from no path to a path
+ * we need to search through all the vxlan's
+ * that use this rp and send NULL registers
+ * for all the vxlan S,G streams
+ */
+ if (!ifp && rp_info->rp.source_nexthop.interface)
+ pim_vxlan_rp_info_is_alive(pim, &rp_info->rp);
}
}
@@ -436,17 +449,27 @@ static int pim_update_upstream_nh_helper(struct hash_bucket *bucket, void *arg)
(rpf_result == PIM_RPF_FAILURE && old.source_nexthop.interface))
pim_zebra_upstream_rpf_changed(pim, up, &old);
+ /*
+ * If we are a VXLAN source and we are transitioning from not
+ * having an outgoing interface to having an outgoing interface
+ * let's immediately send the null pim register
+ */
+ if (!old.source_nexthop.interface && up->rpf.source_nexthop.interface &&
+ PIM_UPSTREAM_FLAG_TEST_SRC_VXLAN_ORIG(up->flags) &&
+ (up->reg_state == PIM_REG_NOINFO || up->reg_state == PIM_REG_JOIN)) {
+ pim_null_register_send(up);
+ }
if (PIM_DEBUG_PIM_NHT) {
- zlog_debug(
- "%s: NHT upstream %s(%s) old ifp %s new ifp %s",
- __func__, up->sg_str, pim->vrf->name,
- old.source_nexthop.interface ? old.source_nexthop
- .interface->name
- : "Unknown",
- up->rpf.source_nexthop.interface ? up->rpf.source_nexthop
- .interface->name
- : "Unknown");
+ zlog_debug("%s: NHT upstream %s(%s) old ifp %s new ifp %s rpf_result: %d",
+ __func__, up->sg_str, pim->vrf->name,
+ old.source_nexthop.interface ? old.source_nexthop
+ .interface->name
+ : "Unknown",
+ up->rpf.source_nexthop.interface ? up->rpf.source_nexthop
+ .interface->name
+ : "Unknown",
+ rpf_result);
}
return HASHWALK_CONTINUE;
diff --git a/pimd/pim_upstream.c b/pimd/pim_upstream.c
index a8d087bf49..fd99e77761 100644
--- a/pimd/pim_upstream.c
+++ b/pimd/pim_upstream.c
@@ -912,6 +912,7 @@ static struct pim_upstream *pim_upstream_new(struct pim_instance *pim,
false /*update_mroute*/);
rpf_result = pim_rpf_update(pim, up, NULL, __func__);
if (rpf_result == PIM_RPF_FAILURE) {
+ up->channel_oil->oil_inherited_rescan = 1;
if (PIM_DEBUG_PIM_TRACE)
zlog_debug(
"%s: Attempting to create upstream(%s), Unable to RPF for source",
diff --git a/pimd/pim_vxlan.c b/pimd/pim_vxlan.c
index 8df3c90f00..9650da89a8 100644
--- a/pimd/pim_vxlan.c
+++ b/pimd/pim_vxlan.c
@@ -32,6 +32,41 @@ static void pim_vxlan_work_timer_setup(bool start);
static void pim_vxlan_set_peerlink_rif(struct pim_instance *pim,
struct interface *ifp);
+/*
+ * The rp info has gone from no path to having a
+ * path. Let's immediately send out the null pim register
+ * as that else we will be sitting for up to 60 seconds waiting
+ * for it too pop. Which is not cool.
+ */
+void pim_vxlan_rp_info_is_alive(struct pim_instance *pim,
+ struct pim_rpf *rpg_changed)
+{
+ struct listnode *listnode;
+ struct pim_vxlan_sg *vxlan_sg;
+ struct pim_rpf *rpg;
+
+ /*
+ * No vxlan here, move along, nothing to see
+ */
+ if (!vxlan_info.work_list)
+ return;
+
+ for (listnode = vxlan_info.work_list->head; listnode;
+ listnode = listnode->next) {
+ vxlan_sg = listgetdata(listnode);
+
+ rpg = RP(pim, vxlan_sg->up->sg.grp);
+
+ /*
+ * If the rp is the same we should send
+ */
+ if (rpg == rpg_changed) {
+ zlog_debug("VXLAN RP INFO is alive sending");
+ pim_null_register_send(vxlan_sg->up);
+ }
+ }
+}
+
/*************************** vxlan work list **********************************
* A work list is maintained for staggered generation of pim null register
* messages for vxlan SG entries that are in a reg_join state.
@@ -66,6 +101,7 @@ static void pim_vxlan_do_reg_work(void)
for (; listnode; listnode = listnode->next) {
vxlan_sg = (struct pim_vxlan_sg *)listnode->data;
+
if (vxlan_sg->up && (vxlan_sg->up->reg_state == PIM_REG_JOIN)) {
if (PIM_DEBUG_VXLAN)
zlog_debug("vxlan SG %s periodic NULL register",
diff --git a/pimd/pim_vxlan.h b/pimd/pim_vxlan.h
index 9a135ca6b8..5039bf6540 100644
--- a/pimd/pim_vxlan.h
+++ b/pimd/pim_vxlan.h
@@ -135,6 +135,9 @@ extern bool pim_vxlan_do_mlag_reg(void);
extern void pim_vxlan_inherit_mlag_flags(struct pim_instance *pim,
struct pim_upstream *up, bool inherit);
+extern void pim_vxlan_rp_info_is_alive(struct pim_instance *pim,
+ struct pim_rpf *rpg_changed);
+
/* Shutdown of PIM stop the thread */
extern void pim_vxlan_terminate(void);
#endif /* PIM_VXLAN_H */
diff --git a/tests/lib/test_segv.c b/tests/lib/test_segv.c
index af5f3aec63..5d2f451ebd 100644
--- a/tests/lib/test_segv.c
+++ b/tests/lib/test_segv.c
@@ -61,7 +61,7 @@ int main(void)
zlog_aux_init("NONE: ", LOG_DEBUG);
- event_execute(master, threadfunc, 0, 0);
+ event_execute(master, threadfunc, 0, 0, NULL);
exit(0);
}
diff --git a/tests/topotests/bgp_evpn_mh/leaf1/evpn.conf b/tests/topotests/bgp_evpn_mh/leaf1/evpn.conf
new file mode 100644
index 0000000000..33b6d08aba
--- /dev/null
+++ b/tests/topotests/bgp_evpn_mh/leaf1/evpn.conf
@@ -0,0 +1,21 @@
+frr defaults datacenter
+!
+router bgp 65101
+ bgp router-id 192.168.100.13
+ no bgp ebgp-requires-policy
+ neighbor 192.168.50.1 remote-as external
+ neighbor 192.168.51.1 remote-as external
+ neighbor 192.168.1.2 remote-as external
+ neighbor 192.168.2.2 remote-as external
+ neighbor 192.168.3.2 remote-as external
+ neighbor 192.168.4.2 remote-as external
+ redistribute connected
+ address-family l2vpn evpn
+ neighbor 192.168.50.1 activate
+ neighbor 192.168.51.1 activate
+ neighbor 192.168.1.2 activate
+ neighbor 192.168.2.2 activate
+ neighbor 192.168.3.2 activate
+ neighbor 192.168.4.2 activate
+ exit-address-family
+!
diff --git a/tests/topotests/bgp_evpn_mh/leaf1/pim.conf b/tests/topotests/bgp_evpn_mh/leaf1/pim.conf
new file mode 100644
index 0000000000..a4de64d1fb
--- /dev/null
+++ b/tests/topotests/bgp_evpn_mh/leaf1/pim.conf
@@ -0,0 +1,26 @@
+#debug pim packet
+#debug pim packet register
+#debug pim event
+#debug pim trace
+ip pim ecmp
+ip pim rp 192.168.100.13
+ip pim spt-switchover infinity-and-beyond
+!
+int leaf1-eth0
+ ip pim
+!
+int leaf1-eth1
+ ip pim
+!
+int leaf1-eth2
+ ip pim
+!
+int leaf1-eth3
+ ip pim
+!
+int leaf1-eth4
+ ip pim
+!
+int leaf1-eth5
+ ip pim
+!
diff --git a/tests/topotests/bgp_evpn_mh/leaf1/zebra.conf b/tests/topotests/bgp_evpn_mh/leaf1/zebra.conf
new file mode 100644
index 0000000000..f666f98abc
--- /dev/null
+++ b/tests/topotests/bgp_evpn_mh/leaf1/zebra.conf
@@ -0,0 +1,30 @@
+# spine 1 connection
+int leaf1-eth0
+ description spine1 connection
+ ip addr 192.168.50.2/24
+
+#spine 2 connection
+int leaf1-eth1
+ description spine2 connection
+ ip addr 192.168.51.2/24
+
+#torm11 connection
+int leaf1-eth2
+ description torm11 connection
+ ip addr 192.168.1.1/24
+!
+#torm12 connection
+int leaf1-eth3
+ description torm12 connection
+ ip addr 192.168.2.1/24
+!
+#torm21 connection
+int leaf1-eth4
+ description torm21 connection
+ ip addr 192.168.3.1/24
+!
+#torm22 connection
+int leaf1-eth5
+ descriptoin torm22 connection
+ ip addr 192.168.4.1/24
+!
diff --git a/tests/topotests/bgp_evpn_mh/leaf2/evpn.conf b/tests/topotests/bgp_evpn_mh/leaf2/evpn.conf
new file mode 100644
index 0000000000..428998b0fe
--- /dev/null
+++ b/tests/topotests/bgp_evpn_mh/leaf2/evpn.conf
@@ -0,0 +1,21 @@
+frr defaults datacenter
+!
+router bgp 65101
+ bgp router-id 192.168.100.14
+ no bgp ebgp-requires-policy
+ neighbor 192.168.61.1 remote-as external
+ neighbor 192.168.51.1 remote-as external
+ neighbor 192.168.5.2 remote-as external
+ neighbor 192.168.6.2 remote-as external
+ neighbor 192.168.7.2 remote-as external
+ neighbor 192.168.8.2 remote-as external
+ redistribute connected
+ address-family l2vpn evpn
+ neighbor 192.168.61.1 activate
+ neighbor 192.168.51.1 activate
+ neighbor 192.168.5.2 activate
+ neighbor 192.168.6.2 activate
+ neighbor 192.168.7.2 activate
+ neighbor 192.168.8.2 activate
+ exit-address-family
+!
diff --git a/tests/topotests/bgp_evpn_mh/leaf2/pim.conf b/tests/topotests/bgp_evpn_mh/leaf2/pim.conf
new file mode 100644
index 0000000000..3abd9698f5
--- /dev/null
+++ b/tests/topotests/bgp_evpn_mh/leaf2/pim.conf
@@ -0,0 +1,20 @@
+#debug pim packet register
+#debug pim packet
+#debug pim event
+#debug pim trace
+ip pim ecmp
+ip pim rp 192.168.100.13
+ip pim spt-switchover infinity-and-beyond
+!
+int leaf2-eth0
+ ip pim
+!
+int leaf2-eth1
+ ip pim
+!
+int leaf2-eth2
+ ip pim
+!
+int leaf2-eth3
+ ip pim
+!
diff --git a/tests/topotests/bgp_evpn_mh/leaf2/zebra.conf b/tests/topotests/bgp_evpn_mh/leaf2/zebra.conf
new file mode 100644
index 0000000000..ff680cf764
--- /dev/null
+++ b/tests/topotests/bgp_evpn_mh/leaf2/zebra.conf
@@ -0,0 +1,24 @@
+# spine1 connection
+int leaf2-eth0
+ ip addr 192.168.51.2/24
+!
+# spine2 connection
+int leaf2-eth1
+ ip addr 192.168.61.2/24
+!
+#torm11 connection
+int leaf2-eth2
+ ip addr 192.168.5.1/24
+!
+#torm12 connection
+int leaf2-eth3
+ ip addr 192.168.6.1/24
+!
+#torm21 connection
+int leaf2-eth4
+ ip addr 192.168.7.1/24
+!
+#torm22 connection
+int leaf2-eth5
+ ip addr 192.168.8.1/24
+!
diff --git a/tests/topotests/bgp_evpn_mh/spine1/evpn.conf b/tests/topotests/bgp_evpn_mh/spine1/evpn.conf
index 2e26f60f44..b9fce46ea4 100644
--- a/tests/topotests/bgp_evpn_mh/spine1/evpn.conf
+++ b/tests/topotests/bgp_evpn_mh/spine1/evpn.conf
@@ -3,15 +3,11 @@ frr defaults datacenter
router bgp 65001
bgp router-id 192.168.100.13
no bgp ebgp-requires-policy
- neighbor 192.168.1.2 remote-as external
- neighbor 192.168.2.2 remote-as external
- neighbor 192.168.3.2 remote-as external
- neighbor 192.168.4.2 remote-as external
+ neighbor 192.168.50.2 remote-as external
+ neighbor 192.168.51.2 remote-as external
redistribute connected
address-family l2vpn evpn
- neighbor 192.168.1.2 activate
- neighbor 192.168.2.2 activate
- neighbor 192.168.3.2 activate
- neighbor 192.168.4.2 activate
+ neighbor 192.168.50.2 activate
+ neighbor 192.168.51.2 activate
exit-address-family
!
diff --git a/tests/topotests/bgp_evpn_mh/spine1/pim.conf b/tests/topotests/bgp_evpn_mh/spine1/pim.conf
index 68e686e8c7..018d244e4d 100644
--- a/tests/topotests/bgp_evpn_mh/spine1/pim.conf
+++ b/tests/topotests/bgp_evpn_mh/spine1/pim.conf
@@ -1,4 +1,10 @@
+ip pim ecmp
ip pim rp 192.168.100.13
+#debug pim packets
+#debug pim packet register
+#debug pim event
+#debug pim trace
+#debug pim vxlan
ip pim spt-switchover infinity-and-beyond
!
int lo
@@ -10,9 +16,3 @@ int spine1-eth0
int spine1-eth1
ip pim
!
-int spine1-eth2
- ip pim
-!
-int spine1-eth3
- ip pim
-!
diff --git a/tests/topotests/bgp_evpn_mh/spine1/zebra.conf b/tests/topotests/bgp_evpn_mh/spine1/zebra.conf
index 80e9e5a263..607a5e8e32 100644
--- a/tests/topotests/bgp_evpn_mh/spine1/zebra.conf
+++ b/tests/topotests/bgp_evpn_mh/spine1/zebra.conf
@@ -1,14 +1,10 @@
+# leaf1 connection
int spine1-eth0
- ip addr 192.168.1.1/24
+ ip addr 192.168.50.1/24
!
+# leaf2 connection
int spine1-eth1
- ip addr 192.168.2.1/24
-!
-int spine1-eth2
- ip addr 192.168.3.1/24
-!
-int spine1-eth3
- ip addr 192.168.4.1/24
+ ip addr 192.168.51.1/24
!
int lo
ip addr 192.168.100.13/32
diff --git a/tests/topotests/bgp_evpn_mh/spine2/evpn.conf b/tests/topotests/bgp_evpn_mh/spine2/evpn.conf
index ec2e789276..1430e10b68 100644
--- a/tests/topotests/bgp_evpn_mh/spine2/evpn.conf
+++ b/tests/topotests/bgp_evpn_mh/spine2/evpn.conf
@@ -3,15 +3,11 @@ frr defaults datacenter
router bgp 65001
bgp router-id 192.168.100.14
no bgp ebgp-requires-policy
- neighbor 192.168.5.2 remote-as external
- neighbor 192.168.6.2 remote-as external
- neighbor 192.168.7.2 remote-as external
- neighbor 192.168.8.2 remote-as external
+ neighbor 192.168.60.2 remote-as external
+ neighbor 192.168.61.2 remote-as external
redistribute connected
address-family l2vpn evpn
- neighbor 192.168.5.2 activate
- neighbor 192.168.6.2 activate
- neighbor 192.168.7.2 activate
- neighbor 192.168.8.2 activate
+ neighbor 192.168.60.2 activate
+ neighbor 192.168.61.2 activate
exit-address-family
!
diff --git a/tests/topotests/bgp_evpn_mh/spine2/pim.conf b/tests/topotests/bgp_evpn_mh/spine2/pim.conf
index c1566240e6..0ece2ff539 100644
--- a/tests/topotests/bgp_evpn_mh/spine2/pim.conf
+++ b/tests/topotests/bgp_evpn_mh/spine2/pim.conf
@@ -1,3 +1,4 @@
+ip pim ecmp
ip pim rp 192.168.100.13
ip pim spt-switchover infinity-and-beyond
!
@@ -10,9 +11,3 @@ int spine2-eth0
int spine2-eth1
ip pim
!
-int spine2-eth2
- ip pim
-!
-int spine2-eth3
- ip pim
-!
diff --git a/tests/topotests/bgp_evpn_mh/spine2/zebra.conf b/tests/topotests/bgp_evpn_mh/spine2/zebra.conf
index 1cd1df8c81..c8cec14e62 100644
--- a/tests/topotests/bgp_evpn_mh/spine2/zebra.conf
+++ b/tests/topotests/bgp_evpn_mh/spine2/zebra.conf
@@ -1,14 +1,12 @@
+# leaf1 connection
int spine2-eth0
- ip addr 192.168.5.1/24
+ description leaf1 connection
+ ip addr 192.168.60.1/24
!
+# leaf2 connection
int spine2-eth1
- ip addr 192.168.6.1/24
-!
-int spine2-eth2
- ip addr 192.168.7.1/24
-!
-int spine2-eth3
- ip addr 192.168.8.1/24
+ description leaf2 connection
+ ip addr 192.168.61.1/24
!
int lo
ip addr 192.168.100.14/32
diff --git a/tests/topotests/bgp_evpn_mh/test_evpn_mh.py b/tests/topotests/bgp_evpn_mh/test_evpn_mh.py
index 0bde5d5a9f..ec5227809e 100644
--- a/tests/topotests/bgp_evpn_mh/test_evpn_mh.py
+++ b/tests/topotests/bgp_evpn_mh/test_evpn_mh.py
@@ -58,6 +58,8 @@ def build_topo(tgen):
tgen.add_router("spine1")
tgen.add_router("spine2")
+ tgen.add_router("leaf1")
+ tgen.add_router("leaf2")
tgen.add_router("torm11")
tgen.add_router("torm12")
tgen.add_router("torm21")
@@ -71,88 +73,109 @@ def build_topo(tgen):
# First switch is for a dummy interface (for local network)
##################### spine1 ########################
- # spine1-eth0 is connected to torm11-eth0
+ # spine1-eth0 is connected to leaf1-eth0
switch = tgen.add_switch("sw1")
switch.add_link(tgen.gears["spine1"])
- switch.add_link(tgen.gears["torm11"])
+ switch.add_link(tgen.gears["leaf1"])
- # spine1-eth1 is connected to torm12-eth0
+ # spine1-eth1 is connected to leaf2-eth0
switch = tgen.add_switch("sw2")
switch.add_link(tgen.gears["spine1"])
- switch.add_link(tgen.gears["torm12"])
+ switch.add_link(tgen.gears["leaf2"])
- # spine1-eth2 is connected to torm21-eth0
+ # spine2-eth0 is connected to leaf1-eth1
switch = tgen.add_switch("sw3")
- switch.add_link(tgen.gears["spine1"])
- switch.add_link(tgen.gears["torm21"])
+ switch.add_link(tgen.gears["spine2"])
+ switch.add_link(tgen.gears["leaf1"])
- # spine1-eth3 is connected to torm22-eth0
+ # spine2-eth1 is connected to leaf2-eth1
switch = tgen.add_switch("sw4")
- switch.add_link(tgen.gears["spine1"])
- switch.add_link(tgen.gears["torm22"])
+ switch.add_link(tgen.gears["spine2"])
+ switch.add_link(tgen.gears["leaf2"])
- ##################### spine2 ########################
- # spine2-eth0 is connected to torm11-eth1
+ ################## leaf1 ##########################
+ # leaf1-eth2 is connected to torm11-eth0
switch = tgen.add_switch("sw5")
- switch.add_link(tgen.gears["spine2"])
+ switch.add_link(tgen.gears["leaf1"])
switch.add_link(tgen.gears["torm11"])
- # spine2-eth1 is connected to torm12-eth1
+ # leaf1-eth3 is connected to torm12-eth0
switch = tgen.add_switch("sw6")
- switch.add_link(tgen.gears["spine2"])
+ switch.add_link(tgen.gears["leaf1"])
switch.add_link(tgen.gears["torm12"])
- # spine2-eth2 is connected to torm21-eth1
+ # leaf1-eth4 is connected to torm21-eth0
switch = tgen.add_switch("sw7")
- switch.add_link(tgen.gears["spine2"])
+ switch.add_link(tgen.gears["leaf1"])
switch.add_link(tgen.gears["torm21"])
- # spine2-eth3 is connected to torm22-eth1
+ # leaf1-eth5 is connected to torm22-eth0
switch = tgen.add_switch("sw8")
- switch.add_link(tgen.gears["spine2"])
+ switch.add_link(tgen.gears["leaf1"])
+ switch.add_link(tgen.gears["torm22"])
+
+ ##################### leaf2 ########################
+ # leaf2-eth2 is connected to torm11-eth1
+ switch = tgen.add_switch("sw9")
+ switch.add_link(tgen.gears["leaf2"])
+ switch.add_link(tgen.gears["torm11"])
+
+ # leaf2-eth3 is connected to torm12-eth1
+ switch = tgen.add_switch("sw10")
+ switch.add_link(tgen.gears["leaf2"])
+ switch.add_link(tgen.gears["torm12"])
+
+ # leaf2-eth4 is connected to torm21-eth1
+ switch = tgen.add_switch("sw11")
+ switch.add_link(tgen.gears["leaf2"])
+ switch.add_link(tgen.gears["torm21"])
+
+ # leaf2-eth5 is connected to torm22-eth1
+ switch = tgen.add_switch("sw12")
+ switch.add_link(tgen.gears["leaf2"])
switch.add_link(tgen.gears["torm22"])
##################### torm11 ########################
# torm11-eth2 is connected to hostd11-eth0
- switch = tgen.add_switch("sw9")
+ switch = tgen.add_switch("sw13")
switch.add_link(tgen.gears["torm11"])
switch.add_link(tgen.gears["hostd11"])
# torm11-eth3 is connected to hostd12-eth0
- switch = tgen.add_switch("sw10")
+ switch = tgen.add_switch("sw14")
switch.add_link(tgen.gears["torm11"])
switch.add_link(tgen.gears["hostd12"])
##################### torm12 ########################
# torm12-eth2 is connected to hostd11-eth1
- switch = tgen.add_switch("sw11")
+ switch = tgen.add_switch("sw15")
switch.add_link(tgen.gears["torm12"])
switch.add_link(tgen.gears["hostd11"])
# torm12-eth3 is connected to hostd12-eth1
- switch = tgen.add_switch("sw12")
+ switch = tgen.add_switch("sw16")
switch.add_link(tgen.gears["torm12"])
switch.add_link(tgen.gears["hostd12"])
##################### torm21 ########################
# torm21-eth2 is connected to hostd21-eth0
- switch = tgen.add_switch("sw13")
+ switch = tgen.add_switch("sw17")
switch.add_link(tgen.gears["torm21"])
switch.add_link(tgen.gears["hostd21"])
# torm21-eth3 is connected to hostd22-eth0
- switch = tgen.add_switch("sw14")
+ switch = tgen.add_switch("sw18")
switch.add_link(tgen.gears["torm21"])
switch.add_link(tgen.gears["hostd22"])
##################### torm22 ########################
# torm22-eth2 is connected to hostd21-eth1
- switch = tgen.add_switch("sw15")
+ switch = tgen.add_switch("sw19")
switch.add_link(tgen.gears["torm22"])
switch.add_link(tgen.gears["hostd21"])
# torm22-eth3 is connected to hostd22-eth1
- switch = tgen.add_switch("sw16")
+ switch = tgen.add_switch("sw20")
switch.add_link(tgen.gears["torm22"])
switch.add_link(tgen.gears["hostd22"])
@@ -591,7 +614,7 @@ def ping_anycast_gw(tgen):
"--interface=" + intf,
'Ether(dst="ff:ff:ff:ff:ff:ff")/ARP(pdst="{}")'.format(ipaddr),
]
- for name in ("hostd11", "hostd21"):
+ for name in ("hostd11", "hostd21", "hostd12", "hostd22"):
host = tgen.net.hosts[name]
_, stdout, _ = host.cmd_status(ping_cmd, warn=False, stderr=subprocess.STDOUT)
stdout = stdout.strip()
diff --git a/tests/topotests/bgp_evpn_mh/torm11/pim.conf b/tests/topotests/bgp_evpn_mh/torm11/pim.conf
index fbba735873..a5d45dabc7 100644
--- a/tests/topotests/bgp_evpn_mh/torm11/pim.conf
+++ b/tests/topotests/bgp_evpn_mh/torm11/pim.conf
@@ -1,4 +1,10 @@
!
+#debug pim packet
+#debug pim packet register
+#debug pim trace
+#debug pim event
+#debug pim vxlan
+ip pim ecmp
ip pim rp 192.168.100.13 239.1.1.0/24
ip pim spt-switchover infinity-and-beyond
!
diff --git a/tests/topotests/bgp_evpn_mh/torm12/pim.conf b/tests/topotests/bgp_evpn_mh/torm12/pim.conf
index 3dd63b44ca..7e09ba7e21 100644
--- a/tests/topotests/bgp_evpn_mh/torm12/pim.conf
+++ b/tests/topotests/bgp_evpn_mh/torm12/pim.conf
@@ -1,4 +1,10 @@
+#debug pim packet
+#debug pim packet register
+#debug pim trace
+#debug pim event
+#debug pim vxlan
!
+ip pim ecmp
ip pim rp 192.168.100.13 239.1.1.0/24
ip pim spt-switchover infinity-and-beyond
!
diff --git a/tests/topotests/bgp_evpn_mh/torm21/pim.conf b/tests/topotests/bgp_evpn_mh/torm21/pim.conf
index 71aa91a06d..6996d74ad8 100644
--- a/tests/topotests/bgp_evpn_mh/torm21/pim.conf
+++ b/tests/topotests/bgp_evpn_mh/torm21/pim.conf
@@ -1,4 +1,10 @@
+#debug pim packet
+#debug pim packet register
+#debug pim trace
+#debug pim event
+#debug pim vxlan
!
+ip pim ecmp
ip pim rp 192.168.100.13 239.1.1.0/24
ip pim spt-switchover infinity-and-beyond
!
diff --git a/tests/topotests/bgp_evpn_mh/torm22/pim.conf b/tests/topotests/bgp_evpn_mh/torm22/pim.conf
index 46f330f5cd..6256e0e8cf 100644
--- a/tests/topotests/bgp_evpn_mh/torm22/pim.conf
+++ b/tests/topotests/bgp_evpn_mh/torm22/pim.conf
@@ -1,4 +1,10 @@
+#debug pim packet
+#debug pim packet register
+#debug pim trace
+#debug pim event
+#debug pim vxlan
!
+ip pim ecmp
ip pim rp 192.168.100.13 239.1.1.0/24
ip pim spt-switchover infinity-and-beyond
!
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/tests/topotests/static_routing_mpls/r1/zebra.conf b/tests/topotests/static_routing_mpls/r1/zebra.conf
new file mode 100644
index 0000000000..4e5d29af98
--- /dev/null
+++ b/tests/topotests/static_routing_mpls/r1/zebra.conf
@@ -0,0 +1,16 @@
+hostname r1
+ip forwarding
+ipv6 forwarding
+
+int r1-eth0
+ ip addr 192.168.1.1/24
+!
+int r1-eth1
+ ip addr 192.168.2.1/24
+!
+int lo
+ ip addr 192.0.2.1/32
+!
+int r1-eth1
+ ip addr 192.168.2.1/24
+!
diff --git a/tests/topotests/static_routing_mpls/r2/zebra.conf b/tests/topotests/static_routing_mpls/r2/zebra.conf
new file mode 100644
index 0000000000..4e06ae5202
--- /dev/null
+++ b/tests/topotests/static_routing_mpls/r2/zebra.conf
@@ -0,0 +1,18 @@
+hostname r2
+ip forwarding
+ipv6 forwarding
+
+int r2-eth0
+ ip addr 192.168.2.2/24
+!
+int r2-eth1
+ mpls enable
+ ip addr 192.168.3.2/24
+!
+int r2-eth2
+ mpls disable
+ ip addr 172.31.3.2/24
+!
+int lo
+ ip addr 192.0.2.2/32
+!
diff --git a/tests/topotests/static_routing_mpls/test_static_routing_mpls.py b/tests/topotests/static_routing_mpls/test_static_routing_mpls.py
new file mode 100644
index 0000000000..c1e249cc8f
--- /dev/null
+++ b/tests/topotests/static_routing_mpls/test_static_routing_mpls.py
@@ -0,0 +1,139 @@
+#!/usr/bin/env python
+# SPDX-License-Identifier: ISC
+
+#
+# test_static_routing_mlpls.py
+# Part of NetDEF Topology Tests
+#
+# Copyright (c) 2023 by 6WIND
+#
+
+"""
+test_static_routing_mpls.py: Testing MPLS configuration with mpls interface settings
+
+"""
+
+import os
+import re
+import sys
+import pytest
+import json
+from functools import partial
+import functools
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.topolog import logger
+
+# Required to instantiate the topology builder class.
+
+#####################################################
+##
+## Network Topology Definition
+##
+#####################################################
+
+
+def build_topo(tgen):
+ "Build function"
+
+ tgen.add_router("r1")
+ tgen.add_router("r2")
+
+ switch = tgen.add_switch("sw1")
+ switch.add_link(tgen.gears["r1"])
+
+ switch = tgen.add_switch("sw2")
+ switch.add_link(tgen.gears["r1"])
+ switch.add_link(tgen.gears["r2"])
+
+ switch = tgen.add_switch("sw3")
+ switch.add_link(tgen.gears["r2"])
+
+ switch = tgen.add_switch("sw4")
+ switch.add_link(tgen.gears["r2"])
+
+
+#####################################################
+##
+## Tests starting
+##
+#####################################################
+def _populate_mpls_labels():
+ tgen = get_topogen()
+ cmds_list = ["echo 100000 > /proc/sys/net/mpls/platform_labels"]
+ for cmd in cmds_list:
+ for host in ("r1", "r2"):
+ logger.info("input: " + cmd)
+ output = tgen.net[host].cmd(cmd)
+ logger.info("output: " + output)
+
+
+def setup_module(module):
+ "Setup topology"
+ tgen = Topogen(build_topo, module.__name__)
+ tgen.start_topology()
+
+ _populate_mpls_labels()
+
+ # This is a sample of configuration loading.
+ router_list = tgen.routers()
+ for rname, router in router_list.items():
+ router.load_config(
+ TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
+ )
+
+ tgen.start_router()
+
+
+def teardown_module(_mod):
+ "Teardown the pytest environment"
+ tgen = get_topogen()
+
+ # This function tears down the whole topology.
+ tgen.stop_topology()
+
+
+def _check_mpls_state_interface(router, interface, up=True):
+ output = router.vtysh_cmd("show interface {}".format(interface))
+ if up and "MPLS enabled" in output:
+ return None
+ elif not up and "MPLS enabled" not in output:
+ return None
+ return "not good"
+
+
+def _check_mpls_state(router, interface, configured=True):
+ test_func = functools.partial(
+ _check_mpls_state_interface, router, interface, up=configured
+ )
+ success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5)
+ return success
+
+
+def test_mpls_configured_on_interface():
+ "Test 'mpls' state is correctly configured on an unconfigured interfaces"
+
+ tgen = get_topogen()
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ logger.info("Checking that MPLS state is on on r2-eth1")
+ assertmsg = "r2, interface r2-eth1, mpls operational state is off, not expected"
+ assert _check_mpls_state(tgen.gears["r2"], "r2-eth1"), assertmsg
+
+ logger.info("Checking that MPLS state is off on r2-eth2")
+ assertmsg = "r2, interface r2-eth2, mpls operational state is on, not expected"
+ assert _check_mpls_state(tgen.gears["r2"], "r2-eth2", False), assertmsg
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/yang/frr-zebra.yang b/yang/frr-zebra.yang
index 7f4254cd41..3c6e45126a 100644
--- a/yang/frr-zebra.yang
+++ b/yang/frr-zebra.yang
@@ -1982,6 +1982,12 @@ module frr-zebra {
"Interface admin status.";
}
+ leaf mpls {
+ type boolean;
+ description
+ "Interface MPLS status.";
+ }
+
leaf bandwidth {
type uint32 {
range "1..100000";
diff --git a/zebra/interface.c b/zebra/interface.c
index 4006f9c574..ab2b7d2446 100644
--- a/zebra/interface.c
+++ b/zebra/interface.c
@@ -3777,23 +3777,20 @@ DEFUN (multicast,
DEFPY (mpls,
mpls_cmd,
- "[no] mpls enable",
+ "[no] mpls <enable$on|disable$off>",
NO_STR
MPLS_STR
- "Set mpls to be on for the interface\n")
+ "Set mpls to be on for the interface\n"
+ "Set mpls to be off for the interface\n")
{
- VTY_DECLVAR_CONTEXT(interface, ifp);
- struct zebra_if *if_data = ifp->info;
-
- if (no) {
- dplane_intf_mpls_modify_state(ifp, false);
- if_data->mpls_config = IF_ZEBRA_DATA_UNSPEC;
- } else {
- dplane_intf_mpls_modify_state(ifp, true);
- if_data->mpls_config = IF_ZEBRA_DATA_ON;
- }
+ if (!no)
+ nb_cli_enqueue_change(vty, "./frr-zebra:zebra/mpls",
+ NB_OP_CREATE, on ? "true" : "false");
+ else
+ nb_cli_enqueue_change(vty, "./frr-zebra:zebra/mpls",
+ NB_OP_DESTROY, NULL);
- return CMD_SUCCESS;
+ return nb_cli_apply_changes(vty, NULL);
}
int if_multicast_unset(struct interface *ifp)
@@ -5633,6 +5630,9 @@ static int if_config_write(struct vty *vty)
if (if_data->mpls_config == IF_ZEBRA_DATA_ON)
vty_out(vty, " mpls enable\n");
+ else if (if_data->mpls_config ==
+ IF_ZEBRA_DATA_OFF)
+ vty_out(vty, " mpls disable\n");
}
hook_call(zebra_if_config_wr, vty, ifp);
diff --git a/zebra/redistribute.c b/zebra/redistribute.c
index 9ca9c7a55a..8c8cbfc8d1 100644
--- a/zebra/redistribute.c
+++ b/zebra/redistribute.c
@@ -647,10 +647,9 @@ int zebra_add_import_table_entry(struct zebra_vrf *zvrf, struct route_node *rn,
afi = family2afi(rn->p.family);
if (rmap_name)
- ret = zebra_import_table_route_map_check(
- afi, re->type, re->instance, &rn->p,
- re->nhe->nhg.nexthop,
- zvrf->vrf->vrf_id, re->tag, rmap_name);
+ ret = zebra_import_table_route_map_check(afi, re, &rn->p,
+ re->nhe->nhg.nexthop,
+ rmap_name);
if (ret != RMAP_PERMITMATCH) {
UNSET_FLAG(re->flags, ZEBRA_FLAG_SELECTED);
diff --git a/zebra/rule_netlink.c b/zebra/rule_netlink.c
index 3bb4936b81..bc96e12902 100644
--- a/zebra/rule_netlink.c
+++ b/zebra/rule_netlink.c
@@ -117,8 +117,8 @@ static ssize_t netlink_rule_msg_encode(
}
/* dsfield, if specified; mask off the ECN bits */
- if (filter_bm & PBR_FILTER_DSFIELD)
- req->frh.tos = dsfield & 0xfc;
+ if (filter_bm & PBR_FILTER_DSCP)
+ req->frh.tos = dsfield & PBR_DSFIELD_DSCP;
/* protocol to match on */
if (filter_bm & PBR_FILTER_IP_PROTOCOL)
diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c
index e9c243217a..f6afb006b7 100644
--- a/zebra/zapi_msg.c
+++ b/zebra/zapi_msg.c
@@ -3188,10 +3188,32 @@ static inline void zread_rule(ZAPI_HANDLER_ARGS)
strlcpy(zpr.ifname, zpr.rule.ifname, sizeof(zpr.ifname));
+ if ((zpr.rule.family != AF_INET) &&
+ (zpr.rule.family != AF_INET6)) {
+ zlog_warn("Unsupported PBR source IP family: %s (%hhu)",
+ family2str(zpr.rule.family), zpr.rule.family);
+ return;
+ }
+
+ /*
+ * Fixup filter src/dst IP addresses if they are unset
+ * because the netlink code currently obtains address family
+ * from them. Address family is used to specify which
+ * kernel database to use when adding/deleting rule.
+ *
+ * TBD: propagate zpr.rule.family into dataplane and
+ * netlink code so they can stop using filter src/dst addrs.
+ */
+ if (!CHECK_FLAG(zpr.rule.filter.filter_bm, PBR_FILTER_SRC_IP))
+ zpr.rule.filter.src_ip.family = zpr.rule.family;
+ if (!CHECK_FLAG(zpr.rule.filter.filter_bm, PBR_FILTER_DST_IP))
+ zpr.rule.filter.dst_ip.family = zpr.rule.family;
+
+ /* TBD delete below block when netlink code gets family from zpr.rule.family */
if (!(zpr.rule.filter.src_ip.family == AF_INET
|| zpr.rule.filter.src_ip.family == AF_INET6)) {
zlog_warn(
- "Unsupported PBR source IP family: %s (%hhu)",
+ "Unsupported PBR source IP family: %s (%u)",
family2str(zpr.rule.filter.src_ip.family),
zpr.rule.filter.src_ip.family);
return;
@@ -3199,11 +3221,12 @@ static inline void zread_rule(ZAPI_HANDLER_ARGS)
if (!(zpr.rule.filter.dst_ip.family == AF_INET
|| zpr.rule.filter.dst_ip.family == AF_INET6)) {
zlog_warn(
- "Unsupported PBR destination IP family: %s (%hhu)",
+ "Unsupported PBR destination IP family: %s (%u)",
family2str(zpr.rule.filter.dst_ip.family),
zpr.rule.filter.dst_ip.family);
return;
}
+ /* TBD delete above block when netlink code gets family from zpr.rule.family */
zpr.vrf_id = zvrf->vrf->vrf_id;
diff --git a/zebra/zebra_fpm_netlink.c b/zebra/zebra_fpm_netlink.c
index ba34951e76..1279762232 100644
--- a/zebra/zebra_fpm_netlink.c
+++ b/zebra/zebra_fpm_netlink.c
@@ -287,6 +287,8 @@ static int netlink_route_info_fill(struct netlink_route_info *ri, int cmd,
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
continue;
+ if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_DUPLICATE))
+ continue;
if (nexthop->type == NEXTHOP_TYPE_BLACKHOLE) {
switch (nexthop->bh_type) {
diff --git a/zebra/zebra_gr.c b/zebra/zebra_gr.c
index cf2056b7ac..39fd8641de 100644
--- a/zebra/zebra_gr.c
+++ b/zebra/zebra_gr.c
@@ -80,13 +80,12 @@ void zebra_gr_stale_client_cleanup(struct list *client_list)
/* Cancel the stale timer */
if (info->t_stale_removal != NULL) {
EVENT_OFF(info->t_stale_removal);
- info->t_stale_removal = NULL;
info->do_delete = true;
/* Process the stale routes */
event_execute(
zrouter.master,
zebra_gr_route_stale_delete_timer_expiry,
- info, 0);
+ info, 0, NULL);
}
}
}
diff --git a/zebra/zebra_nb.c b/zebra/zebra_nb.c
index d94547cffc..a0ef08273c 100644
--- a/zebra/zebra_nb.c
+++ b/zebra/zebra_nb.c
@@ -339,6 +339,13 @@ const struct frr_yang_module_info frr_zebra_info = {
}
},
{
+ .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/mpls",
+ .cbs = {
+ .modify = lib_interface_zebra_mpls_modify,
+ .destroy = lib_interface_zebra_mpls_destroy,
+ }
+ },
+ {
.xpath = "/frr-interface:lib/interface/frr-zebra:zebra/bandwidth",
.cbs = {
.modify = lib_interface_zebra_bandwidth_modify,
diff --git a/zebra/zebra_nb.h b/zebra/zebra_nb.h
index fa576ec3f4..a066a7f9dc 100644
--- a/zebra/zebra_nb.h
+++ b/zebra/zebra_nb.h
@@ -96,6 +96,8 @@ int lib_interface_zebra_shutdown_modify(struct nb_cb_modify_args *args);
int lib_interface_zebra_shutdown_destroy(struct nb_cb_destroy_args *args);
int lib_interface_zebra_bandwidth_modify(struct nb_cb_modify_args *args);
int lib_interface_zebra_bandwidth_destroy(struct nb_cb_destroy_args *args);
+int lib_interface_zebra_mpls_modify(struct nb_cb_modify_args *args);
+int lib_interface_zebra_mpls_destroy(struct nb_cb_destroy_args *args);
int lib_interface_zebra_legacy_admin_group_modify(
struct nb_cb_modify_args *args);
int lib_interface_zebra_legacy_admin_group_destroy(
diff --git a/zebra/zebra_nb_config.c b/zebra/zebra_nb_config.c
index 336669a49b..5ea03112bc 100644
--- a/zebra/zebra_nb_config.c
+++ b/zebra/zebra_nb_config.c
@@ -1088,6 +1088,50 @@ int lib_interface_zebra_shutdown_destroy(struct nb_cb_destroy_args *args)
}
/*
+ * XPath: /frr-interface:lib/interface/frr-zebra:zebra/mpls
+ */
+int lib_interface_zebra_mpls_modify(struct nb_cb_modify_args *args)
+{
+ struct interface *ifp;
+ bool mpls;
+ struct zebra_if *zif;
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ ifp = nb_running_get_entry(args->dnode, NULL, true);
+ zif = ifp->info;
+ mpls = yang_dnode_get_bool(args->dnode, NULL);
+
+ if (mpls)
+ zif->mpls_config = IF_ZEBRA_DATA_ON;
+ else
+ zif->mpls_config = IF_ZEBRA_DATA_OFF;
+
+ dplane_intf_mpls_modify_state(ifp, mpls);
+
+ return NB_OK;
+}
+
+int lib_interface_zebra_mpls_destroy(struct nb_cb_destroy_args *args)
+{
+ struct interface *ifp;
+ struct zebra_if *zif;
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ ifp = nb_running_get_entry(args->dnode, NULL, true);
+ zif = ifp->info;
+
+ zif->mpls_config = IF_ZEBRA_DATA_UNSPEC;
+
+ /* keep the state as it is */
+
+ return NB_OK;
+}
+
+/*
* XPath: /frr-interface:lib/interface/frr-zebra:zebra/bandwidth
*/
int lib_interface_zebra_bandwidth_modify(struct nb_cb_modify_args *args)
diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c
index a701b582ce..d3c86e2a37 100644
--- a/zebra/zebra_nhg.c
+++ b/zebra/zebra_nhg.c
@@ -2703,8 +2703,7 @@ skip_check:
}
/* It'll get set if required inside */
- ret = zebra_route_map_check(family, re->type, re->instance, p, nexthop,
- zvrf, re->tag);
+ ret = zebra_route_map_check(family, re, p, nexthop, zvrf);
if (ret == RMAP_DENYMATCH) {
if (IS_ZEBRA_DEBUG_RIB) {
zlog_debug(
diff --git a/zebra/zebra_pbr.c b/zebra/zebra_pbr.c
index eac93dca41..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);
@@ -522,12 +523,12 @@ void zebra_pbr_show_rule_unit(struct zebra_pbr_rule *rule, struct vty *vty)
if (prule->filter.filter_bm & PBR_FILTER_DST_PORT)
vty_out(vty, " DST Port Match: %u\n", prule->filter.dst_port);
- if (prule->filter.filter_bm & PBR_FILTER_DSFIELD) {
+ if (prule->filter.filter_bm & PBR_FILTER_DSCP)
vty_out(vty, " DSCP Match: %u\n",
(prule->filter.dsfield & PBR_DSFIELD_DSCP) >> 2);
+ if (prule->filter.filter_bm & PBR_FILTER_ECN)
vty_out(vty, " ECN Match: %u\n",
prule->filter.dsfield & PBR_DSFIELD_ECN);
- }
if (prule->filter.filter_bm & PBR_FILTER_FWMARK)
vty_out(vty, " MARK Match: %u\n", prule->filter.fwmark);
@@ -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",
diff --git a/zebra/zebra_pbr.h b/zebra/zebra_pbr.h
index 15ad4e35cf..ddc1460d40 100644
--- a/zebra/zebra_pbr.h
+++ b/zebra/zebra_pbr.h
@@ -61,8 +61,6 @@ struct zebra_pbr_rule {
(r->rule.filter.filter_bm & PBR_FILTER_SRC_PORT)
#define IS_RULE_FILTERING_ON_DST_PORT(r) \
(r->rule.filter.filter_bm & PBR_FILTER_DST_PORT)
-#define IS_RULE_FILTERING_ON_DSFIELD(r) \
- (r->rule.filter.filter_bm & PBR_FILTER_DSFIELD)
#define IS_RULE_FILTERING_ON_FWMARK(r) \
(r->rule.filter.filter_bm & PBR_FILTER_FWMARK)
diff --git a/zebra/zebra_routemap.c b/zebra/zebra_routemap.c
index eb94e26c30..21aaf1d066 100644
--- a/zebra/zebra_routemap.c
+++ b/zebra/zebra_routemap.c
@@ -31,13 +31,9 @@ static uint32_t zebra_rmap_update_timer = ZEBRA_RMAP_DEFAULT_UPDATE_TIMER;
static struct event *zebra_t_rmap_update = NULL;
char *zebra_import_table_routemap[AFI_MAX][ZEBRA_KERNEL_TABLE_MAX];
-struct nh_rmap_obj {
+struct zebra_rmap_obj {
struct nexthop *nexthop;
- vrf_id_t vrf_id;
- uint32_t source_protocol;
- uint8_t instance;
- int metric;
- route_tag_t tag;
+ struct route_entry *re;
};
static void zebra_route_map_set_delay_timer(uint32_t value);
@@ -49,12 +45,12 @@ static enum route_map_cmd_result_t
route_match_tag(void *rule, const struct prefix *prefix, void *object)
{
route_tag_t *tag;
- struct nh_rmap_obj *nh_data;
+ struct zebra_rmap_obj *rm_data;
tag = rule;
- nh_data = object;
+ rm_data = object;
- if (nh_data->tag == *tag)
+ if (rm_data->re->tag == *tag)
return RMAP_MATCH;
return RMAP_NOMATCH;
@@ -74,19 +70,19 @@ static const struct route_map_rule_cmd route_match_tag_cmd = {
static enum route_map_cmd_result_t
route_match_interface(void *rule, const struct prefix *prefix, void *object)
{
- struct nh_rmap_obj *nh_data;
+ struct zebra_rmap_obj *rm_data;
char *ifname = rule;
ifindex_t ifindex;
if (strcasecmp(ifname, "any") == 0)
return RMAP_MATCH;
- nh_data = object;
- if (!nh_data || !nh_data->nexthop)
+ rm_data = object;
+ if (!rm_data || !rm_data->nexthop)
return RMAP_NOMATCH;
- ifindex = ifname2ifindex(ifname, nh_data->vrf_id);
+ ifindex = ifname2ifindex(ifname, rm_data->nexthop->vrf_id);
if (ifindex == 0)
return RMAP_NOMATCH;
- if (nh_data->nexthop->ifindex == ifindex)
+ if (rm_data->nexthop->ifindex == ifindex)
return RMAP_MATCH;
return RMAP_NOMATCH;
@@ -1017,21 +1013,21 @@ static enum route_map_cmd_result_t
route_match_ip_next_hop(void *rule, const struct prefix *prefix, void *object)
{
struct access_list *alist;
- struct nh_rmap_obj *nh_data;
+ struct zebra_rmap_obj *rm_data;
struct prefix_ipv4 p;
- nh_data = object;
- if (!nh_data)
+ rm_data = object;
+ if (!rm_data)
return RMAP_NOMATCH;
- switch (nh_data->nexthop->type) {
+ switch (rm_data->nexthop->type) {
case NEXTHOP_TYPE_IFINDEX:
/* Interface routes can't match ip next-hop */
return RMAP_NOMATCH;
case NEXTHOP_TYPE_IPV4_IFINDEX:
case NEXTHOP_TYPE_IPV4:
p.family = AF_INET;
- p.prefix = nh_data->nexthop->gate.ipv4;
+ p.prefix = rm_data->nexthop->gate.ipv4;
p.prefixlen = IPV4_MAX_BITLEN;
break;
case NEXTHOP_TYPE_IPV6:
@@ -1080,21 +1076,21 @@ route_match_ip_next_hop_prefix_list(void *rule, const struct prefix *prefix,
void *object)
{
struct prefix_list *plist;
- struct nh_rmap_obj *nh_data;
+ struct zebra_rmap_obj *rm_data;
struct prefix_ipv4 p;
- nh_data = (struct nh_rmap_obj *)object;
- if (!nh_data)
+ rm_data = (struct zebra_rmap_obj *)object;
+ if (!rm_data)
return RMAP_NOMATCH;
- switch (nh_data->nexthop->type) {
+ switch (rm_data->nexthop->type) {
case NEXTHOP_TYPE_IFINDEX:
/* Interface routes can't match ip next-hop */
return RMAP_NOMATCH;
case NEXTHOP_TYPE_IPV4_IFINDEX:
case NEXTHOP_TYPE_IPV4:
p.family = AF_INET;
- p.prefix = nh_data->nexthop->gate.ipv4;
+ p.prefix = rm_data->nexthop->gate.ipv4;
p.prefixlen = IPV4_MAX_BITLEN;
break;
case NEXTHOP_TYPE_IPV6:
@@ -1264,14 +1260,14 @@ static enum route_map_cmd_result_t
route_match_ipv6_next_hop_type(void *rule, const struct prefix *prefix,
void *object)
{
- struct nh_rmap_obj *nh_data;
+ struct zebra_rmap_obj *rm_data;
if (prefix->family == AF_INET6) {
- nh_data = (struct nh_rmap_obj *)object;
- if (!nh_data)
+ rm_data = (struct zebra_rmap_obj *)object;
+ if (!rm_data)
return RMAP_NOMATCH;
- if (nh_data->nexthop->type == NEXTHOP_TYPE_BLACKHOLE)
+ if (rm_data->nexthop->type == NEXTHOP_TYPE_BLACKHOLE)
return RMAP_MATCH;
}
@@ -1356,21 +1352,21 @@ route_match_ip_nexthop_prefix_len(void *rule, const struct prefix *prefix,
void *object)
{
uint32_t *prefixlen = (uint32_t *)rule;
- struct nh_rmap_obj *nh_data;
+ struct zebra_rmap_obj *rm_data;
struct prefix_ipv4 p;
- nh_data = (struct nh_rmap_obj *)object;
- if (!nh_data || !nh_data->nexthop)
+ rm_data = (struct zebra_rmap_obj *)object;
+ if (!rm_data || !rm_data->nexthop)
return RMAP_NOMATCH;
- switch (nh_data->nexthop->type) {
+ switch (rm_data->nexthop->type) {
case NEXTHOP_TYPE_IFINDEX:
/* Interface routes can't match ip next-hop */
return RMAP_NOMATCH;
case NEXTHOP_TYPE_IPV4_IFINDEX:
case NEXTHOP_TYPE_IPV4:
p.family = AF_INET;
- p.prefix = nh_data->nexthop->gate.ipv4;
+ p.prefix = rm_data->nexthop->gate.ipv4;
p.prefixlen = IPV4_MAX_BITLEN;
break;
case NEXTHOP_TYPE_IPV6:
@@ -1395,14 +1391,14 @@ static enum route_map_cmd_result_t
route_match_ip_next_hop_type(void *rule, const struct prefix *prefix,
void *object)
{
- struct nh_rmap_obj *nh_data;
+ struct zebra_rmap_obj *rm_data;
if (prefix->family == AF_INET) {
- nh_data = (struct nh_rmap_obj *)object;
- if (!nh_data)
+ rm_data = (struct zebra_rmap_obj *)object;
+ if (!rm_data)
return RMAP_NOMATCH;
- if (nh_data->nexthop->type == NEXTHOP_TYPE_BLACKHOLE)
+ if (rm_data->nexthop->type == NEXTHOP_TYPE_BLACKHOLE)
return RMAP_MATCH;
}
@@ -1432,15 +1428,14 @@ static const struct route_map_rule_cmd
static enum route_map_cmd_result_t
route_match_source_protocol(void *rule, const struct prefix *p, void *object)
{
- uint32_t *rib_type = (uint32_t *)rule;
- struct nh_rmap_obj *nh_data;
+ int32_t *rib_type = (int32_t *)rule;
+ struct zebra_rmap_obj *rm_data;
- nh_data = (struct nh_rmap_obj *)object;
- if (!nh_data)
+ rm_data = (struct zebra_rmap_obj *)object;
+ if (!rm_data)
return RMAP_NOMATCH;
- return ((nh_data->source_protocol == *rib_type) ? RMAP_MATCH
- : RMAP_NOMATCH);
+ return ((rm_data->re->type == *rib_type) ? RMAP_MATCH : RMAP_NOMATCH);
}
static void *route_match_source_protocol_compile(const char *arg)
@@ -1473,13 +1468,13 @@ static enum route_map_cmd_result_t
route_match_source_instance(void *rule, const struct prefix *p, void *object)
{
uint8_t *instance = (uint8_t *)rule;
- struct nh_rmap_obj *nh_data;
+ struct zebra_rmap_obj *rm_data;
- nh_data = (struct nh_rmap_obj *)object;
- if (!nh_data)
+ rm_data = (struct zebra_rmap_obj *)object;
+ if (!rm_data)
return RMAP_NOMATCH;
- return (nh_data->instance == *instance) ? RMAP_MATCH : RMAP_NOMATCH;
+ return (rm_data->re->instance == *instance) ? RMAP_MATCH : RMAP_NOMATCH;
}
static void *route_match_source_instance_compile(const char *arg)
@@ -1513,10 +1508,10 @@ static const struct route_map_rule_cmd route_match_source_instance_cmd = {
static enum route_map_cmd_result_t
route_set_src(void *rule, const struct prefix *prefix, void *object)
{
- struct nh_rmap_obj *nh_data;
+ struct zebra_rmap_obj *rm_data;
- nh_data = (struct nh_rmap_obj *)object;
- nh_data->nexthop->rmap_src = *(union g_addr *)rule;
+ rm_data = (struct zebra_rmap_obj *)object;
+ rm_data->nexthop->rmap_src = *(union g_addr *)rule;
return RMAP_OKAY;
}
@@ -1761,26 +1756,22 @@ void zebra_routemap_finish(void)
route_map_finish();
}
-route_map_result_t
-zebra_route_map_check(afi_t family, int rib_type, uint8_t instance,
- const struct prefix *p, struct nexthop *nexthop,
- struct zebra_vrf *zvrf, route_tag_t tag)
+route_map_result_t zebra_route_map_check(afi_t family, struct route_entry *re,
+ const struct prefix *p,
+ struct nexthop *nexthop,
+ struct zebra_vrf *zvrf)
{
struct route_map *rmap = NULL;
char *rm_name;
route_map_result_t ret = RMAP_PERMITMATCH;
- struct nh_rmap_obj nh_obj;
+ struct zebra_rmap_obj rm_obj;
- nh_obj.nexthop = nexthop;
- nh_obj.vrf_id = nexthop->vrf_id;
- nh_obj.source_protocol = rib_type;
- nh_obj.instance = instance;
- nh_obj.metric = 0;
- nh_obj.tag = tag;
+ rm_obj.nexthop = nexthop;
+ rm_obj.re = re;
- if (rib_type >= 0 && rib_type < ZEBRA_ROUTE_MAX) {
- rm_name = PROTO_RM_NAME(zvrf, family, rib_type);
- rmap = PROTO_RM_MAP(zvrf, family, rib_type);
+ if (re->type >= 0 && re->type < ZEBRA_ROUTE_MAX) {
+ rm_name = PROTO_RM_NAME(zvrf, family, re->type);
+ rmap = PROTO_RM_MAP(zvrf, family, re->type);
if (rm_name && !rmap)
return RMAP_DENYMATCH;
@@ -1793,7 +1784,7 @@ zebra_route_map_check(afi_t family, int rib_type, uint8_t instance,
return RMAP_DENYMATCH;
}
if (rmap) {
- ret = route_map_apply(rmap, p, &nh_obj);
+ ret = route_map_apply(rmap, p, &rm_obj);
}
return (ret);
@@ -1816,28 +1807,23 @@ void zebra_del_import_table_route_map(afi_t afi, uint32_t table)
XFREE(MTYPE_ROUTE_MAP_NAME, zebra_import_table_routemap[afi][table]);
}
-route_map_result_t
-zebra_import_table_route_map_check(int family, int re_type, uint8_t instance,
- const struct prefix *p,
- struct nexthop *nexthop,
- vrf_id_t vrf_id, route_tag_t tag,
- const char *rmap_name)
+route_map_result_t zebra_import_table_route_map_check(int family,
+ struct route_entry *re,
+ const struct prefix *p,
+ struct nexthop *nexthop,
+ const char *rmap_name)
{
struct route_map *rmap = NULL;
route_map_result_t ret = RMAP_DENYMATCH;
- struct nh_rmap_obj nh_obj;
+ struct zebra_rmap_obj rm_obj;
- nh_obj.nexthop = nexthop;
- nh_obj.vrf_id = vrf_id;
- nh_obj.source_protocol = re_type;
- nh_obj.instance = instance;
- nh_obj.metric = 0;
- nh_obj.tag = tag;
+ rm_obj.nexthop = nexthop;
+ rm_obj.re = re;
- if (re_type >= 0 && re_type < ZEBRA_ROUTE_MAX)
+ if (re->type >= 0 && re->type < ZEBRA_ROUTE_MAX)
rmap = route_map_lookup_by_name(rmap_name);
if (rmap) {
- ret = route_map_apply(rmap, p, &nh_obj);
+ ret = route_map_apply(rmap, p, &rm_obj);
}
return (ret);
@@ -1851,21 +1837,17 @@ route_map_result_t zebra_nht_route_map_check(afi_t afi, int client_proto,
{
struct route_map *rmap = NULL;
route_map_result_t ret = RMAP_PERMITMATCH;
- struct nh_rmap_obj nh_obj;
+ struct zebra_rmap_obj rm_obj;
- nh_obj.nexthop = nexthop;
- nh_obj.vrf_id = nexthop->vrf_id;
- nh_obj.source_protocol = re->type;
- nh_obj.instance = re->instance;
- nh_obj.metric = re->metric;
- nh_obj.tag = re->tag;
+ rm_obj.nexthop = nexthop;
+ rm_obj.re = re;
if (client_proto >= 0 && client_proto < ZEBRA_ROUTE_MAX)
rmap = NHT_RM_MAP(zvrf, afi, client_proto);
if (!rmap && NHT_RM_MAP(zvrf, afi, ZEBRA_ROUTE_MAX))
rmap = NHT_RM_MAP(zvrf, afi, ZEBRA_ROUTE_MAX);
if (rmap)
- ret = route_map_apply(rmap, p, &nh_obj);
+ ret = route_map_apply(rmap, p, &rm_obj);
return ret;
}
diff --git a/zebra/zebra_routemap.h b/zebra/zebra_routemap.h
index f77735edc2..fceb53c841 100644
--- a/zebra/zebra_routemap.h
+++ b/zebra/zebra_routemap.h
@@ -21,19 +21,19 @@ extern void zebra_add_import_table_route_map(afi_t afi, const char *rmap_name,
uint32_t table);
extern void zebra_del_import_table_route_map(afi_t afi, uint32_t table);
-extern route_map_result_t
-zebra_import_table_route_map_check(int family, int rib_type, uint8_t instance,
- const struct prefix *p,
- struct nexthop *nexthop, vrf_id_t vrf_id,
- route_tag_t tag, const char *rmap_name);
-extern route_map_result_t
-zebra_route_map_check(afi_t family, int rib_type, uint8_t instance,
- const struct prefix *p, struct nexthop *nexthop,
- struct zebra_vrf *zvrf, route_tag_t tag);
-extern route_map_result_t
-zebra_nht_route_map_check(afi_t afi, int client_proto, const struct prefix *p,
- struct zebra_vrf *zvrf, struct route_entry *,
- struct nexthop *nexthop);
+extern route_map_result_t zebra_import_table_route_map_check(
+ int family, struct route_entry *re, const struct prefix *p,
+ struct nexthop *nexthop, const char *rmap_name);
+extern route_map_result_t zebra_route_map_check(afi_t family,
+ struct route_entry *re,
+ const struct prefix *p,
+ struct nexthop *nexthop,
+ struct zebra_vrf *zvrf);
+extern route_map_result_t zebra_nht_route_map_check(afi_t afi, int client_proto,
+ const struct prefix *p,
+ struct zebra_vrf *zvrf,
+ struct route_entry *re,
+ struct nexthop *nexthop);
extern void zebra_routemap_vrf_delete(struct zebra_vrf *zvrf);