diff options
Diffstat (limited to 'zebra/zebra_router.c')
-rw-r--r-- | zebra/zebra_router.c | 332 |
1 files changed, 332 insertions, 0 deletions
diff --git a/zebra/zebra_router.c b/zebra/zebra_router.c new file mode 100644 index 0000000..4caaf8a --- /dev/null +++ b/zebra/zebra_router.c @@ -0,0 +1,332 @@ +// 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); + +#ifdef HAVE_SCRIPTING + zebra_script_destroy(); +#endif + + /* 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.rules_hash = + hash_create_size(8, zebra_pbr_rules_hash_key, + zebra_pbr_rules_hash_equal, "Rules Hash"); + + 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; + +#ifdef HAVE_SCRIPTING + zebra_script_init(); +#endif + + /* OS-specific init */ + kernel_router_init(); +} |