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