]> git.puffer.fish Git - matthieu/frr.git/commitdiff
pimd: Northbound implementation for pim commands.
authorSarita Patra <saritap@vmware.com>
Fri, 23 Oct 2020 12:06:06 +0000 (05:06 -0700)
committerSarita Patra <saritap@vmware.com>
Fri, 6 Nov 2020 11:41:59 +0000 (03:41 -0800)
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 <false>

Signed-off-by: Sarita Patra <saritap@vmware.com>
pimd/pim_cmd.c
pimd/pim_nb_config.c

index 9065d30f1403e500df57760cdcaeda47f95d5b1d..543a81c1a9cb50ce1728dfc5981c7e414d49adf7 100644 (file)
@@ -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 */
index 366b00f4b6a9dedd0fc822a88dbde77483bb07bd..c6788a2fccf167603b8f6fa1484d16e254e532a3 100644 (file)
 #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;
        }