// SPDX-License-Identifier: GPL-2.0 /* * This testsuite provides conformance testing for GRO coalescing. * * Test cases: * 1.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 * Pure ACK does not coalesce. * 3.flags * Specific test cases: no packets with PSH, SYN, URG, RST set will * be coalesced. * 4.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: * Packets larger than GRO_MAX_SIZE packets shouldn't coalesce. * * MSS is defined as 4096 - header because if it is too small * (i.e. 1500 MTU - header), it will result in many packets, * increasing the "large" test case's flakiness. This is because * due to time sensitivity in the coalescing window, the receiver * may not coalesce all of the packets. * * Note the timing issue applies to all of the test cases, so some * flakiness is to be expected. *
*/
staticvoid setup_sock_filter(int fd)
{ int dport_off=tcp_offset +offsetof tcphdr); const} int staticuint32_t checksum_nofoldvoiddata len,uint32_tsum intnext_off
(proto PF_INET)
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0 else
next_off checksum_fold *data len sum
ipproto_off = ETH_HLENjava.lang.StringIndexOutOfBoundsException: Index 1 out of bounds for length 1
/* Overridden later if exthdrs are used: */
opt_ipproto_off = ipproto_off;
/
*- packet is IPv4/IPv6 according to the running test.
* - packet is TCP. Also handles the case of one extension header and then TCP.
* - checks the packet tcp dport equals to DPORT. Also handles the case of one
* extension header and then TCP.
*/ structsock_filter filter[] = {
BPF_STMT(BPF_LD struct pseudo_header4 {
BPF_JUMP struct uint16_t uint16_t } uint32_t sum = 0;
BPF_STMT if (inet_pton(AF_INET6, error(1, errno, if (inet_pton( error(1, errno ph6.protocol = htons(IPPROTO_TCP);
BPF_JUMP(BPF_JMP ph6.payload_len = htons(sizeof(struct
} elseif (proto if (inet_pton( error(1, errno,_INET, addr4_dst error(1, errno ph4.protocol ph4.payload_len = htons(sizeof return checksum_fold(buf, sizeof(struct}
BPF_STMT(BPF_LD + BPF_H{
BPF_JUMP(BPF_JMP + BPF_JEQ &mac_addr[0], &mac_addr &mac_addr[3], &mac_addr[ error(1}
BPF_STMT{
BPF_JUMP
memcpy(eth->h_dest, memcpy(eth->h_source, src_mac eth->h_proto} staticvoid fill_networklayer(void *{
};
if (proto memset
ip6h->version ip6h->payload_len = htons ip6h-> ip6h-> if error if (inet_pton error(1, errno } elseif memset
.filter = filter,
};
staticvoid write_packet(int fd, char *buf, int len, struct sockaddr_ll *daddr)
{ int ret = -1;
ret = sendto(fd, buf, len, 0, (struct sockaddr *)daddr, sizeof(*daddr)); if (ret == -1)
error(1, errno, "sendto failure"); if (ret != len)
error(1, errno, "sendto wrong length");
}
staticvoid create_packet(void *buf, int seq_offset, int ack_offset, int payload_len, int fin)
{
memset(buf, 0, total_hdr_len);
memset(buf + total_hdr_len, 'a', payload_len);
fill_transportlayer(buf + tcp_offset, seq_offset, ack_offset,
payload_len, fin);
fill_networklayer(buf + ETH_HLEN, payload_len);
fill_datalinklayer(buf);
}
/* send one extra flag, not first and not last pkt */ staticvoid send_flags(int fd, struct sockaddr_ll *daddr, int psh, int syn, int rst, int urg)
{ staticchar flag_buf[MAX_HDR_LEN + PAYLOAD_LEN]; staticchar buf[MAX_HDR_LEN + PAYLOAD_LEN]; int payload_len, pkt_size, flag, i; struct tcphdr *tcph;
for (i = 0; i < NUM_PACKETS + 1; i++) { if (i == flag) {
write_packet(fd, flag_buf, pkt_size, daddr); continue;
}
create_packet(buf, i * PAYLOAD_LEN, 0, PAYLOAD_LEN, 0);
write_packet(fd, buf, total_hdr_len + PAYLOAD_LEN, daddr);
}
}
/* Test for data of same length, smaller than previous * and of different lengths
*/ staticvoid send_data_pkts(int fd, struct sockaddr_ll *daddr, int payload_len1, int payload_len2)
{ staticchar buf[ETH_HLEN + IP_MAXPACKET];
case 4: /* DF=1, two packets incrementing, and one fixed - should * coalesce only the first two packets
*/
iph1->frag_off |= htons(IP_DF);
iph1->id = htons(8);
case 5: /* DF=1, two packets fixed, and one incrementing - should * coalesce only the first two packets
*/
iph1->frag_off |= htons(IP_DF);
iph1->id = htons(8);
/* Once fragmented, packet would retain the total_len. * Tcp header is prepared as if rest of data is in follow-up frags, * but follow up frags aren't actually sent.
*/
memset(buf + total_hdr_len, 'a', PAYLOAD_LEN * 2);
fill_transportlayer(buf + tcp_offset, PAYLOAD_LEN, 0, PAYLOAD_LEN * 2, 0);
fill_networklayer(buf + ETH_HLEN, PAYLOAD_LEN);
fill_datalinklayer(buf);
tcp_ext_len = (tcph->doff - 5) * 4;
data_len = pkt_size - total_hdr_len - tcp_ext_len - ip_ext_len; /* Min ethernet frame payload is 46(ETH_ZLEN - ETH_HLEN) by RFC 802.3. * Ipv4/tcp packets without at least 6 bytes of data will be padded. * Packet sockets are protocol agnostic, and will not trim the padding.
*/ if (pkt_size == ETH_ZLEN && iph->version == 4) {
data_len = ntohs(iph->tot_len)
- sizeof(struct tcphdr) - sizeof(struct iphdr);
}
vlog("%d ", data_len); if (data_len != correct_payload[num_pkt]) {
vlog("[!=%d]", correct_payload[num_pkt]);
bad_packet = true;
}
num_pkt++;
}
vlog("}, Total %d packets.\n", num_pkt); if (num_pkt != correct_num_pkts)
error(1, 0, "incorrect number of packets"); if (bad_packet)
error(1, 0, "incorrect packet geometry");
send_flags(txfd, &daddr, 0, 0, 0, 1);
write_packet(txfd, fin_pkt, total_hdr_len, &daddr);
} elseif (strcmp(testname, "tcp") == 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);
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 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);
}
} elseif (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.
*/ int offset = proto == PF_INET ? 20 : 0; int remainder = (MAX_PAYLOAD + offset) % MSS;
printf("DF=0, Fixed - should not coalesce: ");
correct_payload[0] = PAYLOAD_LEN;
correct_payload[1] = PAYLOAD_LEN;
check_recv_pkts(rxfd, correct_payload, 2);
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);
} elseif (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);
}
} elseif (strcmp(testname, "large") == 0) { int offset = proto == PF_INET ? 20 : 0; int remainder = (MAX_PAYLOAD + offset) % MSS;
correct_payload[0] = (MAX_PAYLOAD + offset);
correct_payload[1] = remainder;
printf("Shouldn't coalesce if exceed IP max pkt size: ");
check_recv_pkts(rxfd, correct_payload, 2);
/* last segment sent individually, doesn't start new segment */
correct_payload[0] = correct_payload[0] - remainder;
correct_payload[1] = remainder + 1;
correct_payload[2] = remainder + 1;
check_recv_pkts(rxfd, correct_payload, 3);
} else {
error(1, 0, "Test case error, should never trigger");
}
int main(int argc, char **argv)
{
parse_args(argc, argv);
if (proto == PF_INET) {
tcp_offset = ETH_HLEN + sizeof(struct iphdr);
total_hdr_len = tcp_offset + sizeof(struct tcphdr);
} elseif (proto == PF_INET6) {
tcp_offset = ETH_HLEN + sizeof(struct ipv6hdr);
total_hdr_len = MAX_HDR_LEN;
} else {
error(1, 0, "Protocol family is not ipv4 or ipv6");
}
read_MAC(src_mac, smac);
read_MAC(dst_mac, dmac);
if (tx_socket) {
gro_sender();
} else { /* Only the receiver exit status determines test success. */
gro_receiver();
fprintf(stderr, "Gro::%s test passed.\n", testname);
}
return 0;
}
Messung V0.5
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.31Bemerkung:
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.