/src/frr/zebra/zebra_router.c
Line | Count | Source (jump to first uncovered line) |
1 | | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | | /* Zebra Router Code. |
3 | | * Copyright (C) 2018 Cumulus Networks, Inc. |
4 | | * Donald Sharp |
5 | | */ |
6 | | #include "zebra.h" |
7 | | |
8 | | #include <pthread.h> |
9 | | #include "lib/frratomic.h" |
10 | | |
11 | | #include "zebra_router.h" |
12 | | #include "zebra_pbr.h" |
13 | | #include "zebra_vxlan.h" |
14 | | #include "zebra_mlag.h" |
15 | | #include "zebra_nhg.h" |
16 | | #include "zebra_neigh.h" |
17 | | #include "zebra/zebra_tc.h" |
18 | | #include "debug.h" |
19 | | #include "zebra_script.h" |
20 | | |
21 | | DEFINE_MTYPE_STATIC(ZEBRA, RIB_TABLE_INFO, "RIB table info"); |
22 | | DEFINE_MTYPE_STATIC(ZEBRA, ZEBRA_RT_TABLE, "Zebra VRF table"); |
23 | | |
24 | | struct zebra_router zrouter = { |
25 | | .multipath_num = MULTIPATH_NUM, |
26 | | .ipv4_multicast_mode = MCAST_NO_CONFIG, |
27 | | }; |
28 | | |
29 | | static inline int |
30 | | zebra_router_table_entry_compare(const struct zebra_router_table *e1, |
31 | | const struct zebra_router_table *e2); |
32 | | |
33 | | RB_GENERATE(zebra_router_table_head, zebra_router_table, |
34 | | zebra_router_table_entry, zebra_router_table_entry_compare); |
35 | | |
36 | | |
37 | | static inline int |
38 | | zebra_router_table_entry_compare(const struct zebra_router_table *e1, |
39 | | const struct zebra_router_table *e2) |
40 | 0 | { |
41 | 0 | if (e1->tableid < e2->tableid) |
42 | 0 | return -1; |
43 | 0 | if (e1->tableid > e2->tableid) |
44 | 0 | return 1; |
45 | 0 | if (e1->ns_id < e2->ns_id) |
46 | 0 | return -1; |
47 | 0 | if (e1->ns_id > e2->ns_id) |
48 | 0 | return 1; |
49 | 0 | if (e1->afi < e2->afi) |
50 | 0 | return -1; |
51 | 0 | if (e1->afi > e2->afi) |
52 | 0 | return 1; |
53 | 0 | return (e1->safi - e2->safi); |
54 | 0 | } |
55 | | |
56 | | struct zebra_router_table *zebra_router_find_zrt(struct zebra_vrf *zvrf, |
57 | | uint32_t tableid, afi_t afi, |
58 | | safi_t safi) |
59 | 0 | { |
60 | 0 | struct zebra_router_table finder; |
61 | 0 | struct zebra_router_table *zrt; |
62 | |
|
63 | 0 | memset(&finder, 0, sizeof(finder)); |
64 | 0 | finder.afi = afi; |
65 | 0 | finder.safi = safi; |
66 | 0 | finder.tableid = tableid; |
67 | 0 | finder.ns_id = zvrf->zns->ns_id; |
68 | 0 | zrt = RB_FIND(zebra_router_table_head, &zrouter.tables, &finder); |
69 | |
|
70 | 0 | return zrt; |
71 | 0 | } |
72 | | |
73 | | struct route_table *zebra_router_find_table(struct zebra_vrf *zvrf, |
74 | | uint32_t tableid, afi_t afi, |
75 | | safi_t safi) |
76 | 0 | { |
77 | 0 | struct zebra_router_table finder; |
78 | 0 | struct zebra_router_table *zrt; |
79 | |
|
80 | 0 | memset(&finder, 0, sizeof(finder)); |
81 | 0 | finder.afi = afi; |
82 | 0 | finder.safi = safi; |
83 | 0 | finder.tableid = tableid; |
84 | 0 | finder.ns_id = zvrf->zns->ns_id; |
85 | 0 | zrt = RB_FIND(zebra_router_table_head, &zrouter.tables, &finder); |
86 | |
|
87 | 0 | if (zrt) |
88 | 0 | return zrt->table; |
89 | 0 | else |
90 | 0 | return NULL; |
91 | 0 | } |
92 | | |
93 | | struct route_table *zebra_router_get_table(struct zebra_vrf *zvrf, |
94 | | uint32_t tableid, afi_t afi, |
95 | | safi_t safi) |
96 | 0 | { |
97 | 0 | struct zebra_router_table finder; |
98 | 0 | struct zebra_router_table *zrt; |
99 | 0 | struct rib_table_info *info; |
100 | |
|
101 | 0 | memset(&finder, 0, sizeof(finder)); |
102 | 0 | finder.afi = afi; |
103 | 0 | finder.safi = safi; |
104 | 0 | finder.tableid = tableid; |
105 | 0 | finder.ns_id = zvrf->zns->ns_id; |
106 | 0 | zrt = RB_FIND(zebra_router_table_head, &zrouter.tables, &finder); |
107 | |
|
108 | 0 | if (zrt) |
109 | 0 | return zrt->table; |
110 | | |
111 | 0 | zrt = XCALLOC(MTYPE_ZEBRA_RT_TABLE, sizeof(*zrt)); |
112 | 0 | zrt->tableid = tableid; |
113 | 0 | zrt->afi = afi; |
114 | 0 | zrt->safi = safi; |
115 | 0 | zrt->ns_id = zvrf->zns->ns_id; |
116 | 0 | zrt->table = |
117 | 0 | (afi == AFI_IP6) ? srcdest_table_init() : route_table_init(); |
118 | |
|
119 | 0 | info = XCALLOC(MTYPE_RIB_TABLE_INFO, sizeof(*info)); |
120 | 0 | info->zvrf = zvrf; |
121 | 0 | info->afi = afi; |
122 | 0 | info->safi = safi; |
123 | 0 | info->table_id = tableid; |
124 | 0 | route_table_set_info(zrt->table, info); |
125 | 0 | zrt->table->cleanup = zebra_rtable_node_cleanup; |
126 | |
|
127 | 0 | RB_INSERT(zebra_router_table_head, &zrouter.tables, zrt); |
128 | 0 | return zrt->table; |
129 | 0 | } |
130 | | |
131 | | void zebra_router_show_table_summary(struct vty *vty) |
132 | 0 | { |
133 | 0 | struct zebra_router_table *zrt; |
134 | |
|
135 | 0 | vty_out(vty, |
136 | 0 | "VRF NS ID VRF ID AFI SAFI Table Count\n"); |
137 | 0 | vty_out(vty, |
138 | 0 | "---------------------------------------------------------------------------\n"); |
139 | 0 | RB_FOREACH (zrt, zebra_router_table_head, &zrouter.tables) { |
140 | 0 | struct rib_table_info *info = route_table_get_info(zrt->table); |
141 | |
|
142 | 0 | vty_out(vty, "%-16s%5d %9d %7s %15s %8d %10lu\n", info->zvrf->vrf->name, |
143 | 0 | zrt->ns_id, info->zvrf->vrf->vrf_id, |
144 | 0 | afi2str(zrt->afi), safi2str(zrt->safi), |
145 | 0 | zrt->tableid, |
146 | 0 | zrt->table->count); |
147 | 0 | } |
148 | 0 | } |
149 | | |
150 | | void zebra_router_sweep_route(void) |
151 | 0 | { |
152 | 0 | struct zebra_router_table *zrt; |
153 | |
|
154 | 0 | RB_FOREACH (zrt, zebra_router_table_head, &zrouter.tables) { |
155 | 0 | if (zrt->ns_id != NS_DEFAULT) |
156 | 0 | continue; |
157 | 0 | rib_sweep_table(zrt->table); |
158 | 0 | } |
159 | 0 | } |
160 | | |
161 | | void zebra_router_sweep_nhgs(void) |
162 | 0 | { |
163 | 0 | zebra_nhg_sweep_table(zrouter.nhgs_id); |
164 | 0 | } |
165 | | |
166 | | static void zebra_router_free_table(struct zebra_router_table *zrt) |
167 | 0 | { |
168 | 0 | void *table_info; |
169 | |
|
170 | 0 | table_info = route_table_get_info(zrt->table); |
171 | 0 | route_table_finish(zrt->table); |
172 | 0 | RB_REMOVE(zebra_router_table_head, &zrouter.tables, zrt); |
173 | |
|
174 | 0 | XFREE(MTYPE_RIB_TABLE_INFO, table_info); |
175 | 0 | XFREE(MTYPE_ZEBRA_RT_TABLE, zrt); |
176 | 0 | } |
177 | | |
178 | | void zebra_router_release_table(struct zebra_vrf *zvrf, uint32_t tableid, |
179 | | afi_t afi, safi_t safi) |
180 | 0 | { |
181 | 0 | struct zebra_router_table finder; |
182 | 0 | struct zebra_router_table *zrt; |
183 | |
|
184 | 0 | memset(&finder, 0, sizeof(finder)); |
185 | 0 | finder.afi = afi; |
186 | 0 | finder.safi = safi; |
187 | 0 | finder.tableid = tableid; |
188 | 0 | finder.ns_id = zvrf->zns->ns_id; |
189 | 0 | zrt = RB_FIND(zebra_router_table_head, &zrouter.tables, &finder); |
190 | |
|
191 | 0 | if (!zrt) |
192 | 0 | return; |
193 | | |
194 | 0 | zebra_router_free_table(zrt); |
195 | 0 | } |
196 | | |
197 | | uint32_t zebra_router_get_next_sequence(void) |
198 | 0 | { |
199 | 0 | return 1 |
200 | 0 | + atomic_fetch_add_explicit(&zrouter.sequence_num, 1, |
201 | 0 | memory_order_relaxed); |
202 | 0 | } |
203 | | |
204 | | void multicast_mode_ipv4_set(enum multicast_mode mode) |
205 | 0 | { |
206 | 0 | if (IS_ZEBRA_DEBUG_RIB) |
207 | 0 | zlog_debug("%s: multicast lookup mode set (%d)", __func__, |
208 | 0 | mode); |
209 | 0 | zrouter.ipv4_multicast_mode = mode; |
210 | 0 | } |
211 | | |
212 | | enum multicast_mode multicast_mode_ipv4_get(void) |
213 | 0 | { |
214 | 0 | return zrouter.ipv4_multicast_mode; |
215 | 0 | } |
216 | | |
217 | | void zebra_router_terminate(void) |
218 | 0 | { |
219 | 0 | struct zebra_router_table *zrt, *tmp; |
220 | |
|
221 | 0 | EVENT_OFF(zrouter.sweeper); |
222 | |
|
223 | 0 | RB_FOREACH_SAFE (zrt, zebra_router_table_head, &zrouter.tables, tmp) |
224 | 0 | zebra_router_free_table(zrt); |
225 | |
|
226 | 0 | work_queue_free_and_null(&zrouter.ribq); |
227 | 0 | meta_queue_free(zrouter.mq, NULL); |
228 | |
|
229 | 0 | zebra_vxlan_disable(); |
230 | 0 | zebra_mlag_terminate(); |
231 | 0 | zebra_neigh_terminate(); |
232 | | |
233 | | /* Free NHE in ID table only since it has unhashable entries as well */ |
234 | 0 | hash_iterate(zrouter.nhgs_id, zebra_nhg_hash_free_zero_id, NULL); |
235 | 0 | hash_clean_and_free(&zrouter.nhgs_id, zebra_nhg_hash_free); |
236 | 0 | hash_clean_and_free(&zrouter.nhgs, NULL); |
237 | |
|
238 | 0 | hash_clean_and_free(&zrouter.rules_hash, zebra_pbr_rules_free); |
239 | |
|
240 | 0 | hash_clean_and_free(&zrouter.ipset_entry_hash, |
241 | 0 | zebra_pbr_ipset_entry_free); |
242 | 0 | hash_clean_and_free(&zrouter.ipset_hash, zebra_pbr_ipset_free); |
243 | 0 | hash_clean_and_free(&zrouter.iptable_hash, zebra_pbr_iptable_free); |
244 | |
|
245 | | #ifdef HAVE_SCRIPTING |
246 | | zebra_script_destroy(); |
247 | | #endif |
248 | | |
249 | | /* OS-specific deinit */ |
250 | 0 | kernel_router_terminate(); |
251 | 0 | } |
252 | | |
253 | | bool zebra_router_notify_on_ack(void) |
254 | 0 | { |
255 | 0 | return !zrouter.asic_offloaded || zrouter.notify_on_ack; |
256 | 0 | } |
257 | | |
258 | | void zebra_router_init(bool asic_offload, bool notify_on_ack) |
259 | 0 | { |
260 | 0 | zrouter.sequence_num = 0; |
261 | |
|
262 | 0 | zrouter.allow_delete = false; |
263 | |
|
264 | 0 | zrouter.packets_to_process = ZEBRA_ZAPI_PACKETS_TO_PROCESS; |
265 | |
|
266 | 0 | zrouter.nhg_keep = ZEBRA_DEFAULT_NHG_KEEP_TIMER; |
267 | |
|
268 | 0 | zebra_vxlan_init(); |
269 | 0 | zebra_mlag_init(); |
270 | 0 | zebra_neigh_init(); |
271 | |
|
272 | 0 | zrouter.rules_hash = hash_create_size(8, zebra_pbr_rules_hash_key, |
273 | 0 | zebra_pbr_rules_hash_equal, |
274 | 0 | "Rules Hash"); |
275 | |
|
276 | 0 | zrouter.ipset_hash = |
277 | 0 | hash_create_size(8, zebra_pbr_ipset_hash_key, |
278 | 0 | zebra_pbr_ipset_hash_equal, "IPset Hash"); |
279 | |
|
280 | 0 | zrouter.ipset_entry_hash = hash_create_size( |
281 | 0 | 8, zebra_pbr_ipset_entry_hash_key, |
282 | 0 | zebra_pbr_ipset_entry_hash_equal, "IPset Hash Entry"); |
283 | |
|
284 | 0 | zrouter.iptable_hash = hash_create_size(8, zebra_pbr_iptable_hash_key, |
285 | 0 | zebra_pbr_iptable_hash_equal, |
286 | 0 | "IPtable Hash Entry"); |
287 | |
|
288 | 0 | zrouter.nhgs = |
289 | 0 | hash_create_size(8, zebra_nhg_hash_key, zebra_nhg_hash_equal, |
290 | 0 | "Zebra Router Nexthop Groups"); |
291 | 0 | zrouter.nhgs_id = |
292 | 0 | hash_create_size(8, zebra_nhg_id_key, zebra_nhg_hash_id_equal, |
293 | 0 | "Zebra Router Nexthop Groups ID index"); |
294 | |
|
295 | 0 | zrouter.rules_hash = |
296 | 0 | hash_create_size(8, zebra_pbr_rules_hash_key, |
297 | 0 | zebra_pbr_rules_hash_equal, "Rules Hash"); |
298 | |
|
299 | 0 | zrouter.qdisc_hash = |
300 | 0 | hash_create_size(8, zebra_tc_qdisc_hash_key, |
301 | 0 | zebra_tc_qdisc_hash_equal, "TC (qdisc) Hash"); |
302 | 0 | zrouter.class_hash = hash_create_size(8, zebra_tc_class_hash_key, |
303 | 0 | zebra_tc_class_hash_equal, |
304 | 0 | "TC (classes) Hash"); |
305 | 0 | zrouter.filter_hash = hash_create_size(8, zebra_tc_filter_hash_key, |
306 | 0 | zebra_tc_filter_hash_equal, |
307 | 0 | "TC (filter) Hash"); |
308 | |
|
309 | 0 | zrouter.asic_offloaded = asic_offload; |
310 | 0 | zrouter.notify_on_ack = notify_on_ack; |
311 | | |
312 | | /* |
313 | | * If you start using asic_notification_nexthop_control |
314 | | * come talk to the FRR community about what you are doing |
315 | | * We would like to know. |
316 | | */ |
317 | | #if CONFDATE > 20251231 |
318 | | CPP_NOTICE( |
319 | | "Remove zrouter.asic_notification_nexthop_control as that it's not being maintained or used"); |
320 | | #endif |
321 | 0 | zrouter.asic_notification_nexthop_control = false; |
322 | |
|
323 | | #ifdef HAVE_SCRIPTING |
324 | | zebra_script_init(); |
325 | | #endif |
326 | | |
327 | | /* OS-specific init */ |
328 | 0 | kernel_router_init(); |
329 | 0 | } |