From nobody Fri Apr 3 11:10:25 2026 Received: from mail-pj1-f47.google.com (mail-pj1-f47.google.com [209.85.216.47]) (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 5B09626E165 for ; Mon, 30 Mar 2026 19:16:35 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.216.47 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774898196; cv=none; b=MTbzCKyBGo4YY+GZCm0FP/Y6lVC74YQowAtYH0X/JCvLIunfQ6zX51CcUlzDD5Y3h51y1TlFlmllLYpzZuxO3lPizfqh+fu9hsBejS+Vrqz6Pf/Ge92EsbC2Ngpqx0s+7NrqRbde/0a7dQMFeKiAf0T7sJ4ppRP4oBuh+1eUtpo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774898196; c=relaxed/simple; bh=WW0vISqU8GwrmrIC4NHoR+TFPQ7BlX0/FvDVbKYURp4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=KpDURiZl9fj22ikTyh3ECsHKqHmlsUI18aBrBBPkkc8Jtt1J8rjK1OXdOF1vDMdP0P6TPbtStYEgqaxdrLW2g9aaHjDTvwJUTyEmhmqNL+tVFDKGqmQuToe8ubu0lINS9IBrBbmc6ITCIGhNu8u8INs4rAjJhrG44j0ljrgw3do= 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=j5FsFZrY; arc=none smtp.client-ip=209.85.216.47 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="j5FsFZrY" Received: by mail-pj1-f47.google.com with SMTP id 98e67ed59e1d1-35d8e548a05so2929444a91.1 for ; Mon, 30 Mar 2026 12:16:35 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1774898195; x=1775502995; 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; bh=O2s2FZ+Hg0ngcpnnbi9FLabs6QrxAbJsZ+G4M5k6jv8=; b=j5FsFZrYBxRHFaLt0P/E8YV8ZMrWOhkJEI0Q90IrBhcd/x5gm8jCQZCHsIsYSko6f7 mCD01Wh0oEQdAKBsxwT4BhmNorRCIXw5fZmwrd6HvKIK+hvcFw50eivOqHjWPdXgnZ9v eKtdiEx70xferoH3H/+lGHswG6NZjRR07ZN+iyvO7XnYidwJBgaqB1hZ1xxmJLrFGPa4 vJNs2A/Kteg38JjuRsskjET5uokcYtmM9/BB5E9yPz5NIQxr8b45MbigEI8/nFZS6T08 OBQEAIDUJ+JZlspmU1D8jcEJUP3tpUYwLkBEL7PoA9TnBvrHCk7sv71t1SjO8WSUfBgy V6Ug== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1774898195; x=1775502995; 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; bh=O2s2FZ+Hg0ngcpnnbi9FLabs6QrxAbJsZ+G4M5k6jv8=; b=CkLrwxfhhyjfrxePZ4Totg0O0YZM32tJ+WWI4y84M8ES3+XxP9V0GJtUqqGWE5hkrP adxgbYLtOTwS8Yp0fV093uUgS+SMRYTl9j6STW3w0I4QXSJlZ/uoiQ6WnRMTo2L30NhF u60oyu4LW8egi2fk9MGXvptGWdUoq66u6a3g0ZdTFsMVOku+dsQiZRMlBSpAGQvPpQZx IpIUGx1mVb1m4LUqQzlnacfSqDTxB1aY/dqVemgXffvMx2pgUeM7B9YIB3SRRHlX0dZq V5qeTiiAujTx3Zw6S8VYAt/64RkBZda6AC4ru6r8j5q/72/ZuezHDfcGX7BAVQN5wSU7 HS9g== X-Forwarded-Encrypted: i=1; AJvYcCXVKyMkJmF8Iojgxa1/3Ggxf4vkFjdhRraUFIbKEFDzmRwMkGGAxcDkC7m/8LvFpdMST+cbHPJjjwK7o70=@vger.kernel.org X-Gm-Message-State: AOJu0Yyv4gbFCAmnIPGe+UTKf2jNKbOPFPjFMTP7DBRUItNU+xEgOcC7 Saqxb8paVeBeAovrpt1PxxzYq9HCkhonhbM1KzUN/v1ZuMWR1rjCYARV X-Gm-Gg: ATEYQzxBmtH5SZ8lS28Nf2SfSpqFBBLd9mAsJXrN/2Q2IeHW8lhPPMPNVb0lkVaD2CH YR1Ykuk315tywoEHs0QtLJTOD0j82Q+5mMQ6vYo0tN3arRmn7JA9Py/QB0ji/QKI3+j2BabnQo7 O8rH9dW6wTPBAXCOO1QSWGUrQkODwQWHWmSbETCrp6Pg20GjSZElGrNaFUTEzd/EJ6dYs9/MWPr 9+vZojjANNWZjH+6ueYH5Nve6PtPi9xXiqCKYcqG6bZLcv4UZZ079APDOKcb9ZBJqaAbkG27ZC7 Ww8OkA07yfT69V3wLiP6J04ERoGVzpuvu+fLmy2EW+T6yPsQCiZHB0ARvYk8+90q1R71A46UvN2 8tf5Dr+PjnU+Z++h6bFl9PczUS7hQ/Da6awmqxWc4CzgUnTayz8JctmR8yItBMt8HtEktge04d9 BRPDQUvPXjLI+dub1jCjgRPxA0huEcbXq6sffzIpNT X-Received: by 2002:a17:90b:3c8b:b0:35b:a1b6:5bf5 with SMTP id 98e67ed59e1d1-35c30146fe2mr12855192a91.31.1774898194656; Mon, 30 Mar 2026 12:16:34 -0700 (PDT) Received: from DESKTOP-82PPU4A.localdomain ([202.8.116.192]) by smtp.gmail.com with ESMTPSA id 98e67ed59e1d1-35d950d9b12sm9627178a91.17.2026.03.30.12.16.27 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 30 Mar 2026 12:16:34 -0700 (PDT) From: Ujjal Roy To: "David S . Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , Nikolay Aleksandrov , Ido Schimmel , David Ahern , Shuah Khan , Andy Roulin , Yong Wang , Petr Machata Cc: Ujjal Roy , bridge@lists.linux.dev, netdev@vger.kernel.org, linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org Subject: [PATCH net-next v2 1/5] ipv4: igmp: get rid of IGMPV3_{QQIC,MRC} and simplify calculation Date: Mon, 30 Mar 2026 19:16:07 +0000 Message-ID: <20260330191611.16929-2-royujjal@gmail.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260330191611.16929-1-royujjal@gmail.com> References: <20260330191611.16929-1-royujjal@gmail.com> 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" Get rid of the IGMPV3_MRC macro and use the igmpv3_mrt() API to calculate the Max Resp Time from the Maximum Response Code. Similarly, for IGMPV3_QQIC, use the igmpv3_qqi() API to calculate the Querier's Query Interval from the QQIC field. Signed-off-by: Ujjal Roy --- include/linux/igmp.h | 78 +++++++++++++++++++++++++++++++++++---- net/bridge/br_multicast.c | 2 +- net/ipv4/igmp.c | 6 +-- 3 files changed, 74 insertions(+), 12 deletions(-) diff --git a/include/linux/igmp.h b/include/linux/igmp.h index 073b30a9b850..3c12c0a63492 100644 --- a/include/linux/igmp.h +++ b/include/linux/igmp.h @@ -92,15 +92,77 @@ struct ip_mc_list { struct rcu_head rcu; }; =20 +/* RFC3376, relevant sections: + * - 4.1.1. Maximum Response Code + * - 4.1.7. QQIC (Querier's Query Interval Code) + * + * If Max Resp Code >=3D 128, Max Resp Code represents a floating-point + * value as follows: + * If QQIC >=3D 128, QQIC represents a floating-point value as follows: + * + * 0 1 2 3 4 5 6 7 + * +-+-+-+-+-+-+-+-+ + * |1| exp | mant | + * +-+-+-+-+-+-+-+-+ + */ +#define IGMPV3_FP_EXP(value) (((value) >> 4) & 0x07) +#define IGMPV3_FP_MAN(value) ((value) & 0x0f) + +/* IGMPV3 floating-point exponential field threshold */ +#define IGMPV3_EXP_MIN_THRESHOLD 128 + /* V3 exponential field decoding */ -#define IGMPV3_MASK(value, nb) ((nb)>=3D32 ? (value) : ((1<<(nb))-1) & (va= lue)) -#define IGMPV3_EXP(thresh, nbmant, nbexp, value) \ - ((value) < (thresh) ? (value) : \ - ((IGMPV3_MASK(value, nbmant) | (1<<(nbmant))) << \ - (IGMPV3_MASK((value) >> (nbmant), nbexp) + (nbexp)))) - -#define IGMPV3_QQIC(value) IGMPV3_EXP(0x80, 4, 3, value) -#define IGMPV3_MRC(value) IGMPV3_EXP(0x80, 4, 3, value) + +/* + * IGMPv3 QQI/MRT 8-bit exponential field decode. + * + * RFC3376, 4.1.1 & 4.1.7. defines the decoding formula: + * 0 1 2 3 4 5 6 7 + * +-+-+-+-+-+-+-+-+ + * |1| exp | mant | + * +-+-+-+-+-+-+-+-+ + * Max Resp Time =3D (mant | 0x10) << (exp + 3) + * QQI =3D (mant | 0x10) << (exp + 3) + */ +static inline unsigned long igmpv3_exp_field_decode(const u8 code) +{ + /* RFC3376, relevant sections: + * - 4.1.1. Maximum Response Code + * - 4.1.7. QQIC (Querier's Query Interval Code) + */ + if (code < IGMPV3_EXP_MIN_THRESHOLD) { + return (unsigned long)code; + } else { + unsigned long mc_man, mc_exp; + + mc_exp =3D IGMPV3_FP_EXP(code); + mc_man =3D IGMPV3_FP_MAN(code); + + return ((mc_man | 0x10) << (mc_exp + 3)); + } +} + +/* Calculate Max Resp Time from Maximum Response Code */ +static inline unsigned long igmpv3_mrt(const struct igmpv3_query *ih3) +{ + /* RFC3376, relevant sections: + * - 4.1.1. Maximum Response Code + * - 8.3. Query Response Interval + */ + return igmpv3_exp_field_decode(ih3->code); +} + +/* Calculate Querier's Query Interval from Querier's Query Interval Code */ +static inline unsigned long igmpv3_qqi(const struct igmpv3_query *ih3) +{ + /* RFC3376, relevant sections: + * - 4.1.7. QQIC (Querier's Query Interval Code) + * - 8.2. Query Interval + * - 8.12. Older Version Querier Present Timeout + * (the [Query Interval] in the last Query received) + */ + return igmpv3_exp_field_decode(ih3->qqic); +} =20 static inline int ip_mc_may_pull(struct sk_buff *skb, unsigned int len) { diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c index 881d866d687a..9fec76e887bc 100644 --- a/net/bridge/br_multicast.c +++ b/net/bridge/br_multicast.c @@ -3518,7 +3518,7 @@ static void br_ip4_multicast_query(struct net_bridge_= mcast *brmctx, goto out; =20 max_delay =3D ih3->code ? - IGMPV3_MRC(ih3->code) * (HZ / IGMP_TIMER_SCALE) : 1; + igmpv3_mrt(ih3) * (HZ / IGMP_TIMER_SCALE) : 1; } else { goto out; } diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index a674fb44ec25..8c6102737096 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c @@ -991,7 +991,7 @@ static bool igmp_heard_query(struct in_device *in_dev, = struct sk_buff *skb, * different encoding. We use the v3 encoding as more likely * to be intended in a v3 query. */ - max_delay =3D IGMPV3_MRC(ih3->code)*(HZ/IGMP_TIMER_SCALE); + max_delay =3D igmpv3_mrt(ih3)*(HZ/IGMP_TIMER_SCALE); if (!max_delay) max_delay =3D 1; /* can't mod w/ 0 */ } else { /* v3 */ @@ -1006,7 +1006,7 @@ static bool igmp_heard_query(struct in_device *in_dev= , struct sk_buff *skb, ih3 =3D igmpv3_query_hdr(skb); } =20 - max_delay =3D IGMPV3_MRC(ih3->code)*(HZ/IGMP_TIMER_SCALE); + max_delay =3D igmpv3_mrt(ih3)*(HZ/IGMP_TIMER_SCALE); if (!max_delay) max_delay =3D 1; /* can't mod w/ 0 */ WRITE_ONCE(in_dev->mr_maxdelay, max_delay); @@ -1016,7 +1016,7 @@ static bool igmp_heard_query(struct in_device *in_dev= , struct sk_buff *skb, * configured value. */ in_dev->mr_qrv =3D ih3->qrv ?: READ_ONCE(net->ipv4.sysctl_igmp_qrv); - in_dev->mr_qi =3D IGMPV3_QQIC(ih3->qqic)*HZ ?: IGMP_QUERY_INTERVAL; + in_dev->mr_qi =3D igmpv3_qqi(ih3)*HZ ?: IGMP_QUERY_INTERVAL; =20 /* RFC3376, 8.3. Query Response Interval: * The number of seconds represented by the [Query Response --=20 2.43.0 From nobody Fri Apr 3 11:10:25 2026 Received: from mail-pj1-f52.google.com (mail-pj1-f52.google.com [209.85.216.52]) (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 3F2FF382291 for ; Mon, 30 Mar 2026 19:16:42 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.216.52 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774898203; cv=none; b=JKWrVpIKCbBnGC2aFAdTtF9jJzblBPs3sLczHmszdVpzHTRCEcWP3Kuk8dN9I8oPq00+wy6qRUJrbfg92h4a8GxnN1DhoFK9qXSIWEHCkmgQPs4sQcpaJ14CIK4oFU4Ot3+Fj1XJizzB1f1WSW9uigEv7syyPmssgpsHMgnAZ08= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774898203; c=relaxed/simple; bh=yJDiUN34AyED1s3Mh0BhhgYdT8RuWlDR34wMFTuxleY=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=IGYy5Q29d12RjQSx8Y35TIYJEqzwYqT5DGsNIuQONayy8vEZ55IuMoYa9vnjPBZqoIKWg4loNxEuoFKPYZuWO19kPwCFSxhxKh5HnDfMNBMIiR1XJgN1XtUS4ZylJlMMn2PYIJXqp8RZbQJIP3SPYD2Zm4eWfkvqFXIbpIst4TE= 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=KXK0wAgJ; arc=none smtp.client-ip=209.85.216.52 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="KXK0wAgJ" Received: by mail-pj1-f52.google.com with SMTP id 98e67ed59e1d1-35d95017a68so1258299a91.3 for ; Mon, 30 Mar 2026 12:16:42 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1774898202; x=1775503002; 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; bh=c1FELrnIn+Cl/sQAWOOdScMKmjJwFkZRPYjIHZTYdfw=; b=KXK0wAgJ61ALIOtY3eaCOy+4gmxE0xDeBuy5pFyauw8fqqYCBIJZa1XHxYxIZN2AXx +Sy+tVx4kMu7EmQDGPla15+3mudmDYLi/dZzitNpBkrTxK0ih1LiKwZtf+9VBxPNymrF +k7gfMJ/17M7eTIIKzeOzOEQBn5PotyCgglu3KmikoSrpOLjCJUQRTAxizKXoRSJNFIt Rum/v7naw1yNmkroS/0VOlO/6l05+ZfjRcK0CYt/w3suc/5/GZwYi89h5NQgxPUF0GLB NXAklHQ9B2pDIDmo1bP9Wi2iQ1gMAlwvk1CZjyopx2AGs9GzkdDZT4204UJU6PNeotk1 dJOQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1774898202; x=1775503002; 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; bh=c1FELrnIn+Cl/sQAWOOdScMKmjJwFkZRPYjIHZTYdfw=; b=JZS7oqezLgEUe7r97WQnYUP4zsWArZVbjTFvAfvVQ/OYtOlvM//C5e4fW9de94fFqu MOwII7QmQAtPDpC8Fbleufbjh7sHZI0jlrRwBztvet4/fCAP5+10uo6YulmTs+SGwXck gak+wUm//4fKUPRg9FlLt3a/ZxN+mi5ZoEKH6Zj62yVhzC3z/0pqeHMEdreWFNoButAF p+qSwx5IwieLu+fsxNzC4TdZEQwT730cK5iehGRPGw9l4u4KimJLhdCMH+y7cWdkhfD9 tK0iS4X9aX9LFiXZrfOev79/9/POuhnqMnP0SRnoy6pEsgcydllRHWzEthWotFmbYHxL hYyw== X-Forwarded-Encrypted: i=1; AJvYcCVao2kIJSj7grbyGBaI8GYMK33bsnKbmj2r7XzWq1JlHzIySgaXV4O6FilgTeRlGdsNSy6sB40jQNj2dIA=@vger.kernel.org X-Gm-Message-State: AOJu0YxB9zk3DJp07c7iwyrnuvXwxjT2rVAqjRJF/Cr8vJaKpGyTJqxJ ZEpCUDz8jRGZTUfQxo8wO0Ff+E4zjOC5nfxbKAt1GxsnAgE5qSppkrBq X-Gm-Gg: ATEYQzwNTed64uI9ogai1qaF041QCWJbanZH1QslrDpjJ8nUiyMFGEYKN0tq2SMbb1H k/9GvctKvR6FayOEBv/KGpgP3zMXrI/XqVWkCXXRomeY7VlZRmLANIK7+KOPyzIt35WwBOwhFgJ jwcDzpPSIdYFz5Ay/MfZ54vNfjjD/pkWg3lyww5zBJ+3/zc+PIG50U/ZC2ReBO/1nt1NbcAiLT1 Z8PLoXdiFcKBiLlUv5V1C6OskbvLE0f1Ze6EODf6D9JDOSy1fgHKmDv+WVgAmgRzFuKsBGvEvHc oOVdjtm9lcTiPDU0xtrCpvMLvN5QMUY5rKk45dVRZSSjX3Eoad7bvYi4nq7JaTUEDQtrVOifXIF UcnIrvtcX5XAcxW9tXOpaHqnzzCD9KMl43yMBfNOmCA94CJBVybdW+Htw/rRyju3Wb0zzGY5rCk xlY/8f2DodWceVGdechwBjSGK7XLOZelrDD/19GwBG X-Received: by 2002:a17:90b:1d11:b0:35c:a8f:5c5f with SMTP id 98e67ed59e1d1-35c2ff6afecmr12284030a91.8.1774898201514; Mon, 30 Mar 2026 12:16:41 -0700 (PDT) Received: from DESKTOP-82PPU4A.localdomain ([202.8.116.192]) by smtp.gmail.com with ESMTPSA id 98e67ed59e1d1-35d950d9b12sm9627178a91.17.2026.03.30.12.16.35 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 30 Mar 2026 12:16:41 -0700 (PDT) From: Ujjal Roy To: "David S . Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , Nikolay Aleksandrov , Ido Schimmel , David Ahern , Shuah Khan , Andy Roulin , Yong Wang , Petr Machata Cc: Ujjal Roy , bridge@lists.linux.dev, netdev@vger.kernel.org, linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org Subject: [PATCH net-next v2 2/5] ipv6: mld: rename mldv2_mrc() and add mldv2_qqi() Date: Mon, 30 Mar 2026 19:16:08 +0000 Message-ID: <20260330191611.16929-3-royujjal@gmail.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260330191611.16929-1-royujjal@gmail.com> References: <20260330191611.16929-1-royujjal@gmail.com> 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" Rename mldv2_mrc() to mldv2_mrd() as it used to calculate the Maximum Response Delay from the Maximum Response Code. Introduce a new API mldv2_qqi() to define the existing calculation logic of QQI from QQIC. This also organizes the existing mld_update_qi() API. Added by e3f5b1704 ("net: ipv6: mld: get rid of MLDV2_MRC and simplify calc= ulation"). Signed-off-by: Ujjal Roy --- include/net/mld.h | 64 +++++++++++++++++++++++++++++++++------ net/bridge/br_multicast.c | 2 +- net/ipv6/mcast.c | 19 ++---------- 3 files changed, 58 insertions(+), 27 deletions(-) diff --git a/include/net/mld.h b/include/net/mld.h index c07359808493..5e093f9c75d9 100644 --- a/include/net/mld.h +++ b/include/net/mld.h @@ -89,29 +89,73 @@ struct mld2_query { #define MLDV2_QQIC_EXP(value) (((value) >> 4) & 0x07) #define MLDV2_QQIC_MAN(value) ((value) & 0x0f) =20 -#define MLD_EXP_MIN_LIMIT 32768UL -#define MLDV1_MRD_MAX_COMPAT (MLD_EXP_MIN_LIMIT - 1) +#define MLD_QQIC_MIN_THRESHOLD 128 +#define MLD_MRC_MIN_THRESHOLD 32768UL +#define MLDV1_MRD_MAX_COMPAT (MLD_MRC_MIN_THRESHOLD - 1) =20 #define MLD_MAX_QUEUE 8 #define MLD_MAX_SKBS 32 =20 -static inline unsigned long mldv2_mrc(const struct mld2_query *mlh2) -{ - /* RFC3810, 5.1.3. Maximum Response Code */ - unsigned long ret, mc_mrc =3D ntohs(mlh2->mld2q_mrc); +/* V2 exponential field decoding */ =20 - if (mc_mrc < MLD_EXP_MIN_LIMIT) { - ret =3D mc_mrc; +/* Calculate Maximum Response Delay from Maximum Response Code + * + * RFC3810, 5.1.3. defines the decoding formula: + * 0 1 2 3 4 5 6 7 8 9 A B C D E F + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |1| exp | mant | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * Maximum Response Delay =3D (mant | 0x1000) << (exp+3) + */ +static inline unsigned long mldv2_mrd(const struct mld2_query *mlh2) +{ + /* RFC3810, relevant sections: + * - 5.1.3. Maximum Response Code + * - 9.3. Query Response Interval + */ + unsigned long mc_mrc =3D ntohs(mlh2->mld2q_mrc); + + if (mc_mrc < MLD_MRC_MIN_THRESHOLD) { + return mc_mrc; } else { unsigned long mc_man, mc_exp; =20 mc_exp =3D MLDV2_MRC_EXP(mc_mrc); mc_man =3D MLDV2_MRC_MAN(mc_mrc); =20 - ret =3D (mc_man | 0x1000) << (mc_exp + 3); + return ((mc_man | 0x1000) << (mc_exp + 3)); } +} =20 - return ret; +/* Calculate Querier's Query Interval from Querier's Query Interval Code + * + * RFC3810, 5.1.9. defines the decoding formula: + * 0 1 2 3 4 5 6 7 + * +-+-+-+-+-+-+-+-+ + * |1| exp | mant | + * +-+-+-+-+-+-+-+-+ + * QQI =3D (mant | 0x10) << (exp + 3) + */ +static inline unsigned long mldv2_qqi(const struct mld2_query *mlh2) +{ + /* RFC3810, relevant sections: + * - 5.1.9. QQIC (Querier's Query Interval Code) + * - 9.2. Query Interval + * - 9.12. Older Version Querier Present Timeout + * (the [Query Interval] in the last Query received) + */ + unsigned long qqic =3D mlh2->mld2q_qqic; + + if (qqic < MLD_QQIC_MIN_THRESHOLD) { + return qqic; + } else { + unsigned long mc_man, mc_exp; + + mc_exp =3D MLDV2_QQIC_EXP(qqic); + mc_man =3D MLDV2_QQIC_MAN(qqic); + + return ((mc_man | 0x10) << (mc_exp + 3)); + } } =20 #endif diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c index 9fec76e887bc..1438c023db62 100644 --- a/net/bridge/br_multicast.c +++ b/net/bridge/br_multicast.c @@ -3606,7 +3606,7 @@ static int br_ip6_multicast_query(struct net_bridge_m= cast *brmctx, mld2q->mld2q_suppress) goto out; =20 - max_delay =3D max(msecs_to_jiffies(mldv2_mrc(mld2q)), 1UL); + max_delay =3D max(msecs_to_jiffies(mldv2_mrd(mld2q)), 1UL); } =20 is_general_query =3D group && ipv6_addr_any(group); diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index 3330adcf26db..6ddc18ac59b9 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c @@ -1315,20 +1315,7 @@ static void mld_update_qi(struct inet6_dev *idev, * - 9.12. Older Version Querier Present Timeout * (the [Query Interval] in the last Query received) */ - unsigned long mc_qqi; - - if (mlh2->mld2q_qqic < 128) { - mc_qqi =3D mlh2->mld2q_qqic; - } else { - unsigned long mc_man, mc_exp; - - mc_exp =3D MLDV2_QQIC_EXP(mlh2->mld2q_qqic); - mc_man =3D MLDV2_QQIC_MAN(mlh2->mld2q_qqic); - - mc_qqi =3D (mc_man | 0x10) << (mc_exp + 3); - } - - idev->mc_qi =3D mc_qqi * HZ; + idev->mc_qi =3D mldv2_qqi(mlh2) * HZ; } =20 static void mld_update_qri(struct inet6_dev *idev, @@ -1338,7 +1325,7 @@ static void mld_update_qri(struct inet6_dev *idev, * - 5.1.3. Maximum Response Code * - 9.3. Query Response Interval */ - idev->mc_qri =3D msecs_to_jiffies(mldv2_mrc(mlh2)); + idev->mc_qri =3D msecs_to_jiffies(mldv2_mrd(mlh2)); } =20 static int mld_process_v1(struct inet6_dev *idev, struct mld_msg *mld, @@ -1390,7 +1377,7 @@ static int mld_process_v1(struct inet6_dev *idev, str= uct mld_msg *mld, static void mld_process_v2(struct inet6_dev *idev, struct mld2_query *mld, unsigned long *max_delay) { - *max_delay =3D max(msecs_to_jiffies(mldv2_mrc(mld)), 1UL); + *max_delay =3D max(msecs_to_jiffies(mldv2_mrd(mld)), 1UL); =20 mld_update_qrv(idev, mld); mld_update_qi(idev, mld); --=20 2.43.0 From nobody Fri Apr 3 11:10:25 2026 Received: from mail-pj1-f48.google.com (mail-pj1-f48.google.com [209.85.216.48]) (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 545182E7F39 for ; Mon, 30 Mar 2026 19:16:49 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.216.48 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774898210; cv=none; b=ZhRYi3mHEQun7+xroVNzsV0+SLl4sSmwt7ClkEAVKyCfGNdndHWadDi8cranwe+M6S+moJGSqbrat8H2g8LOa6N/NDP3g5eaihMvS/zxGcQoz01zvdPAPWouA8rCdqQwxN5hhSIxIkaXnoSk1LHWMKD5PsRBOgEI9IyjyIojuUE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774898210; c=relaxed/simple; bh=kZVwnXWURA3X/G1DyhA5FWIIj06eTQFconwOEGeohEg=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=MZQsTSTJXAXRvkh/ymO3jpubPpvdZ1O3nFO8Ur8Qk1s3qf6bV3wy40NLVA9Jdjeoxm++2MCZ0/FOQMcTO7Bm0fWoPErMQfAXZjmC3VtHDXALOW2qPHSPlqb3F/jZZjngHYDFC330WqUqkfsl1mLFcGrHPOIEnzBVmZd1WsArgUU= 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=Apqs8Kk+; arc=none smtp.client-ip=209.85.216.48 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="Apqs8Kk+" Received: by mail-pj1-f48.google.com with SMTP id 98e67ed59e1d1-35d94f4ee36so1342792a91.3 for ; Mon, 30 Mar 2026 12:16:49 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1774898209; x=1775503009; 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; bh=L6LmQvHoJMIuzVDw1ku5rpZrRgMMk/C43OeFB++Ma9c=; b=Apqs8Kk+ZNtORdgXpYS1lfaNjMHX6xkpPQMEA+CzFfqrUvzwMVIwmgmNEGZZO5ZPDH oix7BXbUZ1nYWMPuyvgZM+AkE0RQMDxeuXnjkE0M6tBV9v9ac7dTAefdxlzGmbPZsLSd C9/G804HBYTSV1xzTxbrmHA24DhywzZtR+QjLq7EcXfVmnDoX6NUL+62xILM9fODmoRS e0RTvB33gLAGKPDytyoXmLr+U7dMmXzbEozmEsnXF+BBamVLyv5DqZvvT6gdvXX+1013 vyCpblDJo2ob3vKUSBj3drqOZ9+X7mpcCrbt6/sU0b2wer+OT5XZdasiDm22ggZAW6ny dj1Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1774898209; x=1775503009; 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; bh=L6LmQvHoJMIuzVDw1ku5rpZrRgMMk/C43OeFB++Ma9c=; b=AVY74K+EHM/qmQoSlPRLEvq+kLaYFbJQCW2k8F6BWIXQaP20Ht08weG959b2nztu/H 7hF++gibTPSM80E4ZZzD5JDtdVYFZ+Morqm/D1TFE1mDSN1JYMFwYM0Vuy4matuH9C4o pLe/jDWSa+pFuX4nwJbcSufiQ2sKJ46AsFagKVs/C+NdN2Mdd+C/ykY/faYB2fp+wqh0 7QSE7YeBrv7eHJ+S5biKSxH7eGSJskMyfkuA04fC1h+c26v8K4PmXQslBOH/u2iUdyP0 hmBpvqV+da6UNWz2oj2wJvauX3jcRJar5aTmPjRvOGOr4JkqcoM2pzSrNfFt9lQ5JbFm BL7Q== X-Forwarded-Encrypted: i=1; AJvYcCVtENzfrVRB9R3DSsqIrsIw1KVaQTfQuhNRG3zEiLUr0zoVYcjybkyARDk9d0eu86uFjuXuPD+BApSrs8k=@vger.kernel.org X-Gm-Message-State: AOJu0YzaHYr0HZZUbr02MdbbZfOefB7TzB6MeS0IJ9pr/m9otUqL49pr Y324BQl28xNFeyXjXu+nQshlbuS4Yakz/y8Q6ItsFQC+iLV6A7NRTJoN X-Gm-Gg: ATEYQzwLVidKoirvvlfHdW5taP+XJVXB9lkhHsxULM/IrtYBWZ2V+cG7hs7HLsSiJfS Cnkp0rVcTW/PvNayyUmmYj+say5pkc0SlzL6+Eh3ndRM+TqjnwtNST6r5/SU//GUO623aIg6baH 4B2YjTcK0nlYP37DLkkVYm/PUb3WNBFsfoGA42Opec+VMi9uL1WkC+5FLwJpm99a3uR5vXfKhy7 lnkhcaWlwqIQTAKPGjQlWXx6RMspTaMzmNB+3TYmZjMD2K/3pqHRKPbLNL/yZ/+romyM3HHEYKo fgGX+CVhw7kWeUrk5eIUp9k5ivVW6Bjw/KfiAIQFIwGGGrxKy2rW6kBi2MX+/DeqDYqqu95ySqF v68JnYutV72C+iQdr0tI2WqUvtZf2tFDgw4Rq/Q/8wN4yZmwQjhR/9R5LXA06bU5kyMU/sX3bN3 2M/0+z2iVynEsmP0pgCT2pMOmPwc5/LdI/ByHiJpCW X-Received: by 2002:a17:90b:4b0e:b0:359:8e5e:43de with SMTP id 98e67ed59e1d1-35c300c19d2mr12577177a91.22.1774898208327; Mon, 30 Mar 2026 12:16:48 -0700 (PDT) Received: from DESKTOP-82PPU4A.localdomain ([202.8.116.192]) by smtp.gmail.com with ESMTPSA id 98e67ed59e1d1-35d950d9b12sm9627178a91.17.2026.03.30.12.16.41 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 30 Mar 2026 12:16:47 -0700 (PDT) From: Ujjal Roy To: "David S . Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , Nikolay Aleksandrov , Ido Schimmel , David Ahern , Shuah Khan , Andy Roulin , Yong Wang , Petr Machata Cc: Ujjal Roy , bridge@lists.linux.dev, netdev@vger.kernel.org, linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org Subject: [PATCH net-next v2 3/5] ipv4: igmp: encode multicast exponential fields Date: Mon, 30 Mar 2026 19:16:09 +0000 Message-ID: <20260330191611.16929-4-royujjal@gmail.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260330191611.16929-1-royujjal@gmail.com> References: <20260330191611.16929-1-royujjal@gmail.com> 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" In IGMP, QQIC and MRC fields are not currently encoded when generating query packets. Since the receiver of the query interprets these fields using the IGMPv3 floating- point decoding logic, any raw interval value that exceeds the linear threshold is currently parsed incorrectly as an exponential value, leading to an incorrect interval calculation. Encode and assign the corresponding protocol fields during query generation. Introduce the logic to dynamically calculate the exponent and mantissa using bit-scan (fls). This ensures QQIC and MRC fields (8-bit) are properly encoded when transmitting query packets with intervals that exceed their respective linear threshold value of 128 (for QQI/MRT). RFC 3376: if QQIC/MRC >=3D 128, the QQIC/MRC field represents a floating-point value as follows: 0 1 2 3 4 5 6 7 +-+-+-+-+-+-+-+-+ |1| exp | mant | +-+-+-+-+-+-+-+-+ Signed-off-by: Ujjal Roy --- include/linux/igmp.h | 80 +++++++++++++++++++++++++++++++++++++++ net/bridge/br_multicast.c | 14 +++---- 2 files changed, 86 insertions(+), 8 deletions(-) diff --git a/include/linux/igmp.h b/include/linux/igmp.h index 3c12c0a63492..3a4e9cec3959 100644 --- a/include/linux/igmp.h +++ b/include/linux/igmp.h @@ -110,6 +110,86 @@ struct ip_mc_list { =20 /* IGMPV3 floating-point exponential field threshold */ #define IGMPV3_EXP_MIN_THRESHOLD 128 +/* Max representable (mant =3D 0xF, exp =3D 7) -> 31744 */ +#define IGMPV3_EXP_MAX_THRESHOLD 31744 + +/* V3 exponential field encoding */ + +/* + * IGMPv3 QQIC/MRC 8-bit exponential field encode. + * + * RFC3376 defines only the decoding formula: + * QQI/MRT =3D (mant | 0x10) << (exp + 3) + * + * but does NOT define the encoding procedure. To derive exponent: + * + * For any value of mantissa and exponent, the decoding formula + * indicates that the "hidden bit" (0x10) is shifted 4 bits left + * to sit above the 4-bit mantissa. The RFC again shifts this + * entire block left by (exp + 3) to reconstruct the value. + * So, 'hidden bit' is the MSB which is shifted by (4 + exp + 3). + * + * Total left shift of the 'hidden bit' =3D 4 + (exp + 3) =3D exp + 7. + * This is the MSB at the 0-based bit position: (exp + 7). + * Since fls() is 1-based, fls(value) - 1 =3D exp + 7. + * + * Therefore: + * exp =3D fls(value) - 8 + * mant =3D (value >> (exp + 3)) & 0x0F + * + * Final encoding formula: + * 0x80 | (exp << 4) | mant + * + * Example (value =3D 3200): + * 0 1 + * 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |0 0 0 0 1 1 0 0 1 0 0 0 0 0 0 0| (value =3D 3200) + * | ^-^-mant^ ^..(exp+3)..^| exp =3D 4, mant =3D 9 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * Encoded: + * 0x80 | (4 << 4) | 9 =3D 0xC9 + */ +static inline u8 igmpv3_exp_field_encode(unsigned long value) +{ + u8 mc_exp, mc_man; + + /* RFC3376: QQIC/MRC < 128 is literal */ + if (value < IGMPV3_EXP_MIN_THRESHOLD) + return (u8)value; + + /* Saturate at max representable (mant =3D 0xF, exp =3D 7) -> 31744 */ + if (value >=3D IGMPV3_EXP_MAX_THRESHOLD) + return 0xFF; + + mc_exp =3D (u8)(fls(value) - 8); + mc_man =3D (u8)((value >> (mc_exp + 3)) & 0x0F); + + return 0x80 | (mc_exp << 4) | mc_man; +} + +/* Calculate Maximum Response Code from Max Resp Time */ +static inline u8 igmpv3_mrc(unsigned long mrt) +{ + /* RFC3376, relevant sections: + * - 4.1.1. Maximum Response Code + * - 8.3. Query Response Interval + */ + return igmpv3_exp_field_encode(mrt); +} + +/* Calculate Querier's Query Interval Code from Query Interval */ +static inline u8 igmpv3_qqic(unsigned long qi) +{ + /* RFC3376, relevant sections: + * - 4.1.7. QQIC (Querier's Query Interval Code) + * - 8.2. Query Interval + * - 8.12. Older Version Querier Present Timeout + * (the [Query Interval] in the last Query received) + */ + return igmpv3_exp_field_encode(qi); +} =20 /* V3 exponential field decoding */ =20 diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c index 1438c023db62..27010744d7ae 100644 --- a/net/bridge/br_multicast.c +++ b/net/bridge/br_multicast.c @@ -934,12 +934,12 @@ static struct sk_buff *br_ip4_multicast_alloc_query(s= truct net_bridge_mcast *brm size_t pkt_size, igmp_hdr_size; unsigned long now =3D jiffies; struct igmpv3_query *ihv3; + unsigned long lmqt, mrt; void *csum_start =3D NULL; __sum16 *csum =3D NULL; struct sk_buff *skb; struct igmphdr *ih; struct ethhdr *eth; - unsigned long lmqt; struct iphdr *iph; u16 lmqt_srcs =3D 0; =20 @@ -1004,15 +1004,15 @@ static struct sk_buff *br_ip4_multicast_alloc_query= (struct net_bridge_mcast *brm skb_put(skb, 24); =20 skb_set_transport_header(skb, skb->len); + mrt =3D group ? brmctx->multicast_last_member_interval : + brmctx->multicast_query_response_interval; *igmp_type =3D IGMP_HOST_MEMBERSHIP_QUERY; =20 switch (brmctx->multicast_igmp_version) { case 2: ih =3D igmp_hdr(skb); ih->type =3D IGMP_HOST_MEMBERSHIP_QUERY; - ih->code =3D (group ? brmctx->multicast_last_member_interval : - brmctx->multicast_query_response_interval) / - (HZ / IGMP_TIMER_SCALE); + ih->code =3D mrt / (HZ / IGMP_TIMER_SCALE); ih->group =3D group; ih->csum =3D 0; csum =3D &ih->csum; @@ -1021,11 +1021,9 @@ static struct sk_buff *br_ip4_multicast_alloc_query(= struct net_bridge_mcast *brm case 3: ihv3 =3D igmpv3_query_hdr(skb); ihv3->type =3D IGMP_HOST_MEMBERSHIP_QUERY; - ihv3->code =3D (group ? brmctx->multicast_last_member_interval : - brmctx->multicast_query_response_interval) / - (HZ / IGMP_TIMER_SCALE); + ihv3->code =3D igmpv3_mrc(mrt / (HZ / IGMP_TIMER_SCALE)); ihv3->group =3D group; - ihv3->qqic =3D brmctx->multicast_query_interval / HZ; + ihv3->qqic =3D igmpv3_qqic(brmctx->multicast_query_interval / HZ); ihv3->nsrcs =3D htons(lmqt_srcs); ihv3->resv =3D 0; ihv3->suppress =3D sflag; --=20 2.43.0 From nobody Fri Apr 3 11:10:25 2026 Received: from mail-pj1-f47.google.com (mail-pj1-f47.google.com [209.85.216.47]) (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 2105B26E165 for ; Mon, 30 Mar 2026 19:16:56 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.216.47 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774898217; cv=none; b=fkULNS1pLCWT2K5+C7WON3htFylcrbJ0dhPab7R31pneCcQVY2q6bv2bnpRGCn+z73ecf6xuQJrVg44IR45C2sPzJreo5uEzRkvrdLSUfHXtUAtFN6xyvddNatX9c9Hkvc3z9M9tivlurojTDvkii2Gjxls+1VX06kANI/5Eg8U= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774898217; c=relaxed/simple; bh=/s+EgbT4cwqyAVP8otaVBOlL/dCCRmkYjYM+V8pat60=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=C3lvVTQFChXgD7QiTDKk/N6u9vzvvhrGKOw6uIFiQH0U5QbCVZ1h0kn7R2NwzRGv3Sa0u54Hs+2zL4Ys0sM5A31SFhXWFWIU4VSUHHaJw/28l1nDsG7chfobppFK+KMVNtxkUezlW8Val+ZFRxcuQOJZvuHonC4eKZwUu3m72Do= 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=W4z5YJbU; arc=none smtp.client-ip=209.85.216.47 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="W4z5YJbU" Received: by mail-pj1-f47.google.com with SMTP id 98e67ed59e1d1-35691a231a7so2947000a91.3 for ; Mon, 30 Mar 2026 12:16:56 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1774898215; x=1775503015; 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; bh=5WISAf0QjUXrCjlDt5u3fdpEKEmBPI+ZNLLd/DIJAm8=; b=W4z5YJbUeGIvrIt7mUCfKAMbBSjHW8Jzu9d89cyue6et/DAqLmNIB1nP3MMctHUpwc 3ivEr19Oq5qbgFomy+6YipxT9PE4GV2A3y3DXlONhpNptd/u+A7LnxMntTP0u8N2F2FD kOmAAdeO2HzQwhaXC08VcqVOkLHtkWxvYstUOtVGLFr/eMTKtT91qjw1uoASLQHf/7CA aO4chdyV+Ar+wXdoezpgj1axZBNrIRnSjdbn9KM8jpXF/0fKlOrm2Ixstz7EyeXSxKkX 1tSlLITWRKt6bHnlYSEZOLJ8q6zSGrNTv3EZ99ju1yrzXxhswwZqFHgN+SjjMtpWK957 Dblw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1774898215; x=1775503015; 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; bh=5WISAf0QjUXrCjlDt5u3fdpEKEmBPI+ZNLLd/DIJAm8=; b=bgQ/aK0LJuZlXEK0qw5vGSECtZvb2J7ULQlYogHuy1D7YmTcOkEhzoyMLUraNlQdNA R+j8N0D0/cou6xeq9I4aiaRGZ+aVje434moTTxjPiugpdkHXI0DBR0onyPOn0DC56N/p +5BPIVC+RWl5Egu46yNCr3yNHIrPbXHw935oA+9vN5KR2srEZHrpZ731LigWUlqQRAlm Sgntv6eDmvz06gSiYoDAdAkhpS7LEfGvgqq92ZQ/HiKFLM2dExki2ad6QebRrxV1MINW nwzoThMiNXBqgGHvey1G1WA9tSahK/vz/TFufa8NPYeSKomjX03nT1TSzd6njNDoLt77 r8qA== X-Forwarded-Encrypted: i=1; AJvYcCUrYaKT2KOAvrgj/Es3ikdCqunJQH1C35GehLb2tQoHYs4skMeKj+UdN6vj13ziMq9cj5/mkfJ58vqIwkE=@vger.kernel.org X-Gm-Message-State: AOJu0YxzV3KWRaGzrOPhPYSKVMOGA/xRlBghv10ZZr7d35iXlM+Wtv6w GBkNSfVtsNV1sd2IfoiG+BfP2Ui9q2psTc6ifEr2sMcujx4REndHRXlR X-Gm-Gg: ATEYQzwW7qHCuSLYUp1OEl3KrAJbMkkec9gTY8ZipZPvJHNVkcmbFA9LePWu0+wChL2 JmReEFJQQtnO49dcwVolFTmTU32M+BKM+vHs/S4jk4LDQS2v/SqT5hS498QwF1Ag6xq5tQbHBWo Ma6Cz5Y62NcBuA7/wJgE17GGq6AIICuEWJIXsH46vBEOQq0YY9t/xfzD0m8XN2xkMdtqKrzo6gS 3w9wrTQBE6YIzDR04ckMztXQENw1ncOduj1U+fYW/6li8TQpUYKGOCkmcQPDosvQZrld9U8utkm ZlNC7ry9zVrBTxvxHJ0tuBQOCy/0Cg1PRKRK854WiNzlLukb8EXNj8MzW71MngIZeSBWFwnjk0t YWxt2qVzZnJfQ+GNe7H3LGVjCLn2aOEnkoqmyD/nCmDYyX4shCUExHNl4zpkIbIpdCnT/BEfKUP EiQUUqirOvlThovDTXeH8bXUdXThz15OeMZiSIIKyb X-Received: by 2002:a17:90a:e7c1:b0:35d:a276:a87d with SMTP id 98e67ed59e1d1-35da276afa0mr6030327a91.27.1774898215457; Mon, 30 Mar 2026 12:16:55 -0700 (PDT) Received: from DESKTOP-82PPU4A.localdomain ([202.8.116.192]) by smtp.gmail.com with ESMTPSA id 98e67ed59e1d1-35d950d9b12sm9627178a91.17.2026.03.30.12.16.48 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 30 Mar 2026 12:16:54 -0700 (PDT) From: Ujjal Roy To: "David S . Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , Nikolay Aleksandrov , Ido Schimmel , David Ahern , Shuah Khan , Andy Roulin , Yong Wang , Petr Machata Cc: Ujjal Roy , bridge@lists.linux.dev, netdev@vger.kernel.org, linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org Subject: [PATCH net-next v2 4/5] ipv6: mld: encode multicast exponential fields Date: Mon, 30 Mar 2026 19:16:10 +0000 Message-ID: <20260330191611.16929-5-royujjal@gmail.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260330191611.16929-1-royujjal@gmail.com> References: <20260330191611.16929-1-royujjal@gmail.com> 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" In MLD, QQIC and MRC fields are not currently encoded when generating query packets. Since the receiver of the query interprets these fields using the MLDv2 floating-point decoding logic, any raw interval value that exceeds the linear threshold is currently parsed incorrectly as an exponential value, leading to an incorrect interval calculation. Encode and assign the corresponding protocol fields during query generation. Introduce the logic to dynamically calculate the exponent and mantissa using bit-scan (fls). This ensures QQIC (8-bit) and MRC (16-bit) fields are properly encoded when transmitting query packets with intervals that exceed their respective linear thresholds (128 for QQI; 32768 for MRD). RFC3810: If QQIC >=3D 128, the QQIC field represents a floating-point value as follows: 0 1 2 3 4 5 6 7 +-+-+-+-+-+-+-+-+ |1| exp | mant | +-+-+-+-+-+-+-+-+ RFC3810: If Maximum Response Code >=3D 32768, the Maximum Response Code field represents a floating-point value as follows: 0 1 2 3 4 5 6 7 8 9 A B C D E F +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |1| exp | mant | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ Signed-off-by: Ujjal Roy --- include/net/mld.h | 117 ++++++++++++++++++++++++++++++++++++++ net/bridge/br_multicast.c | 4 +- 2 files changed, 119 insertions(+), 2 deletions(-) diff --git a/include/net/mld.h b/include/net/mld.h index 5e093f9c75d9..1ee7d3f68a33 100644 --- a/include/net/mld.h +++ b/include/net/mld.h @@ -90,12 +90,129 @@ struct mld2_query { #define MLDV2_QQIC_MAN(value) ((value) & 0x0f) =20 #define MLD_QQIC_MIN_THRESHOLD 128 +/* Max representable (mant =3D 0xF, exp =3D 7) -> 31744 */ +#define MLD_QQIC_MAX_THRESHOLD 31744 #define MLD_MRC_MIN_THRESHOLD 32768UL +/* Max representable (mant =3D 0xFFF, exp =3D 7) -> 8387584 */ +#define MLD_MRC_MAX_THRESHOLD 8387584 #define MLDV1_MRD_MAX_COMPAT (MLD_MRC_MIN_THRESHOLD - 1) =20 #define MLD_MAX_QUEUE 8 #define MLD_MAX_SKBS 32 =20 +/* V2 exponential field encoding */ + +/* + * Calculate Maximum Response Code from Maximum Response Delay + * + * MLDv2 Maximum Response Code 16-bit encoding (RFC3810). + * + * RFC3810 defines only the decoding formula: + * Maximum Response Delay =3D (mant | 0x1000) << (exp + 3) + * + * but does NOT define the encoding procedure. To derive exponent: + * + * For the 16-bit MRC, the "hidden bit" (0x1000) is left shifted by 12 + * to sit above the 12-bit mantissa. The RFC then shifts this entire + * block left by (exp + 3) to reconstruct the value. + * So, 'hidden bit' is the MSB which is shifted by (12 + exp + 3). + * + * - Total left shift of the hidden bit =3D 12 + (exp + 3) =3D exp + 15. + * - This is the MSB at the 0-based bit position: (exp + 15). + * - Since fls() is 1-based, fls(value) - 1 =3D exp + 15. + * + * Therefore: + * exp =3D fls(value) - 16 + * mant =3D (value >> (exp + 3)) & 0x0FFF + * + * Final encoding formula: + * 0x8000 | (exp << 12) | mant + * + * Example (value =3D 1311744): + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0| 13117= 44 + * | ^-^--------mant---------^ ^...(exp+3)...^| exp= =3D5 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * Encoded: + * 0x8000 | (5 << 12) | 0x404 =3D 0xD404 + */ +static inline u16 mldv2_mrc(unsigned long mrd) +{ + u16 mc_man, mc_exp; + + /* RFC3810: MRC < 32768 is literal */ + if (mrd < MLD_MRC_MIN_THRESHOLD) + return (u16)mrd; + + /* Saturate at max representable (mant =3D 0xFFF, exp =3D 7) -> 8387584 */ + if (mrd >=3D MLD_MRC_MAX_THRESHOLD) + return 0xFFFF; + + mc_exp =3D (u16)(fls(mrd) - 16); + mc_man =3D (u16)((mrd >> (mc_exp + 3)) & 0x0FFF); + + return (0x8000 | (mc_exp << 12) | mc_man); +} + +/* + * Calculate Querier's Query Interval Code from Query Interval + * + * MLDv2 QQIC 8-bit floating-point encoding (RFC3810). + * + * RFC3810 defines only the decoding formula: + * QQI =3D (mant | 0x10) << (exp + 3) + * + * but does NOT define the encoding procedure. To derive exponent: + * + * For any value of mantissa and exponent, the decoding formula + * indicates that the "hidden bit" (0x10) is shifted 4 bits left + * to sit above the 4-bit mantissa. The RFC again shifts this + * entire block left by (exp + 3) to reconstruct the value. + * So, 'hidden bit' is the MSB which is shifted by (4 + exp + 3). + * + * Total left shift of the 'hidden bit' =3D 4 + (exp + 3) =3D exp + 7. + * This is the MSB at the 0-based bit position: (exp + 7). + * Since fls() is 1-based, fls(value) - 1 =3D exp + 7. + * + * Therefore: + * exp =3D fls(value) - 8 + * mant =3D (value >> (exp + 3)) & 0x0F + * + * Final encoding formula: + * 0x80 | (exp << 4) | mant + * + * Example (value =3D 3200): + * 0 1 + * 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |0 0 0 0 1 1 0 0 1 0 0 0 0 0 0 0| (value =3D 3200) + * | ^-^-mant^ ^..(exp+3)..^| exp =3D 4, mant =3D 9 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * Encoded: + * 0x80 | (4 << 4) | 9 =3D 0xC9 + */ +static inline u8 mldv2_qqic(unsigned long value) +{ + u8 mc_man, mc_exp; + + /* RFC3810: QQIC < 128 is literal */ + if (value < MLD_QQIC_MIN_THRESHOLD) + return (u8)value; + + /* Saturate at max representable (mant =3D 0xF, exp =3D 7) -> 31744 */ + if (value >=3D MLD_QQIC_MAX_THRESHOLD) + return 0xFF; + + mc_exp =3D (u8)(fls(value) - 8); + mc_man =3D (u8)((value >> (mc_exp + 3)) & 0x0F); + + return (0x80 | (mc_exp << 4) | mc_man); +} + /* V2 exponential field decoding */ =20 /* Calculate Maximum Response Delay from Maximum Response Code diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c index 27010744d7ae..c2d144f6a86e 100644 --- a/net/bridge/br_multicast.c +++ b/net/bridge/br_multicast.c @@ -1181,7 +1181,7 @@ static struct sk_buff *br_ip6_multicast_alloc_query(s= truct net_bridge_mcast *brm break; case 2: mld2q =3D (struct mld2_query *)icmp6_hdr(skb); - mld2q->mld2q_mrc =3D htons((u16)jiffies_to_msecs(interval)); + mld2q->mld2q_mrc =3D htons((u16)jiffies_to_msecs(mldv2_mrc(interval))); mld2q->mld2q_type =3D ICMPV6_MGM_QUERY; mld2q->mld2q_code =3D 0; mld2q->mld2q_cksum =3D 0; @@ -1190,7 +1190,7 @@ static struct sk_buff *br_ip6_multicast_alloc_query(s= truct net_bridge_mcast *brm mld2q->mld2q_suppress =3D sflag; mld2q->mld2q_qrv =3D 2; mld2q->mld2q_nsrcs =3D htons(llqt_srcs); - mld2q->mld2q_qqic =3D brmctx->multicast_query_interval / HZ; + mld2q->mld2q_qqic =3D mldv2_qqic(brmctx->multicast_query_interval / HZ); mld2q->mld2q_mca =3D *group; csum =3D &mld2q->mld2q_cksum; csum_start =3D (void *)mld2q; --=20 2.43.0 From nobody Fri Apr 3 11:10:25 2026 Received: from mail-pj1-f54.google.com (mail-pj1-f54.google.com [209.85.216.54]) (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 26FF538A710 for ; Mon, 30 Mar 2026 19:17:03 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.216.54 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774898225; cv=none; b=QuLugxg29jw1zUPTFhVWZL9HF2F0O/Q1mgjwumMl3QXSSCj/uy+JpO+qKAFHwBBwcqVIoMsAi6mEXhjwVwcrIxYNm9JNovUkD08la7zgjUPOP9iM97mMLAGBDPAW6RF902HHz6AgG1cxxj1j754D25mpUbbvtq6g6PfqSB2NozA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774898225; c=relaxed/simple; bh=cT/13qstn8/nOhBjQXRq0PqqXbdhTgppzUWbgSGQO70=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=tcC+eOhkYs14K1JczvNzlQCVuDsLX+sQGRFFcCzN1sI3tF5m9b/XyAcQ8U1QCJcSyK94iaUUMY0aXNSxOC8gYuUvcleNIk1RsJMWBoe2H+mAQC9BN3OdHq+gMNSCQZa0UQ8juXArIdYKVEKAH8fODVWuQdq3l8Q8rvfX2+83VcM= 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=d8aaPRcY; arc=none smtp.client-ip=209.85.216.54 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="d8aaPRcY" Received: by mail-pj1-f54.google.com with SMTP id 98e67ed59e1d1-35d9f68d011so1219156a91.2 for ; Mon, 30 Mar 2026 12:17:03 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1774898222; x=1775503022; 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; bh=5f2zrKZrRaGjASZcWc6dPmrf+99AFfJekwpd+WSzFDo=; b=d8aaPRcYZSX7vySqHaQcFAOVSDfstKn2CX6UHyPseriRxIDyX9/Y93+rJWIWVawSxV +sQpksv8RIa/yE5NuYRlq5XRqQb+QTAfTHiKu7x4Cc8R0Nk64lxPTyaJCbMFKOC/C1cr NLKWHEBc/SqahVRsExjxPCTpnq2Ek3LSx4KSzohpB/AIzZmUFxgfLbtjnjf1+7p7jD6i Y/TbsfLvj90l/dKQzUubJEsLXh2E8XfBalxK/3LiuBwHDs8S+3S2PvEkalI/WPDvTRmd PzmEbOrDl0HnVLOx/5vPzcHyeEVk/GxxGOABa/Xw6byIWOVHrz3FB8FFvEFtUJRNRdx9 rg/w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1774898222; x=1775503022; 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; bh=5f2zrKZrRaGjASZcWc6dPmrf+99AFfJekwpd+WSzFDo=; b=nnywv3RCEklYuDd7xIZY9Uhh89NFIHXO14+/mimrKiw7jY6vb5TcCaXqTqCwTJt67o GGBQtmvwLOh/7vS7lMmW5Ujz0sWpGnCxF5dOcTwt+FmKTEAPLNfsSPkBxE1yA6OJcwSB LA/hy/ik5J1x+g7WjJhmClW0PTVmiR6GZQa49TNYihnos+R2Ngcc4zuJfy7EMMeAPTVZ YnxJlw1YW8srd1rSOUPmJLaCTV9T8Ys1A/nVH/NepWFwX5YmnYWWIJg042hCVvSifp6k vmEyEXMhaQlBb8fWgSecLMlqJMN6RW1o32ybzKFd/+SmfHtfjMYFh2Z6IaEEm2eLlyr2 zIWA== X-Forwarded-Encrypted: i=1; AJvYcCWngZKfvvSO55p2YrQ2EulyTVMmPCodid5cAf0+uW7w5Yk/igA+4ceI7gfX1GrSk0MgLAEkk9nx3/ZegAs=@vger.kernel.org X-Gm-Message-State: AOJu0YyV02bowEc0a9jRIdraw0h2Cbu5r3siEWcEQ565fpzT/SEWQER5 i06glhJyCxycGeDZ9LKxS3/6kwzssLLvvrgOmhFXiXDm/W2G+gzEEqDV X-Gm-Gg: ATEYQzy8DKBQweZ1yNRr4VM/uuiJyCciaQzmJdHXlcw1GME8B5IxVQnPRnTYXp+K7cR JxjlipT1LYeOY95iAfzUo1/rTm2+s80SkDaiohls+LO1Rt2T/SiqA9dxGdauv8jCMn2RnjVxMq0 0/VyAykHbG5Ocj0j73Rp+GaW0H77ZgkLIX5wstwzSfKhYmFt6bd9Z5MkEedWlRrJdIhBRPz+Ro0 VoOwMEcjA+DFGZXtStO5yyxmQ59J8I6CCN1i5v5RduL1oI4KlsF7qs7X4+ce+SdXa+FhLkQTg3/ r+TFh7Txe0BHfZ5t6xxVrjBMVjgfJDrCRLvGCDDqF3zZG8NH9YAC+ECJBVww6ZCZYL4HsWF00mh UsoVnmAxo5SntMmxeA9Ojlx45w/jHDAgVygBgKcSuyqd+QK8lolxsCbK3A9rwy55FBBiQ4h1uyk QUozAKp+S8VWCNSS0N+ISbsZMcavb/NQfM+IpQT09W X-Received: by 2002:a17:90b:3cce:b0:336:b60f:3936 with SMTP id 98e67ed59e1d1-35c3000c6f0mr12496361a91.12.1774898222332; Mon, 30 Mar 2026 12:17:02 -0700 (PDT) Received: from DESKTOP-82PPU4A.localdomain ([202.8.116.192]) by smtp.gmail.com with ESMTPSA id 98e67ed59e1d1-35d950d9b12sm9627178a91.17.2026.03.30.12.16.55 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 30 Mar 2026 12:17:01 -0700 (PDT) From: Ujjal Roy To: "David S . Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , Nikolay Aleksandrov , Ido Schimmel , David Ahern , Shuah Khan , Andy Roulin , Yong Wang , Petr Machata Cc: Ujjal Roy , bridge@lists.linux.dev, netdev@vger.kernel.org, linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org Subject: [PATCH net-next v2 5/5] selftests: net: bridge: add tests for igmpv3 MRC and QQIC validation Date: Mon, 30 Mar 2026 19:16:11 +0000 Message-ID: <20260330191611.16929-6-royujjal@gmail.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260330191611.16929-1-royujjal@gmail.com> References: <20260330191611.16929-1-royujjal@gmail.com> 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" Add bridge selftests that configure IGMPv3 parameters and validate the resulting Query packet fields for Max Resp Code (MRC) and Querier Query Interval Code (QQIC). This also adds helper binary to encode floating-point exponential fields. Future extensions may cover corresponding IPv6 cases. Signed-off-by: Ujjal Roy --- .../selftests/net/forwarding/.gitignore | 2 + .../testing/selftests/net/forwarding/Makefile | 10 ++ .../selftests/net/forwarding/bridge_igmp.sh | 109 ++++++++++++++++++ .../selftests/net/forwarding/mc_decode.c | 38 ++++++ .../selftests/net/forwarding/mc_encode.c | 40 +++++++ 5 files changed, 199 insertions(+) create mode 100644 tools/testing/selftests/net/forwarding/mc_decode.c create mode 100644 tools/testing/selftests/net/forwarding/mc_encode.c diff --git a/tools/testing/selftests/net/forwarding/.gitignore b/tools/test= ing/selftests/net/forwarding/.gitignore index 418ff96c52ef..aa0c7f1afb4b 100644 --- a/tools/testing/selftests/net/forwarding/.gitignore +++ b/tools/testing/selftests/net/forwarding/.gitignore @@ -1,3 +1,5 @@ # SPDX-License-Identifier: GPL-2.0-only forwarding.config ipmr +mc_encode +mc_decode diff --git a/tools/testing/selftests/net/forwarding/Makefile b/tools/testin= g/selftests/net/forwarding/Makefile index bbaf4d937dd8..a26da846632d 100644 --- a/tools/testing/selftests/net/forwarding/Makefile +++ b/tools/testing/selftests/net/forwarding/Makefile @@ -1,5 +1,15 @@ # SPDX-License-Identifier: GPL-2.0+ OR MIT =20 +top_srcdir =3D ../../../../.. + +CFLAGS +=3D -Wall -Wl,--no-as-needed -O2 -g -I$(top_srcdir)/usr/include $(= KHDR_INCLUDES) +CFLAGS +=3D -I$(top_srcdir)/tools/include + +TEST_GEN_FILES :=3D \ + mc_encode \ + mc_decode \ +# end of TEST_GEN_FILES + TEST_PROGS :=3D \ bridge_activity_notify.sh \ bridge_fdb_learning_limit.sh \ diff --git a/tools/testing/selftests/net/forwarding/bridge_igmp.sh b/tools/= testing/selftests/net/forwarding/bridge_igmp.sh index d4e7dd659354..9841c4e4eca0 100755 --- a/tools/testing/selftests/net/forwarding/bridge_igmp.sh +++ b/tools/testing/selftests/net/forwarding/bridge_igmp.sh @@ -2,6 +2,8 @@ # SPDX-License-Identifier: GPL-2.0 =20 ALL_TESTS=3D" + v3query_mrc_test + v3query_qqic_test v2reportleave_test v3include_test v3inc_allow_test @@ -84,6 +86,7 @@ switch_destroy() { ip link set dev $swp2 down ip link set dev $swp1 down + ip link set dev br0 down =20 ip link del dev br0 } @@ -116,6 +119,112 @@ cleanup() vrf_cleanup } =20 +check_binary() +{ + local cmd=3D$1; shift + local args=3D$@ + + if [[ ! -x "$(command -v "$cmd")" ]]; then + log_test_skip "$args $cmd not found" + return $EXIT_STATUS + fi +} + +tcpdump_show_with_filter() +{ + local if_name=3D$1; shift + local filter=3D$@ + + tcpdump -e -n -r ${capfile[$if_name]} "$filter" 2>&1 +} + +validate_query() +{ + local if_name=3D$1; shift + local test=3D"$1"; shift + local value=3D"$1"; shift + local pattern=3D"" + local field_val=3D"" + local pos=3D"" + local msg=3D"IGMPv3 query: verify $test" + check_command tshark || return 1 + check_binary "./mc_encode" $msg || return 1 + + if [ "$test" =3D "MRC" ]; then + pos=3D1 # MRC field offset within IGMP header + field_val=3D$(tshark -r ${capfile[$if_name]} -Y "igmp.type=3D=3D0x11" \ + -V 2>/dev/null | grep "Max Resp Time") + elif [ "$test" =3D "QQIC" ]; then + pos=3D9 # QQIC field offset within IGMP header + field_val=3D$(tshark -r ${capfile[$if_name]} -Y "igmp.type=3D=3D0x11" \ + -V 2>/dev/null | grep "QQIC") + fi + + local enc_val=3D$(./mc_encode $value) + pattern=3D"ip proto 2 and igmp[0] =3D=3D 0x11 and igmp[$pos] =3D=3D $enc_= val" + local opt_str=3D"" + tcpdump_show_with_filter $if_name $pattern | grep -q "igmp query v3" + ret=3D$? + if [ "$field_val" !=3D "" -a $ret -ne 0 ]; then + opt_str=3D"Bad $test value in IGMP packet: $field_val" + fi + check_err $ret "$opt_str" + + log_test "$msg" "configured=3D$value, expected=3D$enc_val" +} + +v3query_mrc_test() +{ + RET=3D0 + local qri_val=3D160 + local br_qri=3D$((qri_val*10)) + + # Set MRT to validate + ip link set dev br0 type bridge mcast_query_interval 12500 \ + mcast_query_response_interval $br_qri \ + mcast_igmp_version 3 + check_err $? "IGMPv3 QUERY bridge configuration failed" + + ip link set dev br0 down + tcpdump_start $h2 + ip link set dev br0 up + sleep 2 + tcpdump_stop $h2 + + validate_query $h2 "MRC" $qri_val + tcpdump_cleanup $h2 + + ip link set dev br0 type bridge mcast_query_interval 12500 \ + mcast_query_response_interval 1000 \ + mcast_igmp_version 2 +} + +v3query_qqic_test() +{ + RET=3D0 + local qqi_val=3D160 + local br_qqi=3D$((qqi_val*100)) + + # Set QQIC to validate + ip link set dev br0 type bridge mcast_query_interval $br_qqi \ + mcast_query_response_interval 1000 \ + mcast_igmp_version 3 + check_err $? "IGMPv3 QUERY bridge configuration failed" + + ip link set dev br0 down + tcpdump_start $h2 + ip link set dev br0 up + sleep 2 + tcpdump_stop $h2 + + validate_query $h2 "QQIC" $qqi_val + tcpdump_cleanup $h2 + + ip link set dev br0 type bridge mcast_query_interval 12500 \ + mcast_query_response_interval 1000 \ + mcast_igmp_version 2 +} + v2reportleave_test() { RET=3D0 diff --git a/tools/testing/selftests/net/forwarding/mc_decode.c b/tools/tes= ting/selftests/net/forwarding/mc_decode.c new file mode 100644 index 000000000000..5b626101497d --- /dev/null +++ b/tools/testing/selftests/net/forwarding/mc_decode.c @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include +#include + +#define IGMPV3_FP_EXP(value) (((value) >> 4) & 0x07) +#define IGMPV3_FP_MAN(value) ((value) & 0x0f) + +/* IGMPV3 floating-point exponential field threshold */ +#define IGMPV3_EXP_MIN_THRESHOLD 128 + +static inline unsigned long decode_field(const u8 code) +{ + /* RFC3376, relevant sections: + * - 4.1.1. Maximum Response Code + * - 4.1.7. QQIC (Querier's Query Interval Code) + */ + if (code < IGMPV3_EXP_MIN_THRESHOLD) { + return (unsigned long)code; + } else { + unsigned long mc_man, mc_exp; + mc_exp =3D IGMPV3_FP_EXP(code); + mc_man =3D IGMPV3_FP_MAN(code); + return ((mc_man | 0x10) << (mc_exp + 3)); + } +} + +int main(int argc, char *argv[]) +{ + uint8_t qqic =3D 0; + if (argc >=3D 2) + qqic =3D atoi(argv[1]); + unsigned long qqi =3D decode_field(qqic); + + printf("%lu\n", qqi); + + return 0; +} diff --git a/tools/testing/selftests/net/forwarding/mc_encode.c b/tools/tes= ting/selftests/net/forwarding/mc_encode.c new file mode 100644 index 000000000000..a2183b864be4 --- /dev/null +++ b/tools/testing/selftests/net/forwarding/mc_encode.c @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include +#include + +/* IGMPV3 floating-point exponential field threshold */ +#define IGMPV3_EXP_MIN_THRESHOLD 128 +/* Max representable (mant =3D 0xF, exp =3D 7) -> 31744 */ +#define IGMPV3_EXP_MAX_THRESHOLD 31744 + +static inline uint8_t encode_field(unsigned int value) +{ + uint8_t mc_exp, mc_man; + + /* RFC3376: QQIC/MRC < 128 is literal */ + if (value < IGMPV3_EXP_MIN_THRESHOLD) + return (uint8_t)value; + + /* Saturate at max representable (mant =3D 0xF, exp =3D 7) -> 31744 */ + if (value >=3D IGMPV3_EXP_MAX_THRESHOLD) + return 0xFF; + + mc_exp =3D (uint8_t)(fls(value) - 8); + mc_man =3D (uint8_t)((value >> (mc_exp + 3)) & 0x0F); + + return 0x80 | (mc_exp << 4) | mc_man; +} + +int main(int argc, char *argv[]) +{ + unsigned int qqi =3D 0; + if (argc >=3D 2) + qqi =3D atoi(argv[1]); + + uint8_t qqic =3D encode_field(qqi); + + printf("%u\n", qqic); + + return 0; +} --=20 2.43.0