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