From nobody Fri Jan 13 21:25:34 2023 X-Original-To: dev-commits-src-branches@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 4NtvbM27x1z2ql0r; Fri, 13 Jan 2023 21:25:35 +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 4NtvbM1WFmz437d; Fri, 13 Jan 2023 21:25:35 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1673645135; 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=vlq1Xtq5qSvgrBw0xbtLge74tfrFT9nMUz26FQFBnE8=; b=S2GK0giMDpu+ku8vRPXfL90NJWgmOax3lvNs3t2EGGt+AQ8iG6EktYLZckW4apoXNOzWf+ H73FtUvyRbQp18wduPCvmV1KKtCP+mdyZSGYZNw2IYejQOid0NO2mUdblOiUUulZRXhiHG fmFczb0KvpIOycYDXVmPYVzKqrpLGsMuLpcQAGVkbKic9K7x2rUz+7qWohNekmf6WUrsem hySpFgwxUd2AXKtaoH7HLoTYx4n350sntgDlsuNrov1oatyYNTT/KKK+dD/CJyEokWLRkM z2YJ9l0nByLB7KnH3M0H598pFtyO7SAtSZaaN6iu698UsLWmqGuftSDvTBjSLg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1673645135; 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=vlq1Xtq5qSvgrBw0xbtLge74tfrFT9nMUz26FQFBnE8=; b=tr5fz2oARwJ3/uhRRDqk2ZBAS6MH1j0v/i0VKsiVMOF6CPdxBCkDM+kN6b+rBmN6/iMGVE CrzmUdwe+DTUUcy3M3s7dIYJWJKMhb73u34qBgtSMRDykxrMz44b+1zJFQKK1a/WC7obqj 2oyqZqCZ9wnoEIbyqPcn7wpZoVlgHRVKujIW94Xe2WT2tvyvubNJJDoBudcDfww+dcYsEb yJfEjBLS6TYyHfC9YSOPtPlBEJ1TSE1dRrWLvNrKGrtxMZyqpRz29sFKB6gf/51HQwU8bM Uqe5+gepwko54SLc/Ct4WPwnqylRdof7tCps7H0yb1GVV151cGVxbL+Puydpqg== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1673645135; a=rsa-sha256; cv=none; b=voAh4B0BXUMIxLoyCwbm3IxQJoz+BOECjtplam0LbhAiDGAE/ip3bure20ZK2umkfUWlts vHMP+oihZz5O11KSrrgbyIY4QpB8R8cxF1EWcx3qecec0EVIbr2IITs6mCd6CDm58Zr+bY dd1xrXgnNG4KwgN93dCOKcL/ufJbLWpV3YJODJqU0sEoEa6COxv1vYZ7h5YU0VxGERPYFp JUK/JNGHwGwVXV+9tqdTZ9qUQqDhYgqaOxOoxEdvbW2axHlV4IvGyCOP3X6v5p3To5V55o GZBmTI0i3nrFyGRNRmTw9Ivj3k5PEjbKMyUWtlBaJ0zHZ9THmKrZ+TtBLtpiUQ== 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 4NtvbM0ZxgzN2P; Fri, 13 Jan 2023 21:25:35 +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 30DLPYgZ042043; Fri, 13 Jan 2023 21:25:34 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.16.1/8.16.1/Submit) id 30DLPYnD042042; Fri, 13 Jan 2023 21:25:34 GMT (envelope-from git) Date: Fri, 13 Jan 2023 21:25:34 GMT Message-Id: <202301132125.30DLPYnD042042@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org From: "Alexander V. Chernikov" Subject: git: 6554c7743bb1 - stable/13 - netinet6: factor out cached route lookups from selectroute(). List-Id: Commits to the stable branches of the FreeBSD src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-branches List-Help: List-Post: List-Subscribe: List-Unsubscribe: Sender: owner-dev-commits-src-branches@freebsd.org X-BeenThere: dev-commits-src-branches@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/stable/13 X-Git-Reftype: branch X-Git-Commit: 6554c7743bb1480ef39b465d848ca23b2882fbbd Auto-Submitted: auto-generated X-ThisMailContainsUnwantedMimeParts: N The branch stable/13 has been updated by melifaro: URL: https://cgit.FreeBSD.org/src/commit/?id=6554c7743bb1480ef39b465d848ca23b2882fbbd commit 6554c7743bb1480ef39b465d848ca23b2882fbbd Author: Alexander V. Chernikov AuthorDate: 2022-07-04 15:56:56 +0000 Commit: Alexander V. Chernikov CommitDate: 2023-01-13 21:24:11 +0000 netinet6: factor out cached route lookups from selectroute(). Currently selectroute() contains two nearly-identical versions of the route lookup logic - one for original destination and another for the case when IPV6_NEXTHOP option was set on the socket. Factor out handling these route lookups in a separation function to improve readability. This change also fixes handling of link-local IPV6_NEXTHOPs. Differential Revision: https://reviews.freebsd.org/D35710 MFC after: 2 weeks (cherry picked from commit 81a235ecde893a666e3cfac503068d9ea1bb013c) --- sys/netinet6/in6_src.c | 177 ++++++++++++---------------------- tests/sys/netinet6/test_ip6_output.py | 1 - 2 files changed, 60 insertions(+), 118 deletions(-) diff --git a/sys/netinet6/in6_src.c b/sys/netinet6/in6_src.c index 7f623709de13..472e16d318ad 100644 --- a/sys/netinet6/in6_src.c +++ b/sys/netinet6/in6_src.c @@ -612,8 +612,41 @@ in6_selectsrc_addr(uint32_t fibnum, const struct in6_addr *dst, return (error); } +static struct nhop_object * +cache_route(uint32_t fibnum, const struct sockaddr_in6 *dst, struct route_in6 *ro, + uint32_t flowid) +{ + /* + * Use a cached route if it exists and is valid, else try to allocate + * a new one. Note that we should check the address family of the + * cached destination, in case of sharing the cache with IPv4. + * Assumes that 'struct route_in6' is exclusively locked. + */ + if (ro->ro_nh != NULL && ( + !NH_IS_VALID(ro->ro_nh) || ro->ro_dst.sin6_family != AF_INET6 || + !IN6_ARE_ADDR_EQUAL(&ro->ro_dst.sin6_addr, &dst->sin6_addr))) + RO_NHFREE(ro); + + if (ro->ro_nh == NULL) { + ro->ro_dst = *dst; + + const struct in6_addr *paddr; + struct in6_addr unscoped_addr; + uint32_t scopeid = 0; + if (IN6_IS_SCOPE_LINKLOCAL(&dst->sin6_addr)) { + in6_splitscope(&dst->sin6_addr, &unscoped_addr, &scopeid); + paddr = &unscoped_addr; + } else + paddr = &dst->sin6_addr; + ro->ro_nh = fib6_lookup(fibnum, paddr, scopeid, NHR_REF, flowid); + } + return (ro->ro_nh); +} + /* - * clone - meaningful only for bsdi and freebsd + * Finds outgoing nexthop or the outgoing interface for the + * @dstsock. + * Return 0 on success and stores the lookup result in @retnh and @retifp */ static int selectroute(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts, @@ -628,28 +661,12 @@ selectroute(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts, struct in6_pktinfo *pi = NULL; struct in6_addr *dst = &dstsock->sin6_addr; uint32_t zoneid; -#if 0 - char ip6buf[INET6_ADDRSTRLEN]; - - if (dstsock->sin6_addr.s6_addr32[0] == 0 && - dstsock->sin6_addr.s6_addr32[1] == 0 && - !IN6_IS_ADDR_LOOPBACK(&dstsock->sin6_addr)) { - printf("%s: strange destination %s\n", __func__, - ip6_sprintf(ip6buf, &dstsock->sin6_addr)); - } else { - printf("%s: destination = %s%%%d\n", __func__, - ip6_sprintf(ip6buf, &dstsock->sin6_addr), - dstsock->sin6_scope_id); /* for debug */ - } -#endif /* If the caller specify the outgoing interface explicitly, use it. */ if (opts && (pi = opts->ip6po_pktinfo) != NULL && pi->ipi6_ifindex) { /* XXX boundary check is assumed to be already done. */ ifp = ifnet_byindex(pi->ipi6_ifindex); - if (ifp != NULL && - (norouteok || retnh == NULL || - IN6_IS_ADDR_MULTICAST(dst))) { + if (ifp != NULL && (norouteok || IN6_IS_ADDR_MULTICAST(dst))) { /* * we do not have to check or get the route for * multicast. @@ -685,104 +702,27 @@ selectroute(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts, * use it as the gateway. */ if (opts && opts->ip6po_nexthop) { - struct route_in6 *ron; - + struct route_in6 *ron = &opts->ip6po_nextroute; sin6_next = satosin6(opts->ip6po_nexthop); - if (IN6_IS_ADDR_LINKLOCAL(&sin6_next->sin6_addr)) { - /* - * Next hop is LLA, thus it should be neighbor. - * Determine outgoing interface by zone index. - */ - zoneid = ntohs(in6_getscope(&sin6_next->sin6_addr)); - if (zoneid > 0) { - ifp = in6_getlinkifnet(zoneid); - goto done; - } - } - ron = &opts->ip6po_nextroute; - /* Use a cached route if it exists and is valid. */ - if (ron->ro_nh != NULL && ( - !NH_IS_VALID(ron->ro_nh) || - ron->ro_dst.sin6_family != AF_INET6 || - !IN6_ARE_ADDR_EQUAL(&ron->ro_dst.sin6_addr, - &sin6_next->sin6_addr))) - RO_NHFREE(ron); - if (ron->ro_nh == NULL) { - ron->ro_dst = *sin6_next; - /* - * sin6_next is not link-local OR scopeid is 0, - * no need to clear scope - */ - ron->ro_nh = fib6_lookup(fibnum, - &sin6_next->sin6_addr, 0, NHR_REF, flowid); - } + + nh = cache_route(fibnum, sin6_next, ron, flowid); + /* * The node identified by that address must be a * neighbor of the sending host. */ - if (ron->ro_nh == NULL || - (ron->ro_nh->nh_flags & NHF_GATEWAY) != 0) - error = EHOSTUNREACH; - else { - nh = ron->ro_nh; + if (nh != NULL && (nh->nh_flags & NHF_GATEWAY) == 0) ifp = nh->nh_ifp; + else { + nh = NULL; // cached nh is still stored in @opts + error = EHOSTUNREACH; } - goto done; - } - - /* - * Use a cached route if it exists and is valid, else try to allocate - * a new one. Note that we should check the address family of the - * cached destination, in case of sharing the cache with IPv4. - */ - if (ro) { - if (ro->ro_nh && - (!NH_IS_VALID(ro->ro_nh) || - ((struct sockaddr *)(&ro->ro_dst))->sa_family != AF_INET6 || - !IN6_ARE_ADDR_EQUAL(&satosin6(&ro->ro_dst)->sin6_addr, - dst))) { - RO_NHFREE(ro); - } - if (ro->ro_nh == (struct nhop_object *)NULL) { - struct sockaddr_in6 *sa6; - - /* No route yet, so try to acquire one */ - bzero(&ro->ro_dst, sizeof(struct sockaddr_in6)); - sa6 = (struct sockaddr_in6 *)&ro->ro_dst; - *sa6 = *dstsock; - sa6->sin6_scope_id = 0; - - /* - * Currently dst has scopeid embedded iff it is LL. - * New routing API accepts scopeid as a separate argument. - * Convert dst before/after doing lookup - */ - uint32_t scopeid = 0; - if (IN6_IS_SCOPE_LINKLOCAL(&sa6->sin6_addr)) { - /* Unwrap in6_getscope() and in6_clearscope() */ - scopeid = ntohs(sa6->sin6_addr.s6_addr16[1]); - sa6->sin6_addr.s6_addr16[1] = 0; - } - - ro->ro_nh = fib6_lookup(fibnum, - &sa6->sin6_addr, scopeid, NHR_REF, flowid); - - if (IN6_IS_SCOPE_LINKLOCAL(&sa6->sin6_addr)) - sa6->sin6_addr.s6_addr16[1] = htons(scopeid); - } - - /* - * do not care about the result if we have the nexthop - * explicitly specified. - */ - if (opts && opts->ip6po_nexthop) - goto done; - - if (ro->ro_nh) - ifp = ro->ro_nh->nh_ifp; + } else if (ro != NULL) { + nh = cache_route(fibnum, dstsock, ro, flowid); + if (nh != NULL) + ifp = nh->nh_ifp; else error = EHOSTUNREACH; - nh = ro->ro_nh; /* * Check if the outgoing interface conflicts with @@ -797,10 +737,15 @@ selectroute(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts, ifp->if_index != opts->ip6po_pktinfo->ipi6_ifindex) { error = EHOSTUNREACH; - goto done; + ifp = NULL; + nh = NULL; } } } + /* + * Output must be consistent: no error -> both ifp and nh != NULL, + * otherwise both NULL + */ done: if (ifp == NULL && nh == NULL) { @@ -813,15 +758,11 @@ selectroute(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts, if (error == EHOSTUNREACH) IP6STAT_INC(ip6s_noroute); - if (retifp != NULL) { - if (nh != NULL) - *retifp = nh->nh_aifp; - else - *retifp = ifp; - } - - if (retnh != NULL) - *retnh = nh; /* nh may be NULL */ + if (nh != NULL) + *retifp = nh->nh_aifp; + else + *retifp = ifp; + *retnh = nh; /* nh may be NULL */ return (error); } @@ -889,6 +830,8 @@ in6_selectroute(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts, struct ip6_moptions *mopts, struct route_in6 *ro, struct ifnet **retifp, struct nhop_object **retnh, u_int fibnum, uint32_t flowid) { + MPASS(retifp != NULL); + MPASS(retnh != NULL); return (selectroute(dstsock, opts, mopts, ro, retifp, retnh, 0, fibnum, flowid)); diff --git a/tests/sys/netinet6/test_ip6_output.py b/tests/sys/netinet6/test_ip6_output.py index a84e1f9d4d60..112423698cdf 100644 --- a/tests/sys/netinet6/test_ip6_output.py +++ b/tests/sys/netinet6/test_ip6_output.py @@ -257,7 +257,6 @@ class TestIP6OutputLL(BaseTestIP6Ouput): assert rx_obj["dst_iface_alias"] == "if2" -@pytest.mark.skip(reason="Currently fails") class TestIP6OutputNhopLL(BaseTestIP6Ouput): def vnet2_handler(self, vnet, obj_map, pipe): """Generic listener that sends first received packet with metadata