mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-13 13:58:24 +00:00
bgpd: add resolution for l3vpn traffic over gre interfaces
When a route imported from l3vpn is analysed, the nexthop from default VRF is looked up against a valid MPLS path. Generally, this is done on backbones with a MPLS signalisation transport layer like LDP. Generally, the BGP connection is multiple hops away. That scenario is already working. There is case where it is possible to run L3VPN over GRE interfaces, and where there is no LSP path over that GRE interface: GRE is just here to tunnel MPLS traffic. On that case, the nexthop given in the path does not have MPLS path, but should be authorized to convey MPLS traffic provided that the user permits it via a configuration command. That commit introduces a new command that can be activated in route-map: > set l3vpn next-hop encapsulation gre That command authorizes the nexthop tracking engine to accept paths that o have a GRE interface as output, independently of the presence of an LSP path or not. A configuration example is given below. When bgp incoming vpnv4 updates are received, the nexthop of NLRI is 192.168.0.2. Based on nexthop tracking service from zebra, BGP knows that the output interface to reach 192.168.0.2 is r1-gre0. Because that interface is not MPLS based, but is a GRE tunnel, then the update will be using that nexthop to be installed. interface r1-gre0 ip address 192.168.0.1/24 exit router bgp 65500 bgp router-id 1.1.1.1 neighbor 192.168.0.2 remote-as 65500 ! address-family ipv4 unicast no neighbor 192.168.0.2 activate exit-address-family ! address-family ipv4 vpn neighbor 192.168.0.2 activate neighbor 192.168.0.2 route-map rmap in exit-address-family exit ! router bgp 65500 vrf vrf1 bgp router-id 1.1.1.1 no bgp network import-check ! address-family ipv4 unicast network 10.201.0.0/24 redistribute connected label vpn export 101 rd vpn export 444:1 rt vpn both 52:100 export vpn import vpn exit-address-family exit ! route-map rmap permit 1 set l3vpn next-hop encapsulation gre exit Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
This commit is contained in:
parent
f1f38efd83
commit
1bb550b63c
@ -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 {
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -406,6 +406,13 @@ const struct frr_yang_module_info frr_bgp_route_map_info = {
|
||||
.destroy = lib_route_map_entry_set_action_rmap_set_action_evpn_gateway_ip_ipv6_destroy,
|
||||
}
|
||||
},
|
||||
{
|
||||
.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,
|
||||
},
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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"));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user