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;
if (nhr.nexthop_num) {
struct peer *peer = bnc->nht_info;
/* notify bgp fsm if nbr ip goes from invalid->valid */
if (!bnc->nexthop_num)
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]);
/*
* 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 */
if (nexthop->nh_label &&
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)
&& peer->su.sa.sa_family == AF_INET6
&& IN6_IS_ADDR_LINKLOCAL(&peer->su.sin6.sin6_addr)
&& afi == AFI_IP
&& (safi == SAFI_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
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
.. clicmd:: [no] bgp fast-external-failover

View File

@ -51,6 +51,8 @@
#include "zebra/zebra_vxlan.h"
#include "zebra/zebra_errors.h"
DEFINE_MTYPE_STATIC(ZEBRA, ZINFO, "Zebra Interface Information")
#define ZEBRA_PTM_SUPPORT
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;
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->shutdown = IF_ZEBRA_SHUTDOWN_OFF;
@ -136,6 +138,8 @@ static int if_zebra_new_hook(struct interface *ifp)
}
#endif /* HAVE_RTADV */
memset(&zebra_if->neigh_mac[0], 0, 6);
/* Initialize installed address chains tree. */
zebra_if->ipv4_subnets =
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);
XFREE(MTYPE_TMP, zebra_if);
XFREE(MTYPE_ZINFO, zebra_if);
}
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];
}
void if_nbr_ipv6ll_to_ipv4ll_neigh_update(struct interface *ifp,
struct in6_addr *address, int add)
static bool mac_is_same(char *mac1, char *mac2)
{
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_if *zif = ifp->info;
char buf[16] = "169.254.0.1";
struct in_addr ipv4_ll;
char mac[6];
ns_id_t ns_id;
inet_pton(AF_INET, buf, &ipv4_ll);
ipv6_ll_address_to_mac(address, (uint8_t *)mac);
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
*/
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 */
kernel_neigh_update(add, ifp->ifindex, ipv4_ll.s_addr, mac, 6, ns_id);
/* Add arp record */
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
@ -840,6 +863,16 @@ void if_nbr_ipv6ll_to_ipv4ll_neigh_update(struct interface *ifp,
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)
{
if (listhead(ifp->nbr_connected)) {

View File

@ -279,6 +279,7 @@ struct zebra_if {
* for bgp unnumbered?
*/
bool v6_2_v4_ll_neigh_entry;
char neigh_mac[6];
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 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,
struct in6_addr *address,
int add);

View File

@ -455,6 +455,38 @@ static void rtadv_process_solicit(struct interface *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,
struct interface *ifp,
struct sockaddr_in6 *addr)
@ -469,14 +501,19 @@ static void rtadv_process_advert(uint8_t *msg, unsigned int len,
inet_ntop(AF_INET6, &addr->sin6_addr, addr_str, INET6_ADDRSTRLEN);
if (len < sizeof(struct nd_router_advert)) {
zlog_debug("%s(%u): Rx RA with invalid length %d from %s",
ifp->name, ifp->ifindex, len, addr_str);
if (IS_ZEBRA_DEBUG_PACKET)
zlog_debug("%s(%u): Rx RA with invalid length %d from %s",
ifp->name, ifp->ifindex, len, addr_str);
return;
}
if (!IN6_IS_ADDR_LINKLOCAL(&addr->sin6_addr)) {
zlog_debug(
"%s(%u): Rx RA with non-linklocal source address from %s",
ifp->name, ifp->ifindex, addr_str);
rtadv_process_optional(msg + sizeof(struct nd_router_advert),
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);
return;
}