]>
Commit | Line | Data |
---|---|---|
acddc0ed | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
edd7c245 | 2 | /* zebra daemon main routine. |
718e3744 | 3 | * Copyright (C) 1997, 98 Kunihiro Ishiguro |
718e3744 | 4 | */ |
5 | ||
6 | #include <zebra.h> | |
7 | ||
5e4fa164 | 8 | #include <lib/version.h> |
718e3744 | 9 | #include "getopt.h" |
10 | #include "command.h" | |
24a58196 | 11 | #include "frrevent.h" |
718e3744 | 12 | #include "filter.h" |
13 | #include "memory.h" | |
14 | #include "prefix.h" | |
15 | #include "log.h" | |
7514fb77 | 16 | #include "plist.h" |
edd7c245 | 17 | #include "privs.h" |
2d75d052 | 18 | #include "sigevent.h" |
b72ede27 | 19 | #include "vrf.h" |
4f04a76b | 20 | #include "libfrr.h" |
05a12619 | 21 | #include "affinitymap.h" |
bf094f69 | 22 | #include "routemap.h" |
755100ac | 23 | #include "routing_nb.h" |
718e3744 | 24 | |
89272910 | 25 | #include "zebra/zebra_router.h" |
43e52561 | 26 | #include "zebra/zebra_errors.h" |
718e3744 | 27 | #include "zebra/rib.h" |
28 | #include "zebra/zserv.h" | |
29 | #include "zebra/debug.h" | |
18a6dce6 | 30 | #include "zebra/router-id.h" |
ca776988 | 31 | #include "zebra/irdp.h" |
a1ac18c4 | 32 | #include "zebra/rtadv.h" |
244c1cdc | 33 | #include "zebra/zebra_ptm.h" |
fe18ee2d | 34 | #include "zebra/zebra_ns.h" |
e2b1be64 | 35 | #include "zebra/redistribute.h" |
7758e3f3 | 36 | #include "zebra/zebra_mpls.h" |
fea12efb | 37 | #include "zebra/label_manager.h" |
e27dec3c | 38 | #include "zebra/zebra_netns_notify.h" |
453844ab | 39 | #include "zebra/zebra_rnh.h" |
4c0ec639 | 40 | #include "zebra/zebra_pbr.h" |
27627f9a | 41 | #include "zebra/zebra_vxlan.h" |
a2665e38 | 42 | #include "zebra/zebra_routemap.h" |
ce45ffe7 | 43 | #include "zebra/zebra_nb.h" |
9bb02389 | 44 | #include "zebra/zebra_opaque.h" |
31f937fb | 45 | #include "zebra/zebra_srte.h" |
6e68a084 | 46 | #include "zebra/zebra_srv6.h" |
6c0a7c09 | 47 | #include "zebra/zebra_srv6_vty.h" |
244c1cdc DS |
48 | |
49 | #define ZEBRA_PTM_SUPPORT | |
718e3744 | 50 | |
718e3744 | 51 | /* process id. */ |
718e3744 | 52 | pid_t pid; |
53 | ||
55c72803 | 54 | /* Pacify zclient.o in libfrr, which expects this variable. */ |
cd9d0537 | 55 | struct event_loop *master; |
87efd646 | 56 | |
718e3744 | 57 | /* Route retain mode flag. */ |
58 | int retain_mode = 0; | |
59 | ||
d4644d41 DS |
60 | int graceful_restart; |
61 | ||
6b093863 DS |
62 | bool v6_rr_semantics = false; |
63 | ||
9fb83b55 | 64 | /* Receive buffer size for kernel control sockets */ |
0c99696f | 65 | #define RCVBUFSIZE_MIN 4194304 |
c34b6b57 | 66 | #ifdef HAVE_NETLINK |
0c99696f | 67 | uint32_t rcvbufsize = RCVBUFSIZE_MIN; |
9fb83b55 DS |
68 | #else |
69 | uint32_t rcvbufsize = 128 * 1024; | |
70 | #endif | |
c34b6b57 | 71 | |
6b093863 | 72 | #define OPTION_V6_RR_SEMANTICS 2000 |
e4876266 DS |
73 | #define OPTION_ASIC_OFFLOAD 2001 |
74 | ||
718e3744 | 75 | /* Command line options. */ |
2b64873d | 76 | const struct option longopts[] = { |
6b093863 DS |
77 | {"batch", no_argument, NULL, 'b'}, |
78 | {"allow_delete", no_argument, NULL, 'a'}, | |
6b093863 DS |
79 | {"socket", required_argument, NULL, 'z'}, |
80 | {"ecmp", required_argument, NULL, 'e'}, | |
6b093863 | 81 | {"retain", no_argument, NULL, 'r'}, |
d4644d41 | 82 | {"graceful_restart", required_argument, NULL, 'K'}, |
e4876266 | 83 | {"asic-offload", optional_argument, NULL, OPTION_ASIC_OFFLOAD}, |
c34b6b57 | 84 | #ifdef HAVE_NETLINK |
6b093863 DS |
85 | {"vrfwnetns", no_argument, NULL, 'n'}, |
86 | {"nl-bufsize", required_argument, NULL, 's'}, | |
87 | {"v6-rr-semantics", no_argument, NULL, OPTION_V6_RR_SEMANTICS}, | |
c34b6b57 | 88 | #endif /* HAVE_NETLINK */ |
6b093863 | 89 | {0}}; |
718e3744 | 90 | |
fd03f1d4 AK |
91 | zebra_capabilities_t _caps_p[] = {ZCAP_NET_ADMIN, ZCAP_SYS_ADMIN, |
92 | ZCAP_NET_RAW, | |
93 | #ifdef HAVE_DPDK | |
94 | ZCAP_IPC_LOCK, ZCAP_READ_SEARCH, | |
95 | ZCAP_SYS_RAWIO | |
96 | #endif | |
97 | }; | |
edd7c245 | 98 | |
99 | /* zebra privileges to run with */ | |
d62a17ae | 100 | struct zebra_privs_t zserv_privs = { |
b2f36157 | 101 | #if defined(FRR_USER) && defined(FRR_GROUP) |
d62a17ae | 102 | .user = FRR_USER, |
103 | .group = FRR_GROUP, | |
edd7c245 | 104 | #endif |
105 | #ifdef VTY_GROUP | |
d62a17ae | 106 | .vty_group = VTY_GROUP, |
edd7c245 | 107 | #endif |
d62a17ae | 108 | .caps_p = _caps_p, |
109 | .cap_num_p = array_size(_caps_p), | |
110 | .cap_num_i = 0}; | |
edd7c245 | 111 | |
718e3744 | 112 | /* SIGHUP handler. */ |
d62a17ae | 113 | static void sighup(void) |
718e3744 | 114 | { |
d62a17ae | 115 | zlog_info("SIGHUP received"); |
718e3744 | 116 | |
d62a17ae | 117 | /* Reload of config file. */ |
118 | ; | |
718e3744 | 119 | } |
120 | ||
121 | /* SIGINT handler. */ | |
d62a17ae | 122 | static void sigint(void) |
718e3744 | 123 | { |
d62a17ae | 124 | struct vrf *vrf; |
125 | struct zebra_vrf *zvrf; | |
f3e33b69 QY |
126 | struct listnode *ln, *nn; |
127 | struct zserv *client; | |
ff2460d5 MS |
128 | static bool sigint_done; |
129 | ||
130 | if (sigint_done) | |
131 | return; | |
132 | ||
133 | sigint_done = true; | |
fe18ee2d | 134 | |
d62a17ae | 135 | zlog_notice("Terminating on signal"); |
718e3744 | 136 | |
2fc69f03 MS |
137 | atomic_store_explicit(&zrouter.in_shutdown, true, |
138 | memory_order_relaxed); | |
139 | ||
d7fc0e67 DS |
140 | /* send RA lifetime of 0 before stopping. rfc4861/6.2.5 */ |
141 | rtadv_stop_ra_all(); | |
142 | ||
03951374 | 143 | frr_early_fini(); |
718e3744 | 144 | |
9bb02389 MS |
145 | /* Stop the opaque module pthread */ |
146 | zebra_opaque_stop(); | |
147 | ||
4dfd7a02 MS |
148 | zebra_dplane_pre_finish(); |
149 | ||
b9e6727a S |
150 | /* Clean up GR related info. */ |
151 | zebra_gr_stale_client_cleanup(zrouter.stale_client_list); | |
152 | list_delete_all_node(zrouter.stale_client_list); | |
153 | ||
9bb02389 | 154 | /* Clean up zapi clients and server module */ |
161e9ab7 | 155 | for (ALL_LIST_ELEMENTS(zrouter.client_list, ln, nn, client)) |
f3e33b69 QY |
156 | zserv_close_client(client); |
157 | ||
41674562 | 158 | zserv_close(); |
161e9ab7 | 159 | list_delete_all_node(zrouter.client_list); |
41674562 | 160 | |
9bb02389 MS |
161 | /* Once all the zclients are cleaned up, clean up the opaque module */ |
162 | zebra_opaque_finish(); | |
163 | ||
f88bd20c | 164 | zebra_ptm_finish(); |
d62a17ae | 165 | |
b1b07ef5 DS |
166 | if (retain_mode) { |
167 | zebra_nhg_mark_keep(); | |
a2addae8 | 168 | RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { |
d62a17ae | 169 | zvrf = vrf->info; |
170 | if (zvrf) | |
171 | SET_FLAG(zvrf->flags, ZEBRA_VRF_RETAIN); | |
172 | } | |
b1b07ef5 | 173 | } |
3e0372d2 | 174 | |
695b279a MS |
175 | if (zrouter.lsp_process_q) |
176 | work_queue_free_and_null(&zrouter.lsp_process_q); | |
177 | ||
d62a17ae | 178 | access_list_reset(); |
179 | prefix_list_reset(); | |
a2665e38 | 180 | /* |
181 | * zebra_routemap_finish will | |
182 | * 1 set rmap upd timer to 0 so that rmap update wont be scheduled again | |
183 | * 2 Put off the rmap update thread | |
184 | * 3 route_map_finish | |
185 | */ | |
186 | zebra_routemap_finish(); | |
03951374 | 187 | |
3cd0accb DS |
188 | rib_update_finish(); |
189 | ||
161e9ab7 | 190 | list_delete(&zrouter.client_list); |
4dfd7a02 | 191 | |
ff2460d5 MS |
192 | /* Indicate that all new dplane work has been enqueued. When that |
193 | * work is complete, the dataplane will enqueue an event | |
194 | * with the 'finalize' function. | |
195 | */ | |
1d11b21f | 196 | zebra_dplane_finish(); |
4dfd7a02 MS |
197 | } |
198 | ||
ff2460d5 MS |
199 | /* |
200 | * Final shutdown step for the zebra main thread. This is run after all | |
201 | * async update processing has completed. | |
202 | */ | |
e6685141 | 203 | void zebra_finalize(struct event *dummy) |
4dfd7a02 MS |
204 | { |
205 | zlog_info("Zebra final shutdown"); | |
206 | ||
8dc5dbb8 | 207 | vrf_terminate(); |
208 | ||
209 | ns_walk_func(zebra_ns_early_shutdown, NULL, NULL); | |
210 | zebra_ns_notify_close(); | |
211 | ||
4dfd7a02 MS |
212 | /* Stop dplane thread and finish any cleanup */ |
213 | zebra_dplane_shutdown(); | |
1d11b21f | 214 | |
0e61463a DS |
215 | /* Final shutdown of ns resources */ |
216 | ns_walk_func(zebra_ns_final_shutdown, NULL, NULL); | |
217 | ||
89272910 DS |
218 | zebra_router_terminate(); |
219 | ||
54fcc739 | 220 | ns_terminate(); |
03951374 | 221 | frr_fini(); |
d62a17ae | 222 | exit(0); |
718e3744 | 223 | } |
224 | ||
225 | /* SIGUSR1 handler. */ | |
d62a17ae | 226 | static void sigusr1(void) |
718e3744 | 227 | { |
d62a17ae | 228 | zlog_rotate(); |
718e3744 | 229 | } |
230 | ||
7cc91e67 | 231 | struct frr_signal_t zebra_signals[] = { |
d62a17ae | 232 | { |
233 | .signal = SIGHUP, | |
234 | .handler = &sighup, | |
235 | }, | |
236 | { | |
237 | .signal = SIGUSR1, | |
238 | .handler = &sigusr1, | |
239 | }, | |
240 | { | |
241 | .signal = SIGINT, | |
242 | .handler = &sigint, | |
243 | }, | |
244 | { | |
245 | .signal = SIGTERM, | |
246 | .handler = &sigint, | |
247 | }, | |
2d75d052 | 248 | }; |
b72ede27 | 249 | |
05a12619 | 250 | /* clang-format off */ |
0d8c7a26 | 251 | static const struct frr_yang_module_info *const zebra_yang_modules[] = { |
c2aab693 | 252 | &frr_filter_info, |
a4bed468 | 253 | &frr_interface_info, |
91835f1f | 254 | &frr_route_map_info, |
b87fa24d | 255 | &frr_zebra_info, |
6fd8972a | 256 | &frr_vrf_info, |
755100ac | 257 | &frr_routing_info, |
05a12619 | 258 | &frr_affinity_map_info, |
e71627cb | 259 | &frr_zebra_route_map_info, |
8fcdd0d6 | 260 | }; |
05a12619 | 261 | /* clang-format on */ |
8fcdd0d6 | 262 | |
d62a17ae | 263 | FRR_DAEMON_INFO( |
264 | zebra, ZEBRA, .vty_port = ZEBRA_VTY_PORT, .flags = FRR_NO_ZCLIENT, | |
4f04a76b | 265 | |
d62a17ae | 266 | .proghelp = |
3efd0893 | 267 | "Daemon which manages kernel routing table management and\nredistribution between different routing protocols.", |
4f04a76b | 268 | |
d62a17ae | 269 | .signals = zebra_signals, .n_signals = array_size(zebra_signals), |
4f04a76b | 270 | |
8fcdd0d6 RW |
271 | .privs = &zserv_privs, |
272 | ||
273 | .yang_modules = zebra_yang_modules, | |
80413c20 DL |
274 | .n_yang_modules = array_size(zebra_yang_modules), |
275 | ); | |
4f04a76b | 276 | |
718e3744 | 277 | /* Main startup routine. */ |
d62a17ae | 278 | int main(int argc, char **argv) |
718e3744 | 279 | { |
d62a17ae | 280 | // int batch_mode = 0; |
281 | char *zserv_path = NULL; | |
689f5a8c DL |
282 | struct sockaddr_storage dummy; |
283 | socklen_t dummylen; | |
e4876266 DS |
284 | bool asic_offload = false; |
285 | bool notify_on_ack = true; | |
fea12efb | 286 | |
d4644d41 | 287 | graceful_restart = 0; |
78dd30b2 PG |
288 | vrf_configure_backend(VRF_BACKEND_VRF_LITE); |
289 | ||
d62a17ae | 290 | frr_preinit(&zebra_di, argc, argv); |
718e3744 | 291 | |
d62a17ae | 292 | frr_opt_add( |
9fb83b55 | 293 | "baz:e:rK:s:" |
4f04a76b | 294 | #ifdef HAVE_NETLINK |
9fb83b55 | 295 | "n" |
411314ed | 296 | #endif |
d62a17ae | 297 | , |
298 | longopts, | |
d4644d41 DS |
299 | " -b, --batch Runs in batch mode\n" |
300 | " -a, --allow_delete Allow other processes to delete zebra routes\n" | |
301 | " -z, --socket Set path of zebra socket\n" | |
302 | " -e, --ecmp Specify ECMP to use.\n" | |
d4644d41 | 303 | " -r, --retain When program terminates, retain added route by zebra.\n" |
d4644d41 | 304 | " -K, --graceful_restart Graceful restart at the kernel level, timer in seconds for expiration\n" |
e4876266 | 305 | " -A, --asic-offload FRR is interacting with an asic underneath the linux kernel\n" |
4f04a76b | 306 | #ifdef HAVE_NETLINK |
d4644d41 | 307 | " -s, --nl-bufsize Set netlink receive buffer size\n" |
9fb83b55 | 308 | " -n, --vrfwnetns Use NetNS as VRF backend\n" |
d4644d41 | 309 | " --v6-rr-semantics Use v6 RR semantics\n" |
9fb83b55 DS |
310 | #else |
311 | " -s, Set kernel socket receive buffer size\n" | |
4f04a76b | 312 | #endif /* HAVE_NETLINK */ |
6b093863 | 313 | ); |
d62a17ae | 314 | |
315 | while (1) { | |
316 | int opt = frr_getopt(argc, argv, NULL); | |
317 | ||
318 | if (opt == EOF) | |
319 | break; | |
320 | ||
321 | switch (opt) { | |
322 | case 0: | |
323 | break; | |
324 | case 'b': | |
325 | // batch_mode = 1; | |
326 | break; | |
327 | case 'a': | |
88b0baa6 | 328 | zrouter.allow_delete = true; |
d62a17ae | 329 | break; |
1e03d6bc QY |
330 | case 'e': { |
331 | unsigned long int parsed_multipath = | |
332 | strtoul(optarg, NULL, 10); | |
333 | if (parsed_multipath == 0 | |
334 | || parsed_multipath > MULTIPATH_NUM | |
335 | || parsed_multipath > UINT32_MAX) { | |
af4c2728 | 336 | flog_err( |
e914ccbe | 337 | EC_ZEBRA_BAD_MULTIPATH_NUM, |
1e03d6bc | 338 | "Multipath Number specified must be less than %u and greater than 0", |
d62a17ae | 339 | MULTIPATH_NUM); |
340 | return 1; | |
341 | } | |
1e03d6bc | 342 | zrouter.multipath_num = parsed_multipath; |
d62a17ae | 343 | break; |
1e03d6bc | 344 | } |
d62a17ae | 345 | case 'z': |
346 | zserv_path = optarg; | |
689f5a8c DL |
347 | if (!frr_zclient_addr(&dummy, &dummylen, optarg)) { |
348 | fprintf(stderr, | |
349 | "Invalid zserv socket path: %s\n", | |
350 | optarg); | |
351 | exit(1); | |
352 | } | |
d62a17ae | 353 | break; |
d62a17ae | 354 | case 'r': |
355 | retain_mode = 1; | |
356 | break; | |
d4644d41 | 357 | case 'K': |
d4644d41 DS |
358 | graceful_restart = atoi(optarg); |
359 | break; | |
d62a17ae | 360 | case 's': |
9fb83b55 | 361 | rcvbufsize = atoi(optarg); |
0c99696f LV |
362 | if (rcvbufsize < RCVBUFSIZE_MIN) |
363 | fprintf(stderr, | |
364 | "Rcvbufsize is smaller than recommended value: %d\n", | |
365 | RCVBUFSIZE_MIN); | |
d62a17ae | 366 | break; |
9fb83b55 | 367 | #ifdef HAVE_NETLINK |
78dd30b2 PG |
368 | case 'n': |
369 | vrf_configure_backend(VRF_BACKEND_NETNS); | |
370 | break; | |
6b093863 DS |
371 | case OPTION_V6_RR_SEMANTICS: |
372 | v6_rr_semantics = true; | |
373 | break; | |
e4876266 DS |
374 | case OPTION_ASIC_OFFLOAD: |
375 | if (!strcmp(optarg, "notify_on_offload")) | |
376 | notify_on_ack = false; | |
377 | if (!strcmp(optarg, "notify_on_ack")) | |
378 | notify_on_ack = true; | |
379 | asic_offload = true; | |
380 | break; | |
c34b6b57 | 381 | #endif /* HAVE_NETLINK */ |
d62a17ae | 382 | default: |
383 | frr_help_exit(1); | |
d62a17ae | 384 | } |
718e3744 | 385 | } |
d62a17ae | 386 | |
3801e764 | 387 | zrouter.master = frr_init(); |
d62a17ae | 388 | |
389 | /* Zebra related initialize. */ | |
e4876266 | 390 | zebra_router_init(asic_offload, notify_on_ack); |
5f145fb8 | 391 | zserv_init(); |
d62a17ae | 392 | rib_init(); |
393 | zebra_if_init(); | |
394 | zebra_debug_init(); | |
f84fc2c9 DS |
395 | |
396 | /* | |
397 | * Initialize NS( and implicitly the VRF module), and make kernel | |
398 | * routing socket. */ | |
ac2cb9bf | 399 | zebra_ns_init(); |
03fba42e | 400 | router_id_cmd_init(); |
f84fc2c9 | 401 | zebra_vty_init(); |
d62a17ae | 402 | access_list_init(); |
403 | prefix_list_init(); | |
d62a17ae | 404 | rtadv_cmd_init(); |
d62a17ae | 405 | /* PTM socket */ |
244c1cdc | 406 | #ifdef ZEBRA_PTM_SUPPORT |
d62a17ae | 407 | zebra_ptm_init(); |
244c1cdc | 408 | #endif |
718e3744 | 409 | |
d62a17ae | 410 | zebra_mpls_init(); |
411 | zebra_mpls_vty_init(); | |
2dd0d726 | 412 | zebra_pw_vty_init(); |
4c0ec639 | 413 | zebra_pbr_init(); |
9bb02389 | 414 | zebra_opaque_init(); |
31f937fb | 415 | zebra_srte_init(); |
6e68a084 | 416 | zebra_srv6_init(); |
6c0a7c09 | 417 | zebra_srv6_vty_init(); |
7758e3f3 | 418 | |
31f937fb SM |
419 | /* For debug purpose. */ |
420 | /* SET_FLAG (zebra_debug_event, ZEBRA_DEBUG_EVENT); */ | |
718e3744 | 421 | |
d62a17ae | 422 | /* Process the configuration file. Among other configuration |
9d303b37 DL |
423 | * directives we can meet those installing static routes. Such |
424 | * requests will not be executed immediately, but queued in | |
425 | * zebra->ribq structure until we enter the main execution loop. | |
426 | * The notifications from kernel will show originating PID equal | |
427 | * to that after daemon() completes (if ever called). | |
428 | */ | |
d62a17ae | 429 | frr_config_fork(); |
718e3744 | 430 | |
d62a17ae | 431 | /* After we have successfully acquired the pidfile, we can be sure |
9d303b37 DL |
432 | * about being the only copy of zebra process, which is submitting |
433 | * changes to the FIB. | |
434 | * Clean up zebra-originated routes. The requests will be sent to OS | |
435 | * immediately, so originating PID in notifications from kernel | |
436 | * will be equal to the current getpid(). To know about such routes, | |
437 | * we have to have route_read() called before. | |
438 | */ | |
d4644d41 | 439 | zrouter.startup_time = monotime(NULL); |
907a2395 DS |
440 | event_add_timer(zrouter.master, rib_sweep_route, NULL, graceful_restart, |
441 | &zrouter.sweeper); | |
91b7351d | 442 | |
d62a17ae | 443 | /* Needed for BSD routing socket. */ |
444 | pid = getpid(); | |
718e3744 | 445 | |
e5a60d82 MS |
446 | /* Start dataplane system */ |
447 | zebra_dplane_start(); | |
448 | ||
9bb02389 MS |
449 | /* Start the ted module, before zserv */ |
450 | zebra_opaque_start(); | |
451 | ||
21ccc0cf QY |
452 | /* Start Zebra API server */ |
453 | zserv_start(zserv_path); | |
97be79f9 | 454 | |
d62a17ae | 455 | /* Init label manager */ |
e11d7c96 | 456 | label_manager_init(); |
fea12efb | 457 | |
453844ab QY |
458 | /* RNH init */ |
459 | zebra_rnh_init(); | |
89272910 | 460 | |
27627f9a KA |
461 | /* Config handler Init */ |
462 | zebra_evpn_init(); | |
463 | ||
5ad4c39c QY |
464 | /* Error init */ |
465 | zebra_error_init(); | |
453844ab | 466 | |
3801e764 | 467 | frr_run(zrouter.master); |
718e3744 | 468 | |
d62a17ae | 469 | /* Not reached... */ |
470 | return 0; | |
718e3744 | 471 | } |