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