]> git.proxmox.com Git - mirror_frr.git/blob - bfdd/bfdd_vty.c
Merge pull request #4941 from ton31337/fix/do_not_include_nexthop_dash_dash
[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 (BFD_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
115 vty_out(vty, "\t\tStatus: ");
116 switch (bs->ses_state) {
117 case PTM_BFD_ADM_DOWN:
118 vty_out(vty, "shutdown\n");
119 break;
120 case PTM_BFD_DOWN:
121 vty_out(vty, "down\n");
122
123 now = monotime(NULL);
124 integer2timestr(now - bs->downtime.tv_sec, buf, sizeof(buf));
125 vty_out(vty, "\t\tDowntime: %s\n", buf);
126 break;
127 case PTM_BFD_INIT:
128 vty_out(vty, "init\n");
129 break;
130 case PTM_BFD_UP:
131 vty_out(vty, "up\n");
132
133 now = monotime(NULL);
134 integer2timestr(now - bs->uptime.tv_sec, buf, sizeof(buf));
135 vty_out(vty, "\t\tUptime: %s\n", buf);
136 break;
137
138 default:
139 vty_out(vty, "unknown\n");
140 break;
141 }
142
143 vty_out(vty, "\t\tDiagnostics: %s\n", diag2str(bs->local_diag));
144 vty_out(vty, "\t\tRemote diagnostics: %s\n", diag2str(bs->remote_diag));
145
146 vty_out(vty, "\t\tLocal timers:\n");
147 vty_out(vty, "\t\t\tReceive interval: %" PRIu32 "ms\n",
148 bs->timers.required_min_rx / 1000);
149 vty_out(vty, "\t\t\tTransmission interval: %" PRIu32 "ms\n",
150 bs->timers.desired_min_tx / 1000);
151 vty_out(vty, "\t\t\tEcho transmission interval: %" PRIu32 "ms\n",
152 bs->timers.required_min_echo / 1000);
153
154 vty_out(vty, "\t\tRemote timers:\n");
155 vty_out(vty, "\t\t\tReceive interval: %" PRIu32 "ms\n",
156 bs->remote_timers.required_min_rx / 1000);
157 vty_out(vty, "\t\t\tTransmission interval: %" PRIu32 "ms\n",
158 bs->remote_timers.desired_min_tx / 1000);
159 vty_out(vty, "\t\t\tEcho transmission interval: %" PRIu32 "ms\n",
160 bs->remote_timers.required_min_echo / 1000);
161
162 vty_out(vty, "\n");
163 }
164
165 static struct json_object *_peer_json_header(struct bfd_session *bs)
166 {
167 struct json_object *jo = json_object_new_object();
168 char addr_buf[INET6_ADDRSTRLEN];
169
170 if (bs->key.mhop)
171 json_object_boolean_true_add(jo, "multihop");
172 else
173 json_object_boolean_false_add(jo, "multihop");
174
175 json_object_string_add(jo, "peer",
176 inet_ntop(bs->key.family, &bs->key.peer,
177 addr_buf, sizeof(addr_buf)));
178 if (memcmp(&bs->key.local, &zero_addr, sizeof(bs->key.local)))
179 json_object_string_add(jo, "local",
180 inet_ntop(bs->key.family, &bs->key.local,
181 addr_buf, sizeof(addr_buf)));
182
183 if (bs->key.vrfname[0])
184 json_object_string_add(jo, "vrf", bs->key.vrfname);
185 if (bs->key.ifname[0])
186 json_object_string_add(jo, "interface", bs->key.ifname);
187
188 if (bs->pl)
189 json_object_string_add(jo, "label", bs->pl->pl_label);
190
191 return jo;
192 }
193
194 static struct json_object *__display_peer_json(struct bfd_session *bs)
195 {
196 struct json_object *jo = _peer_json_header(bs);
197
198 json_object_int_add(jo, "id", bs->discrs.my_discr);
199 json_object_int_add(jo, "remote-id", bs->discrs.remote_discr);
200
201 switch (bs->ses_state) {
202 case PTM_BFD_ADM_DOWN:
203 json_object_string_add(jo, "status", "shutdown");
204 break;
205 case PTM_BFD_DOWN:
206 json_object_string_add(jo, "status", "down");
207 json_object_int_add(jo, "downtime",
208 monotime(NULL) - bs->downtime.tv_sec);
209 break;
210 case PTM_BFD_INIT:
211 json_object_string_add(jo, "status", "init");
212 break;
213 case PTM_BFD_UP:
214 json_object_string_add(jo, "status", "up");
215 json_object_int_add(jo, "uptime",
216 monotime(NULL) - bs->uptime.tv_sec);
217 break;
218
219 default:
220 json_object_string_add(jo, "status", "unknown");
221 break;
222 }
223
224 json_object_string_add(jo, "diagnostic", diag2str(bs->local_diag));
225 json_object_string_add(jo, "remote-diagnostic",
226 diag2str(bs->remote_diag));
227
228 json_object_int_add(jo, "receive-interval",
229 bs->timers.required_min_rx / 1000);
230 json_object_int_add(jo, "transmit-interval",
231 bs->timers.desired_min_tx / 1000);
232 if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO))
233 json_object_int_add(jo, "echo-interval",
234 bs->timers.required_min_echo / 1000);
235 else
236 json_object_int_add(jo, "echo-interval", 0);
237
238 json_object_int_add(jo, "remote-receive-interval",
239 bs->remote_timers.required_min_rx / 1000);
240 json_object_int_add(jo, "remote-transmit-interval",
241 bs->remote_timers.desired_min_tx / 1000);
242 json_object_int_add(jo, "remote-echo-interval",
243 bs->remote_timers.required_min_echo / 1000);
244
245 return jo;
246 }
247
248 static void _display_peer_json(struct vty *vty, struct bfd_session *bs)
249 {
250 struct json_object *jo = __display_peer_json(bs);
251
252 vty_out(vty, "%s\n", json_object_to_json_string_ext(jo, 0));
253 json_object_free(jo);
254 }
255
256 struct bfd_vrf_tuple {
257 char *vrfname;
258 struct vty *vty;
259 struct json_object *jo;
260 };
261
262 static void _display_peer_iter(struct hash_bucket *hb, void *arg)
263 {
264 struct bfd_vrf_tuple *bvt = (struct bfd_vrf_tuple *)arg;
265 struct vty *vty;
266 struct bfd_session *bs = hb->data;
267
268 if (!bvt)
269 return;
270 vty = bvt->vty;
271
272 if (bvt->vrfname) {
273 if (!bs->key.vrfname[0] ||
274 !strmatch(bs->key.vrfname, bvt->vrfname))
275 return;
276 }
277 _display_peer(vty, bs);
278 }
279
280 static void _display_peer_json_iter(struct hash_bucket *hb, void *arg)
281 {
282 struct bfd_vrf_tuple *bvt = (struct bfd_vrf_tuple *)arg;
283 struct json_object *jo, *jon = NULL;
284 struct bfd_session *bs = hb->data;
285
286 if (!bvt)
287 return;
288 jo = bvt->jo;
289
290 if (bvt->vrfname) {
291 if (!bs->key.vrfname[0] ||
292 !strmatch(bs->key.vrfname, bvt->vrfname))
293 return;
294 }
295
296 jon = __display_peer_json(bs);
297 if (jon == NULL) {
298 log_warning("%s: not enough memory", __func__);
299 return;
300 }
301
302 json_object_array_add(jo, jon);
303 }
304
305 static void _display_all_peers(struct vty *vty, char *vrfname, bool use_json)
306 {
307 struct json_object *jo;
308 struct bfd_vrf_tuple bvt;
309
310 memset(&bvt, 0, sizeof(bvt));
311 bvt.vrfname = vrfname;
312
313 if (!use_json) {
314 bvt.vty = vty;
315 vty_out(vty, "BFD Peers:\n");
316 bfd_id_iterate(_display_peer_iter, &bvt);
317 return;
318 }
319
320 jo = json_object_new_array();
321 bvt.jo = jo;
322 bfd_id_iterate(_display_peer_json_iter, &bvt);
323
324 vty_out(vty, "%s\n", json_object_to_json_string_ext(jo, 0));
325 json_object_free(jo);
326 }
327
328 static void _display_peer_counter(struct vty *vty, struct bfd_session *bs)
329 {
330 _display_peer_header(vty, bs);
331
332 vty_out(vty, "\t\tControl packet input: %" PRIu64 " packets\n",
333 bs->stats.rx_ctrl_pkt);
334 vty_out(vty, "\t\tControl packet output: %" PRIu64 " packets\n",
335 bs->stats.tx_ctrl_pkt);
336 vty_out(vty, "\t\tEcho packet input: %" PRIu64 " packets\n",
337 bs->stats.rx_echo_pkt);
338 vty_out(vty, "\t\tEcho packet output: %" PRIu64 " packets\n",
339 bs->stats.tx_echo_pkt);
340 vty_out(vty, "\t\tSession up events: %" PRIu64 "\n",
341 bs->stats.session_up);
342 vty_out(vty, "\t\tSession down events: %" PRIu64 "\n",
343 bs->stats.session_down);
344 vty_out(vty, "\t\tZebra notifications: %" PRIu64 "\n",
345 bs->stats.znotification);
346 vty_out(vty, "\n");
347 }
348
349 static struct json_object *__display_peer_counters_json(struct bfd_session *bs)
350 {
351 struct json_object *jo = _peer_json_header(bs);
352
353 json_object_int_add(jo, "control-packet-input", bs->stats.rx_ctrl_pkt);
354 json_object_int_add(jo, "control-packet-output", bs->stats.tx_ctrl_pkt);
355 json_object_int_add(jo, "echo-packet-input", bs->stats.rx_echo_pkt);
356 json_object_int_add(jo, "echo-packet-output", bs->stats.tx_echo_pkt);
357 json_object_int_add(jo, "session-up", bs->stats.session_up);
358 json_object_int_add(jo, "session-down", bs->stats.session_down);
359 json_object_int_add(jo, "zebra-notifications", bs->stats.znotification);
360
361 return jo;
362 }
363
364 static void _display_peer_counters_json(struct vty *vty, struct bfd_session *bs)
365 {
366 struct json_object *jo = __display_peer_counters_json(bs);
367
368 vty_out(vty, "%s\n", json_object_to_json_string_ext(jo, 0));
369 json_object_free(jo);
370 }
371
372 static void _display_peer_counter_iter(struct hash_bucket *hb, void *arg)
373 {
374 struct bfd_vrf_tuple *bvt = arg;
375 struct vty *vty;
376 struct bfd_session *bs = hb->data;
377
378 if (!bvt)
379 return;
380 vty = bvt->vty;
381
382 if (bvt->vrfname) {
383 if (!bs->key.vrfname[0] ||
384 !strmatch(bs->key.vrfname, bvt->vrfname))
385 return;
386 }
387
388 _display_peer_counter(vty, bs);
389 }
390
391 static void _display_peer_counter_json_iter(struct hash_bucket *hb, void *arg)
392 {
393 struct json_object *jo, *jon = NULL;
394 struct bfd_session *bs = hb->data;
395 struct bfd_vrf_tuple *bvt = arg;
396
397 if (!bvt)
398 return;
399 jo = bvt->jo;
400
401 if (bvt->vrfname) {
402 if (!bs->key.vrfname[0] ||
403 !strmatch(bs->key.vrfname, bvt->vrfname))
404 return;
405 }
406
407 jon = __display_peer_counters_json(bs);
408 if (jon == NULL) {
409 log_warning("%s: not enough memory", __func__);
410 return;
411 }
412
413 json_object_array_add(jo, jon);
414 }
415
416 static void _display_peers_counter(struct vty *vty, char *vrfname, bool use_json)
417 {
418 struct json_object *jo;
419 struct bfd_vrf_tuple bvt;
420
421 memset(&bvt, 0, sizeof(struct bfd_vrf_tuple));
422 bvt.vrfname = vrfname;
423 if (!use_json) {
424 bvt.vty = vty;
425 vty_out(vty, "BFD Peers:\n");
426 bfd_id_iterate(_display_peer_counter_iter, &bvt);
427 return;
428 }
429
430 jo = json_object_new_array();
431 bvt.jo = jo;
432 bfd_id_iterate(_display_peer_counter_json_iter, jo);
433
434 vty_out(vty, "%s\n", json_object_to_json_string_ext(jo, 0));
435 json_object_free(jo);
436 }
437
438 static struct bfd_session *
439 _find_peer_or_error(struct vty *vty, int argc, struct cmd_token **argv,
440 const char *label, const char *peer_str,
441 const char *local_str, const char *ifname,
442 const char *vrfname)
443 {
444 int idx;
445 bool mhop;
446 struct bfd_session *bs = NULL;
447 struct peer_label *pl;
448 struct bfd_peer_cfg bpc;
449 struct sockaddr_any psa, lsa, *lsap;
450 char errormsg[128];
451
452 /* Look up the BFD peer. */
453 if (label) {
454 pl = pl_find(label);
455 if (pl)
456 bs = pl->pl_bs;
457 } else {
458 strtosa(peer_str, &psa);
459 if (local_str) {
460 strtosa(local_str, &lsa);
461 lsap = &lsa;
462 } else
463 lsap = NULL;
464
465 idx = 0;
466 mhop = argv_find(argv, argc, "multihop", &idx);
467
468 if (bfd_configure_peer(&bpc, mhop, &psa, lsap, ifname, vrfname,
469 errormsg, sizeof(errormsg))
470 != 0) {
471 vty_out(vty, "%% Invalid peer configuration: %s\n",
472 errormsg);
473 return NULL;
474 }
475
476 bs = bs_peer_find(&bpc);
477 }
478
479 /* Find peer data. */
480 if (bs == NULL) {
481 vty_out(vty, "%% Unable to find 'peer %s",
482 label ? label : peer_str);
483 if (ifname)
484 vty_out(vty, " interface %s", ifname);
485 if (local_str)
486 vty_out(vty, " local-address %s", local_str);
487 if (vrfname)
488 vty_out(vty, " vrf %s", vrfname);
489 vty_out(vty, "'\n");
490
491 return NULL;
492 }
493
494 return bs;
495 }
496
497
498 /*
499 * Show commands.
500 */
501 DEFPY(bfd_show_peers, bfd_show_peers_cmd, "show bfd [vrf NAME] peers [json]",
502 SHOW_STR
503 "Bidirection Forwarding Detection\n"
504 VRF_CMD_HELP_STR
505 "BFD peers status\n" JSON_STR)
506 {
507 char *vrf_name = NULL;
508 int idx_vrf = 0;
509
510 if (argv_find(argv, argc, "vrf", &idx_vrf))
511 vrf_name = argv[idx_vrf + 1]->arg;
512
513 _display_all_peers(vty, vrf_name, use_json(argc, argv));
514
515 return CMD_SUCCESS;
516 }
517
518 DEFPY(bfd_show_peer, bfd_show_peer_cmd,
519 "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]",
520 SHOW_STR
521 "Bidirection Forwarding Detection\n"
522 VRF_CMD_HELP_STR
523 "BFD peers status\n"
524 "Peer label\n" PEER_IPV4_STR PEER_IPV6_STR MHOP_STR LOCAL_STR
525 LOCAL_IPV4_STR LOCAL_IPV6_STR INTERFACE_STR LOCAL_INTF_STR JSON_STR)
526 {
527 struct bfd_session *bs;
528
529 /* Look up the BFD peer. */
530 bs = _find_peer_or_error(vty, argc, argv, label, peer_str, local_str,
531 ifname, vrf_name);
532 if (bs == NULL)
533 return CMD_WARNING_CONFIG_FAILED;
534
535 if (use_json(argc, argv)) {
536 _display_peer_json(vty, bs);
537 } else {
538 vty_out(vty, "BFD Peer:\n");
539 _display_peer(vty, bs);
540 }
541
542 return CMD_SUCCESS;
543 }
544
545 DEFPY(bfd_show_peer_counters, bfd_show_peer_counters_cmd,
546 "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]",
547 SHOW_STR
548 "Bidirection Forwarding Detection\n"
549 VRF_CMD_HELP_STR
550 "BFD peers status\n"
551 "Peer label\n"
552 PEER_IPV4_STR
553 PEER_IPV6_STR
554 MHOP_STR
555 LOCAL_STR
556 LOCAL_IPV4_STR
557 LOCAL_IPV6_STR
558 INTERFACE_STR
559 LOCAL_INTF_STR
560 "Show BFD peer counters information\n"
561 JSON_STR)
562 {
563 struct bfd_session *bs;
564
565 /* Look up the BFD peer. */
566 bs = _find_peer_or_error(vty, argc, argv, label, peer_str, local_str,
567 ifname, vrf_name);
568 if (bs == NULL)
569 return CMD_WARNING_CONFIG_FAILED;
570
571 if (use_json(argc, argv))
572 _display_peer_counters_json(vty, bs);
573 else
574 _display_peer_counter(vty, bs);
575
576 return CMD_SUCCESS;
577 }
578
579 DEFPY(bfd_show_peers_counters, bfd_show_peers_counters_cmd,
580 "show bfd [vrf NAME] peers counters [json]",
581 SHOW_STR
582 "Bidirection Forwarding Detection\n"
583 VRF_CMD_HELP_STR
584 "BFD peers status\n"
585 "Show BFD peer counters information\n"
586 JSON_STR)
587 {
588 char *vrf_name = NULL;
589 int idx_vrf = 0;
590
591 if (argv_find(argv, argc, "vrf", &idx_vrf))
592 vrf_name = argv[idx_vrf + 1]->arg;
593
594 _display_peers_counter(vty, vrf_name, use_json(argc, argv));
595
596 return CMD_SUCCESS;
597 }
598
599
600 /*
601 * Function definitions.
602 */
603
604 /*
605 * Configuration rules:
606 *
607 * Single hop:
608 * peer + (interface name)
609 *
610 * Multi hop:
611 * peer + local + (optional vrf)
612 *
613 * Anything else is misconfiguration.
614 */
615 static int bfd_configure_peer(struct bfd_peer_cfg *bpc, bool mhop,
616 const struct sockaddr_any *peer,
617 const struct sockaddr_any *local,
618 const char *ifname, const char *vrfname,
619 char *ebuf, size_t ebuflen)
620 {
621 memset(bpc, 0, sizeof(*bpc));
622
623 /* Defaults */
624 bpc->bpc_shutdown = true;
625 bpc->bpc_detectmultiplier = BPC_DEF_DETECTMULTIPLIER;
626 bpc->bpc_recvinterval = BPC_DEF_RECEIVEINTERVAL;
627 bpc->bpc_txinterval = BPC_DEF_TRANSMITINTERVAL;
628 bpc->bpc_echointerval = BPC_DEF_ECHOINTERVAL;
629 bpc->bpc_lastevent = monotime(NULL);
630
631 /* Safety check: when no error buf is provided len must be zero. */
632 if (ebuf == NULL)
633 ebuflen = 0;
634
635 /* Peer is always mandatory. */
636 if (peer == NULL) {
637 snprintf(ebuf, ebuflen, "peer must not be empty");
638 return -1;
639 }
640
641 /* Validate address families. */
642 if (peer->sa_sin.sin_family == AF_INET) {
643 if (local && local->sa_sin.sin_family != AF_INET) {
644 snprintf(ebuf, ebuflen,
645 "local is IPv6, but peer is IPv4");
646 return -1;
647 }
648
649 bpc->bpc_ipv4 = true;
650 } else if (peer->sa_sin.sin_family == AF_INET6) {
651 if (local && local->sa_sin.sin_family != AF_INET6) {
652 snprintf(ebuf, ebuflen,
653 "local is IPv4, but peer is IPv6");
654 return -1;
655 }
656
657 bpc->bpc_ipv4 = false;
658 } else {
659 snprintf(ebuf, ebuflen, "invalid peer address family");
660 return -1;
661 }
662
663 /* Copy local and/or peer addresses. */
664 if (local)
665 bpc->bpc_local = *local;
666
667 bpc->bpc_peer = *peer;
668 bpc->bpc_mhop = mhop;
669
670 /* Handle interface specification configuration. */
671 if (ifname) {
672 bpc->bpc_has_localif = true;
673 if (strlcpy(bpc->bpc_localif, ifname, sizeof(bpc->bpc_localif))
674 > sizeof(bpc->bpc_localif)) {
675 snprintf(ebuf, ebuflen, "interface name too long");
676 return -1;
677 }
678 }
679
680 /* Handle VRF configuration. */
681 if (vrfname) {
682 bpc->bpc_has_vrfname = true;
683 if (strlcpy(bpc->bpc_vrfname, vrfname, sizeof(bpc->bpc_vrfname))
684 > sizeof(bpc->bpc_vrfname)) {
685 snprintf(ebuf, ebuflen, "vrf name too long");
686 return -1;
687 }
688 } else {
689 bpc->bpc_has_vrfname = true;
690 strlcpy(bpc->bpc_vrfname, VRF_DEFAULT_NAME, sizeof(bpc->bpc_vrfname));
691 }
692
693 return 0;
694 }
695
696 DEFUN_NOSH(show_debugging_bfd,
697 show_debugging_bfd_cmd,
698 "show debugging [bfd]",
699 SHOW_STR
700 DEBUG_STR
701 "BFD daemon\n")
702 {
703 vty_out(vty, "BFD debugging status:\n");
704
705 return CMD_SUCCESS;
706 }
707
708 struct cmd_node bfd_node = {
709 BFD_NODE,
710 "%s(config-bfd)# ",
711 1,
712 };
713
714 struct cmd_node bfd_peer_node = {
715 BFD_PEER_NODE,
716 "%s(config-bfd-peer)# ",
717 1,
718 };
719
720 static int bfdd_write_config(struct vty *vty)
721 {
722 struct lyd_node *dnode;
723 int written = 0;
724
725 dnode = yang_dnode_get(running_config->dnode, "/frr-bfdd:bfdd");
726 if (dnode) {
727 nb_cli_show_dnode_cmds(vty, dnode, false);
728 written = 1;
729 }
730
731 return written;
732 }
733
734 void bfdd_vty_init(void)
735 {
736 install_element(ENABLE_NODE, &bfd_show_peers_counters_cmd);
737 install_element(ENABLE_NODE, &bfd_show_peer_counters_cmd);
738 install_element(ENABLE_NODE, &bfd_show_peers_cmd);
739 install_element(ENABLE_NODE, &bfd_show_peer_cmd);
740 install_element(ENABLE_NODE, &show_debugging_bfd_cmd);
741
742 /* Install BFD node and commands. */
743 install_node(&bfd_node, bfdd_write_config);
744 install_default(BFD_NODE);
745
746 /* Install BFD peer node. */
747 install_node(&bfd_peer_node, NULL);
748 install_default(BFD_PEER_NODE);
749
750 bfdd_cli_init();
751 }