mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-10 23:29:20 +00:00
bgpd: add 'mpls bgp forwarding' to ease mpls vpn ebgp peering
RFC4364 describes peerings between multiple AS domains, to ease the continuity of VPN services across multiple SPs. This commit implements a sub-set of IETF option b) described in chapter 10 b. The ASBR to ASBR approach is taken, with an EBGP peering between the two routers. The EBGP peering must be directly connected to the outgoing interface used. In those conditions, the next hop is directly connected, and there is no need to have a transport label to convey the VPN label. A new vty command is added on a per interface basis: This command if enabled, will permit to convey BGP VPN labels without any transport labels (i.e. with implicit-null label). restriction: this command is used only for EBGP directly connected peerings. Other use cases are not covered. Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
This commit is contained in:
parent
6e616738ca
commit
4cd690ae4d
@ -511,6 +511,8 @@ int main(int argc, char **argv)
|
|||||||
", bgp@%s:%d", address, bm->port);
|
", bgp@%s:%d", address, bm->port);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bgp_if_init();
|
||||||
|
|
||||||
frr_config_fork();
|
frr_config_fork();
|
||||||
/* must be called after fork() */
|
/* must be called after fork() */
|
||||||
bgp_gr_apply_running_config();
|
bgp_gr_apply_running_config();
|
||||||
|
@ -978,6 +978,11 @@ leak_update(struct bgp *to_bgp, struct bgp_dest *bn,
|
|||||||
new = info_make(ZEBRA_ROUTE_BGP, BGP_ROUTE_IMPORTED, 0,
|
new = info_make(ZEBRA_ROUTE_BGP, BGP_ROUTE_IMPORTED, 0,
|
||||||
to_bgp->peer_self, new_attr, bn);
|
to_bgp->peer_self, new_attr, bn);
|
||||||
|
|
||||||
|
if (source_bpi->peer) {
|
||||||
|
extra = bgp_path_info_extra_get(new);
|
||||||
|
extra->peer_orig = peer_lock(source_bpi->peer);
|
||||||
|
}
|
||||||
|
|
||||||
if (nexthop_self_flag)
|
if (nexthop_self_flag)
|
||||||
bgp_path_info_set_flag(bn, new, BGP_PATH_ANNC_NH_SELF);
|
bgp_path_info_set_flag(bn, new, BGP_PATH_ANNC_NH_SELF);
|
||||||
|
|
||||||
|
@ -61,6 +61,42 @@ static int bgp_isvalid_nexthop(struct bgp_nexthop_cache *bnc)
|
|||||||
&& bnc->nexthop_num > 0));
|
&& bnc->nexthop_num > 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int bgp_isvalid_nexthop_for_ebgp(struct bgp_nexthop_cache *bnc,
|
||||||
|
struct bgp_path_info *path)
|
||||||
|
{
|
||||||
|
struct interface *ifp = NULL;
|
||||||
|
struct nexthop *nexthop;
|
||||||
|
struct bgp_interface *iifp;
|
||||||
|
struct peer *peer;
|
||||||
|
|
||||||
|
if (!path->extra || !path->extra->peer_orig)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
peer = path->extra->peer_orig;
|
||||||
|
|
||||||
|
/* only connected ebgp peers are valid */
|
||||||
|
if (peer->sort != BGP_PEER_EBGP || peer->ttl != BGP_DEFAULT_TTL ||
|
||||||
|
CHECK_FLAG(peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK) ||
|
||||||
|
CHECK_FLAG(peer->bgp->flags, BGP_FLAG_DISABLE_NH_CONNECTED_CHK))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (nexthop = bnc->nexthop; nexthop; nexthop = nexthop->next) {
|
||||||
|
if (nexthop->type == NEXTHOP_TYPE_IFINDEX ||
|
||||||
|
nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX ||
|
||||||
|
nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX) {
|
||||||
|
ifp = if_lookup_by_index(
|
||||||
|
bnc->ifindex ? bnc->ifindex : nexthop->ifindex,
|
||||||
|
bnc->bgp->vrf_id);
|
||||||
|
}
|
||||||
|
if (!ifp)
|
||||||
|
continue;
|
||||||
|
iifp = ifp->info;
|
||||||
|
if (CHECK_FLAG(iifp->flags, BGP_INTERFACE_MPLS_BGP_FORWARDING))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
static int bgp_isvalid_nexthop_for_mplsovergre(struct bgp_nexthop_cache *bnc,
|
static int bgp_isvalid_nexthop_for_mplsovergre(struct bgp_nexthop_cache *bnc,
|
||||||
struct bgp_path_info *path)
|
struct bgp_path_info *path)
|
||||||
{
|
{
|
||||||
@ -105,6 +141,7 @@ static int bgp_isvalid_nexthop_for_mpls(struct bgp_nexthop_cache *bnc,
|
|||||||
(bnc && (bnc->nexthop_num > 0 &&
|
(bnc && (bnc->nexthop_num > 0 &&
|
||||||
(CHECK_FLAG(bnc->flags, BGP_NEXTHOP_LABELED_VALID) ||
|
(CHECK_FLAG(bnc->flags, BGP_NEXTHOP_LABELED_VALID) ||
|
||||||
bnc->bgp->srv6_enabled ||
|
bnc->bgp->srv6_enabled ||
|
||||||
|
bgp_isvalid_nexthop_for_ebgp(bnc, path) ||
|
||||||
bgp_isvalid_nexthop_for_mplsovergre(bnc, path)))));
|
bgp_isvalid_nexthop_for_mplsovergre(bnc, path)))));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -255,6 +255,9 @@ void bgp_path_info_extra_free(struct bgp_path_info_extra **extra)
|
|||||||
if (e->bgp_orig)
|
if (e->bgp_orig)
|
||||||
bgp_unlock(e->bgp_orig);
|
bgp_unlock(e->bgp_orig);
|
||||||
|
|
||||||
|
if (e->peer_orig)
|
||||||
|
peer_unlock(e->peer_orig);
|
||||||
|
|
||||||
if (e->aggr_suppressors)
|
if (e->aggr_suppressors)
|
||||||
list_delete(&e->aggr_suppressors);
|
list_delete(&e->aggr_suppressors);
|
||||||
|
|
||||||
|
@ -235,6 +235,12 @@ struct bgp_path_info_extra {
|
|||||||
*/
|
*/
|
||||||
struct bgp *bgp_orig;
|
struct bgp *bgp_orig;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Original bgp session to know if the session is a
|
||||||
|
* connected EBGP session or not
|
||||||
|
*/
|
||||||
|
struct peer *peer_orig;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Nexthop in context of original bgp instance. Needed
|
* Nexthop in context of original bgp instance. Needed
|
||||||
* for label resolution of core mpls routes exported to a vrf.
|
* for label resolution of core mpls routes exported to a vrf.
|
||||||
|
@ -53,6 +53,7 @@
|
|||||||
#include "bgpd/bgp_debug.h"
|
#include "bgpd/bgp_debug.h"
|
||||||
#include "bgpd/bgp_errors.h"
|
#include "bgpd/bgp_errors.h"
|
||||||
#include "bgpd/bgp_fsm.h"
|
#include "bgpd/bgp_fsm.h"
|
||||||
|
#include "bgpd/bgp_nht.h"
|
||||||
#include "bgpd/bgp_nexthop.h"
|
#include "bgpd/bgp_nexthop.h"
|
||||||
#include "bgpd/bgp_network.h"
|
#include "bgpd/bgp_network.h"
|
||||||
#include "bgpd/bgp_open.h"
|
#include "bgpd/bgp_open.h"
|
||||||
@ -18124,6 +18125,84 @@ static void bgp_config_end(void)
|
|||||||
bgp_post_config_delay, &t_bgp_cfg);
|
bgp_post_config_delay, &t_bgp_cfg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int config_write_interface_one(struct vty *vty, struct vrf *vrf)
|
||||||
|
{
|
||||||
|
int write = 0;
|
||||||
|
struct interface *ifp;
|
||||||
|
struct bgp_interface *iifp;
|
||||||
|
|
||||||
|
FOR_ALL_INTERFACES (vrf, ifp) {
|
||||||
|
iifp = ifp->info;
|
||||||
|
if (!iifp)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if_vty_config_start(vty, ifp);
|
||||||
|
|
||||||
|
if (CHECK_FLAG(iifp->flags,
|
||||||
|
BGP_INTERFACE_MPLS_BGP_FORWARDING)) {
|
||||||
|
vty_out(vty, " mpls bgp forwarding\n");
|
||||||
|
write++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if_vty_config_end(vty);
|
||||||
|
}
|
||||||
|
|
||||||
|
return write;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Configuration write function for bgpd. */
|
||||||
|
static int config_write_interface(struct vty *vty)
|
||||||
|
{
|
||||||
|
int write = 0;
|
||||||
|
struct vrf *vrf = NULL;
|
||||||
|
|
||||||
|
/* Display all VRF aware OSPF interface configuration */
|
||||||
|
RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
|
||||||
|
write += config_write_interface_one(vty, vrf);
|
||||||
|
}
|
||||||
|
|
||||||
|
return write;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFPY(mpls_bgp_forwarding, mpls_bgp_forwarding_cmd,
|
||||||
|
"[no$no] mpls bgp forwarding",
|
||||||
|
NO_STR MPLS_STR BGP_STR
|
||||||
|
"Enable MPLS forwarding for eBGP directly connected peers\n")
|
||||||
|
{
|
||||||
|
bool check;
|
||||||
|
struct bgp_interface *iifp;
|
||||||
|
|
||||||
|
VTY_DECLVAR_CONTEXT(interface, ifp);
|
||||||
|
iifp = ifp->info;
|
||||||
|
if (!iifp) {
|
||||||
|
vty_out(vty, "Interface %s not available\n", ifp->name);
|
||||||
|
return CMD_WARNING_CONFIG_FAILED;
|
||||||
|
}
|
||||||
|
check = CHECK_FLAG(iifp->flags, BGP_INTERFACE_MPLS_BGP_FORWARDING);
|
||||||
|
if (check != !no) {
|
||||||
|
if (no)
|
||||||
|
UNSET_FLAG(iifp->flags,
|
||||||
|
BGP_INTERFACE_MPLS_BGP_FORWARDING);
|
||||||
|
else
|
||||||
|
SET_FLAG(iifp->flags,
|
||||||
|
BGP_INTERFACE_MPLS_BGP_FORWARDING);
|
||||||
|
/* trigger a nht update on eBGP sessions */
|
||||||
|
if (if_is_operative(ifp))
|
||||||
|
bgp_nht_ifp_up(ifp);
|
||||||
|
}
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialization of BGP interface. */
|
||||||
|
static void bgp_vty_if_init(void)
|
||||||
|
{
|
||||||
|
/* Install interface node. */
|
||||||
|
if_cmd_init(config_write_interface);
|
||||||
|
|
||||||
|
/* "mpls bgp forwarding" commands. */
|
||||||
|
install_element(INTERFACE_NODE, &mpls_bgp_forwarding_cmd);
|
||||||
|
}
|
||||||
|
|
||||||
void bgp_vty_init(void)
|
void bgp_vty_init(void)
|
||||||
{
|
{
|
||||||
cmd_variable_handler_register(bgp_var_neighbor);
|
cmd_variable_handler_register(bgp_var_neighbor);
|
||||||
@ -19581,6 +19660,8 @@ void bgp_vty_init(void)
|
|||||||
install_element(BGP_SRV6_NODE, &no_bgp_srv6_locator_cmd);
|
install_element(BGP_SRV6_NODE, &no_bgp_srv6_locator_cmd);
|
||||||
install_element(BGP_IPV4_NODE, &af_sid_vpn_export_cmd);
|
install_element(BGP_IPV4_NODE, &af_sid_vpn_export_cmd);
|
||||||
install_element(BGP_IPV6_NODE, &af_sid_vpn_export_cmd);
|
install_element(BGP_IPV6_NODE, &af_sid_vpn_export_cmd);
|
||||||
|
|
||||||
|
bgp_vty_if_init();
|
||||||
}
|
}
|
||||||
|
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
|
@ -75,6 +75,8 @@ struct zclient *zclient = NULL;
|
|||||||
DEFINE_HOOK(bgp_vrf_status_changed, (struct bgp *bgp, struct interface *ifp),
|
DEFINE_HOOK(bgp_vrf_status_changed, (struct bgp *bgp, struct interface *ifp),
|
||||||
(bgp, ifp));
|
(bgp, ifp));
|
||||||
|
|
||||||
|
DEFINE_MTYPE_STATIC(BGPD, BGP_IF_INFO, "BGP interface context");
|
||||||
|
|
||||||
/* Can we install into zebra? */
|
/* Can we install into zebra? */
|
||||||
static inline bool bgp_install_info_to_zebra(struct bgp *bgp)
|
static inline bool bgp_install_info_to_zebra(struct bgp *bgp)
|
||||||
{
|
{
|
||||||
@ -3335,6 +3337,31 @@ static zclient_handler *const bgp_handlers[] = {
|
|||||||
bgp_zebra_process_srv6_locator_chunk,
|
bgp_zebra_process_srv6_locator_chunk,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int bgp_if_new_hook(struct interface *ifp)
|
||||||
|
{
|
||||||
|
struct bgp_interface *iifp;
|
||||||
|
|
||||||
|
if (ifp->info)
|
||||||
|
return 0;
|
||||||
|
iifp = XCALLOC(MTYPE_BGP_IF_INFO, sizeof(struct bgp_interface));
|
||||||
|
ifp->info = iifp;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int bgp_if_delete_hook(struct interface *ifp)
|
||||||
|
{
|
||||||
|
XFREE(MTYPE_BGP_IF_INFO, ifp->info);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void bgp_if_init(void)
|
||||||
|
{
|
||||||
|
/* Initialize Zebra interface data structure. */
|
||||||
|
hook_register_prio(if_add, 0, bgp_if_new_hook);
|
||||||
|
hook_register_prio(if_del, 0, bgp_if_delete_hook);
|
||||||
|
}
|
||||||
|
|
||||||
void bgp_zebra_init(struct thread_master *master, unsigned short instance)
|
void bgp_zebra_init(struct thread_master *master, unsigned short instance)
|
||||||
{
|
{
|
||||||
zclient_num_connects = 0;
|
zclient_num_connects = 0;
|
||||||
|
@ -35,6 +35,7 @@
|
|||||||
|
|
||||||
extern void bgp_zebra_init(struct thread_master *master,
|
extern void bgp_zebra_init(struct thread_master *master,
|
||||||
unsigned short instance);
|
unsigned short instance);
|
||||||
|
extern void bgp_if_init(void);
|
||||||
extern void bgp_zebra_init_tm_connect(struct bgp *bgp);
|
extern void bgp_zebra_init_tm_connect(struct bgp *bgp);
|
||||||
extern uint32_t bgp_zebra_tm_get_id(void);
|
extern uint32_t bgp_zebra_tm_get_id(void);
|
||||||
extern bool bgp_zebra_tm_chunk_obtained(void);
|
extern bool bgp_zebra_tm_chunk_obtained(void);
|
||||||
|
@ -778,6 +778,11 @@ struct bgp {
|
|||||||
};
|
};
|
||||||
DECLARE_QOBJ_TYPE(bgp);
|
DECLARE_QOBJ_TYPE(bgp);
|
||||||
|
|
||||||
|
struct bgp_interface {
|
||||||
|
#define BGP_INTERFACE_MPLS_BGP_FORWARDING (1 << 0)
|
||||||
|
uint32_t flags;
|
||||||
|
};
|
||||||
|
|
||||||
DECLARE_HOOK(bgp_inst_delete, (struct bgp *bgp), (bgp));
|
DECLARE_HOOK(bgp_inst_delete, (struct bgp *bgp), (bgp));
|
||||||
DECLARE_HOOK(bgp_inst_config_write,
|
DECLARE_HOOK(bgp_inst_config_write,
|
||||||
(struct bgp *bgp, struct vty *vty),
|
(struct bgp *bgp, struct vty *vty),
|
||||||
|
@ -2867,6 +2867,13 @@ added for all routes from the CPEs. Routes are validated and prevented from
|
|||||||
being sent back to the same CPE (e.g.: multi-site). This is especially needed
|
being sent back to the same CPE (e.g.: multi-site). This is especially needed
|
||||||
when using ``as-override`` or ``allowas-in`` to prevent routing loops.
|
when using ``as-override`` or ``allowas-in`` to prevent routing loops.
|
||||||
|
|
||||||
|
.. clicmd:: mpls bgp forwarding
|
||||||
|
|
||||||
|
It is possible to permit BGP install VPN prefixes without transport labels,
|
||||||
|
by issuing the following command under the interface configuration context.
|
||||||
|
This configuration will install VPN prefixes originated from an e-bgp session,
|
||||||
|
and with the next-hop directly connected.
|
||||||
|
|
||||||
.. _bgp-l3vpn-srv6:
|
.. _bgp-l3vpn-srv6:
|
||||||
|
|
||||||
L3VPN SRv6
|
L3VPN SRv6
|
||||||
|
@ -60,8 +60,13 @@ extern struct thread_master *master;
|
|||||||
#define VTYSH_ALL VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_LDPD|VTYSH_BGPD|VTYSH_ISISD|VTYSH_PIMD|VTYSH_PIM6D|VTYSH_NHRPD|VTYSH_EIGRPD|VTYSH_BABELD|VTYSH_SHARPD|VTYSH_PBRD|VTYSH_STATICD|VTYSH_BFDD|VTYSH_FABRICD|VTYSH_VRRPD|VTYSH_PATHD
|
#define VTYSH_ALL VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_LDPD|VTYSH_BGPD|VTYSH_ISISD|VTYSH_PIMD|VTYSH_PIM6D|VTYSH_NHRPD|VTYSH_EIGRPD|VTYSH_BABELD|VTYSH_SHARPD|VTYSH_PBRD|VTYSH_STATICD|VTYSH_BFDD|VTYSH_FABRICD|VTYSH_VRRPD|VTYSH_PATHD
|
||||||
#define VTYSH_ACL VTYSH_BFDD|VTYSH_BABELD|VTYSH_BGPD|VTYSH_EIGRPD|VTYSH_ISISD|VTYSH_FABRICD|VTYSH_LDPD|VTYSH_NHRPD|VTYSH_OSPF6D|VTYSH_OSPFD|VTYSH_PBRD|VTYSH_PIMD|VTYSH_PIM6D|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_VRRPD|VTYSH_ZEBRA
|
#define VTYSH_ACL VTYSH_BFDD|VTYSH_BABELD|VTYSH_BGPD|VTYSH_EIGRPD|VTYSH_ISISD|VTYSH_FABRICD|VTYSH_LDPD|VTYSH_NHRPD|VTYSH_OSPF6D|VTYSH_OSPFD|VTYSH_PBRD|VTYSH_PIMD|VTYSH_PIM6D|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_VRRPD|VTYSH_ZEBRA
|
||||||
#define VTYSH_RMAP VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ISISD|VTYSH_PIMD|VTYSH_PIM6D|VTYSH_EIGRPD|VTYSH_FABRICD
|
#define VTYSH_RMAP VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ISISD|VTYSH_PIMD|VTYSH_PIM6D|VTYSH_EIGRPD|VTYSH_FABRICD
|
||||||
#define VTYSH_INTERFACE VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_ISISD|VTYSH_PIMD|VTYSH_PIM6D|VTYSH_NHRPD|VTYSH_EIGRPD|VTYSH_BABELD|VTYSH_PBRD|VTYSH_FABRICD|VTYSH_VRRPD
|
#define VTYSH_INTERFACE_SUBSET \
|
||||||
#define VTYSH_VRF VTYSH_INTERFACE|VTYSH_STATICD
|
VTYSH_ZEBRA | VTYSH_RIPD | VTYSH_RIPNGD | VTYSH_OSPFD | VTYSH_OSPF6D | \
|
||||||
|
VTYSH_ISISD | VTYSH_PIMD | VTYSH_PIM6D | VTYSH_NHRPD | \
|
||||||
|
VTYSH_EIGRPD | VTYSH_BABELD | VTYSH_PBRD | VTYSH_FABRICD | \
|
||||||
|
VTYSH_VRRPD
|
||||||
|
#define VTYSH_INTERFACE VTYSH_INTERFACE_SUBSET | VTYSH_BGPD
|
||||||
|
#define VTYSH_VRF VTYSH_INTERFACE_SUBSET | VTYSH_STATICD
|
||||||
#define VTYSH_KEYS VTYSH_RIPD | VTYSH_EIGRPD | VTYSH_OSPF6D
|
#define VTYSH_KEYS VTYSH_RIPD | VTYSH_EIGRPD | VTYSH_OSPF6D
|
||||||
/* Daemons who can process nexthop-group configs */
|
/* Daemons who can process nexthop-group configs */
|
||||||
#define VTYSH_NH_GROUP VTYSH_PBRD|VTYSH_SHARPD
|
#define VTYSH_NH_GROUP VTYSH_PBRD|VTYSH_SHARPD
|
||||||
|
Loading…
Reference in New Issue
Block a user