]> git.proxmox.com Git - mirror_frr.git/blame - bfdd/bfdd_nb_config.c
Merge pull request #5721 from mjstapp/vty_copy_to_runn
[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. */
102 BFD_SET_FLAG(bs->flags, BFD_SESS_FLAG_CONFIG);
103 bs->refcount++;
104
105 resource->ptr = bs;
106 break;
107 }
108
109 bs = bfd_session_new();
110 if (bs == NULL)
111 return NB_ERR_RESOURCE;
112
113 /* Fill the session key. */
114 bfd_session_get_key(mhop, dnode, &bs->key);
115
116 /* Set configuration flags. */
117 bs->refcount = 1;
118 BFD_SET_FLAG(bs->flags, BFD_SESS_FLAG_CONFIG);
119 if (mhop)
120 BFD_SET_FLAG(bs->flags, BFD_SESS_FLAG_MH);
121 if (bs->key.family == AF_INET6)
122 BFD_SET_FLAG(bs->flags, BFD_SESS_FLAG_IPV6);
123
124 resource->ptr = bs;
125 break;
126
127 case NB_EV_APPLY:
128 bs = resource->ptr;
129
130 /* Only attempt to registrate if freshly allocated. */
131 if (bs->discrs.my_discr == 0 && bs_registrate(bs) == NULL)
132 return NB_ERR_RESOURCE;
133
134 nb_running_set_entry(dnode, bs);
135 break;
136
137 case NB_EV_ABORT:
138 bs = resource->ptr;
139 if (bs->refcount <= 1)
140 bfd_session_free(resource->ptr);
141 break;
142 }
143
144 return NB_OK;
145}
146
147static int bfd_session_destroy(enum nb_event event,
148 const struct lyd_node *dnode, bool mhop)
149{
150 struct bfd_session *bs;
151 struct bfd_key bk;
152
153 switch (event) {
154 case NB_EV_VALIDATE:
155 bfd_session_get_key(mhop, dnode, &bk);
156 if (bfd_key_lookup(bk) == NULL)
157 return NB_ERR_INCONSISTENCY;
158 break;
159
160 case NB_EV_PREPARE:
161 /* NOTHING */
162 break;
163
164 case NB_EV_APPLY:
165 bs = nb_running_unset_entry(dnode);
166 /* CLI is not using this session anymore. */
167 if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_CONFIG) == 0)
168 break;
169
170 BFD_UNSET_FLAG(bs->flags, BFD_SESS_FLAG_CONFIG);
171 bs->refcount--;
172 /* There are still daemons using it. */
173 if (bs->refcount > 0)
174 break;
175
176 bfd_session_free(bs);
177 break;
178
179 case NB_EV_ABORT:
180 /* NOTHING */
181 break;
182 }
183
184 return NB_OK;
185}
186
187/*
188 * XPath: /frr-bfdd:bfdd/bfd
189 */
190int bfdd_bfd_create(enum nb_event event,
191 const struct lyd_node *dnode __attribute__((__unused__)),
192 union nb_resource *resource __attribute__((__unused__)))
193{
194 /* NOTHING */
195 return NB_OK;
196}
197
198int 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 */
224int 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
231int 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/*
238 * XPath: /frr-bfdd:bfdd/bfd/sessions/single-hop/source-addr
239 */
240int bfdd_bfd_sessions_single_hop_source_addr_modify(enum nb_event event
241 __attribute__((__unused__)),
242 const struct lyd_node *dnode
243 __attribute__((__unused__)),
244 union nb_resource *resource
245 __attribute__((__unused__)))
246{
247 return NB_OK;
248}
249
250int bfdd_bfd_sessions_single_hop_source_addr_destroy(
251 enum nb_event event __attribute__((__unused__)),
252 const struct lyd_node *dnode __attribute__((__unused__)))
253{
254 return NB_OK;
255}
256
257/*
258 * XPath: /frr-bfdd:bfdd/bfd/sessions/single-hop/detection-multiplier
259 */
260int bfdd_bfd_sessions_single_hop_detection_multiplier_modify(
261 enum nb_event event, const struct lyd_node *dnode,
262 union nb_resource *resource __attribute__((__unused__)))
263{
264 uint8_t detection_multiplier = yang_dnode_get_uint8(dnode, NULL);
265 struct bfd_session *bs;
266
267 switch (event) {
268 case NB_EV_VALIDATE:
269 break;
270
271 case NB_EV_PREPARE:
272 /* NOTHING */
273 break;
274
275 case NB_EV_APPLY:
276 bs = nb_running_get_entry(dnode, NULL, true);
277 bs->detect_mult = detection_multiplier;
278 break;
279
280 case NB_EV_ABORT:
281 /* NOTHING */
282 break;
283 }
284
285 return NB_OK;
286}
287
288/*
289 * XPath: /frr-bfdd:bfdd/bfd/sessions/single-hop/desired-transmission-interval
290 */
291int bfdd_bfd_sessions_single_hop_desired_transmission_interval_modify(
292 enum nb_event event, const struct lyd_node *dnode,
293 union nb_resource *resource __attribute__((__unused__)))
294{
295 uint32_t tx_interval = yang_dnode_get_uint32(dnode, NULL);
296 struct bfd_session *bs;
297
298 switch (event) {
299 case NB_EV_VALIDATE:
300 if (tx_interval < 10000 || tx_interval > 60000000)
301 return NB_ERR_VALIDATION;
302 break;
303
304 case NB_EV_PREPARE:
305 /* NOTHING */
306 break;
307
308 case NB_EV_APPLY:
309 bs = nb_running_get_entry(dnode, NULL, true);
310 if (tx_interval == bs->timers.desired_min_tx)
311 return NB_OK;
312
313 bs->timers.desired_min_tx = tx_interval;
314 bfd_set_polling(bs);
315 break;
316
317 case NB_EV_ABORT:
318 /* NOTHING */
319 break;
320 }
321
322 return NB_OK;
323}
324
325/*
326 * XPath: /frr-bfdd:bfdd/bfd/sessions/single-hop/required-receive-interval
327 */
328int bfdd_bfd_sessions_single_hop_required_receive_interval_modify(
329 enum nb_event event, const struct lyd_node *dnode,
330 union nb_resource *resource __attribute__((__unused__)))
331{
332 uint32_t rx_interval = yang_dnode_get_uint32(dnode, NULL);
333 struct bfd_session *bs;
334
335 switch (event) {
336 case NB_EV_VALIDATE:
337 if (rx_interval < 10000 || rx_interval > 60000000)
338 return NB_ERR_VALIDATION;
339 break;
340
341 case NB_EV_PREPARE:
342 /* NOTHING */
343 break;
344
345 case NB_EV_APPLY:
346 bs = nb_running_get_entry(dnode, NULL, true);
347 if (rx_interval == bs->timers.required_min_rx)
348 return NB_OK;
349
350 bs->timers.required_min_rx = rx_interval;
351 bfd_set_polling(bs);
352 break;
353
354 case NB_EV_ABORT:
355 /* NOTHING */
356 break;
357 }
358
359 return NB_OK;
360}
361
362/*
363 * XPath: /frr-bfdd:bfdd/bfd/sessions/single-hop/administrative-down
364 */
365int bfdd_bfd_sessions_single_hop_administrative_down_modify(
366 enum nb_event event, const struct lyd_node *dnode,
367 union nb_resource *resource __attribute__((__unused__)))
368{
369 bool shutdown = yang_dnode_get_bool(dnode, NULL);
370 struct bfd_session *bs;
371
372 switch (event) {
373 case NB_EV_VALIDATE:
374 case NB_EV_PREPARE:
375 return NB_OK;
376
377 case NB_EV_APPLY:
378 break;
379
380 case NB_EV_ABORT:
381 return NB_OK;
382 }
383
384 bs = nb_running_get_entry(dnode, NULL, true);
385
386 if (shutdown == false) {
387 if (!BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN))
388 return NB_OK;
389
390 BFD_UNSET_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN);
391
392 /* Change and notify state change. */
393 bs->ses_state = PTM_BFD_DOWN;
394 control_notify(bs, bs->ses_state);
395
396 /* Enable all timers. */
397 bfd_recvtimer_update(bs);
398 bfd_xmttimer_update(bs, bs->xmt_TO);
399 if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO)) {
400 bfd_echo_recvtimer_update(bs);
401 bfd_echo_xmttimer_update(bs, bs->echo_xmt_TO);
402 }
403 } else {
404 if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN))
405 return NB_OK;
406
407 BFD_SET_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN);
408
409 /* Disable all events. */
410 bfd_recvtimer_delete(bs);
411 bfd_echo_recvtimer_delete(bs);
412 bfd_xmttimer_delete(bs);
413 bfd_echo_xmttimer_delete(bs);
414
415 /* Change and notify state change. */
416 bs->ses_state = PTM_BFD_ADM_DOWN;
417 control_notify(bs, bs->ses_state);
418
419 ptm_bfd_snd(bs, 0);
420 }
421
422 return NB_OK;
423}
424
425/*
426 * XPath: /frr-bfdd:bfdd/bfd/sessions/single-hop/echo-mode
427 */
428int bfdd_bfd_sessions_single_hop_echo_mode_modify(enum nb_event event,
429 const struct lyd_node *dnode,
430 union nb_resource *resource
431 __attribute__((__unused__)))
432{
433 bool echo = yang_dnode_get_bool(dnode, NULL);
434 struct bfd_session *bs;
435
436 switch (event) {
437 case NB_EV_VALIDATE:
438 case NB_EV_PREPARE:
439 return NB_OK;
440
441 case NB_EV_APPLY:
442 break;
443
444 case NB_EV_ABORT:
445 return NB_OK;
446 }
447
448 bs = nb_running_get_entry(dnode, NULL, true);
449
450 if (echo == false) {
451 if (!BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO))
452 return NB_OK;
453
454 BFD_UNSET_FLAG(bs->flags, BFD_SESS_FLAG_ECHO);
455 ptm_bfd_echo_stop(bs);
456 } else {
457 if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO))
458 return NB_OK;
459
460 BFD_SET_FLAG(bs->flags, BFD_SESS_FLAG_ECHO);
461 /* Apply setting immediately. */
462 if (!BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN))
463 bs_echo_timer_handler(bs);
464 }
465
466 return NB_OK;
467}
468
469/*
470 * XPath:
471 * /frr-bfdd:bfdd/bfd/sessions/single-hop/desired-echo-transmission-interval
472 */
473int bfdd_bfd_sessions_single_hop_desired_echo_transmission_interval_modify(
474 enum nb_event event, const struct lyd_node *dnode,
475 union nb_resource *resource __attribute__((__unused__)))
476{
477 uint32_t echo_interval = yang_dnode_get_uint32(dnode, NULL);
478 struct bfd_session *bs;
479
480 switch (event) {
481 case NB_EV_VALIDATE:
482 if (echo_interval < 10000 || echo_interval > 60000000)
483 return NB_ERR_VALIDATION;
484 break;
485
486 case NB_EV_PREPARE:
487 /* NOTHING */
488 break;
489
490 case NB_EV_APPLY:
491 bs = nb_running_get_entry(dnode, NULL, true);
492 if (echo_interval == bs->timers.required_min_echo)
493 return NB_OK;
494
495 bs->timers.required_min_echo = echo_interval;
496 break;
497
498 case NB_EV_ABORT:
499 /* NOTHING */
500 break;
501 }
502
503 return NB_OK;
504}
505
506/*
507 * XPath: /frr-bfdd:bfdd/bfd/sessions/multi-hop
508 */
509int bfdd_bfd_sessions_multi_hop_create(enum nb_event event,
510 const struct lyd_node *dnode,
511 union nb_resource *resource)
512{
513 return bfd_session_create(event, dnode, resource, true);
514}
515
516int bfdd_bfd_sessions_multi_hop_destroy(enum nb_event event,
517 const struct lyd_node *dnode)
518{
519 return bfd_session_destroy(event, dnode, true);
520}