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