| // SPDX-License-Identifier: GPL-2.0 |
| #include <kunit/test.h> |
| |
| #include "hsr_main.h" |
| #include "hsr_framereg.h" |
| |
| struct prp_test_data { |
| struct hsr_port port; |
| struct hsr_port port_rcv; |
| struct hsr_frame_info frame; |
| struct hsr_node node; |
| }; |
| |
| static struct prp_test_data *build_prp_test_data(struct kunit *test) |
| { |
| struct prp_test_data *data = kunit_kzalloc(test, |
| sizeof(struct prp_test_data), GFP_USER); |
| KUNIT_EXPECT_NOT_ERR_OR_NULL(test, data); |
| |
| data->frame.node_src = &data->node; |
| data->frame.port_rcv = &data->port_rcv; |
| data->port_rcv.type = HSR_PT_SLAVE_A; |
| data->node.seq_start[HSR_PT_SLAVE_A] = 1; |
| data->node.seq_expected[HSR_PT_SLAVE_A] = 1; |
| data->node.seq_start[HSR_PT_SLAVE_B] = 1; |
| data->node.seq_expected[HSR_PT_SLAVE_B] = 1; |
| data->node.seq_out[HSR_PT_MASTER] = 0; |
| data->node.time_out[HSR_PT_MASTER] = jiffies; |
| data->port.type = HSR_PT_MASTER; |
| |
| return data; |
| } |
| |
| static void check_prp_counters(struct kunit *test, |
| struct prp_test_data *data, |
| u16 seq_start_a, u16 seq_expected_a, |
| u16 seq_start_b, u16 seq_expected_b) |
| { |
| KUNIT_EXPECT_EQ(test, data->node.seq_start[HSR_PT_SLAVE_A], |
| seq_start_a); |
| KUNIT_EXPECT_EQ(test, data->node.seq_start[HSR_PT_SLAVE_B], |
| seq_start_b); |
| KUNIT_EXPECT_EQ(test, data->node.seq_expected[HSR_PT_SLAVE_A], |
| seq_expected_a); |
| KUNIT_EXPECT_EQ(test, data->node.seq_expected[HSR_PT_SLAVE_B], |
| seq_expected_b); |
| } |
| |
| static void prp_dup_discard_forward(struct kunit *test) |
| { |
| /* Normal situation, both LANs in sync. Next frame is forwarded */ |
| struct prp_test_data *data = build_prp_test_data(test); |
| |
| data->frame.sequence_nr = 2; |
| KUNIT_EXPECT_EQ(test, 0, |
| prp_register_frame_out(&data->port, &data->frame)); |
| KUNIT_EXPECT_EQ(test, data->frame.sequence_nr, |
| data->node.seq_out[HSR_PT_MASTER]); |
| KUNIT_EXPECT_EQ(test, jiffies, data->node.time_out[HSR_PT_MASTER]); |
| check_prp_counters(test, data, data->frame.sequence_nr, |
| data->frame.sequence_nr + 1, 1, 1); |
| } |
| |
| static void prp_dup_discard_inside_dropwindow(struct kunit *test) |
| { |
| /* Normal situation, other LAN ahead by one. Frame is dropped */ |
| struct prp_test_data *data = build_prp_test_data(test); |
| unsigned long time = jiffies - 10; |
| |
| data->frame.sequence_nr = 1; |
| data->node.seq_expected[HSR_PT_SLAVE_B] = 3; |
| data->node.seq_out[HSR_PT_MASTER] = 2; |
| data->node.time_out[HSR_PT_MASTER] = time; |
| |
| KUNIT_EXPECT_EQ(test, 1, |
| prp_register_frame_out(&data->port, &data->frame)); |
| KUNIT_EXPECT_EQ(test, 2, data->node.seq_out[HSR_PT_MASTER]); |
| KUNIT_EXPECT_EQ(test, time, data->node.time_out[HSR_PT_MASTER]); |
| check_prp_counters(test, data, 2, 2, 2, 3); |
| } |
| |
| static void prp_dup_discard_node_timeout(struct kunit *test) |
| { |
| /* Timeout situation, node hasn't sent anything for a while */ |
| struct prp_test_data *data = build_prp_test_data(test); |
| |
| data->frame.sequence_nr = 7; |
| data->node.seq_start[HSR_PT_SLAVE_A] = 1234; |
| data->node.seq_expected[HSR_PT_SLAVE_A] = 1235; |
| data->node.seq_start[HSR_PT_SLAVE_B] = 1234; |
| data->node.seq_expected[HSR_PT_SLAVE_B] = 1234; |
| data->node.seq_out[HSR_PT_MASTER] = 1234; |
| data->node.time_out[HSR_PT_MASTER] = |
| jiffies - msecs_to_jiffies(HSR_ENTRY_FORGET_TIME) - 1; |
| |
| KUNIT_EXPECT_EQ(test, 0, |
| prp_register_frame_out(&data->port, &data->frame)); |
| KUNIT_EXPECT_EQ(test, data->frame.sequence_nr, |
| data->node.seq_out[HSR_PT_MASTER]); |
| KUNIT_EXPECT_EQ(test, jiffies, data->node.time_out[HSR_PT_MASTER]); |
| check_prp_counters(test, data, data->frame.sequence_nr, |
| data->frame.sequence_nr + 1, 1234, 1234); |
| } |
| |
| static void prp_dup_discard_out_of_sequence(struct kunit *test) |
| { |
| /* One frame is received out of sequence on both LANs */ |
| struct prp_test_data *data = build_prp_test_data(test); |
| |
| data->node.seq_start[HSR_PT_SLAVE_A] = 10; |
| data->node.seq_expected[HSR_PT_SLAVE_A] = 10; |
| data->node.seq_start[HSR_PT_SLAVE_B] = 10; |
| data->node.seq_expected[HSR_PT_SLAVE_B] = 10; |
| data->node.seq_out[HSR_PT_MASTER] = 9; |
| |
| /* 1st old frame, should be accepted */ |
| data->frame.sequence_nr = 8; |
| KUNIT_EXPECT_EQ(test, 0, |
| prp_register_frame_out(&data->port, &data->frame)); |
| KUNIT_EXPECT_EQ(test, data->frame.sequence_nr, |
| data->node.seq_out[HSR_PT_MASTER]); |
| check_prp_counters(test, data, data->frame.sequence_nr, |
| data->frame.sequence_nr + 1, 10, 10); |
| |
| /* 2nd frame should be dropped */ |
| data->frame.sequence_nr = 8; |
| data->port_rcv.type = HSR_PT_SLAVE_B; |
| KUNIT_EXPECT_EQ(test, 1, |
| prp_register_frame_out(&data->port, &data->frame)); |
| check_prp_counters(test, data, data->frame.sequence_nr + 1, |
| data->frame.sequence_nr + 1, |
| data->frame.sequence_nr + 1, |
| data->frame.sequence_nr + 1); |
| |
| /* Next frame, this is forwarded */ |
| data->frame.sequence_nr = 10; |
| data->port_rcv.type = HSR_PT_SLAVE_A; |
| KUNIT_EXPECT_EQ(test, 0, |
| prp_register_frame_out(&data->port, &data->frame)); |
| KUNIT_EXPECT_EQ(test, data->frame.sequence_nr, |
| data->node.seq_out[HSR_PT_MASTER]); |
| check_prp_counters(test, data, data->frame.sequence_nr, |
| data->frame.sequence_nr + 1, 9, 9); |
| |
| /* and next one is dropped */ |
| data->frame.sequence_nr = 10; |
| data->port_rcv.type = HSR_PT_SLAVE_B; |
| KUNIT_EXPECT_EQ(test, 1, |
| prp_register_frame_out(&data->port, &data->frame)); |
| check_prp_counters(test, data, data->frame.sequence_nr + 1, |
| data->frame.sequence_nr + 1, |
| data->frame.sequence_nr + 1, |
| data->frame.sequence_nr + 1); |
| } |
| |
| static void prp_dup_discard_lan_b_late(struct kunit *test) |
| { |
| /* LAN B is behind */ |
| struct prp_test_data *data = build_prp_test_data(test); |
| |
| data->node.seq_start[HSR_PT_SLAVE_A] = 9; |
| data->node.seq_expected[HSR_PT_SLAVE_A] = 9; |
| data->node.seq_start[HSR_PT_SLAVE_B] = 9; |
| data->node.seq_expected[HSR_PT_SLAVE_B] = 9; |
| data->node.seq_out[HSR_PT_MASTER] = 8; |
| |
| data->frame.sequence_nr = 9; |
| KUNIT_EXPECT_EQ(test, 0, |
| prp_register_frame_out(&data->port, &data->frame)); |
| KUNIT_EXPECT_EQ(test, data->frame.sequence_nr, |
| data->node.seq_out[HSR_PT_MASTER]); |
| check_prp_counters(test, data, 9, 10, 9, 9); |
| |
| data->frame.sequence_nr = 10; |
| KUNIT_EXPECT_EQ(test, 0, |
| prp_register_frame_out(&data->port, &data->frame)); |
| KUNIT_EXPECT_EQ(test, data->frame.sequence_nr, |
| data->node.seq_out[HSR_PT_MASTER]); |
| check_prp_counters(test, data, 9, 11, 9, 9); |
| |
| data->frame.sequence_nr = 9; |
| data->port_rcv.type = HSR_PT_SLAVE_B; |
| KUNIT_EXPECT_EQ(test, 1, |
| prp_register_frame_out(&data->port, &data->frame)); |
| check_prp_counters(test, data, 10, 11, 10, 10); |
| |
| data->frame.sequence_nr = 10; |
| data->port_rcv.type = HSR_PT_SLAVE_B; |
| KUNIT_EXPECT_EQ(test, 1, |
| prp_register_frame_out(&data->port, &data->frame)); |
| check_prp_counters(test, data, 11, 11, 11, 11); |
| } |
| |
| static struct kunit_case prp_dup_discard_test_cases[] = { |
| KUNIT_CASE(prp_dup_discard_forward), |
| KUNIT_CASE(prp_dup_discard_inside_dropwindow), |
| KUNIT_CASE(prp_dup_discard_node_timeout), |
| KUNIT_CASE(prp_dup_discard_out_of_sequence), |
| KUNIT_CASE(prp_dup_discard_lan_b_late), |
| {} |
| }; |
| |
| static struct kunit_suite prp_dup_discard_suite = { |
| .name = "prp_duplicate_discard", |
| .test_cases = prp_dup_discard_test_cases, |
| }; |
| |
| kunit_test_suite(prp_dup_discard_suite); |
| |
| MODULE_LICENSE("GPL"); |
| MODULE_DESCRIPTION("KUnit tests for PRP duplicate discard"); |
| MODULE_AUTHOR("Jaakko Karrenpalo <jkarrenpalo@gmail.com>"); |