blob: 1b29008eed3080b6235e2d634679585eb9f5a8f4 [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')
41 h4 = self.addHost('h4', cls=TaggedDhcpClient, mac='00:aa:00:00:00:04', vlan=30)
42 self.addLink(h1, s204)
43 self.addLink(h2, s204)
44 self.addLink(h3, s205)
45 self.addLink(h4, s205)
46
47 # IPv6 Hosts
48 h1v6 = self.addHost('h1v6', cls=RoutedHost, mac='00:bb:00:00:00:01', ips=['2000::201/120'], gateway='2000::2ff')
49 h2v6 = self.addHost('h2v6', cls=RoutedHost, mac='00:bb:00:00:00:02', ips=['2000::202/120'], gateway='2000::2ff')
50 h3v6 = self.addHost('h3v6', cls=RoutedHost, mac='00:bb:00:00:00:03', ips=['2000::301/120'], gateway='2000::3ff')
51 h4v6 = self.addHost('h4v6', cls=RoutedHost, mac='00:bb:00:00:00:04', ips=['2000::302/120'], gateway='2000::3ff')
52 self.addLink(h1v6, s204)
53 self.addLink(h2v6, s204)
54 self.addLink(h3v6, s205)
55 self.addLink(h4v6, s205)
56
57 # DHCP server
58 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)
59 self.addLink(dhcp, s205)
60
61 # Control plane switch (for quagga fpm)
62 cs0 = self.addSwitch('cs0', cls=OVSBridge)
63
64 # Control plane NAT (for quagga fpm)
65 nat = self.addHost('nat', cls=NAT,
66 ip='172.16.0.1/12',
67 subnet=str(ip_network(u'172.16.0.0/12')), inNamespace=False)
68 self.addLink(cs0, nat)
69
70 # Internal Quagga bgp1
71 intfs = {'bgp1-eth0': {'ipAddrs': ['10.0.1.2/24', '2000::102/120'], 'mac': '00:88:00:00:00:02'},
72 'bgp1-eth1': {'ipAddrs': ['172.16.0.2/12']}}
73 bgp1 = self.addHost('bgp1', cls=BgpRouter,
74 interfaces=intfs,
75 quaggaConfFile='./bgpdbgp1.conf',
76 zebraConfFile='./zebradbgp1.conf')
77 self.addLink(bgp1, s205)
78 self.addLink(bgp1, cs0)
79
80 # External Quagga r1
81 intfs = {'r1-eth0': {'ipAddrs': ['10.0.1.1/24', '2000::101/120'], 'mac': '00:88:00:00:00:01'},
82 'r1-eth1': {'ipAddrs': ['10.0.99.1/16']},
83 'r1-eth2': {'ipAddrs': ['2000::9901/120']}}
84 r1 = self.addHost('r1', cls=BgpRouter,
85 interfaces=intfs,
86 quaggaConfFile='./bgpdr1.conf')
87 self.addLink(r1, s205)
88
89 # External IPv4 Host behind r1
90 rh1 = self.addHost('rh1', cls=RoutedHost, ips=['10.0.99.2/24'], gateway='10.0.99.1')
91 self.addLink(r1, rh1)
92
93 # External IPv6 Host behind r1
94 rh1v6 = self.addHost('rh1v6', cls=RoutedHost, ips=['2000::9902/120'], gateway='2000::9901')
95 self.addLink(r1, rh1v6)
96
97topos = { 'trellis' : Trellis }
98
99class DhcpClient(Host):
100 def __init__(self, name, *args, **kwargs):
101 super(DhcpClient, self).__init__(name, **kwargs)
102 self.pidFile = '/run/dhclient-%s.pid' % self.name
103
104 def config(self, **kwargs):
105 super(DhcpClient, self).config(**kwargs)
106 self.cmd('ip addr flush dev %s' % self.defaultIntf())
107 self.cmd('dhclient -q -4 -nw -pf %s %s' % (self.pidFile, self.defaultIntf()))
108
109 def terminate(self, **kwargs):
110 self.cmd('kill -9 `cat %s`' % self.pidFile)
111 self.cmd('rm -rf %s' % self.pidFile)
112 super(DhcpClient, self).terminate()
113
114class TaggedDhcpClient(Host):
115 def __init__(self, name, vlan, *args, **kwargs):
116 super(TaggedDhcpClient, self).__init__(name, **kwargs)
117 self.pidFile = '/run/dhclient-%s.pid' % self.name
118 self.vlan = vlan
119 self.vlanIntf = None
120
121 def config(self, **kwargs):
122 super(TaggedDhcpClient, self).config(**kwargs)
123 self.vlanIntf = "%s.%s" % (self.defaultIntf(), self.vlan)
124 self.cmd('ip addr flush dev %s' % self.defaultIntf())
125 self.cmd('ip link add link %s name %s type vlan id %s' % (self.defaultIntf(), self.vlanIntf, self.vlan))
126 self.cmd('ip link set up %s' % self.vlanIntf)
127 self.cmd('dhclient -q -4 -nw -pf %s %s' % (self.pidFile, self.vlanIntf))
128
129 def terminate(self, **kwargs):
130 self.cmd('kill -9 `cat %s`' % self.pidFile)
131 self.cmd('rm -rf %s' % self.pidFile)
132 self.cmd('ip link remove link %s' % self.vlanIntf)
133 super(TaggedDhcpClient, self).terminate()
134
135class DhcpServer(RoutedHost):
136 binFile = '/usr/sbin/dhcpd'
137 pidFile = '/run/dhcp-server/dhcpd.pid'
138 configFile = './dhcpd.conf'
139
140 def config(self, **kwargs):
141 super(DhcpServer, self).config(**kwargs)
142 self.cmd('%s -q -4 -pf %s -cf %s %s' % (self.binFile, self.pidFile, self.configFile, self.defaultIntf()))
143
144 def terminate(self, **kwargs):
145 self.cmd('kill -9 `cat %s`' % self.pidFile)
146 self.cmd('rm -rf %s' % self.pidFile)
147 super(DhcpServer, self).terminate()
148
149class TaggedRoutedHost(RoutedHost):
150 """Host that can be configured with multiple IP addresses."""
151 def __init__(self, name, ips, gateway, vlan, *args, **kwargs):
152 super(RoutedHost, self).__init__(name, *args, **kwargs)
153 self.ips = ips
154 self.gateway = gateway
155 self.vlan = vlan
156 self.vlanIntf = None
157
158 def config(self, **kwargs):
159 Host.config(self, **kwargs)
160 self.vlanIntf = "%s.%s" % (self.defaultIntf(), self.vlan)
161 self.cmd('ip -4 addr flush dev %s' % self.defaultIntf())
162 self.cmd('ip link add link %s name %s type vlan id %s' % (self.defaultIntf(), self.vlanIntf, self.vlan))
163 self.cmd('ip link set up %s' % self.vlanIntf)
164
165 for ip in self.ips:
166 self.cmd('ip addr add %s dev %s' % (ip, self.vlanIntf))
167
168 self.cmd('ip route add default via %s' % self.gateway)
169
170 def terminate(self, **kwargs):
171 self.cmd('ip link remove link %s' % self.vlanIntf)
172 super(TaggedRoutedHost, self).terminate()
173
174class TaggedDhcpServer(TaggedRoutedHost):
175 binFile = '/usr/sbin/dhcpd'
176 pidFile = '/run/dhcp-server/dhcpd.pid'
177 configFile = './dhcpd.conf'
178
179 def config(self, **kwargs):
180 super(TaggedDhcpServer, self).config(**kwargs)
181 self.cmd('%s -q -4 -pf %s -cf %s %s' % (self.binFile, self.pidFile, self.configFile, self.vlanIntf))
182
183 def terminate(self, **kwargs):
184 self.cmd('kill -9 `cat %s`' % self.pidFile)
185 self.cmd('rm -rf %s' % self.pidFile)
186 super(TaggedDhcpServer, self).terminate()
187
188if __name__ == "__main__":
189 setLogLevel('debug')
190 topo = Trellis()
191
192 net = Mininet(topo=topo, controller=None)
193 net.addController(RemoteController('c0', ip='192.168.56.11'))
194 net.addController(RemoteController('c1', ip='192.168.56.12'))
195 net.addController(RemoteController('c2', ip='192.168.56.13'))
196
197 net.start()
198 CLI(net)
199 net.stop()