Linux Vlan

From Leo's Notes
Last edited on 1 September 2019, at 06:21.

If an interface is trunked, you can 'untag' the traffic like so:

# ip link add link enp3s0f1 name enp3s0f1.1012 type vlan id 1012

You can then assign an IP address to the interface enp3s0f1.1012.


Linux Switch

You can make your linux box act like a smart switch by using this script:

#!/bin/bash

declare -a Ports # List of ports
declare -A Config # Vlan ID for each port
declare -A Vlans # key=>value | vlanid=>vlan name
Uplink="p4p2"

DryRun=0

function Main() {
	setup_requirements

	add_vlan 911 "BuildNet"
	add_vlan 912 "BuildNet2"
	add_vlan 1010 "DeptNFS"
	add_vlan 7 "WildWest"
	add_vlan 1012 "AdminNet"
	add_vlan 915 "OS-Int"
	# add_vlan 916 "OS-VM"

	# Interfaces are sorted. Run `get_network_interfaces` to see the mapping.
	# eth2 p1p1 p1p2 p4p2
	config_port 0 911
	config_port 1 911
	config_port 2 7
	# config_port 3 trunked

	setup_network
	show_ports

	configure_port_vlan
	show_config

	# Give this machine an IP address through a bridge.
	# ifconfig br1010 172.17.10.9 netmask 255.255.255.0
	# route add default gw 172.17.10.1

	# Statically configure the network for this machine on the trunked bridge
	# p4p2 (the uplink) at 1010 is our interface.
	ifconfig br1010 172.17.10.9 netmask 255.255.255.0
	route add default gw 172.17.10.1

	# dhclient br1010
}

function setup_requirements() {
	echo 1 >  /proc/sys/net/ipv4/ip_forward
	modprobe 8021q
}

function get_network_interfaces() {
	# Get all interfaces except bridges and vlan interfaces and loopback
	/sbin/ip a \
	| /bin/grep -E '^[0-9]+' \
	| cut -f2 -d' ' \
	| grep -vE '(br|@)' \
	| tr : ' ' \
	| grep -v lo \
	| sort
}

function config_port() {
	Config[$1]="$2"
}

function add_vlan() {
	Vlans[$1]="$2"
}

function die() {
	echo $@
	exit
}

function show_ports() {
	echo "Network Interfaces Found:"
	for i in "${!Ports[@]}" ; do
		echo "$i: ${Ports[$i]}"
	done
}

function show_config() {
	echo "Vlan Configuration:"
	for i in "${!Ports[@]}" ; do
		Vlan=${Config[$i]}
		echo "$i: ${Ports[$i]} --> VLAN $Vlan (${Vlans[$Vlan]})"
	done
}

function teardown_network() {
	ifconfig $Uplink down
	for Port in "${Ports[@]}" ; do
		ifconfig $Port down
	done
	
	cat /proc/net/vlan/config | tail -n+3 | cut -f1 -d' '|tr . ' ' | while read line ; do
		Port=`echo $line | cut -f1 -d' '`
		Vlan=`echo $line | cut -f2 -d' '`

		brctl delif br$Vlan $Uplink.Vlan
		brctl delbr br$Vlan

		vconfig rem $Uplink.$Vlan
	done
}

function setup_network() {
	Interfaces=$(get_network_interfaces)
	echo $Interfaces | grep $Uplink > /dev/null || die "Could not find $Uplink interface."
	# Add each port to the ports list excluding the uplink
	for Port in $Interfaces ; do
		if [[ "$Port" != "$Uplink" ]] ; then
			Ports+=($Port)
		fi
	done

	# Set up vlans on the uplink port
	for i in "${!Vlans[@]}" ; do
		Vlan=$i
		VlanName=${Vlans[$i]}

		# Check to see if it's already configured. Skip if it is.
		grep "\b$Vlan\b" /proc/net/vlan/config > /dev/null && continue

		# Add vlan to port. This creates $Uplink.$Vlan
		vconfig add $Uplink $Vlan

		# Create bridge for each vlan
		brctl addbr br$Vlan
		brctl addif br$Vlan $Uplink.$Vlan
		
		# Start the bridge and vlan uplink
		ifconfig br$Vlan up
		ifconfig $Uplink.$Vlan up
	done
}

function configure_port_vlan() {
	# Ensure everything is down.
	for i in "${!Ports[@]}" ; do
		Vlan=${Config[$i]}
		Port=${Ports[$i]}

		# Add the port to the vlan bridge
		brctl addif br$Vlan $Port
		ifconfig $Port up
	done

	# Start things up
	for Port in "${Ports[@]}" ; do
		ifconfig $Port up
	done
}

function ifconfig() {
	echo ifconfig $@
	if [ $DryRun -eq 0 ] ; then
		/sbin/ifconfig $@
	fi
}
function brctl() {
	echo brctl $@
	if [ $DryRun -eq 0 ] ; then
		/sbin/brctl $@
	fi
}
function vconfig() {
	echo vconfig $@
	if [ $DryRun -eq 0 ] ; then
		/sbin/vconfig $@
	fi
}
function dhclient() {
	echo dhclient $@
	if [ $DryRun -eq 0 ] ; then
		/sbin/dhclient $@
	fi
}

Main $@