diff --git a/src/sonic-frr/patch/0077-frr-vtysh-dependencies-for-srv6-static-patches.patch b/src/sonic-frr/patch/0077-frr-vtysh-dependencies-for-srv6-static-patches.patch new file mode 100644 index 000000000000..47d13e7a1783 --- /dev/null +++ b/src/sonic-frr/patch/0077-frr-vtysh-dependencies-for-srv6-static-patches.patch @@ -0,0 +1,5712 @@ +From fd8edc3dfbd41ff1ba8c21ea258276f3dab71e4b Mon Sep 17 00:00:00 2001 +From: Nathan Bahr +Date: Wed, 12 Jun 2024 16:26:48 +0000 +Subject: [PATCH] pimd, lib, vtysh: Added new 'router pim[6] [vrf NAME]' config + node + +Moved all existing global/vrf PIM config to the new subnode. +Existing configuration updated to be hidden and deprecated. +Both versions of configuration still work together. + +Signed-off-by: Nathan Bahr +--- + lib/command.h | 2 + + pimd/pim6_cmd.c | 1127 ++++++++++++++-- + pimd/pim_addr.h | 2 + + pimd/pim_cmd.c | 2845 +++++++++++++++++++++++++++++++++-------- + pimd/pim_cmd_common.c | 188 +-- + pimd/pim_cmd_common.h | 2 + + pimd/pim_instance.c | 21 +- + pimd/pim_msdp.c | 18 +- + pimd/pim_msdp.h | 11 +- + pimd/pim_nb.h | 4 - + pimd/pim_rp.c | 13 +- + pimd/pim_rp.h | 3 +- + pimd/pim_vty.c | 68 +- + vtysh/vtysh.c | 89 ++ + vtysh/vtysh_config.c | 5 + + 15 files changed, 3523 insertions(+), 875 deletions(-) + +diff --git a/lib/command.h b/lib/command.h +index 6f819c7e3693..57e3b9cda0b7 100644 +--- a/lib/command.h ++++ b/lib/command.h +@@ -182,6 +182,8 @@ enum node_type { + ISIS_SRV6_NODE_MSD_NODE, /* ISIS SRv6 Node MSDs node */ + MGMTD_NODE, /* MGMTD node. */ + RPKI_VRF_NODE, /* RPKI node for VRF */ ++ PIM_NODE, /* PIM protocol mode */ ++ PIM6_NODE, /* PIM protocol for IPv6 mode */ + NODE_TYPE_MAX, /* maximum */ + }; + /* clang-format on */ +diff --git a/pimd/pim6_cmd.c b/pimd/pim6_cmd.c +index ec912700d193..99f1474712b5 100644 +--- a/pimd/pim6_cmd.c ++++ b/pimd/pim6_cmd.c +@@ -41,45 +41,207 @@ static struct cmd_node debug_node = { + .config_write = pim_debug_config_write, + }; + +-DEFPY (ipv6_pim_joinprune_time, +- ipv6_pim_joinprune_time_cmd, +- "ipv6 pim join-prune-interval (1-65535)$jpi", +- IPV6_STR +- PIM_STR ++DEFPY_NOSH (router_pim6, ++ router_pim6_cmd, ++ "router pim6 [vrf NAME]", ++ "Enable a routing process\n" ++ "Start PIM6 configuration\n" ++ VRF_CMD_HELP_STR) ++{ ++ char xpath[XPATH_MAXLEN]; ++ const char *vrf_name; ++ ++ if (vrf) ++ vrf_name = vrf; ++ else ++ vrf_name = VRF_DEFAULT_NAME; ++ ++ snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", ++ vrf_name, FRR_PIM_AF_XPATH_VAL); ++ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); ++ if (nb_cli_apply_changes_clear_pending(vty, NULL) != CMD_SUCCESS) ++ return CMD_WARNING_CONFIG_FAILED; ++ ++ VTY_PUSH_XPATH(PIM6_NODE, xpath); ++ ++ return CMD_SUCCESS; ++} ++ ++DEFPY (no_router_pim6, ++ no_router_pim6_cmd, ++ "no router pim6 [vrf NAME]", ++ NO_STR ++ "Enable a routing process\n" ++ "Start PIM6 configuration\n" ++ VRF_CMD_HELP_STR) ++{ ++ char xpath[XPATH_MAXLEN]; ++ const char *vrf_name; ++ ++ if (vrf) ++ vrf_name = vrf; ++ else ++ vrf_name = VRF_DEFAULT_NAME; ++ ++ snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", ++ vrf_name, FRR_PIM_AF_XPATH_VAL); ++ ++ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); ++ ++ return nb_cli_apply_changes(vty, NULL); ++} ++ ++DEFPY (pim6_joinprune_time, ++ pim6_joinprune_time_cmd, ++ "join-prune-interval (1-65535)$jpi", + "Join Prune Send Interval\n" + "Seconds\n") + { + return pim_process_join_prune_cmd(vty, jpi_str); + } ++DEFPY_ATTR(ipv6_joinprune_time, ++ ipv6_pim_joinprune_time_cmd, ++ "ipv6 pim join-prune-interval (1-65535)$jpi", ++ IPV6_STR PIM_STR ++ "Join Prune Send Interval\n" ++ "Seconds\n", ++ CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) ++{ ++ int ret; ++ const char *vrfname; ++ char xpath[XPATH_MAXLEN]; ++ int orig_node = -1; ++ ++ vrfname = pim_cli_get_vrf_name(vty); ++ if (vrfname) { ++ snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, ++ "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); ++ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); ++ if (nb_cli_apply_changes_clear_pending(vty, NULL) == ++ CMD_SUCCESS) { ++ orig_node = vty->node; ++ VTY_PUSH_XPATH(PIM6_NODE, xpath); ++ } else { ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ } else { ++ vty_out(vty, "%% Failed to determine vrf name\n"); ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ ++ ret = pim_process_join_prune_cmd(vty, jpi_str); ++ ++ if (orig_node != -1) { ++ vty->node = orig_node; ++ vty->xpath_index--; ++ } ++ ++ return ret; ++} + +-DEFPY (no_ipv6_pim_joinprune_time, +- no_ipv6_pim_joinprune_time_cmd, +- "no ipv6 pim join-prune-interval [(1-65535)]", ++DEFPY (no_pim6_joinprune_time, ++ no_pim6_joinprune_time_cmd, ++ "no join-prune-interval [(1-65535)]", + NO_STR +- IPV6_STR +- PIM_STR + "Join Prune Send Interval\n" + IGNORED_IN_NO_STR) + { + return pim_process_no_join_prune_cmd(vty); + } ++DEFPY_ATTR(no_ipv6_pim_joinprune_time, ++ no_ipv6_pim_joinprune_time_cmd, ++ "no ipv6 pim join-prune-interval [(1-65535)]", ++ NO_STR ++ IPV6_STR ++ PIM_STR ++ "Join Prune Send Interval\n" ++ IGNORED_IN_NO_STR, ++ CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) ++{ ++ int ret; ++ const char *vrfname; ++ char xpath[XPATH_MAXLEN]; ++ int orig_node = -1; ++ ++ vrfname = pim_cli_get_vrf_name(vty); ++ if (vrfname) { ++ snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, ++ "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); ++ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); ++ if (nb_cli_apply_changes_clear_pending(vty, NULL) == ++ CMD_SUCCESS) { ++ orig_node = vty->node; ++ VTY_PUSH_XPATH(PIM6_NODE, xpath); ++ } else { ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ } else { ++ vty_out(vty, "%% Failed to determine vrf name\n"); ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ ++ ret = pim_process_no_join_prune_cmd(vty); ++ ++ if (orig_node != -1) { ++ vty->node = orig_node; ++ vty->xpath_index--; ++ } ++ ++ return ret; ++} + +-DEFPY (ipv6_pim_spt_switchover_infinity, +- ipv6_pim_spt_switchover_infinity_cmd, +- "ipv6 pim spt-switchover infinity-and-beyond", +- IPV6_STR +- PIM_STR ++DEFPY (pim6_spt_switchover_infinity, ++ pim6_spt_switchover_infinity_cmd, ++ "spt-switchover infinity-and-beyond", + "SPT-Switchover\n" + "Never switch to SPT Tree\n") + { + return pim_process_spt_switchover_infinity_cmd(vty); + } ++DEFPY_ATTR(ipv6_spt_switchover_infinity, ++ ipv6_pim_spt_switchover_infinity_cmd, ++ "ipv6 pim spt-switchover infinity-and-beyond", ++ IPV6_STR ++ PIM_STR ++ "SPT-Switchover\n" ++ "Never switch to SPT Tree\n", ++ CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) ++{ ++ int ret; ++ const char *vrfname; ++ char xpath[XPATH_MAXLEN]; ++ int orig_node = -1; ++ ++ vrfname = pim_cli_get_vrf_name(vty); ++ if (vrfname) { ++ snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, ++ "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); ++ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); ++ if (nb_cli_apply_changes_clear_pending(vty, NULL) == ++ CMD_SUCCESS) { ++ orig_node = vty->node; ++ VTY_PUSH_XPATH(PIM6_NODE, xpath); ++ } else { ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ } else { ++ vty_out(vty, "%% Failed to determine vrf name\n"); ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ ++ ret = pim_process_spt_switchover_infinity_cmd(vty); ++ ++ if (orig_node != -1) { ++ vty->node = orig_node; ++ vty->xpath_index--; ++ } ++ ++ return ret; ++} + +-DEFPY (ipv6_pim_spt_switchover_infinity_plist, +- ipv6_pim_spt_switchover_infinity_plist_cmd, +- "ipv6 pim spt-switchover infinity-and-beyond prefix-list PREFIXLIST6_NAME$plist", +- IPV6_STR +- PIM_STR ++DEFPY (pim6_spt_switchover_infinity_plist, ++ pim6_spt_switchover_infinity_plist_cmd, ++ "spt-switchover infinity-and-beyond prefix-list PREFIXLIST6_NAME$plist", + "SPT-Switchover\n" + "Never switch to SPT Tree\n" + "Prefix-List to control which groups to switch\n" +@@ -87,25 +249,104 @@ DEFPY (ipv6_pim_spt_switchover_infinity_plist, + { + return pim_process_spt_switchover_prefixlist_cmd(vty, plist); + } ++DEFPY_ATTR(ipv6_spt_switchover_infinity_plist, ++ ipv6_pim_spt_switchover_infinity_plist_cmd, ++ "ipv6 pim spt-switchover infinity-and-beyond prefix-list PREFIXLIST6_NAME$plist", ++ IPV6_STR ++ PIM_STR ++ "SPT-Switchover\n" ++ "Never switch to SPT Tree\n" ++ "Prefix-List to control which groups to switch\n" ++ "Prefix-List name\n", ++ CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) ++{ ++ int ret; ++ const char *vrfname; ++ char xpath[XPATH_MAXLEN]; ++ int orig_node = -1; ++ ++ vrfname = pim_cli_get_vrf_name(vty); ++ if (vrfname) { ++ snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, ++ "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); ++ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); ++ if (nb_cli_apply_changes_clear_pending(vty, NULL) == ++ CMD_SUCCESS) { ++ orig_node = vty->node; ++ VTY_PUSH_XPATH(PIM6_NODE, xpath); ++ } else { ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ } else { ++ vty_out(vty, "%% Failed to determine vrf name\n"); ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ ++ ret = pim_process_spt_switchover_prefixlist_cmd(vty, plist); ++ ++ if (orig_node != -1) { ++ vty->node = orig_node; ++ vty->xpath_index--; ++ } ++ ++ return ret; ++} + +-DEFPY (no_ipv6_pim_spt_switchover_infinity, +- no_ipv6_pim_spt_switchover_infinity_cmd, +- "no ipv6 pim spt-switchover infinity-and-beyond", ++DEFPY (no_pim6_spt_switchover_infinity, ++ no_pim6_spt_switchover_infinity_cmd, ++ "no spt-switchover infinity-and-beyond", + NO_STR +- IPV6_STR +- PIM_STR + "SPT_Switchover\n" + "Never switch to SPT Tree\n") + { + return pim_process_no_spt_switchover_cmd(vty); + } ++DEFPY_ATTR(no_ipv6_pim_spt_switchover_infinity, ++ no_ipv6_pim_spt_switchover_infinity_cmd, ++ "no ipv6 pim spt-switchover infinity-and-beyond", ++ NO_STR ++ IPV6_STR ++ PIM_STR ++ "SPT_Switchover\n" ++ "Never switch to SPT Tree\n", ++ CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) ++{ ++ int ret; ++ const char *vrfname; ++ char xpath[XPATH_MAXLEN]; ++ int orig_node = -1; ++ ++ vrfname = pim_cli_get_vrf_name(vty); ++ if (vrfname) { ++ snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, ++ "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); ++ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); ++ if (nb_cli_apply_changes_clear_pending(vty, NULL) == ++ CMD_SUCCESS) { ++ orig_node = vty->node; ++ VTY_PUSH_XPATH(PIM6_NODE, xpath); ++ } else { ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ } else { ++ vty_out(vty, "%% Failed to determine vrf name\n"); ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ ++ ret = pim_process_no_spt_switchover_cmd(vty); ++ ++ if (orig_node != -1) { ++ vty->node = orig_node; ++ vty->xpath_index--; ++ } ++ ++ return ret; ++} + +-DEFPY (no_ipv6_pim_spt_switchover_infinity_plist, +- no_ipv6_pim_spt_switchover_infinity_plist_cmd, +- "no ipv6 pim spt-switchover infinity-and-beyond prefix-list PREFIXLIST6_NAME", ++DEFPY (no_pim6_spt_switchover_infinity_plist, ++ no_pim6_spt_switchover_infinity_plist_cmd, ++ "no spt-switchover infinity-and-beyond prefix-list PREFIXLIST6_NAME", + NO_STR +- IPV6_STR +- PIM_STR + "SPT_Switchover\n" + "Never switch to SPT Tree\n" + "Prefix-List to control which groups to switch\n" +@@ -113,100 +354,453 @@ DEFPY (no_ipv6_pim_spt_switchover_infinity_plist, + { + return pim_process_no_spt_switchover_cmd(vty); + } ++DEFPY_ATTR(no_ipv6_pim_spt_switchover_infinity_plist, ++ no_ipv6_pim_spt_switchover_infinity_plist_cmd, ++ "no ipv6 pim spt-switchover infinity-and-beyond prefix-list PREFIXLIST6_NAME", ++ NO_STR ++ IPV6_STR ++ PIM_STR ++ "SPT_Switchover\n" ++ "Never switch to SPT Tree\n" ++ "Prefix-List to control which groups to switch\n" ++ "Prefix-List name\n", ++ CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) ++{ ++ int ret; ++ const char *vrfname; ++ char xpath[XPATH_MAXLEN]; ++ int orig_node = -1; ++ ++ vrfname = pim_cli_get_vrf_name(vty); ++ if (vrfname) { ++ snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, ++ "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); ++ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); ++ if (nb_cli_apply_changes_clear_pending(vty, NULL) == ++ CMD_SUCCESS) { ++ orig_node = vty->node; ++ VTY_PUSH_XPATH(PIM6_NODE, xpath); ++ } else { ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ } else { ++ vty_out(vty, "%% Failed to determine vrf name\n"); ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ ++ ret = pim_process_no_spt_switchover_cmd(vty); ++ ++ if (orig_node != -1) { ++ vty->node = orig_node; ++ vty->xpath_index--; ++ } ++ ++ return ret; ++} + +-DEFPY (ipv6_pim_packets, +- ipv6_pim_packets_cmd, +- "ipv6 pim packets (1-255)", +- IPV6_STR +- PIM_STR ++DEFPY (pim6_packets, ++ pim6_packets_cmd, ++ "packets (1-255)", + "packets to process at one time per fd\n" + "Number of packets\n") + { + return pim_process_pim_packet_cmd(vty, packets_str); + } ++DEFPY_ATTR(ipv6_pim_packets, ++ ipv6_pim_packets_cmd, ++ "ipv6 pim packets (1-255)", ++ IPV6_STR ++ PIM_STR ++ "packets to process at one time per fd\n" ++ "Number of packets\n", ++ CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) ++{ ++ int ret; ++ const char *vrfname; ++ char xpath[XPATH_MAXLEN]; ++ int orig_node = -1; ++ ++ vrfname = pim_cli_get_vrf_name(vty); ++ if (vrfname) { ++ snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, ++ "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); ++ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); ++ if (nb_cli_apply_changes_clear_pending(vty, NULL) == ++ CMD_SUCCESS) { ++ orig_node = vty->node; ++ VTY_PUSH_XPATH(PIM6_NODE, xpath); ++ } else { ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ } else { ++ vty_out(vty, "%% Failed to determine vrf name\n"); ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ ++ ret = pim_process_pim_packet_cmd(vty, packets_str); ++ ++ if (orig_node != -1) { ++ vty->node = orig_node; ++ vty->xpath_index--; ++ } ++ ++ return ret; ++} + +-DEFPY (no_ipv6_pim_packets, +- no_ipv6_pim_packets_cmd, +- "no ipv6 pim packets [(1-255)]", ++DEFPY (no_pim6_packets, ++ no_pim6_packets_cmd, ++ "no packets [(1-255)]", + NO_STR +- IPV6_STR +- PIM_STR + "packets to process at one time per fd\n" + IGNORED_IN_NO_STR) + { + return pim_process_no_pim_packet_cmd(vty); + } ++DEFPY_ATTR(no_ipv6_pim_packets, ++ no_ipv6_pim_packets_cmd, ++ "no ipv6 pim packets [(1-255)]", ++ NO_STR ++ IPV6_STR ++ PIM_STR ++ "packets to process at one time per fd\n" ++ IGNORED_IN_NO_STR, ++ CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) ++{ ++ int ret; ++ const char *vrfname; ++ char xpath[XPATH_MAXLEN]; ++ int orig_node = -1; ++ ++ vrfname = pim_cli_get_vrf_name(vty); ++ if (vrfname) { ++ snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, ++ "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); ++ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); ++ if (nb_cli_apply_changes_clear_pending(vty, NULL) == ++ CMD_SUCCESS) { ++ orig_node = vty->node; ++ VTY_PUSH_XPATH(PIM6_NODE, xpath); ++ } else { ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ } else { ++ vty_out(vty, "%% Failed to determine vrf name\n"); ++ return CMD_WARNING_CONFIG_FAILED; ++ } + +-DEFPY (ipv6_pim_keep_alive, +- ipv6_pim_keep_alive_cmd, +- "ipv6 pim keep-alive-timer (1-65535)$kat", +- IPV6_STR +- PIM_STR ++ ret = pim_process_no_pim_packet_cmd(vty); ++ ++ if (orig_node != -1) { ++ vty->node = orig_node; ++ vty->xpath_index--; ++ } ++ ++ return ret; ++} ++ ++DEFPY (pim6_keep_alive, ++ pim6_keep_alive_cmd, ++ "keep-alive-timer (1-65535)$kat", + "Keep alive Timer\n" + "Seconds\n") + { + return pim_process_keepalivetimer_cmd(vty, kat_str); + } ++DEFPY_ATTR(ipv6_pim_keep_alive, ++ ipv6_pim_keep_alive_cmd, ++ "ipv6 pim keep-alive-timer (1-65535)$kat", ++ IPV6_STR ++ PIM_STR ++ "Keep alive Timer\n" ++ "Seconds\n", ++ CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) ++{ ++ int ret; ++ const char *vrfname; ++ char xpath[XPATH_MAXLEN]; ++ int orig_node = -1; ++ ++ vrfname = pim_cli_get_vrf_name(vty); ++ if (vrfname) { ++ snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, ++ "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); ++ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); ++ if (nb_cli_apply_changes_clear_pending(vty, NULL) == ++ CMD_SUCCESS) { ++ orig_node = vty->node; ++ VTY_PUSH_XPATH(PIM6_NODE, xpath); ++ } else { ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ } else { ++ vty_out(vty, "%% Failed to determine vrf name\n"); ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ ++ ret = pim_process_keepalivetimer_cmd(vty, kat_str); ++ ++ if (orig_node != -1) { ++ vty->node = orig_node; ++ vty->xpath_index--; ++ } ++ ++ return ret; ++} + +-DEFPY (no_ipv6_pim_keep_alive, +- no_ipv6_pim_keep_alive_cmd, +- "no ipv6 pim keep-alive-timer [(1-65535)]", ++DEFPY (no_pim6_keep_alive, ++ no_pim6_keep_alive_cmd, ++ "no keep-alive-timer [(1-65535)]", + NO_STR +- IPV6_STR +- PIM_STR + "Keep alive Timer\n" + IGNORED_IN_NO_STR) + { + return pim_process_no_keepalivetimer_cmd(vty); + } ++DEFPY_ATTR(no_ipv6_pim_keep_alive, ++ no_ipv6_pim_keep_alive_cmd, ++ "no ipv6 pim keep-alive-timer [(1-65535)]", ++ NO_STR ++ IPV6_STR ++ PIM_STR ++ "Keep alive Timer\n" ++ IGNORED_IN_NO_STR, ++ CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) ++{ ++ int ret; ++ const char *vrfname; ++ char xpath[XPATH_MAXLEN]; ++ int orig_node = -1; ++ ++ vrfname = pim_cli_get_vrf_name(vty); ++ if (vrfname) { ++ snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, ++ "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); ++ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); ++ if (nb_cli_apply_changes_clear_pending(vty, NULL) == ++ CMD_SUCCESS) { ++ orig_node = vty->node; ++ VTY_PUSH_XPATH(PIM6_NODE, xpath); ++ } else { ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ } else { ++ vty_out(vty, "%% Failed to determine vrf name\n"); ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ ++ ret = pim_process_no_keepalivetimer_cmd(vty); ++ ++ if (orig_node != -1) { ++ vty->node = orig_node; ++ vty->xpath_index--; ++ } ++ ++ return ret; ++} + +-DEFPY (ipv6_pim_rp_keep_alive, +- ipv6_pim_rp_keep_alive_cmd, +- "ipv6 pim rp keep-alive-timer (1-65535)$kat", +- IPV6_STR +- PIM_STR ++DEFPY (pim6_rp_keep_alive, ++ pim6_rp_keep_alive_cmd, ++ "rp keep-alive-timer (1-65535)$kat", + "Rendezvous Point\n" + "Keep alive Timer\n" + "Seconds\n") + { + return pim_process_rp_kat_cmd(vty, kat_str); + } ++DEFPY_ATTR(ipv6_pim_rp_keep_alive, ++ ipv6_pim_rp_keep_alive_cmd, ++ "ipv6 pim rp keep-alive-timer (1-65535)$kat", ++ IPV6_STR ++ PIM_STR ++ "Rendezvous Point\n" ++ "Keep alive Timer\n" ++ "Seconds\n", ++ CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) ++{ ++ int ret; ++ const char *vrfname; ++ char xpath[XPATH_MAXLEN]; ++ int orig_node = -1; ++ ++ vrfname = pim_cli_get_vrf_name(vty); ++ if (vrfname) { ++ snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, ++ "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); ++ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); ++ if (nb_cli_apply_changes_clear_pending(vty, NULL) == ++ CMD_SUCCESS) { ++ orig_node = vty->node; ++ VTY_PUSH_XPATH(PIM6_NODE, xpath); ++ } else { ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ } else { ++ vty_out(vty, "%% Failed to determine vrf name\n"); ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ ++ ret = pim_process_rp_kat_cmd(vty, kat_str); ++ ++ if (orig_node != -1) { ++ vty->node = orig_node; ++ vty->xpath_index--; ++ } ++ ++ return ret; ++} + +-DEFPY (no_ipv6_pim_rp_keep_alive, +- no_ipv6_pim_rp_keep_alive_cmd, +- "no ipv6 pim rp keep-alive-timer [(1-65535)]", ++DEFPY (no_pim6_rp_keep_alive, ++ no_pim6_rp_keep_alive_cmd, ++ "no rp keep-alive-timer [(1-65535)]", + NO_STR +- IPV6_STR +- PIM_STR + "Rendezvous Point\n" + "Keep alive Timer\n" + IGNORED_IN_NO_STR) + { + return pim_process_no_rp_kat_cmd(vty); + } ++DEFPY_ATTR(no_ipv6_pim_rp_keep_alive, ++ no_ipv6_pim_rp_keep_alive_cmd, ++ "no ipv6 pim rp keep-alive-timer [(1-65535)]", ++ NO_STR ++ IPV6_STR ++ PIM_STR ++ "Rendezvous Point\n" ++ "Keep alive Timer\n" ++ IGNORED_IN_NO_STR, ++ CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) ++{ ++ int ret; ++ const char *vrfname; ++ char xpath[XPATH_MAXLEN]; ++ int orig_node = -1; ++ ++ vrfname = pim_cli_get_vrf_name(vty); ++ if (vrfname) { ++ snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, ++ "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); ++ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); ++ if (nb_cli_apply_changes_clear_pending(vty, NULL) == ++ CMD_SUCCESS) { ++ orig_node = vty->node; ++ VTY_PUSH_XPATH(PIM6_NODE, xpath); ++ } else { ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ } else { ++ vty_out(vty, "%% Failed to determine vrf name\n"); ++ return CMD_WARNING_CONFIG_FAILED; ++ } + +-DEFPY (ipv6_pim_register_suppress, +- ipv6_pim_register_suppress_cmd, +- "ipv6 pim register-suppress-time (1-65535)$rst", +- IPV6_STR +- PIM_STR ++ ret = pim_process_no_rp_kat_cmd(vty); ++ ++ if (orig_node != -1) { ++ vty->node = orig_node; ++ vty->xpath_index--; ++ } ++ ++ return ret; ++} ++ ++DEFPY (pim6_register_suppress, ++ pim6_register_suppress_cmd, ++ "register-suppress-time (1-65535)$rst", + "Register Suppress Timer\n" + "Seconds\n") + { + return pim_process_register_suppress_cmd(vty, rst_str); + } ++DEFPY_ATTR(ipv6_pim_register_suppress, ++ ipv6_pim_register_suppress_cmd, ++ "ipv6 pim register-suppress-time (1-65535)$rst", ++ IPV6_STR ++ PIM_STR ++ "Register Suppress Timer\n" ++ "Seconds\n", ++ CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) ++{ ++ int ret; ++ const char *vrfname; ++ char xpath[XPATH_MAXLEN]; ++ int orig_node = -1; ++ ++ vrfname = pim_cli_get_vrf_name(vty); ++ if (vrfname) { ++ snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, ++ "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); ++ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); ++ if (nb_cli_apply_changes_clear_pending(vty, NULL) == ++ CMD_SUCCESS) { ++ orig_node = vty->node; ++ VTY_PUSH_XPATH(PIM6_NODE, xpath); ++ } else { ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ } else { ++ vty_out(vty, "%% Failed to determine vrf name\n"); ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ ++ ret = pim_process_register_suppress_cmd(vty, rst_str); ++ ++ if (orig_node != -1) { ++ vty->node = orig_node; ++ vty->xpath_index--; ++ } ++ ++ return ret; ++} + +-DEFPY (no_ipv6_pim_register_suppress, +- no_ipv6_pim_register_suppress_cmd, +- "no ipv6 pim register-suppress-time [(1-65535)]", ++DEFPY (no_pim6_register_suppress, ++ no_pim6_register_suppress_cmd, ++ "no register-suppress-time [(1-65535)]", + NO_STR +- IPV6_STR +- PIM_STR + "Register Suppress Timer\n" + IGNORED_IN_NO_STR) + { + return pim_process_no_register_suppress_cmd(vty); + } ++DEFPY_ATTR(no_ipv6_pim_register_suppress, ++ no_ipv6_pim_register_suppress_cmd, ++ "no ipv6 pim register-suppress-time [(1-65535)]", ++ NO_STR ++ IPV6_STR ++ PIM_STR ++ "Register Suppress Timer\n" ++ IGNORED_IN_NO_STR, ++ CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) ++{ ++ int ret; ++ const char *vrfname; ++ char xpath[XPATH_MAXLEN]; ++ int orig_node = -1; ++ ++ vrfname = pim_cli_get_vrf_name(vty); ++ if (vrfname) { ++ snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, ++ "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); ++ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); ++ if (nb_cli_apply_changes_clear_pending(vty, NULL) == ++ CMD_SUCCESS) { ++ orig_node = vty->node; ++ VTY_PUSH_XPATH(PIM6_NODE, xpath); ++ } else { ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ } else { ++ vty_out(vty, "%% Failed to determine vrf name\n"); ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ ++ ret = pim_process_no_register_suppress_cmd(vty); ++ ++ if (orig_node != -1) { ++ vty->node = orig_node; ++ vty->xpath_index--; ++ } ++ ++ return ret; ++} + + DEFPY (interface_ipv6_pim, + interface_ipv6_pim_cmd, +@@ -405,11 +999,9 @@ DEFPY (interface_no_ipv6_mroute, + source_str); + } + +-DEFPY (ipv6_pim_rp, +- ipv6_pim_rp_cmd, +- "ipv6 pim rp X:X::X:X$rp [X:X::X:X/M]$gp", +- IPV6_STR +- PIM_STR ++DEFPY (pim6_rp, ++ pim6_rp_cmd, ++ "rp X:X::X:X$rp [X:X::X:X/M]$gp", + "Rendezvous Point\n" + "ipv6 address of RP\n" + "Group Address range to cover\n") +@@ -418,13 +1010,53 @@ DEFPY (ipv6_pim_rp, + + return pim_process_rp_cmd(vty, rp_str, group_str); + } ++DEFPY_ATTR(ipv6_pim_rp, ++ ipv6_pim_rp_cmd, ++ "ipv6 pim rp X:X::X:X$rp [X:X::X:X/M]$gp", ++ IPV6_STR ++ PIM_STR ++ "Rendezvous Point\n" ++ "ipv6 address of RP\n" ++ "Group Address range to cover\n", ++ CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) ++{ ++ int ret; ++ const char *group_str = (gp_str) ? gp_str : "FF00::0/8"; ++ const char *vrfname; ++ char xpath[XPATH_MAXLEN]; ++ int orig_node = -1; ++ ++ vrfname = pim_cli_get_vrf_name(vty); ++ if (vrfname) { ++ snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, ++ "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); ++ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); ++ if (nb_cli_apply_changes_clear_pending(vty, NULL) == ++ CMD_SUCCESS) { ++ orig_node = vty->node; ++ VTY_PUSH_XPATH(PIM6_NODE, xpath); ++ } else { ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ } else { ++ vty_out(vty, "%% Failed to determine vrf name\n"); ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ ++ ret = pim_process_rp_cmd(vty, rp_str, group_str); ++ ++ if (orig_node != -1) { ++ vty->node = orig_node; ++ vty->xpath_index--; ++ } ++ ++ return ret; ++} + +-DEFPY (no_ipv6_pim_rp, +- no_ipv6_pim_rp_cmd, +- "no ipv6 pim rp X:X::X:X$rp [X:X::X:X/M]$gp", ++DEFPY (no_pim6_rp, ++ no_pim6_rp_cmd, ++ "no rp X:X::X:X$rp [X:X::X:X/M]$gp", + NO_STR +- IPV6_STR +- PIM_STR + "Rendezvous Point\n" + "ipv6 address of RP\n" + "Group Address range to cover\n") +@@ -433,12 +1065,53 @@ DEFPY (no_ipv6_pim_rp, + + return pim_process_no_rp_cmd(vty, rp_str, group_str); + } ++DEFPY_ATTR(no_ipv6_pim_rp, ++ no_ipv6_pim_rp_cmd, ++ "no ipv6 pim rp X:X::X:X$rp [X:X::X:X/M]$gp", ++ NO_STR ++ IPV6_STR ++ PIM_STR ++ "Rendezvous Point\n" ++ "ipv6 address of RP\n" ++ "Group Address range to cover\n", ++ CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) ++{ ++ int ret; ++ const char *group_str = (gp_str) ? gp_str : "FF00::0/8"; ++ const char *vrfname; ++ char xpath[XPATH_MAXLEN]; ++ int orig_node = -1; ++ ++ vrfname = pim_cli_get_vrf_name(vty); ++ if (vrfname) { ++ snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, ++ "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); ++ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); ++ if (nb_cli_apply_changes_clear_pending(vty, NULL) == ++ CMD_SUCCESS) { ++ orig_node = vty->node; ++ VTY_PUSH_XPATH(PIM6_NODE, xpath); ++ } else { ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ } else { ++ vty_out(vty, "%% Failed to determine vrf name\n"); ++ return CMD_WARNING_CONFIG_FAILED; ++ } + +-DEFPY (ipv6_pim_rp_prefix_list, +- ipv6_pim_rp_prefix_list_cmd, +- "ipv6 pim rp X:X::X:X$rp prefix-list PREFIXLIST6_NAME$plist", +- IPV6_STR +- PIM_STR ++ ret = pim_process_no_rp_cmd(vty, rp_str, group_str); ++ ++ if (orig_node != -1) { ++ vty->node = orig_node; ++ vty->xpath_index--; ++ } ++ ++ return ret; ++} ++ ++DEFPY (pim6_rp_prefix_list, ++ pim6_rp_prefix_list_cmd, ++ "rp X:X::X:X$rp prefix-list PREFIXLIST6_NAME$plist", + "Rendezvous Point\n" + "ipv6 address of RP\n" + "group prefix-list filter\n" +@@ -446,13 +1119,53 @@ DEFPY (ipv6_pim_rp_prefix_list, + { + return pim_process_rp_plist_cmd(vty, rp_str, plist); + } ++DEFPY_ATTR(ipv6_pim_rp_prefix_list, ++ ipv6_pim_rp_prefix_list_cmd, ++ "ipv6 pim rp X:X::X:X$rp prefix-list PREFIXLIST6_NAME$plist", ++ IPV6_STR ++ PIM_STR ++ "Rendezvous Point\n" ++ "ipv6 address of RP\n" ++ "group prefix-list filter\n" ++ "Name of a prefix-list\n", ++ CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) ++{ ++ int ret; ++ const char *vrfname; ++ char xpath[XPATH_MAXLEN]; ++ int orig_node = -1; ++ ++ vrfname = pim_cli_get_vrf_name(vty); ++ if (vrfname) { ++ snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, ++ "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); ++ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); ++ if (nb_cli_apply_changes_clear_pending(vty, NULL) == ++ CMD_SUCCESS) { ++ orig_node = vty->node; ++ VTY_PUSH_XPATH(PIM6_NODE, xpath); ++ } else { ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ } else { ++ vty_out(vty, "%% Failed to determine vrf name\n"); ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ ++ ret = pim_process_rp_plist_cmd(vty, rp_str, plist); ++ ++ if (orig_node != -1) { ++ vty->node = orig_node; ++ vty->xpath_index--; ++ } ++ ++ return ret; ++} + +-DEFPY (no_ipv6_pim_rp_prefix_list, +- no_ipv6_pim_rp_prefix_list_cmd, +- "no ipv6 pim rp X:X::X:X$rp prefix-list PREFIXLIST6_NAME$plist", ++DEFPY (no_pim6_rp_prefix_list, ++ no_pim6_rp_prefix_list_cmd, ++ "no rp X:X::X:X$rp prefix-list PREFIXLIST6_NAME$plist", + NO_STR +- IPV6_STR +- PIM_STR + "Rendezvous Point\n" + "ipv6 address of RP\n" + "group prefix-list filter\n" +@@ -460,6 +1173,49 @@ DEFPY (no_ipv6_pim_rp_prefix_list, + { + return pim_process_no_rp_plist_cmd(vty, rp_str, plist); + } ++DEFPY_ATTR(no_ipv6_pim_rp_prefix_list, ++ no_ipv6_pim_rp_prefix_list_cmd, ++ "no ipv6 pim rp X:X::X:X$rp prefix-list PREFIXLIST6_NAME$plist", ++ NO_STR ++ IPV6_STR ++ PIM_STR ++ "Rendezvous Point\n" ++ "ipv6 address of RP\n" ++ "group prefix-list filter\n" ++ "Name of a prefix-list\n", ++ CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) ++{ ++ int ret; ++ const char *vrfname; ++ char xpath[XPATH_MAXLEN]; ++ int orig_node = -1; ++ ++ vrfname = pim_cli_get_vrf_name(vty); ++ if (vrfname) { ++ snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, ++ "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); ++ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); ++ if (nb_cli_apply_changes_clear_pending(vty, NULL) == ++ CMD_SUCCESS) { ++ orig_node = vty->node; ++ VTY_PUSH_XPATH(PIM6_NODE, xpath); ++ } else { ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ } else { ++ vty_out(vty, "%% Failed to determine vrf name\n"); ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ ++ ret = pim_process_no_rp_plist_cmd(vty, rp_str, plist); ++ ++ if (orig_node != -1) { ++ vty->node = orig_node; ++ vty->xpath_index--; ++ } ++ ++ return ret; ++} + + DEFPY (ipv6_pim_bsm, + ipv6_pim_bsm_cmd, +@@ -503,10 +1259,9 @@ DEFPY (no_ipv6_pim_ucast_bsm, + return pim_process_no_unicast_bsm_cmd(vty); + } + +-DEFPY (ipv6_ssmpingd, +- ipv6_ssmpingd_cmd, +- "ipv6 ssmpingd [X:X::X:X]$source", +- IPV6_STR ++DEFPY (pim6_ssmpingd, ++ pim6_ssmpingd_cmd, ++ "ssmpingd [X:X::X:X]$source", + CONF_SSMPINGD_STR + "Source address\n") + { +@@ -514,20 +1269,99 @@ DEFPY (ipv6_ssmpingd, + + return pim_process_ssmpingd_cmd(vty, NB_OP_CREATE, src_str); + } ++DEFPY_ATTR(ipv6_ssmpingd, ++ ipv6_ssmpingd_cmd, ++ "ipv6 ssmpingd [X:X::X:X]$source", ++ IPV6_STR ++ CONF_SSMPINGD_STR ++ "Source address\n", ++ CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) ++{ ++ int ret; ++ const char *src_str = (source_str) ? source_str : "::"; ++ const char *vrfname; ++ char xpath[XPATH_MAXLEN]; ++ int orig_node = -1; ++ ++ vrfname = pim_cli_get_vrf_name(vty); ++ if (vrfname) { ++ snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, ++ "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); ++ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); ++ if (nb_cli_apply_changes_clear_pending(vty, NULL) == ++ CMD_SUCCESS) { ++ orig_node = vty->node; ++ VTY_PUSH_XPATH(PIM6_NODE, xpath); ++ } else { ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ } else { ++ vty_out(vty, "%% Failed to determine vrf name\n"); ++ return CMD_WARNING_CONFIG_FAILED; ++ } + ++ ret = pim_process_ssmpingd_cmd(vty, NB_OP_CREATE, src_str); + +-DEFPY (no_ipv6_ssmpingd, +- no_ipv6_ssmpingd_cmd, +- "no ipv6 ssmpingd [X:X::X:X]$source", +- NO_STR +- IPV6_STR +- CONF_SSMPINGD_STR +- "Source address\n") ++ if (orig_node != -1) { ++ vty->node = orig_node; ++ vty->xpath_index--; ++ } ++ ++ return ret; ++} ++ ++DEFPY (no_pim6_ssmpingd, ++ no_pim6_ssmpingd_cmd, ++ "no ssmpingd [X:X::X:X]$source", ++ NO_STR ++ CONF_SSMPINGD_STR ++ "Source address\n") + { + const char *src_str = (source_str) ? source_str : "::"; + + return pim_process_ssmpingd_cmd(vty, NB_OP_DESTROY, src_str); + } ++DEFPY_ATTR(no_ipv6_ssmpingd, ++ no_ipv6_ssmpingd_cmd, ++ "no ipv6 ssmpingd [X:X::X:X]$source", ++ NO_STR ++ IPV6_STR ++ CONF_SSMPINGD_STR ++ "Source address\n", ++ CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) ++{ ++ int ret; ++ const char *src_str = (source_str) ? source_str : "::"; ++ const char *vrfname; ++ char xpath[XPATH_MAXLEN]; ++ int orig_node = -1; ++ ++ vrfname = pim_cli_get_vrf_name(vty); ++ if (vrfname) { ++ snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, ++ "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); ++ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); ++ if (nb_cli_apply_changes_clear_pending(vty, NULL) == ++ CMD_SUCCESS) { ++ orig_node = vty->node; ++ VTY_PUSH_XPATH(PIM6_NODE, xpath); ++ } else { ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ } else { ++ vty_out(vty, "%% Failed to determine vrf name\n"); ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ ++ ret = pim_process_ssmpingd_cmd(vty, NB_OP_DESTROY, src_str); ++ ++ if (orig_node != -1) { ++ vty->node = orig_node; ++ vty->xpath_index--; ++ } ++ ++ return ret; ++} + + DEFPY (interface_ipv6_mld_join, + interface_ipv6_mld_join_cmd, +@@ -1733,12 +2567,16 @@ DEFPY (debug_pimv6_bsm, + return CMD_SUCCESS; + } + +-void pim_cmd_init(void) +-{ +- if_cmd_init(pim_interface_config_write); +- +- install_node(&debug_node); ++struct cmd_node pim6_node = { ++ .name = "pim6", ++ .node = PIM6_NODE, ++ .parent_node = CONFIG_NODE, ++ .prompt = "%s(config-pim6)# ", ++ .config_write = pim_router_config_write, ++}; + ++static void pim_install_deprecated(void) ++{ + install_element(CONFIG_NODE, &ipv6_pim_joinprune_time_cmd); + install_element(CONFIG_NODE, &no_ipv6_pim_joinprune_time_cmd); + install_element(CONFIG_NODE, &ipv6_pim_spt_switchover_infinity_cmd); +@@ -1753,6 +2591,60 @@ void pim_cmd_init(void) + install_element(CONFIG_NODE, &no_ipv6_pim_rp_keep_alive_cmd); + install_element(CONFIG_NODE, &ipv6_pim_register_suppress_cmd); + install_element(CONFIG_NODE, &no_ipv6_pim_register_suppress_cmd); ++ install_element(CONFIG_NODE, &ipv6_pim_rp_cmd); ++ install_element(VRF_NODE, &ipv6_pim_rp_cmd); ++ install_element(CONFIG_NODE, &no_ipv6_pim_rp_cmd); ++ install_element(VRF_NODE, &no_ipv6_pim_rp_cmd); ++ install_element(CONFIG_NODE, &ipv6_pim_rp_prefix_list_cmd); ++ install_element(VRF_NODE, &ipv6_pim_rp_prefix_list_cmd); ++ install_element(CONFIG_NODE, &no_ipv6_pim_rp_prefix_list_cmd); ++ install_element(VRF_NODE, &no_ipv6_pim_rp_prefix_list_cmd); ++ install_element(CONFIG_NODE, &ipv6_ssmpingd_cmd); ++ install_element(VRF_NODE, &ipv6_ssmpingd_cmd); ++ install_element(CONFIG_NODE, &no_ipv6_ssmpingd_cmd); ++ install_element(VRF_NODE, &no_ipv6_ssmpingd_cmd); ++} ++ ++void pim_cmd_init(void) ++{ ++ if_cmd_init(pim_interface_config_write); ++ ++ install_node(&debug_node); ++ ++ pim_install_deprecated(); ++ ++ install_element(CONFIG_NODE, &router_pim6_cmd); ++ install_element(CONFIG_NODE, &no_router_pim6_cmd); ++ ++ install_node(&pim6_node); ++ install_default(PIM6_NODE); ++ ++ install_element(PIM6_NODE, &pim6_joinprune_time_cmd); ++ install_element(PIM6_NODE, &no_pim6_joinprune_time_cmd); ++ install_element(PIM6_NODE, &pim6_spt_switchover_infinity_cmd); ++ install_element(PIM6_NODE, &pim6_spt_switchover_infinity_plist_cmd); ++ install_element(PIM6_NODE, &no_pim6_spt_switchover_infinity_cmd); ++ install_element(PIM6_NODE, &no_pim6_spt_switchover_infinity_plist_cmd); ++ install_element(PIM6_NODE, &pim6_packets_cmd); ++ install_element(PIM6_NODE, &no_pim6_packets_cmd); ++ install_element(PIM6_NODE, &pim6_keep_alive_cmd); ++ install_element(PIM6_NODE, &no_pim6_keep_alive_cmd); ++ install_element(PIM6_NODE, &pim6_rp_keep_alive_cmd); ++ install_element(PIM6_NODE, &no_pim6_rp_keep_alive_cmd); ++ install_element(PIM6_NODE, &pim6_register_suppress_cmd); ++ install_element(PIM6_NODE, &no_pim6_register_suppress_cmd); ++ install_element(PIM6_NODE, &pim6_rp_cmd); ++ install_element(PIM6_NODE, &no_pim6_rp_cmd); ++ install_element(PIM6_NODE, &pim6_rp_prefix_list_cmd); ++ install_element(PIM6_NODE, &no_pim6_rp_prefix_list_cmd); ++ install_element(PIM6_NODE, &pim6_ssmpingd_cmd); ++ install_element(PIM6_NODE, &no_pim6_ssmpingd_cmd); ++ ++ install_element(CONFIG_NODE, &ipv6_mld_group_watermark_cmd); ++ install_element(VRF_NODE, &ipv6_mld_group_watermark_cmd); ++ install_element(CONFIG_NODE, &no_ipv6_mld_group_watermark_cmd); ++ install_element(VRF_NODE, &no_ipv6_mld_group_watermark_cmd); ++ + install_element(INTERFACE_NODE, &interface_ipv6_pim_cmd); + install_element(INTERFACE_NODE, &interface_no_ipv6_pim_cmd); + install_element(INTERFACE_NODE, &interface_ipv6_pim_drprio_cmd); +@@ -1764,10 +2656,8 @@ void pim_cmd_init(void) + install_element(INTERFACE_NODE, &interface_no_ipv6_pim_ssm_cmd); + install_element(INTERFACE_NODE, &interface_ipv6_pim_sm_cmd); + install_element(INTERFACE_NODE, &interface_no_ipv6_pim_sm_cmd); +- install_element(INTERFACE_NODE, +- &interface_ipv6_pim_boundary_oil_cmd); +- install_element(INTERFACE_NODE, +- &interface_no_ipv6_pim_boundary_oil_cmd); ++ install_element(INTERFACE_NODE, &interface_ipv6_pim_boundary_oil_cmd); ++ install_element(INTERFACE_NODE, &interface_no_ipv6_pim_boundary_oil_cmd); + install_element(INTERFACE_NODE, &interface_ipv6_mroute_cmd); + install_element(INTERFACE_NODE, &interface_no_ipv6_mroute_cmd); + /* Install BSM command */ +@@ -1775,18 +2665,7 @@ void pim_cmd_init(void) + install_element(INTERFACE_NODE, &no_ipv6_pim_bsm_cmd); + install_element(INTERFACE_NODE, &ipv6_pim_ucast_bsm_cmd); + install_element(INTERFACE_NODE, &no_ipv6_pim_ucast_bsm_cmd); +- install_element(CONFIG_NODE, &ipv6_pim_rp_cmd); +- install_element(VRF_NODE, &ipv6_pim_rp_cmd); +- install_element(CONFIG_NODE, &no_ipv6_pim_rp_cmd); +- install_element(VRF_NODE, &no_ipv6_pim_rp_cmd); +- install_element(CONFIG_NODE, &ipv6_pim_rp_prefix_list_cmd); +- install_element(VRF_NODE, &ipv6_pim_rp_prefix_list_cmd); +- install_element(CONFIG_NODE, &no_ipv6_pim_rp_prefix_list_cmd); +- install_element(VRF_NODE, &no_ipv6_pim_rp_prefix_list_cmd); +- install_element(CONFIG_NODE, &ipv6_ssmpingd_cmd); +- install_element(VRF_NODE, &ipv6_ssmpingd_cmd); +- install_element(CONFIG_NODE, &no_ipv6_ssmpingd_cmd); +- install_element(VRF_NODE, &no_ipv6_ssmpingd_cmd); ++ + install_element(INTERFACE_NODE, &interface_ipv6_mld_cmd); + install_element(INTERFACE_NODE, &interface_no_ipv6_mld_cmd); + install_element(INTERFACE_NODE, &interface_ipv6_mld_join_cmd); +@@ -1796,10 +2675,6 @@ void pim_cmd_init(void) + install_element(INTERFACE_NODE, &interface_ipv6_mld_query_interval_cmd); + install_element(INTERFACE_NODE, + &interface_no_ipv6_mld_query_interval_cmd); +- install_element(CONFIG_NODE, &ipv6_mld_group_watermark_cmd); +- install_element(VRF_NODE, &ipv6_mld_group_watermark_cmd); +- install_element(CONFIG_NODE, &no_ipv6_mld_group_watermark_cmd); +- install_element(VRF_NODE, &no_ipv6_mld_group_watermark_cmd); + install_element(INTERFACE_NODE, + &interface_ipv6_mld_query_max_response_time_cmd); + install_element(INTERFACE_NODE, +diff --git a/pimd/pim_addr.h b/pimd/pim_addr.h +index 7b0c3f0350e2..c1416e1dd0f6 100644 +--- a/pimd/pim_addr.h ++++ b/pimd/pim_addr.h +@@ -26,6 +26,7 @@ typedef struct prefix_ipv4 prefix_pim; + #define PIM_MAX_BITLEN IPV4_MAX_BITLEN + #define PIM_AF_NAME "ip" + #define PIM_AF_DBG "pim" ++#define PIM_AF_ROUTER "pim" + #define GM_AF_DBG "igmp" + #define PIM_MROUTE_DBG "mroute" + #define PIMREG "pimreg" +@@ -58,6 +59,7 @@ typedef struct prefix_ipv6 prefix_pim; + #define PIM_MAX_BITLEN IPV6_MAX_BITLEN + #define PIM_AF_NAME "ipv6" + #define PIM_AF_DBG "pimv6" ++#define PIM_AF_ROUTER "pim6" + #define GM_AF_DBG "mld" + #define PIM_MROUTE_DBG "mroute6" + #define PIMREG "pim6reg" +diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c +index a2d756a96a20..2b8d3e56e521 100644 +--- a/pimd/pim_cmd.c ++++ b/pimd/pim_cmd.c +@@ -1457,19 +1457,13 @@ static void clear_interfaces(struct pim_instance *pim) + static void pim_cli_legacy_mesh_group_behavior(struct vty *vty, + const char *gname) + { +- const char *vrfname; + char xpath_value[XPATH_MAXLEN]; + char xpath_member_value[XPATH_MAXLEN]; + const struct lyd_node *member_dnode; + +- vrfname = pim_cli_get_vrf_name(vty); +- if (vrfname == NULL) +- return; +- + /* Get mesh group base XPath. */ + snprintf(xpath_value, sizeof(xpath_value), +- FRR_PIM_VRF_XPATH "/msdp-mesh-groups[name='%s']", +- "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4", gname); ++ "%s/msdp-mesh-groups[name='%s']", VTY_CURR_XPATH, gname); + /* Group must exists, otherwise just quit. */ + if (!yang_dnode_exists(vty->candidate_config->dnode, xpath_value)) + return; +@@ -1477,8 +1471,7 @@ static void pim_cli_legacy_mesh_group_behavior(struct vty *vty, + /* Group members check: */ + strlcpy(xpath_member_value, xpath_value, sizeof(xpath_member_value)); + strlcat(xpath_member_value, "/members", sizeof(xpath_member_value)); +- if (yang_dnode_exists(vty->candidate_config->dnode, +- xpath_member_value)) { ++ if (yang_dnode_exists(vty->candidate_config->dnode, xpath_member_value)) { + member_dnode = yang_dnode_get(vty->candidate_config->dnode, + xpath_member_value); + if (!member_dnode || !yang_is_last_list_dnode(member_dnode)) +@@ -2989,22 +2982,108 @@ DEFUN (show_ip_ssmpingd, + return CMD_SUCCESS; + } + +-DEFUN (ip_pim_spt_switchover_infinity, +- ip_pim_spt_switchover_infinity_cmd, +- "ip pim spt-switchover infinity-and-beyond", +- IP_STR +- PIM_STR ++DEFPY_NOSH (router_pim, ++ router_pim_cmd, ++ "router pim [vrf NAME]", ++ "Enable a routing process\n" ++ "Start PIM configuration\n" ++ VRF_CMD_HELP_STR) ++{ ++ char xpath[XPATH_MAXLEN]; ++ const char *vrf_name; ++ ++ if (vrf) ++ vrf_name = vrf; ++ else ++ vrf_name = VRF_DEFAULT_NAME; ++ ++ snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", ++ vrf_name, FRR_PIM_AF_XPATH_VAL); ++ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); ++ if (nb_cli_apply_changes_clear_pending(vty, NULL) != CMD_SUCCESS) ++ return CMD_WARNING_CONFIG_FAILED; ++ ++ VTY_PUSH_XPATH(PIM_NODE, xpath); ++ return CMD_SUCCESS; ++} ++ ++DEFPY (no_router_pim, ++ no_router_pim_cmd, ++ "no router pim [vrf NAME]", ++ NO_STR ++ "Enable a routing process\n" ++ "Start PIM configuration\n" ++ VRF_CMD_HELP_STR) ++{ ++ char xpath[XPATH_MAXLEN]; ++ const char *vrf_name; ++ ++ if (vrf) ++ vrf_name = vrf; ++ else ++ vrf_name = VRF_DEFAULT_NAME; ++ ++ snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", ++ vrf_name, FRR_PIM_AF_XPATH_VAL); ++ ++ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); ++ ++ return nb_cli_apply_changes(vty, NULL); ++} ++ ++ ++DEFPY (pim_spt_switchover_infinity, ++ pim_spt_switchover_infinity_cmd, ++ "spt-switchover infinity-and-beyond", + "SPT-Switchover\n" + "Never switch to SPT Tree\n") + { + return pim_process_spt_switchover_infinity_cmd(vty); + } ++DEFPY_ATTR(ip_pim_spt_switchover_infinity, ++ ip_pim_spt_switchover_infinity_cmd, ++ "ip pim spt-switchover infinity-and-beyond", ++ IP_STR ++ PIM_STR ++ "SPT-Switchover\n" ++ "Never switch to SPT Tree\n", ++ CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) ++{ ++ int ret; ++ const char *vrfname; ++ char xpath[XPATH_MAXLEN]; ++ int orig_node = -1; ++ ++ vrfname = pim_cli_get_vrf_name(vty); ++ if (vrfname) { ++ snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, ++ "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); ++ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); ++ if (nb_cli_apply_changes_clear_pending(vty, NULL) == ++ CMD_SUCCESS) { ++ orig_node = vty->node; ++ VTY_PUSH_XPATH(PIM_NODE, xpath); ++ } else { ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ } else { ++ vty_out(vty, "%% Failed to determine vrf name\n"); ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ ++ ret = pim_process_spt_switchover_infinity_cmd(vty); ++ ++ if (orig_node != -1) { ++ vty->node = orig_node; ++ vty->xpath_index--; ++ } ++ ++ return ret; ++} + +-DEFPY (ip_pim_spt_switchover_infinity_plist, +- ip_pim_spt_switchover_infinity_plist_cmd, +- "ip pim spt-switchover infinity-and-beyond prefix-list PREFIXLIST4_NAME$plist", +- IP_STR +- PIM_STR ++DEFPY (pim_spt_switchover_infinity_plist, ++ pim_spt_switchover_infinity_plist_cmd, ++ "spt-switchover infinity-and-beyond prefix-list PREFIXLIST4_NAME$plist", + "SPT-Switchover\n" + "Never switch to SPT Tree\n" + "Prefix-List to control which groups to switch\n" +@@ -3012,25 +3091,104 @@ DEFPY (ip_pim_spt_switchover_infinity_plist, + { + return pim_process_spt_switchover_prefixlist_cmd(vty, plist); + } ++DEFPY_ATTR(ip_pim_spt_switchover_infinity_plist, ++ ip_pim_spt_switchover_infinity_plist_cmd, ++ "ip pim spt-switchover infinity-and-beyond prefix-list PREFIXLIST4_NAME$plist", ++ IP_STR ++ PIM_STR ++ "SPT-Switchover\n" ++ "Never switch to SPT Tree\n" ++ "Prefix-List to control which groups to switch\n" ++ "Prefix-List name\n", ++ CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) ++{ ++ int ret; ++ const char *vrfname; ++ char xpath[XPATH_MAXLEN]; ++ int orig_node = -1; ++ ++ vrfname = pim_cli_get_vrf_name(vty); ++ if (vrfname) { ++ snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, ++ "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); ++ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); ++ if (nb_cli_apply_changes_clear_pending(vty, NULL) == ++ CMD_SUCCESS) { ++ orig_node = vty->node; ++ VTY_PUSH_XPATH(PIM_NODE, xpath); ++ } else { ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ } else { ++ vty_out(vty, "%% Failed to determine vrf name\n"); ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ ++ ret = pim_process_spt_switchover_prefixlist_cmd(vty, plist); ++ ++ if (orig_node != -1) { ++ vty->node = orig_node; ++ vty->xpath_index--; ++ } ++ ++ return ret; ++} + +-DEFUN (no_ip_pim_spt_switchover_infinity, +- no_ip_pim_spt_switchover_infinity_cmd, +- "no ip pim spt-switchover infinity-and-beyond", ++DEFPY (no_pim_spt_switchover_infinity, ++ no_pim_spt_switchover_infinity_cmd, ++ "no spt-switchover infinity-and-beyond", + NO_STR +- IP_STR +- PIM_STR + "SPT_Switchover\n" + "Never switch to SPT Tree\n") + { + return pim_process_no_spt_switchover_cmd(vty); + } ++DEFPY_ATTR(no_ip_pim_spt_switchover_infinity, ++ no_ip_pim_spt_switchover_infinity_cmd, ++ "no ip pim spt-switchover infinity-and-beyond", ++ NO_STR ++ IP_STR ++ PIM_STR ++ "SPT_Switchover\n" ++ "Never switch to SPT Tree\n", ++ CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) ++{ ++ int ret; ++ const char *vrfname; ++ char xpath[XPATH_MAXLEN]; ++ int orig_node = -1; ++ ++ vrfname = pim_cli_get_vrf_name(vty); ++ if (vrfname) { ++ snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, ++ "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); ++ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); ++ if (nb_cli_apply_changes_clear_pending(vty, NULL) == ++ CMD_SUCCESS) { ++ orig_node = vty->node; ++ VTY_PUSH_XPATH(PIM_NODE, xpath); ++ } else { ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ } else { ++ vty_out(vty, "%% Failed to determine vrf name\n"); ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ ++ ret = pim_process_no_spt_switchover_cmd(vty); ++ ++ if (orig_node != -1) { ++ vty->node = orig_node; ++ vty->xpath_index--; ++ } ++ ++ return ret; ++} + +-DEFUN (no_ip_pim_spt_switchover_infinity_plist, +- no_ip_pim_spt_switchover_infinity_plist_cmd, +- "no ip pim spt-switchover infinity-and-beyond prefix-list PREFIXLIST4_NAME", ++DEFPY (no_pim_spt_switchover_infinity_plist, ++ no_pim_spt_switchover_infinity_plist_cmd, ++ "no spt-switchover infinity-and-beyond prefix-list PREFIXLIST4_NAME", + NO_STR +- IP_STR +- PIM_STR + "SPT_Switchover\n" + "Never switch to SPT Tree\n" + "Prefix-List to control which groups to switch\n" +@@ -3038,28 +3196,61 @@ DEFUN (no_ip_pim_spt_switchover_infinity_plist, + { + return pim_process_no_spt_switchover_cmd(vty); + } ++DEFPY_ATTR(no_ip_pim_spt_switchover_infinity_plist, ++ no_ip_pim_spt_switchover_infinity_plist_cmd, ++ "no ip pim spt-switchover infinity-and-beyond prefix-list PREFIXLIST4_NAME", ++ NO_STR ++ IP_STR ++ PIM_STR ++ "SPT_Switchover\n" ++ "Never switch to SPT Tree\n" ++ "Prefix-List to control which groups to switch\n" ++ "Prefix-List name\n", ++ CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) ++{ ++ int ret; ++ const char *vrfname; ++ char xpath[XPATH_MAXLEN]; ++ int orig_node = -1; ++ ++ vrfname = pim_cli_get_vrf_name(vty); ++ if (vrfname) { ++ snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, ++ "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); ++ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); ++ if (nb_cli_apply_changes_clear_pending(vty, NULL) == ++ CMD_SUCCESS) { ++ orig_node = vty->node; ++ VTY_PUSH_XPATH(PIM_NODE, xpath); ++ } else { ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ } else { ++ vty_out(vty, "%% Failed to determine vrf name\n"); ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ ++ ret = pim_process_no_spt_switchover_cmd(vty); ++ ++ if (orig_node != -1) { ++ vty->node = orig_node; ++ vty->xpath_index--; ++ } ++ ++ return ret; ++} + + DEFPY (pim_register_accept_list, + pim_register_accept_list_cmd, +- "[no] ip pim register-accept-list PREFIXLIST4_NAME$word", ++ "[no] register-accept-list PREFIXLIST4_NAME$word", + NO_STR +- IP_STR +- PIM_STR + "Only accept registers from a specific source prefix list\n" + "Prefix-List name\n") + { +- const char *vrfname; + char reg_alist_xpath[XPATH_MAXLEN]; + +- vrfname = pim_cli_get_vrf_name(vty); +- if (vrfname == NULL) +- return CMD_WARNING_CONFIG_FAILED; +- + snprintf(reg_alist_xpath, sizeof(reg_alist_xpath), +- FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname, +- "frr-routing:ipv4"); +- strlcat(reg_alist_xpath, "/register-accept-list", +- sizeof(reg_alist_xpath)); ++ "./register-accept-list"); + + if (no) + nb_cli_enqueue_change(vty, reg_alist_xpath, +@@ -3070,123 +3261,560 @@ DEFPY (pim_register_accept_list, + + return nb_cli_apply_changes(vty, NULL); + } ++DEFPY_ATTR(ip_pim_register_accept_list, ++ ip_pim_register_accept_list_cmd, ++ "[no] ip pim register-accept-list PREFIXLIST4_NAME$word", ++ NO_STR ++ IP_STR ++ PIM_STR ++ "Only accept registers from a specific source prefix list\n" ++ "Prefix-List name\n", ++ CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) ++{ ++ char reg_alist_xpath[XPATH_MAXLEN]; ++ int ret; ++ const char *vrfname; ++ char xpath[XPATH_MAXLEN]; ++ int orig_node = -1; + +-DEFPY (ip_pim_joinprune_time, +- ip_pim_joinprune_time_cmd, +- "ip pim join-prune-interval (1-65535)$jpi", +- IP_STR +- "pim multicast routing\n" ++ vrfname = pim_cli_get_vrf_name(vty); ++ if (vrfname) { ++ snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, ++ "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); ++ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); ++ if (nb_cli_apply_changes_clear_pending(vty, NULL) == ++ CMD_SUCCESS) { ++ orig_node = vty->node; ++ VTY_PUSH_XPATH(PIM_NODE, xpath); ++ } else { ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ } else { ++ vty_out(vty, "%% Failed to determine vrf name\n"); ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ ++ snprintf(reg_alist_xpath, sizeof(reg_alist_xpath), ++ "./register-accept-list"); ++ ++ if (no) ++ 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); ++ ++ ret = nb_cli_apply_changes(vty, NULL); ++ ++ if (orig_node != -1) { ++ vty->node = orig_node; ++ vty->xpath_index--; ++ } ++ ++ return ret; ++} ++ ++DEFPY (pim_joinprune_time, ++ pim_joinprune_time_cmd, ++ "join-prune-interval (1-65535)$jpi", + "Join Prune Send Interval\n" + "Seconds\n") + { + return pim_process_join_prune_cmd(vty, jpi_str); + } ++DEFPY_ATTR(ip_pim_joinprune_time, ++ ip_pim_joinprune_time_cmd, ++ "ip pim join-prune-interval (1-65535)$jpi", ++ IP_STR ++ PIM_STR ++ "Join Prune Send Interval\n" ++ "Seconds\n", ++ CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) ++{ ++ int ret; ++ const char *vrfname; ++ char xpath[XPATH_MAXLEN]; ++ int orig_node = -1; ++ ++ vrfname = pim_cli_get_vrf_name(vty); ++ if (vrfname) { ++ snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, ++ "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); ++ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); ++ if (nb_cli_apply_changes_clear_pending(vty, NULL) == ++ CMD_SUCCESS) { ++ orig_node = vty->node; ++ VTY_PUSH_XPATH(PIM_NODE, xpath); ++ } else { ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ } else { ++ vty_out(vty, "%% Failed to determine vrf name\n"); ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ ++ ret = pim_process_join_prune_cmd(vty, jpi_str); ++ ++ if (orig_node != -1) { ++ vty->node = orig_node; ++ vty->xpath_index--; ++ } ++ ++ return ret; ++} + +-DEFUN (no_ip_pim_joinprune_time, +- no_ip_pim_joinprune_time_cmd, +- "no ip pim join-prune-interval [(1-65535)]", ++DEFPY (no_pim_joinprune_time, ++ no_pim_joinprune_time_cmd, ++ "no join-prune-interval [(1-65535)]", + NO_STR +- IP_STR +- "pim multicast routing\n" + "Join Prune Send Interval\n" + IGNORED_IN_NO_STR) + { + return pim_process_no_join_prune_cmd(vty); + } ++DEFPY_ATTR(no_ip_pim_joinprune_time, ++ no_ip_pim_joinprune_time_cmd, ++ "no ip pim join-prune-interval [(1-65535)]", ++ NO_STR ++ IP_STR ++ PIM_STR ++ "Join Prune Send Interval\n" ++ IGNORED_IN_NO_STR, ++ CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) ++{ ++ int ret; ++ const char *vrfname; ++ char xpath[XPATH_MAXLEN]; ++ int orig_node = -1; + +-DEFPY (ip_pim_register_suppress, +- ip_pim_register_suppress_cmd, +- "ip pim register-suppress-time (1-65535)$rst", +- IP_STR +- "pim multicast routing\n" ++ vrfname = pim_cli_get_vrf_name(vty); ++ if (vrfname) { ++ snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, ++ "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); ++ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); ++ if (nb_cli_apply_changes_clear_pending(vty, NULL) == ++ CMD_SUCCESS) { ++ orig_node = vty->node; ++ VTY_PUSH_XPATH(PIM_NODE, xpath); ++ } else { ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ } else { ++ vty_out(vty, "%% Failed to determine vrf name\n"); ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ ++ ret = pim_process_no_join_prune_cmd(vty); ++ ++ if (orig_node != -1) { ++ vty->node = orig_node; ++ vty->xpath_index--; ++ } ++ ++ return ret; ++} ++ ++DEFPY (pim_register_suppress, ++ pim_register_suppress_cmd, ++ "register-suppress-time (1-65535)$rst", + "Register Suppress Timer\n" + "Seconds\n") + { + return pim_process_register_suppress_cmd(vty, rst_str); + } ++DEFPY_ATTR(ip_pim_register_suppress, ++ ip_pim_register_suppress_cmd, ++ "ip pim register-suppress-time (1-65535)$rst", ++ IP_STR ++ PIM_STR ++ "Register Suppress Timer\n" ++ "Seconds\n", ++ CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) ++{ ++ int ret; ++ const char *vrfname; ++ char xpath[XPATH_MAXLEN]; ++ int orig_node = -1; ++ ++ vrfname = pim_cli_get_vrf_name(vty); ++ if (vrfname) { ++ snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, ++ "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); ++ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); ++ if (nb_cli_apply_changes_clear_pending(vty, NULL) == ++ CMD_SUCCESS) { ++ orig_node = vty->node; ++ VTY_PUSH_XPATH(PIM_NODE, xpath); ++ } else { ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ } else { ++ vty_out(vty, "%% Failed to determine vrf name\n"); ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ ++ ret = pim_process_register_suppress_cmd(vty, rst_str); ++ ++ if (orig_node != -1) { ++ vty->node = orig_node; ++ vty->xpath_index--; ++ } ++ ++ return ret; ++} + +-DEFUN (no_ip_pim_register_suppress, +- no_ip_pim_register_suppress_cmd, +- "no ip pim register-suppress-time [(1-65535)]", ++DEFPY (no_pim_register_suppress, ++ no_pim_register_suppress_cmd, ++ "no register-suppress-time [(1-65535)]", + NO_STR +- IP_STR +- "pim multicast routing\n" + "Register Suppress Timer\n" + IGNORED_IN_NO_STR) + { + return pim_process_no_register_suppress_cmd(vty); + } ++DEFPY_ATTR(no_ip_pim_register_suppress, ++ no_ip_pim_register_suppress_cmd, ++ "no ip pim register-suppress-time [(1-65535)]", ++ NO_STR ++ IP_STR ++ PIM_STR ++ "Register Suppress Timer\n" ++ IGNORED_IN_NO_STR, ++ CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) ++{ ++ int ret; ++ const char *vrfname; ++ char xpath[XPATH_MAXLEN]; ++ int orig_node = -1; ++ ++ vrfname = pim_cli_get_vrf_name(vty); ++ if (vrfname) { ++ snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, ++ "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); ++ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); ++ if (nb_cli_apply_changes_clear_pending(vty, NULL) == ++ CMD_SUCCESS) { ++ orig_node = vty->node; ++ VTY_PUSH_XPATH(PIM_NODE, xpath); ++ } else { ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ } else { ++ vty_out(vty, "%% Failed to determine vrf name\n"); ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ ++ ret = pim_process_no_register_suppress_cmd(vty); ++ ++ if (orig_node != -1) { ++ vty->node = orig_node; ++ vty->xpath_index--; ++ } ++ ++ return ret; ++} + +-DEFPY (ip_pim_rp_keep_alive, +- ip_pim_rp_keep_alive_cmd, +- "ip pim rp keep-alive-timer (1-65535)$kat", +- IP_STR +- "pim multicast routing\n" ++DEFPY (pim_rp_keep_alive, ++ pim_rp_keep_alive_cmd, ++ "rp keep-alive-timer (1-65535)$kat", + "Rendezvous Point\n" + "Keep alive Timer\n" + "Seconds\n") + { + return pim_process_rp_kat_cmd(vty, kat_str); + } ++DEFPY_ATTR(ip_pim_rp_keep_alive, ++ ip_pim_rp_keep_alive_cmd, ++ "ip pim rp keep-alive-timer (1-65535)$kat", ++ IP_STR ++ PIM_STR ++ "Rendezvous Point\n" ++ "Keep alive Timer\n" ++ "Seconds\n", ++ CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) ++{ ++ int ret; ++ const char *vrfname; ++ char xpath[XPATH_MAXLEN]; ++ int orig_node = -1; ++ ++ vrfname = pim_cli_get_vrf_name(vty); ++ if (vrfname) { ++ snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, ++ "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); ++ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); ++ if (nb_cli_apply_changes_clear_pending(vty, NULL) == ++ CMD_SUCCESS) { ++ orig_node = vty->node; ++ VTY_PUSH_XPATH(PIM_NODE, xpath); ++ } else { ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ } else { ++ vty_out(vty, "%% Failed to determine vrf name\n"); ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ ++ ret = pim_process_rp_kat_cmd(vty, kat_str); ++ ++ if (orig_node != -1) { ++ vty->node = orig_node; ++ vty->xpath_index--; ++ } ++ ++ return ret; ++} + +-DEFUN (no_ip_pim_rp_keep_alive, +- no_ip_pim_rp_keep_alive_cmd, +- "no ip pim rp keep-alive-timer [(1-65535)]", ++DEFPY (no_pim_rp_keep_alive, ++ no_pim_rp_keep_alive_cmd, ++ "no rp keep-alive-timer [(1-65535)]", + NO_STR +- IP_STR +- "pim multicast routing\n" + "Rendezvous Point\n" + "Keep alive Timer\n" + IGNORED_IN_NO_STR) + { + return pim_process_no_rp_kat_cmd(vty); + } ++DEFPY_ATTR(no_ip_pim_rp_keep_alive, ++ no_ip_pim_rp_keep_alive_cmd, ++ "no ip pim rp keep-alive-timer [(1-65535)]", ++ NO_STR ++ IP_STR ++ PIM_STR ++ "Rendezvous Point\n" ++ "Keep alive Timer\n" ++ IGNORED_IN_NO_STR, ++ CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) ++{ ++ int ret; ++ const char *vrfname; ++ char xpath[XPATH_MAXLEN]; ++ int orig_node = -1; + +-DEFPY (ip_pim_keep_alive, +- ip_pim_keep_alive_cmd, +- "ip pim keep-alive-timer (1-65535)$kat", +- IP_STR +- "pim multicast routing\n" ++ vrfname = pim_cli_get_vrf_name(vty); ++ if (vrfname) { ++ snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, ++ "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); ++ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); ++ if (nb_cli_apply_changes_clear_pending(vty, NULL) == ++ CMD_SUCCESS) { ++ orig_node = vty->node; ++ VTY_PUSH_XPATH(PIM_NODE, xpath); ++ } else { ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ } else { ++ vty_out(vty, "%% Failed to determine vrf name\n"); ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ ++ ret = pim_process_no_rp_kat_cmd(vty); ++ ++ if (orig_node != -1) { ++ vty->node = orig_node; ++ vty->xpath_index--; ++ } ++ ++ return ret; ++} ++ ++DEFPY (pim_keep_alive, ++ pim_keep_alive_cmd, ++ "keep-alive-timer (1-65535)$kat", + "Keep alive Timer\n" + "Seconds\n") + { + return pim_process_keepalivetimer_cmd(vty, kat_str); + } +- +-DEFUN (no_ip_pim_keep_alive, +- no_ip_pim_keep_alive_cmd, +- "no ip pim keep-alive-timer [(1-65535)]", +- NO_STR +- IP_STR +- "pim multicast routing\n" +- "Keep alive Timer\n" +- IGNORED_IN_NO_STR) ++DEFPY_ATTR(ip_pim_keep_alive, ++ ip_pim_keep_alive_cmd, ++ "ip pim keep-alive-timer (1-65535)$kat", ++ IP_STR ++ PIM_STR ++ "Keep alive Timer\n" ++ "Seconds\n", ++ CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) + { +- return pim_process_no_keepalivetimer_cmd(vty); +-} ++ int ret; ++ const char *vrfname; ++ char xpath[XPATH_MAXLEN]; ++ int orig_node = -1; + +-DEFPY (ip_pim_packets, +- ip_pim_packets_cmd, +- "ip pim packets (1-255)", +- IP_STR +- "pim multicast routing\n" +- "packets to process at one time per fd\n" +- "Number of packets\n") ++ vrfname = pim_cli_get_vrf_name(vty); ++ if (vrfname) { ++ snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, ++ "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); ++ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); ++ if (nb_cli_apply_changes_clear_pending(vty, NULL) == ++ CMD_SUCCESS) { ++ orig_node = vty->node; ++ VTY_PUSH_XPATH(PIM_NODE, xpath); ++ } else { ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ } else { ++ vty_out(vty, "%% Failed to determine vrf name\n"); ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ ++ ret = pim_process_keepalivetimer_cmd(vty, kat_str); ++ ++ if (orig_node != -1) { ++ vty->node = orig_node; ++ vty->xpath_index--; ++ } ++ ++ return ret; ++} ++ ++DEFPY (no_pim_keep_alive, ++ no_pim_keep_alive_cmd, ++ "no keep-alive-timer [(1-65535)]", ++ NO_STR ++ "Keep alive Timer\n" ++ IGNORED_IN_NO_STR) ++{ ++ return pim_process_no_keepalivetimer_cmd(vty); ++} ++DEFPY_ATTR(no_ip_pim_keep_alive, ++ no_ip_pim_keep_alive_cmd, ++ "no ip pim keep-alive-timer [(1-65535)]", ++ NO_STR ++ IP_STR ++ PIM_STR ++ "Keep alive Timer\n" ++ IGNORED_IN_NO_STR, ++ CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) ++{ ++ int ret; ++ const char *vrfname; ++ char xpath[XPATH_MAXLEN]; ++ int orig_node = -1; ++ ++ vrfname = pim_cli_get_vrf_name(vty); ++ if (vrfname) { ++ snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, ++ "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); ++ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); ++ if (nb_cli_apply_changes_clear_pending(vty, NULL) == ++ CMD_SUCCESS) { ++ orig_node = vty->node; ++ VTY_PUSH_XPATH(PIM_NODE, xpath); ++ } else { ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ } else { ++ vty_out(vty, "%% Failed to determine vrf name\n"); ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ ++ ret = pim_process_no_keepalivetimer_cmd(vty); ++ ++ if (orig_node != -1) { ++ vty->node = orig_node; ++ vty->xpath_index--; ++ } ++ ++ return ret; ++} ++ ++DEFPY (pim_packets, ++ pim_packets_cmd, ++ "packets (1-255)", ++ "packets to process at one time per fd\n" ++ "Number of packets\n") + { + return pim_process_pim_packet_cmd(vty, packets_str); + } ++DEFPY_ATTR(ip_pim_packets, ++ ip_pim_packets_cmd, ++ "ip pim packets (1-255)", ++ IP_STR ++ PIM_STR ++ "packets to process at one time per fd\n" ++ "Number of packets\n", ++ CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) ++{ ++ int ret; ++ const char *vrfname; ++ char xpath[XPATH_MAXLEN]; ++ int orig_node = -1; ++ ++ vrfname = pim_cli_get_vrf_name(vty); ++ if (vrfname) { ++ snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, ++ "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); ++ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); ++ if (nb_cli_apply_changes_clear_pending(vty, NULL) == ++ CMD_SUCCESS) { ++ orig_node = vty->node; ++ VTY_PUSH_XPATH(PIM_NODE, xpath); ++ } else { ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ } else { ++ vty_out(vty, "%% Failed to determine vrf name\n"); ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ ++ ret = pim_process_pim_packet_cmd(vty, packets_str); ++ ++ if (orig_node != -1) { ++ vty->node = orig_node; ++ vty->xpath_index--; ++ } + +-DEFUN (no_ip_pim_packets, +- no_ip_pim_packets_cmd, +- "no ip pim packets [(1-255)]", ++ return ret; ++} ++ ++DEFPY (no_pim_packets, ++ no_pim_packets_cmd, ++ "no packets [(1-255)]", + NO_STR +- IP_STR +- "pim multicast routing\n" + "packets to process at one time per fd\n" + IGNORED_IN_NO_STR) + { + return pim_process_no_pim_packet_cmd(vty); + } ++DEFPY_ATTR(no_ip_pim_packets, ++ no_ip_pim_packets_cmd, ++ "no ip pim packets [(1-255)]", ++ NO_STR ++ IP_STR ++ PIM_STR ++ "packets to process at one time per fd\n" ++ IGNORED_IN_NO_STR, ++ CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) ++{ ++ int ret; ++ const char *vrfname; ++ char xpath[XPATH_MAXLEN]; ++ int orig_node = -1; ++ ++ vrfname = pim_cli_get_vrf_name(vty); ++ if (vrfname) { ++ snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, ++ "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); ++ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); ++ if (nb_cli_apply_changes_clear_pending(vty, NULL) == ++ CMD_SUCCESS) { ++ orig_node = vty->node; ++ VTY_PUSH_XPATH(PIM_NODE, xpath); ++ } else { ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ } else { ++ vty_out(vty, "%% Failed to determine vrf name\n"); ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ ++ ret = pim_process_no_pim_packet_cmd(vty); ++ ++ if (orig_node != -1) { ++ vty->node = orig_node; ++ vty->xpath_index--; ++ } ++ ++ return ret; ++} + + DEFPY (ip_igmp_group_watermark, + ip_igmp_group_watermark_cmd, +@@ -3217,64 +3845,131 @@ DEFPY (no_ip_igmp_group_watermark, + return CMD_SUCCESS; + } + +-DEFUN (ip_pim_v6_secondary, +- ip_pim_v6_secondary_cmd, +- "ip pim send-v6-secondary", +- IP_STR +- "pim multicast routing\n" ++DEFPY (pim_v6_secondary, ++ pim_v6_secondary_cmd, ++ "send-v6-secondary", + "Send v6 secondary addresses\n") + { +- const char *vrfname; + char send_v6_secondary_xpath[XPATH_MAXLEN]; + ++ snprintf(send_v6_secondary_xpath, sizeof(send_v6_secondary_xpath), ++ "./send-v6-secondary"); ++ ++ nb_cli_enqueue_change(vty, send_v6_secondary_xpath, NB_OP_MODIFY, ++ "true"); ++ ++ return nb_cli_apply_changes(vty, NULL); ++} ++DEFPY_ATTR(ip_pim_v6_secondary, ++ ip_pim_v6_secondary_cmd, ++ "ip pim send-v6-secondary", ++ IP_STR ++ PIM_STR ++ "Send v6 secondary addresses\n", ++ CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) ++{ ++ char send_v6_secondary_xpath[XPATH_MAXLEN]; ++ int ret; ++ const char *vrfname; ++ char xpath[XPATH_MAXLEN]; ++ int orig_node = -1; ++ + vrfname = pim_cli_get_vrf_name(vty); +- if (vrfname == NULL) ++ if (vrfname) { ++ snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, ++ "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); ++ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); ++ if (nb_cli_apply_changes_clear_pending(vty, NULL) == ++ CMD_SUCCESS) { ++ orig_node = vty->node; ++ VTY_PUSH_XPATH(PIM_NODE, xpath); ++ } else { ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ } else { ++ vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; ++ } + + snprintf(send_v6_secondary_xpath, sizeof(send_v6_secondary_xpath), +- FRR_PIM_VRF_XPATH, +- "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); +- strlcat(send_v6_secondary_xpath, "/send-v6-secondary", +- sizeof(send_v6_secondary_xpath)); +- ++ "./send-v6-secondary"); + nb_cli_enqueue_change(vty, send_v6_secondary_xpath, NB_OP_MODIFY, + "true"); ++ ret = nb_cli_apply_changes(vty, NULL); + +- return nb_cli_apply_changes(vty, NULL); ++ if (orig_node != -1) { ++ vty->node = orig_node; ++ vty->xpath_index--; ++ } ++ ++ return ret; + } + +-DEFUN (no_ip_pim_v6_secondary, +- no_ip_pim_v6_secondary_cmd, +- "no ip pim send-v6-secondary", ++DEFPY (no_pim_v6_secondary, ++ no_pim_v6_secondary_cmd, ++ "no send-v6-secondary", + NO_STR +- IP_STR +- "pim multicast routing\n" + "Send v6 secondary addresses\n") + { +- const char *vrfname; + char send_v6_secondary_xpath[XPATH_MAXLEN]; + ++ snprintf(send_v6_secondary_xpath, sizeof(send_v6_secondary_xpath), ++ "./send-v6-secondary"); ++ ++ nb_cli_enqueue_change(vty, send_v6_secondary_xpath, NB_OP_MODIFY, ++ "false"); ++ ++ return nb_cli_apply_changes(vty, NULL); ++} ++DEFPY_ATTR(no_ip_pim_v6_secondary, ++ no_ip_pim_v6_secondary_cmd, ++ "no ip pim send-v6-secondary", ++ NO_STR ++ IP_STR ++ PIM_STR ++ "Send v6 secondary addresses\n", ++ CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) ++{ ++ char send_v6_secondary_xpath[XPATH_MAXLEN]; ++ int ret; ++ const char *vrfname; ++ char xpath[XPATH_MAXLEN]; ++ int orig_node = -1; ++ + vrfname = pim_cli_get_vrf_name(vty); +- if (vrfname == NULL) ++ if (vrfname) { ++ snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, ++ "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); ++ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); ++ if (nb_cli_apply_changes_clear_pending(vty, NULL) == ++ CMD_SUCCESS) { ++ orig_node = vty->node; ++ VTY_PUSH_XPATH(PIM_NODE, xpath); ++ } else { ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ } else { ++ vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; ++ } + + snprintf(send_v6_secondary_xpath, sizeof(send_v6_secondary_xpath), +- FRR_PIM_VRF_XPATH, +- "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); +- strlcat(send_v6_secondary_xpath, "/send-v6-secondary", +- sizeof(send_v6_secondary_xpath)); +- ++ "./send-v6-secondary"); + nb_cli_enqueue_change(vty, send_v6_secondary_xpath, NB_OP_MODIFY, + "false"); ++ ret = nb_cli_apply_changes(vty, NULL); + +- return nb_cli_apply_changes(vty, NULL); ++ if (orig_node != -1) { ++ vty->node = orig_node; ++ vty->xpath_index--; ++ } ++ ++ return ret; + } + +-DEFPY (ip_pim_rp, +- ip_pim_rp_cmd, +- "ip pim rp A.B.C.D$rp [A.B.C.D/M]$gp", +- IP_STR +- "pim multicast routing\n" ++DEFPY (pim_rp, ++ pim_rp_cmd, ++ "rp A.B.C.D$rp [A.B.C.D/M]$gp", + "Rendezvous Point\n" + "ip address of RP\n" + "Group Address range to cover\n") +@@ -3283,12 +3978,52 @@ DEFPY (ip_pim_rp, + + return pim_process_rp_cmd(vty, rp_str, group_str); + } ++DEFPY_ATTR(ip_pim_rp, ++ ip_pim_rp_cmd, ++ "ip pim rp A.B.C.D$rp [A.B.C.D/M]$gp", ++ IP_STR ++ PIM_STR ++ "Rendezvous Point\n" ++ "ip address of RP\n" ++ "Group Address range to cover\n", ++ CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) ++{ ++ const char *group_str = (gp_str) ? gp_str : "224.0.0.0/4"; ++ int ret; ++ const char *vrfname; ++ char xpath[XPATH_MAXLEN]; ++ int orig_node = -1; + +-DEFPY (ip_pim_rp_prefix_list, +- ip_pim_rp_prefix_list_cmd, +- "ip pim rp A.B.C.D$rp prefix-list PREFIXLIST4_NAME$plist", +- IP_STR +- "pim multicast routing\n" ++ vrfname = pim_cli_get_vrf_name(vty); ++ if (vrfname) { ++ snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, ++ "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); ++ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); ++ if (nb_cli_apply_changes_clear_pending(vty, NULL) == ++ CMD_SUCCESS) { ++ orig_node = vty->node; ++ VTY_PUSH_XPATH(PIM_NODE, xpath); ++ } else { ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ } else { ++ vty_out(vty, "%% Failed to determine vrf name\n"); ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ ++ ret = pim_process_rp_cmd(vty, rp_str, group_str); ++ ++ if (orig_node != -1) { ++ vty->node = orig_node; ++ vty->xpath_index--; ++ } ++ ++ return ret; ++} ++ ++DEFPY (pim_rp_prefix_list, ++ pim_rp_prefix_list_cmd, ++ "rp A.B.C.D$rp prefix-list PREFIXLIST4_NAME$plist", + "Rendezvous Point\n" + "ip address of RP\n" + "group prefix-list filter\n" +@@ -3296,13 +4031,53 @@ DEFPY (ip_pim_rp_prefix_list, + { + return pim_process_rp_plist_cmd(vty, rp_str, plist); + } ++DEFPY_ATTR(ip_pim_rp_prefix_list, ++ ip_pim_rp_prefix_list_cmd, ++ "ip pim rp A.B.C.D$rp prefix-list PREFIXLIST4_NAME$plist", ++ IP_STR ++ PIM_STR ++ "Rendezvous Point\n" ++ "ip address of RP\n" ++ "group prefix-list filter\n" ++ "Name of a prefix-list\n", ++ CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) ++{ ++ int ret; ++ const char *vrfname; ++ char xpath[XPATH_MAXLEN]; ++ int orig_node = -1; ++ ++ vrfname = pim_cli_get_vrf_name(vty); ++ if (vrfname) { ++ snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, ++ "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); ++ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); ++ if (nb_cli_apply_changes_clear_pending(vty, NULL) == ++ CMD_SUCCESS) { ++ orig_node = vty->node; ++ VTY_PUSH_XPATH(PIM_NODE, xpath); ++ } else { ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ } else { ++ vty_out(vty, "%% Failed to determine vrf name\n"); ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ ++ ret = pim_process_rp_plist_cmd(vty, rp_str, plist); ++ ++ if (orig_node != -1) { ++ vty->node = orig_node; ++ vty->xpath_index--; ++ } ++ ++ return ret; ++} + +-DEFPY (no_ip_pim_rp, +- no_ip_pim_rp_cmd, +- "no ip pim rp A.B.C.D$rp [A.B.C.D/M]$gp", ++DEFPY (no_pim_rp, ++ no_pim_rp_cmd, ++ "no rp A.B.C.D$rp [A.B.C.D/M]$gp", + NO_STR +- IP_STR +- "pim multicast routing\n" + "Rendezvous Point\n" + "ip address of RP\n" + "Group Address range to cover\n") +@@ -3311,13 +4086,54 @@ DEFPY (no_ip_pim_rp, + + return pim_process_no_rp_cmd(vty, rp_str, group_str); + } ++DEFPY_ATTR(no_ip_pim_rp, ++ no_ip_pim_rp_cmd, ++ "no ip pim rp A.B.C.D$rp [A.B.C.D/M]$gp", ++ NO_STR ++ IP_STR ++ PIM_STR ++ "Rendezvous Point\n" ++ "ip address of RP\n" ++ "Group Address range to cover\n", ++ CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) ++{ ++ const char *group_str = (gp_str) ? gp_str : "224.0.0.0/4"; ++ int ret; ++ const char *vrfname; ++ char xpath[XPATH_MAXLEN]; ++ int orig_node = -1; ++ ++ vrfname = pim_cli_get_vrf_name(vty); ++ if (vrfname) { ++ snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, ++ "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); ++ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); ++ if (nb_cli_apply_changes_clear_pending(vty, NULL) == ++ CMD_SUCCESS) { ++ orig_node = vty->node; ++ VTY_PUSH_XPATH(PIM_NODE, xpath); ++ } else { ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ } else { ++ vty_out(vty, "%% Failed to determine vrf name\n"); ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ ++ ret = pim_process_no_rp_cmd(vty, rp_str, group_str); + +-DEFPY (no_ip_pim_rp_prefix_list, +- no_ip_pim_rp_prefix_list_cmd, +- "no ip pim rp A.B.C.D$rp prefix-list PREFIXLIST4_NAME$plist", ++ if (orig_node != -1) { ++ vty->node = orig_node; ++ vty->xpath_index--; ++ } ++ ++ return ret; ++} ++ ++DEFPY (no_pim_rp_prefix_list, ++ no_pim_rp_prefix_list_cmd, ++ "no rp A.B.C.D$rp prefix-list PREFIXLIST4_NAME$plist", + NO_STR +- IP_STR +- "pim multicast routing\n" + "Rendezvous Point\n" + "ip address of RP\n" + "group prefix-list filter\n" +@@ -3325,104 +4141,264 @@ DEFPY (no_ip_pim_rp_prefix_list, + { + return pim_process_no_rp_plist_cmd(vty, rp_str, plist); + } ++DEFPY_ATTR(no_ip_pim_rp_prefix_list, ++ no_ip_pim_rp_prefix_list_cmd, ++ "no ip pim rp A.B.C.D$rp prefix-list PREFIXLIST4_NAME$plist", ++ NO_STR ++ IP_STR ++ PIM_STR ++ "Rendezvous Point\n" ++ "ip address of RP\n" ++ "group prefix-list filter\n" ++ "Name of a prefix-list\n", ++ CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) ++{ ++ int ret; ++ const char *vrfname; ++ char xpath[XPATH_MAXLEN]; ++ int orig_node = -1; + +-DEFUN (ip_pim_ssm_prefix_list, +- ip_pim_ssm_prefix_list_cmd, +- "ip pim ssm prefix-list PREFIXLIST4_NAME", +- IP_STR +- "pim multicast routing\n" ++ vrfname = pim_cli_get_vrf_name(vty); ++ if (vrfname) { ++ snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, ++ "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); ++ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); ++ if (nb_cli_apply_changes_clear_pending(vty, NULL) == ++ CMD_SUCCESS) { ++ orig_node = vty->node; ++ VTY_PUSH_XPATH(PIM_NODE, xpath); ++ } else { ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ } else { ++ vty_out(vty, "%% Failed to determine vrf name\n"); ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ ++ ret = pim_process_no_rp_plist_cmd(vty, rp_str, plist); ++ ++ if (orig_node != -1) { ++ vty->node = orig_node; ++ vty->xpath_index--; ++ } ++ ++ return ret; ++} ++ ++DEFPY (pim_ssm_prefix_list, ++ pim_ssm_prefix_list_cmd, ++ "ssm prefix-list PREFIXLIST4_NAME$plist", + "Source Specific Multicast\n" + "group range prefix-list filter\n" + "Name of a prefix-list\n") + { +- const char *vrfname; + char ssm_plist_xpath[XPATH_MAXLEN]; + ++ snprintf(ssm_plist_xpath, sizeof(ssm_plist_xpath), "./ssm-prefix-list"); ++ ++ nb_cli_enqueue_change(vty, ssm_plist_xpath, NB_OP_MODIFY, plist); ++ ++ return nb_cli_apply_changes(vty, NULL); ++} ++DEFPY_ATTR(ip_pim_ssm_prefix_list, ++ ip_pim_ssm_prefix_list_cmd, ++ "ip pim ssm prefix-list PREFIXLIST4_NAME$plist", ++ IP_STR ++ PIM_STR ++ "Source Specific Multicast\n" ++ "group range prefix-list filter\n" ++ "Name of a prefix-list\n", ++ CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) ++{ ++ char ssm_plist_xpath[XPATH_MAXLEN]; ++ int ret; ++ const char *vrfname; ++ char xpath[XPATH_MAXLEN]; ++ int orig_node = -1; ++ + vrfname = pim_cli_get_vrf_name(vty); +- if (vrfname == NULL) ++ if (vrfname) { ++ snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, ++ "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); ++ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); ++ if (nb_cli_apply_changes_clear_pending(vty, NULL) == ++ CMD_SUCCESS) { ++ orig_node = vty->node; ++ VTY_PUSH_XPATH(PIM_NODE, xpath); ++ } else { ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ } else { ++ vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; ++ } + +- snprintf(ssm_plist_xpath, sizeof(ssm_plist_xpath), FRR_PIM_VRF_XPATH, +- "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); +- strlcat(ssm_plist_xpath, "/ssm-prefix-list", sizeof(ssm_plist_xpath)); ++ snprintf(ssm_plist_xpath, sizeof(ssm_plist_xpath), "./ssm-prefix-list"); ++ nb_cli_enqueue_change(vty, ssm_plist_xpath, NB_OP_MODIFY, plist); ++ ret = nb_cli_apply_changes(vty, NULL); + +- nb_cli_enqueue_change(vty, ssm_plist_xpath, NB_OP_MODIFY, argv[4]->arg); ++ if (orig_node != -1) { ++ vty->node = orig_node; ++ vty->xpath_index--; ++ } + +- return nb_cli_apply_changes(vty, NULL); ++ return ret; + } + +-DEFUN (no_ip_pim_ssm_prefix_list, +- no_ip_pim_ssm_prefix_list_cmd, +- "no ip pim ssm prefix-list", ++DEFPY (no_pim_ssm_prefix_list, ++ no_pim_ssm_prefix_list_cmd, ++ "no ssm prefix-list", + NO_STR +- IP_STR +- "pim multicast routing\n" + "Source Specific Multicast\n" + "group range prefix-list filter\n") + { +- const char *vrfname; + char ssm_plist_xpath[XPATH_MAXLEN]; + ++ snprintf(ssm_plist_xpath, sizeof(ssm_plist_xpath), "./ssm-prefix-list"); ++ ++ nb_cli_enqueue_change(vty, ssm_plist_xpath, NB_OP_DESTROY, NULL); ++ ++ return nb_cli_apply_changes(vty, NULL); ++} ++DEFPY_ATTR(no_ip_pim_ssm_prefix_list, ++ no_ip_pim_ssm_prefix_list_cmd, ++ "no ip pim ssm prefix-list", ++ NO_STR ++ IP_STR ++ PIM_STR ++ "Source Specific Multicast\n" ++ "group range prefix-list filter\n", ++ CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) ++{ ++ char ssm_plist_xpath[XPATH_MAXLEN]; ++ int ret; ++ const char *vrfname; ++ char xpath[XPATH_MAXLEN]; ++ int orig_node = -1; ++ + vrfname = pim_cli_get_vrf_name(vty); +- if (vrfname == NULL) ++ if (vrfname) { ++ snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, ++ "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); ++ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); ++ if (nb_cli_apply_changes_clear_pending(vty, NULL) == ++ CMD_SUCCESS) { ++ orig_node = vty->node; ++ VTY_PUSH_XPATH(PIM_NODE, xpath); ++ } else { ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ } else { ++ vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; ++ } + +- snprintf(ssm_plist_xpath, sizeof(ssm_plist_xpath), +- FRR_PIM_VRF_XPATH, +- "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); +- strlcat(ssm_plist_xpath, "/ssm-prefix-list", sizeof(ssm_plist_xpath)); +- ++ snprintf(ssm_plist_xpath, sizeof(ssm_plist_xpath), "./ssm-prefix-list"); + nb_cli_enqueue_change(vty, ssm_plist_xpath, NB_OP_DESTROY, NULL); ++ ret = nb_cli_apply_changes(vty, NULL); + +- return nb_cli_apply_changes(vty, NULL); ++ if (orig_node != -1) { ++ vty->node = orig_node; ++ vty->xpath_index--; ++ } ++ ++ return ret; + } + +-DEFUN (no_ip_pim_ssm_prefix_list_name, +- no_ip_pim_ssm_prefix_list_name_cmd, +- "no ip pim ssm prefix-list PREFIXLIST4_NAME", ++DEFPY (no_pim_ssm_prefix_list_name, ++ no_pim_ssm_prefix_list_name_cmd, ++ "no ssm prefix-list PREFIXLIST4_NAME$plist", + NO_STR +- IP_STR +- "pim multicast routing\n" + "Source Specific Multicast\n" + "group range prefix-list filter\n" + "Name of a prefix-list\n") + { +- const char *vrfname; + const struct lyd_node *ssm_plist_dnode; + char ssm_plist_xpath[XPATH_MAXLEN]; + const char *ssm_plist_name; + +- vrfname = pim_cli_get_vrf_name(vty); +- if (vrfname == NULL) +- return CMD_WARNING_CONFIG_FAILED; +- +- snprintf(ssm_plist_xpath, sizeof(ssm_plist_xpath), +- FRR_PIM_VRF_XPATH, +- "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); +- strlcat(ssm_plist_xpath, "/ssm-prefix-list", sizeof(ssm_plist_xpath)); ++ snprintf(ssm_plist_xpath, sizeof(ssm_plist_xpath), "%s/ssm-prefix-list", ++ VTY_CURR_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); ++ vty_out(vty, "%% pim ssm prefix-list %s doesn't exist\n", plist); + 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); +- ++ if (ssm_plist_name && !strcmp(ssm_plist_name, plist)) { ++ 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); ++ vty_out(vty, "%% pim ssm prefix-list %s doesn't exist\n", plist); + + return CMD_WARNING_CONFIG_FAILED; + } ++DEFPY_ATTR(no_ip_pim_ssm_prefix_list_name, ++ no_ip_pim_ssm_prefix_list_name_cmd, ++ "no ip pim ssm prefix-list PREFIXLIST4_NAME$plist", ++ NO_STR ++ IP_STR ++ PIM_STR ++ "Source Specific Multicast\n" ++ "group range prefix-list filter\n" ++ "Name of a prefix-list\n", ++ CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) ++{ ++ const struct lyd_node *ssm_plist_dnode; ++ char ssm_plist_xpath[XPATH_MAXLEN]; ++ const char *ssm_plist_name; ++ int ret = CMD_WARNING_CONFIG_FAILED; ++ const char *vrfname; ++ char xpath[XPATH_MAXLEN]; ++ int orig_node = -1; ++ ++ vrfname = pim_cli_get_vrf_name(vty); ++ if (vrfname) { ++ snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, ++ "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); ++ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); ++ if (nb_cli_apply_changes_clear_pending(vty, NULL) == ++ CMD_SUCCESS) { ++ orig_node = vty->node; ++ VTY_PUSH_XPATH(PIM_NODE, xpath); ++ } else { ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ } else { ++ vty_out(vty, "%% Failed to determine vrf name\n"); ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ ++ snprintf(ssm_plist_xpath, sizeof(ssm_plist_xpath), "%s/ssm-prefix-list", ++ VTY_CURR_XPATH); ++ ssm_plist_dnode = yang_dnode_get(vty->candidate_config->dnode, ++ ssm_plist_xpath); ++ if (ssm_plist_dnode) { ++ ssm_plist_name = yang_dnode_get_string(ssm_plist_dnode, "."); ++ if (ssm_plist_name && !strcmp(ssm_plist_name, plist)) { ++ nb_cli_enqueue_change(vty, ssm_plist_xpath, ++ NB_OP_DESTROY, NULL); ++ ret = nb_cli_apply_changes(vty, NULL); ++ } else { ++ vty_out(vty, "%% pim ssm prefix-list %s doesn't exist\n", ++ plist); ++ } ++ } else { ++ vty_out(vty, "%% pim ssm prefix-list %s doesn't exist\n", plist); ++ } ++ ++ if (orig_node != -1) { ++ vty->node = orig_node; ++ vty->xpath_index--; ++ } ++ ++ return ret; ++} + + DEFUN (show_ip_pim_ssm_range, + show_ip_pim_ssm_range_cmd, +@@ -3511,135 +4487,354 @@ DEFPY (show_ip_pim_bsr, + return pim_show_bsr_helper(vrf, vty, !!json); + } + +-DEFUN (ip_ssmpingd, +- ip_ssmpingd_cmd, +- "ip ssmpingd [A.B.C.D]", +- IP_STR ++DEFPY (pim_ssmpingd, ++ pim_ssmpingd_cmd, ++ "ssmpingd [A.B.C.D]$src", + CONF_SSMPINGD_STR + "Source address\n") + { +- int idx_ipv4 = 2; +- const char *src_str = (argc == 3) ? argv[idx_ipv4]->arg : "0.0.0.0"; ++ if (src_str) ++ return pim_process_ssmpingd_cmd(vty, NB_OP_CREATE, src_str); ++ else ++ return pim_process_ssmpingd_cmd(vty, NB_OP_CREATE, "0.0.0.0"); ++} ++DEFPY_ATTR(ip_pim_ssmpingd, ++ ip_ssmpingd_cmd, ++ "ip ssmpingd [A.B.C.D]$src", ++ IP_STR ++ CONF_SSMPINGD_STR ++ "Source address\n", ++ CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) ++{ ++ int ret; ++ const char *vrfname; ++ char xpath[XPATH_MAXLEN]; ++ int orig_node = -1; + +- return pim_process_ssmpingd_cmd(vty, NB_OP_CREATE, src_str); ++ vrfname = pim_cli_get_vrf_name(vty); ++ if (vrfname) { ++ snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, ++ "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); ++ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); ++ if (nb_cli_apply_changes_clear_pending(vty, NULL) == ++ CMD_SUCCESS) { ++ orig_node = vty->node; ++ VTY_PUSH_XPATH(PIM_NODE, xpath); ++ } else { ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ } else { ++ vty_out(vty, "%% Failed to determine vrf name\n"); ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ ++ if (src_str) ++ ret = pim_process_ssmpingd_cmd(vty, NB_OP_CREATE, src_str); ++ else ++ ret = pim_process_ssmpingd_cmd(vty, NB_OP_CREATE, "0.0.0.0"); ++ ++ if (orig_node != -1) { ++ vty->node = orig_node; ++ vty->xpath_index--; ++ } ++ ++ return ret; + } + +-DEFUN (no_ip_ssmpingd, +- no_ip_ssmpingd_cmd, +- "no ip ssmpingd [A.B.C.D]", ++DEFPY (no_pim_ssmpingd, ++ no_pim_ssmpingd_cmd, ++ "no ssmpingd [A.B.C.D]$src", + NO_STR +- IP_STR + CONF_SSMPINGD_STR + "Source address\n") + { +- int idx_ipv4 = 3; +- const char *src_str = (argc == 4) ? argv[idx_ipv4]->arg : "0.0.0.0"; ++ if (src_str) ++ return pim_process_ssmpingd_cmd(vty, NB_OP_DESTROY, src_str); ++ else ++ return pim_process_ssmpingd_cmd(vty, NB_OP_DESTROY, "0.0.0.0"); ++} ++DEFPY_ATTR(no_ip_pim_ssmpingd, ++ no_ip_ssmpingd_cmd, ++ "no ip ssmpingd [A.B.C.D]$src", ++ NO_STR ++ IP_STR ++ CONF_SSMPINGD_STR ++ "Source address\n", ++ CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) ++{ ++ int ret; ++ const char *vrfname; ++ char xpath[XPATH_MAXLEN]; ++ int orig_node = -1; ++ ++ vrfname = pim_cli_get_vrf_name(vty); ++ if (vrfname) { ++ snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, ++ "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); ++ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); ++ if (nb_cli_apply_changes_clear_pending(vty, NULL) == ++ CMD_SUCCESS) { ++ orig_node = vty->node; ++ VTY_PUSH_XPATH(PIM_NODE, xpath); ++ } else { ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ } else { ++ vty_out(vty, "%% Failed to determine vrf name\n"); ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ ++ if (src_str) ++ ret = pim_process_ssmpingd_cmd(vty, NB_OP_DESTROY, src_str); ++ else ++ ret = pim_process_ssmpingd_cmd(vty, NB_OP_DESTROY, "0.0.0.0"); ++ ++ if (orig_node != -1) { ++ vty->node = orig_node; ++ vty->xpath_index--; ++ } + +- return pim_process_ssmpingd_cmd(vty, NB_OP_DESTROY, src_str); ++ return ret; + } + +-DEFUN (ip_pim_ecmp, +- ip_pim_ecmp_cmd, +- "ip pim ecmp", +- IP_STR +- "pim multicast routing\n" ++DEFPY (pim_ecmp, ++ pim_ecmp_cmd, ++ "ecmp", + "Enable PIM ECMP \n") + { +- const char *vrfname; + char ecmp_xpath[XPATH_MAXLEN]; + ++ snprintf(ecmp_xpath, sizeof(ecmp_xpath), "./ecmp"); ++ nb_cli_enqueue_change(vty, ecmp_xpath, NB_OP_MODIFY, "true"); ++ ++ return nb_cli_apply_changes(vty, NULL); ++} ++DEFPY_ATTR(ip_pim_ecmp, ++ ip_pim_ecmp_cmd, ++ "ip pim ecmp", ++ IP_STR ++ PIM_STR ++ "Enable PIM ECMP \n", ++ CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) ++{ ++ char ecmp_xpath[XPATH_MAXLEN]; ++ int ret; ++ const char *vrfname; ++ char xpath[XPATH_MAXLEN]; ++ int orig_node = -1; ++ + vrfname = pim_cli_get_vrf_name(vty); +- if (vrfname == NULL) ++ if (vrfname) { ++ snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, ++ "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); ++ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); ++ if (nb_cli_apply_changes_clear_pending(vty, NULL) == ++ CMD_SUCCESS) { ++ orig_node = vty->node; ++ VTY_PUSH_XPATH(PIM_NODE, xpath); ++ } else { ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ } else { ++ vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; ++ } + +- snprintf(ecmp_xpath, sizeof(ecmp_xpath), FRR_PIM_VRF_XPATH, +- "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); +- strlcat(ecmp_xpath, "/ecmp", sizeof(ecmp_xpath)); +- ++ snprintf(ecmp_xpath, sizeof(ecmp_xpath), "./ecmp"); + nb_cli_enqueue_change(vty, ecmp_xpath, NB_OP_MODIFY, "true"); +- return nb_cli_apply_changes(vty, NULL); ++ ret = nb_cli_apply_changes(vty, NULL); ++ ++ if (orig_node != -1) { ++ vty->node = orig_node; ++ vty->xpath_index--; ++ } ++ ++ return ret; + } + +-DEFUN (no_ip_pim_ecmp, +- no_ip_pim_ecmp_cmd, +- "no ip pim ecmp", ++DEFPY (no_pim_ecmp, ++ no_pim_ecmp_cmd, ++ "no ecmp", + NO_STR +- IP_STR +- "pim multicast routing\n" + "Disable PIM ECMP \n") + { +- const char *vrfname; + char ecmp_xpath[XPATH_MAXLEN]; + ++ snprintf(ecmp_xpath, sizeof(ecmp_xpath), "./ecmp"); ++ nb_cli_enqueue_change(vty, ecmp_xpath, NB_OP_MODIFY, "false"); ++ ++ return nb_cli_apply_changes(vty, NULL); ++} ++DEFPY_ATTR(no_ip_pim_ecmp, ++ no_ip_pim_ecmp_cmd, ++ "no ip pim ecmp", ++ NO_STR ++ IP_STR ++ PIM_STR ++ "Disable PIM ECMP \n", ++ CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) ++{ ++ char ecmp_xpath[XPATH_MAXLEN]; ++ int ret; ++ const char *vrfname; ++ char xpath[XPATH_MAXLEN]; ++ int orig_node = -1; ++ + vrfname = pim_cli_get_vrf_name(vty); +- if (vrfname == NULL) ++ if (vrfname) { ++ snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, ++ "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); ++ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); ++ if (nb_cli_apply_changes_clear_pending(vty, NULL) == ++ CMD_SUCCESS) { ++ orig_node = vty->node; ++ VTY_PUSH_XPATH(PIM_NODE, xpath); ++ } else { ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ } else { ++ vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; ++ } + +- snprintf(ecmp_xpath, sizeof(ecmp_xpath), FRR_PIM_VRF_XPATH, +- "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); +- strlcat(ecmp_xpath, "/ecmp", sizeof(ecmp_xpath)); +- ++ snprintf(ecmp_xpath, sizeof(ecmp_xpath), "./ecmp"); + nb_cli_enqueue_change(vty, ecmp_xpath, NB_OP_MODIFY, "false"); ++ ret = nb_cli_apply_changes(vty, NULL); + +- return nb_cli_apply_changes(vty, NULL); ++ if (orig_node != -1) { ++ vty->node = orig_node; ++ vty->xpath_index--; ++ } ++ ++ return ret; + } + +-DEFUN (ip_pim_ecmp_rebalance, +- ip_pim_ecmp_rebalance_cmd, +- "ip pim ecmp rebalance", +- IP_STR +- "pim multicast routing\n" ++DEFPY (pim_ecmp_rebalance, ++ pim_ecmp_rebalance_cmd, ++ "ecmp rebalance", + "Enable PIM ECMP \n" + "Enable PIM ECMP Rebalance\n") + { +- const char *vrfname; + char ecmp_xpath[XPATH_MAXLEN]; + char ecmp_rebalance_xpath[XPATH_MAXLEN]; + ++ snprintf(ecmp_xpath, sizeof(ecmp_xpath), "./ecmp"); ++ snprintf(ecmp_rebalance_xpath, sizeof(ecmp_rebalance_xpath), ++ "./ecmp-rebalance"); ++ ++ 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); ++} ++DEFPY_ATTR(ip_pim_ecmp_rebalance, ++ ip_pim_ecmp_rebalance_cmd, ++ "ip pim ecmp rebalance", ++ IP_STR ++ PIM_STR ++ "Enable PIM ECMP \n" ++ "Enable PIM ECMP Rebalance\n", ++ CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) ++{ ++ char ecmp_xpath[XPATH_MAXLEN]; ++ char ecmp_rebalance_xpath[XPATH_MAXLEN]; ++ int ret; ++ const char *vrfname; ++ char xpath[XPATH_MAXLEN]; ++ int orig_node = -1; ++ + vrfname = pim_cli_get_vrf_name(vty); +- if (vrfname == NULL) ++ if (vrfname) { ++ snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, ++ "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); ++ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); ++ if (nb_cli_apply_changes_clear_pending(vty, NULL) == ++ CMD_SUCCESS) { ++ orig_node = vty->node; ++ VTY_PUSH_XPATH(PIM_NODE, xpath); ++ } else { ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ } else { ++ vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; ++ } + +- snprintf(ecmp_xpath, sizeof(ecmp_xpath), FRR_PIM_VRF_XPATH, +- "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); +- strlcat(ecmp_xpath, "/ecmp", sizeof(ecmp_xpath)); ++ snprintf(ecmp_xpath, sizeof(ecmp_xpath), "./ecmp"); + snprintf(ecmp_rebalance_xpath, sizeof(ecmp_rebalance_xpath), +- FRR_PIM_VRF_XPATH, +- "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); +- strlcat(ecmp_rebalance_xpath, "/ecmp-rebalance", +- sizeof(ecmp_rebalance_xpath)); +- ++ "./ecmp-rebalance"); + nb_cli_enqueue_change(vty, ecmp_xpath, NB_OP_MODIFY, "true"); + nb_cli_enqueue_change(vty, ecmp_rebalance_xpath, NB_OP_MODIFY, "true"); ++ ret = nb_cli_apply_changes(vty, NULL); + +- return nb_cli_apply_changes(vty, NULL); ++ if (orig_node != -1) { ++ vty->node = orig_node; ++ vty->xpath_index--; ++ } ++ ++ return ret; + } + +-DEFUN (no_ip_pim_ecmp_rebalance, +- no_ip_pim_ecmp_rebalance_cmd, +- "no ip pim ecmp rebalance", ++DEFPY (no_pim_ecmp_rebalance, ++ no_pim_ecmp_rebalance_cmd, ++ "no ecmp rebalance", + NO_STR +- IP_STR +- "pim multicast routing\n" + "Disable PIM ECMP \n" + "Disable PIM ECMP Rebalance\n") + { +- const char *vrfname; + char ecmp_rebalance_xpath[XPATH_MAXLEN]; + ++ snprintf(ecmp_rebalance_xpath, sizeof(ecmp_rebalance_xpath), ++ "./ecmp-rebalance"); ++ ++ nb_cli_enqueue_change(vty, ecmp_rebalance_xpath, NB_OP_MODIFY, "false"); ++ ++ return nb_cli_apply_changes(vty, NULL); ++} ++DEFPY_ATTR(no_ip_pim_ecmp_rebalance, ++ no_ip_pim_ecmp_rebalance_cmd, ++ "no ip pim ecmp rebalance", ++ NO_STR ++ IP_STR ++ PIM_STR ++ "Disable PIM ECMP \n" ++ "Disable PIM ECMP Rebalance\n", ++ CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) ++{ ++ char ecmp_rebalance_xpath[XPATH_MAXLEN]; ++ int ret; ++ const char *vrfname; ++ char xpath[XPATH_MAXLEN]; ++ int orig_node = -1; ++ + vrfname = pim_cli_get_vrf_name(vty); +- if (vrfname == NULL) ++ if (vrfname) { ++ snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, ++ "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); ++ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); ++ if (nb_cli_apply_changes_clear_pending(vty, NULL) == ++ CMD_SUCCESS) { ++ orig_node = vty->node; ++ VTY_PUSH_XPATH(PIM_NODE, xpath); ++ } else { ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ } else { ++ vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; ++ } + + snprintf(ecmp_rebalance_xpath, sizeof(ecmp_rebalance_xpath), +- FRR_PIM_VRF_XPATH, +- "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); +- strlcat(ecmp_rebalance_xpath, "/ecmp-rebalance", +- sizeof(ecmp_rebalance_xpath)); +- ++ "./ecmp-rebalance"); + nb_cli_enqueue_change(vty, ecmp_rebalance_xpath, NB_OP_MODIFY, "false"); ++ ret = nb_cli_apply_changes(vty, NULL); + +- return nb_cli_apply_changes(vty, NULL); ++ if (orig_node != -1) { ++ vty->node = orig_node; ++ vty->xpath_index--; ++ } ++ ++ return ret; + } + + DEFUN (interface_ip_igmp, +@@ -4648,15 +5843,24 @@ DEFPY (debug_pim_zebra, + return CMD_SUCCESS; + } + +-DEFUN(debug_pim_mlag, debug_pim_mlag_cmd, "debug pim mlag", +- DEBUG_STR DEBUG_PIM_STR DEBUG_PIM_MLAG_STR) ++DEFUN(debug_pim_mlag, ++ debug_pim_mlag_cmd, ++ "debug pim mlag", ++ DEBUG_STR ++ DEBUG_PIM_STR ++ DEBUG_PIM_MLAG_STR) + { + PIM_DO_DEBUG_MLAG; + return CMD_SUCCESS; + } + +-DEFUN(no_debug_pim_mlag, no_debug_pim_mlag_cmd, "no debug pim mlag", +- NO_STR DEBUG_STR DEBUG_PIM_STR DEBUG_PIM_MLAG_STR) ++DEFUN(no_debug_pim_mlag, ++ no_debug_pim_mlag_cmd, ++ "no debug pim mlag", ++ NO_STR ++ DEBUG_STR ++ DEBUG_PIM_STR ++ DEBUG_PIM_MLAG_STR) + { + PIM_DONT_DEBUG_MLAG; + return CMD_SUCCESS; +@@ -5016,145 +6220,333 @@ ALIAS(no_ip_pim_bfd, no_ip_pim_bfd_param_cmd, + "Desired min transmit interval\n") + #endif /* !HAVE_BFDD */ + +-DEFPY(ip_msdp_peer, ip_msdp_peer_cmd, +- "ip msdp peer A.B.C.D$peer source A.B.C.D$source", +- IP_STR ++DEFPY(pim_msdp_peer, pim_msdp_peer_cmd, ++ "msdp peer A.B.C.D$peer source A.B.C.D$source", + CFG_MSDP_STR + "Configure MSDP peer\n" + "Peer IP address\n" + "Source address for TCP connection\n" + "Local IP address\n") + { +- const char *vrfname; +- char temp_xpath[XPATH_MAXLEN]; + char msdp_peer_source_xpath[XPATH_MAXLEN]; + ++ snprintf(msdp_peer_source_xpath, sizeof(msdp_peer_source_xpath), ++ "./msdp-peer[peer-ip='%s']/source-ip", peer_str); ++ nb_cli_enqueue_change(vty, msdp_peer_source_xpath, NB_OP_MODIFY, ++ source_str); ++ ++ return nb_cli_apply_changes(vty, NULL); ++} ++DEFPY_ATTR(ip_pim_msdp_peer, ++ ip_msdp_peer_cmd, ++ "ip msdp peer A.B.C.D$peer source A.B.C.D$source", ++ IP_STR ++ CFG_MSDP_STR ++ "Configure MSDP peer\n" ++ "Peer IP address\n" ++ "Source address for TCP connection\n" ++ "Local IP address\n", ++ CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) ++{ ++ char msdp_peer_source_xpath[XPATH_MAXLEN]; ++ int ret; ++ const char *vrfname; ++ char xpath[XPATH_MAXLEN]; ++ int orig_node = -1; ++ + vrfname = pim_cli_get_vrf_name(vty); +- if (vrfname == NULL) ++ if (vrfname) { ++ snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, ++ "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); ++ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); ++ if (nb_cli_apply_changes_clear_pending(vty, NULL) == ++ CMD_SUCCESS) { ++ orig_node = vty->node; ++ VTY_PUSH_XPATH(PIM_NODE, xpath); ++ } else { ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ } else { ++ vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; ++ } + + snprintf(msdp_peer_source_xpath, sizeof(msdp_peer_source_xpath), +- FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname, +- "frr-routing:ipv4"); +- snprintf(temp_xpath, sizeof(temp_xpath), +- "/msdp-peer[peer-ip='%s']/source-ip", peer_str); +- strlcat(msdp_peer_source_xpath, temp_xpath, +- sizeof(msdp_peer_source_xpath)); +- ++ "./msdp-peer[peer-ip='%s']/source-ip", peer_str); + nb_cli_enqueue_change(vty, msdp_peer_source_xpath, NB_OP_MODIFY, + source_str); ++ ret = nb_cli_apply_changes(vty, NULL); + +- return nb_cli_apply_changes(vty, +- FRR_PIM_INTERFACE_XPATH, "frr-routing:ipv4"); ++ if (orig_node != -1) { ++ vty->node = orig_node; ++ vty->xpath_index--; ++ } ++ ++ return ret; + } + +-DEFPY(ip_msdp_timers, ip_msdp_timers_cmd, +- "ip msdp timers (1-65535)$keepalive (1-65535)$holdtime [(1-65535)$connretry]", +- IP_STR ++DEFPY(pim_msdp_timers, pim_msdp_timers_cmd, ++ "msdp timers (1-65535)$keepalive (1-65535)$holdtime [(1-65535)$connretry]", + CFG_MSDP_STR + "MSDP timers configuration\n" + "Keep alive period (in seconds)\n" + "Hold time period (in seconds)\n" + "Connection retry period (in seconds)\n") + { ++ nb_cli_enqueue_change(vty, "./msdp/hold-time", NB_OP_MODIFY, ++ holdtime_str); ++ nb_cli_enqueue_change(vty, "./msdp/keep-alive", NB_OP_MODIFY, ++ keepalive_str); ++ if (connretry_str) ++ nb_cli_enqueue_change(vty, "./msdp/connection-retry", ++ NB_OP_MODIFY, connretry_str); ++ else ++ nb_cli_enqueue_change(vty, "./msdp/connection-retry", ++ NB_OP_DESTROY, NULL); ++ ++ nb_cli_apply_changes(vty, NULL); ++ return CMD_SUCCESS; ++} ++DEFPY_ATTR(ip_pim_msdp_timers, ++ ip_msdp_timers_cmd, ++ "ip msdp timers (1-65535)$keepalive (1-65535)$holdtime [(1-65535)$connretry]", ++ IP_STR ++ CFG_MSDP_STR ++ "MSDP timers configuration\n" ++ "Keep alive period (in seconds)\n" ++ "Hold time period (in seconds)\n" ++ "Connection retry period (in seconds)\n", ++ CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) ++{ ++ int ret; + const char *vrfname; ++ char xpath[XPATH_MAXLEN]; ++ int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); +- if (vrfname == NULL) ++ if (vrfname) { ++ snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, ++ "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); ++ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); ++ if (nb_cli_apply_changes_clear_pending(vty, NULL) == ++ CMD_SUCCESS) { ++ orig_node = vty->node; ++ VTY_PUSH_XPATH(PIM_NODE, xpath); ++ } else { ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ } else { ++ vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; ++ } + +- nb_cli_enqueue_change(vty, "./hold-time", NB_OP_MODIFY, holdtime_str); +- nb_cli_enqueue_change(vty, "./keep-alive", NB_OP_MODIFY, keepalive_str); ++ nb_cli_enqueue_change(vty, "./msdp/hold-time", NB_OP_MODIFY, ++ holdtime_str); ++ nb_cli_enqueue_change(vty, "./msdp/keep-alive", NB_OP_MODIFY, ++ keepalive_str); + if (connretry_str) +- nb_cli_enqueue_change(vty, "./connection-retry", NB_OP_MODIFY, +- connretry_str); ++ nb_cli_enqueue_change(vty, "./msdp/connection-retry", ++ NB_OP_MODIFY, connretry_str); + else +- nb_cli_enqueue_change(vty, "./connection-retry", NB_OP_DESTROY, +- NULL); ++ nb_cli_enqueue_change(vty, "./msdp/connection-retry", ++ NB_OP_DESTROY, NULL); ++ ret = nb_cli_apply_changes(vty, NULL); + +- nb_cli_apply_changes(vty, FRR_PIM_MSDP_XPATH, "frr-pim:pimd", "pim", +- vrfname, "frr-routing:ipv4"); +- return CMD_SUCCESS; ++ if (orig_node != -1) { ++ vty->node = orig_node; ++ vty->xpath_index--; ++ } ++ ++ return ret; + } + +-DEFPY(no_ip_msdp_timers, no_ip_msdp_timers_cmd, +- "no ip msdp timers [(1-65535) (1-65535) [(1-65535)]]", ++DEFPY(no_pim_msdp_timers, no_pim_msdp_timers_cmd, ++ "no msdp timers [(1-65535) (1-65535) [(1-65535)]]", + NO_STR +- IP_STR + CFG_MSDP_STR + "MSDP timers configuration\n" + IGNORED_IN_NO_STR + IGNORED_IN_NO_STR + IGNORED_IN_NO_STR) + { ++ nb_cli_enqueue_change(vty, "./msdp/hold-time", NB_OP_DESTROY, NULL); ++ nb_cli_enqueue_change(vty, "./msdp/keep-alive", NB_OP_DESTROY, NULL); ++ nb_cli_enqueue_change(vty, "./msdp/connection-retry", NB_OP_DESTROY, ++ NULL); ++ nb_cli_apply_changes(vty, NULL); ++ return CMD_SUCCESS; ++} ++DEFPY_ATTR(no_ip_pim_msdp_timers, ++ no_ip_msdp_timers_cmd, ++ "no ip msdp timers [(1-65535) (1-65535) [(1-65535)]]", ++ NO_STR ++ IP_STR ++ CFG_MSDP_STR ++ "MSDP timers configuration\n" ++ IGNORED_IN_NO_STR ++ IGNORED_IN_NO_STR ++ IGNORED_IN_NO_STR, ++ CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) ++{ ++ int ret; + const char *vrfname; ++ char xpath[XPATH_MAXLEN]; ++ int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); +- if (vrfname == NULL) ++ if (vrfname) { ++ snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, ++ "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); ++ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); ++ if (nb_cli_apply_changes_clear_pending(vty, NULL) == ++ CMD_SUCCESS) { ++ orig_node = vty->node; ++ VTY_PUSH_XPATH(PIM_NODE, xpath); ++ } else { ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ } else { ++ vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; ++ } + +- nb_cli_enqueue_change(vty, "./hold-time", NB_OP_DESTROY, NULL); +- nb_cli_enqueue_change(vty, "./keep-alive", NB_OP_DESTROY, NULL); +- nb_cli_enqueue_change(vty, "./connection-retry", NB_OP_DESTROY, NULL); ++ nb_cli_enqueue_change(vty, "./msdp/hold-time", NB_OP_DESTROY, NULL); ++ nb_cli_enqueue_change(vty, "./msdp/keep-alive", NB_OP_DESTROY, NULL); ++ nb_cli_enqueue_change(vty, "./msdp/connection-retry", NB_OP_DESTROY, ++ NULL); ++ ret = nb_cli_apply_changes(vty, NULL); + +- nb_cli_apply_changes(vty, FRR_PIM_MSDP_XPATH, "frr-pim:pimd", "pim", +- vrfname, "frr-routing:ipv4"); ++ if (orig_node != -1) { ++ vty->node = orig_node; ++ vty->xpath_index--; ++ } + +- return CMD_SUCCESS; ++ return ret; + } + +-DEFUN (no_ip_msdp_peer, +- no_ip_msdp_peer_cmd, +- "no ip msdp peer A.B.C.D", ++DEFPY (no_pim_msdp_peer, ++ no_pim_msdp_peer_cmd, ++ "no msdp peer A.B.C.D", + NO_STR +- IP_STR + CFG_MSDP_STR + "Delete MSDP peer\n" + "peer ip address\n") + { +- const char *vrfname; + char msdp_peer_xpath[XPATH_MAXLEN]; +- char temp_xpath[XPATH_MAXLEN]; ++ ++ snprintf(msdp_peer_xpath, sizeof(msdp_peer_xpath), ++ "./msdp-peer[peer-ip='%s']", peer_str); ++ nb_cli_enqueue_change(vty, msdp_peer_xpath, NB_OP_DESTROY, NULL); ++ ++ return nb_cli_apply_changes(vty, NULL); ++} ++DEFPY_ATTR(no_ip_pim_msdp_peer, ++ no_ip_msdp_peer_cmd, ++ "no ip msdp peer A.B.C.D", ++ NO_STR ++ IP_STR ++ CFG_MSDP_STR ++ "Delete MSDP peer\n" ++ "peer ip address\n", ++ CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) ++{ ++ char msdp_peer_xpath[XPATH_MAXLEN]; ++ int ret; ++ const char *vrfname; ++ char xpath[XPATH_MAXLEN]; ++ int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); +- if (vrfname == NULL) ++ if (vrfname) { ++ snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, ++ "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); ++ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); ++ if (nb_cli_apply_changes_clear_pending(vty, NULL) == ++ CMD_SUCCESS) { ++ orig_node = vty->node; ++ VTY_PUSH_XPATH(PIM_NODE, xpath); ++ } else { ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ } else { ++ vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; ++ } + + snprintf(msdp_peer_xpath, sizeof(msdp_peer_xpath), +- FRR_PIM_VRF_XPATH, +- "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); +- snprintf(temp_xpath, sizeof(temp_xpath), +- "/msdp-peer[peer-ip='%s']", +- argv[4]->arg); +- +- strlcat(msdp_peer_xpath, temp_xpath, sizeof(msdp_peer_xpath)); +- ++ "./msdp-peer[peer-ip='%s']", peer_str); + nb_cli_enqueue_change(vty, msdp_peer_xpath, NB_OP_DESTROY, NULL); ++ ret = nb_cli_apply_changes(vty, NULL); + +- return nb_cli_apply_changes(vty, NULL); ++ if (orig_node != -1) { ++ vty->node = orig_node; ++ vty->xpath_index--; ++ } ++ ++ return ret; + } + +-DEFPY(ip_msdp_mesh_group_member, +- ip_msdp_mesh_group_member_cmd, +- "ip msdp mesh-group WORD$gname member A.B.C.D$maddr", +- IP_STR ++DEFPY(pim_msdp_mesh_group_member, ++ pim_msdp_mesh_group_member_cmd, ++ "msdp mesh-group WORD$gname member A.B.C.D$maddr", + CFG_MSDP_STR + "Configure MSDP mesh-group\n" + "Mesh group name\n" + "Mesh group member\n" + "Peer IP address\n") + { +- const char *vrfname; + char xpath_value[XPATH_MAXLEN]; + ++ /* Create mesh group. */ ++ snprintf(xpath_value, sizeof(xpath_value), ++ "./msdp-mesh-groups[name='%s']", gname); ++ nb_cli_enqueue_change(vty, xpath_value, NB_OP_CREATE, NULL); ++ ++ /* Create mesh group member. */ ++ strlcat(xpath_value, "/members[address='", sizeof(xpath_value)); ++ strlcat(xpath_value, maddr_str, sizeof(xpath_value)); ++ strlcat(xpath_value, "']", sizeof(xpath_value)); ++ nb_cli_enqueue_change(vty, xpath_value, NB_OP_CREATE, NULL); ++ ++ return nb_cli_apply_changes(vty, NULL); ++} ++DEFPY_ATTR(ip_pim_msdp_mesh_group_member, ++ ip_msdp_mesh_group_member_cmd, ++ "ip msdp mesh-group WORD$gname member A.B.C.D$maddr", ++ IP_STR ++ CFG_MSDP_STR ++ "Configure MSDP mesh-group\n" ++ "Mesh group name\n" ++ "Mesh group member\n" ++ "Peer IP address\n", ++ CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) ++{ ++ char xpath_value[XPATH_MAXLEN]; ++ int ret; ++ const char *vrfname; ++ char xpath[XPATH_MAXLEN]; ++ int orig_node = -1; ++ + vrfname = pim_cli_get_vrf_name(vty); +- if (vrfname == NULL) ++ if (vrfname) { ++ snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, ++ "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); ++ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); ++ if (nb_cli_apply_changes_clear_pending(vty, NULL) == ++ CMD_SUCCESS) { ++ orig_node = vty->node; ++ VTY_PUSH_XPATH(PIM_NODE, xpath); ++ } else { ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ } else { ++ vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; ++ } + + /* Create mesh group. */ + snprintf(xpath_value, sizeof(xpath_value), +- FRR_PIM_VRF_XPATH "/msdp-mesh-groups[name='%s']", +- "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4", gname); ++ "./msdp-mesh-groups[name='%s']", gname); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_CREATE, NULL); + + /* Create mesh group member. */ +@@ -5162,33 +6554,32 @@ DEFPY(ip_msdp_mesh_group_member, + strlcat(xpath_value, maddr_str, sizeof(xpath_value)); + strlcat(xpath_value, "']", sizeof(xpath_value)); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_CREATE, NULL); ++ ret = nb_cli_apply_changes(vty, NULL); + +- return nb_cli_apply_changes(vty, NULL); ++ if (orig_node != -1) { ++ vty->node = orig_node; ++ vty->xpath_index--; ++ } ++ ++ return ret; + } + +-DEFPY(no_ip_msdp_mesh_group_member, +- no_ip_msdp_mesh_group_member_cmd, +- "no ip msdp mesh-group WORD$gname member A.B.C.D$maddr", ++DEFPY(no_pim_msdp_mesh_group_member, ++ no_pim_msdp_mesh_group_member_cmd, ++ "no msdp mesh-group WORD$gname member A.B.C.D$maddr", + NO_STR +- IP_STR + CFG_MSDP_STR + "Delete MSDP mesh-group member\n" + "Mesh group name\n" + "Mesh group member\n" + "Peer IP address\n") + { +- const char *vrfname; + char xpath_value[XPATH_MAXLEN]; + char xpath_member_value[XPATH_MAXLEN]; + +- vrfname = pim_cli_get_vrf_name(vty); +- if (vrfname == NULL) +- return CMD_WARNING_CONFIG_FAILED; +- + /* Get mesh group base XPath. */ + snprintf(xpath_value, sizeof(xpath_value), +- FRR_PIM_VRF_XPATH "/msdp-mesh-groups[name='%s']", +- "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4", gname); ++ "%s/msdp-mesh-groups[name='%s']", VTY_CURR_XPATH, gname); + + if (!yang_dnode_exists(vty->candidate_config->dnode, xpath_value)) { + vty_out(vty, "%% mesh-group does not exist\n"); +@@ -5217,59 +6608,221 @@ DEFPY(no_ip_msdp_mesh_group_member, + + return nb_cli_apply_changes(vty, NULL); + } ++DEFPY_ATTR(no_ip_pim_msdp_mesh_group_member, ++ no_ip_msdp_mesh_group_member_cmd, ++ "no ip msdp mesh-group WORD$gname member A.B.C.D$maddr", ++ NO_STR ++ IP_STR ++ CFG_MSDP_STR ++ "Delete MSDP mesh-group member\n" ++ "Mesh group name\n" ++ "Mesh group member\n" ++ "Peer IP address\n", ++ CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) ++{ ++ char xpath_value[XPATH_MAXLEN]; ++ char xpath_member_value[XPATH_MAXLEN]; ++ int ret = CMD_WARNING_CONFIG_FAILED; ++ const char *vrfname; ++ char xpath[XPATH_MAXLEN]; ++ int orig_node = -1; + +-DEFPY(ip_msdp_mesh_group_source, +- ip_msdp_mesh_group_source_cmd, +- "ip msdp mesh-group WORD$gname source A.B.C.D$saddr", +- IP_STR ++ vrfname = pim_cli_get_vrf_name(vty); ++ if (vrfname) { ++ snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, ++ "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); ++ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); ++ if (nb_cli_apply_changes_clear_pending(vty, NULL) == ++ CMD_SUCCESS) { ++ orig_node = vty->node; ++ VTY_PUSH_XPATH(PIM_NODE, xpath); ++ } else { ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ } else { ++ vty_out(vty, "%% Failed to determine vrf name\n"); ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ ++ /* Get mesh group base XPath. */ ++ snprintf(xpath_value, sizeof(xpath_value), ++ "%s/msdp-mesh-groups[name='%s']", VTY_CURR_XPATH, gname); ++ ++ if (yang_dnode_exists(vty->candidate_config->dnode, xpath_value)) { ++ /* Remove mesh group member. */ ++ strlcpy(xpath_member_value, xpath_value, ++ sizeof(xpath_member_value)); ++ strlcat(xpath_member_value, "/members[address='", ++ sizeof(xpath_member_value)); ++ strlcat(xpath_member_value, maddr_str, ++ sizeof(xpath_member_value)); ++ strlcat(xpath_member_value, "']", sizeof(xpath_member_value)); ++ if (yang_dnode_exists(vty->candidate_config->dnode, ++ xpath_member_value)) { ++ nb_cli_enqueue_change(vty, xpath_member_value, ++ NB_OP_DESTROY, NULL); ++ ++ /* ++ * If this is the last member, then we must remove the group altogether ++ * to not break legacy CLI behaviour. ++ */ ++ pim_cli_legacy_mesh_group_behavior(vty, gname); ++ ret = nb_cli_apply_changes(vty, NULL); ++ } else { ++ vty_out(vty, "%% mesh-group member does not exist\n"); ++ } ++ } else { ++ vty_out(vty, "%% mesh-group does not exist\n"); ++ } ++ ++ if (orig_node != -1) { ++ vty->node = orig_node; ++ vty->xpath_index--; ++ } ++ ++ return ret; ++} ++ ++DEFPY(pim_msdp_mesh_group_source, ++ pim_msdp_mesh_group_source_cmd, ++ "msdp mesh-group WORD$gname source A.B.C.D$saddr", + CFG_MSDP_STR + "Configure MSDP mesh-group\n" + "Mesh group name\n" + "Mesh group local address\n" + "Source IP address for the TCP connection\n") + { +- const char *vrfname; + char xpath_value[XPATH_MAXLEN]; + ++ /* Create mesh group. */ ++ snprintf(xpath_value, sizeof(xpath_value), ++ "./msdp-mesh-groups[name='%s']", gname); ++ nb_cli_enqueue_change(vty, xpath_value, NB_OP_CREATE, NULL); ++ ++ /* Create mesh group source. */ ++ strlcat(xpath_value, "/source", sizeof(xpath_value)); ++ nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, saddr_str); ++ ++ return nb_cli_apply_changes(vty, NULL); ++} ++DEFPY_ATTR(ip_pim_msdp_mesh_group_source, ++ ip_msdp_mesh_group_source_cmd, ++ "ip msdp mesh-group WORD$gname source A.B.C.D$saddr", ++ IP_STR ++ CFG_MSDP_STR ++ "Configure MSDP mesh-group\n" ++ "Mesh group name\n" ++ "Mesh group local address\n" ++ "Source IP address for the TCP connection\n", ++ CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) ++{ ++ char xpath_value[XPATH_MAXLEN]; ++ int ret; ++ const char *vrfname; ++ char xpath[XPATH_MAXLEN]; ++ int orig_node = -1; ++ + vrfname = pim_cli_get_vrf_name(vty); +- if (vrfname == NULL) ++ if (vrfname) { ++ snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, ++ "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); ++ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); ++ if (nb_cli_apply_changes_clear_pending(vty, NULL) == ++ CMD_SUCCESS) { ++ orig_node = vty->node; ++ VTY_PUSH_XPATH(PIM_NODE, xpath); ++ } else { ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ } else { ++ vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; ++ } + + /* Create mesh group. */ + snprintf(xpath_value, sizeof(xpath_value), +- FRR_PIM_VRF_XPATH "/msdp-mesh-groups[name='%s']", +- "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4", gname); ++ "./msdp-mesh-groups[name='%s']", gname); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_CREATE, NULL); +- + /* Create mesh group source. */ + strlcat(xpath_value, "/source", sizeof(xpath_value)); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, saddr_str); ++ ret = nb_cli_apply_changes(vty, NULL); + +- return nb_cli_apply_changes(vty, NULL); ++ if (orig_node != -1) { ++ vty->node = orig_node; ++ vty->xpath_index--; ++ } ++ ++ return ret; + } + +-DEFPY(no_ip_msdp_mesh_group_source, +- no_ip_msdp_mesh_group_source_cmd, +- "no ip msdp mesh-group WORD$gname source [A.B.C.D]", ++DEFPY(no_pim_msdp_mesh_group_source, ++ no_pim_msdp_mesh_group_source_cmd, ++ "no msdp mesh-group WORD$gname source [A.B.C.D]", + NO_STR +- IP_STR + CFG_MSDP_STR + "Delete MSDP mesh-group source\n" + "Mesh group name\n" + "Mesh group source\n" + "Mesh group local address\n") + { +- const char *vrfname; + char xpath_value[XPATH_MAXLEN]; + ++ /* Get mesh group base XPath. */ ++ snprintf(xpath_value, sizeof(xpath_value), ++ "./msdp-mesh-groups[name='%s']", gname); ++ nb_cli_enqueue_change(vty, xpath_value, NB_OP_CREATE, NULL); ++ ++ /* Create mesh group source. */ ++ strlcat(xpath_value, "/source", sizeof(xpath_value)); ++ nb_cli_enqueue_change(vty, xpath_value, NB_OP_DESTROY, NULL); ++ ++ /* ++ * If this is the last member, then we must remove the group altogether ++ * to not break legacy CLI behaviour. ++ */ ++ pim_cli_legacy_mesh_group_behavior(vty, gname); ++ ++ return nb_cli_apply_changes(vty, NULL); ++} ++DEFPY_ATTR(no_ip_pim_msdp_mesh_group_source, ++ no_ip_msdp_mesh_group_source_cmd, ++ "no ip msdp mesh-group WORD$gname source [A.B.C.D]", ++ NO_STR ++ IP_STR ++ CFG_MSDP_STR ++ "Delete MSDP mesh-group source\n" ++ "Mesh group name\n" ++ "Mesh group source\n" ++ "Mesh group local address\n", ++ CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) ++{ ++ char xpath_value[XPATH_MAXLEN]; ++ int ret; ++ const char *vrfname; ++ char xpath[XPATH_MAXLEN]; ++ int orig_node = -1; ++ + vrfname = pim_cli_get_vrf_name(vty); +- if (vrfname == NULL) ++ if (vrfname) { ++ snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, ++ "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); ++ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); ++ if (nb_cli_apply_changes_clear_pending(vty, NULL) == ++ CMD_SUCCESS) { ++ orig_node = vty->node; ++ VTY_PUSH_XPATH(PIM_NODE, xpath); ++ } else { ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ } else { ++ vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; ++ } + + /* Get mesh group base XPath. */ + snprintf(xpath_value, sizeof(xpath_value), +- FRR_PIM_VRF_XPATH "/msdp-mesh-groups[name='%s']", +- "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4", gname); ++ "./msdp-mesh-groups[name='%s']", gname); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_CREATE, NULL); + + /* Create mesh group source. */ +@@ -5281,36 +6834,83 @@ DEFPY(no_ip_msdp_mesh_group_source, + * to not break legacy CLI behaviour. + */ + pim_cli_legacy_mesh_group_behavior(vty, gname); ++ ret = nb_cli_apply_changes(vty, NULL); + +- return nb_cli_apply_changes(vty, NULL); ++ if (orig_node != -1) { ++ vty->node = orig_node; ++ vty->xpath_index--; ++ } ++ ++ return ret; + } + +-DEFPY(no_ip_msdp_mesh_group, +- no_ip_msdp_mesh_group_cmd, +- "no ip msdp mesh-group WORD$gname", ++DEFPY(no_pim_msdp_mesh_group, ++ no_pim_msdp_mesh_group_cmd, ++ "no msdp mesh-group WORD$gname", + NO_STR +- IP_STR + CFG_MSDP_STR + "Delete MSDP mesh-group\n" + "Mesh group name\n") + { +- const char *vrfname; + char xpath_value[XPATH_MAXLEN]; + +- vrfname = pim_cli_get_vrf_name(vty); +- if (vrfname == NULL) +- return CMD_WARNING_CONFIG_FAILED; +- + /* Get mesh group base XPath. */ + snprintf(xpath_value, sizeof(xpath_value), +- FRR_PIM_VRF_XPATH "/msdp-mesh-groups[name='%s']", +- "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4", gname); ++ "%s/msdp-mesh-groups[name='%s']", VTY_CURR_XPATH, gname); + if (!yang_dnode_exists(vty->candidate_config->dnode, xpath_value)) + return CMD_SUCCESS; + + nb_cli_enqueue_change(vty, xpath_value, NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); + } ++DEFPY_ATTR(no_ip_pim_msdp_mesh_group, ++ no_ip_msdp_mesh_group_cmd, ++ "no ip msdp mesh-group WORD$gname", ++ NO_STR ++ IP_STR ++ CFG_MSDP_STR ++ "Delete MSDP mesh-group\n" ++ "Mesh group name\n", ++ CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) ++{ ++ char xpath_value[XPATH_MAXLEN]; ++ int ret = CMD_SUCCESS; ++ const char *vrfname; ++ char xpath[XPATH_MAXLEN]; ++ int orig_node = -1; ++ ++ vrfname = pim_cli_get_vrf_name(vty); ++ if (vrfname) { ++ snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, ++ "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); ++ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); ++ if (nb_cli_apply_changes_clear_pending(vty, NULL) == ++ CMD_SUCCESS) { ++ orig_node = vty->node; ++ VTY_PUSH_XPATH(PIM_NODE, xpath); ++ } else { ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ } else { ++ vty_out(vty, "%% Failed to determine vrf name\n"); ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ ++ /* Get mesh group base XPath. */ ++ snprintf(xpath_value, sizeof(xpath_value), ++ "%s/msdp-mesh-groups[name='%s']", VTY_CURR_XPATH, gname); ++ if (yang_dnode_exists(vty->candidate_config->dnode, xpath_value)) { ++ nb_cli_enqueue_change(vty, xpath_value, NB_OP_DESTROY, NULL); ++ ret = nb_cli_apply_changes(vty, NULL); ++ } ++ ++ if (orig_node != -1) { ++ vty->node = orig_node; ++ vty->xpath_index--; ++ } ++ ++ return ret; ++} + + static void ip_msdp_show_mesh_group(struct vty *vty, struct pim_msdp_mg *mg, + struct json_object *json) +@@ -5329,7 +6929,8 @@ static void ip_msdp_show_mesh_group(struct vty *vty, struct pim_msdp_mg *mg, + if (json) { + /* currently there is only one mesh group but we should still + * make +- * it a dict with mg-name as key */ ++ * it a dict with mg-name as key ++ */ + json_mg_row = json_object_new_object(); + json_object_string_add(json_mg_row, "name", + mg->mesh_group_name); +@@ -6311,119 +7912,224 @@ DEFUN_HIDDEN (show_ip_pim_vxlan_sg_work, + return CMD_SUCCESS; + } + +-DEFUN_HIDDEN (no_ip_pim_mlag, +- no_ip_pim_mlag_cmd, +- "no ip pim mlag", ++DEFPY_HIDDEN (no_pim_mlag, ++ no_pim_mlag_cmd, ++ "no mlag", + NO_STR +- IP_STR +- PIM_STR + "MLAG\n") + { + char mlag_xpath[XPATH_MAXLEN]; + +- snprintf(mlag_xpath, sizeof(mlag_xpath), FRR_PIM_VRF_XPATH, +- "frr-pim:pimd", "pim", "default", "frr-routing:ipv4"); +- strlcat(mlag_xpath, "/mlag", sizeof(mlag_xpath)); ++ snprintf(mlag_xpath, sizeof(mlag_xpath), "./mlag"); ++ nb_cli_enqueue_change(vty, mlag_xpath, NB_OP_DESTROY, NULL); ++ ++ return nb_cli_apply_changes(vty, NULL); ++} ++DEFPY_ATTR(no_ip_pim_mlag, ++ no_ip_pim_mlag_cmd, ++ "no ip pim mlag", ++ NO_STR ++ IP_STR ++ PIM_STR ++ "MLAG\n", ++ CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) ++{ ++ char mlag_xpath[XPATH_MAXLEN]; ++ int ret; ++ const char *vrfname; ++ char xpath[XPATH_MAXLEN]; ++ int orig_node = -1; ++ ++ vrfname = pim_cli_get_vrf_name(vty); ++ if (vrfname) { ++ snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, ++ "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); ++ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); ++ if (nb_cli_apply_changes_clear_pending(vty, NULL) == ++ CMD_SUCCESS) { ++ orig_node = vty->node; ++ VTY_PUSH_XPATH(PIM_NODE, xpath); ++ } else { ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ } else { ++ vty_out(vty, "%% Failed to determine vrf name\n"); ++ return CMD_WARNING_CONFIG_FAILED; ++ } + ++ snprintf(mlag_xpath, sizeof(mlag_xpath), "./mlag"); + nb_cli_enqueue_change(vty, mlag_xpath, NB_OP_DESTROY, NULL); ++ ret = nb_cli_apply_changes(vty, NULL); ++ ++ if (orig_node != -1) { ++ vty->node = orig_node; ++ vty->xpath_index--; ++ } ++ ++ return ret; ++} ++ ++DEFPY_HIDDEN (pim_mlag, ++ pim_mlag_cmd, ++ "mlag INTERFACE$iface role [primary|secondary]$role state [up|down]$state addr A.B.C.D$addr", ++ "MLAG\n" ++ "peerlink sub interface\n" ++ "MLAG role\n" ++ "MLAG role primary\n" ++ "MLAG role secondary\n" ++ "peer session state\n" ++ "peer session state up\n" ++ "peer session state down\n" ++ "configure PIP\n" ++ "unique ip address\n") ++{ ++ 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), ++ "./mlag/peerlink-rif"); ++ nb_cli_enqueue_change(vty, mlag_peerlink_rif_xpath, NB_OP_MODIFY, iface); ++ ++ snprintf(mlag_my_role_xpath, sizeof(mlag_my_role_xpath), ++ "./mlag/my-role"); ++ if (!strcmp(role, "primary")) { ++ nb_cli_enqueue_change(vty, mlag_my_role_xpath, NB_OP_MODIFY, ++ "MLAG_ROLE_PRIMARY"); ++ } else if (!strcmp(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", role); ++ return CMD_WARNING; ++ } ++ ++ snprintf(mlag_peer_state_xpath, sizeof(mlag_peer_state_xpath), ++ "./mlag/peer-state"); ++ if (!strcmp(state, "up")) { ++ nb_cli_enqueue_change(vty, mlag_peer_state_xpath, NB_OP_MODIFY, ++ "true"); ++ } else if (strcmp(state, "down")) { ++ nb_cli_enqueue_change(vty, mlag_peer_state_xpath, NB_OP_MODIFY, ++ "false"); ++ } else { ++ vty_out(vty, "unknown MLAG state %s\n", state); ++ return CMD_WARNING; ++ } + ++ snprintf(mlag_reg_address_xpath, sizeof(mlag_reg_address_xpath), ++ "./mlag/reg-address"); ++ nb_cli_enqueue_change(vty, mlag_reg_address_xpath, NB_OP_MODIFY, ++ addr_str); + + return nb_cli_apply_changes(vty, NULL); + } +- +-DEFUN_HIDDEN (ip_pim_mlag, +- ip_pim_mlag_cmd, +- "ip pim mlag INTERFACE role [primary|secondary] state [up|down] addr A.B.C.D", +- IP_STR +- PIM_STR +- "MLAG\n" +- "peerlink sub interface\n" +- "MLAG role\n" +- "MLAG role primary\n" +- "MLAG role secondary\n" +- "peer session state\n" +- "peer session state up\n" +- "peer session state down\n" +- "configure PIP\n" +- "unique ip address\n") ++DEFPY_ATTR(ip_pim_mlag, ++ ip_pim_mlag_cmd, ++ "ip pim mlag INTERFACE$iface role [primary|secondary]$role state [up|down]$state addr A.B.C.D$addr", ++ IP_STR ++ PIM_STR ++ "MLAG\n" ++ "peerlink sub interface\n" ++ "MLAG role\n" ++ "MLAG role primary\n" ++ "MLAG role secondary\n" ++ "peer session state\n" ++ "peer session state up\n" ++ "peer session state down\n" ++ "configure PIP\n" ++ "unique ip address\n", ++ CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) + { +- int idx; + 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]; ++ int ret; ++ const char *vrfname; ++ char xpath[XPATH_MAXLEN]; ++ int orig_node = -1; + +- snprintf(mlag_peerlink_rif_xpath, sizeof(mlag_peerlink_rif_xpath), +- FRR_PIM_VRF_XPATH, +- "frr-pim:pimd", "pim", "default", "frr-routing:ipv4"); +- strlcat(mlag_peerlink_rif_xpath, "/mlag/peerlink-rif", +- sizeof(mlag_peerlink_rif_xpath)); ++ vrfname = pim_cli_get_vrf_name(vty); ++ if (vrfname) { ++ snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, ++ "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); ++ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); ++ if (nb_cli_apply_changes_clear_pending(vty, NULL) == ++ CMD_SUCCESS) { ++ orig_node = vty->node; ++ VTY_PUSH_XPATH(PIM_NODE, xpath); ++ } else { ++ return CMD_WARNING_CONFIG_FAILED; ++ } ++ } else { ++ vty_out(vty, "%% Failed to determine vrf name\n"); ++ return CMD_WARNING_CONFIG_FAILED; ++ } + +- idx = 3; +- nb_cli_enqueue_change(vty, mlag_peerlink_rif_xpath, NB_OP_MODIFY, +- argv[idx]->arg); ++ snprintf(mlag_peerlink_rif_xpath, sizeof(mlag_peerlink_rif_xpath), ++ "./mlag/peerlink-rif"); ++ nb_cli_enqueue_change(vty, mlag_peerlink_rif_xpath, NB_OP_MODIFY, iface); + + snprintf(mlag_my_role_xpath, sizeof(mlag_my_role_xpath), +- FRR_PIM_VRF_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")) { ++ "./mlag/my-role"); ++ if (!strcmp(role, "primary")) { + nb_cli_enqueue_change(vty, mlag_my_role_xpath, NB_OP_MODIFY, + "MLAG_ROLE_PRIMARY"); +- +- } else if (!strcmp(argv[idx]->arg, "secondary")) { ++ } else if (!strcmp(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; ++ vty_out(vty, "unknown MLAG role %s\n", role); ++ ret = CMD_WARNING; ++ goto done; + } + + snprintf(mlag_peer_state_xpath, sizeof(mlag_peer_state_xpath), +- FRR_PIM_VRF_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")) { ++ "./mlag/peer-state"); ++ if (!strcmp(state, "up")) { + nb_cli_enqueue_change(vty, mlag_peer_state_xpath, NB_OP_MODIFY, + "true"); +- +- } else if (strcmp(argv[idx]->arg, "down")) { ++ } else if (strcmp(state, "down")) { + 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; ++ vty_out(vty, "unknown MLAG state %s\n", state); ++ ret = CMD_WARNING; ++ goto done; + } + + snprintf(mlag_reg_address_xpath, sizeof(mlag_reg_address_xpath), +- FRR_PIM_VRF_XPATH, +- "frr-pim:pimd", "pim", "default", "frr-routing:ipv4"); +- strlcat(mlag_reg_address_xpath, "/mlag/reg-address", +- sizeof(mlag_reg_address_xpath)); +- +- idx += 2; ++ "./mlag/reg-address"); + nb_cli_enqueue_change(vty, mlag_reg_address_xpath, NB_OP_MODIFY, +- argv[idx]->arg); ++ addr_str); + +- return nb_cli_apply_changes(vty, NULL); +-} ++ ret = nb_cli_apply_changes(vty, NULL); + +-void pim_cmd_init(void) +-{ +- if_cmd_init(pim_interface_config_write); ++done: ++ if (orig_node != -1) { ++ vty->node = orig_node; ++ vty->xpath_index--; ++ } + +- install_node(&debug_node); ++ return ret; ++} + +- install_element(ENABLE_NODE, &pim_test_sg_keepalive_cmd); ++struct cmd_node pim_node = { ++ .name = "pim", ++ .node = PIM_NODE, ++ .parent_node = CONFIG_NODE, ++ .prompt = "%s(config-pim)# ", ++ .config_write = pim_router_config_write, ++}; + ++/* This function installs all of the deprecated PIM configuration commands that live in the global config and/or VRF nodes ++ * This configuration has been moved to the new 'router pim' config node instead like all the other routing protocols. ++ * No new commands should be added here. ++ */ ++static void pim_install_deprecated(void) ++{ + install_element(CONFIG_NODE, &ip_pim_rp_cmd); + install_element(VRF_NODE, &ip_pim_rp_cmd); + install_element(CONFIG_NODE, &no_ip_pim_rp_cmd); +@@ -6449,8 +8155,8 @@ void pim_cmd_init(void) + install_element(CONFIG_NODE, + &no_ip_pim_spt_switchover_infinity_plist_cmd); + install_element(VRF_NODE, &no_ip_pim_spt_switchover_infinity_plist_cmd); +- install_element(CONFIG_NODE, &pim_register_accept_list_cmd); +- install_element(VRF_NODE, &pim_register_accept_list_cmd); ++ install_element(CONFIG_NODE, &ip_pim_register_accept_list_cmd); ++ install_element(VRF_NODE, &ip_pim_register_accept_list_cmd); + install_element(CONFIG_NODE, &ip_pim_joinprune_time_cmd); + install_element(CONFIG_NODE, &no_ip_pim_joinprune_time_cmd); + install_element(CONFIG_NODE, &ip_pim_keep_alive_cmd); +@@ -6467,14 +8173,6 @@ void pim_cmd_init(void) + install_element(VRF_NODE, &ip_pim_v6_secondary_cmd); + install_element(CONFIG_NODE, &no_ip_pim_v6_secondary_cmd); + install_element(VRF_NODE, &no_ip_pim_v6_secondary_cmd); +- install_element(CONFIG_NODE, &ip_ssmpingd_cmd); +- install_element(VRF_NODE, &ip_ssmpingd_cmd); +- install_element(CONFIG_NODE, &no_ip_ssmpingd_cmd); +- install_element(VRF_NODE, &no_ip_ssmpingd_cmd); +- install_element(CONFIG_NODE, &ip_msdp_peer_cmd); +- install_element(VRF_NODE, &ip_msdp_peer_cmd); +- install_element(CONFIG_NODE, &no_ip_msdp_peer_cmd); +- install_element(VRF_NODE, &no_ip_msdp_peer_cmd); + install_element(CONFIG_NODE, &ip_pim_ecmp_cmd); + install_element(VRF_NODE, &ip_pim_ecmp_cmd); + install_element(CONFIG_NODE, &no_ip_pim_ecmp_cmd); +@@ -6485,10 +8183,87 @@ void pim_cmd_init(void) + install_element(VRF_NODE, &no_ip_pim_ecmp_rebalance_cmd); + install_element(CONFIG_NODE, &ip_pim_mlag_cmd); + install_element(CONFIG_NODE, &no_ip_pim_mlag_cmd); +- install_element(CONFIG_NODE, &ip_igmp_group_watermark_cmd); +- install_element(VRF_NODE, &ip_igmp_group_watermark_cmd); +- install_element(CONFIG_NODE, &no_ip_igmp_group_watermark_cmd); +- install_element(VRF_NODE, &no_ip_igmp_group_watermark_cmd); ++ ++ install_element(CONFIG_NODE, &ip_ssmpingd_cmd); ++ install_element(VRF_NODE, &ip_ssmpingd_cmd); ++ install_element(CONFIG_NODE, &no_ip_ssmpingd_cmd); ++ install_element(VRF_NODE, &no_ip_ssmpingd_cmd); ++ ++ install_element(CONFIG_NODE, &ip_msdp_peer_cmd); ++ install_element(VRF_NODE, &ip_msdp_peer_cmd); ++ install_element(CONFIG_NODE, &no_ip_msdp_peer_cmd); ++ install_element(VRF_NODE, &no_ip_msdp_peer_cmd); ++ install_element(CONFIG_NODE, &ip_msdp_timers_cmd); ++ install_element(VRF_NODE, &ip_msdp_timers_cmd); ++ install_element(CONFIG_NODE, &no_ip_msdp_timers_cmd); ++ install_element(VRF_NODE, &no_ip_msdp_timers_cmd); ++ install_element(CONFIG_NODE, &ip_msdp_mesh_group_member_cmd); ++ install_element(VRF_NODE, &ip_msdp_mesh_group_member_cmd); ++ install_element(CONFIG_NODE, &no_ip_msdp_mesh_group_member_cmd); ++ install_element(VRF_NODE, &no_ip_msdp_mesh_group_member_cmd); ++ install_element(CONFIG_NODE, &ip_msdp_mesh_group_source_cmd); ++ install_element(VRF_NODE, &ip_msdp_mesh_group_source_cmd); ++ install_element(CONFIG_NODE, &no_ip_msdp_mesh_group_source_cmd); ++ install_element(VRF_NODE, &no_ip_msdp_mesh_group_source_cmd); ++ install_element(CONFIG_NODE, &no_ip_msdp_mesh_group_cmd); ++ install_element(VRF_NODE, &no_ip_msdp_mesh_group_cmd); ++} ++ ++void pim_cmd_init(void) ++{ ++ if_cmd_init(pim_interface_config_write); ++ ++ install_node(&debug_node); ++ ++ install_element(CONFIG_NODE, &router_pim_cmd); ++ install_element(CONFIG_NODE, &no_router_pim_cmd); ++ ++ install_node(&pim_node); ++ install_default(PIM_NODE); ++ ++ install_element(PIM_NODE, &pim_rp_cmd); ++ install_element(PIM_NODE, &no_pim_rp_cmd); ++ install_element(PIM_NODE, &pim_rp_prefix_list_cmd); ++ install_element(PIM_NODE, &no_pim_rp_prefix_list_cmd); ++ install_element(PIM_NODE, &no_pim_ssm_prefix_list_cmd); ++ install_element(PIM_NODE, &no_pim_ssm_prefix_list_name_cmd); ++ install_element(PIM_NODE, &pim_ssm_prefix_list_cmd); ++ install_element(PIM_NODE, &pim_register_suppress_cmd); ++ install_element(PIM_NODE, &no_pim_register_suppress_cmd); ++ install_element(PIM_NODE, &pim_spt_switchover_infinity_cmd); ++ install_element(PIM_NODE, &pim_spt_switchover_infinity_plist_cmd); ++ install_element(PIM_NODE, &no_pim_spt_switchover_infinity_cmd); ++ install_element(PIM_NODE, &no_pim_spt_switchover_infinity_plist_cmd); ++ install_element(PIM_NODE, &pim_register_accept_list_cmd); ++ install_element(PIM_NODE, &pim_joinprune_time_cmd); ++ install_element(PIM_NODE, &no_pim_joinprune_time_cmd); ++ install_element(PIM_NODE, &pim_keep_alive_cmd); ++ install_element(PIM_NODE, &pim_rp_keep_alive_cmd); ++ install_element(PIM_NODE, &no_pim_keep_alive_cmd); ++ install_element(PIM_NODE, &no_pim_rp_keep_alive_cmd); ++ install_element(PIM_NODE, &pim_packets_cmd); ++ install_element(PIM_NODE, &no_pim_packets_cmd); ++ install_element(PIM_NODE, &pim_v6_secondary_cmd); ++ install_element(PIM_NODE, &no_pim_v6_secondary_cmd); ++ install_element(PIM_NODE, &pim_ecmp_cmd); ++ install_element(PIM_NODE, &no_pim_ecmp_cmd); ++ install_element(PIM_NODE, &pim_ecmp_rebalance_cmd); ++ install_element(PIM_NODE, &no_pim_ecmp_rebalance_cmd); ++ install_element(PIM_NODE, &pim_mlag_cmd); ++ install_element(PIM_NODE, &no_pim_mlag_cmd); ++ ++ install_element(PIM_NODE, &pim_ssmpingd_cmd); ++ install_element(PIM_NODE, &no_pim_ssmpingd_cmd); ++ ++ install_element(PIM_NODE, &pim_msdp_peer_cmd); ++ install_element(PIM_NODE, &no_pim_msdp_peer_cmd); ++ install_element(PIM_NODE, &pim_msdp_timers_cmd); ++ install_element(PIM_NODE, &no_pim_msdp_timers_cmd); ++ install_element(PIM_NODE, &pim_msdp_mesh_group_member_cmd); ++ install_element(PIM_NODE, &no_pim_msdp_mesh_group_member_cmd); ++ install_element(PIM_NODE, &pim_msdp_mesh_group_source_cmd); ++ install_element(PIM_NODE, &no_pim_msdp_mesh_group_source_cmd); ++ install_element(PIM_NODE, &no_pim_msdp_mesh_group_cmd); + + install_element(INTERFACE_NODE, &interface_ip_igmp_cmd); + install_element(INTERFACE_NODE, &interface_no_ip_igmp_cmd); +@@ -6534,6 +8309,22 @@ void pim_cmd_init(void) + install_element(INTERFACE_NODE, &interface_ip_mroute_cmd); + install_element(INTERFACE_NODE, &interface_no_ip_mroute_cmd); + ++ install_element(INTERFACE_NODE, &interface_pim_use_source_cmd); ++ install_element(INTERFACE_NODE, &interface_no_pim_use_source_cmd); ++ /* Install BSM command */ ++ install_element(INTERFACE_NODE, &ip_pim_bsm_cmd); ++ install_element(INTERFACE_NODE, &no_ip_pim_bsm_cmd); ++ install_element(INTERFACE_NODE, &ip_pim_ucast_bsm_cmd); ++ install_element(INTERFACE_NODE, &no_ip_pim_ucast_bsm_cmd); ++ /* Install BFD command */ ++ install_element(INTERFACE_NODE, &ip_pim_bfd_cmd); ++ install_element(INTERFACE_NODE, &ip_pim_bfd_param_cmd); ++ install_element(INTERFACE_NODE, &no_ip_pim_bfd_profile_cmd); ++ install_element(INTERFACE_NODE, &no_ip_pim_bfd_cmd); ++#if HAVE_BFDD == 0 ++ install_element(INTERFACE_NODE, &no_ip_pim_bfd_param_cmd); ++#endif /* !HAVE_BFDD */ ++ + install_element(VIEW_NODE, &show_ip_igmp_interface_cmd); + install_element(VIEW_NODE, &show_ip_igmp_interface_vrf_all_cmd); + install_element(VIEW_NODE, &show_ip_igmp_join_cmd); +@@ -6590,6 +8381,20 @@ void pim_cmd_init(void) + install_element(VIEW_NODE, &show_ip_pim_bsrp_cmd); + install_element(VIEW_NODE, &show_ip_pim_bsm_db_cmd); + install_element(VIEW_NODE, &show_ip_pim_statistics_cmd); ++ install_element(VIEW_NODE, &show_ip_msdp_peer_detail_cmd); ++ install_element(VIEW_NODE, &show_ip_msdp_peer_detail_vrf_all_cmd); ++ install_element(VIEW_NODE, &show_ip_msdp_sa_detail_cmd); ++ install_element(VIEW_NODE, &show_ip_msdp_sa_detail_vrf_all_cmd); ++ install_element(VIEW_NODE, &show_ip_msdp_sa_sg_cmd); ++ install_element(VIEW_NODE, &show_ip_msdp_sa_sg_vrf_all_cmd); ++ install_element(VIEW_NODE, &show_ip_msdp_mesh_group_cmd); ++ install_element(VIEW_NODE, &show_ip_msdp_mesh_group_vrf_all_cmd); ++ install_element(VIEW_NODE, &show_ip_pim_ssm_range_cmd); ++ install_element(VIEW_NODE, &show_ip_pim_group_type_cmd); ++ install_element(VIEW_NODE, &show_ip_pim_vxlan_sg_cmd); ++ install_element(VIEW_NODE, &show_ip_pim_vxlan_sg_work_cmd); ++ ++ install_element(ENABLE_NODE, &pim_test_sg_keepalive_cmd); + + install_element(ENABLE_NODE, &clear_ip_mroute_count_cmd); + install_element(ENABLE_NODE, &clear_ip_interfaces_cmd); +@@ -6604,134 +8409,98 @@ void pim_cmd_init(void) + install_element(ENABLE_NODE, &show_debugging_pim_cmd); + + install_element(ENABLE_NODE, &debug_igmp_cmd); +- install_element(ENABLE_NODE, &no_debug_igmp_cmd); +- install_element(ENABLE_NODE, &debug_igmp_events_cmd); +- install_element(ENABLE_NODE, &no_debug_igmp_events_cmd); +- install_element(ENABLE_NODE, &debug_igmp_packets_cmd); +- install_element(ENABLE_NODE, &no_debug_igmp_packets_cmd); +- install_element(ENABLE_NODE, &debug_igmp_trace_cmd); +- install_element(ENABLE_NODE, &no_debug_igmp_trace_cmd); +- install_element(ENABLE_NODE, &debug_igmp_trace_detail_cmd); +- install_element(ENABLE_NODE, &no_debug_igmp_trace_detail_cmd); +- install_element(ENABLE_NODE, &debug_mroute_cmd); +- install_element(ENABLE_NODE, &debug_mroute_detail_cmd); +- install_element(ENABLE_NODE, &no_debug_mroute_cmd); +- install_element(ENABLE_NODE, &no_debug_mroute_detail_cmd); +- install_element(ENABLE_NODE, &debug_pim_static_cmd); +- install_element(ENABLE_NODE, &no_debug_pim_static_cmd); +- install_element(ENABLE_NODE, &debug_pim_cmd); +- install_element(ENABLE_NODE, &debug_pim_nht_cmd); +- install_element(ENABLE_NODE, &debug_pim_nht_det_cmd); +- install_element(ENABLE_NODE, &debug_pim_nht_rp_cmd); +- install_element(ENABLE_NODE, &no_debug_pim_nht_rp_cmd); +- install_element(ENABLE_NODE, &debug_pim_events_cmd); +- install_element(ENABLE_NODE, &debug_pim_packets_cmd); +- install_element(ENABLE_NODE, &debug_pim_packetdump_send_cmd); +- install_element(ENABLE_NODE, &debug_pim_packetdump_recv_cmd); +- install_element(ENABLE_NODE, &debug_pim_trace_cmd); +- install_element(ENABLE_NODE, &debug_pim_trace_detail_cmd); +- install_element(ENABLE_NODE, &debug_ssmpingd_cmd); +- install_element(ENABLE_NODE, &no_debug_ssmpingd_cmd); +- install_element(ENABLE_NODE, &debug_pim_zebra_cmd); +- install_element(ENABLE_NODE, &debug_pim_mlag_cmd); +- install_element(ENABLE_NODE, &no_debug_pim_mlag_cmd); +- install_element(ENABLE_NODE, &debug_pim_vxlan_cmd); +- install_element(ENABLE_NODE, &no_debug_pim_vxlan_cmd); +- install_element(ENABLE_NODE, &debug_msdp_cmd); +- install_element(ENABLE_NODE, &no_debug_msdp_cmd); +- install_element(ENABLE_NODE, &debug_msdp_events_cmd); +- install_element(ENABLE_NODE, &no_debug_msdp_events_cmd); +- install_element(ENABLE_NODE, &debug_msdp_packets_cmd); +- install_element(ENABLE_NODE, &no_debug_msdp_packets_cmd); +- install_element(ENABLE_NODE, &debug_mtrace_cmd); +- install_element(ENABLE_NODE, &no_debug_mtrace_cmd); +- install_element(ENABLE_NODE, &debug_bsm_cmd); +- install_element(ENABLE_NODE, &no_debug_bsm_cmd); +- + install_element(CONFIG_NODE, &debug_igmp_cmd); ++ install_element(ENABLE_NODE, &no_debug_igmp_cmd); + install_element(CONFIG_NODE, &no_debug_igmp_cmd); ++ install_element(ENABLE_NODE, &debug_igmp_events_cmd); + install_element(CONFIG_NODE, &debug_igmp_events_cmd); ++ install_element(ENABLE_NODE, &no_debug_igmp_events_cmd); + install_element(CONFIG_NODE, &no_debug_igmp_events_cmd); ++ install_element(ENABLE_NODE, &debug_igmp_packets_cmd); + install_element(CONFIG_NODE, &debug_igmp_packets_cmd); ++ install_element(ENABLE_NODE, &no_debug_igmp_packets_cmd); + install_element(CONFIG_NODE, &no_debug_igmp_packets_cmd); ++ install_element(ENABLE_NODE, &debug_igmp_trace_cmd); + install_element(CONFIG_NODE, &debug_igmp_trace_cmd); ++ install_element(ENABLE_NODE, &no_debug_igmp_trace_cmd); + install_element(CONFIG_NODE, &no_debug_igmp_trace_cmd); ++ install_element(ENABLE_NODE, &debug_igmp_trace_detail_cmd); + install_element(CONFIG_NODE, &debug_igmp_trace_detail_cmd); ++ install_element(ENABLE_NODE, &no_debug_igmp_trace_detail_cmd); + install_element(CONFIG_NODE, &no_debug_igmp_trace_detail_cmd); ++ install_element(ENABLE_NODE, &debug_mroute_cmd); + install_element(CONFIG_NODE, &debug_mroute_cmd); ++ install_element(ENABLE_NODE, &debug_mroute_detail_cmd); + install_element(CONFIG_NODE, &debug_mroute_detail_cmd); ++ install_element(ENABLE_NODE, &no_debug_mroute_cmd); + install_element(CONFIG_NODE, &no_debug_mroute_cmd); ++ install_element(ENABLE_NODE, &no_debug_mroute_detail_cmd); + install_element(CONFIG_NODE, &no_debug_mroute_detail_cmd); ++ install_element(ENABLE_NODE, &debug_pim_static_cmd); + install_element(CONFIG_NODE, &debug_pim_static_cmd); ++ install_element(ENABLE_NODE, &no_debug_pim_static_cmd); + install_element(CONFIG_NODE, &no_debug_pim_static_cmd); ++ install_element(ENABLE_NODE, &debug_pim_cmd); + install_element(CONFIG_NODE, &debug_pim_cmd); ++ install_element(ENABLE_NODE, &debug_pim_nht_cmd); + install_element(CONFIG_NODE, &debug_pim_nht_cmd); ++ install_element(ENABLE_NODE, &debug_pim_nht_det_cmd); + install_element(CONFIG_NODE, &debug_pim_nht_det_cmd); ++ install_element(ENABLE_NODE, &debug_pim_nht_rp_cmd); + install_element(CONFIG_NODE, &debug_pim_nht_rp_cmd); ++ install_element(ENABLE_NODE, &no_debug_pim_nht_rp_cmd); + install_element(CONFIG_NODE, &no_debug_pim_nht_rp_cmd); ++ install_element(ENABLE_NODE, &debug_pim_events_cmd); + install_element(CONFIG_NODE, &debug_pim_events_cmd); ++ install_element(ENABLE_NODE, &debug_pim_packets_cmd); + install_element(CONFIG_NODE, &debug_pim_packets_cmd); ++ install_element(ENABLE_NODE, &debug_pim_packetdump_send_cmd); + install_element(CONFIG_NODE, &debug_pim_packetdump_send_cmd); ++ install_element(ENABLE_NODE, &debug_pim_packetdump_recv_cmd); + install_element(CONFIG_NODE, &debug_pim_packetdump_recv_cmd); ++ install_element(ENABLE_NODE, &debug_pim_trace_cmd); + install_element(CONFIG_NODE, &debug_pim_trace_cmd); ++ install_element(ENABLE_NODE, &debug_pim_trace_detail_cmd); + install_element(CONFIG_NODE, &debug_pim_trace_detail_cmd); ++ install_element(ENABLE_NODE, &debug_ssmpingd_cmd); + install_element(CONFIG_NODE, &debug_ssmpingd_cmd); ++ install_element(ENABLE_NODE, &no_debug_ssmpingd_cmd); + install_element(CONFIG_NODE, &no_debug_ssmpingd_cmd); ++ install_element(ENABLE_NODE, &debug_pim_zebra_cmd); + install_element(CONFIG_NODE, &debug_pim_zebra_cmd); ++ install_element(ENABLE_NODE, &debug_pim_mlag_cmd); + install_element(CONFIG_NODE, &debug_pim_mlag_cmd); ++ install_element(ENABLE_NODE, &no_debug_pim_mlag_cmd); + install_element(CONFIG_NODE, &no_debug_pim_mlag_cmd); ++ install_element(ENABLE_NODE, &debug_pim_vxlan_cmd); + install_element(CONFIG_NODE, &debug_pim_vxlan_cmd); ++ install_element(ENABLE_NODE, &no_debug_pim_vxlan_cmd); + install_element(CONFIG_NODE, &no_debug_pim_vxlan_cmd); ++ install_element(ENABLE_NODE, &debug_msdp_cmd); + install_element(CONFIG_NODE, &debug_msdp_cmd); ++ install_element(ENABLE_NODE, &no_debug_msdp_cmd); + install_element(CONFIG_NODE, &no_debug_msdp_cmd); ++ install_element(ENABLE_NODE, &debug_msdp_events_cmd); + install_element(CONFIG_NODE, &debug_msdp_events_cmd); ++ install_element(ENABLE_NODE, &no_debug_msdp_events_cmd); + install_element(CONFIG_NODE, &no_debug_msdp_events_cmd); ++ install_element(ENABLE_NODE, &debug_msdp_packets_cmd); + install_element(CONFIG_NODE, &debug_msdp_packets_cmd); ++ install_element(ENABLE_NODE, &no_debug_msdp_packets_cmd); + install_element(CONFIG_NODE, &no_debug_msdp_packets_cmd); ++ install_element(ENABLE_NODE, &debug_mtrace_cmd); + install_element(CONFIG_NODE, &debug_mtrace_cmd); ++ install_element(ENABLE_NODE, &no_debug_mtrace_cmd); + install_element(CONFIG_NODE, &no_debug_mtrace_cmd); ++ install_element(ENABLE_NODE, &debug_bsm_cmd); + install_element(CONFIG_NODE, &debug_bsm_cmd); ++ install_element(ENABLE_NODE, &no_debug_bsm_cmd); + install_element(CONFIG_NODE, &no_debug_bsm_cmd); + +- install_element(CONFIG_NODE, &ip_msdp_timers_cmd); +- install_element(VRF_NODE, &ip_msdp_timers_cmd); +- install_element(CONFIG_NODE, &no_ip_msdp_timers_cmd); +- install_element(VRF_NODE, &no_ip_msdp_timers_cmd); +- install_element(CONFIG_NODE, &ip_msdp_mesh_group_member_cmd); +- install_element(VRF_NODE, &ip_msdp_mesh_group_member_cmd); +- install_element(CONFIG_NODE, &no_ip_msdp_mesh_group_member_cmd); +- install_element(VRF_NODE, &no_ip_msdp_mesh_group_member_cmd); +- install_element(CONFIG_NODE, &ip_msdp_mesh_group_source_cmd); +- install_element(VRF_NODE, &ip_msdp_mesh_group_source_cmd); +- install_element(CONFIG_NODE, &no_ip_msdp_mesh_group_source_cmd); +- install_element(VRF_NODE, &no_ip_msdp_mesh_group_source_cmd); +- install_element(CONFIG_NODE, &no_ip_msdp_mesh_group_cmd); +- install_element(VRF_NODE, &no_ip_msdp_mesh_group_cmd); +- install_element(VIEW_NODE, &show_ip_msdp_peer_detail_cmd); +- install_element(VIEW_NODE, &show_ip_msdp_peer_detail_vrf_all_cmd); +- install_element(VIEW_NODE, &show_ip_msdp_sa_detail_cmd); +- install_element(VIEW_NODE, &show_ip_msdp_sa_detail_vrf_all_cmd); +- install_element(VIEW_NODE, &show_ip_msdp_sa_sg_cmd); +- install_element(VIEW_NODE, &show_ip_msdp_sa_sg_vrf_all_cmd); +- install_element(VIEW_NODE, &show_ip_msdp_mesh_group_cmd); +- install_element(VIEW_NODE, &show_ip_msdp_mesh_group_vrf_all_cmd); +- install_element(VIEW_NODE, &show_ip_pim_ssm_range_cmd); +- install_element(VIEW_NODE, &show_ip_pim_group_type_cmd); +- install_element(VIEW_NODE, &show_ip_pim_vxlan_sg_cmd); +- install_element(VIEW_NODE, &show_ip_pim_vxlan_sg_work_cmd); +- install_element(INTERFACE_NODE, &interface_pim_use_source_cmd); +- install_element(INTERFACE_NODE, &interface_no_pim_use_source_cmd); +- /* Install BSM command */ +- install_element(INTERFACE_NODE, &ip_pim_bsm_cmd); +- install_element(INTERFACE_NODE, &no_ip_pim_bsm_cmd); +- install_element(INTERFACE_NODE, &ip_pim_ucast_bsm_cmd); +- install_element(INTERFACE_NODE, &no_ip_pim_ucast_bsm_cmd); +- /* Install BFD command */ +- install_element(INTERFACE_NODE, &ip_pim_bfd_cmd); +- install_element(INTERFACE_NODE, &ip_pim_bfd_param_cmd); +- install_element(INTERFACE_NODE, &no_ip_pim_bfd_profile_cmd); +- install_element(INTERFACE_NODE, &no_ip_pim_bfd_cmd); +-#if HAVE_BFDD == 0 +- install_element(INTERFACE_NODE, &no_ip_pim_bfd_param_cmd); +-#endif /* !HAVE_BFDD */ ++ install_element(CONFIG_NODE, &ip_igmp_group_watermark_cmd); ++ install_element(VRF_NODE, &ip_igmp_group_watermark_cmd); ++ install_element(CONFIG_NODE, &no_ip_igmp_group_watermark_cmd); ++ install_element(VRF_NODE, &no_ip_igmp_group_watermark_cmd); ++ ++ pim_install_deprecated(); + } +diff --git a/pimd/pim_cmd_common.c b/pimd/pim_cmd_common.c +index 5e50a09355cf..c6cb28c097b9 100644 +--- a/pimd/pim_cmd_common.c ++++ b/pimd/pim_cmd_common.c +@@ -100,25 +100,13 @@ int pim_process_no_join_prune_cmd(struct vty *vty) + + int pim_process_spt_switchover_infinity_cmd(struct vty *vty) + { +- const char *vrfname; + char spt_plist_xpath[XPATH_MAXLEN]; + char spt_action_xpath[XPATH_MAXLEN]; + +- vrfname = pim_cli_get_vrf_name(vty); +- if (vrfname == NULL) +- return CMD_WARNING_CONFIG_FAILED; +- + snprintf(spt_plist_xpath, sizeof(spt_plist_xpath), +- FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname, +- FRR_PIM_AF_XPATH_VAL); +- strlcat(spt_plist_xpath, "/spt-switchover/spt-infinity-prefix-list", +- sizeof(spt_plist_xpath)); +- ++ "%s/spt-switchover/spt-infinity-prefix-list", VTY_CURR_XPATH); + snprintf(spt_action_xpath, sizeof(spt_action_xpath), +- FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname, +- FRR_PIM_AF_XPATH_VAL); +- strlcat(spt_action_xpath, "/spt-switchover/spt-action", +- sizeof(spt_action_xpath)); ++ "%s/spt-switchover/spt-action", VTY_CURR_XPATH); + + if (yang_dnode_exists(vty->candidate_config->dnode, spt_plist_xpath)) + nb_cli_enqueue_change(vty, spt_plist_xpath, NB_OP_DESTROY, +@@ -132,55 +120,30 @@ int pim_process_spt_switchover_infinity_cmd(struct vty *vty) + int pim_process_spt_switchover_prefixlist_cmd(struct vty *vty, + const char *plist) + { +- const char *vrfname; + char spt_plist_xpath[XPATH_MAXLEN]; + char spt_action_xpath[XPATH_MAXLEN]; + +- vrfname = pim_cli_get_vrf_name(vty); +- if (vrfname == NULL) +- return CMD_WARNING_CONFIG_FAILED; +- + snprintf(spt_plist_xpath, sizeof(spt_plist_xpath), +- FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname, +- FRR_PIM_AF_XPATH_VAL); +- strlcat(spt_plist_xpath, "/spt-switchover/spt-infinity-prefix-list", +- sizeof(spt_plist_xpath)); +- ++ "./spt-switchover/spt-infinity-prefix-list"); + snprintf(spt_action_xpath, sizeof(spt_action_xpath), +- FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname, +- FRR_PIM_AF_XPATH_VAL); +- strlcat(spt_action_xpath, "/spt-switchover/spt-action", +- sizeof(spt_action_xpath)); ++ "./spt-switchover/spt-action"); + + 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, +- plist); ++ nb_cli_enqueue_change(vty, spt_plist_xpath, NB_OP_MODIFY, plist); + + return nb_cli_apply_changes(vty, NULL); + } + + int pim_process_no_spt_switchover_cmd(struct vty *vty) + { +- const char *vrfname; + char spt_plist_xpath[XPATH_MAXLEN]; + char spt_action_xpath[XPATH_MAXLEN]; + +- vrfname = pim_cli_get_vrf_name(vty); +- if (vrfname == NULL) +- return CMD_WARNING_CONFIG_FAILED; +- + snprintf(spt_plist_xpath, sizeof(spt_plist_xpath), +- FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname, +- FRR_PIM_AF_XPATH_VAL); +- strlcat(spt_plist_xpath, "/spt-switchover/spt-infinity-prefix-list", +- sizeof(spt_plist_xpath)); +- ++ "./spt-switchover/spt-infinity-prefix-list"); + snprintf(spt_action_xpath, sizeof(spt_action_xpath), +- FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname, +- FRR_PIM_AF_XPATH_VAL); +- strlcat(spt_action_xpath, "/spt-switchover/spt-action", +- sizeof(spt_action_xpath)); ++ "./spt-switchover/spt-action"); + + nb_cli_enqueue_change(vty, spt_plist_xpath, NB_OP_DESTROY, NULL); + nb_cli_enqueue_change(vty, spt_action_xpath, NB_OP_MODIFY, +@@ -217,35 +180,20 @@ int pim_process_no_pim_packet_cmd(struct vty *vty) + + int pim_process_keepalivetimer_cmd(struct vty *vty, const char *kat) + { +- const char *vrfname; + char ka_timer_xpath[XPATH_MAXLEN]; + +- vrfname = pim_cli_get_vrf_name(vty); +- if (vrfname == NULL) +- return CMD_WARNING_CONFIG_FAILED; +- +- snprintf(ka_timer_xpath, sizeof(ka_timer_xpath), FRR_PIM_VRF_XPATH, +- "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); +- strlcat(ka_timer_xpath, "/keep-alive-timer", sizeof(ka_timer_xpath)); ++ snprintf(ka_timer_xpath, sizeof(ka_timer_xpath), "./keep-alive-timer"); + +- nb_cli_enqueue_change(vty, ka_timer_xpath, NB_OP_MODIFY, +- kat); ++ nb_cli_enqueue_change(vty, ka_timer_xpath, NB_OP_MODIFY, kat); + + return nb_cli_apply_changes(vty, NULL); + } + + int pim_process_no_keepalivetimer_cmd(struct vty *vty) + { +- const char *vrfname; + char ka_timer_xpath[XPATH_MAXLEN]; + +- vrfname = pim_cli_get_vrf_name(vty); +- if (vrfname == NULL) +- return CMD_WARNING_CONFIG_FAILED; +- +- snprintf(ka_timer_xpath, sizeof(ka_timer_xpath), FRR_PIM_VRF_XPATH, +- "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); +- strlcat(ka_timer_xpath, "/keep-alive-timer", sizeof(ka_timer_xpath)); ++ snprintf(ka_timer_xpath, sizeof(ka_timer_xpath), "./keep-alive-timer"); + + nb_cli_enqueue_change(vty, ka_timer_xpath, NB_OP_DESTROY, NULL); + +@@ -254,35 +202,25 @@ int pim_process_no_keepalivetimer_cmd(struct vty *vty) + + int pim_process_rp_kat_cmd(struct vty *vty, const char *rpkat) + { +- const char *vrfname; + char rp_ka_timer_xpath[XPATH_MAXLEN]; + +- vrfname = pim_cli_get_vrf_name(vty); +- if (vrfname == NULL) +- return CMD_WARNING_CONFIG_FAILED; +- + snprintf(rp_ka_timer_xpath, sizeof(rp_ka_timer_xpath), +- FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname, +- FRR_PIM_AF_XPATH_VAL); +- strlcat(rp_ka_timer_xpath, "/rp-keep-alive-timer", +- sizeof(rp_ka_timer_xpath)); ++ "./rp-keep-alive-timer"); + +- nb_cli_enqueue_change(vty, rp_ka_timer_xpath, NB_OP_MODIFY, +- rpkat); ++ nb_cli_enqueue_change(vty, rp_ka_timer_xpath, NB_OP_MODIFY, rpkat); + + return nb_cli_apply_changes(vty, NULL); + } + + int pim_process_no_rp_kat_cmd(struct vty *vty) + { +- const char *vrfname; + char rp_ka_timer[6]; + char rp_ka_timer_xpath[XPATH_MAXLEN]; + uint v; + char rs_timer_xpath[XPATH_MAXLEN]; + +- snprintf(rs_timer_xpath, sizeof(rs_timer_xpath), +- FRR_PIM_ROUTER_XPATH, FRR_PIM_AF_XPATH_VAL); ++ snprintf(rs_timer_xpath, sizeof(rs_timer_xpath), FRR_PIM_ROUTER_XPATH, ++ FRR_PIM_AF_XPATH_VAL); + strlcat(rs_timer_xpath, "/register-suppress-time", + sizeof(rs_timer_xpath)); + +@@ -301,18 +239,10 @@ int pim_process_no_rp_kat_cmd(struct vty *vty) + v = UINT16_MAX; + snprintf(rp_ka_timer, sizeof(rp_ka_timer), "%u", v); + +- vrfname = pim_cli_get_vrf_name(vty); +- if (vrfname == NULL) +- return CMD_WARNING_CONFIG_FAILED; +- + snprintf(rp_ka_timer_xpath, sizeof(rp_ka_timer_xpath), +- FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname, +- FRR_PIM_AF_XPATH_VAL); +- strlcat(rp_ka_timer_xpath, "/rp-keep-alive-timer", +- sizeof(rp_ka_timer_xpath)); ++ "./rp-keep-alive-timer"); + +- nb_cli_enqueue_change(vty, rp_ka_timer_xpath, NB_OP_MODIFY, +- rp_ka_timer); ++ nb_cli_enqueue_change(vty, rp_ka_timer_xpath, NB_OP_MODIFY, rp_ka_timer); + + return nb_cli_apply_changes(vty, NULL); + } +@@ -531,9 +461,7 @@ int pim_process_no_ip_mroute_cmd(struct vty *vty, const char *interface, + int pim_process_rp_cmd(struct vty *vty, const char *rp_str, + const char *group_str) + { +- const char *vrfname; + char group_xpath[XPATH_MAXLEN]; +- char rp_xpath[XPATH_MAXLEN]; + int printed; + int result = 0; + struct prefix group; +@@ -575,14 +503,9 @@ int pim_process_rp_cmd(struct vty *vty, const char *rp_str, + } + #endif + +- vrfname = pim_cli_get_vrf_name(vty); +- if (vrfname == NULL) +- return CMD_WARNING_CONFIG_FAILED; +- +- snprintf(rp_xpath, sizeof(rp_xpath), FRR_PIM_STATIC_RP_XPATH, +- "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL, rp_str); + printed = snprintf(group_xpath, sizeof(group_xpath), +- "%s/group-list[.='%s']", rp_xpath, group_str); ++ "./" FRR_PIM_STATIC_RP_XPATH "/group-list[.='%s']", ++ rp_str, group_str); + + if (printed >= (int)(sizeof(group_xpath))) { + vty_out(vty, "Xpath too long (%d > %u)", printed + 1, +@@ -601,15 +524,10 @@ int pim_process_no_rp_cmd(struct vty *vty, const char *rp_str, + char group_xpath[XPATH_MAXLEN]; + char rp_xpath[XPATH_MAXLEN]; + int printed; +- const char *vrfname; + const struct lyd_node *group_dnode; + +- vrfname = pim_cli_get_vrf_name(vty); +- if (vrfname == NULL) +- return CMD_WARNING_CONFIG_FAILED; +- +- snprintf(rp_xpath, sizeof(rp_xpath), FRR_PIM_STATIC_RP_XPATH, +- "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL, rp_str); ++ snprintf(rp_xpath, sizeof(rp_xpath), "%s/" FRR_PIM_STATIC_RP_XPATH, ++ VTY_CURR_XPATH, rp_str); + printed = snprintf(group_xpath, sizeof(group_xpath), + "%s/group-list[.='%s']", rp_xpath, group_str); + +@@ -636,16 +554,10 @@ int pim_process_no_rp_cmd(struct vty *vty, const char *rp_str, + int pim_process_rp_plist_cmd(struct vty *vty, const char *rp_str, + const char *prefix_list) + { +- const char *vrfname; + char rp_plist_xpath[XPATH_MAXLEN]; + +- vrfname = pim_cli_get_vrf_name(vty); +- if (vrfname == NULL) +- return CMD_WARNING_CONFIG_FAILED; +- + snprintf(rp_plist_xpath, sizeof(rp_plist_xpath), +- FRR_PIM_STATIC_RP_XPATH, "frr-pim:pimd", "pim", vrfname, +- FRR_PIM_AF_XPATH_VAL, rp_str); ++ "./" FRR_PIM_STATIC_RP_XPATH, rp_str); + strlcat(rp_plist_xpath, "/prefix-list", sizeof(rp_plist_xpath)); + + nb_cli_enqueue_change(vty, rp_plist_xpath, NB_OP_MODIFY, prefix_list); +@@ -658,19 +570,12 @@ int pim_process_no_rp_plist_cmd(struct vty *vty, const char *rp_str, + { + char rp_xpath[XPATH_MAXLEN]; + char plist_xpath[XPATH_MAXLEN]; +- const char *vrfname; + const struct lyd_node *plist_dnode; + const char *plist; + +- vrfname = pim_cli_get_vrf_name(vty); +- if (vrfname == NULL) +- return CMD_WARNING_CONFIG_FAILED; +- +- snprintf(rp_xpath, sizeof(rp_xpath), FRR_PIM_STATIC_RP_XPATH, +- "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL, rp_str); +- +- snprintf(plist_xpath, sizeof(plist_xpath), FRR_PIM_STATIC_RP_XPATH, +- "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL, rp_str); ++ snprintf(rp_xpath, sizeof(rp_xpath), "%s/" FRR_PIM_STATIC_RP_XPATH, ++ VTY_CURR_XPATH, rp_str); ++ snprintf(plist_xpath, sizeof(plist_xpath), "%s", rp_xpath); + strlcat(plist_xpath, "/prefix-list", sizeof(plist_xpath)); + + plist_dnode = yang_dnode_get(vty->candidate_config->dnode, plist_xpath); +@@ -679,7 +584,7 @@ int pim_process_no_rp_plist_cmd(struct vty *vty, const char *rp_str, + return NB_OK; + } + +- plist = yang_dnode_get_string(plist_dnode, "%s", plist_xpath); ++ plist = yang_dnode_get_string(plist_dnode, NULL); + if (strcmp(prefix_list, plist)) { + vty_out(vty, "%% Unable to find specified RP\n"); + return NB_OK; +@@ -3408,21 +3313,11 @@ int gm_process_no_last_member_query_interval_cmd(struct vty *vty) + int pim_process_ssmpingd_cmd(struct vty *vty, enum nb_operation operation, + const char *src_str) + { +- const char *vrfname; +- char ssmpingd_ip_xpath[XPATH_MAXLEN]; + char ssmpingd_src_ip_xpath[XPATH_MAXLEN]; + int printed; + +- vrfname = pim_cli_get_vrf_name(vty); +- if (vrfname == NULL) +- return CMD_WARNING_CONFIG_FAILED; +- +- snprintf(ssmpingd_ip_xpath, sizeof(ssmpingd_ip_xpath), +- FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname, +- FRR_PIM_AF_XPATH_VAL); + printed = snprintf(ssmpingd_src_ip_xpath, sizeof(ssmpingd_src_ip_xpath), +- "%s/ssm-pingd-source-ip[.='%s']", ssmpingd_ip_xpath, +- src_str); ++ "./ssm-pingd-source-ip[.='%s']", src_str); + if (printed >= (int)sizeof(ssmpingd_src_ip_xpath)) { + vty_out(vty, "Xpath too long (%d > %u)", printed + 1, + XPATH_MAXLEN); +@@ -5705,3 +5600,34 @@ int pim_show_bsm_db_helper(const char *vrf, struct vty *vty, bool uj) + + return CMD_SUCCESS; + } ++ ++int pim_router_config_write(struct vty *vty) ++{ ++ struct vrf *vrf; ++ struct pim_instance *pim; ++ int writes = 0; ++ char framestr[64] = { 0 }; ++ ++ RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { ++ pim = vrf->info; ++ ++ if (!pim) ++ continue; ++ ++ snprintfrr(framestr, sizeof(framestr), "router %s", ++ PIM_AF_ROUTER); ++ if (vrf->vrf_id != VRF_DEFAULT) { ++ strlcat(framestr, " vrf ", sizeof(framestr)); ++ strlcat(framestr, vrf->name, sizeof(framestr)); ++ } ++ vty_frame(vty, "%s\n", framestr); ++ ++writes; ++ ++ writes += pim_global_config_write_worker(pim, vty); ++ ++ vty_endframe(vty, "exit\n"); ++ ++writes; ++ } ++ ++ return writes; ++} +diff --git a/pimd/pim_cmd_common.h b/pimd/pim_cmd_common.h +index e30203fad75b..da2e44be585b 100644 +--- a/pimd/pim_cmd_common.h ++++ b/pimd/pim_cmd_common.h +@@ -182,6 +182,8 @@ int pim_show_interface_traffic_helper(const char *vrf, const char *if_name, + void clear_pim_interfaces(struct pim_instance *pim); + void pim_show_bsr(struct pim_instance *pim, struct vty *vty, bool uj); + int pim_show_bsr_helper(const char *vrf, struct vty *vty, bool uj); ++int pim_router_config_write(struct vty *vty); ++ + /* + * Special Macro to allow us to get the correct pim_instance; + */ +diff --git a/pimd/pim_instance.c b/pimd/pim_instance.c +index b3410d15af72..a9eec9a9d25b 100644 +--- a/pimd/pim_instance.c ++++ b/pimd/pim_instance.c +@@ -201,6 +201,7 @@ static int pim_vrf_config_write(struct vty *vty) + { + struct vrf *vrf; + struct pim_instance *pim; ++ char spaces[10]; + + RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { + pim = vrf->info; +@@ -208,10 +209,24 @@ static int pim_vrf_config_write(struct vty *vty) + if (!pim) + continue; + +- if (vrf->vrf_id != VRF_DEFAULT) ++ if (vrf->vrf_id != VRF_DEFAULT) { + vty_frame(vty, "vrf %s\n", vrf->name); +- +- pim_global_config_write_worker(pim, vty); ++ snprintf(spaces, sizeof(spaces), "%s", " "); ++ } else { ++ snprintf(spaces, sizeof(spaces), "%s", ""); ++ } ++ ++ /* Global IGMP/MLD configuration */ ++ if (pim->gm_watermark_limit != 0) { ++#if PIM_IPV == 4 ++ vty_out(vty, ++ "%s" PIM_AF_NAME " igmp watermark-warn %u\n", ++ spaces, pim->gm_watermark_limit); ++#else ++ vty_out(vty, "%s" PIM_AF_NAME " mld watermark-warn %u\n", ++ spaces, pim->gm_watermark_limit); ++#endif ++ } + + if (vrf->vrf_id != VRF_DEFAULT) + vty_endframe(vty, "exit-vrf\n!\n"); +diff --git a/pimd/pim_msdp.c b/pimd/pim_msdp.c +index 623c14bb0391..04b4d296ddbc 100644 +--- a/pimd/pim_msdp.c ++++ b/pimd/pim_msdp.c +@@ -1276,8 +1276,7 @@ static void pim_msdp_src_del(struct pim_msdp_mg *mg) + } + + /*********************** MSDP feature APIs *********************************/ +-int pim_msdp_config_write(struct pim_instance *pim, struct vty *vty, +- const char *spaces) ++int pim_msdp_config_write(struct pim_instance *pim, struct vty *vty) + { + struct pim_msdp_mg *mg; + struct listnode *mbrnode; +@@ -1292,14 +1291,14 @@ int pim_msdp_config_write(struct pim_instance *pim, struct vty *vty, + if (mg->src_ip.s_addr != INADDR_ANY) { + pim_inet4_dump("", mg->src_ip, src_str, + sizeof(src_str)); +- vty_out(vty, "%sip msdp mesh-group %s source %s\n", +- spaces, mg->mesh_group_name, src_str); ++ vty_out(vty, " msdp mesh-group %s source %s\n", ++ mg->mesh_group_name, src_str); + ++count; + } + + for (ALL_LIST_ELEMENTS_RO(mg->mbr_list, mbrnode, mbr)) { +- vty_out(vty, "%sip msdp mesh-group %s member %pI4\n", +- spaces, mg->mesh_group_name, &mbr->mbr_ip); ++ vty_out(vty, " msdp mesh-group %s member %pI4\n", ++ mg->mesh_group_name, &mbr->mbr_ip); + ++count; + } + } +@@ -1307,8 +1306,7 @@ int pim_msdp_config_write(struct pim_instance *pim, struct vty *vty, + return count; + } + +-bool pim_msdp_peer_config_write(struct vty *vty, struct pim_instance *pim, +- const char *spaces) ++bool pim_msdp_peer_config_write(struct vty *vty, struct pim_instance *pim) + { + struct pim_msdp_peer *mp; + struct listnode *node; +@@ -1319,8 +1317,8 @@ bool pim_msdp_peer_config_write(struct vty *vty, struct pim_instance *pim, + if (mp->flags & PIM_MSDP_PEERF_IN_GROUP) + continue; + +- vty_out(vty, "%sip msdp peer %pI4 source %pI4\n", spaces, +- &mp->peer, &mp->local); ++ vty_out(vty, " msdp peer %pI4 source %pI4\n", &mp->peer, ++ &mp->local); + written = true; + } + +diff --git a/pimd/pim_msdp.h b/pimd/pim_msdp.h +index ddc015f9b62b..80ca003dc595 100644 +--- a/pimd/pim_msdp.h ++++ b/pimd/pim_msdp.h +@@ -228,10 +228,8 @@ void pim_msdp_peer_pkt_rxed(struct pim_msdp_peer *mp); + void pim_msdp_peer_stop_tcp_conn(struct pim_msdp_peer *mp, bool chg_state); + void pim_msdp_peer_reset_tcp_conn(struct pim_msdp_peer *mp, const char *rc_str); + void pim_msdp_write(struct event *thread); +-int pim_msdp_config_write(struct pim_instance *pim, struct vty *vty, +- const char *spaces); +-bool pim_msdp_peer_config_write(struct vty *vty, struct pim_instance *pim, +- const char *spaces); ++int pim_msdp_config_write(struct pim_instance *pim, struct vty *vty); ++bool pim_msdp_peer_config_write(struct vty *vty, struct pim_instance *pim); + void pim_msdp_peer_pkt_txed(struct pim_msdp_peer *mp); + void pim_msdp_sa_ref(struct pim_instance *pim, struct pim_msdp_peer *mp, + pim_sgaddr *sg, struct in_addr rp); +@@ -339,14 +337,13 @@ static inline void pim_msdp_sa_local_del(struct pim_instance *pim, + } + + static inline int pim_msdp_config_write(struct pim_instance *pim, +- struct vty *vty, const char *spaces) ++ struct vty *vty) + { + return 0; + } + + static inline bool pim_msdp_peer_config_write(struct vty *vty, +- struct pim_instance *pim, +- const char *spaces) ++ struct pim_instance *pim) + { + return false; + } +diff --git a/pimd/pim_nb.h b/pimd/pim_nb.h +index 0321d076f0da..2d854d73de5e 100644 +--- a/pimd/pim_nb.h ++++ b/pimd/pim_nb.h +@@ -207,9 +207,6 @@ int routing_control_plane_protocols_name_validate( + "./frr-pim:pim/address-family[address-family='%s']/" \ + "mroute[source-addr='%s'][group-addr='%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_GMP_INTERFACE_XPATH \ + "./frr-gmp:gmp/address-family[address-family='%s']" +@@ -218,6 +215,5 @@ int routing_control_plane_protocols_name_validate( + #define FRR_GMP_JOIN_XPATH \ + "./frr-gmp:gmp/address-family[address-family='%s']/" \ + "static-group[group-addr='%s'][source-addr='%s']" +-#define FRR_PIM_MSDP_XPATH FRR_PIM_VRF_XPATH "/msdp" + + #endif /* _FRR_PIM_NB_H_ */ +diff --git a/pimd/pim_rp.c b/pimd/pim_rp.c +index 49be9c0a7339..0f8940bb16d7 100644 +--- a/pimd/pim_rp.c ++++ b/pimd/pim_rp.c +@@ -1129,8 +1129,7 @@ int pim_rp_set_upstream_addr(struct pim_instance *pim, pim_addr *up, + return 1; + } + +-int pim_rp_config_write(struct pim_instance *pim, struct vty *vty, +- const char *spaces) ++int pim_rp_config_write(struct pim_instance *pim, struct vty *vty) + { + struct listnode *node; + struct rp_info *rp_info; +@@ -1146,13 +1145,11 @@ int pim_rp_config_write(struct pim_instance *pim, struct vty *vty, + + rp_addr = rp_info->rp.rpf_addr; + if (rp_info->plist) +- vty_out(vty, +- "%s" PIM_AF_NAME +- " pim rp %pPA prefix-list %s\n", +- spaces, &rp_addr, rp_info->plist); ++ vty_out(vty, " rp %pPA prefix-list %s\n", &rp_addr, ++ rp_info->plist); + else +- vty_out(vty, "%s" PIM_AF_NAME " pim rp %pPA %pFX\n", +- spaces, &rp_addr, &rp_info->group); ++ vty_out(vty, " rp %pPA %pFX\n", &rp_addr, ++ &rp_info->group); + count++; + } + +diff --git a/pimd/pim_rp.h b/pimd/pim_rp.h +index 9416a9a8a87e..32c6306740d6 100644 +--- a/pimd/pim_rp.h ++++ b/pimd/pim_rp.h +@@ -46,8 +46,7 @@ int pim_rp_change(struct pim_instance *pim, pim_addr new_rp_addr, + void pim_rp_prefix_list_update(struct pim_instance *pim, + struct prefix_list *plist); + +-int pim_rp_config_write(struct pim_instance *pim, struct vty *vty, +- const char *spaces); ++int pim_rp_config_write(struct pim_instance *pim, struct vty *vty); + + void pim_rp_setup(struct pim_instance *pim); + +diff --git a/pimd/pim_vty.c b/pimd/pim_vty.c +index 0f6547ee2e9a..1910a684957e 100644 +--- a/pimd/pim_vty.c ++++ b/pimd/pim_vty.c +@@ -172,89 +172,66 @@ int pim_global_config_write_worker(struct pim_instance *pim, struct vty *vty) + { + int writes = 0; + struct pim_ssm *ssm = pim->ssm_info; +- char spaces[10]; + +- if (pim->vrf->vrf_id == VRF_DEFAULT) +- snprintf(spaces, sizeof(spaces), "%s", ""); +- else +- snprintf(spaces, sizeof(spaces), "%s", " "); +- +- writes += pim_msdp_peer_config_write(vty, pim, spaces); +- writes += pim_msdp_config_write(pim, vty, spaces); ++ writes += pim_msdp_peer_config_write(vty, pim); ++ writes += pim_msdp_config_write(pim, vty); + + if (!pim->send_v6_secondary) { +- vty_out(vty, "%sno ip pim send-v6-secondary\n", spaces); ++ vty_out(vty, " no send-v6-secondary\n"); + ++writes; + } + +- writes += pim_rp_config_write(pim, vty, spaces); ++ writes += pim_rp_config_write(pim, vty); + + if (pim->vrf->vrf_id == VRF_DEFAULT) { + if (router->register_suppress_time + != PIM_REGISTER_SUPPRESSION_TIME_DEFAULT) { +- vty_out(vty, "%s" PIM_AF_NAME " pim register-suppress-time %d\n", +- spaces, router->register_suppress_time); ++ vty_out(vty, " register-suppress-time %d\n", ++ router->register_suppress_time); + ++writes; + } + if (router->t_periodic != PIM_DEFAULT_T_PERIODIC) { +- vty_out(vty, "%s" PIM_AF_NAME " pim join-prune-interval %d\n", +- spaces, router->t_periodic); ++ vty_out(vty, " join-prune-interval %d\n", ++ router->t_periodic); + ++writes; + } + + if (router->packet_process != PIM_DEFAULT_PACKET_PROCESS) { +- vty_out(vty, "%s" PIM_AF_NAME " pim packets %d\n", spaces, +- router->packet_process); ++ vty_out(vty, " packets %d\n", router->packet_process); + ++writes; + } + } + if (pim->keep_alive_time != PIM_KEEPALIVE_PERIOD) { +- vty_out(vty, "%s" PIM_AF_NAME " pim keep-alive-timer %d\n", +- spaces, pim->keep_alive_time); ++ vty_out(vty, " keep-alive-timer %d\n", pim->keep_alive_time); + ++writes; + } + if (pim->rp_keep_alive_time != (unsigned int)PIM_RP_KEEPALIVE_PERIOD) { +- vty_out(vty, "%s" PIM_AF_NAME " pim rp keep-alive-timer %d\n", +- spaces, pim->rp_keep_alive_time); ++ vty_out(vty, " rp keep-alive-timer %d\n", ++ pim->rp_keep_alive_time); + ++writes; + } + if (ssm->plist_name) { +- vty_out(vty, "%sip pim ssm prefix-list %s\n", spaces, +- ssm->plist_name); ++ vty_out(vty, " ssm prefix-list %s\n", ssm->plist_name); + ++writes; + } + if (pim->register_plist) { +- vty_out(vty, "%sip pim register-accept-list %s\n", spaces, +- pim->register_plist); ++ vty_out(vty, " register-accept-list %s\n", pim->register_plist); + ++writes; + } + if (pim->spt.switchover == PIM_SPT_INFINITY) { + if (pim->spt.plist) + vty_out(vty, +- "%s" PIM_AF_NAME " pim spt-switchover infinity-and-beyond prefix-list %s\n", +- spaces, pim->spt.plist); ++ " spt-switchover infinity-and-beyond prefix-list %s\n", ++ pim->spt.plist); + else +- vty_out(vty, +- "%s" PIM_AF_NAME " pim spt-switchover infinity-and-beyond\n", +- spaces); ++ vty_out(vty, " spt-switchover infinity-and-beyond\n"); + ++writes; + } + if (pim->ecmp_rebalance_enable) { +- vty_out(vty, "%sip pim ecmp rebalance\n", spaces); ++ vty_out(vty, " ecmp rebalance\n"); + ++writes; + } else if (pim->ecmp_enable) { +- vty_out(vty, "%sip pim ecmp\n", spaces); +- ++writes; +- } +- +- if (pim->gm_watermark_limit != 0) { +-#if PIM_IPV == 4 +- vty_out(vty, "%s" PIM_AF_NAME " igmp watermark-warn %u\n", +- spaces, pim->gm_watermark_limit); +-#else +- vty_out(vty, "%s" PIM_AF_NAME " mld watermark-warn %u\n", +- spaces, pim->gm_watermark_limit); +-#endif ++ vty_out(vty, " ecmp\n"); + ++writes; + } + +@@ -263,8 +240,7 @@ int pim_global_config_write_worker(struct pim_instance *pim, struct vty *vty) + struct ssmpingd_sock *ss; + ++writes; + for (ALL_LIST_ELEMENTS_RO(pim->ssmpingd_list, node, ss)) { +- vty_out(vty, "%s" PIM_AF_NAME " ssmpingd %pPA\n", +- spaces, &ss->source_addr); ++ vty_out(vty, " ssmpingd %pPA\n", &ss->source_addr); + ++writes; + } + } +@@ -272,8 +248,8 @@ int pim_global_config_write_worker(struct pim_instance *pim, struct vty *vty) + if (pim->msdp.hold_time != PIM_MSDP_PEER_HOLD_TIME + || pim->msdp.keep_alive != PIM_MSDP_PEER_KA_TIME + || pim->msdp.connection_retry != PIM_MSDP_PEER_CONNECT_RETRY_TIME) { +- vty_out(vty, "%sip msdp timers %u %u", spaces, +- pim->msdp.hold_time, pim->msdp.keep_alive); ++ vty_out(vty, " msdp timers %u %u", pim->msdp.hold_time, ++ pim->msdp.keep_alive); + if (pim->msdp.connection_retry + != PIM_MSDP_PEER_CONNECT_RETRY_TIME) + vty_out(vty, " %u", pim->msdp.connection_retry); +diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c +index 573320667c33..1f6dde83c148 100644 +--- a/vtysh/vtysh.c ++++ b/vtysh/vtysh.c +@@ -1677,6 +1677,24 @@ static struct cmd_node bfd_profile_node = { + }; + #endif /* HAVE_BFDD */ + ++#ifdef HAVE_PIMD ++static struct cmd_node pim_node = { ++ .name = "pim", ++ .node = PIM_NODE, ++ .parent_node = CONFIG_NODE, ++ .prompt = "%s(config-pim)# ", ++}; ++#endif /* HAVE_PIMD */ ++ ++#ifdef HAVE_PIM6D ++static struct cmd_node pim6_node = { ++ .name = "pim6", ++ .node = PIM6_NODE, ++ .parent_node = CONFIG_NODE, ++ .prompt = "%s(config-pim6)# ", ++}; ++#endif /* HAVE_PIM6D */ ++ + /* Defined in lib/vty.c */ + extern struct cmd_node vty_node; + +@@ -2413,6 +2431,30 @@ DEFUNSH(VTYSH_BFDD, bfd_profile_enter, bfd_profile_enter_cmd, + } + #endif /* HAVE_BFDD */ + ++#ifdef HAVE_PIMD ++DEFUNSH(VTYSH_PIMD, router_pim, router_pim_cmd, ++ "router pim [vrf NAME]", ++ ROUTER_STR ++ "Start PIM configuration\n" ++ VRF_CMD_HELP_STR) ++{ ++ vty->node = PIM_NODE; ++ return CMD_SUCCESS; ++} ++#endif /* HAVE_PIMD */ ++ ++#ifdef HAVE_PIM6D ++DEFUNSH(VTYSH_PIM6D, router_pim6, router_pim6_cmd, ++ "router pim6 [vrf NAME]", ++ ROUTER_STR ++ "Start PIMv6 configuration\n" ++ VRF_CMD_HELP_STR) ++{ ++ vty->node = PIM6_NODE; ++ return CMD_SUCCESS; ++} ++#endif /* HAVE_PIM6D*/ ++ + DEFUNSH(VTYSH_ALL, vtysh_line_vty, vtysh_line_vty_cmd, "line vty", + "Configure a terminal line\n" + "Virtual terminal\n") +@@ -2826,6 +2868,34 @@ DEFUNSH(VTYSH_PATHD, vtysh_quit_pathd, vtysh_quit_pathd_cmd, "quit", + } + #endif /* HAVE_PATHD */ + ++#ifdef HAVE_PIMD ++DEFUNSH(VTYSH_PIMD, vtysh_exit_pimd, vtysh_exit_pimd_cmd, "exit", ++ "Exit current mode and down to previous mode\n") ++{ ++ return vtysh_exit(vty); ++} ++ ++DEFUNSH(VTYSH_PIMD, vtysh_quit_pimd, vtysh_quit_pimd_cmd, "quit", ++ "Exit current mode and down to previous mode\n") ++{ ++ return vtysh_exit_pimd(self, vty, argc, argv); ++} ++#endif /* HAVE_PIMD */ ++ ++#ifdef HAVE_PIM6D ++DEFUNSH(VTYSH_PIM6D, vtysh_exit_pim6d, vtysh_exit_pim6d_cmd, "exit", ++ "Exit current mode and down to previous mode\n") ++{ ++ return vtysh_exit(vty); ++} ++ ++DEFUNSH(VTYSH_PIM6D, vtysh_quit_pim6d, vtysh_quit_pim6d_cmd, "quit", ++ "Exit current mode and down to previous mode\n") ++{ ++ return vtysh_exit_pim6d(self, vty, argc, argv); ++} ++#endif /* HAVE_PIM6D */ ++ + DEFUNSH(VTYSH_ALL, vtysh_exit_line_vty, vtysh_exit_line_vty_cmd, "exit", + "Exit current mode and down to previous mode\n") + { +@@ -5293,6 +5363,25 @@ void vtysh_init_vty(void) + install_element(INTERFACE_NODE, &vtysh_exit_interface_cmd); + install_element(INTERFACE_NODE, &vtysh_quit_interface_cmd); + ++ /* pimd */ ++#ifdef HAVE_PIMD ++ install_node(&pim_node); ++ install_element(CONFIG_NODE, &router_pim_cmd); ++ install_element(PIM_NODE, &vtysh_exit_pimd_cmd); ++ install_element(PIM_NODE, &vtysh_quit_pimd_cmd); ++ install_element(PIM_NODE, &vtysh_end_all_cmd); ++#endif /* HAVE_PIMD */ ++ ++ /* pim6d */ ++#ifdef HAVE_PIM6D ++ install_node(&pim6_node); ++ install_element(CONFIG_NODE, &router_pim6_cmd); ++ install_element(PIM6_NODE, &vtysh_exit_pim6d_cmd); ++ install_element(PIM6_NODE, &vtysh_quit_pim6d_cmd); ++ install_element(PIM6_NODE, &vtysh_end_all_cmd); ++#endif /* HAVE_PIM6D */ ++ ++ /* zebra and all, cont. */ + install_node(&link_params_node); + install_element(INTERFACE_NODE, &vtysh_link_params_cmd); + install_element(LINK_PARAMS_NODE, &no_link_params_enable_cmd); +diff --git a/vtysh/vtysh_config.c b/vtysh/vtysh_config.c +index c207e4d42759..8f7cd84818c6 100644 +--- a/vtysh/vtysh_config.c ++++ b/vtysh/vtysh_config.c +@@ -497,6 +497,11 @@ void vtysh_config_parse_line(void *arg, const char *line) + config = config_get(BFD_NODE, line); + else if (strncmp(line, "rpki", strlen("rpki")) == 0) + config = config_get(RPKI_NODE, line); ++ else if (strncmp(line, "router pim", strlen("router pim")) == 0) ++ config = config_get(PIM_NODE, line); ++ else if (strncmp(line, "router pim6", strlen("router pim6")) == ++ 0) ++ config = config_get(PIM6_NODE, line); + else { + if (strncmp(line, "log", strlen("log")) == 0 || + strncmp(line, "hostname", strlen("hostname")) == 0 || diff --git a/src/sonic-frr/patch/0078-vtysh-de-conditionalize-and-reorder-install-node.patch b/src/sonic-frr/patch/0078-vtysh-de-conditionalize-and-reorder-install-node.patch new file mode 100644 index 000000000000..b43906c8cc48 --- /dev/null +++ b/src/sonic-frr/patch/0078-vtysh-de-conditionalize-and-reorder-install-node.patch @@ -0,0 +1,790 @@ +From e26c580588b3689463c76aa96888147e53a48885 Mon Sep 17 00:00:00 2001 +From: David Lamparter +Date: Sat, 20 Jul 2024 18:30:31 -0700 +Subject: [PATCH] vtysh: de-conditionalize and reorder install_node + +There is entirely no point to these being conditional. And pull them up +so the upcoming pre-parse code can work on a clean slate. + +Signed-off-by: David Lamparter +--- + lib/command.h | 4 + + vtysh/vtysh.c | 182 ++++++++++++++++++--------------------------- + vtysh/vtysh_main.c | 1 - + 3 files changed, 78 insertions(+), 109 deletions(-) + +diff --git a/lib/command.h b/lib/command.h +index 57e3b9cda0b7..f364f1e8fa2a 100644 +--- a/lib/command.h ++++ b/lib/command.h +@@ -252,6 +252,8 @@ struct cmd_node { + /* Argc max counts. */ + #define CMD_ARGC_MAX 256 + ++/* clang-format off */ ++ + /* helper defines for end-user DEFUN* macros */ + #define DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, attrs, dnum) \ + static const struct cmd_element cmdname = { \ +@@ -376,6 +378,8 @@ struct cmd_node { + #define ALIAS_YANG(funcname, cmdname, cmdstr, helpstr) \ + ALIAS_ATTR(funcname, cmdname, cmdstr, helpstr, CMD_ATTR_YANG) + ++/* clang-format on */ ++ + /* Some macroes */ + + /* +diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c +index e657aa8af0ac..c43e1909e3e1 100644 +--- a/vtysh/vtysh.c ++++ b/vtysh/vtysh.c +@@ -1161,14 +1161,12 @@ static char **new_completion(const char *text, int start, int end) + } + + /* Vty node structures. */ +-#ifdef HAVE_BGPD + static struct cmd_node bgp_node = { + .name = "bgp", + .node = BGP_NODE, + .parent_node = CONFIG_NODE, + .prompt = "%s(config-router)# ", + }; +-#endif /* HAVE_BGPD */ + + static struct cmd_node rip_node = { + .name = "rip", +@@ -1177,7 +1175,6 @@ static struct cmd_node rip_node = { + .prompt = "%s(config-router)# ", + }; + +-#ifdef HAVE_ISISD + static struct cmd_node isis_node = { + .name = "isis", + .node = ISIS_NODE, +@@ -1205,16 +1202,13 @@ static struct cmd_node isis_srv6_node_msd_node = { + .parent_node = ISIS_SRV6_NODE, + .prompt = "%s(config-router-srv6-node-msd)# ", + }; +-#endif /* HAVE_ISISD */ + +-#ifdef HAVE_FABRICD + static struct cmd_node openfabric_node = { + .name = "openfabric", + .node = OPENFABRIC_NODE, + .parent_node = CONFIG_NODE, + .prompt = "%s(config-router)# ", + }; +-#endif /* HAVE_FABRICD */ + + static struct cmd_node interface_node = { + .name = "interface", +@@ -1237,7 +1231,6 @@ static struct cmd_node segment_routing_node = { + .prompt = "%s(config-sr)# ", + }; + +-#if defined(HAVE_PATHD) + static struct cmd_node sr_traffic_eng_node = { + .name = "sr traffic-eng", + .node = SR_TRAFFIC_ENG_NODE, +@@ -1293,7 +1286,6 @@ static struct cmd_node pcep_pce_config_node = { + .parent_node = PCEP_NODE, + .prompt = "%s(pcep-sr-te-pcep-pce-config)# ", + }; +-#endif /* HAVE_PATHD */ + + static struct cmd_node vrf_node = { + .name = "vrf", +@@ -1365,14 +1357,12 @@ static struct cmd_node srv6_sid_format_uncompressed_f4024_node = { + .prompt = "%s(config-srv6-format)# " + }; + +-#ifdef HAVE_PBRD + static struct cmd_node pbr_map_node = { + .name = "pbr-map", + .node = PBRMAP_NODE, + .parent_node = CONFIG_NODE, + .prompt = "%s(config-pbr-map)# ", + }; +-#endif /* HAVE_PBRD */ + + static struct cmd_node zebra_node = { + .name = "zebra", +@@ -1381,7 +1371,6 @@ static struct cmd_node zebra_node = { + .prompt = "%s(config-router)# ", + }; + +-#ifdef HAVE_BGPD + static struct cmd_node bgp_vpnv4_node = { + .name = "bgp vpnv4", + .node = BGP_VPNV4_NODE, +@@ -1477,7 +1466,6 @@ static struct cmd_node bgp_ipv6l_node = { + .no_xpath = true, + }; + +-#ifdef ENABLE_BGP_VNC + static struct cmd_node bgp_vnc_defaults_node = { + .name = "bgp vnc defaults", + .node = BGP_VNC_DEFAULTS_NODE, +@@ -1505,7 +1493,6 @@ static struct cmd_node bgp_vnc_l2_group_node = { + .parent_node = BGP_NODE, + .prompt = "%s(config-router-vnc-l2-group)# ", + }; +-#endif /* ENABLE_BGP_VNC */ + + static struct cmd_node bmp_node = { + .name = "bmp", +@@ -1520,34 +1507,27 @@ static struct cmd_node bgp_srv6_node = { + .parent_node = BGP_NODE, + .prompt = "%s(config-router-srv6)# ", + }; +-#endif /* HAVE_BGPD */ + +-#ifdef HAVE_OSPFD + static struct cmd_node ospf_node = { + .name = "ospf", + .node = OSPF_NODE, + .parent_node = CONFIG_NODE, + .prompt = "%s(config-router)# ", + }; +-#endif /* HAVE_OSPFD */ + +-#ifdef HAVE_EIGRPD + static struct cmd_node eigrp_node = { + .name = "eigrp", + .node = EIGRP_NODE, + .parent_node = CONFIG_NODE, + .prompt = "%s(config-router)# ", + }; +-#endif /* HAVE_EIGRPD */ + +-#ifdef HAVE_BABELD + static struct cmd_node babel_node = { + .name = "babel", + .node = BABEL_NODE, + .parent_node = CONFIG_NODE, + .prompt = "%s(config-router)# ", + }; +-#endif /* HAVE_BABELD */ + + static struct cmd_node ripng_node = { + .name = "ripng", +@@ -1556,16 +1536,13 @@ static struct cmd_node ripng_node = { + .prompt = "%s(config-router)# ", + }; + +-#ifdef HAVE_OSPF6D + static struct cmd_node ospf6_node = { + .name = "ospf6", + .node = OSPF6_NODE, + .parent_node = CONFIG_NODE, + .prompt = "%s(config-ospf6)# ", + }; +-#endif /* HAVE_OSPF6D */ + +-#ifdef HAVE_LDPD + static struct cmd_node ldp_node = { + .name = "ldp", + .node = LDP_NODE, +@@ -1614,7 +1591,6 @@ static struct cmd_node ldp_pseudowire_node = { + .parent_node = LDP_L2VPN_NODE, + .prompt = "%s(config-l2vpn-pw)# ", + }; +-#endif /* HAVE_LDPD */ + + static struct cmd_node keychain_node = { + .name = "keychain", +@@ -1637,7 +1613,6 @@ struct cmd_node link_params_node = { + .prompt = "%s(config-link-params)# ", + }; + +-#ifdef HAVE_BGPD + static struct cmd_node rpki_node = { + .name = "rpki", + .node = RPKI_NODE, +@@ -1652,9 +1627,6 @@ static struct cmd_node rpki_vrf_node = { + .prompt = "%s(config-vrf-rpki)# ", + }; + +-#endif /* HAVE_BGPD */ +- +-#if HAVE_BFDD > 0 + static struct cmd_node bfd_node = { + .name = "bfd", + .node = BFD_NODE, +@@ -1675,25 +1647,20 @@ static struct cmd_node bfd_profile_node = { + .parent_node = BFD_NODE, + .prompt = "%s(config-bfd-profile)# ", + }; +-#endif /* HAVE_BFDD */ + +-#ifdef HAVE_PIMD + static struct cmd_node pim_node = { + .name = "pim", + .node = PIM_NODE, + .parent_node = CONFIG_NODE, + .prompt = "%s(config-pim)# ", + }; +-#endif /* HAVE_PIMD */ + +-#ifdef HAVE_PIM6D + static struct cmd_node pim6_node = { + .name = "pim6", + .node = PIM6_NODE, + .parent_node = CONFIG_NODE, + .prompt = "%s(config-pim6)# ", + }; +-#endif /* HAVE_PIM6D */ + + /* Defined in lib/vty.c */ + extern struct cmd_node vty_node; +@@ -4954,15 +4921,87 @@ void vtysh_init_vty(void) + cmd_init(0); + cmd_variable_handler_register(vtysh_var_handler); + ++ install_node(&bgp_node); ++ install_node(&babel_node); ++ install_node(&bgp_vpnv4_node); ++ install_node(&bgp_vpnv6_node); ++ install_node(&bgp_flowspecv4_node); ++ install_node(&bgp_flowspecv6_node); ++ install_node(&bgp_ipv4_node); ++ install_node(&bgp_ipv4m_node); ++ install_node(&bgp_ipv4l_node); ++ install_node(&bgp_ipv6_node); ++ install_node(&bgp_ipv6m_node); ++ install_node(&bgp_ipv6l_node); ++ install_node(&bgp_vrf_policy_node); ++ install_node(&bgp_vnc_defaults_node); ++ install_node(&bgp_vnc_nve_group_node); ++ install_node(&bgp_vnc_l2_group_node); ++ install_node(&bgp_evpn_node); ++ install_node(&bgp_evpn_vni_node); ++ install_node(&rpki_node); ++ install_node(&bmp_node); ++ install_node(&bgp_srv6_node); ++ install_node(&rip_node); ++ install_node(&ripng_node); ++ install_node(&ospf_node); ++ install_node(&ospf6_node); ++ install_node(&ldp_node); ++ install_node(&ldp_ipv4_node); ++ install_node(&ldp_ipv6_node); ++ install_node(&ldp_ipv4_iface_node); ++ install_node(&ldp_ipv6_iface_node); ++ install_node(&ldp_l2vpn_node); ++ install_node(&ldp_pseudowire_node); ++ install_node(&eigrp_node); ++ install_node(&isis_node); ++ install_node(&isis_flex_algo_node); ++ install_node(&isis_srv6_node); ++ install_node(&isis_srv6_node_msd_node); ++ install_node(&openfabric_node); ++ install_node(&pbr_map_node); ++ install_node(&bfd_node); ++ install_node(&bfd_peer_node); ++ install_node(&bfd_profile_node); ++ install_node(&segment_routing_node); ++ install_node(&sr_traffic_eng_node); ++ install_node(&srte_segment_list_node); ++ install_node(&srte_policy_node); ++ install_node(&srte_candidate_dyn_node); ++ install_node(&pcep_node); ++ install_node(&pcep_pcc_node); ++ install_node(&pcep_pce_node); ++ install_node(&pcep_pce_config_node); ++ install_node(&keychain_node); ++ install_node(&keychain_key_node); ++ install_node(&nh_group_node); ++ install_node(&zebra_node); ++ install_node(&interface_node); ++ install_node(&pim_node); ++ install_node(&pim6_node); ++ install_node(&link_params_node); ++ install_node(&pw_node); ++ install_node(&vrf_node); ++ install_node(&rpki_vrf_node); ++ install_node(&rmap_node); ++ install_node(&vty_node); ++ install_node(&srv6_node); ++ install_node(&srv6_locs_node); ++ install_node(&srv6_loc_node); ++ install_node(&srv6_encap_node); ++ install_node(&srv6_sid_formats_node); ++ install_node(&srv6_sid_format_usid_f3216_node); ++ install_node(&srv6_sid_format_uncompressed_f4024_node); ++ ++ vtysh_init_cmd(); ++ + /* bgpd */ + #ifdef HAVE_BGPD +- install_node(&bgp_node); + install_element(CONFIG_NODE, &router_bgp_cmd); + install_element(BGP_NODE, &vtysh_exit_bgpd_cmd); + install_element(BGP_NODE, &vtysh_quit_bgpd_cmd); + install_element(BGP_NODE, &vtysh_end_all_cmd); + +- install_node(&bgp_vpnv4_node); + install_element(BGP_NODE, &address_family_ipv4_vpn_cmd); + #ifdef KEEP_OLD_VPN_COMMANDS + install_element(BGP_NODE, &address_family_vpnv4_cmd); +@@ -4972,7 +5011,6 @@ void vtysh_init_vty(void) + install_element(BGP_VPNV4_NODE, &vtysh_end_all_cmd); + install_element(BGP_VPNV4_NODE, &exit_address_family_cmd); + +- install_node(&bgp_vpnv6_node); + install_element(BGP_NODE, &address_family_ipv6_vpn_cmd); + #ifdef KEEP_OLD_VPN_COMMANDS + install_element(BGP_NODE, &address_family_vpnv6_cmd); +@@ -4982,56 +5020,48 @@ void vtysh_init_vty(void) + install_element(BGP_VPNV6_NODE, &vtysh_end_all_cmd); + install_element(BGP_VPNV6_NODE, &exit_address_family_cmd); + +- install_node(&bgp_flowspecv4_node); + install_element(BGP_NODE, &address_family_flowspecv4_cmd); + install_element(BGP_FLOWSPECV4_NODE, &vtysh_exit_bgpd_cmd); + install_element(BGP_FLOWSPECV4_NODE, &vtysh_quit_bgpd_cmd); + install_element(BGP_FLOWSPECV4_NODE, &vtysh_end_all_cmd); + install_element(BGP_FLOWSPECV4_NODE, &exit_address_family_cmd); + +- install_node(&bgp_flowspecv6_node); + install_element(BGP_NODE, &address_family_flowspecv6_cmd); + install_element(BGP_FLOWSPECV6_NODE, &vtysh_exit_bgpd_cmd); + install_element(BGP_FLOWSPECV6_NODE, &vtysh_quit_bgpd_cmd); + install_element(BGP_FLOWSPECV6_NODE, &vtysh_end_all_cmd); + install_element(BGP_FLOWSPECV6_NODE, &exit_address_family_cmd); + +- install_node(&bgp_ipv4_node); + install_element(BGP_NODE, &address_family_ipv4_cmd); + install_element(BGP_IPV4_NODE, &vtysh_exit_bgpd_cmd); + install_element(BGP_IPV4_NODE, &vtysh_quit_bgpd_cmd); + install_element(BGP_IPV4_NODE, &vtysh_end_all_cmd); + install_element(BGP_IPV4_NODE, &exit_address_family_cmd); + +- install_node(&bgp_ipv4m_node); + install_element(BGP_NODE, &address_family_ipv4_multicast_cmd); + install_element(BGP_IPV4M_NODE, &vtysh_exit_bgpd_cmd); + install_element(BGP_IPV4M_NODE, &vtysh_quit_bgpd_cmd); + install_element(BGP_IPV4M_NODE, &vtysh_end_all_cmd); + install_element(BGP_IPV4M_NODE, &exit_address_family_cmd); + +- install_node(&bgp_ipv4l_node); + install_element(BGP_NODE, &address_family_ipv4_labeled_unicast_cmd); + install_element(BGP_IPV4L_NODE, &vtysh_exit_bgpd_cmd); + install_element(BGP_IPV4L_NODE, &vtysh_quit_bgpd_cmd); + install_element(BGP_IPV4L_NODE, &vtysh_end_all_cmd); + install_element(BGP_IPV4L_NODE, &exit_address_family_cmd); + +- install_node(&bgp_ipv6_node); + install_element(BGP_NODE, &address_family_ipv6_cmd); + install_element(BGP_IPV6_NODE, &vtysh_exit_bgpd_cmd); + install_element(BGP_IPV6_NODE, &vtysh_quit_bgpd_cmd); + install_element(BGP_IPV6_NODE, &vtysh_end_all_cmd); + install_element(BGP_IPV6_NODE, &exit_address_family_cmd); + +- install_node(&bgp_ipv6m_node); + install_element(BGP_NODE, &address_family_ipv6_multicast_cmd); + install_element(BGP_IPV6M_NODE, &vtysh_exit_bgpd_cmd); + install_element(BGP_IPV6M_NODE, &vtysh_quit_bgpd_cmd); + install_element(BGP_IPV6M_NODE, &vtysh_end_all_cmd); + install_element(BGP_IPV6M_NODE, &exit_address_family_cmd); + +- install_node(&bgp_ipv6l_node); + install_element(BGP_NODE, &address_family_ipv6_labeled_unicast_cmd); + install_element(BGP_IPV6L_NODE, &vtysh_exit_bgpd_cmd); + install_element(BGP_IPV6L_NODE, &vtysh_quit_bgpd_cmd); +@@ -5039,28 +5069,24 @@ void vtysh_init_vty(void) + install_element(BGP_IPV6L_NODE, &exit_address_family_cmd); + + #if defined(ENABLE_BGP_VNC) +- install_node(&bgp_vrf_policy_node); + install_element(BGP_NODE, &vnc_vrf_policy_cmd); + install_element(BGP_VRF_POLICY_NODE, &vtysh_exit_bgpd_cmd); + install_element(BGP_VRF_POLICY_NODE, &vtysh_quit_bgpd_cmd); + install_element(BGP_VRF_POLICY_NODE, &vtysh_end_all_cmd); + install_element(BGP_VRF_POLICY_NODE, &exit_vrf_policy_cmd); + +- install_node(&bgp_vnc_defaults_node); + install_element(BGP_NODE, &vnc_defaults_cmd); + install_element(BGP_VNC_DEFAULTS_NODE, &vtysh_exit_bgpd_cmd); + install_element(BGP_VNC_DEFAULTS_NODE, &vtysh_quit_bgpd_cmd); + install_element(BGP_VNC_DEFAULTS_NODE, &vtysh_end_all_cmd); + install_element(BGP_VNC_DEFAULTS_NODE, &exit_vnc_config_cmd); + +- install_node(&bgp_vnc_nve_group_node); + install_element(BGP_NODE, &vnc_nve_group_cmd); + install_element(BGP_VNC_NVE_GROUP_NODE, &vtysh_exit_bgpd_cmd); + install_element(BGP_VNC_NVE_GROUP_NODE, &vtysh_quit_bgpd_cmd); + install_element(BGP_VNC_NVE_GROUP_NODE, &vtysh_end_all_cmd); + install_element(BGP_VNC_NVE_GROUP_NODE, &exit_vnc_config_cmd); + +- install_node(&bgp_vnc_l2_group_node); + install_element(BGP_NODE, &vnc_l2_group_cmd); + install_element(BGP_VNC_L2_GROUP_NODE, &vtysh_exit_bgpd_cmd); + install_element(BGP_VNC_L2_GROUP_NODE, &vtysh_quit_bgpd_cmd); +@@ -5068,33 +5094,28 @@ void vtysh_init_vty(void) + install_element(BGP_VNC_L2_GROUP_NODE, &exit_vnc_config_cmd); + #endif + +- install_node(&bgp_evpn_node); + install_element(BGP_NODE, &address_family_evpn_cmd); + install_element(BGP_EVPN_NODE, &vtysh_quit_bgpd_cmd); + install_element(BGP_EVPN_NODE, &vtysh_exit_bgpd_cmd); + install_element(BGP_EVPN_NODE, &vtysh_end_all_cmd); + install_element(BGP_EVPN_NODE, &exit_address_family_cmd); + +- install_node(&bgp_evpn_vni_node); + install_element(BGP_EVPN_NODE, &bgp_evpn_vni_cmd); + install_element(BGP_EVPN_VNI_NODE, &vtysh_exit_bgpd_cmd); + install_element(BGP_EVPN_VNI_NODE, &vtysh_quit_bgpd_cmd); + install_element(BGP_EVPN_VNI_NODE, &vtysh_end_all_cmd); + install_element(BGP_EVPN_VNI_NODE, &exit_vni_cmd); + +- install_node(&rpki_node); + install_element(CONFIG_NODE, &rpki_cmd); + install_element(RPKI_NODE, &rpki_exit_cmd); + install_element(RPKI_NODE, &rpki_quit_cmd); + install_element(RPKI_NODE, &vtysh_end_all_cmd); + +- install_node(&bmp_node); + install_element(BGP_NODE, &bmp_targets_cmd); + install_element(BMP_NODE, &bmp_exit_cmd); + install_element(BMP_NODE, &bmp_quit_cmd); + install_element(BMP_NODE, &vtysh_end_all_cmd); + +- install_node(&bgp_srv6_node); + install_element(BGP_NODE, &bgp_srv6_cmd); + install_element(BGP_SRV6_NODE, &exit_bgp_srv6_cmd); + install_element(BGP_SRV6_NODE, &quit_bgp_srv6_cmd); +@@ -5102,7 +5123,6 @@ void vtysh_init_vty(void) + #endif /* HAVE_BGPD */ + + /* ripd */ +- install_node(&rip_node); + #ifdef HAVE_RIPD + install_element(CONFIG_NODE, &router_rip_cmd); + install_element(RIP_NODE, &vtysh_exit_ripd_cmd); +@@ -5111,7 +5131,6 @@ void vtysh_init_vty(void) + #endif /* HAVE_RIPD */ + + /* ripngd */ +- install_node(&ripng_node); + #ifdef HAVE_RIPNGD + install_element(CONFIG_NODE, &router_ripng_cmd); + install_element(RIPNG_NODE, &vtysh_exit_ripngd_cmd); +@@ -5121,7 +5140,6 @@ void vtysh_init_vty(void) + + /* ospfd */ + #ifdef HAVE_OSPFD +- install_node(&ospf_node); + install_element(CONFIG_NODE, &router_ospf_cmd); + install_element(OSPF_NODE, &vtysh_exit_ospfd_cmd); + install_element(OSPF_NODE, &vtysh_quit_ospfd_cmd); +@@ -5130,7 +5148,6 @@ void vtysh_init_vty(void) + + /* ospf6d */ + #ifdef HAVE_OSPF6D +- install_node(&ospf6_node); + install_element(CONFIG_NODE, &router_ospf6_cmd); + install_element(OSPF6_NODE, &vtysh_exit_ospf6d_cmd); + install_element(OSPF6_NODE, &vtysh_quit_ospf6d_cmd); +@@ -5139,45 +5156,38 @@ void vtysh_init_vty(void) + + /* ldpd */ + #if defined(HAVE_LDPD) +- install_node(&ldp_node); + install_element(CONFIG_NODE, &ldp_mpls_ldp_cmd); + install_element(LDP_NODE, &vtysh_exit_ldpd_cmd); + install_element(LDP_NODE, &vtysh_quit_ldpd_cmd); + install_element(LDP_NODE, &vtysh_end_all_cmd); + +- install_node(&ldp_ipv4_node); + install_element(LDP_NODE, &ldp_address_family_ipv4_cmd); + install_element(LDP_IPV4_NODE, &vtysh_exit_ldpd_cmd); + install_element(LDP_IPV4_NODE, &vtysh_quit_ldpd_cmd); + install_element(LDP_IPV4_NODE, &ldp_exit_address_family_cmd); + install_element(LDP_IPV4_NODE, &vtysh_end_all_cmd); + +- install_node(&ldp_ipv6_node); + install_element(LDP_NODE, &ldp_address_family_ipv6_cmd); + install_element(LDP_IPV6_NODE, &vtysh_exit_ldpd_cmd); + install_element(LDP_IPV6_NODE, &vtysh_quit_ldpd_cmd); + install_element(LDP_IPV6_NODE, &ldp_exit_address_family_cmd); + install_element(LDP_IPV6_NODE, &vtysh_end_all_cmd); + +- install_node(&ldp_ipv4_iface_node); + install_element(LDP_IPV4_NODE, &ldp_interface_ifname_cmd); + install_element(LDP_IPV4_IFACE_NODE, &vtysh_exit_ldpd_cmd); + install_element(LDP_IPV4_IFACE_NODE, &vtysh_quit_ldpd_cmd); + install_element(LDP_IPV4_IFACE_NODE, &vtysh_end_all_cmd); + +- install_node(&ldp_ipv6_iface_node); + install_element(LDP_IPV6_NODE, &ldp_interface_ifname_cmd); + install_element(LDP_IPV6_IFACE_NODE, &vtysh_exit_ldpd_cmd); + install_element(LDP_IPV6_IFACE_NODE, &vtysh_quit_ldpd_cmd); + install_element(LDP_IPV6_IFACE_NODE, &vtysh_end_all_cmd); + +- install_node(&ldp_l2vpn_node); + install_element(CONFIG_NODE, &ldp_l2vpn_word_type_vpls_cmd); + install_element(LDP_L2VPN_NODE, &vtysh_exit_ldpd_cmd); + install_element(LDP_L2VPN_NODE, &vtysh_quit_ldpd_cmd); + install_element(LDP_L2VPN_NODE, &vtysh_end_all_cmd); + +- install_node(&ldp_pseudowire_node); + install_element(LDP_L2VPN_NODE, &ldp_member_pseudowire_ifname_cmd); + install_element(LDP_PSEUDOWIRE_NODE, &vtysh_exit_ldpd_cmd); + install_element(LDP_PSEUDOWIRE_NODE, &vtysh_quit_ldpd_cmd); +@@ -5186,7 +5196,6 @@ void vtysh_init_vty(void) + + /* eigrpd */ + #ifdef HAVE_EIGRPD +- install_node(&eigrp_node); + install_element(CONFIG_NODE, &router_eigrp_cmd); + install_element(EIGRP_NODE, &vtysh_exit_eigrpd_cmd); + install_element(EIGRP_NODE, &vtysh_quit_eigrpd_cmd); +@@ -5195,7 +5204,6 @@ void vtysh_init_vty(void) + + /* babeld */ + #ifdef HAVE_BABELD +- install_node(&babel_node); + install_element(CONFIG_NODE, &router_babel_cmd); + install_element(BABEL_NODE, &vtysh_exit_babeld_cmd); + install_element(BABEL_NODE, &vtysh_quit_babeld_cmd); +@@ -5204,25 +5212,21 @@ void vtysh_init_vty(void) + + /* isisd */ + #ifdef HAVE_ISISD +- install_node(&isis_node); + install_element(CONFIG_NODE, &router_isis_cmd); + install_element(ISIS_NODE, &vtysh_exit_isisd_cmd); + install_element(ISIS_NODE, &vtysh_quit_isisd_cmd); + install_element(ISIS_NODE, &vtysh_end_all_cmd); + +- install_node(&isis_flex_algo_node); + install_element(ISIS_NODE, &isis_flex_algo_cmd); + install_element(ISIS_FLEX_ALGO_NODE, &vtysh_exit_isis_flex_algo_cmd); + install_element(ISIS_FLEX_ALGO_NODE, &vtysh_quit_isis_flex_algo_cmd); + install_element(ISIS_FLEX_ALGO_NODE, &vtysh_end_all_cmd); + +- install_node(&isis_srv6_node); + install_element(ISIS_NODE, &isis_srv6_enable_cmd); + install_element(ISIS_SRV6_NODE, &isis_srv6_node_msd_cmd); + install_element(ISIS_SRV6_NODE, &vtysh_exit_isis_srv6_enable_cmd); + install_element(ISIS_SRV6_NODE, &vtysh_quit_isis_srv6_enable_cmd); + install_element(ISIS_SRV6_NODE, &vtysh_end_all_cmd); +- install_node(&isis_srv6_node_msd_node); + install_element(ISIS_SRV6_NODE_MSD_NODE, + &vtysh_exit_isis_srv6_node_msd_cmd); + install_element(ISIS_SRV6_NODE_MSD_NODE, +@@ -5232,7 +5236,6 @@ void vtysh_init_vty(void) + + /* fabricd */ + #ifdef HAVE_FABRICD +- install_node(&openfabric_node); + install_element(CONFIG_NODE, &router_openfabric_cmd); + install_element(OPENFABRIC_NODE, &vtysh_exit_fabricd_cmd); + install_element(OPENFABRIC_NODE, &vtysh_quit_fabricd_cmd); +@@ -5241,7 +5244,6 @@ void vtysh_init_vty(void) + + /* pbrd */ + #ifdef HAVE_PBRD +- install_node(&pbr_map_node); + install_element(CONFIG_NODE, &vtysh_pbr_map_cmd); + install_element(CONFIG_NODE, &vtysh_no_pbr_map_cmd); + install_element(PBRMAP_NODE, &vtysh_exit_pbr_map_cmd); +@@ -5251,37 +5253,28 @@ void vtysh_init_vty(void) + + /* bfdd */ + #if HAVE_BFDD > 0 +- install_node(&bfd_node); + install_element(CONFIG_NODE, &bfd_enter_cmd); + install_element(BFD_NODE, &vtysh_exit_bfdd_cmd); + install_element(BFD_NODE, &vtysh_quit_bfdd_cmd); + install_element(BFD_NODE, &vtysh_end_all_cmd); + +- install_node(&bfd_peer_node); + install_element(BFD_NODE, &bfd_peer_enter_cmd); + install_element(BFD_PEER_NODE, &vtysh_exit_bfdd_cmd); + install_element(BFD_PEER_NODE, &vtysh_quit_bfdd_cmd); + install_element(BFD_PEER_NODE, &vtysh_end_all_cmd); + +- install_node(&bfd_profile_node); + install_element(BFD_NODE, &bfd_profile_enter_cmd); + install_element(BFD_PROFILE_NODE, &vtysh_exit_bfdd_cmd); + install_element(BFD_PROFILE_NODE, &vtysh_quit_bfdd_cmd); + install_element(BFD_PROFILE_NODE, &vtysh_end_all_cmd); + #endif /* HAVE_BFDD */ + +- install_node(&segment_routing_node); + install_element(CONFIG_NODE, &segment_routing_cmd); + install_element(SEGMENT_ROUTING_NODE, &vtysh_exit_sr_cmd); + install_element(SEGMENT_ROUTING_NODE, &vtysh_quit_sr_cmd); + install_element(SEGMENT_ROUTING_NODE, &vtysh_end_all_cmd); + + #if defined(HAVE_PATHD) +- install_node(&sr_traffic_eng_node); +- install_node(&srte_segment_list_node); +- install_node(&srte_policy_node); +- install_node(&srte_candidate_dyn_node); +- + install_element(SR_TRAFFIC_ENG_NODE, &vtysh_exit_pathd_cmd); + install_element(SR_TRAFFIC_ENG_NODE, &vtysh_quit_pathd_cmd); + install_element(SR_SEGMENT_LIST_NODE, &vtysh_exit_pathd_cmd); +@@ -5302,11 +5295,6 @@ void vtysh_init_vty(void) + install_element(SR_TRAFFIC_ENG_NODE, &srte_policy_cmd); + install_element(SR_POLICY_NODE, &srte_policy_candidate_dyn_path_cmd); + +- install_node(&pcep_node); +- install_node(&pcep_pcc_node); +- install_node(&pcep_pce_node); +- install_node(&pcep_pce_config_node); +- + install_element(PCEP_NODE, &vtysh_exit_pathd_cmd); + install_element(PCEP_NODE, &vtysh_quit_pathd_cmd); + install_element(PCEP_PCC_NODE, &vtysh_exit_pathd_cmd); +@@ -5329,14 +5317,12 @@ void vtysh_init_vty(void) + #endif /* HAVE_PATHD */ + + /* keychain */ +- install_node(&keychain_node); + install_element(CONFIG_NODE, &key_chain_cmd); + install_element(KEYCHAIN_NODE, &key_chain_cmd); + install_element(KEYCHAIN_NODE, &vtysh_exit_keys_cmd); + install_element(KEYCHAIN_NODE, &vtysh_quit_keys_cmd); + install_element(KEYCHAIN_NODE, &vtysh_end_all_cmd); + +- install_node(&keychain_key_node); + install_element(KEYCHAIN_NODE, &key_cmd); + install_element(KEYCHAIN_KEY_NODE, &key_chain_cmd); + install_element(KEYCHAIN_KEY_NODE, &vtysh_exit_keys_cmd); +@@ -5344,7 +5330,6 @@ void vtysh_init_vty(void) + install_element(KEYCHAIN_KEY_NODE, &vtysh_end_all_cmd); + + /* nexthop-group */ +- install_node(&nh_group_node); + install_element(CONFIG_NODE, &vtysh_nexthop_group_cmd); + install_element(CONFIG_NODE, &vtysh_no_nexthop_group_cmd); + install_element(NH_GROUP_NODE, &vtysh_end_all_cmd); +@@ -5352,9 +5337,6 @@ void vtysh_init_vty(void) + install_element(NH_GROUP_NODE, &vtysh_quit_nexthop_group_cmd); + + /* zebra and all */ +- install_node(&zebra_node); +- +- install_node(&interface_node); + install_element(CONFIG_NODE, &vtysh_interface_cmd); + install_element(INTERFACE_NODE, &vtysh_end_all_cmd); + install_element(INTERFACE_NODE, &vtysh_exit_interface_cmd); +@@ -5362,7 +5344,6 @@ void vtysh_init_vty(void) + + /* pimd */ + #ifdef HAVE_PIMD +- install_node(&pim_node); + install_element(CONFIG_NODE, &router_pim_cmd); + install_element(PIM_NODE, &vtysh_exit_pimd_cmd); + install_element(PIM_NODE, &vtysh_quit_pimd_cmd); +@@ -5371,15 +5352,12 @@ void vtysh_init_vty(void) + + /* pim6d */ + #ifdef HAVE_PIM6D +- install_node(&pim6_node); + install_element(CONFIG_NODE, &router_pim6_cmd); + install_element(PIM6_NODE, &vtysh_exit_pim6d_cmd); + install_element(PIM6_NODE, &vtysh_quit_pim6d_cmd); + install_element(PIM6_NODE, &vtysh_end_all_cmd); + #endif /* HAVE_PIM6D */ + +- /* zebra and all, cont. */ +- install_node(&link_params_node); + install_element(INTERFACE_NODE, &vtysh_link_params_cmd); + install_element(LINK_PARAMS_NODE, &no_link_params_enable_cmd); + install_element(LINK_PARAMS_NODE, &exit_link_params_cmd); +@@ -5387,13 +5365,11 @@ void vtysh_init_vty(void) + install_element(LINK_PARAMS_NODE, &vtysh_exit_link_params_cmd); + install_element(LINK_PARAMS_NODE, &vtysh_quit_link_params_cmd); + +- install_node(&pw_node); + install_element(CONFIG_NODE, &vtysh_pseudowire_cmd); + install_element(PW_NODE, &vtysh_end_all_cmd); + install_element(PW_NODE, &vtysh_exit_pseudowire_cmd); + install_element(PW_NODE, &vtysh_quit_pseudowire_cmd); + +- install_node(&vrf_node); + install_element(CONFIG_NODE, &vtysh_vrf_cmd); + install_element(VRF_NODE, &exit_vrf_config_cmd); + install_element(VRF_NODE, &vtysh_end_all_cmd); +@@ -5401,7 +5377,6 @@ void vtysh_init_vty(void) + install_element(VRF_NODE, &vtysh_quit_vrf_cmd); + + #ifdef HAVE_BGPD +- install_node(&rpki_vrf_node); + install_element(VRF_NODE, &rpki_cmd); + install_element(RPKI_VRF_NODE, &rpki_exit_cmd); + install_element(RPKI_VRF_NODE, &rpki_quit_cmd); +@@ -5411,13 +5386,11 @@ void vtysh_init_vty(void) + install_element(CONFIG_NODE, &vtysh_affinity_map_cmd); + install_element(CONFIG_NODE, &vtysh_no_affinity_map_cmd); + +- install_node(&rmap_node); + install_element(CONFIG_NODE, &vtysh_route_map_cmd); + install_element(RMAP_NODE, &vtysh_exit_rmap_cmd); + install_element(RMAP_NODE, &vtysh_quit_rmap_cmd); + install_element(RMAP_NODE, &vtysh_end_all_cmd); + +- install_node(&vty_node); + install_element(CONFIG_NODE, &vtysh_line_vty_cmd); + install_element(VTY_NODE, &vtysh_exit_line_vty_cmd); + install_element(VTY_NODE, &vtysh_quit_line_vty_cmd); +@@ -5450,7 +5423,6 @@ void vtysh_init_vty(void) + install_element(ENABLE_NODE, &vtysh_end_all_cmd); + + /* SRv6 Data-plane */ +- install_node(&srv6_node); + install_element(SEGMENT_ROUTING_NODE, &srv6_cmd); + install_element(SRV6_NODE, &srv6_locators_cmd); + install_element(SRV6_NODE, &srv6_sid_formats_cmd); +@@ -5458,32 +5430,26 @@ void vtysh_init_vty(void) + install_element(SRV6_NODE, &vtysh_end_all_cmd); + install_element(SRV6_NODE, &srv6_encap_cmd); + +- install_node(&srv6_locs_node); + install_element(SRV6_LOCS_NODE, &srv6_locator_cmd); + install_element(SRV6_LOCS_NODE, &exit_srv6_locs_config_cmd); + install_element(SRV6_LOCS_NODE, &vtysh_end_all_cmd); + +- install_node(&srv6_loc_node); + install_element(SRV6_LOC_NODE, &exit_srv6_loc_config_cmd); + install_element(SRV6_LOC_NODE, &vtysh_end_all_cmd); + +- install_node(&srv6_encap_node); + install_element(SRV6_ENCAP_NODE, &exit_srv6_encap_cmd); + install_element(SRV6_ENCAP_NODE, &vtysh_end_all_cmd); + +- install_node(&srv6_sid_formats_node); + install_element(SRV6_SID_FORMATS_NODE, &srv6_sid_format_f3216_usid_cmd); + install_element(SRV6_SID_FORMATS_NODE, + &srv6_sid_format_f4024_uncompressed_cmd); + install_element(SRV6_SID_FORMATS_NODE, &exit_srv6_sid_formats_cmd); + install_element(SRV6_SID_FORMATS_NODE, &vtysh_end_all_cmd); + +- install_node(&srv6_sid_format_usid_f3216_node); + install_element(SRV6_SID_FORMAT_USID_F3216_NODE, + &exit_srv6_sid_format_cmd); + install_element(SRV6_SID_FORMAT_USID_F3216_NODE, &vtysh_end_all_cmd); + +- install_node(&srv6_sid_format_uncompressed_f4024_node); + install_element(SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE, + &exit_srv6_sid_format_cmd); + install_element(SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE, +diff --git a/vtysh/vtysh_main.c b/vtysh/vtysh_main.c +index 464d82cf7fee..64198132cc64 100644 +--- a/vtysh/vtysh_main.c ++++ b/vtysh/vtysh_main.c +@@ -489,7 +489,6 @@ int main(int argc, char **argv, char **env) + + /* Make vty structure and register commands. */ + vtysh_init_vty(); +- vtysh_init_cmd(); + vtysh_user_init(); + vtysh_config_init(); + diff --git a/src/sonic-frr/patch/0079-staticd-add-support-for-srv6.patch b/src/sonic-frr/patch/0079-staticd-add-support-for-srv6.patch new file mode 100644 index 000000000000..66afd2eaece4 --- /dev/null +++ b/src/sonic-frr/patch/0079-staticd-add-support-for-srv6.patch @@ -0,0 +1,2372 @@ +From 4520117dfed56515dc3c3ea383a5914c15d3088d Mon Sep 17 00:00:00 2001 +From: Carmine Scarpitta +Date: Tue, 7 Jan 2025 14:23:34 +0100 +Subject: [PATCH] staticd: Add support for SRv6 + +Signed-off-by: Carmine Scarpitta +--- + lib/command.h | 1 + + staticd/static_main.c | 8 + + staticd/static_nb.c | 50 ++ + staticd/static_nb.h | 32 +- + staticd/static_nb_config.c | 179 +++++ + staticd/static_srv6.c | 217 ++++++ + staticd/static_srv6.h | 125 ++++ + staticd/static_vrf.c | 10 + + staticd/static_vty.c | 329 +++++++++ + staticd/static_zebra.c | 632 ++++++++++++++++++ + staticd/static_zebra.h | 12 +- + staticd/subdir.am | 2 + + tests/topotests/static_srv6_sids/__init__.py | 0 + .../static_srv6_sids/expected_srv6_sids.json | 142 ++++ + .../topotests/static_srv6_sids/r1/mgmtd.conf | 0 + tests/topotests/static_srv6_sids/r1/setup.sh | 13 + + .../static_srv6_sids/r1/staticd.conf | 16 + + .../topotests/static_srv6_sids/r1/zebra.conf | 19 + + .../static_srv6_sids/test_static_srv6_sids.py | 89 +++ + vtysh/vtysh.c | 34 +- + yang/frr-staticd.yang | 59 +- + zebra/zebra_srv6.c | 10 +- + 22 files changed, 1968 insertions(+), 11 deletions(-) + create mode 100644 staticd/static_srv6.c + create mode 100644 staticd/static_srv6.h + create mode 100644 tests/topotests/static_srv6_sids/__init__.py + create mode 100644 tests/topotests/static_srv6_sids/expected_srv6_sids.json + create mode 100644 tests/topotests/static_srv6_sids/r1/mgmtd.conf + create mode 100644 tests/topotests/static_srv6_sids/r1/setup.sh + create mode 100644 tests/topotests/static_srv6_sids/r1/staticd.conf + create mode 100644 tests/topotests/static_srv6_sids/r1/zebra.conf + create mode 100755 tests/topotests/static_srv6_sids/test_static_srv6_sids.py + +diff --git a/lib/command.h b/lib/command.h +index c60751789f..dfd732893b 100644 +--- a/lib/command.h ++++ b/lib/command.h +@@ -154,6 +154,7 @@ enum node_type { + PCEP_PCE_NODE, /* PCE configuration node */ + PCEP_PCC_NODE, /* PCC configuration node */ + SRV6_NODE, /* SRv6 node */ ++ SRV6_SIDS_NODE, /* SRv6 SIDs node */ + SRV6_LOCS_NODE, /* SRv6 locators node */ + SRV6_LOC_NODE, /* SRv6 locator node */ + SRV6_ENCAP_NODE, /* SRv6 encapsulation node */ +diff --git a/staticd/static_main.c b/staticd/static_main.c +index 9468a98b83..f01bc08fd8 100644 +--- a/staticd/static_main.c ++++ b/staticd/static_main.c +@@ -26,6 +26,7 @@ + #include "static_zebra.h" + #include "static_debug.h" + #include "static_nb.h" ++#include "static_srv6.h" + + #include "mgmt_be_client.h" + +@@ -76,6 +77,10 @@ static void sigint(void) + static_vrf_terminate(); + + static_zebra_stop(); ++ ++ /* clean up SRv6 data structures */ ++ static_srv6_cleanup(); ++ + frr_fini(); + + exit(0); +@@ -160,6 +165,9 @@ int main(int argc, char **argv, char **envp) + static_debug_init(); + static_vrf_init(); + ++ /* initialize SRv6 data structures */ ++ static_srv6_init(); ++ + static_zebra_init(); + static_vty_init(); + +diff --git a/staticd/static_nb.c b/staticd/static_nb.c +index e6aa71a77b..c4f71e6ee3 100644 +--- a/staticd/static_nb.c ++++ b/staticd/static_nb.c +@@ -224,6 +224,56 @@ const struct frr_yang_module_info frr_staticd_info = { + .destroy = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_frr_nexthops_nexthop_mpls_label_stack_entry_traffic_class_destroy, + } + }, ++ { ++ .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/segment-routing/", ++ .cbs = { ++ .create = routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_create, ++ .destroy = routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_destroy, ++ } ++ }, ++ { ++ .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/segment-routing/srv6/", ++ .cbs = { ++ .create = routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_create, ++ .destroy = routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_destroy, ++ } ++ }, ++ { ++ .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/segment-routing/srv6/local-sids/", ++ .cbs = { ++ .create = routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_create, ++ .destroy = routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_destroy, ++ } ++ }, ++ { ++ .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/segment-routing/srv6/local-sids/sid", ++ .cbs = { ++ .apply_finish = routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_sid_apply_finish, ++ .create = routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_sid_create, ++ .destroy = routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_sid_destroy, ++ } ++ }, ++ { ++ .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/segment-routing/srv6/local-sids/sid/behavior", ++ .cbs = { ++ .modify = routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_sid_behavior_modify, ++ .destroy = routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_sid_behavior_destroy, ++ } ++ }, ++ { ++ .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/segment-routing/srv6/local-sids/sid/vrf-name", ++ .cbs = { ++ .modify = routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_sid_vrf_name_modify, ++ .destroy = routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_sid_vrf_name_destroy, ++ } ++ }, ++ { ++ .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/segment-routing/srv6/local-sids/sid/locator-name", ++ .cbs = { ++ .modify = routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_sid_locator_name_modify, ++ .destroy = routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_sid_locator_name_destroy, ++ } ++ }, + { + .xpath = NULL, + }, +diff --git a/staticd/static_nb.h b/staticd/static_nb.h +index be75d9d38c..fca9f9952c 100644 +--- a/staticd/static_nb.h ++++ b/staticd/static_nb.h +@@ -118,6 +118,34 @@ int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_sr + struct nb_cb_modify_args *args); + int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_frr_nexthops_nexthop_mpls_label_stack_entry_traffic_class_destroy( + struct nb_cb_destroy_args *args); ++int routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_create( ++ struct nb_cb_create_args *args); ++int routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_destroy( ++ struct nb_cb_destroy_args *args); ++int routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_create( ++ struct nb_cb_create_args *args); ++int routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_destroy( ++ struct nb_cb_destroy_args *args); ++int routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_create( ++ struct nb_cb_create_args *args); ++int routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_destroy( ++ struct nb_cb_destroy_args *args); ++int routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_sid_create( ++ struct nb_cb_create_args *args); ++int routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_sid_destroy( ++ struct nb_cb_destroy_args *args); ++int routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_sid_behavior_modify( ++ struct nb_cb_modify_args *args); ++int routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_sid_behavior_destroy( ++ struct nb_cb_destroy_args *args); ++int routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_sid_vrf_name_modify( ++ struct nb_cb_modify_args *args); ++int routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_sid_vrf_name_destroy( ++ struct nb_cb_destroy_args *args); ++int routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_sid_locator_name_modify( ++ struct nb_cb_modify_args *args); ++int routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_sid_locator_name_destroy( ++ struct nb_cb_destroy_args *args); + + /* Optional 'apply_finish' callbacks. */ + +@@ -125,6 +153,8 @@ void routing_control_plane_protocols_control_plane_protocol_staticd_route_list_p + struct nb_cb_apply_finish_args *args); + void routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_frr_nexthops_nexthop_apply_finish( + struct nb_cb_apply_finish_args *args); ++void routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_sid_apply_finish( ++ struct nb_cb_apply_finish_args *args); + + /* Optional 'pre_validate' callbacks. */ + int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_pre_validate( +@@ -210,4 +240,4 @@ int routing_control_plane_protocols_name_validate( + } + #endif + +-#endif ++#endif +\ No newline at end of file +diff --git a/staticd/static_nb_config.c b/staticd/static_nb_config.c +index 7de5f0474a..38f331ba54 100644 +--- a/staticd/static_nb_config.c ++++ b/staticd/static_nb_config.c +@@ -20,6 +20,8 @@ + #include "static_nb.h" + #include "static_zebra.h" + ++#include "static_srv6.h" ++ + + static int static_path_list_create(struct nb_cb_create_args *args) + { +@@ -1367,3 +1369,180 @@ int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_sr + + return NB_OK; + } ++ ++/* ++ * XPath: ++ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/segment-routing ++ */ ++int routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_create( ++ struct nb_cb_create_args *args) ++{ ++ return NB_OK; ++} ++ ++int routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_destroy( ++ struct nb_cb_destroy_args *args) ++{ ++ return NB_OK; ++} ++ ++/* ++ * XPath: ++ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/segment-routing/srv6 ++ */ ++int routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_create( ++ struct nb_cb_create_args *args) ++{ ++ return NB_OK; ++} ++ ++int routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_destroy( ++ struct nb_cb_destroy_args *args) ++{ ++ return NB_OK; ++} ++ ++/* ++ * XPath: ++ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/segment-routing/srv6/local-sids ++ */ ++int routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_create( ++ struct nb_cb_create_args *args) ++{ ++ return NB_OK; ++} ++ ++int routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_destroy( ++ struct nb_cb_destroy_args *args) ++{ ++ return NB_OK; ++} ++ ++/* ++ * XPath: ++ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/segment-routing/srv6/locators/locator/local-sids/sid ++ */ ++int routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_sid_create( ++ struct nb_cb_create_args *args) ++{ ++ struct static_srv6_sid *sid; ++ struct prefix_ipv6 sid_value; ++ ++ if (args->event != NB_EV_APPLY) ++ return NB_OK; ++ ++ yang_dnode_get_ipv6p(&sid_value, args->dnode, "sid"); ++ sid = static_srv6_sid_alloc(&sid_value); ++ nb_running_set_entry(args->dnode, sid); ++ ++ return NB_OK; ++} ++ ++int routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_sid_destroy( ++ struct nb_cb_destroy_args *args) ++{ ++ struct static_srv6_sid *sid; ++ ++ if (args->event != NB_EV_APPLY) ++ return NB_OK; ++ ++ sid = nb_running_unset_entry(args->dnode); ++ listnode_delete(srv6_sids, sid); ++ static_srv6_sid_del(sid); ++ ++ return NB_OK; ++} ++ ++void routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_sid_apply_finish( ++ struct nb_cb_apply_finish_args *args) ++{ ++ struct static_srv6_sid *sid; ++ struct static_srv6_locator *locator; ++ ++ sid = nb_running_get_entry(args->dnode, NULL, true); ++ ++ locator = static_srv6_locator_lookup(sid->locator_name); ++ if (!locator) { ++ zlog_info("Locator not found, trying to get locator information from zebra"); ++ static_zebra_srv6_manager_get_locator(sid->locator_name); ++ listnode_add(srv6_sids, sid); ++ return; ++ } ++ ++ sid->locator = locator; ++ ++ listnode_add(srv6_sids, sid); ++ static_zebra_request_srv6_sid(sid); ++} ++ ++/* ++ * XPath: ++ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/segment-routing/srv6/locators/locator/local-sids/sid/behavior ++ */ ++int routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_sid_behavior_modify( ++ struct nb_cb_modify_args *args) ++{ ++ struct static_srv6_sid *sid; ++ ++ if (args->event != NB_EV_APPLY) ++ return NB_OK; ++ ++ sid = nb_running_get_entry(args->dnode, NULL, true); ++ sid->behavior = yang_dnode_get_enum(args->dnode, "../behavior"); ++ ++ return NB_OK; ++} ++ ++int routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_sid_behavior_destroy( ++ struct nb_cb_destroy_args *args) ++{ ++ return NB_OK; ++} ++ ++/* ++ * XPath: ++ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/segment-routing/srv6/locators/locator/local-sids/sid/vrf-name ++ */ ++int routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_sid_vrf_name_modify( ++ struct nb_cb_modify_args *args) ++{ ++ struct static_srv6_sid *sid; ++ ++ if (args->event != NB_EV_APPLY) ++ return NB_OK; ++ ++ sid = nb_running_get_entry(args->dnode, NULL, true); ++ strncpy(sid->attributes.vrf_name, yang_dnode_get_string(args->dnode, "../vrf-name"), sizeof(sid->attributes.vrf_name)); ++ ++ return NB_OK; ++} ++ ++int routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_sid_vrf_name_destroy( ++ struct nb_cb_destroy_args *args) ++{ ++ return NB_OK; ++} ++ ++/* ++ * XPath: ++ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/segment-routing/srv6/locators/locator/local-sids/sid/vrf-name ++ */ ++int routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_sid_locator_name_modify( ++ struct nb_cb_modify_args *args) ++{ ++ struct static_srv6_sid *sid; ++ ++ if (args->event != NB_EV_APPLY) ++ return NB_OK; ++ ++ sid = nb_running_get_entry(args->dnode, NULL, true); ++ strncpy(sid->locator_name, yang_dnode_get_string(args->dnode, "../locator-name"), sizeof(sid->locator_name)); ++ ++ return NB_OK; ++} ++ ++int routing_control_plane_protocols_control_plane_protocol_staticd_segment_routing_srv6_local_sids_sid_locator_name_destroy( ++ struct nb_cb_destroy_args *args) ++{ ++ return NB_OK; ++} +diff --git a/staticd/static_srv6.c b/staticd/static_srv6.c +new file mode 100644 +index 0000000000..89cfbe08b8 +--- /dev/null ++++ b/staticd/static_srv6.c +@@ -0,0 +1,217 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * STATICd - Segment Routing over IPv6 (SRv6) code ++ */ ++#include ++ ++#include "vrf.h" ++#include "nexthop.h" ++ ++#include "static_routes.h" ++#include "static_srv6.h" ++#include "static_vrf.h" ++#include "static_zebra.h" ++ ++/* ++ * List of SRv6 SIDs. ++ */ ++struct list *srv6_locators = NULL; ++struct list *srv6_sids = NULL; ++ ++DEFINE_MTYPE_STATIC(STATIC, STATIC_SRV6_LOCATOR, "Static SRv6 locator"); ++DEFINE_MTYPE_STATIC(STATIC, STATIC_SRV6_SID, "Static SRv6 SID"); ++ ++/* ++ * Convert SRv6 behavior to human-friendly string. ++ */ ++const char * ++static_srv6_sid_behavior2str(enum static_srv6_sid_behavior_t behavior) ++{ ++ switch (behavior) { ++ case STATIC_SRV6_SID_BEHAVIOR_END: ++ return "End"; ++ case STATIC_SRV6_SID_BEHAVIOR_END_X: ++ return "End.X"; ++ case STATIC_SRV6_SID_BEHAVIOR_END_DT6: ++ return "End.DT6"; ++ case STATIC_SRV6_SID_BEHAVIOR_END_DT4: ++ return "End.DT4"; ++ case STATIC_SRV6_SID_BEHAVIOR_END_DT46: ++ return "End.DT46"; ++ case STATIC_SRV6_SID_BEHAVIOR_UN: ++ return "uN"; ++ case STATIC_SRV6_SID_BEHAVIOR_UA: ++ return "uA"; ++ case STATIC_SRV6_SID_BEHAVIOR_UDT6: ++ return "uDT6"; ++ case STATIC_SRV6_SID_BEHAVIOR_UDT4: ++ return "uDT4"; ++ case STATIC_SRV6_SID_BEHAVIOR_UDT46: ++ return "uDT46"; ++ case STATIC_SRV6_SID_BEHAVIOR_UNSPEC: ++ return "unspec"; ++ } ++ ++ return "unspec"; ++} ++ ++/* ++ * When a VRF is enabled in the kernel, go through all the static SRv6 SIDs in ++ * the system that use this VRF (e.g., End.DT4 or End.DT6 SRv6 SIDs) and install ++ * them in the zebra RIB. ++ * ++ * enable_svrf -> the VRF being enabled ++ */ ++void static_fixup_vrf_srv6_sids(struct static_vrf *enable_svrf) ++{ ++ struct static_srv6_locator *locator; ++ struct static_srv6_sid *sid; ++ struct listnode *node1, *node2; ++ ++ if (!srv6_locators || !enable_svrf) ++ return; ++ ++ zlog_info("VRF %s enabled. Installing SIDs", enable_svrf->vrf->name); ++ ++ for (ALL_LIST_ELEMENTS_RO(srv6_locators, node1, locator)) { ++ /* iterate over the list of SRv6 SIDs and install the SIDs that use this ++ * VRF in the zebra RIB */ ++ zlog_info("Scanning locator %s", locator->name); ++ for (ALL_LIST_ELEMENTS_RO(srv6_sids, node2, sid)) { ++ zlog_info("Scanning SID %pFX, vrf %s", &sid->addr, sid->attributes.vrf_name); ++ if (!strcmp(sid->attributes.vrf_name, enable_svrf->vrf->name)) ++ static_zebra_srv6_sid_install(sid); ++ } ++ } ++} ++ ++/* ++ * When a VRF is disabled in the kernel, we call this function and it removes ++ * all the static SRv6 SIDs using this VRF from the zebra RIB (e.g., End.DT4 or ++ * End.DT6 SRv6 SIDs). ++ * ++ * disable_svrf - The VRF being disabled ++ */ ++void static_cleanup_vrf_srv6_sids(struct static_vrf *disable_svrf) ++{ ++ struct static_srv6_locator *locator; ++ struct static_srv6_sid *sid; ++ struct listnode *node1, *node2; ++ ++ if (!srv6_locators || !disable_svrf) ++ return; ++ ++ for (ALL_LIST_ELEMENTS_RO(srv6_locators, node1, locator)) { ++ /* iterate over the list of SRv6 SIDs and remove the SIDs that use this ++ * VRF from the zebra RIB */ ++ for (ALL_LIST_ELEMENTS_RO(srv6_sids, node2, sid)) { ++ if (!strcmp(sid->attributes.vrf_name, disable_svrf->vrf->name)) ++ static_zebra_srv6_sid_uninstall(sid); ++ } ++ } ++} ++ ++/* ++ * Allocate an SRv6 SID object and initialize the fields common to all the ++ * behaviors (i.e., SID address and behavor). ++ */ ++struct static_srv6_sid *static_srv6_sid_alloc(struct prefix_ipv6 *addr) ++{ ++ struct static_srv6_sid *sid = NULL; ++ ++ sid = XCALLOC(MTYPE_STATIC_SRV6_SID, sizeof(struct static_srv6_sid)); ++ sid->addr = *addr; ++ ++ return sid; ++} ++ ++void static_srv6_sid_free(struct static_srv6_sid *sid) ++{ ++ XFREE(MTYPE_STATIC_SRV6_SID, sid); ++} ++ ++struct static_srv6_locator *static_srv6_locator_lookup(const char *name) ++{ ++ struct static_srv6_locator *locator; ++ struct listnode *node; ++ ++ for (ALL_LIST_ELEMENTS_RO(srv6_locators, node, locator)) ++ if (!strncmp(name, locator->name, SRV6_LOCNAME_SIZE)) ++ return locator; ++ return NULL; ++} ++ ++/* ++ * Look-up an SRv6 SID in the list of SRv6 SIDs. ++ */ ++struct static_srv6_sid *static_srv6_sid_lookup(struct prefix_ipv6 *sid_addr) ++{ ++ struct static_srv6_locator *locator; ++ struct static_srv6_sid *sid; ++ struct listnode *node1, *node2; ++ ++ for (ALL_LIST_ELEMENTS_RO(srv6_locators, node1, locator)) ++ for (ALL_LIST_ELEMENTS_RO(srv6_sids, node2, sid)) ++ if (memcmp(&sid->addr, sid_addr, sizeof(struct prefix_ipv6)) == 0) ++ return sid; ++ ++ return NULL; ++} ++ ++struct static_srv6_locator *static_srv6_locator_alloc(const char *name) ++{ ++ struct static_srv6_locator *locator = NULL; ++ ++ locator = XCALLOC(MTYPE_STATIC_SRV6_LOCATOR, sizeof(struct static_srv6_locator)); ++ strlcpy(locator->name, name, sizeof(locator->name)); ++ ++ return locator; ++} ++ ++void static_srv6_locator_free(struct static_srv6_locator *locator) ++{ ++ if (locator) { ++ XFREE(MTYPE_STATIC_SRV6_LOCATOR, locator); ++ } ++} ++ ++void delete_static_srv6_locator(void *val) ++{ ++ static_srv6_locator_free((struct static_srv6_locator *)val); ++} ++ ++/* ++ * Remove an SRv6 SID from the zebra RIB (if it was previously installed) and ++ * release the memory previously allocated for the SID. ++ */ ++void static_srv6_sid_del(struct static_srv6_sid *sid) ++{ ++ // if (CHECK_FLAG(sid->flags, STATIC_FLAG_SRV6_SID_SENT_TO_ZEBRA)) ++ static_zebra_release_srv6_sid(sid); ++ static_zebra_srv6_sid_uninstall(sid); ++ ++ XFREE(MTYPE_STATIC_SRV6_SID, sid); ++} ++ ++void delete_static_srv6_sid(void *val) ++{ ++ static_srv6_sid_free((struct static_srv6_sid *)val); ++} ++ ++/* ++ * Initialize SRv6 data structures. ++ */ ++void static_srv6_init(void) ++{ ++ srv6_locators = list_new(); ++ srv6_sids = list_new(); ++} ++ ++/* ++ * Clean up all the SRv6 data structures. ++ */ ++void static_srv6_cleanup(void) ++{ ++ list_delete(&srv6_locators); ++ list_delete(&srv6_sids); ++} +\ No newline at end of file +diff --git a/staticd/static_srv6.h b/staticd/static_srv6.h +new file mode 100644 +index 0000000000..d9211d18a0 +--- /dev/null ++++ b/staticd/static_srv6.h +@@ -0,0 +1,125 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * STATICd - Segment Routing over IPv6 (SRv6) header ++ */ ++#ifndef __STATIC_SRV6_H__ ++#define __STATIC_SRV6_H__ ++ ++#include "vrf.h" ++#include "srv6.h" ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++/* ++ * The order for below macros should be in sync with ++ * yang model typedef srv6-behavior ++ */ ++enum static_srv6_sid_behavior_t { ++ STATIC_SRV6_SID_BEHAVIOR_UNSPEC = 0, ++ STATIC_SRV6_SID_BEHAVIOR_END = 1, ++ STATIC_SRV6_SID_BEHAVIOR_END_X = 2, ++ STATIC_SRV6_SID_BEHAVIOR_END_DT6 = 3, ++ STATIC_SRV6_SID_BEHAVIOR_END_DT4 = 4, ++ STATIC_SRV6_SID_BEHAVIOR_END_DT46 = 5, ++ STATIC_SRV6_SID_BEHAVIOR_UN = 6, ++ STATIC_SRV6_SID_BEHAVIOR_UA = 7, ++ STATIC_SRV6_SID_BEHAVIOR_UDT6 = 8, ++ STATIC_SRV6_SID_BEHAVIOR_UDT4 = 9, ++ STATIC_SRV6_SID_BEHAVIOR_UDT46 = 10, ++}; ++ ++/* Attributes for an SRv6 SID */ ++struct static_srv6_sid_attributes { ++ /* VRF name */ ++ char vrf_name[VRF_NAMSIZ]; ++ char ifname[IFNAMSIZ]; ++ struct in6_addr nh6; ++}; ++ ++/* Static SRv6 SID */ ++struct static_srv6_sid { ++ /* SRv6 SID address */ ++ struct prefix_ipv6 addr; ++ /* behavior bound to the SRv6 SID */ ++ enum static_srv6_sid_behavior_t behavior; ++ /* SID attributes */ ++ struct static_srv6_sid_attributes attributes; ++ ++ /* SRv6 SID flags */ ++ uint8_t flags; ++/* this SRv6 SID is valid and can be installed in the zebra RIB */ ++#define STATIC_FLAG_SRV6_SID_VALID (1 << 0) ++/* this SRv6 SID has been installed in the zebra RIB */ ++#define STATIC_FLAG_SRV6_SID_SENT_TO_ZEBRA (2 << 0) ++ ++ char locator_name[SRV6_LOCNAME_SIZE]; ++ struct static_srv6_locator *locator; ++}; ++ ++struct static_srv6_locator { ++ char name[SRV6_LOCNAME_SIZE]; ++ struct prefix_ipv6 prefix; ++ ++ /* ++ * Bit length of SRv6 locator described in ++ * draft-ietf-bess-srv6-services-05#section-3.2.1 ++ */ ++ uint8_t block_bits_length; ++ uint8_t node_bits_length; ++ uint8_t function_bits_length; ++ uint8_t argument_bits_length; ++ ++ uint8_t flags; ++#define SRV6_LOCATOR_USID (1 << 0) /* The SRv6 Locator is a uSID Locator */ ++ ++}; ++ ++/* List of SRv6 SIDs. */ ++extern struct list *srv6_locators; ++extern struct list *srv6_sids; ++ ++/* Allocate an SRv6 SID object and initialize its fields, SID address and ++ * behavor. */ ++extern struct static_srv6_sid * ++static_srv6_sid_alloc(struct prefix_ipv6 *addr); ++extern void ++static_srv6_sid_free(struct static_srv6_sid *sid); ++/* Look-up an SRv6 SID in the list of SRv6 SIDs. */ ++extern struct static_srv6_sid * ++static_srv6_sid_lookup(struct prefix_ipv6 *sid_addr); ++/* Remove an SRv6 SID from the zebra RIB (if it was previously installed) and ++ * release the memory previously allocated for the SID. */ ++extern void static_srv6_sid_del(struct static_srv6_sid *sid); ++ ++/* Convert SRv6 behavior to human-friendly string. */ ++const char * ++static_srv6_sid_behavior2str(enum static_srv6_sid_behavior_t action); ++ ++/* Initialize SRv6 data structures. */ ++extern void static_srv6_init(void); ++/* Clean up all the SRv6 data structures. */ ++extern void static_srv6_cleanup(void); ++ ++/* When a VRF is enabled by the kernel, go through all the static SRv6 SIDs in ++ * the system that use this VRF (e.g., End.DT4 or End.DT6 SRv6 SIDs) and install ++ * them in the zebra RIB. */ ++void static_fixup_vrf_srv6_sids(struct static_vrf *enable_svrf); ++/* When a VRF is shutdown by the kernel, we call this function and it removes ++ * all static SRv6 SIDs using this VRF from the zebra RIB (e.g., End.DT4 or ++ * End.DT6 SRv6 SIDs). */ ++void static_cleanup_vrf_srv6_sids(struct static_vrf *disable_svrf); ++ ++struct static_srv6_locator *static_srv6_locator_alloc(const char *name); ++void static_srv6_locator_free(struct static_srv6_locator *locator); ++struct static_srv6_locator *static_srv6_locator_lookup(const char *name); ++ ++void delete_static_srv6_sid(void *val); ++void delete_static_srv6_locator(void *val); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* __STATIC_SRV6_H__ */ +\ No newline at end of file +diff --git a/staticd/static_vrf.c b/staticd/static_vrf.c +index 710827a9ff..8106f06f30 100644 +--- a/staticd/static_vrf.c ++++ b/staticd/static_vrf.c +@@ -125,6 +125,11 @@ static int static_vrf_enable(struct vrf *vrf) + { + static_zebra_vrf_register(vrf); + static_fixup_vrf_ids(vrf); ++ ++ /* when a VRF is enabled in the kernel, go through all the static SRv6 ++ * SIDs that use this VRF and install them in the zebra RIB */ ++ static_fixup_vrf_srv6_sids(vrf->info); ++ + return 0; + } + +@@ -132,6 +137,11 @@ static int static_vrf_disable(struct vrf *vrf) + { + static_cleanup_vrf_ids(vrf); + static_zebra_vrf_unregister(vrf); ++ ++ /* when a VRF is disabled in the kernel, remove all the static SRv6 SIDs ++ * using this VRF from the zebra RIB */ ++ static_cleanup_vrf_srv6_sids(vrf->info); ++ + return 0; + } + +diff --git a/staticd/static_vty.c b/staticd/static_vty.c +index 07b8bc3d28..b0ecc36f0e 100644 +--- a/staticd/static_vty.c ++++ b/staticd/static_vty.c +@@ -27,6 +27,8 @@ + #include "static_debug.h" + #include "staticd/static_vty_clippy.c" + #include "static_nb.h" ++#include "static_srv6.h" ++#include "static_zebra.h" + + #define STATICD_STR "Static route daemon\n" + +@@ -1201,6 +1203,214 @@ DEFPY_YANG(ipv6_route_vrf, ipv6_route_vrf_cmd, + return static_route_nb_run(vty, &args); + } + ++DEFUN_NOSH (static_segment_routing, static_segment_routing_cmd, ++ "segment-routing", ++ "Segment Routing\n") ++{ ++ VTY_PUSH_CONTEXT_NULL(SEGMENT_ROUTING_NODE); ++ return CMD_SUCCESS; ++} ++ ++DEFUN_NOSH (static_srv6, static_srv6_cmd, ++ "srv6", ++ "Segment Routing SRv6\n") ++{ ++ VTY_PUSH_CONTEXT_NULL(SRV6_NODE); ++ return CMD_SUCCESS; ++} ++ ++DEFUN_YANG_NOSH (no_static_srv6, no_static_srv6_cmd, ++ "no srv6", ++ NO_STR ++ "Segment Routing SRv6\n") ++{ ++ char xpath[XPATH_MAXLEN]; ++ ++ snprintf(xpath, sizeof(xpath), "/frr-routing:routing/control-plane-protocols/control-plane-protocol[type='%s'][name='%s'][vrf='%s']/frr-staticd:staticd/segment-routing/srv6", ++ "frr-staticd:staticd", "staticd", VRF_DEFAULT_NAME); ++ ++ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); ++ ++ return nb_cli_apply_changes(vty, "%s", xpath); ++} ++ ++DEFUN_NOSH (static_srv6_sids, static_srv6_sids_cmd, ++ "static-sids", ++ "Segment Routing SRv6 SIDs\n") ++{ ++ VTY_PUSH_CONTEXT_NULL(SRV6_SIDS_NODE); ++ return CMD_SUCCESS; ++} ++ ++ ++static const char *seg6local_action2yang(uint32_t action) ++{ ++ switch (action) { ++ case STATIC_SRV6_SID_BEHAVIOR_UN: ++ return "un"; ++ case STATIC_SRV6_SID_BEHAVIOR_UA: ++ return "ua"; ++ case STATIC_SRV6_SID_BEHAVIOR_UDT6: ++ return "udt6"; ++ case STATIC_SRV6_SID_BEHAVIOR_UDT4: ++ return "udt4"; ++ case STATIC_SRV6_SID_BEHAVIOR_UDT46: ++ return "udt46"; ++ } ++ return "unspec"; ++} ++ ++DEFPY_YANG(srv6_sid, srv6_sid_cmd, ++ "sid X:X::X:X/M [locator NAME$locator_name] behavior ", ++ "Configure SRv6 SID\n" ++ "Specify SRv6 SID\n" ++ "Locator name\n" ++ "Specify Locator name\n" ++ "Specify SRv6 SID behavior\n" ++ "Apply the code to a uN SID\n" ++ "Apply the code to an uDT6 SID\n" ++ "Configure VRF name\n" ++ "Specify VRF name\n" ++ "Apply the code to an uDT4 SID\n" ++ "Configure VRF name\n" ++ "Specify VRF name\n" ++ "Apply the code to an uDT46 SID\n" ++ "Configure VRF name\n" ++ "Specify VRF name\n") ++{ ++ enum static_srv6_sid_behavior_t behavior = STATIC_SRV6_SID_BEHAVIOR_UNSPEC; ++ int idx = 0; ++ const char *vrf_name = NULL; ++ char xpath_sid[XPATH_MAXLEN]; ++ char xpath_behavior[XPATH_MAXLEN]; ++ char xpath_vrf_name[XPATH_MAXLEN]; ++ char xpath_locator_name[XPATH_MAXLEN]; ++ ++ if (argv_find(argv, argc, "uN", &idx)) { ++ behavior = STATIC_SRV6_SID_BEHAVIOR_UN; ++ } else if (argv_find(argv, argc, "uDT6", &idx)) { ++ behavior = STATIC_SRV6_SID_BEHAVIOR_UDT6; ++ vrf_name = argv[idx + 2]->arg; ++ } else if (argv_find(argv, argc, "uDT4", &idx)) { ++ behavior = STATIC_SRV6_SID_BEHAVIOR_UDT4; ++ vrf_name = argv[idx + 2]->arg; ++ } else if (argv_find(argv, argc, "uDT46", &idx)) { ++ behavior = STATIC_SRV6_SID_BEHAVIOR_UDT46; ++ vrf_name = argv[idx + 2]->arg; ++ } ++ ++ snprintf(xpath_sid, sizeof(xpath_sid), "/frr-routing:routing/control-plane-protocols/control-plane-protocol[type='%s'][name='%s'][vrf='%s']/frr-staticd:staticd/segment-routing/srv6/local-sids/sid[sid='%s']", ++ "frr-staticd:staticd", "staticd", VRF_DEFAULT_NAME, sid_str); ++ ++ snprintf(xpath_behavior, sizeof(xpath_behavior), "/frr-routing:routing/control-plane-protocols/control-plane-protocol[type='%s'][name='%s'][vrf='%s']/frr-staticd:staticd/segment-routing/srv6/local-sids/sid[sid='%s']/behavior", ++ "frr-staticd:staticd", "staticd", VRF_DEFAULT_NAME, sid_str); ++ ++ nb_cli_enqueue_change(vty, xpath_sid, ++ NB_OP_CREATE, sid_str); ++ ++ nb_cli_enqueue_change(vty, xpath_behavior, ++ NB_OP_MODIFY, seg6local_action2yang(behavior)); ++ ++ if (vrf_name) { ++ snprintf(xpath_vrf_name, sizeof(xpath_vrf_name), "/frr-routing:routing/control-plane-protocols/control-plane-protocol[type='%s'][name='%s'][vrf='%s']/frr-staticd:staticd/segment-routing/srv6/local-sids/sid[sid='%s']/vrf-name", ++ "frr-staticd:staticd", "staticd", VRF_DEFAULT_NAME, sid_str); ++ ++ nb_cli_enqueue_change(vty, xpath_vrf_name, ++ NB_OP_MODIFY, vrf_name); ++ } ++ ++ if (locator_name) { ++ snprintf(xpath_locator_name, sizeof(xpath_locator_name), "/frr-routing:routing/control-plane-protocols/control-plane-protocol[type='%s'][name='%s'][vrf='%s']/frr-staticd:staticd/segment-routing/srv6/local-sids/sid[sid='%s']/locator-name", ++ "frr-staticd:staticd", "staticd", VRF_DEFAULT_NAME, sid_str); ++ ++ nb_cli_enqueue_change(vty, xpath_locator_name, ++ NB_OP_MODIFY, locator_name); ++ } ++ ++ return nb_cli_apply_changes(vty, "%s", xpath_sid); ++} ++ ++DEFPY_YANG(no_srv6_sid, no_srv6_sid_cmd, ++ "no sid X:X::X:X/M [locator NAME$locator_name] behavior ", ++ NO_STR ++ "Configure SRv6 SID\n" ++ "Specify SRv6 SID\n" ++ "Locator name\n" ++ "Specify Locator name\n" ++ "Specify SRv6 SID behavior\n" ++ "Apply the code to a uN SID\n" ++ "Apply the code to an uDT6 SID\n" ++ "Configure VRF name\n" ++ "Specify VRF name\n" ++ "Apply the code to an uDT4 SID\n" ++ "Configure VRF name\n" ++ "Specify VRF name\n" ++ "Apply the code to an uDT46 SID\n" ++ "Configure VRF name\n" ++ "Specify VRF name\n") ++{ ++ char xpath[XPATH_MAXLEN + 37]; ++ ++ snprintf(xpath, sizeof(xpath), "/frr-routing:routing/control-plane-protocols/control-plane-protocol[type='%s'][name='%s'][vrf='%s']/frr-staticd:staticd/segment-routing/srv6/local-sids/sid[sid='%s']", ++ "frr-staticd:staticd", "staticd", VRF_DEFAULT_NAME, sid_str); ++ ++ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); ++ ++ return nb_cli_apply_changes(vty, NULL); ++} ++ ++static int static_sr_config_write(struct vty *vty) ++{ ++ int write = 0; ++ struct lyd_node *dnode; ++ char xpath[XPATH_MAXLEN]; ++ ++ vty_out(vty, "!\n"); ++ vty_out(vty, "segment-routing\n"); ++ vty_out(vty, " srv6\n"); ++ vty_out(vty, " static-sids\n"); ++ ++ snprintf(xpath, sizeof(xpath), "/frr-routing:routing/control-plane-protocols/control-plane-protocol[type='%s'][name='%s'][vrf='%s']/frr-staticd:staticd/segment-routing/srv6/local-sids", ++ "frr-staticd:staticd", "staticd", VRF_DEFAULT_NAME); ++ ++ dnode = yang_dnode_get(running_config->dnode, xpath); ++ if (dnode) { ++ nb_cli_show_dnode_cmds(vty, dnode, false); ++ write++; ++ } ++ ++ vty_out(vty, " exit\n"); ++ vty_out(vty, " !\n"); ++ vty_out(vty, " exit\n"); ++ vty_out(vty, " !\n"); ++ vty_out(vty, "exit\n"); ++ vty_out(vty, "!\n"); ++ ++ return write; ++} ++ ++static struct cmd_node sr_node = { ++ .name = "sr", ++ .node = SEGMENT_ROUTING_NODE, ++ .parent_node = CONFIG_NODE, ++ .prompt = "%s(config-sr)# ", ++ .config_write = static_sr_config_write, ++}; ++ ++static struct cmd_node srv6_node = { ++ .name = "srv6", ++ .node = SRV6_NODE, ++ .parent_node = SEGMENT_ROUTING_NODE, ++ .prompt = "%s(config-srv6)# ", ++}; ++ ++static struct cmd_node srv6_sids_node = { ++ .name = "srv6-sids", ++ .node = SRV6_SIDS_NODE, ++ .parent_node = SRV6_NODE, ++ .prompt = "%s(config-srv6-sids)# ", ++}; ++ + #ifdef INCLUDE_MGMTD_CMDDEFS_ONLY + + static void static_cli_show(struct vty *vty, const struct lyd_node *dnode, +@@ -1545,6 +1755,101 @@ static int static_path_list_cli_cmp(const struct lyd_node *dnode1, + return (int)distance1 - (int)distance2; + } + ++static void static_segment_routing_cli_show(struct vty *vty, const struct lyd_node *dnode, ++ bool show_defaults) ++{ ++ vty_out(vty, "segment-routing\n"); ++} ++ ++static void static_segment_routing_cli_show_end(struct vty *vty, const struct lyd_node *dnode) ++{ ++ vty_out(vty, "exit\n"); ++} ++ ++static void static_srv6_cli_show(struct vty *vty, const struct lyd_node *dnode, ++ bool show_defaults) ++{ ++ vty_out(vty, " srv6\n"); ++} ++ ++static void static_srv6_cli_show_end(struct vty *vty, const struct lyd_node *dnode) ++{ ++ vty_out(vty, " exit\n"); ++} ++ ++static void static_sids_cli_show(struct vty *vty, const struct lyd_node *dnode, ++ bool show_defaults) ++{ ++ vty_out(vty, " static-sids\n"); ++} ++ ++static void static_sids_cli_show_end(struct vty *vty, const struct lyd_node *dnode) ++{ ++ vty_out(vty, " exit\n"); ++} ++ ++static void srv6_sid_cli_show(struct vty *vty, const struct lyd_node *sid, ++ bool show_defaults) ++{ ++ enum static_srv6_sid_behavior_t srv6_behavior; ++ struct prefix_ipv6 sid_value; ++ ++ yang_dnode_get_ipv6p(&sid_value, sid, "sid"); ++ ++ vty_out(vty, " sid %pFX", &sid_value); ++ if (yang_dnode_exists(sid, "locator-name")) ++ vty_out(vty, " locator %s", yang_dnode_get_string(sid, "locator-name")); ++ ++ srv6_behavior = yang_dnode_get_enum(sid, "behavior"); ++ switch(srv6_behavior) { ++ case STATIC_SRV6_SID_BEHAVIOR_END: ++ vty_out(vty, " behavior End"); ++ break; ++ case STATIC_SRV6_SID_BEHAVIOR_END_X: ++ vty_out(vty, " behavior End.X"); ++ break; ++ case STATIC_SRV6_SID_BEHAVIOR_END_DT6: ++ vty_out(vty, " behavior End.DT6"); ++ break; ++ case STATIC_SRV6_SID_BEHAVIOR_END_DT4: ++ vty_out(vty, " behavior End.DT4"); ++ break; ++ case STATIC_SRV6_SID_BEHAVIOR_END_DT46: ++ vty_out(vty, " behavior End.DT46"); ++ break; ++ case STATIC_SRV6_SID_BEHAVIOR_UN: ++ vty_out(vty, " behavior uN"); ++ break; ++ case STATIC_SRV6_SID_BEHAVIOR_UA: ++ vty_out(vty, " behavior uA"); ++ break; ++ case STATIC_SRV6_SID_BEHAVIOR_UDT6: ++ vty_out(vty, " behavior uDT6"); ++ break; ++ case STATIC_SRV6_SID_BEHAVIOR_UDT4: ++ vty_out(vty, " behavior uDT4"); ++ break; ++ case STATIC_SRV6_SID_BEHAVIOR_UDT46: ++ vty_out(vty, " behavior uDT46"); ++ break; ++ case STATIC_SRV6_SID_BEHAVIOR_UNSPEC: ++ vty_out(vty, " behavior unknown"); ++ break; ++ } ++ ++ if (yang_dnode_exists(sid, "vrf-name")) ++ vty_out(vty, " vrf %s", yang_dnode_get_string(sid, "vrf-name")); ++ ++ vty_out(vty, "\n"); ++} ++ ++static void static_srv6_sid_cli_show(struct vty *vty, ++ const struct lyd_node *dnode, ++ bool show_defaults) ++{ ++ srv6_sid_cli_show(vty, dnode, show_defaults); ++} ++ + const struct frr_yang_module_info frr_staticd_cli_info = { + .name = "frr-staticd", + .ignore_cfg_cbs = true, +@@ -1594,6 +1899,12 @@ const struct frr_yang_module_info frr_staticd_cli_info = { + .cli_cmp = static_nexthop_cli_cmp, + } + }, ++ { ++ .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/segment-routing/srv6/local-sids/sid", ++ .cbs = { ++ .cli_show = static_srv6_sid_cli_show, ++ } ++ }, + { + .xpath = NULL, + }, +@@ -1653,6 +1964,7 @@ void static_vty_init(void) + install_element(CONFIG_NODE, &debug_staticd_cmd); + install_element(ENABLE_NODE, &show_debugging_static_cmd); + install_element(ENABLE_NODE, &staticd_show_bfd_routes_cmd); ++ + #else /* else INCLUDE_MGMTD_CMDDEFS_ONLY */ + install_element(CONFIG_NODE, &ip_mroute_dist_cmd); + +@@ -1671,6 +1983,23 @@ void static_vty_init(void) + install_element(VRF_NODE, &ipv6_route_vrf_cmd); + #endif /* ifndef INCLUDE_MGMTD_CMDDEFS_ONLY */ + ++ install_node(&sr_node); ++ install_node(&srv6_node); ++ install_node(&srv6_sids_node); ++ install_default(SEGMENT_ROUTING_NODE); ++ install_default(SRV6_NODE); ++ install_default(SRV6_SIDS_NODE); ++ ++ install_element(CONFIG_NODE, &static_segment_routing_cmd); ++ install_element(SEGMENT_ROUTING_NODE, &static_srv6_cmd); ++ install_element(SEGMENT_ROUTING_NODE, &no_static_srv6_cmd); ++ install_element(SRV6_NODE, &static_srv6_sids_cmd); ++ install_element(SRV6_SIDS_NODE, &srv6_sid_cmd); ++ install_element(SRV6_SIDS_NODE, &no_srv6_sid_cmd); ++ ++ install_element(CONFIG_NODE, &srv6_sid_cmd); ++ install_element(CONFIG_NODE, &no_srv6_sid_cmd); ++ + #ifndef INCLUDE_MGMTD_CMDDEFS_ONLY + mgmt_be_client_lib_vty_init(); + #endif +diff --git a/staticd/static_zebra.c b/staticd/static_zebra.c +index d76befc131..72aeeb1f02 100644 +--- a/staticd/static_zebra.c ++++ b/staticd/static_zebra.c +@@ -30,6 +30,9 @@ + #include "static_nht.h" + #include "static_vty.h" + #include "static_debug.h" ++#include "zclient.h" ++#include "static_srv6.h" ++#include "lib_errors.h" + + DEFINE_MTYPE_STATIC(STATIC, STATIC_NHT_DATA, "Static Nexthop tracking data"); + PREDECL_HASH(static_nht_hash); +@@ -530,10 +533,639 @@ extern void static_zebra_route_add(struct static_path *pn, bool install) + zclient, &api); + } + ++/** ++ * Send SRv6 SID to ZEBRA for installation or deletion. ++ * ++ * @param cmd ZEBRA_ROUTE_ADD or ZEBRA_ROUTE_DELETE ++ * @param sid SRv6 SID to install or delete ++ * @param prefixlen Prefix length ++ * @param oif Outgoing interface ++ * @param action SID action ++ * @param context SID context ++ */ ++static void static_zebra_send_localsid(int cmd, const struct in6_addr *sid, ++ uint16_t prefixlen, ifindex_t oif, ++ enum seg6local_action_t action, ++ const struct seg6local_context *context) ++{ ++ struct prefix_ipv6 p = {}; ++ struct zapi_route api = {}; ++ struct zapi_nexthop *znh; ++ ++ if (cmd != ZEBRA_ROUTE_ADD && cmd != ZEBRA_ROUTE_DELETE) { ++ flog_warn(EC_LIB_DEVELOPMENT, "%s: wrong ZEBRA command", ++ __func__); ++ return; ++ } ++ ++ if (prefixlen > IPV6_MAX_BITLEN) { ++ flog_warn(EC_LIB_DEVELOPMENT, "%s: wrong prefixlen %u", ++ __func__, prefixlen); ++ return; ++ } ++ ++ zlog_info(" |- %s SRv6 SID %pI6 behavior %s", ++ cmd == ZEBRA_ROUTE_ADD ? "Add" : "Delete", sid, ++ seg6local_action2str(action)); ++ ++ p.family = AF_INET6; ++ p.prefixlen = prefixlen; ++ p.prefix = *sid; ++ ++ api.vrf_id = VRF_DEFAULT; ++ api.type = ZEBRA_ROUTE_STATIC; ++ api.instance = 0; ++ api.safi = SAFI_UNICAST; ++ memcpy(&api.prefix, &p, sizeof(p)); ++ ++ if (cmd == ZEBRA_ROUTE_DELETE) ++ return (void)zclient_route_send(ZEBRA_ROUTE_DELETE, zclient, ++ &api); ++ ++ SET_FLAG(api.flags, ZEBRA_FLAG_ALLOW_RECURSION); ++ SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); ++ ++ znh = &api.nexthops[0]; ++ ++ memset(znh, 0, sizeof(*znh)); ++ ++ znh->type = NEXTHOP_TYPE_IFINDEX; ++ znh->ifindex = oif; ++ SET_FLAG(znh->flags, ZAPI_NEXTHOP_FLAG_SEG6LOCAL); ++ znh->seg6local_action = action; ++ memcpy(&znh->seg6local_ctx, context, sizeof(struct seg6local_context)); ++ ++ api.nexthop_num = 1; ++ ++ zclient_route_send(ZEBRA_ROUTE_ADD, zclient, &api); ++} ++ ++/** ++ * Install SRv6 SID in the forwarding plane through Zebra. ++ * ++ * @param sid SRv6 SID ++ */ ++void static_zebra_srv6_sid_install(struct static_srv6_sid *sid) ++{ ++ enum seg6local_action_t action = ZEBRA_SEG6_LOCAL_ACTION_UNSPEC; ++ uint16_t prefixlen = IPV6_MAX_BITLEN; ++ struct seg6local_context ctx = {}; ++ struct interface *ifp = NULL; ++ struct vrf *vrf; ++ ++ if (!sid) ++ return; ++ ++ zlog_info("setting SRv6 SID %pFX", ++ &sid->addr); ++ ++ switch (sid->behavior) { ++ case STATIC_SRV6_SID_BEHAVIOR_END: ++ action = ZEBRA_SEG6_LOCAL_ACTION_END; ++ prefixlen = IPV6_MAX_BITLEN; ++ break; ++ case STATIC_SRV6_SID_BEHAVIOR_UN: ++ action = ZEBRA_SEG6_LOCAL_ACTION_END; ++ prefixlen = sid->locator->block_bits_length + ++ sid->locator->node_bits_length; ++ SET_SRV6_FLV_OP(ctx.flv.flv_ops, ++ ZEBRA_SEG6_LOCAL_FLV_OP_NEXT_CSID); ++ ctx.flv.lcblock_len = sid->locator->block_bits_length; ++ ctx.flv.lcnode_func_len = sid->locator->node_bits_length; ++ break; ++ case STATIC_SRV6_SID_BEHAVIOR_END_DT6: ++ case STATIC_SRV6_SID_BEHAVIOR_UDT6: ++ action = ZEBRA_SEG6_LOCAL_ACTION_END_DT6; ++ prefixlen = IPV6_MAX_BITLEN; ++ vrf = vrf_lookup_by_name(sid->attributes.vrf_name); ++ if (!vrf || !CHECK_FLAG(vrf->status, VRF_ACTIVE)) { ++ zlog_warn("Inactive vrf"); ++ return; ++ } ++ ctx.table = vrf->data.l.table_id; ++ ifp = if_get_vrf_loopback(vrf->vrf_id); ++ if (!ifp) { ++ zlog_warn("failed to get interface"); ++ return; ++ } ++ break; ++ case STATIC_SRV6_SID_BEHAVIOR_END_DT4: ++ case STATIC_SRV6_SID_BEHAVIOR_UDT4: ++ action = ZEBRA_SEG6_LOCAL_ACTION_END_DT4; ++ prefixlen = IPV6_MAX_BITLEN; ++ vrf = vrf_lookup_by_name(sid->attributes.vrf_name); ++ if (!vrf || !CHECK_FLAG(vrf->status, VRF_ACTIVE)) { ++ zlog_warn("Inactive vrf"); ++ return; ++ } ++ ctx.table = vrf->data.l.table_id; ++ ifp = if_get_vrf_loopback(vrf->vrf_id); ++ if (!ifp) { ++ zlog_warn("failed to get interface"); ++ return; ++ } ++ break; ++ case STATIC_SRV6_SID_BEHAVIOR_END_DT46: ++ case STATIC_SRV6_SID_BEHAVIOR_UDT46: ++ action = ZEBRA_SEG6_LOCAL_ACTION_END_DT46; ++ prefixlen = IPV6_MAX_BITLEN; ++ vrf = vrf_lookup_by_name(sid->attributes.vrf_name); ++ if (!vrf || !CHECK_FLAG(vrf->status, VRF_ACTIVE)) { ++ zlog_warn("Inactive vrf"); ++ return; ++ } ++ ctx.table = vrf->data.l.table_id; ++ ifp = if_get_vrf_loopback(vrf->vrf_id); ++ if (!ifp) { ++ zlog_warn("failed to get interface"); ++ return; ++ } ++ break; ++ case STATIC_SRV6_SID_BEHAVIOR_UNSPEC: ++ zlog_warn("unsupported behavior: %u", sid->behavior); ++ break; ++ } ++ ++ ctx.block_len = sid->locator->block_bits_length; ++ ctx.node_len = sid->locator->node_bits_length; ++ ctx.function_len = sid->locator->function_bits_length; ++ ctx.argument_len = sid->locator->argument_bits_length; ++ ++ /* Attach the SID to the SRv6 interface */ ++ if (!ifp) { ++ ifp = if_lookup_by_name("sr0", VRF_DEFAULT); ++ if (!ifp) { ++ zlog_warn( ++ "Failed to install SRv6 SID %pFX: %s interface not found", ++ &sid->addr, "sr0"); ++ return; ++ } ++ } ++ ++ /* Send the SID to zebra */ ++ static_zebra_send_localsid(ZEBRA_ROUTE_ADD, &sid->addr.prefix, sid->addr.prefixlen, ++ ifp->ifindex, action, &ctx); ++} ++ ++void static_zebra_srv6_sid_uninstall(struct static_srv6_sid *sid) ++{ ++ enum seg6local_action_t action = ZEBRA_SEG6_LOCAL_ACTION_UNSPEC; ++ struct interface *ifp = NULL; ++ struct seg6local_context ctx = {}; ++ uint16_t prefixlen = IPV6_MAX_BITLEN; ++ struct vrf *vrf; ++ ++ if (!sid) ++ return; ++ ++ zlog_info("delete SID %pFX", &sid->addr); ++ ++ switch (sid->behavior) { ++ case STATIC_SRV6_SID_BEHAVIOR_END: ++ prefixlen = IPV6_MAX_BITLEN; ++ break; ++ case STATIC_SRV6_SID_BEHAVIOR_UN: ++ prefixlen = sid->locator->block_bits_length + ++ sid->locator->node_bits_length; ++ break; ++ case STATIC_SRV6_SID_BEHAVIOR_END_DT6: ++ case STATIC_SRV6_SID_BEHAVIOR_UDT6: ++ prefixlen = IPV6_MAX_BITLEN; ++ vrf = vrf_lookup_by_name(sid->attributes.vrf_name); ++ if (!vrf || !CHECK_FLAG(vrf->status, VRF_ACTIVE)) { ++ zlog_warn("Inactive vrf"); ++ return; ++ } ++ ifp = if_get_vrf_loopback(vrf->vrf_id); ++ if (!ifp) { ++ zlog_warn("failed to get interface"); ++ return; ++ } ++ break; ++ case STATIC_SRV6_SID_BEHAVIOR_END_DT4: ++ case STATIC_SRV6_SID_BEHAVIOR_UDT4: ++ prefixlen = IPV6_MAX_BITLEN; ++ vrf = vrf_lookup_by_name(sid->attributes.vrf_name); ++ if (!vrf || !CHECK_FLAG(vrf->status, VRF_ACTIVE)) { ++ zlog_warn("Inactive vrf"); ++ return; ++ } ++ ifp = if_get_vrf_loopback(vrf->vrf_id); ++ if (!ifp) { ++ zlog_warn("failed to get interface"); ++ return; ++ } ++ break; ++ case STATIC_SRV6_SID_BEHAVIOR_END_DT46: ++ case STATIC_SRV6_SID_BEHAVIOR_UDT46: ++ prefixlen = IPV6_MAX_BITLEN; ++ vrf = vrf_lookup_by_name(sid->attributes.vrf_name); ++ if (!vrf || !CHECK_FLAG(vrf->status, VRF_ACTIVE)) { ++ zlog_warn("Inactive vrf"); ++ return; ++ } ++ ifp = if_get_vrf_loopback(vrf->vrf_id); ++ if (!ifp) { ++ zlog_warn("failed to get interface"); ++ return; ++ } ++ break; ++ case STATIC_SRV6_SID_BEHAVIOR_UNSPEC: ++ zlog_warn("unsupported behavior: %u", sid->behavior); ++ break; ++ } ++ ++ /* The SID is attached to the SRv6 interface */ ++ if (!ifp) { ++ ifp = if_lookup_by_name("sr0", VRF_DEFAULT); ++ if (!ifp) { ++ zlog_warn("%s interface not found: nothing to uninstall", ++ "sr0"); ++ return; ++ } ++ } ++ ++ ctx.block_len = sid->locator->block_bits_length; ++ ctx.node_len = sid->locator->node_bits_length; ++ ctx.function_len = sid->locator->function_bits_length; ++ ctx.argument_len = sid->locator->argument_bits_length; ++ ++ zlog_info("delete SID %pFX", ++ &sid->addr); ++ ++ static_zebra_send_localsid(ZEBRA_ROUTE_DELETE, &sid->addr.prefix, sid->addr.prefixlen, ++ ifp->ifindex, action, &ctx); ++} ++ ++extern void static_zebra_request_srv6_sid(struct static_srv6_sid *sid) ++{ ++ struct srv6_sid_ctx ctx = {}; ++ int ret = 0; ++ struct vrf *vrf; ++ ++ if (!sid) ++ return; ++ ++ /* convert `static_srv6_sid_behavior_t` to `seg6local_action_t` */ ++ switch (sid->behavior) { ++ case STATIC_SRV6_SID_BEHAVIOR_UNSPEC: ++ ctx.behavior = ZEBRA_SEG6_LOCAL_ACTION_UNSPEC; ++ break; ++ case STATIC_SRV6_SID_BEHAVIOR_END: ++ case STATIC_SRV6_SID_BEHAVIOR_UN: ++ ctx.behavior = ZEBRA_SEG6_LOCAL_ACTION_END; ++ break; ++ case STATIC_SRV6_SID_BEHAVIOR_END_DT6: ++ case STATIC_SRV6_SID_BEHAVIOR_UDT6: ++ ctx.behavior = ZEBRA_SEG6_LOCAL_ACTION_END_DT6; ++ /* process SRv6 SID attributes */ ++ /* generate table ID from the VRF name, if configured */ ++ if (sid->attributes.vrf_name[0] != '\0') { ++ vrf = vrf_lookup_by_name(sid->attributes.vrf_name); ++ if (!vrf || !CHECK_FLAG(vrf->status, VRF_ACTIVE)) ++ return; ++ ctx.vrf_id = vrf->vrf_id; ++ } ++ ++ break; ++ case STATIC_SRV6_SID_BEHAVIOR_END_DT4: ++ case STATIC_SRV6_SID_BEHAVIOR_UDT4: ++ ctx.behavior = ZEBRA_SEG6_LOCAL_ACTION_END_DT4; ++ /* process SRv6 SID attributes */ ++ /* generate table ID from the VRF name, if configured */ ++ if (sid->attributes.vrf_name[0] != '\0') { ++ vrf = vrf_lookup_by_name(sid->attributes.vrf_name); ++ if (!vrf || !CHECK_FLAG(vrf->status, VRF_ACTIVE)) ++ return; ++ ctx.vrf_id = vrf->vrf_id; ++ } ++ ++ break; ++ case STATIC_SRV6_SID_BEHAVIOR_END_DT46: ++ case STATIC_SRV6_SID_BEHAVIOR_UDT46: ++ ctx.behavior = ZEBRA_SEG6_LOCAL_ACTION_END_DT46; ++ /* process SRv6 SID attributes */ ++ /* generate table ID from the VRF name, if configured */ ++ if (sid->attributes.vrf_name[0] != '\0') { ++ vrf = vrf_lookup_by_name(sid->attributes.vrf_name); ++ if (!vrf || !CHECK_FLAG(vrf->status, VRF_ACTIVE)) ++ return; ++ ctx.vrf_id = vrf->vrf_id; ++ } ++ ++ break; ++ } ++ ++ zlog_info("calling srv6_manager_get_sid"); ++ ++ /* install the SRv6 SID in the zebra RIB */ ++ ret = srv6_manager_get_sid(zclient, &ctx, &sid->addr.prefix, sid->locator->name, NULL); ++ if (ret < 0) { ++ zlog_warn("%s: error getting SRv6 SID!", __func__); ++ } ++} ++ ++extern void static_zebra_release_srv6_sid(struct static_srv6_sid *sid) ++{ ++ struct srv6_sid_ctx ctx = {}; ++ struct vrf *vrf; ++ int ret = 0; ++ ++ if (!sid) ++ return; ++ ++ /* convert `static_srv6_sid_behavior_t` to `seg6local_action_t` */ ++ switch (sid->behavior) { ++ case STATIC_SRV6_SID_BEHAVIOR_UNSPEC: ++ ctx.behavior = ZEBRA_SEG6_LOCAL_ACTION_UNSPEC; ++ break; ++ case STATIC_SRV6_SID_BEHAVIOR_END: ++ case STATIC_SRV6_SID_BEHAVIOR_UN: ++ ctx.behavior = ZEBRA_SEG6_LOCAL_ACTION_END; ++ break; ++ case STATIC_SRV6_SID_BEHAVIOR_END_DT6: ++ case STATIC_SRV6_SID_BEHAVIOR_UDT6: ++ ctx.behavior = ZEBRA_SEG6_LOCAL_ACTION_END_DT6; ++ /* process SRv6 SID attributes */ ++ /* generate table ID from the VRF name, if configured */ ++ if (sid->attributes.vrf_name[0] != '\0') { ++ vrf = vrf_lookup_by_name(sid->attributes.vrf_name); ++ if (!vrf || !CHECK_FLAG(vrf->status, VRF_ACTIVE)) ++ return; ++ ctx.vrf_id = vrf->vrf_id; ++ } ++ ++ break; ++ case STATIC_SRV6_SID_BEHAVIOR_END_DT4: ++ case STATIC_SRV6_SID_BEHAVIOR_UDT4: ++ ctx.behavior = ZEBRA_SEG6_LOCAL_ACTION_END_DT4; ++ /* process SRv6 SID attributes */ ++ /* generate table ID from the VRF name, if configured */ ++ if (sid->attributes.vrf_name[0] != '\0') { ++ vrf = vrf_lookup_by_name(sid->attributes.vrf_name); ++ if (!vrf || !CHECK_FLAG(vrf->status, VRF_ACTIVE)) ++ return; ++ ctx.vrf_id = vrf->vrf_id; ++ } ++ ++ break; ++ case STATIC_SRV6_SID_BEHAVIOR_END_DT46: ++ case STATIC_SRV6_SID_BEHAVIOR_UDT46: ++ ctx.behavior = ZEBRA_SEG6_LOCAL_ACTION_END_DT46; ++ /* process SRv6 SID attributes */ ++ /* generate table ID from the VRF name, if configured */ ++ if (sid->attributes.vrf_name[0] != '\0') { ++ vrf = vrf_lookup_by_name(sid->attributes.vrf_name); ++ if (!vrf || !CHECK_FLAG(vrf->status, VRF_ACTIVE)) ++ return; ++ ctx.vrf_id = vrf->vrf_id; ++ } ++ ++ break; ++ } ++ ++ /* remove the SRv6 SID from the zebra RIB */ ++ ret = srv6_manager_release_sid(zclient, &ctx); ++ if (ret == ZCLIENT_SEND_FAILURE) ++ flog_err(EC_LIB_ZAPI_SOCKET, ++ "zclient_send_get_srv6_sid() delete failed: %s", ++ safe_strerror(errno)); ++} ++ ++/** ++ * Ask the SRv6 Manager (zebra) about a specific locator ++ * ++ * @param name Locator name ++ * @return 0 on success, -1 otherwise ++ */ ++int static_zebra_srv6_manager_get_locator(const char *name) ++{ ++ if (!name) ++ return -1; ++ ++ /* ++ * Send the Get Locator request to the SRv6 Manager and return the ++ * result ++ */ ++ return srv6_manager_get_locator(zclient, name); ++} ++ ++static void request_srv6_sids(struct static_srv6_locator *locator) ++{ ++ struct static_srv6_sid *sid; ++ struct listnode *node; ++ ++ for (ALL_LIST_ELEMENTS_RO(srv6_sids, node, sid)) { ++ if (sid->locator == locator) ++ static_zebra_request_srv6_sid(sid); ++ } ++} ++ ++/** ++ * Internal function to process an SRv6 locator ++ * ++ * @param locator The locator to be processed ++ */ ++static int static_zebra_process_srv6_locator_internal(struct srv6_locator *locator) ++{ ++ struct static_srv6_locator *loc; ++ struct listnode *node; ++ struct static_srv6_sid *sid; ++ ++ if (!locator) ++ return -1; ++ ++ zlog_info("%s: Received SRv6 locator %s %pFX, loc-block-len=%u, loc-node-len=%u func-len=%u, arg-len=%u", ++ __func__, locator->name, &locator->prefix, ++ locator->block_bits_length, locator->node_bits_length, ++ locator->function_bits_length, locator->argument_bits_length); ++ ++ loc = static_srv6_locator_alloc(locator->name); ++ ++ zlog_info("SRv6 locator (locator %s, prefix %pFX) set", ++ locator->name, &locator->prefix); ++ ++ /* Store the locator prefix */ ++ loc->prefix = locator->prefix; ++ loc->block_bits_length = locator->block_bits_length; ++ loc->node_bits_length = locator->node_bits_length; ++ loc->function_bits_length = locator->function_bits_length; ++ loc->argument_bits_length = 0; ++ loc->flags = locator->flags; ++ ++ listnode_add(srv6_locators, loc); ++ ++ for (ALL_LIST_ELEMENTS_RO(srv6_sids, node, sid)) { ++ if (strncmp(sid->locator_name, loc->name, sizeof(loc->name)) == 0) ++ sid->locator = loc; ++ } ++ ++ /* Request SIDs from the locator */ ++ request_srv6_sids(loc); ++ ++ return 0; ++} ++ ++/** ++ * Callback to process an SRv6 locator received from SRv6 Manager (zebra). ++ * ++ * @result 0 on success, -1 otherwise ++ */ ++static int static_zebra_process_srv6_locator_add(ZAPI_CALLBACK_ARGS) ++{ ++ struct srv6_locator loc = {}; ++ ++ if (!srv6_locators) ++ return -1; ++ ++ /* Decode the SRv6 locator */ ++ if (zapi_srv6_locator_decode(zclient->ibuf, &loc) < 0) ++ return -1; ++ ++ return static_zebra_process_srv6_locator_internal(&loc); ++} ++ ++/** ++ * Callback to process a notification from SRv6 Manager (zebra) of an SRv6 ++ * locator deleted. ++ * ++ * @result 0 on success, -1 otherwise ++ */ ++static int static_zebra_process_srv6_locator_delete(ZAPI_CALLBACK_ARGS) ++{ ++ struct srv6_locator loc = {}; ++ struct listnode *node, *nnode; ++ struct listnode *node2, *nnode2; ++ struct static_srv6_sid *sid; ++ struct static_srv6_locator *locator; ++ ++ if (!srv6_locators) ++ return -1; ++ ++ /* Decode the received zebra message */ ++ if (zapi_srv6_locator_decode(zclient->ibuf, &loc) < 0) ++ return -1; ++ ++ zlog_info( ++ "SRv6 locator deleted in zebra: name %s, " ++ "prefix %pFX, block_len %u, node_len %u, func_len %u, arg_len %u", ++ loc.name, &loc.prefix, loc.block_bits_length, ++ loc.node_bits_length, loc.function_bits_length, ++ loc.argument_bits_length); ++ ++ locator = static_srv6_locator_lookup(loc.name); ++ if (!locator) ++ return 0; ++ ++ zlog_info("Deleting srv6 sids from locator %s", locator->name); ++ ++ /* Delete SRv6 SIDs */ ++ for (ALL_LIST_ELEMENTS(srv6_sids, node2, nnode2, ++ sid)) { ++ ++ if (sid->locator != locator) ++ continue; ++ ++ zlog_info( ++ "Deleting SRv6 SID (locator %s, sid %pFX)", ++ locator->name, ++ &sid->addr); ++ ++ /* Uninstall the SRv6 SID from the forwarding plane ++ * through Zebra */ ++ static_zebra_srv6_sid_uninstall(sid); ++ } ++ ++ listnode_delete(srv6_locators, locator); ++ static_srv6_locator_free(locator); ++ ++ return 0; ++} ++ ++static int static_zebra_srv6_sid_notify(ZAPI_CALLBACK_ARGS) ++{ ++ struct srv6_sid_ctx ctx; ++ struct in6_addr sid_addr; ++ enum zapi_srv6_sid_notify note; ++ uint32_t sid_func; ++ struct listnode *node; ++ char buf[256]; ++ struct static_srv6_locator *locator; ++ struct prefix_ipv6 tmp_prefix; ++ struct static_srv6_sid *sid; ++ char *loc_name; ++ ++ if (!srv6_locators) ++ return -1; ++ ++ /* Decode the received notification message */ ++ if (!zapi_srv6_sid_notify_decode(zclient->ibuf, &ctx, &sid_addr, ++ &sid_func, NULL, ¬e, &loc_name)) { ++ zlog_err("%s : error in msg decode", __func__); ++ return -1; ++ } ++ ++ zlog_info("%s: received SRv6 SID notify: ctx %s sid_value %pI6 sid_func %u note %s", ++ __func__, srv6_sid_ctx2str(buf, sizeof(buf), &ctx), &sid_addr, ++ sid_func, zapi_srv6_sid_notify2str(note)); ++ ++ /* Handle notification */ ++ switch (note) { ++ case ZAPI_SRV6_SID_ALLOCATED: ++ zlog_info("SRv6 SID %pI6 %s ALLOCATED", &sid_addr, ++ srv6_sid_ctx2str(buf, sizeof(buf), &ctx)); ++ ++ bool found = false; ++ for (ALL_LIST_ELEMENTS_RO(srv6_sids, node, sid)) { ++ if (IPV6_ADDR_SAME(&sid->addr.prefix, &sid_addr)) { ++ found = true; ++ break; ++ } ++ } ++ ++ if (!found) { ++ zlog_info("SRv6 SID %pI6 %s: not found", &sid_addr, ++ srv6_sid_ctx2str(buf, sizeof(buf), &ctx)); ++ return 0; ++ } ++ ++ /* ++ * Install the new SRv6 End SID in the forwarding plane through ++ * Zebra ++ */ ++ static_zebra_srv6_sid_install(sid); ++ ++ break; ++ case ZAPI_SRV6_SID_RELEASED: ++ zlog_info("SRv6 SID %pI6 %s: RELEASED", &sid_addr, ++ srv6_sid_ctx2str(buf, sizeof(buf), &ctx)); ++ break; ++ case ZAPI_SRV6_SID_FAIL_ALLOC: ++ zlog_info("SRv6 SID %pI6 %s: Failed to allocate", ++ &sid_addr, ++ srv6_sid_ctx2str(buf, sizeof(buf), &ctx)); ++ ++ /* Error will be logged by zebra module */ ++ break; ++ case ZAPI_SRV6_SID_FAIL_RELEASE: ++ zlog_warn("%s: SRv6 SID %pI6 %s failure to release", ++ __func__, &sid_addr, ++ srv6_sid_ctx2str(buf, sizeof(buf), &ctx)); ++ ++ /* Error will be logged by zebra module */ ++ break; ++ } ++ ++ return 0; ++} ++ + static zclient_handler *const static_handlers[] = { + [ZEBRA_INTERFACE_ADDRESS_ADD] = interface_address_add, + [ZEBRA_INTERFACE_ADDRESS_DELETE] = interface_address_delete, + [ZEBRA_ROUTE_NOTIFY_OWNER] = route_notify_owner, ++ [ZEBRA_SRV6_LOCATOR_ADD] = static_zebra_process_srv6_locator_add, ++ [ZEBRA_SRV6_LOCATOR_DELETE] = static_zebra_process_srv6_locator_delete, ++ [ZEBRA_SRV6_SID_NOTIFY] = static_zebra_srv6_sid_notify, + }; + + void static_zebra_init(void) +diff --git a/staticd/static_zebra.h b/staticd/static_zebra.h +index c4f4ebdcbc..7b00914499 100644 +--- a/staticd/static_zebra.h ++++ b/staticd/static_zebra.h +@@ -7,6 +7,8 @@ + #ifndef __STATIC_ZEBRA_H__ + #define __STATIC_ZEBRA_H__ + ++#include "static_srv6.h" ++ + #ifdef __cplusplus + extern "C" { + #endif +@@ -22,8 +24,16 @@ extern void static_zebra_stop(void); + extern void static_zebra_vrf_register(struct vrf *vrf); + extern void static_zebra_vrf_unregister(struct vrf *vrf); + ++extern int static_zebra_srv6_manager_get_locator(const char *name); ++ ++extern void static_zebra_request_srv6_sid(struct static_srv6_sid *sid); ++extern void static_zebra_release_srv6_sid(struct static_srv6_sid *sid); ++ ++extern void static_zebra_srv6_sid_install(struct static_srv6_sid *sid); ++extern void static_zebra_srv6_sid_uninstall(struct static_srv6_sid *sid); ++ + #ifdef __cplusplus + } + #endif + +-#endif ++#endif +\ No newline at end of file +diff --git a/staticd/subdir.am b/staticd/subdir.am +index 07ebe3c02c..bdbacbdd68 100644 +--- a/staticd/subdir.am ++++ b/staticd/subdir.am +@@ -19,6 +19,7 @@ staticd_libstatic_a_SOURCES = \ + staticd/static_vty.c \ + staticd/static_nb.c \ + staticd/static_nb_config.c \ ++ staticd/static_srv6.c \ + # end + + noinst_HEADERS += \ +@@ -29,6 +30,7 @@ noinst_HEADERS += \ + staticd/static_vty.h \ + staticd/static_vrf.h \ + staticd/static_nb.h \ ++ staticd/static_srv6.h \ + # end + + clippy_scan += \ +diff --git a/tests/topotests/static_srv6_sids/__init__.py b/tests/topotests/static_srv6_sids/__init__.py +new file mode 100644 +index 0000000000..e69de29bb2 +diff --git a/tests/topotests/static_srv6_sids/expected_srv6_sids.json b/tests/topotests/static_srv6_sids/expected_srv6_sids.json +new file mode 100644 +index 0000000000..210adf0fb4 +--- /dev/null ++++ b/tests/topotests/static_srv6_sids/expected_srv6_sids.json +@@ -0,0 +1,142 @@ ++{ ++ "fc00:0:1::/48":[ ++ { ++ "prefix":"fc00:0:1::/48", ++ "prefixLen":48, ++ "protocol":"static", ++ "vrfId":0, ++ "vrfName":"default", ++ "selected":true, ++ "destSelected":true, ++ "distance":1, ++ "metric":0, ++ "installed":true, ++ "table":254, ++ "internalStatus":16, ++ "internalFlags":9, ++ "internalNextHopNum":1, ++ "internalNextHopActiveNum":1, ++ "nexthops":[ ++ { ++ "flags":3, ++ "fib":true, ++ "directlyConnected":true, ++ "interfaceName":"sr0", ++ "active":true, ++ "weight":1, ++ "seg6local":{ ++ "action":"End" ++ }, ++ "seg6localContext":{ ++ "USP":true ++ } ++ } ++ ] ++ } ++ ], ++ "fc00:0:1:fe10::/128":[ ++ { ++ "prefix":"fc00:0:1:fe10::/128", ++ "prefixLen":128, ++ "protocol":"static", ++ "vrfId":0, ++ "vrfName":"default", ++ "selected":true, ++ "destSelected":true, ++ "distance":1, ++ "metric":0, ++ "installed":true, ++ "table":254, ++ "internalStatus":16, ++ "internalFlags":9, ++ "internalNextHopNum":1, ++ "internalNextHopActiveNum":1, ++ "nexthops":[ ++ { ++ "flags":3, ++ "fib":true, ++ "directlyConnected":true, ++ "interfaceName":"Vrf10", ++ "active":true, ++ "weight":1, ++ "seg6local":{ ++ "action":"End.DT4" ++ }, ++ "seg6localContext":{ ++ "table":10 ++ } ++ } ++ ] ++ } ++ ], ++ "fc00:0:1:fe20::/128":[ ++ { ++ "prefix":"fc00:0:1:fe20::/128", ++ "prefixLen":128, ++ "protocol":"static", ++ "vrfId":0, ++ "vrfName":"default", ++ "selected":true, ++ "destSelected":true, ++ "distance":1, ++ "metric":0, ++ "installed":true, ++ "table":254, ++ "internalStatus":16, ++ "internalFlags":9, ++ "internalNextHopNum":1, ++ "internalNextHopActiveNum":1, ++ "nexthops":[ ++ { ++ "flags":3, ++ "fib":true, ++ "directlyConnected":true, ++ "interfaceName":"Vrf20", ++ "active":true, ++ "weight":1, ++ "seg6local":{ ++ "action":"End.DT6" ++ }, ++ "seg6localContext":{ ++ "table":20 ++ } ++ } ++ ] ++ } ++ ], ++ "fc00:0:1:fe30::/128":[ ++ { ++ "prefix":"fc00:0:1:fe30::/128", ++ "prefixLen":128, ++ "protocol":"static", ++ "vrfId":0, ++ "vrfName":"default", ++ "selected":true, ++ "destSelected":true, ++ "distance":1, ++ "metric":0, ++ "installed":true, ++ "table":254, ++ "internalStatus":16, ++ "internalFlags":9, ++ "internalNextHopNum":1, ++ "internalNextHopActiveNum":1, ++ "nexthops":[ ++ { ++ "flags":3, ++ "fib":true, ++ "directlyConnected":true, ++ "interfaceName":"Vrf30", ++ "active":true, ++ "weight":1, ++ "seg6local":{ ++ "action":"End.DT46" ++ }, ++ "seg6localContext":{ ++ "table":30 ++ } ++ } ++ ] ++ } ++ ] ++ } +\ No newline at end of file +diff --git a/tests/topotests/static_srv6_sids/r1/mgmtd.conf b/tests/topotests/static_srv6_sids/r1/mgmtd.conf +new file mode 100644 +index 0000000000..e69de29bb2 +diff --git a/tests/topotests/static_srv6_sids/r1/setup.sh b/tests/topotests/static_srv6_sids/r1/setup.sh +new file mode 100644 +index 0000000000..040be73914 +--- /dev/null ++++ b/tests/topotests/static_srv6_sids/r1/setup.sh +@@ -0,0 +1,13 @@ ++ip link add sr0 type dummy ++ip link set sr0 up ++ ++ip link add Vrf10 type vrf table 10 ++ip link set Vrf10 up ++ ++ip link add Vrf20 type vrf table 20 ++ip link set Vrf20 up ++ ++ip link add Vrf30 type vrf table 30 ++ip link set Vrf30 up ++ ++sysctl -w net.vrf.strict_mode=1 +diff --git a/tests/topotests/static_srv6_sids/r1/staticd.conf b/tests/topotests/static_srv6_sids/r1/staticd.conf +new file mode 100644 +index 0000000000..e769fe6eca +--- /dev/null ++++ b/tests/topotests/static_srv6_sids/r1/staticd.conf +@@ -0,0 +1,16 @@ ++hostname r1 ++! ++log stdout notifications ++log commands ++log file staticd.log debugging ++! ++segment-routing ++ srv6 ++ static-sids ++ sid fc00:0:1::/48 locator MAIN behavior uN ++ sid fc00:0:1:fe10::/128 locator MAIN behavior uDT4 vrf Vrf10 ++ sid fc00:0:1:fe20::/128 locator MAIN behavior uDT6 vrf Vrf20 ++ sid fc00:0:1:fe30::/128 locator MAIN behavior uDT46 vrf Vrf30 ++ ! ++ ! ++! +diff --git a/tests/topotests/static_srv6_sids/r1/zebra.conf b/tests/topotests/static_srv6_sids/r1/zebra.conf +new file mode 100644 +index 0000000000..59ec14f735 +--- /dev/null ++++ b/tests/topotests/static_srv6_sids/r1/zebra.conf +@@ -0,0 +1,19 @@ ++hostname r1 ++! ++! debug zebra events ++! debug zebra rib detailed ++! ++log stdout notifications ++log commands ++log file zebra.log debugging ++! ++segment-routing ++ srv6 ++ locators ++ locator MAIN ++ prefix fc00:0:1::/48 ++ format usid-f3216 ++ ! ++ ! ++ ! ++! +\ No newline at end of file +diff --git a/tests/topotests/static_srv6_sids/test_static_srv6_sids.py b/tests/topotests/static_srv6_sids/test_static_srv6_sids.py +new file mode 100755 +index 0000000000..195ecf9385 +--- /dev/null ++++ b/tests/topotests/static_srv6_sids/test_static_srv6_sids.py +@@ -0,0 +1,89 @@ ++#!/usr/bin/env python ++# SPDX-License-Identifier: ISC ++ ++# ++# test_static_srv6_sids.py ++# ++# Copyright 2025 Carmine Scarpitta ++# ++ ++""" ++test_static_srv6_sids.py: ++Test for SRv6 static route on zebra ++""" ++ ++import os ++import sys ++import json ++import pytest ++import functools ++ ++CWD = os.path.dirname(os.path.realpath(__file__)) ++sys.path.append(os.path.join(CWD, "../")) ++ ++# pylint: disable=C0413 ++from lib import topotest ++from lib.topogen import Topogen, TopoRouter, get_topogen ++from lib.topolog import logger ++ ++pytestmark = [pytest.mark.staticd] ++ ++ ++def open_json_file(filename): ++ try: ++ with open(filename, "r") as f: ++ return json.load(f) ++ except IOError: ++ assert False, "Could not read file {}".format(filename) ++ ++ ++def setup_module(mod): ++ tgen = Topogen({None: "r1"}, mod.__name__) ++ tgen.start_topology() ++ for rname, router in tgen.routers().items(): ++ router.run("/bin/bash {}/{}/setup.sh".format(CWD, rname)) ++ router.load_config( ++ TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ++ ) ++ router.load_config( ++ TopoRouter.RD_MGMTD, os.path.join(CWD, "{}/mgmtd.conf".format(rname)) ++ ) ++ router.load_config( ++ TopoRouter.RD_STATIC, os.path.join(CWD, "{}/staticd.conf".format(rname)) ++ ) ++ tgen.start_router() ++ ++ ++def teardown_module(): ++ tgen = get_topogen() ++ tgen.stop_topology() ++ ++ ++def test_srv6_static_sids(): ++ tgen = get_topogen() ++ if tgen.routers_have_failure(): ++ pytest.skip(tgen.errors) ++ router = tgen.gears["r1"] ++ ++ def _check_srv6_static_sids(router, expected_route_file): ++ logger.info("checking zebra srv6 static sids") ++ output = json.loads(router.vtysh_cmd("show ipv6 route static json")) ++ expected = open_json_file("{}/{}".format(CWD, expected_route_file)) ++ return topotest.json_cmp(output, expected) ++ ++ def check_srv6_static_sids(router, expected_file): ++ func = functools.partial(_check_srv6_static_sids, router, expected_file) ++ _, result = topotest.run_and_expect(func, None, count=15, wait=1) ++ assert result is None, "Failed" ++ ++ # FOR DEVELOPER: ++ # If you want to stop some specific line and start interactive shell, ++ # please use tgen.mininet_cli() to start it. ++ ++ logger.info("Test for srv6 sids configuration") ++ check_srv6_static_sids(router, "expected_srv6_sids.json") ++ ++ ++if __name__ == "__main__": ++ args = ["-s"] + sys.argv[1:] ++ sys.exit(pytest.main(args)) +diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c +index c460dea70c..d4675fe6ae 100644 +--- a/vtysh/vtysh.c ++++ b/vtysh/vtysh.c +@@ -1312,6 +1312,13 @@ static struct cmd_node srv6_node = { + .prompt = "%s(config-srv6)# ", + }; + ++static struct cmd_node srv6_sids_node = { ++ .name = "srv6-sids", ++ .node = SRV6_SIDS_NODE, ++ .parent_node = SRV6_NODE, ++ .prompt = "%s(config-srv6-sids)# ", ++}; ++ + static struct cmd_node srv6_locs_node = { + .name = "srv6-locators", + .node = SRV6_LOCS_NODE, +@@ -1685,7 +1692,7 @@ DEFUNSH(VTYSH_REALLYALL, vtysh_end_all, vtysh_end_all_cmd, "end", + return vtysh_end(); + } + +-DEFUNSH(VTYSH_ZEBRA, srv6, srv6_cmd, ++DEFUNSH(VTYSH_ZEBRA | VTYSH_MGMTD, srv6, srv6_cmd, + "srv6", + "Segment-Routing SRv6 configuration\n") + { +@@ -1693,6 +1700,14 @@ DEFUNSH(VTYSH_ZEBRA, srv6, srv6_cmd, + return CMD_SUCCESS; + } + ++DEFUNSH(VTYSH_MGMTD, srv6_sids, srv6_sids_cmd, ++ "static-sids", ++ "Segment-Routing SRv6 SIDs configuration\n") ++{ ++ vty->node = SRV6_SIDS_NODE; ++ return CMD_SUCCESS; ++} ++ + DEFUNSH(VTYSH_ZEBRA, srv6_locators, srv6_locators_cmd, + "locators", + "Segment-Routing SRv6 locators configuration\n") +@@ -2216,7 +2231,7 @@ DEFUNSH(VTYSH_FABRICD, router_openfabric, router_openfabric_cmd, "router openfab + } + #endif /* HAVE_FABRICD */ + +-DEFUNSH(VTYSH_SR, segment_routing, segment_routing_cmd, ++DEFUNSH(VTYSH_SR | VTYSH_MGMTD, segment_routing, segment_routing_cmd, + "segment-routing", + "Configure segment routing\n") + { +@@ -2535,7 +2550,7 @@ DEFUNSH(VTYSH_VRF, exit_vrf_config, exit_vrf_config_cmd, "exit-vrf", + return CMD_SUCCESS; + } + +-DEFUNSH(VTYSH_ZEBRA, exit_srv6_config, exit_srv6_config_cmd, "exit", ++DEFUNSH(VTYSH_ZEBRA | VTYSH_MGMTD, exit_srv6_config, exit_srv6_config_cmd, "exit", + "Exit from SRv6 configuration mode\n") + { + if (vty->node == SRV6_NODE) +@@ -2551,6 +2566,14 @@ DEFUNSH(VTYSH_ZEBRA, exit_srv6_locs_config, exit_srv6_locs_config_cmd, "exit", + return CMD_SUCCESS; + } + ++DEFUNSH(VTYSH_MGMTD, exit_srv6_sids_config, exit_srv6_sids_config_cmd, "exit", ++ "Exit from SRv6-SIDs configuration mode\n") ++{ ++ if (vty->node == SRV6_SIDS_NODE) ++ vty->node = SRV6_NODE; ++ return CMD_SUCCESS; ++} ++ + DEFUNSH(VTYSH_ZEBRA, exit_srv6_loc_config, exit_srv6_loc_config_cmd, "exit", + "Exit from SRv6-locators configuration mode\n") + { +@@ -4999,6 +5022,7 @@ void vtysh_init_vty(void) + install_node(&rmap_node); + install_node(&vty_node); + install_node(&srv6_node); ++ install_node(&srv6_sids_node); + install_node(&srv6_locs_node); + install_node(&srv6_loc_node); + install_node(&srv6_encap_node); +@@ -5442,6 +5466,10 @@ void vtysh_init_vty(void) + install_element(SRV6_NODE, &exit_srv6_config_cmd); + install_element(SRV6_NODE, &vtysh_end_all_cmd); + install_element(SRV6_NODE, &srv6_encap_cmd); ++ install_element(SRV6_NODE, &srv6_sids_cmd); ++ ++ install_element(SRV6_SIDS_NODE, &exit_srv6_sids_config_cmd); ++ install_element(SRV6_SIDS_NODE, &vtysh_end_all_cmd); + + install_element(SRV6_LOCS_NODE, &srv6_locator_cmd); + install_element(SRV6_LOCS_NODE, &exit_srv6_locs_config_cmd); +diff --git a/yang/frr-staticd.yang b/yang/frr-staticd.yang +index 1e6c54c006..ac3b04dede 100644 +--- a/yang/frr-staticd.yang ++++ b/yang/frr-staticd.yang +@@ -92,6 +92,41 @@ module frr-staticd { + } + } + ++ typedef srv6-behavior { ++ type enumeration { ++ enum end { ++ value 1; ++ } ++ enum end-x { ++ value 2; ++ } ++ enum end-dt6 { ++ value 3; ++ } ++ enum end-dt4 { ++ value 4; ++ } ++ enum end-dt46 { ++ value 5; ++ } ++ enum un { ++ value 6; ++ } ++ enum ua { ++ value 7; ++ } ++ enum udt6 { ++ value 8; ++ } ++ enum udt4 { ++ value 9; ++ } ++ enum udt46 { ++ value 10; ++ } ++ } ++ } ++ + augment "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol" { + container staticd { + when "../frr-rt:type = 'frr-staticd:staticd'" { +@@ -144,6 +179,28 @@ module frr-staticd { + uses staticd-prefix-attributes; + } + } ++ ++ container segment-routing { ++ container srv6 { ++ container local-sids { ++ list sid { ++ key "sid"; ++ leaf sid { ++ type inet:ipv6-prefix; ++ } ++ leaf behavior { ++ type srv6-behavior; ++ } ++ leaf locator-name { ++ type string; ++ } ++ leaf vrf-name { ++ type string; ++ } ++ } ++ } ++ } ++ } + } + } +-} ++} +\ No newline at end of file +diff --git a/zebra/zebra_srv6.c b/zebra/zebra_srv6.c +index 624f60e815..f948c22875 100644 +--- a/zebra/zebra_srv6.c ++++ b/zebra/zebra_srv6.c +@@ -1546,11 +1546,11 @@ static int get_srv6_sid_explicit(struct zebra_srv6_sid **sid, + return -1; + } + +- if (ctx->behavior == ZEBRA_SEG6_LOCAL_ACTION_END) { +- zlog_err("%s: invalid SM request arguments: explicit SID allocation not allowed for End/uN behavior", +- __func__); +- return -1; +- } ++ // if (ctx->behavior == ZEBRA_SEG6_LOCAL_ACTION_END) { ++ // zlog_err("%s: invalid SM request arguments: explicit SID allocation not allowed for End/uN behavior", ++ // __func__); ++ // return -1; ++ // } + + /* Allocate an explicit SID function for the SID */ + if (!alloc_srv6_sid_func_explicit(block, sid_func, sid_func_wide)) { +-- +2.45.2 + diff --git a/src/sonic-frr/patch/series b/src/sonic-frr/patch/series index bd88dbc2bb41..605bfc4d8b34 100644 --- a/src/sonic-frr/patch/series +++ b/src/sonic-frr/patch/series @@ -56,3 +56,6 @@ 0074-bgp-best-port-reordering.patch 0075-bgp-mp-info-changes.patch 0076-Optimizations-and-problem-fixing-for-large-scale-ecmp-from-bgp.patch +0077-frr-vtysh-dependencies-for-srv6-static-patches.patch +0078-vtysh-de-conditionalize-and-reorder-install-node.patch +0079-staticd-add-support-for-srv6.patch