Merge pull request #3020 from donaldsharp/global_5549

Allow v6 global addresses to be nexthops for v4 addresses in bgp
This commit is contained in:
Russ White 2018-09-24 09:55:50 -04:00 committed by GitHub
commit 82977e243a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 116 additions and 15 deletions

View File

@ -415,6 +415,8 @@ void bgp_parse_nexthop_update(int command, vrf_id_t vrf_id)
bnc->change_flags |= BGP_NEXTHOP_CHANGED; bnc->change_flags |= BGP_NEXTHOP_CHANGED;
if (nhr.nexthop_num) { if (nhr.nexthop_num) {
struct peer *peer = bnc->nht_info;
/* notify bgp fsm if nbr ip goes from invalid->valid */ /* notify bgp fsm if nbr ip goes from invalid->valid */
if (!bnc->nexthop_num) if (!bnc->nexthop_num)
UNSET_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED); UNSET_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED);
@ -430,6 +432,22 @@ void bgp_parse_nexthop_update(int command, vrf_id_t vrf_id)
nexthop = nexthop_from_zapi_nexthop(&nhr.nexthops[i]); nexthop = nexthop_from_zapi_nexthop(&nhr.nexthops[i]);
/*
* Turn on RA for the v6 nexthops
* we receive from bgp. This is to allow us
* to work with v4 routing over v6 nexthops
*/
if (peer &&
CHECK_FLAG(peer->flags, PEER_FLAG_CAPABILITY_ENHE)
&& nhr.prefix.family == AF_INET6) {
struct interface *ifp;
ifp = if_lookup_by_index(nexthop->ifindex,
nexthop->vrf_id);
zclient_send_interface_radv_req(
zclient, nexthop->vrf_id, ifp, true,
BGP_UNNUM_DEFAULT_RA_INTERVAL);
}
/* There is at least one label-switched path */ /* There is at least one label-switched path */
if (nexthop->nh_label && if (nexthop->nh_label &&
nexthop->nh_label->num_labels) { nexthop->nh_label->num_labels) {

View File

@ -1331,7 +1331,6 @@ void bgp_open_capability(struct stream *s, struct peer *peer)
*/ */
if (CHECK_FLAG(peer->flags, PEER_FLAG_CAPABILITY_ENHE) if (CHECK_FLAG(peer->flags, PEER_FLAG_CAPABILITY_ENHE)
&& peer->su.sa.sa_family == AF_INET6 && peer->su.sa.sa_family == AF_INET6
&& IN6_IS_ADDR_LINKLOCAL(&peer->su.sin6.sin6_addr)
&& afi == AFI_IP && afi == AFI_IP
&& (safi == SAFI_UNICAST && (safi == SAFI_UNICAST
|| safi == SAFI_LABELED_UNICAST)) { || safi == SAFI_LABELED_UNICAST)) {

View File

@ -845,6 +845,15 @@ Configuring Peers
specified number of hops away will be allowed to become neighbors. This specified number of hops away will be allowed to become neighbors. This
command is mutually exclusive with *ebgp-multihop*. command is mutually exclusive with *ebgp-multihop*.
.. index:: [no] neighbor PEER capability extended-nexthop
.. clicmd:: [no] neighbor PEER capability extended-nexthop
Allow bgp to negotiate the extended-nexthop capability with it's peer.
If you are peering over a v6 LL address then this capability is turned
on automatically. If you are peering over a v6 Global Address then
turning on this command will allow BGP to install v4 routes with
v6 nexthops if you do not have v4 configured on interfaces.
.. index:: [no] bgp fast-external-failover .. index:: [no] bgp fast-external-failover
.. clicmd:: [no] bgp fast-external-failover .. clicmd:: [no] bgp fast-external-failover

View File

@ -51,6 +51,8 @@
#include "zebra/zebra_vxlan.h" #include "zebra/zebra_vxlan.h"
#include "zebra/zebra_errors.h" #include "zebra/zebra_errors.h"
DEFINE_MTYPE_STATIC(ZEBRA, ZINFO, "Zebra Interface Information")
#define ZEBRA_PTM_SUPPORT #define ZEBRA_PTM_SUPPORT
DEFINE_HOOK(zebra_if_extra_info, (struct vty * vty, struct interface *ifp), DEFINE_HOOK(zebra_if_extra_info, (struct vty * vty, struct interface *ifp),
@ -99,7 +101,7 @@ static int if_zebra_new_hook(struct interface *ifp)
{ {
struct zebra_if *zebra_if; struct zebra_if *zebra_if;
zebra_if = XCALLOC(MTYPE_TMP, sizeof(struct zebra_if)); zebra_if = XCALLOC(MTYPE_ZINFO, sizeof(struct zebra_if));
zebra_if->multicast = IF_ZEBRA_MULTICAST_UNSPEC; zebra_if->multicast = IF_ZEBRA_MULTICAST_UNSPEC;
zebra_if->shutdown = IF_ZEBRA_SHUTDOWN_OFF; zebra_if->shutdown = IF_ZEBRA_SHUTDOWN_OFF;
@ -136,6 +138,8 @@ static int if_zebra_new_hook(struct interface *ifp)
} }
#endif /* HAVE_RTADV */ #endif /* HAVE_RTADV */
memset(&zebra_if->neigh_mac[0], 0, 6);
/* Initialize installed address chains tree. */ /* Initialize installed address chains tree. */
zebra_if->ipv4_subnets = zebra_if->ipv4_subnets =
route_table_init_with_delegate(&zebra_if_table_delegate); route_table_init_with_delegate(&zebra_if_table_delegate);
@ -175,7 +179,7 @@ static int if_zebra_delete_hook(struct interface *ifp)
THREAD_OFF(zebra_if->speed_update); THREAD_OFF(zebra_if->speed_update);
XFREE(MTYPE_TMP, zebra_if); XFREE(MTYPE_ZINFO, zebra_if);
} }
return 0; return 0;
@ -802,19 +806,32 @@ static void ipv6_ll_address_to_mac(struct in6_addr *address, uint8_t *mac)
mac[5] = address->s6_addr[15]; mac[5] = address->s6_addr[15];
} }
void if_nbr_ipv6ll_to_ipv4ll_neigh_update(struct interface *ifp, static bool mac_is_same(char *mac1, char *mac2)
struct in6_addr *address, int add) {
if (mac1[0] == mac2[0] &&
mac1[1] == mac2[1] &&
mac1[2] == mac2[2] &&
mac1[3] == mac2[3] &&
mac1[4] == mac2[4] &&
mac1[5] == mac2[5])
return true;
else
return false;
}
void if_nbr_mac_to_ipv4ll_neigh_update(struct interface *ifp,
char mac[6],
struct in6_addr *address,
int add)
{ {
struct zebra_vrf *zvrf = vrf_info_lookup(ifp->vrf_id); struct zebra_vrf *zvrf = vrf_info_lookup(ifp->vrf_id);
struct zebra_if *zif = ifp->info; struct zebra_if *zif = ifp->info;
char buf[16] = "169.254.0.1"; char buf[16] = "169.254.0.1";
struct in_addr ipv4_ll; struct in_addr ipv4_ll;
char mac[6];
ns_id_t ns_id; ns_id_t ns_id;
inet_pton(AF_INET, buf, &ipv4_ll); inet_pton(AF_INET, buf, &ipv4_ll);
ipv6_ll_address_to_mac(address, (uint8_t *)mac);
ns_id = zvrf->zns->ns_id; ns_id = zvrf->zns->ns_id;
/* /*
@ -823,10 +840,16 @@ void if_nbr_ipv6ll_to_ipv4ll_neigh_update(struct interface *ifp,
* *
* supported message types are RTM_NEWNEIGH and RTM_DELNEIGH * supported message types are RTM_NEWNEIGH and RTM_DELNEIGH
*/ */
kernel_neigh_update(0, ifp->ifindex, ipv4_ll.s_addr, mac, 6, ns_id); if (!mac_is_same(zif->neigh_mac, mac)) {
kernel_neigh_update(0, ifp->ifindex, ipv4_ll.s_addr,
mac, 6, ns_id);
/* Add arp record */ /* Add arp record */
kernel_neigh_update(add, ifp->ifindex, ipv4_ll.s_addr, mac, 6, ns_id); kernel_neigh_update(add, ifp->ifindex, ipv4_ll.s_addr,
mac, 6, ns_id);
}
memcpy(&zif->neigh_mac[0], &mac[0], 6);
/* /*
* We need to note whether or not we originated a v6 * We need to note whether or not we originated a v6
@ -840,6 +863,16 @@ void if_nbr_ipv6ll_to_ipv4ll_neigh_update(struct interface *ifp,
zvrf->neigh_updates++; zvrf->neigh_updates++;
} }
void if_nbr_ipv6ll_to_ipv4ll_neigh_update(struct interface *ifp,
struct in6_addr *address, int add)
{
char mac[6];
ipv6_ll_address_to_mac(address, (uint8_t *)mac);
if_nbr_mac_to_ipv4ll_neigh_update(ifp, mac, address, add);
}
static void if_nbr_ipv6ll_to_ipv4ll_neigh_add_all(struct interface *ifp) static void if_nbr_ipv6ll_to_ipv4ll_neigh_add_all(struct interface *ifp)
{ {
if (listhead(ifp->nbr_connected)) { if (listhead(ifp->nbr_connected)) {

View File

@ -279,6 +279,7 @@ struct zebra_if {
* for bgp unnumbered? * for bgp unnumbered?
*/ */
bool v6_2_v4_ll_neigh_entry; bool v6_2_v4_ll_neigh_entry;
char neigh_mac[6];
struct in6_addr v6_2_v4_ll_addr6; struct in6_addr v6_2_v4_ll_addr6;
}; };
@ -332,6 +333,10 @@ extern struct interface *if_link_per_ns(struct zebra_ns *, struct interface *);
extern const char *ifindex2ifname_per_ns(struct zebra_ns *, unsigned int); extern const char *ifindex2ifname_per_ns(struct zebra_ns *, unsigned int);
extern void if_unlink_per_ns(struct interface *); extern void if_unlink_per_ns(struct interface *);
extern void if_nbr_mac_to_ipv4ll_neigh_update(struct interface *fip,
char mac[6],
struct in6_addr *address,
int add);
extern void if_nbr_ipv6ll_to_ipv4ll_neigh_update(struct interface *ifp, extern void if_nbr_ipv6ll_to_ipv4ll_neigh_update(struct interface *ifp,
struct in6_addr *address, struct in6_addr *address,
int add); int add);

View File

@ -455,6 +455,38 @@ static void rtadv_process_solicit(struct interface *ifp)
rtadv_send_packet(zns->rtadv.sock, ifp); rtadv_send_packet(zns->rtadv.sock, ifp);
} }
/*
* This function processes optional attributes off of
* end of a RA packet received. At this point in
* time we only care about this in one situation
* which is when a interface does not have a LL
* v6 address. We still need to be able to install
* the mac address for v4 to v6 resolution
*/
static void rtadv_process_optional(uint8_t *optional, unsigned int len,
struct interface *ifp,
struct sockaddr_in6 *addr)
{
char *mac;
while (len > 0) {
struct nd_opt_hdr *opt_hdr = (struct nd_opt_hdr *)optional;
switch(opt_hdr->nd_opt_type) {
case ND_OPT_SOURCE_LINKADDR:
mac = (char *)(optional+2);
if_nbr_mac_to_ipv4ll_neigh_update(ifp, mac,
&addr->sin6_addr, 1);
break;
default:
break;
}
len -= 8 * opt_hdr->nd_opt_len;
optional += 8 * opt_hdr->nd_opt_len;
}
}
static void rtadv_process_advert(uint8_t *msg, unsigned int len, static void rtadv_process_advert(uint8_t *msg, unsigned int len,
struct interface *ifp, struct interface *ifp,
struct sockaddr_in6 *addr) struct sockaddr_in6 *addr)
@ -469,13 +501,18 @@ static void rtadv_process_advert(uint8_t *msg, unsigned int len,
inet_ntop(AF_INET6, &addr->sin6_addr, addr_str, INET6_ADDRSTRLEN); inet_ntop(AF_INET6, &addr->sin6_addr, addr_str, INET6_ADDRSTRLEN);
if (len < sizeof(struct nd_router_advert)) { if (len < sizeof(struct nd_router_advert)) {
if (IS_ZEBRA_DEBUG_PACKET)
zlog_debug("%s(%u): Rx RA with invalid length %d from %s", zlog_debug("%s(%u): Rx RA with invalid length %d from %s",
ifp->name, ifp->ifindex, len, addr_str); ifp->name, ifp->ifindex, len, addr_str);
return; return;
} }
if (!IN6_IS_ADDR_LINKLOCAL(&addr->sin6_addr)) { if (!IN6_IS_ADDR_LINKLOCAL(&addr->sin6_addr)) {
zlog_debug( rtadv_process_optional(msg + sizeof(struct nd_router_advert),
"%s(%u): Rx RA with non-linklocal source address from %s", len - sizeof(struct nd_router_advert),
ifp, addr);
if (IS_ZEBRA_DEBUG_PACKET)
zlog_debug("%s(%u): Rx RA with non-linklocal source address from %s",
ifp->name, ifp->ifindex, addr_str); ifp->name, ifp->ifindex, addr_str);
return; return;
} }