diff options
| -rw-r--r-- | bgpd/bgp_route.c | 2 | ||||
| -rw-r--r-- | bgpd/bgp_updgrp.c | 11 | ||||
| -rw-r--r-- | bgpd/bgp_vty.c | 22 | ||||
| -rw-r--r-- | bgpd/bgpd.c | 1 | ||||
| -rw-r--r-- | bgpd/bgpd.h | 4 | ||||
| -rw-r--r-- | lib/sigevent.c | 12 | ||||
| -rw-r--r-- | lib/vrf.c | 49 | ||||
| -rw-r--r-- | lib/vrf.h | 6 | ||||
| -rw-r--r-- | tests/topotests/bgp_sender_as_path_loop_detection/test_bgp_sender-as-path-loop-detection.py | 77 | ||||
| -rw-r--r-- | zebra/main.c | 6 |
10 files changed, 141 insertions, 49 deletions
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 1b9bd7670d..d726edcc9f 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -2242,7 +2242,7 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi, } /* AS path loop check. */ - if (peer->as_path_loop_detection && + if (CHECK_FLAG(peer->flags, PEER_FLAG_AS_LOOP_DETECTION) && aspath_loop_check(piattr->aspath, peer->as)) { if (bgp_debug_update(NULL, p, subgrp->update_group, 0)) zlog_debug( diff --git a/bgpd/bgp_updgrp.c b/bgpd/bgp_updgrp.c index d008ef4e79..f36a7b6d0b 100644 --- a/bgpd/bgp_updgrp.c +++ b/bgpd/bgp_updgrp.c @@ -151,7 +151,6 @@ static void conf_copy(struct peer *dst, struct peer *src, afi_t afi, dst->change_local_as = src->change_local_as; dst->shared_network = src->shared_network; dst->local_role = src->local_role; - dst->as_path_loop_detection = src->as_path_loop_detection; if (src->soo[afi][safi]) { ecommunity_free(&dst->soo[afi][safi]); @@ -360,9 +359,12 @@ static unsigned int updgrp_hash_key_make(const void *p) key = jhash_1word(peer->max_packet_size, key); key = jhash_1word(peer->pmax_out[afi][safi], key); - if (peer->as_path_loop_detection) - key = jhash_2words(peer->as, peer->as_path_loop_detection, key); + if (CHECK_FLAG(peer->flags, PEER_FLAG_AS_LOOP_DETECTION)) + key = jhash_2words(peer->as, + CHECK_FLAG(peer->flags, + PEER_FLAG_AS_LOOP_DETECTION), + key); if (peer->group) key = jhash_1word(jhash(peer->group->name, strlen(peer->group->name), SEED1), @@ -464,7 +466,8 @@ static unsigned int updgrp_hash_key_make(const void *p) CHECK_FLAG(peer->af_cap[afi][safi], PEER_UPDGRP_AF_CAP_FLAGS), peer->v_routeadv, peer->change_local_as, - peer->as_path_loop_detection); + !!CHECK_FLAG(peer->flags, + PEER_FLAG_AS_LOOP_DETECTION)); zlog_debug("%pBP Update Group Hash: addpath paths-limit: (send %u, receive %u)", peer, peer->addpath_paths_limit[afi][safi].send, peer->addpath_paths_limit[afi][safi].receive); diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 2920405780..b1f6e2d828 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -9198,15 +9198,7 @@ DEFPY( NEIGHBOR_ADDR_STR2 "Detect AS loops before sending to neighbor\n") { - struct peer *peer; - - peer = peer_and_group_lookup_vty(vty, neighbor); - if (!peer) - return CMD_WARNING_CONFIG_FAILED; - - peer->as_path_loop_detection = true; - - return CMD_SUCCESS; + return peer_flag_set_vty(vty, neighbor, PEER_FLAG_AS_LOOP_DETECTION); } DEFPY (neighbor_addpath_paths_limit, @@ -9275,15 +9267,7 @@ DEFPY( NEIGHBOR_ADDR_STR2 "Detect AS loops before sending to neighbor\n") { - struct peer *peer; - - peer = peer_and_group_lookup_vty(vty, neighbor); - if (!peer) - return CMD_WARNING_CONFIG_FAILED; - - peer->as_path_loop_detection = false; - - return CMD_SUCCESS; + return peer_flag_unset_vty(vty, neighbor, PEER_FLAG_AS_LOOP_DETECTION); } DEFPY(neighbor_path_attribute_discard, @@ -18460,7 +18444,7 @@ static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp, vty_out(vty, " neighbor %s strict-capability-match\n", addr); /* Sender side AS path loop detection. */ - if (peer->as_path_loop_detection) + if (peergroup_flag_check(peer, PEER_FLAG_AS_LOOP_DETECTION)) vty_out(vty, " neighbor %s sender-as-path-loop-detection\n", addr); diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index be816c3361..fcff957d65 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -4587,6 +4587,7 @@ static const struct peer_flag_action peer_flag_action_list[] = { {PEER_FLAG_GRACEFUL_SHUTDOWN, 0, peer_change_none}, {PEER_FLAG_CAPABILITY_SOFT_VERSION, 0, peer_change_none}, {PEER_FLAG_CAPABILITY_FQDN, 0, peer_change_none}, + {PEER_FLAG_AS_LOOP_DETECTION, 0, peer_change_none}, {0, 0, 0}}; static const struct peer_flag_action peer_af_flag_action_list[] = { diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 94bb107253..1c5f90c59b 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -1470,6 +1470,7 @@ struct peer { #define PEER_FLAG_GRACEFUL_SHUTDOWN (1ULL << 35) #define PEER_FLAG_CAPABILITY_SOFT_VERSION (1ULL << 36) #define PEER_FLAG_CAPABILITY_FQDN (1ULL << 37) /* fqdn capability */ +#define PEER_FLAG_AS_LOOP_DETECTION (1ULL << 38) /* as path loop detection */ /* *GR-Disabled mode means unset PEER_FLAG_GRACEFUL_RESTART @@ -1823,9 +1824,6 @@ struct peer { char *hostname; char *domainname; - /* Sender side AS path loop detection. */ - bool as_path_loop_detection; - /* Extended Message Support */ uint16_t max_packet_size; diff --git a/lib/sigevent.c b/lib/sigevent.c index 06f80db4cc..3e69f280da 100644 --- a/lib/sigevent.c +++ b/lib/sigevent.c @@ -240,7 +240,17 @@ core_handler(int signo, siginfo_t *siginfo, void *context) /* dump memory stats on core */ log_memstats(stderr, "core_handler"); - zlog_tls_buffer_fini(); + /* + * This is a buffer flush because FRR is going down + * hard. This is especially important if the crash + * was caused by a memory operation and if we call + * zlog_tls_buffer_fini() then it has memory + * operations as well. This will cause the + * core dump to not happen. BAD MOJO + * So this is intentional, let's try to flush + * what we can and let the crash happen. + */ + zlog_tls_buffer_flush(); /* give the kernel a chance to generate a coredump */ sigaddset(&sigset, signo); @@ -326,6 +326,33 @@ void vrf_disable(struct vrf *vrf) (*vrf_master.vrf_disable_hook)(vrf); } +void vrf_iterate(vrf_iter_func fnc) +{ + struct vrf *vrf, *tmp; + + if (debug_vrf) + zlog_debug("%s: vrf subsystem iteration", __func__); + + RB_FOREACH_SAFE (vrf, vrf_id_head, &vrfs_by_id, tmp) { + if (vrf->vrf_id == VRF_DEFAULT) + continue; + + fnc(vrf); + } + + RB_FOREACH_SAFE (vrf, vrf_name_head, &vrfs_by_name, tmp) { + if (vrf->vrf_id == VRF_DEFAULT) + continue; + + fnc(vrf); + } + + /* Finally process default VRF */ + vrf = vrf_lookup_by_id(VRF_DEFAULT); + if (vrf) + fnc(vrf); +} + const char *vrf_id_to_name(vrf_id_t vrf_id) { struct vrf *vrf; @@ -542,32 +569,12 @@ static void vrf_terminate_single(struct vrf *vrf) vrf_delete(vrf); } -/* Terminate VRF module. */ void vrf_terminate(void) { - struct vrf *vrf, *tmp; - if (debug_vrf) zlog_debug("%s: Shutting down vrf subsystem", __func__); - RB_FOREACH_SAFE (vrf, vrf_id_head, &vrfs_by_id, tmp) { - if (vrf->vrf_id == VRF_DEFAULT) - continue; - - vrf_terminate_single(vrf); - } - - RB_FOREACH_SAFE (vrf, vrf_name_head, &vrfs_by_name, tmp) { - if (vrf->vrf_id == VRF_DEFAULT) - continue; - - vrf_terminate_single(vrf); - } - - /* Finally terminate default VRF */ - vrf = vrf_lookup_by_id(VRF_DEFAULT); - if (vrf) - vrf_terminate_single(vrf); + vrf_iterate(vrf_terminate_single); } int vrf_socket(int domain, int type, int protocol, vrf_id_t vrf_id, @@ -202,6 +202,12 @@ extern void vrf_init(int (*create)(struct vrf *vrf), int (*destroy)(struct vrf *vrf)); /* + * Iterate over custom VRFs and round up by processing the default VRF. + */ +typedef void (*vrf_iter_func)(struct vrf *vrf); +extern void vrf_iterate(vrf_iter_func fnc); + +/* * Call vrf_terminate when the protocol is being shutdown */ extern void vrf_terminate(void); diff --git a/tests/topotests/bgp_sender_as_path_loop_detection/test_bgp_sender-as-path-loop-detection.py b/tests/topotests/bgp_sender_as_path_loop_detection/test_bgp_sender-as-path-loop-detection.py index 3886bc1772..db6dbc61d2 100644 --- a/tests/topotests/bgp_sender_as_path_loop_detection/test_bgp_sender-as-path-loop-detection.py +++ b/tests/topotests/bgp_sender_as_path_loop_detection/test_bgp_sender-as-path-loop-detection.py @@ -129,6 +129,83 @@ def test_bgp_sender_as_path_loop_detection(): assert result is None, "Routes should not be sent to r1 from r2" +def test_remove_loop_detection_on_one_peer(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r2 = tgen.gears["r2"] + + def _bgp_reset_route_to_r1(): + output = json.loads( + r2.vtysh_cmd("show ip bgp neighbor 192.168.255.2 advertised-routes json") + ) + expected = {"totalPrefixCounter": 3} + return topotest.json_cmp(output, expected) + + r2.vtysh_cmd( + """ + configure terminal + router bgp 65002 + no neighbor 192.168.255.2 sender-as-path-loop-detection + """ + ) + + r2.vtysh_cmd( + """ + clear bgp * + """ + ) + test_func = functools.partial(_bgp_reset_route_to_r1) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + assert result is None, "Failed bgp to reset route" + + +def test_loop_detection_on_peer_group(): + tgen = get_topogen() + + r2 = tgen.gears["r2"] + + def _bgp_suppress_route_to_r1(): + output = json.loads( + r2.vtysh_cmd("show ip bgp neighbor 192.168.255.2 advertised-routes json") + ) + expected = {"totalPrefixCounter": 0} + return topotest.json_cmp(output, expected) + + def _bgp_suppress_route_to_r3(): + output = json.loads( + r2.vtysh_cmd("show ip bgp neighbor 192.168.254.2 advertised-routes json") + ) + expected = {"totalPrefixCounter": 2} + return topotest.json_cmp(output, expected) + + r2.vtysh_cmd( + """ + configure terminal + router bgp 65002 + neighbor loop_group peer-group + neighbor 192.168.255.2 peer-group loop_group + neighbor loop_group sender-as-path-loop-detection + """ + ) + + r2.vtysh_cmd( + """ + clear bgp * + """ + ) + + test_func = functools.partial(_bgp_suppress_route_to_r3) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + assert result is None, "Route 172.16.255.253/32 should not be sent to r3 from r2" + + test_func = functools.partial(_bgp_suppress_route_to_r1) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + assert result is None, "Routes should not be sent to r1 from r2" + + if __name__ == "__main__": args = ["-s"] + sys.argv[1:] sys.exit(pytest.main(args)) diff --git a/zebra/main.c b/zebra/main.c index 27e98ed999..d83f1d0491 100644 --- a/zebra/main.c +++ b/zebra/main.c @@ -205,6 +205,12 @@ static void sigint(void) list_delete(&zrouter.client_list); list_delete(&zrouter.stale_client_list); + /* + * Besides other clean-ups zebra's vrf_disable() also enqueues installed + * routes for removal from the kernel, unless ZEBRA_VRF_RETAIN is set. + */ + vrf_iterate(vrf_disable); + /* Indicate that all new dplane work has been enqueued. When that * work is complete, the dataplane will enqueue an event * with the 'finalize' function. |
