Created
March 23, 2014 05:37
-
-
Save kamilion/9719218 to your computer and use it in GitHub Desktop.
This file contains 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
#!/usr/bin/env python | |
# SLLabs.com vif hotplug script | |
# Copyright (C) 2013 SLLabs.com <[email protected]> | |
# This work is free. You can redistribute it and/or modify it under the | |
# terms of the Do What The Fuck You Want To Public License, Version 2, | |
# as published by Sam Hocevar. See http://www.wtfpl.net/ for more details. | |
# Written in 2013 for [email protected] by ircs://irc.ospnet.org/#sllabs residents | |
# "If you have an apple and I have an apple and we exchange these apples | |
# then you and I will still each have one apple. | |
# But if you have an idea and I have an idea and we exchange these ideas, | |
# then each of us will have two ideas." -- George Bernard Shaw | |
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/active/' + 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, '-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, '-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) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
What bridge or ebtables or iptables configuration do I need to make this script work? I was using it before, but lost my previous machine setup due to not backing everything up, and I didn't set it up in the first place. Now I can't get machines configured with it to talk to the bridge.