Commit 23841d8d authored by Martín Ferrari's avatar Martín Ferrari

moved internal interface classes to iproute, as they are used mostly for iproute communication

parent b6d0ee4f
......@@ -58,24 +58,24 @@ class NSInterface(Interface):
if name[0] == '_': # forbid anything that doesn't start with a _
super(Interface, self).__setattr__(name, value)
return
iface = interface(index = self.index)
iface = netns.iproute.interface(index = self.index)
setattr(iface, name, value)
return self._slave.set_if(iface)
def add_v4_address(self, address, prefix_len, broadcast = None):
addr = ipv4address(address, prefix_len, broadcast)
addr = netns.iproute.ipv4address(address, prefix_len, broadcast)
self._slave.add_addr(self.index, addr)
def add_v6_address(self, address, prefix_len):
addr = ipv6address(address, prefix_len)
addr = netns.iproute.ipv6address(address, prefix_len)
self._slave.add_addr(self.index, addr)
def del_v4_address(self, address, prefix_len, broadcast = None):
addr = ipv4address(address, prefix_len, broadcast)
addr = netns.iproute.ipv4address(address, prefix_len, broadcast)
self._slave.del_addr(self.index, addr)
def del_v6_address(self, address, prefix_len):
addr = ipv6address(address, prefix_len)
addr = netns.iproute.ipv6address(address, prefix_len)
self._slave.del_addr(self.index, addr)
def get_addresses(self):
......@@ -102,8 +102,8 @@ class NodeInterface(NSInterface):
def __init__(self, node):
"""Create a new interface. `node' is the name space in which this
interface should be put."""
if1 = interface(name = self._gen_if_name())
if2 = interface(name = self._gen_if_name())
if1 = netns.iproute.interface(name = self._gen_if_name())
if2 = netns.iproute.interface(name = self._gen_if_name())
ctl, ns = netns.iproute.create_if_pair(if1, if2)
try:
netns.iproute.change_netns(ns, node.pid)
......@@ -136,8 +136,8 @@ class P2PInterface(NSInterface):
def create_pair(node1, node2):
"""Create and return a pair of connected P2PInterface objects, assigned
to name spaces represented by `node1' and `node2'."""
if1 = interface(name = P2PInterface._gen_if_name())
if2 = interface(name = P2PInterface._gen_if_name())
if1 = netns.iproute.interface(name = P2PInterface._gen_if_name())
if2 = netns.iproute.interface(name = P2PInterface._gen_if_name())
pair = netns.iproute.create_if_pair(if1, if2)
try:
netns.iproute.change_netns(pair[0], node1.pid)
......@@ -198,24 +198,24 @@ class ExternalInterface(Interface):
if name[0] == '_': # forbid anything that doesn't start with a _
super(ExternalInterface, self).__setattr__(name, value)
return
iface = interface(index = self.index)
iface = netns.iproute.interface(index = self.index)
setattr(iface, name, value)
return netns.iproute.set_if(iface)
def add_v4_address(self, address, prefix_len, broadcast = None):
addr = ipv4address(address, prefix_len, broadcast)
addr = netns.iproute.ipv4address(address, prefix_len, broadcast)
netns.iproute.add_addr(self.index, addr)
def add_v6_address(self, address, prefix_len):
addr = ipv6address(address, prefix_len)
addr = netns.iproute.ipv6address(address, prefix_len)
netns.iproute.add_addr(self.index, addr)
def del_v4_address(self, address, prefix_len, broadcast = None):
addr = ipv4address(address, prefix_len, broadcast)
addr = netns.iproute.ipv4address(address, prefix_len, broadcast)
netns.iproute.del_addr(self.index, addr)
def del_v6_address(self, address, prefix_len):
addr = ipv6address(address, prefix_len)
addr = netns.iproute.ipv6address(address, prefix_len)
netns.iproute.del_addr(self.index, addr)
def get_addresses(self):
......@@ -301,7 +301,7 @@ class Link(ExternalInterface):
if name[0] == '_': # forbid anything that doesn't start with a _
super(ExternalInterface, self).__setattr__(name, value)
return
iface = bridge(index = self.index)
iface = netns.iproute.bridge(index = self.index)
setattr(iface, name, value)
return netns.iproute.set_bridge(iface)
......@@ -332,210 +332,3 @@ class Link(ExternalInterface):
# don't look after this :-)
# helpers
def _any_to_bool(any):
if isinstance(any, bool):
return any
if isinstance(any, int):
return any != 0
if isinstance(any, str):
if any.isdigit():
return int(any) != 0
if any.lower() == "true":
return True
if any.lower() == "false":
return False
return any != ""
return bool(any)
def _positive(val):
v = int(val)
if v <= 0:
raise ValueError("Invalid value: %d" % v)
return v
def _fix_lladdr(addr):
foo = addr.lower()
if ':' in addr:
# Verify sanity and split
m = re.search('^' + ':'.join(['([0-9a-f]{1,2})'] * 6) + '$', foo)
if m is None:
raise ValueError("Invalid address: `%s'." % addr)
# Fill missing zeros and glue again
return ':'.join(('0' * (2 - len(x)) + x for x in m.groups()))
# Fill missing zeros
foo = '0' * (12 - len(foo)) + foo
# Verify sanity and split
m = re.search('^' + '([0-9a-f]{2})' * 6 + '$', foo)
if m is None:
raise ValueError("Invalid address: `%s'." % addr)
# Glue
return ":".join(m.groups())
def _make_getter(attr, conv = lambda x: x):
def getter(self):
return conv(getattr(self, attr))
return getter
def _make_setter(attr, conv = lambda x: x):
def setter(self, value):
if value == None:
setattr(self, attr, None)
else:
setattr(self, attr, conv(value))
return setter
# classes for internal use
class interface(object):
"""Class for internal use. It is mostly a data container used to easily
pass information around; with some convenience methods."""
# information for other parts of the code
changeable_attributes = ["name", "mtu", "lladdr", "broadcast", "up",
"multicast", "arp"]
# Index should be read-only
index = property(_make_getter("_index"))
up = property(_make_getter("_up"), _make_setter("_up", _any_to_bool))
mtu = property(_make_getter("_mtu"), _make_setter("_mtu", _positive))
lladdr = property(_make_getter("_lladdr"),
_make_setter("_lladdr", _fix_lladdr))
arp = property(_make_getter("_arp"), _make_setter("_arp", _any_to_bool))
multicast = property(_make_getter("_mc"), _make_setter("_mc", _any_to_bool))
def __init__(self, index = None, name = None, up = None, mtu = None,
lladdr = None, broadcast = None, multicast = None, arp = None):
self._index = _positive(index) if index is not None else None
self.name = name
self.up = up
self.mtu = mtu
self.lladdr = lladdr
self.broadcast = broadcast
self.multicast = multicast
self.arp = arp
def __repr__(self):
s = "%s.%s(index = %s, name = %s, up = %s, mtu = %s, lladdr = %s, "
s += "broadcast = %s, multicast = %s, arp = %s)"
return s % (self.__module__, self.__class__.__name__,
self.index.__repr__(), self.name.__repr__(),
self.up.__repr__(), self.mtu.__repr__(),
self.lladdr.__repr__(), self.broadcast.__repr__(),
self.multicast.__repr__(), self.arp.__repr__())
def __sub__(self, o):
"""Compare attributes and return a new object with just the attributes
that differ set (with the value they have in the first operand). The
index remains equal to the first operand."""
name = None if self.name == o.name else self.name
up = None if self.up == o.up else self.up
mtu = None if self.mtu == o.mtu else self.mtu
lladdr = None if self.lladdr == o.lladdr else self.lladdr
broadcast = None if self.broadcast == o.broadcast else self.broadcast
multicast = None if self.multicast == o.multicast else self.multicast
arp = None if self.arp == o.arp else self.arp
return self.__class__(self.index, name, up, mtu, lladdr, broadcast,
multicast, arp)
class bridge(interface):
changeable_attributes = interface.changeable_attributes + ["stp",
"forward_delay", "hello_time", "ageing_time", "max_age"]
# Index should be read-only
stp = property(_make_getter("_stp"), _make_setter("_stp", _any_to_bool))
forward_delay = property(_make_getter("_forward_delay"),
_make_setter("_forward_delay", float))
hello_time = property(_make_getter("_hello_time"),
_make_setter("_hello_time", float))
ageing_time = property(_make_getter("_ageing_time"),
_make_setter("_ageing_time", float))
max_age = property(_make_getter("_max_age"),
_make_setter("_max_age", float))
@classmethod
def upgrade(cls, iface, *kargs, **kwargs):
"""Upgrade a interface to a bridge."""
return cls(iface.index, iface.name, iface.up, iface.mtu, iface.lladdr,
iface.broadcast, iface.multicast, iface.arp, *kargs, **kwargs)
def __init__(self, index = None, name = None, up = None, mtu = None,
lladdr = None, broadcast = None, multicast = None, arp = None,
stp = None, forward_delay = None, hello_time = None,
ageing_time = None, max_age = None):
super(bridge, self).__init__(index, name, up, mtu, lladdr, broadcast,
multicast, arp)
self.stp = stp
self.forward_delay = forward_delay
self.hello_time = hello_time
self.ageing_time = ageing_time
self.max_age = max_age
def __repr__(self):
s = "%s.%s(index = %s, name = %s, up = %s, mtu = %s, lladdr = %s, "
s += "broadcast = %s, multicast = %s, arp = %s, stp = %s, "
s += "forward_delay = %s, hello_time = %s, ageing_time = %s, "
s += "max_age = %s)"
return s % (self.__module__, self.__class__.__name__,
self.index.__repr__(), self.name.__repr__(),
self.up.__repr__(), self.mtu.__repr__(),
self.lladdr.__repr__(), self.broadcast.__repr__(),
self.multicast.__repr__(), self.arp.__repr__(),
self.stp.__repr__(), self.forward_delay.__repr__(),
self.hello_time.__repr__(), self.ageing_time.__repr__(),
self.max_age.__repr__())
def __sub__(self, o):
r = super(bridge, self).__sub__(o)
if type(o) == interface:
return r
r.stp = None if self.stp == o.stp else self.stp
r.hello_time = None if self.hello_time == o.hello_time else \
self.hello_time
r.forward_delay = None if self.forward_delay == o.forward_delay else \
self.forward_delay
r.ageing_time = None if self.ageing_time == o.ageing_time else \
self.ageing_time
r.max_age = None if self.max_age == o.max_age else self.max_age
return r
class address(object):
"""Class for internal use. It is mostly a data container used to easily
pass information around; with some convenience methods. __eq__ and __hash__
are defined just to be able to easily find duplicated addresses."""
# broadcast is not taken into account for differentiating addresses
def __eq__(self, o):
if not isinstance(o, address):
return False
return (self.family == o.family and self.address == o.address and
self.prefix_len == o.prefix_len)
def __hash__(self):
h = (self.address.__hash__() ^ self.prefix_len.__hash__() ^
self.family.__hash__())
return h
class ipv4address(address):
def __init__(self, address, prefix_len, broadcast):
self.address = address
self.prefix_len = int(prefix_len)
self.broadcast = broadcast
self.family = socket.AF_INET
def __repr__(self):
s = "%s.%s(address = %s, prefix_len = %d, broadcast = %s)"
return s % (self.__module__, self.__class__.__name__,
self.address.__repr__(), self.prefix_len,
self.broadcast.__repr__())
class ipv6address(address):
def __init__(self, address, prefix_len):
self.address = address
self.prefix_len = int(prefix_len)
self.family = socket.AF_INET6
def __repr__(self):
s = "%s.%s(address = %s, prefix_len = %d)"
return s % (self.__module__, self.__class__.__name__,
self.address.__repr__(), self.prefix_len)
# vim:ts=4:sw=4:et:ai:sts=4
import os, re, subprocess, sys
import netns.interface
# helpers
def _any_to_bool(any):
if isinstance(any, bool):
return any
if isinstance(any, int):
return any != 0
if isinstance(any, str):
if any.isdigit():
return int(any) != 0
if any.lower() == "true":
return True
if any.lower() == "false":
return False
return any != ""
return bool(any)
def _positive(val):
v = int(val)
if v <= 0:
raise ValueError("Invalid value: %d" % v)
return v
def _fix_lladdr(addr):
foo = addr.lower()
if ':' in addr:
# Verify sanity and split
m = re.search('^' + ':'.join(['([0-9a-f]{1,2})'] * 6) + '$', foo)
if m is None:
raise ValueError("Invalid address: `%s'." % addr)
# Fill missing zeros and glue again
return ':'.join(('0' * (2 - len(x)) + x for x in m.groups()))
# Fill missing zeros
foo = '0' * (12 - len(foo)) + foo
# Verify sanity and split
m = re.search('^' + '([0-9a-f]{2})' * 6 + '$', foo)
if m is None:
raise ValueError("Invalid address: `%s'." % addr)
# Glue
return ":".join(m.groups())
def _make_getter(attr, conv = lambda x: x):
def getter(self):
return conv(getattr(self, attr))
return getter
def _make_setter(attr, conv = lambda x: x):
def setter(self, value):
if value == None:
setattr(self, attr, None)
else:
setattr(self, attr, conv(value))
return setter
# classes for internal use
class interface(object):
"""Class for internal use. It is mostly a data container used to easily
pass information around; with some convenience methods."""
# information for other parts of the code
changeable_attributes = ["name", "mtu", "lladdr", "broadcast", "up",
"multicast", "arp"]
# Index should be read-only
index = property(_make_getter("_index"))
up = property(_make_getter("_up"), _make_setter("_up", _any_to_bool))
mtu = property(_make_getter("_mtu"), _make_setter("_mtu", _positive))
lladdr = property(_make_getter("_lladdr"),
_make_setter("_lladdr", _fix_lladdr))
arp = property(_make_getter("_arp"), _make_setter("_arp", _any_to_bool))
multicast = property(_make_getter("_mc"), _make_setter("_mc", _any_to_bool))
def __init__(self, index = None, name = None, up = None, mtu = None,
lladdr = None, broadcast = None, multicast = None, arp = None):
self._index = _positive(index) if index is not None else None
self.name = name
self.up = up
self.mtu = mtu
self.lladdr = lladdr
self.broadcast = broadcast
self.multicast = multicast
self.arp = arp
def __repr__(self):
s = "%s.%s(index = %s, name = %s, up = %s, mtu = %s, lladdr = %s, "
s += "broadcast = %s, multicast = %s, arp = %s)"
return s % (self.__module__, self.__class__.__name__,
self.index.__repr__(), self.name.__repr__(),
self.up.__repr__(), self.mtu.__repr__(),
self.lladdr.__repr__(), self.broadcast.__repr__(),
self.multicast.__repr__(), self.arp.__repr__())
def __sub__(self, o):
"""Compare attributes and return a new object with just the attributes
that differ set (with the value they have in the first operand). The
index remains equal to the first operand."""
name = None if self.name == o.name else self.name
up = None if self.up == o.up else self.up
mtu = None if self.mtu == o.mtu else self.mtu
lladdr = None if self.lladdr == o.lladdr else self.lladdr
broadcast = None if self.broadcast == o.broadcast else self.broadcast
multicast = None if self.multicast == o.multicast else self.multicast
arp = None if self.arp == o.arp else self.arp
return self.__class__(self.index, name, up, mtu, lladdr, broadcast,
multicast, arp)
class bridge(interface):
changeable_attributes = interface.changeable_attributes + ["stp",
"forward_delay", "hello_time", "ageing_time", "max_age"]
# Index should be read-only
stp = property(_make_getter("_stp"), _make_setter("_stp", _any_to_bool))
forward_delay = property(_make_getter("_forward_delay"),
_make_setter("_forward_delay", float))
hello_time = property(_make_getter("_hello_time"),
_make_setter("_hello_time", float))
ageing_time = property(_make_getter("_ageing_time"),
_make_setter("_ageing_time", float))
max_age = property(_make_getter("_max_age"),
_make_setter("_max_age", float))
@classmethod
def upgrade(cls, iface, *kargs, **kwargs):
"""Upgrade a interface to a bridge."""
return cls(iface.index, iface.name, iface.up, iface.mtu, iface.lladdr,
iface.broadcast, iface.multicast, iface.arp, *kargs, **kwargs)
def __init__(self, index = None, name = None, up = None, mtu = None,
lladdr = None, broadcast = None, multicast = None, arp = None,
stp = None, forward_delay = None, hello_time = None,
ageing_time = None, max_age = None):
super(bridge, self).__init__(index, name, up, mtu, lladdr, broadcast,
multicast, arp)
self.stp = stp
self.forward_delay = forward_delay
self.hello_time = hello_time
self.ageing_time = ageing_time
self.max_age = max_age
def __repr__(self):
s = "%s.%s(index = %s, name = %s, up = %s, mtu = %s, lladdr = %s, "
s += "broadcast = %s, multicast = %s, arp = %s, stp = %s, "
s += "forward_delay = %s, hello_time = %s, ageing_time = %s, "
s += "max_age = %s)"
return s % (self.__module__, self.__class__.__name__,
self.index.__repr__(), self.name.__repr__(),
self.up.__repr__(), self.mtu.__repr__(),
self.lladdr.__repr__(), self.broadcast.__repr__(),
self.multicast.__repr__(), self.arp.__repr__(),
self.stp.__repr__(), self.forward_delay.__repr__(),
self.hello_time.__repr__(), self.ageing_time.__repr__(),
self.max_age.__repr__())
def __sub__(self, o):
r = super(bridge, self).__sub__(o)
if type(o) == interface:
return r
r.stp = None if self.stp == o.stp else self.stp
r.hello_time = None if self.hello_time == o.hello_time else \
self.hello_time
r.forward_delay = None if self.forward_delay == o.forward_delay else \
self.forward_delay
r.ageing_time = None if self.ageing_time == o.ageing_time else \
self.ageing_time
r.max_age = None if self.max_age == o.max_age else self.max_age
return r
class address(object):
"""Class for internal use. It is mostly a data container used to easily
pass information around; with some convenience methods. __eq__ and __hash__
are defined just to be able to easily find duplicated addresses."""
# broadcast is not taken into account for differentiating addresses
def __eq__(self, o):
if not isinstance(o, address):
return False
return (self.family == o.family and self.address == o.address and
self.prefix_len == o.prefix_len)
def __hash__(self):
h = (self.address.__hash__() ^ self.prefix_len.__hash__() ^
self.family.__hash__())
return h
class ipv4address(address):
def __init__(self, address, prefix_len, broadcast):
self.address = address
self.prefix_len = int(prefix_len)
self.broadcast = broadcast
self.family = socket.AF_INET
def __repr__(self):
s = "%s.%s(address = %s, prefix_len = %d, broadcast = %s)"
return s % (self.__module__, self.__class__.__name__,
self.address.__repr__(), self.prefix_len,
self.broadcast.__repr__())
class ipv6address(address):
def __init__(self, address, prefix_len):
self.address = address
self.prefix_len = int(prefix_len)
self.family = socket.AF_INET6
def __repr__(self):
s = "%s.%s(address = %s, prefix_len = %d)"
return s % (self.__module__, self.__class__.__name__,
self.address.__repr__(), self.prefix_len)
# XXX: ideally this should be replaced by netlink communication
# helpers
def _execute(cmd):
#print " ".join(cmd)#; return
null = open('/dev/null', 'r+')
p = subprocess.Popen(cmd, stdout = null, stderr = subprocess.PIPE)
out, err = p.communicate()
if p.returncode != 0:
raise RuntimeError("Error executing `%s': %s" % (" ".join(cmd), err))
def _get_if_name(iface):
if isinstance(iface, interface):
if iface.name != None:
return iface.name
if isinstance(iface, str):
return iface
return get_if(iface).name
# Interface handling
def get_if_data():
"""Gets current interface information. Returns a tuple (byidx, bynam) in
......@@ -28,7 +251,7 @@ def get_if_data():
match = re.search(r'^(\d+): (\S+): <(\S+)> mtu (\d+) qdisc \S+' +
r'.*link/\S+ ([0-9a-f:]+) brd ([0-9a-f:]+)', line)
flags = match.group(3).split(",")
i = netns.interface.interface(
i = interface(
index = match.group(1),
name = match.group(2),
up = "UP" in flags,
......@@ -42,7 +265,7 @@ def get_if_data():
def get_if(iface):
ifdata = get_if_data()
if isinstance(iface, netns.interface.interface):
if isinstance(iface, interface):
if iface.index != None:
return ifdata[0][iface.index]
else:
......@@ -163,14 +386,14 @@ 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 netns.interface.ipv4address(
return ipv4address(
address = match.group(1),
prefix_len = match.group(2),
broadcast = match.group(3))
match = re.search(r'^inet6 ([0-9a-f:]+)/(\d+)', line)
if match != None:
return netns.interface.ipv6address(
return ipv6address(
address = match.group(1),
prefix_len = match.group(2))
......@@ -252,7 +475,7 @@ def get_bridge_data():
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)
bridge.upgrade(iface, **brdata)
return byidx, bynam, ports
def get_bridge(br):
......@@ -260,11 +483,11 @@ def get_bridge(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)
return bridge.upgrade(iface, **brdata)
def create_bridge(br):
if isinstance(br, str):
br = netns.interface.interface(name = br)
br = interface(name = br)
assert br.name
_execute(['brctl', 'addbr', br.name])
try:
......@@ -326,20 +549,3 @@ def del_bridge_port(br, iface):
brname = _get_if_name(br)
_execute(['brctl', 'delif', brname, ifname])
# Useful stuff
def _execute(cmd):
#print " ".join(cmd)#; return
null = open('/dev/null', 'r+')
p = subprocess.Popen(cmd, stdout = null, stderr = subprocess.PIPE)
out, err = p.communicate()
if p.returncode != 0:
raise RuntimeError("Error executing `%s': %s" % (" ".join(cmd), err))
def _get_if_name(iface):
if isinstance(iface, netns.interface.interface):
if iface.name != None:
return iface.name
if isinstance(iface, str):
return iface
return get_if(iface).name
......@@ -8,7 +8,7 @@ except ImportError:
from yaml import Loader, Dumper
import base64, os, passfd, re, signal, sys, traceback, unshare, yaml
import netns.subprocess_, netns.iproute, netns.interface
import netns.subprocess_, netns.iproute
# ============================================================================
# Server-side protocol implementation
......@@ -339,7 +339,7 @@ class Server(object):
for i in range(len(args) / 2):
d[str(args[i * 2])] = args[i * 2 + 1]
iface = netns.interface.interface(**d)
iface = netns.iproute.interface(**d)
netns.iproute.set_if(iface)
self.reply(200, "Done.")
......@@ -360,17 +360,17 @@ class Server(object):
def do_ADDR_ADD(self, cmdname, ifnr, address, prefixlen, broadcast = None):
if address.find(":") < 0: # crude, I know
a = netns.interface.ipv4address(address, prefixlen, broadcast)
a = netns.iproute.ipv4address(address, prefixlen, broadcast)
else:
a = netns.interface.ipv6address(address, prefixlen)
a = netns.iproute.ipv6address(address, prefixlen)
netns.iproute.add_addr(ifnr, a)
self.reply(200, "Done.")
def do_ADDR_DEL(self, cmdname, ifnr, address, prefixlen):
if address.find(":") < 0: # crude, I know
a = netns.interface.ipv4address(address, prefixlen, None)
a = netns.iproute.ipv4address(address, prefixlen, None)
else:
a = netns.interface.ipv6address(address, prefixlen)
a = netns.iproute.ipv6address(address, prefixlen)
netns.iproute.del_addr(ifnr, a)
self.reply(200, "Done.")
......
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