blob: 35b97620e0d5d901d3ef2f32c548c9df774618e6 [file] [log] [blame]
Pierfff5db62020-01-21 18:41:55 +01001#!/usr/bin/python
2
3import sys
4sys.path.append('..')
5from mininet.topo import Topo
6from mininet.cli import CLI
7from mininet.log import setLogLevel
8from mininet.node import RemoteController, OVSBridge, Host, OVSSwitch
9from mininet.link import TCLink
10from mininet.nodelib import NAT
11from ipaddress import ip_network
12from routinglib import BgpRouter
13from routinglib import RoutedHost, RoutedHost6
14from trellislib import DhcpClient, Dhcp6Client, Dhcp4and6Client, DhcpRelay, DhcpServer, Dhcp6Server
15from trellislib import DualHomedDhcpClient
16from trellislib import DualHomedDhcp4and6Client
17from trellislib import get_mininet, parse_trellis_args, set_up_zebra_config, get_mac_from_int
18from functools import partial
19
20MAX_AGGREGATION = 4
21MAX_ACCESS = 48
22
23class Trellis( Topo ):
24 """Trellis HAG topology"""
25
26 def __init__( self, *args, **kwargs ):
27 Topo.__init__( self, *args, **kwargs )
28
29 # Spines
30 s226 = self.addSwitch('s226', dpid='226')
31 s227 = self.addSwitch('s227', dpid='227')
32
33 # Leaves
34 s203 = self.addSwitch('s203', dpid='203')
35 s204 = self.addSwitch('s204', dpid='204')
36 s205 = self.addSwitch('s205', dpid='205')
37 s206 = self.addSwitch('s206', dpid='206')
38
39 # Leaf-Spine Links
40 self.addLink(s226, s203)
41 self.addLink(s226, s203)
42 self.addLink(s226, s204)
43 self.addLink(s226, s204)
44 self.addLink(s226, s205)
45 self.addLink(s226, s205)
46 self.addLink(s226, s206)
47 self.addLink(s226, s206)
48 self.addLink(s227, s203)
49 self.addLink(s227, s203)
50 self.addLink(s227, s204)
51 self.addLink(s227, s204)
52 self.addLink(s227, s205)
53 self.addLink(s227, s205)
54 self.addLink(s227, s206)
55 self.addLink(s227, s206)
56
57 # Leaf-Leaf Links
58 self.addLink(s203, s204)
59 self.addLink(s205, s206)
60
61 # NOTE avoid using 10.0.1.0/24 which is the default subnet of quaggas
62 # NOTE avoid using 00:00:00:00:00:xx which is the default mac of host behind upstream router
63 # IPv4 Hosts
64 h1 = self.addHost('h1', cls=DhcpClient, mac='00:aa:00:00:00:01')
65 h2 = self.addHost('h2', cls=DhcpClient, mac='00:aa:00:00:00:02')
66 h3 = self.addHost('h3', cls=DhcpClient, mac='00:aa:00:00:00:03')
67 h4 = self.addHost('h4', cls=DhcpClient, mac='00:aa:00:00:00:04')
68 h5 = self.addHost('h5', cls=DhcpClient, mac='00:aa:00:00:00:05')
69 self.addLink(h1, s204)
70 self.addLink(h2, s204)
71 self.addLink(h3, s205)
72 self.addLink(h4, s205)
73 self.addLink(h5, s203)
74
75 # IPv6 Hosts
76 h1v6 = self.addHost('h1v6', cls=Dhcp6Client, mac='00:bb:00:00:00:01', sleep=0.250)
77 h2v6 = self.addHost('h2v6', cls=Dhcp6Client, mac='00:bb:00:00:00:02', sleep=0.250)
78 h3v6 = self.addHost('h3v6', cls=Dhcp6Client, mac='00:bb:00:00:00:03', sleep=0.250)
79 h4v6 = self.addHost('h4v6', cls=Dhcp6Client, mac='00:bb:00:00:00:04', sleep=0.250)
80 h5v6 = self.addHost('h5v6', cls=Dhcp6Client, mac='00:bb:00:00:00:05', sleep=0.250)
81 self.addLink(h1v6, s204)
82 self.addLink(h2v6, s204)
83 self.addLink(h3v6, s205)
84 self.addLink(h4v6, s205)
85 self.addLink(h5v6, s203)
86
87 # Dual-homed IPv4 and IPv6 Host on 203-204
88 dh1 = self.addHost('dh1', cls=DualHomedDhcp4and6Client, mac='00:cc:00:00:00:01', sleep=0.250)
89 self.addLink(dh1, s204)
90 self.addLink(dh1, s203)
91
92 # DHCP server
93 dhcp = self.addHost('dhcp', cls=DhcpServer, mac='00:99:00:00:00:01', ips=['10.0.3.253/24'], gateway='10.0.3.254')
94
95 # DHCPv6 server
96 dhcp6 = self.addHost('dhcp6', cls=Dhcp6Server, mac='00:99:66:00:00:01', ips=['2000::3fd/120'], gateway='2000::3ff')
97
98 # Dataplane L2 plane switch (for DHCP servers)
99 cs1 = self.addSwitch('cs1', cls=OVSBridge)
100 self.addLink(cs1, s205)
101 self.addLink(dhcp, cs1)
102 self.addLink(dhcp6, cs1)
103
104 # Control plane switch (for quagga fpm)
105 cs0 = self.addSwitch('cs0', cls=OVSBridge)
106
107 # Control plane NAT (for quagga fpm)
108 nat = self.addHost('nat', cls=NAT,
109 ip='172.16.0.1/12',
110 subnet=str(ip_network(u'172.16.0.0/12')), inNamespace=False)
111 self.addLink(cs0, nat)
112
113 # Internal Quagga bgp1
114 """
115 intfs = {'bgp1-eth0': [{'ipAddrs': ['10.0.1.2/24', '2000::102/120'], 'mac': '00:88:00:00:00:03', 'vlan': '110'},
116 {'ipAddrs': ['10.0.7.2/24', '2000::702/120'], 'mac': '00:88:00:00:00:03', 'vlan': '170'}],
117 'bgp1-eth1': {'ipAddrs': ['172.16.0.3/12']}}
118 """
119 intfs = {'bgp1-eth0': {'ipAddrs': ['10.0.1.2/24', '2000::102/120'], 'mac': '00:88:00:00:00:03', 'vlan': '110'},
120 'bgp1-eth1': {'ipAddrs': ['172.16.0.3/12']}}
121 bgp1 = self.addHost('bgp1', cls=BgpRouter,
122 interfaces=intfs,
123 quaggaConfFile='./bgpdbgp1.conf',
124 zebraConfFile='./zebradbgp1.conf')
125 self.addLink(bgp1, s205)
126 self.addLink(bgp1, cs0)
127
128 # Internal Quagga bgp2
129 """
130 intfs = {'bgp2-eth0': [{'ipAddrs': ['10.0.5.2/24', '2000::502/120'], 'mac': '00:88:00:00:00:04', 'vlan': '150'},
131 {'ipAddrs': ['10.0.6.2/24', '2000::602/120'], 'mac': '00:88:00:00:00:04', 'vlan': '160'}],
132 'bgp2-eth1': {'ipAddrs': ['172.16.0.4/12']}}
133 """
134 intfs = {'bgp2-eth0': {'ipAddrs': ['10.0.6.2/24', '2000::602/120'], 'mac': '00:88:00:00:00:04', 'vlan': '160'},
135 'bgp2-eth1': {'ipAddrs': ['172.16.0.4/12']}}
136 bgp2 = self.addHost('bgp2', cls=BgpRouter,
137 interfaces=intfs,
138 quaggaConfFile='./bgpdbgp2.conf',
139 zebraConfFile='./zebradbgp2.conf')
140 self.addLink(bgp2, s206)
141 self.addLink(bgp2, cs0)
142
143 # External Quagga r1
144 intfs = {'r1-eth0': {'ipAddrs': ['10.0.1.1/24', '2000::101/120'], 'mac': '00:88:00:00:00:01'},
145 #'r1-eth1': {'ipAddrs': ['10.0.5.1/24', '2000::501/120'], 'mac': '00:88:00:00:00:11'},
146 'r1-eth1': {'ipAddrs': ['10.0.99.1/16']},
147 'r1-eth2': {'ipAddrs': ['2000::9901/120']},
148 'r1-eth3': {'ipAddrs': ['2000::7701/120']}}
149 r1 = self.addHost('r1', cls=BgpRouter,
150 interfaces=intfs,
151 quaggaConfFile='./bgpdr1.conf')
152 self.addLink(r1, s205)
153
154 # External IPv4 Host behind r1
155 rh1 = self.addHost('rh1', cls=RoutedHost, ips=['10.0.99.2/24'], gateway='10.0.99.1')
156 self.addLink(r1, rh1)
157
158 # External IPv6 Host behind r1
159 rh1v6 = self.addHost('rh1v6', cls=RoutedHost, ips=['2000::9902/120'], gateway='2000::9901')
160 self.addLink(r1, rh1v6)
161
162 # Another external IPv6 Host behind r1
163 rh11v6 = self.addHost('rh11v6', cls=RoutedHost, ips=['2000::7702/120'], gateway='2000::7701')
164 self.addLink(r1, rh11v6)
165
166 # External Quagga r2
167 intfs = {'r2-eth0': {'ipAddrs': ['10.0.6.1/24', '2000::601/120'], 'mac': '00:88:00:00:00:02'},
168 #'r2-eth1': {'ipAddrs': ['10.0.7.1/24', '2000::701/120'], 'mac': '00:88:00:00:00:22'},
169 'r2-eth1': {'ipAddrs': ['10.0.99.1/16']},
170 'r2-eth2': {'ipAddrs': ['2000::9901/120']},
171 'r2-eth3': {'ipAddrs': ['2000::8801/120']}}
172 r2 = self.addHost('r2', cls=BgpRouter,
173 interfaces=intfs,
174 quaggaConfFile='./bgpdr2.conf')
175 self.addLink(r2, s206)
176
177 # External IPv4 Host behind r2
178 rh2 = self.addHost('rh2', cls=RoutedHost, ips=['10.0.99.2/24'], gateway='10.0.99.1')
179 self.addLink(r2, rh2)
180
181 # External IPv6 Host behind r2
182 rh2v6 = self.addHost('rh126', cls=RoutedHost, ips=['2000::9902/120'], gateway='2000::9901')
183 self.addLink(r2, rh2v6)
184
185 # Another external IPv6 Host behind r1
186 rh22v6 = self.addHost('rh22v6', cls=RoutedHost, ips=['2000::8802/120'], gateway='2000::8801')
187 self.addLink(r2, rh22v6)
188
189 # Dual-homed IPv4 Host for 205-206
190 dh2 = self.addHost('dh2', cls=DualHomedDhcpClient, mac='00:cc:00:00:00:02')
191 self.addLink(dh2, s205)
192 self.addLink(dh2, s206)
193
194 # ----- Secondary fabric -----
195
196 # Spines(HAG)
197 s246 = self.addSwitch('s246', dpid='246')
198 s247 = self.addSwitch('s247', dpid='247')
199
200 # HAG - Spine Links
201 self.addLink(s246, s226)
202 self.addLink(s247, s227)
203
204 # Access network - aggregation switches and access devices
205 aggregation = int(args[0])
206 aggregation = min(max(0, aggregation), MAX_AGGREGATION)
207 for i in range(0, aggregation):
208 # Adding the aggregation switch
209 aggregation_dev = self.addSwitch('s%d' % (i + 1) , dpid='%s' % (i + 1))
210 # Adding MAX_ACCESS access devices
211 for j in range (1, MAX_ACCESS + 1):
212 mac_int = j + (MAX_ACCESS * i)
213 mac = get_mac_from_int(mac_int)
214 # Half are IPv6 and half are IPv4
215 if j % 2 == 0:
216 access_dev = self.addHost('acc%d' % mac_int, cls=Dhcp6Client, mac=mac, sleep=0.250)
217 else:
218 access_dev = self.addHost('acc%d' % mac_int, cls=DhcpClient, mac=mac)
219 self.addLink(aggregation_dev, access_dev)
220 # HAG - Aggregation Links
221 self.addLink(s246, aggregation_dev)
222 self.addLink(s247, aggregation_dev)
223
224topos = { 'trellis' : Trellis }
225
226if __name__ == "__main__":
227 setLogLevel('info')
228 arguments = parse_trellis_args()
229
230 topo = Trellis(arguments.aggregation)
231 switch = partial(OVSSwitch, protocols='OpenFlow13')
232 set_up_zebra_config(arguments.controllers)
233 net = get_mininet(arguments, topo, switch)
234
235 net.start()
236 CLI(net)
237 net.stop()