[PATCH v7 net-next 03/13] selftests/net: gro: add self-test for TCP CWR flag

2026-01-03 Thread chia-yu . chang
From: Chia-Yu Chang 

Currently, GRO does not flush packets when the CWR bit is set.
A corresponding self-test is being added, in which the CWR flag
is set for two consecutive packets, but the first packet with the
CWR flag set will not be flushed immediately.

+===+==+===+===+
| Packet id | CWR flag |Payload| Flushing? |
+===+==+===+===+
| 0 | 0|  PAYLOAD_LEN  | 0 |
|...| 0|  PAYLOAD_LEN  | 1 |
+---+--+---+---+
| NUM_PACKETS/2 - 1 | 1|  payload_len  | 0 |
|   NUM_PACKETS/2   | 1|  payload_len  | 1 |
+---+--+---+---+
|...| 0|  PAYLOAD_LEN  | 0 |
|   NUM_PACKETS | 0|  PAYLOAD_LEN  | 1 |
+===+==+===+===+

Signed-off-by: Chia-Yu Chang 
Acked-by: Paolo Abeni 

---
v7:
- Update comments
---
 tools/testing/selftests/drivers/net/gro.c | 81 ---
 1 file changed, 58 insertions(+), 23 deletions(-)

diff --git a/tools/testing/selftests/drivers/net/gro.c 
b/tools/testing/selftests/drivers/net/gro.c
index e894037d2e3e..736da13f85a0 100644
--- a/tools/testing/selftests/drivers/net/gro.c
+++ b/tools/testing/selftests/drivers/net/gro.c
@@ -11,8 +11,8 @@
  * 2.ack
  *  Pure ACK does not coalesce.
  * 3.flags
- *  Specific test cases: no packets with PSH, SYN, URG, RST set will
- *  be coalesced.
+ *  Specific test cases: no packets with PSH, SYN, URG, RST, CWR set
+ *  will be coalesced.
  * 4.tcp
  *  Packets with incorrect checksum, non-consecutive seqno and
  *  different TCP header options shouldn't coalesce. Nit: given that
@@ -333,32 +333,58 @@ static void create_packet(void *buf, int seq_offset, int 
ack_offset,
fill_datalinklayer(buf);
 }
 
-/* send one extra flag, not first and not last pkt */
-static void send_flags(int fd, struct sockaddr_ll *daddr, int psh, int syn,
-  int rst, int urg)
+#ifndef TH_CWR
+#define TH_CWR 0x80
+#endif
+static void set_flags(struct tcphdr *tcph, int payload_len, int psh, int syn,
+ int rst, int urg, int cwr)
 {
-   static char flag_buf[MAX_HDR_LEN + PAYLOAD_LEN];
-   static char buf[MAX_HDR_LEN + PAYLOAD_LEN];
-   int payload_len, pkt_size, flag, i;
-   struct tcphdr *tcph;
-
-   payload_len = PAYLOAD_LEN * psh;
-   pkt_size = total_hdr_len + payload_len;
-   flag = NUM_PACKETS / 2;
-
-   create_packet(flag_buf, flag * payload_len, 0, payload_len, 0);
-
-   tcph = (struct tcphdr *)(flag_buf + tcp_offset);
tcph->psh = psh;
tcph->syn = syn;
tcph->rst = rst;
tcph->urg = urg;
+   if (cwr)
+   tcph->th_flags |= TH_CWR;
+   else
+   tcph->th_flags &= ~TH_CWR;
tcph->check = 0;
tcph->check = tcp_checksum(tcph, payload_len);
+}
+
+/* send extra flags of the (NUM_PACKETS / 2) and (NUM_PACKETS / 2 - 1)
+ * pkts, not first and not last pkt
+ */
+static void send_flags(int fd, struct sockaddr_ll *daddr, int psh, int syn,
+  int rst, int urg, int cwr)
+{
+   static char flag_buf[2][MAX_HDR_LEN + PAYLOAD_LEN];
+   static char buf[MAX_HDR_LEN + PAYLOAD_LEN];
+   int payload_len, pkt_size, i;
+   struct tcphdr *tcph;
+   int flag[2];
+
+   payload_len = PAYLOAD_LEN * (psh || cwr);
+   pkt_size = total_hdr_len + payload_len;
+   flag[0] = NUM_PACKETS / 2;
+   flag[1] = NUM_PACKETS / 2 - 1;
+
+   /* Create and configure packets with flags
+*/
+   for (i = 0; i < 2; i++) {
+   if (flag[i] > 0) {
+   create_packet(flag_buf[i], flag[i] * payload_len, 0,
+ payload_len, 0);
+   tcph = (struct tcphdr *)(flag_buf[i] + tcp_offset);
+   set_flags(tcph, payload_len, psh, syn, rst, urg, cwr);
+   }
+   }
 
for (i = 0; i < NUM_PACKETS + 1; i++) {
-   if (i == flag) {
-   write_packet(fd, flag_buf, pkt_size, daddr);
+   if (i == flag[0]) {
+   write_packet(fd, flag_buf[0], pkt_size, daddr);
+   continue;
+   } else if (i == flag[1] && cwr) {
+   write_packet(fd, flag_buf[1], pkt_size, daddr);
continue;
}
create_packet(buf, i * PAYLOAD_LEN, 0, PAYLOAD_LEN, 0);
@@ -1021,16 +1047,19 @@ static void gro_sender(void)
send_ack(txfd, &daddr);
write_packet(txfd, fin_pkt, total_hdr_len, &daddr);
} else if (strcmp(testname, "flags") == 0) {
-   send_flags(txfd, &daddr, 1, 0, 0, 0);
+   send_flags(txfd, &daddr, 1, 0, 0, 0, 0);
   

[PATCH v7 net-next 03/13] selftests/net: gro: add self-test for TCP CWR flag

2025-12-01 Thread chia-yu . chang
From: Chia-Yu Chang 

Currently, GRO does not flush packets when the CWR bit is set.
A corresponding self-test is being added, in which the CWR flag
is set for two consecutive packets, but the first packet with the
CWR flag set will not be flushed immediately.

+===+==+===+===+
| Packet id | CWR flag |Payload| Flushing? |
+===+==+===+===+
| 0 | 0|  PAYLOAD_LEN  | 0 |
|...| 0|  PAYLOAD_LEN  | 1 |
+---+--+---+---+
| NUM_PACKETS/2 - 1 | 1|  payload_len  | 0 |
|   NUM_PACKETS/2   | 1|  payload_len  | 1 |
+---+--+---+---+
|...| 0|  PAYLOAD_LEN  | 0 |
|   NUM_PACKETS | 0|  PAYLOAD_LEN  | 1 |
+===+==+===+===+

Signed-off-by: Chia-Yu Chang 
Acked-by: Paolo Abeni 

---
v7:
- Update comments
---
 tools/testing/selftests/drivers/net/gro.c | 81 ---
 1 file changed, 58 insertions(+), 23 deletions(-)

diff --git a/tools/testing/selftests/drivers/net/gro.c 
b/tools/testing/selftests/drivers/net/gro.c
index 995b492f5bcb..00fef326efdf 100644
--- a/tools/testing/selftests/drivers/net/gro.c
+++ b/tools/testing/selftests/drivers/net/gro.c
@@ -11,8 +11,8 @@
  * 2.ack
  *  Pure ACK does not coalesce.
  * 3.flags
- *  Specific test cases: no packets with PSH, SYN, URG, RST set will
- *  be coalesced.
+ *  Specific test cases: no packets with PSH, SYN, URG, RST, CWR set
+ *  will be coalesced.
  * 4.tcp
  *  Packets with incorrect checksum, non-consecutive seqno and
  *  different TCP header options shouldn't coalesce. Nit: given that
@@ -333,32 +333,58 @@ static void create_packet(void *buf, int seq_offset, int 
ack_offset,
fill_datalinklayer(buf);
 }
 
-/* send one extra flag, not first and not last pkt */
-static void send_flags(int fd, struct sockaddr_ll *daddr, int psh, int syn,
-  int rst, int urg)
+#ifndef TH_CWR
+#define TH_CWR 0x80
+#endif
+static void set_flags(struct tcphdr *tcph, int payload_len, int psh, int syn,
+ int rst, int urg, int cwr)
 {
-   static char flag_buf[MAX_HDR_LEN + PAYLOAD_LEN];
-   static char buf[MAX_HDR_LEN + PAYLOAD_LEN];
-   int payload_len, pkt_size, flag, i;
-   struct tcphdr *tcph;
-
-   payload_len = PAYLOAD_LEN * psh;
-   pkt_size = total_hdr_len + payload_len;
-   flag = NUM_PACKETS / 2;
-
-   create_packet(flag_buf, flag * payload_len, 0, payload_len, 0);
-
-   tcph = (struct tcphdr *)(flag_buf + tcp_offset);
tcph->psh = psh;
tcph->syn = syn;
tcph->rst = rst;
tcph->urg = urg;
+   if (cwr)
+   tcph->th_flags |= TH_CWR;
+   else
+   tcph->th_flags &= ~TH_CWR;
tcph->check = 0;
tcph->check = tcp_checksum(tcph, payload_len);
+}
+
+/* send extra flags of the (NUM_PACKETS / 2) and (NUM_PACKETS / 2 - 1)
+ * pkts, not first and not last pkt
+ */
+static void send_flags(int fd, struct sockaddr_ll *daddr, int psh, int syn,
+  int rst, int urg, int cwr)
+{
+   static char flag_buf[2][MAX_HDR_LEN + PAYLOAD_LEN];
+   static char buf[MAX_HDR_LEN + PAYLOAD_LEN];
+   int payload_len, pkt_size, i;
+   struct tcphdr *tcph;
+   int flag[2];
+
+   payload_len = PAYLOAD_LEN * (psh || cwr);
+   pkt_size = total_hdr_len + payload_len;
+   flag[0] = NUM_PACKETS / 2;
+   flag[1] = NUM_PACKETS / 2 - 1;
+
+   /* Create and configure packets with flags
+*/
+   for (i = 0; i < 2; i++) {
+   if (flag[i] > 0) {
+   create_packet(flag_buf[i], flag[i] * payload_len, 0,
+ payload_len, 0);
+   tcph = (struct tcphdr *)(flag_buf[i] + tcp_offset);
+   set_flags(tcph, payload_len, psh, syn, rst, urg, cwr);
+   }
+   }
 
for (i = 0; i < NUM_PACKETS + 1; i++) {
-   if (i == flag) {
-   write_packet(fd, flag_buf, pkt_size, daddr);
+   if (i == flag[0]) {
+   write_packet(fd, flag_buf[0], pkt_size, daddr);
+   continue;
+   } else if (i == flag[1] && cwr) {
+   write_packet(fd, flag_buf[1], pkt_size, daddr);
continue;
}
create_packet(buf, i * PAYLOAD_LEN, 0, PAYLOAD_LEN, 0);
@@ -1021,16 +1047,19 @@ static void gro_sender(void)
send_ack(txfd, &daddr);
write_packet(txfd, fin_pkt, total_hdr_len, &daddr);
} else if (strcmp(testname, "flags") == 0) {
-   send_flags(txfd, &daddr, 1, 0, 0, 0);
+   send_flags(txfd, &daddr, 1, 0, 0, 0, 0);