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