summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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.c359
-rw-r--r--bgpd/bgp_route.h14
-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--lib/nexthop_group.c1
-rw-r--r--lib/pbr.h37
-rw-r--r--lib/zclient.c197
-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--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_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
35 files changed, 2047 insertions, 967 deletions
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..0cb32ff94c 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)
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_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/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/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/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/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_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);