Netdev List
 help / color / mirror / Atom feed
* Re: [PATCH] Use Kconfig flag to remove support of deprecated BE2/BE3 adapters
From: Christoph Hellwig @ 2018-08-06 16:21 UTC (permalink / raw)
  To: Petr Oros
  Cc: netdev, ivecera, Sathya Perla, Ajit Khaparde,
	Sriharsha Basavapatna, Somnath Kotur, David S. Miller,
	linux-kernel
In-Reply-To: <20180806121230.23690-1-poros@redhat.com>

On Mon, Aug 06, 2018 at 02:12:28PM +0200, Petr Oros wrote:
>   Add flags to remove support of deprecated BE2/BE3 adapters.
>   BE2 disable will reduce .ko size by 2kb and BE3 by 3kb.
>   Disable both will reduce .ko size by 9kb.
> 
>   With dissabled support is also removed coresponding PCI IDs
>   and codepath with [BE2|BE3|BEx]_chip checks.

deprecated seems like a really odd world for hardware.

Are they just old?  Did they never ship in large numbers?

If you just make some cards optional why not also add options
for families of newer cards for those who only have the older ones
in their systems?

^ permalink raw reply

* [PATCH bpf-next 0/3] Implement bpf map queue
From: Mauricio Vasquez B @ 2018-08-06 13:58 UTC (permalink / raw)
  To: Alexei Starovoitov, Daniel Borkmann; +Cc: netdev

Bpf queue map is a new kind of map that provides a LIFO/FIFO queue
implementation.

In some applications, like a SNAT, it is necessary to keep track of
a pool of free elemenets, network ports in this case, then a queue
can be used for that purpose.

Signed-off-by: Mauricio Vasquez B <mauricio.vasquez@polito.it>
---
Mauricio Vasquez B (3):
      bpf: add bpf queue map
      selftests/bpf: add test cases for BPF_MAP_TYPE_QUEUE
      bpf: add sample for BPF_MAP_TYPE_QUEUE


 include/linux/bpf_types.h               |    1 
 include/uapi/linux/bpf.h                |    5 +
 kernel/bpf/Makefile                     |    2 
 kernel/bpf/queuemap.c                   |  287 +++++++++++++++++++++++++++++++
 kernel/bpf/syscall.c                    |   61 +++++--
 kernel/bpf/verifier.c                   |   16 +-
 samples/bpf/.gitignore                  |    1 
 samples/bpf/Makefile                    |    3 
 samples/bpf/test_map_in_map_user.c      |    9 -
 samples/bpf/test_queuemap.sh            |   37 ++++
 samples/bpf/test_queuemap_kern.c        |   51 ++++++
 samples/bpf/test_queuemap_user.c        |   53 ++++++
 tools/include/uapi/linux/bpf.h          |    5 +
 tools/testing/selftests/bpf/test_maps.c |   72 ++++++++
 14 files changed, 577 insertions(+), 26 deletions(-)
 create mode 100644 kernel/bpf/queuemap.c
 create mode 100755 samples/bpf/test_queuemap.sh
 create mode 100644 samples/bpf/test_queuemap_kern.c
 create mode 100644 samples/bpf/test_queuemap_user.c

^ permalink raw reply

* [PATCH bpf-next 1/3] bpf: add bpf queue map
From: Mauricio Vasquez B @ 2018-08-06 13:58 UTC (permalink / raw)
  To: Alexei Starovoitov, Daniel Borkmann; +Cc: netdev
In-Reply-To: <153356387977.6981.12236150594041620482.stgit@kernel>

Bpf queue implements a LIFO/FIFO data containers for ebpf programs.

It allows to push an element to the queue by using the update operation
and to pop an element from the queue by using the lookup operation.

A use case for this is to keep track of a pool of elements, like
network ports in a SNAT.

Signed-off-by: Mauricio Vasquez B <mauricio.vasquez@polito.it>
---
 include/linux/bpf_types.h |    1 
 include/uapi/linux/bpf.h  |    5 +
 kernel/bpf/Makefile       |    2 
 kernel/bpf/queuemap.c     |  287 +++++++++++++++++++++++++++++++++++++++++++++
 kernel/bpf/syscall.c      |   61 +++++++---
 kernel/bpf/verifier.c     |   16 ++-
 6 files changed, 353 insertions(+), 19 deletions(-)
 create mode 100644 kernel/bpf/queuemap.c

diff --git a/include/linux/bpf_types.h b/include/linux/bpf_types.h
index c5700c2d5549..6c7a62f3fe43 100644
--- a/include/linux/bpf_types.h
+++ b/include/linux/bpf_types.h
@@ -58,3 +58,4 @@ BPF_MAP_TYPE(BPF_MAP_TYPE_CPUMAP, cpu_map_ops)
 BPF_MAP_TYPE(BPF_MAP_TYPE_XSKMAP, xsk_map_ops)
 #endif
 #endif
+BPF_MAP_TYPE(BPF_MAP_TYPE_QUEUE, queue_map_ops)
diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index 0ebaaf7f3568..2c171c40eb45 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -120,6 +120,7 @@ enum bpf_map_type {
 	BPF_MAP_TYPE_CPUMAP,
 	BPF_MAP_TYPE_XSKMAP,
 	BPF_MAP_TYPE_SOCKHASH,
+	BPF_MAP_TYPE_QUEUE,
 };
 
 enum bpf_prog_type {
@@ -255,6 +256,10 @@ enum bpf_attach_type {
 /* Flag for stack_map, store build_id+offset instead of pointer */
 #define BPF_F_STACK_BUILD_ID	(1U << 5)
 
+/* Flags for queue_map, type of queue */
+#define BPF_F_QUEUE_FIFO	(1U << 16)
+#define BPF_F_QUEUE_LIFO	(2U << 16)
+
 enum bpf_stack_build_id_status {
 	/* user space need an empty entry to identify end of a trace */
 	BPF_STACK_BUILD_ID_EMPTY = 0,
diff --git a/kernel/bpf/Makefile b/kernel/bpf/Makefile
index f27f5496d6fe..30f02ef66635 100644
--- a/kernel/bpf/Makefile
+++ b/kernel/bpf/Makefile
@@ -2,7 +2,7 @@
 obj-y := core.o
 
 obj-$(CONFIG_BPF_SYSCALL) += syscall.o verifier.o inode.o helpers.o tnum.o
-obj-$(CONFIG_BPF_SYSCALL) += hashtab.o arraymap.o percpu_freelist.o bpf_lru_list.o lpm_trie.o map_in_map.o
+obj-$(CONFIG_BPF_SYSCALL) += hashtab.o arraymap.o percpu_freelist.o bpf_lru_list.o lpm_trie.o map_in_map.o queuemap.o
 obj-$(CONFIG_BPF_SYSCALL) += disasm.o
 obj-$(CONFIG_BPF_SYSCALL) += btf.o
 ifeq ($(CONFIG_NET),y)
diff --git a/kernel/bpf/queuemap.c b/kernel/bpf/queuemap.c
new file mode 100644
index 000000000000..ab30af43b4cc
--- /dev/null
+++ b/kernel/bpf/queuemap.c
@@ -0,0 +1,287 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * queuemap.c: BPF queue map
+ *
+ * Copyright (c) 2018 Politecnico di Torino
+ */
+#include <linux/bpf.h>
+#include <linux/rculist.h>
+#include <linux/slab.h>
+#include "percpu_freelist.h"
+
+#define QUEUE_CREATE_FLAG_MASK \
+	(BPF_F_NO_PREALLOC | BPF_F_NUMA_NODE | BPF_F_RDONLY | BPF_F_WRONLY | \
+	 BPF_F_QUEUE_FIFO | BPF_F_QUEUE_LIFO)
+
+enum queue_type {
+	QUEUE_FIFO = (BPF_F_QUEUE_FIFO >> 16),
+	QUEUE_LIFO = (BPF_F_QUEUE_LIFO >> 16),
+};
+
+struct bpf_queue {
+	struct bpf_map map;
+	struct list_head head;
+	struct pcpu_freelist freelist;
+	void *nodes;
+	enum queue_type type;
+	raw_spinlock_t lock;
+	atomic_t count;
+	u32 node_size;
+};
+
+struct queue_node {
+	struct pcpu_freelist_node fnode;
+	struct bpf_queue *queue;
+	struct list_head list;
+	struct rcu_head rcu;
+	char element[0] __aligned(8);
+};
+
+static bool queue_map_is_prealloc(struct bpf_queue *queue)
+{
+	return !(queue->map.map_flags & BPF_F_NO_PREALLOC);
+}
+
+/* Called from syscall */
+static int queue_map_alloc_check(union bpf_attr *attr)
+{
+	/* check sanity of attributes */
+	if (attr->max_entries == 0 || attr->key_size != 0 ||
+	    attr->value_size == 0 || attr->map_flags & ~QUEUE_CREATE_FLAG_MASK)
+		return -EINVAL;
+
+	if ((attr->map_flags >> 16) != QUEUE_FIFO &&
+	    (attr->map_flags >> 16) != QUEUE_LIFO) {
+		return -EINVAL;
+	}
+
+	if (attr->value_size > KMALLOC_MAX_SIZE)
+		/* if value_size is bigger, the user space won't be able to
+		 * access the elements.
+		 */
+		return -E2BIG;
+
+	return 0;
+}
+
+static int prealloc_init(struct bpf_queue *queue)
+{
+	u32 node_size = sizeof(struct queue_node) +
+			round_up(queue->map.value_size, 8);
+	u32 num_entries = queue->map.max_entries;
+	int err;
+
+	queue->nodes = bpf_map_area_alloc(node_size * num_entries,
+					  queue->map.numa_node);
+	if (!queue->nodes)
+		return -ENOMEM;
+
+	err = pcpu_freelist_init(&queue->freelist);
+	if (err)
+		goto free_nodes;
+
+	pcpu_freelist_populate(&queue->freelist,
+			       queue->nodes +
+			       offsetof(struct queue_node, fnode),
+			       node_size, num_entries);
+
+	return 0;
+
+free_nodes:
+	bpf_map_area_free(queue->nodes);
+	return err;
+}
+
+static void prealloc_destroy(struct bpf_queue *queue)
+{
+	bpf_map_area_free(queue->nodes);
+	pcpu_freelist_destroy(&queue->freelist);
+}
+
+static struct bpf_map *queue_map_alloc(union bpf_attr *attr)
+{
+	struct bpf_queue *queue;
+	u64 cost = sizeof(*queue);
+	int ret;
+
+	queue = kzalloc(sizeof(*queue), GFP_USER);
+	if (!queue)
+		return ERR_PTR(-ENOMEM);
+
+	bpf_map_init_from_attr(&queue->map, attr);
+
+	queue->node_size = sizeof(struct queue_node) +
+			   round_up(attr->value_size, 8);
+	cost += (u64) attr->max_entries * queue->node_size;
+	if (cost >= U32_MAX - PAGE_SIZE) {
+		ret = -E2BIG;
+		goto free_queue;
+	}
+
+	queue->map.pages = round_up(cost, PAGE_SIZE) >> PAGE_SHIFT;
+
+	ret = bpf_map_precharge_memlock(queue->map.pages);
+	if (ret)
+		goto free_queue;
+
+	INIT_LIST_HEAD(&queue->head);
+
+	raw_spin_lock_init(&queue->lock);
+
+	queue->type = attr->map_flags >> 16;
+
+	if (queue_map_is_prealloc(queue))
+		ret = prealloc_init(queue);
+		if (ret)
+			goto free_queue;
+
+	return &queue->map;
+
+free_queue:
+	kfree(queue);
+	return ERR_PTR(ret);
+}
+
+/* Called when map->refcnt goes to zero, either from workqueue or from syscall */
+static void queue_map_free(struct bpf_map *map)
+{
+	struct bpf_queue *queue = container_of(map, struct bpf_queue, map);
+	struct queue_node *l;
+
+	/* at this point bpf_prog->aux->refcnt == 0 and this map->refcnt == 0,
+	 * so the programs (can be more than one that used this map) were
+	 * disconnected from events. Wait for outstanding critical sections in
+	 * these programs to complete
+	 */
+	synchronize_rcu();
+
+	/* some of queue_elem_free_rcu() callbacks for elements of this map may
+	 * not have executed. Wait for them.
+	 */
+	rcu_barrier();
+	if (!queue_map_is_prealloc(queue))
+		list_for_each_entry_rcu(l, &queue->head, list) {
+			list_del_rcu(&l->list);
+			kfree(l);
+		}
+	else
+		prealloc_destroy(queue);
+	kfree(queue);
+}
+
+static void queue_elem_free_rcu(struct rcu_head *head)
+{
+	struct queue_node *l = container_of(head, struct queue_node, rcu);
+	struct bpf_queue *queue = l->queue;
+
+	/* must increment bpf_prog_active to avoid kprobe+bpf triggering while
+	 * we're calling kfree, otherwise deadlock is possible if kprobes
+	 * are placed somewhere inside of slub
+	 */
+	preempt_disable();
+	__this_cpu_inc(bpf_prog_active);
+	if (queue_map_is_prealloc(queue))
+		pcpu_freelist_push(&queue->freelist, &l->fnode);
+	else
+		kfree(l);
+	__this_cpu_dec(bpf_prog_active);
+	preempt_enable();
+}
+
+/* Called from syscall or from eBPF program */
+static void *queue_map_lookup_elem(struct bpf_map *map, void *key)
+{
+	struct bpf_queue *queue = container_of(map, struct bpf_queue, map);
+	unsigned long flags;
+	struct queue_node *node;
+
+	raw_spin_lock_irqsave(&queue->lock, flags);
+
+	node = list_first_or_null_rcu(&queue->head, struct queue_node, list);
+	if (!node) {
+		raw_spin_unlock_irqrestore(&queue->lock, flags);
+		return NULL;
+	}
+
+	if (!queue_map_is_prealloc(queue))
+		atomic_dec(&queue->count);
+
+	list_del_rcu(&node->list);
+	call_rcu(&node->rcu, queue_elem_free_rcu);
+
+	raw_spin_unlock_irqrestore(&queue->lock, flags);
+
+	return &node->element;
+}
+
+/* Called from syscall or from eBPF program */
+static int queue_map_update_elem(struct bpf_map *map, void *key, void *value,
+				 u64 map_flags)
+{
+	struct bpf_queue *queue = container_of(map, struct bpf_queue, map);
+	unsigned long flags;
+	struct queue_node *new;
+
+	if (!queue_map_is_prealloc(queue)) {
+		if (atomic_inc_return(&queue->count) > queue->map.max_entries) {
+			atomic_dec(&queue->count);
+			return -E2BIG;
+		}
+
+		new = kmalloc_node(queue->node_size, GFP_ATOMIC | __GFP_NOWARN,
+				   queue->map.numa_node);
+		if (!new) {
+			atomic_dec(&queue->count);
+			return -ENOMEM;
+		}
+	} else {
+		struct pcpu_freelist_node *l;
+
+		l = pcpu_freelist_pop(&queue->freelist);
+		if (!l)
+			return -E2BIG;
+		new = container_of(l, struct queue_node, fnode);
+	}
+
+	memcpy(new->element, value, queue->map.value_size);
+	new->queue = queue;
+
+	raw_spin_lock_irqsave(&queue->lock, flags);
+	switch (queue->type) {
+	case QUEUE_FIFO:
+		list_add_tail_rcu(&new->list, &queue->head);
+		break;
+
+	case QUEUE_LIFO:
+		list_add_rcu(&new->list, &queue->head);
+		break;
+	}
+
+	raw_spin_unlock_irqrestore(&queue->lock, flags);
+
+	return 0;
+}
+
+/* Called from syscall or from eBPF program */
+static int queue_map_delete_elem(struct bpf_map *map, void *key)
+{
+	return -EINVAL;
+}
+
+/* Called from syscall */
+static int queue_map_get_next_key(struct bpf_map *map, void *key,
+				  void *next_key)
+{
+	return -EINVAL;
+}
+
+const struct bpf_map_ops queue_map_ops = {
+	.map_alloc_check = queue_map_alloc_check,
+	.map_alloc = queue_map_alloc,
+	.map_free = queue_map_free,
+	.map_lookup_elem = queue_map_lookup_elem,
+	.map_update_elem = queue_map_update_elem,
+	.map_delete_elem = queue_map_delete_elem,
+	.map_get_next_key = queue_map_get_next_key,
+};
+
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index a31a1ba0f8ea..7e9a11d69eef 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -622,11 +622,19 @@ static int map_lookup_elem(union bpf_attr *attr)
 		err = -EPERM;
 		goto err_put;
 	}
+	if (map->map_type != BPF_MAP_TYPE_QUEUE) {
+		key = memdup_user(ukey, map->key_size);
+		if (IS_ERR(key)) {
+			err = PTR_ERR(key);
+			goto err_put;
+		}
+	} else {
+		if (ukey) {
+			err = -EINVAL;
+			goto err_put;
+		}
 
-	key = memdup_user(ukey, map->key_size);
-	if (IS_ERR(key)) {
-		err = PTR_ERR(key);
-		goto err_put;
+		key = NULL;
 	}
 
 	if (map->map_type == BPF_MAP_TYPE_PERCPU_HASH ||
@@ -709,10 +717,19 @@ static int map_update_elem(union bpf_attr *attr)
 		goto err_put;
 	}
 
-	key = memdup_user(ukey, map->key_size);
-	if (IS_ERR(key)) {
-		err = PTR_ERR(key);
-		goto err_put;
+	if (map->map_type != BPF_MAP_TYPE_QUEUE) {
+		key = memdup_user(ukey, map->key_size);
+		if (IS_ERR(key)) {
+			err = PTR_ERR(key);
+			goto err_put;
+		}
+	} else {
+		if (ukey) {
+			err = -EINVAL;
+			goto err_put;
+		}
+
+		key = NULL;
 	}
 
 	if (map->map_type == BPF_MAP_TYPE_PERCPU_HASH ||
@@ -803,10 +820,19 @@ static int map_delete_elem(union bpf_attr *attr)
 		goto err_put;
 	}
 
-	key = memdup_user(ukey, map->key_size);
-	if (IS_ERR(key)) {
-		err = PTR_ERR(key);
-		goto err_put;
+	if (map->map_type != BPF_MAP_TYPE_QUEUE) {
+		key = memdup_user(ukey, map->key_size);
+		if (IS_ERR(key)) {
+			err = PTR_ERR(key);
+			goto err_put;
+		}
+	} else {
+		if (ukey) {
+			err = -EINVAL;
+			goto err_put;
+		}
+
+		key = NULL;
 	}
 
 	if (bpf_map_is_dev_bound(map)) {
@@ -855,9 +881,14 @@ static int map_get_next_key(union bpf_attr *attr)
 	}
 
 	if (ukey) {
-		key = memdup_user(ukey, map->key_size);
-		if (IS_ERR(key)) {
-			err = PTR_ERR(key);
+		if (map->map_type != BPF_MAP_TYPE_QUEUE) {
+			key = memdup_user(ukey, map->key_size);
+			if (IS_ERR(key)) {
+				err = PTR_ERR(key);
+				goto err_put;
+			}
+		} else {
+			err = -EINVAL;
 			goto err_put;
 		}
 	} else {
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 25e47c195874..83099a9a21d9 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -1976,8 +1976,12 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 regno,
 		return -EACCES;
 	}
 
-	if (arg_type == ARG_PTR_TO_MAP_KEY ||
-	    arg_type == ARG_PTR_TO_MAP_VALUE) {
+	if (arg_type == ARG_PTR_TO_MAP_KEY) {
+		expected_type = PTR_TO_STACK;
+		if (!type_is_pkt_pointer(type) && type != PTR_TO_MAP_VALUE &&
+		    type != expected_type && type != SCALAR_VALUE)
+			goto err_type;
+	} else if (arg_type == ARG_PTR_TO_MAP_VALUE) {
 		expected_type = PTR_TO_STACK;
 		if (!type_is_pkt_pointer(type) && type != PTR_TO_MAP_VALUE &&
 		    type != expected_type)
@@ -2021,6 +2025,7 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 regno,
 		/* bpf_map_xxx(map_ptr) call: remember that map_ptr */
 		meta->map_ptr = reg->map_ptr;
 	} else if (arg_type == ARG_PTR_TO_MAP_KEY) {
+		bool zero_size_allowed = false;
 		/* bpf_map_xxx(..., map_ptr, ..., key) call:
 		 * check that [key, key + map->key_size) are within
 		 * stack limits and initialized
@@ -2034,8 +2039,13 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 regno,
 			verbose(env, "invalid map_ptr to access map->key\n");
 			return -EACCES;
 		}
+
+		if (meta->map_ptr->map_type == BPF_MAP_TYPE_QUEUE)
+			zero_size_allowed = true;
+
 		err = check_helper_mem_access(env, regno,
-					      meta->map_ptr->key_size, false,
+					      meta->map_ptr->key_size,
+					      zero_size_allowed,
 					      NULL);
 	} else if (arg_type == ARG_PTR_TO_MAP_VALUE) {
 		/* bpf_map_xxx(..., map_ptr, ..., value) call:

^ permalink raw reply related

* [PATCH bpf-next 2/3] selftests/bpf: add test cases for BPF_MAP_TYPE_QUEUE
From: Mauricio Vasquez B @ 2018-08-06 13:58 UTC (permalink / raw)
  To: Alexei Starovoitov, Daniel Borkmann; +Cc: netdev
In-Reply-To: <153356387977.6981.12236150594041620482.stgit@kernel>

Signed-off-by: Mauricio Vasquez B <mauricio.vasquez@polito.it>
---
 tools/include/uapi/linux/bpf.h          |    5 ++
 tools/testing/selftests/bpf/test_maps.c |   72 +++++++++++++++++++++++++++++++
 2 files changed, 77 insertions(+)

diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h
index 0ebaaf7f3568..2c171c40eb45 100644
--- a/tools/include/uapi/linux/bpf.h
+++ b/tools/include/uapi/linux/bpf.h
@@ -120,6 +120,7 @@ enum bpf_map_type {
 	BPF_MAP_TYPE_CPUMAP,
 	BPF_MAP_TYPE_XSKMAP,
 	BPF_MAP_TYPE_SOCKHASH,
+	BPF_MAP_TYPE_QUEUE,
 };
 
 enum bpf_prog_type {
@@ -255,6 +256,10 @@ enum bpf_attach_type {
 /* Flag for stack_map, store build_id+offset instead of pointer */
 #define BPF_F_STACK_BUILD_ID	(1U << 5)
 
+/* Flags for queue_map, type of queue */
+#define BPF_F_QUEUE_FIFO	(1U << 16)
+#define BPF_F_QUEUE_LIFO	(2U << 16)
+
 enum bpf_stack_build_id_status {
 	/* user space need an empty entry to identify end of a trace */
 	BPF_STACK_BUILD_ID_EMPTY = 0,
diff --git a/tools/testing/selftests/bpf/test_maps.c b/tools/testing/selftests/bpf/test_maps.c
index 6c253343a6f9..34567b017dbb 100644
--- a/tools/testing/selftests/bpf/test_maps.c
+++ b/tools/testing/selftests/bpf/test_maps.c
@@ -457,6 +457,77 @@ static void test_devmap(int task, void *data)
 	close(fd);
 }
 
+static void test_queuemap(int task, void *data)
+{
+	__u32 value;
+	int fd, i;
+
+	/* test FIFO */
+	fd = bpf_create_map(BPF_MAP_TYPE_QUEUE, 0, sizeof(value), 32,
+			    BPF_F_QUEUE_FIFO);
+	if (fd < 0) {
+		printf("Failed to create queuemap '%s'!\n", strerror(errno));
+		exit(1);
+	}
+
+	/* Push 32 elements */
+	for (i = 0; i < 32; i++) {
+		value = 1000 - i * 3;
+		assert(bpf_map_update_elem(fd, NULL, &value, 0) == 0);
+	}
+
+	/* Check that element cannot be pushed due to max_entries limit */
+	value = 1000;
+	assert(bpf_map_update_elem(fd, NULL, &value, 0) == -1 &&
+	       errno == E2BIG);
+
+	/* Pop all elements */
+	for (i = 0; i < 32; i++)
+		assert(bpf_map_lookup_elem(fd, NULL, &value) == 0 &&
+		       value == (1000 - i * 3));
+
+	/* Check that there are not elements left */
+	assert(bpf_map_lookup_elem(fd, NULL, &value) == -1 && errno == ENOENT);
+
+	assert(bpf_map_delete_elem(fd, NULL) == -1 && errno == EINVAL);
+	assert(bpf_map_get_next_key(fd, NULL, NULL) == -1 && errno == EINVAL);
+
+	close(fd);
+
+	/* test LIFO */
+	fd = bpf_create_map(BPF_MAP_TYPE_QUEUE, 0, sizeof(value), 32,
+			    BPF_F_QUEUE_LIFO);
+	if (fd < 0) {
+		printf("Failed to create queuemap '%s'!\n", strerror(errno));
+		exit(1);
+	}
+
+	/* Push 32 elements */
+	for (i = 0; i < 32; i++) {
+		value = 1000 - i * 3;
+		assert(bpf_map_update_elem(fd, NULL, &value, 0) == 0);
+	}
+
+	/* Check that element cannot be pushed due to max_entries limit */
+	value = 1000;
+	assert(bpf_map_update_elem(fd, NULL, &value, 0) == -1 &&
+	       errno == E2BIG);
+
+	/* Pop all elements */
+	for (i = 31; i >= 0; i--)
+		assert(bpf_map_lookup_elem(fd, NULL, &value) == 0 &&
+		       value == (1000 - i * 3));
+
+	/* Check that there are not elements left */
+	assert(bpf_map_lookup_elem(fd, NULL, &value) == -1 &&
+	       errno == ENOENT);
+
+	assert(bpf_map_delete_elem(fd, NULL) == -1 && errno == EINVAL);
+	assert(bpf_map_get_next_key(fd, NULL, NULL) == -1 && errno == EINVAL);
+
+	close(fd);
+}
+
 #include <sys/socket.h>
 #include <sys/ioctl.h>
 #include <arpa/inet.h>
@@ -1162,6 +1233,7 @@ static void run_all_tests(void)
 	test_arraymap_percpu_many_keys();
 
 	test_devmap(0, NULL);
+	test_queuemap(0, NULL);
 	test_sockmap(0, NULL);
 
 	test_map_large();

^ permalink raw reply related

* [PATCH bpf-next 3/3] bpf: add sample for BPF_MAP_TYPE_QUEUE
From: Mauricio Vasquez B @ 2018-08-06 13:58 UTC (permalink / raw)
  To: Alexei Starovoitov, Daniel Borkmann; +Cc: netdev
In-Reply-To: <153356387977.6981.12236150594041620482.stgit@kernel>

The example is made by two parts, a eBPF program that consumes elements
from a FIFO queue and prints them in the screen and a user space
application that inserts new elements into the queue each time this is
executed.

Signed-off-by: Mauricio Vasquez B <mauricio.vasquez@polito.it>
---
 samples/bpf/.gitignore             |    1 +
 samples/bpf/Makefile               |    3 ++
 samples/bpf/test_map_in_map_user.c |    9 +-----
 samples/bpf/test_queuemap.sh       |   37 +++++++++++++++++++++++++
 samples/bpf/test_queuemap_kern.c   |   51 +++++++++++++++++++++++++++++++++++
 samples/bpf/test_queuemap_user.c   |   53 ++++++++++++++++++++++++++++++++++++
 6 files changed, 147 insertions(+), 7 deletions(-)
 create mode 100755 samples/bpf/test_queuemap.sh
 create mode 100644 samples/bpf/test_queuemap_kern.c
 create mode 100644 samples/bpf/test_queuemap_user.c

diff --git a/samples/bpf/.gitignore b/samples/bpf/.gitignore
index 8ae4940025f8..d7e518c1b3ed 100644
--- a/samples/bpf/.gitignore
+++ b/samples/bpf/.gitignore
@@ -26,6 +26,7 @@ test_lru_dist
 test_map_in_map
 test_overhead
 test_probe_write_user
+test_queuemap
 trace_event
 trace_output
 tracex1
diff --git a/samples/bpf/Makefile b/samples/bpf/Makefile
index f88d5683d6ee..624f4f4b81db 100644
--- a/samples/bpf/Makefile
+++ b/samples/bpf/Makefile
@@ -53,6 +53,7 @@ hostprogs-y += xdpsock
 hostprogs-y += xdp_fwd
 hostprogs-y += task_fd_query
 hostprogs-y += xdp_sample_pkts
+hostprogs-y += test_queuemap
 
 # Libbpf dependencies
 LIBBPF = $(TOOLS_PATH)/lib/bpf/libbpf.a
@@ -109,6 +110,7 @@ xdpsock-objs := xdpsock_user.o
 xdp_fwd-objs := xdp_fwd_user.o
 task_fd_query-objs := bpf_load.o task_fd_query_user.o $(TRACE_HELPERS)
 xdp_sample_pkts-objs := xdp_sample_pkts_user.o $(TRACE_HELPERS)
+test_queuemap-objs := bpf_load.o test_queuemap_user.o
 
 # Tell kbuild to always build the programs
 always := $(hostprogs-y)
@@ -166,6 +168,7 @@ always += xdpsock_kern.o
 always += xdp_fwd_kern.o
 always += task_fd_query_kern.o
 always += xdp_sample_pkts_kern.o
+always += test_queuemap_kern.o
 
 HOSTCFLAGS += -I$(objtree)/usr/include
 HOSTCFLAGS += -I$(srctree)/tools/lib/
diff --git a/samples/bpf/test_map_in_map_user.c b/samples/bpf/test_map_in_map_user.c
index e308858f7bcf..28edac94234e 100644
--- a/samples/bpf/test_map_in_map_user.c
+++ b/samples/bpf/test_map_in_map_user.c
@@ -1,10 +1,5 @@
-/*
- * Copyright (c) 2017 Facebook
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of version 2 of the GNU General Public
- * License as published by the Free Software Foundation.
- */
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2018 Politecnico di Torino */
 #include <sys/resource.h>
 #include <sys/socket.h>
 #include <arpa/inet.h>
diff --git a/samples/bpf/test_queuemap.sh b/samples/bpf/test_queuemap.sh
new file mode 100755
index 000000000000..ed08c1fa8c2c
--- /dev/null
+++ b/samples/bpf/test_queuemap.sh
@@ -0,0 +1,37 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+
+[[ -z $TC ]] && TC='tc'
+[[ -z $IP ]] && IP='ip'
+
+TEST_QUEUE_USER='./test_queuemap'
+TEST_QUEUE_BPF='./test_queuemap_kern.o'
+
+function config {
+	$IP netns add ns1
+	$IP link add ve1 type veth peer name vens1
+	$IP link set dev ve1 up
+	$IP link set dev ve1 mtu 1500
+	$IP link set dev vens1 netns ns1
+
+	$IP -n ns1 link set dev lo up
+	$IP -n ns1 link set dev vens1 up
+	$IP -n ns1 addr add 10.1.1.101/24 dev vens1
+
+	$IP addr add 10.1.1.1/24 dev ve1
+	$TC qdisc add dev ve1 clsact
+	$TC filter add dev ve1 ingress bpf da obj $TEST_QUEUE_BPF sec test_queue
+}
+
+function cleanup {
+	set +e
+	[[ -z $DEBUG ]] || set +x
+	$IP netns delete ns1 >& /dev/null
+	$IP link del ve1 >& /dev/null
+	rm -f /sys/fs/bpf/tc/globals/queue
+	[[ -z $DEBUG ]] || set -x
+	set -e
+}
+
+cleanup
+config
diff --git a/samples/bpf/test_queuemap_kern.c b/samples/bpf/test_queuemap_kern.c
new file mode 100644
index 000000000000..2b496dafaffd
--- /dev/null
+++ b/samples/bpf/test_queuemap_kern.c
@@ -0,0 +1,51 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2018 Politecnico di Torino */
+#define KBUILD_MODNAME "foo"
+#include <linux/ptrace.h>
+#include <linux/version.h>
+#include <uapi/linux/bpf.h>
+#include <uapi/linux/in6.h>
+#include <uapi/linux/pkt_cls.h>
+#include "bpf_helpers.h"
+
+#define PIN_GLOBAL_NS		2
+
+struct bpf_elf_map {
+	__u32 type;
+	__u32 key_size;
+	__u32 value_size;
+	__u32 max_entries;
+	__u32 flags;
+	__u32 id;
+	__u32 pinning;
+};
+
+/* map #0 */
+struct bpf_elf_map SEC("maps") queue = {
+	.type = BPF_MAP_TYPE_QUEUE,
+	.key_size = 0,
+	.value_size = sizeof(u32),
+	.flags = BPF_F_QUEUE_FIFO,
+	.max_entries = 1024,
+	.pinning = PIN_GLOBAL_NS,
+};
+
+SEC("test_queue")
+int _test_queue(struct __sk_buff *skb)
+{
+	char msg[] = "element is %u\n";
+	char msg_no[] = "there are not elements\n";
+
+	u32 *val = bpf_map_lookup_elem(&queue, NULL);
+
+	if (!val) {
+		bpf_trace_printk(msg_no, sizeof(msg_no));
+		return TC_ACT_OK;
+	}
+
+	bpf_trace_printk(msg, sizeof(msg), *val);
+	return TC_ACT_OK;
+}
+
+char _license[] SEC("license") = "GPL";
+u32 _version SEC("version") = LINUX_VERSION_CODE;
diff --git a/samples/bpf/test_queuemap_user.c b/samples/bpf/test_queuemap_user.c
new file mode 100644
index 000000000000..68f9a5d54596
--- /dev/null
+++ b/samples/bpf/test_queuemap_user.c
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2018 Politecnico di Torino
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ */
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <stdint.h>
+#include <assert.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <bpf/bpf.h>
+#include "bpf_load.h"
+
+int queue_map;
+
+static void test_queue_map(void)
+{
+	int ret;
+	uint32_t i;
+
+	queue_map = bpf_obj_get("/sys/fs/bpf/tc/globals/queue");
+	if (queue_map < 0) {
+		fprintf(stderr, "error getting map");
+		return;
+	}
+
+	for (i = 0; i < 256; i++) {
+		uint32_t v = 1000 - i*3;
+
+		ret = bpf_map_update_elem(queue_map, NULL, &v, 0);
+		if (ret)
+			fprintf(stderr, "ret is %d\n", ret);
+	}
+}
+
+int main(int argc, char **argv)
+{
+	struct rlimit r = {RLIM_INFINITY, RLIM_INFINITY};
+	char filename[256];
+
+	assert(!setrlimit(RLIMIT_MEMLOCK, &r));
+
+	snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]);
+
+	test_queue_map();
+
+	return 0;
+}

^ permalink raw reply related

* [PATCH net] packet: refine ring v3 block size test to hold one frame
From: Willem de Bruijn @ 2018-08-06 14:38 UTC (permalink / raw)
  To: netdev; +Cc: davem, eric.dumazet, loke.chetan, Willem de Bruijn

From: Willem de Bruijn <willemb@google.com>

TPACKET_V3 stores variable length frames in fixed length blocks.
Blocks must be able to store a block header, optional private space
and at least one minimum sized frame.

Frames, even for a zero snaplen packet, store metadata headers and
optional reserved space.

In the block size bounds check, ensure that the frame of the
chosen configuration fits. This includes sockaddr_ll and optional
tp_reserve.

Syzbot was able to construct a ring with insuffient room for the
sockaddr_ll in the header of a zero-length frame, triggering an
out-of-bounds write in dev_parse_header.

Convert the comparison to less than, as zero is a valid snap len.
This matches the test for minimum tp_frame_size immediately below.

Fixes: f6fb8f100b80 ("af-packet: TPACKET_V3 flexible buffer implementation.")
Fixes: eb73190f4fbe ("net/packet: refine check for priv area size")
Reported-by: syzbot <syzkaller@googlegroups.com>
Signed-off-by: Willem de Bruijn <willemb@google.com>
---
 net/packet/af_packet.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index 9b27d0cd766d5..e6445d8f3f57f 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -4226,6 +4226,8 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u,
 	}
 
 	if (req->tp_block_nr) {
+		unsigned int min_frame_size;
+
 		/* Sanity tests and some calculations */
 		err = -EBUSY;
 		if (unlikely(rb->pg_vec))
@@ -4248,12 +4250,12 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u,
 			goto out;
 		if (unlikely(!PAGE_ALIGNED(req->tp_block_size)))
 			goto out;
+		min_frame_size = po->tp_hdrlen + po->tp_reserve;
 		if (po->tp_version >= TPACKET_V3 &&
-		    req->tp_block_size <=
-		    BLK_PLUS_PRIV((u64)req_u->req3.tp_sizeof_priv) + sizeof(struct tpacket3_hdr))
+		    req->tp_block_size <
+		    BLK_PLUS_PRIV((u64)req_u->req3.tp_sizeof_priv) + min_frame_size)
 			goto out;
-		if (unlikely(req->tp_frame_size < po->tp_hdrlen +
-					po->tp_reserve))
+		if (unlikely(req->tp_frame_size < min_frame_size))
 			goto out;
 		if (unlikely(req->tp_frame_size & (TPACKET_ALIGNMENT - 1)))
 			goto out;
-- 
2.18.0.597.ga71716f1ad-goog

^ permalink raw reply related

* [PATCH] net: thunderx: check for failed allocation lmac->dmacs
From: Colin King @ 2018-08-06 16:50 UTC (permalink / raw)
  To: Sunil Goutham, Robert Richter, David S . Miller, linux-arm-kernel,
	netdev
  Cc: kernel-janitors, linux-kernel

From: Colin Ian King <colin.king@canonical.com>

The allocation of lmac->dmacs is not being checked for allocation
failure. Add the check.

Fixes: 3a34ecfd9d3f ("net: thunderx: add MAC address filter tracking for LMAC")
Signed-off-by: Colin Ian King <colin.king@canonical.com>
---
 drivers/net/ethernet/cavium/thunder/thunder_bgx.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/net/ethernet/cavium/thunder/thunder_bgx.c b/drivers/net/ethernet/cavium/thunder/thunder_bgx.c
index 5d08d2aeb172..e337da6ba2a4 100644
--- a/drivers/net/ethernet/cavium/thunder/thunder_bgx.c
+++ b/drivers/net/ethernet/cavium/thunder/thunder_bgx.c
@@ -1083,6 +1083,8 @@ static int bgx_lmac_enable(struct bgx *bgx, u8 lmacid)
 	lmac->dmacs_count = (RX_DMAC_COUNT / bgx->lmac_count);
 	lmac->dmacs = kcalloc(lmac->dmacs_count, sizeof(*lmac->dmacs),
 			      GFP_KERNEL);
+	if (!lmac->dmacs)
+		return -ENOMEM;
 
 	/* Enable lmac */
 	bgx_reg_modify(bgx, lmacid, BGX_CMRX_CFG, CMR_EN);
-- 
2.17.1

^ permalink raw reply related

* Re: [PATCH v4] selftests: add headers_install to lib.mk
From: Shuah Khan @ 2018-08-06 17:03 UTC (permalink / raw)
  To: Anders Roxell
  Cc: Masahiro Yamada, Michal Marek, Bamvor Zhang, brgl, Paolo Bonzini,
	Andrew Morton, Mike Rapoport, aarcange, linux-kbuild,
	Linux Kernel Mailing List, open list:KERNEL SELFTEST FRAMEWORK,
	Networking, Shuah Khan
In-Reply-To: <CADYN=9LSA60E4mFwrbeY-RGi4kZV6hO0ygz0-C6QB3+KKaoxQg@mail.gmail.com>

Hi Anders,

On 07/25/2018 10:08 AM, Anders Roxell wrote:
> On Tue, 24 Jul 2018 at 19:11, Shuah Khan <shuah@kernel.org> wrote:
>>
>> On 07/23/2018 02:49 PM, Anders Roxell wrote:
>>> On Thu, 7 Jun 2018 at 13:09, Anders Roxell <anders.roxell@linaro.org> wrote:
>>>>
>>>> If the kernel headers aren't installed we can't build all the tests.
>>>> Add a new make target rule 'khdr' in the file lib.mk to generate the
>>>> kernel headers and that gets include for every test-dir Makefile that
>>>> includes lib.mk If the testdir in turn have its own sub-dirs the
>>>> top_srcdir needs to be set to the linux-rootdir to be able to generate
>>>> the kernel headers.
>>>>
>>>> Signed-off-by: Anders Roxell <anders.roxell@linaro.org>
>>>> Reviewed-by: Fathi Boudra <fathi.boudra@linaro.org>
>>>> ---
>>>>  Makefile                                           | 14 +-------------
>>>>  scripts/subarch.include                            | 13 +++++++++++++
>>>>  tools/testing/selftests/android/Makefile           |  2 +-
>>>>  tools/testing/selftests/android/ion/Makefile       |  2 ++
>>>>  tools/testing/selftests/futex/functional/Makefile  |  1 +
>>>>  tools/testing/selftests/gpio/Makefile              |  7 ++-----
>>>>  tools/testing/selftests/kvm/Makefile               |  7 ++-----
>>>>  tools/testing/selftests/lib.mk                     | 12 ++++++++++++
>>>>  tools/testing/selftests/net/Makefile               |  1 +
>>>>  .../selftests/networking/timestamping/Makefile     |  1 +
>>>>  tools/testing/selftests/vm/Makefile                |  4 ----
>>>>  11 files changed, 36 insertions(+), 28 deletions(-)
>>>>  create mode 100644 scripts/subarch.include
>>>>
>>>> diff --git a/Makefile b/Makefile
>>>> index 6b9aea95ae3a..8050072300fa 100644
>>>> --- a/Makefile
>>>> +++ b/Makefile
>>>> @@ -286,19 +286,7 @@ KERNELRELEASE = $(shell cat include/config/kernel.release 2> /dev/null)
>>>>  KERNELVERSION = $(VERSION)$(if $(PATCHLEVEL),.$(PATCHLEVEL)$(if $(SUBLEVEL),.$(SUBLEVEL)))$(EXTRAVERSION)
>>>>  export VERSION PATCHLEVEL SUBLEVEL KERNELRELEASE KERNELVERSION
>>>>
>>>> -# SUBARCH tells the usermode build what the underlying arch is.  That is set
>>>> -# first, and if a usermode build is happening, the "ARCH=um" on the command
>>>> -# line overrides the setting of ARCH below.  If a native build is happening,
>>>> -# then ARCH is assigned, getting whatever value it gets normally, and
>>>> -# SUBARCH is subsequently ignored.
>>>> -
>>>> -SUBARCH := $(shell uname -m | sed -e s/i.86/x86/ -e s/x86_64/x86/ \
>>>> -                                 -e s/sun4u/sparc64/ \
>>>> -                                 -e s/arm.*/arm/ -e s/sa110/arm/ \
>>>> -                                 -e s/s390x/s390/ -e s/parisc64/parisc/ \
>>>> -                                 -e s/ppc.*/powerpc/ -e s/mips.*/mips/ \
>>>> -                                 -e s/sh[234].*/sh/ -e s/aarch64.*/arm64/ \
>>>> -                                 -e s/riscv.*/riscv/)
>>>> +include scripts/subarch.include
>>
>> What is the reason for this SUBARCH block move to to scripts/subarch.include?
>> Is this necessary for adding headers install dependency to lib.mk?
> 
> This is needed to create headers for cross build.
> 

I am sorry for the delay on this patch. I am going to get this into 4.19.
If anybody has objections, please let me.

Anders! Will be able to rebase the patch and send me the latest. I think
I have Acks from kvm, android, and vm so far.

thanks,
-- Shuah

^ permalink raw reply

* Re: [PATCH v2] net/bridge/br_multicast: remove redundant variable "err"
From: David Miller @ 2018-08-06 17:34 UTC (permalink / raw)
  To: zhongjiang; +Cc: stephen, netdev, linux-kernel
In-Reply-To: <1533524843-51236-1-git-send-email-zhongjiang@huawei.com>

From: zhong jiang <zhongjiang@huawei.com>
Date: Mon, 6 Aug 2018 11:07:23 +0800

> The err is not modified after initalization, So remove it and make
> it to be void function.
> 
> Signed-off-by: zhong jiang <zhongjiang@huawei.com>
> ---
> v1->v2:
>  -  The initalization of err  to '0' is unnecesary. so drop the change

Applied, thank you.

^ permalink raw reply

* Re: [PATCH v3 net-next 5/9] net: stmmac: Add MDIO related functions for XGMAC2
From: Florian Fainelli @ 2018-08-06 15:25 UTC (permalink / raw)
  To: Jose Abreu, netdev
  Cc: David S. Miller, Joao Pinto, Giuseppe Cavallaro, Alexandre Torgue,
	Andrew Lunn
In-Reply-To: <982b8bed-e11c-2f94-4f7d-21e358ffc0c0@synopsys.com>

On August 6, 2018 12:59:54 AM PDT, Jose Abreu <Jose.Abreu@synopsys.com> wrote:
>On 03-08-2018 20:06, Florian Fainelli wrote:
>> On 08/03/2018 08:50 AM, Jose Abreu wrote:
>>> Add the MDIO related funcionalities for the new IP block XGMAC2.
>>>
>>> Signed-off-by: Jose Abreu <joabreu@synopsys.com>
>>> Cc: David S. Miller <davem@davemloft.net>
>>> Cc: Joao Pinto <jpinto@synopsys.com>
>>> Cc: Giuseppe Cavallaro <peppe.cavallaro@st.com>
>>> Cc: Alexandre Torgue <alexandre.torgue@st.com>
>>> Cc: Andrew Lunn <andrew@lunn.ch>
>>> ---
>>> +satic int stmmac_xgmac2_c22_format(struct stmmac_priv *priv, int
>phyaddr,
>>> +				    int phyreg, u32 *hw_addr)
>>> +{
>>> +	unsigned int mii_data = priv->hw->mii.data;
>>> +	u32 tmp;
>>> +
>>> +	/* HW does not support C22 addr >= 4 */
>>> +	if (phyaddr >= 4)
>>> +		return -ENODEV;
>> It would be nice if this could be moved at probe time so you don't
>have
>> to wait until you connect to the PHY, read its PHY OUI and find out
>it
>> has a MDIO address >= 4. Not a blocker, but something that could be
>> improved further on.
>>
>> In premise you could even scan the MDIO bus' device tree node, and
>find
>> that out ahead of time.
>
>Oh, but I use phylib ... I only provide the read/write callbacks
>so I think we should avoid duplicating the code that's already in
>the phylib ... No?

You can always extract the code that scans a MDIO bus into a helper function and make it parametrized with a callback of some kind. In that case I would be fine with you open coding the MDIO bus scan to find out if there is an address >= 4.

>
>>
>>> +	/* Wait until any existing MII operation is complete */
>>> +	if (readl_poll_timeout(priv->ioaddr + mii_data, tmp,
>>> +			       !(tmp & MII_XGMAC_BUSY), 100, 10000))
>>> +		return -EBUSY;
>>> +
>>> +	/* Set port as Clause 22 */
>>> +	tmp = readl(priv->ioaddr + XGMAC_MDIO_C22P);
>>> +	tmp |= BIT(phyaddr);
>> Since the registers are being Read/Modify/Write here, don't you need
>to
>> clear the previous address bits as well?
>>
>> You probably did not encounter any problems in your testing if you
>had
>> only one PHY on the MDIO bus, but this is not something that is
>> necessarily true, e.g: if you have an Ethernet switch, several MDIO
>bus
>> addresses are going to be responding.
>>
>> Your MDIO bus implementation must be able to support one transaction
>> with one PHY address and the next transaction with another PHY
>address ,
>> etc...
>>
>> That is something that should be easy to fix and be resubmitted as
>part
>> of v4.
>
>I'm not following you here... I only set/unset the bit for the
>corresponding phyaddr that phylib wants to read/write. Why would
>I clear the remaining addresses?

Because this is all about transactions, the HW must be in a state that it will be able to perform that transaction correctly. So here for instance if you needed to support a C45 transaction you would have to clear that bit for that particular PHY address. Since you don't appear to support those yet then yes the code appears fine though it would not hurt if you did clear all other PHY's c22 bits to make it clear what this does.

-- 
Florian

^ permalink raw reply

* Re: [PATCH net-next V2] vhost: switch to use new message format
From: David Miller @ 2018-08-06 17:41 UTC (permalink / raw)
  To: jasowang; +Cc: mst, kvm, virtualization, netdev, linux-kernel
In-Reply-To: <1533525467-17787-1-git-send-email-jasowang@redhat.com>

From: Jason Wang <jasowang@redhat.com>
Date: Mon,  6 Aug 2018 11:17:47 +0800

> We use to have message like:
> 
> struct vhost_msg {
> 	int type;
> 	union {
> 		struct vhost_iotlb_msg iotlb;
> 		__u8 padding[64];
> 	};
> };
> 
> Unfortunately, there will be a hole of 32bit in 64bit machine because
> of the alignment. This leads a different formats between 32bit API and
> 64bit API. What's more it will break 32bit program running on 64bit
> machine.
> 
> So fixing this by introducing a new message type with an explicit
> 32bit reserved field after type like:
> 
> struct vhost_msg_v2 {
> 	__u32 type;
> 	__u32 reserved;
> 	union {
> 		struct vhost_iotlb_msg iotlb;
> 		__u8 padding[64];
> 	};
> };
> 
> We will have a consistent ABI after switching to use this. To enable
> this capability, introduce a new ioctl (VHOST_SET_BAKCEND_FEATURE) for
> userspace to enable this feature (VHOST_BACKEND_F_IOTLB_V2).
> 
> Fixes: 6b1e6cc7855b ("vhost: new device IOTLB API")
> Signed-off-by: Jason Wang <jasowang@redhat.com>
> ---
> Changes from V1:
> - use __u32 instead of int for type

Applied, thanks Jason.

^ permalink raw reply

* Re: [PATCH net-next] net: avoid unnecessary sock_flag() check when enable timestamp
From: David Miller @ 2018-08-06 17:43 UTC (permalink / raw)
  To: laoar.shao; +Cc: netdev, linux-kernel
In-Reply-To: <1533527822-3324-1-git-send-email-laoar.shao@gmail.com>

From: Yafang Shao <laoar.shao@gmail.com>
Date: Mon,  6 Aug 2018 11:57:02 +0800

> The sock_flag() check is alreay inside sock_enable_timestamp(), so it is
> unnecessary checking it in the caller.
> 
>     void sock_enable_timestamp(struct sock *sk, int flag)
>     {
>         if (!sock_flag(sk, flag)) {
>             ...
>         }
>     }
> 
> Signed-off-by: Yafang Shao <laoar.shao@gmail.com>

Applied.

^ permalink raw reply

* Re: [PATCH] ptp_qoriq: use div_u64/div_u64_rem for 64-bit division
From: David Miller @ 2018-08-06 17:43 UTC (permalink / raw)
  To: yangbo.lu; +Cc: netdev, richardcochran, linux-kernel
In-Reply-To: <20180806043911.15437-1-yangbo.lu@nxp.com>

From: Yangbo Lu <yangbo.lu@nxp.com>
Date: Mon,  6 Aug 2018 12:39:11 +0800

> This is a fix-up patch for below build issue with multi_v7_defconfig.
> 
> drivers/ptp/ptp_qoriq.o: In function `qoriq_ptp_probe':
> ptp_qoriq.c:(.text+0xd0c): undefined reference to `__aeabi_uldivmod'
> 
> Fixes: 91305f281262 ("ptp_qoriq: support automatic configuration for ptp timer")
> Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>

Applied.

^ permalink raw reply

* [PATCH iproute2-next 0/3] support delivering packets in delayed
From: Yousuk Seung @ 2018-08-06 17:09 UTC (permalink / raw)
  To: netdev
  Cc: Stephen Hemminger, David Ahern, Michael McLennan, Priyaranjan Jha,
	Yousuk Seung

This series adds support for the new "slot" netem parameter for
slotting. Slotting is an approximation of shared media that gather up
packets within a varying delay window before delivering them nearly at
once.

Dave Taht (2):
  tc: support conversions to or from 64 bit nanosecond-based time
  q_netem: support delivering packets in delayed time slots

Yousuk Seung (1):
  q_netem: slotting with non-uniform distribution

 man/man8/tc-netem.8 |  40 +++++++++++++++-
 tc/q_netem.c        | 112 +++++++++++++++++++++++++++++++++++++++++++-
 tc/tc_core.h        |   4 ++
 tc/tc_util.c        |  55 ++++++++++++++++++++++
 tc/tc_util.h        |   3 ++
 5 files changed, 212 insertions(+), 2 deletions(-)

-- 
2.18.0.597.ga71716f1ad-goog

^ permalink raw reply

* [PATCH iproute2-next 1/3] tc: support conversions to or from 64 bit nanosecond-based time
From: Yousuk Seung @ 2018-08-06 17:09 UTC (permalink / raw)
  To: netdev
  Cc: Stephen Hemminger, David Ahern, Michael McLennan, Priyaranjan Jha,
	Dave Taht, Yousuk Seung, Neal Cardwell
In-Reply-To: <20180806170953.164776-1-ysseung@google.com>

From: Dave Taht <dave.taht@gmail.com>

Using a 32 bit field to represent time in nanoseconds results in a
maximum value of about 4.3 seconds, which is well below many observed
delays in WiFi and LTE, and barely in the ballpark for a trip past the
Earth's moon, Luna.

Using 64 bit time fields in nanoseconds allows us to simulate
network diameters of several hundred light-years. However, only
conversions to and from ns, us, ms, and seconds are provided.

Signed-off-by: Yousuk Seung <ysseung@google.com>
Signed-off-by: Dave Taht <dave.taht@gmail.com>
Signed-off-by: Neal Cardwell <ncardwell@google.com>
---
 tc/tc_core.h |  4 ++++
 tc/tc_util.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 tc/tc_util.h |  3 +++
 3 files changed, 62 insertions(+)

diff --git a/tc/tc_core.h b/tc/tc_core.h
index 1dfa9a4f773b..a0fe0923d171 100644
--- a/tc/tc_core.h
+++ b/tc/tc_core.h
@@ -7,6 +7,10 @@
 
 #define TIME_UNITS_PER_SEC	1000000
 
+#define NSEC_PER_USEC 1000
+#define NSEC_PER_MSEC 1000000
+#define NSEC_PER_SEC 1000000000LL
+
 enum link_layer {
 	LINKLAYER_UNSPEC,
 	LINKLAYER_ETHERNET,
diff --git a/tc/tc_util.c b/tc/tc_util.c
index d7578528a31b..c39c9046dcae 100644
--- a/tc/tc_util.c
+++ b/tc/tc_util.c
@@ -385,6 +385,61 @@ char *sprint_ticks(__u32 ticks, char *buf)
 	return sprint_time(tc_core_tick2time(ticks), buf);
 }
 
+/* 64 bit times are represented internally in nanoseconds */
+int get_time64(__s64 *time, const char *str)
+{
+	double nsec;
+	char *p;
+
+	nsec = strtod(str, &p);
+	if (p == str)
+		return -1;
+
+	if (*p) {
+		if (strcasecmp(p, "s") == 0 ||
+		    strcasecmp(p, "sec") == 0 ||
+		    strcasecmp(p, "secs") == 0)
+			nsec *= NSEC_PER_SEC;
+		else if (strcasecmp(p, "ms") == 0 ||
+			 strcasecmp(p, "msec") == 0 ||
+			 strcasecmp(p, "msecs") == 0)
+			nsec *= NSEC_PER_MSEC;
+		else if (strcasecmp(p, "us") == 0 ||
+			 strcasecmp(p, "usec") == 0 ||
+			 strcasecmp(p, "usecs") == 0)
+			nsec *= NSEC_PER_USEC;
+		else if (strcasecmp(p, "ns") == 0 ||
+			 strcasecmp(p, "nsec") == 0 ||
+			 strcasecmp(p, "nsecs") == 0)
+			nsec *= 1;
+		else
+			return -1;
+	}
+
+	*time = nsec;
+	return 0;
+}
+
+void print_time64(char *buf, int len, __s64 time)
+{
+	double nsec = time;
+
+	if (time >= NSEC_PER_SEC)
+		snprintf(buf, len, "%.3fs", nsec/NSEC_PER_SEC);
+	else if (time >= NSEC_PER_MSEC)
+		snprintf(buf, len, "%.3fms", nsec/NSEC_PER_MSEC);
+	else if (time >= NSEC_PER_USEC)
+		snprintf(buf, len, "%.3fus", nsec/NSEC_PER_USEC);
+	else
+		snprintf(buf, len, "%lldns", time);
+}
+
+char *sprint_time64(__s64 time, char *buf)
+{
+	print_time64(buf, SPRINT_BSIZE-1, time);
+	return buf;
+}
+
 int get_size(unsigned int *size, const char *str)
 {
 	double sz;
diff --git a/tc/tc_util.h b/tc/tc_util.h
index 6632c4f9c528..87be951c622d 100644
--- a/tc/tc_util.h
+++ b/tc/tc_util.h
@@ -82,12 +82,14 @@ int get_percent_rate64(__u64 *rate, const char *str, const char *dev);
 int get_size(unsigned int *size, const char *str);
 int get_size_and_cell(unsigned int *size, int *cell_log, char *str);
 int get_time(unsigned int *time, const char *str);
+int get_time64(__s64 *time, const char *str);
 int get_linklayer(unsigned int *val, const char *arg);
 
 void print_rate(char *buf, int len, __u64 rate);
 void print_size(char *buf, int len, __u32 size);
 void print_qdisc_handle(char *buf, int len, __u32 h);
 void print_time(char *buf, int len, __u32 time);
+void print_time64(char *buf, int len, __s64 time);
 void print_linklayer(char *buf, int len, unsigned int linklayer);
 void print_devname(enum output_type type, int ifindex);
 
@@ -96,6 +98,7 @@ char *sprint_size(__u32 size, char *buf);
 char *sprint_qdisc_handle(__u32 h, char *buf);
 char *sprint_tc_classid(__u32 h, char *buf);
 char *sprint_time(__u32 time, char *buf);
+char *sprint_time64(__s64 time, char *buf);
 char *sprint_ticks(__u32 ticks, char *buf);
 char *sprint_linklayer(unsigned int linklayer, char *buf);
 
-- 
2.18.0.597.ga71716f1ad-goog

^ permalink raw reply related

* [PATCH iproute2-next 2/3] q_netem: support delivering packets in delayed time slots
From: Yousuk Seung @ 2018-08-06 17:09 UTC (permalink / raw)
  To: netdev
  Cc: Stephen Hemminger, David Ahern, Michael McLennan, Priyaranjan Jha,
	Dave Taht, Yousuk Seung, Neal Cardwell
In-Reply-To: <20180806170953.164776-1-ysseung@google.com>

From: Dave Taht <dave.taht@gmail.com>

Slotting is a crude approximation of the behaviors of shared media such
as cable, wifi, and LTE, which gather up a bunch of packets within a
varying delay window and deliver them, relative to that, nearly all at
once.

It works within the existing loss, duplication, jitter and delay
parameters of netem. Some amount of inherent latency must be specified,
regardless.

The new "slot" parameter specifies a minimum and maximum delay between
transmission attempts.

The "bytes" and "packets" parameters can be used to limit the amount of
information transferred per slot.

Examples of use:

tc qdisc add dev eth0 root netem delay 200us \
        slot 800us 10ms bytes 64k packets 42

A more correct example, using stacked netem instances and a packet limit
to emulate a tail drop wifi queue with slots and variable packet
delivery, with a 200Mbit isochronous underlying rate, and 20ms path
delay:

tc qdisc add dev eth0 root handle 1: netem delay 20ms rate 200mbit \
         limit 10000
tc qdisc add dev eth0 parent 1:1 handle 10:1 netem delay 200us \
         slot 800us 10ms bytes 64k packets 42 limit 512

Signed-off-by: Yousuk Seung <ysseung@google.com>
Signed-off-by: Dave Taht <dave.taht@gmail.com>
Signed-off-by: Neal Cardwell <ncardwell@google.com>
---
 man/man8/tc-netem.8 | 32 ++++++++++++++++++++++-
 tc/q_netem.c        | 63 ++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 93 insertions(+), 2 deletions(-)

diff --git a/man/man8/tc-netem.8 b/man/man8/tc-netem.8
index f2cd86b6ed8a..8d485b026751 100644
--- a/man/man8/tc-netem.8
+++ b/man/man8/tc-netem.8
@@ -8,7 +8,8 @@ NetEm \- Network Emulator
 .I OPTIONS
 
 .IR OPTIONS " := [ " LIMIT " ] [ " DELAY " ] [ " LOSS \
-" ] [ " CORRUPT " ] [ " DUPLICATION " ] [ " REORDERING " ][ " RATE " ]"
+" ] [ " CORRUPT " ] [ " DUPLICATION " ] [ " REORDERING " ] [ " RATE \
+" ] [ " SLOT " ]"
 
 .IR LIMIT " := "
 .B limit
@@ -51,6 +52,14 @@ NetEm \- Network Emulator
 .B rate
 .IR RATE " [ " PACKETOVERHEAD " [ " CELLSIZE " [ " CELLOVERHEAD " ]]]]"
 
+.IR SLOT " := "
+.BR slot
+.IR MIN_DELAY " [ " MAX_DELAY " ] ["
+.BR packets
+.IR PACKETS " ] [ "
+.BR bytes
+.IR BYTES " ]"
+
 
 .SH DESCRIPTION
 NetEm is an enhancement of the Linux traffic control facilities
@@ -162,6 +171,27 @@ granularity avoid a perfect shaping at a specific level. This will show up in
 an artificial packet compression (bursts). Another influence factor are network
 adapter buffers which can also add artificial delay.
 
+.SS slot
+defer delivering accumulated packets to within a slot, with each available slot
+configured with a minimum delay to acquire, and an optional maximum delay.  Slot
+delays can be specified in nanoseconds, microseconds, milliseconds or seconds
+(e.g. 800us). Values for the optional parameters
+.I BYTES
+will limit the number of bytes delivered per slot, and/or
+.I PACKETS
+will limit the number of packets delivered per slot.
+
+These slot options can provide a crude approximation of bursty MACs such as
+DOCSIS, WiFi, and LTE.
+
+Note that slotting is limited by several factors: the kernel clock granularity,
+as with a rate, and attempts to deliver many packets within a slot will be
+smeared by the timer resolution, and by the underlying native bandwidth also.
+
+It is possible to combine slotting with a rate, in which case complex behaviors
+where either the rate, or the slot limits on bytes or packets per slot, govern
+the actual delivered rate.
+
 .SH LIMITATIONS
 The main known limitation of Netem are related to timer granularity, since
 Linux is not a real-time operating system.
diff --git a/tc/q_netem.c b/tc/q_netem.c
index 9f9a9b3df255..f52a36b6c31c 100644
--- a/tc/q_netem.c
+++ b/tc/q_netem.c
@@ -40,7 +40,10 @@ static void explain(void)
 "                 [ loss gemodel PERCENT [R [1-H [1-K]]]\n" \
 "                 [ ecn ]\n" \
 "                 [ reorder PRECENT [CORRELATION] [ gap DISTANCE ]]\n" \
-"                 [ rate RATE [PACKETOVERHEAD] [CELLSIZE] [CELLOVERHEAD]]\n");
+"                 [ rate RATE [PACKETOVERHEAD] [CELLSIZE] [CELLOVERHEAD]]\n" \
+"                 [ slot MIN_DELAY [MAX_DELAY] [packets MAX_PACKETS]" \
+" [bytes MAX_BYTES]]\n" \
+		);
 }
 
 static void explain1(const char *arg)
@@ -164,6 +167,7 @@ static int netem_parse_opt(struct qdisc_util *qu, int argc, char **argv,
 	struct tc_netem_gimodel gimodel;
 	struct tc_netem_gemodel gemodel;
 	struct tc_netem_rate rate = {};
+	struct tc_netem_slot slot = {};
 	__s16 *dist_data = NULL;
 	__u16 loss_type = NETEM_LOSS_UNSPEC;
 	int present[__TCA_NETEM_MAX] = {};
@@ -412,6 +416,44 @@ static int netem_parse_opt(struct qdisc_util *qu, int argc, char **argv,
 					return -1;
 				}
 			}
+		} else if (matches(*argv, "slot") == 0) {
+			NEXT_ARG();
+			present[TCA_NETEM_SLOT] = 1;
+			if (get_time64(&slot.min_delay, *argv)) {
+				explain1("slot min_delay");
+				return -1;
+			}
+			if (NEXT_IS_NUMBER()) {
+				NEXT_ARG();
+				if (get_time64(&slot.max_delay, *argv)) {
+					explain1("slot min_delay max_delay");
+					return -1;
+				}
+			}
+			if (slot.max_delay < slot.min_delay)
+				slot.max_delay = slot.min_delay;
+			if (NEXT_ARG_OK() &&
+			    matches(*(argv+1), "packets") == 0) {
+				NEXT_ARG();
+				if (!NEXT_ARG_OK() ||
+				    get_s32(&slot.max_packets, *(argv+1), 0)) {
+					explain1("slot packets");
+					return -1;
+				}
+				NEXT_ARG();
+			}
+			if (NEXT_ARG_OK() &&
+			    matches(*(argv+1), "bytes") == 0) {
+				unsigned int max_bytes;
+				NEXT_ARG();
+				if (!NEXT_ARG_OK() ||
+				    get_size(&max_bytes, *(argv+1))) {
+					explain1("slot bytes");
+					return -1;
+				}
+				slot.max_bytes = (int) max_bytes;
+				NEXT_ARG();
+			}
 		} else if (strcmp(*argv, "help") == 0) {
 			explain();
 			return -1;
@@ -472,6 +514,10 @@ static int netem_parse_opt(struct qdisc_util *qu, int argc, char **argv,
 	    addattr_l(n, 1024, TCA_NETEM_CORRUPT, &corrupt, sizeof(corrupt)) < 0)
 		return -1;
 
+	if (present[TCA_NETEM_SLOT] &&
+	    addattr_l(n, 1024, TCA_NETEM_SLOT, &slot, sizeof(slot)) < 0)
+		return -1;
+
 	if (loss_type != NETEM_LOSS_UNSPEC) {
 		struct rtattr *start;
 
@@ -526,6 +572,7 @@ static int netem_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
 	int *ecn = NULL;
 	struct tc_netem_qopt qopt;
 	const struct tc_netem_rate *rate = NULL;
+	const struct tc_netem_slot *slot = NULL;
 	int len;
 	__u64 rate64 = 0;
 
@@ -586,6 +633,11 @@ static int netem_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
 				return -1;
 			rate64 = rta_getattr_u64(tb[TCA_NETEM_RATE64]);
 		}
+		if (tb[TCA_NETEM_SLOT]) {
+			if (RTA_PAYLOAD(tb[TCA_NETEM_SLOT]) < sizeof(*slot))
+				return -1;
+		        slot = RTA_DATA(tb[TCA_NETEM_SLOT]);
+		}
 	}
 
 	fprintf(f, "limit %d", qopt.limit);
@@ -659,6 +711,15 @@ static int netem_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
 			fprintf(f, " celloverhead %d", rate->cell_overhead);
 	}
 
+	if (slot) {
+		fprintf(f, " slot %s", sprint_time64(slot->min_delay, b1));
+		fprintf(f, " %s", sprint_time64(slot->max_delay, b1));
+		if(slot->max_packets)
+			fprintf(f, " packets %d", slot->max_packets);
+		if(slot->max_bytes)
+			fprintf(f, " bytes %d", slot->max_bytes);
+	}
+
 	if (ecn)
 		fprintf(f, " ecn ");
 
-- 
2.18.0.597.ga71716f1ad-goog

^ permalink raw reply related

* [PATCH iproute2-next 3/3] q_netem: slotting with non-uniform distribution
From: Yousuk Seung @ 2018-08-06 17:09 UTC (permalink / raw)
  To: netdev
  Cc: Stephen Hemminger, David Ahern, Michael McLennan, Priyaranjan Jha,
	Yousuk Seung, Neal Cardwell, Dave Taht
In-Reply-To: <20180806170953.164776-1-ysseung@google.com>

Extend slotting with support for non-uniform distributions. This is
similar to netem's non-uniform distribution delay feature.

Syntax:
   slot distribution DISTRIBUTION DELAY JITTER [packets MAX_PACKETS] \
      [bytes MAX_BYTES]

The syntax and use of the distribution table is the same as in the
non-uniform distribution delay feature. A file DISTRIBUTION must be
present in TC_LIB_DIR (e.g. /usr/lib/tc) containing numbers scaled by
NETEM_DIST_SCALE. A random value x is selected from the table and it
takes DELAY + ( x * JITTER ) as delay. Correlation between values is not
supported.

Examples:
  Normal distribution delay with mean = 800us and stdev = 100us.
  > tc qdisc add dev eth0 root netem slot distribution normal \
    800us 100us

  Optionally set the max slot size in bytes and/or packets.
  > tc qdisc add dev eth0 root netem slot distribution normal \
    800us 100us bytes 64k packets 42

Signed-off-by: Yousuk Seung <ysseung@google.com>
Signed-off-by: Neal Cardwell <ncardwell@google.com>
Signed-off-by: Dave Taht <dave.taht@gmail.com>
---
 man/man8/tc-netem.8 | 20 ++++++++----
 tc/q_netem.c        | 75 +++++++++++++++++++++++++++++++++++++--------
 2 files changed, 76 insertions(+), 19 deletions(-)

diff --git a/man/man8/tc-netem.8 b/man/man8/tc-netem.8
index 8d485b026751..111109cf042f 100644
--- a/man/man8/tc-netem.8
+++ b/man/man8/tc-netem.8
@@ -53,9 +53,13 @@ NetEm \- Network Emulator
 .IR RATE " [ " PACKETOVERHEAD " [ " CELLSIZE " [ " CELLOVERHEAD " ]]]]"
 
 .IR SLOT " := "
-.BR slot
-.IR MIN_DELAY " [ " MAX_DELAY " ] ["
-.BR packets
+.BR slot " { "
+.IR MIN_DELAY " [ " MAX_DELAY " ] |"
+.br
+.RB "               " distribution " { "uniform " | " normal " | " pareto " | " paretonormal " | "
+.IR FILE " } " DELAY " " JITTER " } "
+.br
+.RB "             [ " packets
 .IR PACKETS " ] [ "
 .BR bytes
 .IR BYTES " ]"
@@ -172,9 +176,13 @@ an artificial packet compression (bursts). Another influence factor are network
 adapter buffers which can also add artificial delay.
 
 .SS slot
-defer delivering accumulated packets to within a slot, with each available slot
-configured with a minimum delay to acquire, and an optional maximum delay.  Slot
-delays can be specified in nanoseconds, microseconds, milliseconds or seconds
+defer delivering accumulated packets to within a slot. Each available slot can be
+configured with a minimum delay to acquire, and an optional maximum delay.
+Alternatively it can be configured with the distribution similar to
+.BR distribution
+for
+.BR delay
+option. Slot delays can be specified in nanoseconds, microseconds, milliseconds or seconds
 (e.g. 800us). Values for the optional parameters
 .I BYTES
 will limit the number of bytes delivered per slot, and/or
diff --git a/tc/q_netem.c b/tc/q_netem.c
index f52a36b6c31c..e655e1a82e12 100644
--- a/tc/q_netem.c
+++ b/tc/q_netem.c
@@ -43,7 +43,9 @@ static void explain(void)
 "                 [ rate RATE [PACKETOVERHEAD] [CELLSIZE] [CELLOVERHEAD]]\n" \
 "                 [ slot MIN_DELAY [MAX_DELAY] [packets MAX_PACKETS]" \
 " [bytes MAX_BYTES]]\n" \
-		);
+"                 [ slot distribution" \
+" {uniform|normal|pareto|paretonormal|custom} DELAY JITTER" \
+" [packets MAX_PACKETS] [bytes MAX_BYTES]]\n");
 }
 
 static void explain1(const char *arg)
@@ -159,6 +161,7 @@ static int netem_parse_opt(struct qdisc_util *qu, int argc, char **argv,
 			   struct nlmsghdr *n, const char *dev)
 {
 	int dist_size = 0;
+	int slot_dist_size = 0;
 	struct rtattr *tail;
 	struct tc_netem_qopt opt = { .limit = 1000 };
 	struct tc_netem_corr cor = {};
@@ -169,6 +172,7 @@ static int netem_parse_opt(struct qdisc_util *qu, int argc, char **argv,
 	struct tc_netem_rate rate = {};
 	struct tc_netem_slot slot = {};
 	__s16 *dist_data = NULL;
+	__s16 *slot_dist_data = NULL;
 	__u16 loss_type = NETEM_LOSS_UNSPEC;
 	int present[__TCA_NETEM_MAX] = {};
 	__u64 rate64 = 0;
@@ -417,21 +421,53 @@ static int netem_parse_opt(struct qdisc_util *qu, int argc, char **argv,
 				}
 			}
 		} else if (matches(*argv, "slot") == 0) {
-			NEXT_ARG();
-			present[TCA_NETEM_SLOT] = 1;
-			if (get_time64(&slot.min_delay, *argv)) {
-				explain1("slot min_delay");
-				return -1;
-			}
 			if (NEXT_IS_NUMBER()) {
 				NEXT_ARG();
-				if (get_time64(&slot.max_delay, *argv)) {
-					explain1("slot min_delay max_delay");
+				present[TCA_NETEM_SLOT] = 1;
+				if (get_time64(&slot.min_delay, *argv)) {
+					explain1("slot min_delay");
+					return -1;
+				}
+				if (NEXT_IS_NUMBER()) {
+					NEXT_ARG();
+					if (get_time64(&slot.max_delay, *argv)) {
+						explain1("slot min_delay max_delay");
+						return -1;
+					}
+				}
+				if (slot.max_delay < slot.min_delay)
+					slot.max_delay = slot.min_delay;
+			} else {
+				NEXT_ARG();
+				if (strcmp(*argv, "distribution") == 0) {
+					present[TCA_NETEM_SLOT] = 1;
+					NEXT_ARG();
+					slot_dist_data = calloc(sizeof(slot_dist_data[0]), MAX_DIST);
+					slot_dist_size = get_distribution(*argv, slot_dist_data, MAX_DIST);
+					if (slot_dist_size <= 0) {
+						free(slot_dist_data);
+						return -1;
+					}
+					NEXT_ARG();
+					if (get_time64(&slot.dist_delay, *argv)) {
+						explain1("slot delay");
+						return -1;
+					}
+					NEXT_ARG();
+					if (get_time64(&slot.dist_jitter, *argv)) {
+						explain1("slot jitter");
+						return -1;
+					}
+					if (slot.dist_jitter <= 0) {
+						fprintf(stderr, "Non-positive jitter\n");
+						return -1;
+					}
+				} else {
+					fprintf(stderr, "Unknown slot parameter: %s\n",
+						*argv);
 					return -1;
 				}
 			}
-			if (slot.max_delay < slot.min_delay)
-				slot.max_delay = slot.min_delay;
 			if (NEXT_ARG_OK() &&
 			    matches(*(argv+1), "packets") == 0) {
 				NEXT_ARG();
@@ -558,6 +594,14 @@ static int netem_parse_opt(struct qdisc_util *qu, int argc, char **argv,
 			return -1;
 		free(dist_data);
 	}
+
+	if (slot_dist_data) {
+		if (addattr_l(n, MAX_DIST * sizeof(slot_dist_data[0]),
+			      TCA_NETEM_SLOT_DIST,
+			      slot_dist_data, slot_dist_size * sizeof(slot_dist_data[0])) < 0)
+			return -1;
+		free(slot_dist_data);
+	}
 	tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
 	return 0;
 }
@@ -712,8 +756,13 @@ static int netem_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
 	}
 
 	if (slot) {
-		fprintf(f, " slot %s", sprint_time64(slot->min_delay, b1));
-		fprintf(f, " %s", sprint_time64(slot->max_delay, b1));
+		if (slot->dist_jitter > 0) {
+		    fprintf(f, " slot distribution %s", sprint_time64(slot->dist_delay, b1));
+		    fprintf(f, " %s", sprint_time64(slot->dist_jitter, b1));
+		} else {
+		    fprintf(f, " slot %s", sprint_time64(slot->min_delay, b1));
+		    fprintf(f, " %s", sprint_time64(slot->max_delay, b1));
+		}
 		if(slot->max_packets)
 			fprintf(f, " packets %d", slot->max_packets);
 		if(slot->max_bytes)
-- 
2.18.0.597.ga71716f1ad-goog

^ permalink raw reply related

* Re: [PATCH] mellanox: fix the dport endianness in call of __inet6_lookup_established()
From: David Miller @ 2018-08-06 17:32 UTC (permalink / raw)
  To: viro; +Cc: borisp, netdev
In-Reply-To: <20180804204127.GC15082@ZenIV.linux.org.uk>

From: Al Viro <viro@ZenIV.linux.org.uk>
Date: Sat, 4 Aug 2018 21:41:27 +0100

> __inet6_lookup_established() expect th->dport passed in host-endian,
> not net-endian.  The reason is microoptimization in __inet6_lookup(),
> but if you use the lower-level helpers, you have to play by their
> rules...
>     
> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>

Applied to net-next, thanks Al.

^ permalink raw reply

* [Patch net] vsock: split dwork to avoid reinitializations
From: Cong Wang @ 2018-08-06 18:06 UTC (permalink / raw)
  To: netdev; +Cc: Cong Wang, Andy king, Stefan Hajnoczi, Jorgen Hansen

syzbot reported that we reinitialize an active delayed
work in vsock_stream_connect():

	ODEBUG: init active (active state 0) object type: timer_list hint:
	delayed_work_timer_fn+0x0/0x90 kernel/workqueue.c:1414
	WARNING: CPU: 1 PID: 11518 at lib/debugobjects.c:329
	debug_print_object+0x16a/0x210 lib/debugobjects.c:326

The pattern is apparently wrong, we should only initialize
the dealyed work once and could repeatly schedule it. So we
have to move out the initializations to allocation side.
And to avoid confusion, we can split the shared dwork
into two, instead of re-using the same one.

Fixes: d021c344051a ("VSOCK: Introduce VM Sockets")
Reported-by: <syzbot+8a9b1bd330476a4f3db6@syzkaller.appspotmail.com>
Cc: Andy king <acking@vmware.com>
Cc: Stefan Hajnoczi <stefanha@redhat.com>
Cc: Jorgen Hansen <jhansen@vmware.com>
Signed-off-by: Cong Wang <xiyou.wangcong@gmail.com>
---
 include/net/af_vsock.h         |  4 ++--
 net/vmw_vsock/af_vsock.c       | 15 ++++++++-------
 net/vmw_vsock/vmci_transport.c |  3 +--
 3 files changed, 11 insertions(+), 11 deletions(-)

diff --git a/include/net/af_vsock.h b/include/net/af_vsock.h
index 9324ac2d9ff2..43913ae79f64 100644
--- a/include/net/af_vsock.h
+++ b/include/net/af_vsock.h
@@ -64,7 +64,8 @@ struct vsock_sock {
 	struct list_head pending_links;
 	struct list_head accept_queue;
 	bool rejected;
-	struct delayed_work dwork;
+	struct delayed_work connect_work;
+	struct delayed_work pending_work;
 	struct delayed_work close_work;
 	bool close_work_scheduled;
 	u32 peer_shutdown;
@@ -77,7 +78,6 @@ struct vsock_sock {
 
 s64 vsock_stream_has_data(struct vsock_sock *vsk);
 s64 vsock_stream_has_space(struct vsock_sock *vsk);
-void vsock_pending_work(struct work_struct *work);
 struct sock *__vsock_create(struct net *net,
 			    struct socket *sock,
 			    struct sock *parent,
diff --git a/net/vmw_vsock/af_vsock.c b/net/vmw_vsock/af_vsock.c
index c1076c19b858..ab27a2872935 100644
--- a/net/vmw_vsock/af_vsock.c
+++ b/net/vmw_vsock/af_vsock.c
@@ -451,14 +451,14 @@ static int vsock_send_shutdown(struct sock *sk, int mode)
 	return transport->shutdown(vsock_sk(sk), mode);
 }
 
-void vsock_pending_work(struct work_struct *work)
+static void vsock_pending_work(struct work_struct *work)
 {
 	struct sock *sk;
 	struct sock *listener;
 	struct vsock_sock *vsk;
 	bool cleanup;
 
-	vsk = container_of(work, struct vsock_sock, dwork.work);
+	vsk = container_of(work, struct vsock_sock, pending_work.work);
 	sk = sk_vsock(vsk);
 	listener = vsk->listener;
 	cleanup = true;
@@ -498,7 +498,6 @@ void vsock_pending_work(struct work_struct *work)
 	sock_put(sk);
 	sock_put(listener);
 }
-EXPORT_SYMBOL_GPL(vsock_pending_work);
 
 /**** SOCKET OPERATIONS ****/
 
@@ -597,6 +596,8 @@ static int __vsock_bind(struct sock *sk, struct sockaddr_vm *addr)
 	return retval;
 }
 
+static void vsock_connect_timeout(struct work_struct *work);
+
 struct sock *__vsock_create(struct net *net,
 			    struct socket *sock,
 			    struct sock *parent,
@@ -638,6 +639,8 @@ struct sock *__vsock_create(struct net *net,
 	vsk->sent_request = false;
 	vsk->ignore_connecting_rst = false;
 	vsk->peer_shutdown = 0;
+	INIT_DELAYED_WORK(&vsk->connect_work, vsock_connect_timeout);
+	INIT_DELAYED_WORK(&vsk->pending_work, vsock_pending_work);
 
 	psk = parent ? vsock_sk(parent) : NULL;
 	if (parent) {
@@ -1117,7 +1120,7 @@ static void vsock_connect_timeout(struct work_struct *work)
 	struct vsock_sock *vsk;
 	int cancel = 0;
 
-	vsk = container_of(work, struct vsock_sock, dwork.work);
+	vsk = container_of(work, struct vsock_sock, connect_work.work);
 	sk = sk_vsock(vsk);
 
 	lock_sock(sk);
@@ -1221,9 +1224,7 @@ static int vsock_stream_connect(struct socket *sock, struct sockaddr *addr,
 			 * timeout fires.
 			 */
 			sock_hold(sk);
-			INIT_DELAYED_WORK(&vsk->dwork,
-					  vsock_connect_timeout);
-			schedule_delayed_work(&vsk->dwork, timeout);
+			schedule_delayed_work(&vsk->connect_work, timeout);
 
 			/* Skip ahead to preserve error code set above. */
 			goto out_wait;
diff --git a/net/vmw_vsock/vmci_transport.c b/net/vmw_vsock/vmci_transport.c
index a7a73ffe675b..cb332adb84cd 100644
--- a/net/vmw_vsock/vmci_transport.c
+++ b/net/vmw_vsock/vmci_transport.c
@@ -1094,8 +1094,7 @@ static int vmci_transport_recv_listen(struct sock *sk,
 	vpending->listener = sk;
 	sock_hold(sk);
 	sock_hold(pending);
-	INIT_DELAYED_WORK(&vpending->dwork, vsock_pending_work);
-	schedule_delayed_work(&vpending->dwork, HZ);
+	schedule_delayed_work(&vpending->pending_work, HZ);
 
 out:
 	return err;
-- 
2.14.4

^ permalink raw reply related

* Re: SLAB_TYPESAFE_BY_RCU without constructors (was Re: [PATCH v4 13/17] khwasan: add hooks implementation)
From: Jan Kara @ 2018-08-06 20:20 UTC (permalink / raw)
  To: Dmitry Vyukov
  Cc: Dave Airlie, DRI, linux-mm, Eric Dumazet, Christoph Lameter,
	Gerrit Renker, dccp, coreteam, Jozsef Kadlecsik, Andrey Ryabinin,
	linux-ext4, Alexey Kuznetsov, Pablo Neira Ayuso, linux-s390,
	Andrey Konovalov, intel-gfx, Jan Kara, Ursula Braun, Rodrigo Vivi,
	Theodore Ts'o, Hideaki YOSHIFUJI, Network Development,
	Florian Westphal, Linux Kernel Mailing List
In-Reply-To: <CACT4Y+aYZumcc-Od5T1AnP4mwn8-FaWfxvfb93MnNwQPqG8TDw@mail.gmail.com>

On Wed 01-08-18 10:46:35, Dmitry Vyukov wrote:
> I guess it would be useful to have such extensive comment for each
> SLAB_TYPESAFE_BY_RCU use explaining why it is needed and how all the
> tricky aspects are handled.
> 
> For example, the one in jbd2 is interesting because it memsets the
> whole object before freeing it into SLAB_TYPESAFE_BY_RCU slab:
> 
> memset(jh, JBD2_POISON_FREE, sizeof(*jh));
> kmem_cache_free(jbd2_journal_head_cache, jh);
> 
> I guess there are also tricky ways how it can all work in the end
> (type-stable state is only a byte, or we check for all possible
> combinations of being overwritten with JBD2_POISON_FREE). But at first
> sight it does look fishy.

The RCU access is used from a single place:

fs/jbd2/transaction.c: jbd2_write_access_granted()

There are also quite some comments explaining why what it does is safe. The
overwrite by JBD2_POISON_FREE is much older than this RCU stuff (honestly I
didn't know about it until this moment) and has nothing to do with the
safety of RCU access.

								Honza

-- 
Jan Kara <jack@suse.com>
SUSE Labs, CR
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply

* Re: [PATCH net-next] tcp: fix the calculation of sysctl_max_tw_buckets in tcp_sk_init()
From: David Miller @ 2018-08-06 20:41 UTC (permalink / raw)
  To: laoar.shao; +Cc: edumazet, yanhaishuang, netdev, linux-kernel
In-Reply-To: <1533556020-20778-1-git-send-email-laoar.shao@gmail.com>

From: Yafang Shao <laoar.shao@gmail.com>
Date: Mon,  6 Aug 2018 19:47:00 +0800

> tcp_hashinfo.ehash_mask is always an odd number, which is set in function
> alloc_large_system_hash(). See bellow,
> 	if (_hash_mask)
> 		*_hash_mask = (1 << log2qty) - 1; <<< always odd number
> 
> Hence the local variable 'cnt' is a even number, as a result of that it is
> no difference to do the incrementation here.
> 
> Maybe the compiler could also optimize it, but this code is a little ugly.
> 
> Fix: fee83d09 ("ipv4: Namespaceify tcp_max_syn_backlog knob")

The correct tag is "Fixes: "

> @@ -2543,7 +2543,7 @@ static int __net_init tcp_sk_init(struct net *net)
>  	net->ipv4.sysctl_tcp_tw_reuse = 2;
>  
>  	cnt = tcp_hashinfo.ehash_mask + 1;
> -	net->ipv4.tcp_death_row.sysctl_max_tw_buckets = (cnt + 1) / 2;
> +	net->ipv4.tcp_death_row.sysctl_max_tw_buckets = cnt / 2;
>  	net->ipv4.tcp_death_row.hashinfo = &tcp_hashinfo;

This is completely harmless, and does no harm.

You aren't "fixing" anything.

^ permalink raw reply

* [PATCH net-next,v2] net/tls: Calculate nsg for zerocopy path without skb_cow_data.
From: Doron Roberts-Kedes @ 2018-08-06 18:25 UTC (permalink / raw)
  To: David S . Miller
  Cc: Vakul Garg, Dave Watson, Boris Pismenny, Aviad Yehezkel, netdev,
	Doron Roberts-Kedes

decrypt_skb fails if the number of sg elements required to map is
greater than MAX_SKB_FRAGS. As noted by Vakul Garg, nsg must always be
calculated, but skb_cow_data adds unnecessary memcpy's for the zerocopy
case.

The new function skb_nsg calculates the number of scatterlist elements
required to map the skb without the extra overhead of skb_cow_data. This
function mimics the structure of skb_to_sgvec.

Fixes: c46234ebb4d1 ("tls: RX path for ktls")
Signed-off-by: Doron Roberts-Kedes <doronrk@fb.com>
---
 net/tls/tls_sw.c | 93 ++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 90 insertions(+), 3 deletions(-)

diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c
index ff3a6904a722..e1c465a2ce0b 100644
--- a/net/tls/tls_sw.c
+++ b/net/tls/tls_sw.c
@@ -43,6 +43,76 @@
 
 #define MAX_IV_SIZE	TLS_CIPHER_AES_GCM_128_IV_SIZE
 
+static int __skb_nsg(struct sk_buff *skb, int offset, int len,
+		   unsigned int recursion_level)
+{
+        int start = skb_headlen(skb);
+        int i, copy = start - offset;
+        struct sk_buff *frag_iter;
+        int elt = 0;
+
+        if (unlikely(recursion_level >= 24))
+                return -EMSGSIZE;
+
+        if (copy > 0) {
+                if (copy > len)
+                        copy = len;
+                elt++;
+                if ((len -= copy) == 0)
+                        return elt;
+                offset += copy;
+        }
+
+        for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
+                int end;
+
+                WARN_ON(start > offset + len);
+
+                end = start + skb_frag_size(&skb_shinfo(skb)->frags[i]);
+                if ((copy = end - offset) > 0) {
+                        if (copy > len)
+                                copy = len;
+                        elt++;
+                        if (!(len -= copy))
+                                return elt;
+                        offset += copy;
+                }
+                start = end;
+        }
+
+        skb_walk_frags(skb, frag_iter) {
+                int end, ret;
+
+                WARN_ON(start > offset + len);
+
+                end = start + frag_iter->len;
+                if ((copy = end - offset) > 0) {
+
+                        if (copy > len)
+                                copy = len;
+                        ret = __skb_nsg(frag_iter, offset - start, copy,
+					recursion_level + 1);
+                        if (unlikely(ret < 0))
+                                return ret;
+                        elt += ret;
+                        if ((len -= copy) == 0)
+                                return elt;
+                        offset += copy;
+                }
+                start = end;
+        }
+        BUG_ON(len);
+        return elt;
+}
+
+/* Return the number of scatterlist elements required to completely map the
+ * skb, or -EMSGSIZE if the recursion depth is exceeded.
+ */
+static int skb_nsg(struct sk_buff *skb, int offset, int len)
+{
+	return __skb_nsg(skb, offset, len, 0);
+}
+
 static int tls_do_decryption(struct sock *sk,
 			     struct scatterlist *sgin,
 			     struct scatterlist *sgout,
@@ -693,7 +763,7 @@ int decrypt_skb(struct sock *sk, struct sk_buff *skb,
 	struct scatterlist sgin_arr[MAX_SKB_FRAGS + 2];
 	struct scatterlist *sgin = &sgin_arr[0];
 	struct strp_msg *rxm = strp_msg(skb);
-	int ret, nsg = ARRAY_SIZE(sgin_arr);
+	int ret, nsg;
 	struct sk_buff *unused;
 
 	ret = skb_copy_bits(skb, rxm->offset + TLS_HEADER_SIZE,
@@ -704,11 +774,28 @@ int decrypt_skb(struct sock *sk, struct sk_buff *skb,
 
 	memcpy(iv, tls_ctx->rx.iv, TLS_CIPHER_AES_GCM_128_SALT_SIZE);
 	if (!sgout) {
-		nsg = skb_cow_data(skb, 0, &unused) + 1;
+		nsg = skb_cow_data(skb, 0, &unused);
+	} else {
+		nsg = skb_nsg(skb,
+			      rxm->offset + tls_ctx->rx.prepend_size,
+			      rxm->full_len - tls_ctx->rx.prepend_size);
+		if (nsg <= 0)
+			return nsg;
+	}
+
+	// We need one extra for ctx->rx_aad_ciphertext
+	nsg++;
+
+	if (nsg > ARRAY_SIZE(sgin_arr)) {
 		sgin = kmalloc_array(nsg, sizeof(*sgin), sk->sk_allocation);
-		sgout = sgin;
+		if (!sgin)
+			return -ENOMEM;
 	}
 
+
+	if (!sgout)
+		sgout = sgin;
+
 	sg_init_table(sgin, nsg);
 	sg_set_buf(&sgin[0], ctx->rx_aad_ciphertext, TLS_AAD_SPACE_SIZE);
 
-- 
2.17.1

^ permalink raw reply related

* Re: [PATCH net-next] net/tls: Calculate nsg for zerocopy path without skb_cow_data.
From: Doron Roberts-Kedes @ 2018-08-06 18:32 UTC (permalink / raw)
  To: Vakul Garg
  Cc: David S . Miller, Dave Watson, Boris Pismenny, Aviad Yehezkel,
	netdev@vger.kernel.org
In-Reply-To: <20180803184902.GA27063@doronrk-mbp.dhcp.thefacebook.com>

On Fri, Aug 03, 2018 at 11:49:02AM -0700, Doron Roberts-Kedes wrote:
> On Fri, Aug 03, 2018 at 01:23:33AM +0000, Vakul Garg wrote:
> > 
> > 
> > > -----Original Message-----
> > > From: Doron Roberts-Kedes [mailto:doronrk@fb.com]
> > > Sent: Friday, August 3, 2018 6:00 AM
> > > To: David S . Miller <davem@davemloft.net>
> > > Cc: Dave Watson <davejwatson@fb.com>; Vakul Garg
> > > <vakul.garg@nxp.com>; Boris Pismenny <borisp@mellanox.com>; Aviad
> > > Yehezkel <aviadye@mellanox.com>; netdev@vger.kernel.org; Doron
> > > Roberts-Kedes <doronrk@fb.com>
> > > Subject: [PATCH net-next] net/tls: Calculate nsg for zerocopy path without
> > > skb_cow_data.
> > > 
> > > decrypt_skb fails if the number of sg elements required to map is greater
> > > than MAX_SKB_FRAGS. As noted by Vakul Garg, nsg must always be
> > > calculated, but skb_cow_data adds unnecessary memcpy's for the zerocopy
> > > case.
> > > 
> > > The new function skb_nsg calculates the number of scatterlist elements
> > > required to map the skb without the extra overhead of skb_cow_data. This
> > > function mimics the structure of skb_to_sgvec.
> > > 
> > > Fixes: c46234ebb4d1 ("tls: RX path for ktls")
> > > Signed-off-by: Doron Roberts-Kedes <doronrk@fb.com>
> > > ---
> > >  net/tls/tls_sw.c | 89
> > > ++++++++++++++++++++++++++++++++++++++++++++++--
> > >  1 file changed, 86 insertions(+), 3 deletions(-)
> > > 
> > >  	memcpy(iv, tls_ctx->rx.iv, TLS_CIPHER_AES_GCM_128_SALT_SIZE);
> > >  	if (!sgout) {
> > > -		nsg = skb_cow_data(skb, 0, &unused) + 1;
> > > +		nsg = skb_cow_data(skb, 0, &unused);
> > > +	} else {
> > > +		nsg = skb_nsg(skb,
> > > +			      rxm->offset + tls_ctx->rx.prepend_size,
> > > +			      rxm->full_len - tls_ctx->rx.prepend_size);
> > > +		if (nsg <= 0)
> > > +			return nsg;
> > Comparison should be (nsg < 1). TLS forbids '0' sized records.
> 
> Yes true, v2 incoming
>

Glancing at this a second time, I actually don't believe this should be
changed. nsg <= 0 is equivalent to nsg < 1. Returning 0 if the record is
0 sized is the proper behavior here, since decrypting a zero-length skb
is a no-op. It is true that zero sized TLS records are forbidden, but it
is confusing to enforce that in this part of the code. I would be
surpised to learn that tls_sw_recvmsg could be invoked with a len equal
to 0, but if I'm wrong, and that case does need to be handled, then it
should be in a different patch. 

^ permalink raw reply

* [PATCH bpf-next] bpf: introduce update_effective_progs()
From: Roman Gushchin @ 2018-08-06 21:27 UTC (permalink / raw)
  To: netdev
  Cc: linux-kernel, kernel-team, Roman Gushchin, Alexei Starovoitov,
	Daniel Borkmann

__cgroup_bpf_attach() and __cgroup_bpf_detach() functions have
a good amount of duplicated code, which is possible to eliminate
by introducing the update_effective_progs() helper function.

The update_effective_progs() calls compute_effective_progs()
and then in case of success it calls activate_effective_progs()
for each descendant cgroup. In case of failure (OOM), it releases
allocated prog arrays and return the error code.

Signed-off-by: Roman Gushchin <guro@fb.com>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Daniel Borkmann <daniel@iogearbox.net>
Acked-by: Song Liu <songliubraving@fb.com>
---
 kernel/bpf/cgroup.c | 99 ++++++++++++++++++++++++-----------------------------
 1 file changed, 45 insertions(+), 54 deletions(-)

diff --git a/kernel/bpf/cgroup.c b/kernel/bpf/cgroup.c
index 0a4fe5a7dc91..6a7d931bbc55 100644
--- a/kernel/bpf/cgroup.c
+++ b/kernel/bpf/cgroup.c
@@ -177,6 +177,45 @@ int cgroup_bpf_inherit(struct cgroup *cgrp)
 	return -ENOMEM;
 }
 
+static int update_effective_progs(struct cgroup *cgrp,
+				  enum bpf_attach_type type)
+{
+	struct cgroup_subsys_state *css;
+	int err;
+
+	/* allocate and recompute effective prog arrays */
+	css_for_each_descendant_pre(css, &cgrp->self) {
+		struct cgroup *desc = container_of(css, struct cgroup, self);
+
+		err = compute_effective_progs(desc, type, &desc->bpf.inactive);
+		if (err)
+			goto cleanup;
+	}
+
+	/* all allocations were successful. Activate all prog arrays */
+	css_for_each_descendant_pre(css, &cgrp->self) {
+		struct cgroup *desc = container_of(css, struct cgroup, self);
+
+		activate_effective_progs(desc, type, desc->bpf.inactive);
+		desc->bpf.inactive = NULL;
+	}
+
+	return 0;
+
+cleanup:
+	/* oom while computing effective. Free all computed effective arrays
+	 * since they were not activated
+	 */
+	css_for_each_descendant_pre(css, &cgrp->self) {
+		struct cgroup *desc = container_of(css, struct cgroup, self);
+
+		bpf_prog_array_free(desc->bpf.inactive);
+		desc->bpf.inactive = NULL;
+	}
+
+	return err;
+}
+
 #define BPF_CGROUP_MAX_PROGS 64
 
 /**
@@ -194,7 +233,6 @@ int __cgroup_bpf_attach(struct cgroup *cgrp, struct bpf_prog *prog,
 	struct list_head *progs = &cgrp->bpf.progs[type];
 	struct bpf_prog *old_prog = NULL;
 	struct bpf_cgroup_storage *storage, *old_storage = NULL;
-	struct cgroup_subsys_state *css;
 	struct bpf_prog_list *pl;
 	bool pl_was_allocated;
 	int err;
@@ -261,22 +299,9 @@ int __cgroup_bpf_attach(struct cgroup *cgrp, struct bpf_prog *prog,
 
 	cgrp->bpf.flags[type] = flags;
 
-	/* allocate and recompute effective prog arrays */
-	css_for_each_descendant_pre(css, &cgrp->self) {
-		struct cgroup *desc = container_of(css, struct cgroup, self);
-
-		err = compute_effective_progs(desc, type, &desc->bpf.inactive);
-		if (err)
-			goto cleanup;
-	}
-
-	/* all allocations were successful. Activate all prog arrays */
-	css_for_each_descendant_pre(css, &cgrp->self) {
-		struct cgroup *desc = container_of(css, struct cgroup, self);
-
-		activate_effective_progs(desc, type, desc->bpf.inactive);
-		desc->bpf.inactive = NULL;
-	}
+	err = update_effective_progs(cgrp, type);
+	if (err)
+		goto cleanup;
 
 	static_branch_inc(&cgroup_bpf_enabled_key);
 	if (old_storage)
@@ -289,16 +314,6 @@ int __cgroup_bpf_attach(struct cgroup *cgrp, struct bpf_prog *prog,
 	return 0;
 
 cleanup:
-	/* oom while computing effective. Free all computed effective arrays
-	 * since they were not activated
-	 */
-	css_for_each_descendant_pre(css, &cgrp->self) {
-		struct cgroup *desc = container_of(css, struct cgroup, self);
-
-		bpf_prog_array_free(desc->bpf.inactive);
-		desc->bpf.inactive = NULL;
-	}
-
 	/* and cleanup the prog list */
 	pl->prog = old_prog;
 	bpf_cgroup_storage_free(pl->storage);
@@ -326,7 +341,6 @@ int __cgroup_bpf_detach(struct cgroup *cgrp, struct bpf_prog *prog,
 	struct list_head *progs = &cgrp->bpf.progs[type];
 	u32 flags = cgrp->bpf.flags[type];
 	struct bpf_prog *old_prog = NULL;
-	struct cgroup_subsys_state *css;
 	struct bpf_prog_list *pl;
 	int err;
 
@@ -365,22 +379,9 @@ int __cgroup_bpf_detach(struct cgroup *cgrp, struct bpf_prog *prog,
 		pl->prog = NULL;
 	}
 
-	/* allocate and recompute effective prog arrays */
-	css_for_each_descendant_pre(css, &cgrp->self) {
-		struct cgroup *desc = container_of(css, struct cgroup, self);
-
-		err = compute_effective_progs(desc, type, &desc->bpf.inactive);
-		if (err)
-			goto cleanup;
-	}
-
-	/* all allocations were successful. Activate all prog arrays */
-	css_for_each_descendant_pre(css, &cgrp->self) {
-		struct cgroup *desc = container_of(css, struct cgroup, self);
-
-		activate_effective_progs(desc, type, desc->bpf.inactive);
-		desc->bpf.inactive = NULL;
-	}
+	err = update_effective_progs(cgrp, type);
+	if (err)
+		goto cleanup;
 
 	/* now can actually delete it from this cgroup list */
 	list_del(&pl->node);
@@ -396,16 +397,6 @@ int __cgroup_bpf_detach(struct cgroup *cgrp, struct bpf_prog *prog,
 	return 0;
 
 cleanup:
-	/* oom while computing effective. Free all computed effective arrays
-	 * since they were not activated
-	 */
-	css_for_each_descendant_pre(css, &cgrp->self) {
-		struct cgroup *desc = container_of(css, struct cgroup, self);
-
-		bpf_prog_array_free(desc->bpf.inactive);
-		desc->bpf.inactive = NULL;
-	}
-
 	/* and restore back old_prog */
 	pl->prog = old_prog;
 	return err;
-- 
2.14.4

^ permalink raw reply related

* [PATCH net-next] ipv4: frags: precedence bug in ip_expire()
From: Dan Carpenter @ 2018-08-06 19:17 UTC (permalink / raw)
  To: David S. Miller, Peter Oskolkov
  Cc: Alexey Kuznetsov, Hideaki YOSHIFUJI, netdev, kernel-janitors

We accidentally removed the parentheses here, but they are required
because '!' has higher precedence than '&'.

Fixes: fa0f527358bd ("ip: use rb trees for IP frag queue.")
Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>

diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c
index 0e8f8de77e71..7cb7ed761d8c 100644
--- a/net/ipv4/ip_fragment.c
+++ b/net/ipv4/ip_fragment.c
@@ -154,7 +154,7 @@ static void ip_expire(struct timer_list *t)
 	__IP_INC_STATS(net, IPSTATS_MIB_REASMFAILS);
 	__IP_INC_STATS(net, IPSTATS_MIB_REASMTIMEOUT);
 
-	if (!qp->q.flags & INET_FRAG_FIRST_IN)
+	if (!(qp->q.flags & INET_FRAG_FIRST_IN))
 		goto out;
 
 	/* sk_buff::dev and sk_buff::rbnode are unionized. So we

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox