Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

selftests: can: Import tst-filter from can-tests

Tests for the can subsystem have been in the can-tests repository[1] so
far. Start moving the tests to kernel selftests by importing the current
tst-filter test. The test is now named test_raw_filter and is substantially
updated to be more aligned with the kernel selftests, follow the coding
style, and simplify the validation of received CAN frames. We also include
documentation of the test design. The test verifies that the single filters
on raw CAN sockets work as expected.

We intend to import more tests from can-tests and add additional test cases
in the future. The goal of moving the CAN selftests into the tree is to
align the tests more closely with the kernel, improve testing of CAN in
general, and to simplify running the tests automatically in the various
kernel CI systems.

[1]: https://github.com/linux-can/can-tests

Signed-off-by: Felix Maurer <fmaurer@redhat.com>
Reviewed-by: Vincent Mailhol <mailhol.vincent@wanadoo.fr>
Link: https://patch.msgid.link/87d289f333cba7bbcc9d69173ea1c320e4b5c3b8.1747833283.git.fmaurer@redhat.com
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>

authored by

Felix Maurer and committed by
Marc Kleine-Budde
77442ffa b803c4a4

+458
+2
MAINTAINERS
··· 5267 5267 F: include/uapi/linux/can/raw.h 5268 5268 F: net/can/ 5269 5269 F: net/sched/em_canid.c 5270 + F: tools/testing/selftests/net/can/ 5270 5271 5271 5272 CAN-J1939 NETWORK LAYER 5272 5273 M: Robin van der Gracht <robin@protonic.nl> ··· 17043 17042 X: net/mac80211/ 17044 17043 X: net/rfkill/ 17045 17044 X: net/wireless/ 17045 + X: tools/testing/selftests/net/can/ 17046 17046 17047 17047 NETWORKING [IPSEC] 17048 17048 M: Steffen Klassert <steffen.klassert@secunet.com>
+1
tools/testing/selftests/Makefile
··· 66 66 TARGETS += nci 67 67 TARGETS += net 68 68 TARGETS += net/af_unix 69 + TARGETS += net/can 69 70 TARGETS += net/forwarding 70 71 TARGETS += net/hsr 71 72 TARGETS += net/mptcp
+2
tools/testing/selftests/net/can/.gitignore
··· 1 + # SPDX-License-Identifier: GPL-2.0-only 2 + test_raw_filter
+11
tools/testing/selftests/net/can/Makefile
··· 1 + # SPDX-License-Identifier: GPL-2.0 2 + 3 + top_srcdir = ../../../../.. 4 + 5 + CFLAGS += -Wall -Wl,--no-as-needed -O2 -g -I$(top_srcdir)/usr/include $(KHDR_INCLUDES) 6 + 7 + TEST_PROGS := test_raw_filter.sh 8 + 9 + TEST_GEN_FILES := test_raw_filter 10 + 11 + include ../../lib.mk
+405
tools/testing/selftests/net/can/test_raw_filter.c
··· 1 + // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) 2 + /* 3 + * Copyright (c) 2011 Volkswagen Group Electronic Research 4 + * All rights reserved. 5 + */ 6 + 7 + #include <stdio.h> 8 + #include <stdlib.h> 9 + #include <unistd.h> 10 + #include <string.h> 11 + 12 + #include <sys/types.h> 13 + #include <sys/socket.h> 14 + #include <sys/ioctl.h> 15 + #include <sys/time.h> 16 + #include <net/if.h> 17 + #include <linux/if.h> 18 + 19 + #include <linux/can.h> 20 + #include <linux/can/raw.h> 21 + 22 + #include "../../kselftest_harness.h" 23 + 24 + #define ID 0x123 25 + 26 + char CANIF[IFNAMSIZ]; 27 + 28 + static int send_can_frames(int sock, int testcase) 29 + { 30 + struct can_frame frame; 31 + 32 + frame.can_dlc = 1; 33 + frame.data[0] = testcase; 34 + 35 + frame.can_id = ID; 36 + if (write(sock, &frame, sizeof(frame)) < 0) 37 + goto write_err; 38 + 39 + frame.can_id = (ID | CAN_RTR_FLAG); 40 + if (write(sock, &frame, sizeof(frame)) < 0) 41 + goto write_err; 42 + 43 + frame.can_id = (ID | CAN_EFF_FLAG); 44 + if (write(sock, &frame, sizeof(frame)) < 0) 45 + goto write_err; 46 + 47 + frame.can_id = (ID | CAN_EFF_FLAG | CAN_RTR_FLAG); 48 + if (write(sock, &frame, sizeof(frame)) < 0) 49 + goto write_err; 50 + 51 + return 0; 52 + 53 + write_err: 54 + perror("write"); 55 + return 1; 56 + } 57 + 58 + FIXTURE(can_filters) { 59 + int sock; 60 + }; 61 + 62 + FIXTURE_SETUP(can_filters) 63 + { 64 + struct sockaddr_can addr; 65 + struct ifreq ifr; 66 + int recv_own_msgs = 1; 67 + int s, ret; 68 + 69 + s = socket(PF_CAN, SOCK_RAW, CAN_RAW); 70 + ASSERT_GE(s, 0) 71 + TH_LOG("failed to create CAN_RAW socket: %d", errno); 72 + 73 + strncpy(ifr.ifr_name, CANIF, sizeof(ifr.ifr_name)); 74 + ret = ioctl(s, SIOCGIFINDEX, &ifr); 75 + ASSERT_GE(ret, 0) 76 + TH_LOG("failed SIOCGIFINDEX: %d", errno); 77 + 78 + addr.can_family = AF_CAN; 79 + addr.can_ifindex = ifr.ifr_ifindex; 80 + 81 + setsockopt(s, SOL_CAN_RAW, CAN_RAW_RECV_OWN_MSGS, 82 + &recv_own_msgs, sizeof(recv_own_msgs)); 83 + 84 + ret = bind(s, (struct sockaddr *)&addr, sizeof(addr)); 85 + ASSERT_EQ(ret, 0) 86 + TH_LOG("failed bind socket: %d", errno); 87 + 88 + self->sock = s; 89 + } 90 + 91 + FIXTURE_TEARDOWN(can_filters) 92 + { 93 + close(self->sock); 94 + } 95 + 96 + FIXTURE_VARIANT(can_filters) { 97 + int testcase; 98 + canid_t id; 99 + canid_t mask; 100 + int exp_num_rx; 101 + canid_t exp_flags[]; 102 + }; 103 + 104 + /* Receive all frames when filtering for the ID in standard frame format */ 105 + FIXTURE_VARIANT_ADD(can_filters, base) { 106 + .testcase = 1, 107 + .id = ID, 108 + .mask = CAN_SFF_MASK, 109 + .exp_num_rx = 4, 110 + .exp_flags = { 111 + 0, 112 + CAN_RTR_FLAG, 113 + CAN_EFF_FLAG, 114 + CAN_EFF_FLAG | CAN_RTR_FLAG, 115 + }, 116 + }; 117 + 118 + /* Ignore EFF flag in filter ID if not covered by filter mask */ 119 + FIXTURE_VARIANT_ADD(can_filters, base_eff) { 120 + .testcase = 2, 121 + .id = ID | CAN_EFF_FLAG, 122 + .mask = CAN_SFF_MASK, 123 + .exp_num_rx = 4, 124 + .exp_flags = { 125 + 0, 126 + CAN_RTR_FLAG, 127 + CAN_EFF_FLAG, 128 + CAN_EFF_FLAG | CAN_RTR_FLAG, 129 + }, 130 + }; 131 + 132 + /* Ignore RTR flag in filter ID if not covered by filter mask */ 133 + FIXTURE_VARIANT_ADD(can_filters, base_rtr) { 134 + .testcase = 3, 135 + .id = ID | CAN_RTR_FLAG, 136 + .mask = CAN_SFF_MASK, 137 + .exp_num_rx = 4, 138 + .exp_flags = { 139 + 0, 140 + CAN_RTR_FLAG, 141 + CAN_EFF_FLAG, 142 + CAN_EFF_FLAG | CAN_RTR_FLAG, 143 + }, 144 + }; 145 + 146 + /* Ignore EFF and RTR flags in filter ID if not covered by filter mask */ 147 + FIXTURE_VARIANT_ADD(can_filters, base_effrtr) { 148 + .testcase = 4, 149 + .id = ID | CAN_EFF_FLAG | CAN_RTR_FLAG, 150 + .mask = CAN_SFF_MASK, 151 + .exp_num_rx = 4, 152 + .exp_flags = { 153 + 0, 154 + CAN_RTR_FLAG, 155 + CAN_EFF_FLAG, 156 + CAN_EFF_FLAG | CAN_RTR_FLAG, 157 + }, 158 + }; 159 + 160 + /* Receive only SFF frames when expecting no EFF flag */ 161 + FIXTURE_VARIANT_ADD(can_filters, filter_eff) { 162 + .testcase = 5, 163 + .id = ID, 164 + .mask = CAN_SFF_MASK | CAN_EFF_FLAG, 165 + .exp_num_rx = 2, 166 + .exp_flags = { 167 + 0, 168 + CAN_RTR_FLAG, 169 + }, 170 + }; 171 + 172 + /* Receive only EFF frames when filter id and filter mask include EFF flag */ 173 + FIXTURE_VARIANT_ADD(can_filters, filter_eff_eff) { 174 + .testcase = 6, 175 + .id = ID | CAN_EFF_FLAG, 176 + .mask = CAN_SFF_MASK | CAN_EFF_FLAG, 177 + .exp_num_rx = 2, 178 + .exp_flags = { 179 + CAN_EFF_FLAG, 180 + CAN_EFF_FLAG | CAN_RTR_FLAG, 181 + }, 182 + }; 183 + 184 + /* Receive only SFF frames when expecting no EFF flag, ignoring RTR flag */ 185 + FIXTURE_VARIANT_ADD(can_filters, filter_eff_rtr) { 186 + .testcase = 7, 187 + .id = ID | CAN_RTR_FLAG, 188 + .mask = CAN_SFF_MASK | CAN_EFF_FLAG, 189 + .exp_num_rx = 2, 190 + .exp_flags = { 191 + 0, 192 + CAN_RTR_FLAG, 193 + }, 194 + }; 195 + 196 + /* Receive only EFF frames when filter id and filter mask include EFF flag, 197 + * ignoring RTR flag 198 + */ 199 + FIXTURE_VARIANT_ADD(can_filters, filter_eff_effrtr) { 200 + .testcase = 8, 201 + .id = ID | CAN_EFF_FLAG | CAN_RTR_FLAG, 202 + .mask = CAN_SFF_MASK | CAN_EFF_FLAG, 203 + .exp_num_rx = 2, 204 + .exp_flags = { 205 + CAN_EFF_FLAG, 206 + CAN_EFF_FLAG | CAN_RTR_FLAG, 207 + }, 208 + }; 209 + 210 + /* Receive no remote frames when filtering for no RTR flag */ 211 + FIXTURE_VARIANT_ADD(can_filters, filter_rtr) { 212 + .testcase = 9, 213 + .id = ID, 214 + .mask = CAN_SFF_MASK | CAN_RTR_FLAG, 215 + .exp_num_rx = 2, 216 + .exp_flags = { 217 + 0, 218 + CAN_EFF_FLAG, 219 + }, 220 + }; 221 + 222 + /* Receive no remote frames when filtering for no RTR flag, ignoring EFF flag */ 223 + FIXTURE_VARIANT_ADD(can_filters, filter_rtr_eff) { 224 + .testcase = 10, 225 + .id = ID | CAN_EFF_FLAG, 226 + .mask = CAN_SFF_MASK | CAN_RTR_FLAG, 227 + .exp_num_rx = 2, 228 + .exp_flags = { 229 + 0, 230 + CAN_EFF_FLAG, 231 + }, 232 + }; 233 + 234 + /* Receive only remote frames when filter includes RTR flag */ 235 + FIXTURE_VARIANT_ADD(can_filters, filter_rtr_rtr) { 236 + .testcase = 11, 237 + .id = ID | CAN_RTR_FLAG, 238 + .mask = CAN_SFF_MASK | CAN_RTR_FLAG, 239 + .exp_num_rx = 2, 240 + .exp_flags = { 241 + CAN_RTR_FLAG, 242 + CAN_EFF_FLAG | CAN_RTR_FLAG, 243 + }, 244 + }; 245 + 246 + /* Receive only remote frames when filter includes RTR flag, ignoring EFF 247 + * flag 248 + */ 249 + FIXTURE_VARIANT_ADD(can_filters, filter_rtr_effrtr) { 250 + .testcase = 12, 251 + .id = ID | CAN_EFF_FLAG | CAN_RTR_FLAG, 252 + .mask = CAN_SFF_MASK | CAN_RTR_FLAG, 253 + .exp_num_rx = 2, 254 + .exp_flags = { 255 + CAN_RTR_FLAG, 256 + CAN_EFF_FLAG | CAN_RTR_FLAG, 257 + }, 258 + }; 259 + 260 + /* Receive only SFF data frame when filtering for no flags */ 261 + FIXTURE_VARIANT_ADD(can_filters, filter_effrtr) { 262 + .testcase = 13, 263 + .id = ID, 264 + .mask = CAN_SFF_MASK | CAN_EFF_FLAG | CAN_RTR_FLAG, 265 + .exp_num_rx = 1, 266 + .exp_flags = { 267 + 0, 268 + }, 269 + }; 270 + 271 + /* Receive only EFF data frame when filtering for EFF but no RTR flag */ 272 + FIXTURE_VARIANT_ADD(can_filters, filter_effrtr_eff) { 273 + .testcase = 14, 274 + .id = ID | CAN_EFF_FLAG, 275 + .mask = CAN_SFF_MASK | CAN_EFF_FLAG | CAN_RTR_FLAG, 276 + .exp_num_rx = 1, 277 + .exp_flags = { 278 + CAN_EFF_FLAG, 279 + }, 280 + }; 281 + 282 + /* Receive only SFF remote frame when filtering for RTR but no EFF flag */ 283 + FIXTURE_VARIANT_ADD(can_filters, filter_effrtr_rtr) { 284 + .testcase = 15, 285 + .id = ID | CAN_RTR_FLAG, 286 + .mask = CAN_SFF_MASK | CAN_EFF_FLAG | CAN_RTR_FLAG, 287 + .exp_num_rx = 1, 288 + .exp_flags = { 289 + CAN_RTR_FLAG, 290 + }, 291 + }; 292 + 293 + /* Receive only EFF remote frame when filtering for EFF and RTR flag */ 294 + FIXTURE_VARIANT_ADD(can_filters, filter_effrtr_effrtr) { 295 + .testcase = 16, 296 + .id = ID | CAN_EFF_FLAG | CAN_RTR_FLAG, 297 + .mask = CAN_SFF_MASK | CAN_EFF_FLAG | CAN_RTR_FLAG, 298 + .exp_num_rx = 1, 299 + .exp_flags = { 300 + CAN_EFF_FLAG | CAN_RTR_FLAG, 301 + }, 302 + }; 303 + 304 + /* Receive only SFF data frame when filtering for no EFF flag and no RTR flag 305 + * but based on EFF mask 306 + */ 307 + FIXTURE_VARIANT_ADD(can_filters, eff) { 308 + .testcase = 17, 309 + .id = ID, 310 + .mask = CAN_EFF_MASK | CAN_EFF_FLAG | CAN_RTR_FLAG, 311 + .exp_num_rx = 1, 312 + .exp_flags = { 313 + 0, 314 + }, 315 + }; 316 + 317 + /* Receive only EFF data frame when filtering for EFF flag and no RTR flag but 318 + * based on EFF mask 319 + */ 320 + FIXTURE_VARIANT_ADD(can_filters, eff_eff) { 321 + .testcase = 18, 322 + .id = ID | CAN_EFF_FLAG, 323 + .mask = CAN_EFF_MASK | CAN_EFF_FLAG | CAN_RTR_FLAG, 324 + .exp_num_rx = 1, 325 + .exp_flags = { 326 + CAN_EFF_FLAG, 327 + }, 328 + }; 329 + 330 + /* This test verifies that the raw CAN filters work, by checking if only frames 331 + * with the expected set of flags are received. For each test case, the given 332 + * filter (id and mask) is added and four CAN frames are sent with every 333 + * combination of set/unset EFF/RTR flags. 334 + */ 335 + TEST_F(can_filters, test_filter) 336 + { 337 + struct can_filter rfilter; 338 + int ret; 339 + 340 + rfilter.can_id = variant->id; 341 + rfilter.can_mask = variant->mask; 342 + setsockopt(self->sock, SOL_CAN_RAW, CAN_RAW_FILTER, 343 + &rfilter, sizeof(rfilter)); 344 + 345 + TH_LOG("filters: can_id = 0x%08X can_mask = 0x%08X", 346 + rfilter.can_id, rfilter.can_mask); 347 + 348 + ret = send_can_frames(self->sock, variant->testcase); 349 + ASSERT_EQ(ret, 0) 350 + TH_LOG("failed to send CAN frames"); 351 + 352 + for (int i = 0; i <= variant->exp_num_rx; i++) { 353 + struct can_frame frame; 354 + struct timeval tv = { 355 + .tv_sec = 0, 356 + .tv_usec = 50000, /* 50ms timeout */ 357 + }; 358 + fd_set rdfs; 359 + 360 + FD_ZERO(&rdfs); 361 + FD_SET(self->sock, &rdfs); 362 + 363 + ret = select(self->sock + 1, &rdfs, NULL, NULL, &tv); 364 + ASSERT_GE(ret, 0) 365 + TH_LOG("failed select for frame %d, err: %d)", i, errno); 366 + 367 + ret = FD_ISSET(self->sock, &rdfs); 368 + if (i == variant->exp_num_rx) { 369 + ASSERT_EQ(ret, 0) 370 + TH_LOG("too many frames received"); 371 + } else { 372 + ASSERT_NE(ret, 0) 373 + TH_LOG("too few frames received"); 374 + 375 + ret = read(self->sock, &frame, sizeof(frame)); 376 + ASSERT_GE(ret, 0) 377 + TH_LOG("failed to read frame %d, err: %d", i, errno); 378 + 379 + TH_LOG("rx: can_id = 0x%08X rx = %d", frame.can_id, i); 380 + 381 + ASSERT_EQ(ID, frame.can_id & CAN_SFF_MASK) 382 + TH_LOG("received wrong can_id"); 383 + ASSERT_EQ(variant->testcase, frame.data[0]) 384 + TH_LOG("received wrong test case"); 385 + 386 + ASSERT_EQ(frame.can_id & ~CAN_ERR_MASK, 387 + variant->exp_flags[i]) 388 + TH_LOG("received unexpected flags"); 389 + } 390 + } 391 + } 392 + 393 + int main(int argc, char **argv) 394 + { 395 + char *ifname = getenv("CANIF"); 396 + 397 + if (!ifname) { 398 + printf("CANIF environment variable must contain the test interface\n"); 399 + return KSFT_FAIL; 400 + } 401 + 402 + strncpy(CANIF, ifname, sizeof(CANIF) - 1); 403 + 404 + return test_harness_run(argc, argv); 405 + }
+37
tools/testing/selftests/net/can/test_raw_filter.sh
··· 1 + #!/bin/bash 2 + # SPDX-License-Identifier: GPL-2.0 3 + 4 + ALL_TESTS=" 5 + test_raw_filter 6 + " 7 + 8 + net_dir=$(dirname $0)/.. 9 + source $net_dir/lib.sh 10 + 11 + export CANIF=${CANIF:-"vcan0"} 12 + 13 + setup() 14 + { 15 + ip link add name $CANIF type vcan || exit $ksft_skip 16 + ip link set dev $CANIF up 17 + pwd 18 + } 19 + 20 + cleanup() 21 + { 22 + ip link delete $CANIF 23 + } 24 + 25 + test_raw_filter() 26 + { 27 + ./test_raw_filter 28 + check_err $? 29 + log_test "test_raw_filter" 30 + } 31 + 32 + trap cleanup EXIT 33 + setup 34 + 35 + tests_run 36 + 37 + exit $EXIT_STATUS