* [PATCH net-next 0/3] packet: Add option to create new fanout group with unique id.
@ 2017-04-21 14:56 Willem de Bruijn
2017-04-21 14:56 ` [PATCH net-next 1/3] selftests/net: cleanup unused parameter in psock_fanout Willem de Bruijn
` (3 more replies)
0 siblings, 4 replies; 5+ messages in thread
From: Willem de Bruijn @ 2017-04-21 14:56 UTC (permalink / raw)
To: netdev; +Cc: maloneykernel, davem, Mike Maloney
From: Mike Maloney <maloney@google.com>
Fanout uses a per net global namespace. A process that intends to create a
new fanout group can accidentally join an existing group. It is
not possible to detect this.
Add a socket option to specify on the first call to
setsockopt(..., PACKET_FANOUT, ...) to ensure that a new group is created.
Also add tests.
Mike Maloney (3):
selftests/net: cleanup unused parameter in psock_fanout
packet: add PACKET_FANOUT_FLAG_UNIQUEID to assign new fanout group id.
selftests/net: add tests for PACKET_FANOUT_FLAG_UNIQUEID
include/uapi/linux/if_packet.h | 1 +
net/packet/af_packet.c | 44 ++++++++++++++
tools/testing/selftests/net/psock_fanout.c | 93 ++++++++++++++++++++++++++----
3 files changed, 128 insertions(+), 10 deletions(-)
--
2.12.2.816.g2cccc81164-goog
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH net-next 1/3] selftests/net: cleanup unused parameter in psock_fanout
2017-04-21 14:56 [PATCH net-next 0/3] packet: Add option to create new fanout group with unique id Willem de Bruijn
@ 2017-04-21 14:56 ` Willem de Bruijn
2017-04-21 14:56 ` [PATCH net-next 2/3] packet: add PACKET_FANOUT_FLAG_UNIQUEID to assign new fanout group id Willem de Bruijn
` (2 subsequent siblings)
3 siblings, 0 replies; 5+ messages in thread
From: Willem de Bruijn @ 2017-04-21 14:56 UTC (permalink / raw)
To: netdev; +Cc: maloneykernel, davem, Mike Maloney
From: Mike Maloney <maloney@google.com>
sock_fanout_open no longer sets the size of packet_socket ring, so stop
passing the parameter.
Signed-off-by: Mike Maloney <maloney@google.com>
Acked-by: Willem de Bruijn <willemb@google.com>
---
tools/testing/selftests/net/psock_fanout.c | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
diff --git a/tools/testing/selftests/net/psock_fanout.c b/tools/testing/selftests/net/psock_fanout.c
index 412459369686..b475d87d3aa3 100644
--- a/tools/testing/selftests/net/psock_fanout.c
+++ b/tools/testing/selftests/net/psock_fanout.c
@@ -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, int num_packets)
+static int sock_fanout_open(uint16_t typeflags)
{
int fd, val;
@@ -210,7 +210,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, 0) != -1) {
+ PACKET_FANOUT_FLAG_ROLLOVER) != -1) {
fprintf(stderr, "ERROR: opened socket with dual rollover\n");
exit(1);
}
@@ -223,26 +223,26 @@ static void test_control_group(void)
fprintf(stderr, "test: control multiple sockets\n");
- fds[0] = sock_fanout_open(PACKET_FANOUT_HASH, 20);
+ fds[0] = sock_fanout_open(PACKET_FANOUT_HASH);
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, 10) != -1) {
+ PACKET_FANOUT_FLAG_DEFRAG) != -1) {
fprintf(stderr, "ERROR: joined group with wrong flag defrag\n");
exit(1);
}
if (sock_fanout_open(PACKET_FANOUT_HASH |
- PACKET_FANOUT_FLAG_ROLLOVER, 10) != -1) {
+ PACKET_FANOUT_FLAG_ROLLOVER) != -1) {
fprintf(stderr, "ERROR: joined group with wrong flag ro\n");
exit(1);
}
- if (sock_fanout_open(PACKET_FANOUT_CPU, 10) != -1) {
+ if (sock_fanout_open(PACKET_FANOUT_CPU) != -1) {
fprintf(stderr, "ERROR: joined group with wrong mode\n");
exit(1);
}
- fds[1] = sock_fanout_open(PACKET_FANOUT_HASH, 20);
+ fds[1] = sock_fanout_open(PACKET_FANOUT_HASH);
if (fds[1] == -1) {
fprintf(stderr, "ERROR: failed to join group\n");
exit(1);
@@ -263,8 +263,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, 20);
- fds[1] = sock_fanout_open(typeflags, 20);
+ fds[0] = sock_fanout_open(typeflags);
+ fds[1] = sock_fanout_open(typeflags);
if (fds[0] == -1 || fds[1] == -1) {
fprintf(stderr, "ERROR: failed open\n");
exit(1);
--
2.12.2.816.g2cccc81164-goog
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH net-next 2/3] packet: add PACKET_FANOUT_FLAG_UNIQUEID to assign new fanout group id.
2017-04-21 14:56 [PATCH net-next 0/3] packet: Add option to create new fanout group with unique id Willem de Bruijn
2017-04-21 14:56 ` [PATCH net-next 1/3] selftests/net: cleanup unused parameter in psock_fanout Willem de Bruijn
@ 2017-04-21 14:56 ` Willem de Bruijn
2017-04-21 14:56 ` [PATCH net-next 3/3] selftests/net: add tests for PACKET_FANOUT_FLAG_UNIQUEID Willem de Bruijn
2017-04-24 16:46 ` [PATCH net-next 0/3] packet: Add option to create new fanout group with unique id David Miller
3 siblings, 0 replies; 5+ messages in thread
From: Willem de Bruijn @ 2017-04-21 14:56 UTC (permalink / raw)
To: netdev; +Cc: maloneykernel, davem, Mike Maloney
From: Mike Maloney <maloney@google.com>
Fanout uses a per net global namespace. A process that intends to create
a new fanout group can accidentally join an existing group. It is not
possible to detect this.
Add socket option PACKET_FANOUT_FLAG_UNIQUEID. When specified the
supplied fanout group id must be set to 0, and the kernel chooses an id
that is not already in use. This is an ephemeral flag so that
other sockets can be added to this group using setsockopt, but NOT
specifying this flag. The current getsockopt(..., PACKET_FANOUT, ...)
can be used to retrieve the new group id.
We assume that there are not a lot of fanout groups and that this is not
a high frequency call.
The method assigns ids starting at zero and increases until it finds an
unused id. It keeps track of the last assigned id, and uses it as a
starting point to find new ids.
Signed-off-by: Mike Maloney <maloney@google.com>
Acked-by: Willem de Bruijn <willemb@google.com>
---
include/uapi/linux/if_packet.h | 1 +
net/packet/af_packet.c | 44 ++++++++++++++++++++++++++++++++++++++++++
2 files changed, 45 insertions(+)
diff --git a/include/uapi/linux/if_packet.h b/include/uapi/linux/if_packet.h
index 9e7edfd8141e..4df96a7dd4fa 100644
--- a/include/uapi/linux/if_packet.h
+++ b/include/uapi/linux/if_packet.h
@@ -66,6 +66,7 @@ struct sockaddr_ll {
#define PACKET_FANOUT_CBPF 6
#define PACKET_FANOUT_EBPF 7
#define PACKET_FANOUT_FLAG_ROLLOVER 0x1000
+#define PACKET_FANOUT_FLAG_UNIQUEID 0x2000
#define PACKET_FANOUT_FLAG_DEFRAG 0x8000
struct tpacket_stats {
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index 8489beff5c25..94052f42058b 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -1496,6 +1496,7 @@ static int packet_rcv_fanout(struct sk_buff *skb, struct net_device *dev,
DEFINE_MUTEX(fanout_mutex);
EXPORT_SYMBOL_GPL(fanout_mutex);
static LIST_HEAD(fanout_list);
+static u16 fanout_next_id;
static void __fanout_link(struct sock *sk, struct packet_sock *po)
{
@@ -1629,6 +1630,36 @@ static void fanout_release_data(struct packet_fanout *f)
};
}
+static bool __fanout_id_is_free(struct sock *sk, u16 candidate_id)
+{
+ struct packet_fanout *f;
+
+ list_for_each_entry(f, &fanout_list, list) {
+ if (f->id == candidate_id &&
+ read_pnet(&f->net) == sock_net(sk)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+static bool fanout_find_new_id(struct sock *sk, u16 *new_id)
+{
+ u16 id = fanout_next_id;
+
+ do {
+ if (__fanout_id_is_free(sk, id)) {
+ *new_id = id;
+ fanout_next_id = id + 1;
+ return true;
+ }
+
+ id++;
+ } while (id != fanout_next_id);
+
+ return false;
+}
+
static int fanout_add(struct sock *sk, u16 id, u16 type_flags)
{
struct packet_rollover *rollover = NULL;
@@ -1676,6 +1707,19 @@ static int fanout_add(struct sock *sk, u16 id, u16 type_flags)
po->rollover = rollover;
}
+ if (type_flags & PACKET_FANOUT_FLAG_UNIQUEID) {
+ if (id != 0) {
+ err = -EINVAL;
+ goto out;
+ }
+ if (!fanout_find_new_id(sk, &id)) {
+ err = -ENOMEM;
+ goto out;
+ }
+ /* ephemeral flag for the first socket in the group: drop it */
+ flags &= ~(PACKET_FANOUT_FLAG_UNIQUEID >> 8);
+ }
+
match = NULL;
list_for_each_entry(f, &fanout_list, list) {
if (f->id == id &&
--
2.12.2.816.g2cccc81164-goog
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH net-next 3/3] selftests/net: add tests for PACKET_FANOUT_FLAG_UNIQUEID
2017-04-21 14:56 [PATCH net-next 0/3] packet: Add option to create new fanout group with unique id Willem de Bruijn
2017-04-21 14:56 ` [PATCH net-next 1/3] selftests/net: cleanup unused parameter in psock_fanout Willem de Bruijn
2017-04-21 14:56 ` [PATCH net-next 2/3] packet: add PACKET_FANOUT_FLAG_UNIQUEID to assign new fanout group id Willem de Bruijn
@ 2017-04-21 14:56 ` Willem de Bruijn
2017-04-24 16:46 ` [PATCH net-next 0/3] packet: Add option to create new fanout group with unique id David Miller
3 siblings, 0 replies; 5+ messages in thread
From: Willem de Bruijn @ 2017-04-21 14:56 UTC (permalink / raw)
To: netdev; +Cc: maloneykernel, davem, Mike Maloney
From: Mike Maloney <maloney@google.com>
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>
---
tools/testing/selftests/net/psock_fanout.c | 95 ++++++++++++++++++++++++++----
1 file changed, 84 insertions(+), 11 deletions(-)
diff --git a/tools/testing/selftests/net/psock_fanout.c b/tools/testing/selftests/net/psock_fanout.c
index b475d87d3aa3..1c46a21a9b5e 100644
--- a/tools/testing/selftests/net/psock_fanout.c
+++ b/tools/testing/selftests/net/psock_fanout.c
@@ -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");
@@ -95,6 +94,20 @@ static int sock_fanout_open(uint16_t typeflags)
return 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);
@@ -210,7 +223,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);
}
@@ -223,26 +236,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);
@@ -253,6 +266,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[])
{
@@ -263,8 +331,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);
@@ -331,10 +399,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,
@@ -365,6 +435,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;
--
2.12.2.816.g2cccc81164-goog
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH net-next 0/3] packet: Add option to create new fanout group with unique id.
2017-04-21 14:56 [PATCH net-next 0/3] packet: Add option to create new fanout group with unique id Willem de Bruijn
` (2 preceding siblings ...)
2017-04-21 14:56 ` [PATCH net-next 3/3] selftests/net: add tests for PACKET_FANOUT_FLAG_UNIQUEID Willem de Bruijn
@ 2017-04-24 16:46 ` David Miller
3 siblings, 0 replies; 5+ messages in thread
From: David Miller @ 2017-04-24 16:46 UTC (permalink / raw)
To: willemdebruijn.kernel; +Cc: netdev, maloneykernel, maloney
From: Willem de Bruijn <willemdebruijn.kernel@gmail.com>
Date: Fri, 21 Apr 2017 10:56:09 -0400
> Fanout uses a per net global namespace. A process that intends to create a
> new fanout group can accidentally join an existing group. It is
> not possible to detect this.
>
> Add a socket option to specify on the first call to
> setsockopt(..., PACKET_FANOUT, ...) to ensure that a new group is created.
> Also add tests.
Series applied, thanks.
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2017-04-24 16:46 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2017-04-21 14:56 [PATCH net-next 0/3] packet: Add option to create new fanout group with unique id Willem de Bruijn
2017-04-21 14:56 ` [PATCH net-next 1/3] selftests/net: cleanup unused parameter in psock_fanout Willem de Bruijn
2017-04-21 14:56 ` [PATCH net-next 2/3] packet: add PACKET_FANOUT_FLAG_UNIQUEID to assign new fanout group id Willem de Bruijn
2017-04-21 14:56 ` [PATCH net-next 3/3] selftests/net: add tests for PACKET_FANOUT_FLAG_UNIQUEID Willem de Bruijn
2017-04-24 16:46 ` [PATCH net-next 0/3] packet: Add option to create new fanout group with unique id David Miller
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).