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

Configure Feed

Select the types of activity you want to include in your feed.

net: hsr: Add KUnit test for PRP

Add unit tests for the PRP duplicate detection

Signed-off-by: Jaakko Karrenpalo <jkarrenpalo@gmail.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Link: https://patch.msgid.link/20250307161700.1045-2-jkarrenpalo@gmail.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>

authored by

Jaakko Karrenpalo and committed by
Paolo Abeni
814dbf4b 05fd00e5

+236
+18
net/hsr/Kconfig
··· 38 38 relying on this code in a safety critical system! 39 39 40 40 If unsure, say N. 41 + 42 + if HSR 43 + 44 + config PRP_DUP_DISCARD_KUNIT_TEST 45 + tristate "PRP duplicate discard KUnit tests" if !KUNIT_ALL_TESTS 46 + depends on KUNIT 47 + default KUNIT_ALL_TESTS 48 + help 49 + Covers the PRP duplicate discard algorithm. 50 + Only useful for kernel devs running KUnit test harness and are not 51 + for inclusion into a production build. 52 + 53 + For more information on KUnit and unit tests in general please refer 54 + to the KUnit documentation in Documentation/dev-tools/kunit/. 55 + 56 + If unsure, say N. 57 + 58 + endif
+2
net/hsr/Makefile
··· 8 8 hsr-y := hsr_main.o hsr_framereg.o hsr_device.o \ 9 9 hsr_netlink.o hsr_slave.o hsr_forward.o 10 10 hsr-$(CONFIG_DEBUG_FS) += hsr_debugfs.o 11 + 12 + obj-$(CONFIG_PRP_DUP_DISCARD_KUNIT_TEST) += prp_dup_discard_test.o
+4
net/hsr/hsr_framereg.c
··· 588 588 return 0; 589 589 } 590 590 591 + #if IS_MODULE(CONFIG_PRP_DUP_DISCARD_KUNIT_TEST) 592 + EXPORT_SYMBOL(prp_register_frame_out); 593 + #endif 594 + 591 595 static struct hsr_port *get_late_port(struct hsr_priv *hsr, 592 596 struct hsr_node *node) 593 597 {
+212
net/hsr/prp_dup_discard_test.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + #include <kunit/test.h> 3 + 4 + #include "hsr_main.h" 5 + #include "hsr_framereg.h" 6 + 7 + struct prp_test_data { 8 + struct hsr_port port; 9 + struct hsr_port port_rcv; 10 + struct hsr_frame_info frame; 11 + struct hsr_node node; 12 + }; 13 + 14 + static struct prp_test_data *build_prp_test_data(struct kunit *test) 15 + { 16 + struct prp_test_data *data = kunit_kzalloc(test, 17 + sizeof(struct prp_test_data), GFP_USER); 18 + KUNIT_EXPECT_NOT_ERR_OR_NULL(test, data); 19 + 20 + data->frame.node_src = &data->node; 21 + data->frame.port_rcv = &data->port_rcv; 22 + data->port_rcv.type = HSR_PT_SLAVE_A; 23 + data->node.seq_start[HSR_PT_SLAVE_A] = 1; 24 + data->node.seq_expected[HSR_PT_SLAVE_A] = 1; 25 + data->node.seq_start[HSR_PT_SLAVE_B] = 1; 26 + data->node.seq_expected[HSR_PT_SLAVE_B] = 1; 27 + data->node.seq_out[HSR_PT_MASTER] = 0; 28 + data->node.time_out[HSR_PT_MASTER] = jiffies; 29 + data->port.type = HSR_PT_MASTER; 30 + 31 + return data; 32 + } 33 + 34 + static void check_prp_counters(struct kunit *test, 35 + struct prp_test_data *data, 36 + u16 seq_start_a, u16 seq_expected_a, 37 + u16 seq_start_b, u16 seq_expected_b) 38 + { 39 + KUNIT_EXPECT_EQ(test, data->node.seq_start[HSR_PT_SLAVE_A], 40 + seq_start_a); 41 + KUNIT_EXPECT_EQ(test, data->node.seq_start[HSR_PT_SLAVE_B], 42 + seq_start_b); 43 + KUNIT_EXPECT_EQ(test, data->node.seq_expected[HSR_PT_SLAVE_A], 44 + seq_expected_a); 45 + KUNIT_EXPECT_EQ(test, data->node.seq_expected[HSR_PT_SLAVE_B], 46 + seq_expected_b); 47 + } 48 + 49 + static void prp_dup_discard_forward(struct kunit *test) 50 + { 51 + /* Normal situation, both LANs in sync. Next frame is forwarded */ 52 + struct prp_test_data *data = build_prp_test_data(test); 53 + 54 + data->frame.sequence_nr = 2; 55 + KUNIT_EXPECT_EQ(test, 0, 56 + prp_register_frame_out(&data->port, &data->frame)); 57 + KUNIT_EXPECT_EQ(test, data->frame.sequence_nr, 58 + data->node.seq_out[HSR_PT_MASTER]); 59 + KUNIT_EXPECT_EQ(test, jiffies, data->node.time_out[HSR_PT_MASTER]); 60 + check_prp_counters(test, data, data->frame.sequence_nr, 61 + data->frame.sequence_nr + 1, 1, 1); 62 + } 63 + 64 + static void prp_dup_discard_inside_dropwindow(struct kunit *test) 65 + { 66 + /* Normal situation, other LAN ahead by one. Frame is dropped */ 67 + struct prp_test_data *data = build_prp_test_data(test); 68 + unsigned long time = jiffies - 10; 69 + 70 + data->frame.sequence_nr = 1; 71 + data->node.seq_expected[HSR_PT_SLAVE_B] = 3; 72 + data->node.seq_out[HSR_PT_MASTER] = 2; 73 + data->node.time_out[HSR_PT_MASTER] = time; 74 + 75 + KUNIT_EXPECT_EQ(test, 1, 76 + prp_register_frame_out(&data->port, &data->frame)); 77 + KUNIT_EXPECT_EQ(test, 2, data->node.seq_out[HSR_PT_MASTER]); 78 + KUNIT_EXPECT_EQ(test, time, data->node.time_out[HSR_PT_MASTER]); 79 + check_prp_counters(test, data, 2, 2, 2, 3); 80 + } 81 + 82 + static void prp_dup_discard_node_timeout(struct kunit *test) 83 + { 84 + /* Timeout situation, node hasn't sent anything for a while */ 85 + struct prp_test_data *data = build_prp_test_data(test); 86 + 87 + data->frame.sequence_nr = 7; 88 + data->node.seq_start[HSR_PT_SLAVE_A] = 1234; 89 + data->node.seq_expected[HSR_PT_SLAVE_A] = 1235; 90 + data->node.seq_start[HSR_PT_SLAVE_B] = 1234; 91 + data->node.seq_expected[HSR_PT_SLAVE_B] = 1234; 92 + data->node.seq_out[HSR_PT_MASTER] = 1234; 93 + data->node.time_out[HSR_PT_MASTER] = 94 + jiffies - msecs_to_jiffies(HSR_ENTRY_FORGET_TIME) - 1; 95 + 96 + KUNIT_EXPECT_EQ(test, 0, 97 + prp_register_frame_out(&data->port, &data->frame)); 98 + KUNIT_EXPECT_EQ(test, data->frame.sequence_nr, 99 + data->node.seq_out[HSR_PT_MASTER]); 100 + KUNIT_EXPECT_EQ(test, jiffies, data->node.time_out[HSR_PT_MASTER]); 101 + check_prp_counters(test, data, data->frame.sequence_nr, 102 + data->frame.sequence_nr + 1, 1234, 1234); 103 + } 104 + 105 + static void prp_dup_discard_out_of_sequence(struct kunit *test) 106 + { 107 + /* One frame is received out of sequence on both LANs */ 108 + struct prp_test_data *data = build_prp_test_data(test); 109 + 110 + data->node.seq_start[HSR_PT_SLAVE_A] = 10; 111 + data->node.seq_expected[HSR_PT_SLAVE_A] = 10; 112 + data->node.seq_start[HSR_PT_SLAVE_B] = 10; 113 + data->node.seq_expected[HSR_PT_SLAVE_B] = 10; 114 + data->node.seq_out[HSR_PT_MASTER] = 9; 115 + 116 + /* 1st old frame, should be accepted */ 117 + data->frame.sequence_nr = 8; 118 + KUNIT_EXPECT_EQ(test, 0, 119 + prp_register_frame_out(&data->port, &data->frame)); 120 + KUNIT_EXPECT_EQ(test, data->frame.sequence_nr, 121 + data->node.seq_out[HSR_PT_MASTER]); 122 + check_prp_counters(test, data, data->frame.sequence_nr, 123 + data->frame.sequence_nr + 1, 10, 10); 124 + 125 + /* 2nd frame should be dropped */ 126 + data->frame.sequence_nr = 8; 127 + data->port_rcv.type = HSR_PT_SLAVE_B; 128 + KUNIT_EXPECT_EQ(test, 1, 129 + prp_register_frame_out(&data->port, &data->frame)); 130 + check_prp_counters(test, data, data->frame.sequence_nr + 1, 131 + data->frame.sequence_nr + 1, 132 + data->frame.sequence_nr + 1, 133 + data->frame.sequence_nr + 1); 134 + 135 + /* Next frame, this is forwarded */ 136 + data->frame.sequence_nr = 10; 137 + data->port_rcv.type = HSR_PT_SLAVE_A; 138 + KUNIT_EXPECT_EQ(test, 0, 139 + prp_register_frame_out(&data->port, &data->frame)); 140 + KUNIT_EXPECT_EQ(test, data->frame.sequence_nr, 141 + data->node.seq_out[HSR_PT_MASTER]); 142 + check_prp_counters(test, data, data->frame.sequence_nr, 143 + data->frame.sequence_nr + 1, 9, 9); 144 + 145 + /* and next one is dropped */ 146 + data->frame.sequence_nr = 10; 147 + data->port_rcv.type = HSR_PT_SLAVE_B; 148 + KUNIT_EXPECT_EQ(test, 1, 149 + prp_register_frame_out(&data->port, &data->frame)); 150 + check_prp_counters(test, data, data->frame.sequence_nr + 1, 151 + data->frame.sequence_nr + 1, 152 + data->frame.sequence_nr + 1, 153 + data->frame.sequence_nr + 1); 154 + } 155 + 156 + static void prp_dup_discard_lan_b_late(struct kunit *test) 157 + { 158 + /* LAN B is behind */ 159 + struct prp_test_data *data = build_prp_test_data(test); 160 + 161 + data->node.seq_start[HSR_PT_SLAVE_A] = 9; 162 + data->node.seq_expected[HSR_PT_SLAVE_A] = 9; 163 + data->node.seq_start[HSR_PT_SLAVE_B] = 9; 164 + data->node.seq_expected[HSR_PT_SLAVE_B] = 9; 165 + data->node.seq_out[HSR_PT_MASTER] = 8; 166 + 167 + data->frame.sequence_nr = 9; 168 + KUNIT_EXPECT_EQ(test, 0, 169 + prp_register_frame_out(&data->port, &data->frame)); 170 + KUNIT_EXPECT_EQ(test, data->frame.sequence_nr, 171 + data->node.seq_out[HSR_PT_MASTER]); 172 + check_prp_counters(test, data, 9, 10, 9, 9); 173 + 174 + data->frame.sequence_nr = 10; 175 + KUNIT_EXPECT_EQ(test, 0, 176 + prp_register_frame_out(&data->port, &data->frame)); 177 + KUNIT_EXPECT_EQ(test, data->frame.sequence_nr, 178 + data->node.seq_out[HSR_PT_MASTER]); 179 + check_prp_counters(test, data, 9, 11, 9, 9); 180 + 181 + data->frame.sequence_nr = 9; 182 + data->port_rcv.type = HSR_PT_SLAVE_B; 183 + KUNIT_EXPECT_EQ(test, 1, 184 + prp_register_frame_out(&data->port, &data->frame)); 185 + check_prp_counters(test, data, 10, 11, 10, 10); 186 + 187 + data->frame.sequence_nr = 10; 188 + data->port_rcv.type = HSR_PT_SLAVE_B; 189 + KUNIT_EXPECT_EQ(test, 1, 190 + prp_register_frame_out(&data->port, &data->frame)); 191 + check_prp_counters(test, data, 11, 11, 11, 11); 192 + } 193 + 194 + static struct kunit_case prp_dup_discard_test_cases[] = { 195 + KUNIT_CASE(prp_dup_discard_forward), 196 + KUNIT_CASE(prp_dup_discard_inside_dropwindow), 197 + KUNIT_CASE(prp_dup_discard_node_timeout), 198 + KUNIT_CASE(prp_dup_discard_out_of_sequence), 199 + KUNIT_CASE(prp_dup_discard_lan_b_late), 200 + {} 201 + }; 202 + 203 + static struct kunit_suite prp_dup_discard_suite = { 204 + .name = "prp_duplicate_discard", 205 + .test_cases = prp_dup_discard_test_cases, 206 + }; 207 + 208 + kunit_test_suite(prp_dup_discard_suite); 209 + 210 + MODULE_LICENSE("GPL"); 211 + MODULE_DESCRIPTION("KUnit tests for PRP duplicate discard"); 212 + MODULE_AUTHOR("Jaakko Karrenpalo <jkarrenpalo@gmail.com>");