diff --git a/examples/quagga-ixp/topo.py b/examples/quagga-ixp/topo.py index 77b20e3..1b0f58c 100644 --- a/examples/quagga-ixp/topo.py +++ b/examples/quagga-ixp/topo.py @@ -17,12 +17,10 @@ class QuaggaTopo(Topo): "Creates a topology of Quagga routers" - def __init__(self): + def build(self): """Initialize a Quagga topology with 5 routers, configure their IP addresses, loop back interfaces, and paths to their private configuration directories.""" - Topo.__init__(self) - # Directory where this file / script is located" selfPath = os.path.dirname(os.path.abspath( inspect.getfile(inspect.currentframe()))) # script directory @@ -74,4 +72,8 @@ def __init__(self): nodeConfig=quaggaSvcConfig) # Attach the quaggaContainer to the IXP Fabric Switch - self.addLink(quaggaContainer, ixpfabric) + # NOTE: needs the fast=False parameter to work on mininet > 2.2 + # The fast path in mininet passes namens to ip instead of + # bringing up the interfaces and moving them to namespaces. + # That approach fails when processes are in separate PID ns + self.addLink(quaggaContainer, ixpfabric, fast=False) diff --git a/mininext/node.py b/mininext/node.py index 10b5ef9..cf641be 100644 --- a/mininext/node.py +++ b/mininext/node.py @@ -6,6 +6,8 @@ import select import shutil import tempfile +import pty +import os from subprocess import Popen, PIPE, STDOUT from mininet.node import Node as BaseNode @@ -50,7 +52,7 @@ def __init__(self, name, inMountNamespace=False, inPIDNamespace=False, self.loIntfs = {} # Request initialization of the BaseNode - BaseNode.__init__(self, name, **params) + BaseNode.__init__(self, name, inUTSNamespace, **params) # Overrides to support additional extensions # @@ -75,11 +77,13 @@ def startShell(self): opts += 'u' # bash -m: enable job control # -s: pass $* to shell, and make process easy to find in ps - cmd = ['mxexec', opts, 'bash', '-ms', 'mininet:' + self.name] - self.shell = Popen(cmd, stdin=PIPE, stdout=PIPE, stderr=STDOUT, - close_fds=True) - self.stdin = self.shell.stdin - self.stdout = self.shell.stdout + cmd = [ 'mxexec', opts, 'env', 'PS1=' + chr( 127 ), + 'bash', '--norc', '-is', 'mininet:' + self.name ] + master, slave = pty.openpty() + self.shell = Popen(cmd, stdin=slave, stdout=slave, stderr=slave, + close_fds=False) + self.stdin = os.fdopen( master, 'rw') + self.stdout = self.stdin self.pid = self.shell.pid self.pollOut = select.poll() self.pollOut.register(self.stdout) @@ -92,17 +96,24 @@ def startShell(self): self.lastCmd = None self.lastPid = None self.readbuf = '' - self.waiting = False - # If this node has a private PID space, grab the PID to attach to # Otherwise, we use the same PID as the shell's PID if self.inPIDNamespace: # monitor() will grab shell's true PID and put in self.lastPid - self.monitor() + self.monitor(1000) if self.lastPid is None: raise Exception('Unable to determine shell\'s PID') self.pid = self.lastPid self.lastPid = None + # Wait for prompt + while True: + data = self.read( 1024 ) + if data[ -1 ] == chr( 127 ): + break + self.pollOut.poll() + self.waiting = False + # +m: disable job control notification + self.cmd( 'unset HISTFILE; stty -echo; set +m' ) # Override on popen() to support mount and PID namespaces def popen(self, *args, **kwargs): @@ -439,6 +450,5 @@ def hasPrivateMount(self, target): class Host(Node): - "MiniNExT enabled host" pass diff --git a/mininext/topo.py b/mininext/topo.py index 177e215..fea4175 100644 --- a/mininext/topo.py +++ b/mininext/topo.py @@ -17,7 +17,7 @@ def __init__(self, nopts=None, **opts): BaseTopo.__init__(self, **opts) # Override addHost so that constructor defaults to MiniNExT host - def addHost(self, name, cls=Host, **opts): + def addHost(self, name, **opts): """Adds a host using the MiniNExT host constructor. name: host name cls: host constructor @@ -25,7 +25,9 @@ def addHost(self, name, cls=Host, **opts): returns: host name""" if not opts and self.hopts: opts = self.hopts - return BaseTopo.addNode(self, name, cls=cls, **opts) + if 'cls' not in opts: + opts['cls'] = Host + return BaseTopo.addNode(self, name, **opts) # Configure a loopback interface def addNodeLoopbackIntf(self, node, ip, loNum=None, **opts):