]> git.proxmox.com Git - mirror_frr.git/blob - ripngd/ripng_northbound.c
ripngd: add VRF support
[mirror_frr.git] / ripngd / ripng_northbound.c
1 /*
2 * Copyright (C) 1998 Kunihiro Ishiguro
3 * Copyright (C) 2018 NetDEF, Inc.
4 * Renato Westphal
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the Free
8 * Software Foundation; either version 2 of the License, or (at your option)
9 * any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; see the file COPYING; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 #include <zebra.h>
22
23 #include "if.h"
24 #include "vrf.h"
25 #include "log.h"
26 #include "prefix.h"
27 #include "table.h"
28 #include "command.h"
29 #include "routemap.h"
30 #include "agg_table.h"
31 #include "northbound.h"
32 #include "libfrr.h"
33
34 #include "ripngd/ripngd.h"
35 #include "ripngd/ripng_route.h"
36 #include "ripngd/ripng_cli.h"
37
38 /*
39 * XPath: /frr-ripngd:ripngd/instance
40 */
41 static int ripngd_instance_create(enum nb_event event,
42 const struct lyd_node *dnode,
43 union nb_resource *resource)
44 {
45 struct ripng *ripng;
46 struct vrf *vrf;
47 const char *vrf_name;
48 int socket;
49
50 vrf_name = yang_dnode_get_string(dnode, "./vrf");
51 vrf = vrf_lookup_by_name(vrf_name);
52
53 /*
54 * Try to create a RIPng socket only if the VRF is enabled, otherwise
55 * create a disabled RIPng instance and wait for the VRF to be enabled.
56 */
57 switch (event) {
58 case NB_EV_VALIDATE:
59 break;
60 case NB_EV_PREPARE:
61 if (!vrf || !vrf_is_enabled(vrf))
62 break;
63
64 socket = ripng_make_socket(vrf);
65 if (socket < 0)
66 return NB_ERR_RESOURCE;
67 resource->fd = socket;
68 break;
69 case NB_EV_ABORT:
70 if (!vrf || !vrf_is_enabled(vrf))
71 break;
72
73 socket = resource->fd;
74 close(socket);
75 break;
76 case NB_EV_APPLY:
77 if (vrf && vrf_is_enabled(vrf))
78 socket = resource->fd;
79 else
80 socket = -1;
81
82 ripng = ripng_create(vrf_name, vrf, socket);
83 yang_dnode_set_entry(dnode, ripng);
84 break;
85 }
86
87 return NB_OK;
88 }
89
90 static int ripngd_instance_delete(enum nb_event event,
91 const struct lyd_node *dnode)
92 {
93 struct ripng *ripng;
94
95 if (event != NB_EV_APPLY)
96 return NB_OK;
97
98 ripng = yang_dnode_get_entry(dnode, true);
99 ripng_clean(ripng);
100
101 return NB_OK;
102 }
103
104 /*
105 * XPath: /frr-ripngd:ripngd/instance/allow-ecmp
106 */
107 static int ripngd_instance_allow_ecmp_modify(enum nb_event event,
108 const struct lyd_node *dnode,
109 union nb_resource *resource)
110 {
111 struct ripng *ripng;
112
113 if (event != NB_EV_APPLY)
114 return NB_OK;
115
116 ripng = yang_dnode_get_entry(dnode, true);
117 ripng->ecmp = yang_dnode_get_bool(dnode, NULL);
118 if (!ripng->ecmp)
119 ripng_ecmp_disable(ripng);
120
121 return NB_OK;
122 }
123
124 /*
125 * XPath: /frr-ripngd:ripngd/instance/default-information-originate
126 */
127 static int ripngd_instance_default_information_originate_modify(
128 enum nb_event event, const struct lyd_node *dnode,
129 union nb_resource *resource)
130 {
131 struct ripng *ripng;
132 bool default_information;
133 struct prefix_ipv6 p;
134
135 if (event != NB_EV_APPLY)
136 return NB_OK;
137
138 ripng = yang_dnode_get_entry(dnode, true);
139 default_information = yang_dnode_get_bool(dnode, NULL);
140
141 str2prefix_ipv6("::/0", &p);
142 if (default_information) {
143 ripng_redistribute_add(ripng, ZEBRA_ROUTE_RIPNG,
144 RIPNG_ROUTE_DEFAULT, &p, 0, NULL, 0);
145 } else {
146 ripng_redistribute_delete(ripng, ZEBRA_ROUTE_RIPNG,
147 RIPNG_ROUTE_DEFAULT, &p, 0);
148 }
149
150 return NB_OK;
151 }
152
153 /*
154 * XPath: /frr-ripngd:ripngd/instance/default-metric
155 */
156 static int ripngd_instance_default_metric_modify(enum nb_event event,
157 const struct lyd_node *dnode,
158 union nb_resource *resource)
159 {
160 struct ripng *ripng;
161
162 if (event != NB_EV_APPLY)
163 return NB_OK;
164
165 ripng = yang_dnode_get_entry(dnode, true);
166 ripng->default_metric = yang_dnode_get_uint8(dnode, NULL);
167
168 return NB_OK;
169 }
170
171 /*
172 * XPath: /frr-ripngd:ripngd/instance/network
173 */
174 static int ripngd_instance_network_create(enum nb_event event,
175 const struct lyd_node *dnode,
176 union nb_resource *resource)
177 {
178 struct ripng *ripng;
179 struct prefix p;
180
181 if (event != NB_EV_APPLY)
182 return NB_OK;
183
184 ripng = yang_dnode_get_entry(dnode, true);
185 yang_dnode_get_ipv6p(&p, dnode, NULL);
186 apply_mask_ipv6((struct prefix_ipv6 *)&p);
187
188 return ripng_enable_network_add(ripng, &p);
189 }
190
191 static int ripngd_instance_network_delete(enum nb_event event,
192 const struct lyd_node *dnode)
193 {
194 struct ripng *ripng;
195 struct prefix p;
196
197 if (event != NB_EV_APPLY)
198 return NB_OK;
199
200 ripng = yang_dnode_get_entry(dnode, true);
201 yang_dnode_get_ipv6p(&p, dnode, NULL);
202 apply_mask_ipv6((struct prefix_ipv6 *)&p);
203
204 return ripng_enable_network_delete(ripng, &p);
205 }
206
207 /*
208 * XPath: /frr-ripngd:ripngd/instance/interface
209 */
210 static int ripngd_instance_interface_create(enum nb_event event,
211 const struct lyd_node *dnode,
212 union nb_resource *resource)
213 {
214 struct ripng *ripng;
215 const char *ifname;
216
217 if (event != NB_EV_APPLY)
218 return NB_OK;
219
220 ripng = yang_dnode_get_entry(dnode, true);
221 ifname = yang_dnode_get_string(dnode, NULL);
222
223 return ripng_enable_if_add(ripng, ifname);
224 }
225
226 static int ripngd_instance_interface_delete(enum nb_event event,
227 const struct lyd_node *dnode)
228 {
229 struct ripng *ripng;
230 const char *ifname;
231
232 if (event != NB_EV_APPLY)
233 return NB_OK;
234
235 ripng = yang_dnode_get_entry(dnode, true);
236 ifname = yang_dnode_get_string(dnode, NULL);
237
238 return ripng_enable_if_delete(ripng, ifname);
239 }
240
241 /*
242 * XPath: /frr-ripngd:ripngd/instance/offset-list
243 */
244 static int ripngd_instance_offset_list_create(enum nb_event event,
245 const struct lyd_node *dnode,
246 union nb_resource *resource)
247 {
248 struct ripng *ripng;
249 const char *ifname;
250 struct ripng_offset_list *offset;
251
252 if (event != NB_EV_APPLY)
253 return NB_OK;
254
255 ripng = yang_dnode_get_entry(dnode, true);
256 ifname = yang_dnode_get_string(dnode, "./interface");
257
258 offset = ripng_offset_list_new(ripng, ifname);
259 yang_dnode_set_entry(dnode, offset);
260
261 return NB_OK;
262 }
263
264 static int ripngd_instance_offset_list_delete(enum nb_event event,
265 const struct lyd_node *dnode)
266 {
267 int direct;
268 struct ripng_offset_list *offset;
269
270 if (event != NB_EV_APPLY)
271 return NB_OK;
272
273 direct = yang_dnode_get_enum(dnode, "./direction");
274
275 offset = yang_dnode_get_entry(dnode, true);
276 if (offset->direct[direct].alist_name) {
277 free(offset->direct[direct].alist_name);
278 offset->direct[direct].alist_name = NULL;
279 }
280 if (offset->direct[RIPNG_OFFSET_LIST_IN].alist_name == NULL
281 && offset->direct[RIPNG_OFFSET_LIST_OUT].alist_name == NULL)
282 ripng_offset_list_del(offset);
283
284 return NB_OK;
285 }
286
287 /*
288 * XPath: /frr-ripngd:ripngd/instance/offset-list/access-list
289 */
290 static int
291 ripngd_instance_offset_list_access_list_modify(enum nb_event event,
292 const struct lyd_node *dnode,
293 union nb_resource *resource)
294 {
295 int direct;
296 struct ripng_offset_list *offset;
297 const char *alist_name;
298
299 if (event != NB_EV_APPLY)
300 return NB_OK;
301
302 direct = yang_dnode_get_enum(dnode, "../direction");
303 alist_name = yang_dnode_get_string(dnode, NULL);
304
305 offset = yang_dnode_get_entry(dnode, true);
306 if (offset->direct[direct].alist_name)
307 free(offset->direct[direct].alist_name);
308 offset->direct[direct].alist_name = strdup(alist_name);
309
310 return NB_OK;
311 }
312
313 /*
314 * XPath: /frr-ripngd:ripngd/instance/offset-list/metric
315 */
316 static int
317 ripngd_instance_offset_list_metric_modify(enum nb_event event,
318 const struct lyd_node *dnode,
319 union nb_resource *resource)
320 {
321 int direct;
322 uint8_t metric;
323 struct ripng_offset_list *offset;
324
325 if (event != NB_EV_APPLY)
326 return NB_OK;
327
328 direct = yang_dnode_get_enum(dnode, "../direction");
329 metric = yang_dnode_get_uint8(dnode, NULL);
330
331 offset = yang_dnode_get_entry(dnode, true);
332 offset->direct[direct].metric = metric;
333
334 return NB_OK;
335 }
336
337 /*
338 * XPath: /frr-ripngd:ripngd/instance/passive-interface
339 */
340 static int
341 ripngd_instance_passive_interface_create(enum nb_event event,
342 const struct lyd_node *dnode,
343 union nb_resource *resource)
344 {
345 struct ripng *ripng;
346 const char *ifname;
347
348 if (event != NB_EV_APPLY)
349 return NB_OK;
350
351 ripng = yang_dnode_get_entry(dnode, true);
352 ifname = yang_dnode_get_string(dnode, NULL);
353
354 return ripng_passive_interface_set(ripng, ifname);
355 }
356
357 static int
358 ripngd_instance_passive_interface_delete(enum nb_event event,
359 const struct lyd_node *dnode)
360 {
361 struct ripng *ripng;
362 const char *ifname;
363
364 if (event != NB_EV_APPLY)
365 return NB_OK;
366
367 ripng = yang_dnode_get_entry(dnode, true);
368 ifname = yang_dnode_get_string(dnode, NULL);
369
370 return ripng_passive_interface_unset(ripng, ifname);
371 }
372
373 /*
374 * XPath: /frr-ripngd:ripngd/instance/redistribute
375 */
376 static int ripngd_instance_redistribute_create(enum nb_event event,
377 const struct lyd_node *dnode,
378 union nb_resource *resource)
379 {
380 return NB_OK;
381 }
382
383 static int ripngd_instance_redistribute_delete(enum nb_event event,
384 const struct lyd_node *dnode)
385 {
386 struct ripng *ripng;
387 int type;
388
389 if (event != NB_EV_APPLY)
390 return NB_OK;
391
392 ripng = yang_dnode_get_entry(dnode, true);
393 type = yang_dnode_get_enum(dnode, "./protocol");
394
395 ripng_redistribute_conf_delete(ripng, type);
396
397 return NB_OK;
398 }
399
400 static void
401 ripngd_instance_redistribute_apply_finish(const struct lyd_node *dnode)
402 {
403 struct ripng *ripng;
404 int type;
405
406 ripng = yang_dnode_get_entry(dnode, true);
407 type = yang_dnode_get_enum(dnode, "./protocol");
408
409 ripng_redistribute_conf_update(ripng, type);
410 }
411
412 /*
413 * XPath: /frr-ripngd:ripngd/instance/redistribute/route-map
414 */
415 static int
416 ripngd_instance_redistribute_route_map_modify(enum nb_event event,
417 const struct lyd_node *dnode,
418 union nb_resource *resource)
419 {
420 struct ripng *ripng;
421 int type;
422 const char *rmap_name;
423
424 if (event != NB_EV_APPLY)
425 return NB_OK;
426
427 ripng = yang_dnode_get_entry(dnode, true);
428 type = yang_dnode_get_enum(dnode, "../protocol");
429 rmap_name = yang_dnode_get_string(dnode, NULL);
430
431 if (ripng->route_map[type].name)
432 free(ripng->route_map[type].name);
433 ripng->route_map[type].name = strdup(rmap_name);
434 ripng->route_map[type].map = route_map_lookup_by_name(rmap_name);
435
436 return NB_OK;
437 }
438
439 static int
440 ripngd_instance_redistribute_route_map_delete(enum nb_event event,
441 const struct lyd_node *dnode)
442 {
443 struct ripng *ripng;
444 int type;
445
446 if (event != NB_EV_APPLY)
447 return NB_OK;
448
449 ripng = yang_dnode_get_entry(dnode, true);
450 type = yang_dnode_get_enum(dnode, "../protocol");
451
452 free(ripng->route_map[type].name);
453 ripng->route_map[type].name = NULL;
454 ripng->route_map[type].map = NULL;
455
456 return NB_OK;
457 }
458
459 /*
460 * XPath: /frr-ripngd:ripngd/instance/redistribute/metric
461 */
462 static int
463 ripngd_instance_redistribute_metric_modify(enum nb_event event,
464 const struct lyd_node *dnode,
465 union nb_resource *resource)
466 {
467 struct ripng *ripng;
468 int type;
469 uint8_t metric;
470
471 if (event != NB_EV_APPLY)
472 return NB_OK;
473
474 ripng = yang_dnode_get_entry(dnode, true);
475 type = yang_dnode_get_enum(dnode, "../protocol");
476 metric = yang_dnode_get_uint8(dnode, NULL);
477
478 ripng->route_map[type].metric_config = true;
479 ripng->route_map[type].metric = metric;
480
481 return NB_OK;
482 }
483
484 static int
485 ripngd_instance_redistribute_metric_delete(enum nb_event event,
486 const struct lyd_node *dnode)
487 {
488 struct ripng *ripng;
489 int type;
490
491 if (event != NB_EV_APPLY)
492 return NB_OK;
493
494 ripng = yang_dnode_get_entry(dnode, true);
495 type = yang_dnode_get_enum(dnode, "../protocol");
496
497 ripng->route_map[type].metric_config = false;
498 ripng->route_map[type].metric = 0;
499
500 return NB_OK;
501 }
502
503 /*
504 * XPath: /frr-ripngd:ripngd/instance/static-route
505 */
506 static int ripngd_instance_static_route_create(enum nb_event event,
507 const struct lyd_node *dnode,
508 union nb_resource *resource)
509 {
510 struct ripng *ripng;
511 struct prefix_ipv6 p;
512
513 if (event != NB_EV_APPLY)
514 return NB_OK;
515
516 ripng = yang_dnode_get_entry(dnode, true);
517 yang_dnode_get_ipv6p(&p, dnode, NULL);
518 apply_mask_ipv6(&p);
519
520 ripng_redistribute_add(ripng, ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_STATIC, &p,
521 0, NULL, 0);
522
523 return NB_OK;
524 }
525
526 static int ripngd_instance_static_route_delete(enum nb_event event,
527 const struct lyd_node *dnode)
528 {
529 struct ripng *ripng;
530 struct prefix_ipv6 p;
531
532 if (event != NB_EV_APPLY)
533 return NB_OK;
534
535 ripng = yang_dnode_get_entry(dnode, true);
536 yang_dnode_get_ipv6p(&p, dnode, NULL);
537 apply_mask_ipv6(&p);
538
539 ripng_redistribute_delete(ripng, ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_STATIC,
540 &p, 0);
541
542 return NB_OK;
543 }
544
545 /*
546 * XPath: /frr-ripngd:ripngd/instance/aggregate-address
547 */
548 static int
549 ripngd_instance_aggregate_address_create(enum nb_event event,
550 const struct lyd_node *dnode,
551 union nb_resource *resource)
552 {
553 struct ripng *ripng;
554 struct prefix_ipv6 p;
555
556 if (event != NB_EV_APPLY)
557 return NB_OK;
558
559 ripng = yang_dnode_get_entry(dnode, true);
560 yang_dnode_get_ipv6p(&p, dnode, NULL);
561 apply_mask_ipv6(&p);
562
563 ripng_aggregate_add(ripng, (struct prefix *)&p);
564
565 return NB_OK;
566 }
567
568 static int
569 ripngd_instance_aggregate_address_delete(enum nb_event event,
570 const struct lyd_node *dnode)
571 {
572 struct ripng *ripng;
573 struct prefix_ipv6 p;
574
575 if (event != NB_EV_APPLY)
576 return NB_OK;
577
578 ripng = yang_dnode_get_entry(dnode, true);
579 yang_dnode_get_ipv6p(&p, dnode, NULL);
580 apply_mask_ipv6(&p);
581
582 ripng_aggregate_delete(ripng, (struct prefix *)&p);
583
584 return NB_OK;
585 }
586
587 /*
588 * XPath: /frr-ripngd:ripngd/instance/timers
589 */
590 static void ripngd_instance_timers_apply_finish(const struct lyd_node *dnode)
591 {
592 struct ripng *ripng;
593
594 ripng = yang_dnode_get_entry(dnode, true);
595
596 /* Reset update timer thread. */
597 ripng_event(ripng, RIPNG_UPDATE_EVENT, 0);
598 }
599
600 /*
601 * XPath: /frr-ripngd:ripngd/instance/timers/flush-interval
602 */
603 static int
604 ripngd_instance_timers_flush_interval_modify(enum nb_event event,
605 const struct lyd_node *dnode,
606 union nb_resource *resource)
607 {
608 struct ripng *ripng;
609
610 if (event != NB_EV_APPLY)
611 return NB_OK;
612
613 ripng = yang_dnode_get_entry(dnode, true);
614 ripng->garbage_time = yang_dnode_get_uint16(dnode, NULL);
615
616 return NB_OK;
617 }
618
619 /*
620 * XPath: /frr-ripngd:ripngd/instance/timers/holddown-interval
621 */
622 static int
623 ripngd_instance_timers_holddown_interval_modify(enum nb_event event,
624 const struct lyd_node *dnode,
625 union nb_resource *resource)
626 {
627 struct ripng *ripng;
628
629 if (event != NB_EV_APPLY)
630 return NB_OK;
631
632 ripng = yang_dnode_get_entry(dnode, true);
633 ripng->timeout_time = yang_dnode_get_uint16(dnode, NULL);
634
635 return NB_OK;
636 }
637
638 /*
639 * XPath: /frr-ripngd:ripngd/instance/timers/update-interval
640 */
641 static int
642 ripngd_instance_timers_update_interval_modify(enum nb_event event,
643 const struct lyd_node *dnode,
644 union nb_resource *resource)
645 {
646 struct ripng *ripng;
647
648 if (event != NB_EV_APPLY)
649 return NB_OK;
650
651 ripng = yang_dnode_get_entry(dnode, true);
652 ripng->update_time = yang_dnode_get_uint16(dnode, NULL);
653
654 return NB_OK;
655 }
656
657 /*
658 * XPath: /frr-ripngd:ripngd/state/neighbors/neighbor
659 */
660 static const void *
661 ripngd_state_neighbors_neighbor_get_next(const void *parent_list_entry,
662 const void *list_entry)
663 {
664 struct ripng *ripng;
665 struct listnode *node;
666
667 ripng = ripng_lookup_by_vrf_id(VRF_DEFAULT);
668 if (!ripng)
669 return NULL;
670
671 if (list_entry == NULL)
672 node = listhead(ripng->peer_list);
673 else
674 node = listnextnode((struct listnode *)list_entry);
675
676 return node;
677 }
678
679 static int ripngd_state_neighbors_neighbor_get_keys(const void *list_entry,
680 struct yang_list_keys *keys)
681 {
682 const struct listnode *node = list_entry;
683 const struct ripng_peer *peer = listgetdata(node);
684
685 keys->num = 1;
686 (void)inet_ntop(AF_INET6, &peer->addr, keys->key[0],
687 sizeof(keys->key[0]));
688
689 return NB_OK;
690 }
691
692 static const void *
693 ripngd_state_neighbors_neighbor_lookup_entry(const void *parent_list_entry,
694 const struct yang_list_keys *keys)
695 {
696 struct ripng *ripng;
697 struct in6_addr address;
698 struct ripng_peer *peer;
699 struct listnode *node;
700
701 yang_str2ipv6(keys->key[0], &address);
702
703 ripng = ripng_lookup_by_vrf_id(VRF_DEFAULT);
704 if (!ripng)
705 return NULL;
706
707 for (ALL_LIST_ELEMENTS_RO(ripng->peer_list, node, peer)) {
708 if (IPV6_ADDR_SAME(&peer->addr, &address))
709 return node;
710 }
711
712 return NULL;
713 }
714
715 /*
716 * XPath: /frr-ripngd:ripngd/state/neighbors/neighbor/address
717 */
718 static struct yang_data *
719 ripngd_state_neighbors_neighbor_address_get_elem(const char *xpath,
720 const void *list_entry)
721 {
722 const struct listnode *node = list_entry;
723 const struct ripng_peer *peer = listgetdata(node);
724
725 return yang_data_new_ipv6(xpath, &peer->addr);
726 }
727
728 /*
729 * XPath: /frr-ripngd:ripngd/state/neighbors/neighbor/last-update
730 */
731 static struct yang_data *
732 ripngd_state_neighbors_neighbor_last_update_get_elem(const char *xpath,
733 const void *list_entry)
734 {
735 /* TODO: yang:date-and-time is tricky */
736 return NULL;
737 }
738
739 /*
740 * XPath: /frr-ripngd:ripngd/state/neighbors/neighbor/bad-packets-rcvd
741 */
742 static struct yang_data *
743 ripngd_state_neighbors_neighbor_bad_packets_rcvd_get_elem(
744 const char *xpath, const void *list_entry)
745 {
746 const struct listnode *node = list_entry;
747 const struct ripng_peer *peer = listgetdata(node);
748
749 return yang_data_new_uint32(xpath, peer->recv_badpackets);
750 }
751
752 /*
753 * XPath: /frr-ripngd:ripngd/state/neighbors/neighbor/bad-routes-rcvd
754 */
755 static struct yang_data *
756 ripngd_state_neighbors_neighbor_bad_routes_rcvd_get_elem(const char *xpath,
757 const void *list_entry)
758 {
759 const struct listnode *node = list_entry;
760 const struct ripng_peer *peer = listgetdata(node);
761
762 return yang_data_new_uint32(xpath, peer->recv_badroutes);
763 }
764
765 /*
766 * XPath: /frr-ripngd:ripngd/state/routes/route
767 */
768 static const void *
769 ripngd_state_routes_route_get_next(const void *parent_list_entry,
770 const void *list_entry)
771 {
772 struct ripng *ripng;
773 struct agg_node *rn;
774
775 ripng = ripng_lookup_by_vrf_id(VRF_DEFAULT);
776 if (ripng == NULL)
777 return NULL;
778
779 if (list_entry == NULL)
780 rn = agg_route_top(ripng->table);
781 else
782 rn = agg_route_next((struct agg_node *)list_entry);
783 while (rn && rn->info == NULL)
784 rn = agg_route_next(rn);
785
786 return rn;
787 }
788
789 static int ripngd_state_routes_route_get_keys(const void *list_entry,
790 struct yang_list_keys *keys)
791 {
792 const struct agg_node *rn = list_entry;
793
794 keys->num = 1;
795 (void)prefix2str(&rn->p, keys->key[0], sizeof(keys->key[0]));
796
797 return NB_OK;
798 }
799
800 static const void *
801 ripngd_state_routes_route_lookup_entry(const void *parent_list_entry,
802 const struct yang_list_keys *keys)
803 {
804 struct ripng *ripng;
805 struct prefix prefix;
806 struct agg_node *rn;
807
808 yang_str2ipv6p(keys->key[0], &prefix);
809
810 ripng = ripng_lookup_by_vrf_id(VRF_DEFAULT);
811 if (!ripng)
812 return NULL;
813
814 rn = agg_node_lookup(ripng->table, &prefix);
815 if (!rn || !rn->info)
816 return NULL;
817
818 agg_unlock_node(rn);
819
820 return rn;
821 }
822
823 /*
824 * XPath: /frr-ripngd:ripngd/state/routes/route/prefix
825 */
826 static struct yang_data *
827 ripngd_state_routes_route_prefix_get_elem(const char *xpath,
828 const void *list_entry)
829 {
830 const struct agg_node *rn = list_entry;
831 const struct ripng_info *rinfo = listnode_head(rn->info);
832
833 return yang_data_new_ipv6p(xpath, &rinfo->rp->p);
834 }
835
836 /*
837 * XPath: /frr-ripngd:ripngd/state/routes/route/next-hop
838 */
839 static struct yang_data *
840 ripngd_state_routes_route_next_hop_get_elem(const char *xpath,
841 const void *list_entry)
842 {
843 const struct agg_node *rn = list_entry;
844 const struct ripng_info *rinfo = listnode_head(rn->info);
845
846 return yang_data_new_ipv6(xpath, &rinfo->nexthop);
847 }
848
849 /*
850 * XPath: /frr-ripngd:ripngd/state/routes/route/interface
851 */
852 static struct yang_data *
853 ripngd_state_routes_route_interface_get_elem(const char *xpath,
854 const void *list_entry)
855 {
856 const struct agg_node *rn = list_entry;
857 const struct ripng_info *rinfo = listnode_head(rn->info);
858
859 return yang_data_new_string(
860 xpath, ifindex2ifname(rinfo->ifindex, VRF_DEFAULT));
861 }
862
863 /*
864 * XPath: /frr-ripngd:ripngd/state/routes/route/metric
865 */
866 static struct yang_data *
867 ripngd_state_routes_route_metric_get_elem(const char *xpath,
868 const void *list_entry)
869 {
870 const struct agg_node *rn = list_entry;
871 const struct ripng_info *rinfo = listnode_head(rn->info);
872
873 return yang_data_new_uint8(xpath, rinfo->metric);
874 }
875
876 /*
877 * XPath: /frr-ripngd:clear-ripng-route
878 */
879 static int clear_ripng_route_rpc(const char *xpath, const struct list *input,
880 struct list *output)
881 {
882 struct ripng *ripng;
883 struct agg_node *rp;
884 struct ripng_info *rinfo;
885 struct list *list;
886 struct listnode *listnode;
887
888 ripng = ripng_lookup_by_vrf_id(VRF_DEFAULT);
889 if (!ripng)
890 return NB_OK;
891
892 /* Clear received RIPng routes */
893 for (rp = agg_route_top(ripng->table); rp; rp = agg_route_next(rp)) {
894 list = rp->info;
895 if (list == NULL)
896 continue;
897
898 for (ALL_LIST_ELEMENTS_RO(list, listnode, rinfo)) {
899 if (!ripng_route_rte(rinfo))
900 continue;
901
902 if (CHECK_FLAG(rinfo->flags, RIPNG_RTF_FIB))
903 ripng_zebra_ipv6_delete(ripng, rp);
904 break;
905 }
906
907 if (rinfo) {
908 RIPNG_TIMER_OFF(rinfo->t_timeout);
909 RIPNG_TIMER_OFF(rinfo->t_garbage_collect);
910 listnode_delete(list, rinfo);
911 ripng_info_free(rinfo);
912 }
913
914 if (list_isempty(list)) {
915 list_delete(&list);
916 rp->info = NULL;
917 agg_unlock_node(rp);
918 }
919 }
920
921 return NB_OK;
922 }
923
924 /*
925 * XPath: /frr-interface:lib/interface/frr-ripngd:ripng/split-horizon
926 */
927 static int
928 lib_interface_ripng_split_horizon_modify(enum nb_event event,
929 const struct lyd_node *dnode,
930 union nb_resource *resource)
931 {
932 struct interface *ifp;
933 struct ripng_interface *ri;
934
935 if (event != NB_EV_APPLY)
936 return NB_OK;
937
938 ifp = yang_dnode_get_entry(dnode, true);
939 ri = ifp->info;
940 ri->split_horizon = yang_dnode_get_enum(dnode, NULL);
941
942 return NB_OK;
943 }
944
945 /* clang-format off */
946 const struct frr_yang_module_info frr_ripngd_info = {
947 .name = "frr-ripngd",
948 .nodes = {
949 {
950 .xpath = "/frr-ripngd:ripngd/instance",
951 .cbs.create = ripngd_instance_create,
952 .cbs.delete = ripngd_instance_delete,
953 .cbs.cli_show = cli_show_router_ripng,
954 },
955 {
956 .xpath = "/frr-ripngd:ripngd/instance/allow-ecmp",
957 .cbs.modify = ripngd_instance_allow_ecmp_modify,
958 .cbs.cli_show = cli_show_ripng_allow_ecmp,
959 },
960 {
961 .xpath = "/frr-ripngd:ripngd/instance/default-information-originate",
962 .cbs.modify = ripngd_instance_default_information_originate_modify,
963 .cbs.cli_show = cli_show_ripng_default_information_originate,
964 },
965 {
966 .xpath = "/frr-ripngd:ripngd/instance/default-metric",
967 .cbs.modify = ripngd_instance_default_metric_modify,
968 .cbs.cli_show = cli_show_ripng_default_metric,
969 },
970 {
971 .xpath = "/frr-ripngd:ripngd/instance/network",
972 .cbs.create = ripngd_instance_network_create,
973 .cbs.delete = ripngd_instance_network_delete,
974 .cbs.cli_show = cli_show_ripng_network_prefix,
975 },
976 {
977 .xpath = "/frr-ripngd:ripngd/instance/interface",
978 .cbs.create = ripngd_instance_interface_create,
979 .cbs.delete = ripngd_instance_interface_delete,
980 .cbs.cli_show = cli_show_ripng_network_interface,
981 },
982 {
983 .xpath = "/frr-ripngd:ripngd/instance/offset-list",
984 .cbs.create = ripngd_instance_offset_list_create,
985 .cbs.delete = ripngd_instance_offset_list_delete,
986 .cbs.cli_show = cli_show_ripng_offset_list,
987 },
988 {
989 .xpath = "/frr-ripngd:ripngd/instance/offset-list/access-list",
990 .cbs.modify = ripngd_instance_offset_list_access_list_modify,
991 },
992 {
993 .xpath = "/frr-ripngd:ripngd/instance/offset-list/metric",
994 .cbs.modify = ripngd_instance_offset_list_metric_modify,
995 },
996 {
997 .xpath = "/frr-ripngd:ripngd/instance/passive-interface",
998 .cbs.create = ripngd_instance_passive_interface_create,
999 .cbs.delete = ripngd_instance_passive_interface_delete,
1000 .cbs.cli_show = cli_show_ripng_passive_interface,
1001 },
1002 {
1003 .xpath = "/frr-ripngd:ripngd/instance/redistribute",
1004 .cbs.create = ripngd_instance_redistribute_create,
1005 .cbs.delete = ripngd_instance_redistribute_delete,
1006 .cbs.apply_finish = ripngd_instance_redistribute_apply_finish,
1007 .cbs.cli_show = cli_show_ripng_redistribute,
1008 },
1009 {
1010 .xpath = "/frr-ripngd:ripngd/instance/redistribute/route-map",
1011 .cbs.modify = ripngd_instance_redistribute_route_map_modify,
1012 .cbs.delete = ripngd_instance_redistribute_route_map_delete,
1013 },
1014 {
1015 .xpath = "/frr-ripngd:ripngd/instance/redistribute/metric",
1016 .cbs.modify = ripngd_instance_redistribute_metric_modify,
1017 .cbs.delete = ripngd_instance_redistribute_metric_delete,
1018 },
1019 {
1020 .xpath = "/frr-ripngd:ripngd/instance/static-route",
1021 .cbs.create = ripngd_instance_static_route_create,
1022 .cbs.delete = ripngd_instance_static_route_delete,
1023 .cbs.cli_show = cli_show_ripng_route,
1024 },
1025 {
1026 .xpath = "/frr-ripngd:ripngd/instance/aggregate-address",
1027 .cbs.create = ripngd_instance_aggregate_address_create,
1028 .cbs.delete = ripngd_instance_aggregate_address_delete,
1029 .cbs.cli_show = cli_show_ripng_aggregate_address,
1030 },
1031 {
1032 .xpath = "/frr-ripngd:ripngd/instance/timers",
1033 .cbs.apply_finish = ripngd_instance_timers_apply_finish,
1034 .cbs.cli_show = cli_show_ripng_timers,
1035 },
1036 {
1037 .xpath = "/frr-ripngd:ripngd/instance/timers/flush-interval",
1038 .cbs.modify = ripngd_instance_timers_flush_interval_modify,
1039 },
1040 {
1041 .xpath = "/frr-ripngd:ripngd/instance/timers/holddown-interval",
1042 .cbs.modify = ripngd_instance_timers_holddown_interval_modify,
1043 },
1044 {
1045 .xpath = "/frr-ripngd:ripngd/instance/timers/update-interval",
1046 .cbs.modify = ripngd_instance_timers_update_interval_modify,
1047 },
1048 {
1049 .xpath = "/frr-ripngd:ripngd/state/neighbors/neighbor",
1050 .cbs.get_next = ripngd_state_neighbors_neighbor_get_next,
1051 .cbs.get_keys = ripngd_state_neighbors_neighbor_get_keys,
1052 .cbs.lookup_entry = ripngd_state_neighbors_neighbor_lookup_entry,
1053 },
1054 {
1055 .xpath = "/frr-ripngd:ripngd/state/neighbors/neighbor/address",
1056 .cbs.get_elem = ripngd_state_neighbors_neighbor_address_get_elem,
1057 },
1058 {
1059 .xpath = "/frr-ripngd:ripngd/state/neighbors/neighbor/last-update",
1060 .cbs.get_elem = ripngd_state_neighbors_neighbor_last_update_get_elem,
1061 },
1062 {
1063 .xpath = "/frr-ripngd:ripngd/state/neighbors/neighbor/bad-packets-rcvd",
1064 .cbs.get_elem = ripngd_state_neighbors_neighbor_bad_packets_rcvd_get_elem,
1065 },
1066 {
1067 .xpath = "/frr-ripngd:ripngd/state/neighbors/neighbor/bad-routes-rcvd",
1068 .cbs.get_elem = ripngd_state_neighbors_neighbor_bad_routes_rcvd_get_elem,
1069 },
1070 {
1071 .xpath = "/frr-ripngd:ripngd/state/routes/route",
1072 .cbs.get_next = ripngd_state_routes_route_get_next,
1073 .cbs.get_keys = ripngd_state_routes_route_get_keys,
1074 .cbs.lookup_entry = ripngd_state_routes_route_lookup_entry,
1075 },
1076 {
1077 .xpath = "/frr-ripngd:ripngd/state/routes/route/prefix",
1078 .cbs.get_elem = ripngd_state_routes_route_prefix_get_elem,
1079 },
1080 {
1081 .xpath = "/frr-ripngd:ripngd/state/routes/route/next-hop",
1082 .cbs.get_elem = ripngd_state_routes_route_next_hop_get_elem,
1083 },
1084 {
1085 .xpath = "/frr-ripngd:ripngd/state/routes/route/interface",
1086 .cbs.get_elem = ripngd_state_routes_route_interface_get_elem,
1087 },
1088 {
1089 .xpath = "/frr-ripngd:ripngd/state/routes/route/metric",
1090 .cbs.get_elem = ripngd_state_routes_route_metric_get_elem,
1091 },
1092 {
1093 .xpath = "/frr-ripngd:clear-ripng-route",
1094 .cbs.rpc = clear_ripng_route_rpc,
1095 },
1096 {
1097 .xpath = "/frr-interface:lib/interface/frr-ripngd:ripng/split-horizon",
1098 .cbs.modify = lib_interface_ripng_split_horizon_modify,
1099 .cbs.cli_show = cli_show_ipv6_ripng_split_horizon,
1100 },
1101 {
1102 .xpath = NULL,
1103 },
1104 }
1105 };