Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions examples/quagga-ixp/topo.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
30 changes: 20 additions & 10 deletions mininext/node.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 #

Expand All @@ -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)
Expand All @@ -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)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reasonable to have a timeout -- not sure if Mininet had this support before, but certainly better than hanging.

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):
Expand Down Expand Up @@ -439,6 +450,5 @@ def hasPrivateMount(self, target):


class Host(Node):

"MiniNExT enabled host"
pass
6 changes: 4 additions & 2 deletions mininext/topo.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,17 @@ 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
opts: host options
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):
Expand Down