Skip to content

Commit ba4a66d

Browse files
liuhangbinNipaLocal
authored andcommitted
tools: ynl: add YNL test framework
Add a test framework for YAML Netlink (YNL) tools, covering both CLI and ethtool functionality. The framework includes: 1) cli: family listing, netdev, ethtool, rt-* families, and nlctrl operations 2) ethtool: device info, statistics, ring/coalesce/pause parameters, and feature gettings The current YNL syntax is a bit obscure, and end users may not always know how to use it. This test framework provides usage examples and also serves as a regression test to catch potential breakages caused by future changes. Reviewed-by: Donald Hunter <[email protected]> Acked-by: Matthieu Baerts (NGI0) <[email protected]> Signed-off-by: Hangbin Liu <[email protected]> Signed-off-by: NipaLocal <nipa@local>
1 parent 196cf56 commit ba4a66d

File tree

5 files changed

+593
-2
lines changed

5 files changed

+593
-2
lines changed

tools/net/ynl/Makefile

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ endif
1212
libdir ?= $(prefix)/$(libdir_relative)
1313
includedir ?= $(prefix)/include
1414

15-
SUBDIRS = lib generated samples ynltool
15+
SUBDIRS = lib generated samples ynltool tests
1616

1717
all: $(SUBDIRS) libynl.a
1818

@@ -49,5 +49,9 @@ install: libynl.a lib/*.h
4949
@echo -e "\tINSTALL pyynl"
5050
@pip install --prefix=$(DESTDIR)$(prefix) .
5151
@make -C generated install
52+
@make -C tests install
5253

53-
.PHONY: all clean distclean install $(SUBDIRS)
54+
run_tests:
55+
@$(MAKE) -C tests run_tests
56+
57+
.PHONY: all clean distclean install run_tests $(SUBDIRS)

tools/net/ynl/tests/Makefile

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# SPDX-License-Identifier: GPL-2.0
2+
# Makefile for YNL tests
3+
4+
TESTS := \
5+
test_ynl_cli.sh \
6+
test_ynl_ethtool.sh \
7+
# end of TESTS
8+
9+
all: $(TESTS)
10+
11+
run_tests:
12+
@for test in $(TESTS); do \
13+
./$$test; \
14+
done
15+
16+
install: $(TESTS)
17+
@mkdir -p $(DESTDIR)/usr/bin
18+
@mkdir -p $(DESTDIR)/usr/share/kselftest
19+
@cp ../../../testing/selftests/kselftest/ktap_helpers.sh $(DESTDIR)/usr/share/kselftest/
20+
@for test in $(TESTS); do \
21+
name=$$(basename $$test .sh); \
22+
sed -e 's|^ynl=.*|ynl="ynl"|' \
23+
-e 's|^ynl_ethtool=.*|ynl_ethtool="ynl-ethtool"|' \
24+
-e 's|KSELFTEST_KTAP_HELPERS=.*|KSELFTEST_KTAP_HELPERS="/usr/share/kselftest/ktap_helpers.sh"|' \
25+
$$test > $(DESTDIR)/usr/bin/$$name; \
26+
chmod +x $(DESTDIR)/usr/bin/$$name; \
27+
done
28+
29+
clean:
30+
@# Nothing to clean
31+
32+
.PHONY: all install clean run_tests

tools/net/ynl/tests/config

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
CONFIG_DUMMY=m
2+
CONFIG_INET_DIAG=y
3+
CONFIG_IPV6=y
4+
CONFIG_NET_NS=y
5+
CONFIG_NETDEVSIM=m
6+
CONFIG_VETH=m
Lines changed: 327 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,327 @@
1+
#!/bin/bash
2+
# SPDX-License-Identifier: GPL-2.0
3+
# Test YNL CLI functionality
4+
5+
# Load KTAP test helpers
6+
KSELFTEST_KTAP_HELPERS="$(dirname "$(realpath "$0")")/../../../testing/selftests/kselftest/ktap_helpers.sh"
7+
# shellcheck source=../../../testing/selftests/kselftest/ktap_helpers.sh
8+
source "$KSELFTEST_KTAP_HELPERS"
9+
10+
# Default ynl path for direct execution, can be overridden by make install
11+
ynl="../pyynl/cli.py"
12+
13+
readonly NSIM_ID="1338"
14+
readonly NSIM_DEV_NAME="nsim${NSIM_ID}"
15+
readonly VETH_A="veth_a"
16+
readonly VETH_B="veth_b"
17+
18+
testns="ynl-$(mktemp -u XXXXXX)"
19+
TESTS_NO=0
20+
21+
# Test listing available families
22+
cli_list_families()
23+
{
24+
if $ynl --list-families &>/dev/null; then
25+
ktap_test_pass "YNL CLI list families"
26+
else
27+
ktap_test_fail "YNL CLI list families"
28+
fi
29+
}
30+
TESTS_NO=$((TESTS_NO + 1))
31+
32+
# Test netdev family operations (dev-get, queue-get)
33+
cli_netdev_ops()
34+
{
35+
local dev_output
36+
local ifindex
37+
38+
ifindex=$(ip netns exec "$testns" cat /sys/class/net/"$NSIM_DEV_NAME"/ifindex 2>/dev/null)
39+
40+
dev_output=$(ip netns exec "$testns" $ynl --family netdev \
41+
--do dev-get --json "{\"ifindex\": $ifindex}" 2>/dev/null)
42+
43+
if ! echo "$dev_output" | grep -q "ifindex"; then
44+
ktap_test_fail "YNL CLI netdev operations (netdev dev-get output missing ifindex)"
45+
return
46+
fi
47+
48+
if ! ip netns exec "$testns" $ynl --family netdev \
49+
--dump queue-get --json "{\"ifindex\": $ifindex}" &>/dev/null; then
50+
ktap_test_fail "YNL CLI netdev operations (failed to get netdev queue info)"
51+
return
52+
fi
53+
54+
ktap_test_pass "YNL CLI netdev operations"
55+
}
56+
TESTS_NO=$((TESTS_NO + 1))
57+
58+
# Test ethtool family operations (rings-get, linkinfo-get)
59+
cli_ethtool_ops()
60+
{
61+
local rings_output
62+
local linkinfo_output
63+
64+
rings_output=$(ip netns exec "$testns" $ynl --family ethtool \
65+
--do rings-get --json "{\"header\": {\"dev-name\": \"$NSIM_DEV_NAME\"}}" 2>/dev/null)
66+
67+
if ! echo "$rings_output" | grep -q "header"; then
68+
ktap_test_fail "YNL CLI ethtool operations (ethtool rings-get output missing header)"
69+
return
70+
fi
71+
72+
linkinfo_output=$(ip netns exec "$testns" $ynl --family ethtool \
73+
--do linkinfo-get --json "{\"header\": {\"dev-name\": \"$VETH_A\"}}" 2>/dev/null)
74+
75+
if ! echo "$linkinfo_output" | grep -q "header"; then
76+
ktap_test_fail "YNL CLI ethtool operations (ethtool linkinfo-get output missing header)"
77+
return
78+
fi
79+
80+
ktap_test_pass "YNL CLI ethtool operations"
81+
}
82+
TESTS_NO=$((TESTS_NO + 1))
83+
84+
# Test rt-route family operations
85+
cli_rt_route_ops()
86+
{
87+
local ifindex
88+
89+
if ! $ynl --list-families 2>/dev/null | grep -q "rt-route"; then
90+
ktap_test_skip "YNL CLI rt-route operations (rt-route family not available)"
91+
return
92+
fi
93+
94+
ifindex=$(ip netns exec "$testns" cat /sys/class/net/"$NSIM_DEV_NAME"/ifindex 2>/dev/null)
95+
96+
# Add route: 192.0.2.0/24 dev $dev scope link
97+
if ! ip netns exec "$testns" $ynl --family rt-route --do newroute --create \
98+
--json "{\"dst\": \"192.0.2.0\", \"oif\": $ifindex, \"rtm-dst-len\": 24, \"rtm-family\": 2, \"rtm-scope\": 253, \"rtm-type\": 1, \"rtm-protocol\": 3, \"rtm-table\": 254}" &>/dev/null; then
99+
ktap_test_fail "YNL CLI rt-route operations (failed to add route)"
100+
return
101+
fi
102+
103+
local route_output
104+
route_output=$(ip netns exec "$testns" $ynl --family rt-route --dump getroute 2>/dev/null)
105+
if echo "$route_output" | grep -q "192.0.2.0"; then
106+
ktap_test_pass "YNL CLI rt-route operations"
107+
else
108+
ktap_test_fail "YNL CLI rt-route operations (failed to verify route)"
109+
fi
110+
111+
ip netns exec "$testns" $ynl --family rt-route --do delroute \
112+
--json "{\"dst\": \"192.0.2.0\", \"oif\": $ifindex, \"rtm-dst-len\": 24, \"rtm-family\": 2, \"rtm-scope\": 253, \"rtm-type\": 1, \"rtm-protocol\": 3, \"rtm-table\": 254}" &>/dev/null
113+
}
114+
TESTS_NO=$((TESTS_NO + 1))
115+
116+
# Test rt-addr family operations
117+
cli_rt_addr_ops()
118+
{
119+
local ifindex
120+
121+
if ! $ynl --list-families 2>/dev/null | grep -q "rt-addr"; then
122+
ktap_test_skip "YNL CLI rt-addr operations (rt-addr family not available)"
123+
return
124+
fi
125+
126+
ifindex=$(ip netns exec "$testns" cat /sys/class/net/"$NSIM_DEV_NAME"/ifindex 2>/dev/null)
127+
128+
if ! ip netns exec "$testns" $ynl --family rt-addr --do newaddr \
129+
--json "{\"ifa-index\": $ifindex, \"local\": \"192.0.2.100\", \"ifa-prefixlen\": 24, \"ifa-family\": 2}" &>/dev/null; then
130+
ktap_test_fail "YNL CLI rt-addr operations (failed to add address)"
131+
return
132+
fi
133+
134+
local addr_output
135+
addr_output=$(ip netns exec "$testns" $ynl --family rt-addr --dump getaddr 2>/dev/null)
136+
if echo "$addr_output" | grep -q "192.0.2.100"; then
137+
ktap_test_pass "YNL CLI rt-addr operations"
138+
else
139+
ktap_test_fail "YNL CLI rt-addr operations (failed to verify address)"
140+
fi
141+
142+
ip netns exec "$testns" $ynl --family rt-addr --do deladdr \
143+
--json "{\"ifa-index\": $ifindex, \"local\": \"192.0.2.100\", \"ifa-prefixlen\": 24, \"ifa-family\": 2}" &>/dev/null
144+
}
145+
TESTS_NO=$((TESTS_NO + 1))
146+
147+
# Test rt-link family operations
148+
cli_rt_link_ops()
149+
{
150+
if ! $ynl --list-families 2>/dev/null | grep -q "rt-link"; then
151+
ktap_test_skip "YNL CLI rt-link operations (rt-link family not available)"
152+
return
153+
fi
154+
155+
if ! ip netns exec "$testns" $ynl --family rt-link --do newlink --create \
156+
--json "{\"ifname\": \"dummy0\", \"linkinfo\": {\"kind\": \"dummy\"}}" &>/dev/null; then
157+
ktap_test_fail "YNL CLI rt-link operations (failed to add link)"
158+
return
159+
fi
160+
161+
local link_output
162+
link_output=$(ip netns exec "$testns" $ynl --family rt-link --dump getlink 2>/dev/null)
163+
if echo "$link_output" | grep -q "$NSIM_DEV_NAME" && echo "$link_output" | grep -q "dummy0"; then
164+
ktap_test_pass "YNL CLI rt-link operations"
165+
else
166+
ktap_test_fail "YNL CLI rt-link operations (failed to verify link)"
167+
fi
168+
169+
ip netns exec "$testns" $ynl --family rt-link --do dellink \
170+
--json "{\"ifname\": \"dummy0\"}" &>/dev/null
171+
}
172+
TESTS_NO=$((TESTS_NO + 1))
173+
174+
# Test rt-neigh family operations
175+
cli_rt_neigh_ops()
176+
{
177+
local ifindex
178+
179+
if ! $ynl --list-families 2>/dev/null | grep -q "rt-neigh"; then
180+
ktap_test_skip "YNL CLI rt-neigh operations (rt-neigh family not available)"
181+
return
182+
fi
183+
184+
ifindex=$(ip netns exec "$testns" cat /sys/class/net/"$NSIM_DEV_NAME"/ifindex 2>/dev/null)
185+
186+
# Add neighbor: 192.0.2.1 dev nsim1338 lladdr 11:22:33:44:55:66 PERMANENT
187+
if ! ip netns exec "$testns" $ynl --family rt-neigh --do newneigh --create \
188+
--json "{\"ndm-ifindex\": $ifindex, \"dst\": \"192.0.2.1\", \"lladdr\": \"11:22:33:44:55:66\", \"ndm-family\": 2, \"ndm-state\": 128}" &>/dev/null; then
189+
ktap_test_fail "YNL CLI rt-neigh operations (failed to add neighbor)"
190+
fi
191+
192+
local neigh_output
193+
neigh_output=$(ip netns exec "$testns" $ynl --family rt-neigh --dump getneigh 2>/dev/null)
194+
if echo "$neigh_output" | grep -q "192.0.2.1"; then
195+
ktap_test_pass "YNL CLI rt-neigh operations"
196+
else
197+
ktap_test_fail "YNL CLI rt-neigh operations (failed to verify neighbor)"
198+
fi
199+
200+
ip netns exec "$testns" $ynl --family rt-neigh --do delneigh \
201+
--json "{\"ndm-ifindex\": $ifindex, \"dst\": \"192.0.2.1\", \"lladdr\": \"11:22:33:44:55:66\", \"ndm-family\": 2}" &>/dev/null
202+
}
203+
TESTS_NO=$((TESTS_NO + 1))
204+
205+
# Test rt-rule family operations
206+
cli_rt_rule_ops()
207+
{
208+
if ! $ynl --list-families 2>/dev/null | grep -q "rt-rule"; then
209+
ktap_test_skip "YNL CLI rt-rule operations (rt-rule family not available)"
210+
return
211+
fi
212+
213+
# Add rule: from 192.0.2.0/24 lookup 100 none
214+
if ! ip netns exec "$testns" $ynl --family rt-rule --do newrule \
215+
--json "{\"family\": 2, \"src-len\": 24, \"src\": \"192.0.2.0\", \"table\": 100}" &>/dev/null; then
216+
ktap_test_fail "YNL CLI rt-rule operations (failed to add rule)"
217+
return
218+
fi
219+
220+
local rule_output
221+
rule_output=$(ip netns exec "$testns" $ynl --family rt-rule --dump getrule 2>/dev/null)
222+
if echo "$rule_output" | grep -q "192.0.2.0"; then
223+
ktap_test_pass "YNL CLI rt-rule operations"
224+
else
225+
ktap_test_fail "YNL CLI rt-rule operations (failed to verify rule)"
226+
fi
227+
228+
ip netns exec "$testns" $ynl --family rt-rule --do delrule \
229+
--json "{\"family\": 2, \"src-len\": 24, \"src\": \"192.0.2.0\", \"table\": 100}" &>/dev/null
230+
}
231+
TESTS_NO=$((TESTS_NO + 1))
232+
233+
# Test nlctrl family operations
234+
cli_nlctrl_ops()
235+
{
236+
local family_output
237+
238+
if ! family_output=$($ynl --family nlctrl \
239+
--do getfamily --json "{\"family-name\": \"netdev\"}" 2>/dev/null); then
240+
ktap_test_fail "YNL CLI nlctrl getfamily (failed to get nlctrl family info)"
241+
return
242+
fi
243+
244+
if ! echo "$family_output" | grep -q "family-name"; then
245+
ktap_test_fail "YNL CLI nlctrl getfamily (nlctrl getfamily output missing family-name)"
246+
return
247+
fi
248+
249+
if ! echo "$family_output" | grep -q "family-id"; then
250+
ktap_test_fail "YNL CLI nlctrl getfamily (nlctrl getfamily output missing family-id)"
251+
return
252+
fi
253+
254+
ktap_test_pass "YNL CLI nlctrl getfamily"
255+
}
256+
TESTS_NO=$((TESTS_NO + 1))
257+
258+
setup()
259+
{
260+
modprobe netdevsim &> /dev/null
261+
if ! [ -f /sys/bus/netdevsim/new_device ]; then
262+
ktap_skip_all "netdevsim module not available"
263+
exit "$KSFT_SKIP"
264+
fi
265+
266+
if ! ip netns add "$testns" 2>/dev/null; then
267+
ktap_skip_all "failed to create test namespace"
268+
exit "$KSFT_SKIP"
269+
fi
270+
271+
echo "$NSIM_ID 1" | ip netns exec "$testns" tee /sys/bus/netdevsim/new_device >/dev/null 2>&1 || {
272+
ktap_skip_all "failed to create netdevsim device"
273+
exit "$KSFT_SKIP"
274+
}
275+
276+
local dev
277+
dev=$(ip netns exec "$testns" ls /sys/bus/netdevsim/devices/netdevsim$NSIM_ID/net 2>/dev/null | head -1)
278+
if [[ -z "$dev" ]]; then
279+
ktap_skip_all "failed to find netdevsim device"
280+
exit "$KSFT_SKIP"
281+
fi
282+
283+
ip -netns "$testns" link set dev "$dev" name "$NSIM_DEV_NAME" 2>/dev/null || {
284+
ktap_skip_all "failed to rename netdevsim device"
285+
exit "$KSFT_SKIP"
286+
}
287+
288+
ip -netns "$testns" link set dev "$NSIM_DEV_NAME" up 2>/dev/null
289+
290+
if ! ip -n "$testns" link add "$VETH_A" type veth peer name "$VETH_B" 2>/dev/null; then
291+
ktap_skip_all "failed to create veth pair"
292+
exit "$KSFT_SKIP"
293+
fi
294+
295+
ip -n "$testns" link set "$VETH_A" up 2>/dev/null
296+
ip -n "$testns" link set "$VETH_B" up 2>/dev/null
297+
}
298+
299+
cleanup()
300+
{
301+
ip netns exec "$testns" bash -c "echo $NSIM_ID > /sys/bus/netdevsim/del_device" 2>/dev/null || true
302+
ip netns del "$testns" 2>/dev/null || true
303+
}
304+
305+
# Check if ynl command is available
306+
if ! command -v $ynl &>/dev/null && [[ ! -x $ynl ]]; then
307+
ktap_skip_all "ynl command not found: $ynl"
308+
exit "$KSFT_SKIP"
309+
fi
310+
311+
trap cleanup EXIT
312+
313+
ktap_print_header
314+
setup
315+
ktap_set_plan "${TESTS_NO}"
316+
317+
cli_list_families
318+
cli_netdev_ops
319+
cli_ethtool_ops
320+
cli_rt_route_ops
321+
cli_rt_addr_ops
322+
cli_rt_link_ops
323+
cli_rt_neigh_ops
324+
cli_rt_rule_ops
325+
cli_nlctrl_ops
326+
327+
ktap_finished

0 commit comments

Comments
 (0)