// SPDX-License-Identifier: GPL-2.0 /* Toeplitz test * * 1. Read packets and their rx_hash using PF_PACKET/TPACKET_V3 * 2. Compute the rx_hash in software based on the packet contents * 3. Compare the two * * Optionally, either '-C $rx_irq_cpu_list' or '-r $rps_bitmap' may be given. * * If '-C $rx_irq_cpu_list' is given, also * * 4. Identify the cpu on which the packet arrived with PACKET_FANOUT_CPU * 5. Compute the rxqueue that RSS would select based on this rx_hash * 6. Using the $rx_irq_cpu_list map, identify the arriving cpu based on rxq irq * 7. Compare the cpus from 4 and 6 * * Else if '-r $rps_bitmap' is given, also * * 4. Identify the cpu on which the packet arrived with PACKET_FANOUT_CPU * 5. Compute the cpu that RPS should select based on rx_hash and $rps_bitmap * 6. Compare the cpus from 4 and 5
*/
/* Compare computed cpu with arrival cpu from packet_fanout_cpu */ staticvoid verify_rss(uint32_t rx_hash, int cpu)
{ int queue = rx_hash % cfg_num_queues;
if (hdr->hv1.tp_rxhash)
verify_rxhash(frame + hdr->tp_net, hdr->hv1.tp_rxhash,
ring->cpu); else
frames_nohash++;
return frame + hdr->tp_next_offset;
}
/* A single TPACKET_V3 block can hold multiple frames */ staticbool recv_block(struct ring_state *ring)
{ struct tpacket_block_desc *block; char *frame; int i;
/* filter on transport protocol and destination port */ staticvoid set_filter(int fd)
{ constint off_dport = offsetof(struct tcphdr, dest); /* same for udp */
uint8_t proto;
proto = cfg_type == SOCK_STREAM ? IPPROTO_TCP : IPPROTO_UDP; if (cfg_family == AF_INET)
__set_filter(fd, offsetof(struct iphdr, protocol), proto, sizeof(struct iphdr) + off_dport); else
__set_filter(fd, offsetof(struct ip6_hdr, ip6_nxt), proto, sizeof(struct ip6_hdr) + off_dport);
}
/* drop everything: used temporarily during setup */ staticvoid set_filter_null(int fd)
{ struct sock_filter filter[] = {
BPF_STMT(BPF_RET + BPF_K, 0),
}; struct sock_fprog prog = {};
/* must come after bind: verifies all programs in group match */ if (setsockopt(fd, SOL_PACKET, PACKET_FANOUT, &args, sizeof(args))) { /* on failure, retry using old API if that is sufficient: * it has a hard limit of 256 sockets, so only try if * (a) only testing rxhash, not RSS or (b) <= 256 cpus. * in this API, the third argument is left implicit.
*/ if (cfg_num_queues || num_cpus > 256 ||
setsockopt(fd, SOL_PACKET, PACKET_FANOUT,
&args, sizeof(uint32_t)))
error(1, errno, "setsockopt PACKET_FANOUT cpu");
}
return fd;
}
/* setup inet(6) socket to blackhole the test traffic, if arg '-s' */ staticint setup_sink(void)
{ int fd, val;
val = 1 << 20; if (setsockopt(fd, SOL_SOCKET, SO_RCVBUFFORCE, &val, sizeof(val)))
error(1, errno, "setsockopt rcvbuf");
return fd;
}
staticvoid setup_rings(void)
{ int i;
for (i = 0; i < num_cpus; i++) {
rings[i].cpu = i;
rings[i].fd = create_ring(&rings[i].mmap);
}
/* accept packets once all rings in the fanout group are up */ for (i = 0; i < num_cpus; i++)
set_filter(rings[i].fd);
}
staticvoid cleanup_rings(void)
{ int i;
for (i = 0; i < num_cpus; i++) { if (munmap(rings[i].mmap, ring_block_nr * ring_block_sz))
error(1, errno, "munmap"); if (close(rings[i].fd))
error(1, errno, "close");
}
}
for (i = 0, off = 0; off < slen; i++, off += 3) {
ret = sscanf(str + off, "%hhx", &key[i]); if (ret != 1)
error(1, 0, "key parse error at %d off %d len %d",
i, off, slen);
}
}
staticvoid parse_rps_bitmap(constchar *arg)
{ unsignedlong bitmap; int i;
bitmap = strtoul(arg, NULL, 0);
if (bitmap & ~(RPS_MAX_CPUS - 1))
error(1, 0, "rps bitmap 0x%lx out of bounds 0..%lu",
bitmap, RPS_MAX_CPUS - 1);
for (i = 0; i < RPS_MAX_CPUS; i++) if (bitmap & 1UL << i)
rps_silo_to_cpu[cfg_num_rps_cpus++] = i;
}
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.