From 6137a77dce5edd49283acab572d7763644273830 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Thu, 6 Sep 2018 09:16:30 -0400 Subject: [PATCH 1/5] bgpd: Extend RFC 5549 metaphor a bit more Currently we only support RFC 5549 in bgp via using the `neighbor swp1 interface remote-as ...` command. This causes the extended capability data to be traded as part of the open message. Additionally at that point in time we notify zebra to turn on the RA code for that interface so that the zebra trick of turning the v6 nexthop into a 169.254.0.1 nexthop and adding a neighbor entry works. This code change does 2 things: 1) Modify bgp to pass the extended capability if we are attempting to establish a v4/unicast session over a v6 peer. In the past we limited this to just the LL based peer. 2) Modify the nexthop tracking code to notice when it receives nexthop data about the global v6 peer to turn on RA code on those interfaces we will be using. This will allow the v4 route with a v6 nexthop received in zebra to auto translate this correctly. Signed-off-by: Donald Sharp --- bgpd/bgp_nht.c | 18 ++++++++++++++++++ bgpd/bgp_open.c | 1 - 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/bgpd/bgp_nht.c b/bgpd/bgp_nht.c index 3d2a4ee0dd..3ef7604b17 100644 --- a/bgpd/bgp_nht.c +++ b/bgpd/bgp_nht.c @@ -401,6 +401,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); @@ -416,6 +418,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) { diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c index 62b412af0c..cf5901df5a 100644 --- a/bgpd/bgp_open.c +++ b/bgpd/bgp_open.c @@ -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)) { From 19f2b5e8751ef6aca63896ac73900b5edc31fc62 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Thu, 13 Sep 2018 12:49:35 -0400 Subject: [PATCH 2/5] doc: Update documentation with the extended-nexthop bgp command Signed-off-by: Donald Sharp --- doc/user/bgp.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst index 14f2c8dc9a..d9d496f7fc 100644 --- a/doc/user/bgp.rst +++ b/doc/user/bgp.rst @@ -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 From ee98d1f11c940d5dc62509bc2cb9ca0f6ae4117d Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 19 Sep 2018 11:02:42 -0400 Subject: [PATCH 3/5] zebra: Abstract mac neigh installation into it's own function Abstract the mac neigh installation for 169.254.0.1 into it's own function that we can pass the mac address into. This will allow a future commit to use this functionality when we have the appropriate mac address from reading optional attributes of a RA packet. Signed-off-by: Donald Sharp --- zebra/interface.c | 45 ++++++++++++++++++++++++++++++++++++++------- zebra/interface.h | 5 +++++ 2 files changed, 43 insertions(+), 7 deletions(-) diff --git a/zebra/interface.c b/zebra/interface.c index ca90c18cf2..131b8598b0 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -136,6 +136,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); @@ -802,19 +804,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 +838,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 +861,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)) { diff --git a/zebra/interface.h b/zebra/interface.h index 02a05e6146..b632d25c2a 100644 --- a/zebra/interface.h +++ b/zebra/interface.h @@ -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); From 71974bf5612447abbb14971752217e2cf7ee7934 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 19 Sep 2018 11:09:18 -0400 Subject: [PATCH 4/5] zebra: Trust the mac address received in some situations When we receive a v6 RA packet with an optional ND_OPT_SOURCE_LINKADDR take that data and construct the v4 to v6 neighbor entry for that interface to allow v4 w/ v6 nexthops to work with only global v6 addresses on an interface. Signed-off-by: Donald Sharp --- zebra/rtadv.c | 47 ++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/zebra/rtadv.c b/zebra/rtadv.c index f9bd5ad1bb..3bb75f3446 100644 --- a/zebra/rtadv.c +++ b/zebra/rtadv.c @@ -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; } From 8e59a4027f2302b79fe2a6f860000267e09f7030 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 19 Sep 2018 11:35:43 -0400 Subject: [PATCH 5/5] zebra: Use actual memory type for zebra info pointer Use MTYPE_ZINFO for the `struct zebra_if` data structure instead of using MTYPE_TMP. Signed-off-by: Donald Sharp --- zebra/interface.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/zebra/interface.c b/zebra/interface.c index 131b8598b0..95a8bd870b 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -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; @@ -177,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;