Statistics
| Branch: | Tag: | Revision:

mininet / mininet / topo.py @ 149a1f56

History | View | Annotate | Download (7.12 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 24baea73 Bob Lantz
# BL: we may have to fix compatibility here.
15
# networkx is also a fairly heavyweight dependency
16
# from networkx.classes.graph import Graph
17
18
from networkx import Graph
19 8bebd377 Bob Lantz
from mininet.util import irange, natural, naturalSeq
20 433a7cc8 Brandon Heller
21
class Topo(object):
22 5a8bb489 Bob Lantz
    "Data center network representation for structured multi-trees."
23
24
    def __init__(self, hopts=None, sopts=None, lopts=None):
25
        """Topo object:
26
           hinfo: default host options
27
           sopts: default switch options
28
           lopts: default link options"""
29 433a7cc8 Brandon Heller
        self.g = Graph()
30 5a8bb489 Bob Lantz
        self.node_info = {}
31
        self.link_info = {}  # (src, dst) tuples hash to EdgeInfo objects
32
        self.hopts = {} if hopts is None else hopts
33 e1246c37 Bob Lantz
        self.sopts = {} if sopts is None else sopts
34 5a8bb489 Bob Lantz
        self.lopts = {} if lopts is None else lopts
35 0774c8bb Bob Lantz
        self.ports = {}  # ports[src][dst] is port on src that connects to dst
36 433a7cc8 Brandon Heller
37 e1246c37 Bob Lantz
    def add_node(self, name, **opts):
38 5a8bb489 Bob Lantz
        """Add Node to graph.
39
           name: name
40 e1246c37 Bob Lantz
           opts: node options
41
           returns: node name"""
42 5a8bb489 Bob Lantz
        self.g.add_node(name)
43
        self.node_info[name] = opts
44
        return name
45
46 e1246c37 Bob Lantz
    def add_host(self, name, **opts):
47 5a8bb489 Bob Lantz
        """Convenience method: Add host to graph.
48 e1246c37 Bob Lantz
           name: host name
49
           opts: host options
50
           returns: host name"""
51 5a8bb489 Bob Lantz
        if not opts and self.hopts:
52
            opts = self.hopts
53 e1246c37 Bob Lantz
        return self.add_node(name, **opts)
54 5a8bb489 Bob Lantz
55
    def add_switch(self, name, **opts):
56
        """Convenience method: Add switch to graph.
57 e1246c37 Bob Lantz
           name: switch name
58
           opts: switch options
59
           returns: switch name"""
60 5a8bb489 Bob Lantz
        if not opts and self.sopts:
61
            opts = self.sopts
62
        result = self.add_node(name, is_switch=True, **opts)
63
        return result
64
65 78606a35 Bob Lantz
    def add_link(self, node1, node2, port1=None, port2=None,
66
                 **opts):
67 e1246c37 Bob Lantz
        """node1, node2: nodes to link together
68
           port1, port2: ports (optional)
69
           opts: link options (optional)
70
           returns: link info key"""
71
        if not opts and self.lopts:
72
            opts = self.lopts
73
        self.add_port(node1, node2, port1, port2)
74
        key = tuple(self.sorted([node1, node2]))
75
        self.link_info[key] = opts
76
        self.g.add_edge(*key)
77
        return key
78
79
    def add_port(self, src, dst, sport=None, dport=None):
80 433a7cc8 Brandon Heller
        '''Generate port mapping for new edge.
81 e1246c37 Bob Lantz
        @param src source switch name
82
        @param dst destination switch name
83 433a7cc8 Brandon Heller
        '''
84 e1246c37 Bob Lantz
        self.ports.setdefault(src, {})
85
        self.ports.setdefault(dst, {})
86
        # New port: number of outlinks + base
87 bf5becc7 Bob Lantz
        src_base = 1 if self.is_switch(src) else 0
88
        dst_base = 1 if self.is_switch(dst) else 0
89 e1246c37 Bob Lantz
        if sport is None:
90
            sport = len(self.ports[src]) + src_base
91
        if dport is None:
92
            dport = len(self.ports[dst]) + dst_base
93
        self.ports[src][dst] = sport
94
        self.ports[dst][src] = dport
95 8bebd377 Bob Lantz
96 5a8bb489 Bob Lantz
    def nodes(self, sort=True):
97
        "Return nodes in graph"
98
        if sort:
99 e1246c37 Bob Lantz
            return self.sorted( self.g.nodes() )
100 433a7cc8 Brandon Heller
        else:
101 5a8bb489 Bob Lantz
            return self.g.nodes()
102 433a7cc8 Brandon Heller
103 dd159b4a Bob Lantz
    def is_switch(self, n):
104
        '''Returns true if node is a switch.'''
105 5a8bb489 Bob Lantz
        info = self.node_info[n]
106 8bebd377 Bob Lantz
        return info and info.get('is_switch', False)
107 dd159b4a Bob Lantz
108 5a8bb489 Bob Lantz
    def switches(self, sort=True):
109 433a7cc8 Brandon Heller
        '''Return switches.
110 5a8bb489 Bob Lantz
        sort: sort switches alphabetically
111 433a7cc8 Brandon Heller
        @return dpids list of dpids
112
        '''
113 5a8bb489 Bob Lantz
        return [n for n in self.nodes(sort) if self.is_switch(n)]
114 433a7cc8 Brandon Heller
115 5a8bb489 Bob Lantz
    def hosts(self, sort=True):
116 433a7cc8 Brandon Heller
        '''Return hosts.
117 5a8bb489 Bob Lantz
        sort: sort hosts alphabetically
118 433a7cc8 Brandon Heller
        @return dpids list of dpids
119
        '''
120 5a8bb489 Bob Lantz
        return [n for n in self.nodes(sort) if not self.is_switch(n)]
121 723d068c Brandon Heller
122 5a8bb489 Bob Lantz
    def links(self, sort=True):
123
        '''Return links.
124
        sort: sort links alphabetically
125
        @return links list of name pairs
126 433a7cc8 Brandon Heller
        '''
127 5a8bb489 Bob Lantz
        if not sort:
128
            return self.g.edges()
129 433a7cc8 Brandon Heller
        else:
130 e1246c37 Bob Lantz
            links = [tuple(self.sorted(e)) for e in self.g.edges()]
131
            return sorted( links, key=naturalSeq )
132 433a7cc8 Brandon Heller
133
    def port(self, src, dst):
134
        '''Get port number.
135 8b5062a3 Brandon Heller

136 5a8bb489 Bob Lantz
        @param src source switch name
137
        @param dst destination switch name
138 8b5062a3 Brandon Heller
        @return tuple (src_port, dst_port):
139
            src_port: port on source switch leading to the destination switch
140
            dst_port: port on destination switch leading to the source switch
141
        '''
142 433a7cc8 Brandon Heller
        if src in self.ports and dst in self.ports[src]:
143
            assert dst in self.ports and src in self.ports[dst]
144
            return (self.ports[src][dst], self.ports[dst][src])
145 8b5062a3 Brandon Heller
146 5a8bb489 Bob Lantz
    def linkInfo( self, src, dst ):
147
        "Return link metadata"
148 e1246c37 Bob Lantz
        src, dst = self.sorted([src, dst])
149 5a8bb489 Bob Lantz
        return self.link_info[(src, dst)]
150 78606a35 Bob Lantz
151 5a8bb489 Bob Lantz
    def nodeInfo( self, name ):
152
        "Return metadata (dict) for node"
153
        info = self.node_info[ name ]
154
        return info if info is not None else {}
155 433a7cc8 Brandon Heller
156 5a8bb489 Bob Lantz
    def setNodeInfo( self, name, info ):
157 8bebd377 Bob Lantz
        "Set metadata (dict) for node"
158 5a8bb489 Bob Lantz
        self.node_info[ name ] = info
159 433a7cc8 Brandon Heller
160 5a8bb489 Bob Lantz
    @staticmethod
161
    def sorted( items ):
162
        "Items sorted in natural (i.e. alphabetical) order"
163
        return sorted(items, key=natural)
164 14ff3ad3 Bob Lantz
165 433a7cc8 Brandon Heller
class SingleSwitchTopo(Topo):
166
    '''Single switch connected to k hosts.'''
167
168 5a8bb489 Bob Lantz
    def __init__(self, k=2, **opts):
169 433a7cc8 Brandon Heller
        '''Init.
170

171
        @param k number of hosts
172
        @param enable_all enables all nodes and switches?
173
        '''
174 5a8bb489 Bob Lantz
        super(SingleSwitchTopo, self).__init__(**opts)
175 433a7cc8 Brandon Heller
176
        self.k = k
177
178 5a8bb489 Bob Lantz
        switch = self.add_switch('s1')
179
        for h in irange(1, k):
180
            host = self.add_host('h%s' % h)
181
            self.add_link(host, switch)
182 433a7cc8 Brandon Heller
183
184 78606a35 Bob Lantz
class SingleSwitchReversedTopo(Topo):
185 6d2cd77b Brandon Heller
    '''Single switch connected to k hosts, with reversed ports.
186

187
    The lowest-numbered host is connected to the highest-numbered port.
188

189
    Useful to verify that Mininet properly handles custom port numberings.
190
    '''
191 e1246c37 Bob Lantz
    def __init__(self, k=2, **opts):
192
        '''Init.
193 6d2cd77b Brandon Heller

194 e1246c37 Bob Lantz
        @param k number of hosts
195
        @param enable_all enables all nodes and switches?
196 6d2cd77b Brandon Heller
        '''
197 78606a35 Bob Lantz
        super(SingleSwitchReversedTopo, self).__init__(**opts)
198 e1246c37 Bob Lantz
        self.k = k
199
        switch = self.add_switch('s1')
200
        for h in irange(1, k):
201
            host = self.add_host('h%s' % h)
202 78606a35 Bob Lantz
            self.add_link(host, switch,
203 e1246c37 Bob Lantz
                          port1=0, port2=(k - h + 1))
204 6d2cd77b Brandon Heller
205 433a7cc8 Brandon Heller
class LinearTopo(Topo):
206 5a8bb489 Bob Lantz
    "Linear topology of k switches, with one host per switch."
207 433a7cc8 Brandon Heller
208 5a8bb489 Bob Lantz
    def __init__(self, k=2, **opts):
209
        """Init.
210
           k: number of switches (and hosts)
211
           hconf: host configuration options
212
           lconf: link configuration options"""
213 433a7cc8 Brandon Heller
214 5a8bb489 Bob Lantz
        super(LinearTopo, self).__init__(**opts)
215 433a7cc8 Brandon Heller
216
        self.k = k
217
218 5a8bb489 Bob Lantz
        lastSwitch = None
219
        for i in irange(1, k):
220
            host = self.add_host('h%s' % i)
221
            switch = self.add_switch('s%s' % i)
222
            self.add_link( host, switch)
223
            if lastSwitch:
224
                self.add_link( switch, lastSwitch)
225
            lastSwitch = switch