2023-08-17 13:36:08 +02:00
|
|
|
#!/usr/bin/env python3
|
|
|
|
|
|
|
|
import unittest
|
|
|
|
import ipaddress
|
2023-08-31 00:47:44 -04:00
|
|
|
from framework import VppTestCase
|
|
|
|
from asfframework import VppTestRunner
|
2024-03-11 10:38:46 +00:00
|
|
|
from config import config
|
2023-08-17 13:36:08 +02:00
|
|
|
|
2023-10-12 18:54:55 +02:00
|
|
|
from scapy.layers.inet6 import IPv6, ICMPv6EchoRequest, ICMPv6DestUnreach
|
2023-08-17 13:36:08 +02:00
|
|
|
from scapy.layers.l2 import Ether
|
|
|
|
from scapy.packet import Raw
|
|
|
|
|
|
|
|
|
2024-03-11 10:38:46 +00:00
|
|
|
@unittest.skipIf("npt66" in config.excluded_plugins, "Exclude NPTv6 plugin tests")
|
2023-08-17 13:36:08 +02:00
|
|
|
class TestNPT66(VppTestCase):
|
|
|
|
"""NPTv6 Test Case"""
|
|
|
|
|
2023-09-01 14:18:23 +02:00
|
|
|
extra_vpp_plugin_config = [
|
|
|
|
"plugin npt66_plugin.so {enable}",
|
|
|
|
]
|
|
|
|
|
2023-08-17 13:36:08 +02:00
|
|
|
def setUp(self):
|
|
|
|
super(TestNPT66, self).setUp()
|
|
|
|
|
|
|
|
# create 2 pg interfaces
|
|
|
|
self.create_pg_interfaces(range(2))
|
|
|
|
|
|
|
|
for i in self.pg_interfaces:
|
|
|
|
i.admin_up()
|
|
|
|
i.config_ip6()
|
|
|
|
i.resolve_ndp()
|
|
|
|
|
|
|
|
def tearDown(self):
|
|
|
|
for i in self.pg_interfaces:
|
|
|
|
i.unconfig_ip6()
|
|
|
|
i.admin_down()
|
|
|
|
super(TestNPT66, self).tearDown()
|
|
|
|
|
2023-10-12 18:54:55 +02:00
|
|
|
def send_and_verify(self, internal, reply_icmp_error=False):
|
2023-09-01 14:15:39 +02:00
|
|
|
sendif = self.pg0
|
|
|
|
recvif = self.pg1
|
|
|
|
local_mac = self.pg0.local_mac
|
|
|
|
remote_mac = self.pg0.remote_mac
|
|
|
|
src = ipaddress.ip_interface(internal).ip + 1
|
|
|
|
dst = self.pg1.remote_ip6
|
2023-08-17 13:36:08 +02:00
|
|
|
|
|
|
|
p = (
|
|
|
|
Ether(dst=local_mac, src=remote_mac)
|
|
|
|
/ IPv6(src=src, dst=dst)
|
|
|
|
/ ICMPv6EchoRequest()
|
2023-09-01 14:15:39 +02:00
|
|
|
/ Raw(b"Request")
|
2023-08-17 13:36:08 +02:00
|
|
|
)
|
2023-10-12 18:54:55 +02:00
|
|
|
# print('Sending packet')
|
|
|
|
# p.show2()
|
2023-08-17 13:36:08 +02:00
|
|
|
rxs = self.send_and_expect(sendif, p, recvif)
|
|
|
|
for rx in rxs:
|
2023-10-12 18:54:55 +02:00
|
|
|
# print('Received packet')
|
|
|
|
# rx.show2()
|
2023-08-17 13:36:08 +02:00
|
|
|
original_cksum = rx[ICMPv6EchoRequest].cksum
|
|
|
|
del rx[ICMPv6EchoRequest].cksum
|
|
|
|
rx = rx.__class__(bytes(rx))
|
|
|
|
self.assertEqual(original_cksum, rx[ICMPv6EchoRequest].cksum)
|
|
|
|
|
2023-09-01 14:15:39 +02:00
|
|
|
# Generate a replies
|
2023-10-12 18:54:55 +02:00
|
|
|
if reply_icmp_error:
|
|
|
|
# print('Generating an ICMP error message')
|
|
|
|
reply = (
|
|
|
|
Ether(dst=rx[Ether].src, src=local_mac)
|
|
|
|
/ IPv6(src=rx[IPv6].dst, dst=rx[IPv6].src)
|
|
|
|
/ ICMPv6DestUnreach()
|
|
|
|
/ rx[IPv6]
|
|
|
|
)
|
|
|
|
# print('Sending ICMP error message reply')
|
|
|
|
# reply.show2()
|
|
|
|
replies = self.send_and_expect(recvif, reply, sendif)
|
|
|
|
for r in replies:
|
|
|
|
# print('Received ICMP error message reply on the other side')
|
|
|
|
# r.show2()
|
|
|
|
self.assertEqual(str(p[IPv6].src), r[IPv6].dst)
|
|
|
|
original_cksum = r[ICMPv6EchoRequest].cksum
|
|
|
|
del r[ICMPv6EchoRequest].cksum
|
|
|
|
r = r.__class__(bytes(r))
|
|
|
|
self.assertEqual(original_cksum, r[ICMPv6EchoRequest].cksum)
|
|
|
|
|
|
|
|
else:
|
|
|
|
reply = (
|
|
|
|
Ether(dst=rx[Ether].src, src=local_mac)
|
|
|
|
/ IPv6(src=rx[IPv6].dst, dst=rx[IPv6].src)
|
|
|
|
/ ICMPv6EchoRequest()
|
|
|
|
/ Raw(b"Reply")
|
|
|
|
)
|
|
|
|
|
|
|
|
replies = self.send_and_expect(recvif, reply, sendif)
|
|
|
|
for r in replies:
|
2023-10-30 17:05:23 -04:00
|
|
|
# r.show2()
|
2023-10-12 18:54:55 +02:00
|
|
|
self.assertEqual(str(p[IPv6].src), r[IPv6].dst)
|
|
|
|
original_cksum = r[ICMPv6EchoRequest].cksum
|
|
|
|
del r[ICMPv6EchoRequest].cksum
|
|
|
|
r = r.__class__(bytes(r))
|
|
|
|
self.assertEqual(original_cksum, r[ICMPv6EchoRequest].cksum)
|
|
|
|
|
|
|
|
def do_test(self, internal, external, reply_icmp_error=False):
|
|
|
|
"""Add NPT66 binding and send packet"""
|
2023-08-17 13:36:08 +02:00
|
|
|
self.vapi.npt66_binding_add_del(
|
|
|
|
sw_if_index=self.pg1.sw_if_index,
|
|
|
|
internal=internal,
|
|
|
|
external=external,
|
|
|
|
is_add=True,
|
|
|
|
)
|
2023-09-01 14:15:39 +02:00
|
|
|
## TODO use route api
|
2023-08-17 13:36:08 +02:00
|
|
|
self.vapi.cli(f"ip route add {internal} via {self.pg0.remote_ip6}")
|
|
|
|
|
2023-10-12 18:54:55 +02:00
|
|
|
self.send_and_verify(internal, reply_icmp_error=reply_icmp_error)
|
2023-08-17 13:36:08 +02:00
|
|
|
|
|
|
|
self.vapi.npt66_binding_add_del(
|
|
|
|
sw_if_index=self.pg1.sw_if_index,
|
|
|
|
internal=internal,
|
|
|
|
external=external,
|
|
|
|
is_add=False,
|
|
|
|
)
|
|
|
|
|
|
|
|
def test_npt66_simple(self):
|
|
|
|
"""Send and receive a packet through NPT66"""
|
|
|
|
|
2023-09-01 14:15:39 +02:00
|
|
|
self.do_test("fd00:0000:0000::/48", "2001:4650:c3ed::/48")
|
2023-08-17 13:36:08 +02:00
|
|
|
self.do_test("fc00:1::/48", "2001:db8:1::/48")
|
|
|
|
self.do_test("fc00:1234::/32", "2001:db8:1::/32")
|
|
|
|
self.do_test("fc00:1234::/63", "2001:db8:1::/56")
|
|
|
|
|
2023-10-12 18:54:55 +02:00
|
|
|
def test_npt66_icmp6(self):
|
|
|
|
"""Send and receive a packet through NPT66"""
|
|
|
|
|
|
|
|
# Test ICMP6 error packets
|
|
|
|
self.do_test(
|
|
|
|
"fd00:0000:0000::/48", "2001:4650:c3ed::/48", reply_icmp_error=True
|
|
|
|
)
|
|
|
|
self.do_test("fc00:1::/48", "2001:db8:1::/48", reply_icmp_error=True)
|
|
|
|
self.do_test("fc00:1234::/32", "2001:db8:1::/32", reply_icmp_error=True)
|
|
|
|
self.do_test("fc00:1234::/63", "2001:db8:1::/56", reply_icmp_error=True)
|
|
|
|
|
2023-08-17 13:36:08 +02:00
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
unittest.main(testRunner=VppTestRunner)
|