Xen with Bonding + VLAN Tagging
Introduction
As powerful and flexible as it may be, Xen’s network configuration often feels like an obstacle course as soon as you stray a bit from the beaten path.
Recently, I had to set up a Xen-based solution in a somewhat special network topology. Each server where Xen was deployed had 2 ethernet adapters, each with 2 gigabit ethernet interfaces. The goal was to maximize the use of the different ethernet interfaces while providing both fault tolerance and load balancing. To make things even more interesting, the network was segmented into VLANs, each VLAN segmenting the network by function (DMZ, LAN, ADMIN, etc.).
The different points that interest us here at the system administration level are:
- Channel Bonding
- VLAN Tagging
- Bridging
After some research on the web, you quickly realize that you will need to create your own network script for Xen. Shame on me, I didn’t really feel capable of doing that (too complicated/I don’t know python/it’s still too obscure for me). So I decided to move the problem from Xen to the host operating system, with most of the configuration happening at the OS level (in this case a Debian Etch), with Xen simply using what already exists.
The final goal is as follows:
Don’t worry about bond0, we’re only interested in bond1, eth1, and eth2 here.
Channel Bonding Configuration
First, we need to configure and load the bonding module. In Debian, go to /etc/modprobe.d/arch/i386
(even if you’re on an x86_64 architecture):
# Channel bonding configuration
#
# mode=802.3ad
# Use 802.3ad for link aggregation (require LACP compatible switch and
# additionnal switch configurations)
# miimon= 100
# MII monitoring frequency in ms
# use_carrier=0
# Use an alternative and deprecated method (ethtool ioctls) to monitor
# link status. Works better with this mode (maybe network drivers issues)
# lacp_rate=fast
# Transmit LACPDU packet each second instead of each 30 seconds
# max_bonds=2
# Indicate that there's 2 bonding device (bond0 and bond1) even if
# only bond0 is explicitely configured. With max_bonds options there's
# no way to configure separately each bond device.
# NOTE : -o bond# (better) seems not to be supported
alias bond0 bonding
options bond0 mode=802.3ad miimon=100 use_carrier=0 lacp_rate=fast max_bonds=2
Yes, I know I’m only specifying the configuration for bond0 here. However, by changing the value of max_bonds, you configure the number of interfaces you want. Despite what is specified in the bonding.txt.gz file of the Linux documentation (aptitude install linux-doc), I was not able to have a per-interface configuration. The kernel is the default one provided with Debian Etch.
Configuration of the bond1 Interface
Next, we need to edit the /etc/network/interfaces
file as follows:
iface bond1 inet manual
pre-up /sbin/ifconfig eth0 up
pre-up /sbin/ifconfig eth3 up
pre-up /sbin/ifconfig bond1 up
pre-up /sbin/ifenslave bond1 eth0
pre-up /sbin/ifenslave bond1 eth3
post-down /sbin/ifenslave -d bond1 eth3
post-down /sbin/ifenslave -d bond1 eth0
post-down /sbin/ifconfig eth0 down
post-down /sbin/ifconfig eth3 down
post-down /sbin/ifconfig bond1 down
Nothing too complicated here. Note a few things though:
- You need to install the ifenslave-2.6 package.
- I use the pre-up directive instead of up which is more commonly found. I had some weird behaviors with the latter (like interfaces not coming up).
- No IP configuration is specified. We’re staying at layer 2 of the OSI model.
At this point, you can start playing with bringing your bond1 interface up and down:
ifup bond1
ifdown bond1
VLAN
On top of this bond1 interface, we’ll now set up one interface per VLAN. First, you need to install the vlan package:
# vlan 3 = LAN
iface vlan3 inet manual
vlan-raw-device bond1
pre-up /sbin/ifup bond1
pre-up /sbin/ifconfig bond1 up
pre-up /sbin/modprobe 8021q
# vlan 2 = DMZ
iface vlan2 inet manual
vlan-raw-device bond1
pre-up /sbin/ifup bond1
pre-up /sbin/ifconfig bond1 up
pre-up /sbin/modprobe 8021q
Note again the use of the pre-up directive (it’s really the only one that worked for me) and the loading of the module handling VLAN (802.1Q standard).
Creating Bridges for DomUs
First, it’s important to understand that a software bridge under Linux works exactly the same way as a physical switch. In everyday life (of an IT person), what we’re doing here is equivalent to:
- Taking a switch
- Plugging network cables into it
- Obviously, each cable is connected to a computer
In my particular case, I need to create 2 bridges: one over the DMZ VLAN, the other over the LAN VLAN:
# xen bridge for hosts which needs LAN network
auto xenbrlan
iface xenbrlan inet dhcp
pre-up /sbin/ifup vlan3
pre-up /sbin/ifconfig vlan3 up
pre-up /usr/sbin/brctl addbr xenbrlan
pre-up /usr/sbin/brctl addif xenbrlan vlan3
pre-up /usr/sbin/brctl setfd xenbrlan 0
post-down /usr/sbin/brctl delif xenbrlan vlan3
post-down /usr/sbin/brctl delbr xenbrlan
post-down /sbin/ifdown vlan3
# xen bridge for hosts which needs DMZ network
auto xenbrdmz
iface xenbrdmz inet manual
pre-up /sbin/ifup vlan2
pre-up /sbin/ifconfig vlan2 up
pre-up /usr/sbin/brctl addbr xenbrdmz
pre-up /usr/sbin/brctl addif xenbrdmz vlan2
pre-up /usr/sbin/brctl setfd xenbrdmz 0
post-down /usr/sbin/brctl delif xenbrdmz vlan2
post-down /usr/sbin/brctl delbr xenbrdmz
post-down /sbin/ifdown vlan2
Note that like any respectable switch, our xenbrlan and xenbrdmz bridges don’t need an IP address (it’s a layer 2 device) to function. At this point, you can play with bringing your bridges up and down on the fly:
ifup xenbrlan xenbrdmz
ifdown xenbrlan xenbrdmz
Configuring Xen
The only small difficulty here is to create a little script that will allow the use of 2 different bridges. To do this, we’ll create a file /etc/xen/script/my-network-bridge
as follows:
#!/bin/sh
dir=$(dirname "$0")
"$dir/network-bridge" "$@" vifnum=0 bridge=xenbrlan
"$dir/network-bridge" "$@" vifnum=1 bridge=xenbrdmz
You’ll also need to tell Xen to use our script instead of the default one. To do this, go to the xend-config.sxp
file and replace (network-script network-bridge)
with (network-script 'my-network-bridge')
.
All that’s left is to specify in the configuration of each DomU the bridge you want to use:
vif = ['mac=02:00:00:00:00:01, bridge=xenbrdmz']
You can now start your VMs :-)
Resources
Last updated 27 Jan 2008, 11:48 +0200.