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): ...@@ -23,7 +23,6 @@ class Interface(object):
return "NETNSif-%.4x%.3x" % (os.getpid(), n) return "NETNSif-%.4x%.3x" % (os.getpid(), n)
def __init__(self, index): def __init__(self, index):
self._changeable_attributes = interface.changeable_attributes
self._idx = index self._idx = index
def __del__(self): def __del__(self):
...@@ -52,27 +51,11 @@ class NSInterface(Interface): ...@@ -52,27 +51,11 @@ class NSInterface(Interface):
# some black magic to automatically get/set interface attributes # some black magic to automatically get/set interface attributes
def __getattr__(self, name): 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) iface = self._slave.get_if_data(self.index)
return getattr(iface, name) return getattr(iface, name)
def __setattr__(self, name, value): def __setattr__(self, name, value):
try: if name[0] == '_': # forbid anything that doesn't start with a _
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) super(Interface, self).__setattr__(name, value)
return return
iface = interface(index = self.index) iface = interface(index = self.index)
...@@ -208,28 +191,12 @@ class ExternalInterface(Interface): ...@@ -208,28 +191,12 @@ class ExternalInterface(Interface):
# some black magic to automatically get/set interface attributes # some black magic to automatically get/set interface attributes
def __getattr__(self, name): 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) iface = netns.iproute.get_if(self.index)
return getattr(iface, name) return getattr(iface, name)
def __setattr__(self, name, value): def __setattr__(self, name, value):
try: if name[0] == '_': # forbid anything that doesn't start with a _
ca = object.__getattr__(self, '_changeable_attributes') super(ExternalInterface, self).__setattr__(name, value)
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)
return return
iface = interface(index = self.index) iface = interface(index = self.index)
setattr(iface, name, value) setattr(iface, name, value)
...@@ -319,10 +286,24 @@ class Link(ExternalInterface): ...@@ -319,10 +286,24 @@ class Link(ExternalInterface):
iface = netns.iproute.create_bridge(self._gen_br_name()) iface = netns.iproute.create_bridge(self._gen_br_name())
super(Link, self).__init__(iface.index) super(Link, self).__init__(iface.index)
self._changeable_attributes = bridge.changeable_attributes
self._ports = set() 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): def __del__(self):
self.destroy() self.destroy()
......
...@@ -163,14 +163,14 @@ def get_addr_data(): ...@@ -163,14 +163,14 @@ def get_addr_data():
def _parse_ip_addr(line): def _parse_ip_addr(line):
match = re.search(r'^inet ([0-9.]+)/(\d+)(?: brd ([0-9.]+))?', line) match = re.search(r'^inet ([0-9.]+)/(\d+)(?: brd ([0-9.]+))?', line)
if match != None: if match != None:
return ipv4address( return netns.interface.ipv4address(
address = match.group(1), address = match.group(1),
prefix_len = match.group(2), prefix_len = match.group(2),
broadcast = match.group(3)) 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: if match != None:
return ipv6address( return netns.interface.ipv6address(
address = match.group(1), address = match.group(1),
prefix_len = match.group(2)) prefix_len = match.group(2))
...@@ -219,38 +219,49 @@ def set_addr(iface, addresses, recover = True): ...@@ -219,38 +219,49 @@ def set_addr(iface, addresses, recover = True):
raise raise
# Bridge handling # Bridge handling
def _sysfs_read_br(brname):
def get_br_data():
# brctl stinks too much; it is better to directly use sysfs, it is probably
# stable by now
def readval(fname): def readval(fname):
f = file(fname) f = file(fname)
return f.readline().strip() return f.readline().strip()
byidx = {} p = '/sys/class/net/%s/bridge/' % brname
bynam = {} p2 = '/sys/class/net/%s/brif/' % brname
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: try:
os.stat(p) os.stat(p)
except: except:
continue return None
params = dict( return dict(
stp = readval(p + 'stp_state'), stp = readval(p + 'stp_state'),
forward_delay = float(readval(p + 'forward_delay')) / 100, forward_delay = float(readval(p + 'forward_delay')) / 100,
hello_time = float(readval(p + 'hello_time')) / 100, hello_time = float(readval(p + 'hello_time')) / 100,
ageing_time = float(readval(p + 'ageing_time')) / 100, ageing_time = float(readval(p + 'ageing_time')) / 100,
max_age = float(readval(p + 'max_age')) / 100) max_age = float(readval(p + 'max_age')) / 100,
iface = ifdata[1][i] ports = os.listdir(p2))
bynam[i] = byidx[iface.index] = netns.interface.bridge.upgrade(
iface, **params)
ports[iface.index] = [ifdata[1][x].index for x in 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 iface in ifdata[0].values():
brdata = _sysfs_read_br(iface.name)
if brdata == None:
continue
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 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): def create_bridge(br):
if isinstance(br, str): if isinstance(br, str):
br = netns.interface.interface(name = br) br = netns.interface.interface(name = br)
...@@ -286,7 +297,7 @@ def set_bridge(br, recover = True): ...@@ -286,7 +297,7 @@ def set_bridge(br, recover = True):
set_if(orig_br, recover = False) # rollback set_if(orig_br, recover = False) # rollback
raise 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 diff = br - orig_br # Only set what's needed
cmds = [] cmds = []
...@@ -302,7 +313,8 @@ def set_bridge(br, recover = True): ...@@ -302,7 +313,8 @@ def set_bridge(br, recover = True):
cmds.append(('max_age', int(diff.max_age))) cmds.append(('max_age', int(diff.max_age)))
set_if(diff) 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): def add_bridge_port(br, iface):
ifname = _get_if_name(iface) ifname = _get_if_name(iface)
......
...@@ -59,9 +59,8 @@ class TestGlobal(unittest.TestCase): ...@@ -59,9 +59,8 @@ class TestGlobal(unittest.TestCase):
i2.add_v4_address('10.0.0.2', 24) i2.add_v4_address('10.0.0.2', 24)
null = file('/dev/null', 'wb') null = file('/dev/null', 'wb')
# the bridge seems to be quite slow! a1 = n1.Popen(['ping', '-qc1', '10.0.0.2'], stdout = null)
a1 = n1.Popen(['ping', '-qc1', '-w20', '10.0.0.2'], stdout = null) a2 = n2.Popen(['ping', '-qc1', '10.0.0.1'], stdout = null)
a2 = n2.Popen(['ping', '-qc1', '-w20', '10.0.0.1'], stdout = null)
self.assertEquals(a1.wait(), 0) self.assertEquals(a1.wait(), 0)
self.assertEquals(a2.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