@@ -93,6 +93,7 @@ static bool tx_socket = true;
9393static int tcp_offset = -1 ;
9494static int total_hdr_len = -1 ;
9595static int ethhdr_proto = -1 ;
96+ static const int num_flush_id_cases = 6 ;
9697
9798static void vlog (const char * fmt , ...)
9899{
@@ -620,6 +621,113 @@ static void add_ipv6_exthdr(void *buf, void *optpkt, __u8 exthdr_type, char *ext
620621 iph -> payload_len = htons (ntohs (iph -> payload_len ) + MIN_EXTHDR_SIZE );
621622}
622623
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+
623731static void send_ipv6_exthdr (int fd , struct sockaddr_ll * daddr , char * ext_data1 , char * ext_data2 )
624732{
625733 static char buf [MAX_HDR_LEN + PAYLOAD_LEN ];
@@ -938,6 +1046,8 @@ static void gro_sender(void)
9381046 send_fragment4 (txfd , & daddr );
9391047 sleep (1 );
9401048 write_packet (txfd , fin_pkt , total_hdr_len , & daddr );
1049+
1050+ test_flush_id (txfd , & daddr , fin_pkt );
9411051 } else if (proto == PF_INET6 ) {
9421052 sleep (1 );
9431053 send_fragment6 (txfd , & daddr );
@@ -1064,6 +1174,34 @@ static void gro_receiver(void)
10641174
10651175 printf ("fragmented ip4 doesn't coalesce: " );
10661176 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 );
10671205 } else if (proto == PF_INET6 ) {
10681206 /* GRO doesn't check for ipv6 hop limit when flushing.
10691207 * Hence no corresponding test to the ipv4 case.
0 commit comments