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