]> git.proxmox.com Git - mirror_frr.git/blame - bfdd/bfdd.c
Merge pull request #12798 from donaldsharp/rib_match_multicast
[mirror_frr.git] / bfdd / bfdd.c
CommitLineData
acddc0ed 1// SPDX-License-Identifier: GPL-2.0-or-later
e9e2c950
RZ
2/*
3 * BFD daemon code
4 * Copyright (C) 2018 Network Device Education Foundation, Inc. ("NetDEF")
e9e2c950
RZ
5 */
6
7#include <zebra.h>
8
230aefe2
RZ
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
9f95a33a 16#include "filter.h"
463d46a3
IR
17#include "if.h"
18#include "vrf.h"
9f95a33a 19
e9e2c950 20#include "bfd.h"
6c574029 21#include "bfdd_nb.h"
230aefe2 22#include "bfddp_packet.h"
e9e2c950 23#include "lib/version.h"
0bdeb5e5 24#include "lib/command.h"
6ed84949 25
e9e2c950
RZ
26
27/*
28 * FRR related code.
29 */
bf8d3d6a
DL
30DEFINE_MGROUP(BFDD, "Bidirectional Forwarding Detection Daemon");
31DEFINE_MTYPE(BFDD, BFDD_CONTROL, "long-lived control socket memory");
32DEFINE_MTYPE(BFDD, BFDD_NOTIFICATION, "short-lived control notification data");
e9e2c950
RZ
33
34/* Master of threads. */
35struct thread_master *master;
36
37/* BFDd privileges */
4e6b48d3 38static zebra_capabilities_t _caps_p[] = {ZCAP_BIND, ZCAP_SYS_ADMIN, ZCAP_NET_RAW};
e9e2c950 39
49cc9e7b
RZ
40/* BFD daemon information. */
41static struct frr_daemon_info bfdd_di;
42
e9e2c950
RZ
43void socket_close(int *s)
44{
45 if (*s <= 0)
46 return;
47
48 if (close(*s) != 0)
259b64eb
RZ
49 zlog_err("%s: close(%d): (%d) %s", __func__, *s, errno,
50 strerror(errno));
e9e2c950
RZ
51
52 *s = -1;
53}
54
55static void sigusr1_handler(void)
56{
57 zlog_rotate();
58}
59
60static void sigterm_handler(void)
61{
f3e1d224
RZ
62 bglobal.bg_shutdown = true;
63
e9e2c950
RZ
64 /* Signalize shutdown. */
65 frr_early_fini();
66
d3af6147
RZ
67 /* Stop receiving message from zebra. */
68 bfdd_zclient_stop();
69
e9e2c950
RZ
70 /* Shutdown controller to avoid receiving anymore commands. */
71 control_shutdown();
72
73 /* Shutdown and free all protocol related memory. */
74 bfd_shutdown();
75
7bcadbae 76 bfd_vrf_terminate();
e9e2c950
RZ
77
78 /* Terminate and free() FRR related memory. */
79 frr_fini();
80
81 exit(0);
82}
83
49cc9e7b
RZ
84static 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
7cc91e67 92static struct frr_signal_t bfd_signals[] = {
e9e2c950
RZ
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 },
49cc9e7b
RZ
105 {
106 .signal = SIGHUP,
107 .handler = &sighup_handler,
108 },
e9e2c950
RZ
109};
110
0d8c7a26 111static const struct frr_yang_module_info *const bfdd_yang_modules[] = {
c2aab693 112 &frr_filter_info,
adc26455
RZ
113 &frr_interface_info,
114 &frr_bfdd_info,
6fd8972a 115 &frr_vrf_info,
adc26455
RZ
116};
117
e9e2c950
RZ
118FRR_DAEMON_INFO(bfdd, BFD, .vty_port = 2617,
119 .proghelp = "Implementation of the BFD protocol.",
120 .signals = bfd_signals, .n_signals = array_size(bfd_signals),
adc26455
RZ
121 .privs = &bglobal.bfdd_privs,
122 .yang_modules = bfdd_yang_modules,
80413c20
DL
123 .n_yang_modules = array_size(bfdd_yang_modules),
124);
e9e2c950
RZ
125
126#define OPTION_CTLSOCK 1001
230aefe2 127#define OPTION_DPLANEADDR 2000
2b64873d 128static const struct option longopts[] = {
e9e2c950 129 {"bfdctl", required_argument, NULL, OPTION_CTLSOCK},
230aefe2 130 {"dplaneaddr", required_argument, NULL, OPTION_DPLANEADDR},
e9e2c950
RZ
131 {0}
132};
133
134
135/*
136 * BFD daemon related code.
137 */
138struct bfd_global bglobal;
139
2b64873d 140const struct bfd_diag_str_list diag_list[] = {
40675ea9
RZ
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},
e9e2c950
RZ
149 {.str = NULL},
150};
151
2b64873d 152const struct bfd_state_str_list state_list[] = {
40675ea9
RZ
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},
e9e2c950
RZ
157 {.str = NULL},
158};
159
230aefe2
RZ
160static uint16_t
161parse_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
190static void
191distributed_bfd_init(const char *arg)
192{
193 char *sptr, *saux;
6655b43d 194 bool is_client = false;
230aefe2
RZ
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. */
6655b43d
RZ
226 if (strcmp(type, "unix") == 0 || strcmp(type, "unixc") == 0) {
227 if (strcmp(type, "unixc") == 0)
228 is_client = true;
229
230aefe2
RZ
230 salen = sizeof(sa.sun);
231 sa.sun.sun_family = AF_UNIX;
232 strlcpy(sa.sun.sun_path, addr, sizeof(sa.sun.sun_path));
6655b43d
RZ
233 } else if (strcmp(type, "ipv4") == 0 || strcmp(type, "ipv4c") == 0) {
234 if (strcmp(type, "ipv4c") == 0)
235 is_client = true;
236
230aefe2
RZ
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);
6655b43d
RZ
252 } else if (strcmp(type, "ipv6") == 0 || strcmp(type, "ipv6c") == 0) {
253 if (strcmp(type, "ipv6c") == 0)
254 is_client = true;
255
230aefe2
RZ
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. */
6655b43d 295 bfd_dplane_init((struct sockaddr *)&sa, salen, is_client);
230aefe2 296}
e9e2c950
RZ
297
298static void bg_init(void)
299{
f21536d2
PG
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
e9e2c950 313 TAILQ_INIT(&bglobal.bg_bcslist);
d245e522 314 TAILQ_INIT(&bglobal.bg_obslist);
f21536d2
PG
315
316 memcpy(&bglobal.bfdd_privs, &bfdd_privs,
317 sizeof(bfdd_privs));
e9e2c950
RZ
318}
319
320int main(int argc, char *argv[])
321{
230aefe2 322 char ctl_path[512], dplane_addr[512];
89277ebf 323 bool ctlsockused = false;
e9e2c950
RZ
324 int opt;
325
e51c0f77
DS
326 bglobal.bg_use_dplane = false;
327
f21536d2
PG
328 /* Initialize system sockets. */
329 bg_init();
330
e9e2c950
RZ
331 frr_preinit(&bfdd_di, argc, argv);
332 frr_opt_add("", longopts,
230aefe2
RZ
333 " --bfdctl Specify bfdd control socket\n"
334 " --dplaneaddr Specify BFD data plane address\n");
e9e2c950 335
89277ebf
DS
336 snprintf(ctl_path, sizeof(ctl_path), BFDD_CONTROL_SOCKET,
337 "", "");
e9e2c950
RZ
338 while (true) {
339 opt = frr_getopt(argc, argv, NULL);
340 if (opt == EOF)
341 break;
342
343 switch (opt) {
344 case OPTION_CTLSOCK:
89277ebf
DS
345 strlcpy(ctl_path, optarg, sizeof(ctl_path));
346 ctlsockused = true;
e9e2c950 347 break;
230aefe2
RZ
348 case OPTION_DPLANEADDR:
349 strlcpy(dplane_addr, optarg, sizeof(dplane_addr));
350 bglobal.bg_use_dplane = true;
351 break;
e9e2c950
RZ
352
353 default:
354 frr_help_exit(1);
e9e2c950
RZ
355 }
356 }
357
89277ebf
DS
358 if (bfdd_di.pathspace && !ctlsockused)
359 snprintf(ctl_path, sizeof(ctl_path), BFDD_CONTROL_SOCKET,
360 "/", bfdd_di.pathspace);
361
d85b048d
DL
362 /* Initialize FRR infrastructure. */
363 master = frr_init();
e9e2c950 364
e9e2c950
RZ
365 /* Initialize control socket. */
366 control_init(ctl_path);
367
e9e2c950
RZ
368 /* Initialize BFD data structures. */
369 bfd_initialize();
370
9fc0bc5c
PG
371 bfd_vrf_init();
372
9f95a33a
DS
373 access_list_init();
374
d3af6147 375 /* Initialize zebra connection. */
f21536d2 376 bfdd_zclient_init(&bglobal.bfdd_privs);
d3af6147 377
e9e2c950
RZ
378 thread_add_read(master, control_accept, NULL, bglobal.bg_csock,
379 &bglobal.bg_csockev);
380
c2f29cf3
RZ
381 /* Install commands. */
382 bfdd_vty_init();
383
e9e2c950
RZ
384 /* read configuration file and daemonize */
385 frr_config_fork();
386
230aefe2
RZ
387 /* Initialize BFD data plane listening socket. */
388 if (bglobal.bg_use_dplane)
389 distributed_bfd_init(dplane_addr);
390
e9e2c950
RZ
391 frr_run(master);
392 /* NOTREACHED */
393
394 return 0;
395}