From nobody Wed May 20 20:58:55 2026 X-Original-To: dev-commits-src-all@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4gLP681g5Pz6fPpB for ; Wed, 20 May 2026 20:58:56 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R13" (not verified)) by mx1.freebsd.org (Postfix) with ESMTPS id 4gLP675MV0z41kM for ; Wed, 20 May 2026 20:58:55 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1779310735; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=Wb7aN7f/xkB+Z0B/4iQZggwes+oiKLkAoi9rgNz+P/U=; b=yye+0OWjVVg5GoalRcbc3+xN4YxFDGDBS4KL5SjExvdX382V/XBQ+TzbvG/YL2YrGESaXo N/c2gQ6LpjlRqduHiBBApebzX2XcoOSCll2PYC9FonNJrzQgnfFssakj1vaWgacIjwnE2d EN/x8tKAJQUjZnUD4K8G7moubXmjXTo2OJBqlkhguhrRTx5DLIw0YDLbB3T32u2nCoVGBY kRJQYdVkz5XwmUtEz/x8k08a5QD7iMl1p6gz13kpqfGWufZEMtKTjxTHnECQaEOpp/PYTE l29TOCEkBFL8HneRfluSKEoDE+Go3ygBnYFALIf77qnuLiRZa8Rh0DemzTOY6w== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1779310735; a=rsa-sha256; cv=none; b=RL2hUIBT95Pd9gLulMqzg+vz8Tu43ZQS8Kdy1o36Y/jh2v0cTKM0VaM8FOE53nhd5QCm38 ES3kvnOFlBRDYMzIjDyi68T9a3e9/zFhgqsLcLlgeqhQ1tYQfFFBX5AdNIVOzj2lUTBVSO buUBxwYJFPuxcVRv/e9ZAdLjMI8JSTLUPNOifVGwiHHczHVhqL58wwsfeu8B4mfKu1KJyT XjxTtoZMP2L0Z3GHCWTf0dOtDSktMJ+ROVobjdZSb4JMainH9JLv/zgonVmUo0p1Td4WzS KNNNy8m1qHxx9xHk7irO3ODc/9K9AQ8pmecuA5DbNdymklYBXp+UI/7uv7ylfA== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1779310735; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=Wb7aN7f/xkB+Z0B/4iQZggwes+oiKLkAoi9rgNz+P/U=; b=quOadhl7SCCfIq7fvt93ZIn5V8iCh9YkJkvIKeP9DM9zEEFeAwXYKlfKHygBYca5qlx5KT H/jl4t6+tEot2ZMXTD7AWuTWf4cRa6hIINoi2dxsDYuCRW4r3pRRqiO0R03WM2cZPc05Lu rtXwbVzUYpTvxzJap1NXjHjkEPvfO5wWR1ON1BKzzcsKXKjtwcAjd7TqOX3ElBqH1ewMsq 8KaABio/dsL09RtM8jqDScWKR92tEASq35LTKJQz9MCWj0EYlad5VzLqOQloe7boLWBgkh acblvcXRI4yvj1YMUxsNpHkT3Jeshd5UhRAj/BzD3qQb5dbz6qzyjzmX5w4tfA== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4gLP674nSmz1Gy2 for ; Wed, 20 May 2026 20:58:55 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 40227 by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Wed, 20 May 2026 20:58:55 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Pouria Mousavizadeh Tehrani Subject: git: bc301fee4cb2 - main - routing: Add tests for metric List-Id: Commit messages for all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-all@freebsd.org Sender: owner-dev-commits-src-all@FreeBSD.org List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: pouria X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: bc301fee4cb2c3e9ce220dc3e0cbb9d7d5a83d6f Auto-Submitted: auto-generated Date: Wed, 20 May 2026 20:58:55 +0000 Message-Id: <6a0e208f.40227.6189aa08@gitrepo.freebsd.org> The branch main has been updated by pouria: URL: https://cgit.FreeBSD.org/src/commit/?id=bc301fee4cb2c3e9ce220dc3e0cbb9d7d5a83d6f commit bc301fee4cb2c3e9ce220dc3e0cbb9d7d5a83d6f Author: Pouria Mousavizadeh Tehrani AuthorDate: 2026-05-15 14:03:37 +0000 Commit: Pouria Mousavizadeh Tehrani CommitDate: 2026-05-20 20:55:11 +0000 routing: Add tests for metric Add tests to make sure: * Default metric is enforced. * Lowest metric wins. * Deleting routes by specifying gateway/metric works. Reviewed by: markj Differential Revision: https://reviews.freebsd.org/D57016 --- tests/sys/net/routing/Makefile | 3 + tests/sys/net/routing/test_routing.sh | 231 ++++++++++++++++++++++++++++++++++ 2 files changed, 234 insertions(+) diff --git a/tests/sys/net/routing/Makefile b/tests/sys/net/routing/Makefile index c725d23f15d1..cbb00a236871 100644 --- a/tests/sys/net/routing/Makefile +++ b/tests/sys/net/routing/Makefile @@ -8,6 +8,7 @@ ATF_TESTS_C += test_rtsock_lladdr ATF_TESTS_C += test_rtsock_ops ATF_TESTS_PYTEST += test_routing_l3.py ATF_TESTS_PYTEST += test_rtsock_multipath.py +ATF_TESTS_SH+= test_routing ${PACKAGE}FILES+= generic_cleanup.sh ${PACKAGE}FILESMODE_generic_cleanup.sh=0555 @@ -15,6 +16,8 @@ ${PACKAGE}FILESMODE_generic_cleanup.sh=0555 # Most of the tests operates on a common IPv4/IPv6 prefix, # so running them in parallel will lead to weird results. TEST_METADATA+= is_exclusive=true +TEST_METADATA.test_routing+= execenv="jail" \ + execenv_jail_params="vnet" CFLAGS+= -I${.CURDIR:H:H:H} diff --git a/tests/sys/net/routing/test_routing.sh b/tests/sys/net/routing/test_routing.sh new file mode 100755 index 000000000000..296bd7ebaffd --- /dev/null +++ b/tests/sys/net/routing/test_routing.sh @@ -0,0 +1,231 @@ +# +# Copyright (c) 2026 Pouria Mousavizadeh Tehrani +# +# SPDX-License-Identifier: BSD-2-Clause +# + +. $(atf_get_srcdir)/../../common/vnet.subr + +jq_rtentry() +{ + local route="$1" + + jq -r '.statistics."route-information"."route-table"."rt-family".[]."rt-entry".[] | + select(.destination == "'${route}'")' +} + +jq_nhop_filter() +{ + local nhop="$1" + local weight="$2" + local metric="$3" + + jq -r 'select(.gateway == "'${nhop}'") | + select(.weight == '${weight}') | + select(.metric == '${metric}') | + .gateway' +} + + +atf_test_case "add_lowest_metric" "cleanup" +add_lowest_metric_head() +{ + atf_set descr 'Create 4 routes to same dst and verify the lowest metric wins' + atf_set require.user root + atf_set require.progs jq +} + +add_lowest_metric_body() +{ + local epair laddr route nhop1 nhop2 nhop3 + + laddr="3fff::1" + route="3fff:a::" + nhop1="3fff::1" + nhop2="3fff::2" + nhop3="3fff::3" + + vnet_init + epair=$(vnet_mkepair) + + atf_check -o ignore \ + ifconfig ${epair}a inet6 ${laddr} up + + # Create an ECMP route with metric 2 + atf_check -o ignore \ + route -6 add -net ${route}/64 -gateway ${nhop2} -weight 10 -metric 2 + atf_check -o ignore \ + route -6 add -net ${route}/64 -gateway ${nhop3} -weight 10 -metric 2 + + # Validate routes + atf_check -o save:netstat \ + netstat -rn6 --libxo json + output=$(cat netstat | jq_rtentry ${route}/64 | jq_nhop_filter ${nhop2} 10 2) + atf_check_equal "$output" "$nhop2" + output=$(cat netstat | jq_rtentry ${route}/64 | jq_nhop_filter ${nhop3} 10 2) + atf_check_equal "$output" "$nhop3" + + # Create a route with metric 3 + atf_check -o ignore \ + route -6 add -net ${route}/64 -gateway ${nhop1} -metric 3 + # Verify that nhop1 is not the best route + atf_check -o not-match:".*gateway: ${nhop1}.*" \ + route -n6 get -net ${route}/64 + + # Create a route to the same nhop with same metric 3 and verify it fails + atf_check -s exit:1 -o ignore -e match:".*exists.*" \ + route -6 add -net ${route}/64 -gateway ${nhop1} -metric 3 + + # Create a route to an existing nhop with lower metric + atf_check -o ignore \ + route -6 add -net ${route}/64 -gateway ${nhop1} -metric 1 + # Verify that nhop1 is now the best route + atf_check -o match:".*gateway: ${nhop1}.*" \ + route -n6 get -net ${route}/64 +} + +add_lowest_metric_cleanup() +{ + vnet_cleanup +} + +atf_test_case "add_default_metric" "cleanup" +add_default_metric_head() +{ + atf_set descr 'Create a route and verify the default metric is set' + atf_set require.user root + atf_set require.progs jq +} + +add_default_metric_body() +{ + local epair laddr route nhop1 + + laddr="3fff::1" + route="3fff:a::" + nhop1="3fff::1" + + vnet_init + epair=$(vnet_mkepair) + + atf_check -o ignore \ + ifconfig ${epair}a inet6 ${laddr} up + + # Create a route without specifying its metric + atf_check -o ignore \ + route -6 add -net ${route}/64 -gateway ${nhop1} + + # Verify the route has the default metric of 1 + atf_check -o save:netstat \ + netstat -rn6 --libxo json + output=$(cat netstat | jq_rtentry ${route}/64 | jq_nhop_filter ${nhop1} 1 1) + atf_check_equal "$output" "$nhop1" +} + +add_default_metric_cleanup() +{ + vnet_cleanup +} + +atf_test_case "delete_route_with_metric" "cleanup" +delete_route_with_metric_head() +{ + atf_set descr 'Create multiple routes to same dst and delete routes with specific metric' + atf_set require.user root + atf_set require.progs jq +} + +delete_route_with_metric_body() +{ + local epair laddr route nhop1 nhop2 + + laddr="3fff::1" + route="3fff:a::" + nhop1="3fff::1" + nhop2="3fff::2" + + vnet_init + epair=$(vnet_mkepair) + + atf_check -o ignore \ + ifconfig ${epair}a inet6 ${laddr} up + + # Create two groups of ECMP routes with metric 2 and 3, and + # another route with metric 4. + atf_check -o ignore \ + route -6 add -net ${route}/64 -gateway ${nhop1} -metric 3 + atf_check -o ignore \ + route -6 add -net ${route}/64 -gateway ${nhop1} -weight 10 -metric 2 + atf_check -o ignore \ + route -6 add -net ${route}/64 -gateway ${nhop2} -weight 10 -metric 2 + atf_check -o ignore \ + route -6 add -net ${route}/64 -gateway ${nhop2} -metric 3 + atf_check -o ignore \ + route -6 add -net ${route}/64 -gateway ${nhop2} -metric 4 + + # Validate we have 5 routes + atf_check -o save:netstat \ + netstat -rn6 --libxo json + output=$(cat netstat | jq_rtentry ${route}/64 | jq_nhop_filter ${nhop1} 1 3) + atf_check_equal "$output" "$nhop1" + output=$(cat netstat | jq_rtentry ${route}/64 | jq_nhop_filter ${nhop1} 10 2) + atf_check_equal "$output" "$nhop1" + output=$(cat netstat | jq_rtentry ${route}/64 | jq_nhop_filter ${nhop2} 10 2) + atf_check_equal "$output" "$nhop2" + output=$(cat netstat | jq_rtentry ${route}/64 | jq_nhop_filter ${nhop2} 1 3) + atf_check_equal "$output" "$nhop2" + output=$(cat netstat | jq_rtentry ${route}/64 | jq_nhop_filter ${nhop2} 1 4) + atf_check_equal "$output" "$nhop2" + + # Delete one of the nexthops of them best ECMP route + # Test that deleting a route by specifying gateway + metric works. + atf_check -o ignore \ + route -n6 delete -net ${route}/64 -gateway ${nhop2} -metric 2 + + # Verify that nhop1 is the best route now + atf_check -o match:".*gateway: ${nhop1}.*" \ + route -n6 get -net ${route}/64 + + # But other route with nhops2 should exists. + atf_check -o save:netstat \ + netstat -rn6 --libxo json + output=$(cat netstat | jq_rtentry ${route}/64 | jq_nhop_filter ${nhop2} 1 3) + atf_check_equal "$output" "$nhop2" + output=$(cat netstat | jq_rtentry ${route}/64 | jq_nhop_filter ${nhop2} 1 4) + atf_check_equal "$output" "$nhop2" + + # Delete routes with nhop1 as nexthop without specifying metric. + # Test that deleting a route by gateway removes all routes with + # that gateway, regardless of metric value. + atf_check -o ignore \ + route -n6 delete -net ${route}/64 -gateway ${nhop1} + + # Verify that nhop2 is the best route now + atf_check -o match:".*gateway: ${nhop2}.*" \ + route -n6 get -net ${route}/64 + + # Delete routes with metric 3 without specifying their gateway. + # Test that deleting a route by metric removes all routes with + # that metric, regardless of gateway value. + atf_check -o ignore \ + route -n6 delete -net ${route}/64 -metric 3 + + # Verify that nhop2 is still the best route with metric of 4 + atf_check -o match:".*gateway: ${nhop2}.*" \ + route -n6 get -net ${route}/64 + output=$(cat netstat | jq_rtentry ${route}/64 | jq_nhop_filter ${nhop2} 1 4) + atf_check_equal "$output" "$nhop2" +} + +delete_route_with_metric_cleanup() +{ + vnet_cleanup +} + + +atf_init_test_cases() +{ + atf_add_test_case "add_lowest_metric" + atf_add_test_case "add_default_metric" + atf_add_test_case "delete_route_with_metric" +}