Netdev List
 help / color / mirror / Atom feed
* [PATCH] [IPROUTE2] Update various classifiers' help output for expected CLASSID syntax
From: PJ Waskiewicz @ 2008-02-13 11:49 UTC (permalink / raw)
  To: stephen.hemminger; +Cc: jarka02, netdev

update: Fix the spelling of "hexidecimal"

This updates the help output to specify that CLASSID should be hexidecimal.
This makes sure that a user entering "flowid 1:10" gets his flow put into
band 15 (0x10) and knows why.

Signed-off-by: Peter P Waskiewicz Jr <peter.p.waskiewicz.jr@intel.com>
---

 doc/actions/actions-general |    3 +++
 tc/f_basic.c                |    1 +
 tc/f_fw.c                   |    1 +
 tc/f_route.c                |    1 +
 tc/f_rsvp.c                 |    1 +
 tc/f_u32.c                  |    1 +
 6 files changed, 8 insertions(+), 0 deletions(-)

diff --git a/doc/actions/actions-general b/doc/actions/actions-general
index 6561eda..70f7cd6 100644
--- a/doc/actions/actions-general
+++ b/doc/actions/actions-general
@@ -88,6 +88,9 @@ tc filter add dev lo parent ffff: protocol ip prio 8 u32 \
 match ip dst 127.0.0.8/32 flowid 1:12 \
 action ipt -j mark --set-mark 2
 
+NOTE: flowid 1:12 is parsed flowid 0x1:0x12.  Make sure if you want flowid
+decimal 12, then use flowid 1:c.
+
 3) A feature i call pipe
 The motivation is derived from Unix pipe mechanism but applied to packets.
 Essentially take a matching packet and pass it through 
diff --git a/tc/f_basic.c b/tc/f_basic.c
index 19a7edf..aab946b 100644
--- a/tc/f_basic.c
+++ b/tc/f_basic.c
@@ -32,6 +32,7 @@ static void explain(void)
 	fprintf(stderr, "\n");
 	fprintf(stderr, "Where: SELECTOR := SAMPLE SAMPLE ...\n");
 	fprintf(stderr, "       FILTERID := X:Y:Z\n");
+	fprintf(stderr, "\nNOTE: CLASSID is parsed as hexadecimal input.\n");
 }
 
 static int basic_parse_opt(struct filter_util *qu, char *handle,
diff --git a/tc/f_fw.c b/tc/f_fw.c
index 6d1490b..b511735 100644
--- a/tc/f_fw.c
+++ b/tc/f_fw.c
@@ -28,6 +28,7 @@ static void explain(void)
 	fprintf(stderr, "Usage: ... fw [ classid CLASSID ] [ police POLICE_SPEC ]\n");
 	fprintf(stderr, "       POLICE_SPEC := ... look at TBF\n");
 	fprintf(stderr, "       CLASSID := X:Y\n");
+	fprintf(stderr, "\nNOTE: CLASSID is parsed as hexadecimal input.\n");
 }
 
 #define usage() return(-1)
diff --git a/tc/f_route.c b/tc/f_route.c
index a41b9d5..67dd49c 100644
--- a/tc/f_route.c
+++ b/tc/f_route.c
@@ -31,6 +31,7 @@ static void explain(void)
 	fprintf(stderr, "                [ flowid CLASSID ] [ police POLICE_SPEC ]\n");
 	fprintf(stderr, "       POLICE_SPEC := ... look at TBF\n");
 	fprintf(stderr, "       CLASSID := X:Y\n");
+	fprintf(stderr, "\nNOTE: CLASSID is parsed as hexadecimal input.\n");
 }
 
 #define usage() return(-1)
diff --git a/tc/f_rsvp.c b/tc/f_rsvp.c
index 13fcf97..7e1e6d9 100644
--- a/tc/f_rsvp.c
+++ b/tc/f_rsvp.c
@@ -34,6 +34,7 @@ static void explain(void)
 	fprintf(stderr, "                u{8|16|32} NUMBER mask MASK at OFFSET}\n");
 	fprintf(stderr, "       POLICE_SPEC := ... look at TBF\n");
 	fprintf(stderr, "       FILTERID := X:Y\n");
+	fprintf(stderr, "\nNOTE: CLASSID is parsed as hexadecimal input.\n");
 }
 
 #define usage() return(-1)
diff --git a/tc/f_u32.c b/tc/f_u32.c
index 91f2838..d75e76c 100644
--- a/tc/f_u32.c
+++ b/tc/f_u32.c
@@ -36,6 +36,7 @@ static void explain(void)
 	fprintf(stderr, "Where: SELECTOR := SAMPLE SAMPLE ...\n");
 	fprintf(stderr, "       SAMPLE := { ip | ip6 | udp | tcp | icmp | u{32|16|8} | mark } SAMPLE_ARGS [divisor DIVISOR]\n");
 	fprintf(stderr, "       FILTERID := X:Y:Z\n");
+	fprintf(stderr, "\nNOTE: CLASSID is parsed at hexadecimal input.\n");
 }
 
 #define usage() return(-1)


^ permalink raw reply related

* Patch to latest iproute to get it to compile on FC5
From: Ben Greear @ 2008-02-13 19:32 UTC (permalink / raw)
  To: NetDev, Stephen Hemminger

[-- Attachment #1: Type: text/plain, Size: 459 bytes --]

I notice that the latest snapshot and git repository for iproute
will not compile on FC5 due to not finding __constant_hton* symbols
and a lack of the hdlc/ioctl.h file on FC5.

I am attaching a patch that appears to fix the problems for me.

Please consider applying this or something similar.

Signed-off-by:  Ben Greear <greearb@candelatech.com>


Thanks,
Ben

-- 
Ben Greear <greearb@candelatech.com>
Candela Technologies Inc  http://www.candelatech.com


[-- Attachment #2: iproute.fc5.patch --]
[-- Type: text/x-patch, Size: 2002 bytes --]

diff --git a/configure b/configure
index dc14e54..f28e4cf 100755
--- a/configure
+++ b/configure
@@ -25,3 +25,22 @@ else
     echo no
 fi
 rm -f /tmp/atmtest.c /tmp/atmtest
+
+echo -n "HDLC IOCTL:   "
+cat >/tmp/hdlctest.c <<EOF
+#include <net/if.h>
+#include <linux/hdlc/ioctl.h>
+int main(int argc, char **argv) {
+        return 0;
+}
+EOF
+gcc -I$INCLUDE -o /tmp/hdlctest /tmp/hdlctest.c >/dev/null 2>&1
+if [ $? -eq 0 ]
+then
+    echo "IPROUTE_CONFIG_HDLC:=y" >>Config
+    echo yes
+else
+    echo no
+fi
+rm -f /tmp/hdlctest.c /tmp/hdlctest
+
diff --git a/include/linux/if.h b/include/linux/if.h
index 40eb61f..9651cc9 100644
--- a/include/linux/if.h
+++ b/include/linux/if.h
@@ -23,7 +23,10 @@
 #include <linux/socket.h>		/* for "struct sockaddr" et al	*/
 
 #define	IFNAMSIZ	16
+
+#ifdef HAVE_HDLC_IOCTL
 #include <linux/hdlc/ioctl.h>
+#endif
 
 /* Standard interface flags (netdevice->flags). */
 #define	IFF_UP		0x1		/* interface is up		*/
@@ -133,6 +136,7 @@ struct if_settings
 {
 	unsigned int type;	/* Type of physical device or protocol */
 	unsigned int size;	/* Size of the data allocated by the caller */
+#ifdef HAVE_HDLC_IOCTL
 	union {
 		/* {atm/eth/dsl}_settings anyone ? */
 		raw_hdlc_proto	 *raw_hdlc;
@@ -145,6 +149,7 @@ struct if_settings
 		sync_serial_settings *sync;
 		te1_settings	 *te1;
 	} ifs_ifsu;
+#endif
 };
 
 /*
diff --git a/include/linux/if_tunnel.h b/include/linux/if_tunnel.h
index 228eb4e..0eb5b04 100644
--- a/include/linux/if_tunnel.h
+++ b/include/linux/if_tunnel.h
@@ -2,6 +2,7 @@
 #define _IF_TUNNEL_H_
 
 #include <linux/types.h>
+#include <asm/byteorder.h>
 
 #define SIOCGETTUNNEL   (SIOCDEVPRIVATE + 0)
 #define SIOCADDTUNNEL   (SIOCDEVPRIVATE + 1)
diff --git a/lib/Makefile b/lib/Makefile
index bc270bf..1c51a42 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -1,3 +1,9 @@
+include ../Config
+
+ifeq ($(IPROUTE_CONFIG_HDLC),y)
+   CFLAGS += -DHAVE_HDLC_IOCTL
+endif
+
 
 UTILOBJ=utils.o rt_names.o ll_types.o ll_proto.o ll_addr.o inet_proto.o
 

^ permalink raw reply related

* Re: Patch to latest iproute to get it to compile on FC5
From: Stephen Hemminger @ 2008-02-13 19:56 UTC (permalink / raw)
  To: Ben Greear; +Cc: NetDev
In-Reply-To: <47B345D0.1020707@candelatech.com>

On Wed, 13 Feb 2008 11:32:32 -0800
Ben Greear <greearb@candelatech.com> wrote:

> I notice that the latest snapshot and git repository for iproute
> will not compile on FC5 due to not finding __constant_hton* symbols
> and a lack of the hdlc/ioctl.h file on FC5.
> 
> I am attaching a patch that appears to fix the problems for me.
> 
> Please consider applying this or something similar.
> 
> Signed-off-by:  Ben Greear <greearb@candelatech.com>
> 
> 
> Thanks,
> Ben
> 

No. please don't change the configure script.
And the linux/if.h comes from kernel stripped headers so it should
not get crufted up by ifdef's.

Short term fix is to include stripped hdlc header if needed.
Long fix is to get rid of hdlc dependency if possible.

-- 
Stephen Hemminger <stephen.hemminger@vyatta.com>

^ permalink raw reply

* [PATCH 2/3] fib_trie: improve output format for /proc/net/fib_trie
From: Stephen Hemminger @ 2008-02-13 19:58 UTC (permalink / raw)
  To: David Miller; +Cc: netdev
In-Reply-To: <20080213195805.493794050@vyatta.com>

[-- Attachment #1: fib-trie-format.patch --]
[-- Type: text/plain, Size: 5134 bytes --]

Make output format prettier (more tree like).

   <local>:
   --- 0.0.0.0/0
     |--- 10.111.111.0/24
     |  +-- 10.111.111.0/32 link broadcast
     |  |--- 10.111.111.254/31
     |  |  +-- 10.111.111.254/32 host local
     |  |  +-- 10.111.111.255/32 link broadcast
     |--- 127.0.0.0/8
     |  |--- 127.0.0.0/31
     |  |  +-- 127.0.0.0/32 link broadcast
     |  |  +-- 127.0.0.0/8 host local
     |  |  +-- 127.0.0.1/32 host local
     |  +-- 127.255.255.255/32 link broadcast
     |--- 192.168.1.0/24
     |  |--- 192.168.1.0/28
     |  |  +-- 192.168.1.0/32 link broadcast
     |  |  +-- 192.168.1.9/32 host local
     |  +-- 192.168.1.255/32 link broadcast
   <main>:
   --- 0.0.0.0/0
     |--- 0.0.0.0/4
     |  +-- 0.0.0.0/0 universe unicast
     |  +-- 10.111.111.0/24 link unicast
     +-- 169.254.0.0/16 link unicast
     +-- 192.168.1.0/24 link unicast
   
Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
---
 net/ipv4/fib_trie.c |  106 ++++++++++++++++++++++++++------------------------
 1 files changed, 55 insertions(+), 51 deletions(-)

--- a/net/ipv4/fib_trie.c	2008-02-13 11:33:43.000000000 -0800
+++ b/net/ipv4/fib_trie.c	2008-02-13 11:41:23.000000000 -0800
@@ -2334,46 +2334,57 @@ static void fib_trie_seq_stop(struct seq
 	rcu_read_unlock();
 }
 
+/* print left side of tree */
 static void seq_indent(struct seq_file *seq, int n)
 {
-	while (n-- > 0) seq_puts(seq, "   ");
+	while (n-- > 0)
+		seq_puts(seq, "  |");
 }
 
-static inline const char *rtn_scope(char *buf, size_t len, enum rt_scope_t s)
+static const char *rtn_type_names[__RTN_MAX] = {
+	[RTN_UNSPEC]	= "unspec",
+	[RTN_UNICAST]	= "unicast",
+	[RTN_LOCAL]	= "local",
+	[RTN_BROADCAST] = "broadcast",
+	[RTN_ANYCAST]	= "anycast",
+	[RTN_MULTICAST] = "multicast",
+	[RTN_BLACKHOLE] = "blackhole",
+	[RTN_UNREACHABLE] = "unreachable",
+	[RTN_PROHIBIT] 	= "prohibit",
+	[RTN_THROW]	= "throw",
+	[RTN_NAT]	= "nat",
+	[RTN_XRESOLVE]	= "xresolve",
+};
+
+static void fib_trie_show_alias(struct seq_file *seq, const struct fib_alias *fa)
 {
-	switch (s) {
-	case RT_SCOPE_UNIVERSE: return "universe";
-	case RT_SCOPE_SITE:	return "site";
-	case RT_SCOPE_LINK:	return "link";
-	case RT_SCOPE_HOST:	return "host";
-	case RT_SCOPE_NOWHERE:	return "nowhere";
+	switch (fa->fa_scope) {
+	case RT_SCOPE_UNIVERSE:
+		seq_puts(seq, "universe");
+		break;
+	case RT_SCOPE_SITE:
+		seq_puts(seq,  "site");
+		break;
+	case RT_SCOPE_LINK:
+		seq_puts(seq,  "link");
+		break;
+	case RT_SCOPE_HOST:
+		seq_puts(seq,  "host");
+		break;
+	case RT_SCOPE_NOWHERE:
+		seq_puts(seq,  "nowhere");
+		break;
 	default:
-		snprintf(buf, len, "scope=%d", s);
-		return buf;
+		seq_printf(seq, "scope:%d", fa->fa_scope);
 	}
-}
 
-static const char *rtn_type_names[__RTN_MAX] = {
-	[RTN_UNSPEC] = "UNSPEC",
-	[RTN_UNICAST] = "UNICAST",
-	[RTN_LOCAL] = "LOCAL",
-	[RTN_BROADCAST] = "BROADCAST",
-	[RTN_ANYCAST] = "ANYCAST",
-	[RTN_MULTICAST] = "MULTICAST",
-	[RTN_BLACKHOLE] = "BLACKHOLE",
-	[RTN_UNREACHABLE] = "UNREACHABLE",
-	[RTN_PROHIBIT] = "PROHIBIT",
-	[RTN_THROW] = "THROW",
-	[RTN_NAT] = "NAT",
-	[RTN_XRESOLVE] = "XRESOLVE",
-};
+	if (fa->fa_type < __RTN_MAX && rtn_type_names[fa->fa_type])
+		seq_printf(seq, " %s", rtn_type_names[fa->fa_type]);
+	else
+		seq_printf(seq, " type:%u", fa->fa_type);
 
-static inline const char *rtn_type(char *buf, size_t len, unsigned t)
-{
-	if (t < __RTN_MAX && rtn_type_names[t])
-		return rtn_type_names[t];
-	snprintf(buf, len, "type %u", t);
-	return buf;
+	if (fa->fa_tos)
+		seq_printf(seq, " tos:%#x", fa->fa_tos);
 }
 
 /* Pretty print the trie */
@@ -2396,10 +2407,8 @@ static int fib_trie_seq_show(struct seq_
 		struct tnode *tn = (struct tnode *) n;
 		__be32 prf = htonl(mask_pfx(tn->key, tn->pos));
 
-		seq_indent(seq, iter->depth-1);
-		seq_printf(seq, "  +-- %d.%d.%d.%d/%d %d %d %d\n",
-			   NIPQUAD(prf), tn->pos, tn->bits, tn->full_children,
-			   tn->empty_children);
+		seq_indent(seq, iter->depth - 1);
+		seq_printf(seq, "--- %d.%d.%d.%d/%d\n", NIPQUAD(prf), tn->pos);
 
 	} else {
 		struct leaf *l = (struct leaf *) n;
@@ -2407,24 +2416,19 @@ static int fib_trie_seq_show(struct seq_
 		struct hlist_node *node;
 		__be32 val = htonl(l->key);
 
-		seq_indent(seq, iter->depth);
-		seq_printf(seq, "  |-- %d.%d.%d.%d\n", NIPQUAD(val));
-
 		hlist_for_each_entry_rcu(li, node, &l->list, hlist) {
 			struct fib_alias *fa;
 
-			list_for_each_entry_rcu(fa, &li->falh, fa_list) {
-				char buf1[32], buf2[32];
+			seq_indent(seq, iter->depth - 1);
+			seq_printf(seq, "  +-- %d.%d.%d.%d/%d ",
+				   NIPQUAD(val), li->plen);
 
-				seq_indent(seq, iter->depth+1);
-				seq_printf(seq, "  /%d %s %s", li->plen,
-					   rtn_scope(buf1, sizeof(buf1),
-						     fa->fa_scope),
-					   rtn_type(buf2, sizeof(buf2),
-						    fa->fa_type));
-				if (fa->fa_tos)
-					seq_printf(seq, " tos=%d", fa->fa_tos);
-				seq_putc(seq, '\n');
+			list_for_each_entry_rcu(fa, &li->falh, fa_list) {
+				fib_trie_show_alias(seq, fa);
+				if (list_is_last(&fa->fa_list, &li->falh))
+					seq_putc(seq, '\n');
+				else
+					seq_puts(seq, ", ");
 			}
 		}
 	}

-- 
Stephen Hemminger <shemminger@vyatta.com>


^ permalink raw reply

* [PATCH 0/3] fib_trie: update (redo)
From: Stephen Hemminger @ 2008-02-13 19:58 UTC (permalink / raw)
  To: David Miller; +Cc: netdev

This supersedes yesterday's changes. It doesn't change list.h
because that seems to make people queasy, even if it is a clone
of existing code.  Moves the trie related special files to debugfs.

-- 
Stephen Hemminger <shemminger@vyatta.com>


^ permalink raw reply

* [PATCH 1/3] fib_trie: move statistics to debugfs
From: Stephen Hemminger @ 2008-02-13 19:58 UTC (permalink / raw)
  To: David Miller; +Cc: netdev
In-Reply-To: <20080213195805.493794050@vyatta.com>

[-- Attachment #1: fib-trie-debugfs.patch --]
[-- Type: text/plain, Size: 7952 bytes --]

Don't want /proc/net/fib_trie and /proc/net/fib_triestat to become
permanent kernel space ABI issues, so move to the safer confines of debugfs.

Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>

---
 net/ipv4/Kconfig    |    9 ++-
 net/ipv4/fib_trie.c |  127 +++++++++++++++++++++++++++++++++-------------------
 2 files changed, 86 insertions(+), 50 deletions(-)

--- a/net/ipv4/Kconfig	2008-02-13 10:58:51.000000000 -0800
+++ b/net/ipv4/Kconfig	2008-02-13 10:59:06.000000000 -0800
@@ -85,11 +85,12 @@ endchoice
 config IP_FIB_HASH
 	def_bool ASK_IP_FIB_HASH || !IP_ADVANCED_ROUTER
 
-config IP_FIB_TRIE_STATS
-	bool "FIB TRIE statistics"
-	depends on IP_FIB_TRIE
+config IP_FIB_TRIE_DEBUG
+	bool "FIB TRIE debugging information"
+	depends on IP_FIB_TRIE && DEBUG_FS
 	---help---
-	  Keep track of statistics on structure of FIB TRIE table.
+	  Provides interface for looking at internal structure, and
+	  statistics on for the  FIB TRIE table.
 	  Useful for testing and measuring TRIE performance.
 
 config IP_MULTIPLE_TABLES
--- a/net/ipv4/fib_trie.c	2008-02-13 10:58:51.000000000 -0800
+++ b/net/ipv4/fib_trie.c	2008-02-13 11:33:43.000000000 -0800
@@ -68,6 +68,7 @@
 #include <linux/netdevice.h>
 #include <linux/if_arp.h>
 #include <linux/proc_fs.h>
+#include <linux/debugfs.h>
 #include <linux/rcupdate.h>
 #include <linux/skbuff.h>
 #include <linux/netlink.h>
@@ -126,7 +127,8 @@ struct tnode {
 	struct node *child[0];
 };
 
-#ifdef CONFIG_IP_FIB_TRIE_STATS
+#ifdef CONFIG_IP_FIB_TRIE_DEBUG
+
 struct trie_use_stats {
 	unsigned int gets;
 	unsigned int backtrack;
@@ -135,7 +137,6 @@ struct trie_use_stats {
 	unsigned int null_node_hit;
 	unsigned int resize_node_skipped;
 };
-#endif
 
 struct trie_stat {
 	unsigned int totdepth;
@@ -146,10 +147,11 @@ struct trie_stat {
 	unsigned int prefixes;
 	unsigned int nodesizes[MAX_STAT_DEPTH];
 };
+#endif
 
 struct trie {
 	struct node *trie;
-#ifdef CONFIG_IP_FIB_TRIE_STATS
+#ifdef CONFIG_IP_FIB_TRIE_DEBUG
 	struct trie_use_stats stats;
 #endif
 };
@@ -588,7 +590,7 @@ static struct node *resize(struct trie *
 
 		if (IS_ERR(tn)) {
 			tn = old_tn;
-#ifdef CONFIG_IP_FIB_TRIE_STATS
+#ifdef CONFIG_IP_FIB_TRIE_DEBUG
 			t->stats.resize_node_skipped++;
 #endif
 			break;
@@ -631,7 +633,7 @@ static struct node *resize(struct trie *
 		tn = halve(t, tn);
 		if (IS_ERR(tn)) {
 			tn = old_tn;
-#ifdef CONFIG_IP_FIB_TRIE_STATS
+#ifdef CONFIG_IP_FIB_TRIE_DEBUG
 			t->stats.resize_node_skipped++;
 #endif
 			break;
@@ -1341,7 +1343,7 @@ static int check_leaf(struct trie *t, st
 		err = fib_semantic_match(&li->falh, flp, res,
 					 htonl(l->key), mask, plen);
 
-#ifdef CONFIG_IP_FIB_TRIE_STATS
+#ifdef CONFIG_IP_FIB_TRIE_DEBUG
 		if (err <= 0)
 			t->stats.semantic_match_passed++;
 		else
@@ -1376,7 +1378,7 @@ static int fn_trie_lookup(struct fib_tab
 	if (!n)
 		goto failed;
 
-#ifdef CONFIG_IP_FIB_TRIE_STATS
+#ifdef CONFIG_IP_FIB_TRIE_DEBUG
 	t->stats.gets++;
 #endif
 
@@ -1403,7 +1405,7 @@ static int fn_trie_lookup(struct fib_tab
 		n = tnode_get_child(pn, cindex);
 
 		if (n == NULL) {
-#ifdef CONFIG_IP_FIB_TRIE_STATS
+#ifdef CONFIG_IP_FIB_TRIE_DEBUG
 			t->stats.null_node_hit++;
 #endif
 			goto backtrace;
@@ -1546,7 +1548,7 @@ backtrace:
 			pn = parent;
 			chopped_off = 0;
 
-#ifdef CONFIG_IP_FIB_TRIE_STATS
+#ifdef CONFIG_IP_FIB_TRIE_DEBUG
 			t->stats.backtrack++;
 #endif
 			goto backtrace;
@@ -2022,7 +2024,8 @@ struct fib_table *fib_hash_table(u32 id)
 	return tb;
 }
 
-#ifdef CONFIG_PROC_FS
+#ifdef CONFIG_IP_FIB_TRIE_DEBUG
+
 /* Depth first Trie walk iterator */
 struct fib_trie_iter {
 	struct seq_net_private p;
@@ -2147,7 +2150,7 @@ static void trie_collect_stats(struct tr
 }
 
 /*
- *	This outputs /proc/net/fib_triestats
+ *	This outputs debugfs/fib/triestats
  */
 static void trie_show_stats(struct seq_file *seq, struct trie_stat *stat)
 {
@@ -2189,7 +2192,6 @@ static void trie_show_stats(struct seq_f
 	seq_printf(seq, "Total size: %u  kB\n", (bytes + 1023) / 1024);
 }
 
-#ifdef CONFIG_IP_FIB_TRIE_STATS
 static void trie_show_usage(struct seq_file *seq,
 			    const struct trie_use_stats *stats)
 {
@@ -2204,7 +2206,7 @@ static void trie_show_usage(struct seq_f
 	seq_printf(seq, "skipped node resize = %u\n\n",
 		   stats->resize_node_skipped);
 }
-#endif /*  CONFIG_IP_FIB_TRIE_STATS */
+
 
 static void fib_trie_show(struct seq_file *seq, const char *name,
 			  struct trie *trie)
@@ -2214,9 +2216,7 @@ static void fib_trie_show(struct seq_fil
 	trie_collect_stats(trie, &stat);
 	seq_printf(seq, "%s:\n", name);
 	trie_show_stats(seq, &stat);
-#ifdef CONFIG_IP_FIB_TRIE_STATS
 	trie_show_usage(seq, &trie->stats);
-#endif
 }
 
 static int fib_triestat_seq_show(struct seq_file *seq, void *v)
@@ -2242,18 +2242,12 @@ static int fib_triestat_seq_show(struct 
 
 static int fib_triestat_seq_open(struct inode *inode, struct file *file)
 {
-	int err;
-	struct net *net;
+	struct net *net = maybe_get_net((struct net *)inode->i_private);
 
-	net = get_proc_net(inode);
-	if (net == NULL)
+	if (!net)
 		return -ENXIO;
-	err = single_open(file, fib_triestat_seq_show, net);
-	if (err < 0) {
-		put_net(net);
-		return err;
-	}
-	return 0;
+
+	return single_open(file, fib_triestat_seq_show, net);
 }
 
 static int fib_triestat_seq_release(struct inode *ino, struct file *f)
@@ -2447,8 +2441,19 @@ static const struct seq_operations fib_t
 
 static int fib_trie_seq_open(struct inode *inode, struct file *file)
 {
-	return seq_open_net(inode, file, &fib_trie_seq_ops,
-			    sizeof(struct fib_trie_iter));
+	struct net *net = maybe_get_net((struct net *)inode->i_private);
+	struct fib_trie_iter *iter;
+
+	if (!net)
+		return -ENXIO;
+
+	iter = __seq_open_private(file, &fib_trie_seq_ops, sizeof(*iter));
+	if (!iter) {
+		put_net(net);
+		return -ENOMEM;
+	}
+	iter->p.net = net;
+	return 0;
 }
 
 static const struct file_operations fib_trie_fops = {
@@ -2459,6 +2464,51 @@ static const struct file_operations fib_
 	.release = seq_release_net,
 };
 
+
+static struct dentry *fib_debug, *trie_debug, *triestat_debug;
+
+static void __net_init trie_debug_init(struct net *net)
+{
+	fib_debug = debugfs_create_dir("fib", NULL);
+	if (!fib_debug || IS_ERR(fib_debug))
+		goto out1;
+
+	trie_debug = debugfs_create_file("trie", S_IRUGO, fib_debug,
+					 net, &fib_trie_fops);
+	if (!trie_debug || IS_ERR(trie_debug))
+		goto out2;
+
+	triestat_debug = debugfs_create_file("triestat", S_IRUGO, fib_debug,
+					     net, &fib_triestat_fops);
+	if (!triestat_debug || IS_ERR(triestat_debug))
+		goto out3;
+
+	hold_net(net);
+	return;
+out3:
+	debugfs_remove(trie_debug);
+out2:
+	debugfs_remove(fib_debug);
+out1:
+	fib_debug = NULL;
+}
+
+static void __net_exit trie_debug_exit(struct net *net)
+{
+	if (!fib_debug)
+		return;
+
+	debugfs_remove(trie_debug);
+	debugfs_remove(triestat_debug);
+	debugfs_remove(fib_debug);
+	put_net(net);
+}
+#else
+#define trie_debug_init(n)
+#define trie_debug_exit(n)
+#endif
+
+#ifdef CONFIG_PROC_FS
 struct fib_route_iter {
 	struct seq_net_private p;
 	struct trie *main_trie;
@@ -2632,34 +2682,19 @@ static const struct file_operations fib_
 	.llseek = seq_lseek,
 	.release = seq_release_net,
 };
+#endif /* CONFIG_PROC_FS */
 
 int __net_init fib_proc_init(struct net *net)
 {
-	if (!proc_net_fops_create(net, "fib_trie", S_IRUGO, &fib_trie_fops))
-		goto out1;
-
-	if (!proc_net_fops_create(net, "fib_triestat", S_IRUGO,
-				  &fib_triestat_fops))
-		goto out2;
-
 	if (!proc_net_fops_create(net, "route", S_IRUGO, &fib_route_fops))
-		goto out3;
+		return -ENOMEM;
 
+	trie_debug_init(net);
 	return 0;
-
-out3:
-	proc_net_remove(net, "fib_triestat");
-out2:
-	proc_net_remove(net, "fib_trie");
-out1:
-	return -ENOMEM;
 }
 
 void __net_exit fib_proc_exit(struct net *net)
 {
-	proc_net_remove(net, "fib_trie");
-	proc_net_remove(net, "fib_triestat");
 	proc_net_remove(net, "route");
+	trie_debug_exit(net);
 }
-
-#endif /* CONFIG_PROC_FS */

-- 
Stephen Hemminger <shemminger@vyatta.com>


^ permalink raw reply

* [PATCH 3/3] fib_trie: print statistics for multiple tables
From: Stephen Hemminger @ 2008-02-13 19:58 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, Stephen Hemminger
In-Reply-To: <20080213195805.493794050@vyatta.com>

[-- Attachment #1: fib-trie-tables.patch --]
[-- Type: text/plain, Size: 7257 bytes --]

Make debugfs/fib/trie and debugfs/fib/triestat handle
multiple (alternate) route tables.

Note: this usage of seq_file doesn't need/want SEQ_START_TOKEN

Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>

--- a/net/ipv4/fib_trie.c	2008-02-13 11:41:23.000000000 -0800
+++ b/net/ipv4/fib_trie.c	2008-02-13 11:41:35.000000000 -0800
@@ -2029,14 +2029,13 @@ struct fib_table *fib_hash_table(u32 id)
 /* Depth first Trie walk iterator */
 struct fib_trie_iter {
 	struct seq_net_private p;
-	struct trie *trie_local, *trie_main;
+	struct fib_table *tb;
 	struct tnode *tnode;
-	struct trie *trie;
 	unsigned index;
 	unsigned depth;
 };
 
-static struct node *fib_trie_get_next(struct fib_trie_iter *iter)
+static struct node *trie_get_next(struct fib_trie_iter *iter)
 {
 	struct tnode *tn = iter->tnode;
 	unsigned cindex = iter->index;
@@ -2081,34 +2080,29 @@ rescan:
 	return NULL;
 }
 
-static struct node *fib_trie_get_first(struct fib_trie_iter *iter,
-				       struct trie *t)
+static struct node *trie_get_first(struct fib_trie_iter *iter,
+				   struct trie *t)
 {
-	struct node *n ;
+	struct node *n;
 
 	if (!t)
 		return NULL;
 
 	n = rcu_dereference(t->trie);
-
-	if (!iter)
+	if (!n)
 		return NULL;
 
-	if (n) {
-		if (IS_TNODE(n)) {
-			iter->tnode = (struct tnode *) n;
-			iter->trie = t;
-			iter->index = 0;
-			iter->depth = 1;
-		} else {
-			iter->tnode = NULL;
-			iter->trie  = t;
-			iter->index = 0;
-			iter->depth = 0;
-		}
-		return n;
+	if (IS_TNODE(n)) {
+		iter->tnode = (struct tnode *) n;
+		iter->index = 0;
+		iter->depth = 1;
+	} else {
+		iter->tnode = NULL;
+		iter->index = 0;
+		iter->depth = 0;
 	}
-	return NULL;
+
+	return n;
 }
 
 static void trie_collect_stats(struct trie *t, struct trie_stat *s)
@@ -2119,8 +2113,7 @@ static void trie_collect_stats(struct tr
 	memset(s, 0, sizeof(*s));
 
 	rcu_read_lock();
-	for (n = fib_trie_get_first(&iter, t); n;
-	     n = fib_trie_get_next(&iter)) {
+	for (n = trie_get_first(&iter, t); n; n = trie_get_next(&iter)) {
 		if (IS_LEAF(n)) {
 			struct leaf *l = (struct leaf *)n;
 			struct leaf_info *li;
@@ -2207,35 +2200,46 @@ static void trie_show_usage(struct seq_f
 		   stats->resize_node_skipped);
 }
 
-
-static void fib_trie_show(struct seq_file *seq, const char *name,
-			  struct trie *trie)
+static void fib_table_print(struct seq_file *seq, struct fib_table *tb)
 {
-	struct trie_stat stat;
-
-	trie_collect_stats(trie, &stat);
-	seq_printf(seq, "%s:\n", name);
-	trie_show_stats(seq, &stat);
-	trie_show_usage(seq, &trie->stats);
+	if (tb->tb_id == RT_TABLE_LOCAL)
+		seq_puts(seq, "Local:\n");
+	else if (tb->tb_id == RT_TABLE_MAIN)
+		seq_puts(seq, "Main:\n");
+	else
+		seq_printf(seq, "Id %d:\n", tb->tb_id);
 }
 
+
 static int fib_triestat_seq_show(struct seq_file *seq, void *v)
 {
 	struct net *net = (struct net *)seq->private;
-	struct fib_table *tb;
+	unsigned int h;
 
 	seq_printf(seq,
 		   "Basic info: size of leaf:"
 		   " %Zd bytes, size of tnode: %Zd bytes.\n",
 		   sizeof(struct leaf), sizeof(struct tnode));
 
-	tb = fib_get_table(net, RT_TABLE_LOCAL);
-	if (tb)
-		fib_trie_show(seq, "Local", (struct trie *) tb->tb_data);
-
-	tb = fib_get_table(net, RT_TABLE_MAIN);
-	if (tb)
-		fib_trie_show(seq, "Main", (struct trie *) tb->tb_data);
+	for (h = 0; h < FIB_TABLE_HASHSZ; h++) {
+		struct hlist_head *head = &net->ipv4.fib_table_hash[h];
+		struct hlist_node *node;
+		struct fib_table *tb;
+
+		hlist_for_each_entry_rcu(tb, node, head, tb_hlist) {
+			struct trie *t = (struct trie *) tb->tb_data;
+			struct trie_stat stat;
+
+			if (!t)
+				continue;
+
+			fib_table_print(seq, tb);
+
+			trie_collect_stats(t, &stat);
+			trie_show_stats(seq, &stat);
+			trie_show_usage(seq, &t->stats);
+		}
+	}
 
 	return 0;
 }
@@ -2265,23 +2269,30 @@ static const struct file_operations fib_
 	.release = fib_triestat_seq_release,
 };
 
-static struct node *fib_trie_get_idx(struct fib_trie_iter *iter,
-				      loff_t pos)
+static struct node *fib_trie_get_idx(struct fib_trie_iter *iter, loff_t pos)
 {
+	struct net *net = iter->p.net;
 	loff_t idx = 0;
-	struct node *n;
+	unsigned int h;
 
-	for (n = fib_trie_get_first(iter, iter->trie_local);
-	     n; ++idx, n = fib_trie_get_next(iter)) {
-		if (pos == idx)
-			return n;
-	}
+	for (h = 0; h < FIB_TABLE_HASHSZ; h++) {
+		struct hlist_head *head = &net->ipv4.fib_table_hash[h];
+		struct hlist_node *node;
+		struct fib_table *tb;
 
-	for (n = fib_trie_get_first(iter, iter->trie_main);
-	     n; ++idx, n = fib_trie_get_next(iter)) {
-		if (pos == idx)
-			return n;
+		hlist_for_each_entry_rcu(tb, node, head, tb_hlist) {
+			struct node *n;
+
+			for (n = trie_get_first(iter,
+						(struct trie *) tb->tb_data);
+			     n; n = trie_get_next(iter))
+				if (pos == idx++) {
+					iter->tb = tb;
+					return n;
+				}
+		}
 	}
+
 	return NULL;
 }
 
@@ -2289,43 +2300,52 @@ static void *fib_trie_seq_start(struct s
 	__acquires(RCU)
 {
 	struct fib_trie_iter *iter = seq->private;
-	struct fib_table *tb;
 
-	if (!iter->trie_local) {
-		tb = fib_get_table(iter->p.net, RT_TABLE_LOCAL);
-		if (tb)
-			iter->trie_local = (struct trie *) tb->tb_data;
-	}
-	if (!iter->trie_main) {
-		tb = fib_get_table(iter->p.net, RT_TABLE_MAIN);
-		if (tb)
-			iter->trie_main = (struct trie *) tb->tb_data;
-	}
 	rcu_read_lock();
-	if (*pos == 0)
-		return SEQ_START_TOKEN;
-	return fib_trie_get_idx(iter, *pos - 1);
+	return fib_trie_get_idx(iter, *pos);
 }
 
+
+
 static void *fib_trie_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 {
 	struct fib_trie_iter *iter = seq->private;
-	void *l = v;
+	struct net *net = iter->p.net;
+	struct fib_table *tb = iter->tb;
+	struct hlist_node *tb_node;
+	unsigned int h;
+	struct node *n;
 
 	++*pos;
-	if (v == SEQ_START_TOKEN)
-		return fib_trie_get_idx(iter, 0);
+	/* next node in same table */
+	n = trie_get_next(iter);
+	if (n)
+		return n;
 
-	v = fib_trie_get_next(iter);
-	BUG_ON(v == l);
-	if (v)
-		return v;
-
-	/* continue scan in next trie */
-	if (iter->trie == iter->trie_local)
-		return fib_trie_get_first(iter, iter->trie_main);
+	/* walk rest of this hash chain */
+	h = tb->tb_id & (FIB_TABLE_HASHSZ - 1);
+	while ( (tb_node = rcu_dereference(tb->tb_hlist.next)) ) {
+		tb = hlist_entry(tb_node, struct fib_table, tb_hlist);
+		n = trie_get_first(iter, (struct trie *) tb->tb_data);
+		if (n)
+			goto found;
+	}
+
+	/* new hash chain */
+	while (++h < FIB_TABLE_HASHSZ) {
+		struct hlist_head *head = &net->ipv4.fib_table_hash[h];
+		hlist_for_each_entry_rcu(tb, tb_node, head, tb_hlist) {
+			n = trie_get_first(iter, (struct trie *) tb->tb_data);
+			if (n)
+				goto found;
+		}
+	}
 
 	return NULL;
+
+found:
+	iter->tb = tb;
+	return n;
 }
 
 static void fib_trie_seq_stop(struct seq_file *seq, void *v)
@@ -2393,15 +2413,8 @@ static int fib_trie_seq_show(struct seq_
 	const struct fib_trie_iter *iter = seq->private;
 	struct node *n = v;
 
-	if (v == SEQ_START_TOKEN)
-		return 0;
-
-	if (!node_parent_rcu(n)) {
-		if (iter->trie == iter->trie_local)
-			seq_puts(seq, "<local>:\n");
-		else
-			seq_puts(seq, "<main>:\n");
-	}
+	if (!node_parent_rcu(n))
+		fib_table_print(seq, iter->tb);
 
 	if (IS_TNODE(n)) {
 		struct tnode *tn = (struct tnode *) n;

-- 
Stephen Hemminger <shemminger@vyatta.com>


^ permalink raw reply

* 64bit counters: iproute(netlink) vs ifconfig
From: Krzysztof Oledzki @ 2008-02-13 20:20 UTC (permalink / raw)
  To: netdev

[-- Attachment #1: Type: TEXT/PLAIN, Size: 1212 bytes --]

Hello,

Just discovered that counters returned by the "ip" tool are truncated:

# ip -s link show bond0
1: bond0: <BROADCAST,MULTICAST,MASTER,UP,LOWER_UP> mtu 1500 qdisc noqueue
     link/ether 00:1d:09:67:6e:2f brd ff:ff:ff:ff:ff:ff
     RX: bytes  packets  errors  dropped overrun mcast
     2485605521 9010211  0       0       0       6
     TX: bytes  packets  errors  dropped carrier collsns
     3023237974 9345397  0       0       0       0

# ifconfig bond0
bond0     Link encap:Ethernet  HWaddr 00:1D:09:67:6E:2F
           inet addr:192.168.152.62  Bcast:192.168.152.255  Mask:255.255.255.0
           inet6 addr: fe80::21d:9ff:fe67:6e2f/64 Scope:Link
           UP BROADCAST RUNNING MASTER MULTICAST  MTU:1500  Metric:1
           RX packets:9010367 errors:0 dropped:351 overruns:0 frame:0
           TX packets:9345521 errors:0 dropped:0 overruns:0 carrier:0
           collisions:0 txqueuelen:0
           RX bytes:2485631020 (2370.4 Mb)  TX bytes:7318232294 (6979.2 Mb)

Is it possible to get 64-bit counters in ip via netlink? Struct 
rtnl_link_stats does not look very optimistic, as it has rx_bytes/tx_bytes 
defined with __u32.

Best regards,

 				Krzysztof Olędzki

^ permalink raw reply

* Re: Patch to latest iproute to get it to compile on FC5
From: Stephen Hemminger @ 2008-02-13 20:34 UTC (permalink / raw)
  To: Ben Greear; +Cc: NetDev
In-Reply-To: <47B345D0.1020707@candelatech.com>

On Wed, 13 Feb 2008 11:32:32 -0800
Ben Greear <greearb@candelatech.com> wrote:

> I notice that the latest snapshot and git repository for iproute
> will not compile on FC5 due to not finding __constant_hton* symbols
> and a lack of the hdlc/ioctl.h file on FC5.
> 
> I am attaching a patch that appears to fix the problems for me.
> 
> Please consider applying this or something similar.
> 
> Signed-off-by:  Ben Greear <greearb@candelatech.com>
> 
> 
> Thanks,
> Ben
> 

I added include/linux/hdlc/ioctl.h to the santized headers in the
current git.

-- 
Stephen Hemminger <stephen.hemminger@vyatta.com>

^ permalink raw reply

* Re: 64bit counters: iproute(netlink) vs ifconfig
From: Stephen Hemminger @ 2008-02-13 20:35 UTC (permalink / raw)
  To: netdev
In-Reply-To: <Pine.LNX.4.64.0802132114110.16999@bizon.gios.gov.pl>

On Wed, 13 Feb 2008 21:20:59 +0100 (CET)
Krzysztof Oledzki <olel@ans.pl> wrote:

> Hello,
> 
> Just discovered that counters returned by the "ip" tool are truncated:
> 
> # ip -s link show bond0
> 1: bond0: <BROADCAST,MULTICAST,MASTER,UP,LOWER_UP> mtu 1500 qdisc noqueue
>      link/ether 00:1d:09:67:6e:2f brd ff:ff:ff:ff:ff:ff
>      RX: bytes  packets  errors  dropped overrun mcast
>      2485605521 9010211  0       0       0       6
>      TX: bytes  packets  errors  dropped carrier collsns
>      3023237974 9345397  0       0       0       0
> 
> # ifconfig bond0
> bond0     Link encap:Ethernet  HWaddr 00:1D:09:67:6E:2F
>            inet addr:192.168.152.62  Bcast:192.168.152.255  Mask:255.255.255.0
>            inet6 addr: fe80::21d:9ff:fe67:6e2f/64 Scope:Link
>            UP BROADCAST RUNNING MASTER MULTICAST  MTU:1500  Metric:1
>            RX packets:9010367 errors:0 dropped:351 overruns:0 frame:0
>            TX packets:9345521 errors:0 dropped:0 overruns:0 carrier:0
>            collisions:0 txqueuelen:0
>            RX bytes:2485631020 (2370.4 Mb)  TX bytes:7318232294 (6979.2 Mb)
> 
> Is it possible to get 64-bit counters in ip via netlink? Struct 
> rtnl_link_stats does not look very optimistic, as it has rx_bytes/tx_bytes 
> defined with __u32.
> 
> Best regards,
> 
>  				Krzysztof Olędzki

The problem is the kernel binary API is now hard coded to 32 bit values.

-- 
Stephen Hemminger <stephen.hemminger@vyatta.com>



^ permalink raw reply

* Re: [PATCh TAKE 2] [IPROUTE2] Add addrlabel sub-command.
From: Stephen Hemminger @ 2008-02-13 20:37 UTC (permalink / raw)
  To: netdev
In-Reply-To: <20080214.032012.71214842.yoshfuji@linux-ipv6.org>

On Thu, 14 Feb 2008 03:20:12 +1100 (EST)
YOSHIFUJI Hideaki / 吉藤英明  <yoshfuji@linux-ipv6.org> wrote:

> Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
> ---
> diff --git a/ip/Makefile b/ip/Makefile
> index b427d58..d908817 100644
> --- a/ip/Makefile
> +++ b/ip/Makefile
> @@ -1,4 +1,4 @@
> -IPOBJ=ip.o ipaddress.o iproute.o iprule.o \
> +IPOBJ=ip.o ipaddress.o ipaddrlabel.o iproute.o iprule.o \
>      rtm_map.o iptunnel.o ip6tunnel.o tunnel.o ipneigh.o ipntable.o iplink.o \
>      ipmaddr.o ipmonitor.o ipmroute.o ipprefix.o \
>      ipxfrm.o xfrm_state.o xfrm_policy.o xfrm_monitor.o \
> diff --git a/ip/ip.c b/ip/ip.c
> index aeb8c68..c4c773f 100644
> --- a/ip/ip.c
> +++ b/ip/ip.c
> @@ -46,8 +46,8 @@ static void usage(void)
>  	fprintf(stderr,
>  "Usage: ip [ OPTIONS ] OBJECT { COMMAND | help }\n"
>  "       ip [ -force ] [-batch filename\n"
> -"where  OBJECT := { link | addr | route | rule | neigh | ntable | tunnel |\n"
> -"                   maddr | mroute | monitor | xfrm }\n"
> +"where  OBJECT := { link | addr | addrlabel | route | rule | neigh | ntable |\n"
> +"                   tunnel | maddr | mroute | monitor | xfrm }\n"
>  "       OPTIONS := { -V[ersion] | -s[tatistics] | -d[etails] | -r[esolve] |\n"
>  "                    -f[amily] { inet | inet6 | ipx | dnet | link } |\n"
>  "                    -o[neline] | -t[imestamp] }\n");
> @@ -64,6 +64,7 @@ static const struct cmd {
>  	int (*func)(int argc, char **argv);
>  } cmds[] = {
>  	{ "address", 	do_ipaddr },
> +	{ "addrlabel",	do_ipaddrlabel },
>  	{ "maddress",	do_multiaddr },
>  	{ "route",	do_iproute },
>  	{ "rule",	do_iprule },
> diff --git a/ip/ip_common.h b/ip/ip_common.h
> index 39f2507..1bbd50d 100644
> --- a/ip/ip_common.h
> +++ b/ip/ip_common.h
> @@ -4,6 +4,9 @@ extern int print_linkinfo(const struct sockaddr_nl *who,
>  extern int print_addrinfo(const struct sockaddr_nl *who,
>  			  struct nlmsghdr *n,
>  			  void *arg);
> +extern int print_addrlabelinfo(const struct sockaddr_nl *who,
> +			       struct nlmsghdr *n,
> +			       void *arg);
>  extern int print_neigh(const struct sockaddr_nl *who,
>  		       struct nlmsghdr *n, void *arg);
>  extern int print_ntable(const struct sockaddr_nl *who,
> @@ -23,6 +26,7 @@ extern int print_prefix(const struct sockaddr_nl *who,
>  extern int print_rule(const struct sockaddr_nl *who,
>  		      struct nlmsghdr *n, void *arg);
>  extern int do_ipaddr(int argc, char **argv);
> +extern int do_ipaddrlabel(int argc, char **argv);
>  extern int do_iproute(int argc, char **argv);
>  extern int do_iprule(int argc, char **argv);
>  extern int do_ipneigh(int argc, char **argv);
> diff --git a/ip/ipaddrlabel.c b/ip/ipaddrlabel.c
> new file mode 100644
> index 0000000..1c873e9
> --- /dev/null
> +++ b/ip/ipaddrlabel.c
> @@ -0,0 +1,260 @@
> +/*
> + * ipaddrlabel.c	"ip addrlabel"
> + *
> + * Copyright (C)2007 USAGI/WIDE Project
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
> + *
> + *
> + * Based on iprule.c.
> + *
> + * Authors:	YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
> + *
> + */
> +
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <unistd.h>
> +#include <syslog.h>
> +#include <fcntl.h>
> +#include <sys/socket.h>
> +#include <netinet/in.h>
> +#include <netinet/ip.h>
> +#include <arpa/inet.h>
> +#include <string.h>
> +#include <linux/types.h>
> +#include <linux/if_addrlabel.h>
> +
> +#include "rt_names.h"
> +#include "utils.h"
> +#include "ip_common.h"
> +
> +#define IFAL_RTA(r)	((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifaddrlblmsg))))
> +#define IFAL_PAYLOAD(n)	NLMSG_PAYLOAD(n,sizeof(struct ifaddrlblmsg))
> +
> +extern struct rtnl_handle rth;
> +
> +static void usage(void) __attribute__((noreturn));
> +
> +static void usage(void)
> +{
> +	fprintf(stderr, "Usage: ip addrlabel [ list | add | del | flush ] prefix PREFIX [ dev DEV ] [ label LABEL ]\n");
> +	exit(-1);
> +}
> +
> +int print_addrlabel(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
> +{
> +	FILE *fp = (FILE*)arg;
> +	struct ifaddrlblmsg *ifal = NLMSG_DATA(n);
> +	int len = n->nlmsg_len;
> +	int host_len = -1;
> +	struct rtattr *tb[IFAL_MAX+1];
> +	char abuf[256];
> +
> +	if (n->nlmsg_type != RTM_NEWADDRLABEL && n->nlmsg_type != RTM_DELADDRLABEL)
> +		return 0;
> +
> +	len -= NLMSG_LENGTH(sizeof(*ifal));
> +	if (len < 0)
> +		return -1;
> +
> +	parse_rtattr(tb, IFAL_MAX, IFAL_RTA(ifal), len);
> +
> +	if (ifal->ifal_family == AF_INET)
> +		host_len = 32;
> +	else if (ifal->ifal_family == AF_INET6)
> +		host_len = 128;
> +
> +	if (n->nlmsg_type == RTM_DELADDRLABEL)
> +		fprintf(fp, "Deleted ");
> +
> +	if (tb[IFAL_ADDRESS]) {
> +		fprintf(fp, "prefix %s/%u ",
> +			format_host(ifal->ifal_family,
> +				    RTA_PAYLOAD(tb[IFAL_ADDRESS]),
> +				    RTA_DATA(tb[IFAL_ADDRESS]),
> +				    abuf, sizeof(abuf)),
> +			ifal->ifal_prefixlen);
> +	}
> +
> +	if (ifal->ifal_index)
> +		fprintf(fp, "dev %s ", ll_index_to_name(ifal->ifal_index));
> +
> +	if (tb[IFAL_LABEL] && RTA_PAYLOAD(tb[IFAL_LABEL]) == sizeof(int32_t)) {
> +		int32_t label;
> +		memcpy(&label, RTA_DATA(tb[IFAL_LABEL]), sizeof(label));
> +		fprintf(fp, "label %d ", label);
> +	}
> +
> +	fprintf(fp, "\n");
> +	fflush(fp);
> +	return 0;
> +}
> +
> +static int ipaddrlabel_list(int argc, char **argv)
> +{
> +	int af = preferred_family;
> +
> +	if (af == AF_UNSPEC)
> +		af = AF_INET6;
> +
> +	if (argc > 0) {
> +		fprintf(stderr, "\"ip addrlabel show\" does not take any arguments.\n");
> +		return -1;
> +	}
> +
> +	if (rtnl_wilddump_request(&rth, af, RTM_GETADDRLABEL) < 0) {
> +		perror("Cannot send dump request");
> +		return 1;
> +	}
> +
> +	if (rtnl_dump_filter(&rth, print_addrlabel, stdout, NULL, NULL) < 0) {
> +		fprintf(stderr, "Dump terminated\n");
> +		return 1;
> +	}
> +
> +	return 0;
> +}
> +
> +
> +static int ipaddrlabel_modify(int cmd, int argc, char **argv)
> +{
> +	struct {
> +		struct nlmsghdr 	n;
> +		struct ifaddrlblmsg	ifal;
> +		char   			buf[1024];
> +	} req;
> +
> +	inet_prefix prefix;
> +	uint32_t label = 0xffffffffUL;
> +
> +	memset(&req, 0, sizeof(req));
> +	memset(&prefix, 0, sizeof(prefix));
> +
> +	req.n.nlmsg_type = cmd;
> +	req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrlblmsg));
> +	req.n.nlmsg_flags = NLM_F_REQUEST;
> +	req.ifal.ifal_family = preferred_family;
> +	req.ifal.ifal_prefixlen = 0;
> +	req.ifal.ifal_index = 0;
> +
> +	if (cmd == RTM_NEWADDRLABEL) {
> +		req.n.nlmsg_flags |= NLM_F_CREATE|NLM_F_EXCL;
> +	}
> +
> +	while (argc > 0) {
> +		if (strcmp(*argv, "prefix") == 0) {
> +			NEXT_ARG();
> +			get_prefix(&prefix, *argv, preferred_family);
> +		} else if (strcmp(*argv, "dev") == 0) {
> +			NEXT_ARG();
> +			if ((req.ifal.ifal_index = ll_name_to_index(*argv)) == 0)
> +				invarg("dev is invalid\n", *argv);
> +		} else if (strcmp(*argv, "label") == 0) {
> +			NEXT_ARG();
> +			if (get_u32(&label, *argv, 0) || label == 0xffffffffUL)
> +				invarg("label is invalid\n", *argv);
> +		}
> +		argc--;
> +		argv++;
> +	}
> +
> +	addattr32(&req.n, sizeof(req), IFAL_LABEL, label);
> +	addattr_l(&req.n, sizeof(req), IFAL_ADDRESS, &prefix.data, prefix.bytelen);
> +
> +	if (req.ifal.ifal_family == AF_UNSPEC)
> +		req.ifal.ifal_family = AF_INET6;
> +
> +	if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0)
> +		return 2;
> +
> +	return 0;
> +}
> +
> +
> +static int flush_addrlabel(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
> +{
> +	struct rtnl_handle rth2;
> +	struct rtmsg *r = NLMSG_DATA(n);
> +	int len = n->nlmsg_len;
> +	struct rtattr * tb[IFAL_MAX+1];
> +
> +	len -= NLMSG_LENGTH(sizeof(*r));
> +	if (len < 0)
> +		return -1;
> +
> +	parse_rtattr(tb, IFAL_MAX, RTM_RTA(r), len);
> +
> +	if (tb[IFAL_ADDRESS]) {
> +		n->nlmsg_type = RTM_DELADDRLABEL;
> +		n->nlmsg_flags = NLM_F_REQUEST;
> +
> +		if (rtnl_open(&rth2, 0) < 0)
> +			return -1;
> +
> +		if (rtnl_talk(&rth2, n, 0, 0, NULL, NULL, NULL) < 0)
> +			return -2;
> +
> +		rtnl_close(&rth2);
> +	}
> +
> +	return 0;
> +}
> +
> +static int ipaddrlabel_flush(int argc, char **argv)
> +{
> +	int af = preferred_family;
> +
> +	if (af == AF_UNSPEC)
> +		af = AF_INET6;
> +
> +	if (argc > 0) {
> +		fprintf(stderr, "\"ip addrlabel flush\" does not allow extra arguments\n");
> +		return -1;
> +	}
> +
> +	if (rtnl_wilddump_request(&rth, af, RTM_GETADDRLABEL) < 0) {
> +		perror("Cannot send dump request");
> +		return 1;
> +	}
> +
> +	if (rtnl_dump_filter(&rth, flush_addrlabel, NULL, NULL, NULL) < 0) {
> +		fprintf(stderr, "Flush terminated\n");
> +		return 1;
> +	}
> +
> +	return 0;
> +}
> +
> +int do_ipaddrlabel(int argc, char **argv)
> +{
> +	if (argc < 1) {
> +		return ipaddrlabel_list(0, NULL);
> +	} else if (matches(argv[0], "list") == 0 ||
> +		   matches(argv[0], "show") == 0) {
> +		return ipaddrlabel_list(argc-1, argv+1);
> +	} else if (matches(argv[0], "add") == 0) {
> +		return ipaddrlabel_modify(RTM_NEWADDRLABEL, argc-1, argv+1);
> +	} else if (matches(argv[0], "delete") == 0) {
> +		return ipaddrlabel_modify(RTM_DELADDRLABEL, argc-1, argv+1);
> +	} else if (matches(argv[0], "flush") == 0) {
> +		return ipaddrlabel_flush(argc-1, argv+1);
> +	} else if (matches(argv[0], "help") == 0)
> +		usage();
> +
> +	fprintf(stderr, "Command \"%s\" is unknown, try \"ip addrlabel help\".\n", *argv);
> +	exit(-1);
> +}
> +
> diff --git a/ip/ipmonitor.c b/ip/ipmonitor.c
> index f1a1f27..df0fd91 100644
> --- a/ip/ipmonitor.c
> +++ b/ip/ipmonitor.c
> @@ -54,6 +54,10 @@ int accept_msg(const struct sockaddr_nl *who,
>  		print_addrinfo(who, n, arg);
>  		return 0;
>  	}
> +	if (n->nlmsg_type == RTM_NEWADDRLABEL || n->nlmsg_type == RTM_DELADDRLABEL) {
> +		print_addrlabel(who, n, arg);
> +		return 0;
> +	}
>  	if (n->nlmsg_type == RTM_NEWNEIGH || n->nlmsg_type == RTM_DELNEIGH) {
>  		print_neigh(who, n, arg);
>  		return 0;
> diff --git a/man/man8/ip.8 b/man/man8/ip.8
> index 1687045..136448c 100644
> --- a/man/man8/ip.8
> +++ b/man/man8/ip.8
> @@ -13,8 +13,8 @@ ip \- show / manipulate routing, devices, policy routing and tunnels
>  
>  .ti -8
>  .IR OBJECT " := { "
> -.BR link " | " addr " | " route " | " rule " | " neigh " | " tunnel " | "\
> -maddr " | "  mroute " | " monitor " }"
> +.BR link " | " addr " | " addrlabel " | " route " | " rule " | " neigh " | "\
> + tunnel " | " maddr " | "  mroute " | " monitor " }"
>  .sp
>  
>  .ti -8
> @@ -97,6 +97,17 @@ maddr " | "  mroute " | " monitor " }"
>  tentative " | " deprecated " ]"
>  
>  .ti -8
> +.BR "ip addrlabel" " { " add " | " del " } " prefix 
> +.BR PREFIX " [ "
> +.B dev
> +.IR DEV " ] [ "
> +.B label
> +.IR NUMBER " ]"
> +
> +.ti -8
> +.BR "ip addrlabel" " { " list " | " flush " }"
> +
> +.ti -8
>  .BR "ip route" " { "
>  .BR list " | " flush " } "
>  .I  SELECTOR
> @@ -404,6 +415,11 @@ host addresses.
>  .TP
>  .B address
>  - protocol (IP or IPv6) address on a device.
> +
> +.TP
> +.B addrlabel
> +- label configuration for protocol address selection.
> +
>  .TP
>  .B neighbour
>  - ARP or NDISC cache entry.
> @@ -708,6 +724,33 @@ this option is given twice,
>  also dumps all the deleted addresses in the format described in the
>  previous subsection.
>  
> +.SH ip addrlabel - protocol address label management.
> +
> +IPv6 address label is used for address selection
> +described in RFC 3484.  Precedence is managed by userspace,
> +and only label is stored in kernel.
> +
> +.SS ip addrlabel add - add an address label
> +the command adds an address label entry to the kernel.
> +.TP
> +.BI prefix " PREFIX"
> +.TP
> +.BI dev " DEV"
> +the outgoing interface.
> +.TP
> +.BI label " NUMBER"
> +the label for the prefix.
> +0xffffffff is reserved.
> +.SS ip addrlabel del - delete an address label
> +the command deletes an address label entry in the kernel.
> +.B Arguments:
> +coincide with the arguments of
> +.B ip addrlabel add
> +but label is not required.
> +.SS ip addrlabel list - list address labels
> +the command show contents of address labels.
> +.SS ip addrlabel flush - flush address labels
> +the commoand flushes the contents of address labels and it does not restore default settings.
>  .SH ip neighbour - neighbour/arp tables management.
>  
>  .B neighbour
> 

applied

-- 
Stephen Hemminger <stephen.hemminger@vyatta.com>



^ permalink raw reply

* Re: [PATCH] [IPROUTE2] Update various classifiers' help output for expected CLASSID syntax
From: Stephen Hemminger @ 2008-02-13 20:37 UTC (permalink / raw)
  To: netdev
In-Reply-To: <20080213114909.13171.97451.stgit@localhost.localdomain>

On Wed, 13 Feb 2008 03:49:09 -0800
PJ Waskiewicz <peter.p.waskiewicz.jr@intel.com> wrote:

> update: Fix the spelling of "hexidecimal"
> 
> This updates the help output to specify that CLASSID should be hexidecimal.
> This makes sure that a user entering "flowid 1:10" gets his flow put into
> band 15 (0x10) and knows why.
> 
> Signed-off-by: Peter P Waskiewicz Jr <peter.p.waskiewicz.jr@intel.com>
> ---
> 
>  doc/actions/actions-general |    3 +++
>  tc/f_basic.c                |    1 +
>  tc/f_fw.c                   |    1 +
>  tc/f_route.c                |    1 +
>  tc/f_rsvp.c                 |    1 +
>  tc/f_u32.c                  |    1 +
>  6 files changed, 8 insertions(+), 0 deletions(-)
> 
> diff --git a/doc/actions/actions-general b/doc/actions/actions-general
> index 6561eda..70f7cd6 100644
> --- a/doc/actions/actions-general
> +++ b/doc/actions/actions-general
> @@ -88,6 +88,9 @@ tc filter add dev lo parent ffff: protocol ip prio 8 u32 \
>  match ip dst 127.0.0.8/32 flowid 1:12 \
>  action ipt -j mark --set-mark 2
>  
> +NOTE: flowid 1:12 is parsed flowid 0x1:0x12.  Make sure if you want flowid
> +decimal 12, then use flowid 1:c.
> +
>  3) A feature i call pipe
>  The motivation is derived from Unix pipe mechanism but applied to packets.
>  Essentially take a matching packet and pass it through 
> diff --git a/tc/f_basic.c b/tc/f_basic.c
> index 19a7edf..aab946b 100644
> --- a/tc/f_basic.c
> +++ b/tc/f_basic.c
> @@ -32,6 +32,7 @@ static void explain(void)
>  	fprintf(stderr, "\n");
>  	fprintf(stderr, "Where: SELECTOR := SAMPLE SAMPLE ...\n");
>  	fprintf(stderr, "       FILTERID := X:Y:Z\n");
> +	fprintf(stderr, "\nNOTE: CLASSID is parsed as hexadecimal input.\n");
>  }
>  
>  static int basic_parse_opt(struct filter_util *qu, char *handle,
> diff --git a/tc/f_fw.c b/tc/f_fw.c
> index 6d1490b..b511735 100644
> --- a/tc/f_fw.c
> +++ b/tc/f_fw.c
> @@ -28,6 +28,7 @@ static void explain(void)
>  	fprintf(stderr, "Usage: ... fw [ classid CLASSID ] [ police POLICE_SPEC ]\n");
>  	fprintf(stderr, "       POLICE_SPEC := ... look at TBF\n");
>  	fprintf(stderr, "       CLASSID := X:Y\n");
> +	fprintf(stderr, "\nNOTE: CLASSID is parsed as hexadecimal input.\n");
>  }
>  
>  #define usage() return(-1)
> diff --git a/tc/f_route.c b/tc/f_route.c
> index a41b9d5..67dd49c 100644
> --- a/tc/f_route.c
> +++ b/tc/f_route.c
> @@ -31,6 +31,7 @@ static void explain(void)
>  	fprintf(stderr, "                [ flowid CLASSID ] [ police POLICE_SPEC ]\n");
>  	fprintf(stderr, "       POLICE_SPEC := ... look at TBF\n");
>  	fprintf(stderr, "       CLASSID := X:Y\n");
> +	fprintf(stderr, "\nNOTE: CLASSID is parsed as hexadecimal input.\n");
>  }
>  
>  #define usage() return(-1)
> diff --git a/tc/f_rsvp.c b/tc/f_rsvp.c
> index 13fcf97..7e1e6d9 100644
> --- a/tc/f_rsvp.c
> +++ b/tc/f_rsvp.c
> @@ -34,6 +34,7 @@ static void explain(void)
>  	fprintf(stderr, "                u{8|16|32} NUMBER mask MASK at OFFSET}\n");
>  	fprintf(stderr, "       POLICE_SPEC := ... look at TBF\n");
>  	fprintf(stderr, "       FILTERID := X:Y\n");
> +	fprintf(stderr, "\nNOTE: CLASSID is parsed as hexadecimal input.\n");
>  }
>  
>  #define usage() return(-1)
> diff --git a/tc/f_u32.c b/tc/f_u32.c
> index 91f2838..d75e76c 100644
> --- a/tc/f_u32.c
> +++ b/tc/f_u32.c
> @@ -36,6 +36,7 @@ static void explain(void)
>  	fprintf(stderr, "Where: SELECTOR := SAMPLE SAMPLE ...\n");
>  	fprintf(stderr, "       SAMPLE := { ip | ip6 | udp | tcp | icmp | u{32|16|8} | mark } SAMPLE_ARGS [divisor DIVISOR]\n");
>  	fprintf(stderr, "       FILTERID := X:Y:Z\n");
> +	fprintf(stderr, "\nNOTE: CLASSID is parsed at hexadecimal input.\n");
>  }
>  
>  #define usage() return(-1)
> 
> --
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 

applied

-- 
Stephen Hemminger <stephen.hemminger@vyatta.com>



^ permalink raw reply

* Re: Patch to latest iproute to get it to compile on FC5
From: Ben Greear @ 2008-02-13 20:52 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: NetDev
In-Reply-To: <20080213123402.43cdbd45@extreme>

[-- Attachment #1: Type: text/plain, Size: 1785 bytes --]

Stephen Hemminger wrote:
> On Wed, 13 Feb 2008 11:32:32 -0800
> Ben Greear <greearb@candelatech.com> wrote:
> 
>> I notice that the latest snapshot and git repository for iproute
>> will not compile on FC5 due to not finding __constant_hton* symbols
>> and a lack of the hdlc/ioctl.h file on FC5.
>>
>> I am attaching a patch that appears to fix the problems for me.
>>
>> Please consider applying this or something similar.
>>
>> Signed-off-by:  Ben Greear <greearb@candelatech.com>
>>
>>
>> Thanks,
>> Ben
>>
> 
> I added include/linux/hdlc/ioctl.h to the santized headers in the
> current git.
> 

That seems to fix the hdlc issue, but it still will not link due to missing
symbols:

gcc -Wl,-export-dynamic  ip.o ipaddress.o ipaddrlabel.o iproute.o iprule.o rtm_map.o iptunnel.o ip6tunnel.o tunnel.o ipneigh.o ipntable.o iplink.o ipmaddr.o ipmonitor.o ipmroute.o ipprefix.o ipxfrm.o xfrm_state.o xfrm_policy.o xfrm_monitor.o iplink_vlan.o link_veth.o ../lib/libnetlink.a ../lib/libutil.a  -lresolv -L../lib -lnetlink -lutil -ldl -o ip
iptunnel.o: In function `parse_args':
iptunnel.c:(.text+0x2c6): undefined reference to `__constant_htons'
iptunnel.c:(.text+0x404): undefined reference to `__constant_htons'
iptunnel.c:(.text+0x48d): undefined reference to `__constant_htons'
iptunnel.c:(.text+0x4a6): undefined reference to `__constant_htons'
iptunnel.c:(.text+0x4e2): undefined reference to `__constant_htons'
iptunnel.o:iptunnel.c:(.text+0x4fb): more undefined references to `__constant_htons' follow
collect2: ld returned 1 exit status
make[1]: *** [ip] Error 1
make[1]: Leaving directory `/root/iproute2/ip'
make: *** [all] Error 2


The attached patch fixes this.

Thanks,
Ben


-- 
Ben Greear <greearb@candelatech.com>
Candela Technologies Inc  http://www.candelatech.com


[-- Attachment #2: iproute.fc5.patch --]
[-- Type: text/x-patch, Size: 350 bytes --]

diff --git a/include/linux/if_tunnel.h b/include/linux/if_tunnel.h
index 228eb4e..0eb5b04 100644
--- a/include/linux/if_tunnel.h
+++ b/include/linux/if_tunnel.h
@@ -2,6 +2,7 @@
 #define _IF_TUNNEL_H_
 
 #include <linux/types.h>
+#include <asm/byteorder.h>
 
 #define SIOCGETTUNNEL   (SIOCDEVPRIVATE + 0)
 #define SIOCADDTUNNEL   (SIOCDEVPRIVATE + 1)

^ permalink raw reply related

* [PATCH] [resend] 3c509: convert to isa_driver and pnp_driver v5
From: Ondrej Zary @ 2008-02-13 21:28 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: Stephen Hemminger, linux-kernel, netdev
In-Reply-To: <20080210051855.GA22064@infradead.org>

Hello,
this patch converts 3c509 driver to isa_driver and pnp_driver. The result is 
that autoloading using udev and hibernation works with ISA PnP cards. It also 
adds hibernation support for non-PnP ISA cards.

xcvr module parameter was removed as its value was not used.

Tested using 3 ISA cards in various combinations of PnP and non-PnP modes. 
EISA and MCA only compile-tested.

Signed-off-by: Ondrej Zary <linux@rainbow-software.org>

--- linux-2.6.24-orig/drivers/net/3c509.c	2008-01-27 19:48:19.000000000 +0100
+++ linux-2.6.24-pentium/drivers/net/3c509.c	2008-02-10 21:52:04.000000000 +0100
@@ -54,25 +54,24 @@
 		v1.19a 28Oct2002 Davud Ruggiero <jdr@farfalle.com>
 			- Increase *read_eeprom udelay to workaround oops with 2 cards.
 		v1.19b 08Nov2002 Marc Zyngier <maz@wild-wind.fr.eu.org>
-		    - Introduce driver model for EISA cards.
+			- Introduce driver model for EISA cards.
+		v1.20  04Feb2008 Ondrej Zary <linux@rainbow-software.org>
+			- convert to isa_driver and pnp_driver and some cleanups
 */
 
 #define DRV_NAME	"3c509"
-#define DRV_VERSION	"1.19b"
-#define DRV_RELDATE	"08Nov2002"
+#define DRV_VERSION	"1.20"
+#define DRV_RELDATE	"04Feb2008"
 
 /* A few values that may be tweaked. */
 
 /* Time in jiffies before concluding the transmitter is hung. */
 #define TX_TIMEOUT  (400*HZ/1000)
-/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
-static int max_interrupt_work = 10;
 
 #include <linux/module.h>
-#ifdef CONFIG_MCA
 #include <linux/mca.h>
-#endif
-#include <linux/isapnp.h>
+#include <linux/isa.h>
+#include <linux/pnp.h>
 #include <linux/string.h>
 #include <linux/interrupt.h>
 #include <linux/errno.h>
@@ -97,10 +96,6 @@
 
 static char version[] __initdata = DRV_NAME ".c:" DRV_VERSION " " DRV_RELDATE " becker@scyld.com\n";
 
-#if defined(CONFIG_PM) && (defined(CONFIG_MCA) || defined(CONFIG_EISA))
-#define EL3_SUSPEND
-#endif
-
 #ifdef EL3_DEBUG
 static int el3_debug = EL3_DEBUG;
 #else
@@ -111,6 +106,7 @@
  * a global variable so that the mca/eisa probe routines can increment
  * it */
 static int el3_cards = 0;
+#define EL3_MAX_CARDS 8
 
 /* To minimize the size of the driver source I only define operating
    constants if they are used several times.  You'll need the manual
@@ -119,7 +115,7 @@
 #define EL3_DATA 0x00
 #define EL3_CMD 0x0e
 #define EL3_STATUS 0x0e
-#define	 EEPROM_READ 0x80
+#define	EEPROM_READ 0x80
 
 #define EL3_IO_EXTENT	16
 
@@ -168,23 +164,31 @@
  */
 #define SKB_QUEUE_SIZE	64
 
+enum el3_cardtype { EL3_ISA, EL3_PNP, EL3_MCA, EL3_EISA };
+
 struct el3_private {
 	struct net_device_stats stats;
-	struct net_device *next_dev;
 	spinlock_t lock;
 	/* skb send-queue */
 	int head, size;
 	struct sk_buff *queue[SKB_QUEUE_SIZE];
-	enum {
-		EL3_MCA,
-		EL3_PNP,
-		EL3_EISA,
-	} type;						/* type of device */
-	struct device *dev;
+	enum el3_cardtype type;
 };
-static int id_port __initdata = 0x110;	/* Start with 0x110 to avoid new sound cards.*/
-static struct net_device *el3_root_dev;
+static int id_port;
+static int current_tag;
+static struct net_device *el3_devs[EL3_MAX_CARDS];
+
+/* Parameters that may be passed into the module. */
+static int debug = -1;
+static int irq[] = {-1, -1, -1, -1, -1, -1, -1, -1};
+/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
+static int max_interrupt_work = 10;
+#ifdef CONFIG_PNP
+static int nopnp;
+#endif
 
+static int __init el3_common_init(struct net_device *dev);
+static void el3_common_remove(struct net_device *dev);
 static ushort id_read_eeprom(int index);
 static ushort read_eeprom(int ioaddr, int index);
 static int el3_open(struct net_device *dev);
@@ -199,23 +203,279 @@
 static void el3_down(struct net_device *dev);
 static void el3_up(struct net_device *dev);
 static const struct ethtool_ops ethtool_ops;
-#ifdef EL3_SUSPEND
+#ifdef CONFIG_PM
 static int el3_suspend(struct device *, pm_message_t);
 static int el3_resume(struct device *);
-#else
-#define el3_suspend NULL
-#define el3_resume NULL
 #endif
 
 
 /* generic device remove for all device types */
-#if defined(CONFIG_EISA) || defined(CONFIG_MCA)
 static int el3_device_remove (struct device *device);
-#endif
 #ifdef CONFIG_NET_POLL_CONTROLLER
 static void el3_poll_controller(struct net_device *dev);
 #endif
 
+/* Return 0 on success, 1 on error, 2 when found already detected PnP card */
+static int el3_isa_id_sequence(__be16 *phys_addr)
+{
+	short lrs_state = 0xff;
+	int i;
+
+	/* ISA boards are detected by sending the ID sequence to the
+	   ID_PORT.  We find cards past the first by setting the 'current_tag'
+	   on cards as they are found.  Cards with their tag set will not
+	   respond to subsequent ID sequences. */
+
+	outb(0x00, id_port);
+	outb(0x00, id_port);
+	for (i = 0; i < 255; i++) {
+		outb(lrs_state, id_port);
+		lrs_state <<= 1;
+		lrs_state = lrs_state & 0x100 ? lrs_state ^ 0xcf : lrs_state;
+	}
+	/* For the first probe, clear all board's tag registers. */
+	if (current_tag == 0)
+		outb(0xd0, id_port);
+	else			/* Otherwise kill off already-found boards. */
+		outb(0xd8, id_port);
+	if (id_read_eeprom(7) != 0x6d50)
+		return 1;
+	/* Read in EEPROM data, which does contention-select.
+	   Only the lowest address board will stay "on-line".
+	   3Com got the byte order backwards. */
+	for (i = 0; i < 3; i++)
+		phys_addr[i] = htons(id_read_eeprom(i));
+#ifdef CONFIG_PNP
+	if (!nopnp) {
+		/* The ISA PnP 3c509 cards respond to the ID sequence too.
+		   This check is needed in order not to register them twice. */
+		for (i = 0; i < el3_cards; i++) {
+			struct el3_private *lp = netdev_priv(el3_devs[i]);
+			if (lp->type == EL3_PNP
+			    && !memcmp(phys_addr, el3_devs[i]->dev_addr,
+				       ETH_ALEN)) {
+				if (el3_debug > 3)
+					printk(KERN_DEBUG "3c509 with address %02x %02x %02x %02x %02x %02x was found by ISAPnP\n",
+						phys_addr[0] & 0xff, phys_addr[0] >> 8,
+						phys_addr[1] & 0xff, phys_addr[1] >> 8,
+						phys_addr[2] & 0xff, phys_addr[2] >> 8);
+				/* Set the adaptor tag so that the next card can be found. */
+				outb(0xd0 + ++current_tag, id_port);
+				return 2;
+			}
+		}
+	}
+#endif /* CONFIG_PNP */
+	return 0;
+
+}
+
+static void __devinit el3_dev_fill(struct net_device *dev, __be16 *phys_addr,
+				   int ioaddr, int irq, int if_port,
+				   enum el3_cardtype type)
+{
+	struct el3_private *lp = netdev_priv(dev);
+
+	memcpy(dev->dev_addr, phys_addr, ETH_ALEN);
+	dev->base_addr = ioaddr;
+	dev->irq = irq;
+	dev->if_port = if_port;
+	lp->type = type;
+}
+
+static int __devinit el3_isa_match(struct device *pdev,
+				   unsigned int ndev)
+{
+	struct net_device *dev;
+	int ioaddr, isa_irq, if_port, err;
+	unsigned int iobase;
+	__be16 phys_addr[3];
+
+	while ((err = el3_isa_id_sequence(phys_addr)) == 2)
+		;	/* Skip to next card when PnP card found */
+	if (err == 1)
+		return 0;
+
+	iobase = id_read_eeprom(8);
+	if_port = iobase >> 14;
+	ioaddr = 0x200 + ((iobase & 0x1f) << 4);
+	if (irq[el3_cards] > 1 && irq[el3_cards] < 16)
+		isa_irq = irq[el3_cards];
+	else
+		isa_irq = id_read_eeprom(9) >> 12;
+
+	dev = alloc_etherdev(sizeof(struct el3_private));
+	if (!dev)
+		return -ENOMEM;
+
+	netdev_boot_setup_check(dev);
+
+	if (!request_region(ioaddr, EL3_IO_EXTENT, "3c509-isa")) {
+		free_netdev(dev);
+		return 0;
+	}
+
+	/* Set the adaptor tag so that the next card can be found. */
+	outb(0xd0 + ++current_tag, id_port);
+
+	/* Activate the adaptor at the EEPROM location. */
+	outb((ioaddr >> 4) | 0xe0, id_port);
+
+	EL3WINDOW(0);
+	if (inw(ioaddr) != 0x6d50) {
+		free_netdev(dev);
+		return 0;
+	}
+
+	/* Free the interrupt so that some other card can use it. */
+	outw(0x0f00, ioaddr + WN0_IRQ);
+
+	el3_dev_fill(dev, phys_addr, ioaddr, isa_irq, if_port, EL3_ISA);
+	dev_set_drvdata(pdev, dev);
+	if (el3_common_init(dev)) {
+		free_netdev(dev);
+		return 0;
+	}
+
+	el3_devs[el3_cards++] = dev;
+	return 1;
+}
+
+static int __devexit el3_isa_remove(struct device *pdev,
+				    unsigned int ndev)
+{
+	el3_device_remove(pdev);
+	dev_set_drvdata(pdev, NULL);
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int el3_isa_suspend(struct device *dev, unsigned int n,
+			   pm_message_t state)
+{
+	current_tag = 0;
+	return el3_suspend(dev, state);
+}
+
+static int el3_isa_resume(struct device *dev, unsigned int n)
+{
+	struct net_device *ndev = dev_get_drvdata(dev);
+	int ioaddr = ndev->base_addr, err;
+	__be16 phys_addr[3];
+
+	while ((err = el3_isa_id_sequence(phys_addr)) == 2)
+		;	/* Skip to next card when PnP card found */
+	if (err == 1)
+		return 0;
+	/* Set the adaptor tag so that the next card can be found. */
+	outb(0xd0 + ++current_tag, id_port);
+	/* Enable the card */
+	outb((ioaddr >> 4) | 0xe0, id_port);
+	EL3WINDOW(0);
+	if (inw(ioaddr) != 0x6d50)
+		return 1;
+	/* Free the interrupt so that some other card can use it. */
+	outw(0x0f00, ioaddr + WN0_IRQ);
+	return el3_resume(dev);
+}
+#endif
+
+static struct isa_driver el3_isa_driver = {
+	.match		= el3_isa_match,
+	.remove		= __devexit_p(el3_isa_remove),
+#ifdef CONFIG_PM
+	.suspend	= el3_isa_suspend,
+	.resume		= el3_isa_resume,
+#endif
+	.driver		= {
+		.name	= "3c509"
+	},
+};
+static int isa_registered;
+
+#ifdef CONFIG_PNP
+static struct pnp_device_id el3_pnp_ids[] = {
+	{ .id = "TCM5090" }, /* 3Com Etherlink III (TP) */
+	{ .id = "TCM5091" }, /* 3Com Etherlink III */
+	{ .id = "TCM5094" }, /* 3Com Etherlink III (combo) */
+	{ .id = "TCM5095" }, /* 3Com Etherlink III (TPO) */
+	{ .id = "TCM5098" }, /* 3Com Etherlink III (TPC) */
+	{ .id = "PNP80f7" }, /* 3Com Etherlink III compatible */
+	{ .id = "PNP80f8" }, /* 3Com Etherlink III compatible */
+	{ .id = "" }
+};
+MODULE_DEVICE_TABLE(pnp, el3_pnp_ids);
+
+static int __devinit el3_pnp_probe(struct pnp_dev *pdev,
+				    const struct pnp_device_id *id)
+{
+	short i;
+	int ioaddr, irq, if_port;
+	u16 phys_addr[3];
+	struct net_device *dev = NULL;
+	int err;
+
+	ioaddr = pnp_port_start(pdev, 0);
+	if (!request_region(ioaddr, EL3_IO_EXTENT, "3c509-pnp"))
+		return -EBUSY;
+	irq = pnp_irq(pdev, 0);
+	EL3WINDOW(0);
+	for (i = 0; i < 3; i++)
+		phys_addr[i] = htons(read_eeprom(ioaddr, i));
+	if_port = read_eeprom(ioaddr, 8) >> 14;
+	dev = alloc_etherdev(sizeof(struct el3_private));
+	if (!dev) {
+		release_region(ioaddr, EL3_IO_EXTENT);
+		return -ENOMEM;
+	}
+	SET_NETDEV_DEV(dev, &pdev->dev);
+	netdev_boot_setup_check(dev);
+
+	el3_dev_fill(dev, phys_addr, ioaddr, irq, if_port, EL3_PNP);
+	pnp_set_drvdata(pdev, dev);
+	err = el3_common_init(dev);
+
+	if (err) {
+		pnp_set_drvdata(pdev, NULL);
+		free_netdev(dev);
+		return err;
+	}
+
+	el3_devs[el3_cards++] = dev;
+	return 0;
+}
+
+static void __devexit el3_pnp_remove(struct pnp_dev *pdev)
+{
+	el3_common_remove(pnp_get_drvdata(pdev));
+	pnp_set_drvdata(pdev, NULL);
+}
+
+#ifdef CONFIG_PM
+static int el3_pnp_suspend(struct pnp_dev *pdev, pm_message_t state)
+{
+	return el3_suspend(&pdev->dev, state);
+}
+
+static int el3_pnp_resume(struct pnp_dev *pdev)
+{
+	return el3_resume(&pdev->dev);
+}
+#endif
+
+static struct pnp_driver el3_pnp_driver = {
+	.name		= "3c509",
+	.id_table	= el3_pnp_ids,
+	.probe		= el3_pnp_probe,
+	.remove		= __devexit_p(el3_pnp_remove),
+#ifdef CONFIG_PM
+	.suspend	= el3_pnp_suspend,
+	.resume		= el3_pnp_resume,
+#endif
+};
+static int pnp_registered;
+#endif /* CONFIG_PNP */
+
 #ifdef CONFIG_EISA
 static struct eisa_device_id el3_eisa_ids[] = {
 		{ "TCM5092" },
@@ -230,13 +490,14 @@
 static struct eisa_driver el3_eisa_driver = {
 		.id_table = el3_eisa_ids,
 		.driver   = {
-				.name    = "3c509",
+				.name    = "3c579",
 				.probe   = el3_eisa_probe,
 				.remove  = __devexit_p (el3_device_remove),
 				.suspend = el3_suspend,
 				.resume  = el3_resume,
 		}
 };
+static int eisa_registered;
 #endif
 
 #ifdef CONFIG_MCA
@@ -271,45 +532,9 @@
 				.resume  = el3_resume,
 		},
 };
+static int mca_registered;
 #endif /* CONFIG_MCA */
 
-#if defined(__ISAPNP__)
-static struct isapnp_device_id el3_isapnp_adapters[] __initdata = {
-	{	ISAPNP_ANY_ID, ISAPNP_ANY_ID,
-		ISAPNP_VENDOR('T', 'C', 'M'), ISAPNP_FUNCTION(0x5090),
-		(long) "3Com Etherlink III (TP)" },
-	{	ISAPNP_ANY_ID, ISAPNP_ANY_ID,
-		ISAPNP_VENDOR('T', 'C', 'M'), ISAPNP_FUNCTION(0x5091),
-		(long) "3Com Etherlink III" },
-	{	ISAPNP_ANY_ID, ISAPNP_ANY_ID,
-		ISAPNP_VENDOR('T', 'C', 'M'), ISAPNP_FUNCTION(0x5094),
-		(long) "3Com Etherlink III (combo)" },
-	{	ISAPNP_ANY_ID, ISAPNP_ANY_ID,
-		ISAPNP_VENDOR('T', 'C', 'M'), ISAPNP_FUNCTION(0x5095),
-		(long) "3Com Etherlink III (TPO)" },
-	{	ISAPNP_ANY_ID, ISAPNP_ANY_ID,
-		ISAPNP_VENDOR('T', 'C', 'M'), ISAPNP_FUNCTION(0x5098),
-		(long) "3Com Etherlink III (TPC)" },
-	{	ISAPNP_ANY_ID, ISAPNP_ANY_ID,
-		ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_FUNCTION(0x80f7),
-		(long) "3Com Etherlink III compatible" },
-	{	ISAPNP_ANY_ID, ISAPNP_ANY_ID,
-		ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_FUNCTION(0x80f8),
-		(long) "3Com Etherlink III compatible" },
-	{ }	/* terminate list */
-};
-
-static __be16 el3_isapnp_phys_addr[8][3];
-static int nopnp;
-#endif /* __ISAPNP__ */
-
-/* With the driver model introduction for EISA devices, both init
- * and cleanup have been split :
- * - EISA devices probe/remove starts in el3_eisa_probe/el3_device_remove
- * - MCA/ISA still use el3_probe
- *
- * Both call el3_common_init/el3_common_remove. */
-
 static int __init el3_common_init(struct net_device *dev)
 {
 	struct el3_private *lp = netdev_priv(dev);
@@ -360,231 +585,11 @@
 
 static void el3_common_remove (struct net_device *dev)
 {
-	struct el3_private *lp = netdev_priv(dev);
-
-	(void) lp;				/* Keep gcc quiet... */
-#if defined(__ISAPNP__)
-	if (lp->type == EL3_PNP)
-		pnp_device_detach(to_pnp_dev(lp->dev));
-#endif
-
 	unregister_netdev (dev);
 	release_region(dev->base_addr, EL3_IO_EXTENT);
 	free_netdev (dev);
 }
 
-static int __init el3_probe(int card_idx)
-{
-	struct net_device *dev;
-	struct el3_private *lp;
-	short lrs_state = 0xff, i;
-	int ioaddr, irq, if_port;
-	__be16 phys_addr[3];
-	static int current_tag;
-	int err = -ENODEV;
-#if defined(__ISAPNP__)
-	static int pnp_cards;
-	struct pnp_dev *idev = NULL;
-	int pnp_found = 0;
-
-	if (nopnp == 1)
-		goto no_pnp;
-
-	for (i=0; el3_isapnp_adapters[i].vendor != 0; i++) {
-		int j;
-		while ((idev = pnp_find_dev(NULL,
-					    el3_isapnp_adapters[i].vendor,
-					    el3_isapnp_adapters[i].function,
-					    idev))) {
-			if (pnp_device_attach(idev) < 0)
-				continue;
-			if (pnp_activate_dev(idev) < 0) {
-__again:
-				pnp_device_detach(idev);
-				continue;
-			}
-			if (!pnp_port_valid(idev, 0) || !pnp_irq_valid(idev, 0))
-				goto __again;
-			ioaddr = pnp_port_start(idev, 0);
-			if (!request_region(ioaddr, EL3_IO_EXTENT, "3c509 PnP")) {
-				pnp_device_detach(idev);
-				return -EBUSY;
-			}
-			irq = pnp_irq(idev, 0);
-			if (el3_debug > 3)
-				printk ("ISAPnP reports %s at i/o 0x%x, irq %d\n",
-					(char*) el3_isapnp_adapters[i].driver_data, ioaddr, irq);
-			EL3WINDOW(0);
-			for (j = 0; j < 3; j++)
-				el3_isapnp_phys_addr[pnp_cards][j] =
-					phys_addr[j] =
-						htons(read_eeprom(ioaddr, j));
-			if_port = read_eeprom(ioaddr, 8) >> 14;
-			dev = alloc_etherdev(sizeof (struct el3_private));
-			if (!dev) {
-					release_region(ioaddr, EL3_IO_EXTENT);
-					pnp_device_detach(idev);
-					return -ENOMEM;
-			}
-
-			SET_NETDEV_DEV(dev, &idev->dev);
-			pnp_cards++;
-
-			netdev_boot_setup_check(dev);
-			pnp_found = 1;
-			goto found;
-		}
-	}
-no_pnp:
-#endif /* __ISAPNP__ */
-
-	/* Select an open I/O location at 0x1*0 to do contention select. */
-	for ( ; id_port < 0x200; id_port += 0x10) {
-		if (!request_region(id_port, 1, "3c509"))
-			continue;
-		outb(0x00, id_port);
-		outb(0xff, id_port);
-		if (inb(id_port) & 0x01){
-			release_region(id_port, 1);
-			break;
-		} else
-			release_region(id_port, 1);
-	}
-	if (id_port >= 0x200) {
-		/* Rare -- do we really need a warning? */
-		printk(" WARNING: No I/O port available for 3c509 activation.\n");
-		return -ENODEV;
-	}
-
-	/* Next check for all ISA bus boards by sending the ID sequence to the
-	   ID_PORT.  We find cards past the first by setting the 'current_tag'
-	   on cards as they are found.  Cards with their tag set will not
-	   respond to subsequent ID sequences. */
-
-	outb(0x00, id_port);
-	outb(0x00, id_port);
-	for(i = 0; i < 255; i++) {
-		outb(lrs_state, id_port);
-		lrs_state <<= 1;
-		lrs_state = lrs_state & 0x100 ? lrs_state ^ 0xcf : lrs_state;
-	}
-
-	/* For the first probe, clear all board's tag registers. */
-	if (current_tag == 0)
-		outb(0xd0, id_port);
-	else				/* Otherwise kill off already-found boards. */
-		outb(0xd8, id_port);
-
-	if (id_read_eeprom(7) != 0x6d50) {
-		return -ENODEV;
-	}
-
-	/* Read in EEPROM data, which does contention-select.
-	   Only the lowest address board will stay "on-line".
-	   3Com got the byte order backwards. */
-	for (i = 0; i < 3; i++) {
-		phys_addr[i] = htons(id_read_eeprom(i));
-	}
-
-#if defined(__ISAPNP__)
-	if (nopnp == 0) {
-		/* The ISA PnP 3c509 cards respond to the ID sequence.
-		   This check is needed in order not to register them twice. */
-		for (i = 0; i < pnp_cards; i++) {
-			if (phys_addr[0] == el3_isapnp_phys_addr[i][0] &&
-			    phys_addr[1] == el3_isapnp_phys_addr[i][1] &&
-			    phys_addr[2] == el3_isapnp_phys_addr[i][2])
-			{
-				if (el3_debug > 3)
-					printk("3c509 with address %02x %02x %02x %02x %02x %02x was found by ISAPnP\n",
-						phys_addr[0] & 0xff, phys_addr[0] >> 8,
-						phys_addr[1] & 0xff, phys_addr[1] >> 8,
-						phys_addr[2] & 0xff, phys_addr[2] >> 8);
-				/* Set the adaptor tag so that the next card can be found. */
-				outb(0xd0 + ++current_tag, id_port);
-				goto no_pnp;
-			}
-		}
-	}
-#endif /* __ISAPNP__ */
-
-	{
-		unsigned int iobase = id_read_eeprom(8);
-		if_port = iobase >> 14;
-		ioaddr = 0x200 + ((iobase & 0x1f) << 4);
-	}
-	irq = id_read_eeprom(9) >> 12;
-
-	dev = alloc_etherdev(sizeof (struct el3_private));
-	if (!dev)
-		return -ENOMEM;
-
-	netdev_boot_setup_check(dev);
-
-	/* Set passed-in IRQ or I/O Addr. */
-	if (dev->irq > 1  &&  dev->irq < 16)
-			irq = dev->irq;
-
-	if (dev->base_addr) {
-		if (dev->mem_end == 0x3c509 	/* Magic key */
-		    && dev->base_addr >= 0x200  &&  dev->base_addr <= 0x3e0)
-			ioaddr = dev->base_addr & 0x3f0;
-		else if (dev->base_addr != ioaddr)
-			goto out;
-	}
-
-	if (!request_region(ioaddr, EL3_IO_EXTENT, "3c509")) {
-		err = -EBUSY;
-		goto out;
-	}
-
-	/* Set the adaptor tag so that the next card can be found. */
-	outb(0xd0 + ++current_tag, id_port);
-
-	/* Activate the adaptor at the EEPROM location. */
-	outb((ioaddr >> 4) | 0xe0, id_port);
-
-	EL3WINDOW(0);
-	if (inw(ioaddr) != 0x6d50)
-		goto out1;
-
-	/* Free the interrupt so that some other card can use it. */
-	outw(0x0f00, ioaddr + WN0_IRQ);
-
-#if defined(__ISAPNP__)
- found:							/* PNP jumps here... */
-#endif /* __ISAPNP__ */
-
-	memcpy(dev->dev_addr, phys_addr, sizeof(phys_addr));
-	dev->base_addr = ioaddr;
-	dev->irq = irq;
-	dev->if_port = if_port;
-	lp = netdev_priv(dev);
-#if defined(__ISAPNP__)
-	lp->dev = &idev->dev;
-	if (pnp_found)
-		lp->type = EL3_PNP;
-#endif
-	err = el3_common_init(dev);
-
-	if (err)
-		goto out1;
-
-	el3_cards++;
-	lp->next_dev = el3_root_dev;
-	el3_root_dev = dev;
-	return 0;
-
-out1:
-#if defined(__ISAPNP__)
-	if (idev)
-		pnp_device_detach(idev);
-#endif
-out:
-	free_netdev(dev);
-	return err;
-}
-
 #ifdef CONFIG_MCA
 static int __init el3_mca_probe(struct device *device)
 {
@@ -596,7 +601,6 @@
 	 * redone for multi-card detection by ZP Gu (zpg@castle.net)
 	 * now works as a module */
 
-	struct el3_private *lp;
 	short i;
 	int ioaddr, irq, if_port;
 	u16 phys_addr[3];
@@ -613,7 +617,7 @@
 	irq = pos5 & 0x0f;
 
 
-	printk("3c529: found %s at slot %d\n",
+	printk(KERN_INFO "3c529: found %s at slot %d\n",
 		   el3_mca_adapter_names[mdev->index], slot + 1);
 
 	/* claim the slot */
@@ -626,7 +630,7 @@
 	irq = mca_device_transform_irq(mdev, irq);
 	ioaddr = mca_device_transform_ioport(mdev, ioaddr);
 	if (el3_debug > 2) {
-			printk("3c529: irq %d  ioaddr 0x%x  ifport %d\n", irq, ioaddr, if_port);
+			printk(KERN_DEBUG "3c529: irq %d  ioaddr 0x%x  ifport %d\n", irq, ioaddr, if_port);
 	}
 	EL3WINDOW(0);
 	for (i = 0; i < 3; i++) {
@@ -641,13 +645,7 @@
 
 	netdev_boot_setup_check(dev);
 
-	memcpy(dev->dev_addr, phys_addr, sizeof(phys_addr));
-	dev->base_addr = ioaddr;
-	dev->irq = irq;
-	dev->if_port = if_port;
-	lp = netdev_priv(dev);
-	lp->dev = device;
-	lp->type = EL3_MCA;
+	el3_dev_fill(dev, phys_addr, ioaddr, irq, if_port, EL3_MCA);
 	device->driver_data = dev;
 	err = el3_common_init(dev);
 
@@ -657,7 +655,7 @@
 		return -ENOMEM;
 	}
 
-	el3_cards++;
+	el3_devs[el3_cards++] = dev;
 	return 0;
 }
 
@@ -666,7 +664,6 @@
 #ifdef CONFIG_EISA
 static int __init el3_eisa_probe (struct device *device)
 {
-	struct el3_private *lp;
 	short i;
 	int ioaddr, irq, if_port;
 	u16 phys_addr[3];
@@ -678,7 +675,7 @@
 	edev = to_eisa_device (device);
 	ioaddr = edev->base_addr;
 
-	if (!request_region(ioaddr, EL3_IO_EXTENT, "3c509"))
+	if (!request_region(ioaddr, EL3_IO_EXTENT, "3c579-eisa"))
 		return -EBUSY;
 
 	/* Change the register set to the configuration window 0. */
@@ -700,13 +697,7 @@
 
 	netdev_boot_setup_check(dev);
 
-	memcpy(dev->dev_addr, phys_addr, sizeof(phys_addr));
-	dev->base_addr = ioaddr;
-	dev->irq = irq;
-	dev->if_port = if_port;
-	lp = netdev_priv(dev);
-	lp->dev = device;
-	lp->type = EL3_EISA;
+	el3_dev_fill(dev, phys_addr, ioaddr, irq, if_port, EL3_EISA);
 	eisa_set_drvdata (edev, dev);
 	err = el3_common_init(dev);
 
@@ -716,12 +707,11 @@
 		return err;
 	}
 
-	el3_cards++;
+	el3_devs[el3_cards++] = dev;
 	return 0;
 }
 #endif
 
-#if defined(CONFIG_EISA) || defined(CONFIG_MCA)
 /* This remove works for all device types.
  *
  * The net dev must be stored in the driver_data field */
@@ -734,7 +724,6 @@
 	el3_common_remove (dev);
 	return 0;
 }
-#endif
 
 /* Read a word from the EEPROM using the regular EEPROM access register.
    Assume that we are in register window zero.
@@ -749,7 +738,7 @@
 }
 
 /* Read a word from the EEPROM when in the ISA ID probe state. */
-static ushort __init id_read_eeprom(int index)
+static ushort id_read_eeprom(int index)
 {
 	int bit, word = 0;
 
@@ -765,7 +754,7 @@
 		word = (word << 1) + (inb(id_port) & 0x01);
 
 	if (el3_debug > 3)
-		printk("  3c509 EEPROM word %d %#4.4x.\n", index, word);
+		printk(KERN_DEBUG "  3c509 EEPROM word %d %#4.4x.\n", index, word);
 
 	return word;
 }
@@ -787,13 +776,13 @@
 
 	EL3WINDOW(0);
 	if (el3_debug > 3)
-		printk("%s: Opening, IRQ %d	 status@%x %4.4x.\n", dev->name,
+		printk(KERN_DEBUG "%s: Opening, IRQ %d	 status@%x %4.4x.\n", dev->name,
 			   dev->irq, ioaddr + EL3_STATUS, inw(ioaddr + EL3_STATUS));
 
 	el3_up(dev);
 
 	if (el3_debug > 3)
-		printk("%s: Opened 3c509  IRQ %d  status %4.4x.\n",
+		printk(KERN_DEBUG "%s: Opened 3c509  IRQ %d  status %4.4x.\n",
 			   dev->name, dev->irq, inw(ioaddr + EL3_STATUS));
 
 	return 0;
@@ -806,7 +795,7 @@
 	int ioaddr = dev->base_addr;
 
 	/* Transmitter timeout, serious problems. */
-	printk("%s: transmit timed out, Tx_status %2.2x status %4.4x "
+	printk(KERN_WARNING "%s: transmit timed out, Tx_status %2.2x status %4.4x "
 		   "Tx FIFO room %d.\n",
 		   dev->name, inb(ioaddr + TX_STATUS), inw(ioaddr + EL3_STATUS),
 		   inw(ioaddr + TX_FREE));
@@ -831,7 +820,7 @@
 	lp->stats.tx_bytes += skb->len;
 
 	if (el3_debug > 4) {
-		printk("%s: el3_start_xmit(length = %u) called, status %4.4x.\n",
+		printk(KERN_DEBUG "%s: el3_start_xmit(length = %u) called, status %4.4x.\n",
 			   dev->name, skb->len, inw(ioaddr + EL3_STATUS));
 	}
 #if 0
@@ -840,7 +829,7 @@
 		ushort status = inw(ioaddr + EL3_STATUS);
 		if (status & 0x0001 		/* IRQ line active, missed one. */
 			&& inw(ioaddr + EL3_STATUS) & 1) { 			/* Make sure. */
-			printk("%s: Missed interrupt, status then %04x now %04x"
+			printk(KERN_DEBUG "%s: Missed interrupt, status then %04x now %04x"
 				   "  Tx %2.2x Rx %4.4x.\n", dev->name, status,
 				   inw(ioaddr + EL3_STATUS), inb(ioaddr + TX_STATUS),
 				   inw(ioaddr + RX_STATUS));
@@ -914,7 +903,7 @@
 
 	if (el3_debug > 4) {
 		status = inw(ioaddr + EL3_STATUS);
-		printk("%s: interrupt, status %4.4x.\n", dev->name, status);
+		printk(KERN_DEBUG "%s: interrupt, status %4.4x.\n", dev->name, status);
 	}
 
 	while ((status = inw(ioaddr + EL3_STATUS)) &
@@ -925,7 +914,7 @@
 
 		if (status & TxAvailable) {
 			if (el3_debug > 5)
-				printk("	TX room bit was handled.\n");
+				printk(KERN_DEBUG "	TX room bit was handled.\n");
 			/* There's room in the FIFO for a full-sized packet. */
 			outw(AckIntr | TxAvailable, ioaddr + EL3_CMD);
 			netif_wake_queue (dev);
@@ -964,7 +953,7 @@
 		}
 
 		if (--i < 0) {
-			printk("%s: Infinite loop in interrupt, status %4.4x.\n",
+			printk(KERN_ERR "%s: Infinite loop in interrupt, status %4.4x.\n",
 				   dev->name, status);
 			/* Clear all interrupts. */
 			outw(AckIntr | 0xFF, ioaddr + EL3_CMD);
@@ -975,7 +964,7 @@
 	}
 
 	if (el3_debug > 4) {
-		printk("%s: exiting interrupt, status %4.4x.\n", dev->name,
+		printk(KERN_DEBUG "%s: exiting interrupt, status %4.4x.\n", dev->name,
 			   inw(ioaddr + EL3_STATUS));
 	}
 	spin_unlock(&lp->lock);
@@ -1450,7 +1439,7 @@
 }
 
 /* Power Management support functions */
-#ifdef EL3_SUSPEND
+#ifdef CONFIG_PM
 
 static int
 el3_suspend(struct device *pdev, pm_message_t state)
@@ -1500,79 +1489,102 @@
 	return 0;
 }
 
-#endif /* EL3_SUSPEND */
-
-/* Parameters that may be passed into the module. */
-static int debug = -1;
-static int irq[] = {-1, -1, -1, -1, -1, -1, -1, -1};
-static int xcvr[] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
+#endif /* CONFIG_PM */
 
 module_param(debug,int, 0);
 module_param_array(irq, int, NULL, 0);
-module_param_array(xcvr, int, NULL, 0);
 module_param(max_interrupt_work, int, 0);
 MODULE_PARM_DESC(debug, "debug level (0-6)");
 MODULE_PARM_DESC(irq, "IRQ number(s) (assigned)");
-MODULE_PARM_DESC(xcvr,"transceiver(s) (0=internal, 1=external)");
 MODULE_PARM_DESC(max_interrupt_work, "maximum events handled per interrupt");
-#if defined(__ISAPNP__)
+#ifdef CONFIG_PNP
 module_param(nopnp, int, 0);
 MODULE_PARM_DESC(nopnp, "disable ISA PnP support (0-1)");
-MODULE_DEVICE_TABLE(isapnp, el3_isapnp_adapters);
-#endif	/* __ISAPNP__ */
-MODULE_DESCRIPTION("3Com Etherlink III (3c509, 3c509B) ISA/PnP ethernet driver");
+#endif	/* CONFIG_PNP */
+MODULE_DESCRIPTION("3Com Etherlink III (3c509, 3c509B, 3c529, 3c579) ethernet driver");
 MODULE_LICENSE("GPL");
 
 static int __init el3_init_module(void)
 {
 	int ret = 0;
-	el3_cards = 0;
 
 	if (debug >= 0)
 		el3_debug = debug;
 
-	el3_root_dev = NULL;
-	while (el3_probe(el3_cards) == 0) {
-		if (irq[el3_cards] > 1)
-			el3_root_dev->irq = irq[el3_cards];
-		if (xcvr[el3_cards] >= 0)
-			el3_root_dev->if_port = xcvr[el3_cards];
-		el3_cards++;
+#ifdef CONFIG_PNP
+	if (!nopnp) {
+		ret = pnp_register_driver(&el3_pnp_driver);
+		if (!ret)
+			pnp_registered = 1;
+	}
+#endif
+	/* Select an open I/O location at 0x1*0 to do ISA contention select. */
+	/* Start with 0x110 to avoid some sound cards.*/
+	for (id_port = 0x110 ; id_port < 0x200; id_port += 0x10) {
+		if (!request_region(id_port, 1, "3c509-control"))
+			continue;
+		outb(0x00, id_port);
+		outb(0xff, id_port);
+		if (inb(id_port) & 0x01)
+			break;
+		else
+			release_region(id_port, 1);
+	}
+	if (id_port >= 0x200) {
+		id_port = 0;
+		printk(KERN_ERR "No I/O port available for 3c509 activation.\n");
+	} else {
+		ret = isa_register_driver(&el3_isa_driver, EL3_MAX_CARDS);
+		if (!ret)
+			isa_registered = 1;
 	}
-
 #ifdef CONFIG_EISA
 	ret = eisa_driver_register(&el3_eisa_driver);
+	if (!ret)
+		eisa_registered = 1;
 #endif
 #ifdef CONFIG_MCA
-	{
-		int err = mca_register_driver(&el3_mca_driver);
-		if (ret == 0)
-			ret = err;
-	}
+	ret = mca_register_driver(&el3_mca_driver);
+	if (!ret)
+		mca_registered = 1;
+#endif
+
+#ifdef CONFIG_PNP
+	if (pnp_registered)
+		ret = 0;
+#endif
+	if (isa_registered)
+		ret = 0;
+#ifdef CONFIG_EISA
+	if (eisa_registered)
+		ret = 0;
+#endif
+#ifdef CONFIG_MCA
+	if (mca_registered)
+		ret = 0;
 #endif
 	return ret;
 }
 
 static void __exit el3_cleanup_module(void)
 {
-	struct net_device *next_dev;
-
-	while (el3_root_dev) {
-		struct el3_private *lp = netdev_priv(el3_root_dev);
-
-		next_dev = lp->next_dev;
-		el3_common_remove (el3_root_dev);
-		el3_root_dev = next_dev;
-	}
-
+#ifdef CONFIG_PNP
+	if (pnp_registered)
+		pnp_unregister_driver(&el3_pnp_driver);
+#endif
+	if (isa_registered)
+		isa_unregister_driver(&el3_isa_driver);
+	if (id_port)
+		release_region(id_port, 1);
 #ifdef CONFIG_EISA
-	eisa_driver_unregister (&el3_eisa_driver);
+	if (eisa_registered)
+		eisa_driver_unregister(&el3_eisa_driver);
 #endif
 #ifdef CONFIG_MCA
-	mca_unregister_driver(&el3_mca_driver);
+	if (mca_registered)
+		mca_unregister_driver(&el3_mca_driver);
 #endif
 }
 
 module_init (el3_init_module);
 module_exit (el3_cleanup_module);
-


-- 
Ondrej Zary

^ permalink raw reply

* [2.6 patch] unexport __inet_hash_connect
From: Adrian Bunk @ 2008-02-13 21:29 UTC (permalink / raw)
  To: Pavel Emelyanov, David S. Miller; +Cc: linux-kernel, netdev

This patch removes the unused EXPORT_SYMBOL_GPL(__inet_hash_connect).

Signed-off-by: Adrian Bunk <bunk@kernel.org>

---
ffa30930d4ba630514fd93ded245456f05358140 diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c
index 9cac6c0..e6a0072 100644
--- a/net/ipv4/inet_hashtables.c
+++ b/net/ipv4/inet_hashtables.c
@@ -494,7 +494,6 @@ out:
 		return ret;
 	}
 }
-EXPORT_SYMBOL_GPL(__inet_hash_connect);
 
 /*
  * Bind a port for a connect operation and hash it.


^ permalink raw reply related

* [2.6 patch] unexport inet_listen_wlock
From: Adrian Bunk @ 2008-02-13 21:29 UTC (permalink / raw)
  To: netdev

This patch removes the no linger used EXPORT_SYMBOL(inet_listen_wlock).

Signed-off-by: Adrian Bunk <bunk@kernel.org>

---
08c580a0a3219ce72f5c534c8868e75c4c224e01 diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c
index e6a0072..1aba606 100644
--- a/net/ipv4/inet_hashtables.c
+++ b/net/ipv4/inet_hashtables.c
@@ -120,8 +120,6 @@ void inet_listen_wlock(struct inet_hashinfo *hashinfo)
 	}
 }
 
-EXPORT_SYMBOL(inet_listen_wlock);
-
 /*
  * Don't inline this cruft. Here are some nice properties to exploit here. The
  * BSD API does not allow a listening sock to specify the remote port nor the


^ permalink raw reply related

* [2.6 patch] make s2io.c:init_tti() static
From: Adrian Bunk @ 2008-02-13 21:30 UTC (permalink / raw)
  To: Surjit Reang, Sreenivasa Honnur, Ramkrishna Vepa,
	santosh.rastapur, sivakumar.subrama
  Cc: netdev, linux-kernel

This patch makes the needlessly global init_tti() static.

Signed-off-by: Adrian Bunk <bunk@kernel.org>

---

This patch has been sent on:
- 30 Jan 2008

1e8c2b07be955b181814e4c24366517a66557908 
diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c
index 5fab7d7..bc94e84 100644
--- a/drivers/net/s2io.c
+++ b/drivers/net/s2io.c
@@ -1088,7 +1088,7 @@ static int s2io_print_pci_mode(struct s2io_nic *nic)
  *  '-1' on failure
  */
 
-int init_tti(struct s2io_nic *nic, int link)
+static int init_tti(struct s2io_nic *nic, int link)
 {
 	struct XENA_dev_config __iomem *bar0 = nic->bar0;
 	register u64 val64 = 0;


^ permalink raw reply related

* RE: [2.6 patch] make s2io.c:init_tti() static
From: Ramkrishna Vepa @ 2008-02-13 21:45 UTC (permalink / raw)
  To: Jeff Garzik
  Cc: netdev, linux-kernel, Adrian Bunk, Surjit Reang,
	Sreenivasa Honnur, Ramkrishna Vepa, Rastapur Santosh,
	Sivakumar Subramani
In-Reply-To: <20080213213050.GN3383@cs181133002.pp.htv.fi>

Please apply. Looks good.

Ram

> -----Original Message-----
> From: Adrian Bunk [mailto:bunk@kernel.org]
> Sent: Wednesday, February 13, 2008 1:31 PM
> To: Surjit Reang; Sreenivasa Honnur; Ramkrishna Vepa; Rastapur
Santosh;
> Sivakumar Subramani
> Cc: netdev@vger.kernel.org; linux-kernel@vger.kernel.org
> Subject: [2.6 patch] make s2io.c:init_tti() static
> 
> This patch makes the needlessly global init_tti() static.
> 
> Signed-off-by: Adrian Bunk <bunk@kernel.org>
> 
> ---
> 
> This patch has been sent on:
> - 30 Jan 2008
> 
> 1e8c2b07be955b181814e4c24366517a66557908
> diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c
> index 5fab7d7..bc94e84 100644
> --- a/drivers/net/s2io.c
> +++ b/drivers/net/s2io.c
> @@ -1088,7 +1088,7 @@ static int s2io_print_pci_mode(struct s2io_nic
*nic)
>   *  '-1' on failure
>   */
> 
> -int init_tti(struct s2io_nic *nic, int link)
> +static int init_tti(struct s2io_nic *nic, int link)
>  {
>  	struct XENA_dev_config __iomem *bar0 = nic->bar0;
>  	register u64 val64 = 0;


^ permalink raw reply

* [PATCH 1/2] remove rcu_assign_pointer(NULL) penalty with type/macro safety
From: Paul E. McKenney @ 2008-02-13 22:00 UTC (permalink / raw)
  To: linux-kernel; +Cc: shemminger, davem, netdev, dipankar, ego, herbert, akpm

Hello!

This is an updated version of the patch posted last November:

	http://archives.free.net.ph/message/20071201.003721.cd6ff17c.en.html

This new version permits arguments with side effects, for example:

	rcu_assign_pointer(global_p, p++);

and also verifies that the arguments are pointers, while still avoiding
the unnecessary memory barrier when assigning NULL to a pointer.
This memory-barrier avoidance means that rcu_assign_pointer() is now only
permitted for pointers (not array indexes), and so this version emits a
compiler warning if the first argument is not a pointer.  I built a "make
allyesconfig" version on an x86 system, and received no such warnings.
If RCU is ever applied to array indexes, then the second patch in this
series should be applied, and the resulting rcu_assign_index() be used.

Given the rather surprising history of subtlely broken implementations of
rcu_assign_pointer(), I took the precaution of generating a full set of
test cases and verified that memory barriers and compiler warnings were
emitted when required.  I guess it is the simple things that get you...

Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
---

 rcupdate.h |   16 ++++++++++++----
 1 file changed, 12 insertions(+), 4 deletions(-)

diff -urpNa -X dontdiff linux-2.6.24/include/linux/rcupdate.h linux-2.6.24-rap/include/linux/rcupdate.h
--- linux-2.6.24/include/linux/rcupdate.h	2008-01-24 14:58:37.000000000 -0800
+++ linux-2.6.24-rap/include/linux/rcupdate.h	2008-02-13 13:36:47.000000000 -0800
@@ -270,12 +270,20 @@ extern struct lockdep_map rcu_lock_map;
  * structure after the pointer assignment.  More importantly, this
  * call documents which pointers will be dereferenced by RCU read-side
  * code.
+ *
+ * Throws a compiler warning for non-pointer arguments.
+ *
+ * Does not insert a memory barrier for a NULL pointer.
  */
 
-#define rcu_assign_pointer(p, v)	({ \
-						smp_wmb(); \
-						(p) = (v); \
-					})
+#define rcu_assign_pointer(p, v)	\
+	({ \
+		typeof(*p) *_________p1 = (v); \
+		\
+		if (!__builtin_constant_p(v) || (_________p1 != NULL)) \
+			smp_wmb(); \
+		(p) = _________p1; \
+	})
 
 /**
  * synchronize_sched - block until all CPUs have exited any non-preemptive

^ permalink raw reply

* [PATCH 2/2] add rcu_assign_index() if ever needed
From: Paul E. McKenney @ 2008-02-13 22:05 UTC (permalink / raw)
  To: linux-kernel; +Cc: shemminger, davem, netdev, dipankar, ego, herbert, akpm
In-Reply-To: <20080213220024.GA30729@linux.vnet.ibm.com>

Hello again!

This is a speculative patch that as far as I can tell is not yet required.
If anyone applies RCU to a data structure allocated out of an array, using
array indexes in place of pointers to link the array elements together,
then the rcu_assign_index() function in this patch will be needed to
assign a given element's array index to the RCU-traversed index.  The
implementation is exactly that of the old rcu_assign_pointer(), so is
extremely well tested.

The existing rcu_assign_pointer() will emit a compiler warning in cases
where rcu_assign_index() is required.

Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
---

 rcupdate.h |   18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff -urpNa -X dontdiff linux-2.6.24-rap/include/linux/rcupdate.h linux-2.6.24-rai/include/linux/rcupdate.h
--- linux-2.6.24-rap/include/linux/rcupdate.h	2008-02-13 13:36:47.000000000 -0800
+++ linux-2.6.24-rai/include/linux/rcupdate.h	2008-02-13 10:55:40.000000000 -0800
@@ -286,6 +286,24 @@ extern struct lockdep_map rcu_lock_map;
 	})
 
 /**
+ * rcu_assign_index - assign (publicize) a index of a newly
+ * initialized array elementg that will be dereferenced by RCU
+ * read-side critical sections.  Returns the value assigned.
+ *
+ * Inserts memory barriers on architectures that require them
+ * (pretty much all of them other than x86), and also prevents
+ * the compiler from reordering the code that initializes the
+ * structure after the index assignment.  More importantly, this
+ * call documents which indexes will be dereferenced by RCU read-side
+ * code.
+ */
+
+#define rcu_assign_index(p, v)	({ \
+					smp_wmb(); \
+					(p) = (v); \
+				})
+
+/**
  * synchronize_sched - block until all CPUs have exited any non-preemptive
  * kernel code sequences.
  *

^ permalink raw reply

* Re: [PATCH 1/2] remove rcu_assign_pointer(NULL) penalty with type/macro safety
From: Andrew Morton @ 2008-02-13 22:11 UTC (permalink / raw)
  To: paulmck; +Cc: linux-kernel, shemminger, davem, netdev, dipankar, ego, herbert
In-Reply-To: <20080213220024.GA30729@linux.vnet.ibm.com>

On Wed, 13 Feb 2008 14:00:24 -0800
"Paul E. McKenney" <paulmck@linux.vnet.ibm.com> wrote:

> Hello!
> 
> This is an updated version of the patch posted last November:
> 
> 	http://archives.free.net.ph/message/20071201.003721.cd6ff17c.en.html
> 
> This new version permits arguments with side effects, for example:
> 
> 	rcu_assign_pointer(global_p, p++);
> 
> and also verifies that the arguments are pointers, while still avoiding
> the unnecessary memory barrier when assigning NULL to a pointer.
> This memory-barrier avoidance means that rcu_assign_pointer() is now only
> permitted for pointers (not array indexes), and so this version emits a
> compiler warning if the first argument is not a pointer.  I built a "make
> allyesconfig" version on an x86 system, and received no such warnings.
> If RCU is ever applied to array indexes, then the second patch in this
> series should be applied, and the resulting rcu_assign_index() be used.
> 
> Given the rather surprising history of subtlely broken implementations of
> rcu_assign_pointer(), I took the precaution of generating a full set of
> test cases and verified that memory barriers and compiler warnings were
> emitted when required.  I guess it is the simple things that get you...
> 
> Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
> ---
> 
>  rcupdate.h |   16 ++++++++++++----
>  1 file changed, 12 insertions(+), 4 deletions(-)
> 
> diff -urpNa -X dontdiff linux-2.6.24/include/linux/rcupdate.h linux-2.6.24-rap/include/linux/rcupdate.h
> --- linux-2.6.24/include/linux/rcupdate.h	2008-01-24 14:58:37.000000000 -0800
> +++ linux-2.6.24-rap/include/linux/rcupdate.h	2008-02-13 13:36:47.000000000 -0800

whoop, ancient kernel alert.

> @@ -270,12 +270,20 @@ extern struct lockdep_map rcu_lock_map;
>   * structure after the pointer assignment.  More importantly, this
>   * call documents which pointers will be dereferenced by RCU read-side
>   * code.
> + *
> + * Throws a compiler warning for non-pointer arguments.
> + *
> + * Does not insert a memory barrier for a NULL pointer.
>   */
>  
> -#define rcu_assign_pointer(p, v)	({ \
> -						smp_wmb(); \
> -						(p) = (v); \
> -					})
> +#define rcu_assign_pointer(p, v)	\
> +	({ \
> +		typeof(*p) *_________p1 = (v); \
> +		\
> +		if (!__builtin_constant_p(v) || (_________p1 != NULL)) \
> +			smp_wmb(); \
> +		(p) = _________p1; \
> +	})

Someone already merged the dont-do-it-for-NULL patch so I reworked this
appropriately.  Was too lazy to update the changelog though.


^ permalink raw reply

* Re: BUG: 2.6.25-rc1: iptables postrouting setup causes oops
From: Ben Nizette @ 2008-02-13 22:41 UTC (permalink / raw)
  To: Andrew Morton; +Cc: netfilter-devel, linux-kernel, netdev, Haavard Skinnemoen
In-Reply-To: <20080213004829.fd8afdc7.akpm@linux-foundation.org>


On Wed, 2008-02-13 at 00:48 -0800, Andrew Morton wrote:
> On Tue, 12 Feb 2008 22:46:01 +1100 Ben Nizette <bn@niasdigital.com> wrote:

> > Perfectly repeatable.
> 
> If my theory is correct, changing pretty much anything in the kernel config
> might just make it go away.  But still, it would be most valuable if you
> could try running a bisection search, as described in
> http://www.kernel.org/doc/local/git-quick.html, thanks.
> 

Hm, not as stable a bug as I'd thought.  I have performed a number of
bisections with different start points and they have not converged on
the same patch twice.  Even bisections with the _same_ start point
didn't always converge on the same patch.

What ever the problem is it isn't immediately apparent in latest git so
I guess we'll just have to keep our eyes peeled.

Thanks,
	--Ben.

^ permalink raw reply

* Re: [PATCH 1/2] remove rcu_assign_pointer(NULL) penalty with type/macro safety
From: Paul E. McKenney @ 2008-02-13 22:41 UTC (permalink / raw)
  To: Stephen Hemminger
  Cc: linux-kernel, shemminger, davem, netdev, dipankar, ego, herbert,
	akpm
In-Reply-To: <20080213143537.1b806790@extreme>

On Wed, Feb 13, 2008 at 02:35:37PM -0800, Stephen Hemminger wrote:
> On Wed, 13 Feb 2008 14:00:24 -0800
> "Paul E. McKenney" <paulmck@linux.vnet.ibm.com> wrote:
> 
> > Hello!
> > 
> > This is an updated version of the patch posted last November:
> > 
> > 	http://archives.free.net.ph/message/20071201.003721.cd6ff17c.en.html
> > 
> > This new version permits arguments with side effects, for example:
> > 
> > 	rcu_assign_pointer(global_p, p++);
> > 
> > and also verifies that the arguments are pointers, while still avoiding
> > the unnecessary memory barrier when assigning NULL to a pointer.
> > This memory-barrier avoidance means that rcu_assign_pointer() is now only
> > permitted for pointers (not array indexes), and so this version emits a
> > compiler warning if the first argument is not a pointer.  I built a "make
> > allyesconfig" version on an x86 system, and received no such warnings.
> > If RCU is ever applied to array indexes, then the second patch in this
> > series should be applied, and the resulting rcu_assign_index() be used.
> > 
> > Given the rather surprising history of subtlely broken implementations of
> > rcu_assign_pointer(), I took the precaution of generating a full set of
> > test cases and verified that memory barriers and compiler warnings were
> > emitted when required.  I guess it is the simple things that get you...
> > 
> > Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
> > ---
> > 
> >  rcupdate.h |   16 ++++++++++++----
> >  1 file changed, 12 insertions(+), 4 deletions(-)
> > 
> > diff -urpNa -X dontdiff linux-2.6.24/include/linux/rcupdate.h linux-2.6.24-rap/include/linux/rcupdate.h
> > --- linux-2.6.24/include/linux/rcupdate.h	2008-01-24 14:58:37.000000000 -0800
> > +++ linux-2.6.24-rap/include/linux/rcupdate.h	2008-02-13 13:36:47.000000000 -0800
> > @@ -270,12 +270,20 @@ extern struct lockdep_map rcu_lock_map;
> >   * structure after the pointer assignment.  More importantly, this
> >   * call documents which pointers will be dereferenced by RCU read-side
> >   * code.
> > + *
> > + * Throws a compiler warning for non-pointer arguments.
> > + *
> > + * Does not insert a memory barrier for a NULL pointer.
> >   */
> >  
> > -#define rcu_assign_pointer(p, v)	({ \
> > -						smp_wmb(); \
> > -						(p) = (v); \
> > -					})
> > +#define rcu_assign_pointer(p, v)	\
> > +	({ \
> > +		typeof(*p) *_________p1 = (v); \
> > +		\
> > +		if (!__builtin_constant_p(v) || (_________p1 != NULL)) \
> > +			smp_wmb(); \
> > +		(p) = _________p1; \
> > +	})
> >  
> >  /**
> >   * synchronize_sched - block until all CPUs have exited any non-preemptive
> 
> Will this still work if p is unsigned long?

Hello, Steve,

If p is unsigned long, then use rcu_assign_index() from the next patch in
the set.  Looks like Andrew has applied it to -mm -- so please make sure
that he is aware if you do use it.

							Thanx, Paul

^ permalink raw reply

* Re: [RFC, PATCH]: Pass link level header from/to PPP interface
From: David Miller @ 2008-02-13 22:53 UTC (permalink / raw)
  To: urs; +Cc: netdev
In-Reply-To: <ygflk5opzhb.fsf@janus.isnogud.escape.de>

From: Urs Thuermann <urs@isnogud.escape.de>
Date: 13 Feb 2008 17:56:00 +0100

> Do you consider this strong enough to justify this change?

Can tcpdump and libpcap already handle PPP properly?

^ permalink raw reply

* Re: [PATCH] fib_trie: rcu_assign_pointer warning fix
From: Paul E. McKenney @ 2008-02-13 22:55 UTC (permalink / raw)
  To: Jarek Poplawski; +Cc: David Miller, shemminger, netdev, linux-kernel
In-Reply-To: <20080212194630.GB2803@ami.dom.local>

On Tue, Feb 12, 2008 at 08:46:30PM +0100, Jarek Poplawski wrote:
> On Tue, Feb 12, 2008 at 08:32:18PM +0100, Jarek Poplawski wrote:
> ...
> > It seems the above version of this macro uses the barrier for 0, but
> > if I miss something, or for these other: documenting reasons,
> 
> ...or __builtin_constants could be used for indexing (?!),

Yep.  For example:

	elem[0].next = 1;
	rcu_assign_index(global_index, 0);

							Thanx, Paul

> > then of
> > course you are right.
> 
> Jarek P.

^ permalink raw reply


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