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