From nobody Tue Apr 7 12:20:08 2026 Received: from mail-pf1-f178.google.com (mail-pf1-f178.google.com [209.85.210.178]) (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 D4F433C3C1B for ; Fri, 3 Apr 2026 15:01:07 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.178 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775228470; cv=none; b=u70MorczyozvMXSxhUvurmPviuA48Ez7eWS8bqJwWhJQbX8QtKAEcFEjJBADXjhC0/5XjSUNeHhycOAWveMC7X+v1BHYA33AhlX0kTmZwmf8Aazzt/AeoZPaGjJj6TUa9Xck/9V1gsz941UcbG1WZbcYzMKPWu3IMEVz0RdH1wA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775228470; c=relaxed/simple; bh=J0qBZOFYr25CwqolwkVoKoYOv65Rm2yGyYDO9qaRe6M=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=TyhVBeH0YKU9iqF39JsNWdt2n2SV5PHoCuPJi+b7Kt9paCyXlM9aoh+U/Meml9K8a8voPOhw/aBOOpdSumDEyZLMYmF/7z+0o3w1LfuaLchcm7MEFJHKMPCoM/JDN/rao487qwPpmPlQN1AAUwVQEopYf4hb/kaVVDwRYbOdT7I= 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=rtPcVAQw; arc=none smtp.client-ip=209.85.210.178 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="rtPcVAQw" Received: by mail-pf1-f178.google.com with SMTP id d2e1a72fcca58-82c70e4654eso921324b3a.2 for ; Fri, 03 Apr 2026 08:01:07 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1775228467; x=1775833267; 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=Cej7nCKLEwnUD6W7mDHvwY/cOSNtwOIhgAuZzAFc2ac=; b=rtPcVAQwC/sZRlIb3dEPBgx5/WeETNEZqotbWkfNVJQJlWr2gb+683OTMtohMlxkiv oncaa/34HknqphnVY6jfAC8LSZUTp9fvZEj44duUAErBi/lvQEC5mSTzaWwAiDS67XF3 BZQkdX2gG22Xu0T/gQOcyZSWCmHzJCOPyVC+3ZNNdJNo9TQj/u6OkvTgHw1Owbnno9ME dLY5In3cwslpwb7DC/yysUeaqD7K6hQ1VvqHNfhEOJg0c7IsLqNNT0EPxmiUuhcqrFua th7+rgNOcJ/dGx7hBSzYGbsZvUdJjRdoNQeR9HcrJAqxtqzPlVCDle5LVxW4h2Md56FE HDGw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1775228467; x=1775833267; 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=Cej7nCKLEwnUD6W7mDHvwY/cOSNtwOIhgAuZzAFc2ac=; b=QH+1Gep8oqnR3wEGOflT3RfPtte1pvN1Ej2PmE+ALZBpx3NcRvMgqNWwqAICyLbc+p OyGTWHa9QI2axxXbRRalAaDNwFMh2IR1UlO41DmOEvsi4xjKE6IMi6sSGWE89EVYs5/c JQPMn6VHO1hzmk8JNlcP1SmNu+N8DXEV701dMmHO7gE4A35AUZwdOXCGI6CVWEc5jK2C SAgXp+QzO0FEPnZ0tFETYZq3j/FFpgDJKQj0P4UegW5xXdn4PWCxDCiWkYfvIeRhE6sS 9ahvout5sf47xck4sdx9ffSDKPou6QNCrkwoNng9cmxHHTw/wLbdATnTO2O/7wv/9RCc sQlg== X-Forwarded-Encrypted: i=1; AJvYcCUun4Udgicpi1SKBaRrZu+CT0fdXb5igcuDq2rqEZGKWo328aAR4SwwOzJJh1Inq3weTPXnq1lG8eoYboQ=@vger.kernel.org X-Gm-Message-State: AOJu0YySZNa5icTDLCPkGvYKEJ3nHwcB6O3xfb+r28Mom+A7/qC7H3jG 7uZC9XeglMqQQBIP/UhjNipx6Kezi0H5qZTp2BylSJlsGQj658T/cnYtD41rxNgPIXI= X-Gm-Gg: ATEYQzwUmyPPHIkhebn4noWXnO5OSvxPWm57We35VHLvHqRiU5jxaGX6hk8Gmr0851h WJMSN0ahhLi8jF+xW7GIqeYHBu4UrWcD9V9h1aD9bKWw1wJ/9zPkhFQAPpLmTycLohj2YUoA8gu 3T9guBRPPzFtySlWtURQJsPaqBkJLGwM18+cdaSbBYBwU+mdLuq7sdh204yeMuQY1L39wyvH+Lv Mv0gflMpWU7XQPeEPASUgHPRVUP92x9ysx+wuoFd91csagILU4kvdRJE5RH5DJJ3UimHBBTFpCQ qID7jfnYu5vQqmfEeO0D/MNKSy78kmYmF62fOrrqnt1t/ArR+Yv7XzB8WTaMOamfDmFLwB20fhv C7CW2SGKO4Ks6CBrr/XArNnctTB8gYGt2x2C83XeGfjSdeB6Zh8LG12o+ON+paR3ppQXad9LzNF GdOlhKHAIr3QStzg/J5z6es7wtEAthg97NvISemUQ0 X-Received: by 2002:a05:6a00:8018:b0:82c:215d:5e9d with SMTP id d2e1a72fcca58-82d0db6bfc5mr3316415b3a.32.1775228467048; Fri, 03 Apr 2026 08:01:07 -0700 (PDT) Received: from DESKTOP-82PPU4A.localdomain ([202.8.116.192]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-82cf9ca79basm7789483b3a.58.2026.04.03.08.01.00 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 03 Apr 2026 08:01:05 -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 v3 1/5] ipv4: igmp: get rid of IGMPV3_{QQIC,MRC} and simplify calculation Date: Fri, 3 Apr 2026 15:00:46 +0000 Message-ID: <20260403150050.1235-2-royujjal@gmail.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260403150050.1235-1-royujjal@gmail.com> References: <20260403150050.1235-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 | 84 +++++++++++++++++++++++++++++++++++---- net/bridge/br_multicast.c | 2 +- net/ipv4/igmp.c | 6 +-- 3 files changed, 80 insertions(+), 12 deletions(-) diff --git a/include/linux/igmp.h b/include/linux/igmp.h index 073b30a9b850..0624410e75c6 100644 --- a/include/linux/igmp.h +++ b/include/linux/igmp.h @@ -92,15 +92,83 @@ 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) + * + * For both MRC and QQIC, values >=3D 128 use the same floating-point + * encoding 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 QQIC/MRC 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 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 + * + * After decode, MRC represents the Maximum Response Time (MRT) in units + * of 0.1 seconds (100 ms). + */ +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 + * + * After decode, QQIC represents the Querier's Query Interval in units + * of seconds. + */ +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..d7eff36d98c3 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 Tue Apr 7 12:20:08 2026 Received: from mail-pg1-f176.google.com (mail-pg1-f176.google.com [209.85.215.176]) (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 019B53CC9FD for ; Fri, 3 Apr 2026 15:01:14 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.215.176 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775228476; cv=none; b=EcWzdvfZbO+Qq+6BL310nUpaCv4D7jPXIsY/AT0qe/I2Uyh7LA37AlsRYu4ZgQTn7S7tpGETwOmq+1hltM/832I7awxBx47Yk5DEvCuZfh/tzuwrSVBOpsSZULM4QvBIsB6GTskax/nVBCE2yI9shYlmvSRi9ZGf4s6vW0Jmhvk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775228476; c=relaxed/simple; bh=/mvWdn/wGAykwRVbilLUMYweyyaQRxjwPI/Js63ZwqU=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=PymAPyL+0vlQ6ED93jNomZ6g2usyH1sIX/ycjWHbw6NqjLkR7boluaznapZQgHHzTNQUAxUmcCgu1BVMyZ6kk2ODkBrFLKcrQm/imWtffYezNwXOY2Wf1srkmwH0jN20bJk/GY9Cv0LNW0D/poyfn6E8Q7YCSo/IYQv9dwyl5Eg= 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=H2X1mRzf; arc=none smtp.client-ip=209.85.215.176 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="H2X1mRzf" Received: by mail-pg1-f176.google.com with SMTP id 41be03b00d2f7-c76c60c7502so763731a12.0 for ; Fri, 03 Apr 2026 08:01:14 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1775228474; x=1775833274; 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=vOZNpt/bcu1cEQwQ1aXYPtHdfiB4Rn2c0iK1yBAhiAY=; b=H2X1mRzf/SBHaPpVtNRcpkYoavd0fk4VUrRxmTHnR08yaiebBsIred7MzVjcJzgNBq qK9pSO5U31qqW5wQTcgGp80FEQXluEXx9Mxxlw+20/9JFnpTabgHM3p2jWBgke2DbcZF NnnPiOByYQG5BKMp8P4XcfW3qNaxVopYnXvLeEljISkEx+AEYvzNSXhbp9vZAgQCLqWE sxt3nN42Ew9gUQ/ih74l915Ua6kP5a9CagOJYIEaWuJzqvqgO/t+9U95k4l93gy5rUeL B36HNziprM4+jpoprQvGYYbKIrYHtiljIgdHBUccphgvYV43BNPpax72qvQMbLwQHRgC U2gg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1775228474; x=1775833274; 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=vOZNpt/bcu1cEQwQ1aXYPtHdfiB4Rn2c0iK1yBAhiAY=; b=mgw9nLVcEpLj/+tp62RKiOfmXvSPyXOV+2X3Xp3svuO0wEqDphl0XQn3XcMnU6XklO CSA+2a1ekVS85C6Zeubrb/MMwyPWMJf6JlNvO8fzmPesHp6W10k9tC9CcaU593gAwp+8 tf70P8t8gw+6SdRniXMSbFCTbXELYxkMt1yMOiMGdRhysO1+Ji9L2XJ6VafxmTJHa8t4 UsMJeHY3HnXHPrszRyWsZdIkQ65BwiOyh/k4biC4kiNw8JR2i4TAWyjSYXnifFMgCzVW 7TVFuSQGInyEUHQ0UeOXOCPemuom9ajXX9wOQH/wcInd1twT7OkpZ/HXJzj1YgCgn7jA vaGg== X-Forwarded-Encrypted: i=1; AJvYcCUwbr2r3QYi0GML4VFRHCInYjt/Jaug4CASYedgqcQ0gccafv5TStuEwjbQZRz5qm+7CiLoe2B5kmEd610=@vger.kernel.org X-Gm-Message-State: AOJu0Yz+wsKgZAteA7+QtVaaKhNidtVZXFSlwANJzKKHgONLqXG+fKfd KGx7emr/4MbWomDdF7eOFsB98z5NxF0BMZ3QQUDb4VmnGi9UKC42n8/H X-Gm-Gg: ATEYQzzpJV0LhKoYkMvNTIi0O0xLrbz3fcsB1/XTY+fQ4xihmFCJJve/HTOFx+KDRnG XViJQN5kfzpvoVyc6NzXiai7VP/WJPGPEpw11SsUYe95vZrQRioFruHmIRmxBmEv8W+9W/DWGEH 1sf1WVPE75e2W+6sGcIUrfJClGNI3hOy+4UJrGpezFiqDrAlotxA4W1F38296xPmeiqBSDtMs7q ukHZPEXKj16M2q5mUQbeKAuXlJ2kL1ywG/cMVtERwbBdEXNUr+yfFjuamF9saSzuwGQMSHWSMoY BuNaRG6xo7hCSJLXx0wOpGTj5KAaQiDcMzEfYCESJ6eRSkKG5InNjjiy9h/eNZfHh1SN64akYEn qEjWhXd3HTiztFrtgm5O/rExn8fGFNfPqRE+BD5i6To+X4KXDJN8/JHYsoajiJs081TX8js7EWv MHjBpKAN/hk57ruJcjUPyKSvTH47M5g4bGubS0AjKq X-Received: by 2002:a05:6a20:7d8a:b0:39f:a42:924b with SMTP id adf61e73a8af0-39f2d8a8ea8mr3039990637.11.1775228473764; Fri, 03 Apr 2026 08:01:13 -0700 (PDT) Received: from DESKTOP-82PPU4A.localdomain ([202.8.116.192]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-82cf9ca79basm7789483b3a.58.2026.04.03.08.01.07 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 03 Apr 2026 08:01:12 -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 v3 2/5] ipv6: mld: rename mldv2_mrc() and add mldv2_qqi() Date: Fri, 3 Apr 2026 15:00:47 +0000 Message-ID: <20260403150050.1235-3-royujjal@gmail.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260403150050.1235-1-royujjal@gmail.com> References: <20260403150050.1235-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 is 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. Signed-off-by: Ujjal Roy --- include/net/mld.h | 70 +++++++++++++++++++++++++++++++++------ net/bridge/br_multicast.c | 2 +- net/ipv6/mcast.c | 19 ++--------- 3 files changed, 64 insertions(+), 27 deletions(-) diff --git a/include/net/mld.h b/include/net/mld.h index c07359808493..da3299545ebd 100644 --- a/include/net/mld.h +++ b/include/net/mld.h @@ -89,29 +89,79 @@ 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 + * + * After decode, MRC represents the Maximum Response Delay (MRD) in units + * of milliseconds. + * + * 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 + * + * After decode, QQIC represents the Querier's Query Interval in units + * of seconds. + * + * 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 Tue Apr 7 12:20:08 2026 Received: from mail-pf1-f172.google.com (mail-pf1-f172.google.com [209.85.210.172]) (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 423DF3C9ED1 for ; Fri, 3 Apr 2026 15:01:23 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775228484; cv=none; b=GyVi7y+NXiWvlbGxZP/KRveJ8qxBeBIaD6hKla/8fdXytAZrKjnHFTpryIxexvDiUI9CBh/6uprl4CrLP9kFu+vasxZA5jwUqPaDuNhgmD90UWI7WqftnYgBSWsVU4TxgUpvrMbdJsX2edq20V/adqpD6xvmtHZ7/kxd1fklm7c= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775228484; c=relaxed/simple; bh=Iq0tktjsX7ePEwq4lGlKSL1uL+gib4ijw7o7rXmI/94=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=PqmMZtRi/fb8r73Dq2hljlvhiBR+Di2H1z1eGvdMzuUkg8uEHlDEoJzrG/V7A8ch44zbL8b5w0+MKR+kUezlh6ZTZwUq+Eb8wwT5jxCbsqQfL4MTwSa8ZCPykyvzJheEnll2b9NEQjDNS8/pPMmAlsEDV9C8cI23xNMbd0bj5hU= 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=R/SkfL3L; arc=none smtp.client-ip=209.85.210.172 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="R/SkfL3L" Received: by mail-pf1-f172.google.com with SMTP id d2e1a72fcca58-82c20b9fb15so893583b3a.3 for ; Fri, 03 Apr 2026 08:01:23 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1775228483; x=1775833283; 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=W4ZMqjHC+tTjU8qo0ldftPqXLWyA0cBMe3rgBvQvxRs=; b=R/SkfL3LfPD87zNE2s1P8hPgDrSK6kInPW9wUSZtd1tle2Ev+GirPlMTuZJ2kfM56p bqF5wjzJrOJyRXEkmmOY69jzceaXpGmUhbs/UwxhvZLYZR6i6xyolD/x2oCJmVPvq7Fu PTKTXIN3ko9d2Uqi3z+osAEnEK9E1d6OZexVJZtlYouGm6pUrCZvOhmukq0hADDFpH7M r8DvHK+7PBWs/PpPiTqWlIFuBXg0V0DP7/74m2leMIkDcp14xDq76uC0lIbXE09kZ7gf U7NmJXSNX2ApxvKvrPcOdtmvhQIPaeDI+REwSSQY3qo8jYwg5ZsGXYShY8E9fAncRHUY pm3w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1775228483; x=1775833283; 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=W4ZMqjHC+tTjU8qo0ldftPqXLWyA0cBMe3rgBvQvxRs=; b=GN+sr4WLMG4v68Ten13+hIY2rtpYhGUcFmJyQwVznbrhNQDGuAGb3C+ZUelAu/9//V rgN38NdGaljvZ3MNbGaUVHwIPcHXLmDLCFevC/pJgK0YhLkS9Dx8s/rUnyoLxzWemJyS enBPskBFqrbpHTBbrJWZKD1Z6yHcJsu9Cam1UfXdOhtMg8UngRQtuUsaubdiypDVlySG 61c+dIwNj/yWoMv2kHRG0B9dRLTPMku5LuGXW+eJeXd0lWXH+i0/VeyYGpWVvENXNGw/ hU19AjmZBbvYtWYjifzpw2GUptNaKYOz14J5MPgYSIlxb/vQG+emqdfdm63meU2mLY1D vnXw== X-Forwarded-Encrypted: i=1; AJvYcCWPE4piSu4Wvhb0WsedpXUdl5zBmM72r7UXelB5P3SkRn6n2IDyrustrTL2NGhyIoSShzX4SrAeK1Cqswo=@vger.kernel.org X-Gm-Message-State: AOJu0YyCmy+jsNlGAvBl27F/DyPUozNFNFYGhEWlZGmIIJkcogwtmXFf MxAN/jJf/RUys7yOOjEgaR+1VGThiadgMwn2zfCRU2k2zNglZ/AoicQK X-Gm-Gg: ATEYQzw52xZ/q2l56/F9L396CeSNKLfyO60F8vtpM1IDVE7hL9+3axw2WWCpOESxaEM jFLf9GY1opzuTVT2miiTizfprA6bwdPDchKQQUquhuFoCf1QZWe63Zpa+vhF3tSgpDPBWf5wrYL oYX/NuUFjhPCD4J4v3t/1SODJCpBHmcKiTvvy2iapxCi/srqON4T5MMS7MUDrQQ3w8SgFzrvCJi vfvsBfcnq/83PAskmWj9Q1/MdC4g24+CUXugKWP0FJ0wgYUO+EATmW8xuNCqxjaS+Rs/XFQK1M6 WJTupZCyyrdLQHyHqj6tsMjsLZcv2RL4zaAO5aluR2xINFJ8DD66DgGLzm9x71qSeFWXvG5XnsK Mrn3tZ7779I4k4mc94QmrVyNslS4mOwtikQUeiuNfKXz0zIe11NKsXaJ6vdDJZzg/KN/vaTf+mw nyjbwJPJIn76JwSCf+hPNKEGRchpSG7HdnaXd35krCo5bYBpgn0qo= X-Received: by 2002:a05:6a00:4397:b0:829:862d:6b46 with SMTP id d2e1a72fcca58-82d0da2f24bmr3265722b3a.6.1775228482267; Fri, 03 Apr 2026 08:01:22 -0700 (PDT) Received: from DESKTOP-82PPU4A.localdomain ([202.8.116.192]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-82cf9ca79basm7789483b3a.58.2026.04.03.08.01.14 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 03 Apr 2026 08:01:20 -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 v3 3/5] ipv4: igmp: encode multicast exponential fields Date: Fri, 3 Apr 2026 15:00:48 +0000 Message-ID: <20260403150050.1235-4-royujjal@gmail.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260403150050.1235-1-royujjal@gmail.com> References: <20260403150050.1235-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 correctly encoded when generating query packets. Since the receiver of the query interprets these fields using the IGMPv3 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 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 | 87 +++++++++++++++++++++++++++++++++++++++ net/bridge/br_multicast.c | 14 +++---- 2 files changed, 93 insertions(+), 8 deletions(-) diff --git a/include/linux/igmp.h b/include/linux/igmp.h index 0624410e75c6..4e895829cd0e 100644 --- a/include/linux/igmp.h +++ b/include/linux/igmp.h @@ -109,6 +109,93 @@ 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 value; + + /* Saturate at max representable (mant =3D 0xF, exp =3D 7) -> 31744 */ + if (value >=3D IGMPV3_EXP_MAX_THRESHOLD) + return 0xFF; + + mc_exp =3D fls(value) - 8; + mc_man =3D (value >> (mc_exp + 3)) & 0x0F; + + return 0x80 | (mc_exp << 4) | mc_man; +} + +/* Calculate Maximum Response Code from Max Resp Time + * + * MRC represents the encoded form of Max Resp Time (MRT); once + * decoded, the resulting value is in units of 0.1 seconds (100 ms). + */ +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 + * + * QQIC represents the encoded form of Query Interval (QI); once + * decoded, the resulting value is in units of seconds. + */ +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 Tue Apr 7 12:20:08 2026 Received: from mail-pf1-f178.google.com (mail-pf1-f178.google.com [209.85.210.178]) (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 CFF003CAE9D for ; Fri, 3 Apr 2026 15:01:29 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.178 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775228491; cv=none; b=gfPU9myRd0M7wcnlfLq8naZbUV1Fb5QYXOwlS8J764w/Kz8HspvjotJwe/DV4Fz2AND8M/BU517DKtutDXZzRIKl0v1kBdqcRdsnMZCndYZsFddrfGC1NW1iSQmOpPzGi33CC9PErNHekQAOwJ6GJHfE86Zcnp9d0R5aoRzBqcE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775228491; c=relaxed/simple; bh=EKpTwE4ZfpPM1Z81RyM2aK+iglf5OV67iJmGTsG62ls=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=dLFdE57mVBbGi/LXrBo8/x4lNAWn4zwcPRkpPxdfi/8oMYQ8ampaS1yzZs0bvrxZ+DuzhBHKaF2zZmTZFCHjEmKy2s2NPqd+4bDM1YonEXcXLudR+QCADJTLea1W2amtHUoMP1Fws+IgRM9YGZytAo9VzhkTf4kbaaLZAarW25E= 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=VljK/N1H; arc=none smtp.client-ip=209.85.210.178 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="VljK/N1H" Received: by mail-pf1-f178.google.com with SMTP id d2e1a72fcca58-82ce2e2880cso1448678b3a.0 for ; Fri, 03 Apr 2026 08:01:29 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1775228489; x=1775833289; 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=kA8wWqgtt+a655+1MvtrE0v6BL6IMopBXGlXnFLxq48=; b=VljK/N1HcWQHhTT/EUp+8siMDgazeIjpCh96QGkXbusS7fb407O0fsxbCS0xaIpV1v 9zwu9xR9jQX/5Hj2aOUMygDMEKt6JSqr+IrmqFxMRjD1pUAwUwgW7csA1HbXPx8uoojJ RMrHqD2iZK9thANcjv63/RtzVuC4+Y6kuzCkpSQderI4137PGU86bUtgxR5oHP5qwTEp Af1f+saZZqGDB89qwpkWrxc9Rr+ygF87dCLJAiYFK4DbOjBm+yGqExEZwMDDMuvii3ug g1FPIEctUTSPvUv15AYGQFfeBzkyv7S5RKnKyaML1Gz5A4sc1WS9LFl2/mF2hIc5+/pZ 20ig== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1775228489; x=1775833289; 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=kA8wWqgtt+a655+1MvtrE0v6BL6IMopBXGlXnFLxq48=; b=ZveoG9elevxrMrY8Glk+jMR6+91rCAXOw29It36vhJmMSEamyvVy7ZGJ/OXPRnIv3+ X1CDSRKZsIbvqbOEiEX4MjQ0vDhPpICuGX4y1PQDaWWp730RQKnrIJioxgZLgKV/BNpL lu9y8RynKWakgw9yrdwjxCkMUYiST1PqQ9CziM1K0XsYWL/AFLXx35uMS6Qq7HyY6nUT G3E4oxeuc3CdGcxXYmpRCWqsW0g9kzxtpru0wXrqVholb4iACw/4+rNJv/+gVDZ3XA8g qgXqd4fzlvKu7nbCf6B0dTgGSNEkWf9PEoolgQYUTbC+3lT2Aleu4eSOJ+eExuN+Qehi 2eHA== X-Forwarded-Encrypted: i=1; AJvYcCVUK5ce4mzSBexu2uyh1r71IbX+uARzKEz4E2JQoFOY5bxOhgbn4thnnQAICsMLj5dpbGZNekqUN7FoBD0=@vger.kernel.org X-Gm-Message-State: AOJu0YxZB1KVsmze1y+fd++t9pR7BX8tS4lhoR8KpBnstB8sWwhaAhVq z3k7Vo/5WB+6vCQilqhqrFb88OGzf8GawckI4s816ri02pHotUCNblymN14ATt0kiRg= X-Gm-Gg: AeBDievJ9dA/+/cqAQUeyMf1LErLh2bal7s6Z0SSBe41FWC2hj0OCat06arigLqdurP 00/V4Zqo/V0Y8f4BJmAcbLv6ocrpZu4Dfwu0pD4+cGMZN1ZziwNxHiI71qofzCnKMUxSzzvlhPg vdo2HWHPMusKDxIJNBuAIhkdNHkJa8cOqvC/gVNPvqUKS9pTq3TCJQVvE+Cj3iG0NL+y6u9E0el sUvOsVH/3q8JF8/RU7cCHzsKdAdu6AqqEzG4v0U0t/p9nKcpfxBfz6KOm+FREoM1ixbPnm4KGFj tWaMahMPoBIQP+l01WhfVM9ygMjKQUO99qENTewhSWSmCDpQsPfGQqcFY9KAHco0AxWDV8VTNZ1 5jelqrm8uYxjrRGKNuiApSNi2RWT3+LNJMuhlPo+UxdUbxXkOjNoT3tEwFdMt5rq3eVC3ZvkkqV hUO85S/lgr78UskjsMiy09XPySdy4+m6G7lFpQnpbHoRBOSBygSkQ= X-Received: by 2002:a05:6a00:1d9e:b0:82c:68f6:a18 with SMTP id d2e1a72fcca58-82d0db5b47amr3435171b3a.34.1775228489031; Fri, 03 Apr 2026 08:01:29 -0700 (PDT) Received: from DESKTOP-82PPU4A.localdomain ([202.8.116.192]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-82cf9ca79basm7789483b3a.58.2026.04.03.08.01.22 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 03 Apr 2026 08:01:28 -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 v3 4/5] ipv6: mld: encode multicast exponential fields Date: Fri, 3 Apr 2026 15:00:49 +0000 Message-ID: <20260403150050.1235-5-royujjal@gmail.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260403150050.1235-1-royujjal@gmail.com> References: <20260403150050.1235-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 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 >=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 | 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) =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 + * + * 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 =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 mrd; + + /* Saturate at max representable (mant =3D 0xFFF, exp =3D 7) -> 8387584 */ + if (mrd >=3D MLD_MRC_MAX_THRESHOLD) + return 0xFFFF; + + mc_exp =3D fls(mrd) - 16; + mc_man =3D (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 =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 value; + + /* Saturate at max representable (mant =3D 0xF, exp =3D 7) -> 31744 */ + if (value >=3D MLD_QQIC_MAX_THRESHOLD) + return 0xFF; + + mc_exp =3D fls(value) - 8; + mc_man =3D (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..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(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)mldv2_mrc(jiffies_to_msecs(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 Tue Apr 7 12:20:08 2026 Received: from mail-pf1-f173.google.com (mail-pf1-f173.google.com [209.85.210.173]) (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 DAAAC3CE4BB for ; Fri, 3 Apr 2026 15:01:37 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.173 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775228500; cv=none; b=ho4F4yO36EebtgvBtlK6zZBAvpjiro+J9b+ifv8egaiMJlNAo/f1y4cJzTfsuGF6seJvWK8x7Gy5pOrX6C4QKWyA+nXFWLoWmdINppmbWfc7eZmi23hUi7fAZb5Du6jvf4r33jUe29XxIrPmdnT8GZHIK5+SV7JbAL8/nASpn4U= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775228500; c=relaxed/simple; bh=4LeT1cJ+asqbP8EaYg7MOJK/G//aZNU+VpLMKTbgT3Y=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=sldJZuV7Giu0zptTqEhSh7WSKChKf4XZgY0SQASF0iK/8Xbig8XBPi6Tt+7Y15d55rjrFzlWKlNL8V7ExTloRjt9I1vhHOY9E+tyFDRkeO/R3lAPo8Ukw9tYw1rGsuC6e0O62AwMsRhUTEQJcaTTxA0nA7DGd1CUkVldEr2mvqM= 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=BubxWlLq; arc=none smtp.client-ip=209.85.210.173 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="BubxWlLq" Received: by mail-pf1-f173.google.com with SMTP id d2e1a72fcca58-82418b0178cso971495b3a.1 for ; Fri, 03 Apr 2026 08:01:37 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1775228497; x=1775833297; 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=VjltsPsyl0fA4bSmkbZpBvZZ8hQ+nYEUswOg9yantuE=; b=BubxWlLqoybWJMSpG7OovPTbP0xjrORg17brdwAOkgNeqsS5e0p1cHawflsxUxcVAt DjLWridLfo0gsKU8en6jwyQwp/glaju5aP5OkvcGXuR7zPKIfB4nXl9RyQu9ZguRpxp2 9OWKtoia+2s4SSahWnqodulNSr/MrC30n1VRUtdQY96d3fB9TEhmHZ84Dtir+W9Hzp1I qFdpC1ssU6uRCPNHF3H6nSobta4lY18u8x8Jevp5CLeWKpKu6meg3Z+85Lrn8i/xS09e 1gfsmm9sYW6pWSApq+t7Es7EqkPJE8AdR8BJBOGJIuORSNshSzGXmsbZ0GSD+3DQ4+Ca geAw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1775228497; x=1775833297; 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=VjltsPsyl0fA4bSmkbZpBvZZ8hQ+nYEUswOg9yantuE=; b=YAqomEajTuSxie5ZTgSOLxeOlveWgFgjIAYuDAtLe31lTaDcogHbf5TP8C+KalH/v4 TZ6KIGpIHqDEB8gin0b9vdjOYWMh6GQRsoIKNUztWitJX28F4RW8GNrMFR6KZzrAFT6P uoO1pD4qGhfQ5fmzcMhx/Pq55TIR/LnjVgZm8DgVuBp4eAOvfBQiaCl/M7g/hX4YHg7v 1J1hc7DJuqCvN9KuxptRy/MOPGIvdiLWeQPgmbxuqZQnaB8jhMekoYf07dfG7+mYUhH1 t2fYxBAPGHEv2aIco0LzUzz3zJYU1R7x+WBQtqB8F6EpKYfCiPTJAS2bXx4h/z3kXaMd s0jg== X-Forwarded-Encrypted: i=1; AJvYcCWs1gFKWu5Hh9rphtpteWhPds/N2rEiHJ7qtxCq7aowEfvIbk9uOWpEZrd1VxDyYd6ADq+TZv/hJ8ZvQVY=@vger.kernel.org X-Gm-Message-State: AOJu0YxBPz100nUFK7HnySRjEKO7FNnd5fZAjt9EFgSlnWIbqwDHiX/3 xQUk20a2o245z9eTDdCWBGf3zu6WMpVzsHkjTuX7JDEJ2BpSJ+1wzimR X-Gm-Gg: AeBDiet3h/LWCnX6ObRiQiN4Y8bLIeB8KpH5ez0Axk5YLi3kOF5ALWN8lPWC9eIHlon KL6/cHv0ytetdYoJiKC9sMmCgWVQAzx3w2wWAwstLuQi0FabzB7Q3zT1ITAFQejNyxDht9Jk3mE 4pIzaex14g5lwGNBkEJHEdb1gMN0a9ZRTqRi5F6Js/pR1iJ7jQr3AXjRLBmXfZKVtu9LGpLWuaH fwUYUyuwFpy54jJft5di/d7eG8wh+I5FbcEXzm3rgKJyHT1uWjXq4890jAw1ofAFmKmB7K4/hNo rSDqkgKdI2jkbOuiDddZlQwnwjzB50Iqz1H/aj7b1/s7NGN6zVPxKNPGsaFaaDQm40TU1VzPzwN aKjdj0dxWpR0XaAsSi2fHDezX2roZ/xhxNSCnYUpR8n/rZ1o2TG1HGTI7xwOHm8HQGRxOnZOtsz +d1HOoHyjZvjcOKRvJkVpExHL0IUYEW1XUEKzGIN05 X-Received: by 2002:a05:6a00:2d10:b0:82c:66f2:1226 with SMTP id d2e1a72fcca58-82d0db84a62mr3307715b3a.38.1775228496765; Fri, 03 Apr 2026 08:01:36 -0700 (PDT) Received: from DESKTOP-82PPU4A.localdomain ([202.8.116.192]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-82cf9ca79basm7789483b3a.58.2026.04.03.08.01.29 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 03 Apr 2026 08:01: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 v3 5/5] selftests: net: bridge: add tests for MRC and QQIC validation Date: Fri, 3 Apr 2026 15:00:50 +0000 Message-ID: <20260403150050.1235-6-royujjal@gmail.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260403150050.1235-1-royujjal@gmail.com> References: <20260403150050.1235-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" Update bridge selftests that configure Max Resp Time (MRT) and Querier Query Interval (QQI) parameters and validate the resulting Query packet fields for Max Resp Code (MRC) and Querier Query Interval Code (QQIC). These tests cover the IGMPv3 and MLDv2 for below cases: * MRC and QQIC in linear range. * MRC and QQIC in non-linear range. TEST: Vlan multicast snooping enable [ OK ] TEST: Vlan mcast_query_interval global option default value [ OK ] Vlan 10 mcast_query_interval (QQIC) test cases: TEST: Number of tagged IGMPv2 general query [ OK ] TEST: IGMPv3 QQIC linear value 60 [ OK ] TEST: MLDv2 QQIC linear value 60 [ OK ] TEST: IGMPv3 QQIC non linear value 160 [ OK ] TEST: MLDv2 QQIC non linear value 160 [ OK ] TEST: Vlan mcast_query_response_interval global option default value [ OK= ] Vlan 10 mcast_query_response_interval (MRC) test cases: TEST: IGMPv3 MRC linear value 60 [ OK ] TEST: IGMPv3 MRC non linear value 160 [ OK ] TEST: MLDv2 MRC linear value 30000 [ OK ] TEST: MLDv2 MRC non linear value 60000 [ OK ] Signed-off-by: Ujjal Roy --- .../selftests/net/forwarding/.gitignore | 2 + .../testing/selftests/net/forwarding/Makefile | 10 ++ .../net/forwarding/bridge_vlan_mcast.sh | 157 +++++++++++++++++- .../selftests/net/forwarding/mc_decode.c | 73 ++++++++ .../selftests/net/forwarding/mc_encode.c | 78 +++++++++ 5 files changed, 315 insertions(+), 5 deletions(-) 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_vlan_mcast.sh b/= tools/testing/selftests/net/forwarding/bridge_vlan_mcast.sh index 72dfbeaf56b9..89598712f869 100755 --- a/tools/testing/selftests/net/forwarding/bridge_vlan_mcast.sh +++ b/tools/testing/selftests/net/forwarding/bridge_vlan_mcast.sh @@ -5,6 +5,7 @@ ALL_TESTS=3D"vlmc_control_test vlmc_querier_test vlmc_igmp_= mld_version_test \ vlmc_last_member_test vlmc_startup_query_test vlmc_membership_test \ vlmc_querier_intvl_test vlmc_query_intvl_test vlmc_query_response_intv= l_test \ vlmc_router_port_test vlmc_filtering_test" +TEST_NAME=3D"" NUM_NETIFS=3D4 CHECK_TC=3D"yes" TEST_GROUP=3D"239.10.10.10" @@ -96,6 +97,17 @@ 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 +} + vlmc_v2join_test() { local expect=3D$1 @@ -162,14 +174,27 @@ vlmc_query_cnt_setup() { local type=3D$1 local dev=3D$2 + local intvl_match=3D"$3" =20 if [[ $type =3D=3D "igmp" ]]; then + # This matches: IP Protocol 2 (IGMP) tc filter add dev $dev egress pref 10 prot 802.1Q \ flower vlan_id 10 vlan_ethtype ipv4 dst_ip 224.0.0.1 ip_proto 2 \ + action continue + # AND Type 0x11 (Query) at offset 24 after IP + # IP (20 byte IP + 4 bytes Option) + tc filter add dev $dev egress pref 20 prot 802.1Q u32 \ + match u8 0x11 0xff at 24 $intvl_match \ action pass else + # This matches: ICMPv6 tc filter add dev $dev egress pref 10 prot 802.1Q \ flower vlan_id 10 vlan_ethtype ipv6 dst_ip ff02::1 ip_proto icmpv6 \ + action continue + # AND Type 0x82 (Query) at offset 48 after IPv6 + # IPv6 (40 bytes IPv6 + 2 bytes next HDR + 4 bytes Option + 2 byte pad) + tc filter add dev $dev egress pref 20 prot 802.1Q u32 \ + match u8 0x82 0xff at 48 $intvl_match \ action pass fi =20 @@ -181,9 +206,46 @@ vlmc_query_cnt_cleanup() local dev=3D$1 =20 ip link set dev br0 type bridge mcast_stats_enabled 0 + tc filter del dev $dev egress pref 20 tc filter del dev $dev egress pref 10 } =20 +vlmc_query_get_intvl_match() +{ + local type=3D$1 + local version=3D$2 + local interval=3D$3 + local encode=3D"" + + if [ "$interval" =3D "" ]; then + return + fi + + if [ "$TEST_NAME" =3D "vlmc_query_intvl_test" ]; then + # QQIC is 8-bit floating point encoding for IGMPv3 and MLDv2 + encode=3D"$(./mc_encode 8 $interval)" + if [ "${type}v${version}" =3D "igmpv3" ]; then + # IP 20 bytes + 4 bytes Option + IGMPv3[9] + echo "match u8 $encode 0xff at 33" + elif [ "${type}v${version}" =3D "mldv2" ]; then + # IPv6 40 + 2 next HDR + 4 Option + 2 pad + MLDv2[25] + echo "match u8 $encode 0xff at 73" + fi + elif [ "$TEST_NAME" =3D "vlmc_query_response_intvl_test" ]; then + if [ "${type}v${version}" =3D "igmpv3" ]; then + # MRC is 8-bit floating point encoding for MLDv2 + encode=3D"$(./mc_encode 8 $interval)" + # IP 20 bytes + 4 bytes Option + IGMPv3[1] + echo "match u8 $encode 0xff at 25" + elif [ "${type}v${version}" =3D "mldv2" ]; then + # MRC is 16-bit floating point encoding for MLDv2 + encode=3D"$(./mc_encode 16 $interval)" + # IPv6 40 + 2 next HDR + 4 Option + 2 pad + MLDv2[4] + echo "match u16 $encode 0xffff at 52" + fi + fi +} + vlmc_check_query() { local type=3D$1 @@ -191,9 +253,12 @@ vlmc_check_query() local dev=3D$3 local expect=3D$4 local time=3D$5 + local interval=3D$6 + local intvl_match=3D"" local ret=3D0 =20 - vlmc_query_cnt_setup $type $dev + intvl_match=3D"$(vlmc_query_get_intvl_match $type $version $interval)" + vlmc_query_cnt_setup $type $dev "$intvl_match" =20 local pre_tx_xstats=3D$(vlmc_query_cnt_xstats $type $version $dev) bridge vlan global set vid 10 dev br0 mcast_snooping 1 mcast_querier 1 @@ -201,7 +266,7 @@ vlmc_check_query() if [[ $ret -eq 0 ]]; then sleep $time =20 - local tcstats=3D$(tc_rule_stats_get $dev 10 egress) + local tcstats=3D$(tc_rule_stats_get $dev 20 egress) local post_tx_xstats=3D$(vlmc_query_cnt_xstats $type $version $dev) =20 if [[ $tcstats !=3D $expect || \ @@ -428,6 +493,10 @@ vlmc_querier_intvl_test() =20 vlmc_query_intvl_test() { + TEST_NAME=3D"vlmc_query_intvl_test" + + check_binary "./mc_encode" "$TEST_NAME: verify" || return 1 + RET=3D0 local goutput=3D`bridge -j vlan global show` echo -n $goutput | @@ -440,6 +509,7 @@ vlmc_query_intvl_test() check_err $? "Wrong default mcast_query_interval global vlan option value" log_test "Vlan mcast_query_interval global option default value" =20 + echo "Vlan 10 mcast_query_interval (QQIC) test cases:" RET=3D0 bridge vlan global set vid 10 dev br0 mcast_snooping 1 mcast_startup_quer= y_count 0 bridge vlan global set vid 10 dev br0 mcast_snooping 1 mcast_query_interv= al 200 @@ -447,14 +517,52 @@ vlmc_query_intvl_test() # 1 is sent immediately, then 2 more in the next 5 seconds vlmc_check_query igmp 2 $swp1 3 5 check_err $? "Wrong number of tagged IGMPv2 general queries sent" - log_test "Vlan 10 mcast_query_interval option changed to 200" + log_test "Number of tagged IGMPv2 general query" + + RET=3D0 + bridge vlan global set vid 10 dev br0 mcast_snooping 1 mcast_igmp_version= 3 + check_err $? "Could not set mcast_igmp_version in vlan 10" + bridge vlan global set vid 10 dev br0 mcast_snooping 1 mcast_mld_version 2 + check_err $? "Could not set mcast_mld_version in vlan 10" + + RET=3D0 + bridge vlan global set vid 10 dev br0 mcast_snooping 1 mcast_query_interv= al 6000 + check_err $? "Could not set mcast_query_interval in vlan 10" + # 1 is sent immediately, IGMPv3 QQIC should match with linear value 60s + vlmc_check_query igmp 3 $swp1 1 1 60 + check_err $? "Wrong QQIC in sent tagged IGMPv3 general queries" + log_test "IGMPv3 QQIC linear value 60" + RET=3D0 + # 1 is sent immediately, MLDv2 QQIC should match with linear value 60s + vlmc_check_query mld 2 $swp1 1 1 60 + check_err $? "Wrong QQIC in sent tagged MLDv2 general queries" + log_test "MLDv2 QQIC linear value 60" =20 + RET=3D0 + bridge vlan global set vid 10 dev br0 mcast_snooping 1 mcast_query_interv= al 16000 + check_err $? "Could not set mcast_query_interval in vlan 10" + # 1 is sent immediately, IGMPv3 QQIC should match with non linear value 1= 60s + vlmc_check_query igmp 3 $swp1 1 1 160 + check_err $? "Wrong QQIC in sent tagged IGMPv3 general queries" + log_test "IGMPv3 QQIC non linear value 160" + RET=3D0 + # 1 is sent immediately, MLDv2 QQIC should match with non linear value 16= 0s + vlmc_check_query mld 2 $swp1 1 1 160 + check_err $? "Wrong QQIC in sent tagged MLDv2 general queries" + log_test "MLDv2 QQIC non linear value 160" + + bridge vlan global set vid 10 dev br0 mcast_snooping 1 mcast_igmp_version= 2 + bridge vlan global set vid 10 dev br0 mcast_snooping 1 mcast_mld_version 1 bridge vlan global set vid 10 dev br0 mcast_snooping 1 mcast_startup_quer= y_count 2 bridge vlan global set vid 10 dev br0 mcast_snooping 1 mcast_query_interv= al 12500 } =20 vlmc_query_response_intvl_test() { + TEST_NAME=3D"vlmc_query_response_intvl_test" + + check_binary "./mc_encode" "$TEST_NAME: verify" || return 1 + RET=3D0 local goutput=3D`bridge -j vlan global show` echo -n $goutput | @@ -468,10 +576,49 @@ vlmc_query_response_intvl_test() log_test "Vlan mcast_query_response_interval global option default value" =20 RET=3D0 - bridge vlan global set vid 10 dev br0 mcast_snooping 1 mcast_query_respon= se_interval 200 + bridge vlan global set vid 10 dev br0 mcast_snooping 1 mcast_startup_quer= y_count 0 + bridge vlan global set vid 10 dev br0 mcast_snooping 1 mcast_igmp_version= 3 + check_err $? "Could not set mcast_igmp_version in vlan 10" + + echo "Vlan 10 mcast_query_response_interval (MRC) test cases:" + RET=3D0 + bridge vlan global set vid 10 dev br0 mcast_snooping 1 mcast_query_respon= se_interval 600 + check_err $? "Could not set mcast_query_response_interval in vlan 10" + # 1 is sent immediately, IGMPv3 MRC should match with linear value 60 uni= ts of 1/10s + vlmc_check_query igmp 3 $swp1 1 1 60 + check_err $? "Wrong MRC in sent tagged IGMPv3 general queries" + log_test "IGMPv3 MRC linear value 60" + + RET=3D0 + bridge vlan global set vid 10 dev br0 mcast_snooping 1 mcast_query_respon= se_interval 1600 + check_err $? "Could not set mcast_query_response_interval in vlan 10" + # 1 is sent immediately, IGMPv3 MRC should match with non linear value 16= 0 unit of 1/10s + vlmc_check_query igmp 3 $swp1 1 1 160 + check_err $? "Wrong MRC in sent tagged IGMPv3 general queries" + log_test "IGMPv3 MRC non linear value 160" + + bridge vlan global set vid 10 dev br0 mcast_snooping 1 mcast_mld_version 2 + check_err $? "Could not set mcast_mld_version in vlan 10" + + RET=3D0 + bridge vlan global set vid 10 dev br0 mcast_snooping 1 mcast_query_respon= se_interval 3000 + check_err $? "Could not set mcast_query_response_interval in vlan 10" + # 1 is sent immediately, MLDv2 MRC should match with linear value 30000(m= s) + vlmc_check_query mld 2 $swp1 1 1 30000 + check_err $? "Wrong MRC in sent tagged MLDv2 general queries" + log_test "MLDv2 MRC linear value 30000" + + RET=3D0 + bridge vlan global set vid 10 dev br0 mcast_snooping 1 mcast_query_respon= se_interval 6000 check_err $? "Could not set mcast_query_response_interval in vlan 10" - log_test "Vlan 10 mcast_query_response_interval option changed to 200" + # 1 is sent immediately, MLDv2 MRC should match with non linear value 600= 00(ms) + vlmc_check_query mld 2 $swp1 1 1 60000 + check_err $? "Wrong MRC in sent tagged MLDv2 general queries" + log_test "MLDv2 MRC non linear value 60000" =20 + bridge vlan global set vid 10 dev br0 mcast_snooping 1 mcast_igmp_version= 2 + bridge vlan global set vid 10 dev br0 mcast_snooping 1 mcast_mld_version 1 + bridge vlan global set vid 10 dev br0 mcast_snooping 1 mcast_startup_quer= y_count 2 bridge vlan global set vid 10 dev br0 mcast_snooping 1 mcast_query_respon= se_interval 1000 } =20 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..2c5e784226e4 --- /dev/null +++ b/tools/testing/selftests/net/forwarding/mc_decode.c @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include +#include + +/* 8-bit floating-point exponential field decode */ +#define FP_8BIT_EXP(value) (((value) >> 4) & 0x07) +#define FP_8BIT_MAN(value) ((value) & 0x0f) + +/* 16-bit floating-point exponential field decode */ +#define FP_16BIT_EXP(value) (((value) >> 12) & 0x0007) +#define FP_16BIT_MAN(value) ((value) & 0x0fff) + +/* 8-bit floating-point exponential field linear threshold */ +#define FP_8BIT_MIN_THRESHOLD 128 +/* 8-bit non linear max representable (mant =3D 0xF, exp =3D 7) -> 31744 */ +#define FP_8BIT_MAX_THRESHOLD 31744 + +/* 16-bit floating-point exponential field linear threshold */ +#define FP_16BIT_MIN_THRESHOLD 32768UL +/* 16-bit non linear max representable (mant =3D 0xFFF, exp =3D 7) -> 8387= 584 */ +#define FP_16BIT_MAX_THRESHOLD 8387584 + +/* This decodes 8-bit floating-point exponential values */ +static inline uint32_t decode_8bit_field(const u8 code) +{ + if (code < FP_8BIT_MIN_THRESHOLD) { + return code; + } else { + uint32_t mc_man, mc_exp; + + mc_exp =3D FP_8BIT_EXP(code); + mc_man =3D FP_8BIT_MAN(code); + return (mc_man | 0x10) << (mc_exp + 3); + } +} + +/* This decodes 16-bit floating-point exponential values */ +static inline uint32_t decode_16bit_field(const uint16_t code) +{ + if (code < FP_16BIT_MIN_THRESHOLD) { + return code; + } else { + uint32_t mc_man, mc_exp; + + mc_exp =3D FP_16BIT_EXP(code); + mc_man =3D FP_16BIT_MAN(code); + + return (mc_man | 0x1000) << (mc_exp + 3); + } +} + +int main(int argc, char *argv[]) +{ + uint32_t bits =3D 8, code =3D 0, decode =3D 0; + + if (argc !=3D 3) + return 1; + + if (bits !=3D 8 && bits !=3D 16) + return 1; + + bits =3D atoi(argv[1]); + code =3D atoi(argv[2]); + + if (bits =3D=3D 8) + decode =3D decode_8bit_field(code); + else + decode =3D decode_16bit_field(code); + printf("%u\n", decode); + + 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..24d9bd9299cc --- /dev/null +++ b/tools/testing/selftests/net/forwarding/mc_encode.c @@ -0,0 +1,78 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include +#include + +/* 8-bit floating-point exponential field linear threshold */ +#define FP_8BIT_MIN_THRESHOLD 128 +/* 8-bit non linear max representable (mant =3D 0xF, exp =3D 7) -> 31744 */ +#define FP_8BIT_MAX_THRESHOLD 31744 + +/* 16-bit floating-point exponential field linear threshold */ +#define FP_16BIT_MIN_THRESHOLD 32768UL +/* 16-bit non linear max representable (mant =3D 0xFFF, exp =3D 7) -> 8387= 584 */ +#define FP_16BIT_MAX_THRESHOLD 8387584 + +/* This encodes value to 8-bit floating-point exponential format */ +static inline uint8_t encode_8bit_field(unsigned int value) +{ + uint8_t mc_exp, mc_man; + + /* Value < 128 is literal */ + if (value < FP_8BIT_MIN_THRESHOLD) + return value; + + /* Saturate at max representable (mant =3D 0xF, exp =3D 7) -> 31744 */ + if (value >=3D FP_8BIT_MAX_THRESHOLD) + return 0xFF; + + mc_exp =3D fls(value) - 8; + mc_man =3D (value >> (mc_exp + 3)) & 0x0F; + + return 0x80 | (mc_exp << 4) | mc_man; +} + +/* This encodes value to 16-bit floating-point exponential format */ +static inline uint16_t encode_16bit_field(unsigned int value) +{ + uint16_t mc_man, mc_exp; + + /* Value < 32768 is literal */ + if (value < FP_16BIT_MIN_THRESHOLD) + return value; + + /* Saturate at max representable (mant =3D 0xFFF, exp =3D 7) -> 8387584 */ + if (value >=3D FP_16BIT_MAX_THRESHOLD) + return 0xFFFF; + + mc_exp =3D fls(value) - 16; + mc_man =3D (value >> (mc_exp + 3)) & 0x0FFF; + + return 0x8000 | (mc_exp << 12) | mc_man; +} + +int main(int argc, char *argv[]) +{ + unsigned int bits =3D 8, value =3D 0; + uint8_t encoded8 =3D 0; + uint16_t encoded16 =3D 0; + + if (argc !=3D 3) + return 1; + + bits =3D atoi(argv[1]); + value =3D atoi(argv[2]); + + if (bits !=3D 8 && bits !=3D 16) + return 1; + + if (bits =3D=3D 8) { + encoded8 =3D encode_8bit_field(value); + printf("%hhu\n", encoded8); + } else { + encoded16 =3D encode_16bit_field(value); + printf("%hu\n", encoded16); + } + + return 0; +} --=20 2.43.0