1 // SPDX-License-Identifier: GPL-2.0-or-later
4 * Copyright (C) 2018 Network Device Education Foundation, Inc. ("NetDEF")
10 #include <netinet/in.h>
11 #include <sys/socket.h>
22 #include "bfddp_packet.h"
23 #include "lib/version.h"
24 #include "lib/command.h"
30 DEFINE_MGROUP(BFDD
, "Bidirectional Forwarding Detection Daemon");
31 DEFINE_MTYPE(BFDD
, BFDD_CONTROL
, "control socket memory");
32 DEFINE_MTYPE(BFDD
, BFDD_NOTIFICATION
, "control notification data");
34 /* Master of threads. */
35 struct event_loop
*master
;
38 static zebra_capabilities_t _caps_p
[] = {ZCAP_BIND
, ZCAP_SYS_ADMIN
, ZCAP_NET_RAW
};
40 /* BFD daemon information. */
41 static struct frr_daemon_info bfdd_di
;
43 void socket_close(int *s
)
49 zlog_err("%s: close(%d): (%d) %s", __func__
, *s
, errno
,
55 static void sigusr1_handler(void)
60 static void sigterm_handler(void)
62 bglobal
.bg_shutdown
= true;
64 /* Signalize shutdown. */
67 /* Stop receiving message from zebra. */
70 /* Shutdown controller to avoid receiving anymore commands. */
73 /* Shutdown and free all protocol related memory. */
78 /* Terminate and free() FRR related memory. */
84 static void sighup_handler(void)
86 zlog_info("SIGHUP received");
88 /* Reload config file. */
89 vty_read_config(NULL
, bfdd_di
.config_file
, config_default
);
92 static struct frr_signal_t bfd_signals
[] = {
95 .handler
= &sigusr1_handler
,
99 .handler
= &sigterm_handler
,
103 .handler
= &sigterm_handler
,
107 .handler
= &sighup_handler
,
111 static const struct frr_yang_module_info
*const bfdd_yang_modules
[] = {
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
),
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
},
136 * BFD daemon related code.
138 struct bfd_global bglobal
;
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
},
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
},
161 parse_port(const char *str
)
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",
174 /* Invalid number range. */
175 if ((rv
<= 0 || rv
>= 65535) || errno
== ERANGE
) {
176 fprintf(stderr
, "invalid BFD data plane port range: %s\n",
180 /* There was garbage at the end of the string. */
182 fprintf(stderr
, "invalid BFD data plane port: %s\n",
191 distributed_bfd_init(const char *arg
)
194 bool is_client
= false;
200 struct sockaddr_in sin
;
201 struct sockaddr_in6 sin6
;
202 struct sockaddr_un sun
;
205 /* Basic parsing: find ':' to figure out type part and address part. */
206 sptr
= strchr(arg
, ':');
208 fprintf(stderr
, "invalid BFD data plane socket: %s\n", arg
);
212 /* Calculate type string length. */
213 slen
= (size_t)(sptr
- arg
);
215 /* Copy the address part. */
217 strlcpy(addr
, sptr
, sizeof(addr
));
219 /* Copy type part. */
220 strlcpy(type
, arg
, slen
+ 1);
222 /* Reset address data. */
223 memset(&sa
, 0, sizeof(sa
));
225 /* Fill the address information. */
226 if (strcmp(type
, "unix") == 0 || strcmp(type
, "unixc") == 0) {
227 if (strcmp(type
, "unixc") == 0)
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)
237 salen
= sizeof(sa
.sin
);
238 sa
.sin
.sin_family
= AF_INET
;
240 /* Parse port if any. */
241 sptr
= strchr(addr
, ':');
243 sa
.sin
.sin_port
= htons(BFD_DATA_PLANE_DEFAULT_PORT
);
246 sa
.sin
.sin_port
= htons(parse_port(sptr
+ 1));
249 if (inet_pton(AF_INET
, addr
, &sa
.sin
.sin_addr
) != 1)
250 errx(1, "%s: inet_pton: invalid address %s", __func__
,
252 } else if (strcmp(type
, "ipv6") == 0 || strcmp(type
, "ipv6c") == 0) {
253 if (strcmp(type
, "ipv6c") == 0)
256 salen
= sizeof(sa
.sin6
);
257 sa
.sin6
.sin6_family
= AF_INET6
;
259 /* Check for IPv6 enclosures '[]' */
262 errx(1, "%s: invalid IPv6 address format: %s", __func__
,
265 saux
= strrchr(addr
, ']');
267 errx(1, "%s: invalid IPv6 address format: %s", __func__
,
270 /* Consume the '[]:' part. */
272 memmove(addr
, addr
+ 1, slen
);
275 /* Parse port if any. */
277 sptr
= strrchr(saux
, ':');
279 sa
.sin6
.sin6_port
= htons(BFD_DATA_PLANE_DEFAULT_PORT
);
282 sa
.sin6
.sin6_port
= htons(parse_port(sptr
+ 1));
285 if (inet_pton(AF_INET6
, addr
, &sa
.sin6
.sin6_addr
) != 1)
286 errx(1, "%s: inet_pton: invalid address %s", __func__
,
289 fprintf(stderr
, "invalid BFD data plane socket type: %s\n",
294 /* Initialize BFD data plane listening socket. */
295 bfd_dplane_init((struct sockaddr
*)&sa
, salen
, is_client
);
298 static void bg_init(void)
300 struct zebra_privs_t bfdd_privs
= {
301 #if defined(FRR_USER) && defined(FRR_GROUP)
305 #if defined(VTY_GROUP)
306 .vty_group
= VTY_GROUP
,
309 .cap_num_p
= array_size(_caps_p
),
313 TAILQ_INIT(&bglobal
.bg_bcslist
);
314 TAILQ_INIT(&bglobal
.bg_obslist
);
316 memcpy(&bglobal
.bfdd_privs
, &bfdd_privs
,
320 int main(int argc
, char *argv
[])
322 char ctl_path
[512], dplane_addr
[512];
323 bool ctlsockused
= false;
326 bglobal
.bg_use_dplane
= false;
328 /* Initialize system sockets. */
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");
336 snprintf(ctl_path
, sizeof(ctl_path
), BFDD_CONTROL_SOCKET
,
339 opt
= frr_getopt(argc
, argv
, NULL
);
345 strlcpy(ctl_path
, optarg
, sizeof(ctl_path
));
348 case OPTION_DPLANEADDR
:
349 strlcpy(dplane_addr
, optarg
, sizeof(dplane_addr
));
350 bglobal
.bg_use_dplane
= true;
358 if (bfdd_di
.pathspace
&& !ctlsockused
)
359 snprintf(ctl_path
, sizeof(ctl_path
), BFDD_CONTROL_SOCKET
,
360 "/", bfdd_di
.pathspace
);
362 /* Initialize FRR infrastructure. */
365 /* Initialize control socket. */
366 control_init(ctl_path
);
368 /* Initialize BFD data structures. */
375 /* Initialize zebra connection. */
376 bfdd_zclient_init(&bglobal
.bfdd_privs
);
378 event_add_read(master
, control_accept
, NULL
, bglobal
.bg_csock
,
379 &bglobal
.bg_csockev
);
381 /* Install commands. */
384 /* read configuration file and daemonize */
387 /* Initialize BFD data plane listening socket. */
388 if (bglobal
.bg_use_dplane
)
389 distributed_bfd_init(dplane_addr
);