Commit b6d0ee4f authored by Martín Ferrari's avatar Martín Ferrari

Fixes to various breakages. bridge parameters now work, and are set by default...

Fixes to various breakages. bridge parameters now work, and are set by default to make the bridge work immediately (forward_delay = 0)
parent 385fbe6c
......@@ -23,7 +23,6 @@ class Interface(object):
return "NETNSif-%.4x%.3x" % (os.getpid(), n)
def __init__(self, index):
self._changeable_attributes = interface.changeable_attributes
self._idx = index
def __del__(self):
......@@ -52,27 +51,11 @@ class NSInterface(Interface):
# some black magic to automatically get/set interface attributes
def __getattr__(self, name):
try:
ca = object.__getattr__(self, '_changeable_attributes')
except:
ca = []
if (name not in ca):
raise AttributeError("'%s' object has no attribute '%s'" %
(self.__class__.__name__, name))
# I can use attributes now, as long as they are not in
# changeable_attributes
iface = self._slave.get_if_data(self.index)
return getattr(iface, name)
def __setattr__(self, name, value):
try:
ca = object.__getattr__(self, '_changeable_attributes')
except:
ca = []
if (name not in ca):
if name[0] != '_': # forbid anything that doesn't start with a _
raise AttributeError("'%s' object has no attribute '%s'" %
(self.__class__.__name__, name))
if name[0] == '_': # forbid anything that doesn't start with a _
super(Interface, self).__setattr__(name, value)
return
iface = interface(index = self.index)
......@@ -208,28 +191,12 @@ class ExternalInterface(Interface):
# some black magic to automatically get/set interface attributes
def __getattr__(self, name):
try:
ca = object.__getattr__(self, '_changeable_attributes')
except:
ca = []
if (name not in ca):
raise AttributeError("'%s' object has no attribute '%s'" %
(self.__class__.__name__, name))
# I can use attributes now, as long as they are not in
# changeable_attributes
iface = netns.iproute.get_if(self.index)
return getattr(iface, name)
def __setattr__(self, name, value):
try:
ca = object.__getattr__(self, '_changeable_attributes')
except:
ca = []
if (name not in ca):
if name[0] != '_': # forbid anything that doesn't start with a _
raise AttributeError("'%s' object has no attribute '%s'" %
(self.__class__.__name__, name))
super(Interface, self).__setattr__(name, value)
if name[0] == '_': # forbid anything that doesn't start with a _
super(ExternalInterface, self).__setattr__(name, value)
return
iface = interface(index = self.index)
setattr(iface, name, value)
......@@ -319,10 +286,24 @@ class Link(ExternalInterface):
iface = netns.iproute.create_bridge(self._gen_br_name())
super(Link, self).__init__(iface.index)
self._changeable_attributes = bridge.changeable_attributes
self._ports = set()
# register somewhere
# FIXME: is this correct/desirable/etc?
self.stp = False
self.forward_delay = 0
# FIXME: register somewhere
def __getattr__(self, name):
iface = netns.iproute.get_bridge(self.index)
return getattr(iface, name)
def __setattr__(self, name, value):
if name[0] == '_': # forbid anything that doesn't start with a _
super(ExternalInterface, self).__setattr__(name, value)
return
iface = bridge(index = self.index)
setattr(iface, name, value)
return netns.iproute.set_bridge(iface)
def __del__(self):
self.destroy()
......
......@@ -163,18 +163,18 @@ def get_addr_data():
def _parse_ip_addr(line):
match = re.search(r'^inet ([0-9.]+)/(\d+)(?: brd ([0-9.]+))?', line)
if match != None:
return ipv4address(
return netns.interface.ipv4address(
address = match.group(1),
prefix_len = match.group(2),
broadcast = match.group(3))
match = re.search(r'^inet6 ([0-9a-f:]+)/(\d+)', line)
match = re.search(r'^inet6 ([0-9a-f:]+)/(\d+)', line)
if match != None:
return ipv6address(
return netns.interface.ipv6address(
address = match.group(1),
prefix_len = match.group(2))
raise RuntimeError("Problems parsing ip command output")
raise RuntimeError("Problems parsing ip command output")
def add_addr(iface, address):
ifname = _get_if_name(iface)
......@@ -219,38 +219,49 @@ def set_addr(iface, addresses, recover = True):
raise
# Bridge handling
def get_br_data():
# brctl stinks too much; it is better to directly use sysfs, it is probably
# stable by now
def _sysfs_read_br(brname):
def readval(fname):
f = file(fname)
return f.readline().strip()
p = '/sys/class/net/%s/bridge/' % brname
p2 = '/sys/class/net/%s/brif/' % brname
try:
os.stat(p)
except:
return None
return dict(
stp = readval(p + 'stp_state'),
forward_delay = float(readval(p + 'forward_delay')) / 100,
hello_time = float(readval(p + 'hello_time')) / 100,
ageing_time = float(readval(p + 'ageing_time')) / 100,
max_age = float(readval(p + 'max_age')) / 100,
ports = os.listdir(p2))
def get_bridge_data():
# brctl stinks too much; it is better to directly use sysfs, it is probably
# stable by now
byidx = {}
bynam = {}
ports = {}
ifdata = get_if_data()
for i in ifdata[1]: # by name
p = '/sys/class/net/%s/bridge/' % i
p2 = '/sys/class/net/%s/brif/' % i
try:
os.stat(p)
except:
for iface in ifdata[0].values():
brdata = _sysfs_read_br(iface.name)
if brdata == None:
continue
params = dict(
stp = readval(p + 'stp_state'),
forward_delay = float(readval(p + 'forward_delay')) / 100,
hello_time = float(readval(p + 'hello_time')) / 100,
ageing_time = float(readval(p + 'ageing_time')) / 100,
max_age = float(readval(p + 'max_age')) / 100)
iface = ifdata[1][i]
bynam[i] = byidx[iface.index] = netns.interface.bridge.upgrade(
iface, **params)
ports[iface.index] = [ifdata[1][x].index for x in os.listdir(p2)]
ports[iface.index] = [ifdata[1][x].index for x in brdata['ports']]
del brdata['ports']
bynam[iface.name] = byidx[iface.index] = \
netns.interface.bridge.upgrade(iface, **brdata)
return byidx, bynam, ports
def get_bridge(br):
iface = get_if(br)
brdata = _sysfs_read_br(iface.name)
#ports = [ifdata[1][x].index for x in brdata['ports']]
del brdata['ports']
return netns.interface.bridge.upgrade(iface, **brdata)
def create_bridge(br):
if isinstance(br, str):
br = netns.interface.interface(name = br)
......@@ -286,7 +297,7 @@ def set_bridge(br, recover = True):
set_if(orig_br, recover = False) # rollback
raise
orig_br = get_br_data()[1][_get_if_name(br)]
orig_br = get_bridge(br)
diff = br - orig_br # Only set what's needed
cmds = []
......@@ -302,7 +313,8 @@ def set_bridge(br, recover = True):
cmds.append(('max_age', int(diff.max_age)))
set_if(diff)
do_cmds('/sys/class/net/%s/bridge/' % br.name, cmds, orig_br)
name = diff.name if diff.name != None else orig_br.name
do_cmds('/sys/class/net/%s/bridge/' % name, cmds, orig_br)
def add_bridge_port(br, iface):
ifname = _get_if_name(iface)
......
......@@ -59,9 +59,8 @@ class TestGlobal(unittest.TestCase):
i2.add_v4_address('10.0.0.2', 24)
null = file('/dev/null', 'wb')
# the bridge seems to be quite slow!
a1 = n1.Popen(['ping', '-qc1', '-w20', '10.0.0.2'], stdout = null)
a2 = n2.Popen(['ping', '-qc1', '-w20', '10.0.0.1'], stdout = null)
a1 = n1.Popen(['ping', '-qc1', '10.0.0.2'], stdout = null)
a2 = n2.Popen(['ping', '-qc1', '10.0.0.1'], stdout = null)
self.assertEquals(a1.wait(), 0)
self.assertEquals(a2.wait(), 0)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment