aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeale Ranns <nranns@cisco.com>2017-04-19 05:24:40 -0700
committerFlorin Coras <florin.coras@gmail.com>2017-04-19 20:23:34 +0000
commit2a3ea49d5cc224ffb2cf02bacaf0c02ddae12b86 (patch)
tree8b6a6176a3129c14c70308fdc5ab338ddc06523d
parentc06eeb0e3c9c1a9fa8f913e2d785b03220bfdabd (diff)
Learn IP6 link-local ND entries from NSs sourced from link-local address
Change-Id: I4c3ce4d58df7977490fc94991291422ea1e31ee3 Signed-off-by: Neale Ranns <nranns@cisco.com>
-rw-r--r--src/vnet/ethernet/arp.c3
-rw-r--r--src/vnet/ip/ip6_neighbor.c7
-rw-r--r--test/test_dhcp.py8
-rw-r--r--test/test_ip6.py106
-rw-r--r--test/util.py21
-rw-r--r--test/vpp_interface.py18
-rw-r--r--test/vpp_neighbor.py2
7 files changed, 126 insertions, 39 deletions
diff --git a/src/vnet/ethernet/arp.c b/src/vnet/ethernet/arp.c
index 3e292e4df93..31af4fbaa80 100644
--- a/src/vnet/ethernet/arp.c
+++ b/src/vnet/ethernet/arp.c
@@ -584,6 +584,9 @@ vnet_arp_set_ip4_over_ethernet_internal (vnet_main_t * vnm,
FIB_PROTOCOL_IP4, &pfx.fp_addr,
e->sw_if_index, ~0, 1, NULL,
FIB_ROUTE_PATH_FLAG_NONE);
+ }
+ else
+ {
e->flags |= ETHERNET_ARP_IP4_ENTRY_FLAG_NO_FIB_ENTRY;
}
}
diff --git a/src/vnet/ip/ip6_neighbor.c b/src/vnet/ip/ip6_neighbor.c
index 42edb79a545..31182770261 100644
--- a/src/vnet/ip/ip6_neighbor.c
+++ b/src/vnet/ip/ip6_neighbor.c
@@ -634,6 +634,9 @@ vnet_set_ip6_ethernet_neighbor (vlib_main_t * vm,
FIB_PROTOCOL_IP6, &pfx.fp_addr,
n->key.sw_if_index, ~0, 1, NULL,
FIB_ROUTE_PATH_FLAG_NONE);
+ }
+ else
+ {
n->flags |= IP6_NEIGHBOR_FLAG_NO_FIB_ENTRY;
}
}
@@ -1027,7 +1030,7 @@ icmp6_neighbor_solicitation_or_advertisement (vlib_main_t * vm,
/* If src address unspecified or link local, donot learn neighbor MAC */
if (PREDICT_TRUE (error0 == ICMP6_ERROR_NONE && o0 != 0 &&
- !ip6_sadd_unspecified && !ip6_sadd_link_local))
+ !ip6_sadd_unspecified))
{
ip6_neighbor_main_t *nm = &ip6_neighbor_main;
if (nm->limit_neighbor_cache_size &&
@@ -1040,7 +1043,7 @@ icmp6_neighbor_solicitation_or_advertisement (vlib_main_t * vm,
&h0->target_address,
o0->ethernet_address,
sizeof (o0->ethernet_address),
- 0, 0);
+ 0, ip6_sadd_link_local);
}
if (is_solicitation && error0 == ICMP6_ERROR_NONE)
diff --git a/test/test_dhcp.py b/test/test_dhcp.py
index 89667d3d1fc..03c749d3f09 100644
--- a/test/test_dhcp.py
+++ b/test/test_dhcp.py
@@ -6,6 +6,7 @@ import struct
from framework import VppTestCase, VppTestRunner
from vpp_neighbor import VppNeighbor
+from util import mk_ll_addr
from scapy.layers.l2 import Ether, getmacbyip
from scapy.layers.inet import IP, UDP, ICMP
@@ -24,13 +25,6 @@ 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 """
diff --git a/test/test_ip6.py b/test/test_ip6.py
index a8e8d4de9ea..3ba092305c5 100644
--- a/test/test_ip6.py
+++ b/test/test_ip6.py
@@ -77,7 +77,6 @@ class TestIPv6ND(VppTestCase):
def send_and_expect_ra(self, intf, pkts, remark, dst_ip=None,
filter_out_fn=is_ipv6_misc):
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)
@@ -86,11 +85,25 @@ class TestIPv6ND(VppTestCase):
rx = rx[0]
self.validate_ra(intf, rx, dst_ip)
+ def send_and_expect_na(self, intf, pkts, remark, dst_ip=None,
+ tgt_ip=None,
+ filter_out_fn=is_ipv6_misc):
+ intf.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_na(intf, rx, dst_ip, 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()
- intf.assert_nothing_captured(remark=remark)
+ for i in self.pg_interfaces:
+ i.get_capture(0)
+ i.assert_nothing_captured(remark=remark)
class TestIPv6(TestIPv6ND):
@@ -376,6 +389,59 @@ class TestIPv6(TestIPv6ND):
128,
inet=AF_INET6))
+ #
+ # send an NS from a link local address to the interface's global
+ # address
+ #
+ p = (Ether(dst=in6_getnsmac(nsma), src=self.pg0.remote_mac) /
+ IPv6(dst=d, src=self.pg0._remote_hosts[2].ip6_ll) /
+ ICMPv6ND_NS(tgt=self.pg0.local_ip6) /
+ ICMPv6NDOptSrcLLAddr(lladdr=self.pg0.remote_mac))
+
+ self.send_and_expect_na(self.pg0, p,
+ "NS from link-local",
+ dst_ip=self.pg0._remote_hosts[2].ip6_ll,
+ tgt_ip=self.pg0.local_ip6)
+
+ #
+ # we should have learned an ND entry for the peer's link-local
+ # but not inserted a route to it in the FIB
+ #
+ self.assertTrue(find_nbr(self,
+ self.pg0.sw_if_index,
+ self.pg0._remote_hosts[2].ip6_ll,
+ inet=AF_INET6))
+ self.assertFalse(find_route(self,
+ self.pg0._remote_hosts[2].ip6_ll,
+ 128,
+ inet=AF_INET6))
+
+ #
+ # An NS to the router's own Link-local
+ #
+ p = (Ether(dst=in6_getnsmac(nsma), src=self.pg0.remote_mac) /
+ IPv6(dst=d, src=self.pg0._remote_hosts[3].ip6_ll) /
+ ICMPv6ND_NS(tgt=self.pg0.local_ip6_ll) /
+ ICMPv6NDOptSrcLLAddr(lladdr=self.pg0.remote_mac))
+
+ self.send_and_expect_na(self.pg0, p,
+ "NS to/from link-local",
+ dst_ip=self.pg0._remote_hosts[3].ip6_ll,
+ tgt_ip=self.pg0.local_ip6_ll)
+
+ #
+ # we should have learned an ND entry for the peer's link-local
+ # but not inserted a route to it in the FIB
+ #
+ self.assertTrue(find_nbr(self,
+ self.pg0.sw_if_index,
+ self.pg0._remote_hosts[3].ip6_ll,
+ inet=AF_INET6))
+ self.assertFalse(find_route(self,
+ self.pg0._remote_hosts[3].ip6_ll,
+ 128,
+ inet=AF_INET6))
+
def validate_ra(self, intf, rx, dst_ip=None, mtu=9000, pi_opt=None):
if not dst_ip:
dst_ip = intf.remote_ip6
@@ -770,14 +836,10 @@ class IPv6NDProxyTest(TestIPv6ND):
#
# try that NS again. this time we expect an NA back
#
- self.pg1.add_stream(ns_pg1)
- self.pg_enable_capture(self.pg_interfaces)
- self.pg_start()
- rx = self.pg1.get_capture(1)
-
- self.validate_na(self.pg1, rx[0],
- dst_ip=self.pg0._remote_hosts[2].ip6,
- tgt_ip=self.pg0.local_ip6)
+ self.send_and_expect_na(self.pg1, ns_pg1,
+ "NS to proxy entry",
+ dst_ip=self.pg0._remote_hosts[2].ip6,
+ tgt_ip=self.pg0.local_ip6)
#
# ... and that we have an entry in the ND cache
@@ -816,14 +878,10 @@ class IPv6NDProxyTest(TestIPv6ND):
ICMPv6ND_NS(tgt=self.pg0._remote_hosts[2].ip6) /
ICMPv6NDOptSrcLLAddr(lladdr=self.pg0.remote_mac))
- self.pg0.add_stream(ns_pg0)
- self.pg_enable_capture(self.pg_interfaces)
- self.pg_start()
- rx = self.pg0.get_capture(1)
-
- self.validate_na(self.pg0, rx[0],
- tgt_ip=self.pg0._remote_hosts[2].ip6,
- dst_ip=self.pg0.remote_ip6)
+ self.send_and_expect_na(self.pg0, ns_pg0,
+ "NS to proxy entry on main",
+ tgt_ip=self.pg0._remote_hosts[2].ip6,
+ dst_ip=self.pg0.remote_ip6)
#
# Setup and resolve proxy for another host on another interface
@@ -837,14 +895,10 @@ class IPv6NDProxyTest(TestIPv6ND):
inet_pton(AF_INET6, self.pg0._remote_hosts[3].ip6),
self.pg2.sw_if_index)
- self.pg2.add_stream(ns_pg2)
- self.pg_enable_capture(self.pg_interfaces)
- self.pg_start()
- rx = self.pg2.get_capture(1)
-
- self.validate_na(self.pg2, rx[0],
- dst_ip=self.pg0._remote_hosts[3].ip6,
- tgt_ip=self.pg0.local_ip6)
+ self.send_and_expect_na(self.pg2, ns_pg2,
+ "NS to proxy entry other interface",
+ dst_ip=self.pg0._remote_hosts[3].ip6,
+ tgt_ip=self.pg0.local_ip6)
self.assertTrue(find_nbr(self,
self.pg2.sw_if_index,
diff --git a/test/util.py b/test/util.py
index d6b77f9d3c3..aeba2ab4ffe 100644
--- a/test/util.py
+++ b/test/util.py
@@ -4,6 +4,7 @@ import socket
import sys
from abc import abstractmethod, ABCMeta
from cStringIO import StringIO
+from scapy.layers.inet6 import in6_mactoifaceid
def ppp(headline, packet):
@@ -52,6 +53,12 @@ def mactobinary(mac):
return mac.replace(':', '').decode('hex')
+def mk_ll_addr(mac):
+ euid = in6_mactoifaceid(mac)
+ addr = "fe80::" + euid
+ return addr
+
+
class NumericConstant(object):
__metaclass__ = ABCMeta
@@ -101,10 +108,22 @@ class Host(object):
""" IPv6 address of remote host - raw, suitable as API parameter."""
return socket.inet_pton(socket.AF_INET6, self._ip6)
- def __init__(self, mac=None, ip4=None, ip6=None):
+ @property
+ def ip6_ll(self):
+ """ IPv6 link-local address - string """
+ return self._ip6_ll
+
+ @property
+ def ip6n_ll(self):
+ """ IPv6 link-local address of remote host -
+ raw, suitable as API parameter."""
+ return socket.inet_pton(socket.AF_INET6, self._ip6_ll)
+
+ def __init__(self, mac=None, ip4=None, ip6=None, ip6_ll=None):
self._mac = mac
self._ip4 = ip4
self._ip6 = ip6
+ self._ip6_ll = ip6_ll
class ForeignAddressFactory(object):
diff --git a/test/vpp_interface.py b/test/vpp_interface.py
index 5dba0978cb9..662015eacf7 100644
--- a/test/vpp_interface.py
+++ b/test/vpp_interface.py
@@ -1,7 +1,7 @@
from abc import abstractmethod, ABCMeta
import socket
-from util import Host
+from util import Host, mk_ll_addr
from vpp_neighbor import VppNeighbor
@@ -55,6 +55,16 @@ class VppInterface(object):
return socket.inet_pton(socket.AF_INET6, self.local_ip6)
@property
+ def local_ip6_ll(self):
+ """Local IPv6 linnk-local address on VPP interface (string)."""
+ return self._local_ip6_ll
+
+ @property
+ def local_ip6n_ll(self):
+ """Local IPv6 link-local address - raw, suitable as API parameter."""
+ return self.local_ip6n_ll
+
+ @property
def remote_ip6(self):
"""IPv6 address of remote peer "connected" to this interface."""
return self._remote_hosts[0].ip6
@@ -133,7 +143,8 @@ class VppInterface(object):
mac = "02:%02x:00:00:ff:%02x" % (self.sw_if_index, i)
ip4 = "172.16.%u.%u" % (self.sw_if_index, i)
ip6 = "fd01:%x::%x" % (self.sw_if_index, i)
- host = Host(mac, ip4, ip6)
+ ip6_ll = mk_ll_addr(mac)
+ host = Host(mac, ip4, ip6, ip6_ll)
self._remote_hosts.append(host)
self._hosts_by_mac[mac] = host
self._hosts_by_ip4[ip4] = host
@@ -176,6 +187,9 @@ class VppInterface(object):
"Could not find interface with sw_if_index %d "
"in interface dump %s" %
(self.sw_if_index, repr(r)))
+ self._local_ip6_ll = mk_ll_addr(self.local_mac)
+ self._local_ip6n_ll = socket.inet_pton(socket.AF_INET6,
+ self.local_ip6_ll)
def config_ip4(self):
"""Configure IPv4 address on the VPP interface."""
diff --git a/test/vpp_neighbor.py b/test/vpp_neighbor.py
index 6968b5f68a5..5919cf8e48b 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=False, is_no_fib_entry=False):
+ af=AF_INET, is_static=False, is_no_fib_entry=0):
self._test = test
self.sw_if_index = sw_if_index
self.mac_addr = mactobinary(mac_addr)