frr/zebra/zebra_router.c
Keelan10 d8e664821e zebra: Set Free Functions for Traffic Control Hash Tables
Configure hash table cleanup with specific free functions for `zrouter.filter_hash`, `zrouter.qdisc_hash`, and `zrouter.class_hash`.
This ensures proper memory cleanup, addressing memory leaks.

The ASan leak log for reference:

```
***********************************************************************************
Address Sanitizer Error detected in tc_basic.test_tc_basic/r1.asan.zebra.15495

=================================================================
==15495==ERROR: LeakSanitizer: detected memory leaks

Direct leak of 176 byte(s) in 1 object(s) allocated from:
    #0 0x7fd5660ffd28 in __interceptor_calloc (/usr/lib/x86_64-linux-gnu/libasan.so.4+0xded28)
    #1 0x7fd565afe238 in qcalloc lib/memory.c:105
    #2 0x5564521c6c9e in tc_filter_alloc_intern zebra/zebra_tc.c:389
    #3 0x7fd565ac49e8 in hash_get lib/hash.c:147
    #4 0x5564521c7c74 in zebra_tc_filter_add zebra/zebra_tc.c:409
    #5 0x55645210755a in zread_tc_filter zebra/zapi_msg.c:3428
    #6 0x5564521127c1 in zserv_handle_commands zebra/zapi_msg.c:4004
    #7 0x5564522208b2 in zserv_process_messages zebra/zserv.c:520
    #8 0x7fd565b9e034 in event_call lib/event.c:1974
    #9 0x7fd565ae142b in frr_run lib/libfrr.c:1214
    #10 0x5564520c14b1 in main zebra/main.c:492
    #11 0x7fd564ec2c86 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21c86)

Direct leak of 40 byte(s) in 1 object(s) allocated from:
    #0 0x7fd5660ffd28 in __interceptor_calloc (/usr/lib/x86_64-linux-gnu/libasan.so.4+0xded28)
    #1 0x7fd565afe238 in qcalloc lib/memory.c:105
    #2 0x5564521c6c6e in tc_class_alloc_intern zebra/zebra_tc.c:239
    #3 0x7fd565ac49e8 in hash_get lib/hash.c:147
    #4 0x5564521c784f in zebra_tc_class_add zebra/zebra_tc.c:293
    #5 0x556452107ce5 in zread_tc_class zebra/zapi_msg.c:3315
    #6 0x5564521127c1 in zserv_handle_commands zebra/zapi_msg.c:4004
    #7 0x5564522208b2 in zserv_process_messages zebra/zserv.c:520
    #8 0x7fd565b9e034 in event_call lib/event.c:1974
    #9 0x7fd565ae142b in frr_run lib/libfrr.c:1214
    #10 0x5564520c14b1 in main zebra/main.c:492
    #11 0x7fd564ec2c86 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21c86)

Direct leak of 12 byte(s) in 1 object(s) allocated from:
    #0 0x7fd5660ffd28 in __interceptor_calloc (/usr/lib/x86_64-linux-gnu/libasan.so.4+0xded28)
    #1 0x7fd565afe238 in qcalloc lib/memory.c:105
    #2 0x5564521c6c3e in tc_qdisc_alloc_intern zebra/zebra_tc.c:128
    #3 0x7fd565ac49e8 in hash_get lib/hash.c:147
    #4 0x5564521c753b in zebra_tc_qdisc_install zebra/zebra_tc.c:184
    #5 0x556452108203 in zread_tc_qdisc zebra/zapi_msg.c:3286
    #6 0x5564521127c1 in zserv_handle_commands zebra/zapi_msg.c:4004
    #7 0x5564522208b2 in zserv_process_messages zebra/zserv.c:520
    #8 0x7fd565b9e034 in event_call lib/event.c:1974
    #9 0x7fd565ae142b in frr_run lib/libfrr.c:1214
    #10 0x5564520c14b1 in main zebra/main.c:492
    #11 0x7fd564ec2c86 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21c86)

SUMMARY: AddressSanitizer: 228 byte(s) leaked in 3 allocation(s).
***********************************************************************************
```

Signed-off-by: Keelan Cannoo <keelan.cannoo@icloud.com>
2023-11-29 16:33:54 +04:00

335 lines
8.7 KiB
C

// SPDX-License-Identifier: GPL-2.0-or-later
/* Zebra Router Code.
* Copyright (C) 2018 Cumulus Networks, Inc.
* Donald Sharp
*/
#include "zebra.h"
#include <pthread.h>
#include "lib/frratomic.h"
#include "zebra_router.h"
#include "zebra_pbr.h"
#include "zebra_vxlan.h"
#include "zebra_mlag.h"
#include "zebra_nhg.h"
#include "zebra_neigh.h"
#include "zebra/zebra_tc.h"
#include "debug.h"
#include "zebra_script.h"
DEFINE_MTYPE_STATIC(ZEBRA, RIB_TABLE_INFO, "RIB table info");
DEFINE_MTYPE_STATIC(ZEBRA, ZEBRA_RT_TABLE, "Zebra VRF table");
struct zebra_router zrouter = {
.multipath_num = MULTIPATH_NUM,
.ipv4_multicast_mode = MCAST_NO_CONFIG,
};
static inline int
zebra_router_table_entry_compare(const struct zebra_router_table *e1,
const struct zebra_router_table *e2);
RB_GENERATE(zebra_router_table_head, zebra_router_table,
zebra_router_table_entry, zebra_router_table_entry_compare);
static inline int
zebra_router_table_entry_compare(const struct zebra_router_table *e1,
const struct zebra_router_table *e2)
{
if (e1->tableid < e2->tableid)
return -1;
if (e1->tableid > e2->tableid)
return 1;
if (e1->ns_id < e2->ns_id)
return -1;
if (e1->ns_id > e2->ns_id)
return 1;
if (e1->afi < e2->afi)
return -1;
if (e1->afi > e2->afi)
return 1;
return (e1->safi - e2->safi);
}
struct zebra_router_table *zebra_router_find_zrt(struct zebra_vrf *zvrf,
uint32_t tableid, afi_t afi,
safi_t safi)
{
struct zebra_router_table finder;
struct zebra_router_table *zrt;
memset(&finder, 0, sizeof(finder));
finder.afi = afi;
finder.safi = safi;
finder.tableid = tableid;
finder.ns_id = zvrf->zns->ns_id;
zrt = RB_FIND(zebra_router_table_head, &zrouter.tables, &finder);
return zrt;
}
struct route_table *zebra_router_find_table(struct zebra_vrf *zvrf,
uint32_t tableid, afi_t afi,
safi_t safi)
{
struct zebra_router_table finder;
struct zebra_router_table *zrt;
memset(&finder, 0, sizeof(finder));
finder.afi = afi;
finder.safi = safi;
finder.tableid = tableid;
finder.ns_id = zvrf->zns->ns_id;
zrt = RB_FIND(zebra_router_table_head, &zrouter.tables, &finder);
if (zrt)
return zrt->table;
else
return NULL;
}
struct route_table *zebra_router_get_table(struct zebra_vrf *zvrf,
uint32_t tableid, afi_t afi,
safi_t safi)
{
struct zebra_router_table finder;
struct zebra_router_table *zrt;
struct rib_table_info *info;
memset(&finder, 0, sizeof(finder));
finder.afi = afi;
finder.safi = safi;
finder.tableid = tableid;
finder.ns_id = zvrf->zns->ns_id;
zrt = RB_FIND(zebra_router_table_head, &zrouter.tables, &finder);
if (zrt)
return zrt->table;
zrt = XCALLOC(MTYPE_ZEBRA_RT_TABLE, sizeof(*zrt));
zrt->tableid = tableid;
zrt->afi = afi;
zrt->safi = safi;
zrt->ns_id = zvrf->zns->ns_id;
zrt->table =
(afi == AFI_IP6) ? srcdest_table_init() : route_table_init();
info = XCALLOC(MTYPE_RIB_TABLE_INFO, sizeof(*info));
info->zvrf = zvrf;
info->afi = afi;
info->safi = safi;
info->table_id = tableid;
route_table_set_info(zrt->table, info);
zrt->table->cleanup = zebra_rtable_node_cleanup;
RB_INSERT(zebra_router_table_head, &zrouter.tables, zrt);
return zrt->table;
}
void zebra_router_show_table_summary(struct vty *vty)
{
struct zebra_router_table *zrt;
vty_out(vty,
"VRF NS ID VRF ID AFI SAFI Table Count\n");
vty_out(vty,
"---------------------------------------------------------------------------\n");
RB_FOREACH (zrt, zebra_router_table_head, &zrouter.tables) {
struct rib_table_info *info = route_table_get_info(zrt->table);
vty_out(vty, "%-16s%5d %9d %7s %15s %8d %10lu\n", info->zvrf->vrf->name,
zrt->ns_id, info->zvrf->vrf->vrf_id,
afi2str(zrt->afi), safi2str(zrt->safi),
zrt->tableid,
zrt->table->count);
}
}
void zebra_router_sweep_route(void)
{
struct zebra_router_table *zrt;
RB_FOREACH (zrt, zebra_router_table_head, &zrouter.tables) {
if (zrt->ns_id != NS_DEFAULT)
continue;
rib_sweep_table(zrt->table);
}
}
void zebra_router_sweep_nhgs(void)
{
zebra_nhg_sweep_table(zrouter.nhgs_id);
}
static void zebra_router_free_table(struct zebra_router_table *zrt)
{
void *table_info;
table_info = route_table_get_info(zrt->table);
route_table_finish(zrt->table);
RB_REMOVE(zebra_router_table_head, &zrouter.tables, zrt);
XFREE(MTYPE_RIB_TABLE_INFO, table_info);
XFREE(MTYPE_ZEBRA_RT_TABLE, zrt);
}
void zebra_router_release_table(struct zebra_vrf *zvrf, uint32_t tableid,
afi_t afi, safi_t safi)
{
struct zebra_router_table finder;
struct zebra_router_table *zrt;
memset(&finder, 0, sizeof(finder));
finder.afi = afi;
finder.safi = safi;
finder.tableid = tableid;
finder.ns_id = zvrf->zns->ns_id;
zrt = RB_FIND(zebra_router_table_head, &zrouter.tables, &finder);
if (!zrt)
return;
zebra_router_free_table(zrt);
}
uint32_t zebra_router_get_next_sequence(void)
{
return 1
+ atomic_fetch_add_explicit(&zrouter.sequence_num, 1,
memory_order_relaxed);
}
void multicast_mode_ipv4_set(enum multicast_mode mode)
{
if (IS_ZEBRA_DEBUG_RIB)
zlog_debug("%s: multicast lookup mode set (%d)", __func__,
mode);
zrouter.ipv4_multicast_mode = mode;
}
enum multicast_mode multicast_mode_ipv4_get(void)
{
return zrouter.ipv4_multicast_mode;
}
void zebra_router_terminate(void)
{
struct zebra_router_table *zrt, *tmp;
EVENT_OFF(zrouter.sweeper);
RB_FOREACH_SAFE (zrt, zebra_router_table_head, &zrouter.tables, tmp)
zebra_router_free_table(zrt);
work_queue_free_and_null(&zrouter.ribq);
meta_queue_free(zrouter.mq, NULL);
zebra_vxlan_disable();
zebra_mlag_terminate();
zebra_neigh_terminate();
/* Free NHE in ID table only since it has unhashable entries as well */
hash_iterate(zrouter.nhgs_id, zebra_nhg_hash_free_zero_id, NULL);
hash_clean_and_free(&zrouter.nhgs_id, zebra_nhg_hash_free);
hash_clean_and_free(&zrouter.nhgs, NULL);
hash_clean_and_free(&zrouter.rules_hash, zebra_pbr_rules_free);
hash_clean_and_free(&zrouter.ipset_entry_hash,
zebra_pbr_ipset_entry_free);
hash_clean_and_free(&zrouter.ipset_hash, zebra_pbr_ipset_free);
hash_clean_and_free(&zrouter.iptable_hash, zebra_pbr_iptable_free);
hash_clean_and_free(&zrouter.filter_hash, (void (*)(void *)) zebra_tc_filter_free);
hash_clean_and_free(&zrouter.qdisc_hash, (void (*)(void *)) zebra_tc_qdisc_free);
hash_clean_and_free(&zrouter.class_hash, (void (*)(void *)) zebra_tc_class_free);
#ifdef HAVE_SCRIPTING
zebra_script_destroy();
#endif
zebra_vxlan_terminate();
/* OS-specific deinit */
kernel_router_terminate();
}
bool zebra_router_notify_on_ack(void)
{
return !zrouter.asic_offloaded || zrouter.notify_on_ack;
}
void zebra_router_init(bool asic_offload, bool notify_on_ack,
bool v6_with_v4_nexthop)
{
zrouter.sequence_num = 0;
zrouter.protodown_r_bit = FRR_PROTODOWN_REASON_DEFAULT_BIT;
zrouter.allow_delete = false;
zrouter.packets_to_process = ZEBRA_ZAPI_PACKETS_TO_PROCESS;
zrouter.nhg_keep = ZEBRA_DEFAULT_NHG_KEEP_TIMER;
zebra_vxlan_init();
zebra_mlag_init();
zebra_neigh_init();
zrouter.rules_hash = hash_create_size(8, zebra_pbr_rules_hash_key,
zebra_pbr_rules_hash_equal,
"Rules Hash");
zrouter.ipset_hash =
hash_create_size(8, zebra_pbr_ipset_hash_key,
zebra_pbr_ipset_hash_equal, "IPset Hash");
zrouter.ipset_entry_hash = hash_create_size(
8, zebra_pbr_ipset_entry_hash_key,
zebra_pbr_ipset_entry_hash_equal, "IPset Hash Entry");
zrouter.iptable_hash = hash_create_size(8, zebra_pbr_iptable_hash_key,
zebra_pbr_iptable_hash_equal,
"IPtable Hash Entry");
zrouter.nhgs =
hash_create_size(8, zebra_nhg_hash_key, zebra_nhg_hash_equal,
"Zebra Router Nexthop Groups");
zrouter.nhgs_id =
hash_create_size(8, zebra_nhg_id_key, zebra_nhg_hash_id_equal,
"Zebra Router Nexthop Groups ID index");
zrouter.qdisc_hash =
hash_create_size(8, zebra_tc_qdisc_hash_key,
zebra_tc_qdisc_hash_equal, "TC (qdisc) Hash");
zrouter.class_hash = hash_create_size(8, zebra_tc_class_hash_key,
zebra_tc_class_hash_equal,
"TC (classes) Hash");
zrouter.filter_hash = hash_create_size(8, zebra_tc_filter_hash_key,
zebra_tc_filter_hash_equal,
"TC (filter) Hash");
zrouter.asic_offloaded = asic_offload;
zrouter.notify_on_ack = notify_on_ack;
zrouter.v6_with_v4_nexthop = v6_with_v4_nexthop;
/*
* If you start using asic_notification_nexthop_control
* come talk to the FRR community about what you are doing
* We would like to know.
*/
#if CONFDATE > 20251231
CPP_NOTICE(
"Remove zrouter.asic_notification_nexthop_control as that it's not being maintained or used");
#endif
zrouter.asic_notification_nexthop_control = false;
zrouter.nexthop_weight_scale_value = 255;
#ifdef HAVE_SCRIPTING
zebra_script_init();
#endif
/* OS-specific init */
kernel_router_init();
}