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