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