diff options
-rw-r--r-- | lib/command.h | 4 | ||||
-rw-r--r-- | lib/lib_vty.c | 54 | ||||
-rw-r--r-- | lib/vty.c | 1 | ||||
-rw-r--r-- | lib/yang.c | 6 | ||||
-rw-r--r-- | lib/yang.h | 5 | ||||
-rw-r--r-- | ospf6d/ospf6_snmp.c | 6 | ||||
-rw-r--r-- | pimd/pim_cmd.c | 2994 | ||||
-rw-r--r-- | pimd/pim_main.c | 9 | ||||
-rw-r--r-- | pimd/pim_nb.c | 417 | ||||
-rw-r--r-- | pimd/pim_nb.h | 203 | ||||
-rw-r--r-- | pimd/pim_nb_config.c | 3034 | ||||
-rw-r--r-- | pimd/pim_rp.c | 33 | ||||
-rw-r--r-- | pimd/pim_rp.h | 2 | ||||
-rw-r--r-- | pimd/subdir.am | 12 | ||||
-rw-r--r-- | sharpd/sharp_main.c | 12 | ||||
-rw-r--r-- | vtysh/vtysh_config.c | 4 | ||||
-rw-r--r-- | yang/frr-igmp.yang | 7 | ||||
-rw-r--r-- | yang/frr-pim.yang | 107 |
18 files changed, 5376 insertions, 1534 deletions
diff --git a/lib/command.h b/lib/command.h index bb007b086..e529239f6 100644 --- a/lib/command.h +++ b/lib/command.h @@ -530,7 +530,9 @@ extern int cmd_execute_command(vector, struct vty *, const struct cmd_element **, int); extern int cmd_execute_command_strict(vector, struct vty *, const struct cmd_element **); -extern void cmd_init(int); +extern void cmd_init(int terminal); +extern void cmd_init_config_callbacks(void (*start_config)(void), + void (*end_config)(void)); extern void cmd_terminate(void); extern void cmd_exit(struct vty *vty); extern int cmd_list_cmds(struct vty *vty, int do_permute); diff --git a/lib/lib_vty.c b/lib/lib_vty.c index 9c927ca4a..8207aa20e 100644 --- a/lib/lib_vty.c +++ b/lib/lib_vty.c @@ -212,6 +212,57 @@ DEFUN (frr_version, return CMD_SUCCESS; } +static struct call_back { + time_t readin_time; + + void (*start_config)(void); + void (*end_config)(void); +} callback; + + +DEFUN_HIDDEN (start_config, + start_config_cmd, + "start_configuration", + "The Beginning of Configuration\n") +{ + callback.readin_time = monotime(NULL); + + if (callback.start_config) + (*callback.start_config)(); + + return CMD_SUCCESS; +} + +DEFUN_HIDDEN (end_config, + end_config_cmd, + "end_configuration", + "The End of Configuration\n") +{ + time_t readin_time; + char readin_time_str[MONOTIME_STRLEN]; + + readin_time = monotime(NULL); + readin_time -= callback.readin_time; + + frrtime_to_interval(readin_time, readin_time_str, + sizeof(readin_time_str)); + + zlog_info("Configuration Read in Took: %s", readin_time_str); + + if (callback.end_config) + (*callback.end_config)(); + + return CMD_SUCCESS; +} + +void cmd_init_config_callbacks(void (*start_config)(void), + void (*end_config)(void)) +{ + callback.start_config = start_config; + callback.end_config = end_config; +} + + static void defaults_autocomplete(vector comps, struct cmd_token *token) { const char **p; @@ -234,6 +285,9 @@ void lib_cmd_init(void) install_element(VIEW_NODE, &show_memory_cmd); install_element(VIEW_NODE, &show_modules_cmd); + + install_element(CONFIG_NODE, &start_config_cmd); + install_element(CONFIG_NODE, &end_config_cmd); } /* Stats querying from users */ @@ -1811,6 +1811,7 @@ static int vty_accept(struct thread *thread) set_cloexec(vty_sock); if (!sockunion2hostprefix(&su, &p)) { + close(vty_sock); zlog_info("Vty unable to convert prefix from sockunion %s", sockunion2str(&su, buf, SU_ADDRSTRLEN)); return -1; diff --git a/lib/yang.c b/lib/yang.c index c59cb642f..22fe938e4 100644 --- a/lib/yang.c +++ b/lib/yang.c @@ -772,8 +772,7 @@ const struct lyd_node *yang_dnode_get_parent(const struct lyd_node *dnode, return NULL; } -/* API to check if the given node is last node in the list */ -static bool yang_is_last_list_dnode(const struct lyd_node *dnode) +bool yang_is_last_list_dnode(const struct lyd_node *dnode) { return (((dnode->next == NULL) || (dnode->next @@ -785,8 +784,7 @@ static bool yang_is_last_list_dnode(const struct lyd_node *dnode) != 0))); } -/* API to check if the given node is last node in the data tree level */ -static bool yang_is_last_level_dnode(const struct lyd_node *dnode) +bool yang_is_last_level_dnode(const struct lyd_node *dnode) { const struct lyd_node *parent; const struct lys_node_list *snode; diff --git a/lib/yang.h b/lib/yang.h index 0cd6a4a6f..b8bf07ee7 100644 --- a/lib/yang.h +++ b/lib/yang.h @@ -587,6 +587,11 @@ extern uint32_t yang_get_list_elements_count(const struct lyd_node *node); /* To get the immediate child of a dnode */ const struct lyd_node *yang_dnode_get_child(const struct lyd_node *dnode); +/* API to check if the given node is last node in the list */ +bool yang_is_last_list_dnode(const struct lyd_node *dnode); + +/* API to check if the given node is last node in the data tree level */ +bool yang_is_last_level_dnode(const struct lyd_node *dnode); #ifdef __cplusplus } diff --git a/ospf6d/ospf6_snmp.c b/ospf6d/ospf6_snmp.c index 1836dc206..51a3bff2a 100644 --- a/ospf6d/ospf6_snmp.c +++ b/ospf6d/ospf6_snmp.c @@ -963,8 +963,6 @@ static uint8_t *ospfv3WwLsdbEntry(struct variable *v, oid *name, size_t *length, else if (v->magic & OSPFv3WWLINKTABLE) { /* We build a sorted list of interfaces */ ifslist = list_new(); - if (!ifslist) - return NULL; ifslist->cmp = (int (*)(void *, void *))if_icmp_func; FOR_ALL_INTERFACES (vrf, iif) listnode_add_sort(ifslist, iif); @@ -993,6 +991,7 @@ static uint8_t *ospfv3WwLsdbEntry(struct variable *v, oid *name, size_t *length, } list_delete_all_node(ifslist); + list_delete(&ifslist); } } @@ -1100,8 +1099,6 @@ static uint8_t *ospfv3IfEntry(struct variable *v, oid *name, size_t *length, } else { /* We build a sorted list of interfaces */ ifslist = list_new(); - if (!ifslist) - return NULL; ifslist->cmp = (int (*)(void *, void *))if_icmp_func; FOR_ALL_INTERFACES (vrf, iif) listnode_add_sort(ifslist, iif); @@ -1121,6 +1118,7 @@ static uint8_t *ospfv3IfEntry(struct variable *v, oid *name, size_t *length, } list_delete_all_node(ifslist); + list_delete(&ifslist); } if (!oi) diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index adf6faef5..81a778fd5 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -64,6 +64,9 @@ #include "pim_mlag.h" #include "bfd.h" #include "pim_bsm.h" +#include "lib/northbound_cli.h" +#include "pim_errors.h" +#include "pim_nb.h" #ifndef VTYSH_EXTRACT_PL #include "pimd/pim_cmd_clippy.c" @@ -101,94 +104,6 @@ static struct vrf *pim_cmd_lookup_vrf(struct vty *vty, struct cmd_token *argv[], return vrf; } -static void pim_if_membership_clear(struct interface *ifp) -{ - struct pim_interface *pim_ifp; - - pim_ifp = ifp->info; - zassert(pim_ifp); - - if (PIM_IF_TEST_PIM(pim_ifp->options) - && PIM_IF_TEST_IGMP(pim_ifp->options)) { - return; - } - - pim_ifchannel_membership_clear(ifp); -} - -/* - When PIM is disabled on interface, IGMPv3 local membership - information is not injected into PIM interface state. - - The function pim_if_membership_refresh() fetches all IGMPv3 local - membership information into PIM. It is intented to be called - whenever PIM is enabled on the interface in order to collect missed - local membership information. - */ -static void pim_if_membership_refresh(struct interface *ifp) -{ - struct pim_interface *pim_ifp; - struct listnode *sock_node; - struct igmp_sock *igmp; - - pim_ifp = ifp->info; - zassert(pim_ifp); - - if (!PIM_IF_TEST_PIM(pim_ifp->options)) - return; - if (!PIM_IF_TEST_IGMP(pim_ifp->options)) - return; - - /* - First clear off membership from all PIM (S,G) entries on the - interface - */ - - pim_ifchannel_membership_clear(ifp); - - /* - Then restore PIM (S,G) membership from all IGMPv3 (S,G) entries on - the interface - */ - - /* scan igmp sockets */ - for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, sock_node, igmp)) { - struct listnode *grpnode; - struct igmp_group *grp; - - /* scan igmp groups */ - for (ALL_LIST_ELEMENTS_RO(igmp->igmp_group_list, grpnode, - grp)) { - struct listnode *srcnode; - struct igmp_source *src; - - /* scan group sources */ - for (ALL_LIST_ELEMENTS_RO(grp->group_source_list, - srcnode, src)) { - - if (IGMP_SOURCE_TEST_FORWARDING( - src->source_flags)) { - struct prefix_sg sg; - - memset(&sg, 0, - sizeof(struct prefix_sg)); - sg.src = src->source_addr; - sg.grp = grp->group_addr; - pim_ifchannel_local_membership_add(ifp, - &sg, false /*is_vxlan*/); - } - - } /* scan group sources */ - } /* scan igmp groups */ - } /* scan igmp sockets */ - - /* - Finally delete every PIM (S,G) entry lacking all state info - */ - - pim_ifchannel_delete_on_noinfo(ifp); -} - static void pim_show_assert_helper(struct vty *vty, struct pim_interface *pim_ifp, struct pim_ifchannel *ch, time_t now) @@ -6797,83 +6712,6 @@ DEFUN (show_ip_ssmpingd, return CMD_SUCCESS; } -static int pim_rp_cmd_worker(struct pim_instance *pim, struct vty *vty, - const char *rp, const char *group, - const char *plist) -{ - int result; - - result = pim_rp_new_config(pim, rp, group, plist); - - if (result == PIM_GROUP_BAD_ADDR_MASK_COMBO) { - vty_out(vty, "%% Inconsistent address and mask: %s\n", - group ? group : "No Group Address"); - return CMD_WARNING_CONFIG_FAILED; - } - - if (result == PIM_GROUP_BAD_ADDRESS) { - vty_out(vty, "%% Bad group address specified: %s\n", - group ? group : "No Group Address"); - return CMD_WARNING_CONFIG_FAILED; - } - - if (result == PIM_RP_BAD_ADDRESS) { - vty_out(vty, "%% Bad RP address specified: %s\n", rp); - return CMD_WARNING_CONFIG_FAILED; - } - - if (result == PIM_RP_NO_PATH) { - vty_out(vty, "%% No Path to RP address specified: %s\n", rp); - return CMD_WARNING; - } - - if (result == PIM_GROUP_OVERLAP) { - vty_out(vty, - "%% Group range specified cannot exact match another\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - if (result == PIM_GROUP_PFXLIST_OVERLAP) { - vty_out(vty, - "%% This group is already covered by a RP prefix-list\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - if (result == PIM_RP_PFXLIST_IN_USE) { - vty_out(vty, - "%% The same prefix-list cannot be applied to multiple RPs\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - return CMD_SUCCESS; -} - -static int pim_cmd_spt_switchover(struct pim_instance *pim, - enum pim_spt_switchover spt, - const char *plist) -{ - pim->spt.switchover = spt; - - switch (pim->spt.switchover) { - case PIM_SPT_IMMEDIATE: - XFREE(MTYPE_PIM_PLIST_NAME, pim->spt.plist); - - pim_upstream_add_lhr_star_pimreg(pim); - break; - case PIM_SPT_INFINITY: - pim_upstream_remove_lhr_star_pimreg(pim, plist); - - XFREE(MTYPE_PIM_PLIST_NAME, pim->spt.plist); - - if (plist) - pim->spt.plist = - XSTRDUP(MTYPE_PIM_PLIST_NAME, plist); - break; - } - - return CMD_SUCCESS; -} - DEFUN (ip_pim_spt_switchover_infinity, ip_pim_spt_switchover_infinity_cmd, "ip pim spt-switchover infinity-and-beyond", @@ -6882,8 +6720,45 @@ DEFUN (ip_pim_spt_switchover_infinity, "SPT-Switchover\n" "Never switch to SPT Tree\n") { - PIM_DECLVAR_CONTEXT(vrf, pim); - return pim_cmd_spt_switchover(pim, PIM_SPT_INFINITY, NULL); + const struct lyd_node *vrf_dnode; + const char *vrfname; + char spt_plist_xpath[XPATH_MAXLEN]; + char spt_action_xpath[XPATH_MAXLEN]; + + if (vty->xpath_index) { + vrf_dnode = + yang_dnode_get(vty->candidate_config->dnode, + VTY_CURR_XPATH); + + if (!vrf_dnode) { + vty_out(vty, + "%% Failed to get vrf dnode in candidate db\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + vrfname = yang_dnode_get_string(vrf_dnode, "./name"); + } else + vrfname = VRF_DEFAULT_NAME; + + snprintf(spt_plist_xpath, sizeof(spt_plist_xpath), + FRR_PIM_AF_XPATH, "frr-pim:pimd", "pim", vrfname, + "frr-routing:ipv4"); + strlcat(spt_plist_xpath, "/spt-switchover/spt-infinity-prefix-list", + sizeof(spt_plist_xpath)); + + snprintf(spt_action_xpath, sizeof(spt_action_xpath), + FRR_PIM_AF_XPATH, "frr-pim:pimd", "pim", vrfname, + "frr-routing:ipv4"); + strlcat(spt_action_xpath, "/spt-switchover/spt-action", + sizeof(spt_action_xpath)); + + if (yang_dnode_exists(vty->candidate_config->dnode, spt_plist_xpath)) + nb_cli_enqueue_change(vty, spt_plist_xpath, NB_OP_DESTROY, + NULL); + nb_cli_enqueue_change(vty, spt_action_xpath, NB_OP_MODIFY, + "PIM_SPT_INFINITY"); + + return nb_cli_apply_changes(vty, NULL); } DEFUN (ip_pim_spt_switchover_infinity_plist, @@ -6896,8 +6771,44 @@ DEFUN (ip_pim_spt_switchover_infinity_plist, "Prefix-List to control which groups to switch\n" "Prefix-List name\n") { - PIM_DECLVAR_CONTEXT(vrf, pim); - return pim_cmd_spt_switchover(pim, PIM_SPT_INFINITY, argv[5]->arg); + const struct lyd_node *vrf_dnode; + const char *vrfname; + char spt_plist_xpath[XPATH_MAXLEN]; + char spt_action_xpath[XPATH_MAXLEN]; + + if (vty->xpath_index) { + vrf_dnode = + yang_dnode_get(vty->candidate_config->dnode, + VTY_CURR_XPATH); + + if (!vrf_dnode) { + vty_out(vty, + "%% Failed to get vrf dnode in candidate db\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + vrfname = yang_dnode_get_string(vrf_dnode, "./name"); + } else + vrfname = VRF_DEFAULT_NAME; + + snprintf(spt_plist_xpath, sizeof(spt_plist_xpath), + FRR_PIM_AF_XPATH, "frr-pim:pimd", "pim", vrfname, + "frr-routing:ipv4"); + strlcat(spt_plist_xpath, "/spt-switchover/spt-infinity-prefix-list", + sizeof(spt_plist_xpath)); + + snprintf(spt_action_xpath, sizeof(spt_action_xpath), + FRR_PIM_AF_XPATH, "frr-pim:pimd", "pim", vrfname, + "frr-routing:ipv4"); + strlcat(spt_action_xpath, "/spt-switchover/spt-action", + sizeof(spt_action_xpath)); + + nb_cli_enqueue_change(vty, spt_action_xpath, NB_OP_MODIFY, + "PIM_SPT_INFINITY"); + nb_cli_enqueue_change(vty, spt_plist_xpath, NB_OP_MODIFY, + argv[5]->arg); + + return nb_cli_apply_changes(vty, NULL); } DEFUN (no_ip_pim_spt_switchover_infinity, @@ -6909,8 +6820,43 @@ DEFUN (no_ip_pim_spt_switchover_infinity, "SPT_Switchover\n" "Never switch to SPT Tree\n") { - PIM_DECLVAR_CONTEXT(vrf, pim); - return pim_cmd_spt_switchover(pim, PIM_SPT_IMMEDIATE, NULL); + const struct lyd_node *vrf_dnode; + const char *vrfname; + char spt_plist_xpath[XPATH_MAXLEN]; + char spt_action_xpath[XPATH_MAXLEN]; + + if (vty->xpath_index) { + vrf_dnode = + yang_dnode_get(vty->candidate_config->dnode, + VTY_CURR_XPATH); + + if (!vrf_dnode) { + vty_out(vty, + "%% Failed to get vrf dnode in candidate db\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + vrfname = yang_dnode_get_string(vrf_dnode, "./name"); + } else + vrfname = VRF_DEFAULT_NAME; + + snprintf(spt_plist_xpath, sizeof(spt_plist_xpath), + FRR_PIM_AF_XPATH, "frr-pim:pimd", "pim", vrfname, + "frr-routing:ipv4"); + strlcat(spt_plist_xpath, "/spt-switchover/spt-infinity-prefix-list", + sizeof(spt_plist_xpath)); + + snprintf(spt_action_xpath, sizeof(spt_action_xpath), + FRR_PIM_AF_XPATH, "frr-pim:pimd", "pim", vrfname, + "frr-routing:ipv4"); + strlcat(spt_action_xpath, "/spt-switchover/spt-action", + sizeof(spt_action_xpath)); + + nb_cli_enqueue_change(vty, spt_plist_xpath, NB_OP_DESTROY, NULL); + nb_cli_enqueue_change(vty, spt_action_xpath, NB_OP_MODIFY, + "PIM_SPT_IMMEDIATE"); + + return nb_cli_apply_changes(vty, NULL); } DEFUN (no_ip_pim_spt_switchover_infinity_plist, @@ -6924,8 +6870,43 @@ DEFUN (no_ip_pim_spt_switchover_infinity_plist, "Prefix-List to control which groups to switch\n" "Prefix-List name\n") { - PIM_DECLVAR_CONTEXT(vrf, pim); - return pim_cmd_spt_switchover(pim, PIM_SPT_IMMEDIATE, NULL); + const struct lyd_node *vrf_dnode; + const char *vrfname; + char spt_plist_xpath[XPATH_MAXLEN]; + char spt_action_xpath[XPATH_MAXLEN]; + + if (vty->xpath_index) { + vrf_dnode = + yang_dnode_get(vty->candidate_config->dnode, + VTY_CURR_XPATH); + + if (!vrf_dnode) { + vty_out(vty, + "%% Failed to get vrf dnode in candidate db\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + vrfname = yang_dnode_get_string(vrf_dnode, "./name"); + } else + vrfname = VRF_DEFAULT_NAME; + + snprintf(spt_plist_xpath, sizeof(spt_plist_xpath), + FRR_PIM_AF_XPATH, "frr-pim:pimd", "pim", vrfname, + "frr-routing:ipv4"); + strlcat(spt_plist_xpath, "/spt-switchover/spt-infinity-prefix-list", + sizeof(spt_plist_xpath)); + + snprintf(spt_action_xpath, sizeof(spt_action_xpath), + FRR_PIM_AF_XPATH, "frr-pim:pimd", "pim", vrfname, + "frr-routing:ipv4"); + strlcat(spt_action_xpath, "/spt-switchover/spt-action", + sizeof(spt_action_xpath)); + + nb_cli_enqueue_change(vty, spt_plist_xpath, NB_OP_DESTROY, NULL); + nb_cli_enqueue_change(vty, spt_action_xpath, NB_OP_MODIFY, + "PIM_SPT_IMMEDIATE"); + + return nb_cli_apply_changes(vty, NULL); } DEFPY (pim_register_accept_list, @@ -6937,15 +6918,37 @@ DEFPY (pim_register_accept_list, "Only accept registers from a specific source prefix list\n" "Prefix-List name\n") { - PIM_DECLVAR_CONTEXT(vrf, pim); + const struct lyd_node *vrf_dnode; + const char *vrfname; + char reg_alist_xpath[XPATH_MAXLEN]; + + if (vty->xpath_index) { + vrf_dnode = + yang_dnode_get(vty->candidate_config->dnode, + VTY_CURR_XPATH); + if (!vrf_dnode) { + vty_out(vty, + "%% Failed to get vrf dnode in candidate db\n"); + return CMD_WARNING_CONFIG_FAILED; + } + vrfname = yang_dnode_get_string(vrf_dnode, "./name"); + } else + vrfname = VRF_DEFAULT_NAME; + + snprintf(reg_alist_xpath, sizeof(reg_alist_xpath), + FRR_PIM_AF_XPATH, "frr-pim:pimd", "pim", vrfname, + "frr-routing:ipv4"); + strlcat(reg_alist_xpath, "/register-accept-list", + sizeof(reg_alist_xpath)); if (no) - XFREE(MTYPE_PIM_PLIST_NAME, pim->register_plist); - else { - XFREE(MTYPE_PIM_PLIST_NAME, pim->register_plist); - pim->register_plist = XSTRDUP(MTYPE_PIM_PLIST_NAME, word); - } - return CMD_SUCCESS; + nb_cli_enqueue_change(vty, reg_alist_xpath, + NB_OP_DESTROY, NULL); + else + nb_cli_enqueue_change(vty, reg_alist_xpath, + NB_OP_MODIFY, word); + + return nb_cli_apply_changes(vty, NULL); } DEFUN (ip_pim_joinprune_time, @@ -6956,9 +6959,10 @@ DEFUN (ip_pim_joinprune_time, "Join Prune Send Interval\n" "Seconds\n") { - PIM_DECLVAR_CONTEXT(vrf, pim); - router->t_periodic = atoi(argv[3]->arg); - return CMD_SUCCESS; + nb_cli_enqueue_change(vty, "/frr-pim:pim/join-prune-interval", + NB_OP_MODIFY, argv[3]->arg); + + return nb_cli_apply_changes(vty, NULL); } DEFUN (no_ip_pim_joinprune_time, @@ -6970,9 +6974,15 @@ DEFUN (no_ip_pim_joinprune_time, "Join Prune Send Interval\n" "Seconds\n") { - PIM_DECLVAR_CONTEXT(vrf, pim); - router->t_periodic = PIM_DEFAULT_T_PERIODIC; - return CMD_SUCCESS; + char jp_default_timer[5]; + + snprintf(jp_default_timer, sizeof(jp_default_timer), "%d", + PIM_DEFAULT_T_PERIODIC); + + nb_cli_enqueue_change(vty, "/frr-pim:pim/join-prune-interval", + NB_OP_MODIFY, jp_default_timer); + + return nb_cli_apply_changes(vty, NULL); } DEFUN (ip_pim_register_suppress, @@ -6983,9 +6993,10 @@ DEFUN (ip_pim_register_suppress, "Register Suppress Timer\n" "Seconds\n") { - PIM_DECLVAR_CONTEXT(vrf, pim); - router->register_suppress_time = atoi(argv[3]->arg); - return CMD_SUCCESS; + nb_cli_enqueue_change(vty, "/frr-pim:pim/register-suppress-time", + NB_OP_MODIFY, argv[3]->arg); + + return nb_cli_apply_changes(vty, NULL); } DEFUN (no_ip_pim_register_suppress, @@ -6997,9 +7008,15 @@ DEFUN (no_ip_pim_register_suppress, "Register Suppress Timer\n" "Seconds\n") { - PIM_DECLVAR_CONTEXT(vrf, pim); - router->register_suppress_time = PIM_REGISTER_SUPPRESSION_TIME_DEFAULT; - return CMD_SUCCESS; + char rs_default_timer[5]; + + snprintf(rs_default_timer, sizeof(rs_default_timer), "%d", + PIM_REGISTER_SUPPRESSION_TIME_DEFAULT); + + nb_cli_enqueue_change(vty, "/frr-pim:pim/register-suppress-time", + NB_OP_MODIFY, rs_default_timer); + + return nb_cli_apply_changes(vty, NULL); } DEFUN (ip_pim_rp_keep_alive, @@ -7011,9 +7028,32 @@ DEFUN (ip_pim_rp_keep_alive, "Keep alive Timer\n" "Seconds\n") { - PIM_DECLVAR_CONTEXT(vrf, pim); - pim->rp_keep_alive_time = atoi(argv[4]->arg); - return CMD_SUCCESS; + const struct lyd_node *vrf_dnode; + const char *vrfname; + char rp_ka_timer_xpath[XPATH_MAXLEN]; + + if (vty->xpath_index) { + vrf_dnode = + yang_dnode_get(vty->candidate_config->dnode, + VTY_CURR_XPATH); + if (!vrf_dnode) { + vty_out(vty, + "%% Failed to get vrf dnode in candidate db\n"); + return CMD_WARNING_CONFIG_FAILED; + } + vrfname = yang_dnode_get_string(vrf_dnode, "./name"); + } else + vrfname = VRF_DEFAULT_NAME; + + snprintf(rp_ka_timer_xpath, sizeof(rp_ka_timer_xpath), + FRR_PIM_XPATH, "frr-pim:pimd", "pim", vrfname); + strlcat(rp_ka_timer_xpath, "/rp-keep-alive-timer", + sizeof(rp_ka_timer_xpath)); + + nb_cli_enqueue_change(vty, rp_ka_timer_xpath, NB_OP_MODIFY, + argv[4]->arg); + + return nb_cli_apply_changes(vty, NULL); } DEFUN (no_ip_pim_rp_keep_alive, @@ -7026,9 +7066,36 @@ DEFUN (no_ip_pim_rp_keep_alive, "Keep alive Timer\n" "Seconds\n") { - PIM_DECLVAR_CONTEXT(vrf, pim); - pim->rp_keep_alive_time = PIM_KEEPALIVE_PERIOD; - return CMD_SUCCESS; + const struct lyd_node *vrf_dnode; + const char *vrfname; + char rp_ka_timer[5]; + char rp_ka_timer_xpath[XPATH_MAXLEN]; + + snprintf(rp_ka_timer, sizeof(rp_ka_timer), "%d", PIM_KEEPALIVE_PERIOD); + + if (vty->xpath_index) { + vrf_dnode = + yang_dnode_get(vty->candidate_config->dnode, + VTY_CURR_XPATH); + if (!vrf_dnode) { + vty_out(vty, + "%% Failed to get vrf dnode in candidate db\n"); + return CMD_WARNING_CONFIG_FAILED; + } + vrfname = yang_dnode_get_string(vrf_dnode, "./name"); + } else + vrfname = VRF_DEFAULT_NAME; + + + snprintf(rp_ka_timer_xpath, sizeof(rp_ka_timer_xpath), + FRR_PIM_XPATH, "frr-pim:pimd", "pim", vrfname); + strlcat(rp_ka_timer_xpath, "/rp-keep-alive-timer", + sizeof(rp_ka_timer_xpath)); + + nb_cli_enqueue_change(vty, rp_ka_timer_xpath, NB_OP_MODIFY, + rp_ka_timer); + + return nb_cli_apply_changes(vty, NULL); } DEFUN (ip_pim_keep_alive, @@ -7039,9 +7106,31 @@ DEFUN (ip_pim_keep_alive, "Keep alive Timer\n" "Seconds\n") { - PIM_DECLVAR_CONTEXT(vrf, pim); - pim->keep_alive_time = atoi(argv[3]->arg); - return CMD_SUCCESS; + const struct lyd_node *vrf_dnode; + const char *vrfname; + char ka_timer_xpath[XPATH_MAXLEN]; + + if (vty->xpath_index) { + vrf_dnode = + yang_dnode_get(vty->candidate_config->dnode, + VTY_CURR_XPATH); + if (!vrf_dnode) { + vty_out(vty, + "%% Failed to get vrf dnode in candidate db\n"); + return CMD_WARNING_CONFIG_FAILED; + } + vrfname = yang_dnode_get_string(vrf_dnode, "./name"); + } else + vrfname = VRF_DEFAULT_NAME; + + snprintf(ka_timer_xpath, sizeof(ka_timer_xpath), FRR_PIM_XPATH, + "frr-pim:pimd", "pim", vrfname); + strlcat(ka_timer_xpath, "/keep-alive-timer", sizeof(ka_timer_xpath)); + + nb_cli_enqueue_change(vty, ka_timer_xpath, NB_OP_MODIFY, + argv[3]->arg); + + return nb_cli_apply_changes(vty, NULL); } DEFUN (no_ip_pim_keep_alive, @@ -7053,9 +7142,34 @@ DEFUN (no_ip_pim_keep_alive, "Keep alive Timer\n" "Seconds\n") { - PIM_DECLVAR_CONTEXT(vrf, pim); - pim->keep_alive_time = PIM_KEEPALIVE_PERIOD; - return CMD_SUCCESS; + const struct lyd_node *vrf_dnode; + const char *vrfname; + char ka_timer[5]; + char ka_timer_xpath[XPATH_MAXLEN]; + + snprintf(ka_timer, sizeof(ka_timer), "%d", PIM_KEEPALIVE_PERIOD); + + if (vty->xpath_index) { + vrf_dnode = + yang_dnode_get(vty->candidate_config->dnode, + VTY_CURR_XPATH); + if (!vrf_dnode) { + vty_out(vty, + "%% Failed to get vrf dnode in candidate db\n"); + return CMD_WARNING_CONFIG_FAILED; + } + vrfname = yang_dnode_get_string(vrf_dnode, "./name"); + } else + vrfname = VRF_DEFAULT_NAME; + + snprintf(ka_timer_xpath, sizeof(ka_timer_xpath), FRR_PIM_XPATH, + "frr-pim:pimd", "pim", vrfname); + strlcat(ka_timer_xpath, "/keep-alive-timer", sizeof(ka_timer_xpath)); + + nb_cli_enqueue_change(vty, ka_timer_xpath, NB_OP_MODIFY, + ka_timer); + + return nb_cli_apply_changes(vty, NULL); } DEFUN (ip_pim_packets, @@ -7066,9 +7180,10 @@ DEFUN (ip_pim_packets, "packets to process at one time per fd\n" "Number of packets\n") { - PIM_DECLVAR_CONTEXT(vrf, pim); - router->packet_process = atoi(argv[3]->arg); - return CMD_SUCCESS; + nb_cli_enqueue_change(vty, "/frr-pim:pim/packets", NB_OP_MODIFY, + argv[3]->arg); + + return nb_cli_apply_changes(vty, NULL); } DEFUN (no_ip_pim_packets, @@ -7080,9 +7195,15 @@ DEFUN (no_ip_pim_packets, "packets to process at one time per fd\n" "Number of packets\n") { - PIM_DECLVAR_CONTEXT(vrf, pim); - router->packet_process = PIM_DEFAULT_PACKET_PROCESS; - return CMD_SUCCESS; + char default_packet[3]; + + snprintf(default_packet, sizeof(default_packet), "%d", + PIM_DEFAULT_PACKET_PROCESS); + + nb_cli_enqueue_change(vty, "/frr-pim:pim/packets", NB_OP_MODIFY, + default_packet); + + return nb_cli_apply_changes(vty, NULL); } DEFPY (igmp_group_watermark, @@ -7121,10 +7242,33 @@ DEFUN (ip_pim_v6_secondary, "pim multicast routing\n" "Send v6 secondary addresses\n") { - PIM_DECLVAR_CONTEXT(vrf, pim); - pim->send_v6_secondary = 1; + const struct lyd_node *vrf_dnode; + const char *vrfname; + char send_v6_secondary_xpath[XPATH_MAXLEN]; - return CMD_SUCCESS; + if (vty->xpath_index) { + vrf_dnode = + yang_dnode_get(vty->candidate_config->dnode, + VTY_CURR_XPATH); + if (!vrf_dnode) { + vty_out(vty, + "%% Failed to get vrf dnode in candidate db\n"); + return CMD_WARNING_CONFIG_FAILED; + } + vrfname = yang_dnode_get_string(vrf_dnode, "./name"); + } else + vrfname = VRF_DEFAULT_NAME; + + snprintf(send_v6_secondary_xpath, sizeof(send_v6_secondary_xpath), + FRR_PIM_AF_XPATH, + "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); + strlcat(send_v6_secondary_xpath, "/send-v6-secondary", + sizeof(send_v6_secondary_xpath)); + + nb_cli_enqueue_change(vty, send_v6_secondary_xpath, NB_OP_MODIFY, + "true"); + + return nb_cli_apply_changes(vty, NULL); } DEFUN (no_ip_pim_v6_secondary, @@ -7135,10 +7279,33 @@ DEFUN (no_ip_pim_v6_secondary, "pim multicast routing\n" "Send v6 secondary addresses\n") { - PIM_DECLVAR_CONTEXT(vrf, pim); - pim->send_v6_secondary = 0; + const struct lyd_node *vrf_dnode; + const char *vrfname; + char send_v6_secondary_xpath[XPATH_MAXLEN]; - return CMD_SUCCESS; + if (vty->xpath_index) { + vrf_dnode = + yang_dnode_get(vty->candidate_config->dnode, + VTY_CURR_XPATH); + if (!vrf_dnode) { + vty_out(vty, + "%% Failed to get vrf dnode in candidate db\n"); + return CMD_WARNING_CONFIG_FAILED; + } + vrfname = yang_dnode_get_string(vrf_dnode, "./name"); + } else + vrfname = VRF_DEFAULT_NAME; + + snprintf(send_v6_secondary_xpath, sizeof(send_v6_secondary_xpath), + FRR_PIM_AF_XPATH, + "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); + strlcat(send_v6_secondary_xpath, "/send-v6-secondary", + sizeof(send_v6_secondary_xpath)); + + nb_cli_enqueue_change(vty, send_v6_secondary_xpath, NB_OP_MODIFY, + "false"); + + return nb_cli_apply_changes(vty, NULL); } DEFUN (ip_pim_rp, @@ -7150,15 +7317,66 @@ DEFUN (ip_pim_rp, "ip address of RP\n" "Group Address range to cover\n") { - PIM_DECLVAR_CONTEXT(vrf, pim); - int idx_ipv4 = 3; + const struct lyd_node *vrf_dnode; + const char *vrfname; + int idx_rp = 3, idx_group = 4; + char rp_group_xpath[XPATH_MAXLEN]; + int result = 0; + struct prefix group; + struct in_addr rp_addr; + const char *group_str = + (argc == 5) ? argv[idx_group]->arg : "224.0.0.0/4"; - if (argc == (idx_ipv4 + 1)) - return pim_rp_cmd_worker(pim, vty, argv[idx_ipv4]->arg, NULL, - NULL); - else - return pim_rp_cmd_worker(pim, vty, argv[idx_ipv4]->arg, - argv[idx_ipv4 + 1]->arg, NULL); + result = str2prefix(group_str, &group); + if (result) { + struct prefix temp; + + prefix_copy(&temp, &group); + apply_mask(&temp); + if (!prefix_same(&group, &temp)) { + vty_out(vty, "%% Inconsistent address and mask: %s\n", + group_str); + return CMD_WARNING_CONFIG_FAILED; + } + } + + if (!result) { + vty_out(vty, "%% Bad group address specified: %s\n", + group_str); + return CMD_WARNING_CONFIG_FAILED; + } + + result = inet_pton(AF_INET, argv[idx_rp]->arg, &rp_addr); + if (result <= 0) { + vty_out(vty, "%% Bad RP address specified: %s\n", + argv[idx_rp]->arg); + return CMD_WARNING_CONFIG_FAILED; + } + + if (vty->xpath_index) { + vrf_dnode = + yang_dnode_get(vty->candidate_config->dnode, + VTY_CURR_XPATH); + + if (!vrf_dnode) { + vty_out(vty, + "%% Failed to get vrf dnode in candidate db\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + vrfname = yang_dnode_get_string(vrf_dnode, "./name"); + } else + vrfname = VRF_DEFAULT_NAME; + + snprintf(rp_group_xpath, sizeof(rp_group_xpath), + FRR_PIM_STATIC_RP_XPATH, + "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4", + argv[idx_rp]->arg); + strlcat(rp_group_xpath, "/group-list", sizeof(rp_group_xpath)); + + nb_cli_enqueue_change(vty, rp_group_xpath, NB_OP_CREATE, group_str); + + return nb_cli_apply_changes(vty, NULL); } DEFUN (ip_pim_rp_prefix_list, @@ -7171,33 +7389,36 @@ DEFUN (ip_pim_rp_prefix_list, "group prefix-list filter\n" "Name of a prefix-list\n") { - PIM_DECLVAR_CONTEXT(vrf, pim); - return pim_rp_cmd_worker(pim, vty, argv[3]->arg, NULL, argv[5]->arg); -} + int idx_rp = 3, idx_plist = 5; + const struct lyd_node *vrf_dnode; + const char *vrfname; + char rp_plist_xpath[XPATH_MAXLEN]; -static int pim_no_rp_cmd_worker(struct pim_instance *pim, struct vty *vty, - const char *rp, const char *group, - const char *plist) -{ - int result = pim_rp_del_config(pim, rp, group, plist); + if (vty->xpath_index) { + vrf_dnode = + yang_dnode_get(vty->candidate_config->dnode, + VTY_CURR_XPATH); - if (result == PIM_GROUP_BAD_ADDRESS) { - vty_out(vty, "%% Bad group address specified: %s\n", - group ? group : "No Group Address"); - return CMD_WARNING_CONFIG_FAILED; - } + if (!vrf_dnode) { + vty_out(vty, + "%% Failed to get vrf dnode in candidate db\n"); + return CMD_WARNING_CONFIG_FAILED; + } - if (result == PIM_RP_BAD_ADDRESS) { - vty_out(vty, "%% Bad RP address specified: %s\n", rp); - return CMD_WARNING_CONFIG_FAILED; - } + vrfname = yang_dnode_get_string(vrf_dnode, "./name"); + } else + vrfname = VRF_DEFAULT_NAME; - if (result == PIM_RP_NOT_FOUND) { - vty_out(vty, "%% Unable to find specified RP\n"); - return CMD_WARNING_CONFIG_FAILED; - } + snprintf(rp_plist_xpath, sizeof(rp_plist_xpath), + FRR_PIM_STATIC_RP_XPATH, + "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4", + argv[idx_rp]->arg); + strlcat(rp_plist_xpath, "/prefix-list", sizeof(rp_plist_xpath)); - return CMD_SUCCESS; + nb_cli_enqueue_change(vty, rp_plist_xpath, NB_OP_MODIFY, + argv[idx_plist]->arg); + + return nb_cli_apply_changes(vty, NULL); } DEFUN (no_ip_pim_rp, @@ -7210,15 +7431,55 @@ DEFUN (no_ip_pim_rp, "ip address of RP\n" "Group Address range to cover\n") { - PIM_DECLVAR_CONTEXT(vrf, pim); - int idx_ipv4 = 4, idx_group = 0; + int idx_rp = 4, idx_group = 5; + const char *group_str = + (argc == 6) ? argv[idx_group]->arg : "224.0.0.0/4"; + char group_xpath[XPATH_MAXLEN]; + char temp_xpath[XPATH_MAXLEN]; + char rp_xpath[XPATH_MAXLEN]; + const struct lyd_node *vrf_dnode; + const char *vrfname; + const struct lyd_node *group_dnode; + + if (vty->xpath_index) { + vrf_dnode = + yang_dnode_get(vty->candidate_config->dnode, + VTY_CURR_XPATH); + + if (!vrf_dnode) { + vty_out(vty, + "%% Failed to get vrf dnode in candidate db\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + vrfname = yang_dnode_get_string(vrf_dnode, "./name"); + } else + vrfname = VRF_DEFAULT_NAME; - if (argv_find(argv, argc, "A.B.C.D/M", &idx_group)) - return pim_no_rp_cmd_worker(pim, vty, argv[idx_ipv4]->arg, - argv[idx_group]->arg, NULL); + snprintf(rp_xpath, sizeof(rp_xpath), FRR_PIM_STATIC_RP_XPATH, + "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4", + argv[idx_rp]->arg); + + snprintf(group_xpath, sizeof(group_xpath), FRR_PIM_STATIC_RP_XPATH, + "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4", + argv[idx_rp]->arg); + snprintf(temp_xpath, sizeof(temp_xpath), "/group-list[.='%s']", + group_str); + strlcat(group_xpath, temp_xpath, sizeof(group_xpath)); + + if (!yang_dnode_exists(vty->candidate_config->dnode, group_xpath)) { + vty_out(vty, "%% Unable to find specified RP\n"); + return NB_OK; + } + + group_dnode = yang_dnode_get(vty->candidate_config->dnode, group_xpath); + + if (yang_is_last_list_dnode(group_dnode)) + nb_cli_enqueue_change(vty, rp_xpath, NB_OP_DESTROY, NULL); else - return pim_no_rp_cmd_worker(pim, vty, argv[idx_ipv4]->arg, NULL, - NULL); + nb_cli_enqueue_change(vty, group_xpath, NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); } DEFUN (no_ip_pim_rp_prefix_list, @@ -7232,32 +7493,52 @@ DEFUN (no_ip_pim_rp_prefix_list, "group prefix-list filter\n" "Name of a prefix-list\n") { - PIM_DECLVAR_CONTEXT(vrf, pim); - return pim_no_rp_cmd_worker(pim, vty, argv[4]->arg, NULL, argv[6]->arg); -} + int idx_rp = 4; + int idx_plist = 6; + char rp_xpath[XPATH_MAXLEN]; + char plist_xpath[XPATH_MAXLEN]; + const struct lyd_node *vrf_dnode; + const char *vrfname; + const struct lyd_node *plist_dnode; + const char *plist; + + if (vty->xpath_index) { + vrf_dnode = + yang_dnode_get(vty->candidate_config->dnode, + VTY_CURR_XPATH); + if (!vrf_dnode) { + vty_out(vty, + "%% Failed to get vrf dnode in candidate db\n"); + return CMD_WARNING_CONFIG_FAILED; + } + vrfname = yang_dnode_get_string(vrf_dnode, "./name"); + } else + vrfname = VRF_DEFAULT_NAME; -static int pim_ssm_cmd_worker(struct pim_instance *pim, struct vty *vty, - const char *plist) -{ - int result = pim_ssm_range_set(pim, pim->vrf_id, plist); - int ret = CMD_WARNING_CONFIG_FAILED; + snprintf(rp_xpath, sizeof(rp_xpath), FRR_PIM_STATIC_RP_XPATH, + "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4", + argv[idx_rp]->arg); - if (result == PIM_SSM_ERR_NONE) - return CMD_SUCCESS; + snprintf(plist_xpath, sizeof(plist_xpath), FRR_PIM_STATIC_RP_XPATH, + "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4", + argv[idx_rp]->arg); + strlcat(plist_xpath, "/prefix-list", sizeof(plist_xpath)); - switch (result) { - case PIM_SSM_ERR_NO_VRF: - vty_out(vty, "%% VRF doesn't exist\n"); - break; - case PIM_SSM_ERR_DUP: - vty_out(vty, "%% duplicate config\n"); - ret = CMD_WARNING; - break; - default: - vty_out(vty, "%% ssm range config failed\n"); + plist_dnode = yang_dnode_get(vty->candidate_config->dnode, plist_xpath); + if (!plist_dnode) { + vty_out(vty, "%% Unable to find specified RP\n"); + return NB_OK; + } + + plist = yang_dnode_get_string(plist_dnode, plist_xpath); + if (strcmp(argv[idx_plist]->arg, plist)) { + vty_out(vty, "%% Unable to find specified RP\n"); + return NB_OK; } - return ret; + nb_cli_enqueue_change(vty, rp_xpath, NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); } DEFUN (ip_pim_ssm_prefix_list, @@ -7269,8 +7550,31 @@ DEFUN (ip_pim_ssm_prefix_list, "group range prefix-list filter\n" "Name of a prefix-list\n") { - PIM_DECLVAR_CONTEXT(vrf, pim); - return pim_ssm_cmd_worker(pim, vty, argv[4]->arg); + const struct lyd_node *vrf_dnode; + const char *vrfname; + char ssm_plist_xpath[XPATH_MAXLEN]; + + if (vty->xpath_index) { + vrf_dnode = + yang_dnode_get(vty->candidate_config->dnode, + VTY_CURR_XPATH); + if (!vrf_dnode) { + vty_out(vty, + "%% Failed to get vrf dnode in candidate db\n"); + return CMD_WARNING_CONFIG_FAILED; + } + vrfname = yang_dnode_get_string(vrf_dnode, "./name"); + } else + vrfname = VRF_DEFAULT_NAME; + + snprintf(ssm_plist_xpath, sizeof(ssm_plist_xpath), + FRR_PIM_AF_XPATH, + "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); + strlcat(ssm_plist_xpath, "/ssm-prefix-list", sizeof(ssm_plist_xpath)); + + nb_cli_enqueue_change(vty, ssm_plist_xpath, NB_OP_MODIFY, argv[4]->arg); + + return nb_cli_apply_changes(vty, NULL); } DEFUN (no_ip_pim_ssm_prefix_list, @@ -7282,8 +7586,31 @@ DEFUN (no_ip_pim_ssm_prefix_list, "Source Specific Multicast\n" "group range prefix-list filter\n") { - PIM_DECLVAR_CONTEXT(vrf, pim); - return pim_ssm_cmd_worker(pim, vty, NULL); + const struct lyd_node *vrf_dnode; + const char *vrfname; + char ssm_plist_xpath[XPATH_MAXLEN]; + + if (vty->xpath_index) { + vrf_dnode = + yang_dnode_get(vty->candidate_config->dnode, + VTY_CURR_XPATH); + if (!vrf_dnode) { + vty_out(vty, + "%% Failed to get vrf dnode in candidate db\n"); + return CMD_WARNING_CONFIG_FAILED; + } + vrfname = yang_dnode_get_string(vrf_dnode, "./name"); + } else + vrfname = VRF_DEFAULT_NAME; + + snprintf(ssm_plist_xpath, sizeof(ssm_plist_xpath), + FRR_PIM_AF_XPATH, + "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); + strlcat(ssm_plist_xpath, "/ssm-prefix-list", sizeof(ssm_plist_xpath)); + + nb_cli_enqueue_change(vty, ssm_plist_xpath, NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); } DEFUN (no_ip_pim_ssm_prefix_list_name, @@ -7296,11 +7623,50 @@ DEFUN (no_ip_pim_ssm_prefix_list_name, "group range prefix-list filter\n" "Name of a prefix-list\n") { - PIM_DECLVAR_CONTEXT(vrf, pim); - struct pim_ssm *ssm = pim->ssm_info; + const struct lyd_node *vrf_dnode; + const char *vrfname; + const struct lyd_node *ssm_plist_dnode; + char ssm_plist_xpath[XPATH_MAXLEN]; + const char *ssm_plist_name; + + if (vty->xpath_index) { + vrf_dnode = + yang_dnode_get(vty->candidate_config->dnode, + VTY_CURR_XPATH); + + if (!vrf_dnode) { + vty_out(vty, + "%% Failed to get vrf dnode in candidate db\n"); + return CMD_WARNING_CONFIG_FAILED; + } - if (ssm->plist_name && !strcmp(ssm->plist_name, argv[5]->arg)) - return pim_ssm_cmd_worker(pim, vty, NULL); + vrfname = yang_dnode_get_string(vrf_dnode, "./name"); + } else + vrfname = VRF_DEFAULT_NAME; + + + snprintf(ssm_plist_xpath, sizeof(ssm_plist_xpath), + FRR_PIM_AF_XPATH, + "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); + strlcat(ssm_plist_xpath, "/ssm-prefix-list", sizeof(ssm_plist_xpath)); + ssm_plist_dnode = yang_dnode_get(vty->candidate_config->dnode, + ssm_plist_xpath); + + if (!ssm_plist_dnode) { + vty_out(vty, + "%% pim ssm prefix-list %s doesn't exist\n", + argv[5]->arg); + return CMD_WARNING_CONFIG_FAILED; + } + + ssm_plist_name = yang_dnode_get_string(ssm_plist_dnode, "."); + + if (ssm_plist_name && !strcmp(ssm_plist_name, argv[5]->arg)) { + nb_cli_enqueue_change(vty, ssm_plist_xpath, NB_OP_DESTROY, + NULL); + + return nb_cli_apply_changes(vty, NULL); + } vty_out(vty, "%% pim ssm prefix-list %s doesn't exist\n", argv[5]->arg); @@ -7429,27 +7795,35 @@ DEFUN (ip_ssmpingd, CONF_SSMPINGD_STR "Source address\n") { - PIM_DECLVAR_CONTEXT(vrf, pim); int idx_ipv4 = 2; - int result; - struct in_addr source_addr; const char *source_str = (argc == 3) ? argv[idx_ipv4]->arg : "0.0.0.0"; + const struct lyd_node *vrf_dnode; + const char *vrfname; + char ssmpingd_ip_xpath[XPATH_MAXLEN]; + + if (vty->xpath_index) { + vrf_dnode = + yang_dnode_get(vty->candidate_config->dnode, + VTY_CURR_XPATH); + if (!vrf_dnode) { + vty_out(vty, + "%% Failed to get vrf dnode in candidate db\n"); + return CMD_WARNING_CONFIG_FAILED; + } + vrfname = yang_dnode_get_string(vrf_dnode, "./name"); + } else + vrfname = VRF_DEFAULT_NAME; - result = inet_pton(AF_INET, source_str, &source_addr); - if (result <= 0) { - vty_out(vty, "%% Bad source address %s: errno=%d: %s\n", - source_str, errno, safe_strerror(errno)); - return CMD_WARNING_CONFIG_FAILED; - } + snprintf(ssmpingd_ip_xpath, sizeof(ssmpingd_ip_xpath), + FRR_PIM_AF_XPATH, + "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); + strlcat(ssmpingd_ip_xpath, "/ssm-pingd-source-ip", + sizeof(ssmpingd_ip_xpath)); - result = pim_ssmpingd_start(pim, source_addr); - if (result) { - vty_out(vty, "%% Failure starting ssmpingd for source %s: %d\n", - source_str, result); - return CMD_WARNING_CONFIG_FAILED; - } + nb_cli_enqueue_change(vty, ssmpingd_ip_xpath, NB_OP_CREATE, + source_str); - return CMD_SUCCESS; + return nb_cli_apply_changes(vty, NULL); } DEFUN (no_ip_ssmpingd, @@ -7460,27 +7834,35 @@ DEFUN (no_ip_ssmpingd, CONF_SSMPINGD_STR "Source address\n") { - PIM_DECLVAR_CONTEXT(vrf, pim); + const struct lyd_node *vrf_dnode; + const char *vrfname; int idx_ipv4 = 3; - int result; - struct in_addr source_addr; const char *source_str = (argc == 4) ? argv[idx_ipv4]->arg : "0.0.0.0"; + char ssmpingd_ip_xpath[XPATH_MAXLEN]; - result = inet_pton(AF_INET, source_str, &source_addr); - if (result <= 0) { - vty_out(vty, "%% Bad source address %s: errno=%d: %s\n", - source_str, errno, safe_strerror(errno)); - return CMD_WARNING_CONFIG_FAILED; - } + if (vty->xpath_index) { + vrf_dnode = + yang_dnode_get(vty->candidate_config->dnode, + VTY_CURR_XPATH); + if (!vrf_dnode) { + vty_out(vty, + "%% Failed to get vrf dnode in candidate db\n"); + return CMD_WARNING_CONFIG_FAILED; + } + vrfname = yang_dnode_get_string(vrf_dnode, "./name"); + } else + vrfname = VRF_DEFAULT_NAME; - result = pim_ssmpingd_stop(pim, source_addr); - if (result) { - vty_out(vty, "%% Failure stopping ssmpingd for source %s: %d\n", - source_str, result); - return CMD_WARNING_CONFIG_FAILED; - } + snprintf(ssmpingd_ip_xpath, sizeof(ssmpingd_ip_xpath), + FRR_PIM_AF_XPATH, + "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); + strlcat(ssmpingd_ip_xpath, "/ssm-pingd-source-ip", + sizeof(ssmpingd_ip_xpath)); - return CMD_SUCCESS; + nb_cli_enqueue_change(vty, ssmpingd_ip_xpath, NB_OP_DESTROY, + source_str); + + return nb_cli_apply_changes(vty, NULL); } DEFUN (ip_pim_ecmp, @@ -7490,10 +7872,29 @@ DEFUN (ip_pim_ecmp, "pim multicast routing\n" "Enable PIM ECMP \n") { - PIM_DECLVAR_CONTEXT(vrf, pim); - pim->ecmp_enable = true; + const struct lyd_node *vrf_dnode; + const char *vrfname; + char ecmp_xpath[XPATH_MAXLEN]; - return CMD_SUCCESS; + if (vty->xpath_index) { + vrf_dnode = + yang_dnode_get(vty->candidate_config->dnode, + VTY_CURR_XPATH); + if (!vrf_dnode) { + vty_out(vty, + "%% Failed to get vrf dnode in candidate db\n"); + return CMD_WARNING_CONFIG_FAILED; + } + vrfname = yang_dnode_get_string(vrf_dnode, "./name"); + } else + vrfname = VRF_DEFAULT_NAME; + + snprintf(ecmp_xpath, sizeof(ecmp_xpath), FRR_PIM_XPATH, + "frr-pim:pimd", "pim", vrfname); + strlcat(ecmp_xpath, "/ecmp", sizeof(ecmp_xpath)); + + nb_cli_enqueue_change(vty, ecmp_xpath, NB_OP_MODIFY, "true"); + return nb_cli_apply_changes(vty, NULL); } DEFUN (no_ip_pim_ecmp, @@ -7504,10 +7905,30 @@ DEFUN (no_ip_pim_ecmp, "pim multicast routing\n" "Disable PIM ECMP \n") { - PIM_DECLVAR_CONTEXT(vrf, pim); - pim->ecmp_enable = false; + const struct lyd_node *vrf_dnode; + const char *vrfname; + char ecmp_xpath[XPATH_MAXLEN]; - return CMD_SUCCESS; + if (vty->xpath_index) { + vrf_dnode = + yang_dnode_get(vty->candidate_config->dnode, + VTY_CURR_XPATH); + if (!vrf_dnode) { + vty_out(vty, + "%% Failed to get vrf dnode in candidate db\n"); + return CMD_WARNING_CONFIG_FAILED; + } + vrfname = yang_dnode_get_string(vrf_dnode, "./name"); + } else + vrfname = VRF_DEFAULT_NAME; + + snprintf(ecmp_xpath, sizeof(ecmp_xpath), FRR_PIM_XPATH, + "frr-pim:pimd", "pim", vrfname); + strlcat(ecmp_xpath, "/ecmp", sizeof(ecmp_xpath)); + + nb_cli_enqueue_change(vty, ecmp_xpath, NB_OP_MODIFY, "false"); + + return nb_cli_apply_changes(vty, NULL); } DEFUN (ip_pim_ecmp_rebalance, @@ -7518,11 +7939,37 @@ DEFUN (ip_pim_ecmp_rebalance, "Enable PIM ECMP \n" "Enable PIM ECMP Rebalance\n") { - PIM_DECLVAR_CONTEXT(vrf, pim); - pim->ecmp_enable = true; - pim->ecmp_rebalance_enable = true; + const struct lyd_node *vrf_dnode; + const char *vrfname; + char ecmp_xpath[XPATH_MAXLEN]; + char ecmp_rebalance_xpath[XPATH_MAXLEN]; - return CMD_SUCCESS; + if (vty->xpath_index) { + vrf_dnode = + yang_dnode_get(vty->candidate_config->dnode, + VTY_CURR_XPATH); + if (!vrf_dnode) { + vty_out(vty, + "%% Failed to get vrf dnode in candidate db\n"); + return CMD_WARNING_CONFIG_FAILED; + } + vrfname = yang_dnode_get_string(vrf_dnode, "./name"); + } else + vrfname = VRF_DEFAULT_NAME; + + snprintf(ecmp_xpath, sizeof(ecmp_xpath), FRR_PIM_XPATH, + "frr-pim:pimd", "pim", vrfname); + strlcat(ecmp_xpath, "/ecmp", sizeof(ecmp_xpath)); + snprintf(ecmp_rebalance_xpath, sizeof(ecmp_rebalance_xpath), + FRR_PIM_XPATH, + "frr-pim:pimd", "pim", vrfname); + strlcat(ecmp_rebalance_xpath, "/ecmp-rebalance", + sizeof(ecmp_rebalance_xpath)); + + nb_cli_enqueue_change(vty, ecmp_xpath, NB_OP_MODIFY, "true"); + nb_cli_enqueue_change(vty, ecmp_rebalance_xpath, NB_OP_MODIFY, "true"); + + return nb_cli_apply_changes(vty, NULL); } DEFUN (no_ip_pim_ecmp_rebalance, @@ -7534,46 +7981,32 @@ DEFUN (no_ip_pim_ecmp_rebalance, "Disable PIM ECMP \n" "Disable PIM ECMP Rebalance\n") { - PIM_DECLVAR_CONTEXT(vrf, pim); - pim->ecmp_rebalance_enable = false; - - return CMD_SUCCESS; -} + const struct lyd_node *vrf_dnode; + const char *vrfname; + char ecmp_rebalance_xpath[XPATH_MAXLEN]; -static int pim_cmd_igmp_start(struct vty *vty, struct interface *ifp) -{ - struct pim_interface *pim_ifp; - struct pim_instance *pim; - uint8_t need_startup = 0; - - pim_ifp = ifp->info; - - if (!pim_ifp) { - pim = pim_get_pim_instance(ifp->vrf_id); - /* Limit mcast interfaces to number of vifs available */ - if (pim->mcast_if_count == MAXVIFS) { + if (vty->xpath_index) { + vrf_dnode = + yang_dnode_get(vty->candidate_config->dnode, + VTY_CURR_XPATH); + if (!vrf_dnode) { vty_out(vty, - "Max multicast interfaces(%d) Reached. Could not enable IGMP on interface %s\n", - MAXVIFS, ifp->name); + "%% Failed to get vrf dnode in candidate db\n"); return CMD_WARNING_CONFIG_FAILED; } - (void)pim_if_new(ifp, true, false, false, false); - need_startup = 1; - } else { - if (!PIM_IF_TEST_IGMP(pim_ifp->options)) { - PIM_IF_DO_IGMP(pim_ifp->options); - need_startup = 1; - } - } + vrfname = yang_dnode_get_string(vrf_dnode, "./name"); + } else + vrfname = VRF_DEFAULT_NAME; - /* 'ip igmp' executed multiple times, with need_startup - avoid multiple if add all and membership refresh */ - if (need_startup) { - pim_if_addr_add_all(ifp); - pim_if_membership_refresh(ifp); - } + snprintf(ecmp_rebalance_xpath, sizeof(ecmp_rebalance_xpath), + FRR_PIM_XPATH, + "frr-pim:pimd", "pim", vrfname); + strlcat(ecmp_rebalance_xpath, "/ecmp-rebalance", + sizeof(ecmp_rebalance_xpath)); - return CMD_SUCCESS; + nb_cli_enqueue_change(vty, ecmp_rebalance_xpath, NB_OP_MODIFY, "false"); + + return nb_cli_apply_changes(vty, NULL); } DEFUN (interface_ip_igmp, @@ -7582,9 +8015,9 @@ DEFUN (interface_ip_igmp, IP_STR IFACE_IGMP_STR) { - VTY_DECLVAR_CONTEXT(interface, ifp); + nb_cli_enqueue_change(vty, "./igmp-enable", NB_OP_MODIFY, "true"); - return pim_cmd_igmp_start(vty, ifp); + return nb_cli_apply_changes(vty, "./frr-igmp:igmp"); } DEFUN (interface_no_ip_igmp, @@ -7594,23 +8027,28 @@ DEFUN (interface_no_ip_igmp, IP_STR IFACE_IGMP_STR) { - VTY_DECLVAR_CONTEXT(interface, ifp); - struct pim_interface *pim_ifp = ifp->info; - - if (!pim_ifp) - return CMD_SUCCESS; - - PIM_IF_DONT_IGMP(pim_ifp->options); + const struct lyd_node *pim_enable_dnode; + char pim_if_xpath[XPATH_MAXLEN]; - pim_if_membership_clear(ifp); + snprintf(pim_if_xpath, sizeof(pim_if_xpath), + "%s/frr-pim:pim", VTY_CURR_XPATH); - pim_if_addr_del_all_igmp(ifp); - - if (!PIM_IF_TEST_PIM(pim_ifp->options)) { - pim_if_delete(ifp); + pim_enable_dnode = yang_dnode_get(vty->candidate_config->dnode, + "%s/pim-enable", pim_if_xpath); + if (!pim_enable_dnode) { + nb_cli_enqueue_change(vty, pim_if_xpath, NB_OP_DESTROY, NULL); + nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); + } else { + if (!yang_dnode_get_bool(pim_enable_dnode, ".")) { + nb_cli_enqueue_change(vty, pim_if_xpath, NB_OP_DESTROY, + NULL); + nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); + } else + nb_cli_enqueue_change(vty, "./igmp-enable", + NB_OP_MODIFY, "false"); } - return CMD_SUCCESS; + return nb_cli_apply_changes(vty, "./frr-igmp:igmp"); } DEFUN (interface_ip_igmp_join, @@ -7622,46 +8060,28 @@ DEFUN (interface_ip_igmp_join, "Multicast group address\n" "Source address\n") { - VTY_DECLVAR_CONTEXT(interface, ifp); - int idx_ipv4 = 3; - int idx_ipv4_2 = 4; - const char *group_str; + int idx_group = 3; + int idx_source = 4; const char *source_str; - struct in_addr group_addr; - struct in_addr source_addr; - int result; + char xpath[XPATH_MAXLEN]; - /* Group address */ - group_str = argv[idx_ipv4]->arg; - result = inet_pton(AF_INET, group_str, &group_addr); - if (result <= 0) { - vty_out(vty, "Bad group address %s: errno=%d: %s\n", group_str, - errno, safe_strerror(errno)); - return CMD_WARNING_CONFIG_FAILED; - } + if (argc == 5) { + source_str = argv[idx_source]->arg; - /* Source address */ - if (argc == (idx_ipv4_2 + 1)) { - source_str = argv[idx_ipv4_2]->arg; - result = inet_pton(AF_INET, source_str, &source_addr); - if (result <= 0) { - vty_out(vty, "Bad source address %s: errno=%d: %s\n", - source_str, errno, safe_strerror(errno)); - return CMD_WARNING_CONFIG_FAILED; - } - /* Reject 0.0.0.0. Reserved for any source. */ - if (source_addr.s_addr == INADDR_ANY) { - vty_out(vty, "Bad source address %s\n", source_str); + if (strcmp(source_str, "0.0.0.0") == 0) { + vty_out(vty, "Bad source address %s\n", + argv[idx_source]->arg); return CMD_WARNING_CONFIG_FAILED; } - } else { - source_addr.s_addr = INADDR_ANY; - } + } else + source_str = "0.0.0.0"; - CMD_FERR_RETURN(pim_if_igmp_join_add(ifp, group_addr, source_addr), - "Failure joining IGMP group: $ERR"); + snprintf(xpath, sizeof(xpath), FRR_IGMP_JOIN_XPATH, + "frr-routing:ipv4", argv[idx_group]->arg, source_str); - return CMD_SUCCESS; + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + + return nb_cli_apply_changes(vty, NULL); } DEFUN (interface_no_ip_igmp_join, @@ -7674,190 +8094,30 @@ DEFUN (interface_no_ip_igmp_join, "Multicast group address\n" "Source address\n") { - VTY_DECLVAR_CONTEXT(interface, ifp); - int idx_ipv4 = 4; - int idx_ipv4_2 = 5; - const char *group_str; + int idx_group = 4; + int idx_source = 5; const char *source_str; - struct in_addr group_addr; - struct in_addr source_addr; - int result; + char xpath[XPATH_MAXLEN]; - /* Group address */ - group_str = argv[idx_ipv4]->arg; - result = inet_pton(AF_INET, group_str, &group_addr); - if (result <= 0) { - vty_out(vty, "Bad group address %s: errno=%d: %s\n", group_str, - errno, safe_strerror(errno)); - return CMD_WARNING_CONFIG_FAILED; - } + if (argc == 6) { + source_str = argv[idx_source]->arg; - /* Source address */ - if (argc == (idx_ipv4_2 + 1)) { - source_str = argv[idx_ipv4_2]->arg; - result = inet_pton(AF_INET, source_str, &source_addr); - if (result <= 0) { - vty_out(vty, "Bad source address %s: errno=%d: %s\n", - source_str, errno, safe_strerror(errno)); - return CMD_WARNING_CONFIG_FAILED; - } - /* Reject 0.0.0.0. Reserved for any source. */ - if (source_addr.s_addr == INADDR_ANY) { - vty_out(vty, "Bad source address %s\n", source_str); + if (strcmp(source_str, "0.0.0.0") == 0) { + vty_out(vty, "Bad source address %s\n", + argv[idx_source]->arg); return CMD_WARNING_CONFIG_FAILED; } - } else { - source_str = "*"; - source_addr.s_addr = INADDR_ANY; - } - - result = pim_if_igmp_join_del(ifp, group_addr, source_addr); - if (result) { - vty_out(vty, - "%% Failure leaving IGMP group %s source %s on interface %s: %d\n", - group_str, source_str, ifp->name, result); - return CMD_WARNING_CONFIG_FAILED; - } - - return CMD_SUCCESS; -} - -/* - CLI reconfiguration affects the interface level (struct pim_interface). - This function propagates the reconfiguration to every active socket - for that interface. - */ -static void igmp_sock_query_interval_reconfig(struct igmp_sock *igmp) -{ - struct interface *ifp; - struct pim_interface *pim_ifp; - - zassert(igmp); - - /* other querier present? */ - - if (igmp->t_other_querier_timer) - return; - - /* this is the querier */ - - zassert(igmp->interface); - zassert(igmp->interface->info); - - ifp = igmp->interface; - pim_ifp = ifp->info; - - if (PIM_DEBUG_IGMP_TRACE) { - char ifaddr_str[INET_ADDRSTRLEN]; - pim_inet4_dump("<ifaddr?>", igmp->ifaddr, ifaddr_str, - sizeof(ifaddr_str)); - zlog_debug("%s: Querier %s on %s reconfig query_interval=%d", - __func__, ifaddr_str, ifp->name, - pim_ifp->igmp_default_query_interval); - } - - /* - igmp_startup_mode_on() will reset QQI: - - igmp->querier_query_interval = pim_ifp->igmp_default_query_interval; - */ - igmp_startup_mode_on(igmp); -} - -static void igmp_sock_query_reschedule(struct igmp_sock *igmp) -{ - if (igmp->mtrace_only) - return; - - if (igmp->t_igmp_query_timer) { - /* other querier present */ - zassert(igmp->t_igmp_query_timer); - zassert(!igmp->t_other_querier_timer); - - pim_igmp_general_query_off(igmp); - pim_igmp_general_query_on(igmp); - - zassert(igmp->t_igmp_query_timer); - zassert(!igmp->t_other_querier_timer); - } else { - /* this is the querier */ - - zassert(!igmp->t_igmp_query_timer); - zassert(igmp->t_other_querier_timer); - - pim_igmp_other_querier_timer_off(igmp); - pim_igmp_other_querier_timer_on(igmp); - - zassert(!igmp->t_igmp_query_timer); - zassert(igmp->t_other_querier_timer); - } -} - -static void change_query_interval(struct pim_interface *pim_ifp, - int query_interval) -{ - struct listnode *sock_node; - struct igmp_sock *igmp; - - pim_ifp->igmp_default_query_interval = query_interval; - - for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, sock_node, igmp)) { - igmp_sock_query_interval_reconfig(igmp); - igmp_sock_query_reschedule(igmp); - } -} - -static void change_query_max_response_time(struct pim_interface *pim_ifp, - int query_max_response_time_dsec) -{ - struct listnode *sock_node; - struct igmp_sock *igmp; - - pim_ifp->igmp_query_max_response_time_dsec = - query_max_response_time_dsec; - - /* - Below we modify socket/group/source timers in order to quickly - reflect the change. Otherwise, those timers would eventually catch - up. - */ - - /* scan all sockets */ - for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, sock_node, igmp)) { - struct listnode *grp_node; - struct igmp_group *grp; - - /* reschedule socket general query */ - igmp_sock_query_reschedule(igmp); - - /* scan socket groups */ - for (ALL_LIST_ELEMENTS_RO(igmp->igmp_group_list, grp_node, - grp)) { - struct listnode *src_node; - struct igmp_source *src; + } else + source_str = "0.0.0.0"; - /* reset group timers for groups in EXCLUDE mode */ - if (grp->group_filtermode_isexcl) { - igmp_group_reset_gmi(grp); - } + snprintf(xpath, sizeof(xpath), FRR_IGMP_JOIN_XPATH, + "frr-routing:ipv4", argv[idx_group]->arg, source_str); - /* scan group sources */ - for (ALL_LIST_ELEMENTS_RO(grp->group_source_list, - src_node, src)) { + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); - /* reset source timers for sources with running - * timers */ - if (src->t_source_timer) { - igmp_source_reset_gmi(igmp, grp, src); - } - } - } - } + return nb_cli_apply_changes(vty, NULL); } -#define IGMP_QUERY_INTERVAL_MIN (1) -#define IGMP_QUERY_INTERVAL_MAX (1800) - DEFUN (interface_ip_igmp_query_interval, interface_ip_igmp_query_interval_cmd, "ip igmp query-interval (1-1800)", @@ -7866,50 +8126,24 @@ DEFUN (interface_ip_igmp_query_interval, IFACE_IGMP_QUERY_INTERVAL_STR "Query interval in seconds\n") { - VTY_DECLVAR_CONTEXT(interface, ifp); - struct pim_interface *pim_ifp = ifp->info; - int query_interval; - int query_interval_dsec; - int ret; - - if (!pim_ifp) { - ret = pim_cmd_igmp_start(vty, ifp); - if (ret != CMD_SUCCESS) - return ret; - pim_ifp = ifp->info; - } - - query_interval = atoi(argv[3]->arg); - query_interval_dsec = 10 * query_interval; + const struct lyd_node *pim_enable_dnode; - /* - It seems we don't need to check bounds since command.c does it - already, but we verify them anyway for extra safety. - */ - if (query_interval < IGMP_QUERY_INTERVAL_MIN) { - vty_out(vty, - "General query interval %d lower than minimum %d\n", - query_interval, IGMP_QUERY_INTERVAL_MIN); - return CMD_WARNING_CONFIG_FAILED; - } - if (query_interval > IGMP_QUERY_INTERVAL_MAX) { - vty_out(vty, - "General query interval %d higher than maximum %d\n", - query_interval, IGMP_QUERY_INTERVAL_MAX); - return CMD_WARNING_CONFIG_FAILED; - } - - if (query_interval_dsec <= pim_ifp->igmp_query_max_response_time_dsec) { - vty_out(vty, - "Can't set general query interval %d dsec <= query max response time %d dsec.\n", - query_interval_dsec, - pim_ifp->igmp_query_max_response_time_dsec); - return CMD_WARNING_CONFIG_FAILED; + pim_enable_dnode = yang_dnode_get(vty->candidate_config->dnode, + "%s/frr-pim:pim/pim-enable", + VTY_CURR_XPATH); + if (!pim_enable_dnode) { + nb_cli_enqueue_change(vty, "./igmp-enable", NB_OP_MODIFY, + "true"); + } else { + if (!yang_dnode_get_bool(pim_enable_dnode, ".")) + nb_cli_enqueue_change(vty, "./igmp-enable", + NB_OP_MODIFY, "true"); } - change_query_interval(pim_ifp, query_interval); + nb_cli_enqueue_change(vty, "./query-interval", NB_OP_MODIFY, + argv[3]->arg); - return CMD_SUCCESS; + return nb_cli_apply_changes(vty, "./frr-igmp:igmp"); } DEFUN (interface_no_ip_igmp_query_interval, @@ -7920,27 +8154,15 @@ DEFUN (interface_no_ip_igmp_query_interval, IFACE_IGMP_STR IFACE_IGMP_QUERY_INTERVAL_STR) { - VTY_DECLVAR_CONTEXT(interface, ifp); - struct pim_interface *pim_ifp = ifp->info; - int default_query_interval_dsec; - - if (!pim_ifp) - return CMD_SUCCESS; + char default_query_interval[5]; - default_query_interval_dsec = IGMP_GENERAL_QUERY_INTERVAL * 10; + snprintf(default_query_interval, sizeof(default_query_interval), "%d", + IGMP_GENERAL_QUERY_INTERVAL); - if (default_query_interval_dsec - <= pim_ifp->igmp_query_max_response_time_dsec) { - vty_out(vty, - "Can't set default general query interval %d dsec <= query max response time %d dsec.\n", - default_query_interval_dsec, - pim_ifp->igmp_query_max_response_time_dsec); - return CMD_WARNING_CONFIG_FAILED; - } + nb_cli_enqueue_change(vty, "./query-interval", NB_OP_MODIFY, + default_query_interval); - change_query_interval(pim_ifp, IGMP_GENERAL_QUERY_INTERVAL); - - return CMD_SUCCESS; + return nb_cli_apply_changes(vty, "./frr-igmp:igmp"); } DEFUN (interface_ip_igmp_version, @@ -7951,36 +8173,11 @@ DEFUN (interface_ip_igmp_version, "IGMP version\n" "IGMP version number\n") { - VTY_DECLVAR_CONTEXT(interface, ifp); - struct pim_interface *pim_ifp = ifp->info; - int igmp_version, old_version = 0; - int ret; - - if (!pim_ifp) { - ret = pim_cmd_igmp_start(vty, ifp); - if (ret != CMD_SUCCESS) - return ret; - pim_ifp = ifp->info; - } + nb_cli_enqueue_change(vty, "./igmp-enable", NB_OP_MODIFY, + "true"); + nb_cli_enqueue_change(vty, "./version", NB_OP_MODIFY, argv[3]->arg); - igmp_version = atoi(argv[3]->arg); - old_version = pim_ifp->igmp_version; - pim_ifp->igmp_version = igmp_version; - - // Check if IGMP is Enabled otherwise, enable on interface - if (!PIM_IF_TEST_IGMP(pim_ifp->options)) { - PIM_IF_DO_IGMP(pim_ifp->options); - pim_if_addr_add_all(ifp); - pim_if_membership_refresh(ifp); - old_version = igmp_version; - // avoid refreshing membership again. - } - /* Current and new version is different refresh existing - membership. Going from 3 -> 2 or 2 -> 3. */ - if (old_version != igmp_version) - pim_if_membership_refresh(ifp); - - return CMD_SUCCESS; + return nb_cli_apply_changes(vty, "./frr-igmp:igmp"); } DEFUN (interface_no_ip_igmp_version, @@ -7992,20 +8189,11 @@ DEFUN (interface_no_ip_igmp_version, "IGMP version\n" "IGMP version number\n") { - VTY_DECLVAR_CONTEXT(interface, ifp); - struct pim_interface *pim_ifp = ifp->info; - - if (!pim_ifp) - return CMD_SUCCESS; + nb_cli_enqueue_change(vty, "./version", NB_OP_DESTROY, NULL); - pim_ifp->igmp_version = IGMP_DEFAULT_VERSION; - - return CMD_SUCCESS; + return nb_cli_apply_changes(vty, "./frr-igmp:igmp"); } -#define IGMP_QUERY_MAX_RESPONSE_TIME_MIN_DSEC (10) -#define IGMP_QUERY_MAX_RESPONSE_TIME_MAX_DSEC (250) - DEFUN (interface_ip_igmp_query_max_response_time, interface_ip_igmp_query_max_response_time_cmd, "ip igmp query-max-response-time (10-250)", @@ -8014,32 +8202,25 @@ DEFUN (interface_ip_igmp_query_max_response_time, IFACE_IGMP_QUERY_MAX_RESPONSE_TIME_STR "Query response value in deci-seconds\n") { - VTY_DECLVAR_CONTEXT(interface, ifp); - struct pim_interface *pim_ifp = ifp->info; - int query_max_response_time; - int ret; + const struct lyd_node *pim_enable_dnode; - if (!pim_ifp) { - ret = pim_cmd_igmp_start(vty, ifp); - if (ret != CMD_SUCCESS) - return ret; - pim_ifp = ifp->info; - } + pim_enable_dnode = yang_dnode_get(vty->candidate_config->dnode, + "%s/frr-pim:pim/pim-enable", + VTY_CURR_XPATH); - query_max_response_time = atoi(argv[3]->arg); - - if (query_max_response_time - >= pim_ifp->igmp_default_query_interval * 10) { - vty_out(vty, - "Can't set query max response time %d sec >= general query interval %d sec\n", - query_max_response_time, - pim_ifp->igmp_default_query_interval); - return CMD_WARNING_CONFIG_FAILED; + if (!pim_enable_dnode) { + nb_cli_enqueue_change(vty, "./igmp-enable", NB_OP_MODIFY, + "true"); + } else { + if (!yang_dnode_get_bool(pim_enable_dnode, ".")) + nb_cli_enqueue_change(vty, "./igmp-enable", + NB_OP_MODIFY, "true"); } - change_query_max_response_time(pim_ifp, query_max_response_time); + nb_cli_enqueue_change(vty, "./query-max-response-time", NB_OP_MODIFY, + argv[3]->arg); - return CMD_SUCCESS; + return nb_cli_apply_changes(vty, "./frr-igmp:igmp"); } DEFUN (interface_no_ip_igmp_query_max_response_time, @@ -8051,21 +8232,17 @@ DEFUN (interface_no_ip_igmp_query_max_response_time, IFACE_IGMP_QUERY_MAX_RESPONSE_TIME_STR "Time for response in deci-seconds\n") { - VTY_DECLVAR_CONTEXT(interface, ifp); - struct pim_interface *pim_ifp = ifp->info; - - if (!pim_ifp) - return CMD_SUCCESS; + char default_query_max_response_time[4]; - change_query_max_response_time(pim_ifp, - IGMP_QUERY_MAX_RESPONSE_TIME_DSEC); + snprintf(default_query_max_response_time, + sizeof(default_query_max_response_time), + "%d", IGMP_QUERY_MAX_RESPONSE_TIME_DSEC); - return CMD_SUCCESS; + nb_cli_enqueue_change(vty, "./query-max-response-time", NB_OP_MODIFY, + default_query_max_response_time); + return nb_cli_apply_changes(vty, "./frr-igmp:igmp"); } -#define IGMP_QUERY_MAX_RESPONSE_TIME_MIN_DSEC (10) -#define IGMP_QUERY_MAX_RESPONSE_TIME_MAX_DSEC (250) - DEFUN_HIDDEN (interface_ip_igmp_query_max_response_time_dsec, interface_ip_igmp_query_max_response_time_dsec_cmd, "ip igmp query-max-response-time-dsec (10-250)", @@ -8074,34 +8251,24 @@ DEFUN_HIDDEN (interface_ip_igmp_query_max_response_time_dsec, IFACE_IGMP_QUERY_MAX_RESPONSE_TIME_DSEC_STR "Query response value in deciseconds\n") { - VTY_DECLVAR_CONTEXT(interface, ifp); - struct pim_interface *pim_ifp = ifp->info; - int query_max_response_time_dsec; - int default_query_interval_dsec; - int ret; - - if (!pim_ifp) { - ret = pim_cmd_igmp_start(vty, ifp); - if (ret != CMD_SUCCESS) - return ret; - pim_ifp = ifp->info; - } + const struct lyd_node *pim_enable_dnode; - query_max_response_time_dsec = atoi(argv[4]->arg); - - default_query_interval_dsec = 10 * pim_ifp->igmp_default_query_interval; - - if (query_max_response_time_dsec >= default_query_interval_dsec) { - vty_out(vty, - "Can't set query max response time %d dsec >= general query interval %d dsec\n", - query_max_response_time_dsec, - default_query_interval_dsec); - return CMD_WARNING_CONFIG_FAILED; + pim_enable_dnode = yang_dnode_get(vty->candidate_config->dnode, + "%s/frr-pim:pim/pim-enable", + VTY_CURR_XPATH); + if (!pim_enable_dnode) { + nb_cli_enqueue_change(vty, "./igmp-enable", NB_OP_MODIFY, + "true"); + } else { + if (!yang_dnode_get_bool(pim_enable_dnode, ".")) + nb_cli_enqueue_change(vty, "./igmp-enable", + NB_OP_MODIFY, "true"); } - change_query_max_response_time(pim_ifp, query_max_response_time_dsec); + nb_cli_enqueue_change(vty, "./query-max-response-time", NB_OP_MODIFY, + argv[3]->arg); - return CMD_SUCCESS; + return nb_cli_apply_changes(vty, "./frr-igmp:igmp"); } DEFUN_HIDDEN (interface_no_ip_igmp_query_max_response_time_dsec, @@ -8112,21 +8279,18 @@ DEFUN_HIDDEN (interface_no_ip_igmp_query_max_response_time_dsec, IFACE_IGMP_STR IFACE_IGMP_QUERY_MAX_RESPONSE_TIME_DSEC_STR) { - VTY_DECLVAR_CONTEXT(interface, ifp); - struct pim_interface *pim_ifp = ifp->info; + char default_query_max_response_time[4]; - if (!pim_ifp) - return CMD_SUCCESS; + snprintf(default_query_max_response_time, + sizeof(default_query_max_response_time), + "%d", IGMP_QUERY_MAX_RESPONSE_TIME_DSEC); - change_query_max_response_time(pim_ifp, - IGMP_QUERY_MAX_RESPONSE_TIME_DSEC); + nb_cli_enqueue_change(vty, "./query-max-response-time", NB_OP_MODIFY, + default_query_max_response_time); - return CMD_SUCCESS; + return nb_cli_apply_changes(vty, "./frr-igmp:igmp"); } -#define IGMP_LAST_MEMBER_QUERY_COUNT_MIN (1) -#define IGMP_LAST_MEMBER_QUERY_COUNT_MAX (7) - DEFUN (interface_ip_igmp_last_member_query_count, interface_ip_igmp_last_member_query_count_cmd, "ip igmp last-member-query-count (1-7)", @@ -8135,23 +8299,24 @@ DEFUN (interface_ip_igmp_last_member_query_count, IFACE_IGMP_LAST_MEMBER_QUERY_COUNT_STR "Last member query count\n") { - VTY_DECLVAR_CONTEXT(interface, ifp); - struct pim_interface *pim_ifp = ifp->info; - int last_member_query_count; - int ret; + const struct lyd_node *pim_enable_dnode; - if (!pim_ifp) { - ret = pim_cmd_igmp_start(vty, ifp); - if (ret != CMD_SUCCESS) - return ret; - pim_ifp = ifp->info; + pim_enable_dnode = yang_dnode_get(vty->candidate_config->dnode, + "%s/frr-pim:pim/pim-enable", + VTY_CURR_XPATH); + if (!pim_enable_dnode) { + nb_cli_enqueue_change(vty, "./igmp-enable", NB_OP_MODIFY, + "true"); + } else { + if (!yang_dnode_get_bool(pim_enable_dnode, ".")) + nb_cli_enqueue_change(vty, "./igmp-enable", + NB_OP_MODIFY, "true"); } - last_member_query_count = atoi(argv[3]->arg); - - pim_ifp->igmp_last_member_query_count = last_member_query_count; + nb_cli_enqueue_change(vty, "./robustness-variable", NB_OP_MODIFY, + argv[3]->arg); - return CMD_SUCCESS; + return nb_cli_apply_changes(vty, "./frr-igmp:igmp"); } DEFUN (interface_no_ip_igmp_last_member_query_count, @@ -8162,21 +8327,17 @@ DEFUN (interface_no_ip_igmp_last_member_query_count, IFACE_IGMP_STR IFACE_IGMP_LAST_MEMBER_QUERY_COUNT_STR) { - VTY_DECLVAR_CONTEXT(interface, ifp); - struct pim_interface *pim_ifp = ifp->info; + char default_robustness[2]; - if (!pim_ifp) - return CMD_SUCCESS; + snprintf(default_robustness, sizeof(default_robustness), "%d", + IGMP_DEFAULT_ROBUSTNESS_VARIABLE); - pim_ifp->igmp_last_member_query_count = - IGMP_DEFAULT_ROBUSTNESS_VARIABLE; + nb_cli_enqueue_change(vty, "./robustness-variable", NB_OP_MODIFY, + default_robustness); - return CMD_SUCCESS; + return nb_cli_apply_changes(vty, "./frr-igmp:igmp"); } -#define IGMP_LAST_MEMBER_QUERY_INTERVAL_MIN (1) -#define IGMP_LAST_MEMBER_QUERY_INTERVAL_MAX (255) - DEFUN (interface_ip_igmp_last_member_query_interval, interface_ip_igmp_last_member_query_interval_cmd, "ip igmp last-member-query-interval (1-255)", @@ -8185,23 +8346,24 @@ DEFUN (interface_ip_igmp_last_member_query_interval, IFACE_IGMP_LAST_MEMBER_QUERY_INTERVAL_STR "Last member query interval in deciseconds\n") { - VTY_DECLVAR_CONTEXT(interface, ifp); - struct pim_interface *pim_ifp = ifp->info; - int last_member_query_interval; - int ret; + const struct lyd_node *pim_enable_dnode; - if (!pim_ifp) { - ret = pim_cmd_igmp_start(vty, ifp); - if (ret != CMD_SUCCESS) - return ret; - pim_ifp = ifp->info; + pim_enable_dnode = yang_dnode_get(vty->candidate_config->dnode, + "%s/frr-pim:pim/pim-enable", + VTY_CURR_XPATH); + if (!pim_enable_dnode) { + nb_cli_enqueue_change(vty, "./igmp-enable", NB_OP_MODIFY, + "true"); + } else { + if (!yang_dnode_get_bool(pim_enable_dnode, ".")) + nb_cli_enqueue_change(vty, "./igmp-enable", + NB_OP_MODIFY, "true"); } - last_member_query_interval = atoi(argv[3]->arg); - pim_ifp->igmp_specific_query_max_response_time_dsec - = last_member_query_interval; + nb_cli_enqueue_change(vty, "./last-member-query-interval", NB_OP_MODIFY, + argv[3]->arg); - return CMD_SUCCESS; + return nb_cli_apply_changes(vty, "./frr-igmp:igmp"); } DEFUN (interface_no_ip_igmp_last_member_query_interval, @@ -8212,16 +8374,16 @@ DEFUN (interface_no_ip_igmp_last_member_query_interval, IFACE_IGMP_STR IFACE_IGMP_LAST_MEMBER_QUERY_INTERVAL_STR) { - VTY_DECLVAR_CONTEXT(interface, ifp); - struct pim_interface *pim_ifp = ifp->info; + char default_last_member_query_count[4]; - if (!pim_ifp) - return CMD_SUCCESS; + snprintf(default_last_member_query_count, + sizeof(default_last_member_query_count), + "%d", IGMP_SPECIFIC_QUERY_MAX_RESPONSE_TIME_DSEC); - pim_ifp->igmp_specific_query_max_response_time_dsec = - IGMP_SPECIFIC_QUERY_MAX_RESPONSE_TIME_DSEC; + nb_cli_enqueue_change(vty, "./last-member-query-interval", NB_OP_MODIFY, + default_last_member_query_count); - return CMD_SUCCESS; + return nb_cli_apply_changes(vty, "./frr-igmp:igmp"); } DEFUN (interface_ip_pim_drprio, @@ -8232,26 +8394,12 @@ DEFUN (interface_ip_pim_drprio, "Set the Designated Router Election Priority\n" "Value of the new DR Priority\n") { - VTY_DECLVAR_CONTEXT(interface, ifp); int idx_number = 3; - struct pim_interface *pim_ifp = ifp->info; - uint32_t old_dr_prio; - - if (!pim_ifp) { - vty_out(vty, "Please enable PIM on interface, first\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - old_dr_prio = pim_ifp->pim_dr_priority; - - pim_ifp->pim_dr_priority = strtol(argv[idx_number]->arg, NULL, 10); - if (old_dr_prio != pim_ifp->pim_dr_priority) { - pim_if_dr_election(ifp); - pim_hello_restart_now(ifp); - } + nb_cli_enqueue_change(vty, "./dr-priority", NB_OP_MODIFY, + argv[idx_number]->arg); - return CMD_SUCCESS; + return nb_cli_apply_changes(vty, "./frr-pim:pim"); } DEFUN (interface_no_ip_pim_drprio, @@ -8263,21 +8411,15 @@ DEFUN (interface_no_ip_pim_drprio, "Revert the Designated Router Priority to default\n" "Old Value of the Priority\n") { - VTY_DECLVAR_CONTEXT(interface, ifp); - struct pim_interface *pim_ifp = ifp->info; + char default_priority[10]; - if (!pim_ifp) { - vty_out(vty, "Pim not enabled on this interface\n"); - return CMD_WARNING_CONFIG_FAILED; - } + snprintf(default_priority, sizeof(default_priority), "%d", + PIM_DEFAULT_DR_PRIORITY); - if (pim_ifp->pim_dr_priority != PIM_DEFAULT_DR_PRIORITY) { - pim_ifp->pim_dr_priority = PIM_DEFAULT_DR_PRIORITY; - pim_if_dr_election(ifp); - pim_hello_restart_now(ifp); - } + nb_cli_enqueue_change(vty, "./dr-priority", NB_OP_MODIFY, + default_priority); - return CMD_SUCCESS; + return nb_cli_apply_changes(vty, "./frr-pim:pim"); } DEFPY_HIDDEN (interface_ip_igmp_query_generate, @@ -8306,30 +8448,6 @@ DEFPY_HIDDEN (interface_ip_igmp_query_generate, return CMD_SUCCESS; } -static int pim_cmd_interface_add(struct vty *vty, struct interface *ifp) -{ - struct pim_interface *pim_ifp = ifp->info; - struct pim_instance *pim; - - if (!pim_ifp) { - pim = pim_get_pim_instance(ifp->vrf_id); - /* Limiting mcast interfaces to number of VIFs */ - if (pim->mcast_if_count == MAXVIFS) { - vty_out(vty, "Max multicast interfaces(%d) reached.", - MAXVIFS); - return 0; - } - pim_ifp = pim_if_new(ifp, false, true, false, false); - } else - PIM_IF_DO_PIM(pim_ifp->options); - - pim_if_addr_add_all(ifp); - pim_if_membership_refresh(ifp); - - pim_if_create_pimreg(pim_ifp->pim); - return 1; -} - DEFPY_HIDDEN (pim_test_sg_keepalive, pim_test_sg_keepalive_cmd, "test pim [vrf NAME$name] keepalive-reset A.B.C.D$source A.B.C.D$group", @@ -8388,28 +8506,18 @@ DEFPY (interface_ip_pim_activeactive, PIM_STR "Mark interface as Active-Active for MLAG operations, Hidden because not finished yet\n") { - VTY_DECLVAR_CONTEXT(interface, ifp); - struct pim_interface *pim_ifp; + if (no) + nb_cli_enqueue_change(vty, "./active-active", NB_OP_MODIFY, + "false"); + else { + nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY, + "true"); - if (!no && !pim_cmd_interface_add(vty, ifp)) { - vty_out(vty, - "Could not enable PIM SM active-active on interface %s\n", - ifp->name); - return CMD_WARNING_CONFIG_FAILED; + nb_cli_enqueue_change(vty, "./active-active", NB_OP_MODIFY, + "true"); } - - if (PIM_DEBUG_MLAG) - zlog_debug("%sConfiguring PIM active-active on Interface: %s", - no ? "Un-" : " ", ifp->name); - - pim_ifp = ifp->info; - if (no) - pim_if_unconfigure_mlag_dualactive(pim_ifp); - else - pim_if_configure_mlag_dualactive(pim_ifp); - - return CMD_SUCCESS; + return nb_cli_apply_changes(vty, "./frr-pim:pim"); } DEFUN_HIDDEN (interface_ip_pim_ssm, @@ -8419,36 +8527,19 @@ DEFUN_HIDDEN (interface_ip_pim_ssm, PIM_STR IFACE_PIM_STR) { - VTY_DECLVAR_CONTEXT(interface, ifp); - - if (!pim_cmd_interface_add(vty, ifp)) { - vty_out(vty, "Could not enable PIM SM on interface %s\n", - ifp->name); - return CMD_WARNING_CONFIG_FAILED; - } - - vty_out(vty, - "WARN: Enabled PIM SM on interface; configure PIM SSM range if needed\n"); - return CMD_SUCCESS; -} - -static int interface_ip_pim_helper(struct vty *vty) -{ - struct pim_interface *pim_ifp; + int ret; - VTY_DECLVAR_CONTEXT(interface, ifp); + nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY, "true"); - if (!pim_cmd_interface_add(vty, ifp)) { - vty_out(vty, "Could not enable PIM SM on interface %s\n", - ifp->name); - return CMD_WARNING_CONFIG_FAILED; - } + ret = nb_cli_apply_changes(vty, "./frr-pim:pim"); - pim_ifp = ifp->info; + if (ret != NB_OK) + return ret; - pim_if_create_pimreg(pim_ifp->pim); + vty_out(vty, + "WARN: Enabled PIM SM on interface; configure PIM SSM range if needed\n"); - return CMD_SUCCESS; + return NB_OK; } DEFUN_HIDDEN (interface_ip_pim_sm, @@ -8458,7 +8549,9 @@ DEFUN_HIDDEN (interface_ip_pim_sm, PIM_STR IFACE_PIM_SM_STR) { - return interface_ip_pim_helper(vty); + nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY, "true"); + + return nb_cli_apply_changes(vty, "./frr-pim:pim"); } DEFUN (interface_ip_pim, @@ -8467,43 +8560,9 @@ DEFUN (interface_ip_pim, IP_STR PIM_STR) { - return interface_ip_pim_helper(vty); -} - -static int pim_cmd_interface_delete(struct interface *ifp) -{ - struct pim_interface *pim_ifp = ifp->info; - - if (!pim_ifp) - return 1; - - PIM_IF_DONT_PIM(pim_ifp->options); - - pim_if_membership_clear(ifp); + nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY, "true"); - /* - pim_sock_delete() removes all neighbors from - pim_ifp->pim_neighbor_list. - */ - pim_sock_delete(ifp, "pim unconfigured on interface"); - - if (!PIM_IF_TEST_IGMP(pim_ifp->options)) { - pim_if_addr_del_all(ifp); - pim_if_delete(ifp); - } - - return 1; -} - -static int interface_no_ip_pim_helper(struct vty *vty) -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - if (!pim_cmd_interface_delete(ifp)) { - vty_out(vty, "Unable to delete interface information\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - return CMD_SUCCESS; + return nb_cli_apply_changes(vty, "./frr-pim:pim"); } DEFUN_HIDDEN (interface_no_ip_pim_ssm, @@ -8514,7 +8573,28 @@ DEFUN_HIDDEN (interface_no_ip_pim_ssm, PIM_STR IFACE_PIM_STR) { - return interface_no_ip_pim_helper(vty); + const struct lyd_node *igmp_enable_dnode; + char igmp_if_xpath[XPATH_MAXLEN]; + + snprintf(igmp_if_xpath, sizeof(igmp_if_xpath), + "%s/frr-igmp:igmp", VTY_CURR_XPATH); + igmp_enable_dnode = yang_dnode_get(vty->candidate_config->dnode, + "%s/igmp-enable", igmp_if_xpath); + + if (!igmp_enable_dnode) { + nb_cli_enqueue_change(vty, igmp_if_xpath, NB_OP_DESTROY, NULL); + nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); + } else { + if (!yang_dnode_get_bool(igmp_enable_dnode, ".")) { + nb_cli_enqueue_change(vty, igmp_if_xpath, NB_OP_DESTROY, + NULL); + nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); + } else + nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY, + "false"); + } + + return nb_cli_apply_changes(vty, "./frr-pim:pim"); } DEFUN_HIDDEN (interface_no_ip_pim_sm, @@ -8525,7 +8605,28 @@ DEFUN_HIDDEN (interface_no_ip_pim_sm, PIM_STR IFACE_PIM_SM_STR) { - return interface_no_ip_pim_helper(vty); + const struct lyd_node *igmp_enable_dnode; + char igmp_if_xpath[XPATH_MAXLEN]; + + snprintf(igmp_if_xpath, sizeof(igmp_if_xpath), + "%s/frr-igmp:igmp", VTY_CURR_XPATH); + igmp_enable_dnode = yang_dnode_get(vty->candidate_config->dnode, + "%s/igmp-enable", igmp_if_xpath); + + if (!igmp_enable_dnode) { + nb_cli_enqueue_change(vty, igmp_if_xpath, NB_OP_DESTROY, NULL); + nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); + } else { + if (!yang_dnode_get_bool(igmp_enable_dnode, ".")) { + nb_cli_enqueue_change(vty, igmp_if_xpath, NB_OP_DESTROY, + NULL); + nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); + } else + nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY, + "false"); + } + + return nb_cli_apply_changes(vty, "./frr-pim:pim"); } DEFUN (interface_no_ip_pim, @@ -8535,7 +8636,28 @@ DEFUN (interface_no_ip_pim, IP_STR PIM_STR) { - return interface_no_ip_pim_helper(vty); + const struct lyd_node *igmp_enable_dnode; + char igmp_if_xpath[XPATH_MAXLEN]; + + snprintf(igmp_if_xpath, sizeof(igmp_if_xpath), + "%s/frr-igmp:igmp", VTY_CURR_XPATH); + igmp_enable_dnode = yang_dnode_get(vty->candidate_config->dnode, + "%s/igmp-enable", igmp_if_xpath); + + if (!igmp_enable_dnode) { + nb_cli_enqueue_change(vty, igmp_if_xpath, NB_OP_DESTROY, NULL); + nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); + } else { + if (!yang_dnode_get_bool(igmp_enable_dnode, ".")) { + nb_cli_enqueue_change(vty, igmp_if_xpath, NB_OP_DESTROY, + NULL); + nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); + } else + nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY, + "false"); + } + + return nb_cli_apply_changes(vty, "./frr-pim:pim"); } /* boundaries */ @@ -8548,22 +8670,13 @@ DEFUN(interface_ip_pim_boundary_oil, "Filter OIL by group using prefix list\n" "Prefix list to filter OIL with\n") { - VTY_DECLVAR_CONTEXT(interface, iif); - struct pim_interface *pim_ifp; - int idx = 0; - - argv_find(argv, argc, "WORD", &idx); - - PIM_GET_PIM_INTERFACE(pim_ifp, iif); - - if (pim_ifp->boundary_oil_plist) - XFREE(MTYPE_PIM_INTERFACE, pim_ifp->boundary_oil_plist); + nb_cli_enqueue_change(vty, "./multicast-boundary-oil", NB_OP_MODIFY, + argv[4]->arg); - pim_ifp->boundary_oil_plist = - XSTRDUP(MTYPE_PIM_INTERFACE, argv[idx]->arg); + return nb_cli_apply_changes(vty, + "./frr-pim:pim/address-family[address-family='%s']", + "frr-routing:ipv4"); - /* Interface will be pruned from OIL on next Join */ - return CMD_SUCCESS; } DEFUN(interface_no_ip_pim_boundary_oil, @@ -8576,18 +8689,12 @@ DEFUN(interface_no_ip_pim_boundary_oil, "Filter OIL by group using prefix list\n" "Prefix list to filter OIL with\n") { - VTY_DECLVAR_CONTEXT(interface, iif); - struct pim_interface *pim_ifp; - int idx = 0; - - argv_find(argv, argc, "WORD", &idx); + nb_cli_enqueue_change(vty, "./multicast-boundary-oil", NB_OP_DESTROY, + NULL); - PIM_GET_PIM_INTERFACE(pim_ifp, iif); - - if (pim_ifp->boundary_oil_plist) - XFREE(MTYPE_PIM_INTERFACE, pim_ifp->boundary_oil_plist); - - return CMD_SUCCESS; + return nb_cli_apply_changes(vty, + "./frr-pim:pim/address-family[address-family='%s']", + "frr-routing:ipv4"); } DEFUN (interface_ip_mroute, @@ -8599,56 +8706,21 @@ DEFUN (interface_ip_mroute, "Group address\n" "Source address\n") { - VTY_DECLVAR_CONTEXT(interface, iif); - struct pim_interface *pim_ifp; - struct pim_instance *pim; int idx_interface = 2; int idx_ipv4 = 3; - struct interface *oif; - const char *oifname; - const char *grp_str; - struct in_addr grp_addr; - const char *src_str; - struct in_addr src_addr; - int result; - - PIM_GET_PIM_INTERFACE(pim_ifp, iif); - pim = pim_ifp->pim; - - oifname = argv[idx_interface]->arg; - oif = if_lookup_by_name(oifname, pim->vrf_id); - if (!oif) { - vty_out(vty, "No such interface name %s\n", oifname); - return CMD_WARNING; - } + const char *source_str; - grp_str = argv[idx_ipv4]->arg; - result = inet_pton(AF_INET, grp_str, &grp_addr); - if (result <= 0) { - vty_out(vty, "Bad group address %s: errno=%d: %s\n", grp_str, - errno, safe_strerror(errno)); - return CMD_WARNING; - } + if (argc == (idx_ipv4 + 1)) + source_str = "0.0.0.0"; + else + source_str = argv[idx_ipv4 + 1]->arg; - if (argc == (idx_ipv4 + 1)) { - src_addr.s_addr = INADDR_ANY; - } - else { - src_str = argv[idx_ipv4 + 1]->arg; - result = inet_pton(AF_INET, src_str, &src_addr); - if (result <= 0) { - vty_out(vty, "Bad source address %s: errno=%d: %s\n", src_str, - errno, safe_strerror(errno)); - return CMD_WARNING; - } - } - - if (pim_static_add(pim, iif, oif, grp_addr, src_addr)) { - vty_out(vty, "Failed to add static mroute\n"); - return CMD_WARNING; - } + nb_cli_enqueue_change(vty, "./oif", NB_OP_MODIFY, + argv[idx_interface]->arg); - return CMD_SUCCESS; + return nb_cli_apply_changes(vty, + "./frr-pim:pim/address-family[address-family='%s']/mroute[source-addr='%s'][group-addr='%s']", + "frr-routing:ipv4", source_str, argv[idx_ipv4]->arg); } DEFUN (interface_no_ip_mroute, @@ -8661,56 +8733,19 @@ DEFUN (interface_no_ip_mroute, "Group Address\n" "Source Address\n") { - VTY_DECLVAR_CONTEXT(interface, iif); - struct pim_interface *pim_ifp; - struct pim_instance *pim; - int idx_interface = 3; int idx_ipv4 = 4; - struct interface *oif; - const char *oifname; - const char *grp_str; - struct in_addr grp_addr; - const char *src_str; - struct in_addr src_addr; - int result; - - PIM_GET_PIM_INTERFACE(pim_ifp, iif); - pim = pim_ifp->pim; - - oifname = argv[idx_interface]->arg; - oif = if_lookup_by_name(oifname, pim->vrf_id); - if (!oif) { - vty_out(vty, "No such interface name %s\n", oifname); - return CMD_WARNING; - } + const char *source_str; - grp_str = argv[idx_ipv4]->arg; - result = inet_pton(AF_INET, grp_str, &grp_addr); - if (result <= 0) { - vty_out(vty, "Bad group address %s: errno=%d: %s\n", grp_str, - errno, safe_strerror(errno)); - return CMD_WARNING; - } + if (argc == (idx_ipv4 + 1)) + source_str = "0.0.0.0"; + else + source_str = argv[idx_ipv4 + 1]->arg; - if (argc == (idx_ipv4 + 1)) { - src_addr.s_addr = INADDR_ANY; - } - else { - src_str = argv[idx_ipv4 + 1]->arg; - result = inet_pton(AF_INET, src_str, &src_addr); - if (result <= 0) { - vty_out(vty, "Bad source address %s: errno=%d: %s\n", src_str, - errno, safe_strerror(errno)); - return CMD_WARNING; - } - } - - if (pim_static_del(pim, iif, oif, grp_addr, src_addr)) { - vty_out(vty, "Failed to remove static mroute\n"); - return CMD_WARNING; - } + nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); - return CMD_SUCCESS; + return nb_cli_apply_changes(vty, + "./frr-pim:pim/address-family[address-family='%s']/mroute[source-addr='%s'][group-addr='%s']", + "frr-routing:ipv4", source_str, argv[idx_ipv4]->arg); } DEFUN (interface_ip_pim_hello, @@ -8722,28 +8757,30 @@ DEFUN (interface_ip_pim_hello, IFACE_PIM_HELLO_TIME_STR IFACE_PIM_HELLO_HOLD_STR) { - VTY_DECLVAR_CONTEXT(interface, ifp); int idx_time = 3; int idx_hold = 4; - struct pim_interface *pim_ifp = ifp->info; - - if (!pim_ifp) { - if (!pim_cmd_interface_add(vty, ifp)) { - vty_out(vty, - "Could not enable PIM SM on interface %s\n", - ifp->name); - return CMD_WARNING_CONFIG_FAILED; - } + const struct lyd_node *igmp_enable_dnode; + + igmp_enable_dnode = yang_dnode_get(vty->candidate_config->dnode, + "%s/frr-igmp:igmp/igmp-enable", + VTY_CURR_XPATH); + if (!igmp_enable_dnode) { + nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY, + "true"); + } else { + if (!yang_dnode_get_bool(igmp_enable_dnode, ".")) + nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY, + "true"); } - pim_ifp = ifp->info; - pim_ifp->pim_hello_period = strtol(argv[idx_time]->arg, NULL, 10); + nb_cli_enqueue_change(vty, "./hello-interval", NB_OP_MODIFY, + argv[idx_time]->arg); if (argc == idx_hold + 1) - pim_ifp->pim_default_holdtime = - strtol(argv[idx_hold]->arg, NULL, 10); + nb_cli_enqueue_change(vty, "./hello-holdtime", NB_OP_MODIFY, + argv[idx_hold]->arg); - return CMD_SUCCESS; + return nb_cli_apply_changes(vty, "./frr-pim:pim"); } DEFUN (interface_no_ip_pim_hello, @@ -8756,18 +8793,16 @@ DEFUN (interface_no_ip_pim_hello, IFACE_PIM_HELLO_TIME_STR IFACE_PIM_HELLO_HOLD_STR) { - VTY_DECLVAR_CONTEXT(interface, ifp); - struct pim_interface *pim_ifp = ifp->info; + char hello_default_timer[3]; - if (!pim_ifp) { - vty_out(vty, "Pim not enabled on this interface\n"); - return CMD_WARNING_CONFIG_FAILED; - } + snprintf(hello_default_timer, sizeof(hello_default_timer), "%d", + PIM_DEFAULT_HELLO_PERIOD); - pim_ifp->pim_hello_period = PIM_DEFAULT_HELLO_PERIOD; - pim_ifp->pim_default_holdtime = -1; + nb_cli_enqueue_change(vty, "./hello-interval", NB_OP_MODIFY, + hello_default_timer); + nb_cli_enqueue_change(vty, "./hello-holdtime", NB_OP_DESTROY, NULL); - return CMD_SUCCESS; + return nb_cli_apply_changes(vty, "./frr-pim:pim"); } DEFUN (debug_igmp, @@ -9404,40 +9439,6 @@ DEFUN_NOSH (show_debugging_pim, return CMD_SUCCESS; } -static int interface_pim_use_src_cmd_worker(struct vty *vty, const char *source) -{ - int result; - struct in_addr source_addr; - int ret = CMD_SUCCESS; - VTY_DECLVAR_CONTEXT(interface, ifp); - - result = inet_pton(AF_INET, source, &source_addr); - if (result <= 0) { - vty_out(vty, "%% Bad source address %s: errno=%d: %s\n", source, - errno, safe_strerror(errno)); - return CMD_WARNING_CONFIG_FAILED; - } - - result = pim_update_source_set(ifp, source_addr); - switch (result) { - case PIM_SUCCESS: - break; - case PIM_IFACE_NOT_FOUND: - ret = CMD_WARNING_CONFIG_FAILED; - vty_out(vty, "Pim not enabled on this interface\n"); - break; - case PIM_UPDATE_SOURCE_DUP: - ret = CMD_WARNING; - vty_out(vty, "%% Source already set to %s\n", source); - break; - default: - ret = CMD_WARNING_CONFIG_FAILED; - vty_out(vty, "%% Source set failed\n"); - } - - return ret; -} - DEFUN (interface_pim_use_source, interface_pim_use_source_cmd, "ip pim use-source A.B.C.D", @@ -9446,7 +9447,11 @@ DEFUN (interface_pim_use_source, "Configure primary IP address\n" "source ip address\n") { - return interface_pim_use_src_cmd_worker(vty, argv[3]->arg); + nb_cli_enqueue_change(vty, "./use-source", NB_OP_MODIFY, argv[3]->arg); + + return nb_cli_apply_changes(vty, + "./frr-pim:pim/address-family[address-family='%s']", + "frr-routing:ipv4"); } DEFUN (interface_no_pim_use_source, @@ -9458,7 +9463,11 @@ DEFUN (interface_no_pim_use_source, "Delete source IP address\n" "source ip address\n") { - return interface_pim_use_src_cmd_worker(vty, "0.0.0.0"); + nb_cli_enqueue_change(vty, "./use-source", NB_OP_MODIFY, "0.0.0.0"); + + return nb_cli_apply_changes(vty, + "./frr-pim:pim/address-family[address-family='%s']", + "frr-routing:ipv4"); } DEFUN (ip_pim_bfd, @@ -9468,27 +9477,50 @@ DEFUN (ip_pim_bfd, PIM_STR "Enables BFD support\n") { - VTY_DECLVAR_CONTEXT(interface, ifp); - struct pim_interface *pim_ifp = ifp->info; struct bfd_info *bfd_info = NULL; - - if (!pim_ifp) { - if (!pim_cmd_interface_add(vty, ifp)) { - vty_out(vty, - "Could not enable PIM SM on interface %s\n", - ifp->name); - return CMD_WARNING; - } + char default_rx_interval[5]; + char default_tx_interval[5]; + char default_detect_mult[3]; + const struct lyd_node *igmp_enable_dnode; + char bfd_xpath[XPATH_MAXLEN]; + + igmp_enable_dnode = yang_dnode_get(vty->candidate_config->dnode, + "%s/frr-igmp:igmp/igmp-enable", + VTY_CURR_XPATH); + if (!igmp_enable_dnode) + nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY, + "true"); + else { + if (!yang_dnode_get_bool(igmp_enable_dnode, ".")) + nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY, + "true"); } - pim_ifp = ifp->info; - bfd_info = pim_ifp->bfd_info; + snprintf(default_rx_interval, sizeof(default_rx_interval), "%d", + BFD_DEF_MIN_RX); + snprintf(default_tx_interval, sizeof(default_tx_interval), "%d", + BFD_DEF_MIN_TX); + snprintf(default_detect_mult, sizeof(default_detect_mult), "%d", + BFD_DEF_DETECT_MULT); - if (!bfd_info || !CHECK_FLAG(bfd_info->flags, BFD_FLAG_PARAM_CFG)) - pim_bfd_if_param_set(ifp, BFD_DEF_MIN_RX, BFD_DEF_MIN_TX, - BFD_DEF_DETECT_MULT, 1); + snprintf(bfd_xpath, sizeof(bfd_xpath), "%s/frr-pim:pim/bfd", + VTY_CURR_XPATH); + bfd_info = nb_running_get_entry(NULL, bfd_xpath, false); - return CMD_SUCCESS; + if (!bfd_info || + !CHECK_FLAG(bfd_info->flags, BFD_FLAG_PARAM_CFG)) { + nb_cli_enqueue_change(vty, "./bfd/min-rx-interval", + NB_OP_MODIFY, default_rx_interval); + nb_cli_enqueue_change(vty, "./bfd/min-tx-interval", + NB_OP_MODIFY, default_tx_interval); + nb_cli_enqueue_change(vty, "./bfd/detect_mult", + NB_OP_MODIFY, + default_detect_mult); + + return nb_cli_apply_changes(vty, "./frr-pim:pim"); + } + + return NB_OK; } DEFUN (no_ip_pim_bfd, @@ -9499,20 +9531,9 @@ DEFUN (no_ip_pim_bfd, PIM_STR "Disables BFD support\n") { - VTY_DECLVAR_CONTEXT(interface, ifp); - struct pim_interface *pim_ifp = ifp->info; - - if (!pim_ifp) { - vty_out(vty, "Pim not enabled on this interface\n"); - return CMD_WARNING; - } + nb_cli_enqueue_change(vty, "./bfd", NB_OP_DESTROY, NULL); - if (pim_ifp->bfd_info) { - pim_bfd_reg_dereg_all_nbr(ifp, ZEBRA_BFD_DEST_DEREGISTER); - bfd_info_free(&(pim_ifp->bfd_info)); - } - - return CMD_SUCCESS; + return nb_cli_apply_changes(vty, "./frr-pim:pim"); } DEFUN (ip_pim_bsm, @@ -9522,22 +9543,23 @@ DEFUN (ip_pim_bsm, PIM_STR "Enables BSM support on the interface\n") { - VTY_DECLVAR_CONTEXT(interface, ifp); - struct pim_interface *pim_ifp = ifp->info; + const struct lyd_node *igmp_enable_dnode; - if (!pim_ifp) { - if (!pim_cmd_interface_add(vty, ifp)) { - vty_out(vty, - "Could not enable PIM SM on interface %s\n", - ifp->name); - return CMD_WARNING; - } + igmp_enable_dnode = yang_dnode_get(vty->candidate_config->dnode, + "%s/frr-igmp:igmp/igmp-enable", + VTY_CURR_XPATH); + if (!igmp_enable_dnode) + nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY, + "true"); + else { + if (!yang_dnode_get_bool(igmp_enable_dnode, ".")) + nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY, + "true"); } - pim_ifp = ifp->info; - pim_ifp->bsm_enable = true; + nb_cli_enqueue_change(vty, "./bsm", NB_OP_MODIFY, "true"); - return CMD_SUCCESS; + return nb_cli_apply_changes(vty, "./frr-pim:pim"); } DEFUN (no_ip_pim_bsm, @@ -9548,17 +9570,9 @@ DEFUN (no_ip_pim_bsm, PIM_STR "Disables BSM support\n") { - VTY_DECLVAR_CONTEXT(interface, ifp); - struct pim_interface *pim_ifp = ifp->info; + nb_cli_enqueue_change(vty, "./bsm", NB_OP_MODIFY, "false"); - if (!pim_ifp) { - vty_out(vty, "Pim not enabled on this interface\n"); - return CMD_WARNING; - } - - pim_ifp->bsm_enable = false; - - return CMD_SUCCESS; + return nb_cli_apply_changes(vty, "./frr-pim:pim"); } DEFUN (ip_pim_ucast_bsm, @@ -9568,22 +9582,23 @@ DEFUN (ip_pim_ucast_bsm, PIM_STR "Accept/Send unicast BSM on the interface\n") { - VTY_DECLVAR_CONTEXT(interface, ifp); - struct pim_interface *pim_ifp = ifp->info; + const struct lyd_node *igmp_enable_dnode; - if (!pim_ifp) { - if (!pim_cmd_interface_add(vty, ifp)) { - vty_out(vty, - "Could not enable PIM SM on interface %s\n", - ifp->name); - return CMD_WARNING; - } + igmp_enable_dnode = yang_dnode_get(vty->candidate_config->dnode, + "%s/frr-igmp:igmp/igmp-enable", + VTY_CURR_XPATH); + if (!igmp_enable_dnode) + nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY, + "true"); + else { + if (!yang_dnode_get_bool(igmp_enable_dnode, ".")) + nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY, + "true"); } - pim_ifp = ifp->info; - pim_ifp->ucast_bsm_accept = true; + nb_cli_enqueue_change(vty, "./unicast-bsm", NB_OP_MODIFY, "true"); - return CMD_SUCCESS; + return nb_cli_apply_changes(vty, "./frr-pim:pim"); } DEFUN (no_ip_pim_ucast_bsm, @@ -9594,17 +9609,9 @@ DEFUN (no_ip_pim_ucast_bsm, PIM_STR "Block send/receive unicast BSM on this interface\n") { - VTY_DECLVAR_CONTEXT(interface, ifp); - struct pim_interface *pim_ifp = ifp->info; - - if (!pim_ifp) { - vty_out(vty, "Pim not enabled on this interface\n"); - return CMD_WARNING; - } - - pim_ifp->ucast_bsm_accept = false; + nb_cli_enqueue_change(vty, "./unicast-bsm", NB_OP_MODIFY, "false"); - return CMD_SUCCESS; + return nb_cli_apply_changes(vty, "./frr-pim:pim"); } #if HAVE_BFDD > 0 @@ -9631,7 +9638,6 @@ DEFUN( "Desired min transmit interval\n") #endif /* HAVE_BFDD */ { - VTY_DECLVAR_CONTEXT(interface, ifp); int idx_number = 3; int idx_number_2 = 4; int idx_number_3 = 5; @@ -9639,26 +9645,35 @@ DEFUN( uint32_t tx_val; uint8_t dm_val; int ret; - struct pim_interface *pim_ifp = ifp->info; + const struct lyd_node *igmp_enable_dnode; - if (!pim_ifp) { - if (!pim_cmd_interface_add(vty, ifp)) { - vty_out(vty, - "Could not enable PIM SM on interface %s\n", - ifp->name); - return CMD_WARNING; - } - } - - if ((ret = bfd_validate_param( - vty, argv[idx_number]->arg, argv[idx_number_2]->arg, - argv[idx_number_3]->arg, &dm_val, &rx_val, &tx_val)) - != CMD_SUCCESS) + if ((ret = bfd_validate_param(vty, argv[idx_number]->arg, + argv[idx_number_2]->arg, + argv[idx_number_3]->arg, &dm_val, &rx_val, + &tx_val)) + != CMD_SUCCESS) return ret; - pim_bfd_if_param_set(ifp, rx_val, tx_val, dm_val, 0); + igmp_enable_dnode = yang_dnode_get(vty->candidate_config->dnode, + "%s/frr-igmp:igmp/igmp-enable", + VTY_CURR_XPATH); + if (!igmp_enable_dnode) + nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY, + "true"); + else { + if (!yang_dnode_get_bool(igmp_enable_dnode, ".")) + nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY, + "true"); + } - return CMD_SUCCESS; + nb_cli_enqueue_change(vty, "./bfd/min-rx-interval", NB_OP_MODIFY, + argv[idx_number_2]->arg); + nb_cli_enqueue_change(vty, "./bfd/min-tx-interval", NB_OP_MODIFY, + argv[idx_number_3]->arg); + nb_cli_enqueue_change(vty, "./bfd/detect_mult", NB_OP_MODIFY, + argv[idx_number]->arg); + + return nb_cli_apply_changes(vty, "./frr-pim:pim"); } #if HAVE_BFDD == 0 @@ -9670,53 +9685,6 @@ ALIAS(no_ip_pim_bfd, no_ip_pim_bfd_param_cmd, "Desired min transmit interval\n") #endif /* !HAVE_BFDD */ -static int ip_msdp_peer_cmd_worker(struct pim_instance *pim, struct vty *vty, - const char *peer, const char *local) -{ - enum pim_msdp_err result; - struct in_addr peer_addr; - struct in_addr local_addr; - int ret = CMD_SUCCESS; - - result = inet_pton(AF_INET, peer, &peer_addr); - if (result <= 0) { - vty_out(vty, "%% Bad peer address %s: errno=%d: %s\n", peer, - errno, safe_strerror(errno)); - return CMD_WARNING_CONFIG_FAILED; - } - - result = inet_pton(AF_INET, local, &local_addr); - if (result <= 0) { - vty_out(vty, "%% Bad source address %s: errno=%d: %s\n", local, - errno, safe_strerror(errno)); - return CMD_WARNING_CONFIG_FAILED; - } - - result = pim_msdp_peer_add(pim, peer_addr, local_addr, "default", - NULL /* mp_p */); - switch (result) { - case PIM_MSDP_ERR_NONE: - break; - case PIM_MSDP_ERR_OOM: - ret = CMD_WARNING_CONFIG_FAILED; - vty_out(vty, "%% Out of memory\n"); - break; - case PIM_MSDP_ERR_PEER_EXISTS: - ret = CMD_WARNING; - vty_out(vty, "%% Peer exists\n"); - break; - case PIM_MSDP_ERR_MAX_MESH_GROUPS: - ret = CMD_WARNING_CONFIG_FAILED; - vty_out(vty, "%% Only one mesh-group allowed currently\n"); - break; - default: - ret = CMD_WARNING_CONFIG_FAILED; - vty_out(vty, "%% peer add failed\n"); - } - - return ret; -} - DEFUN (ip_msdp_peer, ip_msdp_peer_cmd, "ip msdp peer A.B.C.D source A.B.C.D", @@ -9727,35 +9695,37 @@ DEFUN (ip_msdp_peer, "Source address for TCP connection\n" "local ip address\n") { - PIM_DECLVAR_CONTEXT(vrf, pim); - return ip_msdp_peer_cmd_worker(pim, vty, argv[3]->arg, argv[5]->arg); -} + const struct lyd_node *vrf_dnode; + const char *vrfname; + char temp_xpath[XPATH_MAXLEN]; + char msdp_peer_source_xpath[XPATH_MAXLEN]; -static int ip_no_msdp_peer_cmd_worker(struct pim_instance *pim, struct vty *vty, - const char *peer) -{ - enum pim_msdp_err result; - struct in_addr peer_addr; + if (vty->xpath_index) { + vrf_dnode = + yang_dnode_get(vty->candidate_config->dnode, + VTY_CURR_XPATH); + if (!vrf_dnode) { + vty_out(vty, + "%% Failed to get vrf dnode in candidate db\n"); + return CMD_WARNING_CONFIG_FAILED; + } + vrfname = yang_dnode_get_string(vrf_dnode, "./name"); + } else + vrfname = VRF_DEFAULT_NAME; - result = inet_pton(AF_INET, peer, &peer_addr); - if (result <= 0) { - vty_out(vty, "%% Bad peer address %s: errno=%d: %s\n", peer, - errno, safe_strerror(errno)); - return CMD_WARNING_CONFIG_FAILED; - } + snprintf(msdp_peer_source_xpath, sizeof(msdp_peer_source_xpath), + FRR_PIM_AF_XPATH, + "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); + snprintf(temp_xpath, sizeof(temp_xpath), + "/msdp-peer[peer-ip='%s']/source-ip", + argv[3]->arg); + strlcat(msdp_peer_source_xpath, temp_xpath, + sizeof(msdp_peer_source_xpath)); - result = pim_msdp_peer_del(pim, peer_addr); - switch (result) { - case PIM_MSDP_ERR_NONE: - break; - case PIM_MSDP_ERR_NO_PEER: - vty_out(vty, "%% Peer does not exist\n"); - break; - default: - vty_out(vty, "%% peer del failed\n"); - } + nb_cli_enqueue_change(vty, msdp_peer_source_xpath, NB_OP_MODIFY, + argv[5]->arg); - return result ? CMD_WARNING_CONFIG_FAILED : CMD_SUCCESS; + return nb_cli_apply_changes(vty, NULL); } DEFUN (no_ip_msdp_peer, @@ -9767,47 +9737,36 @@ DEFUN (no_ip_msdp_peer, "Delete MSDP peer\n" "peer ip address\n") { - PIM_DECLVAR_CONTEXT(vrf, pim); - return ip_no_msdp_peer_cmd_worker(pim, vty, argv[4]->arg); -} + const struct lyd_node *vrf_dnode; + const char *vrfname; + char msdp_peer_xpath[XPATH_MAXLEN]; + char temp_xpath[XPATH_MAXLEN]; -static int ip_msdp_mesh_group_member_cmd_worker(struct pim_instance *pim, - struct vty *vty, const char *mg, - const char *mbr) -{ - enum pim_msdp_err result; - struct in_addr mbr_ip; - int ret = CMD_SUCCESS; + if (vty->xpath_index) { + vrf_dnode = + yang_dnode_get(vty->candidate_config->dnode, + VTY_CURR_XPATH); + if (!vrf_dnode) { + vty_out(vty, + "%% Failed to get vrf dnode in candidate db\n"); + return CMD_WARNING_CONFIG_FAILED; + } + vrfname = yang_dnode_get_string(vrf_dnode, "./name"); + } else + vrfname = VRF_DEFAULT_NAME; - result = inet_pton(AF_INET, mbr, &mbr_ip); - if (result <= 0) { - vty_out(vty, "%% Bad member address %s: errno=%d: %s\n", mbr, - errno, safe_strerror(errno)); - return CMD_WARNING_CONFIG_FAILED; - } + snprintf(msdp_peer_xpath, sizeof(msdp_peer_xpath), + FRR_PIM_AF_XPATH, + "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); + snprintf(temp_xpath, sizeof(temp_xpath), + "/msdp-peer[peer-ip='%s']", + argv[4]->arg); - result = pim_msdp_mg_mbr_add(pim, mg, mbr_ip); - switch (result) { - case PIM_MSDP_ERR_NONE: - break; - case PIM_MSDP_ERR_OOM: - ret = CMD_WARNING_CONFIG_FAILED; - vty_out(vty, "%% Out of memory\n"); - break; - case PIM_MSDP_ERR_MG_MBR_EXISTS: - ret = CMD_WARNING; - vty_out(vty, "%% mesh-group member exists\n"); - break; - case PIM_MSDP_ERR_MAX_MESH_GROUPS: - ret = CMD_WARNING_CONFIG_FAILED; - vty_out(vty, "%% Only one mesh-group allowed currently\n"); - break; - default: - ret = CMD_WARNING_CONFIG_FAILED; - vty_out(vty, "%% member add failed\n"); - } + strlcat(msdp_peer_xpath, temp_xpath, sizeof(msdp_peer_xpath)); - return ret; + nb_cli_enqueue_change(vty, msdp_peer_xpath, NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); } DEFUN (ip_msdp_mesh_group_member, @@ -9820,42 +9779,44 @@ DEFUN (ip_msdp_mesh_group_member, "mesh group member\n" "peer ip address\n") { - PIM_DECLVAR_CONTEXT(vrf, pim); - return ip_msdp_mesh_group_member_cmd_worker(pim, vty, argv[3]->arg, - argv[5]->arg); -} + const struct lyd_node *vrf_dnode; + const char *vrfname; + char msdp_mesh_group_name_xpath[XPATH_MAXLEN]; + char msdp_mesh_group_member_xpath[XPATH_MAXLEN]; -static int ip_no_msdp_mesh_group_member_cmd_worker(struct pim_instance *pim, - struct vty *vty, - const char *mg, - const char *mbr) -{ - enum pim_msdp_err result; - struct in_addr mbr_ip; + if (vty->xpath_index) { + vrf_dnode = + yang_dnode_get(vty->candidate_config->dnode, + VTY_CURR_XPATH); + if (!vrf_dnode) { + vty_out(vty, + "%% Failed to get vrf dnode in candidate db\n"); + return CMD_WARNING_CONFIG_FAILED; + } + vrfname = yang_dnode_get_string(vrf_dnode, "./name"); + } else + vrfname = VRF_DEFAULT_NAME; - result = inet_pton(AF_INET, mbr, &mbr_ip); - if (result <= 0) { - vty_out(vty, "%% Bad member address %s: errno=%d: %s\n", mbr, - errno, safe_strerror(errno)); - return CMD_WARNING_CONFIG_FAILED; - } + snprintf(msdp_mesh_group_name_xpath, sizeof(msdp_mesh_group_name_xpath), + FRR_PIM_AF_XPATH, + "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); + strlcat(msdp_mesh_group_name_xpath, "/msdp-mesh-group/mesh-group-name", + sizeof(msdp_mesh_group_name_xpath)); + snprintf(msdp_mesh_group_member_xpath, + sizeof(msdp_mesh_group_member_xpath), + FRR_PIM_AF_XPATH, + "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); + strlcat(msdp_mesh_group_member_xpath, "/msdp-mesh-group/member-ip", + sizeof(msdp_mesh_group_member_xpath)); - result = pim_msdp_mg_mbr_del(pim, mg, mbr_ip); - switch (result) { - case PIM_MSDP_ERR_NONE: - break; - case PIM_MSDP_ERR_NO_MG: - vty_out(vty, "%% mesh-group does not exist\n"); - break; - case PIM_MSDP_ERR_NO_MG_MBR: - vty_out(vty, "%% mesh-group member does not exist\n"); - break; - default: - vty_out(vty, "%% mesh-group member del failed\n"); - } + nb_cli_enqueue_change(vty, msdp_mesh_group_name_xpath, NB_OP_MODIFY, + argv[3]->arg); + nb_cli_enqueue_change(vty, msdp_mesh_group_member_xpath, NB_OP_CREATE, + argv[5]->arg); - return result ? CMD_WARNING_CONFIG_FAILED : CMD_SUCCESS; + return nb_cli_apply_changes(vty, NULL); } + DEFUN (no_ip_msdp_mesh_group_member, no_ip_msdp_mesh_group_member_cmd, "no ip msdp mesh-group WORD member A.B.C.D", @@ -9867,42 +9828,89 @@ DEFUN (no_ip_msdp_mesh_group_member, "mesh group member\n" "peer ip address\n") { - PIM_DECLVAR_CONTEXT(vrf, pim); - return ip_no_msdp_mesh_group_member_cmd_worker(pim, vty, argv[4]->arg, - argv[6]->arg); -} - -static int ip_msdp_mesh_group_source_cmd_worker(struct pim_instance *pim, - struct vty *vty, const char *mg, - const char *src) -{ - enum pim_msdp_err result; - struct in_addr src_ip; - - result = inet_pton(AF_INET, src, &src_ip); - if (result <= 0) { - vty_out(vty, "%% Bad source address %s: errno=%d: %s\n", src, - errno, safe_strerror(errno)); - return CMD_WARNING_CONFIG_FAILED; + const struct lyd_node *vrf_dnode; + const char *vrfname; + char temp_xpath[XPATH_MAXLEN]; + char mesh_group_xpath[XPATH_MAXLEN]; + char group_member_xpath[XPATH_MAXLEN]; + char source_xpath[XPATH_MAXLEN]; + char mesh_group_name_xpath[XPATH_MAXLEN]; + const char *mesh_group_name; + const struct lyd_node *member_dnode; + + if (vty->xpath_index) { + vrf_dnode = + yang_dnode_get(vty->candidate_config->dnode, + VTY_CURR_XPATH); + if (!vrf_dnode) { + vty_out(vty, + "%% Failed to get vrf dnode in candidate db\n"); + return CMD_WARNING_CONFIG_FAILED; + } + vrfname = yang_dnode_get_string(vrf_dnode, "./name"); + } else + vrfname = VRF_DEFAULT_NAME; + + snprintf(mesh_group_xpath, sizeof(mesh_group_xpath), + FRR_PIM_AF_XPATH, + "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); + strlcat(mesh_group_xpath, "/msdp-mesh-group", sizeof(mesh_group_xpath)); + + snprintf(group_member_xpath, sizeof(group_member_xpath), + FRR_PIM_AF_XPATH, + "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); + snprintf(temp_xpath, sizeof(temp_xpath), + "/msdp-mesh-group/member-ip[.='%s']", argv[6]->arg); + strlcat(group_member_xpath, temp_xpath, sizeof(group_member_xpath)); + + snprintf(source_xpath, sizeof(source_xpath), + FRR_PIM_AF_XPATH, + "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); + snprintf(temp_xpath, sizeof(temp_xpath), + "/msdp-mesh-group/source-ip"); + strlcat(source_xpath, temp_xpath, sizeof(source_xpath)); + + snprintf(mesh_group_name_xpath, sizeof(mesh_group_name_xpath), + FRR_PIM_AF_XPATH, + "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); + strlcat(mesh_group_name_xpath, "/msdp-mesh-group/mesh-group-name", + sizeof(mesh_group_name_xpath)); + + if (yang_dnode_exists(running_config->dnode, mesh_group_name_xpath) + == true) { + mesh_group_name = yang_dnode_get_string(running_config->dnode, + mesh_group_name_xpath); + if (strcmp(mesh_group_name, argv[4]->arg)) { + vty_out(vty, "%% mesh-group does not exist\n"); + return CMD_WARNING_CONFIG_FAILED; + } } - result = pim_msdp_mg_src_add(pim, mg, src_ip); - switch (result) { - case PIM_MSDP_ERR_NONE: - break; - case PIM_MSDP_ERR_OOM: - vty_out(vty, "%% Out of memory\n"); - break; - case PIM_MSDP_ERR_MAX_MESH_GROUPS: - vty_out(vty, "%% Only one mesh-group allowed currently\n"); - break; - default: - vty_out(vty, "%% source add failed\n"); + if (yang_dnode_exists(vty->candidate_config->dnode, + group_member_xpath)) { + if (!yang_dnode_exists(vty->candidate_config->dnode, + source_xpath)) { + member_dnode = yang_dnode_get( + vty->candidate_config->dnode, + group_member_xpath); + if (yang_is_last_list_dnode(member_dnode)) { + nb_cli_enqueue_change(vty, mesh_group_xpath, + NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); + } + nb_cli_enqueue_change(vty, group_member_xpath, + NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); + } + nb_cli_enqueue_change(vty, group_member_xpath, + NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); } - return result ? CMD_WARNING_CONFIG_FAILED : CMD_SUCCESS; -} + vty_out(vty, "%% mesh-group member does not exist\n"); + return CMD_SUCCESS; +} DEFUN (ip_msdp_mesh_group_source, ip_msdp_mesh_group_source_cmd, @@ -9914,48 +9922,42 @@ DEFUN (ip_msdp_mesh_group_source, "mesh group local address\n" "source ip address for the TCP connection\n") { - PIM_DECLVAR_CONTEXT(vrf, pim); - return ip_msdp_mesh_group_source_cmd_worker(pim, vty, argv[3]->arg, - argv[5]->arg); -} - -static int ip_no_msdp_mesh_group_source_cmd_worker(struct pim_instance *pim, - struct vty *vty, - const char *mg) -{ - enum pim_msdp_err result; + const struct lyd_node *vrf_dnode; + const char *vrfname; + char msdp_mesh_source_ip_xpath[XPATH_MAXLEN]; + char msdp_mesh_group_name_xpath[XPATH_MAXLEN]; - result = pim_msdp_mg_src_del(pim, mg); - switch (result) { - case PIM_MSDP_ERR_NONE: - break; - case PIM_MSDP_ERR_NO_MG: - vty_out(vty, "%% mesh-group does not exist\n"); - break; - default: - vty_out(vty, "%% mesh-group source del failed\n"); - } + if (vty->xpath_index) { + vrf_dnode = + yang_dnode_get(vty->candidate_config->dnode, + VTY_CURR_XPATH); + if (!vrf_dnode) { + vty_out(vty, + "%% Failed to get vrf dnode in candidate db\n"); + return CMD_WARNING_CONFIG_FAILED; + } + vrfname = yang_dnode_get_string(vrf_dnode, "./name"); + } else + vrfname = VRF_DEFAULT_NAME; - return result ? CMD_WARNING_CONFIG_FAILED : CMD_SUCCESS; -} + snprintf(msdp_mesh_group_name_xpath, sizeof(msdp_mesh_group_name_xpath), + FRR_PIM_AF_XPATH, + "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); + strlcat(msdp_mesh_group_name_xpath, "/msdp-mesh-group/mesh-group-name", + sizeof(msdp_mesh_group_name_xpath)); -static int ip_no_msdp_mesh_group_cmd_worker(struct pim_instance *pim, - struct vty *vty, const char *mg) -{ - enum pim_msdp_err result; + snprintf(msdp_mesh_source_ip_xpath, sizeof(msdp_mesh_source_ip_xpath), + FRR_PIM_AF_XPATH, + "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); + strlcat(msdp_mesh_source_ip_xpath, "/msdp-mesh-group/source-ip", + sizeof(msdp_mesh_source_ip_xpath)); - result = pim_msdp_mg_del(pim, mg); - switch (result) { - case PIM_MSDP_ERR_NONE: - break; - case PIM_MSDP_ERR_NO_MG: - vty_out(vty, "%% mesh-group does not exist\n"); - break; - default: - vty_out(vty, "%% mesh-group source del failed\n"); - } + nb_cli_enqueue_change(vty, msdp_mesh_group_name_xpath, NB_OP_MODIFY, + argv[3]->arg); + nb_cli_enqueue_change(vty, msdp_mesh_source_ip_xpath, NB_OP_MODIFY, + argv[5]->arg); - return result ? CMD_WARNING_CONFIG_FAILED : CMD_SUCCESS; + return nb_cli_apply_changes(vty, NULL); } DEFUN (no_ip_msdp_mesh_group_source, @@ -9969,9 +9971,69 @@ DEFUN (no_ip_msdp_mesh_group_source, "mesh group source\n" "mesh group local address\n") { - PIM_DECLVAR_CONTEXT(vrf, pim); + const struct lyd_node *vrf_dnode; + const char *vrfname; + char msdp_mesh_xpath[XPATH_MAXLEN]; + char source_xpath[XPATH_MAXLEN]; + char group_member_xpath[XPATH_MAXLEN]; + char mesh_group_name_xpath[XPATH_MAXLEN]; + const char *mesh_group_name; + + if (vty->xpath_index) { + vrf_dnode = + yang_dnode_get(vty->candidate_config->dnode, + VTY_CURR_XPATH); + if (!vrf_dnode) { + vty_out(vty, + "%% Failed to get vrf dnode in candidate db\n"); + return CMD_WARNING_CONFIG_FAILED; + } + vrfname = yang_dnode_get_string(vrf_dnode, "./name"); + } else + vrfname = VRF_DEFAULT_NAME; + + snprintf(msdp_mesh_xpath, sizeof(msdp_mesh_xpath), + FRR_PIM_AF_XPATH, + "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); + strlcat(msdp_mesh_xpath, "/msdp-mesh-group", sizeof(msdp_mesh_xpath)); + + snprintf(source_xpath, sizeof(source_xpath), + FRR_PIM_AF_XPATH, + "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); + strlcat(source_xpath, "/msdp-mesh-group/source-ip", + sizeof(source_xpath)); + + snprintf(group_member_xpath, + sizeof(group_member_xpath), + FRR_PIM_AF_XPATH, + "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); + strlcat(group_member_xpath, "/msdp-mesh-group/member-ip", + sizeof(group_member_xpath)); + + snprintf(mesh_group_name_xpath, sizeof(mesh_group_name_xpath), + FRR_PIM_AF_XPATH, + "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); + strlcat(mesh_group_name_xpath, "/msdp-mesh-group/mesh-group-name", + sizeof(mesh_group_name_xpath)); + + if (yang_dnode_exists(running_config->dnode, mesh_group_name_xpath) + == true) { + mesh_group_name = yang_dnode_get_string(running_config->dnode, + mesh_group_name_xpath); + if (strcmp(mesh_group_name, argv[4]->arg)) { + vty_out(vty, "%% mesh-group does not exist\n"); + return CMD_WARNING_CONFIG_FAILED; + } + } - return ip_no_msdp_mesh_group_source_cmd_worker(pim, vty, argv[4]->arg); + if (!yang_dnode_exists(vty->candidate_config->dnode, + group_member_xpath)) { + nb_cli_enqueue_change(vty, msdp_mesh_xpath, NB_OP_DESTROY, + NULL); + return nb_cli_apply_changes(vty, NULL); + } + nb_cli_enqueue_change(vty, source_xpath, NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); } DEFUN (no_ip_msdp_mesh_group, @@ -9983,12 +10045,50 @@ DEFUN (no_ip_msdp_mesh_group, "Delete MSDP mesh-group\n" "mesh group name") { - PIM_DECLVAR_CONTEXT(vrf, pim); + const struct lyd_node *vrf_dnode; + const char *vrfname; + const char *mesh_group_name; + char xpath[XPATH_MAXLEN]; + char msdp_mesh_xpath[XPATH_MAXLEN]; + + if (vty->xpath_index) { + vrf_dnode = + yang_dnode_get(vty->candidate_config->dnode, + VTY_CURR_XPATH); + if (!vrf_dnode) { + vty_out(vty, + "%% Failed to get vrf dnode in candidate db\n"); + return CMD_WARNING_CONFIG_FAILED; + } + vrfname = yang_dnode_get_string(vrf_dnode, "./name"); + } else + vrfname = VRF_DEFAULT_NAME; + + if (argc == 5) { + snprintf(xpath, sizeof(xpath), FRR_PIM_AF_XPATH, "frr-pim:pimd", + "pim", vrfname, "frr-routing:ipv4"); + strlcat(xpath, "/msdp-mesh-group/mesh-group-name", + sizeof(xpath)); + + if (yang_dnode_exists(running_config->dnode, xpath) == true) { + mesh_group_name = + yang_dnode_get_string(running_config->dnode, + xpath); + + if (strcmp(mesh_group_name, argv[4]->arg)) { + vty_out(vty, "%% mesh-group does not exist\n"); + return CMD_WARNING_CONFIG_FAILED; + } + } + } - if (argc == 5) - return ip_no_msdp_mesh_group_cmd_worker(pim, vty, argv[4]->arg); - else - return ip_no_msdp_mesh_group_cmd_worker(pim, vty, NULL); + snprintf(msdp_mesh_xpath, sizeof(msdp_mesh_xpath), + FRR_PIM_AF_XPATH, + "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); + strlcat(msdp_mesh_xpath, "/msdp-mesh-group", sizeof(msdp_mesh_xpath)); + + nb_cli_enqueue_change(vty, msdp_mesh_xpath, NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); } static void print_empty_json_obj(struct vty *vty) @@ -11008,14 +11108,16 @@ DEFUN_HIDDEN (no_ip_pim_mlag, PIM_STR "MLAG\n") { - struct in_addr addr; + char mlag_xpath[XPATH_MAXLEN]; - addr.s_addr = 0; - pim_vxlan_mlag_update(true/*mlag_enable*/, - false/*peer_state*/, MLAG_ROLE_NONE, - NULL/*peerlink*/, &addr); + snprintf(mlag_xpath, sizeof(mlag_xpath), FRR_PIM_AF_XPATH, + "frr-pim:pimd", "pim", "default", "frr-routing:ipv4"); + strlcat(mlag_xpath, "/mlag", sizeof(mlag_xpath)); - return CMD_SUCCESS; + nb_cli_enqueue_change(vty, mlag_xpath, NB_OP_DESTROY, NULL); + + + return nb_cli_apply_changes(vty, NULL); } DEFUN_HIDDEN (ip_pim_mlag, @@ -11034,53 +11136,73 @@ DEFUN_HIDDEN (ip_pim_mlag, "configure PIP\n" "unique ip address\n") { - struct interface *ifp; - const char *peerlink; - uint32_t role; int idx; - bool peer_state; - int result; - struct in_addr reg_addr; + char mlag_peerlink_rif_xpath[XPATH_MAXLEN]; + char mlag_my_role_xpath[XPATH_MAXLEN]; + char mlag_peer_state_xpath[XPATH_MAXLEN]; + char mlag_reg_address_xpath[XPATH_MAXLEN]; + + snprintf(mlag_peerlink_rif_xpath, sizeof(mlag_peerlink_rif_xpath), + FRR_PIM_AF_XPATH, + "frr-pim:pimd", "pim", "default", "frr-routing:ipv4"); + strlcat(mlag_peerlink_rif_xpath, "/mlag/peerlink-rif", + sizeof(mlag_peerlink_rif_xpath)); idx = 3; - peerlink = argv[idx]->arg; - ifp = if_lookup_by_name(peerlink, VRF_DEFAULT); - if (!ifp) { - vty_out(vty, "No such interface name %s\n", peerlink); - return CMD_WARNING; - } + nb_cli_enqueue_change(vty, mlag_peerlink_rif_xpath, NB_OP_MODIFY, + argv[idx]->arg); + + snprintf(mlag_my_role_xpath, sizeof(mlag_my_role_xpath), + FRR_PIM_AF_XPATH, + "frr-pim:pimd", "pim", "default", "frr-routing:ipv4"); + strlcat(mlag_my_role_xpath, "/mlag/my-role", + sizeof(mlag_my_role_xpath)); idx += 2; if (!strcmp(argv[idx]->arg, "primary")) { - role = MLAG_ROLE_PRIMARY; + nb_cli_enqueue_change(vty, mlag_my_role_xpath, NB_OP_MODIFY, + "MLAG_ROLE_PRIMARY"); + } else if (!strcmp(argv[idx]->arg, "secondary")) { - role = MLAG_ROLE_SECONDARY; + nb_cli_enqueue_change(vty, mlag_my_role_xpath, NB_OP_MODIFY, + "MLAG_ROLE_SECONDARY"); + } else { vty_out(vty, "unknown MLAG role %s\n", argv[idx]->arg); return CMD_WARNING; } + snprintf(mlag_peer_state_xpath, sizeof(mlag_peer_state_xpath), + FRR_PIM_AF_XPATH, + "frr-pim:pimd", "pim", "default", "frr-routing:ipv4"); + strlcat(mlag_peer_state_xpath, "/mlag/peer-state", + sizeof(mlag_peer_state_xpath)); + idx += 2; if (!strcmp(argv[idx]->arg, "up")) { - peer_state = true; + nb_cli_enqueue_change(vty, mlag_peer_state_xpath, NB_OP_MODIFY, + "true"); + } else if (strcmp(argv[idx]->arg, "down")) { - peer_state = false; + nb_cli_enqueue_change(vty, mlag_peer_state_xpath, NB_OP_MODIFY, + "false"); + } else { vty_out(vty, "unknown MLAG state %s\n", argv[idx]->arg); return CMD_WARNING; } + snprintf(mlag_reg_address_xpath, sizeof(mlag_reg_address_xpath), + FRR_PIM_AF_XPATH, + "frr-pim:pimd", "pim", "default", "frr-routing:ipv4"); + strlcat(mlag_reg_address_xpath, "/mlag/reg-address", + sizeof(mlag_reg_address_xpath)); + idx += 2; - result = inet_pton(AF_INET, argv[idx]->arg, ®_addr); - if (result <= 0) { - vty_out(vty, "%% Bad reg address %s: errno=%d: %s\n", - argv[idx]->arg, - errno, safe_strerror(errno)); - return CMD_WARNING_CONFIG_FAILED; - } - pim_vxlan_mlag_update(true, peer_state, role, ifp, ®_addr); + nb_cli_enqueue_change(vty, mlag_reg_address_xpath, NB_OP_MODIFY, + argv[idx]->arg); - return CMD_SUCCESS; + return nb_cli_apply_changes(vty, NULL); } void pim_cmd_init(void) diff --git a/pimd/pim_main.c b/pimd/pim_main.c index 132d913f6..b7ca90ad9 100644 --- a/pimd/pim_main.c +++ b/pimd/pim_main.c @@ -38,6 +38,7 @@ #include "vrf.h" #include "libfrr.h" #include "routemap.h" +#include "routing_nb.h" #include "pimd.h" #include "pim_instance.h" @@ -49,6 +50,7 @@ #include "pim_bfd.h" #include "pim_mlag.h" #include "pim_errors.h" +#include "pim_nb.h" extern struct host host; @@ -77,6 +79,10 @@ static const struct frr_yang_module_info *const pimd_yang_modules[] = { &frr_interface_info, &frr_route_map_info, &frr_vrf_info, + &frr_routing_info, + &frr_pim_info, + &frr_pim_rp_info, + &frr_igmp_info, }; FRR_DAEMON_INFO(pimd, PIM, .vty_port = PIMD_VTY_PORT, @@ -137,6 +143,9 @@ int main(int argc, char **argv, char **envp) pim_bfd_init(); pim_mlag_init(); + hook_register(routing_conf_event, + routing_control_plane_protocols_name_validate); + frr_config_fork(); #ifdef PIM_DEBUG_BYDEFAULT diff --git a/pimd/pim_nb.c b/pimd/pim_nb.c new file mode 100644 index 000000000..8ca0e0780 --- /dev/null +++ b/pimd/pim_nb.c @@ -0,0 +1,417 @@ +/* + * Copyright (C) 2020 VmWare + * Sarita Patra + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <zebra.h> + +#include "northbound.h" +#include "libfrr.h" +#include "vrf.h" +#include "pimd/pim_nb.h" + +/* clang-format off */ +const struct frr_yang_module_info frr_pim_info = { + .name = "frr-pim", + .nodes = { + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/ecmp", + .cbs = { + .modify = routing_control_plane_protocols_control_plane_protocol_pim_ecmp_modify, + } + }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/ecmp-rebalance", + .cbs = { + .modify = routing_control_plane_protocols_control_plane_protocol_pim_ecmp_rebalance_modify, + } + }, + { + .xpath = "/frr-pim:pim/join-prune-interval", + .cbs = { + .modify = pim_join_prune_interval_modify, + } + }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/keep-alive-timer", + .cbs = { + .modify = routing_control_plane_protocols_control_plane_protocol_pim_keep_alive_timer_modify, + } + }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/rp-keep-alive-timer", + .cbs = { + .modify = routing_control_plane_protocols_control_plane_protocol_pim_rp_keep_alive_timer_modify, + } + }, + { + .xpath = "/frr-pim:pim/packets", + .cbs = { + .modify = pim_packets_modify, + } + }, + { + .xpath = "/frr-pim:pim/register-suppress-time", + .cbs = { + .modify = pim_register_suppress_time_modify, + } + }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family", + .cbs = { + .create = routing_control_plane_protocols_control_plane_protocol_pim_address_family_create, + .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_destroy, + } + }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/send-v6-secondary", + .cbs = { + .modify = routing_control_plane_protocols_control_plane_protocol_pim_address_family_send_v6_secondary_modify, + .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_send_v6_secondary_destroy, + } + }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/spt-switchover", + .cbs = { + .apply_finish = routing_control_plane_protocols_control_plane_protocol_pim_address_family_spt_switchover_apply_finish, + } + }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/spt-switchover/spt-action", + .cbs = { + .modify = routing_control_plane_protocols_control_plane_protocol_pim_address_family_spt_switchover_spt_action_modify, + } + }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/spt-switchover/spt-infinity-prefix-list", + .cbs = { + .modify = routing_control_plane_protocols_control_plane_protocol_pim_address_family_spt_switchover_spt_infinity_prefix_list_modify, + .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_spt_switchover_spt_infinity_prefix_list_destroy, + } + }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/ssm-prefix-list", + .cbs = { + .modify = routing_control_plane_protocols_control_plane_protocol_pim_address_family_ssm_prefix_list_modify, + .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_ssm_prefix_list_destroy, + } + }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/ssm-pingd-source-ip", + .cbs = { + .create = routing_control_plane_protocols_control_plane_protocol_pim_address_family_ssm_pingd_source_ip_create, + .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_ssm_pingd_source_ip_destroy, + } + }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-mesh-group", + .cbs = { + .create = routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_create, + .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_destroy, + } + }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-mesh-group/mesh-group-name", + .cbs = { + .modify = routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_mesh_group_name_modify, + .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_mesh_group_name_destroy, + } + }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-mesh-group/member-ip", + .cbs = { + .create = routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_member_ip_create, + .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_member_ip_destroy, + } + }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-mesh-group/source-ip", + .cbs = { + .modify = routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_source_ip_modify, + .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_source_ip_destroy, + } + }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-peer", + .cbs = { + .create = routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_peer_create, + .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_peer_destroy, + } + }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-peer/source-ip", + .cbs = { + .modify = routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_peer_source_ip_modify, + .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_peer_source_ip_destroy, + } + }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/mlag", + .cbs = { + .create = routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_create, + .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_destroy, + .apply_finish = routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_apply_finish, + } + }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/mlag/peerlink-rif", + .cbs = { + .modify = routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_peerlink_rif_modify, + .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_peerlink_rif_destroy, + } + }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/mlag/reg-address", + .cbs = { + .modify = routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_reg_address_modify, + .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_reg_address_destroy, + } + }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/mlag/my-role", + .cbs = { + .modify = routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_my_role_modify, + } + }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/mlag/peer-state", + .cbs = { + .modify = routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_peer_state_modify, + } + }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/register-accept-list", + .cbs = { + .modify = routing_control_plane_protocols_control_plane_protocol_pim_address_family_register_accept_list_modify, + .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_register_accept_list_destroy, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-pim:pim", + .cbs = { + .create = lib_interface_pim_create, + .destroy = lib_interface_pim_destroy, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-pim:pim/pim-enable", + .cbs = { + .modify = lib_interface_pim_pim_enable_modify, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-pim:pim/dr-priority", + .cbs = { + .modify = lib_interface_pim_dr_priority_modify, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-pim:pim/hello-interval", + .cbs = { + .modify = lib_interface_pim_hello_interval_modify, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-pim:pim/hello-holdtime", + .cbs = { + .modify = lib_interface_pim_hello_holdtime_modify, + .destroy = lib_interface_pim_hello_holdtime_destroy, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-pim:pim/bfd", + .cbs = { + .create = lib_interface_pim_bfd_create, + .destroy = lib_interface_pim_bfd_destroy, + .apply_finish = lib_interface_pim_bfd_apply_finish, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-pim:pim/bfd/min-rx-interval", + .cbs = { + .modify = lib_interface_pim_bfd_min_rx_interval_modify, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-pim:pim/bfd/min-tx-interval", + .cbs = { + .modify = lib_interface_pim_bfd_min_tx_interval_modify, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-pim:pim/bfd/detect_mult", + .cbs = { + .modify = lib_interface_pim_bfd_detect_mult_modify, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-pim:pim/bsm", + .cbs = { + .modify = lib_interface_pim_bsm_modify, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-pim:pim/unicast-bsm", + .cbs = { + .modify = lib_interface_pim_unicast_bsm_modify, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-pim:pim/active-active", + .cbs = { + .modify = lib_interface_pim_active_active_modify, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-pim:pim/address-family", + .cbs = { + .create = lib_interface_pim_address_family_create, + .destroy = lib_interface_pim_address_family_destroy, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-pim:pim/address-family/use-source", + .cbs = { + .modify = lib_interface_pim_address_family_use_source_modify, + .destroy = lib_interface_pim_address_family_use_source_destroy, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-pim:pim/address-family/multicast-boundary-oil", + .cbs = { + .modify = lib_interface_pim_address_family_multicast_boundary_oil_modify, + .destroy = lib_interface_pim_address_family_multicast_boundary_oil_destroy, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-pim:pim/address-family/mroute", + .cbs = { + .create = lib_interface_pim_address_family_mroute_create, + .destroy = lib_interface_pim_address_family_mroute_destroy, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-pim:pim/address-family/mroute/oif", + .cbs = { + .modify = lib_interface_pim_address_family_mroute_oif_modify, + .destroy = lib_interface_pim_address_family_mroute_oif_destroy, + } + }, + { + .xpath = NULL, + }, + } +}; + +/* clang-format off */ +const struct frr_yang_module_info frr_pim_rp_info = { + .name = "frr-pim-rp", + .nodes = { + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-rp:rp/static-rp/rp-list", + .cbs = { + .create = routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_static_rp_rp_list_create, + .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_static_rp_rp_list_destroy, + } + }, + { + .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", + .cbs = { + .create = routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_static_rp_rp_list_group_list_create, + .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_static_rp_rp_list_group_list_destroy, + } + }, + { + .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", + .cbs = { + .modify = routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_static_rp_rp_list_prefix_list_modify, + .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_static_rp_rp_list_prefix_list_destroy, + } + }, + { + .xpath = NULL, + }, + } +}; + +/* clang-format off */ +const struct frr_yang_module_info frr_igmp_info = { + .name = "frr-igmp", + .nodes = { + { + .xpath = "/frr-interface:lib/interface/frr-igmp:igmp", + .cbs = { + .create = lib_interface_igmp_create, + .destroy = lib_interface_igmp_destroy, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-igmp:igmp/igmp-enable", + .cbs = { + .modify = lib_interface_igmp_igmp_enable_modify, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-igmp:igmp/version", + .cbs = { + .modify = lib_interface_igmp_version_modify, + .destroy = lib_interface_igmp_version_destroy, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-igmp:igmp/query-interval", + .cbs = { + .modify = lib_interface_igmp_query_interval_modify, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-igmp:igmp/query-max-response-time", + .cbs = { + .modify = lib_interface_igmp_query_max_response_time_modify, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-igmp:igmp/last-member-query-interval", + .cbs = { + .modify = lib_interface_igmp_last_member_query_interval_modify, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-igmp:igmp/robustness-variable", + .cbs = { + .modify = lib_interface_igmp_robustness_variable_modify, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-igmp:igmp/address-family", + .cbs = { + .create = lib_interface_igmp_address_family_create, + .destroy = lib_interface_igmp_address_family_destroy, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-igmp:igmp/address-family/static-group", + .cbs = { + .create = lib_interface_igmp_address_family_static_group_create, + .destroy = lib_interface_igmp_address_family_static_group_destroy, + } + }, + { + .xpath = NULL, + }, + } +}; diff --git a/pimd/pim_nb.h b/pimd/pim_nb.h new file mode 100644 index 000000000..78eb68010 --- /dev/null +++ b/pimd/pim_nb.h @@ -0,0 +1,203 @@ +/* + * Copyright (C) 2020 VmWare + * Sarita Patra + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _FRR_PIM_NB_H_ +#define _FRR_PIM_NB_H_ + +extern const struct frr_yang_module_info frr_pim_info; +extern const struct frr_yang_module_info frr_pim_rp_info; +extern const struct frr_yang_module_info frr_igmp_info; + +/* frr-pim prototypes*/ +int routing_control_plane_protocols_control_plane_protocol_pim_ecmp_modify( + struct nb_cb_modify_args *args); +int routing_control_plane_protocols_control_plane_protocol_pim_ecmp_rebalance_modify( + struct nb_cb_modify_args *args); +int pim_join_prune_interval_modify(struct nb_cb_modify_args *args); +int routing_control_plane_protocols_control_plane_protocol_pim_keep_alive_timer_modify( + struct nb_cb_modify_args *args); +int routing_control_plane_protocols_control_plane_protocol_pim_rp_keep_alive_timer_modify( + struct nb_cb_modify_args *args); +int pim_packets_modify(struct nb_cb_modify_args *args); +int pim_register_suppress_time_modify(struct nb_cb_modify_args *args); +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_create( + struct nb_cb_create_args *args); +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_destroy( + struct nb_cb_destroy_args *args); +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_send_v6_secondary_modify( + struct nb_cb_modify_args *args); +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_send_v6_secondary_destroy( + struct nb_cb_destroy_args *args); +void routing_control_plane_protocols_control_plane_protocol_pim_address_family_spt_switchover_apply_finish( + struct nb_cb_apply_finish_args *args); +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_spt_switchover_spt_action_modify( + struct nb_cb_modify_args *args); +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_spt_switchover_spt_infinity_prefix_list_modify( + struct nb_cb_modify_args *args); +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_spt_switchover_spt_infinity_prefix_list_destroy( + struct nb_cb_destroy_args *args); +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_ssm_prefix_list_modify( + struct nb_cb_modify_args *args); +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_ssm_prefix_list_destroy( + struct nb_cb_destroy_args *args); +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_ssm_pingd_source_ip_create( + struct nb_cb_create_args *args); +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_ssm_pingd_source_ip_destroy( + struct nb_cb_destroy_args *args); +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_create( + struct nb_cb_create_args *args); +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_destroy( + struct nb_cb_destroy_args *args); +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_mesh_group_name_modify( + struct nb_cb_modify_args *args); +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_mesh_group_name_destroy( + struct nb_cb_destroy_args *args); +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_member_ip_create( + struct nb_cb_create_args *args); +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_member_ip_destroy( + struct nb_cb_destroy_args *args); +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_source_ip_modify( + struct nb_cb_modify_args *args); +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_source_ip_destroy( + struct nb_cb_destroy_args *args); +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_peer_create( + struct nb_cb_create_args *args); +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_peer_destroy( + struct nb_cb_destroy_args *args); +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_peer_source_ip_modify( + struct nb_cb_modify_args *args); +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_peer_source_ip_destroy( + struct nb_cb_destroy_args *args); +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_create( + struct nb_cb_create_args *args); +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_destroy( + struct nb_cb_destroy_args *args); +void routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_apply_finish( + struct nb_cb_apply_finish_args *args); +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_peerlink_rif_modify( + struct nb_cb_modify_args *args); +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_peerlink_rif_destroy( + struct nb_cb_destroy_args *args); +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_reg_address_modify( + struct nb_cb_modify_args *args); +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_reg_address_destroy( + struct nb_cb_destroy_args *args); +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_my_role_modify( + struct nb_cb_modify_args *args); +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_peer_state_modify( + struct nb_cb_modify_args *args); +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_register_accept_list_modify( + struct nb_cb_modify_args *args); +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_register_accept_list_destroy( + struct nb_cb_destroy_args *args); +int lib_interface_pim_dr_priority_modify( + struct nb_cb_modify_args *args); +int lib_interface_pim_create(struct nb_cb_create_args *args); +int lib_interface_pim_destroy(struct nb_cb_destroy_args *args); +int lib_interface_pim_pim_enable_modify(struct nb_cb_modify_args *args); +int lib_interface_pim_hello_interval_modify(struct nb_cb_modify_args *args); +int lib_interface_pim_hello_holdtime_modify(struct nb_cb_modify_args *args); +int lib_interface_pim_hello_holdtime_destroy(struct nb_cb_destroy_args *args); +int lib_interface_pim_bfd_create(struct nb_cb_create_args *args); +int lib_interface_pim_bfd_destroy(struct nb_cb_destroy_args *args); +void lib_interface_pim_bfd_apply_finish(struct nb_cb_apply_finish_args *args); +int lib_interface_pim_bfd_min_rx_interval_modify(struct nb_cb_modify_args *args); +int lib_interface_pim_bfd_min_tx_interval_modify( + struct nb_cb_modify_args *args); +int lib_interface_pim_bfd_detect_mult_modify(struct nb_cb_modify_args *args); +int lib_interface_pim_bsm_modify(struct nb_cb_modify_args *args); +int lib_interface_pim_unicast_bsm_modify(struct nb_cb_modify_args *args); +int lib_interface_pim_active_active_modify(struct nb_cb_modify_args *args); +int lib_interface_pim_address_family_create(struct nb_cb_create_args *args); +int lib_interface_pim_address_family_destroy(struct nb_cb_destroy_args *args); +int lib_interface_pim_address_family_use_source_modify( + struct nb_cb_modify_args *args); +int lib_interface_pim_address_family_use_source_destroy( + struct nb_cb_destroy_args *args); +int lib_interface_pim_address_family_multicast_boundary_oil_modify( + struct nb_cb_modify_args *args); +int lib_interface_pim_address_family_multicast_boundary_oil_destroy( + struct nb_cb_destroy_args *args); +int lib_interface_pim_address_family_mroute_create( + struct nb_cb_create_args *args); +int lib_interface_pim_address_family_mroute_destroy( + struct nb_cb_destroy_args *args); +int lib_interface_pim_address_family_mroute_oif_modify( + struct nb_cb_modify_args *args); +int lib_interface_pim_address_family_mroute_oif_destroy( + struct nb_cb_destroy_args *args); + +/* frr-pim-rp prototypes*/ +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_static_rp_rp_list_create( + struct nb_cb_create_args *args); +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_static_rp_rp_list_destroy( + struct nb_cb_destroy_args *args); +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_static_rp_rp_list_group_list_create( + struct nb_cb_create_args *args); +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_static_rp_rp_list_group_list_destroy( + struct nb_cb_destroy_args *args); +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_static_rp_rp_list_prefix_list_modify( + struct nb_cb_modify_args *args); +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_static_rp_rp_list_prefix_list_destroy( + struct nb_cb_destroy_args *args); + +/* frr-igmp prototypes*/ +int lib_interface_igmp_create(struct nb_cb_create_args *args); +int lib_interface_igmp_destroy(struct nb_cb_destroy_args *args); +int lib_interface_igmp_igmp_enable_modify(struct nb_cb_modify_args *args); +int lib_interface_igmp_version_modify(struct nb_cb_modify_args *args); +int lib_interface_igmp_version_destroy(struct nb_cb_destroy_args *args); +int lib_interface_igmp_query_interval_modify(struct nb_cb_modify_args *args); +int lib_interface_igmp_query_max_response_time_modify( + struct nb_cb_modify_args *args); +int lib_interface_igmp_last_member_query_interval_modify( + struct nb_cb_modify_args *args); +int lib_interface_igmp_robustness_variable_modify( + struct nb_cb_modify_args *args); +int lib_interface_igmp_address_family_create(struct nb_cb_create_args *args); +int lib_interface_igmp_address_family_destroy(struct nb_cb_destroy_args *args); +int lib_interface_igmp_address_family_static_group_create( + struct nb_cb_create_args *args); +int lib_interface_igmp_address_family_static_group_destroy( + struct nb_cb_destroy_args *args); + +/* + * Callback registered with routing_nb lib to validate only + * one instance of staticd is allowed + */ +int routing_control_plane_protocols_name_validate( + struct nb_cb_create_args *args); + +#define FRR_PIM_XPATH \ + "/frr-routing:routing/control-plane-protocols/" \ + "control-plane-protocol[type='%s'][name='%s'][vrf='%s']/" \ + "frr-pim:pim" +#define FRR_PIM_AF_XPATH \ + "/frr-routing:routing/control-plane-protocols/" \ + "control-plane-protocol[type='%s'][name='%s'][vrf='%s']/" \ + "frr-pim:pim/address-family[address-family='%s']" +#define FRR_PIM_STATIC_RP_XPATH \ + "/frr-routing:routing/control-plane-protocols/" \ + "control-plane-protocol[type='%s'][name='%s'][vrf='%s']/" \ + "frr-pim:pim/address-family[address-family='%s']/" \ + "frr-pim-rp:rp/static-rp/rp-list[rp-address='%s']" +#define FRR_IGMP_JOIN_XPATH \ + "./frr-igmp:igmp/address-family[address-family='%s']/" \ + "static-group[group-addr='%s'][source-addr='%s']" +#endif /* _FRR_PIM_NB_H_ */ diff --git a/pimd/pim_nb_config.c b/pimd/pim_nb_config.c new file mode 100644 index 000000000..9f7e5286f --- /dev/null +++ b/pimd/pim_nb_config.c @@ -0,0 +1,3034 @@ +/* + * Copyright (C) 2020 VmWare + * Sarita Patra + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "pimd.h" +#include "pim_nb.h" +#include "lib/northbound_cli.h" +#include "pim_igmpv3.h" +#include "pim_pim.h" +#include "pim_mlag.h" +#include "pim_bfd.h" +#include "pim_static.h" +#include "pim_ssm.h" +#include "pim_ssmpingd.h" +#include "pim_vxlan.h" + +static void pim_if_membership_clear(struct interface *ifp) +{ + struct pim_interface *pim_ifp; + + pim_ifp = ifp->info; + zassert(pim_ifp); + + if (PIM_IF_TEST_PIM(pim_ifp->options) + && PIM_IF_TEST_IGMP(pim_ifp->options)) { + return; + } + + pim_ifchannel_membership_clear(ifp); +} + +/* + * When PIM is disabled on interface, IGMPv3 local membership + * information is not injected into PIM interface state. + + * The function pim_if_membership_refresh() fetches all IGMPv3 local + * membership information into PIM. It is intented to be called + * whenever PIM is enabled on the interface in order to collect missed + * local membership information. + */ +static void pim_if_membership_refresh(struct interface *ifp) +{ + struct pim_interface *pim_ifp; + struct listnode *sock_node; + struct igmp_sock *igmp; + + pim_ifp = ifp->info; + zassert(pim_ifp); + + if (!PIM_IF_TEST_PIM(pim_ifp->options)) + return; + if (!PIM_IF_TEST_IGMP(pim_ifp->options)) + return; + + /* + * First clear off membership from all PIM (S,G) entries on the + * interface + */ + + pim_ifchannel_membership_clear(ifp); + + /* + * Then restore PIM (S,G) membership from all IGMPv3 (S,G) entries on + * the interface + */ + + /* scan igmp sockets */ + for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, sock_node, igmp)) { + struct listnode *grpnode; + struct igmp_group *grp; + + /* scan igmp groups */ + for (ALL_LIST_ELEMENTS_RO(igmp->igmp_group_list, grpnode, + grp)) { + struct listnode *srcnode; + struct igmp_source *src; + + /* scan group sources */ + for (ALL_LIST_ELEMENTS_RO(grp->group_source_list, + srcnode, src)) { + + if (IGMP_SOURCE_TEST_FORWARDING( + src->source_flags)) { + struct prefix_sg sg; + + memset(&sg, 0, + sizeof(struct prefix_sg)); + sg.src = src->source_addr; + sg.grp = grp->group_addr; + pim_ifchannel_local_membership_add( + ifp, &sg, false /*is_vxlan*/); + } + + } /* scan group sources */ + } /* scan igmp groups */ + } /* scan igmp sockets */ + + /* + * Finally delete every PIM (S,G) entry lacking all state info + */ + + pim_ifchannel_delete_on_noinfo(ifp); +} + +static int pim_cmd_interface_add(struct interface *ifp) +{ + struct pim_interface *pim_ifp = ifp->info; + + if (!pim_ifp) + pim_ifp = pim_if_new(ifp, false, true, false, false); + else + PIM_IF_DO_PIM(pim_ifp->options); + + pim_if_addr_add_all(ifp); + pim_if_membership_refresh(ifp); + + pim_if_create_pimreg(pim_ifp->pim); + return 1; +} + +static int pim_cmd_interface_delete(struct interface *ifp) +{ + struct pim_interface *pim_ifp = ifp->info; + + if (!pim_ifp) + return 1; + + PIM_IF_DONT_PIM(pim_ifp->options); + + pim_if_membership_clear(ifp); + + /* + * pim_sock_delete() removes all neighbors from + * pim_ifp->pim_neighbor_list. + */ + pim_sock_delete(ifp, "pim unconfigured on interface"); + + if (!PIM_IF_TEST_IGMP(pim_ifp->options)) { + pim_if_addr_del_all(ifp); + pim_if_delete(ifp); + } + + return 1; +} + +static int interface_pim_use_src_cmd_worker(struct interface *ifp, + struct in_addr source_addr, + char *errmsg, size_t errmsg_len) +{ + int result; + int ret = NB_OK; + + result = pim_update_source_set(ifp, source_addr); + + switch (result) { + case PIM_SUCCESS: + break; + case PIM_IFACE_NOT_FOUND: + ret = NB_ERR; + snprintf(errmsg, errmsg_len, + "Pim not enabled on this interface %s", + ifp->name); + break; + case PIM_UPDATE_SOURCE_DUP: + ret = NB_ERR; + snprintf(errmsg, errmsg_len, "Source already set"); + break; + default: + ret = NB_ERR; + snprintf(errmsg, errmsg_len, "Source set failed"); + } + + return ret; +} + +static int pim_cmd_spt_switchover(struct pim_instance *pim, + enum pim_spt_switchover spt, + const char *plist) +{ + pim->spt.switchover = spt; + + switch (pim->spt.switchover) { + case PIM_SPT_IMMEDIATE: + XFREE(MTYPE_PIM_PLIST_NAME, pim->spt.plist); + + pim_upstream_add_lhr_star_pimreg(pim); + break; + case PIM_SPT_INFINITY: + pim_upstream_remove_lhr_star_pimreg(pim, plist); + + XFREE(MTYPE_PIM_PLIST_NAME, pim->spt.plist); + + if (plist) + pim->spt.plist = XSTRDUP(MTYPE_PIM_PLIST_NAME, plist); + break; + } + + return NB_OK; +} + +static int pim_ssm_cmd_worker(struct pim_instance *pim, const char *plist, + char *errmsg, size_t errmsg_len) +{ + int result = pim_ssm_range_set(pim, pim->vrf_id, plist); + int ret = NB_ERR; + + if (result == PIM_SSM_ERR_NONE) + return NB_OK; + + switch (result) { + case PIM_SSM_ERR_NO_VRF: + snprintf(errmsg, errmsg_len, + "VRF doesn't exist"); + break; + case PIM_SSM_ERR_DUP: + snprintf(errmsg, errmsg_len, + "duplicate config"); + break; + default: + snprintf(errmsg, errmsg_len, + "ssm range config failed"); + } + + return ret; +} + +static int ip_no_msdp_mesh_group_cmd_worker(struct pim_instance *pim, + const char *mg, + char *errmsg, size_t errmsg_len) +{ + enum pim_msdp_err result; + + result = pim_msdp_mg_del(pim, mg); + + switch (result) { + case PIM_MSDP_ERR_NONE: + break; + case PIM_MSDP_ERR_NO_MG: + snprintf(errmsg, errmsg_len, + "%% mesh-group does not exist"); + break; + default: + snprintf(errmsg, errmsg_len, + "mesh-group source del failed"); + } + + return result ? NB_ERR : NB_OK; +} + +static int ip_msdp_mesh_group_member_cmd_worker(struct pim_instance *pim, + const char *mg, + struct in_addr mbr_ip, + char *errmsg, size_t errmsg_len) +{ + enum pim_msdp_err result; + int ret = NB_OK; + + result = pim_msdp_mg_mbr_add(pim, mg, mbr_ip); + + switch (result) { + case PIM_MSDP_ERR_NONE: + break; + case PIM_MSDP_ERR_OOM: + ret = NB_ERR; + snprintf(errmsg, errmsg_len, + "%% Out of memory"); + break; + case PIM_MSDP_ERR_MG_MBR_EXISTS: + ret = NB_ERR; + snprintf(errmsg, errmsg_len, + "%% mesh-group member exists"); + break; + case PIM_MSDP_ERR_MAX_MESH_GROUPS: + ret = NB_ERR; + snprintf(errmsg, errmsg_len, + "%% Only one mesh-group allowed currently"); + break; + default: + ret = NB_ERR; + snprintf(errmsg, errmsg_len, + "%% member add failed"); + } + + return ret; +} + +static int ip_no_msdp_mesh_group_member_cmd_worker(struct pim_instance *pim, + const char *mg, + struct in_addr mbr_ip, + char *errmsg, + size_t errmsg_len) +{ + enum pim_msdp_err result; + + result = pim_msdp_mg_mbr_del(pim, mg, mbr_ip); + + switch (result) { + case PIM_MSDP_ERR_NONE: + break; + case PIM_MSDP_ERR_NO_MG: + snprintf(errmsg, errmsg_len, + "%% mesh-group does not exist"); + break; + case PIM_MSDP_ERR_NO_MG_MBR: + snprintf(errmsg, errmsg_len, + "%% mesh-group member does not exist"); + break; + default: + snprintf(errmsg, errmsg_len, + "%% mesh-group member del failed"); + } + + return result ? NB_ERR : NB_OK; +} + +static int ip_msdp_mesh_group_source_cmd_worker(struct pim_instance *pim, + const char *mg, + struct in_addr src_ip, + char *errmsg, size_t errmsg_len) +{ + enum pim_msdp_err result; + + result = pim_msdp_mg_src_add(pim, mg, src_ip); + + switch (result) { + case PIM_MSDP_ERR_NONE: + break; + case PIM_MSDP_ERR_OOM: + snprintf(errmsg, errmsg_len, + "%% Out of memory"); + break; + case PIM_MSDP_ERR_MAX_MESH_GROUPS: + snprintf(errmsg, errmsg_len, + "%% Only one mesh-group allowed currently"); + break; + default: + snprintf(errmsg, errmsg_len, + "%% source add failed"); + } + + return result ? NB_ERR : NB_OK; +} + +static int ip_no_msdp_mesh_group_source_cmd_worker(struct pim_instance *pim, + const char *mg, + char *errmsg, + size_t errmsg_len) +{ + enum pim_msdp_err result; + + result = pim_msdp_mg_src_del(pim, mg); + + switch (result) { + case PIM_MSDP_ERR_NONE: + break; + case PIM_MSDP_ERR_NO_MG: + snprintf(errmsg, errmsg_len, + "%% mesh-group does not exist"); + break; + default: + snprintf(errmsg, errmsg_len, + "%% mesh-group source del failed"); + } + + return result ? NB_ERR : NB_OK; +} + +static int ip_msdp_peer_cmd_worker(struct pim_instance *pim, + struct in_addr peer_addr, + struct in_addr local_addr, + char *errmsg, size_t errmsg_len) +{ + enum pim_msdp_err result; + int ret = NB_OK; + + result = pim_msdp_peer_add(pim, peer_addr, local_addr, "default", + NULL /* mp_p */); + switch (result) { + case PIM_MSDP_ERR_NONE: + break; + case PIM_MSDP_ERR_OOM: + ret = NB_ERR; + snprintf(errmsg, errmsg_len, + "%% Out of memory"); + break; + case PIM_MSDP_ERR_PEER_EXISTS: + ret = NB_ERR; + snprintf(errmsg, errmsg_len, + "%% Peer exists"); + break; + case PIM_MSDP_ERR_MAX_MESH_GROUPS: + ret = NB_ERR; + snprintf(errmsg, errmsg_len, + "%% Only one mesh-group allowed currently"); + break; + default: + ret = NB_ERR; + snprintf(errmsg, errmsg_len, + "%% peer add failed"); + } + + return ret; +} + +static int ip_no_msdp_peer_cmd_worker(struct pim_instance *pim, + struct in_addr peer_addr, + char *errmsg, size_t errmsg_len) +{ + enum pim_msdp_err result; + + result = pim_msdp_peer_del(pim, peer_addr); + switch (result) { + case PIM_MSDP_ERR_NONE: + break; + case PIM_MSDP_ERR_NO_PEER: + snprintf(errmsg, errmsg_len, + "%% Peer does not exist"); + break; + default: + snprintf(errmsg, errmsg_len, + "%% peer del failed"); + } + + return result ? NB_ERR : NB_OK; +} + +static int pim_rp_cmd_worker(struct pim_instance *pim, + struct in_addr rp_addr, + struct prefix group, const char *plist, + char *errmsg, size_t errmsg_len) +{ + char rp_str[INET_ADDRSTRLEN]; + int result; + + inet_ntop(AF_INET, &rp_addr, rp_str, sizeof(rp_str)); + + result = pim_rp_new(pim, rp_addr, group, plist, RP_SRC_STATIC); + + if (result == PIM_RP_NO_PATH) { + snprintf(errmsg, errmsg_len, + "No Path to RP address specified: %s", rp_str); + return NB_ERR_INCONSISTENCY; + } + + if (result == PIM_GROUP_OVERLAP) { + snprintf(errmsg, errmsg_len, + "Group range specified cannot exact match another"); + return NB_ERR_INCONSISTENCY; + } + + if (result == PIM_GROUP_PFXLIST_OVERLAP) { + snprintf(errmsg, errmsg_len, + "This group is already covered by a RP prefix-list"); + return NB_ERR_INCONSISTENCY; + } + + if (result == PIM_RP_PFXLIST_IN_USE) { + snprintf(errmsg, errmsg_len, + "The same prefix-list cannot be applied to multiple RPs"); + return NB_ERR_INCONSISTENCY; + } + + return NB_OK; +} + +static int pim_no_rp_cmd_worker(struct pim_instance *pim, + struct in_addr rp_addr, struct prefix group, + const char *plist, + char *errmsg, size_t errmsg_len) +{ + char rp_str[INET_ADDRSTRLEN]; + char group_str[PREFIX2STR_BUFFER]; + int result; + + inet_ntop(AF_INET, &rp_addr, rp_str, sizeof(rp_str)); + prefix2str(&group, group_str, sizeof(group_str)); + + result = pim_rp_del(pim, rp_addr, group, plist, RP_SRC_STATIC); + + if (result == PIM_GROUP_BAD_ADDRESS) { + snprintf(errmsg, errmsg_len, + "Bad group address specified: %s", group_str); + return NB_ERR_INCONSISTENCY; + } + + if (result == PIM_RP_BAD_ADDRESS) { + snprintf(errmsg, errmsg_len, + "Bad RP address specified: %s", rp_str); + return NB_ERR_INCONSISTENCY; + } + + if (result == PIM_RP_NOT_FOUND) { + snprintf(errmsg, errmsg_len, + "Unable to find specified RP"); + return NB_ERR_INCONSISTENCY; + } + + return NB_OK; +} + +static bool is_pim_interface(const struct lyd_node *dnode) +{ + char if_xpath[XPATH_MAXLEN]; + const struct lyd_node *pim_enable_dnode; + const struct lyd_node *igmp_enable_dnode; + + yang_dnode_get_path(dnode, if_xpath, sizeof(if_xpath)); + pim_enable_dnode = yang_dnode_get(dnode, "%s/frr-pim:pim/pim-enable", + if_xpath); + igmp_enable_dnode = yang_dnode_get(dnode, + "%s/frr-igmp:igmp/igmp-enable", + if_xpath); + + if (((pim_enable_dnode) && + (yang_dnode_get_bool(pim_enable_dnode, "."))) || + ((igmp_enable_dnode) && + (yang_dnode_get_bool(igmp_enable_dnode, ".")))) + return true; + + return false; +} + +static int pim_cmd_igmp_start(struct interface *ifp) +{ + struct pim_interface *pim_ifp; + uint8_t need_startup = 0; + + pim_ifp = ifp->info; + + if (!pim_ifp) { + (void)pim_if_new(ifp, true, false, false, false); + need_startup = 1; + } else { + if (!PIM_IF_TEST_IGMP(pim_ifp->options)) { + PIM_IF_DO_IGMP(pim_ifp->options); + need_startup = 1; + } + } + + /* 'ip igmp' executed multiple times, with need_startup + * avoid multiple if add all and membership refresh + */ + if (need_startup) { + pim_if_addr_add_all(ifp); + pim_if_membership_refresh(ifp); + } + + return NB_OK; +} + +/* + * CLI reconfiguration affects the interface level (struct pim_interface). + * This function propagates the reconfiguration to every active socket + * for that interface. + */ +static void igmp_sock_query_interval_reconfig(struct igmp_sock *igmp) +{ + struct interface *ifp; + struct pim_interface *pim_ifp; + + zassert(igmp); + + /* other querier present? */ + + if (igmp->t_other_querier_timer) + return; + + /* this is the querier */ + + zassert(igmp->interface); + zassert(igmp->interface->info); + + ifp = igmp->interface; + pim_ifp = ifp->info; + + if (PIM_DEBUG_IGMP_TRACE) { + char ifaddr_str[INET_ADDRSTRLEN]; + + pim_inet4_dump("<ifaddr?>", igmp->ifaddr, ifaddr_str, + sizeof(ifaddr_str)); + zlog_debug("%s: Querier %s on %s reconfig query_interval=%d", + __func__, ifaddr_str, ifp->name, + pim_ifp->igmp_default_query_interval); + } + + /* + * igmp_startup_mode_on() will reset QQI: + + * igmp->querier_query_interval = pim_ifp->igmp_default_query_interval; + */ + igmp_startup_mode_on(igmp); +} + +static void igmp_sock_query_reschedule(struct igmp_sock *igmp) +{ + if (igmp->mtrace_only) + return; + + if (igmp->t_igmp_query_timer) { + /* other querier present */ + zassert(igmp->t_igmp_query_timer); + zassert(!igmp->t_other_querier_timer); + + pim_igmp_general_query_off(igmp); + pim_igmp_general_query_on(igmp); + + zassert(igmp->t_igmp_query_timer); + zassert(!igmp->t_other_querier_timer); + } else { + /* this is the querier */ + + zassert(!igmp->t_igmp_query_timer); + zassert(igmp->t_other_querier_timer); + + pim_igmp_other_querier_timer_off(igmp); + pim_igmp_other_querier_timer_on(igmp); + + zassert(!igmp->t_igmp_query_timer); + zassert(igmp->t_other_querier_timer); + } +} + +static void change_query_interval(struct pim_interface *pim_ifp, + int query_interval) +{ + struct listnode *sock_node; + struct igmp_sock *igmp; + + pim_ifp->igmp_default_query_interval = query_interval; + + for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, sock_node, igmp)) { + igmp_sock_query_interval_reconfig(igmp); + igmp_sock_query_reschedule(igmp); + } +} + +static void change_query_max_response_time(struct pim_interface *pim_ifp, + int query_max_response_time_dsec) +{ + struct listnode *sock_node; + struct igmp_sock *igmp; + + pim_ifp->igmp_query_max_response_time_dsec = + query_max_response_time_dsec; + + /* + * Below we modify socket/group/source timers in order to quickly + * reflect the change. Otherwise, those timers would args->eventually + * catch up. + */ + + /* scan all sockets */ + for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, sock_node, igmp)) { + struct listnode *grp_node; + struct igmp_group *grp; + + /* reschedule socket general query */ + igmp_sock_query_reschedule(igmp); + + /* scan socket groups */ + for (ALL_LIST_ELEMENTS_RO(igmp->igmp_group_list, grp_node, + grp)) { + struct listnode *src_node; + struct igmp_source *src; + + /* reset group timers for groups in EXCLUDE mode */ + if (grp->group_filtermode_isexcl) + igmp_group_reset_gmi(grp); + + /* scan group sources */ + for (ALL_LIST_ELEMENTS_RO(grp->group_source_list, + src_node, src)) { + + /* reset source timers for sources with running + * timers + */ + if (src->t_source_timer) + igmp_source_reset_gmi(igmp, grp, src); + } + } + } +} + +int routing_control_plane_protocols_name_validate( + struct nb_cb_create_args *args) +{ + const char *name; + + name = yang_dnode_get_string(args->dnode, "./name"); + if (!strmatch(name, "pim")) { + snprintf(args->errmsg, args->errmsg_len, + "pim supports only one instance with name pimd"); + return NB_ERR_VALIDATION; + } + return NB_OK; +} + +/* + * XPath: /frr-pim:pim/packets + */ +int pim_packets_modify(struct nb_cb_modify_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + router->packet_process = yang_dnode_get_uint8(args->dnode, + NULL); + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-pim:pim/join-prune-interval + */ +int pim_join_prune_interval_modify(struct nb_cb_modify_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + router->t_periodic = yang_dnode_get_uint16(args->dnode, NULL); + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-pim:pim/register-suppress-time + */ +int pim_register_suppress_time_modify(struct nb_cb_modify_args *args) +{ + struct vrf *vrf; + struct pim_instance *pim; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + vrf = nb_running_get_entry(args->dnode, NULL, true); + pim = vrf->info; + pim->keep_alive_time = yang_dnode_get_uint16(args->dnode, NULL); + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/ecmp + */ +int routing_control_plane_protocols_control_plane_protocol_pim_ecmp_modify( + struct nb_cb_modify_args *args) +{ + struct vrf *vrf; + struct pim_instance *pim; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + vrf = nb_running_get_entry(args->dnode, NULL, true); + pim = vrf->info; + pim->ecmp_enable = yang_dnode_get_bool(args->dnode, NULL); + } + + return NB_OK; +} + +/* + * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/ecmp-rebalance + */ +int routing_control_plane_protocols_control_plane_protocol_pim_ecmp_rebalance_modify( + struct nb_cb_modify_args *args) +{ + struct vrf *vrf; + struct pim_instance *pim; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + vrf = nb_running_get_entry(args->dnode, NULL, true); + pim = vrf->info; + pim->ecmp_rebalance_enable = + yang_dnode_get_bool(args->dnode, NULL); + } + + return NB_OK; +} + +/* + * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/keep-alive-timer + */ +int routing_control_plane_protocols_control_plane_protocol_pim_keep_alive_timer_modify( + struct nb_cb_modify_args *args) +{ + struct vrf *vrf; + struct pim_instance *pim; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + vrf = nb_running_get_entry(args->dnode, NULL, true); + pim = vrf->info; + pim->keep_alive_time = yang_dnode_get_uint16(args->dnode, NULL); + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/rp-keep-alive-timer + */ +int routing_control_plane_protocols_control_plane_protocol_pim_rp_keep_alive_timer_modify( + struct nb_cb_modify_args *args) +{ + struct vrf *vrf; + struct pim_instance *pim; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + vrf = nb_running_get_entry(args->dnode, NULL, true); + pim = vrf->info; + pim->rp_keep_alive_time = yang_dnode_get_uint16(args->dnode, + NULL); + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family + */ +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_create( + struct nb_cb_create_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + break; + } + + return NB_OK; +} + +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/send-v6-secondary + */ +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_send_v6_secondary_modify( + struct nb_cb_modify_args *args) +{ + struct vrf *vrf; + struct pim_instance *pim; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + vrf = nb_running_get_entry(args->dnode, NULL, true); + pim = vrf->info; + pim->send_v6_secondary = yang_dnode_get_bool(args->dnode, NULL); + break; + } + + return NB_OK; +} + +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_send_v6_secondary_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + break; + } + + return NB_OK; +} + +/* + * XPath: + * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/spt-switchover + */ +void routing_control_plane_protocols_control_plane_protocol_pim_address_family_spt_switchover_apply_finish( + struct nb_cb_apply_finish_args *args) +{ + struct vrf *vrf; + struct pim_instance *pim; + int spt_switch_action; + const char *prefix_list = NULL; + + vrf = nb_running_get_entry(args->dnode, NULL, true); + pim = vrf->info; + spt_switch_action = yang_dnode_get_enum(args->dnode, "./spt-action"); + + switch (spt_switch_action) { + case PIM_SPT_INFINITY: + if (yang_dnode_exists(args->dnode, + "./spt-infinity-prefix-list")) + prefix_list = yang_dnode_get_string( + args->dnode, "./spt-infinity-prefix-list"); + + pim_cmd_spt_switchover(pim, PIM_SPT_INFINITY, + prefix_list); + break; + case PIM_SPT_IMMEDIATE: + pim_cmd_spt_switchover(pim, PIM_SPT_IMMEDIATE, NULL); + } +} + +/* + * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/spt-switchover/spt-action + */ +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_spt_switchover_spt_action_modify( + struct nb_cb_modify_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/spt-switchover/spt-infinity-prefix-list + */ +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_spt_switchover_spt_infinity_prefix_list_modify( + struct nb_cb_modify_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + break; + } + + return NB_OK; +} + +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_spt_switchover_spt_infinity_prefix_list_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/ssm-prefix-list + */ +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_ssm_prefix_list_modify( + struct nb_cb_modify_args *args) +{ + struct vrf *vrf; + struct pim_instance *pim; + const char *plist_name; + int result; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + vrf = nb_running_get_entry(args->dnode, NULL, true); + pim = vrf->info; + plist_name = yang_dnode_get_string(args->dnode, NULL); + result = pim_ssm_cmd_worker(pim, plist_name, args->errmsg, + args->errmsg_len); + + if (result) + return NB_ERR_INCONSISTENCY; + + break; + } + + return NB_OK; +} + +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_ssm_prefix_list_destroy( + struct nb_cb_destroy_args *args) +{ + struct vrf *vrf; + struct pim_instance *pim; + int result; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + vrf = nb_running_get_entry(args->dnode, NULL, true); + pim = vrf->info; + result = pim_ssm_cmd_worker(pim, NULL, args->errmsg, + args->errmsg_len); + + if (result) + return NB_ERR_INCONSISTENCY; + + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/ssm-pingd-source-ip + */ +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_ssm_pingd_source_ip_create( + struct nb_cb_create_args *args) +{ + struct vrf *vrf; + struct pim_instance *pim; + int result; + struct ipaddr source_addr; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + vrf = nb_running_get_entry(args->dnode, NULL, true); + pim = vrf->info; + yang_dnode_get_ip(&source_addr, args->dnode, NULL); + result = pim_ssmpingd_start(pim, source_addr.ip._v4_addr); + if (result) { + char source_str[INET_ADDRSTRLEN]; + + ipaddr2str(&source_addr, source_str, + sizeof(source_str)); + snprintf(args->errmsg, args->errmsg_len, + "%% Failure starting ssmpingd for source %s: %d", + source_str, result); + return NB_ERR_INCONSISTENCY; + } + } + + return NB_OK; +} + +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_ssm_pingd_source_ip_destroy( + struct nb_cb_destroy_args *args) +{ + struct vrf *vrf; + struct pim_instance *pim; + int result; + struct ipaddr source_addr; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + vrf = nb_running_get_entry(args->dnode, NULL, true); + pim = vrf->info; + yang_dnode_get_ip(&source_addr, args->dnode, NULL); + result = pim_ssmpingd_stop(pim, source_addr.ip._v4_addr); + if (result) { + char source_str[INET_ADDRSTRLEN]; + + ipaddr2str(&source_addr, source_str, + sizeof(source_str)); + snprintf(args->errmsg, args->errmsg_len, + "%% Failure stopping ssmpingd for source %s: %d", + source_str, result); + return NB_ERR_INCONSISTENCY; + } + + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-mesh-group + */ +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_create( + struct nb_cb_create_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + break; + } + + return NB_OK; +} + +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_destroy( + struct nb_cb_destroy_args *args) +{ + struct vrf *vrf; + struct pim_instance *pim; + const char *mesh_group_name; + int result; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + vrf = nb_running_get_entry(args->dnode, NULL, true); + pim = vrf->info; + mesh_group_name = yang_dnode_get_string(args->dnode, "."); + + result = ip_no_msdp_mesh_group_cmd_worker(pim, mesh_group_name, + args->errmsg, + args->errmsg_len); + + if (result != PIM_MSDP_ERR_NONE) + return NB_ERR_INCONSISTENCY; + + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-mesh-group/mesh-group-name + */ +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_mesh_group_name_modify( + struct nb_cb_modify_args *args) +{ + const char *mesh_group_name; + const char *mesh_group_name_old; + char xpath[XPATH_MAXLEN]; + + switch (args->event) { + case NB_EV_VALIDATE: + mesh_group_name = yang_dnode_get_string(args->dnode, "."); + yang_dnode_get_path(args->dnode, xpath, sizeof(xpath)); + + if (yang_dnode_exists(running_config->dnode, xpath) == false) + break; + + mesh_group_name_old = yang_dnode_get_string( + running_config->dnode, + xpath); + if (strcmp(mesh_group_name, mesh_group_name_old)) { + /* currently only one mesh-group can exist at a time */ + snprintf(args->errmsg, args->errmsg_len, + "Only one mesh-group allowed currently"); + return NB_ERR_VALIDATION; + } + break; + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + break; + } + + return NB_OK; +} + +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_mesh_group_name_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-mesh-group/member-ip + */ +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_member_ip_create( + struct nb_cb_create_args *args) +{ + struct vrf *vrf; + struct pim_instance *pim; + const char *mesh_group_name; + struct ipaddr mbr_ip; + enum pim_msdp_err result; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + vrf = nb_running_get_entry(args->dnode, NULL, true); + pim = vrf->info; + mesh_group_name = yang_dnode_get_string(args->dnode, + "../mesh-group-name"); + yang_dnode_get_ip(&mbr_ip, args->dnode, NULL); + + result = ip_msdp_mesh_group_member_cmd_worker( + pim, mesh_group_name, mbr_ip.ip._v4_addr, + args->errmsg, args->errmsg_len); + + if (result != PIM_MSDP_ERR_NONE) + return NB_ERR_INCONSISTENCY; + + break; + } + + return NB_OK; +} + +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_member_ip_destroy( + struct nb_cb_destroy_args *args) +{ + struct vrf *vrf; + struct pim_instance *pim; + const char *mesh_group_name; + struct ipaddr mbr_ip; + enum pim_msdp_err result; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + vrf = nb_running_get_entry(args->dnode, NULL, true); + pim = vrf->info; + mesh_group_name = yang_dnode_get_string(args->dnode, + "../mesh-group-name"); + yang_dnode_get_ip(&mbr_ip, args->dnode, NULL); + + result = ip_no_msdp_mesh_group_member_cmd_worker( + pim, mesh_group_name, mbr_ip.ip._v4_addr, + args->errmsg, args->errmsg_len); + + if (result != PIM_MSDP_ERR_NONE) + return NB_ERR_INCONSISTENCY; + + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-mesh-group/source-ip + */ +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_source_ip_modify( + struct nb_cb_modify_args *args) +{ + struct vrf *vrf; + struct pim_instance *pim; + const char *mesh_group_name; + struct ipaddr src_ip; + enum pim_msdp_err result; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + vrf = nb_running_get_entry(args->dnode, NULL, true); + pim = vrf->info; + mesh_group_name = yang_dnode_get_string(args->dnode, + "../mesh-group-name"); + yang_dnode_get_ip(&src_ip, args->dnode, NULL); + + result = ip_msdp_mesh_group_source_cmd_worker( + pim, mesh_group_name, src_ip.ip._v4_addr, + args->errmsg, args->errmsg_len); + + if (result != PIM_MSDP_ERR_NONE) + return NB_ERR_INCONSISTENCY; + + break; + } + return NB_OK; +} + +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_source_ip_destroy( + struct nb_cb_destroy_args *args) +{ + struct vrf *vrf; + struct pim_instance *pim; + const char *mesh_group_name; + enum pim_msdp_err result; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + vrf = nb_running_get_entry(args->dnode, NULL, true); + pim = vrf->info; + mesh_group_name = yang_dnode_get_string(args->dnode, + "../mesh-group-name"); + + result = ip_no_msdp_mesh_group_source_cmd_worker( + pim, mesh_group_name, args->errmsg, + args->errmsg_len); + + if (result != PIM_MSDP_ERR_NONE) + return NB_ERR_INCONSISTENCY; + + break; + } + return NB_OK; +} + +/* + * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-peer + */ +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_peer_create( + struct nb_cb_create_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + break; + } + + return NB_OK; +} + +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_peer_destroy( + struct nb_cb_destroy_args *args) +{ + int result; + struct pim_instance *pim; + struct ipaddr peer_ip; + struct vrf *vrf; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + vrf = nb_running_get_entry(args->dnode, NULL, true); + pim = vrf->info; + yang_dnode_get_ip(&peer_ip, args->dnode, "./peer-ip"); + result = ip_no_msdp_peer_cmd_worker(pim, peer_ip.ip._v4_addr, + args->errmsg, + args->errmsg_len); + + if (result) + return NB_ERR_INCONSISTENCY; + + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-peer/source-ip + */ +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_peer_source_ip_modify( + struct nb_cb_modify_args *args) +{ + int result; + struct vrf *vrf; + struct pim_instance *pim; + struct ipaddr peer_ip; + struct ipaddr source_ip; + const struct lyd_node *mesh_group_name_dnode; + const char *mesh_group_name; + + switch (args->event) { + case NB_EV_VALIDATE: + mesh_group_name_dnode = + yang_dnode_get(args->dnode, + "../../msdp-mesh-group/mesh-group-name"); + if (mesh_group_name_dnode) { + mesh_group_name = + yang_dnode_get_string(mesh_group_name_dnode, + "."); + if (strcmp(mesh_group_name, "default")) { + /* currently only one mesh-group can exist at a + * time + */ + snprintf(args->errmsg, args->errmsg_len, + "%% Only one mesh-group allowed currently"); + return NB_ERR_VALIDATION; + } + } + break; + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + vrf = nb_running_get_entry(args->dnode, NULL, true); + pim = vrf->info; + yang_dnode_get_ip(&peer_ip, args->dnode, "../peer-ip"); + yang_dnode_get_ip(&source_ip, args->dnode, NULL); + + result = ip_msdp_peer_cmd_worker(pim, peer_ip.ip._v4_addr, + source_ip.ip._v4_addr, + args->errmsg, + args->errmsg_len); + + if (result) + return NB_ERR_INCONSISTENCY; + + break; + } + + return NB_OK; +} + +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_peer_source_ip_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/mlag + */ +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_create( + struct nb_cb_create_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + break; + } + + return NB_OK; +} + +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_destroy( + struct nb_cb_destroy_args *args) +{ + struct in_addr addr; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + addr.s_addr = 0; + pim_vxlan_mlag_update(true/*mlag_enable*/, + false/*peer_state*/, MLAG_ROLE_NONE, + NULL/*peerlink*/, &addr); + } + + return NB_OK; +} + +/* + * XPath: + * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/mlag + */ +void routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_apply_finish( + struct nb_cb_apply_finish_args *args) +{ + const char *ifname; + uint32_t role; + bool peer_state; + struct interface *ifp; + struct ipaddr reg_addr; + + ifname = yang_dnode_get_string(args->dnode, "./peerlink-rif"); + ifp = if_lookup_by_name(ifname, VRF_DEFAULT); + if (!ifp) { + snprintf(args->errmsg, args->errmsg_len, + "No such interface name %s", ifname); + return; + } + role = yang_dnode_get_enum(args->dnode, "./my-role"); + peer_state = yang_dnode_get_bool(args->dnode, "./peer-state"); + yang_dnode_get_ip(®_addr, args->dnode, "./reg-address"); + + pim_vxlan_mlag_update(true, peer_state, role, ifp, + ®_addr.ip._v4_addr); +} + + +/* + * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/mlag/peerlink-rif + */ +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_peerlink_rif_modify( + struct nb_cb_modify_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + break; + } + + return NB_OK; +} + +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_peerlink_rif_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/mlag/reg-address + */ +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_reg_address_modify( + struct nb_cb_modify_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + break; + } + + return NB_OK; +} + +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_reg_address_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/mlag/my-role + */ +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_my_role_modify( + struct nb_cb_modify_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/mlag/peer-state + */ +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_peer_state_modify( + struct nb_cb_modify_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/register-accept-list + */ +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_register_accept_list_modify( + struct nb_cb_modify_args *args) +{ + struct vrf *vrf; + struct pim_instance *pim; + const char *plist; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + vrf = nb_running_get_entry(args->dnode, NULL, true); + pim = vrf->info; + plist = yang_dnode_get_string(args->dnode, NULL); + + XFREE(MTYPE_PIM_PLIST_NAME, pim->register_plist); + pim->register_plist = XSTRDUP(MTYPE_PIM_PLIST_NAME, plist); + + break; + } + + return NB_OK; +} + +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_register_accept_list_destroy( + struct nb_cb_destroy_args *args) +{ + struct vrf *vrf; + struct pim_instance *pim; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + vrf = nb_running_get_entry(args->dnode, NULL, true); + pim = vrf->info; + + XFREE(MTYPE_PIM_PLIST_NAME, pim->register_plist); + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-pim:pim + */ +int lib_interface_pim_create(struct nb_cb_create_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + break; + } + + return NB_OK; +} + +int lib_interface_pim_destroy(struct nb_cb_destroy_args *args) +{ + struct interface *ifp; + struct pim_interface *pim_ifp; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + ifp = nb_running_get_entry(args->dnode, NULL, true); + pim_ifp = ifp->info; + if (!pim_ifp) + return NB_OK; + + if (!pim_cmd_interface_delete(ifp)) { + snprintf(args->errmsg, args->errmsg_len, + "Unable to delete interface information %s", + ifp->name); + return NB_ERR_INCONSISTENCY; + } + } + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-pim:pim/pim-enable + */ +int lib_interface_pim_pim_enable_modify(struct nb_cb_modify_args *args) +{ + struct interface *ifp; + struct pim_interface *pim_ifp; + int mcast_if_count; + const struct lyd_node *if_dnode; + + switch (args->event) { + case NB_EV_VALIDATE: + if_dnode = yang_dnode_get_parent(args->dnode, "interface"); + mcast_if_count = + yang_get_list_elements_count(if_dnode); + + /* Limiting mcast interfaces to number of VIFs */ + if (mcast_if_count == MAXVIFS) { + snprintf(args->errmsg, args->errmsg_len, + "Max multicast interfaces(%d) reached.", + MAXVIFS); + return NB_ERR_VALIDATION; + } + break; + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + ifp = nb_running_get_entry(args->dnode, NULL, true); + + if (yang_dnode_get_bool(args->dnode, NULL)) { + if (!pim_cmd_interface_add(ifp)) { + snprintf(args->errmsg, args->errmsg_len, + "Could not enable PIM SM on interface %s", + ifp->name); + return NB_ERR_INCONSISTENCY; + } + } else { + pim_ifp = ifp->info; + if (!pim_ifp) + return NB_ERR_INCONSISTENCY; + + if (!pim_cmd_interface_delete(ifp)) { + snprintf(args->errmsg, args->errmsg_len, + "Unable to delete interface information"); + return NB_ERR_INCONSISTENCY; + } + } + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-pim:pim/hello-interval + */ +int lib_interface_pim_hello_interval_modify(struct nb_cb_modify_args *args) +{ + struct interface *ifp; + struct pim_interface *pim_ifp; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_ABORT: + case NB_EV_PREPARE: + break; + case NB_EV_APPLY: + ifp = nb_running_get_entry(args->dnode, NULL, true); + pim_ifp = ifp->info; + pim_ifp->pim_hello_period = + yang_dnode_get_uint8(args->dnode, NULL); + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-pim:pim/hello-holdtime + */ +int lib_interface_pim_hello_holdtime_modify(struct nb_cb_modify_args *args) +{ + struct interface *ifp; + struct pim_interface *pim_ifp; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_ABORT: + case NB_EV_PREPARE: + break; + case NB_EV_APPLY: + ifp = nb_running_get_entry(args->dnode, NULL, true); + pim_ifp = ifp->info; + pim_ifp->pim_default_holdtime = + yang_dnode_get_uint8(args->dnode, NULL); + break; + } + + return NB_OK; + +} + +int lib_interface_pim_hello_holdtime_destroy(struct nb_cb_destroy_args *args) +{ + struct interface *ifp; + struct pim_interface *pim_ifp; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_ABORT: + case NB_EV_PREPARE: + break; + case NB_EV_APPLY: + ifp = nb_running_get_entry(args->dnode, NULL, true); + pim_ifp = ifp->info; + pim_ifp->pim_default_holdtime = -1; + break; + } + + return NB_OK; +} +/* + * XPath: /frr-interface:lib/interface/frr-pim:pim/bfd + */ +int lib_interface_pim_bfd_create(struct nb_cb_create_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + break; + } + + return NB_OK; +} + +int lib_interface_pim_bfd_destroy(struct nb_cb_destroy_args *args) +{ + struct interface *ifp; + struct pim_interface *pim_ifp; + const struct lyd_node *if_dnode; + + switch (args->event) { + case NB_EV_VALIDATE: + if_dnode = yang_dnode_get_parent(args->dnode, "interface"); + if (!is_pim_interface(if_dnode)) { + snprintf(args->errmsg, args->errmsg_len, + "Pim not enabled on this interface"); + return NB_ERR_VALIDATION; + } + break; + case NB_EV_ABORT: + case NB_EV_PREPARE: + break; + case NB_EV_APPLY: + ifp = nb_running_get_entry(args->dnode->parent, NULL, true); + pim_ifp = ifp->info; + if (pim_ifp->bfd_info) { + pim_bfd_reg_dereg_all_nbr(ifp, + ZEBRA_BFD_DEST_DEREGISTER); + bfd_info_free(&(pim_ifp->bfd_info)); + } + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-pim:pim/bfd + */ +void lib_interface_pim_bfd_apply_finish(struct nb_cb_apply_finish_args *args) +{ + struct interface *ifp; + struct pim_interface *pim_ifp; + uint32_t min_rx; + uint32_t min_tx; + uint8_t detect_mult; + + ifp = nb_running_get_entry(args->dnode->parent, NULL, true); + pim_ifp = ifp->info; + + if (!pim_ifp) { + zlog_debug("Pim not enabled on this interface"); + return; + } + + min_rx = yang_dnode_get_uint16(args->dnode, "./min-rx-interval"); + min_tx = yang_dnode_get_uint16(args->dnode, "./min-tx-interval"); + detect_mult = yang_dnode_get_uint8(args->dnode, "./detect_mult"); + + if ((min_rx == BFD_DEF_MIN_RX) && (min_tx == BFD_DEF_MIN_TX) + && (detect_mult == BFD_DEF_DETECT_MULT)) + pim_bfd_if_param_set(ifp, min_rx, min_tx, detect_mult, 1); + else + pim_bfd_if_param_set(ifp, min_rx, min_tx, detect_mult, 0); + + nb_running_set_entry(args->dnode, pim_ifp->bfd_info); +} + +/* + * XPath: /frr-interface:lib/interface/frr-pim:pim/bfd/min-rx-interval + */ +int lib_interface_pim_bfd_min_rx_interval_modify(struct nb_cb_modify_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-pim:pim/bfd/min-tx-interval + */ +int lib_interface_pim_bfd_min_tx_interval_modify(struct nb_cb_modify_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-pim:pim/bfd/detect_mult + */ +int lib_interface_pim_bfd_detect_mult_modify(struct nb_cb_modify_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-pim:pim/bsm + */ +int lib_interface_pim_bsm_modify(struct nb_cb_modify_args *args) +{ + struct interface *ifp; + struct pim_interface *pim_ifp; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + ifp = nb_running_get_entry(args->dnode, NULL, true); + pim_ifp = ifp->info; + pim_ifp->bsm_enable = yang_dnode_get_bool(args->dnode, NULL); + + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-pim:pim/unicast-bsm + */ +int lib_interface_pim_unicast_bsm_modify(struct nb_cb_modify_args *args) +{ + struct interface *ifp; + struct pim_interface *pim_ifp; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + ifp = nb_running_get_entry(args->dnode, NULL, true); + pim_ifp = ifp->info; + pim_ifp->ucast_bsm_accept = + yang_dnode_get_bool(args->dnode, NULL); + + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-pim:pim/active-active + */ +int lib_interface_pim_active_active_modify(struct nb_cb_modify_args *args) +{ + struct interface *ifp; + struct pim_interface *pim_ifp; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + ifp = nb_running_get_entry(args->dnode, NULL, true); + pim_ifp = ifp->info; + if (yang_dnode_get_bool(args->dnode, NULL)) { + if (PIM_DEBUG_MLAG) + zlog_debug( + "Configuring PIM active-active on Interface: %s", + ifp->name); + pim_if_configure_mlag_dualactive(pim_ifp); + } else { + if (PIM_DEBUG_MLAG) + zlog_debug( + "UnConfiguring PIM active-active on Interface: %s", + ifp->name); + pim_if_unconfigure_mlag_dualactive(pim_ifp); + } + + break; + } + + return NB_OK; + +} + +/* + * XPath: /frr-interface:lib/interface/frr-pim:pim/dr-priority + */ +int lib_interface_pim_dr_priority_modify(struct nb_cb_modify_args *args) +{ + struct interface *ifp; + struct pim_interface *pim_ifp; + uint32_t old_dr_prio; + const struct lyd_node *if_dnode; + + switch (args->event) { + case NB_EV_VALIDATE: + if_dnode = yang_dnode_get_parent(args->dnode, "interface"); + if (!is_pim_interface(if_dnode)) { + snprintf(args->errmsg, args->errmsg_len, + "Pim not enabled on this interface"); + return NB_ERR_VALIDATION; + } + break; + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + ifp = nb_running_get_entry(args->dnode, NULL, true); + pim_ifp = ifp->info; + old_dr_prio = pim_ifp->pim_dr_priority; + pim_ifp->pim_dr_priority = yang_dnode_get_uint32(args->dnode, + NULL); + + if (old_dr_prio != pim_ifp->pim_dr_priority) { + pim_if_dr_election(ifp); + pim_hello_restart_now(ifp); + } + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-pim:pim/address-family + */ +int lib_interface_pim_address_family_create(struct nb_cb_create_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + break; + } + + return NB_OK; +} + +int lib_interface_pim_address_family_destroy(struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-pim:pim/address-family/use-source + */ +int lib_interface_pim_address_family_use_source_modify(struct nb_cb_modify_args *args) +{ + struct interface *ifp; + struct ipaddr source_addr; + int result; + const struct lyd_node *if_dnode; + + switch (args->event) { + case NB_EV_VALIDATE: + if_dnode = yang_dnode_get_parent(args->dnode, "interface"); + if (!is_pim_interface(if_dnode)) { + snprintf(args->errmsg, args->errmsg_len, + "Pim not enabled on this interface"); + return NB_ERR_VALIDATION; + } + break; + case NB_EV_ABORT: + case NB_EV_PREPARE: + break; + case NB_EV_APPLY: + ifp = nb_running_get_entry(args->dnode, NULL, true); + yang_dnode_get_ip(&source_addr, args->dnode, NULL); + + result = interface_pim_use_src_cmd_worker( + ifp, source_addr.ip._v4_addr, + args->errmsg, args->errmsg_len); + + if (result != PIM_SUCCESS) + return NB_ERR_INCONSISTENCY; + + break; + } + + return NB_OK; +} + +int lib_interface_pim_address_family_use_source_destroy( + struct nb_cb_destroy_args *args) +{ + struct interface *ifp; + struct in_addr source_addr = {INADDR_ANY}; + int result; + const struct lyd_node *if_dnode; + + switch (args->event) { + case NB_EV_VALIDATE: + if_dnode = yang_dnode_get_parent(args->dnode, "interface"); + if (!is_pim_interface(if_dnode)) { + snprintf(args->errmsg, args->errmsg_len, + "Pim not enabled on this interface"); + return NB_ERR_VALIDATION; + } + break; + case NB_EV_ABORT: + case NB_EV_PREPARE: + break; + case NB_EV_APPLY: + ifp = nb_running_get_entry(args->dnode, NULL, true); + + result = interface_pim_use_src_cmd_worker(ifp, source_addr, + args->errmsg, + args->errmsg_len); + + if (result != PIM_SUCCESS) + return NB_ERR_INCONSISTENCY; + + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-pim:pim/address-family/multicast-boundary-oil + */ +int lib_interface_pim_address_family_multicast_boundary_oil_modify( + struct nb_cb_modify_args *args) +{ + struct interface *ifp; + struct pim_interface *pim_ifp; + const char *plist; + const struct lyd_node *if_dnode; + + switch (args->event) { + case NB_EV_VALIDATE: + if_dnode = yang_dnode_get_parent(args->dnode, "interface"); + if (!is_pim_interface(if_dnode)) { + snprintf(args->errmsg, args->errmsg_len, + "Pim not enabled on this interface"); + return NB_ERR_VALIDATION; + } + break; + case NB_EV_ABORT: + case NB_EV_PREPARE: + break; + case NB_EV_APPLY: + ifp = nb_running_get_entry(args->dnode, NULL, true); + pim_ifp = ifp->info; + plist = yang_dnode_get_string(args->dnode, NULL); + + if (pim_ifp->boundary_oil_plist) + XFREE(MTYPE_PIM_INTERFACE, pim_ifp->boundary_oil_plist); + + pim_ifp->boundary_oil_plist = + XSTRDUP(MTYPE_PIM_INTERFACE, plist); + + break; + } + + return NB_OK; +} + +int lib_interface_pim_address_family_multicast_boundary_oil_destroy( + struct nb_cb_destroy_args *args) +{ + struct interface *ifp; + struct pim_interface *pim_ifp; + const struct lyd_node *if_dnode; + + switch (args->event) { + case NB_EV_VALIDATE: + if_dnode = yang_dnode_get_parent(args->dnode, "interface"); + if (!is_pim_interface(if_dnode)) { + snprintf(args->errmsg, args->errmsg_len, + "%% Enable PIM and/or IGMP on this interface first"); + return NB_ERR_VALIDATION; + } + break; + case NB_EV_ABORT: + case NB_EV_PREPARE: + break; + case NB_EV_APPLY: + ifp = nb_running_get_entry(args->dnode, NULL, true); + pim_ifp = ifp->info; + if (pim_ifp->boundary_oil_plist) + XFREE(MTYPE_PIM_INTERFACE, pim_ifp->boundary_oil_plist); + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-pim:pim/address-family/mroute + */ +int lib_interface_pim_address_family_mroute_create( + struct nb_cb_create_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + break; + } + + return NB_OK; +} + +int lib_interface_pim_address_family_mroute_destroy( + struct nb_cb_destroy_args *args) +{ + struct pim_instance *pim; + struct pim_interface *pim_iifp; + struct interface *iif; + struct interface *oif; + const char *oifname; + struct ipaddr source_addr; + struct ipaddr group_addr; + const struct lyd_node *if_dnode; + + switch (args->event) { + case NB_EV_VALIDATE: + if_dnode = yang_dnode_get_parent(args->dnode, "interface"); + if (!is_pim_interface(if_dnode)) { + snprintf(args->errmsg, args->errmsg_len, + "%% Enable PIM and/or IGMP on this interface first"); + return NB_ERR_VALIDATION; + } + break; + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + iif = nb_running_get_entry(args->dnode, NULL, true); + pim_iifp = iif->info; + pim = pim_iifp->pim; + + oifname = yang_dnode_get_string(args->dnode, "./oif"); + oif = if_lookup_by_name(oifname, pim->vrf_id); + + if (!oif) { + snprintf(args->errmsg, args->errmsg_len, + "No such interface name %s", + oifname); + return NB_ERR_INCONSISTENCY; + } + + yang_dnode_get_ip(&source_addr, args->dnode, "./source-addr"); + yang_dnode_get_ip(&group_addr, args->dnode, "./group-addr"); + + if (pim_static_del(pim, iif, oif, group_addr.ip._v4_addr, + source_addr.ip._v4_addr)) { + snprintf(args->errmsg, args->errmsg_len, + "Failed to remove static mroute"); + return NB_ERR_INCONSISTENCY; + } + + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-pim:pim/address-family/mroute/oif + */ +int lib_interface_pim_address_family_mroute_oif_modify( + struct nb_cb_modify_args *args) +{ + struct pim_instance *pim; + struct pim_interface *pim_iifp; + struct interface *iif; + struct interface *oif; + const char *oifname; + struct ipaddr source_addr; + struct ipaddr group_addr; + const struct lyd_node *if_dnode; + + switch (args->event) { + case NB_EV_VALIDATE: + if_dnode = yang_dnode_get_parent(args->dnode, "interface"); + if (!is_pim_interface(if_dnode)) { + snprintf(args->errmsg, args->errmsg_len, + "%% Enable PIM and/or IGMP on this interface first"); + return NB_ERR_VALIDATION; + } + break; + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + iif = nb_running_get_entry(args->dnode, NULL, true); + pim_iifp = iif->info; + pim = pim_iifp->pim; + + oifname = yang_dnode_get_string(args->dnode, NULL); + oif = if_lookup_by_name(oifname, pim->vrf_id); + + if (!oif) { + snprintf(args->errmsg, args->errmsg_len, + "No such interface name %s", + oifname); + return NB_ERR_INCONSISTENCY; + } + + yang_dnode_get_ip(&source_addr, args->dnode, "../source-addr"); + yang_dnode_get_ip(&group_addr, args->dnode, "../group-addr"); + + if (pim_static_add(pim, iif, oif, group_addr.ip._v4_addr, + source_addr.ip._v4_addr)) { + snprintf(args->errmsg, args->errmsg_len, + "Failed to add static mroute"); + return NB_ERR_INCONSISTENCY; + } + + break; + } + + return NB_OK; +} + +int lib_interface_pim_address_family_mroute_oif_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-rp:rp/static-rp/rp-list + */ +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_static_rp_rp_list_create( + struct nb_cb_create_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + break; + } + + return NB_OK; +} + +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_static_rp_rp_list_destroy( + struct nb_cb_destroy_args *args) +{ + struct vrf *vrf; + struct pim_instance *pim; + struct prefix group; + struct ipaddr rp_addr; + const char *plist; + int result = 0; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + vrf = nb_running_get_entry(args->dnode, NULL, true); + pim = vrf->info; + yang_dnode_get_ip(&rp_addr, args->dnode, "./rp-address"); + + if (yang_dnode_get(args->dnode, "./group-list")) { + yang_dnode_get_ipv4p(&group, args->dnode, + "./group-list"); + apply_mask_ipv4((struct prefix_ipv4 *)&group); + result = pim_no_rp_cmd_worker(pim, rp_addr.ip._v4_addr, + group, NULL, args->errmsg, + args->errmsg_len); + } + + else if (yang_dnode_get(args->dnode, "./prefix-list")) { + plist = yang_dnode_get_string(args->dnode, + "./prefix-list"); + str2prefix("224.0.0.0/4", &group); + result = pim_no_rp_cmd_worker(pim, rp_addr.ip._v4_addr, + group, plist, + args->errmsg, + args->errmsg_len); + } + + if (result) + return NB_ERR_INCONSISTENCY; + break; + } + + return NB_OK; +} + +/* + * 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 + */ +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_static_rp_rp_list_group_list_create( + struct nb_cb_create_args *args) +{ + struct vrf *vrf; + struct pim_instance *pim; + struct prefix group; + struct ipaddr rp_addr; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + vrf = nb_running_get_entry(args->dnode, NULL, true); + pim = vrf->info; + yang_dnode_get_ip(&rp_addr, args->dnode, "../rp-address"); + yang_dnode_get_ipv4p(&group, args->dnode, NULL); + apply_mask_ipv4((struct prefix_ipv4 *)&group); + + return pim_rp_cmd_worker(pim, rp_addr.ip._v4_addr, group, + NULL, args->errmsg, args->errmsg_len); + } + + return NB_OK; +} + +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_static_rp_rp_list_group_list_destroy( + struct nb_cb_destroy_args *args) +{ + struct vrf *vrf; + struct pim_instance *pim; + struct prefix group; + struct ipaddr rp_addr; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + vrf = nb_running_get_entry(args->dnode, NULL, true); + pim = vrf->info; + yang_dnode_get_ip(&rp_addr, args->dnode, "../rp-address"); + yang_dnode_get_ipv4p(&group, args->dnode, NULL); + apply_mask_ipv4((struct prefix_ipv4 *)&group); + + return pim_no_rp_cmd_worker(pim, rp_addr.ip._v4_addr, group, + NULL, args->errmsg, + args->errmsg_len); + } + + return NB_OK; +} + +/* + * 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 + */ +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_static_rp_rp_list_prefix_list_modify( + struct nb_cb_modify_args *args) +{ + struct vrf *vrf; + struct pim_instance *pim; + struct prefix group; + struct ipaddr rp_addr; + const char *plist; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + vrf = nb_running_get_entry(args->dnode, NULL, true); + pim = vrf->info; + plist = yang_dnode_get_string(args->dnode, NULL); + yang_dnode_get_ip(&rp_addr, args->dnode, "../rp-address"); + str2prefix("224.0.0.0/4", &group); + return pim_rp_cmd_worker(pim, rp_addr.ip._v4_addr, group, + plist, args->errmsg, args->errmsg_len); + } + + return NB_OK; +} + +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_static_rp_rp_list_prefix_list_destroy( + struct nb_cb_destroy_args *args) +{ + struct vrf *vrf; + struct pim_instance *pim; + struct prefix group; + struct ipaddr rp_addr; + const char *plist; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + vrf = nb_running_get_entry(args->dnode, NULL, true); + pim = vrf->info; + yang_dnode_get_ip(&rp_addr, args->dnode, "../rp-address"); + plist = yang_dnode_get_string(args->dnode, NULL); + str2prefix("224.0.0.0/4", &group); + return pim_no_rp_cmd_worker(pim, rp_addr.ip._v4_addr, group, + plist, args->errmsg, + args->errmsg_len); + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-igmp:igmp + */ +int lib_interface_igmp_create(struct nb_cb_create_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + break; + } + + return NB_OK; +} + +int lib_interface_igmp_destroy(struct nb_cb_destroy_args *args) +{ + struct interface *ifp; + struct pim_interface *pim_ifp; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + ifp = nb_running_get_entry(args->dnode, NULL, true); + pim_ifp = ifp->info; + + if (!pim_ifp) + return NB_OK; + + PIM_IF_DONT_IGMP(pim_ifp->options); + + pim_if_membership_clear(ifp); + + pim_if_addr_del_all_igmp(ifp); + + if (!PIM_IF_TEST_PIM(pim_ifp->options)) + pim_if_delete(ifp); + } + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-igmp:igmp/igmp-enable + */ +int lib_interface_igmp_igmp_enable_modify(struct nb_cb_modify_args *args) +{ + struct interface *ifp; + bool igmp_enable; + struct pim_interface *pim_ifp; + int mcast_if_count; + const char *ifp_name; + const struct lyd_node *if_dnode; + + switch (args->event) { + case NB_EV_VALIDATE: + if_dnode = yang_dnode_get_parent(args->dnode, "interface"); + ifp_name = yang_dnode_get_string(if_dnode, "."); + mcast_if_count = + yang_get_list_elements_count(if_dnode); + /* Limiting mcast interfaces to number of VIFs */ + if (mcast_if_count == MAXVIFS) { + snprintf(args->errmsg, args->errmsg_len, + "Max multicast interfaces(%d) Reached. Could not enable IGMP on interface %s", + MAXVIFS, ifp_name); + return NB_ERR_VALIDATION; + } + break; + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + ifp = nb_running_get_entry(args->dnode, NULL, true); + igmp_enable = yang_dnode_get_bool(args->dnode, NULL); + + if (igmp_enable) + return pim_cmd_igmp_start(ifp); + + else { + pim_ifp = ifp->info; + + if (!pim_ifp) + return NB_ERR_INCONSISTENCY; + + PIM_IF_DONT_IGMP(pim_ifp->options); + + pim_if_membership_clear(ifp); + + pim_if_addr_del_all_igmp(ifp); + + if (!PIM_IF_TEST_PIM(pim_ifp->options)) + pim_if_delete(ifp); + } + } + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-igmp:igmp/version + */ +int lib_interface_igmp_version_modify(struct nb_cb_modify_args *args) +{ + struct interface *ifp; + struct pim_interface *pim_ifp; + int igmp_version, old_version = 0; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + ifp = nb_running_get_entry(args->dnode, NULL, true); + pim_ifp = ifp->info; + + if (!pim_ifp) + return NB_ERR_INCONSISTENCY; + + igmp_version = yang_dnode_get_uint8(args->dnode, NULL); + old_version = pim_ifp->igmp_version; + pim_ifp->igmp_version = igmp_version; + + /* Current and new version is different refresh existing + * membership. Going from 3 -> 2 or 2 -> 3. + */ + if (old_version != igmp_version) + pim_if_membership_refresh(ifp); + + break; + } + + return NB_OK; +} + +int lib_interface_igmp_version_destroy(struct nb_cb_destroy_args *args) +{ + struct interface *ifp; + struct pim_interface *pim_ifp; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + ifp = nb_running_get_entry(args->dnode, NULL, true); + pim_ifp = ifp->info; + pim_ifp->igmp_version = IGMP_DEFAULT_VERSION; + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-igmp:igmp/query-interval + */ +int lib_interface_igmp_query_interval_modify(struct nb_cb_modify_args *args) +{ + struct interface *ifp; + struct pim_interface *pim_ifp; + int query_interval; + int query_interval_dsec; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + ifp = nb_running_get_entry(args->dnode, NULL, true); + pim_ifp = ifp->info; + query_interval = yang_dnode_get_uint16(args->dnode, NULL); + query_interval_dsec = 10 * query_interval; + if (query_interval_dsec <= + pim_ifp->igmp_query_max_response_time_dsec) { + snprintf(args->errmsg, args->errmsg_len, + "Can't set general query interval %d dsec <= query max response time %d dsec.", + query_interval_dsec, + pim_ifp->igmp_query_max_response_time_dsec); + return NB_ERR_INCONSISTENCY; + } + change_query_interval(pim_ifp, query_interval); + } + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-igmp:igmp/query-max-response-time + */ +int lib_interface_igmp_query_max_response_time_modify( + struct nb_cb_modify_args *args) +{ + struct interface *ifp; + struct pim_interface *pim_ifp; + int query_max_response_time_dsec; + int default_query_interval_dsec; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + ifp = nb_running_get_entry(args->dnode, NULL, true); + pim_ifp = ifp->info; + query_max_response_time_dsec = + yang_dnode_get_uint8(args->dnode, NULL); + default_query_interval_dsec = + 10 * pim_ifp->igmp_default_query_interval; + + if (query_max_response_time_dsec + >= default_query_interval_dsec) { + snprintf(args->errmsg, args->errmsg_len, + "Can't set query max response time %d sec >= general query interval %d sec", + query_max_response_time_dsec, + pim_ifp->igmp_default_query_interval); + return NB_ERR_INCONSISTENCY; + } + + change_query_max_response_time(pim_ifp, + query_max_response_time_dsec); + } + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-igmp:igmp/last-member-query-interval + */ +int lib_interface_igmp_last_member_query_interval_modify( + struct nb_cb_modify_args *args) +{ + struct interface *ifp; + struct pim_interface *pim_ifp; + int last_member_query_interval; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + ifp = nb_running_get_entry(args->dnode, NULL, true); + pim_ifp = ifp->info; + last_member_query_interval = yang_dnode_get_uint8(args->dnode, + NULL); + pim_ifp->igmp_specific_query_max_response_time_dsec = + last_member_query_interval; + + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-igmp:igmp/robustness-variable + */ +int lib_interface_igmp_robustness_variable_modify( + struct nb_cb_modify_args *args) +{ + struct interface *ifp; + struct pim_interface *pim_ifp; + int last_member_query_count; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + ifp = nb_running_get_entry(args->dnode, NULL, true); + pim_ifp = ifp->info; + last_member_query_count = yang_dnode_get_uint8(args->dnode, + NULL); + pim_ifp->igmp_last_member_query_count = last_member_query_count; + + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-igmp:igmp/address-family + */ +int lib_interface_igmp_address_family_create(struct nb_cb_create_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + break; + } + + return NB_OK; +} + +int lib_interface_igmp_address_family_destroy(struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-igmp:igmp/address-family/static-group + */ +int lib_interface_igmp_address_family_static_group_create( + struct nb_cb_create_args *args) +{ + struct interface *ifp; + struct ipaddr source_addr; + struct ipaddr group_addr; + int result; + const char *ifp_name; + const struct lyd_node *if_dnode; + + switch (args->event) { + case NB_EV_VALIDATE: + if_dnode = yang_dnode_get_parent(args->dnode, "interface"); + if (!is_pim_interface(if_dnode)) { + ifp_name = yang_dnode_get_string(if_dnode, "."); + snprintf(args->errmsg, args->errmsg_len, + "multicast not enabled on interface %s", + ifp_name); + return NB_ERR_VALIDATION; + } + break; + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + ifp = nb_running_get_entry(args->dnode, NULL, true); + yang_dnode_get_ip(&source_addr, args->dnode, "./source-addr"); + yang_dnode_get_ip(&group_addr, args->dnode, "./group-addr"); + + result = pim_if_igmp_join_add(ifp, group_addr.ip._v4_addr, + source_addr.ip._v4_addr); + if (result) { + snprintf(args->errmsg, args->errmsg_len, + "Failure joining IGMP group"); + return NB_ERR_INCONSISTENCY; + } + } + + return NB_OK; +} + +int lib_interface_igmp_address_family_static_group_destroy( + struct nb_cb_destroy_args *args) +{ + struct interface *ifp; + struct ipaddr source_addr; + struct ipaddr group_addr; + int result; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + ifp = nb_running_get_entry(args->dnode, NULL, true); + yang_dnode_get_ip(&source_addr, args->dnode, "./source-addr"); + yang_dnode_get_ip(&group_addr, args->dnode, "./group-addr"); + + result = pim_if_igmp_join_del(ifp, group_addr.ip._v4_addr, + source_addr.ip._v4_addr); + + if (result) { + char src_str[INET_ADDRSTRLEN]; + char grp_str[INET_ADDRSTRLEN]; + + ipaddr2str(&source_addr, src_str, sizeof(src_str)); + ipaddr2str(&group_addr, grp_str, sizeof(grp_str)); + + snprintf(args->errmsg, args->errmsg_len, + "%% Failure leaving IGMP group %s %s on interface %s: %d", + src_str, grp_str, ifp->name, result); + + return NB_ERR_INCONSISTENCY; + } + + break; + } + + return NB_OK; +} diff --git a/pimd/pim_rp.c b/pimd/pim_rp.c index 7246482f0..727daa42c 100644 --- a/pimd/pim_rp.c +++ b/pimd/pim_rp.c @@ -394,39 +394,6 @@ void pim_upstream_update(struct pim_instance *pim, struct pim_upstream *up) pim_zebra_update_all_interfaces(pim); } -int pim_rp_new_config(struct pim_instance *pim, const char *rp, - const char *group_range, const char *plist) -{ - int result = 0; - struct prefix group; - struct in_addr rp_addr; - - if (group_range == NULL) - result = str2prefix("224.0.0.0/4", &group); - else { - result = str2prefix(group_range, &group); - if (result) { - struct prefix temp; - - prefix_copy(&temp, &group); - apply_mask(&temp); - if (!prefix_same(&group, &temp)) - return PIM_GROUP_BAD_ADDR_MASK_COMBO; - } - } - - if (!result) - return PIM_GROUP_BAD_ADDRESS; - - result = inet_pton(AF_INET, rp, &rp_addr); - - if (result <= 0) - return PIM_RP_BAD_ADDRESS; - - result = pim_rp_new(pim, rp_addr, group, plist, RP_SRC_STATIC); - return result; -} - int pim_rp_new(struct pim_instance *pim, struct in_addr rp_addr, struct prefix group, const char *plist, enum rp_source rp_src_flag) diff --git a/pimd/pim_rp.h b/pimd/pim_rp.h index 6dc26c07a..8a12cb076 100644 --- a/pimd/pim_rp.h +++ b/pimd/pim_rp.h @@ -46,8 +46,6 @@ void pim_rp_free(struct pim_instance *pim); void pim_rp_list_hash_clean(void *data); -int pim_rp_new_config(struct pim_instance *pim, const char *rp, - const char *group, const char *plist); int pim_rp_new(struct pim_instance *pim, struct in_addr rp_addr, struct prefix group, const char *plist, enum rp_source rp_src_flag); diff --git a/pimd/subdir.am b/pimd/subdir.am index 8952d15aa..ad5463caf 100644 --- a/pimd/subdir.am +++ b/pimd/subdir.am @@ -41,6 +41,8 @@ pimd_libpim_a_SOURCES = \ pimd/pim_msdp_packet.c \ pimd/pim_msdp_socket.c \ pimd/pim_msg.c \ + pimd/pim_nb.c \ + pimd/pim_nb_config.c \ pimd/pim_neighbor.c \ pimd/pim_nht.c \ pimd/pim_oil.c \ @@ -66,6 +68,9 @@ pimd_libpim_a_SOURCES = \ pimd/pim_vxlan.c \ pimd/pim_zpthread.c \ pimd/pimd.c \ + yang/frr-pim.yang.c \ + yang/frr-pim-rp.yang.c \ + yang/frr-igmp.yang.c \ # end noinst_HEADERS += \ @@ -96,6 +101,7 @@ noinst_HEADERS += \ pimd/pim_msdp_packet.h \ pimd/pim_msdp_socket.h \ pimd/pim_msg.h \ + pimd/pim_nb.h \ pimd/pim_neighbor.h \ pimd/pim_nht.h \ pimd/pim_oil.h \ @@ -145,3 +151,9 @@ pimd_mtracebis_SOURCES = pimd/mtracebis.c \ pimd/mtracebis_netlink.c \ pimd/mtracebis_routeget.c \ # end + +nodist_pimd_pimd_SOURCES = \ + yang/frr-pim.yang.c \ + yang/frr-pim-rp.yang.c \ + yang/frr-igmp.yang.c \ + # end diff --git a/sharpd/sharp_main.c b/sharpd/sharp_main.c index 4cd92c7f3..fe7f9851f 100644 --- a/sharpd/sharp_main.c +++ b/sharpd/sharp_main.c @@ -139,6 +139,16 @@ static void sharp_global_init(void) sg.nhs = list_new(); } +static void sharp_start_configuration(void) +{ + zlog_debug("Configuration has started to be read"); +} + +static void sharp_end_configuration(void) +{ + zlog_debug("Configuration has finished being read"); +} + int main(int argc, char **argv, char **envp) { frr_preinit(&sharpd_di, argc, argv); @@ -163,6 +173,8 @@ int main(int argc, char **argv, char **envp) master = frr_init(); + cmd_init_config_callbacks(sharp_start_configuration, + sharp_end_configuration); sharp_global_init(); sharp_nhgroup_init(); diff --git a/vtysh/vtysh_config.c b/vtysh/vtysh_config.c index 4b6c648d2..7dcf01988 100644 --- a/vtysh/vtysh_config.c +++ b/vtysh/vtysh_config.c @@ -526,9 +526,13 @@ static int vtysh_read_file(FILE *confp) vtysh_execute_no_pager("enable"); vtysh_execute_no_pager("configure terminal"); + vtysh_execute_no_pager("start_configuration"); + /* Execute configuration file. */ ret = vtysh_config_from_file(vty, confp); + vtysh_execute_no_pager("end_configuration"); + vtysh_execute_no_pager("end"); vtysh_execute_no_pager("disable"); diff --git a/yang/frr-igmp.yang b/yang/frr-igmp.yang index b63d0f97e..e2971dc5c 100644 --- a/yang/frr-igmp.yang +++ b/yang/frr-igmp.yang @@ -71,14 +71,13 @@ module frr-igmp { type boolean; default "false"; description - "Enable IGMP protocol on the interface."; + "Enable IGMP flag on the interface."; } leaf version { type uint8 { range "2..3"; } - default "3"; description "IGMP version."; } @@ -156,8 +155,8 @@ module frr-igmp { */ augment "/frr-interface:lib/frr-interface:interface" { container igmp { - description - "IGMP interface parameters."; + presence + "Configure IGMP on an interface."; uses interface-config-attributes; list address-family { key "address-family"; diff --git a/yang/frr-pim.yang b/yang/frr-pim.yang index 2135d22f6..f959ff8be 100644 --- a/yang/frr-pim.yang +++ b/yang/frr-pim.yang @@ -82,26 +82,19 @@ module frr-pim { "A grouping defining pim global attributes."; leaf ecmp { - type empty; + type boolean; + default "false"; description "Enable PIM ECMP."; } leaf ecmp-rebalance { - type empty; + type boolean; + default "false"; description "Enable PIM ECMP Rebalance."; } - leaf join-prune-interval { - type uint16 { - range "60..600"; - } - default "60"; - description - "Join Prune Send Interval in seconds."; - } - leaf keep-alive-timer { type uint16 { range "31..60000"; @@ -119,26 +112,7 @@ module frr-pim { description "RP keep alive Timer in seconds."; } - - leaf packets { - type uint8 { - range "1..100"; - } - default "3"; - description - "Number of packets to process at one time per fd."; - } - - leaf register-suppress-time { - type uint16 { - range "5..60000"; - } - default "60"; - description - "Register Suppress Timer."; - } } - grouping per-af-global-pim-config-attributes { description "A grouping defining per address family pim global attributes"; @@ -148,7 +122,8 @@ module frr-pim { description "Only applicable to IPv4 address family."; } - type empty; + type boolean; + default "true"; description "Send v6 secondary addresses."; } @@ -241,7 +216,7 @@ module frr-pim { } container mlag { - description + presence "Multi-chassis link aggregation."; leaf peerlink-rif { @@ -300,22 +275,14 @@ module frr-pim { "A grouping defining pim interface attributes."; leaf pim-enable { - type empty; + type boolean; + default "false"; description "Enable PIM flag on the interface."; } - leaf dr-priority { - type uint32 { - range "1..4294967295"; - } - default 1; - description - "DR (Designated Router) priority"; - } - leaf hello-interval { - type uint16 { + type uint8 { range "1..180"; } default "30"; @@ -324,7 +291,7 @@ module frr-pim { } leaf hello-holdtime { - type uint16 { + type uint8 { range "1..180"; } description @@ -364,22 +331,34 @@ module frr-pim { } leaf bsm { - type empty; + type boolean; + default "false"; description "Enables BSM support on the interface."; } leaf unicast-bsm { - type empty; + type boolean; + default "false"; description "Accept/Send unicast BSM on the interface."; } leaf active-active { - type empty; + type boolean; + default "false"; description "Mark interface as Active-Active for MLAG operations."; } + + leaf dr-priority { + type uint32 { + range "1..4294967295"; + } + default 1; + description + "DR (Designated Router) priority"; + } } // interface-pim-config-attributes grouping per-af-interface-pim-config-attributes { @@ -455,8 +434,8 @@ module frr-pim { */ augment "/frr-interface:lib/frr-interface:interface" { container pim { - description - "PIM interface parameters."; + presence + "Configure PIM on an interface."; uses interface-pim-config-attributes; list address-family { key "address-family"; @@ -467,5 +446,33 @@ module frr-pim { } } } -} + container pim { + description + "PIM router parameters."; + leaf packets { + type uint8 { + range "1..100"; + } + default "3"; + description + "Number of packets to process at one time per fd."; + } + leaf join-prune-interval { + type uint16 { + range "60..600"; + } + default "60"; + description + "Join Prune Send Interval in seconds."; + } + leaf register-suppress-time { + type uint16 { + range "5..60000"; + } + default "60"; + description + "Register Suppress Timer."; + } + } +} |