]> git.proxmox.com Git - mirror_frr.git/blame - bfdd/bfdd_vty.c
bfdd: add show bfd [vrf NAME] peers command
[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);
9146cc2a 67static void _display_all_peers(struct vty *vty, char *vrfname, 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 81
c2f29cf3
RZ
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,
5764d816 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
c2f29cf3
RZ
129 strtosa(peer, &psa);
130 if (local) {
131 strtosa(local, &lsa);
132 lsap = &lsa;
133 } else
134 lsap = NULL;
135
136 if (bfd_configure_peer(&bpc, mhop, &psa, lsap, ifname, vrfname,
137 errormsg, sizeof(errormsg))
138 != 0) {
139 vty_out(vty, "%% Invalid peer configuration: %s\n", errormsg);
140 return CMD_WARNING_CONFIG_FAILED;
141 }
142
143 bs = bs_peer_find(&bpc);
144 if (bs == NULL) {
145 bs = ptm_bfd_sess_new(&bpc);
146 if (bs == NULL) {
147 vty_out(vty, "%% Failed to add peer.\n");
148 return CMD_WARNING_CONFIG_FAILED;
149 }
150 }
151
6bdb4a42
PG
152 if (!BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_CONFIG)) {
153 if (bs->refcount)
154 vty_out(vty, "%% session peer is now configurable via bfd daemon.\n");
155 BFD_SET_FLAG(bs->flags, BFD_SESS_FLAG_CONFIG);
156 }
157
c2f29cf3
RZ
158 VTY_PUSH_CONTEXT(BFD_PEER_NODE, bs);
159
160 return CMD_SUCCESS;
161}
162
163DEFPY(bfd_peer_detectmultiplier, bfd_peer_detectmultiplier_cmd,
164 "detect-multiplier (2-255)$multiplier",
165 "Configure peer detection multiplier\n"
166 "Configure peer detection multiplier value\n")
167{
168 struct bfd_session *bs;
169
170 bs = VTY_GET_CONTEXT(bfd_session);
d3f3a2c4
RZ
171 if (bs->detect_mult == multiplier)
172 return CMD_SUCCESS;
173
c2f29cf3
RZ
174 bs->detect_mult = multiplier;
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);
f43b9368 204 if (bs->timers.desired_min_tx == (uint32_t)(interval * 1000))
d3f3a2c4
RZ
205 return CMD_SUCCESS;
206
f43b9368 207 bs->timers.desired_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
RZ
224 bs->timers.required_min_echo = interval * 1000;
225
226 return CMD_SUCCESS;
227}
228
229DEFPY(bfd_peer_shutdown, bfd_peer_shutdown_cmd, "[no] shutdown",
230 NO_STR "Disable BFD peer")
231{
232 struct bfd_session *bs;
233
234 bs = VTY_GET_CONTEXT(bfd_session);
235 if (no) {
236 if (!BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN))
237 return CMD_SUCCESS;
238
239 BFD_UNSET_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN);
240
241 /* Change and notify state change. */
242 bs->ses_state = PTM_BFD_DOWN;
243 control_notify(bs);
244
245 /* Enable all timers. */
246 bfd_recvtimer_update(bs);
247 bfd_xmttimer_update(bs, bs->xmt_TO);
248 if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO)) {
249 bfd_echo_recvtimer_update(bs);
250 bfd_echo_xmttimer_update(bs, bs->echo_xmt_TO);
251 }
252 } else {
253 if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN))
254 return CMD_SUCCESS;
255
256 BFD_SET_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN);
257
258 /* Disable all events. */
259 bfd_recvtimer_delete(bs);
260 bfd_echo_recvtimer_delete(bs);
261 bfd_xmttimer_delete(bs);
262 bfd_echo_xmttimer_delete(bs);
263
264 /* Change and notify state change. */
265 bs->ses_state = PTM_BFD_ADM_DOWN;
266 control_notify(bs);
267
268 ptm_bfd_snd(bs, 0);
269 }
270
271 return CMD_SUCCESS;
272}
273
274DEFPY(bfd_peer_echo, bfd_peer_echo_cmd, "[no] echo-mode",
275 NO_STR "Configure echo mode\n")
276{
277 struct bfd_session *bs;
278
279 bs = VTY_GET_CONTEXT(bfd_session);
280 if (no) {
281 if (!BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO))
282 return CMD_SUCCESS;
283
284 BFD_UNSET_FLAG(bs->flags, BFD_SESS_FLAG_ECHO);
8bd859f6 285 ptm_bfd_echo_stop(bs);
c2f29cf3
RZ
286 } else {
287 if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO))
288 return CMD_SUCCESS;
289
290 BFD_SET_FLAG(bs->flags, BFD_SESS_FLAG_ECHO);
291 /* Apply setting immediately. */
9f37770f 292 if (!BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN))
73c62f8e 293 bs_echo_timer_handler(bs);
c2f29cf3
RZ
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
bc50bcc8 354 if (ptm_bfd_sess_del(&bpc) != 0) {
c2f29cf3
RZ
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{
79b4a6fc
RZ
368 char addr_buf[INET6_ADDRSTRLEN];
369
370 vty_out(vty, "\tpeer %s",
371 inet_ntop(bs->key.family, &bs->key.peer, addr_buf,
372 sizeof(addr_buf)));
373
374 if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH))
c2f29cf3 375 vty_out(vty, " multihop");
79b4a6fc
RZ
376
377 if (memcmp(&bs->key.local, &zero_addr, sizeof(bs->key.local)))
378 vty_out(vty, " local-address %s",
379 inet_ntop(bs->key.family, &bs->key.local, addr_buf,
380 sizeof(addr_buf)));
381
382 if (bs->key.vrfname[0])
383 vty_out(vty, " vrf %s", bs->key.vrfname);
384 if (bs->key.ifname[0])
385 vty_out(vty, " interface %s", bs->key.ifname);
386 vty_out(vty, "\n");
c2f29cf3
RZ
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);
f43b9368 436 vty_out(vty, "\t\t\tTransmission interval: %" PRIu32 "ms\n",
c2f29cf3 437 bs->timers.desired_min_tx / 1000);
f43b9368
RZ
438 vty_out(vty, "\t\t\tEcho transmission interval: %" PRIu32 "ms\n",
439 bs->timers.required_min_echo / 1000);
c2f29cf3
RZ
440
441 vty_out(vty, "\t\tRemote timers:\n");
442 vty_out(vty, "\t\t\tReceive interval: %" PRIu32 "ms\n",
443 bs->remote_timers.required_min_rx / 1000);
444 vty_out(vty, "\t\t\tTransmission interval: %" PRIu32 "ms\n",
445 bs->remote_timers.desired_min_tx / 1000);
446 vty_out(vty, "\t\t\tEcho transmission interval: %" PRIu32 "ms\n",
447 bs->remote_timers.required_min_echo / 1000);
448
449 vty_out(vty, "\n");
450}
451
89a634c1 452static struct json_object *_peer_json_header(struct bfd_session *bs)
c2f29cf3
RZ
453{
454 struct json_object *jo = json_object_new_object();
79b4a6fc 455 char addr_buf[INET6_ADDRSTRLEN];
c2f29cf3 456
79b4a6fc 457 if (bs->key.mhop)
c2f29cf3 458 json_object_boolean_true_add(jo, "multihop");
79b4a6fc 459 else
c2f29cf3 460 json_object_boolean_false_add(jo, "multihop");
79b4a6fc
RZ
461
462 json_object_string_add(jo, "peer",
463 inet_ntop(bs->key.family, &bs->key.peer,
464 addr_buf, sizeof(addr_buf)));
465 if (memcmp(&bs->key.local, &zero_addr, sizeof(bs->key.local)))
466 json_object_string_add(jo, "local",
467 inet_ntop(bs->key.family, &bs->key.local,
468 addr_buf, sizeof(addr_buf)));
469
470 if (bs->key.vrfname[0])
471 json_object_string_add(jo, "vrf", bs->key.vrfname);
472 if (bs->key.ifname[0])
473 json_object_string_add(jo, "interface", bs->key.ifname);
c2f29cf3
RZ
474
475 if (bs->pl)
476 json_object_string_add(jo, "label", bs->pl->pl_label);
477
89a634c1
RZ
478 return jo;
479}
480
481static struct json_object *__display_peer_json(struct bfd_session *bs)
482{
483 struct json_object *jo = _peer_json_header(bs);
484
c2f29cf3
RZ
485 json_object_int_add(jo, "id", bs->discrs.my_discr);
486 json_object_int_add(jo, "remote-id", bs->discrs.remote_discr);
487
488 switch (bs->ses_state) {
489 case PTM_BFD_ADM_DOWN:
490 json_object_string_add(jo, "status", "shutdown");
491 break;
492 case PTM_BFD_DOWN:
493 json_object_string_add(jo, "status", "down");
494 json_object_int_add(jo, "downtime",
98ef9c16 495 monotime(NULL) - bs->downtime.tv_sec);
c2f29cf3
RZ
496 break;
497 case PTM_BFD_INIT:
498 json_object_string_add(jo, "status", "init");
499 break;
500 case PTM_BFD_UP:
501 json_object_string_add(jo, "status", "up");
502 json_object_int_add(jo, "uptime",
503 monotime(NULL) - bs->uptime.tv_sec);
504 break;
505
506 default:
507 json_object_string_add(jo, "status", "unknown");
508 break;
509 }
510
511 json_object_string_add(jo, "diagnostic", diag2str(bs->local_diag));
512 json_object_string_add(jo, "remote-diagnostic",
513 diag2str(bs->remote_diag));
514
515 json_object_int_add(jo, "receive-interval",
516 bs->timers.required_min_rx / 1000);
517 json_object_int_add(jo, "transmit-interval",
518 bs->timers.desired_min_tx / 1000);
519 if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO))
520 json_object_int_add(jo, "echo-interval",
521 bs->timers.required_min_echo / 1000);
522 else
523 json_object_int_add(jo, "echo-interval", 0);
524
525 json_object_int_add(jo, "remote-receive-interval",
526 bs->remote_timers.required_min_rx / 1000);
527 json_object_int_add(jo, "remote-transmit-interval",
528 bs->remote_timers.desired_min_tx / 1000);
529 json_object_int_add(jo, "remote-echo-interval",
530 bs->remote_timers.required_min_echo / 1000);
531
532 return jo;
533}
534
535static void _display_peer_json(struct vty *vty, struct bfd_session *bs)
536{
537 struct json_object *jo = __display_peer_json(bs);
538
539 vty_out(vty, "%s\n", json_object_to_json_string_ext(jo, 0));
540 json_object_free(jo);
541}
542
9146cc2a
PG
543struct bfd_vrf_tuple {
544 char *vrfname;
545 struct vty *vty;
546 struct json_object *jo;
547};
548
e3b78da8 549static void _display_peer_iter(struct hash_bucket *hb, void *arg)
c2f29cf3 550{
9146cc2a
PG
551 struct bfd_vrf_tuple *bvt = (struct bfd_vrf_tuple *)arg;
552 struct vty *vty;
c2f29cf3
RZ
553 struct bfd_session *bs = hb->data;
554
9146cc2a
PG
555 if (!bvt)
556 return;
557 vty = bvt->vty;
558
559 if (bvt->vrfname) {
560 if (!bs->key.vrfname[0] ||
561 !strmatch(bs->key.vrfname, bvt->vrfname))
562 return;
563 }
c2f29cf3
RZ
564 _display_peer(vty, bs);
565}
566
e3b78da8 567static void _display_peer_json_iter(struct hash_bucket *hb, void *arg)
c2f29cf3 568{
9146cc2a
PG
569 struct bfd_vrf_tuple *bvt = (struct bfd_vrf_tuple *)arg;
570 struct json_object *jo, *jon = NULL;
c2f29cf3
RZ
571 struct bfd_session *bs = hb->data;
572
9146cc2a
PG
573 if (!bvt)
574 return;
575 jo = bvt->jo;
576
577 if (bvt->vrfname) {
578 if (!bs->key.vrfname[0] ||
579 !strmatch(bs->key.vrfname, bvt->vrfname))
580 return;
581 }
582
c2f29cf3
RZ
583 jon = __display_peer_json(bs);
584 if (jon == NULL) {
585 log_warning("%s: not enough memory", __func__);
586 return;
587 }
588
589 json_object_array_add(jo, jon);
590}
591
9146cc2a 592static void _display_all_peers(struct vty *vty, char *vrfname, bool use_json)
c2f29cf3
RZ
593{
594 struct json_object *jo;
9146cc2a
PG
595 struct bfd_vrf_tuple bvt;
596
597 memset(&bvt, 0, sizeof(bvt));
598 bvt.vrfname = vrfname;
c2f29cf3 599
d8729f8c 600 if (!use_json) {
9146cc2a 601 bvt.vty = vty;
89a634c1 602 vty_out(vty, "BFD Peers:\n");
9146cc2a 603 bfd_id_iterate(_display_peer_iter, &bvt);
c2f29cf3
RZ
604 return;
605 }
606
607 jo = json_object_new_array();
9146cc2a
PG
608 bvt.jo = jo;
609 bfd_id_iterate(_display_peer_json_iter, &bvt);
c2f29cf3
RZ
610
611 vty_out(vty, "%s\n", json_object_to_json_string_ext(jo, 0));
612 json_object_free(jo);
613}
614
0684c9b1
RZ
615static void _display_peer_counter(struct vty *vty, struct bfd_session *bs)
616{
617 _display_peer_header(vty, bs);
618
619 vty_out(vty, "\t\tControl packet input: %" PRIu64 " packets\n",
620 bs->stats.rx_ctrl_pkt);
621 vty_out(vty, "\t\tControl packet output: %" PRIu64 " packets\n",
622 bs->stats.tx_ctrl_pkt);
623 vty_out(vty, "\t\tEcho packet input: %" PRIu64 " packets\n",
624 bs->stats.rx_echo_pkt);
625 vty_out(vty, "\t\tEcho packet output: %" PRIu64 " packets\n",
626 bs->stats.tx_echo_pkt);
627 vty_out(vty, "\t\tSession up events: %" PRIu64 "\n",
628 bs->stats.session_up);
629 vty_out(vty, "\t\tSession down events: %" PRIu64 "\n",
630 bs->stats.session_down);
631 vty_out(vty, "\t\tZebra notifications: %" PRIu64 "\n",
632 bs->stats.znotification);
633 vty_out(vty, "\n");
634}
635
636static struct json_object *__display_peer_counters_json(struct bfd_session *bs)
637{
638 struct json_object *jo = _peer_json_header(bs);
639
640 json_object_int_add(jo, "control-packet-input", bs->stats.rx_ctrl_pkt);
641 json_object_int_add(jo, "control-packet-output", bs->stats.tx_ctrl_pkt);
642 json_object_int_add(jo, "echo-packet-input", bs->stats.rx_echo_pkt);
643 json_object_int_add(jo, "echo-packet-output", bs->stats.tx_echo_pkt);
644 json_object_int_add(jo, "session-up", bs->stats.session_up);
645 json_object_int_add(jo, "session-down", bs->stats.session_down);
646 json_object_int_add(jo, "zebra-notifications", bs->stats.znotification);
647
648 return jo;
649}
650
651static void _display_peer_counters_json(struct vty *vty, struct bfd_session *bs)
652{
653 struct json_object *jo = __display_peer_counters_json(bs);
654
655 vty_out(vty, "%s\n", json_object_to_json_string_ext(jo, 0));
656 json_object_free(jo);
657}
658
e3b78da8 659static void _display_peer_counter_iter(struct hash_bucket *hb, void *arg)
0684c9b1
RZ
660{
661 struct vty *vty = arg;
662 struct bfd_session *bs = hb->data;
663
664 _display_peer_counter(vty, bs);
665}
666
e3b78da8 667static void _display_peer_counter_json_iter(struct hash_bucket *hb, void *arg)
0684c9b1
RZ
668{
669 struct json_object *jo = arg, *jon = NULL;
670 struct bfd_session *bs = hb->data;
671
672 jon = __display_peer_counters_json(bs);
673 if (jon == NULL) {
674 log_warning("%s: not enough memory", __func__);
675 return;
676 }
677
678 json_object_array_add(jo, jon);
679}
680
681static void _display_peers_counter(struct vty *vty, bool use_json)
682{
683 struct json_object *jo;
684
d8729f8c 685 if (!use_json) {
0684c9b1
RZ
686 vty_out(vty, "BFD Peers:\n");
687 bfd_id_iterate(_display_peer_counter_iter, vty);
688 return;
689 }
690
691 jo = json_object_new_array();
692 bfd_id_iterate(_display_peer_counter_json_iter, jo);
693
694 vty_out(vty, "%s\n", json_object_to_json_string_ext(jo, 0));
695 json_object_free(jo);
696}
697
89a634c1
RZ
698static struct bfd_session *
699_find_peer_or_error(struct vty *vty, int argc, struct cmd_token **argv,
700 const char *label, const char *peer_str,
701 const char *local_str, const char *ifname,
702 const char *vrfname)
c2f29cf3
RZ
703{
704 int idx;
705 bool mhop;
706 struct bfd_session *bs = NULL;
707 struct peer_label *pl;
708 struct bfd_peer_cfg bpc;
709 struct sockaddr_any psa, lsa, *lsap;
710 char errormsg[128];
711
712 /* Look up the BFD peer. */
713 if (label) {
714 pl = pl_find(label);
715 if (pl)
716 bs = pl->pl_bs;
717 } else {
718 strtosa(peer_str, &psa);
89a634c1 719 if (local_str) {
c2f29cf3
RZ
720 strtosa(local_str, &lsa);
721 lsap = &lsa;
722 } else
723 lsap = NULL;
724
725 idx = 0;
726 mhop = argv_find(argv, argc, "multihop", &idx);
727
728 if (bfd_configure_peer(&bpc, mhop, &psa, lsap, ifname, vrfname,
729 errormsg, sizeof(errormsg))
730 != 0) {
731 vty_out(vty, "%% Invalid peer configuration: %s\n",
732 errormsg);
89a634c1 733 return NULL;
c2f29cf3
RZ
734 }
735
736 bs = bs_peer_find(&bpc);
737 }
738
739 /* Find peer data. */
740 if (bs == NULL) {
741 vty_out(vty, "%% Unable to find 'peer %s",
742 label ? label : peer_str);
743 if (ifname)
744 vty_out(vty, " interface %s", ifname);
89a634c1 745 if (local_str)
c2f29cf3
RZ
746 vty_out(vty, " local-address %s", local_str);
747 if (vrfname)
748 vty_out(vty, " vrf %s", vrfname);
749 vty_out(vty, "'\n");
750
89a634c1 751 return NULL;
c2f29cf3
RZ
752 }
753
89a634c1
RZ
754 return bs;
755}
756
757
758/*
759 * Show commands.
760 */
9146cc2a 761DEFPY(bfd_show_peers, bfd_show_peers_cmd, "show bfd [vrf <NAME>] peers [json]",
89a634c1
RZ
762 SHOW_STR
763 "Bidirection Forwarding Detection\n"
9146cc2a 764 VRF_CMD_HELP_STR
89a634c1
RZ
765 "BFD peers status\n" JSON_STR)
766{
9146cc2a
PG
767 char *vrf_name = NULL;
768 int idx_vrf = 0;
769
770 if (argv_find(argv, argc, "vrf", &idx_vrf))
771 vrf_name = argv[idx_vrf + 1]->arg;
772
773 _display_all_peers(vty, vrf_name, use_json(argc, argv));
89a634c1
RZ
774
775 return CMD_SUCCESS;
776}
777
778DEFPY(bfd_show_peer, bfd_show_peer_cmd,
779 "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]",
780 SHOW_STR
781 "Bidirection Forwarding Detection\n"
782 "BFD peers status\n"
783 "Peer label\n" PEER_IPV4_STR PEER_IPV6_STR MHOP_STR LOCAL_STR
784 LOCAL_IPV4_STR LOCAL_IPV6_STR INTERFACE_STR LOCAL_INTF_STR VRF_STR
785 VRF_NAME_STR JSON_STR)
786{
787 struct bfd_session *bs;
788
789 /* Look up the BFD peer. */
790 bs = _find_peer_or_error(vty, argc, argv, label, peer_str, local_str,
791 ifname, vrfname);
792 if (bs == NULL)
793 return CMD_WARNING_CONFIG_FAILED;
794
c2f29cf3
RZ
795 if (use_json(argc, argv)) {
796 _display_peer_json(vty, bs);
797 } else {
798 vty_out(vty, "BFD Peer:\n");
799 _display_peer(vty, bs);
800 }
801
802 return CMD_SUCCESS;
803}
804
0684c9b1
RZ
805DEFPY(bfd_show_peer_counters, bfd_show_peer_counters_cmd,
806 "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]",
807 SHOW_STR
808 "Bidirection Forwarding Detection\n"
809 "BFD peers status\n"
810 "Peer label\n"
811 PEER_IPV4_STR
812 PEER_IPV6_STR
813 MHOP_STR
814 LOCAL_STR
815 LOCAL_IPV4_STR
816 LOCAL_IPV6_STR
817 INTERFACE_STR
818 LOCAL_INTF_STR
819 VRF_STR
820 VRF_NAME_STR
821 "Show BFD peer counters information\n"
822 JSON_STR)
823{
824 struct bfd_session *bs;
825
826 /* Look up the BFD peer. */
827 bs = _find_peer_or_error(vty, argc, argv, label, peer_str, local_str,
828 ifname, vrfname);
829 if (bs == NULL)
830 return CMD_WARNING_CONFIG_FAILED;
831
832 if (use_json(argc, argv))
833 _display_peer_counters_json(vty, bs);
834 else
835 _display_peer_counter(vty, bs);
836
837 return CMD_SUCCESS;
838}
839
840DEFPY(bfd_show_peers_counters, bfd_show_peers_counters_cmd,
841 "show bfd peers counters [json]",
842 SHOW_STR
843 "Bidirection Forwarding Detection\n"
844 "BFD peers status\n"
845 "Show BFD peer counters information\n"
846 JSON_STR)
847{
848 _display_peers_counter(vty, use_json(argc, argv));
849
850 return CMD_SUCCESS;
851}
852
c2f29cf3
RZ
853
854/*
855 * Function definitions.
856 */
857
858/*
859 * Configuration rules:
860 *
861 * Single hop:
8a9f760e 862 * peer + (interface name)
c2f29cf3
RZ
863 *
864 * Multi hop:
865 * peer + local + (optional vrf)
866 *
867 * Anything else is misconfiguration.
868 */
869static int bfd_configure_peer(struct bfd_peer_cfg *bpc, bool mhop,
870 const struct sockaddr_any *peer,
871 const struct sockaddr_any *local,
872 const char *ifname, const char *vrfname,
873 char *ebuf, size_t ebuflen)
874{
875 memset(bpc, 0, sizeof(*bpc));
876
877 /* Defaults */
878 bpc->bpc_shutdown = true;
879 bpc->bpc_detectmultiplier = BPC_DEF_DETECTMULTIPLIER;
880 bpc->bpc_recvinterval = BPC_DEF_RECEIVEINTERVAL;
881 bpc->bpc_txinterval = BPC_DEF_TRANSMITINTERVAL;
882 bpc->bpc_echointerval = BPC_DEF_ECHOINTERVAL;
883 bpc->bpc_lastevent = monotime(NULL);
884
885 /* Safety check: when no error buf is provided len must be zero. */
886 if (ebuf == NULL)
887 ebuflen = 0;
888
889 /* Peer is always mandatory. */
890 if (peer == NULL) {
891 snprintf(ebuf, ebuflen, "peer must not be empty");
892 return -1;
893 }
894
895 /* Validate address families. */
896 if (peer->sa_sin.sin_family == AF_INET) {
897 if (local && local->sa_sin.sin_family != AF_INET) {
898 snprintf(ebuf, ebuflen,
899 "local is IPv6, but peer is IPv4");
900 return -1;
901 }
902
903 bpc->bpc_ipv4 = true;
904 } else if (peer->sa_sin.sin_family == AF_INET6) {
905 if (local && local->sa_sin.sin_family != AF_INET6) {
906 snprintf(ebuf, ebuflen,
907 "local is IPv4, but peer is IPv6");
908 return -1;
909 }
910
911 bpc->bpc_ipv4 = false;
912 } else {
913 snprintf(ebuf, ebuflen, "invalid peer address family");
914 return -1;
915 }
916
917 /* Copy local and/or peer addresses. */
918 if (local)
919 bpc->bpc_local = *local;
920
4848ef74 921 bpc->bpc_peer = *peer;
c2f29cf3
RZ
922 bpc->bpc_mhop = mhop;
923
c2f29cf3
RZ
924 /* Handle interface specification configuration. */
925 if (ifname) {
926 if (bpc->bpc_mhop) {
927 snprintf(ebuf, ebuflen,
928 "multihop doesn't accept interface names");
929 return -1;
930 }
931
932 bpc->bpc_has_localif = true;
933 if (strlcpy(bpc->bpc_localif, ifname, sizeof(bpc->bpc_localif))
934 > sizeof(bpc->bpc_localif)) {
935 snprintf(ebuf, ebuflen, "interface name too long");
936 return -1;
937 }
938 }
939
940 /* Handle VRF configuration. */
941 if (vrfname) {
942 bpc->bpc_has_vrfname = true;
943 if (strlcpy(bpc->bpc_vrfname, vrfname, sizeof(bpc->bpc_vrfname))
944 > sizeof(bpc->bpc_vrfname)) {
945 snprintf(ebuf, ebuflen, "vrf name too long");
946 return -1;
947 }
948 }
949
950 return 0;
951}
952static int bfdd_write_config(struct vty *vty)
953{
954 vty_out(vty, "bfd\n");
955 vty_out(vty, "!\n");
956 return 0;
957}
958
d245e522 959static void _bfdd_peer_write_config(struct vty *vty, struct bfd_session *bs)
c2f29cf3 960{
79b4a6fc
RZ
961 char addr_buf[INET6_ADDRSTRLEN];
962
963 vty_out(vty, " peer %s",
964 inet_ntop(bs->key.family, &bs->key.peer, addr_buf,
965 sizeof(addr_buf)));
966
967 if (bs->key.mhop)
c2f29cf3 968 vty_out(vty, " multihop");
79b4a6fc
RZ
969
970 if (memcmp(&bs->key.local, &zero_addr, sizeof(bs->key.local)))
971 vty_out(vty, " local-address %s",
972 inet_ntop(bs->key.family, &bs->key.local, addr_buf,
973 sizeof(addr_buf)));
974
975 if (bs->key.vrfname[0])
976 vty_out(vty, " vrf %s", bs->key.vrfname);
977 if (bs->key.ifname[0])
978 vty_out(vty, " interface %s", bs->key.ifname);
979 vty_out(vty, "\n");
c2f29cf3 980
d245e522 981 if (bs->sock == -1)
261e0ba9
RZ
982 vty_out(vty,
983 " ! vrf, interface or local-address doesn't exist\n");
d245e522 984
c2f29cf3
RZ
985 if (bs->detect_mult != BPC_DEF_DETECTMULTIPLIER)
986 vty_out(vty, " detect-multiplier %d\n", bs->detect_mult);
987 if (bs->timers.required_min_rx != (BPC_DEF_RECEIVEINTERVAL * 1000))
988 vty_out(vty, " receive-interval %" PRIu32 "\n",
989 bs->timers.required_min_rx / 1000);
f43b9368 990 if (bs->timers.desired_min_tx != (BPC_DEF_TRANSMITINTERVAL * 1000))
c2f29cf3 991 vty_out(vty, " transmit-interval %" PRIu32 "\n",
f43b9368 992 bs->timers.desired_min_tx / 1000);
c2f29cf3
RZ
993 if (bs->timers.required_min_echo != (BPC_DEF_ECHOINTERVAL * 1000))
994 vty_out(vty, " echo-interval %" PRIu32 "\n",
995 bs->timers.required_min_echo / 1000);
996 if (bs->pl)
997 vty_out(vty, " label %s\n", bs->pl->pl_label);
998 if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO))
999 vty_out(vty, " echo-mode\n");
1000
1001 vty_out(vty, " %sshutdown\n",
1002 BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN) ? "" : "no ");
1003
1004 vty_out(vty, " !\n");
1005}
1006
a244e599
DS
1007DEFUN_NOSH(show_debugging_bfd,
1008 show_debugging_bfd_cmd,
1009 "show debugging [bfd]",
1010 SHOW_STR
1011 DEBUG_STR
1012 "BFD daemon\n")
1013{
1014 vty_out(vty, "BFD debugging status:\n");
1015
1016 return CMD_SUCCESS;
1017}
1018
e3b78da8 1019static void _bfdd_peer_write_config_iter(struct hash_bucket *hb, void *arg)
d245e522
RZ
1020{
1021 struct vty *vty = arg;
1022 struct bfd_session *bs = hb->data;
1023
6bdb4a42
PG
1024 if (!BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_CONFIG))
1025 return;
1026
d245e522
RZ
1027 _bfdd_peer_write_config(vty, bs);
1028}
1029
c2f29cf3
RZ
1030static int bfdd_peer_write_config(struct vty *vty)
1031{
d245e522 1032 bfd_id_iterate(_bfdd_peer_write_config_iter, vty);
d245e522 1033
c2f29cf3
RZ
1034 return 1;
1035}
1036
1037struct cmd_node bfd_node = {
1038 BFD_NODE,
1039 "%s(config-bfd)# ",
1040 1,
1041};
1042
1043struct cmd_node bfd_peer_node = {
1044 BFD_PEER_NODE,
1045 "%s(config-bfd-peer)# ",
1046 1,
1047};
1048
1049void bfdd_vty_init(void)
1050{
0684c9b1
RZ
1051 install_element(ENABLE_NODE, &bfd_show_peers_counters_cmd);
1052 install_element(ENABLE_NODE, &bfd_show_peer_counters_cmd);
c2f29cf3
RZ
1053 install_element(ENABLE_NODE, &bfd_show_peers_cmd);
1054 install_element(ENABLE_NODE, &bfd_show_peer_cmd);
1055 install_element(CONFIG_NODE, &bfd_enter_cmd);
a244e599 1056 install_element(ENABLE_NODE, &show_debugging_bfd_cmd);
c2f29cf3
RZ
1057
1058 /* Install BFD node and commands. */
1059 install_node(&bfd_node, bfdd_write_config);
1060 install_default(BFD_NODE);
1061 install_element(BFD_NODE, &bfd_peer_enter_cmd);
1062 install_element(BFD_NODE, &bfd_no_peer_cmd);
1063
1064 /* Install BFD peer node. */
1065 install_node(&bfd_peer_node, bfdd_peer_write_config);
1066 install_default(BFD_PEER_NODE);
1067 install_element(BFD_PEER_NODE, &bfd_peer_detectmultiplier_cmd);
1068 install_element(BFD_PEER_NODE, &bfd_peer_recvinterval_cmd);
1069 install_element(BFD_PEER_NODE, &bfd_peer_txinterval_cmd);
1070 install_element(BFD_PEER_NODE, &bfd_peer_echointerval_cmd);
1071 install_element(BFD_PEER_NODE, &bfd_peer_shutdown_cmd);
1072 install_element(BFD_PEER_NODE, &bfd_peer_echo_cmd);
1073 install_element(BFD_PEER_NODE, &bfd_peer_label_cmd);
1074}