Netdev List
 help / color / mirror / Atom feed
* Re: [net-2.6 2/2] bnx2x: Update bnx2x version to 1.52.53-4
From: David Miller @ 2010-08-19  6:41 UTC (permalink / raw)
  To: yaniv.home; +Cc: netdev
In-Reply-To: <1281976447.3997.18.camel@lb-tlvb-yanivr.il.broadcom.com>

From: "Yaniv Rosner" <yaniv.home@broadcom.com>
Date: Mon, 16 Aug 2010 19:34:07 +0300

> Update bnx2x version to 1.52.53-4
> 
> Signed-off-by: Yaniv Rosner <yanivr@broadcom.com>
> Signed-off-by: Eilon Greenstein <eilong@broadcom.com>

Applied.

^ permalink raw reply

* Re: [net-2.6 1/2] bnx2x: Fix PHY locking problem
From: David Miller @ 2010-08-19  6:41 UTC (permalink / raw)
  To: yaniv.home; +Cc: netdev
In-Reply-To: <1281976446.3997.17.camel@lb-tlvb-yanivr.il.broadcom.com>

From: "Yaniv Rosner" <yaniv.home@broadcom.com>
Date: Mon, 16 Aug 2010 19:34:06 +0300

> PHY locking is required between two ports for some external PHYs. Since
> initialization was done in the common init function (called only on the 
> first port initialization) rather than in the port init function, there
> was in fact no PHY locking between the ports. 
> 
> Signed-off-by: Yaniv Rosner <yanivr@broadcom.com>
> Signed-off-by: Eilon Greenstein <eilong@broadcom.com> 

Applied.

^ permalink raw reply

* Re: [PATCH] rds: fix a leak of kernel memory
From: David Miller @ 2010-08-19  6:40 UTC (permalink / raw)
  To: eric.dumazet; +Cc: andy.grover, netdev
In-Reply-To: <1281965100.2524.52.camel@edumazet-laptop>

From: Eric Dumazet <eric.dumazet@gmail.com>
Date: Mon, 16 Aug 2010 15:25:00 +0200

> struct rds_rdma_notify contains a 32 bits hole on 64bit arches,
> make sure it is zeroed before copying it to user.
> 
> Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>

Applied, thanks a lot Eric.

^ permalink raw reply

* Re: [PATCH] netlink: fix compat recvmsg
From: David Miller @ 2010-08-19  6:36 UTC (permalink / raw)
  To: eric.dumazet; +Cc: johannes, netdev, kalle.valo
In-Reply-To: <1281963025.2524.43.camel@edumazet-laptop>

From: Eric Dumazet <eric.dumazet@gmail.com>
Date: Mon, 16 Aug 2010 14:50:25 +0200

> Le lundi 16 août 2010 à 09:20 +0200, Johannes Berg a écrit :
>> From: Johannes Berg <johannes.berg@intel.com>
>> 
>> Since
>> commit 1dacc76d0014a034b8aca14237c127d7c19d7726
>> Author: Johannes Berg <johannes@sipsolutions.net>
>> Date:   Wed Jul 1 11:26:02 2009 +0000
>> 
>>     net/compat/wext: send different messages to compat tasks
>> 
>> we had a race condition when setting and then
>> restoring frag_list. Eric attempted to fix it,
>> but the fix created even worse problems.
 ...
>> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
 ...
> Acked-by: Eric Dumazet <eric.dumazet@gmail.com>

Applied, thanks guys!

^ permalink raw reply

* Re: [PATCH] tcp: allow effective reduction of TCP's rcv-buffer via setsockopt
From: David Miller @ 2010-08-19  6:33 UTC (permalink / raw)
  To: hagen; +Cc: netdev, kaber, eric.dumazet, ilpo.jarvinen
In-Reply-To: <1281900976-11852-1-git-send-email-hagen@jauu.net>

From: Hagen Paul Pfeifer <hagen@jauu.net>
Date: Sun, 15 Aug 2010 21:36:16 +0200

> +
> +		/* limit the window selection if the user enforce a smaller rx buffer */
> +		if (sk->sk_userlocks & SOCK_RCVBUF_LOCK &&
> +				(req->window_clamp > tcp_full_space(sk) || req->window_clamp == 0))
> +			req->window_clamp = tcp_full_space(sk);
> +

Logically the patch looks fine, but please fix the indentation of the
second line of the two new if() statements in this patch, the
second line's first character should line up with the character
right after the openning "(" on the previous line.

Thanks.

^ permalink raw reply

* Re: dccp test-tree [PATCH 0/3] ccid-2: Congestion Window Validation, TCP code sharing
From: David Miller @ 2010-08-19  6:28 UTC (permalink / raw)
  To: gerrit; +Cc: dccp, netdev
In-Reply-To: <20100818.232532.98880936.davem@davemloft.net>

From: David Miller <davem@davemloft.net>
Date: Wed, 18 Aug 2010 23:25:32 -0700 (PDT)

> I'll add them to net-next-2.6, thanks a lot!

Ok, these obviously have dependencies with things in your dccp
trees that are not upstream yet, my bad :-)

Please submit that stuff whenever you find it convenient.

^ permalink raw reply

* Re: dccp test-tree [PATCH 0/3] ccid-2: Congestion Window Validation, TCP code sharing
From: David Miller @ 2010-08-19  6:25 UTC (permalink / raw)
  To: gerrit; +Cc: dccp, netdev
In-Reply-To: <1281676901-7018-1-git-send-email-gerrit@erg.abdn.ac.uk>

From: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date: Fri, 13 Aug 2010 07:21:38 +0200

> This is a small set to enhance CCID-2, consisting mainly of Congestion Window
> Validation (RFC 2681) ported over from TCP.
> 
> The first patch allows to make the TCP minimum RTO visible also to CCID-2. Since
> CCID-3 also uses RTO (in the formula and for the nofeedback timer), I wonder
> whether we should also do the same for CCID-3??
> 
> The changeset is:
> 
>   Patch #1: makes TCP's minimum-RTO code available to CCID-2
>   Patch #2: simplifies the code by using an existing function
>   Patch #3: implements CWV for CCID-2 -- largely taken from TCP
> 
> The patches have been dusted off from my development tree. They have been tested,
> though it is some time ago. Hence I'd very much appreciate review and comments.

I think these changes are wonderful.

I'll add them to net-next-2.6, thanks a lot!

^ permalink raw reply

* Re: [PATCH v6] PPTP: PPP over IPv4 (Point-to-Point Tunneling Protocol)
From: Eric Dumazet @ 2010-08-19  6:18 UTC (permalink / raw)
  To: Dmitry Kozlov; +Cc: netdev
In-Reply-To: <E1OlwR9-0004FI-00.xeb-mail-ru@f275.mail.ru>

Le jeudi 19 août 2010 à 08:09 +0400, Dmitry Kozlov a écrit :
> This patch contains:
> 1. pptp driver
> 2. gre demultiplexer driver for demultiplexing gre packets with different gre version
>    so ip_gre and pptp may coexists
> 3. ip_gre modification
> 4. other stuff
> 

Almost done ;)

>  
> +GRE DEMULTIPLEXER DRIVER
> +M:	Dmitry Kozlov <xeb@xxxxxxx>
> +L:	netdev@xxxxxxxxxxxxxxx
> +S:	Maintained
> +F:	net/ipv4/gre.c
> +F:	include/net/gre.h
> +
> +PPTP DRIVER
> +M:	Dmitry Kozlov <xeb@xxxxxxx>
> +L:	netdev@xxxxxxxxxxxxxxx
> +S:	Maintained
> +F:	drivers/net/pptp.c
> +W:	http://sourceforge.net/projects/accel-pptp
> +


Please fill correct addresses, not xxxxxx

> +
> +static int __init pptp_init_module(void)
> +{
> +	int err = 0;
> +	pr_info("PPTP driver version " PPTP_DRIVER_VERSION "\n");
> +
> +	if (gre_add_protocol(&gre_pptp_protocol, GREPROTO_PPTP) < 0) {
> +		pr_err("PPTP: can't add protocol\n");
> +		goto out;
> +	}
> +
> +	err = proto_register(&pptp_sk_proto, 0);
> +	if (err) {
> +		pr_err("PPTP: can't register sk_proto\n");
> +		goto out_inet_del_protocol;
> +	}
> +
> +	err = register_pppox_proto(PX_PROTO_PPTP, &pppox_pptp_proto);
> +	if (err) {
> +		pr_err("PPTP: can't register pppox_proto\n");
> +		goto out_unregister_sk_proto;
> +	}
> +
+ callid_sock = (struct pppox_sock **)__vmalloc((MAX_CALLID + 1) * sizeof(void *), GFP_KERNEL | __GFP_ZERO, PAGE_KERNEL);

No need for the cast

Please split this to :

	callid_sock = __vmalloc((MAX_CALLID + 1) * sizeof(void *),
				GFP_KERNEL | __GFP_ZERO, PAGE_KERNEL);


> +	if (!callid_sock) {
> +		pr_err("PPTP: cann't allocate memory\n");
> +		goto out_unregister_pppox_proto;
> +	}
> +
> +out:
> +	return err;
> +out_unregister_pppox_proto:
> +	unregister_pppox_proto(PX_PROTO_PPTP);
> +out_unregister_sk_proto:
> +	proto_unregister(&pptp_sk_proto);
> +out_inet_del_protocol:
> +	gre_del_protocol(&gre_pptp_protocol, GREPROTO_PPTP);
> +	return err;
> +}


You should attempt the vmalloc() at the start of this function (before
proto_register() and register_pppox_proto()), or
maybe another cpu can enter your code and try to dereference null
pointer. Dont forget to vfree() in case of error unwinding.

Thanks



^ permalink raw reply

* [PATCH v4] ether3: Use net_device_stats from struct net_device
From: Tobias Klauser @ 2010-08-19  6:15 UTC (permalink / raw)
  To: David S. Miller, Russell King, netdev
  Cc: linux-arm-kernel, kernel-janitors, Stephen Hemminger,
	Eric Dumazet, Dan Carpenter
In-Reply-To: <1282061733-19700-1-git-send-email-tklauser@distanz.ch>

struct net_device has its own struct net_device_stats member, so use
this one instead of a private copy in the ether1_priv struct. As the new
ndo_get_stats function would just return dev->stats we can omit it. This
patch also removes an incorrect memset of the stats on open.

Signed-off-by: Tobias Klauser <tklauser@distanz.ch>
---
 drivers/net/arm/ether3.c |   33 ++++++++++-----------------------
 drivers/net/arm/ether3.h |    1 -
 2 files changed, 10 insertions(+), 24 deletions(-)

diff --git a/drivers/net/arm/ether3.c b/drivers/net/arm/ether3.c
index 1361b73..44a8746 100644
--- a/drivers/net/arm/ether3.c
+++ b/drivers/net/arm/ether3.c
@@ -81,7 +81,6 @@ static int	ether3_open (struct net_device *dev);
 static int	ether3_sendpacket (struct sk_buff *skb, struct net_device *dev);
 static irqreturn_t ether3_interrupt (int irq, void *dev_id);
 static int	ether3_close (struct net_device *dev);
-static struct net_device_stats *ether3_getstats (struct net_device *dev);
 static void	ether3_setmulticastlist (struct net_device *dev);
 static void	ether3_timeout(struct net_device *dev);
 
@@ -323,8 +322,6 @@ ether3_init_for_open(struct net_device *dev)
 {
 	int i;
 
-	memset(&priv(dev)->stats, 0, sizeof(struct net_device_stats));
-
 	/* Reset the chip */
 	ether3_outw(CFG2_RESET, REG_CONFIG2);
 	udelay(4);
@@ -442,15 +439,6 @@ ether3_close(struct net_device *dev)
 }
 
 /*
- * Get the current statistics.	This may be called with the card open or
- * closed.
- */
-static struct net_device_stats *ether3_getstats(struct net_device *dev)
-{
-	return &priv(dev)->stats;
-}
-
-/*
  * Set or clear promiscuous/multicast mode filter for this adaptor.
  *
  * We don't attempt any packet filtering.  The card may have a SEEQ 8004
@@ -490,7 +478,7 @@ static void ether3_timeout(struct net_device *dev)
 	local_irq_restore(flags);
 
 	priv(dev)->regs.config2 |= CFG2_CTRLO;
-	priv(dev)->stats.tx_errors += 1;
+	dev->stats.tx_errors += 1;
 	ether3_outw(priv(dev)->regs.config2, REG_CONFIG2);
 	priv(dev)->tx_head = priv(dev)->tx_tail = 0;
 
@@ -509,7 +497,7 @@ ether3_sendpacket(struct sk_buff *skb, struct net_device *dev)
 
 	if (priv(dev)->broken) {
 		dev_kfree_skb(skb);
-		priv(dev)->stats.tx_dropped ++;
+		dev->stats.tx_dropped++;
 		netif_start_queue(dev);
 		return NETDEV_TX_OK;
 	}
@@ -673,7 +661,7 @@ if (next_ptr < RX_START || next_ptr >= RX_END) {
 			} else
 				goto dropping;
 		} else {
-			struct net_device_stats *stats = &priv(dev)->stats;
+			struct net_device_stats *stats = &dev->stats;
 			ether3_outw(next_ptr >> 8, REG_RECVEND);
 			if (status & RXSTAT_OVERSIZE)	  stats->rx_over_errors ++;
 			if (status & RXSTAT_CRCERROR)	  stats->rx_crc_errors ++;
@@ -685,14 +673,14 @@ if (next_ptr < RX_START || next_ptr >= RX_END) {
 	while (-- maxcnt);
 
 done:
-	priv(dev)->stats.rx_packets += received;
+	dev->stats.rx_packets += received;
 	priv(dev)->rx_head = next_ptr;
 	/*
 	 * If rx went off line, then that means that the buffer may be full.  We
 	 * have dropped at least one packet.
 	 */
 	if (!(ether3_inw(REG_STATUS) & STAT_RXON)) {
-		priv(dev)->stats.rx_dropped ++;
+		dev->stats.rx_dropped++;
     		ether3_outw(next_ptr, REG_RECVPTR);
 		ether3_outw(priv(dev)->regs.command | CMD_RXON, REG_COMMAND);
 	}
@@ -710,7 +698,7 @@ dropping:{
 		last_warned = jiffies;
 		printk("%s: memory squeeze, dropping packet.\n", dev->name);
 	}
-	priv(dev)->stats.rx_dropped ++;
+	dev->stats.rx_dropped++;
 	goto done;
 	}
 }
@@ -743,13 +731,13 @@ static void ether3_tx(struct net_device *dev)
 		 * Update errors
 		 */
 		if (!(status & (TXSTAT_BABBLED | TXSTAT_16COLLISIONS)))
-			priv(dev)->stats.tx_packets++;
+			dev->stats.tx_packets++;
 		else {
-			priv(dev)->stats.tx_errors ++;
+			dev->stats.tx_errors++;
 			if (status & TXSTAT_16COLLISIONS)
-				priv(dev)->stats.collisions += 16;
+				dev->stats.collisions += 16;
 			if (status & TXSTAT_BABBLED)
-				priv(dev)->stats.tx_fifo_errors ++;
+				dev->stats.tx_fifo_errors++;
 		}
 
 		tx_tail = (tx_tail + 1) & 15;
@@ -773,7 +761,6 @@ static const struct net_device_ops ether3_netdev_ops = {
 	.ndo_open		= ether3_open,
 	.ndo_stop		= ether3_close,
 	.ndo_start_xmit		= ether3_sendpacket,
-	.ndo_get_stats		= ether3_getstats,
 	.ndo_set_multicast_list	= ether3_setmulticastlist,
 	.ndo_tx_timeout		= ether3_timeout,
 	.ndo_validate_addr	= eth_validate_addr,
diff --git a/drivers/net/arm/ether3.h b/drivers/net/arm/ether3.h
index 1921a3a..2db63b0 100644
--- a/drivers/net/arm/ether3.h
+++ b/drivers/net/arm/ether3.h
@@ -164,7 +164,6 @@ struct dev_priv {
     unsigned char tx_head;		/* buffer nr to insert next packet	 */
     unsigned char tx_tail;		/* buffer nr of transmitting packet	 */
     unsigned int rx_head;		/* address to fetch next packet from	 */
-    struct net_device_stats stats;
     struct timer_list timer;
     int broken;				/* 0 = ok, 1 = something went wrong	 */
 };
-- 
1.7.0.4


^ permalink raw reply related

* [PATCH v4] ether1: Use net_device_stats from struct net_device
From: Tobias Klauser @ 2010-08-19  6:15 UTC (permalink / raw)
  To: David S. Miller, Russell King, netdev
  Cc: linux-arm-kernel, kernel-janitors, Stephen Hemminger,
	Eric Dumazet, Dan Carpenter
In-Reply-To: <1282061719-19645-1-git-send-email-tklauser@distanz.ch>

struct net_device has its own struct net_device_stats member, so use
this one instead of a private copy in the ether1_priv struct. As the new
ndo_get_stats function would just return dev->stats we can omit it. This
patch also removes an incorrect memset of the stats on open.

Signed-off-by: Tobias Klauser <tklauser@distanz.ch>
---
 drivers/net/arm/ether1.c |   34 ++++++++++++----------------------
 drivers/net/arm/ether1.h |    1 -
 2 files changed, 12 insertions(+), 23 deletions(-)

diff --git a/drivers/net/arm/ether1.c b/drivers/net/arm/ether1.c
index b17ab51..b00781c 100644
--- a/drivers/net/arm/ether1.c
+++ b/drivers/net/arm/ether1.c
@@ -68,7 +68,6 @@ static int ether1_open(struct net_device *dev);
 static int ether1_sendpacket(struct sk_buff *skb, struct net_device *dev);
 static irqreturn_t ether1_interrupt(int irq, void *dev_id);
 static int ether1_close(struct net_device *dev);
-static struct net_device_stats *ether1_getstats(struct net_device *dev);
 static void ether1_setmulticastlist(struct net_device *dev);
 static void ether1_timeout(struct net_device *dev);
 
@@ -649,8 +648,6 @@ ether1_open (struct net_device *dev)
 	if (request_irq(dev->irq, ether1_interrupt, 0, "ether1", dev))
 		return -EAGAIN;
 
-	memset (&priv(dev)->stats, 0, sizeof (struct net_device_stats));
-
 	if (ether1_init_for_open (dev)) {
 		free_irq (dev->irq, dev);
 		return -EAGAIN;
@@ -673,7 +670,7 @@ ether1_timeout(struct net_device *dev)
 	if (ether1_init_for_open (dev))
 		printk (KERN_ERR "%s: unable to restart interface\n", dev->name);
 
-	priv(dev)->stats.tx_errors++;
+	dev->stats.tx_errors++;
 	netif_wake_queue(dev);
 }
 
@@ -802,21 +799,21 @@ again:
 
 	while (nop.nop_status & STAT_COMPLETE) {
 		if (nop.nop_status & STAT_OK) {
-			priv(dev)->stats.tx_packets ++;
-			priv(dev)->stats.collisions += (nop.nop_status & STAT_COLLISIONS);
+			dev->stats.tx_packets++;
+			dev->stats.collisions += (nop.nop_status & STAT_COLLISIONS);
 		} else {
-			priv(dev)->stats.tx_errors ++;
+			dev->stats.tx_errors++;
 
 			if (nop.nop_status & STAT_COLLAFTERTX)
-				priv(dev)->stats.collisions ++;
+				dev->stats.collisions++;
 			if (nop.nop_status & STAT_NOCARRIER)
-				priv(dev)->stats.tx_carrier_errors ++;
+				dev->stats.tx_carrier_errors++;
 			if (nop.nop_status & STAT_TXLOSTCTS)
 				printk (KERN_WARNING "%s: cts lost\n", dev->name);
 			if (nop.nop_status & STAT_TXSLOWDMA)
-				priv(dev)->stats.tx_fifo_errors ++;
+				dev->stats.tx_fifo_errors++;
 			if (nop.nop_status & STAT_COLLEXCESSIVE)
-				priv(dev)->stats.collisions += 16;
+				dev->stats.collisions += 16;
 		}
 
 		if (nop.nop_link == caddr) {
@@ -879,13 +876,13 @@ ether1_recv_done (struct net_device *dev)
 
 				skb->protocol = eth_type_trans (skb, dev);
 				netif_rx (skb);
-				priv(dev)->stats.rx_packets ++;
+				dev->stats.rx_packets++;
 			} else
-				priv(dev)->stats.rx_dropped ++;
+				dev->stats.rx_dropped++;
 		} else {
 			printk(KERN_WARNING "%s: %s\n", dev->name,
 				(rbd.rbd_status & RBD_EOF) ? "oversized packet" : "acnt not valid");
-			priv(dev)->stats.rx_dropped ++;
+			dev->stats.rx_dropped++;
 		}
 
 		nexttail = ether1_readw(dev, priv(dev)->rx_tail, rfd_t, rfd_link, NORMALIRQS);
@@ -939,7 +936,7 @@ ether1_interrupt (int irq, void *dev_id)
 				printk (KERN_WARNING "%s: RU went not ready: RU suspended\n", dev->name);
 				ether1_writew(dev, SCB_CMDRXRESUME, SCB_ADDR, scb_t, scb_command, NORMALIRQS);
 				writeb(CTRL_CA, REG_CONTROL);
-				priv(dev)->stats.rx_dropped ++;	/* we suspended due to lack of buffer space */
+				dev->stats.rx_dropped++;	/* we suspended due to lack of buffer space */
 			} else
 				printk(KERN_WARNING "%s: RU went not ready: %04X\n", dev->name,
 					ether1_readw(dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS));
@@ -962,12 +959,6 @@ ether1_close (struct net_device *dev)
 	return 0;
 }
 
-static struct net_device_stats *
-ether1_getstats (struct net_device *dev)
-{
-	return &priv(dev)->stats;
-}
-
 /*
  * Set or clear the multicast filter for this adaptor.
  * num_addrs == -1	Promiscuous mode, receive all packets.
@@ -994,7 +985,6 @@ static const struct net_device_ops ether1_netdev_ops = {
 	.ndo_open		= ether1_open,
 	.ndo_stop		= ether1_close,
 	.ndo_start_xmit		= ether1_sendpacket,
-	.ndo_get_stats		= ether1_getstats,
 	.ndo_set_multicast_list	= ether1_setmulticastlist,
 	.ndo_tx_timeout		= ether1_timeout,
 	.ndo_validate_addr	= eth_validate_addr,
diff --git a/drivers/net/arm/ether1.h b/drivers/net/arm/ether1.h
index c8a4b23..3a5830a 100644
--- a/drivers/net/arm/ether1.h
+++ b/drivers/net/arm/ether1.h
@@ -38,7 +38,6 @@
 
 struct ether1_priv {
 	void __iomem *base;
-	struct net_device_stats stats;
 	unsigned int tx_link;
 	unsigned int tx_head;
 	volatile unsigned int tx_tail;
-- 
1.7.0.4


^ permalink raw reply related

* Re: [PATCH v2] ether1: Use net_device_stats from struct net_device
From: Tobias Klauser @ 2010-08-19  6:14 UTC (permalink / raw)
  To: David Miller
  Cc: shemminger, linux, netdev, linux-arm-kernel, kernel-janitors,
	error27
In-Reply-To: <20100818.131043.226780154.davem@davemloft.net>

On 2010-08-18 at 22:10:43 +0200, David Miller <davem@davemloft.net> wrote:
> From: Stephen Hemminger <shemminger@vyatta.com>
> Date: Wed, 18 Aug 2010 08:33:04 -0700
> 
> > On Wed, 18 Aug 2010 09:04:24 +0200
> > Tobias Klauser <tklauser@distanz.ch> wrote:
> > 
> >>  
> >> -	memset (&priv(dev)->stats, 0, sizeof (struct net_device_stats));
> >> +	memset(&dev->stats, 0, sizeof(struct net_device_stats));
> > 
> > This is incorrect, just remove the memset.  The stats are initialized
> > when device is created.  The Linux device driver convention is to
> > keep stats when device is set down and brought back up; that is what
> > the majority of other drivers do.
> 
> Yep, both the ether1 and ether3 patch have this problem.  Looks
> like we'll see v4 coming some :-)

Thanks a lot. I'll send another updated patch. Hope I get it right this
time :-)

AFAICS there are a few other network drivers having the same problem,
I'll send patches for those too.

^ permalink raw reply

* Re: [PATCH 1/5] ptp: Added a brand new class driver for ptp clocks.
From: Richard Cochran @ 2010-08-19  5:55 UTC (permalink / raw)
  To: john stultz
  Cc: Rodolfo Giometti, netdev-u79uwXL29TY76Z2rM5mHXA,
	devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linuxppc-dev-uLR06cmDAlY/bJ5BZ2RsiQ,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	Krzysztof Halasa
In-Reply-To: <1282176776.2865.100.camel-bi+AKbBUZKY6gyzm1THtWbp2dZbC/Bob@public.gmane.org>

On Wed, Aug 18, 2010 at 05:12:56PM -0700, john stultz wrote:
> On Wed, 2010-08-18 at 09:19 +0200, Richard Cochran wrote:
> > The timer/alarm stuff is "ancillary" and is not at all necessary. It
> > is just a "nice to have." I will happily remove it, if it is too
> > troubling for people.
> 
> If there's a compelling argument for it, I'm interested to hear. But
> again, it seems like just
> yet-another-way-to-get-alarm/timer-functionality, so before we add an
> extra API (or widen an existing API) I'd like to understand the need.

We don't really need it, IMHO.

But if we offer clockid_t CLOCK_PTP, then we get timer_settime()
without any extra effort.

> > I was emulating the posix interface. Instead I should use it directly.
> 
> I'm definitely interested to see what you come up with here. I'm still
> hesitant with adding a PTP clock_id, but extending the posix-clocks
> interface in this way isn't unprecedented (see: CLOCK_SGI_CYCLE) I just
> would like to make sure we don't end up with a clock_id namespace
> littered with oddball clocks that were not well abstracted (see:
> CLOCK_SGI_CYCLE :).
> 
> For instance: imagine if instead of keeping the clocksource abstraction
> internal to the timekeeping core, we exposed each clocksource to
> userland via a clock_id.  Every arch would have different ids, and each
> arch might have multiple ids. Programming against that would be a huge
> pain.

The clockid_t CLOCK_PTP will be arch-neutral.

> So in thinking about this, try to focus on what the new clock_id
> provides that the other existing clockids do not? Are they at comparable
> levels of abstraction? 15 years from now, are folks likely to still be
> using it? Will it be maintainable? etc...

Arnd convinced me that clockid_t=CLOCK_PTP is a good fit. My plan
would be to introduce just one additional syscall:

SYSCALL_DEFINE3(clock_adjtime, const clockid_t, clkid,
		int, ppb, struct timespec __user *, ts)

ppb - desired frequency adjustment in parts per billion
ts  - desired time step (or jump) in <sec,nsec> to correct
      a measured offset

Arguably, this syscall might be useful for other clocks, too.

I think the ancillary features from PTP hardware clocks should be made
available throught the sysfs. A syscall for these would end up very
ugly, looking like an ioctl. Also, it is hard to see how these
features relate to the more general idea of the clockid.

In contrast, sysfs attributes will fit the need nicely:

1. enable or disable pps
2. enable or disable external timestamps
3. read out external timestamp
4. configure period for periodic output

> > 1. Use Case: SW timestamping
> The way I tend to see it: PTP is just one of the many ways to sync
> system time.

> > 2. Use Case: HW timestamping for industrial control
> These specialized applications are part of what concerns me the most. 

PTP was not invented to just to get a computer's system time in the
ball park. For that, NTP is good enough. Rather, some people want to
use their computers for tasks that require close synchronization, like
industrial control, audio/video streaming, and many others.

Are you saying that we should not support such applications?

> For example, I can see some parallels between things like audio
> processing, where you have a buffer consumed by the card at a certain
> rate. Now, the card has its own crystal it uses to time its consumption,
> so it has its own time domain, and could drift from system time. Thus
> you want to trigger buffer-refill interrupts off of the audio card's
> clock, not the system time which might run the risk of being late.
> 
> But again, we don't expose the audio hardware clock to userland in the
> same way we expose system time.

This is a good example of the poverty (in regards to time
synchronization) of our current systems.

Lets say I want to build a surround sound audio system, using a set of
distributed computers, each host connected to one speaker. How I can
be sure that the samples in one channel (ie one host) pass through the
DA converter at exactly the same time?

> Again, my knowledge in the networking stack is pretty limited. But it
> would seem that having an interface that does something to the effect of
> "adjust the timestamp clock on the hardware that generated it from this
> packet by Xppb" would feel like the right level of abstraction. Its
> closely related to SO_TIMESTAMP, option right? Would something like
> using the setsockopt/getsockopt interface with
> SO_TIMESTAMP_ADJUST/OFFSET/SET/etc be reasonable?

The clock and its adjustment have nothing to do with a network
socket. The current PTP hacks floating around all add private ioctls
to the MAC driver. That is the *wrong* way to do it.

> > 3. Use Case: HW timestamping with PPS to host
...
> And yes, this seems perfectly reasonable feature to add. Its not
> controversial to me, because its likely to work within the existing
> interfaces and won't expose anything new to userland.

Okay, then will you support an elegant solution for case 3, that also
supports cases 1 and 2 without any additional work?

> Again, sorry to be such a pain about all of this. I know its frustrating...

Thanks for your comments!

Richard

^ permalink raw reply

* Re: Join request for mailing list
From: Simon Horman @ 2010-08-19  4:13 UTC (permalink / raw)
  To: Raju Dantuluri; +Cc: netdev
In-Reply-To: <305090.32745.qm@web114007.mail.gq1.yahoo.com>

On Wed, Aug 18, 2010 at 04:38:51PM -0700, Raju Dantuluri wrote:
> Hi I'd like to subscribe the mailing list.

As per the footer appended to list emails,
you can find that information at http://vger.kernel.org/majordomo-info.html

> Also appreciate on a link on how to contribute in bug fixes.

A good place to start would be Documentation/SubmittingPatches
in the kernel tree. Or to just monitor the mailing list for a while
and see how things work.


^ permalink raw reply

* [PATCH v6] PPTP: PPP over IPv4 (Point-to-Point Tunneling Protocol)
From: Dmitry Kozlov @ 2010-08-19  4:09 UTC (permalink / raw)
  To: netdev

This patch contains:
1. pptp driver
2. gre demultiplexer driver for demultiplexing gre packets with different gre version
   so ip_gre and pptp may coexists
3. ip_gre modification
4. other stuff

--
 MAINTAINERS              |   14 +
 drivers/net/Kconfig      |   11 +
 drivers/net/Makefile     |    1 +
 drivers/net/pptp.c       |  721 ++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/if_pppox.h |   59 +++--
 include/net/gre.h        |   18 ++
 net/ipv4/Kconfig         |    7 +
 net/ipv4/Makefile        |    1 +
 net/ipv4/gre.c           |  151 ++++++++++
 net/ipv4/ip_gre.c        |   14 +-
 10 files changed, 970 insertions(+), 27 deletions(-)

diff --git a/MAINTAINERS b/MAINTAINERS
index 02f75fc..3eaaf18 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -6450,6 +6450,20 @@ M:	"Maciej W. Rozycki" <macro@linux-mips.org>
 S:	Maintained
 F:	drivers/serial/zs.*
 
+GRE DEMULTIPLEXER DRIVER
+M:	Dmitry Kozlov <xeb@xxxxxxx>
+L:	netdev@xxxxxxxxxxxxxxx
+S:	Maintained
+F:	net/ipv4/gre.c
+F:	include/net/gre.h
+
+PPTP DRIVER
+M:	Dmitry Kozlov <xeb@xxxxxxx>
+L:	netdev@xxxxxxxxxxxxxxx
+S:	Maintained
+F:	drivers/net/pptp.c
+W:	http://sourceforge.net/projects/accel-pptp
+
 THE REST
 M:	Linus Torvalds <torvalds@linux-foundation.org>
 L:	linux-kernel@vger.kernel.org
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index ce2fcdd..2fa0516 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -3167,6 +3167,17 @@ config PPPOE
 	  which contains instruction on how to use this driver (under 
 	  the heading "Kernel mode PPPoE").
 
+config PPTP
+	tristate "PPP over IPv4 (PPTP) (EXPERIMENTAL)"
+	depends on EXPERIMENTAL && PPP && NET_IPGRE_DEMUX
+	help
+	  Support for PPP over IPv4.(Point-to-Point Tunneling Protocol)
+
+	  This driver requires pppd plugin to work in client mode or
+	  modified pptpd (poptop) to work in server mode.
+	  See http://accel-pptp.sourceforge.net/ for information how to
+	  utilize this module.
+
 config PPPOATM
 	tristate "PPP over ATM"
 	depends on ATM && PPP
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 0a0512a..b33fef1 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -162,6 +162,7 @@ obj-$(CONFIG_PPP_BSDCOMP) += bsd_comp.o
 obj-$(CONFIG_PPP_MPPE) += ppp_mppe.o
 obj-$(CONFIG_PPPOE) += pppox.o pppoe.o
 obj-$(CONFIG_PPPOL2TP) += pppox.o
+obj-$(CONFIG_PPTP) += pppox.o pptp.o
 
 obj-$(CONFIG_SLIP) += slip.o
 obj-$(CONFIG_SLHC) += slhc.o
diff --git a/drivers/net/pptp.c b/drivers/net/pptp.c
new file mode 100644
index 0000000..836a696
--- /dev/null
+++ b/drivers/net/pptp.c
@@ -0,0 +1,721 @@
+/*
+ *  Point-to-Point Tunneling Protocol for Linux
+ *
+ *	Authors: Dmitry Kozlov <xeb@mail.ru>
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License
+ *	as published by the Free Software Foundation; either version
+ *	2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <linux/string.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/netdevice.h>
+#include <linux/net.h>
+#include <linux/skbuff.h>
+#include <linux/init.h>
+#include <linux/ppp_channel.h>
+#include <linux/ppp_defs.h>
+#include <linux/if_pppox.h>
+#include <linux/if_ppp.h>
+#include <linux/notifier.h>
+#include <linux/file.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/netfilter.h>
+#include <linux/netfilter_ipv4.h>
+#include <linux/version.h>
+#include <linux/rcupdate.h>
+#include <linux/spinlock.h>
+
+#include <net/sock.h>
+#include <net/protocol.h>
+#include <net/ip.h>
+#include <net/icmp.h>
+#include <net/route.h>
+#include <net/gre.h>
+
+#include <linux/uaccess.h>
+
+#define PPTP_DRIVER_VERSION "0.8.5"
+
+#define MAX_CALLID 65535
+
+static DECLARE_BITMAP(callid_bitmap, MAX_CALLID + 1);
+static struct pppox_sock **callid_sock;
+
+static DEFINE_SPINLOCK(chan_lock);
+
+static struct proto pptp_sk_proto __read_mostly;
+static struct ppp_channel_ops pptp_chan_ops;
+static const struct proto_ops pptp_ops;
+
+#define PPP_LCP_ECHOREQ 0x09
+#define PPP_LCP_ECHOREP 0x0A
+#define SC_RCV_BITS	(SC_RCV_B7_1|SC_RCV_B7_0|SC_RCV_ODDP|SC_RCV_EVNP)
+
+#define MISSING_WINDOW 20
+#define WRAPPED(curseq, lastseq)\
+	((((curseq) & 0xffffff00) == 0) &&\
+	(((lastseq) & 0xffffff00) == 0xffffff00))
+
+#define PPTP_GRE_PROTO  0x880B
+#define PPTP_GRE_VER    0x1
+
+#define PPTP_GRE_FLAG_C	0x80
+#define PPTP_GRE_FLAG_R	0x40
+#define PPTP_GRE_FLAG_K	0x20
+#define PPTP_GRE_FLAG_S	0x10
+#define PPTP_GRE_FLAG_A	0x80
+
+#define PPTP_GRE_IS_C(f) ((f)&PPTP_GRE_FLAG_C)
+#define PPTP_GRE_IS_R(f) ((f)&PPTP_GRE_FLAG_R)
+#define PPTP_GRE_IS_K(f) ((f)&PPTP_GRE_FLAG_K)
+#define PPTP_GRE_IS_S(f) ((f)&PPTP_GRE_FLAG_S)
+#define PPTP_GRE_IS_A(f) ((f)&PPTP_GRE_FLAG_A)
+
+#define PPTP_HEADER_OVERHEAD (2+sizeof(struct pptp_gre_header))
+struct pptp_gre_header {
+	u8  flags;
+	u8  ver;
+	u16 protocol;
+	u16 payload_len;
+	u16 call_id;
+	u32 seq;
+	u32 ack;
+} __packed;
+
+static struct pppox_sock *lookup_chan(u16 call_id, __be32 s_addr)
+{
+	struct pppox_sock *sock;
+	struct pptp_opt *opt;
+
+	rcu_read_lock();
+	sock = rcu_dereference(callid_sock[call_id]);
+	if (sock) {
+		opt = &sock->proto.pptp;
+		if (opt->dst_addr.sin_addr.s_addr != s_addr)
+			sock = NULL;
+		else
+			sock_hold(sk_pppox(sock));
+	}
+	rcu_read_unlock();
+
+	return sock;
+}
+
+static int lookup_chan_dst(u16 call_id, __be32 d_addr)
+{
+	struct pppox_sock *sock;
+	struct pptp_opt *opt;
+	int i;
+
+	rcu_read_lock();
+	for (i = find_next_bit(callid_bitmap, MAX_CALLID, 1); i < MAX_CALLID;
+	     i = find_next_bit(callid_bitmap, MAX_CALLID, i + 1)) {
+		sock = rcu_dereference(callid_sock[i]);
+		if (!sock)
+			continue;
+		opt = &sock->proto.pptp;
+		if (opt->dst_addr.call_id == call_id &&	opt->dst_addr.sin_addr.s_addr == d_addr)
+			break;
+	}
+	rcu_read_unlock();
+
+	return i < MAX_CALLID;
+}
+
+static int add_chan(struct pppox_sock *sock)
+{
+	static int call_id;
+
+	spin_lock(&chan_lock);
+	if (!sock->proto.pptp.src_addr.call_id)	{
+		call_id = find_next_zero_bit(callid_bitmap, MAX_CALLID, call_id + 1);
+		if (call_id == MAX_CALLID) {
+			call_id = find_next_zero_bit(callid_bitmap, MAX_CALLID, 1);
+			if (call_id == MAX_CALLID)
+				goto out_err;
+		}
+		sock->proto.pptp.src_addr.call_id = call_id;
+	} else if (test_bit(sock->proto.pptp.src_addr.call_id, callid_bitmap))
+		goto out_err;
+
+	set_bit(sock->proto.pptp.src_addr.call_id, callid_bitmap);
+	rcu_assign_pointer(callid_sock[sock->proto.pptp.src_addr.call_id], sock);
+	spin_unlock(&chan_lock);
+
+	return 0;
+
+out_err:
+	spin_unlock(&chan_lock);
+	return -1;
+}
+
+static void del_chan(struct pppox_sock *sock)
+{
+	spin_lock(&chan_lock);
+	clear_bit(sock->proto.pptp.src_addr.call_id, callid_bitmap);
+	rcu_assign_pointer(callid_sock[sock->proto.pptp.src_addr.call_id], NULL);
+	spin_unlock(&chan_lock);
+	synchronize_rcu();
+}
+
+static int pptp_xmit(struct ppp_channel *chan, struct sk_buff *skb)
+{
+	struct sock *sk = (struct sock *) chan->private;
+	struct pppox_sock *po = pppox_sk(sk);
+	struct pptp_opt *opt = &po->proto.pptp;
+	struct pptp_gre_header *hdr;
+	unsigned int header_len = sizeof(*hdr);
+	int err = 0;
+	int islcp;
+	int len;
+	unsigned char *data;
+	__u32 seq_recv;
+
+
+	struct rtable *rt;
+	struct net_device *tdev;
+	struct iphdr  *iph;
+	int    max_headroom;
+
+	if (sk_pppox(po)->sk_state & PPPOX_DEAD)
+		goto tx_error;
+
+	{
+		struct flowi fl = { .oif = 0,
+			.nl_u = {
+				.ip4_u = {
+					.daddr = opt->dst_addr.sin_addr.s_addr,
+					.saddr = opt->src_addr.sin_addr.s_addr,
+					.tos = RT_TOS(0) } },
+			.proto = IPPROTO_GRE };
+		err = ip_route_output_key(&init_net, &rt, &fl);
+		if (err)
+			goto tx_error;
+	}
+	tdev = rt->u.dst.dev;
+
+	max_headroom = LL_RESERVED_SPACE(tdev) + sizeof(*iph) + sizeof(*hdr) + 2;
+
+	if (skb_headroom(skb) < max_headroom || skb_cloned(skb) || skb_shared(skb)) {
+		struct sk_buff *new_skb = skb_realloc_headroom(skb, max_headroom);
+		if (!new_skb) {
+			ip_rt_put(rt);
+			goto tx_error;
+		}
+		if (skb->sk)
+			skb_set_owner_w(new_skb, skb->sk);
+		kfree_skb(skb);
+		skb = new_skb;
+	}
+
+	data = skb->data;
+	islcp = ((data[0] << 8) + data[1]) == PPP_LCP && 1 <= data[2] && data[2] <= 7;
+
+	/* compress protocol field */
+	if ((opt->ppp_flags & SC_COMP_PROT) && data[0] == 0 && !islcp)
+		skb_pull(skb, 1);
+
+	/* Put in the address/control bytes if necessary */
+	if ((opt->ppp_flags & SC_COMP_AC) == 0 || islcp) {
+		data = skb_push(skb, 2);
+		data[0] = PPP_ALLSTATIONS;
+		data[1] = PPP_UI;
+	}
+
+	len = skb->len;
+
+	seq_recv = opt->seq_recv;
+
+	if (opt->ack_sent == seq_recv)
+		header_len -= sizeof(hdr->ack);
+
+	/* Push down and install GRE header */
+	skb_push(skb, header_len);
+	hdr = (struct pptp_gre_header *)(skb->data);
+
+	hdr->flags       = PPTP_GRE_FLAG_K;
+	hdr->ver         = PPTP_GRE_VER;
+	hdr->protocol    = htons(PPTP_GRE_PROTO);
+	hdr->call_id     = htons(opt->dst_addr.call_id);
+
+	hdr->flags      |= PPTP_GRE_FLAG_S;
+	hdr->seq         = htonl(++opt->seq_sent);
+	if (opt->ack_sent != seq_recv)	{
+		/* send ack with this message */
+		hdr->ver |= PPTP_GRE_FLAG_A;
+		hdr->ack  = htonl(seq_recv);
+		opt->ack_sent = seq_recv;
+	}
+	hdr->payload_len = htons(len);
+
+	/*	Push down and install the IP header. */
+
+	skb_reset_transport_header(skb);
+	skb_push(skb, sizeof(*iph));
+	skb_reset_network_header(skb);
+	memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
+	IPCB(skb)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED | IPSKB_REROUTED);
+
+	iph =	ip_hdr(skb);
+	iph->version =	4;
+	iph->ihl =	sizeof(struct iphdr) >> 2;
+	if (ip_dont_fragment(sk, &rt->u.dst))
+		iph->frag_off	=	htons(IP_DF);
+	else
+		iph->frag_off	=	0;
+	iph->protocol = IPPROTO_GRE;
+	iph->tos      = 0;
+	iph->daddr    = rt->rt_dst;
+	iph->saddr    = rt->rt_src;
+	iph->ttl      = dst_metric(&rt->u.dst, RTAX_HOPLIMIT);
+	iph->tot_len  = htons(skb->len);
+
+	skb_dst_drop(skb);
+	skb_dst_set(skb, &rt->u.dst);
+
+	nf_reset(skb);
+
+	skb->ip_summed = CHECKSUM_NONE;
+	ip_select_ident(iph, &rt->u.dst, NULL);
+	ip_send_check(iph);
+
+	ip_local_out(skb);
+
+tx_error:
+	return 1;
+}
+
+static int pptp_rcv_core(struct sock *sk, struct sk_buff *skb)
+{
+	struct pppox_sock *po = pppox_sk(sk);
+	struct pptp_opt *opt = &po->proto.pptp;
+	int headersize, payload_len, seq;
+	__u8 *payload;
+	struct pptp_gre_header *header;
+
+	if (!(sk->sk_state & PPPOX_CONNECTED)) {
+		if (sock_queue_rcv_skb(sk, skb))
+			goto drop;
+		return NET_RX_SUCCESS;
+	}
+
+	header = (struct pptp_gre_header *)(skb->data);
+
+	/* test if acknowledgement present */
+	if (PPTP_GRE_IS_A(header->ver)) {
+		__u32 ack = (PPTP_GRE_IS_S(header->flags)) ?
+				header->ack : header->seq; /* ack in different place if S = 0 */
+
+		ack = ntohl(ack);
+
+		if (ack > opt->ack_recv)
+			opt->ack_recv = ack;
+		/* also handle sequence number wrap-around  */
+		if (WRAPPED(ack, opt->ack_recv))
+			opt->ack_recv = ack;
+	}
+
+	/* test if payload present */
+	if (!PPTP_GRE_IS_S(header->flags))
+		goto drop;
+
+	headersize  = sizeof(*header);
+	payload_len = ntohs(header->payload_len);
+	seq         = ntohl(header->seq);
+
+	/* no ack present? */
+	if (!PPTP_GRE_IS_A(header->ver))
+		headersize -= sizeof(header->ack);
+	/* check for incomplete packet (length smaller than expected) */
+	if (skb->len - headersize < payload_len)
+		goto drop;
+
+	payload = skb->data + headersize;
+	/* check for expected sequence number */
+	if (seq < opt->seq_recv + 1 || WRAPPED(opt->seq_recv, seq)) {
+		if ((payload[0] == PPP_ALLSTATIONS) && (payload[1] == PPP_UI) &&
+		     (PPP_PROTOCOL(payload) == PPP_LCP) &&
+		     ((payload[4] == PPP_LCP_ECHOREQ) || (payload[4] == PPP_LCP_ECHOREP)))
+			goto allow_packet;
+	} else {
+		opt->seq_recv = seq;
+allow_packet:
+		skb_pull(skb, headersize);
+
+		if (payload[0] == PPP_ALLSTATIONS && payload[1] == PPP_UI) {
+			/* chop off address/control */
+			if (skb->len < 3)
+				goto drop;
+			skb_pull(skb, 2);
+		}
+
+		if ((*skb->data) & 1) {
+			/* protocol is compressed */
+			skb_push(skb, 1)[0] = 0;
+		}
+
+		skb->ip_summed = CHECKSUM_NONE;
+		skb_set_network_header(skb, skb->head-skb->data);
+		ppp_input(&po->chan, skb);
+
+		return NET_RX_SUCCESS;
+	}
+drop:
+	kfree_skb(skb);
+	return NET_RX_DROP;
+}
+
+static int pptp_rcv(struct sk_buff *skb)
+{
+	struct pppox_sock *po;
+	struct pptp_gre_header *header;
+	struct iphdr *iph;
+
+	if (skb->pkt_type != PACKET_HOST)
+		goto drop;
+
+	if (!pskb_may_pull(skb, 12))
+		goto drop;
+
+	iph = ip_hdr(skb);
+
+	header = (struct pptp_gre_header *)skb->data;
+
+	if (ntohs(header->protocol) != PPTP_GRE_PROTO || /* PPTP-GRE protocol for PPTP */
+		PPTP_GRE_IS_C(header->flags) ||                /* flag C should be clear */
+		PPTP_GRE_IS_R(header->flags) ||                /* flag R should be clear */
+		!PPTP_GRE_IS_K(header->flags) ||               /* flag K should be set */
+		(header->flags&0xF) != 0)                      /* routing and recursion ctrl = 0 */
+		/* if invalid, discard this packet */
+		goto drop;
+
+	po = lookup_chan(htons(header->call_id), iph->saddr);
+	if (po) {
+		skb_dst_drop(skb);
+		nf_reset(skb);
+		return sk_receive_skb(sk_pppox(po), skb, 0);
+	}
+drop:
+	kfree_skb(skb);
+	return NET_RX_DROP;
+}
+
+static int pptp_bind(struct socket *sock, struct sockaddr *uservaddr, int sockaddr_len)
+{
+	struct sock *sk = sock->sk;
+	struct sockaddr_pppox *sp = (struct sockaddr_pppox *) uservaddr;
+	struct pppox_sock *po = pppox_sk(sk);
+	struct pptp_opt *opt = &po->proto.pptp;
+	int error = 0;
+
+	lock_sock(sk);
+
+	opt->src_addr = sp->sa_addr.pptp;
+	if (add_chan(po)) {
+		release_sock(sk);
+		error = -EBUSY;
+	}
+
+	release_sock(sk);
+	return error;
+}
+
+static int pptp_connect(struct socket *sock, struct sockaddr *uservaddr,
+		  int sockaddr_len, int flags)
+{
+	struct sock *sk = sock->sk;
+	struct sockaddr_pppox *sp = (struct sockaddr_pppox *) uservaddr;
+	struct pppox_sock *po = pppox_sk(sk);
+	struct pptp_opt *opt = &po->proto.pptp;
+	struct rtable *rt;
+	int error = 0;
+
+	if (sp->sa_protocol != PX_PROTO_PPTP)
+		return -EINVAL;
+
+	if (lookup_chan_dst(sp->sa_addr.pptp.call_id, sp->sa_addr.pptp.sin_addr.s_addr))
+		return -EALREADY;
+
+	lock_sock(sk);
+	/* Check for already bound sockets */
+	if (sk->sk_state & PPPOX_CONNECTED) {
+		error = -EBUSY;
+		goto end;
+	}
+
+	/* Check for already disconnected sockets, on attempts to disconnect */
+	if (sk->sk_state & PPPOX_DEAD) {
+		error = -EALREADY;
+		goto end;
+	}
+
+	if (!opt->src_addr.sin_addr.s_addr || !sp->sa_addr.pptp.sin_addr.s_addr) {
+		error = -EINVAL;
+		goto end;
+	}
+
+	po->chan.private = sk;
+	po->chan.ops = &pptp_chan_ops;
+
+	{
+		struct flowi fl = {
+			.nl_u = {
+				.ip4_u = {
+					.daddr = opt->dst_addr.sin_addr.s_addr,
+					.saddr = opt->src_addr.sin_addr.s_addr,
+					.tos = RT_CONN_FLAGS(sk) } },
+			.proto = IPPROTO_GRE };
+		security_sk_classify_flow(sk, &fl);
+		if (ip_route_output_key(&init_net, &rt, &fl)) {
+			error = -EHOSTUNREACH;
+			goto end;
+		}
+		sk_setup_caps(sk, &rt->u.dst);
+	}
+	po->chan.mtu = dst_mtu(&rt->u.dst);
+	if (!po->chan.mtu)
+		po->chan.mtu = PPP_MTU;
+	ip_rt_put(rt);
+	po->chan.mtu -= PPTP_HEADER_OVERHEAD;
+
+	po->chan.hdrlen = 2 + sizeof(struct pptp_gre_header);
+	error = ppp_register_channel(&po->chan);
+	if (error) {
+		pr_err("PPTP: failed to register PPP channel (%d)\n", error);
+		goto end;
+	}
+
+	opt->dst_addr = sp->sa_addr.pptp;
+	sk->sk_state = PPPOX_CONNECTED;
+
+ end:
+	release_sock(sk);
+	return error;
+}
+
+static int pptp_getname(struct socket *sock, struct sockaddr *uaddr,
+		  int *usockaddr_len, int peer)
+{
+	int len = sizeof(struct sockaddr_pppox);
+	struct sockaddr_pppox sp;
+
+	sp.sa_family	  = AF_PPPOX;
+	sp.sa_protocol  = PX_PROTO_PPTP;
+	sp.sa_addr.pptp = pppox_sk(sock->sk)->proto.pptp.src_addr;
+
+	memcpy(uaddr, &sp, len);
+
+	*usockaddr_len = len;
+
+	return 0;
+}
+
+static int pptp_release(struct socket *sock)
+{
+	struct sock *sk = sock->sk;
+	struct pppox_sock *po;
+	struct pptp_opt *opt;
+	int error = 0;
+
+	if (!sk)
+		return 0;
+
+	lock_sock(sk);
+
+	if (sock_flag(sk, SOCK_DEAD)) {
+		release_sock(sk);
+		return -EBADF;
+	}
+
+	po = pppox_sk(sk);
+	opt = &po->proto.pptp;
+	del_chan(po);
+
+	pppox_unbind_sock(sk);
+	sk->sk_state = PPPOX_DEAD;
+
+	sock_orphan(sk);
+	sock->sk = NULL;
+
+	release_sock(sk);
+	sock_put(sk);
+
+	return error;
+}
+
+static void pptp_sock_destruct(struct sock *sk)
+{
+	if (!(sk->sk_state & PPPOX_DEAD)) {
+		del_chan(pppox_sk(sk));
+		pppox_unbind_sock(sk);
+	}
+	skb_queue_purge(&sk->sk_receive_queue);
+}
+
+static int pptp_create(struct net *net, struct socket *sock)
+{
+	int error = -ENOMEM;
+	struct sock *sk;
+	struct pppox_sock *po;
+	struct pptp_opt *opt;
+
+	sk = sk_alloc(net, PF_PPPOX, GFP_KERNEL, &pptp_sk_proto);
+	if (!sk)
+		goto out;
+
+	sock_init_data(sock, sk);
+
+	sock->state = SS_UNCONNECTED;
+	sock->ops   = &pptp_ops;
+
+	sk->sk_backlog_rcv = pptp_rcv_core;
+	sk->sk_state       = PPPOX_NONE;
+	sk->sk_type        = SOCK_STREAM;
+	sk->sk_family      = PF_PPPOX;
+	sk->sk_protocol    = PX_PROTO_PPTP;
+	sk->sk_destruct    = pptp_sock_destruct;
+
+	po = pppox_sk(sk);
+	opt = &po->proto.pptp;
+
+	opt->seq_sent = 0; opt->seq_recv = 0;
+	opt->ack_recv = 0; opt->ack_sent = 0;
+
+	error = 0;
+out:
+	return error;
+}
+
+static int pptp_ppp_ioctl(struct ppp_channel *chan, unsigned int cmd,
+			   unsigned long arg)
+{
+	struct sock *sk = (struct sock *) chan->private;
+	struct pppox_sock *po = pppox_sk(sk);
+	struct pptp_opt *opt = &po->proto.pptp;
+	void __user *argp = (void __user *)arg;
+	int __user *p = argp;
+	int err, val;
+
+	err = -EFAULT;
+	switch (cmd) {
+	case PPPIOCGFLAGS:
+		val = opt->ppp_flags;
+		if (put_user(val, p))
+			break;
+		err = 0;
+		break;
+	case PPPIOCSFLAGS:
+		if (get_user(val, p))
+			break;
+		opt->ppp_flags = val & ~SC_RCV_BITS;
+		err = 0;
+		break;
+	default:
+		err = -ENOTTY;
+	}
+
+	return err;
+}
+
+static struct ppp_channel_ops pptp_chan_ops = {
+	.start_xmit = pptp_xmit,
+	.ioctl      = pptp_ppp_ioctl,
+};
+
+static struct proto pptp_sk_proto __read_mostly = {
+	.name     = "PPTP",
+	.owner    = THIS_MODULE,
+	.obj_size = sizeof(struct pppox_sock),
+};
+
+static const struct proto_ops pptp_ops = {
+	.family     = AF_PPPOX,
+	.owner      = THIS_MODULE,
+	.release    = pptp_release,
+	.bind       = pptp_bind,
+	.connect    = pptp_connect,
+	.socketpair = sock_no_socketpair,
+	.accept     = sock_no_accept,
+	.getname    = pptp_getname,
+	.poll       = sock_no_poll,
+	.listen     = sock_no_listen,
+	.shutdown   = sock_no_shutdown,
+	.setsockopt = sock_no_setsockopt,
+	.getsockopt = sock_no_getsockopt,
+	.sendmsg    = sock_no_sendmsg,
+	.recvmsg    = sock_no_recvmsg,
+	.mmap       = sock_no_mmap,
+	.ioctl      = pppox_ioctl,
+};
+
+static struct pppox_proto pppox_pptp_proto = {
+	.create = pptp_create,
+	.owner  = THIS_MODULE,
+};
+
+static struct gre_protocol gre_pptp_protocol = {
+	.handler = pptp_rcv,
+};
+
+static int __init pptp_init_module(void)
+{
+	int err = 0;
+	pr_info("PPTP driver version " PPTP_DRIVER_VERSION "\n");
+
+	if (gre_add_protocol(&gre_pptp_protocol, GREPROTO_PPTP) < 0) {
+		pr_err("PPTP: can't add protocol\n");
+		goto out;
+	}
+
+	err = proto_register(&pptp_sk_proto, 0);
+	if (err) {
+		pr_err("PPTP: can't register sk_proto\n");
+		goto out_inet_del_protocol;
+	}
+
+	err = register_pppox_proto(PX_PROTO_PPTP, &pppox_pptp_proto);
+	if (err) {
+		pr_err("PPTP: can't register pppox_proto\n");
+		goto out_unregister_sk_proto;
+	}
+
+	callid_sock = (struct pppox_sock **)__vmalloc((MAX_CALLID + 1) * sizeof(void *), GFP_KERNEL | __GFP_ZERO, PAGE_KERNEL);
+	if (!callid_sock) {
+		pr_err("PPTP: cann't allocate memory\n");
+		goto out_unregister_pppox_proto;
+	}
+
+out:
+	return err;
+out_unregister_pppox_proto:
+	unregister_pppox_proto(PX_PROTO_PPTP);
+out_unregister_sk_proto:
+	proto_unregister(&pptp_sk_proto);
+out_inet_del_protocol:
+	gre_del_protocol(&gre_pptp_protocol, GREPROTO_PPTP);
+	return err;
+}
+
+static void __exit pptp_exit_module(void)
+{
+	unregister_pppox_proto(PX_PROTO_PPTP);
+	proto_unregister(&pptp_sk_proto);
+	gre_del_protocol(&gre_pptp_protocol, GREPROTO_PPTP);
+	vfree(callid_sock);
+}
+
+module_init(pptp_init_module);
+module_exit(pptp_exit_module);
+
+MODULE_DESCRIPTION("Point-to-Point Tunneling Protocol");
+MODULE_AUTHOR("D. Kozlov (xeb@mail.ru)");
+MODULE_LICENSE("GPL");
+
diff --git a/include/linux/if_pppox.h b/include/linux/if_pppox.h
index a6577af..e5c820a 100644
--- a/include/linux/if_pppox.h
+++ b/include/linux/if_pppox.h
@@ -40,26 +40,37 @@
  * PPPoE addressing definition 
  */ 
 typedef __be16 sid_t;
-struct pppoe_addr{ 
-       sid_t           sid;                    /* Session identifier */ 
-       unsigned char   remote[ETH_ALEN];       /* Remote address */ 
-       char            dev[IFNAMSIZ];          /* Local device to use */ 
+struct pppoe_addr {
+	sid_t         sid;                    /* Session identifier */
+	unsigned char remote[ETH_ALEN];       /* Remote address */
+	char          dev[IFNAMSIZ];          /* Local device to use */
 }; 
  
 /************************************************************************ 
- * Protocols supported by AF_PPPOX 
- */ 
+ * PPTP addressing definition
+ */
+struct pptp_addr {
+	u16             call_id;
+	struct in_addr  sin_addr;
+};
+
+/************************************************************************
+ * Protocols supported by AF_PPPOX
+ */
 #define PX_PROTO_OE    0 /* Currently just PPPoE */
 #define PX_PROTO_OL2TP 1 /* Now L2TP also */
-#define PX_MAX_PROTO   2
+#define PX_PROTO_PPTP  2
+#define PX_MAX_PROTO   3
 
-struct sockaddr_pppox { 
-       sa_family_t     sa_family;            /* address family, AF_PPPOX */ 
-       unsigned int    sa_protocol;          /* protocol identifier */ 
-       union{ 
-               struct pppoe_addr       pppoe; 
-       }sa_addr; 
-}__attribute__ ((packed)); 
+struct sockaddr_pppox {
+	sa_family_t     sa_family;            /* address family, AF_PPPOX */
+	unsigned int    sa_protocol;          /* protocol identifier */
+	union {
+		struct pppoe_addr  pppoe;
+		struct pptp_addr   pptp;
+	} sa_addr;
+} __packed;
+/* hm ... why packed here ? */
 
 /* The use of the above union isn't viable because the size of this
  * struct must stay fixed over time -- applications use sizeof(struct
@@ -70,7 +81,7 @@ struct sockaddr_pppol2tp {
 	sa_family_t     sa_family;      /* address family, AF_PPPOX */
 	unsigned int    sa_protocol;    /* protocol identifier */
 	struct pppol2tp_addr pppol2tp;
-}__attribute__ ((packed));
+} __packed;
 
 /* The L2TPv3 protocol changes tunnel and session ids from 16 to 32
  * bits. So we need a different sockaddr structure.
@@ -79,7 +90,7 @@ struct sockaddr_pppol2tpv3 {
 	sa_family_t     sa_family;      /* address family, AF_PPPOX */
 	unsigned int    sa_protocol;    /* protocol identifier */
 	struct pppol2tpv3_addr pppol2tp;
-} __attribute__ ((packed));
+} __packed;
 
 /*********************************************************************
  *
@@ -101,7 +112,7 @@ struct pppoe_tag {
 	__be16 tag_type;
 	__be16 tag_len;
 	char tag_data[0];
-} __attribute ((packed));
+} __packed;
 
 /* Tag identifiers */
 #define PTT_EOL		__cpu_to_be16(0x0000)
@@ -129,7 +140,7 @@ struct pppoe_hdr {
 	__be16 sid;
 	__be16 length;
 	struct pppoe_tag tag[0];
-} __attribute__ ((packed));
+} __packed;
 
 /* Length of entire PPPoE + PPP header */
 #define PPPOE_SES_HLEN	8
@@ -150,15 +161,23 @@ struct pppoe_opt {
 					     relayed to (PPPoE relaying) */
 };
 
+struct pptp_opt {
+	struct pptp_addr src_addr;
+	struct pptp_addr dst_addr;
+	u32 ack_sent, ack_recv;
+	u32 seq_sent, seq_recv;
+	int ppp_flags;
+};
 #include <net/sock.h>
 
 struct pppox_sock {
 	/* struct sock must be the first member of pppox_sock */
-	struct sock		sk;
-	struct ppp_channel	chan;
+	struct sock sk;
+	struct ppp_channel chan;
 	struct pppox_sock	*next;	  /* for hash table */
 	union {
 		struct pppoe_opt pppoe;
+		struct pptp_opt  pptp;
 	} proto;
 	__be16			num;
 };
diff --git a/include/net/gre.h b/include/net/gre.h
new file mode 100644
index 0000000..8266547
--- /dev/null
+++ b/include/net/gre.h
@@ -0,0 +1,18 @@
+#ifndef __LINUX_GRE_H
+#define __LINUX_GRE_H
+
+#include <linux/skbuff.h>
+
+#define GREPROTO_CISCO		0
+#define GREPROTO_PPTP		1
+#define GREPROTO_MAX		2
+
+struct gre_protocol {
+	int  (*handler)(struct sk_buff *skb);
+	void (*err_handler)(struct sk_buff *skb, u32 info);
+};
+
+int gre_add_protocol(const struct gre_protocol *proto, u8 version);
+int gre_del_protocol(const struct gre_protocol *proto, u8 version);
+
+#endif
diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig
index 7c3a7d1..7458bda 100644
--- a/net/ipv4/Kconfig
+++ b/net/ipv4/Kconfig
@@ -215,8 +215,15 @@ config NET_IPIP
 	  be inserted in and removed from the running kernel whenever you
 	  want). Most people won't need this and can say N.
 
+config NET_IPGRE_DEMUX
+	tristate "IP: GRE demultiplexer"
+	help
+	 This is helper module to demultiplex GRE packets on GRE version field criteria.
+	 Required by ip_gre and pptp modules.
+
 config NET_IPGRE
 	tristate "IP: GRE tunnels over IP"
+	depends on NET_IPGRE_DEMUX
 	help
 	  Tunneling means encapsulating data of one protocol type within
 	  another protocol and sending it over a channel that understands the
diff --git a/net/ipv4/Makefile b/net/ipv4/Makefile
index 80ff87c..4978d22 100644
--- a/net/ipv4/Makefile
+++ b/net/ipv4/Makefile
@@ -20,6 +20,7 @@ obj-$(CONFIG_PROC_FS) += proc.o
 obj-$(CONFIG_IP_MULTIPLE_TABLES) += fib_rules.o
 obj-$(CONFIG_IP_MROUTE) += ipmr.o
 obj-$(CONFIG_NET_IPIP) += ipip.o
+obj-$(CONFIG_NET_IPGRE_DEMUX) += gre.o
 obj-$(CONFIG_NET_IPGRE) += ip_gre.o
 obj-$(CONFIG_SYN_COOKIES) += syncookies.o
 obj-$(CONFIG_INET_AH) += ah4.o
diff --git a/net/ipv4/gre.c b/net/ipv4/gre.c
new file mode 100644
index 0000000..422f701
--- /dev/null
+++ b/net/ipv4/gre.c
@@ -0,0 +1,151 @@
+/*
+ *	GRE over IPv4 demultiplexer driver
+ *
+ *	Authors: Dmitry Kozlov (xeb@xxxxxxx)
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License
+ *	as published by the Free Software Foundation; either version
+ *	2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/kmod.h>
+#include <linux/skbuff.h>
+#include <linux/in.h>
+#include <linux/netdevice.h>
+#include <linux/version.h>
+#include <linux/spinlock.h>
+#include <net/protocol.h>
+#include <net/gre.h>
+
+
+const struct gre_protocol *gre_proto[GREPROTO_MAX] __read_mostly;
+static DEFINE_SPINLOCK(gre_proto_lock);
+
+int gre_add_protocol(const struct gre_protocol *proto, u8 version)
+{
+	if (version >= GREPROTO_MAX)
+		goto err_out;
+
+	spin_lock(&gre_proto_lock);
+	if (gre_proto[version])
+		goto err_out_unlock;
+
+	rcu_assign_pointer(gre_proto[version], proto);
+	spin_unlock(&gre_proto_lock);
+	return 0;
+
+err_out_unlock:
+	spin_unlock(&gre_proto_lock);
+err_out:
+	return -1;
+}
+EXPORT_SYMBOL_GPL(gre_add_protocol);
+
+int gre_del_protocol(const struct gre_protocol *proto, u8 version)
+{
+	if (version >= GREPROTO_MAX)
+		goto err_out;
+
+	spin_lock(&gre_proto_lock);
+	if (gre_proto[version] != proto)
+		goto err_out_unlock;
+	rcu_assign_pointer(gre_proto[version], NULL);
+	spin_unlock(&gre_proto_lock);
+	synchronize_rcu();
+	return 0;
+
+err_out_unlock:
+	spin_unlock(&gre_proto_lock);
+err_out:
+	return -1;
+}
+EXPORT_SYMBOL_GPL(gre_del_protocol);
+
+static int gre_rcv(struct sk_buff *skb)
+{
+	const struct gre_protocol *proto;
+	u8 ver;
+	int ret;
+
+	if (!pskb_may_pull(skb, 12))
+		goto drop;
+
+	ver = skb->data[1]&0x7f;
+	if (ver >= GREPROTO_MAX)
+		goto drop;
+
+	rcu_read_lock();
+	proto = rcu_dereference(gre_proto[ver]);
+	if (!proto || !proto->handler)
+		goto drop_unlock;
+	ret = proto->handler(skb);
+	rcu_read_unlock();
+	return ret;
+
+drop_unlock:
+	rcu_read_unlock();
+drop:
+	kfree_skb(skb);
+	return NET_RX_DROP;
+}
+
+static void gre_err(struct sk_buff *skb, u32 info)
+{
+	const struct gre_protocol *proto;
+	u8 ver;
+
+	if (!pskb_may_pull(skb, 12))
+		goto drop;
+
+	ver = skb->data[1]&0x7f;
+	if (ver >= GREPROTO_MAX)
+		goto drop;
+
+	rcu_read_lock();
+	proto = rcu_dereference(gre_proto[ver]);
+	if (!proto || !proto->err_handler)
+		goto drop_unlock;
+	proto->err_handler(skb, info);
+	rcu_read_unlock();
+	return;
+
+drop_unlock:
+	rcu_read_unlock();
+drop:
+	kfree_skb(skb);
+}
+
+static const struct net_protocol net_gre_protocol = {
+	.handler     = gre_rcv,
+	.err_handler = gre_err,
+	.netns_ok    = 1,
+};
+
+static int __init gre_init(void)
+{
+	pr_info("GRE over IPv4 demultiplexor driver");
+
+	if (inet_add_protocol(&net_gre_protocol, IPPROTO_GRE) < 0) {
+		pr_err("gre: can't add protocol\n");
+		return -EAGAIN;
+	}
+
+	return 0;
+}
+
+static void __exit gre_exit(void)
+{
+	inet_del_protocol(&net_gre_protocol, IPPROTO_GRE);
+}
+
+module_init(gre_init);
+module_exit(gre_exit);
+
+MODULE_DESCRIPTION("GRE over IPv4 demultiplexer driver");
+MODULE_AUTHOR("D. Kozlov (xeb@xxxxxxx)");
+MODULE_LICENSE("GPL");
+
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c
index 32618e1..5a01d86 100644
--- a/net/ipv4/ip_gre.c
+++ b/net/ipv4/ip_gre.c
@@ -44,6 +44,7 @@
 #include <net/net_namespace.h>
 #include <net/netns/generic.h>
 #include <net/rtnetlink.h>
+#include <net/gre.h>
 
 #ifdef CONFIG_IPV6
 #include <net/ipv6.h>
@@ -1276,10 +1277,9 @@ static void ipgre_fb_tunnel_init(struct net_device *dev)
 }
 
 
-static const struct net_protocol ipgre_protocol = {
-	.handler	=	ipgre_rcv,
-	.err_handler	=	ipgre_err,
-	.netns_ok	=	1,
+static const struct gre_protocol ipgre_protocol = {
+	.handler     = ipgre_rcv,
+	.err_handler = ipgre_err,
 };
 
 static void ipgre_destroy_tunnels(struct ipgre_net *ign, struct list_head *head)
@@ -1661,7 +1661,7 @@ static int __init ipgre_init(void)
 	if (err < 0)
 		return err;
 
-	err = inet_add_protocol(&ipgre_protocol, IPPROTO_GRE);
+	err = gre_add_protocol(&ipgre_protocol, GREPROTO_CISCO);
 	if (err < 0) {
 		printk(KERN_INFO "ipgre init: can't add protocol\n");
 		goto add_proto_failed;
@@ -1681,7 +1681,7 @@ out:
 tap_ops_failed:
 	rtnl_link_unregister(&ipgre_link_ops);
 rtnl_link_failed:
-	inet_del_protocol(&ipgre_protocol, IPPROTO_GRE);
+	gre_del_protocol(&ipgre_protocol, GREPROTO_CISCO);
 add_proto_failed:
 	unregister_pernet_device(&ipgre_net_ops);
 	goto out;
@@ -1691,7 +1691,7 @@ static void __exit ipgre_fini(void)
 {
 	rtnl_link_unregister(&ipgre_tap_ops);
 	rtnl_link_unregister(&ipgre_link_ops);
-	if (inet_del_protocol(&ipgre_protocol, IPPROTO_GRE) < 0)
+	if (gre_del_protocol(&ipgre_protocol, GREPROTO_CISCO) < 0)
 		printk(KERN_INFO "ipgre close: can't remove protocol\n");
 	unregister_pernet_device(&ipgre_net_ops);
 }

^ permalink raw reply related

* Re: bne2 rx packet drop?
From: Rusty Russell @ 2010-08-19  2:35 UTC (permalink / raw)
  To: Michael Chan; +Cc: netdev@vger.kernel.org
In-Reply-To: <1280965623.7554.33.camel@HP1>

On Thu, 5 Aug 2010 09:17:03 am Michael Chan wrote:
> 
> On Wed, 2010-08-04 at 16:29 -0700, Rusty Russell wrote:
> > Hi Michael (and netdev!)
> > 
> >    I've got a customer seeing ~1000 rx packets dropped per day (on a busy
> > interface, bonding) via 'netstat -ni' RX-DRP's field across their 4-node
> > cluster.  The code seems to put checksum_discard and mac_discard into
> > that counter, so I'm not sure what the root cause is.
> 
> Please ask the customer for ethtool -S ethx.  It has a number of
> different counters for rx dropped packets so we can get a better idea of
> what's happening.

Thanks, finally got this.  Here's the ethtool -S from one of the quiet
interfaces:

NIC statistics:
    rx_bytes: 4490460
    rx_error_bytes: 0
    tx_bytes: 0
    tx_error_bytes: 0
    rx_ucast_packets: 0
    rx_mcast_packets: 0
    rx_bcast_packets: 31879
    tx_ucast_packets: 0
    tx_mcast_packets: 0
    tx_bcast_packets: 0
    tx_mac_errors: 0
    tx_carrier_errors: 0
    rx_crc_errors: 0
    rx_align_errors: 0
    tx_single_collisions: 0
    tx_multi_collisions: 0
    tx_deferred: 0
    tx_excess_collisions: 0
    tx_late_collisions: 0
    tx_total_collisions: 0
    rx_fragments: 0
    rx_jabbers: 0
    rx_undersize_packets: 0
    rx_oversize_packets: 0
    rx_64_byte_packets: 27241
    rx_65_to_127_byte_packets: 0
    rx_128_to_255_byte_packets: 0
    rx_256_to_511_byte_packets: 32
    rx_512_to_1023_byte_packets: 4606
    rx_1024_to_1522_byte_packets: 0
    rx_1523_to_9022_byte_packets: 0
    tx_64_byte_packets: 0
    tx_65_to_127_byte_packets: 0
    tx_128_to_255_byte_packets: 0
    tx_256_to_511_byte_packets: 0
    tx_512_to_1023_byte_packets: 0
    tx_1024_to_1522_byte_packets: 0
    tx_1523_to_9022_byte_packets: 0
    rx_xon_frames: 0
    rx_xoff_frames: 0
    tx_xon_frames: 0
    tx_xoff_frames: 0
    rx_mac_ctrl_frames: 0
    rx_filtered_packets: 4630821
    rx_discards: 0
    rx_fw_discards: 31876

Thanks!
Rusty.

^ permalink raw reply

* Re: Broadcom 5709 take long time to bring up
From: Joe Jin @ 2010-08-19  1:13 UTC (permalink / raw)
  To: Benjamin Li
  Cc: Joe Jin, Michael Chan, terry.liu@oracle.com,
	netdev@vger.kernel.org
In-Reply-To: <1282147735.3880.83.camel@localhost>

Hi Benjamin,

Thanks for your reply, see the answers in the lines.

On 2010-08-18 09:08, Benjamin Li wrote:
> Hi Joe,
> 
> Just a couple of quick questions:
> 
> 1.  It is possible that autonegotiation could take in the orders of
> seconds depending on the remote partner.   Could you describe the remote
> partner?

I dont think it caused that.
>From system log(see below) could saw brought up the interface took
around 3 seconds. I have add some debugging codes in the drivers and
could saw 3 times poll the devices and all the state of device is
link down.

Also, from system could found during bootup, brought all devices 
took less than 1 seconds, but ifdown/ifup take long times.

> 
> 2.  Are there iSCSI offload connections?  With iSCSI there is
> additionial overhead to cleanup/setup iSCSI connections on the
> chip/firmware when ifup'ing/ifdown'ing a network interface.

I'll confirm it later, but from system log saw have initialized 
iSCSI module, it maybe cause it.

> 
> 3.  Could you provide the kernel logs during this up/down test?  I
> wanted to see if there was anything interesting in the kernel logs.
> 

Here are kernel log:


System log of bootup
~~~~~~~~~~~~~~~~~~~~
Jul 19 11:23:28 bond-test kernel: Ethernet Channel Bonding Driver: v3.4.0 (October 7, 2008)
Jul 19 11:23:28 bond-test kernel: bonding: Warning: updelay (150) is not a multiple of miimon (100), updelay rounded to 100 ms
Jul 19 11:23:28 bond-test kernel: bonding: MII link monitoring set to 100 ms
Jul 19 11:23:28 bond-test kernel: ADDRCONF(NETDEV_UP): bond0: link is not ready
Jul 19 11:23:28 bond-test kernel: bonding: bond0: Adding slave eth0.
Jul 19 11:23:28 bond-test kernel: bnx2: eth0: using MSI
Jul 19 11:23:28 bond-test kernel: iscsi: registered transport (bcm570x-020000)
Jul 19 11:23:28 bond-test kernel: bnx2i: netif=eth0, iscsi=bcm570x-020000
Jul 19 11:23:28 bond-test kernel: bnx2i [02:00.00]: ISCSI_INIT passed
Jul 19 11:23:28 bond-test kernel: bonding: bond0: enslaving eth0 as a backup interface with a down link.
Jul 19 11:23:28 bond-test kernel: bonding: bond0: Adding slave eth1.
Jul 19 11:23:28 bond-test kernel: bnx2: eth1: using MSI
Jul 19 11:23:28 bond-test kernel: iscsi: registered transport (bcm570x-020001)
Jul 19 11:23:28 bond-test kernel: bnx2i: netif=eth1, iscsi=bcm570x-020001
Jul 19 11:23:28 bond-test kernel: bnx2i [02:00.01]: ISCSI_INIT passed
Jul 19 11:23:28 bond-test kernel: bonding: bond0: enslaving eth1 as a backup interface with a down link.
Jul 19 11:23:28 bond-test kernel: bnx2: eth1 NIC Copper Link is Up, 1000 Mbps full duplex, receive & transmit flow control ON
Jul 19 11:23:28 bond-test kernel: bonding: bond0: link status up for interface eth1, enabling it in 0 ms.
Jul 19 11:23:28 bond-test kernel: bonding: bond0: link status definitely up for interface eth1.
Jul 19 11:23:28 bond-test kernel: bonding: bond0: making interface eth1 the new active one.
Jul 19 11:23:28 bond-test kernel: bonding: bond0: first active interface up!
Jul 19 11:23:28 bond-test kernel: ADDRCONF(NETDEV_CHANGE): bond0: link becomes ready
Jul 19 11:23:28 bond-test kernel: bnx2: eth0 NIC Copper Link is Up, 1000 Mbps full duplex, receive & transmit flow control ON
Jul 19 11:23:28 bond-test kernel: bonding: bond0: link status up for interface eth0, enabling it in 100 ms.
Jul 19 11:23:28 bond-test kernel: bonding: bond0: link status definitely up for interface eth0.
Jul 19 11:23:28 bond-test kernel: bonding: bond0: making interface eth0 the new active one.


System log of the testcase
~~~~~~~~~~~~~~~~~~~~~~~~~~
Jul 19 11:25:41 bond-test kernel: bonding: bond0: Removing slave eth0
Jul 19 11:25:41 bond-test kernel: bonding: bond0: Warning: the permanent HWaddr of eth0 - 00:26:55:4F:1F:18 - is still in use by bond0. Set the HWaddr of eth0 to a different address to avoid conflicts.
Jul 19 11:25:41 bond-test kernel: bonding: bond0: releasing active interface eth0
Jul 19 11:25:41 bond-test kernel: bonding: bond0: making interface eth1 the new active one.
Jul 19 11:25:45 bond-test kernel: bonding: bond0: Adding slave eth0.
Jul 19 11:25:45 bond-test kernel: bnx2: eth0: using MSI
Jul 19 11:25:45 bond-test kernel: bnx2i [02:00.00]: ISCSI_INIT passed
Jul 19 11:25:45 bond-test kernel: bonding: bond0: enslaving eth0 as a backup interface with a down link.
Jul 19 11:25:47 bond-test kernel: bonding: bond0: Removing slave eth1
Jul 19 11:25:47 bond-test kernel: bonding: bond0: releasing active interface eth1
Jul 19 11:25:48 bond-test kernel: bnx2: eth0 NIC Copper Link is Up, 1000 Mbps full duplex, receive & transmit flow control ON
Jul 19 11:25:48 bond-test kernel: bonding: bond0: link status up for interface eth0, enabling it in 0 ms.
Jul 19 11:25:48 bond-test kernel: bonding: bond0: link status definitely up for interface eth0.
Jul 19 11:25:48 bond-test kernel: bonding: bond0: making interface eth0 the new active one.
Jul 19 11:25:53 bond-test kernel: bonding: bond0: Adding slave eth1.
Jul 19 11:25:53 bond-test kernel: bnx2: eth1: using MSI
Jul 19 11:25:53 bond-test kernel: bnx2i [02:00.01]: ISCSI_INIT passed
Jul 19 11:25:53 bond-test kernel: bonding: bond0: enslaving eth1 as a backup interface with a down link.
Jul 19 11:25:55 bond-test kernel: bonding: bond0: Removing slave eth0
Jul 19 11:25:55 bond-test kernel: bonding: bond0: Warning: the permanent HWaddr of eth0 - 00:26:55:4F:1F:18 - is still in use by bond0. Set the HWaddr of eth0 to a different address to avoid conflicts.
Jul 19 11:25:55 bond-test kernel: bonding: bond0: releasing active interface eth0
Jul 19 11:25:56 bond-test kernel: bnx2: eth1 NIC Copper Link is Up, 1000 Mbps full duplex, receive & transmit flow control ON
Jul 19 11:25:56 bond-test kernel: bonding: bond0: link status up for interface eth1, enabling it in 0 ms.
Jul 19 11:25:56 bond-test kernel: bonding: bond0: link status definitely up for interface eth1.
Jul 19 11:25:56 bond-test kernel: bonding: bond0: making interface eth1 the new active one.
Jul 19 11:25:59 bond-test kernel: bonding: bond0: Adding slave eth0.
Jul 19 11:25:59 bond-test kernel: bnx2: eth0: using MSI
Jul 19 11:25:59 bond-test kernel: bnx2i [02:00.00]: ISCSI_INIT passed
Jul 19 11:25:59 bond-test kernel: bonding: bond0: enslaving eth0 as a backup interface with a down link.
Jul 19 11:26:02 bond-test kernel: bnx2: eth0 NIC Copper Link is Up, 1000 Mbps full duplex, receive & transmit flow control ON
Jul 19 11:26:02 bond-test kernel: bonding: bond0: link status up for interface eth0, enabling it in 100 ms.
Jul 19 11:26:02 bond-test kernel: bonding: bond0: link status definitely up for interface eth0.
Jul 19 11:26:02 bond-test kernel: bonding: bond0: making interface eth0 the new active one.
Jul 19 11:26:27 bond-test kernel: bonding: bond0: Removing slave eth1
Jul 19 11:26:27 bond-test kernel: bonding: bond0: releasing backup interface eth1
Jul 19 11:26:29 bond-test kernel: bonding: bond0: Adding slave eth1.
Jul 19 11:26:29 bond-test kernel: bnx2: eth1: using MSI
Jul 19 11:26:29 bond-test kernel: bnx2i [02:00.01]: ISCSI_INIT passed
Jul 19 11:26:29 bond-test kernel: bonding: bond0: enslaving eth1 as a backup interface with a down link.
Jul 19 11:26:32 bond-test kernel: bnx2: eth1 NIC Copper Link is Up, 1000 Mbps full duplex, receive & transmit flow control ON
Jul 19 11:26:32 bond-test kernel: bonding: bond0: link status up for interface eth1, enabling it in 100 ms.
Jul 19 11:26:32 bond-test kernel: bonding: bond0: link status definitely up for interface eth1.
Jul 19 11:26:33 bond-test kernel: bonding: bond0: Removing slave eth0
Jul 19 11:26:33 bond-test kernel: bonding: bond0: Warning: the permanent HWaddr of eth0 - 00:26:55:4F:1F:18 - is still in use by bond0. Set the HWaddr of eth0 to a different address to avoid conflicts.
Jul 19 11:26:33 bond-test kernel: bonding: bond0: releasing active interface eth0
Jul 19 11:26:33 bond-test kernel: bonding: bond0: making interface eth1 the new active one.
Jul 19 11:26:36 bond-test kernel: bonding: bond0: Adding slave eth0.
Jul 19 11:26:36 bond-test kernel: bnx2: eth0: using MSI
Jul 19 11:26:36 bond-test kernel: bnx2i [02:00.00]: ISCSI_INIT passed
Jul 19 11:26:36 bond-test kernel: bonding: bond0: enslaving eth0 as a backup interface with a down link.
Jul 19 11:26:38 bond-test kernel: bnx2: eth0 NIC Copper Link is Up, 1000 Mbps full duplex, receive & transmit flow control ON
Jul 19 11:26:39 bond-test kernel: bonding: bond0: link status up for interface eth0, enabling it in 100 ms.
Jul 19 11:26:39 bond-test kernel: bonding: bond0: link status definitely up for interface eth0.
Jul 19 11:26:39 bond-test kernel: bonding: bond0: making interface eth0 the new active one.
Jul 19 11:27:07 bond-test kernel: bonding: bond0: Removing slave eth1
Jul 19 11:27:07 bond-test kernel: bonding: bond0: releasing backup interface eth1
Jul 19 11:27:09 bond-test kernel: bonding: bond0: Adding slave eth1.
Jul 19 11:27:09 bond-test kernel: bnx2: eth1: using MSI
Jul 19 11:27:09 bond-test kernel: bnx2i [02:00.01]: ISCSI_INIT passed
Jul 19 11:27:09 bond-test kernel: bonding: bond0: enslaving eth1 as a backup interface with a down link.
Jul 19 11:27:12 bond-test kernel: bnx2: eth1 NIC Copper Link is Up, 1000 Mbps full duplex, receive & transmit flow control ON
Jul 19 11:27:12 bond-test kernel: bonding: bond0: link status up for interface eth1, enabling it in 100 ms.
Jul 19 11:27:12 bond-test kernel: bonding: bond0: link status definitely up for interface eth1.
Jul 19 11:27:12 bond-test kernel: bonding: bond0: Removing slave eth0
Jul 19 11:27:12 bond-test kernel: bonding: bond0: Warning: the permanent HWaddr of eth0 - 00:26:55:4F:1F:18 - is still in use by bond0. Set the HWaddr of eth0 to a different address to avoid conflicts.
Jul 19 11:27:12 bond-test kernel: bonding: bond0: releasing active interface eth0
Jul 19 11:27:12 bond-test kernel: bonding: bond0: making interface eth1 the new active one.
Jul 19 11:27:15 bond-test kernel: bonding: bond0: Adding slave eth0.
Jul 19 11:27:15 bond-test kernel: bnx2: eth0: using MSI
Jul 19 11:27:15 bond-test kernel: bnx2i [02:00.00]: ISCSI_INIT passed
Jul 19 11:27:15 bond-test kernel: bonding: bond0: enslaving eth0 as a backup interface with a down link.
Jul 19 11:27:18 bond-test kernel: bnx2: eth0 NIC Copper Link is Up, 1000 Mbps full duplex, receive & transmit flow control ON
Jul 19 11:27:18 bond-test kernel: bonding: bond0: link status up for interface eth0, enabling it in 100 ms.
Jul 19 11:27:18 bond-test kernel: bonding: bond0: link status definitely up for interface eth0.
Jul 19 11:27:18 bond-test kernel: bonding: bond0: making interface eth0 the new active one.
Jul 19 11:27:22 bond-test kernel: bonding: bond0: Removing slave eth1
Jul 19 11:27:22 bond-test kernel: bonding: bond0: releasing backup interface eth1
Jul 19 11:27:24 bond-test kernel: bonding: bond0: Adding slave eth1.
Jul 19 11:27:24 bond-test kernel: bnx2: eth1: using MSI
Jul 19 11:27:24 bond-test kernel: bnx2i [02:00.01]: ISCSI_INIT passed
Jul 19 11:27:24 bond-test kernel: bonding: bond0: enslaving eth1 as a backup interface with a down link.
Jul 19 11:27:26 bond-test kernel: bnx2: eth1 NIC Copper Link is Up, 1000 Mbps full duplex, receive & transmit flow control ON
Jul 19 11:27:26 bond-test kernel: bonding: bond0: link status up for interface eth1, enabling it in 100 ms.
Jul 19 11:27:26 bond-test kernel: bonding: bond0: link status definitely up for interface eth1.
Jul 19 11:27:27 bond-test kernel: bonding: bond0: Removing slave eth0
Jul 19 11:27:27 bond-test kernel: bonding: bond0: Warning: the permanent HWaddr of eth0 - 00:26:55:4F:1F:18 - is still in use by bond0. Set the HWaddr of eth0 to a different address to avoid conflicts.
Jul 19 11:27:27 bond-test kernel: bonding: bond0: releasing active interface eth0
Jul 19 11:27:27 bond-test kernel: bonding: bond0: making interface eth1 the new active one.
Jul 19 11:27:30 bond-test kernel: bonding: bond0: Adding slave eth0.
Jul 19 11:27:30 bond-test kernel: bnx2: eth0: using MSI
Jul 19 11:27:30 bond-test kernel: bnx2i [02:00.00]: ISCSI_INIT passed
Jul 19 11:27:30 bond-test kernel: bonding: bond0: enslaving eth0 as a backup interface with a down link.
Jul 19 11:27:33 bond-test kernel: bnx2: eth0 NIC Copper Link is Up, 1000 Mbps full duplex, receive & transmit flow control ON
Jul 19 11:27:33 bond-test kernel: bonding: bond0: link status up for interface eth0, enabling it in 100 ms.
Jul 19 11:27:33 bond-test kernel: bonding: bond0: link status definitely up for interface eth0.
Jul 19 11:27:33 bond-test kernel: bonding: bond0: making interface eth0 the new active one.
Jul 19 11:27:52 bond-test kernel: bonding: bond0: Removing slave eth1
Jul 19 11:27:52 bond-test kernel: bonding: bond0: releasing backup interface eth1
Jul 19 11:27:54 bond-test kernel: bonding: bond0: Adding slave eth1.
Jul 19 11:27:54 bond-test kernel: bnx2: eth1: using MSI
Jul 19 11:27:54 bond-test kernel: bnx2i [02:00.01]: ISCSI_INIT passed
Jul 19 11:27:54 bond-test kernel: bonding: bond0: enslaving eth1 as a backup interface with a down link.
Jul 19 11:27:56 bond-test kernel: bnx2: eth1 NIC Copper Link is Up, 1000 Mbps full duplex, receive & transmit flow control ON
Jul 19 11:27:56 bond-test kernel: bonding: bond0: link status up for interface eth1, enabling it in 100 ms.
Jul 19 11:27:56 bond-test kernel: bonding: bond0: link status definitely up for interface eth1.
Jul 19 11:28:05 bond-test kernel: bonding: bond0: Removing slave eth0
Jul 19 11:28:05 bond-test kernel: bonding: bond0: Warning: the permanent HWaddr of eth0 - 00:26:55:4F:1F:18 - is still in use by bond0. Set the HWaddr of eth0 to a different address to avoid conflicts.
Jul 19 11:28:05 bond-test kernel: bonding: bond0: releasing active interface eth0
Jul 19 11:28:05 bond-test kernel: bonding: bond0: making interface eth1 the new active one.
Jul 19 11:28:07 bond-test ntpd[7189]: synchronized to 144.145.109.92, stratum 3
Jul 19 11:28:07 bond-test kernel: bonding: bond0: Adding slave eth0.
Jul 19 11:28:07 bond-test kernel: bnx2: eth0: using MSI
Jul 19 11:28:07 bond-test kernel: bnx2i [02:00.00]: ISCSI_INIT passed
Jul 19 11:28:07 bond-test kernel: bonding: bond0: enslaving eth0 as a backup interface with a down link.
Jul 19 11:28:11 bond-test kernel: bnx2: eth0 NIC Copper Link is Up, 1000 Mbps full duplex, receive & transmit flow control ON
Jul 19 11:28:11 bond-test kernel: bonding: bond0: link status up for interface eth0, enabling it in 100 ms.
Jul 19 11:28:11 bond-test kernel: bonding: bond0: link status definitely up for interface eth0.
Jul 19 11:28:11 bond-test kernel: bonding: bond0: making interface eth0 the new active one.
Jul 19 11:28:32 bond-test kernel: bonding: bond0: Removing slave eth1
Jul 19 11:28:32 bond-test kernel: bonding: bond0: releasing backup interface eth1
Jul 19 11:28:34 bond-test kernel: bonding: bond0: Adding slave eth1.
Jul 19 11:28:34 bond-test kernel: bnx2: eth1: using MSI
Jul 19 11:28:34 bond-test kernel: bnx2i [02:00.01]: ISCSI_INIT passed
Jul 19 11:28:34 bond-test kernel: bonding: bond0: enslaving eth1 as a backup interface with a down link.
Jul 19 11:28:37 bond-test kernel: bnx2: eth1 NIC Copper Link is Up, 1000 Mbps full duplex, receive & transmit flow control ON
Jul 19 11:28:37 bond-test kernel: bonding: bond0: link status up for interface eth1, enabling it in 100 ms.
Jul 19 11:28:37 bond-test kernel: bonding: bond0: link status definitely up for interface eth1.
Jul 19 11:28:40 bond-test kernel: bonding: bond0: Removing slave eth0
Jul 19 11:28:40 bond-test kernel: bonding: bond0: Warning: the permanent HWaddr of eth0 - 00:26:55:4F:1F:18 - is still in use by bond0. Set the HWaddr of eth0 to a different address to avoid conflicts.
Jul 19 11:28:40 bond-test kernel: bonding: bond0: releasing active interface eth0
Jul 19 11:28:40 bond-test kernel: bonding: bond0: making interface eth1 the new active one.
Jul 19 11:28:43 bond-test kernel: bonding: bond0: Adding slave eth0.
Jul 19 11:28:43 bond-test kernel: bnx2: eth0: using MSI
Jul 19 11:28:43 bond-test kernel: bnx2i [02:00.00]: ISCSI_INIT passed
Jul 19 11:28:43 bond-test kernel: bonding: bond0: enslaving eth0 as a backup interface with a down link.
Jul 19 11:28:45 bond-test kernel: bnx2: eth0 NIC Copper Link is Up, 1000 Mbps full duplex, receive & transmit flow control ON
Jul 19 11:28:45 bond-test kernel: bonding: bond0: link status up for interface eth0, enabling it in 100 ms.
Jul 19 11:28:45 bond-test kernel: bonding: bond0: link status definitely up for interface eth0.
Jul 19 11:28:45 bond-test kernel: bonding: bond0: making interface eth0 the new active one.
Jul 19 11:28:45 bond-test kernel: bonding: bond0: Removing slave eth1
Jul 19 11:28:45 bond-test kernel: bonding: bond0: releasing backup interface eth1
Jul 19 11:28:48 bond-test kernel: bonding: bond0: Adding slave eth1.
Jul 19 11:28:48 bond-test kernel: bnx2: eth1: using MSI
Jul 19 11:28:48 bond-test kernel: bnx2i [02:00.01]: ISCSI_INIT passed
Jul 19 11:28:48 bond-test kernel: bonding: bond0: enslaving eth1 as a backup interface with a down link.
Jul 19 11:28:51 bond-test kernel: bnx2: eth1 NIC Copper Link is Up, 1000 Mbps full duplex, receive & transmit flow control ON
Jul 19 11:28:51 bond-test kernel: bonding: bond0: link status up for interface eth1, enabling it in 100 ms.
Jul 19 11:28:51 bond-test kernel: bonding: bond0: link status definitely up for interface eth1.
Jul 19 11:28:53 bond-test kernel: bonding: bond0: Removing slave eth0
Jul 19 11:28:53 bond-test kernel: bonding: bond0: Warning: the permanent HWaddr of eth0 - 00:26:55:4F:1F:18 - is still in use by bond0. Set the HWaddr of eth0 to a different address to avoid conflicts.
Jul 19 11:28:53 bond-test kernel: bonding: bond0: releasing active interface eth0
Jul 19 11:28:53 bond-test kernel: bonding: bond0: making interface eth1 the new active one.
Jul 19 11:28:57 bond-test kernel: bonding: bond0: Adding slave eth0.
Jul 19 11:28:57 bond-test kernel: bnx2: eth0: using MSI
Jul 19 11:28:57 bond-test kernel: bnx2i [02:00.00]: ISCSI_INIT passed
Jul 19 11:28:57 bond-test kernel: bonding: bond0: enslaving eth0 as a backup interface with a down link.
Jul 19 11:28:59 bond-test kernel: bonding: bond0: Removing slave eth1
Jul 19 11:28:59 bond-test kernel: bonding: bond0: releasing active interface eth1
Jul 19 11:29:00 bond-test kernel: bnx2: eth0 NIC Copper Link is Up, 1000 Mbps full duplex, receive & transmit flow control ON
Jul 19 11:29:00 bond-test kernel: bonding: bond0: link status up for interface eth0, enabling it in 0 ms.
Jul 19 11:29:00 bond-test kernel: bonding: bond0: link status definitely up for interface eth0.
Jul 19 11:29:00 bond-test kernel: bonding: bond0: making interface eth0 the new active one.
Jul 19 11:29:13 bond-test kernel: bonding: bond0: Adding slave eth1.
Jul 19 11:29:13 bond-test kernel: bnx2: eth1: using MSI
Jul 19 11:29:13 bond-test kernel: bnx2i [02:00.01]: ISCSI_INIT passed
Jul 19 11:29:13 bond-test kernel: bonding: bond0: enslaving eth1 as a backup interface with a down link.
Jul 19 11:29:15 bond-test kernel: bonding: bond0: Removing slave eth0
Jul 19 11:29:15 bond-test kernel: bonding: bond0: Warning: the permanent HWaddr of eth0 - 00:26:55:4F:1F:18 - is still in use by bond0. Set the HWaddr of eth0 to a different address to avoid conflicts.
Jul 19 11:29:15 bond-test kernel: bonding: bond0: releasing active interface eth0
Jul 19 11:29:15 bond-test kernel: bnx2: eth1 NIC Copper Link is Up, 1000 Mbps full duplex, receive & transmit flow control ON
Jul 19 11:29:16 bond-test kernel: bonding: bond0: link status up for interface eth1, enabling it in 0 ms.
Jul 19 11:29:16 bond-test kernel: bonding: bond0: link status definitely up for interface eth1.
Jul 19 11:29:16 bond-test kernel: bonding: bond0: making interface eth1 the new active one.
Jul 19 11:29:20 bond-test kernel: bonding: bond0: Adding slave eth0.
Jul 19 11:29:20 bond-test kernel: bnx2: eth0: using MSI
Jul 19 11:29:20 bond-test kernel: bnx2i [02:00.00]: ISCSI_INIT passed
Jul 19 11:29:20 bond-test kernel: bonding: bond0: enslaving eth0 as a backup interface with a down link.
Jul 19 11:29:22 bond-test kernel: bnx2: eth0 NIC Copper Link is Up, 1000 Mbps full duplex, receive & transmit flow control ON
Jul 19 11:29:22 bond-test kernel: bonding: bond0: link status up for interface eth0, enabling it in 100 ms.
Jul 19 11:29:22 bond-test kernel: bonding: bond0: link status definitely up for interface eth0.



Thanks,
Joe



^ permalink raw reply

* Re: [PATCH 2/4] platform: Facilitate the creation of pseudo-platform buses
From: Grant Likely @ 2010-08-18 22:25 UTC (permalink / raw)
  To: Patrick Pannuto
  Cc: linux-kernel, linux-arm-msm, magnus.damm, gregkh, Kevin Hilman,
	Paul Mundt, Magnus Damm, Rafael J. Wysocki, Eric Miao,
	Dmitry Torokhov, netdev
In-Reply-To: <1282158943-11902-3-git-send-email-ppannuto@codeaurora.org>

Hi Patrick,

On Wed, Aug 18, 2010 at 1:15 PM, Patrick Pannuto
<ppannuto@codeaurora.org> wrote:
> (lkml.org seems to have lost August 3rd...)
> RFC: http://lkml.indiana.edu/hypermail/linux/kernel/1008.0/01342.html
>  v1: http://lkml.indiana.edu/hypermail/linux/kernel/1008.0/01942.html
>  v2: http://lkml.indiana.edu/hypermail/linux/kernel/1008.1/00958.html
>
> Based on the idea and code originally proposed by Kevin Hilman:
> http://www.mail-archive.com/linux-omap@vger.kernel.org/msg31161.html
>
> Changes from v2:
>   * Remove the pseudo_platform_bus_[un]register functions
>   * Split affected platform functions:
>       - Platform functions are split into a wrapper (with the
>         original function name) that retains the 'bus-setting'
>         and 'parent-setting' duties, and then exports all the
>         heavy-lifting to new __platform* counterparts
>       - "Pseudo" buses work the same as the platform bus now,
>         writing their own wrappers and calling the __platform
>         functions
>   * Export a *lot* of platform symbols to allow for intialization
>     of "pseudo" platform bus types.
>       - I personally like this model a lot, I think it is very
>         clean from an implementation perspective, even if it
>         does export a lot of new symbols
>       - Thanks to Michal Miroslaw <mirqus@gmail.com> for the
>         suggestion here

I'm not quite as hot on this approach, mostly because it is a lot more
invasive to the namespace than just exposing an initialization
routine.  However, I leave that as a point of 'taste' and Greg can
decide.  :-)

Otherwise, the patch looks good.  As I commented on the other patch, I
still want to see a real use case (ie, a bus with different behaviour)
before casting my vote.

One more comment below...

>   * Add more use-cases justifying the need of platform-ish bus types
>
> Changes from v1:
>
>   * "Pseudo" buses are no longer init'd, they are [un]registered by:
>       - pseudo_platform_bus_register(struct bus_type *)
>       - pseudo_platform_bus_unregister(struct bus_type *)
>   * These registrations [de]allocate a dev_pm_ops structure for the
>     pseudo bus_type
>   * Do not overwrite the parent if .bus is already set (that is, allow
>     pseudo bus devices to be root devices)
>
>   * Split into 2 patches:
>       - 1/2: Already sent separately, but included here for clarity
>       - 2/2: The real meat of the patch (this patch)
>
> INTRO
>
> As SOCs become more popular, the desire to quickly define a simple,
> but functional, bus type with only a few unique properties becomes
> desirable. As they become more complicated, the ability to nest these
> simple busses and otherwise orchestrate them to match the actual
> topology also becomes desirable.
>
> Also, as power management becomes more challenging, grouping devices
> on the same SOC under the same /logical bus/ provides a very natural
> interface and location for power-management issues for that SOC.
>
> This is a fairly natural extension of the "platform" bus; ultimately,
> this patch series allows for the creation of multiple platform buses (SOC
> buses), with the correct name and quirks for each of the "platforms" (SOCs)
> they are trying to support.
>
> EXAMPLE USAGE
>
> See follow-on patches implementing the MSM bus and moving the
> MSM uart device / driver onto it.
>
> Change-Id: I10d2fa4671302e81be8f9cac01a3855cef4eeebf
> Cc: Kevin Hilman <khilman@deeprootsystems.com>
> Signed-off-by: Patrick Pannuto <ppannuto@codeaurora.org>
> ---
>  drivers/base/platform.c         |  184 ++++++++++++++++++++------------------
>  include/linux/platform_device.h |   87 ++++++++++++++++++
>  2 files changed, 184 insertions(+), 87 deletions(-)
>
> diff --git a/drivers/base/platform.c b/drivers/base/platform.c
> index b69ccb4..e75640f 100644
> --- a/drivers/base/platform.c
> +++ b/drivers/base/platform.c
> @@ -224,25 +224,10 @@ int platform_device_add_data(struct platform_device *pdev, const void *data,
>  }
>  EXPORT_SYMBOL_GPL(platform_device_add_data);
>
> -/**
> - * platform_device_add - add a platform device to device hierarchy
> - * @pdev: platform device we're adding
> - *
> - * This is part 2 of platform_device_register(), though may be called
> - * separately _iff_ pdev was allocated by platform_device_alloc().
> - */
> -int platform_device_add(struct platform_device *pdev)
> +int __platform_device_add(struct platform_device *pdev)
>  {
>        int i, ret = 0;
>
> -       if (!pdev)
> -               return -EINVAL;
> -
> -       if (!pdev->dev.parent)
> -               pdev->dev.parent = &platform_bus;
> -
> -       pdev->dev.bus = &platform_bus_type;
> -
>        if (pdev->id != -1)
>                dev_set_name(&pdev->dev, "%s.%d", pdev->name,  pdev->id);
>        else
> @@ -289,6 +274,27 @@ int platform_device_add(struct platform_device *pdev)
>
>        return ret;
>  }
> +EXPORT_SYMBOL_GPL(__platform_device_add);
> +
> +/**
> + * platform_device_add - add a platform device to device hierarchy
> + * @pdev: platform device we're adding
> + *
> + * This is part 2 of platform_device_register(), though may be called
> + * separately _iff_ pdev was allocated by platform_device_alloc().
> + */
> +int platform_device_add(struct platform_device *pdev)
> +{
> +       if (!pdev)
> +               return -EINVAL;
> +
> +       if (!pdev->dev.parent)
> +               pdev->dev.parent = &platform_bus;
> +
> +       pdev->dev.bus = &platform_bus_type;
> +
> +       return __platform_device_add(pdev);
> +}
>  EXPORT_SYMBOL_GPL(platform_device_add);
>
>  /**
> @@ -476,13 +482,8 @@ static void platform_drv_shutdown(struct device *_dev)
>        drv->shutdown(dev);
>  }
>
> -/**
> - * platform_driver_register - register a driver for platform-level devices
> - * @drv: platform driver structure
> - */
> -int platform_driver_register(struct platform_driver *drv)
> +int __platform_driver_register(struct platform_driver *drv)
>  {
> -       drv->driver.bus = &platform_bus_type;
>        if (drv->probe)
>                drv->driver.probe = platform_drv_probe;
>        if (drv->remove)
> @@ -492,6 +493,18 @@ int platform_driver_register(struct platform_driver *drv)
>
>        return driver_register(&drv->driver);
>  }
> +EXPORT_SYMBOL_GPL(__platform_driver_register);
> +
> +/**
> + * platform_driver_register - register a driver for platform-level devices
> + * @drv: platform driver structure
> + */
> +int platform_driver_register(struct platform_driver *drv)
> +{
> +       drv->driver.bus = &platform_bus_type;
> +
> +       return __platform_driver_register(drv);
> +}
>  EXPORT_SYMBOL_GPL(platform_driver_register);
>
>  /**
> @@ -504,25 +517,9 @@ void platform_driver_unregister(struct platform_driver *drv)
>  }
>  EXPORT_SYMBOL_GPL(platform_driver_unregister);
>
> -/**
> - * platform_driver_probe - register driver for non-hotpluggable device
> - * @drv: platform driver structure
> - * @probe: the driver probe routine, probably from an __init section
> - *
> - * Use this instead of platform_driver_register() when you know the device
> - * is not hotpluggable and has already been registered, and you want to
> - * remove its run-once probe() infrastructure from memory after the driver
> - * has bound to the device.
> - *
> - * One typical use for this would be with drivers for controllers integrated
> - * into system-on-chip processors, where the controller devices have been
> - * configured as part of board setup.
> - *
> - * Returns zero if the driver registered and bound to a device, else returns
> - * a negative error code and with the driver not registered.
> - */
> -int __init_or_module platform_driver_probe(struct platform_driver *drv,
> -               int (*probe)(struct platform_device *))
> +int __init_or_module __platform_driver_probe(struct platform_driver *drv,
> +               int (*probe)(struct platform_device *),
> +               int (*bustype_driver_register)(struct platform_driver *))

Personally, unless you already have a use-case for using the
platform_driver_probe() hook on the custom busses, I would just leave
this one unimplemented.  It isn't critical (and I don't like it, but
that's a rant for another email).

>  {
>        int retval, code;
>
> @@ -531,7 +528,7 @@ int __init_or_module platform_driver_probe(struct platform_driver *drv,
>
>        /* temporary section violation during probe() */
>        drv->probe = probe;
> -       retval = code = platform_driver_register(drv);
> +       retval = code = bustype_driver_register(drv);
>
>        /*
>         * Fixup that section violation, being paranoid about code scanning
> @@ -550,6 +547,30 @@ int __init_or_module platform_driver_probe(struct platform_driver *drv,
>                platform_driver_unregister(drv);
>        return retval;
>  }
> +EXPORT_SYMBOL_GPL(__platform_driver_probe);
> +
> +/**
> + * platform_driver_probe - register driver for non-hotpluggable device
> + * @drv: platform driver structure
> + * @probe: the driver probe routine, probably from an __init section
> + *
> + * Use this instead of platform_driver_register() when you know the device
> + * is not hotpluggable and has already been registered, and you want to
> + * remove its run-once probe() infrastructure from memory after the driver
> + * has bound to the device.
> + *
> + * One typical use for this would be with drivers for controllers integrated
> + * into system-on-chip processors, where the controller devices have been
> + * configured as part of board setup.
> + *
> + * Returns zero if the driver registered and bound to a device, else returns
> + * a negative error code and with the driver not registered.
> + */
> +int __init_or_module platform_driver_probe(struct platform_driver *drv,
> +               int (*probe)(struct platform_device *))
> +{
> +       return __platform_driver_probe(drv, probe, &platform_driver_register);
> +}
>  EXPORT_SYMBOL_GPL(platform_driver_probe);
>
>  /**
> @@ -627,12 +648,13 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *a,
>        return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len;
>  }
>
> -static struct device_attribute platform_dev_attrs[] = {
> +struct device_attribute platform_dev_attrs[] = {
>        __ATTR_RO(modalias),
>        __ATTR_NULL,
>  };
> +EXPORT_SYMBOL_GPL(platform_dev_attrs);
>
> -static int platform_uevent(struct device *dev, struct kobj_uevent_env *env)
> +int platform_uevent(struct device *dev, struct kobj_uevent_env *env)
>  {
>        struct platform_device  *pdev = to_platform_device(dev);
>
> @@ -640,6 +662,7 @@ static int platform_uevent(struct device *dev, struct kobj_uevent_env *env)
>                (pdev->id_entry) ? pdev->id_entry->name : pdev->name);
>        return 0;
>  }
> +EXPORT_SYMBOL_GPL(platform_uevent);
>
>  static const struct platform_device_id *platform_match_id(
>                        const struct platform_device_id *id,
> @@ -668,7 +691,7 @@ static const struct platform_device_id *platform_match_id(
>  * and compare it against the name of the driver. Return whether they match
>  * or not.
>  */
> -static int platform_match(struct device *dev, struct device_driver *drv)
> +int platform_match(struct device *dev, struct device_driver *drv)
>  {
>        struct platform_device *pdev = to_platform_device(dev);
>        struct platform_driver *pdrv = to_platform_driver(drv);
> @@ -680,10 +703,11 @@ static int platform_match(struct device *dev, struct device_driver *drv)
>        /* fall-back to driver name match */
>        return (strcmp(pdev->name, drv->name) == 0);
>  }
> +EXPORT_SYMBOL_GPL(platform_match);
>
>  #ifdef CONFIG_PM_SLEEP
>
> -static int platform_legacy_suspend(struct device *dev, pm_message_t mesg)
> +int platform_legacy_suspend(struct device *dev, pm_message_t mesg)
>  {
>        struct platform_driver *pdrv = to_platform_driver(dev->driver);
>        struct platform_device *pdev = to_platform_device(dev);
> @@ -695,7 +719,7 @@ static int platform_legacy_suspend(struct device *dev, pm_message_t mesg)
>        return ret;
>  }
>
> -static int platform_legacy_resume(struct device *dev)
> +int platform_legacy_resume(struct device *dev)
>  {
>        struct platform_driver *pdrv = to_platform_driver(dev->driver);
>        struct platform_device *pdev = to_platform_device(dev);
> @@ -707,7 +731,7 @@ static int platform_legacy_resume(struct device *dev)
>        return ret;
>  }
>
> -static int platform_pm_prepare(struct device *dev)
> +int platform_pm_prepare(struct device *dev)
>  {
>        struct device_driver *drv = dev->driver;
>        int ret = 0;
> @@ -717,19 +741,16 @@ static int platform_pm_prepare(struct device *dev)
>
>        return ret;
>  }
> +EXPORT_SYMBOL_GPL(platform_pm_prepare);
>
> -static void platform_pm_complete(struct device *dev)
> +void platform_pm_complete(struct device *dev)
>  {
>        struct device_driver *drv = dev->driver;
>
>        if (drv && drv->pm && drv->pm->complete)
>                drv->pm->complete(dev);
>  }
> -
> -#else /* !CONFIG_PM_SLEEP */
> -
> -#define platform_pm_prepare            NULL
> -#define platform_pm_complete           NULL
> +EXPORT_SYMBOL_GPL(platform_pm_complete);
>
>  #endif /* !CONFIG_PM_SLEEP */
>
> @@ -752,6 +773,7 @@ int __weak platform_pm_suspend(struct device *dev)
>
>        return ret;
>  }
> +EXPORT_SYMBOL_GPL(platform_pm_suspend);
>
>  int __weak platform_pm_suspend_noirq(struct device *dev)
>  {
> @@ -768,6 +790,7 @@ int __weak platform_pm_suspend_noirq(struct device *dev)
>
>        return ret;
>  }
> +EXPORT_SYMBOL_GPL(platform_pm_suspend_noirq);
>
>  int __weak platform_pm_resume(struct device *dev)
>  {
> @@ -786,6 +809,7 @@ int __weak platform_pm_resume(struct device *dev)
>
>        return ret;
>  }
> +EXPORT_SYMBOL_GPL(platform_pm_resume);
>
>  int __weak platform_pm_resume_noirq(struct device *dev)
>  {
> @@ -802,19 +826,13 @@ int __weak platform_pm_resume_noirq(struct device *dev)
>
>        return ret;
>  }
> -
> -#else /* !CONFIG_SUSPEND */
> -
> -#define platform_pm_suspend            NULL
> -#define platform_pm_resume             NULL
> -#define platform_pm_suspend_noirq      NULL
> -#define platform_pm_resume_noirq       NULL
> +EXPORT_SYMBOL_GPL(platform_pm_resume_noirq);
>
>  #endif /* !CONFIG_SUSPEND */
>
>  #ifdef CONFIG_HIBERNATION
>
> -static int platform_pm_freeze(struct device *dev)
> +int platform_pm_freeze(struct device *dev)
>  {
>        struct device_driver *drv = dev->driver;
>        int ret = 0;
> @@ -831,8 +849,9 @@ static int platform_pm_freeze(struct device *dev)
>
>        return ret;
>  }
> +EXPORT_SYMBOL_GPL(platform_pm_freeze);
>
> -static int platform_pm_freeze_noirq(struct device *dev)
> +int platform_pm_freeze_noirq(struct device *dev)
>  {
>        struct device_driver *drv = dev->driver;
>        int ret = 0;
> @@ -847,8 +866,9 @@ static int platform_pm_freeze_noirq(struct device *dev)
>
>        return ret;
>  }
> +EXPORT_SYMBOL_GPL(platform_pm_freeze_noirq);
>
> -static int platform_pm_thaw(struct device *dev)
> +int platform_pm_thaw(struct device *dev)
>  {
>        struct device_driver *drv = dev->driver;
>        int ret = 0;
> @@ -865,8 +885,9 @@ static int platform_pm_thaw(struct device *dev)
>
>        return ret;
>  }
> +EXPORT_SYMBOL_GPL(platform_pm_thaw);
>
> -static int platform_pm_thaw_noirq(struct device *dev)
> +int platform_pm_thaw_noirq(struct device *dev)
>  {
>        struct device_driver *drv = dev->driver;
>        int ret = 0;
> @@ -881,8 +902,9 @@ static int platform_pm_thaw_noirq(struct device *dev)
>
>        return ret;
>  }
> +EXPORT_SYMBOL_GPL(platform_pm_thaw_noirq);
>
> -static int platform_pm_poweroff(struct device *dev)
> +int platform_pm_poweroff(struct device *dev)
>  {
>        struct device_driver *drv = dev->driver;
>        int ret = 0;
> @@ -899,8 +921,9 @@ static int platform_pm_poweroff(struct device *dev)
>
>        return ret;
>  }
> +EXPORT_SYMBOL_GPL(platform_pm_poweroff);
>
> -static int platform_pm_poweroff_noirq(struct device *dev)
> +int platform_pm_poweroff_noirq(struct device *dev)
>  {
>        struct device_driver *drv = dev->driver;
>        int ret = 0;
> @@ -915,8 +938,9 @@ static int platform_pm_poweroff_noirq(struct device *dev)
>
>        return ret;
>  }
> +EXPORT_SYMBOL_GPL(platform_pm_poweroff_noirq);
>
> -static int platform_pm_restore(struct device *dev)
> +int platform_pm_restore(struct device *dev)
>  {
>        struct device_driver *drv = dev->driver;
>        int ret = 0;
> @@ -933,8 +957,9 @@ static int platform_pm_restore(struct device *dev)
>
>        return ret;
>  }
> +EXPORT_SYMBOL_GPL(platform_pm_restore);
>
> -static int platform_pm_restore_noirq(struct device *dev)
> +int platform_pm_restore_noirq(struct device *dev)
>  {
>        struct device_driver *drv = dev->driver;
>        int ret = 0;
> @@ -949,17 +974,7 @@ static int platform_pm_restore_noirq(struct device *dev)
>
>        return ret;
>  }
> -
> -#else /* !CONFIG_HIBERNATION */
> -
> -#define platform_pm_freeze             NULL
> -#define platform_pm_thaw               NULL
> -#define platform_pm_poweroff           NULL
> -#define platform_pm_restore            NULL
> -#define platform_pm_freeze_noirq       NULL
> -#define platform_pm_thaw_noirq         NULL
> -#define platform_pm_poweroff_noirq     NULL
> -#define platform_pm_restore_noirq      NULL
> +EXPORT_SYMBOL_GPL(platform_pm_restore_noirq);
>
>  #endif /* !CONFIG_HIBERNATION */
>
> @@ -980,15 +995,9 @@ int __weak platform_pm_runtime_idle(struct device *dev)
>        return pm_generic_runtime_idle(dev);
>  };
>
> -#else /* !CONFIG_PM_RUNTIME */
> -
> -#define platform_pm_runtime_suspend NULL
> -#define platform_pm_runtime_resume NULL
> -#define platform_pm_runtime_idle NULL
> -
>  #endif /* !CONFIG_PM_RUNTIME */
>
> -static const struct dev_pm_ops platform_dev_pm_ops = {
> +const struct dev_pm_ops platform_dev_pm_ops = {
>        .prepare = platform_pm_prepare,
>        .complete = platform_pm_complete,
>        .suspend = platform_pm_suspend,
> @@ -1007,6 +1016,7 @@ static const struct dev_pm_ops platform_dev_pm_ops = {
>        .runtime_resume = platform_pm_runtime_resume,
>        .runtime_idle = platform_pm_runtime_idle,
>  };
> +EXPORT_SYMBOL_GPL(platform_dev_pm_ops);
>
>  struct bus_type platform_bus_type = {
>        .name           = "platform",
> diff --git a/include/linux/platform_device.h b/include/linux/platform_device.h
> index 5417944..6d7d399 100644
> --- a/include/linux/platform_device.h
> +++ b/include/linux/platform_device.h
> @@ -53,6 +53,7 @@ extern int platform_device_add_resources(struct platform_device *pdev,
>                                         const struct resource *res,
>                                         unsigned int num);
>  extern int platform_device_add_data(struct platform_device *pdev, const void *data, size_t size);
> +extern int __platform_device_add(struct platform_device *pdev);
>  extern int platform_device_add(struct platform_device *pdev);
>  extern void platform_device_del(struct platform_device *pdev);
>  extern void platform_device_put(struct platform_device *pdev);
> @@ -67,12 +68,16 @@ struct platform_driver {
>        const struct platform_device_id *id_table;
>  };
>
> +extern int __platform_driver_register(struct platform_driver *);
>  extern int platform_driver_register(struct platform_driver *);
>  extern void platform_driver_unregister(struct platform_driver *);
>
>  /* non-hotpluggable platform devices may use this so that probe() and
>  * its support may live in __init sections, conserving runtime memory.
>  */
> +extern int __platform_driver_probe(struct platform_driver *driver,
> +               int (*probe)(struct platform_device *),
> +               int (*bustype_driver_register)(struct platform_driver *));
>  extern int platform_driver_probe(struct platform_driver *driver,
>                int (*probe)(struct platform_device *));
>
> @@ -84,6 +89,88 @@ extern struct platform_device *platform_create_bundle(struct platform_driver *dr
>                                        struct resource *res, unsigned int n_res,
>                                        const void *data, size_t size);
>
> +extern struct device_attribute platform_dev_attrs[];
> +extern int platform_uevent(struct device *dev, struct kobj_uevent_env *env);
> +extern int platform_match(struct device *dev, struct device_driver *drv);
> +
> +#ifdef CONFIG_PM_SLEEP
> +extern int platform_pm_prepare(struct device *dev);
> +extern void platform_pm_complete(struct device *dev);
> +#else  /* !CONFIG_PM_SLEEP */
> +#define platform_pm_prepare            NULL
> +#define platform_pm_complete           NULL
> +#endif /* !CONFIG_PM_SLEEP */
> +
> +#ifdef CONFIG_SUSPEND
> +extern int __weak platform_pm_suspend(struct device *dev);
> +extern int __weak platform_pm_suspend_noirq(struct device *dev);
> +extern int __weak platform_pm_resume(struct device *dev);
> +extern int __weak platform_pm_resume_noirq(struct device *dev);
> +#else  /* !CONFIG_SUSPEND */
> +#define platform_pm_suspend            NULL
> +#define platform_pm_resume             NULL
> +#define platform_pm_suspend_noirq      NULL
> +#define platform_pm_resume_noirq       NULL
> +#endif /* !CONFIG_SUSPEND */
> +
> +#ifdef CONFIG_HIBERNATION
> +extern int platform_pm_freeze(struct device *dev);
> +extern int platform_pm_freeze_noirq(struct device *dev);
> +extern int platform_pm_thaw(struct device *dev);
> +extern int platform_pm_thaw_noirq(struct device *dev);
> +extern int platform_pm_poweroff(struct device *dev);
> +extern int platform_pm_poweroff_noirq(struct device *dev);
> +extern int platform_pm_restore(struct device *dev);
> +extern int platform_pm_restore_noirq(struct device *dev);
> +#else  /* !CONFIG_HIBERNATION */
> +#define platform_pm_freeze             NULL
> +#define platform_pm_thaw               NULL
> +#define platform_pm_poweroff           NULL
> +#define platform_pm_restore            NULL
> +#define platform_pm_freeze_noirq       NULL
> +#define platform_pm_thaw_noirq         NULL
> +#define platform_pm_poweroff_noirq     NULL
> +#define platform_pm_restore_noirq      NULL
> +#endif /* !CONFIG_HIBERNATION */
> +
> +#ifdef CONFIG_PM_RUNTIME
> +extern int __weak platform_pm_runtime_suspend(struct device *dev);
> +extern int __weak platform_pm_runtime_resume(struct device *dev);
> +extern int __weak platform_pm_runtime_idle(struct device *dev);
> +#else  /* !CONFIG_PM_RUNTIME */
> +#define platform_pm_runtime_suspend NULL
> +#define platform_pm_runtime_resume NULL
> +#define platform_pm_runtime_idle NULL
> +#endif /* !CONFIG_PM_RUNTIME */
> +
> +extern const struct dev_pm_ops platform_dev_pm_ops;
> +
> +#define PLATFORM_BUS_TEMPLATE \
> +       .name           = "XXX_OVERRIDEME_XXX", \
> +       .dev_attrs      = platform_dev_attrs,   \
> +       .match          = platform_match,       \
> +       .uevent         = platform_uevent,      \
> +       .pm             = &platform_dev_pm_ops
> +
> +#define PLATFORM_PM_OPS_TEMPLATE \
> +       .prepare = platform_pm_prepare,                 \
> +       .complete = platform_pm_complete,               \
> +       .suspend = platform_pm_suspend,                 \
> +       .resume = platform_pm_resume,                   \
> +       .freeze = platform_pm_freeze,                   \
> +       .thaw = platform_pm_thaw,                       \
> +       .poweroff = platform_pm_poweroff,               \
> +       .restore = platform_pm_restore,                 \
> +       .suspend_noirq = platform_pm_suspend_noirq,     \
> +       .resume_noirq = platform_pm_resume_noirq,       \
> +       .freeze_noirq = platform_pm_freeze_noirq,       \
> +       .thaw_noirq = platform_pm_thaw_noirq,           \
> +       .poweroff_noirq = platform_pm_poweroff_noirq,   \
> +       .restore_noirq = platform_pm_restore_noirq,     \
> +       .runtime_suspend = platform_pm_runtime_suspend, \
> +       .runtime_resume = platform_pm_runtime_resume,   \
> +       .runtime_idle = platform_pm_runtime_idle
> +
>  /* early platform driver interface */
>  struct early_platform_driver {
>        const char *class_str;
> --
> 1.7.2.1
>
>



-- 
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.

^ permalink raw reply

* Re: [PATCH 1/5] ptp: Added a brand new class driver for ptp clocks.
From: john stultz @ 2010-08-19  0:12 UTC (permalink / raw)
  To: Richard Cochran
  Cc: netdev, linux-kernel, linuxppc-dev, devicetree-discuss,
	linux-arm-kernel, Krzysztof Halasa, Rodolfo Giometti,
	Arnd Bergmann
In-Reply-To: <20100818071942.GA4096@riccoc20.at.omicron.at>

On Wed, 2010-08-18 at 09:19 +0200, Richard Cochran wrote:
> On Tue, Aug 17, 2010 at 05:22:43PM -0700, john stultz wrote:
>>
> > So while to me, it think it would be more ideal (or maybe just less
> > different) to have a read-only interface (like the RTC), leaving PTPd to
> > manage offset calculations and use that to steer the system time. I can
> > acknowledge the need to have some way to correct the freq so the packet
> > timestamps are corrected.
> 
> The PTPd need not change the system time at all for PTP clock to be
> useful. (see below)

Right, obviously an ok-solution is often more useful then no-solution.
But that doesn't mean we shouldn't shoot for a good or even
great-solution. :)


> > I still feel a little concerned over the timer/alarm related interfaces.
> > Could you explain why the alarm interface is necessary? 
> 
> The timer/alarm stuff is "ancillary" and is not at all necessary. It
> is just a "nice to have." I will happily remove it, if it is too
> troubling for people.

If there's a compelling argument for it, I'm interested to hear. But
again, it seems like just
yet-another-way-to-get-alarm/timer-functionality, so before we add an
extra API (or widen an existing API) I'd like to understand the need.

But maybe it might simplify the discussion to pull it for now, but
keeping it in mind to possibly include later as an extension?

> > So really I think my initial negative gut reaction to this was mostly
> > out of the fact that you introduced a char dev that provides almost 100%
> > coverage of the posix-time interface. That is duplication we definitely
> > don't want. 
> 
> The reason why I modelled the char device on the posix interface was
> to make the API more familiar to application programmers. After the
> recent discussion (and having reviewed the posix clock implementation
> in Linux), I now think it would be even better to simply offer a new
> posic clock ID for PTP.
> 
> I was emulating the posix interface. Instead I should use it directly.

I'm definitely interested to see what you come up with here. I'm still
hesitant with adding a PTP clock_id, but extending the posix-clocks
interface in this way isn't unprecedented (see: CLOCK_SGI_CYCLE) I just
would like to make sure we don't end up with a clock_id namespace
littered with oddball clocks that were not well abstracted (see:
CLOCK_SGI_CYCLE :).

For instance: imagine if instead of keeping the clocksource abstraction
internal to the timekeeping core, we exposed each clocksource to
userland via a clock_id.  Every arch would have different ids, and each
arch might have multiple ids. Programming against that would be a huge
pain.

So in thinking about this, try to focus on what the new clock_id
provides that the other existing clockids do not? Are they at comparable
levels of abstraction? 15 years from now, are folks likely to still be
using it? Will it be maintainable? etc...


> > Also I think the documentation I've read about PTP (likely just due to
> > the engineering focus) has an odd inverted sense of priority, focusing
> > on keeping obscure hardware clocks on NIC cards in sync, rather then the
> > the more tangible feature of keeping the system time in sync.
> > 
> > This could be comically interpreted as trying to create a shadow-time on
> > the system that is the "real time" and "yea, maybe we'll let the system
> > know what time it is, but user-apps who want to know the score can send
> > a magic ioctl to /dev/something and get the real deal". ;)  I'm sure
> > that's not the case, but I'd like to keep any confusion in userland
> > about which time is the best time to a minimum (ie: use the system
> > time).
> 
> You are right. As John Eidson's excellent book points out, modern
> computers and operating systems provide surprisingly little support
> for programming based on absolute time. It is not PTP's fault. PTP is
> actually a step in the right direction, but it doesn't yet really fit
> in to the present computing world.

You'll have to forgive me, as I haven't had the time to check out that
book. What exactly do you mean by operating systems provide little
support for programming based on absolute time?


> Okay, here is the Big Picture.
> 
> 1. Use Case: SW timestamping
> 
>    PTP with software timestamping (ie without special hardware) can
>    acheive synchronization within a few dozen microseconds, after
>    about twenty minutes. This is sufficient for very many people. The
>    new API (whether char device or syscall) fully and simply supports
>    this use case. When the PTPd adjusts the PTP clock, it is actually
>    adjusting the system time, just like NTPd.

Again this illustrates the inversion of focus: system time is merely one
of many possible PTP clocks in the larger PTP framework.

The way I tend to see it: PTP is just one of the many ways to sync
system time.


> 2. Use Case: HW timestamping for industrial control
> 
>    PTP with hardware timestamping can acheive synchronization within
>    100 nanoseconds after one minute. If you want to do something with
>    your wonderfully synchronization PTP clock, it must have some kind
>    of special hardware, like timestamping external signals or
>    generating one-shot or periodic outputs. The new API (whether char
>    device or syscall) supports this use case via the ancillary
>    commands.
> 
>    In this case, the end user has an application that interfaces with
>    the outside world via the PTP clock API. Such a specialized
>    application (for example, motor control) uses only the PTP API,
>    since it knows that the standard posix API cannot help. It is
>    irrelevant that the system time is not synchronized, in this case.
> 
>    The PTP clock hardware may or may not provide a hardware interface
>    (interrupt) to the main CPU. In this case, it does not matter. The
>    PTP clock is useful all by itself.

These specialized applications are part of what concerns me the most. 

For example, I can see some parallels between things like audio
processing, where you have a buffer consumed by the card at a certain
rate. Now, the card has its own crystal it uses to time its consumption,
so it has its own time domain, and could drift from system time. Thus
you want to trigger buffer-refill interrupts off of the audio card's
clock, not the system time which might run the risk of being late.

But again, we don't expose the audio hardware clock to userland in the
same way we expose system time.

So, instead of a chardev or a posix clock id, would it make more sense
for the PTP adjustment interface to be more closely to the
nic/phy/whatever interface?  Much like how the audio apis do it?

Again, my knowledge in the networking stack is pretty limited. But it
would seem that having an interface that does something to the effect of
"adjust the timestamp clock on the hardware that generated it from this
packet by Xppb" would feel like the right level of abstraction. Its
closely related to SO_TIMESTAMP, option right? Would something like
using the setsockopt/getsockopt interface with
SO_TIMESTAMP_ADJUST/OFFSET/SET/etc be reasonable?


> 3. Use Case: HW timestamping with PPS to host
> 
>    This case is the same as case 2, with the exception that the PTP
>    clock can interrupt the main CPU. The PTP clock driver advertises
>    the "PPS" capability. When enabled, the PTP layer delivers events
>    via the existing Linux PPS subsystem. Programs like NTPd can use
>    these events to regulate the system time.
> 
>    This means that the system clock and the PTP clock will be at least
>    as well synchronized as when using a traditionial radio clock, GPS,
>    or IRIG-B method. In my opinion, this will be good enough for any
>    practical purpose. For example, let's say you want to run a
>    periodic task synchronized to the absolute wall clock time. Your
>    scheduling latency will be a dozen microseconds or so. Your PPS
>    synchronized system clock should be close enough to the PTP clock
>    to support this.

And yes, this seems perfectly reasonable feature to add. Its not
controversial to me, because its likely to work within the existing
interfaces and won't expose anything new to userland.


Again, sorry to be such a pain about all of this. I know its frustrating
to bring your hard work to lkml and then get a lot of non-specific
push-back to "do it differently". You're earlier comments about being
wary of adding syscalls because it requires lots of review and debate
were spot on, but *any* user-visible API really requires the same level
of care (which, of course, they don't always get). So please don't take
my comments personally. Keep pushing and I will either come around or
maybe we can find a better middle-ground.

thanks
-john

^ permalink raw reply

* [iproute2 v2] tc: add ACT_CSUM action support (csum)
From: Grégoire Baron @ 2010-08-18 23:58 UTC (permalink / raw)
  To: netdev

tc: add ACT_CSUM action support (csum)

Add the iproute2 support for the ACT_CSUM action. Can be used as
following, certainly in conjunction with the ACT_PEDIT action (pedit):

# In order to DNAT (stateless) IPv4 packet from 192.168.1.100 to
#  0x12345678 (18.52.86.120), and update the IPv4 header checksum and
#  the UDP checksum (the last one, only if the packet is UDP).
tc filter add eth0 prio 1 protocol ip parent ffff: \
  u32 match ip src 192.168.1.100/32 flowid :1 \
    action pedit munge offset 16 u32 set 0x12345678 \
      pipe csum ip and udp

# In order to alter destination address of IPv6 TCP packets from fc00::1
#  and correct the TCP checksum (nothing happened? except maybe for
#  checksums in the TCP payload ...).
tc filter add eth0 prio 1 protocol ipv6 parent ffff: \
  u32 match ip6 src fc00::1/128 match ip6 protocol 0x06 0xff flowid :1 \
    action pedit munge offset 24 u32 set 0x12345678 \
      pipe csum tcp

Version 2 changes:
 - correction in print_csum() (bad statistics print)

Signed-off-by: Gregoire Baron <baronchon@n7mm.org>
---
 include/linux/tc_act/tc_csum.h |   32 +++++
 tc/Makefile                    |    1 +
 tc/m_csum.c                    |  246 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 279 insertions(+), 0 deletions(-)
 create mode 100644 include/linux/tc_act/tc_csum.h
 create mode 100644 tc/m_csum.c

diff --git a/include/linux/tc_act/tc_csum.h b/include/linux/tc_act/tc_csum.h
new file mode 100644
index 0000000..a047c49
--- /dev/null
+++ b/include/linux/tc_act/tc_csum.h
@@ -0,0 +1,32 @@
+#ifndef __LINUX_TC_CSUM_H
+#define __LINUX_TC_CSUM_H
+
+#include <linux/types.h>
+#include <linux/pkt_cls.h>
+
+#define TCA_ACT_CSUM 16
+
+enum {
+	TCA_CSUM_UNSPEC,
+	TCA_CSUM_PARMS,
+	TCA_CSUM_TM,
+	__TCA_CSUM_MAX
+};
+#define TCA_CSUM_MAX (__TCA_CSUM_MAX - 1)
+
+enum {
+	TCA_CSUM_UPDATE_FLAG_IPV4HDR = 1,
+	TCA_CSUM_UPDATE_FLAG_ICMP    = 2,
+	TCA_CSUM_UPDATE_FLAG_IGMP    = 4,
+	TCA_CSUM_UPDATE_FLAG_TCP     = 8,
+	TCA_CSUM_UPDATE_FLAG_UDP     = 16,
+	TCA_CSUM_UPDATE_FLAG_UDPLITE = 32
+};
+
+struct tc_csum {
+	tc_gen;
+
+	__u32 update_flags;
+};
+
+#endif /* __LINUX_TC_CSUM_H */
diff --git a/tc/Makefile b/tc/Makefile
index 3aa9f26..101cc83 100644
--- a/tc/Makefile
+++ b/tc/Makefile
@@ -34,6 +34,7 @@ TCMODULES += m_mirred.o
 TCMODULES += m_nat.o
 TCMODULES += m_pedit.o
 TCMODULES += m_skbedit.o
+TCMODULES += m_csum.o
 TCMODULES += p_ip.o
 TCMODULES += p_icmp.o
 TCMODULES += p_tcp.o
diff --git a/tc/m_csum.c b/tc/m_csum.c
new file mode 100644
index 0000000..d251335
--- /dev/null
+++ b/tc/m_csum.c
@@ -0,0 +1,246 @@
+/*
+ * m_csum.c	checksum updating action
+ *
+ *		This program is free software; you can distribute 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.
+ *
+ * Authors: Gregoire Baron <baronchon@n7mm.org>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <linux/tc_act/tc_csum.h>
+
+#include "utils.h"
+#include "tc_util.h"
+
+static void
+explain(void)
+{
+	fprintf(stderr, "Usage: ... csum <UPDATE>\n"
+			"Where: UPDATE := <TARGET> [<UPDATE>]\n"
+			"       TARGET := { ip4h | icmp | igmp |"
+				" tcp | udp | udplite | <SWEETS> }\n"
+			"       SWEETS := { and | or | \'+\' }\n");
+}
+
+static void
+usage(void)
+{
+	explain();
+	exit(-1);
+}
+
+static int
+parse_csum_args(int *argc_p, char ***argv_p, struct tc_csum *sel)
+{
+	int argc = *argc_p;
+	char **argv = *argv_p;
+
+	if (argc <= 0)
+		return -1;
+
+	while(argc > 0) {
+		if ((matches(*argv, "iph") == 0) ||
+		    (matches(*argv, "ip4h") == 0) ||
+		    (matches(*argv, "ipv4h") == 0))
+			sel->update_flags |= TCA_CSUM_UPDATE_FLAG_IPV4HDR;
+
+		else if (matches(*argv, "icmp") == 0)
+			sel->update_flags |= TCA_CSUM_UPDATE_FLAG_ICMP;
+
+		else if (matches(*argv, "igmp") == 0)
+			sel->update_flags |= TCA_CSUM_UPDATE_FLAG_IGMP;
+
+		else if (matches(*argv, "tcp") == 0)
+			sel->update_flags |= TCA_CSUM_UPDATE_FLAG_TCP;
+
+		else if (matches(*argv, "udp") == 0)
+			sel->update_flags |= TCA_CSUM_UPDATE_FLAG_UDP;
+
+		else if (matches(*argv, "udplite") == 0)
+			sel->update_flags |= TCA_CSUM_UPDATE_FLAG_UDPLITE;
+
+		else if ((matches(*argv, "and") == 0) ||
+			 (matches(*argv, "or") == 0) ||
+			 (matches(*argv, "+") == 0))
+			; /* just ignore: ... csum iph and tcp or udp */
+		else
+			break;
+		argc--;
+		argv++;
+	}
+
+	*argc_p = argc;
+	*argv_p = argv;
+
+	return 0;
+}
+
+static int
+parse_csum(struct action_util *a, int *argc_p,
+	   char ***argv_p, int tca_id, struct nlmsghdr *n)
+{
+	struct tc_csum sel;
+
+	int argc = *argc_p;
+	char **argv = *argv_p;
+	int ok = 0;
+	struct rtattr *tail;
+
+	memset(&sel, 0, sizeof(sel));
+
+	while (argc > 0) {
+		if (matches(*argv, "csum") == 0) {
+			NEXT_ARG();
+			if (parse_csum_args(&argc, &argv, &sel)) {
+				fprintf(stderr, "Illegal csum construct (%s)\n",
+					*argv);
+				explain();
+				return -1;
+			}
+			ok++;
+			continue;
+		} else if (matches(*argv, "help") == 0) {
+			usage();
+		}
+		else {
+			break;
+		}
+	}
+
+	if (!ok) {
+		explain();
+		return -1;
+	}
+
+	if (sel.update_flags == 0) {
+		fprintf(stderr, "Illegal csum construct, empty <UPDATE> list\n");
+		return -1;
+	}
+
+	if (argc) {
+		if (matches(*argv, "reclassify") == 0) {
+			sel.action = TC_ACT_RECLASSIFY;
+			argc--;
+			argv++;
+		} else if (matches(*argv, "pipe") == 0) {
+			sel.action = TC_ACT_PIPE;
+			argc--;
+			argv++;
+		} else if (matches(*argv, "drop") == 0 ||
+			matches(*argv, "shot") == 0) {
+			sel.action = TC_ACT_SHOT;
+			argc--;
+			argv++;
+		} else if (matches(*argv, "continue") == 0) {
+			sel.action = TC_ACT_UNSPEC;
+			argc--;
+			argv++;
+		} else if (matches(*argv, "pass") == 0) {
+			sel.action = TC_ACT_OK;
+			argc--;
+			argv++;
+		}
+	}
+
+	if (argc) {
+		if (matches(*argv, "index") == 0) {
+			NEXT_ARG();
+			if (get_u32(&sel.index, *argv, 10)) {
+				fprintf(stderr, "Illegal \"index\" (%s) <csum>\n",
+					*argv);
+				return -1;
+			}
+			argc--;
+			argv++;
+		}
+	}
+
+	tail = NLMSG_TAIL(n);
+	addattr_l(n, MAX_MSG, tca_id, NULL, 0);
+	addattr_l(n, MAX_MSG, TCA_CSUM_PARMS, &sel, sizeof(sel));
+	tail->rta_len = (char *)NLMSG_TAIL(n) - (char *)tail;
+
+	*argc_p = argc;
+	*argv_p = argv;
+
+	return 0;
+}
+
+static int
+print_csum(struct action_util *au, FILE * f, struct rtattr *arg)
+{
+	struct tc_csum *sel;
+
+	struct rtattr *tb[TCA_CSUM_MAX + 1];
+
+	char *uflag_1 = "";
+	char *uflag_2 = "";
+	char *uflag_3 = "";
+	char *uflag_4 = "";
+	char *uflag_5 = "";
+	char *uflag_6 = "";
+	SPRINT_BUF(action_buf);
+
+	int uflag_count = 0;
+
+	if (arg == NULL)
+		return -1;
+
+	parse_rtattr_nested(tb, TCA_CSUM_MAX, arg);
+
+	if (tb[TCA_CSUM_PARMS] == NULL) {
+		fprintf(f, "[NULL csum parameters]");
+		return -1;
+	}
+	sel = RTA_DATA(tb[TCA_CSUM_PARMS]);
+
+	if (sel->update_flags & TCA_CSUM_UPDATE_FLAG_IPV4HDR) {
+		uflag_1 = "iph";
+		uflag_count++;
+	}
+	#define CSUM_UFLAG_BUFFER(flag_buffer, flag_value, flag_string)	\
+		do {							\
+			if (sel->update_flags & flag_value) {		\
+				flag_buffer = uflag_count > 0 ?		\
+					", " flag_string : flag_string; \
+				uflag_count++;				\
+			}						\
+		} while(0)
+	CSUM_UFLAG_BUFFER(uflag_2, TCA_CSUM_UPDATE_FLAG_ICMP, "icmp");
+	CSUM_UFLAG_BUFFER(uflag_3, TCA_CSUM_UPDATE_FLAG_IGMP, "igmp");
+	CSUM_UFLAG_BUFFER(uflag_4, TCA_CSUM_UPDATE_FLAG_TCP, "tdp");
+	CSUM_UFLAG_BUFFER(uflag_5, TCA_CSUM_UPDATE_FLAG_UDP, "udp");
+	CSUM_UFLAG_BUFFER(uflag_6, TCA_CSUM_UPDATE_FLAG_UDPLITE, "udplite");
+	if (!uflag_count) {
+		uflag_1 = "?empty";
+	}
+
+	fprintf(f, "csum (%s%s%s%s%s%s) action %s\n",
+		uflag_1, uflag_2, uflag_3,
+		uflag_4, uflag_5, uflag_6,
+		action_n2a(sel->action, action_buf, sizeof(action_buf)));
+	fprintf(f, "\tindex %d ref %d bind %d", sel->index, sel->refcnt, sel->bindcnt);
+
+	if (show_stats) {
+		if (tb[TCA_CSUM_TM]) {
+			struct tcf_t *tm = RTA_DATA(tb[TCA_CSUM_TM]);
+			print_tm(f,tm);
+		}
+	}
+	fprintf(f, "\n");
+
+	return 0;
+}
+
+struct action_util csum_action_util = {
+	.id = "csum",
+	.parse_aopt = parse_csum,
+	.print_aopt = print_csum,
+};

^ permalink raw reply related

* Join request for mailing list
From: Raju Dantuluri @ 2010-08-18 23:38 UTC (permalink / raw)
  To: netdev

Hi I'd like to subscribe the mailing list.
Also appreciate on a link on how to contribute in bug fixes.

 Thanks,
Raju



      


^ permalink raw reply

* [PATCH v3] net/sched: add ACT_CSUM action to update packets checksums
From: Grégoire Baron @ 2010-08-18 23:10 UTC (permalink / raw)
  To: netdev; +Cc: jamal

net/sched: add ACT_CSUM action to update packets checksums

ACT_CSUM can be called just after ACT_PEDIT in order to re-compute some
altered checksums in IPv4 and IPv6 packets. The following checksums are
supported by this patch:
 - IPv4: IPv4 header, ICMP, IGMP, TCP, UDP & UDPLite
 - IPv6: ICMPv6, TCP, UDP & UDPLite
It's possible to request in the same action to update different kind of
checksums, if the packets flow mix TCP, UDP and UDPLite, ...

An example of usage is done in the associated iproute2 patch.

Version 3 changes:
 - remove useless goto instructions
 - improve IPv6 hop options decoding

Version 2 changes:
 - coding style correction
 - remove useless arguments of some functions
 - use stack in tcf_csum_dump()
 - add tcf_csum_skb_nextlayer() to factor code

Acked-by: jamal <hadi@cyberus.ca>
Signed-off-by: Gregoire Baron <baronchon@n7mm.org>
---
 include/linux/tc_act/Kbuild    |    1 +
 include/linux/tc_act/tc_csum.h |   32 +++
 include/net/tc_act/tc_csum.h   |   15 +
 net/sched/Kconfig              |   10 +
 net/sched/Makefile             |    1 +
 net/sched/act_csum.c           |  595 ++++++++++++++++++++++++++++++++++++++++
 6 files changed, 654 insertions(+), 0 deletions(-)
 create mode 100644 include/linux/tc_act/tc_csum.h
 create mode 100644 include/net/tc_act/tc_csum.h
 create mode 100644 net/sched/act_csum.c

diff --git a/include/linux/tc_act/Kbuild b/include/linux/tc_act/Kbuild
index 7699093..67b501c 100644
--- a/include/linux/tc_act/Kbuild
+++ b/include/linux/tc_act/Kbuild
@@ -4,3 +4,4 @@ header-y += tc_mirred.h
 header-y += tc_pedit.h
 header-y += tc_nat.h
 header-y += tc_skbedit.h
+header-y += tc_csum.h
diff --git a/include/linux/tc_act/tc_csum.h b/include/linux/tc_act/tc_csum.h
new file mode 100644
index 0000000..a047c49
--- /dev/null
+++ b/include/linux/tc_act/tc_csum.h
@@ -0,0 +1,32 @@
+#ifndef __LINUX_TC_CSUM_H
+#define __LINUX_TC_CSUM_H
+
+#include <linux/types.h>
+#include <linux/pkt_cls.h>
+
+#define TCA_ACT_CSUM 16
+
+enum {
+	TCA_CSUM_UNSPEC,
+	TCA_CSUM_PARMS,
+	TCA_CSUM_TM,
+	__TCA_CSUM_MAX
+};
+#define TCA_CSUM_MAX (__TCA_CSUM_MAX - 1)
+
+enum {
+	TCA_CSUM_UPDATE_FLAG_IPV4HDR = 1,
+	TCA_CSUM_UPDATE_FLAG_ICMP    = 2,
+	TCA_CSUM_UPDATE_FLAG_IGMP    = 4,
+	TCA_CSUM_UPDATE_FLAG_TCP     = 8,
+	TCA_CSUM_UPDATE_FLAG_UDP     = 16,
+	TCA_CSUM_UPDATE_FLAG_UDPLITE = 32
+};
+
+struct tc_csum {
+	tc_gen;
+
+	__u32 update_flags;
+};
+
+#endif /* __LINUX_TC_CSUM_H */
diff --git a/include/net/tc_act/tc_csum.h b/include/net/tc_act/tc_csum.h
new file mode 100644
index 0000000..9e8710b
--- /dev/null
+++ b/include/net/tc_act/tc_csum.h
@@ -0,0 +1,15 @@
+#ifndef __NET_TC_CSUM_H
+#define __NET_TC_CSUM_H
+
+#include <linux/types.h>
+#include <net/act_api.h>
+
+struct tcf_csum {
+	struct tcf_common common;
+
+	u32 update_flags;
+};
+#define to_tcf_csum(pc) \
+	container_of(pc,struct tcf_csum,common)
+
+#endif /* __NET_TC_CSUM_H */
diff --git a/net/sched/Kconfig b/net/sched/Kconfig
index 2f691fb..522d5a9 100644
--- a/net/sched/Kconfig
+++ b/net/sched/Kconfig
@@ -518,6 +518,16 @@ config NET_ACT_SKBEDIT
 	  To compile this code as a module, choose M here: the
 	  module will be called act_skbedit.
 
+config NET_ACT_CSUM
+        tristate "Checksum Updating"
+        depends on NET_CLS_ACT
+        ---help---
+	  Say Y here to update some common checksum after some direct
+	  packet alterations.
+
+	  To compile this code as a module, choose M here: the
+	  module will be called act_csum.
+
 config NET_CLS_IND
 	bool "Incoming device classification"
 	depends on NET_CLS_U32 || NET_CLS_FW
diff --git a/net/sched/Makefile b/net/sched/Makefile
index f14e71b..960f5db 100644
--- a/net/sched/Makefile
+++ b/net/sched/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_NET_ACT_NAT)	+= act_nat.o
 obj-$(CONFIG_NET_ACT_PEDIT)	+= act_pedit.o
 obj-$(CONFIG_NET_ACT_SIMP)	+= act_simple.o
 obj-$(CONFIG_NET_ACT_SKBEDIT)	+= act_skbedit.o
+obj-$(CONFIG_NET_ACT_CSUM)	+= act_csum.o
 obj-$(CONFIG_NET_SCH_FIFO)	+= sch_fifo.o
 obj-$(CONFIG_NET_SCH_CBQ)	+= sch_cbq.o
 obj-$(CONFIG_NET_SCH_HTB)	+= sch_htb.o
diff --git a/net/sched/act_csum.c b/net/sched/act_csum.c
new file mode 100644
index 0000000..58d7f36
--- /dev/null
+++ b/net/sched/act_csum.c
@@ -0,0 +1,595 @@
+/*
+ * Checksum updating actions
+ *
+ * Copyright (c) 2010 Gregoire Baron <baronchon@n7mm.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+
+#include <linux/netlink.h>
+#include <net/netlink.h>
+#include <linux/rtnetlink.h>
+
+#include <linux/skbuff.h>
+
+#include <net/ip.h>
+#include <net/ipv6.h>
+#include <net/icmp.h>
+#include <linux/icmpv6.h>
+#include <linux/igmp.h>
+#include <net/tcp.h>
+#include <net/udp.h>
+
+#include <net/act_api.h>
+
+#include <linux/tc_act/tc_csum.h>
+#include <net/tc_act/tc_csum.h>
+
+#define CSUM_TAB_MASK 15
+static struct tcf_common *tcf_csum_ht[CSUM_TAB_MASK + 1];
+static u32 csum_idx_gen;
+static DEFINE_RWLOCK(csum_lock);
+
+static struct tcf_hashinfo csum_hash_info = {
+	.htab	=	tcf_csum_ht,
+	.hmask	=	CSUM_TAB_MASK,
+	.lock	=	&csum_lock,
+};
+
+static const struct nla_policy csum_policy[TCA_CSUM_MAX + 1] = {
+	[TCA_CSUM_PARMS] = { .len = sizeof(struct tc_csum), },
+};
+
+static int tcf_csum_init(struct nlattr *nla, struct nlattr *est,
+			 struct tc_action *a, int ovr, int bind)
+{
+	struct nlattr *tb[TCA_CSUM_MAX + 1];
+	struct tc_csum *parm;
+	struct tcf_common *pc;
+	struct tcf_csum *p;
+	int ret = 0, err;
+
+	if (nla == NULL)
+		return -EINVAL;
+
+	err = nla_parse_nested(tb, TCA_CSUM_MAX, nla,csum_policy);
+	if (err < 0)
+		return err;
+
+	if (tb[TCA_CSUM_PARMS] == NULL)
+		return -EINVAL;
+	parm = nla_data(tb[TCA_CSUM_PARMS]);
+
+	pc = tcf_hash_check(parm->index, a, bind, &csum_hash_info);
+	if (!pc) {
+		pc = tcf_hash_create(parm->index, est, a, sizeof(*p), bind, &csum_idx_gen, &csum_hash_info);
+		if (IS_ERR(pc))
+			return PTR_ERR(pc);
+		p = to_tcf_csum(pc);
+		ret = ACT_P_CREATED;
+	} else {
+		p = to_tcf_csum(pc);
+		if (!ovr) {
+			tcf_hash_release(pc, bind, &csum_hash_info);
+			return -EEXIST;
+		}
+	}
+
+	spin_lock_bh(&p->tcf_lock);
+	p->tcf_action = parm->action;
+	p->update_flags = parm->update_flags;
+	spin_unlock_bh(&p->tcf_lock);
+
+	if (ret == ACT_P_CREATED)
+		tcf_hash_insert(pc, &csum_hash_info);
+
+	return ret;
+}
+
+static int tcf_csum_cleanup(struct tc_action *a, int bind)
+{
+	struct tcf_csum *p = a->priv;
+	return tcf_hash_release(&p->common, bind, &csum_hash_info);
+}
+
+/**
+ * tcf_csum_skb_nextlayer - Get next layer pointer
+ * @skb: sk_buff to use
+ * @ihl: previous summed headers length
+ * @ipl: complete packet length
+ * @jhl: next header length
+ *
+ * Check the expected next layer availability in the specified sk_buff.
+ * Return the next layer pointer if pass, NULL otherwise.
+ */
+static void *tcf_csum_skb_nextlayer(struct sk_buff *skb,
+				    unsigned int ihl, unsigned int ipl,
+				    unsigned int jhl)
+{
+	int ntkoff = skb_network_offset(skb);
+	int hl = ihl + jhl;
+
+	if (!pskb_may_pull(skb, ipl + ntkoff) || (ipl < hl) ||
+	    (skb_cloned(skb) &&
+	     !skb_clone_writable(skb, hl + ntkoff) &&
+	     pskb_expand_head(skb, 0, 0, GFP_ATOMIC)))
+		return NULL;
+	else
+		return (void *)(skb_network_header(skb) + ihl);
+}
+
+static int tcf_csum_ipv4_icmp(struct sk_buff *skb,
+			      unsigned int ihl, unsigned int ipl)
+{
+	struct icmphdr *icmph;
+
+	icmph = tcf_csum_skb_nextlayer(skb, ihl, ipl, sizeof(*icmph));
+	if (icmph == NULL)
+		return 0;
+
+	icmph->checksum = 0;
+	skb->csum = csum_partial(icmph, ipl - ihl, 0);
+	icmph->checksum = csum_fold(skb->csum);
+
+	skb->ip_summed = CHECKSUM_NONE;
+
+	return 1;
+}
+
+static int tcf_csum_ipv4_igmp(struct sk_buff *skb,
+			      unsigned int ihl, unsigned int ipl)
+{
+	struct igmphdr *igmph;
+
+	igmph = tcf_csum_skb_nextlayer(skb, ihl, ipl, sizeof(*igmph));
+	if (igmph == NULL)
+		return 0;
+
+	igmph->csum = 0;
+	skb->csum = csum_partial(igmph, ipl - ihl, 0);
+	igmph->csum = csum_fold(skb->csum);
+
+	skb->ip_summed = CHECKSUM_NONE;
+
+	return 1;
+}
+
+static int tcf_csum_ipv6_icmp(struct sk_buff *skb, struct ipv6hdr *ip6h,
+			      unsigned int ihl, unsigned int ipl)
+{
+	struct icmp6hdr *icmp6h;
+
+	icmp6h = tcf_csum_skb_nextlayer(skb, ihl, ipl, sizeof(*icmp6h));
+	if (icmp6h == NULL)
+		return 0;
+
+	icmp6h->icmp6_cksum = 0;
+	skb->csum = csum_partial(icmp6h, ipl - ihl, 0);
+	icmp6h->icmp6_cksum = csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr,
+					      ipl - ihl, IPPROTO_ICMPV6,
+					      skb->csum);
+
+	skb->ip_summed = CHECKSUM_NONE;
+
+	return 1;
+}
+
+static int tcf_csum_ipv4_tcp(struct sk_buff *skb, struct iphdr *iph,
+			     unsigned int ihl, unsigned int ipl)
+{
+	struct tcphdr *tcph;
+
+	tcph = tcf_csum_skb_nextlayer(skb, ihl, ipl, sizeof(*tcph));
+	if (tcph == NULL)
+		return 0;
+
+	tcph->check = 0;
+	skb->csum = csum_partial(tcph, ipl - ihl, 0);
+	tcph->check = tcp_v4_check(ipl - ihl,
+				   iph->saddr, iph->daddr, skb->csum);
+
+	skb->ip_summed = CHECKSUM_NONE;
+
+	return 1;
+}
+
+static int tcf_csum_ipv6_tcp(struct sk_buff *skb, struct ipv6hdr *ip6h,
+			     unsigned int ihl, unsigned int ipl)
+{
+	struct tcphdr *tcph;
+
+	tcph = tcf_csum_skb_nextlayer(skb, ihl, ipl, sizeof(*tcph));
+	if (tcph == NULL)
+		return 0;
+
+	tcph->check = 0;
+	skb->csum = csum_partial(tcph, ipl - ihl, 0);
+	tcph->check = csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr,
+				      ipl - ihl, IPPROTO_TCP,
+				      skb->csum);
+
+	skb->ip_summed = CHECKSUM_NONE;
+
+	return 1;
+}
+
+static int tcf_csum_ipv4_udp(struct sk_buff *skb, struct iphdr *iph,
+			     unsigned int ihl, unsigned int ipl, int udplite)
+{
+	struct udphdr *udph;
+	u16 ul;
+
+	/* Support both UDP and UDPLITE checksum algorithms,
+	 * Don't use udph->len to get the real length without any protocol check,
+	 * UDPLITE uses udph->len for another thing,
+	 * Use iph->tot_len, or just ipl.
+	 */
+
+	udph = tcf_csum_skb_nextlayer(skb, ihl, ipl, sizeof(*udph));
+	if (udph == NULL)
+		return 0;
+
+	ul = ntohs(udph->len);
+
+	if (udplite || udph->check) {
+
+		udph->check = 0;
+
+		if (udplite) {
+			if (ul == 0)
+				skb->csum = csum_partial(udph, ipl - ihl, 0);
+
+			else if ((ul >= sizeof(*udph)) && (ul <= ipl - ihl))
+				skb->csum = csum_partial(udph, ul, 0);
+
+			else
+				goto ignore_obscure_skb;
+		} else {
+			if (ul != ipl - ihl)
+				goto ignore_obscure_skb;
+
+			skb->csum = csum_partial(udph, ul, 0);
+		}
+
+		udph->check = csum_tcpudp_magic(iph->saddr, iph->daddr,
+						ul, iph->protocol,
+						skb->csum);
+
+		if (!udph->check)
+			udph->check = CSUM_MANGLED_0;
+	}
+
+	skb->ip_summed = CHECKSUM_NONE;
+
+ignore_obscure_skb:
+	return 1;
+}
+
+static int tcf_csum_ipv6_udp(struct sk_buff *skb, struct ipv6hdr *ip6h,
+			     unsigned int ihl, unsigned int ipl, int udplite)
+{
+	struct udphdr *udph;
+	u16 ul;
+
+	/* Support both UDP and UDPLITE checksum algorithms,
+	 * Don't use udph->len to get the real length without any protocol check,
+	 * UDPLITE uses udph->len for another thing,
+	 * Use ip6h->payload_len + sizeof(*ip6h) ... , or just ipl.
+	 */
+
+	udph = tcf_csum_skb_nextlayer(skb, ihl, ipl, sizeof(*udph));
+	if (udph == NULL)
+		return 0;
+
+	ul = ntohs(udph->len);
+
+	udph->check = 0;
+
+	if (udplite) {
+		if (ul == 0)
+			skb->csum = csum_partial(udph, ipl - ihl, 0);
+
+		else if ((ul >= sizeof(*udph)) && (ul <= ipl - ihl))
+			skb->csum = csum_partial(udph, ul, 0);
+
+		else
+			goto ignore_obscure_skb;
+	} else {
+		if (ul != ipl - ihl)
+			goto ignore_obscure_skb;
+
+		skb->csum = csum_partial(udph, ul, 0);
+	}
+
+	udph->check = csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr, ul,
+				      udplite ? IPPROTO_UDPLITE : IPPROTO_UDP,
+				      skb->csum);
+
+	if (!udph->check)
+		udph->check = CSUM_MANGLED_0;
+
+	skb->ip_summed = CHECKSUM_NONE;
+
+ignore_obscure_skb:
+	return 1;
+}
+
+static int tcf_csum_ipv4(struct sk_buff *skb, u32 update_flags)
+{
+	struct iphdr *iph;
+	int ntkoff;
+
+	ntkoff = skb_network_offset(skb);
+
+	if (!pskb_may_pull(skb, sizeof(*iph) + ntkoff))
+		goto fail;
+
+	iph = ip_hdr(skb);
+
+	switch (iph->frag_off & htons(IP_OFFSET) ? 0 : iph->protocol) {
+	case IPPROTO_ICMP:
+		if (update_flags & TCA_CSUM_UPDATE_FLAG_ICMP)
+			if (!tcf_csum_ipv4_icmp(skb,
+						iph->ihl * 4, ntohs(iph->tot_len)))
+				goto fail;
+		break;
+	case IPPROTO_IGMP:
+		if (update_flags & TCA_CSUM_UPDATE_FLAG_IGMP)
+			if (!tcf_csum_ipv4_igmp(skb,
+						iph->ihl * 4, ntohs(iph->tot_len)))
+				goto fail;
+		break;
+	case IPPROTO_TCP:
+		if (update_flags & TCA_CSUM_UPDATE_FLAG_TCP)
+			if (!tcf_csum_ipv4_tcp(skb, iph,
+					       iph->ihl * 4, ntohs(iph->tot_len)))
+				goto fail;
+		break;
+	case IPPROTO_UDP:
+		if (update_flags & TCA_CSUM_UPDATE_FLAG_UDP)
+			if (!tcf_csum_ipv4_udp(skb, iph,
+					       iph->ihl * 4, ntohs(iph->tot_len), 0))
+				goto fail;
+		break;
+	case IPPROTO_UDPLITE:
+		if (update_flags & TCA_CSUM_UPDATE_FLAG_UDPLITE)
+			if (!tcf_csum_ipv4_udp(skb, iph,
+					       iph->ihl * 4, ntohs(iph->tot_len), 1))
+				goto fail;
+		break;
+	}
+
+	if (update_flags & TCA_CSUM_UPDATE_FLAG_IPV4HDR) {
+		if (skb_cloned(skb) &&
+		    !skb_clone_writable(skb, sizeof(*iph) + ntkoff) &&
+		    pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
+			goto fail;
+
+		ip_send_check(iph);
+	}
+
+	return 1;
+
+fail:
+	return 0;
+}
+
+static int tcf_csum_ipv6_hopopts(struct ipv6_opt_hdr *ip6xh,
+				  unsigned int ixhl, unsigned int *pl)
+{
+	int off, len, optlen;
+	unsigned char *xh = (void *)ip6xh;
+
+	off = sizeof(*ip6xh);
+	len = ixhl - off;
+
+	while (len > 1) {
+		switch (xh[off])
+		{
+		case IPV6_TLV_PAD0:
+			optlen = 1;
+			break;
+		case IPV6_TLV_JUMBO:
+			optlen = xh[off + 1] + 2;
+			if (optlen != 6 || len < 6 || (off & 3) != 2)
+				/* wrong jumbo option length/alignment */
+				return 0;
+			*pl = ntohl(*(__be32 *)(xh + off + 2));
+			goto done;
+		default:
+			optlen = xh[off + 1] + 2;
+			if (optlen > len)
+				/* ignore obscure options */
+				goto done;
+			break;
+		}
+		off += optlen;
+		len -= optlen;
+	}
+
+done:
+	return 1;
+}
+
+static int tcf_csum_ipv6(struct sk_buff *skb, u32 update_flags)
+{
+	struct ipv6hdr *ip6h;
+	struct ipv6_opt_hdr *ip6xh;
+	unsigned int hl, ixhl;
+	unsigned int pl;
+	int ntkoff;
+	u8 nexthdr;
+
+	ntkoff = skb_network_offset(skb);
+
+	hl = sizeof(*ip6h);
+
+	if (!pskb_may_pull(skb, hl + ntkoff))
+		goto fail;
+
+	ip6h = ipv6_hdr(skb);
+
+	pl = ntohs(ip6h->payload_len);
+	nexthdr = ip6h->nexthdr;
+
+	do {
+		switch (nexthdr) {
+		case NEXTHDR_FRAGMENT:
+			goto ignore_skb;
+		case NEXTHDR_ROUTING:
+		case NEXTHDR_HOP:
+		case NEXTHDR_DEST:
+			if (!pskb_may_pull(skb, hl + sizeof(*ip6xh) + ntkoff))
+				goto fail;
+			ip6xh = (void *)(skb_network_header(skb) + hl);
+			ixhl = ipv6_optlen(ip6xh);
+			if (!pskb_may_pull(skb, hl + ixhl + ntkoff))
+				goto fail;
+			if ((nexthdr == NEXTHDR_HOP) &&
+			    !(tcf_csum_ipv6_hopopts(ip6xh, ixhl, &pl)))
+				goto fail;
+			nexthdr = ip6xh->nexthdr;
+			hl += ixhl;
+			break;
+		case IPPROTO_ICMPV6:
+			if (update_flags & TCA_CSUM_UPDATE_FLAG_ICMP)
+				if (!tcf_csum_ipv6_icmp(skb, ip6h,
+							hl, pl + sizeof(*ip6h)))
+					goto fail;
+			goto done;
+		case IPPROTO_TCP:
+			if (update_flags & TCA_CSUM_UPDATE_FLAG_TCP)
+				if (!tcf_csum_ipv6_tcp(skb, ip6h,
+						       hl, pl + sizeof(*ip6h)))
+					goto fail;
+			goto done;
+		case IPPROTO_UDP:
+			if (update_flags & TCA_CSUM_UPDATE_FLAG_UDP)
+				if (!tcf_csum_ipv6_udp(skb, ip6h,
+						       hl, pl + sizeof(*ip6h), 0))
+					goto fail;
+			goto done;
+		case IPPROTO_UDPLITE:
+			if (update_flags & TCA_CSUM_UPDATE_FLAG_UDPLITE)
+				if (!tcf_csum_ipv6_udp(skb, ip6h,
+						       hl, pl + sizeof(*ip6h), 1))
+					goto fail;
+			goto done;
+		default:
+			goto ignore_skb;
+		}
+	} while (pskb_may_pull(skb, hl + 1 + ntkoff));
+
+done:
+ignore_skb:
+	return 1;
+
+fail:
+	return 0;
+}
+
+static int tcf_csum(struct sk_buff *skb,
+		    struct tc_action *a, struct tcf_result *res)
+{
+	struct tcf_csum *p = a->priv;
+	int action;
+	u32 update_flags;
+
+	spin_lock(&p->tcf_lock);
+	p->tcf_tm.lastuse = jiffies;
+	p->tcf_bstats.bytes += qdisc_pkt_len(skb);
+	p->tcf_bstats.packets++;
+	action = p->tcf_action;
+	update_flags = p->update_flags;
+	spin_unlock(&p->tcf_lock);
+
+	if (unlikely(action == TC_ACT_SHOT))
+		goto drop;
+
+	switch (skb->protocol) {
+	case cpu_to_be16(ETH_P_IP):
+		if (!tcf_csum_ipv4(skb, update_flags))
+			goto drop;
+		break;
+	case cpu_to_be16(ETH_P_IPV6):
+		if (!tcf_csum_ipv6(skb, update_flags))
+			goto drop;
+		break;
+	}
+
+	return action;
+
+drop:
+	spin_lock(&p->tcf_lock);
+	p->tcf_qstats.drops++;
+	spin_unlock(&p->tcf_lock);
+	return TC_ACT_SHOT;
+}
+
+static int tcf_csum_dump(struct sk_buff *skb,
+			 struct tc_action *a, int bind, int ref)
+{
+	unsigned char *b = skb_tail_pointer(skb);
+	struct tcf_csum *p = a->priv;
+	struct tc_csum opt = {
+		.update_flags = p->update_flags,
+
+		.index   = p->tcf_index,
+		.action  = p->tcf_action,
+		.refcnt  = p->tcf_refcnt - ref,
+		.bindcnt = p->tcf_bindcnt - bind,
+	};
+	struct tcf_t t;
+
+	NLA_PUT(skb, TCA_CSUM_PARMS, sizeof(opt), &opt);
+	t.install = jiffies_to_clock_t(jiffies - p->tcf_tm.install);
+	t.lastuse = jiffies_to_clock_t(jiffies - p->tcf_tm.lastuse);
+	t.expires = jiffies_to_clock_t(p->tcf_tm.expires);
+	NLA_PUT(skb, TCA_CSUM_TM, sizeof(t), &t);
+
+	return skb->len;
+
+nla_put_failure:
+	nlmsg_trim(skb, b);
+	return -1;
+}
+
+static struct tc_action_ops act_csum_ops = {
+	.kind		=	"csum",
+	.hinfo		=	&csum_hash_info,
+	.type		=	TCA_ACT_CSUM,
+	.capab		=	TCA_CAP_NONE,
+	.owner		=	THIS_MODULE,
+	.act		=	tcf_csum,
+	.dump		=	tcf_csum_dump,
+	.cleanup	=	tcf_csum_cleanup,
+	.lookup		=	tcf_hash_search,
+	.init		=	tcf_csum_init,
+	.walk		=	tcf_generic_walker
+};
+
+MODULE_DESCRIPTION("Checksum updating actions");
+MODULE_LICENSE("GPL");
+
+static int __init csum_init_module(void)
+{
+	return tcf_register_action(&act_csum_ops);
+}
+
+static void __exit csum_cleanup_module(void)
+{
+	tcf_unregister_action(&act_csum_ops);
+}
+
+module_init(csum_init_module);
+module_exit(csum_cleanup_module);
-- 
1.7.1


^ permalink raw reply related

* Re: [PATCH net-next-2.6] vxge: Implement 64bit stats
From: Jon Mason @ 2010-08-18 22:53 UTC (permalink / raw)
  To: Eric Dumazet
  Cc: David Miller, netdev, Ramkrishna Vepa, Sivakumar Subramani,
	Sreenivasa Honnur
In-Reply-To: <1282138974.2194.83.camel@edumazet-laptop>

On Wed, Aug 18, 2010 at 06:42:54AM -0700, Eric Dumazet wrote:
> vxge_get_stats() is racy, since it clears a block of memory (net_stats)
> possibly still used by other cpus.
> 
> We can update this driver to full 64bit stats, since ndo_get_stats64()
> provides a private block to store results, and driver maintains 64bit
> counters already.
> 
> We also remove net_stats field from struct vxge_sw_stats
> 
> Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
Acked-by: Jon Mason <jon.mason@exar.com>
> ---
>  drivers/net/vxge/vxge-main.c |   22 +++++++---------------
>  drivers/net/vxge/vxge-main.h |    1 -
>  2 files changed, 7 insertions(+), 16 deletions(-)
> 
> diff --git a/drivers/net/vxge/vxge-main.c b/drivers/net/vxge/vxge-main.c
> index c7c5605..ac90196 100644
> --- a/drivers/net/vxge/vxge-main.c
> +++ b/drivers/net/vxge/vxge-main.c
> @@ -2914,26 +2914,18 @@ static int vxge_change_mtu(struct net_device *dev, int new_mtu)
>  }
>  
>  /**
> - * vxge_get_stats
> + * vxge_get_stats64
>   * @dev: pointer to the device structure
> + * @stats: pointer to struct rtnl_link_stats64
>   *
> - * Updates the device statistics structure. This function updates the device
> - * statistics structure in the net_device structure and returns a pointer
> - * to the same.
>   */
> -static struct net_device_stats *
> -vxge_get_stats(struct net_device *dev)
> +static struct rtnl_link_stats64 *
> +vxge_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *net_stats)
>  {
> -	struct vxgedev *vdev;
> -	struct net_device_stats *net_stats;
> +	struct vxgedev *vdev = netdev_priv(dev);
>  	int k;
>  
> -	vdev = netdev_priv(dev);
> -
> -	net_stats = &vdev->stats.net_stats;
> -
> -	memset(net_stats, 0, sizeof(struct net_device_stats));
> -
> +	/* net_stats already zeroed by caller */
>  	for (k = 0; k < vdev->no_of_vpath; k++) {
>  		net_stats->rx_packets += vdev->vpaths[k].ring.stats.rx_frms;
>  		net_stats->rx_bytes += vdev->vpaths[k].ring.stats.rx_bytes;
> @@ -3102,7 +3094,7 @@ vxge_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
>  static const struct net_device_ops vxge_netdev_ops = {
>  	.ndo_open               = vxge_open,
>  	.ndo_stop               = vxge_close,
> -	.ndo_get_stats          = vxge_get_stats,
> +	.ndo_get_stats64        = vxge_get_stats64,
>  	.ndo_start_xmit         = vxge_xmit,
>  	.ndo_validate_addr      = eth_validate_addr,
>  	.ndo_set_multicast_list = vxge_set_multicast,
> diff --git a/drivers/net/vxge/vxge-main.h b/drivers/net/vxge/vxge-main.h
> index 2e3b064..d4be07e 100644
> --- a/drivers/net/vxge/vxge-main.h
> +++ b/drivers/net/vxge/vxge-main.h
> @@ -172,7 +172,6 @@ struct vxge_msix_entry {
>  
>  struct vxge_sw_stats {
>  	/* Network Stats (interface stats) */
> -	struct net_device_stats net_stats;
>  
>  	/* Tx */
>  	u64 tx_frms;
> 
> 

^ permalink raw reply

* Re: Broadcom 5709 take long time to bring up
From: Ben Hutchings @ 2010-08-18 22:19 UTC (permalink / raw)
  To: Rick Jones
  Cc: Mitchell Erblich, Benjamin Li, Joe Jin, Michael Chan,
	terry.liu@oracle.com, netdev@vger.kernel.org
In-Reply-To: <4C6C4FE5.20509@hp.com>

On Wed, 2010-08-18 at 14:25 -0700, Rick Jones wrote:
> Mitchell Erblich wrote:
> > On Aug 18, 2010, at 9:08 AM, Benjamin Li wrote:
> > 
> > 
> >>Hi Joe,
> >>
> >>Just a couple of quick questions:
> >>
> >>1.  It is possible that autonegotiation could take in the orders of
> >>seconds depending on the remote partner.   
> > 
> > 
> > No. It happens in ms.
> > 
> > Mitchell Erblich
> 
> Both may be correct, depending on the context.  The IEEE specs likely mandate 
> that autonegotiation take no longer than N ms, but there may indeed be kit out 
> there that takes rather longer...

Autonegotiation per se should not take very long, but 1000BASE-T or
10GBASE-T also require the PHYs to sync clocks, detect and cancel
echoes, and so on.  I believe that that link training normally takes a
few seconds after AN is done.

Ben.

-- 
Ben Hutchings, Senior Software Engineer, Solarflare Communications
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.


^ permalink raw reply

* Re: GTSM and TCP accept problem
From: David Miller @ 2010-08-18 21:48 UTC (permalink / raw)
  To: shemminger; +Cc: eric.dumazet, herbert, netdev
In-Reply-To: <20100818143913.1478acea@nehalam>

From: Stephen Hemminger <shemminger@vyatta.com>
Date: Wed, 18 Aug 2010 14:39:13 -0700

> On Mon, 16 Aug 2010 11:43:45 +0200
> Eric Dumazet <eric.dumazet@gmail.com> wrote:
> 
>> Another idea would be to store the TTL of the SYN packet (or third
>> packet) and let application read it after accept(), allowing it to
>> reject the connection if it doesnt match expected TTL.
> 
> could be in tcp_info?

I'm sure we can squeeze a byte out of there :-)

^ permalink raw reply

* Re: [PATCH] Add firmware label support to iproute2
From: Stephen Hemminger @ 2010-08-18 21:41 UTC (permalink / raw)
  To: Narendra_K; +Cc: netdev, Matt_Domsch, Charles_Rose, Jordan_Hargrave
In-Reply-To: <EDA0A4495861324DA2618B4C45DCB3EE612E34@blrx3m08.blr.amer.dell.com>

On Fri, 13 Aug 2010 18:06:26 +0530
<Narendra_K@Dell.com> wrote:

> > -----Original Message-----
> > From: Stephen Hemminger [mailto:shemminger@vyatta.com]
> > Sent: Thursday, August 12, 2010 11:43 PM
> > To: K, Narendra
> > Cc: netdev@vger.kernel.org; Domsch, Matt; Rose, Charles; Hargrave,
> > Jordan
> > Subject: Re: [PATCH] Add firmware label support to iproute2
> > 
> > On Thu, 12 Aug 2010 12:35:37 -0500
> > Narendra K <Narendra_K@dell.com> wrote:
> > 
> > > +#ifndef LIBNETDEVNAME_PRESENT
> > >  			filter_dev = *argv;
> > > +#else
> > > +			if (netdev_alias_to_kernelname(*argv,
> kernel_name) <
> > 0)
> > > +				show_firmware_alias_usage(*argv);
> > > +			filter_dev = kernel_name;
> > > +#endif
> > >  		}
> > 
> > like the kernel, I don't like ifdef cases in main code.
> > You should put in stub inline that returns appropriate error.
> > 
> 
> Stephen,
> 
> Thanks for the suggestions. I will rework the patch and send a revised
> version soon.
> 
> > What happens if alias matches existing interface name?
> 
> If the user inputs an existing 'ethN' name, the function
> 'netdev_alias_to_kernelaname' will return it as it is. If the user
> inputs 'Embedded NIC N', then the function would do a sysfs lookup and
> return the corresponding 'ethN' name.

The netdev_alias_to_kernelname should only happen after normal lookup failed.
Also how does ifindex to name mapping work?

-- 

^ 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