From: Nikolay Aleksandrov <razor@blackwall.org>
To: Ujjal Roy <royujjal@gmail.com>,
"David S . Miller" <davem@davemloft.net>,
Eric Dumazet <edumazet@google.com>,
Jakub Kicinski <kuba@kernel.org>, Paolo Abeni <pabeni@redhat.com>,
Simon Horman <horms@kernel.org>, Ido Schimmel <idosch@nvidia.com>,
David Ahern <dsahern@kernel.org>, Shuah Khan <shuah@kernel.org>,
Andy Roulin <aroulin@nvidia.com>, Yong Wang <yongwang@nvidia.com>,
Petr Machata <petrm@nvidia.com>
Cc: Ujjal Roy <ujjal@alumnux.com>,
bridge@lists.linux.dev, netdev@vger.kernel.org,
linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org
Subject: Re: [PATCH net-next v3 4/5] ipv6: mld: encode multicast exponential fields
Date: Tue, 7 Apr 2026 17:09:01 +0300 [thread overview]
Message-ID: <b10f5928-ebec-4313-b04b-22ff7ab76c96@blackwall.org> (raw)
In-Reply-To: <20260403150050.1235-5-royujjal@gmail.com>
On 03/04/2026 18:00, Ujjal Roy wrote:
> In MLD, QQIC and MRC fields are not correctly encoded when
> generating query packets. Since the receiver of the query
> interprets these fields using the MLDv2 floating-point
> decoding logic, any value that exceeds the linear threshold
> is incorrectly parsed 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 >= 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 >= 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 <royujjal@gmail.com>
> ---
> include/net/mld.h | 122 ++++++++++++++++++++++++++++++++++++++
> net/bridge/br_multicast.c | 4 +-
> 2 files changed, 124 insertions(+), 2 deletions(-)
>
> diff --git a/include/net/mld.h b/include/net/mld.h
> index da3299545ebd..147e8c44eb28 100644
> --- a/include/net/mld.h
> +++ b/include/net/mld.h
> @@ -90,12 +90,134 @@ struct mld2_query {
> #define MLDV2_QQIC_MAN(value) ((value) & 0x0f)
>
> #define MLD_QQIC_MIN_THRESHOLD 128
> +/* Max representable (mant = 0xF, exp = 7) -> 31744 */
> +#define MLD_QQIC_MAX_THRESHOLD 31744
> #define MLD_MRC_MIN_THRESHOLD 32768UL
> +/* Max representable (mant = 0xFFF, exp = 7) -> 8387584 */
> +#define MLD_MRC_MAX_THRESHOLD 8387584
> #define MLDV1_MRD_MAX_COMPAT (MLD_MRC_MIN_THRESHOLD - 1)
>
> #define MLD_MAX_QUEUE 8
> #define MLD_MAX_SKBS 32
>
> +/* V2 exponential field encoding */
> +
> +/*
> + * Calculate Maximum Response Code from Maximum Response Delay
> + *
> + * MRC represents the 16-bit encoded form of Maximum Response
> + * Delay (MRD); once decoded, the resulting value is in
> + * milliseconds.
> + *
> + * RFC3810 defines only the decoding formula:
> + * Maximum Response Delay = (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 = 12 + (exp + 3) = exp + 15.
> + * This is the MSB at the 0-based bit position: (exp + 15).
> + * Since fls() is 1-based, fls(value) - 1 = exp + 15.
> + *
> + * Therefore:
> + * exp = fls(value) - 16
> + * mant = (value >> (exp + 3)) & 0x0FFF
> + *
> + * Final encoding formula:
> + * 0x8000 | (exp << 12) | mant
> + *
> + * Example (value = 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| 1311744
> + * | ^-^--------mant---------^ ^...(exp+3)...^| exp=5
> + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
> + *
> + * Encoded:
> + * 0x8000 | (5 << 12) | 0x404 = 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 mrd;
> +
> + /* Saturate at max representable (mant = 0xFFF, exp = 7) -> 8387584 */
> + if (mrd >= MLD_MRC_MAX_THRESHOLD)
> + return 0xFFFF;
> +
> + mc_exp = fls(mrd) - 16;
> + mc_man = (mrd >> (mc_exp + 3)) & 0x0FFF;
> +
> + return 0x8000 | (mc_exp << 12) | mc_man;
> +}
> +
> +/*
> + * Calculate Querier's Query Interval Code from Query Interval
> + *
> + * QQIC represents the 8-bit encoded form of Query Interval (QQI);
> + * once decoded, the resulting value is in seconds.
> + *
> + * MLDv2 QQIC 8-bit floating-point encoding (RFC3810).
> + *
> + * RFC3810 defines only the decoding formula:
> + * QQI = (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' = 4 + (exp + 3) = exp + 7.
> + * This is the MSB at the 0-based bit position: (exp + 7).
> + * Since fls() is 1-based, fls(value) - 1 = exp + 7.
> + *
> + * Therefore:
> + * exp = fls(value) - 8
> + * mant = (value >> (exp + 3)) & 0x0F
> + *
> + * Final encoding formula:
> + * 0x80 | (exp << 4) | mant
> + *
> + * Example (value = 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 = 3200)
> + * | ^-^-mant^ ^..(exp+3)..^| exp = 4, mant = 9
> + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
> + *
> + * Encoded:
> + * 0x80 | (4 << 4) | 9 = 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 value;
> +
> + /* Saturate at max representable (mant = 0xF, exp = 7) -> 31744 */
> + if (value >= MLD_QQIC_MAX_THRESHOLD)
> + return 0xFF;
> +
> + mc_exp = fls(value) - 8;
> + mc_man = (value >> (mc_exp + 3)) & 0x0F;
> +
> + return 0x80 | (mc_exp << 4) | mc_man;
> +}
> +
> /* V2 exponential field decoding */
>
> /* Calculate Maximum Response Delay from Maximum Response Code
> diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
> index 27010744d7ae..a22e44c4fa48 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(struct net_bridge_mcast *brm
> break;
> case 2:
> mld2q = (struct mld2_query *)icmp6_hdr(skb);
> - mld2q->mld2q_mrc = htons((u16)jiffies_to_msecs(interval));
> + mld2q->mld2q_mrc = htons((u16)mldv2_mrc(jiffies_to_msecs(interval)));
you've defined mldv2_mrc as u16, no need to cast it again here
> mld2q->mld2q_type = ICMPV6_MGM_QUERY;
> mld2q->mld2q_code = 0;
> mld2q->mld2q_cksum = 0;
> @@ -1190,7 +1190,7 @@ static struct sk_buff *br_ip6_multicast_alloc_query(struct net_bridge_mcast *brm
> mld2q->mld2q_suppress = sflag;
> mld2q->mld2q_qrv = 2;
> mld2q->mld2q_nsrcs = htons(llqt_srcs);
> - mld2q->mld2q_qqic = brmctx->multicast_query_interval / HZ;
> + mld2q->mld2q_qqic = mldv2_qqic(brmctx->multicast_query_interval / HZ);
> mld2q->mld2q_mca = *group;
> csum = &mld2q->mld2q_cksum;
> csum_start = (void *)mld2q;
next prev parent reply other threads:[~2026-04-07 14:09 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-04-03 15:00 [PATCH net-next v3 0/5] net: bridge: mcast: support exponential field encoding Ujjal Roy
2026-04-03 15:00 ` [PATCH net-next v3 1/5] ipv4: igmp: get rid of IGMPV3_{QQIC,MRC} and simplify calculation Ujjal Roy
2026-04-07 13:44 ` Ido Schimmel
2026-04-03 15:00 ` [PATCH net-next v3 2/5] ipv6: mld: rename mldv2_mrc() and add mldv2_qqi() Ujjal Roy
2026-04-07 13:44 ` Ido Schimmel
2026-04-03 15:00 ` [PATCH net-next v3 3/5] ipv4: igmp: encode multicast exponential fields Ujjal Roy
2026-04-07 13:44 ` Ido Schimmel
2026-04-03 15:00 ` [PATCH net-next v3 4/5] ipv6: mld: " Ujjal Roy
2026-04-07 13:45 ` Ido Schimmel
2026-04-07 14:09 ` Nikolay Aleksandrov [this message]
2026-04-03 15:00 ` [PATCH net-next v3 5/5] selftests: net: bridge: add tests for MRC and QQIC validation Ujjal Roy
2026-04-07 1:25 ` Jakub Kicinski
2026-04-07 6:53 ` Ujjal Roy
2026-04-07 13:45 ` Ido Schimmel
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=b10f5928-ebec-4313-b04b-22ff7ab76c96@blackwall.org \
--to=razor@blackwall.org \
--cc=aroulin@nvidia.com \
--cc=bridge@lists.linux.dev \
--cc=davem@davemloft.net \
--cc=dsahern@kernel.org \
--cc=edumazet@google.com \
--cc=horms@kernel.org \
--cc=idosch@nvidia.com \
--cc=kuba@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-kselftest@vger.kernel.org \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=petrm@nvidia.com \
--cc=royujjal@gmail.com \
--cc=shuah@kernel.org \
--cc=ujjal@alumnux.com \
--cc=yongwang@nvidia.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox