* Re: bcm43xx: "transmit timed out" and apparent hang with "preemptible periodic work" patches
From: Michael Buesch @ 2006-06-26 12:43 UTC (permalink / raw)
To: Paul Collins; +Cc: bcm43xx-dev, netdev
In-Reply-To: <87ac80ps5o.fsf@briny.internal.ondioline.org>
On Monday 26 June 2006 04:28, Paul Collins wrote:
> With the bcm43xx periodic work patches that recently made it into
> Linus's tree, my PowerBook does not survive running overnight.
>
> Yesterday I reverted
>
> 91769e7dd9cef7988dc4280f74ed168351beb5b8 [PATCH] bcm43xx: preemptible periodic work
> 78ff56a06edc3407996173daf63e48f6b90c7062 [PATCH] bcm43xx: redesign locking
>
> and it was still alive this morning.
>
> The following is logged, but that may not be all since the screen was
> turned off and kern.log was marked for no-fsync.
>
> Jun 24 06:53:41 briny kernel: NETDEV WATCHDOG: eth1: transmit timed out
> Jun 24 06:53:41 briny kernel: bcm43xx: Controller RESET (TX timeout) ...
> Jun 24 06:53:41 briny kernel: bcm43xx: Chip ID 0x4306, rev 0x3
> Jun 24 06:53:41 briny kernel: bcm43xx: Number of cores: 5
> Jun 24 06:53:41 briny kernel: bcm43xx: Core 0: ID 0x800, rev 0x4, vendor 0x4243, enabled
> Jun 24 06:53:41 briny kernel: bcm43xx: Core 1: ID 0x812, rev 0x5, vendor 0x4243, disabled
> Jun 24 06:53:41 briny kernel: bcm43xx: Core 2: ID 0x80d, rev 0x2, vendor 0x4243, enabled
> Jun 24 06:53:41 briny kernel: bcm43xx: Core 3: ID 0x807, rev 0x2, vendor 0x4243, disabled
> Jun 24 06:53:41 briny kernel: bcm43xx: Core 4: ID 0x804, rev 0x9, vendor 0x4243, enabled
> Jun 24 06:53:41 briny kernel: bcm43xx: PHY connected
> Jun 24 06:53:41 briny kernel: bcm43xx: Detected PHY: Version: 2, Type 2, Revision 2
> Jun 24 06:53:41 briny kernel: bcm43xx: Detected Radio: ID: 2205017f (Manuf: 17f Ver: 2050 Rev: 2)
> Jun 24 06:53:41 briny kernel: bcm43xx: Radio turned off
> Jun 24 06:53:41 briny kernel: bcm43xx: Radio turned off
> Jun 24 06:53:41 briny kernel: bcm43xx: Controller restarted
Try to get more logs.
I suggest to do a netconsole for logging.
--
Greetings Michael.
^ permalink raw reply
* RE: [PATCH 7/32] [TIPC] Multicast link failure now resets all links to "nacking" node.
From: Per Liden @ 2006-06-26 11:50 UTC (permalink / raw)
To: Stephens, Allan; +Cc: James Morris, David Miller, netdev
In-Reply-To: <3A30AD378ECC6F41A4AC64F18E8B3F7F48EA08@ala-mail04.corp.ad.wrs.com>
On Thu, 22 Jun 2006, Stephens, Allan wrote:
[...]
> Per, I'll leave it to you to decide if you want to address James's
> concern. But be aware that the link_reset_all() routine is only called
> to handle emergency situations when TIPC's multicast link has run into
> serious problems and is trying to recover. Most systems will never
> follow this path, so the cost of the unnecessary
> local_bh_disable()/local_bh_enable() pairing shouldn't have any real
> impact on the overall performance of TIPC.
I tend to agree with you Allan. Since local_bh_disable()/local_bh_enable()
supports nesting and this code is only called in extreme situations I
don't think it's a real problem.
/Per
^ permalink raw reply
* Re: [PATCH 0/2] NET: Accurate packet scheduling for ATM/ADSL
From: Patrick McHardy @ 2006-06-26 11:21 UTC (permalink / raw)
To: hadi; +Cc: Jesper Dangaard Brouer, hawk, russell-tcatm, netdev,
Stephen Hemminger
In-Reply-To: <1151159997.6716.116.camel@jzny2>
jamal wrote:
> On Fri, 2006-23-06 at 16:32 +0200, Patrick McHardy wrote:
>
>>I don't think it should carry both old and new speed. Netlink
>>notifications usually provide a snapshot of the new state, but
>>no indication what changed, with one notable exception, the
>>ifi_change field, which IMO is a hack for lazy userspace.
>
>
> I am quiet fond of the ifi_change ;->
>
>>Since
>>notifications can get lost, userspace needs to resync occasionally.
>>The naiive approach (works for every other object) to determine if
>>the object state changed from my last known state is to compare
>>all attributes ..
>
>
> scalability issues abound when you have a gazillion things to look at.
> There used or may still be a way to tell from looking at netlink socket
> that an error occurred since last time - such as "a message was lost".
> You could use that to tell a message was lost and do scanning only
> then.
It returns -ENOBUFS on socket overrun. Without it netlink notifications
wouldn't be very useable as you couldn't figure out when you missed
some.
>> but the ifi_change field will be different
>>between notifications and dumps even if the object itself didn't
>>change. "Lazy userspace" because looking at ifi_change is obviously
>>only useful if it doesn't keep its last known state and tries to
>>derive the change from update notifications alone .. which means it
>>fails when notifications are lost.
>>
>
>
> But thats not the real intent for it.
Then what is the intent, it doesn't carry any other information?
It includes information that are not available any other way from
the kernel, yet the information is not transmitted reliably. How
could a program that relies on this possibly work reliable?
^ permalink raw reply
* Re: [PATCH 0/2] NET: Accurate packet scheduling for ATM/ADSL
From: Patrick McHardy @ 2006-06-26 11:10 UTC (permalink / raw)
To: Russell Stuart
Cc: hadi, Alan Cox, Stephen Hemminger, netdev, Jesper Dangaard Brouer
In-Reply-To: <1151282720.4210.46.camel@ras.pc.brisbane.lube>
Russell Stuart wrote:
> On Fri, 2006-06-23 at 17:21 +0200, Patrick McHardy wrote:
>
>>Not really. The randomization doesn't happen by default, but it doesn't
>>influence this anyway. SFQ allows flows to send up to "quantum" bytes
>>at a time before moving on to the next one. A flow that sends 75 * 20
>>byte will in the eyes of SFQ use 1500bytes, on the (ethernet) wire it
>>needs 4800bytes. A flow that sents 1500byte packets will only need
>>1504 bytes on the wire, but will be treated equally. So it does make
>>a different for SFQ.
>
>
> I hadn't even thought to check. My bad. The S in SFQ stands
> for stochastic, so something that does without randomisation
> the algorithm implemented couldn't really be called SFQ -
> particularly as it weakens the algorithm considerably. I
> hope that most users do specify a perturb.
Its not as great as you think. Changing hash-functions on the
fly causes reordering for non-idle flows when bucket-lengths
aren't distributed even. I never use it.
> Your 20 byte example is hardly realistic. skb->len includes
> the 14 byte ethernet header, so there is a total of 6 data
> bytes in a 20 byte packet. The IP header alone is 20 bytes.
> TCP as implemented on Linux adds another 32 bytes (20 + the
> rtt option). In other words I agree with Jamal's comments
> elsewhere - optimising for MPU sized packets doesn't seem
> like a win.
The point is that SFQ does care about packet sizes, and this is
true for both MPU-sized and other packets.
>>Its not about cleanup, its about providing the same capabilities
>>to all qdiscs instead of just a few selected ones and generalizing
>>it so it is also usable for non-ATM overhead calculations.
>
>
> Perhaps I chose my words poorly.
>
> My intent was to contrast the size and goals of the two
> proposed patches. The ATM patch is a 37 line patch. It
> includes some minor cleanups. From the pseudo code you
> have posted what you are proposing is a more ambitious and
> much larger patch that moves a chunk of user space code
> into the kernel. I am a complete newbie when it comes to
> getting code into the kernel, but that strikes me as
> contentious. I would rather not have the ATM patch
> depend on it.
>
> By the by, here are a couple of observations:
>
> 1. The entries in the current rtab are already very closely
> related to packet lengths. They are actually the packet
> length multiplied by a constant that converts the units
> from "bytes" to "jiffies". The constant is the same for
> all entries in the table.
>
> 2. As such, the current rtab could already be used by SFQ
> and any other qdisc that needs to know the packet length.
> That SFQ doesn't do this is probably because it doesn't
> effect its performance overly.
The rtab includes the transmission time, which is related to,
but still is something different than the length. You can't
calculate the transmission time without a rate, which is
not needed otherwise for SFQ for example. The way rtabs
are used also needs more space, my current size tables
only use as much space as needed, which is 16 entries for
ethernet instead of 256.
> 3. Be that as it may, the current RTAB isn't in the most
> convenient form for SFQ, and I am guessing it is in a
> very inconvenient form for HFSC. Adding a new version
> that is identical except that it contains the raw packet
> length would be a simple change. In that format it
> could be used by all qdiscs. The users of the existing
> rtab would have to do the multiplication that converts
> the packet length to jiffies in the kernel. This means
> the conceptually at least, should the gootput change
> you need to change this one constant, not the entire
> table.
Well, I don't care much whether we use rtabs or something new,
but rtabs are meant for something different and as such are not
optimally suited for this.
> 4. Much as you seem to dislike having the rate / packet length
> calculations in user space, having them there makes it easy
> to add new technologies such as ATM. You just have to
> change a user space tool - not the kernel.
I don't dislike it for beeing in userspace, I dislike it for
a) beeing used for this since it only covers TBF-based qdiscs
b) beeing used for an ATM "special case" which is not special
at all.
I should also note that my tables don't come out of the random
generator but are provided by userspace as well. Unless the
mechanism is unable to express the needs of a particular link
layer type all you have to do is to provide a different set
of values without touching any code at all.
> 5. We still did have to modify the kernel for ATM. That was
> because of its rather unusual characteristics. However,
> it you look at the size of modifications made to the kernel
> verses the size made to the user space tool, (37 lines
> versus 303 lines,) the bulk of the work was does in user
> space.
I'm sorry, but arguing that a limited special case solution is
better because it needs slightly less code is just not reasonable.
^ permalink raw reply
* Problem with redirecting traffic via ifb device
From: Egor Duda @ 2006-06-26 10:48 UTC (permalink / raw)
To: netdev
I have a linux router which is connected via pppoe to my ISP. My
provider limits aggregate upload+download rate to some fixed amount of
kbps, so to perform shaping on my router i'm trying to do the same on my
router (to "own the queue", so to say). Since standard tbf accounts to
the packets going only one way, i wanted to create virtual ifb
interface, which will gather all incoming and outgoing packets, and then
perform appropriate shaping on it.
I'm doing it roughly in the following way:
-------------------------------------------------------------------------
tc qdisc add dev $iface ingress
tc qdisc add dev $iface parent ffff: handle 1: prio
tc filter add dev $iface parent 1: protocol ip prio 10 \
u32 match u32 0 0 flowid 1:1 \
action ipt -j MARK --set-mark 1 \
action mirred egress redirect dev ifb0
tc qdisc add dev $iface root handle 2: prio
tc filter add dev $iface parent 2: protocol ip prio 10 \
u32 match u32 0 0 flowid 2:1 \
action ipt -j MARK --set-mark 1 \
action mirred egress redirect dev ifb0
-------------------------------------------------------------------------
The strange thing is, when i run this script over vtun interface, it
works as expected, i can later attach qdiscs on ifb0 interface and
perform shaping i need. But when i try to do the same on ppp interface
(which is my primary outbound interface), packets go to ifb0 (tcpdump
shows them) but not being returned to userspace. So, when i run
ping somehost &
tcpdump -p -n -i ifb0
i see both icmp request and icmp reply packtes in tcpdump output. But
ping seems to never receive icmp replies.
My kernel version is 2.6.16.19, pppd version 2.4.4b1-1 from debian.
Am i totally misguided about how all this stuff works? In this case i'd
appreciate some links to description of 'action mirred egress redirect'.
Or is it some specific of ppp interface which prevents my setup from
working? In fact, i'd be thankful for any advice on handling my
situation (upload+download rate is limited).
As as side note, ifb implementation sets dev type to ARPHRD_ETHER to ifb
device, which prevents tcpdump from parsing packets (it treats them as
ethernet frames, while they are, in fact ip packets). I've patched ifb.c
to set device type to ARPHRD_VOID, and it fixed tcpdump problem.
egor.
^ permalink raw reply
* [2.6 patch] drivers/net/hamradio/dmascc.c: fix section mismatch
From: Adrian Bunk @ 2006-06-26 10:31 UTC (permalink / raw)
To: jgarzik; +Cc: netdev, linux-kernel
dev_setup() is using the __initdata variables ax25_broadcast and
ax25_test.
Since the only caller of dev_setup() (setup_adapter()) is already
__init, the solution is to make dev_setup() __init, too.
Signed-off-by: Adrian Bunk <bunk@stusta.de>
--- linux-2.6.17-mm2-full/drivers/net/hamradio/dmascc.c.old 2006-06-26 01:56:37.000000000 +0200
+++ linux-2.6.17-mm2-full/drivers/net/hamradio/dmascc.c 2006-06-26 01:56:55.000000000 +0200
@@ -436,7 +436,7 @@
module_init(dmascc_init);
module_exit(dmascc_exit);
-static void dev_setup(struct net_device *dev)
+static void __init dev_setup(struct net_device *dev)
{
dev->type = ARPHRD_AX25;
dev->hard_header_len = AX25_MAX_HEADER_LEN;
^ permalink raw reply
* [patch 4/4] Network namespaces: playing and debugging
From: Andrey Savochkin @ 2006-06-26 9:55 UTC (permalink / raw)
To: dlezcano
Cc: linux-kernel, netdev, serue, haveblue, clg, Andrew Morton, dev,
herbert, devel, sam, ebiederm, viro
In-Reply-To: <20060626135427.C28942@castle.nmd.msu.ru>
Temporary code to play with network namespaces in the simplest way.
Do
exec 7< /proc/net/net_ns
in your bash shell and you'll get a brand new network namespace.
There you can, for example, do
ip link set lo up
ip addr list
ip addr add 1.2.3.4 dev lo
ping -n 1.2.3.4
Signed-off-by: Andrey Savochkin <saw@swsoft.com>
---
dev.c | 27 ++++++++++++++++++++++++++-
1 files changed, 26 insertions, 1 deletion
--- ./net/core/dev.c.vensdbg Fri Jun 23 11:50:16 2006
+++ ./net/core/dev.c Fri Jun 23 11:50:40 2006
@@ -3444,6 +3444,8 @@ int net_ns_start(void)
if (err)
goto out_register;
put_net_ns(orig_ns);
+ printk(KERN_DEBUG "NET_NS: created new netcontext %p for %s (pid=%d)\n",
+ ns, task->comm, task->tgid);
return 0;
out_register:
@@ -3461,6 +3463,7 @@ EXPORT_SYMBOL(net_ns_start);
void net_ns_free(struct net_namespace *ns)
{
+ printk(KERN_DEBUG "NET_NS: netcontext %p freed\n", ns);
kfree(ns);
}
EXPORT_SYMBOL(net_ns_free);
@@ -3473,8 +3476,13 @@ static void net_ns_destroy(void *data)
ns = data;
push_net_ns(ns, orig_ns);
unregister_netdev(ns->loopback);
+ if (!list_empty(&ns->dev_base)) {
+ printk("NET_NS: BUG: context %p has devices! ref %d\n",
+ ns, atomic_read(&ns->active_ref));
+ pop_net_ns(orig_ns);
+ return;
+ }
ip_fib_struct_fini();
- BUG_ON(!list_empty(&ns->dev_base));
pop_net_ns(orig_ns);
/* drop (hopefully) final reference */
@@ -3483,9 +3491,23 @@ static void net_ns_destroy(void *data)
void net_ns_stop(struct net_namespace *ns)
{
+ printk(KERN_DEBUG "NET_NS: netcontext %p scheduled for stop\n", ns);
execute_in_process_context(net_ns_destroy, ns, &ns->destroy_work);
}
EXPORT_SYMBOL(net_ns_stop);
+
+static int net_ns_open(struct inode *i, struct file *f)
+{
+ return net_ns_start();
+}
+static struct file_operations net_ns_fops = {
+ .open = net_ns_open,
+};
+static int net_ns_init(void)
+{
+ return proc_net_fops_create("net_ns", S_IRWXU, &net_ns_fops)
+ ? 0 : -ENOMEM;
+}
#endif
/*
@@ -3550,6 +3572,9 @@ static int __init net_dev_init(void)
hotcpu_notifier(dev_cpu_callback, 0);
dst_init();
dev_mcast_init();
+#ifdef CONFIG_NET_NS
+ net_ns_init();
+#endif
rc = 0;
out:
return rc;
^ permalink raw reply
* [patch 3/4] Network namespaces: IPv4 FIB/routing in namespaces
From: Andrey Savochkin @ 2006-06-26 9:54 UTC (permalink / raw)
To: dlezcano
Cc: linux-kernel, netdev, serue, haveblue, clg, Andrew Morton, dev,
herbert, devel, sam, ebiederm, viro
In-Reply-To: <20060626135250.B28942@castle.nmd.msu.ru>
Structures related to IPv4 rounting (FIB and routing cache)
are made per-namespace.
Signed-off-by: Andrey Savochkin <saw@swsoft.com>
---
include/linux/net_ns.h | 9 +++
include/net/flow.h | 3 +
include/net/ip_fib.h | 62 ++++++++++++++++++++-----
net/core/dev.c | 7 ++
net/ipv4/Kconfig | 4 -
net/ipv4/fib_frontend.c | 87 +++++++++++++++++++++++++++++------
net/ipv4/fib_hash.c | 13 ++++-
net/ipv4/fib_rules.c | 114 +++++++++++++++++++++++++++++++++++++++++------
net/ipv4/fib_semantics.c | 104 +++++++++++++++++++++++++++++-------------
net/ipv4/route.c | 26 ++++++++++
10 files changed, 348 insertions, 81 deletions
--- ./include/linux/net_ns.h.vensrt Fri Jun 23 11:49:42 2006
+++ ./include/linux/net_ns.h Fri Jun 23 11:50:16 2006
@@ -14,7 +14,16 @@ struct net_namespace {
atomic_t active_ref, use_ref;
struct list_head dev_base;
struct net_device *loopback;
+#ifndef CONFIG_IP_MULTIPLE_TABLES
+ struct fib_table *fib4_local_table, *fib4_main_table;
+#else
+ struct fib_table **fib4_tables;
+ struct hlist_head fib4_rules;
+#endif
+ struct hlist_head *fib4_hash, *fib4_laddrhash;
+ unsigned fib4_hash_size, fib4_info_cnt;
unsigned int hash;
+ char destroying;
struct execute_work destroy_work;
};
--- ./include/net/flow.h.vensrt Wed Jun 21 18:51:08 2006
+++ ./include/net/flow.h Fri Jun 23 11:50:16 2006
@@ -78,6 +78,9 @@ struct flowi {
#define fl_icmp_type uli_u.icmpt.type
#define fl_icmp_code uli_u.icmpt.code
#define fl_ipsec_spi uli_u.spi
+#ifdef CONFIG_NET_NS
+ struct net_namespace *net_ns;
+#endif
} __attribute__((__aligned__(BITS_PER_LONG/8)));
#define FLOW_DIR_IN 0
--- ./include/net/ip_fib.h.vensrt Wed Jun 21 18:53:17 2006
+++ ./include/net/ip_fib.h Fri Jun 23 11:50:16 2006
@@ -18,6 +18,7 @@
#include <net/flow.h>
#include <linux/seq_file.h>
+#include <linux/net_ns.h>
/* WARNING: The ordering of these elements must match ordering
* of RTA_* rtnetlink attribute numbers.
@@ -169,14 +170,21 @@ struct fib_table {
#ifndef CONFIG_IP_MULTIPLE_TABLES
-extern struct fib_table *ip_fib_local_table;
-extern struct fib_table *ip_fib_main_table;
+#ifndef CONFIG_NET_NS
+extern struct fib_table *ip_fib_local_table_static;
+extern struct fib_table *ip_fib_main_table_static;
+#define ip_fib_local_table_ns() ip_fib_local_table_static
+#define ip_fib_main_table_ns() ip_fib_main_table_static
+#else
+#define ip_fib_local_table_ns() (current_net_ns->fib4_local_table)
+#define ip_fib_main_table_ns() (current_net_ns->fib4_main_table)
+#endif
static inline struct fib_table *fib_get_table(int id)
{
if (id != RT_TABLE_LOCAL)
- return ip_fib_main_table;
- return ip_fib_local_table;
+ return ip_fib_main_table_ns();
+ return ip_fib_local_table_ns();
}
static inline struct fib_table *fib_new_table(int id)
@@ -186,23 +194,36 @@ static inline struct fib_table *fib_new_
static inline int fib_lookup(const struct flowi *flp, struct fib_result *res)
{
- if (ip_fib_local_table->tb_lookup(ip_fib_local_table, flp, res) &&
- ip_fib_main_table->tb_lookup(ip_fib_main_table, flp, res))
+ struct fib_table *tb;
+
+ tb = ip_fib_local_table_ns();
+ if (!tb->tb_lookup(tb, flp, res))
+ return 0;
+ tb = ip_fib_main_table_ns();
+ if (tb->tb_lookup(tb, flp, res))
return -ENETUNREACH;
return 0;
}
static inline void fib_select_default(const struct flowi *flp, struct fib_result *res)
{
+ struct fib_table *tb;
+
+ tb = ip_fib_main_table_ns();
if (FIB_RES_GW(*res) && FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK)
- ip_fib_main_table->tb_select_default(ip_fib_main_table, flp, res);
+ tb->tb_select_default(main_table, flp, res);
}
#else /* CONFIG_IP_MULTIPLE_TABLES */
-#define ip_fib_local_table (fib_tables[RT_TABLE_LOCAL])
-#define ip_fib_main_table (fib_tables[RT_TABLE_MAIN])
+#define ip_fib_local_table_ns() (fib_tables_ns()[RT_TABLE_LOCAL])
+#define ip_fib_main_table_ns() (fib_tables_ns()[RT_TABLE_MAIN])
-extern struct fib_table * fib_tables[RT_TABLE_MAX+1];
+#ifndef CONFIG_NET_NS
+extern struct fib_table * fib_tables_static[RT_TABLE_MAX+1];
+#define fib_tables_ns() fib_tables_static
+#else
+#define fib_tables_ns() (current_net_ns->fib4_tables)
+#endif
extern int fib_lookup(const struct flowi *flp, struct fib_result *res);
extern struct fib_table *__fib_new_table(int id);
extern void fib_rule_put(struct fib_rule *r);
@@ -212,7 +233,7 @@ static inline struct fib_table *fib_get_
if (id == 0)
id = RT_TABLE_MAIN;
- return fib_tables[id];
+ return fib_tables_ns()[id];
}
static inline struct fib_table *fib_new_table(int id)
@@ -220,7 +241,7 @@ static inline struct fib_table *fib_new_
if (id == 0)
id = RT_TABLE_MAIN;
- return fib_tables[id] ? : __fib_new_table(id);
+ return fib_tables_ns()[id] ? : __fib_new_table(id);
}
extern void fib_select_default(const struct flowi *flp, struct fib_result *res);
@@ -229,6 +250,10 @@ extern void fib_select_default(const str
/* Exported by fib_frontend.c */
extern void ip_fib_init(void);
+#ifdef CONFIG_NET_NS
+extern int ip_fib_struct_init(void);
+extern void ip_fib_struct_fini(void);
+#endif
extern int inet_rtm_delroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg);
extern int inet_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg);
extern int inet_rtm_getroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg);
@@ -246,9 +271,16 @@ extern int fib_sync_up(struct net_device
extern int fib_convert_rtentry(int cmd, struct nlmsghdr *nl, struct rtmsg *rtm,
struct kern_rta *rta, struct rtentry *r);
extern u32 __fib_res_prefsrc(struct fib_result *res);
+#ifdef CONFIG_NET_NS
+extern void fib_hashtable_destroy(void);
+#endif
/* Exported by fib_hash.c */
extern struct fib_table *fib_hash_init(int id);
+#ifdef CONFIG_NET_NS
+extern void fib_hash_fini(struct fib_table *tb);
+extern void fib_hash_destroy_hash(void);
+#endif
#ifdef CONFIG_IP_MULTIPLE_TABLES
/* Exported by fib_rules.c */
@@ -259,7 +291,11 @@ extern int inet_dump_rules(struct sk_buf
#ifdef CONFIG_NET_CLS_ROUTE
extern u32 fib_rules_tclass(struct fib_result *res);
#endif
-extern void fib_rules_init(void);
+extern int fib_rules_struct_init(void);
+extern void fib_rules_notif_init(void);
+#ifdef CONFIG_NET_NS
+extern void fib_rules_struct_fini(void);
+#endif
#endif
static inline void fib_combine_itag(u32 *itag, struct fib_result *res)
--- ./net/core/dev.c.vensrt Fri Jun 23 11:48:15 2006
+++ ./net/core/dev.c Fri Jun 23 11:50:16 2006
@@ -3398,6 +3398,8 @@ static int __init netdev_dma_register(vo
#endif /* CONFIG_NET_DMA */
#ifdef CONFIG_NET_NS
+#include <net/ip_fib.h>
+
struct net_namespace init_net_ns = {
.active_ref = ATOMIC_INIT(2),
/* one for init_task->net_context,
@@ -3436,6 +3438,8 @@ int net_ns_start(void)
task = current;
orig_ns = task->net_context;
task->net_context = ns;
+ if (ip_fib_struct_init())
+ goto out_fib4;
err = register_netdev(dev);
if (err)
goto out_register;
@@ -3443,6 +3447,8 @@ int net_ns_start(void)
return 0;
out_register:
+ ip_fib_struct_fini();
+out_fib4:
dev->destructor(dev);
task->net_context = orig_ns;
BUG_ON(atomic_read(&ns->active_ref) != 1);
@@ -3467,6 +3473,7 @@ static void net_ns_destroy(void *data)
ns = data;
push_net_ns(ns, orig_ns);
unregister_netdev(ns->loopback);
+ ip_fib_struct_fini();
BUG_ON(!list_empty(&ns->dev_base));
pop_net_ns(orig_ns);
--- ./net/ipv4/Kconfig.vensrt Wed Jun 21 18:53:19 2006
+++ ./net/ipv4/Kconfig Fri Jun 23 11:50:16 2006
@@ -53,7 +53,7 @@ config IP_ADVANCED_ROUTER
choice
prompt "Choose IP: FIB lookup algorithm (choose FIB_HASH if unsure)"
- depends on IP_ADVANCED_ROUTER
+ depends on IP_ADVANCED_ROUTER && !NET_NS
default ASK_IP_FIB_HASH
config ASK_IP_FIB_HASH
@@ -83,7 +83,7 @@ config IP_FIB_TRIE
endchoice
config IP_FIB_HASH
- def_bool ASK_IP_FIB_HASH || !IP_ADVANCED_ROUTER
+ def_bool ASK_IP_FIB_HASH || !IP_ADVANCED_ROUTER || NET_NS
config IP_MULTIPLE_TABLES
bool "IP: policy routing"
--- ./net/ipv4/fib_frontend.c.vensrt Wed Jun 21 18:53:19 2006
+++ ./net/ipv4/fib_frontend.c Fri Jun 23 11:50:16 2006
@@ -53,14 +53,18 @@
#define RT_TABLE_MIN RT_TABLE_MAIN
-struct fib_table *ip_fib_local_table;
-struct fib_table *ip_fib_main_table;
+#ifndef CONFIG_NET_NS
+struct fib_table *ip_fib_local_table_static;
+struct fib_table *ip_fib_main_table_static;
+#endif
#else
#define RT_TABLE_MIN 1
-struct fib_table *fib_tables[RT_TABLE_MAX+1];
+#ifndef CONFIG_NET_NS
+struct fib_table *fib_tables_static[RT_TABLE_MAX+1];
+#endif
struct fib_table *__fib_new_table(int id)
{
@@ -69,7 +73,7 @@ struct fib_table *__fib_new_table(int id
tb = fib_hash_init(id);
if (!tb)
return NULL;
- fib_tables[id] = tb;
+ fib_tables_ns()[id] = tb;
return tb;
}
@@ -80,8 +84,8 @@ struct fib_table *__fib_new_table(int id
static void fib_flush(void)
{
int flushed = 0;
-#ifdef CONFIG_IP_MULTIPLE_TABLES
struct fib_table *tb;
+#ifdef CONFIG_IP_MULTIPLE_TABLES
int id;
for (id = RT_TABLE_MAX; id>0; id--) {
@@ -90,8 +94,10 @@ static void fib_flush(void)
flushed += tb->tb_flush(tb);
}
#else /* CONFIG_IP_MULTIPLE_TABLES */
- flushed += ip_fib_main_table->tb_flush(ip_fib_main_table);
- flushed += ip_fib_local_table->tb_flush(ip_fib_local_table);
+ tb = ip_fib_main_table_ns();
+ flushed += tb->tb_flush(tb);
+ tb = ip_fib_local_table_ns();
+ flushed += tb->tb_flush(tb);
#endif /* CONFIG_IP_MULTIPLE_TABLES */
if (flushed)
@@ -106,14 +112,15 @@ struct net_device * ip_dev_find(u32 addr
{
struct flowi fl = { .nl_u = { .ip4_u = { .daddr = addr } } };
struct fib_result res;
+ struct fib_table *tb;
struct net_device *dev = NULL;
#ifdef CONFIG_IP_MULTIPLE_TABLES
res.r = NULL;
#endif
- if (!ip_fib_local_table ||
- ip_fib_local_table->tb_lookup(ip_fib_local_table, &fl, &res))
+ tb = ip_fib_local_table_ns();
+ if (!tb || tb->tb_lookup(tb, &fl, &res))
return NULL;
if (res.type != RTN_LOCAL)
goto out;
@@ -130,6 +137,7 @@ unsigned inet_addr_type(u32 addr)
{
struct flowi fl = { .nl_u = { .ip4_u = { .daddr = addr } } };
struct fib_result res;
+ struct fib_table *tb;
unsigned ret = RTN_BROADCAST;
if (ZERONET(addr) || BADCLASS(addr))
@@ -141,10 +149,10 @@ unsigned inet_addr_type(u32 addr)
res.r = NULL;
#endif
- if (ip_fib_local_table) {
+ tb = ip_fib_local_table_ns();
+ if (tb) {
ret = RTN_UNICAST;
- if (!ip_fib_local_table->tb_lookup(ip_fib_local_table,
- &fl, &res)) {
+ if (!tb->tb_lookup(tb, &fl, &res)) {
ret = res.type;
fib_res_put(&res);
}
@@ -651,19 +659,66 @@ static struct notifier_block fib_netdev_
.notifier_call =fib_netdev_event,
};
-void __init ip_fib_init(void)
+int ip_fib_struct_init(void)
{
#ifndef CONFIG_IP_MULTIPLE_TABLES
- ip_fib_local_table = fib_hash_init(RT_TABLE_LOCAL);
- ip_fib_main_table = fib_hash_init(RT_TABLE_MAIN);
+ ip_fib_local_table_ns() = fib_hash_init(RT_TABLE_LOCAL);
+ ip_fib_main_table_ns() = fib_hash_init(RT_TABLE_MAIN);
+#else
+#ifndef CONFIG_NET_NS
+ return fib_rules_struct_init();
#else
- fib_rules_init();
+ struct fib_table **tables;
+
+ tables = kmalloc((RT_TABLE_MAX+1) * sizeof(*tables), GFP_KERNEL);
+ if (tables == NULL)
+ return -ENOMEM;
+ memset(tables, 0, (RT_TABLE_MAX+1) * sizeof(*tables));
+ fib_tables_ns() = tables;
+ if (fib_rules_struct_init()) {
+ kfree(tables);
+ fib_tables_ns() = NULL;
+ return -ENOMEM;
+ }
#endif
+#endif
+ return 0;
+}
+void __init ip_fib_init(void)
+{
+ ip_fib_struct_init();
+
+#ifdef CONFIG_IP_MULTIPLE_TABLES
+ fib_rules_notif_init();
+#endif
register_netdevice_notifier(&fib_netdev_notifier);
register_inetaddr_notifier(&fib_inetaddr_notifier);
nl_fib_lookup_init();
}
+#ifdef CONFIG_NET_NS
+void ip_fib_struct_fini(void)
+{
+ current_net_ns->destroying = 1;
+ rtnl_lock();
+#ifdef CONFIG_IP_MULTIPLE_TABLES
+ fib_rules_struct_fini();
+#endif
+ /*
+ * FIB should already be empty since there is no netdevice,
+ * but clear it anyway
+ */
+ fib_flush();
+ rt_cache_flush(0);
+#ifdef CONFIG_IP_MULTIPLE_TABLES
+ kfree(fib_tables_ns());
+ fib_tables_ns() = NULL;
+#endif
+ fib_hashtable_destroy();
+ rtnl_unlock();
+}
+#endif /* CONFIG_NET_NS */
+
EXPORT_SYMBOL(inet_addr_type);
EXPORT_SYMBOL(ip_dev_find);
--- ./net/ipv4/fib_hash.c.vensrt Mon Mar 20 08:53:29 2006
+++ ./net/ipv4/fib_hash.c Fri Jun 23 11:50:16 2006
@@ -629,6 +629,11 @@ static int fn_flush_list(struct fn_zone
struct hlist_node *node, *n;
struct fib_node *f;
int found = 0;
+#ifndef CONFIG_NET_NS
+ const int destroy = 0;
+#else
+ const int destroy = current_net_ns->destroying;
+#endif
hlist_for_each_entry_safe(f, node, n, head, fn_hash) {
struct fib_alias *fa, *fa_node;
@@ -638,7 +643,9 @@ static int fn_flush_list(struct fn_zone
list_for_each_entry_safe(fa, fa_node, &f->fn_alias, fa_list) {
struct fib_info *fi = fa->fa_info;
- if (fi && (fi->fib_flags&RTNH_F_DEAD)) {
+ if (fi == NULL)
+ continue;
+ if (destroy || (fi->fib_flags&RTNH_F_DEAD)) {
write_lock_bh(&fib_hash_lock);
list_del(&fa->fa_list);
if (list_empty(&f->fn_alias)) {
@@ -819,7 +826,7 @@ struct fib_iter_state {
static struct fib_alias *fib_get_first(struct seq_file *seq)
{
struct fib_iter_state *iter = seq->private;
- struct fn_hash *table = (struct fn_hash *) ip_fib_main_table->tb_data;
+ struct fn_hash *table = (struct fn_hash *) ip_fib_main_table_ns()->tb_data;
iter->bucket = 0;
iter->hash_head = NULL;
@@ -958,7 +965,7 @@ static void *fib_seq_start(struct seq_fi
void *v = NULL;
read_lock(&fib_hash_lock);
- if (ip_fib_main_table)
+ if (ip_fib_main_table_ns())
v = *pos ? fib_get_idx(seq, *pos - 1) : SEQ_START_TOKEN;
return v;
}
--- ./net/ipv4/fib_rules.c.vensrt Wed Jun 21 18:51:09 2006
+++ ./net/ipv4/fib_rules.c Fri Jun 23 11:50:16 2006
@@ -100,7 +100,12 @@ static struct fib_rule local_rule = {
.r_action = RTN_UNICAST,
};
-static struct hlist_head fib_rules;
+#ifndef CONFIG_NET_NS
+static struct hlist_head fib_rules_static;
+#define fib_rules_ns() (&fib_rules_static)
+#else
+#define fib_rules_ns() (¤t_net_ns->fib4_rules)
+#endif
/* writer func called from netlink -- rtnl_sem hold*/
@@ -110,11 +115,13 @@ int inet_rtm_delrule(struct sk_buff *skb
{
struct rtattr **rta = arg;
struct rtmsg *rtm = NLMSG_DATA(nlh);
+ struct hlist_head *fib_rules;
struct fib_rule *r;
struct hlist_node *node;
int err = -ESRCH;
- hlist_for_each_entry(r, node, &fib_rules, hlist) {
+ fib_rules = fib_rules_ns();
+ hlist_for_each_entry(r, node, fib_rules, hlist) {
if ((!rta[RTA_SRC-1] || memcmp(RTA_DATA(rta[RTA_SRC-1]), &r->r_src, 4) == 0) &&
rtm->rtm_src_len == r->r_src_len &&
rtm->rtm_dst_len == r->r_dst_len &&
@@ -128,7 +135,7 @@ int inet_rtm_delrule(struct sk_buff *skb
(!rta[RTA_IIF-1] || rtattr_strcmp(rta[RTA_IIF-1], r->r_ifname) == 0) &&
(!rtm->rtm_table || (r && rtm->rtm_table == r->r_table))) {
err = -EPERM;
- if (r == &local_rule)
+ if (&r->hlist == fib_rules->first)
break;
hlist_del_rcu(&r->hlist);
@@ -147,9 +154,11 @@ int inet_rtm_delrule(struct sk_buff *skb
static struct fib_table *fib_empty_table(void)
{
int id;
+ struct fib_table **tbs;
+ tbs = fib_tables_ns();
for (id = 1; id <= RT_TABLE_MAX; id++)
- if (fib_tables[id] == NULL)
+ if (tbs[id] == NULL)
return __fib_new_table(id);
return NULL;
}
@@ -176,6 +185,7 @@ int inet_rtm_newrule(struct sk_buff *skb
{
struct rtattr **rta = arg;
struct rtmsg *rtm = NLMSG_DATA(nlh);
+ struct hlist_head *fib_rules;
struct fib_rule *r, *new_r, *last = NULL;
struct hlist_node *node = NULL;
unsigned char table_id;
@@ -234,7 +244,8 @@ int inet_rtm_newrule(struct sk_buff *skb
if (rta[RTA_FLOW-1])
memcpy(&new_r->r_tclassid, RTA_DATA(rta[RTA_FLOW-1]), 4);
#endif
- r = container_of(fib_rules.first, struct fib_rule, hlist);
+ fib_rules = fib_rules_ns();
+ r = container_of(fib_rules->first, struct fib_rule, hlist);
if (!new_r->r_preference) {
if (r && r->hlist.next != NULL) {
@@ -244,7 +255,7 @@ int inet_rtm_newrule(struct sk_buff *skb
}
}
- hlist_for_each_entry(r, node, &fib_rules, hlist) {
+ hlist_for_each_entry(r, node, fib_rules, hlist) {
if (r->r_preference > new_r->r_preference)
break;
last = r;
@@ -273,10 +284,12 @@ u32 fib_rules_tclass(struct fib_result *
static void fib_rules_detach(struct net_device *dev)
{
+ struct hlist_head *fib_rules;
struct hlist_node *node;
struct fib_rule *r;
- hlist_for_each_entry(r, node, &fib_rules, hlist) {
+ fib_rules = fib_rules_ns();
+ hlist_for_each_entry(r, node, fib_rules, hlist) {
if (r->r_ifindex == dev->ifindex)
r->r_ifindex = -1;
@@ -287,10 +300,12 @@ static void fib_rules_detach(struct net_
static void fib_rules_attach(struct net_device *dev)
{
+ struct hlist_head *fib_rules;
struct hlist_node *node;
struct fib_rule *r;
- hlist_for_each_entry(r, node, &fib_rules, hlist) {
+ fib_rules = fib_rules_ns();
+ hlist_for_each_entry(r, node, fib_rules, hlist) {
if (r->r_ifindex == -1 && strcmp(dev->name, r->r_ifname) == 0)
r->r_ifindex = dev->ifindex;
}
@@ -299,6 +314,7 @@ static void fib_rules_attach(struct net_
int fib_lookup(const struct flowi *flp, struct fib_result *res)
{
int err;
+ struct hlist_head *fib_rules;
struct fib_rule *r, *policy;
struct fib_table *tb;
struct hlist_node *node;
@@ -311,7 +327,8 @@ FRprintk("Lookup: %u.%u.%u.%u <- %u.%u.%
rcu_read_lock();
- hlist_for_each_entry_rcu(r, node, &fib_rules, hlist) {
+ fib_rules = fib_rules_ns();
+ hlist_for_each_entry_rcu(r, node, fib_rules, hlist) {
if (((saddr^r->r_src) & r->r_srcmask) ||
((daddr^r->r_dst) & r->r_dstmask) ||
(r->r_tos && r->r_tos != flp->fl4_tos) ||
@@ -453,11 +470,13 @@ int inet_dump_rules(struct sk_buff *skb,
{
int idx = 0;
int s_idx = cb->args[0];
+ struct hlist_head *fib_rules;
struct fib_rule *r;
struct hlist_node *node;
rcu_read_lock();
- hlist_for_each_entry(r, node, &fib_rules, hlist) {
+ fib_rules = fib_rules_ns();
+ hlist_for_each_entry(r, node, fib_rules, hlist) {
if (idx < s_idx)
continue;
@@ -473,11 +492,80 @@ int inet_dump_rules(struct sk_buff *skb,
return skb->len;
}
-void __init fib_rules_init(void)
+#ifndef CONFIG_NET_NS
+
+int fib_rules_struct_init(void)
{
- INIT_HLIST_HEAD(&fib_rules);
- hlist_add_head(&local_rule.hlist, &fib_rules);
+ INIT_HLIST_HEAD(&fib_rules_static);
+ hlist_add_head(&local_rule.hlist, &fib_rules_static);
hlist_add_after(&local_rule.hlist, &main_rule.hlist);
hlist_add_after(&main_rule.hlist, &default_rule.hlist);
+ return 0;
+}
+
+#else
+
+static struct fib_rule *fib_rule_create(struct fib_rule *orig,
+ struct fib_rule *prev)
+{
+ struct fib_rule *p;
+
+ p = kmalloc(sizeof(*p), GFP_KERNEL);
+ if (p == NULL)
+ goto out;
+ memcpy(p, orig, sizeof(*p));
+ if (prev != NULL)
+ hlist_add_after(&prev->hlist, &p->hlist);
+ else
+ hlist_add_head(&p->hlist, fib_rules_ns());
+out:
+ return p;
+}
+
+int fib_rules_struct_init(void)
+{
+ struct hlist_head *fib_rules;
+ struct fib_rule *p, *q;
+
+ fib_rules = fib_rules_ns();
+ INIT_HLIST_HEAD(fib_rules);
+ p = fib_rule_create(&local_rule, NULL);
+ if (p == NULL)
+ goto out_rule;
+ q = fib_rule_create(&main_rule, p);
+ if (q == NULL)
+ goto out_rule;
+ p = q;
+ q = fib_rule_create(&default_rule, p);
+ if (q == NULL)
+ goto out_rule;
+ return 0;
+
+out_rule:
+ while (!hlist_empty(fib_rules)) {
+ p = hlist_entry(fib_rules->first, struct fib_rule, hlist);
+ hlist_del(&p->hlist);
+ kfree(p);
+ }
+ return -ENOMEM;
+}
+
+void fib_rules_struct_fini(void)
+{
+ struct fib_rule *r, *nxt;
+
+ for (r = hlist_entry(fib_rules_ns()->first, struct fib_rule, hlist);
+ r != NULL; r = nxt) {
+ nxt = hlist_entry(r->hlist.next, struct fib_rule, hlist);
+ hlist_del_rcu(&r->hlist);
+ r->r_dead = 1;
+ fib_rule_put(r);
+ }
+}
+
+#endif
+
+void __init fib_rules_notif_init(void)
+{
register_netdevice_notifier(&fib_rules_notifier);
}
--- ./net/ipv4/fib_semantics.c.vensrt Mon Mar 20 08:53:29 2006
+++ ./net/ipv4/fib_semantics.c Fri Jun 23 11:50:16 2006
@@ -31,6 +31,7 @@
#include <linux/inet.h>
#include <linux/inetdevice.h>
#include <linux/netdevice.h>
+#include <linux/net_ns.h>
#include <linux/if_arp.h>
#include <linux/proc_fs.h>
#include <linux/skbuff.h>
@@ -51,10 +52,21 @@
#define FSprintk(a...)
static DEFINE_RWLOCK(fib_info_lock);
-static struct hlist_head *fib_info_hash;
-static struct hlist_head *fib_info_laddrhash;
-static unsigned int fib_hash_size;
-static unsigned int fib_info_cnt;
+#ifndef CONFIG_NET_NS
+static struct hlist_head *fib_info_hash_static;
+static struct hlist_head *fib_info_laddrhash_static;
+static unsigned int fib_hash_size_static;
+static unsigned int fib_info_cnt_static;
+#define fib_info_hash(ns) fib_info_hash_static
+#define fib_info_laddrhash(ns) fib_info_laddrhash_static
+#define fib_hash_size(ns) fib_hash_size_static
+#define fib_info_cnt(ns) fib_info_cnt_static
+#else
+#define fib_info_hash(ns) ((ns)->fib4_hash)
+#define fib_info_laddrhash(ns) ((ns)->fib4_laddrhash)
+#define fib_hash_size(ns) ((ns)->fib4_hash_size)
+#define fib_info_cnt(ns) ((ns)->fib4_info_cnt)
+#endif
#define DEVINDEX_HASHBITS 8
#define DEVINDEX_HASHSIZE (1U << DEVINDEX_HASHBITS)
@@ -145,6 +157,8 @@ static const struct
void free_fib_info(struct fib_info *fi)
{
+ struct net_namespace *ns __attribute_used__ = current_net_ns;
+
if (fi->fib_dead == 0) {
printk("Freeing alive fib_info %p\n", fi);
return;
@@ -154,7 +168,7 @@ void free_fib_info(struct fib_info *fi)
dev_put(nh->nh_dev);
nh->nh_dev = NULL;
} endfor_nexthops(fi);
- fib_info_cnt--;
+ fib_info_cnt(ns)--;
kfree(fi);
}
@@ -197,9 +211,10 @@ static __inline__ int nh_comp(const stru
return 0;
}
-static inline unsigned int fib_info_hashfn(const struct fib_info *fi)
+static inline unsigned int fib_info_hashfn(const struct fib_info *fi,
+ struct net_namespace *ns)
{
- unsigned int mask = (fib_hash_size - 1);
+ unsigned int mask = (fib_hash_size(ns) - 1);
unsigned int val = fi->fib_nhs;
val ^= fi->fib_protocol;
@@ -211,13 +226,14 @@ static inline unsigned int fib_info_hash
static struct fib_info *fib_find_info(const struct fib_info *nfi)
{
+ struct net_namespace *ns = current_net_ns;
struct hlist_head *head;
struct hlist_node *node;
struct fib_info *fi;
unsigned int hash;
- hash = fib_info_hashfn(nfi);
- head = &fib_info_hash[hash];
+ hash = fib_info_hashfn(nfi, ns);
+ head = &fib_info_hash(ns)[hash];
hlist_for_each_entry(fi, node, head, fib_hash) {
if (fi->fib_nhs != nfi->fib_nhs)
@@ -237,11 +253,15 @@ static struct fib_info *fib_find_info(co
static inline unsigned int fib_devindex_hashfn(unsigned int val)
{
- unsigned int mask = DEVINDEX_HASHSIZE - 1;
+ unsigned int r, mask = DEVINDEX_HASHSIZE - 1;
- return (val ^
+ r = val ^
(val >> DEVINDEX_HASHBITS) ^
- (val >> (DEVINDEX_HASHBITS * 2))) & mask;
+ (val >> (DEVINDEX_HASHBITS * 2));
+#ifdef CONFIG_NET_NS
+ r ^= current_net_ns->hash;
+#endif
+ return r & mask;
}
/* Check, that the gateway is already configured.
@@ -564,9 +584,9 @@ out:
return 0;
}
-static inline unsigned int fib_laddr_hashfn(u32 val)
+static inline unsigned int fib_laddr_hashfn(u32 val, struct net_namespace *ns)
{
- unsigned int mask = (fib_hash_size - 1);
+ unsigned int mask = (fib_hash_size(ns) - 1);
return (val ^ (val >> 7) ^ (val >> 14)) & mask;
}
@@ -595,17 +615,18 @@ static void fib_hash_move(struct hlist_h
struct hlist_head *new_laddrhash,
unsigned int new_size)
{
+ struct net_namespace *ns = current_net_ns;
struct hlist_head *old_info_hash, *old_laddrhash;
- unsigned int old_size = fib_hash_size;
+ unsigned int old_size = fib_hash_size(ns);
unsigned int i, bytes;
write_lock(&fib_info_lock);
- old_info_hash = fib_info_hash;
- old_laddrhash = fib_info_laddrhash;
- fib_hash_size = new_size;
+ old_info_hash = fib_info_hash(ns);
+ old_laddrhash = fib_info_laddrhash(ns);
+ fib_hash_size(ns) = new_size;
for (i = 0; i < old_size; i++) {
- struct hlist_head *head = &fib_info_hash[i];
+ struct hlist_head *head = &old_info_hash[i];
struct hlist_node *node, *n;
struct fib_info *fi;
@@ -615,15 +636,15 @@ static void fib_hash_move(struct hlist_h
hlist_del(&fi->fib_hash);
- new_hash = fib_info_hashfn(fi);
+ new_hash = fib_info_hashfn(fi, ns);
dest = &new_info_hash[new_hash];
hlist_add_head(&fi->fib_hash, dest);
}
}
- fib_info_hash = new_info_hash;
+ fib_info_hash(ns) = new_info_hash;
for (i = 0; i < old_size; i++) {
- struct hlist_head *lhead = &fib_info_laddrhash[i];
+ struct hlist_head *lhead = &old_laddrhash[i];
struct hlist_node *node, *n;
struct fib_info *fi;
@@ -633,12 +654,12 @@ static void fib_hash_move(struct hlist_h
hlist_del(&fi->fib_lhash);
- new_hash = fib_laddr_hashfn(fi->fib_prefsrc);
+ new_hash = fib_laddr_hashfn(fi->fib_prefsrc, ns);
ldest = &new_laddrhash[new_hash];
hlist_add_head(&fi->fib_lhash, ldest);
}
}
- fib_info_laddrhash = new_laddrhash;
+ fib_info_laddrhash(ns) = new_laddrhash;
write_unlock(&fib_info_lock);
@@ -647,11 +668,27 @@ static void fib_hash_move(struct hlist_h
fib_hash_free(old_laddrhash, bytes);
}
+#ifdef CONFIG_NET_NS
+void fib_hashtable_destroy(void)
+{
+ struct net_namespace *ns;
+ unsigned int bytes;
+
+ ns = current_net_ns;
+ bytes = ns->fib4_hash_size * sizeof(struct hlist_head *);
+ fib_hash_free(ns->fib4_hash, bytes);
+ ns->fib4_hash = NULL;
+ fib_hash_free(ns->fib4_laddrhash, bytes);
+ ns->fib4_laddrhash = NULL;
+}
+#endif
+
struct fib_info *
fib_create_info(const struct rtmsg *r, struct kern_rta *rta,
const struct nlmsghdr *nlh, int *errp)
{
int err;
+ struct net_namespace *ns = current_net_ns;
struct fib_info *fi = NULL;
struct fib_info *ofi;
#ifdef CONFIG_IP_ROUTE_MULTIPATH
@@ -685,8 +722,8 @@ fib_create_info(const struct rtmsg *r, s
#endif
err = -ENOBUFS;
- if (fib_info_cnt >= fib_hash_size) {
- unsigned int new_size = fib_hash_size << 1;
+ if (fib_info_cnt(ns) >= fib_hash_size(ns)) {
+ unsigned int new_size = fib_hash_size(ns) << 1;
struct hlist_head *new_info_hash;
struct hlist_head *new_laddrhash;
unsigned int bytes;
@@ -706,14 +743,14 @@ fib_create_info(const struct rtmsg *r, s
fib_hash_move(new_info_hash, new_laddrhash, new_size);
}
- if (!fib_hash_size)
+ if (!fib_hash_size(ns))
goto failure;
}
fi = kmalloc(sizeof(*fi)+nhs*sizeof(struct fib_nh), GFP_KERNEL);
if (fi == NULL)
goto failure;
- fib_info_cnt++;
+ fib_info_cnt(ns)++;
memset(fi, 0, sizeof(*fi)+nhs*sizeof(struct fib_nh));
fi->fib_protocol = r->rtm_protocol;
@@ -824,11 +861,11 @@ link_it:
atomic_inc(&fi->fib_clntref);
write_lock(&fib_info_lock);
hlist_add_head(&fi->fib_hash,
- &fib_info_hash[fib_info_hashfn(fi)]);
+ &fib_info_hash(ns)[fib_info_hashfn(fi, ns)]);
if (fi->fib_prefsrc) {
struct hlist_head *head;
- head = &fib_info_laddrhash[fib_laddr_hashfn(fi->fib_prefsrc)];
+ head = &fib_info_laddrhash(ns)[fib_laddr_hashfn(fi->fib_prefsrc, ns)];
hlist_add_head(&fi->fib_lhash, head);
}
change_nexthops(fi) {
@@ -1162,15 +1199,16 @@ fib_convert_rtentry(int cmd, struct nlms
int fib_sync_down(u32 local, struct net_device *dev, int force)
{
+ struct net_namespace *ns = current_net_ns;
int ret = 0;
int scope = RT_SCOPE_NOWHERE;
if (force)
scope = -1;
- if (local && fib_info_laddrhash) {
- unsigned int hash = fib_laddr_hashfn(local);
- struct hlist_head *head = &fib_info_laddrhash[hash];
+ if (local && fib_info_laddrhash(ns)) {
+ unsigned int hash = fib_laddr_hashfn(local, ns);
+ struct hlist_head *head = &fib_info_laddrhash(ns)[hash];
struct hlist_node *node;
struct fib_info *fi;
--- ./net/ipv4/route.c.vensrt Wed Jun 21 18:53:19 2006
+++ ./net/ipv4/route.c Fri Jun 23 11:50:16 2006
@@ -267,6 +267,7 @@ struct rt_cache_iter_state {
int bucket;
};
+static struct rtable *rt_cache_get_next(struct seq_file *seq, struct rtable *r);
static struct rtable *rt_cache_get_first(struct seq_file *seq)
{
struct rtable *r = NULL;
@@ -279,21 +280,28 @@ static struct rtable *rt_cache_get_first
break;
rcu_read_unlock_bh();
}
+ if (r && !net_ns_same(r->fl.net_ns, current_net_ns))
+ r = rt_cache_get_next(seq, r);
return r;
}
static struct rtable *rt_cache_get_next(struct seq_file *seq, struct rtable *r)
{
struct rt_cache_iter_state *st = rcu_dereference(seq->private);
+ struct net_namespace *ns __attribute_used__ = current_net_ns;
+next:
r = r->u.rt_next;
while (!r) {
rcu_read_unlock_bh();
if (--st->bucket < 0)
- break;
+ goto out;
rcu_read_lock_bh();
r = rt_hash_table[st->bucket].chain;
}
+ if (!net_ns_same(r->fl.net_ns, ns))
+ goto next;
+out:
return r;
}
@@ -564,6 +572,7 @@ static inline u32 rt_score(struct rtable
static inline int compare_keys(struct flowi *fl1, struct flowi *fl2)
{
return memcmp(&fl1->nl_u.ip4_u, &fl2->nl_u.ip4_u, sizeof(fl1->nl_u.ip4_u)) == 0 &&
+ net_ns_same(fl1->net_ns, fl2->net_ns) &&
fl1->oif == fl2->oif &&
fl1->iif == fl2->iif;
}
@@ -1127,6 +1136,7 @@ void ip_rt_redirect(u32 old_gw, u32 dadd
struct rtable *rth, **rthp;
u32 skeys[2] = { saddr, 0 };
int ikeys[2] = { dev->ifindex, 0 };
+ struct net_namespace *ns __attribute_used__ = current_net_ns;
if (!in_dev)
return;
@@ -1158,6 +1168,7 @@ void ip_rt_redirect(u32 old_gw, u32 dadd
if (rth->fl.fl4_dst != daddr ||
rth->fl.fl4_src != skeys[i] ||
+ !net_ns_same(rth->fl.net_ns, ns) ||
rth->fl.oif != ikeys[k] ||
rth->fl.iif != 0) {
rthp = &rth->u.rt_next;
@@ -1643,6 +1654,9 @@ static int ip_route_input_mc(struct sk_b
dev_hold(rth->u.dst.dev);
rth->idev = in_dev_get(rth->u.dst.dev);
rth->fl.oif = 0;
+#ifdef CONFIG_NET_NS
+ rth->fl.net_ns = current_net_ns;
+#endif
rth->rt_gateway = daddr;
rth->rt_spec_dst= spec_dst;
rth->rt_type = RTN_MULTICAST;
@@ -1786,6 +1800,9 @@ static inline int __mkroute_input(struct
dev_hold(rth->u.dst.dev);
rth->idev = in_dev_get(rth->u.dst.dev);
rth->fl.oif = 0;
+#ifdef CONFIG_NET_NS
+ rth->fl.net_ns = current_net_ns;
+#endif
rth->rt_spec_dst= spec_dst;
rth->u.dst.input = ip_forward;
@@ -2087,6 +2104,7 @@ int ip_route_input(struct sk_buff *skb,
struct rtable * rth;
unsigned hash;
int iif = dev->ifindex;
+ struct net_namespace *ns __attribute_used__ = current_net_ns;
tos &= IPTOS_RT_MASK;
hash = rt_hash_code(daddr, saddr ^ (iif << 5));
@@ -2096,6 +2114,7 @@ int ip_route_input(struct sk_buff *skb,
rth = rcu_dereference(rth->u.rt_next)) {
if (rth->fl.fl4_dst == daddr &&
rth->fl.fl4_src == saddr &&
+ net_ns_same(rth->fl.net_ns, ns) &&
rth->fl.iif == iif &&
rth->fl.oif == 0 &&
#ifdef CONFIG_IP_ROUTE_FWMARK
@@ -2235,6 +2254,9 @@ static inline int __mkroute_output(struc
rth->u.dst.dev = dev_out;
dev_hold(dev_out);
rth->idev = in_dev_get(dev_out);
+#ifdef CONFIG_NET_NS
+ rth->fl.net_ns = current_net_ns;
+#endif
rth->rt_gateway = fl->fl4_dst;
rth->rt_spec_dst= fl->fl4_src;
@@ -2560,6 +2582,7 @@ int __ip_route_output_key(struct rtable
{
unsigned hash;
struct rtable *rth;
+ struct net_namespace *ns __attribute_used__ = current_net_ns;
hash = rt_hash_code(flp->fl4_dst, flp->fl4_src ^ (flp->oif << 5));
@@ -2568,6 +2591,7 @@ int __ip_route_output_key(struct rtable
rth = rcu_dereference(rth->u.rt_next)) {
if (rth->fl.fl4_dst == flp->fl4_dst &&
rth->fl.fl4_src == flp->fl4_src &&
+ net_ns_same(rth->fl.net_ns, ns) &&
rth->fl.iif == 0 &&
rth->fl.oif == flp->oif &&
#ifdef CONFIG_IP_ROUTE_FWMARK
^ permalink raw reply
* [patch 2/4] Network namespaces: cleanup of dev_base list use
From: Andrey Savochkin @ 2006-06-26 9:52 UTC (permalink / raw)
To: dlezcano
Cc: linux-kernel, netdev, serue, haveblue, clg, Andrew Morton, dev,
herbert, devel, sam, ebiederm, viro
In-Reply-To: <20060626134945.A28942@castle.nmd.msu.ru>
CONFIG_NET_NS and net_namespace structure are introduced.
List of network devices is made per-namespace.
Each namespace gets its own loopback device.
Task's net_namespace pointer is not incorporated into nsproxy structure,
since current namespace changes temporarily for processing of packets
in softirq.
Signed-off-by: Andrey Savochkin <saw@swsoft.com>
---
drivers/net/loopback.c | 70 +++++++++++--------
include/linux/init_task.h | 9 ++
include/linux/net_ns.h | 88 ++++++++++++++++++++++++
include/linux/netdevice.h | 20 ++++-
include/linux/nsproxy.h | 3
include/linux/sched.h | 3
kernel/nsproxy.c | 14 +++
net/Kconfig | 7 +
net/core/dev.c | 162 +++++++++++++++++++++++++++++++++++++++++++++-
net/core/net-sysfs.c | 24 ++++++
net/ipv4/devinet.c | 2
net/ipv6/addrconf.c | 2
net/ipv6/route.c | 3
13 files changed, 371 insertions, 36 deletions
--- ./drivers/net/loopback.c.venshd Wed Jun 21 18:50:39 2006
+++ ./drivers/net/loopback.c Fri Jun 23 11:48:09 2006
@@ -196,42 +196,56 @@ static struct ethtool_ops loopback_ethto
.set_tso = ethtool_op_set_tso,
};
-struct net_device loopback_dev = {
- .name = "lo",
- .mtu = (16 * 1024) + 20 + 20 + 12,
- .hard_start_xmit = loopback_xmit,
- .hard_header = eth_header,
- .hard_header_cache = eth_header_cache,
- .header_cache_update = eth_header_cache_update,
- .hard_header_len = ETH_HLEN, /* 14 */
- .addr_len = ETH_ALEN, /* 6 */
- .tx_queue_len = 0,
- .type = ARPHRD_LOOPBACK, /* 0x0001*/
- .rebuild_header = eth_rebuild_header,
- .flags = IFF_LOOPBACK,
- .features = NETIF_F_SG | NETIF_F_FRAGLIST
+struct net_device loopback_dev_static;
+EXPORT_SYMBOL(loopback_dev_static);
+
+void loopback_dev_dtor(struct net_device *dev)
+{
+ if (dev->priv) {
+ kfree(dev->priv);
+ dev->priv = NULL;
+ }
+ free_netdev(dev);
+}
+
+void loopback_dev_ctor(struct net_device *dev)
+{
+ struct net_device_stats *stats;
+
+ memset(dev, 0, sizeof(*dev));
+ strcpy(dev->name, "lo");
+ dev->mtu = (16 * 1024) + 20 + 20 + 12;
+ dev->hard_start_xmit = loopback_xmit;
+ dev->hard_header = eth_header;
+ dev->hard_header_cache = eth_header_cache;
+ dev->header_cache_update = eth_header_cache_update;
+ dev->hard_header_len = ETH_HLEN; /* 14 */
+ dev->addr_len = ETH_ALEN; /* 6 */
+ dev->tx_queue_len = 0;
+ dev->type = ARPHRD_LOOPBACK; /* 0x0001*/
+ dev->rebuild_header = eth_rebuild_header;
+ dev->flags = IFF_LOOPBACK;
+ dev->features = NETIF_F_SG | NETIF_F_FRAGLIST
#ifdef LOOPBACK_TSO
| NETIF_F_TSO
#endif
| NETIF_F_NO_CSUM | NETIF_F_HIGHDMA
- | NETIF_F_LLTX,
- .ethtool_ops = &loopback_ethtool_ops,
-};
-
-/* Setup and register the loopback device. */
-int __init loopback_init(void)
-{
- struct net_device_stats *stats;
+ | NETIF_F_LLTX
+ | NETIF_F_NSOK;
+ dev->ethtool_ops = &loopback_ethtool_ops;
/* Can survive without statistics */
stats = kmalloc(sizeof(struct net_device_stats), GFP_KERNEL);
if (stats) {
memset(stats, 0, sizeof(struct net_device_stats));
- loopback_dev.priv = stats;
- loopback_dev.get_stats = &get_stats;
+ dev->priv = stats;
+ dev->get_stats = &get_stats;
}
-
- return register_netdev(&loopback_dev);
-};
+}
-EXPORT_SYMBOL(loopback_dev);
+/* Setup and register the loopback device. */
+int __init loopback_init(void)
+{
+ loopback_dev_ctor(&loopback_dev_static);
+ return register_netdev(&loopback_dev_static);
+};
--- ./include/linux/init_task.h.venshd Wed Jun 21 18:53:16 2006
+++ ./include/linux/init_task.h Fri Jun 23 11:48:09 2006
@@ -87,6 +87,14 @@ extern struct nsproxy init_nsproxy;
extern struct group_info init_groups;
+#ifdef CONFIG_NET_NS
+extern struct net_namespace init_net_ns;
+#define INIT_NET_NS \
+ .net_context = &init_net_ns,
+#else
+#define INIT_NET_NS
+#endif
+
/*
* INIT_TASK is used to set up the first task table, touch at
* your own risk!. Base=0, limit=0x1fffff (=2MB)
@@ -129,6 +137,7 @@ extern struct group_info init_groups;
.signal = &init_signals, \
.sighand = &init_sighand, \
.nsproxy = &init_nsproxy, \
+ INIT_NET_NS \
.pending = { \
.list = LIST_HEAD_INIT(tsk.pending.list), \
.signal = {{0}}}, \
--- ./include/linux/net_ns.h.venshd Thu Jun 22 12:10:13 2006
+++ ./include/linux/net_ns.h Fri Jun 23 11:49:42 2006
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2006 SWsoft
+ */
+#ifndef __LINUX_NET_NS__
+#define __LINUX_NET_NS__
+
+#ifdef CONFIG_NET_NS
+
+#include <asm/atomic.h>
+#include <linux/list.h>
+#include <linux/workqueue.h>
+
+struct net_namespace {
+ atomic_t active_ref, use_ref;
+ struct list_head dev_base;
+ struct net_device *loopback;
+ unsigned int hash;
+ struct execute_work destroy_work;
+};
+
+static inline struct net_namespace *get_net_ns(struct net_namespace *ns)
+{
+ atomic_inc(&ns->active_ref);
+ return ns;
+}
+
+extern void net_ns_stop(struct net_namespace *ns);
+static inline void put_net_ns(struct net_namespace *ns)
+{
+ if (atomic_dec_and_test(&ns->active_ref))
+ net_ns_stop(ns);
+}
+
+static inline struct net_namespace *ref_net_ns(struct net_namespace *ns)
+{
+ atomic_inc(&ns->use_ref);
+ return ns;
+}
+
+extern void net_ns_free(struct net_namespace *ns);
+static inline void unref_net_ns(struct net_namespace *ns)
+{
+ if (atomic_dec_and_test(&ns->use_ref))
+ net_ns_free(ns);
+}
+
+extern struct net_namespace init_net_ns;
+#define current_net_ns (current->net_context)
+
+#define push_net_ns(to, orig) do { \
+ task_t *__cur; \
+ __cur = current; \
+ orig = __cur->net_context; \
+ __cur->net_context = ref_net_ns(to); \
+ } while (0)
+#define pop_net_ns(orig) do { \
+ task_t *__cur; \
+ struct net_namespace *__cur_ns; \
+ __cur = current; \
+ __cur_ns = __cur->net_context; \
+ __cur->net_context = orig; \
+ unref_net_ns(__cur_ns); \
+ } while (0)
+#define switch_net_ns(to) do { \
+ task_t *__cur; \
+ struct net_namespace *__cur_ns; \
+ __cur = current; \
+ __cur_ns = __cur->net_context; \
+ __cur->net_context = ref_net_ns(to); \
+ unref_net_ns(__cur_ns); \
+ } while (0)
+
+#define net_ns_same(target, context) ((target) == (context))
+
+#else /* CONFIG_NET_NS */
+
+struct net_namespace;
+
+#define get_net_ns(x) NULL
+#define put_net_ns(x) ((void)0)
+
+#define current_net_ns NULL
+
+#define net_ns_same(target, context) 1
+
+#endif /* CONFIG_NET_NS */
+
+#endif /* __LINUX_NET_NS__ */
--- ./include/linux/netdevice.h.venshd Thu Jun 22 18:57:50 2006
+++ ./include/linux/netdevice.h Fri Jun 23 11:48:15 2006
@@ -311,6 +311,7 @@ struct net_device
#define NETIF_F_TSO 2048 /* Can offload TCP/IP segmentation */
#define NETIF_F_LLTX 4096 /* LockLess TX */
#define NETIF_F_UFO 8192 /* Can offload UDP Large Send*/
+#define NETIF_F_NSOK 16384 /* OK for namespaces */
#define NETIF_F_GEN_CSUM (NETIF_F_NO_CSUM | NETIF_F_HW_CSUM)
#define NETIF_F_ALL_CSUM (NETIF_F_IP_CSUM | NETIF_F_GEN_CSUM)
@@ -366,6 +367,10 @@ struct net_device
int promiscuity;
int allmulti;
+#ifdef CONFIG_NET_NS
+ struct net_namespace *net_ns;
+#endif
+
/* Protocol specific pointers */
@@ -542,17 +547,26 @@ struct packet_type {
#include <linux/interrupt.h>
#include <linux/notifier.h>
+#include <linux/net_ns.h>
-extern struct net_device loopback_dev; /* The loopback */
+extern struct net_device loopback_dev_static;
+#ifndef CONFIG_NET_NS
+#define loopback_dev loopback_dev_static /* The loopback */
extern struct list_head dev_base_head; /* All devices */
+#else
+#define loopback_dev (*current_net_ns->loopback)
+#define dev_base_head (current_net_ns->dev_base)
+#endif
extern rwlock_t dev_base_lock; /* Device list lock */
#define for_each_netdev(p) list_for_each_entry(p, &dev_base_head, dev_list)
/* DO NOT USE first_netdev/next_netdev, use loop defined above */
#define first_netdev() ({ \
- list_empty(&dev_base_head) ? NULL : \
- list_entry(dev_base_head.next, \
+ struct list_head *__base; \
+ __base = &dev_base_head; \
+ list_empty(__base) ? NULL : \
+ list_entry(__base->next, \
struct net_device, \
dev_list); \
})
--- ./include/linux/nsproxy.h.venshd Wed Jun 21 18:53:17 2006
+++ ./include/linux/nsproxy.h Fri Jun 23 11:48:15 2006
@@ -33,6 +33,7 @@ struct nsproxy *dup_namespaces(struct ns
int copy_namespaces(int flags, struct task_struct *tsk);
void get_task_namespaces(struct task_struct *tsk);
void free_nsproxy(struct nsproxy *ns);
+void release_net_context(struct task_struct *tsk);
static inline void put_nsproxy(struct nsproxy *ns)
{
@@ -48,5 +49,7 @@ static inline void exit_task_namespaces(
put_nsproxy(ns);
p->nsproxy = NULL;
}
+ release_net_context(p);
}
+
#endif
--- ./include/linux/sched.h.venshd Wed Jun 21 18:53:17 2006
+++ ./include/linux/sched.h Fri Jun 23 11:48:15 2006
@@ -887,6 +887,9 @@ struct task_struct {
struct files_struct *files;
/* namespaces */
struct nsproxy *nsproxy;
+#ifdef CONFIG_NET_NS
+ struct net_namespace *net_context;
+#endif
/* signal handlers */
struct signal_struct *signal;
struct sighand_struct *sighand;
--- ./kernel/nsproxy.c.venshd Wed Jun 21 18:53:17 2006
+++ ./kernel/nsproxy.c Fri Jun 23 11:48:15 2006
@@ -16,6 +16,7 @@
#include <linux/module.h>
#include <linux/version.h>
#include <linux/nsproxy.h>
+#include <linux/net_ns.h>
#include <linux/namespace.h>
#include <linux/utsname.h>
@@ -84,6 +85,7 @@ int copy_namespaces(int flags, struct ta
return 0;
get_nsproxy(old_ns);
+ (void) get_net_ns(tsk->net_context); /* for pointer copied by memcpy */
if (!(flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC)))
return 0;
@@ -134,3 +136,15 @@ void free_nsproxy(struct nsproxy *ns)
put_ipc_ns(ns->ipc_ns);
kfree(ns);
}
+
+void release_net_context(struct task_struct *tsk)
+{
+#ifdef CONFIG_NET_NS
+ struct net_namespace *net_ns;
+
+ net_ns = tsk->net_context;
+ /* do not get refcounter here, nobody can put it later */
+ tsk->net_context = &init_net_ns;
+ put_net_ns(net_ns);
+#endif
+}
--- ./net/Kconfig.venshd Wed Jun 21 18:53:22 2006
+++ ./net/Kconfig Fri Jun 23 11:48:15 2006
@@ -66,6 +66,13 @@ source "net/ipv6/Kconfig"
endif # if INET
+config NET_NS
+ bool "Network Namespaces"
+ help
+ This option enables multiple independent network namespaces,
+ each having own network devices, IP addresses, routes, and so on.
+ If unsure, answer N.
+
config NETWORK_SECMARK
bool "Security Marking"
help
--- ./net/core/dev.c.venshd Thu Jun 22 17:40:13 2006
+++ ./net/core/dev.c Fri Jun 23 11:48:15 2006
@@ -91,6 +91,7 @@
#include <linux/if_ether.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
+#include <linux/net_ns.h>
#include <linux/notifier.h>
#include <linux/skbuff.h>
#include <net/sock.h>
@@ -177,8 +178,10 @@ static spinlock_t net_dma_event_lock;
DEFINE_RWLOCK(dev_base_lock);
EXPORT_SYMBOL(dev_base_lock);
+#ifndef CONFIG_NET_NS
LIST_HEAD(dev_base_head);
EXPORT_SYMBOL(dev_base_head);
+#endif
#define NETDEV_HASHBITS 8
static struct hlist_head dev_name_head[1<<NETDEV_HASHBITS];
@@ -187,6 +190,9 @@ static struct hlist_head dev_index_head[
static inline struct hlist_head *dev_name_hash(const char *name)
{
unsigned hash = full_name_hash(name, strnlen(name, IFNAMSIZ));
+#ifdef CONFIG_NET_NS
+ hash ^= current_net_ns->hash;
+#endif
return &dev_name_head[hash & ((1<<NETDEV_HASHBITS)-1)];
}
@@ -211,10 +217,12 @@ DEFINE_PER_CPU(struct softnet_data, soft
extern int netdev_sysfs_init(void);
extern int netdev_register_sysfs(struct net_device *);
extern void netdev_unregister_sysfs(struct net_device *);
+extern int netdev_rename_sysfs(struct net_device *);
#else
#define netdev_sysfs_init() (0)
#define netdev_register_sysfs(dev) (0)
#define netdev_unregister_sysfs(dev) do { } while(0)
+#define netdev_rename_sysfs(dev) (0)
#endif
@@ -474,10 +482,13 @@ __setup("netdev=", netdev_boot_setup);
struct net_device *__dev_get_by_name(const char *name)
{
struct hlist_node *p;
+ struct net_namespace *ns __attribute_used__ = current_net_ns;
hlist_for_each(p, dev_name_hash(name)) {
struct net_device *dev
= hlist_entry(p, struct net_device, name_hlist);
+ if (!net_ns_same(dev->net_ns, ns))
+ continue;
if (!strncmp(dev->name, name, IFNAMSIZ))
return dev;
}
@@ -740,7 +751,7 @@ int dev_change_name(struct net_device *d
else
strlcpy(dev->name, newname, IFNAMSIZ);
- err = class_device_rename(&dev->class_dev, dev->name);
+ err = netdev_rename_sysfs(dev);
if (!err) {
hlist_del(&dev->name_hlist);
hlist_add_head(&dev->name_hlist, dev_name_hash(dev->name));
@@ -1531,7 +1542,14 @@ static void net_tx_action(struct softirq
clear_bit(__LINK_STATE_SCHED, &dev->state);
if (spin_trylock(&dev->queue_lock)) {
+#ifdef CONFIG_NET_NS
+ struct net_namespace *orig_net_ns;
+ push_net_ns(dev->net_ns, orig_net_ns);
+#endif
qdisc_run(dev);
+#ifdef CONFIG_NET_NS
+ pop_net_ns(orig_net_ns);
+#endif
spin_unlock(&dev->queue_lock);
} else {
netif_schedule(dev);
@@ -1618,6 +1636,7 @@ int netif_receive_skb(struct sk_buff *sk
{
struct packet_type *ptype, *pt_prev;
struct net_device *orig_dev;
+ struct net_namespace *orig_net_ns __attribute_used__;
int ret = NET_RX_DROP;
unsigned short type;
@@ -1636,6 +1655,10 @@ int netif_receive_skb(struct sk_buff *sk
if (!orig_dev)
return NET_RX_DROP;
+#ifdef CONFIG_NET_NS
+ push_net_ns(skb->dev->net_ns, orig_net_ns);
+#endif
+
__get_cpu_var(netdev_rx_stat).total++;
skb->h.raw = skb->nh.raw = skb->data;
@@ -1706,6 +1729,9 @@ ncls:
out:
rcu_read_unlock();
+#ifdef CONFIG_NET_NS
+ pop_net_ns(orig_net_ns);
+#endif
return ret;
}
@@ -2732,6 +2758,7 @@ int register_netdevice(struct net_device
{
struct hlist_head *head;
struct hlist_node *p;
+ struct net_namespace *ns __attribute_used__ = current_net_ns;
int ret;
BUG_ON(dev_boot_phase);
@@ -2749,9 +2776,19 @@ int register_netdevice(struct net_device
spin_lock_init(&dev->ingress_lock);
#endif
+#ifdef CONFIG_NET_NS
+ dev->net_ns = ref_net_ns(ns);
+ /*
+ * loopback device doesn't hold active reference: it doesn't prevent
+ * stopping of net_namespace
+ */
+ if (dev != ns->loopback)
+ get_net_ns(ns);
+#endif
+
ret = alloc_divert_blk(dev);
if (ret)
- goto out;
+ goto out_divert;
dev->iflink = -1;
@@ -2779,6 +2816,8 @@ int register_netdevice(struct net_device
hlist_for_each(p, head) {
struct net_device *d
= hlist_entry(p, struct net_device, name_hlist);
+ if (!net_ns_same(d->net_ns, ns))
+ continue;
if (!strncmp(d->name, dev->name, IFNAMSIZ)) {
ret = -EEXIST;
goto out_err;
@@ -2852,6 +2891,13 @@ out:
return ret;
out_err:
free_divert_blk(dev);
+out_divert:
+#ifdef CONFIG_NET_NS
+ unref_net_ns(ns);
+ if (dev != ns->loopback)
+ put_net_ns(ns);
+ dev->net_ns = NULL;
+#endif
goto out;
}
@@ -2977,9 +3023,13 @@ static DEFINE_MUTEX(net_todo_run_mutex);
void netdev_run_todo(void)
{
struct list_head list;
+ struct net_namespace *orig_net_ns __attribute_used__;
/* Need to guard against multiple cpu's getting out of order. */
mutex_lock(&net_todo_run_mutex);
+#ifdef CONFIG_NET_NS
+ push_net_ns(current_net_ns, orig_net_ns);
+#endif
/* Not safe to do outside the semaphore. We must not return
* until all unregister events invoked by the local processor
@@ -3006,6 +3056,9 @@ void netdev_run_todo(void)
continue;
}
+#ifdef CONFIG_NET_NS
+ switch_net_ns(dev->net_ns);
+#endif
netdev_unregister_sysfs(dev);
dev->reg_state = NETREG_UNREGISTERED;
@@ -3025,6 +3078,9 @@ void netdev_run_todo(void)
}
out:
+#ifdef CONFIG_NET_NS
+ pop_net_ns(orig_net_ns);
+#endif
mutex_unlock(&net_todo_run_mutex);
}
@@ -3077,6 +3133,17 @@ EXPORT_SYMBOL(alloc_netdev);
*/
void free_netdev(struct net_device *dev)
{
+#ifdef CONFIG_NET_NS
+ struct net_namespace *ns;
+
+ ns = dev->net_ns;
+ if (ns != NULL) {
+ unref_net_ns(ns);
+ if (dev != ns->loopback)
+ put_net_ns(ns);
+ dev->net_ns = NULL;
+ }
+#endif
#ifdef CONFIG_SYSFS
/* Compatibility with error handling in drivers */
if (dev->reg_state == NETREG_UNINITIALIZED) {
@@ -3087,6 +3154,13 @@ void free_netdev(struct net_device *dev)
BUG_ON(dev->reg_state != NETREG_UNREGISTERED);
dev->reg_state = NETREG_RELEASED;
+#ifdef CONFIG_NET_NS
+ if (ns != NULL && ns != &init_net_ns) {
+ kfree((char *)dev - dev->padded);
+ return;
+ }
+#endif
+
/* will free via class release */
class_device_put(&dev->class_dev);
#else
@@ -3323,6 +3397,90 @@ static int __init netdev_dma_register(vo
static int __init netdev_dma_register(void) { return -ENODEV; }
#endif /* CONFIG_NET_DMA */
+#ifdef CONFIG_NET_NS
+struct net_namespace init_net_ns = {
+ .active_ref = ATOMIC_INIT(2),
+ /* one for init_task->net_context,
+ one not to let init_net_ns go away */
+ .use_ref = ATOMIC_INIT(1), /* for active references */
+ .dev_base = LIST_HEAD_INIT(init_net_ns.dev_base),
+ .loopback = &loopback_dev_static,
+};
+
+extern void loopback_dev_ctor(struct net_device *dev);
+extern void loopback_dev_dtor(struct net_device *dev);
+int net_ns_start(void)
+{
+ struct net_namespace *ns, *orig_ns;
+ struct net_device *dev;
+ task_t *task;
+ int err;
+
+ err = -ENOMEM;
+ ns = kmalloc(sizeof(*ns), GFP_KERNEL);
+ if (ns == NULL)
+ goto out_ns;
+ dev = kmalloc(sizeof(*dev), GFP_KERNEL);
+ if (dev == NULL)
+ goto out_dev;
+ loopback_dev_ctor(dev);
+ dev->destructor = loopback_dev_dtor;
+
+ memset(ns, 0, sizeof(*ns));
+ atomic_set(&ns->active_ref, 1);
+ atomic_set(&ns->use_ref, 1);
+ INIT_LIST_HEAD(&ns->dev_base);
+ ns->hash = net_random();
+ ns->loopback = dev;
+
+ task = current;
+ orig_ns = task->net_context;
+ task->net_context = ns;
+ err = register_netdev(dev);
+ if (err)
+ goto out_register;
+ put_net_ns(orig_ns);
+ return 0;
+
+out_register:
+ dev->destructor(dev);
+ task->net_context = orig_ns;
+ BUG_ON(atomic_read(&ns->active_ref) != 1);
+out_dev:
+ kfree(ns);
+out_ns:
+ return err;
+}
+EXPORT_SYMBOL(net_ns_start);
+
+void net_ns_free(struct net_namespace *ns)
+{
+ kfree(ns);
+}
+EXPORT_SYMBOL(net_ns_free);
+
+/* destroy loopback device and protocol datastructures in process context */
+static void net_ns_destroy(void *data)
+{
+ struct net_namespace *ns, *orig_ns;
+
+ ns = data;
+ push_net_ns(ns, orig_ns);
+ unregister_netdev(ns->loopback);
+ BUG_ON(!list_empty(&ns->dev_base));
+ pop_net_ns(orig_ns);
+
+ /* drop (hopefully) final reference */
+ unref_net_ns(ns);
+}
+
+void net_ns_stop(struct net_namespace *ns)
+{
+ execute_in_process_context(net_ns_destroy, ns, &ns->destroy_work);
+}
+EXPORT_SYMBOL(net_ns_stop);
+#endif
+
/*
* Initialize the DEV module. At boot time this walks the device list and
* unhooks any devices that fail to initialise (normally hardware not
--- ./net/core/net-sysfs.c.venshd Wed Jun 21 18:51:08 2006
+++ ./net/core/net-sysfs.c Fri Jun 23 11:48:15 2006
@@ -13,6 +13,7 @@
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/netdevice.h>
+#include <linux/net_ns.h>
#include <linux/if_arp.h>
#include <net/sock.h>
#include <linux/rtnetlink.h>
@@ -445,6 +446,12 @@ static struct class net_class = {
void netdev_unregister_sysfs(struct net_device * net)
{
+#ifdef CONFIG_NET_NS
+ if (current_net_ns != &init_net_ns)
+ /* not supported yet: sysfs virtualization is required */
+ return;
+#endif
+
class_device_del(&(net->class_dev));
}
@@ -454,6 +461,12 @@ int netdev_register_sysfs(struct net_dev
struct class_device *class_dev = &(net->class_dev);
struct attribute_group **groups = net->sysfs_groups;
+#ifdef CONFIG_NET_NS
+ if (current_net_ns != &init_net_ns)
+ /* not supported yet: sysfs virtualization is required */
+ return 0;
+#endif
+
class_device_initialize(class_dev);
class_dev->class = &net_class;
class_dev->class_data = net;
@@ -474,6 +487,17 @@ int netdev_register_sysfs(struct net_dev
return class_device_add(class_dev);
}
+int netdev_rename_sysfs(struct net_device *dev)
+{
+#ifdef CONFIG_NET_NS
+ if (current_net_ns != &init_net_ns)
+ /* not supported yet: sysfs virtualization is required */
+ return 0;
+#endif
+
+ return class_device_rename(&dev->class_dev, dev->name);
+}
+
int netdev_sysfs_init(void)
{
return class_register(&net_class);
--- ./net/ipv4/devinet.c.venshd Thu Jun 22 12:03:08 2006
+++ ./net/ipv4/devinet.c Fri Jun 23 11:48:15 2006
@@ -190,7 +190,7 @@ static void inetdev_destroy(struct in_de
ASSERT_RTNL();
dev = in_dev->dev;
- if (dev == &loopback_dev)
+ if (dev == &loopback_dev_static)
return;
in_dev->dead = 1;
--- ./net/ipv6/addrconf.c.venshd Thu Jun 22 12:03:08 2006
+++ ./net/ipv6/addrconf.c Fri Jun 23 11:48:15 2006
@@ -2277,7 +2277,7 @@ static int addrconf_ifdown(struct net_de
ASSERT_RTNL();
- if (dev == &loopback_dev && how == 1)
+ if (dev == &loopback_dev_static && how == 1)
how = 0;
rt6_ifdown(dev);
--- ./net/ipv6/route.c.venshd Wed Jun 21 18:53:20 2006
+++ ./net/ipv6/route.c Fri Jun 23 11:48:15 2006
@@ -125,7 +125,7 @@ struct rt6_info ip6_null_entry = {
.dst = {
.__refcnt = ATOMIC_INIT(1),
.__use = 1,
- .dev = &loopback_dev,
+ /* .dev = &loopback_dev, */
.obsolete = -1,
.error = -ENETUNREACH,
.metrics = { [RTAX_HOPLIMIT - 1] = 255, },
@@ -2268,6 +2268,7 @@ void __init ip6_route_init(void)
#ifdef CONFIG_XFRM
xfrm6_init();
#endif
+ ip6_null_entry.u.dst.dev = &loopback_dev;
}
void ip6_route_cleanup(void)
^ permalink raw reply
* [patch 1/4] Network namespaces: cleanup of dev_base list use
From: Andrey Savochkin @ 2006-06-26 9:49 UTC (permalink / raw)
To: dlezcano
Cc: linux-kernel, netdev, serue, haveblue, clg, Andrew Morton, dev,
herbert, devel, sam, ebiederm, viro
Cleanup of dev_base list use, with the aim to make device list per-namespace.
In almost every occasion, use of dev_base variable and dev->next pointer
could be easily replaced by for_each_netdev loop.
A few most complicated places were converted to using
first_netdev()/next_netdev().
Signed-off-by: Andrey Savochkin <saw@swsoft.com>
---
arch/s390/appldata/appldata_net_sum.c | 2
arch/sparc64/solaris/ioctl.c | 2
drivers/block/aoe/aoecmd.c | 8 ++-
drivers/net/wireless/strip.c | 4 -
drivers/parisc/led.c | 2
include/linux/netdevice.h | 28 +++++++++++--
net/8021q/vlan.c | 4 -
net/8021q/vlanproc.c | 10 ++--
net/bridge/br_if.c | 4 -
net/bridge/br_ioctl.c | 4 +
net/bridge/br_netlink.c | 3 -
net/core/dev.c | 70 ++++++++++++----------------------
net/core/dev_mcast.c | 4 -
net/core/rtnetlink.c | 18 ++++----
net/decnet/af_decnet.c | 11 +++--
net/decnet/dn_dev.c | 17 ++++----
net/decnet/dn_fib.c | 2
net/decnet/dn_route.c | 12 ++---
net/ipv4/devinet.c | 15 ++++---
net/ipv4/igmp.c | 25 +++++++-----
net/ipv6/addrconf.c | 28 ++++++++-----
net/ipv6/anycast.c | 22 ++++++----
net/ipv6/mcast.c | 20 +++++----
net/llc/llc_core.c | 7 ++-
net/netrom/nr_route.c | 4 -
net/rose/rose_route.c | 8 ++-
net/sched/sch_api.c | 8 ++-
net/sctp/protocol.c | 2
net/tipc/eth_media.c | 12 +++--
29 files changed, 200 insertions, 156 deletions
--- ./arch/s390/appldata/appldata_net_sum.c.vedevbase Mon Mar 20 08:53:29 2006
+++ ./arch/s390/appldata/appldata_net_sum.c Thu Jun 22 12:03:07 2006
@@ -108,7 +108,7 @@ static void appldata_get_net_sum_data(vo
tx_dropped = 0;
collisions = 0;
read_lock(&dev_base_lock);
- for (dev = dev_base; dev != NULL; dev = dev->next) {
+ for_each_netdev(dev) {
if (dev->get_stats == NULL) {
continue;
}
--- ./arch/sparc64/solaris/ioctl.c.vedevbase Mon Mar 20 08:53:29 2006
+++ ./arch/sparc64/solaris/ioctl.c Thu Jun 22 12:03:07 2006
@@ -686,7 +686,7 @@ static inline int solaris_i(unsigned int
int i = 0;
read_lock_bh(&dev_base_lock);
- for (d = dev_base; d; d = d->next) i++;
+ for_each_netdev(d) i++;
read_unlock_bh(&dev_base_lock);
if (put_user (i, (int __user *)A(arg)))
--- ./drivers/block/aoe/aoecmd.c.vedevbase Wed Jun 21 18:50:28 2006
+++ ./drivers/block/aoe/aoecmd.c Thu Jun 22 12:03:07 2006
@@ -204,14 +204,17 @@ aoecmd_cfg_pkts(ushort aoemajor, unsigne
sl = sl_tail = NULL;
read_lock(&dev_base_lock);
- for (ifp = dev_base; ifp; dev_put(ifp), ifp = ifp->next) {
+ for_each_netdev(dev) {
dev_hold(ifp);
- if (!is_aoe_netif(ifp))
+ if (!is_aoe_netif(ifp)) {
+ dev_put(ifp);
continue;
+ }
skb = new_skb(ifp, sizeof *h + sizeof *ch);
if (skb == NULL) {
printk(KERN_INFO "aoe: aoecmd_cfg: skb alloc failure\n");
+ dev_put(ifp);
continue;
}
if (sl_tail == NULL)
@@ -229,6 +232,7 @@ aoecmd_cfg_pkts(ushort aoemajor, unsigne
skb->next = sl;
sl = skb;
+ dev_put(ifp);
}
read_unlock(&dev_base_lock);
--- ./drivers/net/wireless/strip.c.vedevbase Wed Jun 21 18:50:43 2006
+++ ./drivers/net/wireless/strip.c Thu Jun 22 12:03:07 2006
@@ -1970,8 +1970,7 @@ static struct net_device *get_strip_dev(
sizeof(zero_address))) {
struct net_device *dev;
read_lock_bh(&dev_base_lock);
- dev = dev_base;
- while (dev) {
+ for_each_netdev(dev) {
if (dev->type == strip_info->dev->type &&
!memcmp(dev->dev_addr,
&strip_info->true_dev_addr,
@@ -1982,7 +1981,6 @@ static struct net_device *get_strip_dev(
read_unlock_bh(&dev_base_lock);
return (dev);
}
- dev = dev->next;
}
read_unlock_bh(&dev_base_lock);
}
--- ./drivers/parisc/led.c.vedevbase Wed Jun 21 18:52:58 2006
+++ ./drivers/parisc/led.c Thu Jun 22 12:03:07 2006
@@ -368,7 +368,7 @@ static __inline__ int led_get_net_activi
* for reading should be OK */
read_lock(&dev_base_lock);
rcu_read_lock();
- for (dev = dev_base; dev; dev = dev->next) {
+ for_each_netdev(dev) {
struct net_device_stats *stats;
struct in_device *in_dev = __in_dev_get_rcu(dev);
if (!in_dev || !in_dev->ifa_list)
--- ./include/linux/netdevice.h.vedevbase Wed Jun 21 18:53:17 2006
+++ ./include/linux/netdevice.h Thu Jun 22 18:57:50 2006
@@ -289,8 +289,8 @@ struct net_device
unsigned long state;
- struct net_device *next;
-
+ struct list_head dev_list;
+
/* The device initialization function. Called only once. */
int (*init)(struct net_device *dev);
@@ -543,9 +543,27 @@ struct packet_type {
#include <linux/interrupt.h>
#include <linux/notifier.h>
-extern struct net_device loopback_dev; /* The loopback */
-extern struct net_device *dev_base; /* All devices */
-extern rwlock_t dev_base_lock; /* Device list lock */
+extern struct net_device loopback_dev; /* The loopback */
+extern struct list_head dev_base_head; /* All devices */
+extern rwlock_t dev_base_lock; /* Device list lock */
+
+#define for_each_netdev(p) list_for_each_entry(p, &dev_base_head, dev_list)
+
+/* DO NOT USE first_netdev/next_netdev, use loop defined above */
+#define first_netdev() ({ \
+ list_empty(&dev_base_head) ? NULL : \
+ list_entry(dev_base_head.next, \
+ struct net_device, \
+ dev_list); \
+ })
+#define next_netdev(dev) ({ \
+ struct list_head *__next; \
+ __next = (dev)->dev_list.next; \
+ __next == &dev_base_head ? NULL : \
+ list_entry(__next, \
+ struct net_device, \
+ dev_list); \
+ })
extern int netdev_boot_setup_check(struct net_device *dev);
extern unsigned long netdev_boot_base(const char *prefix, int unit);
--- ./net/8021q/vlan.c.vedevbase Wed Jun 21 18:51:08 2006
+++ ./net/8021q/vlan.c Thu Jun 22 12:03:07 2006
@@ -121,8 +121,8 @@ static void __exit vlan_cleanup_devices(
struct net_device *dev, *nxt;
rtnl_lock();
- for (dev = dev_base; dev; dev = nxt) {
- nxt = dev->next;
+ for (dev = first_netdev(); dev; dev = nxt) {
+ nxt = next_netdev(dev);
if (dev->priv_flags & IFF_802_1Q_VLAN) {
unregister_vlan_dev(VLAN_DEV_INFO(dev)->real_dev,
VLAN_DEV_INFO(dev)->vlan_id);
--- ./net/8021q/vlanproc.c.vedevbase Mon Mar 20 08:53:29 2006
+++ ./net/8021q/vlanproc.c Thu Jun 22 12:03:07 2006
@@ -242,7 +242,7 @@ int vlan_proc_rem_dev(struct net_device
static struct net_device *vlan_skip(struct net_device *dev)
{
while (dev && !(dev->priv_flags & IFF_802_1Q_VLAN))
- dev = dev->next;
+ dev = next_netdev(dev);
return dev;
}
@@ -258,8 +258,8 @@ static void *vlan_seq_start(struct seq_f
if (*pos == 0)
return SEQ_START_TOKEN;
- for (dev = vlan_skip(dev_base); dev && i < *pos;
- dev = vlan_skip(dev->next), ++i);
+ for (dev = vlan_skip(first_netdev()); dev && i < *pos;
+ dev = vlan_skip(next_netdev(dev)), ++i);
return (i == *pos) ? dev : NULL;
}
@@ -269,8 +269,8 @@ static void *vlan_seq_next(struct seq_fi
++*pos;
return vlan_skip((v == SEQ_START_TOKEN)
- ? dev_base
- : ((struct net_device *)v)->next);
+ ? first_netdev()
+ : next_netdev((struct net_device *)v));
}
static void vlan_seq_stop(struct seq_file *seq, void *v)
--- ./net/bridge/br_if.c.vedevbase Wed Jun 21 18:53:18 2006
+++ ./net/bridge/br_if.c Thu Jun 22 12:03:07 2006
@@ -468,8 +468,8 @@ void __exit br_cleanup_bridges(void)
struct net_device *dev, *nxt;
rtnl_lock();
- for (dev = dev_base; dev; dev = nxt) {
- nxt = dev->next;
+ for (dev = first_netdev(); dev; dev = nxt) {
+ nxt = next_netdev(dev);
if (dev->priv_flags & IFF_EBRIDGE)
del_br(dev->priv);
}
--- ./net/bridge/br_ioctl.c.vedevbase Mon Mar 20 08:53:29 2006
+++ ./net/bridge/br_ioctl.c Thu Jun 22 12:03:07 2006
@@ -27,7 +27,9 @@ static int get_bridge_ifindices(int *ind
struct net_device *dev;
int i = 0;
- for (dev = dev_base; dev && i < num; dev = dev->next) {
+ for_each_netdev(dev) {
+ if (i >= num)
+ break;
if (dev->priv_flags & IFF_EBRIDGE)
indices[i++] = dev->ifindex;
}
--- ./net/bridge/br_netlink.c.vedevbase Wed Jun 21 18:53:18 2006
+++ ./net/bridge/br_netlink.c Thu Jun 22 12:03:07 2006
@@ -109,7 +109,8 @@ static int br_dump_ifinfo(struct sk_buff
int err = 0;
read_lock(&dev_base_lock);
- for (dev = dev_base, idx = 0; dev; dev = dev->next) {
+ idx = 0;
+ for_each_netdev(dev) {
struct net_bridge_port *p = dev->br_port;
/* not a bridge port */
--- ./net/core/dev.c.vedevbase Wed Jun 21 18:53:18 2006
+++ ./net/core/dev.c Thu Jun 22 17:40:13 2006
@@ -174,13 +174,12 @@ static spinlock_t net_dma_event_lock;
* unregister_netdevice(), which must be called with the rtnl
* semaphore held.
*/
-struct net_device *dev_base;
-static struct net_device **dev_tail = &dev_base;
DEFINE_RWLOCK(dev_base_lock);
-
-EXPORT_SYMBOL(dev_base);
EXPORT_SYMBOL(dev_base_lock);
+LIST_HEAD(dev_base_head);
+EXPORT_SYMBOL(dev_base_head);
+
#define NETDEV_HASHBITS 8
static struct hlist_head dev_name_head[1<<NETDEV_HASHBITS];
static struct hlist_head dev_index_head[1<<NETDEV_HASHBITS];
@@ -575,7 +574,7 @@ struct net_device *dev_getbyhwaddr(unsig
ASSERT_RTNL();
- for (dev = dev_base; dev; dev = dev->next)
+ for_each_netdev(dev)
if (dev->type == type &&
!memcmp(dev->dev_addr, ha, dev->addr_len))
break;
@@ -589,7 +588,7 @@ struct net_device *dev_getfirstbyhwtype(
struct net_device *dev;
rtnl_lock();
- for (dev = dev_base; dev; dev = dev->next) {
+ for_each_netdev(dev) {
if (dev->type == type) {
dev_hold(dev);
break;
@@ -617,7 +616,7 @@ struct net_device * dev_get_by_flags(uns
struct net_device *dev;
read_lock(&dev_base_lock);
- for (dev = dev_base; dev != NULL; dev = dev->next) {
+ for_each_netdev(dev) {
if (((dev->flags ^ if_flags) & mask) == 0) {
dev_hold(dev);
break;
@@ -680,7 +679,7 @@ int dev_alloc_name(struct net_device *de
if (!inuse)
return -ENOMEM;
- for (d = dev_base; d; d = d->next) {
+ for_each_netdev(d) {
if (!sscanf(d->name, name, &i))
continue;
if (i < 0 || i >= max_netdevices)
@@ -966,7 +965,7 @@ int register_netdevice_notifier(struct n
rtnl_lock();
err = raw_notifier_chain_register(&netdev_chain, nb);
if (!err) {
- for (dev = dev_base; dev; dev = dev->next) {
+ for_each_netdev(dev) {
nb->notifier_call(nb, NETDEV_REGISTER, dev);
if (dev->flags & IFF_UP)
@@ -1903,7 +1902,7 @@ static int dev_ifconf(char __user *arg)
*/
total = 0;
- for (dev = dev_base; dev; dev = dev->next) {
+ for_each_netdev(dev) {
for (i = 0; i < NPROTO; i++) {
if (gifconf_list[i]) {
int done;
@@ -1935,26 +1934,25 @@ static int dev_ifconf(char __user *arg)
* This is invoked by the /proc filesystem handler to display a device
* in detail.
*/
-static __inline__ struct net_device *dev_get_idx(loff_t pos)
-{
- struct net_device *dev;
- loff_t i;
-
- for (i = 0, dev = dev_base; dev && i < pos; ++i, dev = dev->next);
-
- return i == pos ? dev : NULL;
-}
-
void *dev_seq_start(struct seq_file *seq, loff_t *pos)
{
+ struct net_device *dev;
+ loff_t off = 1;
read_lock(&dev_base_lock);
- return *pos ? dev_get_idx(*pos - 1) : SEQ_START_TOKEN;
+ if (!*pos)
+ return SEQ_START_TOKEN;
+ for_each_netdev(dev) {
+ if (off++ == *pos)
+ return dev;
+ }
+ return NULL;
}
void *dev_seq_next(struct seq_file *seq, void *v, loff_t *pos)
{
+ struct net_device *dev = v;
++*pos;
- return v == SEQ_START_TOKEN ? dev_base : ((struct net_device *)v)->next;
+ return v == SEQ_START_TOKEN ? first_netdev() : next_netdev(dev);
}
void dev_seq_stop(struct seq_file *seq, void *v)
@@ -2837,11 +2835,9 @@ int register_netdevice(struct net_device
set_bit(__LINK_STATE_PRESENT, &dev->state);
- dev->next = NULL;
dev_init_scheduler(dev);
write_lock_bh(&dev_base_lock);
- *dev_tail = dev;
- dev_tail = &dev->next;
+ list_add_tail(&dev->dev_list, &dev_base_head);
hlist_add_head(&dev->name_hlist, head);
hlist_add_head(&dev->index_hlist, dev_index_hash(dev->ifindex));
dev_hold(dev);
@@ -3119,8 +3115,6 @@ void synchronize_net(void)
int unregister_netdevice(struct net_device *dev)
{
- struct net_device *d, **dp;
-
BUG_ON(dev_boot_phase);
ASSERT_RTNL();
@@ -3138,23 +3132,11 @@ int unregister_netdevice(struct net_devi
dev_close(dev);
/* And unlink it from device chain. */
- for (dp = &dev_base; (d = *dp) != NULL; dp = &d->next) {
- if (d == dev) {
- write_lock_bh(&dev_base_lock);
- hlist_del(&dev->name_hlist);
- hlist_del(&dev->index_hlist);
- if (dev_tail == &dev->next)
- dev_tail = dp;
- *dp = d->next;
- write_unlock_bh(&dev_base_lock);
- break;
- }
- }
- if (!d) {
- printk(KERN_ERR "unregister net_device: '%s' not found\n",
- dev->name);
- return -ENODEV;
- }
+ write_lock_bh(&dev_base_lock);
+ list_del(&dev->dev_list);
+ hlist_del(&dev->name_hlist);
+ hlist_del(&dev->index_hlist);
+ write_unlock_bh(&dev_base_lock);
dev->reg_state = NETREG_UNREGISTERING;
--- ./net/core/dev_mcast.c.vedevbase Wed Jun 21 18:53:18 2006
+++ ./net/core/dev_mcast.c Thu Jun 22 12:03:08 2006
@@ -225,7 +225,7 @@ static void *dev_mc_seq_start(struct seq
loff_t off = 0;
read_lock(&dev_base_lock);
- for (dev = dev_base; dev; dev = dev->next) {
+ for_each_netdev(dev) {
if (off++ == *pos)
return dev;
}
@@ -236,7 +236,7 @@ static void *dev_mc_seq_next(struct seq_
{
struct net_device *dev = v;
++*pos;
- return dev->next;
+ return next_netdev(dev);
}
static void dev_mc_seq_stop(struct seq_file *seq, void *v)
--- ./net/core/rtnetlink.c.vedevbase Wed Jun 21 18:51:09 2006
+++ ./net/core/rtnetlink.c Thu Jun 22 12:03:08 2006
@@ -320,14 +320,16 @@ static int rtnetlink_dump_ifinfo(struct
struct net_device *dev;
read_lock(&dev_base_lock);
- for (dev=dev_base, idx=0; dev; dev = dev->next, idx++) {
- if (idx < s_idx)
- continue;
- if (rtnetlink_fill_ifinfo(skb, dev, RTM_NEWLINK,
- NETLINK_CB(cb->skb).pid,
- cb->nlh->nlmsg_seq, 0,
- NLM_F_MULTI) <= 0)
- break;
+ idx = 0;
+ for_each_netdev(dev) {
+ if (idx >= s_idx) {
+ if (rtnetlink_fill_ifinfo(skb, dev, RTM_NEWLINK,
+ NETLINK_CB(cb->skb).pid,
+ cb->nlh->nlmsg_seq, 0,
+ NLM_F_MULTI) <= 0)
+ break;
+ }
+ idx++;
}
read_unlock(&dev_base_lock);
cb->args[0] = idx;
--- ./net/decnet/af_decnet.c.vedevbase Wed Jun 21 18:51:09 2006
+++ ./net/decnet/af_decnet.c Thu Jun 22 12:03:08 2006
@@ -721,7 +721,7 @@ static int dn_bind(struct socket *sock,
struct sock *sk = sock->sk;
struct dn_scp *scp = DN_SK(sk);
struct sockaddr_dn *saddr = (struct sockaddr_dn *)uaddr;
- struct net_device *dev;
+ struct net_device *pdev, *dev;
int rv;
if (addr_len != sizeof(struct sockaddr_dn))
@@ -745,12 +745,15 @@ static int dn_bind(struct socket *sock,
if (!(saddr->sdn_flags & SDF_WILD)) {
if (dn_ntohs(saddr->sdn_nodeaddrl)) {
+ dev = NULL;
read_lock(&dev_base_lock);
- for(dev = dev_base; dev; dev = dev->next) {
- if (!dev->dn_ptr)
+ for_each_netdev(pdev) {
+ if (!pdev->dn_ptr)
continue;
- if (dn_dev_islocal(dev, dn_saddr2dn(saddr)))
+ if (dn_dev_islocal(pdev, dn_saddr2dn(saddr))) {
+ dev = pdev;
break;
+ }
}
read_unlock(&dev_base_lock);
if (dev == NULL)
--- ./net/decnet/dn_dev.c.vedevbase Wed Jun 21 18:51:09 2006
+++ ./net/decnet/dn_dev.c Thu Jun 22 12:03:08 2006
@@ -776,13 +776,14 @@ static int dn_dev_dump_ifaddr(struct sk_
s_idx = cb->args[0];
s_dn_idx = dn_idx = cb->args[1];
read_lock(&dev_base_lock);
- for(dev = dev_base, idx = 0; dev; dev = dev->next, idx++) {
+ idx = 0;
+ for_each_netdev(dev) {
if (idx < s_idx)
- continue;
+ goto cont;
if (idx > s_idx)
s_dn_idx = 0;
if ((dn_db = dev->dn_ptr) == NULL)
- continue;
+ goto cont;
for(ifa = dn_db->ifa_list, dn_idx = 0; ifa; ifa = ifa->ifa_next, dn_idx++) {
if (dn_idx < s_dn_idx)
@@ -795,6 +796,8 @@ static int dn_dev_dump_ifaddr(struct sk_
NLM_F_MULTI) <= 0)
goto done;
}
+cont:
+ idx++;
}
done:
read_unlock(&dev_base_lock);
@@ -1265,7 +1268,7 @@ void dn_dev_devices_off(void)
struct net_device *dev;
rtnl_lock();
- for(dev = dev_base; dev; dev = dev->next)
+ for_each_netdev(dev)
dn_dev_down(dev);
rtnl_unlock();
@@ -1276,7 +1279,7 @@ void dn_dev_devices_on(void)
struct net_device *dev;
rtnl_lock();
- for(dev = dev_base; dev; dev = dev->next) {
+ for_each_netdev(dev) {
if (dev->flags & IFF_UP)
dn_dev_up(dev);
}
@@ -1297,7 +1300,7 @@ int unregister_dnaddr_notifier(struct no
static inline struct net_device *dn_dev_get_next(struct seq_file *seq, struct net_device *dev)
{
do {
- dev = dev->next;
+ dev = next_netdev(dev);
} while(dev && !dev->dn_ptr);
return dev;
@@ -1307,7 +1310,7 @@ static struct net_device *dn_dev_get_idx
{
struct net_device *dev;
- dev = dev_base;
+ dev = first_netdev();
if (dev && !dev->dn_ptr)
dev = dn_dev_get_next(seq, dev);
if (pos) {
--- ./net/decnet/dn_fib.c.vedevbase Wed Jun 21 18:51:09 2006
+++ ./net/decnet/dn_fib.c Thu Jun 22 12:03:08 2006
@@ -631,7 +631,7 @@ static void dn_fib_del_ifaddr(struct dn_
/* Scan device list */
read_lock(&dev_base_lock);
- for(dev = dev_base; dev; dev = dev->next) {
+ for_each_netdev(dev) {
dn_db = dev->dn_ptr;
if (dn_db == NULL)
continue;
--- ./net/decnet/dn_route.c.vedevbase Wed Jun 21 18:53:19 2006
+++ ./net/decnet/dn_route.c Thu Jun 22 12:03:08 2006
@@ -923,16 +923,16 @@ static int dn_route_output_slow(struct d
goto out;
}
read_lock(&dev_base_lock);
- for(dev_out = dev_base; dev_out; dev_out = dev_out->next) {
+ for_each_netdev(dev_out) {
if (!dev_out->dn_ptr)
continue;
- if (dn_dev_islocal(dev_out, oldflp->fld_src))
- break;
+ if (dn_dev_islocal(dev_out, oldflp->fld_src)) {
+ dev_hold(dev_out);
+ goto source_ok;
+ }
}
read_unlock(&dev_base_lock);
- if (dev_out == NULL)
- goto out;
- dev_hold(dev_out);
+ goto out;
source_ok:
;
}
--- ./net/ipv4/devinet.c.vedevbase Wed Jun 21 18:51:09 2006
+++ ./net/ipv4/devinet.c Thu Jun 22 12:03:08 2006
@@ -842,7 +842,7 @@ no_in_dev:
*/
read_lock(&dev_base_lock);
rcu_read_lock();
- for (dev = dev_base; dev; dev = dev->next) {
+ for_each_netdev(dev) {
if ((in_dev = __in_dev_get_rcu(dev)) == NULL)
continue;
@@ -921,7 +921,7 @@ u32 inet_confirm_addr(const struct net_d
read_lock(&dev_base_lock);
rcu_read_lock();
- for (dev = dev_base; dev; dev = dev->next) {
+ for_each_netdev(dev) {
if ((in_dev = __in_dev_get_rcu(dev))) {
addr = confirm_addr_indev(in_dev, dst, local, scope);
if (addr)
@@ -1095,17 +1095,18 @@ static int inet_dump_ifaddr(struct sk_bu
struct in_ifaddr *ifa;
int s_ip_idx, s_idx = cb->args[0];
+ idx = 0;
s_ip_idx = ip_idx = cb->args[1];
read_lock(&dev_base_lock);
- for (dev = dev_base, idx = 0; dev; dev = dev->next, idx++) {
+ for_each_netdev(dev) {
if (idx < s_idx)
- continue;
+ goto cont;
if (idx > s_idx)
s_ip_idx = 0;
rcu_read_lock();
if ((in_dev = __in_dev_get_rcu(dev)) == NULL) {
rcu_read_unlock();
- continue;
+ goto cont;
}
for (ifa = in_dev->ifa_list, ip_idx = 0; ifa;
@@ -1120,6 +1121,8 @@ static int inet_dump_ifaddr(struct sk_bu
}
}
rcu_read_unlock();
+cont:
+ idx++;
}
done:
@@ -1171,7 +1174,7 @@ void inet_forward_change(void)
ipv4_devconf_dflt.forwarding = on;
read_lock(&dev_base_lock);
- for (dev = dev_base; dev; dev = dev->next) {
+ for_each_netdev(dev) {
struct in_device *in_dev;
rcu_read_lock();
in_dev = __in_dev_get_rcu(dev);
--- ./net/ipv4/igmp.c.vedevbase Wed Jun 21 18:53:19 2006
+++ ./net/ipv4/igmp.c Thu Jun 22 12:03:08 2006
@@ -2255,19 +2255,21 @@ struct igmp_mc_iter_state {
static inline struct ip_mc_list *igmp_mc_get_first(struct seq_file *seq)
{
+ struct net_device *dev;
struct ip_mc_list *im = NULL;
struct igmp_mc_iter_state *state = igmp_mc_seq_private(seq);
- for (state->dev = dev_base, state->in_dev = NULL;
- state->dev;
- state->dev = state->dev->next) {
+ state->dev = NULL;
+ state->in_dev = NULL;
+ for_each_netdev(dev) {
struct in_device *in_dev;
- in_dev = in_dev_get(state->dev);
+ in_dev = in_dev_get(dev);
if (!in_dev)
continue;
read_lock(&in_dev->mc_list_lock);
im = in_dev->mc_list;
if (im) {
+ state->dev = dev;
state->in_dev = in_dev;
break;
}
@@ -2286,7 +2288,7 @@ static struct ip_mc_list *igmp_mc_get_ne
read_unlock(&state->in_dev->mc_list_lock);
in_dev_put(state->in_dev);
}
- state->dev = state->dev->next;
+ state->dev = next_netdev(state->dev);
if (!state->dev) {
state->in_dev = NULL;
break;
@@ -2417,15 +2419,17 @@ struct igmp_mcf_iter_state {
static inline struct ip_sf_list *igmp_mcf_get_first(struct seq_file *seq)
{
+ struct net_device *dev;
struct ip_sf_list *psf = NULL;
struct ip_mc_list *im = NULL;
struct igmp_mcf_iter_state *state = igmp_mcf_seq_private(seq);
- for (state->dev = dev_base, state->idev = NULL, state->im = NULL;
- state->dev;
- state->dev = state->dev->next) {
+ state->dev = NULL;
+ state->im = NULL;
+ state->idev = NULL;
+ for_each_netdev(dev) {
struct in_device *idev;
- idev = in_dev_get(state->dev);
+ idev = in_dev_get(dev);
if (unlikely(idev == NULL))
continue;
read_lock(&idev->mc_list_lock);
@@ -2434,6 +2438,7 @@ static inline struct ip_sf_list *igmp_mc
spin_lock_bh(&im->lock);
psf = im->sources;
if (likely(psf != NULL)) {
+ state->dev = dev;
state->im = im;
state->idev = idev;
break;
@@ -2459,7 +2464,7 @@ static struct ip_sf_list *igmp_mcf_get_n
read_unlock(&state->idev->mc_list_lock);
in_dev_put(state->idev);
}
- state->dev = state->dev->next;
+ state->dev = next_netdev(state->dev);
if (!state->dev) {
state->idev = NULL;
goto out;
--- ./net/ipv6/addrconf.c.vedevbase Wed Jun 21 18:53:20 2006
+++ ./net/ipv6/addrconf.c Thu Jun 22 12:03:08 2006
@@ -470,7 +470,7 @@ static void addrconf_forward_change(void
struct inet6_dev *idev;
read_lock(&dev_base_lock);
- for (dev=dev_base; dev; dev=dev->next) {
+ for_each_netdev(dev) {
read_lock(&addrconf_lock);
idev = __in6_dev_get(dev);
if (idev) {
@@ -889,7 +889,7 @@ int ipv6_dev_get_saddr(struct net_device
read_lock(&dev_base_lock);
read_lock(&addrconf_lock);
- for (dev = dev_base; dev; dev=dev->next) {
+ for_each_netdev(dev) {
struct inet6_dev *idev;
struct inet6_ifaddr *ifa;
@@ -1971,7 +1971,7 @@ static void sit_add_v4_addrs(struct inet
return;
}
- for (dev = dev_base; dev != NULL; dev = dev->next) {
+ for_each_netdev(dev) {
struct in_device * in_dev = __in_dev_get_rtnl(dev);
if (in_dev && (dev->flags & IFF_UP)) {
struct in_ifaddr * ifa;
@@ -2120,7 +2120,7 @@ static void ip6_tnl_add_linklocal(struct
return;
}
/* then try to inherit it from any device */
- for (link_dev = dev_base; link_dev; link_dev = link_dev->next) {
+ for_each_netdev(link_dev) {
if (!ipv6_inherit_linklocal(idev, link_dev))
return;
}
@@ -3005,18 +3005,19 @@ static int inet6_dump_addr(struct sk_buf
struct ifmcaddr6 *ifmca;
struct ifacaddr6 *ifaca;
+ idx = 0;
s_idx = cb->args[0];
s_ip_idx = ip_idx = cb->args[1];
read_lock(&dev_base_lock);
- for (dev = dev_base, idx = 0; dev; dev = dev->next, idx++) {
+ for_each_netdev(dev) {
if (idx < s_idx)
- continue;
+ goto cont;
if (idx > s_idx)
s_ip_idx = 0;
ip_idx = 0;
if ((idev = in6_dev_get(dev)) == NULL)
- continue;
+ goto cont;
read_lock_bh(&idev->lock);
switch (type) {
case UNICAST_ADDR:
@@ -3063,6 +3064,8 @@ static int inet6_dump_addr(struct sk_buf
}
read_unlock_bh(&idev->lock);
in6_dev_put(idev);
+cont:
+ idx++;
}
done:
if (err <= 0) {
@@ -3230,17 +3233,20 @@ static int inet6_dump_ifinfo(struct sk_b
struct net_device *dev;
struct inet6_dev *idev;
+ idx = 0;
read_lock(&dev_base_lock);
- for (dev=dev_base, idx=0; dev; dev = dev->next, idx++) {
+ for_each_netdev(dev) {
if (idx < s_idx)
- continue;
+ goto cont;
if ((idev = in6_dev_get(dev)) == NULL)
- continue;
+ goto cont;
err = inet6_fill_ifinfo(skb, idev, NETLINK_CB(cb->skb).pid,
cb->nlh->nlmsg_seq, RTM_NEWLINK, NLM_F_MULTI);
in6_dev_put(idev);
if (err <= 0)
break;
+cont:
+ idx++;
}
read_unlock(&dev_base_lock);
cb->args[0] = idx;
@@ -3864,7 +3870,7 @@ void __exit addrconf_cleanup(void)
* clean dev list.
*/
- for (dev=dev_base; dev; dev=dev->next) {
+ for_each_netdev(dev) {
if ((idev = __in6_dev_get(dev)) == NULL)
continue;
addrconf_ifdown(dev, 1);
--- ./net/ipv6/anycast.c.vedevbase Wed Jun 21 18:51:09 2006
+++ ./net/ipv6/anycast.c Thu Jun 22 12:03:08 2006
@@ -428,11 +428,13 @@ int ipv6_chk_acast_addr(struct net_devic
if (dev)
return ipv6_chk_acast_dev(dev, addr);
read_lock(&dev_base_lock);
- for (dev=dev_base; dev; dev=dev->next)
- if (ipv6_chk_acast_dev(dev, addr))
- break;
+ for_each_netdev(dev)
+ if (ipv6_chk_acast_dev(dev, addr)) {
+ read_unlock(&dev_base_lock);
+ return 1;
+ }
read_unlock(&dev_base_lock);
- return dev != 0;
+ return 0;
}
@@ -446,19 +448,21 @@ struct ac6_iter_state {
static inline struct ifacaddr6 *ac6_get_first(struct seq_file *seq)
{
+ struct net_device *dev;
struct ifacaddr6 *im = NULL;
struct ac6_iter_state *state = ac6_seq_private(seq);
- for (state->dev = dev_base, state->idev = NULL;
- state->dev;
- state->dev = state->dev->next) {
+ state->dev = NULL;
+ state->idev = NULL;
+ for_each_netdev(dev) {
struct inet6_dev *idev;
- idev = in6_dev_get(state->dev);
+ idev = in6_dev_get(dev);
if (!idev)
continue;
read_lock_bh(&idev->lock);
im = idev->ac_list;
if (im) {
+ state->dev = dev;
state->idev = idev;
break;
}
@@ -477,7 +481,7 @@ static struct ifacaddr6 *ac6_get_next(st
read_unlock_bh(&state->idev->lock);
in6_dev_put(state->idev);
}
- state->dev = state->dev->next;
+ state->dev = next_netdev(state->dev);
if (!state->dev) {
state->idev = NULL;
break;
--- ./net/ipv6/mcast.c.vedevbase Wed Jun 21 18:51:09 2006
+++ ./net/ipv6/mcast.c Thu Jun 22 12:03:08 2006
@@ -2326,9 +2326,8 @@ static inline struct ifmcaddr6 *igmp6_mc
struct ifmcaddr6 *im = NULL;
struct igmp6_mc_iter_state *state = igmp6_mc_seq_private(seq);
- for (state->dev = dev_base, state->idev = NULL;
- state->dev;
- state->dev = state->dev->next) {
+ state->idev = NULL;
+ for_each_netdev(state->dev) {
struct inet6_dev *idev;
idev = in6_dev_get(state->dev);
if (!idev)
@@ -2355,7 +2354,7 @@ static struct ifmcaddr6 *igmp6_mc_get_ne
read_unlock_bh(&state->idev->lock);
in6_dev_put(state->idev);
}
- state->dev = state->dev->next;
+ state->dev = next_netdev(state->dev);
if (!state->dev) {
state->idev = NULL;
break;
@@ -2466,15 +2465,17 @@ struct igmp6_mcf_iter_state {
static inline struct ip6_sf_list *igmp6_mcf_get_first(struct seq_file *seq)
{
+ struct net_device *dev;
struct ip6_sf_list *psf = NULL;
struct ifmcaddr6 *im = NULL;
struct igmp6_mcf_iter_state *state = igmp6_mcf_seq_private(seq);
- for (state->dev = dev_base, state->idev = NULL, state->im = NULL;
- state->dev;
- state->dev = state->dev->next) {
+ state->dev = NULL;
+ state->im = NULL;
+ state->idev = NULL;
+ for_each_netdev(dev) {
struct inet6_dev *idev;
- idev = in6_dev_get(state->dev);
+ idev = in6_dev_get(dev);
if (unlikely(idev == NULL))
continue;
read_lock_bh(&idev->lock);
@@ -2483,6 +2484,7 @@ static inline struct ip6_sf_list *igmp6_
spin_lock_bh(&im->mca_lock);
psf = im->mca_sources;
if (likely(psf != NULL)) {
+ state->dev = dev;
state->im = im;
state->idev = idev;
break;
@@ -2508,7 +2510,7 @@ static struct ip6_sf_list *igmp6_mcf_get
read_unlock_bh(&state->idev->lock);
in6_dev_put(state->idev);
}
- state->dev = state->dev->next;
+ state->dev = next_netdev(state->dev);
if (!state->dev) {
state->idev = NULL;
goto out;
--- ./net/llc/llc_core.c.vedevbase Wed Jun 21 18:51:09 2006
+++ ./net/llc/llc_core.c Thu Jun 22 12:03:08 2006
@@ -161,8 +161,11 @@ static struct packet_type llc_tr_packet_
static int __init llc_init(void)
{
- if (dev_base->next)
- memcpy(llc_station_mac_sa, dev_base->next->dev_addr, ETH_ALEN);
+ struct net_device *dev;
+
+ dev = next_netdev(first_netdev());
+ if (dev)
+ memcpy(llc_station_mac_sa, dev->dev_addr, ETH_ALEN);
else
memset(llc_station_mac_sa, 0, ETH_ALEN);
dev_add_pack(&llc_packet_type);
--- ./net/netrom/nr_route.c.vedevbase Mon Mar 20 08:53:29 2006
+++ ./net/netrom/nr_route.c Thu Jun 22 12:03:08 2006
@@ -595,7 +595,7 @@ struct net_device *nr_dev_first(void)
struct net_device *dev, *first = NULL;
read_lock(&dev_base_lock);
- for (dev = dev_base; dev != NULL; dev = dev->next) {
+ for_each_netdev(dev) {
if ((dev->flags & IFF_UP) && dev->type == ARPHRD_NETROM)
if (first == NULL || strncmp(dev->name, first->name, 3) < 0)
first = dev;
@@ -615,7 +615,7 @@ struct net_device *nr_dev_get(ax25_addre
struct net_device *dev;
read_lock(&dev_base_lock);
- for (dev = dev_base; dev != NULL; dev = dev->next) {
+ for_each_netdev(dev) {
if ((dev->flags & IFF_UP) && dev->type == ARPHRD_NETROM && ax25cmp(addr, (ax25_address *)dev->dev_addr) == 0) {
dev_hold(dev);
goto out;
--- ./net/rose/rose_route.c.vedevbase Wed Jun 21 18:51:09 2006
+++ ./net/rose/rose_route.c Thu Jun 22 12:03:08 2006
@@ -600,7 +600,7 @@ struct net_device *rose_dev_first(void)
struct net_device *dev, *first = NULL;
read_lock(&dev_base_lock);
- for (dev = dev_base; dev != NULL; dev = dev->next) {
+ for_each_netdev(dev) {
if ((dev->flags & IFF_UP) && dev->type == ARPHRD_ROSE)
if (first == NULL || strncmp(dev->name, first->name, 3) < 0)
first = dev;
@@ -618,12 +618,13 @@ struct net_device *rose_dev_get(rose_add
struct net_device *dev;
read_lock(&dev_base_lock);
- for (dev = dev_base; dev != NULL; dev = dev->next) {
+ for_each_netdev(dev) {
if ((dev->flags & IFF_UP) && dev->type == ARPHRD_ROSE && rosecmp(addr, (rose_address *)dev->dev_addr) == 0) {
dev_hold(dev);
goto out;
}
}
+ dev = NULL;
out:
read_unlock(&dev_base_lock);
return dev;
@@ -634,10 +635,11 @@ static int rose_dev_exists(rose_address
struct net_device *dev;
read_lock(&dev_base_lock);
- for (dev = dev_base; dev != NULL; dev = dev->next) {
+ for_each_netdev(dev) {
if ((dev->flags & IFF_UP) && dev->type == ARPHRD_ROSE && rosecmp(addr, (rose_address *)dev->dev_addr) == 0)
goto out;
}
+ dev = NULL;
out:
read_unlock(&dev_base_lock);
return dev != NULL;
--- ./net/sched/sch_api.c.vedevbase Mon Mar 20 08:53:29 2006
+++ ./net/sched/sch_api.c Thu Jun 22 12:03:08 2006
@@ -830,12 +830,15 @@ static int tc_dump_qdisc(struct sk_buff
struct net_device *dev;
struct Qdisc *q;
+ idx = 0;
s_idx = cb->args[0];
s_q_idx = q_idx = cb->args[1];
read_lock(&dev_base_lock);
- for (dev=dev_base, idx=0; dev; dev = dev->next, idx++) {
- if (idx < s_idx)
+ for_each_netdev(dev) {
+ if (idx < s_idx) {
+ idx++;
continue;
+ }
if (idx > s_idx)
s_q_idx = 0;
read_lock_bh(&qdisc_tree_lock);
@@ -853,6 +856,7 @@ static int tc_dump_qdisc(struct sk_buff
q_idx++;
}
read_unlock_bh(&qdisc_tree_lock);
+ idx++;
}
done:
--- ./net/sctp/protocol.c.vedevbase Wed Jun 21 18:53:23 2006
+++ ./net/sctp/protocol.c Thu Jun 22 12:03:08 2006
@@ -177,7 +177,7 @@ static void __sctp_get_local_addr_list(v
struct sctp_af *af;
read_lock(&dev_base_lock);
- for (dev = dev_base; dev; dev = dev->next) {
+ for_each_netdev(dev) {
__list_for_each(pos, &sctp_address_families) {
af = list_entry(pos, struct sctp_af, list);
af->copy_addrlist(&sctp_local_addr_list, dev);
--- ./net/tipc/eth_media.c.vedevbase Wed Jun 21 18:51:09 2006
+++ ./net/tipc/eth_media.c Thu Jun 22 12:03:08 2006
@@ -118,17 +118,19 @@ static int recv_msg(struct sk_buff *buf,
static int enable_bearer(struct tipc_bearer *tb_ptr)
{
- struct net_device *dev = dev_base;
+ struct net_device *pdev, *dev;
struct eth_bearer *eb_ptr = ð_bearers[0];
struct eth_bearer *stop = ð_bearers[MAX_ETH_BEARERS];
char *driver_name = strchr((const char *)tb_ptr->name, ':') + 1;
/* Find device with specified name */
- while (dev && dev->name &&
- (memcmp(dev->name, driver_name, strlen(dev->name)))) {
- dev = dev->next;
- }
+ dev = NULL;
+ for_each_netdev(pdev)
+ if (!memcmp(pdev->name, driver_name, strlen(pdev->name))) {
+ dev = pdev;
+ break;
+ }
if (!dev)
return -ENODEV;
^ permalink raw reply
* Re: [patch 2/6] [Network namespace] Network device sharing by view
From: Andrey Savochkin @ 2006-06-26 9:47 UTC (permalink / raw)
To: dlezcano
Cc: linux-kernel, netdev, serue, haveblue, clg, Andrew Morton, dev,
herbert, devel, sam, ebiederm, viro
In-Reply-To: <20060609210625.144158000@localhost.localdomain>
Hi Daniel,
It's good that you kicked off network namespace discussion.
Although I wish you'd Cc'ed someone at OpenVZ so I could notice it earlier :).
Indeed, the first point to agree in this discussion is device list.
In your patch, you essentially introduce a data structure parallel
to the main device list, creating a "view" of this list.
I see a fundamental problem with this approach.
When a device presents an skb to the protocol layer, it needs to know to which
namespace this skb belongs.
Otherwise you would never get rid of problems with bind: what to do if device
eth1 is visible in namespace1, namespace2, and root namespace, and each
namespace has a socket bound to 0.0.0.0:80?
We have to conclude that each device should be visible only in one namespace.
In this case, instead of introducing net_ns_dev and net_ns_dev_list
structures, we can simply have a separate dev_base list head in each namespace.
Moreover, separate device list in each namespace will be in line with
making namespace isolation complete. Complete isolation will allow each
namespace to set up own tun/tap devices, have own routes, netfilter tables,
and so on.
My follow-up messages will contain the first set of patches with network
namespaces implemented in the same way as network isolation in OpenVZ.
This patchset introduces namespaces for device list and IPv4 FIB/routing.
Two technical issues are omitted to make the patch idea clearer: device moving
between namespaces, and selective routing cache flush + garbage collection.
If this patchset is agreeable, the next patchset will finalize integration
with nsproxy, add namespaces to socket lookup code and neighbour
cache, and introduce a simple device to pass traffic between namespaces.
Then we will turn to less obvious matters including netlink messages,
network statistics, representation of network information in proc and sysfs,
tuning of parameters through sysctl, IPv6 and other protocols, and
per-namespace netfilters.
Best regards
Andrey
^ permalink raw reply
* Re: -git: Why is drivers/net/wan/hdlc_generic.c:hdlc_setup() exported?
From: Christoph Hellwig @ 2006-06-26 9:35 UTC (permalink / raw)
To: David Boggs; +Cc: Adrian Bunk, netdev
In-Reply-To: <200606260611.k5Q6BUSO017145@gw.wa3dbj.vix.com>
On Sun, Jun 25, 2006 at 11:11:30PM -0700, David Boggs wrote:
> [Resent because I forgot to copy netdev on my answer]
>
> I asked Krzysztof to export that so that I could use it
> in a re-written driver for LMC WAN cards which I put out
> for comments on netdev in March.
>
> I have incorporated the comments from the March posting and
> intend to repost the new driver very soon. If you delete
> the export then I will have to write some nasty code to work
> around it.
Why can't you use alloc_hdlcdev?
^ permalink raw reply
* Re: [NETROM] Fix possible null pointer dereference.
From: David Miller @ 2006-06-26 7:05 UTC (permalink / raw)
To: ralf; +Cc: netdev
In-Reply-To: <20060623214437.GA8463@linux-mips.org>
From: Ralf Baechle <ralf@linux-mips.org>
Date: Fri, 23 Jun 2006 22:44:37 +0100
> If in nr_link_failed the neighbour list is non-empty but the node list
> is empty we'll end dereferencing a in a NULL pointer.
>
> This fixes coverity 362.
>
> Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Applied, thanks Ralf.
^ permalink raw reply
* Re: [patch 3/6] netpoll: break recursive loop in netpoll rx path
From: David Miller @ 2006-06-26 7:04 UTC (permalink / raw)
To: akpm; +Cc: netdev, nhorman, mpm
In-Reply-To: <200606250847.k5P8lUEX020903@shell0.pdx.osdl.net>
From: akpm@osdl.org
Date: Sun, 25 Jun 2006 01:47:30 -0700
> The netpoll system currently has a rx to tx path via:
>
> netpoll_rx
> __netpoll_rx
> arp_reply
> netpoll_send_skb
> dev->hard_start_tx
>
> This rx->tx loop places network drivers at risk of inadvertently causing a
> deadlock or BUG halt by recursively trying to acquire a spinlock that is
> used in both their rx and tx paths (this problem was origionally reported
> to me in the 3c59x driver, which shares a spinlock between the
> boomerang_interrupt and boomerang_start_xmit routines).
>
> This patch breaks this loop, by queueing arp frames, so that they can be
> responded to after all receive operations have been completed. Tested by
> myself and the reported with successful results.
>
> Specifically it was tested with netdump. Heres the BZ with details:
> https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=194055
>
> Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
> Acked-by: Matt Mackall <mpm@selenic.com>
> Cc: "David S. Miller" <davem@davemloft.net>
> Signed-off-by: Andrew Morton <akpm@osdl.org>
Applied, thanks.
^ permalink raw reply
* Re: [patch 2/6] netpoll: don't spin forever sending to stopped queues
From: David Miller @ 2006-06-26 7:03 UTC (permalink / raw)
To: akpm; +Cc: netdev, jeremy, mpm
In-Reply-To: <200606250847.k5P8lThc020900@shell0.pdx.osdl.net>
From: akpm@osdl.org
Date: Sun, 25 Jun 2006 01:47:29 -0700
>
> From: Jeremy Fitzhardinge <jeremy@goop.org>
>
> When transmitting a skb in netpoll_send_skb(), only retry a limited number
> of times if the device queue is stopped.
>
> Signed-off-by: Jeremy Fitzhardinge <jeremy@goop.org>
> Acked-by: Matt Mackall <mpm@selenic.com>
> Signed-off-by: Andrew Morton <akpm@osdl.org>
Applied, thanks.
^ permalink raw reply
* Re: [patch 4/6] IRDA: add some IBM think pads
From: David Miller @ 2006-06-26 7:02 UTC (permalink / raw)
To: akpm; +Cc: netdev, bcollins, randy.dunlap
In-Reply-To: <200606250847.k5P8lVUm020906@shell0.pdx.osdl.net>
From: akpm@osdl.org
Date: Sun, 25 Jun 2006 01:47:31 -0700
>
> From: Ben Collins <bcollins@ubuntu.com>
>
> [UBUNTU:nsc-ircc] Add some IBM think pads
> Add Thinkpad T60/X60/Z60/T43/R52 Infrared driver support.
>
> http://www.kernel.org/git/?p=linux/kernel/git/bcollins/ubuntu-dapper.git;a=commitdiff;h=7b8d2713435a9fb69719a282ba75e117f3f76a5b
>
> Cc: Randy Dunlap <randy.dunlap@oracle.com>
> Signed-off-by: Ben Collins <bcollins@ubuntu.com>
> Cc: "David S. Miller" <davem@davemloft.net>
> Signed-off-by: Andrew Morton <akpm@osdl.org>
Applied, thanks.
^ permalink raw reply
* Re: [patch 5/6] atm/mpc.c warning fix
From: David Miller @ 2006-06-26 7:02 UTC (permalink / raw)
To: akpm; +Cc: netdev, chas
In-Reply-To: <200606250847.k5P8lWQq020909@shell0.pdx.osdl.net>
From: akpm@osdl.org
Date: Sun, 25 Jun 2006 01:47:32 -0700
> net/atm/mpc.c: In function 'MPOA_res_reply_rcvd':
> net/atm/mpc.c:1116: warning: unused variable 'ip'
>
> Cc: chas williams <chas@cmf.nrl.navy.mil>
> Cc: "David S. Miller" <davem@davemloft.net>
> Signed-off-by: Andrew Morton <akpm@osdl.org>
Applied, thanks Andrew.
^ permalink raw reply
* Re: [PATCH] skb_find_text ignores to argument
From: David Miller @ 2006-06-26 7:01 UTC (permalink / raw)
To: kernel; +Cc: netdev
In-Reply-To: <20060625145200.GA32074@linuxace.com>
From: Phil Oester <kernel@linuxace.com>
Date: Sun, 25 Jun 2006 07:52:00 -0700
> skb_find_text takes a "to" argument which is supposed to limit how
> far into the skb it will search for the given text. At present,
> it seems to ignore that argument on the first skb, and instead
> return a match even if the text occurs beyond the limit.
>
> Patch below fixes this, after adjusting for the "from" starting
> point. This consequently fixes the netfilter string match's "--to"
> handling, which currently is broken.
>
> Signed-off-by: Phil Oester <kernel@linuxace.com>
Looks good, applied.
Thanks Phil.
^ permalink raw reply
* Re: [2.6 patch] make net/core/dev.c:netdev_nit static
From: David Miller @ 2006-06-26 6:58 UTC (permalink / raw)
To: bunk; +Cc: herbert, netdev, linux-kernel
In-Reply-To: <20060625231327.GL23314@stusta.de>
From: Adrian Bunk <bunk@stusta.de>
Date: Mon, 26 Jun 2006 01:13:27 +0200
> netdev_nit can now become static.
>
> Signed-off-by: Adrian Bunk <bunk@stusta.de>
Applied, thanks Adrian.
^ permalink raw reply
* Re: [PATCH]NET: Fix GSO problems in dev_hard_start_xmit()
From: David Miller @ 2006-06-26 6:57 UTC (permalink / raw)
To: herbert; +Cc: mchan, netdev
In-Reply-To: <20060625233602.GA22255@gondor.apana.org.au>
From: Herbert Xu <herbert@gondor.apana.org.au>
Date: Mon, 26 Jun 2006 09:36:02 +1000
> On Sun, Jun 25, 2006 at 03:38:05PM -0700, Michael Chan wrote:
> > Fix 2 problems in dev_hard_start_xmit():
> >
> > 1. nskb->next needs to link back to skb->next if hard_start_xmit()
> > returns non-zero.
> >
> > 2. Since the total number of GSO fragments may exceed MAX_SKB_FRAGS + 1,
> > it needs to stop transmitting if the netif_queue is stopped.
> >
> > Signed-off-by: Michael Chan <mchan@broadcom.com>
>
> Good catch.
>
> Acked-by: Herbert Xu <herbert@gondor.apana.org.au>
Applied, thanks.
^ permalink raw reply
* Re: [3/5] [NET]: Add software TSOv4
From: David Miller @ 2006-06-26 6:55 UTC (permalink / raw)
To: mchan; +Cc: herbert, netdev
In-Reply-To: <1151118521.7719.0.camel@rh4>
From: "Michael Chan" <mchan@broadcom.com>
Date: Fri, 23 Jun 2006 20:08:41 -0700
> On Sat, 2006-06-24 at 09:53 +1000, Herbert Xu wrote:
>
> > Nevermind, I obviously complete ignored your other fix to the length of
> > the last segment :) Here is a fixed version.
> >
> > [NET]: Fix CHECKSUM_HW GSO problems.
> >
> > Fix checksum problems in the GSO code path for CHECKSUM_HW packets.
> >
> > The ipv4 TCP pseudo header checksum has to be adjusted for GSO
> > segmented packets.
> >
> > The adjustment is needed because the length field in the pseudo-header
> > changes. However, because we have the inequality oldlen > newlen, we
> > know that delta = (u16)~oldlen + newlen is still a 16-bit quantity.
> > This also means that htonl(delta) + th->check still fits in 32 bits.
> > Therefore we don't have to use csum_add on this operations.
> >
> > This is based on a patch by Michael Chan <mchan@broadcom.com>.
> >
> > Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
> >
> Yes, this should work. ACK.
Applied, thanks a lot guys.
^ permalink raw reply
* Re: [PATCH 0/32] TIPC updates
From: David Miller @ 2006-06-26 6:54 UTC (permalink / raw)
To: per.liden; +Cc: netdev
In-Reply-To: <Pine.LNX.4.64.0606221233570.15853@ulinpc219.uab.ericsson.se>
From: Per Liden <per.liden@ericsson.com>
Date: Thu, 22 Jun 2006 13:14:46 +0200 (CEST)
> Patches can be pulled from:
>
> git://tipc.cslab.ericsson.net/pub/git/tipc.git
Since this would not merge cleanly into Linus's current tree,
I applied all of the patches by hand.
Thanks a lot.
^ permalink raw reply
* Re: [PATCH 6/6] PMC MSP85x0 gigabit ethernet driver
From: Yoichi Yuasa @ 2006-06-26 6:18 UTC (permalink / raw)
To: Kiran Thota; +Cc: linux-mips, netdev, Rajesh_Palani, ralf
In-Reply-To: <C28979E4F697C249ABDA83AC0C33CDF8143EFB@sjc1exm07.pmc_nt.nt.pmc-sierra.bc.ca>
Hello Kiran,
On Fri, 23 Jun 2006 19:19:00 -0700
Kiran Thota <Kiran_Thota@pmc-sierra.com> wrote:
>
> - Based on linux-2.6.12 from http://www.linux-mips.org/pub/linux/mips/kernel/v2.6/linux-2.6.12.tar.gz
> - Rewritten clean driver for PMC MSP85x0 gigabit ethernet driver (planning a rewritten titan driver) \
> source, Kconfig and makefile. Will remove dependency on TITAN_GE flag with future titan driver.
>
>
> Signed-off-by: Kiran Kumar Thota <Kiran_Thota@pmc-sierra.com>
>
> diff -Naur a/drivers/net/Kconfig b/drivers/net/Kconfig
> --- a/drivers/net/Kconfig 2005-07-11 11:28:10.000000000 -0700
> +++ b/drivers/net/Kconfig 2006-06-22 11:48:21.000000000 -0700
> @@ -2098,7 +2098,7 @@
>
> config TITAN_GE
> bool "PMC-Sierra TITAN Gigabit Ethernet Support"
> - depends on PMC_YOSEMITE
> + depends on PMC_YOSEMITE || PMC_SEQUOIA
> help
> This enables support for the the integrated ethernet of
> PMC-Sierra's Titan SoC.
> diff -Naur a/drivers/net/Makefile b/drivers/net/Makefile
> --- a/drivers/net/Makefile 2005-07-11 11:28:10.000000000 -0700
> +++ b/drivers/net/Makefile 2006-06-22 11:48:21.000000000 -0700
> @@ -103,7 +103,8 @@
> obj-$(CONFIG_GALILEO_64240_ETH) += gt64240eth.o
> obj-$(CONFIG_MV64340_ETH) += mv64340_eth.o
> obj-$(CONFIG_BIG_SUR_FE) += big_sur_ge.o
> -obj-$(CONFIG_TITAN_GE) += titan_mdio.o titan_ge.o
> +obj-$(CONFIG_PMC_SEQUOIA) += titan_mdio.o msp85x0_ge.o
> +#obj-$(CONFIG_TITAN_GE) += titan_mdio.o titan_ge.o
>
> obj-$(CONFIG_PPP) += ppp_generic.o slhc.o
> obj-$(CONFIG_PPP_ASYNC) += ppp_async.o
I think that you shold add a new config for msp85x0_ge.
Yoichi
^ permalink raw reply
* Re: -git: Why is drivers/net/wan/hdlc_generic.c:hdlc_setup() exported?
From: David Boggs @ 2006-06-26 6:11 UTC (permalink / raw)
To: Adrian Bunk; +Cc: netdev
[Resent because I forgot to copy netdev on my answer]
I asked Krzysztof to export that so that I could use it
in a re-written driver for LMC WAN cards which I put out
for comments on netdev in March.
I have incorporated the comments from the March posting and
intend to repost the new driver very soon. If you delete
the export then I will have to write some nasty code to work
around it.
/David Boggs
^ permalink raw reply
* Re: Network performance degradation from 2.6.11.12 to 2.6.16.20
From: Andi Kleen @ 2006-06-26 5:23 UTC (permalink / raw)
To: Willy Tarreau; +Cc: Jesper Dangaard Brouer, Harry Edmon, linux-kernel, netdev
In-Reply-To: <20060625222243.GJ13255@w.ods.org>
> I encountered the same problem on a dual core opteron equipped with a
> broadcom NIC (tg3) under 2.4. It could receive 1 Mpps when using TSC
> as the clock source, but the time jumped back and forth, so I changed
> it to 'notsc', then the performance dropped dramatically to around the
> same value as above with one CPU saturated. I suspect that the clock
> precision is needed by the tg3 driver to correctly decide to switch to
> polling mode, but unfortunately, the performance drop rendered the
> solution so much unusable that I finally decided to use it only in
> uniprocessor with TSC enabled.
2.6 is more clever at this than 2.4. In particular it does the timestamp
for each packet only when actually needed, which is relativelt rare.
Old experiences do not always apply to new kernels.
-Andi
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox