From a197c47cfbfe88f8f2772f8b1f0a837356fc4265 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Fri, 12 Jun 2015 07:59:09 -0700 Subject: [PATCH] When an interface goes down, any neigbors learnt on that interface using IPv6 Router Advertisements (RAs) must be deleted. When an interface comes up and neighbors are learnt on that interface, the BGP FSM for any interface peer must be started only if a valid local address exists; the local address may come up later after IPv6 Duplicate Address Detection. --- bgpd/bgp_zebra.c | 56 ++++++++++++++++++++++++++++++++++++++++++----- zebra/interface.c | 17 ++++++++++++++ 2 files changed, 67 insertions(+), 6 deletions(-) diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 054b0916ab..aade248f7c 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -133,7 +133,7 @@ bgp_read_import_check_update(int command, struct zclient *zclient, } static void -bgp_nbr_connected_add (struct nbr_connected *ifc) +bgp_start_interface_nbrs (struct interface *ifp) { struct listnode *node, *nnode, *mnode; struct bgp *bgp; @@ -143,7 +143,9 @@ bgp_nbr_connected_add (struct nbr_connected *ifc) { for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer)) { - if (peer->conf_if && (strcmp (peer->conf_if, ifc->ifp->name) == 0)) + if (peer->conf_if && + (strcmp (peer->conf_if, ifp->name) == 0) && + peer->status != Established) { if (peer_active(peer)) BGP_EVENT_ADD (peer, BGP_Stop); @@ -154,11 +156,37 @@ bgp_nbr_connected_add (struct nbr_connected *ifc) } static void -bgp_nbr_connected_delete (struct nbr_connected *ifc) +bgp_nbr_connected_add (struct nbr_connected *ifc) +{ + struct listnode *node; + struct connected *connected; + struct interface *ifp; + struct prefix *p; + + /* Kick-off the FSM for any relevant peers only if there is a + * valid local address on the interface. + */ + ifp = ifc->ifp; + for (ALL_LIST_ELEMENTS_RO (ifp->connected, node, connected)) + { + p = connected->address; + if (p->family == AF_INET6 && + IN6_IS_ADDR_LINKLOCAL (&p->u.prefix6)) + break; + } + if (!connected) + return; + + bgp_start_interface_nbrs (ifp); +} + +static void +bgp_nbr_connected_delete (struct nbr_connected *ifc, int del) { struct listnode *node, *nnode, *mnode; struct bgp *bgp; struct peer *peer; + struct interface *ifp; for (ALL_LIST_ELEMENTS_RO (bm->bgp, mnode, bgp)) { @@ -170,6 +198,13 @@ bgp_nbr_connected_delete (struct nbr_connected *ifc) } } } + /* Free neighbor also, if we're asked to. */ + if (del) + { + ifp = ifc->ifp; + listnode_delete (ifp->nbr_connected, ifc); + nbr_connected_free (ifc); + } } /* Inteface addition message from zebra. */ @@ -251,7 +286,7 @@ bgp_interface_down (int command, struct zclient *zclient, zebra_size_t length) bgp_connected_delete (c); for (ALL_LIST_ELEMENTS (ifp->nbr_connected, node, nnode, nc)) - bgp_nbr_connected_delete (nc); + bgp_nbr_connected_delete (nc, 1); /* Fast external-failover */ { @@ -339,7 +374,16 @@ bgp_interface_address_add (int command, struct zclient *zclient, } if (if_is_operative (ifc->ifp)) - bgp_connected_add (ifc); + { + bgp_connected_add (ifc); + /* If we have learnt of any neighbors on this interface, + * check to kick off any BGP interface-based neighbors, + * but only if this is a link-local address. + */ + if (IN6_IS_ADDR_LINKLOCAL(&ifc->address->u.prefix6) && + !list_isempty(ifc->ifp->nbr_connected)) + bgp_start_interface_nbrs (ifc->ifp); + } return 0; } @@ -416,7 +460,7 @@ bgp_interface_nbr_address_delete (int command, struct zclient *zclient, } if (if_is_operative (ifc->ifp)) - bgp_nbr_connected_delete (ifc); + bgp_nbr_connected_delete (ifc, 0); nbr_connected_free (ifc); diff --git a/zebra/interface.c b/zebra/interface.c index 8af7ef7180..2f8de0b03d 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -42,6 +42,7 @@ #include "zebra/irdp.h" #include "zebra/zebra_ptm.h" #include "zebra/rt_netlink.h" +#include "zebra/zserv.h" #define ZEBRA_PTM_SUPPORT @@ -587,6 +588,19 @@ if_nbr_ipv6ll_to_ipv4ll_neigh_del_all (struct interface *ifp) } } +void +if_down_del_nbr_connected (struct interface *ifp) +{ + struct nbr_connected *nbr_connected; + struct listnode *node, *nnode; + + for (ALL_LIST_ELEMENTS (ifp->nbr_connected, node, nnode, nbr_connected)) + { + listnode_delete (ifp->nbr_connected, nbr_connected); + nbr_connected_free (nbr_connected); + } +} + /* Interface is up. */ void if_up (struct interface *ifp) @@ -659,6 +673,9 @@ if_down (struct interface *ifp) rib_update (); if_nbr_ipv6ll_to_ipv4ll_neigh_del_all (ifp); + + /* Delete all neighbor addresses learnt through IPv6 RA */ + if_down_del_nbr_connected (ifp); } void -- 2.39.5