From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-pj1-f43.google.com (mail-pj1-f43.google.com [209.85.216.43]) (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 656F24D37DA for ; Fri, 9 Oct 2026 12:24:38 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.216.43 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1791548685; cv=none; b=PAVKHjSR8G3VCmSRWCtZ6dQ4ov/A8K9t2d7qnGddZfr5xtZB+Eg27eCRPmFM0n6wJMRed7GB3hX+7Y3EMY6UVUMhBK1dnFxPeGS7x7FCMVN9Ovpd/47fX86YEGbfKItv2F3xXr5qiZD8okkvieFu11yiOpzxYUE3KJekxhymgAE= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1791548685; c=relaxed/simple; bh=TmplD7M3/ZS5S2MqUm5uRoy8Tnhp/HPPz1KHIvm0O+Q=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=YsF+Ik864BKhyTA/d6p975XL45pIyMtbYpUUcZiQeqvU+WwKTOKk9rUHWMqCLWOqboU4xQU45meBhvpOmLSRHRROV45K+RK70alPRTjWIeA74KyUOFDPwkmU6Q7PUiYlM169N7FLOQm9+7qNWNBddtvSGmNtQllN3Y0nbPeo/YA= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=blockcast.net; spf=pass smtp.mailfrom=blockcast.net; dkim=pass (2048-bit key) header.d=blockcast.net header.i=@blockcast.net header.b=qX2nhVKP; arc=none smtp.client-ip=209.85.216.43 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=blockcast.net Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=blockcast.net Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=blockcast.net header.i=@blockcast.net header.b="qX2nhVKP" Received: by mail-pj1-f43.google.com with SMTP id 98e67ed59e1d1-3a49623b865so3939438a91.0 for ; Fri, 09 Oct 2026 05:24:38 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=blockcast.net; s=google; t=1791548677; x=1792153477; 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=nZvhZNf/1EH5SUhLAT8AYkRI8zQOSFEZ0YB2gJwWoYA=; b=qX2nhVKPpKITrWjwsp9sMMj4p/vpOcQt2NFvGVYqbYxx5Tzl3g0P4iNi9yXk6X1hoD aHHIHDwBStO5teYG3pipRNZebZdBuz3FTPCwSgQAFtXaYxRozJ4wYFItvbcwmbgQyoRS 9bMAJedb90MINk2akYDwz7TMla5jiG/1dfGmxcZ9GG7v6qQFHjog77NcHPAjJnqydzic Gsh0tSh1KdlzlK7wlDT6vPhuARoi4CDQYcz7ZFIin3yXRxUSlmeh6L1a+0tMnpvq5zLn pcRauf3QBl7qxGWTX1/cA7XoWadfTGB8aoKKT0Kk+yXqXxfHOxXF5JA69y6amlthzwf4 H28g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1791548677; x=1792153477; 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=nZvhZNf/1EH5SUhLAT8AYkRI8zQOSFEZ0YB2gJwWoYA=; b=MexCq8Q6i6HSe2roi+3G5ho6CHHx+gwAZ7fvY+ama87qjs4sYv8ZOI0tS8ibhufaNw KUO+aKYh4+ScZ4WkC1wN/durH4ND9fsYnyByW3jV7O50Q7aRSTN8pEUQoK8onsIiaec+ zq5yzYwJNcQ6CM+0pW+g+U5k2NSZcLBWk/kyLjOGn5ueK7DZ25XaFDM0Gj103iG6L/MV sekk9eJ9vO5G+bZ/Zr6XXBTzMzamjJGq4d82xYJs9HmNK9RdIH9kCJ03RTATeDYemc27 DEC0MG3sj6rk/0tIC0S9muN14sPNy0eVC6rsgdamdeW1TYTVS39BtAVEtixzUL9fcdKx LxHQ== X-Forwarded-Encrypted: i=1; AKwUvBy3Wfc8zqkuv6LHhv+whpd8xHEU2FHgsI0jiKLW+sUrzoQXLHIOmyG5yUo61u37tRVYV6KkfZK5LVEvRts=@vger.kernel.org X-Gm-Message-State: AFq9FYLdMDZpKCVy+qG9n61y/CCwBJPaEGm1tTEHfWCjBv45ql9ycFOL ChZZazQhoI+Jk/23y55ANmipAnud517X+SZ8ojnz8rkWbtTzXaXUs5vgujQWKFqLzqQ= X-Gm-Gg: AYBFou1SA6ZDFAkA19XmwFkARopyuTVh+Hxpdo9tTq4CUOd7B+ersI+24oTAcfBYEOb lt7SVu1AIq43PelUPSxnd3YxHUeTbjy3fTWFKWkPKj9jUsyYjE+mn/dXv3DbqaS7CA37rofvU2n y9Cs83HPKL6W7n94RFAl2nRNKNgf7s88K5enUPybpk9Q/gd6N4mBc/pL9qCJ020xrgFR/A21XMk p55/YZ92GfJMrFHD3js8+L4FZnwgSWXvNYHkCDR9WB+/6jwY5VujpRJfUktT0zrnY371ElxiO+7 7l64nJDJV8IRtCgLWicUF0lHXhaKfO9fLvulf633ayP6diVA7G2EesqZdPVeYsq0/J32GRdAbMJ wCzsART6nlwdkGnxHkbHcJmJ0irke555jhdl9ntVNABTu17Anh48fnY0vuJ4TqXVP1Gm83jFF9/ nYU3ZjPoiwL7jMpbpl8WwgXQ7viyL8PJyMz7cZmzxgY9ZnBRX2qhN6IPc08hCKB6PPZyjNRFQav wseX9Yf75KUchqGB08UETTF1P8L++gdvW2SZngy X-Received: by 2002:a17:90b:4b:b0:3ab:2c2b:1030 with SMTP id 98e67ed59e1d1-3ab3a747cfcmr1496285a91.22.1791548677492; Fri, 09 Oct 2026 05:24:37 -0700 (PDT) Received: from devbox.ts.blockcast.net ([2602:f74d:1::32]) by smtp.gmail.com with ESMTPSA id 98e67ed59e1d1-3ab55e41eefsm1660502a91.10.2026.10.09.05.24.36 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 09 Oct 2026 05:24:37 -0700 (PDT) From: Omar Ramadan To: Taehee Yoo , Andrew Lunn , "David S . Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Shuah Khan Cc: Simon Horman , netdev@vger.kernel.org, linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH net-next 04/13] amt: send the Membership Query over IPv6 Date: Fri, 9 Oct 2026 12:24:17 +0000 Message-ID: <20261009122426.551178-5-omar@blockcast.net> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20261009122426.551178-1-omar@blockcast.net> References: <20261009122426.551178-1-omar@blockcast.net> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit After the Request, a relay answers each gateway with a Membership Query through amt_send_membership_query(), which routes and transmits only over IPv4. Rather than adding an IPv6 twin of the function, move its routing and transmit step into amt_udp_xmit(). Given an skb that already carries the AMT message, a union amt_addr destination and the port pair, it sends over the device's family: ip_route_output_key() and udp_tunnel_xmit_skb() for IPv4, as before, and amt_route6() and udp_tunnel6_xmit_skb(), which fills in the mandatory IPv6 UDP checksum, for IPv6. Both use AMT_TOS, as the IPv4 path and the IPv6 control messages do. udp_tunnel_xmit_skb() scrubs the skb in iptunnel_xmit(), but udp_tunnel6_xmit_skb() does not, so the IPv6 path calls skb_scrub_packet() itself. Otherwise the conntrack entry and extensions of the inner packet would stay on the outer one, which conntrack would then pass as an already tracked flow. amt_send_membership_query() sizes its headroom for the outer family with amt_ip_hlen(), builds the AMT header and hands the skb to amt_udp_xmit(). The route lookup now runs after the header push; on a route failure the caller still frees the skb. The relay's General Query, which amt_send_igmp_gq() and amt_send_mld_gq() now send directly through amt_send_membership_query(), takes the IPv6 path with no change to those functions. Assisted-by: LLM Signed-off-by: Omar Ramadan --- drivers/net/amt.c | 94 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 68 insertions(+), 26 deletions(-) diff --git a/drivers/net/amt.c b/drivers/net/amt.c index eaa5637..5e8a74c 100644 --- a/drivers/net/amt.c +++ b/drivers/net/amt.c @@ -88,6 +88,11 @@ static bool amt_v6(const struct amt_dev *amt) return IS_ENABLED(CONFIG_IPV6) && !ipv6_addr_any(&amt->local_ipv6); } +static unsigned int amt_ip_hlen(const struct amt_dev *amt) +{ + return amt_v6(amt) ? sizeof(struct ipv6hdr) : sizeof(struct iphdr); +} + /* Copy the outer source address of a received message by value, so that * the caller may pull the skb afterwards. */ @@ -1098,6 +1103,65 @@ static void amt_req_work(struct work_struct *work) msecs_to_jiffies(100)); } +/* Route an AMT-encapsulated skb to @daddr and send it over the device's + * outer family. The caller has already pushed the AMT header. + */ +static int amt_udp_xmit(struct amt_dev *amt, struct sock *sk, + struct sk_buff *skb, const union amt_addr *daddr, + __be16 sport, __be16 dport) +{ + struct rtable *rt; + struct flowi4 fl4; + + if (amt_v6(amt)) { + struct dst_entry *dst; + + dst = amt_route6(amt, sk, &amt->local_ipv6, &daddr->ip6, + sport, dport); + if (IS_ERR(dst)) { + netdev_dbg(amt->dev, "no route to %pI6c\n", + &daddr->ip6); + return PTR_ERR(dst); + } + /* iptunnel_xmit() scrubs the IPv4 tunnel skb, but + * udp_tunnel6_xmit_skb() does not, so drop the inner + * packet's conntrack and extensions here. Links cannot + * cross netns, so this is never xnet. + */ + skb_scrub_packet(skb, false); + udp_tunnel6_xmit_skb(dst, sk, skb, amt->dev, &amt->local_ipv6, + &daddr->ip6, AMT_TOS, + ip6_dst_hoplimit(dst), 0, sport, dport, + false, 0); + return 0; + } + + memset(&fl4, 0, sizeof(struct flowi4)); + fl4.flowi4_oif = amt->stream_dev->ifindex; + fl4.daddr = daddr->ip4; + fl4.saddr = amt->local_ip; + fl4.flowi4_dscp = inet_dsfield_to_dscp(AMT_TOS); + fl4.flowi4_proto = IPPROTO_UDP; + rt = ip_route_output_key(amt->net, &fl4); + if (IS_ERR(rt)) { + netdev_dbg(amt->dev, "no route to %pI4\n", &daddr->ip4); + return PTR_ERR(rt); + } + + udp_tunnel_xmit_skb(rt, sk, skb, + fl4.saddr, + fl4.daddr, + AMT_TOS, + ip4_dst_hoplimit(&rt->dst), + 0, + sport, + dport, + false, + false, + 0); + return 0; +} + static bool amt_send_membership_update(struct amt_dev *amt, struct sk_buff *skb, bool v6) @@ -1230,8 +1294,6 @@ static bool amt_send_membership_query(struct amt_dev *amt, bool v6) { struct amt_header_membership_query *amtmq; - struct rtable *rt; - struct flowi4 fl4; struct sock *sk; int err; @@ -1240,23 +1302,11 @@ static bool amt_send_membership_query(struct amt_dev *amt, return true; err = skb_cow_head(skb, LL_RESERVED_SPACE(amt->dev) + sizeof(*amtmq) + - sizeof(struct iphdr) + sizeof(struct udphdr)); + amt_ip_hlen(amt) + sizeof(struct udphdr)); if (err) return true; skb_reset_inner_headers(skb); - memset(&fl4, 0, sizeof(struct flowi4)); - fl4.flowi4_oif = amt->stream_dev->ifindex; - fl4.daddr = tunnel->addr.ip4; - fl4.saddr = amt->local_ip; - fl4.flowi4_dscp = inet_dsfield_to_dscp(AMT_TOS); - fl4.flowi4_proto = IPPROTO_UDP; - rt = ip_route_output_key(amt->net, &fl4); - if (IS_ERR(rt)) { - netdev_dbg(amt->dev, "no route to %pI4\n", &tunnel->addr.ip4); - return true; - } - amtmq = skb_push(skb, sizeof(*amtmq)); amtmq->version = 0; amtmq->type = AMT_MSG_MEMBERSHIP_QUERY; @@ -1270,17 +1320,9 @@ static bool amt_send_membership_query(struct amt_dev *amt, skb_set_inner_protocol(skb, htons(ETH_P_IP)); else skb_set_inner_protocol(skb, htons(ETH_P_IPV6)); - udp_tunnel_xmit_skb(rt, sk, skb, - fl4.saddr, - fl4.daddr, - AMT_TOS, - ip4_dst_hoplimit(&rt->dst), - 0, - amt->relay_port, - tunnel->source_port, - false, - false, - 0); + if (amt_udp_xmit(amt, sk, skb, &tunnel->addr, amt->relay_port, + tunnel->source_port)) + return true; amt_update_relay_status(tunnel, AMT_STATUS_SENT_QUERY, true); return false; } -- 2.43.0