blob: a998b4e9394ed58844cb8538a23d5f62ad777c7c [file] [log] [blame]
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -07001#!/usr/bin/python
2
3"""
4Libraries for Trellis hosts.
5"""
6
You Wang6cd51b42018-03-08 15:28:25 -08007import time
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -07008import sys
9sys.path.append('..')
10from mininet.node import Host
11from routinglib import RoutedHost, RoutedHost6, Router
12
13class TaggedRoutedHost(RoutedHost):
14 """Host that can be configured with multiple IP addresses."""
15 def __init__(self, name, ips, gateway, vlan, *args, **kwargs):
16 super(RoutedHost, self).__init__(name, *args, **kwargs)
17 self.ips = ips
18 self.gateway = gateway
19 self.vlan = vlan
20 self.vlanIntf = None
21
22 def config(self, **kwargs):
23 Host.config(self, **kwargs)
24 intf = self.defaultIntf()
25 self.vlanIntf = "%s.%s" % (intf, self.vlan)
26 self.cmd('ip -4 addr flush dev %s' % intf)
27 self.cmd('ip link add link %s name %s type vlan id %s' % (intf, self.vlanIntf, self.vlan))
28 self.cmd('ip link set up %s' % self.vlanIntf)
29
30 for ip in self.ips:
31 self.cmd('ip addr add %s dev %s' % (ip, self.vlanIntf))
32
33 self.cmd('ip route add default via %s' % self.gateway)
34 intf.name = self.vlanIntf
35 self.nameToIntf[self.vlanIntf] = intf
36
37 def terminate(self, **kwargs):
38 self.cmd('ip link remove link %s' % self.vlanIntf)
39 super(TaggedRoutedHost, self).terminate()
40
41class DualHomedRoutedHost(Host):
42 def __init__(self, name, ips, gateway, *args, **kwargs):
43 super(DualHomedRoutedHost, self).__init__(name, **kwargs)
44 self.bond0 = None
45 self.ips = ips
46 self.gateway = gateway
47
48 def config(self, **kwargs):
49 super(DualHomedRoutedHost, self).config(**kwargs)
50 intf0 = self.intfs[0].name
51 intf1 = self.intfs[1].name
52 self.bond0 = "%s-bond0" % self.name
53 self.cmd('modprobe bonding')
54 self.cmd('ip link add %s type bond' % self.bond0)
55 self.cmd('ip link set %s down' % intf0)
56 self.cmd('ip link set %s down' % intf1)
57 self.cmd('ip link set %s master %s' % (intf0, self.bond0))
58 self.cmd('ip link set %s master %s' % (intf1, self.bond0))
59 self.cmd('ip addr flush dev %s' % intf0)
60 self.cmd('ip addr flush dev %s' % intf1)
61 self.cmd('ip link set %s up' % self.bond0)
62
63 for ip in self.ips:
64 self.cmd('ip addr add %s dev %s' % (ip, self.bond0))
65
66 self.cmd('ip route add default via %s' % self.gateway)
67 default_intf = self.defaultIntf()
68 default_intf.name = self.bond0
69 self.nameToIntf[self.bond0] = default_intf
70
71 def terminate(self, **kwargs):
72 self.cmd('ip link set %s down' % self.bond0)
73 self.cmd('ip link delete %s' % self.bond0)
74 super(DualHomedRoutedHost, self).terminate()
75
76class DualHomedTaggedRoutedHost(DualHomedRoutedHost):
77 def __init__(self, name, ips, gateway, vlan, *args, **kwargs):
78 super(DualHomedTaggedRoutedHost, self).__init__(name, ips, gateway, *args, **kwargs)
79 self.ips = ips
80 self.gateway = gateway
81 self.vlan = vlan
82 self.vlanIntf = None
83
84 def config(self, **kwargs):
85 super(DualHomedTaggedRoutedHost, self).config(**kwargs)
86 default_intf = self.defaultIntf()
87 self.vlanIntf = "%s.%s" % (default_intf, self.vlan)
88 self.cmd('ip -4 addr flush dev %s' % default_intf)
89 self.cmd('ip link add link %s name %s type vlan id %s' % (default_intf, self.vlanIntf, self.vlan))
90 self.cmd('ip link set up %s' % self.vlanIntf)
91
92 for ip in self.ips:
93 self.cmd('ip addr add %s dev %s' % (ip, self.vlanIntf))
94
95 self.cmd('ip route add default via %s' % self.gateway)
96 default_intf.name = self.vlanIntf
97 self.nameToIntf[self.vlanIntf] = default_intf
98
99 def terminate(self, **kwargs):
100 self.cmd('ip link remove link %s' % self.vlanIntf)
101 super(DualHomedTaggedRoutedHost, self).terminate()
102
103class DhcpClient(Host):
104 def __init__(self, name, *args, **kwargs):
105 super(DhcpClient, self).__init__(name, **kwargs)
106 self.pidFile = '/run/dhclient-%s.pid' % self.name
107 self.leaseFile = '/var/lib/dhcp/dhcpclient-%s.lease' % (self.name, )
108
109 def config(self, **kwargs):
110 super(DhcpClient, self).config(**kwargs)
111 self.cmd('ip addr flush dev %s' % self.defaultIntf())
112 self.cmd('dhclient -q -4 -nw -pf %s -lf %s %s' % (self.pidFile, self.leaseFile, self.defaultIntf()))
113
114 def terminate(self, **kwargs):
115 self.cmd('kill -9 `cat %s`' % self.pidFile)
116 self.cmd('rm -rf %s' % self.pidFile)
117 super(DhcpClient, self).terminate()
118
119class Dhcp6Client(Host):
120 def __init__(self, name, *args, **kwargs):
121 super(Dhcp6Client, self).__init__(name, **kwargs)
122 self.pidFile = '/run/dhclient-%s.pid' % self.name
123 self.leaseFile = '/var/lib/dhcp/dhcpclient6-%s.lease' % (self.name, )
124
125 def config(self, **kwargs):
126 super(Dhcp6Client, self).config(**kwargs)
127 self.cmd('ip -4 addr flush dev %s' % self.defaultIntf())
128 self.cmd('dhclient -q -6 -nw -pf %s -lf %s %s' % (self.pidFile, self.leaseFile, self.defaultIntf()))
129
130 def terminate(self, **kwargs):
131 self.cmd('kill -9 `cat %s`' % self.pidFile)
132 self.cmd('rm -rf %s' % self.pidFile)
133 super(Dhcp6Client, self).terminate()
134
135class DhcpServer(RoutedHost):
136 binFile = '/usr/sbin/dhcpd'
137 pidFile = '/run/dhcp-server-dhcpd.pid'
138 configFile = './dhcpd.conf'
139 leasesFile = '/var/lib/dhcp/dhcpd.leases'
140
141 def config(self, **kwargs):
142 super(DhcpServer, self).config(**kwargs)
143 self.cmd('touch %s' % self.leasesFile)
144 self.cmd('%s -q -4 -pf %s -cf %s %s' % (self.binFile, self.pidFile, self.configFile, self.defaultIntf()))
145
146 def terminate(self, **kwargs):
147 self.cmd('kill -9 `cat %s`' % self.pidFile)
148 self.cmd('rm -rf %s' % self.pidFile)
149 super(DhcpServer, self).terminate()
150
151class Dhcp6Server(RoutedHost6):
152 binFile = '/usr/sbin/dhcpd'
153 pidFile = '/run/dhcp-server-dhcpd6.pid'
154 configFile = './dhcpd6.conf'
155 leasesFile = '/var/lib/dhcp/dhcpd6.leases'
156
157 def config(self, **kwargs):
158 super(Dhcp6Server, self).config(**kwargs)
159 linkLocalAddr = mac_to_ipv6_linklocal(kwargs['mac'])
160 self.cmd('ip -6 addr add dev %s scope link %s' % (self.defaultIntf(), linkLocalAddr))
161 self.cmd('touch %s' % self.leasesFile)
162 self.cmd('%s -q -6 -pf %s -cf %s %s' % (self.binFile, self.pidFile, self.configFile, self.defaultIntf()))
163
164 def terminate(self, **kwargs):
165 self.cmd('kill -9 `cat %s`' % self.pidFile)
166 self.cmd('rm -rf %s' % self.pidFile)
167 self.cmd('rm -rf %s' % self.leasesFile)
168 super(Dhcp6Server, self).terminate()
169
170class DhcpRelay(Router):
171 binFile = '/usr/sbin/dhcrelay'
172 pidFile = '/run/dhcp-relay.pid'
173 serverIp = None
174 gateway = None
175
176 def __init__(self, name, serverIp, gateway, *args, **kwargs):
177 super(DhcpRelay, self).__init__(name, **kwargs)
178 self.serverIp = serverIp
179 self.gateway = gateway
180
181 def config(self, **kwargs):
182 super(DhcpRelay, self).config(**kwargs)
183 ifacesStr = ' '.join(["-i " + ifaceName for ifaceName in self.interfaces.keys()])
184 self.cmd('route add default gw %s' % self.gateway)
185 self.cmd('%s -4 -a -pf %s %s %s' % (self.binFile, self.pidFile, ifacesStr, self.serverIp))
186
187 def terminate(self, **kwargs):
188 self.cmd('kill -9 `cat %s`', self.pidFile)
189 self.cmd('rm -rf %s' % self.pidFile)
190 super(DhcpRelay, self).terminate()
191
192class TaggedDhcpClient(Host):
193 def __init__(self, name, vlan, *args, **kwargs):
194 super(TaggedDhcpClient, self).__init__(name, **kwargs)
195 self.pidFile = '/run/dhclient-%s.pid' % self.name
196 self.vlan = vlan
197 self.vlanIntf = None
198
199 def config(self, **kwargs):
200 super(TaggedDhcpClient, self).config(**kwargs)
201 self.vlanIntf = "%s.%s" % (self.defaultIntf(), self.vlan)
202 self.cmd('ip addr flush dev %s' % self.defaultIntf())
203 self.cmd('ip link add link %s name %s type vlan id %s' % (self.defaultIntf(), self.vlanIntf, self.vlan))
204 self.cmd('ip link set up %s' % self.vlanIntf)
205 self.cmd('dhclient -q -4 -nw -pf %s %s' % (self.pidFile, self.vlanIntf))
206
207 def terminate(self, **kwargs):
208 self.cmd('kill -9 `cat %s`' % self.pidFile)
209 self.cmd('rm -rf %s' % self.pidFile)
210 self.cmd('ip link remove link %s' % self.vlanIntf)
211 super(TaggedDhcpClient, self).terminate()
212
213class TaggedDhcpServer(TaggedRoutedHost):
214 binFile = '/usr/sbin/dhcpd'
215 pidFile = '/run/dhcp-server/dhcpd.pid'
216 configFile = './dhcpd.conf'
217
218 def config(self, **kwargs):
219 super(TaggedDhcpServer, self).config(**kwargs)
220 self.cmd('%s -q -4 -pf %s -cf %s %s' % (self.binFile, self.pidFile, self.configFile, self.vlanIntf))
221
222 def terminate(self, **kwargs):
223 self.cmd('kill -9 `cat %s`' % self.pidFile)
224 self.cmd('rm -rf %s' % self.pidFile)
225 super(TaggedDhcpServer, self).terminate()
226
227class DualHomedDhcpClient(Host):
228 def __init__(self, name, *args, **kwargs):
229 super(DualHomedDhcpClient, self).__init__(name, **kwargs)
230 self.pidFile = '/run/dhclient-%s.pid' % self.name
231 self.bond0 = None
232
233 def config(self, **kwargs):
234 super(DualHomedDhcpClient, self).config(**kwargs)
235 intf0 = self.intfs[0].name
236 intf1 = self.intfs[1].name
237 self.bond0 = "%s-bond0" % self.name
238 self.cmd('modprobe bonding')
239 self.cmd('ip link add %s type bond' % self.bond0)
240 self.cmd('ip link set %s down' % intf0)
241 self.cmd('ip link set %s down' % intf1)
242 self.cmd('ip link set %s master %s' % (intf0, self.bond0))
243 self.cmd('ip link set %s master %s' % (intf1, self.bond0))
244 self.cmd('ip addr flush dev %s' % intf0)
245 self.cmd('ip addr flush dev %s' % intf1)
246 self.cmd('ip link set %s up' % self.bond0)
247 self.cmd('dhclient -q -4 -nw -pf %s %s' % (self.pidFile, self.bond0))
248
249 def terminate(self, **kwargs):
250 self.cmd('ip link set %s down' % self.bond0)
251 self.cmd('ip link delete %s' % self.bond0)
252 self.cmd('kill -9 `cat %s`' % self.pidFile)
253 self.cmd('rm -rf %s' % self.pidFile)
254 super(DualHomedDhcpClient, self).terminate()
255
You Wang5102af12018-02-08 12:30:12 -0800256class TrellisHost(Host):
257 def __init__(self, name, ips=[], gateway="", dualHomed=False, vlan=None, dhcpClient=False, dhcpServer=False, ipv6=False, *args, **kwargs):
258 super(TrellisHost, self).__init__(name, *args, **kwargs)
259 self.dualHomed = dualHomed
260 self.bond0 = None
261 self.vlan = vlan
262 self.vlanIntf = None
263 self.dhcpClient = dhcpClient
264 self.dhcpServer = dhcpServer
265 if dhcpClient:
266 self.pidFile = '/run/dhclient-%s.pid' % self.name
267 self.leaseFile = '/var/lib/dhcp/dhcpclient%s-%s.lease' % ("6" if ipv6 else "", self.name)
268 else:
269 self.ips = ips
270 self.gateway = gateway
271 if dhcpServer:
272 self.binFile = '/usr/sbin/dhcpd'
273 self.pidFile = '/run/dhcp-server-dhcpd%s.pid' % ("6" if ipv6 else "")
274 self.configFile = './dhcpd%s.conf' % ("6" if ipv6 else "")
275 self.leasesFile = '/var/lib/dhcp/dhcpd%s.leases' % ("6" if ipv6 else "")
276 self.ipv6 = ipv6
277
278 def config(self, **kwargs):
279 super(TrellisHost, self).config(**kwargs)
280
281 if self.dualHomed:
282 # Setup bond0 interface
283 intf0 = self.intfs[0].name
284 intf1 = self.intfs[1].name
285 self.bond0 = "%s-bond0" % self.name
286 self.cmd('modprobe bonding')
287 self.cmd('ip link add %s type bond' % self.bond0)
288 self.cmd('ip link set %s down' % intf0)
289 self.cmd('ip link set %s down' % intf1)
290 self.cmd('ip link set %s master %s' % (intf0, self.bond0))
291 self.cmd('ip link set %s master %s' % (intf1, self.bond0))
292 self.cmd('ip addr flush dev %s' % intf0)
293 self.cmd('ip addr flush dev %s' % intf1)
294 self.cmd('ip link set %s up' % self.bond0)
295 defaultIntf = self.defaultIntf()
296 defaultIntf.name = self.bond0
297 self.nameToIntf[self.bond0] = defaultIntf
298
299 self.cmd('ip %s addr flush dev %s' % ("-4" if self.ipv6 else "", self.defaultIntf()))
300
301 if self.vlan:
302 # Setup vlan interface
303 defaultIntf = self.defaultIntf()
304 self.vlanIntf = "%s.%s" % (defaultIntf, self.vlan)
305 self.cmd('ip link add link %s name %s type vlan id %s' % (defaultIntf, self.vlanIntf, self.vlan))
306 self.cmd('ip link set up %s' % self.vlanIntf)
307 defaultIntf.name = self.vlanIntf
308 self.nameToIntf[self.vlanIntf] = defaultIntf
309
310 if self.dhcpClient:
You Wang6cd51b42018-03-08 15:28:25 -0800311 time.sleep(3)
You Wangb097c0f2018-02-16 16:19:41 -0800312 self.cmd('dhclient -q -%s -nw -pf %s -lf %s %s' % (6 if self.ipv6 else 4, self.pidFile, self.leaseFile, self.defaultIntf()))
You Wang5102af12018-02-08 12:30:12 -0800313 else:
314 # Setup IP addresses
315 for ip in self.ips:
316 self.cmd('ip addr add %s dev %s' % (ip, self.defaultIntf()))
317 self.cmd('ip route add default via %s' % self.gateway)
318
319 if self.dhcpServer:
320 if self.ipv6:
321 linkLocalAddr = mac_to_ipv6_linklocal(kwargs['mac'])
322 self.cmd('ip -6 addr add dev %s scope link %s' % (self.defaultIntf(), linkLocalAddr))
323 self.cmd('touch %s' % self.leasesFile)
324 self.cmd('%s -q -%s -pf %s -cf %s %s' % (self.binFile, 6 if self.ipv6 else 4, self.pidFile, self.configFile, self.defaultIntf()))
325
326 def terminate(self, **kwargs):
327 if self.vlan:
328 self.cmd('ip link remove link %s' % self.vlanIntf)
329 if self.dualHomed:
330 self.cmd('ip link set %s down' % self.bond0)
331 self.cmd('ip link delete %s' % self.bond0)
332 if self.dhcpClient:
333 self.cmd('kill -9 `cat %s`' % self.pidFile)
334 self.cmd('rm -rf %s' % self.pidFile)
335 if self.dhcpServer:
336 self.cmd('kill -9 `cat %s`' % self.pidFile)
337 self.cmd('rm -rf %s' % self.pidFile)
338 super(TrellisHost, self).terminate()
339
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -0700340# Utility for IPv6
341def mac_to_ipv6_linklocal(mac):
342 '''
343 Convert mac address to link-local IPv6 address
344 '''
345 # Remove the most common delimiters; dots, dashes, etc.
346 mac_value = int(mac.translate(None, ' .:-'), 16)
347
348 # Split out the bytes that slot into the IPv6 address
349 # XOR the most significant byte with 0x02, inverting the
350 # Universal / Local bit
351 high2 = mac_value >> 32 & 0xffff ^ 0x0200
352 high1 = mac_value >> 24 & 0xff
353 low1 = mac_value >> 16 & 0xff
354 low2 = mac_value & 0xffff
355
356 return 'fe80::{:04x}:{:02x}ff:fe{:02x}:{:04x}'.format(high2, high1, low1, low2)