summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bgpd/bgp_attr.h1
-rw-r--r--bgpd/bgp_nht.c56
-rw-r--r--bgpd/bgp_routemap.c81
-rw-r--r--bgpd/bgp_routemap_nb.c7
-rw-r--r--bgpd/bgp_routemap_nb.h4
-rw-r--r--bgpd/bgp_routemap_nb_config.c53
-rw-r--r--doc/user/bgp.rst19
-rw-r--r--doc/user/routemap.rst3
-rw-r--r--lib/routemap.h2
-rw-r--r--lib/routemap_cli.c5
-rw-r--r--yang/frr-bgp-route-map.yang22
11 files changed, 240 insertions, 13 deletions
diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h
index 5007fafc29..4963ea64d0 100644
--- a/bgpd/bgp_attr.h
+++ b/bgpd/bgp_attr.h
@@ -348,6 +348,7 @@ struct attr {
#define BATTR_RMAP_IPV6_LL_NHOP_CHANGED (1 << 5)
#define BATTR_RMAP_IPV6_PREFER_GLOBAL_CHANGED (1 << 6)
#define BATTR_RMAP_LINK_BW_SET (1 << 7)
+#define BATTR_RMAP_L3VPN_ACCEPT_GRE (1 << 8)
/* Router Reflector related structure. */
struct cluster_list {
diff --git a/bgpd/bgp_nht.c b/bgpd/bgp_nht.c
index 61f1b295ca..297623365a 100644
--- a/bgpd/bgp_nht.c
+++ b/bgpd/bgp_nht.c
@@ -61,22 +61,51 @@ static int bgp_isvalid_nexthop(struct bgp_nexthop_cache *bnc)
&& bnc->nexthop_num > 0));
}
-static int bgp_isvalid_labeled_nexthop(struct bgp_nexthop_cache *bnc)
+static int bgp_isvalid_nexthop_for_mplsovergre(struct bgp_nexthop_cache *bnc,
+ struct bgp_path_info *path)
+{
+ struct interface *ifp = NULL;
+ struct nexthop *nexthop;
+
+ for (nexthop = bnc->nexthop; nexthop; nexthop = nexthop->next) {
+ if (nexthop->type != NEXTHOP_TYPE_BLACKHOLE) {
+ ifp = if_lookup_by_index(
+ bnc->ifindex ? bnc->ifindex : nexthop->ifindex,
+ bnc->bgp->vrf_id);
+ if (ifp && (ifp->ll_type == ZEBRA_LLT_IPGRE ||
+ ifp->ll_type == ZEBRA_LLT_IP6GRE))
+ break;
+ }
+ }
+ if (!ifp)
+ return false;
+
+ if (CHECK_FLAG(path->attr->rmap_change_flags,
+ BATTR_RMAP_L3VPN_ACCEPT_GRE))
+ return true;
+
+ return false;
+}
+
+static int bgp_isvalid_nexthop_for_mpls(struct bgp_nexthop_cache *bnc,
+ struct bgp_path_info *path)
{
/*
- * In the case of MPLS-VPN, the label is learned from LDP or other
+ * - In the case of MPLS-VPN, the label is learned from LDP or other
* protocols, and nexthop tracking is enabled for the label.
* The value is recorded as BGP_NEXTHOP_LABELED_VALID.
- * In the case of SRv6-VPN, we need to track the reachability to the
+ * - In the case of SRv6-VPN, we need to track the reachability to the
* SID (in other words, IPv6 address). As in MPLS, we need to record
* the value as BGP_NEXTHOP_SID_VALID. However, this function is
* currently not implemented, and this function assumes that all
* Transit routes for SRv6-VPN are valid.
+ * - Otherwise check for mpls-gre acceptance
*/
- return (bgp_zebra_num_connects() == 0
- || (bnc && bnc->nexthop_num > 0
- && (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_LABELED_VALID)
- || bnc->bgp->srv6_enabled)));
+ return (bgp_zebra_num_connects() == 0 ||
+ (bnc && (bnc->nexthop_num > 0 &&
+ (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_LABELED_VALID) ||
+ bnc->bgp->srv6_enabled ||
+ bgp_isvalid_nexthop_for_mplsovergre(bnc, path)))));
}
static void bgp_unlink_nexthop_check(struct bgp_nexthop_cache *bnc)
@@ -359,11 +388,11 @@ int bgp_find_or_add_nexthop(struct bgp *bgp_route, struct bgp *bgp_nexthop,
*/
if (bgp_route->inst_type == BGP_INSTANCE_TYPE_VIEW)
return 1;
- else if (safi == SAFI_UNICAST && pi
- && pi->sub_type == BGP_ROUTE_IMPORTED && pi->extra
- && pi->extra->num_labels && !bnc->is_evpn_gwip_nexthop) {
- return bgp_isvalid_labeled_nexthop(bnc);
- } else
+ else if (safi == SAFI_UNICAST && pi &&
+ pi->sub_type == BGP_ROUTE_IMPORTED && pi->extra &&
+ pi->extra->num_labels && !bnc->is_evpn_gwip_nexthop)
+ return bgp_isvalid_nexthop_for_mpls(bnc, pi);
+ else
return (bgp_isvalid_nexthop(bnc));
}
@@ -1063,7 +1092,8 @@ void evaluate_paths(struct bgp_nexthop_cache *bnc)
&& (path->attr->evpn_overlay.type
!= OVERLAY_INDEX_GATEWAY_IP)) {
bnc_is_valid_nexthop =
- bgp_isvalid_labeled_nexthop(bnc) ? true : false;
+ bgp_isvalid_nexthop_for_mpls(bnc, path) ? true
+ : false;
} else {
if (bgp_update_martian_nexthop(
bnc->bgp, afi, safi, path->type,
diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c
index 33f68c9e88..40bbdccff4 100644
--- a/bgpd/bgp_routemap.c
+++ b/bgpd/bgp_routemap.c
@@ -1953,6 +1953,57 @@ static const struct route_map_rule_cmd route_set_ip_nexthop_cmd = {
route_set_ip_nexthop_free
};
+/* `set l3vpn next-hop encapsulation l3vpn gre' */
+
+/* Set nexthop to object */
+struct rmap_l3vpn_nexthop_encapsulation_set {
+ uint8_t protocol;
+};
+
+static enum route_map_cmd_result_t
+route_set_l3vpn_nexthop_encapsulation(void *rule, const struct prefix *prefix,
+ void *object)
+{
+ struct rmap_l3vpn_nexthop_encapsulation_set *rins = rule;
+ struct bgp_path_info *path;
+
+ path = object;
+
+ if (rins->protocol != IPPROTO_GRE)
+ return RMAP_OKAY;
+
+ SET_FLAG(path->attr->rmap_change_flags, BATTR_RMAP_L3VPN_ACCEPT_GRE);
+ return RMAP_OKAY;
+}
+
+/* Route map `l3vpn nexthop encapsulation' compile function. */
+static void *route_set_l3vpn_nexthop_encapsulation_compile(const char *arg)
+{
+ struct rmap_l3vpn_nexthop_encapsulation_set *rins;
+
+ rins = XCALLOC(MTYPE_ROUTE_MAP_COMPILED,
+ sizeof(struct rmap_l3vpn_nexthop_encapsulation_set));
+
+ /* XXX ALL GRE modes are accepted for now: gre or ip6gre */
+ rins->protocol = IPPROTO_GRE;
+
+ return rins;
+}
+
+/* Free route map's compiled `ip nexthop' value. */
+static void route_set_l3vpn_nexthop_encapsulation_free(void *rule)
+{
+ XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+/* Route map commands for l3vpn next-hop encapsulation set. */
+static const struct route_map_rule_cmd
+ route_set_l3vpn_nexthop_encapsulation_cmd = {
+ "l3vpn next-hop encapsulation",
+ route_set_l3vpn_nexthop_encapsulation,
+ route_set_l3vpn_nexthop_encapsulation_compile,
+ route_set_l3vpn_nexthop_encapsulation_free};
+
/* `set local-preference LOCAL_PREF' */
/* Set local preference. */
@@ -5290,6 +5341,34 @@ DEFUN_YANG (no_set_distance,
return nb_cli_apply_changes(vty, NULL);
}
+DEFPY_YANG(set_l3vpn_nexthop_encapsulation, set_l3vpn_nexthop_encapsulation_cmd,
+ "[no] set l3vpn next-hop encapsulation gre",
+ NO_STR SET_STR
+ "L3VPN operations\n"
+ "Next hop Information\n"
+ "Encapsulation options (for BGP only)\n"
+ "Accept L3VPN traffic over GRE encapsulation\n")
+{
+ const char *xpath =
+ "./set-action[action='frr-bgp-route-map:set-l3vpn-nexthop-encapsulation']";
+ const char *xpath_value =
+ "./set-action[action='frr-bgp-route-map:set-l3vpn-nexthop-encapsulation']/rmap-set-action/frr-bgp-route-map:l3vpn-nexthop-encapsulation";
+ enum nb_operation operation;
+
+ if (no)
+ operation = NB_OP_DESTROY;
+ else
+ operation = NB_OP_CREATE;
+
+ nb_cli_enqueue_change(vty, xpath, operation, NULL);
+ if (operation == NB_OP_DESTROY)
+ return nb_cli_apply_changes(vty, NULL);
+
+ nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, "gre");
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
DEFUN_YANG (set_local_pref,
set_local_pref_cmd,
"set local-preference WORD",
@@ -6835,6 +6914,7 @@ void bgp_route_map_init(void)
route_map_install_set(&route_set_ecommunity_none_cmd);
route_map_install_set(&route_set_tag_cmd);
route_map_install_set(&route_set_label_index_cmd);
+ route_map_install_set(&route_set_l3vpn_nexthop_encapsulation_cmd);
install_element(RMAP_NODE, &match_peer_cmd);
install_element(RMAP_NODE, &match_peer_local_cmd);
@@ -6937,6 +7017,7 @@ void bgp_route_map_init(void)
install_element(RMAP_NODE, &no_set_ipx_vpn_nexthop_cmd);
install_element(RMAP_NODE, &set_originator_id_cmd);
install_element(RMAP_NODE, &no_set_originator_id_cmd);
+ install_element(RMAP_NODE, &set_l3vpn_nexthop_encapsulation_cmd);
route_map_install_match(&route_match_ipv6_address_cmd);
route_map_install_match(&route_match_ipv6_next_hop_cmd);
diff --git a/bgpd/bgp_routemap_nb.c b/bgpd/bgp_routemap_nb.c
index 585596e1aa..2117334f7f 100644
--- a/bgpd/bgp_routemap_nb.c
+++ b/bgpd/bgp_routemap_nb.c
@@ -407,6 +407,13 @@ const struct frr_yang_module_info frr_bgp_route_map_info = {
}
},
{
+ .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:l3vpn-nexthop-encapsulation",
+ .cbs = {
+ .modify = lib_route_map_entry_set_action_rmap_set_action_l3vpn_nexthop_encapsulation_modify,
+ .destroy = lib_route_map_entry_set_action_rmap_set_action_l3vpn_nexthop_encapsulation_destroy,
+ }
+ },
+ {
.xpath = NULL,
},
}
diff --git a/bgpd/bgp_routemap_nb.h b/bgpd/bgp_routemap_nb.h
index a01adf7d5d..cd7a70dbcf 100644
--- a/bgpd/bgp_routemap_nb.h
+++ b/bgpd/bgp_routemap_nb.h
@@ -150,6 +150,10 @@ int lib_route_map_entry_set_action_rmap_set_action_evpn_gateway_ip_ipv6_modify(
struct nb_cb_modify_args *args);
int lib_route_map_entry_set_action_rmap_set_action_evpn_gateway_ip_ipv6_destroy(
struct nb_cb_destroy_args *args);
+int lib_route_map_entry_set_action_rmap_set_action_l3vpn_nexthop_encapsulation_modify(
+ struct nb_cb_modify_args *args);
+int lib_route_map_entry_set_action_rmap_set_action_l3vpn_nexthop_encapsulation_destroy(
+ struct nb_cb_destroy_args *args);
#ifdef __cplusplus
}
diff --git a/bgpd/bgp_routemap_nb_config.c b/bgpd/bgp_routemap_nb_config.c
index b87877b1e0..585c2a3ff0 100644
--- a/bgpd/bgp_routemap_nb_config.c
+++ b/bgpd/bgp_routemap_nb_config.c
@@ -2922,3 +2922,56 @@ int lib_route_map_entry_set_action_rmap_set_action_evpn_gateway_ip_ipv6_destroy(
return NB_OK;
}
+
+/*
+ * XPath:
+ * /frr-route-map:lib/route-map/entry/set-action/rmap-set-action/l3vpn-nexthop-encapsulation
+ */
+int lib_route_map_entry_set_action_rmap_set_action_l3vpn_nexthop_encapsulation_modify(
+ struct nb_cb_modify_args *args)
+{
+ struct routemap_hook_context *rhc;
+ const char *type;
+ int rv;
+
+ switch (args->event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ break;
+ case NB_EV_APPLY:
+ /* Add configuration. */
+ rhc = nb_running_get_entry(args->dnode, NULL, true);
+ type = yang_dnode_get_string(args->dnode, NULL);
+
+ /* Set destroy information. */
+ rhc->rhc_shook = generic_set_delete;
+ rhc->rhc_rule = "l3vpn next-hop encapsulation";
+ rhc->rhc_event = RMAP_EVENT_SET_DELETED;
+
+ rv = generic_set_add(rhc->rhc_rmi,
+ "l3vpn next-hop encapsulation", type,
+ args->errmsg, args->errmsg_len);
+ if (rv != CMD_SUCCESS) {
+ rhc->rhc_shook = NULL;
+ return NB_ERR_INCONSISTENCY;
+ }
+ }
+
+ return NB_OK;
+}
+
+int lib_route_map_entry_set_action_rmap_set_action_l3vpn_nexthop_encapsulation_destroy(
+ struct nb_cb_destroy_args *args)
+{
+ switch (args->event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ break;
+ case NB_EV_APPLY:
+ return lib_route_map_entry_set_destroy(args);
+ }
+
+ return NB_OK;
+}
diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst
index 033b753639..905c9861b3 100644
--- a/doc/user/bgp.rst
+++ b/doc/user/bgp.rst
@@ -2720,6 +2720,25 @@ are reached using *core* MPLS labels which are distributed using LDP or BGP
labeled unicast. *bgpd* also supports inter-VRF route leaking.
+L3VPN over GRE interfaces
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+In MPLS-VPN or SRv6-VPN, an L3VPN next-hop entry requires that the path
+chosen respectively contains a labelled path or a valid SID IPv6 address.
+Otherwise the L3VPN entry will not be installed. It is possible to ignore
+that check when the path chosen by the next-hop uses a GRE interface, and
+there is a route-map configured at inbound side of ipv4-vpn or ipv6-vpn
+address family with following syntax:
+
+.. clicmd:: set l3vpn next-hop encapsulation gre
+
+The incoming BGP L3VPN entry is accepted, provided that the next hop of the
+L3VPN entry uses a path that takes the GRE tunnel as outgoing interface. The
+remote endpoint should be configured just behind the GRE tunnel; remote
+device configuration may vary depending whether it acts at edge endpoint or
+not: in any case, the expectation is that incoming MPLS traffic received at
+this endpoint should be considered as a valid path for L3VPN.
+
.. _bgp-vrf-route-leaking:
VRF Route Leaking
diff --git a/doc/user/routemap.rst b/doc/user/routemap.rst
index 05c9eeb755..5e222576ca 100644
--- a/doc/user/routemap.rst
+++ b/doc/user/routemap.rst
@@ -339,6 +339,9 @@ Route Map Set Command
Set the color of a SR-TE Policy to be applied to a learned route. The SR-TE
Policy is uniquely determined by the color and the BGP nexthop.
+.. clicmd:: set l3vpn next-hop encapsulation gre
+
+ Accept L3VPN traffic over GRE encapsulation.
.. _route-map-call-command:
diff --git a/lib/routemap.h b/lib/routemap.h
index ad391981e0..0152e820d0 100644
--- a/lib/routemap.h
+++ b/lib/routemap.h
@@ -387,6 +387,8 @@ DECLARE_QOBJ_TYPE(route_map);
(strmatch(A, "frr-bgp-route-map:set-evpn-gateway-ip-ipv4"))
#define IS_SET_BGP_EVPN_GATEWAY_IP_IPV6(A) \
(strmatch(A, "frr-bgp-route-map:set-evpn-gateway-ip-ipv6"))
+#define IS_SET_BGP_L3VPN_NEXTHOP_ENCAPSULATION(A) \
+ (strmatch(A, "frr-bgp-route-map:set-l3vpn-nexthop-encapsulation"))
enum ecommunity_lb_type {
EXPLICIT_BANDWIDTH,
diff --git a/lib/routemap_cli.c b/lib/routemap_cli.c
index ff98a14c41..42c7a05d18 100644
--- a/lib/routemap_cli.c
+++ b/lib/routemap_cli.c
@@ -1258,6 +1258,11 @@ void route_map_action_show(struct vty *vty, const struct lyd_node *dnode,
yang_dnode_get_string(
dnode,
"./rmap-set-action/frr-bgp-route-map:evpn-gateway-ip-ipv6"));
+ } else if (IS_SET_BGP_L3VPN_NEXTHOP_ENCAPSULATION(action)) {
+ vty_out(vty, " set l3vpn next-hop encapsulation %s\n",
+ yang_dnode_get_string(
+ dnode,
+ "./rmap-set-action/frr-bgp-route-map:l3vpn-nexthop-encapsulation"));
}
}
diff --git a/yang/frr-bgp-route-map.yang b/yang/frr-bgp-route-map.yang
index eaa7891f0c..fcfd14e4fe 100644
--- a/yang/frr-bgp-route-map.yang
+++ b/yang/frr-bgp-route-map.yang
@@ -330,6 +330,12 @@ module frr-bgp-route-map {
"Set EVPN gateway IP overlay index IPv6";
}
+ identity set-l3vpn-nexthop-encapsulation {
+ base frr-route-map:rmap-set-type;
+ description
+ "Accept L3VPN traffic over other than LSP encapsulation";
+ }
+
grouping extcommunity-non-transitive-types {
leaf two-octet-as-specific {
type boolean;
@@ -902,5 +908,21 @@ module frr-bgp-route-map {
type inet:ipv6-address;
}
}
+ case l3vpn-nexthop-encapsulation {
+ when
+ "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:set-action/frr-route-map:action,
+ 'frr-bgp-route-map:set-l3vpn-nexthop-encapsulation')";
+ description
+ "Accept L3VPN traffic over other than LSP encapsulation";
+ leaf l3vpn-nexthop-encapsulation {
+ type enumeration {
+ enum "gre" {
+ value 0;
+ description
+ "GRE protocol";
+ }
+ }
+ }
+ }
}
}