From: Sarita Patra Date: Fri, 23 Oct 2020 12:06:06 +0000 (-0700) Subject: pimd: Northbound implementation for pim commands. X-Git-Tag: base_7.6~243^2~11 X-Git-Url: https://git.puffer.fish/?a=commitdiff_plain;h=50d194f8c8c9c00332e8e7eb4f7b67324e7d1e0b;p=matthieu%2Ffrr.git pimd: Northbound implementation for pim commands. interface_ip_pim_ssm interface_ip_pim_sm interface_ip_pim interface_no_ip_pim_ssm interface_no_ip_pim_sm interface_no_ip_pim Yang Model: augment /frr-interface:lib/frr-interface:interface: +--rw pim! +--rw pim-enable? boolean Signed-off-by: Sarita Patra --- diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index 9065d30f14..543a81c1a9 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -8092,36 +8092,19 @@ DEFUN_HIDDEN (interface_ip_pim_ssm, PIM_STR IFACE_PIM_STR) { - VTY_DECLVAR_CONTEXT(interface, ifp); - - if (!pim_cmd_interface_add(vty, ifp)) { - vty_out(vty, "Could not enable PIM SM on interface %s\n", - ifp->name); - return CMD_WARNING_CONFIG_FAILED; - } - - vty_out(vty, - "WARN: Enabled PIM SM on interface; configure PIM SSM range if needed\n"); - return CMD_SUCCESS; -} + int ret; -static int interface_ip_pim_helper(struct vty *vty) -{ - struct pim_interface *pim_ifp; + nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY, "true"); - VTY_DECLVAR_CONTEXT(interface, ifp); + ret = nb_cli_apply_changes(vty, "./frr-pim:pim"); - if (!pim_cmd_interface_add(vty, ifp)) { - vty_out(vty, "Could not enable PIM SM on interface %s\n", - ifp->name); - return CMD_WARNING_CONFIG_FAILED; - } - - pim_ifp = ifp->info; + if (ret != NB_OK) + return ret; - pim_if_create_pimreg(pim_ifp->pim); + vty_out(vty, + "WARN: Enabled PIM SM on interface; configure PIM SSM range if needed\n"); - return CMD_SUCCESS; + return NB_OK; } DEFUN_HIDDEN (interface_ip_pim_sm, @@ -8131,7 +8114,9 @@ DEFUN_HIDDEN (interface_ip_pim_sm, PIM_STR IFACE_PIM_SM_STR) { - return interface_ip_pim_helper(vty); + nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY, "true"); + + return nb_cli_apply_changes(vty, "./frr-pim:pim"); } DEFUN (interface_ip_pim, @@ -8140,43 +8125,9 @@ DEFUN (interface_ip_pim, IP_STR PIM_STR) { - return interface_ip_pim_helper(vty); -} - -static int pim_cmd_interface_delete(struct interface *ifp) -{ - struct pim_interface *pim_ifp = ifp->info; - - if (!pim_ifp) - return 1; - - PIM_IF_DONT_PIM(pim_ifp->options); - - pim_if_membership_clear(ifp); - - /* - pim_sock_delete() removes all neighbors from - pim_ifp->pim_neighbor_list. - */ - pim_sock_delete(ifp, "pim unconfigured on interface"); - - if (!PIM_IF_TEST_IGMP(pim_ifp->options)) { - pim_if_addr_del_all(ifp); - pim_if_delete(ifp); - } + nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY, "true"); - return 1; -} - -static int interface_no_ip_pim_helper(struct vty *vty) -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - if (!pim_cmd_interface_delete(ifp)) { - vty_out(vty, "Unable to delete interface information\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - return CMD_SUCCESS; + return nb_cli_apply_changes(vty, "./frr-pim:pim"); } DEFUN_HIDDEN (interface_no_ip_pim_ssm, @@ -8187,7 +8138,28 @@ DEFUN_HIDDEN (interface_no_ip_pim_ssm, PIM_STR IFACE_PIM_STR) { - return interface_no_ip_pim_helper(vty); + const struct lyd_node *igmp_enable_dnode; + char igmp_if_xpath[XPATH_MAXLEN]; + + snprintf(igmp_if_xpath, sizeof(igmp_if_xpath), + "%s/frr-igmp:igmp", VTY_CURR_XPATH); + igmp_enable_dnode = yang_dnode_get(vty->candidate_config->dnode, + "%s/igmp-enable", igmp_if_xpath); + + if (!igmp_enable_dnode) { + nb_cli_enqueue_change(vty, igmp_if_xpath, NB_OP_DESTROY, NULL); + nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); + } else { + if (!yang_dnode_get_bool(igmp_enable_dnode, ".")) { + nb_cli_enqueue_change(vty, igmp_if_xpath, NB_OP_DESTROY, + NULL); + nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); + } else + nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY, + "false"); + } + + return nb_cli_apply_changes(vty, "./frr-pim:pim"); } DEFUN_HIDDEN (interface_no_ip_pim_sm, @@ -8198,7 +8170,28 @@ DEFUN_HIDDEN (interface_no_ip_pim_sm, PIM_STR IFACE_PIM_SM_STR) { - return interface_no_ip_pim_helper(vty); + const struct lyd_node *igmp_enable_dnode; + char igmp_if_xpath[XPATH_MAXLEN]; + + snprintf(igmp_if_xpath, sizeof(igmp_if_xpath), + "%s/frr-igmp:igmp", VTY_CURR_XPATH); + igmp_enable_dnode = yang_dnode_get(vty->candidate_config->dnode, + "%s/igmp-enable", igmp_if_xpath); + + if (!igmp_enable_dnode) { + nb_cli_enqueue_change(vty, igmp_if_xpath, NB_OP_DESTROY, NULL); + nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); + } else { + if (!yang_dnode_get_bool(igmp_enable_dnode, ".")) { + nb_cli_enqueue_change(vty, igmp_if_xpath, NB_OP_DESTROY, + NULL); + nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); + } else + nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY, + "false"); + } + + return nb_cli_apply_changes(vty, "./frr-pim:pim"); } DEFUN (interface_no_ip_pim, @@ -8208,7 +8201,28 @@ DEFUN (interface_no_ip_pim, IP_STR PIM_STR) { - return interface_no_ip_pim_helper(vty); + const struct lyd_node *igmp_enable_dnode; + char igmp_if_xpath[XPATH_MAXLEN]; + + snprintf(igmp_if_xpath, sizeof(igmp_if_xpath), + "%s/frr-igmp:igmp", VTY_CURR_XPATH); + igmp_enable_dnode = yang_dnode_get(vty->candidate_config->dnode, + "%s/igmp-enable", igmp_if_xpath); + + if (!igmp_enable_dnode) { + nb_cli_enqueue_change(vty, igmp_if_xpath, NB_OP_DESTROY, NULL); + nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); + } else { + if (!yang_dnode_get_bool(igmp_enable_dnode, ".")) { + nb_cli_enqueue_change(vty, igmp_if_xpath, NB_OP_DESTROY, + NULL); + nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); + } else + nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY, + "false"); + } + + return nb_cli_apply_changes(vty, "./frr-pim:pim"); } /* boundaries */ diff --git a/pimd/pim_nb_config.c b/pimd/pim_nb_config.c index 366b00f4b6..c6788a2fcc 100644 --- a/pimd/pim_nb_config.c +++ b/pimd/pim_nb_config.c @@ -21,9 +21,136 @@ #include "pim_nb.h" #include "lib/northbound_cli.h" #include "pim_igmpv3.h" +#include "pim_pim.h" -void pim_if_membership_clear(struct interface *ifp); -void pim_if_membership_refresh(struct interface *ifp); +static void pim_if_membership_clear(struct interface *ifp) +{ + struct pim_interface *pim_ifp; + + pim_ifp = ifp->info; + zassert(pim_ifp); + + if (PIM_IF_TEST_PIM(pim_ifp->options) + && PIM_IF_TEST_IGMP(pim_ifp->options)) { + return; + } + + pim_ifchannel_membership_clear(ifp); +} + +/* + * When PIM is disabled on interface, IGMPv3 local membership + * information is not injected into PIM interface state. + + * The function pim_if_membership_refresh() fetches all IGMPv3 local + * membership information into PIM. It is intented to be called + * whenever PIM is enabled on the interface in order to collect missed + * local membership information. + */ +static void pim_if_membership_refresh(struct interface *ifp) +{ + struct pim_interface *pim_ifp; + struct listnode *sock_node; + struct igmp_sock *igmp; + + pim_ifp = ifp->info; + zassert(pim_ifp); + + if (!PIM_IF_TEST_PIM(pim_ifp->options)) + return; + if (!PIM_IF_TEST_IGMP(pim_ifp->options)) + return; + + /* + * First clear off membership from all PIM (S,G) entries on the + * interface + */ + + pim_ifchannel_membership_clear(ifp); + + /* + * Then restore PIM (S,G) membership from all IGMPv3 (S,G) entries on + * the interface + */ + + /* scan igmp sockets */ + for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, sock_node, igmp)) { + struct listnode *grpnode; + struct igmp_group *grp; + + /* scan igmp groups */ + for (ALL_LIST_ELEMENTS_RO(igmp->igmp_group_list, grpnode, + grp)) { + struct listnode *srcnode; + struct igmp_source *src; + + /* scan group sources */ + for (ALL_LIST_ELEMENTS_RO(grp->group_source_list, + srcnode, src)) { + + if (IGMP_SOURCE_TEST_FORWARDING( + src->source_flags)) { + struct prefix_sg sg; + + memset(&sg, 0, + sizeof(struct prefix_sg)); + sg.src = src->source_addr; + sg.grp = grp->group_addr; + pim_ifchannel_local_membership_add( + ifp, &sg, false /*is_vxlan*/); + } + + } /* scan group sources */ + } /* scan igmp groups */ + } /* scan igmp sockets */ + + /* + * Finally delete every PIM (S,G) entry lacking all state info + */ + + pim_ifchannel_delete_on_noinfo(ifp); +} + +static int pim_cmd_interface_add(struct interface *ifp) +{ + struct pim_interface *pim_ifp = ifp->info; + + if (!pim_ifp) + pim_ifp = pim_if_new(ifp, false, true, false, false); + else + PIM_IF_DO_PIM(pim_ifp->options); + + pim_if_addr_add_all(ifp); + pim_if_membership_refresh(ifp); + + pim_if_create_pimreg(pim_ifp->pim); + return 1; +} + +static int pim_cmd_interface_delete(struct interface *ifp) +{ + struct pim_interface *pim_ifp = ifp->info; + + if (!pim_ifp) + return 1; + + PIM_IF_DONT_PIM(pim_ifp->options); + + pim_if_membership_clear(ifp); + + /* + * pim_sock_delete() removes all neighbors from + * pim_ifp->pim_neighbor_list. + */ + pim_sock_delete(ifp, "pim unconfigured on interface"); + + if (!PIM_IF_TEST_IGMP(pim_ifp->options)) { + pim_if_addr_del_all(ifp); + pim_if_delete(ifp); + } + + return 1; +} static bool is_pim_interface(const struct lyd_node *dnode) { @@ -866,7 +993,6 @@ int lib_interface_pim_create(struct nb_cb_create_args *args) case NB_EV_PREPARE: case NB_EV_ABORT: case NB_EV_APPLY: - /* TODO: implement me. */ break; } @@ -875,13 +1001,26 @@ int lib_interface_pim_create(struct nb_cb_create_args *args) int lib_interface_pim_destroy(struct nb_cb_destroy_args *args) { + struct interface *ifp; + struct pim_interface *pim_ifp; + switch (args->event) { case NB_EV_VALIDATE: case NB_EV_PREPARE: case NB_EV_ABORT: - case NB_EV_APPLY: - /* TODO: implement me. */ break; + case NB_EV_APPLY: + ifp = nb_running_get_entry(args->dnode, NULL, true); + pim_ifp = ifp->info; + if (!pim_ifp) + return NB_OK; + + if (!pim_cmd_interface_delete(ifp)) { + snprintf(args->errmsg, args->errmsg_len, + "Unable to delete interface information %s", + ifp->name); + return NB_ERR_INCONSISTENCY; + } } return NB_OK; @@ -892,12 +1031,49 @@ int lib_interface_pim_destroy(struct nb_cb_destroy_args *args) */ int lib_interface_pim_pim_enable_modify(struct nb_cb_modify_args *args) { + struct interface *ifp; + struct pim_interface *pim_ifp; + int mcast_if_count; + const struct lyd_node *if_dnode; + switch (args->event) { case NB_EV_VALIDATE: + if_dnode = yang_dnode_get_parent(args->dnode, "interface"); + mcast_if_count = + yang_get_list_elements_count(if_dnode); + + /* Limiting mcast interfaces to number of VIFs */ + if (mcast_if_count == MAXVIFS) { + snprintf(args->errmsg, args->errmsg_len, + "Max multicast interfaces(%d) reached.", + MAXVIFS); + return NB_ERR_VALIDATION; + } + break; case NB_EV_PREPARE: case NB_EV_ABORT: + break; case NB_EV_APPLY: - /* TODO: implement me. */ + ifp = nb_running_get_entry(args->dnode, NULL, true); + + if (yang_dnode_get_bool(args->dnode, NULL)) { + if (!pim_cmd_interface_add(ifp)) { + snprintf(args->errmsg, args->errmsg_len, + "Could not enable PIM SM on interface %s", + ifp->name); + return NB_ERR_INCONSISTENCY; + } + } else { + pim_ifp = ifp->info; + if (!pim_ifp) + return NB_ERR_INCONSISTENCY; + + if (!pim_cmd_interface_delete(ifp)) { + snprintf(args->errmsg, args->errmsg_len, + "Unable to delete interface information"); + return NB_ERR_INCONSISTENCY; + } + } break; }