]> git.proxmox.com Git - mirror_frr.git/blob - bfdd/bfdd.c
Merge pull request #12818 from imzyxwvu/fix/other-table-inactive
[mirror_frr.git] / bfdd / bfdd.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * BFD daemon code
4 * Copyright (C) 2018 Network Device Education Foundation, Inc. ("NetDEF")
5 */
6
7 #include <zebra.h>
8
9 #include <arpa/inet.h>
10 #include <netinet/in.h>
11 #include <sys/socket.h>
12 #include <sys/un.h>
13
14 #include <err.h>
15
16 #include "filter.h"
17 #include "if.h"
18 #include "vrf.h"
19
20 #include "bfd.h"
21 #include "bfdd_nb.h"
22 #include "bfddp_packet.h"
23 #include "lib/version.h"
24 #include "lib/command.h"
25
26
27 /*
28 * FRR related code.
29 */
30 DEFINE_MGROUP(BFDD, "Bidirectional Forwarding Detection Daemon");
31 DEFINE_MTYPE(BFDD, BFDD_CONTROL, "long-lived control socket memory");
32 DEFINE_MTYPE(BFDD, BFDD_NOTIFICATION, "short-lived control notification data");
33
34 /* Master of threads. */
35 struct thread_master *master;
36
37 /* BFDd privileges */
38 static zebra_capabilities_t _caps_p[] = {ZCAP_BIND, ZCAP_SYS_ADMIN, ZCAP_NET_RAW};
39
40 /* BFD daemon information. */
41 static struct frr_daemon_info bfdd_di;
42
43 void socket_close(int *s)
44 {
45 if (*s <= 0)
46 return;
47
48 if (close(*s) != 0)
49 zlog_err("%s: close(%d): (%d) %s", __func__, *s, errno,
50 strerror(errno));
51
52 *s = -1;
53 }
54
55 static void sigusr1_handler(void)
56 {
57 zlog_rotate();
58 }
59
60 static void sigterm_handler(void)
61 {
62 bglobal.bg_shutdown = true;
63
64 /* Signalize shutdown. */
65 frr_early_fini();
66
67 /* Stop receiving message from zebra. */
68 bfdd_zclient_stop();
69
70 /* Shutdown controller to avoid receiving anymore commands. */
71 control_shutdown();
72
73 /* Shutdown and free all protocol related memory. */
74 bfd_shutdown();
75
76 bfd_vrf_terminate();
77
78 /* Terminate and free() FRR related memory. */
79 frr_fini();
80
81 exit(0);
82 }
83
84 static void sighup_handler(void)
85 {
86 zlog_info("SIGHUP received");
87
88 /* Reload config file. */
89 vty_read_config(NULL, bfdd_di.config_file, config_default);
90 }
91
92 static struct frr_signal_t bfd_signals[] = {
93 {
94 .signal = SIGUSR1,
95 .handler = &sigusr1_handler,
96 },
97 {
98 .signal = SIGTERM,
99 .handler = &sigterm_handler,
100 },
101 {
102 .signal = SIGINT,
103 .handler = &sigterm_handler,
104 },
105 {
106 .signal = SIGHUP,
107 .handler = &sighup_handler,
108 },
109 };
110
111 static const struct frr_yang_module_info *const bfdd_yang_modules[] = {
112 &frr_filter_info,
113 &frr_interface_info,
114 &frr_bfdd_info,
115 &frr_vrf_info,
116 };
117
118 FRR_DAEMON_INFO(bfdd, BFD, .vty_port = 2617,
119 .proghelp = "Implementation of the BFD protocol.",
120 .signals = bfd_signals, .n_signals = array_size(bfd_signals),
121 .privs = &bglobal.bfdd_privs,
122 .yang_modules = bfdd_yang_modules,
123 .n_yang_modules = array_size(bfdd_yang_modules),
124 );
125
126 #define OPTION_CTLSOCK 1001
127 #define OPTION_DPLANEADDR 2000
128 static const struct option longopts[] = {
129 {"bfdctl", required_argument, NULL, OPTION_CTLSOCK},
130 {"dplaneaddr", required_argument, NULL, OPTION_DPLANEADDR},
131 {0}
132 };
133
134
135 /*
136 * BFD daemon related code.
137 */
138 struct bfd_global bglobal;
139
140 const struct bfd_diag_str_list diag_list[] = {
141 {.str = "control-expired", .type = BD_CONTROL_EXPIRED},
142 {.str = "echo-failed", .type = BD_ECHO_FAILED},
143 {.str = "neighbor-down", .type = BD_NEIGHBOR_DOWN},
144 {.str = "forwarding-reset", .type = BD_FORWARDING_RESET},
145 {.str = "path-down", .type = BD_PATH_DOWN},
146 {.str = "concatenated-path-down", .type = BD_CONCATPATH_DOWN},
147 {.str = "administratively-down", .type = BD_ADMIN_DOWN},
148 {.str = "reverse-concat-path-down", .type = BD_REVCONCATPATH_DOWN},
149 {.str = NULL},
150 };
151
152 const struct bfd_state_str_list state_list[] = {
153 {.str = "admin-down", .type = PTM_BFD_ADM_DOWN},
154 {.str = "down", .type = PTM_BFD_DOWN},
155 {.str = "init", .type = PTM_BFD_INIT},
156 {.str = "up", .type = PTM_BFD_UP},
157 {.str = NULL},
158 };
159
160 static uint16_t
161 parse_port(const char *str)
162 {
163 char *nulbyte;
164 long rv;
165
166 errno = 0;
167 rv = strtol(str, &nulbyte, 10);
168 /* No conversion performed. */
169 if (rv == 0 && errno == EINVAL) {
170 fprintf(stderr, "invalid BFD data plane address port: %s\n",
171 str);
172 exit(0);
173 }
174 /* Invalid number range. */
175 if ((rv <= 0 || rv >= 65535) || errno == ERANGE) {
176 fprintf(stderr, "invalid BFD data plane port range: %s\n",
177 str);
178 exit(0);
179 }
180 /* There was garbage at the end of the string. */
181 if (*nulbyte != 0) {
182 fprintf(stderr, "invalid BFD data plane port: %s\n",
183 str);
184 exit(0);
185 }
186
187 return (uint16_t)rv;
188 }
189
190 static void
191 distributed_bfd_init(const char *arg)
192 {
193 char *sptr, *saux;
194 bool is_client = false;
195 size_t slen;
196 socklen_t salen;
197 char addr[64];
198 char type[64];
199 union {
200 struct sockaddr_in sin;
201 struct sockaddr_in6 sin6;
202 struct sockaddr_un sun;
203 } sa;
204
205 /* Basic parsing: find ':' to figure out type part and address part. */
206 sptr = strchr(arg, ':');
207 if (sptr == NULL) {
208 fprintf(stderr, "invalid BFD data plane socket: %s\n", arg);
209 exit(1);
210 }
211
212 /* Calculate type string length. */
213 slen = (size_t)(sptr - arg);
214
215 /* Copy the address part. */
216 sptr++;
217 strlcpy(addr, sptr, sizeof(addr));
218
219 /* Copy type part. */
220 strlcpy(type, arg, slen + 1);
221
222 /* Reset address data. */
223 memset(&sa, 0, sizeof(sa));
224
225 /* Fill the address information. */
226 if (strcmp(type, "unix") == 0 || strcmp(type, "unixc") == 0) {
227 if (strcmp(type, "unixc") == 0)
228 is_client = true;
229
230 salen = sizeof(sa.sun);
231 sa.sun.sun_family = AF_UNIX;
232 strlcpy(sa.sun.sun_path, addr, sizeof(sa.sun.sun_path));
233 } else if (strcmp(type, "ipv4") == 0 || strcmp(type, "ipv4c") == 0) {
234 if (strcmp(type, "ipv4c") == 0)
235 is_client = true;
236
237 salen = sizeof(sa.sin);
238 sa.sin.sin_family = AF_INET;
239
240 /* Parse port if any. */
241 sptr = strchr(addr, ':');
242 if (sptr == NULL) {
243 sa.sin.sin_port = htons(BFD_DATA_PLANE_DEFAULT_PORT);
244 } else {
245 *sptr = 0;
246 sa.sin.sin_port = htons(parse_port(sptr + 1));
247 }
248
249 if (inet_pton(AF_INET, addr, &sa.sin.sin_addr) != 1)
250 errx(1, "%s: inet_pton: invalid address %s", __func__,
251 addr);
252 } else if (strcmp(type, "ipv6") == 0 || strcmp(type, "ipv6c") == 0) {
253 if (strcmp(type, "ipv6c") == 0)
254 is_client = true;
255
256 salen = sizeof(sa.sin6);
257 sa.sin6.sin6_family = AF_INET6;
258
259 /* Check for IPv6 enclosures '[]' */
260 sptr = &addr[0];
261 if (*sptr != '[')
262 errx(1, "%s: invalid IPv6 address format: %s", __func__,
263 addr);
264
265 saux = strrchr(addr, ']');
266 if (saux == NULL)
267 errx(1, "%s: invalid IPv6 address format: %s", __func__,
268 addr);
269
270 /* Consume the '[]:' part. */
271 slen = saux - sptr;
272 memmove(addr, addr + 1, slen);
273 addr[slen - 1] = 0;
274
275 /* Parse port if any. */
276 saux++;
277 sptr = strrchr(saux, ':');
278 if (sptr == NULL) {
279 sa.sin6.sin6_port = htons(BFD_DATA_PLANE_DEFAULT_PORT);
280 } else {
281 *sptr = 0;
282 sa.sin6.sin6_port = htons(parse_port(sptr + 1));
283 }
284
285 if (inet_pton(AF_INET6, addr, &sa.sin6.sin6_addr) != 1)
286 errx(1, "%s: inet_pton: invalid address %s", __func__,
287 addr);
288 } else {
289 fprintf(stderr, "invalid BFD data plane socket type: %s\n",
290 type);
291 exit(1);
292 }
293
294 /* Initialize BFD data plane listening socket. */
295 bfd_dplane_init((struct sockaddr *)&sa, salen, is_client);
296 }
297
298 static void bg_init(void)
299 {
300 struct zebra_privs_t bfdd_privs = {
301 #if defined(FRR_USER) && defined(FRR_GROUP)
302 .user = FRR_USER,
303 .group = FRR_GROUP,
304 #endif
305 #if defined(VTY_GROUP)
306 .vty_group = VTY_GROUP,
307 #endif
308 .caps_p = _caps_p,
309 .cap_num_p = array_size(_caps_p),
310 .cap_num_i = 0,
311 };
312
313 TAILQ_INIT(&bglobal.bg_bcslist);
314 TAILQ_INIT(&bglobal.bg_obslist);
315
316 memcpy(&bglobal.bfdd_privs, &bfdd_privs,
317 sizeof(bfdd_privs));
318 }
319
320 int main(int argc, char *argv[])
321 {
322 char ctl_path[512], dplane_addr[512];
323 bool ctlsockused = false;
324 int opt;
325
326 bglobal.bg_use_dplane = false;
327
328 /* Initialize system sockets. */
329 bg_init();
330
331 frr_preinit(&bfdd_di, argc, argv);
332 frr_opt_add("", longopts,
333 " --bfdctl Specify bfdd control socket\n"
334 " --dplaneaddr Specify BFD data plane address\n");
335
336 snprintf(ctl_path, sizeof(ctl_path), BFDD_CONTROL_SOCKET,
337 "", "");
338 while (true) {
339 opt = frr_getopt(argc, argv, NULL);
340 if (opt == EOF)
341 break;
342
343 switch (opt) {
344 case OPTION_CTLSOCK:
345 strlcpy(ctl_path, optarg, sizeof(ctl_path));
346 ctlsockused = true;
347 break;
348 case OPTION_DPLANEADDR:
349 strlcpy(dplane_addr, optarg, sizeof(dplane_addr));
350 bglobal.bg_use_dplane = true;
351 break;
352
353 default:
354 frr_help_exit(1);
355 }
356 }
357
358 if (bfdd_di.pathspace && !ctlsockused)
359 snprintf(ctl_path, sizeof(ctl_path), BFDD_CONTROL_SOCKET,
360 "/", bfdd_di.pathspace);
361
362 /* Initialize FRR infrastructure. */
363 master = frr_init();
364
365 /* Initialize control socket. */
366 control_init(ctl_path);
367
368 /* Initialize BFD data structures. */
369 bfd_initialize();
370
371 bfd_vrf_init();
372
373 access_list_init();
374
375 /* Initialize zebra connection. */
376 bfdd_zclient_init(&bglobal.bfdd_privs);
377
378 thread_add_read(master, control_accept, NULL, bglobal.bg_csock,
379 &bglobal.bg_csockev);
380
381 /* Install commands. */
382 bfdd_vty_init();
383
384 /* read configuration file and daemonize */
385 frr_config_fork();
386
387 /* Initialize BFD data plane listening socket. */
388 if (bglobal.bg_use_dplane)
389 distributed_bfd_init(dplane_addr);
390
391 frr_run(master);
392 /* NOTREACHED */
393
394 return 0;
395 }