[PATCH net-next v2 5/5] selftests: net: bridge: add tests for igmpv3 MRC and QQIC validation

Ujjal Roy posted 5 patches 5 days, 17 hours ago
[PATCH net-next v2 5/5] selftests: net: bridge: add tests for igmpv3 MRC and QQIC validation
Posted by Ujjal Roy 5 days, 17 hours ago
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
Re: [PATCH net-next v2 5/5] selftests: net: bridge: add tests for igmpv3 MRC and QQIC validation
Posted by Ido Schimmel 4 days, 22 hours ago
On Mon, Mar 30, 2026 at 07:16:11PM +0000, Ujjal Roy wrote:
> 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.

Please cover both IGMPv3 and MLDv2 since the patchset touches both. You
can add the MLDv2 tests in bridge_mld.sh.

Also, I think you can simplify the test by simply matching on the
expected values of MRC and QQIC using tc-u32.

For both IGMPv3 and MLDv2 please test both:

* MRC and QQIC in linear range.
* MRC and QQIC in non-linear range.

And please make sure the new test cases don't add new shellcheck
warnings / errors or it will fail in the CI. You can ignore existing
ones.
Re: [PATCH net-next v2 5/5] selftests: net: bridge: add tests for igmpv3 MRC and QQIC validation
Posted by Ujjal Roy 2 days, 5 hours ago
On Tue, Mar 31, 2026 at 7:44 PM Ido Schimmel <idosch@nvidia.com> wrote:
>
> On Mon, Mar 30, 2026 at 07:16:11PM +0000, Ujjal Roy wrote:
> > 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.
>
> Please cover both IGMPv3 and MLDv2 since the patchset touches both. You
> can add the MLDv2 tests in bridge_mld.sh.
>
> Also, I think you can simplify the test by simply matching on the
> expected values of MRC and QQIC using tc-u32.
>
> For both IGMPv3 and MLDv2 please test both:
>
> * MRC and QQIC in linear range.
> * MRC and QQIC in non-linear range.
>
> And please make sure the new test cases don't add new shellcheck
> warnings / errors or it will fail in the CI. You can ignore existing
> ones.

I will upgrade the existing test cases in file bridge_vlan_mcast.sh
instead of the previous file (bridge_igmp/mld.sh).

I have some doubts on test case logs reporting. Below are the logs
without my patchset. API used vlmc_query_intvl_test() and
vlmc_query_response_intvl_test().
TEST: Vlan mcast_query_interval global option default value         [ OK ]
TEST: Vlan 10 mcast_query_interval option changed to 200            [ OK ]
TEST: Vlan mcast_query_response_interval global option default value   [ OK ]
TEST: Vlan 10 mcast_query_response_interval option changed to 200   [ OK ]

I am expecting some suggestions from the logs below. And are these
covers both IGMPv3 and MLDv2 for QQIC and MRC?
Actually mcast_query_interval=QQIC and
mcast_query_response_interval=MRC we already know.

TEST: Vlan mcast_query_interval global option default value         [ OK ]
TEST: Vlan 10 mcast_query_interval option changed to 200            [ OK ]
TEST: Vlan 10 mcast_query_interval number of IGMPv2 general query   [
OK ] -> old case added log
TEST: Vlan 10 mcast_query_interval option changed to 6000           [ OK ]
TEST: Vlan 10 mcast_query_interval in IGMPv3 is 60                  [ OK ]
TEST: Vlan 10 mcast_query_interval in MLDv2 is 60                   [ OK ]
TEST: Vlan 10 mcast_query_interval option changed to 16000          [ OK ]
TEST: Vlan 10 mcast_query_interval in IGMPv3 is 160                 [ OK ]
TEST: Vlan 10 mcast_query_interval in MLDv2 is 160                  [ OK ]
TEST: Vlan mcast_query_response_interval global option default value   [ OK ]
TEST: Vlan 10 mcast_query_response_interval option changed to 600   [ OK ]
TEST: Vlan 10 mcast_query_response_interval in IGMPv3 is 60         [ OK ]
TEST: Vlan 10 mcast_query_response_interval option changed to 1600   [ OK ]
TEST: Vlan 10 mcast_query_response_interval in IGMPv3 is 160        [ OK ]
TEST: Vlan 10 mcast_query_response_interval option changed to 3000   [ OK ]
TEST: Vlan 10 mcast_query_response_interval in MLDv2 is 30000       [ OK ]
TEST: Vlan 10 mcast_query_response_interval option changed to 6000   [ OK ]
TEST: Vlan 10 mcast_query_response_interval in MLDv2 is 60000       [ OK ]

Or is it better to name them properly instead of mcast option names, like below?

Vlan 10 mcast_query_interval:
TEST: Number of tagged IGMPv2 general query                         [ OK ]
TEST: IGMPv3 QQIC linear value 60                                   [ OK ]
TEST: IGMPv3 QQIC non linear value 160                              [ OK ]
TEST: MLDv2 QQIC linear value 60                                    [ OK ]
TEST: MLDv2 QQIC non linear value 160                               [ OK ]
Re: [PATCH net-next v2 5/5] selftests: net: bridge: add tests for igmpv3 MRC and QQIC validation
Posted by Ido Schimmel 2 days, 2 hours ago
On Fri, Apr 03, 2026 at 01:20:49PM +0530, Ujjal Roy wrote:
> On Tue, Mar 31, 2026 at 7:44 PM Ido Schimmel <idosch@nvidia.com> wrote:
> >
> > On Mon, Mar 30, 2026 at 07:16:11PM +0000, Ujjal Roy wrote:
> > > 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.
> >
> > Please cover both IGMPv3 and MLDv2 since the patchset touches both. You
> > can add the MLDv2 tests in bridge_mld.sh.
> >
> > Also, I think you can simplify the test by simply matching on the
> > expected values of MRC and QQIC using tc-u32.
> >
> > For both IGMPv3 and MLDv2 please test both:
> >
> > * MRC and QQIC in linear range.
> > * MRC and QQIC in non-linear range.
> >
> > And please make sure the new test cases don't add new shellcheck
> > warnings / errors or it will fail in the CI. You can ignore existing
> > ones.
> 
> I will upgrade the existing test cases in file bridge_vlan_mcast.sh
> instead of the previous file (bridge_igmp/mld.sh).

Is there a reason to place them in bridge_vlan_mcast.sh given they are
not specific to the per-VLAN multicast context? bridge_{igmp,mld}.sh
looks like a better fit.

> 
> I have some doubts on test case logs reporting. Below are the logs
> without my patchset. API used vlmc_query_intvl_test() and
> vlmc_query_response_intvl_test().
> TEST: Vlan mcast_query_interval global option default value         [ OK ]
> TEST: Vlan 10 mcast_query_interval option changed to 200            [ OK ]
> TEST: Vlan mcast_query_response_interval global option default value   [ OK ]
> TEST: Vlan 10 mcast_query_response_interval option changed to 200   [ OK ]
> 
> I am expecting some suggestions from the logs below. And are these
> covers both IGMPv3 and MLDv2 for QQIC and MRC?
> Actually mcast_query_interval=QQIC and
> mcast_query_response_interval=MRC we already know.

Not sure what you are asking. My request was to have test cases for both
MRC and QQIC, for both IGMPv3 and MLDv2.

> 
> TEST: Vlan mcast_query_interval global option default value         [ OK ]
> TEST: Vlan 10 mcast_query_interval option changed to 200            [ OK ]
> TEST: Vlan 10 mcast_query_interval number of IGMPv2 general query   [
> OK ] -> old case added log
> TEST: Vlan 10 mcast_query_interval option changed to 6000           [ OK ]
> TEST: Vlan 10 mcast_query_interval in IGMPv3 is 60                  [ OK ]
> TEST: Vlan 10 mcast_query_interval in MLDv2 is 60                   [ OK ]
> TEST: Vlan 10 mcast_query_interval option changed to 16000          [ OK ]
> TEST: Vlan 10 mcast_query_interval in IGMPv3 is 160                 [ OK ]
> TEST: Vlan 10 mcast_query_interval in MLDv2 is 160                  [ OK ]
> TEST: Vlan mcast_query_response_interval global option default value   [ OK ]
> TEST: Vlan 10 mcast_query_response_interval option changed to 600   [ OK ]
> TEST: Vlan 10 mcast_query_response_interval in IGMPv3 is 60         [ OK ]
> TEST: Vlan 10 mcast_query_response_interval option changed to 1600   [ OK ]
> TEST: Vlan 10 mcast_query_response_interval in IGMPv3 is 160        [ OK ]
> TEST: Vlan 10 mcast_query_response_interval option changed to 3000   [ OK ]
> TEST: Vlan 10 mcast_query_response_interval in MLDv2 is 30000       [ OK ]
> TEST: Vlan 10 mcast_query_response_interval option changed to 6000   [ OK ]
> TEST: Vlan 10 mcast_query_response_interval in MLDv2 is 60000       [ OK ]
> 
> Or is it better to name them properly instead of mcast option names, like below?
> 
> Vlan 10 mcast_query_interval:
> TEST: Number of tagged IGMPv2 general query                         [ OK ]
> TEST: IGMPv3 QQIC linear value 60                                   [ OK ]
> TEST: IGMPv3 QQIC non linear value 160                              [ OK ]
> TEST: MLDv2 QQIC linear value 60                                    [ OK ]
> TEST: MLDv2 QQIC non linear value 160                               [ OK ]

I find the latter clearer.
Re: [PATCH net-next v2 5/5] selftests: net: bridge: add tests for igmpv3 MRC and QQIC validation
Posted by Ujjal Roy 2 days, 2 hours ago
On Fri, Apr 3, 2026 at 3:49 PM Ido Schimmel <idosch@nvidia.com> wrote:
>
[...]
>
> Is there a reason to place them in bridge_vlan_mcast.sh given they are
> not specific to the per-VLAN multicast context? bridge_{igmp,mld}.sh
> looks like a better fit.

I could see the framework is ready to validate using
bridge_vlan_mcast.sh script. Just had to apply a new tc rule to
validate QEURY+MRC/QQIC fields. Something like this.

                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

And writing a few lines will validate the test for IGMPv3 QQIC non
linear value of 160s.
+       RET=0
+       bridge vlan global set vid 10 dev br0 mcast_snooping 1
mcast_query_interval 16000
+       check_err $? "Could not set mcast_query_interval in vlan 10"
+       log_test "Vlan 10 mcast_query_interval option changed to 16000"
+       # 1 is sent immediately, IGMPv3 QQIC should match with non
linear value 160s
+       vlmc_check_query igmp 3 $swp1 1 1 160
+       check_err $? "Wrong QQIC in sent tagged IGMPv3 general queries"
+       log_test "Vlan 10 mcast_query_interval in IGMPv3 is 160"

>
[...]
> > Vlan 10 mcast_query_interval:
> > TEST: Number of tagged IGMPv2 general query                         [ OK ]
> > TEST: IGMPv3 QQIC linear value 60                                   [ OK ]
> > TEST: IGMPv3 QQIC non linear value 160                              [ OK ]
> > TEST: MLDv2 QQIC linear value 60                                    [ OK ]
> > TEST: MLDv2 QQIC non linear value 160                               [ OK ]
>
> I find the latter clearer.

I thought so, hence asked which would be a better version of log.
Thanks for clearing it.