diff --git a/.github/workflows/kernel-test.yml b/.github/workflows/kernel-test.yml
index 38d2d664..04b8b01b 100644
--- a/.github/workflows/kernel-test.yml
+++ b/.github/workflows/kernel-test.yml
@@ -66,4 +66,5 @@ jobs:
           vmlinuz: '${{ github.workspace }}/vmlinuz'
           kernel-root: '.'
           max-cpu: 8
-          kernel-test: ${{ inputs.test }}
\ No newline at end of file
+          kernel-test: ${{ inputs.test }}
+          toolchain: ${{ inputs.toolchain_full }}
diff --git a/.github/workflows/kernel-veristat.yml b/.github/workflows/kernel-veristat.yml
index 03a3c4dc..f147e07b 100644
--- a/.github/workflows/kernel-veristat.yml
+++ b/.github/workflows/kernel-veristat.yml
@@ -81,6 +81,7 @@ jobs:
           # Don't run meta's veristat from forked repo.
           kernel-test: ${{ github.event.pull_request.head.repo.full_name == github.repository && 'run_veristat_kernel,run_veristat_meta' || 'run_veristat_kernel' }}
           output-dir: '${{ github.workspace }}'
+          toolchain: ${{ inputs.toolchain }}
 
       - name: Compare and save veristat.kernel.csv
         uses: ./.github/actions/veristat_baseline_compare
diff --git a/ci/diffs/0002-selftests-bpf-Add-the-traffic-monitor-option-to-test.patch b/ci/diffs/0002-selftests-bpf-Add-the-traffic-monitor-option-to-test.patch
new file mode 100644
index 00000000..c65f087b
--- /dev/null
+++ b/ci/diffs/0002-selftests-bpf-Add-the-traffic-monitor-option-to-test.patch
@@ -0,0 +1,203 @@
+From d1303b03da0b05b6fdfc273835f8f2b71e30525b Mon Sep 17 00:00:00 2001
+From: Kui-Feng Lee <thinker.li@gmail.com>
+Date: Fri, 26 Jul 2024 13:28:22 -0700
+Subject: [PATCH bpf-next v9 2/6] selftests/bpf: Add the traffic monitor option
+ to test_progs.
+
+Add option '-m' to test_progs to accept names and patterns of test cases.
+This option will be used later to enable traffic monitor that capture
+network packets generated by test cases.
+
+Acked-by: Stanislav Fomichev <sdf@fomichev.me>
+Signed-off-by: Kui-Feng Lee <thinker.li@gmail.com>
+---
+ tools/testing/selftests/bpf/test_progs.c | 86 +++++++++++++++++-------
+ tools/testing/selftests/bpf/test_progs.h |  2 +
+ 2 files changed, 64 insertions(+), 24 deletions(-)
+
+diff --git a/tools/testing/selftests/bpf/test_progs.c b/tools/testing/selftests/bpf/test_progs.c
+index 60fafa2f1ed7..f8ed1a16a884 100644
+--- a/tools/testing/selftests/bpf/test_progs.c
++++ b/tools/testing/selftests/bpf/test_progs.c
+@@ -155,6 +155,7 @@ struct prog_test_def {
+ 	void (*run_serial_test)(void);
+ 	bool should_run;
+ 	bool need_cgroup_cleanup;
++	bool should_tmon;
+ };
+ 
+ /* Override C runtime library's usleep() implementation to ensure nanosleep()
+@@ -192,46 +193,59 @@ static bool should_run(struct test_selector *sel, int num, const char *name)
+ 	return num < sel->num_set_len && sel->num_set[num];
+ }
+ 
+-static bool should_run_subtest(struct test_selector *sel,
+-			       struct test_selector *subtest_sel,
+-			       int subtest_num,
+-			       const char *test_name,
+-			       const char *subtest_name)
++static bool match_subtest(struct test_filter_set *filter,
++			  const char *test_name,
++			  const char *subtest_name)
+ {
+ 	int i, j;
+ 
+-	for (i = 0; i < sel->blacklist.cnt; i++) {
+-		if (glob_match(test_name, sel->blacklist.tests[i].name)) {
+-			if (!sel->blacklist.tests[i].subtest_cnt)
+-				return false;
+-
+-			for (j = 0; j < sel->blacklist.tests[i].subtest_cnt; j++) {
+-				if (glob_match(subtest_name,
+-					       sel->blacklist.tests[i].subtests[j]))
+-					return false;
+-			}
+-		}
+-	}
+-
+-	for (i = 0; i < sel->whitelist.cnt; i++) {
+-		if (glob_match(test_name, sel->whitelist.tests[i].name)) {
+-			if (!sel->whitelist.tests[i].subtest_cnt)
++	for (i = 0; i < filter->cnt; i++) {
++		if (glob_match(test_name, filter->tests[i].name)) {
++			if (!filter->tests[i].subtest_cnt)
+ 				return true;
+ 
+-			for (j = 0; j < sel->whitelist.tests[i].subtest_cnt; j++) {
++			for (j = 0; j < filter->tests[i].subtest_cnt; j++) {
+ 				if (glob_match(subtest_name,
+-					       sel->whitelist.tests[i].subtests[j]))
++					       filter->tests[i].subtests[j]))
+ 					return true;
+ 			}
+ 		}
+ 	}
+ 
++	return false;
++}
++
++static bool should_run_subtest(struct test_selector *sel,
++			       struct test_selector *subtest_sel,
++			       int subtest_num,
++			       const char *test_name,
++			       const char *subtest_name)
++{
++	if (match_subtest(&sel->blacklist, test_name, subtest_name))
++		return false;
++
++	if (match_subtest(&sel->whitelist, test_name, subtest_name))
++		return true;
++
+ 	if (!sel->whitelist.cnt && !subtest_sel->num_set)
+ 		return true;
+ 
+ 	return subtest_num < subtest_sel->num_set_len && subtest_sel->num_set[subtest_num];
+ }
+ 
++static bool should_tmon(struct test_selector *sel, const char *name)
++{
++	int i;
++
++	for (i = 0; i < sel->whitelist.cnt; i++) {
++		if (glob_match(name, sel->whitelist.tests[i].name) &&
++		    !sel->whitelist.tests[i].subtest_cnt)
++			return true;
++	}
++
++	return false;
++}
++
+ static char *test_result(bool failed, bool skipped)
+ {
+ 	return failed ? "FAIL" : (skipped ? "SKIP" : "OK");
+@@ -488,6 +502,10 @@ bool test__start_subtest(const char *subtest_name)
+ 		return false;
+ 	}
+ 
++	subtest_state->should_tmon = match_subtest(&env.tmon_selector.whitelist,
++						   test->test_name,
++						   subtest_name);
++
+ 	env.subtest_state = subtest_state;
+ 	stdio_hijack_init(&subtest_state->log_buf, &subtest_state->log_cnt);
+ 
+@@ -667,7 +685,8 @@ enum ARG_KEYS {
+ 	ARG_TEST_NAME_GLOB_DENYLIST = 'd',
+ 	ARG_NUM_WORKERS = 'j',
+ 	ARG_DEBUG = -1,
+-	ARG_JSON_SUMMARY = 'J'
++	ARG_JSON_SUMMARY = 'J',
++	ARG_TRAFFIC_MONITOR = 'm',
+ };
+ 
+ static const struct argp_option opts[] = {
+@@ -694,6 +713,10 @@ static const struct argp_option opts[] = {
+ 	{ "debug", ARG_DEBUG, NULL, 0,
+ 	  "print extra debug information for test_progs." },
+ 	{ "json-summary", ARG_JSON_SUMMARY, "FILE", 0, "Write report in json format to this file."},
++#ifdef TRAFFIC_MONITOR
++	{ "traffic-monitor", ARG_TRAFFIC_MONITOR, "NAMES", 0,
++	  "Monitor network traffic of tests with name matching the pattern (supports '*' wildcard)." },
++#endif
+ 	{},
+ };
+ 
+@@ -905,6 +928,18 @@ static error_t parse_arg(int key, char *arg, struct argp_state *state)
+ 		break;
+ 	case ARGP_KEY_END:
+ 		break;
++#ifdef TRAFFIC_MONITOR
++	case ARG_TRAFFIC_MONITOR:
++		if (arg[0] == '@')
++			err = parse_test_list_file(arg + 1,
++						   &env->tmon_selector.whitelist,
++						   true);
++		else
++			err = parse_test_list(arg,
++					      &env->tmon_selector.whitelist,
++					      true);
++		break;
++#endif
+ 	default:
+ 		return ARGP_ERR_UNKNOWN;
+ 	}
+@@ -1736,6 +1771,8 @@ int main(int argc, char **argv)
+ 				test->test_num, test->test_name, test->test_name, test->test_name);
+ 			exit(EXIT_ERR_SETUP_INFRA);
+ 		}
++		if (test->should_run)
++			test->should_tmon = should_tmon(&env.tmon_selector, test->test_name);
+ 	}
+ 
+ 	/* ignore workers if we are just listing */
+@@ -1820,6 +1857,7 @@ int main(int argc, char **argv)
+ 
+ 	free_test_selector(&env.test_selector);
+ 	free_test_selector(&env.subtest_selector);
++	free_test_selector(&env.tmon_selector);
+ 	free_test_states();
+ 
+ 	if (env.succ_cnt + env.fail_cnt + env.skip_cnt == 0)
+diff --git a/tools/testing/selftests/bpf/test_progs.h b/tools/testing/selftests/bpf/test_progs.h
+index cb9d6d46826b..966011eb7ec8 100644
+--- a/tools/testing/selftests/bpf/test_progs.h
++++ b/tools/testing/selftests/bpf/test_progs.h
+@@ -74,6 +74,7 @@ struct subtest_state {
+ 	int error_cnt;
+ 	bool skipped;
+ 	bool filtered;
++	bool should_tmon;
+ 
+ 	FILE *stdout_saved;
+ };
+@@ -98,6 +99,7 @@ struct test_state {
+ struct test_env {
+ 	struct test_selector test_selector;
+ 	struct test_selector subtest_selector;
++	struct test_selector tmon_selector;
+ 	bool verifier_stats;
+ 	bool debug;
+ 	enum verbosity verbosity;
+-- 
+2.34.1
+
diff --git a/ci/vmtest/configs/TMONLIST b/ci/vmtest/configs/TMONLIST
new file mode 100644
index 00000000..8c3baa08
--- /dev/null
+++ b/ci/vmtest/configs/TMONLIST
@@ -0,0 +1,3 @@
+select_reuseport
+sockmap_listen
+tc_redirect
diff --git a/ci/vmtest/vmtest_selftests.sh b/ci/vmtest/vmtest_selftests.sh
index e4e368b8..49fbe75e 100755
--- a/ci/vmtest/vmtest_selftests.sh
+++ b/ci/vmtest/vmtest_selftests.sh
@@ -21,6 +21,8 @@ OUTPUT_DIR=/mnt/vmtest
 WORKING_DIR="/${PROJECT_NAME}"
 BPF_SELFTESTS_DIR="${WORKING_DIR}/selftests/bpf"
 VMTEST_CONFIGS_PATH="${WORKING_DIR}/ci/vmtest/configs"
+PKG_CONFIG=pkg-config
+TMON_DIR=/tmp/tmon_pcap
 
 read_lists() {
 	(for path in "$@"; do
@@ -44,6 +46,16 @@ ALLOWLIST=$(read_lists \
 	"$VMTEST_CONFIGS_PATH/ALLOWLIST.${ARCH}" \
 )
 
+TMONLIST=""
+if ${PKG_CONFIG} --exists libpcap 2>/dev/null; then
+    TMONLIST=$(read_lists \
+	           "$BPF_SELFTESTS_DIR/TMONLIST" \
+	           "$BPF_SELFTESTS_DIR/TMONLIST.${ARCH}" \
+	           "$VMTEST_CONFIGS_PATH/TMONLIST" \
+	           "$VMTEST_CONFIGS_PATH/TMONLIST.${ARCH}" \
+            )
+fi
+
 declare -a TEST_NAMES=()
 
 read_test_names() {
@@ -83,7 +95,7 @@ test_progs_helper() {
   # "&& true" does not change the return code (it is not executed
   # if the Python script fails), but it prevents exiting on a
   # failure due to the "set -e".
-  ./${selftest} ${args} ${DENYLIST:+-d"$DENYLIST"} ${ALLOWLIST:+-a"$ALLOWLIST"} --json-summary "${json_file}" && true
+  ./${selftest} ${args} ${DENYLIST:+-d"$DENYLIST"} ${ALLOWLIST:+-a"$ALLOWLIST"} ${TMONLIST:+-m"$TMONLIST"} --json-summary "${json_file}" && true
   echo "${selftest}:$?" >>"${STATUS_FILE}"
   foldable end ${selftest}
 }
@@ -175,9 +187,14 @@ foldable end kernel_config
 
 echo "DENYLIST: ${DENYLIST}"
 echo "ALLOWLIST: ${ALLOWLIST}"
+echo "TMONLIST: ${TMONLIST}"
 
 cd ${PROJECT_NAME}/selftests/bpf
 
+if [ -d "${TMON_DIR}" ]; then
+    rm -rf "${TMON_DIR}"
+fi
+
 # populate TEST_NAMES
 read_test_names "$@"
 # if we don't have any test name provided to the script, we run all tests.
@@ -194,3 +211,8 @@ else
 		"${test_name}"
 	done
 fi
+
+if [ -d "${TMON_DIR}" ]; then
+    rm -rf "${OUTPUT_DIR}/tmon-logs"
+    mv "${TMON_DIR}" "${OUTPUT_DIR}/tmon-logs"
+fi