]> git.puffer.fish Git - mirror/frr.git/commitdiff
bgpd: turn off RAs when numbered peers are deleted 6303/head
authorDon Slice <dslice@cumulusnetworks.com>
Tue, 21 Apr 2020 19:01:35 +0000 (19:01 +0000)
committerDon Slice <dslice@cumulusnetworks.com>
Mon, 27 Apr 2020 17:49:41 +0000 (17:49 +0000)
Problem reported that in many circumstances, RAs created in the
process of bringing up numbered IPv6 peers with extended-nexthop
capability enabled (for ipv4 over ipv6) were not stopped on the
interface when those peers were deleted.  Found several circumstances
where this occurred and fix them in this patch.

Ticket: CM-26875
Signed-off-by: Don Slice <dslice@cumulusnetworks.com>
bgpd/bgp_nht.c
bgpd/bgp_nht.h
bgpd/bgp_vty.c
bgpd/bgp_zebra.c
bgpd/bgpd.c

index 1af9be46f1af29842e5f3da2680e5aae27a5dc89..cc208a8190efe0b5fc7ce541872bbe5d79c14a0d 100644 (file)
@@ -873,7 +873,7 @@ void bgp_nht_register_nexthops(struct bgp *bgp)
        }
 }
 
-void bgp_nht_register_enhe_capability_interfaces(struct peer *peer)
+void bgp_nht_reg_enhe_cap_intfs(struct peer *peer)
 {
        struct bgp *bgp;
        struct bgp_node *rn;
@@ -891,9 +891,8 @@ void bgp_nht_register_enhe_capability_interfaces(struct peer *peer)
                return;
 
        if (!sockunion2hostprefix(&peer->su, &p)) {
-               if (BGP_DEBUG(nht, NHT))
-                       zlog_debug("%s: Unable to convert prefix to sockunion",
-                                  __func__);
+               zlog_warn("%s: Unable to convert sockunion to prefix for %s",
+                         __func__, peer->host);
                return;
        }
 
@@ -922,3 +921,48 @@ void bgp_nht_register_enhe_capability_interfaces(struct peer *peer)
                                                BGP_UNNUM_DEFAULT_RA_INTERVAL);
        }
 }
+
+void bgp_nht_dereg_enhe_cap_intfs(struct peer *peer)
+{
+       struct bgp *bgp;
+       struct bgp_node *rn;
+       struct bgp_nexthop_cache *bnc;
+       struct nexthop *nhop;
+       struct interface *ifp;
+       struct prefix p;
+
+       if (peer->ifp)
+               return;
+
+       bgp = peer->bgp;
+
+       if (!bgp->nexthop_cache_table[AFI_IP6])
+               return;
+
+       if (!sockunion2hostprefix(&peer->su, &p)) {
+               zlog_warn("%s: Unable to convert sockunion to prefix for %s",
+                         __func__, peer->host);
+               return;
+       }
+
+       if (p.family != AF_INET6)
+               return;
+
+       rn = bgp_node_lookup(bgp->nexthop_cache_table[AFI_IP6], &p);
+       if (!rn)
+               return;
+
+       bnc = bgp_node_get_bgp_nexthop_info(rn);
+       if (!bnc)
+               return;
+
+       if (peer != bnc->nht_info)
+               return;
+
+       for (nhop = bnc->nexthop; nhop; nhop = nhop->next) {
+               ifp = if_lookup_by_index(nhop->ifindex, nhop->vrf_id);
+
+               zclient_send_interface_radv_req(zclient, nhop->vrf_id, ifp, 0,
+                                               0);
+       }
+}
index e39d55567aa1c613531f2b9d614a95e65f1a4a1d..4e015e4aaeb6aeee386b6aac3347258d191eb0eb 100644 (file)
@@ -87,6 +87,7 @@ extern void bgp_nht_register_nexthops(struct bgp *bgp);
  * this code can walk the registered nexthops and
  * register the important ones with zebra for RA.
  */
-extern void bgp_nht_register_enhe_capability_interfaces(struct peer *peer);
+extern void bgp_nht_reg_enhe_cap_intfs(struct peer *peer);
+extern void bgp_nht_dereg_enhe_cap_intfs(struct peer *peer);
 
 #endif /* _BGP_NHT_H */
index b7a7d2c3828eeb4fa47fca7ec03098e55b67a71d..2989e183ad5416ead1fddc0256496bfaa57b6b85 100644 (file)
@@ -3818,6 +3818,10 @@ DEFUN (no_neighbor,
                        }
 
                        other = peer->doppelganger;
+
+                       if (CHECK_FLAG(peer->flags, PEER_FLAG_CAPABILITY_ENHE))
+                               bgp_zebra_terminate_radv(peer->bgp, peer);
+
                        peer_notify_unconfig(peer);
                        peer_delete(peer);
                        if (other && other->status != Deleted) {
@@ -4238,6 +4242,9 @@ DEFUN (no_neighbor_set_peer_group,
                return CMD_WARNING_CONFIG_FAILED;
        }
 
+       if (CHECK_FLAG(peer->flags, PEER_FLAG_CAPABILITY_ENHE))
+               bgp_zebra_terminate_radv(peer->bgp, peer);
+
        peer_notify_unconfig(peer);
        ret = peer_delete(peer);
 
index 4f54bc81fb990ed95b74bba824f4e895214984ca..cca3f4aaa3cdd7c39198cb005c2929f412cac958 100644 (file)
@@ -1939,8 +1939,14 @@ void bgp_zebra_initiate_radv(struct bgp *bgp, struct peer *peer)
                zlog_debug("%u: Initiating RA for peer %s", bgp->vrf_id,
                           peer->host);
 
-       zclient_send_interface_radv_req(zclient, bgp->vrf_id, peer->ifp, 1,
-                                       ra_interval);
+       /*
+        * If unnumbered peer (peer->ifp) call thru zapi to start RAs.
+        * If we don't have an ifp pointer, call function to find the
+        * ifps for a numbered enhe peer to turn RAs on.
+        */
+       peer->ifp ? zclient_send_interface_radv_req(zclient, bgp->vrf_id,
+                                                   peer->ifp, 1, ra_interval)
+                 : bgp_nht_reg_enhe_cap_intfs(peer);
 }
 
 void bgp_zebra_terminate_radv(struct bgp *bgp, struct peer *peer)
@@ -1953,7 +1959,14 @@ void bgp_zebra_terminate_radv(struct bgp *bgp, struct peer *peer)
                zlog_debug("%u: Terminating RA for peer %s", bgp->vrf_id,
                           peer->host);
 
-       zclient_send_interface_radv_req(zclient, bgp->vrf_id, peer->ifp, 0, 0);
+       /*
+        * If unnumbered peer (peer->ifp) call thru zapi to stop RAs.
+        * If we don't have an ifp pointer, call function to find the
+        * ifps for a numbered enhe peer to turn RAs off.
+        */
+       peer->ifp ? zclient_send_interface_radv_req(zclient, bgp->vrf_id,
+                                                   peer->ifp, 0, 0)
+                 : bgp_nht_dereg_enhe_cap_intfs(peer);
 }
 
 int bgp_zebra_advertise_subnet(struct bgp *bgp, int advertise, vni_t vni)
index 5d28b138d68ae8563fe21e93a79716e8e5cd9468..cf6335d3734965de8002760f4f9a67d0ad4714ae 100644 (file)
@@ -2490,6 +2490,11 @@ static void peer_group2peer_config_copy(struct peer_group *group,
                                                   : BGP_DEFAULT_EBGP_ROUTEADV;
        }
 
+       /* capability extended-nexthop apply */
+       if (!CHECK_FLAG(peer->flags_override, PEER_FLAG_CAPABILITY_ENHE))
+               if (CHECK_FLAG(conf->flags, PEER_FLAG_CAPABILITY_ENHE))
+                       SET_FLAG(peer->flags, PEER_FLAG_CAPABILITY_ENHE);
+
        /* password apply */
        if (!CHECK_FLAG(peer->flags_override, PEER_FLAG_PASSWORD))
                PEER_STR_ATTR_INHERIT(peer, group, password,
@@ -2577,6 +2582,10 @@ int peer_group_delete(struct peer_group *group)
 
        for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
                other = peer->doppelganger;
+
+               if (CHECK_FLAG(peer->flags, PEER_FLAG_CAPABILITY_ENHE))
+                       bgp_zebra_terminate_radv(bgp, peer);
+
                peer_delete(peer);
                if (other && other->status != Deleted) {
                        other->group = NULL;
@@ -2621,6 +2630,9 @@ int peer_group_remote_as_delete(struct peer_group *group)
        for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
                other = peer->doppelganger;
 
+               if (CHECK_FLAG(peer->flags, PEER_FLAG_CAPABILITY_ENHE))
+                       bgp_zebra_terminate_radv(peer->bgp, peer);
+
                peer_delete(peer);
 
                if (other && other->status != Deleted) {
@@ -4065,8 +4077,22 @@ static int peer_flag_modify(struct peer *peer, uint32_t flag, int set)
                /* Update flag override state accordingly. */
                COND_FLAG(peer->flags_override, flag, set != invert);
 
-               if (set && flag == PEER_FLAG_CAPABILITY_ENHE)
-                       bgp_nht_register_enhe_capability_interfaces(peer);
+               /*
+                * For the extended next-hop encoding flag we need to turn RAs
+                * on if flag is being set, but only turn RAs off if the flag
+                * is being unset on this peer and if this peer is a member of a
+                * peer-group, the peer-group also doesn't have the flag set.
+                */
+               if (flag == PEER_FLAG_CAPABILITY_ENHE) {
+                       if (set) {
+                               bgp_zebra_initiate_radv(peer->bgp, peer);
+                       } else if (peer_group_active(peer)) {
+                               if (!CHECK_FLAG(peer->group->conf->flags, flag))
+                                       bgp_zebra_terminate_radv(peer->bgp,
+                                                                peer);
+                       } else
+                               bgp_zebra_terminate_radv(peer->bgp, peer);
+               }
 
                /* Execute flag action on peer. */
                if (action.type == peer_change_reset)
@@ -4099,8 +4125,9 @@ static int peer_flag_modify(struct peer *peer, uint32_t flag, int set)
                /* Update flag on peer-group member. */
                COND_FLAG(member->flags, flag, set != member_invert);
 
-               if (set && flag == PEER_FLAG_CAPABILITY_ENHE)
-                       bgp_nht_register_enhe_capability_interfaces(member);
+               if (flag == PEER_FLAG_CAPABILITY_ENHE)
+                       set ? bgp_zebra_initiate_radv(member->bgp, member)
+                           : bgp_zebra_terminate_radv(member->bgp, member);
 
                /* Execute flag action on peer-group member. */
                if (action.type == peer_change_reset)