@@ -93,6 +93,7 @@ static bool tx_socket = true;
93
93
static int tcp_offset = -1 ;
94
94
static int total_hdr_len = -1 ;
95
95
static int ethhdr_proto = -1 ;
96
+ static const int num_flush_id_cases = 6 ;
96
97
97
98
static void vlog (const char * fmt , ...)
98
99
{
@@ -620,6 +621,113 @@ static void add_ipv6_exthdr(void *buf, void *optpkt, __u8 exthdr_type, char *ext
620
621
iph -> payload_len = htons (ntohs (iph -> payload_len ) + MIN_EXTHDR_SIZE );
621
622
}
622
623
624
+ static void fix_ip4_checksum (struct iphdr * iph )
625
+ {
626
+ iph -> check = 0 ;
627
+ iph -> check = checksum_fold (iph , sizeof (struct iphdr ), 0 );
628
+ }
629
+
630
+ static void send_flush_id_case (int fd , struct sockaddr_ll * daddr , int tcase )
631
+ {
632
+ static char buf1 [MAX_HDR_LEN + PAYLOAD_LEN ];
633
+ static char buf2 [MAX_HDR_LEN + PAYLOAD_LEN ];
634
+ static char buf3 [MAX_HDR_LEN + PAYLOAD_LEN ];
635
+ bool send_three = false;
636
+ struct iphdr * iph1 ;
637
+ struct iphdr * iph2 ;
638
+ struct iphdr * iph3 ;
639
+
640
+ iph1 = (struct iphdr * )(buf1 + ETH_HLEN );
641
+ iph2 = (struct iphdr * )(buf2 + ETH_HLEN );
642
+ iph3 = (struct iphdr * )(buf3 + ETH_HLEN );
643
+
644
+ create_packet (buf1 , 0 , 0 , PAYLOAD_LEN , 0 );
645
+ create_packet (buf2 , PAYLOAD_LEN , 0 , PAYLOAD_LEN , 0 );
646
+ create_packet (buf3 , PAYLOAD_LEN * 2 , 0 , PAYLOAD_LEN , 0 );
647
+
648
+ switch (tcase ) {
649
+ case 0 : /* DF=1, Incrementing - should coalesce */
650
+ iph1 -> frag_off |= htons (IP_DF );
651
+ iph1 -> id = htons (8 );
652
+
653
+ iph2 -> frag_off |= htons (IP_DF );
654
+ iph2 -> id = htons (9 );
655
+ break ;
656
+
657
+ case 1 : /* DF=1, Fixed - should coalesce */
658
+ iph1 -> frag_off |= htons (IP_DF );
659
+ iph1 -> id = htons (8 );
660
+
661
+ iph2 -> frag_off |= htons (IP_DF );
662
+ iph2 -> id = htons (8 );
663
+ break ;
664
+
665
+ case 2 : /* DF=0, Incrementing - should coalesce */
666
+ iph1 -> frag_off &= ~htons (IP_DF );
667
+ iph1 -> id = htons (8 );
668
+
669
+ iph2 -> frag_off &= ~htons (IP_DF );
670
+ iph2 -> id = htons (9 );
671
+ break ;
672
+
673
+ case 3 : /* DF=0, Fixed - should not coalesce */
674
+ iph1 -> frag_off &= ~htons (IP_DF );
675
+ iph1 -> id = htons (8 );
676
+
677
+ iph2 -> frag_off &= ~htons (IP_DF );
678
+ iph2 -> id = htons (8 );
679
+ break ;
680
+
681
+ case 4 : /* DF=1, two packets incrementing, and one fixed - should
682
+ * coalesce only the first two packets
683
+ */
684
+ iph1 -> frag_off |= htons (IP_DF );
685
+ iph1 -> id = htons (8 );
686
+
687
+ iph2 -> frag_off |= htons (IP_DF );
688
+ iph2 -> id = htons (9 );
689
+
690
+ iph3 -> frag_off |= htons (IP_DF );
691
+ iph3 -> id = htons (9 );
692
+ send_three = true;
693
+ break ;
694
+
695
+ case 5 : /* DF=1, two packets fixed, and one incrementing - should
696
+ * coalesce only the first two packets
697
+ */
698
+ iph1 -> frag_off |= htons (IP_DF );
699
+ iph1 -> id = htons (8 );
700
+
701
+ iph2 -> frag_off |= htons (IP_DF );
702
+ iph2 -> id = htons (8 );
703
+
704
+ iph3 -> frag_off |= htons (IP_DF );
705
+ iph3 -> id = htons (9 );
706
+ send_three = true;
707
+ break ;
708
+ }
709
+
710
+ fix_ip4_checksum (iph1 );
711
+ fix_ip4_checksum (iph2 );
712
+ write_packet (fd , buf1 , total_hdr_len + PAYLOAD_LEN , daddr );
713
+ write_packet (fd , buf2 , total_hdr_len + PAYLOAD_LEN , daddr );
714
+
715
+ if (send_three ) {
716
+ fix_ip4_checksum (iph3 );
717
+ write_packet (fd , buf3 , total_hdr_len + PAYLOAD_LEN , daddr );
718
+ }
719
+ }
720
+
721
+ static void test_flush_id (int fd , struct sockaddr_ll * daddr , char * fin_pkt )
722
+ {
723
+ for (int i = 0 ; i < num_flush_id_cases ; i ++ ) {
724
+ sleep (1 );
725
+ send_flush_id_case (fd , daddr , i );
726
+ sleep (1 );
727
+ write_packet (fd , fin_pkt , total_hdr_len , daddr );
728
+ }
729
+ }
730
+
623
731
static void send_ipv6_exthdr (int fd , struct sockaddr_ll * daddr , char * ext_data1 , char * ext_data2 )
624
732
{
625
733
static char buf [MAX_HDR_LEN + PAYLOAD_LEN ];
@@ -938,6 +1046,8 @@ static void gro_sender(void)
938
1046
send_fragment4 (txfd , & daddr );
939
1047
sleep (1 );
940
1048
write_packet (txfd , fin_pkt , total_hdr_len , & daddr );
1049
+
1050
+ test_flush_id (txfd , & daddr , fin_pkt );
941
1051
} else if (proto == PF_INET6 ) {
942
1052
sleep (1 );
943
1053
send_fragment6 (txfd , & daddr );
@@ -1064,6 +1174,34 @@ static void gro_receiver(void)
1064
1174
1065
1175
printf ("fragmented ip4 doesn't coalesce: " );
1066
1176
check_recv_pkts (rxfd , correct_payload , 2 );
1177
+
1178
+ /* is_atomic checks */
1179
+ printf ("DF=1, Incrementing - should coalesce: " );
1180
+ correct_payload [0 ] = PAYLOAD_LEN * 2 ;
1181
+ check_recv_pkts (rxfd , correct_payload , 1 );
1182
+
1183
+ printf ("DF=1, Fixed - should coalesce: " );
1184
+ correct_payload [0 ] = PAYLOAD_LEN * 2 ;
1185
+ check_recv_pkts (rxfd , correct_payload , 1 );
1186
+
1187
+ printf ("DF=0, Incrementing - should coalesce: " );
1188
+ correct_payload [0 ] = PAYLOAD_LEN * 2 ;
1189
+ check_recv_pkts (rxfd , correct_payload , 1 );
1190
+
1191
+ printf ("DF=0, Fixed - should not coalesce: " );
1192
+ correct_payload [0 ] = PAYLOAD_LEN ;
1193
+ correct_payload [1 ] = PAYLOAD_LEN ;
1194
+ check_recv_pkts (rxfd , correct_payload , 2 );
1195
+
1196
+ printf ("DF=1, 2 Incrementing and one fixed - should coalesce only first 2 packets: " );
1197
+ correct_payload [0 ] = PAYLOAD_LEN * 2 ;
1198
+ correct_payload [1 ] = PAYLOAD_LEN ;
1199
+ check_recv_pkts (rxfd , correct_payload , 2 );
1200
+
1201
+ printf ("DF=1, 2 Fixed and one incrementing - should coalesce only first 2 packets: " );
1202
+ correct_payload [0 ] = PAYLOAD_LEN * 2 ;
1203
+ correct_payload [1 ] = PAYLOAD_LEN ;
1204
+ check_recv_pkts (rxfd , correct_payload , 2 );
1067
1205
} else if (proto == PF_INET6 ) {
1068
1206
/* GRO doesn't check for ipv6 hop limit when flushing.
1069
1207
* Hence no corresponding test to the ipv4 case.
0 commit comments