blob: bdc5df7a26731144d035a92b4025bb4383f752d4 [file] [log] [blame]
Neale Rannsfca0c242017-01-13 07:57:46 -08001#!/usr/bin/env python
2
3import unittest
4import socket
Neale Ranns3466c302017-02-16 07:45:03 -08005import struct
Neale Rannsfca0c242017-01-13 07:57:46 -08006
John Lo70bfcaf2017-11-14 13:19:26 -05007from framework import VppTestCase, VppTestRunner, running_extended_tests
Neale Ranns3466c302017-02-16 07:45:03 -08008from vpp_neighbor import VppNeighbor
Neale Ranns15002542017-09-10 04:39:11 -07009from vpp_ip_route import find_route, VppIpTable
Neale Ranns2a3ea492017-04-19 05:24:40 -070010from util import mk_ll_addr
Paul Vinciguerraa7427ec2019-03-10 10:04:23 -070011import scapy.compat
Neale Ranns51822bf2017-07-18 09:26:53 -070012from scapy.layers.l2 import Ether, getmacbyip, ARP
Neale Rannsfca0c242017-01-13 07:57:46 -080013from scapy.layers.inet import IP, UDP, ICMP
Neale Ranns2bc94022018-02-25 12:27:18 -080014from scapy.layers.inet6 import IPv6, in6_getnsmac
15from scapy.utils6 import in6_mactoifaceid
Neale Rannsfca0c242017-01-13 07:57:46 -080016from scapy.layers.dhcp import DHCP, BOOTP, DHCPTypes
17from scapy.layers.dhcp6 import DHCP6, DHCP6_Solicit, DHCP6_RelayForward, \
18 DHCP6_RelayReply, DHCP6_Advertise, DHCP6OptRelayMsg, DHCP6OptIfaceId, \
Neale Ranns3466c302017-02-16 07:45:03 -080019 DHCP6OptStatusCode, DHCP6OptVSS, DHCP6OptClientLinkLayerAddr, DHCP6_Request
Neale Rannsfca0c242017-01-13 07:57:46 -080020from socket import AF_INET, AF_INET6
21from scapy.utils import inet_pton, inet_ntop
22from scapy.utils6 import in6_ptop
Ole Troan8006c6a2018-12-17 12:02:26 +010023from vpp_papi import mac_pton
Neale Rannsfca0c242017-01-13 07:57:46 -080024
25DHCP4_CLIENT_PORT = 68
26DHCP4_SERVER_PORT = 67
27DHCP6_CLIENT_PORT = 547
28DHCP6_SERVER_PORT = 546
29
30
Neale Rannsfca0c242017-01-13 07:57:46 -080031class TestDHCP(VppTestCase):
32 """ DHCP Test Case """
33
Paul Vinciguerra7f9b7f92019-03-12 19:23:27 -070034 @classmethod
35 def setUpClass(cls):
36 super(TestDHCP, cls).setUpClass()
37
38 @classmethod
39 def tearDownClass(cls):
40 super(TestDHCP, cls).tearDownClass()
41
Neale Rannsfca0c242017-01-13 07:57:46 -080042 def setUp(self):
43 super(TestDHCP, self).setUp()
44
John Lo70bfcaf2017-11-14 13:19:26 -050045 # create 6 pg interfaces for pg0 to pg5
46 self.create_pg_interfaces(range(6))
Neale Ranns15002542017-09-10 04:39:11 -070047 self.tables = []
Neale Rannsfca0c242017-01-13 07:57:46 -080048
John Lo70bfcaf2017-11-14 13:19:26 -050049 # pg0 to 2 are IP configured in VRF 0, 1 and 2.
50 # pg3 to 5 are non IP-configured in VRF 0, 1 and 2.
Neale Rannsfca0c242017-01-13 07:57:46 -080051 table_id = 0
Neale Ranns15002542017-09-10 04:39:11 -070052 for table_id in range(1, 4):
53 tbl4 = VppIpTable(self, table_id)
54 tbl4.add_vpp_config()
55 self.tables.append(tbl4)
56 tbl6 = VppIpTable(self, table_id, is_ip6=1)
57 tbl6.add_vpp_config()
58 self.tables.append(tbl6)
59
60 table_id = 0
John Lo70bfcaf2017-11-14 13:19:26 -050061 for i in self.pg_interfaces[:3]:
Neale Rannsfca0c242017-01-13 07:57:46 -080062 i.admin_up()
63 i.set_table_ip4(table_id)
64 i.set_table_ip6(table_id)
65 i.config_ip4()
66 i.resolve_arp()
67 i.config_ip6()
68 i.resolve_ndp()
69 table_id += 1
70
71 table_id = 0
John Lo70bfcaf2017-11-14 13:19:26 -050072 for i in self.pg_interfaces[3:]:
Neale Rannsfca0c242017-01-13 07:57:46 -080073 i.admin_up()
74 i.set_table_ip4(table_id)
75 i.set_table_ip6(table_id)
76 table_id += 1
77
Neale Ranns4008ac92017-02-13 23:20:04 -080078 def tearDown(self):
John Lo70bfcaf2017-11-14 13:19:26 -050079 for i in self.pg_interfaces[:3]:
Neale Ranns4008ac92017-02-13 23:20:04 -080080 i.unconfig_ip4()
81 i.unconfig_ip6()
Neale Ranns15002542017-09-10 04:39:11 -070082
83 for i in self.pg_interfaces:
84 i.set_table_ip4(0)
85 i.set_table_ip6(0)
Neale Ranns4008ac92017-02-13 23:20:04 -080086 i.admin_down()
Neale Ranns15002542017-09-10 04:39:11 -070087 super(TestDHCP, self).tearDown()
Neale Ranns4008ac92017-02-13 23:20:04 -080088
Neale Rannsa2fbf6b2017-07-18 08:23:32 -070089 def verify_dhcp_has_option(self, pkt, option, value):
90 dhcp = pkt[DHCP]
91 found = False
92
93 for i in dhcp.options:
94 if type(i) is tuple:
95 if i[0] == option:
96 self.assertEqual(i[1], value)
97 found = True
98
99 self.assertTrue(found)
100
John Lo70bfcaf2017-11-14 13:19:26 -0500101 def validate_relay_options(self, pkt, intf, ip_addr, vpn_id, fib_id, oui):
Neale Rannsfca0c242017-01-13 07:57:46 -0800102 dhcp = pkt[DHCP]
103 found = 0
104 data = []
John Lo70bfcaf2017-11-14 13:19:26 -0500105 id_len = len(vpn_id)
Neale Rannsfca0c242017-01-13 07:57:46 -0800106
107 for i in dhcp.options:
108 if type(i) is tuple:
109 if i[0] == "relay_agent_Information":
110 #
111 # There are two sb-options present - each of length 6.
112 #
113 data = i[1]
Neale Ranns20a175a2017-02-14 07:28:41 -0800114 if oui != 0:
115 self.assertEqual(len(data), 24)
John Lo70bfcaf2017-11-14 13:19:26 -0500116 elif len(vpn_id) > 0:
117 self.assertEqual(len(data), len(vpn_id)+17)
Neale Ranns20a175a2017-02-14 07:28:41 -0800118 else:
119 self.assertEqual(len(data), 12)
Neale Rannsfca0c242017-01-13 07:57:46 -0800120
121 #
122 # First sub-option is ID 1, len 4, then encoded
123 # sw_if_index. This test uses low valued indicies
124 # so [2:4] are 0.
125 # The ID space is VPP internal - so no matching value
126 # scapy
127 #
128 self.assertEqual(ord(data[0]), 1)
129 self.assertEqual(ord(data[1]), 4)
130 self.assertEqual(ord(data[2]), 0)
131 self.assertEqual(ord(data[3]), 0)
132 self.assertEqual(ord(data[4]), 0)
133 self.assertEqual(ord(data[5]), intf._sw_if_index)
134
135 #
136 # next sub-option is the IP address of the client side
137 # interface.
138 # sub-option ID=5, length (of a v4 address)=4
139 #
140 claddr = socket.inet_pton(AF_INET, ip_addr)
141
142 self.assertEqual(ord(data[6]), 5)
143 self.assertEqual(ord(data[7]), 4)
144 self.assertEqual(data[8], claddr[0])
145 self.assertEqual(data[9], claddr[1])
146 self.assertEqual(data[10], claddr[2])
147 self.assertEqual(data[11], claddr[3])
148
Neale Ranns20a175a2017-02-14 07:28:41 -0800149 if oui != 0:
John Lo70bfcaf2017-11-14 13:19:26 -0500150 # sub-option 151 encodes vss_type 1,
151 # the 3 byte oui and the 4 byte fib_id
152 self.assertEqual(id_len, 0)
Neale Ranns20a175a2017-02-14 07:28:41 -0800153 self.assertEqual(ord(data[12]), 151)
154 self.assertEqual(ord(data[13]), 8)
155 self.assertEqual(ord(data[14]), 1)
156 self.assertEqual(ord(data[15]), 0)
157 self.assertEqual(ord(data[16]), 0)
158 self.assertEqual(ord(data[17]), oui)
159 self.assertEqual(ord(data[18]), 0)
160 self.assertEqual(ord(data[19]), 0)
161 self.assertEqual(ord(data[20]), 0)
162 self.assertEqual(ord(data[21]), fib_id)
163
164 # VSS control sub-option
165 self.assertEqual(ord(data[22]), 152)
166 self.assertEqual(ord(data[23]), 0)
167
John Lo70bfcaf2017-11-14 13:19:26 -0500168 if id_len > 0:
169 # sub-option 151 encode vss_type of 0
170 # followerd by vpn_id in ascii
171 self.assertEqual(oui, 0)
172 self.assertEqual(ord(data[12]), 151)
173 self.assertEqual(ord(data[13]), id_len+1)
174 self.assertEqual(ord(data[14]), 0)
175 self.assertEqual(data[15:15+id_len], vpn_id)
176
177 # VSS control sub-option
178 self.assertEqual(ord(data[15+len(vpn_id)]), 152)
179 self.assertEqual(ord(data[16+len(vpn_id)]), 0)
180
Neale Rannsfca0c242017-01-13 07:57:46 -0800181 found = 1
182 self.assertTrue(found)
183
184 return data
185
Neale Rannsa2fbf6b2017-07-18 08:23:32 -0700186 def verify_dhcp_msg_type(self, pkt, name):
187 dhcp = pkt[DHCP]
188 found = False
189 for o in dhcp.options:
190 if type(o) is tuple:
191 if o[0] == "message-type" \
192 and DHCPTypes[o[1]] == name:
193 found = True
194 self.assertTrue(found)
195
John Lo70bfcaf2017-11-14 13:19:26 -0500196 def verify_dhcp_offer(self, pkt, intf, vpn_id="", fib_id=0, oui=0):
Neale Rannsfca0c242017-01-13 07:57:46 -0800197 ether = pkt[Ether]
198 self.assertEqual(ether.dst, "ff:ff:ff:ff:ff:ff")
199 self.assertEqual(ether.src, intf.local_mac)
200
201 ip = pkt[IP]
202 self.assertEqual(ip.dst, "255.255.255.255")
203 self.assertEqual(ip.src, intf.local_ip4)
204
205 udp = pkt[UDP]
206 self.assertEqual(udp.dport, DHCP4_CLIENT_PORT)
207 self.assertEqual(udp.sport, DHCP4_SERVER_PORT)
208
Neale Rannsa2fbf6b2017-07-18 08:23:32 -0700209 self.verify_dhcp_msg_type(pkt, "offer")
Neale Ranns3466c302017-02-16 07:45:03 -0800210 data = self.validate_relay_options(pkt, intf, intf.local_ip4,
John Lo70bfcaf2017-11-14 13:19:26 -0500211 vpn_id, fib_id, oui)
Neale Rannsfca0c242017-01-13 07:57:46 -0800212
Neale Rannsa2fbf6b2017-07-18 08:23:32 -0700213 def verify_orig_dhcp_pkt(self, pkt, intf):
214 ether = pkt[Ether]
215 self.assertEqual(ether.dst, "ff:ff:ff:ff:ff:ff")
216 self.assertEqual(ether.src, intf.local_mac)
217
218 ip = pkt[IP]
219 self.assertEqual(ip.dst, "255.255.255.255")
220 self.assertEqual(ip.src, "0.0.0.0")
221
222 udp = pkt[UDP]
223 self.assertEqual(udp.dport, DHCP4_SERVER_PORT)
224 self.assertEqual(udp.sport, DHCP4_CLIENT_PORT)
225
Neale Ranns54c6dc42018-01-17 10:29:10 -0800226 def verify_orig_dhcp_discover(self, pkt, intf, hostname, client_id=None,
227 broadcast=1):
Neale Rannsa2fbf6b2017-07-18 08:23:32 -0700228 self.verify_orig_dhcp_pkt(pkt, intf)
229
230 self.verify_dhcp_msg_type(pkt, "discover")
231 self.verify_dhcp_has_option(pkt, "hostname", hostname)
Neale Ranns51822bf2017-07-18 09:26:53 -0700232 if client_id:
233 self.verify_dhcp_has_option(pkt, "client_id", client_id)
Neale Ranns808c5b22017-08-02 05:15:07 -0700234 bootp = pkt[BOOTP]
235 self.assertEqual(bootp.ciaddr, "0.0.0.0")
236 self.assertEqual(bootp.giaddr, "0.0.0.0")
Neale Ranns54c6dc42018-01-17 10:29:10 -0800237 if broadcast:
238 self.assertEqual(bootp.flags, 0x8000)
239 else:
240 self.assertEqual(bootp.flags, 0x0000)
Neale Rannsa2fbf6b2017-07-18 08:23:32 -0700241
Neale Ranns54c6dc42018-01-17 10:29:10 -0800242 def verify_orig_dhcp_request(self, pkt, intf, hostname, ip,
243 broadcast=1):
Neale Rannsa2fbf6b2017-07-18 08:23:32 -0700244 self.verify_orig_dhcp_pkt(pkt, intf)
245
246 self.verify_dhcp_msg_type(pkt, "request")
247 self.verify_dhcp_has_option(pkt, "hostname", hostname)
248 self.verify_dhcp_has_option(pkt, "requested_addr", ip)
Neale Ranns808c5b22017-08-02 05:15:07 -0700249 bootp = pkt[BOOTP]
250 self.assertEqual(bootp.ciaddr, "0.0.0.0")
251 self.assertEqual(bootp.giaddr, "0.0.0.0")
Neale Ranns54c6dc42018-01-17 10:29:10 -0800252 if broadcast:
253 self.assertEqual(bootp.flags, 0x8000)
254 else:
255 self.assertEqual(bootp.flags, 0x0000)
Neale Rannsa2fbf6b2017-07-18 08:23:32 -0700256
257 def verify_relayed_dhcp_discover(self, pkt, intf, src_intf=None,
258 fib_id=0, oui=0,
John Lo70bfcaf2017-11-14 13:19:26 -0500259 vpn_id="",
Neale Rannsa2fbf6b2017-07-18 08:23:32 -0700260 dst_mac=None, dst_ip=None):
Neale Ranns3466c302017-02-16 07:45:03 -0800261 if not dst_mac:
262 dst_mac = intf.remote_mac
263 if not dst_ip:
264 dst_ip = intf.remote_ip4
265
Neale Rannsfca0c242017-01-13 07:57:46 -0800266 ether = pkt[Ether]
Neale Ranns3466c302017-02-16 07:45:03 -0800267 self.assertEqual(ether.dst, dst_mac)
Neale Rannsfca0c242017-01-13 07:57:46 -0800268 self.assertEqual(ether.src, intf.local_mac)
269
270 ip = pkt[IP]
Neale Ranns3466c302017-02-16 07:45:03 -0800271 self.assertEqual(ip.dst, dst_ip)
Neale Rannsfca0c242017-01-13 07:57:46 -0800272 self.assertEqual(ip.src, intf.local_ip4)
273
274 udp = pkt[UDP]
275 self.assertEqual(udp.dport, DHCP4_SERVER_PORT)
276 self.assertEqual(udp.sport, DHCP4_CLIENT_PORT)
277
278 dhcp = pkt[DHCP]
279
280 is_discover = False
281 for o in dhcp.options:
282 if type(o) is tuple:
283 if o[0] == "message-type" \
284 and DHCPTypes[o[1]] == "discover":
285 is_discover = True
286 self.assertTrue(is_discover)
287
Neale Ranns20a175a2017-02-14 07:28:41 -0800288 data = self.validate_relay_options(pkt, src_intf,
289 src_intf.local_ip4,
John Lo70bfcaf2017-11-14 13:19:26 -0500290 vpn_id,
Neale Ranns20a175a2017-02-14 07:28:41 -0800291 fib_id, oui)
292 return data
Neale Rannsfca0c242017-01-13 07:57:46 -0800293
294 def verify_dhcp6_solicit(self, pkt, intf,
295 peer_ip, peer_mac,
John Lo70bfcaf2017-11-14 13:19:26 -0500296 vpn_id="",
Neale Rannsfca0c242017-01-13 07:57:46 -0800297 fib_id=0,
Neale Ranns3466c302017-02-16 07:45:03 -0800298 oui=0,
299 dst_mac=None,
300 dst_ip=None):
301 if not dst_mac:
302 dst_mac = intf.remote_mac
303 if not dst_ip:
304 dst_ip = in6_ptop(intf.remote_ip6)
305
Neale Rannsfca0c242017-01-13 07:57:46 -0800306 ether = pkt[Ether]
Neale Ranns3466c302017-02-16 07:45:03 -0800307 self.assertEqual(ether.dst, dst_mac)
Neale Rannsfca0c242017-01-13 07:57:46 -0800308 self.assertEqual(ether.src, intf.local_mac)
309
310 ip = pkt[IPv6]
Neale Ranns3466c302017-02-16 07:45:03 -0800311 self.assertEqual(in6_ptop(ip.dst), dst_ip)
Neale Rannsfca0c242017-01-13 07:57:46 -0800312 self.assertEqual(in6_ptop(ip.src), in6_ptop(intf.local_ip6))
313
314 udp = pkt[UDP]
315 self.assertEqual(udp.dport, DHCP6_CLIENT_PORT)
316 self.assertEqual(udp.sport, DHCP6_SERVER_PORT)
317
318 relay = pkt[DHCP6_RelayForward]
319 self.assertEqual(in6_ptop(relay.peeraddr), in6_ptop(peer_ip))
320 oid = pkt[DHCP6OptIfaceId]
321 cll = pkt[DHCP6OptClientLinkLayerAddr]
322 self.assertEqual(cll.optlen, 8)
323 self.assertEqual(cll.lltype, 1)
324 self.assertEqual(cll.clladdr, peer_mac)
325
John Lo70bfcaf2017-11-14 13:19:26 -0500326 id_len = len(vpn_id)
327
Neale Ranns20a175a2017-02-14 07:28:41 -0800328 if fib_id != 0:
John Lo70bfcaf2017-11-14 13:19:26 -0500329 self.assertEqual(id_len, 0)
Neale Ranns20a175a2017-02-14 07:28:41 -0800330 vss = pkt[DHCP6OptVSS]
331 self.assertEqual(vss.optlen, 8)
332 self.assertEqual(vss.type, 1)
333 # the OUI and FIB-id are really 3 and 4 bytes resp.
334 # but the tested range is small
335 self.assertEqual(ord(vss.data[0]), 0)
336 self.assertEqual(ord(vss.data[1]), 0)
337 self.assertEqual(ord(vss.data[2]), oui)
338 self.assertEqual(ord(vss.data[3]), 0)
339 self.assertEqual(ord(vss.data[4]), 0)
340 self.assertEqual(ord(vss.data[5]), 0)
341 self.assertEqual(ord(vss.data[6]), fib_id)
Neale Rannsfca0c242017-01-13 07:57:46 -0800342
John Lo70bfcaf2017-11-14 13:19:26 -0500343 if id_len > 0:
344 self.assertEqual(oui, 0)
345 vss = pkt[DHCP6OptVSS]
346 self.assertEqual(vss.optlen, id_len+1)
347 self.assertEqual(vss.type, 0)
348 self.assertEqual(vss.data[0:id_len], vpn_id)
349
Neale Rannsfca0c242017-01-13 07:57:46 -0800350 # the relay message should be an encoded Solicit
351 msg = pkt[DHCP6OptRelayMsg]
352 sol = DHCP6_Solicit()
353 self.assertEqual(msg.optlen, len(str(sol)))
354 self.assertEqual(str(sol), (str(msg[1]))[:msg.optlen])
355
356 def verify_dhcp6_advert(self, pkt, intf, peer):
357 ether = pkt[Ether]
358 self.assertEqual(ether.dst, "ff:ff:ff:ff:ff:ff")
359 self.assertEqual(ether.src, intf.local_mac)
360
361 ip = pkt[IPv6]
362 self.assertEqual(in6_ptop(ip.dst), in6_ptop(peer))
363 self.assertEqual(in6_ptop(ip.src), in6_ptop(intf.local_ip6))
364
365 udp = pkt[UDP]
366 self.assertEqual(udp.dport, DHCP6_SERVER_PORT)
367 self.assertEqual(udp.sport, DHCP6_CLIENT_PORT)
368
369 # not sure why this is not decoding
370 # adv = pkt[DHCP6_Advertise]
371
Neale Rannsf6e9b012019-01-25 06:37:15 -0800372 def wait_for_no_route(self, address, length,
373 n_tries=50, s_time=1):
374 while (n_tries):
375 if not find_route(self, address, length):
376 return True
377 n_tries = n_tries - 1
378 self.sleep(s_time)
379
380 return False
381
Neale Rannsfca0c242017-01-13 07:57:46 -0800382 def test_dhcp_proxy(self):
383 """ DHCPv4 Proxy """
384
385 #
386 # Verify no response to DHCP request without DHCP config
387 #
388 p_disc_vrf0 = (Ether(dst="ff:ff:ff:ff:ff:ff",
John Lo70bfcaf2017-11-14 13:19:26 -0500389 src=self.pg3.remote_mac) /
Neale Rannsfca0c242017-01-13 07:57:46 -0800390 IP(src="0.0.0.0", dst="255.255.255.255") /
391 UDP(sport=DHCP4_CLIENT_PORT,
392 dport=DHCP4_SERVER_PORT) /
393 BOOTP(op=1) /
394 DHCP(options=[('message-type', 'discover'), ('end')]))
395 pkts_disc_vrf0 = [p_disc_vrf0]
396 p_disc_vrf1 = (Ether(dst="ff:ff:ff:ff:ff:ff",
John Lo70bfcaf2017-11-14 13:19:26 -0500397 src=self.pg4.remote_mac) /
Neale Rannsfca0c242017-01-13 07:57:46 -0800398 IP(src="0.0.0.0", dst="255.255.255.255") /
399 UDP(sport=DHCP4_CLIENT_PORT,
400 dport=DHCP4_SERVER_PORT) /
401 BOOTP(op=1) /
402 DHCP(options=[('message-type', 'discover'), ('end')]))
John Lo70bfcaf2017-11-14 13:19:26 -0500403 pkts_disc_vrf1 = [p_disc_vrf1]
404 p_disc_vrf2 = (Ether(dst="ff:ff:ff:ff:ff:ff",
405 src=self.pg5.remote_mac) /
406 IP(src="0.0.0.0", dst="255.255.255.255") /
407 UDP(sport=DHCP4_CLIENT_PORT,
408 dport=DHCP4_SERVER_PORT) /
409 BOOTP(op=1) /
410 DHCP(options=[('message-type', 'discover'), ('end')]))
411 pkts_disc_vrf2 = [p_disc_vrf2]
Neale Rannsfca0c242017-01-13 07:57:46 -0800412
John Lo70bfcaf2017-11-14 13:19:26 -0500413 self.send_and_assert_no_replies(self.pg3, pkts_disc_vrf0,
Neale Rannsfca0c242017-01-13 07:57:46 -0800414 "DHCP with no configuration")
John Lo70bfcaf2017-11-14 13:19:26 -0500415 self.send_and_assert_no_replies(self.pg4, pkts_disc_vrf1,
416 "DHCP with no configuration")
417 self.send_and_assert_no_replies(self.pg5, pkts_disc_vrf2,
Neale Rannsfca0c242017-01-13 07:57:46 -0800418 "DHCP with no configuration")
419
420 #
421 # Enable DHCP proxy in VRF 0
422 #
423 server_addr = self.pg0.remote_ip4n
424 src_addr = self.pg0.local_ip4n
425
426 self.vapi.dhcp_proxy_config(server_addr,
427 src_addr,
428 rx_table_id=0)
429
430 #
Neale Ranns20a175a2017-02-14 07:28:41 -0800431 # Discover packets from the client are dropped because there is no
432 # IP address configured on the client facing interface
Neale Rannsfca0c242017-01-13 07:57:46 -0800433 #
John Lo70bfcaf2017-11-14 13:19:26 -0500434 self.send_and_assert_no_replies(self.pg3, pkts_disc_vrf0,
Neale Ranns20a175a2017-02-14 07:28:41 -0800435 "Discover DHCP no relay address")
Neale Rannsfca0c242017-01-13 07:57:46 -0800436
437 #
438 # Inject a response from the server
Neale Ranns20a175a2017-02-14 07:28:41 -0800439 # dropped, because there is no IP addrees on the
Neale Ranns2dd68522017-02-16 03:38:59 -0800440 # client interfce to fill in the option.
Neale Rannsfca0c242017-01-13 07:57:46 -0800441 #
442 p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
443 IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) /
444 UDP(sport=DHCP4_SERVER_PORT, dport=DHCP4_SERVER_PORT) /
445 BOOTP(op=1) /
446 DHCP(options=[('message-type', 'offer'), ('end')]))
447 pkts = [p]
448
John Lo70bfcaf2017-11-14 13:19:26 -0500449 self.send_and_assert_no_replies(self.pg3, pkts,
Neale Ranns20a175a2017-02-14 07:28:41 -0800450 "Offer DHCP no relay address")
Neale Rannsfca0c242017-01-13 07:57:46 -0800451
452 #
453 # configure an IP address on the client facing interface
454 #
John Lo70bfcaf2017-11-14 13:19:26 -0500455 self.pg3.config_ip4()
Neale Rannsfca0c242017-01-13 07:57:46 -0800456
457 #
458 # Try again with a discover packet
459 # Rx'd packet should be to the server address and from the configured
460 # source address
461 # UDP source ports are unchanged
462 # we've no option 82 config so that should be absent
463 #
John Lo70bfcaf2017-11-14 13:19:26 -0500464 self.pg3.add_stream(pkts_disc_vrf0)
Neale Rannsfca0c242017-01-13 07:57:46 -0800465 self.pg_enable_capture(self.pg_interfaces)
466 self.pg_start()
467
468 rx = self.pg0.get_capture(1)
469 rx = rx[0]
470
Neale Rannsa2fbf6b2017-07-18 08:23:32 -0700471 option_82 = self.verify_relayed_dhcp_discover(rx, self.pg0,
John Lo70bfcaf2017-11-14 13:19:26 -0500472 src_intf=self.pg3)
Neale Rannsfca0c242017-01-13 07:57:46 -0800473
474 #
475 # Create an DHCP offer reply from the server with a correctly formatted
476 # option 82. i.e. send back what we just captured
477 # The offer, sent mcast to the client, still has option 82.
478 #
479 p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
480 IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) /
481 UDP(sport=DHCP4_SERVER_PORT, dport=DHCP4_SERVER_PORT) /
482 BOOTP(op=1) /
483 DHCP(options=[('message-type', 'offer'),
484 ('relay_agent_Information', option_82),
485 ('end')]))
486 pkts = [p]
487
488 self.pg0.add_stream(pkts)
489 self.pg_enable_capture(self.pg_interfaces)
490 self.pg_start()
491
John Lo70bfcaf2017-11-14 13:19:26 -0500492 rx = self.pg3.get_capture(1)
Neale Rannsfca0c242017-01-13 07:57:46 -0800493 rx = rx[0]
494
John Lo70bfcaf2017-11-14 13:19:26 -0500495 self.verify_dhcp_offer(rx, self.pg3)
Neale Rannsfca0c242017-01-13 07:57:46 -0800496
497 #
498 # Bogus Option 82:
499 #
500 # 1. not our IP address = not checked by VPP? so offer is replayed
501 # to client
Paul Vinciguerraa7427ec2019-03-10 10:04:23 -0700502 bad_ip = option_82[0:8] + scapy.compat.chb(33) + option_82[9:]
Neale Rannsfca0c242017-01-13 07:57:46 -0800503
504 p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
505 IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) /
506 UDP(sport=DHCP4_SERVER_PORT, dport=DHCP4_SERVER_PORT) /
507 BOOTP(op=1) /
508 DHCP(options=[('message-type', 'offer'),
509 ('relay_agent_Information', bad_ip),
510 ('end')]))
511 pkts = [p]
Neale Ranns20a175a2017-02-14 07:28:41 -0800512 self.send_and_assert_no_replies(self.pg0, pkts,
513 "DHCP offer option 82 bad address")
Neale Rannsfca0c242017-01-13 07:57:46 -0800514
515 # 2. Not a sw_if_index VPP knows
Paul Vinciguerraa7427ec2019-03-10 10:04:23 -0700516 bad_if_index = option_82[0:2] + scapy.compat.chb(33) + option_82[3:]
Neale Rannsfca0c242017-01-13 07:57:46 -0800517
518 p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
519 IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) /
520 UDP(sport=DHCP4_SERVER_PORT, dport=DHCP4_SERVER_PORT) /
521 BOOTP(op=1) /
522 DHCP(options=[('message-type', 'offer'),
523 ('relay_agent_Information', bad_if_index),
524 ('end')]))
525 pkts = [p]
526 self.send_and_assert_no_replies(self.pg0, pkts,
527 "DHCP offer option 82 bad if index")
528
529 #
530 # Send a DHCP request in VRF 1. should be dropped.
531 #
John Lo70bfcaf2017-11-14 13:19:26 -0500532 self.send_and_assert_no_replies(self.pg4, pkts_disc_vrf1,
Neale Rannsfca0c242017-01-13 07:57:46 -0800533 "DHCP with no configuration VRF 1")
534
535 #
536 # Delete the DHCP config in VRF 0
537 # Should now drop requests.
538 #
539 self.vapi.dhcp_proxy_config(server_addr,
540 src_addr,
541 rx_table_id=0,
Neale Ranns20a175a2017-02-14 07:28:41 -0800542 is_add=0)
Neale Rannsfca0c242017-01-13 07:57:46 -0800543
John Lo70bfcaf2017-11-14 13:19:26 -0500544 self.send_and_assert_no_replies(self.pg3, pkts_disc_vrf0,
Neale Rannsfca0c242017-01-13 07:57:46 -0800545 "DHCP config removed VRF 0")
John Lo70bfcaf2017-11-14 13:19:26 -0500546 self.send_and_assert_no_replies(self.pg4, pkts_disc_vrf1,
Neale Rannsfca0c242017-01-13 07:57:46 -0800547 "DHCP config removed VRF 1")
548
549 #
John Lo70bfcaf2017-11-14 13:19:26 -0500550 # Add DHCP config for VRF 1 & 2
Neale Rannsfca0c242017-01-13 07:57:46 -0800551 #
John Lo70bfcaf2017-11-14 13:19:26 -0500552 server_addr1 = self.pg1.remote_ip4n
553 src_addr1 = self.pg1.local_ip4n
554 self.vapi.dhcp_proxy_config(server_addr1,
555 src_addr1,
Neale Rannsfca0c242017-01-13 07:57:46 -0800556 rx_table_id=1,
Neale Ranns20a175a2017-02-14 07:28:41 -0800557 server_table_id=1)
John Lo70bfcaf2017-11-14 13:19:26 -0500558 server_addr2 = self.pg2.remote_ip4n
559 src_addr2 = self.pg2.local_ip4n
560 self.vapi.dhcp_proxy_config(server_addr2,
561 src_addr2,
562 rx_table_id=2,
563 server_table_id=2)
Neale Rannsfca0c242017-01-13 07:57:46 -0800564
565 #
John Lo70bfcaf2017-11-14 13:19:26 -0500566 # Confim DHCP requests ok in VRF 1 & 2.
Neale Rannsfca0c242017-01-13 07:57:46 -0800567 # - dropped on IP config on client interface
568 #
John Lo70bfcaf2017-11-14 13:19:26 -0500569 self.send_and_assert_no_replies(self.pg4, pkts_disc_vrf1,
Neale Rannsfca0c242017-01-13 07:57:46 -0800570 "DHCP config removed VRF 1")
John Lo70bfcaf2017-11-14 13:19:26 -0500571 self.send_and_assert_no_replies(self.pg5, pkts_disc_vrf2,
572 "DHCP config removed VRF 2")
Neale Rannsfca0c242017-01-13 07:57:46 -0800573
574 #
575 # configure an IP address on the client facing interface
576 #
John Lo70bfcaf2017-11-14 13:19:26 -0500577 self.pg4.config_ip4()
578 self.pg4.add_stream(pkts_disc_vrf1)
Neale Rannsfca0c242017-01-13 07:57:46 -0800579 self.pg_enable_capture(self.pg_interfaces)
580 self.pg_start()
Neale Rannsfca0c242017-01-13 07:57:46 -0800581 rx = self.pg1.get_capture(1)
582 rx = rx[0]
John Lo70bfcaf2017-11-14 13:19:26 -0500583 self.verify_relayed_dhcp_discover(rx, self.pg1, src_intf=self.pg4)
584
585 self.pg5.config_ip4()
586 self.pg5.add_stream(pkts_disc_vrf2)
587 self.pg_enable_capture(self.pg_interfaces)
588 self.pg_start()
589 rx = self.pg2.get_capture(1)
590 rx = rx[0]
591 self.verify_relayed_dhcp_discover(rx, self.pg2, src_intf=self.pg5)
Neale Rannsfca0c242017-01-13 07:57:46 -0800592
593 #
Neale Ranns20a175a2017-02-14 07:28:41 -0800594 # Add VSS config
John Lo70bfcaf2017-11-14 13:19:26 -0500595 # table=1, vss_type=1, vpn_index=1, oui=4
596 # table=2, vss_type=0, vpn_id = "ip4-table-2"
597 self.vapi.dhcp_proxy_set_vss(1, 1, vpn_index=1, oui=4, is_add=1)
598 self.vapi.dhcp_proxy_set_vss(2, 0, "ip4-table-2", is_add=1)
Neale Ranns20a175a2017-02-14 07:28:41 -0800599
John Lo70bfcaf2017-11-14 13:19:26 -0500600 self.pg4.add_stream(pkts_disc_vrf1)
Neale Ranns20a175a2017-02-14 07:28:41 -0800601 self.pg_enable_capture(self.pg_interfaces)
602 self.pg_start()
603
604 rx = self.pg1.get_capture(1)
605 rx = rx[0]
Neale Rannsa2fbf6b2017-07-18 08:23:32 -0700606 self.verify_relayed_dhcp_discover(rx, self.pg1,
John Lo70bfcaf2017-11-14 13:19:26 -0500607 src_intf=self.pg4,
Neale Rannsa2fbf6b2017-07-18 08:23:32 -0700608 fib_id=1, oui=4)
Neale Ranns20a175a2017-02-14 07:28:41 -0800609
John Lo70bfcaf2017-11-14 13:19:26 -0500610 self.pg5.add_stream(pkts_disc_vrf2)
611 self.pg_enable_capture(self.pg_interfaces)
612 self.pg_start()
613
614 rx = self.pg2.get_capture(1)
615 rx = rx[0]
616 self.verify_relayed_dhcp_discover(rx, self.pg2,
617 src_intf=self.pg5,
618 vpn_id="ip4-table-2")
619
Neale Ranns20a175a2017-02-14 07:28:41 -0800620 #
Neale Ranns3466c302017-02-16 07:45:03 -0800621 # Add a second DHCP server in VRF 1
622 # expect clients messages to be relay to both configured servers
623 #
624 self.pg1.generate_remote_hosts(2)
John Lo70bfcaf2017-11-14 13:19:26 -0500625 server_addr12 = socket.inet_pton(AF_INET, self.pg1.remote_hosts[1].ip4)
Neale Ranns3466c302017-02-16 07:45:03 -0800626
John Lo70bfcaf2017-11-14 13:19:26 -0500627 self.vapi.dhcp_proxy_config(server_addr12,
628 src_addr1,
Neale Ranns3466c302017-02-16 07:45:03 -0800629 rx_table_id=1,
630 server_table_id=1,
631 is_add=1)
632
633 #
634 # We'll need an ARP entry for the server to send it packets
635 #
636 arp_entry = VppNeighbor(self,
637 self.pg1.sw_if_index,
638 self.pg1.remote_hosts[1].mac,
639 self.pg1.remote_hosts[1].ip4)
640 arp_entry.add_vpp_config()
641
642 #
643 # Send a discover from the client. expect two relayed messages
644 # The frist packet is sent to the second server
645 # We're not enforcing that here, it's just the way it is.
646 #
John Lo70bfcaf2017-11-14 13:19:26 -0500647 self.pg4.add_stream(pkts_disc_vrf1)
Neale Ranns3466c302017-02-16 07:45:03 -0800648 self.pg_enable_capture(self.pg_interfaces)
649 self.pg_start()
650
651 rx = self.pg1.get_capture(2)
652
Neale Rannsa2fbf6b2017-07-18 08:23:32 -0700653 option_82 = self.verify_relayed_dhcp_discover(
Neale Ranns3466c302017-02-16 07:45:03 -0800654 rx[0], self.pg1,
John Lo70bfcaf2017-11-14 13:19:26 -0500655 src_intf=self.pg4,
Neale Ranns3466c302017-02-16 07:45:03 -0800656 dst_mac=self.pg1.remote_hosts[1].mac,
657 dst_ip=self.pg1.remote_hosts[1].ip4,
658 fib_id=1, oui=4)
Neale Rannsa2fbf6b2017-07-18 08:23:32 -0700659 self.verify_relayed_dhcp_discover(rx[1], self.pg1,
John Lo70bfcaf2017-11-14 13:19:26 -0500660 src_intf=self.pg4,
Neale Rannsa2fbf6b2017-07-18 08:23:32 -0700661 fib_id=1, oui=4)
Neale Ranns3466c302017-02-16 07:45:03 -0800662
663 #
664 # Send both packets back. Client gets both.
665 #
666 p1 = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
667 IP(src=self.pg1.remote_ip4, dst=self.pg1.local_ip4) /
668 UDP(sport=DHCP4_SERVER_PORT, dport=DHCP4_SERVER_PORT) /
669 BOOTP(op=1) /
670 DHCP(options=[('message-type', 'offer'),
671 ('relay_agent_Information', option_82),
672 ('end')]))
673 p2 = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
674 IP(src=self.pg1.remote_hosts[1].ip4, dst=self.pg1.local_ip4) /
675 UDP(sport=DHCP4_SERVER_PORT, dport=DHCP4_SERVER_PORT) /
676 BOOTP(op=1) /
677 DHCP(options=[('message-type', 'offer'),
678 ('relay_agent_Information', option_82),
679 ('end')]))
680 pkts = [p1, p2]
681
682 self.pg1.add_stream(pkts)
683 self.pg_enable_capture(self.pg_interfaces)
684 self.pg_start()
685
John Lo70bfcaf2017-11-14 13:19:26 -0500686 rx = self.pg4.get_capture(2)
Neale Ranns3466c302017-02-16 07:45:03 -0800687
John Lo70bfcaf2017-11-14 13:19:26 -0500688 self.verify_dhcp_offer(rx[0], self.pg4, fib_id=1, oui=4)
689 self.verify_dhcp_offer(rx[1], self.pg4, fib_id=1, oui=4)
Neale Ranns3466c302017-02-16 07:45:03 -0800690
691 #
692 # Ensure offers from non-servers are dropeed
693 #
694 p2 = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
695 IP(src="8.8.8.8", dst=self.pg1.local_ip4) /
696 UDP(sport=DHCP4_SERVER_PORT, dport=DHCP4_SERVER_PORT) /
697 BOOTP(op=1) /
698 DHCP(options=[('message-type', 'offer'),
699 ('relay_agent_Information', option_82),
700 ('end')]))
701 self.send_and_assert_no_replies(self.pg1, p2,
702 "DHCP offer from non-server")
703
704 #
705 # Ensure only the discover is sent to multiple servers
706 #
707 p_req_vrf1 = (Ether(dst="ff:ff:ff:ff:ff:ff",
John Lo70bfcaf2017-11-14 13:19:26 -0500708 src=self.pg4.remote_mac) /
Neale Ranns3466c302017-02-16 07:45:03 -0800709 IP(src="0.0.0.0", dst="255.255.255.255") /
710 UDP(sport=DHCP4_CLIENT_PORT,
711 dport=DHCP4_SERVER_PORT) /
712 BOOTP(op=1) /
713 DHCP(options=[('message-type', 'request'),
714 ('end')]))
715
John Lo70bfcaf2017-11-14 13:19:26 -0500716 self.pg4.add_stream(p_req_vrf1)
Neale Ranns3466c302017-02-16 07:45:03 -0800717 self.pg_enable_capture(self.pg_interfaces)
718 self.pg_start()
719
720 rx = self.pg1.get_capture(1)
721
722 #
723 # Remove the second DHCP server
724 #
John Lo70bfcaf2017-11-14 13:19:26 -0500725 self.vapi.dhcp_proxy_config(server_addr12,
726 src_addr1,
Neale Ranns3466c302017-02-16 07:45:03 -0800727 rx_table_id=1,
728 server_table_id=1,
729 is_add=0)
730
731 #
732 # Test we can still relay with the first
733 #
John Lo70bfcaf2017-11-14 13:19:26 -0500734 self.pg4.add_stream(pkts_disc_vrf1)
Neale Ranns3466c302017-02-16 07:45:03 -0800735 self.pg_enable_capture(self.pg_interfaces)
736 self.pg_start()
737
738 rx = self.pg1.get_capture(1)
739 rx = rx[0]
Neale Rannsa2fbf6b2017-07-18 08:23:32 -0700740 self.verify_relayed_dhcp_discover(rx, self.pg1,
John Lo70bfcaf2017-11-14 13:19:26 -0500741 src_intf=self.pg4,
Neale Rannsa2fbf6b2017-07-18 08:23:32 -0700742 fib_id=1, oui=4)
Neale Ranns3466c302017-02-16 07:45:03 -0800743
744 #
Neale Ranns20a175a2017-02-14 07:28:41 -0800745 # Remove the VSS config
746 # relayed DHCP has default vlaues in the option.
747 #
John Lo70bfcaf2017-11-14 13:19:26 -0500748 self.vapi.dhcp_proxy_set_vss(1, is_add=0)
749 self.vapi.dhcp_proxy_set_vss(2, is_add=0)
Neale Ranns20a175a2017-02-14 07:28:41 -0800750
John Lo70bfcaf2017-11-14 13:19:26 -0500751 self.pg4.add_stream(pkts_disc_vrf1)
Neale Ranns20a175a2017-02-14 07:28:41 -0800752 self.pg_enable_capture(self.pg_interfaces)
753 self.pg_start()
754
755 rx = self.pg1.get_capture(1)
756 rx = rx[0]
John Lo70bfcaf2017-11-14 13:19:26 -0500757 self.verify_relayed_dhcp_discover(rx, self.pg1, src_intf=self.pg4)
Neale Ranns20a175a2017-02-14 07:28:41 -0800758
759 #
Neale Rannsfca0c242017-01-13 07:57:46 -0800760 # remove DHCP config to cleanup
761 #
John Lo70bfcaf2017-11-14 13:19:26 -0500762 self.vapi.dhcp_proxy_config(server_addr1,
763 src_addr1,
Neale Rannsfca0c242017-01-13 07:57:46 -0800764 rx_table_id=1,
Neale Ranns3466c302017-02-16 07:45:03 -0800765 server_table_id=1,
Neale Rannsfca0c242017-01-13 07:57:46 -0800766 is_add=0)
John Lo70bfcaf2017-11-14 13:19:26 -0500767 self.vapi.dhcp_proxy_config(server_addr2,
768 src_addr2,
769 rx_table_id=2,
770 server_table_id=2,
771 is_add=0)
Neale Rannsfca0c242017-01-13 07:57:46 -0800772
John Lo70bfcaf2017-11-14 13:19:26 -0500773 self.send_and_assert_no_replies(self.pg3, pkts_disc_vrf0,
Neale Rannsfca0c242017-01-13 07:57:46 -0800774 "DHCP cleanup VRF 0")
John Lo70bfcaf2017-11-14 13:19:26 -0500775 self.send_and_assert_no_replies(self.pg4, pkts_disc_vrf1,
Neale Rannsfca0c242017-01-13 07:57:46 -0800776 "DHCP cleanup VRF 1")
John Lo70bfcaf2017-11-14 13:19:26 -0500777 self.send_and_assert_no_replies(self.pg5, pkts_disc_vrf2,
778 "DHCP cleanup VRF 2")
779
Neale Ranns15002542017-09-10 04:39:11 -0700780 self.pg3.unconfig_ip4()
John Lo70bfcaf2017-11-14 13:19:26 -0500781 self.pg4.unconfig_ip4()
782 self.pg5.unconfig_ip4()
Neale Rannsfca0c242017-01-13 07:57:46 -0800783
784 def test_dhcp6_proxy(self):
785 """ DHCPv6 Proxy"""
786 #
787 # Verify no response to DHCP request without DHCP config
788 #
789 dhcp_solicit_dst = "ff02::1:2"
John Lo70bfcaf2017-11-14 13:19:26 -0500790 dhcp_solicit_src_vrf0 = mk_ll_addr(self.pg3.remote_mac)
791 dhcp_solicit_src_vrf1 = mk_ll_addr(self.pg4.remote_mac)
792 dhcp_solicit_src_vrf2 = mk_ll_addr(self.pg5.remote_mac)
Neale Rannsfca0c242017-01-13 07:57:46 -0800793 server_addr_vrf0 = self.pg0.remote_ip6n
794 src_addr_vrf0 = self.pg0.local_ip6n
795 server_addr_vrf1 = self.pg1.remote_ip6n
796 src_addr_vrf1 = self.pg1.local_ip6n
John Lo70bfcaf2017-11-14 13:19:26 -0500797 server_addr_vrf2 = self.pg2.remote_ip6n
798 src_addr_vrf2 = self.pg2.local_ip6n
Neale Rannsfca0c242017-01-13 07:57:46 -0800799
Neale Rannsfca0c242017-01-13 07:57:46 -0800800 dmac = in6_getnsmac(inet_pton(socket.AF_INET6, dhcp_solicit_dst))
John Lo70bfcaf2017-11-14 13:19:26 -0500801 p_solicit_vrf0 = (Ether(dst=dmac, src=self.pg3.remote_mac) /
Neale Rannsfca0c242017-01-13 07:57:46 -0800802 IPv6(src=dhcp_solicit_src_vrf0,
803 dst=dhcp_solicit_dst) /
804 UDP(sport=DHCP6_SERVER_PORT,
805 dport=DHCP6_CLIENT_PORT) /
806 DHCP6_Solicit())
John Lo70bfcaf2017-11-14 13:19:26 -0500807 p_solicit_vrf1 = (Ether(dst=dmac, src=self.pg4.remote_mac) /
Neale Rannsfca0c242017-01-13 07:57:46 -0800808 IPv6(src=dhcp_solicit_src_vrf1,
809 dst=dhcp_solicit_dst) /
810 UDP(sport=DHCP6_SERVER_PORT,
811 dport=DHCP6_CLIENT_PORT) /
812 DHCP6_Solicit())
John Lo70bfcaf2017-11-14 13:19:26 -0500813 p_solicit_vrf2 = (Ether(dst=dmac, src=self.pg5.remote_mac) /
814 IPv6(src=dhcp_solicit_src_vrf2,
815 dst=dhcp_solicit_dst) /
816 UDP(sport=DHCP6_SERVER_PORT,
817 dport=DHCP6_CLIENT_PORT) /
818 DHCP6_Solicit())
Neale Rannsfca0c242017-01-13 07:57:46 -0800819
John Lo70bfcaf2017-11-14 13:19:26 -0500820 self.send_and_assert_no_replies(self.pg3, p_solicit_vrf0,
Neale Rannsfca0c242017-01-13 07:57:46 -0800821 "DHCP with no configuration")
John Lo70bfcaf2017-11-14 13:19:26 -0500822 self.send_and_assert_no_replies(self.pg4, p_solicit_vrf1,
823 "DHCP with no configuration")
824 self.send_and_assert_no_replies(self.pg5, p_solicit_vrf2,
Neale Rannsfca0c242017-01-13 07:57:46 -0800825 "DHCP with no configuration")
826
827 #
828 # DHCPv6 config in VRF 0.
829 # Packets still dropped because the client facing interface has no
830 # IPv6 config
831 #
832 self.vapi.dhcp_proxy_config(server_addr_vrf0,
833 src_addr_vrf0,
834 rx_table_id=0,
835 server_table_id=0,
Neale Rannsfca0c242017-01-13 07:57:46 -0800836 is_ipv6=1)
837
John Lo70bfcaf2017-11-14 13:19:26 -0500838 self.send_and_assert_no_replies(self.pg3, p_solicit_vrf0,
Neale Rannsfca0c242017-01-13 07:57:46 -0800839 "DHCP with no configuration")
John Lo70bfcaf2017-11-14 13:19:26 -0500840 self.send_and_assert_no_replies(self.pg4, p_solicit_vrf1,
Neale Rannsfca0c242017-01-13 07:57:46 -0800841 "DHCP with no configuration")
842
843 #
844 # configure an IP address on the client facing interface
845 #
John Lo70bfcaf2017-11-14 13:19:26 -0500846 self.pg3.config_ip6()
Neale Rannsfca0c242017-01-13 07:57:46 -0800847
848 #
849 # Now the DHCP requests are relayed to the server
850 #
John Lo70bfcaf2017-11-14 13:19:26 -0500851 self.pg3.add_stream(p_solicit_vrf0)
Neale Rannsfca0c242017-01-13 07:57:46 -0800852 self.pg_enable_capture(self.pg_interfaces)
853 self.pg_start()
854
855 rx = self.pg0.get_capture(1)
Neale Ranns3466c302017-02-16 07:45:03 -0800856
857 self.verify_dhcp6_solicit(rx[0], self.pg0,
Neale Rannsfca0c242017-01-13 07:57:46 -0800858 dhcp_solicit_src_vrf0,
John Lo70bfcaf2017-11-14 13:19:26 -0500859 self.pg3.remote_mac)
Neale Rannsfca0c242017-01-13 07:57:46 -0800860
861 #
862 # Exception cases for rejected relay responses
863 #
864
865 # 1 - not a relay reply
866 p_adv_vrf0 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
867 IPv6(dst=self.pg0.local_ip6, src=self.pg0.remote_ip6) /
868 UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_SERVER_PORT) /
869 DHCP6_Advertise())
John Lo70bfcaf2017-11-14 13:19:26 -0500870 self.send_and_assert_no_replies(self.pg3, p_adv_vrf0,
Neale Rannsfca0c242017-01-13 07:57:46 -0800871 "DHCP6 not a relay reply")
872
873 # 2 - no relay message option
874 p_adv_vrf0 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
875 IPv6(dst=self.pg0.local_ip6, src=self.pg0.remote_ip6) /
876 UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_SERVER_PORT) /
877 DHCP6_RelayReply() /
878 DHCP6_Advertise())
John Lo70bfcaf2017-11-14 13:19:26 -0500879 self.send_and_assert_no_replies(self.pg3, p_adv_vrf0,
Neale Rannsfca0c242017-01-13 07:57:46 -0800880 "DHCP not a relay message")
881
882 # 3 - no circuit ID
883 p_adv_vrf0 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
884 IPv6(dst=self.pg0.local_ip6, src=self.pg0.remote_ip6) /
885 UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_SERVER_PORT) /
886 DHCP6_RelayReply() /
887 DHCP6OptRelayMsg(optlen=0) /
888 DHCP6_Advertise())
John Lo70bfcaf2017-11-14 13:19:26 -0500889 self.send_and_assert_no_replies(self.pg3, p_adv_vrf0,
Neale Rannsfca0c242017-01-13 07:57:46 -0800890 "DHCP6 no circuit ID")
891 # 4 - wrong circuit ID
892 p_adv_vrf0 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
893 IPv6(dst=self.pg0.local_ip6, src=self.pg0.remote_ip6) /
894 UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_SERVER_PORT) /
895 DHCP6_RelayReply() /
896 DHCP6OptIfaceId(optlen=4, ifaceid='\x00\x00\x00\x05') /
897 DHCP6OptRelayMsg(optlen=0) /
898 DHCP6_Advertise())
John Lo70bfcaf2017-11-14 13:19:26 -0500899 self.send_and_assert_no_replies(self.pg3, p_adv_vrf0,
Neale Rannsfca0c242017-01-13 07:57:46 -0800900 "DHCP6 wrong circuit ID")
901
902 #
903 # Send the relay response (the advertisement)
904 # - no peer address
905 p_adv_vrf0 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
906 IPv6(dst=self.pg0.local_ip6, src=self.pg0.remote_ip6) /
907 UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_SERVER_PORT) /
908 DHCP6_RelayReply() /
John Lo70bfcaf2017-11-14 13:19:26 -0500909 DHCP6OptIfaceId(optlen=4, ifaceid='\x00\x00\x00\x04') /
Neale Rannsfca0c242017-01-13 07:57:46 -0800910 DHCP6OptRelayMsg(optlen=0) /
911 DHCP6_Advertise(trid=1) /
912 DHCP6OptStatusCode(statuscode=0))
913 pkts_adv_vrf0 = [p_adv_vrf0]
914
915 self.pg0.add_stream(pkts_adv_vrf0)
916 self.pg_enable_capture(self.pg_interfaces)
917 self.pg_start()
918
John Lo70bfcaf2017-11-14 13:19:26 -0500919 rx = self.pg3.get_capture(1)
Neale Ranns3466c302017-02-16 07:45:03 -0800920
John Lo70bfcaf2017-11-14 13:19:26 -0500921 self.verify_dhcp6_advert(rx[0], self.pg3, "::")
Neale Rannsfca0c242017-01-13 07:57:46 -0800922
923 #
924 # Send the relay response (the advertisement)
925 # - with peer address
926 p_adv_vrf0 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
927 IPv6(dst=self.pg0.local_ip6, src=self.pg0.remote_ip6) /
928 UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_SERVER_PORT) /
929 DHCP6_RelayReply(peeraddr=dhcp_solicit_src_vrf0) /
John Lo70bfcaf2017-11-14 13:19:26 -0500930 DHCP6OptIfaceId(optlen=4, ifaceid='\x00\x00\x00\x04') /
Neale Rannsfca0c242017-01-13 07:57:46 -0800931 DHCP6OptRelayMsg(optlen=0) /
932 DHCP6_Advertise(trid=1) /
933 DHCP6OptStatusCode(statuscode=0))
934 pkts_adv_vrf0 = [p_adv_vrf0]
935
936 self.pg0.add_stream(pkts_adv_vrf0)
937 self.pg_enable_capture(self.pg_interfaces)
938 self.pg_start()
939
John Lo70bfcaf2017-11-14 13:19:26 -0500940 rx = self.pg3.get_capture(1)
Neale Ranns3466c302017-02-16 07:45:03 -0800941
John Lo70bfcaf2017-11-14 13:19:26 -0500942 self.verify_dhcp6_advert(rx[0], self.pg3, dhcp_solicit_src_vrf0)
Neale Rannsfca0c242017-01-13 07:57:46 -0800943
944 #
John Lo70bfcaf2017-11-14 13:19:26 -0500945 # Add all the config for VRF 1 & 2
Neale Rannsfca0c242017-01-13 07:57:46 -0800946 #
947 self.vapi.dhcp_proxy_config(server_addr_vrf1,
948 src_addr_vrf1,
949 rx_table_id=1,
950 server_table_id=1,
Neale Rannsfca0c242017-01-13 07:57:46 -0800951 is_ipv6=1)
John Lo70bfcaf2017-11-14 13:19:26 -0500952 self.pg4.config_ip6()
953
954 self.vapi.dhcp_proxy_config(server_addr_vrf2,
955 src_addr_vrf2,
956 rx_table_id=2,
957 server_table_id=2,
958 is_ipv6=1)
959 self.pg5.config_ip6()
Neale Rannsfca0c242017-01-13 07:57:46 -0800960
961 #
962 # VRF 1 solicit
963 #
John Lo70bfcaf2017-11-14 13:19:26 -0500964 self.pg4.add_stream(p_solicit_vrf1)
Neale Rannsfca0c242017-01-13 07:57:46 -0800965 self.pg_enable_capture(self.pg_interfaces)
966 self.pg_start()
967
968 rx = self.pg1.get_capture(1)
Neale Ranns3466c302017-02-16 07:45:03 -0800969
970 self.verify_dhcp6_solicit(rx[0], self.pg1,
Neale Rannsfca0c242017-01-13 07:57:46 -0800971 dhcp_solicit_src_vrf1,
John Lo70bfcaf2017-11-14 13:19:26 -0500972 self.pg4.remote_mac)
973
974 #
975 # VRF 2 solicit
976 #
977 self.pg5.add_stream(p_solicit_vrf2)
978 self.pg_enable_capture(self.pg_interfaces)
979 self.pg_start()
980
981 rx = self.pg2.get_capture(1)
982
983 self.verify_dhcp6_solicit(rx[0], self.pg2,
984 dhcp_solicit_src_vrf2,
985 self.pg5.remote_mac)
Neale Rannsfca0c242017-01-13 07:57:46 -0800986
987 #
988 # VRF 1 Advert
989 #
990 p_adv_vrf1 = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
991 IPv6(dst=self.pg1.local_ip6, src=self.pg1.remote_ip6) /
992 UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_SERVER_PORT) /
993 DHCP6_RelayReply(peeraddr=dhcp_solicit_src_vrf1) /
John Lo70bfcaf2017-11-14 13:19:26 -0500994 DHCP6OptIfaceId(optlen=4, ifaceid='\x00\x00\x00\x05') /
Neale Rannsfca0c242017-01-13 07:57:46 -0800995 DHCP6OptRelayMsg(optlen=0) /
996 DHCP6_Advertise(trid=1) /
997 DHCP6OptStatusCode(statuscode=0))
998 pkts_adv_vrf1 = [p_adv_vrf1]
999
1000 self.pg1.add_stream(pkts_adv_vrf1)
1001 self.pg_enable_capture(self.pg_interfaces)
1002 self.pg_start()
1003
John Lo70bfcaf2017-11-14 13:19:26 -05001004 rx = self.pg4.get_capture(1)
Neale Ranns3466c302017-02-16 07:45:03 -08001005
John Lo70bfcaf2017-11-14 13:19:26 -05001006 self.verify_dhcp6_advert(rx[0], self.pg4, dhcp_solicit_src_vrf1)
Neale Rannsfca0c242017-01-13 07:57:46 -08001007
1008 #
1009 # Add VSS config
John Lo70bfcaf2017-11-14 13:19:26 -05001010 # table=1, vss_type=1, vpn_index=1, oui=4
1011 # table=2, vss_type=0, vpn_id = "ip6-table-2"
1012 self.vapi.dhcp_proxy_set_vss(1, 1, oui=4, vpn_index=1, is_ip6=1)
1013 self.vapi.dhcp_proxy_set_vss(2, 0, "IPv6-table-2", is_ip6=1)
Neale Rannsfca0c242017-01-13 07:57:46 -08001014
John Lo70bfcaf2017-11-14 13:19:26 -05001015 self.pg4.add_stream(p_solicit_vrf1)
Neale Rannsfca0c242017-01-13 07:57:46 -08001016 self.pg_enable_capture(self.pg_interfaces)
1017 self.pg_start()
1018
1019 rx = self.pg1.get_capture(1)
Neale Ranns3466c302017-02-16 07:45:03 -08001020
1021 self.verify_dhcp6_solicit(rx[0], self.pg1,
Neale Rannsfca0c242017-01-13 07:57:46 -08001022 dhcp_solicit_src_vrf1,
John Lo70bfcaf2017-11-14 13:19:26 -05001023 self.pg4.remote_mac,
Neale Rannsfca0c242017-01-13 07:57:46 -08001024 fib_id=1,
1025 oui=4)
1026
John Lo70bfcaf2017-11-14 13:19:26 -05001027 self.pg5.add_stream(p_solicit_vrf2)
1028 self.pg_enable_capture(self.pg_interfaces)
1029 self.pg_start()
1030
1031 rx = self.pg2.get_capture(1)
1032
1033 self.verify_dhcp6_solicit(rx[0], self.pg2,
1034 dhcp_solicit_src_vrf2,
1035 self.pg5.remote_mac,
1036 vpn_id="IPv6-table-2")
1037
Neale Rannsfca0c242017-01-13 07:57:46 -08001038 #
1039 # Remove the VSS config
1040 # relayed DHCP has default vlaues in the option.
1041 #
John Lo70bfcaf2017-11-14 13:19:26 -05001042 self.vapi.dhcp_proxy_set_vss(1, is_ip6=1, is_add=0)
Neale Rannsfca0c242017-01-13 07:57:46 -08001043
John Lo70bfcaf2017-11-14 13:19:26 -05001044 self.pg4.add_stream(p_solicit_vrf1)
Neale Rannsfca0c242017-01-13 07:57:46 -08001045 self.pg_enable_capture(self.pg_interfaces)
1046 self.pg_start()
1047
1048 rx = self.pg1.get_capture(1)
Neale Ranns3466c302017-02-16 07:45:03 -08001049
1050 self.verify_dhcp6_solicit(rx[0], self.pg1,
1051 dhcp_solicit_src_vrf1,
John Lo70bfcaf2017-11-14 13:19:26 -05001052 self.pg4.remote_mac)
Neale Ranns3466c302017-02-16 07:45:03 -08001053
1054 #
1055 # Add a second DHCP server in VRF 1
1056 # expect clients messages to be relay to both configured servers
1057 #
1058 self.pg1.generate_remote_hosts(2)
John Lo70bfcaf2017-11-14 13:19:26 -05001059 server_addr12 = socket.inet_pton(AF_INET6,
1060 self.pg1.remote_hosts[1].ip6)
Neale Ranns3466c302017-02-16 07:45:03 -08001061
John Lo70bfcaf2017-11-14 13:19:26 -05001062 self.vapi.dhcp_proxy_config(server_addr12,
Neale Ranns3466c302017-02-16 07:45:03 -08001063 src_addr_vrf1,
1064 rx_table_id=1,
1065 server_table_id=1,
1066 is_ipv6=1)
1067
1068 #
1069 # We'll need an ND entry for the server to send it packets
1070 #
1071 nd_entry = VppNeighbor(self,
1072 self.pg1.sw_if_index,
1073 self.pg1.remote_hosts[1].mac,
Neale Ranns37029302018-08-10 05:30:06 -07001074 self.pg1.remote_hosts[1].ip6)
Neale Ranns3466c302017-02-16 07:45:03 -08001075 nd_entry.add_vpp_config()
1076
1077 #
1078 # Send a discover from the client. expect two relayed messages
1079 # The frist packet is sent to the second server
1080 # We're not enforcing that here, it's just the way it is.
1081 #
John Lo70bfcaf2017-11-14 13:19:26 -05001082 self.pg4.add_stream(p_solicit_vrf1)
Neale Ranns3466c302017-02-16 07:45:03 -08001083 self.pg_enable_capture(self.pg_interfaces)
1084 self.pg_start()
1085
1086 rx = self.pg1.get_capture(2)
1087
1088 self.verify_dhcp6_solicit(rx[0], self.pg1,
1089 dhcp_solicit_src_vrf1,
John Lo70bfcaf2017-11-14 13:19:26 -05001090 self.pg4.remote_mac)
Neale Ranns3466c302017-02-16 07:45:03 -08001091 self.verify_dhcp6_solicit(rx[1], self.pg1,
1092 dhcp_solicit_src_vrf1,
John Lo70bfcaf2017-11-14 13:19:26 -05001093 self.pg4.remote_mac,
Neale Ranns3466c302017-02-16 07:45:03 -08001094 dst_mac=self.pg1.remote_hosts[1].mac,
1095 dst_ip=self.pg1.remote_hosts[1].ip6)
1096
1097 #
1098 # Send both packets back. Client gets both.
1099 #
1100 p1 = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
1101 IPv6(dst=self.pg1.local_ip6, src=self.pg1.remote_ip6) /
1102 UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_SERVER_PORT) /
1103 DHCP6_RelayReply(peeraddr=dhcp_solicit_src_vrf1) /
John Lo70bfcaf2017-11-14 13:19:26 -05001104 DHCP6OptIfaceId(optlen=4, ifaceid='\x00\x00\x00\x05') /
Neale Ranns3466c302017-02-16 07:45:03 -08001105 DHCP6OptRelayMsg(optlen=0) /
1106 DHCP6_Advertise(trid=1) /
1107 DHCP6OptStatusCode(statuscode=0))
1108 p2 = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_hosts[1].mac) /
1109 IPv6(dst=self.pg1.local_ip6, src=self.pg1._remote_hosts[1].ip6) /
1110 UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_SERVER_PORT) /
1111 DHCP6_RelayReply(peeraddr=dhcp_solicit_src_vrf1) /
John Lo70bfcaf2017-11-14 13:19:26 -05001112 DHCP6OptIfaceId(optlen=4, ifaceid='\x00\x00\x00\x05') /
Neale Ranns3466c302017-02-16 07:45:03 -08001113 DHCP6OptRelayMsg(optlen=0) /
1114 DHCP6_Advertise(trid=1) /
1115 DHCP6OptStatusCode(statuscode=0))
1116
1117 pkts = [p1, p2]
1118
1119 self.pg1.add_stream(pkts)
1120 self.pg_enable_capture(self.pg_interfaces)
1121 self.pg_start()
1122
John Lo70bfcaf2017-11-14 13:19:26 -05001123 rx = self.pg4.get_capture(2)
Neale Ranns3466c302017-02-16 07:45:03 -08001124
John Lo70bfcaf2017-11-14 13:19:26 -05001125 self.verify_dhcp6_advert(rx[0], self.pg4, dhcp_solicit_src_vrf1)
1126 self.verify_dhcp6_advert(rx[1], self.pg4, dhcp_solicit_src_vrf1)
Neale Ranns3466c302017-02-16 07:45:03 -08001127
1128 #
1129 # Ensure only solicit messages are duplicated
1130 #
John Lo70bfcaf2017-11-14 13:19:26 -05001131 p_request_vrf1 = (Ether(dst=dmac, src=self.pg4.remote_mac) /
Neale Ranns3466c302017-02-16 07:45:03 -08001132 IPv6(src=dhcp_solicit_src_vrf1,
1133 dst=dhcp_solicit_dst) /
1134 UDP(sport=DHCP6_SERVER_PORT,
1135 dport=DHCP6_CLIENT_PORT) /
1136 DHCP6_Request())
1137
John Lo70bfcaf2017-11-14 13:19:26 -05001138 self.pg4.add_stream(p_request_vrf1)
Neale Ranns3466c302017-02-16 07:45:03 -08001139 self.pg_enable_capture(self.pg_interfaces)
1140 self.pg_start()
1141
1142 rx = self.pg1.get_capture(1)
1143
1144 #
1145 # Test we drop DHCP packets from addresses that are not configured as
1146 # DHCP servers
1147 #
1148 p2 = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_hosts[1].mac) /
1149 IPv6(dst=self.pg1.local_ip6, src="3001::1") /
1150 UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_SERVER_PORT) /
1151 DHCP6_RelayReply(peeraddr=dhcp_solicit_src_vrf1) /
John Lo70bfcaf2017-11-14 13:19:26 -05001152 DHCP6OptIfaceId(optlen=4, ifaceid='\x00\x00\x00\x05') /
Neale Ranns3466c302017-02-16 07:45:03 -08001153 DHCP6OptRelayMsg(optlen=0) /
1154 DHCP6_Advertise(trid=1) /
1155 DHCP6OptStatusCode(statuscode=0))
1156 self.send_and_assert_no_replies(self.pg1, p2,
1157 "DHCP6 not from server")
1158
1159 #
1160 # Remove the second DHCP server
1161 #
John Lo70bfcaf2017-11-14 13:19:26 -05001162 self.vapi.dhcp_proxy_config(server_addr12,
Neale Ranns3466c302017-02-16 07:45:03 -08001163 src_addr_vrf1,
1164 rx_table_id=1,
1165 server_table_id=1,
1166 is_ipv6=1,
1167 is_add=0)
1168
1169 #
1170 # Test we can still relay with the first
1171 #
John Lo70bfcaf2017-11-14 13:19:26 -05001172 self.pg4.add_stream(p_solicit_vrf1)
Neale Ranns3466c302017-02-16 07:45:03 -08001173 self.pg_enable_capture(self.pg_interfaces)
1174 self.pg_start()
1175
1176 rx = self.pg1.get_capture(1)
1177
1178 self.verify_dhcp6_solicit(rx[0], self.pg1,
Neale Rannsfca0c242017-01-13 07:57:46 -08001179 dhcp_solicit_src_vrf1,
John Lo70bfcaf2017-11-14 13:19:26 -05001180 self.pg4.remote_mac)
Neale Rannsfca0c242017-01-13 07:57:46 -08001181
1182 #
1183 # Cleanup
1184 #
John Lo70bfcaf2017-11-14 13:19:26 -05001185 self.vapi.dhcp_proxy_config(server_addr_vrf2,
1186 src_addr_vrf2,
1187 rx_table_id=2,
1188 server_table_id=2,
1189 is_ipv6=1,
1190 is_add=0)
Neale Rannsfca0c242017-01-13 07:57:46 -08001191 self.vapi.dhcp_proxy_config(server_addr_vrf1,
1192 src_addr_vrf1,
1193 rx_table_id=1,
1194 server_table_id=1,
Neale Rannsfca0c242017-01-13 07:57:46 -08001195 is_ipv6=1,
1196 is_add=0)
Neale Ranns3466c302017-02-16 07:45:03 -08001197 self.vapi.dhcp_proxy_config(server_addr_vrf0,
1198 src_addr_vrf0,
1199 rx_table_id=0,
1200 server_table_id=0,
1201 is_ipv6=1,
1202 is_add=0)
1203
1204 # duplicate delete
1205 self.vapi.dhcp_proxy_config(server_addr_vrf0,
1206 src_addr_vrf0,
Neale Rannsfca0c242017-01-13 07:57:46 -08001207 rx_table_id=0,
1208 server_table_id=0,
Neale Rannsfca0c242017-01-13 07:57:46 -08001209 is_ipv6=1,
1210 is_add=0)
Neale Ranns15002542017-09-10 04:39:11 -07001211 self.pg3.unconfig_ip6()
John Lo70bfcaf2017-11-14 13:19:26 -05001212 self.pg4.unconfig_ip6()
1213 self.pg5.unconfig_ip6()
Neale Rannsfca0c242017-01-13 07:57:46 -08001214
Neale Rannsa2fbf6b2017-07-18 08:23:32 -07001215 def test_dhcp_client(self):
1216 """ DHCP Client"""
1217
1218 hostname = 'universal-dp'
1219
1220 self.pg_enable_capture(self.pg_interfaces)
1221
1222 #
John Lo70bfcaf2017-11-14 13:19:26 -05001223 # Configure DHCP client on PG3 and capture the discover sent
Neale Rannsa2fbf6b2017-07-18 08:23:32 -07001224 #
Ole Troane1ade682019-03-04 23:55:43 +01001225 self.vapi.dhcp_client_config(self.pg3.sw_if_index, hostname)
Neale Rannsa2fbf6b2017-07-18 08:23:32 -07001226
John Lo70bfcaf2017-11-14 13:19:26 -05001227 rx = self.pg3.get_capture(1)
Neale Rannsa2fbf6b2017-07-18 08:23:32 -07001228
John Lo70bfcaf2017-11-14 13:19:26 -05001229 self.verify_orig_dhcp_discover(rx[0], self.pg3, hostname)
Neale Rannsa2fbf6b2017-07-18 08:23:32 -07001230
1231 #
John Lo70bfcaf2017-11-14 13:19:26 -05001232 # Send back on offer, expect the request
Neale Rannsa2fbf6b2017-07-18 08:23:32 -07001233 #
John Lo70bfcaf2017-11-14 13:19:26 -05001234 p_offer = (Ether(dst=self.pg3.local_mac, src=self.pg3.remote_mac) /
1235 IP(src=self.pg3.remote_ip4, dst="255.255.255.255") /
Neale Ranns808c5b22017-08-02 05:15:07 -07001236 UDP(sport=DHCP4_SERVER_PORT, dport=DHCP4_CLIENT_PORT) /
Neale Ranns1f2f4b72018-03-23 11:53:12 -07001237 BOOTP(op=1,
1238 yiaddr=self.pg3.local_ip4,
Ole Troan8006c6a2018-12-17 12:02:26 +01001239 chaddr=mac_pton(self.pg3.local_mac)) /
Neale Ranns808c5b22017-08-02 05:15:07 -07001240 DHCP(options=[('message-type', 'offer'),
John Lo70bfcaf2017-11-14 13:19:26 -05001241 ('server_id', self.pg3.remote_ip4),
Jan Gelety2a3fb1a2018-06-27 10:56:17 +02001242 'end']))
Neale Rannsa2fbf6b2017-07-18 08:23:32 -07001243
John Lo70bfcaf2017-11-14 13:19:26 -05001244 self.pg3.add_stream(p_offer)
Neale Rannsa2fbf6b2017-07-18 08:23:32 -07001245 self.pg_enable_capture(self.pg_interfaces)
1246 self.pg_start()
1247
John Lo70bfcaf2017-11-14 13:19:26 -05001248 rx = self.pg3.get_capture(1)
1249 self.verify_orig_dhcp_request(rx[0], self.pg3, hostname,
1250 self.pg3.local_ip4)
Neale Rannsa2fbf6b2017-07-18 08:23:32 -07001251
1252 #
Jan Gelety2a3fb1a2018-06-27 10:56:17 +02001253 # Send an acknowledgment
Neale Rannsa2fbf6b2017-07-18 08:23:32 -07001254 #
John Lo70bfcaf2017-11-14 13:19:26 -05001255 p_ack = (Ether(dst=self.pg3.local_mac, src=self.pg3.remote_mac) /
1256 IP(src=self.pg3.remote_ip4, dst="255.255.255.255") /
Neale Ranns808c5b22017-08-02 05:15:07 -07001257 UDP(sport=DHCP4_SERVER_PORT, dport=DHCP4_CLIENT_PORT) /
Neale Ranns1f2f4b72018-03-23 11:53:12 -07001258 BOOTP(op=1, yiaddr=self.pg3.local_ip4,
Ole Troan8006c6a2018-12-17 12:02:26 +01001259 chaddr=mac_pton(self.pg3.local_mac)) /
Neale Ranns808c5b22017-08-02 05:15:07 -07001260 DHCP(options=[('message-type', 'ack'),
1261 ('subnet_mask', "255.255.255.0"),
John Lo70bfcaf2017-11-14 13:19:26 -05001262 ('router', self.pg3.remote_ip4),
1263 ('server_id', self.pg3.remote_ip4),
Neale Ranns808c5b22017-08-02 05:15:07 -07001264 ('lease_time', 43200),
Jan Gelety2a3fb1a2018-06-27 10:56:17 +02001265 'end']))
Neale Rannsa2fbf6b2017-07-18 08:23:32 -07001266
John Lo70bfcaf2017-11-14 13:19:26 -05001267 self.pg3.add_stream(p_ack)
Neale Rannsa2fbf6b2017-07-18 08:23:32 -07001268 self.pg_enable_capture(self.pg_interfaces)
1269 self.pg_start()
1270
1271 #
Neale Ranns51822bf2017-07-18 09:26:53 -07001272 # We'll get an ARP request for the router address
1273 #
John Lo70bfcaf2017-11-14 13:19:26 -05001274 rx = self.pg3.get_capture(1)
Neale Ranns51822bf2017-07-18 09:26:53 -07001275
John Lo70bfcaf2017-11-14 13:19:26 -05001276 self.assertEqual(rx[0][ARP].pdst, self.pg3.remote_ip4)
Neale Ranns51822bf2017-07-18 09:26:53 -07001277 self.pg_enable_capture(self.pg_interfaces)
1278
1279 #
Neale Rannsa2fbf6b2017-07-18 08:23:32 -07001280 # At the end of this procedure there should be a connected route
1281 # in the FIB
1282 #
John Lo70bfcaf2017-11-14 13:19:26 -05001283 self.assertTrue(find_route(self, self.pg3.local_ip4, 24))
1284 self.assertTrue(find_route(self, self.pg3.local_ip4, 32))
Neale Rannsa2fbf6b2017-07-18 08:23:32 -07001285
Neale Ranns51822bf2017-07-18 09:26:53 -07001286 # remove the left over ARP entry
John Lo70bfcaf2017-11-14 13:19:26 -05001287 self.vapi.ip_neighbor_add_del(self.pg3.sw_if_index,
Neale Ranns37029302018-08-10 05:30:06 -07001288 self.pg3.remote_mac,
John Lo70bfcaf2017-11-14 13:19:26 -05001289 self.pg3.remote_ip4,
Neale Ranns51822bf2017-07-18 09:26:53 -07001290 is_add=0)
Neale Ranns37029302018-08-10 05:30:06 -07001291
Neale Rannsa2fbf6b2017-07-18 08:23:32 -07001292 #
1293 # remove the DHCP config
1294 #
Ole Troane1ade682019-03-04 23:55:43 +01001295 self.vapi.dhcp_client_config(self.pg3.sw_if_index, hostname, is_add=0)
Neale Rannsa2fbf6b2017-07-18 08:23:32 -07001296
1297 #
1298 # and now the route should be gone
1299 #
John Lo70bfcaf2017-11-14 13:19:26 -05001300 self.assertFalse(find_route(self, self.pg3.local_ip4, 32))
1301 self.assertFalse(find_route(self, self.pg3.local_ip4, 24))
Neale Rannsa2fbf6b2017-07-18 08:23:32 -07001302
Neale Ranns51822bf2017-07-18 09:26:53 -07001303 #
Neale Ranns808c5b22017-08-02 05:15:07 -07001304 # Start the procedure again. this time have VPP send the client-ID
Neale Ranns51822bf2017-07-18 09:26:53 -07001305 #
John Lo70bfcaf2017-11-14 13:19:26 -05001306 self.pg3.admin_down()
Neale Ranns808c5b22017-08-02 05:15:07 -07001307 self.sleep(1)
John Lo70bfcaf2017-11-14 13:19:26 -05001308 self.pg3.admin_up()
Ole Troane1ade682019-03-04 23:55:43 +01001309 self.vapi.dhcp_client_config(self.pg3.sw_if_index, hostname,
1310 client_id=self.pg3.local_mac)
Neale Ranns51822bf2017-07-18 09:26:53 -07001311
John Lo70bfcaf2017-11-14 13:19:26 -05001312 rx = self.pg3.get_capture(1)
Neale Ranns51822bf2017-07-18 09:26:53 -07001313
John Lo70bfcaf2017-11-14 13:19:26 -05001314 self.verify_orig_dhcp_discover(rx[0], self.pg3, hostname,
1315 self.pg3.local_mac)
Neale Ranns51822bf2017-07-18 09:26:53 -07001316
Jan Gelety2a3fb1a2018-06-27 10:56:17 +02001317 # TODO: VPP DHCP client should not accept DHCP OFFER message with
1318 # the XID (Transaction ID) not matching the XID of the most recent
1319 # DHCP DISCOVERY message.
1320 # Such DHCP OFFER message must be silently discarded - RFC2131.
1321 # Reported in Jira ticket: VPP-99
John Lo70bfcaf2017-11-14 13:19:26 -05001322 self.pg3.add_stream(p_offer)
Neale Ranns808c5b22017-08-02 05:15:07 -07001323 self.pg_enable_capture(self.pg_interfaces)
1324 self.pg_start()
1325
John Lo70bfcaf2017-11-14 13:19:26 -05001326 rx = self.pg3.get_capture(1)
1327 self.verify_orig_dhcp_request(rx[0], self.pg3, hostname,
1328 self.pg3.local_ip4)
Neale Ranns808c5b22017-08-02 05:15:07 -07001329
1330 #
1331 # unicast the ack to the offered address
1332 #
John Lo70bfcaf2017-11-14 13:19:26 -05001333 p_ack = (Ether(dst=self.pg3.local_mac, src=self.pg3.remote_mac) /
1334 IP(src=self.pg3.remote_ip4, dst=self.pg3.local_ip4) /
Neale Ranns808c5b22017-08-02 05:15:07 -07001335 UDP(sport=DHCP4_SERVER_PORT, dport=DHCP4_CLIENT_PORT) /
Neale Ranns1f2f4b72018-03-23 11:53:12 -07001336 BOOTP(op=1, yiaddr=self.pg3.local_ip4,
Ole Troan8006c6a2018-12-17 12:02:26 +01001337 chaddr=mac_pton(self.pg3.local_mac)) /
Neale Ranns808c5b22017-08-02 05:15:07 -07001338 DHCP(options=[('message-type', 'ack'),
1339 ('subnet_mask', "255.255.255.0"),
John Lo70bfcaf2017-11-14 13:19:26 -05001340 ('router', self.pg3.remote_ip4),
1341 ('server_id', self.pg3.remote_ip4),
Neale Ranns808c5b22017-08-02 05:15:07 -07001342 ('lease_time', 43200),
Jan Gelety2a3fb1a2018-06-27 10:56:17 +02001343 'end']))
Neale Ranns808c5b22017-08-02 05:15:07 -07001344
John Lo70bfcaf2017-11-14 13:19:26 -05001345 self.pg3.add_stream(p_ack)
Neale Ranns808c5b22017-08-02 05:15:07 -07001346 self.pg_enable_capture(self.pg_interfaces)
1347 self.pg_start()
1348
1349 #
Neale Ranns54c6dc42018-01-17 10:29:10 -08001350 # We'll get an ARP request for the router address
1351 #
1352 rx = self.pg3.get_capture(1)
1353
1354 self.assertEqual(rx[0][ARP].pdst, self.pg3.remote_ip4)
1355 self.pg_enable_capture(self.pg_interfaces)
1356
1357 #
Neale Ranns808c5b22017-08-02 05:15:07 -07001358 # At the end of this procedure there should be a connected route
1359 # in the FIB
1360 #
John Lo70bfcaf2017-11-14 13:19:26 -05001361 self.assertTrue(find_route(self, self.pg3.local_ip4, 32))
1362 self.assertTrue(find_route(self, self.pg3.local_ip4, 24))
Neale Ranns808c5b22017-08-02 05:15:07 -07001363
Neale Ranns51822bf2017-07-18 09:26:53 -07001364 #
1365 # remove the DHCP config
1366 #
Ole Troane1ade682019-03-04 23:55:43 +01001367 self.vapi.dhcp_client_config(self.pg3.sw_if_index, hostname, is_add=0)
Neale Rannsa2fbf6b2017-07-18 08:23:32 -07001368
John Lo70bfcaf2017-11-14 13:19:26 -05001369 self.assertFalse(find_route(self, self.pg3.local_ip4, 32))
1370 self.assertFalse(find_route(self, self.pg3.local_ip4, 24))
Neale Ranns808c5b22017-08-02 05:15:07 -07001371
Neale Ranns54c6dc42018-01-17 10:29:10 -08001372 #
1373 # Rince and repeat, this time with VPP configured not to set
1374 # the braodcast flag in the discover and request messages,
1375 # and for the server to unicast the responses.
1376 #
1377 # Configure DHCP client on PG3 and capture the discover sent
1378 #
Ole Troane1ade682019-03-04 23:55:43 +01001379 self.vapi.dhcp_client_config(self.pg3.sw_if_index, hostname,
1380 set_broadcast_flag=0)
Neale Ranns54c6dc42018-01-17 10:29:10 -08001381
1382 rx = self.pg3.get_capture(1)
1383
1384 self.verify_orig_dhcp_discover(rx[0], self.pg3, hostname,
1385 broadcast=0)
1386
1387 #
1388 # Send back on offer, unicasted to the offered address.
1389 # Expect the request.
1390 #
1391 p_offer = (Ether(dst=self.pg3.local_mac, src=self.pg3.remote_mac) /
1392 IP(src=self.pg3.remote_ip4, dst=self.pg3.local_ip4) /
1393 UDP(sport=DHCP4_SERVER_PORT, dport=DHCP4_CLIENT_PORT) /
Neale Ranns1f2f4b72018-03-23 11:53:12 -07001394 BOOTP(op=1, yiaddr=self.pg3.local_ip4,
Ole Troan8006c6a2018-12-17 12:02:26 +01001395 chaddr=mac_pton(self.pg3.local_mac)) /
Neale Ranns54c6dc42018-01-17 10:29:10 -08001396 DHCP(options=[('message-type', 'offer'),
1397 ('server_id', self.pg3.remote_ip4),
Jan Gelety2a3fb1a2018-06-27 10:56:17 +02001398 'end']))
Neale Ranns54c6dc42018-01-17 10:29:10 -08001399
1400 self.pg3.add_stream(p_offer)
1401 self.pg_enable_capture(self.pg_interfaces)
1402 self.pg_start()
1403
1404 rx = self.pg3.get_capture(1)
1405 self.verify_orig_dhcp_request(rx[0], self.pg3, hostname,
1406 self.pg3.local_ip4,
1407 broadcast=0)
1408
1409 #
Jan Gelety2a3fb1a2018-06-27 10:56:17 +02001410 # Send an acknowledgment
Neale Ranns54c6dc42018-01-17 10:29:10 -08001411 #
1412 p_ack = (Ether(dst=self.pg3.local_mac, src=self.pg3.remote_mac) /
1413 IP(src=self.pg3.remote_ip4, dst=self.pg3.local_ip4) /
1414 UDP(sport=DHCP4_SERVER_PORT, dport=DHCP4_CLIENT_PORT) /
Neale Ranns1f2f4b72018-03-23 11:53:12 -07001415 BOOTP(op=1, yiaddr=self.pg3.local_ip4,
Ole Troan8006c6a2018-12-17 12:02:26 +01001416 chaddr=mac_pton(self.pg3.local_mac)) /
Neale Ranns54c6dc42018-01-17 10:29:10 -08001417 DHCP(options=[('message-type', 'ack'),
1418 ('subnet_mask', "255.255.255.0"),
1419 ('router', self.pg3.remote_ip4),
1420 ('server_id', self.pg3.remote_ip4),
1421 ('lease_time', 43200),
Jan Gelety2a3fb1a2018-06-27 10:56:17 +02001422 'end']))
Neale Ranns54c6dc42018-01-17 10:29:10 -08001423
1424 self.pg3.add_stream(p_ack)
1425 self.pg_enable_capture(self.pg_interfaces)
1426 self.pg_start()
1427
1428 #
1429 # We'll get an ARP request for the router address
1430 #
1431 rx = self.pg3.get_capture(1)
1432
1433 self.assertEqual(rx[0][ARP].pdst, self.pg3.remote_ip4)
1434 self.pg_enable_capture(self.pg_interfaces)
1435
1436 #
1437 # At the end of this procedure there should be a connected route
1438 # in the FIB
1439 #
1440 self.assertTrue(find_route(self, self.pg3.local_ip4, 24))
1441 self.assertTrue(find_route(self, self.pg3.local_ip4, 32))
1442
1443 # remove the left over ARP entry
1444 self.vapi.ip_neighbor_add_del(self.pg3.sw_if_index,
Neale Ranns37029302018-08-10 05:30:06 -07001445 self.pg3.remote_mac,
Neale Ranns54c6dc42018-01-17 10:29:10 -08001446 self.pg3.remote_ip4,
1447 is_add=0)
Neale Rannsdaff1782018-05-16 04:12:18 -07001448
1449 #
1450 # read the DHCP client details from a dump
1451 #
1452 clients = self.vapi.dhcp_client_dump()
1453
1454 self.assertEqual(clients[0].client.sw_if_index,
1455 self.pg3.sw_if_index)
1456 self.assertEqual(clients[0].lease.sw_if_index,
1457 self.pg3.sw_if_index)
1458 self.assertEqual(clients[0].client.hostname.rstrip('\0'),
1459 hostname)
1460 self.assertEqual(clients[0].lease.hostname.rstrip('\0'),
1461 hostname)
1462 self.assertEqual(clients[0].lease.is_ipv6, 0)
1463 # 0 = DISCOVER, 1 = REQUEST, 2 = BOUND
1464 self.assertEqual(clients[0].lease.state, 2)
1465 self.assertEqual(clients[0].lease.mask_width, 24)
1466 self.assertEqual(clients[0].lease.router_address.rstrip('\0'),
1467 self.pg3.remote_ip4n)
1468 self.assertEqual(clients[0].lease.host_address.rstrip('\0'),
1469 self.pg3.local_ip4n)
1470
Neale Ranns54c6dc42018-01-17 10:29:10 -08001471 #
1472 # remove the DHCP config
1473 #
Ole Troane1ade682019-03-04 23:55:43 +01001474 self.vapi.dhcp_client_config(self.pg3.sw_if_index, hostname, is_add=0)
Neale Ranns54c6dc42018-01-17 10:29:10 -08001475
1476 #
1477 # and now the route should be gone
1478 #
1479 self.assertFalse(find_route(self, self.pg3.local_ip4, 32))
1480 self.assertFalse(find_route(self, self.pg3.local_ip4, 24))
1481
Jan Gelety2a3fb1a2018-06-27 10:56:17 +02001482 #
1483 # Start the procedure again. Use requested lease time option.
1484 #
1485 self.pg3.admin_down()
1486 self.sleep(1)
1487 self.pg3.admin_up()
Ole Troane1ade682019-03-04 23:55:43 +01001488 self.vapi.dhcp_client_config(self.pg3.sw_if_index, hostname)
Jan Gelety2a3fb1a2018-06-27 10:56:17 +02001489
1490 rx = self.pg3.get_capture(1)
1491
1492 self.verify_orig_dhcp_discover(rx[0], self.pg3, hostname)
1493
1494 #
1495 # Send back on offer with requested lease time, expect the request
1496 #
1497 lease_time = 1
1498 p_offer = (Ether(dst=self.pg3.local_mac, src=self.pg3.remote_mac) /
1499 IP(src=self.pg3.remote_ip4, dst='255.255.255.255') /
1500 UDP(sport=DHCP4_SERVER_PORT, dport=DHCP4_CLIENT_PORT) /
1501 BOOTP(op=1,
1502 yiaddr=self.pg3.local_ip4,
Ole Troan8006c6a2018-12-17 12:02:26 +01001503 chaddr=mac_pton(self.pg3.local_mac)) /
Jan Gelety2a3fb1a2018-06-27 10:56:17 +02001504 DHCP(options=[('message-type', 'offer'),
1505 ('server_id', self.pg3.remote_ip4),
1506 ('lease_time', lease_time),
1507 'end']))
1508
1509 self.pg3.add_stream(p_offer)
1510 self.pg_enable_capture(self.pg_interfaces)
1511 self.pg_start()
1512
1513 rx = self.pg3.get_capture(1)
1514 self.verify_orig_dhcp_request(rx[0], self.pg3, hostname,
1515 self.pg3.local_ip4)
1516
1517 #
1518 # Send an acknowledgment
1519 #
1520 p_ack = (Ether(dst=self.pg3.local_mac, src=self.pg3.remote_mac) /
1521 IP(src=self.pg3.remote_ip4, dst='255.255.255.255') /
1522 UDP(sport=DHCP4_SERVER_PORT, dport=DHCP4_CLIENT_PORT) /
1523 BOOTP(op=1, yiaddr=self.pg3.local_ip4,
Ole Troan8006c6a2018-12-17 12:02:26 +01001524 chaddr=mac_pton(self.pg3.local_mac)) /
Jan Gelety2a3fb1a2018-06-27 10:56:17 +02001525 DHCP(options=[('message-type', 'ack'),
1526 ('subnet_mask', '255.255.255.0'),
1527 ('router', self.pg3.remote_ip4),
1528 ('server_id', self.pg3.remote_ip4),
1529 ('lease_time', lease_time),
1530 'end']))
1531
1532 self.pg3.add_stream(p_ack)
1533 self.pg_enable_capture(self.pg_interfaces)
1534 self.pg_start()
1535
1536 #
1537 # We'll get an ARP request for the router address
1538 #
1539 rx = self.pg3.get_capture(1)
1540
1541 self.assertEqual(rx[0][ARP].pdst, self.pg3.remote_ip4)
1542
1543 #
1544 # At the end of this procedure there should be a connected route
1545 # in the FIB
1546 #
1547 self.assertTrue(find_route(self, self.pg3.local_ip4, 32))
1548 self.assertTrue(find_route(self, self.pg3.local_ip4, 24))
1549
1550 # remove the left over ARP entry
1551 self.vapi.ip_neighbor_add_del(self.pg3.sw_if_index,
Neale Ranns37029302018-08-10 05:30:06 -07001552 self.pg3.remote_mac,
Jan Gelety2a3fb1a2018-06-27 10:56:17 +02001553 self.pg3.remote_ip4,
1554 is_add=0)
1555
1556 #
Neale Rannsf6e9b012019-01-25 06:37:15 -08001557 # the route should be gone after the lease expires
Jan Gelety2a3fb1a2018-06-27 10:56:17 +02001558 #
Neale Rannsf6e9b012019-01-25 06:37:15 -08001559 self.assertTrue(self.wait_for_no_route(self.pg3.local_ip4, 32))
1560 self.assertTrue(self.wait_for_no_route(self.pg3.local_ip4, 24))
Jan Gelety2a3fb1a2018-06-27 10:56:17 +02001561
1562 #
1563 # remove the DHCP config
1564 #
Ole Troane1ade682019-03-04 23:55:43 +01001565 self.vapi.dhcp_client_config(self.pg3.sw_if_index, hostname, is_add=0)
Jan Gelety2a3fb1a2018-06-27 10:56:17 +02001566
Neale Ranns808c5b22017-08-02 05:15:07 -07001567
Neale Rannsfca0c242017-01-13 07:57:46 -08001568if __name__ == '__main__':
1569 unittest.main(testRunner=VppTestRunner)