From nobody Thu Sep 24 14:25:06 2026 Received: from mail-dy1-f177.google.com (mail-dy1-f177.google.com [74.125.82.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 83BA635E1BD for ; Wed, 23 Sep 2026 01:34:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.82.177 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790127267; cv=none; b=YSAo5XWRxahCJ8WgwrQe/2yBNaclkYm3E0CFFhklqL7tnabJgzTurnnUwLnpQklE0+tAYIpZ01GMDsroWe7i07KW8Wfj/b6L7liYWEp/7AwzJrLj0ADiEj4AOIwu2zlKxu3z5eALJ1DCCPtNXLd8G4l5lNK1ukh9Fa9ggj/B2/g= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790127267; c=relaxed/simple; bh=xA4WU1urp6a9IoQYp7ZKNyOjLTk6vSKIj/MoA4yE48c=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=fWHr1SqXNcy36oqQD4Vxv6YWgeBPifsD9aLJ8NRAKIvyhmXLfAXAdERnKfP5gnfJzXJFmf4q+wG7KiKDyskOjSng0lW+k4DnlSZ9QKvy5LVy1r8lMHBpBieCadHrmQQqpq8NE+dj5yYx1nO56byUhX6qrpvBLTEPUaBX+uDulYg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=W+NYEXf5; arc=none smtp.client-ip=74.125.82.177 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="W+NYEXf5" Received: by mail-dy1-f177.google.com with SMTP id 5a478bee46e88-32ca15c81aaso174966eec.1 for ; Tue, 22 Sep 2026 18:34:25 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1790127264; x=1790732064; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=rBZlZPS0y4qnYkFfYjvPWcFQrZpMybZs72GhSU2wrpE=; b=W+NYEXf5/fvNyrSSiNZDFAnRIWupmQrLxXO5qMZgCZIiP5F2BE6raVD2X7qUzP4iCK v57/Z/Ne3pmMArzL5cqEOgPLaQbOSvRSEguXHcqW52h5IlEdrA8GwbthbBNN598kQ+od lgHGqg0ikSX2sqUGf3qfgEmo7zi1MHZi+U8UMwAPFWOWryDuvBAiJIa0+HY7Q5cfDC4p rzV3aciDOeCW7Gzb0mZOElJqNOTk3isSm5OmtgduRjNvfQl+Qvrf1X/cTs4F8UTmwEMU Y9AcNhlFce4FSnxircw8EhFkCf/sZLFqrgD5sjGRC7wWlMbk41NyrRHI3CzJeYqQB7so 5MdQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1790127264; x=1790732064; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=rBZlZPS0y4qnYkFfYjvPWcFQrZpMybZs72GhSU2wrpE=; b=YSyCNF6w/Vg7bS0S0R7Z8cDZ0cQI6U6tM3NHEWn7KR1iWGfF3sev5q/4uB7aTdr992 Y88FKOsvo6i83IvbsDqbF8B/+cSt66Dppmpk3PjJ45KqVIDh8LtDWFCuxUkdsymd2sVV 3iAUjPmgHVYoqjARHYwJBH3ulVP8wfA24HTZM692V48fvq1ekOH9wSdMcKZIKpdfYa9M y+GjrHeXvsVUATsdd4uIi4ZgemIZ5Zpd1egcI3KuG155nwsC5qcM3jjllox4Y04Gba8W 6iINXK9aWvmrfV7IapjG4WaeVv8Nx9P3Uq8e2RoePDPFEjgirzbvrcjDoPWSU92+XU5G 4u+Q== X-Forwarded-Encrypted: i=1; AKwUvByz2WCENAtzMVrk3LJZROBWJqf+NZngEC/x5zLAZY+s627DmSWaMzaZ3amw03UYQvC0IsBF85y8+FwgF2I=@vger.kernel.org X-Gm-Message-State: AFuF++mBLAIBjyuRc7b0zJx4Hgxm2LXDw0oor4HuiRbCPZiN2v42OeHV a57OMQ78wWOpBjUpT2Jan9fcH6n5i7RDs2e2kR+cK/SsQ8V5hUhe6Jho X-Gm-Gg: AYBFou3pj1Usqa9JrsuNaWFtMnz3ycdAUITw9Rw9F0XbHZi197UMCNssskglh/xTix6 D2fkSdeP5/X5TMmluXQDfJU5o+Jeh8f5xulGBabpIB0Gr+6dI1i5mx0snNuXsMbLggw3N1OUjqL 06iyovsP6vpar71KDA71USdj1x0aXPwYcb121KtDrFtzEsZZBgr+qJC6/OO1kiYNmo2duZXdNF6 qsrlEiqQloJzev1zH1t4wDro1malxCGCLFBBZiUeBP7eGtIWthGuEv5E54eUTKTkjqXQiRwHS8+ 6TUV9suTuVucmSN2YRGhJxFHjKK2K1z21F8PUjJjiKzsBp6fJ3whuSl016nxXgkHgCdpbLiUaQ4 hRYVuN4mu3q8XeHGazGuxF0wmQssXNE0vGVFp/dPJQoJa8mFLz/f1QhbDYnEWEkpRUUM+va9GGQ J1KPesy55xeXc8ydcTaXD6i/vXVUnzw3Bnep4bguAvYAhki3ycNdwBq7ljdWD7TFZgR6gFHGhCK 3582dlNJUJyLcqFSdI6u80x1D2HGhIeQc0W4oOoRwWV5XoiYmHlnSUQm40BhcfRx+2usiHeuMVm wXkLr1BQ6yK6pMcVLQIBE7ROvOuudQE= X-Received: by 2002:a05:7300:dd41:b0:339:851c:4c1 with SMTP id 5a478bee46e88-33e5ca9fdbbmr1148155eec.18.1790127264190; Tue, 22 Sep 2026 18:34:24 -0700 (PDT) Received: from lawlee-vm0.d4y3nv5wwgfelhhopdxv1tqjld.dx.internal.cloudapp.net ([13.93.150.60]) by smtp.gmail.com with ESMTPSA id 5a478bee46e88-33e96f47d52sm2013520eec.28.2026.09.22.18.34.22 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 22 Sep 2026 18:34:23 -0700 (PDT) From: Lawrence Lee To: David Ahern , Ido Schimmel , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni Cc: Simon Horman , Randy Dunlap , netdev@vger.kernel.org, Arun Ajith S , Roopa Prabhu , Jaehee Park , Jonathan Corbet , Shuah Khan , Shuah Khan , linux-doc@vger.kernel.org, linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH net-next v4 1/2] ipv6: update NUD_FAILED neighbors from NA messages Date: Wed, 23 Sep 2026 01:34:18 +0000 Message-ID: <6be400e601f4ffa59e47ddb5daa33ecdd85dd88b.1790127207.git.lfqlee314@gmail.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Transition a FAILED neighbor entry to STALE upon receipt of an NA message on routers when accept_untracked_na is enabled. This extends the RFC 9131 accept_untracked_na behavior so that FAILED entries are treated the same as non-existent entries. RFC 4861 section 7.3.3 says that an entry should be deleted when address resolution fails. Linux instead retains the entry in NUD_FAILED, so treating it as untracked is consistent with the protocol model. Trying to resolve FAILED neighbors via periodic probing (e.g. using NTF_EXT_MANAGED) is more work compared to this approach which uses information in NAs that the kernel may already be receiving. Note that because this behavior in IPv6 is dependent on the accept_untracked_na sysctl setting, this approach is more conservative than IPv4 which transitions FAILED neighbors to STALE by default upon receiving GARPs. Link: https://lore.kernel.org/r/20260813233344.445265-1-lfqlee314@gmail.com Assisted-by: LLM Sashiko sparse Signed-off-by: Lawrence Lee Reviewed-by: Ido Schimmel --- The existing 6LoWPAN override-only handling also applies to INCOMPLETE entries and is intentionally left unchanged. The existing rt6_clean_tohost() source-versus-target behavior applies to all neighbor states and is also left unchanged. Documentation/networking/ip-sysctl.rst | 28 ++++++++------- net/ipv6/ndisc.c | 47 ++++++++++++++------------ 2 files changed, 41 insertions(+), 34 deletions(-) diff --git a/Documentation/networking/ip-sysctl.rst b/Documentation/network= ing/ip-sysctl.rst index f7af0286341c..685c84cf543d 100644 --- a/Documentation/networking/ip-sysctl.rst +++ b/Documentation/networking/ip-sysctl.rst @@ -3225,18 +3225,19 @@ drop_unsolicited_na - BOOLEAN Default: 0 (disabled). =20 accept_untracked_na - INTEGER - Define behavior for accepting neighbor advertisements from devices that - are absent in the neighbor cache: + Define behavior for accepting neighbor advertisements for IPv6 addresses + that are absent from the neighbor cache or whose entries are in FAILED + state: =20 - - 0 - (default) Do not accept unsolicited and untracked neighbor - advertisements. + - 0 - (default) Do not create new neighbor cache entries or update + FAILED entries from neighbor advertisements. =20 - - 1 - Add a new neighbor cache entry in STALE state for routers on - receiving a neighbor advertisement (either solicited or unsolicited) - with target link-layer address option specified if no neighbor entry - is already present for the advertised IPv6 address. Without this knob, - NAs received for untracked addresses (absent in neighbor cache) are - silently ignored. + - 1 - For routers, add a new neighbor cache entry or update an existing + FAILED entry to STALE upon receiving a neighbor advertisement (either + solicited or unsolicited) with the target link-layer address option + specified. Without this knob, NAs received for untracked addresses + (absent from the neighbor cache or in FAILED state) are silently + ignored. =20 This is as per router-side behavior documented in RFC9131. =20 @@ -3251,9 +3252,10 @@ accept_untracked_na - INTEGER used in conjunction with the ndisc_notify setting on the host to satisfy this prerequisite. =20 - - 2 - Extend option (1) to add a new neighbor cache entry only if the - source IP address is in the same subnet as an address configured on - the interface that received the neighbor advertisement. + - 2 - Extend option (1) to add a new neighbor cache entry or update a + FAILED entry only if the source IP address is in the same subnet as + an address configured on the interface that received the neighbor + advertisement. =20 enhanced_dad - BOOLEAN Include a nonce option in the IPv6 neighbor solicitation messages used for diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 90cd5d852569..12d85d7f8234 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -973,13 +973,13 @@ static enum skb_drop_reason ndisc_recv_ns(struct sk_b= uff *skb) static int accept_untracked_na(struct inet6_dev *idev, struct in6_addr *sa= ddr) { switch (READ_ONCE(idev->cnf.accept_untracked_na)) { - case 0: /* Don't accept untracked na (absent in neighbor cache) */ + case 0: /* Don't accept untracked NA (absent or FAILED) */ return 0; - case 1: /* Create new entries from na if currently untracked */ + case 1: /* Create new or update FAILED entries from NA */ return 1; - case 2: /* Create new entries from untracked na only if saddr is in the + case 2: /* Create new or update FAILED entries only if saddr is in the * same subnet as an address configured on the interface that - * received the na + * received the NA */ return !!ipv6_chk_prefix(saddr, idev->dev); default: @@ -1067,34 +1067,39 @@ static enum skb_drop_reason ndisc_recv_na(struct sk= _buff *skb) neigh =3D neigh_lookup(tbl, &msg->target, dev); =20 /* RFC 9131 updates original Neighbour Discovery RFC 4861. - * NAs with Target LL Address option without a corresponding - * entry in the neighbour cache can now create a STALE neighbour - * cache entry on routers. + * NAs with Target LL Address option can now create a STALE neighbor + * cache entry on routers if the NA does not have a corresponding entry + * in the neighbour cache or has a corresponding FAILED entry. * - * entry accept fwding solicited behaviour - * ------- ------ ------ --------- ---------------------- - * present X X 0 Set state to STALE - * present X X 1 Set state to REACHABLE - * absent 0 X X Do nothing - * absent 1 0 X Do nothing - * absent 1 1 X Add a new STALE entry + * entry accept fwding solicited behaviour + * ----------- ------ ------ --------- ---------------------- + * non-FAILED X X 0 Set state to STALE + * non-FAILED X X 1 Set state to REACHABLE + * FAILED 0 X X Do nothing + * FAILED 1 0 X Do nothing + * FAILED 1 1 X Set state to STALE + * absent 0 X X Do nothing + * absent 1 0 X Do nothing + * absent 1 1 X Add a new STALE entry * * Note that we don't do a (daddr =3D=3D all-routers-mcast) check. */ new_state =3D msg->icmph.icmp6_solicited ? NUD_REACHABLE : NUD_STALE; - if (!neigh && lladdr && idev && READ_ONCE(idev->cnf.forwarding)) { - if (accept_untracked_na(idev, saddr)) { - neigh =3D neigh_create(tbl, &msg->target, dev); - new_state =3D NUD_STALE; + if (!neigh || (READ_ONCE(neigh->nud_state) & NUD_FAILED)) { + if (!lladdr || !idev || !READ_ONCE(idev->cnf.forwarding) || + !accept_untracked_na(idev, saddr)) { + if (neigh) + neigh_release(neigh); + return reason; } + if (!neigh) + neigh =3D neigh_create(tbl, &msg->target, dev); + new_state =3D NUD_STALE; } =20 if (neigh && !IS_ERR(neigh)) { u8 old_flags =3D neigh->flags; =20 - if (READ_ONCE(neigh->nud_state) & NUD_FAILED) - goto out; - /* * Don't update the neighbor cache entry on a proxy NA from * ourselves because either the proxied node is off link or it --=20 2.43.0 From nobody Thu Sep 24 14:25:06 2026 Received: from mail-dy2-f12.google.com (mail-dy2-f12.google.com [74.125.229.12]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0422F360EFF for ; Wed, 23 Sep 2026 01:34:26 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.229.12 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790127268; cv=none; b=UuzZsd3O+I/hq730K3545+p8ZCaM3LtjiRI9t9YlpXLi0TPX8C+9++PGsOMLi1dQW7VoBdlKsTZ7KNO4iO0Swg27ZryBVPkp61ohoGtdFyONhN6yEYAssQj2+6yasMHFj2X5rvqCcmwwe8C1v/4McVTMZnTsF+YaL0nKS8I8i4g= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790127268; c=relaxed/simple; bh=iU2FuQNmEXQCPbvdO6PlHEX1diONiNT34AcuPNd2qjA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=ngUfQ63IxbriWbiM5BpeKgH4xNPEEGefr7vFFYkMrehPjtr/w4ZbJu5O5tCJZtTgekO7byTGmLh14fJbHKVlLmWDIb5b22MxOre0LhR/C8cufmcuUsKLT8u/+LmKDgOscvOiy/pkDP4Cuvh2XSKlj4WpaR3MA5vIhDXXpA9RjUc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=QByuSs0N; arc=none smtp.client-ip=74.125.229.12 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="QByuSs0N" Received: by mail-dy2-f12.google.com with SMTP id 5a478bee46e88-328664c2da6so224442eec.1 for ; Tue, 22 Sep 2026 18:34:26 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1790127266; x=1790732066; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=z425s6s/R/+sgdabTRg+eLb5zfe4+RFtNm44lmjghrE=; b=QByuSs0NhvzHWfBVNF8y+JnkxS3sY6M0+ui4WBxikrxr6OwsRY9CXl60GCkwpI4L9p HIXKntmIsf4VRiwisl9mGOQEF+KqPvJCVaz8ulFTIApu5XpaSKlIPuRyYoACIm2sQ+l+ 6FxG14OsFdawRQ5PX9XxTqCsWdT9v4lbkvjaTiIhgxSbtZh2BDSr0swHl7HsxWUZloT/ EHvijuDrJuRuQTOTkAx6vwTxRC0D3yDmemTgGy8dO0nin/VJ5o4Hy5Qttyr5C+V6/30J QDDf0iT5Fs3dueSXrB0vlvb+QgaO0RZiIC2D5Q9TJxi1aaQrg5RV7w3cSNZdcI7E1/PC x1Vg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1790127266; x=1790732066; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=z425s6s/R/+sgdabTRg+eLb5zfe4+RFtNm44lmjghrE=; b=QxG84pbr/rUMTYi759i4rPR66E/QXxcL+5z9JpxX2dVuK4q8qiDC++8Fdc83G+/Hua IxSed5jLzCRXldrX+bNEj5SQbRyeKDHvlOMzNa8QQ9/5vwsqORd661Kt3GElmkJnM94N dLx7n3t504ldQRdwMu0ocw6s5Sh0FEeHcBCIRpYzPcLHjzidxL8yeb9b6LaTY/g+m6ob HX8zjJ+y7fRElPDcOos9DUDDLUs3DqjKff+nyufAG2Vzaxo7z1dbW1SeqAjssxOkK/U6 k6pIfGTVy6koDnyhzyIx0lwBOlU+i5gorCxxv8B7/5yx0wPm1i7FyD87n/PZWSqsAcBe GL2Q== X-Forwarded-Encrypted: i=1; AKwUvBxMU22bc/uEZHVQZRWkkArD5GHl99auHO/bHQM9Za13I4/nb2pcpCIUpvyBbRYBItIN6OOC5ak6hStCRMw=@vger.kernel.org X-Gm-Message-State: AFuF++lyuMVsdtHgq3V6Q9iUpVAbivGamD2YIOi2PkNJ/uNqNsouHVLL 4fJnSRLisFH9XbQj7c372u2Gt0ULWtiVlBthOGF+7oNeIABLY4v/t/7d X-Gm-Gg: AYBFou2xcgo4qvptAyJQLjOGyQtg4UEgeBJ9+dYRq45HYaj5A7WxRfioWhU1EP1ov2Z vTsin+YxA6DO2m1KuYLvz4ujghK4Yp7zqOkZ6ZkbRdtTBE5pjFxm3x5o8H2HPXyqMweS420Rpvw HVQRkGlyf4AJJX0GdKbzIIoNfP+0YK3qZ3DTR8sazF5oe3t8v8J+SMT4pASKN1cGHiQIMwbGS59 V9G+DxbYH2C9PcIaN7FA5X7BUOnXZNlzbejKPLx6ZCX/WIvYgjH9nvY92JAvwLe+8CnXAb0KDUp PvbdNRh24MTbZMFr6ZKwSNe7rIFNgE++7I/YM68MXbvERWBaXQtjRcSfWP1Y66wGNgZHWiTh2mX 7z5Rkh1FJXvZA80pR3HcegmUdLxVj7quEv9rj0S6qUx3IicMcZOmYgzalHAoOhG7sTQbRIOB0N2 V+a8WzbYDW/bSIep5mEnluwNBel+hkaVNNFi8br2+5eN5p9S0LE+H30QkZbMmpyw1/nXnb4UV0B EPJ5cxt7aLsK4ez2/abctlsAwQB/NEXJxnU6OSBpNwy1Ped2taUmTFKsPRKuVoznHhB3XuiTLos Ky6NvNfAE/4EPs08y3YBSxeUVqkpZus= X-Received: by 2002:a05:693c:8804:20b0:33c:2308:c0af with SMTP id 5a478bee46e88-33e8c05dccfmr1090276eec.17.1790127265904; Tue, 22 Sep 2026 18:34:25 -0700 (PDT) Received: from lawlee-vm0.d4y3nv5wwgfelhhopdxv1tqjld.dx.internal.cloudapp.net ([13.93.150.60]) by smtp.gmail.com with ESMTPSA id 5a478bee46e88-33e96f47d52sm2013520eec.28.2026.09.22.18.34.24 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 22 Sep 2026 18:34:25 -0700 (PDT) From: Lawrence Lee To: David Ahern , Ido Schimmel , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni Cc: Simon Horman , Randy Dunlap , netdev@vger.kernel.org, Arun Ajith S , Roopa Prabhu , Jaehee Park , Jonathan Corbet , Shuah Khan , Shuah Khan , linux-doc@vger.kernel.org, linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH net-next v4 2/2] selftests: net: test untracked NA recovery of FAILED neighbors Date: Wed, 23 Sep 2026 01:34:19 +0000 Message-ID: X-Mailer: git-send-email 2.43.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Seed a FAILED neighbor before triggering an unsolicited NA. Verify that the entry transitions to STALE and learns the advertised link-layer address only when drop_unsolicited_na is disabled, accept_untracked_na mode 1 or in-prefix mode 2 is enabled, and IPv6 forwarding is enabled. Verify that disabling each gate keeps the entry in FAILED without a link-layer address. Mark the seed externally learned and disable carrier-based eviction so the entry cannot be garbage-collected before the NA arrives. Require the marker after processing to prove that a recovered entry was updated in place instead of deleted and recreated. Keep the NA source, target, and neighbor key fixed for the mode 2 cases. Vary the prefix configured on the router to exercise the source-prefix check without changing the entry under test. Arm packet capture before bringing up the host interface and starting DAD. Wait for the capture to become ready and for tcpdump to exit so the NA cannot be missed and receive processing is complete before checking the neighbor entry. Preserve the return code from test_unsolicited_na_common() before constructing the test description. The array assignment previously reset the return code to zero and caused existing cases to report false success. Fixes: f9a2fb73318e ("net/ipv6: Introduce accept_unsolicited_na knob to imp= lement router-side changes for RFC9131") Link: https://lore.kernel.org/r/20260813233344.445265-1-lfqlee314@gmail.com Assisted-by: LLM Sashiko sparse Signed-off-by: Lawrence Lee --- .../net/ndisc_unsolicited_na_test.sh | 195 ++++++++++++++---- 1 file changed, 160 insertions(+), 35 deletions(-) diff --git a/tools/testing/selftests/net/ndisc_unsolicited_na_test.sh b/too= ls/testing/selftests/net/ndisc_unsolicited_na_test.sh index 5db69dad0cfc..ba9e670b5149 100755 --- a/tools/testing/selftests/net/ndisc_unsolicited_na_test.sh +++ b/tools/testing/selftests/net/ndisc_unsolicited_na_test.sh @@ -3,12 +3,18 @@ =20 # This test is for the accept_untracked_na feature to # enable RFC9131 behaviour. The following is the test-matrix. -# drop accept fwding behaviour -# ---- ------ ------ ---------------------------------------------- -# 1 X X Don't update NC -# 0 0 X Don't update NC -# 0 1 0 Don't update NC -# 0 1 1 Add a STALE NC entry +# state drop accept fwding behaviour +# ------ ---- ------ ------ -----------------------------------------= ----- +# absent 1 X X Don't update NC +# absent 0 0 X Don't update NC +# absent 0 1 0 Don't update NC +# absent 0 1 1 Add a STALE NC entry +# failed 1 X X Keep the NC entry in FAILED state +# failed 0 0 X Keep the NC entry in FAILED state +# failed 0 1 0 Keep the NC entry in FAILED state +# failed 0 1 1 Update the NC entry to STALE +# failed 0 2 1 Update the NC entry to STALE if in-network +# failed 0 2 1 Keep the NC entry FAILED if out-of-network =20 source lib.sh ret=3D0 @@ -19,14 +25,18 @@ PAUSE=3Dno HOST_INTF=3D"veth-host" ROUTER_INTF=3D"veth-router" =20 -ROUTER_ADDR=3D"2000:20::1" +ROUTER_ADDR_IN_NETWORK=3D"2000:20::1" +ROUTER_ADDR_OUT_OF_NETWORK=3D"2000:21::1" +ROUTER_ADDR=3D"${ROUTER_ADDR_IN_NETWORK}" HOST_ADDR=3D"2000:20::2" +HOST_LLADDR=3D"02:00:00:00:00:02" SUBNET_WIDTH=3D64 ROUTER_ADDR_WITH_MASK=3D"${ROUTER_ADDR}/${SUBNET_WIDTH}" HOST_ADDR_WITH_MASK=3D"${HOST_ADDR}/${SUBNET_WIDTH}" =20 tcpdump_stdout=3D tcpdump_stderr=3D +tcpdump_pid=3D =20 log_test() { @@ -75,6 +85,7 @@ setup() =20 ${IP_ROUTER} link add ${ROUTER_INTF} type veth \ peer name ${HOST_INTF} netns ${HOST_NS} + ${IP_HOST} link set dev "${HOST_INTF}" address "${HOST_LLADDR}" =20 # Enable IPv6 on both router and host, and configure static addresses. # The router here is the DUT @@ -88,6 +99,8 @@ setup() ${ROUTER_CONF}.drop_unsolicited_na=3D${drop_unsolicited_na} ${IP_ROUTER_EXEC} sysctl -qw \ ${ROUTER_CONF}.accept_untracked_na=3D${accept_untracked_na} + ${IP_ROUTER_EXEC} sysctl -qw \ + ${ROUTER_CONF}.ndisc_evict_nocarrier=3D0 ${IP_ROUTER_EXEC} sysctl -qw ${ROUTER_CONF}.disable_ipv6=3D0 ${IP_ROUTER} addr add ${ROUTER_ADDR_WITH_MASK} dev ${ROUTER_INTF} =20 @@ -102,24 +115,39 @@ setup() } =20 start_tcpdump() { - set -e - tcpdump_stdout=3D`mktemp` - tcpdump_stderr=3D`mktemp` + tcpdump_stdout=3D$(mktemp) || return 1 + tcpdump_stderr=3D$(mktemp) || return 1 ${IP_ROUTER_EXEC} timeout 15s \ tcpdump --immediate-mode -tpni ${ROUTER_INTF} -c 1 \ "icmp6 && icmp6[0] =3D=3D 136 && src ${HOST_ADDR}" \ - > ${tcpdump_stdout} 2> /dev/null - set +e + > "${tcpdump_stdout}" 2> "${tcpdump_stderr}" & + tcpdump_pid=3D$! + + slowwait 5 grep -q "listening on ${ROUTER_INTF}" "${tcpdump_stderr}" +} + +wait_tcpdump() +{ + local rc + + wait "${tcpdump_pid}" + rc=3D$? + tcpdump_pid=3D + + return "${rc}" } =20 cleanup_tcpdump() { - set -e - [[ ! -z ${tcpdump_stdout} ]] && rm -f ${tcpdump_stdout} - [[ ! -z ${tcpdump_stderr} ]] && rm -f ${tcpdump_stderr} + if [ -n "${tcpdump_pid}" ]; then + kill "${tcpdump_pid}" 2> /dev/null + wait "${tcpdump_pid}" 2> /dev/null + fi + [ -n "${tcpdump_stdout}" ] && rm -f "${tcpdump_stdout}" + [ -n "${tcpdump_stderr}" ] && rm -f "${tcpdump_stderr}" tcpdump_stdout=3D tcpdump_stderr=3D - set +e + tcpdump_pid=3D } =20 cleanup() @@ -129,58 +157,145 @@ cleanup() ip netns del ${ROUTER_NS} } =20 -link_up() { - set -e +router_link_up() +{ ${IP_ROUTER} link set dev ${ROUTER_INTF} up +} + +host_link_up() +{ ${IP_HOST} link set dev ${HOST_INTF} up - set +e } =20 verify_ndisc() { local drop_unsolicited_na=3D$1 local accept_untracked_na=3D$2 local forwarding=3D$3 + local initial_state=3D${4:-absent} + local same_subnet=3D${5:-1} + local expected_lladdr + local neigh_show_output + local expected_state + + if [ "${drop_unsolicited_na}" -eq 0 ] && + [ "${forwarding}" -eq 1 ]; then + case "${accept_untracked_na}" in + 1) + expected_state=3DSTALE + expected_lladdr=3D"${HOST_LLADDR}" + ;; + 2) + if [ "${same_subnet}" -eq 1 ]; then + expected_state=3DSTALE + expected_lladdr=3D"${HOST_LLADDR}" + fi + ;; + esac + fi + if [ -z "${expected_state}" ] && + [ "${initial_state}" =3D "failed" ]; then + expected_state=3DFAILED + fi =20 - neigh_show_output=3D$(${IP_ROUTER} neigh show \ - to ${HOST_ADDR} dev ${ROUTER_INTF} nud stale) - if [ ${drop_unsolicited_na} -eq 0 ] && \ - [ ${accept_untracked_na} -eq 1 ] && \ - [ ${forwarding} -eq 1 ]; then - # Neighbour entry expected to be present for 011 case - [[ ${neigh_show_output} ]] + if [ -n "${expected_state}" ]; then + neigh_show_output=3D$(${IP_ROUTER} neigh show \ + to "${HOST_ADDR}" dev "${ROUTER_INTF}") + if [[ " ${neigh_show_output} " !=3D \ + *" ${expected_state} "* ]]; then + return 1 + fi + if [ -n "${expected_lladdr}" ] && + [[ " ${neigh_show_output} " !=3D \ + *" lladdr ${expected_lladdr} "* ]]; then + return 1 + fi + if [[ "${expected_state}" =3D=3D "FAILED" && + "${neigh_show_output}" =3D=3D *"lladdr"* ]]; then + return 1 + fi + if [ "${initial_state}" =3D "failed" ]; then + [[ "${neigh_show_output}" =3D=3D *"extern_learn"* ]] + fi else - # Neighbour entry expected to be absent for all other cases + neigh_show_output=3D$(${IP_ROUTER} neigh show \ + to "${HOST_ADDR}" dev "${ROUTER_INTF}") [[ -z ${neigh_show_output} ]] fi } =20 test_unsolicited_na_common() { + local same_subnet=3D${5:-1} + local neigh_show_output + + if [ "${same_subnet}" -eq 1 ]; then + ROUTER_ADDR=3D"${ROUTER_ADDR_IN_NETWORK}" + else + ROUTER_ADDR=3D"${ROUTER_ADDR_OUT_OF_NETWORK}" + fi + ROUTER_ADDR_WITH_MASK=3D"${ROUTER_ADDR}/${SUBNET_WIDTH}" + # Setup the test bed, but keep links down - setup $1 $2 $3 + setup "$1" "$2" "$3" + + if [ "${4:-absent}" =3D "failed" ]; then + if ! ${IP_ROUTER} neigh replace "${HOST_ADDR}" \ + dev "${ROUTER_INTF}" \ + nud failed extern_learn; then + echo "Unable to create NUD_FAILED neighbor entry" + return 1 + fi + neigh_show_output=3D$(${IP_ROUTER} neigh show \ + to "${HOST_ADDR}" dev "${ROUTER_INTF}") + if [[ " ${neigh_show_output} " !=3D *" FAILED "* ]]; then + echo "Unable to verify NUD_FAILED neighbor entry" + return 1 + fi + if [[ "${neigh_show_output}" !=3D *"extern_learn"* ]]; then + echo "Neighbor entry is not externally learned" + return 1 + fi + fi =20 - # Bring the link up, wait for the NA, - # and add a delay to ensure neighbour processing is done. - link_up - start_tcpdump + # Arm the capture before bringing up the host and starting DAD. + router_link_up || return 1 + start_tcpdump || return 1 + host_link_up || return 1 + + # Closing tcpdump's packet socket calls synchronize_net(), so waiting + # for it also waits for receive processing of the captured NA. + wait_tcpdump || return 1 =20 # Verify the neighbour table - verify_ndisc $1 $2 $3 + verify_ndisc "$1" "$2" "$3" "$4" "${same_subnet}" =20 } =20 test_unsolicited_na_combination() { - test_unsolicited_na_common $1 $2 $3 + local initial_state=3D${4:-absent} + local same_subnet=3D${5:-1} + local rc + + test_unsolicited_na_common "$1" "$2" "$3" "${initial_state}" \ + "${same_subnet}" + rc=3D$? test_msg=3D("test_unsolicited_na: " "drop_unsolicited_na=3D$1 " "accept_untracked_na=3D$2 " "forwarding=3D$3") - log_test $? 0 "${test_msg[*]}" + if [ "${initial_state}" =3D "failed" ]; then + test_msg+=3D("initial_state=3Dfailed") + fi + if [ "$2" -eq 2 ]; then + test_msg+=3D("same_subnet=3D${same_subnet}") + fi + log_test "${rc}" 0 "${test_msg[*]}" cleanup } =20 test_unsolicited_na_combinations() { # Args: drop_unsolicited_na accept_untracked_na forwarding + # [initial_state] [same_subnet] =20 # Expect entry test_unsolicited_na_combination 0 1 1 @@ -193,6 +308,16 @@ test_unsolicited_na_combinations() { test_unsolicited_na_combination 1 0 1 test_unsolicited_na_combination 1 1 0 test_unsolicited_na_combination 1 1 1 + + # Expect FAILED entry to become STALE + test_unsolicited_na_combination 0 1 1 failed + test_unsolicited_na_combination 0 2 1 failed 1 + + # Expect FAILED entry to remain FAILED + test_unsolicited_na_combination 0 0 1 failed + test_unsolicited_na_combination 0 1 0 failed + test_unsolicited_na_combination 1 1 1 failed + test_unsolicited_na_combination 0 2 1 failed 0 } =20 ##########################################################################= ##### --=20 2.43.0