#!/usr/bin/env python
import unittest
-from socket import AF_INET6
+import socket
from framework import VppTestCase, VppTestRunner
+from util import ppp, ip6_normalize
from vpp_sub_interface import VppSubInterface, VppDot1QSubint
from vpp_pg_interface import is_ipv6_misc
from vpp_ip_route import VppIpRoute, VppRoutePath, find_route, VppIpMRoute, \
VppMRoutePath, MRouteItfFlags, MRouteEntryFlags, VppMplsIpBind, \
- VppMplsRoute, DpoProto, VppMplsTable
+ VppMplsRoute, DpoProto, VppMplsTable, VppIpTable
from vpp_neighbor import find_nbr, VppNeighbor
from scapy.packet import Raw
from scapy.layers.l2 import Ether, Dot1Q
-from scapy.layers.inet6 import IPv6, UDP, ICMPv6ND_NS, ICMPv6ND_RS, \
+from scapy.layers.inet6 import IPv6, UDP, TCP, ICMPv6ND_NS, ICMPv6ND_RS, \
ICMPv6ND_RA, ICMPv6NDOptSrcLLAddr, getmacbyip6, ICMPv6MRD_Solicitation, \
ICMPv6NDOptMTU, ICMPv6NDOptSrcLLAddr, ICMPv6NDOptPrefixInfo, \
- ICMPv6ND_NA, ICMPv6NDOptDstLLAddr, ICMPv6DestUnreach, icmp6types
-
-from util import ppp
+ ICMPv6ND_NA, ICMPv6NDOptDstLLAddr, ICMPv6DestUnreach, icmp6types, \
+ ICMPv6TimeExceeded, ICMPv6EchoRequest, ICMPv6EchoReply
from scapy.utils6 import in6_getnsma, in6_getnsmac, in6_ptop, in6_islladdr, \
in6_mactoifaceid, in6_ismaddr
from scapy.utils import inet_pton, inet_ntop
from scapy.contrib.mpls import MPLS
+AF_INET6 = socket.AF_INET6
+
+
def mk_ll_addr(mac):
euid = in6_mactoifaceid(mac)
addr = "fe80::" + euid
dst_ip = inet_ntop(AF_INET6, nsma)
# NS is broadcast
- self.assertEqual(rx[Ether].dst, "ff:ff:ff:ff:ff:ff")
+ self.assertEqual(rx[Ether].dst, in6_getnsmac(nsma))
# and from the router's MAC
self.assertEqual(rx[Ether].src, intf.local_mac)
rx = rx[0]
self.validate_ns(rx_intf, rx, tgt_ip)
- 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.get_capture(0)
- i.assert_nothing_captured(remark=remark)
-
def verify_ip(self, rx, smac, dmac, sip, dip):
ether = rx[Ether]
self.assertEqual(ether.dst, dmac)
:ivar list interfaces: pg interfaces and subinterfaces.
:ivar dict flows: IPv4 packet flows in test.
- :ivar list pg_if_packet_sizes: packet sizes in test.
*TODO:* Create AD sub interface
"""
self.flows[self.pg2.sub_if] = [self.pg0, self.pg1.sub_if]
# packet sizes
- self.pg_if_packet_sizes = [64, 512, 1518, 9018]
- self.sub_if_packet_sizes = [64, 512, 1518 + 4, 9018 + 4]
+ self.pg_if_packet_sizes = [64, 1500, 9020]
self.interfaces = list(self.pg_interfaces)
self.interfaces.extend(self.sub_interfaces)
def tearDown(self):
"""Run standard test teardown and log ``show ip6 neighbors``."""
- for i in self.sub_interfaces:
+ for i in self.interfaces:
i.unconfig_ip6()
i.ip6_disable()
i.admin_down()
+ for i in self.sub_interfaces:
i.remove_vpp_config()
super(TestIPv6, self).tearDown()
(count, percent))
percent += 1
- def create_stream(self, src_if, packet_sizes):
+ def modify_packet(self, src_if, packet_size, pkt):
+ """Add load, set destination IP and extend packet to required packet
+ size for defined interface.
+
+ :param VppInterface src_if: Interface to create packet for.
+ :param int packet_size: Required packet size.
+ :param Scapy pkt: Packet to be modified.
+ """
+ dst_if_idx = packet_size / 10 % 2
+ dst_if = self.flows[src_if][dst_if_idx]
+ info = self.create_packet_info(src_if, dst_if)
+ payload = self.info_to_payload(info)
+ p = pkt/Raw(payload)
+ p[IPv6].dst = dst_if.remote_ip6
+ info.data = p.copy()
+ if isinstance(src_if, VppSubInterface):
+ p = src_if.add_dot1_layer(p)
+ self.extend_packet(p, packet_size)
+
+ return p
+
+ def create_stream(self, src_if):
"""Create input packet stream for defined interface.
:param VppInterface src_if: Interface to create packet stream for.
- :param list packet_sizes: Required packet sizes.
"""
- pkts = []
- for i in range(0, 257):
- dst_if = self.flows[src_if][i % 2]
- info = self.create_packet_info(src_if, dst_if)
- payload = self.info_to_payload(info)
- p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
- IPv6(src=src_if.remote_ip6, dst=dst_if.remote_ip6) /
- UDP(sport=1234, dport=1234) /
- Raw(payload))
- info.data = p.copy()
- if isinstance(src_if, VppSubInterface):
- p = src_if.add_dot1_layer(p)
- size = packet_sizes[(i // 2) % len(packet_sizes)]
- self.extend_packet(p, size)
- pkts.append(p)
+ hdr_ext = 4 if isinstance(src_if, VppSubInterface) else 0
+ pkt_tmpl = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
+ IPv6(src=src_if.remote_ip6) /
+ UDP(sport=1234, dport=1234))
+
+ pkts = [self.modify_packet(src_if, i, pkt_tmpl)
+ for i in xrange(self.pg_if_packet_sizes[0],
+ self.pg_if_packet_sizes[1], 10)]
+ pkts_b = [self.modify_packet(src_if, i, pkt_tmpl)
+ for i in xrange(self.pg_if_packet_sizes[1] + hdr_ext,
+ self.pg_if_packet_sizes[2] + hdr_ext, 50)]
+ pkts.extend(pkts_b)
+
return pkts
def verify_capture(self, dst_if, capture):
- Send and verify received packets on each interface.
"""
- pkts = self.create_stream(self.pg0, self.pg_if_packet_sizes)
+ pkts = self.create_stream(self.pg0)
self.pg0.add_stream(pkts)
for i in self.sub_interfaces:
- pkts = self.create_stream(i, self.sub_if_packet_sizes)
+ pkts = self.create_stream(i)
i.parent.add_stream(pkts)
self.pg_enable_capture(self.pg_interfaces)
self.pg0.ip6_ra_config(no=1, suppress=1, send_unicast=0)
+class TestICMPv6Echo(VppTestCase):
+ """ ICMPv6 Echo Test Case """
+
+ def setUp(self):
+ super(TestICMPv6Echo, self).setUp()
+
+ # create 1 pg interface
+ self.create_pg_interfaces(range(1))
+
+ for i in self.pg_interfaces:
+ i.admin_up()
+ i.config_ip6()
+ i.resolve_ndp()
+
+ def tearDown(self):
+ super(TestICMPv6Echo, self).tearDown()
+ for i in self.pg_interfaces:
+ i.unconfig_ip6()
+ i.ip6_disable()
+ i.admin_down()
+
+ def test_icmpv6_echo(self):
+ """ VPP replies to ICMPv6 Echo Request
+
+ Test scenario:
+
+ - Receive ICMPv6 Echo Request message on pg0 interface.
+ - Check outgoing ICMPv6 Echo Reply message on pg0 interface.
+ """
+
+ icmpv6_id = 0xb
+ icmpv6_seq = 5
+ icmpv6_data = '\x0a' * 18
+ p_echo_request = (Ether(src=self.pg0.remote_mac,
+ dst=self.pg0.local_mac) /
+ IPv6(src=self.pg0.remote_ip6,
+ dst=self.pg0.local_ip6) /
+ ICMPv6EchoRequest(id=icmpv6_id, seq=icmpv6_seq,
+ data=icmpv6_data))
+
+ self.pg0.add_stream(p_echo_request)
+ self.pg_enable_capture(self.pg_interfaces)
+ self.pg_start()
+
+ rx = self.pg0.get_capture(1)
+ rx = rx[0]
+ ether = rx[Ether]
+ ipv6 = rx[IPv6]
+ icmpv6 = rx[ICMPv6EchoReply]
+
+ self.assertEqual(ether.src, self.pg0.local_mac)
+ self.assertEqual(ether.dst, self.pg0.remote_mac)
+
+ self.assertEqual(ipv6.src, self.pg0.local_ip6)
+ self.assertEqual(ipv6.dst, self.pg0.remote_ip6)
+
+ self.assertEqual(icmp6types[icmpv6.type], "Echo Reply")
+ self.assertEqual(icmpv6.id, icmpv6_id)
+ self.assertEqual(icmpv6.seq, icmpv6_seq)
+ self.assertEqual(icmpv6.data, icmpv6_data)
+
+
+class TestIPv6RD(TestIPv6ND):
+ """ IPv6 Router Discovery Test Case """
+
+ @classmethod
+ def setUpClass(cls):
+ super(TestIPv6RD, cls).setUpClass()
+
+ def setUp(self):
+ super(TestIPv6RD, self).setUp()
+
+ # create 2 pg interfaces
+ self.create_pg_interfaces(range(2))
+
+ self.interfaces = list(self.pg_interfaces)
+
+ # setup all interfaces
+ for i in self.interfaces:
+ i.admin_up()
+ i.config_ip6()
+
+ def tearDown(self):
+ for i in self.interfaces:
+ i.unconfig_ip6()
+ i.admin_down()
+ super(TestIPv6RD, self).tearDown()
+
+ def test_rd_send_router_solicitation(self):
+ """ Verify router solicitation packets """
+
+ count = 2
+ self.pg_enable_capture(self.pg_interfaces)
+ self.pg_start()
+ self.vapi.ip6nd_send_router_solicitation(self.pg1.sw_if_index,
+ mrc=count)
+ rx_list = self.pg1.get_capture(count, timeout=3)
+ self.assertEqual(len(rx_list), count)
+ for packet in rx_list:
+ self.assertTrue(packet.haslayer(IPv6))
+ self.assertTrue(packet[IPv6].haslayer(ICMPv6ND_RS))
+ dst = ip6_normalize(packet[IPv6].dst)
+ dst2 = ip6_normalize("ff02::2")
+ self.assert_equal(dst, dst2)
+ src = ip6_normalize(packet[IPv6].src)
+ src2 = ip6_normalize(self.pg1.local_ip6_ll)
+ self.assert_equal(src, src2)
+ self.assertTrue(packet[ICMPv6ND_RS].haslayer(ICMPv6NDOptSrcLLAddr))
+ self.assert_equal(packet[ICMPv6NDOptSrcLLAddr].lladdr,
+ self.pg1.local_mac)
+
+ def verify_prefix_info(self, reported_prefix, prefix_option):
+ prefix = socket.inet_pton(socket.AF_INET6,
+ prefix_option.getfieldval("prefix"))
+ self.assert_equal(reported_prefix.dst_address, prefix)
+ self.assert_equal(reported_prefix.dst_address_length,
+ prefix_option.getfieldval("prefixlen"))
+ L = prefix_option.getfieldval("L")
+ A = prefix_option.getfieldval("A")
+ option_flags = (L << 7) | (A << 6)
+ self.assert_equal(reported_prefix.flags, option_flags)
+ self.assert_equal(reported_prefix.valid_time,
+ prefix_option.getfieldval("validlifetime"))
+ self.assert_equal(reported_prefix.preferred_time,
+ prefix_option.getfieldval("preferredlifetime"))
+
+ def test_rd_receive_router_advertisement(self):
+ """ Verify events triggered by received RA packets """
+
+ self.vapi.want_ip6_ra_events()
+
+ prefix_info_1 = ICMPv6NDOptPrefixInfo(
+ prefix="1::2",
+ prefixlen=50,
+ validlifetime=200,
+ preferredlifetime=500,
+ L=1,
+ A=1,
+ )
+
+ prefix_info_2 = ICMPv6NDOptPrefixInfo(
+ prefix="7::4",
+ prefixlen=20,
+ validlifetime=70,
+ preferredlifetime=1000,
+ L=1,
+ A=0,
+ )
+
+ p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
+ IPv6(dst=self.pg1.local_ip6_ll,
+ src=mk_ll_addr(self.pg1.remote_mac)) /
+ ICMPv6ND_RA() /
+ prefix_info_1 /
+ prefix_info_2)
+ self.pg1.add_stream([p])
+ self.pg_start()
+
+ ev = self.vapi.wait_for_event(10, "ip6_ra_event")
+
+ self.assert_equal(ev.current_hop_limit, 0)
+ self.assert_equal(ev.flags, 8)
+ self.assert_equal(ev.router_lifetime_in_sec, 1800)
+ self.assert_equal(ev.neighbor_reachable_time_in_msec, 0)
+ self.assert_equal(
+ ev.time_in_msec_between_retransmitted_neighbor_solicitations, 0)
+
+ self.assert_equal(ev.n_prefixes, 2)
+
+ self.verify_prefix_info(ev.prefixes[0], prefix_info_1)
+ self.verify_prefix_info(ev.prefixes[1], prefix_info_2)
+
+
+class TestIPv6RDControlPlane(TestIPv6ND):
+ """ IPv6 Router Discovery Control Plane Test Case """
+
+ @classmethod
+ def setUpClass(cls):
+ super(TestIPv6RDControlPlane, cls).setUpClass()
+
+ def setUp(self):
+ super(TestIPv6RDControlPlane, self).setUp()
+
+ # create 1 pg interface
+ self.create_pg_interfaces(range(1))
+
+ self.interfaces = list(self.pg_interfaces)
+
+ # setup all interfaces
+ for i in self.interfaces:
+ i.admin_up()
+ i.config_ip6()
+
+ def tearDown(self):
+ super(TestIPv6RDControlPlane, self).tearDown()
+
+ @staticmethod
+ def create_ra_packet(pg, routerlifetime=None):
+ src_ip = pg.remote_ip6_ll
+ dst_ip = pg.local_ip6
+ if routerlifetime is not None:
+ ra = ICMPv6ND_RA(routerlifetime=routerlifetime)
+ else:
+ ra = ICMPv6ND_RA()
+ p = (Ether(dst=pg.local_mac, src=pg.remote_mac) /
+ IPv6(dst=dst_ip, src=src_ip) / ra)
+ return p
+
+ @staticmethod
+ def get_default_routes(fib):
+ list = []
+ for entry in fib:
+ if entry.address_length == 0:
+ for path in entry.path:
+ if path.sw_if_index != 0xFFFFFFFF:
+ defaut_route = {}
+ defaut_route['sw_if_index'] = path.sw_if_index
+ defaut_route['next_hop'] = path.next_hop
+ list.append(defaut_route)
+ return list
+
+ @staticmethod
+ def get_interface_addresses(fib, pg):
+ list = []
+ for entry in fib:
+ if entry.address_length == 128:
+ path = entry.path[0]
+ if path.sw_if_index == pg.sw_if_index:
+ list.append(entry.address)
+ return list
+
+ def test_all(self):
+ """ Test handling of SLAAC addresses and default routes """
+
+ fib = self.vapi.ip6_fib_dump()
+ default_routes = self.get_default_routes(fib)
+ initial_addresses = set(self.get_interface_addresses(fib, self.pg0))
+ self.assertEqual(default_routes, [])
+ router_address = self.pg0.remote_ip6n_ll
+
+ self.vapi.ip6_nd_address_autoconfig(self.pg0.sw_if_index, 1, 1)
+
+ self.sleep(0.1)
+
+ # send RA
+ packet = (self.create_ra_packet(self.pg0) / ICMPv6NDOptPrefixInfo(
+ prefix="1::",
+ prefixlen=64,
+ validlifetime=2,
+ preferredlifetime=2,
+ L=1,
+ A=1,
+ ) / ICMPv6NDOptPrefixInfo(
+ prefix="7::",
+ prefixlen=20,
+ validlifetime=1500,
+ preferredlifetime=1000,
+ L=1,
+ A=0,
+ ))
+ self.pg0.add_stream([packet])
+ self.pg_start()
+
+ self.sleep(0.1)
+
+ fib = self.vapi.ip6_fib_dump()
+
+ # check FIB for new address
+ addresses = set(self.get_interface_addresses(fib, self.pg0))
+ new_addresses = addresses.difference(initial_addresses)
+ self.assertEqual(len(new_addresses), 1)
+ prefix = list(new_addresses)[0][:8] + '\0\0\0\0\0\0\0\0'
+ self.assertEqual(inet_ntop(AF_INET6, prefix), '1::')
+
+ # check FIB for new default route
+ default_routes = self.get_default_routes(fib)
+ self.assertEqual(len(default_routes), 1)
+ dr = default_routes[0]
+ self.assertEqual(dr['sw_if_index'], self.pg0.sw_if_index)
+ self.assertEqual(dr['next_hop'], router_address)
+
+ # send RA to delete default route
+ packet = self.create_ra_packet(self.pg0, routerlifetime=0)
+ self.pg0.add_stream([packet])
+ self.pg_start()
+
+ self.sleep(0.1)
+
+ # check that default route is deleted
+ fib = self.vapi.ip6_fib_dump()
+ default_routes = self.get_default_routes(fib)
+ self.assertEqual(len(default_routes), 0)
+
+ self.sleep(0.1)
+
+ # send RA
+ packet = self.create_ra_packet(self.pg0)
+ self.pg0.add_stream([packet])
+ self.pg_start()
+
+ self.sleep(0.1)
+
+ # check FIB for new default route
+ fib = self.vapi.ip6_fib_dump()
+ default_routes = self.get_default_routes(fib)
+ self.assertEqual(len(default_routes), 1)
+ dr = default_routes[0]
+ self.assertEqual(dr['sw_if_index'], self.pg0.sw_if_index)
+ self.assertEqual(dr['next_hop'], router_address)
+
+ # send RA, updating router lifetime to 1s
+ packet = self.create_ra_packet(self.pg0, 1)
+ self.pg0.add_stream([packet])
+ self.pg_start()
+
+ self.sleep(0.1)
+
+ # check that default route still exists
+ fib = self.vapi.ip6_fib_dump()
+ default_routes = self.get_default_routes(fib)
+ self.assertEqual(len(default_routes), 1)
+ dr = default_routes[0]
+ self.assertEqual(dr['sw_if_index'], self.pg0.sw_if_index)
+ self.assertEqual(dr['next_hop'], router_address)
+
+ self.sleep(1)
+
+ # check that default route is deleted
+ fib = self.vapi.ip6_fib_dump()
+ default_routes = self.get_default_routes(fib)
+ self.assertEqual(len(default_routes), 0)
+
+ # check FIB still contains the SLAAC address
+ addresses = set(self.get_interface_addresses(fib, self.pg0))
+ new_addresses = addresses.difference(initial_addresses)
+ self.assertEqual(len(new_addresses), 1)
+ prefix = list(new_addresses)[0][:8] + '\0\0\0\0\0\0\0\0'
+ self.assertEqual(inet_ntop(AF_INET6, prefix), '1::')
+
+ self.sleep(1)
+
+ # check that SLAAC address is deleted
+ fib = self.vapi.ip6_fib_dump()
+ addresses = set(self.get_interface_addresses(fib, self.pg0))
+ new_addresses = addresses.difference(initial_addresses)
+ self.assertEqual(len(new_addresses), 0)
+
+
class IPv6NDProxyTest(TestIPv6ND):
""" IPv6 ND ProxyTest Case """
i.unconfig_ip4()
i.admin_down()
- 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.get_capture(0)
- i.assert_nothing_captured(remark=remark)
-
def test_ip_disabled(self):
""" IP Disabled """
super(TestIP6LoadBalance, self).tearDown()
def send_and_expect_load_balancing(self, input, pkts, outputs):
+ self.vapi.cli("clear trace")
input.add_stream(pkts)
self.pg_enable_capture(self.pg_interfaces)
self.pg_start()
self.assertNotEqual(0, len(rx))
def send_and_expect_one_itf(self, input, pkts, itf):
+ self.vapi.cli("clear trace")
input.add_stream(pkts)
self.pg_enable_capture(self.pg_interfaces)
self.pg_start()
self.send_and_expect_one_itf(self.pg0, port_pkts, self.pg3)
+class TestIP6Punt(VppTestCase):
+ """ IPv6 Punt Police/Redirect """
+
+ def setUp(self):
+ super(TestIP6Punt, self).setUp()
+
+ self.create_pg_interfaces(range(2))
+
+ for i in self.pg_interfaces:
+ i.admin_up()
+ i.config_ip6()
+ i.resolve_ndp()
+
+ def tearDown(self):
+ super(TestIP6Punt, self).tearDown()
+ for i in self.pg_interfaces:
+ i.unconfig_ip6()
+ i.admin_down()
+
+ def test_ip_punt(self):
+ """ IP6 punt police and redirect """
+
+ p = (Ether(src=self.pg0.remote_mac,
+ dst=self.pg0.local_mac) /
+ IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6) /
+ TCP(sport=1234, dport=1234) /
+ Raw('\xa5' * 100))
+
+ pkts = p * 1025
+
+ #
+ # Configure a punt redirect via pg1.
+ #
+ nh_addr = inet_pton(AF_INET6,
+ self.pg1.remote_ip6)
+ self.vapi.ip_punt_redirect(self.pg0.sw_if_index,
+ self.pg1.sw_if_index,
+ nh_addr,
+ is_ip6=1)
+
+ self.send_and_expect(self.pg0, pkts, self.pg1)
+
+ #
+ # add a policer
+ #
+ policer = self.vapi.policer_add_del("ip6-punt", 400, 0, 10, 0,
+ rate_type=1)
+ self.vapi.ip_punt_police(policer.policer_index, is_ip6=1)
+
+ self.vapi.cli("clear trace")
+ self.pg0.add_stream(pkts)
+ self.pg_enable_capture(self.pg_interfaces)
+ self.pg_start()
+
+ #
+ # the number of packet recieved should be greater than 0,
+ # but not equal to the number sent, since some were policed
+ #
+ rx = self.pg1._get_capture(1)
+ self.assertTrue(len(rx) > 0)
+ self.assertTrue(len(rx) < len(pkts))
+
+ #
+ # remove the poilcer. back to full rx
+ #
+ self.vapi.ip_punt_police(policer.policer_index, is_add=0, is_ip6=1)
+ self.vapi.policer_add_del("ip6-punt", 400, 0, 10, 0,
+ rate_type=1, is_add=0)
+ self.send_and_expect(self.pg0, pkts, self.pg1)
+
+ #
+ # remove the redirect. expect full drop.
+ #
+ self.vapi.ip_punt_redirect(self.pg0.sw_if_index,
+ self.pg1.sw_if_index,
+ nh_addr,
+ is_add=0,
+ is_ip6=1)
+ self.send_and_assert_no_replies(self.pg0, pkts,
+ "IP no punt config")
+
+ #
+ # Add a redirect that is not input port selective
+ #
+ self.vapi.ip_punt_redirect(0xffffffff,
+ self.pg1.sw_if_index,
+ nh_addr,
+ is_ip6=1)
+ self.send_and_expect(self.pg0, pkts, self.pg1)
+
+ self.vapi.ip_punt_redirect(0xffffffff,
+ self.pg1.sw_if_index,
+ nh_addr,
+ is_add=0,
+ is_ip6=1)
+
+
+class TestIPDeag(VppTestCase):
+ """ IPv6 Deaggregate Routes """
+
+ def setUp(self):
+ super(TestIPDeag, self).setUp()
+
+ self.create_pg_interfaces(range(3))
+
+ for i in self.pg_interfaces:
+ i.admin_up()
+ i.config_ip6()
+ i.resolve_ndp()
+
+ def tearDown(self):
+ super(TestIPDeag, self).tearDown()
+ for i in self.pg_interfaces:
+ i.unconfig_ip6()
+ i.admin_down()
+
+ def test_ip_deag(self):
+ """ IP Deag Routes """
+
+ #
+ # Create a table to be used for:
+ # 1 - another destination address lookup
+ # 2 - a source address lookup
+ #
+ table_dst = VppIpTable(self, 1, is_ip6=1)
+ table_src = VppIpTable(self, 2, is_ip6=1)
+ table_dst.add_vpp_config()
+ table_src.add_vpp_config()
+
+ #
+ # Add a route in the default table to point to a deag/
+ # second lookup in each of these tables
+ #
+ route_to_dst = VppIpRoute(self, "1::1", 128,
+ [VppRoutePath("::",
+ 0xffffffff,
+ nh_table_id=1,
+ proto=DpoProto.DPO_PROTO_IP6)],
+ is_ip6=1)
+ route_to_src = VppIpRoute(self, "1::2", 128,
+ [VppRoutePath("::",
+ 0xffffffff,
+ nh_table_id=2,
+ is_source_lookup=1,
+ proto=DpoProto.DPO_PROTO_IP6)],
+ is_ip6=1)
+ route_to_dst.add_vpp_config()
+ route_to_src.add_vpp_config()
+
+ #
+ # packets to these destination are dropped, since they'll
+ # hit the respective default routes in the second table
+ #
+ p_dst = (Ether(src=self.pg0.remote_mac,
+ dst=self.pg0.local_mac) /
+ IPv6(src="5::5", dst="1::1") /
+ TCP(sport=1234, dport=1234) /
+ Raw('\xa5' * 100))
+ p_src = (Ether(src=self.pg0.remote_mac,
+ dst=self.pg0.local_mac) /
+ IPv6(src="2::2", dst="1::2") /
+ TCP(sport=1234, dport=1234) /
+ Raw('\xa5' * 100))
+ pkts_dst = p_dst * 257
+ pkts_src = p_src * 257
+
+ self.send_and_assert_no_replies(self.pg0, pkts_dst,
+ "IP in dst table")
+ self.send_and_assert_no_replies(self.pg0, pkts_src,
+ "IP in src table")
+
+ #
+ # add a route in the dst table to forward via pg1
+ #
+ route_in_dst = VppIpRoute(self, "1::1", 128,
+ [VppRoutePath(self.pg1.remote_ip6,
+ self.pg1.sw_if_index,
+ proto=DpoProto.DPO_PROTO_IP6)],
+ is_ip6=1,
+ table_id=1)
+ route_in_dst.add_vpp_config()
+
+ self.send_and_expect(self.pg0, pkts_dst, self.pg1)
+
+ #
+ # add a route in the src table to forward via pg2
+ #
+ route_in_src = VppIpRoute(self, "2::2", 128,
+ [VppRoutePath(self.pg2.remote_ip6,
+ self.pg2.sw_if_index,
+ proto=DpoProto.DPO_PROTO_IP6)],
+ is_ip6=1,
+ table_id=2)
+ route_in_src.add_vpp_config()
+ self.send_and_expect(self.pg0, pkts_src, self.pg2)
+
+ #
+ # loop in the lookup DP
+ #
+ route_loop = VppIpRoute(self, "3::3", 128,
+ [VppRoutePath("::",
+ 0xffffffff,
+ proto=DpoProto.DPO_PROTO_IP6)],
+ is_ip6=1)
+ route_loop.add_vpp_config()
+
+ p_l = (Ether(src=self.pg0.remote_mac,
+ dst=self.pg0.local_mac) /
+ IPv6(src="3::4", dst="3::3") /
+ TCP(sport=1234, dport=1234) /
+ Raw('\xa5' * 100))
+
+ self.send_and_assert_no_replies(self.pg0, p_l * 257,
+ "IP lookup loop")
+
+
+class TestIP6Input(VppTestCase):
+ """ IPv6 Input Exceptions """
+
+ def setUp(self):
+ super(TestIP6Input, self).setUp()
+
+ self.create_pg_interfaces(range(2))
+
+ for i in self.pg_interfaces:
+ i.admin_up()
+ i.config_ip6()
+ i.resolve_ndp()
+
+ def tearDown(self):
+ super(TestIP6Input, self).tearDown()
+ for i in self.pg_interfaces:
+ i.unconfig_ip6()
+ i.admin_down()
+
+ def test_ip_input(self):
+ """ IP6 Input Exceptions """
+
+ #
+ # bad version - this is dropped
+ #
+ p_version = (Ether(src=self.pg0.remote_mac,
+ dst=self.pg0.local_mac) /
+ IPv6(src=self.pg0.remote_ip6,
+ dst=self.pg1.remote_ip6,
+ version=3) /
+ UDP(sport=1234, dport=1234) /
+ Raw('\xa5' * 100))
+
+ self.send_and_assert_no_replies(self.pg0, p_version * 65,
+ "funky version")
+
+ #
+ # hop limit - IMCP replies
+ #
+ p_version = (Ether(src=self.pg0.remote_mac,
+ dst=self.pg0.local_mac) /
+ IPv6(src=self.pg0.remote_ip6,
+ dst=self.pg1.remote_ip6,
+ hlim=1) /
+ UDP(sport=1234, dport=1234) /
+ Raw('\xa5' * 100))
+
+ rx = self.send_and_expect(self.pg0, p_version * 65, self.pg0)
+ rx = rx[0]
+ icmp = rx[ICMPv6TimeExceeded]
+ self.assertEqual(icmp.type, 3)
+ # 0: "hop limit exceeded in transit",
+ self.assertEqual(icmp.code, 0)
+
+
if __name__ == '__main__':
unittest.main(testRunner=VppTestRunner)