Statistics
| Branch: | Tag: | Revision:

mininet / mininet / topo.py @ 376bcba4

History | View | Annotate | Download (9.89 KB)

1 8b5062a3 Brandon Heller
#!/usr/bin/env python
2 433a7cc8 Brandon Heller
'''@package topo
3 8b5062a3 Brandon Heller

4 433a7cc8 Brandon Heller
Network topology creation.
5 8b5062a3 Brandon Heller

6 433a7cc8 Brandon Heller
@author Brandon Heller (brandonh@stanford.edu)
7 8b5062a3 Brandon Heller

8 433a7cc8 Brandon Heller
This package includes code to represent network topologies.
9 8b5062a3 Brandon Heller

10 433a7cc8 Brandon Heller
A Topo object can be a topology database for NOX, can represent a physical
11
setup for testing, and can even be emulated with the Mininet package.
12
'''
13 8b5062a3 Brandon Heller
14 433a7cc8 Brandon Heller
from networkx import Graph
15 8b5062a3 Brandon Heller
16
17 433a7cc8 Brandon Heller
class NodeID(object):
18
    '''Topo node identifier.'''
19 8b5062a3 Brandon Heller
20 433a7cc8 Brandon Heller
    def __init__(self, dpid = None):
21
        '''Init.
22

23
        @param dpid dpid
24
        '''
25
        # DPID-compatible hashable identifier: opaque 64-bit unsigned int
26
        self.dpid = dpid
27
28
    def __str__(self):
29
        '''String conversion.
30

31
        @return str dpid as string
32
        '''
33
        return str(self.dpid)
34
35
    def name_str(self):
36
        '''Name conversion.
37 8b5062a3 Brandon Heller

38 433a7cc8 Brandon Heller
        @return name name as string
39
        '''
40
        return str(self.dpid)
41
42
    def ip_str(self):
43
        '''Name conversion.
44

45
        @return ip ip as string
46
        '''
47
        hi = (self.dpid & 0xff0000) >> 16
48
        mid = (self.dpid & 0xff00) >> 8
49
        lo = self.dpid & 0xff
50
        return "10.%i.%i.%i" % (hi, mid, lo)
51 8b5062a3 Brandon Heller
52 433a7cc8 Brandon Heller
53
class Node(object):
54
    '''Node-specific vertex metadata for a Topo object.'''
55
56
    def __init__(self, connected = False, admin_on = True,
57
                 power_on = True, fault = False, is_switch = True):
58 8b5062a3 Brandon Heller
        '''Init.
59

60 433a7cc8 Brandon Heller
        @param connected actively connected to controller
61
        @param admin_on administratively on or off
62
        @param power_on powered on or off
63
        @param fault fault seen on node
64
        @param is_switch switch or host
65
        '''
66
        self.connected = connected
67
        self.admin_on = admin_on
68
        self.power_on = power_on
69
        self.fault = fault
70
        self.is_switch = is_switch
71 8b5062a3 Brandon Heller
72
73 433a7cc8 Brandon Heller
class Edge(object):
74
    '''Edge-specific metadata for a StructuredTopo graph.'''
75
76
    def __init__(self, admin_on = True, power_on = True, fault = False):
77
        '''Init.
78

79
        @param admin_on administratively on or off; defaults to True
80
        @param power_on powered on or off; defaults to True
81
        @param fault fault seen on edge; defaults to False
82
        '''
83
        self.admin_on = admin_on
84
        self.power_on = power_on
85
        self.fault = fault
86
87
88
class Topo(object):
89
    '''Data center network representation for structured multi-trees.'''
90
    def __init__(self):
91
        '''Create Topo object.
92

93
        '''
94
        self.g = Graph()
95
        self.node_info = {} # dpids hash to Node objects
96
        self.edge_info = {} # (src_dpid, dst_dpid) tuples hash to Edge objects
97
        self.ports = {} # ports[src][dst] is port on src that connects to dst
98
        self.id_gen = NodeID # class used to generate dpid
99
100
    def _add_node(self, dpid, node):
101
        '''Add Node to graph.
102

103
        @param dpid dpid
104
        @param node Node object
105
        '''
106
        self.g.add_node(dpid)
107
        self.node_info[dpid] = node
108
109
    def _add_edge(self, src, dst, edge):
110
        '''Add edge (Node, Node) to graph.
111

112
        @param src src dpid
113
        @param dst dst dpid
114
        @param edge Edge object
115
        '''
116
        src, dst = tuple(sorted([src, dst]))
117
        self.g.add_edge(src, dst)
118
        self.edge_info[(src, dst)] = edge
119
        self._add_port(src, dst)
120 8b5062a3 Brandon Heller
121 433a7cc8 Brandon Heller
    def _add_port(self, src, dst):
122
        '''Generate port mapping for new edge.
123

124
        @param src source switch DPID
125
        @param dst destination switch DPID
126
        '''
127
        if src not in self.ports:
128
            self.ports[src] = {}
129
        if dst not in self.ports[src]:
130
            self.ports[src][dst] = len(self.ports[src]) # num outlinks
131
132
        if dst not in self.ports:
133
            self.ports[dst] = {}
134
        if src not in self.ports[dst]:
135
            self.ports[dst][src] = len(self.ports[dst]) # num outlinks
136
137
    def node_enabled(self, dpid):
138
        '''Is node connected, admin on, powered on, and fault-free?
139

140
        @param dpid dpid
141

142
        @return bool node is enabled
143
        '''
144
        ni = self.node_info[dpid]
145
        return ni.connected and ni.admin_on and ni.power_on and not ni.fault
146
147
    def nodes_enabled(self, dpids, enabled = True):
148
        '''Return subset of enabled nodes
149

150
        @param dpids list of dpids
151
        @param enabled only return enabled nodes?
152

153
        @return dpids filtered list of dpids
154
        '''
155
        if enabled:
156
            return [n for n in dpids if self.node_enabled(n)]
157
        else:
158
            return dpids
159
160
    def nodes(self, enabled = True):
161
        '''Return graph nodes.
162

163
        @param enabled only return enabled nodes?
164

165
        @return dpids list of dpids
166
        '''
167
        return self.nodes_enabled(self.g.nodes(), enabled)
168
169
    def nodes_str(self, dpids):
170
        '''Return string of custom-encoded nodes.
171

172
        @param dpids list of dpids
173

174
        @return str string
175
        '''
176
        return [str(self.id_gen(dpid = dpid)) for dpid in dpids]
177
178
    def switches(self, enabled = True):
179
        '''Return switches.
180

181
        @param enabled only return enabled nodes?
182

183
        @return dpids list of dpids
184
        '''
185
        def is_switch(n):
186
            '''Returns true if node is a switch.'''
187
            return self.node_info[n].is_switch
188
189
        nodes = [n for n in self.g.nodes() if is_switch(n)]
190
        return self.nodes_enabled(nodes, enabled)
191
192
    def hosts(self, enabled = True):
193
        '''Return hosts.
194

195
        @param enabled only return enabled nodes?
196

197
        @return dpids list of dpids
198
        '''
199
        def is_host(n):
200
            '''Returns true if node is a host.'''
201
            return not self.node_info[n].is_switch
202
203
        nodes = [n for n in self.g.nodes() if is_host(n)]
204
        return self.nodes_enabled(nodes, enabled)
205
206
    def edge_enabled(self, edge):
207
        '''Is edge admin on, powered on, and fault-free?
208

209
        @param edge (src, dst) dpid tuple
210

211
        @return bool edge is enabled
212
        '''
213
        src, dst = edge
214
        src, dst = tuple(sorted([src, dst]))
215
        ei = self.edge_info[tuple(sorted([src, dst]))]
216
        return ei.admin_on and ei.power_on and not ei.fault
217
218
    def edges_enabled(self, edges, enabled = True):
219
        '''Return subset of enabled edges
220

221
        @param edges list of edges
222
        @param enabled only return enabled edges?
223

224
        @return edges filtered list of edges
225
        '''
226
        if enabled:
227
            return [e for e in edges if self.edge_enabled(e)]
228
        else:
229
            return edges
230
231
    def edges(self, enabled = True):
232
        '''Return edges.
233

234
        @param enabled only return enabled edges?
235

236
        @return edges list of dpid pairs
237
        '''
238
        return self.edges_enabled(self.g.edges(), enabled)
239
240
    def edges_str(self, dpid_pairs):
241
        '''Return string of custom-encoded node pairs.
242

243
        @param dpid_pairs list of dpid pairs (src, dst)
244

245
        @return str string
246
        '''
247
        edges = []
248
        for pair in dpid_pairs:
249
            src, dst = pair
250
            src = str(self.id_gen(dpid = src))
251
            dst = str(self.id_gen(dpid = dst))
252
            edges.append((src, dst))
253
        return edges
254
255
    def port(self, src, dst):
256
        '''Get port number.
257 8b5062a3 Brandon Heller

258
        @param src source switch DPID
259
        @param dst destination switch DPID
260
        @return tuple (src_port, dst_port):
261
            src_port: port on source switch leading to the destination switch
262
            dst_port: port on destination switch leading to the source switch
263
        '''
264 433a7cc8 Brandon Heller
        if src in self.ports and dst in self.ports[src]:
265
            assert dst in self.ports and src in self.ports[dst]
266
            return (self.ports[src][dst], self.ports[dst][src])
267 8b5062a3 Brandon Heller
268 433a7cc8 Brandon Heller
    def enable_edges(self):
269
        '''Enable all edges in the network graph.
270 8b5062a3 Brandon Heller

271 433a7cc8 Brandon Heller
        Set admin on, power on, and fault off.
272
        '''
273
        for e in self.g.edges():
274
            src, dst = e
275
            ei = self.edge_info[tuple(sorted([src, dst]))]
276
            ei.admin_on = True
277
            ei.power_on = True
278
            ei.fault = False
279 8b5062a3 Brandon Heller
280 433a7cc8 Brandon Heller
    def enable_nodes(self):
281
        '''Enable all nodes in the network graph.
282 8b5062a3 Brandon Heller

283 433a7cc8 Brandon Heller
        Set connected on, admin on, power on, and fault off.
284
        '''
285
        for node in self.g.nodes():
286
            ni = self.node_info[node]
287
            ni.connected = True
288
            ni.admin_on = True
289
            ni.power_on = True
290
            ni.fault = False
291
292
    def enable_all(self):
293
        '''Enable all nodes and edges in the network graph.'''
294
        self.enable_nodes()
295
        self.enable_edges()
296 8b5062a3 Brandon Heller
297
    def name(self, dpid):
298
        '''Get string name of node ID.
299

300
        @param dpid DPID of host or switch
301
        @return name_str string name with no dashes
302
        '''
303
        return self.id_gen(dpid = dpid).name_str()
304
305
    def ip(self, dpid):
306
        '''Get IP dotted-decimal string of node ID.
307

308
        @param dpid DPID of host or switch
309
        @return ip_str
310
        '''
311 433a7cc8 Brandon Heller
        return self.id_gen(dpid = dpid).ip_str()
312
313
314
class SingleSwitchTopo(Topo):
315
    '''Single switch connected to k hosts.'''
316
317
    def __init__(self, k = 2, enable_all = True):
318
        '''Init.
319

320
        @param k number of hosts
321
        @param enable_all enables all nodes and switches?
322
        '''
323
        super(SingleSwitchTopo, self).__init__()
324
325
        self.k = k
326
327
        self._add_node(0, Node())
328
        hosts = range(1, k + 1)
329
        for h in hosts:
330
            self._add_node(h, Node(is_switch = False))
331
            self._add_edge(h, 0, Edge())
332
333
        if enable_all:
334
            self.enable_all()
335
336
337
class LinearTopo(Topo):
338
    '''Linear topology of k switches, with one host per switch.'''
339
340
    def __init__(self, k = 2, enable_all = True):
341
        '''Init.
342

343
        @param k number of switches (and hosts too)
344
        @param enable_all enables all nodes and switches?
345
        '''
346
        super(LinearTopo, self).__init__()
347
348
        self.k = k
349
350
        switches = range(0, k)
351
        for s in switches:
352
            h = s + k
353
            self._add_node(s, Node())
354
            self._add_node(h, Node(is_switch = False))
355
            self._add_edge(s, h, Edge())
356
        for s in switches:
357
            if s != k - 1:
358
                self._add_edge(s, s + 1, Edge())
359
360
        if enable_all:
361
            self.enable_all()