]> git.proxmox.com Git - mirror_frr.git/blob - bfdd/bfdd_northbound.c
Merge pull request #5246 from sworleys/README-Frr-Chicken
[mirror_frr.git] / bfdd / bfdd_northbound.c
1 /*
2 * BFD daemon northbound implementation.
3 *
4 * Copyright (C) 2019 Network Device Education Foundation, Inc. ("NetDEF")
5 * Rafael Zalamena
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 * 02110-1301 USA.
21 */
22
23 #include <zebra.h>
24
25 #include "lib/log.h"
26 #include "lib/northbound.h"
27
28 #include "bfd.h"
29
30 /*
31 * Helpers.
32 */
33 static void bfd_session_get_key(bool mhop, const struct lyd_node *dnode,
34 struct bfd_key *bk)
35 {
36 const char *ifname = NULL, *vrfname = NULL;
37 struct sockaddr_any psa, lsa;
38
39 /* Required destination parameter. */
40 strtosa(yang_dnode_get_string(dnode, "./dest-addr"), &psa);
41
42 /* Get optional source address. */
43 memset(&lsa, 0, sizeof(lsa));
44 if (yang_dnode_exists(dnode, "./source-addr"))
45 strtosa(yang_dnode_get_string(dnode, "./source-addr"), &lsa);
46
47 /* Get optional interface and vrf names. */
48 if (yang_dnode_exists(dnode, "./interface"))
49 ifname = yang_dnode_get_string(dnode, "./interface");
50 if (yang_dnode_exists(dnode, "./vrf"))
51 vrfname = yang_dnode_get_string(dnode, "./vrf");
52
53 /* Generate the corresponding key. */
54 gen_bfd_key(bk, &psa, &lsa, mhop, ifname, vrfname);
55 }
56
57 static int bfd_session_create(enum nb_event event, const struct lyd_node *dnode,
58 union nb_resource *resource, bool mhop)
59 {
60 struct bfd_session *bs;
61 const char *ifname;
62 struct bfd_key bk;
63 struct prefix p;
64
65 switch (event) {
66 case NB_EV_VALIDATE:
67 /*
68 * When `dest-addr` is IPv6 and link-local we must
69 * require interface name, otherwise we can't figure
70 * which interface to use to send the packets.
71 */
72 yang_dnode_get_prefix(&p, dnode, "./dest-addr");
73
74 /*
75 * To support old FRR versions we must allow empty
76 * interface to be specified, however that should
77 * change in the future.
78 */
79 if (yang_dnode_exists(dnode, "./interface"))
80 ifname = yang_dnode_get_string(dnode, "./interface");
81 else
82 ifname = "";
83
84 if (p.family == AF_INET6
85 && IN6_IS_ADDR_LINKLOCAL(&p.u.prefix6)
86 && strlen(ifname) == 0) {
87 zlog_warn("%s: when using link-local you must specify "
88 "an interface.", __func__);
89 return NB_ERR_VALIDATION;
90 }
91 break;
92
93 case NB_EV_PREPARE:
94 bfd_session_get_key(mhop, dnode, &bk);
95 bs = bfd_key_lookup(bk);
96
97 /* This session was already configured by another daemon. */
98 if (bs != NULL) {
99 /* Now it is configured also by CLI. */
100 BFD_SET_FLAG(bs->flags, BFD_SESS_FLAG_CONFIG);
101 bs->refcount++;
102
103 resource->ptr = bs;
104 break;
105 }
106
107 bs = bfd_session_new();
108 if (bs == NULL)
109 return NB_ERR_RESOURCE;
110
111 /* Fill the session key. */
112 bfd_session_get_key(mhop, dnode, &bs->key);
113
114 /* Set configuration flags. */
115 bs->refcount = 1;
116 BFD_SET_FLAG(bs->flags, BFD_SESS_FLAG_CONFIG);
117 if (mhop)
118 BFD_SET_FLAG(bs->flags, BFD_SESS_FLAG_MH);
119 if (bs->key.family == AF_INET6)
120 BFD_SET_FLAG(bs->flags, BFD_SESS_FLAG_IPV6);
121
122 resource->ptr = bs;
123 break;
124
125 case NB_EV_APPLY:
126 bs = resource->ptr;
127
128 /* Only attempt to registrate if freshly allocated. */
129 if (bs->discrs.my_discr == 0 && bs_registrate(bs) == NULL)
130 return NB_ERR_RESOURCE;
131
132 nb_running_set_entry(dnode, bs);
133 break;
134
135 case NB_EV_ABORT:
136 bs = resource->ptr;
137 if (bs->refcount <= 1)
138 bfd_session_free(resource->ptr);
139 break;
140 }
141
142 return NB_OK;
143 }
144
145 static int bfd_session_destroy(enum nb_event event,
146 const struct lyd_node *dnode, bool mhop)
147 {
148 struct bfd_session *bs;
149 struct bfd_key bk;
150
151 switch (event) {
152 case NB_EV_VALIDATE:
153 bfd_session_get_key(mhop, dnode, &bk);
154 if (bfd_key_lookup(bk) == NULL)
155 return NB_ERR_INCONSISTENCY;
156 break;
157
158 case NB_EV_PREPARE:
159 /* NOTHING */
160 break;
161
162 case NB_EV_APPLY:
163 bs = nb_running_unset_entry(dnode);
164 /* CLI is not using this session anymore. */
165 if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_CONFIG) == 0)
166 break;
167
168 BFD_UNSET_FLAG(bs->flags, BFD_SESS_FLAG_CONFIG);
169 bs->refcount--;
170 /* There are still daemons using it. */
171 if (bs->refcount > 0)
172 break;
173
174 bfd_session_free(bs);
175 break;
176
177 case NB_EV_ABORT:
178 /* NOTHING */
179 break;
180 }
181
182 return NB_OK;
183 }
184
185 /*
186 * XPath: /frr-bfdd:bfdd/bfd
187 */
188 static int bfdd_bfd_create(enum nb_event event,
189 const struct lyd_node *dnode
190 __attribute__((__unused__)),
191 union nb_resource *resource
192 __attribute__((__unused__)))
193 {
194 /* NOTHING */
195 return NB_OK;
196 }
197
198 static int bfdd_bfd_destroy(enum nb_event event, const struct lyd_node *dnode)
199 {
200 switch (event) {
201 case NB_EV_VALIDATE:
202 /* NOTHING */
203 return NB_OK;
204
205 case NB_EV_PREPARE:
206 /* NOTHING */
207 return NB_OK;
208
209 case NB_EV_APPLY:
210 bfd_sessions_remove_manual();
211 break;
212
213 case NB_EV_ABORT:
214 /* NOTHING */
215 return NB_OK;
216 }
217
218 return NB_OK;
219 }
220
221 /*
222 * XPath: /frr-bfdd:bfdd/bfd/sessions/single-hop
223 */
224 static int bfdd_bfd_sessions_single_hop_create(enum nb_event event,
225 const struct lyd_node *dnode,
226 union nb_resource *resource)
227 {
228 return bfd_session_create(event, dnode, resource, false);
229 }
230
231 static int bfdd_bfd_sessions_single_hop_destroy(enum nb_event event,
232 const struct lyd_node *dnode)
233 {
234 return bfd_session_destroy(event, dnode, false);
235 }
236
237 static const void *
238 bfdd_bfd_sessions_single_hop_get_next(const void *parent_list_entry
239 __attribute__((__unused__)),
240 const void *list_entry)
241 {
242 return bfd_session_next(list_entry, false);
243 }
244
245 static int bfdd_bfd_sessions_single_hop_get_keys(const void *list_entry,
246 struct yang_list_keys *keys)
247 {
248 const struct bfd_session *bs = list_entry;
249 char dstbuf[INET6_ADDRSTRLEN];
250
251 inet_ntop(bs->key.family, &bs->key.peer, dstbuf, sizeof(dstbuf));
252
253 keys->num = 3;
254 strlcpy(keys->key[0], dstbuf, sizeof(keys->key[0]));
255 strlcpy(keys->key[1], bs->key.ifname, sizeof(keys->key[1]));
256 strlcpy(keys->key[2], bs->key.vrfname, sizeof(keys->key[2]));
257
258 return NB_OK;
259 }
260
261 static const void *
262 bfdd_bfd_sessions_single_hop_lookup_entry(const void *parent_list_entry
263 __attribute__((__unused__)),
264 const struct yang_list_keys *keys)
265 {
266 const char *dest_addr = keys->key[0];
267 const char *ifname = keys->key[1];
268 const char *vrf = keys->key[2];
269 struct sockaddr_any psa, lsa;
270 struct bfd_key bk;
271
272 strtosa(dest_addr, &psa);
273 memset(&lsa, 0, sizeof(lsa));
274 gen_bfd_key(&bk, &psa, &lsa, false, ifname, vrf);
275
276 return bfd_key_lookup(bk);
277 }
278
279 /*
280 * XPath: /frr-bfdd:bfdd/bfd/sessions/single-hop/source-addr
281 */
282 static int bfdd_bfd_sessions_single_hop_source_addr_modify(
283 enum nb_event event __attribute__((__unused__)),
284 const struct lyd_node *dnode __attribute__((__unused__)),
285 union nb_resource *resource __attribute__((__unused__)))
286 {
287 return NB_OK;
288 }
289
290 static int bfdd_bfd_sessions_single_hop_source_addr_destroy(
291 enum nb_event event __attribute__((__unused__)),
292 const struct lyd_node *dnode __attribute__((__unused__)))
293 {
294 return NB_OK;
295 }
296
297 /*
298 * XPath: /frr-bfdd:bfdd/bfd/sessions/single-hop/detection-multiplier
299 */
300 static int bfdd_bfd_sessions_single_hop_detection_multiplier_modify(
301 enum nb_event event, const struct lyd_node *dnode,
302 union nb_resource *resource __attribute__((__unused__)))
303 {
304 uint8_t detection_multiplier = yang_dnode_get_uint8(dnode, NULL);
305 struct bfd_session *bs;
306
307 switch (event) {
308 case NB_EV_VALIDATE:
309 break;
310
311 case NB_EV_PREPARE:
312 /* NOTHING */
313 break;
314
315 case NB_EV_APPLY:
316 bs = nb_running_get_entry(dnode, NULL, true);
317 bs->detect_mult = detection_multiplier;
318 break;
319
320 case NB_EV_ABORT:
321 /* NOTHING */
322 break;
323 }
324
325 return NB_OK;
326 }
327
328 /*
329 * XPath: /frr-bfdd:bfdd/bfd/sessions/single-hop/desired-transmission-interval
330 */
331 static int bfdd_bfd_sessions_single_hop_desired_transmission_interval_modify(
332 enum nb_event event, const struct lyd_node *dnode,
333 union nb_resource *resource __attribute__((__unused__)))
334 {
335 uint32_t tx_interval = yang_dnode_get_uint32(dnode, NULL);
336 struct bfd_session *bs;
337
338 switch (event) {
339 case NB_EV_VALIDATE:
340 if (tx_interval < 10000 || tx_interval > 60000000)
341 return NB_ERR_VALIDATION;
342 break;
343
344 case NB_EV_PREPARE:
345 /* NOTHING */
346 break;
347
348 case NB_EV_APPLY:
349 bs = nb_running_get_entry(dnode, NULL, true);
350 if (tx_interval == bs->timers.desired_min_tx)
351 return NB_OK;
352
353 bs->timers.desired_min_tx = tx_interval;
354 bfd_set_polling(bs);
355 break;
356
357 case NB_EV_ABORT:
358 /* NOTHING */
359 break;
360 }
361
362 return NB_OK;
363 }
364
365 /*
366 * XPath: /frr-bfdd:bfdd/bfd/sessions/single-hop/required-receive-interval
367 */
368 static int bfdd_bfd_sessions_single_hop_required_receive_interval_modify(
369 enum nb_event event, const struct lyd_node *dnode,
370 union nb_resource *resource __attribute__((__unused__)))
371 {
372 uint32_t rx_interval = yang_dnode_get_uint32(dnode, NULL);
373 struct bfd_session *bs;
374
375 switch (event) {
376 case NB_EV_VALIDATE:
377 if (rx_interval < 10000 || rx_interval > 60000000)
378 return NB_ERR_VALIDATION;
379 break;
380
381 case NB_EV_PREPARE:
382 /* NOTHING */
383 break;
384
385 case NB_EV_APPLY:
386 bs = nb_running_get_entry(dnode, NULL, true);
387 if (rx_interval == bs->timers.required_min_rx)
388 return NB_OK;
389
390 bs->timers.required_min_rx = rx_interval;
391 bfd_set_polling(bs);
392 break;
393
394 case NB_EV_ABORT:
395 /* NOTHING */
396 break;
397 }
398
399 return NB_OK;
400 }
401
402 /*
403 * XPath: /frr-bfdd:bfdd/bfd/sessions/single-hop/administrative-down
404 */
405 static int bfdd_bfd_sessions_single_hop_administrative_down_modify(
406 enum nb_event event, const struct lyd_node *dnode,
407 union nb_resource *resource __attribute__((__unused__)))
408 {
409 bool shutdown = yang_dnode_get_bool(dnode, NULL);
410 struct bfd_session *bs;
411
412 switch (event) {
413 case NB_EV_VALIDATE:
414 case NB_EV_PREPARE:
415 return NB_OK;
416
417 case NB_EV_APPLY:
418 break;
419
420 case NB_EV_ABORT:
421 return NB_OK;
422 }
423
424 bs = nb_running_get_entry(dnode, NULL, true);
425
426 if (shutdown == false) {
427 if (!BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN))
428 return NB_OK;
429
430 BFD_UNSET_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN);
431
432 /* Change and notify state change. */
433 bs->ses_state = PTM_BFD_DOWN;
434 control_notify(bs, bs->ses_state);
435
436 /* Enable all timers. */
437 bfd_recvtimer_update(bs);
438 bfd_xmttimer_update(bs, bs->xmt_TO);
439 if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO)) {
440 bfd_echo_recvtimer_update(bs);
441 bfd_echo_xmttimer_update(bs, bs->echo_xmt_TO);
442 }
443 } else {
444 if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN))
445 return NB_OK;
446
447 BFD_SET_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN);
448
449 /* Disable all events. */
450 bfd_recvtimer_delete(bs);
451 bfd_echo_recvtimer_delete(bs);
452 bfd_xmttimer_delete(bs);
453 bfd_echo_xmttimer_delete(bs);
454
455 /* Change and notify state change. */
456 bs->ses_state = PTM_BFD_ADM_DOWN;
457 control_notify(bs, bs->ses_state);
458
459 ptm_bfd_snd(bs, 0);
460 }
461
462 return NB_OK;
463 }
464
465 /*
466 * XPath: /frr-bfdd:bfdd/bfd/sessions/single-hop/echo-mode
467 */
468 static int bfdd_bfd_sessions_single_hop_echo_mode_modify(
469 enum nb_event event, const struct lyd_node *dnode,
470 union nb_resource *resource __attribute__((__unused__)))
471 {
472 bool echo = yang_dnode_get_bool(dnode, NULL);
473 struct bfd_session *bs;
474
475 switch (event) {
476 case NB_EV_VALIDATE:
477 case NB_EV_PREPARE:
478 return NB_OK;
479
480 case NB_EV_APPLY:
481 break;
482
483 case NB_EV_ABORT:
484 return NB_OK;
485 }
486
487 bs = nb_running_get_entry(dnode, NULL, true);
488
489 if (echo == false) {
490 if (!BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO))
491 return NB_OK;
492
493 BFD_UNSET_FLAG(bs->flags, BFD_SESS_FLAG_ECHO);
494 ptm_bfd_echo_stop(bs);
495 } else {
496 if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO))
497 return NB_OK;
498
499 BFD_SET_FLAG(bs->flags, BFD_SESS_FLAG_ECHO);
500 /* Apply setting immediately. */
501 if (!BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN))
502 bs_echo_timer_handler(bs);
503 }
504
505 return NB_OK;
506 }
507
508 /*
509 * XPath:
510 * /frr-bfdd:bfdd/bfd/sessions/single-hop/desired-echo-transmission-interval
511 */
512 static int
513 bfdd_bfd_sessions_single_hop_desired_echo_transmission_interval_modify(
514 enum nb_event event, const struct lyd_node *dnode,
515 union nb_resource *resource __attribute__((__unused__)))
516 {
517 uint32_t echo_interval = yang_dnode_get_uint32(dnode, NULL);
518 struct bfd_session *bs;
519
520 switch (event) {
521 case NB_EV_VALIDATE:
522 if (echo_interval < 10000 || echo_interval > 60000000)
523 return NB_ERR_VALIDATION;
524 break;
525
526 case NB_EV_PREPARE:
527 /* NOTHING */
528 break;
529
530 case NB_EV_APPLY:
531 bs = nb_running_get_entry(dnode, NULL, true);
532 if (echo_interval == bs->timers.required_min_echo)
533 return NB_OK;
534
535 bs->timers.required_min_echo = echo_interval;
536 break;
537
538 case NB_EV_ABORT:
539 /* NOTHING */
540 break;
541 }
542
543 return NB_OK;
544 }
545
546 /*
547 * XPath: /frr-bfdd:bfdd/bfd/sessions/single-hop/stats/local-discriminator
548 */
549 static struct yang_data *
550 bfdd_bfd_sessions_single_hop_stats_local_discriminator_get_elem(
551 const char *xpath, const void *list_entry)
552 {
553 const struct bfd_session *bs = list_entry;
554
555 return yang_data_new_uint32(xpath, bs->discrs.my_discr);
556 }
557
558 /*
559 * XPath: /frr-bfdd:bfdd/bfd/sessions/single-hop/stats/local-state
560 */
561 static struct yang_data *
562 bfdd_bfd_sessions_single_hop_stats_local_state_get_elem(const char *xpath,
563 const void *list_entry)
564 {
565 const struct bfd_session *bs = list_entry;
566
567 return yang_data_new_enum(xpath, bs->ses_state);
568 }
569
570 /*
571 * XPath: /frr-bfdd:bfdd/bfd/sessions/single-hop/stats/local-diagnostic
572 */
573 static struct yang_data *
574 bfdd_bfd_sessions_single_hop_stats_local_diagnostic_get_elem(
575 const char *xpath, const void *list_entry)
576 {
577 const struct bfd_session *bs = list_entry;
578
579 return yang_data_new_enum(xpath, bs->local_diag);
580 }
581
582 /*
583 * XPath: /frr-bfdd:bfdd/bfd/sessions/single-hop/stats/local-multiplier
584 */
585 static struct yang_data *
586 bfdd_bfd_sessions_single_hop_stats_local_multiplier_get_elem(
587 const char *xpath, const void *list_entry)
588 {
589 const struct bfd_session *bs = list_entry;
590
591 return yang_data_new_int8(xpath, bs->detect_mult);
592 }
593
594 /*
595 * XPath: /frr-bfdd:bfdd/bfd/sessions/single-hop/stats/remote-discriminator
596 */
597 static struct yang_data *
598 bfdd_bfd_sessions_single_hop_stats_remote_discriminator_get_elem(
599 const char *xpath, const void *list_entry)
600 {
601 const struct bfd_session *bs = list_entry;
602
603 if (bs->discrs.remote_discr == 0)
604 return NULL;
605
606 return yang_data_new_uint32(xpath, bs->discrs.remote_discr);
607 }
608
609 /*
610 * XPath: /frr-bfdd:bfdd/bfd/sessions/single-hop/stats/remote-state
611 */
612 static struct yang_data *
613 bfdd_bfd_sessions_single_hop_stats_remote_state_get_elem(const char *xpath,
614 const void *list_entry)
615 {
616 const struct bfd_session *bs = list_entry;
617
618 return yang_data_new_enum(xpath, bs->ses_state);
619 }
620
621 /*
622 * XPath: /frr-bfdd:bfdd/bfd/sessions/single-hop/stats/remote-diagnostic
623 */
624 static struct yang_data *
625 bfdd_bfd_sessions_single_hop_stats_remote_diagnostic_get_elem(
626 const char *xpath, const void *list_entry)
627 {
628 const struct bfd_session *bs = list_entry;
629
630 return yang_data_new_enum(xpath, bs->remote_diag);
631 }
632
633 /*
634 * XPath: /frr-bfdd:bfdd/bfd/sessions/single-hop/stats/remote-multiplier
635 */
636 static struct yang_data *
637 bfdd_bfd_sessions_single_hop_stats_remote_multiplier_get_elem(
638 const char *xpath, const void *list_entry)
639 {
640 const struct bfd_session *bs = list_entry;
641
642 return yang_data_new_int8(xpath, bs->remote_detect_mult);
643 }
644
645 /*
646 * XPath:
647 * /frr-bfdd:bfdd/bfd/sessions/single-hop/stats/negotiated-transmission-interval
648 */
649 static struct yang_data *
650 bfdd_bfd_sessions_single_hop_stats_negotiated_transmission_interval_get_elem(
651 const char *xpath, const void *list_entry)
652 {
653 const struct bfd_session *bs = list_entry;
654
655 return yang_data_new_uint32(xpath, bs->remote_timers.desired_min_tx);
656 }
657
658 /*
659 * XPath:
660 * /frr-bfdd:bfdd/bfd/sessions/single-hop/stats/negotiated-receive-interval
661 */
662 static struct yang_data *
663 bfdd_bfd_sessions_single_hop_stats_negotiated_receive_interval_get_elem(
664 const char *xpath, const void *list_entry)
665 {
666 const struct bfd_session *bs = list_entry;
667
668 return yang_data_new_uint32(xpath, bs->remote_timers.required_min_rx);
669 }
670
671 /*
672 * XPath: /frr-bfdd:bfdd/bfd/sessions/single-hop/stats/detection-mode
673 */
674 static struct yang_data *
675 bfdd_bfd_sessions_single_hop_stats_detection_mode_get_elem(
676 const char *xpath, const void *list_entry)
677 {
678 const struct bfd_session *bs = list_entry;
679 int detection_mode;
680
681 /*
682 * Detection mode:
683 * 1. Async with echo
684 * 2. Async without echo
685 * 3. Demand with echo
686 * 4. Demand without echo
687 *
688 * TODO: support demand mode.
689 */
690 if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO))
691 detection_mode = 1;
692 else
693 detection_mode = 2;
694
695 return yang_data_new_enum(xpath, detection_mode);
696 }
697
698 /*
699 * XPath: /frr-bfdd:bfdd/bfd/sessions/single-hop/stats/last-down-time
700 */
701 static struct yang_data *
702 bfdd_bfd_sessions_single_hop_stats_last_down_time_get_elem(
703 const char *xpath __attribute__((__unused__)),
704 const void *list_entry __attribute__((__unused__)))
705 {
706 /*
707 * TODO: implement me.
708 *
709 * No yang support for time elements yet.
710 */
711 return NULL;
712 }
713
714 /*
715 * XPath: /frr-bfdd:bfdd/bfd/sessions/single-hop/stats/last-up-time
716 */
717 static struct yang_data *
718 bfdd_bfd_sessions_single_hop_stats_last_up_time_get_elem(
719 const char *xpath __attribute__((__unused__)),
720 const void *list_entry __attribute__((__unused__)))
721 {
722 /*
723 * TODO: implement me.
724 *
725 * No yang support for time elements yet.
726 */
727 return NULL;
728 }
729
730 /*
731 * XPath: /frr-bfdd:bfdd/bfd/sessions/single-hop/stats/session-down-count
732 */
733 static struct yang_data *
734 bfdd_bfd_sessions_single_hop_stats_session_down_count_get_elem(
735 const char *xpath, const void *list_entry)
736 {
737 const struct bfd_session *bs = list_entry;
738
739 return yang_data_new_uint64(xpath, bs->stats.session_down);
740 }
741
742 /*
743 * XPath: /frr-bfdd:bfdd/bfd/sessions/single-hop/stats/session-up-count
744 */
745 static struct yang_data *
746 bfdd_bfd_sessions_single_hop_stats_session_up_count_get_elem(
747 const char *xpath, const void *list_entry)
748 {
749 const struct bfd_session *bs = list_entry;
750
751 return yang_data_new_uint64(xpath, bs->stats.session_up);
752 }
753
754 /*
755 * XPath:
756 * /frr-bfdd:bfdd/bfd/sessions/single-hop/stats/control-packet-input-count
757 */
758 static struct yang_data *
759 bfdd_bfd_sessions_single_hop_stats_control_packet_input_count_get_elem(
760 const char *xpath, const void *list_entry)
761 {
762 const struct bfd_session *bs = list_entry;
763
764 return yang_data_new_uint64(xpath, bs->stats.rx_ctrl_pkt);
765 }
766
767 /*
768 * XPath:
769 * /frr-bfdd:bfdd/bfd/sessions/single-hop/stats/control-packet-output-count
770 */
771 static struct yang_data *
772 bfdd_bfd_sessions_single_hop_stats_control_packet_output_count_get_elem(
773 const char *xpath, const void *list_entry)
774 {
775 const struct bfd_session *bs = list_entry;
776
777 return yang_data_new_uint64(xpath, bs->stats.tx_ctrl_pkt);
778 }
779
780 /*
781 * XPath:
782 * /frr-bfdd:bfdd/bfd/sessions/single-hop/stats/negotiated-echo-transmission-interval
783 */
784 static struct yang_data *
785 bfdd_bfd_sessions_single_hop_stats_negotiated_echo_transmission_interval_get_elem(
786 const char *xpath, const void *list_entry)
787 {
788 const struct bfd_session *bs = list_entry;
789
790 return yang_data_new_uint32(xpath, bs->remote_timers.required_min_echo);
791 }
792
793 /*
794 * XPath: /frr-bfdd:bfdd/bfd/sessions/single-hop/stats/echo-packet-input-count
795 */
796 static struct yang_data *
797 bfdd_bfd_sessions_single_hop_stats_echo_packet_input_count_get_elem(
798 const char *xpath, const void *list_entry)
799 {
800 const struct bfd_session *bs = list_entry;
801
802 return yang_data_new_uint64(xpath, bs->stats.rx_echo_pkt);
803 }
804
805 /*
806 * XPath: /frr-bfdd:bfdd/bfd/sessions/single-hop/stats/echo-packet-output-count
807 */
808 static struct yang_data *
809 bfdd_bfd_sessions_single_hop_stats_echo_packet_output_count_get_elem(
810 const char *xpath, const void *list_entry)
811 {
812 const struct bfd_session *bs = list_entry;
813
814 return yang_data_new_uint64(xpath, bs->stats.tx_echo_pkt);
815 }
816
817 /*
818 * XPath: /frr-bfdd:bfdd/bfd/sessions/multi-hop
819 */
820 static int bfdd_bfd_sessions_multi_hop_create(enum nb_event event,
821 const struct lyd_node *dnode,
822 union nb_resource *resource)
823 {
824 return bfd_session_create(event, dnode, resource, true);
825 }
826
827 static int bfdd_bfd_sessions_multi_hop_destroy(enum nb_event event,
828 const struct lyd_node *dnode)
829 {
830 return bfd_session_destroy(event, dnode, true);
831 }
832
833 static const void *
834 bfdd_bfd_sessions_multi_hop_get_next(const void *parent_list_entry
835 __attribute__((__unused__)),
836 const void *list_entry)
837 {
838 return bfd_session_next(list_entry, true);
839 }
840
841 static int bfdd_bfd_sessions_multi_hop_get_keys(const void *list_entry,
842 struct yang_list_keys *keys)
843 {
844 const struct bfd_session *bs = list_entry;
845 char dstbuf[INET6_ADDRSTRLEN], srcbuf[INET6_ADDRSTRLEN];
846
847 inet_ntop(bs->key.family, &bs->key.peer, dstbuf, sizeof(dstbuf));
848 inet_ntop(bs->key.family, &bs->key.local, srcbuf, sizeof(srcbuf));
849
850 keys->num = 4;
851 strlcpy(keys->key[0], srcbuf, sizeof(keys->key[0]));
852 strlcpy(keys->key[1], dstbuf, sizeof(keys->key[1]));
853 strlcpy(keys->key[2], bs->key.ifname, sizeof(keys->key[2]));
854 strlcpy(keys->key[3], bs->key.vrfname, sizeof(keys->key[3]));
855
856 return NB_OK;
857 }
858
859 static const void *
860 bfdd_bfd_sessions_multi_hop_lookup_entry(const void *parent_list_entry
861 __attribute__((__unused__)),
862 const struct yang_list_keys *keys)
863 {
864 const char *source_addr = keys->key[0];
865 const char *dest_addr = keys->key[1];
866 const char *ifname = keys->key[2];
867 const char *vrf = keys->key[3];
868 struct sockaddr_any psa, lsa;
869 struct bfd_key bk;
870
871 strtosa(dest_addr, &psa);
872 strtosa(source_addr, &lsa);
873 gen_bfd_key(&bk, &psa, &lsa, true, ifname, vrf);
874
875 return bfd_key_lookup(bk);
876 }
877
878 /* clang-format off */
879 const struct frr_yang_module_info frr_bfdd_info = {
880 .name = "frr-bfdd",
881 .nodes = {
882 {
883 .xpath = "/frr-bfdd:bfdd/bfd",
884 .cbs = {
885 .create = bfdd_bfd_create,
886 .destroy = bfdd_bfd_destroy,
887 .cli_show = bfd_cli_show_header,
888 .cli_show_end = bfd_cli_show_header_end,
889 }
890 },
891 {
892 .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop",
893 .cbs = {
894 .create = bfdd_bfd_sessions_single_hop_create,
895 .destroy = bfdd_bfd_sessions_single_hop_destroy,
896 .get_next = bfdd_bfd_sessions_single_hop_get_next,
897 .get_keys = bfdd_bfd_sessions_single_hop_get_keys,
898 .lookup_entry = bfdd_bfd_sessions_single_hop_lookup_entry,
899 .cli_show = bfd_cli_show_single_hop_peer,
900 .cli_show_end = bfd_cli_show_peer_end,
901 }
902 },
903 {
904 .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/source-addr",
905 .cbs = {
906 .modify = bfdd_bfd_sessions_single_hop_source_addr_modify,
907 .destroy = bfdd_bfd_sessions_single_hop_source_addr_destroy,
908 }
909 },
910 {
911 .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/detection-multiplier",
912 .cbs = {
913 .modify = bfdd_bfd_sessions_single_hop_detection_multiplier_modify,
914 .cli_show = bfd_cli_show_mult,
915 }
916 },
917 {
918 .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/desired-transmission-interval",
919 .cbs = {
920 .modify = bfdd_bfd_sessions_single_hop_desired_transmission_interval_modify,
921 .cli_show = bfd_cli_show_tx,
922 }
923 },
924 {
925 .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/required-receive-interval",
926 .cbs = {
927 .modify = bfdd_bfd_sessions_single_hop_required_receive_interval_modify,
928 .cli_show = bfd_cli_show_rx,
929 }
930 },
931 {
932 .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/administrative-down",
933 .cbs = {
934 .modify = bfdd_bfd_sessions_single_hop_administrative_down_modify,
935 .cli_show = bfd_cli_show_shutdown,
936 }
937 },
938 {
939 .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/echo-mode",
940 .cbs = {
941 .modify = bfdd_bfd_sessions_single_hop_echo_mode_modify,
942 .cli_show = bfd_cli_show_echo,
943 }
944 },
945 {
946 .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/desired-echo-transmission-interval",
947 .cbs = {
948 .modify = bfdd_bfd_sessions_single_hop_desired_echo_transmission_interval_modify,
949 .cli_show = bfd_cli_show_echo_interval,
950 }
951 },
952 {
953 .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/stats/local-discriminator",
954 .cbs = {
955 .get_elem = bfdd_bfd_sessions_single_hop_stats_local_discriminator_get_elem,
956 }
957 },
958 {
959 .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/stats/local-state",
960 .cbs = {
961 .get_elem = bfdd_bfd_sessions_single_hop_stats_local_state_get_elem,
962 }
963 },
964 {
965 .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/stats/local-diagnostic",
966 .cbs = {
967 .get_elem = bfdd_bfd_sessions_single_hop_stats_local_diagnostic_get_elem,
968 }
969 },
970 {
971 .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/stats/local-multiplier",
972 .cbs = {
973 .get_elem = bfdd_bfd_sessions_single_hop_stats_local_multiplier_get_elem,
974 }
975 },
976 {
977 .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/stats/remote-discriminator",
978 .cbs = {
979 .get_elem = bfdd_bfd_sessions_single_hop_stats_remote_discriminator_get_elem,
980 }
981 },
982 {
983 .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/stats/remote-state",
984 .cbs = {
985 .get_elem = bfdd_bfd_sessions_single_hop_stats_remote_state_get_elem,
986 }
987 },
988 {
989 .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/stats/remote-diagnostic",
990 .cbs = {
991 .get_elem = bfdd_bfd_sessions_single_hop_stats_remote_diagnostic_get_elem,
992 }
993 },
994 {
995 .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/stats/remote-multiplier",
996 .cbs = {
997 .get_elem = bfdd_bfd_sessions_single_hop_stats_remote_multiplier_get_elem,
998 }
999 },
1000 {
1001 .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/stats/negotiated-transmission-interval",
1002 .cbs = {
1003 .get_elem = bfdd_bfd_sessions_single_hop_stats_negotiated_transmission_interval_get_elem,
1004 }
1005 },
1006 {
1007 .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/stats/negotiated-receive-interval",
1008 .cbs = {
1009 .get_elem = bfdd_bfd_sessions_single_hop_stats_negotiated_receive_interval_get_elem,
1010 }
1011 },
1012 {
1013 .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/stats/detection-mode",
1014 .cbs = {
1015 .get_elem = bfdd_bfd_sessions_single_hop_stats_detection_mode_get_elem,
1016 }
1017 },
1018 {
1019 .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/stats/last-down-time",
1020 .cbs = {
1021 .get_elem = bfdd_bfd_sessions_single_hop_stats_last_down_time_get_elem,
1022 }
1023 },
1024 {
1025 .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/stats/last-up-time",
1026 .cbs = {
1027 .get_elem = bfdd_bfd_sessions_single_hop_stats_last_up_time_get_elem,
1028 }
1029 },
1030 {
1031 .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/stats/session-down-count",
1032 .cbs = {
1033 .get_elem = bfdd_bfd_sessions_single_hop_stats_session_down_count_get_elem,
1034 }
1035 },
1036 {
1037 .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/stats/session-up-count",
1038 .cbs = {
1039 .get_elem = bfdd_bfd_sessions_single_hop_stats_session_up_count_get_elem,
1040 }
1041 },
1042 {
1043 .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/stats/control-packet-input-count",
1044 .cbs = {
1045 .get_elem = bfdd_bfd_sessions_single_hop_stats_control_packet_input_count_get_elem,
1046 }
1047 },
1048 {
1049 .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/stats/control-packet-output-count",
1050 .cbs = {
1051 .get_elem = bfdd_bfd_sessions_single_hop_stats_control_packet_output_count_get_elem,
1052 }
1053 },
1054 {
1055 .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/stats/negotiated-echo-transmission-interval",
1056 .cbs = {
1057 .get_elem = bfdd_bfd_sessions_single_hop_stats_negotiated_echo_transmission_interval_get_elem,
1058 }
1059 },
1060 {
1061 .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/stats/echo-packet-input-count",
1062 .cbs = {
1063 .get_elem = bfdd_bfd_sessions_single_hop_stats_echo_packet_input_count_get_elem,
1064 }
1065 },
1066 {
1067 .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/stats/echo-packet-output-count",
1068 .cbs = {
1069 .get_elem = bfdd_bfd_sessions_single_hop_stats_echo_packet_output_count_get_elem,
1070 }
1071 },
1072 {
1073 .xpath = "/frr-bfdd:bfdd/bfd/sessions/multi-hop",
1074 .cbs = {
1075 .create = bfdd_bfd_sessions_multi_hop_create,
1076 .destroy = bfdd_bfd_sessions_multi_hop_destroy,
1077 .get_next = bfdd_bfd_sessions_multi_hop_get_next,
1078 .get_keys = bfdd_bfd_sessions_multi_hop_get_keys,
1079 .lookup_entry = bfdd_bfd_sessions_multi_hop_lookup_entry,
1080 .cli_show = bfd_cli_show_multi_hop_peer,
1081 .cli_show_end = bfd_cli_show_peer_end,
1082 }
1083 },
1084 {
1085 .xpath = "/frr-bfdd:bfdd/bfd/sessions/multi-hop/detection-multiplier",
1086 .cbs = {
1087 .modify = bfdd_bfd_sessions_single_hop_detection_multiplier_modify,
1088 .cli_show = bfd_cli_show_mult,
1089 }
1090 },
1091 {
1092 .xpath = "/frr-bfdd:bfdd/bfd/sessions/multi-hop/desired-transmission-interval",
1093 .cbs = {
1094 .modify = bfdd_bfd_sessions_single_hop_desired_transmission_interval_modify,
1095 .cli_show = bfd_cli_show_tx,
1096 }
1097 },
1098 {
1099 .xpath = "/frr-bfdd:bfdd/bfd/sessions/multi-hop/required-receive-interval",
1100 .cbs = {
1101 .modify = bfdd_bfd_sessions_single_hop_required_receive_interval_modify,
1102 .cli_show = bfd_cli_show_rx,
1103 }
1104 },
1105 {
1106 .xpath = "/frr-bfdd:bfdd/bfd/sessions/multi-hop/administrative-down",
1107 .cbs = {
1108 .modify = bfdd_bfd_sessions_single_hop_administrative_down_modify,
1109 .cli_show = bfd_cli_show_shutdown,
1110 }
1111 },
1112 {
1113 .xpath = "/frr-bfdd:bfdd/bfd/sessions/multi-hop/stats/local-discriminator",
1114 .cbs = {
1115 .get_elem = bfdd_bfd_sessions_single_hop_stats_local_discriminator_get_elem,
1116 }
1117 },
1118 {
1119 .xpath = "/frr-bfdd:bfdd/bfd/sessions/multi-hop/stats/local-state",
1120 .cbs = {
1121 .get_elem = bfdd_bfd_sessions_single_hop_stats_local_state_get_elem,
1122 }
1123 },
1124 {
1125 .xpath = "/frr-bfdd:bfdd/bfd/sessions/multi-hop/stats/local-diagnostic",
1126 .cbs = {
1127 .get_elem = bfdd_bfd_sessions_single_hop_stats_local_diagnostic_get_elem,
1128 }
1129 },
1130 {
1131 .xpath = "/frr-bfdd:bfdd/bfd/sessions/multi-hop/stats/local-multiplier",
1132 .cbs = {
1133 .get_elem = bfdd_bfd_sessions_single_hop_stats_local_multiplier_get_elem,
1134 }
1135 },
1136 {
1137 .xpath = "/frr-bfdd:bfdd/bfd/sessions/multi-hop/stats/remote-discriminator",
1138 .cbs = {
1139 .get_elem = bfdd_bfd_sessions_single_hop_stats_remote_discriminator_get_elem,
1140 }
1141 },
1142 {
1143 .xpath = "/frr-bfdd:bfdd/bfd/sessions/multi-hop/stats/remote-state",
1144 .cbs = {
1145 .get_elem = bfdd_bfd_sessions_single_hop_stats_remote_state_get_elem,
1146 }
1147 },
1148 {
1149 .xpath = "/frr-bfdd:bfdd/bfd/sessions/multi-hop/stats/remote-diagnostic",
1150 .cbs = {
1151 .get_elem = bfdd_bfd_sessions_single_hop_stats_remote_diagnostic_get_elem,
1152 }
1153 },
1154 {
1155 .xpath = "/frr-bfdd:bfdd/bfd/sessions/multi-hop/stats/remote-multiplier",
1156 .cbs = {
1157 .get_elem = bfdd_bfd_sessions_single_hop_stats_remote_multiplier_get_elem,
1158 }
1159 },
1160 {
1161 .xpath = "/frr-bfdd:bfdd/bfd/sessions/multi-hop/stats/negotiated-transmission-interval",
1162 .cbs = {
1163 .get_elem = bfdd_bfd_sessions_single_hop_stats_negotiated_transmission_interval_get_elem,
1164 }
1165 },
1166 {
1167 .xpath = "/frr-bfdd:bfdd/bfd/sessions/multi-hop/stats/negotiated-receive-interval",
1168 .cbs = {
1169 .get_elem = bfdd_bfd_sessions_single_hop_stats_negotiated_receive_interval_get_elem,
1170 }
1171 },
1172 {
1173 .xpath = "/frr-bfdd:bfdd/bfd/sessions/multi-hop/stats/detection-mode",
1174 .cbs = {
1175 .get_elem = bfdd_bfd_sessions_single_hop_stats_detection_mode_get_elem,
1176 }
1177 },
1178 {
1179 .xpath = "/frr-bfdd:bfdd/bfd/sessions/multi-hop/stats/last-down-time",
1180 .cbs = {
1181 .get_elem = bfdd_bfd_sessions_single_hop_stats_last_down_time_get_elem,
1182 }
1183 },
1184 {
1185 .xpath = "/frr-bfdd:bfdd/bfd/sessions/multi-hop/stats/last-up-time",
1186 .cbs = {
1187 .get_elem = bfdd_bfd_sessions_single_hop_stats_last_up_time_get_elem,
1188 }
1189 },
1190 {
1191 .xpath = "/frr-bfdd:bfdd/bfd/sessions/multi-hop/stats/session-down-count",
1192 .cbs = {
1193 .get_elem = bfdd_bfd_sessions_single_hop_stats_session_down_count_get_elem,
1194 }
1195 },
1196 {
1197 .xpath = "/frr-bfdd:bfdd/bfd/sessions/multi-hop/stats/session-up-count",
1198 .cbs = {
1199 .get_elem = bfdd_bfd_sessions_single_hop_stats_session_up_count_get_elem,
1200 }
1201 },
1202 {
1203 .xpath = "/frr-bfdd:bfdd/bfd/sessions/multi-hop/stats/control-packet-input-count",
1204 .cbs = {
1205 .get_elem = bfdd_bfd_sessions_single_hop_stats_control_packet_input_count_get_elem,
1206 }
1207 },
1208 {
1209 .xpath = "/frr-bfdd:bfdd/bfd/sessions/multi-hop/stats/control-packet-output-count",
1210 .cbs = {
1211 .get_elem = bfdd_bfd_sessions_single_hop_stats_control_packet_output_count_get_elem,
1212 }
1213 },
1214 {
1215 .xpath = "/frr-bfdd:bfdd/bfd/sessions/multi-hop/stats/negotiated-echo-transmission-interval",
1216 .cbs = {
1217 .get_elem = bfdd_bfd_sessions_single_hop_stats_negotiated_echo_transmission_interval_get_elem,
1218 }
1219 },
1220 {
1221 .xpath = "/frr-bfdd:bfdd/bfd/sessions/multi-hop/stats/echo-packet-input-count",
1222 .cbs = {
1223 .get_elem = bfdd_bfd_sessions_single_hop_stats_echo_packet_input_count_get_elem,
1224 }
1225 },
1226 {
1227 .xpath = "/frr-bfdd:bfdd/bfd/sessions/multi-hop/stats/echo-packet-output-count",
1228 .cbs = {
1229 .get_elem = bfdd_bfd_sessions_single_hop_stats_echo_packet_output_count_get_elem,
1230 }
1231 },
1232 {
1233 .xpath = NULL,
1234 },
1235 }
1236 };