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