Jakub Kicinski wrote: > GRO test groups the cases into categories, e.g. "tcp" case > checks coalescing in presence of: > - packets with bad csum, > - sequence number mismatch, > - timestamp option value mismatch, > - different TCP options. > > Since we now have TAP support grouping the cases like that > lowers our reporting granularity. This matters even more for > NICs performing HW GRO and LRO since it appears that most > implementation have _some_ bugs. Flagging the whole group > of tests as failed prevents us from catching regressions > in the things that work today. > > Signed-off-by: Jakub Kicinski <[email protected]>
Reviewed-by: Willem de Bruijn <[email protected]> Thanks for doing this! Interesting that many devices do seem to fail some tests. > --- > tools/testing/selftests/drivers/net/gro.c | 399 ++++++++++++--------- > tools/testing/selftests/drivers/net/gro.py | 65 +++- > 2 files changed, 285 insertions(+), 179 deletions(-) > > diff --git a/tools/testing/selftests/drivers/net/gro.c > b/tools/testing/selftests/drivers/net/gro.c > index e894037d2e3e..a5838de97ba8 100644 > --- a/tools/testing/selftests/drivers/net/gro.c > +++ b/tools/testing/selftests/drivers/net/gro.c > @@ -3,26 +3,45 @@ > * This testsuite provides conformance testing for GRO coalescing. > * > * Test cases: > - * 1.data > + * > + * data_*: > * Data packets of the same size and same header setup with correct > * sequence numbers coalesce. The one exception being the last data > * packet coalesced: it can be smaller than the rest and coalesced > * as long as it is in the same flow. > - * 2.ack > + * - data_same: same size packets coalesce > + * - data_lrg_sml: large then small coalesces > + * - data_sml_lrg: small then large doesn't coalesce > + * > + * ack: > * Pure ACK does not coalesce. > - * 3.flags > - * Specific test cases: no packets with PSH, SYN, URG, RST set will > - * be coalesced. > - * 4.tcp > + * > + * flags_*: > + * No packets with PSH, SYN, URG, RST set will be coalesced. > + * - flags_psh, flags_syn, flags_rst, flags_urg > + * > + * tcp_*: > * Packets with incorrect checksum, non-consecutive seqno and > * different TCP header options shouldn't coalesce. Nit: given that > * some extension headers have paddings, such as timestamp, headers > - * that are padding differently would not be coalesced. > - * 5.ip: > - * Packets with different (ECN, TTL, TOS) header, ip options or > - * ip fragments (ipv6) shouldn't coalesce. > - * 6.large: > + * that are padded differently would not be coalesced. > + * - tcp_csum: incorrect checksum > + * - tcp_seq: non-consecutive sequence numbers > + * - tcp_ts: different timestamps > + * - tcp_opt: different TCP options > + * > + * ip_*: > + * Packets with different (ECN, TTL, TOS) header, IP options or > + * IP fragments shouldn't coalesce. > + * - ip_ecn, ip_tos: shared between IPv4/IPv6 > + * - ip_ttl, ip_opt, ip_frag4: IPv4 only > + * - ip_id_df*: IPv4 IP ID field coalescing tests > + * - ip_frag6, ip_v6ext_*: IPv6 only > + * > + * large_*: > * Packets larger than GRO_MAX_SIZE packets shouldn't coalesce. > + * - large_max: exceeding max size > + * - large_rem: remainder handling > * > * MSS is defined as 4096 - header because if it is too small > * (i.e. 1500 MTU - header), it will result in many packets, > @@ -95,7 +114,6 @@ static int tcp_offset = -1; > static int total_hdr_len = -1; > static int ethhdr_proto = -1; > static bool ipip; > -static const int num_flush_id_cases = 6; > > static void vlog(const char *fmt, ...) > { > @@ -127,19 +145,19 @@ static void setup_sock_filter(int fd) > /* Overridden later if exthdrs are used: */ > opt_ipproto_off = ipproto_off; > > - if (strcmp(testname, "ip") == 0) { > - if (proto == PF_INET) > - optlen = sizeof(struct ip_timestamp); > - else { > - BUILD_BUG_ON(sizeof(struct ip6_hbh) > MIN_EXTHDR_SIZE); > - BUILD_BUG_ON(sizeof(struct ip6_dest) > MIN_EXTHDR_SIZE); > - BUILD_BUG_ON(sizeof(struct ip6_frag) > MIN_EXTHDR_SIZE); > + if (strcmp(testname, "ip_opt") == 0) { > + optlen = sizeof(struct ip_timestamp); > + } else if (strcmp(testname, "ip_frag6") == 0 || > + strcmp(testname, "ip_v6ext_same") == 0 || > + strcmp(testname, "ip_v6ext_diff") == 0) { > + BUILD_BUG_ON(sizeof(struct ip6_hbh) > MIN_EXTHDR_SIZE); > + BUILD_BUG_ON(sizeof(struct ip6_dest) > MIN_EXTHDR_SIZE); > + BUILD_BUG_ON(sizeof(struct ip6_frag) > MIN_EXTHDR_SIZE); > > - /* same size for HBH and Fragment extension header > types */ > - optlen = MIN_EXTHDR_SIZE; > - opt_ipproto_off = ETH_HLEN + sizeof(struct ipv6hdr) > - + offsetof(struct ip6_ext, ip6e_nxt); > - } > + /* same size for HBH and Fragment extension header types */ > + optlen = MIN_EXTHDR_SIZE; > + opt_ipproto_off = ETH_HLEN + sizeof(struct ipv6hdr) > + + offsetof(struct ip6_ext, ip6e_nxt); > } > > /* this filter validates the following: > @@ -739,16 +757,6 @@ static void send_flush_id_case(int fd, struct > sockaddr_ll *daddr, int tcase) > } > } > > -static void test_flush_id(int fd, struct sockaddr_ll *daddr, char *fin_pkt) > -{ > - for (int i = 0; i < num_flush_id_cases; i++) { > - sleep(1); > - send_flush_id_case(fd, daddr, i); > - sleep(1); > - write_packet(fd, fin_pkt, total_hdr_len, daddr); > - } > -} > - > static void send_ipv6_exthdr(int fd, struct sockaddr_ll *daddr, char > *ext_data1, char *ext_data2) > { > static char buf[MAX_HDR_LEN + PAYLOAD_LEN]; > @@ -1008,108 +1016,128 @@ static void gro_sender(void) > daddr.sll_halen = ETH_ALEN; > create_packet(fin_pkt, PAYLOAD_LEN * 2, 0, 0, 1); > > - if (strcmp(testname, "data") == 0) { > + /* data sub-tests */ > + if (strcmp(testname, "data_same") == 0) { > send_data_pkts(txfd, &daddr, PAYLOAD_LEN, PAYLOAD_LEN); > write_packet(txfd, fin_pkt, total_hdr_len, &daddr); > - > + } else if (strcmp(testname, "data_lrg_sml") == 0) { > send_data_pkts(txfd, &daddr, PAYLOAD_LEN, PAYLOAD_LEN / 2); > write_packet(txfd, fin_pkt, total_hdr_len, &daddr); > - > + } else if (strcmp(testname, "data_sml_lrg") == 0) { > send_data_pkts(txfd, &daddr, PAYLOAD_LEN / 2, PAYLOAD_LEN); > write_packet(txfd, fin_pkt, total_hdr_len, &daddr); > + > + /* ack test */ > } else if (strcmp(testname, "ack") == 0) { > send_ack(txfd, &daddr); > write_packet(txfd, fin_pkt, total_hdr_len, &daddr); > - } else if (strcmp(testname, "flags") == 0) { > + > + /* flags sub-tests */ > + } else if (strcmp(testname, "flags_psh") == 0) { > send_flags(txfd, &daddr, 1, 0, 0, 0); > write_packet(txfd, fin_pkt, total_hdr_len, &daddr); > - > + } else if (strcmp(testname, "flags_syn") == 0) { > send_flags(txfd, &daddr, 0, 1, 0, 0); > write_packet(txfd, fin_pkt, total_hdr_len, &daddr); > - > + } else if (strcmp(testname, "flags_rst") == 0) { > send_flags(txfd, &daddr, 0, 0, 1, 0); > write_packet(txfd, fin_pkt, total_hdr_len, &daddr); > - > + } else if (strcmp(testname, "flags_urg") == 0) { > send_flags(txfd, &daddr, 0, 0, 0, 1); > write_packet(txfd, fin_pkt, total_hdr_len, &daddr); > - } else if (strcmp(testname, "tcp") == 0) { > + > + /* tcp sub-tests */ > + } else if (strcmp(testname, "tcp_csum") == 0) { > send_changed_checksum(txfd, &daddr); > - /* Adding sleep before sending FIN so that it is not > - * received prior to other packets. > - */ > usleep(fin_delay_us); > write_packet(txfd, fin_pkt, total_hdr_len, &daddr); > - > + } else if (strcmp(testname, "tcp_seq") == 0) { > send_changed_seq(txfd, &daddr); > usleep(fin_delay_us); > write_packet(txfd, fin_pkt, total_hdr_len, &daddr); > - > + } else if (strcmp(testname, "tcp_ts") == 0) { > send_changed_ts(txfd, &daddr); > usleep(fin_delay_us); > write_packet(txfd, fin_pkt, total_hdr_len, &daddr); > - > + } else if (strcmp(testname, "tcp_opt") == 0) { > send_diff_opt(txfd, &daddr); > usleep(fin_delay_us); > write_packet(txfd, fin_pkt, total_hdr_len, &daddr); > - } else if (strcmp(testname, "ip") == 0) { > + > + /* ip sub-tests - shared between IPv4 and IPv6 */ > + } else if (strcmp(testname, "ip_ecn") == 0) { > send_changed_ECN(txfd, &daddr); > write_packet(txfd, fin_pkt, total_hdr_len, &daddr); > - > + } else if (strcmp(testname, "ip_tos") == 0) { > send_changed_tos(txfd, &daddr); > write_packet(txfd, fin_pkt, total_hdr_len, &daddr); > - if (proto == PF_INET) { > - /* Modified packets may be received out of order. > - * Sleep function added to enforce test boundaries > - * so that fin pkts are not received prior to other > pkts. > - */ > - sleep(1); > - send_changed_ttl(txfd, &daddr); > - write_packet(txfd, fin_pkt, total_hdr_len, &daddr); > > - sleep(1); > - send_ip_options(txfd, &daddr); > - sleep(1); > - write_packet(txfd, fin_pkt, total_hdr_len, &daddr); > + /* ip sub-tests - IPv4 only */ > + } else if (strcmp(testname, "ip_ttl") == 0) { > + send_changed_ttl(txfd, &daddr); > + write_packet(txfd, fin_pkt, total_hdr_len, &daddr); > + } else if (strcmp(testname, "ip_opt") == 0) { > + send_ip_options(txfd, &daddr); > + usleep(fin_delay_us); > + write_packet(txfd, fin_pkt, total_hdr_len, &daddr); > + } else if (strcmp(testname, "ip_frag4") == 0) { > + send_fragment4(txfd, &daddr); > + usleep(fin_delay_us); > + write_packet(txfd, fin_pkt, total_hdr_len, &daddr); > + } else if (strcmp(testname, "ip_id_df1_inc") == 0) { > + send_flush_id_case(txfd, &daddr, 0); > + usleep(fin_delay_us); > + write_packet(txfd, fin_pkt, total_hdr_len, &daddr); > + } else if (strcmp(testname, "ip_id_df1_fixed") == 0) { > + send_flush_id_case(txfd, &daddr, 1); > + usleep(fin_delay_us); > + write_packet(txfd, fin_pkt, total_hdr_len, &daddr); > + } else if (strcmp(testname, "ip_id_df0_inc") == 0) { > + send_flush_id_case(txfd, &daddr, 2); > + usleep(fin_delay_us); > + write_packet(txfd, fin_pkt, total_hdr_len, &daddr); > + } else if (strcmp(testname, "ip_id_df0_fixed") == 0) { > + send_flush_id_case(txfd, &daddr, 3); > + usleep(fin_delay_us); > + write_packet(txfd, fin_pkt, total_hdr_len, &daddr); > + } else if (strcmp(testname, "ip_id_df1_inc_fixed") == 0) { > + send_flush_id_case(txfd, &daddr, 4); > + usleep(fin_delay_us); > + write_packet(txfd, fin_pkt, total_hdr_len, &daddr); > + } else if (strcmp(testname, "ip_id_df1_fixed_inc") == 0) { > + send_flush_id_case(txfd, &daddr, 5); (not critical at all) now that we no longer loop over the cases, might be nice to have descriptive enums for the various flush_id cases. > + usleep(fin_delay_us); > + write_packet(txfd, fin_pkt, total_hdr_len, &daddr); > > - sleep(1); > - send_fragment4(txfd, &daddr); > - sleep(1); > - write_packet(txfd, fin_pkt, total_hdr_len, &daddr); > + /* ip sub-tests - IPv6 only */ > + } else if (strcmp(testname, "ip_frag6") == 0) { > + send_fragment6(txfd, &daddr); > + usleep(fin_delay_us); > + write_packet(txfd, fin_pkt, total_hdr_len, &daddr); > + } else if (strcmp(testname, "ip_v6ext_same") == 0) { > + send_ipv6_exthdr(txfd, &daddr, EXT_PAYLOAD_1, EXT_PAYLOAD_1); > + usleep(fin_delay_us); > + write_packet(txfd, fin_pkt, total_hdr_len, &daddr); > + } else if (strcmp(testname, "ip_v6ext_diff") == 0) { > + send_ipv6_exthdr(txfd, &daddr, EXT_PAYLOAD_1, EXT_PAYLOAD_2); > + usleep(fin_delay_us); > + write_packet(txfd, fin_pkt, total_hdr_len, &daddr); > > - test_flush_id(txfd, &daddr, fin_pkt); > - } else if (proto == PF_INET6) { > - sleep(1); > - send_fragment6(txfd, &daddr); > - sleep(1); > - write_packet(txfd, fin_pkt, total_hdr_len, &daddr); > - > - sleep(1); > - /* send IPv6 packets with ext header with same payload > */ > - send_ipv6_exthdr(txfd, &daddr, EXT_PAYLOAD_1, > EXT_PAYLOAD_1); > - sleep(1); > - write_packet(txfd, fin_pkt, total_hdr_len, &daddr); > - > - sleep(1); > - /* send IPv6 packets with ext header with different > payload */ > - send_ipv6_exthdr(txfd, &daddr, EXT_PAYLOAD_1, > EXT_PAYLOAD_2); > - sleep(1); > - write_packet(txfd, fin_pkt, total_hdr_len, &daddr); > - } > - } else if (strcmp(testname, "large") == 0) { > - /* 20 is the difference between min iphdr size > - * and min ipv6hdr size. Like MAX_HDR_SIZE, > - * MAX_PAYLOAD is defined with the larger header of the two. > - */ > + /* large sub-tests */ > + } else if (strcmp(testname, "large_max") == 0) { > int offset = (proto == PF_INET && !ipip) ? 20 : 0; > int remainder = (MAX_PAYLOAD + offset) % MSS; > > send_large(txfd, &daddr, remainder); > write_packet(txfd, fin_pkt, total_hdr_len, &daddr); > + } else if (strcmp(testname, "large_rem") == 0) { > + int offset = (proto == PF_INET && !ipip) ? 20 : 0; > + int remainder = (MAX_PAYLOAD + offset) % MSS; > > send_large(txfd, &daddr, remainder + 1); > write_packet(txfd, fin_pkt, total_hdr_len, &daddr); > } else { > - error(1, 0, "Unknown testcase"); > + error(1, 0, "Unknown testcase: %s", testname); > } > > if (close(txfd)) > @@ -1132,126 +1160,153 @@ static void gro_receiver(void) > > memset(correct_payload, 0, sizeof(correct_payload)); > > - if (strcmp(testname, "data") == 0) { > + /* data sub-tests */ > + if (strcmp(testname, "data_same") == 0) { > printf("pure data packet of same size: "); > correct_payload[0] = PAYLOAD_LEN * 2; > check_recv_pkts(rxfd, correct_payload, 1); > - > + } else if (strcmp(testname, "data_lrg_sml") == 0) { > printf("large data packets followed by a smaller one: "); > correct_payload[0] = PAYLOAD_LEN * 1.5; > check_recv_pkts(rxfd, correct_payload, 1); > - > + } else if (strcmp(testname, "data_sml_lrg") == 0) { > printf("small data packets followed by a larger one: "); > correct_payload[0] = PAYLOAD_LEN / 2; > correct_payload[1] = PAYLOAD_LEN; > check_recv_pkts(rxfd, correct_payload, 2); > + > + /* ack test */ > } else if (strcmp(testname, "ack") == 0) { > printf("duplicate ack and pure ack: "); > check_recv_pkts(rxfd, correct_payload, 3); > - } else if (strcmp(testname, "flags") == 0) { > + > + /* flags sub-tests */ > + } else if (strcmp(testname, "flags_psh") == 0) { > correct_payload[0] = PAYLOAD_LEN * 3; > correct_payload[1] = PAYLOAD_LEN * 2; > - > printf("psh flag ends coalescing: "); > check_recv_pkts(rxfd, correct_payload, 2); > - > + } else if (strcmp(testname, "flags_syn") == 0) { > correct_payload[0] = PAYLOAD_LEN * 2; > correct_payload[1] = 0; > correct_payload[2] = PAYLOAD_LEN * 2; > printf("syn flag ends coalescing: "); > check_recv_pkts(rxfd, correct_payload, 3); > - > + } else if (strcmp(testname, "flags_rst") == 0) { > + correct_payload[0] = PAYLOAD_LEN * 2; > + correct_payload[1] = 0; > + correct_payload[2] = PAYLOAD_LEN * 2; > printf("rst flag ends coalescing: "); > check_recv_pkts(rxfd, correct_payload, 3); > - > + } else if (strcmp(testname, "flags_urg") == 0) { > + correct_payload[0] = PAYLOAD_LEN * 2; > + correct_payload[1] = 0; > + correct_payload[2] = PAYLOAD_LEN * 2; > printf("urg flag ends coalescing: "); > check_recv_pkts(rxfd, correct_payload, 3); > - } else if (strcmp(testname, "tcp") == 0) { > + > + /* tcp sub-tests */ > + } else if (strcmp(testname, "tcp_csum") == 0) { > correct_payload[0] = PAYLOAD_LEN; > correct_payload[1] = PAYLOAD_LEN; > + printf("changed checksum does not coalesce: "); > + check_recv_pkts(rxfd, correct_payload, 2); > + } else if (strcmp(testname, "tcp_seq") == 0) { > + correct_payload[0] = PAYLOAD_LEN; > + correct_payload[1] = PAYLOAD_LEN; > + printf("Wrong Seq number doesn't coalesce: "); > + check_recv_pkts(rxfd, correct_payload, 2); > + } else if (strcmp(testname, "tcp_ts") == 0) { > + correct_payload[0] = PAYLOAD_LEN * 2; > + correct_payload[1] = PAYLOAD_LEN; > correct_payload[2] = PAYLOAD_LEN; > correct_payload[3] = PAYLOAD_LEN; > - > - printf("changed checksum does not coalesce: "); > - check_recv_pkts(rxfd, correct_payload, 2); > - > - printf("Wrong Seq number doesn't coalesce: "); > - check_recv_pkts(rxfd, correct_payload, 2); > - > printf("Different timestamp doesn't coalesce: "); > - correct_payload[0] = PAYLOAD_LEN * 2; > check_recv_pkts(rxfd, correct_payload, 4); > - > - printf("Different options doesn't coalesce: "); > + } else if (strcmp(testname, "tcp_opt") == 0) { > correct_payload[0] = PAYLOAD_LEN * 2; > + correct_payload[1] = PAYLOAD_LEN; > + printf("Different options doesn't coalesce: "); > check_recv_pkts(rxfd, correct_payload, 2); > - } else if (strcmp(testname, "ip") == 0) { > + > + /* ip sub-tests - shared between IPv4 and IPv6 */ > + } else if (strcmp(testname, "ip_ecn") == 0) { > correct_payload[0] = PAYLOAD_LEN; > correct_payload[1] = PAYLOAD_LEN; > - > printf("different ECN doesn't coalesce: "); > check_recv_pkts(rxfd, correct_payload, 2); > - > + } else if (strcmp(testname, "ip_tos") == 0) { > + correct_payload[0] = PAYLOAD_LEN; > + correct_payload[1] = PAYLOAD_LEN; > printf("different tos doesn't coalesce: "); > check_recv_pkts(rxfd, correct_payload, 2); > > - if (proto == PF_INET) { > - printf("different ttl doesn't coalesce: "); > - check_recv_pkts(rxfd, correct_payload, 2); > + /* ip sub-tests - IPv4 only */ > + } else if (strcmp(testname, "ip_ttl") == 0) { > + correct_payload[0] = PAYLOAD_LEN; > + correct_payload[1] = PAYLOAD_LEN; > + printf("different ttl doesn't coalesce: "); > + check_recv_pkts(rxfd, correct_payload, 2); > + } else if (strcmp(testname, "ip_opt") == 0) { > + correct_payload[0] = PAYLOAD_LEN; > + correct_payload[1] = PAYLOAD_LEN; > + correct_payload[2] = PAYLOAD_LEN; > + printf("ip options doesn't coalesce: "); > + check_recv_pkts(rxfd, correct_payload, 3); > + } else if (strcmp(testname, "ip_frag4") == 0) { > + correct_payload[0] = PAYLOAD_LEN; > + correct_payload[1] = PAYLOAD_LEN; > + printf("fragmented ip4 doesn't coalesce: "); > + check_recv_pkts(rxfd, correct_payload, 2); > + } else if (strcmp(testname, "ip_id_df1_inc") == 0) { > + printf("DF=1, Incrementing - should coalesce: "); > + correct_payload[0] = PAYLOAD_LEN * 2; > + check_recv_pkts(rxfd, correct_payload, 1); > + } else if (strcmp(testname, "ip_id_df1_fixed") == 0) { > + printf("DF=1, Fixed - should coalesce: "); > + correct_payload[0] = PAYLOAD_LEN * 2; > + check_recv_pkts(rxfd, correct_payload, 1); > + } else if (strcmp(testname, "ip_id_df0_inc") == 0) { > + printf("DF=0, Incrementing - should coalesce: "); > + correct_payload[0] = PAYLOAD_LEN * 2; > + check_recv_pkts(rxfd, correct_payload, 1); > + } else if (strcmp(testname, "ip_id_df0_fixed") == 0) { > + printf("DF=0, Fixed - should coalesce: "); > + correct_payload[0] = PAYLOAD_LEN * 2; > + check_recv_pkts(rxfd, correct_payload, 1); > + } else if (strcmp(testname, "ip_id_df1_inc_fixed") == 0) { > + printf("DF=1, 2 Incrementing and one fixed - should coalesce > only first 2 packets: "); > + correct_payload[0] = PAYLOAD_LEN * 2; > + correct_payload[1] = PAYLOAD_LEN; > + check_recv_pkts(rxfd, correct_payload, 2); > + } else if (strcmp(testname, "ip_id_df1_fixed_inc") == 0) { > + printf("DF=1, 2 Fixed and one incrementing - should coalesce > only first 2 packets: "); > + correct_payload[0] = PAYLOAD_LEN * 2; > + correct_payload[1] = PAYLOAD_LEN; > + check_recv_pkts(rxfd, correct_payload, 2); > > - printf("ip options doesn't coalesce: "); > - correct_payload[2] = PAYLOAD_LEN; > - check_recv_pkts(rxfd, correct_payload, 3); > + /* ip sub-tests - IPv6 only */ > + } else if (strcmp(testname, "ip_frag6") == 0) { > + /* GRO doesn't check for ipv6 hop limit when flushing. > + * Hence no corresponding test to the ipv4 case. > + */ > + printf("fragmented ip6 doesn't coalesce: "); > + correct_payload[0] = PAYLOAD_LEN * 2; > + correct_payload[1] = PAYLOAD_LEN; > + correct_payload[2] = PAYLOAD_LEN; > + check_recv_pkts(rxfd, correct_payload, 3); > + } else if (strcmp(testname, "ip_v6ext_same") == 0) { > + printf("ipv6 with ext header does coalesce: "); > + correct_payload[0] = PAYLOAD_LEN * 2; > + check_recv_pkts(rxfd, correct_payload, 1); > + } else if (strcmp(testname, "ip_v6ext_diff") == 0) { > + printf("ipv6 with ext header with different payloads doesn't > coalesce: "); > + correct_payload[0] = PAYLOAD_LEN; > + correct_payload[1] = PAYLOAD_LEN; > + check_recv_pkts(rxfd, correct_payload, 2); > > - printf("fragmented ip4 doesn't coalesce: "); > - check_recv_pkts(rxfd, correct_payload, 2); > - > - /* is_atomic checks */ > - printf("DF=1, Incrementing - should coalesce: "); > - correct_payload[0] = PAYLOAD_LEN * 2; > - check_recv_pkts(rxfd, correct_payload, 1); > - > - printf("DF=1, Fixed - should coalesce: "); > - correct_payload[0] = PAYLOAD_LEN * 2; > - check_recv_pkts(rxfd, correct_payload, 1); > - > - printf("DF=0, Incrementing - should coalesce: "); > - correct_payload[0] = PAYLOAD_LEN * 2; > - check_recv_pkts(rxfd, correct_payload, 1); > - > - printf("DF=0, Fixed - should coalesce: "); > - correct_payload[0] = PAYLOAD_LEN * 2; > - check_recv_pkts(rxfd, correct_payload, 1); > - > - printf("DF=1, 2 Incrementing and one fixed - should > coalesce only first 2 packets: "); > - correct_payload[0] = PAYLOAD_LEN * 2; > - correct_payload[1] = PAYLOAD_LEN; > - check_recv_pkts(rxfd, correct_payload, 2); > - > - printf("DF=1, 2 Fixed and one incrementing - should > coalesce only first 2 packets: "); > - correct_payload[0] = PAYLOAD_LEN * 2; > - correct_payload[1] = PAYLOAD_LEN; > - check_recv_pkts(rxfd, correct_payload, 2); > - } else if (proto == PF_INET6) { > - /* GRO doesn't check for ipv6 hop limit when flushing. > - * Hence no corresponding test to the ipv4 case. > - */ > - printf("fragmented ip6 doesn't coalesce: "); > - correct_payload[0] = PAYLOAD_LEN * 2; > - correct_payload[1] = PAYLOAD_LEN; > - correct_payload[2] = PAYLOAD_LEN; > - check_recv_pkts(rxfd, correct_payload, 3); > - > - printf("ipv6 with ext header does coalesce: "); > - correct_payload[0] = PAYLOAD_LEN * 2; > - check_recv_pkts(rxfd, correct_payload, 1); > - > - printf("ipv6 with ext header with different payloads > doesn't coalesce: "); > - correct_payload[0] = PAYLOAD_LEN; > - correct_payload[1] = PAYLOAD_LEN; > - check_recv_pkts(rxfd, correct_payload, 2); > - } > - } else if (strcmp(testname, "large") == 0) { > + /* large sub-tests */ > + } else if (strcmp(testname, "large_max") == 0) { > int offset = (proto == PF_INET && !ipip) ? 20 : 0; > int remainder = (MAX_PAYLOAD + offset) % MSS; > > @@ -1259,14 +1314,18 @@ static void gro_receiver(void) > correct_payload[1] = remainder; > printf("Shouldn't coalesce if exceed IP max pkt size: "); > check_recv_pkts(rxfd, correct_payload, 2); > + } else if (strcmp(testname, "large_rem") == 0) { > + int offset = (proto == PF_INET && !ipip) ? 20 : 0; > + int remainder = (MAX_PAYLOAD + offset) % MSS; > > /* last segment sent individually, doesn't start new segment */ > - correct_payload[0] = correct_payload[0] - remainder; > + correct_payload[0] = (MAX_PAYLOAD + offset) - remainder; > correct_payload[1] = remainder + 1; > correct_payload[2] = remainder + 1; > + printf("last segment sent individually: "); > check_recv_pkts(rxfd, correct_payload, 3); > } else { > - error(1, 0, "Test case error, should never trigger"); > + error(1, 0, "Test case error: unknown testname %s", testname); > } > > if (close(rxfd)) > diff --git a/tools/testing/selftests/drivers/net/gro.py > b/tools/testing/selftests/drivers/net/gro.py > index 112560482d04..08b22d7857bd 100755 > --- a/tools/testing/selftests/drivers/net/gro.py > +++ b/tools/testing/selftests/drivers/net/gro.py > @@ -9,12 +9,29 @@ binary in different configurations and checking for correct > packet > coalescing behavior. > > Test cases: > - - data: Data packets with same size/headers and correct seq numbers > coalesce > + - data_same: Same size data packets coalesce > + - data_lrg_sml: Large packet followed by smaller one coalesces > + - data_sml_lrg: Small packet followed by larger one doesn't coalesce > - ack: Pure ACK packets do not coalesce > - - flags: Packets with PSH, SYN, URG, RST flags do not coalesce > - - tcp: Packets with incorrect checksum, non-consecutive seqno don't > coalesce > - - ip: Packets with different ECN, TTL, TOS, or IP options don't coalesce > - - large: Packets larger than GRO_MAX_SIZE don't coalesce > + - flags_psh: Packets with PSH flag don't coalesce > + - flags_syn: Packets with SYN flag don't coalesce > + - flags_rst: Packets with RST flag don't coalesce > + - flags_urg: Packets with URG flag don't coalesce > + - tcp_csum: Packets with incorrect checksum don't coalesce > + - tcp_seq: Packets with non-consecutive seqno don't coalesce > + - tcp_ts: Packets with different timestamp options don't coalesce > + - tcp_opt: Packets with different TCP options don't coalesce > + - ip_ecn: Packets with different ECN don't coalesce > + - ip_tos: Packets with different TOS don't coalesce > + - ip_ttl: (IPv4) Packets with different TTL don't coalesce > + - ip_opt: (IPv4) Packets with IP options don't coalesce > + - ip_frag4: (IPv4) IPv4 fragments don't coalesce > + - ip_id_df*: (IPv4) IP ID field coalescing tests > + - ip_frag6: (IPv6) IPv6 fragments don't coalesce > + - ip_v6ext_same: (IPv6) IPv6 ext header with same payload coalesces > + - ip_v6ext_diff: (IPv6) IPv6 ext header with different payload doesn't > coalesce > + - large_max: Packets exceeding GRO_MAX_SIZE don't coalesce > + - large_rem: Large packet remainder handling > """ > > import os > @@ -107,8 +124,8 @@ from lib.py import ksft_variants > cfg.remote_feat = ethtool(f"-k {cfg.remote_ifname}", > host=cfg.remote, json=True)[0] > > - # "large" test needs at least 4k MTU > - if test_name == "large": > + # "large_*" tests need at least 4k MTU > + if test_name.startswith("large_"): > _set_mtu_restore(cfg.dev, 4096, None) > _set_mtu_restore(cfg.remote_dev, 4096, cfg.remote) > > @@ -165,11 +182,41 @@ from lib.py import ksft_variants > def _gro_variants(): > """Generator that yields all combinations of protocol and test types.""" > > + # Tests that work for all protocols > + common_tests = [ > + "data_same", "data_lrg_sml", "data_sml_lrg", > + "ack", > + "flags_psh", "flags_syn", "flags_rst", "flags_urg", > + "tcp_csum", "tcp_seq", "tcp_ts", "tcp_opt", > + "ip_ecn", "ip_tos", > + "large_max", "large_rem", > + ] > + > + # Tests specific to IPv4 > + ipv4_tests = [ > + "ip_ttl", "ip_opt", "ip_frag4", > + "ip_id_df1_inc", "ip_id_df1_fixed", > + "ip_id_df0_inc", "ip_id_df0_fixed", > + "ip_id_df1_inc_fixed", "ip_id_df1_fixed_inc", > + ] > + > + # Tests specific to IPv6 > + ipv6_tests = [ > + "ip_frag6", "ip_v6ext_same", "ip_v6ext_diff", > + ] > + > for mode in ["sw", "hw", "lro"]: > for protocol in ["ipv4", "ipv6", "ipip"]: > - for test_name in ["data", "ack", "flags", "tcp", "ip", "large"]: > + for test_name in common_tests: > yield mode, protocol, test_name > > + if protocol in ["ipv4", "ipip"]: > + for test_name in ipv4_tests: > + yield mode, protocol, test_name > + elif protocol == "ipv6": > + for test_name in ipv6_tests: > + yield mode, protocol, test_name > + > > @ksft_variants(_gro_variants()) > def test(cfg, mode, protocol, test_name): > @@ -210,7 +257,7 @@ from lib.py import ksft_variants > > ksft_pr(rx_proc) > > - if test_name == "large" and os.environ.get("KSFT_MACHINE_SLOW"): > + if test_name.startswith("large_") and > os.environ.get("KSFT_MACHINE_SLOW"): > ksft_pr(f"Ignoring {protocol}/{test_name} failure due to slow > environment") > return > > -- > 2.52.0 >
