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