blob: bdff679c6b2b03d830ace96deab255a0594e48c7 [file] [log] [blame]
Neale Rannsfca0c242017-01-13 07:57:46 -08001#!/usr/bin/env python
2
3import unittest
4import socket
5
6from framework import VppTestCase, VppTestRunner
7from vpp_ip_route import IpRoute, RoutePath
8from vpp_lo_interface import VppLoInterface
9
10from scapy.layers.l2 import Ether, getmacbyip
11from scapy.layers.inet import IP, UDP, ICMP
12from scapy.layers.inet6 import IPv6, in6_getnsmac, in6_mactoifaceid
13from scapy.layers.dhcp import DHCP, BOOTP, DHCPTypes
14from scapy.layers.dhcp6 import DHCP6, DHCP6_Solicit, DHCP6_RelayForward, \
15 DHCP6_RelayReply, DHCP6_Advertise, DHCP6OptRelayMsg, DHCP6OptIfaceId, \
16 DHCP6OptStatusCode, DHCP6OptVSS, DHCP6OptClientLinkLayerAddr
17from socket import AF_INET, AF_INET6
18from scapy.utils import inet_pton, inet_ntop
19from scapy.utils6 import in6_ptop
20
21DHCP4_CLIENT_PORT = 68
22DHCP4_SERVER_PORT = 67
23DHCP6_CLIENT_PORT = 547
24DHCP6_SERVER_PORT = 546
25
26
27def mk_ll_addr(mac):
28
29 euid = in6_mactoifaceid(mac)
30 addr = "fe80::" + euid
31 return addr
32
33
34class TestDHCP(VppTestCase):
35 """ DHCP Test Case """
36
37 def setUp(self):
38 super(TestDHCP, self).setUp()
39
40 # create 3 pg interfaces
41 self.create_pg_interfaces(range(4))
42
43 # pg0 and 1 are IP configured in VRF 0 and 1.
44 # pg2 and 3 are non IP-configured in VRF 0 and 1
45 table_id = 0
46 for i in self.pg_interfaces[:2]:
47 i.admin_up()
48 i.set_table_ip4(table_id)
49 i.set_table_ip6(table_id)
50 i.config_ip4()
51 i.resolve_arp()
52 i.config_ip6()
53 i.resolve_ndp()
54 table_id += 1
55
56 table_id = 0
57 for i in self.pg_interfaces[2:]:
58 i.admin_up()
59 i.set_table_ip4(table_id)
60 i.set_table_ip6(table_id)
61 table_id += 1
62
63 def send_and_assert_no_replies(self, intf, pkts, remark):
64 intf.add_stream(pkts)
65 self.pg_enable_capture(self.pg_interfaces)
66 self.pg_start()
67 for i in self.pg_interfaces:
68 i.assert_nothing_captured(remark=remark)
69
70 def validate_option_82(self, pkt, intf, ip_addr):
71 dhcp = pkt[DHCP]
72 found = 0
73 data = []
74
75 for i in dhcp.options:
76 if type(i) is tuple:
77 if i[0] == "relay_agent_Information":
78 #
79 # There are two sb-options present - each of length 6.
80 #
81 data = i[1]
82 self.assertEqual(len(data), 12)
83
84 #
85 # First sub-option is ID 1, len 4, then encoded
86 # sw_if_index. This test uses low valued indicies
87 # so [2:4] are 0.
88 # The ID space is VPP internal - so no matching value
89 # scapy
90 #
91 self.assertEqual(ord(data[0]), 1)
92 self.assertEqual(ord(data[1]), 4)
93 self.assertEqual(ord(data[2]), 0)
94 self.assertEqual(ord(data[3]), 0)
95 self.assertEqual(ord(data[4]), 0)
96 self.assertEqual(ord(data[5]), intf._sw_if_index)
97
98 #
99 # next sub-option is the IP address of the client side
100 # interface.
101 # sub-option ID=5, length (of a v4 address)=4
102 #
103 claddr = socket.inet_pton(AF_INET, ip_addr)
104
105 self.assertEqual(ord(data[6]), 5)
106 self.assertEqual(ord(data[7]), 4)
107 self.assertEqual(data[8], claddr[0])
108 self.assertEqual(data[9], claddr[1])
109 self.assertEqual(data[10], claddr[2])
110 self.assertEqual(data[11], claddr[3])
111
112 found = 1
113 self.assertTrue(found)
114
115 return data
116
117 def verify_dhcp_offer(self, pkt, intf, check_option_82=True):
118 ether = pkt[Ether]
119 self.assertEqual(ether.dst, "ff:ff:ff:ff:ff:ff")
120 self.assertEqual(ether.src, intf.local_mac)
121
122 ip = pkt[IP]
123 self.assertEqual(ip.dst, "255.255.255.255")
124 self.assertEqual(ip.src, intf.local_ip4)
125
126 udp = pkt[UDP]
127 self.assertEqual(udp.dport, DHCP4_CLIENT_PORT)
128 self.assertEqual(udp.sport, DHCP4_SERVER_PORT)
129
130 dhcp = pkt[DHCP]
131 is_offer = False
132 for o in dhcp.options:
133 if type(o) is tuple:
134 if o[0] == "message-type" \
135 and DHCPTypes[o[1]] == "offer":
136 is_offer = True
137 self.assertTrue(is_offer)
138
139 if check_option_82:
140 data = self.validate_option_82(pkt, intf, intf.local_ip4)
141
142 def verify_dhcp_discover(self, pkt, intf, src_intf=None,
143 option_82_present=True):
144 ether = pkt[Ether]
145 self.assertEqual(ether.dst, intf.remote_mac)
146 self.assertEqual(ether.src, intf.local_mac)
147
148 ip = pkt[IP]
149 self.assertEqual(ip.dst, intf.remote_ip4)
150 self.assertEqual(ip.src, intf.local_ip4)
151
152 udp = pkt[UDP]
153 self.assertEqual(udp.dport, DHCP4_SERVER_PORT)
154 self.assertEqual(udp.sport, DHCP4_CLIENT_PORT)
155
156 dhcp = pkt[DHCP]
157
158 is_discover = False
159 for o in dhcp.options:
160 if type(o) is tuple:
161 if o[0] == "message-type" \
162 and DHCPTypes[o[1]] == "discover":
163 is_discover = True
164 self.assertTrue(is_discover)
165
166 if option_82_present:
167 data = self.validate_option_82(pkt, src_intf, src_intf.local_ip4)
168 return data
169 else:
170 for i in dhcp.options:
171 if type(i) is tuple:
172 self.assertNotEqual(i[0], "relay_agent_Information")
173
174 def verify_dhcp6_solicit(self, pkt, intf,
175 peer_ip, peer_mac,
176 fib_id=0,
177 oui=0):
178 ether = pkt[Ether]
179 self.assertEqual(ether.dst, intf.remote_mac)
180 self.assertEqual(ether.src, intf.local_mac)
181
182 ip = pkt[IPv6]
183 self.assertEqual(in6_ptop(ip.dst), in6_ptop(intf.remote_ip6))
184 self.assertEqual(in6_ptop(ip.src), in6_ptop(intf.local_ip6))
185
186 udp = pkt[UDP]
187 self.assertEqual(udp.dport, DHCP6_CLIENT_PORT)
188 self.assertEqual(udp.sport, DHCP6_SERVER_PORT)
189
190 relay = pkt[DHCP6_RelayForward]
191 self.assertEqual(in6_ptop(relay.peeraddr), in6_ptop(peer_ip))
192 oid = pkt[DHCP6OptIfaceId]
193 cll = pkt[DHCP6OptClientLinkLayerAddr]
194 self.assertEqual(cll.optlen, 8)
195 self.assertEqual(cll.lltype, 1)
196 self.assertEqual(cll.clladdr, peer_mac)
197
198 vss = pkt[DHCP6OptVSS]
199 self.assertEqual(vss.optlen, 8)
200 self.assertEqual(vss.type, 1)
201 # the OUI and FIB-id are really 3 and 4 bytes resp.
202 # but the tested range is small
203 self.assertEqual(ord(vss.data[0]), 0)
204 self.assertEqual(ord(vss.data[1]), 0)
205 self.assertEqual(ord(vss.data[2]), oui)
206 self.assertEqual(ord(vss.data[3]), 0)
207 self.assertEqual(ord(vss.data[4]), 0)
208 self.assertEqual(ord(vss.data[5]), 0)
209 self.assertEqual(ord(vss.data[6]), fib_id)
210
211 # the relay message should be an encoded Solicit
212 msg = pkt[DHCP6OptRelayMsg]
213 sol = DHCP6_Solicit()
214 self.assertEqual(msg.optlen, len(str(sol)))
215 self.assertEqual(str(sol), (str(msg[1]))[:msg.optlen])
216
217 def verify_dhcp6_advert(self, pkt, intf, peer):
218 ether = pkt[Ether]
219 self.assertEqual(ether.dst, "ff:ff:ff:ff:ff:ff")
220 self.assertEqual(ether.src, intf.local_mac)
221
222 ip = pkt[IPv6]
223 self.assertEqual(in6_ptop(ip.dst), in6_ptop(peer))
224 self.assertEqual(in6_ptop(ip.src), in6_ptop(intf.local_ip6))
225
226 udp = pkt[UDP]
227 self.assertEqual(udp.dport, DHCP6_SERVER_PORT)
228 self.assertEqual(udp.sport, DHCP6_CLIENT_PORT)
229
230 # not sure why this is not decoding
231 # adv = pkt[DHCP6_Advertise]
232
233 def test_dhcp_proxy(self):
234 """ DHCPv4 Proxy """
235
236 #
237 # Verify no response to DHCP request without DHCP config
238 #
239 p_disc_vrf0 = (Ether(dst="ff:ff:ff:ff:ff:ff",
240 src=self.pg2.remote_mac) /
241 IP(src="0.0.0.0", dst="255.255.255.255") /
242 UDP(sport=DHCP4_CLIENT_PORT,
243 dport=DHCP4_SERVER_PORT) /
244 BOOTP(op=1) /
245 DHCP(options=[('message-type', 'discover'), ('end')]))
246 pkts_disc_vrf0 = [p_disc_vrf0]
247 p_disc_vrf1 = (Ether(dst="ff:ff:ff:ff:ff:ff",
248 src=self.pg3.remote_mac) /
249 IP(src="0.0.0.0", dst="255.255.255.255") /
250 UDP(sport=DHCP4_CLIENT_PORT,
251 dport=DHCP4_SERVER_PORT) /
252 BOOTP(op=1) /
253 DHCP(options=[('message-type', 'discover'), ('end')]))
254 pkts_disc_vrf1 = [p_disc_vrf0]
255
256 self.send_and_assert_no_replies(self.pg2, pkts_disc_vrf0,
257 "DHCP with no configuration")
258 self.send_and_assert_no_replies(self.pg3, pkts_disc_vrf1,
259 "DHCP with no configuration")
260
261 #
262 # Enable DHCP proxy in VRF 0
263 #
264 server_addr = self.pg0.remote_ip4n
265 src_addr = self.pg0.local_ip4n
266
267 self.vapi.dhcp_proxy_config(server_addr,
268 src_addr,
269 rx_table_id=0)
270
271 #
272 # Now a DHCP request on pg2, which is in the same VRF
273 # as the DHCP config, will result in a relayed DHCP
274 # message to the [fake] server
275 #
276 self.pg2.add_stream(pkts_disc_vrf0)
277 self.pg_enable_capture(self.pg_interfaces)
278 self.pg_start()
279
280 rx = self.pg0.get_capture(1)
281 rx = rx[0]
282
283 #
284 # Rx'd packet should be to the server address and from the configured
285 # source address
286 # UDP source ports are unchanged
287 # we've no option 82 config so that should be absent
288 #
289 self.verify_dhcp_discover(rx, self.pg0, option_82_present=False)
290
291 #
292 # Inject a response from the server
293 # VPP will only relay the offer if option 82 is present.
294 # so this one is dropped
295 #
296 p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
297 IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) /
298 UDP(sport=DHCP4_SERVER_PORT, dport=DHCP4_SERVER_PORT) /
299 BOOTP(op=1) /
300 DHCP(options=[('message-type', 'offer'), ('end')]))
301 pkts = [p]
302
303 self.send_and_assert_no_replies(self.pg0, pkts,
304 "DHCP offer no option 82")
305
306 #
307 # Configure sending option 82 in relayed messages
308 #
309 self.vapi.dhcp_proxy_config(server_addr,
310 src_addr,
311 rx_table_id=0,
312 insert_circuit_id=1)
313
314 #
315 # Send a request:
316 # again dropped, but ths time because there is no IP addrees on the
317 # clinet interfce to fill in the option.
318 #
319 self.send_and_assert_no_replies(self.pg2, pkts_disc_vrf0,
320 "DHCP no relay address")
321
322 #
323 # configure an IP address on the client facing interface
324 #
325 self.pg2.config_ip4()
326
327 #
328 # Try again with a discover packet
329 # Rx'd packet should be to the server address and from the configured
330 # source address
331 # UDP source ports are unchanged
332 # we've no option 82 config so that should be absent
333 #
334 self.pg2.add_stream(pkts_disc_vrf0)
335 self.pg_enable_capture(self.pg_interfaces)
336 self.pg_start()
337
338 rx = self.pg0.get_capture(1)
339 rx = rx[0]
340
341 option_82 = self.verify_dhcp_discover(rx, self.pg0, src_intf=self.pg2)
342
343 #
344 # Create an DHCP offer reply from the server with a correctly formatted
345 # option 82. i.e. send back what we just captured
346 # The offer, sent mcast to the client, still has option 82.
347 #
348 p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
349 IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) /
350 UDP(sport=DHCP4_SERVER_PORT, dport=DHCP4_SERVER_PORT) /
351 BOOTP(op=1) /
352 DHCP(options=[('message-type', 'offer'),
353 ('relay_agent_Information', option_82),
354 ('end')]))
355 pkts = [p]
356
357 self.pg0.add_stream(pkts)
358 self.pg_enable_capture(self.pg_interfaces)
359 self.pg_start()
360
361 rx = self.pg2.get_capture(1)
362 rx = rx[0]
363
364 self.verify_dhcp_offer(rx, self.pg2)
365
366 #
367 # Bogus Option 82:
368 #
369 # 1. not our IP address = not checked by VPP? so offer is replayed
370 # to client
371 bad_ip = option_82[0:8] + chr(33) + option_82[9:]
372
373 p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
374 IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) /
375 UDP(sport=DHCP4_SERVER_PORT, dport=DHCP4_SERVER_PORT) /
376 BOOTP(op=1) /
377 DHCP(options=[('message-type', 'offer'),
378 ('relay_agent_Information', bad_ip),
379 ('end')]))
380 pkts = [p]
381
382 self.pg0.add_stream(pkts)
383 self.pg_enable_capture(self.pg_interfaces)
384 self.pg_start()
385 rx = self.pg2.get_capture(1)
386 rx = rx[0]
387
388 self.verify_dhcp_offer(rx, self.pg2, check_option_82=False)
389 self.pg0.assert_nothing_captured(remark="")
390
391 # 2. Not a sw_if_index VPP knows
392 bad_if_index = option_82[0:2] + chr(33) + option_82[3:]
393
394 p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
395 IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) /
396 UDP(sport=DHCP4_SERVER_PORT, dport=DHCP4_SERVER_PORT) /
397 BOOTP(op=1) /
398 DHCP(options=[('message-type', 'offer'),
399 ('relay_agent_Information', bad_if_index),
400 ('end')]))
401 pkts = [p]
402 self.send_and_assert_no_replies(self.pg0, pkts,
403 "DHCP offer option 82 bad if index")
404
405 #
406 # Send a DHCP request in VRF 1. should be dropped.
407 #
408 self.send_and_assert_no_replies(self.pg3, pkts_disc_vrf1,
409 "DHCP with no configuration VRF 1")
410
411 #
412 # Delete the DHCP config in VRF 0
413 # Should now drop requests.
414 #
415 self.vapi.dhcp_proxy_config(server_addr,
416 src_addr,
417 rx_table_id=0,
418 is_add=0,
419 insert_circuit_id=1)
420
421 self.send_and_assert_no_replies(self.pg2, pkts_disc_vrf0,
422 "DHCP config removed VRF 0")
423 self.send_and_assert_no_replies(self.pg3, pkts_disc_vrf1,
424 "DHCP config removed VRF 1")
425
426 #
427 # Add DHCP config for VRF 1
428 #
429 server_addr = self.pg1.remote_ip4n
430 src_addr = self.pg1.local_ip4n
431 self.vapi.dhcp_proxy_config(server_addr,
432 src_addr,
433 rx_table_id=1,
434 server_table_id=1,
435 insert_circuit_id=1)
436
437 #
438 # Confim DHCP requests ok in VRF 1.
439 # - dropped on IP config on client interface
440 #
441 self.send_and_assert_no_replies(self.pg3, pkts_disc_vrf1,
442 "DHCP config removed VRF 1")
443
444 #
445 # configure an IP address on the client facing interface
446 #
447 self.pg3.config_ip4()
448
449 self.pg3.add_stream(pkts_disc_vrf1)
450 self.pg_enable_capture(self.pg_interfaces)
451 self.pg_start()
452
453 rx = self.pg1.get_capture(1)
454 rx = rx[0]
455 self.verify_dhcp_discover(rx, self.pg1, src_intf=self.pg3)
456
457 #
458 # remove DHCP config to cleanup
459 #
460 self.vapi.dhcp_proxy_config(server_addr,
461 src_addr,
462 rx_table_id=1,
463 server_table_id=1,
464 insert_circuit_id=1,
465 is_add=0)
466
467 self.send_and_assert_no_replies(self.pg2, pkts_disc_vrf0,
468 "DHCP cleanup VRF 0")
469 self.send_and_assert_no_replies(self.pg3, pkts_disc_vrf1,
470 "DHCP cleanup VRF 1")
471
472 def test_dhcp6_proxy(self):
473 """ DHCPv6 Proxy"""
474 #
475 # Verify no response to DHCP request without DHCP config
476 #
477 dhcp_solicit_dst = "ff02::1:2"
478 dhcp_solicit_src_vrf0 = mk_ll_addr(self.pg2.remote_mac)
479 dhcp_solicit_src_vrf1 = mk_ll_addr(self.pg3.remote_mac)
480 server_addr_vrf0 = self.pg0.remote_ip6n
481 src_addr_vrf0 = self.pg0.local_ip6n
482 server_addr_vrf1 = self.pg1.remote_ip6n
483 src_addr_vrf1 = self.pg1.local_ip6n
484
485 #
486 # Add the Route to receive the DHCP packets
487 #
488 route_dhcp_vrf0 = IpRoute(self, dhcp_solicit_dst, 128,
489 [], is_local=1, is_ip6=1)
490 route_dhcp_vrf0.add_vpp_config()
491 route_dhcp_vrf1 = IpRoute(self, dhcp_solicit_dst, 128,
492 [], is_local=1, is_ip6=1,
493 table_id=1)
494 route_dhcp_vrf1.add_vpp_config()
495
496 dmac = in6_getnsmac(inet_pton(socket.AF_INET6, dhcp_solicit_dst))
497 p_solicit_vrf0 = (Ether(dst=dmac, src=self.pg2.remote_mac) /
498 IPv6(src=dhcp_solicit_src_vrf0,
499 dst=dhcp_solicit_dst) /
500 UDP(sport=DHCP6_SERVER_PORT,
501 dport=DHCP6_CLIENT_PORT) /
502 DHCP6_Solicit())
503 pkts_solicit_vrf0 = [p_solicit_vrf0]
504 p_solicit_vrf1 = (Ether(dst=dmac, src=self.pg3.remote_mac) /
505 IPv6(src=dhcp_solicit_src_vrf1,
506 dst=dhcp_solicit_dst) /
507 UDP(sport=DHCP6_SERVER_PORT,
508 dport=DHCP6_CLIENT_PORT) /
509 DHCP6_Solicit())
510 pkts_solicit_vrf1 = [p_solicit_vrf1]
511
512 self.send_and_assert_no_replies(self.pg2, pkts_solicit_vrf0,
513 "DHCP with no configuration")
514 self.send_and_assert_no_replies(self.pg3, pkts_solicit_vrf1,
515 "DHCP with no configuration")
516
517 #
518 # DHCPv6 config in VRF 0.
519 # Packets still dropped because the client facing interface has no
520 # IPv6 config
521 #
522 self.vapi.dhcp_proxy_config(server_addr_vrf0,
523 src_addr_vrf0,
524 rx_table_id=0,
525 server_table_id=0,
526 insert_circuit_id=1,
527 is_ipv6=1)
528
529 self.send_and_assert_no_replies(self.pg2, pkts_solicit_vrf0,
530 "DHCP with no configuration")
531 self.send_and_assert_no_replies(self.pg3, pkts_solicit_vrf1,
532 "DHCP with no configuration")
533
534 #
535 # configure an IP address on the client facing interface
536 #
537 self.pg2.config_ip6()
538
539 #
540 # Now the DHCP requests are relayed to the server
541 #
542 self.pg2.add_stream(pkts_solicit_vrf0)
543 self.pg_enable_capture(self.pg_interfaces)
544 self.pg_start()
545
546 rx = self.pg0.get_capture(1)
547 rx = rx[0]
548 self.verify_dhcp6_solicit(rx, self.pg0,
549 dhcp_solicit_src_vrf0,
550 self.pg2.remote_mac)
551
552 #
553 # Exception cases for rejected relay responses
554 #
555
556 # 1 - not a relay reply
557 p_adv_vrf0 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
558 IPv6(dst=self.pg0.local_ip6, src=self.pg0.remote_ip6) /
559 UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_SERVER_PORT) /
560 DHCP6_Advertise())
561 pkts_adv_vrf0 = [p_adv_vrf0]
562 self.send_and_assert_no_replies(self.pg2, pkts_adv_vrf0,
563 "DHCP6 not a relay reply")
564
565 # 2 - no relay message option
566 p_adv_vrf0 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
567 IPv6(dst=self.pg0.local_ip6, src=self.pg0.remote_ip6) /
568 UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_SERVER_PORT) /
569 DHCP6_RelayReply() /
570 DHCP6_Advertise())
571 pkts_adv_vrf0 = [p_adv_vrf0]
572 self.send_and_assert_no_replies(self.pg2, pkts_adv_vrf0,
573 "DHCP not a relay message")
574
575 # 3 - no circuit ID
576 p_adv_vrf0 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
577 IPv6(dst=self.pg0.local_ip6, src=self.pg0.remote_ip6) /
578 UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_SERVER_PORT) /
579 DHCP6_RelayReply() /
580 DHCP6OptRelayMsg(optlen=0) /
581 DHCP6_Advertise())
582 pkts_adv_vrf0 = [p_adv_vrf0]
583 self.send_and_assert_no_replies(self.pg2, pkts_adv_vrf0,
584 "DHCP6 no circuit ID")
585 # 4 - wrong circuit ID
586 p_adv_vrf0 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
587 IPv6(dst=self.pg0.local_ip6, src=self.pg0.remote_ip6) /
588 UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_SERVER_PORT) /
589 DHCP6_RelayReply() /
590 DHCP6OptIfaceId(optlen=4, ifaceid='\x00\x00\x00\x05') /
591 DHCP6OptRelayMsg(optlen=0) /
592 DHCP6_Advertise())
593 pkts_adv_vrf0 = [p_adv_vrf0]
594 self.send_and_assert_no_replies(self.pg2, pkts_adv_vrf0,
595 "DHCP6 wrong circuit ID")
596
597 #
598 # Send the relay response (the advertisement)
599 # - no peer address
600 p_adv_vrf0 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
601 IPv6(dst=self.pg0.local_ip6, src=self.pg0.remote_ip6) /
602 UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_SERVER_PORT) /
603 DHCP6_RelayReply() /
604 DHCP6OptIfaceId(optlen=4, ifaceid='\x00\x00\x00\x03') /
605 DHCP6OptRelayMsg(optlen=0) /
606 DHCP6_Advertise(trid=1) /
607 DHCP6OptStatusCode(statuscode=0))
608 pkts_adv_vrf0 = [p_adv_vrf0]
609
610 self.pg0.add_stream(pkts_adv_vrf0)
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_dhcp6_advert(rx, self.pg2, "::")
617
618 #
619 # Send the relay response (the advertisement)
620 # - with peer address
621 p_adv_vrf0 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
622 IPv6(dst=self.pg0.local_ip6, src=self.pg0.remote_ip6) /
623 UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_SERVER_PORT) /
624 DHCP6_RelayReply(peeraddr=dhcp_solicit_src_vrf0) /
625 DHCP6OptIfaceId(optlen=4, ifaceid='\x00\x00\x00\x03') /
626 DHCP6OptRelayMsg(optlen=0) /
627 DHCP6_Advertise(trid=1) /
628 DHCP6OptStatusCode(statuscode=0))
629 pkts_adv_vrf0 = [p_adv_vrf0]
630
631 self.pg0.add_stream(pkts_adv_vrf0)
632 self.pg_enable_capture(self.pg_interfaces)
633 self.pg_start()
634
635 rx = self.pg2.get_capture(1)
636 rx = rx[0]
637 self.verify_dhcp6_advert(rx, self.pg2, dhcp_solicit_src_vrf0)
638
639 #
640 # Add all the config for VRF 1
641 #
642 self.vapi.dhcp_proxy_config(server_addr_vrf1,
643 src_addr_vrf1,
644 rx_table_id=1,
645 server_table_id=1,
646 insert_circuit_id=1,
647 is_ipv6=1)
648 self.pg3.config_ip6()
649
650 #
651 # VRF 1 solicit
652 #
653 self.pg3.add_stream(pkts_solicit_vrf1)
654 self.pg_enable_capture(self.pg_interfaces)
655 self.pg_start()
656
657 rx = self.pg1.get_capture(1)
658 rx = rx[0]
659 self.verify_dhcp6_solicit(rx, self.pg1,
660 dhcp_solicit_src_vrf1,
661 self.pg3.remote_mac)
662
663 #
664 # VRF 1 Advert
665 #
666 p_adv_vrf1 = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
667 IPv6(dst=self.pg1.local_ip6, src=self.pg1.remote_ip6) /
668 UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_SERVER_PORT) /
669 DHCP6_RelayReply(peeraddr=dhcp_solicit_src_vrf1) /
670 DHCP6OptIfaceId(optlen=4, ifaceid='\x00\x00\x00\x04') /
671 DHCP6OptRelayMsg(optlen=0) /
672 DHCP6_Advertise(trid=1) /
673 DHCP6OptStatusCode(statuscode=0))
674 pkts_adv_vrf1 = [p_adv_vrf1]
675
676 self.pg1.add_stream(pkts_adv_vrf1)
677 self.pg_enable_capture(self.pg_interfaces)
678 self.pg_start()
679
680 rx = self.pg3.get_capture(1)
681 rx = rx[0]
682 self.verify_dhcp6_advert(rx, self.pg3, dhcp_solicit_src_vrf1)
683
684 #
685 # Add VSS config
686 # table=1, fib=id=1, oui=4
687 self.vapi.dhcp_proxy_set_vss(1, 1, 4, is_ip6=1)
688
689 self.pg3.add_stream(pkts_solicit_vrf1)
690 self.pg_enable_capture(self.pg_interfaces)
691 self.pg_start()
692
693 rx = self.pg1.get_capture(1)
694 rx = rx[0]
695 self.verify_dhcp6_solicit(rx, self.pg1,
696 dhcp_solicit_src_vrf1,
697 self.pg3.remote_mac,
698 fib_id=1,
699 oui=4)
700
701 #
702 # Remove the VSS config
703 # relayed DHCP has default vlaues in the option.
704 #
705 self.vapi.dhcp_proxy_set_vss(1, 1, 4, is_ip6=1, is_add=0)
706
707 self.pg3.add_stream(pkts_solicit_vrf1)
708 self.pg_enable_capture(self.pg_interfaces)
709 self.pg_start()
710
711 rx = self.pg1.get_capture(1)
712 rx = rx[0]
713 self.verify_dhcp6_solicit(rx, self.pg1,
714 dhcp_solicit_src_vrf1,
715 self.pg3.remote_mac)
716
717 #
718 # Cleanup
719 #
720 self.vapi.dhcp_proxy_config(server_addr_vrf1,
721 src_addr_vrf1,
722 rx_table_id=1,
723 server_table_id=1,
724 insert_circuit_id=1,
725 is_ipv6=1,
726 is_add=0)
727 self.vapi.dhcp_proxy_config(server_addr_vrf1,
728 src_addr_vrf1,
729 rx_table_id=0,
730 server_table_id=0,
731 insert_circuit_id=1,
732 is_ipv6=1,
733 is_add=0)
734
735 route_dhcp_vrf0.remove_vpp_config()
736 route_dhcp_vrf1.remove_vpp_config()
737
738if __name__ == '__main__':
739 unittest.main(testRunner=VppTestRunner)