+++ /dev/null
-#!/bin/sh
-
-. /lib/functions.sh
-. /lib/functions/network.sh
-
-switch_names=""
-
-warn() {
- echo "$@" >&2
-}
-
-clear_port_vlans() {
- local port=$1
- local self=$2
- local vlans=$(bridge vlan show dev "$port" | sed -ne 's#^[^ ]* \+\([0-9]\+\).*$#\1#p')
-
- local vlan
- for vlan in $vlans; do
- bridge vlan del vid "$vlan" dev "$port" $self
- done
-}
-
-lookup_switch() {
- local cfg=$1
- local swname
-
- config_get swname "$cfg" switch
-
- # Auto-determine switch if not specified ...
- if [ -z "$swname" ]; then
- case "$switch_names" in
- *\ *)
- warn "VLAN section '$cfg' does not specify a switch but multiple switches present, using first one"
- swname=${switch_names%% *}
- ;;
- *)
- swname=${switch_names}
- ;;
- esac
-
- # ... otherwise check if the referenced switch is declared
- else
- case " $switch_names " in
- *" $swname "*) : ;;
- *)
- warn "Switch '$swname' specified by VLAN section '$cfg' does not exist"
- return 1
- ;;
- esac
- fi
-
- export -n "switch=$swname"
-}
-
-validate_vid() {
- local vid=$1
-
- case "$vid" in
- [1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-4][0-9][0-9][0-9])
- if [ $vid -gt 4096 ]; then
- return 1
- fi
- ;;
- *)
- return 1
- ;;
- esac
-
- return 0
-}
-
-setup_switch() {
- local cfg=$1
- local cpu
-
- # Read configured CPU port from uci ...
- config_get cpu "$cfg" cpu_port
-
- # ... if unspecified, find first CPU port
- if [ -z "$cpu" ]; then
- local e
- for e in /sys/class/net/*/dsa; do
- if [ -d "$e" ]; then
- cpu=${e%/dsa}
- cpu=${cpu##*/}
- break
- fi
- done
- fi
-
- # Bail out if we cannot determine the CPU port
- if [ -z "$cpu" ]; then
- warn "Unable to determine CPU port for switch '$cfg'"
- return 1
- fi
-
- append switch_names "$cfg"
-
- # Prevent netifd from picking up our switch bridge just yet
- network_defer_device "$cfg"
-
- # Increase MTU of CPU port to 1508 to accomodate for VID + DSA tag
- ip link set "$cpu" mtu 1508
- ip link set "$cpu" up
-
- # (Re)create switch bridge device in case it is not yet set up
- local filtering=$(cat "/sys/class/net/$cfg/bridge/vlan_filtering" 2>/dev/null)
- if [ ${filtering:-0} != 1 ]; then
- ip link set "$cfg" down 2>/dev/null
- ip link delete dev "$cfg" 2>/dev/null
- ip link add name "$cfg" type bridge
- echo 1 > "/sys/class/net/$cfg/bridge/vlan_filtering"
- fi
-
- ip link set "$cfg" up
-
- # Unbridge DSA ports and flush any VLAN filters on them, they're added back later
- local port
- for port in /sys/class/net/*"/upper_${cfg}"; do
- if [ -e "$port" ]; then
- port=${port%/upper_*}
- port=${port##*/}
-
- ip link set "$port" nomaster
-
- # Unbridging the port should already clear VLANs, but be safe
- clear_port_vlans "$port"
- fi
- done
-
- # Clear any VLANs on the switch bridge, they're added back later
- clear_port_vlans "$cfg" self
-}
-
-setup_switch_vlan() {
- local cfg=$1
- local switch vlan ports
-
- config_get switch "$cfg" switch
- config_get vlan "$cfg" vlan
- config_get ports "$cfg" ports
-
- lookup_switch "$cfg" || return 1
- validate_vid "$vlan" || {
- warn "VLAN section '$cfg' specifies an invalid VLAN ID '$vlan'"
- return 1
- }
-
- # Setup ports
- local port tag pvid
- for port in $ports; do
- tag=${port#*.}
- port=${port%.*}
- pvid=
-
- if [ "$tag" != "$port" ] && [ "$tag" = t ]; then
- tag=tagged
- else
- tag=untagged
- fi
-
- # Add the port to the switch bridge and delete the default
- # VLAN 1 if it is not yet joined to the switch.
- if [ ! -e "/sys/class/net/$port/upper_$switch" ]; then
- ip link set dev "$port" up
- ip link set dev "$port" master "$switch"
-
- # Get rid of default VLAN 1
- bridge vlan del vid 1 dev "$port"
- fi
-
- # Promote the first untagged VLAN of this port to the PVID
- if [ "$tag" = untagged ] && ! bridge vlan show dev "$port" | grep -qi pvid; then
- pvid=pvid
- fi
-
- # Add VLAN filter entry for port
- bridge vlan add dev "$port" vid $vlan $pvid $tag
- done
-
- # Make the switch bridge itself handle the VLAN as well
- bridge vlan add dev "$switch" self vid $vlan tagged
-}
-
-setup_switch_port() {
- local cfg=$1
- local switch port pvid tag
-
- config_get port "$cfg" port
- config_get pvid "$cfg" pvid
-
- lookup_switch "$cfg" || return 1
- validate_vid "$pvid" || {
- warn "Port section '$cfg' specifies an invalid PVID '$pvid'"
- return 1
- }
-
- # Disallow setting the PVID of the switch bridge itself
- [ "$port" != "$switch" ] || {
- warn "Port section '$cfg' must not change PVID of the switch bridge"
- return 1
- }
-
- # Determine existing VLAN config
- local vlanspec=$(bridge vlan show dev "$port" vid "$pvid" 2>/dev/null | sed -ne2p)
- echo "$vlanspec" | grep -qi untagged && tag=untagged || tag=tagged
-
- bridge vlan add vid "$pvid" dev "$port" pvid $tag
-}
-
-apply_config() {
- config_load network
- config_foreach setup_switch dsa
-
- # If no switch is explicitely declared, synthesize switch0
- if [ -z "$switch_names" ] && ! setup_switch switch0; then
- warn "No DSA switches found"
- return 1
- fi
-
- config_foreach setup_switch_vlan dsa_vlan
- config_foreach setup_switch_port dsa_port
-
- # Ready switch bridge devices
- local switch
- for switch in $switch_names; do
- network_ready_device "$switch"
- done
-}
-
-show_switch() {
- local switch=$1
-
- printf "Switch: %s\n" "$switch"
- printf "VLAN/"
-
- local port ports
- for port in "/sys/class/net/$switch/lower_"*; do
- port=${port##*/lower_}
-
-
- printf " | %-5s" "$port"
- append ports "$port"
- done
-
- printf " |\nLink:"
-
- for port in $ports; do
- local carrier=$(cat "/sys/class/net/$port/carrier")
- local duplex=$(cat "/sys/class/net/$port/duplex")
- local speed=$(cat "/sys/class/net/$port/speed")
-
- if [ ${carrier:-0} -eq 0 ]; then
- printf " | %-5s" "down"
- else
- [ "$duplex" = "full" ] && duplex=F || duplex=H
- printf " | %4d%s" "$speed" "$duplex"
- fi
- done
-
- local vlans=$(bridge vlan show dev "$switch" | sed -ne 's#^[^ ]* \+\([0-9]\+\).*$#\1#p')
- local vlan
- for vlan in $vlans; do
- printf " |\n%4d " "$vlan"
-
- for port in $ports; do
- local pvid="" utag="" word
- for word in $(bridge vlan show dev "$port" vid "$vlan"); do
- case "$word" in
- PVID) pvid="*" ;;
- "$vlan") utag="t" ;;
- Untagged) utag="u" ;;
- esac
- done
-
- printf " | %-2s " "$utag$pvid"
- done
- done
-
- printf " |\n\n"
-}
-
-add_switch() {
- append switch_names "$1"
-}
-
-show_config() {
- config_load network
- config_foreach add_switch dsa
-
- local switch
- for switch in ${switch_names:-switch0}; do
- show_switch "$switch"
- done
-}
-
-
-case "$1" in
- show) show_config ;;
- apply) apply_config ;;
- *)
- echo "Usage: ${0##*/} show"
- echo " ${0##*/} apply"
- exit 1
- ;;
-esac