diff options
author | Donald Sharp <donaldsharp72@gmail.com> | 2024-08-22 17:32:56 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-08-22 17:32:56 +0200 |
commit | 05c17eff06536e750d43829ccded5c9e8f0f9ca4 (patch) | |
tree | 5cafbf2d7a2d501cc51f998d941ef7c11ccf300a /pimd | |
parent | Merge pull request #16613 from donaldsharp/weight_issues (diff) | |
parent | tests: Added new topotest for pim igmp static groups (diff) | |
download | frr-05c17eff06536e750d43829ccded5c9e8f0f9ca4.tar.xz frr-05c17eff06536e750d43829ccded5c9e8f0f9ca4.zip |
Merge pull request #16450 from nabahr/static_joins
PIM: Implement static IGMP joins without an IGMP report
Diffstat (limited to 'pimd')
-rw-r--r-- | pimd/pim6_cmd.c | 82 | ||||
-rw-r--r-- | pimd/pim_cmd.c | 266 | ||||
-rw-r--r-- | pimd/pim_iface.c | 166 | ||||
-rw-r--r-- | pimd/pim_iface.h | 6 | ||||
-rw-r--r-- | pimd/pim_igmp.h | 6 | ||||
-rw-r--r-- | pimd/pim_memory.c | 1 | ||||
-rw-r--r-- | pimd/pim_memory.h | 1 | ||||
-rw-r--r-- | pimd/pim_nb.c | 8 | ||||
-rw-r--r-- | pimd/pim_nb.h | 11 | ||||
-rw-r--r-- | pimd/pim_nb_config.c | 97 | ||||
-rw-r--r-- | pimd/pim_vty.c | 49 |
11 files changed, 578 insertions, 115 deletions
diff --git a/pimd/pim6_cmd.c b/pimd/pim6_cmd.c index 99f147471..f7a4e0e48 100644 --- a/pimd/pim6_cmd.c +++ b/pimd/pim6_cmd.c @@ -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); diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index f57048c70..633c46966 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -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, @@ -4924,71 +5081,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, @@ -8420,7 +8553,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); @@ -8480,7 +8614,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); diff --git a/pimd/pim_iface.c b/pimd/pim_iface.c index cdcca0ebe..45a2435ae 100644 --- a/pimd/pim_iface.c +++ b/pimd/pim_iface.c @@ -37,10 +37,12 @@ #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) { @@ -1382,7 +1438,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; @@ -1404,6 +1459,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 diff --git a/pimd/pim_iface.h b/pimd/pim_iface.h index 0312f719d..4d2037966 100644 --- a/pimd/pim_iface.h +++ b/pimd/pim_iface.h @@ -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); diff --git a/pimd/pim_igmp.h b/pimd/pim_igmp.h index a1f19b3c6..de0ec01a6 100644 --- a/pimd/pim_igmp.h +++ b/pimd/pim_igmp.h @@ -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; diff --git a/pimd/pim_memory.c b/pimd/pim_memory.c index 604e24482..2c35bc647 100644 --- a/pimd/pim_memory.c +++ b/pimd/pim_memory.c @@ -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"); diff --git a/pimd/pim_memory.h b/pimd/pim_memory.h index 353e09a71..b44d3e191 100644 --- a/pimd/pim_memory.h +++ b/pimd/pim_memory.h @@ -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); diff --git a/pimd/pim_nb.c b/pimd/pim_nb.c index 72b5bdefc..c154c18af 100644 --- a/pimd/pim_nb.c +++ b/pimd/pim_nb.c @@ -441,6 +441,13 @@ const struct frr_yang_module_info frr_gmp_info = { } }, { + .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 = { .create = lib_interface_gmp_address_family_static_group_create, @@ -452,4 +459,3 @@ const struct frr_yang_module_info frr_gmp_info = { }, } }; - diff --git a/pimd/pim_nb.h b/pimd/pim_nb.h index 3c7ab49ab..fc4c11cea 100644 --- a/pimd/pim_nb.h +++ b/pimd/pim_nb.h @@ -182,6 +182,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( @@ -219,8 +223,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_ */ diff --git a/pimd/pim_nb_config.c b/pimd/pim_nb_config.c index bc7338ce1..037bfea78 100644 --- a/pimd/pim_nb_config.c +++ b/pimd/pim_nb_config.c @@ -2989,9 +2989,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; @@ -3049,7 +3049,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; @@ -3084,3 +3084,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; +} diff --git a/pimd/pim_vty.c b/pimd/pim_vty.c index 1910a6849..9cf4bb3e8 100644 --- a/pimd/pim_vty.c +++ b/pimd/pim_vty.c @@ -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 |