]> git.proxmox.com Git - mirror_frr.git/blame - bfdd/bfdd_nb_config.c
Merge pull request #6719 from opensourcerouting/fpm-force-nhg-fix
[mirror_frr.git] / bfdd / bfdd_nb_config.c
CommitLineData
6c574029
RW
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#include "bfdd_nb.h"
30
31/*
32 * Helpers.
33 */
34static void bfd_session_get_key(bool mhop, const struct lyd_node *dnode,
35 struct bfd_key *bk)
36{
37 const char *ifname = NULL, *vrfname = NULL;
38 struct sockaddr_any psa, lsa;
39
40 /* Required destination parameter. */
41 strtosa(yang_dnode_get_string(dnode, "./dest-addr"), &psa);
42
43 /* Get optional source address. */
44 memset(&lsa, 0, sizeof(lsa));
45 if (yang_dnode_exists(dnode, "./source-addr"))
46 strtosa(yang_dnode_get_string(dnode, "./source-addr"), &lsa);
47
48 /* Get optional interface and vrf names. */
49 if (yang_dnode_exists(dnode, "./interface"))
50 ifname = yang_dnode_get_string(dnode, "./interface");
51 if (yang_dnode_exists(dnode, "./vrf"))
52 vrfname = yang_dnode_get_string(dnode, "./vrf");
53
54 /* Generate the corresponding key. */
55 gen_bfd_key(bk, &psa, &lsa, mhop, ifname, vrfname);
56}
57
58static int bfd_session_create(enum nb_event event, const struct lyd_node *dnode,
59 union nb_resource *resource, bool mhop)
60{
61 struct bfd_session *bs;
62 const char *ifname;
63 struct bfd_key bk;
64 struct prefix p;
65
66 switch (event) {
67 case NB_EV_VALIDATE:
68 /*
69 * When `dest-addr` is IPv6 and link-local we must
70 * require interface name, otherwise we can't figure
71 * which interface to use to send the packets.
72 */
73 yang_dnode_get_prefix(&p, dnode, "./dest-addr");
74
75 /*
76 * To support old FRR versions we must allow empty
77 * interface to be specified, however that should
78 * change in the future.
79 */
80 if (yang_dnode_exists(dnode, "./interface"))
81 ifname = yang_dnode_get_string(dnode, "./interface");
82 else
83 ifname = "";
84
85 if (p.family == AF_INET6 && IN6_IS_ADDR_LINKLOCAL(&p.u.prefix6)
86 && strlen(ifname) == 0) {
87 zlog_warn(
88 "%s: when using link-local you must specify "
89 "an interface.",
90 __func__);
91 return NB_ERR_VALIDATION;
92 }
93 break;
94
95 case NB_EV_PREPARE:
96 bfd_session_get_key(mhop, dnode, &bk);
97 bs = bfd_key_lookup(bk);
98
99 /* This session was already configured by another daemon. */
100 if (bs != NULL) {
101 /* Now it is configured also by CLI. */
b88113ef 102 SET_FLAG(bs->flags, BFD_SESS_FLAG_CONFIG);
6c574029
RW
103 bs->refcount++;
104
105 resource->ptr = bs;
106 break;
107 }
108
109 bs = bfd_session_new();
6c574029
RW
110
111 /* Fill the session key. */
112 bfd_session_get_key(mhop, dnode, &bs->key);
113
114 /* Set configuration flags. */
115 bs->refcount = 1;
b88113ef 116 SET_FLAG(bs->flags, BFD_SESS_FLAG_CONFIG);
6c574029 117 if (mhop)
b88113ef 118 SET_FLAG(bs->flags, BFD_SESS_FLAG_MH);
6c574029 119 if (bs->key.family == AF_INET6)
b88113ef 120 SET_FLAG(bs->flags, BFD_SESS_FLAG_IPV6);
6c574029
RW
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
145static 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. */
b88113ef 165 if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_CONFIG) == 0)
6c574029
RW
166 break;
167
b88113ef 168 UNSET_FLAG(bs->flags, BFD_SESS_FLAG_CONFIG);
6c574029
RW
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 */
60ee8be1 188int bfdd_bfd_create(struct nb_cb_create_args *args)
6c574029
RW
189{
190 /* NOTHING */
191 return NB_OK;
192}
193
60ee8be1 194int bfdd_bfd_destroy(struct nb_cb_destroy_args *args)
6c574029 195{
60ee8be1 196 switch (args->event) {
6c574029
RW
197 case NB_EV_VALIDATE:
198 /* NOTHING */
199 return NB_OK;
200
201 case NB_EV_PREPARE:
202 /* NOTHING */
203 return NB_OK;
204
205 case NB_EV_APPLY:
206 bfd_sessions_remove_manual();
207 break;
208
209 case NB_EV_ABORT:
210 /* NOTHING */
211 return NB_OK;
212 }
213
214 return NB_OK;
215}
216
ccc9ada8
RZ
217/*
218 * XPath: /frr-bfdd:bfdd/bfd/profile
219 */
220int bfdd_bfd_profile_create(struct nb_cb_create_args *args)
221{
222 struct bfd_profile *bp;
223 const char *name;
224
225 if (args->event != NB_EV_APPLY)
226 return NB_OK;
227
228 name = yang_dnode_get_string(args->dnode, "./name");
229 bp = bfd_profile_new(name);
230 nb_running_set_entry(args->dnode, bp);
231
232 return NB_OK;
233}
234
235int bfdd_bfd_profile_destroy(struct nb_cb_destroy_args *args)
236{
237 struct bfd_profile *bp;
238
239 if (args->event != NB_EV_APPLY)
240 return NB_OK;
241
242 bp = nb_running_unset_entry(args->dnode);
243 bfd_profile_free(bp);
244
245 return NB_OK;
246}
247
248/*
249 * XPath: /frr-bfdd:bfdd/bfd/profile/detection-multiplier
250 */
251int bfdd_bfd_profile_detection_multiplier_modify(struct nb_cb_modify_args *args)
252{
253 struct bfd_profile *bp;
254
255 if (args->event != NB_EV_APPLY)
256 return NB_OK;
257
258 bp = nb_running_get_entry(args->dnode, NULL, true);
259 bp->detection_multiplier = yang_dnode_get_uint8(args->dnode, NULL);
260
261 return NB_OK;
262}
263
264/*
265 * XPath: /frr-bfdd:bfdd/bfd/profile/desired-transmission-interval
266 */
267int bfdd_bfd_profile_desired_transmission_interval_modify(
268 struct nb_cb_modify_args *args)
269{
270 struct bfd_profile *bp;
271 uint32_t min_tx;
272
273 switch (args->event) {
274 case NB_EV_VALIDATE:
275 min_tx = yang_dnode_get_uint32(args->dnode, NULL);
276 if (min_tx < 10000 || min_tx > 60000000)
277 return NB_ERR_VALIDATION;
278 break;
279
280 case NB_EV_PREPARE:
281 /* NOTHING */
282 break;
283
284 case NB_EV_APPLY:
285 min_tx = yang_dnode_get_uint32(args->dnode, NULL);
286 bp = nb_running_get_entry(args->dnode, NULL, true);
287 if (bp->min_tx == min_tx)
288 return NB_OK;
289
290 bp->min_tx = min_tx;
291 bfd_profile_update(bp);
292 break;
293
294 case NB_EV_ABORT:
295 /* NOTHING */
296 break;
297 }
298
299 return NB_OK;
300}
301
302/*
303 * XPath: /frr-bfdd:bfdd/bfd/profile/required-receive-interval
304 */
305int bfdd_bfd_profile_required_receive_interval_modify(
306 struct nb_cb_modify_args *args)
307{
308 struct bfd_profile *bp;
309 uint32_t min_rx;
310
311 switch (args->event) {
312 case NB_EV_VALIDATE:
313 min_rx = yang_dnode_get_uint32(args->dnode, NULL);
314 if (min_rx < 10000 || min_rx > 60000000)
315 return NB_ERR_VALIDATION;
316 break;
317
318 case NB_EV_PREPARE:
319 /* NOTHING */
320 break;
321
322 case NB_EV_APPLY:
323 min_rx = yang_dnode_get_uint32(args->dnode, NULL);
324 bp = nb_running_get_entry(args->dnode, NULL, true);
325 if (bp->min_rx == min_rx)
326 return NB_OK;
327
328 bp->min_rx = min_rx;
329 bfd_profile_update(bp);
330 break;
331
332 case NB_EV_ABORT:
333 /* NOTHING */
334 break;
335 }
336
337 return NB_OK;
338}
339
340/*
341 * XPath: /frr-bfdd:bfdd/bfd/profile/administrative-down
342 */
343int bfdd_bfd_profile_administrative_down_modify(struct nb_cb_modify_args *args)
344{
345 struct bfd_profile *bp;
346 bool shutdown;
347
348 if (args->event != NB_EV_APPLY)
349 return NB_OK;
350
351 shutdown = yang_dnode_get_bool(args->dnode, NULL);
352 bp = nb_running_get_entry(args->dnode, NULL, true);
353 if (bp->admin_shutdown == shutdown)
354 return NB_OK;
355
356 bp->admin_shutdown = shutdown;
357 bfd_profile_update(bp);
358
359 return NB_OK;
360}
361
362/*
363 * XPath: /frr-bfdd:bfdd/bfd/profile/echo-mode
364 */
365int bfdd_bfd_profile_echo_mode_modify(struct nb_cb_modify_args *args)
366{
367 struct bfd_profile *bp;
368 bool echo;
369
370 if (args->event != NB_EV_APPLY)
371 return NB_OK;
372
373 echo = yang_dnode_get_bool(args->dnode, NULL);
374 bp = nb_running_get_entry(args->dnode, NULL, true);
375 if (bp->echo_mode == echo)
376 return NB_OK;
377
378 bp->echo_mode = echo;
379 bfd_profile_update(bp);
380
381 return NB_OK;
382}
383
384/*
385 * XPath: /frr-bfdd:bfdd/bfd/profile/desired-echo-echo-transmission-interval
386 */
387int bfdd_bfd_profile_desired_echo_transmission_interval_modify(
388 struct nb_cb_modify_args *args)
389{
390 struct bfd_profile *bp;
391 uint32_t min_rx;
392
393 switch (args->event) {
394 case NB_EV_VALIDATE:
395 min_rx = yang_dnode_get_uint32(args->dnode, NULL);
396 if (min_rx < 10000 || min_rx > 60000000)
397 return NB_ERR_VALIDATION;
398 break;
399
400 case NB_EV_PREPARE:
401 /* NOTHING */
402 break;
403
404 case NB_EV_APPLY:
405 min_rx = yang_dnode_get_uint32(args->dnode, NULL);
406 bp = nb_running_get_entry(args->dnode, NULL, true);
407 if (bp->min_echo_rx == min_rx)
408 return NB_OK;
409
410 bp->min_echo_rx = min_rx;
411 bfd_profile_update(bp);
412 break;
413
414 case NB_EV_ABORT:
415 /* NOTHING */
416 break;
417 }
418
419 return NB_OK;
420}
421
6c574029
RW
422/*
423 * XPath: /frr-bfdd:bfdd/bfd/sessions/single-hop
424 */
60ee8be1 425int bfdd_bfd_sessions_single_hop_create(struct nb_cb_create_args *args)
6c574029 426{
60ee8be1
RW
427 return bfd_session_create(args->event, args->dnode, args->resource,
428 false);
6c574029
RW
429}
430
60ee8be1 431int bfdd_bfd_sessions_single_hop_destroy(struct nb_cb_destroy_args *args)
6c574029 432{
60ee8be1 433 return bfd_session_destroy(args->event, args->dnode, false);
6c574029
RW
434}
435
436/*
437 * XPath: /frr-bfdd:bfdd/bfd/sessions/single-hop/source-addr
438 */
60ee8be1
RW
439int bfdd_bfd_sessions_single_hop_source_addr_modify(
440 struct nb_cb_modify_args *args)
6c574029
RW
441{
442 return NB_OK;
443}
444
445int bfdd_bfd_sessions_single_hop_source_addr_destroy(
60ee8be1 446 struct nb_cb_destroy_args *args)
6c574029
RW
447{
448 return NB_OK;
449}
450
ccc9ada8
RZ
451/*
452 * XPath: /frr-bfdd:bfdd/bfd/sessions/single-hop/profile
453 */
454int bfdd_bfd_sessions_single_hop_profile_modify(struct nb_cb_modify_args *args)
455{
456 struct bfd_session *bs;
457
458 if (args->event != NB_EV_APPLY)
459 return NB_OK;
460
461 bs = nb_running_get_entry(args->dnode, NULL, true);
462 bfd_profile_apply(yang_dnode_get_string(args->dnode, NULL), bs);
463
464 return NB_OK;
465}
466
467int bfdd_bfd_sessions_single_hop_profile_destroy(
468 struct nb_cb_destroy_args *args)
469{
470 struct bfd_session *bs;
471
472 if (args->event != NB_EV_APPLY)
473 return NB_OK;
474
475 bs = nb_running_get_entry(args->dnode, NULL, true);
476 bfd_profile_remove(bs);
477
478 return NB_OK;
479}
480
6c574029
RW
481/*
482 * XPath: /frr-bfdd:bfdd/bfd/sessions/single-hop/detection-multiplier
483 */
484int bfdd_bfd_sessions_single_hop_detection_multiplier_modify(
60ee8be1 485 struct nb_cb_modify_args *args)
6c574029 486{
60ee8be1 487 uint8_t detection_multiplier = yang_dnode_get_uint8(args->dnode, NULL);
6c574029
RW
488 struct bfd_session *bs;
489
60ee8be1 490 switch (args->event) {
6c574029
RW
491 case NB_EV_VALIDATE:
492 break;
493
494 case NB_EV_PREPARE:
495 /* NOTHING */
496 break;
497
498 case NB_EV_APPLY:
60ee8be1 499 bs = nb_running_get_entry(args->dnode, NULL, true);
6c574029 500 bs->detect_mult = detection_multiplier;
ccc9ada8 501 bs->peer_profile.detection_multiplier = detection_multiplier;
6c574029
RW
502 break;
503
504 case NB_EV_ABORT:
505 /* NOTHING */
506 break;
507 }
508
509 return NB_OK;
510}
511
512/*
513 * XPath: /frr-bfdd:bfdd/bfd/sessions/single-hop/desired-transmission-interval
514 */
515int bfdd_bfd_sessions_single_hop_desired_transmission_interval_modify(
60ee8be1 516 struct nb_cb_modify_args *args)
6c574029 517{
60ee8be1 518 uint32_t tx_interval = yang_dnode_get_uint32(args->dnode, NULL);
6c574029
RW
519 struct bfd_session *bs;
520
60ee8be1 521 switch (args->event) {
6c574029
RW
522 case NB_EV_VALIDATE:
523 if (tx_interval < 10000 || tx_interval > 60000000)
524 return NB_ERR_VALIDATION;
525 break;
526
527 case NB_EV_PREPARE:
528 /* NOTHING */
529 break;
530
531 case NB_EV_APPLY:
60ee8be1 532 bs = nb_running_get_entry(args->dnode, NULL, true);
6c574029
RW
533 if (tx_interval == bs->timers.desired_min_tx)
534 return NB_OK;
535
536 bs->timers.desired_min_tx = tx_interval;
ccc9ada8 537 bs->peer_profile.min_tx = tx_interval;
6c574029
RW
538 bfd_set_polling(bs);
539 break;
540
541 case NB_EV_ABORT:
542 /* NOTHING */
543 break;
544 }
545
546 return NB_OK;
547}
548
549/*
550 * XPath: /frr-bfdd:bfdd/bfd/sessions/single-hop/required-receive-interval
551 */
552int bfdd_bfd_sessions_single_hop_required_receive_interval_modify(
60ee8be1 553 struct nb_cb_modify_args *args)
6c574029 554{
60ee8be1 555 uint32_t rx_interval = yang_dnode_get_uint32(args->dnode, NULL);
6c574029
RW
556 struct bfd_session *bs;
557
60ee8be1 558 switch (args->event) {
6c574029
RW
559 case NB_EV_VALIDATE:
560 if (rx_interval < 10000 || rx_interval > 60000000)
561 return NB_ERR_VALIDATION;
562 break;
563
564 case NB_EV_PREPARE:
565 /* NOTHING */
566 break;
567
568 case NB_EV_APPLY:
60ee8be1 569 bs = nb_running_get_entry(args->dnode, NULL, true);
6c574029
RW
570 if (rx_interval == bs->timers.required_min_rx)
571 return NB_OK;
572
573 bs->timers.required_min_rx = rx_interval;
ccc9ada8 574 bs->peer_profile.min_rx = rx_interval;
6c574029
RW
575 bfd_set_polling(bs);
576 break;
577
578 case NB_EV_ABORT:
579 /* NOTHING */
580 break;
581 }
582
583 return NB_OK;
584}
585
586/*
587 * XPath: /frr-bfdd:bfdd/bfd/sessions/single-hop/administrative-down
588 */
589int bfdd_bfd_sessions_single_hop_administrative_down_modify(
60ee8be1 590 struct nb_cb_modify_args *args)
6c574029 591{
60ee8be1 592 bool shutdown = yang_dnode_get_bool(args->dnode, NULL);
6c574029
RW
593 struct bfd_session *bs;
594
60ee8be1 595 switch (args->event) {
6c574029
RW
596 case NB_EV_VALIDATE:
597 case NB_EV_PREPARE:
598 return NB_OK;
599
600 case NB_EV_APPLY:
601 break;
602
603 case NB_EV_ABORT:
604 return NB_OK;
605 }
606
60ee8be1 607 bs = nb_running_get_entry(args->dnode, NULL, true);
ccc9ada8 608 bs->peer_profile.admin_shutdown = shutdown;
4d12e1f9 609 bfd_set_shutdown(bs, shutdown);
6c574029
RW
610
611 return NB_OK;
612}
613
614/*
615 * XPath: /frr-bfdd:bfdd/bfd/sessions/single-hop/echo-mode
616 */
60ee8be1
RW
617int bfdd_bfd_sessions_single_hop_echo_mode_modify(
618 struct nb_cb_modify_args *args)
6c574029 619{
60ee8be1 620 bool echo = yang_dnode_get_bool(args->dnode, NULL);
6c574029
RW
621 struct bfd_session *bs;
622
60ee8be1 623 switch (args->event) {
6c574029
RW
624 case NB_EV_VALIDATE:
625 case NB_EV_PREPARE:
626 return NB_OK;
627
628 case NB_EV_APPLY:
629 break;
630
631 case NB_EV_ABORT:
632 return NB_OK;
633 }
634
60ee8be1 635 bs = nb_running_get_entry(args->dnode, NULL, true);
ccc9ada8 636 bs->peer_profile.echo_mode = echo;
4d12e1f9 637 bfd_set_echo(bs, echo);
6c574029
RW
638
639 return NB_OK;
640}
641
642/*
643 * XPath:
644 * /frr-bfdd:bfdd/bfd/sessions/single-hop/desired-echo-transmission-interval
645 */
646int bfdd_bfd_sessions_single_hop_desired_echo_transmission_interval_modify(
60ee8be1 647 struct nb_cb_modify_args *args)
6c574029 648{
60ee8be1 649 uint32_t echo_interval = yang_dnode_get_uint32(args->dnode, NULL);
6c574029
RW
650 struct bfd_session *bs;
651
60ee8be1 652 switch (args->event) {
6c574029
RW
653 case NB_EV_VALIDATE:
654 if (echo_interval < 10000 || echo_interval > 60000000)
655 return NB_ERR_VALIDATION;
656 break;
657
658 case NB_EV_PREPARE:
659 /* NOTHING */
660 break;
661
662 case NB_EV_APPLY:
60ee8be1 663 bs = nb_running_get_entry(args->dnode, NULL, true);
6c574029
RW
664 if (echo_interval == bs->timers.required_min_echo)
665 return NB_OK;
666
667 bs->timers.required_min_echo = echo_interval;
ccc9ada8 668 bs->peer_profile.min_echo_rx = echo_interval;
6c574029
RW
669 break;
670
671 case NB_EV_ABORT:
672 /* NOTHING */
673 break;
674 }
675
676 return NB_OK;
677}
678
679/*
680 * XPath: /frr-bfdd:bfdd/bfd/sessions/multi-hop
681 */
60ee8be1 682int bfdd_bfd_sessions_multi_hop_create(struct nb_cb_create_args *args)
6c574029 683{
60ee8be1
RW
684 return bfd_session_create(args->event, args->dnode, args->resource,
685 true);
6c574029
RW
686}
687
60ee8be1 688int bfdd_bfd_sessions_multi_hop_destroy(struct nb_cb_destroy_args *args)
6c574029 689{
60ee8be1 690 return bfd_session_destroy(args->event, args->dnode, true);
6c574029 691}