]> git.proxmox.com Git - mirror_frr.git/blame - bfdd/bfdd_vty.c
bfdd: don't poll to make echo/multiplier changes
[mirror_frr.git] / bfdd / bfdd_vty.c
CommitLineData
c2f29cf3
RZ
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 */
52static int bfdd_write_config(struct vty *vty);
53static int bfdd_peer_write_config(struct vty *vty);
54static void _bfdd_peer_write_config(struct hash_backet *hb, void *arg);
55static 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
89a634c1 61static void _display_peer_header(struct vty *vty, struct bfd_session *bs);
c2f29cf3 62static struct json_object *__display_peer_json(struct bfd_session *bs);
89a634c1 63static struct json_object *_peer_json_header(struct bfd_session *bs);
c2f29cf3
RZ
64static void _display_peer_json(struct vty *vty, struct bfd_session *bs);
65static void _display_peer(struct vty *vty, struct bfd_session *bs);
66static void _display_all_peers(struct vty *vty, bool use_json);
67static void _display_peer_iter(struct hash_backet *hb, void *arg);
68static void _display_peer_json_iter(struct hash_backet *hb, void *arg);
0684c9b1
RZ
69static void _display_peer_counter(struct vty *vty, struct bfd_session *bs);
70static struct json_object *__display_peer_counters_json(struct bfd_session *bs);
71static void _display_peer_counters_json(struct vty *vty, struct bfd_session *bs);
72static void _display_peer_counter_iter(struct hash_backet *hb, void *arg);
73static void _display_peer_counter_json_iter(struct hash_backet *hb, void *arg);
74static void _display_peers_counter(struct vty *vty, bool use_json);
89a634c1
RZ
75static struct bfd_session *
76_find_peer_or_error(struct vty *vty, int argc, struct cmd_token **argv,
77 const char *label, const char *peer_str,
78 const char *local_str, const char *ifname,
79 const char *vrfname);
c2f29cf3
RZ
80
81
82/*
83 * Commands definition.
84 */
85DEFUN_NOSH(bfd_enter, bfd_enter_cmd, "bfd", "Configure BFD peers\n")
86{
87 vty->node = BFD_NODE;
88 return CMD_SUCCESS;
89}
90
91DEFUN_NOSH(
92 bfd_peer_enter, bfd_peer_enter_cmd,
affa816b 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}]",
c2f29cf3
RZ
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 VTY_PUSH_CONTEXT(BFD_PEER_NODE, bs);
158
159 return CMD_SUCCESS;
160}
161
162DEFPY(bfd_peer_detectmultiplier, bfd_peer_detectmultiplier_cmd,
163 "detect-multiplier (2-255)$multiplier",
164 "Configure peer detection multiplier\n"
165 "Configure peer detection multiplier value\n")
166{
167 struct bfd_session *bs;
168
169 bs = VTY_GET_CONTEXT(bfd_session);
d3f3a2c4
RZ
170 if (bs->detect_mult == multiplier)
171 return CMD_SUCCESS;
172
c2f29cf3
RZ
173 bs->detect_mult = multiplier;
174
175 return CMD_SUCCESS;
176}
177
178DEFPY(bfd_peer_recvinterval, bfd_peer_recvinterval_cmd,
179 "receive-interval (10-60000)$interval",
180 "Configure peer receive interval\n"
181 "Configure peer receive interval value in milliseconds\n")
182{
183 struct bfd_session *bs;
184
185 bs = VTY_GET_CONTEXT(bfd_session);
d3f3a2c4
RZ
186 if (bs->timers.required_min_rx == (uint32_t)(interval * 1000))
187 return CMD_SUCCESS;
188
c2f29cf3 189 bs->timers.required_min_rx = interval * 1000;
d3f3a2c4 190 bfd_set_polling(bs);
c2f29cf3
RZ
191
192 return CMD_SUCCESS;
193}
194
195DEFPY(bfd_peer_txinterval, bfd_peer_txinterval_cmd,
196 "transmit-interval (10-60000)$interval",
197 "Configure peer transmit interval\n"
198 "Configure peer transmit interval value in milliseconds\n")
199{
200 struct bfd_session *bs;
201
202 bs = VTY_GET_CONTEXT(bfd_session);
d3f3a2c4
RZ
203 if (bs->up_min_tx == (uint32_t)(interval * 1000))
204 return CMD_SUCCESS;
205
c2f29cf3 206 bs->up_min_tx = interval * 1000;
d3f3a2c4 207 bfd_set_polling(bs);
c2f29cf3
RZ
208
209 return CMD_SUCCESS;
210}
211
212DEFPY(bfd_peer_echointerval, bfd_peer_echointerval_cmd,
213 "echo-interval (10-60000)$interval",
214 "Configure peer echo interval\n"
215 "Configure peer echo interval value in milliseconds\n")
216{
217 struct bfd_session *bs;
218
219 bs = VTY_GET_CONTEXT(bfd_session);
d3f3a2c4
RZ
220 if (bs->timers.required_min_echo == (uint32_t)(interval * 1000))
221 return CMD_SUCCESS;
222
c2f29cf3
RZ
223 bs->timers.required_min_echo = interval * 1000;
224
225 return CMD_SUCCESS;
226}
227
228DEFPY(bfd_peer_shutdown, bfd_peer_shutdown_cmd, "[no] shutdown",
229 NO_STR "Disable BFD peer")
230{
231 struct bfd_session *bs;
232
233 bs = VTY_GET_CONTEXT(bfd_session);
234 if (no) {
235 if (!BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN))
236 return CMD_SUCCESS;
237
238 BFD_UNSET_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN);
239
240 /* Change and notify state change. */
241 bs->ses_state = PTM_BFD_DOWN;
242 control_notify(bs);
243
244 /* Enable all timers. */
245 bfd_recvtimer_update(bs);
246 bfd_xmttimer_update(bs, bs->xmt_TO);
247 if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO)) {
248 bfd_echo_recvtimer_update(bs);
249 bfd_echo_xmttimer_update(bs, bs->echo_xmt_TO);
250 }
251 } else {
252 if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN))
253 return CMD_SUCCESS;
254
255 BFD_SET_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN);
256
257 /* Disable all events. */
258 bfd_recvtimer_delete(bs);
259 bfd_echo_recvtimer_delete(bs);
260 bfd_xmttimer_delete(bs);
261 bfd_echo_xmttimer_delete(bs);
262
263 /* Change and notify state change. */
264 bs->ses_state = PTM_BFD_ADM_DOWN;
265 control_notify(bs);
266
267 ptm_bfd_snd(bs, 0);
268 }
269
270 return CMD_SUCCESS;
271}
272
273DEFPY(bfd_peer_echo, bfd_peer_echo_cmd, "[no] echo-mode",
274 NO_STR "Configure echo mode\n")
275{
276 struct bfd_session *bs;
277
278 bs = VTY_GET_CONTEXT(bfd_session);
279 if (no) {
280 if (!BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO))
281 return CMD_SUCCESS;
282
283 BFD_UNSET_FLAG(bs->flags, BFD_SESS_FLAG_ECHO);
8bd859f6 284 ptm_bfd_echo_stop(bs);
c2f29cf3
RZ
285 } else {
286 if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO))
287 return CMD_SUCCESS;
288
289 BFD_SET_FLAG(bs->flags, BFD_SESS_FLAG_ECHO);
290 /* Apply setting immediately. */
291 if (!BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN)) {
73c62f8e 292 bs_echo_timer_handler(bs);
c2f29cf3
RZ
293 }
294 }
295
296 return CMD_SUCCESS;
297}
298
299DEFPY(bfd_peer_label, bfd_peer_label_cmd, "label WORD$label",
300 "Register peer label\n"
301 "Register peer label identification\n")
302{
303 struct bfd_session *bs;
304
305 /* Validate label length. */
306 if (strlen(label) >= MAXNAMELEN) {
307 vty_out(vty, "%% Label name is too long\n");
308 return CMD_WARNING_CONFIG_FAILED;
309 }
310
311 bs = VTY_GET_CONTEXT(bfd_session);
312 if (bfd_session_update_label(bs, label) == -1) {
313 vty_out(vty, "%% Failed to update peer label.\n");
314 return CMD_WARNING_CONFIG_FAILED;
315 }
316
317 return CMD_SUCCESS;
318}
319
320DEFPY(bfd_no_peer, bfd_no_peer_cmd,
321 "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}]",
322 NO_STR
323 PEER_STR PEER_IPV4_STR PEER_IPV6_STR
324 MHOP_STR
325 LOCAL_STR LOCAL_IPV4_STR LOCAL_IPV6_STR
326 INTERFACE_STR
327 LOCAL_INTF_STR
328 VRF_STR VRF_NAME_STR)
329{
330 int idx;
331 bool mhop;
332 struct bfd_peer_cfg bpc;
333 struct sockaddr_any psa, lsa, *lsap;
334 char errormsg[128];
335
336 strtosa(peer_str, &psa);
337 if (local) {
338 strtosa(local_str, &lsa);
339 lsap = &lsa;
340 } else {
341 lsap = NULL;
342 }
343
344 idx = 0;
345 mhop = argv_find(argv, argc, "multihop", &idx);
346
347 if (bfd_configure_peer(&bpc, mhop, &psa, lsap, ifname, vrfname,
348 errormsg, sizeof(errormsg))
349 != 0) {
350 vty_out(vty, "%% Invalid peer configuration: %s\n", errormsg);
351 return CMD_WARNING_CONFIG_FAILED;
352 }
353
354 if (ptm_bfd_ses_del(&bpc) != 0) {
355 vty_out(vty, "%% Failed to remove peer.\n");
356 return CMD_WARNING_CONFIG_FAILED;
357 }
358
359 return CMD_SUCCESS;
360}
361
362
363/*
364 * Show commands helper functions
365 */
89a634c1 366static void _display_peer_header(struct vty *vty, struct bfd_session *bs)
c2f29cf3 367{
c2f29cf3
RZ
368 if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) {
369 vty_out(vty, "\tpeer %s", satostr(&bs->mhop.peer));
370 vty_out(vty, " multihop");
371 vty_out(vty, " local-address %s", satostr(&bs->mhop.local));
372 if (bs->mhop.vrf_name[0])
373 vty_out(vty, " vrf %s", bs->mhop.vrf_name);
374 vty_out(vty, "\n");
375 } else {
f85498ef
RZ
376 vty_out(vty, "\tpeer %s", satostr(&bs->shop.peer));
377 if (bs->local_address.sa_sin.sin_family != AF_UNSPEC)
378 vty_out(vty, " local-address %s",
379 satostr(&bs->local_address));
c2f29cf3
RZ
380 if (bs->shop.port_name[0])
381 vty_out(vty, " interface %s", bs->shop.port_name);
382 vty_out(vty, "\n");
383 }
384
385 if (bs->pl)
386 vty_out(vty, "\t\tlabel: %s\n", bs->pl->pl_label);
89a634c1
RZ
387}
388
389static void _display_peer(struct vty *vty, struct bfd_session *bs)
390{
391 char buf[256];
392 time_t now;
393
394 _display_peer_header(vty, bs);
c2f29cf3
RZ
395
396 vty_out(vty, "\t\tID: %u\n", bs->discrs.my_discr);
397 vty_out(vty, "\t\tRemote ID: %u\n", bs->discrs.remote_discr);
398
399 vty_out(vty, "\t\tStatus: ");
400 switch (bs->ses_state) {
401 case PTM_BFD_ADM_DOWN:
402 vty_out(vty, "shutdown\n");
403 break;
404 case PTM_BFD_DOWN:
405 vty_out(vty, "down\n");
406
407 now = monotime(NULL);
98ef9c16 408 integer2timestr(now - bs->downtime.tv_sec, buf, sizeof(buf));
c2f29cf3
RZ
409 vty_out(vty, "\t\tDowntime: %s\n", buf);
410 break;
411 case PTM_BFD_INIT:
412 vty_out(vty, "init\n");
413 break;
414 case PTM_BFD_UP:
415 vty_out(vty, "up\n");
416
417 now = monotime(NULL);
418 integer2timestr(now - bs->uptime.tv_sec, buf, sizeof(buf));
419 vty_out(vty, "\t\tUptime: %s\n", buf);
420 break;
421
422 default:
423 vty_out(vty, "unknown\n");
424 break;
425 }
426
427 vty_out(vty, "\t\tDiagnostics: %s\n", diag2str(bs->local_diag));
428 vty_out(vty, "\t\tRemote diagnostics: %s\n", diag2str(bs->remote_diag));
429
430 vty_out(vty, "\t\tLocal timers:\n");
431 vty_out(vty, "\t\t\tReceive interval: %" PRIu32 "ms\n",
432 bs->timers.required_min_rx / 1000);
674680df 433 vty_out(vty, "\t\t\tTransmission interval: %" PRIu32 "ms",
c2f29cf3 434 bs->timers.desired_min_tx / 1000);
674680df 435 if (bs->up_min_tx != bs->timers.desired_min_tx)
89a634c1 436 vty_out(vty, " (configured %" PRIu32 "ms)\n",
674680df
RZ
437 bs->up_min_tx / 1000);
438 else
439 vty_out(vty, "\n");
c2f29cf3
RZ
440
441 vty_out(vty, "\t\t\tEcho transmission interval: ");
442 if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO))
443 vty_out(vty, "%" PRIu32 "ms\n",
444 bs->timers.required_min_echo / 1000);
445 else
446 vty_out(vty, "disabled\n");
447
448 vty_out(vty, "\t\tRemote timers:\n");
449 vty_out(vty, "\t\t\tReceive interval: %" PRIu32 "ms\n",
450 bs->remote_timers.required_min_rx / 1000);
451 vty_out(vty, "\t\t\tTransmission interval: %" PRIu32 "ms\n",
452 bs->remote_timers.desired_min_tx / 1000);
453 vty_out(vty, "\t\t\tEcho transmission interval: %" PRIu32 "ms\n",
454 bs->remote_timers.required_min_echo / 1000);
455
456 vty_out(vty, "\n");
457}
458
89a634c1 459static struct json_object *_peer_json_header(struct bfd_session *bs)
c2f29cf3
RZ
460{
461 struct json_object *jo = json_object_new_object();
462
463 if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) {
464 json_object_boolean_true_add(jo, "multihop");
465 json_object_string_add(jo, "peer", satostr(&bs->mhop.peer));
466 json_object_string_add(jo, "local", satostr(&bs->mhop.local));
467 if (bs->mhop.vrf_name[0])
468 json_object_string_add(jo, "vrf", bs->mhop.vrf_name);
469 } else {
470 json_object_boolean_false_add(jo, "multihop");
471 json_object_string_add(jo, "peer", satostr(&bs->shop.peer));
f85498ef
RZ
472 if (bs->local_address.sa_sin.sin_family != AF_UNSPEC)
473 json_object_string_add(jo, "local",
474 satostr(&bs->local_address));
c2f29cf3
RZ
475 if (bs->shop.port_name[0])
476 json_object_string_add(jo, "interface",
477 bs->shop.port_name);
478 }
479
480 if (bs->pl)
481 json_object_string_add(jo, "label", bs->pl->pl_label);
482
89a634c1
RZ
483 return jo;
484}
485
486static struct json_object *__display_peer_json(struct bfd_session *bs)
487{
488 struct json_object *jo = _peer_json_header(bs);
489
c2f29cf3
RZ
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",
98ef9c16 500 monotime(NULL) - bs->downtime.tv_sec);
c2f29cf3
RZ
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
540static 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
548static void _display_peer_iter(struct hash_backet *hb, void *arg)
549{
550 struct vty *vty = arg;
551 struct bfd_session *bs = hb->data;
552
553 _display_peer(vty, bs);
554}
555
556static void _display_peer_json_iter(struct hash_backet *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
570static void _display_all_peers(struct vty *vty, bool use_json)
571{
572 struct json_object *jo;
573
574 if (use_json == false) {
89a634c1 575 vty_out(vty, "BFD Peers:\n");
c2f29cf3
RZ
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
0684c9b1
RZ
587static 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
608static 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
623static 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
631static void _display_peer_counter_iter(struct hash_backet *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
639static void _display_peer_counter_json_iter(struct hash_backet *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
653static void _display_peers_counter(struct vty *vty, bool use_json)
654{
655 struct json_object *jo;
656
657 if (use_json == false) {
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
89a634c1
RZ
670static 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)
c2f29cf3
RZ
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);
89a634c1 691 if (local_str) {
c2f29cf3
RZ
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);
89a634c1 705 return NULL;
c2f29cf3
RZ
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);
89a634c1 717 if (local_str)
c2f29cf3
RZ
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
89a634c1 723 return NULL;
c2f29cf3
RZ
724 }
725
89a634c1
RZ
726 return bs;
727}
728
729
730/*
731 * Show commands.
732 */
733DEFPY(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
743DEFPY(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
c2f29cf3
RZ
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
0684c9b1
RZ
770DEFPY(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
805DEFPY(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
c2f29cf3
RZ
818
819/*
820 * Function definitions.
821 */
822
823/*
824 * Configuration rules:
825 *
826 * Single hop:
8a9f760e 827 * peer + (interface name)
c2f29cf3
RZ
828 *
829 * Multi hop:
830 * peer + local + (optional vrf)
831 *
832 * Anything else is misconfiguration.
833 */
834static 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
4848ef74 886 bpc->bpc_peer = *peer;
c2f29cf3
RZ
887 bpc->bpc_mhop = mhop;
888
c2f29cf3
RZ
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}
917static int bfdd_write_config(struct vty *vty)
918{
919 vty_out(vty, "bfd\n");
920 vty_out(vty, "!\n");
921 return 0;
922}
923
924static void _bfdd_peer_write_config(struct hash_backet *hb, void *arg)
925{
926 struct vty *vty = arg;
927 struct bfd_session *bs = hb->data;
928
929 if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) {
930 vty_out(vty, " peer %s", satostr(&bs->mhop.peer));
931 vty_out(vty, " multihop");
932 vty_out(vty, " local-address %s", satostr(&bs->mhop.local));
933 if (bs->mhop.vrf_name[0])
934 vty_out(vty, " vrf %s", bs->mhop.vrf_name);
935 vty_out(vty, "\n");
936 } else {
937 vty_out(vty, " peer %s", satostr(&bs->shop.peer));
938 if (bs->local_address.sa_sin.sin_family != AF_UNSPEC)
939 vty_out(vty, " local-address %s",
940 satostr(&bs->local_address));
941 if (bs->shop.port_name[0])
942 vty_out(vty, " interface %s", bs->shop.port_name);
943 vty_out(vty, "\n");
944 }
945
946 if (bs->detect_mult != BPC_DEF_DETECTMULTIPLIER)
947 vty_out(vty, " detect-multiplier %d\n", bs->detect_mult);
948 if (bs->timers.required_min_rx != (BPC_DEF_RECEIVEINTERVAL * 1000))
949 vty_out(vty, " receive-interval %" PRIu32 "\n",
950 bs->timers.required_min_rx / 1000);
674680df 951 if (bs->up_min_tx != (BPC_DEF_TRANSMITINTERVAL * 1000))
c2f29cf3 952 vty_out(vty, " transmit-interval %" PRIu32 "\n",
674680df 953 bs->up_min_tx / 1000);
c2f29cf3
RZ
954 if (bs->timers.required_min_echo != (BPC_DEF_ECHOINTERVAL * 1000))
955 vty_out(vty, " echo-interval %" PRIu32 "\n",
956 bs->timers.required_min_echo / 1000);
957 if (bs->pl)
958 vty_out(vty, " label %s\n", bs->pl->pl_label);
959 if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO))
960 vty_out(vty, " echo-mode\n");
961
962 vty_out(vty, " %sshutdown\n",
963 BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN) ? "" : "no ");
964
965 vty_out(vty, " !\n");
966}
967
a244e599
DS
968DEFUN_NOSH(show_debugging_bfd,
969 show_debugging_bfd_cmd,
970 "show debugging [bfd]",
971 SHOW_STR
972 DEBUG_STR
973 "BFD daemon\n")
974{
975 vty_out(vty, "BFD debugging status:\n");
976
977 return CMD_SUCCESS;
978}
979
c2f29cf3
RZ
980static int bfdd_peer_write_config(struct vty *vty)
981{
982 bfd_id_iterate(_bfdd_peer_write_config, vty);
983 return 1;
984}
985
986struct cmd_node bfd_node = {
987 BFD_NODE,
988 "%s(config-bfd)# ",
989 1,
990};
991
992struct cmd_node bfd_peer_node = {
993 BFD_PEER_NODE,
994 "%s(config-bfd-peer)# ",
995 1,
996};
997
998void bfdd_vty_init(void)
999{
0684c9b1
RZ
1000 install_element(ENABLE_NODE, &bfd_show_peers_counters_cmd);
1001 install_element(ENABLE_NODE, &bfd_show_peer_counters_cmd);
c2f29cf3
RZ
1002 install_element(ENABLE_NODE, &bfd_show_peers_cmd);
1003 install_element(ENABLE_NODE, &bfd_show_peer_cmd);
1004 install_element(CONFIG_NODE, &bfd_enter_cmd);
a244e599 1005 install_element(ENABLE_NODE, &show_debugging_bfd_cmd);
c2f29cf3
RZ
1006
1007 /* Install BFD node and commands. */
1008 install_node(&bfd_node, bfdd_write_config);
1009 install_default(BFD_NODE);
1010 install_element(BFD_NODE, &bfd_peer_enter_cmd);
1011 install_element(BFD_NODE, &bfd_no_peer_cmd);
1012
1013 /* Install BFD peer node. */
1014 install_node(&bfd_peer_node, bfdd_peer_write_config);
1015 install_default(BFD_PEER_NODE);
1016 install_element(BFD_PEER_NODE, &bfd_peer_detectmultiplier_cmd);
1017 install_element(BFD_PEER_NODE, &bfd_peer_recvinterval_cmd);
1018 install_element(BFD_PEER_NODE, &bfd_peer_txinterval_cmd);
1019 install_element(BFD_PEER_NODE, &bfd_peer_echointerval_cmd);
1020 install_element(BFD_PEER_NODE, &bfd_peer_shutdown_cmd);
1021 install_element(BFD_PEER_NODE, &bfd_peer_echo_cmd);
1022 install_element(BFD_PEER_NODE, &bfd_peer_label_cmd);
1023}