diff --git a/bin/mn b/bin/mn index bba2353b7898412b0cc6e3e3732b883f087e94ca..5e1c2e90cba3ddbaa969a815d7a7f03b8f2d9211 100755 --- a/bin/mn +++ b/bin/mn @@ -26,7 +26,7 @@ from mininet.log import lg, LEVELS, info from mininet.net import Mininet, MininetWithControlNet, VERSION from mininet.node import ( Host, CPULimitedHost, Controller, OVSController, NOX, RemoteController, UserSwitch, OVSKernelSwitch, - OVSLegacyKernelSwitch ) + OVSLegacyKernelSwitch, IVSSwitch ) from mininet.link import Link, TCLink from mininet.topo import SingleSwitchTopo, LinearTopo, SingleSwitchReversedTopo from mininet.topolib import TreeTopo @@ -45,7 +45,8 @@ TOPOS = { 'minimal': lambda: SingleSwitchTopo( k=2 ), SWITCHDEF = 'ovsk' SWITCHES = { 'user': UserSwitch, 'ovsk': OVSKernelSwitch, - 'ovsl': OVSLegacyKernelSwitch } + 'ovsl': OVSLegacyKernelSwitch, + 'ivs': IVSSwitch } HOSTDEF = 'proc' HOSTS = { 'proc': Host, diff --git a/mininet/node.py b/mininet/node.py index d6a66ba24ebbf9f14b53f40aec58b2070a57afbb..edb46de04cb952206f203e11a77f52fd77c7e3ea 100644 --- a/mininet/node.py +++ b/mininet/node.py @@ -1018,6 +1018,71 @@ def stop( self ): OVSKernelSwitch = OVSSwitch +class IVSSwitch(Switch): + """IVS virtual switch + Currently only works in the root namespace. + """ + + def __init__( self, name, **kwargs ): + Switch.__init__( self, name, **kwargs ) + self.process = None + if self.inNamespace: + error( "IVSSwitch currently only works" + " in the root namespace.\n" ) + exit( 1 ) + + @classmethod + def setup( cls ): + "Make sure IVS is installed" + pathCheck( 'ivs-ctl', 'ivs', + moduleName="Indigo Virtual Switch (projectfloodlight.org)" ) + out, err, exitcode = errRun( 'ivs-ctl show' ) + if exitcode: + error( out + err + + 'ivs-ctl exited with code %d\n' % exitcode + + '*** The openvswitch kernel module might ' + 'not be loaded. Try modprobe openvswitch.\n' ) + exit( 1 ) + + def start( self, controllers ): + "Start up a new IVS switch" + args = ['ivs'] + args.extend( ['--name', self.name] ) + args.extend( ['--dpid', self.dpid] ) + args.extend( ['--verbose'] ) + for intf in self.intfs.values(): + if not intf.IP(): + args.extend( ['-i', intf.name] ) + for c in controllers: + args.extend( ['-c', '%s:%d' % (c.IP(), c.port)] ) + + with open( '/tmp/ivs.%s.log' % self.name, 'w' ) as logfile: + with open( '/dev/null', 'w' ) as nullfile: + self.process = Popen( args, stdout=logfile, stderr=STDOUT, + stdin=nullfile, preexec_fn=os.setsid ) + self.execed = False + + def stop( self ): + "Terminate IVS switch." + if self.process: + self.process.terminate() + self.process.wait() + self.process = None + self.deleteIntfs() + + def attach( self, intf ): + "Connect a data port" + self.cmd( 'ivs-ctl', 'add-port', '--datapath', self.name, intf ) + + def detach( self, intf ): + "Disconnect a data port" + self.cmd( 'ivs-ctl', 'del-port', '--datapath', self.name, intf ) + + def dpctl( self, *args ): + "Run dpctl command" + return "dpctl not supported\n" or args or self # satisfy pylint + + class Controller( Node ): """A Controller is a Node that is running (or has execed?) an OpenFlow controller."""