From b6477e8b8479933c6827492fcedbf1b0686ffe5d Mon Sep 17 00:00:00 2001 From: Anatoly Mirin Date: Mon, 7 Aug 2023 13:44:36 +0300 Subject: [PATCH] mcastmngr: add snooping configuration support for linux targets l2 snooping mode implements on the linux kernel multicast bridge level. If snooping mode is enabled, mcastmngr configure kernel multicast bridge with the appropriate uci mcast params. --- mcastmngr/files/linux/lib/mcast/linux.sh | 167 +++++++++++++++++++++-- 1 file changed, 156 insertions(+), 11 deletions(-) diff --git a/mcastmngr/files/linux/lib/mcast/linux.sh b/mcastmngr/files/linux/lib/mcast/linux.sh index d67588a05..b969ba676 100755 --- a/mcastmngr/files/linux/lib/mcast/linux.sh +++ b/mcastmngr/files/linux/lib/mcast/linux.sh @@ -10,6 +10,8 @@ PROG_EXE=/usr/sbin/mcproxy PROG_PARAMS= PROG_PARAMS_SEPARATOR=: +snooping_bridges= + __device_is_bridge() { local device="$2" @@ -114,10 +116,11 @@ config_mcproxy_interfaces() { config_sysfs_mcast_snooping() { local downstreams="$1" + local snooping="$2" for downstream in $downstreams; do if device_is_bridge "$downstream"; then - echo 1 > /sys/class/net/$downstream/bridge/multicast_snooping + echo $snooping > /sys/class/net/$downstream/bridge/multicast_snooping fi done } @@ -136,7 +139,53 @@ config_sysfs_mcast_fastleave() { done } -config_sysfs_mcast_mode() { +config_sysfs_mcast_version() { + local protocol="$1" + local interfaces="$2" + local version="$3" + + for iface in $interfaces; do + echo $version > /sys/class/net/$iface/bridge/multicast_"$protocol"_version + done +} + +config_sysfs_mcast_robustness() { + local interfaces="$1" + local robustness="$2" + + for iface in $interfaces; do + echo $robustness > /sys/class/net/$iface/bridge/multicast_last_member_count + done +} + +config_sysfs_mcast_query_interval() { + local interfaces="$1" + local query_interval="$2" + + for iface in $interfaces; do + echo $query_interval > /sys/class/net/$iface/bridge/multicast_query_interval + done +} + +config_sysfs_mcast_q_resp_interval() { + local interfaces="$1" + local q_resp_interval="$2" + + for iface in $interfaces; do + echo $q_resp_interval > /sys/class/net/$iface/bridge/multicast_query_response_interval + done +} + +config_sysfs_mcast_last_mem_q_int() { + local interfaces="$1" + local last_mem_q_int="$2" + + for iface in $interfaces; do + echo $last_mem_q_int > /sys/class/net/$iface/bridge/multicast_last_member_interval + done +} + +config_sysfs_mcast_flood() { local downstreams=$1 local mcast_mode=$2 local prt @@ -157,6 +206,25 @@ config_sysfs_mcast_mode() { done } +config_snooping_mode() { + local interfaces="$1" + local snooping="$2" + + # snooping_mode: + # 0 - snooping is disabled + # 1 - multicast flood is enabled + # 2 - multicast flood is disabled + [ -z "$snooping_mode" ] && snooping_mode=2 + + if [ "$snooping_mode" == 0 ]; then + config_sysfs_mcast_snooping "$interfaces" 0 + else + config_sysfs_mcast_snooping "$interfaces" 1 + fi + + config_sysfs_mcast_flood "$interfaces" "$snooping_mode" +} + config_mcproxy_instance() { local protocol="$1" local version="$2" @@ -195,6 +263,11 @@ config_mcproxy_instance() { upstreams=$igmp_p_up_interfaces downstreams=$igmp_p_down_interfaces mcast_mode=$igmp_p_mode + + # mcproxy reserves two multicast subscriptions for igmp router service groups + local mg=$(cat /proc/sys/net/ipv4/igmp_max_memberships) + mg=$((mg+2)) + echo $mg > /proc/sys/net/ipv4/igmp_max_memberships elif [ "$protocol" == "mld" ]; then case "$version" in [1-2]) @@ -228,21 +301,98 @@ config_mcproxy_instance() { # for snooping to work we should enable it on the bridge, doing it from # here instead of from inside network config - config_sysfs_mcast_snooping "$downstreams" - [ -n $fast_leave ] && - config_sysfs_mcast_fastleave "$downstreams" "$fast_leave" - config_sysfs_mcast_mode "$downstreams" "$mcast_mode" + if [ "$downstreams" != "$snooping_bridges" ]; then + config_sysfs_mcast_snooping "$downstreams" 1 + [ -n $fast_leave ] && + config_sysfs_mcast_fastleave "$downstreams" "$fast_leave" + config_sysfs_mcast_flood "$downstreams" "$mcast_mode" + fi PROG_PARAMS="${PROG_PARAMS} -f ${CONFFILE}${PROG_PARAMS_SEPARATOR}" } +config_snooping() { + local protocol="$1" + + local version= + local robustness= + local query_interval= + local q_resp_interval= + local last_mem_q_int= + local fast_leave=0 + local snooping_mode= + local interfaces= + + local HZ=100 + + local all_interfaces= + if [ "$protocol" == "igmp" ]; then + all_interfaces=$igmp_s_iface + elif [ "$protocol" == "mld" ]; then + all_interfaces=$mld_s_iface + fi + for iface in $all_interfaces; do + device_is_bridge "$iface" || continue + interfaces="$interfaces $iface" + done + [ -z "$interfaces" ] && return + snooping_bridges="$interfaces" + + if [ "$protocol" == "igmp" ]; then + case "$igmp_s_version" in + [1-3]) + version="$igmp_s_version" + ;; + *) + version="2" + ;; + esac + + robustness=$igmp_s_robustness + query_interval=$(( igmp_s_query_interval * HZ )) + q_resp_interval=$(( igmp_s_q_resp_interval * HZ / 10 )) + last_mem_q_int=$(( igmp_s_last_mem_q_int * HZ / 10 )) + fast_leave=$igmp_s_fast_leave + snooping_mode=$igmp_s_mode + elif [ "$protocol" == "mld" ]; then + case "$mld_s_version" in + [1-2]) + version="$mld_s_version" + ;; + *) + version="2" + ;; + esac + + robustness=$mld_s_robustness + query_interval=$(( mld_s_query_interval * HZ )) + q_resp_interval=$(( mld_s_q_resp_interval * HZ / 10 )) + last_mem_q_int=$(( mld_s_last_mem_q_int * HZ / 10 )) + fast_leave=$mld_s_fast_leave + snooping_mode=$mld_s_mode + fi + + config_snooping_mode "$interfaces" "$snooping_mode" + + [ -n "$version" ] && config_sysfs_mcast_version "$protocol" "$interfaces" "$version" + [ -n "$robustness" ] && config_sysfs_mcast_robustness "$interfaces" "$robustness" + [ -n "$query_interval" ] && config_sysfs_mcast_query_interval "$interfaces" "$query_interval" + [ -n "$q_resp_interval" ] && config_sysfs_mcast_q_resp_interval "$interfaces" "$q_resp_interval" + [ -n "$last_mem_q_int" ] && config_sysfs_mcast_last_mem_q_int "$interfaces" "$last_mem_q_int" + [ -n "$fast_leave" ] && config_sysfs_mcast_fastleave "$interfaces" "$fast_leave" +} + config_mcproxy() { if [ "$igmp_p_enable" == "1" ]; then config_mcproxy_instance igmp "$igmp_p_version" + elif [ "$igmp_s_enable" == "1" ]; then + config_snooping igmp "$igmp_s_version" fi if [ "$mld_p_enable" == "1" ]; then config_mcproxy_instance mld "$mld_p_version" + elif [ "$mld_s_enable" == "1" ]; then + config_snooping mld "$mld_s_version" fi } @@ -253,11 +403,6 @@ setup_mcast_mode() { configure_mcast() { config_global_params "set_max_groups_and_sources" - # mcproxy reserves two multicast subscriptions for igmp router service groups - local mg=$(cat /proc/sys/net/ipv4/igmp_max_memberships) - mg=$((mg+2)) - echo $mg > /proc/sys/net/ipv4/igmp_max_memberships - read_mcast_snooping_params read_mcast_proxy_params config_mcproxy