]> git.proxmox.com Git - mirror_frr.git/blob - pimd/pim_nb_config.c
lib: Remove unnecessary comparison, for linked list
[mirror_frr.git] / pimd / pim_nb_config.c
1 /*
2 * Copyright (C) 2020 VmWare
3 * Sarita Patra
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the Free
7 * Software Foundation; either version 2 of the License, or (at your option)
8 * any later version.
9 *
10 * This program is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; see the file COPYING; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20 #include <zebra.h>
21
22 #include "pimd.h"
23 #include "pim_nb.h"
24 #include "lib/northbound_cli.h"
25 #include "pim_igmpv3.h"
26 #include "pim_neighbor.h"
27 #include "pim_pim.h"
28 #include "pim_mlag.h"
29 #include "pim_bfd.h"
30 #include "pim_static.h"
31 #include "pim_ssm.h"
32 #include "pim_ssmpingd.h"
33 #include "pim_vxlan.h"
34 #include "pim_util.h"
35 #include "log.h"
36 #include "lib_errors.h"
37 #include "pim_util.h"
38 #include "pim6_mld.h"
39
40 #if PIM_IPV == 6
41 #define pim6_msdp_err(funcname, argtype) \
42 int funcname(struct argtype *args) \
43 { \
44 snprintf(args->errmsg, args->errmsg_len, \
45 "Trying to configure MSDP in pim6d. " \
46 "MSDP does not exist for IPv6."); \
47 return NB_ERR_VALIDATION; \
48 } \
49 MACRO_REQUIRE_SEMICOLON()
50
51 #define yang_dnode_get_pimaddr yang_dnode_get_ipv6
52
53 #else /* PIM_IPV != 6 */
54 #define pim6_msdp_err(funcname, argtype) \
55 MACRO_REQUIRE_SEMICOLON()
56
57 #define yang_dnode_get_pimaddr yang_dnode_get_ipv4
58 #endif /* PIM_IPV != 6 */
59
60 static void pim_if_membership_clear(struct interface *ifp)
61 {
62 struct pim_interface *pim_ifp;
63
64 pim_ifp = ifp->info;
65 assert(pim_ifp);
66
67 if (pim_ifp->pim_enable && pim_ifp->gm_enable) {
68 return;
69 }
70
71 pim_ifchannel_membership_clear(ifp);
72 }
73
74 /*
75 * When PIM is disabled on interface, IGMPv3 local membership
76 * information is not injected into PIM interface state.
77
78 * The function pim_if_membership_refresh() fetches all IGMPv3 local
79 * membership information into PIM. It is intented to be called
80 * whenever PIM is enabled on the interface in order to collect missed
81 * local membership information.
82 */
83 static void pim_if_membership_refresh(struct interface *ifp)
84 {
85 struct pim_interface *pim_ifp;
86 struct listnode *grpnode;
87 struct gm_group *grp;
88
89
90 pim_ifp = ifp->info;
91 assert(pim_ifp);
92
93 if (!pim_ifp->pim_enable)
94 return;
95 if (!pim_ifp->gm_enable)
96 return;
97
98 /*
99 * First clear off membership from all PIM (S,G) entries on the
100 * interface
101 */
102
103 pim_ifchannel_membership_clear(ifp);
104
105 /*
106 * Then restore PIM (S,G) membership from all IGMPv3 (S,G) entries on
107 * the interface
108 */
109
110 /* scan igmp groups */
111 for (ALL_LIST_ELEMENTS_RO(pim_ifp->gm_group_list, grpnode, grp)) {
112 struct listnode *srcnode;
113 struct gm_source *src;
114
115 /* scan group sources */
116 for (ALL_LIST_ELEMENTS_RO(grp->group_source_list, srcnode,
117 src)) {
118
119 if (IGMP_SOURCE_TEST_FORWARDING(src->source_flags)) {
120 pim_sgaddr sg;
121
122 memset(&sg, 0, sizeof(sg));
123 sg.src = src->source_addr;
124 sg.grp = grp->group_addr;
125 pim_ifchannel_local_membership_add(
126 ifp, &sg, false /*is_vxlan*/);
127 }
128
129 } /* scan group sources */
130 } /* scan igmp groups */
131
132 /*
133 * Finally delete every PIM (S,G) entry lacking all state info
134 */
135
136 pim_ifchannel_delete_on_noinfo(ifp);
137 }
138
139 static int pim_cmd_interface_add(struct interface *ifp)
140 {
141 struct pim_interface *pim_ifp = ifp->info;
142
143 if (!pim_ifp)
144 pim_ifp = pim_if_new(ifp, false, true, false, false);
145 else
146 pim_ifp->pim_enable = true;
147
148 pim_if_addr_add_all(ifp);
149 pim_if_membership_refresh(ifp);
150
151 pim_if_create_pimreg(pim_ifp->pim);
152 return 1;
153 }
154
155 static int pim_cmd_interface_delete(struct interface *ifp)
156 {
157 struct pim_interface *pim_ifp = ifp->info;
158
159 if (!pim_ifp)
160 return 1;
161
162 pim_ifp->pim_enable = false;
163
164 pim_if_membership_clear(ifp);
165
166 /*
167 * pim_sock_delete() removes all neighbors from
168 * pim_ifp->pim_neighbor_list.
169 */
170 pim_sock_delete(ifp, "pim unconfigured on interface");
171
172 if (!pim_ifp->gm_enable) {
173 pim_if_addr_del_all(ifp);
174 pim_if_delete(ifp);
175 }
176
177 return 1;
178 }
179
180 static int interface_pim_use_src_cmd_worker(struct interface *ifp,
181 pim_addr source_addr, char *errmsg, size_t errmsg_len)
182 {
183 int result;
184 int ret = NB_OK;
185
186 result = pim_update_source_set(ifp, source_addr);
187
188 switch (result) {
189 case PIM_SUCCESS:
190 break;
191 case PIM_IFACE_NOT_FOUND:
192 ret = NB_ERR;
193 snprintf(errmsg, errmsg_len,
194 "Pim not enabled on this interface %s",
195 ifp->name);
196 break;
197 case PIM_UPDATE_SOURCE_DUP:
198 ret = NB_ERR;
199 snprintf(errmsg, errmsg_len, "Source already set");
200 break;
201 default:
202 ret = NB_ERR;
203 snprintf(errmsg, errmsg_len, "Source set failed");
204 }
205
206 return ret;
207 }
208
209 static int pim_cmd_spt_switchover(struct pim_instance *pim,
210 enum pim_spt_switchover spt,
211 const char *plist)
212 {
213 pim->spt.switchover = spt;
214
215 switch (pim->spt.switchover) {
216 case PIM_SPT_IMMEDIATE:
217 XFREE(MTYPE_PIM_PLIST_NAME, pim->spt.plist);
218
219 pim_upstream_add_lhr_star_pimreg(pim);
220 break;
221 case PIM_SPT_INFINITY:
222 pim_upstream_remove_lhr_star_pimreg(pim, plist);
223
224 XFREE(MTYPE_PIM_PLIST_NAME, pim->spt.plist);
225
226 if (plist)
227 pim->spt.plist = XSTRDUP(MTYPE_PIM_PLIST_NAME, plist);
228 break;
229 }
230
231 return NB_OK;
232 }
233
234 static int pim_ssm_cmd_worker(struct pim_instance *pim, const char *plist,
235 char *errmsg, size_t errmsg_len)
236 {
237 int result = pim_ssm_range_set(pim, pim->vrf->vrf_id, plist);
238 int ret = NB_ERR;
239
240 if (result == PIM_SSM_ERR_NONE)
241 return NB_OK;
242
243 switch (result) {
244 case PIM_SSM_ERR_NO_VRF:
245 snprintf(errmsg, errmsg_len,
246 "VRF doesn't exist");
247 break;
248 case PIM_SSM_ERR_DUP:
249 snprintf(errmsg, errmsg_len,
250 "duplicate config");
251 break;
252 default:
253 snprintf(errmsg, errmsg_len,
254 "ssm range config failed");
255 }
256
257 return ret;
258 }
259
260 static int pim_rp_cmd_worker(struct pim_instance *pim, pim_addr rp_addr,
261 struct prefix group, const char *plist,
262 char *errmsg, size_t errmsg_len)
263 {
264 int result;
265
266 result = pim_rp_new(pim, rp_addr, group, plist, RP_SRC_STATIC);
267
268 if (result == PIM_RP_NO_PATH) {
269 snprintfrr(errmsg, errmsg_len,
270 "No Path to RP address specified: %pPA", &rp_addr);
271 return NB_ERR_INCONSISTENCY;
272 }
273
274 if (result == PIM_GROUP_OVERLAP) {
275 snprintf(errmsg, errmsg_len,
276 "Group range specified cannot exact match another");
277 return NB_ERR_INCONSISTENCY;
278 }
279
280 if (result == PIM_GROUP_PFXLIST_OVERLAP) {
281 snprintf(errmsg, errmsg_len,
282 "This group is already covered by a RP prefix-list");
283 return NB_ERR_INCONSISTENCY;
284 }
285
286 if (result == PIM_RP_PFXLIST_IN_USE) {
287 snprintf(errmsg, errmsg_len,
288 "The same prefix-list cannot be applied to multiple RPs");
289 return NB_ERR_INCONSISTENCY;
290 }
291
292 return NB_OK;
293 }
294
295 static int pim_no_rp_cmd_worker(struct pim_instance *pim, pim_addr rp_addr,
296 struct prefix group, const char *plist,
297 char *errmsg, size_t errmsg_len)
298 {
299 char group_str[PREFIX2STR_BUFFER];
300 int result;
301
302 prefix2str(&group, group_str, sizeof(group_str));
303
304 result = pim_rp_del(pim, rp_addr, group, plist, RP_SRC_STATIC);
305
306 if (result == PIM_GROUP_BAD_ADDRESS) {
307 snprintf(errmsg, errmsg_len,
308 "Bad group address specified: %s", group_str);
309 return NB_ERR_INCONSISTENCY;
310 }
311
312 if (result == PIM_RP_BAD_ADDRESS) {
313 snprintfrr(errmsg, errmsg_len, "Bad RP address specified: %pPA",
314 &rp_addr);
315 return NB_ERR_INCONSISTENCY;
316 }
317
318 if (result == PIM_RP_NOT_FOUND) {
319 snprintf(errmsg, errmsg_len,
320 "Unable to find specified RP");
321 return NB_ERR_INCONSISTENCY;
322 }
323
324 return NB_OK;
325 }
326
327 static bool is_pim_interface(const struct lyd_node *dnode)
328 {
329 char if_xpath[XPATH_MAXLEN];
330 const struct lyd_node *pim_enable_dnode;
331 const struct lyd_node *igmp_enable_dnode;
332
333 yang_dnode_get_path(dnode, if_xpath, sizeof(if_xpath));
334 pim_enable_dnode =
335 yang_dnode_getf(dnode,
336 "%s/frr-pim:pim/address-family[address-family='%s']/pim-enable",
337 if_xpath, FRR_PIM_AF_XPATH_VAL);
338 igmp_enable_dnode = yang_dnode_getf(dnode,
339 "%s/frr-gmp:gmp/address-family[address-family='%s']/enable",
340 if_xpath, FRR_PIM_AF_XPATH_VAL);
341
342 if (((pim_enable_dnode) &&
343 (yang_dnode_get_bool(pim_enable_dnode, "."))) ||
344 ((igmp_enable_dnode) &&
345 (yang_dnode_get_bool(igmp_enable_dnode, "."))))
346 return true;
347
348 return false;
349 }
350
351 static int pim_cmd_gm_start(struct interface *ifp)
352 {
353 struct pim_interface *pim_ifp;
354 uint8_t need_startup = 0;
355
356 pim_ifp = ifp->info;
357
358 if (!pim_ifp) {
359 pim_ifp = pim_if_new(ifp, true, false, false, false);
360 need_startup = 1;
361 } else {
362 if (!pim_ifp->gm_enable) {
363 pim_ifp->gm_enable = true;
364 need_startup = 1;
365 }
366 }
367 pim_if_create_pimreg(pim_ifp->pim);
368
369 /* 'ip igmp' executed multiple times, with need_startup
370 * avoid multiple if add all and membership refresh
371 */
372 if (need_startup) {
373 pim_if_addr_add_all(ifp);
374 pim_if_membership_refresh(ifp);
375 }
376
377 return NB_OK;
378 }
379
380 /*
381 * CLI reconfiguration affects the interface level (struct pim_interface).
382 * This function propagates the reconfiguration to every active socket
383 * for that interface.
384 */
385 #if PIM_IPV == 4
386 static void igmp_sock_query_interval_reconfig(struct gm_sock *igmp)
387 {
388 struct interface *ifp;
389 struct pim_interface *pim_ifp;
390
391 assert(igmp);
392 assert(igmp->interface);
393 assert(igmp->interface->info);
394
395 ifp = igmp->interface;
396 pim_ifp = ifp->info;
397
398 if (PIM_DEBUG_GM_TRACE)
399 zlog_debug("%s: Querier %pPAs on %s reconfig query_interval=%d",
400 __func__, &igmp->ifaddr, ifp->name,
401 pim_ifp->gm_default_query_interval);
402
403 /*
404 * igmp_startup_mode_on() will reset QQI:
405
406 * igmp->querier_query_interval = pim_ifp->gm_default_query_interval;
407 */
408 igmp_startup_mode_on(igmp);
409 }
410
411 static void igmp_sock_query_reschedule(struct gm_sock *igmp)
412 {
413 if (igmp->mtrace_only)
414 return;
415
416 if (igmp->t_igmp_query_timer) {
417 /* other querier present */
418 assert(igmp->t_igmp_query_timer);
419 assert(!igmp->t_other_querier_timer);
420
421 pim_igmp_general_query_off(igmp);
422 pim_igmp_general_query_on(igmp);
423
424 assert(igmp->t_igmp_query_timer);
425 assert(!igmp->t_other_querier_timer);
426 } else {
427 /* this is the querier */
428
429 assert(!igmp->t_igmp_query_timer);
430 assert(igmp->t_other_querier_timer);
431
432 pim_igmp_other_querier_timer_off(igmp);
433 pim_igmp_other_querier_timer_on(igmp);
434
435 assert(!igmp->t_igmp_query_timer);
436 assert(igmp->t_other_querier_timer);
437 }
438 }
439 #endif /* PIM_IPV == 4 */
440
441 #if PIM_IPV == 4
442 static void change_query_interval(struct pim_interface *pim_ifp,
443 int query_interval)
444 {
445 struct listnode *sock_node;
446 struct gm_sock *igmp;
447
448 pim_ifp->gm_default_query_interval = query_interval;
449
450 for (ALL_LIST_ELEMENTS_RO(pim_ifp->gm_socket_list, sock_node, igmp)) {
451 igmp_sock_query_interval_reconfig(igmp);
452 igmp_sock_query_reschedule(igmp);
453 }
454 }
455 #endif
456
457 static void change_query_max_response_time(struct interface *ifp,
458 int query_max_response_time_dsec)
459 {
460 #if PIM_IPV == 4
461 struct listnode *sock_node;
462 struct gm_sock *igmp;
463 struct listnode *grp_node;
464 struct gm_group *grp;
465 #endif
466
467 struct pim_interface *pim_ifp = ifp->info;
468
469 if (pim_ifp->gm_query_max_response_time_dsec ==
470 query_max_response_time_dsec)
471 return;
472
473 pim_ifp->gm_query_max_response_time_dsec = query_max_response_time_dsec;
474
475 #if PIM_IPV == 6
476 gm_ifp_update(ifp);
477 #else
478 /*
479 * Below we modify socket/group/source timers in order to quickly
480 * reflect the change. Otherwise, those timers would args->eventually
481 * catch up.
482 */
483
484 /* scan all sockets */
485 for (ALL_LIST_ELEMENTS_RO(pim_ifp->gm_socket_list, sock_node, igmp)) {
486 /* reschedule socket general query */
487 igmp_sock_query_reschedule(igmp);
488 }
489
490 /* scan socket groups */
491 for (ALL_LIST_ELEMENTS_RO(pim_ifp->gm_group_list, grp_node, grp)) {
492 struct listnode *src_node;
493 struct gm_source *src;
494
495 /* reset group timers for groups in EXCLUDE mode */
496 if (grp->group_filtermode_isexcl)
497 igmp_group_reset_gmi(grp);
498
499 /* scan group sources */
500 for (ALL_LIST_ELEMENTS_RO(grp->group_source_list, src_node,
501 src)) {
502
503 /* reset source timers for sources with running
504 * timers
505 */
506 if (src->t_source_timer)
507 igmp_source_reset_gmi(grp, src);
508 }
509 }
510 #endif /* PIM_IPV == 4 */
511 }
512
513 int routing_control_plane_protocols_name_validate(
514 struct nb_cb_create_args *args)
515 {
516 const char *name;
517
518 name = yang_dnode_get_string(args->dnode, "./name");
519 if (!strmatch(name, "pim")) {
520 snprintf(args->errmsg, args->errmsg_len,
521 "pim supports only one instance with name pimd");
522 return NB_ERR_VALIDATION;
523 }
524 return NB_OK;
525 }
526
527 /*
528 * XPath: /frr-pim:pim/address-family
529 */
530 int pim_address_family_create(struct nb_cb_create_args *args)
531 {
532 switch (args->event) {
533 case NB_EV_VALIDATE:
534 case NB_EV_PREPARE:
535 case NB_EV_ABORT:
536 case NB_EV_APPLY:
537 break;
538 }
539
540 return NB_OK;
541 }
542
543 int pim_address_family_destroy(struct nb_cb_destroy_args *args)
544 {
545 switch (args->event) {
546 case NB_EV_VALIDATE:
547 case NB_EV_PREPARE:
548 case NB_EV_ABORT:
549 case NB_EV_APPLY:
550 break;
551 }
552
553 return NB_OK;
554 }
555
556 /*
557 * XPath: /frr-pim:pim/address-family/packets
558 */
559 int pim_address_family_packets_modify(struct nb_cb_modify_args *args)
560 {
561 switch (args->event) {
562 case NB_EV_VALIDATE:
563 case NB_EV_PREPARE:
564 case NB_EV_ABORT:
565 break;
566 case NB_EV_APPLY:
567 router->packet_process = yang_dnode_get_uint8(args->dnode,
568 NULL);
569 break;
570 }
571
572 return NB_OK;
573 }
574
575 /*
576 * XPath: /frr-pim:pim/address-family/join-prune-interval
577 */
578 int pim_address_family_join_prune_interval_modify(
579 struct nb_cb_modify_args *args)
580 {
581 switch (args->event) {
582 case NB_EV_VALIDATE:
583 case NB_EV_PREPARE:
584 case NB_EV_ABORT:
585 break;
586 case NB_EV_APPLY:
587 router->t_periodic = yang_dnode_get_uint16(args->dnode, NULL);
588 break;
589 }
590
591 return NB_OK;
592 }
593
594 /*
595 * XPath: /frr-pim:pim/address-family/register-suppress-time
596 */
597 int pim_address_family_register_suppress_time_modify(
598 struct nb_cb_modify_args *args)
599 {
600 uint16_t value;
601 switch (args->event) {
602 case NB_EV_VALIDATE:
603 value = yang_dnode_get_uint16(args->dnode, NULL);
604 /*
605 * As soon as this is non-constant it needs to be replaced with
606 * a yang_dnode_get to lookup the candidate value, *not* the
607 * operational value. Since the code has a field assigned and
608 * used for this value it should have YANG/CLI to set it too,
609 * otherwise just use the #define!
610 */
611 /* RFC7761: 4.11. Timer Values */
612 if (value <= router->register_probe_time * 2) {
613 snprintf(
614 args->errmsg, args->errmsg_len,
615 "Register suppress time (%u) must be more than "
616 "twice the register probe time (%u).",
617 value, router->register_probe_time);
618 return NB_ERR_VALIDATION;
619 }
620 break;
621 case NB_EV_PREPARE:
622 case NB_EV_ABORT:
623 break;
624 case NB_EV_APPLY:
625 pim_update_suppress_timers(
626 yang_dnode_get_uint16(args->dnode, NULL));
627 break;
628 }
629
630 return NB_OK;
631 }
632
633 /*
634 * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/ecmp
635 */
636 int routing_control_plane_protocols_control_plane_protocol_pim_address_family_ecmp_modify(
637 struct nb_cb_modify_args *args)
638 {
639 struct vrf *vrf;
640 struct pim_instance *pim;
641
642 switch (args->event) {
643 case NB_EV_VALIDATE:
644 case NB_EV_PREPARE:
645 case NB_EV_ABORT:
646 break;
647 case NB_EV_APPLY:
648 vrf = nb_running_get_entry(args->dnode, NULL, true);
649 pim = vrf->info;
650 pim->ecmp_enable = yang_dnode_get_bool(args->dnode, NULL);
651 }
652
653 return NB_OK;
654 }
655
656 /*
657 * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/ecmp-rebalance
658 */
659 int routing_control_plane_protocols_control_plane_protocol_pim_address_family_ecmp_rebalance_modify(
660 struct nb_cb_modify_args *args)
661 {
662 struct vrf *vrf;
663 struct pim_instance *pim;
664
665 switch (args->event) {
666 case NB_EV_VALIDATE:
667 case NB_EV_PREPARE:
668 case NB_EV_ABORT:
669 break;
670 case NB_EV_APPLY:
671 vrf = nb_running_get_entry(args->dnode, NULL, true);
672 pim = vrf->info;
673 pim->ecmp_rebalance_enable =
674 yang_dnode_get_bool(args->dnode, NULL);
675 }
676
677 return NB_OK;
678 }
679
680 /*
681 * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/keep-alive-timer
682 */
683 int routing_control_plane_protocols_control_plane_protocol_pim_address_family_keep_alive_timer_modify(
684 struct nb_cb_modify_args *args)
685 {
686 struct vrf *vrf;
687 struct pim_instance *pim;
688
689 switch (args->event) {
690 case NB_EV_VALIDATE:
691 case NB_EV_PREPARE:
692 case NB_EV_ABORT:
693 break;
694 case NB_EV_APPLY:
695 vrf = nb_running_get_entry(args->dnode, NULL, true);
696 pim = vrf->info;
697 pim->keep_alive_time = yang_dnode_get_uint16(args->dnode, NULL);
698 break;
699 }
700
701 return NB_OK;
702 }
703
704 /*
705 * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/rp-keep-alive-timer
706 */
707 int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_keep_alive_timer_modify(
708 struct nb_cb_modify_args *args)
709 {
710 struct vrf *vrf;
711 struct pim_instance *pim;
712
713 switch (args->event) {
714 case NB_EV_VALIDATE:
715 case NB_EV_PREPARE:
716 case NB_EV_ABORT:
717 break;
718 case NB_EV_APPLY:
719 vrf = nb_running_get_entry(args->dnode, NULL, true);
720 pim = vrf->info;
721 pim->rp_keep_alive_time = yang_dnode_get_uint16(args->dnode,
722 NULL);
723 break;
724 }
725
726 return NB_OK;
727 }
728
729 /*
730 * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family
731 */
732 int routing_control_plane_protocols_control_plane_protocol_pim_address_family_create(
733 struct nb_cb_create_args *args)
734 {
735 switch (args->event) {
736 case NB_EV_VALIDATE:
737 case NB_EV_PREPARE:
738 case NB_EV_ABORT:
739 case NB_EV_APPLY:
740 break;
741 }
742
743 return NB_OK;
744 }
745
746 int routing_control_plane_protocols_control_plane_protocol_pim_address_family_destroy(
747 struct nb_cb_destroy_args *args)
748 {
749 switch (args->event) {
750 case NB_EV_VALIDATE:
751 case NB_EV_PREPARE:
752 case NB_EV_ABORT:
753 case NB_EV_APPLY:
754 break;
755 }
756
757 return NB_OK;
758 }
759
760 /*
761 * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/send-v6-secondary
762 */
763 int routing_control_plane_protocols_control_plane_protocol_pim_address_family_send_v6_secondary_modify(
764 struct nb_cb_modify_args *args)
765 {
766 struct vrf *vrf;
767 struct pim_instance *pim;
768
769 switch (args->event) {
770 case NB_EV_VALIDATE:
771 case NB_EV_PREPARE:
772 case NB_EV_ABORT:
773 break;
774 case NB_EV_APPLY:
775 vrf = nb_running_get_entry(args->dnode, NULL, true);
776 pim = vrf->info;
777 pim->send_v6_secondary = yang_dnode_get_bool(args->dnode, NULL);
778 break;
779 }
780
781 return NB_OK;
782 }
783
784 int routing_control_plane_protocols_control_plane_protocol_pim_address_family_send_v6_secondary_destroy(
785 struct nb_cb_destroy_args *args)
786 {
787 switch (args->event) {
788 case NB_EV_VALIDATE:
789 case NB_EV_PREPARE:
790 case NB_EV_ABORT:
791 case NB_EV_APPLY:
792 break;
793 }
794
795 return NB_OK;
796 }
797
798 /*
799 * XPath:
800 * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/spt-switchover
801 */
802 void routing_control_plane_protocols_control_plane_protocol_pim_address_family_spt_switchover_apply_finish(
803 struct nb_cb_apply_finish_args *args)
804 {
805 struct vrf *vrf;
806 struct pim_instance *pim;
807 int spt_switch_action;
808 const char *prefix_list = NULL;
809
810 vrf = nb_running_get_entry(args->dnode, NULL, true);
811 pim = vrf->info;
812 spt_switch_action = yang_dnode_get_enum(args->dnode, "./spt-action");
813
814 switch (spt_switch_action) {
815 case PIM_SPT_INFINITY:
816 if (yang_dnode_exists(args->dnode,
817 "./spt-infinity-prefix-list"))
818 prefix_list = yang_dnode_get_string(
819 args->dnode, "./spt-infinity-prefix-list");
820
821 pim_cmd_spt_switchover(pim, PIM_SPT_INFINITY,
822 prefix_list);
823 break;
824 case PIM_SPT_IMMEDIATE:
825 pim_cmd_spt_switchover(pim, PIM_SPT_IMMEDIATE, NULL);
826 }
827 }
828
829 /*
830 * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/spt-switchover/spt-action
831 */
832 int routing_control_plane_protocols_control_plane_protocol_pim_address_family_spt_switchover_spt_action_modify(
833 struct nb_cb_modify_args *args)
834 {
835 switch (args->event) {
836 case NB_EV_VALIDATE:
837 case NB_EV_PREPARE:
838 case NB_EV_ABORT:
839 case NB_EV_APPLY:
840 break;
841 }
842
843 return NB_OK;
844 }
845
846 /*
847 * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/spt-switchover/spt-infinity-prefix-list
848 */
849 int routing_control_plane_protocols_control_plane_protocol_pim_address_family_spt_switchover_spt_infinity_prefix_list_modify(
850 struct nb_cb_modify_args *args)
851 {
852 switch (args->event) {
853 case NB_EV_VALIDATE:
854 case NB_EV_PREPARE:
855 case NB_EV_ABORT:
856 case NB_EV_APPLY:
857 break;
858 }
859
860 return NB_OK;
861 }
862
863 int routing_control_plane_protocols_control_plane_protocol_pim_address_family_spt_switchover_spt_infinity_prefix_list_destroy(
864 struct nb_cb_destroy_args *args)
865 {
866 switch (args->event) {
867 case NB_EV_VALIDATE:
868 case NB_EV_PREPARE:
869 case NB_EV_ABORT:
870 case NB_EV_APPLY:
871 break;
872 }
873
874 return NB_OK;
875 }
876
877 /*
878 * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/ssm-prefix-list
879 */
880 int routing_control_plane_protocols_control_plane_protocol_pim_address_family_ssm_prefix_list_modify(
881 struct nb_cb_modify_args *args)
882 {
883 struct vrf *vrf;
884 struct pim_instance *pim;
885 const char *plist_name;
886 int result;
887
888 switch (args->event) {
889 case NB_EV_VALIDATE:
890 case NB_EV_PREPARE:
891 case NB_EV_ABORT:
892 break;
893 case NB_EV_APPLY:
894 vrf = nb_running_get_entry(args->dnode, NULL, true);
895 pim = vrf->info;
896 plist_name = yang_dnode_get_string(args->dnode, NULL);
897 result = pim_ssm_cmd_worker(pim, plist_name, args->errmsg,
898 args->errmsg_len);
899
900 if (result)
901 return NB_ERR_INCONSISTENCY;
902
903 break;
904 }
905
906 return NB_OK;
907 }
908
909 int routing_control_plane_protocols_control_plane_protocol_pim_address_family_ssm_prefix_list_destroy(
910 struct nb_cb_destroy_args *args)
911 {
912 struct vrf *vrf;
913 struct pim_instance *pim;
914 int result;
915
916 switch (args->event) {
917 case NB_EV_VALIDATE:
918 case NB_EV_PREPARE:
919 case NB_EV_ABORT:
920 break;
921 case NB_EV_APPLY:
922 vrf = nb_running_get_entry(args->dnode, NULL, true);
923 pim = vrf->info;
924 result = pim_ssm_cmd_worker(pim, NULL, args->errmsg,
925 args->errmsg_len);
926
927 if (result)
928 return NB_ERR_INCONSISTENCY;
929
930 break;
931 }
932
933 return NB_OK;
934 }
935
936 /*
937 * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/ssm-pingd-source-ip
938 */
939 int routing_control_plane_protocols_control_plane_protocol_pim_address_family_ssm_pingd_source_ip_create(
940 struct nb_cb_create_args *args)
941 {
942 struct vrf *vrf;
943 struct pim_instance *pim;
944 int result;
945 pim_addr source_addr;
946
947 switch (args->event) {
948 case NB_EV_VALIDATE:
949 case NB_EV_PREPARE:
950 case NB_EV_ABORT:
951 break;
952 case NB_EV_APPLY:
953 vrf = nb_running_get_entry(args->dnode, NULL, true);
954 pim = vrf->info;
955 yang_dnode_get_pimaddr(&source_addr, args->dnode,
956 "./source-addr");
957 result = pim_ssmpingd_start(pim, source_addr);
958 if (result) {
959 snprintf(
960 args->errmsg, args->errmsg_len,
961 "%% Failure starting ssmpingd for source %pPA: %d",
962 &source_addr, result);
963 return NB_ERR_INCONSISTENCY;
964 }
965 }
966
967 return NB_OK;
968 }
969
970 int routing_control_plane_protocols_control_plane_protocol_pim_address_family_ssm_pingd_source_ip_destroy(
971 struct nb_cb_destroy_args *args)
972 {
973 struct vrf *vrf;
974 struct pim_instance *pim;
975 int result;
976 pim_addr source_addr;
977
978 switch (args->event) {
979 case NB_EV_VALIDATE:
980 case NB_EV_PREPARE:
981 case NB_EV_ABORT:
982 break;
983 case NB_EV_APPLY:
984 vrf = nb_running_get_entry(args->dnode, NULL, true);
985 pim = vrf->info;
986 yang_dnode_get_pimaddr(&source_addr, args->dnode,
987 "./source-addr");
988 result = pim_ssmpingd_stop(pim, source_addr);
989 if (result) {
990 snprintf(
991 args->errmsg, args->errmsg_len,
992 "%% Failure stopping ssmpingd for source %pPA: %d",
993 &source_addr, result);
994 return NB_ERR_INCONSISTENCY;
995 }
996
997 break;
998 }
999
1000 return NB_OK;
1001 }
1002
1003 /*
1004 * XPath:
1005 * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp/hold-time
1006 */
1007 int pim_msdp_hold_time_modify(struct nb_cb_modify_args *args)
1008 {
1009 struct pim_instance *pim;
1010 struct vrf *vrf;
1011
1012 switch (args->event) {
1013 case NB_EV_VALIDATE:
1014 case NB_EV_PREPARE:
1015 case NB_EV_ABORT:
1016 break;
1017 case NB_EV_APPLY:
1018 vrf = nb_running_get_entry(args->dnode, NULL, true);
1019 pim = vrf->info;
1020 pim->msdp.hold_time = yang_dnode_get_uint16(args->dnode, NULL);
1021 break;
1022 }
1023
1024 return NB_OK;
1025 }
1026
1027 /*
1028 * XPath:
1029 * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp/keep-alive
1030 */
1031 int pim_msdp_keep_alive_modify(struct nb_cb_modify_args *args)
1032 {
1033 struct pim_instance *pim;
1034 struct vrf *vrf;
1035
1036 switch (args->event) {
1037 case NB_EV_VALIDATE:
1038 case NB_EV_PREPARE:
1039 case NB_EV_ABORT:
1040 break;
1041 case NB_EV_APPLY:
1042 vrf = nb_running_get_entry(args->dnode, NULL, true);
1043 pim = vrf->info;
1044 pim->msdp.keep_alive = yang_dnode_get_uint16(args->dnode, NULL);
1045 break;
1046 }
1047
1048 return NB_OK;
1049 }
1050
1051 /*
1052 * XPath:
1053 * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp/connection-retry
1054 */
1055 int pim_msdp_connection_retry_modify(struct nb_cb_modify_args *args)
1056 {
1057 struct pim_instance *pim;
1058 struct vrf *vrf;
1059
1060 switch (args->event) {
1061 case NB_EV_VALIDATE:
1062 case NB_EV_PREPARE:
1063 case NB_EV_ABORT:
1064 break;
1065 case NB_EV_APPLY:
1066 vrf = nb_running_get_entry(args->dnode, NULL, true);
1067 pim = vrf->info;
1068 pim->msdp.connection_retry =
1069 yang_dnode_get_uint16(args->dnode, NULL);
1070 break;
1071 }
1072
1073 return NB_OK;
1074 }
1075
1076 pim6_msdp_err(pim_msdp_mesh_group_destroy, nb_cb_destroy_args);
1077 pim6_msdp_err(pim_msdp_mesh_group_create, nb_cb_create_args);
1078 pim6_msdp_err(pim_msdp_mesh_group_source_modify, nb_cb_modify_args);
1079 pim6_msdp_err(pim_msdp_mesh_group_source_destroy, nb_cb_destroy_args);
1080 pim6_msdp_err(pim_msdp_mesh_group_members_create, nb_cb_create_args);
1081 pim6_msdp_err(pim_msdp_mesh_group_members_destroy, nb_cb_destroy_args);
1082 pim6_msdp_err(routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_peer_source_ip_modify,
1083 nb_cb_modify_args);
1084 pim6_msdp_err(routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_peer_destroy,
1085 nb_cb_destroy_args);
1086 pim6_msdp_err(routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_peer_create,
1087 nb_cb_create_args);
1088
1089 #if PIM_IPV != 6
1090 /*
1091 * XPath:
1092 * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-mesh-groups
1093 */
1094 int pim_msdp_mesh_group_create(struct nb_cb_create_args *args)
1095 {
1096 struct pim_msdp_mg *mg;
1097 struct vrf *vrf;
1098
1099 switch (args->event) {
1100 case NB_EV_VALIDATE:
1101 case NB_EV_PREPARE:
1102 case NB_EV_ABORT:
1103 break;
1104 case NB_EV_APPLY:
1105 vrf = nb_running_get_entry(args->dnode, NULL, true);
1106 mg = pim_msdp_mg_new(vrf->info, yang_dnode_get_string(
1107 args->dnode, "./name"));
1108 nb_running_set_entry(args->dnode, mg);
1109 break;
1110 }
1111
1112 return NB_OK;
1113 }
1114
1115 int pim_msdp_mesh_group_destroy(struct nb_cb_destroy_args *args)
1116 {
1117 struct pim_msdp_mg *mg;
1118 struct vrf *vrf;
1119
1120 switch (args->event) {
1121 case NB_EV_VALIDATE:
1122 case NB_EV_PREPARE:
1123 case NB_EV_ABORT:
1124 break;
1125 case NB_EV_APPLY:
1126 mg = nb_running_unset_entry(args->dnode);
1127 vrf = nb_running_get_entry(args->dnode, NULL, true);
1128 pim_msdp_mg_free(vrf->info, &mg);
1129 break;
1130 }
1131
1132 return NB_OK;
1133 }
1134
1135 /*
1136 * XPath:
1137 * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-mesh-groups/source
1138 */
1139 int pim_msdp_mesh_group_source_modify(struct nb_cb_modify_args *args)
1140 {
1141 const struct lyd_node *vrf_dnode;
1142 struct pim_msdp_mg *mg;
1143 struct vrf *vrf;
1144 struct ipaddr ip;
1145
1146 switch (args->event) {
1147 case NB_EV_VALIDATE:
1148 case NB_EV_PREPARE:
1149 case NB_EV_ABORT:
1150 break;
1151 case NB_EV_APPLY:
1152 mg = nb_running_get_entry(args->dnode, NULL, true);
1153 vrf_dnode =
1154 yang_dnode_get_parent(args->dnode, "address-family");
1155 vrf = nb_running_get_entry(vrf_dnode, "../../", true);
1156 yang_dnode_get_ip(&ip, args->dnode, NULL);
1157
1158 pim_msdp_mg_src_add(vrf->info, mg, &ip.ip._v4_addr);
1159 break;
1160 }
1161 return NB_OK;
1162 }
1163
1164 int pim_msdp_mesh_group_source_destroy(struct nb_cb_destroy_args *args)
1165 {
1166 const struct lyd_node *vrf_dnode;
1167 struct pim_msdp_mg *mg;
1168 struct vrf *vrf;
1169 struct in_addr addr;
1170
1171 switch (args->event) {
1172 case NB_EV_VALIDATE:
1173 case NB_EV_PREPARE:
1174 case NB_EV_ABORT:
1175 break;
1176 case NB_EV_APPLY:
1177 mg = nb_running_get_entry(args->dnode, NULL, true);
1178 vrf_dnode =
1179 yang_dnode_get_parent(args->dnode, "address-family");
1180 vrf = nb_running_get_entry(vrf_dnode, "../../", true);
1181
1182 addr.s_addr = INADDR_ANY;
1183 pim_msdp_mg_src_add(vrf->info, mg, &addr);
1184 break;
1185 }
1186 return NB_OK;
1187 }
1188
1189
1190 /*
1191 * XPath:
1192 * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-mesh-groups/members
1193 */
1194 int pim_msdp_mesh_group_members_create(struct nb_cb_create_args *args)
1195 {
1196 const struct lyd_node *vrf_dnode;
1197 struct pim_msdp_mg_mbr *mbr;
1198 struct pim_msdp_mg *mg;
1199 struct vrf *vrf;
1200 struct ipaddr ip;
1201
1202 switch (args->event) {
1203 case NB_EV_VALIDATE:
1204 case NB_EV_PREPARE:
1205 case NB_EV_ABORT:
1206 break;
1207 case NB_EV_APPLY:
1208 mg = nb_running_get_entry(args->dnode, NULL, true);
1209 vrf_dnode =
1210 yang_dnode_get_parent(args->dnode, "address-family");
1211 vrf = nb_running_get_entry(vrf_dnode, "../../", true);
1212 yang_dnode_get_ip(&ip, args->dnode, "address");
1213
1214 mbr = pim_msdp_mg_mbr_add(vrf->info, mg, &ip.ip._v4_addr);
1215 nb_running_set_entry(args->dnode, mbr);
1216 break;
1217 }
1218
1219 return NB_OK;
1220 }
1221
1222 int pim_msdp_mesh_group_members_destroy(struct nb_cb_destroy_args *args)
1223 {
1224 struct pim_msdp_mg_mbr *mbr;
1225 struct pim_msdp_mg *mg;
1226 const struct lyd_node *mg_dnode;
1227
1228 switch (args->event) {
1229 case NB_EV_VALIDATE:
1230 case NB_EV_PREPARE:
1231 case NB_EV_ABORT:
1232 break;
1233 case NB_EV_APPLY:
1234 mbr = nb_running_get_entry(args->dnode, NULL, true);
1235 mg_dnode =
1236 yang_dnode_get_parent(args->dnode, "msdp-mesh-groups");
1237 mg = nb_running_get_entry(mg_dnode, NULL, true);
1238 pim_msdp_mg_mbr_del(mg, mbr);
1239 nb_running_unset_entry(args->dnode);
1240 break;
1241 }
1242
1243 return NB_OK;
1244 }
1245
1246 /*
1247 * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-peer
1248 */
1249 int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_peer_create(
1250 struct nb_cb_create_args *args)
1251 {
1252 struct pim_msdp_peer *mp;
1253 struct pim_instance *pim;
1254 struct vrf *vrf;
1255 struct ipaddr peer_ip;
1256 struct ipaddr source_ip;
1257
1258 switch (args->event) {
1259 case NB_EV_VALIDATE:
1260 case NB_EV_PREPARE:
1261 case NB_EV_ABORT:
1262 break;
1263 case NB_EV_APPLY:
1264 vrf = nb_running_get_entry(args->dnode, NULL, true);
1265 pim = vrf->info;
1266 yang_dnode_get_ip(&peer_ip, args->dnode, "./peer-ip");
1267 yang_dnode_get_ip(&source_ip, args->dnode, "./source-ip");
1268 mp = pim_msdp_peer_add(pim, &peer_ip.ipaddr_v4,
1269 &source_ip.ipaddr_v4, NULL);
1270 nb_running_set_entry(args->dnode, mp);
1271 break;
1272 }
1273
1274 return NB_OK;
1275 }
1276
1277 int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_peer_destroy(
1278 struct nb_cb_destroy_args *args)
1279 {
1280 struct pim_msdp_peer *mp;
1281
1282 switch (args->event) {
1283 case NB_EV_VALIDATE:
1284 case NB_EV_PREPARE:
1285 case NB_EV_ABORT:
1286 break;
1287 case NB_EV_APPLY:
1288 mp = nb_running_unset_entry(args->dnode);
1289 pim_msdp_peer_del(&mp);
1290 break;
1291 }
1292
1293 return NB_OK;
1294 }
1295
1296 /*
1297 * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-peer/source-ip
1298 */
1299 int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_peer_source_ip_modify(
1300 struct nb_cb_modify_args *args)
1301 {
1302 struct pim_msdp_peer *mp;
1303 struct ipaddr source_ip;
1304
1305 switch (args->event) {
1306 case NB_EV_VALIDATE:
1307 case NB_EV_PREPARE:
1308 case NB_EV_ABORT:
1309 break;
1310 case NB_EV_APPLY:
1311 mp = nb_running_get_entry(args->dnode, NULL, true);
1312 yang_dnode_get_ip(&source_ip, args->dnode, NULL);
1313 pim_msdp_peer_change_source(mp, &source_ip.ipaddr_v4);
1314 break;
1315 }
1316
1317 return NB_OK;
1318 }
1319 #endif /* PIM_IPV != 6 */
1320
1321 /*
1322 * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/mlag
1323 */
1324 int routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_create(
1325 struct nb_cb_create_args *args)
1326 {
1327 switch (args->event) {
1328 case NB_EV_VALIDATE:
1329 case NB_EV_PREPARE:
1330 case NB_EV_ABORT:
1331 case NB_EV_APPLY:
1332 break;
1333 }
1334
1335 return NB_OK;
1336 }
1337
1338 int routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_destroy(
1339 struct nb_cb_destroy_args *args)
1340 {
1341 struct in_addr addr;
1342
1343 switch (args->event) {
1344 case NB_EV_VALIDATE:
1345 case NB_EV_PREPARE:
1346 case NB_EV_ABORT:
1347 break;
1348 case NB_EV_APPLY:
1349 addr.s_addr = 0;
1350 pim_vxlan_mlag_update(true/*mlag_enable*/,
1351 false/*peer_state*/, MLAG_ROLE_NONE,
1352 NULL/*peerlink*/, &addr);
1353 }
1354
1355 return NB_OK;
1356 }
1357
1358 /*
1359 * XPath:
1360 * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/mlag
1361 */
1362 void routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_apply_finish(
1363 struct nb_cb_apply_finish_args *args)
1364 {
1365 const char *ifname;
1366 uint32_t role;
1367 bool peer_state;
1368 struct interface *ifp;
1369 struct ipaddr reg_addr;
1370
1371 ifname = yang_dnode_get_string(args->dnode, "./peerlink-rif");
1372 ifp = if_lookup_by_name(ifname, VRF_DEFAULT);
1373 if (!ifp) {
1374 snprintf(args->errmsg, args->errmsg_len,
1375 "No such interface name %s", ifname);
1376 return;
1377 }
1378 role = yang_dnode_get_enum(args->dnode, "./my-role");
1379 peer_state = yang_dnode_get_bool(args->dnode, "./peer-state");
1380 yang_dnode_get_ip(&reg_addr, args->dnode, "./reg-address");
1381
1382 pim_vxlan_mlag_update(true, peer_state, role, ifp,
1383 &reg_addr.ip._v4_addr);
1384 }
1385
1386
1387 /*
1388 * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/mlag/peerlink-rif
1389 */
1390 int routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_peerlink_rif_modify(
1391 struct nb_cb_modify_args *args)
1392 {
1393 switch (args->event) {
1394 case NB_EV_VALIDATE:
1395 case NB_EV_PREPARE:
1396 case NB_EV_ABORT:
1397 case NB_EV_APPLY:
1398 break;
1399 }
1400
1401 return NB_OK;
1402 }
1403
1404 int routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_peerlink_rif_destroy(
1405 struct nb_cb_destroy_args *args)
1406 {
1407 switch (args->event) {
1408 case NB_EV_VALIDATE:
1409 case NB_EV_PREPARE:
1410 case NB_EV_ABORT:
1411 case NB_EV_APPLY:
1412 break;
1413 }
1414
1415 return NB_OK;
1416 }
1417
1418 /*
1419 * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/mlag/reg-address
1420 */
1421 int routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_reg_address_modify(
1422 struct nb_cb_modify_args *args)
1423 {
1424 switch (args->event) {
1425 case NB_EV_VALIDATE:
1426 case NB_EV_PREPARE:
1427 case NB_EV_ABORT:
1428 case NB_EV_APPLY:
1429 break;
1430 }
1431
1432 return NB_OK;
1433 }
1434
1435 int routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_reg_address_destroy(
1436 struct nb_cb_destroy_args *args)
1437 {
1438 switch (args->event) {
1439 case NB_EV_VALIDATE:
1440 case NB_EV_PREPARE:
1441 case NB_EV_ABORT:
1442 case NB_EV_APPLY:
1443 break;
1444 }
1445
1446 return NB_OK;
1447 }
1448
1449 /*
1450 * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/mlag/my-role
1451 */
1452 int routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_my_role_modify(
1453 struct nb_cb_modify_args *args)
1454 {
1455 switch (args->event) {
1456 case NB_EV_VALIDATE:
1457 case NB_EV_PREPARE:
1458 case NB_EV_ABORT:
1459 case NB_EV_APPLY:
1460 break;
1461 }
1462
1463 return NB_OK;
1464 }
1465
1466 /*
1467 * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/mlag/peer-state
1468 */
1469 int routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_peer_state_modify(
1470 struct nb_cb_modify_args *args)
1471 {
1472 switch (args->event) {
1473 case NB_EV_VALIDATE:
1474 case NB_EV_PREPARE:
1475 case NB_EV_ABORT:
1476 case NB_EV_APPLY:
1477 break;
1478 }
1479
1480 return NB_OK;
1481 }
1482
1483 /*
1484 * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/register-accept-list
1485 */
1486 int routing_control_plane_protocols_control_plane_protocol_pim_address_family_register_accept_list_modify(
1487 struct nb_cb_modify_args *args)
1488 {
1489 struct vrf *vrf;
1490 struct pim_instance *pim;
1491 const char *plist;
1492
1493 switch (args->event) {
1494 case NB_EV_VALIDATE:
1495 case NB_EV_PREPARE:
1496 case NB_EV_ABORT:
1497 break;
1498 case NB_EV_APPLY:
1499 vrf = nb_running_get_entry(args->dnode, NULL, true);
1500 pim = vrf->info;
1501 plist = yang_dnode_get_string(args->dnode, NULL);
1502
1503 XFREE(MTYPE_PIM_PLIST_NAME, pim->register_plist);
1504 pim->register_plist = XSTRDUP(MTYPE_PIM_PLIST_NAME, plist);
1505
1506 break;
1507 }
1508
1509 return NB_OK;
1510 }
1511
1512 int routing_control_plane_protocols_control_plane_protocol_pim_address_family_register_accept_list_destroy(
1513 struct nb_cb_destroy_args *args)
1514 {
1515 struct vrf *vrf;
1516 struct pim_instance *pim;
1517
1518 switch (args->event) {
1519 case NB_EV_VALIDATE:
1520 case NB_EV_PREPARE:
1521 case NB_EV_ABORT:
1522 break;
1523 case NB_EV_APPLY:
1524 vrf = nb_running_get_entry(args->dnode, NULL, true);
1525 pim = vrf->info;
1526
1527 XFREE(MTYPE_PIM_PLIST_NAME, pim->register_plist);
1528 break;
1529 }
1530
1531 return NB_OK;
1532 }
1533
1534 /*
1535 * XPath: /frr-interface:lib/interface/frr-pim:pim/address-family
1536 */
1537 int lib_interface_pim_address_family_create(struct nb_cb_create_args *args)
1538 {
1539 switch (args->event) {
1540 case NB_EV_VALIDATE:
1541 case NB_EV_PREPARE:
1542 case NB_EV_ABORT:
1543 case NB_EV_APPLY:
1544 break;
1545 }
1546
1547 return NB_OK;
1548 }
1549
1550 int lib_interface_pim_address_family_destroy(struct nb_cb_destroy_args *args)
1551 {
1552 struct interface *ifp;
1553 struct pim_interface *pim_ifp;
1554
1555 switch (args->event) {
1556 case NB_EV_VALIDATE:
1557 case NB_EV_PREPARE:
1558 case NB_EV_ABORT:
1559 break;
1560 case NB_EV_APPLY:
1561 ifp = nb_running_get_entry(args->dnode, NULL, true);
1562 pim_ifp = ifp->info;
1563 if (!pim_ifp)
1564 return NB_OK;
1565
1566 if (!pim_cmd_interface_delete(ifp)) {
1567 snprintf(args->errmsg, args->errmsg_len,
1568 "Unable to delete interface information %s",
1569 ifp->name);
1570 return NB_ERR_INCONSISTENCY;
1571 }
1572 }
1573
1574 return NB_OK;
1575 }
1576
1577 /*
1578 * XPath: /frr-interface:lib/interface/frr-pim:pim/address-family/pim-enable
1579 */
1580 int lib_interface_pim_address_family_pim_enable_modify(struct nb_cb_modify_args *args)
1581 {
1582 struct interface *ifp;
1583 struct pim_interface *pim_ifp;
1584 int mcast_if_count;
1585 const struct lyd_node *if_dnode;
1586
1587 switch (args->event) {
1588 case NB_EV_VALIDATE:
1589 if_dnode = yang_dnode_get_parent(args->dnode, "interface");
1590 mcast_if_count =
1591 yang_get_list_elements_count(if_dnode);
1592
1593 /* Limiting mcast interfaces to number of VIFs */
1594 if (mcast_if_count == MAXVIFS) {
1595 snprintf(args->errmsg, args->errmsg_len,
1596 "Max multicast interfaces(%d) reached.",
1597 MAXVIFS);
1598 return NB_ERR_VALIDATION;
1599 }
1600 break;
1601 case NB_EV_PREPARE:
1602 case NB_EV_ABORT:
1603 break;
1604 case NB_EV_APPLY:
1605 ifp = nb_running_get_entry(args->dnode, NULL, true);
1606
1607 if (yang_dnode_get_bool(args->dnode, NULL)) {
1608 if (!pim_cmd_interface_add(ifp)) {
1609 snprintf(args->errmsg, args->errmsg_len,
1610 "Could not enable PIM SM on interface %s",
1611 ifp->name);
1612 return NB_ERR_INCONSISTENCY;
1613 }
1614 } else {
1615 pim_ifp = ifp->info;
1616 if (!pim_ifp)
1617 return NB_ERR_INCONSISTENCY;
1618
1619 if (!pim_cmd_interface_delete(ifp)) {
1620 snprintf(args->errmsg, args->errmsg_len,
1621 "Unable to delete interface information");
1622 return NB_ERR_INCONSISTENCY;
1623 }
1624 }
1625 break;
1626 }
1627
1628 return NB_OK;
1629 }
1630
1631 /*
1632 * XPath:
1633 * /frr-interface:lib/interface/frr-pim:pim/address-family/pim-passive-enable
1634 */
1635 int lib_interface_pim_address_family_pim_passive_enable_modify(
1636 struct nb_cb_modify_args *args)
1637 {
1638 struct interface *ifp;
1639 struct pim_interface *pim_ifp;
1640
1641 switch (args->event) {
1642 case NB_EV_VALIDATE:
1643 case NB_EV_ABORT:
1644 case NB_EV_PREPARE:
1645 break;
1646 case NB_EV_APPLY:
1647 ifp = nb_running_get_entry(args->dnode, NULL, true);
1648 pim_ifp = ifp->info;
1649 pim_ifp->pim_passive_enable =
1650 yang_dnode_get_bool(args->dnode, NULL);
1651 break;
1652 }
1653
1654 return NB_OK;
1655 }
1656
1657 /*
1658 * XPath: /frr-interface:lib/interface/frr-pim:pim/address-family/hello-interval
1659 */
1660 int lib_interface_pim_address_family_hello_interval_modify(
1661 struct nb_cb_modify_args *args)
1662 {
1663 struct interface *ifp;
1664 struct pim_interface *pim_ifp;
1665
1666 switch (args->event) {
1667 case NB_EV_VALIDATE:
1668 case NB_EV_ABORT:
1669 case NB_EV_PREPARE:
1670 break;
1671 case NB_EV_APPLY:
1672 ifp = nb_running_get_entry(args->dnode, NULL, true);
1673 pim_ifp = ifp->info;
1674 pim_ifp->pim_hello_period =
1675 yang_dnode_get_uint8(args->dnode, NULL);
1676 pim_ifp->pim_default_holdtime = -1;
1677 break;
1678 }
1679
1680 return NB_OK;
1681 }
1682
1683 /*
1684 * XPath: /frr-interface:lib/interface/frr-pim:pim/address-family/hello-holdtime
1685 */
1686 int lib_interface_pim_address_family_hello_holdtime_modify(
1687 struct nb_cb_modify_args *args)
1688 {
1689 struct interface *ifp;
1690 struct pim_interface *pim_ifp;
1691
1692 switch (args->event) {
1693 case NB_EV_VALIDATE:
1694 case NB_EV_ABORT:
1695 case NB_EV_PREPARE:
1696 break;
1697 case NB_EV_APPLY:
1698 ifp = nb_running_get_entry(args->dnode, NULL, true);
1699 pim_ifp = ifp->info;
1700 pim_ifp->pim_default_holdtime =
1701 yang_dnode_get_uint16(args->dnode, NULL);
1702 break;
1703 }
1704
1705 return NB_OK;
1706
1707 }
1708
1709 int lib_interface_pim_address_family_hello_holdtime_destroy(
1710 struct nb_cb_destroy_args *args)
1711 {
1712 struct interface *ifp;
1713 struct pim_interface *pim_ifp;
1714
1715 switch (args->event) {
1716 case NB_EV_VALIDATE:
1717 case NB_EV_ABORT:
1718 case NB_EV_PREPARE:
1719 break;
1720 case NB_EV_APPLY:
1721 ifp = nb_running_get_entry(args->dnode, NULL, true);
1722 pim_ifp = ifp->info;
1723 pim_ifp->pim_default_holdtime = -1;
1724 break;
1725 }
1726
1727 return NB_OK;
1728 }
1729 /*
1730 * XPath: /frr-interface:lib/interface/frr-pim:pim/address-family/bfd
1731 */
1732 int lib_interface_pim_address_family_bfd_create(struct nb_cb_create_args *args)
1733 {
1734 struct interface *ifp;
1735 struct pim_interface *pim_ifp;
1736
1737 switch (args->event) {
1738 case NB_EV_VALIDATE:
1739 case NB_EV_PREPARE:
1740 case NB_EV_ABORT:
1741 /* NOTHING */
1742 break;
1743 case NB_EV_APPLY:
1744 ifp = nb_running_get_entry(args->dnode, NULL, true);
1745 pim_ifp = ifp->info;
1746 pim_ifp->bfd_config.enabled = true;
1747 break;
1748 }
1749
1750 return NB_OK;
1751 }
1752
1753 int lib_interface_pim_address_family_bfd_destroy(
1754 struct nb_cb_destroy_args *args)
1755 {
1756 struct interface *ifp;
1757 struct pim_interface *pim_ifp;
1758 const struct lyd_node *if_dnode;
1759
1760 switch (args->event) {
1761 case NB_EV_VALIDATE:
1762 if_dnode = yang_dnode_get_parent(args->dnode, "interface");
1763 if (!is_pim_interface(if_dnode)) {
1764 snprintf(args->errmsg, args->errmsg_len,
1765 "Pim not enabled on this interface");
1766 return NB_ERR_VALIDATION;
1767 }
1768 break;
1769 case NB_EV_ABORT:
1770 case NB_EV_PREPARE:
1771 break;
1772 case NB_EV_APPLY:
1773 ifp = nb_running_get_entry(args->dnode, NULL, true);
1774 pim_ifp = ifp->info;
1775 pim_ifp->bfd_config.enabled = false;
1776 pim_bfd_reg_dereg_all_nbr(ifp);
1777 break;
1778 }
1779
1780 return NB_OK;
1781 }
1782
1783 /*
1784 * XPath: /frr-interface:lib/interface/frr-pim:pim/address-family/bfd
1785 */
1786 void lib_interface_pim_address_family_bfd_apply_finish(
1787 struct nb_cb_apply_finish_args *args)
1788 {
1789 struct interface *ifp;
1790 struct pim_interface *pim_ifp;
1791
1792 ifp = nb_running_get_entry(args->dnode, NULL, true);
1793 pim_ifp = ifp->info;
1794
1795 if (!pim_ifp) {
1796 zlog_debug("Pim not enabled on this interface");
1797 return;
1798 }
1799
1800 pim_ifp->bfd_config.detection_multiplier =
1801 yang_dnode_get_uint8(args->dnode, "./detect_mult");
1802 pim_ifp->bfd_config.min_rx =
1803 yang_dnode_get_uint16(args->dnode, "./min-rx-interval");
1804 pim_ifp->bfd_config.min_tx =
1805 yang_dnode_get_uint16(args->dnode, "./min-tx-interval");
1806
1807 pim_bfd_reg_dereg_all_nbr(ifp);
1808 }
1809
1810 /*
1811 * XPath: /frr-interface:lib/interface/frr-pim:pim/address-family/bfd/min-rx-interval
1812 */
1813 int lib_interface_pim_address_family_bfd_min_rx_interval_modify(
1814 struct nb_cb_modify_args *args)
1815 {
1816 switch (args->event) {
1817 case NB_EV_VALIDATE:
1818 case NB_EV_PREPARE:
1819 case NB_EV_ABORT:
1820 case NB_EV_APPLY:
1821 break;
1822 }
1823
1824 return NB_OK;
1825 }
1826
1827 /*
1828 * XPath: /frr-interface:lib/interface/frr-pim:pim/address-family/bfd/min-tx-interval
1829 */
1830 int lib_interface_pim_address_family_bfd_min_tx_interval_modify(
1831 struct nb_cb_modify_args *args)
1832 {
1833 switch (args->event) {
1834 case NB_EV_VALIDATE:
1835 case NB_EV_PREPARE:
1836 case NB_EV_ABORT:
1837 case NB_EV_APPLY:
1838 break;
1839 }
1840
1841 return NB_OK;
1842 }
1843
1844 /*
1845 * XPath: /frr-interface:lib/interface/frr-pim:pim/address-family/bfd/detect_mult
1846 */
1847 int lib_interface_pim_address_family_bfd_detect_mult_modify(
1848 struct nb_cb_modify_args *args)
1849 {
1850 switch (args->event) {
1851 case NB_EV_VALIDATE:
1852 case NB_EV_PREPARE:
1853 case NB_EV_ABORT:
1854 case NB_EV_APPLY:
1855 break;
1856 }
1857
1858 return NB_OK;
1859 }
1860
1861 /*
1862 * XPath: /frr-interface:lib/interface/frr-pim:pim/address-family/bfd/profile
1863 */
1864 int lib_interface_pim_address_family_bfd_profile_modify(
1865 struct nb_cb_modify_args *args)
1866 {
1867 struct interface *ifp;
1868 struct pim_interface *pim_ifp;
1869
1870 switch (args->event) {
1871 case NB_EV_VALIDATE:
1872 case NB_EV_PREPARE:
1873 case NB_EV_ABORT:
1874 /* NOTHING */
1875 break;
1876 case NB_EV_APPLY:
1877 ifp = nb_running_get_entry(args->dnode, NULL, true);
1878 pim_ifp = ifp->info;
1879 XFREE(MTYPE_TMP, pim_ifp->bfd_config.profile);
1880 pim_ifp->bfd_config.profile = XSTRDUP(
1881 MTYPE_TMP, yang_dnode_get_string(args->dnode, NULL));
1882 break;
1883 }
1884
1885 return NB_OK;
1886 }
1887
1888 int lib_interface_pim_address_family_bfd_profile_destroy(
1889 struct nb_cb_destroy_args *args)
1890 {
1891 struct interface *ifp;
1892 struct pim_interface *pim_ifp;
1893
1894 switch (args->event) {
1895 case NB_EV_VALIDATE:
1896 case NB_EV_PREPARE:
1897 case NB_EV_ABORT:
1898 /* NOTHING */
1899 break;
1900 case NB_EV_APPLY:
1901 ifp = nb_running_get_entry(args->dnode, NULL, true);
1902 pim_ifp = ifp->info;
1903 XFREE(MTYPE_TMP, pim_ifp->bfd_config.profile);
1904 break;
1905 }
1906
1907 return NB_OK;
1908 }
1909
1910 /*
1911 * XPath: /frr-interface:lib/interface/frr-pim:pim/address-family/bsm
1912 */
1913 int lib_interface_pim_address_family_bsm_modify(struct nb_cb_modify_args *args)
1914 {
1915 struct interface *ifp;
1916 struct pim_interface *pim_ifp;
1917
1918 switch (args->event) {
1919 case NB_EV_VALIDATE:
1920 case NB_EV_PREPARE:
1921 case NB_EV_ABORT:
1922 break;
1923 case NB_EV_APPLY:
1924 ifp = nb_running_get_entry(args->dnode, NULL, true);
1925 pim_ifp = ifp->info;
1926 pim_ifp->bsm_enable = yang_dnode_get_bool(args->dnode, NULL);
1927
1928 break;
1929 }
1930
1931 return NB_OK;
1932 }
1933
1934 /*
1935 * XPath: /frr-interface:lib/interface/frr-pim:pim/address-family/unicast-bsm
1936 */
1937 int lib_interface_pim_address_family_unicast_bsm_modify(
1938 struct nb_cb_modify_args *args)
1939 {
1940 struct interface *ifp;
1941 struct pim_interface *pim_ifp;
1942
1943 switch (args->event) {
1944 case NB_EV_VALIDATE:
1945 case NB_EV_PREPARE:
1946 case NB_EV_ABORT:
1947 break;
1948 case NB_EV_APPLY:
1949 ifp = nb_running_get_entry(args->dnode, NULL, true);
1950 pim_ifp = ifp->info;
1951 pim_ifp->ucast_bsm_accept =
1952 yang_dnode_get_bool(args->dnode, NULL);
1953
1954 break;
1955 }
1956
1957 return NB_OK;
1958 }
1959
1960 /*
1961 * XPath: /frr-interface:lib/interface/frr-pim:pim/address-family/active-active
1962 */
1963 int lib_interface_pim_address_family_active_active_modify(
1964 struct nb_cb_modify_args *args)
1965 {
1966 struct interface *ifp;
1967 struct pim_interface *pim_ifp;
1968
1969 switch (args->event) {
1970 case NB_EV_VALIDATE:
1971 case NB_EV_PREPARE:
1972 case NB_EV_ABORT:
1973 break;
1974 case NB_EV_APPLY:
1975 ifp = nb_running_get_entry(args->dnode, NULL, true);
1976 pim_ifp = ifp->info;
1977 if (yang_dnode_get_bool(args->dnode, NULL)) {
1978 if (PIM_DEBUG_MLAG)
1979 zlog_debug(
1980 "Configuring PIM active-active on Interface: %s",
1981 ifp->name);
1982 pim_if_configure_mlag_dualactive(pim_ifp);
1983 } else {
1984 if (PIM_DEBUG_MLAG)
1985 zlog_debug(
1986 "UnConfiguring PIM active-active on Interface: %s",
1987 ifp->name);
1988 pim_if_unconfigure_mlag_dualactive(pim_ifp);
1989 }
1990
1991 break;
1992 }
1993
1994 return NB_OK;
1995
1996 }
1997
1998 /*
1999 * XPath: /frr-interface:lib/interface/frr-pim:pim/address-family/dr-priority
2000 */
2001 int lib_interface_pim_address_family_dr_priority_modify(
2002 struct nb_cb_modify_args *args)
2003 {
2004 struct interface *ifp;
2005 struct pim_interface *pim_ifp;
2006 uint32_t old_dr_prio;
2007 const struct lyd_node *if_dnode;
2008
2009 switch (args->event) {
2010 case NB_EV_VALIDATE:
2011 if_dnode = yang_dnode_get_parent(args->dnode, "interface");
2012 if (!is_pim_interface(if_dnode)) {
2013 snprintf(args->errmsg, args->errmsg_len,
2014 "Pim not enabled on this interface");
2015 return NB_ERR_VALIDATION;
2016 }
2017 break;
2018 case NB_EV_PREPARE:
2019 case NB_EV_ABORT:
2020 break;
2021 case NB_EV_APPLY:
2022 ifp = nb_running_get_entry(args->dnode, NULL, true);
2023 pim_ifp = ifp->info;
2024 old_dr_prio = pim_ifp->pim_dr_priority;
2025 pim_ifp->pim_dr_priority = yang_dnode_get_uint32(args->dnode,
2026 NULL);
2027
2028 if (old_dr_prio != pim_ifp->pim_dr_priority) {
2029 pim_if_dr_election(ifp);
2030 pim_hello_restart_now(ifp);
2031 }
2032 break;
2033 }
2034
2035 return NB_OK;
2036 }
2037
2038 /*
2039 * XPath: /frr-interface:lib/interface/frr-pim:pim/address-family/use-source
2040 */
2041 int lib_interface_pim_address_family_use_source_modify(
2042 struct nb_cb_modify_args *args)
2043 {
2044 struct interface *ifp;
2045 pim_addr source_addr;
2046 int result;
2047 const struct lyd_node *if_dnode;
2048
2049 switch (args->event) {
2050 case NB_EV_VALIDATE:
2051 if_dnode = yang_dnode_get_parent(args->dnode, "interface");
2052 if (!is_pim_interface(if_dnode)) {
2053 snprintf(args->errmsg, args->errmsg_len,
2054 "Pim not enabled on this interface");
2055 return NB_ERR_VALIDATION;
2056 }
2057 break;
2058 case NB_EV_ABORT:
2059 case NB_EV_PREPARE:
2060 break;
2061 case NB_EV_APPLY:
2062 ifp = nb_running_get_entry(args->dnode, NULL, true);
2063 #if PIM_IPV == 4
2064 yang_dnode_get_ipv4(&source_addr, args->dnode, NULL);
2065 #else
2066 yang_dnode_get_ipv6(&source_addr, args->dnode, NULL);
2067 #endif
2068
2069 result = interface_pim_use_src_cmd_worker(
2070 ifp, source_addr,
2071 args->errmsg, args->errmsg_len);
2072
2073 if (result != PIM_SUCCESS)
2074 return NB_ERR_INCONSISTENCY;
2075
2076 break;
2077 }
2078
2079 return NB_OK;
2080 }
2081
2082 int lib_interface_pim_address_family_use_source_destroy(
2083 struct nb_cb_destroy_args *args)
2084 {
2085 struct interface *ifp;
2086 int result;
2087 const struct lyd_node *if_dnode;
2088
2089 switch (args->event) {
2090 case NB_EV_VALIDATE:
2091 if_dnode = yang_dnode_get_parent(args->dnode, "interface");
2092 if (!is_pim_interface(if_dnode)) {
2093 snprintf(args->errmsg, args->errmsg_len,
2094 "Pim not enabled on this interface");
2095 return NB_ERR_VALIDATION;
2096 }
2097 break;
2098 case NB_EV_ABORT:
2099 case NB_EV_PREPARE:
2100 break;
2101 case NB_EV_APPLY:
2102 ifp = nb_running_get_entry(args->dnode, NULL, true);
2103
2104 result = interface_pim_use_src_cmd_worker(ifp, PIMADDR_ANY,
2105 args->errmsg,
2106 args->errmsg_len);
2107
2108 if (result != PIM_SUCCESS)
2109 return NB_ERR_INCONSISTENCY;
2110
2111 break;
2112 }
2113
2114 return NB_OK;
2115 }
2116
2117 /*
2118 * XPath: /frr-interface:lib/interface/frr-pim:pim/address-family/multicast-boundary-oil
2119 */
2120 int lib_interface_pim_address_family_multicast_boundary_oil_modify(
2121 struct nb_cb_modify_args *args)
2122 {
2123 struct interface *ifp;
2124 struct pim_interface *pim_ifp;
2125 const char *plist;
2126 const struct lyd_node *if_dnode;
2127
2128 switch (args->event) {
2129 case NB_EV_VALIDATE:
2130 if_dnode = yang_dnode_get_parent(args->dnode, "interface");
2131 if (!is_pim_interface(if_dnode)) {
2132 snprintf(args->errmsg, args->errmsg_len,
2133 "Pim not enabled on this interface");
2134 return NB_ERR_VALIDATION;
2135 }
2136 break;
2137 case NB_EV_ABORT:
2138 case NB_EV_PREPARE:
2139 break;
2140 case NB_EV_APPLY:
2141 ifp = nb_running_get_entry(args->dnode, NULL, true);
2142 pim_ifp = ifp->info;
2143 plist = yang_dnode_get_string(args->dnode, NULL);
2144
2145 if (pim_ifp->boundary_oil_plist)
2146 XFREE(MTYPE_PIM_INTERFACE, pim_ifp->boundary_oil_plist);
2147
2148 pim_ifp->boundary_oil_plist =
2149 XSTRDUP(MTYPE_PIM_INTERFACE, plist);
2150
2151 break;
2152 }
2153
2154 return NB_OK;
2155 }
2156
2157 int lib_interface_pim_address_family_multicast_boundary_oil_destroy(
2158 struct nb_cb_destroy_args *args)
2159 {
2160 struct interface *ifp;
2161 struct pim_interface *pim_ifp;
2162 const struct lyd_node *if_dnode;
2163
2164 switch (args->event) {
2165 case NB_EV_VALIDATE:
2166 if_dnode = yang_dnode_get_parent(args->dnode, "interface");
2167 if (!is_pim_interface(if_dnode)) {
2168 snprintf(args->errmsg, args->errmsg_len,
2169 "%% Enable PIM and/or IGMP on this interface first");
2170 return NB_ERR_VALIDATION;
2171 }
2172 break;
2173 case NB_EV_ABORT:
2174 case NB_EV_PREPARE:
2175 break;
2176 case NB_EV_APPLY:
2177 ifp = nb_running_get_entry(args->dnode, NULL, true);
2178 pim_ifp = ifp->info;
2179 if (pim_ifp->boundary_oil_plist)
2180 XFREE(MTYPE_PIM_INTERFACE, pim_ifp->boundary_oil_plist);
2181 break;
2182 }
2183
2184 return NB_OK;
2185 }
2186
2187 /*
2188 * XPath: /frr-interface:lib/interface/frr-pim:pim/address-family/mroute
2189 */
2190 int lib_interface_pim_address_family_mroute_create(
2191 struct nb_cb_create_args *args)
2192 {
2193 switch (args->event) {
2194 case NB_EV_VALIDATE:
2195 case NB_EV_PREPARE:
2196 case NB_EV_ABORT:
2197 case NB_EV_APPLY:
2198 break;
2199 }
2200
2201 return NB_OK;
2202 }
2203
2204 int lib_interface_pim_address_family_mroute_destroy(
2205 struct nb_cb_destroy_args *args)
2206 {
2207 struct pim_instance *pim;
2208 struct pim_interface *pim_iifp;
2209 struct interface *iif;
2210 struct interface *oif;
2211 const char *oifname;
2212 pim_addr source_addr;
2213 pim_addr group_addr;
2214 const struct lyd_node *if_dnode;
2215
2216 switch (args->event) {
2217 case NB_EV_VALIDATE:
2218 if_dnode = yang_dnode_get_parent(args->dnode, "interface");
2219 if (!is_pim_interface(if_dnode)) {
2220 snprintf(args->errmsg, args->errmsg_len,
2221 "%% Enable PIM and/or IGMP on this interface first");
2222 return NB_ERR_VALIDATION;
2223 }
2224 break;
2225 case NB_EV_PREPARE:
2226 case NB_EV_ABORT:
2227 break;
2228 case NB_EV_APPLY:
2229 iif = nb_running_get_entry(args->dnode, NULL, true);
2230 pim_iifp = iif->info;
2231 pim = pim_iifp->pim;
2232
2233 oifname = yang_dnode_get_string(args->dnode, "./oif");
2234 oif = if_lookup_by_name(oifname, pim->vrf->vrf_id);
2235
2236 if (!oif) {
2237 snprintf(args->errmsg, args->errmsg_len,
2238 "No such interface name %s",
2239 oifname);
2240 return NB_ERR_INCONSISTENCY;
2241 }
2242
2243 yang_dnode_get_pimaddr(&source_addr, args->dnode, "./source-addr");
2244 yang_dnode_get_pimaddr(&group_addr, args->dnode, "./group-addr");
2245
2246 if (pim_static_del(pim, iif, oif, group_addr, source_addr)) {
2247 snprintf(args->errmsg, args->errmsg_len,
2248 "Failed to remove static mroute");
2249 return NB_ERR_INCONSISTENCY;
2250 }
2251
2252 break;
2253 }
2254
2255 return NB_OK;
2256 }
2257
2258 /*
2259 * XPath: /frr-interface:lib/interface/frr-pim:pim/address-family/mroute/oif
2260 */
2261 int lib_interface_pim_address_family_mroute_oif_modify(
2262 struct nb_cb_modify_args *args)
2263 {
2264 struct pim_instance *pim;
2265 struct pim_interface *pim_iifp;
2266 struct interface *iif;
2267 struct interface *oif;
2268 const char *oifname;
2269 pim_addr source_addr;
2270 pim_addr group_addr;
2271 const struct lyd_node *if_dnode;
2272
2273 switch (args->event) {
2274 case NB_EV_VALIDATE:
2275 if_dnode = yang_dnode_get_parent(args->dnode, "interface");
2276 if (!is_pim_interface(if_dnode)) {
2277 snprintf(args->errmsg, args->errmsg_len,
2278 "%% Enable PIM and/or IGMP on this interface first");
2279 return NB_ERR_VALIDATION;
2280 }
2281
2282 #ifdef PIM_ENFORCE_LOOPFREE_MFC
2283 iif = nb_running_get_entry(args->dnode, NULL, false);
2284 if (!iif) {
2285 return NB_OK;
2286 }
2287
2288 pim_iifp = iif->info;
2289 pim = pim_iifp->pim;
2290
2291 oifname = yang_dnode_get_string(args->dnode, NULL);
2292 oif = if_lookup_by_name(oifname, pim->vrf->vrf_id);
2293
2294 if (oif && (iif->ifindex == oif->ifindex)) {
2295 strlcpy(args->errmsg,
2296 "% IIF same as OIF and loopfree enforcement is enabled; rejecting",
2297 args->errmsg_len);
2298 return NB_ERR_VALIDATION;
2299 }
2300 #endif
2301 break;
2302 case NB_EV_PREPARE:
2303 case NB_EV_ABORT:
2304 break;
2305 case NB_EV_APPLY:
2306 iif = nb_running_get_entry(args->dnode, NULL, true);
2307 pim_iifp = iif->info;
2308 pim = pim_iifp->pim;
2309
2310 oifname = yang_dnode_get_string(args->dnode, NULL);
2311 oif = if_lookup_by_name(oifname, pim->vrf->vrf_id);
2312 if (!oif) {
2313 snprintf(args->errmsg, args->errmsg_len,
2314 "No such interface name %s",
2315 oifname);
2316 return NB_ERR_INCONSISTENCY;
2317 }
2318
2319 yang_dnode_get_pimaddr(&source_addr, args->dnode, "../source-addr");
2320 yang_dnode_get_pimaddr(&group_addr, args->dnode, "../group-addr");
2321
2322 if (pim_static_add(pim, iif, oif, group_addr, source_addr)) {
2323 snprintf(args->errmsg, args->errmsg_len,
2324 "Failed to add static mroute");
2325 return NB_ERR_INCONSISTENCY;
2326 }
2327
2328 break;
2329 }
2330
2331 return NB_OK;
2332 }
2333
2334 int lib_interface_pim_address_family_mroute_oif_destroy(
2335 struct nb_cb_destroy_args *args)
2336 {
2337 switch (args->event) {
2338 case NB_EV_VALIDATE:
2339 case NB_EV_PREPARE:
2340 case NB_EV_ABORT:
2341 case NB_EV_APPLY:
2342 break;
2343 }
2344
2345 return NB_OK;
2346 }
2347
2348 /*
2349 * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-rp:rp/static-rp/rp-list
2350 */
2351 int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_static_rp_rp_list_create(
2352 struct nb_cb_create_args *args)
2353 {
2354 switch (args->event) {
2355 case NB_EV_VALIDATE:
2356 case NB_EV_PREPARE:
2357 case NB_EV_ABORT:
2358 case NB_EV_APPLY:
2359 break;
2360 }
2361
2362 return NB_OK;
2363 }
2364
2365 int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_static_rp_rp_list_destroy(
2366 struct nb_cb_destroy_args *args)
2367 {
2368 struct vrf *vrf;
2369 struct pim_instance *pim;
2370 struct prefix group;
2371 pim_addr rp_addr;
2372 const char *plist;
2373 int result = 0;
2374
2375 switch (args->event) {
2376 case NB_EV_VALIDATE:
2377 case NB_EV_PREPARE:
2378 case NB_EV_ABORT:
2379 break;
2380 case NB_EV_APPLY:
2381 vrf = nb_running_get_entry(args->dnode, NULL, true);
2382 pim = vrf->info;
2383 yang_dnode_get_pimaddr(&rp_addr, args->dnode, "./rp-address");
2384
2385 if (yang_dnode_get(args->dnode, "./group-list")) {
2386 yang_dnode_get_prefix(&group, args->dnode,
2387 "./group-list");
2388 apply_mask(&group);
2389 result = pim_no_rp_cmd_worker(pim, rp_addr, group, NULL,
2390 args->errmsg,
2391 args->errmsg_len);
2392 }
2393
2394 else if (yang_dnode_get(args->dnode, "./prefix-list")) {
2395 plist = yang_dnode_get_string(args->dnode,
2396 "./prefix-list");
2397 if (!pim_get_all_mcast_group(&group)) {
2398 flog_err(
2399 EC_LIB_DEVELOPMENT,
2400 "Unable to convert 224.0.0.0/4 to prefix");
2401 return NB_ERR_INCONSISTENCY;
2402 }
2403
2404 result = pim_no_rp_cmd_worker(pim, rp_addr, group,
2405 plist, args->errmsg,
2406 args->errmsg_len);
2407 }
2408
2409 if (result)
2410 return NB_ERR_INCONSISTENCY;
2411 break;
2412 }
2413
2414 return NB_OK;
2415 }
2416
2417 /*
2418 * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-rp:rp/static-rp/rp-list/group-list
2419 */
2420 int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_static_rp_rp_list_group_list_create(
2421 struct nb_cb_create_args *args)
2422 {
2423 struct vrf *vrf;
2424 struct pim_instance *pim;
2425 struct prefix group;
2426 pim_addr rp_addr;
2427
2428 switch (args->event) {
2429 case NB_EV_VALIDATE:
2430 case NB_EV_PREPARE:
2431 case NB_EV_ABORT:
2432 break;
2433 case NB_EV_APPLY:
2434 vrf = nb_running_get_entry(args->dnode, NULL, true);
2435 pim = vrf->info;
2436 yang_dnode_get_pimaddr(&rp_addr, args->dnode, "../rp-address");
2437 yang_dnode_get_prefix(&group, args->dnode, NULL);
2438 apply_mask(&group);
2439 return pim_rp_cmd_worker(pim, rp_addr, group, NULL,
2440 args->errmsg, args->errmsg_len);
2441 }
2442
2443 return NB_OK;
2444 }
2445
2446 int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_static_rp_rp_list_group_list_destroy(
2447 struct nb_cb_destroy_args *args)
2448 {
2449 struct vrf *vrf;
2450 struct pim_instance *pim;
2451 struct prefix group;
2452 pim_addr rp_addr;
2453
2454 switch (args->event) {
2455 case NB_EV_VALIDATE:
2456 case NB_EV_PREPARE:
2457 case NB_EV_ABORT:
2458 break;
2459 case NB_EV_APPLY:
2460 vrf = nb_running_get_entry(args->dnode, NULL, true);
2461 pim = vrf->info;
2462 yang_dnode_get_pimaddr(&rp_addr, args->dnode, "../rp-address");
2463 yang_dnode_get_prefix(&group, args->dnode, NULL);
2464 apply_mask(&group);
2465
2466 return pim_no_rp_cmd_worker(pim, rp_addr, group, NULL,
2467 args->errmsg, args->errmsg_len);
2468 }
2469
2470 return NB_OK;
2471 }
2472
2473 /*
2474 * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-rp:rp/static-rp/rp-list/prefix-list
2475 */
2476 int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_static_rp_rp_list_prefix_list_modify(
2477 struct nb_cb_modify_args *args)
2478 {
2479 struct vrf *vrf;
2480 struct pim_instance *pim;
2481 struct prefix group;
2482 pim_addr rp_addr;
2483 const char *plist;
2484
2485 switch (args->event) {
2486 case NB_EV_VALIDATE:
2487 case NB_EV_PREPARE:
2488 case NB_EV_ABORT:
2489 break;
2490 case NB_EV_APPLY:
2491 vrf = nb_running_get_entry(args->dnode, NULL, true);
2492 pim = vrf->info;
2493 plist = yang_dnode_get_string(args->dnode, NULL);
2494 yang_dnode_get_pimaddr(&rp_addr, args->dnode, "../rp-address");
2495 if (!pim_get_all_mcast_group(&group)) {
2496 flog_err(EC_LIB_DEVELOPMENT,
2497 "Unable to convert 224.0.0.0/4 to prefix");
2498 return NB_ERR_INCONSISTENCY;
2499 }
2500 return pim_rp_cmd_worker(pim, rp_addr, group, plist,
2501 args->errmsg, args->errmsg_len);
2502 }
2503
2504 return NB_OK;
2505 }
2506
2507 int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_static_rp_rp_list_prefix_list_destroy(
2508 struct nb_cb_destroy_args *args)
2509 {
2510 struct vrf *vrf;
2511 struct pim_instance *pim;
2512 struct prefix group;
2513 pim_addr rp_addr;
2514 const char *plist;
2515
2516 switch (args->event) {
2517 case NB_EV_VALIDATE:
2518 case NB_EV_PREPARE:
2519 case NB_EV_ABORT:
2520 break;
2521 case NB_EV_APPLY:
2522 vrf = nb_running_get_entry(args->dnode, NULL, true);
2523 pim = vrf->info;
2524 yang_dnode_get_pimaddr(&rp_addr, args->dnode, "../rp-address");
2525 plist = yang_dnode_get_string(args->dnode, NULL);
2526 if (!pim_get_all_mcast_group(&group)) {
2527 flog_err(EC_LIB_DEVELOPMENT,
2528 "Unable to convert 224.0.0.0/4 to prefix");
2529 return NB_ERR_INCONSISTENCY;
2530 }
2531 return pim_no_rp_cmd_worker(pim, rp_addr, group, plist,
2532 args->errmsg, args->errmsg_len);
2533 break;
2534 }
2535
2536 return NB_OK;
2537 }
2538
2539 /*
2540 * XPath: /frr-interface:lib/interface/frr-gmp:gmp/address-family
2541 */
2542 int lib_interface_gmp_address_family_create(struct nb_cb_create_args *args)
2543 {
2544 switch (args->event) {
2545 case NB_EV_VALIDATE:
2546 case NB_EV_PREPARE:
2547 case NB_EV_ABORT:
2548 case NB_EV_APPLY:
2549 break;
2550 }
2551
2552 return NB_OK;
2553 }
2554
2555 int lib_interface_gmp_address_family_destroy(struct nb_cb_destroy_args *args)
2556 {
2557 struct interface *ifp;
2558 struct pim_interface *pim_ifp;
2559
2560 switch (args->event) {
2561 case NB_EV_VALIDATE:
2562 case NB_EV_PREPARE:
2563 case NB_EV_ABORT:
2564 break;
2565 case NB_EV_APPLY:
2566 ifp = nb_running_get_entry(args->dnode, NULL, true);
2567 pim_ifp = ifp->info;
2568
2569 if (!pim_ifp)
2570 return NB_OK;
2571
2572 pim_ifp->gm_enable = false;
2573
2574 pim_if_membership_clear(ifp);
2575
2576 pim_if_addr_del_all_igmp(ifp);
2577
2578 if (!pim_ifp->pim_enable)
2579 pim_if_delete(ifp);
2580 }
2581
2582 return NB_OK;
2583 }
2584
2585 /*
2586 * XPath: /frr-interface:lib/interface/frr-gmp:gmp/address-family/enable
2587 */
2588 int lib_interface_gmp_address_family_enable_modify(
2589 struct nb_cb_modify_args *args)
2590 {
2591 struct interface *ifp;
2592 bool gm_enable;
2593 struct pim_interface *pim_ifp;
2594 int mcast_if_count;
2595 const char *ifp_name;
2596 const struct lyd_node *if_dnode;
2597
2598 switch (args->event) {
2599 case NB_EV_VALIDATE:
2600 if_dnode = yang_dnode_get_parent(args->dnode, "interface");
2601 mcast_if_count =
2602 yang_get_list_elements_count(if_dnode);
2603 /* Limiting mcast interfaces to number of VIFs */
2604 if (mcast_if_count == MAXVIFS) {
2605 ifp_name = yang_dnode_get_string(if_dnode, "name");
2606 snprintf(
2607 args->errmsg, args->errmsg_len,
2608 "Max multicast interfaces(%d) Reached. Could not enable %s on interface %s",
2609 MAXVIFS, GM, ifp_name);
2610 return NB_ERR_VALIDATION;
2611 }
2612 break;
2613 case NB_EV_PREPARE:
2614 case NB_EV_ABORT:
2615 break;
2616 case NB_EV_APPLY:
2617 ifp = nb_running_get_entry(args->dnode, NULL, true);
2618 gm_enable = yang_dnode_get_bool(args->dnode, NULL);
2619
2620 if (gm_enable)
2621 return pim_cmd_gm_start(ifp);
2622
2623 else {
2624 pim_ifp = ifp->info;
2625
2626 if (!pim_ifp)
2627 return NB_ERR_INCONSISTENCY;
2628
2629 pim_ifp->gm_enable = false;
2630
2631 pim_if_membership_clear(ifp);
2632
2633 #if PIM_IPV == 4
2634 pim_if_addr_del_all_igmp(ifp);
2635 #else
2636 gm_ifp_teardown(ifp);
2637 #endif
2638
2639 if (!pim_ifp->pim_enable)
2640 pim_if_delete(ifp);
2641 }
2642 }
2643 return NB_OK;
2644 }
2645
2646 /*
2647 * XPath: /frr-interface:lib/interface/frr-gmp:gmp/address-family/igmp-version
2648 */
2649 int lib_interface_gmp_address_family_igmp_version_modify(
2650 struct nb_cb_modify_args *args)
2651 {
2652 struct interface *ifp;
2653 struct pim_interface *pim_ifp;
2654 int igmp_version, old_version = 0;
2655
2656 switch (args->event) {
2657 case NB_EV_VALIDATE:
2658 case NB_EV_PREPARE:
2659 case NB_EV_ABORT:
2660 break;
2661 case NB_EV_APPLY:
2662 ifp = nb_running_get_entry(args->dnode, NULL, true);
2663 pim_ifp = ifp->info;
2664
2665 if (!pim_ifp)
2666 return NB_ERR_INCONSISTENCY;
2667
2668 igmp_version = yang_dnode_get_uint8(args->dnode, NULL);
2669 old_version = pim_ifp->igmp_version;
2670 pim_ifp->igmp_version = igmp_version;
2671
2672 /* Current and new version is different refresh existing
2673 * membership. Going from 3 -> 2 or 2 -> 3.
2674 */
2675 if (old_version != igmp_version)
2676 pim_if_membership_refresh(ifp);
2677
2678 break;
2679 }
2680
2681 return NB_OK;
2682 }
2683
2684 int lib_interface_gmp_address_family_igmp_version_destroy(
2685 struct nb_cb_destroy_args *args)
2686 {
2687 struct interface *ifp;
2688 struct pim_interface *pim_ifp;
2689
2690 switch (args->event) {
2691 case NB_EV_VALIDATE:
2692 case NB_EV_PREPARE:
2693 case NB_EV_ABORT:
2694 break;
2695 case NB_EV_APPLY:
2696 ifp = nb_running_get_entry(args->dnode, NULL, true);
2697 pim_ifp = ifp->info;
2698 pim_ifp->igmp_version = IGMP_DEFAULT_VERSION;
2699 break;
2700 }
2701
2702 return NB_OK;
2703 }
2704
2705 /*
2706 * XPath: /frr-interface:lib/interface/frr-gmp:gmp/address-family/mld-version
2707 */
2708 int lib_interface_gmp_address_family_mld_version_modify(
2709 struct nb_cb_modify_args *args)
2710 {
2711 struct interface *ifp;
2712 struct pim_interface *pim_ifp;
2713
2714 switch (args->event) {
2715 case NB_EV_VALIDATE:
2716 case NB_EV_PREPARE:
2717 case NB_EV_ABORT:
2718 break;
2719 case NB_EV_APPLY:
2720 ifp = nb_running_get_entry(args->dnode, NULL, true);
2721 pim_ifp = ifp->info;
2722 if (!pim_ifp)
2723 return NB_ERR_INCONSISTENCY;
2724
2725 pim_ifp->mld_version = yang_dnode_get_uint8(args->dnode, NULL);
2726 gm_ifp_update(ifp);
2727 break;
2728 }
2729
2730 return NB_OK;
2731 }
2732
2733 int lib_interface_gmp_address_family_mld_version_destroy(
2734 struct nb_cb_destroy_args *args)
2735 {
2736 struct interface *ifp;
2737 struct pim_interface *pim_ifp;
2738
2739 switch (args->event) {
2740 case NB_EV_VALIDATE:
2741 case NB_EV_PREPARE:
2742 case NB_EV_ABORT:
2743 break;
2744 case NB_EV_APPLY:
2745 ifp = nb_running_get_entry(args->dnode, NULL, true);
2746 pim_ifp = ifp->info;
2747 if (!pim_ifp)
2748 return NB_ERR_INCONSISTENCY;
2749
2750 pim_ifp->mld_version = 2;
2751 gm_ifp_update(ifp);
2752 break;
2753 }
2754
2755 return NB_OK;
2756 }
2757
2758 /*
2759 * XPath: /frr-interface:lib/interface/frr-gmp:gmp/address-family/query-interval
2760 */
2761 int lib_interface_gmp_address_family_query_interval_modify(
2762 struct nb_cb_modify_args *args)
2763 {
2764 struct interface *ifp;
2765 int query_interval;
2766
2767 #if PIM_IPV == 4
2768 switch (args->event) {
2769 case NB_EV_VALIDATE:
2770 case NB_EV_PREPARE:
2771 case NB_EV_ABORT:
2772 break;
2773 case NB_EV_APPLY:
2774 ifp = nb_running_get_entry(args->dnode, NULL, true);
2775 query_interval = yang_dnode_get_uint16(args->dnode, NULL);
2776 change_query_interval(ifp->info, query_interval);
2777 }
2778 #else
2779 struct pim_interface *pim_ifp;
2780
2781 switch (args->event) {
2782 case NB_EV_VALIDATE:
2783 case NB_EV_PREPARE:
2784 case NB_EV_ABORT:
2785 break;
2786 case NB_EV_APPLY:
2787 ifp = nb_running_get_entry(args->dnode, NULL, true);
2788 pim_ifp = ifp->info;
2789 if (!pim_ifp)
2790 return NB_ERR_INCONSISTENCY;
2791
2792 query_interval = yang_dnode_get_uint16(args->dnode, NULL);
2793 pim_ifp->gm_default_query_interval = query_interval;
2794 gm_ifp_update(ifp);
2795 }
2796 #endif
2797 return NB_OK;
2798 }
2799
2800 /*
2801 * XPath: /frr-interface:lib/interface/frr-gmp:gmp/address-family/query-max-response-time
2802 */
2803 int lib_interface_gmp_address_family_query_max_response_time_modify(
2804 struct nb_cb_modify_args *args)
2805 {
2806 struct interface *ifp;
2807 int query_max_response_time_dsec;
2808
2809 switch (args->event) {
2810 case NB_EV_VALIDATE:
2811 case NB_EV_PREPARE:
2812 case NB_EV_ABORT:
2813 break;
2814 case NB_EV_APPLY:
2815 ifp = nb_running_get_entry(args->dnode, NULL, true);
2816 query_max_response_time_dsec =
2817 yang_dnode_get_uint16(args->dnode, NULL);
2818 change_query_max_response_time(ifp,
2819 query_max_response_time_dsec);
2820 }
2821
2822 return NB_OK;
2823 }
2824
2825 /*
2826 * XPath: /frr-interface:lib/interface/frr-gmp:gmp/address-family/last-member-query-interval
2827 */
2828 int lib_interface_gmp_address_family_last_member_query_interval_modify(
2829 struct nb_cb_modify_args *args)
2830 {
2831 struct interface *ifp;
2832 struct pim_interface *pim_ifp;
2833 int last_member_query_interval;
2834
2835 switch (args->event) {
2836 case NB_EV_VALIDATE:
2837 case NB_EV_PREPARE:
2838 case NB_EV_ABORT:
2839 break;
2840 case NB_EV_APPLY:
2841 ifp = nb_running_get_entry(args->dnode, NULL, true);
2842 pim_ifp = ifp->info;
2843 last_member_query_interval =
2844 yang_dnode_get_uint16(args->dnode, NULL);
2845 pim_ifp->gm_specific_query_max_response_time_dsec =
2846 last_member_query_interval;
2847 #if PIM_IPV == 6
2848 gm_ifp_update(ifp);
2849 #endif
2850
2851 break;
2852 }
2853
2854 return NB_OK;
2855 }
2856
2857 /*
2858 * XPath: /frr-interface:lib/interface/frr-gmp:gmp/address-family/robustness-variable
2859 */
2860 int lib_interface_gmp_address_family_robustness_variable_modify(
2861 struct nb_cb_modify_args *args)
2862 {
2863 struct interface *ifp;
2864 struct pim_interface *pim_ifp;
2865 int last_member_query_count;
2866
2867 switch (args->event) {
2868 case NB_EV_VALIDATE:
2869 case NB_EV_PREPARE:
2870 case NB_EV_ABORT:
2871 break;
2872 case NB_EV_APPLY:
2873 ifp = nb_running_get_entry(args->dnode, NULL, true);
2874 pim_ifp = ifp->info;
2875 last_member_query_count =
2876 yang_dnode_get_uint8(args->dnode, NULL);
2877 pim_ifp->gm_last_member_query_count = last_member_query_count;
2878 #if PIM_IPV == 6
2879 gm_ifp_update(ifp);
2880 #endif
2881 break;
2882 }
2883
2884 return NB_OK;
2885 }
2886
2887 /*
2888 * XPath: /frr-interface:lib/interface/frr-gmp:gmp/address-family/static-group
2889 */
2890 int lib_interface_gmp_address_family_static_group_create(
2891 struct nb_cb_create_args *args)
2892 {
2893 #if PIM_IPV == 4
2894 struct interface *ifp;
2895 struct ipaddr source_addr;
2896 struct ipaddr group_addr;
2897 int result;
2898 const char *ifp_name;
2899 const struct lyd_node *if_dnode;
2900
2901 switch (args->event) {
2902 case NB_EV_VALIDATE:
2903 if_dnode = yang_dnode_get_parent(args->dnode, "interface");
2904 if (!is_pim_interface(if_dnode)) {
2905 ifp_name = yang_dnode_get_string(if_dnode, "name");
2906 snprintf(args->errmsg, args->errmsg_len,
2907 "multicast not enabled on interface %s",
2908 ifp_name);
2909 return NB_ERR_VALIDATION;
2910 }
2911
2912 yang_dnode_get_ip(&group_addr, args->dnode, "./group-addr");
2913 if (pim_is_group_224_0_0_0_24(group_addr.ip._v4_addr)) {
2914 snprintf(
2915 args->errmsg, args->errmsg_len,
2916 "Groups within 224.0.0.0/24 are reserved and cannot be joined");
2917 return NB_ERR_VALIDATION;
2918 }
2919 break;
2920 case NB_EV_PREPARE:
2921 case NB_EV_ABORT:
2922 break;
2923 case NB_EV_APPLY:
2924 ifp = nb_running_get_entry(args->dnode, NULL, true);
2925 yang_dnode_get_ip(&source_addr, args->dnode, "./source-addr");
2926 yang_dnode_get_ip(&group_addr, args->dnode, "./group-addr");
2927
2928 result = pim_if_igmp_join_add(ifp, group_addr.ip._v4_addr,
2929 source_addr.ip._v4_addr);
2930 if (result) {
2931 snprintf(args->errmsg, args->errmsg_len,
2932 "Failure joining IGMP group");
2933 return NB_ERR_INCONSISTENCY;
2934 }
2935 }
2936 #else
2937 /* TBD Depends on MLD data structure changes */
2938 #endif /* PIM_IPV == 4 */
2939 return NB_OK;
2940 }
2941
2942 int lib_interface_gmp_address_family_static_group_destroy(
2943 struct nb_cb_destroy_args *args)
2944 {
2945 struct interface *ifp;
2946 struct ipaddr source_addr;
2947 struct ipaddr group_addr;
2948 int result;
2949
2950 switch (args->event) {
2951 case NB_EV_VALIDATE:
2952 case NB_EV_PREPARE:
2953 case NB_EV_ABORT:
2954 break;
2955 case NB_EV_APPLY:
2956 ifp = nb_running_get_entry(args->dnode, NULL, true);
2957 yang_dnode_get_ip(&source_addr, args->dnode, "./source-addr");
2958 yang_dnode_get_ip(&group_addr, args->dnode, "./group-addr");
2959
2960 result = pim_if_igmp_join_del(ifp, group_addr.ip._v4_addr,
2961 source_addr.ip._v4_addr);
2962
2963 if (result) {
2964 char src_str[INET_ADDRSTRLEN];
2965 char grp_str[INET_ADDRSTRLEN];
2966
2967 ipaddr2str(&source_addr, src_str, sizeof(src_str));
2968 ipaddr2str(&group_addr, grp_str, sizeof(grp_str));
2969
2970 snprintf(args->errmsg, args->errmsg_len,
2971 "%% Failure leaving IGMP group %s %s on interface %s: %d",
2972 src_str, grp_str, ifp->name, result);
2973
2974 return NB_ERR_INCONSISTENCY;
2975 }
2976
2977 break;
2978 }
2979
2980 return NB_OK;
2981 }