Statistics
| Branch: | Tag: | Revision:

mininet / mininet / topo.py @ 824afb84

History | View | Annotate | Download (8.25 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 8bebd377 Bob Lantz
from mininet.util import irange, natural, naturalSeq
15 433a7cc8 Brandon Heller
16 5b48a7d9 Bob Lantz
class MultiGraph( object ):
17 2485d57f Bob Lantz
    "Utility class to track nodes and edges - replaces networkx.Graph"
18 65c35b65 ryanc
19 2485d57f Bob Lantz
    def __init__( self ):
20 65c35b65 ryanc
        self.data = {}
21
22 2485d57f Bob Lantz
    def add_node( self, node ):
23
        "Add node to graph"
24 5b48a7d9 Bob Lantz
        self.data.setdefault( node, [] )
25 65c35b65 ryanc
26 2485d57f Bob Lantz
    def add_edge( self, src, dest ):
27
        "Add edge to graph"
28 5b48a7d9 Bob Lantz
        src, dest = sorted( ( src, dest ) )
29 2485d57f Bob Lantz
        self.add_node( src )
30
        self.add_node( dest )
31
        self.data[ src ].append( dest )
32 65c35b65 ryanc
33 2485d57f Bob Lantz
    def nodes( self ):
34
        "Return list of graph nodes"
35 65c35b65 ryanc
        return self.data.keys()
36
37 2485d57f Bob Lantz
    def edges( self ):
38
        "Iterator: return graph edges"
39 65c35b65 ryanc
        for src in self.data.keys():
40 2485d57f Bob Lantz
            for dest in self.data[ src ]:
41
                yield ( src, dest )
42
43 4e1630e1 Brandon Heller
    def __getitem__( self, node ):
44
        "Return link dict for the given node"
45
        return self.data[node]
46
47 65c35b65 ryanc
48 433a7cc8 Brandon Heller
class Topo(object):
49 5a8bb489 Bob Lantz
    "Data center network representation for structured multi-trees."
50
51
    def __init__(self, hopts=None, sopts=None, lopts=None):
52
        """Topo object:
53
           hinfo: default host options
54
           sopts: default switch options
55
           lopts: default link options"""
56 5b48a7d9 Bob Lantz
        self.g = MultiGraph()
57 5a8bb489 Bob Lantz
        self.node_info = {}
58
        self.link_info = {}  # (src, dst) tuples hash to EdgeInfo objects
59
        self.hopts = {} if hopts is None else hopts
60 e1246c37 Bob Lantz
        self.sopts = {} if sopts is None else sopts
61 5a8bb489 Bob Lantz
        self.lopts = {} if lopts is None else lopts
62 0774c8bb Bob Lantz
        self.ports = {}  # ports[src][dst] is port on src that connects to dst
63 433a7cc8 Brandon Heller
64 ce15c4f6 Bob Lantz
    def addNode(self, name, **opts):
65 5a8bb489 Bob Lantz
        """Add Node to graph.
66
           name: name
67 e1246c37 Bob Lantz
           opts: node options
68
           returns: node name"""
69 5a8bb489 Bob Lantz
        self.g.add_node(name)
70
        self.node_info[name] = opts
71
        return name
72
73 ce15c4f6 Bob Lantz
    def addHost(self, name, **opts):
74 5a8bb489 Bob Lantz
        """Convenience method: Add host to graph.
75 e1246c37 Bob Lantz
           name: host name
76
           opts: host options
77
           returns: host name"""
78 5a8bb489 Bob Lantz
        if not opts and self.hopts:
79
            opts = self.hopts
80 ce15c4f6 Bob Lantz
        return self.addNode(name, **opts)
81 5a8bb489 Bob Lantz
82 ce15c4f6 Bob Lantz
    def addSwitch(self, name, **opts):
83 5a8bb489 Bob Lantz
        """Convenience method: Add switch to graph.
84 e1246c37 Bob Lantz
           name: switch name
85
           opts: switch options
86
           returns: switch name"""
87 5a8bb489 Bob Lantz
        if not opts and self.sopts:
88
            opts = self.sopts
89 ce15c4f6 Bob Lantz
        result = self.addNode(name, isSwitch=True, **opts)
90 5a8bb489 Bob Lantz
        return result
91
92 ce15c4f6 Bob Lantz
    def addLink(self, node1, node2, port1=None, port2=None,
93 2e089b5e Brandon Heller
                **opts):
94 e1246c37 Bob Lantz
        """node1, node2: nodes to link together
95
           port1, port2: ports (optional)
96
           opts: link options (optional)
97
           returns: link info key"""
98
        if not opts and self.lopts:
99
            opts = self.lopts
100 ce15c4f6 Bob Lantz
        self.addPort(node1, node2, port1, port2)
101 e1246c37 Bob Lantz
        key = tuple(self.sorted([node1, node2]))
102
        self.link_info[key] = opts
103
        self.g.add_edge(*key)
104
        return key
105
106 ce15c4f6 Bob Lantz
    def addPort(self, src, dst, sport=None, dport=None):
107 433a7cc8 Brandon Heller
        '''Generate port mapping for new edge.
108 e1246c37 Bob Lantz
        @param src source switch name
109
        @param dst destination switch name
110 433a7cc8 Brandon Heller
        '''
111 e1246c37 Bob Lantz
        self.ports.setdefault(src, {})
112
        self.ports.setdefault(dst, {})
113
        # New port: number of outlinks + base
114 ce15c4f6 Bob Lantz
        src_base = 1 if self.isSwitch(src) else 0
115
        dst_base = 1 if self.isSwitch(dst) else 0
116 e1246c37 Bob Lantz
        if sport is None:
117
            sport = len(self.ports[src]) + src_base
118
        if dport is None:
119
            dport = len(self.ports[dst]) + dst_base
120
        self.ports[src][dst] = sport
121
        self.ports[dst][src] = dport
122 8bebd377 Bob Lantz
123 5a8bb489 Bob Lantz
    def nodes(self, sort=True):
124
        "Return nodes in graph"
125
        if sort:
126 e1246c37 Bob Lantz
            return self.sorted( self.g.nodes() )
127 433a7cc8 Brandon Heller
        else:
128 5a8bb489 Bob Lantz
            return self.g.nodes()
129 433a7cc8 Brandon Heller
130 ce15c4f6 Bob Lantz
    def isSwitch(self, n):
131 dd159b4a Bob Lantz
        '''Returns true if node is a switch.'''
132 5a8bb489 Bob Lantz
        info = self.node_info[n]
133 ce15c4f6 Bob Lantz
        return info and info.get('isSwitch', False)
134 dd159b4a Bob Lantz
135 5a8bb489 Bob Lantz
    def switches(self, sort=True):
136 433a7cc8 Brandon Heller
        '''Return switches.
137 5a8bb489 Bob Lantz
        sort: sort switches alphabetically
138 433a7cc8 Brandon Heller
        @return dpids list of dpids
139
        '''
140 ce15c4f6 Bob Lantz
        return [n for n in self.nodes(sort) if self.isSwitch(n)]
141 433a7cc8 Brandon Heller
142 5a8bb489 Bob Lantz
    def hosts(self, sort=True):
143 433a7cc8 Brandon Heller
        '''Return hosts.
144 5a8bb489 Bob Lantz
        sort: sort hosts alphabetically
145 433a7cc8 Brandon Heller
        @return dpids list of dpids
146
        '''
147 ce15c4f6 Bob Lantz
        return [n for n in self.nodes(sort) if not self.isSwitch(n)]
148 723d068c Brandon Heller
149 5a8bb489 Bob Lantz
    def links(self, sort=True):
150
        '''Return links.
151
        sort: sort links alphabetically
152
        @return links list of name pairs
153 433a7cc8 Brandon Heller
        '''
154 5a8bb489 Bob Lantz
        if not sort:
155
            return self.g.edges()
156 433a7cc8 Brandon Heller
        else:
157 e1246c37 Bob Lantz
            links = [tuple(self.sorted(e)) for e in self.g.edges()]
158
            return sorted( links, key=naturalSeq )
159 433a7cc8 Brandon Heller
160
    def port(self, src, dst):
161
        '''Get port number.
162 8b5062a3 Brandon Heller

163 5a8bb489 Bob Lantz
        @param src source switch name
164
        @param dst destination switch name
165 8b5062a3 Brandon Heller
        @return tuple (src_port, dst_port):
166
            src_port: port on source switch leading to the destination switch
167
            dst_port: port on destination switch leading to the source switch
168
        '''
169 433a7cc8 Brandon Heller
        if src in self.ports and dst in self.ports[src]:
170
            assert dst in self.ports and src in self.ports[dst]
171 824afb84 Rémy Léone
            return self.ports[src][dst], self.ports[dst][src]
172 8b5062a3 Brandon Heller
173 5a8bb489 Bob Lantz
    def linkInfo( self, src, dst ):
174
        "Return link metadata"
175 e1246c37 Bob Lantz
        src, dst = self.sorted([src, dst])
176 5a8bb489 Bob Lantz
        return self.link_info[(src, dst)]
177 78606a35 Bob Lantz
178 8f310286 Bob Lantz
    def setlinkInfo( self, src, dst, info ):
179
        "Set link metadata"
180
        src, dst = self.sorted([src, dst])
181
        self.link_info[(src, dst)] = info
182
183 5a8bb489 Bob Lantz
    def nodeInfo( self, name ):
184
        "Return metadata (dict) for node"
185
        info = self.node_info[ name ]
186
        return info if info is not None else {}
187 433a7cc8 Brandon Heller
188 5a8bb489 Bob Lantz
    def setNodeInfo( self, name, info ):
189 8bebd377 Bob Lantz
        "Set metadata (dict) for node"
190 5a8bb489 Bob Lantz
        self.node_info[ name ] = info
191 433a7cc8 Brandon Heller
192 5a8bb489 Bob Lantz
    @staticmethod
193
    def sorted( items ):
194
        "Items sorted in natural (i.e. alphabetical) order"
195
        return sorted(items, key=natural)
196 14ff3ad3 Bob Lantz
197 433a7cc8 Brandon Heller
class SingleSwitchTopo(Topo):
198
    '''Single switch connected to k hosts.'''
199
200 5a8bb489 Bob Lantz
    def __init__(self, k=2, **opts):
201 433a7cc8 Brandon Heller
        '''Init.
202

203
        @param k number of hosts
204
        @param enable_all enables all nodes and switches?
205
        '''
206 5a8bb489 Bob Lantz
        super(SingleSwitchTopo, self).__init__(**opts)
207 433a7cc8 Brandon Heller
208
        self.k = k
209
210 ce15c4f6 Bob Lantz
        switch = self.addSwitch('s1')
211 5a8bb489 Bob Lantz
        for h in irange(1, k):
212 ce15c4f6 Bob Lantz
            host = self.addHost('h%s' % h)
213
            self.addLink(host, switch)
214 433a7cc8 Brandon Heller
215
216 78606a35 Bob Lantz
class SingleSwitchReversedTopo(Topo):
217 6d2cd77b Brandon Heller
    '''Single switch connected to k hosts, with reversed ports.
218

219
    The lowest-numbered host is connected to the highest-numbered port.
220

221
    Useful to verify that Mininet properly handles custom port numberings.
222
    '''
223 e1246c37 Bob Lantz
    def __init__(self, k=2, **opts):
224
        '''Init.
225 6d2cd77b Brandon Heller

226 e1246c37 Bob Lantz
        @param k number of hosts
227
        @param enable_all enables all nodes and switches?
228 6d2cd77b Brandon Heller
        '''
229 78606a35 Bob Lantz
        super(SingleSwitchReversedTopo, self).__init__(**opts)
230 e1246c37 Bob Lantz
        self.k = k
231 ce15c4f6 Bob Lantz
        switch = self.addSwitch('s1')
232 e1246c37 Bob Lantz
        for h in irange(1, k):
233 ce15c4f6 Bob Lantz
            host = self.addHost('h%s' % h)
234
            self.addLink(host, switch,
235 2e089b5e Brandon Heller
                         port1=0, port2=(k - h + 1))
236 6d2cd77b Brandon Heller
237 433a7cc8 Brandon Heller
class LinearTopo(Topo):
238 92112315 Brian O'Connor
    "Linear topology of k switches, with n hosts per switch."
239 433a7cc8 Brandon Heller
240 92112315 Brian O'Connor
    def __init__(self, k=2, n=1, **opts):
241 5a8bb489 Bob Lantz
        """Init.
242 92112315 Brian O'Connor
           k: number of switches
243
           n: number of hosts per switch
244 5a8bb489 Bob Lantz
           hconf: host configuration options
245
           lconf: link configuration options"""
246 433a7cc8 Brandon Heller
247 5a8bb489 Bob Lantz
        super(LinearTopo, self).__init__(**opts)
248 433a7cc8 Brandon Heller
249
        self.k = k
250 92112315 Brian O'Connor
        self.n = n
251 433a7cc8 Brandon Heller
252 bb0006b6 Brian O'Connor
        if n == 1:
253 f796f01f Bob Lantz
            genHostName = lambda i, j: 'h%s' % i
254 a22e2618 Murphy McCauley
        else:
255 f796f01f Bob Lantz
            genHostName = lambda i, j: 'h%ss%d' % (j, i)
256 bb0006b6 Brian O'Connor
257 433a7cc8 Brandon Heller
258 5a8bb489 Bob Lantz
        lastSwitch = None
259
        for i in irange(1, k):
260 92112315 Brian O'Connor
            # Add switch
261 ce15c4f6 Bob Lantz
            switch = self.addSwitch('s%s' % i)
262 92112315 Brian O'Connor
            # Add hosts to switch
263
            for j in irange(1, n):
264 bb0006b6 Brian O'Connor
                host = self.addHost(genHostName(i, j))
265 9c4b7343 Bob Lantz
                self.addLink(host, switch)
266 92112315 Brian O'Connor
            # Connect switch to previous
267 5a8bb489 Bob Lantz
            if lastSwitch:
268 92112315 Brian O'Connor
                self.addLink(switch, lastSwitch)
269 5a8bb489 Bob Lantz
            lastSwitch = switch