5454from mininet .util import quietRun , errRun , errFail , moveIntf , isShellBuiltin
5555from mininet .util import numCores
5656from mininet .moduledeps import moduleDeps , pathCheck , OVS_KMOD , OF_KMOD , TUN
57- from mininet .link import Link
57+ from mininet .link import Link , Intf
5858
5959class Node ( object ):
6060 """A virtual network node is simply a shell in a network namespace.
@@ -316,16 +316,19 @@ def intf( self, intf='' ):
316316 else :
317317 return intf
318318
319- def linksTo ( self , node ):
320- "Return [ link1, link2 ...] for all links from self to node."
319+ def connectionsTo ( self , node ):
320+ "Return [ intf1, intf2 ... ] for all intfs that connect self to node."
321321 # We could optimize this if it is important
322- links = []
323- for intf in self .intfs :
322+ connections = []
323+ for intf in self .intfList () :
324324 link = intf .link
325- nodes = ( link .intf1 .node , link .intf2 .node )
326- if self in nodes and node in nodes :
327- links .append ( link )
328- return links
325+ if link :
326+ node1 , node2 = link .intf1 .node , link .intf2 .node
327+ if node1 == self and node2 == node :
328+ connections += [ ( intf , link .intf2 ) ]
329+ elif node1 == node and node2 == self :
330+ connections += [ ( intf , link .intf1 ) ]
331+ return connections
329332
330333 def deleteIntfs ( self ):
331334 "Delete all of our interfaces."
@@ -418,8 +421,8 @@ def setParam( self, results, method, **param ):
418421 results [ name ] = result
419422 return result
420423
421- def config ( self , mac = None , ip = None , ifconfig = None ,
422- defaultRoute = None , ** _params ):
424+ def config ( self , mac = None , ip = None ,
425+ defaultRoute = None , lo = 'up' , ** _params ):
423426 """Configure Node according to (optional) parameters:
424427 mac: MAC address for default interface
425428 ip: IP address for default interface
@@ -432,8 +435,9 @@ def config( self, mac=None, ip=None, ifconfig=None,
432435 r = {}
433436 self .setParam ( r , 'setMAC' , mac = mac )
434437 self .setParam ( r , 'setIP' , ip = ip )
435- self .setParam ( r , 'ifconfig' , ifconfig = ifconfig )
436438 self .setParam ( r , 'defaultRoute' , defaultRoute = defaultRoute )
439+ # This should be examined
440+ self .cmd ( 'ifconfig lo ' + lo )
437441 return r
438442
439443 def configDefault ( self , ** moreParams ):
@@ -457,9 +461,16 @@ def intfNames( self ):
457461 "The names of our interfaces sorted by port number"
458462 return [ str ( i ) for i in self .intfList () ]
459463
464+ def __repr__ ( self ):
465+ "More informative string representation"
466+ intfs = ( ',' .join ( [ '%s:%s' % ( i .name , i .IP () )
467+ for i in self .intfList () ] ) )
468+ return '<%s %s: %s pid=%s> ' % (
469+ self .__class__ .__name__ , self .name , intfs , self .pid )
470+
460471 def __str__ ( self ):
461- return '%s: IP=%s intfs=%s pid=%s' % (
462- self .name , self . IP (), ',' . join ( self . intfNames () ), self . pid )
472+ "Abbreviated string representation"
473+ return self .name
463474
464475 # Automatic class setup support
465476
@@ -634,9 +645,8 @@ def __init__( self, name, dpid=None, opts='', listenPort=None, **params):
634645 self .dpid = dpid if dpid else self .defaultDpid ()
635646 self .opts = opts
636647 self .listenPort = listenPort
637- if self .listenPort :
638- self .opts += ' --listen=ptcp:%i ' % self .listenPort
639- self .controlIntf = None
648+ if not self .inNamespace :
649+ self .controlIntf = Intf ( 'lo' , self )
640650
641651 def defaultDpid ( self ):
642652 "Derive dpid from switch name, s1 -> 1"
@@ -646,11 +656,11 @@ def defaultDpid( self ):
646656 return dpid
647657
648658 def defaultIntf ( self ):
649- "Return control interface, if any "
650- if not self .inNamespace :
651- error ( "error: tried to access control interface of "
652- " switch %s in root namespace" % self . name )
653- return self . controlIntf
659+ "Return control interface"
660+ if self .controlIntf :
661+ return self . controlIntf
662+ else :
663+ return Node . defaultIntf ( self )
654664
655665 def sendCmd ( self , * cmd , ** kwargs ):
656666 """Send command to Node.
@@ -662,6 +672,13 @@ def sendCmd( self, *cmd, **kwargs ):
662672 error ( '*** Error: %s has execed and cannot accept commands' %
663673 self .name )
664674
675+ def __repr__ ( self ):
676+ "More informative string representation"
677+ intfs = ( ',' .join ( [ '%s:%s' % ( i .name , i .IP () )
678+ for i in self .intfList () ] ) )
679+ return '<%s %s: %s pid=%s> ' % (
680+ self .__class__ .__name__ , self .name , intfs , self .pid )
681+
665682class UserSwitch ( Switch ):
666683 "User-space switch."
667684
@@ -671,13 +688,22 @@ def __init__( self, name, **kwargs ):
671688 Switch .__init__ ( self , name , ** kwargs )
672689 pathCheck ( 'ofdatapath' , 'ofprotocol' ,
673690 moduleName = 'the OpenFlow reference user switch (openflow.org)' )
691+ if self .listenPort :
692+ self .opts += ' --listen=ptcp:%i ' % self .listenPort
674693
675694 @classmethod
676695 def setup ( cls ):
677696 "Ensure any dependencies are loaded; if not, try to load them."
678697 if not os .path .exists ( '/dev/net/tun' ):
679698 moduleDeps ( add = TUN )
680699
700+ def dpctl ( self , * args ):
701+ "Run dpctl command"
702+ if not self .listenPort :
703+ return "can't run dpctl w/no passive listening port"
704+ return self .cmdPrint ( 'dpctl ' + ' ' .join ( args ) +
705+ ' tcp:127.0.0.1:%i' % self .listenPort )
706+
681707 def start ( self , controllers ):
682708 """Start OpenFlow reference user datapath.
683709 Log to /tmp/sN-{ofd,ofp}.log.
@@ -736,7 +762,7 @@ def start( self, controllers ):
736762 quietRun ( 'ifconfig lo up' )
737763 # Delete local datapath if it exists;
738764 # then create a new one monitoring the given interfaces
739- quietRun ( 'ovs-dpctl del-dp ' + self .dp )
765+ self . cmd ( 'ovs-dpctl del-dp ' + self .dp )
740766 self .cmd ( 'ovs-dpctl add-dp ' + self .dp )
741767 ports = sorted ( self .ports .values () )
742768 if len ( ports ) != ports [ - 1 ] + 1 - self .portBase :
@@ -768,15 +794,6 @@ def __init__( self, name, **params ):
768794 name: name for switch
769795 defaultMAC: default MAC as unsigned int; random value if None"""
770796 Switch .__init__ ( self , name , ** params )
771- # self.dp is the text name for the datapath that
772- # we use for ovs-vsctl. This is different from the
773- # dpid, which is a 64-bit numerical value used by
774- # the openflow protocol.
775- self .dp = name
776- if self .inNamespace :
777- error ( "OVSSwitch currently only works"
778- " in the root namespace.\n " )
779- exit ( 1 )
780797
781798 @classmethod
782799 def setup ( cls ):
@@ -796,32 +813,47 @@ def setup( cls ):
796813 '"service openvswitch-switch start".\n ' )
797814 exit ( 1 )
798815
816+ def dpctl ( self , * args ):
817+ "Run ovs-dpctl command"
818+ return self .cmd ( 'ovs-dpctl' , args [ 0 ], self , * args [ 1 : ] )
819+
820+ def attach ( self , intf ):
821+ "Connect a data port"
822+ self .cmd ( 'ovs-vsctl add-port' , self , intf )
823+ self .cmd ( 'ifconfig' , intf , 'up' )
824+
825+ def detach ( self , intf ):
826+ "Disconnect a data port"
827+ self .cmd ( 'ovs-vsctl del-port' , self , intf )
828+
799829 def start ( self , controllers ):
800830 "Start up a new OVS OpenFlow switch using ovs-vsctl"
801831 if self .inNamespace :
802- raise Exception (
832+ raise Exception (
803833 'OVS kernel switch does not work in a namespace' )
834+ # We should probably call config instead, but this
835+ # requires some rethinking...
836+ self .cmd ( 'ifconfig lo up' )
804837 # Annoyingly, --if-exists option seems not to work
805- self .cmd ( 'ovs-vsctl del-br ' , self .dp )
806- self .cmd ( 'ovs-vsctl add-br' , self .dp )
807- self .cmd ( 'ovs-vsctl set-fail-mode' , self .dp , 'secure' )
808- ports = sorted ( self .ports .values () )
809- intfs = [ self .intfs [ port ] for port in ports ]
838+ self .cmd ( 'ovs-vsctl del-br' , self )
839+ self .cmd ( 'ovs-vsctl add-br' , self )
840+ self .cmd ( 'ovs-vsctl set-fail-mode' , self , 'secure' )
810841 # XXX: Ugly check - we should probably fix this!
842+ ports = sorted ( self .ports .values () )
811843 if ports and ( len ( ports ) != ports [ - 1 ] + 1 - self .portBase ):
812844 raise Exception ( 'only contiguous, one-indexed port ranges '
813845 'supported: %s' % self .intfs )
814- for intf in intfs :
815- self . cmd ( 'ovs-vsctl add-port' , self . dp , intf )
816- self .cmd ( 'ifconfig' , intf , 'up' )
846+ for intf in self . intfList () :
847+ if not intf . IP ():
848+ self .attach ( intf )
817849 # Add controllers
818850 clist = ',' .join ( [ 'tcp:%s:%d' % ( c .IP (), c .port )
819851 for c in controllers ] )
820- self .cmd ( 'ovs-vsctl set-controller' , self . dp , clist )
852+ self .cmd ( 'ovs-vsctl set-controller' , self , clist )
821853
822854 def stop ( self ):
823855 "Terminate OVS switch."
824- self .cmd ( 'ovs-vsctl del-br' , self . dp )
856+ self .cmd ( 'ovs-vsctl del-br' , self )
825857
826858OVSKernelSwitch = OVSSwitch
827859
@@ -865,6 +897,12 @@ def IP( self, intf=None ):
865897 ip = self .ip
866898 return ip
867899
900+ def __repr__ ( self ):
901+ "More informative string representation"
902+ return '<%s %s: %s:%s pid=%s> ' % (
903+ self .__class__ .__name__ , self .name ,
904+ self .IP (), self .port , self .pid )
905+
868906
869907class OVSController ( Controller ):
870908 "Open vSwitch controller"
0 commit comments