// SPDX-License-Identifier: GPL-2.0-only /* * Copyright 2013 Google Inc. * Author: Willem de Bruijn (willemb@google.com) * * A basic test of packet socket fanout behavior. * * Control: * - create fanout fails as expected with illegal flag combinations * - join fanout fails as expected with diverging types or flags * * Datapath: * Open a pair of packet sockets and a pair of INET sockets, send a known * number of packets across the two INET sockets and count the number of * packets enqueued onto the two packet sockets. * * The test currently runs for * - PACKET_FANOUT_HASH * - PACKET_FANOUT_HASH with PACKET_FANOUT_FLAG_ROLLOVER * - PACKET_FANOUT_LB * - PACKET_FANOUT_CPU * - PACKET_FANOUT_ROLLOVER * - PACKET_FANOUT_CBPF * - PACKET_FANOUT_EBPF * * Todo: * - functionality: PACKET_FANOUT_FLAG_DEFRAG
*/
/* Open a socket in a given fanout mode.
* @return -1 if mode is bad, a valid socket otherwise */ staticint sock_fanout_open(uint16_t typeflags, uint16_t group_id)
{ struct sockaddr_ll addr = {0}; struct fanout_args args; int fd, val, err;
/* Test that creating/joining a fanout group fails for unbound socket without * a specified protocol
*/ staticvoid test_unbound_fanout(void)
{ int val, fd0, fd1, err;
fprintf(stderr, "test: unbound fanout\n");
fd0 = socket(PF_PACKET, SOCK_RAW, 0); if (fd0 < 0) {
perror("socket packet"); exit(1);
} /* Try to create a new fanout group. Should fail. */
val = (PACKET_FANOUT_HASH << 16) | 1;
err = setsockopt(fd0, SOL_PACKET, PACKET_FANOUT, &val, sizeof(val)); if (!err) {
fprintf(stderr, "ERROR: unbound socket fanout create\n"); exit(1);
}
fd1 = sock_fanout_open(PACKET_FANOUT_HASH, 1); if (fd1 == -1) {
fprintf(stderr, "ERROR: failed to open HASH socket\n"); exit(1);
} /* Try to join an existing fanout group. Should fail. */
err = setsockopt(fd0, SOL_PACKET, PACKET_FANOUT, &val, sizeof(val)); if (!err) {
fprintf(stderr, "ERROR: unbound socket fanout join\n"); exit(1);
}
close(fd0);
close(fd1);
}
/* Test illegal mode + flag combination */ staticvoid test_control_single(void)
{
fprintf(stderr, "test: control single socket\n");
if (sock_fanout_open(PACKET_FANOUT_ROLLOVER |
PACKET_FANOUT_FLAG_ROLLOVER, 0) != -1) {
fprintf(stderr, "ERROR: opened socket with dual rollover\n"); exit(1);
}
}
/* Test illegal group with different modes or flags */ staticvoid test_control_group(int toggle)
{ int fds[2];
if (toggle)
fprintf(stderr, "test: control multiple sockets with link down toggle\n"); else
fprintf(stderr, "test: control multiple sockets\n");
fds[0] = sock_fanout_open(PACKET_FANOUT_HASH, 0); if (fds[0] == -1) {
fprintf(stderr, "ERROR: failed to open HASH socket\n"); exit(1);
} if (toggle)
loopback_set_up_down(0); if (sock_fanout_open(PACKET_FANOUT_HASH |
PACKET_FANOUT_FLAG_DEFRAG, 0) != -1) {
fprintf(stderr, "ERROR: joined group with wrong flag defrag\n"); exit(1);
} if (sock_fanout_open(PACKET_FANOUT_HASH |
PACKET_FANOUT_FLAG_ROLLOVER, 0) != -1) {
fprintf(stderr, "ERROR: joined group with wrong flag ro\n"); exit(1);
} if (sock_fanout_open(PACKET_FANOUT_CPU, 0) != -1) {
fprintf(stderr, "ERROR: joined group with wrong mode\n"); exit(1);
}
fds[1] = sock_fanout_open(PACKET_FANOUT_HASH, 0); if (fds[1] == -1) {
fprintf(stderr, "ERROR: failed to join group\n"); exit(1);
} if (toggle)
loopback_set_up_down(1); if (close(fds[1]) || close(fds[0])) {
fprintf(stderr, "ERROR: closing sockets\n"); exit(1);
}
}
/* Test illegal max_num_members values */ staticvoid test_control_group_max_num_members(void)
{ int fds[3];
fprintf(stderr, "test: control multiple sockets, max_num_members\n");
/* expected failure on greater than PACKET_FANOUT_MAX */
cfg_max_num_members = (1 << 16) + 1; if (sock_fanout_open(PACKET_FANOUT_HASH, 0) != -1) {
fprintf(stderr, "ERROR: max_num_members > PACKET_FANOUT_MAX\n"); exit(1);
}
/* expected failure on joining group with different max_num_members */
cfg_max_num_members = 257; if (sock_fanout_open(PACKET_FANOUT_HASH, 0) != -1) {
fprintf(stderr, "ERROR: set different max_num_members\n"); exit(1);
}
/* success on joining group with same max_num_members */
cfg_max_num_members = 256;
fds[1] = sock_fanout_open(PACKET_FANOUT_HASH, 0); if (fds[1] == -1) {
fprintf(stderr, "ERROR: failed to join group\n"); exit(1);
}
/* success on joining group with max_num_members unspecified */
cfg_max_num_members = 0;
fds[2] = sock_fanout_open(PACKET_FANOUT_HASH, 0); if (fds[2] == -1) {
fprintf(stderr, "ERROR: failed to join group\n"); exit(1);
}
/* Test creating a unique fanout group ids */ staticvoid test_unique_fanout_group_ids(void)
{ int fds[3];
uint16_t typeflags, first_group_id, second_group_id;
fprintf(stderr, "test: unique ids\n");
fds[0] = sock_fanout_open(PACKET_FANOUT_HASH |
PACKET_FANOUT_FLAG_UNIQUEID, 0); if (fds[0] == -1) {
fprintf(stderr, "ERROR: failed to create a unique id group.\n"); exit(1);
}
if (sock_fanout_open(PACKET_FANOUT_CPU, first_group_id) != -1) {
fprintf(stderr, "ERROR: joined group with wrong type.\n"); exit(1);
}
fds[1] = sock_fanout_open(PACKET_FANOUT_HASH, first_group_id); if (fds[1] == -1) {
fprintf(stderr, "ERROR: failed to join previously created group.\n"); exit(1);
}
fds[2] = sock_fanout_open(PACKET_FANOUT_HASH |
PACKET_FANOUT_FLAG_UNIQUEID, 0); if (fds[2] == -1) {
fprintf(stderr, "ERROR: failed to create a second unique id group.\n"); exit(1);
}
sock_fanout_getopts(fds[2], &typeflags, &second_group_id); if (sock_fanout_open(PACKET_FANOUT_HASH | PACKET_FANOUT_FLAG_UNIQUEID,
second_group_id) != -1) {
fprintf(stderr, "ERROR: specified a group id when requesting unique id\n"); exit(1);
}
/* Send data, but not enough to overflow a queue */
pair_udp_send(fds_udp[0], 15);
pair_udp_send_char(fds_udp[1], 5, DATA_CHAR_1);
ret = sock_fanout_read(fds, rings, expect1);
/* Send more data, overflow the queue */
pair_udp_send_char(fds_udp[0], 15, DATA_CHAR_1); /* TODO: ensure consistent order between expect1 and expect2 */
ret |= sock_fanout_read(fds, rings, expect2);
/* PACKET_FANOUT_MAX */
cfg_max_num_members = 1 << 16; /* find a set of ports that do not collide onto the same socket */
ret = test_datapath(PACKET_FANOUT_HASH, port_off,
expect_hash[0], expect_hash[1]); while (ret) {
fprintf(stderr, "info: trying alternate ports (%d)\n", tries);
ret = test_datapath(PACKET_FANOUT_HASH, ++port_off,
expect_hash[0], expect_hash[1]); if (!--tries) {
fprintf(stderr, "too many collisions\n"); return 1;
}
}
ret |= test_datapath(PACKET_FANOUT_HASH | PACKET_FANOUT_FLAG_ROLLOVER,
port_off, expect_hash_rb[0], expect_hash_rb[1]);
ret |= test_datapath(PACKET_FANOUT_LB,
port_off, expect_lb[0], expect_lb[1]);
ret |= test_datapath(PACKET_FANOUT_ROLLOVER,
port_off, expect_rb[0], expect_rb[1]);
ret |= test_datapath(PACKET_FANOUT_CBPF,
port_off, expect_bpf[0], expect_bpf[1]);
ret |= test_datapath(PACKET_FANOUT_EBPF,
port_off, expect_bpf[0], expect_bpf[1]);
set_cpuaffinity(0);
ret |= test_datapath(PACKET_FANOUT_CPU, port_off,
expect_cpu0[0], expect_cpu0[1]); if (!set_cpuaffinity(1)) /* TODO: test that choice alternates with previous */
ret |= test_datapath(PACKET_FANOUT_CPU, port_off,
expect_cpu1[0], expect_cpu1[1]);
ret |= test_datapath(PACKET_FANOUT_FLAG_UNIQUEID, port_off,
expect_uniqueid[0], expect_uniqueid[1]);
if (ret) return 1;
printf("OK. All tests passed\n"); return 0;
}
Messung V0.5
¤ Dauer der Verarbeitung: 0.12 Sekunden
(vorverarbeitet)
¤
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.