Compare commits
36 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 107785ddf1 | |||
| 6bb5e12347 | |||
| 928c0761a0 | |||
| 30b4b4e7f9 | |||
| f509ae282d | |||
| 6c947bca07 | |||
| e4514a4ecb | |||
| 8c778bb081 | |||
| f1bf3c60e0 | |||
| 06f7408cf2 | |||
| e1ca7196c7 | |||
| 8f310286f8 | |||
| b97c0392a9 | |||
| 9c6620d85d | |||
| ae2ede7994 | |||
| b91008345f | |||
| 2f8dfe5810 | |||
| 79dcdc0491 | |||
| b0fb398833 | |||
| 6e64deec08 | |||
| b97c1dbd56 | |||
| d75e39ac61 | |||
| e8d60e0fcf | |||
| 0d94548a09 | |||
| 4c3ff8f184 | |||
| 0e8cca0869 | |||
| 0eba655d2d | |||
| cece39e439 | |||
| cfd381134f | |||
| 55cf19c4de | |||
| 50cebe6753 | |||
| 237a3c54cf | |||
| 5ca91f9ced | |||
| df600200a7 | |||
| 089e8130e4 | |||
| e78e8fb56a |
@@ -26,29 +26,8 @@ from mininet.node import ( Host, CPULimitedHost, Controller, OVSController,
|
||||
from mininet.link import Link, TCLink
|
||||
from mininet.topo import SingleSwitchTopo, LinearTopo, SingleSwitchReversedTopo
|
||||
from mininet.topolib import TreeTopo
|
||||
from mininet.util import makeNumeric, custom
|
||||
|
||||
|
||||
def customNode( constructors, argStr ):
|
||||
"Return custom Node constructor based on argStr"
|
||||
cname, newargs, kwargs = splitArgs( argStr )
|
||||
constructor = constructors.get( cname, None )
|
||||
|
||||
if not constructor:
|
||||
raise Exception( "error: %s is unknown - please specify one of %s" %
|
||||
( cname, constructors.keys() ) )
|
||||
|
||||
def customized( name, *args, **params ):
|
||||
"Customized Node constructor"
|
||||
params.update( kwargs )
|
||||
if not newargs:
|
||||
return constructor( name, *args, **params )
|
||||
if args:
|
||||
warn( 'warning: %s replacing %s with %s\n' % (
|
||||
constructor, args, newargs ) )
|
||||
return constructor( name, *newargs, **params )
|
||||
|
||||
return customized
|
||||
from mininet.util import makeNumeric, custom, customConstructor, splitArgs
|
||||
from mininet.util import buildTopo
|
||||
|
||||
|
||||
# built in topologies, created only when run
|
||||
@@ -89,31 +68,6 @@ ALTSPELLING = { 'pingall': 'pingAll', 'pingpair': 'pingPair',
|
||||
'iperfudp': 'iperfUdp', 'iperfUDP': 'iperfUdp', 'prefixlen': 'prefixLen' }
|
||||
|
||||
|
||||
def splitArgs( argstr ):
|
||||
"""Split argument string into usable python arguments
|
||||
argstr: argument string with format fn,arg2,kw1=arg3...
|
||||
returns: fn, args, kwargs"""
|
||||
split = argstr.split( ',' )
|
||||
fn = split[ 0 ]
|
||||
params = split[ 1: ]
|
||||
# Convert int and float args; removes the need for function
|
||||
# to be flexible with input arg formats.
|
||||
args = [ makeNumeric( s ) for s in params if '=' not in s ]
|
||||
kwargs = {}
|
||||
for s in [ p for p in params if '=' in p ]:
|
||||
key, val = s.split( '=' )
|
||||
kwargs[ key ] = makeNumeric( val )
|
||||
return fn, args, kwargs
|
||||
|
||||
|
||||
def buildTopo( topoStr ):
|
||||
"Create topology from string with format (object, arg1, arg2,...)."
|
||||
topo, args, kwargs = splitArgs( topoStr )
|
||||
if topo not in TOPOS:
|
||||
raise Exception( 'Invalid topo name %s' % topo )
|
||||
return TOPOS[ topo ]( *args, **kwargs )
|
||||
|
||||
|
||||
def addDictOption( opts, choicesDict, default, name, helpStr=None ):
|
||||
"""Convenience function to add choices dicts to OptionParser.
|
||||
opts: OptionParser instance
|
||||
@@ -205,9 +159,6 @@ class MininetRunner( object ):
|
||||
opts.add_option( '--verbosity', '-v', type='choice',
|
||||
choices=LEVELS.keys(), default = 'info',
|
||||
help = '|'.join( LEVELS.keys() ) )
|
||||
opts.add_option( '--ip', type='string', default='127.0.0.1',
|
||||
help='ip address as a dotted decimal string for a'
|
||||
'remote controller' )
|
||||
opts.add_option( '--innamespace', action='store_true',
|
||||
default=False, help='sw and ctrl in namespace?' )
|
||||
opts.add_option( '--listenport', type='int', default=6635,
|
||||
@@ -247,11 +198,11 @@ class MininetRunner( object ):
|
||||
|
||||
start = time.time()
|
||||
|
||||
topo = buildTopo( self.options.topo )
|
||||
switch = customNode( SWITCHES, self.options.switch )
|
||||
host = customNode( HOSTS, self.options.host )
|
||||
controller = customNode( CONTROLLERS, self.options.controller )
|
||||
link = customNode( LINKS, self.options.link )
|
||||
topo = buildTopo( TOPOS, self.options.topo )
|
||||
switch = customConstructor( SWITCHES, self.options.switch )
|
||||
host = customConstructor( HOSTS, self.options.host )
|
||||
controller = customConstructor( CONTROLLERS, self.options.controller )
|
||||
link = customConstructor( LINKS, self.options.link )
|
||||
|
||||
if self.validate:
|
||||
self.validate( self.options )
|
||||
|
||||
@@ -48,6 +48,11 @@ multitest.py:
|
||||
|
||||
This example creates a network and runs multiple tests on it.
|
||||
|
||||
popenpoll.py:
|
||||
|
||||
This example demonstrates monitoring output from multiple hosts using
|
||||
the node.popen() interface (which returns Popen objects) and pmonitor().
|
||||
|
||||
scratchnet.py, scratchnetuser.py:
|
||||
|
||||
These two examples demonstrate how to create a network by using the lowest-
|
||||
|
||||
Executable
+36
@@ -0,0 +1,36 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
"""
|
||||
This example monitors a number of hosts using host.popen() and
|
||||
pmonitor()
|
||||
"""
|
||||
|
||||
from mininet.net import Mininet
|
||||
from mininet.node import CPULimitedHost
|
||||
from mininet.topo import SingleSwitchTopo
|
||||
from mininet.log import setLogLevel
|
||||
from mininet.util import custom, pmonitor
|
||||
|
||||
def monitorhosts( hosts=5, sched='cfs' ):
|
||||
"Start a bunch of pings and monitor them using popen"
|
||||
mytopo = SingleSwitchTopo( hosts )
|
||||
cpu = .5 / hosts
|
||||
myhost = custom( CPULimitedHost, cpu=cpu, sched=sched )
|
||||
net = Mininet( topo=mytopo, host=myhost )
|
||||
net.start()
|
||||
# Start a bunch of pings
|
||||
popens = {}
|
||||
last = net.hosts[ -1 ]
|
||||
for host in net.hosts:
|
||||
popens[ host ] = host.popen( "ping -c5 %s" % last.IP() )
|
||||
last = host
|
||||
# Monitor them and print output
|
||||
for host, line in pmonitor( popens ):
|
||||
if host:
|
||||
print "<%s>: %s" % ( host.name, line.strip() )
|
||||
# Done
|
||||
net.stop()
|
||||
|
||||
if __name__ == '__main__':
|
||||
setLogLevel( 'info' )
|
||||
monitorhosts( hosts=5 )
|
||||
Executable
+33
@@ -0,0 +1,33 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
"Monitor multiple hosts using popen()/pmonitor()"
|
||||
|
||||
from mininet.net import Mininet
|
||||
from mininet.topo import SingleSwitchTopo
|
||||
from mininet.util import pmonitor
|
||||
from time import time
|
||||
from signal import SIGINT
|
||||
|
||||
def pmonitorTest( N=3, seconds=10 ):
|
||||
"Run pings and monitor multiple hosts using pmonitor"
|
||||
topo = SingleSwitchTopo( N )
|
||||
net = Mininet( topo )
|
||||
net.start()
|
||||
hosts = net.hosts
|
||||
print "Starting test..."
|
||||
server = hosts[ 0 ]
|
||||
popens = {}
|
||||
for h in hosts:
|
||||
popens[ h ] = h.popen('ping', server.IP() )
|
||||
print "Monitoring output for", seconds, "seconds"
|
||||
endTime = time() + seconds
|
||||
for h, line in pmonitor( popens, timeoutms=500 ):
|
||||
if h:
|
||||
print '%s: %s' % ( h.name, line ),
|
||||
if time() >= endTime:
|
||||
for p in popens.values():
|
||||
p.send_signal( SIGINT )
|
||||
net.stop()
|
||||
|
||||
if __name__ == '__main__':
|
||||
pmonitorTest()
|
||||
+10
-2
@@ -30,6 +30,7 @@ from cmd import Cmd
|
||||
from os import isatty
|
||||
from select import poll, POLLIN
|
||||
import sys
|
||||
import time
|
||||
|
||||
from mininet.log import info, output, error
|
||||
from mininet.term import makeTerms
|
||||
@@ -278,6 +279,13 @@ class CLI( Cmd ):
|
||||
output( '*** ' + sw.name + ' ' + ('-' * 72) + '\n' )
|
||||
output( sw.dpctl( *args ) )
|
||||
|
||||
def do_time( self, line ):
|
||||
"Measure time taken for any command in Mininet."
|
||||
start = time.time()
|
||||
self.onecmd(line)
|
||||
elapsed = time.time() - start
|
||||
self.stdout.write("*** Elapsed time: %0.6f secs\n" % elapsed)
|
||||
|
||||
def default( self, line ):
|
||||
"""Called on an input line when the command prefix is not recognized.
|
||||
Overridden to run shell commands when a node is the first CLI argument.
|
||||
@@ -313,8 +321,8 @@ class CLI( Cmd ):
|
||||
nodePoller = poll()
|
||||
nodePoller.register( node.stdout )
|
||||
bothPoller = poll()
|
||||
bothPoller.register( self.stdin )
|
||||
bothPoller.register( node.stdout )
|
||||
bothPoller.register( self.stdin, POLLIN )
|
||||
bothPoller.register( node.stdout, POLLIN )
|
||||
if self.isatty():
|
||||
# Buffer by character, so that interactive
|
||||
# commands sort of work
|
||||
|
||||
+7
-8
@@ -196,36 +196,35 @@ class TCIntf( Intf ):
|
||||
# are specifying the correct sizes. For now I have used
|
||||
# the same settings we had in the mininet-hifi code.
|
||||
if use_hfsc:
|
||||
cmds = [ '%s qdisc add dev %s root handle 1:0 hfsc default 1',
|
||||
cmds += [ '%s qdisc add dev %s root handle 1:0 hfsc default 1',
|
||||
'%s class add dev %s parent 1:0 classid 1:1 hfsc sc '
|
||||
+ 'rate %fMbit ul rate %fMbit' % ( bw, bw ) ]
|
||||
elif use_tbf:
|
||||
latency_us = 10 * 1500 * 8 / bw
|
||||
cmds = ['%s qdisc add dev %s root handle 1: tbf ' +
|
||||
cmds += ['%s qdisc add dev %s root handle 1: tbf ' +
|
||||
'rate %fMbit burst 15000 latency %fus' %
|
||||
( bw, latency_us ) ]
|
||||
else:
|
||||
cmds = [ '%s qdisc add dev %s root handle 1:0 htb default 1',
|
||||
cmds += [ '%s qdisc add dev %s root handle 1:0 htb default 1',
|
||||
'%s class add dev %s parent 1:0 classid 1:1 htb ' +
|
||||
'rate %fMbit burst 15k' % bw ]
|
||||
parent = ' parent 1:1 '
|
||||
|
||||
# ECN or RED
|
||||
if enable_ecn:
|
||||
cmds = [ '%s qdisc add dev %s' + parent +
|
||||
cmds += [ '%s qdisc add dev %s' + parent +
|
||||
'handle 10: red limit 1000000 ' +
|
||||
'min 20000 max 25000 avpkt 1000 ' +
|
||||
'min 30000 max 35000 avpkt 1500 ' +
|
||||
'burst 20 ' +
|
||||
'bandwidth %fmbit probability 1 ecn' % bw ]
|
||||
parent = ' parent 10: '
|
||||
elif enable_red:
|
||||
cmds = [ '%s qdisc add dev %s' + parent +
|
||||
cmds += [ '%s qdisc add dev %s' + parent +
|
||||
'handle 10: red limit 1000000 ' +
|
||||
'min 20000 max 25000 avpkt 1000 ' +
|
||||
'min 30000 max 35000 avpkt 1500 ' +
|
||||
'burst 20 ' +
|
||||
'bandwidth %fmbit probability 1' % bw ]
|
||||
parent = ' parent 10: '
|
||||
|
||||
return cmds, parent
|
||||
|
||||
@staticmethod
|
||||
|
||||
+10
-1
@@ -220,6 +220,10 @@ class Mininet( object ):
|
||||
return self.nameToNode[ args[ 0 ] ]
|
||||
return [ self.nameToNode[ n ] for n in args ]
|
||||
|
||||
def get( self, *args ):
|
||||
"Convenience alias for getNodeByName"
|
||||
return self.getNodeByName( *args )
|
||||
|
||||
def addLink( self, node1, node2, port1=None, port2=None,
|
||||
cls=None, **params ):
|
||||
""""Add a link from node1 to node2
|
||||
@@ -240,7 +244,12 @@ class Mininet( object ):
|
||||
"Configure a set of hosts."
|
||||
for host in self.hosts:
|
||||
info( host.name + ' ' )
|
||||
host.configDefault( defaultRoute=host.defaultIntf() )
|
||||
intf = host.defaultIntf()
|
||||
if intf:
|
||||
host.configDefault( defaultRoute=intf )
|
||||
else:
|
||||
# Don't configure nonexistent intf
|
||||
host.configDefault( ip=None, mac=None )
|
||||
# You're low priority, dude!
|
||||
# BL: do we want to do this here or not?
|
||||
# May not make sense if we have CPU lmiting...
|
||||
|
||||
+69
-10
@@ -282,6 +282,43 @@ class Node( object ):
|
||||
cmd: string"""
|
||||
return self.cmd( *args, **{ 'verbose': True } )
|
||||
|
||||
def popen( self, *args, **kwargs ):
|
||||
"""Return a Popen() object in our namespace
|
||||
args: Popen() args, single list, or string
|
||||
kwargs: Popen() keyword args"""
|
||||
defaults = { 'stdout': PIPE, 'stderr': PIPE,
|
||||
'mncmd':
|
||||
[ 'mnexec', '-a', str( self.pid ) ] }
|
||||
defaults.update( kwargs )
|
||||
if len( args ) == 1:
|
||||
if type( args[ 0 ] ) is list:
|
||||
# popen([cmd, arg1, arg2...])
|
||||
cmd = args[ 0 ]
|
||||
elif type( args[ 0 ] ) is str:
|
||||
# popen("cmd arg1 arg2...")
|
||||
cmd = args[ 0 ].split()
|
||||
else:
|
||||
raise Exception( 'popen() requires a string or list' )
|
||||
elif len( args ) > 0:
|
||||
# popen( cmd, arg1, arg2... )
|
||||
cmd = list( args )
|
||||
# Attach to our namespace using mnexec -a
|
||||
mncmd = defaults[ 'mncmd' ]
|
||||
del defaults[ 'mncmd' ]
|
||||
cmd = mncmd + cmd
|
||||
# Shell requires a string, not a list!
|
||||
if defaults.get( 'shell', False ):
|
||||
cmd = ' '.join( cmd )
|
||||
return Popen( cmd, **defaults )
|
||||
|
||||
def pexec( self, *args, **kwargs ):
|
||||
"""Execute a command using popen
|
||||
returns: out, err, exitcode"""
|
||||
popen = self.popen( *args, **kwargs)
|
||||
out, err = popen.communicate()
|
||||
exitcode = popen.wait()
|
||||
return out, err, exitcode
|
||||
|
||||
# Interface management, configuration, and routing
|
||||
|
||||
# BL notes: This might be a bit redundant or over-complicated.
|
||||
@@ -529,6 +566,7 @@ class CPULimitedHost( Host ):
|
||||
# still does better with larger period values.
|
||||
self.period_us = kwargs.get( 'period_us', 100000 )
|
||||
self.sched = sched
|
||||
self.rtprio = 20
|
||||
|
||||
def cgroupSet( self, param, value, resource='cpu' ):
|
||||
"Set a cgroup parameter and return its value"
|
||||
@@ -553,13 +591,24 @@ class CPULimitedHost( Host ):
|
||||
_out, _err, exitcode = errRun( 'cgdelete -r ' + self.cgroup )
|
||||
return exitcode != 0
|
||||
|
||||
def popen( self, *args, **kwargs ):
|
||||
"""Return a Popen() object in node's namespace
|
||||
args: Popen() args, single list, or string
|
||||
kwargs: Popen() keyword args"""
|
||||
# Tell mnexec to execute command in our cgroup
|
||||
mncmd = [ 'mnexec', '-a', str( self.pid ),
|
||||
'-g', self.name ]
|
||||
if self.sched == 'rt':
|
||||
mncmd += [ '-r', str( self.rtprio ) ]
|
||||
return Host.popen( self, *args, mncmd=mncmd, **kwargs )
|
||||
|
||||
def cleanup( self ):
|
||||
"Clean up our cgroup"
|
||||
retry( retries=3, delaySecs=1, fn=self.cgroupDel )
|
||||
|
||||
def chrt( self, prio=20 ):
|
||||
def chrt( self ):
|
||||
"Set RT scheduling priority"
|
||||
quietRun( 'chrt -p %s %s' % ( prio, self.pid ) )
|
||||
quietRun( 'chrt -p %s %s' % ( self.rtprio, self.pid ) )
|
||||
result = quietRun( 'chrt -p %s' % self.pid )
|
||||
firstline = result.split( '\n' )[ 0 ]
|
||||
lastword = firstline.split( ' ' )[ -1 ]
|
||||
@@ -618,7 +667,7 @@ class CPULimitedHost( Host ):
|
||||
self.cgroupSet( qstr, quota )
|
||||
if sched == 'rt':
|
||||
# Set RT priority if necessary
|
||||
self.chrt( prio=20 )
|
||||
self.chrt()
|
||||
info( '(%s %d/%dus) ' % ( sched, quota, period ) )
|
||||
|
||||
def setCPUs( self, cores, mems=0 ):
|
||||
@@ -681,9 +730,10 @@ class Switch( Node ):
|
||||
an OpenFlow switch."""
|
||||
|
||||
portBase = 1 # Switches start with port 1 in OpenFlow
|
||||
dpidLen = 16 # digits in dpid passed to switch
|
||||
|
||||
def __init__( self, name, dpid=None, opts='', listenPort=None, **params):
|
||||
"""dpid: dpid for switch (or None for default)
|
||||
"""dpid: dpid for switch (or None to derive from name, e.g. s1 -> 1)
|
||||
opts: additional switch options
|
||||
listenPort: port to listen on for dpctl connections"""
|
||||
Node.__init__( self, name, **params )
|
||||
@@ -695,10 +745,15 @@ class Switch( Node ):
|
||||
|
||||
def defaultDpid( self ):
|
||||
"Derive dpid from switch name, s1 -> 1"
|
||||
dpid = int( re.findall( '\d+', self.name )[ 0 ] )
|
||||
dpid = hex( dpid )[ 2: ]
|
||||
dpid = '0' * ( 16 - len( dpid ) ) + dpid
|
||||
return dpid
|
||||
try:
|
||||
dpid = int( re.findall( '\d+', self.name )[ 0 ] )
|
||||
dpid = hex( dpid )[ 2: ]
|
||||
dpid = '0' * ( self.dpidLen - len( dpid ) ) + dpid
|
||||
return dpid
|
||||
except IndexError:
|
||||
raise Exception( 'Unable to derive default datapath ID - '
|
||||
'please either specify a dpid or use a '
|
||||
'canonical switch name such as s23.' )
|
||||
|
||||
def defaultIntf( self ):
|
||||
"Return control interface"
|
||||
@@ -727,6 +782,8 @@ class Switch( Node ):
|
||||
class UserSwitch( Switch ):
|
||||
"User-space switch."
|
||||
|
||||
dpidLen = 12
|
||||
|
||||
def __init__( self, name, **kwargs ):
|
||||
"""Init.
|
||||
name: name for the switch"""
|
||||
@@ -885,6 +942,8 @@ class OVSSwitch( Switch ):
|
||||
# Annoyingly, --if-exists option seems not to work
|
||||
self.cmd( 'ovs-vsctl del-br', self )
|
||||
self.cmd( 'ovs-vsctl add-br', self )
|
||||
self.cmd( 'ovs-vsctl -- set Bridge', self,
|
||||
'other_config:datapath-id=' + self.dpid )
|
||||
self.cmd( 'ovs-vsctl set-fail-mode', self, self.failMode )
|
||||
for intf in self.intfList():
|
||||
if not intf.IP():
|
||||
@@ -982,14 +1041,14 @@ class NOX( Controller ):
|
||||
class RemoteController( Controller ):
|
||||
"Controller running outside of Mininet's control."
|
||||
|
||||
def __init__( self, name, defaultIP='127.0.0.1',
|
||||
def __init__( self, name, ip='127.0.0.1',
|
||||
port=6633, **kwargs):
|
||||
"""Init.
|
||||
name: name to give controller
|
||||
defaultIP: the IP address where the remote controller is
|
||||
listening
|
||||
port: the port where the remote controller is listening"""
|
||||
Controller.__init__( self, name, defaultIP=defaultIP, port=port,
|
||||
Controller.__init__( self, name, ip=ip, port=port,
|
||||
**kwargs )
|
||||
|
||||
def start( self ):
|
||||
|
||||
@@ -148,6 +148,11 @@ class Topo(object):
|
||||
src, dst = self.sorted([src, dst])
|
||||
return self.link_info[(src, dst)]
|
||||
|
||||
def setlinkInfo( self, src, dst, info ):
|
||||
"Set link metadata"
|
||||
src, dst = self.sorted([src, dst])
|
||||
self.link_info[(src, dst)] = info
|
||||
|
||||
def nodeInfo( self, name ):
|
||||
"Return metadata (dict) for node"
|
||||
info = self.node_info[ name ]
|
||||
|
||||
+112
-13
@@ -1,11 +1,14 @@
|
||||
"Utility functions for Mininet."
|
||||
|
||||
from mininet.log import output, info, error
|
||||
|
||||
from time import sleep
|
||||
from resource import setrlimit, RLIMIT_NPROC, RLIMIT_NOFILE
|
||||
from select import poll, POLLIN
|
||||
from subprocess import call, check_call, Popen, PIPE, STDOUT
|
||||
from mininet.log import output, info, error
|
||||
import re
|
||||
from fcntl import fcntl, F_GETFL, F_SETFL
|
||||
from os import O_NONBLOCK
|
||||
|
||||
# Command execution support
|
||||
|
||||
@@ -49,7 +52,7 @@ def oldQuietRun( *cmd ):
|
||||
|
||||
|
||||
# This is a bit complicated, but it enables us to
|
||||
# monitor commount output as it is happening
|
||||
# monitor command output as it is happening
|
||||
|
||||
def errRun( *cmd, **kwargs ):
|
||||
"""Run a command and return stdout, stderr and return code
|
||||
@@ -71,31 +74,33 @@ def errRun( *cmd, **kwargs ):
|
||||
# cmd goes to stderr, output goes to stdout
|
||||
info( cmd, '\n' )
|
||||
popen = Popen( cmd, stdout=PIPE, stderr=stderr, shell=shell )
|
||||
# We use poll() because select() doesn't work with large fd numbers
|
||||
# We use poll() because select() doesn't work with large fd numbers,
|
||||
# and thus communicate() doesn't work either
|
||||
out, err = '', ''
|
||||
poller = poll()
|
||||
poller.register( popen.stdout, POLLIN )
|
||||
fdtofile = { popen.stdout.fileno(): popen.stdout }
|
||||
outDone, errDone = False, True
|
||||
if popen.stderr:
|
||||
fdtofile[ popen.stderr.fileno() ] = popen.stderr
|
||||
poller.register( popen.stderr, POLLIN )
|
||||
while True:
|
||||
errDone = False
|
||||
while not outDone or not errDone:
|
||||
readable = poller.poll()
|
||||
# Tell pylint to ignore unused variable event
|
||||
# pylint: disable-msg=W0612
|
||||
for fd, event in readable:
|
||||
# pylint: enable-msg=W0612
|
||||
for fd, _event in readable:
|
||||
f = fdtofile[ fd ]
|
||||
data = f.read( 1024 )
|
||||
if echo:
|
||||
output( data )
|
||||
if f == popen.stdout:
|
||||
out += data
|
||||
if data == '':
|
||||
outDone = True
|
||||
elif f == popen.stderr:
|
||||
err += data
|
||||
returncode = popen.poll()
|
||||
if returncode is not None:
|
||||
break
|
||||
if data == '':
|
||||
errDone = True
|
||||
returncode = popen.wait()
|
||||
return out, err, returncode
|
||||
|
||||
def errFail( *cmd, **kwargs ):
|
||||
@@ -111,7 +116,7 @@ def quietRun( cmd, **kwargs ):
|
||||
return errRun( cmd, stderr=STDOUT, **kwargs )[ 0 ]
|
||||
|
||||
# pylint: enable-msg=E1103
|
||||
# pylint: disable-msg=E1101,W0612
|
||||
# pylint: disable-msg=E1101
|
||||
|
||||
def isShellBuiltin( cmd ):
|
||||
"Return True if cmd is a bash builtin."
|
||||
@@ -124,7 +129,7 @@ def isShellBuiltin( cmd ):
|
||||
|
||||
isShellBuiltin.builtIns = None
|
||||
|
||||
# pylint: enable-msg=E1101,W0612
|
||||
# pylint: enable-msg=E1101
|
||||
|
||||
# Interface management
|
||||
#
|
||||
@@ -300,6 +305,49 @@ def makeNumeric( s ):
|
||||
else:
|
||||
return s
|
||||
|
||||
# Popen support
|
||||
|
||||
def pmonitor(popens, timeoutms=500, readline=True,
|
||||
readmax=1024 ):
|
||||
"""Monitor dict of hosts to popen objects
|
||||
a line at a time
|
||||
timeoutms: timeout for poll()
|
||||
readline: return single line of output
|
||||
yields: host, line/output (if any)
|
||||
terminates: when all EOFs received"""
|
||||
poller = poll()
|
||||
fdToHost = {}
|
||||
for host, popen in popens.iteritems():
|
||||
fd = popen.stdout.fileno()
|
||||
fdToHost[ fd ] = host
|
||||
poller.register( fd, POLLIN )
|
||||
if not readline:
|
||||
# Use non-blocking reads
|
||||
flags = fcntl( fd, F_GETFL )
|
||||
fcntl( fd, F_SETFL, flags | O_NONBLOCK )
|
||||
while True:
|
||||
fds = poller.poll( timeoutms )
|
||||
if fds:
|
||||
for fd, _event in fds:
|
||||
host = fdToHost[ fd ]
|
||||
popen = popens[ host ]
|
||||
if readline:
|
||||
# Attempt to read a line of output
|
||||
# This blocks until we receive a newline!
|
||||
line = popen.stdout.readline()
|
||||
else:
|
||||
line = popen.stdout.read( readmax )
|
||||
yield host, line
|
||||
# Check for EOF
|
||||
if not line:
|
||||
popen.poll()
|
||||
if popen.returncode is not None:
|
||||
poller.unregister( fd )
|
||||
del popens[ host ]
|
||||
if not popens:
|
||||
return
|
||||
else:
|
||||
yield None, ''
|
||||
|
||||
# Other stuff we use
|
||||
|
||||
@@ -352,3 +400,54 @@ def custom( cls, **params ):
|
||||
kwargs.update( params )
|
||||
return cls( *args, **kwargs )
|
||||
return customized
|
||||
|
||||
def splitArgs( argstr ):
|
||||
"""Split argument string into usable python arguments
|
||||
argstr: argument string with format fn,arg2,kw1=arg3...
|
||||
returns: fn, args, kwargs"""
|
||||
split = argstr.split( ',' )
|
||||
fn = split[ 0 ]
|
||||
params = split[ 1: ]
|
||||
# Convert int and float args; removes the need for function
|
||||
# to be flexible with input arg formats.
|
||||
args = [ makeNumeric( s ) for s in params if '=' not in s ]
|
||||
kwargs = {}
|
||||
for s in [ p for p in params if '=' in p ]:
|
||||
key, val = s.split( '=' )
|
||||
kwargs[ key ] = makeNumeric( val )
|
||||
return fn, args, kwargs
|
||||
|
||||
def customConstructor( constructors, argStr ):
|
||||
"""Return custom constructor based on argStr
|
||||
|
||||
The args and key/val pairs in argsStr will be automatically applied
|
||||
when the generated constructor is later used.
|
||||
"""
|
||||
cname, newargs, kwargs = splitArgs( argStr )
|
||||
constructor = constructors.get( cname, None )
|
||||
|
||||
if not constructor:
|
||||
raise Exception( "error: %s is unknown - please specify one of %s" %
|
||||
( cname, constructors.keys() ) )
|
||||
|
||||
def customized( name, *args, **params ):
|
||||
"Customized constructor, useful for Node, Link, and other classes"
|
||||
params.update( kwargs )
|
||||
if not newargs:
|
||||
return constructor( name, *args, **params )
|
||||
if args:
|
||||
warn( 'warning: %s replacing %s with %s\n' % (
|
||||
constructor, args, newargs ) )
|
||||
return constructor( name, *newargs, **params )
|
||||
|
||||
return customized
|
||||
|
||||
def buildTopo( topos, topoStr ):
|
||||
"""Create topology from string with format (object, arg1, arg2,...).
|
||||
|
||||
input topos is a dict of topo names to constructors, possibly w/args.
|
||||
"""
|
||||
topo, args, kwargs = splitArgs( topoStr )
|
||||
if topo not in topos:
|
||||
raise Exception( 'Invalid topo name %s' % topo )
|
||||
return topos[ topo ]( *args, **kwargs )
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
* - detaching from a controlling tty using setsid
|
||||
* - running in a network namespace
|
||||
* - printing out the pid of a process so we can identify it later
|
||||
* - attaching to a namespace and cgroup
|
||||
* - setting RT scheduling
|
||||
*
|
||||
* Partially based on public domain setsid(1)
|
||||
*/
|
||||
@@ -14,23 +16,83 @@
|
||||
#include <stdio.h>
|
||||
#include <linux/sched.h>
|
||||
#include <unistd.h>
|
||||
#include <limits.h>
|
||||
#include <syscall.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
#include <sched.h>
|
||||
|
||||
void usage(char *name)
|
||||
{
|
||||
printf("Execution utility for Mininet.\n"
|
||||
"usage: %s [-cdnp]\n"
|
||||
"usage: %s [-cdnp] [-a pid] [-g group] [-r rtprio] cmd args...\n"
|
||||
"-c: close all file descriptors except stdin/out/error\n"
|
||||
"-d: detach from tty by calling setsid()\n"
|
||||
"-n: run in new network namespace\n"
|
||||
"-p: print ^A + pid\n", name);
|
||||
"-p: print ^A + pid\n"
|
||||
"-a pid: attach to pid's network namespace\n"
|
||||
"-g group: add to cgroup\n"
|
||||
"-r rtprio: run with SCHED_RR (usually requires -g)\n",
|
||||
name);
|
||||
}
|
||||
|
||||
|
||||
int setns(int fd, int nstype)
|
||||
{
|
||||
return syscall(308, fd, nstype);
|
||||
}
|
||||
|
||||
/* Validate alphanumeric path foo1/bar2/baz */
|
||||
void validate(char *path)
|
||||
{
|
||||
char *s;
|
||||
for (s=path; *s; s++) {
|
||||
if (!isalnum(*s) && *s != '/') {
|
||||
fprintf(stderr, "invalid path: %s\n", path);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Add our pid to cgroup */
|
||||
int cgroup(char *gname)
|
||||
{
|
||||
static char path[PATH_MAX];
|
||||
static char *groups[] = {
|
||||
"cpu", "cpuacct", "cpuset", NULL
|
||||
};
|
||||
char **gptr;
|
||||
pid_t pid = getpid();
|
||||
int count = 0;
|
||||
validate(gname);
|
||||
for (gptr = groups; *gptr; gptr++) {
|
||||
FILE *f;
|
||||
snprintf(path, PATH_MAX, "/sys/fs/cgroup/%s/%s/tasks",
|
||||
*gptr, gname);
|
||||
f = fopen(path, "w");
|
||||
if (f) {
|
||||
count++;
|
||||
fprintf(f, "%d\n", pid);
|
||||
fclose(f);
|
||||
}
|
||||
}
|
||||
if (!count) {
|
||||
fprintf(stderr, "cgroup: could not add to cgroup %s\n",
|
||||
gname);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
char c;
|
||||
int fd;
|
||||
|
||||
while ((c = getopt(argc, argv, "+cdnp")) != -1)
|
||||
char path[PATH_MAX];
|
||||
int nsid;
|
||||
int pid;
|
||||
static struct sched_param sp;
|
||||
while ((c = getopt(argc, argv, "+cdnpa:g:r:")) != -1)
|
||||
switch(c) {
|
||||
case 'c':
|
||||
/* close file descriptors except stdin/out/error */
|
||||
@@ -64,16 +126,42 @@ int main(int argc, char *argv[])
|
||||
printf("\001%d\n", getpid());
|
||||
fflush(stdout);
|
||||
break;
|
||||
case 'a':
|
||||
/* Attach to pid's network namespace */
|
||||
pid = atoi(optarg);
|
||||
sprintf(path, "/proc/%d/ns/net", pid );
|
||||
nsid = open(path, O_RDONLY);
|
||||
if (nsid < 0) {
|
||||
perror(path);
|
||||
return 1;
|
||||
}
|
||||
if (setns(nsid, 0) != 0) {
|
||||
perror("setns");
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
case 'g':
|
||||
/* Attach to cgroup */
|
||||
cgroup(optarg);
|
||||
break;
|
||||
case 'r':
|
||||
/* Set RT scheduling priority */
|
||||
sp.sched_priority = atoi(optarg);
|
||||
if (sched_setscheduler(getpid(), SCHED_RR, &sp) < 0) {
|
||||
perror("sched_setscheduler");
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
usage(argv[0]);
|
||||
break;
|
||||
}
|
||||
|
||||
if (optind < argc) {
|
||||
execvp(argv[optind], &argv[optind]);
|
||||
perror(argv[optind]);
|
||||
return 1;
|
||||
}
|
||||
execvp(argv[optind], &argv[optind]);
|
||||
perror(argv[optind]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
usage(argv[0]);
|
||||
}
|
||||
|
||||
+31
-17
@@ -189,7 +189,7 @@ function wireshark {
|
||||
sudo apt-get install -y scons mercurial libglib2.0-dev
|
||||
sudo apt-get install -y libwiretap-dev libwireshark-dev
|
||||
cd ~
|
||||
hg clone https://bitbucket.org/onlab/of-dissector
|
||||
hg clone https://bitbucket.org/barnstorm/of-dissector
|
||||
cd of-dissector/src
|
||||
export WIRESHARK=/usr/include/wireshark
|
||||
scons
|
||||
@@ -213,16 +213,19 @@ function wireshark {
|
||||
|
||||
# Install Open vSwitch
|
||||
# Instructions derived from OVS INSTALL, INSTALL.OpenFlow and README files.
|
||||
|
||||
function ovs {
|
||||
echo "Installing Open vSwitch..."
|
||||
|
||||
# Required for module build/dkms install
|
||||
$install $KERNEL_HEADERS
|
||||
|
||||
ovspresent=0
|
||||
|
||||
# First see if we have packages
|
||||
# XXX wget -c seems to fail from github/amazon s3
|
||||
cd /tmp
|
||||
if wget $OVS_PACKAGE_LOC/$OVS_PACKAGE_NAME; then
|
||||
if wget $OVS_PACKAGE_LOC/$OVS_PACKAGE_NAME 2> /dev/null; then
|
||||
$install patch dkms fakeroot python-argparse
|
||||
tar xf $OVS_PACKAGE_NAME
|
||||
orig=`tar tf $OVS_PACKAGE_NAME`
|
||||
@@ -234,21 +237,11 @@ function ovs {
|
||||
# Annoyingly, things seem to be missing without this flag
|
||||
$pkginst --force-confmiss $pkg
|
||||
done
|
||||
# Switch can run on its own, but
|
||||
# Mininet should control the controller
|
||||
if [ -e /etc/init.d/openvswitch-controller ]; then
|
||||
if sudo service openvswitch-controller stop; then
|
||||
echo "Stopped running controller"
|
||||
fi
|
||||
sudo update-rc.d openvswitch-controller disable
|
||||
fi
|
||||
echo "Done (hopefully) installing packages"
|
||||
cd ~
|
||||
return
|
||||
ovspresent=1
|
||||
fi
|
||||
|
||||
# Otherwise try distribution's OVS packages
|
||||
if [ "$DIST" = "Ubuntu" ] && [ `echo "$RELEASE >= 11.10" | bc` = 1 ]; then
|
||||
if [ "$DIST" = "Ubuntu" ] && [ `expr $RELEASE '>=' 11.10` = 1 ]; then
|
||||
if ! dpkg --get-selections | grep openvswitch-datapath; then
|
||||
# If you've already installed a datapath, assume you
|
||||
# know what you're doing and don't need dkms datapath.
|
||||
@@ -256,10 +249,28 @@ function ovs {
|
||||
$install openvswitch-datapath-dkms
|
||||
fi
|
||||
if $install openvswitch-switch openvswitch-controller; then
|
||||
return
|
||||
echo "Ignoring error installing openvswitch-controller"
|
||||
fi
|
||||
ovspresent=1
|
||||
fi
|
||||
|
||||
# Switch can run on its own, but
|
||||
# Mininet should control the controller
|
||||
if [ -e /etc/init.d/openvswitch-controller ]; then
|
||||
if sudo service openvswitch-controller stop; then
|
||||
echo "Stopped running controller"
|
||||
fi
|
||||
sudo update-rc.d openvswitch-controller disable
|
||||
fi
|
||||
|
||||
if [ $ovspresent = 1 ]; then
|
||||
echo "Done (hopefully) installing packages"
|
||||
cd ~
|
||||
return
|
||||
fi
|
||||
|
||||
# Otherwise attempt to install from source
|
||||
|
||||
$install pkg-config gcc make python-dev libssl-dev libtool
|
||||
|
||||
if [ "$DIST" = "Debian" ]; then
|
||||
@@ -343,7 +354,10 @@ function nox {
|
||||
|
||||
# Apply patches
|
||||
git checkout -b tutorial-destiny
|
||||
git am ~/mininet/util/nox-patches/*.patch
|
||||
git am ~/mininet/util/nox-patches/*tutorial-port-nox-destiny*.patch
|
||||
if [ "$DIST" = "Ubuntu" ] && [ `expr $RELEASE '>=' 12.04` = 1 ]; then
|
||||
git am ~/mininet/util/nox-patches/*nox-ubuntu12-hacks.patch
|
||||
fi
|
||||
|
||||
# Build
|
||||
./boot.sh
|
||||
@@ -380,7 +394,7 @@ function oftest {
|
||||
function cbench {
|
||||
echo "Installing cbench..."
|
||||
|
||||
$install libsnmp-dev libpcap-dev
|
||||
$install libsnmp-dev libpcap-dev libconfig-dev
|
||||
cd ~/
|
||||
git clone git://openflow.org/oflops.git
|
||||
cd oflops
|
||||
|
||||
@@ -0,0 +1,175 @@
|
||||
From 166693d7cb640d4a41251b87e92c52d9c688196b Mon Sep 17 00:00:00 2001
|
||||
From: Bob Lantz <rlantz@cs.stanford.edu>
|
||||
Date: Mon, 14 May 2012 15:30:44 -0700
|
||||
Subject: [PATCH] Hacks to get NOX classic/destiny to compile under Ubuntu
|
||||
12.04
|
||||
|
||||
Thanks to Srinivasu R. Kanduru for the initial patch.
|
||||
|
||||
Apologies for the hacks - it is my hope that this will be fixed
|
||||
upstream eventually.
|
||||
|
||||
---
|
||||
config/ac_pkg_swig.m4 | 7 ++++---
|
||||
src/Make.vars | 2 +-
|
||||
src/nox/coreapps/pyrt/deferredcallback.cc | 2 +-
|
||||
src/nox/coreapps/pyrt/pyglue.cc | 2 +-
|
||||
src/nox/coreapps/pyrt/pyrt.cc | 2 +-
|
||||
src/nox/netapps/authenticator/auth.i | 2 ++
|
||||
src/nox/netapps/authenticator/flow_util.i | 1 +
|
||||
src/nox/netapps/routing/routing.i | 2 ++
|
||||
.../switch_management/pyswitch_management.i | 2 ++
|
||||
src/nox/netapps/tests/tests.cc | 2 +-
|
||||
src/nox/netapps/topology/pytopology.i | 2 ++
|
||||
11 files changed, 18 insertions(+), 8 deletions(-)
|
||||
|
||||
diff --git a/config/ac_pkg_swig.m4 b/config/ac_pkg_swig.m4
|
||||
index d12556e..9b608f2 100644
|
||||
--- a/config/ac_pkg_swig.m4
|
||||
+++ b/config/ac_pkg_swig.m4
|
||||
@@ -78,9 +78,10 @@ AC_DEFUN([AC_PROG_SWIG],[
|
||||
if test -z "$available_patch" ; then
|
||||
[available_patch=0]
|
||||
fi
|
||||
- if test $available_major -ne $required_major \
|
||||
- -o $available_minor -ne $required_minor \
|
||||
- -o $available_patch -lt $required_patch ; then
|
||||
+ major_done=`test $available_major -gt $required_major`
|
||||
+ minor_done=`test $available_minor -gt $required_minor`
|
||||
+ if test !$major_done -a !$minor_done \
|
||||
+ -a $available_patch -lt $required_patch ; then
|
||||
AC_MSG_WARN([SWIG version >= $1 is required. You have $swig_version. You should look at http://www.swig.org])
|
||||
SWIG=''
|
||||
else
|
||||
diff --git a/src/Make.vars b/src/Make.vars
|
||||
index d70d6aa..93b2879 100644
|
||||
--- a/src/Make.vars
|
||||
+++ b/src/Make.vars
|
||||
@@ -53,7 +53,7 @@ AM_LDFLAGS += -export-dynamic
|
||||
endif
|
||||
|
||||
# set python runtimefiles to be installed in the same directory as pkg
|
||||
-pkglib_SCRIPTS = $(NOX_RUNTIMEFILES) $(NOX_PYBUILDFILES)
|
||||
+pkgdata_SCRIPTS = $(NOX_RUNTIMEFILES) $(NOX_PYBUILDFILES)
|
||||
BUILT_SOURCES = $(NOX_PYBUILDFILES)
|
||||
|
||||
# Runtime-files build and clean rules
|
||||
diff --git a/src/nox/coreapps/pyrt/deferredcallback.cc b/src/nox/coreapps/pyrt/deferredcallback.cc
|
||||
index 3a40fa7..111a586 100644
|
||||
--- a/src/nox/coreapps/pyrt/deferredcallback.cc
|
||||
+++ b/src/nox/coreapps/pyrt/deferredcallback.cc
|
||||
@@ -69,7 +69,7 @@ DeferredCallback::get_instance(const Callback& c)
|
||||
DeferredCallback* cb = new DeferredCallback(c);
|
||||
|
||||
// flag as used in *_wrap.cc....correct?
|
||||
- return SWIG_Python_NewPointerObj(cb, s, SWIG_POINTER_OWN | 0);
|
||||
+ return SWIG_Python_NewPointerObj(m, cb, s, SWIG_POINTER_OWN | 0);
|
||||
}
|
||||
|
||||
bool
|
||||
diff --git a/src/nox/coreapps/pyrt/pyglue.cc b/src/nox/coreapps/pyrt/pyglue.cc
|
||||
index 48b9716..317fd04 100644
|
||||
--- a/src/nox/coreapps/pyrt/pyglue.cc
|
||||
+++ b/src/nox/coreapps/pyrt/pyglue.cc
|
||||
@@ -874,7 +874,7 @@ to_python(const Flow& flow)
|
||||
if (!s) {
|
||||
throw std::runtime_error("Could not find Flow SWIG type_info");
|
||||
}
|
||||
- return SWIG_Python_NewPointerObj(f, s, SWIG_POINTER_OWN | 0);
|
||||
+ return SWIG_Python_NewPointerObj(m, f, s, SWIG_POINTER_OWN | 0);
|
||||
|
||||
// PyObject* dict = PyDict_New();
|
||||
// if (!dict) {
|
||||
diff --git a/src/nox/coreapps/pyrt/pyrt.cc b/src/nox/coreapps/pyrt/pyrt.cc
|
||||
index fbda461..8ec05d6 100644
|
||||
--- a/src/nox/coreapps/pyrt/pyrt.cc
|
||||
+++ b/src/nox/coreapps/pyrt/pyrt.cc
|
||||
@@ -776,7 +776,7 @@ Python_event_manager::create_python_context(const Context* ctxt,
|
||||
pretty_print_python_exception());
|
||||
}
|
||||
|
||||
- PyObject* pyctxt = SWIG_Python_NewPointerObj(p, s, 0);
|
||||
+ PyObject* pyctxt = SWIG_Python_NewPointerObj(m, p, s, 0);
|
||||
Py_INCREF(pyctxt); // XXX needed?
|
||||
|
||||
//Py_DECREF(m);
|
||||
diff --git a/src/nox/netapps/authenticator/auth.i b/src/nox/netapps/authenticator/auth.i
|
||||
index 1de1a17..bfa04e2 100644
|
||||
--- a/src/nox/netapps/authenticator/auth.i
|
||||
+++ b/src/nox/netapps/authenticator/auth.i
|
||||
@@ -18,6 +18,8 @@
|
||||
|
||||
%module "nox.netapps.authenticator.pyauth"
|
||||
|
||||
+// Hack to get it to compile -BL
|
||||
+%include "std_list.i"
|
||||
%{
|
||||
#include "core_events.hh"
|
||||
#include "pyrt/pycontext.hh"
|
||||
diff --git a/src/nox/netapps/authenticator/flow_util.i b/src/nox/netapps/authenticator/flow_util.i
|
||||
index f67c3ef..2a314e2 100644
|
||||
--- a/src/nox/netapps/authenticator/flow_util.i
|
||||
+++ b/src/nox/netapps/authenticator/flow_util.i
|
||||
@@ -32,6 +32,7 @@ using namespace vigil::applications;
|
||||
%}
|
||||
|
||||
%include "common-defs.i"
|
||||
+%include "std_list.i"
|
||||
|
||||
%import "netinet/netinet.i"
|
||||
%import "pyrt/event.i"
|
||||
diff --git a/src/nox/netapps/routing/routing.i b/src/nox/netapps/routing/routing.i
|
||||
index 44ccb3d..f9221a2 100644
|
||||
--- a/src/nox/netapps/routing/routing.i
|
||||
+++ b/src/nox/netapps/routing/routing.i
|
||||
@@ -17,6 +17,8 @@
|
||||
*/
|
||||
%module "nox.netapps.routing.pyrouting"
|
||||
|
||||
+// Hack to get it to compile -BL
|
||||
+%include "std_list.i"
|
||||
%{
|
||||
#include "pyrouting.hh"
|
||||
#include "routing.hh"
|
||||
diff --git a/src/nox/netapps/switch_management/pyswitch_management.i b/src/nox/netapps/switch_management/pyswitch_management.i
|
||||
index 72bfed4..ad2c90d 100644
|
||||
--- a/src/nox/netapps/switch_management/pyswitch_management.i
|
||||
+++ b/src/nox/netapps/switch_management/pyswitch_management.i
|
||||
@@ -18,6 +18,8 @@
|
||||
|
||||
%module "nox.netapps.pyswitch_management"
|
||||
|
||||
+// Hack to get it to compile -BL
|
||||
+%include "std_list.i"
|
||||
%{
|
||||
#include "switch_management_proxy.hh"
|
||||
#include "pyrt/pycontext.hh"
|
||||
diff --git a/src/nox/netapps/tests/tests.cc b/src/nox/netapps/tests/tests.cc
|
||||
index 20e900d..f027028 100644
|
||||
--- a/src/nox/netapps/tests/tests.cc
|
||||
+++ b/src/nox/netapps/tests/tests.cc
|
||||
@@ -306,7 +306,7 @@ private:
|
||||
throw runtime_error("Could not find PyContext SWIG type_info.");
|
||||
}
|
||||
|
||||
- PyObject* pyctxt = SWIG_Python_NewPointerObj(p, s, 0);
|
||||
+ PyObject* pyctxt = SWIG_Python_NewPointerObj(m, p, s, 0);
|
||||
assert(pyctxt);
|
||||
|
||||
Py_DECREF(m);
|
||||
diff --git a/src/nox/netapps/topology/pytopology.i b/src/nox/netapps/topology/pytopology.i
|
||||
index 94a9f4b..7a8cd94 100644
|
||||
--- a/src/nox/netapps/topology/pytopology.i
|
||||
+++ b/src/nox/netapps/topology/pytopology.i
|
||||
@@ -18,6 +18,8 @@
|
||||
|
||||
%module "nox.netapps.topology"
|
||||
|
||||
+// Hack to get it to compile -BL
|
||||
+%include "std_list.i"
|
||||
%{
|
||||
#include "pytopology.hh"
|
||||
#include "pyrt/pycontext.hh"
|
||||
--
|
||||
1.7.5.4
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
This patch adds the OpenFlow tutorial module source code to nox-destiny.
|
||||
0001: This patch adds the OpenFlow tutorial module source code to nox-destiny.
|
||||
0002: This patch hacks nox-destiny to compile on Ubuntu 12.04.
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
obj-m = sch_htb.o
|
||||
KVERSION = $(shell uname -r)
|
||||
all:
|
||||
make -C /lib/modules/$(KVERSION)/build M=$(PWD) modules
|
||||
install:
|
||||
test -e /lib/modules/$(KVERSION)/kernel/net/sched/sch_htb.ko.bak || mv /lib/modules/$(KVERSION)/kernel/net/sched/sch_htb.ko /lib/modules/$(KVERSION)/kernel/net/sched/sch_htb.ko.bak
|
||||
cp sch_htb.ko /lib/modules/$(KVERSION)/kernel/net/sched/sch_htb.ko
|
||||
rmmod sch_htb
|
||||
modprobe sch_htb
|
||||
clean:
|
||||
make -C /lib/modules/$(KVERSION)/build M=$(PWD) clean
|
||||
@@ -0,0 +1,10 @@
|
||||
Modified sch_htb implementation with ofbuf support.
|
||||
|
||||
To compile, just type make. To use this module instead
|
||||
of regular sch_htb, do:
|
||||
|
||||
0. make
|
||||
1. rmmod sch_htb
|
||||
2. insmod ./sch_htb.ko
|
||||
|
||||
To revert, just rmmod sch_htb.
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user