[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <willemdebruijn.kernel.3ad3dec6c886b@gmail.com>
Date: Sun, 11 Jan 2026 12:12:09 -0500
From: Willem de Bruijn <willemdebruijn.kernel@...il.com>
To: Jakub Kicinski <kuba@...nel.org>,
davem@...emloft.net
Cc: netdev@...r.kernel.org,
edumazet@...gle.com,
pabeni@...hat.com,
andrew+netdev@...n.ch,
horms@...nel.org,
shuah@...nel.org,
linux-kselftest@...r.kernel.org,
sdf@...ichev.me,
willemb@...gle.com,
petrm@...dia.com,
Jakub Kicinski <kuba@...nel.org>
Subject: Re: [PATCH net-next v2 6/6] selftests: drv-net: gro: break out all
individual test cases
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 <kuba@...nel.org>
Reviewed-by: Willem de Bruijn <willemb@...gle.com>
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
>
Powered by blists - more mailing lists