public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
From: Ujjal Roy <royujjal@gmail.com>
To: "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>,
	Nikolay Aleksandrov <razor@blackwall.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: [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	[thread overview]
Message-ID: <20260330191611.16929-6-royujjal@gmail.com> (raw)
In-Reply-To: <20260330191611.16929-1-royujjal@gmail.com>

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 <royujjal@gmail.com>
---
 .../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/testing/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/testing/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
 
+top_srcdir = ../../../../..
+
+CFLAGS += -Wall -Wl,--no-as-needed -O2 -g -I$(top_srcdir)/usr/include $(KHDR_INCLUDES)
+CFLAGS += -I$(top_srcdir)/tools/include
+
+TEST_GEN_FILES := \
+	mc_encode \
+	mc_decode \
+# end of TEST_GEN_FILES
+
 TEST_PROGS := \
 	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
 
 ALL_TESTS="
+	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
 
 	ip link del dev br0
 }
@@ -116,6 +119,112 @@ cleanup()
 	vrf_cleanup
 }
 
+check_binary()
+{
+	local cmd=$1; shift
+	local args=$@
+
+	if [[ ! -x "$(command -v "$cmd")" ]]; then
+		log_test_skip "$args $cmd not found"
+		return $EXIT_STATUS
+	fi
+}
+
+tcpdump_show_with_filter()
+{
+	local if_name=$1; shift
+	local filter=$@
+
+	tcpdump -e -n -r ${capfile[$if_name]} "$filter" 2>&1
+}
+
+validate_query()
+{
+	local if_name=$1; shift
+	local test="$1"; shift
+	local value="$1"; shift
+	local pattern=""
+	local field_val=""
+	local pos=""
+	local msg="IGMPv3 query: verify $test"
+	check_command tshark || return 1
+	check_binary "./mc_encode" $msg || return 1
+
+	if [ "$test" = "MRC" ]; then
+		pos=1 # MRC field offset within IGMP header
+		field_val=$(tshark -r ${capfile[$if_name]} -Y "igmp.type==0x11" \
+			   -V 2>/dev/null | grep "Max Resp Time")
+	elif [ "$test" = "QQIC" ]; then
+		pos=9 # QQIC field offset within IGMP header
+		field_val=$(tshark -r ${capfile[$if_name]} -Y "igmp.type==0x11" \
+			   -V 2>/dev/null | grep "QQIC")
+	fi
+
+	local enc_val=$(./mc_encode $value)
+	pattern="ip proto 2 and igmp[0] == 0x11 and igmp[$pos] == $enc_val"
+	local opt_str=""
+	tcpdump_show_with_filter $if_name $pattern | grep -q "igmp query v3"
+	ret=$?
+	if [ "$field_val" != "" -a $ret -ne 0 ]; then
+		opt_str="Bad $test value in IGMP packet: $field_val"
+	fi
+	check_err $ret "$opt_str"
+
+	log_test "$msg" "configured=$value, expected=$enc_val"
+}
+
+v3query_mrc_test()
+{
+	RET=0
+	local qri_val=160
+	local br_qri=$((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=0
+	local qqi_val=160
+	local br_qqi=$((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=0
diff --git a/tools/testing/selftests/net/forwarding/mc_decode.c b/tools/testing/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 <stdio.h>
+#include <stdlib.h>
+#include <linux/bitops.h>
+
+#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 = IGMPV3_FP_EXP(code);
+        mc_man = IGMPV3_FP_MAN(code);
+        return ((mc_man | 0x10) << (mc_exp + 3));
+    }
+}
+
+int main(int argc, char *argv[])
+{
+    uint8_t qqic = 0;
+    if (argc >= 2)
+        qqic = atoi(argv[1]);
+    unsigned long qqi = decode_field(qqic);
+
+    printf("%lu\n", qqi);
+
+    return 0;
+}
diff --git a/tools/testing/selftests/net/forwarding/mc_encode.c b/tools/testing/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 <stdio.h>
+#include <stdlib.h>
+#include <linux/bitops.h>
+
+/* IGMPV3 floating-point exponential field threshold */
+#define IGMPV3_EXP_MIN_THRESHOLD        128
+/* Max representable (mant = 0xF, exp = 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 = 0xF, exp = 7) -> 31744 */
+    if (value >= IGMPV3_EXP_MAX_THRESHOLD)
+        return 0xFF;
+
+    mc_exp  = (uint8_t)(fls(value) - 8);
+    mc_man = (uint8_t)((value >> (mc_exp + 3)) & 0x0F);
+
+    return 0x80 | (mc_exp << 4) | mc_man;
+}
+
+int main(int argc, char *argv[])
+{
+    unsigned int qqi = 0;
+    if (argc >= 2)
+        qqi = atoi(argv[1]);
+
+    uint8_t qqic = encode_field(qqi);
+
+    printf("%u\n", qqic);
+
+    return 0;
+}
-- 
2.43.0


  parent reply	other threads:[~2026-03-30 19:17 UTC|newest]

Thread overview: 26+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-03-26 15:07 [PATCH 0/4] net: bridge: mcast: add multicast exponential field encoding Ujjal Roy
2026-03-26 15:07 ` [PATCH 1/4] ipv4: igmp: get rid of IGMPV3_{QQIC,MRC} and simplify calculation Ujjal Roy
2026-03-26 15:07 ` [PATCH 2/4] ipv6: mld: rename mldv2_mrc() and add mldv2_qqi() Ujjal Roy
2026-03-27 15:49   ` kernel test robot
2026-03-26 15:07 ` [PATCH 3/4] ipv4: igmp: encode multicast exponential fields Ujjal Roy
2026-03-27 12:19   ` Nikolay Aleksandrov
2026-03-30 19:16     ` [PATCH net-next v2 0/5] net: bridge: mcast: add multicast exponential field encoding Ujjal Roy
2026-03-30 19:16       ` [PATCH net-next v2 1/5] ipv4: igmp: get rid of IGMPV3_{QQIC,MRC} and simplify calculation Ujjal Roy
2026-04-01  7:25         ` Ido Schimmel
2026-03-30 19:16       ` [PATCH net-next v2 2/5] ipv6: mld: rename mldv2_mrc() and add mldv2_qqi() Ujjal Roy
2026-04-01  7:26         ` Ido Schimmel
2026-03-30 19:16       ` [PATCH net-next v2 3/5] ipv4: igmp: encode multicast exponential fields Ujjal Roy
2026-04-01  7:27         ` Ido Schimmel
2026-03-30 19:16       ` [PATCH net-next v2 4/5] ipv6: mld: " Ujjal Roy
2026-04-01  7:29         ` Ido Schimmel
2026-03-30 19:16       ` Ujjal Roy [this message]
2026-03-31 14:13         ` [PATCH net-next v2 5/5] selftests: net: bridge: add tests for igmpv3 MRC and QQIC validation Ido Schimmel
2026-04-03  7:50           ` Ujjal Roy
2026-04-03 10:19             ` Ido Schimmel
2026-04-03 10:31               ` Ujjal Roy
2026-03-30 19:39       ` [PATCH net-next v2 0/5] net: bridge: mcast: add multicast exponential field encoding Ujjal Roy
2026-03-31 14:16       ` Ido Schimmel
2026-04-04 17:25         ` Ujjal Roy
2026-03-26 15:07 ` [PATCH 4/4] ipv6: mld: encode multicast exponential fields Ujjal Roy
2026-03-27  6:41 ` [PATCH 0/4] net: bridge: mcast: add multicast exponential field encoding Nikolay Aleksandrov
2026-03-27 11:31   ` Nikolay Aleksandrov

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=20260330191611.16929-6-royujjal@gmail.com \
    --to=royujjal@gmail.com \
    --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=razor@blackwall.org \
    --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