]> git.proxmox.com Git - mirror_frr.git/blob - bfdd/bfdd_vty.c
Merge pull request #10135 from donaldsharp/ripng_faster_timers
[mirror_frr.git] / bfdd / bfdd_vty.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 "lib/command.h"
24 #include "lib/json.h"
25 #include "lib/log.h"
26 #include "lib/northbound_cli.h"
27 #include "lib/vty.h"
28
29 #include "bfd.h"
30
31 #ifndef VTYSH_EXTRACT_PL
32 #include "bfdd/bfdd_vty_clippy.c"
33 #endif
34
35 /*
36 * Commands help string definitions.
37 */
38 #define PEER_IPV4_STR "IPv4 peer address\n"
39 #define PEER_IPV6_STR "IPv6 peer address\n"
40 #define MHOP_STR "Configure multihop\n"
41 #define LOCAL_STR "Configure local address\n"
42 #define LOCAL_IPV4_STR "IPv4 local address\n"
43 #define LOCAL_IPV6_STR "IPv6 local address\n"
44 #define LOCAL_INTF_STR "Configure local interface name to use\n"
45
46 /*
47 * Prototypes
48 */
49 static int bfd_configure_peer(struct bfd_peer_cfg *bpc, bool mhop,
50 const struct sockaddr_any *peer,
51 const struct sockaddr_any *local,
52 const char *ifname, const char *vrfname,
53 char *ebuf, size_t ebuflen);
54
55 static void _display_peer_header(struct vty *vty, struct bfd_session *bs);
56 static struct json_object *__display_peer_json(struct bfd_session *bs);
57 static struct json_object *_peer_json_header(struct bfd_session *bs);
58 static void _display_peer_json(struct vty *vty, struct bfd_session *bs);
59 static void _display_peer(struct vty *vty, struct bfd_session *bs);
60 static void _display_all_peers(struct vty *vty, char *vrfname, bool use_json);
61 static void _display_peer_iter(struct hash_bucket *hb, void *arg);
62 static void _display_peer_json_iter(struct hash_bucket *hb, void *arg);
63 static void _display_peer_counter(struct vty *vty, struct bfd_session *bs);
64 static struct json_object *__display_peer_counters_json(struct bfd_session *bs);
65 static void _display_peer_counters_json(struct vty *vty, struct bfd_session *bs);
66 static void _display_peer_counter_iter(struct hash_bucket *hb, void *arg);
67 static void _display_peer_counter_json_iter(struct hash_bucket *hb, void *arg);
68 static void _display_peers_counter(struct vty *vty, char *vrfname, bool use_json);
69 static struct bfd_session *
70 _find_peer_or_error(struct vty *vty, int argc, struct cmd_token **argv,
71 const char *label, const char *peer_str,
72 const char *local_str, const char *ifname,
73 const char *vrfname);
74
75
76 /*
77 * Show commands helper functions
78 */
79 static void _display_peer_header(struct vty *vty, struct bfd_session *bs)
80 {
81 char addr_buf[INET6_ADDRSTRLEN];
82
83 vty_out(vty, "\tpeer %s",
84 inet_ntop(bs->key.family, &bs->key.peer, addr_buf,
85 sizeof(addr_buf)));
86
87 if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH))
88 vty_out(vty, " multihop");
89
90 if (memcmp(&bs->key.local, &zero_addr, sizeof(bs->key.local)))
91 vty_out(vty, " local-address %s",
92 inet_ntop(bs->key.family, &bs->key.local, addr_buf,
93 sizeof(addr_buf)));
94
95 if (bs->key.vrfname[0])
96 vty_out(vty, " vrf %s", bs->key.vrfname);
97 if (bs->key.ifname[0])
98 vty_out(vty, " interface %s", bs->key.ifname);
99 vty_out(vty, "\n");
100
101 if (bs->pl)
102 vty_out(vty, "\t\tlabel: %s\n", bs->pl->pl_label);
103 }
104
105 static void _display_peer(struct vty *vty, struct bfd_session *bs)
106 {
107 char buf[256];
108 time_t now;
109
110 _display_peer_header(vty, bs);
111
112 vty_out(vty, "\t\tID: %u\n", bs->discrs.my_discr);
113 vty_out(vty, "\t\tRemote ID: %u\n", bs->discrs.remote_discr);
114 if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_PASSIVE))
115 vty_out(vty, "\t\tPassive mode\n");
116 else
117 vty_out(vty, "\t\tActive mode\n");
118 if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH))
119 vty_out(vty, "\t\tMinimum TTL: %d\n", bs->mh_ttl);
120
121 vty_out(vty, "\t\tStatus: ");
122 switch (bs->ses_state) {
123 case PTM_BFD_ADM_DOWN:
124 vty_out(vty, "shutdown\n");
125 break;
126 case PTM_BFD_DOWN:
127 vty_out(vty, "down\n");
128
129 now = monotime(NULL);
130 integer2timestr(now - bs->downtime.tv_sec, buf, sizeof(buf));
131 vty_out(vty, "\t\tDowntime: %s\n", buf);
132 break;
133 case PTM_BFD_INIT:
134 vty_out(vty, "init\n");
135 break;
136 case PTM_BFD_UP:
137 vty_out(vty, "up\n");
138
139 now = monotime(NULL);
140 integer2timestr(now - bs->uptime.tv_sec, buf, sizeof(buf));
141 vty_out(vty, "\t\tUptime: %s\n", buf);
142 break;
143
144 default:
145 vty_out(vty, "unknown\n");
146 break;
147 }
148
149 vty_out(vty, "\t\tDiagnostics: %s\n", diag2str(bs->local_diag));
150 vty_out(vty, "\t\tRemote diagnostics: %s\n", diag2str(bs->remote_diag));
151 vty_out(vty, "\t\tPeer Type: %s\n",
152 CHECK_FLAG(bs->flags, BFD_SESS_FLAG_CONFIG) ? "configured" : "dynamic");
153
154 vty_out(vty, "\t\tLocal timers:\n");
155 vty_out(vty, "\t\t\tDetect-multiplier: %u\n",
156 bs->detect_mult);
157 vty_out(vty, "\t\t\tReceive interval: %ums\n",
158 bs->timers.required_min_rx / 1000);
159 vty_out(vty, "\t\t\tTransmission interval: %ums\n",
160 bs->timers.desired_min_tx / 1000);
161 if (bs->timers.required_min_echo_rx != 0)
162 vty_out(vty, "\t\t\tEcho receive interval: %ums\n",
163 bs->timers.required_min_echo_rx / 1000);
164 else
165 vty_out(vty, "\t\t\tEcho receive interval: disabled\n");
166 if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO))
167 vty_out(vty, "\t\t\tEcho transmission interval: %ums\n",
168 bs->timers.desired_min_echo_tx / 1000);
169 else
170 vty_out(vty, "\t\t\tEcho transmission interval: disabled\n");
171
172 vty_out(vty, "\t\tRemote timers:\n");
173 vty_out(vty, "\t\t\tDetect-multiplier: %u\n",
174 bs->remote_detect_mult);
175 vty_out(vty, "\t\t\tReceive interval: %ums\n",
176 bs->remote_timers.required_min_rx / 1000);
177 vty_out(vty, "\t\t\tTransmission interval: %ums\n",
178 bs->remote_timers.desired_min_tx / 1000);
179 if (bs->remote_timers.required_min_echo != 0)
180 vty_out(vty, "\t\t\tEcho receive interval: %ums\n",
181 bs->remote_timers.required_min_echo / 1000);
182 else
183 vty_out(vty, "\t\t\tEcho receive interval: disabled\n");
184
185 vty_out(vty, "\n");
186 }
187
188 static struct json_object *_peer_json_header(struct bfd_session *bs)
189 {
190 struct json_object *jo = json_object_new_object();
191 char addr_buf[INET6_ADDRSTRLEN];
192
193 if (bs->key.mhop)
194 json_object_boolean_true_add(jo, "multihop");
195 else
196 json_object_boolean_false_add(jo, "multihop");
197
198 json_object_string_add(jo, "peer",
199 inet_ntop(bs->key.family, &bs->key.peer,
200 addr_buf, sizeof(addr_buf)));
201 if (memcmp(&bs->key.local, &zero_addr, sizeof(bs->key.local)))
202 json_object_string_add(jo, "local",
203 inet_ntop(bs->key.family, &bs->key.local,
204 addr_buf, sizeof(addr_buf)));
205
206 if (bs->key.vrfname[0])
207 json_object_string_add(jo, "vrf", bs->key.vrfname);
208 if (bs->key.ifname[0])
209 json_object_string_add(jo, "interface", bs->key.ifname);
210
211 if (bs->pl)
212 json_object_string_add(jo, "label", bs->pl->pl_label);
213
214 return jo;
215 }
216
217 static struct json_object *__display_peer_json(struct bfd_session *bs)
218 {
219 struct json_object *jo = _peer_json_header(bs);
220
221 json_object_int_add(jo, "id", bs->discrs.my_discr);
222 json_object_int_add(jo, "remote-id", bs->discrs.remote_discr);
223 json_object_boolean_add(jo, "passive-mode",
224 CHECK_FLAG(bs->flags, BFD_SESS_FLAG_PASSIVE));
225 if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH))
226 json_object_int_add(jo, "minimum-ttl", bs->mh_ttl);
227
228 switch (bs->ses_state) {
229 case PTM_BFD_ADM_DOWN:
230 json_object_string_add(jo, "status", "shutdown");
231 break;
232 case PTM_BFD_DOWN:
233 json_object_string_add(jo, "status", "down");
234 json_object_int_add(jo, "downtime",
235 monotime(NULL) - bs->downtime.tv_sec);
236 break;
237 case PTM_BFD_INIT:
238 json_object_string_add(jo, "status", "init");
239 break;
240 case PTM_BFD_UP:
241 json_object_string_add(jo, "status", "up");
242 json_object_int_add(jo, "uptime",
243 monotime(NULL) - bs->uptime.tv_sec);
244 break;
245
246 default:
247 json_object_string_add(jo, "status", "unknown");
248 break;
249 }
250
251 json_object_string_add(jo, "diagnostic", diag2str(bs->local_diag));
252 json_object_string_add(jo, "remote-diagnostic",
253 diag2str(bs->remote_diag));
254
255 json_object_int_add(jo, "receive-interval",
256 bs->timers.required_min_rx / 1000);
257 json_object_int_add(jo, "transmit-interval",
258 bs->timers.desired_min_tx / 1000);
259 json_object_int_add(jo, "echo-receive-interval",
260 bs->timers.required_min_echo_rx / 1000);
261 if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO))
262 json_object_int_add(jo, "echo-transmit-interval",
263 bs->timers.desired_min_echo_tx / 1000);
264 else
265 json_object_int_add(jo, "echo-transmit-interval", 0);
266
267 json_object_int_add(jo, "detect-multiplier", bs->detect_mult);
268
269 json_object_int_add(jo, "remote-receive-interval",
270 bs->remote_timers.required_min_rx / 1000);
271 json_object_int_add(jo, "remote-transmit-interval",
272 bs->remote_timers.desired_min_tx / 1000);
273 json_object_int_add(jo, "remote-echo-receive-interval",
274 bs->remote_timers.required_min_echo / 1000);
275 json_object_int_add(jo, "remote-detect-multiplier",
276 bs->remote_detect_mult);
277
278 return jo;
279 }
280
281 static void _display_peer_json(struct vty *vty, struct bfd_session *bs)
282 {
283 struct json_object *jo = __display_peer_json(bs);
284
285 vty_json(vty, jo);
286 }
287
288 struct bfd_vrf_tuple {
289 const char *vrfname;
290 struct vty *vty;
291 struct json_object *jo;
292 };
293
294 static void _display_peer_iter(struct hash_bucket *hb, void *arg)
295 {
296 struct bfd_vrf_tuple *bvt = (struct bfd_vrf_tuple *)arg;
297 struct vty *vty;
298 struct bfd_session *bs = hb->data;
299
300 if (!bvt)
301 return;
302 vty = bvt->vty;
303
304 if (bvt->vrfname) {
305 if (!bs->key.vrfname[0] ||
306 !strmatch(bs->key.vrfname, bvt->vrfname))
307 return;
308 }
309 _display_peer(vty, bs);
310 }
311
312 static void _display_peer_json_iter(struct hash_bucket *hb, void *arg)
313 {
314 struct bfd_vrf_tuple *bvt = (struct bfd_vrf_tuple *)arg;
315 struct json_object *jo, *jon = NULL;
316 struct bfd_session *bs = hb->data;
317
318 if (!bvt)
319 return;
320 jo = bvt->jo;
321
322 if (bvt->vrfname) {
323 if (!bs->key.vrfname[0] ||
324 !strmatch(bs->key.vrfname, bvt->vrfname))
325 return;
326 }
327
328 jon = __display_peer_json(bs);
329 if (jon == NULL) {
330 zlog_warn("%s: not enough memory", __func__);
331 return;
332 }
333
334 json_object_array_add(jo, jon);
335 }
336
337 static void _display_all_peers(struct vty *vty, char *vrfname, bool use_json)
338 {
339 struct json_object *jo;
340 struct bfd_vrf_tuple bvt = {0};
341
342 bvt.vrfname = vrfname;
343
344 if (!use_json) {
345 bvt.vty = vty;
346 vty_out(vty, "BFD Peers:\n");
347 bfd_id_iterate(_display_peer_iter, &bvt);
348 return;
349 }
350
351 jo = json_object_new_array();
352 bvt.jo = jo;
353 bfd_id_iterate(_display_peer_json_iter, &bvt);
354
355 vty_json(vty, jo);
356 }
357
358 static void _display_peer_counter(struct vty *vty, struct bfd_session *bs)
359 {
360 _display_peer_header(vty, bs);
361
362 /* Ask data plane for updated counters. */
363 if (bfd_dplane_update_session_counters(bs) == -1)
364 zlog_debug("%s: failed to update BFD session counters (%s)",
365 __func__, bs_to_string(bs));
366
367 vty_out(vty, "\t\tControl packet input: %" PRIu64 " packets\n",
368 bs->stats.rx_ctrl_pkt);
369 vty_out(vty, "\t\tControl packet output: %" PRIu64 " packets\n",
370 bs->stats.tx_ctrl_pkt);
371 vty_out(vty, "\t\tEcho packet input: %" PRIu64 " packets\n",
372 bs->stats.rx_echo_pkt);
373 vty_out(vty, "\t\tEcho packet output: %" PRIu64 " packets\n",
374 bs->stats.tx_echo_pkt);
375 vty_out(vty, "\t\tSession up events: %" PRIu64 "\n",
376 bs->stats.session_up);
377 vty_out(vty, "\t\tSession down events: %" PRIu64 "\n",
378 bs->stats.session_down);
379 vty_out(vty, "\t\tZebra notifications: %" PRIu64 "\n",
380 bs->stats.znotification);
381 vty_out(vty, "\n");
382 }
383
384 static struct json_object *__display_peer_counters_json(struct bfd_session *bs)
385 {
386 struct json_object *jo = _peer_json_header(bs);
387
388 /* Ask data plane for updated counters. */
389 if (bfd_dplane_update_session_counters(bs) == -1)
390 zlog_debug("%s: failed to update BFD session counters (%s)",
391 __func__, bs_to_string(bs));
392
393 json_object_int_add(jo, "control-packet-input", bs->stats.rx_ctrl_pkt);
394 json_object_int_add(jo, "control-packet-output", bs->stats.tx_ctrl_pkt);
395 json_object_int_add(jo, "echo-packet-input", bs->stats.rx_echo_pkt);
396 json_object_int_add(jo, "echo-packet-output", bs->stats.tx_echo_pkt);
397 json_object_int_add(jo, "session-up", bs->stats.session_up);
398 json_object_int_add(jo, "session-down", bs->stats.session_down);
399 json_object_int_add(jo, "zebra-notifications", bs->stats.znotification);
400
401 return jo;
402 }
403
404 static void _display_peer_counters_json(struct vty *vty, struct bfd_session *bs)
405 {
406 struct json_object *jo = __display_peer_counters_json(bs);
407
408 vty_json(vty, jo);
409 }
410
411 static void _display_peer_counter_iter(struct hash_bucket *hb, void *arg)
412 {
413 struct bfd_vrf_tuple *bvt = arg;
414 struct vty *vty;
415 struct bfd_session *bs = hb->data;
416
417 if (!bvt)
418 return;
419 vty = bvt->vty;
420
421 if (bvt->vrfname) {
422 if (!bs->key.vrfname[0] ||
423 !strmatch(bs->key.vrfname, bvt->vrfname))
424 return;
425 }
426
427 _display_peer_counter(vty, bs);
428 }
429
430 static void _display_peer_counter_json_iter(struct hash_bucket *hb, void *arg)
431 {
432 struct json_object *jo, *jon = NULL;
433 struct bfd_session *bs = hb->data;
434 struct bfd_vrf_tuple *bvt = arg;
435
436 if (!bvt)
437 return;
438 jo = bvt->jo;
439
440 if (bvt->vrfname) {
441 if (!bs->key.vrfname[0] ||
442 !strmatch(bs->key.vrfname, bvt->vrfname))
443 return;
444 }
445
446 jon = __display_peer_counters_json(bs);
447 if (jon == NULL) {
448 zlog_warn("%s: not enough memory", __func__);
449 return;
450 }
451
452 json_object_array_add(jo, jon);
453 }
454
455 static void _display_peers_counter(struct vty *vty, char *vrfname, bool use_json)
456 {
457 struct json_object *jo;
458 struct bfd_vrf_tuple bvt = {0};
459
460 bvt.vrfname = vrfname;
461 if (!use_json) {
462 bvt.vty = vty;
463 vty_out(vty, "BFD Peers:\n");
464 bfd_id_iterate(_display_peer_counter_iter, &bvt);
465 return;
466 }
467
468 jo = json_object_new_array();
469 bvt.jo = jo;
470 bfd_id_iterate(_display_peer_counter_json_iter, &bvt);
471
472 vty_json(vty, jo);
473 }
474
475 static void _clear_peer_counter(struct bfd_session *bs)
476 {
477 /* Clear only pkt stats, intention is not to loose system
478 events counters */
479 bs->stats.rx_ctrl_pkt = 0;
480 bs->stats.tx_ctrl_pkt = 0;
481 bs->stats.rx_echo_pkt = 0;
482 bs->stats.tx_echo_pkt = 0;
483 }
484
485 static void _display_peer_brief(struct vty *vty, struct bfd_session *bs)
486 {
487 char addr_buf[INET6_ADDRSTRLEN];
488
489 if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) {
490 vty_out(vty, "%-10u", bs->discrs.my_discr);
491 inet_ntop(bs->key.family, &bs->key.local, addr_buf, sizeof(addr_buf));
492 vty_out(vty, " %-40s", addr_buf);
493 inet_ntop(bs->key.family, &bs->key.peer, addr_buf, sizeof(addr_buf));
494 vty_out(vty, " %-40s", addr_buf);
495 vty_out(vty, "%-15s\n", state_list[bs->ses_state].str);
496 } else {
497 vty_out(vty, "%-10u", bs->discrs.my_discr);
498 vty_out(vty, " %-40s", satostr(&bs->local_address));
499 inet_ntop(bs->key.family, &bs->key.peer, addr_buf, sizeof(addr_buf));
500 vty_out(vty, " %-40s", addr_buf);
501
502 vty_out(vty, "%-15s\n", state_list[bs->ses_state].str);
503 }
504 }
505
506 static void _display_peer_brief_iter(struct hash_bucket *hb, void *arg)
507 {
508 struct bfd_vrf_tuple *bvt = arg;
509 struct vty *vty;
510 struct bfd_session *bs = hb->data;
511
512 if (!bvt)
513 return;
514 vty = bvt->vty;
515
516 if (bvt->vrfname) {
517 if (!bs->key.vrfname[0] ||
518 !strmatch(bs->key.vrfname, bvt->vrfname))
519 return;
520 }
521
522 _display_peer_brief(vty, bs);
523 }
524
525 static void _display_peers_brief(struct vty *vty, const char *vrfname, bool use_json)
526 {
527 struct json_object *jo;
528 struct bfd_vrf_tuple bvt = {0};
529
530 bvt.vrfname = vrfname;
531
532 if (!use_json) {
533 bvt.vty = vty;
534
535 vty_out(vty, "Session count: %lu\n", bfd_get_session_count());
536 vty_out(vty, "%-10s", "SessionId");
537 vty_out(vty, " %-40s", "LocalAddress");
538 vty_out(vty, " %-40s", "PeerAddress");
539 vty_out(vty, "%-15s\n", "Status");
540
541 vty_out(vty, "%-10s", "=========");
542 vty_out(vty, " %-40s", "============");
543 vty_out(vty, " %-40s", "===========");
544 vty_out(vty, "%-15s\n", "======");
545
546 bfd_id_iterate(_display_peer_brief_iter, &bvt);
547 return;
548 }
549
550 jo = json_object_new_array();
551 bvt.jo = jo;
552
553 bfd_id_iterate(_display_peer_json_iter, &bvt);
554
555 vty_json(vty, jo);
556 }
557
558 static struct bfd_session *
559 _find_peer_or_error(struct vty *vty, int argc, struct cmd_token **argv,
560 const char *label, const char *peer_str,
561 const char *local_str, const char *ifname,
562 const char *vrfname)
563 {
564 int idx;
565 bool mhop;
566 struct bfd_session *bs = NULL;
567 struct peer_label *pl;
568 struct bfd_peer_cfg bpc;
569 struct sockaddr_any psa, lsa, *lsap;
570 char errormsg[128];
571
572 /* Look up the BFD peer. */
573 if (label) {
574 pl = pl_find(label);
575 if (pl)
576 bs = pl->pl_bs;
577 } else if (peer_str) {
578 strtosa(peer_str, &psa);
579 if (local_str) {
580 strtosa(local_str, &lsa);
581 lsap = &lsa;
582 } else
583 lsap = NULL;
584
585 idx = 0;
586 mhop = argv_find(argv, argc, "multihop", &idx);
587
588 if (bfd_configure_peer(&bpc, mhop, &psa, lsap, ifname, vrfname,
589 errormsg, sizeof(errormsg))
590 != 0) {
591 vty_out(vty, "%% Invalid peer configuration: %s\n",
592 errormsg);
593 return NULL;
594 }
595
596 bs = bs_peer_find(&bpc);
597 } else {
598 vty_out(vty, "%% Invalid arguments\n");
599 return NULL;
600 }
601
602 /* Find peer data. */
603 if (bs == NULL) {
604 vty_out(vty, "%% Unable to find 'peer %s",
605 label ? label : peer_str);
606 if (ifname)
607 vty_out(vty, " interface %s", ifname);
608 if (local_str)
609 vty_out(vty, " local-address %s", local_str);
610 if (vrfname)
611 vty_out(vty, " vrf %s", vrfname);
612 vty_out(vty, "'\n");
613
614 return NULL;
615 }
616
617 return bs;
618 }
619
620
621 /*
622 * Show commands.
623 */
624 DEFPY(bfd_show_peers, bfd_show_peers_cmd, "show bfd [vrf NAME] peers [json]",
625 SHOW_STR
626 "Bidirection Forwarding Detection\n"
627 VRF_CMD_HELP_STR
628 "BFD peers status\n" JSON_STR)
629 {
630 char *vrf_name = NULL;
631 int idx_vrf = 0;
632
633 if (argv_find(argv, argc, "vrf", &idx_vrf))
634 vrf_name = argv[idx_vrf + 1]->arg;
635
636 _display_all_peers(vty, vrf_name, use_json(argc, argv));
637
638 return CMD_SUCCESS;
639 }
640
641 DEFPY(bfd_show_peer, bfd_show_peer_cmd,
642 "show bfd [vrf NAME$vrf_name] peer <WORD$label|<A.B.C.D|X:X::X:X>$peer [{multihop|local-address <A.B.C.D|X:X::X:X>$local|interface IFNAME$ifname}]> [json]",
643 SHOW_STR
644 "Bidirection Forwarding Detection\n"
645 VRF_CMD_HELP_STR
646 "BFD peers status\n"
647 "Peer label\n" PEER_IPV4_STR PEER_IPV6_STR MHOP_STR LOCAL_STR
648 LOCAL_IPV4_STR LOCAL_IPV6_STR INTERFACE_STR LOCAL_INTF_STR JSON_STR)
649 {
650 struct bfd_session *bs;
651
652 /* Look up the BFD peer. */
653 bs = _find_peer_or_error(vty, argc, argv, label, peer_str, local_str,
654 ifname, vrf_name);
655 if (bs == NULL)
656 return CMD_WARNING_CONFIG_FAILED;
657
658 if (use_json(argc, argv)) {
659 _display_peer_json(vty, bs);
660 } else {
661 vty_out(vty, "BFD Peer:\n");
662 _display_peer(vty, bs);
663 }
664
665 return CMD_SUCCESS;
666 }
667
668 DEFPY(bfd_show_peer_counters, bfd_show_peer_counters_cmd,
669 "show bfd [vrf NAME$vrf_name] peer <WORD$label|<A.B.C.D|X:X::X:X>$peer [{multihop|local-address <A.B.C.D|X:X::X:X>$local|interface IFNAME$ifname}]> counters [json]",
670 SHOW_STR
671 "Bidirection Forwarding Detection\n"
672 VRF_CMD_HELP_STR
673 "BFD peers status\n"
674 "Peer label\n"
675 PEER_IPV4_STR
676 PEER_IPV6_STR
677 MHOP_STR
678 LOCAL_STR
679 LOCAL_IPV4_STR
680 LOCAL_IPV6_STR
681 INTERFACE_STR
682 LOCAL_INTF_STR
683 "Show BFD peer counters information\n"
684 JSON_STR)
685 {
686 struct bfd_session *bs;
687
688 /* Look up the BFD peer. */
689 bs = _find_peer_or_error(vty, argc, argv, label, peer_str, local_str,
690 ifname, vrf_name);
691 if (bs == NULL)
692 return CMD_WARNING_CONFIG_FAILED;
693
694 if (use_json(argc, argv))
695 _display_peer_counters_json(vty, bs);
696 else
697 _display_peer_counter(vty, bs);
698
699 return CMD_SUCCESS;
700 }
701
702 DEFPY(bfd_show_peers_counters, bfd_show_peers_counters_cmd,
703 "show bfd [vrf NAME] peers counters [json]",
704 SHOW_STR
705 "Bidirection Forwarding Detection\n"
706 VRF_CMD_HELP_STR
707 "BFD peers status\n"
708 "Show BFD peer counters information\n"
709 JSON_STR)
710 {
711 char *vrf_name = NULL;
712 int idx_vrf = 0;
713
714 if (argv_find(argv, argc, "vrf", &idx_vrf))
715 vrf_name = argv[idx_vrf + 1]->arg;
716
717 _display_peers_counter(vty, vrf_name, use_json(argc, argv));
718
719 return CMD_SUCCESS;
720 }
721
722 DEFPY(bfd_clear_peer_counters, bfd_clear_peer_counters_cmd,
723 "clear bfd [vrf <NAME$vrfname>] peer <WORD$label|<A.B.C.D|X:X::X:X>$peer [{multihop|local-address <A.B.C.D|X:X::X:X>$local|interface IFNAME$ifname}]> counters",
724 SHOW_STR
725 "Bidirection Forwarding Detection\n"
726 VRF_CMD_HELP_STR
727 "BFD peers status\n"
728 "Peer label\n"
729 PEER_IPV4_STR
730 PEER_IPV6_STR
731 MHOP_STR
732 LOCAL_STR
733 LOCAL_IPV4_STR
734 LOCAL_IPV6_STR
735 INTERFACE_STR
736 LOCAL_INTF_STR
737 "clear BFD peer counters information\n")
738 {
739 struct bfd_session *bs;
740
741 /* Look up the BFD peer. */
742 bs = _find_peer_or_error(vty, argc, argv, label, peer_str, local_str,
743 ifname, vrfname);
744 if (bs == NULL)
745 return CMD_WARNING_CONFIG_FAILED;
746
747 _clear_peer_counter(bs);
748
749 return CMD_SUCCESS;
750 }
751
752 DEFPY(bfd_show_peers_brief, bfd_show_peers_brief_cmd,
753 "show bfd [vrf <NAME$vrfname>] peers brief [json]",
754 SHOW_STR
755 "Bidirection Forwarding Detection\n"
756 VRF_CMD_HELP_STR
757 "BFD peers status\n"
758 "Show BFD peer information in tabular form\n"
759 JSON_STR)
760 {
761 char *vrf_name = NULL;
762 int idx_vrf = 0;
763
764 if (argv_find(argv, argc, "vrf", &idx_vrf))
765 vrf_name = argv[idx_vrf + 1]->arg;
766
767 _display_peers_brief(vty, vrf_name, use_json(argc, argv));
768
769 return CMD_SUCCESS;
770 }
771
772 DEFPY(show_bfd_distributed, show_bfd_distributed_cmd,
773 "show bfd distributed",
774 SHOW_STR
775 "Bidirection Forwarding Detection\n"
776 "Show BFD data plane (distributed BFD) statistics\n")
777 {
778 bfd_dplane_show_counters(vty);
779 return CMD_SUCCESS;
780 }
781
782 DEFPY(
783 bfd_debug_distributed, bfd_debug_distributed_cmd,
784 "[no] debug bfd distributed",
785 NO_STR
786 DEBUG_STR
787 "Bidirection Forwarding Detection\n"
788 "BFD data plane (distributed BFD) debugging\n")
789 {
790 bglobal.debug_dplane = !no;
791 return CMD_SUCCESS;
792 }
793
794 DEFPY(
795 bfd_debug_peer, bfd_debug_peer_cmd,
796 "[no] debug bfd peer",
797 NO_STR
798 DEBUG_STR
799 "Bidirection Forwarding Detection\n"
800 "Peer events debugging\n")
801 {
802 bglobal.debug_peer_event = !no;
803 return CMD_SUCCESS;
804 }
805
806 DEFPY(
807 bfd_debug_zebra, bfd_debug_zebra_cmd,
808 "[no] debug bfd zebra",
809 NO_STR
810 DEBUG_STR
811 "Bidirection Forwarding Detection\n"
812 "Zebra events debugging\n")
813 {
814 bglobal.debug_zebra = !no;
815 return CMD_SUCCESS;
816 }
817
818 DEFPY(
819 bfd_debug_network, bfd_debug_network_cmd,
820 "[no] debug bfd network",
821 NO_STR
822 DEBUG_STR
823 "Bidirection Forwarding Detection\n"
824 "Network layer debugging\n")
825 {
826 bglobal.debug_network = !no;
827 return CMD_SUCCESS;
828 }
829
830 /*
831 * Function definitions.
832 */
833
834 /*
835 * Configuration rules:
836 *
837 * Single hop:
838 * peer + (interface name)
839 *
840 * Multi hop:
841 * peer + local + (optional vrf)
842 *
843 * Anything else is misconfiguration.
844 */
845 static int bfd_configure_peer(struct bfd_peer_cfg *bpc, bool mhop,
846 const struct sockaddr_any *peer,
847 const struct sockaddr_any *local,
848 const char *ifname, const char *vrfname,
849 char *ebuf, size_t ebuflen)
850 {
851 memset(bpc, 0, sizeof(*bpc));
852
853 /* Defaults */
854 bpc->bpc_shutdown = false;
855 bpc->bpc_detectmultiplier = BPC_DEF_DETECTMULTIPLIER;
856 bpc->bpc_recvinterval = BPC_DEF_RECEIVEINTERVAL;
857 bpc->bpc_txinterval = BPC_DEF_TRANSMITINTERVAL;
858 bpc->bpc_echorecvinterval = BPC_DEF_ECHORECEIVEINTERVAL;
859 bpc->bpc_echotxinterval = BPC_DEF_ECHOTRANSMITINTERVAL;
860 bpc->bpc_lastevent = monotime(NULL);
861
862 /* Safety check: when no error buf is provided len must be zero. */
863 if (ebuf == NULL)
864 ebuflen = 0;
865
866 /* Peer is always mandatory. */
867 if (peer == NULL) {
868 snprintf(ebuf, ebuflen, "peer must not be empty");
869 return -1;
870 }
871
872 /* Validate address families. */
873 if (peer->sa_sin.sin_family == AF_INET) {
874 if (local && local->sa_sin.sin_family != AF_INET) {
875 snprintf(ebuf, ebuflen,
876 "local is IPv6, but peer is IPv4");
877 return -1;
878 }
879
880 bpc->bpc_ipv4 = true;
881 } else if (peer->sa_sin.sin_family == AF_INET6) {
882 if (local && local->sa_sin.sin_family != AF_INET6) {
883 snprintf(ebuf, ebuflen,
884 "local is IPv4, but peer is IPv6");
885 return -1;
886 }
887
888 bpc->bpc_ipv4 = false;
889 } else {
890 snprintf(ebuf, ebuflen, "invalid peer address family");
891 return -1;
892 }
893
894 /* Copy local and/or peer addresses. */
895 if (local)
896 bpc->bpc_local = *local;
897
898 bpc->bpc_peer = *peer;
899 bpc->bpc_mhop = mhop;
900
901 /* Handle interface specification configuration. */
902 if (ifname) {
903 bpc->bpc_has_localif = true;
904 if (strlcpy(bpc->bpc_localif, ifname, sizeof(bpc->bpc_localif))
905 > sizeof(bpc->bpc_localif)) {
906 snprintf(ebuf, ebuflen, "interface name too long");
907 return -1;
908 }
909 }
910
911 /* Handle VRF configuration. */
912 if (vrfname) {
913 bpc->bpc_has_vrfname = true;
914 if (strlcpy(bpc->bpc_vrfname, vrfname, sizeof(bpc->bpc_vrfname))
915 > sizeof(bpc->bpc_vrfname)) {
916 snprintf(ebuf, ebuflen, "vrf name too long");
917 return -1;
918 }
919 } else {
920 bpc->bpc_has_vrfname = true;
921 strlcpy(bpc->bpc_vrfname, VRF_DEFAULT_NAME, sizeof(bpc->bpc_vrfname));
922 }
923
924 return 0;
925 }
926
927 DEFUN_NOSH(show_debugging_bfd,
928 show_debugging_bfd_cmd,
929 "show debugging [bfd]",
930 SHOW_STR
931 DEBUG_STR
932 "BFD daemon\n")
933 {
934 vty_out(vty, "BFD debugging status:\n");
935 if (bglobal.debug_dplane)
936 vty_out(vty, " Distributed BFD debugging is on.\n");
937 if (bglobal.debug_peer_event)
938 vty_out(vty, " Peer events debugging is on.\n");
939 if (bglobal.debug_zebra)
940 vty_out(vty, " Zebra events debugging is on.\n");
941 if (bglobal.debug_network)
942 vty_out(vty, " Network layer debugging is on.\n");
943
944 return CMD_SUCCESS;
945 }
946
947 static int bfdd_write_config(struct vty *vty);
948 struct cmd_node bfd_node = {
949 .name = "bfd",
950 .node = BFD_NODE,
951 .parent_node = CONFIG_NODE,
952 .prompt = "%s(config-bfd)# ",
953 .config_write = bfdd_write_config,
954 };
955
956 struct cmd_node bfd_peer_node = {
957 .name = "bfd peer",
958 .node = BFD_PEER_NODE,
959 .parent_node = BFD_NODE,
960 .prompt = "%s(config-bfd-peer)# ",
961 };
962
963 static int bfdd_write_config(struct vty *vty)
964 {
965 struct lyd_node *dnode;
966 int written = 0;
967
968 if (bglobal.debug_dplane) {
969 vty_out(vty, "debug bfd distributed\n");
970 written = 1;
971 }
972
973 if (bglobal.debug_peer_event) {
974 vty_out(vty, "debug bfd peer\n");
975 written = 1;
976 }
977
978 if (bglobal.debug_zebra) {
979 vty_out(vty, "debug bfd zebra\n");
980 written = 1;
981 }
982
983 if (bglobal.debug_network) {
984 vty_out(vty, "debug bfd network\n");
985 written = 1;
986 }
987
988 dnode = yang_dnode_get(running_config->dnode, "/frr-bfdd:bfdd");
989 if (dnode) {
990 nb_cli_show_dnode_cmds(vty, dnode, false);
991 written = 1;
992 }
993
994 return written;
995 }
996
997 void bfdd_vty_init(void)
998 {
999 install_element(ENABLE_NODE, &bfd_show_peers_counters_cmd);
1000 install_element(ENABLE_NODE, &bfd_show_peer_counters_cmd);
1001 install_element(ENABLE_NODE, &bfd_clear_peer_counters_cmd);
1002 install_element(ENABLE_NODE, &bfd_show_peers_cmd);
1003 install_element(ENABLE_NODE, &bfd_show_peer_cmd);
1004 install_element(ENABLE_NODE, &bfd_show_peers_brief_cmd);
1005 install_element(ENABLE_NODE, &show_bfd_distributed_cmd);
1006 install_element(ENABLE_NODE, &show_debugging_bfd_cmd);
1007
1008 install_element(ENABLE_NODE, &bfd_debug_distributed_cmd);
1009 install_element(ENABLE_NODE, &bfd_debug_peer_cmd);
1010 install_element(ENABLE_NODE, &bfd_debug_zebra_cmd);
1011 install_element(ENABLE_NODE, &bfd_debug_network_cmd);
1012
1013 install_element(CONFIG_NODE, &bfd_debug_distributed_cmd);
1014 install_element(CONFIG_NODE, &bfd_debug_peer_cmd);
1015 install_element(CONFIG_NODE, &bfd_debug_zebra_cmd);
1016 install_element(CONFIG_NODE, &bfd_debug_network_cmd);
1017
1018 /* Install BFD node and commands. */
1019 install_node(&bfd_node);
1020 install_default(BFD_NODE);
1021
1022 /* Install BFD peer node. */
1023 install_node(&bfd_peer_node);
1024 install_default(BFD_PEER_NODE);
1025
1026 bfdd_cli_init();
1027 }