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