selftests/net: add tests for PACKET_FANOUT_FLAG_UNIQUEID
authorMike Maloney <maloney@google.com>
Fri, 21 Apr 2017 14:56:12 +0000 (10:56 -0400)
committerDavid S. Miller <davem@davemloft.net>
Mon, 24 Apr 2017 16:46:16 +0000 (12:46 -0400)
Create two groups with PACKET_FANOUT_FLAG_UNIQUEID, add a socket to one.
Ensure that the groups can only be joined if all options are consistent
with the original except for this flag.

Signed-off-by: Mike Maloney <maloney@google.com>
Acked-by: Willem de Bruijn <willemb@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
tools/testing/selftests/net/psock_fanout.c

index 27c4027fab031b47910fe273e4e9b54861473f8a..b4b1d91fcea57ecf288722e95c6c1dd2050a0e66 100644 (file)
@@ -71,7 +71,7 @@
 
 /* Open a socket in a given fanout mode.
  * @return -1 if mode is bad, a valid socket otherwise */
-static int sock_fanout_open(uint16_t typeflags)
+static int sock_fanout_open(uint16_t typeflags, uint16_t group_id)
 {
        int fd, val;
 
@@ -81,8 +81,7 @@ static int sock_fanout_open(uint16_t typeflags)
                exit(1);
        }
 
-       /* fanout group ID is always 0: tests whether old groups are deleted */
-       val = ((int) typeflags) << 16;
+       val = (((int) typeflags) << 16) | group_id;
        if (setsockopt(fd, SOL_PACKET, PACKET_FANOUT, &val, sizeof(val))) {
                if (close(fd)) {
                        perror("close packet");
@@ -113,6 +112,20 @@ static void sock_fanout_set_cbpf(int fd)
        }
 }
 
+static void sock_fanout_getopts(int fd, uint16_t *typeflags, uint16_t *group_id)
+{
+       int sockopt;
+       socklen_t sockopt_len = sizeof(sockopt);
+
+       if (getsockopt(fd, SOL_PACKET, PACKET_FANOUT,
+                      &sockopt, &sockopt_len)) {
+               perror("failed to getsockopt");
+               exit(1);
+       }
+       *typeflags = sockopt >> 16;
+       *group_id = sockopt & 0xfffff;
+}
+
 static void sock_fanout_set_ebpf(int fd)
 {
        const int len_off = __builtin_offsetof(struct __sk_buff, len);
@@ -228,7 +241,7 @@ static void test_control_single(void)
        fprintf(stderr, "test: control single socket\n");
 
        if (sock_fanout_open(PACKET_FANOUT_ROLLOVER |
-                              PACKET_FANOUT_FLAG_ROLLOVER) != -1) {
+                              PACKET_FANOUT_FLAG_ROLLOVER, 0) != -1) {
                fprintf(stderr, "ERROR: opened socket with dual rollover\n");
                exit(1);
        }
@@ -241,26 +254,26 @@ static void test_control_group(void)
 
        fprintf(stderr, "test: control multiple sockets\n");
 
-       fds[0] = sock_fanout_open(PACKET_FANOUT_HASH);
+       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 (sock_fanout_open(PACKET_FANOUT_HASH |
-                              PACKET_FANOUT_FLAG_DEFRAG) != -1) {
+                              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) != -1) {
+                              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) != -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);
+       fds[1] = sock_fanout_open(PACKET_FANOUT_HASH, 0);
        if (fds[1] == -1) {
                fprintf(stderr, "ERROR: failed to join group\n");
                exit(1);
@@ -271,6 +284,61 @@ static void test_control_group(void)
        }
 }
 
+/* Test creating a unique fanout group ids */
+static void 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);
+       }
+
+       sock_fanout_getopts(fds[0], &typeflags, &first_group_id);
+       if (typeflags != PACKET_FANOUT_HASH) {
+               fprintf(stderr, "ERROR: unexpected typeflags %x\n", typeflags);
+               exit(1);
+       }
+
+       if (sock_fanout_open(PACKET_FANOUT_CPU, first_group_id)) {
+               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);
+       }
+
+       if (close(fds[0]) || close(fds[1]) || close(fds[2])) {
+               fprintf(stderr, "ERROR: closing sockets\n");
+               exit(1);
+       }
+}
+
 static int test_datapath(uint16_t typeflags, int port_off,
                         const int expect1[], const int expect2[])
 {
@@ -281,8 +349,8 @@ static int test_datapath(uint16_t typeflags, int port_off,
 
        fprintf(stderr, "test: datapath 0x%hx\n", typeflags);
 
-       fds[0] = sock_fanout_open(typeflags);
-       fds[1] = sock_fanout_open(typeflags);
+       fds[0] = sock_fanout_open(typeflags, 0);
+       fds[1] = sock_fanout_open(typeflags, 0);
        if (fds[0] == -1 || fds[1] == -1) {
                fprintf(stderr, "ERROR: failed open\n");
                exit(1);
@@ -349,10 +417,12 @@ int main(int argc, char **argv)
        const int expect_cpu0[2][2]     = { { 20, 0 },  { 20, 0 } };
        const int expect_cpu1[2][2]     = { { 0, 20 },  { 0, 20 } };
        const int expect_bpf[2][2]      = { { 15, 5 },  { 15, 20 } };
+       const int expect_uniqueid[2][2] = { { 20, 20},  { 20, 20 } };
        int port_off = 2, tries = 5, ret;
 
        test_control_single();
        test_control_group();
+       test_unique_fanout_group_ids();
 
        /* find a set of ports that do not collide onto the same socket */
        ret = test_datapath(PACKET_FANOUT_HASH, port_off,
@@ -383,6 +453,9 @@ int main(int argc, char **argv)
                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;