Snippets

Doug Freed VIF Hotplug Script

Created by Doug Freed
#!/usr/bin/env python
import os, sys, re, json
from fcntl import flock, LOCK_EX, LOCK_UN
from sh import brctl, xenstore_read, xenstore_write, xenstore_ls, ip, ebtables
from netaddr import EUI, IPNetwork

def load_vifdata():
	vifdata = {}
	for i in xenstore_ls(os.environ['XENBUS_PATH']):
		match = re.match(r'^\s*([^\s]+) = "([^"]+)"\s*$', i)
		if match is not None:
			vifdata[match.group(1)] = match.group(2)
	return vifdata

def load_ipconf(domain):
	ipconf = {}
	with open('/vms/' + domain + '/ips.conf', 'r') as handle:
		ipconf = json.load(handle)
	return ipconf

def add_filter(chain):
	ebtables('-N', chain + '-filter', '-P', 'RETURN')
	ebtables('-A', chain + '-filter', '-j', 'RETURN')
	ebtables('-A', chain, '-j', chain + '-filter')

def add_ipv6(ipconf, vifdata, vifindex, chain, direction):
	if 'ipv6' in ipconf[vifindex]:
		mac = EUI(vifdata['mac'])
		linklocal = mac.ipv6_link_local()
		snma = IPNetwork('ff02::1:ff00:0/104')[int(mac) % 16777216]
		ebtables('-A', chain, '-p', 'IPv6', direction, ipconf[vifindex]['ipv6'], '-j', 'ACCEPT')
		ebtables('-A', chain, '-p', 'IPv6', direction, str(linklocal), '-j', 'ACCEPT')
		ebtables('-A', chain, '-p', 'IPv6', direction, str(snma), '-j', 'ACCEPT')

def add_ipv4(ipconf, vifindex, chain, direction):
	ebtables('-A', chain, '-p', 'IPv4', '--' + direction, ipconf[vifindex]['ip'], '-j', 'ACCEPT')
	ebtables('-A', chain, '-p', 'ARP', '--arp-' + direction, ipconf[vifindex]['ip'], '-j', 'ACCEPT')

def online():
	vif = os.environ['vif']
	fromvif = 'from-' + vif
	tovif = 'to-' + vif
	vifdata = load_vifdata()
	vifindex = int(vifdata['handle'])
	domid = vifdata['frontend-id']
	domain = str(xenstore_read('/local/domain/' + domid + '/name')).rstrip()
	ipconf = load_ipconf(domain)
	lockfile = open('/var/lock/ebtables', 'w')
	flock(lockfile, LOCK_EX)
	ebtables('-N', fromvif, '-P', 'DROP')
	ebtables('-A', fromvif, '-s', '!', vifdata['mac'], '-j', 'DROP')
	ebtables('-A', fromvif, '-p', 'IPv4', '--ip-src', '0.0.0.0', '--ip-dst', '255.255.255.255', '--ip-proto', 'UDP', '--ip-sport', '68', '--ip-dport', '67', '-j', 'ACCEPT')
	add_filter(fromvif)
	fromviflimit = fromvif + '-limit'
	ebtables('-N', fromviflimit, '-P', 'DROP')
	ebtables('-A', fromviflimit, '--limit', '10000/second', '--limit-burst', '5000', '-j', 'RETURN')
	ebtables('-A', fromviflimit, '--limit', '10000/second', '--limit-burst', '5000', '-j', 'RETURN')
	ebtables('-A', fromviflimit, '--limit', '10000/second', '--limit-burst', '5000', '-j', 'RETURN')
	ebtables('-A', fromviflimit, '-j', 'DROP')
	ebtables('-A', fromvif, '-j', fromvif + '-limit')
	add_ipv6(ipconf, vifdata, vifindex, fromvif, '--ip6-src')
	add_ipv4(ipconf, vifindex, fromvif, 'ip-src')
	ebtables('-A', fromvif, '--log', '--log-prefix', fromvif, '--log-ip', '--log-arp', '--log-ip6', '-j', 'DROP')
	ebtables('-A', 'INPUT', '-i', vif, '-j', fromvif)
	ebtables('-A', 'FORWARD', '-i', vif, '-j', fromvif)
	ebtables('-N', tovif, '-P', 'DROP')
	ebtables('-A', tovif, '-p', 'IPv4', '--ip-dst', '255.255.255.255', '--ip-proto', 'UDP', '--ip-sport', '67', '--ip-dport', '68', '-j', 'ACCEPT')
	add_filter(tovif)
	add_ipv6(ipconf, vifdata, vifindex, tovif, '--ip6-dst')
	add_ipv4(ipconf, vifindex, tovif, 'ip-dst')
	ebtables('-A', tovif, '--log', '--log-prefix', tovif, '--log-ip', '--log-arp', '--log-ip6', '-j', 'DROP')
	ebtables('-A', 'OUTPUT', '-o', vif, '-j', tovif)
	ebtables('-A', 'FORWARD', '-o', vif, '-j', tovif)
	flock(lockfile, LOCK_UN)
	lockfile.close()
	ip('link', 'set', vif, 'up')
	brctl('addif', ipconf[vifindex]['bridge'], vif)
	xenstore_write(os.environ['XENBUS_PATH'] + '/hotplug-status', 'connected')

def offline():
	vif = os.environ['vif']
	fromvif = 'from-' + vif
	tovif = 'to-' + vif
	vifdata = load_vifdata()
	vifindex = int(vifdata['handle'])
	domid = vifdata['frontend-id']
	domain = str(xenstore_read('/local/domain/' + domid + '/name')).rstrip()
	ipconf = load_ipconf(domain)
	brctl('delif', ipconf[vifindex]['bridge'], vif, _ok_code=[0,1])
	ip('link', 'set', vif, 'down', _ok_code=[0,255])
	lockfile = open('/var/lock/ebtables', 'w')
	flock(lockfile, LOCK_EX)
	ebtables('-D', 'INPUT', '-i', vif, '-j', fromvif)
	ebtables('-D', 'FORWARD', '-i', vif, '-j', fromvif)
	ebtables('-X', fromvif)
	ebtables('-X', fromvif + '-filter')
	ebtables('-X', fromvif + '-limit')
	ebtables('-D', 'OUTPUT', '-o', vif, '-j', tovif)
	ebtables('-D', 'FORWARD', '-o', vif, '-j', tovif)
	ebtables('-X', tovif)
	ebtables('-X', tovif + '-filter')
	flock(lockfile, LOCK_UN)
	lockfile.close()

if sys.argv[1] == 'online':
	online()
elif sys.argv[1] == 'offline':
	offline()
else:
	sys.exit(1)

Comments (0)

HTTPS SSH

You can clone a snippet to your computer for local editing. Learn more.