]> git.proxmox.com Git - mirror_frr.git/blob - bfdd/bfdd_vty.c
bfdd: add vty shell commands
[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/vty.h"
27
28 #include "bfd.h"
29
30 #ifndef VTYSH_EXTRACT_PL
31 #include "bfdd/bfdd_vty_clippy.c"
32 #endif
33
34 /*
35 * Commands help string definitions.
36 */
37 #define PEER_STR "Configure peer\n"
38 #define INTERFACE_NAME_STR "Configure interface name to use\n"
39 #define PEER_IPV4_STR "IPv4 peer address\n"
40 #define PEER_IPV6_STR "IPv6 peer address\n"
41 #define MHOP_STR "Configure multihop\n"
42 #define LOCAL_STR "Configure local address\n"
43 #define LOCAL_IPV4_STR "IPv4 local address\n"
44 #define LOCAL_IPV6_STR "IPv6 local address\n"
45 #define LOCAL_INTF_STR "Configure local interface name to use\n"
46 #define VRF_STR "Configure VRF\n"
47 #define VRF_NAME_STR "Configure VRF name\n"
48
49 /*
50 * Prototypes
51 */
52 static int bfdd_write_config(struct vty *vty);
53 static int bfdd_peer_write_config(struct vty *vty);
54 static void _bfdd_peer_write_config(struct hash_backet *hb, void *arg);
55 static int bfd_configure_peer(struct bfd_peer_cfg *bpc, bool mhop,
56 const struct sockaddr_any *peer,
57 const struct sockaddr_any *local,
58 const char *ifname, const char *vrfname,
59 char *ebuf, size_t ebuflen);
60
61 static struct json_object *__display_peer_json(struct bfd_session *bs);
62 static void _display_peer_json(struct vty *vty, struct bfd_session *bs);
63 static void _display_peer(struct vty *vty, struct bfd_session *bs);
64 static void _display_all_peers(struct vty *vty, bool use_json);
65 static void _display_peer_iter(struct hash_backet *hb, void *arg);
66 static void _display_peer_json_iter(struct hash_backet *hb, void *arg);
67
68
69 /*
70 * Commands definition.
71 */
72 DEFUN_NOSH(bfd_enter, bfd_enter_cmd, "bfd", "Configure BFD peers\n")
73 {
74 vty->node = BFD_NODE;
75 return CMD_SUCCESS;
76 }
77
78 DEFUN_NOSH(
79 bfd_peer_enter, bfd_peer_enter_cmd,
80 "peer <A.B.C.D|X:X::X:X> [{multihop|local-address <A.B.C.D|X:X::X:X>|interface IFNAME|vrf NAME}]",
81 PEER_STR PEER_IPV4_STR PEER_IPV6_STR
82 MHOP_STR
83 LOCAL_STR LOCAL_IPV4_STR LOCAL_IPV6_STR
84 INTERFACE_STR
85 LOCAL_INTF_STR
86 VRF_STR VRF_NAME_STR)
87 {
88 bool mhop;
89 int idx;
90 struct bfd_session *bs;
91 const char *peer, *ifname, *local, *vrfname;
92 struct bfd_peer_cfg bpc;
93 struct sockaddr_any psa, lsa, *lsap;
94 char errormsg[128];
95
96 vrfname = peer = ifname = local = NULL;
97
98 /* Gather all provided information. */
99 peer = argv[1]->arg;
100
101 idx = 0;
102 mhop = argv_find(argv, argc, "multihop", &idx);
103
104 idx = 0;
105 if (argv_find(argv, argc, "interface", &idx))
106 ifname = argv[idx + 1]->arg;
107
108 idx = 0;
109 if (argv_find(argv, argc, "local-address", &idx))
110 local = argv[idx + 1]->arg;
111
112 idx = 0;
113 if (argv_find(argv, argc, "vrf", &idx))
114 vrfname = argv[idx + 1]->arg;
115
116 if (vrfname && ifname) {
117 vty_out(vty, "%% VRF is not mixable with interface\n");
118 return CMD_WARNING_CONFIG_FAILED;
119 }
120
121 strtosa(peer, &psa);
122 if (local) {
123 strtosa(local, &lsa);
124 lsap = &lsa;
125 } else
126 lsap = NULL;
127
128 if (bfd_configure_peer(&bpc, mhop, &psa, lsap, ifname, vrfname,
129 errormsg, sizeof(errormsg))
130 != 0) {
131 vty_out(vty, "%% Invalid peer configuration: %s\n", errormsg);
132 return CMD_WARNING_CONFIG_FAILED;
133 }
134
135 bs = bs_peer_find(&bpc);
136 if (bs == NULL) {
137 bs = ptm_bfd_sess_new(&bpc);
138 if (bs == NULL) {
139 vty_out(vty, "%% Failed to add peer.\n");
140 return CMD_WARNING_CONFIG_FAILED;
141 }
142 }
143
144 VTY_PUSH_CONTEXT(BFD_PEER_NODE, bs);
145
146 return CMD_SUCCESS;
147 }
148
149 DEFPY(bfd_peer_detectmultiplier, bfd_peer_detectmultiplier_cmd,
150 "detect-multiplier (2-255)$multiplier",
151 "Configure peer detection multiplier\n"
152 "Configure peer detection multiplier value\n")
153 {
154 struct bfd_session *bs;
155
156 bs = VTY_GET_CONTEXT(bfd_session);
157 bs->detect_mult = multiplier;
158
159 return CMD_SUCCESS;
160 }
161
162 DEFPY(bfd_peer_recvinterval, bfd_peer_recvinterval_cmd,
163 "receive-interval (10-60000)$interval",
164 "Configure peer receive interval\n"
165 "Configure peer receive interval value in milliseconds\n")
166 {
167 struct bfd_session *bs;
168
169 bs = VTY_GET_CONTEXT(bfd_session);
170 bs->timers.required_min_rx = interval * 1000;
171
172 return CMD_SUCCESS;
173 }
174
175 DEFPY(bfd_peer_txinterval, bfd_peer_txinterval_cmd,
176 "transmit-interval (10-60000)$interval",
177 "Configure peer transmit interval\n"
178 "Configure peer transmit interval value in milliseconds\n")
179 {
180 struct bfd_session *bs;
181
182 bs = VTY_GET_CONTEXT(bfd_session);
183 bs->up_min_tx = interval * 1000;
184
185 return CMD_SUCCESS;
186 }
187
188 DEFPY(bfd_peer_echointerval, bfd_peer_echointerval_cmd,
189 "echo-interval (10-60000)$interval",
190 "Configure peer echo interval\n"
191 "Configure peer echo interval value in milliseconds\n")
192 {
193 struct bfd_session *bs;
194
195 bs = VTY_GET_CONTEXT(bfd_session);
196 bs->timers.required_min_echo = interval * 1000;
197
198 return CMD_SUCCESS;
199 }
200
201 DEFPY(bfd_peer_shutdown, bfd_peer_shutdown_cmd, "[no] shutdown",
202 NO_STR "Disable BFD peer")
203 {
204 struct bfd_session *bs;
205
206 bs = VTY_GET_CONTEXT(bfd_session);
207 if (no) {
208 if (!BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN))
209 return CMD_SUCCESS;
210
211 BFD_UNSET_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN);
212
213 /* Change and notify state change. */
214 bs->ses_state = PTM_BFD_DOWN;
215 control_notify(bs);
216
217 /* Enable all timers. */
218 bfd_recvtimer_update(bs);
219 bfd_xmttimer_update(bs, bs->xmt_TO);
220 if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO)) {
221 bfd_echo_recvtimer_update(bs);
222 bfd_echo_xmttimer_update(bs, bs->echo_xmt_TO);
223 }
224 } else {
225 if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN))
226 return CMD_SUCCESS;
227
228 BFD_SET_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN);
229
230 /* Disable all events. */
231 bfd_recvtimer_delete(bs);
232 bfd_echo_recvtimer_delete(bs);
233 bfd_xmttimer_delete(bs);
234 bfd_echo_xmttimer_delete(bs);
235
236 /* Change and notify state change. */
237 bs->ses_state = PTM_BFD_ADM_DOWN;
238 control_notify(bs);
239
240 ptm_bfd_snd(bs, 0);
241 }
242
243 return CMD_SUCCESS;
244 }
245
246 DEFPY(bfd_peer_echo, bfd_peer_echo_cmd, "[no] echo-mode",
247 NO_STR "Configure echo mode\n")
248 {
249 struct bfd_session *bs;
250
251 bs = VTY_GET_CONTEXT(bfd_session);
252 if (no) {
253 if (!BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO))
254 return CMD_SUCCESS;
255
256 BFD_UNSET_FLAG(bs->flags, BFD_SESS_FLAG_ECHO);
257 ptm_bfd_echo_stop(bs, 0);
258 } else {
259 if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO))
260 return CMD_SUCCESS;
261
262 BFD_SET_FLAG(bs->flags, BFD_SESS_FLAG_ECHO);
263 /* Apply setting immediately. */
264 if (!BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN)) {
265 ptm_bfd_echo_start(bs);
266 bfd_echo_recvtimer_update(bs);
267 }
268 }
269
270 return CMD_SUCCESS;
271 }
272
273 DEFPY(bfd_peer_label, bfd_peer_label_cmd, "label WORD$label",
274 "Register peer label\n"
275 "Register peer label identification\n")
276 {
277 struct bfd_session *bs;
278
279 /* Validate label length. */
280 if (strlen(label) >= MAXNAMELEN) {
281 vty_out(vty, "%% Label name is too long\n");
282 return CMD_WARNING_CONFIG_FAILED;
283 }
284
285 bs = VTY_GET_CONTEXT(bfd_session);
286 if (bfd_session_update_label(bs, label) == -1) {
287 vty_out(vty, "%% Failed to update peer label.\n");
288 return CMD_WARNING_CONFIG_FAILED;
289 }
290
291 return CMD_SUCCESS;
292 }
293
294 DEFPY(bfd_no_peer, bfd_no_peer_cmd,
295 "no peer <A.B.C.D|X:X::X:X>$peer [{multihop|local-address <A.B.C.D|X:X::X:X>$local|interface IFNAME$ifname|vrf NAME$vrfname}]",
296 NO_STR
297 PEER_STR PEER_IPV4_STR PEER_IPV6_STR
298 MHOP_STR
299 LOCAL_STR LOCAL_IPV4_STR LOCAL_IPV6_STR
300 INTERFACE_STR
301 LOCAL_INTF_STR
302 VRF_STR VRF_NAME_STR)
303 {
304 int idx;
305 bool mhop;
306 struct bfd_peer_cfg bpc;
307 struct sockaddr_any psa, lsa, *lsap;
308 char errormsg[128];
309
310 strtosa(peer_str, &psa);
311 if (local) {
312 strtosa(local_str, &lsa);
313 lsap = &lsa;
314 } else {
315 lsap = NULL;
316 }
317
318 idx = 0;
319 mhop = argv_find(argv, argc, "multihop", &idx);
320
321 if (bfd_configure_peer(&bpc, mhop, &psa, lsap, ifname, vrfname,
322 errormsg, sizeof(errormsg))
323 != 0) {
324 vty_out(vty, "%% Invalid peer configuration: %s\n", errormsg);
325 return CMD_WARNING_CONFIG_FAILED;
326 }
327
328 if (ptm_bfd_ses_del(&bpc) != 0) {
329 vty_out(vty, "%% Failed to remove peer.\n");
330 return CMD_WARNING_CONFIG_FAILED;
331 }
332
333 return CMD_SUCCESS;
334 }
335
336
337 /*
338 * Show commands helper functions
339 */
340 static void _display_peer(struct vty *vty, struct bfd_session *bs)
341 {
342 char buf[256];
343 time_t now;
344
345 if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) {
346 vty_out(vty, "\tpeer %s", satostr(&bs->mhop.peer));
347 vty_out(vty, " multihop");
348 vty_out(vty, " local-address %s", satostr(&bs->mhop.local));
349 if (bs->mhop.vrf_name[0])
350 vty_out(vty, " vrf %s", bs->mhop.vrf_name);
351 vty_out(vty, "\n");
352 } else {
353 vty_out(vty, "\tpeer %s", satostr(&bs->mhop.peer));
354 if (bs->shop.port_name[0])
355 vty_out(vty, " interface %s", bs->shop.port_name);
356 vty_out(vty, "\n");
357 }
358
359 if (bs->pl)
360 vty_out(vty, "\t\tlabel: %s\n", bs->pl->pl_label);
361
362 vty_out(vty, "\t\tID: %u\n", bs->discrs.my_discr);
363 vty_out(vty, "\t\tRemote ID: %u\n", bs->discrs.remote_discr);
364
365 vty_out(vty, "\t\tStatus: ");
366 switch (bs->ses_state) {
367 case PTM_BFD_ADM_DOWN:
368 vty_out(vty, "shutdown\n");
369 break;
370 case PTM_BFD_DOWN:
371 vty_out(vty, "down\n");
372
373 now = monotime(NULL);
374 integer2timestr(now - bs->uptime.tv_sec, buf, sizeof(buf));
375 vty_out(vty, "\t\tDowntime: %s\n", buf);
376 break;
377 case PTM_BFD_INIT:
378 vty_out(vty, "init\n");
379 break;
380 case PTM_BFD_UP:
381 vty_out(vty, "up\n");
382
383 now = monotime(NULL);
384 integer2timestr(now - bs->uptime.tv_sec, buf, sizeof(buf));
385 vty_out(vty, "\t\tUptime: %s\n", buf);
386 break;
387
388 default:
389 vty_out(vty, "unknown\n");
390 break;
391 }
392
393 vty_out(vty, "\t\tDiagnostics: %s\n", diag2str(bs->local_diag));
394 vty_out(vty, "\t\tRemote diagnostics: %s\n", diag2str(bs->remote_diag));
395
396 vty_out(vty, "\t\tLocal timers:\n");
397 vty_out(vty, "\t\t\tReceive interval: %" PRIu32 "ms\n",
398 bs->timers.required_min_rx / 1000);
399 vty_out(vty, "\t\t\tTransmission interval: %" PRIu32 "ms\n",
400 bs->timers.desired_min_tx / 1000);
401
402 vty_out(vty, "\t\t\tEcho transmission interval: ");
403 if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO))
404 vty_out(vty, "%" PRIu32 "ms\n",
405 bs->timers.required_min_echo / 1000);
406 else
407 vty_out(vty, "disabled\n");
408
409 vty_out(vty, "\t\tRemote timers:\n");
410 vty_out(vty, "\t\t\tReceive interval: %" PRIu32 "ms\n",
411 bs->remote_timers.required_min_rx / 1000);
412 vty_out(vty, "\t\t\tTransmission interval: %" PRIu32 "ms\n",
413 bs->remote_timers.desired_min_tx / 1000);
414 vty_out(vty, "\t\t\tEcho transmission interval: %" PRIu32 "ms\n",
415 bs->remote_timers.required_min_echo / 1000);
416
417 vty_out(vty, "\n");
418 }
419
420 static struct json_object *__display_peer_json(struct bfd_session *bs)
421 {
422 struct json_object *jo = json_object_new_object();
423
424 if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) {
425 json_object_boolean_true_add(jo, "multihop");
426 json_object_string_add(jo, "peer", satostr(&bs->mhop.peer));
427 json_object_string_add(jo, "local", satostr(&bs->mhop.local));
428 if (bs->mhop.vrf_name[0])
429 json_object_string_add(jo, "vrf", bs->mhop.vrf_name);
430 } else {
431 json_object_boolean_false_add(jo, "multihop");
432 json_object_string_add(jo, "peer", satostr(&bs->shop.peer));
433 if (bs->shop.port_name[0])
434 json_object_string_add(jo, "interface",
435 bs->shop.port_name);
436 }
437
438 if (bs->pl)
439 json_object_string_add(jo, "label", bs->pl->pl_label);
440
441 json_object_int_add(jo, "id", bs->discrs.my_discr);
442 json_object_int_add(jo, "remote-id", bs->discrs.remote_discr);
443
444 switch (bs->ses_state) {
445 case PTM_BFD_ADM_DOWN:
446 json_object_string_add(jo, "status", "shutdown");
447 break;
448 case PTM_BFD_DOWN:
449 json_object_string_add(jo, "status", "down");
450 json_object_int_add(jo, "downtime",
451 monotime(NULL) - bs->uptime.tv_sec);
452 break;
453 case PTM_BFD_INIT:
454 json_object_string_add(jo, "status", "init");
455 break;
456 case PTM_BFD_UP:
457 json_object_string_add(jo, "status", "up");
458 json_object_int_add(jo, "uptime",
459 monotime(NULL) - bs->uptime.tv_sec);
460 break;
461
462 default:
463 json_object_string_add(jo, "status", "unknown");
464 break;
465 }
466
467 json_object_string_add(jo, "diagnostic", diag2str(bs->local_diag));
468 json_object_string_add(jo, "remote-diagnostic",
469 diag2str(bs->remote_diag));
470
471 json_object_int_add(jo, "receive-interval",
472 bs->timers.required_min_rx / 1000);
473 json_object_int_add(jo, "transmit-interval",
474 bs->timers.desired_min_tx / 1000);
475 if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO))
476 json_object_int_add(jo, "echo-interval",
477 bs->timers.required_min_echo / 1000);
478 else
479 json_object_int_add(jo, "echo-interval", 0);
480
481 json_object_int_add(jo, "remote-receive-interval",
482 bs->remote_timers.required_min_rx / 1000);
483 json_object_int_add(jo, "remote-transmit-interval",
484 bs->remote_timers.desired_min_tx / 1000);
485 json_object_int_add(jo, "remote-echo-interval",
486 bs->remote_timers.required_min_echo / 1000);
487
488 return jo;
489 }
490
491 static void _display_peer_json(struct vty *vty, struct bfd_session *bs)
492 {
493 struct json_object *jo = __display_peer_json(bs);
494
495 vty_out(vty, "%s\n", json_object_to_json_string_ext(jo, 0));
496 json_object_free(jo);
497 }
498
499 static void _display_peer_iter(struct hash_backet *hb, void *arg)
500 {
501 struct vty *vty = arg;
502 struct bfd_session *bs = hb->data;
503
504 _display_peer(vty, bs);
505 }
506
507 static void _display_peer_json_iter(struct hash_backet *hb, void *arg)
508 {
509 struct json_object *jo = arg, *jon = NULL;
510 struct bfd_session *bs = hb->data;
511
512 jon = __display_peer_json(bs);
513 if (jon == NULL) {
514 log_warning("%s: not enough memory", __func__);
515 return;
516 }
517
518 json_object_array_add(jo, jon);
519 }
520
521 static void _display_all_peers(struct vty *vty, bool use_json)
522 {
523 struct json_object *jo;
524
525 if (use_json == false) {
526 bfd_id_iterate(_display_peer_iter, vty);
527 return;
528 }
529
530 jo = json_object_new_array();
531 bfd_id_iterate(_display_peer_json_iter, jo);
532
533 vty_out(vty, "%s\n", json_object_to_json_string_ext(jo, 0));
534 json_object_free(jo);
535 }
536
537 DEFPY(bfd_show_peers, bfd_show_peers_cmd, "show bfd peers [json]",
538 SHOW_STR
539 "Bidirection Forwarding Detection\n"
540 "BFD peers status\n"
541 JSON_STR)
542 {
543 bool json = use_json(argc, argv);
544
545 if (json) {
546 _display_all_peers(vty, true);
547 } else {
548 vty_out(vty, "BFD Peers:\n");
549 _display_all_peers(vty, false);
550 }
551
552 return CMD_SUCCESS;
553 }
554
555 DEFPY(bfd_show_peer, bfd_show_peer_cmd,
556 "show bfd 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|vrf NAME$vrfname}]> [json]",
557 SHOW_STR
558 "Bidirection Forwarding Detection\n"
559 "BFD peers status\n"
560 "Peer label\n"
561 PEER_IPV4_STR PEER_IPV6_STR
562 MHOP_STR
563 LOCAL_STR LOCAL_IPV4_STR LOCAL_IPV6_STR
564 INTERFACE_STR
565 LOCAL_INTF_STR
566 VRF_STR VRF_NAME_STR
567 JSON_STR)
568 {
569 int idx;
570 bool mhop;
571 struct bfd_session *bs = NULL;
572 struct peer_label *pl;
573 struct bfd_peer_cfg bpc;
574 struct sockaddr_any psa, lsa, *lsap;
575 char errormsg[128];
576
577 /* Look up the BFD peer. */
578 if (label) {
579 pl = pl_find(label);
580 if (pl)
581 bs = pl->pl_bs;
582 } else {
583 strtosa(peer_str, &psa);
584 if (local) {
585 strtosa(local_str, &lsa);
586 lsap = &lsa;
587 } else
588 lsap = NULL;
589
590 idx = 0;
591 mhop = argv_find(argv, argc, "multihop", &idx);
592
593 if (bfd_configure_peer(&bpc, mhop, &psa, lsap, ifname, vrfname,
594 errormsg, sizeof(errormsg))
595 != 0) {
596 vty_out(vty, "%% Invalid peer configuration: %s\n",
597 errormsg);
598 return CMD_WARNING_CONFIG_FAILED;
599 }
600
601 bs = bs_peer_find(&bpc);
602 }
603
604 /* Find peer data. */
605 if (bs == NULL) {
606 vty_out(vty, "%% Unable to find 'peer %s",
607 label ? label : peer_str);
608 if (ifname)
609 vty_out(vty, " interface %s", ifname);
610 if (local)
611 vty_out(vty, " local-address %s", local_str);
612 if (vrfname)
613 vty_out(vty, " vrf %s", vrfname);
614 vty_out(vty, "'\n");
615
616 return CMD_WARNING_CONFIG_FAILED;
617 }
618
619 if (use_json(argc, argv)) {
620 _display_peer_json(vty, bs);
621 } else {
622 vty_out(vty, "BFD Peer:\n");
623 _display_peer(vty, bs);
624 }
625
626 return CMD_SUCCESS;
627 }
628
629
630 /*
631 * Function definitions.
632 */
633
634 /*
635 * Configuration rules:
636 *
637 * Single hop:
638 * peer + (optional vxlan or interface name)
639 *
640 * Multi hop:
641 * peer + local + (optional vrf)
642 *
643 * Anything else is misconfiguration.
644 */
645 static int bfd_configure_peer(struct bfd_peer_cfg *bpc, bool mhop,
646 const struct sockaddr_any *peer,
647 const struct sockaddr_any *local,
648 const char *ifname, const char *vrfname,
649 char *ebuf, size_t ebuflen)
650 {
651 memset(bpc, 0, sizeof(*bpc));
652
653 /* Defaults */
654 bpc->bpc_shutdown = true;
655 bpc->bpc_detectmultiplier = BPC_DEF_DETECTMULTIPLIER;
656 bpc->bpc_recvinterval = BPC_DEF_RECEIVEINTERVAL;
657 bpc->bpc_txinterval = BPC_DEF_TRANSMITINTERVAL;
658 bpc->bpc_echointerval = BPC_DEF_ECHOINTERVAL;
659 bpc->bpc_lastevent = monotime(NULL);
660
661 /* Safety check: when no error buf is provided len must be zero. */
662 if (ebuf == NULL)
663 ebuflen = 0;
664
665 /* Peer is always mandatory. */
666 if (peer == NULL) {
667 snprintf(ebuf, ebuflen, "peer must not be empty");
668 return -1;
669 }
670
671 /* Validate address families. */
672 if (peer->sa_sin.sin_family == AF_INET) {
673 if (local && local->sa_sin.sin_family != AF_INET) {
674 snprintf(ebuf, ebuflen,
675 "local is IPv6, but peer is IPv4");
676 return -1;
677 }
678
679 bpc->bpc_ipv4 = true;
680 } else if (peer->sa_sin.sin_family == AF_INET6) {
681 if (local && local->sa_sin.sin_family != AF_INET6) {
682 snprintf(ebuf, ebuflen,
683 "local is IPv4, but peer is IPv6");
684 return -1;
685 }
686
687 bpc->bpc_ipv4 = false;
688 } else {
689 snprintf(ebuf, ebuflen, "invalid peer address family");
690 return -1;
691 }
692
693 /* Copy local and/or peer addresses. */
694 if (local)
695 bpc->bpc_local = *local;
696
697 if (peer) {
698 bpc->bpc_peer = *peer;
699 } else {
700 /* Peer configuration is mandatory. */
701 snprintf(ebuf, ebuflen, "no peer configured");
702 return -1;
703 }
704
705 bpc->bpc_mhop = mhop;
706
707 #if 0
708 /* Handle VxLAN configuration. */
709 if (vxlan >= 0) {
710 if (vxlan > ((1 << 24) - 1)) {
711 snprintf(ebuf, ebuflen, "invalid VxLAN %d", vxlan);
712 return -1;
713 }
714 if (bpc->bpc_mhop) {
715 snprintf(ebuf, ebuflen,
716 "multihop doesn't accept VxLAN");
717 return -1;
718 }
719
720 bpc->bpc_vxlan = vxlan;
721 }
722 #endif /* VxLAN */
723
724 /* Handle interface specification configuration. */
725 if (ifname) {
726 if (bpc->bpc_mhop) {
727 snprintf(ebuf, ebuflen,
728 "multihop doesn't accept interface names");
729 return -1;
730 }
731
732 bpc->bpc_has_localif = true;
733 if (strlcpy(bpc->bpc_localif, ifname, sizeof(bpc->bpc_localif))
734 > sizeof(bpc->bpc_localif)) {
735 snprintf(ebuf, ebuflen, "interface name too long");
736 return -1;
737 }
738 }
739
740 /* Handle VRF configuration. */
741 if (vrfname) {
742 bpc->bpc_has_vrfname = true;
743 if (strlcpy(bpc->bpc_vrfname, vrfname, sizeof(bpc->bpc_vrfname))
744 > sizeof(bpc->bpc_vrfname)) {
745 snprintf(ebuf, ebuflen, "vrf name too long");
746 return -1;
747 }
748 }
749
750 return 0;
751 }
752 static int bfdd_write_config(struct vty *vty)
753 {
754 vty_out(vty, "bfd\n");
755 vty_out(vty, "!\n");
756 return 0;
757 }
758
759 static void _bfdd_peer_write_config(struct hash_backet *hb, void *arg)
760 {
761 struct vty *vty = arg;
762 struct bfd_session *bs = hb->data;
763
764 if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) {
765 vty_out(vty, " peer %s", satostr(&bs->mhop.peer));
766 vty_out(vty, " multihop");
767 vty_out(vty, " local-address %s", satostr(&bs->mhop.local));
768 if (bs->mhop.vrf_name[0])
769 vty_out(vty, " vrf %s", bs->mhop.vrf_name);
770 vty_out(vty, "\n");
771 } else {
772 vty_out(vty, " peer %s", satostr(&bs->shop.peer));
773 if (bs->local_address.sa_sin.sin_family != AF_UNSPEC)
774 vty_out(vty, " local-address %s",
775 satostr(&bs->local_address));
776 if (bs->shop.port_name[0])
777 vty_out(vty, " interface %s", bs->shop.port_name);
778 vty_out(vty, "\n");
779 }
780
781 if (bs->detect_mult != BPC_DEF_DETECTMULTIPLIER)
782 vty_out(vty, " detect-multiplier %d\n", bs->detect_mult);
783 if (bs->timers.required_min_rx != (BPC_DEF_RECEIVEINTERVAL * 1000))
784 vty_out(vty, " receive-interval %" PRIu32 "\n",
785 bs->timers.required_min_rx / 1000);
786 if (bs->timers.desired_min_tx != (BPC_DEF_TRANSMITINTERVAL * 1000))
787 vty_out(vty, " transmit-interval %" PRIu32 "\n",
788 bs->timers.desired_min_tx / 1000);
789 if (bs->timers.required_min_echo != (BPC_DEF_ECHOINTERVAL * 1000))
790 vty_out(vty, " echo-interval %" PRIu32 "\n",
791 bs->timers.required_min_echo / 1000);
792 if (bs->pl)
793 vty_out(vty, " label %s\n", bs->pl->pl_label);
794 if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO))
795 vty_out(vty, " echo-mode\n");
796
797 vty_out(vty, " %sshutdown\n",
798 BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN) ? "" : "no ");
799
800 vty_out(vty, " !\n");
801 }
802
803 static int bfdd_peer_write_config(struct vty *vty)
804 {
805 bfd_id_iterate(_bfdd_peer_write_config, vty);
806 return 1;
807 }
808
809 struct cmd_node bfd_node = {
810 BFD_NODE,
811 "%s(config-bfd)# ",
812 1,
813 };
814
815 struct cmd_node bfd_peer_node = {
816 BFD_PEER_NODE,
817 "%s(config-bfd-peer)# ",
818 1,
819 };
820
821 void bfdd_vty_init(void)
822 {
823 install_element(ENABLE_NODE, &bfd_show_peers_cmd);
824 install_element(ENABLE_NODE, &bfd_show_peer_cmd);
825 install_element(CONFIG_NODE, &bfd_enter_cmd);
826
827 /* Install BFD node and commands. */
828 install_node(&bfd_node, bfdd_write_config);
829 install_default(BFD_NODE);
830 install_element(BFD_NODE, &bfd_peer_enter_cmd);
831 install_element(BFD_NODE, &bfd_no_peer_cmd);
832
833 /* Install BFD peer node. */
834 install_node(&bfd_peer_node, bfdd_peer_write_config);
835 install_default(BFD_PEER_NODE);
836 install_element(BFD_PEER_NODE, &bfd_peer_detectmultiplier_cmd);
837 install_element(BFD_PEER_NODE, &bfd_peer_recvinterval_cmd);
838 install_element(BFD_PEER_NODE, &bfd_peer_txinterval_cmd);
839 install_element(BFD_PEER_NODE, &bfd_peer_echointerval_cmd);
840 install_element(BFD_PEER_NODE, &bfd_peer_shutdown_cmd);
841 install_element(BFD_PEER_NODE, &bfd_peer_echo_cmd);
842 install_element(BFD_PEER_NODE, &bfd_peer_label_cmd);
843 }