mininet / examples / mobility.py @ 13bdd914
History | View | Annotate | Download (4.68 KB)
1 |
#!/usr/bin/python
|
---|---|
2 |
|
3 |
"""
|
4 |
Simple example of Mobility with Mininet
|
5 |
(aka enough rope to hang yourself.)
|
6 |
|
7 |
We move a host from s1 to s2, s2 to s3, and then back to s1.
|
8 |
|
9 |
Gotchas:
|
10 |
|
11 |
The reference controller doesn't support mobility, so we need to
|
12 |
manually flush the switch flow tables!
|
13 |
|
14 |
Good luck!
|
15 |
|
16 |
to-do:
|
17 |
|
18 |
- think about wifi/hub behavior
|
19 |
- think about clearing last hop - why doesn't that work?
|
20 |
"""
|
21 |
|
22 |
from mininet.net import Mininet |
23 |
from mininet.node import OVSSwitch |
24 |
from mininet.topo import LinearTopo |
25 |
from mininet.util import quietRun |
26 |
from mininet.log import output, warn |
27 |
|
28 |
from random import randint |
29 |
from re import findall |
30 |
from distutils.version import StrictVersion |
31 |
|
32 |
class MobilitySwitch( OVSSwitch ): |
33 |
"Switch that can reattach and rename interfaces"
|
34 |
|
35 |
@classmethod
|
36 |
def setup( cls ): |
37 |
"Call our parent method and determine OVS version"
|
38 |
OVSSwitch.setup() |
39 |
info = quietRun( 'ovs-vsctl --version' )
|
40 |
cls.OVSVersion = findall( '\d+\.\d+', info )[ 0 ] |
41 |
if cls.isOldOVS():
|
42 |
warn( 'WARNING: port selection may not work '
|
43 |
' with OVS ', cls.OVSVersion )
|
44 |
|
45 |
@classmethod
|
46 |
def isOldOVS( cls ): |
47 |
return ( StrictVersion( cls.OVSVersion ) <
|
48 |
StrictVersion( '1.10' ) )
|
49 |
|
50 |
def delIntf( self, intf ): |
51 |
"Remove (and detach) an interface"
|
52 |
port = self.ports[ intf ]
|
53 |
del self.ports[ intf ] |
54 |
del self.intfs[ port ] |
55 |
del self.nameToIntf[ intf.name ] |
56 |
|
57 |
def addIntf( self, intf, rename=False, **kwargs ): |
58 |
"Add (and reparent) an interface"
|
59 |
OVSSwitch.addIntf( self, intf, **kwargs )
|
60 |
intf.node = self
|
61 |
if rename:
|
62 |
self.renameIntf( intf )
|
63 |
|
64 |
def attach( self, intf ): |
65 |
"Attach an interface and set its port"
|
66 |
port = self.ports[ intf ]
|
67 |
if port:
|
68 |
if self.isOldOVS(): |
69 |
self.cmd( 'ovs-vsctl add-port', self, intf ) |
70 |
else:
|
71 |
self.cmd( 'ovs-vsctl add-port', self, intf, |
72 |
'-- set Interface', intf,
|
73 |
'ofport_request=%s' % port )
|
74 |
self.validatePort( intf )
|
75 |
|
76 |
def validatePort( self, intf ): |
77 |
"Validate intf's OF port number"
|
78 |
ofport = int( self.cmd( 'ovs-vsctl get Interface', intf, |
79 |
'ofport' ) )
|
80 |
if ofport != self.ports[ intf ]: |
81 |
warn( 'WARNING: ofport for', intf, 'is actually', ofport, |
82 |
'\n' )
|
83 |
|
84 |
def renameIntf( self, intf, newname='' ): |
85 |
"Rename an interface (to its canonical name)"
|
86 |
intf.ifconfig( 'down' )
|
87 |
if not newname: |
88 |
newname = '%s-eth%d' % ( self.name, self.ports[ intf ] ) |
89 |
intf.cmd( 'ip link set', intf, 'name', newname ) |
90 |
del self.nameToIntf[ intf.name ] |
91 |
intf.name = newname |
92 |
self.nameToIntf[ intf.name ] = intf
|
93 |
intf.ifconfig( 'up' )
|
94 |
|
95 |
def moveIntf( self, intf, switch, port=None, rename=True ): |
96 |
"Move one of our interfaces to another switch"
|
97 |
self.detach( intf )
|
98 |
self.delIntf( intf )
|
99 |
switch.addIntf( intf, port=port, rename=rename ) |
100 |
switch.attach( intf ) |
101 |
|
102 |
|
103 |
def printConnections( switches ): |
104 |
"Compactly print connected nodes to each switch"
|
105 |
for sw in switches: |
106 |
output( '%s: ' % sw )
|
107 |
for intf in sw.intfList(): |
108 |
link = intf.link |
109 |
if link:
|
110 |
intf1, intf2 = link.intf1, link.intf2 |
111 |
remote = intf1 if intf1.node != sw else intf2 |
112 |
output( '%s(%s) ' % ( remote.node, sw.ports[ intf ] ) )
|
113 |
output( '\n' )
|
114 |
|
115 |
|
116 |
def moveHost( host, oldSwitch, newSwitch, newPort=None ): |
117 |
"Move a host from old switch to new switch"
|
118 |
hintf, sintf = host.connectionsTo( oldSwitch )[ 0 ]
|
119 |
oldSwitch.moveIntf( sintf, newSwitch, port=newPort ) |
120 |
return hintf, sintf
|
121 |
|
122 |
|
123 |
def mobilityTest(): |
124 |
"A simple test of mobility"
|
125 |
print '* Simple mobility test' |
126 |
net = Mininet( topo=LinearTopo( 3 ), switch=MobilitySwitch )
|
127 |
print '* Starting network:' |
128 |
net.start() |
129 |
printConnections( net.switches ) |
130 |
print '* Testing network' |
131 |
net.pingAll() |
132 |
print '* Identifying switch interface for h1' |
133 |
h1, old = net.get( 'h1', 's1' ) |
134 |
for s in 2, 3, 1: |
135 |
new = net[ 's%d' % s ]
|
136 |
port = randint( 10, 20 ) |
137 |
print '* Moving', h1, 'from', old, 'to', new, 'port', port |
138 |
hintf, sintf = moveHost( h1, old, new, newPort=port ) |
139 |
print '*', hintf, 'is now connected to', sintf |
140 |
print '* Clearing out old flows' |
141 |
for sw in net.switches: |
142 |
sw.dpctl( 'del-flows' )
|
143 |
print '* New network:' |
144 |
printConnections( net.switches ) |
145 |
print '* Testing connectivity:' |
146 |
net.pingAll() |
147 |
old = new |
148 |
net.stop() |
149 |
|
150 |
if __name__ == '__main__': |
151 |
mobilityTest() |