From 87df12d5de67600414ae80b891e8a0f89e89ce5c Mon Sep 17 00:00:00 2001 From: Neale Ranns Date: Sat, 18 Feb 2017 08:16:41 -0800 Subject: IPv6 RA improvements 1) tests for RA options 2) memleaks deleteing a ip6_radv_info_t 3) MLD prefix code refactoring Change-Id: I34db103994bd8fbdbbec50b202d72770dd145681 Signed-off-by: Neale Ranns --- test/test_ip6.py | 219 ++++++++++++++++++++++++++++++++++++++++++++-- test/vpp_interface.py | 11 +++ test/vpp_neighbor.py | 2 +- test/vpp_papi_provider.py | 25 ++++++ 4 files changed, 251 insertions(+), 6 deletions(-) (limited to 'test') diff --git a/test/test_ip6.py b/test/test_ip6.py index fb5383cfc0c..b8278329ba9 100644 --- a/test/test_ip6.py +++ b/test/test_ip6.py @@ -10,7 +10,8 @@ from vpp_pg_interface import is_ipv6_misc from scapy.packet import Raw from scapy.layers.l2 import Ether, Dot1Q from scapy.layers.inet6 import IPv6, UDP, ICMPv6ND_NS, ICMPv6ND_RS, \ - ICMPv6ND_RA, ICMPv6NDOptSrcLLAddr, getmacbyip6, ICMPv6MRD_Solicitation + ICMPv6ND_RA, ICMPv6NDOptSrcLLAddr, getmacbyip6, ICMPv6MRD_Solicitation, \ + ICMPv6NDOptMTU, ICMPv6NDOptSrcLLAddr, ICMPv6NDOptPrefixInfo from util import ppp from scapy.utils6 import in6_getnsma, in6_getnsmac, in6_ptop, in6_islladdr, \ in6_mactoifaceid, in6_ismaddr @@ -288,7 +289,7 @@ class TestIPv6(VppTestCase): self.send_and_assert_no_replies(self.pg0, pkts, "No response to NS for unknown target") - def validate_ra(self, intf, rx, dst_ip=None): + def validate_ra(self, intf, rx, dst_ip=None, mtu=9000, pi_opt=None): if not dst_ip: dst_ip = intf.remote_ip6 @@ -308,17 +309,47 @@ class TestIPv6(VppTestCase): self.assertEqual(in6_ptop(rx[IPv6].src), in6_ptop(mk_ll_addr(intf.local_mac))) + # it should contain the links MTU + ra = rx[ICMPv6ND_RA] + self.assertEqual(ra[ICMPv6NDOptMTU].mtu, mtu) + + # it should contain the source's link layer address option + sll = ra[ICMPv6NDOptSrcLLAddr] + self.assertEqual(sll.lladdr, intf.local_mac) + + if not pi_opt: + # the RA should not contain prefix information + self.assertFalse(ra.haslayer(ICMPv6NDOptPrefixInfo)) + else: + raos = rx.getlayer(ICMPv6NDOptPrefixInfo, 1) + + # the options are nested in the scapy packet in way that i cannot + # decipher how to decode. this 1st layer of option always returns + # nested classes, so a direct obj1=obj2 comparison always fails. + # however, the getlayer(.., 2) does give one instnace. + # so we cheat here and construct a new opt instnace for comparison + rd = ICMPv6NDOptPrefixInfo(prefixlen=raos.prefixlen, + prefix=raos.prefix, + L=raos.L, + A=raos.A) + if type(pi_opt) is list: + for ii in range(len(pi_opt)): + self.assertEqual(pi_opt[ii], rd) + rd = rx.getlayer(ICMPv6NDOptPrefixInfo, ii+2) + else: + self.assertEqual(pi_opt, raos) + def send_and_expect_ra(self, intf, pkts, remark, dst_ip=None, - filter_out_fn=is_ipv6_misc): + filter_out_fn=is_ipv6_misc, + opt=None): intf.add_stream(pkts) - self.pg0.add_stream(pkts) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = intf.get_capture(1, filter_out_fn=filter_out_fn) self.assertEqual(len(rx), 1) rx = rx[0] - self.validate_ra(intf, rx, dst_ip) + self.validate_ra(intf, rx, dst_ip, pi_opt=opt) def test_rs(self): """ IPv6 Router Solicitation Exceptions @@ -415,6 +446,184 @@ class TestIPv6(VppTestCase): dst_ip="ff02::1", filter_out_fn=None) + # + # Configure The RA to announce the links prefix + # + self.pg0.ip6_ra_prefix(self.pg0.local_ip6n, + self.pg0.local_ip6_prefix_len) + + # + # RAs should now contain the prefix information option + # + opt = ICMPv6NDOptPrefixInfo(prefixlen=self.pg0.local_ip6_prefix_len, + prefix=self.pg0.local_ip6, + L=1, + A=1) + + self.pg0.ip6_ra_config(send_unicast=1) + ll = mk_ll_addr(self.pg0.remote_mac) + p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / + IPv6(dst=self.pg0.local_ip6, src=ll) / + ICMPv6ND_RS()) + self.send_and_expect_ra(self.pg0, p, + "RA with prefix-info", + dst_ip=ll, + opt=opt) + + # + # Change the prefix info to not off-link + # L-flag is clear + # + self.pg0.ip6_ra_prefix(self.pg0.local_ip6n, + self.pg0.local_ip6_prefix_len, + off_link=1) + + opt = ICMPv6NDOptPrefixInfo(prefixlen=self.pg0.local_ip6_prefix_len, + prefix=self.pg0.local_ip6, + L=0, + A=1) + + self.pg0.ip6_ra_config(send_unicast=1) + self.send_and_expect_ra(self.pg0, p, + "RA with Prefix info with L-flag=0", + dst_ip=ll, + opt=opt) + + # + # Change the prefix info to not off-link, no-autoconfig + # L and A flag are clear in the advert + # + self.pg0.ip6_ra_prefix(self.pg0.local_ip6n, + self.pg0.local_ip6_prefix_len, + off_link=1, + no_autoconfig=1) + + opt = ICMPv6NDOptPrefixInfo(prefixlen=self.pg0.local_ip6_prefix_len, + prefix=self.pg0.local_ip6, + L=0, + A=0) + + self.pg0.ip6_ra_config(send_unicast=1) + self.send_and_expect_ra(self.pg0, p, + "RA with Prefix info with A & L-flag=0", + dst_ip=ll, + opt=opt) + + # + # Change the flag settings back to the defaults + # L and A flag are set in the advert + # + self.pg0.ip6_ra_prefix(self.pg0.local_ip6n, + self.pg0.local_ip6_prefix_len) + + opt = ICMPv6NDOptPrefixInfo(prefixlen=self.pg0.local_ip6_prefix_len, + prefix=self.pg0.local_ip6, + L=1, + A=1) + + self.pg0.ip6_ra_config(send_unicast=1) + self.send_and_expect_ra(self.pg0, p, + "RA with Prefix info", + dst_ip=ll, + opt=opt) + + # + # Change the prefix info to not off-link, no-autoconfig + # L and A flag are clear in the advert + # + self.pg0.ip6_ra_prefix(self.pg0.local_ip6n, + self.pg0.local_ip6_prefix_len, + off_link=1, + no_autoconfig=1) + + opt = ICMPv6NDOptPrefixInfo(prefixlen=self.pg0.local_ip6_prefix_len, + prefix=self.pg0.local_ip6, + L=0, + A=0) + + self.pg0.ip6_ra_config(send_unicast=1) + self.send_and_expect_ra(self.pg0, p, + "RA with Prefix info with A & L-flag=0", + dst_ip=ll, + opt=opt) + + # + # Use the reset to defults option to revert to defaults + # L and A flag are clear in the advert + # + self.pg0.ip6_ra_prefix(self.pg0.local_ip6n, + self.pg0.local_ip6_prefix_len, + use_default=1) + + opt = ICMPv6NDOptPrefixInfo(prefixlen=self.pg0.local_ip6_prefix_len, + prefix=self.pg0.local_ip6, + L=1, + A=1) + + self.pg0.ip6_ra_config(send_unicast=1) + self.send_and_expect_ra(self.pg0, p, + "RA with Prefix reverted to defaults", + dst_ip=ll, + opt=opt) + + # + # Advertise Another prefix. With no L-flag/A-flag + # + self.pg0.ip6_ra_prefix(self.pg1.local_ip6n, + self.pg1.local_ip6_prefix_len, + off_link=1, + no_autoconfig=1) + + opt = [ICMPv6NDOptPrefixInfo(prefixlen=self.pg0.local_ip6_prefix_len, + prefix=self.pg0.local_ip6, + L=1, + A=1), + ICMPv6NDOptPrefixInfo(prefixlen=self.pg1.local_ip6_prefix_len, + prefix=self.pg1.local_ip6, + L=0, + A=0)] + + self.pg0.ip6_ra_config(send_unicast=1) + ll = mk_ll_addr(self.pg0.remote_mac) + p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / + IPv6(dst=self.pg0.local_ip6, src=ll) / + ICMPv6ND_RS()) + self.send_and_expect_ra(self.pg0, p, + "RA with multiple Prefix infos", + dst_ip=ll, + opt=opt) + + # + # Remove the first refix-info - expect the second is still in the + # advert + # + self.pg0.ip6_ra_prefix(self.pg0.local_ip6n, + self.pg0.local_ip6_prefix_len, + is_no=1) + + opt = ICMPv6NDOptPrefixInfo(prefixlen=self.pg1.local_ip6_prefix_len, + prefix=self.pg1.local_ip6, + L=0, + A=0) + + self.pg0.ip6_ra_config(send_unicast=1) + self.send_and_expect_ra(self.pg0, p, + "RA with Prefix reverted to defaults", + dst_ip=ll, + opt=opt) + + # + # Remove the second prefix-info - expect no prefix-info i nthe adverts + # + self.pg0.ip6_ra_prefix(self.pg1.local_ip6n, + self.pg1.local_ip6_prefix_len, + is_no=1) + + self.pg0.ip6_ra_config(send_unicast=1) + self.send_and_expect_ra(self.pg0, p, + "RA with Prefix reverted to defaults", + dst_ip=ll) + # # Reset the periodic advertisements back to default values # diff --git a/test/vpp_interface.py b/test/vpp_interface.py index 4588943dd8a..53a0ae8de98 100644 --- a/test/vpp_interface.py +++ b/test/vpp_interface.py @@ -272,6 +272,17 @@ class VppInterface(object): suppress, send_unicast) + def ip6_ra_prefix(self, address, address_length, is_no=0, + off_link=0, no_autoconfig=0, use_default=0): + """Configure IPv6 RA suppress on the VPP interface.""" + self.test.vapi.ip6_sw_interface_ra_prefix(self.sw_if_index, + address, + address_length, + is_no=is_no, + off_link=off_link, + no_autoconfig=no_autoconfig, + use_default=use_default) + def admin_up(self): """Put interface ADMIN-UP.""" self.test.vapi.sw_interface_set_flags(self.sw_if_index, diff --git a/test/vpp_neighbor.py b/test/vpp_neighbor.py index fbd41eb5352..5c2e34794ec 100644 --- a/test/vpp_neighbor.py +++ b/test/vpp_neighbor.py @@ -31,7 +31,7 @@ class VppNeighbor(VppObject): """ def __init__(self, test, sw_if_index, mac_addr, nbr_addr, - af=AF_INET, is_static=0): + af=AF_INET, is_static=False): self._test = test self.sw_if_index = sw_if_index self.mac_addr = mactobinary(mac_addr) diff --git a/test/vpp_papi_provider.py b/test/vpp_papi_provider.py index 5d4d6b7ef0c..fe152de3969 100644 --- a/test/vpp_papi_provider.py +++ b/test/vpp_papi_provider.py @@ -286,6 +286,31 @@ class VppPapiProvider(object): 'suppress': suppress, 'send_unicast': send_unicast}) + def ip6_sw_interface_ra_prefix(self, + sw_if_index, + address, + address_length, + use_default=0, + no_advertise=0, + off_link=0, + no_autoconfig=0, + no_onlink=0, + is_no=0, + val_lifetime=0xffffffff, + pref_lifetime=0xffffffff): + return self.api(self.papi.sw_interface_ip6nd_ra_prefix, + {'sw_if_index': sw_if_index, + 'address': address, + 'address_length': address_length, + 'use_default': use_default, + 'no_advertise': no_advertise, + 'off_link': off_link, + 'no_autoconfig': no_autoconfig, + 'no_onlink': no_onlink, + 'is_no': is_no, + 'val_lifetime': val_lifetime, + 'pref_lifetime': pref_lifetime}) + def ip6_sw_interface_enable_disable(self, sw_if_index, enable): """ Enable/Disable An interface for IPv6 -- cgit 1.2.3-korg