diff options
Diffstat (limited to 'test/test_dhcp.py')
-rw-r--r-- | test/test_dhcp.py | 739 |
1 files changed, 739 insertions, 0 deletions
diff --git a/test/test_dhcp.py b/test/test_dhcp.py new file mode 100644 index 00000000000..bdff679c6b2 --- /dev/null +++ b/test/test_dhcp.py @@ -0,0 +1,739 @@ +#!/usr/bin/env python + +import unittest +import socket + +from framework import VppTestCase, VppTestRunner +from vpp_ip_route import IpRoute, RoutePath +from vpp_lo_interface import VppLoInterface + +from scapy.layers.l2 import Ether, getmacbyip +from scapy.layers.inet import IP, UDP, ICMP +from scapy.layers.inet6 import IPv6, in6_getnsmac, in6_mactoifaceid +from scapy.layers.dhcp import DHCP, BOOTP, DHCPTypes +from scapy.layers.dhcp6 import DHCP6, DHCP6_Solicit, DHCP6_RelayForward, \ + DHCP6_RelayReply, DHCP6_Advertise, DHCP6OptRelayMsg, DHCP6OptIfaceId, \ + DHCP6OptStatusCode, DHCP6OptVSS, DHCP6OptClientLinkLayerAddr +from socket import AF_INET, AF_INET6 +from scapy.utils import inet_pton, inet_ntop +from scapy.utils6 import in6_ptop + +DHCP4_CLIENT_PORT = 68 +DHCP4_SERVER_PORT = 67 +DHCP6_CLIENT_PORT = 547 +DHCP6_SERVER_PORT = 546 + + +def mk_ll_addr(mac): + + euid = in6_mactoifaceid(mac) + addr = "fe80::" + euid + return addr + + +class TestDHCP(VppTestCase): + """ DHCP Test Case """ + + def setUp(self): + super(TestDHCP, self).setUp() + + # create 3 pg interfaces + self.create_pg_interfaces(range(4)) + + # pg0 and 1 are IP configured in VRF 0 and 1. + # pg2 and 3 are non IP-configured in VRF 0 and 1 + table_id = 0 + for i in self.pg_interfaces[:2]: + i.admin_up() + i.set_table_ip4(table_id) + i.set_table_ip6(table_id) + i.config_ip4() + i.resolve_arp() + i.config_ip6() + i.resolve_ndp() + table_id += 1 + + table_id = 0 + for i in self.pg_interfaces[2:]: + i.admin_up() + i.set_table_ip4(table_id) + i.set_table_ip6(table_id) + table_id += 1 + + def send_and_assert_no_replies(self, intf, pkts, remark): + intf.add_stream(pkts) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + for i in self.pg_interfaces: + i.assert_nothing_captured(remark=remark) + + def validate_option_82(self, pkt, intf, ip_addr): + dhcp = pkt[DHCP] + found = 0 + data = [] + + for i in dhcp.options: + if type(i) is tuple: + if i[0] == "relay_agent_Information": + # + # There are two sb-options present - each of length 6. + # + data = i[1] + self.assertEqual(len(data), 12) + + # + # First sub-option is ID 1, len 4, then encoded + # sw_if_index. This test uses low valued indicies + # so [2:4] are 0. + # The ID space is VPP internal - so no matching value + # scapy + # + self.assertEqual(ord(data[0]), 1) + self.assertEqual(ord(data[1]), 4) + self.assertEqual(ord(data[2]), 0) + self.assertEqual(ord(data[3]), 0) + self.assertEqual(ord(data[4]), 0) + self.assertEqual(ord(data[5]), intf._sw_if_index) + + # + # next sub-option is the IP address of the client side + # interface. + # sub-option ID=5, length (of a v4 address)=4 + # + claddr = socket.inet_pton(AF_INET, ip_addr) + + self.assertEqual(ord(data[6]), 5) + self.assertEqual(ord(data[7]), 4) + self.assertEqual(data[8], claddr[0]) + self.assertEqual(data[9], claddr[1]) + self.assertEqual(data[10], claddr[2]) + self.assertEqual(data[11], claddr[3]) + + found = 1 + self.assertTrue(found) + + return data + + def verify_dhcp_offer(self, pkt, intf, check_option_82=True): + ether = pkt[Ether] + self.assertEqual(ether.dst, "ff:ff:ff:ff:ff:ff") + self.assertEqual(ether.src, intf.local_mac) + + ip = pkt[IP] + self.assertEqual(ip.dst, "255.255.255.255") + self.assertEqual(ip.src, intf.local_ip4) + + udp = pkt[UDP] + self.assertEqual(udp.dport, DHCP4_CLIENT_PORT) + self.assertEqual(udp.sport, DHCP4_SERVER_PORT) + + dhcp = pkt[DHCP] + is_offer = False + for o in dhcp.options: + if type(o) is tuple: + if o[0] == "message-type" \ + and DHCPTypes[o[1]] == "offer": + is_offer = True + self.assertTrue(is_offer) + + if check_option_82: + data = self.validate_option_82(pkt, intf, intf.local_ip4) + + def verify_dhcp_discover(self, pkt, intf, src_intf=None, + option_82_present=True): + ether = pkt[Ether] + self.assertEqual(ether.dst, intf.remote_mac) + self.assertEqual(ether.src, intf.local_mac) + + ip = pkt[IP] + self.assertEqual(ip.dst, intf.remote_ip4) + self.assertEqual(ip.src, intf.local_ip4) + + udp = pkt[UDP] + self.assertEqual(udp.dport, DHCP4_SERVER_PORT) + self.assertEqual(udp.sport, DHCP4_CLIENT_PORT) + + dhcp = pkt[DHCP] + + is_discover = False + for o in dhcp.options: + if type(o) is tuple: + if o[0] == "message-type" \ + and DHCPTypes[o[1]] == "discover": + is_discover = True + self.assertTrue(is_discover) + + if option_82_present: + data = self.validate_option_82(pkt, src_intf, src_intf.local_ip4) + return data + else: + for i in dhcp.options: + if type(i) is tuple: + self.assertNotEqual(i[0], "relay_agent_Information") + + def verify_dhcp6_solicit(self, pkt, intf, + peer_ip, peer_mac, + fib_id=0, + oui=0): + ether = pkt[Ether] + self.assertEqual(ether.dst, intf.remote_mac) + self.assertEqual(ether.src, intf.local_mac) + + ip = pkt[IPv6] + self.assertEqual(in6_ptop(ip.dst), in6_ptop(intf.remote_ip6)) + self.assertEqual(in6_ptop(ip.src), in6_ptop(intf.local_ip6)) + + udp = pkt[UDP] + self.assertEqual(udp.dport, DHCP6_CLIENT_PORT) + self.assertEqual(udp.sport, DHCP6_SERVER_PORT) + + relay = pkt[DHCP6_RelayForward] + self.assertEqual(in6_ptop(relay.peeraddr), in6_ptop(peer_ip)) + oid = pkt[DHCP6OptIfaceId] + cll = pkt[DHCP6OptClientLinkLayerAddr] + self.assertEqual(cll.optlen, 8) + self.assertEqual(cll.lltype, 1) + self.assertEqual(cll.clladdr, peer_mac) + + vss = pkt[DHCP6OptVSS] + self.assertEqual(vss.optlen, 8) + self.assertEqual(vss.type, 1) + # the OUI and FIB-id are really 3 and 4 bytes resp. + # but the tested range is small + self.assertEqual(ord(vss.data[0]), 0) + self.assertEqual(ord(vss.data[1]), 0) + self.assertEqual(ord(vss.data[2]), oui) + self.assertEqual(ord(vss.data[3]), 0) + self.assertEqual(ord(vss.data[4]), 0) + self.assertEqual(ord(vss.data[5]), 0) + self.assertEqual(ord(vss.data[6]), fib_id) + + # the relay message should be an encoded Solicit + msg = pkt[DHCP6OptRelayMsg] + sol = DHCP6_Solicit() + self.assertEqual(msg.optlen, len(str(sol))) + self.assertEqual(str(sol), (str(msg[1]))[:msg.optlen]) + + def verify_dhcp6_advert(self, pkt, intf, peer): + ether = pkt[Ether] + self.assertEqual(ether.dst, "ff:ff:ff:ff:ff:ff") + self.assertEqual(ether.src, intf.local_mac) + + ip = pkt[IPv6] + self.assertEqual(in6_ptop(ip.dst), in6_ptop(peer)) + self.assertEqual(in6_ptop(ip.src), in6_ptop(intf.local_ip6)) + + udp = pkt[UDP] + self.assertEqual(udp.dport, DHCP6_SERVER_PORT) + self.assertEqual(udp.sport, DHCP6_CLIENT_PORT) + + # not sure why this is not decoding + # adv = pkt[DHCP6_Advertise] + + def test_dhcp_proxy(self): + """ DHCPv4 Proxy """ + + # + # Verify no response to DHCP request without DHCP config + # + p_disc_vrf0 = (Ether(dst="ff:ff:ff:ff:ff:ff", + src=self.pg2.remote_mac) / + IP(src="0.0.0.0", dst="255.255.255.255") / + UDP(sport=DHCP4_CLIENT_PORT, + dport=DHCP4_SERVER_PORT) / + BOOTP(op=1) / + DHCP(options=[('message-type', 'discover'), ('end')])) + pkts_disc_vrf0 = [p_disc_vrf0] + p_disc_vrf1 = (Ether(dst="ff:ff:ff:ff:ff:ff", + src=self.pg3.remote_mac) / + IP(src="0.0.0.0", dst="255.255.255.255") / + UDP(sport=DHCP4_CLIENT_PORT, + dport=DHCP4_SERVER_PORT) / + BOOTP(op=1) / + DHCP(options=[('message-type', 'discover'), ('end')])) + pkts_disc_vrf1 = [p_disc_vrf0] + + self.send_and_assert_no_replies(self.pg2, pkts_disc_vrf0, + "DHCP with no configuration") + self.send_and_assert_no_replies(self.pg3, pkts_disc_vrf1, + "DHCP with no configuration") + + # + # Enable DHCP proxy in VRF 0 + # + server_addr = self.pg0.remote_ip4n + src_addr = self.pg0.local_ip4n + + self.vapi.dhcp_proxy_config(server_addr, + src_addr, + rx_table_id=0) + + # + # Now a DHCP request on pg2, which is in the same VRF + # as the DHCP config, will result in a relayed DHCP + # message to the [fake] server + # + self.pg2.add_stream(pkts_disc_vrf0) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + + rx = self.pg0.get_capture(1) + rx = rx[0] + + # + # Rx'd packet should be to the server address and from the configured + # source address + # UDP source ports are unchanged + # we've no option 82 config so that should be absent + # + self.verify_dhcp_discover(rx, self.pg0, option_82_present=False) + + # + # Inject a response from the server + # VPP will only relay the offer if option 82 is present. + # so this one is dropped + # + p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / + IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) / + UDP(sport=DHCP4_SERVER_PORT, dport=DHCP4_SERVER_PORT) / + BOOTP(op=1) / + DHCP(options=[('message-type', 'offer'), ('end')])) + pkts = [p] + + self.send_and_assert_no_replies(self.pg0, pkts, + "DHCP offer no option 82") + + # + # Configure sending option 82 in relayed messages + # + self.vapi.dhcp_proxy_config(server_addr, + src_addr, + rx_table_id=0, + insert_circuit_id=1) + + # + # Send a request: + # again dropped, but ths time because there is no IP addrees on the + # clinet interfce to fill in the option. + # + self.send_and_assert_no_replies(self.pg2, pkts_disc_vrf0, + "DHCP no relay address") + + # + # configure an IP address on the client facing interface + # + self.pg2.config_ip4() + + # + # Try again with a discover packet + # Rx'd packet should be to the server address and from the configured + # source address + # UDP source ports are unchanged + # we've no option 82 config so that should be absent + # + self.pg2.add_stream(pkts_disc_vrf0) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + + rx = self.pg0.get_capture(1) + rx = rx[0] + + option_82 = self.verify_dhcp_discover(rx, self.pg0, src_intf=self.pg2) + + # + # Create an DHCP offer reply from the server with a correctly formatted + # option 82. i.e. send back what we just captured + # The offer, sent mcast to the client, still has option 82. + # + p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / + IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) / + UDP(sport=DHCP4_SERVER_PORT, dport=DHCP4_SERVER_PORT) / + BOOTP(op=1) / + DHCP(options=[('message-type', 'offer'), + ('relay_agent_Information', option_82), + ('end')])) + pkts = [p] + + self.pg0.add_stream(pkts) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + + rx = self.pg2.get_capture(1) + rx = rx[0] + + self.verify_dhcp_offer(rx, self.pg2) + + # + # Bogus Option 82: + # + # 1. not our IP address = not checked by VPP? so offer is replayed + # to client + bad_ip = option_82[0:8] + chr(33) + option_82[9:] + + p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / + IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) / + UDP(sport=DHCP4_SERVER_PORT, dport=DHCP4_SERVER_PORT) / + BOOTP(op=1) / + DHCP(options=[('message-type', 'offer'), + ('relay_agent_Information', bad_ip), + ('end')])) + pkts = [p] + + self.pg0.add_stream(pkts) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + rx = self.pg2.get_capture(1) + rx = rx[0] + + self.verify_dhcp_offer(rx, self.pg2, check_option_82=False) + self.pg0.assert_nothing_captured(remark="") + + # 2. Not a sw_if_index VPP knows + bad_if_index = option_82[0:2] + chr(33) + option_82[3:] + + p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / + IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) / + UDP(sport=DHCP4_SERVER_PORT, dport=DHCP4_SERVER_PORT) / + BOOTP(op=1) / + DHCP(options=[('message-type', 'offer'), + ('relay_agent_Information', bad_if_index), + ('end')])) + pkts = [p] + self.send_and_assert_no_replies(self.pg0, pkts, + "DHCP offer option 82 bad if index") + + # + # Send a DHCP request in VRF 1. should be dropped. + # + self.send_and_assert_no_replies(self.pg3, pkts_disc_vrf1, + "DHCP with no configuration VRF 1") + + # + # Delete the DHCP config in VRF 0 + # Should now drop requests. + # + self.vapi.dhcp_proxy_config(server_addr, + src_addr, + rx_table_id=0, + is_add=0, + insert_circuit_id=1) + + self.send_and_assert_no_replies(self.pg2, pkts_disc_vrf0, + "DHCP config removed VRF 0") + self.send_and_assert_no_replies(self.pg3, pkts_disc_vrf1, + "DHCP config removed VRF 1") + + # + # Add DHCP config for VRF 1 + # + server_addr = self.pg1.remote_ip4n + src_addr = self.pg1.local_ip4n + self.vapi.dhcp_proxy_config(server_addr, + src_addr, + rx_table_id=1, + server_table_id=1, + insert_circuit_id=1) + + # + # Confim DHCP requests ok in VRF 1. + # - dropped on IP config on client interface + # + self.send_and_assert_no_replies(self.pg3, pkts_disc_vrf1, + "DHCP config removed VRF 1") + + # + # configure an IP address on the client facing interface + # + self.pg3.config_ip4() + + self.pg3.add_stream(pkts_disc_vrf1) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + + rx = self.pg1.get_capture(1) + rx = rx[0] + self.verify_dhcp_discover(rx, self.pg1, src_intf=self.pg3) + + # + # remove DHCP config to cleanup + # + self.vapi.dhcp_proxy_config(server_addr, + src_addr, + rx_table_id=1, + server_table_id=1, + insert_circuit_id=1, + is_add=0) + + self.send_and_assert_no_replies(self.pg2, pkts_disc_vrf0, + "DHCP cleanup VRF 0") + self.send_and_assert_no_replies(self.pg3, pkts_disc_vrf1, + "DHCP cleanup VRF 1") + + def test_dhcp6_proxy(self): + """ DHCPv6 Proxy""" + # + # Verify no response to DHCP request without DHCP config + # + dhcp_solicit_dst = "ff02::1:2" + dhcp_solicit_src_vrf0 = mk_ll_addr(self.pg2.remote_mac) + dhcp_solicit_src_vrf1 = mk_ll_addr(self.pg3.remote_mac) + server_addr_vrf0 = self.pg0.remote_ip6n + src_addr_vrf0 = self.pg0.local_ip6n + server_addr_vrf1 = self.pg1.remote_ip6n + src_addr_vrf1 = self.pg1.local_ip6n + + # + # Add the Route to receive the DHCP packets + # + route_dhcp_vrf0 = IpRoute(self, dhcp_solicit_dst, 128, + [], is_local=1, is_ip6=1) + route_dhcp_vrf0.add_vpp_config() + route_dhcp_vrf1 = IpRoute(self, dhcp_solicit_dst, 128, + [], is_local=1, is_ip6=1, + table_id=1) + route_dhcp_vrf1.add_vpp_config() + + dmac = in6_getnsmac(inet_pton(socket.AF_INET6, dhcp_solicit_dst)) + p_solicit_vrf0 = (Ether(dst=dmac, src=self.pg2.remote_mac) / + IPv6(src=dhcp_solicit_src_vrf0, + dst=dhcp_solicit_dst) / + UDP(sport=DHCP6_SERVER_PORT, + dport=DHCP6_CLIENT_PORT) / + DHCP6_Solicit()) + pkts_solicit_vrf0 = [p_solicit_vrf0] + p_solicit_vrf1 = (Ether(dst=dmac, src=self.pg3.remote_mac) / + IPv6(src=dhcp_solicit_src_vrf1, + dst=dhcp_solicit_dst) / + UDP(sport=DHCP6_SERVER_PORT, + dport=DHCP6_CLIENT_PORT) / + DHCP6_Solicit()) + pkts_solicit_vrf1 = [p_solicit_vrf1] + + self.send_and_assert_no_replies(self.pg2, pkts_solicit_vrf0, + "DHCP with no configuration") + self.send_and_assert_no_replies(self.pg3, pkts_solicit_vrf1, + "DHCP with no configuration") + + # + # DHCPv6 config in VRF 0. + # Packets still dropped because the client facing interface has no + # IPv6 config + # + self.vapi.dhcp_proxy_config(server_addr_vrf0, + src_addr_vrf0, + rx_table_id=0, + server_table_id=0, + insert_circuit_id=1, + is_ipv6=1) + + self.send_and_assert_no_replies(self.pg2, pkts_solicit_vrf0, + "DHCP with no configuration") + self.send_and_assert_no_replies(self.pg3, pkts_solicit_vrf1, + "DHCP with no configuration") + + # + # configure an IP address on the client facing interface + # + self.pg2.config_ip6() + + # + # Now the DHCP requests are relayed to the server + # + self.pg2.add_stream(pkts_solicit_vrf0) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + + rx = self.pg0.get_capture(1) + rx = rx[0] + self.verify_dhcp6_solicit(rx, self.pg0, + dhcp_solicit_src_vrf0, + self.pg2.remote_mac) + + # + # Exception cases for rejected relay responses + # + + # 1 - not a relay reply + p_adv_vrf0 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / + IPv6(dst=self.pg0.local_ip6, src=self.pg0.remote_ip6) / + UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_SERVER_PORT) / + DHCP6_Advertise()) + pkts_adv_vrf0 = [p_adv_vrf0] + self.send_and_assert_no_replies(self.pg2, pkts_adv_vrf0, + "DHCP6 not a relay reply") + + # 2 - no relay message option + p_adv_vrf0 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / + IPv6(dst=self.pg0.local_ip6, src=self.pg0.remote_ip6) / + UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_SERVER_PORT) / + DHCP6_RelayReply() / + DHCP6_Advertise()) + pkts_adv_vrf0 = [p_adv_vrf0] + self.send_and_assert_no_replies(self.pg2, pkts_adv_vrf0, + "DHCP not a relay message") + + # 3 - no circuit ID + p_adv_vrf0 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / + IPv6(dst=self.pg0.local_ip6, src=self.pg0.remote_ip6) / + UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_SERVER_PORT) / + DHCP6_RelayReply() / + DHCP6OptRelayMsg(optlen=0) / + DHCP6_Advertise()) + pkts_adv_vrf0 = [p_adv_vrf0] + self.send_and_assert_no_replies(self.pg2, pkts_adv_vrf0, + "DHCP6 no circuit ID") + # 4 - wrong circuit ID + p_adv_vrf0 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / + IPv6(dst=self.pg0.local_ip6, src=self.pg0.remote_ip6) / + UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_SERVER_PORT) / + DHCP6_RelayReply() / + DHCP6OptIfaceId(optlen=4, ifaceid='\x00\x00\x00\x05') / + DHCP6OptRelayMsg(optlen=0) / + DHCP6_Advertise()) + pkts_adv_vrf0 = [p_adv_vrf0] + self.send_and_assert_no_replies(self.pg2, pkts_adv_vrf0, + "DHCP6 wrong circuit ID") + + # + # Send the relay response (the advertisement) + # - no peer address + p_adv_vrf0 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / + IPv6(dst=self.pg0.local_ip6, src=self.pg0.remote_ip6) / + UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_SERVER_PORT) / + DHCP6_RelayReply() / + DHCP6OptIfaceId(optlen=4, ifaceid='\x00\x00\x00\x03') / + DHCP6OptRelayMsg(optlen=0) / + DHCP6_Advertise(trid=1) / + DHCP6OptStatusCode(statuscode=0)) + pkts_adv_vrf0 = [p_adv_vrf0] + + self.pg0.add_stream(pkts_adv_vrf0) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + + rx = self.pg2.get_capture(1) + rx = rx[0] + self.verify_dhcp6_advert(rx, self.pg2, "::") + + # + # Send the relay response (the advertisement) + # - with peer address + p_adv_vrf0 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / + IPv6(dst=self.pg0.local_ip6, src=self.pg0.remote_ip6) / + UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_SERVER_PORT) / + DHCP6_RelayReply(peeraddr=dhcp_solicit_src_vrf0) / + DHCP6OptIfaceId(optlen=4, ifaceid='\x00\x00\x00\x03') / + DHCP6OptRelayMsg(optlen=0) / + DHCP6_Advertise(trid=1) / + DHCP6OptStatusCode(statuscode=0)) + pkts_adv_vrf0 = [p_adv_vrf0] + + self.pg0.add_stream(pkts_adv_vrf0) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + + rx = self.pg2.get_capture(1) + rx = rx[0] + self.verify_dhcp6_advert(rx, self.pg2, dhcp_solicit_src_vrf0) + + # + # Add all the config for VRF 1 + # + self.vapi.dhcp_proxy_config(server_addr_vrf1, + src_addr_vrf1, + rx_table_id=1, + server_table_id=1, + insert_circuit_id=1, + is_ipv6=1) + self.pg3.config_ip6() + + # + # VRF 1 solicit + # + self.pg3.add_stream(pkts_solicit_vrf1) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + + rx = self.pg1.get_capture(1) + rx = rx[0] + self.verify_dhcp6_solicit(rx, self.pg1, + dhcp_solicit_src_vrf1, + self.pg3.remote_mac) + + # + # VRF 1 Advert + # + p_adv_vrf1 = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / + IPv6(dst=self.pg1.local_ip6, src=self.pg1.remote_ip6) / + UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_SERVER_PORT) / + DHCP6_RelayReply(peeraddr=dhcp_solicit_src_vrf1) / + DHCP6OptIfaceId(optlen=4, ifaceid='\x00\x00\x00\x04') / + DHCP6OptRelayMsg(optlen=0) / + DHCP6_Advertise(trid=1) / + DHCP6OptStatusCode(statuscode=0)) + pkts_adv_vrf1 = [p_adv_vrf1] + + self.pg1.add_stream(pkts_adv_vrf1) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + + rx = self.pg3.get_capture(1) + rx = rx[0] + self.verify_dhcp6_advert(rx, self.pg3, dhcp_solicit_src_vrf1) + + # + # Add VSS config + # table=1, fib=id=1, oui=4 + self.vapi.dhcp_proxy_set_vss(1, 1, 4, is_ip6=1) + + self.pg3.add_stream(pkts_solicit_vrf1) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + + rx = self.pg1.get_capture(1) + rx = rx[0] + self.verify_dhcp6_solicit(rx, self.pg1, + dhcp_solicit_src_vrf1, + self.pg3.remote_mac, + fib_id=1, + oui=4) + + # + # Remove the VSS config + # relayed DHCP has default vlaues in the option. + # + self.vapi.dhcp_proxy_set_vss(1, 1, 4, is_ip6=1, is_add=0) + + self.pg3.add_stream(pkts_solicit_vrf1) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + + rx = self.pg1.get_capture(1) + rx = rx[0] + self.verify_dhcp6_solicit(rx, self.pg1, + dhcp_solicit_src_vrf1, + self.pg3.remote_mac) + + # + # Cleanup + # + self.vapi.dhcp_proxy_config(server_addr_vrf1, + src_addr_vrf1, + rx_table_id=1, + server_table_id=1, + insert_circuit_id=1, + is_ipv6=1, + is_add=0) + self.vapi.dhcp_proxy_config(server_addr_vrf1, + src_addr_vrf1, + rx_table_id=0, + server_table_id=0, + insert_circuit_id=1, + is_ipv6=1, + is_add=0) + + route_dhcp_vrf0.remove_vpp_config() + route_dhcp_vrf1.remove_vpp_config() + +if __name__ == '__main__': + unittest.main(testRunner=VppTestRunner) |