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