Commit 1e51417b authored by Martín Ferrari's avatar Martín Ferrari

better layout; now Client is just the protocol implementation

parent dd785bb2
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
# vim:ts=4:sw=4:et:ai:sts=4 # vim:ts=4:sw=4:et:ai:sts=4
import os import os
import netns.protocol from netns.node import Node
class __Config(object): class __Config(object):
def __init__(self): def __init__(self):
...@@ -17,44 +17,8 @@ def get_nodes(): ...@@ -17,44 +17,8 @@ def get_nodes():
def set_cleanup_hooks(on_exit = False, on_signals = []): def set_cleanup_hooks(on_exit = False, on_signals = []):
pass pass
class Node(object):
def __init__(self):
self._slave = netns.protocol.Slave()
self._valid = True
@property
def pid(self):
return self.slave_pid
def add_if(self, mac_address = None, mtu = None):
return Interface(mac_address, mtu)
def add_route(self, prefix, prefix_len, nexthop = None, interface = None):
assert nexthop or interface
def add_default_route(self, nexthop, interface = None):
return self.add_route('0.0.0.0', 0, nexthop, interface)
def start_process(self, args):
return Process()
def run_process(self, args):
return ("", "")
def get_routes(self):
return set()
class Link(object): class Link(object):
def connect(self, iface): def connect(self, iface):
pass pass
class Interface(object):
def __init__(self, mac_address = None, mtu = None):
self.name = None
self.mac_address = mac_address
self.mtu = mtu
self.valid = True
def add_v4_address(self, address, prefix_len, broadcast = None):
pass
def add_v6_address(self, address, prefix_len):
pass
class Process(object):
def __init__(self):
self.pid = os.getpid()
self.valid = True
#!/usr/bin/env python
# vim:ts=4:sw=4:et:ai:sts=4
import os, socket, sys, traceback, unshare
import netns.protocol
class Node(object):
def __init__(self, debug = False):
"""Create a new node in the emulation. Implemented as a separate
process in a new network name space. Requires root privileges to run.
If keepns is true, the network name space is not created and can be run
as a normal user, for testing. If debug is true, details of the
communication protocol are printed on stderr."""
fd, pid = _start_child(debug)
self._pid = pid
self._slave = netns.protocol.Client(fd, debug)
self._valid = True
@property
def pid(self):
return self._pid
def add_if(self, mac_address = None, mtu = None):
return Interface(mac_address, mtu)
def add_route(self, prefix, prefix_len, nexthop = None, interface = None):
assert nexthop or interface
def add_default_route(self, nexthop, interface = None):
return self.add_route('0.0.0.0', 0, nexthop, interface)
def start_process(self, args):
return Process()
def run_process(self, args):
return ("", "")
def get_routes(self):
return set()
class Interface(object):
def __init__(self, mac_address = None, mtu = None):
self.name = None
self.mac_address = mac_address
self.mtu = mtu
self.valid = True
def add_v4_address(self, address, prefix_len, broadcast = None):
pass
def add_v6_address(self, address, prefix_len):
pass
class Process(object):
def __init__(self):
self.pid = os.getpid()
self.valid = True
# Handle the creation of the child; parent gets (fd, pid), child creates and
# runs a Server(); never returns.
# Requires CAP_SYS_ADMIN privileges to run.
def _start_child(debug = False):
# Create socket pair to communicate
(s0, s1) = socket.socketpair(socket.AF_UNIX, socket.SOCK_STREAM, 0)
# Spawn a child that will run in a loop
pid = os.fork()
if pid:
s1.close()
return (s0, pid)
try:
s0.close()
srv = netns.protocol.Server(s1, debug)
unshare.unshare(unshare.CLONE_NEWNET)
srv.run()
except BaseException, e:
s = "Slave node aborting: %s\n" % str(e)
sep = "=" * 70 + "\n"
sys.stderr.write(s + sep)
traceback.print_exc(file=sys.stdout)
sys.stderr.write(sep)
try:
# try to pass the error to parent, if possible
s1.send("500 " + s)
except:
pass
os._exit(1)
os._exit(0)
# NOTREACHED
...@@ -352,55 +352,12 @@ class Server(object): ...@@ -352,55 +352,12 @@ class Server(object):
# ============================================================================ # ============================================================================
# #
# Client-side protocol implementation, and slave process creation # Client-side protocol implementation.
# #
# Handle the creation of the child; parent gets (fd, pid), child never returns class Client(object):
def _start_child(debug = False): """Client-side implementation of the communication protocol. Acts as a RPC
# Create socket pair to communicate service."""
(s0, s1) = socket.socketpair(socket.AF_UNIX, socket.SOCK_STREAM, 0) def __init__(self, fd, debug = False):
# Spawn a child that will run in a loop
pid = os.fork()
if pid:
s1.close()
return (s0, pid)
try:
s0.close()
srv = Server(s1, debug)
unshare.unshare(unshare.CLONE_NEWNET)
srv.run()
except BaseException, e:
s = "Slave node aborting: %s\n" % str(e)
sep = "=" * 70 + "\n"
sys.stderr.write(s + sep)
traceback.print_exc(file=sys.stdout)
sys.stderr.write(sep)
try:
# try to pass the error to parent, if possible
s1.send("500 " + s)
except:
pass
os._exit(1)
os._exit(0)
# NOTREACHED
class Slave(object):
"""Class to create and manage slave processes; it is at the same time a
client implementation for the communication protocol."""
def __init__(self, debug = False, fd = None, pid = None):
"""When called without arguments, it will fork, create a new network
namespace and enter a loop to serve requests from the master. The
parent process will return an object which is used to control the slave
thru RPC-like calls.
If fd and pid are specified, the slave process is not created; fd is
used as a control socket and pid is assumed to be the pid of the slave
process."""
# If fd is passed do not fork or anything
if not (fd and pid):
fd, pid = _start_child(debug)
# XXX: In some cases we do not call dup(); maybe this should be # XXX: In some cases we do not call dup(); maybe this should be
# consistent? # consistent?
if not hasattr(fd, "readline"): if not hasattr(fd, "readline"):
...@@ -412,7 +369,6 @@ class Slave(object): ...@@ -412,7 +369,6 @@ class Slave(object):
nfd = os.dup(fd) nfd = os.dup(fd)
fd = os.fdopen(nfd, "r+", 1) fd = os.fdopen(nfd, "r+", 1)
self._pid = pid
self._fd = fd self._fd = fd
# Wait for slave to send banner # Wait for slave to send banner
self._read_and_check_reply() self._read_and_check_reply()
......
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