]> git.puffer.fish Git - mirror/frr.git/commitdiff
pimd, yang: Implement igmp static-group command
authorNathan Bahr <nbahr@atcorp.com>
Wed, 26 Jun 2024 17:41:45 +0000 (12:41 -0500)
committerNathan Bahr <nbahr@atcorp.com>
Thu, 15 Aug 2024 16:20:00 +0000 (16:20 +0000)
This will add a static IGMP group that does not rely on an underlying
socket join which sends traffic to the cpu unneccesarily. Instead, the
groups are joined directly without any IGMP interactions.
New command is under interfaces, 'ip igmp static-group ...'.
Added an alias for 'ip igmp join ...' to 'ip igmp join-group'.
Moved IGMP join groups to new yang list "join-group" and reused
the "static-group" list for the IGMP static groups.

Signed-off-by: Nathan Bahr <nbahr@atcorp.com>
12 files changed:
pimd/pim6_cmd.c
pimd/pim_cmd.c
pimd/pim_iface.c
pimd/pim_iface.h
pimd/pim_igmp.h
pimd/pim_memory.c
pimd/pim_memory.h
pimd/pim_nb.c
pimd/pim_nb.h
pimd/pim_nb_config.c
pimd/pim_vty.c
yang/frr-gmp.yang

index 99f1474712b5d0da87c8bcf0b9a7b28e8d692af9..f7a4e0e481120c4d41abe3d2de84a231a9b1a9db 100644 (file)
@@ -1363,45 +1363,56 @@ DEFPY_ATTR(no_ipv6_ssmpingd,
        return ret;
 }
 
-DEFPY (interface_ipv6_mld_join,
-       interface_ipv6_mld_join_cmd,
-       "ipv6 mld join X:X::X:X$group [X:X::X:X$source]",
+DEFPY_YANG_HIDDEN (interface_ipv6_mld_join,
+                   interface_ipv6_mld_join_cmd,
+                   "[no] ipv6 mld join X:X::X:X$grp [X:X::X:X]$src",
+                   NO_STR
+                   IPV6_STR
+                   IFACE_MLD_STR
+                   "MLD join multicast group\n"
+                   "Multicast group address\n"
+                   "Source address\n")
+{
+       nb_cli_enqueue_change(vty, ".", (!no ? NB_OP_CREATE : NB_OP_DESTROY),
+                             NULL);
+       return nb_cli_apply_changes(vty, FRR_GMP_JOIN_GROUP_XPATH,
+                                   "frr-routing:ipv6", grp_str,
+                                   (src_str ? src_str : "::"));
+}
+ALIAS (interface_ipv6_mld_join,
+       interface_ipv6_mld_join_group_cmd,
+       "[no] ipv6 mld join-group X:X::X:X$grp [X:X::X:X]$src",
+       NO_STR
        IPV6_STR
        IFACE_MLD_STR
        "MLD join multicast group\n"
        "Multicast group address\n"
-       "Source address\n")
-{
-       char xpath[XPATH_MAXLEN];
-
-       if (!IN6_IS_ADDR_MULTICAST(&group)) {
-               vty_out(vty, "Invalid Multicast Address\n");
-               return CMD_WARNING_CONFIG_FAILED;
-       }
-
-       if (source_str) {
-               if (IPV6_ADDR_SAME(&source, &in6addr_any)) {
-                       vty_out(vty, "Bad source address %s\n", source_str);
-                       return CMD_WARNING_CONFIG_FAILED;
-               }
-       } else
-               source_str = "::";
-
-       snprintf(xpath, sizeof(xpath), FRR_GMP_JOIN_XPATH, "frr-routing:ipv6",
-                group_str, source_str);
-
-       nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
-
-       return nb_cli_apply_changes(vty, NULL);
-}
-
-DEFPY (interface_no_ipv6_mld_join,
-       interface_no_ipv6_mld_join_cmd,
-       "no ipv6 mld join X:X::X:X$group [X:X::X:X$source]",
+       "Source address\n");
+
+DEFPY_YANG (interface_ipv6_mld_static_group,
+            interface_ipv6_mld_static_group_cmd,
+            "[no] ipv6 mld static-group X:X::X:X$grp [X:X::X:X]$src",
+            NO_STR
+            IPV6_STR
+            IFACE_MLD_STR
+            "Static multicast group\n"
+            "Multicast group address\n"
+            "Source address\n")
+{
+       nb_cli_enqueue_change(vty, ".", (!no ? NB_OP_CREATE : NB_OP_DESTROY),
+                             NULL);
+       return nb_cli_apply_changes(vty, FRR_GMP_STATIC_GROUP_XPATH,
+                                   "frr-routing:ipv6", grp_str,
+                                   (src_str ? src_str : "::"));
+}
+
+DEFPY (interface_no_ipv6_mld_static_group,
+       interface_no_ipv6_mld_static_group_cmd,
+       "no ipv6 mld static-group X:X::X:X$group [X:X::X:X$source]",
        NO_STR
        IPV6_STR
        IFACE_MLD_STR
-       "MLD join multicast group\n"
+       "Static multicast group\n"
        "Multicast group address\n"
        "Source address\n")
 {
@@ -1415,8 +1426,8 @@ DEFPY (interface_no_ipv6_mld_join,
        } else
                source_str = "::";
 
-       snprintf(xpath, sizeof(xpath), FRR_GMP_JOIN_XPATH, "frr-routing:ipv6",
-                group_str, source_str);
+       snprintf(xpath, sizeof(xpath), FRR_GMP_STATIC_GROUP_XPATH,
+                "frr-routing:ipv6", group_str, source_str);
 
        nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
 
@@ -2669,7 +2680,8 @@ void pim_cmd_init(void)
        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);
-       install_element(INTERFACE_NODE, &interface_no_ipv6_mld_join_cmd);
+       install_element(INTERFACE_NODE, &interface_ipv6_mld_join_group_cmd);
+       install_element(INTERFACE_NODE, &interface_ipv6_mld_static_group_cmd);
        install_element(INTERFACE_NODE, &interface_ipv6_mld_version_cmd);
        install_element(INTERFACE_NODE, &interface_no_ipv6_mld_version_cmd);
        install_element(INTERFACE_NODE, &interface_ipv6_mld_query_interval_cmd);
index 92214eced4ae614655c618fbdfda223482cc00d5..241350b62e0c5c756c7bc1c64ab873fae15a296d 100644 (file)
@@ -682,6 +682,91 @@ static void igmp_show_interface_join(struct pim_instance *pim, struct vty *vty,
                vty_json(vty, json);
 }
 
+static void igmp_show_interface_static_group(struct pim_instance *pim,
+                                            struct vty *vty, bool uj)
+{
+       struct interface *ifp;
+       json_object *json = NULL;
+       json_object *json_iface = NULL;
+       json_object *json_grp = NULL;
+       json_object *json_grp_arr = NULL;
+
+       if (uj) {
+               json = json_object_new_object();
+               json_object_string_add(json, "vrf",
+                                      vrf_id_to_name(pim->vrf->vrf_id));
+       } else {
+               vty_out(vty,
+                       "Interface        Address         Source          Group\n");
+       }
+
+       FOR_ALL_INTERFACES (pim->vrf, ifp) {
+               struct pim_interface *pim_ifp;
+               struct listnode *node;
+               struct static_group *stgrp;
+               struct in_addr pri_addr;
+               char pri_addr_str[INET_ADDRSTRLEN];
+
+               pim_ifp = ifp->info;
+
+               if (!pim_ifp)
+                       continue;
+
+               if (!pim_ifp->static_group_list)
+                       continue;
+
+               pri_addr = pim_find_primary_addr(ifp);
+               pim_inet4_dump("<pri?>", pri_addr, pri_addr_str,
+                              sizeof(pri_addr_str));
+
+               for (ALL_LIST_ELEMENTS_RO(pim_ifp->static_group_list, node,
+                                         stgrp)) {
+                       char group_str[INET_ADDRSTRLEN];
+                       char source_str[INET_ADDRSTRLEN];
+
+                       pim_inet4_dump("<grp?>", stgrp->group_addr, group_str,
+                                      sizeof(group_str));
+                       pim_inet4_dump("<src?>", stgrp->source_addr, source_str,
+                                      sizeof(source_str));
+
+                       if (uj) {
+                               json_object_object_get_ex(json, ifp->name,
+                                                         &json_iface);
+
+                               if (!json_iface) {
+                                       json_iface = json_object_new_object();
+                                       json_object_string_add(json_iface,
+                                                              "name",
+                                                              ifp->name);
+                                       json_object_object_add(json, ifp->name,
+                                                              json_iface);
+                                       json_grp_arr = json_object_new_array();
+                                       json_object_object_add(json_iface,
+                                                              "groups",
+                                                              json_grp_arr);
+                               }
+
+                               json_grp = json_object_new_object();
+                               json_object_string_add(json_grp, "source",
+                                                      source_str);
+                               json_object_string_add(json_grp, "group",
+                                                      group_str);
+                               json_object_string_add(json_grp, "primaryAddr",
+                                                      pri_addr_str);
+                               json_object_array_add(json_grp_arr, json_grp);
+                       } else {
+                               vty_out(vty, "%-16s %-15s %-15s %-15s\n",
+                                       ifp->name, pri_addr_str, source_str,
+                                       group_str);
+                       }
+               } /* for (pim_ifp->static_group_list) */
+
+       } /* for (iflist) */
+
+       if (uj)
+               vty_json(vty, json);
+}
+
 static void igmp_show_statistics(struct pim_instance *pim, struct vty *vty,
                                 const char *ifname, bool uj)
 {
@@ -1724,6 +1809,15 @@ DEFUN (show_ip_igmp_join,
 
        return CMD_SUCCESS;
 }
+ALIAS (show_ip_igmp_join,
+       show_ip_igmp_join_group_cmd,
+       "show ip igmp [vrf NAME] join-group [json]",
+       SHOW_STR
+       IP_STR
+       IGMP_STR
+       VRF_CMD_HELP_STR
+       "IGMP static join information\n"
+       JSON_STR);
 
 DEFUN (show_ip_igmp_join_vrf_all,
        show_ip_igmp_join_vrf_all_cmd,
@@ -1756,6 +1850,69 @@ DEFUN (show_ip_igmp_join_vrf_all,
 
        return CMD_SUCCESS;
 }
+ALIAS (show_ip_igmp_join_vrf_all,
+       show_ip_igmp_join_group_vrf_all_cmd,
+       "show ip igmp vrf all join-group [json]",
+       SHOW_STR
+       IP_STR
+       IGMP_STR
+       VRF_CMD_HELP_STR
+       "IGMP static join information\n"
+       JSON_STR);
+
+DEFUN (show_ip_igmp_static_group,
+       show_ip_igmp_static_group_cmd,
+       "show ip igmp [vrf NAME] static-group [json]",
+       SHOW_STR
+       IP_STR
+       IGMP_STR
+       VRF_CMD_HELP_STR
+       "Static group information\n"
+       JSON_STR)
+{
+       int idx = 2;
+       bool uj = use_json(argc, argv);
+       struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx, uj);
+
+       if (!vrf)
+               return CMD_WARNING;
+
+       igmp_show_interface_static_group(vrf->info, vty, uj);
+
+       return CMD_SUCCESS;
+}
+
+DEFUN (show_ip_igmp_static_group_vrf_all,
+       show_ip_igmp_static_group_vrf_all_cmd,
+       "show ip igmp vrf all static-group [json]",
+       SHOW_STR
+       IP_STR
+       IGMP_STR
+       VRF_CMD_HELP_STR
+       "Static group information\n"
+       JSON_STR)
+{
+       bool uj = use_json(argc, argv);
+       struct vrf *vrf;
+       bool first = true;
+
+       if (uj)
+               vty_out(vty, "{ ");
+       RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
+               if (uj) {
+                       if (!first)
+                               vty_out(vty, ", ");
+                       vty_out(vty, " \"%s\": ", vrf->name);
+                       first = false;
+               } else
+                       vty_out(vty, "VRF: %s\n", vrf->name);
+               igmp_show_interface_static_group(vrf->info, vty, uj);
+       }
+       if (uj)
+               vty_out(vty, "}\n");
+
+       return CMD_SUCCESS;
+}
 
 DEFPY(show_ip_igmp_groups,
       show_ip_igmp_groups_cmd,
@@ -4890,71 +5047,47 @@ DEFUN (interface_no_ip_igmp,
                                    "frr-routing:ipv4");
 }
 
-DEFUN (interface_ip_igmp_join,
-       interface_ip_igmp_join_cmd,
-       "ip igmp join A.B.C.D [A.B.C.D]",
-       IP_STR
-       IFACE_IGMP_STR
-       "IGMP join multicast group\n"
-       "Multicast group address\n"
-       "Source address\n")
+DEFPY_YANG_HIDDEN (interface_ip_igmp_join,
+                   interface_ip_igmp_join_cmd,
+                   "[no] ip igmp join A.B.C.D$grp [A.B.C.D]$src",
+                   NO_STR
+                   IP_STR
+                   IFACE_IGMP_STR
+                   "IGMP join multicast group\n"
+                   "Multicast group address\n"
+                   "Source address\n")
 {
-       int idx_group = 3;
-       int idx_source = 4;
-       const char *source_str;
-       char xpath[XPATH_MAXLEN];
-
-       if (argc == 5) {
-               source_str = argv[idx_source]->arg;
-
-               if (strcmp(source_str, "0.0.0.0") == 0) {
-                       vty_out(vty, "Bad source address %s\n",
-                               argv[idx_source]->arg);
-                       return CMD_WARNING_CONFIG_FAILED;
-               }
-       } else
-               source_str = "0.0.0.0";
-
-       snprintf(xpath, sizeof(xpath), FRR_GMP_JOIN_XPATH,
-                "frr-routing:ipv4", argv[idx_group]->arg, source_str);
-
-       nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
-
-       return nb_cli_apply_changes(vty, NULL);
+       nb_cli_enqueue_change(vty, ".", (!no ? NB_OP_CREATE : NB_OP_DESTROY),
+                             NULL);
+       return nb_cli_apply_changes(vty, FRR_GMP_JOIN_GROUP_XPATH,
+                                   "frr-routing:ipv4", grp_str,
+                                   (src_str ? src_str : "0.0.0.0"));
 }
-
-DEFUN (interface_no_ip_igmp_join,
-       interface_no_ip_igmp_join_cmd,
-       "no ip igmp join A.B.C.D [A.B.C.D]",
-       NO_STR
-       IP_STR
-       IFACE_IGMP_STR
-       "IGMP join multicast group\n"
-       "Multicast group address\n"
-       "Source address\n")
-{
-       int idx_group = 4;
-       int idx_source = 5;
-       const char *source_str;
-       char xpath[XPATH_MAXLEN];
-
-       if (argc == 6) {
-               source_str = argv[idx_source]->arg;
-
-               if (strcmp(source_str, "0.0.0.0") == 0) {
-                       vty_out(vty, "Bad source address %s\n",
-                               argv[idx_source]->arg);
-                       return CMD_WARNING_CONFIG_FAILED;
-               }
-       } else
-               source_str = "0.0.0.0";
-
-       snprintf(xpath, sizeof(xpath), FRR_GMP_JOIN_XPATH,
-                "frr-routing:ipv4", argv[idx_group]->arg, source_str);
-
-       nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
-
-       return nb_cli_apply_changes(vty, NULL);
+ALIAS(interface_ip_igmp_join,
+      interface_ip_igmp_join_group_cmd,
+      "[no] ip igmp join-group A.B.C.D$grp [A.B.C.D]$src",
+      NO_STR
+      IP_STR
+      IFACE_IGMP_STR
+      "IGMP join multicast group\n"
+      "Multicast group address\n"
+      "Source address\n");
+
+DEFPY_YANG (interface_ip_igmp_static_group,
+            interface_ip_igmp_static_group_cmd,
+            "[no] ip igmp static-group A.B.C.D$grp [A.B.C.D]$src",
+            NO_STR
+            IP_STR
+            IFACE_IGMP_STR
+            "Static multicast group\n"
+            "Multicast group address\n"
+            "Source address\n")
+{
+       nb_cli_enqueue_change(vty, ".", (!no ? NB_OP_CREATE : NB_OP_DESTROY),
+                             NULL);
+       return nb_cli_apply_changes(vty, FRR_GMP_STATIC_GROUP_XPATH,
+                                   "frr-routing:ipv4", grp_str,
+                                   (src_str ? src_str : "0.0.0.0"));
 }
 
 DEFUN (interface_ip_igmp_query_interval,
@@ -8268,7 +8401,8 @@ void pim_cmd_init(void)
        install_element(INTERFACE_NODE, &interface_ip_igmp_cmd);
        install_element(INTERFACE_NODE, &interface_no_ip_igmp_cmd);
        install_element(INTERFACE_NODE, &interface_ip_igmp_join_cmd);
-       install_element(INTERFACE_NODE, &interface_no_ip_igmp_join_cmd);
+       install_element(INTERFACE_NODE, &interface_ip_igmp_join_group_cmd);
+       install_element(INTERFACE_NODE, &interface_ip_igmp_static_group_cmd);
        install_element(INTERFACE_NODE, &interface_ip_igmp_version_cmd);
        install_element(INTERFACE_NODE, &interface_no_ip_igmp_version_cmd);
        install_element(INTERFACE_NODE, &interface_ip_igmp_query_interval_cmd);
@@ -8328,7 +8462,11 @@ void pim_cmd_init(void)
        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);
+       install_element(VIEW_NODE, &show_ip_igmp_join_group_cmd);
        install_element(VIEW_NODE, &show_ip_igmp_join_vrf_all_cmd);
+       install_element(VIEW_NODE, &show_ip_igmp_join_group_vrf_all_cmd);
+       install_element(VIEW_NODE, &show_ip_igmp_static_group_cmd);
+       install_element(VIEW_NODE, &show_ip_igmp_static_group_vrf_all_cmd);
        install_element(VIEW_NODE, &show_ip_igmp_groups_cmd);
        install_element(VIEW_NODE, &show_ip_igmp_groups_vrf_all_cmd);
        install_element(VIEW_NODE, &show_ip_igmp_groups_retransmissions_cmd);
index dcb6116012e5ec863bffbc7f12ab69e8009f7900..ba23e4ec82a412aba295a57998cc9092d1d3b1a7 100644 (file)
 #include "pim_jp_agg.h"
 #include "pim_igmp_join.h"
 #include "pim_vxlan.h"
+#include "pim_tib.h"
 
 #include "pim6_mld.h"
 
 static void pim_if_gm_join_del_all(struct interface *ifp);
+static void pim_if_static_group_del_all(struct interface *ifp);
 
 static int gm_join_sock(const char *ifname, ifindex_t ifindex,
                        pim_addr group_addr, pim_addr source_addr,
@@ -144,6 +146,7 @@ struct pim_interface *pim_if_new(struct interface *ifp, bool gm, bool pim,
        pim_ifp->gm_enable = gm;
 
        pim_ifp->gm_join_list = NULL;
+       pim_ifp->static_group_list = NULL;
        pim_ifp->pim_neighbor_list = NULL;
        pim_ifp->upstream_switch_list = NULL;
        pim_ifp->pim_generation_id = 0;
@@ -188,9 +191,11 @@ void pim_if_delete(struct interface *ifp)
        assert(pim_ifp);
 
        pim_ifp->pim->mcast_if_count--;
-       if (pim_ifp->gm_join_list) {
+       if (pim_ifp->gm_join_list)
                pim_if_gm_join_del_all(ifp);
-       }
+
+       if (pim_ifp->static_group_list)
+               pim_if_static_group_del_all(ifp);
 
        pim_ifchannel_delete_all(ifp);
 #if PIM_IPV == 4
@@ -1218,6 +1223,11 @@ static void gm_join_free(struct gm_join *ij)
        XFREE(MTYPE_PIM_IGMP_JOIN, ij);
 }
 
+static void static_group_free(struct static_group *stgrp)
+{
+       XFREE(MTYPE_PIM_STATIC_GROUP, stgrp);
+}
+
 static struct gm_join *gm_join_find(struct list *join_list, pim_addr group_addr,
                                    pim_addr source_addr)
 {
@@ -1232,7 +1242,25 @@ static struct gm_join *gm_join_find(struct list *join_list, pim_addr group_addr,
                        return ij;
        }
 
-       return 0;
+       return NULL;
+}
+
+static struct static_group *static_group_find(struct list *static_group_list,
+                                             pim_addr group_addr,
+                                             pim_addr source_addr)
+{
+       struct listnode *node;
+       struct static_group *stgrp;
+
+       assert(static_group_list);
+
+       for (ALL_LIST_ELEMENTS_RO(static_group_list, node, stgrp)) {
+               if ((!pim_addr_cmp(group_addr, stgrp->group_addr)) &&
+                   (!pim_addr_cmp(source_addr, stgrp->source_addr)))
+                       return stgrp;
+       }
+
+       return NULL;
 }
 
 static int gm_join_sock(const char *ifname, ifindex_t ifindex,
@@ -1296,6 +1324,34 @@ static struct gm_join *gm_join_new(struct interface *ifp, pim_addr group_addr,
        return ij;
 }
 
+static struct static_group *static_group_new(struct interface *ifp,
+                                            pim_addr group_addr,
+                                            pim_addr source_addr)
+{
+       struct pim_interface *pim_ifp;
+       struct static_group *stgrp;
+       pim_sgaddr sg;
+
+       pim_ifp = ifp->info;
+       assert(pim_ifp);
+
+       stgrp = XCALLOC(MTYPE_PIM_STATIC_GROUP, sizeof(*stgrp));
+
+       stgrp->group_addr = group_addr;
+       stgrp->source_addr = source_addr;
+       stgrp->oilp = NULL;
+
+       memset(&sg, 0, sizeof(sg));
+       sg.src = source_addr;
+       sg.grp = group_addr;
+
+       tib_sg_gm_join(pim_ifp->pim, sg, ifp, &(stgrp->oilp));
+
+       listnode_add(pim_ifp->static_group_list, stgrp);
+
+       return stgrp;
+}
+
 ferr_r pim_if_gm_join_add(struct interface *ifp, pim_addr group_addr,
                          pim_addr source_addr)
 {
@@ -1379,7 +1435,6 @@ int pim_if_gm_join_del(struct interface *ifp, pim_addr group_addr,
        return 0;
 }
 
-__attribute__((unused))
 static void pim_if_gm_join_del_all(struct interface *ifp)
 {
        struct pim_interface *pim_ifp;
@@ -1401,6 +1456,109 @@ static void pim_if_gm_join_del_all(struct interface *ifp)
                pim_if_gm_join_del(ifp, ij->group_addr, ij->source_addr);
 }
 
+ferr_r pim_if_static_group_add(struct interface *ifp, pim_addr group_addr,
+                              pim_addr source_addr)
+{
+       struct pim_interface *pim_ifp;
+       struct static_group *stgrp;
+
+       pim_ifp = ifp->info;
+       if (!pim_ifp) {
+               return ferr_cfg_invalid("multicast not enabled on interface %s",
+                                       ifp->name);
+       }
+
+       if (!pim_ifp->static_group_list) {
+               pim_ifp->static_group_list = list_new();
+               pim_ifp->static_group_list->del =
+                       (void (*)(void *))static_group_free;
+       }
+
+       stgrp = static_group_find(pim_ifp->static_group_list, group_addr,
+                                 source_addr);
+
+       /* This interface has already been configured with this static group
+        */
+       if (stgrp)
+               return ferr_ok();
+
+       (void)static_group_new(ifp, group_addr, source_addr);
+
+       if (PIM_DEBUG_GM_EVENTS) {
+               zlog_debug("%s: Added static group (S,G)=(%pPA,%pPA) on interface %s",
+                          __func__, &source_addr, &group_addr, ifp->name);
+       }
+
+       return ferr_ok();
+}
+
+int pim_if_static_group_del(struct interface *ifp, pim_addr group_addr,
+                           pim_addr source_addr)
+{
+       struct pim_interface *pim_ifp;
+       struct static_group *stgrp;
+       pim_sgaddr sg;
+
+       pim_ifp = ifp->info;
+       if (!pim_ifp) {
+               zlog_warn("%s: multicast not enabled on interface %s", __func__,
+                         ifp->name);
+               return -1;
+       }
+
+       if (!pim_ifp->static_group_list) {
+               zlog_warn("%s: no static groups on interface %s", __func__,
+                         ifp->name);
+               return -2;
+       }
+
+       stgrp = static_group_find(pim_ifp->static_group_list, group_addr,
+                                 source_addr);
+       if (!stgrp) {
+               zlog_warn("%s: could not find static group %pPAs source %pPAs on interface %s",
+                         __func__, &group_addr, &source_addr, ifp->name);
+               return -3;
+       }
+
+       memset(&sg, 0, sizeof(sg));
+       sg.src = source_addr;
+       sg.grp = group_addr;
+
+       tib_sg_gm_prune(pim_ifp->pim, sg, ifp, &(stgrp->oilp));
+
+       listnode_delete(pim_ifp->static_group_list, stgrp);
+       static_group_free(stgrp);
+       if (listcount(pim_ifp->static_group_list) < 1) {
+               list_delete(&pim_ifp->static_group_list);
+               pim_ifp->static_group_list = 0;
+       }
+
+       return 0;
+}
+
+static void pim_if_static_group_del_all(struct interface *ifp)
+{
+       struct pim_interface *pim_ifp;
+       struct listnode *node;
+       struct listnode *nextnode;
+       struct static_group *stgrp;
+
+       pim_ifp = ifp->info;
+       if (!pim_ifp) {
+               zlog_warn("%s: multicast not enabled on interface %s", __func__,
+                         ifp->name);
+               return;
+       }
+
+       if (!pim_ifp->static_group_list)
+               return;
+
+       for (ALL_LIST_ELEMENTS(pim_ifp->static_group_list, node, nextnode,
+                              stgrp))
+               pim_if_static_group_del(ifp, stgrp->group_addr,
+                                       stgrp->source_addr);
+}
+
 /*
   RFC 4601
 
index 0312f719d3005fc0b368e6c481fb3f0e78d8ba84..4d20379665982f31dfb1157c6fd334a30c1fd26e 100644 (file)
@@ -98,6 +98,7 @@ struct pim_interface {
                                                       */
        struct list *gm_socket_list; /* list of struct IGMP or MLD sock */
        struct list *gm_join_list;   /* list of struct IGMP or MLD join */
+       struct list *static_group_list; /* list of struct static group */
        struct list *gm_group_list;  /* list of struct IGMP or MLD group */
        struct hash *gm_group_hash;
 
@@ -222,6 +223,11 @@ ferr_r pim_if_gm_join_add(struct interface *ifp, pim_addr group_addr,
 int pim_if_gm_join_del(struct interface *ifp, pim_addr group_addr,
                       pim_addr source_addr);
 
+ferr_r pim_if_static_group_add(struct interface *ifp, pim_addr group_addr,
+                              pim_addr source_addr);
+int pim_if_static_group_del(struct interface *ifp, pim_addr group_addr,
+                           pim_addr source_addr);
+
 void pim_if_update_could_assert(struct interface *ifp);
 
 void pim_if_assert_on_neighbor_down(struct interface *ifp, pim_addr neigh_addr);
index a1f19b3c6e1cd7ce4aa524725988e212e4bc33e8..de0ec01a655e4956d29652c789b4d74348ddbf79 100644 (file)
@@ -58,6 +58,12 @@ struct gm_join {
        time_t sock_creation;
 };
 
+struct static_group {
+       pim_addr group_addr;
+       pim_addr source_addr;
+       struct channel_oil *oilp;
+};
+
 struct gm_sock {
        int fd;
        struct interface *interface;
index 85780f013b321f08d70c02c8e3f8c34ea36adaf5..31e2646f0537c376c951d22ceb34eb2fa2eae508 100644 (file)
@@ -14,6 +14,7 @@ DEFINE_MGROUP(PIMD, "pimd");
 DEFINE_MTYPE(PIMD, PIM_CHANNEL_OIL, "PIM SSM (S,G) channel OIL");
 DEFINE_MTYPE(PIMD, PIM_INTERFACE, "PIM interface");
 DEFINE_MTYPE(PIMD, PIM_IGMP_JOIN, "PIM interface IGMP static join");
+DEFINE_MTYPE(PIMD, PIM_STATIC_GROUP, "PIM interface IGMP static group");
 DEFINE_MTYPE(PIMD, PIM_IGMP_SOCKET, "PIM interface IGMP socket");
 DEFINE_MTYPE(PIMD, PIM_IGMP_GROUP, "PIM interface IGMP group");
 DEFINE_MTYPE(PIMD, PIM_IGMP_GROUP_SOURCE, "PIM interface IGMP source");
index 41730e752284eb961f34416d024f25ed956eda84..8534aab7bebde6003d3043b28ca59f04e3ad33ec 100644 (file)
@@ -13,6 +13,7 @@ DECLARE_MGROUP(PIMD);
 DECLARE_MTYPE(PIM_CHANNEL_OIL);
 DECLARE_MTYPE(PIM_INTERFACE);
 DECLARE_MTYPE(PIM_IGMP_JOIN);
+DECLARE_MTYPE(PIM_STATIC_GROUP);
 DECLARE_MTYPE(PIM_IGMP_SOCKET);
 DECLARE_MTYPE(PIM_IGMP_GROUP);
 DECLARE_MTYPE(PIM_IGMP_GROUP_SOURCE);
index 339935f81a57b4c757743aa9a3f9cf1c63669ed1..dd88677efd2cb38522ae680bd895a8bdef78c561 100644 (file)
@@ -413,6 +413,13 @@ const struct frr_yang_module_info frr_gmp_info = {
                                .modify = lib_interface_gmp_address_family_robustness_variable_modify,
                        }
                },
+               {
+                       .xpath = "/frr-interface:lib/interface/frr-gmp:gmp/address-family/join-group",
+                       .cbs = {
+                               .create = lib_interface_gmp_address_family_join_group_create,
+                               .destroy = lib_interface_gmp_address_family_join_group_destroy,
+                       }
+               },
                {
                        .xpath = "/frr-interface:lib/interface/frr-gmp:gmp/address-family/static-group",
                        .cbs = {
@@ -425,4 +432,3 @@ const struct frr_yang_module_info frr_gmp_info = {
                },
        }
 };
-
index 2d854d73de5ec493de7cb0987a6267c48bac5cd8..1ce9afbc4bf4fc97e73cb3d93f501bc395657c14 100644 (file)
@@ -175,6 +175,10 @@ int lib_interface_gmp_address_family_last_member_query_interval_modify(
                struct nb_cb_modify_args *args);
 int lib_interface_gmp_address_family_robustness_variable_modify(
                struct nb_cb_modify_args *args);
+int lib_interface_gmp_address_family_join_group_create(
+       struct nb_cb_create_args *args);
+int lib_interface_gmp_address_family_join_group_destroy(
+       struct nb_cb_destroy_args *args);
 int lib_interface_gmp_address_family_static_group_create(
                struct nb_cb_create_args *args);
 int lib_interface_gmp_address_family_static_group_destroy(
@@ -212,8 +216,11 @@ int routing_control_plane_protocols_name_validate(
        "./frr-gmp:gmp/address-family[address-family='%s']"
 #define FRR_GMP_ENABLE_XPATH                                            \
        "%s/frr-gmp:gmp/address-family[address-family='%s']/enable"
-#define FRR_GMP_JOIN_XPATH                                              \
-       "./frr-gmp:gmp/address-family[address-family='%s']/"            \
+#define FRR_GMP_JOIN_GROUP_XPATH                                               \
+       "./frr-gmp:gmp/address-family[address-family='%s']/"                   \
+       "join-group[group-addr='%s'][source-addr='%s']"
+#define FRR_GMP_STATIC_GROUP_XPATH                                             \
+       "./frr-gmp:gmp/address-family[address-family='%s']/"                   \
        "static-group[group-addr='%s'][source-addr='%s']"
 
 #endif /* _FRR_PIM_NB_H_ */
index be0be8588b3094ff43e255b2b11259b6bc2faf9e..fb67f74ba20a33921a37436e9ebfa2bf51281925 100644 (file)
@@ -2821,9 +2821,9 @@ int lib_interface_gmp_address_family_robustness_variable_modify(
 }
 
 /*
- * XPath: /frr-interface:lib/interface/frr-gmp:gmp/address-family/static-group
+ * XPath: /frr-interface:lib/interface/frr-gmp:gmp/address-family/join-group
  */
-int lib_interface_gmp_address_family_static_group_create(
+int lib_interface_gmp_address_family_join_group_create(
        struct nb_cb_create_args *args)
 {
        struct interface *ifp;
@@ -2881,7 +2881,7 @@ int lib_interface_gmp_address_family_static_group_create(
        return NB_OK;
 }
 
-int lib_interface_gmp_address_family_static_group_destroy(
+int lib_interface_gmp_address_family_join_group_destroy(
        struct nb_cb_destroy_args *args)
 {
        struct interface *ifp;
@@ -2916,3 +2916,94 @@ int lib_interface_gmp_address_family_static_group_destroy(
 
        return NB_OK;
 }
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-gmp:gmp/address-family/static-group
+ */
+int lib_interface_gmp_address_family_static_group_create(
+       struct nb_cb_create_args *args)
+{
+       struct interface *ifp;
+       pim_addr source_addr;
+       pim_addr group_addr;
+       int result;
+       const char *ifp_name;
+       const struct lyd_node *if_dnode;
+
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+               if_dnode = yang_dnode_get_parent(args->dnode, "interface");
+               if (!is_pim_interface(if_dnode)) {
+                       ifp_name = yang_dnode_get_string(if_dnode, "name");
+                       snprintf(args->errmsg, args->errmsg_len,
+                                "multicast not enabled on interface %s",
+                                ifp_name);
+                       return NB_ERR_VALIDATION;
+               }
+
+               yang_dnode_get_pimaddr(&group_addr, args->dnode, "./group-addr");
+#if PIM_IPV == 4
+               if (pim_is_group_224_0_0_0_24(group_addr)) {
+                       snprintf(args->errmsg, args->errmsg_len,
+                                "Groups within 224.0.0.0/24 are reserved and cannot be joined");
+                       return NB_ERR_VALIDATION;
+               }
+#else
+               if (ipv6_mcast_reserved(&group_addr)) {
+                       snprintf(args->errmsg, args->errmsg_len,
+                                "Groups within ffx2::/16 are reserved and cannot be joined");
+                       return NB_ERR_VALIDATION;
+               }
+#endif
+               break;
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               ifp = nb_running_get_entry(args->dnode, NULL, true);
+               yang_dnode_get_pimaddr(&source_addr, args->dnode,
+                                      "./source-addr");
+               yang_dnode_get_pimaddr(&group_addr, args->dnode, "./group-addr");
+               result = pim_if_static_group_add(ifp, group_addr, source_addr);
+               if (result) {
+                       snprintf(args->errmsg, args->errmsg_len,
+                                "Failure adding static group");
+                       return NB_ERR_INCONSISTENCY;
+               }
+       }
+       return NB_OK;
+}
+
+int lib_interface_gmp_address_family_static_group_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       struct interface *ifp;
+       pim_addr source_addr;
+       pim_addr group_addr;
+       int result;
+
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               ifp = nb_running_get_entry(args->dnode, NULL, true);
+               yang_dnode_get_pimaddr(&source_addr, args->dnode,
+                                      "./source-addr");
+               yang_dnode_get_pimaddr(&group_addr, args->dnode, "./group-addr");
+               result = pim_if_static_group_del(ifp, group_addr, source_addr);
+
+               if (result) {
+                       snprintf(args->errmsg, args->errmsg_len,
+                                "%% Failure removing static group %pPAs %pPAs on interface %s: %d",
+                                &source_addr, &group_addr, ifp->name, result);
+
+                       return NB_ERR_INCONSISTENCY;
+               }
+
+               break;
+       }
+
+       return NB_OK;
+}
index 1910a684957e36d352c7cefa65da7ce02c82f231..9cf4bb3e874a1a70ddf1ad3f21940e3fc57edf48 100644 (file)
@@ -306,21 +306,38 @@ static int gm_config_write(struct vty *vty, int writes,
                ++writes;
        }
 
-       /* IF ip igmp join */
+       /* IF ip igmp join-group */
        if (pim_ifp->gm_join_list) {
                struct listnode *node;
                struct gm_join *ij;
                for (ALL_LIST_ELEMENTS_RO(pim_ifp->gm_join_list, node, ij)) {
                        if (pim_addr_is_any(ij->source_addr))
-                               vty_out(vty, " ip igmp join %pPAs\n",
+                               vty_out(vty, " ip igmp join-group %pPAs\n",
                                        &ij->group_addr);
                        else
-                               vty_out(vty, " ip igmp join %pPAs %pPAs\n",
+                               vty_out(vty, " ip igmp join-group %pPAs %pPAs\n",
                                        &ij->group_addr, &ij->source_addr);
                        ++writes;
                }
        }
 
+       /* IF ip igmp static-group */
+       if (pim_ifp->static_group_list) {
+               struct listnode *node;
+               struct static_group *stgrp;
+               for (ALL_LIST_ELEMENTS_RO(pim_ifp->static_group_list, node,
+                                         stgrp)) {
+                       if (pim_addr_is_any(stgrp->source_addr))
+                               vty_out(vty, " ip igmp static-group %pPAs\n",
+                                       &stgrp->group_addr);
+                       else
+                               vty_out(vty,
+                                       " ip igmp static-group %pPAs %pPAs\n",
+                                       &stgrp->group_addr, &stgrp->source_addr);
+                       ++writes;
+               }
+       }
+
        return writes;
 }
 #else
@@ -358,21 +375,41 @@ static int gm_config_write(struct vty *vty, int writes,
                vty_out(vty, " ipv6 mld last-member-query-interval %d\n",
                        pim_ifp->gm_specific_query_max_response_time_dsec);
 
-       /* IF ipv6 mld join */
+       /* IF ipv6 mld join-group */
        if (pim_ifp->gm_join_list) {
                struct listnode *node;
                struct gm_join *ij;
+
                for (ALL_LIST_ELEMENTS_RO(pim_ifp->gm_join_list, node, ij)) {
                        if (pim_addr_is_any(ij->source_addr))
-                               vty_out(vty, " ipv6 mld join %pPAs\n",
+                               vty_out(vty, " ipv6 mld join-group %pPAs\n",
                                        &ij->group_addr);
                        else
-                               vty_out(vty, " ipv6 mld join %pPAs %pPAs\n",
+                               vty_out(vty,
+                                       " ipv6 mld join-group %pPAs %pPAs\n",
                                        &ij->group_addr, &ij->source_addr);
                        ++writes;
                }
        }
 
+       /* IF ipv6 mld static-group */
+       if (pim_ifp->static_group_list) {
+               struct listnode *node;
+               struct static_group *stgrp;
+
+               for (ALL_LIST_ELEMENTS_RO(pim_ifp->static_group_list, node,
+                                         stgrp)) {
+                       if (pim_addr_is_any(stgrp->source_addr))
+                               vty_out(vty, " ipv6 mld static-group %pPAs\n",
+                                       &stgrp->group_addr);
+                       else
+                               vty_out(vty,
+                                       " ipv6 mld static-group %pPAs %pPAs\n",
+                                       &stgrp->group_addr, &stgrp->source_addr);
+                       ++writes;
+               }
+       }
+
        return writes;
 }
 #endif
index c8a05a2bdba71482e48db25bb527f966628f2179..e6a1f7f640bb4cf24acf5eeea08ef19bee889cfd 100644 (file)
@@ -147,10 +147,10 @@ module frr-gmp {
          expected packet loss on a network.";
     }
 
-    list static-group {
+    list join-group {
       key "group-addr source-addr";
       description
-        "A static multicast route, (*,G) or (S,G).
+        "A static GMP join, (*,G) or (S,G).
          The version of IGMP must be 3 to support (S,G).";
 
       leaf group-addr {
@@ -164,6 +164,23 @@ module frr-gmp {
           "Multicast source address.";
       }
     }
+
+    list static-group {
+      key "group-addr source-addr";
+      description
+        "A static multicast group without GMP, (*,G) or (S,G).";
+
+      leaf group-addr {
+        type rt-types:ip-multicast-group-address;
+        description
+          "Multicast group address.";
+      }
+      leaf source-addr {
+        type inet:ip-address;
+        description
+          "Multicast source address.";
+      }
+    }
   } // interface-config-attributes
 
   /*