From owner-dev-commits-src-all@freebsd.org Tue Mar 9 11:17:54 2021 Return-Path: Delivered-To: dev-commits-src-all@mailman.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.nyi.freebsd.org (Postfix) with ESMTP id 1F12B575E3D; Tue, 9 Mar 2021 11:17:54 +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 4Dvt3c5rs3z3nmK; Tue, 9 Mar 2021 11:17:48 +0000 (UTC) (envelope-from git@FreeBSD.org) 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 AE6F11B3FA; Tue, 9 Mar 2021 11:17:23 +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 129BHNLY042830; Tue, 9 Mar 2021 11:17:23 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.16.1/8.16.1/Submit) id 129BHN0a042829; Tue, 9 Mar 2021 11:17:23 GMT (envelope-from git) Date: Tue, 9 Mar 2021 11:17:23 GMT Message-Id: <202103091117.129BHN0a042829@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Kyle Evans Subject: git: e80e371d79d8 - main - if_wg: avoid sleeping under the net epoch MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: kevans X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: e80e371d79d825712a9078e0d1a14b62567291c4 Auto-Submitted: auto-generated X-BeenThere: dev-commits-src-all@freebsd.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: Commit messages for all branches of the src repository List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 09 Mar 2021 11:17:54 -0000 The branch main has been updated by kevans: URL: https://cgit.FreeBSD.org/src/commit/?id=e80e371d79d825712a9078e0d1a14b62567291c4 commit e80e371d79d825712a9078e0d1a14b62567291c4 Author: Kyle Evans AuthorDate: 2021-03-08 06:06:28 +0000 Commit: Kyle Evans CommitDate: 2021-03-09 11:16:30 +0000 if_wg: avoid sleeping under the net epoch No sleeping allowed here, so avoid it. Collect the subset of data we want inside of the epoch, as we'll need extra allocations when we add items to the nvlist. Reviewed by: grehan (earlier version), markj MFC after: 3 days Differential Revision: https://reviews.freebsd.org/D29124 --- sys/dev/if_wg/module/module.c | 136 ++++++++++++++++++++++++++++++------------ 1 file changed, 99 insertions(+), 37 deletions(-) diff --git a/sys/dev/if_wg/module/module.c b/sys/dev/if_wg/module/module.c index a40a304616c7..6ae3bf9db022 100644 --- a/sys/dev/if_wg/module/module.c +++ b/sys/dev/if_wg/module/module.c @@ -69,6 +69,14 @@ MALLOC_DEFINE(M_WG, "WG", "wireguard"); TASKQGROUP_DECLARE(if_io_tqg); +struct wg_peer_export { + struct sockaddr_storage endpoint; + uint8_t public_key[WG_KEY_SIZE]; + size_t endpoint_sz; + struct wg_allowedip *aip; + int aip_count; +}; + static int clone_count; uma_zone_t ratelimit_zone; @@ -386,37 +394,70 @@ wg_stop(if_ctx_t ctx) wg_socket_reinit(sc, NULL, NULL); } -static nvlist_t * -wg_peer_to_nvl(struct wg_peer *peer) +static int +wg_peer_to_export(struct wg_peer *peer, struct wg_peer_export *exp) { - struct wg_route *rt; - int i, count; - nvlist_t *nvl; - caddr_t key; - size_t sa_sz; - struct wg_allowedip *aip; struct wg_endpoint *ep; + struct wg_route *rt; + int i; - if ((nvl = nvlist_create(0)) == NULL) - return (NULL); - key = peer->p_remote.r_public; - nvlist_add_binary(nvl, "public-key", key, WG_KEY_SIZE); + /* Non-sleepable context. */ + NET_EPOCH_ASSERT(); + + bzero(&exp->endpoint, sizeof(exp->endpoint)); ep = &peer->p_endpoint; if (ep->e_remote.r_sa.sa_family != 0) { - sa_sz = (ep->e_remote.r_sa.sa_family == AF_INET) ? - sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6); - nvlist_add_binary(nvl, "endpoint", &ep->e_remote, sa_sz); + exp->endpoint_sz = (ep->e_remote.r_sa.sa_family == AF_INET) ? + sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6); + + memcpy(&exp->endpoint, &ep->e_remote, exp->endpoint_sz); } - i = count = 0; + + memcpy(exp->public_key, peer->p_remote.r_public, + sizeof(exp->public_key)); + + exp->aip_count = 0; CK_LIST_FOREACH(rt, &peer->p_routes, r_entry) { - count++; + exp->aip_count++; } - aip = malloc(count*sizeof(*aip), M_TEMP, M_WAITOK); + + /* Early success; no allowed-ips to copy out. */ + if (exp->aip_count == 0) + return (0); + + exp->aip = malloc(exp->aip_count * sizeof(*exp->aip), M_TEMP, M_NOWAIT); + if (exp->aip == NULL) + return (ENOMEM); + + i = 0; CK_LIST_FOREACH(rt, &peer->p_routes, r_entry) { - memcpy(&aip[i++], &rt->r_cidr, sizeof(*aip)); + memcpy(&exp->aip[i++], &rt->r_cidr, sizeof(*exp->aip)); + if (i == exp->aip_count) + break; } - nvlist_add_binary(nvl, "allowed-ips", aip, count*sizeof(*aip)); - free(aip, M_TEMP); + + /* Again, AllowedIPs might have shrank; update it. */ + exp->aip_count = i; + + return (0); +} + +static nvlist_t * +wg_peer_export_to_nvl(struct wg_peer_export *exp) +{ + nvlist_t *nvl; + + if ((nvl = nvlist_create(0)) == NULL) + return (NULL); + + nvlist_add_binary(nvl, "public-key", exp->public_key, WG_KEY_SIZE); + if (exp->endpoint_sz != 0) + nvlist_add_binary(nvl, "endpoint", &exp->endpoint, + exp->endpoint_sz); + + nvlist_add_binary(nvl, "allowed-ips", exp->aip, + exp->aip_count * sizeof(*exp->aip)); + return (nvl); } @@ -427,10 +468,8 @@ wg_marshal_peers(struct wg_softc *sc, nvlist_t **nvlp, nvlist_t ***nvl_arrayp, i int err, i, peer_count; nvlist_t *nvl, **nvl_array; struct epoch_tracker et; -#ifdef INVARIANTS - void *packed; - size_t size; -#endif + struct wg_peer_export *wpe; + nvl = NULL; nvl_array = NULL; if (nvl_arrayp) @@ -447,34 +486,44 @@ wg_marshal_peers(struct wg_softc *sc, nvlist_t **nvlp, nvlist_t ***nvl_arrayp, i if (nvlp && (nvl = nvlist_create(0)) == NULL) return (ENOMEM); + err = i = 0; nvl_array = malloc(peer_count*sizeof(void*), M_TEMP, M_WAITOK); + wpe = malloc(peer_count*sizeof(*wpe), M_TEMP, M_WAITOK | M_ZERO); + NET_EPOCH_ENTER(et); CK_LIST_FOREACH(peer, &sc->sc_hashtable.h_peers_list, p_entry) { - nvl_array[i] = wg_peer_to_nvl(peer); - if (nvl_array[i] == NULL) { - printf("wg_peer_to_nvl failed on %d peer\n", i); + if ((err = wg_peer_to_export(peer, &wpe[i])) != 0) { + printf("wg_peer_to_export failed on %d peer, error %d\n", + i, err); break; } -#ifdef INVARIANTS - packed = nvlist_pack(nvl_array[i], &size); - if (packed == NULL) { - printf("nvlist_pack(%p, %p) => %d", - nvl_array[i], &size, nvlist_error(nvl)); - } - free(packed, M_NVLIST); -#endif + i++; if (i == peer_count) break; } NET_EPOCH_EXIT(et); + + if (err != 0) + goto out; + + /* Update the peer count, in case we found fewer entries. */ *peer_countp = peer_count = i; if (peer_count == 0) { printf("no peers found in list\n"); err = ENOENT; goto out; } + + for (i = 0; i < peer_count; i++) { + nvl_array[i] = wg_peer_export_to_nvl(&wpe[i]); + if (nvl_array[i] == NULL) { + printf("wg_peer_export_to_nvl failed on %d peer\n", i); + break; + } + } + if (nvl) { nvlist_add_nvlist_array(nvl, "peer-list", (const nvlist_t * const *)nvl_array, peer_count); @@ -486,8 +535,21 @@ wg_marshal_peers(struct wg_softc *sc, nvlist_t **nvlp, nvlist_t ***nvl_arrayp, i *nvlp = nvl; } *nvl_arrayp = nvl_array; - return (0); + err = 0; out: + if (err != 0) { + for (i = 0; i < peer_count; i++) { + nvlist_destroy(nvl_array[i]); + } + + free(nvl_array, M_TEMP); + if (nvl != NULL) + nvlist_destroy(nvl); + } + + for (i = 0; i < peer_count; i++) + free(wpe[i].aip, M_TEMP); + free(wpe, M_TEMP); return (err); }