Netdev List
 help / color / mirror / Atom feed
* [patch 02/11][NETNS][IPV6] ip6_fib - make the tables per namespace
From: Daniel Lezcano @ 2008-01-25 16:50 UTC (permalink / raw)
  To: davem; +Cc: benjamin.thery, netdev, den
In-Reply-To: <20080125165008.317745745@localhost.localdomain>

[-- Attachment #1: ip6-fib-per-network-namespace.patch --]
[-- Type: text/plain, Size: 14465 bytes --]

The fib table for ipv6 are moved to the network namespace structure.
All references to them are made relatively to the network namespace.

All external calls to the ip6_fib functions taking the network namespace 
parameter are made using the init_net variable, so the ip6_fib engine is
ready for the namespaces but the callers not yet.

Signed-off-by: Daniel Lezcano <dlezcano@fr.ibm.com>
Signed-off-by: Benjamin Thery <benjamin.thery@bull.net>
---
 include/net/ip6_fib.h    |    9 +-
 include/net/netns/ipv6.h |    6 +
 net/ipv6/fib6_rules.c    |    8 +-
 net/ipv6/ip6_fib.c       |  161 +++++++++++++++++++++++++++--------------------
 net/ipv6/route.c         |   22 +++---
 5 files changed, 120 insertions(+), 86 deletions(-)

Index: net-2.6.25/include/net/ip6_fib.h
===================================================================
--- net-2.6.25.orig/include/net/ip6_fib.h
+++ net-2.6.25/include/net/ip6_fib.h
@@ -194,10 +194,11 @@ typedef struct rt6_info *(*pol_lookup_t)
  *	exported functions
  */
 
-extern struct fib6_table *	fib6_get_table(u32 id);
-extern struct fib6_table *	fib6_new_table(u32 id);
-extern struct dst_entry *	fib6_rule_lookup(struct flowi *fl, int flags,
-						 pol_lookup_t lookup);
+extern struct fib6_table        *fib6_get_table(struct net *net, u32 id);
+extern struct fib6_table        *fib6_new_table(struct net *net, u32 id);
+extern struct dst_entry         *fib6_rule_lookup(struct net *net,
+						  struct flowi *fl, int flags,
+						  pol_lookup_t lookup);
 
 extern struct fib6_node		*fib6_lookup(struct fib6_node *root,
 					     struct in6_addr *daddr,
Index: net-2.6.25/include/net/netns/ipv6.h
===================================================================
--- net-2.6.25.orig/include/net/netns/ipv6.h
+++ net-2.6.25/include/net/netns/ipv6.h
@@ -31,5 +31,11 @@ struct netns_ipv6 {
 	struct ipv6_devconf	*devconf_all;
 	struct ipv6_devconf	*devconf_dflt;
 	struct netns_frags	frags;
+
+	struct hlist_head       *fib_table_hash;
+	struct fib6_table       *fib6_main_tbl;
+#ifdef CONFIG_IPV6_MULTIPLE_TABLES
+	struct fib6_table       *fib6_local_tbl;
+#endif
 };
 #endif
Index: net-2.6.25/net/ipv6/fib6_rules.c
===================================================================
--- net-2.6.25.orig/net/ipv6/fib6_rules.c
+++ net-2.6.25/net/ipv6/fib6_rules.c
@@ -31,8 +31,8 @@ struct fib6_rule
 
 static struct fib_rules_ops fib6_rules_ops;
 
-struct dst_entry *fib6_rule_lookup(struct flowi *fl, int flags,
-				   pol_lookup_t lookup)
+struct dst_entry *fib6_rule_lookup(struct net *net, struct flowi *fl,
+				   int flags, pol_lookup_t lookup)
 {
 	struct fib_lookup_arg arg = {
 		.lookup_ptr = lookup,
@@ -71,7 +71,7 @@ static int fib6_rule_action(struct fib_r
 		goto discard_pkt;
 	}
 
-	table = fib6_get_table(rule->table);
+	table = fib6_get_table(&init_net, rule->table);
 	if (table)
 		rt = lookup(table, flp, flags);
 
@@ -151,7 +151,7 @@ static int fib6_rule_configure(struct fi
 		if (rule->table == RT6_TABLE_UNSPEC)
 			goto errout;
 
-		if (fib6_new_table(rule->table) == NULL) {
+		if (fib6_new_table(&init_net, rule->table) == NULL) {
 			err = -ENOBUFS;
 			goto errout;
 		}
Index: net-2.6.25/net/ipv6/ip6_fib.c
===================================================================
--- net-2.6.25.orig/net/ipv6/ip6_fib.c
+++ net-2.6.25/net/ipv6/ip6_fib.c
@@ -166,16 +166,13 @@ static __inline__ void rt6_release(struc
 		dst_free(&rt->u.dst);
 }
 
-static struct fib6_table *fib6_main_tbl;
-
 #ifdef CONFIG_IPV6_MULTIPLE_TABLES
 #define FIB_TABLE_HASHSZ 256
 #else
 #define FIB_TABLE_HASHSZ 1
 #endif
-static struct hlist_head *fib_table_hash;
 
-static void fib6_link_table(struct fib6_table *tb)
+static void fib6_link_table(struct net *net, struct fib6_table *tb)
 {
 	unsigned int h;
 
@@ -191,13 +188,11 @@ static void fib6_link_table(struct fib6_
 	 * No protection necessary, this is the only list mutatation
 	 * operation, tables never disappear once they exist.
 	 */
-	hlist_add_head_rcu(&tb->tb6_hlist, &fib_table_hash[h]);
+	hlist_add_head_rcu(&tb->tb6_hlist, &net->ipv6.fib_table_hash[h]);
 }
 
 #ifdef CONFIG_IPV6_MULTIPLE_TABLES
 
-static struct fib6_table *fib6_local_tbl;
-
 static struct fib6_table *fib6_alloc_table(u32 id)
 {
 	struct fib6_table *table;
@@ -212,26 +207,27 @@ static struct fib6_table *fib6_alloc_tab
 	return table;
 }
 
-struct fib6_table *fib6_new_table(u32 id)
+struct fib6_table *fib6_new_table(struct net *net, u32 id)
 {
 	struct fib6_table *tb;
 
 	if (id == 0)
 		id = RT6_TABLE_MAIN;
-	tb = fib6_get_table(id);
+	tb = fib6_get_table(net, id);
 	if (tb)
 		return tb;
 
 	tb = fib6_alloc_table(id);
 	if (tb != NULL)
-		fib6_link_table(tb);
+		fib6_link_table(net, tb);
 
 	return tb;
 }
 
-struct fib6_table *fib6_get_table(u32 id)
+struct fib6_table *fib6_get_table(struct net *net, u32 id)
 {
 	struct fib6_table *tb;
+	struct hlist_head *head;
 	struct hlist_node *node;
 	unsigned int h;
 
@@ -239,7 +235,8 @@ struct fib6_table *fib6_get_table(u32 id
 		id = RT6_TABLE_MAIN;
 	h = id & (FIB_TABLE_HASHSZ - 1);
 	rcu_read_lock();
-	hlist_for_each_entry_rcu(tb, node, &fib_table_hash[h], tb6_hlist) {
+	head = &net->ipv6.fib_table_hash[h];
+	hlist_for_each_entry_rcu(tb, node, head, tb6_hlist) {
 		if (tb->tb6_id == id) {
 			rcu_read_unlock();
 			return tb;
@@ -250,33 +247,32 @@ struct fib6_table *fib6_get_table(u32 id
 	return NULL;
 }
 
-static void __init fib6_tables_init(void)
+static void fib6_tables_init(struct net *net)
 {
-	fib6_link_table(fib6_main_tbl);
-	fib6_link_table(fib6_local_tbl);
+	fib6_link_table(net, net->ipv6.fib6_main_tbl);
+	fib6_link_table(net, net->ipv6.fib6_local_tbl);
 }
-
 #else
 
-struct fib6_table *fib6_new_table(u32 id)
+struct fib6_table *fib6_new_table(struct net *net, u32 id)
 {
-	return fib6_get_table(id);
+	return fib6_get_table(net, id);
 }
 
-struct fib6_table *fib6_get_table(u32 id)
+struct fib6_table *fib6_get_table(struct net *net, u32 id)
 {
-	return fib6_main_tbl;
+	  return net->ipv6.fib6_main_tbl;
 }
 
-struct dst_entry *fib6_rule_lookup(struct flowi *fl, int flags,
-				   pol_lookup_t lookup)
+struct dst_entry *fib6_rule_lookup(struct net *net, struct flowi *fl,
+				   int flags, pol_lookup_t lookup)
 {
-	return (struct dst_entry *) lookup(fib6_main_tbl, fl, flags);
+	return (struct dst_entry *) lookup(net->ipv6.fib6_main_tbl, fl, flags);
 }
 
-static void __init fib6_tables_init(void)
+static void fib6_tables_init(struct net *net)
 {
-	fib6_link_table(fib6_main_tbl);
+	fib6_link_table(net, net->ipv6.fib6_main_tbl);
 }
 
 #endif
@@ -357,11 +353,9 @@ static int inet6_dump_fib(struct sk_buff
 	struct fib6_walker_t *w;
 	struct fib6_table *tb;
 	struct hlist_node *node;
+	struct hlist_head *head;
 	int res = 0;
 
-	if (net != &init_net)
-		return 0;
-
 	s_h = cb->args[0];
 	s_e = cb->args[1];
 
@@ -390,7 +384,8 @@ static int inet6_dump_fib(struct sk_buff
 
 	for (h = s_h; h < FIB_TABLE_HASHSZ; h++, s_e = 0) {
 		e = 0;
-		hlist_for_each_entry(tb, node, &fib_table_hash[h], tb6_hlist) {
+		head = &net->ipv6.fib_table_hash[h];
+		hlist_for_each_entry(tb, node, head, tb6_hlist) {
 			if (e < s_e)
 				goto next;
 			res = fib6_dump_table(tb, skb, cb);
@@ -1360,12 +1355,13 @@ void fib6_clean_all(int (*func)(struct r
 {
 	struct fib6_table *table;
 	struct hlist_node *node;
+	struct hlist_head *head;
 	unsigned int h;
 
 	rcu_read_lock();
 	for (h = 0; h < FIB_TABLE_HASHSZ; h++) {
-		hlist_for_each_entry_rcu(table, node, &fib_table_hash[h],
-					 tb6_hlist) {
+		head = &init_net.ipv6.fib_table_hash[h];
+		hlist_for_each_entry_rcu(table, node, head, tb6_hlist) {
 			write_lock_bh(&table->tb6_lock);
 			fib6_clean_tree(&table->tb6_root, func, prune, arg);
 			write_unlock_bh(&table->tb6_lock);
@@ -1466,55 +1462,88 @@ void fib6_run_gc(unsigned long dummy)
 	spin_unlock_bh(&fib6_gc_lock);
 }
 
-int __init fib6_init(void)
+static int fib6_net_init(struct net *net)
 {
-	int ret = -ENOMEM;
-	fib6_node_kmem = kmem_cache_create("fib6_nodes",
-					   sizeof(struct fib6_node),
-					   0, SLAB_HWCACHE_ALIGN,
-					   NULL);
-	if (!fib6_node_kmem)
-		goto out;
+	int ret;
 
-	fib_table_hash = kzalloc(sizeof(*fib_table_hash)*FIB_TABLE_HASHSZ,
-				 GFP_KERNEL);
-	if (!fib_table_hash)
-		goto out_kmem_cache_create;
+	ret = -ENOMEM;
+	net->ipv6.fib_table_hash =
+		kzalloc(sizeof(*net->ipv6.fib_table_hash)*FIB_TABLE_HASHSZ,
+			GFP_KERNEL);
+	if (!net->ipv6.fib_table_hash)
+		goto out;
 
-	fib6_main_tbl = kzalloc(sizeof(*fib6_main_tbl), GFP_KERNEL);
-	if (!fib6_main_tbl)
+	net->ipv6.fib6_main_tbl = kzalloc(sizeof(*net->ipv6.fib6_main_tbl),
+					  GFP_KERNEL);
+	if (!net->ipv6.fib6_main_tbl)
 		goto out_fib_table_hash;
 
-	fib6_main_tbl->tb6_id = RT6_TABLE_MAIN;
-	fib6_main_tbl->tb6_root.leaf = &ip6_null_entry;
-	fib6_main_tbl->tb6_root.fn_flags = RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO;
+	net->ipv6.fib6_main_tbl->tb6_id = RT6_TABLE_MAIN;
+	net->ipv6.fib6_main_tbl->tb6_root.leaf = &ip6_null_entry;
+	net->ipv6.fib6_main_tbl->tb6_root.fn_flags =
+		RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO;
 
 #ifdef CONFIG_IPV6_MULTIPLE_TABLES
-	fib6_local_tbl = kzalloc(sizeof(*fib6_local_tbl), GFP_KERNEL);
-	if (!fib6_local_tbl)
+	net->ipv6.fib6_local_tbl = kzalloc(sizeof(*net->ipv6.fib6_local_tbl),
+					   GFP_KERNEL);
+	if (!net->ipv6.fib6_local_tbl)
 		goto out_fib6_main_tbl;
-
-	fib6_local_tbl->tb6_id = RT6_TABLE_LOCAL;
-	fib6_local_tbl->tb6_root.leaf = &ip6_null_entry;
-	fib6_local_tbl->tb6_root.fn_flags = RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO;
+	net->ipv6.fib6_local_tbl->tb6_id = RT6_TABLE_LOCAL;
+	net->ipv6.fib6_local_tbl->tb6_root.leaf = &ip6_null_entry;
+	net->ipv6.fib6_local_tbl->tb6_root.fn_flags =
+		RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO;
 #endif
+	fib6_tables_init(net);
 
-	fib6_tables_init();
-
-	ret = __rtnl_register(PF_INET6, RTM_GETROUTE, NULL, inet6_dump_fib);
-	if (ret)
-		goto out_fib6_local_tbl;
+	ret = 0;
 out:
 	return ret;
 
-out_fib6_local_tbl:
 #ifdef CONFIG_IPV6_MULTIPLE_TABLES
-	kfree(fib6_local_tbl);
 out_fib6_main_tbl:
+	kfree(net->ipv6.fib6_main_tbl);
 #endif
-	kfree(fib6_main_tbl);
 out_fib_table_hash:
-	kfree(fib_table_hash);
+	kfree(net->ipv6.fib_table_hash);
+	goto out;
+ }
+
+static void fib6_net_exit(struct net *net)
+{
+#ifdef CONFIG_IPV6_MULTIPLE_TABLES
+	kfree(net->ipv6.fib6_local_tbl);
+#endif
+	kfree(net->ipv6.fib6_main_tbl);
+	kfree(net->ipv6.fib_table_hash);
+}
+
+static struct pernet_operations fib6_net_ops = {
+	.init = fib6_net_init,
+	.exit = fib6_net_exit,
+};
+
+int __init fib6_init(void)
+{
+	int ret = -ENOMEM;
+	fib6_node_kmem = kmem_cache_create("fib6_nodes",
+					   sizeof(struct fib6_node),
+					   0, SLAB_HWCACHE_ALIGN,
+					   NULL);
+	if (!fib6_node_kmem)
+		goto out;
+
+	ret = register_pernet_subsys(&fib6_net_ops);
+	if (ret)
+		goto out_kmem_cache_create;
+
+	ret = __rtnl_register(PF_INET6, RTM_GETROUTE, NULL, inet6_dump_fib);
+	if (ret)
+		goto out_unregister_subsys;
+out:
+	return ret;
+
+out_unregister_subsys:
+	unregister_pernet_subsys(&fib6_net_ops);
 out_kmem_cache_create:
 	kmem_cache_destroy(fib6_node_kmem);
 	goto out;
@@ -1523,10 +1552,6 @@ out_kmem_cache_create:
 void fib6_gc_cleanup(void)
 {
 	del_timer(&ip6_fib_timer);
-#ifdef CONFIG_IPV6_MULTIPLE_TABLES
-	kfree(fib6_local_tbl);
-#endif
-	kfree(fib6_main_tbl);
-	kfree(fib_table_hash);
+	unregister_pernet_subsys(&fib6_net_ops);
 	kmem_cache_destroy(fib6_node_kmem);
 }
Index: net-2.6.25/net/ipv6/route.c
===================================================================
--- net-2.6.25.orig/net/ipv6/route.c
+++ net-2.6.25/net/ipv6/route.c
@@ -569,7 +569,7 @@ struct rt6_info *rt6_lookup(struct in6_a
 		flags |= RT6_LOOKUP_F_HAS_SADDR;
 	}
 
-	dst = fib6_rule_lookup(&fl, flags, ip6_pol_route_lookup);
+	dst = fib6_rule_lookup(&init_net, &fl, flags, ip6_pol_route_lookup);
 	if (dst->error == 0)
 		return (struct rt6_info *) dst;
 
@@ -756,7 +756,7 @@ void ip6_route_input(struct sk_buff *skb
 	if (rt6_need_strict(&iph->daddr))
 		flags |= RT6_LOOKUP_F_IFACE;
 
-	skb->dst = fib6_rule_lookup(&fl, flags, ip6_pol_route_input);
+	skb->dst = fib6_rule_lookup(&init_net, &fl, flags, ip6_pol_route_input);
 }
 
 static struct rt6_info *ip6_pol_route_output(struct fib6_table *table,
@@ -775,7 +775,7 @@ struct dst_entry * ip6_route_output(stru
 	if (!ipv6_addr_any(&fl->fl6_src))
 		flags |= RT6_LOOKUP_F_HAS_SADDR;
 
-	return fib6_rule_lookup(fl, flags, ip6_pol_route_output);
+	return fib6_rule_lookup(&init_net, fl, flags, ip6_pol_route_output);
 }
 
 EXPORT_SYMBOL(ip6_route_output);
@@ -1068,7 +1068,7 @@ int ip6_route_add(struct fib6_config *cf
 	if (cfg->fc_metric == 0)
 		cfg->fc_metric = IP6_RT_PRIO_USER;
 
-	table = fib6_new_table(cfg->fc_table);
+	table = fib6_new_table(&init_net, cfg->fc_table);
 	if (table == NULL) {
 		err = -ENOBUFS;
 		goto out;
@@ -1274,7 +1274,7 @@ static int ip6_route_del(struct fib6_con
 	struct rt6_info *rt;
 	int err = -ESRCH;
 
-	table = fib6_get_table(cfg->fc_table);
+	table = fib6_get_table(&init_net, cfg->fc_table);
 	if (table == NULL)
 		return err;
 
@@ -1389,7 +1389,9 @@ static struct rt6_info *ip6_route_redire
 	if (rt6_need_strict(dest))
 		flags |= RT6_LOOKUP_F_IFACE;
 
-	return (struct rt6_info *)fib6_rule_lookup((struct flowi *)&rdfl, flags, __ip6_route_redirect);
+	return (struct rt6_info *)fib6_rule_lookup(&init_net,
+						   (struct flowi *)&rdfl,
+						   flags, __ip6_route_redirect);
 }
 
 void rt6_redirect(struct in6_addr *dest, struct in6_addr *src,
@@ -1588,7 +1590,7 @@ static struct rt6_info *rt6_get_route_in
 	struct rt6_info *rt = NULL;
 	struct fib6_table *table;
 
-	table = fib6_get_table(RT6_TABLE_INFO);
+	table = fib6_get_table(&init_net, RT6_TABLE_INFO);
 	if (table == NULL)
 		return NULL;
 
@@ -1643,7 +1645,7 @@ struct rt6_info *rt6_get_dflt_router(str
 	struct rt6_info *rt;
 	struct fib6_table *table;
 
-	table = fib6_get_table(RT6_TABLE_DFLT);
+	table = fib6_get_table(&init_net, RT6_TABLE_DFLT);
 	if (table == NULL)
 		return NULL;
 
@@ -1687,7 +1689,7 @@ void rt6_purge_dflt_routers(void)
 	struct fib6_table *table;
 
 	/* NOTE: Keep consistent with rt6_get_dflt_router */
-	table = fib6_get_table(RT6_TABLE_DFLT);
+	table = fib6_get_table(&init_net, RT6_TABLE_DFLT);
 	if (table == NULL)
 		return;
 
@@ -1848,7 +1850,7 @@ struct rt6_info *addrconf_dst_alloc(stru
 
 	ipv6_addr_copy(&rt->rt6i_dst.addr, addr);
 	rt->rt6i_dst.plen = 128;
-	rt->rt6i_table = fib6_get_table(RT6_TABLE_LOCAL);
+	rt->rt6i_table = fib6_get_table(&init_net, RT6_TABLE_LOCAL);
 
 	atomic_set(&rt->u.dst.__refcnt, 1);
 

-- 

^ permalink raw reply

* [patch 03/11][NETNS][IPV6] ip6_fib - make fib6_clean_all per namespace
From: Daniel Lezcano @ 2008-01-25 16:50 UTC (permalink / raw)
  To: davem; +Cc: benjamin.thery, netdev, den
In-Reply-To: <20080125165008.317745745@localhost.localdomain>

[-- Attachment #1: ip6-fib-make-fib6_clean_all-per-namespace.patch --]
[-- Type: text/plain, Size: 5624 bytes --]

The function fib6_clean_all takes the network namespace
as parameter. That allows to flush the routes related to 
a specific network namespace.

Signed-off-by: Daniel Lezcano <dlezcano@fr.ibm.com>
Signed-off-by: Benjamin Thery <benjamin.thery@bull.net>
---
 include/net/ip6_fib.h   |    3 ++-
 include/net/ip6_route.h |    2 +-
 net/ipv6/addrconf.c     |    3 ++-
 net/ipv6/ip6_fib.c      |    7 ++++---
 net/ipv6/route.c        |   28 ++++++++++++++++++++--------
 5 files changed, 29 insertions(+), 14 deletions(-)

Index: net-2.6.25/include/net/ip6_fib.h
===================================================================
--- net-2.6.25.orig/include/net/ip6_fib.h
+++ net-2.6.25/include/net/ip6_fib.h
@@ -208,7 +208,8 @@ struct fib6_node		*fib6_locate(struct fi
 					     struct in6_addr *daddr, int dst_len,
 					     struct in6_addr *saddr, int src_len);
 
-extern void			fib6_clean_all(int (*func)(struct rt6_info *, void *arg),
+extern void			fib6_clean_all(struct net *net,
+					       int (*func)(struct rt6_info *, void *arg),
 					       int prune, void *arg);
 
 extern int			fib6_add(struct fib6_node *root,
Index: net-2.6.25/net/ipv6/ip6_fib.c
===================================================================
--- net-2.6.25.orig/net/ipv6/ip6_fib.c
+++ net-2.6.25/net/ipv6/ip6_fib.c
@@ -1350,7 +1350,7 @@ static void fib6_clean_tree(struct fib6_
 	fib6_walk(&c.w);
 }
 
-void fib6_clean_all(int (*func)(struct rt6_info *, void *arg),
+void fib6_clean_all(struct net *net, int (*func)(struct rt6_info *, void *arg),
 		    int prune, void *arg)
 {
 	struct fib6_table *table;
@@ -1360,7 +1360,7 @@ void fib6_clean_all(int (*func)(struct r
 
 	rcu_read_lock();
 	for (h = 0; h < FIB_TABLE_HASHSZ; h++) {
-		head = &init_net.ipv6.fib_table_hash[h];
+		head = &net->ipv6.fib_table_hash[h];
 		hlist_for_each_entry_rcu(table, node, head, tb6_hlist) {
 			write_lock_bh(&table->tb6_lock);
 			fib6_clean_tree(&table->tb6_root, func, prune, arg);
@@ -1450,7 +1450,8 @@ void fib6_run_gc(unsigned long dummy)
 	gc_args.more = 0;
 
 	ndisc_dst_gc(&gc_args.more);
-	fib6_clean_all(fib6_age, 0, NULL);
+
+	fib6_clean_all(&init_net, fib6_age, 0, NULL);
 
 	if (gc_args.more)
 		mod_timer(&ip6_fib_timer, jiffies +
Index: net-2.6.25/net/ipv6/route.c
===================================================================
--- net-2.6.25.orig/net/ipv6/route.c
+++ net-2.6.25/net/ipv6/route.c
@@ -1867,9 +1867,9 @@ static int fib6_ifdown(struct rt6_info *
 	return 0;
 }
 
-void rt6_ifdown(struct net_device *dev)
+void rt6_ifdown(struct net *net, struct net_device *dev)
 {
-	fib6_clean_all(fib6_ifdown, 0, dev);
+	fib6_clean_all(net, fib6_ifdown, 0, dev);
 }
 
 struct rt6_mtu_change_arg
@@ -1925,7 +1925,7 @@ void rt6_mtu_change(struct net_device *d
 		.mtu = mtu,
 	};
 
-	fib6_clean_all(rt6_mtu_change_route, 0, &arg);
+	fib6_clean_all(dev->nd_net, rt6_mtu_change_route, 0, &arg);
 }
 
 static const struct nla_policy rtm_ipv6_policy[RTA_MAX+1] = {
@@ -2313,13 +2313,25 @@ static int rt6_info_route(struct rt6_inf
 
 static int ipv6_route_show(struct seq_file *m, void *v)
 {
-	fib6_clean_all(rt6_info_route, 0, m);
+	struct net *net = (struct net *)m->private;
+	fib6_clean_all(net, rt6_info_route, 0, m);
 	return 0;
 }
 
 static int ipv6_route_open(struct inode *inode, struct file *file)
 {
-	return single_open(file, ipv6_route_show, NULL);
+	struct net *net = get_proc_net(inode);
+	if (!net)
+		return -ENXIO;
+	return single_open(file, ipv6_route_show, net);
+}
+
+static int ipv6_route_release(struct inode *inode, struct file *file)
+{
+	struct seq_file *seq = file->private_data;
+	struct net *net = seq->private;
+	put_net(net);
+	return single_release(inode, file);
 }
 
 static const struct file_operations ipv6_route_proc_fops = {
@@ -2327,7 +2339,7 @@ static const struct file_operations ipv6
 	.open		= ipv6_route_open,
 	.read		= seq_read,
 	.llseek		= seq_lseek,
-	.release	= single_release,
+	.release	= ipv6_route_release,
 };
 
 static int rt6_stats_seq_show(struct seq_file *seq, void *v)
@@ -2551,7 +2563,7 @@ xfrm6_init:
 out_proc_init:
 	ipv6_route_proc_fini(&init_net);
 out_fib6_init:
-	rt6_ifdown(NULL);
+	rt6_ifdown(&init_net, NULL);
 	fib6_gc_cleanup();
 out_kmem_cache:
 	kmem_cache_destroy(ip6_dst_ops.kmem_cachep);
@@ -2563,7 +2575,7 @@ void ip6_route_cleanup(void)
 	fib6_rules_cleanup();
 	ipv6_route_proc_fini(&init_net);
 	xfrm6_fini();
-	rt6_ifdown(NULL);
+	rt6_ifdown(&init_net, NULL);
 	fib6_gc_cleanup();
 	kmem_cache_destroy(ip6_dst_ops.kmem_cachep);
 }
Index: net-2.6.25/include/net/ip6_route.h
===================================================================
--- net-2.6.25.orig/include/net/ip6_route.h
+++ net-2.6.25/include/net/ip6_route.h
@@ -123,7 +123,7 @@ struct rt6_rtnl_dump_arg
 };
 
 extern int rt6_dump_route(struct rt6_info *rt, void *p_arg);
-extern void rt6_ifdown(struct net_device *dev);
+extern void rt6_ifdown(struct net *net, struct net_device *dev);
 extern void rt6_mtu_change(struct net_device *dev, unsigned mtu);
 
 extern rwlock_t rt6_lock;
Index: net-2.6.25/net/ipv6/addrconf.c
===================================================================
--- net-2.6.25.orig/net/ipv6/addrconf.c
+++ net-2.6.25/net/ipv6/addrconf.c
@@ -2430,6 +2430,7 @@ static int addrconf_ifdown(struct net_de
 {
 	struct inet6_dev *idev;
 	struct inet6_ifaddr *ifa, **bifa;
+	struct net *net = dev->nd_net;
 	int i;
 
 	ASSERT_RTNL();
@@ -2437,7 +2438,7 @@ static int addrconf_ifdown(struct net_de
 	if (dev == init_net.loopback_dev && how == 1)
 		how = 0;
 
-	rt6_ifdown(dev);
+	rt6_ifdown(net, dev);
 	neigh_ifdown(&nd_tbl, dev);
 
 	idev = __in6_dev_get(dev);

-- 

^ permalink raw reply

* [patch 04/11][NETNS][IPV6] ip6_fib - pass the network namespace parameter to timer callback
From: Daniel Lezcano @ 2008-01-25 16:50 UTC (permalink / raw)
  To: davem; +Cc: benjamin.thery, netdev, den
In-Reply-To: <20080125165008.317745745@localhost.localdomain>

[-- Attachment #1: ip6-fib-add-net-to-gc-timer-parameter.patch --]
[-- Type: text/plain, Size: 5694 bytes --]

The fib tables are now relative to the network namespace. When the 
garbage collector timer expires, we must have a network namespace 
parameter in order to retrieve the tables. For now this is the 
init_net, but we should be able to have a timer per namespace and 
use the timer callback parameter to pass the network namespace from 
the expired timer.

The timer callback, fib6_run_gc, is actually used to be called 
synchronously by some functions and asynchronously when the timer 
expires.

When the timer expires, the delay specified for fib6_run_gc parameter
is always zero. So, I changed fib6_run_gc to not be a timer callback
but a function called by the timer callback and I added a timer callback
where its work is just to retrieve from the data arg of the timer the 
network namespace and call fib6_run_gc with zero expiring time and
the network namespace parameters. That makes the code cleaner for the
fib6_run_gc callers.

Signed-off-by: Daniel Lezcano <dlezcano@fr.ibm.com>
Signed-off-by: Benjamin Thery <benjamin.thery@bull.net>
---
 include/net/ip6_fib.h |    3 ++-
 net/ipv6/ip6_fib.c    |   24 ++++++++++++++++--------
 net/ipv6/ndisc.c      |    5 +++--
 net/ipv6/route.c      |    8 +++++---
 4 files changed, 26 insertions(+), 14 deletions(-)

Index: net-2.6.25/net/ipv6/ip6_fib.c
===================================================================
--- net-2.6.25.orig/net/ipv6/ip6_fib.c
+++ net-2.6.25/net/ipv6/ip6_fib.c
@@ -93,7 +93,10 @@ static int fib6_walk_continue(struct fib
 
 static __u32 rt_sernum;
 
-static DEFINE_TIMER(ip6_fib_timer, fib6_run_gc, 0, 0);
+static void fib6_gc_timer_cb(unsigned long arg);
+
+static DEFINE_TIMER(ip6_fib_timer, fib6_gc_timer_cb, 0,
+		    (unsigned long)&init_net);
 
 static struct fib6_walker_t fib6_walker_list = {
 	.prev	= &fib6_walker_list,
@@ -1432,12 +1435,12 @@ static int fib6_age(struct rt6_info *rt,
 
 static DEFINE_SPINLOCK(fib6_gc_lock);
 
-void fib6_run_gc(unsigned long dummy)
+void fib6_run_gc(unsigned long expires, struct net *net)
 {
-	if (dummy != ~0UL) {
+	if (expires != ~0UL) {
 		spin_lock_bh(&fib6_gc_lock);
-		gc_args.timeout = dummy ? (int)dummy :
-			init_net.ipv6.sysctl.ip6_rt_gc_interval;
+		gc_args.timeout = expires ? (int)expires :
+			net->ipv6.sysctl.ip6_rt_gc_interval;
 	} else {
 		local_bh_disable();
 		if (!spin_trylock(&fib6_gc_lock)) {
@@ -1445,17 +1448,17 @@ void fib6_run_gc(unsigned long dummy)
 			local_bh_enable();
 			return;
 		}
-		gc_args.timeout = init_net.ipv6.sysctl.ip6_rt_gc_interval;
+		gc_args.timeout = net->ipv6.sysctl.ip6_rt_gc_interval;
 	}
 	gc_args.more = 0;
 
 	ndisc_dst_gc(&gc_args.more);
 
-	fib6_clean_all(&init_net, fib6_age, 0, NULL);
+	fib6_clean_all(net, fib6_age, 0, NULL);
 
 	if (gc_args.more)
 		mod_timer(&ip6_fib_timer, jiffies +
-			  init_net.ipv6.sysctl.ip6_rt_gc_interval);
+			  net->ipv6.sysctl.ip6_rt_gc_interval);
 	else {
 		del_timer(&ip6_fib_timer);
 		ip6_fib_timer.expires = 0;
@@ -1463,6 +1466,11 @@ void fib6_run_gc(unsigned long dummy)
 	spin_unlock_bh(&fib6_gc_lock);
 }
 
+static void fib6_gc_timer_cb(unsigned long arg)
+{
+	fib6_run_gc(0, (struct net *)arg);
+}
+
 static int fib6_net_init(struct net *net)
 {
 	int ret;
Index: net-2.6.25/include/net/ip6_fib.h
===================================================================
--- net-2.6.25.orig/include/net/ip6_fib.h
+++ net-2.6.25/include/net/ip6_fib.h
@@ -222,7 +222,8 @@ extern int			fib6_del(struct rt6_info *r
 extern void			inet6_rt_notify(int event, struct rt6_info *rt,
 						struct nl_info *info);
 
-extern void			fib6_run_gc(unsigned long dummy);
+extern void			fib6_run_gc(unsigned long expires,
+					    struct net *net);
 
 extern void			fib6_gc_cleanup(void);
 
Index: net-2.6.25/net/ipv6/ndisc.c
===================================================================
--- net-2.6.25.orig/net/ipv6/ndisc.c
+++ net-2.6.25/net/ipv6/ndisc.c
@@ -1613,6 +1613,7 @@ int ndisc_rcv(struct sk_buff *skb)
 static int ndisc_netdev_event(struct notifier_block *this, unsigned long event, void *ptr)
 {
 	struct net_device *dev = ptr;
+	struct net *net = dev->nd_net;
 
 	if (dev->nd_net != &init_net)
 		return NOTIFY_DONE;
@@ -1620,11 +1621,11 @@ static int ndisc_netdev_event(struct not
 	switch (event) {
 	case NETDEV_CHANGEADDR:
 		neigh_changeaddr(&nd_tbl, dev);
-		fib6_run_gc(~0UL);
+		fib6_run_gc(~0UL, net);
 		break;
 	case NETDEV_DOWN:
 		neigh_ifdown(&nd_tbl, dev);
-		fib6_run_gc(~0UL);
+		fib6_run_gc(~0UL, net);
 		break;
 	default:
 		break;
Index: net-2.6.25/net/ipv6/route.c
===================================================================
--- net-2.6.25.orig/net/ipv6/route.c
+++ net-2.6.25/net/ipv6/route.c
@@ -40,6 +40,7 @@
 #include <linux/if_arp.h>
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
+#include <linux/nsproxy.h>
 #include <net/net_namespace.h>
 #include <net/snmp.h>
 #include <net/ipv6.h>
@@ -994,7 +995,7 @@ static int ip6_dst_gc(struct dst_ops *op
 		goto out;
 
 	expire++;
-	fib6_run_gc(expire);
+	fib6_run_gc(expire, &init_net);
 	last_gc = now;
 	if (atomic_read(&ip6_dst_ops.entries) < ip6_dst_ops.gc_thresh)
 		expire = init_net.ipv6.sysctl.ip6_rt_gc_timeout>>1;
@@ -2408,10 +2409,11 @@ static
 int ipv6_sysctl_rtcache_flush(ctl_table *ctl, int write, struct file * filp,
 			      void __user *buffer, size_t *lenp, loff_t *ppos)
 {
-	int delay = init_net.ipv6.sysctl.flush_delay;
+	struct net *net = current->nsproxy->net_ns;
+	int delay = net->ipv6.sysctl.flush_delay;
 	if (write) {
 		proc_dointvec(ctl, write, filp, buffer, lenp, ppos);
-		fib6_run_gc(delay <= 0 ? ~0UL : (unsigned long)delay);
+		fib6_run_gc(delay <= 0 ? ~0UL : (unsigned long)delay, net);
 		return 0;
 	} else
 		return -EINVAL;

-- 

^ permalink raw reply

* [patch 07/11][NETNS][IPV6] make fib6_clean_node to use the network namespace
From: Daniel Lezcano @ 2008-01-25 16:50 UTC (permalink / raw)
  To: davem; +Cc: benjamin.thery, netdev, den
In-Reply-To: <20080125165008.317745745@localhost.localdomain>

[-- Attachment #1: ip6-fib-clean-node-use-namespace.patch --]
[-- Type: text/plain, Size: 3376 bytes --]

The fib6_clean_node function should have the network namespace
it is working on. The fib6_cleaner_t structure is extended with the
network namespace field to be passed to the fib6_clean_node function.

The different functions calling the fib6_clean_node function are extended
with the netns parameter when needed to propagate the netns pointer.

Signed-off-by: Daniel Lezcano <dlezcano@fr.ibm.com>
---
 net/ipv6/ip6_fib.c |   25 +++++++++++++++----------
 1 file changed, 15 insertions(+), 10 deletions(-)

Index: net-2.6.25/net/ipv6/ip6_fib.c
===================================================================
--- net-2.6.25.orig/net/ipv6/ip6_fib.c
+++ net-2.6.25/net/ipv6/ip6_fib.c
@@ -66,6 +66,7 @@ enum fib_walk_state_t
 struct fib6_cleaner_t
 {
 	struct fib6_walker_t w;
+	struct net *net;
 	int (*func)(struct rt6_info *, void *arg);
 	void *arg;
 };
@@ -78,7 +79,8 @@ static DEFINE_RWLOCK(fib6_walker_lock);
 #define FWS_INIT FWS_L
 #endif
 
-static void fib6_prune_clones(struct fib6_node *fn, struct rt6_info *rt);
+static void fib6_prune_clones(struct net *net, struct fib6_node *fn,
+			      struct rt6_info *rt);
 static struct rt6_info * fib6_find_prefix(struct fib6_node *fn);
 static struct fib6_node * fib6_repair_tree(struct fib6_node *fn);
 static int fib6_walk(struct fib6_walker_t *w);
@@ -762,7 +764,7 @@ int fib6_add(struct fib6_node *root, str
 	if (err == 0) {
 		fib6_start_gc(info->nl_net, rt);
 		if (!(rt->rt6i_flags&RTF_CACHE))
-			fib6_prune_clones(pn, rt);
+			fib6_prune_clones(info->nl_net, pn, rt);
 	}
 
 out:
@@ -1168,7 +1170,7 @@ int fib6_del(struct rt6_info *rt, struct
 			pn = pn->parent;
 		}
 #endif
-		fib6_prune_clones(pn, rt);
+		fib6_prune_clones(info->nl_net, pn, rt);
 	}
 
 	/*
@@ -1298,12 +1300,12 @@ static int fib6_walk(struct fib6_walker_
 
 static int fib6_clean_node(struct fib6_walker_t *w)
 {
-	struct nl_info info = {
-		.nl_net = &init_net,
-	};
 	int res;
 	struct rt6_info *rt;
 	struct fib6_cleaner_t *c = container_of(w, struct fib6_cleaner_t, w);
+	struct nl_info info = {
+		.nl_net = c->net,
+	};
 
 	for (rt = w->leaf; rt; rt = rt->u.dst.rt6_next) {
 		res = c->func(rt, c->arg);
@@ -1335,7 +1337,7 @@ static int fib6_clean_node(struct fib6_w
  *	ignoring pure split nodes) will be scanned.
  */
 
-static void fib6_clean_tree(struct fib6_node *root,
+static void fib6_clean_tree(struct net *net, struct fib6_node *root,
 			    int (*func)(struct rt6_info *, void *arg),
 			    int prune, void *arg)
 {
@@ -1346,6 +1348,7 @@ static void fib6_clean_tree(struct fib6_
 	c.w.prune = prune;
 	c.func = func;
 	c.arg = arg;
+	c.net = net;
 
 	fib6_walk(&c.w);
 }
@@ -1363,7 +1366,8 @@ void fib6_clean_all(struct net *net, int
 		head = &net->ipv6.fib_table_hash[h];
 		hlist_for_each_entry_rcu(table, node, head, tb6_hlist) {
 			write_lock_bh(&table->tb6_lock);
-			fib6_clean_tree(&table->tb6_root, func, prune, arg);
+			fib6_clean_tree(net, &table->tb6_root,
+					func, prune, arg);
 			write_unlock_bh(&table->tb6_lock);
 		}
 	}
@@ -1380,9 +1384,10 @@ static int fib6_prune_clone(struct rt6_i
 	return 0;
 }
 
-static void fib6_prune_clones(struct fib6_node *fn, struct rt6_info *rt)
+static void fib6_prune_clones(struct net *net, struct fib6_node *fn,
+			      struct rt6_info *rt)
 {
-	fib6_clean_tree(fn, fib6_prune_clone, 1, rt);
+	fib6_clean_tree(net, fn, fib6_prune_clone, 1, rt);
 }
 
 /*

-- 

^ permalink raw reply

* [patch 08/11][NETNS][IPV6] fib6_rules - dynamically allocate the fib rules ops
From: Daniel Lezcano @ 2008-01-25 16:50 UTC (permalink / raw)
  To: davem; +Cc: benjamin.thery, netdev, den
In-Reply-To: <20080125165008.317745745@localhost.localdomain>

[-- Attachment #1: fib6-rules-dynamic-allocation.patch --]
[-- Type: text/plain, Size: 2897 bytes --]

The fib6_rules_ops structure is dynamically allocated, so that allows
to make several instances of it per network namespace.

The global static fib6_rules_ops structure is renamed to 
fib6_rules_ops_template in order to quickly memcopy it for the
structure initialization.

Signed-off-by: Daniel Lezcano <dlezcano@fr.ibm.com>
---
 net/ipv6/fib6_rules.c |   26 +++++++++++++++++---------
 1 file changed, 17 insertions(+), 9 deletions(-)

Index: net-2.6.25/net/ipv6/fib6_rules.c
===================================================================
--- net-2.6.25.orig/net/ipv6/fib6_rules.c
+++ net-2.6.25/net/ipv6/fib6_rules.c
@@ -29,7 +29,7 @@ struct fib6_rule
 	u8			tclass;
 };
 
-static struct fib_rules_ops fib6_rules_ops;
+static struct fib_rules_ops *fib6_rules_ops;
 
 struct dst_entry *fib6_rule_lookup(struct net *net, struct flowi *fl,
 				   int flags, pol_lookup_t lookup)
@@ -38,7 +38,7 @@ struct dst_entry *fib6_rule_lookup(struc
 		.lookup_ptr = lookup,
 	};
 
-	fib_rules_lookup(&fib6_rules_ops, fl, flags, &arg);
+	fib_rules_lookup(fib6_rules_ops, fl, flags, &arg);
 	if (arg.rule)
 		fib_rule_put(arg.rule);
 
@@ -234,7 +234,7 @@ static size_t fib6_rule_nlmsg_payload(st
 	       + nla_total_size(16); /* src */
 }
 
-static struct fib_rules_ops fib6_rules_ops = {
+static struct fib_rules_ops fib6_rules_ops_template = {
 	.family			= AF_INET6,
 	.rule_size		= sizeof(struct fib6_rule),
 	.addr_size		= sizeof(struct in6_addr),
@@ -247,7 +247,6 @@ static struct fib_rules_ops fib6_rules_o
 	.nlmsg_payload		= fib6_rule_nlmsg_payload,
 	.nlgroup		= RTNLGRP_IPV6_RULE,
 	.policy			= fib6_rule_policy,
-	.rules_list		= LIST_HEAD_INIT(fib6_rules_ops.rules_list),
 	.owner			= THIS_MODULE,
 	.fro_net		= &init_net,
 };
@@ -256,11 +255,18 @@ static int __init fib6_default_rules_ini
 {
 	int err;
 
-	err = fib_default_rule_add(&fib6_rules_ops, 0,
+	fib6_rules_ops = kmemdup(&fib6_rules_ops_template,
+				 sizeof(*fib6_rules_ops), GFP_KERNEL);
+	if (!fib6_rules_ops)
+		return -ENOMEM;
+
+	INIT_LIST_HEAD(&fib6_rules_ops->rules_list);
+
+	err = fib_default_rule_add(fib6_rules_ops, 0,
 				   RT6_TABLE_LOCAL, FIB_RULE_PERMANENT);
 	if (err < 0)
 		return err;
-	err = fib_default_rule_add(&fib6_rules_ops, 0x7FFE, RT6_TABLE_MAIN, 0);
+	err = fib_default_rule_add(fib6_rules_ops, 0x7FFE, RT6_TABLE_MAIN, 0);
 	if (err < 0)
 		return err;
 	return 0;
@@ -274,18 +280,20 @@ int __init fib6_rules_init(void)
 	if (ret)
 		goto out;
 
-	ret = fib_rules_register(&fib6_rules_ops);
+	ret = fib_rules_register(fib6_rules_ops);
 	if (ret)
 		goto out_default_rules_init;
 out:
 	return ret;
 
 out_default_rules_init:
-	fib_rules_cleanup_ops(&fib6_rules_ops);
+	fib_rules_cleanup_ops(fib6_rules_ops);
+	kfree(fib6_rules_ops);
 	goto out;
 }
 
 void fib6_rules_cleanup(void)
 {
-	fib_rules_unregister(&fib6_rules_ops);
+	fib_rules_unregister(fib6_rules_ops);
+	kfree(fib6_rules_ops);
 }

-- 

^ permalink raw reply

* [patch 06/11][NETNS][IPV6] ip6_fib - make the ip6 fib gc timer per network namespace
From: Daniel Lezcano @ 2008-01-25 16:50 UTC (permalink / raw)
  To: davem; +Cc: benjamin.thery, netdev, den
In-Reply-To: <20080125165008.317745745@localhost.localdomain>

[-- Attachment #1: ip6-fib-gc-timer-per-namespace.patch --]
[-- Type: text/plain, Size: 6564 bytes --]

Move the timer initialization at the network namespace creation
and store the network namespace in the timer argument.

That enables multiple timers (one per network namespace) to do garbage
collecting.

Signed-off-by: Daniel Lezcano <dlezcano@fr.ibm.com>
Signed-off-by: Benjamin Thery <benjamin.thery@bull.net>
---
 include/net/ip6_route.h  |    2 -
 include/net/netns/ipv6.h |    1 
 net/ipv6/ip6_fib.c       |   56 +++++++++++++++++++++++------------------------
 net/ipv6/route.c         |    5 +++-
 4 files changed, 34 insertions(+), 30 deletions(-)

Index: net-2.6.25/net/ipv6/ip6_fib.c
===================================================================
--- net-2.6.25.orig/net/ipv6/ip6_fib.c
+++ net-2.6.25/net/ipv6/ip6_fib.c
@@ -95,8 +95,6 @@ static __u32 rt_sernum;
 
 static void fib6_gc_timer_cb(unsigned long arg);
 
-static struct timer_list *ip6_fib_timer;
-
 static struct fib6_walker_t fib6_walker_list = {
 	.prev	= &fib6_walker_list,
 	.next	= &fib6_walker_list,
@@ -663,19 +661,19 @@ static int fib6_add_rt2node(struct fib6_
 	return 0;
 }
 
-static __inline__ void fib6_start_gc(struct rt6_info *rt)
+static __inline__ void fib6_start_gc(struct net *net, struct rt6_info *rt)
 {
-	if (ip6_fib_timer->expires == 0 &&
+	if (net->ipv6.ip6_fib_timer->expires == 0 &&
 	    (rt->rt6i_flags & (RTF_EXPIRES|RTF_CACHE)))
-		mod_timer(ip6_fib_timer, jiffies +
-			  init_net.ipv6.sysctl.ip6_rt_gc_interval);
+		mod_timer(net->ipv6.ip6_fib_timer, jiffies +
+			  net->ipv6.sysctl.ip6_rt_gc_interval);
 }
 
-void fib6_force_start_gc(void)
+void fib6_force_start_gc(struct net *net)
 {
-	if (ip6_fib_timer->expires == 0)
-		mod_timer(ip6_fib_timer, jiffies +
-			  init_net.ipv6.sysctl.ip6_rt_gc_interval);
+	if (net->ipv6.ip6_fib_timer->expires == 0)
+		mod_timer(net->ipv6.ip6_fib_timer, jiffies +
+			  net->ipv6.sysctl.ip6_rt_gc_interval);
 }
 
 /*
@@ -762,7 +760,7 @@ int fib6_add(struct fib6_node *root, str
 	err = fib6_add_rt2node(fn, rt, info);
 
 	if (err == 0) {
-		fib6_start_gc(rt);
+		fib6_start_gc(info->nl_net, rt);
 		if (!(rt->rt6i_flags&RTF_CACHE))
 			fib6_prune_clones(pn, rt);
 	}
@@ -1443,7 +1441,7 @@ void fib6_run_gc(unsigned long expires, 
 	} else {
 		local_bh_disable();
 		if (!spin_trylock(&fib6_gc_lock)) {
-			mod_timer(ip6_fib_timer, jiffies + HZ);
+			mod_timer(net->ipv6.ip6_fib_timer, jiffies + HZ);
 			local_bh_enable();
 			return;
 		}
@@ -1456,11 +1454,11 @@ void fib6_run_gc(unsigned long expires, 
 	fib6_clean_all(net, fib6_age, 0, NULL);
 
 	if (gc_args.more)
-		mod_timer(ip6_fib_timer, jiffies +
+		mod_timer(net->ipv6.ip6_fib_timer, jiffies +
 			  net->ipv6.sysctl.ip6_rt_gc_interval);
 	else {
-		del_timer(ip6_fib_timer);
-		ip6_fib_timer->expires = 0;
+		del_timer(net->ipv6.ip6_fib_timer);
+		net->ipv6.ip6_fib_timer->expires = 0;
 	}
 	spin_unlock_bh(&fib6_gc_lock);
 }
@@ -1473,13 +1471,21 @@ static void fib6_gc_timer_cb(unsigned lo
 static int fib6_net_init(struct net *net)
 {
 	int ret;
+	struct timer_list *timer;
 
 	ret = -ENOMEM;
+	timer = kzalloc(sizeof(*timer), GFP_KERNEL);
+	if (!timer)
+		goto out;
+
+	setup_timer(timer, fib6_gc_timer_cb, (unsigned long)net);
+	net->ipv6.ip6_fib_timer = timer;
+
 	net->ipv6.fib_table_hash =
 		kzalloc(sizeof(*net->ipv6.fib_table_hash)*FIB_TABLE_HASHSZ,
 			GFP_KERNEL);
 	if (!net->ipv6.fib_table_hash)
-		goto out;
+		goto out_timer;
 
 	net->ipv6.fib6_main_tbl = kzalloc(sizeof(*net->ipv6.fib6_main_tbl),
 					  GFP_KERNEL);
@@ -1513,11 +1519,15 @@ out_fib6_main_tbl:
 #endif
 out_fib_table_hash:
 	kfree(net->ipv6.fib_table_hash);
+out_timer:
+	kfree(timer);
 	goto out;
  }
 
 static void fib6_net_exit(struct net *net)
 {
+	del_timer(net->ipv6.ip6_fib_timer);
+	kfree(net->ipv6.ip6_fib_timer);
 #ifdef CONFIG_IPV6_MULTIPLE_TABLES
 	kfree(net->ipv6.fib6_local_tbl);
 #endif
@@ -1533,6 +1543,7 @@ static struct pernet_operations fib6_net
 int __init fib6_init(void)
 {
 	int ret = -ENOMEM;
+
 	fib6_node_kmem = kmem_cache_create("fib6_nodes",
 					   sizeof(struct fib6_node),
 					   0, SLAB_HWCACHE_ALIGN,
@@ -1540,16 +1551,9 @@ int __init fib6_init(void)
 	if (!fib6_node_kmem)
 		goto out;
 
-	ret = -ENOMEM;
-	ip6_fib_timer = kzalloc(sizeof(*ip6_fib_timer), GFP_KERNEL);
-	if (!ip6_fib_timer)
-		goto out_kmem_cache_create;
-
-	setup_timer(ip6_fib_timer, fib6_gc_timer_cb, (unsigned long)&init_net);
-
 	ret = register_pernet_subsys(&fib6_net_ops);
 	if (ret)
-		goto out_timer;
+		goto out_kmem_cache_create;
 
 	ret = __rtnl_register(PF_INET6, RTM_GETROUTE, NULL, inet6_dump_fib);
 	if (ret)
@@ -1559,8 +1563,6 @@ out:
 
 out_unregister_subsys:
 	unregister_pernet_subsys(&fib6_net_ops);
-out_timer:
-	kfree(ip6_fib_timer);
 out_kmem_cache_create:
 	kmem_cache_destroy(fib6_node_kmem);
 	goto out;
@@ -1568,8 +1570,6 @@ out_kmem_cache_create:
 
 void fib6_gc_cleanup(void)
 {
-	del_timer(ip6_fib_timer);
-	kfree(ip6_fib_timer);
 	unregister_pernet_subsys(&fib6_net_ops);
 	kmem_cache_destroy(fib6_node_kmem);
 }
Index: net-2.6.25/include/net/netns/ipv6.h
===================================================================
--- net-2.6.25.orig/include/net/netns/ipv6.h
+++ net-2.6.25/include/net/netns/ipv6.h
@@ -32,6 +32,7 @@ struct netns_ipv6 {
 	struct ipv6_devconf	*devconf_dflt;
 	struct netns_frags	frags;
 
+	struct timer_list       *ip6_fib_timer;
 	struct hlist_head       *fib_table_hash;
 	struct fib6_table       *fib6_main_tbl;
 #ifdef CONFIG_IPV6_MULTIPLE_TABLES
Index: net-2.6.25/include/net/ip6_route.h
===================================================================
--- net-2.6.25.orig/include/net/ip6_route.h
+++ net-2.6.25/include/net/ip6_route.h
@@ -80,7 +80,7 @@ extern struct dst_entry *ndisc_dst_alloc
 					 struct in6_addr *addr,
 					 int (*output)(struct sk_buff *));
 extern int ndisc_dst_gc(int *more);
-extern void fib6_force_start_gc(void);
+extern void fib6_force_start_gc(struct net *net);
 
 extern struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev,
 					   const struct in6_addr *addr,
Index: net-2.6.25/net/ipv6/route.c
===================================================================
--- net-2.6.25.orig/net/ipv6/route.c
+++ net-2.6.25/net/ipv6/route.c
@@ -951,7 +951,7 @@ struct dst_entry *ndisc_dst_alloc(struct
 	ndisc_dst_gc_list = &rt->u.dst;
 	spin_unlock_bh(&ndisc_lock);
 
-	fib6_force_start_gc();
+	fib6_force_start_gc(dev->nd_net);
 
 out:
 	return &rt->u.dst;
@@ -1229,6 +1229,9 @@ install_route:
 	rt->u.dst.dev = dev;
 	rt->rt6i_idev = idev;
 	rt->rt6i_table = table;
+
+	cfg->fc_nlinfo.nl_net = dev->nd_net;
+
 	return __ip6_ins_rt(rt, &cfg->fc_nlinfo);
 
 out:

-- 

^ permalink raw reply

* [patch 10/11][NETNS][IPV6] rt6_stats - dynamically allocate the rt6_stats
From: Daniel Lezcano @ 2008-01-25 16:50 UTC (permalink / raw)
  To: davem; +Cc: benjamin.thery, netdev, den
In-Reply-To: <20080125165008.317745745@localhost.localdomain>

[-- Attachment #1: rt6-stats-dynamic-allocation.patch --]
[-- Type: text/plain, Size: 3946 bytes --]

This patch allocates the rt6_stats struct dynamically when
the fib6 is initialized. That provides the ability to create
several instances of this structure for the network namespaces.

Signed-off-by: Daniel Lezcano <dlezcano@fr.ibm.com>
Signed-off-by: Benjamin Thery <benjamin.thery@bull.net>
---
 include/net/ipv6.h |    2 +-
 net/ipv6/ip6_fib.c |   22 +++++++++++++++-------
 net/ipv6/route.c   |    8 ++++----
 3 files changed, 20 insertions(+), 12 deletions(-)

Index: net-2.6.25/include/net/ipv6.h
===================================================================
--- net-2.6.25.orig/include/net/ipv6.h
+++ net-2.6.25/include/net/ipv6.h
@@ -604,7 +604,7 @@ extern void ipv6_misc_proc_exit(void);
 extern int snmp6_register_dev(struct inet6_dev *idev);
 extern int snmp6_unregister_dev(struct inet6_dev *idev);
 
-extern struct rt6_statistics rt6_stats;
+extern struct rt6_statistics *rt6_stats;
 #else
 static inline int snmp6_register_dev(struct inet6_dev *idev)
 {
Index: net-2.6.25/net/ipv6/ip6_fib.c
===================================================================
--- net-2.6.25.orig/net/ipv6/ip6_fib.c
+++ net-2.6.25/net/ipv6/ip6_fib.c
@@ -48,7 +48,7 @@
 #define RT6_TRACE(x...) do { ; } while (0)
 #endif
 
-struct rt6_statistics	rt6_stats;
+struct rt6_statistics *rt6_stats;
 
 static struct kmem_cache * fib6_node_kmem __read_mostly;
 
@@ -653,10 +653,10 @@ static int fib6_add_rt2node(struct fib6_
 	rt->rt6i_node = fn;
 	atomic_inc(&rt->rt6i_ref);
 	inet6_rt_notify(RTM_NEWROUTE, rt, info);
-	rt6_stats.fib_rt_entries++;
+	rt6_stats->fib_rt_entries++;
 
 	if ((fn->fn_flags & RTN_RTINFO) == 0) {
-		rt6_stats.fib_route_nodes++;
+		rt6_stats->fib_route_nodes++;
 		fn->fn_flags |= RTN_RTINFO;
 	}
 
@@ -1093,8 +1093,8 @@ static void fib6_del_route(struct fib6_n
 	/* Unlink it */
 	*rtp = rt->u.dst.rt6_next;
 	rt->rt6i_node = NULL;
-	rt6_stats.fib_rt_entries--;
-	rt6_stats.fib_discarded_routes++;
+	rt6_stats->fib_rt_entries--;
+	rt6_stats->fib_discarded_routes++;
 
 	/* Reset round-robin state, if necessary */
 	if (fn->rr_ptr == rt)
@@ -1117,7 +1117,7 @@ static void fib6_del_route(struct fib6_n
 	/* If it was last route, expunge its radix tree node */
 	if (fn->leaf == NULL) {
 		fn->fn_flags &= ~RTN_RTINFO;
-		rt6_stats.fib_route_nodes--;
+		rt6_stats->fib_route_nodes--;
 		fn = fib6_repair_tree(fn);
 	}
 
@@ -1556,9 +1556,14 @@ int __init fib6_init(void)
 	if (!fib6_node_kmem)
 		goto out;
 
+	ret = -ENOMEM;
+	rt6_stats = kzalloc(sizeof(*rt6_stats), GFP_KERNEL);
+	if (!rt6_stats)
+		goto out_kmem_cache_create;
+
 	ret = register_pernet_subsys(&fib6_net_ops);
 	if (ret)
-		goto out_kmem_cache_create;
+		goto out_rt6_stats;
 
 	ret = __rtnl_register(PF_INET6, RTM_GETROUTE, NULL, inet6_dump_fib);
 	if (ret)
@@ -1568,6 +1573,8 @@ out:
 
 out_unregister_subsys:
 	unregister_pernet_subsys(&fib6_net_ops);
+out_rt6_stats:
+	kfree(rt6_stats);
 out_kmem_cache_create:
 	kmem_cache_destroy(fib6_node_kmem);
 	goto out;
@@ -1576,5 +1583,6 @@ out_kmem_cache_create:
 void fib6_gc_cleanup(void)
 {
 	unregister_pernet_subsys(&fib6_net_ops);
+	kfree(rt6_stats);
 	kmem_cache_destroy(fib6_node_kmem);
 }
Index: net-2.6.25/net/ipv6/route.c
===================================================================
--- net-2.6.25.orig/net/ipv6/route.c
+++ net-2.6.25/net/ipv6/route.c
@@ -2349,11 +2349,11 @@ static const struct file_operations ipv6
 static int rt6_stats_seq_show(struct seq_file *seq, void *v)
 {
 	seq_printf(seq, "%04x %04x %04x %04x %04x %04x %04x\n",
-		      rt6_stats.fib_nodes, rt6_stats.fib_route_nodes,
-		      rt6_stats.fib_rt_alloc, rt6_stats.fib_rt_entries,
-		      rt6_stats.fib_rt_cache,
+		      rt6_stats->fib_nodes, rt6_stats->fib_route_nodes,
+		      rt6_stats->fib_rt_alloc, rt6_stats->fib_rt_entries,
+		      rt6_stats->fib_rt_cache,
 		      atomic_read(&ip6_dst_ops.entries),
-		      rt6_stats.fib_discarded_routes);
+		      rt6_stats->fib_discarded_routes);
 
 	return 0;
 }

-- 

^ permalink raw reply

* [patch 05/11][NETNS][IPV6] ip6_fib - dynamically allocate the gc_timer
From: Daniel Lezcano @ 2008-01-25 16:50 UTC (permalink / raw)
  To: davem; +Cc: benjamin.thery, netdev, den
In-Reply-To: <20080125165008.317745745@localhost.localdomain>

[-- Attachment #1: ip6-fib-dynamically-allocate-gc-timer.patch --]
[-- Type: text/plain, Size: 3216 bytes --]

The ip6_fib_timer gc timer is dynamically allocated and initialized in
the ip6 fib init function. There are no more references to a
static global variable. That will allow to make multiple instance
of the garbage collecting timer and make them per namespace.

Signed-off-by: Daniel Lezcano <dlezcano@fr.ibm.com>
Signed-off-by: Benjamin Thery <benjamin.thery@bull.net>
---
 net/ipv6/ip6_fib.c |   33 +++++++++++++++++++++------------
 1 file changed, 21 insertions(+), 12 deletions(-)

Index: net-2.6.25/net/ipv6/ip6_fib.c
===================================================================
--- net-2.6.25.orig/net/ipv6/ip6_fib.c
+++ net-2.6.25/net/ipv6/ip6_fib.c
@@ -95,8 +95,7 @@ static __u32 rt_sernum;
 
 static void fib6_gc_timer_cb(unsigned long arg);
 
-static DEFINE_TIMER(ip6_fib_timer, fib6_gc_timer_cb, 0,
-		    (unsigned long)&init_net);
+static struct timer_list *ip6_fib_timer;
 
 static struct fib6_walker_t fib6_walker_list = {
 	.prev	= &fib6_walker_list,
@@ -666,16 +665,16 @@ static int fib6_add_rt2node(struct fib6_
 
 static __inline__ void fib6_start_gc(struct rt6_info *rt)
 {
-	if (ip6_fib_timer.expires == 0 &&
+	if (ip6_fib_timer->expires == 0 &&
 	    (rt->rt6i_flags & (RTF_EXPIRES|RTF_CACHE)))
-		mod_timer(&ip6_fib_timer, jiffies +
+		mod_timer(ip6_fib_timer, jiffies +
 			  init_net.ipv6.sysctl.ip6_rt_gc_interval);
 }
 
 void fib6_force_start_gc(void)
 {
-	if (ip6_fib_timer.expires == 0)
-		mod_timer(&ip6_fib_timer, jiffies +
+	if (ip6_fib_timer->expires == 0)
+		mod_timer(ip6_fib_timer, jiffies +
 			  init_net.ipv6.sysctl.ip6_rt_gc_interval);
 }
 
@@ -1444,7 +1443,7 @@ void fib6_run_gc(unsigned long expires, 
 	} else {
 		local_bh_disable();
 		if (!spin_trylock(&fib6_gc_lock)) {
-			mod_timer(&ip6_fib_timer, jiffies + HZ);
+			mod_timer(ip6_fib_timer, jiffies + HZ);
 			local_bh_enable();
 			return;
 		}
@@ -1457,11 +1456,11 @@ void fib6_run_gc(unsigned long expires, 
 	fib6_clean_all(net, fib6_age, 0, NULL);
 
 	if (gc_args.more)
-		mod_timer(&ip6_fib_timer, jiffies +
+		mod_timer(ip6_fib_timer, jiffies +
 			  net->ipv6.sysctl.ip6_rt_gc_interval);
 	else {
-		del_timer(&ip6_fib_timer);
-		ip6_fib_timer.expires = 0;
+		del_timer(ip6_fib_timer);
+		ip6_fib_timer->expires = 0;
 	}
 	spin_unlock_bh(&fib6_gc_lock);
 }
@@ -1541,9 +1540,16 @@ int __init fib6_init(void)
 	if (!fib6_node_kmem)
 		goto out;
 
+	ret = -ENOMEM;
+	ip6_fib_timer = kzalloc(sizeof(*ip6_fib_timer), GFP_KERNEL);
+	if (!ip6_fib_timer)
+		goto out_kmem_cache_create;
+
+	setup_timer(ip6_fib_timer, fib6_gc_timer_cb, (unsigned long)&init_net);
+
 	ret = register_pernet_subsys(&fib6_net_ops);
 	if (ret)
-		goto out_kmem_cache_create;
+		goto out_timer;
 
 	ret = __rtnl_register(PF_INET6, RTM_GETROUTE, NULL, inet6_dump_fib);
 	if (ret)
@@ -1553,6 +1559,8 @@ out:
 
 out_unregister_subsys:
 	unregister_pernet_subsys(&fib6_net_ops);
+out_timer:
+	kfree(ip6_fib_timer);
 out_kmem_cache_create:
 	kmem_cache_destroy(fib6_node_kmem);
 	goto out;
@@ -1560,7 +1568,8 @@ out_kmem_cache_create:
 
 void fib6_gc_cleanup(void)
 {
-	del_timer(&ip6_fib_timer);
+	del_timer(ip6_fib_timer);
+	kfree(ip6_fib_timer);
 	unregister_pernet_subsys(&fib6_net_ops);
 	kmem_cache_destroy(fib6_node_kmem);
 }

-- 

^ permalink raw reply

* [patch 11/11][NETNS][IPV6] rt6_stats - make rt6_stats per namespace
From: Daniel Lezcano @ 2008-01-25 16:50 UTC (permalink / raw)
  To: davem; +Cc: benjamin.thery, netdev, den
In-Reply-To: <20080125165008.317745745@localhost.localdomain>

[-- Attachment #1: rt6-stats-per-namespace.patch --]
[-- Type: text/plain, Size: 5759 bytes --]

The rt6_stats is now per namespace with this patch. It is
allocated when a network namespace is created and freed
when the network namespace exits and references are relative
to the network namespace.

Signed-off-by: Benjamin Thery <benjamin.thery@bull.net>
Signed-off-by: Daniel Lezcano <dlezcano@fr.ibm.com>
---
 include/net/ipv6.h       |    1 -
 include/net/netns/ipv6.h |    1 +
 net/ipv6/ip6_fib.c       |   32 +++++++++++++++-----------------
 net/ipv6/route.c         |   12 +++++++-----
 4 files changed, 23 insertions(+), 23 deletions(-)

Index: net-2.6.25/include/net/ipv6.h
===================================================================
--- net-2.6.25.orig/include/net/ipv6.h
+++ net-2.6.25/include/net/ipv6.h
@@ -604,7 +604,6 @@ extern void ipv6_misc_proc_exit(void);
 extern int snmp6_register_dev(struct inet6_dev *idev);
 extern int snmp6_unregister_dev(struct inet6_dev *idev);
 
-extern struct rt6_statistics *rt6_stats;
 #else
 static inline int snmp6_register_dev(struct inet6_dev *idev)
 {
Index: net-2.6.25/net/ipv6/ip6_fib.c
===================================================================
--- net-2.6.25.orig/net/ipv6/ip6_fib.c
+++ net-2.6.25/net/ipv6/ip6_fib.c
@@ -48,8 +48,6 @@
 #define RT6_TRACE(x...) do { ; } while (0)
 #endif
 
-struct rt6_statistics *rt6_stats;
-
 static struct kmem_cache * fib6_node_kmem __read_mostly;
 
 enum fib_walk_state_t
@@ -653,10 +651,10 @@ static int fib6_add_rt2node(struct fib6_
 	rt->rt6i_node = fn;
 	atomic_inc(&rt->rt6i_ref);
 	inet6_rt_notify(RTM_NEWROUTE, rt, info);
-	rt6_stats->fib_rt_entries++;
+	info->nl_net->ipv6.rt6_stats->fib_rt_entries++;
 
 	if ((fn->fn_flags & RTN_RTINFO) == 0) {
-		rt6_stats->fib_route_nodes++;
+		info->nl_net->ipv6.rt6_stats->fib_route_nodes++;
 		fn->fn_flags |= RTN_RTINFO;
 	}
 
@@ -1087,14 +1085,15 @@ static void fib6_del_route(struct fib6_n
 {
 	struct fib6_walker_t *w;
 	struct rt6_info *rt = *rtp;
+	struct net *net = info->nl_net;
 
 	RT6_TRACE("fib6_del_route\n");
 
 	/* Unlink it */
 	*rtp = rt->u.dst.rt6_next;
 	rt->rt6i_node = NULL;
-	rt6_stats->fib_rt_entries--;
-	rt6_stats->fib_discarded_routes++;
+	net->ipv6.rt6_stats->fib_rt_entries--;
+	net->ipv6.rt6_stats->fib_discarded_routes++;
 
 	/* Reset round-robin state, if necessary */
 	if (fn->rr_ptr == rt)
@@ -1117,7 +1116,7 @@ static void fib6_del_route(struct fib6_n
 	/* If it was last route, expunge its radix tree node */
 	if (fn->leaf == NULL) {
 		fn->fn_flags &= ~RTN_RTINFO;
-		rt6_stats->fib_route_nodes--;
+		net->ipv6.rt6_stats->fib_route_nodes--;
 		fn = fib6_repair_tree(fn);
 	}
 
@@ -1486,11 +1485,15 @@ static int fib6_net_init(struct net *net
 	setup_timer(timer, fib6_gc_timer_cb, (unsigned long)net);
 	net->ipv6.ip6_fib_timer = timer;
 
+	net->ipv6.rt6_stats = kzalloc(sizeof(*net->ipv6.rt6_stats), GFP_KERNEL);
+	if (!net->ipv6.rt6_stats)
+		goto out_timer;
+
 	net->ipv6.fib_table_hash =
 		kzalloc(sizeof(*net->ipv6.fib_table_hash)*FIB_TABLE_HASHSZ,
 			GFP_KERNEL);
 	if (!net->ipv6.fib_table_hash)
-		goto out_timer;
+		goto out_rt6_stats;
 
 	net->ipv6.fib6_main_tbl = kzalloc(sizeof(*net->ipv6.fib6_main_tbl),
 					  GFP_KERNEL);
@@ -1524,6 +1527,8 @@ out_fib6_main_tbl:
 #endif
 out_fib_table_hash:
 	kfree(net->ipv6.fib_table_hash);
+out_rt6_stats:
+	kfree(net->ipv6.rt6_stats);
 out_timer:
 	kfree(timer);
 	goto out;
@@ -1538,6 +1543,7 @@ static void fib6_net_exit(struct net *ne
 #endif
 	kfree(net->ipv6.fib6_main_tbl);
 	kfree(net->ipv6.fib_table_hash);
+	kfree(net->ipv6.rt6_stats);
 }
 
 static struct pernet_operations fib6_net_ops = {
@@ -1556,14 +1562,9 @@ int __init fib6_init(void)
 	if (!fib6_node_kmem)
 		goto out;
 
-	ret = -ENOMEM;
-	rt6_stats = kzalloc(sizeof(*rt6_stats), GFP_KERNEL);
-	if (!rt6_stats)
-		goto out_kmem_cache_create;
-
 	ret = register_pernet_subsys(&fib6_net_ops);
 	if (ret)
-		goto out_rt6_stats;
+		goto out_kmem_cache_create;
 
 	ret = __rtnl_register(PF_INET6, RTM_GETROUTE, NULL, inet6_dump_fib);
 	if (ret)
@@ -1573,8 +1574,6 @@ out:
 
 out_unregister_subsys:
 	unregister_pernet_subsys(&fib6_net_ops);
-out_rt6_stats:
-	kfree(rt6_stats);
 out_kmem_cache_create:
 	kmem_cache_destroy(fib6_node_kmem);
 	goto out;
@@ -1583,6 +1582,5 @@ out_kmem_cache_create:
 void fib6_gc_cleanup(void)
 {
 	unregister_pernet_subsys(&fib6_net_ops);
-	kfree(rt6_stats);
 	kmem_cache_destroy(fib6_node_kmem);
 }
Index: net-2.6.25/net/ipv6/route.c
===================================================================
--- net-2.6.25.orig/net/ipv6/route.c
+++ net-2.6.25/net/ipv6/route.c
@@ -2349,11 +2349,13 @@ static const struct file_operations ipv6
 static int rt6_stats_seq_show(struct seq_file *seq, void *v)
 {
 	seq_printf(seq, "%04x %04x %04x %04x %04x %04x %04x\n",
-		      rt6_stats->fib_nodes, rt6_stats->fib_route_nodes,
-		      rt6_stats->fib_rt_alloc, rt6_stats->fib_rt_entries,
-		      rt6_stats->fib_rt_cache,
-		      atomic_read(&ip6_dst_ops.entries),
-		      rt6_stats->fib_discarded_routes);
+		   init_net.ipv6.rt6_stats->fib_nodes,
+		   init_net.ipv6.rt6_stats->fib_route_nodes,
+		   init_net.ipv6.rt6_stats->fib_rt_alloc,
+		   init_net.ipv6.rt6_stats->fib_rt_entries,
+		   init_net.ipv6.rt6_stats->fib_rt_cache,
+		   atomic_read(&ip6_dst_ops.entries),
+		   init_net.ipv6.rt6_stats->fib_discarded_routes);
 
 	return 0;
 }
Index: net-2.6.25/include/net/netns/ipv6.h
===================================================================
--- net-2.6.25.orig/include/net/netns/ipv6.h
+++ net-2.6.25/include/net/netns/ipv6.h
@@ -32,6 +32,7 @@ struct netns_ipv6 {
 	struct ipv6_devconf	*devconf_dflt;
 	struct netns_frags	frags;
 
+	struct rt6_statistics   *rt6_stats;
 	struct timer_list       *ip6_fib_timer;
 	struct hlist_head       *fib_table_hash;
 	struct fib6_table       *fib6_main_tbl;

-- 

^ permalink raw reply

* [patch 09/11][NETNS][IPV6] fib6_rules: make per network namespace
From: Daniel Lezcano @ 2008-01-25 16:50 UTC (permalink / raw)
  To: davem; +Cc: benjamin.thery, netdev, den
In-Reply-To: <20080125165008.317745745@localhost.localdomain>

[-- Attachment #1: fib6-rules-per-network-namespace.patch --]
[-- Type: text/plain, Size: 4708 bytes --]

The fib6_rules_ops is moved to the network namespace structure.
All references are changed to have it relatively to it.

Each time a network namespace is created a new fib6_rules_ops is
allocated, initialized and stored into the network namespace
structure.

The common part of the fib rules is namespace aware, so it is
quite easy to retrieve the network namespace from the rules and use
it in the different callbacks.

Signed-off-by: Daniel Lezcano <dlezcano@fr.ibm.com>
---
 include/net/netns/ipv6.h |    1 
 net/ipv6/fib6_rules.c    |   82 ++++++++++++++++++++++++++---------------------
 2 files changed, 47 insertions(+), 36 deletions(-)

Index: net-2.6.25/include/net/netns/ipv6.h
===================================================================
--- net-2.6.25.orig/include/net/netns/ipv6.h
+++ net-2.6.25/include/net/netns/ipv6.h
@@ -37,6 +37,7 @@ struct netns_ipv6 {
 	struct fib6_table       *fib6_main_tbl;
 #ifdef CONFIG_IPV6_MULTIPLE_TABLES
 	struct fib6_table       *fib6_local_tbl;
+	struct fib_rules_ops    *fib6_rules_ops;
 #endif
 };
 #endif
Index: net-2.6.25/net/ipv6/fib6_rules.c
===================================================================
--- net-2.6.25.orig/net/ipv6/fib6_rules.c
+++ net-2.6.25/net/ipv6/fib6_rules.c
@@ -29,8 +29,6 @@ struct fib6_rule
 	u8			tclass;
 };
 
-static struct fib_rules_ops *fib6_rules_ops;
-
 struct dst_entry *fib6_rule_lookup(struct net *net, struct flowi *fl,
 				   int flags, pol_lookup_t lookup)
 {
@@ -38,7 +36,7 @@ struct dst_entry *fib6_rule_lookup(struc
 		.lookup_ptr = lookup,
 	};
 
-	fib_rules_lookup(fib6_rules_ops, fl, flags, &arg);
+	fib_rules_lookup(net->ipv6.fib6_rules_ops, fl, flags, &arg);
 	if (arg.rule)
 		fib_rule_put(arg.rule);
 
@@ -71,7 +69,7 @@ static int fib6_rule_action(struct fib_r
 		goto discard_pkt;
 	}
 
-	table = fib6_get_table(&init_net, rule->table);
+	table = fib6_get_table(rule->fr_net, rule->table);
 	if (table)
 		rt = lookup(table, flp, flags);
 
@@ -145,13 +143,14 @@ static int fib6_rule_configure(struct fi
 			       struct nlattr **tb)
 {
 	int err = -EINVAL;
+	struct net *net = skb->sk->sk_net;
 	struct fib6_rule *rule6 = (struct fib6_rule *) rule;
 
 	if (rule->action == FR_ACT_TO_TBL) {
 		if (rule->table == RT6_TABLE_UNSPEC)
 			goto errout;
 
-		if (fib6_new_table(&init_net, rule->table) == NULL) {
+		if (fib6_new_table(net, rule->table) == NULL) {
 			err = -ENOBUFS;
 			goto errout;
 		}
@@ -251,49 +250,60 @@ static struct fib_rules_ops fib6_rules_o
 	.fro_net		= &init_net,
 };
 
-static int __init fib6_default_rules_init(void)
+static int fib6_rules_net_init(struct net *net)
 {
-	int err;
+	int err = -ENOMEM;
 
-	fib6_rules_ops = kmemdup(&fib6_rules_ops_template,
-				 sizeof(*fib6_rules_ops), GFP_KERNEL);
-	if (!fib6_rules_ops)
-		return -ENOMEM;
+	net->ipv6.fib6_rules_ops = kmemdup(&fib6_rules_ops_template,
+					   sizeof(*net->ipv6.fib6_rules_ops),
+					   GFP_KERNEL);
+	if (!net->ipv6.fib6_rules_ops)
+		goto out;
 
-	INIT_LIST_HEAD(&fib6_rules_ops->rules_list);
+	net->ipv6.fib6_rules_ops->fro_net = net;
+	INIT_LIST_HEAD(&net->ipv6.fib6_rules_ops->rules_list);
 
-	err = fib_default_rule_add(fib6_rules_ops, 0,
+	err = fib_default_rule_add(net->ipv6.fib6_rules_ops, 0,
 				   RT6_TABLE_LOCAL, FIB_RULE_PERMANENT);
-	if (err < 0)
-		return err;
-	err = fib_default_rule_add(fib6_rules_ops, 0x7FFE, RT6_TABLE_MAIN, 0);
-	if (err < 0)
-		return err;
-	return 0;
+	if (err)
+		goto out_fib6_rules_ops;
+
+	err = fib_default_rule_add(net->ipv6.fib6_rules_ops,
+				   0x7FFE, RT6_TABLE_MAIN, 0);
+	if (err)
+		goto out_fib6_default_rule_add;
+
+	err = fib_rules_register(net->ipv6.fib6_rules_ops);
+	if (err)
+		goto out_fib6_default_rule_add;
+out:
+	return err;
+
+out_fib6_default_rule_add:
+	fib_rules_cleanup_ops(net->ipv6.fib6_rules_ops);
+out_fib6_rules_ops:
+	kfree(net->ipv6.fib6_rules_ops);
+	goto out;
 }
 
-int __init fib6_rules_init(void)
+static void fib6_rules_net_exit(struct net *net)
 {
-	int ret;
-
-	ret = fib6_default_rules_init();
-	if (ret)
-		goto out;
+	fib_rules_unregister(net->ipv6.fib6_rules_ops);
+	kfree(net->ipv6.fib6_rules_ops);
+}
 
-	ret = fib_rules_register(fib6_rules_ops);
-	if (ret)
-		goto out_default_rules_init;
-out:
-	return ret;
+static struct pernet_operations fib6_rules_net_ops = {
+	.init = fib6_rules_net_init,
+	.exit = fib6_rules_net_exit,
+};
 
-out_default_rules_init:
-	fib_rules_cleanup_ops(fib6_rules_ops);
-	kfree(fib6_rules_ops);
-	goto out;
+int __init fib6_rules_init(void)
+{
+	return register_pernet_subsys(&fib6_rules_net_ops);
 }
 
+
 void fib6_rules_cleanup(void)
 {
-	fib_rules_unregister(fib6_rules_ops);
-	kfree(fib6_rules_ops);
+	return unregister_pernet_subsys(&fib6_rules_net_ops);
 }

-- 

^ permalink raw reply

* Re: [PATCH UCC TDM 3/3 ] Modified Documentation to explain dtsentries for TDM driver
From: Scott Wood @ 2008-01-25 18:13 UTC (permalink / raw)
  To: Aggrwal Poonam
  Cc: Gala Kumar, akpm, linux-kernel, netdev, rubini, linuxppc-dev,
	Barkowski Michael, Cutler Richard, Tabi Timur, Kalra Ashish
In-Reply-To: <FBA61160C48B8D438F3323FEFB4EF2C279AFF5@zin33exm24.fsl.freescale.net>

Aggrwal Poonam wrote:
> The device tree already has a brg-frequency  property in qe node which
> is the value of BRGCLK. 

Yes, I'm saying it belongs as brg/clock-frequency. :-)
CPM1/2 already do this.

-Scott

^ permalink raw reply

* Re: [PATCH] fib_trie: rescan if key is lost during dump
From: Jarek Poplawski @ 2008-01-25 19:01 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: David Miller, kaber, netdev
In-Reply-To: <20080125081315.467fad70@deepthought>

On Fri, Jan 25, 2008 at 08:13:15AM -0800, Stephen Hemminger wrote:
...
> 2. RCU is unnecessary here because of use of RTNL.  I am going to defer
>    on this till after #1. That patch is much less important.

Thanks! (I've started to suspect another advanced RCU trick already...)

Jarek P.

^ permalink raw reply

* Re: [PATCH 00/14] RFC: Driver for Wireless RNDIS USB devices.
From: David Brownell @ 2008-01-25 20:08 UTC (permalink / raw)
  To: Jussi Kivilinna; +Cc: linux-wireless, bjd, netdev
In-Reply-To: <1201267224.7266.6.camel@localhost>

On Friday 25 January 2008, Jussi Kivilinna wrote:
> On Thu, 2008-01-24 at 17:19 -0800, David Brownell wrote:
> > > 13. [rndis_host] blacklist known wireless RNDIS devices
> > 
> > That will be a headache over time though ... can't you just
> > let the probe succeed enough to recogize it's wireless (using
> > the media flag) and then bail, so the next driver can try?
> 
> Sure, that works too (but causes a little bit more message flood).

Excess messages can be dealt with, or at worst, ignored.

Thanks.


^ permalink raw reply

* Re: 2.6.24-rc6-mm1
From: Torsten Kaiser @ 2008-01-25 21:06 UTC (permalink / raw)
  To: FUJITA Tomonori
  Cc: tomof, akpm, jarkao2, herbert, linux-kernel, neilb, bfields,
	netdev, tom
In-Reply-To: <20080107151639P.fujita.tomonori@lab.ntt.co.jp>

Sorry for the *really* late answer, but I did not have any time to do
linux things the last weeks. :-(

On Jan 7, 2008 7:16 AM, FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp> wrote:
> On Sun, 6 Jan 2008 21:03:42 +0100
> "Torsten Kaiser" <just.for.lkml@googlemail.com> wrote:
> > On Jan 6, 2008 2:33 PM, FUJITA Tomonori <tomof@acm.org> wrote:
> > > On Sun, 6 Jan 2008 12:35:35 +0100
> > > "Torsten Kaiser" <just.for.lkml@googlemail.com> wrote:
> > > > On Jan 6, 2008 12:23 PM, FUJITA Tomonori <tomof@acm.org> wrote:
> > > > And double using something does fit with the errors I'm seeing...
> > > >
> > > > > Can you try the patch to revert my IOMMU changes?
> > > > >
> > > > > http://www.mail-archive.com/linux-scsi@vger.kernel.org/msg12694.html

-> This is the revert-patch I'm talking about later

> > > > Testing for this bug is a little bit slow, as I'm compiling ~100
> > > > packages trying to trigger it.
> > > > If my current testrun with the patch from
> > > > http://www.mail-archive.com/linux-scsi@vger.kernel.org/msg12702.html
> > > > crashes, I will revert the hole IOMMU changes with above patch and try again.
> > >
> > > Thanks for testing,
> >
> > OK, I'm still testing this, but after 95 completed packages I'm rather
> > certain that reverting the IOMMU changes with this patch fixes my
> > problem.
> > I didn't have time to look more into this, so I can't offer any
> > concrete ideas where the bug is.

Until my last mail from 7. Jan this was true, that I was not able to
crash 2.6.24-rc6-mm1 with above patch.
But after testing 2.6.24-rc7 with only the IOMMU changes applied it
did crash once again.

After looking at the patch that seems rather expected as it only
touches powerpc code.
(I only looked at its diffstat after testing it, so I was not aware of
that fact during testing)

> > If you send more patches, I'm willing to test them, but it might take
> > some more time during the next week.
>
> Can you try 2.6.24-rc7 + the IOMMU changes?
>
> The patches are available at:
>
> http://www.kernel.org/pub/linux/kernel/people/tomo/iommu/
>
> Or if you prefer the git tree:
>
> git://git.kernel.org/pub/scm/linux/kernel/git/tomo/linux-2.6-misc.git iommu-sg-fixes
>
>
>
> I've looked at the changes to GART but they are straightforward and
> don't look wrong...

The resulting 2.6.24-rc7 kernel worked for me. I compiled 146 packages
without a crash.

Today I finally had some time for debugging again and tried the new
2.6.24-rc8-mm1.
The crash is still there, I will report that crash in current thread.

Torsten

^ permalink raw reply

* Re: [PATCH 2/5] [POWERPC][NET] ucc_geth_mii and users: get rid of device_type
From: Kumar Gala @ 2008-01-25 21:20 UTC (permalink / raw)
  To: Anton Vorontsov; +Cc: linuxppc-dev, Jeff Garzik, netdev
In-Reply-To: <20080124154001.GB23246@localhost.localdomain>

On Thu, 24 Jan 2008, Anton Vorontsov wrote:

> device_type property is bogus, thus use proper compatible.
>
> Also change compatible property to "fsl,ucc-mdio".
>
> Per http://ozlabs.org/pipermail/linuxppc-dev/2007-December/048388.html
>
> Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
> ---
>  arch/powerpc/boot/dts/mpc832x_mds.dts |    3 +--
>  arch/powerpc/boot/dts/mpc832x_rdb.dts |    3 +--
>  arch/powerpc/boot/dts/mpc836x_mds.dts |    3 +--
>  arch/powerpc/boot/dts/mpc836x_rdk.dts |    3 +--
>  arch/powerpc/boot/dts/mpc8568mds.dts  |    2 +-
>  drivers/net/ucc_geth_mii.c            |    3 +++
>  6 files changed, 8 insertions(+), 9 deletions(-)
>

applied. (same comment about rdk)

- k

^ permalink raw reply

* [PATCH v3][NET] gen_estimator: faster gen_kill_estimator
From: Jarek Poplawski @ 2008-01-25 22:00 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, slavon, kaber, hadi, shemminger
In-Reply-To: <20080121.162918.148129860.davem@davemloft.net>

On Mon, Jan 21, 2008 at 04:29:18PM -0800, David Miller wrote:
...
> Fix this right, make a structure like:
> 
> struct kernel_gnet_stats_rate_est {
> 	struct gnet_stats_rate_est	est;
> 	void				*gen_estimator;
> }
> 
> And update all the code as needed.

Hi,

Here is a patch which uses this idea, I hope mostly as expected. This
new structure has to replace the older one in most kernel places. I was
uncertain of gnet_stats_copy_rate_est(), the change wasn't necessary here
but could be considered for uniformity reasons. Currently it's unchanged.
Of course, I admit it's not the last version, and any suggestions are
welcomed (including updating to some later version - I see there is some
queue waiting with sched changes).

Regards,
Jarek P.

--------------> (take 3)

gen_kill_estimator() is called during qdisc_destroy() with BHs disabled,
and each time does searching for each list member. This can block soft
interrupts for quite a long time when many classes are used.

This patch changes this by storing pointers to internal gen_estimator
structures. New kernel_gnet_stats_rate_est structure is created for this
as a wrapper around gnet_stats_rate_est being a part of userspace API.
Respectively all callers of gen_estimator functions, and structures used
by them to store rate_est are modified.

This method removes currently possibile registering in gen_estimator the
same structures more than once, but it isn't used after all.

Thanks to David Miller for pointing errors in first versions of this patch
and for suggesting proper solution.


Reported-by: Badalian Vyacheslav <slavon@bigtelecom.ru>
Signed-off-by: Jarek Poplawski <jarkao2@gmail.com>

---

 Documentation/networking/gen_stats.txt |   10 +++--
 include/linux/gen_stats.h              |   13 ++++++
 include/net/act_api.h                  |    4 +-
 include/net/gen_stats.h                |    8 ++--
 include/net/netfilter/xt_rateest.h     |    2 +-
 include/net/sch_generic.h              |    2 +-
 net/core/gen_estimator.c               |   65 ++++++++++++++------------------
 net/netfilter/xt_RATEEST.c             |    4 +-
 net/netfilter/xt_rateest.c             |    4 +-
 net/sched/act_api.c                    |    7 +--
 net/sched/act_police.c                 |    7 +--
 net/sched/sch_api.c                    |    6 +-
 net/sched/sch_cbq.c                    |   10 ++--
 net/sched/sch_generic.c                |    2 +-
 net/sched/sch_hfsc.c                   |   10 ++--
 net/sched/sch_htb.c                    |   12 +++---
 16 files changed, 85 insertions(+), 81 deletions(-)


diff --git a/Documentation/networking/gen_stats.txt b/Documentation/networking/gen_stats.txt
index 70e6275..fc45f94 100644
--- a/Documentation/networking/gen_stats.txt
+++ b/Documentation/networking/gen_stats.txt
@@ -6,10 +6,12 @@ Statistic counters are grouped into structs:
 Struct               TLV type              Description
 ----------------------------------------------------------------------
 gnet_stats_basic     TCA_STATS_BASIC       Basic statistics
-gnet_stats_rate_est  TCA_STATS_RATE_EST    Rate estimator
+gnet_stats_rate_est* TCA_STATS_RATE_EST    Rate estimator
 gnet_stats_queue     TCA_STATS_QUEUE       Queue statistics
 none                 TCA_STATS_APP         Application specific
 
+* From v2.6.25 kernel uses internal struct kernel_gnet_stats_rate_est
+  for gen_estimator functions calls.
 
 Collecting:
 -----------
@@ -106,9 +108,9 @@ In the kernel when setting up:
 From now on, every time you dump my_rate_est_stats it will contain
 up-to-date info.
 
-Once you are done, call gen_kill_estimator(my_basicstats,
-my_rate_est_stats) Make sure that my_basicstats and my_rate_est_stats
-are still valid (i.e still exist) at the time of making this call.
+Once you are done, call gen_kill_estimator(my_rate_est_stats). Make
+sure that my_rate_est_stats is still valid (i.e still exists) at the
+time of making this call.
 
 
 Authors:
diff --git a/include/linux/gen_stats.h b/include/linux/gen_stats.h
index 13f4e74..12b76d2 100644
--- a/include/linux/gen_stats.h
+++ b/include/linux/gen_stats.h
@@ -35,6 +35,19 @@ struct gnet_stats_rate_est
 	__u32	pps;
 };
 
+#ifdef __KERNEL__
+/**
+ * struct kernel_gnet_stats_rate_est - rate estimator wrapper
+ * @est: rate estimator
+ * @gen_estimator: internal data
+ */
+struct kernel_gnet_stats_rate_est
+{
+	struct gnet_stats_rate_est	est;
+	void				*gen_estimator;
+};
+#endif
+
 /**
  * struct gnet_stats_queue - queuing statistics
  * @qlen: queue length
diff --git a/include/net/act_api.h b/include/net/act_api.h
index c5ac61a..c02ce27 100644
--- a/include/net/act_api.h
+++ b/include/net/act_api.h
@@ -18,7 +18,7 @@ struct tcf_common {
 	struct tcf_t			tcfc_tm;
 	struct gnet_stats_basic		tcfc_bstats;
 	struct gnet_stats_queue		tcfc_qstats;
-	struct gnet_stats_rate_est	tcfc_rate_est;
+	struct kernel_gnet_stats_rate_est	tcfc_k_rate_est;
 	spinlock_t			tcfc_lock;
 };
 #define tcf_next	common.tcfc_next
@@ -30,7 +30,7 @@ struct tcf_common {
 #define tcf_tm		common.tcfc_tm
 #define tcf_bstats	common.tcfc_bstats
 #define tcf_qstats	common.tcfc_qstats
-#define tcf_rate_est	common.tcfc_rate_est
+#define tcf_k_rate_est	common.tcfc_k_rate_est
 #define tcf_lock	common.tcfc_lock
 
 struct tcf_police {
diff --git a/include/net/gen_stats.h b/include/net/gen_stats.h
index 8cd8185..af131f6 100644
--- a/include/net/gen_stats.h
+++ b/include/net/gen_stats.h
@@ -38,12 +38,12 @@ extern int gnet_stats_copy_app(struct gnet_dump *d, void *st, int len);
 extern int gnet_stats_finish_copy(struct gnet_dump *d);
 
 extern int gen_new_estimator(struct gnet_stats_basic *bstats,
-			     struct gnet_stats_rate_est *rate_est,
+			     struct kernel_gnet_stats_rate_est *k_rate_est,
 			     spinlock_t *stats_lock, struct nlattr *opt);
-extern void gen_kill_estimator(struct gnet_stats_basic *bstats,
-			       struct gnet_stats_rate_est *rate_est);
+extern void gen_kill_estimator(struct kernel_gnet_stats_rate_est *k_rate_est);
+
 extern int gen_replace_estimator(struct gnet_stats_basic *bstats,
-				 struct gnet_stats_rate_est *rate_est,
+				 struct kernel_gnet_stats_rate_est *k_rate_est,
 				 spinlock_t *stats_lock, struct nlattr *opt);
 
 #endif
diff --git a/include/net/netfilter/xt_rateest.h b/include/net/netfilter/xt_rateest.h
index 65d594d..60aca83 100644
--- a/include/net/netfilter/xt_rateest.h
+++ b/include/net/netfilter/xt_rateest.h
@@ -7,7 +7,7 @@ struct xt_rateest {
 	unsigned int			refcnt;
 	spinlock_t			lock;
 	struct gnet_estimator		params;
-	struct gnet_stats_rate_est	rstats;
+	struct kernel_gnet_stats_rate_est	k_rstats;
 	struct gnet_stats_basic		bstats;
 };
 
diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h
index ab502ec..ea6f5f4 100644
--- a/include/net/sch_generic.h
+++ b/include/net/sch_generic.h
@@ -42,7 +42,7 @@ struct Qdisc
 
 	struct gnet_stats_basic	bstats;
 	struct gnet_stats_queue	qstats;
-	struct gnet_stats_rate_est	rate_est;
+	struct kernel_gnet_stats_rate_est	k_rate_est;
 	spinlock_t		*stats_lock;
 	struct rcu_head 	q_rcu;
 	int			(*reshape_fail)(struct sk_buff *skb,
diff --git a/net/core/gen_estimator.c b/net/core/gen_estimator.c
index 57abe82..986fc84 100644
--- a/net/core/gen_estimator.c
+++ b/net/core/gen_estimator.c
@@ -142,22 +142,23 @@ skip:
 /**
  * gen_new_estimator - create a new rate estimator
  * @bstats: basic statistics
- * @rate_est: rate estimator statistics
+ * @k_rate_est: rate estimator statistics and internal data
  * @stats_lock: statistics lock
  * @opt: rate estimator configuration TLV
  *
- * Creates a new rate estimator with &bstats as source and &rate_est
+ * Creates a new rate estimator with &bstats as source and &k_rate_est->est
  * as destination. A new timer with the interval specified in the
  * configuration TLV is created. Upon each interval, the latest statistics
  * will be read from &bstats and the estimated rate will be stored in
- * &rate_est with the statistics lock grabed during this period.
+ * &k_rate_est->est with the statistics lock grabed during this period.
+ * &k_rate_est also stores internal data required for gen_kill_estimator.
  *
  * Returns 0 on success or a negative error code.
  *
  * NOTE: Called under rtnl_mutex
  */
 int gen_new_estimator(struct gnet_stats_basic *bstats,
-		      struct gnet_stats_rate_est *rate_est,
+		      struct kernel_gnet_stats_rate_est *k_rate_est,
 		      spinlock_t *stats_lock,
 		      struct nlattr *opt)
 {
@@ -172,18 +173,19 @@ int gen_new_estimator(struct gnet_stats_basic *bstats,
 		return -EINVAL;
 
 	est = kzalloc(sizeof(*est), GFP_KERNEL);
+	k_rate_est->gen_estimator = est;
 	if (est == NULL)
 		return -ENOBUFS;
 
 	idx = parm->interval + 2;
 	est->bstats = bstats;
-	est->rate_est = rate_est;
+	est->rate_est = &k_rate_est->est;
 	est->stats_lock = stats_lock;
 	est->ewma_log = parm->ewma_log;
 	est->last_bytes = bstats->bytes;
-	est->avbps = rate_est->bps<<5;
+	est->avbps = k_rate_est->est.bps << 5;
 	est->last_packets = bstats->packets;
-	est->avpps = rate_est->pps<<10;
+	est->avpps = k_rate_est->est.pps << 10;
 
 	if (!elist[idx].timer.function) {
 		INIT_LIST_HEAD(&elist[idx].list);
@@ -206,44 +208,33 @@ static void __gen_kill_estimator(struct rcu_head *head)
 
 /**
  * gen_kill_estimator - remove a rate estimator
- * @bstats: basic statistics
- * @rate_est: rate estimator statistics
+ * @k_rate_est: rate estimator statistics and internal data
  *
- * Removes the rate estimator specified by &bstats and &rate_est
- * and deletes the timer.
+ * Removes the rate estimator specified by &k_rate_est.
  *
  * NOTE: Called under rtnl_mutex
  */
-void gen_kill_estimator(struct gnet_stats_basic *bstats,
-	struct gnet_stats_rate_est *rate_est)
+void gen_kill_estimator(struct kernel_gnet_stats_rate_est *k_rate_est)
 {
-	int idx;
-	struct gen_estimator *e, *n;
-
-	for (idx=0; idx <= EST_MAX_INTERVAL; idx++) {
-
-		/* Skip non initialized indexes */
-		if (!elist[idx].timer.function)
-			continue;
-
-		list_for_each_entry_safe(e, n, &elist[idx].list, list) {
-			if (e->rate_est != rate_est || e->bstats != bstats)
-				continue;
-
-			write_lock_bh(&est_lock);
-			e->bstats = NULL;
-			write_unlock_bh(&est_lock);
-
-			list_del_rcu(&e->list);
-			call_rcu(&e->e_rcu, __gen_kill_estimator);
-		}
+	if (k_rate_est && k_rate_est->gen_estimator) {
+		struct gen_estimator *e;
+		
+		e = (struct gen_estimator *)k_rate_est->gen_estimator;
+		k_rate_est->gen_estimator = NULL;
+
+		write_lock_bh(&est_lock);
+		e->bstats = NULL;
+		write_unlock_bh(&est_lock);
+
+		list_del_rcu(&e->list);
+		call_rcu(&e->e_rcu, __gen_kill_estimator);
 	}
 }
 
 /**
  * gen_replace_estimator - replace rate estimator configuration
  * @bstats: basic statistics
- * @rate_est: rate estimator statistics
+ * @k_rate_est: rate estimator statistics and internal data
  * @stats_lock: statistics lock
  * @opt: rate estimator configuration TLV
  *
@@ -253,11 +244,11 @@ void gen_kill_estimator(struct gnet_stats_basic *bstats,
  * Returns 0 on success or a negative error code.
  */
 int gen_replace_estimator(struct gnet_stats_basic *bstats,
-			  struct gnet_stats_rate_est *rate_est,
+			  struct kernel_gnet_stats_rate_est *k_rate_est,
 			  spinlock_t *stats_lock, struct nlattr *opt)
 {
-	gen_kill_estimator(bstats, rate_est);
-	return gen_new_estimator(bstats, rate_est, stats_lock, opt);
+	gen_kill_estimator(k_rate_est);
+	return gen_new_estimator(bstats, k_rate_est, stats_lock, opt);
 }
 
 
diff --git a/net/netfilter/xt_RATEEST.c b/net/netfilter/xt_RATEEST.c
index 24c73ba..ac5a4ec 100644
--- a/net/netfilter/xt_RATEEST.c
+++ b/net/netfilter/xt_RATEEST.c
@@ -63,7 +63,7 @@ void xt_rateest_put(struct xt_rateest *est)
 	mutex_lock(&xt_rateest_mutex);
 	if (--est->refcnt == 0) {
 		hlist_del(&est->list);
-		gen_kill_estimator(&est->bstats, &est->rstats);
+		gen_kill_estimator(&est->k_rstats);
 		kfree(est);
 	}
 	mutex_unlock(&xt_rateest_mutex);
@@ -134,7 +134,7 @@ xt_rateest_tg_checkentry(const char *tablename,
 	cfg.est.interval	= info->interval;
 	cfg.est.ewma_log	= info->ewma_log;
 
-	if (gen_new_estimator(&est->bstats, &est->rstats, &est->lock,
+	if (gen_new_estimator(&est->bstats, &est->k_rstats, &est->lock,
 			      &cfg.opt) < 0)
 		goto err2;
 
diff --git a/net/netfilter/xt_rateest.c b/net/netfilter/xt_rateest.c
index fdb86a5..e2ba9c7 100644
--- a/net/netfilter/xt_rateest.c
+++ b/net/netfilter/xt_rateest.c
@@ -29,7 +29,7 @@ static bool xt_rateest_mt(const struct sk_buff *skb,
 	bool ret = true;
 
 	spin_lock_bh(&info->est1->lock);
-	r = &info->est1->rstats;
+	r = &info->est1->k_rstats.est;
 	if (info->flags & XT_RATEEST_MATCH_DELTA) {
 		bps1 = info->bps1 >= r->bps ? info->bps1 - r->bps : 0;
 		pps1 = info->pps1 >= r->pps ? info->pps1 - r->pps : 0;
@@ -44,7 +44,7 @@ static bool xt_rateest_mt(const struct sk_buff *skb,
 		pps2 = info->pps2;
 	} else {
 		spin_lock_bh(&info->est2->lock);
-		r = &info->est2->rstats;
+		r = &info->est2->k_rstats.est;
 		if (info->flags & XT_RATEEST_MATCH_DELTA) {
 			bps2 = info->bps2 >= r->bps ? info->bps2 - r->bps : 0;
 			pps2 = info->pps2 >= r->pps ? info->pps2 - r->pps : 0;
diff --git a/net/sched/act_api.c b/net/sched/act_api.c
index ebd21d2..edfb238 100644
--- a/net/sched/act_api.c
+++ b/net/sched/act_api.c
@@ -34,8 +34,7 @@ void tcf_hash_destroy(struct tcf_common *p, struct tcf_hashinfo *hinfo)
 			write_lock_bh(hinfo->lock);
 			*p1p = p->tcfc_next;
 			write_unlock_bh(hinfo->lock);
-			gen_kill_estimator(&p->tcfc_bstats,
-					   &p->tcfc_rate_est);
+			gen_kill_estimator(&p->tcfc_k_rate_est);
 			kfree(p);
 			return;
 		}
@@ -226,7 +225,7 @@ struct tcf_common *tcf_hash_create(u32 index, struct nlattr *est, struct tc_acti
 	p->tcfc_tm.install = jiffies;
 	p->tcfc_tm.lastuse = jiffies;
 	if (est)
-		gen_new_estimator(&p->tcfc_bstats, &p->tcfc_rate_est,
+		gen_new_estimator(&p->tcfc_bstats, &p->tcfc_k_rate_est,
 				  &p->tcfc_lock, est);
 	a->priv = (void *) p;
 	return p;
@@ -605,7 +604,7 @@ int tcf_action_copy_stats(struct sk_buff *skb, struct tc_action *a,
 			goto errout;
 
 	if (gnet_stats_copy_basic(&d, &h->tcf_bstats) < 0 ||
-	    gnet_stats_copy_rate_est(&d, &h->tcf_rate_est) < 0 ||
+	    gnet_stats_copy_rate_est(&d, &h->tcf_k_rate_est.est) < 0 ||
 	    gnet_stats_copy_queue(&d, &h->tcf_qstats) < 0)
 		goto errout;
 
diff --git a/net/sched/act_police.c b/net/sched/act_police.c
index 3af5759..c0ca461 100644
--- a/net/sched/act_police.c
+++ b/net/sched/act_police.c
@@ -105,8 +105,7 @@ static void tcf_police_destroy(struct tcf_police *p)
 			write_lock_bh(&police_lock);
 			*p1p = p->tcf_next;
 			write_unlock_bh(&police_lock);
-			gen_kill_estimator(&p->tcf_bstats,
-					   &p->tcf_rate_est);
+			gen_kill_estimator(&p->tcf_k_rate_est);
 			if (p->tcfp_R_tab)
 				qdisc_put_rtab(p->tcfp_R_tab);
 			if (p->tcfp_P_tab)
@@ -215,7 +214,7 @@ override:
 			*(u32*)nla_data(tb[TCA_POLICE_AVRATE]);
 	if (est)
 		gen_replace_estimator(&police->tcf_bstats,
-				      &police->tcf_rate_est,
+				      &police->tcf_k_rate_est,
 				      &police->tcf_lock, est);
 
 	spin_unlock_bh(&police->tcf_lock);
@@ -272,7 +271,7 @@ static int tcf_act_police(struct sk_buff *skb, struct tc_action *a,
 	police->tcf_bstats.packets++;
 
 	if (police->tcfp_ewma_rate &&
-	    police->tcf_rate_est.bps >= police->tcfp_ewma_rate) {
+	    police->tcf_k_rate_est.est.bps >= police->tcfp_ewma_rate) {
 		police->tcf_qstats.overlimits++;
 		spin_unlock(&police->tcf_lock);
 		return police->tcf_action;
diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c
index 7abb028..87b8113 100644
--- a/net/sched/sch_api.c
+++ b/net/sched/sch_api.c
@@ -511,7 +511,7 @@ qdisc_create(struct net_device *dev, u32 parent, u32 handle,
 
 	if (!ops->init || (err = ops->init(sch, tca[TCA_OPTIONS])) == 0) {
 		if (tca[TCA_RATE]) {
-			err = gen_new_estimator(&sch->bstats, &sch->rate_est,
+			err = gen_new_estimator(&sch->bstats, &sch->k_rate_est,
 						sch->stats_lock,
 						tca[TCA_RATE]);
 			if (err) {
@@ -553,7 +553,7 @@ static int qdisc_change(struct Qdisc *sch, struct nlattr **tca)
 			return err;
 	}
 	if (tca[TCA_RATE])
-		gen_replace_estimator(&sch->bstats, &sch->rate_est,
+		gen_replace_estimator(&sch->bstats, &sch->k_rate_est,
 			sch->stats_lock, tca[TCA_RATE]);
 	return 0;
 }
@@ -847,7 +847,7 @@ static int tc_fill_qdisc(struct sk_buff *skb, struct Qdisc *q, u32 clid,
 		goto nla_put_failure;
 
 	if (gnet_stats_copy_basic(&d, &q->bstats) < 0 ||
-	    gnet_stats_copy_rate_est(&d, &q->rate_est) < 0 ||
+	    gnet_stats_copy_rate_est(&d, &q->k_rate_est.est) < 0 ||
 	    gnet_stats_copy_queue(&d, &q->qstats) < 0)
 		goto nla_put_failure;
 
diff --git a/net/sched/sch_cbq.c b/net/sched/sch_cbq.c
index 5c8667e..cbf24bd 100644
--- a/net/sched/sch_cbq.c
+++ b/net/sched/sch_cbq.c
@@ -131,7 +131,7 @@ struct cbq_class
 	psched_time_t		penalized;
 	struct gnet_stats_basic bstats;
 	struct gnet_stats_queue qstats;
-	struct gnet_stats_rate_est rate_est;
+	struct kernel_gnet_stats_rate_est k_rate_est;
 	struct tc_cbq_xstats	xstats;
 
 	struct tcf_proto	*filter_list;
@@ -1627,7 +1627,7 @@ cbq_dump_class_stats(struct Qdisc *sch, unsigned long arg,
 		cl->xstats.undertime = cl->undertime - q->now;
 
 	if (gnet_stats_copy_basic(d, &cl->bstats) < 0 ||
-	    gnet_stats_copy_rate_est(d, &cl->rate_est) < 0 ||
+	    gnet_stats_copy_rate_est(d, &cl->k_rate_est.est) < 0 ||
 	    gnet_stats_copy_queue(d, &cl->qstats) < 0)
 		return -1;
 
@@ -1698,7 +1698,7 @@ static void cbq_destroy_class(struct Qdisc *sch, struct cbq_class *cl)
 	tcf_destroy_chain(cl->filter_list);
 	qdisc_destroy(cl->q);
 	qdisc_put_rtab(cl->R_tab);
-	gen_kill_estimator(&cl->bstats, &cl->rate_est);
+	gen_kill_estimator(&cl->k_rate_est);
 	if (cl != &q->link)
 		kfree(cl);
 }
@@ -1844,7 +1844,7 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct nlattr **t
 		sch_tree_unlock(sch);
 
 		if (tca[TCA_RATE])
-			gen_replace_estimator(&cl->bstats, &cl->rate_est,
+			gen_replace_estimator(&cl->bstats, &cl->k_rate_est,
 					      &sch->dev->queue_lock,
 					      tca[TCA_RATE]);
 		return 0;
@@ -1932,7 +1932,7 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct nlattr **t
 	sch_tree_unlock(sch);
 
 	if (tca[TCA_RATE])
-		gen_new_estimator(&cl->bstats, &cl->rate_est,
+		gen_new_estimator(&cl->bstats, &cl->k_rate_est,
 				  &sch->dev->queue_lock, tca[TCA_RATE]);
 
 	*arg = (unsigned long)cl;
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c
index 10b5c08..37206e7 100644
--- a/net/sched/sch_generic.c
+++ b/net/sched/sch_generic.c
@@ -509,7 +509,7 @@ void qdisc_destroy(struct Qdisc *qdisc)
 		return;
 
 	list_del(&qdisc->list);
-	gen_kill_estimator(&qdisc->bstats, &qdisc->rate_est);
+	gen_kill_estimator(&qdisc->k_rate_est);
 	if (ops->reset)
 		ops->reset(qdisc);
 	if (ops->destroy)
diff --git a/net/sched/sch_hfsc.c b/net/sched/sch_hfsc.c
index 4e6a164..31b9752 100644
--- a/net/sched/sch_hfsc.c
+++ b/net/sched/sch_hfsc.c
@@ -118,7 +118,7 @@ struct hfsc_class
 
 	struct gnet_stats_basic bstats;
 	struct gnet_stats_queue qstats;
-	struct gnet_stats_rate_est rate_est;
+	struct kernel_gnet_stats_rate_est k_rate_est;
 	unsigned int	level;		/* class level in hierarchy */
 	struct tcf_proto *filter_list;	/* filter list */
 	unsigned int	filter_cnt;	/* filter count */
@@ -1051,7 +1051,7 @@ hfsc_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
 		sch_tree_unlock(sch);
 
 		if (tca[TCA_RATE])
-			gen_replace_estimator(&cl->bstats, &cl->rate_est,
+			gen_replace_estimator(&cl->bstats, &cl->k_rate_est,
 					      &sch->dev->queue_lock,
 					      tca[TCA_RATE]);
 		return 0;
@@ -1107,7 +1107,7 @@ hfsc_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
 	sch_tree_unlock(sch);
 
 	if (tca[TCA_RATE])
-		gen_new_estimator(&cl->bstats, &cl->rate_est,
+		gen_new_estimator(&cl->bstats, &cl->k_rate_est,
 				  &sch->dev->queue_lock, tca[TCA_RATE]);
 	*arg = (unsigned long)cl;
 	return 0;
@@ -1120,7 +1120,7 @@ hfsc_destroy_class(struct Qdisc *sch, struct hfsc_class *cl)
 
 	tcf_destroy_chain(cl->filter_list);
 	qdisc_destroy(cl->qdisc);
-	gen_kill_estimator(&cl->bstats, &cl->rate_est);
+	gen_kill_estimator(&cl->k_rate_est);
 	if (cl != &q->root)
 		kfree(cl);
 }
@@ -1371,7 +1371,7 @@ hfsc_dump_class_stats(struct Qdisc *sch, unsigned long arg,
 	xstats.rtwork  = cl->cl_cumul;
 
 	if (gnet_stats_copy_basic(d, &cl->bstats) < 0 ||
-	    gnet_stats_copy_rate_est(d, &cl->rate_est) < 0 ||
+	    gnet_stats_copy_rate_est(d, &cl->k_rate_est.est) < 0 ||
 	    gnet_stats_copy_queue(d, &cl->qstats) < 0)
 		return -1;
 
diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c
index 3b3ff64..cee8c01 100644
--- a/net/sched/sch_htb.c
+++ b/net/sched/sch_htb.c
@@ -54,7 +54,7 @@
 
 #define HTB_HSIZE 16		/* classid hash size */
 #define HTB_HYSTERESIS 1	/* whether to use mode hysteresis for speedup */
-#define HTB_VER 0x30011		/* major must be matched with number suplied by TC as version */
+#define HTB_VER 0x30012		/* major must be matched with number suplied by TC as version */
 
 #if HTB_VER >> 16 != TC_HTB_PROTOVER
 #error "Mismatched sch_htb.c and pkt_sch.h"
@@ -73,7 +73,7 @@ struct htb_class {
 	u32 classid;
 	struct gnet_stats_basic bstats;
 	struct gnet_stats_queue qstats;
-	struct gnet_stats_rate_est rate_est;
+	struct kernel_gnet_stats_rate_est k_rate_est;
 	struct tc_htb_xstats xstats;	/* our special stats */
 	int refcnt;		/* usage count of this class */
 
@@ -1104,7 +1104,7 @@ htb_dump_class_stats(struct Qdisc *sch, unsigned long arg, struct gnet_dump *d)
 	cl->xstats.ctokens = cl->ctokens;
 
 	if (gnet_stats_copy_basic(d, &cl->bstats) < 0 ||
-	    gnet_stats_copy_rate_est(d, &cl->rate_est) < 0 ||
+	    gnet_stats_copy_rate_est(d, &cl->k_rate_est.est) < 0 ||
 	    gnet_stats_copy_queue(d, &cl->qstats) < 0)
 		return -1;
 
@@ -1195,7 +1195,7 @@ static void htb_destroy_class(struct Qdisc *sch, struct htb_class *cl)
 		BUG_TRAP(cl->un.leaf.q);
 		qdisc_destroy(cl->un.leaf.q);
 	}
-	gen_kill_estimator(&cl->bstats, &cl->rate_est);
+	gen_kill_estimator(&cl->k_rate_est);
 	qdisc_put_rtab(cl->rate);
 	qdisc_put_rtab(cl->ceil);
 
@@ -1348,7 +1348,7 @@ static int htb_change_class(struct Qdisc *sch, u32 classid,
 		if ((cl = kzalloc(sizeof(*cl), GFP_KERNEL)) == NULL)
 			goto failure;
 
-		gen_new_estimator(&cl->bstats, &cl->rate_est,
+		gen_new_estimator(&cl->bstats, &cl->k_rate_est,
 				  &sch->dev->queue_lock,
 				  tca[TCA_RATE] ? : &est.nla);
 		cl->refcnt = 1;
@@ -1404,7 +1404,7 @@ static int htb_change_class(struct Qdisc *sch, u32 classid,
 			      parent ? &parent->children : &q->root);
 	} else {
 		if (tca[TCA_RATE])
-			gen_replace_estimator(&cl->bstats, &cl->rate_est,
+			gen_replace_estimator(&cl->bstats, &cl->k_rate_est,
 					      &sch->dev->queue_lock,
 					      tca[TCA_RATE]);
 		sch_tree_lock(sch);

^ permalink raw reply related

* Re: [Bugme-new] [Bug 9816] New: cannot replace route
From: Andrew Morton @ 2008-01-25 22:26 UTC (permalink / raw)
  To: netdev, Joonwoo Park; +Cc: bugme-daemon, schwab
In-Reply-To: <bug-9816-10286@http.bugzilla.kernel.org/>

> On Fri, 25 Jan 2008 13:23:49 -0800 (PST) bugme-daemon@bugzilla.kernel.org wrote:
> http://bugzilla.kernel.org/show_bug.cgi?id=9816
> 
>            Summary: cannot replace route
>            Product: Networking
>            Version: 2.5
>      KernelVersion: 2.6.24
>           Platform: All
>         OS/Version: Linux
>               Tree: Mainline
>             Status: NEW
>           Severity: normal
>           Priority: P1
>          Component: IPV4
>         AssignedTo: shemminger@linux-foundation.org
>         ReportedBy: schwab@suse.de
> 
> 
> Latest working kernel version: 2.6.24-rc8
> Earliest failing kernel version: 2.6.24
> Distribution: SuSE 10.3
> Hardware Environment: ppc32/ppc64
> Software Environment:
> Problem Description:
> ip route replace always fails with EEXIST.  (del+add still works.)
> 
> Steps to reproduce:
> # ip ro show 127.0.0.0/8
> 127.0.0.0/8 dev lo  scope link 
> # ip ro rep 127.0.0.0/8 dev lo
> RTNETLINK answers: File exists
> 
> Broken by bd566e7525b5986864e8d6eb5b67640abcd284a9.
> 

There is a bit more discussion in the bugzilla writeup.

I'd agree with Andrea: replacing a route with itself a) used to work and b)
should still work (surely)?


^ permalink raw reply

* [PATCH 00/14][v3]: Driver for Wireless RNDIS USB devices.
From: Jussi Kivilinna @ 2008-01-25 22:50 UTC (permalink / raw)
  To: linux-wireless-u79uwXL29TY76Z2rM5mHXA
  Cc: netdev-u79uwXL29TY76Z2rM5mHXA, bjd-a1rhEgazXTw,
	david-b-yBeKhBN/0LDR7s880joybQ

Hello,

Here is the third try on wireless RNDIS patchset.

Patches 1-9 are from second patchset (with name change rndis_wext -> rndis_wlan
in comments where needed):
 1. Fix sparse warning: returning void valued expression
 2. [cdc_ether] Hardwire CDC descriptors when missing
 3. [rndis_host] Use 1KB buffer in rndis_unbind
 4. [rndis_host] Halt device if rndis_bind fails
 5. [rndis_host] Fix rndis packet filter flags
 6. [usbnet] Use wlan device name for RNDIS wireless devices
 7. [rndis_host] Split up rndis_host.c
 8. [rndis_host] export functions
 9. [usbnet] add driver_priv pointer to 'struct usbnet'

Changed patches 10-14:
10. [rndis_host] Add early_init function pointer to 'struct rndis_data'.
11. [rndis_host] Add link_change function pointer to 'struct rndis_data'.
12. [rndis_host] Add RNDIS physical medium checking into generic_rndis_bind()
13. Move usbnet.h and rndis_host.h to include/linux/usb
14. Add new driver 'rndis_wlan' for wireless RNDIS devices.

Devices are now detected by RNDIS physical medium type instead of
vendor/product ids. Driver has new infrastucture/authentication/encryption 
setup code (from ndiswrapper) which fixes issued with WEP and AdHoc. 
List of modes I've tested and work:
 - WEP
 - WPA2 PSK (with CCMP)
 - unencrypted
 - unencrypted ad-hoc
 - hidden unencrypted
 - ad-hoc WEP
 - hidden WEP
That do not work:
 - WPA PSK (with TKIP), I couldn't get this work with Windows driver using
   ndiswrapper and driver from previous patchset and no call were made
   to driver with SIOCSIWENCODEEXT so I'm starting to think problem is with
   the version of wpa_supplicant I have.
 - Hidden WPA, didn't work with earlier driver and as far as I know ndiswrapper
   has the same problem.
Untested:
 - WPA PSK with CCMP
 - WPA2 PSK with TKIP
 - WPA/WPA2 Enterprise

Patches should be applied in order, series apply cleanly to 2.6.24-git1.

 - Jussi Kivilinna

^ permalink raw reply

* [PATCH 01/14] Fix sparse warning: returning void-valued expression
From: Jussi Kivilinna @ 2008-01-25 22:50 UTC (permalink / raw)
  To: linux-wireless-u79uwXL29TY76Z2rM5mHXA
  Cc: netdev-u79uwXL29TY76Z2rM5mHXA, bjd-a1rhEgazXTw,
	david-b-yBeKhBN/0LDR7s880joybQ
In-Reply-To: <20080125225032.11716.77713.stgit-q/85JClnwdg@public.gmane.org>

From: Bjorge Dijkstra <bjd-a1rhEgazXTw@public.gmane.org>

rndis_unbind and usbnet_cdc_unbind don't return anything.

Signed-off-by: Bjorge Dijkstra <bjd-a1rhEgazXTw@public.gmane.org>
Signed-off-by: Jussi Kivilinna <jussi.kivilinna-E01nCVcF24I@public.gmane.org>
---

 drivers/net/usb/rndis_host.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/net/usb/rndis_host.c b/drivers/net/usb/rndis_host.c
index 1ebe325..96ef6a9 100644
--- a/drivers/net/usb/rndis_host.c
+++ b/drivers/net/usb/rndis_host.c
@@ -585,7 +585,7 @@ static void rndis_unbind(struct usbnet *dev, struct usb_interface *intf)
 		kfree(halt);
 	}
 
-	return usbnet_cdc_unbind(dev, intf);
+	usbnet_cdc_unbind(dev, intf);
 }
 
 /*

^ permalink raw reply related

* [PATCH 02/14] [cdc_ether] Hardwire CDC descriptors when missing
From: Jussi Kivilinna @ 2008-01-25 22:50 UTC (permalink / raw)
  To: linux-wireless-u79uwXL29TY76Z2rM5mHXA
  Cc: netdev-u79uwXL29TY76Z2rM5mHXA, bjd-a1rhEgazXTw,
	david-b-yBeKhBN/0LDR7s880joybQ
In-Reply-To: <20080125225032.11716.77713.stgit-q/85JClnwdg@public.gmane.org>

From: Bjorge Dijkstra <bjd-a1rhEgazXTw@public.gmane.org>

Just as ActiveSync devices, some regular RNDIS devices also lack
the CDC descriptors (e.g. devices based on BCM4320 WLAN chip).
This patch hardwires the CDC descriptors for all RNDIS style devices
when they are missing.

Signed-off-by: Bjorge Dijkstra <bjd-a1rhEgazXTw@public.gmane.org>
Signed-off-by: Jussi Kivilinna <jussi.kivilinna-E01nCVcF24I@public.gmane.org>
---

 drivers/net/usb/cdc_ether.c |   10 +++++-----
 1 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c
index a42acc3..97c17bb 100644
--- a/drivers/net/usb/cdc_ether.c
+++ b/drivers/net/usb/cdc_ether.c
@@ -228,15 +228,16 @@ next_desc:
 		buf += buf [0];
 	}
 
-	/* Microsoft ActiveSync based RNDIS devices lack the CDC descriptors,
-	 * so we'll hard-wire the interfaces and not check for descriptors.
+	/* Microsoft ActiveSync based and some regular RNDIS devices lack the
+	 * CDC descriptors, so we'll hard-wire the interfaces and not check
+	 * for descriptors.
 	 */
-	if (is_activesync(&intf->cur_altsetting->desc) && !info->u) {
+	if (rndis && !info->u) {
 		info->control = usb_ifnum_to_if(dev->udev, 0);
 		info->data = usb_ifnum_to_if(dev->udev, 1);
 		if (!info->control || !info->data) {
 			dev_dbg(&intf->dev,
-				"activesync: master #0/%p slave #1/%p\n",
+				"rndis: master #0/%p slave #1/%p\n",
 				info->control,
 				info->data);
 			goto bad_desc;
@@ -316,7 +317,6 @@ void usbnet_cdc_unbind(struct usbnet *dev, struct usb_interface *intf)
 }
 EXPORT_SYMBOL_GPL(usbnet_cdc_unbind);
 
-\f
 /*-------------------------------------------------------------------------
  *
  * Communications Device Class, Ethernet Control model

^ permalink raw reply related

* [PATCH 04/14] [rndis_host] Halt device if rndis_bind fails.
From: Jussi Kivilinna @ 2008-01-25 22:50 UTC (permalink / raw)
  To: linux-wireless-u79uwXL29TY76Z2rM5mHXA
  Cc: netdev-u79uwXL29TY76Z2rM5mHXA, bjd-a1rhEgazXTw,
	david-b-yBeKhBN/0LDR7s880joybQ
In-Reply-To: <20080125225032.11716.77713.stgit-q/85JClnwdg@public.gmane.org>

When bind fails after device was initialized, shutdown device properly
by sending RNDIS_MSG_HALT.

Signed-off-by: Jussi Kivilinna <jussi.kivilinna-E01nCVcF24I@public.gmane.org>
Signed-off-by: Bjorge Dijkstra <bjd-a1rhEgazXTw@public.gmane.org>
---

 drivers/net/usb/rndis_host.c |   12 +++++++++---
 1 files changed, 9 insertions(+), 3 deletions(-)

diff --git a/drivers/net/usb/rndis_host.c b/drivers/net/usb/rndis_host.c
index 42b161c..c686025 100644
--- a/drivers/net/usb/rndis_host.c
+++ b/drivers/net/usb/rndis_host.c
@@ -467,6 +467,7 @@ static int rndis_bind(struct usbnet *dev, struct usb_interface *intf)
 		struct rndis_query_c	*get_c;
 		struct rndis_set	*set;
 		struct rndis_set_c	*set_c;
+		struct rndis_halt	*halt;
 	} u;
 	u32			tmp;
 	int			reply_len;
@@ -517,7 +518,7 @@ static int rndis_bind(struct usbnet *dev, struct usb_interface *intf)
 				"dev can't take %u byte packets (max %u)\n",
 				dev->hard_mtu, tmp);
 			retval = -EINVAL;
-			goto fail_and_release;
+			goto halt_fail_and_release;
 		}
 		dev->hard_mtu = tmp;
 		net->mtu = dev->hard_mtu - net->hard_header_len;
@@ -539,7 +540,7 @@ static int rndis_bind(struct usbnet *dev, struct usb_interface *intf)
 			48, (void **) &bp, &reply_len);
 	if (unlikely(retval< 0)) {
 		dev_err(&intf->dev, "rndis get ethaddr, %d\n", retval);
-		goto fail_and_release;
+		goto halt_fail_and_release;
 	}
 	memcpy(net->dev_addr, bp, ETH_ALEN);
 
@@ -555,7 +556,7 @@ static int rndis_bind(struct usbnet *dev, struct usb_interface *intf)
 	retval = rndis_command(dev, u.header);
 	if (unlikely(retval < 0)) {
 		dev_err(&intf->dev, "rndis set packet filter, %d\n", retval);
-		goto fail_and_release;
+		goto halt_fail_and_release;
 	}
 
 	retval = 0;
@@ -563,6 +564,11 @@ static int rndis_bind(struct usbnet *dev, struct usb_interface *intf)
 	kfree(u.buf);
 	return retval;
 
+halt_fail_and_release:
+	memset(u.halt, 0, sizeof *u.halt);
+	u.halt->msg_type = RNDIS_MSG_HALT;
+	u.halt->msg_len = ccpu2(sizeof *u.halt);
+	(void) rndis_command(dev, (void *)u.halt);
 fail_and_release:
 	usb_set_intfdata(info->data, NULL);
 	usb_driver_release_interface(driver_of(intf), info->data);

^ permalink raw reply related

* [PATCH 03/14] [rndis_host] Use 1KB buffer in rndis_unbind
From: Jussi Kivilinna @ 2008-01-25 22:50 UTC (permalink / raw)
  To: linux-wireless; +Cc: netdev, bjd, david-b
In-Reply-To: <20080125225032.11716.77713.stgit@fate.lan>

rndis_command requires the caller to pass in a buffer of at least 1KB.

Signed-off-by: Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
Signed-off-by: Bjorge Dijkstra <bjd@jooz.net>
---

 drivers/net/usb/rndis_host.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/net/usb/rndis_host.c b/drivers/net/usb/rndis_host.c
index 96ef6a9..42b161c 100644
--- a/drivers/net/usb/rndis_host.c
+++ b/drivers/net/usb/rndis_host.c
@@ -577,7 +577,7 @@ static void rndis_unbind(struct usbnet *dev, struct usb_interface *intf)
 	struct rndis_halt	*halt;
 
 	/* try to clear any rndis state/activity (no i/o from stack!) */
-	halt = kzalloc(sizeof *halt, GFP_KERNEL);
+	halt = kzalloc(CONTROL_BUFFER_SIZE, GFP_KERNEL);
 	if (halt) {
 		halt->msg_type = RNDIS_MSG_HALT;
 		halt->msg_len = ccpu2(sizeof *halt);


^ permalink raw reply related

* [PATCH 06/14] [usbnet] Use wlan device name for RNDIS wireless devices
From: Jussi Kivilinna @ 2008-01-25 22:51 UTC (permalink / raw)
  To: linux-wireless-u79uwXL29TY76Z2rM5mHXA
  Cc: netdev-u79uwXL29TY76Z2rM5mHXA, bjd-a1rhEgazXTw,
	david-b-yBeKhBN/0LDR7s880joybQ
In-Reply-To: <20080125225032.11716.77713.stgit-q/85JClnwdg@public.gmane.org>

Use wlan device name for RNDIS wireless devices.

Signed-off-by: Jussi Kivilinna <jussi.kivilinna-E01nCVcF24I@public.gmane.org>
Signed-off-by: Bjorge Dijkstra <bjd-a1rhEgazXTw@public.gmane.org>
---

 drivers/net/usb/usbnet.c |    3 +++
 drivers/net/usb/usbnet.h |    2 ++
 2 files changed, 5 insertions(+), 0 deletions(-)

diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
index 8ed1fc5..a2a2d5e 100644
--- a/drivers/net/usb/usbnet.c
+++ b/drivers/net/usb/usbnet.c
@@ -1204,6 +1204,9 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
 		if ((dev->driver_info->flags & FLAG_ETHER) != 0
 				&& (net->dev_addr [0] & 0x02) == 0)
 			strcpy (net->name, "eth%d");
+		/* WLAN devices should always be named "wlan%d" */
+		if ((dev->driver_info->flags & FLAG_WLAN) != 0)
+			strcpy(net->name, "wlan%d");
 
 		/* maybe the remote can't receive an Ethernet MTU */
 		if (net->mtu > (dev->hard_mtu - net->hard_header_len))
diff --git a/drivers/net/usb/usbnet.h b/drivers/net/usb/usbnet.h
index 1fae434..29ab92e 100644
--- a/drivers/net/usb/usbnet.h
+++ b/drivers/net/usb/usbnet.h
@@ -87,6 +87,8 @@ struct driver_info {
 #define FLAG_ETHER	0x0020		/* maybe use "eth%d" names */
 
 #define FLAG_FRAMING_AX 0x0040		/* AX88772/178 packets */
+#define FLAG_WLAN	0x0080		/* use "wlan%d" names */
+
 
 	/* init device ... can sleep, or cause probe() failure */
 	int	(*bind)(struct usbnet *, struct usb_interface *);

^ permalink raw reply related

* [PATCH 05/14] [rndis_host] Fix rndis packet filter flags.
From: Jussi Kivilinna @ 2008-01-25 22:51 UTC (permalink / raw)
  To: linux-wireless; +Cc: netdev, bjd, david-b
In-Reply-To: <20080125225032.11716.77713.stgit@fate.lan>

RNDIS packet filter flags are not exactly the same as CDC flags
so we cannot reuse them.

Signed-off-by: Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
Signed-off-by: Bjorge Dijkstra <bjd@jooz.net>
---

 drivers/net/usb/rndis_host.c |   23 ++++++++++++++++++++++-
 1 files changed, 22 insertions(+), 1 deletions(-)

diff --git a/drivers/net/usb/rndis_host.c b/drivers/net/usb/rndis_host.c
index c686025..12daf9c 100644
--- a/drivers/net/usb/rndis_host.c
+++ b/drivers/net/usb/rndis_host.c
@@ -256,6 +256,27 @@ struct rndis_keepalive_c {	/* IN (optionally OUT) */
 #define OID_GEN_MAXIMUM_FRAME_SIZE	ccpu2(0x00010106)
 #define OID_GEN_CURRENT_PACKET_FILTER	ccpu2(0x0001010e)
 
+/* packet filter bits used by OID_GEN_CURRENT_PACKET_FILTER */
+#define RNDIS_PACKET_TYPE_DIRECTED		ccpu2(0x00000001)
+#define RNDIS_PACKET_TYPE_MULTICAST		ccpu2(0x00000002)
+#define RNDIS_PACKET_TYPE_ALL_MULTICAST		ccpu2(0x00000004)
+#define RNDIS_PACKET_TYPE_BROADCAST		ccpu2(0x00000008)
+#define RNDIS_PACKET_TYPE_SOURCE_ROUTING	ccpu2(0x00000010)
+#define RNDIS_PACKET_TYPE_PROMISCUOUS		ccpu2(0x00000020)
+#define RNDIS_PACKET_TYPE_SMT			ccpu2(0x00000040)
+#define RNDIS_PACKET_TYPE_ALL_LOCAL		ccpu2(0x00000080)
+#define RNDIS_PACKET_TYPE_GROUP			ccpu2(0x00001000)
+#define RNDIS_PACKET_TYPE_ALL_FUNCTIONAL	ccpu2(0x00002000)
+#define RNDIS_PACKET_TYPE_FUNCTIONAL		ccpu2(0x00004000)
+#define RNDIS_PACKET_TYPE_MAC_FRAME		ccpu2(0x00008000)
+
+/* default filter used with RNDIS devices */
+#define RNDIS_DEFAULT_FILTER ( \
+	RNDIS_PACKET_TYPE_DIRECTED | \
+	RNDIS_PACKET_TYPE_BROADCAST | \
+	RNDIS_PACKET_TYPE_ALL_MULTICAST | \
+	RNDIS_PACKET_TYPE_PROMISCUOUS)
+
 /*
  * RNDIS notifications from device: command completion; "reverse"
  * keepalives; etc
@@ -551,7 +572,7 @@ static int rndis_bind(struct usbnet *dev, struct usb_interface *intf)
 	u.set->oid = OID_GEN_CURRENT_PACKET_FILTER;
 	u.set->len = ccpu2(4);
 	u.set->offset = ccpu2((sizeof *u.set) - 8);
-	*(__le32 *)(u.buf + sizeof *u.set) = ccpu2(DEFAULT_FILTER);
+	*(__le32 *)(u.buf + sizeof *u.set) = RNDIS_DEFAULT_FILTER;
 
 	retval = rndis_command(dev, u.header);
 	if (unlikely(retval < 0)) {


^ permalink raw reply related

* [PATCH 07/14] [rndis_host] Split up rndis_host.c
From: Jussi Kivilinna @ 2008-01-25 22:51 UTC (permalink / raw)
  To: linux-wireless-u79uwXL29TY76Z2rM5mHXA
  Cc: netdev-u79uwXL29TY76Z2rM5mHXA, bjd-a1rhEgazXTw,
	david-b-yBeKhBN/0LDR7s880joybQ
In-Reply-To: <20080125225032.11716.77713.stgit-q/85JClnwdg@public.gmane.org>

Split up rndis_host.c into rndis_host.h and rndis_base.c. This is done so
that rndis_wlan can reuse common parts with rndis_host.

Signed-off-by: Jussi Kivilinna <jussi.kivilinna-E01nCVcF24I@public.gmane.org>
---

 drivers/net/usb/rndis_host.c |  223 --------------------------------------
 drivers/net/usb/rndis_host.h |  248 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 249 insertions(+), 222 deletions(-)

diff --git a/drivers/net/usb/rndis_host.c b/drivers/net/usb/rndis_host.c
index 12daf9c..29d7e3b 100644
--- a/drivers/net/usb/rndis_host.c
+++ b/drivers/net/usb/rndis_host.c
@@ -31,6 +31,7 @@
 #include <linux/usb/cdc.h>
 
 #include "usbnet.h"
+#include "rndis_host.h"
 
 
 /*
@@ -56,228 +57,6 @@
  */
 
 /*
- * CONTROL uses CDC "encapsulated commands" with funky notifications.
- *  - control-out:  SEND_ENCAPSULATED
- *  - interrupt-in:  RESPONSE_AVAILABLE
- *  - control-in:  GET_ENCAPSULATED
- *
- * We'll try to ignore the RESPONSE_AVAILABLE notifications.
- *
- * REVISIT some RNDIS implementations seem to have curious issues still
- * to be resolved.
- */
-struct rndis_msg_hdr {
-	__le32	msg_type;			/* RNDIS_MSG_* */
-	__le32	msg_len;
-	// followed by data that varies between messages
-	__le32	request_id;
-	__le32	status;
-	// ... and more
-} __attribute__ ((packed));
-
-/* MS-Windows uses this strange size, but RNDIS spec says 1024 minimum */
-#define	CONTROL_BUFFER_SIZE		1025
-
-/* RNDIS defines an (absurdly huge) 10 second control timeout,
- * but ActiveSync seems to use a more usual 5 second timeout
- * (which matches the USB 2.0 spec).
- */
-#define	RNDIS_CONTROL_TIMEOUT_MS	(5 * 1000)
-
-
-#define ccpu2 __constant_cpu_to_le32
-
-#define RNDIS_MSG_COMPLETION	ccpu2(0x80000000)
-
-/* codes for "msg_type" field of rndis messages;
- * only the data channel uses packet messages (maybe batched);
- * everything else goes on the control channel.
- */
-#define RNDIS_MSG_PACKET	ccpu2(0x00000001)	/* 1-N packets */
-#define RNDIS_MSG_INIT		ccpu2(0x00000002)
-#define RNDIS_MSG_INIT_C	(RNDIS_MSG_INIT|RNDIS_MSG_COMPLETION)
-#define RNDIS_MSG_HALT		ccpu2(0x00000003)
-#define RNDIS_MSG_QUERY		ccpu2(0x00000004)
-#define RNDIS_MSG_QUERY_C	(RNDIS_MSG_QUERY|RNDIS_MSG_COMPLETION)
-#define RNDIS_MSG_SET		ccpu2(0x00000005)
-#define RNDIS_MSG_SET_C		(RNDIS_MSG_SET|RNDIS_MSG_COMPLETION)
-#define RNDIS_MSG_RESET		ccpu2(0x00000006)
-#define RNDIS_MSG_RESET_C	(RNDIS_MSG_RESET|RNDIS_MSG_COMPLETION)
-#define RNDIS_MSG_INDICATE	ccpu2(0x00000007)
-#define RNDIS_MSG_KEEPALIVE	ccpu2(0x00000008)
-#define RNDIS_MSG_KEEPALIVE_C	(RNDIS_MSG_KEEPALIVE|RNDIS_MSG_COMPLETION)
-
-/* codes for "status" field of completion messages */
-#define	RNDIS_STATUS_SUCCESS		ccpu2(0x00000000)
-#define	RNDIS_STATUS_FAILURE		ccpu2(0xc0000001)
-#define	RNDIS_STATUS_INVALID_DATA	ccpu2(0xc0010015)
-#define	RNDIS_STATUS_NOT_SUPPORTED	ccpu2(0xc00000bb)
-#define	RNDIS_STATUS_MEDIA_CONNECT	ccpu2(0x4001000b)
-#define	RNDIS_STATUS_MEDIA_DISCONNECT	ccpu2(0x4001000c)
-
-
-struct rndis_data_hdr {
-	__le32	msg_type;		/* RNDIS_MSG_PACKET */
-	__le32	msg_len;		// rndis_data_hdr + data_len + pad
-	__le32	data_offset;		// 36 -- right after header
-	__le32	data_len;		// ... real packet size
-
-	__le32	oob_data_offset;	// zero
-	__le32	oob_data_len;		// zero
-	__le32	num_oob;		// zero
-	__le32	packet_data_offset;	// zero
-
-	__le32	packet_data_len;	// zero
-	__le32	vc_handle;		// zero
-	__le32	reserved;		// zero
-} __attribute__ ((packed));
-
-struct rndis_init {		/* OUT */
-	// header and:
-	__le32	msg_type;			/* RNDIS_MSG_INIT */
-	__le32	msg_len;			// 24
-	__le32	request_id;
-	__le32	major_version;			// of rndis (1.0)
-	__le32	minor_version;
-	__le32	max_transfer_size;
-} __attribute__ ((packed));
-
-struct rndis_init_c {		/* IN */
-	// header and:
-	__le32	msg_type;			/* RNDIS_MSG_INIT_C */
-	__le32	msg_len;
-	__le32	request_id;
-	__le32	status;
-	__le32	major_version;			// of rndis (1.0)
-	__le32	minor_version;
-	__le32	device_flags;
-	__le32	medium;				// zero == 802.3
-	__le32	max_packets_per_message;
-	__le32	max_transfer_size;
-	__le32	packet_alignment;		// max 7; (1<<n) bytes
-	__le32	af_list_offset;			// zero
-	__le32	af_list_size;			// zero
-} __attribute__ ((packed));
-
-struct rndis_halt {		/* OUT (no reply) */
-	// header and:
-	__le32	msg_type;			/* RNDIS_MSG_HALT */
-	__le32	msg_len;
-	__le32	request_id;
-} __attribute__ ((packed));
-
-struct rndis_query {		/* OUT */
-	// header and:
-	__le32	msg_type;			/* RNDIS_MSG_QUERY */
-	__le32	msg_len;
-	__le32	request_id;
-	__le32	oid;
-	__le32	len;
-	__le32	offset;
-/*?*/	__le32	handle;				// zero
-} __attribute__ ((packed));
-
-struct rndis_query_c {		/* IN */
-	// header and:
-	__le32	msg_type;			/* RNDIS_MSG_QUERY_C */
-	__le32	msg_len;
-	__le32	request_id;
-	__le32	status;
-	__le32	len;
-	__le32	offset;
-} __attribute__ ((packed));
-
-struct rndis_set {		/* OUT */
-	// header and:
-	__le32	msg_type;			/* RNDIS_MSG_SET */
-	__le32	msg_len;
-	__le32	request_id;
-	__le32	oid;
-	__le32	len;
-	__le32	offset;
-/*?*/	__le32	handle;				// zero
-} __attribute__ ((packed));
-
-struct rndis_set_c {		/* IN */
-	// header and:
-	__le32	msg_type;			/* RNDIS_MSG_SET_C */
-	__le32	msg_len;
-	__le32	request_id;
-	__le32	status;
-} __attribute__ ((packed));
-
-struct rndis_reset {		/* IN */
-	// header and:
-	__le32	msg_type;			/* RNDIS_MSG_RESET */
-	__le32	msg_len;
-	__le32	reserved;
-} __attribute__ ((packed));
-
-struct rndis_reset_c {		/* OUT */
-	// header and:
-	__le32	msg_type;			/* RNDIS_MSG_RESET_C */
-	__le32	msg_len;
-	__le32	status;
-	__le32	addressing_lost;
-} __attribute__ ((packed));
-
-struct rndis_indicate {		/* IN (unrequested) */
-	// header and:
-	__le32	msg_type;			/* RNDIS_MSG_INDICATE */
-	__le32	msg_len;
-	__le32	status;
-	__le32	length;
-	__le32	offset;
-/**/	__le32	diag_status;
-	__le32	error_offset;
-/**/	__le32	message;
-} __attribute__ ((packed));
-
-struct rndis_keepalive {	/* OUT (optionally IN) */
-	// header and:
-	__le32	msg_type;			/* RNDIS_MSG_KEEPALIVE */
-	__le32	msg_len;
-	__le32	request_id;
-} __attribute__ ((packed));
-
-struct rndis_keepalive_c {	/* IN (optionally OUT) */
-	// header and:
-	__le32	msg_type;			/* RNDIS_MSG_KEEPALIVE_C */
-	__le32	msg_len;
-	__le32	request_id;
-	__le32	status;
-} __attribute__ ((packed));
-
-/* NOTE:  about 30 OIDs are "mandatory" for peripherals to support ... and
- * there are gobs more that may optionally be supported.  We'll avoid as much
- * of that mess as possible.
- */
-#define OID_802_3_PERMANENT_ADDRESS	ccpu2(0x01010101)
-#define OID_GEN_MAXIMUM_FRAME_SIZE	ccpu2(0x00010106)
-#define OID_GEN_CURRENT_PACKET_FILTER	ccpu2(0x0001010e)
-
-/* packet filter bits used by OID_GEN_CURRENT_PACKET_FILTER */
-#define RNDIS_PACKET_TYPE_DIRECTED		ccpu2(0x00000001)
-#define RNDIS_PACKET_TYPE_MULTICAST		ccpu2(0x00000002)
-#define RNDIS_PACKET_TYPE_ALL_MULTICAST		ccpu2(0x00000004)
-#define RNDIS_PACKET_TYPE_BROADCAST		ccpu2(0x00000008)
-#define RNDIS_PACKET_TYPE_SOURCE_ROUTING	ccpu2(0x00000010)
-#define RNDIS_PACKET_TYPE_PROMISCUOUS		ccpu2(0x00000020)
-#define RNDIS_PACKET_TYPE_SMT			ccpu2(0x00000040)
-#define RNDIS_PACKET_TYPE_ALL_LOCAL		ccpu2(0x00000080)
-#define RNDIS_PACKET_TYPE_GROUP			ccpu2(0x00001000)
-#define RNDIS_PACKET_TYPE_ALL_FUNCTIONAL	ccpu2(0x00002000)
-#define RNDIS_PACKET_TYPE_FUNCTIONAL		ccpu2(0x00004000)
-#define RNDIS_PACKET_TYPE_MAC_FRAME		ccpu2(0x00008000)
-
-/* default filter used with RNDIS devices */
-#define RNDIS_DEFAULT_FILTER ( \
-	RNDIS_PACKET_TYPE_DIRECTED | \
-	RNDIS_PACKET_TYPE_BROADCAST | \
-	RNDIS_PACKET_TYPE_ALL_MULTICAST | \
-	RNDIS_PACKET_TYPE_PROMISCUOUS)
-
-/*
  * RNDIS notifications from device: command completion; "reverse"
  * keepalives; etc
  */
diff --git a/drivers/net/usb/rndis_host.h b/drivers/net/usb/rndis_host.h
new file mode 100644
index 0000000..1386a17
--- /dev/null
+++ b/drivers/net/usb/rndis_host.h
@@ -0,0 +1,248 @@
+/*
+ * Host Side support for RNDIS Networking Links
+ * Copyright (C) 2005 by David Brownell
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+
+#ifndef	__RNDIS_HOST_H
+#define	__RNDIS_HOST_H
+
+
+/*
+ * CONTROL uses CDC "encapsulated commands" with funky notifications.
+ *  - control-out:  SEND_ENCAPSULATED
+ *  - interrupt-in:  RESPONSE_AVAILABLE
+ *  - control-in:  GET_ENCAPSULATED
+ *
+ * We'll try to ignore the RESPONSE_AVAILABLE notifications.
+ *
+ * REVISIT some RNDIS implementations seem to have curious issues still
+ * to be resolved.
+ */
+struct rndis_msg_hdr {
+	__le32	msg_type;			/* RNDIS_MSG_* */
+	__le32	msg_len;
+	// followed by data that varies between messages
+	__le32	request_id;
+	__le32	status;
+	// ... and more
+} __attribute__ ((packed));
+
+/* MS-Windows uses this strange size, but RNDIS spec says 1024 minimum */
+#define	CONTROL_BUFFER_SIZE		1025
+
+/* RNDIS defines an (absurdly huge) 10 second control timeout,
+ * but ActiveSync seems to use a more usual 5 second timeout
+ * (which matches the USB 2.0 spec).
+ */
+#define	RNDIS_CONTROL_TIMEOUT_MS	(5 * 1000)
+
+
+#define ccpu2 __constant_cpu_to_le32
+
+#define RNDIS_MSG_COMPLETION	ccpu2(0x80000000)
+
+/* codes for "msg_type" field of rndis messages;
+ * only the data channel uses packet messages (maybe batched);
+ * everything else goes on the control channel.
+ */
+#define RNDIS_MSG_PACKET	ccpu2(0x00000001)	/* 1-N packets */
+#define RNDIS_MSG_INIT		ccpu2(0x00000002)
+#define RNDIS_MSG_INIT_C	(RNDIS_MSG_INIT|RNDIS_MSG_COMPLETION)
+#define RNDIS_MSG_HALT		ccpu2(0x00000003)
+#define RNDIS_MSG_QUERY		ccpu2(0x00000004)
+#define RNDIS_MSG_QUERY_C	(RNDIS_MSG_QUERY|RNDIS_MSG_COMPLETION)
+#define RNDIS_MSG_SET		ccpu2(0x00000005)
+#define RNDIS_MSG_SET_C		(RNDIS_MSG_SET|RNDIS_MSG_COMPLETION)
+#define RNDIS_MSG_RESET		ccpu2(0x00000006)
+#define RNDIS_MSG_RESET_C	(RNDIS_MSG_RESET|RNDIS_MSG_COMPLETION)
+#define RNDIS_MSG_INDICATE	ccpu2(0x00000007)
+#define RNDIS_MSG_KEEPALIVE	ccpu2(0x00000008)
+#define RNDIS_MSG_KEEPALIVE_C	(RNDIS_MSG_KEEPALIVE|RNDIS_MSG_COMPLETION)
+
+/* codes for "status" field of completion messages */
+#define	RNDIS_STATUS_SUCCESS		ccpu2(0x00000000)
+#define	RNDIS_STATUS_FAILURE		ccpu2(0xc0000001)
+#define	RNDIS_STATUS_INVALID_DATA	ccpu2(0xc0010015)
+#define	RNDIS_STATUS_NOT_SUPPORTED	ccpu2(0xc00000bb)
+#define	RNDIS_STATUS_MEDIA_CONNECT	ccpu2(0x4001000b)
+#define	RNDIS_STATUS_MEDIA_DISCONNECT	ccpu2(0x4001000c)
+
+
+struct rndis_data_hdr {
+	__le32	msg_type;		/* RNDIS_MSG_PACKET */
+	__le32	msg_len;		// rndis_data_hdr + data_len + pad
+	__le32	data_offset;		// 36 -- right after header
+	__le32	data_len;		// ... real packet size
+
+	__le32	oob_data_offset;	// zero
+	__le32	oob_data_len;		// zero
+	__le32	num_oob;		// zero
+	__le32	packet_data_offset;	// zero
+
+	__le32	packet_data_len;	// zero
+	__le32	vc_handle;		// zero
+	__le32	reserved;		// zero
+} __attribute__ ((packed));
+
+struct rndis_init {		/* OUT */
+	// header and:
+	__le32	msg_type;			/* RNDIS_MSG_INIT */
+	__le32	msg_len;			// 24
+	__le32	request_id;
+	__le32	major_version;			// of rndis (1.0)
+	__le32	minor_version;
+	__le32	max_transfer_size;
+} __attribute__ ((packed));
+
+struct rndis_init_c {		/* IN */
+	// header and:
+	__le32	msg_type;			/* RNDIS_MSG_INIT_C */
+	__le32	msg_len;
+	__le32	request_id;
+	__le32	status;
+	__le32	major_version;			// of rndis (1.0)
+	__le32	minor_version;
+	__le32	device_flags;
+	__le32	medium;				// zero == 802.3
+	__le32	max_packets_per_message;
+	__le32	max_transfer_size;
+	__le32	packet_alignment;		// max 7; (1<<n) bytes
+	__le32	af_list_offset;			// zero
+	__le32	af_list_size;			// zero
+} __attribute__ ((packed));
+
+struct rndis_halt {		/* OUT (no reply) */
+	// header and:
+	__le32	msg_type;			/* RNDIS_MSG_HALT */
+	__le32	msg_len;
+	__le32	request_id;
+} __attribute__ ((packed));
+
+struct rndis_query {		/* OUT */
+	// header and:
+	__le32	msg_type;			/* RNDIS_MSG_QUERY */
+	__le32	msg_len;
+	__le32	request_id;
+	__le32	oid;
+	__le32	len;
+	__le32	offset;
+/*?*/	__le32	handle;				// zero
+} __attribute__ ((packed));
+
+struct rndis_query_c {		/* IN */
+	// header and:
+	__le32	msg_type;			/* RNDIS_MSG_QUERY_C */
+	__le32	msg_len;
+	__le32	request_id;
+	__le32	status;
+	__le32	len;
+	__le32	offset;
+} __attribute__ ((packed));
+
+struct rndis_set {		/* OUT */
+	// header and:
+	__le32	msg_type;			/* RNDIS_MSG_SET */
+	__le32	msg_len;
+	__le32	request_id;
+	__le32	oid;
+	__le32	len;
+	__le32	offset;
+/*?*/	__le32	handle;				// zero
+} __attribute__ ((packed));
+
+struct rndis_set_c {		/* IN */
+	// header and:
+	__le32	msg_type;			/* RNDIS_MSG_SET_C */
+	__le32	msg_len;
+	__le32	request_id;
+	__le32	status;
+} __attribute__ ((packed));
+
+struct rndis_reset {		/* IN */
+	// header and:
+	__le32	msg_type;			/* RNDIS_MSG_RESET */
+	__le32	msg_len;
+	__le32	reserved;
+} __attribute__ ((packed));
+
+struct rndis_reset_c {		/* OUT */
+	// header and:
+	__le32	msg_type;			/* RNDIS_MSG_RESET_C */
+	__le32	msg_len;
+	__le32	status;
+	__le32	addressing_lost;
+} __attribute__ ((packed));
+
+struct rndis_indicate {		/* IN (unrequested) */
+	// header and:
+	__le32	msg_type;			/* RNDIS_MSG_INDICATE */
+	__le32	msg_len;
+	__le32	status;
+	__le32	length;
+	__le32	offset;
+/**/	__le32	diag_status;
+	__le32	error_offset;
+/**/	__le32	message;
+} __attribute__ ((packed));
+
+struct rndis_keepalive {	/* OUT (optionally IN) */
+	// header and:
+	__le32	msg_type;			/* RNDIS_MSG_KEEPALIVE */
+	__le32	msg_len;
+	__le32	request_id;
+} __attribute__ ((packed));
+
+struct rndis_keepalive_c {	/* IN (optionally OUT) */
+	// header and:
+	__le32	msg_type;			/* RNDIS_MSG_KEEPALIVE_C */
+	__le32	msg_len;
+	__le32	request_id;
+	__le32	status;
+} __attribute__ ((packed));
+
+/* NOTE:  about 30 OIDs are "mandatory" for peripherals to support ... and
+ * there are gobs more that may optionally be supported.  We'll avoid as much
+ * of that mess as possible.
+ */
+#define OID_802_3_PERMANENT_ADDRESS	ccpu2(0x01010101)
+#define OID_GEN_MAXIMUM_FRAME_SIZE	ccpu2(0x00010106)
+#define OID_GEN_CURRENT_PACKET_FILTER	ccpu2(0x0001010e)
+
+/* packet filter bits used by OID_GEN_CURRENT_PACKET_FILTER */
+#define RNDIS_PACKET_TYPE_DIRECTED		ccpu2(0x00000001)
+#define RNDIS_PACKET_TYPE_MULTICAST		ccpu2(0x00000002)
+#define RNDIS_PACKET_TYPE_ALL_MULTICAST		ccpu2(0x00000004)
+#define RNDIS_PACKET_TYPE_BROADCAST		ccpu2(0x00000008)
+#define RNDIS_PACKET_TYPE_SOURCE_ROUTING	ccpu2(0x00000010)
+#define RNDIS_PACKET_TYPE_PROMISCUOUS		ccpu2(0x00000020)
+#define RNDIS_PACKET_TYPE_SMT			ccpu2(0x00000040)
+#define RNDIS_PACKET_TYPE_ALL_LOCAL		ccpu2(0x00000080)
+#define RNDIS_PACKET_TYPE_GROUP			ccpu2(0x00001000)
+#define RNDIS_PACKET_TYPE_ALL_FUNCTIONAL	ccpu2(0x00002000)
+#define RNDIS_PACKET_TYPE_FUNCTIONAL		ccpu2(0x00004000)
+#define RNDIS_PACKET_TYPE_MAC_FRAME		ccpu2(0x00008000)
+
+/* default filter used with RNDIS devices */
+#define RNDIS_DEFAULT_FILTER ( \
+	RNDIS_PACKET_TYPE_DIRECTED | \
+	RNDIS_PACKET_TYPE_BROADCAST | \
+	RNDIS_PACKET_TYPE_ALL_MULTICAST | \
+	RNDIS_PACKET_TYPE_PROMISCUOUS)
+
+#endif	/* __RNDIS_HOST_H */
+

^ permalink raw reply related


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