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