Revision 0534932b

View differences:

examples/multiovs.py
1
#!/usr/bin/python
2

  
3
"""
4
Multiple ovsdb OVS!!
5

  
6
We scale up by creating multiple ovsdb instances,
7
each of which is shared by several OVS switches
8

  
9
Note: here is the command that is actually run to start ovsdb:
10

  
11
ovsdb-server /etc/openvswitch/conf.db -vconsole:emer -vsyslog:err -vfile:info --remote=punix:/var/run/openvswitch/db.sock --private-key=db:Open_vSwitch,SSL,private_key --certificate=db:Open_vSwitch,SSL,certificate --bootstrap-ca-cert=db:Open_vSwitch,SSL,ca_cert --no-chdir --log-file=/var/log/openvswitch/ovsdb-server.log --pidfile=/var/run/openvswitch/ovsdb-server.pid --detach --monitor
12

  
13
"""
14

  
15
from mininet.net import Mininet
16
from mininet.node import Node, OVSSwitch
17
from mininet.node import OVSBridge
18
from mininet.link import Link, OVSLink
19
from mininet.topo import LinearTopo, SingleSwitchTopo
20
from mininet.topolib import TreeTopo
21
from mininet.log import setLogLevel, info
22
from mininet.cli import CLI
23

  
24
from itertools import groupby
25
from operator import attrgetter
26

  
27
class OVSDB( Node ):
28
    "Namespace for an OVSDB instance"
29

  
30
    privateDirs = [ '/etc/openvswitch',
31
                    '/var/run/openvswitch',
32
                    '/var/log/openvswitch' ]
33

  
34
    # Control network
35
    ipBase = '172.123.123.0/24'
36
    cnet = None
37

  
38
    @classmethod
39
    def startControlNet( cls ):
40
        "Start control net if necessary and return it"
41
        cnet = cls.cnet
42
        if not cnet:
43
            info( '### Starting control network\n' )
44
            cnet = Mininet( ipBase=cls.ipBase )
45
            cswitch = cnet.addSwitch( 'ovsbr0', cls=OVSBridge )
46
            root = cnet.addHost( 'root0', inNamespace=False )
47
            cnet.addLink( root, cswitch )
48
            cls.cnet = cnet
49
            cnet.start()
50
            info( '### Control network started\n' )
51
        return cnet
52
  
53
    @classmethod
54
    def rootIntf( cls ):
55
        return cls.cnet[ 'root0' ].intfs[ 0 ]
56

  
57
    def stopControlNet( self ):
58
        info( '\n### Stopping control network\n' )
59
        cls = self.__class__
60
        cls.cnet.stop()
61
        info( '### Control network stopped\n' )
62

  
63
    def addSwitch( self, switch ):
64
        "Add a switch to our namespace"
65
        self.switches.append( switch )
66

  
67
    def delSwitch( self, switch ):
68
        "Delete a switch from our namespace, and terminate if none left"
69
        self.switches.remove( switch )
70
        if not self.switches:
71
            self.stopOVS()
72

  
73
    ovsdbCount = 0
74
    
75
    def startOVS( self ):
76
        "Start new OVS instance"
77
        self.cmd( 'ovsdb-tool create /etc/openvswitch/conf.db' )
78
        self.cmd( 'ovsdb-server /etc/openvswitch/conf.db'
79
                  ' -vfile:emer -vfile:err -vfile:info'
80
                  ' --remote=punix:/var/run/openvswitch/db.sock '
81
                  ' --log-file=/var/log/openvswitch/ovsdb-server.log'
82
                  ' --pidfile=/var/run/openvswitch/ovsdb-server.pid'
83
                  ' --no-chdir'
84
                  ' --detach' )
85

  
86
        self.cmd( 'ovs-vswitchd unix:/var/run/openvswitch/db.sock'
87
                  ' -vfile:emer -vfile:err -vfile:info'
88
                  ' --mlockall --log-file=/var/log/openvswitch/ovs-vswitchd.log'
89
                  ' --pidfile=/var/run/openvswitch/ovs-vswitchd.pid'
90
                  ' --no-chdir'
91
                  ' --detach' )
92

  
93
    def stopOVS( self ):
94
        self.cmd( 'kill',
95
                  '`cat /var/run/openvswitch/ovs-vswitchd.pid`',
96
                  '`cat /var/run/openvswitch/ovsdb-server.pid`' )
97
        self.cmd( 'wait' )
98
        self.__class__.ovsdbCount -= 1
99
        if self.__class__.ovsdbCount <= 0:
100
            self.stopControlNet()
101

  
102
    def self( self, *args, **kwargs ):
103
        "A fake constructor that sets params and returns self"
104
        self.params = kwargs
105
        return self
106

  
107
    def __init__( self, **kwargs ):
108
        cls = self.__class__
109
        cls.ovsdbCount += 1
110
        cnet = self.startControlNet()
111
        # Create a new ovsdb namespace
112
        self.switches = []
113
        name = 'ovsdb%d' % cls.ovsdbCount
114
        kwargs.update( inNamespace=True )
115
        kwargs.setdefault( 'privateDirs', self.privateDirs )
116
        super( OVSDB, self ).__init__( name, **kwargs )
117
        ovsdb = cnet.addHost( name, cls=self.self, **kwargs )
118
        link = cnet.addLink( ovsdb, cnet.switches[ 0 ] )
119
        cnet.switches[ 0 ].attach( link.intf2 )
120
        ovsdb.configDefault()
121
        ovsdb.startOVS()
122

  
123

  
124
class OVSSwitchNS( OVSSwitch ):
125
    "OVS Switch in shared OVSNS namespace"
126

  
127
    isSetup = False
128

  
129
    @classmethod
130
    def batchStartup( cls, switches ):
131
        result = []
132
        for ovsdb, switchGroup in groupby( switches, attrgetter( 'ovsdb') ):
133
            switchGroup = list( switchGroup )
134
            info( '(%s)' % ovsdb )
135
            result += OVSSwitch.batchStartup( switchGroup, run=ovsdb.cmd )
136
        return result
137

  
138
    @classmethod
139
    def batchShutdown( cls, switches ):
140
        result = []
141
        for ovsdb, switchGroup in groupby( switches, attrgetter( 'ovsdb') ):
142
            switchGroup = list( switchGroup )
143
            info( '(%s)' % ovsdb )
144
            result += OVSSwitch.batchShutdown( switchGroup, run=ovsdb.cmd )
145
            for switch in switchGroup:
146
                switch.ovsdbFree()
147
        return result
148

  
149
    # OVSDB allocation
150
    groupSize = 1      # switch group size
151
    switchCount = 0
152
    lastOvsdb = None
153

  
154
    @classmethod
155
    def ovsdbAlloc( cls, switch ):
156
        "Allocate (possibly new) OVSDB instance for switch"
157
        if cls.switchCount % cls.groupSize == 0:
158
            cls.lastOvsdb = OVSDB()
159
        cls.switchCount += 1
160
        cls.lastOvsdb.addSwitch( switch )
161
        return cls.lastOvsdb
162

  
163
    def ovsdbFree( self ):
164
        "Deallocate OVSDB instance for switch"
165
        self.ovsdb.delSwitch( self )
166

  
167
    def startShell( self, *args, **kwargs ):
168
        "Start shell in shared OVSDB namespace"
169
        ovsdb = self.ovsdbAlloc( self )
170
        kwargs.update( mnopts='-da %d ' % ovsdb.pid )
171
        self.ns = [ 'net' ]
172
        self.ovsdb = ovsdb
173
        super( OVSSwitchNS, self ).startShell( *args, **kwargs )
174
        self.defaultIntf().updateIP()
175

  
176
    def start( self, controllers ):
177
        "Update controller IP addresses if necessary"
178
        for controller in controllers:
179
            if controller.IP() == '127.0.0.1' and not controller.intfs:
180
                controller.intfs[ 0 ] = self.ovsdb.rootIntf()
181
        super( OVSSwitchNS, self ).start( controllers )
182

  
183
    def stop( self, *args, **kwargs ):
184
        "Stop and free OVSDB namespace if necessary"
185
        super( OVSSwitchNS, self ).stop( *args, **kwargs )
186
        self.ovsdbFree()
187

  
188
    def defaultIntf( self ):
189
        return self.ovsdb.defaultIntf()
190

  
191

  
192
switches = { 'ovsns': OVSSwitchNS }
193

  
194

  
195
def test():
196
    "Test OVSNS switch"
197
    setLogLevel( 'info' )
198
    topo = TreeTopo( depth=4, fanout=2 )
199
    net = Mininet( topo=topo, switch=OVSSwitchNS )
200
    # Add connectivity to controller which is on LAN or in root NS
201
    # net.addNAT().configDefault()
202
    net.start()
203
    CLI( net )
204
    net.stop()
205

  
206

  
207
if __name__ == '__main__':
208
    test()

Also available in: Unified diff