tests: Add support for getting corefile patterns on FreeBSD
[vpp.git] / test / test_ip6_nd_mirror_proxy.py
1 #!/usr/bin/env python3
2
3 import unittest
4 from socket import inet_pton, inet_ntop
5
6 from framework import VppTestCase
7 from asfframework import VppTestRunner
8
9 from vpp_ip import VppIpPuntRedirect
10
11 from scapy.layers.l2 import Ether
12 from scapy.layers.inet6 import (
13     IPv6,
14     ipv6nh,
15     ICMPv6ND_NS,
16     ICMPv6ND_NA,
17     ICMPv6NDOptSrcLLAddr,
18     ICMPv6NDOptDstLLAddr,
19     ICMPv6EchoRequest,
20     ICMPv6EchoReply,
21 )
22 from scapy.utils6 import in6_ptop, in6_getnsma, in6_getnsmac
23
24
25 class TestNDPROXY(VppTestCase):
26     """IP6 ND (mirror) Proxy Test Case"""
27
28     @classmethod
29     def setUpClass(self):
30         super(TestNDPROXY, self).setUpClass()
31         self.create_pg_interfaces(range(2))
32
33     @classmethod
34     def tearDownClass(self):
35         super(TestNDPROXY, self).tearDownClass()
36
37     def setUp(self):
38         super(TestNDPROXY, self).setUp()
39         for i in self.pg_interfaces:
40             i.admin_up()
41             i.config_ip6()
42             i.disable_ipv6_ra()
43
44     def tearDown(self):
45         super(TestNDPROXY, self).tearDown()
46         if not self.vpp_dead:
47             for i in self.pg_interfaces:
48                 i.unconfig_ip6()
49                 i.admin_down()
50
51     def test_nd_mirror_proxy(self):
52         """Interface (Mirror) Proxy ND"""
53
54         #
55         # When VPP has an interface whose address is also applied to a TAP
56         # interface on the host, then VPP's TAP interface will be unnumbered
57         # to the 'real' interface and do proxy ND from the host.
58         # the curious aspect of this setup is that ND requests from the host
59         # will come from the VPP's own address.
60         #
61         addr = self.pg0.remote_ip6
62         nsma = in6_getnsma(inet_pton(socket.AF_INET6, addr))
63         d = inet_ntop(socket.AF_INET6, nsma)
64
65         # Make pg1 un-numbered to pg0
66         #
67         self.pg1.unconfig_ip6()
68         self.pg1.set_unnumbered(self.pg0.sw_if_index)
69
70         #
71         # Enable ND proxy on pg1
72         #
73         self.vapi.ip6nd_proxy_enable_disable(
74             sw_if_index=self.pg1.sw_if_index, is_enable=1
75         )
76         #
77         # Send the ND request with an originating address that
78         # is VPP's own address
79         #
80         nd_req_from_host = (
81             Ether(src=self.pg1.remote_mac, dst=in6_getnsmac(nsma))
82             / IPv6(dst=d, src=self.pg0.local_ip6)
83             / ICMPv6ND_NS(tgt=addr)
84             / ICMPv6NDOptSrcLLAddr(lladdr=self.pg1.remote_mac)
85         )
86
87         rx = self.send_and_expect(self.pg1, [nd_req_from_host], self.pg1)
88         self.assertEqual(rx[0][Ether].src, self.pg1.local_mac)
89         self.assertEqual(rx[0][Ether].dst, self.pg1.remote_mac)
90         self.assertEqual(rx[0][IPv6].src, self.pg0.remote_ip6)
91         self.assertEqual(rx[0][IPv6].dst, self.pg0.local_ip6)
92         self.assertEqual(ipv6nh[rx[0][IPv6].nh], "ICMPv6")
93         self.assertEqual(rx[0][ICMPv6ND_NA].tgt, self.pg0.remote_ip6)
94         self.assertTrue(rx[0].haslayer(ICMPv6NDOptDstLLAddr))
95         self.assertEqual(rx[0][ICMPv6NDOptDstLLAddr].lladdr, self.pg1.local_mac)
96
97         #
98         # Send the unicast ND request
99         #
100         unicast_nd_req_from_host = (
101             Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
102             / IPv6(dst=self.pg0.remote_ip6, src=self.pg1.remote_ip6_ll)
103             / ICMPv6ND_NS(tgt=self.pg0.remote_ip6)
104             / ICMPv6NDOptSrcLLAddr(lladdr=self.pg1.remote_mac)
105         )
106
107         rx = self.send_and_expect(self.pg1, [unicast_nd_req_from_host], self.pg0)
108         self.assertEqual(rx[0][Ether].src, self.pg0.local_mac)
109         self.assertEqual(rx[0][Ether].dst, in6_getnsmac(nsma))
110         self.assertEqual(rx[0][IPv6].src, self.pg0.local_ip6_ll)
111         self.assertEqual(rx[0][IPv6].dst, d)
112         self.assertEqual(ipv6nh[rx[0][IPv6].nh], "ICMPv6")
113         self.assertEqual(rx[0][ICMPv6ND_NS].tgt, self.pg0.remote_ip6)
114         self.assertTrue(rx[0].haslayer(ICMPv6NDOptSrcLLAddr))
115         self.assertEqual(rx[0][ICMPv6NDOptSrcLLAddr].lladdr, self.pg0.local_mac)
116
117         # Resolve the NDs on the uplink
118         self.pg0.resolve_ndp()
119
120         #
121         # Again send the unicast ND request, this time dst address should be
122         # in local cache
123         #
124         rx = self.send_and_expect(self.pg1, [unicast_nd_req_from_host], self.pg1)
125         self.assertEqual(rx[0][Ether].src, self.pg1.local_mac)
126         self.assertEqual(rx[0][Ether].dst, self.pg1.remote_mac)
127         self.assertEqual(rx[0][IPv6].src, self.pg0.remote_ip6)
128         self.assertEqual(in6_ptop(rx[0][IPv6].dst), in6_ptop(self.pg1.remote_ip6_ll))
129         self.assertEqual(ipv6nh[rx[0][IPv6].nh], "ICMPv6")
130         self.assertEqual(rx[0][ICMPv6ND_NA].tgt, self.pg0.remote_ip6)
131         self.assertTrue(rx[0].haslayer(ICMPv6NDOptDstLLAddr))
132         self.assertEqual(rx[0][ICMPv6NDOptDstLLAddr].lladdr, self.pg1.local_mac)
133
134         #
135         # Send the Echo Request from host to remote (of uplink)
136         #
137         id = self.pg1.sw_if_index
138         seq = 0x1
139         echo_request = (
140             Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac)
141             / IPv6(dst=self.pg0.remote_ip6, src=self.pg0.local_ip6)
142             / ICMPv6EchoRequest(seq=seq, id=id)
143         )
144
145         rx = self.send_and_expect(self.pg1, [echo_request], self.pg0)
146         self.assertEqual(rx[0][Ether].src, self.pg0.local_mac)
147         self.assertEqual(rx[0][Ether].dst, self.pg0.remote_mac)
148         self.assertEqual(rx[0][IPv6].src, self.pg0.local_ip6)
149         self.assertEqual(rx[0][IPv6].dst, self.pg0.remote_ip6)
150         self.assertEqual(ipv6nh[rx[0][IPv6].nh], "ICMPv6")
151         self.assertTrue(rx[0].haslayer(ICMPv6EchoRequest))
152         self.assertEqual(rx[0][ICMPv6EchoRequest].id, id)
153         self.assertEqual(rx[0][ICMPv6EchoRequest].seq, seq)
154
155         #
156         # setup a punt redirect so packets from the uplink go to the tap
157         #
158         redirect = VppIpPuntRedirect(
159             self, self.pg0.sw_if_index, self.pg1.sw_if_index, self.pg0.local_ip6
160         )
161         redirect.add_vpp_config()
162
163         echo_reply = (
164             Ether(dst=self.pg0.remote_mac, src=self.pg0.local_mac)
165             / IPv6(dst=self.pg0.local_ip6, src=self.pg0.remote_ip6)
166             / ICMPv6EchoReply(seq=1, id=id)
167         )
168
169         rx = self.send_and_expect(self.pg0, [echo_reply], self.pg1)
170         self.assertEqual(rx[0][Ether].src, self.pg1.local_mac)
171         self.assertEqual(rx[0][Ether].dst, self.pg1.remote_mac)
172         self.assertEqual(rx[0][IPv6].src, self.pg0.remote_ip6)
173         self.assertEqual(rx[0][IPv6].dst, self.pg0.local_ip6)
174         self.assertEqual(ipv6nh[rx[0][IPv6].nh], "ICMPv6")
175         self.assertTrue(rx[0].haslayer(ICMPv6EchoReply))
176         self.assertEqual(rx[0][ICMPv6EchoReply].id, id)
177         self.assertEqual(rx[0][ICMPv6EchoReply].seq, seq)
178
179         #
180         # cleanup
181         #
182         self.vapi.ip6nd_proxy_enable_disable(
183             sw_if_index=self.pg1.sw_if_index, is_enable=0
184         )
185         redirect.remove_vpp_config()
186
187
188 if __name__ == "__main__":
189     unittest.main(testRunner=VppTestRunner)