]> git.proxmox.com Git - mirror_frr.git/blob - lib/bfd.c
Merge pull request #6243 from pguibert6WIND/flowspec_some_regression_seen
[mirror_frr.git] / lib / bfd.c
1 /**
2 * bfd.c: BFD handling routines
3 *
4 * @copyright Copyright (C) 2015 Cumulus Networks, Inc.
5 *
6 * This file is part of GNU Zebra.
7 *
8 * GNU Zebra is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2, or (at your option) any
11 * later version.
12 *
13 * GNU Zebra is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; see the file COPYING; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23 #include <zebra.h>
24
25 #include "command.h"
26 #include "memory.h"
27 #include "prefix.h"
28 #include "thread.h"
29 #include "stream.h"
30 #include "zclient.h"
31 #include "table.h"
32 #include "vty.h"
33 #include "bfd.h"
34
35 DEFINE_MTYPE_STATIC(LIB, BFD_INFO, "BFD info")
36
37 static int bfd_debug = 0;
38 static struct bfd_gbl bfd_gbl;
39
40 /*
41 * bfd_gbl_init - Initialize the BFD global structure
42 */
43 void bfd_gbl_init(void)
44 {
45 memset(&bfd_gbl, 0, sizeof(struct bfd_gbl));
46 }
47
48 /*
49 * bfd_gbl_exit - Called when daemon exits
50 */
51 void bfd_gbl_exit(void)
52 {
53 SET_FLAG(bfd_gbl.flags, BFD_GBL_FLAG_IN_SHUTDOWN);
54 }
55
56 /*
57 * bfd_info_create - Allocate the BFD information
58 */
59 struct bfd_info *bfd_info_create(void)
60 {
61 struct bfd_info *bfd_info;
62
63 bfd_info = XCALLOC(MTYPE_BFD_INFO, sizeof(struct bfd_info));
64 assert(bfd_info);
65
66 bfd_info->status = BFD_STATUS_UNKNOWN;
67 bfd_info->type = BFD_TYPE_NOT_CONFIGURED;
68 bfd_info->last_update = 0;
69 return bfd_info;
70 }
71
72 /*
73 * bfd_info_free - Free the BFD information.
74 */
75 void bfd_info_free(struct bfd_info **bfd_info)
76 {
77 XFREE(MTYPE_BFD_INFO, *bfd_info);
78 }
79
80 /*
81 * bfd_validate_param - Validate the BFD paramter information.
82 */
83 int bfd_validate_param(struct vty *vty, const char *dm_str, const char *rx_str,
84 const char *tx_str, uint8_t *dm_val, uint32_t *rx_val,
85 uint32_t *tx_val)
86 {
87 *dm_val = strtoul(dm_str, NULL, 10);
88 *rx_val = strtoul(rx_str, NULL, 10);
89 *tx_val = strtoul(tx_str, NULL, 10);
90 return CMD_SUCCESS;
91 }
92
93 /*
94 * bfd_set_param - Set the configured BFD paramter values
95 */
96 void bfd_set_param(struct bfd_info **bfd_info, uint32_t min_rx, uint32_t min_tx,
97 uint8_t detect_mult, const char *profile, int defaults,
98 int *command)
99 {
100 if (!*bfd_info) {
101 *bfd_info = bfd_info_create();
102 *command = ZEBRA_BFD_DEST_REGISTER;
103 } else {
104 if (((*bfd_info)->required_min_rx != min_rx)
105 || ((*bfd_info)->desired_min_tx != min_tx)
106 || ((*bfd_info)->detect_mult != detect_mult)
107 || (profile && strcmp((*bfd_info)->profile, profile)))
108 *command = ZEBRA_BFD_DEST_UPDATE;
109 }
110
111 if (*command) {
112 (*bfd_info)->required_min_rx = min_rx;
113 (*bfd_info)->desired_min_tx = min_tx;
114 (*bfd_info)->detect_mult = detect_mult;
115 if (profile)
116 strlcpy((*bfd_info)->profile, profile,
117 BFD_PROFILE_NAME_LEN);
118 else
119 (*bfd_info)->profile[0] = '\0';
120 }
121
122 if (!defaults)
123 SET_FLAG((*bfd_info)->flags, BFD_FLAG_PARAM_CFG);
124 else
125 UNSET_FLAG((*bfd_info)->flags, BFD_FLAG_PARAM_CFG);
126 }
127
128 /*
129 * bfd_peer_sendmsg - Format and send a peer register/Unregister
130 * command to Zebra to be forwarded to BFD
131 *
132 * DEPRECATED: use zclient_bfd_command instead
133 */
134 void bfd_peer_sendmsg(struct zclient *zclient, struct bfd_info *bfd_info,
135 int family, void *dst_ip, void *src_ip, char *if_name,
136 int ttl, int multihop, int cbit, int command,
137 int set_flag, vrf_id_t vrf_id)
138 {
139 struct bfd_session_arg args = {};
140 size_t addrlen;
141
142 /* Individual reg/dereg messages are suppressed during shutdown. */
143 if (CHECK_FLAG(bfd_gbl.flags, BFD_GBL_FLAG_IN_SHUTDOWN)) {
144 if (bfd_debug)
145 zlog_debug(
146 "%s: Suppressing BFD peer reg/dereg messages",
147 __func__);
148 return;
149 }
150
151 /* Check socket. */
152 if (!zclient || zclient->sock < 0) {
153 if (bfd_debug)
154 zlog_debug(
155 "%s: Can't send BFD peer register, Zebra client not established",
156 __func__);
157 return;
158 }
159
160 /* Fill in all arguments. */
161 args.ttl = ttl;
162 args.cbit = cbit;
163 args.family = family;
164 args.mhop = multihop;
165 args.vrf_id = vrf_id;
166 args.command = command;
167 args.set_flag = set_flag;
168 args.bfd_info = bfd_info;
169 if (args.bfd_info) {
170 args.min_rx = bfd_info->required_min_rx;
171 args.min_tx = bfd_info->desired_min_tx;
172 args.detection_multiplier = bfd_info->detect_mult;
173 if (bfd_info->profile[0]) {
174 args.profilelen = strlen(bfd_info->profile);
175 strlcpy(args.profile, bfd_info->profile,
176 sizeof(args.profile));
177 }
178 }
179
180 addrlen = family == AF_INET ? sizeof(struct in_addr)
181 : sizeof(struct in6_addr);
182 memcpy(&args.dst, dst_ip, addrlen);
183 if (src_ip)
184 memcpy(&args.src, src_ip, addrlen);
185
186 if (if_name)
187 args.ifnamelen =
188 strlcpy(args.ifname, if_name, sizeof(args.ifname));
189
190 zclient_bfd_command(zclient, &args);
191 }
192
193 /*
194 * bfd_get_command_dbg_str - Convert command to a debug string.
195 */
196 const char *bfd_get_command_dbg_str(int command)
197 {
198 switch (command) {
199 case ZEBRA_BFD_DEST_REGISTER:
200 return "Register";
201 case ZEBRA_BFD_DEST_DEREGISTER:
202 return "Deregister";
203 case ZEBRA_BFD_DEST_UPDATE:
204 return "Update";
205 default:
206 return "Unknown";
207 }
208 }
209
210 /*
211 * bfd_get_peer_info - Extract the Peer information for which the BFD session
212 * went down from the message sent from Zebra to clients.
213 */
214 struct interface *bfd_get_peer_info(struct stream *s, struct prefix *dp,
215 struct prefix *sp, int *status,
216 int *remote_cbit,
217 vrf_id_t vrf_id)
218 {
219 unsigned int ifindex;
220 struct interface *ifp = NULL;
221 int plen;
222 int local_remote_cbit;
223
224 /* Get interface index. */
225 ifindex = stream_getl(s);
226
227 /* Lookup index. */
228 if (ifindex != 0) {
229 ifp = if_lookup_by_index(ifindex, vrf_id);
230 if (ifp == NULL) {
231 if (bfd_debug)
232 zlog_debug(
233 "zebra_interface_bfd_read: Can't find interface by ifindex: %d ",
234 ifindex);
235 return NULL;
236 }
237 }
238
239 /* Fetch destination address. */
240 dp->family = stream_getc(s);
241
242 plen = prefix_blen(dp);
243 stream_get(&dp->u.prefix, s, plen);
244 dp->prefixlen = stream_getc(s);
245
246 /* Get BFD status. */
247 *status = stream_getl(s);
248
249 if (sp) {
250 sp->family = stream_getc(s);
251
252 plen = prefix_blen(sp);
253 stream_get(&sp->u.prefix, s, plen);
254 sp->prefixlen = stream_getc(s);
255 }
256 local_remote_cbit = stream_getc(s);
257 if (remote_cbit)
258 *remote_cbit = local_remote_cbit;
259 return ifp;
260 }
261
262 /*
263 * bfd_get_status_str - Convert BFD status to a display string.
264 */
265 const char *bfd_get_status_str(int status)
266 {
267 switch (status) {
268 case BFD_STATUS_DOWN:
269 return "Down";
270 case BFD_STATUS_UP:
271 return "Up";
272 case BFD_STATUS_ADMIN_DOWN:
273 return "Admin Down";
274 case BFD_STATUS_UNKNOWN:
275 default:
276 return "Unknown";
277 }
278 }
279
280 /*
281 * bfd_last_update - Calculate the last BFD update time and convert it
282 * into a dd:hh:mm:ss display format.
283 */
284 static void bfd_last_update(time_t last_update, char *buf, size_t len)
285 {
286 time_t curr;
287 time_t diff;
288 struct tm tm;
289 struct timeval tv;
290
291 /* If no BFD satatus update has ever been received, print `never'. */
292 if (last_update == 0) {
293 snprintf(buf, len, "never");
294 return;
295 }
296
297 /* Get current time. */
298 monotime(&tv);
299 curr = tv.tv_sec;
300 diff = curr - last_update;
301 gmtime_r(&diff, &tm);
302
303 snprintf(buf, len, "%d:%02d:%02d:%02d", tm.tm_yday, tm.tm_hour,
304 tm.tm_min, tm.tm_sec);
305 }
306
307 /*
308 * bfd_show_param - Show the BFD parameter information.
309 */
310 void bfd_show_param(struct vty *vty, struct bfd_info *bfd_info, int bfd_tag,
311 int extra_space, bool use_json, json_object *json_obj)
312 {
313 json_object *json_bfd = NULL;
314
315 if (!bfd_info)
316 return;
317
318 if (use_json) {
319 if (bfd_tag)
320 json_bfd = json_object_new_object();
321 else
322 json_bfd = json_obj;
323
324 json_object_int_add(json_bfd, "detectMultiplier",
325 bfd_info->detect_mult);
326 json_object_int_add(json_bfd, "rxMinInterval",
327 bfd_info->required_min_rx);
328 json_object_int_add(json_bfd, "txMinInterval",
329 bfd_info->desired_min_tx);
330 if (bfd_tag)
331 json_object_object_add(json_obj, "peerBfdInfo",
332 json_bfd);
333 } else {
334 vty_out(vty,
335 " %s%sDetect Multiplier: %d, Min Rx interval: %d, Min Tx interval: %d\n",
336 (extra_space) ? " " : "", (bfd_tag) ? "BFD: " : " ",
337 bfd_info->detect_mult, bfd_info->required_min_rx,
338 bfd_info->desired_min_tx);
339 }
340 }
341
342 /*
343 * bfd_show_status - Show the BFD status information.
344 */
345 static void bfd_show_status(struct vty *vty, struct bfd_info *bfd_info,
346 int bfd_tag, int extra_space, bool use_json,
347 json_object *json_bfd)
348 {
349 char time_buf[32];
350
351 if (!bfd_info)
352 return;
353
354 bfd_last_update(bfd_info->last_update, time_buf, 32);
355 if (use_json) {
356 json_object_string_add(json_bfd, "status",
357 bfd_get_status_str(bfd_info->status));
358 json_object_string_add(json_bfd, "lastUpdate", time_buf);
359 } else {
360 vty_out(vty, " %s%sStatus: %s, Last update: %s\n",
361 (extra_space) ? " " : "", (bfd_tag) ? "BFD: " : " ",
362 bfd_get_status_str(bfd_info->status), time_buf);
363 }
364 }
365
366 /*
367 * bfd_show_info - Show the BFD information.
368 */
369 void bfd_show_info(struct vty *vty, struct bfd_info *bfd_info, int multihop,
370 int extra_space, bool use_json, json_object *json_obj)
371 {
372 json_object *json_bfd = NULL;
373
374 if (!bfd_info)
375 return;
376
377 if (use_json) {
378 json_bfd = json_object_new_object();
379 if (multihop)
380 json_object_string_add(json_bfd, "type", "multi hop");
381 else
382 json_object_string_add(json_bfd, "type", "single hop");
383 } else {
384 vty_out(vty, " %sBFD: Type: %s\n", (extra_space) ? " " : "",
385 (multihop) ? "multi hop" : "single hop");
386 }
387
388 bfd_show_param(vty, bfd_info, 0, extra_space, use_json, json_bfd);
389 bfd_show_status(vty, bfd_info, 0, extra_space, use_json, json_bfd);
390
391 if (use_json)
392 json_object_object_add(json_obj, "peerBfdInfo", json_bfd);
393 else
394 vty_out(vty, "\n");
395 }
396
397 /*
398 * bfd_client_sendmsg - Format and send a client register
399 * command to Zebra to be forwarded to BFD
400 */
401 void bfd_client_sendmsg(struct zclient *zclient, int command,
402 vrf_id_t vrf_id)
403 {
404 struct stream *s;
405 int ret;
406
407 /* Check socket. */
408 if (!zclient || zclient->sock < 0) {
409 if (bfd_debug)
410 zlog_debug(
411 "%s: Can't send BFD client register, Zebra client not established",
412 __func__);
413 return;
414 }
415
416 s = zclient->obuf;
417 stream_reset(s);
418 zclient_create_header(s, command, vrf_id);
419
420 stream_putl(s, getpid());
421
422 stream_putw_at(s, 0, stream_get_endp(s));
423
424 ret = zclient_send_message(zclient);
425
426 if (ret < 0) {
427 if (bfd_debug)
428 zlog_debug(
429 "bfd_client_sendmsg %ld: zclient_send_message() failed",
430 (long)getpid());
431 return;
432 }
433
434 return;
435 }
436
437 int zclient_bfd_command(struct zclient *zc, struct bfd_session_arg *args)
438 {
439 struct stream *s;
440 size_t addrlen;
441
442 /* Individual reg/dereg messages are suppressed during shutdown. */
443 if (CHECK_FLAG(bfd_gbl.flags, BFD_GBL_FLAG_IN_SHUTDOWN)) {
444 if (bfd_debug)
445 zlog_debug(
446 "%s: Suppressing BFD peer reg/dereg messages",
447 __func__);
448 return -1;
449 }
450
451 /* Check socket. */
452 if (!zc || zc->sock < 0) {
453 if (bfd_debug)
454 zlog_debug("%s: zclient unavailable", __func__);
455 return -1;
456 }
457
458 s = zc->obuf;
459 stream_reset(s);
460
461 /* Create new message. */
462 zclient_create_header(s, args->command, args->vrf_id);
463 stream_putl(s, getpid());
464
465 /* Encode destination address. */
466 stream_putw(s, args->family);
467 addrlen = (args->family == AF_INET) ? sizeof(struct in_addr)
468 : sizeof(struct in6_addr);
469 stream_put(s, &args->dst, addrlen);
470
471 /* Encode timers if this is a registration message. */
472 if (args->command != ZEBRA_BFD_DEST_DEREGISTER) {
473 stream_putl(s, args->min_rx);
474 stream_putl(s, args->min_tx);
475 stream_putc(s, args->detection_multiplier);
476 }
477
478 if (args->mhop) {
479 /* Multi hop indicator. */
480 stream_putc(s, 1);
481
482 /* Multi hop always sends the source address. */
483 stream_putw(s, args->family);
484 stream_put(s, &args->src, addrlen);
485
486 /* Send the expected TTL. */
487 stream_putc(s, args->ttl);
488 } else {
489 /* Multi hop indicator. */
490 stream_putc(s, 0);
491
492 /* Single hop only sends the source address when IPv6. */
493 if (args->family == AF_INET6) {
494 stream_putw(s, args->family);
495 stream_put(s, &args->src, addrlen);
496 }
497
498 /* Send interface name if any. */
499 stream_putc(s, args->ifnamelen);
500 if (args->ifnamelen)
501 stream_put(s, args->ifname, args->ifnamelen);
502 }
503
504 /* Send the C bit indicator. */
505 stream_putc(s, args->cbit);
506
507 /* `ptm-bfd` doesn't support profiles yet. */
508 #if HAVE_BFDD > 0
509 /* Send profile name if any. */
510 stream_putc(s, args->profilelen);
511 if (args->profilelen)
512 stream_put(s, args->profile, args->profilelen);
513 #endif /* HAVE_BFDD */
514
515 /* Finish the message by writing the size. */
516 stream_putw_at(s, 0, stream_get_endp(s));
517
518 /* Send message to zebra. */
519 if (zclient_send_message(zc) == -1) {
520 if (bfd_debug)
521 zlog_debug("%s: zclient_send_message failed", __func__);
522 return -1;
523 }
524
525 /* Write registration indicator into data structure. */
526 if (args->bfd_info && args->set_flag) {
527 if (args->command == ZEBRA_BFD_DEST_REGISTER)
528 SET_FLAG(args->bfd_info->flags, BFD_FLAG_BFD_REG);
529 else if (args->command == ZEBRA_BFD_DEST_DEREGISTER)
530 UNSET_FLAG(args->bfd_info->flags, BFD_FLAG_BFD_REG);
531 }
532
533 return 0;
534 }