3 * Copyright (C) 2018 Network Device Education Foundation, Inc. ("NetDEF")
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
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.
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
23 #include <arpa/inet.h>
24 #include <netinet/in.h>
25 #include <sys/socket.h>
36 #include "bfddp_packet.h"
37 #include "lib/version.h"
38 #include "lib/command.h"
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")
48 /* Master of threads. */
49 struct thread_master
*master
;
52 static zebra_capabilities_t _caps_p
[] = {ZCAP_BIND
, ZCAP_SYS_ADMIN
, ZCAP_NET_RAW
};
54 /* BFD daemon information. */
55 static struct frr_daemon_info bfdd_di
;
57 void socket_close(int *s
)
63 zlog_err("%s: close(%d): (%d) %s", __func__
, *s
, errno
,
69 static void sigusr1_handler(void)
74 static void sigterm_handler(void)
76 bglobal
.bg_shutdown
= true;
78 /* Signalize shutdown. */
81 /* Stop receiving message from zebra. */
84 /* Shutdown controller to avoid receiving anymore commands. */
87 /* Shutdown and free all protocol related memory. */
92 /* Terminate and free() FRR related memory. */
98 static void sighup_handler(void)
100 zlog_info("SIGHUP received");
102 /* Reload config file. */
103 vty_read_config(NULL
, bfdd_di
.config_file
, config_default
);
106 static struct quagga_signal_t bfd_signals
[] = {
109 .handler
= &sigusr1_handler
,
113 .handler
= &sigterm_handler
,
117 .handler
= &sigterm_handler
,
121 .handler
= &sighup_handler
,
125 static const struct frr_yang_module_info
*const bfdd_yang_modules
[] = {
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
))
139 #define OPTION_CTLSOCK 1001
140 #define OPTION_DPLANEADDR 2000
141 static const struct option longopts
[] = {
142 {"bfdctl", required_argument
, NULL
, OPTION_CTLSOCK
},
143 {"dplaneaddr", required_argument
, NULL
, OPTION_DPLANEADDR
},
149 * BFD daemon related code.
151 struct bfd_global bglobal
;
153 const struct bfd_diag_str_list diag_list
[] = {
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
},
165 const struct bfd_state_str_list state_list
[] = {
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
},
174 parse_port(const char *str
)
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",
187 /* Invalid number range. */
188 if ((rv
<= 0 || rv
>= 65535) || errno
== ERANGE
) {
189 fprintf(stderr
, "invalid BFD data plane port range: %s\n",
193 /* There was garbage at the end of the string. */
195 fprintf(stderr
, "invalid BFD data plane port: %s\n",
204 distributed_bfd_init(const char *arg
)
207 bool is_client
= false;
213 struct sockaddr_in sin
;
214 struct sockaddr_in6 sin6
;
215 struct sockaddr_un sun
;
218 /* Basic parsing: find ':' to figure out type part and address part. */
219 sptr
= strchr(arg
, ':');
221 fprintf(stderr
, "invalid BFD data plane socket: %s\n", arg
);
225 /* Calculate type string length. */
226 slen
= (size_t)(sptr
- arg
);
228 /* Copy the address part. */
230 strlcpy(addr
, sptr
, sizeof(addr
));
232 /* Copy type part. */
233 strlcpy(type
, arg
, slen
+ 1);
235 /* Reset address data. */
236 memset(&sa
, 0, sizeof(sa
));
238 /* Fill the address information. */
239 if (strcmp(type
, "unix") == 0 || strcmp(type
, "unixc") == 0) {
240 if (strcmp(type
, "unixc") == 0)
243 salen
= sizeof(sa
.sun
);
244 sa
.sun
.sun_family
= AF_UNIX
;
245 strlcpy(sa
.sun
.sun_path
, addr
, sizeof(sa
.sun
.sun_path
));
246 } else if (strcmp(type
, "ipv4") == 0 || strcmp(type
, "ipv4c") == 0) {
247 if (strcmp(type
, "ipv4c") == 0)
250 salen
= sizeof(sa
.sin
);
251 sa
.sin
.sin_family
= AF_INET
;
253 /* Parse port if any. */
254 sptr
= strchr(addr
, ':');
256 sa
.sin
.sin_port
= htons(BFD_DATA_PLANE_DEFAULT_PORT
);
259 sa
.sin
.sin_port
= htons(parse_port(sptr
+ 1));
262 if (inet_pton(AF_INET
, addr
, &sa
.sin
.sin_addr
) != 1)
263 errx(1, "%s: inet_pton: invalid address %s", __func__
,
265 } else if (strcmp(type
, "ipv6") == 0 || strcmp(type
, "ipv6c") == 0) {
266 if (strcmp(type
, "ipv6c") == 0)
269 salen
= sizeof(sa
.sin6
);
270 sa
.sin6
.sin6_family
= AF_INET6
;
272 /* Check for IPv6 enclosures '[]' */
275 errx(1, "%s: invalid IPv6 address format: %s", __func__
,
278 saux
= strrchr(addr
, ']');
280 errx(1, "%s: invalid IPv6 address format: %s", __func__
,
283 /* Consume the '[]:' part. */
285 memmove(addr
, addr
+ 1, slen
);
288 /* Parse port if any. */
290 sptr
= strrchr(saux
, ':');
292 sa
.sin6
.sin6_port
= htons(BFD_DATA_PLANE_DEFAULT_PORT
);
295 sa
.sin6
.sin6_port
= htons(parse_port(sptr
+ 1));
298 if (inet_pton(AF_INET6
, addr
, &sa
.sin6
.sin6_addr
) != 1)
299 errx(1, "%s: inet_pton: invalid address %s", __func__
,
302 fprintf(stderr
, "invalid BFD data plane socket type: %s\n",
307 /* Initialize BFD data plane listening socket. */
308 bfd_dplane_init((struct sockaddr
*)&sa
, salen
, is_client
);
311 static void bg_init(void)
313 struct zebra_privs_t bfdd_privs
= {
314 #if defined(FRR_USER) && defined(FRR_GROUP)
318 #if defined(VTY_GROUP)
319 .vty_group
= VTY_GROUP
,
322 .cap_num_p
= array_size(_caps_p
),
326 TAILQ_INIT(&bglobal
.bg_bcslist
);
327 TAILQ_INIT(&bglobal
.bg_obslist
);
329 memcpy(&bglobal
.bfdd_privs
, &bfdd_privs
,
333 int main(int argc
, char *argv
[])
335 char ctl_path
[512], dplane_addr
[512];
336 bool ctlsockused
= false;
339 /* Initialize system sockets. */
342 frr_preinit(&bfdd_di
, argc
, argv
);
343 frr_opt_add("", longopts
,
344 " --bfdctl Specify bfdd control socket\n"
345 " --dplaneaddr Specify BFD data plane address\n");
347 snprintf(ctl_path
, sizeof(ctl_path
), BFDD_CONTROL_SOCKET
,
350 opt
= frr_getopt(argc
, argv
, NULL
);
356 strlcpy(ctl_path
, optarg
, sizeof(ctl_path
));
359 case OPTION_DPLANEADDR
:
360 strlcpy(dplane_addr
, optarg
, sizeof(dplane_addr
));
361 bglobal
.bg_use_dplane
= true;
370 if (bfdd_di
.pathspace
&& !ctlsockused
)
371 snprintf(ctl_path
, sizeof(ctl_path
), BFDD_CONTROL_SOCKET
,
372 "/", bfdd_di
.pathspace
);
374 /* Initialize FRR infrastructure. */
377 /* Initialize control socket. */
378 control_init(ctl_path
);
380 /* Initialize BFD data structures. */
387 /* Initialize zebra connection. */
388 bfdd_zclient_init(&bglobal
.bfdd_privs
);
390 thread_add_read(master
, control_accept
, NULL
, bglobal
.bg_csock
,
391 &bglobal
.bg_csockev
);
393 /* Install commands. */
396 /* read configuration file and daemonize */
399 /* Initialize BFD data plane listening socket. */
400 if (bglobal
.bg_use_dplane
)
401 distributed_bfd_init(dplane_addr
);