From nobody Mon May 30 10:54:04 2022 X-Original-To: dev-commits-src-main@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 82A0D1B65A6B; Mon, 30 May 2022 10:54:05 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4LBXMx1cJ6z4q5N; Mon, 30 May 2022 10:54:04 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1653908045; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=sjkAc3FNAIGydAkhNVAfkPN9Rc6UAotsBkAdThLhCgw=; b=fsDsr7oUbOEvr14y/tqS+XKjSwV2jorWSU1YGldQ7dJ1yFISajqfrkYiwxDfSSCzEhvltF HH15Sap1ophVs0kiFRyKQq0R2Bf3WdIzgpfPamKdNkLyeHGwjIEckj6zgvGg7mAFglySAV JmB83/WvT0h0yKyaoNn8/q+jG2iLh6CM/04eqmAI3FJk4Vex9ZQuw1dOOzhQRsK7PAhNft ApTU3s5n3lR3dotC9GtIZMXXQkVazMDaDDxpgoGls1JgT4kXsJ/+oalYDj/EYAWYDcLDFp 1pxOqjXSnKyojG7cEhtk2ps4VMfqJd55XnjVysW3qnb6zyXuFI94nztFzP74Hw== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id B573315DD5; Mon, 30 May 2022 10:54:04 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.16.1/8.16.1) with ESMTP id 24UAs4K8066925; Mon, 30 May 2022 10:54:04 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.16.1/8.16.1/Submit) id 24UAs4m6066923; Mon, 30 May 2022 10:54:04 GMT (envelope-from git) Date: Mon, 30 May 2022 10:54:04 GMT Message-Id: <202205301054.24UAs4m6066923@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: "Alexander V. Chernikov" Subject: git: d6cd20cc5c47 - main - netinet6: fix ndp proxying List-Id: Commit messages for the main branch of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-main List-Help: List-Post: List-Subscribe: List-Unsubscribe: Sender: owner-dev-commits-src-main@freebsd.org X-BeenThere: dev-commits-src-main@freebsd.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: melifaro X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: d6cd20cc5c475e8bbf257ac1474ff490ae4dcab6 Auto-Submitted: auto-generated ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1653908045; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=sjkAc3FNAIGydAkhNVAfkPN9Rc6UAotsBkAdThLhCgw=; b=WU4If6XCVliwVjfPv8RodRZMLkKAnREOOfUsDXWRhQ644p/YgvOcVhKiEPzBJ40LvrPIkr 5zEgwziHpznzW3z1Y6Zlb9sEhRXexOIZCDEiS2q4ms0k/P54IT3G9tvPQ5JiPB5BrT90MQ 2hUfNZGw3YCiY3nTaUWG2HdL0QadnEtCEt4hqg3E7cs1X6J2EQABjBJJuK0tXezIw8TDSu Ov6XWSV/4ZhlM2/fEqlcTZjZr6EjPD34Z0uL0qq593OvxYCFRglbr4V/1/HtxYPqPRaTS6 ZMBPYDiCVYbFov0zAWeyNpLVSWCfOfpWXH5l4gI/pPJrdWPEPl/nc1zRbcOdzA== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1653908045; a=rsa-sha256; cv=none; b=EoFSepNnHewf6ChBZ/vjuqmXMAx1gCo5V+HnmwZ9gCv55Yn1bQ/uA+x0whJwsy12W7poe4 1IzaPCLKCo7TJ+qUIrey3rBKy70+AB/t1djOGXgVOvuQ78pcVhrCED7B3pwKjsQ0gbaLtG rJCJMWLH6wr+cXSrqRj7ep4916IHn1MCmOuA7+df9OsuY74IS0L+aHOioF2Hlnzu4YjiPa ud4IcjJBjHyvarreoVtGqGgpPT6Viypb383buDCe3OvBismiLFjVb4v6J1CKty12LaKqSA i46EsEY2M02aAgXEmV6dl69wW8UxU8qqJ2kQy5C43OdHtcaMyr8fV8G8oT0N4A== ARC-Authentication-Results: i=1; mx1.freebsd.org; none X-ThisMailContainsUnwantedMimeParts: N The branch main has been updated by melifaro: URL: https://cgit.FreeBSD.org/src/commit/?id=d6cd20cc5c475e8bbf257ac1474ff490ae4dcab6 commit d6cd20cc5c475e8bbf257ac1474ff490ae4dcab6 Author: KUROSAWA Takahiro AuthorDate: 2022-05-30 07:51:15 +0000 Commit: Alexander V. Chernikov CommitDate: 2022-05-30 10:53:33 +0000 netinet6: fix ndp proxying We could insert proxy NDP entries by the ndp command, but the host with proxy ndp entries had not responded to Neighbor Solicitations. Change the following points for proxy NDP to work as expected: * join solicited-node multicast addresses for proxy NDP entries in order to receive Neighbor Solicitations. * look up proxy NDP entries not on the routing table but on the link-level address table when receiving Neighbor Solicitations. Reviewed By: melifaro Differential Revision: https://reviews.freebsd.org/D35307 MFC after: 2 weeks --- sys/net/if.c | 10 ++ sys/net/if_llatbl.c | 48 +++++++++ sys/net/if_llatbl.h | 12 ++- sys/netinet6/in6.c | 111 ++++++++++++++++++-- sys/netinet6/in6_var.h | 2 + sys/netinet6/nd6_nbr.c | 57 ++++++----- tests/sys/netinet6/Makefile | 3 +- tests/sys/netinet6/proxy_ndp.sh | 222 ++++++++++++++++++++++++++++++++++++++++ 8 files changed, 425 insertions(+), 40 deletions(-) diff --git a/sys/net/if.c b/sys/net/if.c index c50cc2d291e2..8f463d0bfa58 100644 --- a/sys/net/if.c +++ b/sys/net/if.c @@ -1017,6 +1017,16 @@ if_purgeaddrs(struct ifnet *ifp) { struct ifaddr *ifa; +#ifdef INET6 + /* + * Need to leave multicast addresses of proxy NDP llentries + * before in6_purgeifaddr() because the llentries are keys + * for in6_multi objects of proxy NDP entries. + * in6_purgeifaddr()s clean up llentries including proxy NDPs + * then we would lose the keys if they are called earlier. + */ + in6_purge_proxy_ndp(ifp); +#endif while (1) { struct epoch_tracker et; diff --git a/sys/net/if_llatbl.c b/sys/net/if_llatbl.c index 1e7229ba95ca..b7ea4bc8e4ea 100644 --- a/sys/net/if_llatbl.c +++ b/sys/net/if_llatbl.c @@ -730,6 +730,51 @@ lltable_prefix_free(int af, struct sockaddr *addr, struct sockaddr *mask, LLTABLE_LIST_RUNLOCK(); } +/* + * Delete llentries that func() returns true. + */ +struct lle_match_data { + struct llentries dchain; + llt_match_cb_t *func; + void *farg; +}; + +static int +lltable_delete_conditional_cb(struct lltable *llt, struct llentry *lle, + void *farg) +{ + struct lle_match_data *lmd; + + lmd = (struct lle_match_data *)farg; + if (lmd->func(llt, lle, lmd->farg)) { + LLE_WLOCK(lle); + CK_LIST_INSERT_HEAD(&lmd->dchain, lle, lle_chain); + } + + return (0); +} + +void +lltable_delete_conditional(struct lltable *llt, llt_match_cb_t *func, + void *farg) +{ + struct llentry *lle, *next; + struct lle_match_data lmd; + + bzero(&lmd, sizeof(lmd)); + CK_LIST_INIT(&lmd.dchain); + lmd.func = func; + lmd.farg = farg; + + IF_AFDATA_WLOCK(llt->llt_ifp); + lltable_foreach_lle(llt, lltable_delete_conditional_cb, &lmd); + llentries_unlink(llt, &lmd.dchain); + IF_AFDATA_WUNLOCK(llt->llt_ifp); + + CK_LIST_FOREACH_SAFE(lle, &lmd.dchain, lle_chain, next) + llt->llt_delete_entry(llt, lle); +} + struct lltable * lltable_allocate_htbl(uint32_t hsize) { @@ -955,6 +1000,9 @@ lla_rt_output(struct rt_msghdr *rtm, struct rt_addrinfo *info) lltable_unlink_entry(llt, lle_tmp); } lltable_link_entry(llt, lle); + if ((lle->la_flags & LLE_PUB) != 0 && + (llt->llt_flags & LLT_ADDEDPROXY) == 0) + llt->llt_flags |= LLT_ADDEDPROXY; IF_AFDATA_WUNLOCK(ifp); if (lle_tmp != NULL) { diff --git a/sys/net/if_llatbl.h b/sys/net/if_llatbl.h index a290fb2349aa..5c5dd7a9e08f 100644 --- a/sys/net/if_llatbl.h +++ b/sys/net/if_llatbl.h @@ -164,11 +164,13 @@ typedef void (llt_post_resolved_t)(struct lltable *, struct llentry *); typedef int (llt_foreach_cb_t)(struct lltable *, struct llentry *, void *); typedef int (llt_foreach_entry_t)(struct lltable *, llt_foreach_cb_t *, void *); +typedef bool (llt_match_cb_t)(struct lltable *, struct llentry *, void *); struct lltable { SLIST_ENTRY(lltable) llt_link; sa_family_t llt_af; - uint8_t llt_spare[3]; + uint8_t llt_flags; + uint8_t llt_spare[2]; int llt_hsize; int llt_entries; int llt_maxentries; @@ -194,6 +196,11 @@ struct lltable { MALLOC_DECLARE(M_LLTABLE); +/* + * LLtable flags + */ +#define LLT_ADDEDPROXY 0x01 /* added a proxy llentry */ + /* * LLentry flags */ @@ -258,6 +265,9 @@ bool lltable_acquire_wlock(struct ifnet *ifp, struct llentry *lle); int lltable_foreach_lle(struct lltable *llt, llt_foreach_cb_t *f, void *farg); +void lltable_delete_conditional(struct lltable *llt, llt_match_cb_t *func, + void *farg); + /* * Generic link layer address lookup function. */ diff --git a/sys/netinet6/in6.c b/sys/netinet6/in6.c index a39f7734e0ba..857e05c0f112 100644 --- a/sys/netinet6/in6.c +++ b/sys/netinet6/in6.c @@ -162,6 +162,9 @@ static int in6_update_ifa_internal(struct ifnet *, struct in6_aliasreq *, static int in6_broadcast_ifa(struct ifnet *, struct in6_aliasreq *, struct in6_ifaddr *, int); +static void in6_join_proxy_ndp_mc(struct ifnet *, const struct in6_addr *); +static void in6_leave_proxy_ndp_mc(struct ifnet *, const struct in6_addr *); + #define ifa2ia6(ifa) ((struct in6_ifaddr *)(ifa)) #define ia62ifa(ia6) (&((ia6)->ia_ifa)) @@ -741,6 +744,26 @@ in6_joingroup_legacy(struct ifnet *ifp, const struct in6_addr *mcaddr, return (imm); } + +static int +in6_solicited_node_maddr(struct in6_addr *maddr, + struct ifnet *ifp, const struct in6_addr *base) +{ + int error; + + bzero(maddr, sizeof(struct in6_addr)); + maddr->s6_addr32[0] = IPV6_ADDR_INT32_MLL; + maddr->s6_addr32[2] = htonl(1); + maddr->s6_addr32[3] = base->s6_addr32[3]; + maddr->s6_addr8[12] = 0xff; + if ((error = in6_setscope(maddr, ifp, NULL)) != 0) { + /* XXX: should not happen */ + log(LOG_ERR, "%s: in6_setscope failed\n", __func__); + } + + return error; +} + /* * Join necessary multicast groups. Factored out from in6_update_ifa(). * This entire work should only be done once, for the default FIB. @@ -757,16 +780,9 @@ in6_update_ifa_join_mc(struct ifnet *ifp, struct in6_aliasreq *ifra, KASSERT(in6m_sol != NULL, ("%s: in6m_sol is NULL", __func__)); /* Join solicited multicast addr for new host id. */ - bzero(&mltaddr, sizeof(struct in6_addr)); - mltaddr.s6_addr32[0] = IPV6_ADDR_INT32_MLL; - mltaddr.s6_addr32[2] = htonl(1); - mltaddr.s6_addr32[3] = ifra->ifra_addr.sin6_addr.s6_addr32[3]; - mltaddr.s6_addr8[12] = 0xff; - if ((error = in6_setscope(&mltaddr, ifp, NULL)) != 0) { - /* XXX: should not happen */ - log(LOG_ERR, "%s: in6_setscope failed\n", __func__); + if ((error = in6_solicited_node_maddr(&mltaddr, ifp, + &ifra->ifra_addr.sin6_addr)) != 0) goto cleanup; - } delay = error = 0; if ((flags & IN6_IFAUPDATE_DADDELAY)) { /* @@ -2285,6 +2301,10 @@ in6_lltable_delete_entry(struct lltable *llt, struct llentry *lle) { lle->la_flags |= LLE_DELETED; + + /* Leave the solicited multicast group. */ + if ((lle->la_flags & LLE_PUB) != 0) + in6_leave_proxy_ndp_mc(llt->llt_ifp, &lle->r_l3addr.addr6); EVENTHANDLER_INVOKE(lle_event, lle, LLENTRY_DELETED); #ifdef DIAGNOSTIC log(LOG_INFO, "ifaddr cache = %p is deleted\n", lle); @@ -2463,7 +2483,9 @@ in6_lltable_dump_entry(struct lltable *llt, struct llentry *lle, static void in6_lltable_post_resolved(struct lltable *llt, struct llentry *lle) { - /* Handle proxy NDP entries (not yet). */ + /* Join the solicited multicast group for dst. */ + if ((lle->la_flags & LLE_PUB) == LLE_PUB) + in6_join_proxy_ndp_mc(llt->llt_ifp, &lle->r_l3addr.addr6); } static struct lltable * @@ -2621,3 +2643,72 @@ in6_sin_2_v4mapsin6_in_sock(struct sockaddr **nam) free(*nam, M_SONAME); *nam = (struct sockaddr *)sin6_p; } + +/* + * Join/leave the solicited multicast groups for proxy NDP entries. + */ +static void +in6_join_proxy_ndp_mc(struct ifnet *ifp, const struct in6_addr *dst) +{ + struct in6_multi *inm; + struct in6_addr mltaddr; + char ip6buf[INET6_ADDRSTRLEN]; + int error; + + if (in6_solicited_node_maddr(&mltaddr, ifp, dst) != 0) + return; /* error logged in in6_solicited_node_maddr. */ + + error = in6_joingroup(ifp, &mltaddr, NULL, &inm, 0); + if (error != 0) { + nd6log((LOG_WARNING, + "%s: in6_joingroup failed for %s on %s (errno=%d)\n", + __func__, ip6_sprintf(ip6buf, &mltaddr), if_name(ifp), + error)); + } +} + +static void +in6_leave_proxy_ndp_mc(struct ifnet *ifp, const struct in6_addr *dst) +{ + struct epoch_tracker et; + struct in6_multi *inm; + struct in6_addr mltaddr; + char ip6buf[INET6_ADDRSTRLEN]; + + if (in6_solicited_node_maddr(&mltaddr, ifp, dst) != 0) + return; /* error logged in in6_solicited_node_maddr. */ + + NET_EPOCH_ENTER(et); + inm = in6m_lookup(ifp, &mltaddr); + NET_EPOCH_EXIT(et); + if (inm != NULL) + in6_leavegroup(inm, NULL); + else + nd6log((LOG_WARNING, "%s: in6m_lookup failed for %s on %s\n", + __func__, ip6_sprintf(ip6buf, &mltaddr), if_name(ifp))); +} + +static bool +in6_lle_match_pub(struct lltable *llt, struct llentry *lle, void *farg) +{ + return ((lle->la_flags & LLE_PUB) != 0); +} + +void +in6_purge_proxy_ndp(struct ifnet *ifp) +{ + struct lltable *llt; + bool need_purge; + + llt = LLTABLE6(ifp); + IF_AFDATA_WLOCK(ifp); + need_purge = ((llt->llt_flags & LLT_ADDEDPROXY) != 0); + IF_AFDATA_WUNLOCK(ifp); + + /* + * Ever added proxy ndp entries, leave solicited node multicast + * before deleting the llentry. + */ + if (need_purge) + lltable_delete_conditional(llt, in6_lle_match_pub, NULL); +} diff --git a/sys/netinet6/in6_var.h b/sys/netinet6/in6_var.h index d3da832d2b90..1c8e78edd46c 100644 --- a/sys/netinet6/in6_var.h +++ b/sys/netinet6/in6_var.h @@ -916,6 +916,8 @@ int in6_is_addr_deprecated(struct sockaddr_in6 *); int in6_src_ioctl(u_long, caddr_t); void in6_newaddrmsg(struct in6_ifaddr *, int); + +void in6_purge_proxy_ndp(struct ifnet *); /* * Extended API for IPv6 FIB support. */ diff --git a/sys/netinet6/nd6_nbr.c b/sys/netinet6/nd6_nbr.c index 3a56964f8eb3..7877a7bc91b1 100644 --- a/sys/netinet6/nd6_nbr.c +++ b/sys/netinet6/nd6_nbr.c @@ -96,6 +96,9 @@ static void nd6_na_output_fib(struct ifnet *, const struct in6_addr *, static void nd6_ns_output_fib(struct ifnet *, const struct in6_addr *, const struct in6_addr *, const struct in6_addr *, uint8_t *, u_int); +static struct ifaddr *nd6_proxy_fill_sdl(struct ifnet *, + const struct in6_addr *, struct sockaddr_dl *); + VNET_DEFINE_STATIC(int, dad_enhanced) = 1; #define V_dad_enhanced VNET(dad_enhanced) @@ -255,34 +258,8 @@ nd6_ns_input(struct mbuf *m, int off, int icmp6len) /* (2) check. */ proxy = 0; if (ifa == NULL) { - struct sockaddr_dl rt_gateway; - struct rt_addrinfo info; - struct sockaddr_in6 dst6; - - bzero(&dst6, sizeof(dst6)); - dst6.sin6_len = sizeof(struct sockaddr_in6); - dst6.sin6_family = AF_INET6; - dst6.sin6_addr = taddr6; - - bzero(&rt_gateway, sizeof(rt_gateway)); - rt_gateway.sdl_len = sizeof(rt_gateway); - bzero(&info, sizeof(info)); - info.rti_info[RTAX_GATEWAY] = (struct sockaddr *)&rt_gateway; - - if (rib_lookup_info(ifp->if_fib, (struct sockaddr *)&dst6, - 0, 0, &info) == 0) { - if ((info.rti_flags & RTF_ANNOUNCE) != 0 && - rt_gateway.sdl_family == AF_LINK) { - /* - * proxy NDP for single entry - */ - proxydl = *SDL(&rt_gateway); - ifa = (struct ifaddr *)in6ifa_ifpforlinklocal( - ifp, IN6_IFF_NOTREADY|IN6_IFF_ANYCAST); - if (ifa) - proxy = 1; - } - } + if ((ifa = nd6_proxy_fill_sdl(ifp, &taddr6, &proxydl)) != NULL) + proxy = 1; } if (ifa == NULL) { /* @@ -386,6 +363,30 @@ nd6_ns_input(struct mbuf *m, int off, int icmp6len) m_freem(m); } +static struct ifaddr * +nd6_proxy_fill_sdl(struct ifnet *ifp, const struct in6_addr *taddr6, + struct sockaddr_dl *sdl) +{ + struct ifaddr *ifa; + struct llentry *ln; + + ifa = NULL; + ln = nd6_lookup(taddr6, LLE_SF(AF_INET6, 0), ifp); + if (ln == NULL) + return (ifa); + if ((ln->la_flags & (LLE_PUB | LLE_VALID)) == (LLE_PUB | LLE_VALID)) { + link_init_sdl(ifp, (struct sockaddr *)sdl, ifp->if_type); + sdl->sdl_alen = ifp->if_addrlen; + bcopy(ln->ll_addr, &sdl->sdl_data, ifp->if_addrlen); + LLE_RUNLOCK(ln); + ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp, + IN6_IFF_NOTREADY|IN6_IFF_ANYCAST); + } else + LLE_RUNLOCK(ln); + + return (ifa); +} + /* * Output a Neighbor Solicitation Message. Caller specifies: * - ICMP6 header source IP6 address diff --git a/tests/sys/netinet6/Makefile b/tests/sys/netinet6/Makefile index dfae9f698ec4..a4b6aa553b1d 100644 --- a/tests/sys/netinet6/Makefile +++ b/tests/sys/netinet6/Makefile @@ -15,7 +15,8 @@ ATF_TESTS_SH= \ output6 \ lpm6 \ fibs6 \ - ndp + ndp \ + proxy_ndp TEST_METADATA.output6+= required_programs="python" ${PACKAGE}FILES+= exthdr.py diff --git a/tests/sys/netinet6/proxy_ndp.sh b/tests/sys/netinet6/proxy_ndp.sh new file mode 100755 index 000000000000..64b9d0d45b06 --- /dev/null +++ b/tests/sys/netinet6/proxy_ndp.sh @@ -0,0 +1,222 @@ +#!/usr/bin/env atf-sh +#- +# SPDX-License-Identifier: BSD-2-Clause +# +# Copyright (c) 2022 KUROSAWA Takahiro +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# $FreeBSD$ +# + +. $(atf_get_srcdir)/../common/vnet.subr + +atf_test_case "pndp_add_gu_success" "cleanup" +pndp_add_gu_success_head() { + atf_set descr 'Test proxy ndp record addition' + atf_set require.user root +} + +pndp_add_gu_success_body() { + + vnet_init + + jname="v6t-pndp_add_success" + + epair0=$(vnet_mkepair) + + vnet_mkjail ${jname} ${epair0}a + jexec ${jname} ndp -i ${epair0}a -- -disabled + jexec ${jname} ifconfig ${epair0}a up + + jexec ${jname} ifconfig ${epair0}a inet6 2001:db8::1/64 + proxy_mac=`jexec ${jname} ifconfig ${epair0}a ether | awk '$1~/ether/{print$2}'` + + # wait for DAD to complete + while [ `jexec ${jname} ifconfig | grep inet6 | grep -c tentative` != "0" ]; do + sleep 0.1 + done + + atf_check jexec ${jname} ndp -s 2001:db8::2 ${proxy_mac} proxy + while [ `jexec ${jname} ifmcstat | grep -c undefined` != "0" ]; do + sleep 0.1 + done + + # checking the output of ndp -an is covered by ndp.sh. + # we check the output of ifmcstat output here. + t=`jexec ${jname} ifmcstat -i ${epair0}a -f inet6 | grep -A1 'group ff02::1:ff00:2'` + atf_check -o match:'mcast-macaddr 33:33:ff:00:00:02' echo $t +} + +pndp_add_gu_success_cleanup() { + vnet_cleanup +} + +atf_test_case "pndp_del_gu_success" "cleanup" +pndp_del_gu_success_head() { + atf_set descr 'Test proxy ndp record deletion' + atf_set require.user root +} + +pndp_del_gu_success_body() { + + vnet_init + + jname="v6t-pndp_del_gu_success" + + epair0=$(vnet_mkepair) + + vnet_mkjail ${jname} ${epair0}a + + jexec ${jname} ndp -i ${epair0}a -- -disabled + jexec ${jname} ifconfig ${epair0}a up + + jexec ${jname} ifconfig ${epair0}a inet6 2001:db8::1/64 + proxy_mac=`jexec ${jname} ifconfig ${epair0}a ether | awk '$1~/ether/{print$2}'` + + # wait for DAD to complete + while [ `jexec ${jname} ifconfig | grep inet6 | grep -c tentative` != "0" ]; do + sleep 0.1 + done + + atf_check jexec ${jname} ndp -s 2001:db8::2 ${proxy_mac} proxy + while [ `jexec ${jname} ifmcstat | grep -c undefined` != "0" ]; do + sleep 0.1 + done + jexec ${jname} ping -c1 -t1 2001:db8::2 + + atf_check -o match:"2001:db8::2 \(2001:db8::2\) deleted" jexec ${jname} ndp -nd 2001:db8::2 + while [ `jexec ${jname} ifmcstat | grep -c undefined` != "0" ]; do + sleep 0.1 + done + atf_check \ + -o not-match:'group ff02::1:ff00:2' \ + -o not-match:'mcast-macaddr 33:33:ff:00:00:02' \ + jexec ${jname} ifmcstat -i ${epair0}a -f inet6 +} + +pndp_del_gu_success_cleanup() { + vnet_cleanup +} + +atf_test_case "pndp_ifdestroy_success" "cleanup" +pndp_ifdetroy_success_head() { + atf_set descr 'Test interface destruction with proxy ndp' + atf_set require.user root +} + +pndp_ifdestroy_success_body() { + + vnet_init + + jname="v6t-pndp_ifdestroy_success" + + epair0=$(vnet_mkepair) + + vnet_mkjail ${jname} ${epair0}a + + jexec ${jname} ndp -i ${epair0}a -- -disabled + jexec ${jname} ifconfig ${epair0}a up + + jexec ${jname} ifconfig ${epair0}a inet6 2001:db8::1/64 + proxy_mac=`jexec ${jname} ifconfig ${epair0}a ether | awk '$1~/ether/{print$2}'` + + # wait for DAD to complete + while [ `jexec ${jname} ifconfig | grep inet6 | grep -c tentative` != "0" ]; do + sleep 0.1 + done + + atf_check jexec ${jname} ndp -s 2001:db8::2 ${proxy_mac} proxy + while [ `jexec ${jname} ifmcstat | grep -c undefined` != "0" ]; do + sleep 0.1 + done + + atf_check jexec ${jname} ifconfig ${epair0}a destroy +} + +pndp_ifdestroy_success_cleanup() { + vnet_cleanup +} + +atf_test_case "pndp_neighbor_advert" "cleanup" +pndp_neighbor_advert_head() { + atf_set descr 'Test Neighbor Advertisement for proxy ndp' + atf_set require.user root +} + +pndp_neighbor_advert_body() { + + vnet_init + + jname_a="v6t-pndp_neighbor_advert_a" # NA sender (w/proxy ndp entry) + jname_b="v6t-pndp_neighbor_advert_b" # NA receiver (checker) + proxy_addr="2001:db8::aaaa" + + epair0=$(vnet_mkepair) + + vnet_mkjail ${jname_a} ${epair0}a + jexec ${jname_a} ndp -i ${epair0}a -- -disabled + jexec ${jname_a} ifconfig ${epair0}a up + jexec ${jname_a} ifconfig ${epair0}a inet6 2001:db8::1/64 + proxy_mac=`jexec ${jname_a} ifconfig ${epair0}a ether | awk '$1~/ether/{print$2}'` + # wait for DAD to complete + while [ `jexec ${jname_a} ifconfig | grep inet6 | grep -c tentative` != "0" ]; do + sleep 0.1 + done + atf_check jexec ${jname_a} ndp -s ${proxy_addr} ${proxy_mac} proxy + while [ `jexec ${jname_a} ifmcstat | grep -c undefined` != "0" ]; do + sleep 0.1 + done + + vnet_mkjail ${jname_b} ${epair0}b + jexec ${jname_b} ndp -i ${epair0}b -- -disabled + jexec ${jname_b} ifconfig ${epair0}b up + jexec ${jname_b} ifconfig ${epair0}b inet6 2001:db8::2/64 + # wait for DAD to complete + while [ `jexec ${jname_b} ifconfig | grep inet6 | grep -c tentative` != "0" ]; do + sleep 0.1 + done + + jexec ${jname_b} ndp -nc + # jname_b sends a NS before ICMPv6 Echo Request for the proxy address. + # jname_a responds with a NA resolving the proxy address. + # Then there must be a NDP entry of the proxy address in jname_b. + jexec ${jname_b} ping -c1 -t1 ${proxy_addr} + atf_check -o match:"${proxy_addr} +${proxy_mac} +${epair0}b" \ + jexec ${jname_b} ndp -an +} + +pndp_neighbor_advert_cleanup() { + vnet_cleanup +} + +atf_init_test_cases() +{ + + atf_add_test_case "pndp_add_gu_success" + atf_add_test_case "pndp_del_gu_success" + atf_add_test_case "pndp_ifdestroy_success" + atf_add_test_case "pndp_neighbor_advert" +} + +# end +