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