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
> 



Reply via email to