forked from Mirror/frr
pimd: implement IGMP group/source count limit
For groups we can just look at the length of the list, for sources we need to count them on a per-interface level. Signed-off-by: David Lamparter <equinox@opensourcerouting.org>
This commit is contained in:
parent
baf4c1a78f
commit
f07d379b74
|
@ -5656,6 +5656,43 @@ DEFUN (interface_no_ip_igmp_last_member_query_interval,
|
|||
return gm_process_no_last_member_query_interval_cmd(vty);
|
||||
}
|
||||
|
||||
DEFPY_YANG(interface_ip_igmp_limits,
|
||||
interface_ip_igmp_limits_cmd,
|
||||
"[no] ip igmp <max-sources$do_src (0-4294967295)$val"
|
||||
"|max-groups$do_grp (0-4294967295)$val>",
|
||||
NO_STR
|
||||
IP_STR
|
||||
IFACE_IGMP_STR
|
||||
"Limit number of IGMPv3 sources to track\n"
|
||||
"Permitted number of sources\n"
|
||||
"Limit number of IGMP group memberships to track\n"
|
||||
"Permitted number of groups\n")
|
||||
{
|
||||
const char *xpath;
|
||||
|
||||
assert(do_src || do_grp);
|
||||
if (do_src)
|
||||
xpath = "./max-sources";
|
||||
else
|
||||
xpath = "./max-groups";
|
||||
|
||||
if (no)
|
||||
nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
|
||||
else
|
||||
nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, val_str);
|
||||
|
||||
return nb_cli_apply_changes(vty, FRR_GMP_INTERFACE_XPATH, FRR_PIM_AF_XPATH_VAL);
|
||||
}
|
||||
|
||||
ALIAS_YANG(interface_ip_igmp_limits,
|
||||
no_interface_ip_igmp_limits_cmd,
|
||||
"no ip igmp <max-sources$do_src|max-groups$do_grp>",
|
||||
NO_STR
|
||||
IP_STR
|
||||
IFACE_IGMP_STR
|
||||
"Limit number of IGMPv3 sources to track\n"
|
||||
"Limit number of IGMP group memberships to track\n")
|
||||
|
||||
DEFUN (interface_ip_pim_drprio,
|
||||
interface_ip_pim_drprio_cmd,
|
||||
"ip pim drpriority (0-4294967295)",
|
||||
|
@ -9101,6 +9138,8 @@ void pim_cmd_init(void)
|
|||
install_element(INTERFACE_NODE,
|
||||
&interface_no_ip_igmp_last_member_query_interval_cmd);
|
||||
install_element(INTERFACE_NODE, &interface_ip_igmp_proxy_cmd);
|
||||
install_element(INTERFACE_NODE, &interface_ip_igmp_limits_cmd);
|
||||
install_element(INTERFACE_NODE, &no_interface_ip_igmp_limits_cmd);
|
||||
install_element(INTERFACE_NODE, &interface_ip_pim_activeactive_cmd);
|
||||
install_element(INTERFACE_NODE, &interface_ip_pim_ssm_cmd);
|
||||
install_element(INTERFACE_NODE, &interface_no_ip_pim_ssm_cmd);
|
||||
|
|
|
@ -105,6 +105,8 @@ struct pim_interface {
|
|||
|
||||
struct gm_if *mld;
|
||||
|
||||
uint32_t gm_source_limit, gm_group_limit;
|
||||
|
||||
int pim_sock_fd; /* PIM socket file descriptor */
|
||||
struct event *t_pim_sock_read; /* thread for reading PIM socket */
|
||||
int64_t pim_sock_creation; /* timestamp of PIM socket creation */
|
||||
|
|
|
@ -1126,6 +1126,9 @@ void pim_igmp_if_init(struct pim_interface *pim_ifp, struct interface *ifp)
|
|||
{
|
||||
char hash_name[64];
|
||||
|
||||
pim_ifp->gm_group_limit = UINT32_MAX;
|
||||
pim_ifp->gm_source_limit = UINT32_MAX;
|
||||
|
||||
pim_ifp->gm_socket_list = list_new();
|
||||
pim_ifp->gm_socket_list->del = (void (*)(void *))igmp_sock_free;
|
||||
|
||||
|
@ -1416,6 +1419,14 @@ struct gm_group *igmp_add_group_by_addr(struct gm_sock *igmp,
|
|||
__func__, &group_addr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (listcount(pim_ifp->gm_group_list) >= pim_ifp->gm_group_limit) {
|
||||
if (PIM_DEBUG_GM_TRACE)
|
||||
zlog_debug("interface %s has reached group limit (%u), refusing to add group %pI4",
|
||||
igmp->interface->name, pim_ifp->gm_group_limit, &group_addr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
Non-existant group is created as INCLUDE {empty}:
|
||||
|
||||
|
|
|
@ -423,6 +423,7 @@ struct gm_source *igmp_find_source_by_addr(struct gm_group *group,
|
|||
struct gm_source *igmp_get_source_by_addr(struct gm_group *group,
|
||||
struct in_addr src_addr, bool *new)
|
||||
{
|
||||
const struct pim_interface *pim_interface = group->interface->info;
|
||||
struct gm_source *src;
|
||||
|
||||
if (new)
|
||||
|
@ -432,6 +433,14 @@ struct gm_source *igmp_get_source_by_addr(struct gm_group *group,
|
|||
if (src)
|
||||
return src;
|
||||
|
||||
if (listcount(group->group_source_list) >= pim_interface->gm_source_limit) {
|
||||
if (PIM_DEBUG_GM_TRACE)
|
||||
zlog_debug("interface %s has reached source limit (%u), refusing to add source %pI4 (group %pI4)",
|
||||
group->interface->name, pim_interface->gm_source_limit,
|
||||
&src_addr, &group->group_addr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (PIM_DEBUG_GM_TRACE) {
|
||||
char group_str[INET_ADDRSTRLEN];
|
||||
char source_str[INET_ADDRSTRLEN];
|
||||
|
|
|
@ -724,6 +724,18 @@ const struct frr_yang_module_info frr_gmp_info = {
|
|||
.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/max-sources",
|
||||
.cbs = {
|
||||
.modify = lib_interface_gm_max_sources_modify,
|
||||
}
|
||||
},
|
||||
{
|
||||
.xpath = "/frr-interface:lib/interface/frr-gmp:gmp/address-family/max-groups",
|
||||
.cbs = {
|
||||
.modify = lib_interface_gm_max_groups_modify,
|
||||
}
|
||||
},
|
||||
{
|
||||
.xpath = "/frr-interface:lib/interface/frr-gmp:gmp/address-family/proxy",
|
||||
|
|
|
@ -287,6 +287,8 @@ int lib_interface_gmp_address_family_static_group_create(
|
|||
struct nb_cb_create_args *args);
|
||||
int lib_interface_gmp_address_family_static_group_destroy(
|
||||
struct nb_cb_destroy_args *args);
|
||||
int lib_interface_gm_max_sources_modify(struct nb_cb_modify_args *args);
|
||||
int lib_interface_gm_max_groups_modify(struct nb_cb_modify_args *args);
|
||||
|
||||
/*
|
||||
* Callback registered with routing_nb lib to validate only
|
||||
|
|
|
@ -4396,6 +4396,72 @@ int lib_interface_gmp_address_family_last_member_query_interval_modify(
|
|||
return NB_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* XPath: /frr-interface:lib/interface/frr-gmp:gmp/address-family/max-groups
|
||||
*/
|
||||
int lib_interface_gm_max_groups_modify(struct nb_cb_modify_args *args)
|
||||
{
|
||||
struct interface *ifp;
|
||||
struct pim_interface *pim_ifp;
|
||||
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;
|
||||
}
|
||||
break;
|
||||
case NB_EV_PREPARE:
|
||||
case NB_EV_ABORT:
|
||||
break;
|
||||
case NB_EV_APPLY:
|
||||
ifp = nb_running_get_entry(args->dnode, NULL, true);
|
||||
pim_ifp = ifp->info;
|
||||
pim_ifp->gm_group_limit = yang_dnode_get_uint32(args->dnode, NULL);
|
||||
break;
|
||||
}
|
||||
|
||||
return NB_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* XPath: /frr-interface:lib/interface/frr-gmp:gmp/address-family/max-sources
|
||||
*/
|
||||
int lib_interface_gm_max_sources_modify(struct nb_cb_modify_args *args)
|
||||
{
|
||||
struct interface *ifp;
|
||||
struct pim_interface *pim_ifp;
|
||||
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;
|
||||
}
|
||||
break;
|
||||
case NB_EV_PREPARE:
|
||||
case NB_EV_ABORT:
|
||||
break;
|
||||
case NB_EV_APPLY:
|
||||
ifp = nb_running_get_entry(args->dnode, NULL, true);
|
||||
pim_ifp = ifp->info;
|
||||
pim_ifp->gm_source_limit = yang_dnode_get_uint32(args->dnode, NULL);
|
||||
break;
|
||||
}
|
||||
|
||||
return NB_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* XPath: /frr-interface:lib/interface/frr-gmp:gmp/address-family/robustness-variable
|
||||
*/
|
||||
|
|
|
@ -457,6 +457,20 @@ int pim_config_write(struct vty *vty, int writes, struct interface *ifp,
|
|||
++writes;
|
||||
}
|
||||
|
||||
/* IF ip igmp max-sources */
|
||||
if (pim_ifp->gm_source_limit != UINT32_MAX) {
|
||||
vty_out(vty, " " PIM_AF_NAME " " GM_AF_DBG " max-sources %u\n",
|
||||
pim_ifp->gm_source_limit);
|
||||
++writes;
|
||||
}
|
||||
|
||||
/* IF ip igmp max-groups */
|
||||
if (pim_ifp->gm_group_limit != UINT32_MAX) {
|
||||
vty_out(vty, " " PIM_AF_NAME " " GM_AF_DBG " max-groups %u\n",
|
||||
pim_ifp->gm_group_limit);
|
||||
++writes;
|
||||
}
|
||||
|
||||
/* IF ip pim drpriority */
|
||||
if (pim_ifp->pim_dr_priority != PIM_DEFAULT_DR_PRIORITY) {
|
||||
vty_out(vty, " " PIM_AF_NAME " pim drpriority %u\n",
|
||||
|
|
|
@ -154,6 +154,20 @@ module frr-gmp {
|
|||
"Enable IGMP proxy on the interface.";
|
||||
}
|
||||
|
||||
leaf max-groups {
|
||||
type uint32;
|
||||
default "4294967295";
|
||||
description
|
||||
"Limit number of tracked IGMP group memberships on this interface.";
|
||||
}
|
||||
|
||||
leaf max-sources {
|
||||
type uint32;
|
||||
default "4294967295";
|
||||
description
|
||||
"Limit number of tracked IGMPv3 sources on this interface.";
|
||||
}
|
||||
|
||||
list join-group {
|
||||
key "group-addr source-addr";
|
||||
description
|
||||
|
|
Loading…
Reference in a new issue