From 39f9d8bd226ab5aa366f181a5cbf7c873f599e06 Mon Sep 17 00:00:00 2001 From: Neale Ranns Date: Thu, 16 Feb 2017 21:57:05 -0800 Subject: [Proxy] ARP tests Change-Id: I40d6d763b55a26cdee0afef85d1acdd19dd10dd6 Signed-off-by: Neale Ranns --- test/vpp_neighbor.py | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 test/vpp_neighbor.py (limited to 'test/vpp_neighbor.py') diff --git a/test/vpp_neighbor.py b/test/vpp_neighbor.py new file mode 100644 index 00000000..fbd41eb5 --- /dev/null +++ b/test/vpp_neighbor.py @@ -0,0 +1,77 @@ +""" + Neighbour Entries + + object abstractions for ARP and ND +""" + +from socket import inet_pton, inet_ntop, AF_INET, AF_INET6 +from vpp_object import * +from util import mactobinary + + +def find_nbr(test, sw_if_index, ip_addr, is_static=0, inet=AF_INET): + nbrs = test.vapi.ip_neighbor_dump(sw_if_index, + is_ipv6=1 if AF_INET6 == inet else 0) + if inet == AF_INET: + s = 4 + else: + s = 16 + nbr_addr = inet_pton(inet, ip_addr) + + for n in nbrs: + if nbr_addr == n.ip_address[:s] \ + and is_static == n.is_static: + return True + return False + + +class VppNeighbor(VppObject): + """ + ARP Entry + """ + + def __init__(self, test, sw_if_index, mac_addr, nbr_addr, + af=AF_INET, is_static=0): + self._test = test + self.sw_if_index = sw_if_index + self.mac_addr = mactobinary(mac_addr) + self.af = af + self.is_static = is_static + self.nbr_addr = inet_pton(af, nbr_addr) + + def add_vpp_config(self): + self._test.vapi.ip_neighbor_add_del( + self.sw_if_index, + self.mac_addr, + self.nbr_addr, + is_add=1, + is_ipv6=1 if AF_INET6 == self.af else 0, + is_static=self.is_static) + self._test.registry.register(self, self._test.logger) + + def remove_vpp_config(self): + self._test.vapi.ip_neighbor_add_del( + self.sw_if_index, + self.mac_addr, + self.nbr_addr, + is_ipv6=1 if AF_INET6 == self.af else 0, + is_add=0, + is_static=self.is_static) + + def query_vpp_config(self): + dump = self._test.vapi.ip_neighbor_dump( + self.sw_if_index, + is_ipv6=1 if AF_INET6 == self.af else 0) + for n in dump: + if self.nbr_addr == n.ip_address \ + and self.is_static == n.is_static: + return True + return False + + def __str__(self): + return self.object_id() + + def object_id(self): + return ("%d:%s" + % (self.sw_if_index, + inet_ntop(self.af, self.nbr_addr))) -- cgit 1.2.3-korg 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 --- src/vnet/ip/ip.api | 36 +++++-- src/vnet/ip/ip6_neighbor.c | 244 ++++++++++++++++++--------------------------- src/vppinfra/pool.h | 26 +++++ test/test_ip6.py | 219 +++++++++++++++++++++++++++++++++++++++- test/vpp_interface.py | 11 ++ test/vpp_neighbor.py | 2 +- test/vpp_papi_provider.py | 25 +++++ 7 files changed, 400 insertions(+), 163 deletions(-) (limited to 'test/vpp_neighbor.py') diff --git a/src/vnet/ip/ip.api b/src/vnet/ip/ip.api index 326c825b..ff16e781 100644 --- a/src/vnet/ip/ip.api +++ b/src/vnet/ip/ip.api @@ -241,17 +241,31 @@ define sw_interface_ip6nd_ra_config_reply /** \brief IPv6 router advertisement prefix config request @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request - @param sw_if_index - - @param address[] - - @param address_length - - @param use_default - - @param no_advertise - - @param off_link - - @param no_autoconfig - - @param no_onlink - - @param is_no - - @param val_lifetime - - @param pref_lifetime - + @param sw_if_index - The interface the RA prefix information is for + @param address[] - The prefix to advertise + @param address_length - the prefix length + @param use_default - Revert to default settings + @param no_advertise - Do not advertise this prefix + @param off_link - The prefix is off link (it is not configured on the interface) + Configures the L-flag, When set, indicates that this + prefix can be used for on-link determination. + @param no_autoconfig - Setting for the A-flag. When + set indicates that this prefix can be used for + stateless address configuration. + @param no_onlink - The prefix is not on link. Make sure this is consistent + with the off_link parameter else YMMV + @param is_no - add/delete + @param val_lifetime - The length of time in + seconds (relative to the time the packet is sent) + that the prefix is valid for the purpose of on-link + determination. A value of all one bits + (0xffffffff) represents infinity + @param pref_lifetime - The length of time in + seconds (relative to the time the packet is sent) + that addresses generated from the prefix via + stateless address autoconfiguration remain + preferred [ADDRCONF]. A value of all one bits + (0xffffffff) represents infinity. */ define sw_interface_ip6nd_ra_prefix { diff --git a/src/vnet/ip/ip6_neighbor.c b/src/vnet/ip/ip6_neighbor.c index 91ff224c..43d68cd1 100644 --- a/src/vnet/ip/ip6_neighbor.c +++ b/src/vnet/ip/ip6_neighbor.c @@ -107,7 +107,6 @@ typedef struct /* local information */ u32 sw_if_index; - u32 fib_index; int send_radv; /* radv on/off on this interface - set by config */ int cease_radv; /* we are ceasing to send - set byf config */ int send_unicast; @@ -1924,7 +1923,79 @@ icmp6_router_advertisement (vlib_main_t * vm, return frame->n_vectors; } -/* create and initialize router advertisement parameters with default values for this intfc */ +/** + * @brief Add a multicast Address to the advertised MLD set + */ +static void +ip6_neighbor_add_mld_prefix (ip6_radv_t * radv_info, ip6_address_t * addr) +{ + ip6_mldp_group_t *mcast_group_info; + uword *p; + + /* lookup mldp info for this interface */ + p = mhash_get (&radv_info->address_to_mldp_index, &addr); + mcast_group_info = + p ? pool_elt_at_index (radv_info->mldp_group_pool, p[0]) : 0; + + /* add address */ + if (!mcast_group_info) + { + /* add */ + u32 mi; + pool_get (radv_info->mldp_group_pool, mcast_group_info); + + mi = mcast_group_info - radv_info->mldp_group_pool; + mhash_set (&radv_info->address_to_mldp_index, &addr, mi, /* old_value */ + 0); + + mcast_group_info->type = 4; + mcast_group_info->mcast_source_address_pool = 0; + mcast_group_info->num_sources = 0; + clib_memcpy (&mcast_group_info->mcast_address, &addr, + sizeof (ip6_address_t)); + } +} + +/** + * @brief Delete a multicast Address from the advertised MLD set + */ +static void +ip6_neighbor_del_mld_prefix (ip6_radv_t * radv_info, ip6_address_t * addr) +{ + ip6_mldp_group_t *mcast_group_info; + uword *p; + + p = mhash_get (&radv_info->address_to_mldp_index, &addr); + mcast_group_info = + p ? pool_elt_at_index (radv_info->mldp_group_pool, p[0]) : 0; + + if (mcast_group_info) + { + mhash_unset (&radv_info->address_to_mldp_index, &addr, + /* old_value */ 0); + pool_put (radv_info->mldp_group_pool, mcast_group_info); + } +} + +/** + * @brief Add a multicast Address to the advertised MLD set + */ +static void +ip6_neighbor_add_mld_grp (ip6_radv_t * a, + ip6_multicast_address_scope_t scope, + ip6_multicast_link_local_group_id_t group) +{ + ip6_address_t addr; + + ip6_set_reserved_multicast_address (&addr, scope, group); + + ip6_neighbor_add_mld_prefix (a, &addr); +} + +/** + * @brief create and initialize router advertisement parameters with default + * values for this intfc + */ static u32 ip6_neighbor_sw_interface_add_del (vnet_main_t * vnm, u32 sw_if_index, u32 is_add) @@ -1953,47 +2024,29 @@ ip6_neighbor_sw_interface_add_del (vnet_main_t * vnm, if (!is_add) { - u32 i, *to_delete = 0; ip6_radv_prefix_t *p; ip6_mldp_group_t *m; /* release the lock on the interface's mcast adj */ adj_unlock (a->mcast_adj_index); - /* clean up prefix_pool */ + /* clean up prefix and MDP pools */ /* *INDENT-OFF* */ - pool_foreach (p, a->adv_prefixes_pool, + pool_flush(p, a->adv_prefixes_pool, ({ - vec_add1 (to_delete, p - a->adv_prefixes_pool); - })); - /* *INDENT-ON* */ - - for (i = 0; i < vec_len (to_delete); i++) - { - p = pool_elt_at_index (a->adv_prefixes_pool, to_delete[i]); mhash_unset (&a->address_to_prefix_index, &p->prefix, 0); - pool_put (a->adv_prefixes_pool, p); - } - - vec_free (to_delete); - to_delete = 0; - - /* clean up mldp group pool */ - /* *INDENT-OFF* */ - pool_foreach (m, a->mldp_group_pool, + })); + pool_flush (m, a->mldp_group_pool, ({ - vec_add1 (to_delete, m - a->mldp_group_pool); + mhash_unset (&a->address_to_mldp_index, &m->mcast_address, 0); })); /* *INDENT-ON* */ - for (i = 0; i < vec_len (to_delete); i++) - { - m = pool_elt_at_index (a->mldp_group_pool, to_delete[i]); - mhash_unset (&a->address_to_mldp_index, &m->mcast_address, 0); - pool_put (a->mldp_group_pool, m); - } + pool_free (a->mldp_group_pool); + pool_free (a->adv_prefixes_pool); - vec_free (to_delete); + mhash_free (&a->address_to_prefix_index); + mhash_free (&a->address_to_mldp_index); pool_put (nm->if_radv_pool, a); nm->if_radv_pool_index_by_sw_if_index[sw_if_index] = ~0; @@ -2017,13 +2070,13 @@ ip6_neighbor_sw_interface_add_del (vnet_main_t * vnm, memset (a, 0, sizeof (a[0])); a->sw_if_index = sw_if_index; - a->fib_index = ~0; a->max_radv_interval = DEF_MAX_RADV_INTERVAL; a->min_radv_interval = DEF_MIN_RADV_INTERVAL; a->curr_hop_limit = DEF_CURR_HOP_LIMIT; a->adv_router_lifetime_in_sec = DEF_DEF_RTR_LIFETIME; - a->adv_link_layer_address = 1; /* send ll address source address option */ + /* send ll address source address option */ + a->adv_link_layer_address = 1; a->min_delay_between_radv = MIN_DELAY_BETWEEN_RAS; a->max_delay_between_radv = MAX_DELAY_BETWEEN_RAS; @@ -2059,86 +2112,15 @@ ip6_neighbor_sw_interface_add_del (vnet_main_t * vnm, sw_if_index); /* add multicast groups we will always be reporting */ - ip6_address_t addr; - ip6_mldp_group_t *mcast_group_info; - - ip6_set_reserved_multicast_address (&addr, - IP6_MULTICAST_SCOPE_link_local, - IP6_MULTICAST_GROUP_ID_all_hosts); - - /* lookup mldp info for this interface */ - - uword *p = mhash_get (&a->address_to_mldp_index, &addr); - mcast_group_info = - p ? pool_elt_at_index (a->mldp_group_pool, p[0]) : 0; - - /* add address */ - if (!mcast_group_info) - { - /* add */ - u32 mi; - pool_get (a->mldp_group_pool, mcast_group_info); - - mi = mcast_group_info - a->mldp_group_pool; - mhash_set (&a->address_to_mldp_index, &addr, mi, /* old_value */ - 0); - - mcast_group_info->type = 4; - mcast_group_info->mcast_source_address_pool = 0; - mcast_group_info->num_sources = 0; - clib_memcpy (&mcast_group_info->mcast_address, &addr, - sizeof (ip6_address_t)); - } - - ip6_set_reserved_multicast_address (&addr, - IP6_MULTICAST_SCOPE_link_local, - IP6_MULTICAST_GROUP_ID_all_routers); - - p = mhash_get (&a->address_to_mldp_index, &addr); - mcast_group_info = - p ? pool_elt_at_index (a->mldp_group_pool, p[0]) : 0; - - if (!mcast_group_info) - { - /* add */ - u32 mi; - pool_get (a->mldp_group_pool, mcast_group_info); - - mi = mcast_group_info - a->mldp_group_pool; - mhash_set (&a->address_to_mldp_index, &addr, mi, /* old_value */ - 0); - - mcast_group_info->type = 4; - mcast_group_info->mcast_source_address_pool = 0; - mcast_group_info->num_sources = 0; - clib_memcpy (&mcast_group_info->mcast_address, &addr, - sizeof (ip6_address_t)); - } - - ip6_set_reserved_multicast_address (&addr, - IP6_MULTICAST_SCOPE_link_local, - IP6_MULTICAST_GROUP_ID_mldv2_routers); - - p = mhash_get (&a->address_to_mldp_index, &addr); - mcast_group_info = - p ? pool_elt_at_index (a->mldp_group_pool, p[0]) : 0; - - if (!mcast_group_info) - { - /* add */ - u32 mi; - pool_get (a->mldp_group_pool, mcast_group_info); - - mi = mcast_group_info - a->mldp_group_pool; - mhash_set (&a->address_to_mldp_index, &addr, mi, /* old_value */ - 0); - - mcast_group_info->type = 4; - mcast_group_info->mcast_source_address_pool = 0; - mcast_group_info->num_sources = 0; - clib_memcpy (&mcast_group_info->mcast_address, &addr, - sizeof (ip6_address_t)); - } + ip6_neighbor_add_mld_grp (a, + IP6_MULTICAST_SCOPE_link_local, + IP6_MULTICAST_GROUP_ID_all_hosts); + ip6_neighbor_add_mld_grp (a, + IP6_MULTICAST_SCOPE_link_local, + IP6_MULTICAST_GROUP_ID_all_routers); + ip6_neighbor_add_mld_grp (a, + IP6_MULTICAST_SCOPE_link_local, + IP6_MULTICAST_GROUP_ID_mldv2_routers); } } return ri; @@ -3695,7 +3677,9 @@ VLIB_CLI_COMMAND (set_ip6_link_local_address_command, static) = }; /* *INDENT-ON* */ -/* callback when an interface address is added or deleted */ +/** + * @brief callback when an interface address is added or deleted + */ static void ip6_neighbor_add_del_interface_address (ip6_main_t * im, uword opaque, @@ -3710,7 +3694,6 @@ ip6_neighbor_add_del_interface_address (ip6_main_t * im, vlib_main_t *vm = vnm->vlib_main; ip6_radv_t *radv_info; ip6_address_t a; - ip6_mldp_group_t *mcast_group_info; /* create solicited node multicast address for this interface adddress */ ip6_set_solicited_node_multicast_address (&a, 0); @@ -3737,28 +3720,7 @@ ip6_neighbor_add_del_interface_address (ip6_main_t * im, if (!ip6_address_is_link_local_unicast (address)) radv_info->ref_count++; - /* lookup prefix info for this address on this interface */ - uword *p = mhash_get (&radv_info->address_to_mldp_index, &a); - mcast_group_info = - p ? pool_elt_at_index (radv_info->mldp_group_pool, p[0]) : 0; - - /* add -solicted node multicast address */ - if (!mcast_group_info) - { - /* add */ - u32 mi; - pool_get (radv_info->mldp_group_pool, mcast_group_info); - - mi = mcast_group_info - radv_info->mldp_group_pool; - mhash_set (&radv_info->address_to_mldp_index, &a, mi, - /* old_value */ 0); - - mcast_group_info->type = 4; - mcast_group_info->mcast_source_address_pool = 0; - mcast_group_info->num_sources = 0; - clib_memcpy (&mcast_group_info->mcast_address, &a, - sizeof (ip6_address_t)); - } + ip6_neighbor_add_mld_prefix (radv_info, &a); } } else @@ -3775,17 +3737,7 @@ ip6_neighbor_add_del_interface_address (ip6_main_t * im, /* get radv_info */ radv_info = pool_elt_at_index (nm->if_radv_pool, ri); - /* lookup prefix info for this address on this interface */ - uword *p = mhash_get (&radv_info->address_to_mldp_index, &a); - mcast_group_info = - p ? pool_elt_at_index (radv_info->mldp_group_pool, p[0]) : 0; - - if (mcast_group_info) - { - mhash_unset (&radv_info->address_to_mldp_index, &a, - /* old_value */ 0); - pool_put (radv_info->mldp_group_pool, mcast_group_info); - } + ip6_neighbor_del_mld_prefix (radv_info, &a); /* if interface up send MLDP "report" */ radv_info->all_routers_mcast = 0; diff --git a/src/vppinfra/pool.h b/src/vppinfra/pool.h index 586d13e7..57838e1c 100644 --- a/src/vppinfra/pool.h +++ b/src/vppinfra/pool.h @@ -350,6 +350,7 @@ do { \ It is a bad idea to allocate or free pool element from within @c pool_foreach. Build a vector of indices and dispose of them later. + Or call pool_flush. @par Example @@ -421,6 +422,31 @@ do { \ do { body; } while (0); \ } +/** + * @brief Remove all elemenets from a pool in a safe way + * + * @param VAR each element in the pool + * @param POOL The pool to flush + * @param BODY The actions to perform on each element before it is returned to + * the pool. i.e. before it is 'freed' + */ +#define pool_flush(VAR, POOL, BODY) \ +{ \ + uword *_pool_var(ii), *_pool_var(dv) = NULL; \ + \ + pool_foreach((VAR), (POOL), \ + ({ \ + vec_add1(_pool_var(dv), (VAR) - (POOL)); \ + })); \ + vec_foreach(_pool_var(ii), _pool_var(dv)) \ + { \ + (VAR) = pool_elt_at_index((POOL), *_pool_var(ii)); \ + do { BODY; } while (0); \ + pool_put((POOL), (VAR)); \ + } \ + vec_free(_pool_var(dv)); \ +} + #endif /* included_pool_h */ /* diff --git a/test/test_ip6.py b/test/test_ip6.py index fb5383cf..b8278329 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 4588943d..53a0ae8d 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 fbd41eb5..5c2e3479 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 5d4d6b7e..fe152de3 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 From b3b2de71ceea0cc7ce18f89cc8180ed4a42e355d Mon Sep 17 00:00:00 2001 From: Neale Ranns Date: Wed, 8 Mar 2017 05:17:22 -0800 Subject: IMplementation for option to not create a FIB table entry when adding a neighbor entry Change-Id: I952039e101031ee6a06e63f4c73d8eb359423e1a Signed-off-by: Neale Ranns --- src/vat/api_format.c | 4 +++ src/vnet/ethernet/arp.c | 61 +++++++++++++++++++-------------- src/vnet/ethernet/arp_packet.h | 11 ++++-- src/vnet/ethernet/ethernet.h | 3 +- src/vnet/ip/ip6_neighbor.c | 59 ++++++++++++++++++++------------ src/vnet/ip/ip6_neighbor.h | 14 +++++--- src/vnet/ip/ip_api.c | 6 ++-- src/vpp/api/custom_dump.c | 3 ++ test/test_ip6.py | 28 +++++++++++++-- test/test_neighbor.py | 23 +++++++++++-- test/vpp_ip_route.py | 78 ++++++++++++++++++++++++------------------ test/vpp_neighbor.py | 6 ++-- test/vpp_papi_provider.py | 3 ++ 13 files changed, 203 insertions(+), 96 deletions(-) (limited to 'test/vpp_neighbor.py') diff --git a/src/vat/api_format.c b/src/vat/api_format.c index 08a2a774..0da31208 100644 --- a/src/vat/api_format.c +++ b/src/vat/api_format.c @@ -7132,6 +7132,7 @@ api_ip_neighbor_add_del (vat_main_t * vam) u8 sw_if_index_set = 0; u8 is_add = 1; u8 is_static = 0; + u8 is_no_fib_entry = 0; u8 mac_address[6]; u8 mac_set = 0; u8 v4_address_set = 0; @@ -7158,6 +7159,8 @@ api_ip_neighbor_add_del (vat_main_t * vam) sw_if_index_set = 1; else if (unformat (i, "is_static")) is_static = 1; + else if (unformat (i, "no-fib-entry")) + is_no_fib_entry = 1; else if (unformat (i, "dst %U", unformat_ip4_address, &v4address)) v4_address_set = 1; else if (unformat (i, "dst %U", unformat_ip6_address, &v6address)) @@ -7191,6 +7194,7 @@ api_ip_neighbor_add_del (vat_main_t * vam) mp->sw_if_index = ntohl (sw_if_index); mp->is_add = is_add; mp->is_static = is_static; + mp->is_no_adj_fib = is_no_fib_entry; if (mac_set) clib_memcpy (mp->mac_address, mac_address, 6); if (v6_address_set) diff --git a/src/vnet/ethernet/arp.c b/src/vnet/ethernet/arp.c index 222415b0..d8ae8443 100644 --- a/src/vnet/ethernet/arp.c +++ b/src/vnet/ethernet/arp.c @@ -100,6 +100,7 @@ typedef struct u32 sw_if_index; ethernet_arp_ip4_over_ethernet_address_t a; int is_static; + int is_no_fib_entry; int flags; #define ETHERNET_ARP_ARGS_REMOVE (1<<0) #define ETHERNET_ARP_ARGS_FLUSH (1<<1) @@ -254,6 +255,9 @@ format_ethernet_arp_ip4_entry (u8 * s, va_list * va) if (e->flags & ETHERNET_ARP_IP4_ENTRY_FLAG_DYNAMIC) flags = format (flags, "D"); + if (e->flags & ETHERNET_ARP_IP4_ENTRY_FLAG_NO_FIB_ENTRY) + flags = format (flags, "N"); + s = format (s, "%=12U%=16U%=6s%=20U%=24U", format_vlib_cpu_time, vnm->vlib_main, e->cpu_time_last_updated, format_ip4_address, &e->ip4_address, @@ -525,6 +529,7 @@ vnet_arp_set_ip4_over_ethernet_internal (vnet_main_t * vnm, ethernet_arp_interface_t *arp_int; int is_static = args->is_static; u32 sw_if_index = args->sw_if_index; + int is_no_fib_entry = args->is_no_fib_entry; vec_validate (am->ethernet_arp_by_sw_if_index, sw_if_index); @@ -546,16 +551,6 @@ vnet_arp_set_ip4_over_ethernet_internal (vnet_main_t * vnm, if (make_new_arp_cache_entry) { - fib_prefix_t pfx = { - .fp_len = 32, - .fp_proto = FIB_PROTOCOL_IP4, - .fp_addr = { - .ip4 = a->ip4, - } - , - }; - u32 fib_index; - pool_get (am->ip4_entry_pool, e); if (NULL == arp_int->arp_entries) @@ -570,17 +565,25 @@ vnet_arp_set_ip4_over_ethernet_internal (vnet_main_t * vnm, clib_memcpy (e->ethernet_address, a->ethernet, sizeof (e->ethernet_address)); - fib_index = ip4_fib_table_get_index_for_sw_if_index (e->sw_if_index); - e->fib_entry_index = - fib_table_entry_update_one_path (fib_index, - &pfx, - FIB_SOURCE_ADJ, - FIB_ENTRY_FLAG_ATTACHED, - FIB_PROTOCOL_IP4, - &pfx.fp_addr, - e->sw_if_index, - ~0, - 1, NULL, FIB_ROUTE_PATH_FLAG_NONE); + if (!is_no_fib_entry) + { + fib_prefix_t pfx = { + .fp_len = 32, + .fp_proto = FIB_PROTOCOL_IP4, + .fp_addr.ip4 = a->ip4, + }; + u32 fib_index; + + fib_index = + ip4_fib_table_get_index_for_sw_if_index (e->sw_if_index); + e->fib_entry_index = + fib_table_entry_update_one_path (fib_index, &pfx, FIB_SOURCE_ADJ, + FIB_ENTRY_FLAG_ATTACHED, + FIB_PROTOCOL_IP4, &pfx.fp_addr, + e->sw_if_index, ~0, 1, NULL, + FIB_ROUTE_PATH_FLAG_NONE); + e->flags |= ETHERNET_ARP_IP4_ENTRY_FLAG_NO_FIB_ENTRY; + } } else { @@ -1142,7 +1145,7 @@ arp_input (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) vnet_arp_set_ip4_over_ethernet (vnm, sw_if_index0, &arp0->ip4_over_ethernet[0], - 0 /* is_static */ ); + 0 /* is_static */ , 0); error0 = ETHERNET_ARP_ERROR_l3_src_address_learned; } @@ -1658,6 +1661,8 @@ arp_entry_free (ethernet_arp_interface_t * eai, ethernet_arp_ip4_entry_t * e) { ethernet_arp_main_t *am = ðernet_arp_main; + /* it's safe to delete the ADJ source on the FIB entry, even if it + * was added */ fib_table_entry_delete_index (e->fib_entry_index, FIB_SOURCE_ADJ); hash_unset (eai->arp_entries, e->ip4_address.as_u32); pool_put (am->ip4_entry_pool, e); @@ -1828,13 +1833,15 @@ increment_ip4_and_mac_address (ethernet_arp_ip4_over_ethernet_address_t * a) int vnet_arp_set_ip4_over_ethernet (vnet_main_t * vnm, - u32 sw_if_index, void *a_arg, int is_static) + u32 sw_if_index, void *a_arg, + int is_static, int is_no_fib_entry) { ethernet_arp_ip4_over_ethernet_address_t *a = a_arg; vnet_arp_set_ip4_over_ethernet_rpc_args_t args; args.sw_if_index = sw_if_index; args.is_static = is_static; + args.is_no_fib_entry = is_no_fib_entry; args.flags = 0; clib_memcpy (&args.a, a, sizeof (*a)); @@ -1931,6 +1938,7 @@ ip_arp_add_del_command_fn (vlib_main_t * vm, u32 fib_index = 0; u32 fib_id; int is_static = 0; + int is_no_fib_entry = 0; int is_proxy = 0; while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) @@ -1948,6 +1956,9 @@ ip_arp_add_del_command_fn (vlib_main_t * vm, else if (unformat (input, "static")) is_static = 1; + else if (unformat (input, "no-fib-entry")) + is_no_fib_entry = 1; + else if (unformat (input, "count %d", &count)) ; @@ -1991,7 +2002,7 @@ ip_arp_add_del_command_fn (vlib_main_t * vm, 1 /* type */ , 0 /* data */ ); vnet_arp_set_ip4_over_ethernet - (vnm, sw_if_index, &addr, is_static); + (vnm, sw_if_index, &addr, is_static, is_no_fib_entry); vlib_process_wait_for_event (vm); event_type = vlib_process_get_events (vm, &event_data); @@ -2046,7 +2057,7 @@ ip_arp_add_del_command_fn (vlib_main_t * vm, VLIB_CLI_COMMAND (ip_arp_add_del_command, static) = { .path = "set ip arp", .short_help = - "set ip arp [del] [static] [count ] [fib-id ] [proxy - ]", + "set ip arp [del] [static] [no-fib-entry] [count ] [fib-id ] [proxy - ]", .function = ip_arp_add_del_command_fn, }; /* *INDENT-ON* */ diff --git a/src/vnet/ethernet/arp_packet.h b/src/vnet/ethernet/arp_packet.h index e762ffa4..17e64f43 100644 --- a/src/vnet/ethernet/arp_packet.h +++ b/src/vnet/ethernet/arp_packet.h @@ -140,6 +140,13 @@ typedef struct }; } ethernet_arp_header_t; +typedef enum ethernet_arp_entry_flags_t_ +{ + ETHERNET_ARP_IP4_ENTRY_FLAG_STATIC = (1 << 0), + ETHERNET_ARP_IP4_ENTRY_FLAG_DYNAMIC = (1 << 1), + ETHERNET_ARP_IP4_ENTRY_FLAG_NO_FIB_ENTRY = (1 << 2), +} __attribute__ ((packed)) ethernet_arp_entry_flags_t; + typedef struct { u32 sw_if_index; @@ -147,9 +154,7 @@ typedef struct u8 ethernet_address[6]; - u16 flags; -#define ETHERNET_ARP_IP4_ENTRY_FLAG_STATIC (1 << 0) -#define ETHERNET_ARP_IP4_ENTRY_FLAG_DYNAMIC (1 << 1) + ethernet_arp_entry_flags_t flags; u64 cpu_time_last_updated; diff --git a/src/vnet/ethernet/ethernet.h b/src/vnet/ethernet/ethernet.h index ba84c69c..dcc656a7 100644 --- a/src/vnet/ethernet/ethernet.h +++ b/src/vnet/ethernet/ethernet.h @@ -403,7 +403,8 @@ void ethernet_set_rx_redirect (vnet_main_t * vnm, vnet_hw_interface_t * hi, int vnet_arp_set_ip4_over_ethernet (vnet_main_t * vnm, - u32 sw_if_index, void *a_arg, int is_static); + u32 sw_if_index, void *a_arg, + int is_static, int is_no_fib_entry); int vnet_arp_unset_ip4_over_ethernet (vnet_main_t * vnm, diff --git a/src/vnet/ip/ip6_neighbor.c b/src/vnet/ip/ip6_neighbor.c index 715891b8..8d355ab2 100644 --- a/src/vnet/ip/ip6_neighbor.c +++ b/src/vnet/ip/ip6_neighbor.c @@ -235,6 +235,9 @@ format_ip6_neighbor_ip6_entry (u8 * s, va_list * va) if (n->flags & IP6_NEIGHBOR_FLAG_STATIC) flags = format (flags, "S"); + if (n->flags & IP6_NEIGHBOR_FLAG_NO_FIB_ENTRY) + flags = format (flags, "N"); + si = vnet_get_sw_interface (vnm, n->key.sw_if_index); s = format (s, "%=12U%=20U%=6s%=20U%=40U", format_vlib_cpu_time, vm, n->cpu_time_last_updated, @@ -317,6 +320,7 @@ typedef struct { u8 is_add; u8 is_static; + u8 is_no_fib_entry; u8 link_layer_address[6]; u32 sw_if_index; ip6_address_t addr; @@ -328,7 +332,8 @@ static void ip6_neighbor_set_unset_rpc_callback static void set_unset_ip6_neighbor_rpc (vlib_main_t * vm, u32 sw_if_index, - ip6_address_t * a, u8 * link_layer_address, int is_add, int is_static) + ip6_address_t * a, u8 * link_layer_address, int is_add, int is_static, + int is_no_fib_entry) { ip6_neighbor_set_unset_rpc_args_t args; void vl_api_rpc_call_main_thread (void *fp, u8 * data, u32 data_length); @@ -336,6 +341,7 @@ static void set_unset_ip6_neighbor_rpc args.sw_if_index = sw_if_index; args.is_add = is_add; args.is_static = is_static; + args.is_no_fib_entry = is_no_fib_entry; clib_memcpy (&args.addr, a, sizeof (*a)); if (NULL != link_layer_address) clib_memcpy (args.link_layer_address, link_layer_address, 6); @@ -565,7 +571,7 @@ vnet_set_ip6_ethernet_neighbor (vlib_main_t * vm, ip6_address_t * a, u8 * link_layer_address, uword n_bytes_link_layer_address, - int is_static) + int is_static, int is_no_fib_entry) { ip6_neighbor_main_t *nm = &ip6_neighbor_main; ip6_neighbor_key_t k; @@ -578,7 +584,8 @@ vnet_set_ip6_ethernet_neighbor (vlib_main_t * vm, if (os_get_cpu_number ()) { set_unset_ip6_neighbor_rpc (vm, sw_if_index, a, link_layer_address, - 1 /* set new neighbor */ , is_static); + 1 /* set new neighbor */ , is_static, + is_no_fib_entry); return 0; } @@ -598,16 +605,6 @@ vnet_set_ip6_ethernet_neighbor (vlib_main_t * vm, if (make_new_nd_cache_entry) { - fib_prefix_t pfx = { - .fp_len = 128, - .fp_proto = FIB_PROTOCOL_IP6, - .fp_addr = { - .ip6 = k.ip6_address, - } - , - }; - u32 fib_index; - pool_get (nm->neighbor_pool, n); mhash_set (&nm->neighbor_index_by_key, &k, n - nm->neighbor_pool, /* old value */ 0); @@ -619,9 +616,25 @@ vnet_set_ip6_ethernet_neighbor (vlib_main_t * vm, /* * create the adj-fib. the entry in the FIB table for and to the peer. */ - fib_index = ip6_main.fib_index_by_sw_if_index[n->key.sw_if_index]; - n->fib_entry_index = fib_table_entry_update_one_path (fib_index, &pfx, FIB_SOURCE_ADJ, FIB_ENTRY_FLAG_NONE, FIB_PROTOCOL_IP6, &pfx.fp_addr, n->key.sw_if_index, ~0, 1, NULL, // no label stack - FIB_ROUTE_PATH_FLAG_NONE); + if (!is_no_fib_entry) + { + fib_prefix_t pfx = { + .fp_len = 128, + .fp_proto = FIB_PROTOCOL_IP6, + .fp_addr.ip6 = k.ip6_address, + }; + u32 fib_index; + + fib_index = ip6_main.fib_index_by_sw_if_index[n->key.sw_if_index]; + n->fib_entry_index = + fib_table_entry_update_one_path (fib_index, &pfx, + FIB_SOURCE_ADJ, + FIB_ENTRY_FLAG_NONE, + FIB_PROTOCOL_IP6, &pfx.fp_addr, + n->key.sw_if_index, ~0, 1, NULL, + FIB_ROUTE_PATH_FLAG_NONE); + n->flags |= IP6_NEIGHBOR_FLAG_NO_FIB_ENTRY; + } } else { @@ -712,7 +725,7 @@ vnet_unset_ip6_ethernet_neighbor (vlib_main_t * vm, if (os_get_cpu_number ()) { set_unset_ip6_neighbor_rpc (vm, sw_if_index, a, link_layer_address, - 0 /* unset */ , 0); + 0 /* unset */ , 0, 0); return 0; } @@ -746,7 +759,8 @@ static void ip6_neighbor_set_unset_rpc_callback vlib_main_t *vm = vlib_get_main (); if (a->is_add) vnet_set_ip6_ethernet_neighbor (vm, a->sw_if_index, &a->addr, - a->link_layer_address, 6, a->is_static); + a->link_layer_address, 6, a->is_static, + a->is_no_fib_entry); else vnet_unset_ip6_ethernet_neighbor (vm, a->sw_if_index, &a->addr, a->link_layer_address, 6); @@ -850,6 +864,7 @@ set_ip6_neighbor (vlib_main_t * vm, int addr_valid = 0; int is_del = 0; int is_static = 0; + int is_no_fib_entry = 0; u32 sw_if_index; while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) @@ -865,6 +880,8 @@ set_ip6_neighbor (vlib_main_t * vm, is_del = 1; else if (unformat (input, "static")) is_static = 1; + else if (unformat (input, "no-fib-entry")) + is_no_fib_entry = 1; else break; } @@ -875,7 +892,7 @@ set_ip6_neighbor (vlib_main_t * vm, if (!is_del) vnet_set_ip6_ethernet_neighbor (vm, sw_if_index, &addr, mac_address, sizeof (mac_address), - is_static); + is_static, is_no_fib_entry); else vnet_unset_ip6_ethernet_neighbor (vm, sw_if_index, &addr, mac_address, sizeof (mac_address)); @@ -1023,7 +1040,7 @@ icmp6_neighbor_solicitation_or_advertisement (vlib_main_t * vm, &h0->target_address, o0->ethernet_address, sizeof (o0->ethernet_address), - 0); + 0, 0); } if (is_solicitation && error0 == ICMP6_ERROR_NONE) @@ -1338,7 +1355,7 @@ icmp6_router_solicitation (vlib_main_t * vm, &ip0->src_address, o0->ethernet_address, sizeof (o0->ethernet_address), - 0); + 0, 0); } /* default is to drop */ diff --git a/src/vnet/ip/ip6_neighbor.h b/src/vnet/ip/ip6_neighbor.h index 3d256316..ef1e84c2 100644 --- a/src/vnet/ip/ip6_neighbor.h +++ b/src/vnet/ip/ip6_neighbor.h @@ -28,13 +28,18 @@ typedef struct u32 pad; } ip6_neighbor_key_t; +typedef enum ip6_neighbor_flags_t_ +{ + IP6_NEIGHBOR_FLAG_STATIC = (1 << 0), + IP6_NEIGHBOR_FLAG_DYNAMIC = (1 << 1), + IP6_NEIGHBOR_FLAG_NO_FIB_ENTRY = (1 << 2), +} __attribute__ ((packed)) ip6_neighbor_flags_t; + typedef struct { ip6_neighbor_key_t key; u8 link_layer_address[8]; - u16 flags; -#define IP6_NEIGHBOR_FLAG_STATIC (1 << 0) -#define IP6_NEIGHBOR_FLAG_DYNAMIC (2 << 0) + ip6_neighbor_flags_t flags; u64 cpu_time_last_updated; fib_node_index_t fib_entry_index; } ip6_neighbor_t; @@ -69,7 +74,8 @@ extern int vnet_set_ip6_ethernet_neighbor (vlib_main_t * vm, ip6_address_t * a, u8 * link_layer_address, uword n_bytes_link_layer_address, - int is_static); + int is_static, + int is_no_fib_entry); extern int vnet_unset_ip6_ethernet_neighbor (vlib_main_t * vm, u32 sw_if_index, diff --git a/src/vnet/ip/ip_api.c b/src/vnet/ip/ip_api.c index 0ca058ab..e3a1fee8 100644 --- a/src/vnet/ip/ip_api.c +++ b/src/vnet/ip/ip_api.c @@ -655,7 +655,8 @@ vl_api_ip_neighbor_add_del_t_handler (vl_api_ip_neighbor_add_del_t * mp, rv = vnet_set_ip6_ethernet_neighbor (vm, ntohl (mp->sw_if_index), (ip6_address_t *) (mp->dst_address), - mp->mac_address, sizeof (mp->mac_address), mp->is_static); + mp->mac_address, sizeof (mp->mac_address), mp->is_static, + mp->is_no_adj_fib); else rv = vnet_unset_ip6_ethernet_neighbor (vm, ntohl (mp->sw_if_index), @@ -671,7 +672,8 @@ vl_api_ip_neighbor_add_del_t_handler (vl_api_ip_neighbor_add_del_t * mp, if (mp->is_add) rv = vnet_arp_set_ip4_over_ethernet (vnm, ntohl (mp->sw_if_index), - &a, mp->is_static); + &a, mp->is_static, + mp->is_no_adj_fib); else rv = vnet_arp_unset_ip4_over_ethernet (vnm, ntohl (mp->sw_if_index), &a); diff --git a/src/vpp/api/custom_dump.c b/src/vpp/api/custom_dump.c index 8250279e..648ac5f3 100644 --- a/src/vpp/api/custom_dump.c +++ b/src/vpp/api/custom_dump.c @@ -593,6 +593,9 @@ static void *vl_api_ip_neighbor_add_del_t_print if (mp->is_static) s = format (s, "is_static "); + if (mp->is_no_adj_fib) + s = format (s, "is_no_fib_entry "); + if (memcmp (mp->mac_address, null_mac, 6)) s = format (s, "mac %U ", format_ethernet_address, mp->mac_address); diff --git a/test/test_ip6.py b/test/test_ip6.py index b95809b1..e57e034d 100644 --- a/test/test_ip6.py +++ b/test/test_ip6.py @@ -6,8 +6,8 @@ from socket import AF_INET6 from framework import VppTestCase, VppTestRunner from vpp_sub_interface import VppSubInterface, VppDot1QSubint from vpp_pg_interface import is_ipv6_misc -from vpp_neighbor import find_nbr -from vpp_ip_route import VppIpRoute, VppRoutePath +from vpp_ip_route import VppIpRoute, VppRoutePath, find_route +from vpp_neighbor import find_nbr, VppNeighbor from scapy.packet import Raw from scapy.layers.l2 import Ether, Dot1Q @@ -351,6 +351,30 @@ class TestIPv6(TestIPv6ND): self.send_and_assert_no_replies(self.pg0, pkts, "No response to NS for unknown target") + # + # A neighbor entry that has no associated FIB-entry + # + self.pg0.generate_remote_hosts(4) + nd_entry = VppNeighbor(self, + self.pg0.sw_if_index, + self.pg0.remote_hosts[2].mac, + self.pg0.remote_hosts[2].ip6, + af=AF_INET6, + is_no_fib_entry=1) + nd_entry.add_vpp_config() + + # + # check we have the neighbor, but no route + # + self.assertTrue(find_nbr(self, + self.pg0.sw_if_index, + self.pg0._remote_hosts[2].ip6, + inet=AF_INET6)) + self.assertFalse(find_route(self, + self.pg0._remote_hosts[2].ip6, + 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 diff --git a/test/test_neighbor.py b/test/test_neighbor.py index 2ce0a635..1dfae241 100644 --- a/test/test_neighbor.py +++ b/test/test_neighbor.py @@ -5,7 +5,7 @@ from socket import AF_INET, AF_INET6, inet_pton from framework import VppTestCase, VppTestRunner from vpp_neighbor import VppNeighbor, find_nbr -from vpp_ip_route import VppIpRoute, VppRoutePath +from vpp_ip_route import VppIpRoute, VppRoutePath, find_route from scapy.packet import Raw from scapy.layers.l2 import Ether, ARP @@ -115,7 +115,7 @@ class ARPTestCase(VppTestCase): # # Generate some hosts on the LAN # - self.pg1.generate_remote_hosts(4) + self.pg1.generate_remote_hosts(5) # # Send IP traffic to one of these unresolved hosts. @@ -301,6 +301,25 @@ class ARPTestCase(VppTestCase): "ARP req for non-local source") # + # A neighbor entry that has no associated FIB-entry + # + arp_no_fib = VppNeighbor(self, + self.pg1.sw_if_index, + self.pg1.remote_hosts[4].mac, + self.pg1.remote_hosts[4].ip4, + is_no_fib_entry=1) + arp_no_fib.add_vpp_config() + + # + # check we have the neighbor, but no route + # + self.assertTrue(find_nbr(self, + self.pg1.sw_if_index, + self.pg1._remote_hosts[4].ip4)) + self.assertFalse(find_route(self, + self.pg1._remote_hosts[4].ip4, + 32)) + # # cleanup # dyn_arp.remove_vpp_config() diff --git a/test/vpp_ip_route.py b/test/vpp_ip_route.py index 247263a3..7a62b230 100644 --- a/test/vpp_ip_route.py +++ b/test/vpp_ip_route.py @@ -4,14 +4,31 @@ object abstractions for representing IP routes in VPP """ -import socket from vpp_object import * +from socket import inet_pton, inet_ntop, AF_INET, AF_INET6 # from vnet/vnet/mpls/mpls_types.h MPLS_IETF_MAX_LABEL = 0xfffff MPLS_LABEL_INVALID = MPLS_IETF_MAX_LABEL + 1 +def find_route(test, ip_addr, len, table_id=0, inet=AF_INET): + if inet == AF_INET: + s = 4 + routes = test.vapi.ip_fib_dump() + else: + s = 16 + routes = test.vapi.ip6_fib_dump() + + route_addr = inet_pton(inet, ip_addr) + for e in routes: + if route_addr == e.address[:s] \ + and len == e.address_length \ + and table_id == e.table_id: + return True + return False + + class VppRoutePath(object): def __init__( @@ -27,9 +44,9 @@ class VppRoutePath(object): self.nh_via_label = nh_via_label self.nh_labels = labels if is_ip6: - self.nh_addr = socket.inet_pton(socket.AF_INET6, nh_addr) + self.nh_addr = inet_pton(AF_INET6, nh_addr) else: - self.nh_addr = socket.inet_pton(socket.AF_INET, nh_addr) + self.nh_addr = inet_pton(AF_INET, nh_addr) class VppMRoutePath(VppRoutePath): @@ -56,17 +73,18 @@ class VppIpRoute(VppObject): self.is_local = is_local self.is_unreach = is_unreach self.is_prohibit = is_prohibit + self.dest_addr_p = dest_addr if is_ip6: - self.dest_addr = socket.inet_pton(socket.AF_INET6, dest_addr) + self.dest_addr = inet_pton(AF_INET6, dest_addr) else: - self.dest_addr = socket.inet_pton(socket.AF_INET, dest_addr) + self.dest_addr = inet_pton(AF_INET, dest_addr) def add_vpp_config(self): if self.is_local or self.is_unreach or self.is_prohibit: self._test.vapi.ip_add_del_route( self.dest_addr, self.dest_addr_len, - socket.inet_pton(socket.AF_INET6, "::"), + inet_pton(AF_INET6, "::"), 0xffffffff, is_local=self.is_local, is_unreach=self.is_unreach, @@ -93,7 +111,7 @@ class VppIpRoute(VppObject): self._test.vapi.ip_add_del_route( self.dest_addr, self.dest_addr_len, - socket.inet_pton(socket.AF_INET6, "::"), + inet_pton(AF_INET6, "::"), 0xffffffff, is_local=self.is_local, is_unreach=self.is_unreach, @@ -111,28 +129,20 @@ class VppIpRoute(VppObject): is_add=0) def query_vpp_config(self): - dump = self._test.vapi.ip_fib_dump() - for e in dump: - if self.dest_addr == e.address \ - and self.dest_addr_len == e.address_length \ - and self.table_id == e.table_id: - return True - return False + return find_route(self._test, + self.dest_addr_p, + self.dest_addr_len, + self.table_id, + inet=AF_INET6 if self.is_ip6 == 1 else AF_INET) def __str__(self): return self.object_id() def object_id(self): - if self.is_ip6: - return ("%d:%s/%d" - % (self.table_id, - socket.inet_ntop(socket.AF_INET6, self.dest_addr), - self.dest_addr_len)) - else: - return ("%d:%s/%d" - % (self.table_id, - socket.inet_ntop(socket.AF_INET, self.dest_addr), - self.dest_addr_len)) + return ("%d:%s/%d" + % (self.table_id, + self.dest_addr_p, + self.dest_addr_len)) class VppIpMRoute(VppObject): @@ -150,11 +160,11 @@ class VppIpMRoute(VppObject): self.is_ip6 = is_ip6 if is_ip6: - self.grp_addr = socket.inet_pton(socket.AF_INET6, grp_addr) - self.src_addr = socket.inet_pton(socket.AF_INET6, src_addr) + self.grp_addr = inet_pton(AF_INET6, grp_addr) + self.src_addr = inet_pton(AF_INET6, src_addr) else: - self.grp_addr = socket.inet_pton(socket.AF_INET, grp_addr) - self.src_addr = socket.inet_pton(socket.AF_INET, src_addr) + self.grp_addr = inet_pton(AF_INET, grp_addr) + self.src_addr = inet_pton(AF_INET, src_addr) def add_vpp_config(self): for path in self.paths: @@ -221,14 +231,14 @@ class VppIpMRoute(VppObject): if self.is_ip6: return ("%d:(%s,%s/%d)" % (self.table_id, - socket.inet_ntop(socket.AF_INET6, self.src_addr), - socket.inet_ntop(socket.AF_INET6, self.grp_addr), + inet_ntop(AF_INET6, self.src_addr), + inet_ntop(AF_INET6, self.grp_addr), self.grp_addr_len)) else: return ("%d:(%s,%s/%d)" % (self.table_id, - socket.inet_ntop(socket.AF_INET, self.src_addr), - socket.inet_ntop(socket.AF_INET, self.grp_addr), + inet_ntop(AF_INET, self.src_addr), + inet_ntop(AF_INET, self.grp_addr), self.grp_addr_len)) @@ -261,7 +271,7 @@ class VppMplsIpBind(VppObject): def __init__(self, test, local_label, dest_addr, dest_addr_len, table_id=0, ip_table_id=0): self._test = test - self.dest_addr = socket.inet_pton(socket.AF_INET, dest_addr) + self.dest_addr = inet_pton(AF_INET, dest_addr) self.dest_addr_len = dest_addr_len self.local_label = local_label self.table_id = table_id @@ -298,7 +308,7 @@ class VppMplsIpBind(VppObject): % (self.table_id, self.local_label, self.ip_table_id, - socket.inet_ntop(socket.AF_INET, self.dest_addr), + inet_ntop(AF_INET, self.dest_addr), self.dest_addr_len)) diff --git a/test/vpp_neighbor.py b/test/vpp_neighbor.py index 5c2e3479..6968b5f6 100644 --- a/test/vpp_neighbor.py +++ b/test/vpp_neighbor.py @@ -31,12 +31,13 @@ class VppNeighbor(VppObject): """ def __init__(self, test, sw_if_index, mac_addr, nbr_addr, - af=AF_INET, is_static=False): + af=AF_INET, is_static=False, is_no_fib_entry=False): self._test = test self.sw_if_index = sw_if_index self.mac_addr = mactobinary(mac_addr) self.af = af self.is_static = is_static + self.is_no_fib_entry = is_no_fib_entry self.nbr_addr = inet_pton(af, nbr_addr) def add_vpp_config(self): @@ -46,7 +47,8 @@ class VppNeighbor(VppObject): self.nbr_addr, is_add=1, is_ipv6=1 if AF_INET6 == self.af else 0, - is_static=self.is_static) + is_static=self.is_static, + is_no_adj_fib=self.is_no_fib_entry) self._test.registry.register(self, self._test.logger) def remove_vpp_config(self): diff --git a/test/vpp_papi_provider.py b/test/vpp_papi_provider.py index 92070424..2d683dc2 100644 --- a/test/vpp_papi_provider.py +++ b/test/vpp_papi_provider.py @@ -663,6 +663,7 @@ class VppPapiProvider(object): is_add=1, is_ipv6=0, is_static=0, + is_no_adj_fib=0, ): """ Add neighbor MAC to IPv4 or IPv6 address. @@ -672,6 +673,7 @@ class VppPapiProvider(object): :param is_add: (Default value = 1) :param is_ipv6: (Default value = 0) :param is_static: (Default value = 0) + :param is_no_adj_fib: (Default value = 0) """ return self.api( @@ -680,6 +682,7 @@ class VppPapiProvider(object): 'is_add': is_add, 'is_ipv6': is_ipv6, 'is_static': is_static, + 'is_no_adj_fib': is_no_adj_fib, 'mac_address': mac_address, 'dst_address': dst_address } -- cgit 1.2.3-korg From 2a3ea49d5cc224ffb2cf02bacaf0c02ddae12b86 Mon Sep 17 00:00:00 2001 From: Neale Ranns Date: Wed, 19 Apr 2017 05:24:40 -0700 Subject: Learn IP6 link-local ND entries from NSs sourced from link-local address Change-Id: I4c3ce4d58df7977490fc94991291422ea1e31ee3 Signed-off-by: Neale Ranns --- src/vnet/ethernet/arp.c | 3 ++ src/vnet/ip/ip6_neighbor.c | 7 ++- test/test_dhcp.py | 8 +--- test/test_ip6.py | 106 ++++++++++++++++++++++++++++++++++----------- test/util.py | 21 ++++++++- test/vpp_interface.py | 18 +++++++- test/vpp_neighbor.py | 2 +- 7 files changed, 126 insertions(+), 39 deletions(-) (limited to 'test/vpp_neighbor.py') diff --git a/src/vnet/ethernet/arp.c b/src/vnet/ethernet/arp.c index 3e292e4d..31af4fba 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 42edb79a..31182770 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 89667d3d..03c749d3 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 a8e8d4de..3ba09230 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 d6b77f9d..aeba2ab4 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 5dba0978..662015ea 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 @@ -54,6 +54,16 @@ class VppInterface(object): """Local IPv6 address - raw, suitable as API parameter.""" 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.""" @@ -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 6968b5f6..5919cf8e 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) -- cgit 1.2.3-korg