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