From nobody Sat Feb 7 17:54:54 2026 Received: from out-176.mta1.migadu.com (out-176.mta1.migadu.com [95.215.58.176]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 544AD32E737 for ; Fri, 14 Nov 2025 14:57:10 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=95.215.58.176 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1763132232; cv=none; b=gKxVXSycfPULpBv+ZVf7aiD4UUGdVrfNxTvjlFljV+7Ca/EZn40skhrfBnhEh6atsrmz9cwOmgKj2csFp2fOe1u/IaKnrJCvhaQ8/qWKpY2b2Ki5eObzh0SHxSoScqSVlGfcNMmMcbaqx0RAcLflkqCg/UNsqPIDh/Tu0BfC1aY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1763132232; c=relaxed/simple; bh=xauUswBoLMFSzRmMwdlcsAl0rkGHpTKz2CtgNOaktKU=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=iSFZMssNY2af/EaC2Vr4IMkrxMO/eWyt/Vt8iWNGckbTGTUVo9kiPTzq9Id1xHjO/FEvzgCKZZEESwe/SrtDiCNJ+OkbroDRsh3qwU05xcjLptIvlj0zGm4JK466atxDzuAZCTCxl2TCKrDp6PElbiszp8bYg70YTKYfqyoeZPU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=dzwdz.net; spf=pass smtp.mailfrom=dzwdz.net; dkim=pass (2048-bit key) header.d=dzwdz.net header.i=@dzwdz.net header.b=rY2XBcTo; arc=none smtp.client-ip=95.215.58.176 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=dzwdz.net Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=dzwdz.net Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=dzwdz.net header.i=@dzwdz.net header.b="rY2XBcTo" X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=dzwdz.net; s=key1; t=1763132226; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=U/IYMpUaNXsqfh7isVdh2eJJOJMSfyZEONyFvaN55Dw=; b=rY2XBcToi5CkAziRygtloEF++TRj6PhTpVWepL42DXntZNIxDjpsvaf++Gpqyogeogam9l lHhRfRUtXForbrMQfPwlai9KlYGwiL6SEZKEQF0Td1CMhMYLQ22Yv94F8p2yR1QH7cD4AW KdPDWGFpe8Qb3HOhha/Eggqc9v+MnPT+vbWPIAzidFQNG8MP1dKcoT1iMEM3cbNw7zBEdw ddwGO63i7KCGybnTpSRIsY+OJSElEe93AEcAV7MT4MwZXWMU/9QLiZmf/kjcVJ/ptmiWD5 JKR5Hgh/92/fvQiPyHnw4hxopXEsVtC/J9TcQoIbPGCwnCMRhJd7yQX/ivWjNw== From: =?UTF-8?q?Jakub=20G=C5=82ogowski?= To: Alejandro Colomar Cc: =?UTF-8?q?Jakub=20G=C5=82ogowski?= , linux-man@vger.kernel.org, LKML , Linux API , ej@inai.de Subject: [PATCH 1/2] man/man7/ip.7: Clarify PKTINFO's semantics depending on packet direction Date: Fri, 14 Nov 2025 15:29:30 +0100 Message-ID: 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-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable X-Migadu-Flow: FLOW_OUT For recvmsg(2), ipi_spec_dst is set by ipv4_pktinfo_prepare() to the result of fib_compute_sec_dst(). The latter was introduced in linux.git 35ebf65e851c6d97 ("ipv4: Create and use fib_compute_spec_dst() h= elper."). Quoting its commit message: > The specific destination is the host we direct unicast replies to. > Usually this is the original packet source address, but if we are > responding to a multicast or broadcast packet we have to use something > different. > > Specifically we must use the source address we would use if we were to > send a packet to the unicast source of the original packet. Experimentation seems to confirm that behavior. As for the note about ipi_spec_dst being on a different interface: - For unicast packets (for which ipi_spec_dst is the original destination address), I believe this is trivially true because Linux uses the weak host model (unless there's some interaction with RTCF_LOCAL that I'm missing). - For multicast/broadcast packets, fib_compute_sec_dst() only passes the original interface to the lookup in the context of L3M. In particular, the original implementation (cited above) set iif and oof to 0. Also, citing linux.git e7372197e15856ec ("net/ipv4: Set oif in fib_compute_spec_dst"), > If the device is not enslaved, oif is still 0 so no affect. It doesn't seem like using an address specifically from the interface the packet was received on was ever the intention. I've also confirmed this behavior (sending a multicast packet from another machine, whose IP I've routed to a dummy interface). I'm focusing on this because that's a misconception I've had before digging into the code - the sendmsg behavior explained in the same paragraph made me think ipi_spec_dst was the (primary?) address of ipi_ifindex. I think this is worth clarifying. I've made it explicit that ipi_addr isn't used by sendmsg because that's another possible misconception. The (first) extra comma in sendmsg's ipi_spec_dst's description is meant to emphasize that it's used as the local source address _and_ for the routing table lookup, as opposed to just affecting the routing table lookup. Stylistically it might be a bit weird but idk how to convey this better. Apart from the cited commits I was referencing the linux-6.17.7 tarball. __fib_validate_source (and the comment near it) might also be of interest to people trying to figure out what "specific destinations" are, exactly. Signed-off-by: Jakub G=C5=82ogowski --- man/man7/ip.7 | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/man/man7/ip.7 b/man/man7/ip.7 index a92939cd0..a7f118b42 100644 --- a/man/man7/ip.7 +++ b/man/man7/ip.7 @@ -809,12 +809,20 @@ .SS Socket options .EE .in .IP +When returned by +.BR recvmsg (2) , .I ipi_ifindex is the unique index of the interface the packet was received on. .I ipi_spec_dst -is the local address of the packet and +is the preferred source address for replies to the given packet, and .I ipi_addr is the destination address in the packet header. +These addresses are usually the same, +but can differ for broadcast or multicast packets. +Note that, depending on the configured routes, +.I ipi_spec_dst +might belong to a different interface from the one that received the packe= t. +.IP If .B IP_PKTINFO is passed to @@ -822,14 +830,16 @@ .SS Socket options and .\" This field is grossly misnamed .I ipi_spec_dst -is not zero, then it is used as the local source address for the routing -table lookup and for setting up IP source route options. +is not zero, then it is used as the local source address, for the routing +table lookup, and for setting up IP source route options. When .I ipi_ifindex is not zero, the primary local address of the interface specified by the index overwrites .I ipi_spec_dst for the routing table lookup. +.I ipi_addr +is ignored. .IP Not supported for .B SOCK_STREAM --=20 2.47.3 From nobody Sat Feb 7 17:54:54 2026 Received: from out-180.mta1.migadu.com (out-180.mta1.migadu.com [95.215.58.180]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 5E41732ED28 for ; Fri, 14 Nov 2025 14:57:11 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=95.215.58.180 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1763132233; cv=none; b=da8arMQFNVc+LabB1S2mb3QBNYY04t9s/ptcBNyBVwLZ2Gs6Yb5BRDqJb8+qqvcuuBYthAMT2i2dyVbkne542dNajyc01MlFOO7x03bCXEg0KhYC2YDg3J2498xgTndYqE4evDSxGaQWNkGBPYaWAlDartNKZGG/DjFcQWUBRPQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1763132233; c=relaxed/simple; bh=W2Gcv0qFNa2nw3WotZuVReW5CUB2KVmI6C0Q/QkZuzE=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=bVwaWpYItM3CHQdfWaggPYDpN430d69gZm0rnOuAL6F44xXdY7pIF7fkoYj4/pNyNiBFSo4D2mMHs9+p+gMyim9WQlek8c8B/F0nxLgkzwyX8/TPYyPC27VeGRO+2wY0WX95DETpim3QL9V/ZLy+Rkibkk+JWfyA3gkDRQSqflU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=dzwdz.net; spf=pass smtp.mailfrom=dzwdz.net; dkim=pass (2048-bit key) header.d=dzwdz.net header.i=@dzwdz.net header.b=efW28XaQ; arc=none smtp.client-ip=95.215.58.180 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=dzwdz.net Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=dzwdz.net Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=dzwdz.net header.i=@dzwdz.net header.b="efW28XaQ" X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=dzwdz.net; s=key1; t=1763132229; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=bfJpda/GGjCKTqmdx5tIqUG7cVkIF4M2WisIV8rj7eg=; b=efW28XaQn8IGCIkFrIM+a6O7ao0/VLNlpBw1wAwafzWc++KLFVtGR9qmVEMIn8jFYqNdsj Di9s9pACROiVBRJZuUNLu49IatpWr9Q7xuLMQbYTzJ+1qbykd6GCilY74EGKzxqH1OAwsb NzxsrogZuaJYE9rWgDMpQYbitA7FAtKTX4g5sAyIj/EJtRLjPw86abBBlu72rXej5oabtV WHUBwUQ6GUq/CazE3arVCq0JZdDwngq/Tj5ioGpDqtFx3/eHGnyRkjSj2e/4CZ8HLIhKHH eIRVKOtJxQwLGF/a6n0EannOwL5ij7zeDzkhhgljDPNzM/PZoo43+NULJ7LAOg== From: =?UTF-8?q?Jakub=20G=C5=82ogowski?= To: Alejandro Colomar Cc: =?UTF-8?q?Jakub=20G=C5=82ogowski?= , linux-man@vger.kernel.org, LKML , Linux API , ej@inai.de Subject: [PATCH 2/2] man/man7/ip.7: Reword IP_PKTINFO's description Date: Fri, 14 Nov 2025 15:29:31 +0100 Message-ID: <38cfae87620d99ab0fa15f1970ef18d4ab5ff5a5.1763130571.git.not@dzwdz.net> 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-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable X-Migadu-Flow: FLOW_OUT I've heavily cut down the first paragraph (which wasn't really saying anything), and emphasized the difference between how recvmsg(2) and sendmsg(2) treat this struct. "This works only for datagram oriented sockets" is redundant with "Not supported for SOCK_STREAM", and the mention of sendmsg(2) was moved down. I called it a boolean option because that's how these were introduced at the start of the section. I've tried rewording ipi_spec_dst's effect on sendmsg to be a bit more clear. The only piece of new information which this adds is that you can use the structure returned by recvmsg with sendmsg, which directly follows from the preceding text. RFC 3542, Section 6, directly calls out this usecase for in6_pktinfo: > Some UDP servers want to respond to client > requests by sending their reply out the same interface on which the > request was received and with the source IPv6 address of the reply > equal to the destination IPv6 address of the request. To do this the > application can enable just the IPV6_RECVPKTINFO socket option and > then use the received control information from recvmsg() as the > outgoing control information for sendmsg(). The application need not > examine or modify the in6_pktinfo structure at all. I'm not sure if this is the best place to document this, as the sendmsg behavior is unrelated to the IP_PKTINFO sockopt at all. Maybe some of the control messages should be broken out to another manpage? Signed-off-by: Jakub G=C5=82ogowski --- man/man7/ip.7 | 49 +++++++++++++++++++++---------------------------- 1 file changed, 21 insertions(+), 28 deletions(-) diff --git a/man/man7/ip.7 b/man/man7/ip.7 index a7f118b42..aa2508bc7 100644 --- a/man/man7/ip.7 +++ b/man/man7/ip.7 @@ -783,20 +783,13 @@ .SS Socket options .TP .BR IP_PKTINFO " (since Linux 2.2)" .\" Precisely: since Linux 2.1.68 -Pass an -.B IP_PKTINFO -ancillary message that contains a -.I pktinfo -structure that supplies some information about the incoming packet. -This works only for datagram oriented sockets. -The argument is a flag that tells the socket whether the -.B IP_PKTINFO -message should be passed or not. -The message itself can be sent/retrieved -only as a control message with a packet using +If this boolean option is enabled, .BR recvmsg (2) -or -.BR sendmsg (2). +outputs an +.B IP_PKTINFO +ancillary message containing an +.I in_pktinfo +structure. .IP .in +4n .EX @@ -809,37 +802,37 @@ .SS Socket options .EE .in .IP -When returned by -.BR recvmsg (2) , +In this context, .I ipi_ifindex is the unique index of the interface the packet was received on. .I ipi_spec_dst is the preferred source address for replies to the given packet, and .I ipi_addr -is the destination address in the packet header. +is the destination address from the packet header. These addresses are usually the same, but can differ for broadcast or multicast packets. Note that, depending on the configured routes, .I ipi_spec_dst might belong to a different interface from the one that received the packe= t. .IP -If -.B IP_PKTINFO -is passed to -.BR sendmsg (2) -and +This structure can also be passed as an ancillary message to +.BR sendmsg (2) . +In that case, .\" This field is grossly misnamed .I ipi_spec_dst -is not zero, then it is used as the local source address, for the routing -table lookup, and for setting up IP source route options. -When +is used as the local source address +(if non-zero), +including for the purposes of setting up IP source route options. +It's also used for the routing table lookup, unless .I ipi_ifindex -is not zero, the primary local address of the interface specified by the -index overwrites -.I ipi_spec_dst -for the routing table lookup. +is non-zero \(en +then the primary local address of that interface is used there instead. .I ipi_addr is ignored. +The structure returned by +.BR recvmsg (2) +can be reused, +which effectively sends a reply to the original packet. .IP Not supported for .B SOCK_STREAM --=20 2.47.3