blob: 64c4654b4185a2354f90feead35edd120dbeed95 [file] [log] [blame]
Renato Botelho do Coutoead1e532019-10-31 13:31:07 -05001#!/usr/bin/env python3
Neale Rannsfca0c242017-01-13 07:57:46 -08002
3import unittest
4import socket
Ole Troan12966a72019-10-18 14:33:54 +02005import six
Neale Rannsfca0c242017-01-13 07:57:46 -08006
Dave Wallace8800f732023-08-31 00:47:44 -04007from framework import VppTestCase
8from asfframework import VppTestRunner, tag_run_solo
Neale Ranns3466c302017-02-16 07:45:03 -08009from vpp_neighbor import VppNeighbor
Neale Ranns15002542017-09-10 04:39:11 -070010from vpp_ip_route import find_route, VppIpTable
Neale Ranns2a3ea492017-04-19 05:24:40 -070011from util import mk_ll_addr
Paul Vinciguerraa7427ec2019-03-10 10:04:23 -070012import scapy.compat
Dave Wallace8800f732023-08-31 00:47:44 -040013from scapy.layers.l2 import Ether, ARP, Dot1Q
14from scapy.layers.inet import IP, UDP
Neale Ranns2bc94022018-02-25 12:27:18 -080015from scapy.layers.inet6 import IPv6, in6_getnsmac
Neale Rannsfca0c242017-01-13 07:57:46 -080016from scapy.layers.dhcp import DHCP, BOOTP, DHCPTypes
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020017from scapy.layers.dhcp6 import (
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020018 DHCP6_Solicit,
19 DHCP6_RelayForward,
20 DHCP6_RelayReply,
21 DHCP6_Advertise,
22 DHCP6OptRelayMsg,
23 DHCP6OptIfaceId,
24 DHCP6OptStatusCode,
25 DHCP6OptVSS,
26 DHCP6OptClientLinkLayerAddr,
27 DHCP6_Request,
28)
Dave Wallace8800f732023-08-31 00:47:44 -040029from socket import AF_INET, AF_INET6, inet_pton
Neale Rannsfca0c242017-01-13 07:57:46 -080030from scapy.utils6 import in6_ptop
Neale Ranns038e1df2019-07-19 14:01:02 +000031from vpp_papi import mac_pton, VppEnum
32from vpp_sub_interface import VppDot1QSubint
33from vpp_qos import VppQosEgressMap, VppQosMark
Jakub Grajciar103ba6b2019-10-01 11:30:56 +020034from vpp_dhcp import VppDHCPClient, VppDHCPProxy
Dmitry Valter34fa0ce2024-03-11 10:38:46 +000035from config import config
Neale Ranns038e1df2019-07-19 14:01:02 +000036
Neale Rannsfca0c242017-01-13 07:57:46 -080037
38DHCP4_CLIENT_PORT = 68
39DHCP4_SERVER_PORT = 67
40DHCP6_CLIENT_PORT = 547
41DHCP6_SERVER_PORT = 546
42
43
Andrew Yourtchenko06f32812021-01-14 10:19:08 +000044@tag_run_solo
Dmitry Valter34fa0ce2024-03-11 10:38:46 +000045@unittest.skipIf("dhcp" in config.excluded_plugins, "Exclude DHCP plugin tests")
Neale Rannsfca0c242017-01-13 07:57:46 -080046class TestDHCP(VppTestCase):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020047 """DHCP Test Case"""
Neale Rannsfca0c242017-01-13 07:57:46 -080048
Paul Vinciguerra7f9b7f92019-03-12 19:23:27 -070049 @classmethod
50 def setUpClass(cls):
51 super(TestDHCP, cls).setUpClass()
52
53 @classmethod
54 def tearDownClass(cls):
55 super(TestDHCP, cls).tearDownClass()
56
Neale Rannsfca0c242017-01-13 07:57:46 -080057 def setUp(self):
58 super(TestDHCP, self).setUp()
59
John Lo70bfcaf2017-11-14 13:19:26 -050060 # create 6 pg interfaces for pg0 to pg5
61 self.create_pg_interfaces(range(6))
Neale Ranns15002542017-09-10 04:39:11 -070062 self.tables = []
Neale Rannsfca0c242017-01-13 07:57:46 -080063
John Lo70bfcaf2017-11-14 13:19:26 -050064 # pg0 to 2 are IP configured in VRF 0, 1 and 2.
65 # pg3 to 5 are non IP-configured in VRF 0, 1 and 2.
Neale Rannsfca0c242017-01-13 07:57:46 -080066 table_id = 0
Neale Ranns15002542017-09-10 04:39:11 -070067 for table_id in range(1, 4):
68 tbl4 = VppIpTable(self, table_id)
69 tbl4.add_vpp_config()
70 self.tables.append(tbl4)
71 tbl6 = VppIpTable(self, table_id, is_ip6=1)
72 tbl6.add_vpp_config()
73 self.tables.append(tbl6)
74
75 table_id = 0
John Lo70bfcaf2017-11-14 13:19:26 -050076 for i in self.pg_interfaces[:3]:
Neale Rannsfca0c242017-01-13 07:57:46 -080077 i.admin_up()
78 i.set_table_ip4(table_id)
79 i.set_table_ip6(table_id)
80 i.config_ip4()
81 i.resolve_arp()
82 i.config_ip6()
83 i.resolve_ndp()
84 table_id += 1
85
86 table_id = 0
John Lo70bfcaf2017-11-14 13:19:26 -050087 for i in self.pg_interfaces[3:]:
Neale Rannsfca0c242017-01-13 07:57:46 -080088 i.admin_up()
89 i.set_table_ip4(table_id)
90 i.set_table_ip6(table_id)
91 table_id += 1
92
Neale Ranns4008ac92017-02-13 23:20:04 -080093 def tearDown(self):
John Lo70bfcaf2017-11-14 13:19:26 -050094 for i in self.pg_interfaces[:3]:
Neale Ranns4008ac92017-02-13 23:20:04 -080095 i.unconfig_ip4()
96 i.unconfig_ip6()
Neale Ranns15002542017-09-10 04:39:11 -070097
98 for i in self.pg_interfaces:
99 i.set_table_ip4(0)
100 i.set_table_ip6(0)
Neale Ranns4008ac92017-02-13 23:20:04 -0800101 i.admin_down()
Neale Ranns15002542017-09-10 04:39:11 -0700102 super(TestDHCP, self).tearDown()
Neale Ranns4008ac92017-02-13 23:20:04 -0800103
Neale Rannsa2fbf6b2017-07-18 08:23:32 -0700104 def verify_dhcp_has_option(self, pkt, option, value):
105 dhcp = pkt[DHCP]
106 found = False
107
108 for i in dhcp.options:
Jakub Grajciar103ba6b2019-10-01 11:30:56 +0200109 if isinstance(i, tuple):
Neale Rannsa2fbf6b2017-07-18 08:23:32 -0700110 if i[0] == option:
111 self.assertEqual(i[1], value)
112 found = True
113
114 self.assertTrue(found)
115
John Lo70bfcaf2017-11-14 13:19:26 -0500116 def validate_relay_options(self, pkt, intf, ip_addr, vpn_id, fib_id, oui):
Neale Rannsfca0c242017-01-13 07:57:46 -0800117 dhcp = pkt[DHCP]
118 found = 0
119 data = []
John Lo70bfcaf2017-11-14 13:19:26 -0500120 id_len = len(vpn_id)
Neale Rannsfca0c242017-01-13 07:57:46 -0800121
122 for i in dhcp.options:
Jakub Grajciar103ba6b2019-10-01 11:30:56 +0200123 if isinstance(i, tuple):
Neale Rannsfca0c242017-01-13 07:57:46 -0800124 if i[0] == "relay_agent_Information":
125 #
126 # There are two sb-options present - each of length 6.
127 #
128 data = i[1]
Neale Ranns20a175a2017-02-14 07:28:41 -0800129 if oui != 0:
130 self.assertEqual(len(data), 24)
John Lo70bfcaf2017-11-14 13:19:26 -0500131 elif len(vpn_id) > 0:
Jakub Grajciar103ba6b2019-10-01 11:30:56 +0200132 self.assertEqual(len(data), len(vpn_id) + 17)
Neale Ranns20a175a2017-02-14 07:28:41 -0800133 else:
134 self.assertEqual(len(data), 12)
Neale Rannsfca0c242017-01-13 07:57:46 -0800135
136 #
137 # First sub-option is ID 1, len 4, then encoded
138 # sw_if_index. This test uses low valued indicies
139 # so [2:4] are 0.
140 # The ID space is VPP internal - so no matching value
141 # scapy
142 #
Ole Troan12966a72019-10-18 14:33:54 +0200143 self.assertEqual(six.byte2int(data[0:1]), 1)
144 self.assertEqual(six.byte2int(data[1:2]), 4)
145 self.assertEqual(six.byte2int(data[2:3]), 0)
146 self.assertEqual(six.byte2int(data[3:4]), 0)
147 self.assertEqual(six.byte2int(data[4:5]), 0)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200148 self.assertEqual(six.byte2int(data[5:6]), intf._sw_if_index)
Neale Rannsfca0c242017-01-13 07:57:46 -0800149
150 #
151 # next sub-option is the IP address of the client side
152 # interface.
153 # sub-option ID=5, length (of a v4 address)=4
154 #
155 claddr = socket.inet_pton(AF_INET, ip_addr)
156
Ole Troan12966a72019-10-18 14:33:54 +0200157 self.assertEqual(six.byte2int(data[6:7]), 5)
158 self.assertEqual(six.byte2int(data[7:8]), 4)
Neale Rannsfca0c242017-01-13 07:57:46 -0800159 self.assertEqual(data[8], claddr[0])
160 self.assertEqual(data[9], claddr[1])
161 self.assertEqual(data[10], claddr[2])
162 self.assertEqual(data[11], claddr[3])
163
Neale Ranns20a175a2017-02-14 07:28:41 -0800164 if oui != 0:
John Lo70bfcaf2017-11-14 13:19:26 -0500165 # sub-option 151 encodes vss_type 1,
166 # the 3 byte oui and the 4 byte fib_id
167 self.assertEqual(id_len, 0)
Ole Troan12966a72019-10-18 14:33:54 +0200168 self.assertEqual(six.byte2int(data[12:13]), 151)
169 self.assertEqual(six.byte2int(data[13:14]), 8)
170 self.assertEqual(six.byte2int(data[14:15]), 1)
171 self.assertEqual(six.byte2int(data[15:16]), 0)
172 self.assertEqual(six.byte2int(data[16:17]), 0)
173 self.assertEqual(six.byte2int(data[17:18]), oui)
174 self.assertEqual(six.byte2int(data[18:19]), 0)
175 self.assertEqual(six.byte2int(data[19:20]), 0)
176 self.assertEqual(six.byte2int(data[20:21]), 0)
177 self.assertEqual(six.byte2int(data[21:22]), fib_id)
Neale Ranns20a175a2017-02-14 07:28:41 -0800178
179 # VSS control sub-option
Ole Troan12966a72019-10-18 14:33:54 +0200180 self.assertEqual(six.byte2int(data[22:23]), 152)
181 self.assertEqual(six.byte2int(data[23:24]), 0)
Neale Ranns20a175a2017-02-14 07:28:41 -0800182
John Lo70bfcaf2017-11-14 13:19:26 -0500183 if id_len > 0:
184 # sub-option 151 encode vss_type of 0
185 # followerd by vpn_id in ascii
186 self.assertEqual(oui, 0)
Ole Troan12966a72019-10-18 14:33:54 +0200187 self.assertEqual(six.byte2int(data[12:13]), 151)
188 self.assertEqual(six.byte2int(data[13:14]), id_len + 1)
189 self.assertEqual(six.byte2int(data[14:15]), 0)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200190 self.assertEqual(data[15 : 15 + id_len].decode("ascii"), vpn_id)
John Lo70bfcaf2017-11-14 13:19:26 -0500191
192 # VSS control sub-option
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200193 self.assertEqual(
194 six.byte2int(data[15 + len(vpn_id) : 16 + len(vpn_id)]), 152
195 )
196 self.assertEqual(
197 six.byte2int(data[16 + len(vpn_id) : 17 + len(vpn_id)]), 0
198 )
John Lo70bfcaf2017-11-14 13:19:26 -0500199
Neale Rannsfca0c242017-01-13 07:57:46 -0800200 found = 1
201 self.assertTrue(found)
202
203 return data
204
Neale Rannsa2fbf6b2017-07-18 08:23:32 -0700205 def verify_dhcp_msg_type(self, pkt, name):
206 dhcp = pkt[DHCP]
207 found = False
208 for o in dhcp.options:
Jakub Grajciar103ba6b2019-10-01 11:30:56 +0200209 if isinstance(o, tuple):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200210 if o[0] == "message-type" and DHCPTypes[o[1]] == name:
Neale Rannsa2fbf6b2017-07-18 08:23:32 -0700211 found = True
212 self.assertTrue(found)
213
John Lo70bfcaf2017-11-14 13:19:26 -0500214 def verify_dhcp_offer(self, pkt, intf, vpn_id="", fib_id=0, oui=0):
Neale Rannsfca0c242017-01-13 07:57:46 -0800215 ether = pkt[Ether]
216 self.assertEqual(ether.dst, "ff:ff:ff:ff:ff:ff")
217 self.assertEqual(ether.src, intf.local_mac)
218
219 ip = pkt[IP]
220 self.assertEqual(ip.dst, "255.255.255.255")
221 self.assertEqual(ip.src, intf.local_ip4)
222
223 udp = pkt[UDP]
224 self.assertEqual(udp.dport, DHCP4_CLIENT_PORT)
225 self.assertEqual(udp.sport, DHCP4_SERVER_PORT)
226
Neale Rannsa2fbf6b2017-07-18 08:23:32 -0700227 self.verify_dhcp_msg_type(pkt, "offer")
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200228 data = self.validate_relay_options(
229 pkt, intf, intf.local_ip4, vpn_id, fib_id, oui
230 )
Neale Rannsfca0c242017-01-13 07:57:46 -0800231
Neale Ranns038e1df2019-07-19 14:01:02 +0000232 def verify_orig_dhcp_pkt(self, pkt, intf, dscp, l2_bc=True):
Neale Rannsa2fbf6b2017-07-18 08:23:32 -0700233 ether = pkt[Ether]
Neale Ranns99536f42019-07-25 06:11:58 -0700234 if l2_bc:
235 self.assertEqual(ether.dst, "ff:ff:ff:ff:ff:ff")
236 else:
237 self.assertEqual(ether.dst, intf.remote_mac)
Neale Rannsa2fbf6b2017-07-18 08:23:32 -0700238 self.assertEqual(ether.src, intf.local_mac)
239
240 ip = pkt[IP]
Neale Ranns99536f42019-07-25 06:11:58 -0700241
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200242 if l2_bc:
Neale Ranns99536f42019-07-25 06:11:58 -0700243 self.assertEqual(ip.dst, "255.255.255.255")
244 self.assertEqual(ip.src, "0.0.0.0")
245 else:
246 self.assertEqual(ip.dst, intf.remote_ip4)
247 self.assertEqual(ip.src, intf.local_ip4)
Neale Ranns038e1df2019-07-19 14:01:02 +0000248 self.assertEqual(ip.tos, dscp)
Neale Rannsa2fbf6b2017-07-18 08:23:32 -0700249
250 udp = pkt[UDP]
251 self.assertEqual(udp.dport, DHCP4_SERVER_PORT)
252 self.assertEqual(udp.sport, DHCP4_CLIENT_PORT)
253
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200254 def verify_orig_dhcp_discover(
255 self, pkt, intf, hostname, client_id=None, broadcast=True, dscp=0
256 ):
Neale Ranns038e1df2019-07-19 14:01:02 +0000257 self.verify_orig_dhcp_pkt(pkt, intf, dscp)
Neale Rannsa2fbf6b2017-07-18 08:23:32 -0700258
259 self.verify_dhcp_msg_type(pkt, "discover")
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200260 self.verify_dhcp_has_option(pkt, "hostname", hostname.encode("ascii"))
Neale Ranns51822bf2017-07-18 09:26:53 -0700261 if client_id:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200262 client_id = "\x00" + client_id
263 self.verify_dhcp_has_option(pkt, "client_id", client_id.encode("ascii"))
Neale Ranns808c5b22017-08-02 05:15:07 -0700264 bootp = pkt[BOOTP]
265 self.assertEqual(bootp.ciaddr, "0.0.0.0")
266 self.assertEqual(bootp.giaddr, "0.0.0.0")
Neale Ranns54c6dc42018-01-17 10:29:10 -0800267 if broadcast:
268 self.assertEqual(bootp.flags, 0x8000)
269 else:
270 self.assertEqual(bootp.flags, 0x0000)
Neale Rannsa2fbf6b2017-07-18 08:23:32 -0700271
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200272 def verify_orig_dhcp_request(
273 self, pkt, intf, hostname, ip, broadcast=True, l2_bc=True, dscp=0
274 ):
Neale Ranns038e1df2019-07-19 14:01:02 +0000275 self.verify_orig_dhcp_pkt(pkt, intf, dscp, l2_bc=l2_bc)
Neale Rannsa2fbf6b2017-07-18 08:23:32 -0700276
277 self.verify_dhcp_msg_type(pkt, "request")
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200278 self.verify_dhcp_has_option(pkt, "hostname", hostname.encode("ascii"))
Neale Rannsa2fbf6b2017-07-18 08:23:32 -0700279 self.verify_dhcp_has_option(pkt, "requested_addr", ip)
Neale Ranns808c5b22017-08-02 05:15:07 -0700280 bootp = pkt[BOOTP]
Neale Ranns99536f42019-07-25 06:11:58 -0700281
282 if l2_bc:
283 self.assertEqual(bootp.ciaddr, "0.0.0.0")
284 else:
285 self.assertEqual(bootp.ciaddr, intf.local_ip4)
Neale Ranns808c5b22017-08-02 05:15:07 -0700286 self.assertEqual(bootp.giaddr, "0.0.0.0")
Neale Ranns99536f42019-07-25 06:11:58 -0700287
Neale Ranns54c6dc42018-01-17 10:29:10 -0800288 if broadcast:
289 self.assertEqual(bootp.flags, 0x8000)
290 else:
291 self.assertEqual(bootp.flags, 0x0000)
Neale Rannsa2fbf6b2017-07-18 08:23:32 -0700292
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200293 def verify_relayed_dhcp_discover(
294 self,
295 pkt,
296 intf,
297 src_intf=None,
298 fib_id=0,
299 oui=0,
300 vpn_id="",
301 dst_mac=None,
302 dst_ip=None,
303 ):
Neale Ranns3466c302017-02-16 07:45:03 -0800304 if not dst_mac:
305 dst_mac = intf.remote_mac
306 if not dst_ip:
307 dst_ip = intf.remote_ip4
308
Neale Rannsfca0c242017-01-13 07:57:46 -0800309 ether = pkt[Ether]
Neale Ranns3466c302017-02-16 07:45:03 -0800310 self.assertEqual(ether.dst, dst_mac)
Neale Rannsfca0c242017-01-13 07:57:46 -0800311 self.assertEqual(ether.src, intf.local_mac)
312
313 ip = pkt[IP]
Neale Ranns3466c302017-02-16 07:45:03 -0800314 self.assertEqual(ip.dst, dst_ip)
Neale Rannsfca0c242017-01-13 07:57:46 -0800315 self.assertEqual(ip.src, intf.local_ip4)
316
317 udp = pkt[UDP]
318 self.assertEqual(udp.dport, DHCP4_SERVER_PORT)
319 self.assertEqual(udp.sport, DHCP4_CLIENT_PORT)
320
321 dhcp = pkt[DHCP]
322
323 is_discover = False
324 for o in dhcp.options:
Jakub Grajciar103ba6b2019-10-01 11:30:56 +0200325 if isinstance(o, tuple):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200326 if o[0] == "message-type" and DHCPTypes[o[1]] == "discover":
Neale Rannsfca0c242017-01-13 07:57:46 -0800327 is_discover = True
328 self.assertTrue(is_discover)
329
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200330 data = self.validate_relay_options(
331 pkt, src_intf, src_intf.local_ip4, vpn_id, fib_id, oui
332 )
Neale Ranns20a175a2017-02-14 07:28:41 -0800333 return data
Neale Rannsfca0c242017-01-13 07:57:46 -0800334
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200335 def verify_dhcp6_solicit(
336 self,
337 pkt,
338 intf,
339 peer_ip,
340 peer_mac,
341 vpn_id="",
342 fib_id=0,
343 oui=0,
344 dst_mac=None,
345 dst_ip=None,
346 ):
Neale Ranns3466c302017-02-16 07:45:03 -0800347 if not dst_mac:
348 dst_mac = intf.remote_mac
349 if not dst_ip:
350 dst_ip = in6_ptop(intf.remote_ip6)
351
Neale Rannsfca0c242017-01-13 07:57:46 -0800352 ether = pkt[Ether]
Neale Ranns3466c302017-02-16 07:45:03 -0800353 self.assertEqual(ether.dst, dst_mac)
Neale Rannsfca0c242017-01-13 07:57:46 -0800354 self.assertEqual(ether.src, intf.local_mac)
355
356 ip = pkt[IPv6]
Neale Ranns3466c302017-02-16 07:45:03 -0800357 self.assertEqual(in6_ptop(ip.dst), dst_ip)
Neale Rannsfca0c242017-01-13 07:57:46 -0800358 self.assertEqual(in6_ptop(ip.src), in6_ptop(intf.local_ip6))
359
360 udp = pkt[UDP]
361 self.assertEqual(udp.dport, DHCP6_CLIENT_PORT)
362 self.assertEqual(udp.sport, DHCP6_SERVER_PORT)
363
364 relay = pkt[DHCP6_RelayForward]
365 self.assertEqual(in6_ptop(relay.peeraddr), in6_ptop(peer_ip))
366 oid = pkt[DHCP6OptIfaceId]
367 cll = pkt[DHCP6OptClientLinkLayerAddr]
368 self.assertEqual(cll.optlen, 8)
369 self.assertEqual(cll.lltype, 1)
370 self.assertEqual(cll.clladdr, peer_mac)
371
John Lo70bfcaf2017-11-14 13:19:26 -0500372 id_len = len(vpn_id)
373
Neale Ranns20a175a2017-02-14 07:28:41 -0800374 if fib_id != 0:
John Lo70bfcaf2017-11-14 13:19:26 -0500375 self.assertEqual(id_len, 0)
Neale Ranns20a175a2017-02-14 07:28:41 -0800376 vss = pkt[DHCP6OptVSS]
377 self.assertEqual(vss.optlen, 8)
378 self.assertEqual(vss.type, 1)
379 # the OUI and FIB-id are really 3 and 4 bytes resp.
380 # but the tested range is small
Ole Troan12966a72019-10-18 14:33:54 +0200381 self.assertEqual(six.byte2int(vss.data[0:1]), 0)
382 self.assertEqual(six.byte2int(vss.data[1:2]), 0)
383 self.assertEqual(six.byte2int(vss.data[2:3]), oui)
384 self.assertEqual(six.byte2int(vss.data[3:4]), 0)
385 self.assertEqual(six.byte2int(vss.data[4:5]), 0)
386 self.assertEqual(six.byte2int(vss.data[5:6]), 0)
387 self.assertEqual(six.byte2int(vss.data[6:7]), fib_id)
Neale Rannsfca0c242017-01-13 07:57:46 -0800388
John Lo70bfcaf2017-11-14 13:19:26 -0500389 if id_len > 0:
390 self.assertEqual(oui, 0)
391 vss = pkt[DHCP6OptVSS]
Jakub Grajciar103ba6b2019-10-01 11:30:56 +0200392 self.assertEqual(vss.optlen, id_len + 1)
John Lo70bfcaf2017-11-14 13:19:26 -0500393 self.assertEqual(vss.type, 0)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200394 self.assertEqual(vss.data[0:id_len].decode("ascii"), vpn_id)
John Lo70bfcaf2017-11-14 13:19:26 -0500395
Neale Rannsfca0c242017-01-13 07:57:46 -0800396 # the relay message should be an encoded Solicit
397 msg = pkt[DHCP6OptRelayMsg]
398 sol = DHCP6_Solicit()
Ole Troan12966a72019-10-18 14:33:54 +0200399 self.assertEqual(msg.optlen, len(sol))
400 self.assertEqual(sol, msg[1])
Neale Rannsfca0c242017-01-13 07:57:46 -0800401
402 def verify_dhcp6_advert(self, pkt, intf, peer):
403 ether = pkt[Ether]
404 self.assertEqual(ether.dst, "ff:ff:ff:ff:ff:ff")
405 self.assertEqual(ether.src, intf.local_mac)
406
407 ip = pkt[IPv6]
408 self.assertEqual(in6_ptop(ip.dst), in6_ptop(peer))
409 self.assertEqual(in6_ptop(ip.src), in6_ptop(intf.local_ip6))
410
411 udp = pkt[UDP]
412 self.assertEqual(udp.dport, DHCP6_SERVER_PORT)
413 self.assertEqual(udp.sport, DHCP6_CLIENT_PORT)
414
415 # not sure why this is not decoding
416 # adv = pkt[DHCP6_Advertise]
417
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200418 def wait_for_no_route(self, address, length, n_tries=50, s_time=1):
419 while n_tries:
Neale Rannsf6e9b012019-01-25 06:37:15 -0800420 if not find_route(self, address, length):
421 return True
422 n_tries = n_tries - 1
423 self.sleep(s_time)
424
425 return False
426
Neale Rannsfca0c242017-01-13 07:57:46 -0800427 def test_dhcp_proxy(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200428 """DHCPv4 Proxy"""
Neale Rannsfca0c242017-01-13 07:57:46 -0800429
430 #
431 # Verify no response to DHCP request without DHCP config
432 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200433 p_disc_vrf0 = (
434 Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg3.remote_mac)
435 / IP(src="0.0.0.0", dst="255.255.255.255")
436 / UDP(sport=DHCP4_CLIENT_PORT, dport=DHCP4_SERVER_PORT)
437 / BOOTP(op=1)
438 / DHCP(options=[("message-type", "discover"), ("end")])
439 )
Neale Rannsfca0c242017-01-13 07:57:46 -0800440 pkts_disc_vrf0 = [p_disc_vrf0]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200441 p_disc_vrf1 = (
442 Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg4.remote_mac)
443 / IP(src="0.0.0.0", dst="255.255.255.255")
444 / UDP(sport=DHCP4_CLIENT_PORT, dport=DHCP4_SERVER_PORT)
445 / BOOTP(op=1)
446 / DHCP(options=[("message-type", "discover"), ("end")])
447 )
John Lo70bfcaf2017-11-14 13:19:26 -0500448 pkts_disc_vrf1 = [p_disc_vrf1]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200449 p_disc_vrf2 = (
450 Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg5.remote_mac)
451 / IP(src="0.0.0.0", dst="255.255.255.255")
452 / UDP(sport=DHCP4_CLIENT_PORT, dport=DHCP4_SERVER_PORT)
453 / BOOTP(op=1)
454 / DHCP(options=[("message-type", "discover"), ("end")])
455 )
John Lo70bfcaf2017-11-14 13:19:26 -0500456 pkts_disc_vrf2 = [p_disc_vrf2]
Neale Rannsfca0c242017-01-13 07:57:46 -0800457
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200458 self.send_and_assert_no_replies(
459 self.pg3, pkts_disc_vrf0, "DHCP with no configuration"
460 )
461 self.send_and_assert_no_replies(
462 self.pg4, pkts_disc_vrf1, "DHCP with no configuration"
463 )
464 self.send_and_assert_no_replies(
465 self.pg5, pkts_disc_vrf2, "DHCP with no configuration"
466 )
Neale Rannsfca0c242017-01-13 07:57:46 -0800467
468 #
469 # Enable DHCP proxy in VRF 0
470 #
Jakub Grajciar103ba6b2019-10-01 11:30:56 +0200471 server_addr = self.pg0.remote_ip4
472 src_addr = self.pg0.local_ip4
Neale Rannsfca0c242017-01-13 07:57:46 -0800473
Jakub Grajciar103ba6b2019-10-01 11:30:56 +0200474 Proxy = VppDHCPProxy(self, server_addr, src_addr, rx_vrf_id=0)
475 Proxy.add_vpp_config()
Neale Rannsfca0c242017-01-13 07:57:46 -0800476
477 #
Neale Ranns20a175a2017-02-14 07:28:41 -0800478 # Discover packets from the client are dropped because there is no
479 # IP address configured on the client facing interface
Neale Rannsfca0c242017-01-13 07:57:46 -0800480 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200481 self.send_and_assert_no_replies(
482 self.pg3, pkts_disc_vrf0, "Discover DHCP no relay address"
483 )
Neale Rannsfca0c242017-01-13 07:57:46 -0800484
485 #
486 # Inject a response from the server
Neale Ranns20a175a2017-02-14 07:28:41 -0800487 # dropped, because there is no IP addrees on the
Neale Ranns2dd68522017-02-16 03:38:59 -0800488 # client interfce to fill in the option.
Neale Rannsfca0c242017-01-13 07:57:46 -0800489 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200490 p = (
491 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
492 / IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4)
493 / UDP(sport=DHCP4_SERVER_PORT, dport=DHCP4_SERVER_PORT)
494 / BOOTP(op=1)
495 / DHCP(options=[("message-type", "offer"), ("end")])
496 )
Neale Rannsfca0c242017-01-13 07:57:46 -0800497 pkts = [p]
498
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200499 self.send_and_assert_no_replies(self.pg3, pkts, "Offer DHCP no relay address")
Neale Rannsfca0c242017-01-13 07:57:46 -0800500
501 #
502 # configure an IP address on the client facing interface
503 #
John Lo70bfcaf2017-11-14 13:19:26 -0500504 self.pg3.config_ip4()
Neale Rannsfca0c242017-01-13 07:57:46 -0800505
506 #
507 # Try again with a discover packet
508 # Rx'd packet should be to the server address and from the configured
509 # source address
510 # UDP source ports are unchanged
511 # we've no option 82 config so that should be absent
512 #
John Lo70bfcaf2017-11-14 13:19:26 -0500513 self.pg3.add_stream(pkts_disc_vrf0)
Neale Rannsfca0c242017-01-13 07:57:46 -0800514 self.pg_enable_capture(self.pg_interfaces)
515 self.pg_start()
516
517 rx = self.pg0.get_capture(1)
518 rx = rx[0]
519
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200520 option_82 = self.verify_relayed_dhcp_discover(rx, self.pg0, src_intf=self.pg3)
Neale Rannsfca0c242017-01-13 07:57:46 -0800521
522 #
523 # Create an DHCP offer reply from the server with a correctly formatted
524 # option 82. i.e. send back what we just captured
525 # The offer, sent mcast to the client, still has option 82.
526 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200527 p = (
528 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
529 / IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4)
530 / UDP(sport=DHCP4_SERVER_PORT, dport=DHCP4_SERVER_PORT)
531 / BOOTP(op=1)
532 / DHCP(
533 options=[
534 ("message-type", "offer"),
535 ("relay_agent_Information", option_82),
536 ("end"),
537 ]
538 )
539 )
Neale Rannsfca0c242017-01-13 07:57:46 -0800540 pkts = [p]
541
542 self.pg0.add_stream(pkts)
543 self.pg_enable_capture(self.pg_interfaces)
544 self.pg_start()
545
John Lo70bfcaf2017-11-14 13:19:26 -0500546 rx = self.pg3.get_capture(1)
Neale Rannsfca0c242017-01-13 07:57:46 -0800547 rx = rx[0]
548
John Lo70bfcaf2017-11-14 13:19:26 -0500549 self.verify_dhcp_offer(rx, self.pg3)
Neale Rannsfca0c242017-01-13 07:57:46 -0800550
551 #
552 # Bogus Option 82:
553 #
554 # 1. not our IP address = not checked by VPP? so offer is replayed
555 # to client
Paul Vinciguerraa7427ec2019-03-10 10:04:23 -0700556 bad_ip = option_82[0:8] + scapy.compat.chb(33) + option_82[9:]
Neale Rannsfca0c242017-01-13 07:57:46 -0800557
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200558 p = (
559 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
560 / IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4)
561 / UDP(sport=DHCP4_SERVER_PORT, dport=DHCP4_SERVER_PORT)
562 / BOOTP(op=1)
563 / DHCP(
564 options=[
565 ("message-type", "offer"),
566 ("relay_agent_Information", bad_ip),
567 ("end"),
568 ]
569 )
570 )
Neale Rannsfca0c242017-01-13 07:57:46 -0800571 pkts = [p]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200572 self.send_and_assert_no_replies(
573 self.pg0, pkts, "DHCP offer option 82 bad address"
574 )
Neale Rannsfca0c242017-01-13 07:57:46 -0800575
576 # 2. Not a sw_if_index VPP knows
Paul Vinciguerraa7427ec2019-03-10 10:04:23 -0700577 bad_if_index = option_82[0:2] + scapy.compat.chb(33) + option_82[3:]
Neale Rannsfca0c242017-01-13 07:57:46 -0800578
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200579 p = (
580 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
581 / IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4)
582 / UDP(sport=DHCP4_SERVER_PORT, dport=DHCP4_SERVER_PORT)
583 / BOOTP(op=1)
584 / DHCP(
585 options=[
586 ("message-type", "offer"),
587 ("relay_agent_Information", bad_if_index),
588 ("end"),
589 ]
590 )
591 )
Neale Rannsfca0c242017-01-13 07:57:46 -0800592 pkts = [p]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200593 self.send_and_assert_no_replies(
594 self.pg0, pkts, "DHCP offer option 82 bad if index"
595 )
Neale Rannsfca0c242017-01-13 07:57:46 -0800596
597 #
598 # Send a DHCP request in VRF 1. should be dropped.
599 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200600 self.send_and_assert_no_replies(
601 self.pg4, pkts_disc_vrf1, "DHCP with no configuration VRF 1"
602 )
Neale Rannsfca0c242017-01-13 07:57:46 -0800603
604 #
605 # Delete the DHCP config in VRF 0
606 # Should now drop requests.
607 #
Jakub Grajciar103ba6b2019-10-01 11:30:56 +0200608 Proxy.remove_vpp_config()
Neale Rannsfca0c242017-01-13 07:57:46 -0800609
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200610 self.send_and_assert_no_replies(
611 self.pg3, pkts_disc_vrf0, "DHCP config removed VRF 0"
612 )
613 self.send_and_assert_no_replies(
614 self.pg4, pkts_disc_vrf1, "DHCP config removed VRF 1"
615 )
Neale Rannsfca0c242017-01-13 07:57:46 -0800616
617 #
John Lo70bfcaf2017-11-14 13:19:26 -0500618 # Add DHCP config for VRF 1 & 2
Neale Rannsfca0c242017-01-13 07:57:46 -0800619 #
Jakub Grajciar103ba6b2019-10-01 11:30:56 +0200620 server_addr1 = self.pg1.remote_ip4
621 src_addr1 = self.pg1.local_ip4
622 Proxy1 = VppDHCPProxy(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200623 self, server_addr1, src_addr1, rx_vrf_id=1, server_vrf_id=1
624 )
Jakub Grajciar103ba6b2019-10-01 11:30:56 +0200625 Proxy1.add_vpp_config()
626
627 server_addr2 = self.pg2.remote_ip4
628 src_addr2 = self.pg2.local_ip4
629 Proxy2 = VppDHCPProxy(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200630 self, server_addr2, src_addr2, rx_vrf_id=2, server_vrf_id=2
631 )
Jakub Grajciar103ba6b2019-10-01 11:30:56 +0200632 Proxy2.add_vpp_config()
Neale Rannsfca0c242017-01-13 07:57:46 -0800633
634 #
John Lo70bfcaf2017-11-14 13:19:26 -0500635 # Confim DHCP requests ok in VRF 1 & 2.
Neale Rannsfca0c242017-01-13 07:57:46 -0800636 # - dropped on IP config on client interface
637 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200638 self.send_and_assert_no_replies(
639 self.pg4, pkts_disc_vrf1, "DHCP config removed VRF 1"
640 )
641 self.send_and_assert_no_replies(
642 self.pg5, pkts_disc_vrf2, "DHCP config removed VRF 2"
643 )
Neale Rannsfca0c242017-01-13 07:57:46 -0800644
645 #
646 # configure an IP address on the client facing interface
647 #
John Lo70bfcaf2017-11-14 13:19:26 -0500648 self.pg4.config_ip4()
649 self.pg4.add_stream(pkts_disc_vrf1)
Neale Rannsfca0c242017-01-13 07:57:46 -0800650 self.pg_enable_capture(self.pg_interfaces)
651 self.pg_start()
Neale Rannsfca0c242017-01-13 07:57:46 -0800652 rx = self.pg1.get_capture(1)
653 rx = rx[0]
John Lo70bfcaf2017-11-14 13:19:26 -0500654 self.verify_relayed_dhcp_discover(rx, self.pg1, src_intf=self.pg4)
655
656 self.pg5.config_ip4()
657 self.pg5.add_stream(pkts_disc_vrf2)
658 self.pg_enable_capture(self.pg_interfaces)
659 self.pg_start()
660 rx = self.pg2.get_capture(1)
661 rx = rx[0]
662 self.verify_relayed_dhcp_discover(rx, self.pg2, src_intf=self.pg5)
Neale Rannsfca0c242017-01-13 07:57:46 -0800663
664 #
Neale Ranns20a175a2017-02-14 07:28:41 -0800665 # Add VSS config
John Lo70bfcaf2017-11-14 13:19:26 -0500666 # table=1, vss_type=1, vpn_index=1, oui=4
667 # table=2, vss_type=0, vpn_id = "ip4-table-2"
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200668 self.vapi.dhcp_proxy_set_vss(tbl_id=1, vss_type=1, vpn_index=1, oui=4, is_add=1)
669 self.vapi.dhcp_proxy_set_vss(
670 tbl_id=2, vss_type=0, vpn_ascii_id="ip4-table-2", is_add=1
671 )
Neale Ranns20a175a2017-02-14 07:28:41 -0800672
John Lo70bfcaf2017-11-14 13:19:26 -0500673 self.pg4.add_stream(pkts_disc_vrf1)
Neale Ranns20a175a2017-02-14 07:28:41 -0800674 self.pg_enable_capture(self.pg_interfaces)
675 self.pg_start()
676
677 rx = self.pg1.get_capture(1)
678 rx = rx[0]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200679 self.verify_relayed_dhcp_discover(
680 rx, self.pg1, src_intf=self.pg4, fib_id=1, oui=4
681 )
Neale Ranns20a175a2017-02-14 07:28:41 -0800682
John Lo70bfcaf2017-11-14 13:19:26 -0500683 self.pg5.add_stream(pkts_disc_vrf2)
684 self.pg_enable_capture(self.pg_interfaces)
685 self.pg_start()
686
687 rx = self.pg2.get_capture(1)
688 rx = rx[0]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200689 self.verify_relayed_dhcp_discover(
690 rx, self.pg2, src_intf=self.pg5, vpn_id="ip4-table-2"
691 )
John Lo70bfcaf2017-11-14 13:19:26 -0500692
Neale Ranns20a175a2017-02-14 07:28:41 -0800693 #
Neale Ranns3466c302017-02-16 07:45:03 -0800694 # Add a second DHCP server in VRF 1
695 # expect clients messages to be relay to both configured servers
696 #
697 self.pg1.generate_remote_hosts(2)
Jakub Grajciar103ba6b2019-10-01 11:30:56 +0200698 server_addr12 = self.pg1.remote_hosts[1].ip4
Neale Ranns3466c302017-02-16 07:45:03 -0800699
Jakub Grajciar103ba6b2019-10-01 11:30:56 +0200700 Proxy12 = VppDHCPProxy(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200701 self, server_addr12, src_addr, rx_vrf_id=1, server_vrf_id=1
702 )
Jakub Grajciar103ba6b2019-10-01 11:30:56 +0200703 Proxy12.add_vpp_config()
Neale Ranns3466c302017-02-16 07:45:03 -0800704
705 #
706 # We'll need an ARP entry for the server to send it packets
707 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200708 arp_entry = VppNeighbor(
709 self,
710 self.pg1.sw_if_index,
711 self.pg1.remote_hosts[1].mac,
712 self.pg1.remote_hosts[1].ip4,
713 )
Neale Ranns3466c302017-02-16 07:45:03 -0800714 arp_entry.add_vpp_config()
715
716 #
717 # Send a discover from the client. expect two relayed messages
718 # The frist packet is sent to the second server
719 # We're not enforcing that here, it's just the way it is.
720 #
John Lo70bfcaf2017-11-14 13:19:26 -0500721 self.pg4.add_stream(pkts_disc_vrf1)
Neale Ranns3466c302017-02-16 07:45:03 -0800722 self.pg_enable_capture(self.pg_interfaces)
723 self.pg_start()
724
725 rx = self.pg1.get_capture(2)
726
Neale Rannsa2fbf6b2017-07-18 08:23:32 -0700727 option_82 = self.verify_relayed_dhcp_discover(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200728 rx[0],
729 self.pg1,
John Lo70bfcaf2017-11-14 13:19:26 -0500730 src_intf=self.pg4,
Neale Ranns3466c302017-02-16 07:45:03 -0800731 dst_mac=self.pg1.remote_hosts[1].mac,
732 dst_ip=self.pg1.remote_hosts[1].ip4,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200733 fib_id=1,
734 oui=4,
735 )
736 self.verify_relayed_dhcp_discover(
737 rx[1], self.pg1, src_intf=self.pg4, fib_id=1, oui=4
738 )
Neale Ranns3466c302017-02-16 07:45:03 -0800739
740 #
741 # Send both packets back. Client gets both.
742 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200743 p1 = (
744 Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac)
745 / IP(src=self.pg1.remote_ip4, dst=self.pg1.local_ip4)
746 / UDP(sport=DHCP4_SERVER_PORT, dport=DHCP4_SERVER_PORT)
747 / BOOTP(op=1)
748 / DHCP(
749 options=[
750 ("message-type", "offer"),
751 ("relay_agent_Information", option_82),
752 ("end"),
753 ]
754 )
755 )
756 p2 = (
757 Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac)
758 / IP(src=self.pg1.remote_hosts[1].ip4, dst=self.pg1.local_ip4)
759 / UDP(sport=DHCP4_SERVER_PORT, dport=DHCP4_SERVER_PORT)
760 / BOOTP(op=1)
761 / DHCP(
762 options=[
763 ("message-type", "offer"),
764 ("relay_agent_Information", option_82),
765 ("end"),
766 ]
767 )
768 )
Neale Ranns3466c302017-02-16 07:45:03 -0800769 pkts = [p1, p2]
770
771 self.pg1.add_stream(pkts)
772 self.pg_enable_capture(self.pg_interfaces)
773 self.pg_start()
774
John Lo70bfcaf2017-11-14 13:19:26 -0500775 rx = self.pg4.get_capture(2)
Neale Ranns3466c302017-02-16 07:45:03 -0800776
John Lo70bfcaf2017-11-14 13:19:26 -0500777 self.verify_dhcp_offer(rx[0], self.pg4, fib_id=1, oui=4)
778 self.verify_dhcp_offer(rx[1], self.pg4, fib_id=1, oui=4)
Neale Ranns3466c302017-02-16 07:45:03 -0800779
780 #
781 # Ensure offers from non-servers are dropeed
782 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200783 p2 = (
784 Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac)
785 / IP(src="8.8.8.8", dst=self.pg1.local_ip4)
786 / UDP(sport=DHCP4_SERVER_PORT, dport=DHCP4_SERVER_PORT)
787 / BOOTP(op=1)
788 / DHCP(
789 options=[
790 ("message-type", "offer"),
791 ("relay_agent_Information", option_82),
792 ("end"),
793 ]
794 )
795 )
796 self.send_and_assert_no_replies(self.pg1, p2, "DHCP offer from non-server")
Neale Ranns3466c302017-02-16 07:45:03 -0800797
798 #
799 # Ensure only the discover is sent to multiple servers
800 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200801 p_req_vrf1 = (
802 Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg4.remote_mac)
803 / IP(src="0.0.0.0", dst="255.255.255.255")
804 / UDP(sport=DHCP4_CLIENT_PORT, dport=DHCP4_SERVER_PORT)
805 / BOOTP(op=1)
806 / DHCP(options=[("message-type", "request"), ("end")])
807 )
Neale Ranns3466c302017-02-16 07:45:03 -0800808
John Lo70bfcaf2017-11-14 13:19:26 -0500809 self.pg4.add_stream(p_req_vrf1)
Neale Ranns3466c302017-02-16 07:45:03 -0800810 self.pg_enable_capture(self.pg_interfaces)
811 self.pg_start()
812
813 rx = self.pg1.get_capture(1)
814
815 #
816 # Remove the second DHCP server
817 #
Jakub Grajciar103ba6b2019-10-01 11:30:56 +0200818 Proxy12.remove_vpp_config()
Neale Ranns3466c302017-02-16 07:45:03 -0800819
820 #
821 # Test we can still relay with the first
822 #
John Lo70bfcaf2017-11-14 13:19:26 -0500823 self.pg4.add_stream(pkts_disc_vrf1)
Neale Ranns3466c302017-02-16 07:45:03 -0800824 self.pg_enable_capture(self.pg_interfaces)
825 self.pg_start()
826
827 rx = self.pg1.get_capture(1)
828 rx = rx[0]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200829 self.verify_relayed_dhcp_discover(
830 rx, self.pg1, src_intf=self.pg4, fib_id=1, oui=4
831 )
Neale Ranns3466c302017-02-16 07:45:03 -0800832
833 #
Neale Ranns20a175a2017-02-14 07:28:41 -0800834 # Remove the VSS config
835 # relayed DHCP has default vlaues in the option.
836 #
Neale Ranns02bfd642019-10-07 00:39:28 -0700837 self.vapi.dhcp_proxy_set_vss(tbl_id=1, is_add=0)
838 self.vapi.dhcp_proxy_set_vss(tbl_id=2, is_add=0)
Neale Ranns20a175a2017-02-14 07:28:41 -0800839
John Lo70bfcaf2017-11-14 13:19:26 -0500840 self.pg4.add_stream(pkts_disc_vrf1)
Neale Ranns20a175a2017-02-14 07:28:41 -0800841 self.pg_enable_capture(self.pg_interfaces)
842 self.pg_start()
843
844 rx = self.pg1.get_capture(1)
845 rx = rx[0]
John Lo70bfcaf2017-11-14 13:19:26 -0500846 self.verify_relayed_dhcp_discover(rx, self.pg1, src_intf=self.pg4)
Neale Ranns20a175a2017-02-14 07:28:41 -0800847
848 #
Neale Rannsfca0c242017-01-13 07:57:46 -0800849 # remove DHCP config to cleanup
850 #
Jakub Grajciar103ba6b2019-10-01 11:30:56 +0200851 Proxy1.remove_vpp_config()
852 Proxy2.remove_vpp_config()
Neale Rannsfca0c242017-01-13 07:57:46 -0800853
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200854 self.send_and_assert_no_replies(self.pg3, pkts_disc_vrf0, "DHCP cleanup VRF 0")
855 self.send_and_assert_no_replies(self.pg4, pkts_disc_vrf1, "DHCP cleanup VRF 1")
856 self.send_and_assert_no_replies(self.pg5, pkts_disc_vrf2, "DHCP cleanup VRF 2")
John Lo70bfcaf2017-11-14 13:19:26 -0500857
Neale Ranns15002542017-09-10 04:39:11 -0700858 self.pg3.unconfig_ip4()
John Lo70bfcaf2017-11-14 13:19:26 -0500859 self.pg4.unconfig_ip4()
860 self.pg5.unconfig_ip4()
Neale Rannsfca0c242017-01-13 07:57:46 -0800861
862 def test_dhcp6_proxy(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200863 """DHCPv6 Proxy"""
Neale Rannsfca0c242017-01-13 07:57:46 -0800864 #
865 # Verify no response to DHCP request without DHCP config
866 #
867 dhcp_solicit_dst = "ff02::1:2"
John Lo70bfcaf2017-11-14 13:19:26 -0500868 dhcp_solicit_src_vrf0 = mk_ll_addr(self.pg3.remote_mac)
869 dhcp_solicit_src_vrf1 = mk_ll_addr(self.pg4.remote_mac)
870 dhcp_solicit_src_vrf2 = mk_ll_addr(self.pg5.remote_mac)
Jakub Grajciar103ba6b2019-10-01 11:30:56 +0200871 server_addr_vrf0 = self.pg0.remote_ip6
872 src_addr_vrf0 = self.pg0.local_ip6
873 server_addr_vrf1 = self.pg1.remote_ip6
874 src_addr_vrf1 = self.pg1.local_ip6
875 server_addr_vrf2 = self.pg2.remote_ip6
876 src_addr_vrf2 = self.pg2.local_ip6
Neale Rannsfca0c242017-01-13 07:57:46 -0800877
Neale Rannsfca0c242017-01-13 07:57:46 -0800878 dmac = in6_getnsmac(inet_pton(socket.AF_INET6, dhcp_solicit_dst))
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200879 p_solicit_vrf0 = (
880 Ether(dst=dmac, src=self.pg3.remote_mac)
881 / IPv6(src=dhcp_solicit_src_vrf0, dst=dhcp_solicit_dst)
882 / UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_CLIENT_PORT)
883 / DHCP6_Solicit()
884 )
885 p_solicit_vrf1 = (
886 Ether(dst=dmac, src=self.pg4.remote_mac)
887 / IPv6(src=dhcp_solicit_src_vrf1, dst=dhcp_solicit_dst)
888 / UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_CLIENT_PORT)
889 / DHCP6_Solicit()
890 )
891 p_solicit_vrf2 = (
892 Ether(dst=dmac, src=self.pg5.remote_mac)
893 / IPv6(src=dhcp_solicit_src_vrf2, dst=dhcp_solicit_dst)
894 / UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_CLIENT_PORT)
895 / DHCP6_Solicit()
896 )
Neale Rannsfca0c242017-01-13 07:57:46 -0800897
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200898 self.send_and_assert_no_replies(
899 self.pg3, p_solicit_vrf0, "DHCP with no configuration"
900 )
901 self.send_and_assert_no_replies(
902 self.pg4, p_solicit_vrf1, "DHCP with no configuration"
903 )
904 self.send_and_assert_no_replies(
905 self.pg5, p_solicit_vrf2, "DHCP with no configuration"
906 )
Neale Rannsfca0c242017-01-13 07:57:46 -0800907
908 #
909 # DHCPv6 config in VRF 0.
910 # Packets still dropped because the client facing interface has no
911 # IPv6 config
912 #
Jakub Grajciar103ba6b2019-10-01 11:30:56 +0200913 Proxy = VppDHCPProxy(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200914 self, server_addr_vrf0, src_addr_vrf0, rx_vrf_id=0, server_vrf_id=0
915 )
Jakub Grajciar103ba6b2019-10-01 11:30:56 +0200916 Proxy.add_vpp_config()
Neale Rannsfca0c242017-01-13 07:57:46 -0800917
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200918 self.send_and_assert_no_replies(
919 self.pg3, p_solicit_vrf0, "DHCP with no configuration"
920 )
921 self.send_and_assert_no_replies(
922 self.pg4, p_solicit_vrf1, "DHCP with no configuration"
923 )
Neale Rannsfca0c242017-01-13 07:57:46 -0800924
925 #
926 # configure an IP address on the client facing interface
927 #
John Lo70bfcaf2017-11-14 13:19:26 -0500928 self.pg3.config_ip6()
Neale Rannsfca0c242017-01-13 07:57:46 -0800929
930 #
931 # Now the DHCP requests are relayed to the server
932 #
John Lo70bfcaf2017-11-14 13:19:26 -0500933 self.pg3.add_stream(p_solicit_vrf0)
Neale Rannsfca0c242017-01-13 07:57:46 -0800934 self.pg_enable_capture(self.pg_interfaces)
935 self.pg_start()
936
937 rx = self.pg0.get_capture(1)
Neale Ranns3466c302017-02-16 07:45:03 -0800938
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200939 self.verify_dhcp6_solicit(
940 rx[0], self.pg0, dhcp_solicit_src_vrf0, self.pg3.remote_mac
941 )
Neale Rannsfca0c242017-01-13 07:57:46 -0800942
943 #
944 # Exception cases for rejected relay responses
945 #
946
947 # 1 - not a relay reply
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200948 p_adv_vrf0 = (
949 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
950 / IPv6(dst=self.pg0.local_ip6, src=self.pg0.remote_ip6)
951 / UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_SERVER_PORT)
952 / DHCP6_Advertise()
953 )
954 self.send_and_assert_no_replies(self.pg3, p_adv_vrf0, "DHCP6 not a relay reply")
Neale Rannsfca0c242017-01-13 07:57:46 -0800955
956 # 2 - no relay message option
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200957 p_adv_vrf0 = (
958 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
959 / IPv6(dst=self.pg0.local_ip6, src=self.pg0.remote_ip6)
960 / UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_SERVER_PORT)
961 / DHCP6_RelayReply()
962 / DHCP6_Advertise()
963 )
964 self.send_and_assert_no_replies(
965 self.pg3, p_adv_vrf0, "DHCP not a relay message"
966 )
Neale Rannsfca0c242017-01-13 07:57:46 -0800967
968 # 3 - no circuit ID
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200969 p_adv_vrf0 = (
970 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
971 / IPv6(dst=self.pg0.local_ip6, src=self.pg0.remote_ip6)
972 / UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_SERVER_PORT)
973 / DHCP6_RelayReply()
974 / DHCP6OptRelayMsg(optlen=0)
975 / DHCP6_Advertise()
976 )
977 self.send_and_assert_no_replies(self.pg3, p_adv_vrf0, "DHCP6 no circuit ID")
Neale Rannsfca0c242017-01-13 07:57:46 -0800978 # 4 - wrong circuit ID
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200979 p_adv_vrf0 = (
980 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
981 / IPv6(dst=self.pg0.local_ip6, src=self.pg0.remote_ip6)
982 / UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_SERVER_PORT)
983 / DHCP6_RelayReply()
984 / DHCP6OptIfaceId(optlen=4, ifaceid="\x00\x00\x00\x05")
985 / DHCP6OptRelayMsg(optlen=0)
986 / DHCP6_Advertise()
987 )
988 self.send_and_assert_no_replies(self.pg3, p_adv_vrf0, "DHCP6 wrong circuit ID")
Neale Rannsfca0c242017-01-13 07:57:46 -0800989
990 #
991 # Send the relay response (the advertisement)
992 # - no peer address
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200993 p_adv_vrf0 = (
994 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
995 / IPv6(dst=self.pg0.local_ip6, src=self.pg0.remote_ip6)
996 / UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_SERVER_PORT)
997 / DHCP6_RelayReply()
998 / DHCP6OptIfaceId(optlen=4, ifaceid="\x00\x00\x00\x04")
999 / DHCP6OptRelayMsg(optlen=0)
1000 / DHCP6_Advertise(trid=1)
1001 / DHCP6OptStatusCode(statuscode=0)
1002 )
Neale Rannsfca0c242017-01-13 07:57:46 -08001003 pkts_adv_vrf0 = [p_adv_vrf0]
1004
1005 self.pg0.add_stream(pkts_adv_vrf0)
1006 self.pg_enable_capture(self.pg_interfaces)
1007 self.pg_start()
1008
John Lo70bfcaf2017-11-14 13:19:26 -05001009 rx = self.pg3.get_capture(1)
Neale Ranns3466c302017-02-16 07:45:03 -08001010
John Lo70bfcaf2017-11-14 13:19:26 -05001011 self.verify_dhcp6_advert(rx[0], self.pg3, "::")
Neale Rannsfca0c242017-01-13 07:57:46 -08001012
1013 #
1014 # Send the relay response (the advertisement)
1015 # - with peer address
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001016 p_adv_vrf0 = (
1017 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1018 / IPv6(dst=self.pg0.local_ip6, src=self.pg0.remote_ip6)
1019 / UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_SERVER_PORT)
1020 / DHCP6_RelayReply(peeraddr=dhcp_solicit_src_vrf0)
1021 / DHCP6OptIfaceId(optlen=4, ifaceid="\x00\x00\x00\x04")
1022 / DHCP6OptRelayMsg(optlen=0)
1023 / DHCP6_Advertise(trid=1)
1024 / DHCP6OptStatusCode(statuscode=0)
1025 )
Neale Rannsfca0c242017-01-13 07:57:46 -08001026 pkts_adv_vrf0 = [p_adv_vrf0]
1027
1028 self.pg0.add_stream(pkts_adv_vrf0)
1029 self.pg_enable_capture(self.pg_interfaces)
1030 self.pg_start()
1031
John Lo70bfcaf2017-11-14 13:19:26 -05001032 rx = self.pg3.get_capture(1)
Neale Ranns3466c302017-02-16 07:45:03 -08001033
John Lo70bfcaf2017-11-14 13:19:26 -05001034 self.verify_dhcp6_advert(rx[0], self.pg3, dhcp_solicit_src_vrf0)
Neale Rannsfca0c242017-01-13 07:57:46 -08001035
1036 #
John Lo70bfcaf2017-11-14 13:19:26 -05001037 # Add all the config for VRF 1 & 2
Neale Rannsfca0c242017-01-13 07:57:46 -08001038 #
Jakub Grajciar103ba6b2019-10-01 11:30:56 +02001039 Proxy1 = VppDHCPProxy(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001040 self, server_addr_vrf1, src_addr_vrf1, rx_vrf_id=1, server_vrf_id=1
1041 )
Jakub Grajciar103ba6b2019-10-01 11:30:56 +02001042 Proxy1.add_vpp_config()
John Lo70bfcaf2017-11-14 13:19:26 -05001043 self.pg4.config_ip6()
1044
Jakub Grajciar103ba6b2019-10-01 11:30:56 +02001045 Proxy2 = VppDHCPProxy(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001046 self, server_addr_vrf2, src_addr_vrf2, rx_vrf_id=2, server_vrf_id=2
1047 )
Jakub Grajciar103ba6b2019-10-01 11:30:56 +02001048 Proxy2.add_vpp_config()
John Lo70bfcaf2017-11-14 13:19:26 -05001049 self.pg5.config_ip6()
Neale Rannsfca0c242017-01-13 07:57:46 -08001050
1051 #
1052 # VRF 1 solicit
1053 #
John Lo70bfcaf2017-11-14 13:19:26 -05001054 self.pg4.add_stream(p_solicit_vrf1)
Neale Rannsfca0c242017-01-13 07:57:46 -08001055 self.pg_enable_capture(self.pg_interfaces)
1056 self.pg_start()
1057
1058 rx = self.pg1.get_capture(1)
Neale Ranns3466c302017-02-16 07:45:03 -08001059
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001060 self.verify_dhcp6_solicit(
1061 rx[0], self.pg1, dhcp_solicit_src_vrf1, self.pg4.remote_mac
1062 )
John Lo70bfcaf2017-11-14 13:19:26 -05001063
1064 #
1065 # VRF 2 solicit
1066 #
1067 self.pg5.add_stream(p_solicit_vrf2)
1068 self.pg_enable_capture(self.pg_interfaces)
1069 self.pg_start()
1070
1071 rx = self.pg2.get_capture(1)
1072
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001073 self.verify_dhcp6_solicit(
1074 rx[0], self.pg2, dhcp_solicit_src_vrf2, self.pg5.remote_mac
1075 )
Neale Rannsfca0c242017-01-13 07:57:46 -08001076
1077 #
1078 # VRF 1 Advert
1079 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001080 p_adv_vrf1 = (
1081 Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac)
1082 / IPv6(dst=self.pg1.local_ip6, src=self.pg1.remote_ip6)
1083 / UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_SERVER_PORT)
1084 / DHCP6_RelayReply(peeraddr=dhcp_solicit_src_vrf1)
1085 / DHCP6OptIfaceId(optlen=4, ifaceid="\x00\x00\x00\x05")
1086 / DHCP6OptRelayMsg(optlen=0)
1087 / DHCP6_Advertise(trid=1)
1088 / DHCP6OptStatusCode(statuscode=0)
1089 )
Neale Rannsfca0c242017-01-13 07:57:46 -08001090 pkts_adv_vrf1 = [p_adv_vrf1]
1091
1092 self.pg1.add_stream(pkts_adv_vrf1)
1093 self.pg_enable_capture(self.pg_interfaces)
1094 self.pg_start()
1095
John Lo70bfcaf2017-11-14 13:19:26 -05001096 rx = self.pg4.get_capture(1)
Neale Ranns3466c302017-02-16 07:45:03 -08001097
John Lo70bfcaf2017-11-14 13:19:26 -05001098 self.verify_dhcp6_advert(rx[0], self.pg4, dhcp_solicit_src_vrf1)
Neale Rannsfca0c242017-01-13 07:57:46 -08001099
1100 #
1101 # Add VSS config
Jakub Grajciar103ba6b2019-10-01 11:30:56 +02001102 #
1103 self.vapi.dhcp_proxy_set_vss(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001104 tbl_id=1, vss_type=1, oui=4, vpn_index=1, is_ipv6=1, is_add=1
1105 )
Jakub Grajciar103ba6b2019-10-01 11:30:56 +02001106 self.vapi.dhcp_proxy_set_vss(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001107 tbl_id=2, vss_type=0, vpn_ascii_id="IPv6-table-2", is_ipv6=1, is_add=1
1108 )
Neale Rannsfca0c242017-01-13 07:57:46 -08001109
John Lo70bfcaf2017-11-14 13:19:26 -05001110 self.pg4.add_stream(p_solicit_vrf1)
Neale Rannsfca0c242017-01-13 07:57:46 -08001111 self.pg_enable_capture(self.pg_interfaces)
1112 self.pg_start()
1113
1114 rx = self.pg1.get_capture(1)
Neale Ranns3466c302017-02-16 07:45:03 -08001115
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001116 self.verify_dhcp6_solicit(
1117 rx[0], self.pg1, dhcp_solicit_src_vrf1, self.pg4.remote_mac, fib_id=1, oui=4
1118 )
Neale Rannsfca0c242017-01-13 07:57:46 -08001119
John Lo70bfcaf2017-11-14 13:19:26 -05001120 self.pg5.add_stream(p_solicit_vrf2)
1121 self.pg_enable_capture(self.pg_interfaces)
1122 self.pg_start()
1123
1124 rx = self.pg2.get_capture(1)
1125
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001126 self.verify_dhcp6_solicit(
1127 rx[0],
1128 self.pg2,
1129 dhcp_solicit_src_vrf2,
1130 self.pg5.remote_mac,
1131 vpn_id="IPv6-table-2",
1132 )
John Lo70bfcaf2017-11-14 13:19:26 -05001133
Neale Rannsfca0c242017-01-13 07:57:46 -08001134 #
1135 # Remove the VSS config
1136 # relayed DHCP has default vlaues in the option.
1137 #
Neale Ranns02bfd642019-10-07 00:39:28 -07001138 self.vapi.dhcp_proxy_set_vss(tbl_id=1, is_ipv6=1, is_add=0)
Neale Rannsfca0c242017-01-13 07:57:46 -08001139
John Lo70bfcaf2017-11-14 13:19:26 -05001140 self.pg4.add_stream(p_solicit_vrf1)
Neale Rannsfca0c242017-01-13 07:57:46 -08001141 self.pg_enable_capture(self.pg_interfaces)
1142 self.pg_start()
1143
1144 rx = self.pg1.get_capture(1)
Neale Ranns3466c302017-02-16 07:45:03 -08001145
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001146 self.verify_dhcp6_solicit(
1147 rx[0], self.pg1, dhcp_solicit_src_vrf1, self.pg4.remote_mac
1148 )
Neale Ranns3466c302017-02-16 07:45:03 -08001149
1150 #
1151 # Add a second DHCP server in VRF 1
1152 # expect clients messages to be relay to both configured servers
1153 #
1154 self.pg1.generate_remote_hosts(2)
Jakub Grajciar103ba6b2019-10-01 11:30:56 +02001155 server_addr12 = self.pg1.remote_hosts[1].ip6
Neale Ranns3466c302017-02-16 07:45:03 -08001156
Jakub Grajciar103ba6b2019-10-01 11:30:56 +02001157 Proxy12 = VppDHCPProxy(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001158 self, server_addr12, src_addr_vrf1, rx_vrf_id=1, server_vrf_id=1
1159 )
Jakub Grajciar103ba6b2019-10-01 11:30:56 +02001160 Proxy12.add_vpp_config()
Neale Ranns3466c302017-02-16 07:45:03 -08001161
1162 #
1163 # We'll need an ND entry for the server to send it packets
1164 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001165 nd_entry = VppNeighbor(
1166 self,
1167 self.pg1.sw_if_index,
1168 self.pg1.remote_hosts[1].mac,
1169 self.pg1.remote_hosts[1].ip6,
1170 )
Neale Ranns3466c302017-02-16 07:45:03 -08001171 nd_entry.add_vpp_config()
1172
1173 #
1174 # Send a discover from the client. expect two relayed messages
1175 # The frist packet is sent to the second server
1176 # We're not enforcing that here, it's just the way it is.
1177 #
John Lo70bfcaf2017-11-14 13:19:26 -05001178 self.pg4.add_stream(p_solicit_vrf1)
Neale Ranns3466c302017-02-16 07:45:03 -08001179 self.pg_enable_capture(self.pg_interfaces)
1180 self.pg_start()
1181
1182 rx = self.pg1.get_capture(2)
1183
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001184 self.verify_dhcp6_solicit(
1185 rx[0], self.pg1, dhcp_solicit_src_vrf1, self.pg4.remote_mac
1186 )
1187 self.verify_dhcp6_solicit(
1188 rx[1],
1189 self.pg1,
1190 dhcp_solicit_src_vrf1,
1191 self.pg4.remote_mac,
1192 dst_mac=self.pg1.remote_hosts[1].mac,
1193 dst_ip=self.pg1.remote_hosts[1].ip6,
1194 )
Neale Ranns3466c302017-02-16 07:45:03 -08001195
1196 #
1197 # Send both packets back. Client gets both.
1198 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001199 p1 = (
1200 Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac)
1201 / IPv6(dst=self.pg1.local_ip6, src=self.pg1.remote_ip6)
1202 / UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_SERVER_PORT)
1203 / DHCP6_RelayReply(peeraddr=dhcp_solicit_src_vrf1)
1204 / DHCP6OptIfaceId(optlen=4, ifaceid="\x00\x00\x00\x05")
1205 / DHCP6OptRelayMsg(optlen=0)
1206 / DHCP6_Advertise(trid=1)
1207 / DHCP6OptStatusCode(statuscode=0)
1208 )
1209 p2 = (
1210 Ether(dst=self.pg1.local_mac, src=self.pg1.remote_hosts[1].mac)
1211 / IPv6(dst=self.pg1.local_ip6, src=self.pg1._remote_hosts[1].ip6)
1212 / UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_SERVER_PORT)
1213 / DHCP6_RelayReply(peeraddr=dhcp_solicit_src_vrf1)
1214 / DHCP6OptIfaceId(optlen=4, ifaceid="\x00\x00\x00\x05")
1215 / DHCP6OptRelayMsg(optlen=0)
1216 / DHCP6_Advertise(trid=1)
1217 / DHCP6OptStatusCode(statuscode=0)
1218 )
Neale Ranns3466c302017-02-16 07:45:03 -08001219
1220 pkts = [p1, p2]
1221
1222 self.pg1.add_stream(pkts)
1223 self.pg_enable_capture(self.pg_interfaces)
1224 self.pg_start()
1225
John Lo70bfcaf2017-11-14 13:19:26 -05001226 rx = self.pg4.get_capture(2)
Neale Ranns3466c302017-02-16 07:45:03 -08001227
John Lo70bfcaf2017-11-14 13:19:26 -05001228 self.verify_dhcp6_advert(rx[0], self.pg4, dhcp_solicit_src_vrf1)
1229 self.verify_dhcp6_advert(rx[1], self.pg4, dhcp_solicit_src_vrf1)
Neale Ranns3466c302017-02-16 07:45:03 -08001230
1231 #
1232 # Ensure only solicit messages are duplicated
1233 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001234 p_request_vrf1 = (
1235 Ether(dst=dmac, src=self.pg4.remote_mac)
1236 / IPv6(src=dhcp_solicit_src_vrf1, dst=dhcp_solicit_dst)
1237 / UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_CLIENT_PORT)
1238 / DHCP6_Request()
1239 )
Neale Ranns3466c302017-02-16 07:45:03 -08001240
John Lo70bfcaf2017-11-14 13:19:26 -05001241 self.pg4.add_stream(p_request_vrf1)
Neale Ranns3466c302017-02-16 07:45:03 -08001242 self.pg_enable_capture(self.pg_interfaces)
1243 self.pg_start()
1244
1245 rx = self.pg1.get_capture(1)
1246
1247 #
1248 # Test we drop DHCP packets from addresses that are not configured as
1249 # DHCP servers
1250 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001251 p2 = (
1252 Ether(dst=self.pg1.local_mac, src=self.pg1.remote_hosts[1].mac)
1253 / IPv6(dst=self.pg1.local_ip6, src="3001::1")
1254 / UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_SERVER_PORT)
1255 / DHCP6_RelayReply(peeraddr=dhcp_solicit_src_vrf1)
1256 / DHCP6OptIfaceId(optlen=4, ifaceid="\x00\x00\x00\x05")
1257 / DHCP6OptRelayMsg(optlen=0)
1258 / DHCP6_Advertise(trid=1)
1259 / DHCP6OptStatusCode(statuscode=0)
1260 )
1261 self.send_and_assert_no_replies(self.pg1, p2, "DHCP6 not from server")
Neale Ranns3466c302017-02-16 07:45:03 -08001262
1263 #
1264 # Remove the second DHCP server
1265 #
Jakub Grajciar103ba6b2019-10-01 11:30:56 +02001266 Proxy12.remove_vpp_config()
Neale Ranns3466c302017-02-16 07:45:03 -08001267
1268 #
1269 # Test we can still relay with the first
1270 #
John Lo70bfcaf2017-11-14 13:19:26 -05001271 self.pg4.add_stream(p_solicit_vrf1)
Neale Ranns3466c302017-02-16 07:45:03 -08001272 self.pg_enable_capture(self.pg_interfaces)
1273 self.pg_start()
1274
1275 rx = self.pg1.get_capture(1)
1276
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001277 self.verify_dhcp6_solicit(
1278 rx[0], self.pg1, dhcp_solicit_src_vrf1, self.pg4.remote_mac
1279 )
Neale Rannsfca0c242017-01-13 07:57:46 -08001280
1281 #
1282 # Cleanup
1283 #
Jakub Grajciar103ba6b2019-10-01 11:30:56 +02001284 Proxy.remove_vpp_config()
1285 Proxy1.remove_vpp_config()
1286 Proxy2.remove_vpp_config()
Neale Ranns3466c302017-02-16 07:45:03 -08001287
Neale Ranns15002542017-09-10 04:39:11 -07001288 self.pg3.unconfig_ip6()
John Lo70bfcaf2017-11-14 13:19:26 -05001289 self.pg4.unconfig_ip6()
1290 self.pg5.unconfig_ip6()
Neale Rannsfca0c242017-01-13 07:57:46 -08001291
Neale Rannsa2fbf6b2017-07-18 08:23:32 -07001292 def test_dhcp_client(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001293 """DHCP Client"""
Neale Rannsa2fbf6b2017-07-18 08:23:32 -07001294
Neale Ranns038e1df2019-07-19 14:01:02 +00001295 vdscp = VppEnum.vl_api_ip_dscp_t
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001296 hostname = "universal-dp"
Neale Rannsa2fbf6b2017-07-18 08:23:32 -07001297
1298 self.pg_enable_capture(self.pg_interfaces)
1299
1300 #
John Lo70bfcaf2017-11-14 13:19:26 -05001301 # Configure DHCP client on PG3 and capture the discover sent
Neale Rannsa2fbf6b2017-07-18 08:23:32 -07001302 #
Jakub Grajciar103ba6b2019-10-01 11:30:56 +02001303 Client = VppDHCPClient(self, self.pg3.sw_if_index, hostname)
1304 Client.add_vpp_config()
1305 self.assertTrue(Client.query_vpp_config())
Neale Rannsa2fbf6b2017-07-18 08:23:32 -07001306
John Lo70bfcaf2017-11-14 13:19:26 -05001307 rx = self.pg3.get_capture(1)
Neale Rannsa2fbf6b2017-07-18 08:23:32 -07001308
John Lo70bfcaf2017-11-14 13:19:26 -05001309 self.verify_orig_dhcp_discover(rx[0], self.pg3, hostname)
Neale Rannsa2fbf6b2017-07-18 08:23:32 -07001310
1311 #
John Lo70bfcaf2017-11-14 13:19:26 -05001312 # Send back on offer, expect the request
Neale Rannsa2fbf6b2017-07-18 08:23:32 -07001313 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001314 p_offer = (
1315 Ether(dst=self.pg3.local_mac, src=self.pg3.remote_mac)
1316 / IP(src=self.pg3.remote_ip4, dst="255.255.255.255")
1317 / UDP(sport=DHCP4_SERVER_PORT, dport=DHCP4_CLIENT_PORT)
1318 / BOOTP(
1319 op=1, yiaddr=self.pg3.local_ip4, chaddr=mac_pton(self.pg3.local_mac)
1320 )
1321 / DHCP(
1322 options=[
1323 ("message-type", "offer"),
1324 ("server_id", self.pg3.remote_ip4),
1325 "end",
1326 ]
1327 )
1328 )
Neale Rannsa2fbf6b2017-07-18 08:23:32 -07001329
John Lo70bfcaf2017-11-14 13:19:26 -05001330 self.pg3.add_stream(p_offer)
Neale Rannsa2fbf6b2017-07-18 08:23:32 -07001331 self.pg_enable_capture(self.pg_interfaces)
1332 self.pg_start()
1333
John Lo70bfcaf2017-11-14 13:19:26 -05001334 rx = self.pg3.get_capture(1)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001335 self.verify_orig_dhcp_request(rx[0], self.pg3, hostname, self.pg3.local_ip4)
Neale Rannsa2fbf6b2017-07-18 08:23:32 -07001336
1337 #
Jan Gelety2a3fb1a2018-06-27 10:56:17 +02001338 # Send an acknowledgment
Neale Rannsa2fbf6b2017-07-18 08:23:32 -07001339 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001340 p_ack = (
1341 Ether(dst=self.pg3.local_mac, src=self.pg3.remote_mac)
1342 / IP(src=self.pg3.remote_ip4, dst="255.255.255.255")
1343 / UDP(sport=DHCP4_SERVER_PORT, dport=DHCP4_CLIENT_PORT)
1344 / BOOTP(
1345 op=1, yiaddr=self.pg3.local_ip4, chaddr=mac_pton(self.pg3.local_mac)
1346 )
1347 / DHCP(
1348 options=[
1349 ("message-type", "ack"),
1350 ("subnet_mask", "255.255.255.0"),
1351 ("router", self.pg3.remote_ip4),
1352 ("server_id", self.pg3.remote_ip4),
1353 ("lease_time", 43200),
1354 "end",
1355 ]
1356 )
1357 )
Neale Rannsa2fbf6b2017-07-18 08:23:32 -07001358
John Lo70bfcaf2017-11-14 13:19:26 -05001359 self.pg3.add_stream(p_ack)
Neale Rannsa2fbf6b2017-07-18 08:23:32 -07001360 self.pg_enable_capture(self.pg_interfaces)
1361 self.pg_start()
1362
1363 #
Neale Ranns51822bf2017-07-18 09:26:53 -07001364 # We'll get an ARP request for the router address
1365 #
John Lo70bfcaf2017-11-14 13:19:26 -05001366 rx = self.pg3.get_capture(1)
Neale Ranns51822bf2017-07-18 09:26:53 -07001367
John Lo70bfcaf2017-11-14 13:19:26 -05001368 self.assertEqual(rx[0][ARP].pdst, self.pg3.remote_ip4)
Neale Ranns51822bf2017-07-18 09:26:53 -07001369 self.pg_enable_capture(self.pg_interfaces)
1370
1371 #
Neale Rannsa2fbf6b2017-07-18 08:23:32 -07001372 # At the end of this procedure there should be a connected route
1373 # in the FIB
1374 #
John Lo70bfcaf2017-11-14 13:19:26 -05001375 self.assertTrue(find_route(self, self.pg3.local_ip4, 24))
1376 self.assertTrue(find_route(self, self.pg3.local_ip4, 32))
Neale Rannsa2fbf6b2017-07-18 08:23:32 -07001377
1378 #
1379 # remove the DHCP config
1380 #
Jakub Grajciar103ba6b2019-10-01 11:30:56 +02001381 Client.remove_vpp_config()
Neale Rannsa2fbf6b2017-07-18 08:23:32 -07001382
1383 #
1384 # and now the route should be gone
1385 #
John Lo70bfcaf2017-11-14 13:19:26 -05001386 self.assertFalse(find_route(self, self.pg3.local_ip4, 32))
1387 self.assertFalse(find_route(self, self.pg3.local_ip4, 24))
Neale Rannsa2fbf6b2017-07-18 08:23:32 -07001388
Neale Ranns51822bf2017-07-18 09:26:53 -07001389 #
Neale Ranns808c5b22017-08-02 05:15:07 -07001390 # Start the procedure again. this time have VPP send the client-ID
Neale Ranns038e1df2019-07-19 14:01:02 +00001391 # and set the DSCP value
Neale Ranns51822bf2017-07-18 09:26:53 -07001392 #
John Lo70bfcaf2017-11-14 13:19:26 -05001393 self.pg3.admin_down()
Neale Ranns808c5b22017-08-02 05:15:07 -07001394 self.sleep(1)
John Lo70bfcaf2017-11-14 13:19:26 -05001395 self.pg3.admin_up()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001396 Client.set_client(
1397 self.pg3.sw_if_index,
1398 hostname,
1399 id=self.pg3.local_mac,
1400 dscp=vdscp.IP_API_DSCP_EF,
1401 )
Jakub Grajciar103ba6b2019-10-01 11:30:56 +02001402 Client.add_vpp_config()
Neale Ranns51822bf2017-07-18 09:26:53 -07001403
John Lo70bfcaf2017-11-14 13:19:26 -05001404 rx = self.pg3.get_capture(1)
Neale Ranns51822bf2017-07-18 09:26:53 -07001405
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001406 self.verify_orig_dhcp_discover(
1407 rx[0], self.pg3, hostname, self.pg3.local_mac, dscp=vdscp.IP_API_DSCP_EF
1408 )
Neale Ranns51822bf2017-07-18 09:26:53 -07001409
Jan Gelety2a3fb1a2018-06-27 10:56:17 +02001410 # TODO: VPP DHCP client should not accept DHCP OFFER message with
1411 # the XID (Transaction ID) not matching the XID of the most recent
1412 # DHCP DISCOVERY message.
1413 # Such DHCP OFFER message must be silently discarded - RFC2131.
1414 # Reported in Jira ticket: VPP-99
John Lo70bfcaf2017-11-14 13:19:26 -05001415 self.pg3.add_stream(p_offer)
Neale Ranns808c5b22017-08-02 05:15:07 -07001416 self.pg_enable_capture(self.pg_interfaces)
1417 self.pg_start()
1418
John Lo70bfcaf2017-11-14 13:19:26 -05001419 rx = self.pg3.get_capture(1)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001420 self.verify_orig_dhcp_request(
1421 rx[0], self.pg3, hostname, self.pg3.local_ip4, dscp=vdscp.IP_API_DSCP_EF
1422 )
Neale Ranns808c5b22017-08-02 05:15:07 -07001423
1424 #
1425 # unicast the ack to the offered address
1426 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001427 p_ack = (
1428 Ether(dst=self.pg3.local_mac, src=self.pg3.remote_mac)
1429 / IP(src=self.pg3.remote_ip4, dst=self.pg3.local_ip4)
1430 / UDP(sport=DHCP4_SERVER_PORT, dport=DHCP4_CLIENT_PORT)
1431 / BOOTP(
1432 op=1, yiaddr=self.pg3.local_ip4, chaddr=mac_pton(self.pg3.local_mac)
1433 )
1434 / DHCP(
1435 options=[
1436 ("message-type", "ack"),
1437 ("subnet_mask", "255.255.255.0"),
1438 ("router", self.pg3.remote_ip4),
1439 ("server_id", self.pg3.remote_ip4),
1440 ("lease_time", 43200),
1441 "end",
1442 ]
1443 )
1444 )
Neale Ranns808c5b22017-08-02 05:15:07 -07001445
John Lo70bfcaf2017-11-14 13:19:26 -05001446 self.pg3.add_stream(p_ack)
Neale Ranns808c5b22017-08-02 05:15:07 -07001447 self.pg_enable_capture(self.pg_interfaces)
1448 self.pg_start()
1449
1450 #
Neale Ranns54c6dc42018-01-17 10:29:10 -08001451 # We'll get an ARP request for the router address
1452 #
1453 rx = self.pg3.get_capture(1)
1454
1455 self.assertEqual(rx[0][ARP].pdst, self.pg3.remote_ip4)
1456 self.pg_enable_capture(self.pg_interfaces)
1457
1458 #
Neale Ranns808c5b22017-08-02 05:15:07 -07001459 # At the end of this procedure there should be a connected route
1460 # in the FIB
1461 #
John Lo70bfcaf2017-11-14 13:19:26 -05001462 self.assertTrue(find_route(self, self.pg3.local_ip4, 32))
1463 self.assertTrue(find_route(self, self.pg3.local_ip4, 24))
Neale Ranns808c5b22017-08-02 05:15:07 -07001464
Neale Ranns51822bf2017-07-18 09:26:53 -07001465 #
1466 # remove the DHCP config
1467 #
Jakub Grajciar103ba6b2019-10-01 11:30:56 +02001468 Client.remove_vpp_config()
Neale Rannsa2fbf6b2017-07-18 08:23:32 -07001469
John Lo70bfcaf2017-11-14 13:19:26 -05001470 self.assertFalse(find_route(self, self.pg3.local_ip4, 32))
1471 self.assertFalse(find_route(self, self.pg3.local_ip4, 24))
Neale Ranns808c5b22017-08-02 05:15:07 -07001472
Neale Ranns54c6dc42018-01-17 10:29:10 -08001473 #
1474 # Rince and repeat, this time with VPP configured not to set
1475 # the braodcast flag in the discover and request messages,
1476 # and for the server to unicast the responses.
1477 #
1478 # Configure DHCP client on PG3 and capture the discover sent
1479 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001480 Client.set_client(self.pg3.sw_if_index, hostname, set_broadcast_flag=False)
Jakub Grajciar103ba6b2019-10-01 11:30:56 +02001481 Client.add_vpp_config()
Neale Ranns54c6dc42018-01-17 10:29:10 -08001482
1483 rx = self.pg3.get_capture(1)
1484
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001485 self.verify_orig_dhcp_discover(rx[0], self.pg3, hostname, broadcast=False)
Neale Ranns54c6dc42018-01-17 10:29:10 -08001486
1487 #
1488 # Send back on offer, unicasted to the offered address.
1489 # Expect the request.
1490 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001491 p_offer = (
1492 Ether(dst=self.pg3.local_mac, src=self.pg3.remote_mac)
1493 / IP(src=self.pg3.remote_ip4, dst=self.pg3.local_ip4)
1494 / UDP(sport=DHCP4_SERVER_PORT, dport=DHCP4_CLIENT_PORT)
1495 / BOOTP(
1496 op=1, yiaddr=self.pg3.local_ip4, chaddr=mac_pton(self.pg3.local_mac)
1497 )
1498 / DHCP(
1499 options=[
1500 ("message-type", "offer"),
1501 ("server_id", self.pg3.remote_ip4),
1502 "end",
1503 ]
1504 )
1505 )
Neale Ranns54c6dc42018-01-17 10:29:10 -08001506
1507 self.pg3.add_stream(p_offer)
1508 self.pg_enable_capture(self.pg_interfaces)
1509 self.pg_start()
1510
1511 rx = self.pg3.get_capture(1)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001512 self.verify_orig_dhcp_request(
1513 rx[0], self.pg3, hostname, self.pg3.local_ip4, broadcast=False
1514 )
Neale Ranns54c6dc42018-01-17 10:29:10 -08001515
1516 #
Neale Ranns99536f42019-07-25 06:11:58 -07001517 # Send an acknowledgment, the lease renewal time is 2 seconds
1518 # so we should expect the renew straight after
Neale Ranns54c6dc42018-01-17 10:29:10 -08001519 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001520 p_ack = (
1521 Ether(dst=self.pg3.local_mac, src=self.pg3.remote_mac)
1522 / IP(src=self.pg3.remote_ip4, dst=self.pg3.local_ip4)
1523 / UDP(sport=DHCP4_SERVER_PORT, dport=DHCP4_CLIENT_PORT)
1524 / BOOTP(
1525 op=1, yiaddr=self.pg3.local_ip4, chaddr=mac_pton(self.pg3.local_mac)
1526 )
1527 / DHCP(
1528 options=[
1529 ("message-type", "ack"),
1530 ("subnet_mask", "255.255.255.0"),
1531 ("router", self.pg3.remote_ip4),
1532 ("server_id", self.pg3.remote_ip4),
1533 ("lease_time", 43200),
1534 ("renewal_time", 2),
1535 "end",
1536 ]
1537 )
1538 )
Neale Ranns54c6dc42018-01-17 10:29:10 -08001539
1540 self.pg3.add_stream(p_ack)
1541 self.pg_enable_capture(self.pg_interfaces)
1542 self.pg_start()
1543
1544 #
1545 # We'll get an ARP request for the router address
1546 #
1547 rx = self.pg3.get_capture(1)
1548
1549 self.assertEqual(rx[0][ARP].pdst, self.pg3.remote_ip4)
1550 self.pg_enable_capture(self.pg_interfaces)
1551
1552 #
1553 # At the end of this procedure there should be a connected route
1554 # in the FIB
1555 #
1556 self.assertTrue(find_route(self, self.pg3.local_ip4, 24))
1557 self.assertTrue(find_route(self, self.pg3.local_ip4, 32))
1558
Neale Ranns99536f42019-07-25 06:11:58 -07001559 #
Neale Ranns6bcc6a42019-10-15 15:47:55 +00001560 # read the DHCP client details from a dump
1561 #
1562 clients = self.vapi.dhcp_client_dump()
1563
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001564 self.assertEqual(clients[0].client.sw_if_index, self.pg3.sw_if_index)
1565 self.assertEqual(clients[0].lease.sw_if_index, self.pg3.sw_if_index)
Neale Ranns6bcc6a42019-10-15 15:47:55 +00001566 self.assertEqual(clients[0].client.hostname, hostname)
1567 self.assertEqual(clients[0].lease.hostname, hostname)
1568 # 0 = DISCOVER, 1 = REQUEST, 2 = BOUND
1569 self.assertEqual(clients[0].lease.state, 2)
1570 self.assertEqual(clients[0].lease.mask_width, 24)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001571 self.assertEqual(str(clients[0].lease.router_address), self.pg3.remote_ip4)
1572 self.assertEqual(str(clients[0].lease.host_address), self.pg3.local_ip4)
Neale Ranns6bcc6a42019-10-15 15:47:55 +00001573
1574 #
Neale Ranns99536f42019-07-25 06:11:58 -07001575 # wait for the unicasted renewal
1576 # the first attempt will be an ARP packet, since we have not yet
1577 # responded to VPP's request
1578 #
1579 self.logger.info(self.vapi.cli("sh dhcp client intfc pg3 verbose"))
1580 rx = self.pg3.get_capture(1, timeout=10)
1581
1582 self.assertEqual(rx[0][ARP].pdst, self.pg3.remote_ip4)
1583
1584 # respond to the arp
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001585 p_arp = Ether(dst=self.pg3.local_mac, src=self.pg3.remote_mac) / ARP(
1586 op="is-at",
1587 hwdst=self.pg3.local_mac,
1588 hwsrc=self.pg3.remote_mac,
1589 pdst=self.pg3.local_ip4,
1590 psrc=self.pg3.remote_ip4,
1591 )
Neale Ranns99536f42019-07-25 06:11:58 -07001592 self.pg3.add_stream(p_arp)
1593 self.pg_enable_capture(self.pg_interfaces)
1594 self.pg_start()
1595
1596 # the next packet is the unicasted renewal
1597 rx = self.pg3.get_capture(1, timeout=10)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001598 self.verify_orig_dhcp_request(
1599 rx[0], self.pg3, hostname, self.pg3.local_ip4, l2_bc=False, broadcast=False
1600 )
Neale Rannsdaff1782018-05-16 04:12:18 -07001601
Neale Ranns6bcc6a42019-10-15 15:47:55 +00001602 # send an ACK with different data from the original offer *
1603 self.pg3.generate_remote_hosts(4)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001604 p_ack = (
1605 Ether(dst=self.pg3.local_mac, src=self.pg3.remote_mac)
1606 / IP(src=self.pg3.remote_ip4, dst=self.pg3.local_ip4)
1607 / UDP(sport=DHCP4_SERVER_PORT, dport=DHCP4_CLIENT_PORT)
1608 / BOOTP(
1609 op=1,
1610 yiaddr=self.pg3.remote_hosts[3].ip4,
1611 chaddr=mac_pton(self.pg3.local_mac),
1612 )
1613 / DHCP(
1614 options=[
1615 ("message-type", "ack"),
1616 ("subnet_mask", "255.255.255.0"),
1617 ("router", self.pg3.remote_hosts[1].ip4),
1618 ("server_id", self.pg3.remote_hosts[2].ip4),
1619 ("lease_time", 43200),
1620 ("renewal_time", 2),
1621 "end",
1622 ]
1623 )
1624 )
Neale Ranns6bcc6a42019-10-15 15:47:55 +00001625
1626 self.pg3.add_stream(p_ack)
1627 self.pg_enable_capture(self.pg_interfaces)
1628 self.pg_start()
1629
Neale Rannsdaff1782018-05-16 04:12:18 -07001630 #
1631 # read the DHCP client details from a dump
1632 #
1633 clients = self.vapi.dhcp_client_dump()
1634
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001635 self.assertEqual(clients[0].client.sw_if_index, self.pg3.sw_if_index)
1636 self.assertEqual(clients[0].lease.sw_if_index, self.pg3.sw_if_index)
Neale Ranns6bcc6a42019-10-15 15:47:55 +00001637 self.assertEqual(clients[0].client.hostname, hostname)
1638 self.assertEqual(clients[0].lease.hostname, hostname)
Neale Rannsdaff1782018-05-16 04:12:18 -07001639 # 0 = DISCOVER, 1 = REQUEST, 2 = BOUND
1640 self.assertEqual(clients[0].lease.state, 2)
1641 self.assertEqual(clients[0].lease.mask_width, 24)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001642 self.assertEqual(
1643 str(clients[0].lease.router_address), self.pg3.remote_hosts[1].ip4
1644 )
1645 self.assertEqual(
1646 str(clients[0].lease.host_address), self.pg3.remote_hosts[3].ip4
1647 )
Neale Ranns99536f42019-07-25 06:11:58 -07001648
Neale Ranns54c6dc42018-01-17 10:29:10 -08001649 #
1650 # remove the DHCP config
1651 #
Jakub Grajciar103ba6b2019-10-01 11:30:56 +02001652 Client.remove_vpp_config()
Neale Ranns54c6dc42018-01-17 10:29:10 -08001653
1654 #
1655 # and now the route should be gone
1656 #
1657 self.assertFalse(find_route(self, self.pg3.local_ip4, 32))
1658 self.assertFalse(find_route(self, self.pg3.local_ip4, 24))
1659
Jan Gelety2a3fb1a2018-06-27 10:56:17 +02001660 #
1661 # Start the procedure again. Use requested lease time option.
Neale Ranns6bcc6a42019-10-15 15:47:55 +00001662 # this time wait for the lease to expire and the client to
1663 # self-destruct
Jan Gelety2a3fb1a2018-06-27 10:56:17 +02001664 #
Neale Ranns99536f42019-07-25 06:11:58 -07001665 hostname += "-2"
Jan Gelety2a3fb1a2018-06-27 10:56:17 +02001666 self.pg3.admin_down()
1667 self.sleep(1)
1668 self.pg3.admin_up()
Neale Ranns99536f42019-07-25 06:11:58 -07001669 self.pg_enable_capture(self.pg_interfaces)
Jakub Grajciar103ba6b2019-10-01 11:30:56 +02001670 Client.set_client(self.pg3.sw_if_index, hostname)
1671 Client.add_vpp_config()
Jan Gelety2a3fb1a2018-06-27 10:56:17 +02001672
1673 rx = self.pg3.get_capture(1)
1674
1675 self.verify_orig_dhcp_discover(rx[0], self.pg3, hostname)
1676
1677 #
1678 # Send back on offer with requested lease time, expect the request
1679 #
1680 lease_time = 1
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001681 p_offer = (
1682 Ether(dst=self.pg3.local_mac, src=self.pg3.remote_mac)
1683 / IP(src=self.pg3.remote_ip4, dst="255.255.255.255")
1684 / UDP(sport=DHCP4_SERVER_PORT, dport=DHCP4_CLIENT_PORT)
1685 / BOOTP(
1686 op=1, yiaddr=self.pg3.local_ip4, chaddr=mac_pton(self.pg3.local_mac)
1687 )
1688 / DHCP(
1689 options=[
1690 ("message-type", "offer"),
1691 ("server_id", self.pg3.remote_ip4),
1692 ("lease_time", lease_time),
1693 "end",
1694 ]
1695 )
1696 )
Jan Gelety2a3fb1a2018-06-27 10:56:17 +02001697
1698 self.pg3.add_stream(p_offer)
1699 self.pg_enable_capture(self.pg_interfaces)
1700 self.pg_start()
1701
1702 rx = self.pg3.get_capture(1)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001703 self.verify_orig_dhcp_request(rx[0], self.pg3, hostname, self.pg3.local_ip4)
Jan Gelety2a3fb1a2018-06-27 10:56:17 +02001704
1705 #
1706 # Send an acknowledgment
1707 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001708 p_ack = (
1709 Ether(dst=self.pg3.local_mac, src=self.pg3.remote_mac)
1710 / IP(src=self.pg3.remote_ip4, dst="255.255.255.255")
1711 / UDP(sport=DHCP4_SERVER_PORT, dport=DHCP4_CLIENT_PORT)
1712 / BOOTP(
1713 op=1, yiaddr=self.pg3.local_ip4, chaddr=mac_pton(self.pg3.local_mac)
1714 )
1715 / DHCP(
1716 options=[
1717 ("message-type", "ack"),
1718 ("subnet_mask", "255.255.255.0"),
1719 ("router", self.pg3.remote_ip4),
1720 ("server_id", self.pg3.remote_ip4),
1721 ("lease_time", lease_time),
1722 "end",
1723 ]
1724 )
1725 )
Jan Gelety2a3fb1a2018-06-27 10:56:17 +02001726
1727 self.pg3.add_stream(p_ack)
1728 self.pg_enable_capture(self.pg_interfaces)
1729 self.pg_start()
1730
1731 #
1732 # We'll get an ARP request for the router address
1733 #
1734 rx = self.pg3.get_capture(1)
1735
1736 self.assertEqual(rx[0][ARP].pdst, self.pg3.remote_ip4)
1737
1738 #
1739 # At the end of this procedure there should be a connected route
1740 # in the FIB
1741 #
1742 self.assertTrue(find_route(self, self.pg3.local_ip4, 32))
1743 self.assertTrue(find_route(self, self.pg3.local_ip4, 24))
1744
Jan Gelety2a3fb1a2018-06-27 10:56:17 +02001745 #
Neale Rannsf6e9b012019-01-25 06:37:15 -08001746 # the route should be gone after the lease expires
Jan Gelety2a3fb1a2018-06-27 10:56:17 +02001747 #
Neale Rannsf6e9b012019-01-25 06:37:15 -08001748 self.assertTrue(self.wait_for_no_route(self.pg3.local_ip4, 32))
1749 self.assertTrue(self.wait_for_no_route(self.pg3.local_ip4, 24))
Jan Gelety2a3fb1a2018-06-27 10:56:17 +02001750
1751 #
1752 # remove the DHCP config
1753 #
Jakub Grajciar103ba6b2019-10-01 11:30:56 +02001754 Client.remove_vpp_config()
Jan Gelety2a3fb1a2018-06-27 10:56:17 +02001755
Neale Ranns038e1df2019-07-19 14:01:02 +00001756 def test_dhcp_client_vlan(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001757 """DHCP Client w/ VLAN"""
Neale Ranns038e1df2019-07-19 14:01:02 +00001758
1759 vdscp = VppEnum.vl_api_ip_dscp_t
1760 vqos = VppEnum.vl_api_qos_source_t
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001761 hostname = "universal-dp"
Neale Ranns038e1df2019-07-19 14:01:02 +00001762
1763 self.pg_enable_capture(self.pg_interfaces)
1764
1765 vlan_100 = VppDot1QSubint(self, self.pg3, 100)
1766 vlan_100.admin_up()
1767
1768 output = [scapy.compat.chb(4)] * 256
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001769 os = b"".join(output)
1770 rows = [{"outputs": os}, {"outputs": os}, {"outputs": os}, {"outputs": os}]
Neale Ranns038e1df2019-07-19 14:01:02 +00001771
1772 qem1 = VppQosEgressMap(self, 1, rows).add_vpp_config()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001773 qm1 = VppQosMark(
1774 self, vlan_100, qem1, vqos.QOS_API_SOURCE_VLAN
1775 ).add_vpp_config()
Neale Ranns038e1df2019-07-19 14:01:02 +00001776
1777 #
1778 # Configure DHCP client on PG3 and capture the discover sent
1779 #
Jakub Grajciar103ba6b2019-10-01 11:30:56 +02001780 Client = VppDHCPClient(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001781 self, vlan_100.sw_if_index, hostname, dscp=vdscp.IP_API_DSCP_EF
1782 )
Jakub Grajciar103ba6b2019-10-01 11:30:56 +02001783 Client.add_vpp_config()
Neale Ranns038e1df2019-07-19 14:01:02 +00001784
1785 rx = self.pg3.get_capture(1)
1786
1787 self.assertEqual(rx[0][Dot1Q].vlan, 100)
Prashant Maheshwari3bcf1a92019-07-31 21:37:33 +05301788 self.assertEqual(rx[0][Dot1Q].prio, 2)
Neale Ranns038e1df2019-07-19 14:01:02 +00001789
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001790 self.verify_orig_dhcp_discover(
1791 rx[0], self.pg3, hostname, dscp=vdscp.IP_API_DSCP_EF
1792 )
Neale Ranns038e1df2019-07-19 14:01:02 +00001793
Neale Ranns808c5b22017-08-02 05:15:07 -07001794
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001795if __name__ == "__main__":
Neale Rannsfca0c242017-01-13 07:57:46 -08001796 unittest.main(testRunner=VppTestRunner)