Netdev List
 help / color / mirror / Atom feed
* [PATCH v3 net-next 2/9] ila: Fix use of rhashtable walk in ila_xlat.c
From: Tom Herbert @ 2017-12-11 20:38 UTC (permalink / raw)
  To: davem; +Cc: netdev, roopa, rohit, Tom Herbert
In-Reply-To: <20171211203837.2540-1-tom@quantonium.net>

Perform better EAGAIN handling, handle case where ila_dump_info
fails and we miss mis objects in the dump, and add a skip index
to skip over ila entires in a list on a rhashtable node that have
already been visited (by a previous call to ila_nl_dump).

Signed-off-by: Tom Herbert <tom@quantonium.net>
---
 net/ipv6/ila/ila_xlat.c | 60 ++++++++++++++++++++++++++++++++++++-------------
 1 file changed, 44 insertions(+), 16 deletions(-)

diff --git a/net/ipv6/ila/ila_xlat.c b/net/ipv6/ila/ila_xlat.c
index 44c39c5f0638..9fca75b9cab3 100644
--- a/net/ipv6/ila/ila_xlat.c
+++ b/net/ipv6/ila/ila_xlat.c
@@ -474,24 +474,31 @@ static int ila_nl_cmd_get_mapping(struct sk_buff *skb, struct genl_info *info)
 
 struct ila_dump_iter {
 	struct rhashtable_iter rhiter;
+	int skip;
 };
 
 static int ila_nl_dump_start(struct netlink_callback *cb)
 {
 	struct net *net = sock_net(cb->skb->sk);
 	struct ila_net *ilan = net_generic(net, ila_net_id);
-	struct ila_dump_iter *iter = (struct ila_dump_iter *)cb->args[0];
+	struct ila_dump_iter *iter;
+	int ret;
 
-	if (!iter) {
-		iter = kmalloc(sizeof(*iter), GFP_KERNEL);
-		if (!iter)
-			return -ENOMEM;
+	iter = kmalloc(sizeof(*iter), GFP_KERNEL);
+	if (!iter)
+		return -ENOMEM;
 
-		cb->args[0] = (long)iter;
+	ret = rhashtable_walk_init(&ilan->rhash_table, &iter->rhiter,
+				   GFP_KERNEL);
+	if (ret) {
+		kfree(iter);
+		return ret;
 	}
 
-	return rhashtable_walk_init(&ilan->rhash_table, &iter->rhiter,
-				    GFP_KERNEL);
+	iter->skip = 0;
+	cb->args[0] = (long)iter;
+
+	return ret;
 }
 
 static int ila_nl_dump_done(struct netlink_callback *cb)
@@ -509,37 +516,58 @@ static int ila_nl_dump(struct sk_buff *skb, struct netlink_callback *cb)
 {
 	struct ila_dump_iter *iter = (struct ila_dump_iter *)cb->args[0];
 	struct rhashtable_iter *rhiter = &iter->rhiter;
+	int skip = iter->skip;
 	struct ila_map *ila;
 	int ret;
 
 	rhashtable_walk_start(rhiter);
 
-	for (;;) {
-		ila = rhashtable_walk_next(rhiter);
+	/* Get first entty */
+	ila = rhashtable_walk_peek(rhiter);
 
+	for (;;) {
 		if (IS_ERR(ila)) {
-			if (PTR_ERR(ila) == -EAGAIN)
-				continue;
 			ret = PTR_ERR(ila);
-			goto done;
+			if (ret == -EAGAIN) {
+				/* Table has changed and iter has reset. Return
+				 * -EAGAIN to the application even if we have
+				 * written data to the skb. The application
+				 * needs to deal with this.
+				 */
+
+				goto out_ret;
+			} else {
+				break;
+			}
 		} else if (!ila) {
+			ret = 0;
 			break;
 		}
 
+		while (ila && skip) {
+			/* Skip over any ila entries in this list that we
+			 * have already dumped.
+			 */
+			ila = rcu_access_pointer(ila->next);
+			skip--;
+		}
 		while (ila) {
 			ret =  ila_dump_info(ila, NETLINK_CB(cb->skb).portid,
 					     cb->nlh->nlmsg_seq, NLM_F_MULTI,
 					     skb, ILA_CMD_GET);
 			if (ret)
-				goto done;
+				goto out;
 
 			ila = rcu_access_pointer(ila->next);
 		}
+		ila = rhashtable_walk_next(rhiter);
 	}
 
-	ret = skb->len;
+out:
+	iter->skip = skip;
+	ret = (skb->len ? : ret);
 
-done:
+out_ret:
 	rhashtable_walk_stop(rhiter);
 	return ret;
 }
-- 
2.11.0

^ permalink raw reply related

* [PATCH v3 net-next 3/9] ila: Call library function alloc_bucket_locks
From: Tom Herbert @ 2017-12-11 20:38 UTC (permalink / raw)
  To: davem; +Cc: netdev, roopa, rohit, Tom Herbert
In-Reply-To: <20171211203837.2540-1-tom@quantonium.net>

To allocate the array of bucket locks for the hash table we now
call library function alloc_bucket_spinlocks.

Signed-off-by: Tom Herbert <tom@quantonium.net>
---
 net/ipv6/ila/ila_xlat.c | 22 +++++-----------------
 1 file changed, 5 insertions(+), 17 deletions(-)

diff --git a/net/ipv6/ila/ila_xlat.c b/net/ipv6/ila/ila_xlat.c
index 9fca75b9cab3..402193ef74c2 100644
--- a/net/ipv6/ila/ila_xlat.c
+++ b/net/ipv6/ila/ila_xlat.c
@@ -31,26 +31,14 @@ struct ila_net {
 	bool hooks_registered;
 };
 
+#define MAX_LOCKS 1024
 #define	LOCKS_PER_CPU 10
 
 static int alloc_ila_locks(struct ila_net *ilan)
 {
-	unsigned int i, size;
-	unsigned int nr_pcpus = num_possible_cpus();
-
-	nr_pcpus = min_t(unsigned int, nr_pcpus, 32UL);
-	size = roundup_pow_of_two(nr_pcpus * LOCKS_PER_CPU);
-
-	if (sizeof(spinlock_t) != 0) {
-		ilan->locks = kvmalloc(size * sizeof(spinlock_t), GFP_KERNEL);
-		if (!ilan->locks)
-			return -ENOMEM;
-		for (i = 0; i < size; i++)
-			spin_lock_init(&ilan->locks[i]);
-	}
-	ilan->locks_mask = size - 1;
-
-	return 0;
+	return alloc_bucket_spinlocks(&ilan->xlat.locks, &ilan->xlat.locks_mask,
+				      MAX_LOCKS, LOCKS_PER_CPU,
+				      GFP_KERNEL);
 }
 
 static u32 hashrnd __read_mostly;
@@ -629,7 +617,7 @@ static __net_exit void ila_exit_net(struct net *net)
 
 	rhashtable_free_and_destroy(&ilan->rhash_table, ila_free_cb, NULL);
 
-	kvfree(ilan->locks);
+	free_bucket_spinlocks(ilan->xlat.locks);
 
 	if (ilan->hooks_registered)
 		nf_unregister_net_hooks(net, ila_nf_hook_ops,
-- 
2.11.0

^ permalink raw reply related

* [PATCH v3 net-next 4/9] ila: create main ila source file
From: Tom Herbert @ 2017-12-11 20:38 UTC (permalink / raw)
  To: davem; +Cc: netdev, roopa, rohit, Tom Herbert
In-Reply-To: <20171211203837.2540-1-tom@quantonium.net>

Create a main ila file that contains the module intialization functions
as well as netlink definitions. Previously these were defined in
ila_xlat and ila_common. This approach allows better extensibility.

Signed-off-by: Tom Herbert <tom@quantonium.net>
---
 net/ipv6/ila/Makefile     |   2 +-
 net/ipv6/ila/ila.h        |  26 ++++++++-
 net/ipv6/ila/ila_common.c |  30 ----------
 net/ipv6/ila/ila_main.c   | 115 ++++++++++++++++++++++++++++++++++++++
 net/ipv6/ila/ila_xlat.c   | 138 +++++++++-------------------------------------
 5 files changed, 166 insertions(+), 145 deletions(-)
 create mode 100644 net/ipv6/ila/ila_main.c

diff --git a/net/ipv6/ila/Makefile b/net/ipv6/ila/Makefile
index 4b32e5921e5c..b7739aba6e68 100644
--- a/net/ipv6/ila/Makefile
+++ b/net/ipv6/ila/Makefile
@@ -4,4 +4,4 @@
 
 obj-$(CONFIG_IPV6_ILA) += ila.o
 
-ila-objs := ila_common.o ila_lwt.o ila_xlat.o
+ila-objs := ila_main.o ila_common.o ila_lwt.o ila_xlat.o
diff --git a/net/ipv6/ila/ila.h b/net/ipv6/ila/ila.h
index 3c7a11b62334..faba7824ea56 100644
--- a/net/ipv6/ila/ila.h
+++ b/net/ipv6/ila/ila.h
@@ -19,6 +19,7 @@
 #include <linux/skbuff.h>
 #include <linux/types.h>
 #include <net/checksum.h>
+#include <net/genetlink.h>
 #include <net/ip.h>
 #include <net/protocol.h>
 #include <uapi/linux/ila.h>
@@ -104,9 +105,30 @@ void ila_update_ipv6_locator(struct sk_buff *skb, struct ila_params *p,
 
 void ila_init_saved_csum(struct ila_params *p);
 
+struct ila_net {
+	struct {
+		struct rhashtable rhash_table;
+		spinlock_t *locks; /* Bucket locks for entry manipulation */
+		unsigned int locks_mask;
+		bool hooks_registered;
+	} xlat;
+};
+
 int ila_lwt_init(void);
 void ila_lwt_fini(void);
-int ila_xlat_init(void);
-void ila_xlat_fini(void);
+
+int ila_xlat_init_net(struct net *net);
+void ila_xlat_exit_net(struct net *net);
+
+int ila_xlat_nl_cmd_add_mapping(struct sk_buff *skb, struct genl_info *info);
+int ila_xlat_nl_cmd_del_mapping(struct sk_buff *skb, struct genl_info *info);
+int ila_xlat_nl_cmd_get_mapping(struct sk_buff *skb, struct genl_info *info);
+int ila_xlat_nl_dump_start(struct netlink_callback *cb);
+int ila_xlat_nl_dump_done(struct netlink_callback *cb);
+int ila_xlat_nl_dump(struct sk_buff *skb, struct netlink_callback *cb);
+
+extern unsigned int ila_net_id;
+
+extern struct genl_family ila_nl_family;
 
 #endif /* __ILA_H */
diff --git a/net/ipv6/ila/ila_common.c b/net/ipv6/ila/ila_common.c
index 8c88ecf29b93..579310466eac 100644
--- a/net/ipv6/ila/ila_common.c
+++ b/net/ipv6/ila/ila_common.c
@@ -154,33 +154,3 @@ void ila_update_ipv6_locator(struct sk_buff *skb, struct ila_params *p,
 	iaddr->loc = p->locator;
 }
 
-static int __init ila_init(void)
-{
-	int ret;
-
-	ret = ila_lwt_init();
-
-	if (ret)
-		goto fail_lwt;
-
-	ret = ila_xlat_init();
-	if (ret)
-		goto fail_xlat;
-
-	return 0;
-fail_xlat:
-	ila_lwt_fini();
-fail_lwt:
-	return ret;
-}
-
-static void __exit ila_fini(void)
-{
-	ila_xlat_fini();
-	ila_lwt_fini();
-}
-
-module_init(ila_init);
-module_exit(ila_fini);
-MODULE_AUTHOR("Tom Herbert <tom@herbertland.com>");
-MODULE_LICENSE("GPL");
diff --git a/net/ipv6/ila/ila_main.c b/net/ipv6/ila/ila_main.c
new file mode 100644
index 000000000000..f6ac6b14577e
--- /dev/null
+++ b/net/ipv6/ila/ila_main.c
@@ -0,0 +1,115 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <net/genetlink.h>
+#include <net/ila.h>
+#include <net/netns/generic.h>
+#include <uapi/linux/genetlink.h>
+#include "ila.h"
+
+static const struct nla_policy ila_nl_policy[ILA_ATTR_MAX + 1] = {
+	[ILA_ATTR_LOCATOR] = { .type = NLA_U64, },
+	[ILA_ATTR_LOCATOR_MATCH] = { .type = NLA_U64, },
+	[ILA_ATTR_IFINDEX] = { .type = NLA_U32, },
+	[ILA_ATTR_CSUM_MODE] = { .type = NLA_U8, },
+	[ILA_ATTR_IDENT_TYPE] = { .type = NLA_U8, },
+};
+
+static const struct genl_ops ila_nl_ops[] = {
+	{
+		.cmd = ILA_CMD_ADD,
+		.doit = ila_xlat_nl_cmd_add_mapping,
+		.policy = ila_nl_policy,
+		.flags = GENL_ADMIN_PERM,
+	},
+	{
+		.cmd = ILA_CMD_DEL,
+		.doit = ila_xlat_nl_cmd_del_mapping,
+		.policy = ila_nl_policy,
+		.flags = GENL_ADMIN_PERM,
+	},
+	{
+		.cmd = ILA_CMD_GET,
+		.doit = ila_xlat_nl_cmd_get_mapping,
+		.start = ila_xlat_nl_dump_start,
+		.dumpit = ila_xlat_nl_dump,
+		.done = ila_xlat_nl_dump_done,
+		.policy = ila_nl_policy,
+	},
+};
+
+unsigned int ila_net_id;
+
+struct genl_family ila_nl_family __ro_after_init = {
+	.hdrsize	= 0,
+	.name		= ILA_GENL_NAME,
+	.version	= ILA_GENL_VERSION,
+	.maxattr	= ILA_ATTR_MAX,
+	.netnsok	= true,
+	.parallel_ops	= true,
+	.module		= THIS_MODULE,
+	.ops		= ila_nl_ops,
+	.n_ops		= ARRAY_SIZE(ila_nl_ops),
+};
+
+static __net_init int ila_init_net(struct net *net)
+{
+	int err;
+
+	err = ila_xlat_init_net(net);
+	if (err)
+		goto ila_xlat_init_fail;
+
+	return 0;
+
+ila_xlat_init_fail:
+	return err;
+}
+
+static __net_exit void ila_exit_net(struct net *net)
+{
+	ila_xlat_exit_net(net);
+}
+
+static struct pernet_operations ila_net_ops = {
+	.init = ila_init_net,
+	.exit = ila_exit_net,
+	.id   = &ila_net_id,
+	.size = sizeof(struct ila_net),
+};
+
+static int __init ila_init(void)
+{
+	int ret;
+
+	ret = register_pernet_device(&ila_net_ops);
+	if (ret)
+		goto register_device_fail;
+
+	ret = genl_register_family(&ila_nl_family);
+	if (ret)
+		goto register_family_fail;
+
+	ret = ila_lwt_init();
+	if (ret)
+		goto fail_lwt;
+
+	return 0;
+
+fail_lwt:
+	genl_unregister_family(&ila_nl_family);
+register_family_fail:
+	unregister_pernet_device(&ila_net_ops);
+register_device_fail:
+	return ret;
+}
+
+static void __exit ila_fini(void)
+{
+	ila_lwt_fini();
+	genl_unregister_family(&ila_nl_family);
+	unregister_pernet_device(&ila_net_ops);
+}
+
+module_init(ila_init);
+module_exit(ila_fini);
+MODULE_AUTHOR("Tom Herbert <tom@herbertland.com>");
+MODULE_LICENSE("GPL");
diff --git a/net/ipv6/ila/ila_xlat.c b/net/ipv6/ila/ila_xlat.c
index 402193ef74c2..610852b3dfa7 100644
--- a/net/ipv6/ila/ila_xlat.c
+++ b/net/ipv6/ila/ila_xlat.c
@@ -22,15 +22,6 @@ struct ila_map {
 	struct rcu_head rcu;
 };
 
-static unsigned int ila_net_id;
-
-struct ila_net {
-	struct rhashtable rhash_table;
-	spinlock_t *locks; /* Bucket locks for entry manipulation */
-	unsigned int locks_mask;
-	bool hooks_registered;
-};
-
 #define MAX_LOCKS 1024
 #define	LOCKS_PER_CPU 10
 
@@ -58,7 +49,7 @@ static inline u32 ila_locator_hash(struct ila_locator loc)
 static inline spinlock_t *ila_get_lock(struct ila_net *ilan,
 				       struct ila_locator loc)
 {
-	return &ilan->locks[ila_locator_hash(loc) & ilan->locks_mask];
+	return &ilan->xlat.locks[ila_locator_hash(loc) & ilan->xlat.locks_mask];
 }
 
 static inline int ila_cmp_wildcards(struct ila_map *ila,
@@ -102,16 +93,6 @@ static const struct rhashtable_params rht_params = {
 	.obj_cmpfn = ila_cmpfn,
 };
 
-static struct genl_family ila_nl_family;
-
-static const struct nla_policy ila_nl_policy[ILA_ATTR_MAX + 1] = {
-	[ILA_ATTR_LOCATOR] = { .type = NLA_U64, },
-	[ILA_ATTR_LOCATOR_MATCH] = { .type = NLA_U64, },
-	[ILA_ATTR_IFINDEX] = { .type = NLA_U32, },
-	[ILA_ATTR_CSUM_MODE] = { .type = NLA_U8, },
-	[ILA_ATTR_IDENT_TYPE] = { .type = NLA_U8, },
-};
-
 static int parse_nl_config(struct genl_info *info,
 			   struct ila_xlat_params *xp)
 {
@@ -149,7 +130,7 @@ static inline struct ila_map *ila_lookup_wildcards(struct ila_addr *iaddr,
 {
 	struct ila_map *ila;
 
-	ila = rhashtable_lookup_fast(&ilan->rhash_table, &iaddr->loc,
+	ila = rhashtable_lookup_fast(&ilan->xlat.rhash_table, &iaddr->loc,
 				     rht_params);
 	while (ila) {
 		if (!ila_cmp_wildcards(ila, iaddr, ifindex))
@@ -166,7 +147,7 @@ static inline struct ila_map *ila_lookup_by_params(struct ila_xlat_params *xp,
 {
 	struct ila_map *ila;
 
-	ila = rhashtable_lookup_fast(&ilan->rhash_table,
+	ila = rhashtable_lookup_fast(&ilan->xlat.rhash_table,
 				     &xp->ip.locator_match,
 				     rht_params);
 	while (ila) {
@@ -222,7 +203,7 @@ static int ila_add_mapping(struct net *net, struct ila_xlat_params *xp)
 	spinlock_t *lock = ila_get_lock(ilan, xp->ip.locator_match);
 	int err = 0, order;
 
-	if (!ilan->hooks_registered) {
+	if (!ilan->xlat.hooks_registered) {
 		/* We defer registering net hooks in the namespace until the
 		 * first mapping is added.
 		 */
@@ -231,7 +212,7 @@ static int ila_add_mapping(struct net *net, struct ila_xlat_params *xp)
 		if (err)
 			return err;
 
-		ilan->hooks_registered = true;
+		ilan->xlat.hooks_registered = true;
 	}
 
 	ila = kzalloc(sizeof(*ila), GFP_KERNEL);
@@ -246,12 +227,12 @@ static int ila_add_mapping(struct net *net, struct ila_xlat_params *xp)
 
 	spin_lock(lock);
 
-	head = rhashtable_lookup_fast(&ilan->rhash_table,
+	head = rhashtable_lookup_fast(&ilan->xlat.rhash_table,
 				      &xp->ip.locator_match,
 				      rht_params);
 	if (!head) {
 		/* New entry for the rhash_table */
-		err = rhashtable_lookup_insert_fast(&ilan->rhash_table,
+		err = rhashtable_lookup_insert_fast(&ilan->xlat.rhash_table,
 						    &ila->node, rht_params);
 	} else {
 		struct ila_map *tila = head, *prev = NULL;
@@ -277,7 +258,7 @@ static int ila_add_mapping(struct net *net, struct ila_xlat_params *xp)
 		} else {
 			/* Make this ila new head */
 			RCU_INIT_POINTER(ila->next, head);
-			err = rhashtable_replace_fast(&ilan->rhash_table,
+			err = rhashtable_replace_fast(&ilan->xlat.rhash_table,
 						      &head->node,
 						      &ila->node, rht_params);
 			if (err)
@@ -303,7 +284,7 @@ static int ila_del_mapping(struct net *net, struct ila_xlat_params *xp)
 
 	spin_lock(lock);
 
-	head = rhashtable_lookup_fast(&ilan->rhash_table,
+	head = rhashtable_lookup_fast(&ilan->xlat.rhash_table,
 				      &xp->ip.locator_match, rht_params);
 	ila = head;
 
@@ -333,15 +314,15 @@ static int ila_del_mapping(struct net *net, struct ila_xlat_params *xp)
 				 * table
 				 */
 				err = rhashtable_replace_fast(
-					&ilan->rhash_table, &ila->node,
+					&ilan->xlat.rhash_table, &ila->node,
 					&head->node, rht_params);
 				if (err)
 					goto out;
 			} else {
 				/* Entry no longer used */
-				err = rhashtable_remove_fast(&ilan->rhash_table,
-							     &ila->node,
-							     rht_params);
+				err = rhashtable_remove_fast(
+						&ilan->xlat.rhash_table,
+						&ila->node, rht_params);
 			}
 		}
 
@@ -356,7 +337,7 @@ static int ila_del_mapping(struct net *net, struct ila_xlat_params *xp)
 	return err;
 }
 
-static int ila_nl_cmd_add_mapping(struct sk_buff *skb, struct genl_info *info)
+int ila_xlat_nl_cmd_add_mapping(struct sk_buff *skb, struct genl_info *info)
 {
 	struct net *net = genl_info_net(info);
 	struct ila_xlat_params p;
@@ -369,7 +350,7 @@ static int ila_nl_cmd_add_mapping(struct sk_buff *skb, struct genl_info *info)
 	return ila_add_mapping(net, &p);
 }
 
-static int ila_nl_cmd_del_mapping(struct sk_buff *skb, struct genl_info *info)
+int ila_xlat_nl_cmd_del_mapping(struct sk_buff *skb, struct genl_info *info)
 {
 	struct net *net = genl_info_net(info);
 	struct ila_xlat_params xp;
@@ -421,7 +402,7 @@ static int ila_dump_info(struct ila_map *ila,
 	return -EMSGSIZE;
 }
 
-static int ila_nl_cmd_get_mapping(struct sk_buff *skb, struct genl_info *info)
+int ila_xlat_nl_cmd_get_mapping(struct sk_buff *skb, struct genl_info *info)
 {
 	struct net *net = genl_info_net(info);
 	struct ila_net *ilan = net_generic(net, ila_net_id);
@@ -465,7 +446,7 @@ struct ila_dump_iter {
 	int skip;
 };
 
-static int ila_nl_dump_start(struct netlink_callback *cb)
+int ila_xlat_nl_dump_start(struct netlink_callback *cb)
 {
 	struct net *net = sock_net(cb->skb->sk);
 	struct ila_net *ilan = net_generic(net, ila_net_id);
@@ -476,7 +457,7 @@ static int ila_nl_dump_start(struct netlink_callback *cb)
 	if (!iter)
 		return -ENOMEM;
 
-	ret = rhashtable_walk_init(&ilan->rhash_table, &iter->rhiter,
+	ret = rhashtable_walk_init(&ilan->xlat.rhash_table, &iter->rhiter,
 				   GFP_KERNEL);
 	if (ret) {
 		kfree(iter);
@@ -489,7 +470,7 @@ static int ila_nl_dump_start(struct netlink_callback *cb)
 	return ret;
 }
 
-static int ila_nl_dump_done(struct netlink_callback *cb)
+int ila_xlat_nl_dump_done(struct netlink_callback *cb)
 {
 	struct ila_dump_iter *iter = (struct ila_dump_iter *)cb->args[0];
 
@@ -500,7 +481,7 @@ static int ila_nl_dump_done(struct netlink_callback *cb)
 	return 0;
 }
 
-static int ila_nl_dump(struct sk_buff *skb, struct netlink_callback *cb)
+int ila_xlat_nl_dump(struct sk_buff *skb, struct netlink_callback *cb)
 {
 	struct ila_dump_iter *iter = (struct ila_dump_iter *)cb->args[0];
 	struct rhashtable_iter *rhiter = &iter->rhiter;
@@ -560,77 +541,35 @@ static int ila_nl_dump(struct sk_buff *skb, struct netlink_callback *cb)
 	return ret;
 }
 
-static const struct genl_ops ila_nl_ops[] = {
-	{
-		.cmd = ILA_CMD_ADD,
-		.doit = ila_nl_cmd_add_mapping,
-		.policy = ila_nl_policy,
-		.flags = GENL_ADMIN_PERM,
-	},
-	{
-		.cmd = ILA_CMD_DEL,
-		.doit = ila_nl_cmd_del_mapping,
-		.policy = ila_nl_policy,
-		.flags = GENL_ADMIN_PERM,
-	},
-	{
-		.cmd = ILA_CMD_GET,
-		.doit = ila_nl_cmd_get_mapping,
-		.start = ila_nl_dump_start,
-		.dumpit = ila_nl_dump,
-		.done = ila_nl_dump_done,
-		.policy = ila_nl_policy,
-	},
-};
-
-static struct genl_family ila_nl_family __ro_after_init = {
-	.hdrsize	= 0,
-	.name		= ILA_GENL_NAME,
-	.version	= ILA_GENL_VERSION,
-	.maxattr	= ILA_ATTR_MAX,
-	.netnsok	= true,
-	.parallel_ops	= true,
-	.module		= THIS_MODULE,
-	.ops		= ila_nl_ops,
-	.n_ops		= ARRAY_SIZE(ila_nl_ops),
-};
-
 #define ILA_HASH_TABLE_SIZE 1024
 
-static __net_init int ila_init_net(struct net *net)
+int ila_xlat_init_net(struct net *net)
 {
-	int err;
 	struct ila_net *ilan = net_generic(net, ila_net_id);
+	int err;
 
 	err = alloc_ila_locks(ilan);
 	if (err)
 		return err;
 
-	rhashtable_init(&ilan->rhash_table, &rht_params);
+	rhashtable_init(&ilan->xlat.rhash_table, &rht_params);
 
 	return 0;
 }
 
-static __net_exit void ila_exit_net(struct net *net)
+void ila_xlat_exit_net(struct net *net)
 {
 	struct ila_net *ilan = net_generic(net, ila_net_id);
 
-	rhashtable_free_and_destroy(&ilan->rhash_table, ila_free_cb, NULL);
+	rhashtable_free_and_destroy(&ilan->xlat.rhash_table, ila_free_cb, NULL);
 
 	free_bucket_spinlocks(ilan->xlat.locks);
 
-	if (ilan->hooks_registered)
+	if (ilan->xlat.hooks_registered)
 		nf_unregister_net_hooks(net, ila_nf_hook_ops,
 					ARRAY_SIZE(ila_nf_hook_ops));
 }
 
-static struct pernet_operations ila_net_ops = {
-	.init = ila_init_net,
-	.exit = ila_exit_net,
-	.id   = &ila_net_id,
-	.size = sizeof(struct ila_net),
-};
-
 static int ila_xlat_addr(struct sk_buff *skb, bool sir2ila)
 {
 	struct ila_map *ila;
@@ -657,28 +596,3 @@ static int ila_xlat_addr(struct sk_buff *skb, bool sir2ila)
 	return 0;
 }
 
-int __init ila_xlat_init(void)
-{
-	int ret;
-
-	ret = register_pernet_device(&ila_net_ops);
-	if (ret)
-		goto exit;
-
-	ret = genl_register_family(&ila_nl_family);
-	if (ret < 0)
-		goto unregister;
-
-	return 0;
-
-unregister:
-	unregister_pernet_device(&ila_net_ops);
-exit:
-	return ret;
-}
-
-void ila_xlat_fini(void)
-{
-	genl_unregister_family(&ila_nl_family);
-	unregister_pernet_device(&ila_net_ops);
-}
-- 
2.11.0

^ permalink raw reply related

* [PATCH v3 net-next 5/9] ila: Flush netlink command to clear xlat table
From: Tom Herbert @ 2017-12-11 20:38 UTC (permalink / raw)
  To: davem; +Cc: netdev, roopa, rohit, Tom Herbert
In-Reply-To: <20171211203837.2540-1-tom@quantonium.net>

Add ILA_CMD_FLUSH netlink command to clear the ILA translation table.

Signed-off-by: Tom Herbert <tom@quantonium.net>
---
 include/uapi/linux/ila.h |  1 +
 net/ipv6/ila/ila.h       |  1 +
 net/ipv6/ila/ila_main.c  |  6 +++++
 net/ipv6/ila/ila_xlat.c  | 62 ++++++++++++++++++++++++++++++++++++++++++++++--
 4 files changed, 68 insertions(+), 2 deletions(-)

diff --git a/include/uapi/linux/ila.h b/include/uapi/linux/ila.h
index 483b77af4eb8..db45d3e49a12 100644
--- a/include/uapi/linux/ila.h
+++ b/include/uapi/linux/ila.h
@@ -30,6 +30,7 @@ enum {
 	ILA_CMD_ADD,
 	ILA_CMD_DEL,
 	ILA_CMD_GET,
+	ILA_CMD_FLUSH,
 
 	__ILA_CMD_MAX,
 };
diff --git a/net/ipv6/ila/ila.h b/net/ipv6/ila/ila.h
index faba7824ea56..1f747bcbec29 100644
--- a/net/ipv6/ila/ila.h
+++ b/net/ipv6/ila/ila.h
@@ -123,6 +123,7 @@ void ila_xlat_exit_net(struct net *net);
 int ila_xlat_nl_cmd_add_mapping(struct sk_buff *skb, struct genl_info *info);
 int ila_xlat_nl_cmd_del_mapping(struct sk_buff *skb, struct genl_info *info);
 int ila_xlat_nl_cmd_get_mapping(struct sk_buff *skb, struct genl_info *info);
+int ila_xlat_nl_cmd_flush(struct sk_buff *skb, struct genl_info *info);
 int ila_xlat_nl_dump_start(struct netlink_callback *cb);
 int ila_xlat_nl_dump_done(struct netlink_callback *cb);
 int ila_xlat_nl_dump(struct sk_buff *skb, struct netlink_callback *cb);
diff --git a/net/ipv6/ila/ila_main.c b/net/ipv6/ila/ila_main.c
index f6ac6b14577e..18fac76b9520 100644
--- a/net/ipv6/ila/ila_main.c
+++ b/net/ipv6/ila/ila_main.c
@@ -27,6 +27,12 @@ static const struct genl_ops ila_nl_ops[] = {
 		.flags = GENL_ADMIN_PERM,
 	},
 	{
+		.cmd = ILA_CMD_FLUSH,
+		.doit = ila_xlat_nl_cmd_flush,
+		.policy = ila_nl_policy,
+		.flags = GENL_ADMIN_PERM,
+	},
+	{
 		.cmd = ILA_CMD_GET,
 		.doit = ila_xlat_nl_cmd_get_mapping,
 		.start = ila_xlat_nl_dump_start,
diff --git a/net/ipv6/ila/ila_xlat.c b/net/ipv6/ila/ila_xlat.c
index 610852b3dfa7..6bb1a081ff04 100644
--- a/net/ipv6/ila/ila_xlat.c
+++ b/net/ipv6/ila/ila_xlat.c
@@ -164,9 +164,9 @@ static inline void ila_release(struct ila_map *ila)
 	kfree_rcu(ila, rcu);
 }
 
-static void ila_free_cb(void *ptr, void *arg)
+static void ila_free_node(struct ila_map *ila)
 {
-	struct ila_map *ila = (struct ila_map *)ptr, *next;
+	struct ila_map *next;
 
 	/* Assume rcu_readlock held */
 	while (ila) {
@@ -176,6 +176,11 @@ static void ila_free_cb(void *ptr, void *arg)
 	}
 }
 
+static void ila_free_cb(void *ptr, void *arg)
+{
+	ila_free_node((struct ila_map *)ptr);
+}
+
 static int ila_xlat_addr(struct sk_buff *skb, bool sir2ila);
 
 static unsigned int
@@ -365,6 +370,59 @@ int ila_xlat_nl_cmd_del_mapping(struct sk_buff *skb, struct genl_info *info)
 	return 0;
 }
 
+static inline spinlock_t *lock_from_ila_map(struct ila_net *ilan,
+					    struct ila_map *ila)
+{
+	return ila_get_lock(ilan, ila->xp.ip.locator_match);
+}
+
+int ila_xlat_nl_cmd_flush(struct sk_buff *skb, struct genl_info *info)
+{
+	struct net *net = genl_info_net(info);
+	struct ila_net *ilan = net_generic(net, ila_net_id);
+	struct rhashtable_iter iter;
+	struct ila_map *ila;
+	spinlock_t *lock;
+	int ret;
+
+	ret = rhashtable_walk_init(&ilan->xlat.rhash_table, &iter, GFP_KERNEL);
+	if (ret)
+		goto done;
+
+	rhashtable_walk_start(&iter);
+
+	for (;;) {
+		ila = rhashtable_walk_next(&iter);
+
+		if (IS_ERR(ila)) {
+			if (PTR_ERR(ila) == -EAGAIN)
+				continue;
+			ret = PTR_ERR(ila);
+			goto done;
+		} else if (!ila) {
+			break;
+		}
+
+		lock = lock_from_ila_map(ilan, ila);
+
+		spin_lock(lock);
+
+		ret = rhashtable_remove_fast(&ilan->xlat.rhash_table,
+					     &ila->node, rht_params);
+		if (!ret)
+			ila_free_node(ila);
+
+		spin_unlock(lock);
+
+		if (ret)
+			break;
+	}
+
+done:
+	rhashtable_walk_stop(&iter);
+	return ret;
+}
+
 static int ila_fill_info(struct ila_map *ila, struct sk_buff *msg)
 {
 	if (nla_put_u64_64bit(msg, ILA_ATTR_LOCATOR,
-- 
2.11.0

^ permalink raw reply related

* [PATCH v3 net-next 6/9] net: Generic resolver backend
From: Tom Herbert @ 2017-12-11 20:38 UTC (permalink / raw)
  To: davem; +Cc: netdev, roopa, rohit, Tom Herbert
In-Reply-To: <20171211203837.2540-1-tom@quantonium.net>

This patch implements the backend of a resolver, specifically it
provides a means to track unresolved addresses and expire entries
based on timeout.

The resolver is mostly a frontend to an rhashtable where the key
of the table is whatever address type or object is tracked. A resolver
instance is created by net_rslv_create. A resolver is destroyed by
net_rslv_destroy.

There are two functions that are used to manipulate entries in the
table: net_rslv_lookup_and_create and net_rslv_resolved.

net_rslv_lookup_and_create is called with an unresolved address as
the argument. It returns zero on success and an error on failure.
When called a lookup is performed to see if an entry for the address
is already in the table, if it is then the -EEXISTS is returned.  If
an entry is not found, one is created and zero is returned.  It is
expected that when an entry is new the address resolution protocol is
initiated (for instance a RTM_ADDR_RESOLVE message may be sent to a
userspace daemon as we will do in ILA). If net_rslv_lookup_and_create
returns an error other than -EEXIST then presumably the hash table
has reached the limit of number of outstanding unresolved addresses,
the caller should take appropriate actions to avoid spamming the
resolution protocol.

net_rslv_resolved is called when resolution is completely (e.g.
ILA locator mapping was instantiated for a locator. The entry is
removed for the hash table.

An argument to net_rslv_create indicates a time for the pending
resolution in milliseconds. If the timer fires before resolution
then the entry is removed from the table. Subsequently, another
attempt to resolve the same address will result in a new entry in
the table.

There is one callback functions that can be set as arugments in
net_rslv_create:

   - cmp_fn: Compare function for hash table. Arguments are the
       key and an object in the table. If this is NULL then the
       default memcmp of rhashtable is used.

DOS mitigation is done by limiting the number of entries in the
resolver table (the max_size which argument of net_rslv_create)
and setting a timeout. If the timeout is set then the maximum rate
of new resolution requests is max_table_size / timeout. For
instance, with a maximum size of 1000 entries and a timeout of 100
msecs the maximum rate of resolutions requests is 10000/s.

Signed-off-by: Tom Herbert <tom@quantonium.net>
---
 include/net/resolver.h  |  43 ++++++++
 net/Kconfig             |   1 +
 net/Makefile            |   1 +
 net/resolver/Kconfig    |   7 ++
 net/resolver/Makefile   |   8 ++
 net/resolver/resolver.c | 283 ++++++++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 343 insertions(+)
 create mode 100644 include/net/resolver.h
 create mode 100644 net/resolver/Kconfig
 create mode 100644 net/resolver/Makefile
 create mode 100644 net/resolver/resolver.c

diff --git a/include/net/resolver.h b/include/net/resolver.h
new file mode 100644
index 000000000000..f38c7e9f1205
--- /dev/null
+++ b/include/net/resolver.h
@@ -0,0 +1,43 @@
+/*
+ * Generic network address resovler backend
+ *
+ * Copyright (c) 2017 Tom Herbert <tom@quantonium.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __NET_RESOLVER_H
+#define __NET_RESOLVER_H
+
+#include <linux/rhashtable.h>
+#include <linux/types.h>
+
+struct net_rslv;
+
+typedef int (*net_rslv_cmpfn)(struct net_rslv *nrslv, const void *key,
+			      const void *object);
+
+struct net_rslv {
+	struct rhashtable rhash_table;
+	struct rhashtable_params params;
+	net_rslv_cmpfn rslv_cmp;
+	size_t obj_size;
+	spinlock_t *locks;
+	unsigned int locks_mask;
+	unsigned int hash_rnd;
+};
+
+struct net_rslv *net_rslv_create(size_t obj_size, size_t key_len,
+				 size_t max_size, net_rslv_cmpfn cmp_fn);
+
+void net_rslv_destroy(struct net_rslv *nrslv);
+
+int net_rslv_lookup_and_create(struct net_rslv *nrslv, void *key,
+			       unsigned int timeout);
+
+void net_rslv_resolved(struct net_rslv *nrslv, void *key);
+
+#endif /* __NET_RESOLVER_H */
diff --git a/net/Kconfig b/net/Kconfig
index 9dba2715919d..b1e73325de6a 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -399,6 +399,7 @@ source "net/ceph/Kconfig"
 source "net/nfc/Kconfig"
 source "net/psample/Kconfig"
 source "net/ife/Kconfig"
+source "net/resolver/Kconfig"
 
 config LWTUNNEL
 	bool "Network light weight tunnels"
diff --git a/net/Makefile b/net/Makefile
index 14fede520840..6b3b0c5e676a 100644
--- a/net/Makefile
+++ b/net/Makefile
@@ -86,3 +86,4 @@ obj-y				+= l3mdev/
 endif
 obj-$(CONFIG_QRTR)		+= qrtr/
 obj-$(CONFIG_NET_NCSI)		+= ncsi/
+obj-$(CONFIG_NET_RESOLVER)	+= resolver/
diff --git a/net/resolver/Kconfig b/net/resolver/Kconfig
new file mode 100644
index 000000000000..99eff276e0b7
--- /dev/null
+++ b/net/resolver/Kconfig
@@ -0,0 +1,7 @@
+#
+# Net resolver configuration
+#
+
+menuconfig NET_RESOLVER
+        tristate
+	default n
diff --git a/net/resolver/Makefile b/net/resolver/Makefile
new file mode 100644
index 000000000000..fc15e6e5f19f
--- /dev/null
+++ b/net/resolver/Makefile
@@ -0,0 +1,8 @@
+#
+# Makefile for the generic network resolver
+#
+
+obj-$(CONFIG_NET_RESOLVER) += net_resolver.o
+
+net_resolver-objs := resolver.o
+
diff --git a/net/resolver/resolver.c b/net/resolver/resolver.c
new file mode 100644
index 000000000000..32a915ed8f93
--- /dev/null
+++ b/net/resolver/resolver.c
@@ -0,0 +1,283 @@
+/*
+ * net/core/resolver.c - Generic network address resolver backend
+ *
+ * Copyright (c) 2017 Tom Herbert <tom@quantonium.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/errno.h>
+#include <linux/ip.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/netlink.h>
+#include <linux/skbuff.h>
+#include <linux/socket.h>
+#include <linux/types.h>
+#include <linux/vmalloc.h>
+#include <net/checksum.h>
+#include <net/ip.h>
+#include <net/ip6_fib.h>
+#include <net/lwtunnel.h>
+#include <net/protocol.h>
+#include <net/resolver.h>
+
+struct net_rslv_ent {
+	struct rhash_head node;
+	struct delayed_work timeout_work;
+	struct net_rslv *nrslv;
+
+	struct rcu_head rcu;
+
+	char object[];
+};
+
+static void net_rslv_destroy_rcu(struct rcu_head *head)
+{
+	struct net_rslv_ent *nrent = container_of(head, struct net_rslv_ent,
+						  rcu);
+	kfree(nrent);
+}
+
+static void net_rslv_destroy_entry(struct net_rslv *nrslv,
+				   struct net_rslv_ent *nrent)
+{
+	call_rcu(&nrent->rcu, net_rslv_destroy_rcu);
+}
+
+static inline spinlock_t *net_rslv_get_lock(struct net_rslv *nrslv, void *key)
+{
+	unsigned int hash;
+
+	/* Use the rhashtable hash function */
+	hash = rht_key_get_hash(&nrslv->rhash_table, key, nrslv->params,
+				nrslv->hash_rnd);
+
+	return &nrslv->locks[hash & nrslv->locks_mask];
+}
+
+static void net_rslv_delayed_work(struct work_struct *w)
+{
+	struct delayed_work *delayed_work = to_delayed_work(w);
+	struct net_rslv_ent *nrent = container_of(delayed_work,
+						  struct net_rslv_ent,
+						  timeout_work);
+	struct net_rslv *nrslv = nrent->nrslv;
+	spinlock_t *lock = net_rslv_get_lock(nrslv, nrent->object);
+
+	spin_lock(lock);
+	rhashtable_remove_fast(&nrslv->rhash_table, &nrent->node,
+			       nrslv->params);
+	spin_unlock(lock);
+
+	net_rslv_destroy_entry(nrslv, nrent);
+}
+
+static void net_rslv_ent_free_cb(void *ptr, void *arg)
+{
+	struct net_rslv_ent *nrent = (struct net_rslv_ent *)ptr;
+	struct net_rslv *nrslv = nrent->nrslv;
+
+	net_rslv_destroy_entry(nrslv, nrent);
+}
+
+void net_rslv_resolved(struct net_rslv *nrslv, void *key)
+{
+	spinlock_t *lock = net_rslv_get_lock(nrslv, key);
+	struct net_rslv_ent *nrent;
+
+	rcu_read_lock();
+
+	nrent = rhashtable_lookup_fast(&nrslv->rhash_table, key,
+				       nrslv->params);
+	if (!nrent)
+		goto out;
+
+	/* Cancel timer first */
+	cancel_delayed_work_sync(&nrent->timeout_work);
+
+	spin_lock(lock);
+
+	/* Lookup again just in case someone already removed */
+	nrent = rhashtable_lookup_fast(&nrslv->rhash_table, key,
+				       nrslv->params);
+	if (unlikely(!nrent)) {
+		spin_unlock(lock);
+		goto out;
+	}
+
+	rhashtable_remove_fast(&nrslv->rhash_table, &nrent->node,
+			       nrslv->params);
+	spin_unlock(lock);
+
+	net_rslv_destroy_entry(nrslv, nrent);
+
+out:
+	rcu_read_unlock();
+}
+EXPORT_SYMBOL_GPL(net_rslv_resolved);
+
+/* Called with hash bucket lock held */
+static int net_rslv_new_ent(struct net_rslv *nrslv, void *key,
+			    unsigned int timeout)
+{
+	struct net_rslv_ent *nrent;
+	int err;
+
+	nrent = kzalloc(sizeof(*nrent) + nrslv->obj_size, GFP_KERNEL);
+	if (!nrent)
+		return -ENOMEM;
+
+	/* Key is always at beginning of object data */
+	memcpy(nrent->object, key, nrslv->params.key_len);
+
+	nrent->nrslv = nrslv;
+
+	/* Put in hash table */
+	err = rhashtable_lookup_insert_fast(&nrslv->rhash_table,
+					    &nrent->node, nrslv->params);
+	if (err) {
+		kfree(nrent);
+		return err;
+	}
+
+	if (timeout) {
+		/* Schedule timeout for resolver */
+		INIT_DELAYED_WORK(&nrent->timeout_work, net_rslv_delayed_work);
+		schedule_delayed_work(&nrent->timeout_work,
+				      msecs_to_jiffies(timeout));
+	}
+
+	return 0;
+}
+
+int net_rslv_lookup_and_create(struct net_rslv *nrslv, void *key,
+			       unsigned int timeout)
+{
+	spinlock_t *lock = net_rslv_get_lock(nrslv, key);
+	int ret;
+
+	if (rhashtable_lookup_fast(&nrslv->rhash_table, key, nrslv->params))
+		return -EEXIST;
+
+	spin_lock(lock);
+
+	/* Check if someone beat us to the punch */
+	if (rhashtable_lookup_fast(&nrslv->rhash_table, key, nrslv->params)) {
+		spin_unlock(lock);
+		return -EEXIST;
+	}
+
+	ret = net_rslv_new_ent(nrslv, key, timeout);
+
+	spin_unlock(lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(net_rslv_lookup_and_create);
+
+static int net_rslv_cmp(struct rhashtable_compare_arg *arg,
+			const void *obj)
+{
+	struct net_rslv *nrslv = container_of(arg->ht, struct net_rslv,
+					      rhash_table);
+
+	return nrslv->rslv_cmp(nrslv, arg->key, obj);
+}
+
+#define LOCKS_PER_CPU	10
+#define MAX_LOCKS 1024
+
+struct net_rslv *net_rslv_create(size_t obj_size, size_t key_len,
+				 size_t max_size,
+				 net_rslv_cmpfn cmp_fn)
+{
+	struct net_rslv *nrslv;
+	int err;
+
+	if (key_len < obj_size)
+		return ERR_PTR(-EINVAL);
+
+	nrslv = kzalloc(sizeof(*nrslv), GFP_KERNEL);
+	if (!nrslv)
+		return ERR_PTR(-ENOMEM);
+
+	err = alloc_bucket_spinlocks(&nrslv->locks, &nrslv->locks_mask,
+				     MAX_LOCKS, LOCKS_PER_CPU, GFP_KERNEL);
+	if (err)
+		return ERR_PTR(err);
+
+	nrslv->obj_size = obj_size;
+	nrslv->rslv_cmp = cmp_fn;
+	get_random_bytes(&nrslv->hash_rnd, sizeof(nrslv->hash_rnd));
+
+	nrslv->params.head_offset = offsetof(struct net_rslv_ent, node);
+	nrslv->params.key_offset = offsetof(struct net_rslv_ent, object);
+	nrslv->params.key_len = key_len;
+	nrslv->params.max_size = max_size;
+	nrslv->params.min_size = 256;
+	nrslv->params.automatic_shrinking = true;
+	nrslv->params.obj_cmpfn = cmp_fn ? net_rslv_cmp : NULL;
+
+	rhashtable_init(&nrslv->rhash_table, &nrslv->params);
+
+	return nrslv;
+}
+EXPORT_SYMBOL_GPL(net_rslv_create);
+
+static void net_rslv_cancel_all_delayed_work(struct net_rslv *nrslv)
+{
+	struct rhashtable_iter iter;
+	struct net_rslv_ent *nrent;
+	int ret;
+
+	ret = rhashtable_walk_init(&nrslv->rhash_table, &iter, GFP_ATOMIC);
+	if (WARN_ON(ret))
+		return;
+
+	rhashtable_walk_start(&iter);
+
+	for (;;) {
+		nrent = rhashtable_walk_next(&iter);
+
+		if (IS_ERR(nrent)) {
+			if (PTR_ERR(nrent) == -EAGAIN) {
+				/* New table, we're okay to continue */
+				continue;
+			}
+			ret = PTR_ERR(nrent);
+			break;
+		} else if (!nrent) {
+			break;
+		}
+
+		cancel_delayed_work_sync(&nrent->timeout_work);
+	}
+
+	rhashtable_walk_stop(&iter);
+	rhashtable_walk_exit(&iter);
+}
+
+void net_rslv_destroy(struct net_rslv *nrslv)
+{
+	/* First cancel delayed work in all the nodes. We don't want
+	 * delayed work trying to remove nodes from the table while
+	 * rhashtable_free_and_destroy is walking.
+	 */
+	net_rslv_cancel_all_delayed_work(nrslv);
+
+	rhashtable_free_and_destroy(&nrslv->rhash_table,
+				    net_rslv_ent_free_cb, NULL);
+
+	free_bucket_spinlocks(nrslv->locks);
+
+	kfree(nrslv);
+}
+EXPORT_SYMBOL_GPL(net_rslv_destroy);
+
+MODULE_AUTHOR("Tom Herbert <tom@quantonium.net>");
+MODULE_LICENSE("GPL");
+
-- 
2.11.0

^ permalink raw reply related

* [PATCH v3 net-next 7/9] ila: Resolver mechanism
From: Tom Herbert @ 2017-12-11 20:38 UTC (permalink / raw)
  To: davem; +Cc: netdev, roopa, rohit, Tom Herbert
In-Reply-To: <20171211203837.2540-1-tom@quantonium.net>

Implement an ILA resolver. This uses LWT to implement the hook to a
userspace resolver and tracks pending unresolved address using the
backend net resolver.

The idea is that the kernel sets an ILA resolver route to the
SIR prefix, something like:

ip route add 3333::/64 encap ila-resolve \
     via 2401:db00:20:911a::27:0 dev eth0

When a packet hits the route the address is looked up in a resolver
table. If the entry is created (no entry with the address already
exists) then an rtnl message is generated with group
RTNLGRP_ILA_NOTIFY and type RTM_ADDR_RESOLVE. A userspace
daemon can listen for such messages and perform an ILA resolution
protocol to determine the ILA mapping. If the mapping is resolved
then a /128 ila encap router is set so that host can perform
ILA translation and send directly to destination.

Signed-off-by: Tom Herbert <tom@quantonium.net>
---
 include/uapi/linux/ila.h       |   9 ++
 include/uapi/linux/lwtunnel.h  |   1 +
 include/uapi/linux/rtnetlink.h |   8 +-
 net/core/lwtunnel.c            |   2 +
 net/ipv6/Kconfig               |   1 +
 net/ipv6/ila/Makefile          |   2 +-
 net/ipv6/ila/ila.h             |  11 ++
 net/ipv6/ila/ila_lwt.c         |   8 ++
 net/ipv6/ila/ila_main.c        |  14 +++
 net/ipv6/ila/ila_resolver.c    | 244 +++++++++++++++++++++++++++++++++++++++++
 10 files changed, 298 insertions(+), 2 deletions(-)
 create mode 100644 net/ipv6/ila/ila_resolver.c

diff --git a/include/uapi/linux/ila.h b/include/uapi/linux/ila.h
index db45d3e49a12..66557265bf5b 100644
--- a/include/uapi/linux/ila.h
+++ b/include/uapi/linux/ila.h
@@ -65,4 +65,13 @@ enum {
 	ILA_HOOK_ROUTE_INPUT,
 };
 
+enum {
+	ILA_NOTIFY_ATTR_UNSPEC,
+	ILA_NOTIFY_ATTR_TIMEOUT,		/* u32 */
+
+	__ILA_NOTIFY_ATTR_MAX,
+};
+
+#define ILA_NOTIFY_ATTR_MAX	(__ILA_NOTIFY_ATTR_MAX - 1)
+
 #endif /* _UAPI_LINUX_ILA_H */
diff --git a/include/uapi/linux/lwtunnel.h b/include/uapi/linux/lwtunnel.h
index de696ca12f2c..2eac16f8323f 100644
--- a/include/uapi/linux/lwtunnel.h
+++ b/include/uapi/linux/lwtunnel.h
@@ -13,6 +13,7 @@ enum lwtunnel_encap_types {
 	LWTUNNEL_ENCAP_SEG6,
 	LWTUNNEL_ENCAP_BPF,
 	LWTUNNEL_ENCAP_SEG6_LOCAL,
+	LWTUNNEL_ENCAP_ILA_NOTIFY,
 	__LWTUNNEL_ENCAP_MAX,
 };
 
diff --git a/include/uapi/linux/rtnetlink.h b/include/uapi/linux/rtnetlink.h
index d8b5f80c2ea6..8d358a300d8a 100644
--- a/include/uapi/linux/rtnetlink.h
+++ b/include/uapi/linux/rtnetlink.h
@@ -13,7 +13,8 @@
  */
 #define RTNL_FAMILY_IPMR		128
 #define RTNL_FAMILY_IP6MR		129
-#define RTNL_FAMILY_MAX			129
+#define RTNL_FAMILY_ILA			130
+#define RTNL_FAMILY_MAX			130
 
 /****
  *		Routing/neighbour discovery messages.
@@ -150,6 +151,9 @@ enum {
 	RTM_NEWCACHEREPORT = 96,
 #define RTM_NEWCACHEREPORT RTM_NEWCACHEREPORT
 
+	RTM_ADDR_RESOLVE = 98,
+#define RTM_ADDR_RESOLVE RTM_ADDR_RESOLVE
+
 	__RTM_MAX,
 #define RTM_MAX		(((__RTM_MAX + 3) & ~3) - 1)
 };
@@ -676,6 +680,8 @@ enum rtnetlink_groups {
 #define RTNLGRP_IPV4_MROUTE_R	RTNLGRP_IPV4_MROUTE_R
 	RTNLGRP_IPV6_MROUTE_R,
 #define RTNLGRP_IPV6_MROUTE_R	RTNLGRP_IPV6_MROUTE_R
+	RTNLGRP_ILA_NOTIFY,
+#define RTNLGRP_ILA_NOTIFY	RTNLGRP_ILA_NOTIFY
 	__RTNLGRP_MAX
 };
 #define RTNLGRP_MAX	(__RTNLGRP_MAX - 1)
diff --git a/net/core/lwtunnel.c b/net/core/lwtunnel.c
index b3f2f77dfe72..16b04d05e9b9 100644
--- a/net/core/lwtunnel.c
+++ b/net/core/lwtunnel.c
@@ -46,6 +46,8 @@ static const char *lwtunnel_encap_str(enum lwtunnel_encap_types encap_type)
 		return "BPF";
 	case LWTUNNEL_ENCAP_SEG6_LOCAL:
 		return "SEG6LOCAL";
+	case LWTUNNEL_ENCAP_ILA_NOTIFY:
+		return "ILA-NOTIFY";
 	case LWTUNNEL_ENCAP_IP6:
 	case LWTUNNEL_ENCAP_IP:
 	case LWTUNNEL_ENCAP_NONE:
diff --git a/net/ipv6/Kconfig b/net/ipv6/Kconfig
index ea71e4b0ab7a..5b0a6e1bd7cc 100644
--- a/net/ipv6/Kconfig
+++ b/net/ipv6/Kconfig
@@ -110,6 +110,7 @@ config IPV6_ILA
 	tristate "IPv6: Identifier Locator Addressing (ILA)"
 	depends on NETFILTER
 	select LWTUNNEL
+	select NET_RESOLVER
 	---help---
 	  Support for IPv6 Identifier Locator Addressing (ILA).
 
diff --git a/net/ipv6/ila/Makefile b/net/ipv6/ila/Makefile
index b7739aba6e68..3ec2d65ceee2 100644
--- a/net/ipv6/ila/Makefile
+++ b/net/ipv6/ila/Makefile
@@ -4,4 +4,4 @@
 
 obj-$(CONFIG_IPV6_ILA) += ila.o
 
-ila-objs := ila_main.o ila_common.o ila_lwt.o ila_xlat.o
+ila-objs := ila_main.o ila_common.o ila_lwt.o ila_xlat.o ila_resolver.o
diff --git a/net/ipv6/ila/ila.h b/net/ipv6/ila/ila.h
index 1f747bcbec29..02a800c71796 100644
--- a/net/ipv6/ila/ila.h
+++ b/net/ipv6/ila/ila.h
@@ -15,6 +15,7 @@
 #include <linux/ip.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/rhashtable.h>
 #include <linux/socket.h>
 #include <linux/skbuff.h>
 #include <linux/types.h>
@@ -112,6 +113,9 @@ struct ila_net {
 		unsigned int locks_mask;
 		bool hooks_registered;
 	} xlat;
+	struct {
+		struct net_rslv *nrslv;
+	} rslv;
 };
 
 int ila_lwt_init(void);
@@ -120,6 +124,11 @@ void ila_lwt_fini(void);
 int ila_xlat_init_net(struct net *net);
 void ila_xlat_exit_net(struct net *net);
 
+int ila_rslv_init(void);
+void ila_rslv_fini(void);
+int ila_rslv_init_net(struct net *net);
+void ila_rslv_exit_net(struct net *net);
+
 int ila_xlat_nl_cmd_add_mapping(struct sk_buff *skb, struct genl_info *info);
 int ila_xlat_nl_cmd_del_mapping(struct sk_buff *skb, struct genl_info *info);
 int ila_xlat_nl_cmd_get_mapping(struct sk_buff *skb, struct genl_info *info);
@@ -132,4 +141,6 @@ extern unsigned int ila_net_id;
 
 extern struct genl_family ila_nl_family;
 
+void ila_rslv_resolved(struct ila_net *ilan, struct ila_addr *iaddr);
+
 #endif /* __ILA_H */
diff --git a/net/ipv6/ila/ila_lwt.c b/net/ipv6/ila/ila_lwt.c
index 9f1e46a1468e..20dddc7ea8d0 100644
--- a/net/ipv6/ila/ila_lwt.c
+++ b/net/ipv6/ila/ila_lwt.c
@@ -12,6 +12,7 @@
 #include <net/ip6_fib.h>
 #include <net/ip6_route.h>
 #include <net/lwtunnel.h>
+#include <net/netns/generic.h>
 #include <net/protocol.h>
 #include <uapi/linux/ila.h>
 #include "ila.h"
@@ -250,6 +251,13 @@ static int ila_build_state(struct net *net, struct nlattr *nla,
 
 	*ts = newts;
 
+	if (cfg6->fc_dst_len >= sizeof(struct ila_addr)) {
+		struct ila_net *ilan = net_generic(net, ila_net_id);
+
+		/* Cancel any pending resolution on this address */
+		ila_rslv_resolved(ilan, iaddr);
+	}
+
 	return 0;
 }
 
diff --git a/net/ipv6/ila/ila_main.c b/net/ipv6/ila/ila_main.c
index 18fac76b9520..411d3d112157 100644
--- a/net/ipv6/ila/ila_main.c
+++ b/net/ipv6/ila/ila_main.c
@@ -64,14 +64,21 @@ static __net_init int ila_init_net(struct net *net)
 	if (err)
 		goto ila_xlat_init_fail;
 
+	err = ila_rslv_init_net(net);
+	if (err)
+		goto resolver_init_fail;
+
 	return 0;
 
 ila_xlat_init_fail:
+	ila_xlat_exit_net(net);
+resolver_init_fail:
 	return err;
 }
 
 static __net_exit void ila_exit_net(struct net *net)
 {
+	ila_rslv_exit_net(net);
 	ila_xlat_exit_net(net);
 }
 
@@ -98,8 +105,14 @@ static int __init ila_init(void)
 	if (ret)
 		goto fail_lwt;
 
+	ret = ila_rslv_init();
+	if (ret)
+		goto fail_rslv;
+
 	return 0;
 
+fail_rslv:
+	ila_lwt_fini();
 fail_lwt:
 	genl_unregister_family(&ila_nl_family);
 register_family_fail:
@@ -110,6 +123,7 @@ static int __init ila_init(void)
 
 static void __exit ila_fini(void)
 {
+	ila_rslv_fini();
 	ila_lwt_fini();
 	genl_unregister_family(&ila_nl_family);
 	unregister_pernet_device(&ila_net_ops);
diff --git a/net/ipv6/ila/ila_resolver.c b/net/ipv6/ila/ila_resolver.c
new file mode 100644
index 000000000000..8b9a3c5305a4
--- /dev/null
+++ b/net/ipv6/ila/ila_resolver.c
@@ -0,0 +1,244 @@
+/*
+ * net/core/ila_resolver.c - ILA address resolver
+ *
+ * Copyright (c) 2017 Tom Herbert <tom@quantonium.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+#include <linux/errno.h>
+#include <linux/ip.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/netlink.h>
+#include <linux/skbuff.h>
+#include <linux/types.h>
+#include <net/ip6_fib.h>
+#include <net/lwtunnel.h>
+#include <net/netns/generic.h>
+#include <net/resolver.h>
+#include <uapi/linux/ila.h>
+#include "ila.h"
+
+struct ila_notify_params {
+	unsigned int timeout;
+};
+
+static inline struct ila_notify_params *ila_notify_params_lwtunnel(
+	struct lwtunnel_state *lwstate)
+{
+	return (struct ila_notify_params *)lwstate->data;
+}
+
+static int ila_fill_notify(struct sk_buff *skb, struct in6_addr *addr,
+			   u32 pid, u32 seq, int event, int flags)
+{
+	struct nlmsghdr *nlh;
+	struct rtmsg *rtm;
+
+	nlh = nlmsg_put(skb, pid, seq, event, sizeof(*rtm), flags);
+	if (!nlh)
+		return -EMSGSIZE;
+
+	rtm = nlmsg_data(nlh);
+	rtm->rtm_family   = AF_INET6;
+	rtm->rtm_dst_len  = 128;
+	rtm->rtm_src_len  = 0;
+	rtm->rtm_tos      = 0;
+	rtm->rtm_table    = RT6_TABLE_UNSPEC;
+	rtm->rtm_type     = RTN_UNICAST;
+	rtm->rtm_scope    = RT_SCOPE_UNIVERSE;
+
+	if (nla_put_in6_addr(skb, RTA_DST, addr)) {
+		nlmsg_cancel(skb, nlh);
+		return -EMSGSIZE;
+	}
+
+	nlmsg_end(skb, nlh);
+	return 0;
+}
+
+static size_t ila_rslv_msgsize(void)
+{
+	size_t len =
+		NLMSG_ALIGN(sizeof(struct rtmsg))
+		+ nla_total_size(16)     /* RTA_DST */
+		;
+
+	return len;
+}
+
+void ila_rslv_notify(struct net *net, struct sk_buff *skb)
+{
+	struct ipv6hdr *ip6h = ipv6_hdr(skb);
+	struct sk_buff *nlskb;
+	int err = 0;
+
+	/* Send ILA notification to user */
+	nlskb = nlmsg_new(ila_rslv_msgsize(), GFP_KERNEL);
+	if (!nlskb)
+		goto errout;
+
+	err = ila_fill_notify(nlskb, &ip6h->daddr, 0, 0, RTM_ADDR_RESOLVE,
+			      NLM_F_MULTI);
+	if (err < 0) {
+		WARN_ON(err == -EMSGSIZE);
+		kfree_skb(nlskb);
+		goto errout;
+	}
+	rtnl_notify(nlskb, net, 0, RTNLGRP_ILA_NOTIFY, NULL, GFP_ATOMIC);
+	return;
+
+errout:
+	if (err < 0)
+		rtnl_set_sk_err(net, RTNLGRP_ILA_NOTIFY, err);
+}
+
+static int ila_rslv_output(struct net *net, struct sock *sk,
+			   struct sk_buff *skb)
+{
+	struct ila_net *ilan = net_generic(net, ila_net_id);
+	struct dst_entry *dst = skb_dst(skb);
+	struct ipv6hdr *ip6h = ipv6_hdr(skb);
+	struct ila_notify_params *p;
+
+	p = ila_notify_params_lwtunnel(dst->lwtstate);
+
+	/* Net resolver create function returns zero only when a new
+	 * entry is create (returns -EEXIST is entry already in table)..
+	 */
+	if (!net_rslv_lookup_and_create(ilan->rslv.nrslv, &ip6h->daddr,
+					p->timeout))
+		ila_rslv_notify(net, skb);
+
+	return dst->lwtstate->orig_output(net, sk, skb);
+}
+
+void ila_rslv_resolved(struct ila_net *ilan, struct ila_addr *iaddr)
+{
+	if (ilan->rslv.nrslv)
+		net_rslv_resolved(ilan->rslv.nrslv, iaddr);
+}
+
+static int ila_rslv_input(struct sk_buff *skb)
+{
+	struct dst_entry *dst = skb_dst(skb);
+
+	return dst->lwtstate->orig_input(skb);
+}
+
+static const struct nla_policy ila_notify_nl_policy[ILA_NOTIFY_ATTR_MAX + 1] = {
+	[ILA_NOTIFY_ATTR_TIMEOUT] = { .type = NLA_U32, },
+};
+
+static int ila_rslv_build_state(struct net *net, struct nlattr *nla,
+				unsigned int family, const void *cfg,
+				struct lwtunnel_state **ts,
+				struct netlink_ext_ack *extack)
+{
+	struct ila_notify_params *p;
+	struct nlattr *tb[ILA_NOTIFY_ATTR_MAX + 1];
+	struct lwtunnel_state *newts;
+	size_t encap_len = sizeof(*p);
+	int ret;
+
+	if (family != AF_INET6)
+		return -EINVAL;
+
+	ret = nla_parse_nested(tb, ILA_NOTIFY_ATTR_MAX, nla,
+			       ila_notify_nl_policy, extack);
+
+	if (ret < 0)
+		return ret;
+
+	newts = lwtunnel_state_alloc(encap_len);
+	if (!newts)
+		return -ENOMEM;
+
+	newts->type = LWTUNNEL_ENCAP_ILA_NOTIFY;
+	newts->flags |= LWTUNNEL_STATE_OUTPUT_REDIRECT |
+			LWTUNNEL_STATE_INPUT_REDIRECT;
+
+	p = ila_notify_params_lwtunnel(newts);
+
+	if (tb[ILA_NOTIFY_ATTR_TIMEOUT])
+		p->timeout = msecs_to_jiffies(nla_get_u32(
+			tb[ILA_NOTIFY_ATTR_TIMEOUT]));
+
+	*ts = newts;
+
+	return 0;
+}
+
+static int ila_rslv_fill_encap_info(struct sk_buff *skb,
+				    struct lwtunnel_state *lwtstate)
+{
+	struct ila_notify_params *p = ila_notify_params_lwtunnel(lwtstate);
+
+	if (nla_put_u32(skb, ILA_NOTIFY_ATTR_TIMEOUT,
+			(__force u32)jiffies_to_msecs(p->timeout)))
+		goto nla_put_failure;
+
+	return 0;
+
+nla_put_failure:
+	return -EMSGSIZE;
+}
+
+static int ila_rslv_nlsize(struct lwtunnel_state *lwtstate)
+{
+	return nla_total_size(sizeof(u32)) + /* ILA_NOTIFY_ATTR_TIMEOUT */
+	       0;
+}
+
+static int ila_rslv_cmp(struct lwtunnel_state *a, struct lwtunnel_state *b)
+{
+	return 0;
+}
+
+static const struct lwtunnel_encap_ops ila_rslv_ops = {
+	.build_state = ila_rslv_build_state,
+	.output = ila_rslv_output,
+	.input = ila_rslv_input,
+	.fill_encap = ila_rslv_fill_encap_info,
+	.get_encap_size = ila_rslv_nlsize,
+	.cmp_encap = ila_rslv_cmp,
+};
+
+#define ILA_MAX_SIZE 8192
+
+int ila_rslv_init_net(struct net *net)
+{
+	struct ila_net *ilan = net_generic(net, ila_net_id);
+	struct net_rslv *nrslv;
+
+	nrslv = net_rslv_create(sizeof(struct ila_addr),
+				sizeof(struct ila_addr), ILA_MAX_SIZE, NULL);
+
+	if (IS_ERR(nrslv))
+		return PTR_ERR(nrslv);
+
+	ilan->rslv.nrslv = nrslv;
+
+	return 0;
+}
+
+void ila_rslv_exit_net(struct net *net)
+{
+	struct ila_net *ilan = net_generic(net, ila_net_id);
+
+	if (ilan->rslv.nrslv)
+		net_rslv_destroy(ilan->rslv.nrslv);
+}
+
+int ila_rslv_init(void)
+{
+	return lwtunnel_encap_add_ops(&ila_rslv_ops, LWTUNNEL_ENCAP_ILA_NOTIFY);
+}
+
+void ila_rslv_fini(void)
+{
+	lwtunnel_encap_del_ops(&ila_rslv_ops, LWTUNNEL_ENCAP_ILA_NOTIFY);
+}
-- 
2.11.0

^ permalink raw reply related

* [PATCH v3 net-next 8/9] resolver: add netlink control
From: Tom Herbert @ 2017-12-11 20:38 UTC (permalink / raw)
  To: davem; +Cc: netdev, roopa, rohit, Tom Herbert
In-Reply-To: <20171211203837.2540-1-tom@quantonium.net>

Add interfaces into resolver backend that can be used to provide
netlink. The interface includes fucntions to support the common
netlink commands (get, add, list, delete, and flush). The
frontend that is using the resolver implements the actual
netlink interfaces for its service and calls the backend functions
to provide netlink for the resolver.

Signed-off-by: Tom Herbert <tom@quantonium.net>
---
 include/net/resolver.h      |  26 +++-
 net/ipv6/ila/ila_resolver.c |   3 +-
 net/resolver/resolver.c     | 280 +++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 305 insertions(+), 4 deletions(-)

diff --git a/include/net/resolver.h b/include/net/resolver.h
index f38c7e9f1205..307938ad91a6 100644
--- a/include/net/resolver.h
+++ b/include/net/resolver.h
@@ -14,12 +14,21 @@
 
 #include <linux/rhashtable.h>
 #include <linux/types.h>
+#include <net/genetlink.h>
+#include <uapi/linux/genetlink.h>
 
 struct net_rslv;
 
 typedef int (*net_rslv_cmpfn)(struct net_rslv *nrslv, const void *key,
 			      const void *object);
 
+struct net_rslv_netlink_map {
+	int dst_attr;
+	int timo_attr;
+	int get_cmd;
+	struct genl_family *genl_family;
+};
+
 struct net_rslv {
 	struct rhashtable rhash_table;
 	struct rhashtable_params params;
@@ -28,10 +37,12 @@ struct net_rslv {
 	spinlock_t *locks;
 	unsigned int locks_mask;
 	unsigned int hash_rnd;
+	const struct net_rslv_netlink_map *nlmap;
 };
 
 struct net_rslv *net_rslv_create(size_t obj_size, size_t key_len,
-				 size_t max_size, net_rslv_cmpfn cmp_fn);
+				 size_t max_size, net_rslv_cmpfn cmp_fn,
+				 const struct net_rslv_netlink_map *nlmap);
 
 void net_rslv_destroy(struct net_rslv *nrslv);
 
@@ -40,4 +51,17 @@ int net_rslv_lookup_and_create(struct net_rslv *nrslv, void *key,
 
 void net_rslv_resolved(struct net_rslv *nrslv, void *key);
 
+int net_rslv_nl_cmd_add(struct net_rslv *nrslv, struct sk_buff *skb,
+			struct genl_info *info);
+int net_rslv_nl_cmd_del(struct net_rslv *nrslv, struct sk_buff *skb,
+			struct genl_info *info);
+int net_rslv_nl_cmd_get(struct net_rslv *nrslv, struct sk_buff *skb,
+			struct genl_info *info);
+int net_rslv_nl_cmd_flush(struct net_rslv *nrslv, struct sk_buff *skb,
+			  struct genl_info *info);
+int net_rslv_nl_dump_start(struct net_rslv *nrslv, struct netlink_callback *cb);
+int net_rslv_nl_dump_done(struct net_rslv *nrslv, struct netlink_callback *cb);
+int net_rslv_nl_dump(struct net_rslv *nrslv, struct sk_buff *skb,
+		     struct netlink_callback *cb);
+
 #endif /* __NET_RESOLVER_H */
diff --git a/net/ipv6/ila/ila_resolver.c b/net/ipv6/ila/ila_resolver.c
index 8b9a3c5305a4..2aebc0526221 100644
--- a/net/ipv6/ila/ila_resolver.c
+++ b/net/ipv6/ila/ila_resolver.c
@@ -215,7 +215,8 @@ int ila_rslv_init_net(struct net *net)
 	struct net_rslv *nrslv;
 
 	nrslv = net_rslv_create(sizeof(struct ila_addr),
-				sizeof(struct ila_addr), ILA_MAX_SIZE, NULL);
+				sizeof(struct ila_addr), ILA_MAX_SIZE, NULL,
+				NULL);
 
 	if (IS_ERR(nrslv))
 		return PTR_ERR(nrslv);
diff --git a/net/resolver/resolver.c b/net/resolver/resolver.c
index 32a915ed8f93..e2496b0bf852 100644
--- a/net/resolver/resolver.c
+++ b/net/resolver/resolver.c
@@ -19,11 +19,13 @@
 #include <linux/types.h>
 #include <linux/vmalloc.h>
 #include <net/checksum.h>
+#include <net/genetlink.h>
 #include <net/ip.h>
 #include <net/ip6_fib.h>
 #include <net/lwtunnel.h>
 #include <net/protocol.h>
 #include <net/resolver.h>
+#include <uapi/linux/genetlink.h>
 
 struct net_rslv_ent {
 	struct rhash_head node;
@@ -192,8 +194,8 @@ static int net_rslv_cmp(struct rhashtable_compare_arg *arg,
 #define MAX_LOCKS 1024
 
 struct net_rslv *net_rslv_create(size_t obj_size, size_t key_len,
-				 size_t max_size,
-				 net_rslv_cmpfn cmp_fn)
+				 size_t max_size, net_rslv_cmpfn cmp_fn,
+				 const struct net_rslv_netlink_map *nlmap)
 {
 	struct net_rslv *nrslv;
 	int err;
@@ -212,6 +214,7 @@ struct net_rslv *net_rslv_create(size_t obj_size, size_t key_len,
 
 	nrslv->obj_size = obj_size;
 	nrslv->rslv_cmp = cmp_fn;
+	nrslv->nlmap = nlmap;
 	get_random_bytes(&nrslv->hash_rnd, sizeof(nrslv->hash_rnd));
 
 	nrslv->params.head_offset = offsetof(struct net_rslv_ent, node);
@@ -278,6 +281,279 @@ void net_rslv_destroy(struct net_rslv *nrslv)
 }
 EXPORT_SYMBOL_GPL(net_rslv_destroy);
 
+/* Netlink access utility functions and structures. */
+
+struct net_rslv_params {
+	unsigned int timeout;
+	__u8 key[MAX_ADDR_LEN];
+	size_t keysize;
+};
+
+static int parse_nl_config(struct net_rslv *nrslv, struct genl_info *info,
+			   struct net_rslv_params *np)
+{
+	if (!info->attrs[nrslv->nlmap->dst_attr] ||
+	    nla_len(info->attrs[nrslv->nlmap->dst_attr]) !=
+					nrslv->params.key_len)
+		return -EINVAL;
+
+	memset(np, 0, sizeof(*np));
+
+	memcpy(np->key, nla_data(info->attrs[nrslv->nlmap->dst_attr]),
+	       nla_len(info->attrs[nrslv->nlmap->dst_attr]));
+
+	if (info->attrs[nrslv->nlmap->timo_attr])
+		np->timeout = nla_get_u32(info->attrs[nrslv->nlmap->timo_attr]);
+
+	return 0;
+}
+
+int net_rslv_nl_cmd_add(struct net_rslv *nrslv, struct sk_buff *skb,
+			struct genl_info *info)
+{
+	struct net_rslv_params p;
+	int err;
+
+	err = parse_nl_config(nrslv, info, &p);
+	if (err)
+		return err;
+
+	return net_rslv_lookup_and_create(nrslv, p.key, p.timeout);
+}
+EXPORT_SYMBOL_GPL(net_rslv_nl_cmd_add);
+
+int net_rslv_nl_cmd_del(struct net_rslv *nrslv, struct sk_buff *skb,
+			struct genl_info *info)
+{
+	struct net_rslv_params p;
+	int err;
+
+	err = parse_nl_config(nrslv, info, &p);
+	if (err)
+		return err;
+
+	/* Treat removal as being resolved */
+	net_rslv_resolved(nrslv, p.key);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(net_rslv_nl_cmd_del);
+
+static int net_rslv_fill_info(struct net_rslv *nrslv,
+			      struct net_rslv_ent *nrent,
+			      struct sk_buff *msg)
+{
+	int from_now = 0;
+
+	if (delayed_work_pending(&nrent->timeout_work)) {
+		unsigned long expires = nrent->timeout_work.timer.expires;
+
+		from_now = jiffies_to_msecs(expires - jiffies);
+
+		if (from_now < 0)
+			from_now = 0;
+	}
+
+	if (nla_put(msg, nrslv->nlmap->dst_attr, nrslv->params.key_len,
+		    nrent->object) ||
+	    nla_put_s32(msg, nrslv->nlmap->timo_attr, from_now))
+		return -1;
+
+	return 0;
+}
+
+static int net_rslv_dump_info(struct net_rslv *nrslv,
+			      struct net_rslv_ent *nrent, u32 portid, u32 seq,
+			      u32 flags, struct sk_buff *skb, u8 cmd)
+{
+	void *hdr;
+
+	hdr = genlmsg_put(skb, portid, seq, nrslv->nlmap->genl_family, flags,
+			  cmd);
+	if (!hdr)
+		return -ENOMEM;
+
+	if (net_rslv_fill_info(nrslv, nrent, skb) < 0)
+		goto nla_put_failure;
+
+	genlmsg_end(skb, hdr);
+	return 0;
+
+nla_put_failure:
+	genlmsg_cancel(skb, hdr);
+	return -EMSGSIZE;
+}
+
+int net_rslv_nl_cmd_get(struct net_rslv *nrslv, struct sk_buff *skb,
+			struct genl_info *info)
+{
+	struct net_rslv_ent *nrent;
+	struct net_rslv_params p;
+	struct sk_buff *msg;
+	int err;
+
+	err = parse_nl_config(nrslv, info, &p);
+	if (err)
+		return err;
+
+	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+	if (!msg)
+		return -ENOMEM;
+
+	rcu_read_lock();
+
+	nrent = rhashtable_lookup_fast(&nrslv->rhash_table, p.key,
+				       nrslv->params);
+	if (nrent)
+		err = net_rslv_dump_info(nrslv, nrent, info->snd_portid,
+					 info->snd_seq, 0, msg,
+					 info->genlhdr->cmd);
+
+	rcu_read_unlock();
+
+	if (err < 0)
+		goto out_free;
+
+	return genlmsg_reply(msg, info);
+
+out_free:
+	nlmsg_free(msg);
+	return err;
+}
+EXPORT_SYMBOL_GPL(net_rslv_nl_cmd_get);
+
+int net_rslv_nl_cmd_flush(struct net_rslv *nrslv, struct sk_buff *skb,
+			  struct genl_info *info)
+{
+	struct rhashtable_iter iter;
+	struct net_rslv_ent *nrent;
+	spinlock_t *lock;
+	int ret;
+
+	ret = rhashtable_walk_init(&nrslv->rhash_table, &iter, GFP_KERNEL);
+	if (ret)
+		return ret;
+
+	rhashtable_walk_start(&iter);
+
+	for (;;) {
+		nrent = rhashtable_walk_next(&iter);
+
+		if (IS_ERR(nrent)) {
+			if (PTR_ERR(nrent) == -EAGAIN) {
+				/* New table, we're okay to continue */
+				continue;
+			}
+			ret = PTR_ERR(nrent);
+			break;
+		} else if (!nrent) {
+			break;
+		}
+
+		lock = net_rslv_get_lock(nrslv, nrent->object);
+
+		spin_lock(lock);
+		ret = rhashtable_remove_fast(&nrslv->rhash_table, &nrent->node,
+					     nrslv->params);
+		spin_unlock(lock);
+
+		if (ret)
+			break;
+	}
+
+	rhashtable_walk_stop(&iter);
+	rhashtable_walk_exit(&iter);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(net_rslv_nl_cmd_flush);
+
+int net_rslv_nl_dump_start(struct net_rslv *nrslv, struct netlink_callback *cb)
+{
+	struct rhashtable_iter *iter;
+	int ret;
+
+	iter = kmalloc(sizeof(*iter), GFP_KERNEL);
+	if (!iter)
+		return -ENOMEM;
+
+	ret = rhashtable_walk_init(&nrslv->rhash_table, iter, GFP_KERNEL);
+	if (ret) {
+		kfree(iter);
+		return ret;
+	}
+
+	cb->args[0] = (long)iter;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(net_rslv_nl_dump_start);
+
+int net_rslv_nl_dump_done(struct net_rslv *nrslv, struct netlink_callback *cb)
+{
+	struct rhashtable_iter *iter =
+				(struct rhashtable_iter *)cb->args[0];
+
+	rhashtable_walk_exit(iter);
+
+	kfree(iter);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(net_rslv_nl_dump_done);
+
+int net_rslv_nl_dump(struct net_rslv *nrslv, struct sk_buff *skb,
+		     struct netlink_callback *cb)
+{
+	struct rhashtable_iter *iter =
+				(struct rhashtable_iter *)cb->args[0];
+	struct net_rslv_ent *nrent;
+	int ret;
+
+	ret = rhashtable_walk_start_check(iter);
+	if (ret)
+		goto done;
+
+	/* Get first entty */
+	nrent = rhashtable_walk_peek(iter);
+
+	for (;;) {
+		if (IS_ERR(nrent)) {
+			ret = PTR_ERR(nrent);
+			if (ret == -EAGAIN) {
+				/* Table has changed and iter has reset. Return
+				 * -EAGAIN to the application even if we have
+				 * written data to the skb. The application
+				 * needs to deal with this.
+				 */
+
+				goto done;
+			}
+			break;
+		} else if (!nrent) {
+			break;
+		}
+
+		ret =  net_rslv_dump_info(nrslv, nrent,
+					  NETLINK_CB(cb->skb).portid,
+					  cb->nlh->nlmsg_seq,
+					  NLM_F_MULTI, skb,
+					  nrslv->nlmap->get_cmd);
+		if (ret)
+			break;
+
+		/* Get next and advance the iter */
+		nrent = rhashtable_walk_next(iter);
+	}
+
+	ret = (skb->len ? : ret);
+
+done:
+	rhashtable_walk_stop(iter);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(net_rslv_nl_dump);
+
 MODULE_AUTHOR("Tom Herbert <tom@quantonium.net>");
 MODULE_LICENSE("GPL");
 
-- 
2.11.0

^ permalink raw reply related

* [PATCH v3 net-next 9/9] ila: add netlink control ILA resolver
From: Tom Herbert @ 2017-12-11 20:38 UTC (permalink / raw)
  To: davem; +Cc: netdev, roopa, rohit, Tom Herbert
In-Reply-To: <20171211203837.2540-1-tom@quantonium.net>

Add a netlink family to processe netlinkf for the ILA resolver.
This calls the net resolver netlink functions.

Signed-off-by: Tom Herbert <tom@quantonium.net>
---
 include/uapi/linux/ila.h    | 11 ++++++++
 net/ipv6/ila/ila.h          |  8 ++++++
 net/ipv6/ila/ila_main.c     | 26 ++++++++++++++++++
 net/ipv6/ila/ila_resolver.c | 67 ++++++++++++++++++++++++++++++++++++++++++++-
 4 files changed, 111 insertions(+), 1 deletion(-)

diff --git a/include/uapi/linux/ila.h b/include/uapi/linux/ila.h
index 66557265bf5b..2481dab25d57 100644
--- a/include/uapi/linux/ila.h
+++ b/include/uapi/linux/ila.h
@@ -19,6 +19,8 @@ enum {
 	ILA_ATTR_CSUM_MODE,			/* u8 */
 	ILA_ATTR_IDENT_TYPE,			/* u8 */
 	ILA_ATTR_HOOK_TYPE,			/* u8 */
+	ILA_RSLV_ATTR_DST,			/* IPv6 address */
+	ILA_RSLV_ATTR_TIMEOUT,			/* u32 */
 
 	__ILA_ATTR_MAX,
 };
@@ -31,6 +33,10 @@ enum {
 	ILA_CMD_DEL,
 	ILA_CMD_GET,
 	ILA_CMD_FLUSH,
+	ILA_RSLV_CMD_ADD,
+	ILA_RSLV_CMD_DEL,
+	ILA_RSLV_CMD_GET,
+	ILA_RSLV_CMD_FLUSH,
 
 	__ILA_CMD_MAX,
 };
@@ -68,10 +74,15 @@ enum {
 enum {
 	ILA_NOTIFY_ATTR_UNSPEC,
 	ILA_NOTIFY_ATTR_TIMEOUT,		/* u32 */
+	ILA_NOTIFY_ATTR_DST,			/* Binary address */
 
 	__ILA_NOTIFY_ATTR_MAX,
 };
 
 #define ILA_NOTIFY_ATTR_MAX	(__ILA_NOTIFY_ATTR_MAX - 1)
 
+/* NETLINK_GENERIC related info */
+#define ILA_RSLV_GENL_NAME	"ila-rslv"
+#define ILA_RSLV_GENL_VERSION	0x1
+
 #endif /* _UAPI_LINUX_ILA_H */
diff --git a/net/ipv6/ila/ila.h b/net/ipv6/ila/ila.h
index 02a800c71796..0aa99e359a38 100644
--- a/net/ipv6/ila/ila.h
+++ b/net/ipv6/ila/ila.h
@@ -137,6 +137,14 @@ int ila_xlat_nl_dump_start(struct netlink_callback *cb);
 int ila_xlat_nl_dump_done(struct netlink_callback *cb);
 int ila_xlat_nl_dump(struct sk_buff *skb, struct netlink_callback *cb);
 
+int ila_rslv_nl_cmd_add(struct sk_buff *skb, struct genl_info *info);
+int ila_rslv_nl_cmd_del(struct sk_buff *skb, struct genl_info *info);
+int ila_rslv_nl_cmd_get(struct sk_buff *skb, struct genl_info *info);
+int ila_rslv_nl_cmd_flush(struct sk_buff *skb, struct genl_info *info);
+int ila_rslv_nl_dump_start(struct netlink_callback *cb);
+int ila_rslv_nl_dump_done(struct netlink_callback *cb);
+int ila_rslv_nl_dump(struct sk_buff *skb, struct netlink_callback *cb);
+
 extern unsigned int ila_net_id;
 
 extern struct genl_family ila_nl_family;
diff --git a/net/ipv6/ila/ila_main.c b/net/ipv6/ila/ila_main.c
index 411d3d112157..8589d422568b 100644
--- a/net/ipv6/ila/ila_main.c
+++ b/net/ipv6/ila/ila_main.c
@@ -40,6 +40,32 @@ static const struct genl_ops ila_nl_ops[] = {
 		.done = ila_xlat_nl_dump_done,
 		.policy = ila_nl_policy,
 	},
+	{
+		.cmd = ILA_RSLV_CMD_ADD,
+		.doit = ila_rslv_nl_cmd_add,
+		.policy = ila_nl_policy,
+		.flags = GENL_ADMIN_PERM,
+	},
+	{
+		.cmd = ILA_RSLV_CMD_DEL,
+		.doit = ila_rslv_nl_cmd_del,
+		.policy = ila_nl_policy,
+		.flags = GENL_ADMIN_PERM,
+	},
+	{
+		.cmd = ILA_RSLV_CMD_FLUSH,
+		.doit = ila_rslv_nl_cmd_flush,
+		.policy = ila_nl_policy,
+		.flags = GENL_ADMIN_PERM,
+	},
+	{
+		.cmd = ILA_RSLV_CMD_GET,
+		.doit = ila_rslv_nl_cmd_get,
+		.start = ila_rslv_nl_dump_start,
+		.dumpit = ila_rslv_nl_dump,
+		.done = ila_rslv_nl_dump_done,
+		.policy = ila_nl_policy,
+	},
 };
 
 unsigned int ila_net_id;
diff --git a/net/ipv6/ila/ila_resolver.c b/net/ipv6/ila/ila_resolver.c
index 2aebc0526221..3278e93bb799 100644
--- a/net/ipv6/ila/ila_resolver.c
+++ b/net/ipv6/ila/ila_resolver.c
@@ -209,6 +209,13 @@ static const struct lwtunnel_encap_ops ila_rslv_ops = {
 
 #define ILA_MAX_SIZE 8192
 
+static struct net_rslv_netlink_map ila_netlink_map = {
+	.dst_attr = ILA_RSLV_ATTR_DST,
+	.timo_attr = ILA_RSLV_ATTR_TIMEOUT,
+	.get_cmd = ILA_RSLV_CMD_GET,
+	.genl_family = &ila_nl_family,
+};
+
 int ila_rslv_init_net(struct net *net)
 {
 	struct ila_net *ilan = net_generic(net, ila_net_id);
@@ -216,7 +223,7 @@ int ila_rslv_init_net(struct net *net)
 
 	nrslv = net_rslv_create(sizeof(struct ila_addr),
 				sizeof(struct ila_addr), ILA_MAX_SIZE, NULL,
-				NULL);
+				&ila_netlink_map);
 
 	if (IS_ERR(nrslv))
 		return PTR_ERR(nrslv);
@@ -234,6 +241,64 @@ void ila_rslv_exit_net(struct net *net)
 		net_rslv_destroy(ilan->rslv.nrslv);
 }
 
+/* Netlink access */
+
+int ila_rslv_nl_cmd_add(struct sk_buff *skb, struct genl_info *info)
+{
+	struct net *net = sock_net(skb->sk);
+	struct ila_net *ilan = net_generic(net, ila_net_id);
+
+	return net_rslv_nl_cmd_add(ilan->rslv.nrslv, skb, info);
+}
+
+int ila_rslv_nl_cmd_del(struct sk_buff *skb, struct genl_info *info)
+{
+	struct net *net = sock_net(skb->sk);
+	struct ila_net *ilan = net_generic(net, ila_net_id);
+
+	return net_rslv_nl_cmd_del(ilan->rslv.nrslv, skb, info);
+}
+
+int ila_rslv_nl_cmd_get(struct sk_buff *skb, struct genl_info *info)
+{
+	struct net *net = sock_net(skb->sk);
+	struct ila_net *ilan = net_generic(net, ila_net_id);
+
+	return net_rslv_nl_cmd_get(ilan->rslv.nrslv, skb, info);
+}
+
+int ila_rslv_nl_cmd_flush(struct sk_buff *skb, struct genl_info *info)
+{
+	struct net *net = sock_net(skb->sk);
+	struct ila_net *ilan = net_generic(net, ila_net_id);
+
+	return net_rslv_nl_cmd_flush(ilan->rslv.nrslv, skb, info);
+}
+
+int ila_rslv_nl_dump_start(struct netlink_callback *cb)
+{
+	struct net *net = sock_net(cb->skb->sk);
+	struct ila_net *ilan = net_generic(net, ila_net_id);
+
+	return net_rslv_nl_dump_start(ilan->rslv.nrslv, cb);
+}
+
+int ila_rslv_nl_dump_done(struct netlink_callback *cb)
+{
+	struct net *net = sock_net(cb->skb->sk);
+	struct ila_net *ilan = net_generic(net, ila_net_id);
+
+	return net_rslv_nl_dump_done(ilan->rslv.nrslv, cb);
+}
+
+int ila_rslv_nl_dump(struct sk_buff *skb, struct netlink_callback *cb)
+{
+	struct net *net = sock_net(cb->skb->sk);
+	struct ila_net *ilan = net_generic(net, ila_net_id);
+
+	return net_rslv_nl_dump(ilan->rslv.nrslv, skb, cb);
+}
+
 int ila_rslv_init(void)
 {
 	return lwtunnel_encap_add_ops(&ila_rslv_ops, LWTUNNEL_ENCAP_ILA_NOTIFY);
-- 
2.11.0

^ permalink raw reply related

* [PATCH net,stable] net: qmi_wwan: add Sierra EM7565 1199:9091
From: ssjoholm @ 2017-12-11 20:51 UTC (permalink / raw)
  To: netdev; +Cc: linux-usb, linux-kernel, bjorn, rspmn, Sebastian Sjoholm

From: Sebastian Sjoholm <ssjoholm@mac.com>

Sierra Wireless EM7565 is an Qualcomm MDM9x50 based M.2 modem.
The USB id is added to qmi_wwan.c to allow QMI communication 
with the EM7565.

Signed-off-by: Sebastian Sjoholm <ssjoholm@mac.com>
Acked-by: Bjørn Mork <bjorn@mork.no>
---
[The corresponding qcserial patch will be submitted by Reinhard Speyerer.]
---
 drivers/net/usb/qmi_wwan.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c
index 304ec6555cd8..3cebd6683938 100644
--- a/drivers/net/usb/qmi_wwan.c
+++ b/drivers/net/usb/qmi_wwan.c
@@ -1204,6 +1204,7 @@ static const struct usb_device_id products[] = {
 	{QMI_FIXED_INTF(0x1199, 0x9079, 10)},	/* Sierra Wireless EM74xx */
 	{QMI_FIXED_INTF(0x1199, 0x907b, 8)},	/* Sierra Wireless EM74xx */
 	{QMI_FIXED_INTF(0x1199, 0x907b, 10)},	/* Sierra Wireless EM74xx */
+	{QMI_FIXED_INTF(0x1199, 0x9091, 8)},	/* Sierra Wireless EM7565 */
 	{QMI_FIXED_INTF(0x1bbb, 0x011e, 4)},	/* Telekom Speedstick LTE II (Alcatel One Touch L100V LTE) */
 	{QMI_FIXED_INTF(0x1bbb, 0x0203, 2)},	/* Alcatel L800MA */
 	{QMI_FIXED_INTF(0x2357, 0x0201, 4)},	/* TP-LINK HSUPA Modem MA180 */
-- 
2.14.1

^ permalink raw reply related

* [PATCH ipsec-next] xfrm: check for xdo_dev_state_free
From: Shannon Nelson @ 2017-12-11 20:57 UTC (permalink / raw)
  To: steffen.klassert; +Cc: netdev

The current XFRM code assumes that we've implemented the
xdo_dev_state_free() callback, even if it is meaningless to the driver.
This patch adds a check for it before calling, as done in other APIs,
and is done for the xdo_state_offload_ok() callback.

Also, we add a check for the required add and delete functions up front
at registration time to be sure both are defined, and complain if not.

Signed-off-by: Shannon Nelson <shannon.nelson@oracle.com>
---
 include/net/xfrm.h     |  3 ++-
 net/xfrm/xfrm_device.c | 18 ++++++++++++++----
 2 files changed, 16 insertions(+), 5 deletions(-)

diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index e015e16..dfabd04 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -1891,7 +1891,8 @@ static inline void xfrm_dev_state_free(struct xfrm_state *x)
 	 struct net_device *dev = xso->dev;
 
 	if (dev && dev->xfrmdev_ops) {
-		dev->xfrmdev_ops->xdo_dev_state_free(x);
+		if (dev->xfrmdev_ops->xdo_dev_state_free)
+			dev->xfrmdev_ops->xdo_dev_state_free(x);
 		xso->dev = NULL;
 		dev_put(dev);
 	}
diff --git a/net/xfrm/xfrm_device.c b/net/xfrm/xfrm_device.c
index 30e5746..0df1cc2 100644
--- a/net/xfrm/xfrm_device.c
+++ b/net/xfrm/xfrm_device.c
@@ -144,11 +144,21 @@ EXPORT_SYMBOL_GPL(xfrm_dev_offload_ok);
 
 static int xfrm_dev_register(struct net_device *dev)
 {
-	if ((dev->features & NETIF_F_HW_ESP) && !dev->xfrmdev_ops)
-		return NOTIFY_BAD;
-	if ((dev->features & NETIF_F_HW_ESP_TX_CSUM) &&
-	    !(dev->features & NETIF_F_HW_ESP))
+	if (!(dev->features & NETIF_F_HW_ESP)) {
+		if (dev->features & NETIF_F_HW_ESP_TX_CSUM) {
+			netdev_err(dev, "NETIF_F_HW_ESP_TX_CSUM without NETIF_F_HW_ESP\n");
+			return NOTIFY_BAD;
+		} else {
+			return NOTIFY_DONE;
+		}
+	}
+
+	if (!(dev->xfrmdev_ops &&
+	      dev->xfrmdev_ops->xdo_dev_state_add &&
+	      dev->xfrmdev_ops->xdo_dev_state_delete)) {
+		netdev_err(dev, "add or delete function missing from xfrmdev_ops\n");
 		return NOTIFY_BAD;
+	}
 
 	return NOTIFY_DONE;
 }
-- 
2.7.4

^ permalink raw reply related

* [PATCH iproute2 1/1] ss: remove duplicate assignment
From: Roman Mashak @ 2017-12-11 21:24 UTC (permalink / raw)
  To: stephen; +Cc: jhs, netdev, Roman Mashak

Signed-off-by: Roman Mashak <mrv@mojatatu.com>
---
 misc/ss.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/misc/ss.c b/misc/ss.c
index 90da93e..da52d5e 100644
--- a/misc/ss.c
+++ b/misc/ss.c
@@ -2306,7 +2306,6 @@ static void tcp_show_info(const struct nlmsghdr *nlh, struct inet_diag_msg *r,
 		s.sacked	 = info->tcpi_sacked;
 		s.fackets	 = info->tcpi_fackets;
 		s.reordering	 = info->tcpi_reordering;
-		s.rcv_space	 = info->tcpi_rcv_space;
 		s.rcv_ssthresh   = info->tcpi_rcv_ssthresh;
 		s.cwnd		 = info->tcpi_snd_cwnd;
 
-- 
2.7.4

^ permalink raw reply related

* Re: [REGRESSION][4.13.y][4.14.y][v4.15.y] net: reduce skb_warn_bad_offload() noise
From: Willem de Bruijn @ 2017-12-11 21:25 UTC (permalink / raw)
  To: Joseph Salisbury
  Cc: Eric Dumazet, Dmitry Vyukov, Willem de Bruijn, David Miller,
	Daniel Borkmann, jakub.kicinski, linux, John Fastabend, me,
	idosch, Network Development, LKML, Greg Kroah-Hartman, stable,
	1715609
In-Reply-To: <0a352e7b-0404-2f91-206f-099e2376ab9a@canonical.com>

On Mon, Dec 11, 2017 at 3:35 PM, Joseph Salisbury
<joseph.salisbury@canonical.com> wrote:
> Hi Eric,
>
> A kernel bug report was opened against Ubuntu [0].  It was found that
> reverting the following commit resolved this bug:

The recorded trace in that bug is against 4.10.0 with some backports.
Given that commit b2504a5dbef3 ("net: reduce skb_warn_bad_offload()
noise") is implicated, I guess that that was backported from 4.11-rc1.

The WARN shows

  e1000e: caps=(0x00000030002149a9, 0x0000000000000000)
  len=1701 data_len=1659 gso_size=1480 gso_type=2 ip_summed=0

The numbering changed in 4.14, but for this kernel

  SKB_GSO_UDP = 1 << 1,

so this is a UFO packet with CHECKSUM_NONE. The stack shows

kernel: [570943.494549] skb_warn_bad_offload+0xd1/0x120
kernel: [570943.494550] __skb_gso_segment+0x17d/0x190
kernel: [570943.494564] validate_xmit_skb+0x14f/0x2a0
kernel: [570943.494565] validate_xmit_skb_list+0x43/0x70

so if that patch has been backported, then this must trigger in
__skb_gso_segment on the return path from skb_mac_gso_segment.

Did you backport

commit 8d63bee643f1fb53e472f0e135cae4eb99d62d19
Author: Willem de Bruijn <willemb@google.com>
Date:   Tue Aug 8 14:22:55 2017 -0400

    net: avoid skb_warn_bad_offload false positives on UFO

    skb_warn_bad_offload triggers a warning when an skb enters the GSO
    stack at __skb_gso_segment that does not have CHECKSUM_PARTIAL
    checksum offload set.

    Commit b2504a5dbef3 ("net: reduce skb_warn_bad_offload() noise")
    observed that SKB_GSO_DODGY producers can trigger the check and
    that passing those packets through the GSO handlers will fix it
    up. But, the software UFO handler will set ip_summed to
    CHECKSUM_NONE.

    When __skb_gso_segment is called from the receive path, this
    triggers the warning again.

    Make UFO set CHECKSUM_UNNECESSARY instead of CHECKSUM_NONE. On
    Tx these two are equivalent. On Rx, this better matches the
    skb state (checksum computed), as CHECKSUM_NONE here means no
    checksum computed.

    See also this thread for context:
    http://patchwork.ozlabs.org/patch/799015/

    Fixes: b2504a5dbef3 ("net: reduce skb_warn_bad_offload() noise")
    Signed-off-by: Willem de Bruijn <willemb@google.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

Note that UFO was removed in 4.14 and that skb_warn_bad_offload
can happen for various types of packets, so there may be multiple
independent bug reports. I'm investigating two other non-UFO reports
just now.

^ permalink raw reply

* Re: [REGRESSION][4.13.y][4.14.y][v4.15.y] net: reduce skb_warn_bad_offload() noise
From: David Miller @ 2017-12-11 21:28 UTC (permalink / raw)
  To: joseph.salisbury
  Cc: edumazet, dvyukov, willemb, daniel, jakub.kicinski, linux,
	john.fastabend, me, idosch, netdev, linux-kernel, gregkh, stable,
	1715609
In-Reply-To: <0a352e7b-0404-2f91-206f-099e2376ab9a@canonical.com>

From: Joseph Salisbury <joseph.salisbury@canonical.com>
Date: Mon, 11 Dec 2017 15:35:34 -0500

> A kernel bug report was opened against Ubuntu [0].  It was found that
> reverting the following commit resolved this bug:
> 
> commit b2504a5dbef3305ef41988ad270b0e8ec289331c
> Author: Eric Dumazet <edumazet@google.com>
> Date:   Tue Jan 31 10:20:32 2017 -0800
> 
>     net: reduce skb_warn_bad_offload() noise
>    
> 
> The regression was introduced as of v4.11-rc1 and still exists in
> current mainline.
>    
> I was hoping to get your feedback, since you are the patch author.  Do
> you think gathering any additional data will help diagnose this issue,
> or would it be best to submit a revert request?
>    
> This commit did in fact resolve another bug[1], but in the process
> introduced this regression.

It helps if you can consolidate the information obtained in your bug
tracking here in the email so that people on this list can get an idea
of what the problem scope might be without having to go to your
special bug tracking site.

This is really not about us being snobs about this mailing list, it's
about you wanting to get a result.  And you'll get a better result
faster if you post the details here on the lsit because most
developers are not going to go to your bug tracking site to read the
bug comments.

Also, this isn't a functional regression, it is just that we are
generating warnings that we didn't before.  It doesn't mean that
Eric's patch is wrong, it could just be that his new check is
triggering for a bug that has always been there.

Scanning the bug myself it seems that the critical required component
is IPSEC, and IPSEC has it's own way of doing segmentation offload.

Thanks.

^ permalink raw reply

* Huge memory leak with 4.15.0-rc2+
From: Paweł Staszewski @ 2017-12-11 21:23 UTC (permalink / raw)
  To: Linux Kernel Network Developers

Hi


I just upgraded some testing host to 4.15.0-rc2+ kernel

And after some time of traffic processing - when traffic on all ports 
reach about 3Mpps - memleak started.

Graph attached from memory usage: https://ibb.co/idK4zb



HW config:

Intel E5

8x Intel 82599 (used ixgbe driver from kernel)

Interfaces with vlans attached

All 8 ethernet ports are in one LAG group configured by team.

With current settings

(this host is acting as a router - and bgpd process is eating same 
amount of memory from the beginning about 5.2GB)

  cat /proc/meminfo
MemTotal:       32770588 kB
MemFree:        11342492 kB
MemAvailable:   10982752 kB
Buffers:           84704 kB
Cached:            83180 kB
SwapCached:            0 kB
Active:          5105320 kB
Inactive:          46252 kB
Active(anon):    4985448 kB
Inactive(anon):     1096 kB
Active(file):     119872 kB
Inactive(file):    45156 kB
Unevictable:           0 kB
Mlocked:               0 kB
SwapTotal:       4005280 kB
SwapFree:        4005280 kB
Dirty:               236 kB
Writeback:             0 kB
AnonPages:       4983752 kB
Mapped:            13556 kB
Shmem:              2852 kB
Slab:            1013124 kB
SReclaimable:      45876 kB
SUnreclaim:       967248 kB
KernelStack:        7152 kB
PageTables:        12164 kB
NFS_Unstable:          0 kB
Bounce:                0 kB
WritebackTmp:          0 kB
CommitLimit:    20390572 kB
Committed_AS:     396568 kB
VmallocTotal:   34359738367 kB
VmallocUsed:           0 kB
VmallocChunk:          0 kB
HardwareCorrupted:     0 kB
AnonHugePages:         0 kB
ShmemHugePages:        0 kB
ShmemPmdMapped:        0 kB
CmaTotal:              0 kB
CmaFree:               0 kB
HugePages_Total:       0
HugePages_Free:        0
HugePages_Rsvd:        0
HugePages_Surp:        0
Hugepagesize:       2048 kB
DirectMap4k:     1407572 kB
DirectMap2M:    20504576 kB
DirectMap1G:    13631488 kB

ps aux --sort -rss
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root      6758  1.8 14.9 5044996 4886964 ?     Sl   01:22  23:21 
/usr/local/sbin/bgpd -d  -u root -g root -I --ignore_warnings
root      6752  0.0  0.1  86272 61920 ?        Ss   01:22   0:16 
/usr/local/sbin/zebra -d  -u root -g root -I --ignore_warnings
root      6766 12.6  0.0  51592 29196 ?        S    01:22 157:48 
/usr/sbin/snmpd -p /var/run/snmpd.pid -Ln
root      7494  0.0  0.0 708976  5896 ?        Ssl  01:22   0:09 
/opt/collectd/sbin/collectd
root     15531  0.0  0.0  67864  5056 ?        Ss   21:57   0:00 sshd: 
paol [priv]
root      4915  0.0  0.0 271912  4904 ?        Ss   01:21   0:25 
/usr/sbin/syslog-ng --persist-file /var/lib/syslog-ng/syslog-ng.persist 
--cfgfile /etc/syslog-ng/syslog-ng.conf --pidfile /run/syslog-ng.pid
root      4278  0.0  0.0  37220  4164 ?        Ss   01:21   0:00 
/lib/systemd/systemd-udevd --daemon
root      5147  0.0  0.0  32072  3232 ?        Ss   01:21   0:00 
/usr/sbin/sshd
root      5203  0.0  0.0  28876  2436 ?        S    01:21   0:00 teamd 
-d -f /etc/teamd.conf
root     17372  0.0  0.0  17924  2388 pts/2    R+   22:13   0:00 ps aux 
--sort -rss
root      4789  0.0  0.0   5032  2176 ?        Ss   01:21   0:00 mdadm 
--monitor --scan --daemonise --pid-file /var/run/mdadm.pid --syslog
root      7511  0.0  0.0  12676  1920 tty4     Ss+  01:22   0:00 
/sbin/agetty 38400 tty4 linux
root      7510  0.0  0.0  12676  1896 tty3     Ss+  01:22   0:00 
/sbin/agetty 38400 tty3 linux
root      7512  0.0  0.0  12676  1860 tty5     Ss+  01:22   0:00 
/sbin/agetty 38400 tty5 linux
root      7513  0.0  0.0  12676  1836 tty6     Ss+  01:22   0:00 
/sbin/agetty 38400 tty6 linux
root      7509  0.0  0.0  12676  1832 tty2     Ss+  01:22   0:00 
/sbin/agetty 38400 tty2 linux

And latest kernel that everything was working is: 4.14.3


Some observations - when i disable tso on all cards there is more memleak.

^ permalink raw reply

* Re: [PATCH v3 net-next 0/9] net: Generic network resolver backend and ILA resolver
From: David Miller @ 2017-12-11 21:34 UTC (permalink / raw)
  To: tom; +Cc: netdev, roopa, rohit
In-Reply-To: <20171211203837.2540-1-tom@quantonium.net>

From: Tom Herbert <tom@quantonium.net>
Date: Mon, 11 Dec 2017 12:38:28 -0800

> DOS mitigations:
> 
> - The number of outstanding resolutions is limited by the size of the
>   table
> - Timeout of pending entries limits the number of netlink resolution
>   messages
> - Packets are not queued that are pending resolution. In the current
>   model that can be forwarded to a router that has all reachability
>   information (ILA use case for example)

None of these mitigation schemes matter.

If packet traffic can influence the table of entries (your cache
or whatever), then you will be DoS'able.

If you limit outstanding resolutions, you harm legitimate traffic
whose resolutions will not be processed now too just as equally
as you will harm "bad guy" traffic.

If you forward in the case of pending resolution, the bad guy can
make you forward everything there.  The bad guy can effectively
make your caching node stop caching completely.

Please, learn from OVS, the ipv4 routing cache, and the IPSEC
flow cache.  This kind of architecture, _especially_ when the
resolution is user side, is deeply flawed.

We're trying to remove code that does this kind of stuff, rather
than add new instances.

Thank you.

^ permalink raw reply

* Re: [REGRESSION][4.13.y][4.14.y][v4.15.y] net: reduce skb_warn_bad_offload() noise
From: Greg Kroah-Hartman @ 2017-12-11 21:44 UTC (permalink / raw)
  To: Willem de Bruijn
  Cc: Joseph Salisbury, Eric Dumazet, Dmitry Vyukov, Willem de Bruijn,
	David Miller, Daniel Borkmann, jakub.kicinski, linux,
	John Fastabend, me, idosch, Network Development, LKML, stable,
	1715609
In-Reply-To: <CAF=yD-L_S312Ryyg5fE3p6kqFus4SKQcgL2zXKiofq-ohiK7bg@mail.gmail.com>

On Mon, Dec 11, 2017 at 04:25:26PM -0500, Willem de Bruijn wrote:
> Note that UFO was removed in 4.14 and that skb_warn_bad_offload
> can happen for various types of packets, so there may be multiple
> independent bug reports. I'm investigating two other non-UFO reports
> just now.

Meta-comment, now that UFO is gone from mainline, I'm wondering if I
should just delete it from 4.4 and 4.9 as well.  Any objections for
that?  I'd like to make it easy to maintain these kernels for a while,
and having them diverge like this, with all of the issues around UFO,
seems like it will just make life harder for myself if I leave it in.

Any opinions?

thanks,

greg k-h

^ permalink raw reply

* Re: Huge memory leak with 4.15.0-rc2+
From: Paweł Staszewski @ 2017-12-11 21:48 UTC (permalink / raw)
  To: Linux Kernel Network Developers
In-Reply-To: <c3244df1-464d-0705-f798-896eaffe4c91@itcare.pl>



W dniu 2017-12-11 o 22:23, Paweł Staszewski pisze:
> Hi
>
>
> I just upgraded some testing host to 4.15.0-rc2+ kernel
>
> And after some time of traffic processing - when traffic on all ports 
> reach about 3Mpps - memleak started.
>
> Graph attached from memory usage: https://ibb.co/idK4zb
>
>
>
> HW config:
>
> Intel E5
>
> 8x Intel 82599 (used ixgbe driver from kernel)
>
> Interfaces with vlans attached
>
> All 8 ethernet ports are in one LAG group configured by team.
>
> With current settings
>
> (this host is acting as a router - and bgpd process is eating same 
> amount of memory from the beginning about 5.2GB)
>
>  cat /proc/meminfo
> MemTotal:       32770588 kB
> MemFree:        11342492 kB
> MemAvailable:   10982752 kB
> Buffers:           84704 kB
> Cached:            83180 kB
> SwapCached:            0 kB
> Active:          5105320 kB
> Inactive:          46252 kB
> Active(anon):    4985448 kB
> Inactive(anon):     1096 kB
> Active(file):     119872 kB
> Inactive(file):    45156 kB
> Unevictable:           0 kB
> Mlocked:               0 kB
> SwapTotal:       4005280 kB
> SwapFree:        4005280 kB
> Dirty:               236 kB
> Writeback:             0 kB
> AnonPages:       4983752 kB
> Mapped:            13556 kB
> Shmem:              2852 kB
> Slab:            1013124 kB
> SReclaimable:      45876 kB
> SUnreclaim:       967248 kB
> KernelStack:        7152 kB
> PageTables:        12164 kB
> NFS_Unstable:          0 kB
> Bounce:                0 kB
> WritebackTmp:          0 kB
> CommitLimit:    20390572 kB
> Committed_AS:     396568 kB
> VmallocTotal:   34359738367 kB
> VmallocUsed:           0 kB
> VmallocChunk:          0 kB
> HardwareCorrupted:     0 kB
> AnonHugePages:         0 kB
> ShmemHugePages:        0 kB
> ShmemPmdMapped:        0 kB
> CmaTotal:              0 kB
> CmaFree:               0 kB
> HugePages_Total:       0
> HugePages_Free:        0
> HugePages_Rsvd:        0
> HugePages_Surp:        0
> Hugepagesize:       2048 kB
> DirectMap4k:     1407572 kB
> DirectMap2M:    20504576 kB
> DirectMap1G:    13631488 kB
>
> ps aux --sort -rss
> USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
> root      6758  1.8 14.9 5044996 4886964 ?     Sl   01:22  23:21 
> /usr/local/sbin/bgpd -d  -u root -g root -I --ignore_warnings
> root      6752  0.0  0.1  86272 61920 ?        Ss   01:22   0:16 
> /usr/local/sbin/zebra -d  -u root -g root -I --ignore_warnings
> root      6766 12.6  0.0  51592 29196 ?        S    01:22 157:48 
> /usr/sbin/snmpd -p /var/run/snmpd.pid -Ln
> root      7494  0.0  0.0 708976  5896 ?        Ssl  01:22   0:09 
> /opt/collectd/sbin/collectd
> root     15531  0.0  0.0  67864  5056 ?        Ss   21:57   0:00 sshd: 
> paol [priv]
> root      4915  0.0  0.0 271912  4904 ?        Ss   01:21   0:25 
> /usr/sbin/syslog-ng --persist-file 
> /var/lib/syslog-ng/syslog-ng.persist --cfgfile 
> /etc/syslog-ng/syslog-ng.conf --pidfile /run/syslog-ng.pid
> root      4278  0.0  0.0  37220  4164 ?        Ss   01:21   0:00 
> /lib/systemd/systemd-udevd --daemon
> root      5147  0.0  0.0  32072  3232 ?        Ss   01:21   0:00 
> /usr/sbin/sshd
> root      5203  0.0  0.0  28876  2436 ?        S    01:21   0:00 teamd 
> -d -f /etc/teamd.conf
> root     17372  0.0  0.0  17924  2388 pts/2    R+   22:13   0:00 ps 
> aux --sort -rss
> root      4789  0.0  0.0   5032  2176 ?        Ss   01:21   0:00 mdadm 
> --monitor --scan --daemonise --pid-file /var/run/mdadm.pid --syslog
> root      7511  0.0  0.0  12676  1920 tty4     Ss+  01:22   0:00 
> /sbin/agetty 38400 tty4 linux
> root      7510  0.0  0.0  12676  1896 tty3     Ss+  01:22   0:00 
> /sbin/agetty 38400 tty3 linux
> root      7512  0.0  0.0  12676  1860 tty5     Ss+  01:22   0:00 
> /sbin/agetty 38400 tty5 linux
> root      7513  0.0  0.0  12676  1836 tty6     Ss+  01:22   0:00 
> /sbin/agetty 38400 tty6 linux
> root      7509  0.0  0.0  12676  1832 tty2     Ss+  01:22   0:00 
> /sbin/agetty 38400 tty2 linux
>
> And latest kernel that everything was working is: 4.14.3
>
>
> Some observations - when i disable tso on all cards there is more 
> memleak.
>
>
>
>
>
When traffic starts to drop - there is less and less memleak
below link to memory usage graph:
https://ibb.co/hU97kG

And there is rising slab_unrecl - Amount of unreclaimable memory used 
for slab kernel allocations


Forgot to add that im using hfsc and qdiscs like pfifo on classes.

^ permalink raw reply

* Re: [PATCH v5] leds: trigger: Introduce a NETDEV trigger
From: Jacek Anaszewski @ 2017-12-11 21:53 UTC (permalink / raw)
  To: Ben Whitten, rpurdie, pavel; +Cc: linux-leds, linux-kernel, netdev
In-Reply-To: <1512940675-9536-1-git-send-email-ben.whitten@gmail.com>

Hi Ben,

Thanks for the update.

On 12/10/2017 10:17 PM, Ben Whitten wrote:
> This commit introduces a NETDEV trigger for named device
> activity. Available triggers are link, rx, and tx.
> 
> Signed-off-by: Ben Whitten <ben.whitten@gmail.com>
> 
> ---
> Changes in v5:
> Adjust header comment style to be consistent
> Changes in v4:
> Adopt SPDX licence header
> Changes in v3:
> Cancel the software blink prior to a oneshot re-queue
> Changes in v2:
> Sort includes and redate documentation
> Correct licence
> Remove macro and replace with generic function using enums
> Convert blink logic in stats work to use led_blink_oneshot
> Uses configured brightness instead of FULL
> ---
>  .../ABI/testing/sysfs-class-led-trigger-netdev     |  45 ++
>  drivers/leds/trigger/Kconfig                       |   7 +
>  drivers/leds/trigger/Makefile                      |   1 +
>  drivers/leds/trigger/ledtrig-netdev.c              | 496 +++++++++++++++++++++
>  4 files changed, 549 insertions(+)
>  create mode 100644 Documentation/ABI/testing/sysfs-class-led-trigger-netdev
>  create mode 100644 drivers/leds/trigger/ledtrig-netdev.c
> 
> diff --git a/Documentation/ABI/testing/sysfs-class-led-trigger-netdev b/Documentation/ABI/testing/sysfs-class-led-trigger-netdev
> new file mode 100644
> index 0000000..451af6d
> --- /dev/null
> +++ b/Documentation/ABI/testing/sysfs-class-led-trigger-netdev
> @@ -0,0 +1,45 @@
> +What:		/sys/class/leds/<led>/device_name
> +Date:		Dec 2017
> +KernelVersion:	4.16
> +Contact:	linux-leds@vger.kernel.org
> +Description:
> +		Specifies the network device name to monitor.
> +
> +What:		/sys/class/leds/<led>/interval
> +Date:		Dec 2017
> +KernelVersion:	4.16
> +Contact:	linux-leds@vger.kernel.org
> +Description:
> +		Specifies the duration of the LED blink in milliseconds.
> +		Defaults to 50 ms.
> +
> +What:		/sys/class/leds/<led>/link
> +Date:		Dec 2017
> +KernelVersion:	4.16
> +Contact:	linux-leds@vger.kernel.org
> +Description:
> +		Signal the link state of the named network device.
> +		If set to 0 (default), the LED's normal state is off.
> +		If set to 1, the LED's normal state reflects the link state
> +		of the named network device.
> +		Setting this value also immediately changes the LED state.
> +
> +What:		/sys/class/leds/<led>/tx
> +Date:		Dec 2017
> +KernelVersion:	4.16
> +Contact:	linux-leds@vger.kernel.org
> +Description:
> +		Signal transmission of data on the named network device.
> +		If set to 0 (default), the LED will not blink on transmission.
> +		If set to 1, the LED will blink for the milliseconds specified
> +		in interval to signal transmission.
> +
> +What:		/sys/class/leds/<led>/rx
> +Date:		Dec 2017
> +KernelVersion:	4.16
> +Contact:	linux-leds@vger.kernel.org
> +Description:
> +		Signal reception of data on the named network device.
> +		If set to 0 (default), the LED will not blink on reception.
> +		If set to 1, the LED will blink for the milliseconds specified
> +		in interval to signal reception.
> diff --git a/drivers/leds/trigger/Kconfig b/drivers/leds/trigger/Kconfig
> index 3f9ddb9..4ec1853 100644
> --- a/drivers/leds/trigger/Kconfig
> +++ b/drivers/leds/trigger/Kconfig
> @@ -126,4 +126,11 @@ config LEDS_TRIGGER_PANIC
>  	  a different trigger.
>  	  If unsure, say Y.
>  
> +config LEDS_TRIGGER_NETDEV
> +	tristate "LED Netdev Trigger"
> +	depends on NET && LEDS_TRIGGERS
> +	help
> +	  This allows LEDs to be controlled by network device activity.
> +	  If unsure, say Y.
> +
>  endif # LEDS_TRIGGERS
> diff --git a/drivers/leds/trigger/Makefile b/drivers/leds/trigger/Makefile
> index 9f2e868..59e163d 100644
> --- a/drivers/leds/trigger/Makefile
> +++ b/drivers/leds/trigger/Makefile
> @@ -11,3 +11,4 @@ obj-$(CONFIG_LEDS_TRIGGER_DEFAULT_ON)	+= ledtrig-default-on.o
>  obj-$(CONFIG_LEDS_TRIGGER_TRANSIENT)	+= ledtrig-transient.o
>  obj-$(CONFIG_LEDS_TRIGGER_CAMERA)	+= ledtrig-camera.o
>  obj-$(CONFIG_LEDS_TRIGGER_PANIC)	+= ledtrig-panic.o
> +obj-$(CONFIG_LEDS_TRIGGER_NETDEV)	+= ledtrig-netdev.o
> diff --git a/drivers/leds/trigger/ledtrig-netdev.c b/drivers/leds/trigger/ledtrig-netdev.c
> new file mode 100644
> index 0000000..6df4781
> --- /dev/null
> +++ b/drivers/leds/trigger/ledtrig-netdev.c
> @@ -0,0 +1,496 @@
> +// SPDX-License-Identifier: GPL-2.0
> +// Copyright 2017 Ben Whitten <ben.whitten@gmail.com>
> +// Copyright 2007 Oliver Jowett <oliver@opencloud.com>
> +//
> +// LED Kernel Netdev Trigger
> +//
> +// Toggles the LED to reflect the link and traffic state of a named net device
> +//
> +// Derived from ledtrig-timer.c which is:
> +//  Copyright 2005-2006 Openedhand Ltd.
> +//  Author: Richard Purdie <rpurdie@openedhand.com>
> +
> +#include <linux/atomic.h>
> +#include <linux/ctype.h>
> +#include <linux/device.h>
> +#include <linux/init.h>
> +#include <linux/jiffies.h>
> +#include <linux/kernel.h>
> +#include <linux/leds.h>
> +#include <linux/list.h>
> +#include <linux/module.h>
> +#include <linux/netdevice.h>
> +#include <linux/spinlock.h>
> +#include <linux/timer.h>
> +#include "../leds.h"
> +
> +/*
> + * Configurable sysfs attributes:
> + *
> + * device_name - network device name to monitor
> + * interval - duration of LED blink, in milliseconds
> + * link -  LED's normal state reflects whether the link is up
> + *         (has carrier) or not
> + * tx -  LED blinks on transmitted data
> + * rx -  LED blinks on receive data
> + *
> + */
> +
> +struct led_netdev_data {
> +	spinlock_t lock;
> +
> +	struct delayed_work work;
> +	struct notifier_block notifier;
> +
> +	struct led_classdev *led_cdev;
> +	struct net_device *net_dev;
> +
> +	char device_name[IFNAMSIZ];
> +	atomic_t interval;
> +	unsigned int last_activity;
> +
> +	unsigned long mode;
> +#define NETDEV_LED_LINK	0
> +#define NETDEV_LED_TX	1
> +#define NETDEV_LED_RX	2
> +#define NETDEV_LED_MODE_LINKUP	3
> +};
> +
> +enum netdev_led_attr {
> +	NETDEV_ATTR_LINK,
> +	NETDEV_ATTR_TX,
> +	NETDEV_ATTR_RX
> +};
> +
> +static void set_baseline_state(struct led_netdev_data *trigger_data)
> +{
> +	int current_brightness;
> +	struct led_classdev *led_cdev = trigger_data->led_cdev;
> +
> +	current_brightness = led_cdev->brightness;
> +	if (current_brightness)
> +		led_cdev->blink_brightness = current_brightness;
> +	if (!led_cdev->blink_brightness)
> +		led_cdev->blink_brightness = led_cdev->max_brightness;
> +
> +	if (!test_bit(NETDEV_LED_MODE_LINKUP, &trigger_data->mode))
> +		led_set_brightness(led_cdev, LED_OFF);
> +	else {
> +		if (test_bit(NETDEV_LED_LINK, &trigger_data->mode))
> +			led_set_brightness(led_cdev,
> +					   led_cdev->blink_brightness);
> +		else
> +			led_set_brightness(led_cdev, LED_OFF);
> +
> +		/* If we are looking for RX/TX start periodically
> +		 * checking stats
> +		 */
> +		if (test_bit(NETDEV_LED_TX, &trigger_data->mode) ||
> +		    test_bit(NETDEV_LED_RX, &trigger_data->mode))
> +			schedule_delayed_work(&trigger_data->work, 0);
> +	}
> +}
> +
> +static ssize_t device_name_show(struct device *dev,
> +				struct device_attribute *attr, char *buf)
> +{
> +	struct led_classdev *led_cdev = dev_get_drvdata(dev);
> +	struct led_netdev_data *trigger_data = led_cdev->trigger_data;
> +	ssize_t len;
> +
> +	spin_lock_bh(&trigger_data->lock);
> +	len = sprintf(buf, "%s\n", trigger_data->device_name);
> +	spin_unlock_bh(&trigger_data->lock);
> +
> +	return len;
> +}
> +
> +static ssize_t device_name_store(struct device *dev,
> +				 struct device_attribute *attr, const char *buf,
> +				 size_t size)
> +{
> +	struct led_classdev *led_cdev = dev_get_drvdata(dev);
> +	struct led_netdev_data *trigger_data = led_cdev->trigger_data;
> +
> +	if (size >= IFNAMSIZ)
> +		return -EINVAL;
> +
> +	cancel_delayed_work_sync(&trigger_data->work);
> +
> +	spin_lock_bh(&trigger_data->lock);
> +
> +	if (trigger_data->net_dev) {
> +		dev_put(trigger_data->net_dev);
> +		trigger_data->net_dev = NULL;
> +	}
> +
> +	strncpy(trigger_data->device_name, buf, size);
> +	if (size > 0 && trigger_data->device_name[size - 1] == '\n')
> +		trigger_data->device_name[size - 1] = 0;
> +
> +	if (trigger_data->device_name[0] != 0)
> +		trigger_data->net_dev =
> +		    dev_get_by_name(&init_net, trigger_data->device_name);
> +
> +	clear_bit(NETDEV_LED_MODE_LINKUP, &trigger_data->mode);
> +	if (trigger_data->net_dev != NULL)
> +		if (netif_carrier_ok(trigger_data->net_dev))
> +			set_bit(NETDEV_LED_MODE_LINKUP, &trigger_data->mode);
> +
> +	trigger_data->last_activity = 0;
> +
> +	set_baseline_state(trigger_data);
> +	spin_unlock_bh(&trigger_data->lock);
> +
> +	return size;
> +}
> +
> +static DEVICE_ATTR_RW(device_name);
> +
> +static ssize_t netdev_led_attr_show(struct device *dev, char *buf,
> +	enum netdev_led_attr attr)
> +{
> +	struct led_classdev *led_cdev = dev_get_drvdata(dev);
> +	struct led_netdev_data *trigger_data = led_cdev->trigger_data;
> +	int bit;
> +
> +	switch (attr) {
> +	case NETDEV_ATTR_LINK:
> +		bit = NETDEV_LED_LINK;
> +		break;
> +	case NETDEV_ATTR_TX:
> +		bit = NETDEV_LED_TX;
> +		break;
> +	case NETDEV_ATTR_RX:
> +		bit = NETDEV_LED_RX;
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	return sprintf(buf, "%u\n", test_bit(bit, &trigger_data->mode));
> +}
> +
> +static ssize_t netdev_led_attr_store(struct device *dev, const char *buf,
> +	size_t size, enum netdev_led_attr attr)
> +{
> +	struct led_classdev *led_cdev = dev_get_drvdata(dev);
> +	struct led_netdev_data *trigger_data = led_cdev->trigger_data;
> +	unsigned long state;
> +	int ret;
> +	int bit;
> +
> +	ret = kstrtoul(buf, 0, &state);
> +	if (ret)
> +		return ret;
> +
> +	switch (attr) {
> +	case NETDEV_ATTR_LINK:
> +		bit = NETDEV_LED_LINK;
> +		break;
> +	case NETDEV_ATTR_TX:
> +		bit = NETDEV_LED_TX;
> +		break;
> +	case NETDEV_ATTR_RX:
> +		bit = NETDEV_LED_RX;
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	cancel_delayed_work_sync(&trigger_data->work);
> +
> +	if (state)
> +		set_bit(bit, &trigger_data->mode);
> +	else
> +		clear_bit(bit, &trigger_data->mode);
> +
> +	set_baseline_state(trigger_data);
> +
> +	return size;
> +}
> +
> +static ssize_t link_show(struct device *dev,
> +	struct device_attribute *attr, char *buf)
> +{
> +	return netdev_led_attr_show(dev, buf, NETDEV_ATTR_LINK);
> +}
> +
> +static ssize_t link_store(struct device *dev,
> +	struct device_attribute *attr, const char *buf, size_t size)
> +{
> +	return netdev_led_attr_store(dev, buf, size, NETDEV_ATTR_LINK);
> +}
> +
> +static DEVICE_ATTR_RW(link);
> +
> +static ssize_t tx_show(struct device *dev,
> +	struct device_attribute *attr, char *buf)
> +{
> +	return netdev_led_attr_show(dev, buf, NETDEV_ATTR_TX);
> +}
> +
> +static ssize_t tx_store(struct device *dev,
> +	struct device_attribute *attr, const char *buf, size_t size)
> +{
> +	return netdev_led_attr_store(dev, buf, size, NETDEV_ATTR_TX);
> +}
> +
> +static DEVICE_ATTR_RW(tx);
> +
> +static ssize_t rx_show(struct device *dev,
> +	struct device_attribute *attr, char *buf)
> +{
> +	return netdev_led_attr_show(dev, buf, NETDEV_ATTR_RX);
> +}
> +
> +static ssize_t rx_store(struct device *dev,
> +	struct device_attribute *attr, const char *buf, size_t size)
> +{
> +	return netdev_led_attr_store(dev, buf, size, NETDEV_ATTR_RX);
> +}
> +
> +static DEVICE_ATTR_RW(rx);
> +
> +static ssize_t interval_show(struct device *dev,
> +			     struct device_attribute *attr, char *buf)
> +{
> +	struct led_classdev *led_cdev = dev_get_drvdata(dev);
> +	struct led_netdev_data *trigger_data = led_cdev->trigger_data;
> +
> +	return sprintf(buf, "%u\n",
> +		       jiffies_to_msecs(atomic_read(&trigger_data->interval)));
> +}
> +
> +static ssize_t interval_store(struct device *dev,
> +			      struct device_attribute *attr, const char *buf,
> +			      size_t size)
> +{
> +	struct led_classdev *led_cdev = dev_get_drvdata(dev);
> +	struct led_netdev_data *trigger_data = led_cdev->trigger_data;
> +	unsigned long value;
> +	int ret;
> +
> +	ret = kstrtoul(buf, 0, &value);
> +	if (ret)
> +		return ret;
> +
> +	/* impose some basic bounds on the timer interval */
> +	if (value >= 5 && value <= 10000) {
> +		cancel_delayed_work_sync(&trigger_data->work);
> +
> +		atomic_set(&trigger_data->interval, msecs_to_jiffies(value));
> +		set_baseline_state(trigger_data);	/* resets timer */
> +	}
> +
> +	return size;
> +}
> +
> +static DEVICE_ATTR_RW(interval);
> +
> +static int netdev_trig_notify(struct notifier_block *nb,
> +			      unsigned long evt, void *dv)
> +{
> +	struct net_device *dev =
> +		netdev_notifier_info_to_dev((struct netdev_notifier_info *)dv);
> +	struct led_netdev_data *trigger_data = container_of(nb,
> +							    struct
> +							    led_netdev_data,
> +							    notifier);
> +
> +	if (evt != NETDEV_UP && evt != NETDEV_DOWN && evt != NETDEV_CHANGE
> +	    && evt != NETDEV_REGISTER && evt != NETDEV_UNREGISTER
> +	    && evt != NETDEV_CHANGENAME)
> +		return NOTIFY_DONE;
> +
> +	if (strcmp(dev->name, trigger_data->device_name))
> +		return NOTIFY_DONE;
> +
> +	cancel_delayed_work_sync(&trigger_data->work);
> +
> +	spin_lock_bh(&trigger_data->lock);
> +
> +	clear_bit(NETDEV_LED_MODE_LINKUP, &trigger_data->mode);
> +	switch (evt) {
> +	case NETDEV_REGISTER:
> +		if (trigger_data->net_dev)
> +			dev_put(trigger_data->net_dev);
> +		dev_hold(dev);
> +		trigger_data->net_dev = dev;
> +		break;
> +	case NETDEV_CHANGENAME:
> +	case NETDEV_UNREGISTER:
> +		if (trigger_data->net_dev) {
> +			dev_put(trigger_data->net_dev);
> +			trigger_data->net_dev = NULL;
> +		}
> +		break;
> +	case NETDEV_UP:
> +	case NETDEV_CHANGE:
> +		if (netif_carrier_ok(dev))
> +			set_bit(NETDEV_LED_MODE_LINKUP, &trigger_data->mode);
> +		break;
> +	}
> +
> +	set_baseline_state(trigger_data);
> +
> +	spin_unlock_bh(&trigger_data->lock);
> +
> +	return NOTIFY_DONE;
> +}
> +
> +/* here's the real work! */
> +static void netdev_trig_work(struct work_struct *work)
> +{
> +	struct led_netdev_data *trigger_data = container_of(work,
> +							    struct
> +							    led_netdev_data,
> +							    work.work);
> +	struct rtnl_link_stats64 *dev_stats;
> +	unsigned int new_activity;
> +	struct rtnl_link_stats64 temp;
> +	unsigned long interval;
> +	int invert;
> +
> +	/* If we dont have a device, insure we are off */
> +	if (!trigger_data->net_dev) {
> +		led_set_brightness(trigger_data->led_cdev, LED_OFF);
> +		return;
> +	}
> +
> +	/* If we are not looking for RX/TX then return  */
> +	if (!test_bit(NETDEV_LED_TX, &trigger_data->mode) &&
> +	    !test_bit(NETDEV_LED_RX, &trigger_data->mode))
> +		return;
> +
> +	dev_stats = dev_get_stats(trigger_data->net_dev, &temp);
> +	new_activity =
> +	    (test_bit(NETDEV_LED_TX, &trigger_data->mode) ?
> +		dev_stats->tx_packets : 0) +
> +	    (test_bit(NETDEV_LED_RX, &trigger_data->mode) ?
> +		dev_stats->rx_packets : 0);
> +
> +	if (trigger_data->last_activity != new_activity) {
> +		led_stop_software_blink(trigger_data->led_cdev);
> +
> +		invert = test_bit(NETDEV_LED_LINK, &trigger_data->mode);
> +		interval = jiffies_to_msecs(
> +				atomic_read(&trigger_data->interval));
> +		/* base state is ON (link present) */
> +		led_blink_set_oneshot(trigger_data->led_cdev,
> +				      &interval,
> +				      &interval,
> +				      invert);
> +		trigger_data->last_activity = new_activity;
> +	}
> +
> +	schedule_delayed_work(&trigger_data->work,
> +			(atomic_read(&trigger_data->interval)*2));
> +}
> +
> +static void netdev_trig_activate(struct led_classdev *led_cdev)
> +{
> +	struct led_netdev_data *trigger_data;
> +	int rc;
> +
> +	trigger_data = kzalloc(sizeof(struct led_netdev_data), GFP_KERNEL);
> +	if (!trigger_data)
> +		return;
> +
> +	spin_lock_init(&trigger_data->lock);
> +
> +	trigger_data->notifier.notifier_call = netdev_trig_notify;
> +	trigger_data->notifier.priority = 10;
> +
> +	INIT_DELAYED_WORK(&trigger_data->work, netdev_trig_work);
> +
> +	trigger_data->led_cdev = led_cdev;
> +	trigger_data->net_dev = NULL;
> +	trigger_data->device_name[0] = 0;
> +
> +	trigger_data->mode = 0;
> +	atomic_set(&trigger_data->interval, msecs_to_jiffies(50));
> +	trigger_data->last_activity = 0;
> +
> +	led_cdev->trigger_data = trigger_data;
> +
> +	rc = device_create_file(led_cdev->dev, &dev_attr_device_name);
> +	if (rc)
> +		goto err_out;
> +	rc = device_create_file(led_cdev->dev, &dev_attr_link);
> +	if (rc)
> +		goto err_out_device_name;
> +	rc = device_create_file(led_cdev->dev, &dev_attr_rx);
> +	if (rc)
> +		goto err_out_link;
> +	rc = device_create_file(led_cdev->dev, &dev_attr_tx);
> +	if (rc)
> +		goto err_out_rx;
> +	rc = device_create_file(led_cdev->dev, &dev_attr_interval);
> +	if (rc)
> +		goto err_out_tx;
> +	rc = register_netdevice_notifier(&trigger_data->notifier);
> +	if (rc)
> +		goto err_out_interval;
> +	return;
> +
> +err_out_interval:
> +	device_remove_file(led_cdev->dev, &dev_attr_interval);
> +err_out_tx:
> +	device_remove_file(led_cdev->dev, &dev_attr_tx);
> +err_out_rx:
> +	device_remove_file(led_cdev->dev, &dev_attr_rx);
> +err_out_link:
> +	device_remove_file(led_cdev->dev, &dev_attr_link);
> +err_out_device_name:
> +	device_remove_file(led_cdev->dev, &dev_attr_device_name);
> +err_out:
> +	led_cdev->trigger_data = NULL;
> +	kfree(trigger_data);
> +}
> +
> +static void netdev_trig_deactivate(struct led_classdev *led_cdev)
> +{
> +	struct led_netdev_data *trigger_data = led_cdev->trigger_data;
> +
> +	if (trigger_data) {
> +		unregister_netdevice_notifier(&trigger_data->notifier);
> +
> +		device_remove_file(led_cdev->dev, &dev_attr_device_name);
> +		device_remove_file(led_cdev->dev, &dev_attr_link);
> +		device_remove_file(led_cdev->dev, &dev_attr_rx);
> +		device_remove_file(led_cdev->dev, &dev_attr_tx);
> +		device_remove_file(led_cdev->dev, &dev_attr_interval);
> +
> +		cancel_delayed_work_sync(&trigger_data->work);
> +
> +		if (trigger_data->net_dev)
> +			dev_put(trigger_data->net_dev);
> +
> +		kfree(trigger_data);
> +	}
> +}
> +
> +static struct led_trigger netdev_led_trigger = {
> +	.name = "netdev",
> +	.activate = netdev_trig_activate,
> +	.deactivate = netdev_trig_deactivate,
> +};
> +
> +static int __init netdev_trig_init(void)
> +{
> +	return led_trigger_register(&netdev_led_trigger);
> +}
> +
> +static void __exit netdev_trig_exit(void)
> +{
> +	led_trigger_unregister(&netdev_led_trigger);
> +}
> +
> +module_init(netdev_trig_init);
> +module_exit(netdev_trig_exit);
> +
> +MODULE_AUTHOR("Ben Whitten <ben.whitten@gmail.com>");
> +MODULE_AUTHOR("Oliver Jowett <oliver@opencloud.com>");
> +MODULE_DESCRIPTION("Netdev LED trigger");
> +MODULE_LICENSE("GPL v2");
> 

Applied to the for-next branch of linux-leds.git.

-- 
Best regards,
Jacek Anaszewski

^ permalink raw reply

* [net-next PATCH 1/1] tipc: add back tipc prefix to log messages
From: John Thompson @ 2017-12-11 21:54 UTC (permalink / raw)
  To: davem, netdev; +Cc: tipc-discussion

The tipc prefix to log messages generated by tipc was
removed in commit 07f6c4bc0 ("tipc: convert tipc reference
table to use generic rhashtable").

This is still a useful prefix and so add it back.

Acked-by: Jon Maloy <jon.maloy@ericsson.com>
Signed-off-by: John Thompson <thompa.atl@gmail.com>
---
 net/tipc/core.c | 2 --
 net/tipc/core.h | 2 ++
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/net/tipc/core.c b/net/tipc/core.c
index 0b982d048fb9..4cd9e57446ec 100644
--- a/net/tipc/core.c
+++ b/net/tipc/core.c
@@ -34,8 +34,6 @@
  * POSSIBILITY OF SUCH DAMAGE.
  */

-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
 #include "core.h"
 #include "name_table.h"
 #include "subscr.h"
diff --git a/net/tipc/core.h b/net/tipc/core.h
index 964342689f2c..f89f9a3c18c2 100644
--- a/net/tipc/core.h
+++ b/net/tipc/core.h
@@ -37,6 +37,8 @@
 #ifndef _TIPC_CORE_H
 #define _TIPC_CORE_H

+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/tipc.h>
 #include <linux/tipc_config.h>
 #include <linux/tipc_netlink.h>
-- 
2.15.0
------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot

^ permalink raw reply related

* Re: [REGRESSION][4.13.y][4.14.y][v4.15.y] net: reduce skb_warn_bad_offload() noise
From: Willem de Bruijn @ 2017-12-11 21:56 UTC (permalink / raw)
  To: Greg Kroah-Hartman
  Cc: Joseph Salisbury, Eric Dumazet, Dmitry Vyukov, Willem de Bruijn,
	David Miller, Daniel Borkmann, jakub.kicinski, linux,
	John Fastabend, me, idosch, Network Development, LKML, stable,
	1715609
In-Reply-To: <20171211214457.GA28858@kroah.com>

On Mon, Dec 11, 2017 at 4:44 PM, Greg Kroah-Hartman
<gregkh@linuxfoundation.org> wrote:
> On Mon, Dec 11, 2017 at 04:25:26PM -0500, Willem de Bruijn wrote:
>> Note that UFO was removed in 4.14 and that skb_warn_bad_offload
>> can happen for various types of packets, so there may be multiple
>> independent bug reports. I'm investigating two other non-UFO reports
>> just now.
>
> Meta-comment, now that UFO is gone from mainline, I'm wondering if I
> should just delete it from 4.4 and 4.9 as well.  Any objections for
> that?  I'd like to make it easy to maintain these kernels for a while,
> and having them diverge like this, with all of the issues around UFO,
> seems like it will just make life harder for myself if I leave it in.
>
> Any opinions?

Some of that removal had to be reverted with commit 0c19f846d582
("net: accept UFO datagrams from tuntap and packet") for VM live
migration between kernels.

Any backports probably should squash that in at the least. Just today
another thread discussed that that patch may not address all open
issues still, so it may be premature to backport at this point.
http://lkml.kernel.org/r/<d71df64e-e65f-4db4-6f2e-c002c15fcbe4@01019freenet.de>

^ permalink raw reply

* Re: Huge memory leak with 4.15.0-rc2+
From: John Fastabend @ 2017-12-11 22:15 UTC (permalink / raw)
  To: Paweł Staszewski, Linux Kernel Network Developers
In-Reply-To: <2353c149-cae1-f986-63d0-3568534a1e8c@itcare.pl>

On 12/11/2017 01:48 PM, Paweł Staszewski wrote:
> 
> 
> W dniu 2017-12-11 o 22:23, Paweł Staszewski pisze:
>> Hi
>>
>>
>> I just upgraded some testing host to 4.15.0-rc2+ kernel
>>
>> And after some time of traffic processing - when traffic on all ports
>> reach about 3Mpps - memleak started.
>>


[...]

>> Some observations - when i disable tso on all cards there is more
>> memleak.
>>
>>
>>
>>
>>
> When traffic starts to drop - there is less and less memleak
> below link to memory usage graph:
> https://ibb.co/hU97kG
> 
> And there is rising slab_unrecl - Amount of unreclaimable memory used
> for slab kernel allocations
> 
> 
> Forgot to add that im using hfsc and qdiscs like pfifo on classes.
> 
> 

Maybe some error case I missed in the qdisc patches I'm looking into
it.

Thanks,
John

^ permalink raw reply

* Re: [PATCH v3 net-next 0/9] net: Generic network resolver backend and ILA resolver
From: Tom Herbert @ 2017-12-11 22:16 UTC (permalink / raw)
  To: David Miller
  Cc: Linux Kernel Network Developers, Roopa Prabhu, Rohit LastName
In-Reply-To: <20171211.163416.1305681033764328226.davem@davemloft.net>

On Mon, Dec 11, 2017 at 1:34 PM, David Miller <davem@davemloft.net> wrote:
> From: Tom Herbert <tom@quantonium.net>
> Date: Mon, 11 Dec 2017 12:38:28 -0800
>
>> DOS mitigations:
>>
>> - The number of outstanding resolutions is limited by the size of the
>>   table
>> - Timeout of pending entries limits the number of netlink resolution
>>   messages
>> - Packets are not queued that are pending resolution. In the current
>>   model that can be forwarded to a router that has all reachability
>>   information (ILA use case for example)
>
> None of these mitigation schemes matter.
>
> If packet traffic can influence the table of entries (your cache
> or whatever), then you will be DoS'able.
>
> If you limit outstanding resolutions, you harm legitimate traffic
> whose resolutions will not be processed now too just as equally
> as you will harm "bad guy" traffic.
>
David,

How can we build a system that allows an unlimited number of
resolutions without drop? Unless the resolution path can handle a
higher packet load than the receive path, there will be some place in
the system where memory is allocated and that limits the amount of
pending resolutions (i.e. pending packet skbs, entry in a resolution
table, skbs on a netlink socket).

> If you forward in the case of pending resolution, the bad guy can
> make you forward everything there.  The bad guy can effectively
> make your caching node stop caching completely.
>
But a DOS attack doesn't stop fowarding, at best it forces suboptimal
forwarding. This analogous to when the SYN cache is filled up but SYN
cookies allow forward progress in a degraded operational mode.

Thanks,
Tom

^ permalink raw reply

* Re: Huge memory leak with 4.15.0-rc2+
From: Paweł Staszewski @ 2017-12-11 22:27 UTC (permalink / raw)
  To: John Fastabend, Linux Kernel Network Developers
In-Reply-To: <65a3563d-396e-e4fb-7dad-937ce999868e@gmail.com>



W dniu 2017-12-11 o 23:15, John Fastabend pisze:
> On 12/11/2017 01:48 PM, Paweł Staszewski wrote:
>>
>> W dniu 2017-12-11 o 22:23, Paweł Staszewski pisze:
>>> Hi
>>>
>>>
>>> I just upgraded some testing host to 4.15.0-rc2+ kernel
>>>
>>> And after some time of traffic processing - when traffic on all ports
>>> reach about 3Mpps - memleak started.
>>>
>
> [...]
>
>>> Some observations - when i disable tso on all cards there is more
>>> memleak.
>>>
>>>
>>>
>>>
>>>
>> When traffic starts to drop - there is less and less memleak
>> below link to memory usage graph:
>> https://ibb.co/hU97kG
>>
>> And there is rising slab_unrecl - Amount of unreclaimable memory used
>> for slab kernel allocations
>>
>>
>> Forgot to add that im using hfsc and qdiscs like pfifo on classes.
>>
>>
> Maybe some error case I missed in the qdisc patches I'm looking into
> it.
>
> Thanks,
> John
>
>
This is how it looks like when corelated on graph - traffic vs mem
https://ibb.co/njpkqG

Typical hfsc class + qdisc:
### Client interface vlan1616
tc qdisc del dev vlan1616 root
tc qdisc add dev vlan1616 handle 1: root hfsc default 100
tc class add dev vlan1616 parent 1: classid 1:100 hfsc ls m2 200Mbit ul 
m2 200Mbit
tc qdisc add dev vlan1616 parent 1:100 handle 100: pfifo limit 128
### End TM for client interface
tc qdisc del dev vlan1616 ingress
tc qdisc add dev vlan1616 handle ffff: ingress
tc filter add dev vlan1616 parent ffff: protocol ip prio 50 u32 match ip 
src 0.0.0.0/0 police rate 200Mbit burst 200M mtu 32k drop flowid 1:1

And this is same for about 450 vlan interfaces


Good thing is that compared to 4.14.3 i have about 5% less cpu load on 
4.15.0-rc2+

When hfsc will be lockless or tbf - then it will be really huge 
difference in cpu load on x86 when using traffic shaping - so really 
good job John.

^ permalink raw reply

* Re: [PATCH v3 net-next 0/9] net: Generic network resolver backend and ILA resolver
From: Tom Herbert @ 2017-12-11 22:32 UTC (permalink / raw)
  To: Tom Herbert
  Cc: David Miller, Linux Kernel Network Developers, Roopa Prabhu,
	Rohit LastName
In-Reply-To: <CAPDqMer_F=uFZ08LytAbU7hwT4d98iYFGfHHFKKtL1mB4a+6qw@mail.gmail.com>

On Mon, Dec 11, 2017 at 2:16 PM, Tom Herbert <tom@quantonium.net> wrote:
> On Mon, Dec 11, 2017 at 1:34 PM, David Miller <davem@davemloft.net> wrote:
>> From: Tom Herbert <tom@quantonium.net>
>> Date: Mon, 11 Dec 2017 12:38:28 -0800
>>
>>> DOS mitigations:
>>>
>>> - The number of outstanding resolutions is limited by the size of the
>>>   table
>>> - Timeout of pending entries limits the number of netlink resolution
>>>   messages
>>> - Packets are not queued that are pending resolution. In the current
>>>   model that can be forwarded to a router that has all reachability
>>>   information (ILA use case for example)
>>
>> None of these mitigation schemes matter.
>>
>> If packet traffic can influence the table of entries (your cache
>> or whatever), then you will be DoS'able.
>>
>> If you limit outstanding resolutions, you harm legitimate traffic
>> whose resolutions will not be processed now too just as equally
>> as you will harm "bad guy" traffic.
>>
> David,
>
Actually, please disregard. I will respin to use secure redirects.

> How can we build a system that allows an unlimited number of
> resolutions without drop? Unless the resolution path can handle a
> higher packet load than the receive path, there will be some place in
> the system where memory is allocated and that limits the amount of
> pending resolutions (i.e. pending packet skbs, entry in a resolution
> table, skbs on a netlink socket).
>
>> If you forward in the case of pending resolution, the bad guy can
>> make you forward everything there.  The bad guy can effectively
>> make your caching node stop caching completely.
>>
> But a DOS attack doesn't stop fowarding, at best it forces suboptimal
> forwarding. This analogous to when the SYN cache is filled up but SYN
> cookies allow forward progress in a degraded operational mode.
>
> Thanks,
> Tom

^ permalink raw reply

* Re: [PATCH net-next v5 1/2] net: add support for Cavium PTP coprocessor
From: Richard Cochran @ 2017-12-11 22:59 UTC (permalink / raw)
  To: Aleksey Makarov
  Cc: netdev, linux-arm-kernel, linux-kernel, Goutham, Sunil,
	Radoslaw Biernacki, Robert Richter, David Daney,
	Philippe Ombredanne
In-Reply-To: <20171211141435.2915-2-aleksey.makarov@cavium.com>


Sorry I didn't finish reviewing before...

On Mon, Dec 11, 2017 at 05:14:30PM +0300, Aleksey Makarov wrote:
> +/**
> + * cavium_ptp_adjfreq() - Adjust ptp frequency
> + * @ptp: PTP clock info
> + * @ppb: how much to adjust by, in parts-per-billion
> + */
> +static int cavium_ptp_adjfreq(struct ptp_clock_info *ptp_info, s32 ppb)

adjfreq() is deprecated.  See ptp_clock_kernel.h.  Please re-work this
to implement the adjfine() method instead.

> +/**
> + * cavium_ptp_enable() - Check if PTP is enabled

Nit - comment is not correct. This method is for the auxiliary PHC
functions.

> + * @ptp: PTP clock info
> + * @rq:  request
> + * @on:  is it on
> + */
> +static int cavium_ptp_enable(struct ptp_clock_info *ptp_info,
> +			     struct ptp_clock_request *rq, int on)
> +{
> +	return -EOPNOTSUPP;
> +}

...

> +static int cavium_ptp_probe(struct pci_dev *pdev,
> +			    const struct pci_device_id *ent)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct cavium_ptp *clock;
> +	struct cyclecounter *cc;
> +	u64 clock_cfg;
> +	u64 clock_comp;
> +	int err;
> +
> +	clock = devm_kzalloc(dev, sizeof(*clock), GFP_KERNEL);
> +	if (!clock)
> +		return -ENOMEM;
> +
> +	clock->pdev = pdev;
> +
> +	err = pcim_enable_device(pdev);
> +	if (err)
> +		return err;
> +
> +	err = pcim_iomap_regions(pdev, 1 << PCI_PTP_BAR_NO, pci_name(pdev));
> +	if (err)
> +		return err;
> +
> +	clock->reg_base = pcim_iomap_table(pdev)[PCI_PTP_BAR_NO];
> +
> +	spin_lock_init(&clock->spin_lock);
> +
> +	cc = &clock->cycle_counter;
> +	cc->read = cavium_ptp_cc_read;
> +	cc->mask = CYCLECOUNTER_MASK(64);
> +	cc->mult = 1;
> +	cc->shift = 0;
> +
> +	timecounter_init(&clock->time_counter, &clock->cycle_counter,
> +			 ktime_to_ns(ktime_get_real()));
> +
> +	clock->clock_rate = ptp_cavium_clock_get();
> +
> +	clock->ptp_info = (struct ptp_clock_info) {
> +		.owner		= THIS_MODULE,
> +		.name		= "ThunderX PTP",
> +		.max_adj	= 1000000000ull,
> +		.n_ext_ts	= 0,
> +		.n_pins		= 0,
> +		.pps		= 0,
> +		.adjfreq	= cavium_ptp_adjfreq,
> +		.adjtime	= cavium_ptp_adjtime,
> +		.gettime64	= cavium_ptp_gettime,
> +		.settime64	= cavium_ptp_settime,
> +		.enable		= cavium_ptp_enable,
> +	};
> +
> +	clock_cfg = readq(clock->reg_base + PTP_CLOCK_CFG);
> +	clock_cfg |= PTP_CLOCK_CFG_PTP_EN;
> +	writeq(clock_cfg, clock->reg_base + PTP_CLOCK_CFG);
> +
> +	clock_comp = ((u64)1000000000ull << 32) / clock->clock_rate;
> +	writeq(clock_comp, clock->reg_base + PTP_CLOCK_COMP);
> +
> +	clock->ptp_clock = ptp_clock_register(&clock->ptp_info, dev);
> +	if (IS_ERR(clock->ptp_clock)) {

You need to handle the case when ptp_clock_register() returns NULL.

from ptp_clock_kernel.h:

/**
 * ptp_clock_register() - register a PTP hardware clock driver
 *
 * @info:   Structure describing the new clock.
 * @parent: Pointer to the parent device of the new clock.
 *
 * Returns a valid pointer on success or PTR_ERR on failure.  If PHC
 * support is missing at the configuration level, this function
 * returns NULL, and drivers are expected to gracefully handle that
 * case separately.
 */

> +		clock_cfg = readq(clock->reg_base + PTP_CLOCK_CFG);
> +		clock_cfg &= ~PTP_CLOCK_CFG_PTP_EN;
> +		writeq(clock_cfg, clock->reg_base + PTP_CLOCK_CFG);
> +		return PTR_ERR(clock->ptp_clock);
> +	}
> +
> +	pci_set_drvdata(pdev, clock);
> +	return 0;
> +}

Thanks,
Richard

^ permalink raw reply


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