Basic DSA VLAN setup script

It took me a bit of reading up to set up VLANs on DSA, so I thought i'd share a little script I whipped up to make things easier. The scope is intentionally limited: it just handles the VLAN side of things. That being said, in my experience it's the most complex part of setting up e.g. a guest network.

What this script does:

  • Set up a default VLAN if undefined, and migrate your LAN interface to the new device (br-lan.1 or switch.1). The latter is crucial, since not doing so would render your device inaccessible over the LAN.
  • Define a custom, named VLAN through a series of prompts, with some explanations and examples with the right port notation. (The script enforces naming, but this is not mandatory for OpenWrt. It does help to keep the overview though.)
  • Define a 802.1q type VLAN if you just one single port in the VLAN (and if you do not need to bridge it to a wireless inteface e.g.).
  • Check whether ports defined in the new VLAN are used in the default (LAN) VLAN and alert the user if so, since the primary VLAN ID (PVID) needs to be set in that case.
  • Make a backup of /etc/config/network in /tmp/, in case you need to restore things (gone with a reboot!).

What this script does not do:

  • Set up an interface to use the extra VLAN(s). This is rather trivial (e.g. you configure an interface br-lan.10 if you defined a VLAN on the br-lan device with VID 10).
  • Save you from yourself if you do not bother reading the warnings or setting a PVID.

With that in mind: enjoy.

#!/bin/sh

# Script to set VLANs and migrate LAN interface to default VLAN if unset

SCRIPTVERSION="2022-10-08"

# Variables. br-lan and switch are mutually exclusive.
[ -d /sys/class/net/br-lan ] && _BRIDGEDEV="br-lan"
[ -d /sys/class/net/switch ] && _BRIDGEDEV="switch"
_PORTLIST="$(uci get network.@device[0].ports)"				# Populate interface list

# Backup config.
cp /etc/config/network /tmp/network.backup

# Create LAN VLAN (VID 1) if not present, and include all ports by default.
if [ "$(uci get network.lan_vlan)" ]
then
	echo -e ":: LAN VLAN already defined. Skipping.\n"
else
	uci set network.lan_vlan='bridge-vlan'
	uci set network.lan_vlan.device="$_BRIDGEDEV"
	uci set network.lan_vlan.vlan='1'
	for i in $_PORTLIST ; do uci add_list network.lan_vlan.ports=$i ; done
fi

# Migrate LAN interface.
uci set network.lan.device="$_BRIDGEDEV.1"
uci commit network

# Custom user defined VLANs
echo -e ":: Enter the \e[34mVLAN name\e[0m, e.g. 'guest'.\n"
read _VLAN_NAME

echo -e "\n:: Provide a space separated \e[34mlist of port(s)\e[0m to include in your VLAN.\n   Use the names as listed in the default VLAN. Notation:\n
     lan1        untagged
     lan1:u*     untagged, primary VLAN ID ('PVID'). \e[31mMandatory\e[0m if same port is used in another VLAN!
     lan1:t      tagged

   E.g.: lan0:u* lan2 lan3

   Available ports: $_PORTLIST. Hit Enter to process the list after specifying the ports.

   \e[31mDo not forget to modify the default VLAN and specify the PVID for ports you are using in multiple VLANs.\e[0m\n"

read _VLAN_PORTLIST


# Enquire about desired VID and check whether it's in use already.
echo -e "\n:: Enter the \e[34mVLAN ID\e[0m. 1 is reserved for the default VLAN. Use e.g. 10 for a\n   guest VLAN, 20 for an additional VLAN, 30, 40, ... for subsequent VLANs etc.
   Make sure not to use a VLAN that might be in use already (e.g. if your ISP\n   requires a specific tagged VLAN on the WAN interface).\n"
read _VLAN_ID

if grep "$_VLAN_ID" /etc/config/network | egrep -q "option vid|option vlan"
then
	echo -e "\n ::\e[31mWARNING:\e[0m VLAN ID is already in use. Please specify another VLAN ID."
	read _VLAN_ID
fi


# Check whether a 802.1q VLAN is sufficient
if ! echo "$_VLAN_PORTLIST" | grep -q ' '
then
	if echo "$_VLAN_PORTLIST" | grep -q ':t'
	then 
		echo -e "\n:: You specified just a single tagged port. Will you be bridging this to a wireless interface? [Y/n]"
		read _VLAN_BRIDGE_WLAN
		_VLAN_BRIDGE_WLAN=${_VLAN_BRIDGE_WLAN:-Y}

		if [ "$_VLAN_BRIDGE_WLAN" = "n" ]
		then
			echo -e "\n:: Setting up 802.1q VLAN..."
			uci add network device > /dev/null
			uci set network.@device[-1].type='8021q'
			uci set network.@device[-1].ifname="${_VLAN_PORTLIST/:t/}"	# Strip tag notation
			uci set network.@device[-1].vid="$_VLAN_ID"
			uci set network.@device[-1].name="$_VLAN_NAME"
			touch /tmp/_dsa_8021q_vlan
		fi
	fi
fi

# Bridge VLAN
if [ ! -f /tmp/_dsa_8021q_vlan ]
then
	echo -e "\n:: Adding new $_VLAN_NAME bridge VLAN...\n"
	uci set network."$_VLAN_NAME"_vlan='bridge-vlan'
	uci set network."$_VLAN_NAME"_vlan.device="$_BRIDGEDEV"
	uci set network."$_VLAN_NAME"_vlan.vlan="$_VLAN_ID"
	for i in $_VLAN_PORTLIST ; do uci add_list network."$_VLAN_NAME"_vlan.ports=$i ; done
fi

# Check if ports are already in use in another VLAN and prompt if so, with PVID hint
for i in $_VLAN_PORTLIST ; do uci get network.lan_vlan.ports|grep -q ${i%%:*} && echo -e ":: \e[31mWARNING:\e[0m port ${i%%:*} is already in use in LAN VLAN! Please set the PVID." ; done

# Save and quit.
uci commit network
[ -f /tmp/_dsa_8021q_vlan ] && rm /tmp/_dsa_8021q_vlan
echo -e "\n:: Done."
8 Likes

Script has been updated to point out a single network interface should be configured directly in /etc/config/network and does not require you to set up a bridge VLAN. Also checks now if a VLAN ID is already in use and prompts you to define another one.

3 Likes

I have updated the script so it wil set up single port VLANs as wel, as a brige VLAN when needed (e.g. when you need to bridge a wireless interface to it) or a standalone 802.1q VLAN.

4 Likes