blob: 1383cc964f975f3abdebb91c6ce9d273cc06dbff [file] [log] [blame]
Charles Chanb0dd5ed2017-03-29 17:36:21 -07001#!/usr/bin/python
2
3import sys
4sys.path.append('..')
5from mininet.topo import Topo
6from mininet.net import Mininet
7from mininet.cli import CLI
8from mininet.log import setLogLevel
9from mininet.node import RemoteController, OVSBridge, Host
10from mininet.link import TCLink
11from mininet.nodelib import NAT
12from ipaddress import ip_network
13from routinglib import BgpRouter
14from routinglib import RoutedHost
15
16class Trellis( Topo ):
17 "Trellis basic topology"
18
19 def __init__( self, *args, **kwargs ):
20 Topo.__init__( self, *args, **kwargs )
21
22 # Spines
23 s226 = self.addSwitch('s226', dpid='226')
24 s227 = self.addSwitch('s227', dpid='227')
25
26 # Leaves
27 s203 = self.addSwitch('s203', dpid='203')
28 s204 = self.addSwitch('s204', dpid='204')
29 s205 = self.addSwitch('s205', dpid='205')
30 s206 = self.addSwitch('s206', dpid='206')
31
32 # Leaf-Spine Links
33 self.addLink(s226, s203)
34 self.addLink(s226, s203)
35 self.addLink(s226, s204)
36 self.addLink(s226, s204)
37 self.addLink(s226, s205)
38 self.addLink(s226, s205)
39 self.addLink(s226, s206)
40 self.addLink(s226, s206)
41 self.addLink(s227, s203)
42 self.addLink(s227, s203)
43 self.addLink(s227, s204)
44 self.addLink(s227, s204)
45 self.addLink(s227, s205)
46 self.addLink(s227, s205)
47 self.addLink(s227, s206)
48 self.addLink(s227, s206)
49
50 # Leaf-Leaf Links
51 self.addLink(s203, s204)
52 self.addLink(s205, s206)
53
54 # NOTE avoid using 10.0.1.0/24 which is the default subnet of quaggas
55 # NOTE avoid using 00:00:00:00:00:xx which is the default mac of host behind upstream router
56 # IPv4 Hosts
57 h1 = self.addHost('h1', cls=DhcpClient, mac='00:aa:00:00:00:01')
58 h2 = self.addHost('h2', cls=DhcpClient, mac='00:aa:00:00:00:02')
59 h3 = self.addHost('h3', cls=DhcpClient, mac='00:aa:00:00:00:03')
60 h4 = self.addHost('h4', cls=DhcpClient, mac='00:aa:00:00:00:04')
61 self.addLink(h1, s204)
62 self.addLink(h2, s204)
63 self.addLink(h3, s205)
64 self.addLink(h4, s205)
65
66 # IPv6 Hosts
67 h1v6 = self.addHost('h1v6', cls=RoutedHost, mac='00:bb:00:00:00:01', ips=['2000::201/120'], gateway='2000::2ff')
68 h2v6 = self.addHost('h2v6', cls=RoutedHost, mac='00:bb:00:00:00:02', ips=['2000::202/120'], gateway='2000::2ff')
69 h3v6 = self.addHost('h3v6', cls=RoutedHost, mac='00:bb:00:00:00:03', ips=['2000::301/120'], gateway='2000::3ff')
70 h4v6 = self.addHost('h4v6', cls=RoutedHost, mac='00:bb:00:00:00:04', ips=['2000::302/120'], gateway='2000::3ff')
71 self.addLink(h1v6, s204)
72 self.addLink(h2v6, s204)
73 self.addLink(h3v6, s205)
74 self.addLink(h4v6, s205)
75
76 # Dual-homed IPv4 Hosts
77 dh1 = self.addHost('dh1', cls=DualHomedDhcpClient, mac='00:cc:00:00:00:01')
78 self.addLink(dh1, s204)
79 self.addLink(dh1, s203)
80
81 # DHCP server
82 dhcp = self.addHost('dhcp', cls=DhcpServer, mac='00:99:00:00:00:01', ips=['10.0.3.253/24'], gateway='10.0.3.254')
83 self.addLink(dhcp, s205)
84
85 # Control plane switch (for quagga fpm)
86 cs0 = self.addSwitch('cs0', cls=OVSBridge)
87
88 # Control plane NAT (for quagga fpm)
89 nat = self.addHost('nat', cls=NAT,
90 ip='172.16.0.1/12',
91 subnet=str(ip_network(u'172.16.0.0/12')), inNamespace=False)
92 self.addLink(cs0, nat)
93
94 # Internal Quagga bgp1
95 intfs = {'bgp1-eth0': {'ipAddrs': ['10.0.1.2/24', '2000::102/120'], 'mac': '00:88:00:00:00:02'},
96 'bgp1-eth1': {'ipAddrs': ['172.16.0.2/12']}}
97 bgp1 = self.addHost('bgp1', cls=BgpRouter,
98 interfaces=intfs,
99 quaggaConfFile='./bgpdbgp1.conf',
100 zebraConfFile='./zebradbgp1.conf')
101 self.addLink(bgp1, s205)
102 self.addLink(bgp1, cs0)
103
104 # External Quagga r1
105 intfs = {'r1-eth0': {'ipAddrs': ['10.0.1.1/24', '2000::101/120'], 'mac': '00:88:00:00:00:01'},
106 'r1-eth1': {'ipAddrs': ['10.0.99.1/16']},
107 'r1-eth2': {'ipAddrs': ['2000::9901/120']}}
108 r1 = self.addHost('r1', cls=BgpRouter,
109 interfaces=intfs,
110 quaggaConfFile='./bgpdr1.conf')
111 self.addLink(r1, s205)
112
113 # External IPv4 Host behind r1
114 rh1 = self.addHost('rh1', cls=RoutedHost, ips=['10.0.99.2/24'], gateway='10.0.99.1')
115 self.addLink(r1, rh1)
116
117 # External IPv6 Host behind r1
118 rh1v6 = self.addHost('rh1v6', cls=RoutedHost, ips=['2000::9902/120'], gateway='2000::9901')
119 self.addLink(r1, rh1v6)
120
121topos = { 'trellis' : Trellis }
122
123# TODO extract dhcp classes to a separate library
124class DhcpClient(Host):
125 def __init__(self, name, *args, **kwargs):
126 super(DhcpClient, self).__init__(name, **kwargs)
127 self.pidFile = '/run/dhclient-%s.pid' % self.name
128
129 def config(self, **kwargs):
130 super(DhcpClient, self).config(**kwargs)
131 self.cmd('ip addr flush dev %s' % self.defaultIntf())
132 self.cmd('dhclient -q -4 -nw -pf %s %s' % (self.pidFile, self.defaultIntf()))
133
134 def terminate(self, **kwargs):
135 self.cmd('kill -9 `cat %s`' % self.pidFile)
136 self.cmd('rm -rf %s' % self.pidFile)
137 super(DhcpClient, self).terminate()
138
139class DualHomedDhcpClient(Host):
140 def __init__(self, name, *args, **kwargs):
141 super(DualHomedDhcpClient, self).__init__(name, **kwargs)
142 self.pidFile = '/run/dhclient-%s.pid' % self.name
143 self.bond0 = None
144
145 def config(self, **kwargs):
146 super(DualHomedDhcpClient, self).config(**kwargs)
147 intf0 = self.intfs[0].name
148 intf1 = self.intfs[1].name
149 self.bond0 = "%s-bond0" % self.name
150 self.cmd('modprobe bonding')
151 self.cmd('ip link add %s type bond' % self.bond0)
152 self.cmd('ip link set %s down' % intf0)
153 self.cmd('ip link set %s down' % intf1)
154 self.cmd('ip link set %s master %s' % (intf0, self.bond0))
155 self.cmd('ip link set %s master %s' % (intf1, self.bond0))
156 self.cmd('ip addr flush dev %s' % intf0)
157 self.cmd('ip addr flush dev %s' % intf1)
158 self.cmd('ip link set %s up' % self.bond0)
159 self.cmd('dhclient -q -4 -nw -pf %s %s' % (self.pidFile, self.bond0))
160
161 def terminate(self, **kwargs):
162 self.cmd('ip link set %s down' % self.bond0)
163 self.cmd('ip link delete %s' % self.bond0)
164 self.cmd('kill -9 `cat %s`' % self.pidFile)
165 self.cmd('rm -rf %s' % self.pidFile)
166 super(DualHomedDhcpClient, self).terminate()
167
168class DhcpServer(RoutedHost):
169 binFile = '/usr/sbin/dhcpd'
170 pidFile = '/run/dhcp-server/dhcpd.pid'
171 configFile = './dhcpd.conf'
172
173 def config(self, **kwargs):
174 super(DhcpServer, self).config(**kwargs)
175 self.cmd('%s -q -4 -pf %s -cf %s %s' % (self.binFile, self.pidFile, self.configFile, self.defaultIntf()))
176
177 def terminate(self, **kwargs):
178 self.cmd('kill -9 `cat %s`' % self.pidFile)
179 self.cmd('rm -rf %s' % self.pidFile)
180 super(DhcpServer, self).terminate()
181
182if __name__ == "__main__":
183 setLogLevel('debug')
184 topo = Trellis()
185
186 net = Mininet(topo=topo, controller=None)
187 net.addController(RemoteController('c0', ip='192.168.56.11'))
188 net.addController(RemoteController('c1', ip='192.168.56.12'))
189 net.addController(RemoteController('c2', ip='192.168.56.13'))
190
191 net.start()
192 CLI(net)
193 net.stop()