From cd4733efa9a221752f11d1780a44daead94bbf73 Mon Sep 17 00:00:00 2001 From: Rahul Date: Sun, 19 Apr 2020 15:21:29 +0530 Subject: [PATCH] mcastmngr: Add mcastmngr The mcastmngr read the uci file and configures the corresponding multicast daemon accordingly. It is for now doing this for broadcom's mcpd utility. Here are a few examples of what UCI config gets converted to what /var/mcpd.conf Snooping: config snooping 'msnoop_1' option enable '1' option proto 'igmp' option version '2' option robustness '2' option aggregation '0' option interface 'br-wan100' root@iopsys:~# cat /var/mcpd.conf igmp-default-version 2 igmp-robustness-value 2 igmp-max-groups 20 igmp-max-sources 10 igmp-max-members 20 igmp-snooping-enable 1 igmp-proxy-enable 0 igmp-query-interval 125 igmp-query-response-interval 100 igmp-last-member-query-interval 10 igmp-mcast-interfaces eth5.100 igmp-snooping-interfaces br-wan100 Proxy: config proxy 'mproxy_1' option enable '1' option proto 'igmp' option version '2' option robustness '2' option aggregation '0' option last_member_query_interval '10' option query_interval '120' option query_response_interval '100' list downstream_interface 'br-lan' list upstream_interface 'eth5.1' root@iopsys:~# cat /var/mcpd.conf igmp-default-version 2 igmp-robustness-value 2 igmp-max-groups 20 igmp-max-sources 10 igmp-max-members 20 igmp-snooping-enable 2 igmp-proxy-enable 1 igmp-fast-leave 1 igmp-query-interval 120 igmp-query-response-interval 100 igmp-last-member-query-interval 10 igmp-proxy-interfaces eth5.1 igmp-mcast-interfaces eth5.1 igmp-snooping-interfaces br-lan --- mcastmngr/Makefile | 38 +++ mcastmngr/files/etc/init.d/mcast | 35 +++ .../etc/uci-defaults/61-mcast_config_generate | 48 ++++ mcastmngr/files/lib/mcast/broadcom.sh | 238 ++++++++++++++++++ 4 files changed, 359 insertions(+) create mode 100644 mcastmngr/Makefile create mode 100755 mcastmngr/files/etc/init.d/mcast create mode 100644 mcastmngr/files/etc/uci-defaults/61-mcast_config_generate create mode 100755 mcastmngr/files/lib/mcast/broadcom.sh diff --git a/mcastmngr/Makefile b/mcastmngr/Makefile new file mode 100644 index 000000000..2ae0df96c --- /dev/null +++ b/mcastmngr/Makefile @@ -0,0 +1,38 @@ +# +# Copyright (C) 2013-2020 iopsys +# + +include $(TOPDIR)/rules.mk +include $(INCLUDE_DIR)/kernel.mk + +PKG_NAME:=mcastmngr +PKG_VERSION:=1.0.0 + +PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION) + +PKG_LICENSE:=GPL-2.0-only +PKG_LICENSE_FILES:=LICENSE + +include $(INCLUDE_DIR)/package.mk + +define Package/mcastmngr + CATEGORY:=Utilities + TITLE:=multicast packets manager daemon +endef + +define Package/mcastmngr/description + Configures IGMP and MLD snooping and proxy +endef + +#define Build/Prepare +# $(CP) -rf ./mcastmngr/* $(PKG_BUILD_DIR)/ +#endef + +define Build/Compile +endef + +define Package/mcastmngr/install + $(CP) ./files/* $(1)/ +endef + +$(eval $(call BuildPackage,mcastmngr)) diff --git a/mcastmngr/files/etc/init.d/mcast b/mcastmngr/files/etc/init.d/mcast new file mode 100755 index 000000000..749b775c5 --- /dev/null +++ b/mcastmngr/files/etc/init.d/mcast @@ -0,0 +1,35 @@ +#!/bin/sh /etc/rc.common + +START=98 +STOP=10 + +USE_PROCD=1 +NAME=mcast + +include /lib/network +include /lib/mcast + +service_triggers() { + procd_add_reload_trigger network $NAME +} + +start_service() { + if [ -f "/etc/config/mcast" ]; then + configure_mcast_igmp + fi + + procd_open_instance + procd_set_param command "$PROG_EXE" + procd_set_param respawn + procd_close_instance +} + +stop_service() { + service_stop $PROG_EXE +} + +reload_service() { + stop + start +} + diff --git a/mcastmngr/files/etc/uci-defaults/61-mcast_config_generate b/mcastmngr/files/etc/uci-defaults/61-mcast_config_generate new file mode 100644 index 000000000..5c667151d --- /dev/null +++ b/mcastmngr/files/etc/uci-defaults/61-mcast_config_generate @@ -0,0 +1,48 @@ +#!/bin/sh + +. /lib/functions.sh + +generate_igmp_global_params(){ + uci add mcast igmp + uci rename mcast.@igmp[-1]="igmp" + uci set mcast.@igmp[-1].max_groups="20" + uci set mcast.@igmp[-1].max_msf="10" + uci set mcast.@igmp[-1].max_membership="20" + uci set mcast.@igmp[-1].max_qrv="2" + uci set mcast.@igmp[-1].force_version="0" + uci commit mcast +} + +generate_mcast_config(){ + section="$1" + + config_get type "$section" "type" + if [ "$type" != "bridge" ]; then + return + fi + + uci add mcast snooping + uci rename mcast.@snooping[-1]="msnoop_1" + uci set mcast.@snooping[-1].enable="0" + uci set mcast.@snooping[-1].proto="igmp" + uci set mcast.@snooping[-1].version="2" + uci set mcast.@snooping[-1].robustness="2" + uci set mcast.@snooping[-1].aggregation="0" + uci set mcast.@snooping[-1].interface="br-$section" + uci commit mcast +} + +if [ -s "/etc/config/mcast" ]; then + if uci -q get mcast.@snooping[0] >/dev/null; then + # return if there is any valid content + exit + else + rm -f /etc/config/mcast + fi +fi +touch /etc/config/mcast + +generate_igmp_global_params + +config_load network +config_foreach generate_mcast_config interface diff --git a/mcastmngr/files/lib/mcast/broadcom.sh b/mcastmngr/files/lib/mcast/broadcom.sh new file mode 100755 index 000000000..ee69106b0 --- /dev/null +++ b/mcastmngr/files/lib/mcast/broadcom.sh @@ -0,0 +1,238 @@ +#!/bin/sh + +. /lib/functions.sh +. /usr/share/libubox/jshn.sh + +include /lib/network + +CONFFILE=/var/mcpd.conf +PROG_EXE=/usr/sbin/mcpd + +# Parameters available in snooping configuration +s_enable=0 +s_version=2 +s_robustness=2 +s_interface="" +s_exceptions="" + +# Parameters available in proxy configuration +p_enable=0 +p_version=2 +query_interval=125 +q_resp_interval=100 +last_mem_q_int=10 +max_groups=25 +max_msf=10 +max_members=25 +fast_leave=1 +p_robustness=2 +p_up_interfaces="" +p_down_interfaces="" +p_exceptions="" + +# Standard parameters need by BCM's multicast daemon +l_2_l_mcast=0 +bcm_mcast_p=1 +allow_brdevice=0 + +proxdevs="" +ethwan="$(db -q get hw.board.ethernetWanPort)" + +read_snooping() { + local config="$1" + config_get s_enable "$config" enable 0 + + if [ "$s_enable" == "0" ]; then + return + fi + + config_get s_version "$config" version 2 + config_get s_robustness "$config" robustness 2 + config_get s_interface "$config" interface + config_get s_exceptions "$config" filter +} + +read_proxy() { + local config="$1" + config_get p_enable "$config" enable 0 + + if [ "$p_enable" == "0" ]; then + return + fi + + config_get p_version "$config" version 2 + config_get query_interval "$config" query_interval + config_get q_resp_interval "$config" query_response_interval + config_get last_mem_q_int "$config" last_member_query_interval + config_get fast_leave "$config" fast_leave 1 + config_get p_robustness "$config" robustness 2 + config_get p_up_interfaces "$config" upstream_interface + config_get p_down_interfaces "$config" downstream_interface + config_get p_exceptions "$config" filter +} + +config_igmps_common_params() { + echo "igmp-default-version $1" >> $CONFFILE + echo "igmp-robustness-value $2" >> $CONFFILE + echo "igmp-max-groups $max_groups" >> $CONFFILE + echo "igmp-max-sources $max_msf" >> $CONFFILE + echo "igmp-max-members $max_members" >> $CONFFILE + echo "igmp-snooping-enable $3" >> $CONFFILE +} + +config_igmp_querier_params() { + echo "igmp-query-interval $query_interval" >> $CONFFILE + echo "igmp-query-response-interval $q_resp_interval" >> $CONFFILE + echo "igmp-last-member-query-interval $last_mem_q_int" >> $CONFFILE +} + +config_snooping_on_bridge() { + echo "igmp-snooping-interfaces $1" >> $CONFFILE + + for snpif in $1; do + case "$snpif" in + br-*) + # set snooping mode on the bridge + bcmmcastctl mode -i $snpif -p $bcm_mcast_p -m $2 + # set L2L snooping mode on the bridge + bcmmcastctl l2l -i $snpif -p $bcm_mcast_p -e $l_2_l_mcast # set L2L snooping mode on the bridge + ;; + esac + done +} + +handle_bridged_proxy_interface() { + bridged=1 + if [ $p_enable -eq 1 -a $allow_brdevice -eq 1 ] + then + proxdevs="$proxdevs $1" + echo "upstream-interface $1" >>$CONFFILE + else + json_load "$(devstatus $1)" + itr=1 + json_select bridge-members + while json_get_var dev $itr; do + case "$dev" in + *.*) + port="$(echo "$dev" | cut -d'.' -f 1)" + if [ $port == $ethwan ]; then + ifconfig $dev | grep RUNNING >/dev/null && proxdevs="$proxdevs $dev" && break + fi + ;; + esac + itr=$(($itr + 1)) + done + json_select .. + fi +} + +config_igmp_proxy_interface() { + local itr + + for proxif in $1; do + case "$proxif" in + br-*) + handle_bridged_proxy_interface $proxif + ;; + *) + proxdevs="$proxdevs $proxif" + ;; + esac + done + + if [ $p_enable -eq 1 ]; then + echo "igmp-proxy-interfaces $proxdevs" >> $CONFFILE + fi + + [ -n "$proxdevs" ] && echo "igmp-mcast-interfaces $proxdevs" >> $CONFFILE +} + +configure_mcpd_snooping() { + # Configure snooping related params + config_igmps_common_params $s_version $s_robustness $s_enable + echo "igmp-proxy-enable 0" >> $CONFFILE + + # BCM's mcpd always acts as queries, so configure some default values to prevent flooding + # of queries towards the clients or early leaves even in pure snooping with what will be + # default values for these params + config_igmp_querier_params + + config_igmp_proxy_interface $s_interface + + # set snooping mode on the bridge + config_snooping_on_bridge $s_interface $s_enable + + [ -n "$s_exceptions" ] && echo "igmp-mcast-snoop-exceptions $s_exceptions" >> $CONFFILE +} + +configure_mcpd_proxy() { + local s_mode=2 + + # Configure snooping related params + config_igmps_common_params $p_version $p_robustness $s_mode + echo "igmp-proxy-enable $p_enable" >> $CONFFILE + echo "igmp-fast-leave $fast_leave" >> $CONFFILE + + config_igmp_querier_params + + config_igmp_proxy_interface $p_up_interfaces + + config_snooping_on_bridge $p_down_interfaces $s_mode + + [ -n "$p_exceptions" ] && echo "igmp-mcast-snoop-exceptions $p_exceptions" >> $CONFFILE +} + +configure_mcpd() { + for br in $(brctl show | grep 'br-' | awk '{print$1}' | tr '\n' ' '); do + bcmmcastctl mode -i $br -p $bcm_mcast_p -m 0 # disable snooping on all bridges + bcmmcastctl l2l -i $br -p $bcm_mcast_p -e 0 # disable L2L snooping on all bridges + done + + # BCM's mcpd does not allow configuration of proxy and L2 snooping simultaneously, hence + # here, if proxy is to be configured then the configuration params of snooping are ignored. + if [ "$p_enable" == "1" ]; then + configure_mcpd_proxy + elif [ "$s_enable" == "1" ]; then + configure_mcpd_snooping + fi +} + +read_igmp_snooping_params() { + config_load mcast + config_foreach read_snooping snooping +} + +read_igmp_proxy_params() { + config_load mcast + config_foreach read_proxy proxy +} + +config_global_igmp_params() { + local qrv + local force_version + + config_load mcast + config_get max_groups igmp max_groups 25 + config_get max_msf igmp max_msf 10 + config_get max_members igmp max_membership 25 + config_get qrv igmp qrv 2 + config_get force_version igmp force_version 0 + + echo $max_members >/proc/sys/net/ipv4/igmp_max_memberships + echo $max_msf > /proc/sys/net/ipv4/igmp_max_msf + echo $qrv > /proc/sys/net/ipv4/igmp_qrv + echo $force_version > /proc/sys/net/ipv4/conf/all/force_igmp_version + +} + +configure_mcast_igmp() { + rm -f $CONFFILE + touch $CONFFILE + + config_global_igmp_params + + read_igmp_snooping_params + read_igmp_proxy_params + + configure_mcpd +}