[Record] Multiple Spanning Tree Protocol Daemon Review === ###### tags: `record`, `protocol`, [mstpd](https://github.com/mstpd/mstpd), `stp`, `rstp`, `netwrok redundancy`, `IEEE 802.1D`, `IEEE 802.1W`, `IEEE 802.1S` [TOC] # Overview This is a third-party user space daemom. I am going to study it because we may migrate it to our system in the future. Therefore, let's take a look what are provided in mstpd. # Tree-structured directory + /sbin + bridge-stp [Check STP state before terminating MSTPd] + mstpd + mstpctl + /lib/mstpctl-utils + ifquery + ifupdown.sh [Disable STP processing on a specific port] + mstp_config_bridge [Fix new shellcheck warnings] + mstpctl_restart_config + mstpctl-utils-functions.sh + /opt/mips-buildroot-linux-uclibc_sdk-gcc7.3/etc/bridge-stp.conf [automatically start/stop mstpd as needed] --- ## 1. /sbin/bridge-stp ``` shell= #!/bin/sh # # Configuration is in /opt/mips-buildroot-linux-uclibc_sdk-gcc7.3/etc/bridge-stp.conf # # `/sbin/bridge-stp <bridge> <start|stop>` is called by the kernel when STP is # enabled/disabled on a bridge (via `brctl stp <bridge> <on|off>`). The kernel # enables user_stp mode if that command returns 0, or enables kernel_stp mode if # that command returns any other value. # # If called with the above arguments, this script determines whether MSTP should # be used for the specified bridge (based on the "MSTP_BRIDGES" configuration # value), starts/stops mstpd if necessary, and calls # `mstpctl <addbridge|delbridge> <bridge>` to add/remove the bridge from mstpd # (possibly in a background job after a delay; see the comments in the code # below). No further configuration is performed automatically by this script at # that time. Additional configuration is usually performed by # /lib/mstpctl-utils/ifupdown.sh (which calls `brctl stp <bridge> on` # to trigger this script to start mstpd if necessary). # # This script is not intended to be called with the above arguments directly # (not via the kernel). However, this script may be called directly as # `mstpctl_restart_config` or `/sbin/bridge-stp restart_config` to reconfigure # (using `/lib/mstpctl-utils/mstp_config_bridge <bridge>` or an alternative command specified using # a "config_cmd" configuration value) all existing bridges that are using mstpd, # or called as `mstp_restart` or `/sbin/bridge-stp restart` to restart mstpd and # then reconfigure all bridges that are using it. # # To avoid kernel deadlocks, this script (and any foreground processes it runs) # must not make any changes (using brctl, ifconfig, ip, /sys/..., etc) to the # bridge or any associated kernel network interfaces in any code paths that are # used when this script is called by the kernel. # Parse arguments. CalledAs="$(basename "$0")" if [ "$CalledAs" = 'mstpctl_restart_config' ]; then action='restart_config' elif [ $# -eq 1 ] && [ "$1" = 'restart_config' ]; then action='restart_config' elif [ "$CalledAs" = 'mstp_restart' ]; then action='restart' elif [ $# -eq 1 ] && [ "$1" = 'restart' ]; then action='restart' elif [ $# -eq 2 ] && [ "$2" = 'start' ]; then action='start' bridge="$1" elif [ $# -eq 2 ] && [ "$2" = 'stop' ]; then action='stop' bridge="$1" else echo "Usage: $0 <bridge> {start|stop}" >&2 echo " or: $0 {restart|restart_config}" >&2 exit 1 fi # Make sure this script is being run as root. if [ "$(id -u)" != '0' ]; then echo 'This script must be run as root' >&2 exit 1 fi # Ensure that we have a sane umask. umask 022 # Ensure that we have a sane PATH. PATH='/sbin:/usr/sbin:/bin:/usr/bin' export PATH # Define some relevant paths. mstpctl='/sbin/mstpctl' mstpd='/sbin/mstpd' config_cmd='/lib/mstpctl-utils/mstp_config_bridge' pid_file='@mstpdpidfile@' #/var/run/mstpd.pid net_dir='/sys/class/net' # Set default config values. # If 'y', mstpd will be automatically started/stopped as needed. MANAGE_MSTPD='y' # Arguments to pass to mstpd when it is started. MSTPD_ARGS='' # A space-separated list of bridges for which MSTP should be used in place of # the kernel's STP implementation. If empty, MSTP will be used for all bridges. MSTP_BRIDGES='' # Read the config. if [ -e '/opt/mips-buildroot-linux-uclibc_sdk-gcc7.3/etc/bridge-stp.conf' ]; then . '/opt/mips-buildroot-linux-uclibc_sdk-gcc7.3/etc/bridge-stp.conf' fi # Ensure that mstpctl and mstpd exist and are executable. if [ -z "$mstpctl" ] || [ ! -x "$mstpctl" ]; then echo "mstpctl binary does not exist or is not executable" >&2 exit 2 fi if [ "$MANAGE_MSTPD" = 'y' ]; then if [ -z "$mstpd" ] || [ ! -x "$mstpd" ]; then echo "mstpd binary does not exist or is not executable" >&2 exit 2 fi fi # Determine whether mstpd should manage STP for the specified bridge. # Returns 0 if mstpd should manage STP for the specified bridge, or 1 if mstpd # should not manage STP for the specified bridge. is_mstp_bridge() { if [ -z "$MSTP_BRIDGES" ]; then return 0 fi for b in $MSTP_BRIDGES; do if [ "$1" = "$b" ]; then return 0 fi done return 1 } case "$action" in start) # Make sure the specified bridge is valid. # /sys/class/net/$bridge/bridge if [ ! -d "$net_dir/$bridge/bridge" ]; then echo "'$bridge' is not a bridge" >&2 exit 1 fi # Determine whether the specified bridge should use MSTP. if ! is_mstp_bridge "$bridge"; then echo "Ignoring bridge '$bridge' that is not listed in \$MSTP_BRIDGES" exit 10 fi # Start mstpd if necessary. if ! pidof -c -s mstpd >/dev/null; then if [ "$MANAGE_MSTPD" != 'y' ]; then echo 'mstpd is not running' >&2 exit 3 fi echo 'mstpd is not running' echo 'Starting mstpd ...' "$mstpd" $MSTPD_ARGS || exit 3 # Due to kernel locks, mstpd will not respond to mstpctl until after # this script exits, so `mstpctl addbridge <bridge>` must be run as # an asynchronous background process. # On some systems (eg. OpenWrt), mstpctl will fail if it is called # too soon after mstpd is started, so the call must also be delayed. # # To avoid race conditions, any scripts that configure the bridge # immediately after calling `brctl stp <bridge> on` should # explicitly call `mstpctl addbridge <bridge>` themselves before # configuring the bridge. (It should not hurt to call # `mstpctl addbridge <bridge>` multiple times.) # # If `mstpctl addbridge` fails, we could turn STP off and back on # again to fall back to kernel STP mode. However, that could cause # an infinite loop if mstpd is being started successfully but is # then dying before or when mstpctl connects to it. To avoid that # possibility, we instead simply turn STP off if `mstpctl addbridge` # fails. ( sleep 1 ; "$mstpctl" addbridge "$bridge" || brctl stp "$bridge" off ) & exit 0 fi # Add bridge to mstpd. "$mstpctl" addbridge "$bridge" || exit 3 ;; stop) # Remove bridge from mstpd. "$mstpctl" delbridge "$bridge" || exit 3 # Exit if mstpd should not be stopped when it is no longer used. if [ "$MANAGE_MSTPD" != 'y' ]; then exit 0 fi # Exit if any other bridges are using mstpd. for bridge in $(ls "$net_dir"); do # Ignore interfaces that are not bridges. # /sys/class/net/$bridge/bridge/stp_state if [ ! -e "$net_dir/$bridge/bridge/stp_state" ]; then continue fi # Ignore bridges that should not use MSTP. if ! is_mstp_bridge "$bridge"; then continue fi # If bridge is in user_stp mode, then it is probably using MSTP. read State < "$net_dir/$bridge/bridge/stp_state" if [ "$State" = '2' ]; then exit 0 fi done # Kill mstpd, since no bridges are currently using it. kill $(pidof -c mstpd) ;; restart|restart_config) if [ "$action" = 'restart' ]; then # Kill mstpd. pids="$(pidof -c mstpd)" ; Err=$? if [ $Err -eq 0 ]; then echo 'Stopping mstpd ...' kill $pids fi # Start mstpd. echo 'Starting mstpd ...' "$mstpd" $MSTPD_ARGS || exit 3 fi # Reconfigure bridges. for bridge in $(ls "$net_dir"); do # Ignore interfaces that are not bridges. if [ ! -e "$net_dir/$bridge/bridge/stp_state" ]; then continue fi # Ignore bridges that should not use MSTP. if ! is_mstp_bridge "$bridge"; then continue fi # Skip bridges that have STP disabled. read State < "$net_dir/$bridge/bridge/stp_state" if [ "$State" = '0' ]; then echo echo "Skipping bridge '$bridge' that has STP disabled." echo "To configure this bridge to use MSTP, run:" echo "brctl stp '$bridge' on" continue fi # Skip bridges that are not in user_stp mode. if [ "$State" != '2' ]; then echo echo "Skipping bridge '$bridge' that is not in user_stp mode." echo "To reconfigure this bridge to use MSTP, run:" echo "brctl stp '$bridge' off ; brctl stp '$bridge' on" continue fi # Add bridge to mstpd and configure. echo "Adding/configuring bridge '$bridge' ..." "$mstpctl" addbridge "$bridge" || continue if [ -x "$config_cmd" ] || type "$config_cmd" 2>/dev/null >/dev/null ; then "$config_cmd" "$bridge" fi done echo echo 'Done' ;; esac ``` ## 2. /opt/mips-buildroot-linux-uclibc_sdk-gcc7.3/etc/bridge-stp.conf ``` shell= # If 'y' or commented out, mstpd will be automatically started/stopped as # needed. If 'n', mstpd will not be automatically started/stopped by the # bridge-stp script. #MANAGE_MSTPD='n' # Arguments to be passed to mstpd when it is started. # -v <0-4> : Adjust log level (default is 2) #MSTPD_ARGS='-v 2' # A space-separated list of bridges for which MSTP should be used in place of # the kernel's STP implementation. If empty or commented out, MSTP will be used # for all bridges. #MSTP_BRIDGES='br0 br1' ~ ~ ``` ## 3. /lib/mstpctl-utils/ifupdown.sh ``` shell= #!/bin/sh # ifup -av # un-parts /etc/network/if-pre-up.d # rip addr add 192.168.1.1/24 dev eth0 label eth0 # rip link set eth0 up # rip route add default via 192.168.1.254 dev eth0 # run-parts /etc/network/if-up.d # # This script should be symlinked into /etc/network/if-pre-up.d/ and # /etc/network/if-post-down.d/ on Debian/Ubuntu systems so that it will be run # by ifupdown when configuring network interfaces. # # This script is also used by `mstp_config_bridge`. # `mstp_config_bridge` is used by `/sbin/bridge-stp` when # `mstpctl_restart_config` or `mstp_restart` or # `/sbin/bridge-stp restart_config` or `/sbin/bridge-stp restart` are called to # automatically reconfigure bridges. # `mstp_config_bridge` may also be used and to configure bridges on systems # without ifupdown (on systems that are not based on Debian or Ubuntu). # # Have a look at /usr/share/doc/bridge-utils/README.Debian if you want # more info about the way in which bridges are set up on Debian. # # Author: Satish Ashok, <sashok@cumulusnetworks.com> if [ "$IF_MSTPCTL_STP" != 'on' ]; then exit 0 fi mstpctl='/sbin/mstpctl' if [ ! -x "$mstpctl" ]; then exit 0 fi brctl="$(command -v brctl)" if [ -z "$brctl" ] || [ ! -x "$brctl" ]; then echo "'brctl' binary does not exist or is not executable" >&2 exit 2 fi ip="$(command -v ip)" if [ -z "$ip" ] || [ ! -x "$ip" ]; then echo "'ip' binary does not exist or is not executable" >&2 exit 2 fi # shellcheck disable=SC1091 . '/lib/mstpctl-utils/mstpctl-utils-functions.sh' || exit 2 case "$IF_MSTPCTL_PORTS" in '') exit 0 ;; none) INTERFACES='' ;; *) INTERFACES="$IF_MSTPCTL_PORTS" ;; esac # Previous work (create the interface) if [ "$MODE" = 'start' ] && [ ! -d "/sys/class/net/$IFACE" ]; then "$brctl" addbr "$IFACE" || exit 2 # Previous work (stop the interface) elif [ "$MODE" = 'stop' ]; then "$ip" link set dev "$IFACE" down || exit 2 fi # shellcheck disable=SC2086 unset all_interfaces && # $INTERFACES should be word split into multiple arguments to # mstpctl_parse_ports. Therefore it should not be quoted here. mstpctl_parse_ports $INTERFACES | while read -r i; do for port in $i; do # We attach and configure each port of the bridge if [ "$MODE" = 'start' ] && [ ! -d "/sys/class/net/$IFACE/brif/$port" ]; then if [ -x /etc/network/if-pre-up.d/vlan ]; then IFACE="$port" /etc/network/if-pre-up.d/vlan fi if [ "$IF_BRIDGE_HW" ]; then "$ip" link set dev "$port" down; "$ip" link set dev "$port" address "$IF_BRIDGE_HW" fi if [ -f "/proc/sys/net/ipv6/conf/$port/disable_ipv6" ]; then echo 1 > "/proc/sys/net/ipv6/conf/$port/disable_ipv6" fi "$brctl" addif "$IFACE" "$port" && "$ip" link set dev "$port" up # We detach each port of the bridge elif [ "$MODE" = 'stop' ] && [ -d "/sys/class/net/$IFACE/brif/$port" ]; then "$ip" link set dev "$port" down && "$brctl" delif "$IFACE" "$port" && \ if [ -x /etc/network/if-post-down.d/vlan ]; then IFACE="$port" /etc/network/if-post-down.d/vlan fi if [ -f "/proc/sys/net/ipv6/conf/$port/disable_ipv6" ]; then echo 0 > "/proc/sys/net/ipv6/conf/$port/disable_ipv6" fi fi done done # We finish setting up the bridge if [ "$MODE" = 'start' ]; then # This triggers the kernel to run `/sbin/bridge-stp start $IFACE` "$brctl" stp "$IFACE" on # `mstpctl addbridge $IFACE` must be called before this script continues. # If mstpd is already running then /sbin/bridge-stp will call # `mstpctl addbridge $IFACE` before `brctl stp $IFACE on` returns. # If mstpd is not already running then /sbin/bridge-stp will start it and call # `mstpctl addbridge $IFACE` as a delayed background process, in which case it # may not run before `brctl stp $IFACE on` returns. # It should not hurt to call `mstpctl addbridge $IFACE` twice, so call it # again to ensure that it has been called before continuing. # See the code and comments in /sbin/bridge-stp for more details. "$mstpctl" addbridge "$IFACE" if [ "$IF_MSTPCTL_MAXAGE" ]; then "$mstpctl" setmaxage "$IFACE" "$IF_MSTPCTL_MAXAGE" fi if [ "$IF_MSTPCTL_FDELAY" ]; then "$mstpctl" setfdelay "$IFACE" "$IF_MSTPCTL_FDELAY" fi if [ "$IF_MSTPCTL_MAXHOPS" ]; then "$mstpctl" setmaxhops "$IFACE" "$IF_MSTPCTL_MAXHOPS" fi if [ "$IF_MSTPCTL_TXHOLDCOUNT" ]; then "$mstpctl" settxholdcount "$IFACE" "$IF_MSTPCTL_TXHOLDCOUNT" fi if [ "$IF_MSTPCTL_FORCEVERS" ]; then "$mstpctl" setforcevers "$IFACE" "$IF_MSTPCTL_FORCEVERS" fi if [ "$IF_MSTPCTL_TREEPRIO" ]; then "$mstpctl" settreeprio "$IFACE" 0 "$IF_MSTPCTL_TREEPRIO" fi if [ "$IF_MSTPCTL_PORTPATHCOST" ]; then portpathcosts="$(echo "$IF_MSTPCTL_PORTPATHCOST" | tr '\n' ' ' | tr -s ' ')" for portpathcost in $portpathcosts; do port="$(echo "$portpathcost" | cut -d '=' -f1)" pathcost="$(echo "$portpathcost" | cut -d '=' -f2)" if [ -n "$port" ] && [ -n "$pathcost" ]; then "$mstpctl" setportpathcost "$IFACE" "$port" "$pathcost" fi done fi if [ "$IF_MSTPCTL_PORTADMINEDGE" ]; then portadminedges="$(echo "$IF_MSTPCTL_PORTADMINEDGE" | tr '\n' ' ' | tr -s ' ')" for portadminedge in $portadminedges; do port="$(echo "$portadminedge" | cut -d '=' -f1)" adminedge="$(echo "$portadminedge" | cut -d '=' -f2)" if [ -n "$port" ] && [ -n "$adminedge" ]; then "$mstpctl" setportadminedge "$IFACE" "$port" "$adminedge" fi done fi if [ "$IF_MSTPCTL_PORTAUTOEDGE" ]; then portautoedges="$(echo "$IF_MSTPCTL_PORTAUTOEDGE" | tr '\n' ' ' | tr -s ' ')" for portautoedge in $portautoedges; do port="$(echo "$portautoedge" | cut -d '=' -f1)" autoedge="$(echo "$portautoedge" | cut -d '=' -f2)" if [ -n "$port" ] && [ -n "$autoedge" ]; then "$mstpctl" setportautoedge "$IFACE" "$port" "$autoedge" fi done fi if [ "$IF_MSTPCTL_PORTP2P" ]; then portp2ps="$(echo "$IF_MSTPCTL_PORTP2P" | tr '\n' ' ' | tr -s ' ')" for portp2p in $portp2ps; do port="$(echo "$portp2p" | cut -d '=' -f1)" p2p="$(echo "$portp2p" | cut -d '=' -f2)" if [ -n "$port" ] && [ -n "$p2p" ]; then "$mstpctl" setportp2p "$IFACE" "$port" "$p2p" fi done fi if [ "$IF_MSTPCTL_PORTRESTRROLE" ]; then portrestrroles="$(echo "$IF_MSTPCTL_PORTRESTRROLE" | tr '\n' ' ' | tr -s ' ')" for portrestrrole in $portrestrroles; do port="$(echo "$portrestrrole" | cut -d '=' -f1)" restrrole="$(echo "$portrestrrole" | cut -d '=' -f2)" if [ -n "$port" ] && [ -n "$restrrole" ]; then "$mstpctl" setportrestrrole "$IFACE" "$port" "$restrrole" fi done fi if [ "$IF_MSTPCTL_PORTRESTRTCN" ]; then portrestrtcns="$(echo "$IF_MSTPCTL_PORTRESTRTCN" | tr '\n' ' ' | tr -s ' ')" for portrestrtcn in $portrestrtcns; do port="$(echo "$portrestrtcn" | cut -d '=' -f1)" restrtcn="$(echo "$portrestrtcn" | cut -d '=' -f2)" if [ -n "$port" ] && [ -n "$restrtcn" ]; then "$mstpctl" setportrestrtcn "$IFACE" "$port" "$restrtcn" fi done fi if [ "$IF_MSTPCTL_BPDUGUARD" ]; then portbpduguards="$(echo "$IF_MSTPCTL_BPDUGUARD" | tr '\n' ' ' | tr -s ' ')" for portbpduguard in $portbpduguards; do port="$(echo "$portbpduguard" | cut -d '=' -f1)" bpduguard="$(echo "$portbpduguard" | cut -d '=' -f2)" if [ -n "$port" ] && [ -n "$bpduguard" ]; then "$mstpctl" setbpduguard "$IFACE" "$port" "$bpduguard" fi done fi if [ "$IF_MSTPCTL_PORTBPDUFILTER" ]; then portbpdufilters="$(echo "$IF_MSTPCTL_PORTBPDUFILTER" | tr '\n' ' ' | tr -s ' ')" for portbpdufilter in $portbpdufilters; do port="$(echo "$portbpdufilter" | cut -d '=' -f1)" bpdufilter="$(echo "$portbpdufilter" | cut -d '=' -f2)" if [ -n "$port" ] && [ -n "$bpdufilter" ]; then "$mstpctl" setportbpdufilter "$IFACE" "$port" "$bpdufilter" fi done fi if [ "$IF_MSTPCTL_TREEPORTPRIO" ]; then treeportprios="$(echo "$IF_MSTPCTL_TREEPORTPRIO" | tr '\n' ' ' | tr -s ' ')" for treeportprio in $treeportprios; do treeport="$(echo "$treeportprio" | cut -d '=' -f1)" prio="$(echo "$treeportprio" | cut -d '=' -f2)" if [ -n "$treeport" ] && [ -n "$prio" ]; then "$mstpctl" settreeportprio "$IFACE" "$treeport" 0 "$prio" fi done fi if [ "$IF_MSTPCTL_TREEPORTCOST" ]; then treeportcosts="$(echo "$IF_MSTPCTL_TREEPORTCOST" | tr '\n' ' ' | tr -s ' ')" for treeportcost in $treeportcosts; do treeport="$(echo "$treeportcost" | cut -d '=' -f1)" cost="$(echo "$treeportcost" | cut -d '=' -f2)" if [ -n "$treeport" ] && [ -n "$cost" ]; then "$mstpctl" settreeportcost "$IFACE" "$treeport" 0 "$cost" fi done fi if [ "$IF_MSTPCTL_HELLO" ]; then "$mstpctl" sethello "$IFACE" "$IF_MSTPCTL_HELLO" fi if [ "$IF_MSTPCTL_AGEING" ]; then "$mstpctl" setageing "$IFACE" "$IF_MSTPCTL_AGEING" fi if [ "$IF_MSTPCTL_PORTNETWORK" ]; then portnetworks="$(echo "$IF_MSTPCTL_PORTNETWORK" | tr '\n' ' ' | tr -s ' ')" for portnetwork in $portnetworks; do port="$(echo "$portnetwork" | cut -d '=' -f1)" network="$(echo "$portnetwork" | cut -d '=' -f2)" if [ -n "$port" ] && [ -n "$network" ]; then "$mstpctl" setportnetwork "$IFACE" "$port" "$network" fi done fi # We activate the bridge "$ip" link set dev "$IFACE" up # Calculate the maximum time to wait for STP to converge maxwait='' if [ -n "$IF_MSTPCTL_MAXWAIT" ] && [ "$IF_MSTPCTL_MAXWAIT" != 'auto' ]; then # if [ "$IF_MSTPCTL_MAXWAIT" is a number ]; then if [ "$IF_MSTPCTL_MAXWAIT" = "${IF_MSTPCTL_MAXWAIT%[!0-9]*}" ]; then maxwait="$IF_MSTPCTL_MAXWAIT" else echo "Ignoring invalid mstpctl_maxwait value '$maxwait'" >&2 fi fi if [ -z "$maxwait" ]; then root_forward_delay="$("$mstpctl" showbridge "$IFACE" forward-delay)" if [ -z "$root_forward_delay" ] || [ "$root_forward_delay" != "${root_forward_delay%[!0-9]*}" ]; then root_forward_delay=0 fi bridge_forward_delay="$("$mstpctl" showbridge "$IFACE" bridge-forward-delay)" if [ -z "$bridge_forward_delay" ] || [ "$root_forward_delay" != "${bridge_forward_delay%[!0-9]*}" ]; then bridge_forward_delay=0 fi if [ $root_forward_delay -gt $bridge_forward_delay ]; then maxwait="$root_forward_delay" else maxwait="$bridge_forward_delay" fi maxwait=$((maxwait*2+1)) fi # Wait for STP to converge if [ $maxwait -ne 0 ]; then echo echo "Waiting for STP on bridge '$IFACE' to converge (mstpctl_maxwait is $maxwait seconds)." # Use 0.1 delay if available sleep 0.1 2>/dev/null && maxwait=$((maxwait*10)) count=0 ; transitioned='' ; converged='' while [ -z "$converged" ] && [ $count -lt $maxwait ]; do sleep 0.1 2>/dev/null || sleep 1 count=$((count+1)) # Converged if all ports are either 'forwarding', 'blocking', or # 'disabled', except if all ports are 'disabled' and we have yet to see # any port transition to any other valid state. converged=true for i in $("$brctl" showstp "$IFACE" | sed -n 's/^.*port id.*state[ \t]*\(.*\)$/\1/p'); do if [ "$i" = 'listening' ] || [ "$i" = 'learning' ]; then transitioned=true converged='' break elif [ "$i" = 'forwarding' ] || [ "$i" = 'blocking' ]; then transitioned=true elif [ "$i" != 'disabled' ] || [ -z "$transitioned" ]; then converged='' fi done done if [ -z "$converged" ]; then echo "Timed out waiting for STP on bridge '$IFACE' to converge" >&2 fi fi # Finally we destroy the interface elif [ "$MODE" = 'stop' ]; then "$brctl" delbr "$IFACE" fi ``` ## 4. /lib/mstpctl-utils/mstpctl_restart_config = 1. /sbin/bridge-stp ## 5. /lib/mstpctl-utils/mstp_config_bridge ``` shell= #!/bin/sh # # This script uses `ifquery` to read the config in # /etc/network/interfaces and then runs the mstpctl-utils # `ifupdown.sh` script to configure the specified bridge in mstpd. # # This is used by the `/sbin/bridge-stp` script when called as # `mstpctl_restart_config` or `mstp_restart` or # `/sbin/bridge-stp restart_config` or `/sbin/bridge-stp restart` to # automatically reconfigure bridges. # # This may also be used to configure mstpd on systems without ifupdown (on # systems that are not based on Debian or Ubuntu). # Parse arguments. if [ $# -ne 1 ]; then echo "Usage: $0 <bridge>" >&2 exit 1 fi Bridge="$1" # Make sure this script is being run as root. if [ "$(id -u)" != '0' ]; then echo 'This script must be run as root' >&2 exit 1 fi # Ensure that we have a sane umask. umask 022 # Ensure that we have a sane PATH. PATH='/sbin:/usr/sbin:/bin:/usr/bin' export PATH # The mstp ifupdown.sh script will not work properly unless mstpctl, brctl, and # ip exist and are executable. mstpctl='/sbin/mstpctl' if [ ! -x "$mstpctl" ]; then echo "'mstpctl' binary does not exist or is not executable" >&2 exit 2 fi brctl="$(command -v brctl)" if [ -z "$brctl" ] || [ ! -x "$brctl" ]; then echo "'brctl' binary does not exist or is not executable" >&2 exit 2 fi ip="$(command -v ip)" if [ -z "$ip" ] || [ ! -x "$ip" ]; then echo "'ip' binary does not exist or is not executable" >&2 exit 2 fi # Find ifquery. ifquery="$(command -v ifquery 2>/dev/null)" if [ -z "$ifquery" ]; then # If the real ifquery is not installed, use our emulator. ifquery='/lib/mstpctl-utils/ifquery' fi if [ ! -x "$ifquery" ]; then echo "'ifquery' binary does not exist or is not executable" >&2 exit 2 fi # Run ifquery. # For example, # ifquery eth0 # Out= # address: 192.168.1.1 # netmask: 255.255.255.0 # gateway: 192.168.1.254 # broadcast: 192.168.1.255 Out="$("$ifquery" "$Bridge" 2>/dev/null)" ; Err=$? if [ $Err -ne 0 ]; then echo "Skipping configuration of bridge '$Bridge' that is not configured in" echo '/etc/network/interfaces' exit 0 fi # Read the interface config and generate the environment variables that are # typically generated by ifupdown. export IFACE="$Bridge" export LOGICAL="$Bridge" export ADDRFAM='inet' export METHOD='manual' export MODE='start' export PHASE='post-up' export VERBOSITY=0 eval "$( IFS= ; echo "$Out" | \ while read -r Line; do OptName="${Line%%: *}" # Strip everything after the first ': ' OptName="IF_$(echo "$OptName" | tr '[:lower:]' '[:upper:]')" # Uppercase OptVal="${Line#*: }" # Strip everything before the first ': ' echo "export $OptName=\"$OptVal\"" done )" # Call the mstpctl-utils ifupdown.sh script. '/lib/mstpctl-utils/ifupdown.sh' ``` ## 6. /lib/mstpctl-utils/ifquery ``` python= #!/usr/bin/python # Crudely emulate ifquery on systems that don't have it. import sys import glob def parse_config(interfaces_file, interface): f = open(interfaces_file) intf = '' for line in f: str = line.strip().split(' ') len_str = len(str) if 2 > len_str : continue if str[0].startswith('#') : continue # Check if the source <file> keyword is present and extract the file if str[0] == 'source' : for sfile in glob.glob(str[1]): parse_config(sfile, interface) if str[0] == 'iface' : intf = str[1] continue # Check if this is the relevant interface. if intf != interface : continue # Print configuration. print(str[0]+": "+" ".join(str[1:])) f.close() return parse_config('/etc/network/interfaces', sys.argv[1]) ``` ## 7. /lib/mstpctl-utils/mstpctl-utils-functions.sh ``` shell= #!/bin/sh mstpctl_parse_ports() { while [ x"${1+set}" = xset ] do # For compatibility: the 'all' option. case $1 in all) shift && set -- regex eth.\* em.\* 'p[0-9].*' noregex "$@" ;; esac # Primitive state machine... case $1-$(uname -s) in regex-Linux) all_interfaces=$(sed -n 's%^[\ ]*\([^:]*\):.*$%\1%p' < /proc/net/dev) shift ;; regex-*) echo "$0 needs to be ported for your $(uname -s) system. " \ "Trying to continue nevertheless." >&2 shift ;; noregex-*) unset all_interfaces shift ;; esac case ${all_interfaces+regex}-${1+set} in regex-set) # The following interface specification are to be parsed as regular # expressions against all interfaces the system provides. i=$(grep -E "^$1$" << EOAI $all_interfaces EOAI ) shift ;; *-set) # Literal interfaces. i=$1 shift ;; *) # No interface specification is following. i= ;; esac echo $i done } ``` # Reference https://github.com/mstpd/mstpd