Last active
October 22, 2023 12:58
-
-
Save jow-/ae0f51a27f20a14e4b9e8416956f60bb to your computer and use it in GitHub Desktop.
UCI configuration support for DSA VLAN filtering
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/sh | |
# This is /lib/network/dsaconfig.sh | |
. /lib/functions/network.sh | |
switch_names="" | |
clear_port_vlans() { | |
local port=$1 | |
local self=$2 | |
local word | |
for word in $(bridge vlan show dev "$port"); do | |
case "$word" in | |
[0-9]*) bridge vlan del vid "$word" dev "$port" $self ;; | |
esac | |
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 | |
*\ *) | |
logger -t dsaconfig "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 "*) : ;; | |
*) | |
logger -t dsaconfig "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 | |
[0-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_switchdev() { | |
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 | |
logger -t dsaconfig "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 | |
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" || { | |
logger -t dsaconfig "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/master" ]; 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" || { | |
logger -t dsaconfig "Port section '$cfg' specifies an invalid PVID '$pvid'" | |
return 1 | |
} | |
# Disallow setting the PVID of the switch bridge itself | |
[ "$port" != "$switch" ] || { | |
logger -t dsaconfig "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 | |
} | |
setup_switch() { | |
# Skip switch setup on network restart. The netifd process | |
# will be started afterwards and remove all interfaces again... | |
if [ "$initscript" = /etc/init.d/network ] && [ "$action" = restart ]; then | |
return 0 | |
fi | |
config_load network | |
config_foreach setup_switchdev switch | |
# If no switch is explicitely declared, synthesize switch0 | |
if [ -z "$switch_names" ] && ! setup_switchdev switch0; then | |
logger -t dsaconfig "No DSA switches found" | |
return 1 | |
fi | |
config_foreach setup_switch_vlan switch_vlan | |
config_foreach setup_switch_port switch_port | |
# Ready switch bridge devices | |
local switch | |
for switch in $switch_names; do | |
network_ready_device "$switch" | |
done | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/sh | |
# This is /etc/hotplug.d/iface/01-dsaconfig | |
if [ "$ACTION" = ifup ] && [ "$INTERFACE" = loopback ]; then | |
. /lib/network/dsaconfig.sh | |
setup_switch | |
fi |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# This is /etc/config/network | |
config interface 'loopback' | |
option ifname 'lo' | |
option proto 'static' | |
option ipaddr '127.0.0.1' | |
option netmask '255.0.0.0' | |
config globals 'globals' | |
option ula_prefix 'fd5d:ea15:562d::/48' | |
config device 'wan_wan_dev' | |
option name 'wan' | |
option macaddr '32:23:03:dc:13:a8' | |
config interface 'wwan' | |
option proto 'dhcp' | |
config switch switch0 | |
## Override CPU port. Normally it is auto-discovered. | |
#option cpu_port eth0 | |
config switch_vlan | |
## Specify the switch this vlan belongs to. | |
## If there is only one switch on the system, it may be omitted. | |
#option device switch0 | |
option vlan 1 | |
option ports 'lan1 lan2.t' | |
config switch_vlan | |
#option device switch0 | |
option vlan 2 | |
option ports 'wan' | |
config switch_vlan | |
#option device switch0 | |
option vlan 5 | |
option ports 'lan2.t lan3' | |
config switch_vlan | |
#option device switch0 | |
option vlan 8 | |
option ports 'lan2.t lan4' | |
config switch_vlan | |
#option device switch0 | |
option vlan 11 | |
option ports 'lan2.t lan4.t' | |
config switch_port | |
#option device switch0 | |
option port lan1 | |
## By default, the port PVID is set to the ID of the first | |
## VLAN the port is member of. It can be overriden here. | |
option pvid 8 | |
config interface lan | |
option ifname switch0.1 | |
option proto static | |
option ipaddr 192.168.1.1/24 | |
config interface wan | |
option ifname switch0.2 | |
option proto dhcp | |
config interface vlan5 | |
option ifname switch0.5 | |
option proto static | |
option ipaddr 10.255.5.1/24 | |
config interface vlan8 | |
option ifname switch0.8 | |
option proto static | |
option ipaddr 10.255.8.1/24 | |
config interface vlan11 | |
option ifname switch0.11 | |
option proto static | |
option ipaddr 10.255.11.1/24 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment