blob: 56216729c0615d11d6e968c3dca98e7c786fc747 [file] [log] [blame]
Charles Chan6e29b322017-04-11 11:10:31 -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.nodelib import NAT
11from ipaddress import ip_network
12from routinglib import BgpRouter
13from routinglib import RoutedHost
14
15class Trellis( Topo ):
16 "Trellis basic topology"
17
18 def __init__( self, *args, **kwargs ):
19 Topo.__init__( self, *args, **kwargs )
20
21 # Spines
22 s226 = self.addSwitch('s226', dpid='226')
23 s227 = self.addSwitch('s227', dpid='227')
24
25 # Leaves
26 s204 = self.addSwitch('s204', dpid='204')
27 s205 = self.addSwitch('s205', dpid='205')
28
29 # Switch Links
30 self.addLink(s226, s204)
31 self.addLink(s226, s205)
32 self.addLink(s227, s204)
33 self.addLink(s227, s205)
34
35 # NOTE avoid using 10.0.1.0/24 which is the default subnet of quaggas
36 # NOTE avoid using 00:00:00:00:00:xx which is the default mac of host behind upstream router
37 # IPv4 Hosts
38 h1 = self.addHost('h1', cls=DhcpClient, mac='00:aa:00:00:00:01')
39 h2 = self.addHost('h2', cls=TaggedDhcpClient, mac='00:aa:00:00:00:02', vlan=20)
40 h3 = self.addHost('h3', cls=DhcpClient, mac='00:aa:00:00:00:03')
Charles Chan279fabf2017-04-24 15:33:14 -070041 h4 = self.addHost('h4', cls=DhcpClient, mac='00:aa:00:00:00:04')
42 # In order to emulate tagged Quagga VM in h4
43 h4ovs = self.addSwitch('h4ovs', cls=OVSBridge)
Charles Chan6e29b322017-04-11 11:10:31 -070044 self.addLink(h1, s204)
45 self.addLink(h2, s204)
46 self.addLink(h3, s205)
Charles Chan279fabf2017-04-24 15:33:14 -070047 self.addLink(h4ovs, s205)
48 self.addLink(h4ovs, h4)
Charles Chan6e29b322017-04-11 11:10:31 -070049
50 # IPv6 Hosts
51 h1v6 = self.addHost('h1v6', cls=RoutedHost, mac='00:bb:00:00:00:01', ips=['2000::201/120'], gateway='2000::2ff')
52 h2v6 = self.addHost('h2v6', cls=RoutedHost, mac='00:bb:00:00:00:02', ips=['2000::202/120'], gateway='2000::2ff')
53 h3v6 = self.addHost('h3v6', cls=RoutedHost, mac='00:bb:00:00:00:03', ips=['2000::301/120'], gateway='2000::3ff')
54 h4v6 = self.addHost('h4v6', cls=RoutedHost, mac='00:bb:00:00:00:04', ips=['2000::302/120'], gateway='2000::3ff')
55 self.addLink(h1v6, s204)
56 self.addLink(h2v6, s204)
57 self.addLink(h3v6, s205)
58 self.addLink(h4v6, s205)
59
60 # DHCP server
61 dhcp = self.addHost('dhcp', cls=TaggedDhcpServer, mac='00:99:00:00:00:01', ips=['10.0.3.253/24'], gateway='10.0.3.254', vlan=30)
62 self.addLink(dhcp, s205)
63
64 # Control plane switch (for quagga fpm)
65 cs0 = self.addSwitch('cs0', cls=OVSBridge)
66
67 # Control plane NAT (for quagga fpm)
68 nat = self.addHost('nat', cls=NAT,
69 ip='172.16.0.1/12',
70 subnet=str(ip_network(u'172.16.0.0/12')), inNamespace=False)
71 self.addLink(cs0, nat)
72
73 # Internal Quagga bgp1
Charles Chan279fabf2017-04-24 15:33:14 -070074 intfs = {'bgp1-eth0': {'ipAddrs': ['10.0.1.2/24', '2000::102/120'], 'mac': '00:88:00:00:00:02', 'vlan': '10'},
Charles Chan6e29b322017-04-11 11:10:31 -070075 'bgp1-eth1': {'ipAddrs': ['172.16.0.2/12']}}
76 bgp1 = self.addHost('bgp1', cls=BgpRouter,
77 interfaces=intfs,
78 quaggaConfFile='./bgpdbgp1.conf',
79 zebraConfFile='./zebradbgp1.conf')
Charles Chan279fabf2017-04-24 15:33:14 -070080 self.addLink(bgp1, h4ovs)
Charles Chan6e29b322017-04-11 11:10:31 -070081 self.addLink(bgp1, cs0)
82
83 # External Quagga r1
84 intfs = {'r1-eth0': {'ipAddrs': ['10.0.1.1/24', '2000::101/120'], 'mac': '00:88:00:00:00:01'},
85 'r1-eth1': {'ipAddrs': ['10.0.99.1/16']},
86 'r1-eth2': {'ipAddrs': ['2000::9901/120']}}
87 r1 = self.addHost('r1', cls=BgpRouter,
88 interfaces=intfs,
89 quaggaConfFile='./bgpdr1.conf')
90 self.addLink(r1, s205)
91
92 # External IPv4 Host behind r1
93 rh1 = self.addHost('rh1', cls=RoutedHost, ips=['10.0.99.2/24'], gateway='10.0.99.1')
94 self.addLink(r1, rh1)
95
96 # External IPv6 Host behind r1
97 rh1v6 = self.addHost('rh1v6', cls=RoutedHost, ips=['2000::9902/120'], gateway='2000::9901')
98 self.addLink(r1, rh1v6)
99
100topos = { 'trellis' : Trellis }
101
102class DhcpClient(Host):
103 def __init__(self, name, *args, **kwargs):
104 super(DhcpClient, self).__init__(name, **kwargs)
105 self.pidFile = '/run/dhclient-%s.pid' % self.name
106
107 def config(self, **kwargs):
108 super(DhcpClient, self).config(**kwargs)
109 self.cmd('ip addr flush dev %s' % self.defaultIntf())
110 self.cmd('dhclient -q -4 -nw -pf %s %s' % (self.pidFile, self.defaultIntf()))
111
112 def terminate(self, **kwargs):
113 self.cmd('kill -9 `cat %s`' % self.pidFile)
114 self.cmd('rm -rf %s' % self.pidFile)
115 super(DhcpClient, self).terminate()
116
117class TaggedDhcpClient(Host):
118 def __init__(self, name, vlan, *args, **kwargs):
119 super(TaggedDhcpClient, self).__init__(name, **kwargs)
120 self.pidFile = '/run/dhclient-%s.pid' % self.name
121 self.vlan = vlan
122 self.vlanIntf = None
123
124 def config(self, **kwargs):
125 super(TaggedDhcpClient, self).config(**kwargs)
126 self.vlanIntf = "%s.%s" % (self.defaultIntf(), self.vlan)
127 self.cmd('ip addr flush dev %s' % self.defaultIntf())
128 self.cmd('ip link add link %s name %s type vlan id %s' % (self.defaultIntf(), self.vlanIntf, self.vlan))
129 self.cmd('ip link set up %s' % self.vlanIntf)
130 self.cmd('dhclient -q -4 -nw -pf %s %s' % (self.pidFile, self.vlanIntf))
131
132 def terminate(self, **kwargs):
133 self.cmd('kill -9 `cat %s`' % self.pidFile)
134 self.cmd('rm -rf %s' % self.pidFile)
135 self.cmd('ip link remove link %s' % self.vlanIntf)
136 super(TaggedDhcpClient, self).terminate()
137
138class DhcpServer(RoutedHost):
139 binFile = '/usr/sbin/dhcpd'
140 pidFile = '/run/dhcp-server/dhcpd.pid'
141 configFile = './dhcpd.conf'
142
143 def config(self, **kwargs):
144 super(DhcpServer, self).config(**kwargs)
145 self.cmd('%s -q -4 -pf %s -cf %s %s' % (self.binFile, self.pidFile, self.configFile, self.defaultIntf()))
146
147 def terminate(self, **kwargs):
148 self.cmd('kill -9 `cat %s`' % self.pidFile)
149 self.cmd('rm -rf %s' % self.pidFile)
150 super(DhcpServer, self).terminate()
151
152class TaggedRoutedHost(RoutedHost):
153 """Host that can be configured with multiple IP addresses."""
154 def __init__(self, name, ips, gateway, vlan, *args, **kwargs):
155 super(RoutedHost, self).__init__(name, *args, **kwargs)
156 self.ips = ips
157 self.gateway = gateway
158 self.vlan = vlan
159 self.vlanIntf = None
160
161 def config(self, **kwargs):
162 Host.config(self, **kwargs)
163 self.vlanIntf = "%s.%s" % (self.defaultIntf(), self.vlan)
164 self.cmd('ip -4 addr flush dev %s' % self.defaultIntf())
165 self.cmd('ip link add link %s name %s type vlan id %s' % (self.defaultIntf(), self.vlanIntf, self.vlan))
166 self.cmd('ip link set up %s' % self.vlanIntf)
167
168 for ip in self.ips:
169 self.cmd('ip addr add %s dev %s' % (ip, self.vlanIntf))
170
171 self.cmd('ip route add default via %s' % self.gateway)
172
173 def terminate(self, **kwargs):
174 self.cmd('ip link remove link %s' % self.vlanIntf)
175 super(TaggedRoutedHost, self).terminate()
176
177class TaggedDhcpServer(TaggedRoutedHost):
178 binFile = '/usr/sbin/dhcpd'
179 pidFile = '/run/dhcp-server/dhcpd.pid'
180 configFile = './dhcpd.conf'
181
182 def config(self, **kwargs):
183 super(TaggedDhcpServer, self).config(**kwargs)
184 self.cmd('%s -q -4 -pf %s -cf %s %s' % (self.binFile, self.pidFile, self.configFile, self.vlanIntf))
185
186 def terminate(self, **kwargs):
187 self.cmd('kill -9 `cat %s`' % self.pidFile)
188 self.cmd('rm -rf %s' % self.pidFile)
189 super(TaggedDhcpServer, self).terminate()
190
191if __name__ == "__main__":
192 setLogLevel('debug')
193 topo = Trellis()
194
195 net = Mininet(topo=topo, controller=None)
196 net.addController(RemoteController('c0', ip='192.168.56.11'))
197 net.addController(RemoteController('c1', ip='192.168.56.12'))
198 net.addController(RemoteController('c2', ip='192.168.56.13'))
199
200 net.start()
201 CLI(net)
202 net.stop()