Netdev List
 help / color / mirror / Atom feed
* Re: [PATCH] net/ipv6/sit.c: return unhandled skb to tunnel4_rcv
From: Eric Dumazet @ 2010-11-30  6:12 UTC (permalink / raw)
  To: David McCullough; +Cc: netdev
In-Reply-To: <20101130053234.GA28609@mcafee.com>

Le mardi 30 novembre 2010 à 15:32 +1000, David McCullough a écrit :
> Hi all,
> 
> I found a problem using an IPv6 over IPv4 tunnel.  When CONFIG_IPV6_SIT
> was enabled, the packets would be rejected as net/ipv6/sit.c was catching
> all IPPROTO_IPV6 packets and returning an ICMP port unreachable error.
> 
> I think this patch fixes the problem cleanly.  I believe the code in
> net/ipv4/tunnel4.c:tunnel4_rcv takes care of it properly if none of the
> handlers claim the skb.
> 
> Patch is against 2.6.35,  bit still applies to current.
> 
> Cheers,
> Davidm
> 
> Signed-off-by: David McCullough <david_mccullough@mcafee.com>
> 
> diff -u -r1.1.1.45 sit.c
> --- a/net/ipv6/sit.c	12 Aug 2010 00:16:26 -0000	1.1.1.45
> +++ b/net/ipv6/sit.c	30 Nov 2010 05:01:19 -0000
> @@ -575,8 +575,9 @@
>  		return 0;
>  	}
>  
> -	icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
> +	/* no tunnel matched,  let upstream know, ipsec may handle it */
>  	rcu_read_unlock();
> +	return 1;
>  out:
>  	kfree_skb(skb);
>  	return 0;
> 

Good catch !

Acked-by: Eric Dumazet <eric.dumazet@gmail.com>




^ permalink raw reply

* Re: [PATCH 1/3] inetpeer: Support ipv6 addresses.
From: David Miller @ 2010-11-30  6:31 UTC (permalink / raw)
  To: eric.dumazet; +Cc: xiaosuo, netdev
In-Reply-To: <1291097479.2725.13.camel@edumazet-laptop>

From: Eric Dumazet <eric.dumazet@gmail.com>
Date: Tue, 30 Nov 2010 07:11:19 +0100

> Le lundi 29 novembre 2010 à 21:53 -0800, David Miller a écrit :
>> From: Eric Dumazet <eric.dumazet@gmail.com>
>> Date: Tue, 30 Nov 2010 06:42:16 +0100
>> 
>> > Its a bit early in the morning here, I must confess I dont yet
>> > understand your patch David :)
>> > 
>> > As we use a tree, why not using two different trees for ipv4 / ipv6 ?
>> 
>> The "key" just creates a natural ordering in the tree, it's
>> almost arbitrary except that it must distribute well amongst
>> the entries.
> 
> Hmm. AVL search must take a decision, take the left or the right path.
> 
> if current key is equal, which path do you take ?

Right. :-)  But yes there is some error that needs to
be handled in that equal keys can lead to imporper paths
as you showed.

I guess I do need to make a seperate tree, how disappointing.

Anyways I will work on fixing this.

> Do you know how to make an estimation on a server ?

No way to do it straightforward I guess because right now TCP metrics
key on all sorts of rediculious things like source address, TOS, and
other crap as a consequence of how the routing cache works.

So much replicated information and wasted memory.


^ permalink raw reply

* RE: [PATCH] net/r8169: Correct the ram code for RTL8111D(L)
From: hayeswang @ 2010-11-30  6:37 UTC (permalink / raw)
  To: 'Stephen Hemminger', 'Francois Romieu'
  Cc: 'Ben Hutchings', netdev, linux-kernel,
	'David Miller', 564628
In-Reply-To: <20101129161344.059239d6@nehalam>

Hi Romieu,

Let me explain that not all of the phy settings are the ram code (or firmware).
Some of them are the initialization sequence. Only the "Low pass filter &
DLY_CAP fine tune from uC" is the firmware. And there is no firmware before
RTL8111D. That is, except 8111DP, the chips which have firmware are 8111d,
8111e,and 8105 now.

Now, I would modify my patch according to the example from Ben. And I would
update the firmware and licence to linux-firmware.

Thanks for everybody who help and answer to me.
 
Best Regards,
Hayes


> -----Original Message-----
> From: Stephen Hemminger [mailto:shemminger@vyatta.com] 
> Sent: Tuesday, November 30, 2010 8:14 AM
> To: Francois Romieu
> Cc: Hayeswang; 'Ben Hutchings'; netdev@vger.kernel.org; 
> linux-kernel@vger.kernel.org; 'David Miller'; 564628@bugs.debian.org
> Subject: Re: [PATCH] net/r8169: Correct the ram code for RTL8111D(L)
> 
> On Tue, 30 Nov 2010 00:33:34 +0100
> Francois Romieu <romieu@fr.zoreil.com> wrote:
> 
> > hayeswang <hayeswang@realtek.com> :
> > > Excuse me, I have some questions about the firmware patch.
> > > 
> > > 1. I should convert the data into the binary files 
> (.bin). Is it right?
> > 
> > You may do it.
> > 
> > Fwiw I have cooked something for it in the attached patch 
> #9 this WE. 
> > Feel free to take bits from it. I will not do more changes 
> while you work on it.
> > 
> > > 2. Where should I update the firmware files? Is the path the 
> > > linux-2.6/firmware?
> > 
> > ! This directory is only here to contain firmware images extracted 
> > from old ! device drivers which predate the common use of 
> request_firmware().
> > 
> > It is fine for the existing code.
> > 
> > > However, according to 
> linux-2.6/firmeware/README.AddingFirmware, I 
> > > should update they to another repository:
> > > 	
> > > 
> git://git.kernel.org/pub/scm/linux/kernel/git/dwmw2/linux-firmware.g
> > > it
> > 
> > /me scratches head.
> > 
> > Assuming Realtek does not intend to stand this code / data 
> as GPLable, yes.
> > It will help people staying clear from non-free code, it will help 
> > packaging something useful and it will remove some cruft 
> from the code.
> > 
> > So everybody will end happy. Especially after an aspirin.
> 
> The plan is to do away with linux-2.6/firmware entirely.
> Distributions are shipping the firmware from linux-firmware, 
> not the kernel files.
> 
> 
> ------Please consider the environment before printing this e-mail. 
> 
> 

^ permalink raw reply

* Re: [PATCH v2] net: avoid the unnecessary kmalloc
From: Eric Dumazet @ 2010-11-30  6:52 UTC (permalink / raw)
  To: Changli Gao; +Cc: David S. Miller, netdev
In-Reply-To: <1291077629-6339-1-git-send-email-xiaosuo@gmail.com>

Le mardi 30 novembre 2010 à 08:40 +0800, Changli Gao a écrit :
> If the old memory allocated by kmalloc() is larger than the new requested,
> pskb_expand_head() doesn't need to allocate a new one, unless the skb->head
> is shared.
> 
> Signed-off-by: Changli Gao <xiaosuo@gmail.com>

Seems fine to me, but patch title and changelog are a bit uninformative.


skb head being allocated by kmalloc(), it might be larger than what
actually requested because of discrete kmem caches sizes. Before
reallocating a new skb head, check if the current one has the needed
extra size.

Do this check only if skb head is not shared.



> +
> +	if (fastpath &&
> +	    size + sizeof(struct skb_shared_info) <= ksize(skb->head)) {
> +		memmove(skb->head + size, skb_shinfo(skb),
> +			offsetof(struct skb_shared_info,
> +				 frags[skb_shinfo(skb)->nr_frags]));
> +		memmove(skb->head + nhead, skb->head,
> +			skb_tail_pointer(skb) - skb->head);
> +		off = nhead;
> +		goto adjust_others;
> +	}
> +

I suggest doing the max possible resize at this stage ?

Ie moving skb_shared_info at the edge of memory block.

Maybe its not necessary, and a given skb is not expanded multiple times
in our stack, I dont really know.




^ permalink raw reply

* Re: [PATCH 3/3] ipip: add module alias for tunl0 tunnel device
From: Eric Dumazet @ 2010-11-30  7:19 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: David Miller, netdev
In-Reply-To: <20101129194805.851988995@vyatta.com>

Le lundi 29 novembre 2010 à 11:47 -0800, Stephen Hemminger a écrit :
> pièce jointe document texte brut (ipip-alias.patch)
> If ipip is built as a module the 'ip tunnel add' command would fail because
> the ipip module was not being autoloaded.  Adding an alias for
> the tunl0 device name cause dev_load() to autoload it when needed.
> 
> Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
> 
> --- a/net/ipv4/ipip.c	2010-11-29 11:40:25.026277890 -0800
> +++ b/net/ipv4/ipip.c	2010-11-29 11:41:05.790681069 -0800
> @@ -913,3 +913,4 @@ static void __exit ipip_fini(void)
>  module_init(ipip_init);
>  module_exit(ipip_fini);
>  MODULE_LICENSE("GPL");
> +MODULE_ALIAS("tunl0");

I am not sure I understand you...

Here, I do have ipip built as a module, and I have no problem :

# lsmod|grep ipip
# ip tunnel add
cannot determine tunnel mode (ipip, gre or sit)
# lsmod|grep ipip
# ip tunnel add mode ipip
# lsmod|grep ipip
ipip                    7692  0 
tunnel4                 2949  1 ipip
# 

What am I missing ?



^ permalink raw reply

* Re: [PATCH v2] net: avoid the unnecessary kmalloc
From: Changli Gao @ 2010-11-30  7:45 UTC (permalink / raw)
  To: Eric Dumazet; +Cc: David S. Miller, netdev
In-Reply-To: <1291099921.2725.28.camel@edumazet-laptop>

On Tue, Nov 30, 2010 at 2:52 PM, Eric Dumazet <eric.dumazet@gmail.com> wrote:
> Le mardi 30 novembre 2010 à 08:40 +0800, Changli Gao a écrit :
>> If the old memory allocated by kmalloc() is larger than the new requested,
>> pskb_expand_head() doesn't need to allocate a new one, unless the skb->head
>> is shared.
>>
>> Signed-off-by: Changli Gao <xiaosuo@gmail.com>
>
> Seems fine to me, but patch title and changelog are a bit uninformative.
>
>
> skb head being allocated by kmalloc(), it might be larger than what
> actually requested because of discrete kmem caches sizes. Before
> reallocating a new skb head, check if the current one has the needed
> extra size.
>
> Do this check only if skb head is not shared.
>
>

OK, I'll refine it with your comment. Thanks.

>
>> +
>> +     if (fastpath &&
>> +         size + sizeof(struct skb_shared_info) <= ksize(skb->head)) {
>> +             memmove(skb->head + size, skb_shinfo(skb),
>> +                     offsetof(struct skb_shared_info,
>> +                              frags[skb_shinfo(skb)->nr_frags]));
>> +             memmove(skb->head + nhead, skb->head,
>> +                     skb_tail_pointer(skb) - skb->head);
>> +             off = nhead;
>> +             goto adjust_others;
>> +     }
>> +
>
> I suggest doing the max possible resize at this stage ?
>
> Ie moving skb_shared_info at the edge of memory block.
>
> Maybe its not necessary, and a given skb is not expanded multiple times
> in our stack, I dont really know.
>

I don't think it is a good idea, If it is, why not use
ksize(skb->head) to set the tail pointer of skb when allocating a new
skb.

If we do sth. like this, more cache lines maybe involved.

-- 
Regards,
Changli Gao(xiaosuo@gmail.com)

^ permalink raw reply

* Re: [PATCH 3/3] ipip: add module alias for tunl0 tunnel device
From: Changli Gao @ 2010-11-30  7:55 UTC (permalink / raw)
  To: Eric Dumazet; +Cc: Stephen Hemminger, David Miller, netdev
In-Reply-To: <1291101577.2725.41.camel@edumazet-laptop>

On Tue, Nov 30, 2010 at 3:19 PM, Eric Dumazet <eric.dumazet@gmail.com> wrote:
> Le lundi 29 novembre 2010 à 11:47 -0800, Stephen Hemminger a écrit :
>> pièce jointe document texte brut (ipip-alias.patch)
>> If ipip is built as a module the 'ip tunnel add' command would fail because
>> the ipip module was not being autoloaded.  Adding an alias for
>> the tunl0 device name cause dev_load() to autoload it when needed.
>>
>> Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
>>
>> --- a/net/ipv4/ipip.c 2010-11-29 11:40:25.026277890 -0800
>> +++ b/net/ipv4/ipip.c 2010-11-29 11:41:05.790681069 -0800
>> @@ -913,3 +913,4 @@ static void __exit ipip_fini(void)
>>  module_init(ipip_init);
>>  module_exit(ipip_fini);
>>  MODULE_LICENSE("GPL");
>> +MODULE_ALIAS("tunl0");
>
> I am not sure I understand you...
>
> Here, I do have ipip built as a module, and I have no problem :
>
> # lsmod|grep ipip
> # ip tunnel add
> cannot determine tunnel mode (ipip, gre or sit)
> # lsmod|grep ipip
> # ip tunnel add mode ipip
> # lsmod|grep ipip
> ipip                    7692  0
> tunnel4                 2949  1 ipip
> #
>
> What am I missing ?
>
>

localhost linux # lsmod
Module                  Size  Used by
ipv6                  309359  12
localhost linux # ip -V
ip utility, iproute2-ss091226
localhost linux # ip tunnel add mode gre
ioctl: No such device
localhost linux # ip tunnel add mode ipip
ioctl: No such device
localhost linux # modprobe ip_gre
localhost linux # modprobe ipip
localhost linux # ip tunnel add mode ipip
localhost linux # ip tunnel add mode gre
localhost linux # lsmod
Module                  Size  Used by
ipip                    8128  0
tunnel4                 2683  1 ipip
ip_gre                 15055  0
gre                     1967  1 ip_gre
ipv6                  309359  13 ip_gre


-- 
Regards,
Changli Gao(xiaosuo@gmail.com)

^ permalink raw reply

* [PATCH] Net-ethtool : Allow ethtool to set interface in loopback mode.
From: Mahesh Bandewar @ 2010-11-30  8:00 UTC (permalink / raw)
  To: David Miller, linux-netdev

This patch enables ethtool to set the loopback mode on a given
interface. This is the reworked version of earlier submit (which I
don't have reference to). By configuring the interface in loopback
mode in conjunction with a policy route / rule, a userland application
can stress the egress / ingress path exposing the flows of the change
in progress and potentially help developer(s) understand the impact of
those changes without even sending a packet out on the network.

Following set of commands illustrates one such example -
    a) ifconfig eth1 192.168.1.1
    b) ip -4 rule add from all iif eth1 lookup 250
    c) ip -4 route add local 0/0 dev lo proto kernel scope host table 250
    d) arp -Ds 192.168.1.100 eth1
    e) arp -Ds 192.168.1.200 eth1
    f) sysctl -w net.ipv4.ip_nonlocal_bind=1
    g) sysctl -w net.ipv4.conf.all.accept_local=1
    # Assuming that the machine has 8 cores
    h) taskset 000f netserver -L 192.168.1.200
    i) taskset 00f0 netperf -t TCP_CRR -L 192.168.1.100 -H 192.168.1.200 -l 30

Signed-off-by: Mahesh Bandewar <maheshb@google.com>
---
 include/linux/ethtool.h |    4 ++++
 net/core/ethtool.c      |   39 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 43 insertions(+), 0 deletions(-)

diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h
index 6628a50..7523d45 100644
--- a/include/linux/ethtool.h
+++ b/include/linux/ethtool.h
@@ -678,6 +678,8 @@ struct ethtool_ops {
                                  struct ethtool_rxfh_indir *);
        int     (*set_rxfh_indir)(struct net_device *,
                                  const struct ethtool_rxfh_indir *);
+       int     (*get_loopback)(struct net_device *, u32 *);
+       int     (*set_loopback)(struct net_device *, u32);
 };
 #endif /* __KERNEL__ */

@@ -741,6 +743,8 @@ struct ethtool_ops {
 #define ETHTOOL_GSSET_INFO     0x00000037 /* Get string set info */
 #define ETHTOOL_GRXFHINDIR     0x00000038 /* Get RX flow hash indir'n table */
 #define ETHTOOL_SRXFHINDIR     0x00000039 /* Set RX flow hash indir'n table */
+#define ETHTOOL_SLOOPBACK      0x0000003a /* Enable / Disable Loopback */
+#define ETHTOOL_GLOOPBACK      0x0000003b /* Get Loopback status */

 /* compatibility with older code */
 #define SPARC_ETH_GSET         ETHTOOL_GSET
diff --git a/net/core/ethtool.c b/net/core/ethtool.c
index 956a9f4..5c87c93 100644
--- a/net/core/ethtool.c
+++ b/net/core/ethtool.c
@@ -1434,6 +1434,39 @@ static noinline_for_stack int ethtool_flash_device(struct
        return dev->ethtool_ops->flash_device(dev, &efl);
 }

+static int ethtool_set_loopback(struct net_device *dev, void __user *useraddr)
+{
+       struct ethtool_value edata;
+       const struct ethtool_ops *ops = dev->ethtool_ops;
+
+       if (!ops || !ops->set_loopback)
+               return -EOPNOTSUPP;
+
+       if (copy_from_user(&edata, useraddr, sizeof(edata)))
+               return -EFAULT;
+
+       return ops->set_loopback(dev, edata.data);
+}
+
+static int ethtool_get_loopback(struct net_device *dev, void __user *useraddr)
+{
+       struct ethtool_value edata;
+       const struct ethtool_ops *ops = dev->ethtool_ops;
+       int err;
+
+       if (!ops || !ops->get_loopback)
+               return -EOPNOTSUPP;
+
+       err = ops->get_loopback(dev, &edata.data);
+       if (err)
+               return (err);
+
+       if (copy_to_user(useraddr, &edata, sizeof(edata)))
+               return -EFAULT;
+
+       return 0;
+}
+
 /* The main entry point in this file.  Called from net/core/dev.c */

 int dev_ethtool(struct net *net, struct ifreq *ifr)
@@ -1678,6 +1711,12 @@ int dev_ethtool(struct net *net, struct ifreq *ifr)
        case ETHTOOL_SRXFHINDIR:
                rc = ethtool_set_rxfh_indir(dev, useraddr);
                break;
+       case ETHTOOL_SLOOPBACK:
+               rc = ethtool_set_loopback(dev, useraddr);
+               break;
+       case ETHTOOL_GLOOPBACK:
+               rc = ethtool_get_loopback(dev, useraddr);
+               break;
        default:
                rc = -EOPNOTSUPP;
        }

^ permalink raw reply related

* Re: [PATCH v2] net: avoid the unnecessary kmalloc
From: Eric Dumazet @ 2010-11-30  8:16 UTC (permalink / raw)
  To: Changli Gao; +Cc: David S. Miller, netdev
In-Reply-To: <AANLkTiny5bXgEMt6dciURNnF+v1X6AnVrbJNo0S9FJP5@mail.gmail.com>

Le mardi 30 novembre 2010 à 15:45 +0800, Changli Gao a écrit :

> I don't think it is a good idea, If it is, why not use
> ksize(skb->head) to set the tail pointer of skb when allocating a new
> skb.
> 

Calling ksize() for all allocated skb would be overkill, since most of
them are correctly sized and dont need expand() at all.

In what situation do you notice this being expand_head() ever called ?


> If we do sth. like this, more cache lines maybe involved.
> 

This has same number of _touched_ cache lines actually, and this is what
matters.

Actually I dont have strong feeling, this is a detail.



^ permalink raw reply

* Re: [PATCH 3/3] ipip: add module alias for tunl0 tunnel device
From: Eric Dumazet @ 2010-11-30  8:21 UTC (permalink / raw)
  To: Changli Gao; +Cc: Stephen Hemminger, David Miller, netdev
In-Reply-To: <AANLkTi=DFN=r5XLYEwb3RYOyTF+u0uTEUa3wX5i2ijJZ@mail.gmail.com>

Le mardi 30 novembre 2010 à 15:55 +0800, Changli Gao a écrit :
> On Tue, Nov 30, 2010 at 3:19 PM, Eric Dumazet <eric.dumazet@gmail.com> wrote:
> > Le lundi 29 novembre 2010 à 11:47 -0800, Stephen Hemminger a écrit :
> >> pièce jointe document texte brut (ipip-alias.patch)
> >> If ipip is built as a module the 'ip tunnel add' command would fail because
> >> the ipip module was not being autoloaded.  Adding an alias for
> >> the tunl0 device name cause dev_load() to autoload it when needed.
> >>
> >> Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
> >>
> >> --- a/net/ipv4/ipip.c 2010-11-29 11:40:25.026277890 -0800
> >> +++ b/net/ipv4/ipip.c 2010-11-29 11:41:05.790681069 -0800
> >> @@ -913,3 +913,4 @@ static void __exit ipip_fini(void)
> >>  module_init(ipip_init);
> >>  module_exit(ipip_fini);
> >>  MODULE_LICENSE("GPL");
> >> +MODULE_ALIAS("tunl0");
> >
> > I am not sure I understand you...
> >
> > Here, I do have ipip built as a module, and I have no problem :
> >
> > # lsmod|grep ipip
> > # ip tunnel add
> > cannot determine tunnel mode (ipip, gre or sit)
> > # lsmod|grep ipip
> > # ip tunnel add mode ipip
> > # lsmod|grep ipip
> > ipip                    7692  0
> > tunnel4                 2949  1 ipip
> > #
> >
> > What am I missing ?
> >
> >
> 
> localhost linux # lsmod
> Module                  Size  Used by
> ipv6                  309359  12
> localhost linux # ip -V
> ip utility, iproute2-ss091226
> localhost linux # ip tunnel add mode gre
> ioctl: No such device
> localhost linux # ip tunnel add mode ipip
> ioctl: No such device
> localhost linux # modprobe ip_gre
> localhost linux # modprobe ipip
> localhost linux # ip tunnel add mode ipip
> localhost linux # ip tunnel add mode gre
> localhost linux # lsmod
> Module                  Size  Used by
> ipip                    8128  0
> tunnel4                 2683  1 ipip
> ip_gre                 15055  0
> gre                     1967  1 ip_gre
> ipv6                  309359  13 ip_gre
> 
> 

Hmm. I still dont get it, ipv6 as a module ?

Works well here.

# lsmod
Module                  Size  Used by
bonding                89194  0 
ipv6                  232889  29 bonding
# ip tunnel add mode ipip
# lsmod
Module                  Size  Used by
ipip                    6221  0 
bonding                89194  0 
ipv6                  232889  29 bonding
# ip -V
ip utility, iproute2-ss100823
# 



^ permalink raw reply

* [PATCH v3] net: don't reallocate skb->head unless the current one hasn't the needed extra size or is shared
From: Changli Gao @ 2010-11-30  8:48 UTC (permalink / raw)
  To: David S. Miller; +Cc: netdev, Changli Gao, Eric Dumazet

skb head being allocated by kmalloc(), it might be larger than what
actually requested because of discrete kmem caches sizes. Before
reallocating a new skb head, check if the current one has the needed
extra size.

Do this check only if skb head is not shared.

Signed-off-by: Changli Gao <xiaosuo@gmail.com>
Cc: Eric Dumazet <eric.dumazet@gmail.com>
---
V3: update the comment.
v2: apply this trick for the cloned but not shared skb
 net/core/skbuff.c |   34 +++++++++++++++++++++++-----------
 1 file changed, 23 insertions(+), 11 deletions(-)
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 104f844..8814a9a 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -778,6 +778,28 @@ int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail,
 
 	size = SKB_DATA_ALIGN(size);
 
+	/* Check if we can avoid taking references on fragments if we own
+	 * the last reference on skb->head. (see skb_release_data())
+	 */
+	if (!skb->cloned)
+		fastpath = true;
+	else {
+		int delta = skb->nohdr ? (1 << SKB_DATAREF_SHIFT) + 1 : 1;
+
+		fastpath = atomic_read(&skb_shinfo(skb)->dataref) == delta;
+	}
+
+	if (fastpath &&
+	    size + sizeof(struct skb_shared_info) <= ksize(skb->head)) {
+		memmove(skb->head + size, skb_shinfo(skb),
+			offsetof(struct skb_shared_info,
+				 frags[skb_shinfo(skb)->nr_frags]));
+		memmove(skb->head + nhead, skb->head,
+			skb_tail_pointer(skb) - skb->head);
+		off = nhead;
+		goto adjust_others;
+	}
+
 	data = kmalloc(size + sizeof(struct skb_shared_info), gfp_mask);
 	if (!data)
 		goto nodata;
@@ -791,17 +813,6 @@ int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail,
 	       skb_shinfo(skb),
 	       offsetof(struct skb_shared_info, frags[skb_shinfo(skb)->nr_frags]));
 
-	/* Check if we can avoid taking references on fragments if we own
-	 * the last reference on skb->head. (see skb_release_data())
-	 */
-	if (!skb->cloned)
-		fastpath = true;
-	else {
-		int delta = skb->nohdr ? (1 << SKB_DATAREF_SHIFT) + 1 : 1;
-
-		fastpath = atomic_read(&skb_shinfo(skb)->dataref) == delta;
-	}
-
 	if (fastpath) {
 		kfree(skb->head);
 	} else {
@@ -816,6 +827,7 @@ int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail,
 	off = (data + nhead) - skb->head;
 
 	skb->head     = data;
+adjust_others:
 	skb->data    += off;
 #ifdef NET_SKBUFF_DATA_USES_OFFSET
 	skb->end      = size;

^ permalink raw reply related

* Re: 2.6.35 -> 2.6.36 panic when vlan and promisc with tg3
From: Michael Leun @ 2010-11-30  8:59 UTC (permalink / raw)
  To: Ben Greear; +Cc: linux-kernel, netdev
In-Reply-To: <4CF442FA.4070701@candelatech.com>

On Mon, 29 Nov 2010 16:19:06 -0800
Ben Greear <greearb@candelatech.com> wrote:

> On 11/29/2010 11:17 AM, Michael Leun wrote:
> > UG: unable to handle kernel paging request at 01cc921c
> > IP: [<c034bfce>] vlan_hwaccel_do_receive+0x59/0xd0
> > *pdpt = 0000000036a2a001 *pde = 0000000000000000
> > Oops: 0002 [#1] SMP
> > last sysfs
> >
> > Then machine dead.
> >
> > In 2.6.35.x this did not happen (but vlans broken - cannot see vlan
> > tags with tcpdump),
> 
> Try this patch:
> 
> http://permalink.gmane.org/gmane.linux.network/176566
> 
> It looks like this hasn't made it into stable yet?

> > To reproduce:
> >
> > ip link set eth0 up
> > vconfig add eth0 2
> > ip link set eth0 promisc on

It makes it better - it does not crash anymore on this commands - but
if you add an "tcpdump -i eth0 -n" at the end it does. So,
unfortunately no real solution.

I guess, "dropping packet no one is interested in" (as noted in the
patch) does not work very well if tcpdump is actually interested?

-- 
MfG,

Michael Leun

^ permalink raw reply

* Re: 2.6.35 -> 2.6.36 panic when vlan and promisc with tg3
From: Eric Dumazet @ 2010-11-30  9:20 UTC (permalink / raw)
  To: Michael Leun; +Cc: Ben Greear, linux-kernel, netdev
In-Reply-To: <20101130095944.41b5f7b6@xenia.leun.net>

Le mardi 30 novembre 2010 à 09:59 +0100, Michael Leun a écrit :
> On Mon, 29 Nov 2010 16:19:06 -0800
> Ben Greear <greearb@candelatech.com> wrote:
> 
> > On 11/29/2010 11:17 AM, Michael Leun wrote:
> > > UG: unable to handle kernel paging request at 01cc921c
> > > IP: [<c034bfce>] vlan_hwaccel_do_receive+0x59/0xd0
> > > *pdpt = 0000000036a2a001 *pde = 0000000000000000
> > > Oops: 0002 [#1] SMP
> > > last sysfs
> > >
> > > Then machine dead.
> > >
> > > In 2.6.35.x this did not happen (but vlans broken - cannot see vlan
> > > tags with tcpdump),
> > 
> > Try this patch:
> > 
> > http://permalink.gmane.org/gmane.linux.network/176566
> > 
> > It looks like this hasn't made it into stable yet?
> 
> > > To reproduce:
> > >
> > > ip link set eth0 up
> > > vconfig add eth0 2
> > > ip link set eth0 promisc on
> 
> It makes it better - it does not crash anymore on this commands - but
> if you add an "tcpdump -i eth0 -n" at the end it does. So,
> unfortunately no real solution.
> 
> I guess, "dropping packet no one is interested in" (as noted in the
> patch) does not work very well if tcpdump is actually interested?
> 

Could you try with following patch instead, for net/core/dev.c 

(and keep the net/8021q/vlan_core.c part)

--- net/core/dev.c.orig
+++ net/core/dev.c
@@ -2891,6 +2891,9 @@
 ncls:
 #endif
 
+	if (unlikely(vlan_tx_tag_present(skb)))
+		goto bypass;
+
 	/* Handle special case of bridge or macvlan */
 	rx_handler = rcu_dereference(skb->dev->rx_handler);
 	if (rx_handler) {
@@ -2927,6 +2930,7 @@
 		}
 	}
 
+bypass:
 	if (pt_prev) {
 		ret = pt_prev->func(skb, skb->dev, pt_prev, orig_dev);
 	} else {

^ permalink raw reply

* multi bpf filter will impact performance?
From: Rui @ 2010-11-30  9:22 UTC (permalink / raw)
  To: netdev

hi

I did a test with an intel X520 10Gnic, HP DL380 G6,  to see how the
bpf filter will impact the performance.

kernel .2.6.32 SLES11+SP1, original ixgbe driver

step 0:
launch 4 tcpdump processes,each applied a filter to filter out some
GTP-U packets. seen with 'tcpdump -d', the bpf code has about 100
lines.

#!/bin/sh
PCAP_FRAMES=32000 ./tcpdump_MMAP -i eth4 'udp dst port 2152 and (
(((ether[48:1]&0x07)>0) and
(((ether[66:1]+ether[67:1]+ether[68:1]+ether[69:1]+ether[70:1]+ether[71:1]+ether[72:1]+ether[73:1])&0x03)==0))
or (((ether[48:1]&0x07)==0) and
(((ether[62:1]+ether[63:1]+ether[64:1]+ether[65:1]+ether[66:1]+ether[67:1]+ether[68:1]+ether[69:1])&0x03)==0))
) ' -w /dev/null -s 4096 2>f1.log &
PCAP_FRAMES=32000 ./tcpdump_MMAP -i eth4 'udp dst port 2152 and (
(((ether[48:1]&0x07)>0) and
(((ether[66:1]+ether[67:1]+ether[68:1]+ether[69:1]+ether[70:1]+ether[71:1]+ether[72:1]+ether[73:1])&0x03)==1))
or (((ether[48:1]&0x07)==0) and
(((ether[62:1]+ether[63:1]+ether[64:1]+ether[65:1]+ether[66:1]+ether[67:1]+ether[68:1]+ether[69:1])&0x03)==1))
) ' -w /dev/null -s 4096 2>f2.log &
PCAP_FRAMES=32000 ./tcpdump_MMAP -i eth4 'udp dst port 2152 and (
(((ether[48:1]&0x07)>0) and
(((ether[66:1]+ether[67:1]+ether[68:1]+ether[69:1]+ether[70:1]+ether[71:1]+ether[72:1]+ether[73:1])&0x03)==2))
or (((ether[48:1]&0x07)==0) and
(((ether[62:1]+ether[63:1]+ether[64:1]+ether[65:1]+ether[66:1]+ether[67:1]+ether[68:1]+ether[69:1])&0x03)==2))
) ' -w /dev/null -s 4096 2>f3.log &
PCAP_FRAMES=32000 ./tcpdump_MMAP -i eth4 'udp dst port 2152 and (
(((ether[48:1]&0x07)>0) and
(((ether[66:1]+ether[67:1]+ether[68:1]+ether[69:1]+ether[70:1]+ether[71:1]+ether[72:1]+ether[73:1])&0x03)==3))
or (((ether[48:1]&0x07)==0) and
(((ether[62:1]+ether[63:1]+ether[64:1]+ether[65:1]+ether[66:1]+ether[67:1]+ether[68:1]+ether[69:1])&0x03)==3))
) ' -w /dev/null -s 4096 2>f4.log &


step1:
use stress test equipment to generate traffic >1.2Gbps


step2:
type 'ifconfig eth4'
saw many packets dropped

step3:
type 'sar -n DEV 1', the incoming throughput limited at 800Mbps


my questions:

Q1. the bpf filter is run one by one? will only one filter be executed
for one sock? (so that the tcpdump corresponding kernel part will run
filter in parallel?)

Q2. performance is bad? any idea to improve it?

thanks a lot
rui

^ permalink raw reply

* [PATCHv3 1/2] usbnet: changes for upcoming cdc_ncm driver
From: Alexey Orishko @ 2010-11-30  9:23 UTC (permalink / raw)
  To: gregkh, linux-usb
  Cc: netdev, oliver, yauheni.kaliuta, balbi, sjur.brandeland,
	alexey.orishko

Changes:
include/linux/usb/usbnet.h:
- a new flag to indicate driver's capability to accumulate IP packets in Tx
 direction and extract several packets from single skb in Rx direction.
drivers/net/usb/usbnet.c:
- the procedure of counting packets in usbnet was updated due to the
 accumulating of IP packets in the driver
- no short packets are sent if indicated by the flag in driver_info
 structure

Signed-off-by: Alexey Orishko <alexey.orishko@stericsson.com>
---
 drivers/net/usb/usbnet.c   |   45 ++++++++++++++++++++++++++++++-------------
 include/linux/usb/usbnet.h |    6 +++++
 2 files changed, 37 insertions(+), 14 deletions(-)

diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
index c04d49e..cff74b8 100644
--- a/drivers/net/usb/usbnet.c
+++ b/drivers/net/usb/usbnet.c
@@ -391,14 +391,19 @@ static inline void rx_process (struct usbnet *dev, struct sk_buff *skb)
 		goto error;
 	// else network stack removes extra byte if we forced a short packet
 
-	if (skb->len)
-		usbnet_skb_return (dev, skb);
-	else {
-		netif_dbg(dev, rx_err, dev->net, "drop\n");
-error:
-		dev->net->stats.rx_errors++;
-		skb_queue_tail (&dev->done, skb);
+	if (skb->len) {
+		/* all data was already cloned from skb inside the driver */
+		if (dev->driver_info->flags & FLAG_MULTI_PACKET)
+			dev_kfree_skb_any(skb);
+		else
+			usbnet_skb_return(dev, skb);
+		return;
 	}
+
+	netif_dbg(dev, rx_err, dev->net, "drop\n");
+error:
+	dev->net->stats.rx_errors++;
+	skb_queue_tail(&dev->done, skb);
 }
 
 /*-------------------------------------------------------------------------*/
@@ -971,7 +976,8 @@ static void tx_complete (struct urb *urb)
 	struct usbnet		*dev = entry->dev;
 
 	if (urb->status == 0) {
-		dev->net->stats.tx_packets++;
+		if (!(dev->driver_info->flags & FLAG_MULTI_PACKET))
+			dev->net->stats.tx_packets++;
 		dev->net->stats.tx_bytes += entry->length;
 	} else {
 		dev->net->stats.tx_errors++;
@@ -1044,8 +1050,13 @@ netdev_tx_t usbnet_start_xmit (struct sk_buff *skb,
 	if (info->tx_fixup) {
 		skb = info->tx_fixup (dev, skb, GFP_ATOMIC);
 		if (!skb) {
-			netif_dbg(dev, tx_err, dev->net, "can't tx_fixup skb\n");
-			goto drop;
+			if (netif_msg_tx_err(dev)) {
+				netif_dbg(dev, tx_err, dev->net, "can't tx_fixup skb\n");
+				goto drop;
+			} else {
+				/* cdc_ncm collected packet; waits for more */
+				goto not_drop;
+			}
 		}
 	}
 	length = skb->len;
@@ -1067,13 +1078,18 @@ netdev_tx_t usbnet_start_xmit (struct sk_buff *skb,
 	/* don't assume the hardware handles USB_ZERO_PACKET
 	 * NOTE:  strictly conforming cdc-ether devices should expect
 	 * the ZLP here, but ignore the one-byte packet.
+	 * NOTE2: CDC NCM specification is different from CDC ECM when
+	 * handling ZLP/short packets, so cdc_ncm driver will make short
+	 * packet itself if needed.
 	 */
 	if (length % dev->maxpacket == 0) {
 		if (!(info->flags & FLAG_SEND_ZLP)) {
-			urb->transfer_buffer_length++;
-			if (skb_tailroom(skb)) {
-				skb->data[skb->len] = 0;
-				__skb_put(skb, 1);
+			if (!(info->flags & FLAG_MULTI_PACKET)) {
+				urb->transfer_buffer_length++;
+				if (skb_tailroom(skb)) {
+					skb->data[skb->len] = 0;
+					__skb_put(skb, 1);
+				}
 			}
 		} else
 			urb->transfer_flags |= URB_ZERO_PACKET;
@@ -1122,6 +1138,7 @@ netdev_tx_t usbnet_start_xmit (struct sk_buff *skb,
 		netif_dbg(dev, tx_err, dev->net, "drop, code %d\n", retval);
 drop:
 		dev->net->stats.tx_dropped++;
+not_drop:
 		if (skb)
 			dev_kfree_skb_any (skb);
 		usb_free_urb (urb);
diff --git a/include/linux/usb/usbnet.h b/include/linux/usb/usbnet.h
index 7ae27a4..44842c8 100644
--- a/include/linux/usb/usbnet.h
+++ b/include/linux/usb/usbnet.h
@@ -97,6 +97,12 @@ struct driver_info {
 
 #define FLAG_LINK_INTR	0x0800		/* updates link (carrier) status */
 
+/*
+ * Indicates to usbnet, that USB driver accumulates multiple IP packets.
+ * Affects statistic (counters) and short packet handling.
+ */
+#define FLAG_MULTI_PACKET	0x1000
+
 	/* init device ... can sleep, or cause probe() failure */
 	int	(*bind)(struct usbnet *, struct usb_interface *);
 
-- 
1.7.3.2


^ permalink raw reply related

* [PATCHv3 2/2] USB CDC NCM host driver
From: Alexey Orishko @ 2010-11-30  9:23 UTC (permalink / raw)
  To: gregkh, linux-usb
  Cc: netdev, oliver, yauheni.kaliuta, balbi, sjur.brandeland,
	alexey.orishko
In-Reply-To: <1291109008-3613-1-git-send-email-alexey.orishko@stericsson.com>

The patch provides USB CDC NCM host driver support in the Linux Kernel.

Changes:
drivers/net/usb/cdc_ncm.c:
- initial submission of the CDC NCM host driver;
- verified on Intel 32/64 bit, Intel Atom, ST-Ericsson U8500 (ARM)
- throughput measured over 100 Mbits duplex;
- driver supports 16-bit NTB format only, but it is more than enough for
  transfers up to 64K;
- driver can handle up to 32 datagrams in received NTB;
- timer is used to collect several packets in Tx direction

drivers/net/usb/Kconfig:
- a new entry to compile CDC NCM host driver
drivers/net/usb/Makefile:
- a new entry to compile CDC NCM host driver

Signed-off-by: Alexey Orishko <alexey.orishko@stericsson.com>
---
Changes from v2 to v3: replaced locally defined macro CDC_NCM_ALIGN with a
generic one ALIGN. Macro is used to set offset in the data buffer.

 drivers/net/usb/Kconfig   |   19 +
 drivers/net/usb/Makefile  |    1 +
 drivers/net/usb/cdc_ncm.c | 1213 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 1233 insertions(+), 0 deletions(-)
 create mode 100644 drivers/net/usb/cdc_ncm.c

diff --git a/drivers/net/usb/Kconfig b/drivers/net/usb/Kconfig
index 52ffabe..6f600cc 100644
--- a/drivers/net/usb/Kconfig
+++ b/drivers/net/usb/Kconfig
@@ -196,6 +196,25 @@ config USB_NET_CDC_EEM
 	  IEEE 802 "local assignment" bit is set in the address, a "usbX"
 	  name is used instead.
 
+config USB_NET_CDC_NCM
+	tristate "CDC NCM support"
+	depends on USB_USBNET
+	default y
+	help
+	  This driver provides support for CDC NCM (Network Control Model
+	  Device USB Class Specification). The CDC NCM specification is
+	  available from <http://www.usb.org/>.
+
+	  Say "y" to link the driver statically, or "m" to build a
+	  dynamically linked module.
+
+	  This driver should work with at least the following devices:
+	    * ST-Ericsson M700 LTE FDD/TDD Mobile Broadband Modem (ref. design)
+	    * ST-Ericsson M5730 HSPA+ Mobile Broadband Modem (reference design)
+	    * ST-Ericsson M570 HSPA+ Mobile Broadband Modem (reference design)
+	    * ST-Ericsson M343 HSPA Mobile Broadband Modem (reference design)
+	    * Ericsson F5521gw Mobile Broadband Module
+
 config USB_NET_DM9601
 	tristate "Davicom DM9601 based USB 1.1 10/100 ethernet devices"
 	depends on USB_USBNET
diff --git a/drivers/net/usb/Makefile b/drivers/net/usb/Makefile
index a19b025..cac1703 100644
--- a/drivers/net/usb/Makefile
+++ b/drivers/net/usb/Makefile
@@ -26,4 +26,5 @@ obj-$(CONFIG_USB_CDC_PHONET)	+= cdc-phonet.o
 obj-$(CONFIG_USB_IPHETH)	+= ipheth.o
 obj-$(CONFIG_USB_SIERRA_NET)	+= sierra_net.o
 obj-$(CONFIG_USB_NET_CX82310_ETH)	+= cx82310_eth.o
+obj-$(CONFIG_USB_NET_CDC_NCM)	+= cdc_ncm.o
 
diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c
new file mode 100644
index 0000000..593c104
--- /dev/null
+++ b/drivers/net/usb/cdc_ncm.c
@@ -0,0 +1,1213 @@
+/*
+ * cdc_ncm.c
+ *
+ * Copyright (C) ST-Ericsson 2010
+ * Contact: Alexey Orishko <alexey.orishko@stericsson.com>
+ * Original author: Hans Petter Selasky <hans.petter.selasky@stericsson.com>
+ *
+ * USB Host Driver for Network Control Model (NCM)
+ * http://www.usb.org/developers/devclass_docs/NCM10.zip
+ *
+ * The NCM encoding, decoding and initialization logic
+ * derives from FreeBSD 8.x. if_cdce.c and if_cdcereg.h
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose this file to be licensed under the terms
+ * of the GNU General Public License (GPL) Version 2 or the 2-clause
+ * BSD license listed below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/ctype.h>
+#include <linux/ethtool.h>
+#include <linux/workqueue.h>
+#include <linux/mii.h>
+#include <linux/crc32.h>
+#include <linux/usb.h>
+#include <linux/version.h>
+#include <linux/timer.h>
+#include <linux/spinlock.h>
+#include <linux/atomic.h>
+#include <linux/usb/usbnet.h>
+#include <linux/usb/cdc.h>
+
+#define	DRIVER_VERSION				"30-Nov-2010"
+
+/* CDC NCM subclass 3.2.1 */
+#define USB_CDC_NCM_NDP16_LENGTH_MIN		0x10
+
+/* Maximum NTB length */
+#define	CDC_NCM_NTB_MAX_SIZE_TX			16384	/* bytes */
+#define	CDC_NCM_NTB_MAX_SIZE_RX			16384	/* bytes */
+
+/* Minimum value for MaxDatagramSize, ch. 6.2.9 */
+#define	CDC_NCM_MIN_DATAGRAM_SIZE		1514	/* bytes */
+
+#define	CDC_NCM_MIN_TX_PKT			512	/* bytes */
+
+/* Default value for MaxDatagramSize */
+#define	CDC_NCM_MAX_DATAGRAM_SIZE		2048	/* bytes */
+
+/*
+ * Maximum amount of datagrams in NCM Datagram Pointer Table, not counting
+ * the last NULL entry. Any additional datagrams in NTB would be discarded.
+ */
+#define	CDC_NCM_DPT_DATAGRAMS_MAX		32
+
+/* Restart the timer, if amount of datagrams is less than given value */
+#define	CDC_NCM_RESTART_TIMER_DATAGRAM_CNT	3
+
+/* The following macro defines the minimum header space */
+#define	CDC_NCM_MIN_HDR_SIZE \
+	(sizeof(struct usb_cdc_ncm_nth16) + sizeof(struct usb_cdc_ncm_ndp16) + \
+	(CDC_NCM_DPT_DATAGRAMS_MAX + 1) * sizeof(struct usb_cdc_ncm_dpe16))
+
+struct connection_speed_change {
+	__le32	USBitRate; /* holds 3GPP downlink value, bits per second */
+	__le32	DSBitRate; /* holds 3GPP uplink value, bits per second */
+} __attribute__ ((packed));
+
+struct cdc_ncm_data {
+	struct usb_cdc_ncm_nth16 nth16;
+	struct usb_cdc_ncm_ndp16 ndp16;
+	struct usb_cdc_ncm_dpe16 dpe16[CDC_NCM_DPT_DATAGRAMS_MAX + 1];
+};
+
+struct cdc_ncm_ctx {
+	struct cdc_ncm_data rx_ncm;
+	struct cdc_ncm_data tx_ncm;
+	struct usb_cdc_ncm_ntb_parameters ncm_parm;
+	struct timer_list tx_timer;
+
+	const struct usb_cdc_ncm_desc *func_desc;
+	const struct usb_cdc_header_desc *header_desc;
+	const struct usb_cdc_union_desc *union_desc;
+	const struct usb_cdc_ether_desc *ether_desc;
+
+	struct net_device *netdev;
+	struct usb_device *udev;
+	struct usb_host_endpoint *in_ep;
+	struct usb_host_endpoint *out_ep;
+	struct usb_host_endpoint *status_ep;
+	struct usb_interface *intf;
+	struct usb_interface *control;
+	struct usb_interface *data;
+
+	struct sk_buff *tx_curr_skb;
+	struct sk_buff *tx_rem_skb;
+
+	spinlock_t mtx;
+
+	u32 tx_timer_pending;
+	u32 tx_curr_offset;
+	u32 tx_curr_last_offset;
+	u32 tx_curr_frame_num;
+	u32 rx_speed;
+	u32 tx_speed;
+	u32 rx_max;
+	u32 tx_max;
+	u32 max_datagram_size;
+	u16 tx_max_datagrams;
+	u16 tx_remainder;
+	u16 tx_modulus;
+	u16 tx_ndp_modulus;
+	u16 tx_seq;
+	u16 connected;
+	u8 data_claimed;
+	u8 control_claimed;
+};
+
+static void cdc_ncm_tx_timeout(unsigned long arg);
+static const struct driver_info cdc_ncm_info;
+static struct usb_driver cdc_ncm_driver;
+static struct ethtool_ops cdc_ncm_ethtool_ops;
+
+static const struct usb_device_id cdc_devs[] = {
+	{ USB_INTERFACE_INFO(USB_CLASS_COMM,
+		USB_CDC_SUBCLASS_NCM, USB_CDC_PROTO_NONE),
+		.driver_info = (unsigned long)&cdc_ncm_info,
+	},
+	{
+	},
+};
+
+MODULE_DEVICE_TABLE(usb, cdc_devs);
+
+static void
+cdc_ncm_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *info)
+{
+	struct usbnet *dev = netdev_priv(net);
+
+	strncpy(info->driver, dev->driver_name, sizeof(info->driver));
+	strncpy(info->version, DRIVER_VERSION, sizeof(info->version));
+	strncpy(info->fw_version, dev->driver_info->description,
+		sizeof(info->fw_version));
+	usb_make_path(dev->udev, info->bus_info, sizeof(info->bus_info));
+}
+
+static int
+cdc_ncm_do_request(struct cdc_ncm_ctx *ctx, struct usb_cdc_notification *req,
+		   void *data, u16 flags, u16 *actlen, u16 timeout)
+{
+	int err;
+
+	err = usb_control_msg(ctx->udev, (req->bmRequestType & USB_DIR_IN) ?
+				usb_rcvctrlpipe(ctx->udev, 0) :
+				usb_sndctrlpipe(ctx->udev, 0),
+				req->bNotificationType, req->bmRequestType,
+				req->wValue,
+				req->wIndex, data,
+				req->wLength, timeout);
+
+	if (err < 0) {
+		if (actlen)
+			*actlen = 0;
+		return err;
+	}
+
+	if (actlen)
+		*actlen = err;
+
+	return 0;
+}
+
+static u8 cdc_ncm_setup(struct cdc_ncm_ctx *ctx)
+{
+	struct usb_cdc_notification req;
+	u32 val;
+	__le16 max_datagram_size;
+	u8 flags;
+	u8 iface_no;
+	int err;
+
+	iface_no = ctx->control->cur_altsetting->desc.bInterfaceNumber;
+
+	req.bmRequestType = USB_TYPE_CLASS | USB_DIR_IN | USB_RECIP_INTERFACE;
+	req.bNotificationType = USB_CDC_GET_NTB_PARAMETERS;
+	req.wValue = 0;
+	req.wIndex = cpu_to_le16(iface_no);
+	req.wLength = cpu_to_le16(sizeof(ctx->ncm_parm));
+
+	err = cdc_ncm_do_request(ctx, &req, &ctx->ncm_parm, 0, NULL, 1000);
+	if (err) {
+		pr_debug("failed GET_NTB_PARAMETERS\n");
+		return 1;
+	}
+
+	/* read correct set of parameters according to device mode */
+	ctx->rx_max = le32_to_cpu(ctx->ncm_parm.dwNtbInMaxSize);
+	ctx->tx_max = le32_to_cpu(ctx->ncm_parm.dwNtbOutMaxSize);
+	ctx->tx_remainder = le16_to_cpu(ctx->ncm_parm.wNdpOutPayloadRemainder);
+	ctx->tx_modulus = le16_to_cpu(ctx->ncm_parm.wNdpOutDivisor);
+	ctx->tx_ndp_modulus = le16_to_cpu(ctx->ncm_parm.wNdpOutAlignment);
+
+	if (ctx->func_desc != NULL)
+		flags = ctx->func_desc->bmNetworkCapabilities;
+	else
+		flags = 0;
+
+	pr_debug("dwNtbInMaxSize=%u dwNtbOutMaxSize=%u "
+		 "wNdpOutPayloadRemainder=%u wNdpOutDivisor=%u "
+		 "wNdpOutAlignment=%u flags=0x%x\n",
+		 ctx->rx_max, ctx->tx_max, ctx->tx_remainder, ctx->tx_modulus,
+		 ctx->tx_ndp_modulus, flags);
+
+	/* max count of tx datagrams without terminating NULL entry */
+	ctx->tx_max_datagrams = CDC_NCM_DPT_DATAGRAMS_MAX;
+
+	/* verify maximum size of received NTB in bytes */
+	if ((ctx->rx_max <
+	    (CDC_NCM_MIN_HDR_SIZE + CDC_NCM_MIN_DATAGRAM_SIZE)) ||
+	    (ctx->rx_max > CDC_NCM_NTB_MAX_SIZE_RX)) {
+		pr_debug("Using default maximum receive length=%d\n",
+						CDC_NCM_NTB_MAX_SIZE_RX);
+		ctx->rx_max = CDC_NCM_NTB_MAX_SIZE_RX;
+	}
+
+	/* verify maximum size of transmitted NTB in bytes */
+	if ((ctx->tx_max <
+	    (CDC_NCM_MIN_HDR_SIZE + CDC_NCM_MIN_DATAGRAM_SIZE)) ||
+	    (ctx->tx_max > CDC_NCM_NTB_MAX_SIZE_TX)) {
+		pr_debug("Using default maximum transmit length=%d\n",
+						CDC_NCM_NTB_MAX_SIZE_TX);
+		ctx->tx_max = CDC_NCM_NTB_MAX_SIZE_TX;
+	}
+
+	/*
+	 * verify that the structure alignment is:
+	 * - power of two
+	 * - not greater than the maximum transmit length
+	 * - not less than four bytes
+	 */
+	val = ctx->tx_ndp_modulus;
+
+	if ((val < USB_CDC_NCM_NDP_ALIGN_MIN_SIZE) ||
+	    (val != ((-val) & val)) || (val >= ctx->tx_max)) {
+		pr_debug("Using default alignment: 4 bytes\n");
+		ctx->tx_ndp_modulus = USB_CDC_NCM_NDP_ALIGN_MIN_SIZE;
+	}
+
+	/*
+	 * verify that the payload alignment is:
+	 * - power of two
+	 * - not greater than the maximum transmit length
+	 * - not less than four bytes
+	 */
+	val = ctx->tx_modulus;
+
+	if ((val < USB_CDC_NCM_NDP_ALIGN_MIN_SIZE) ||
+	    (val != ((-val) & val)) || (val >= ctx->tx_max)) {
+		pr_debug("Using default transmit modulus: 4 bytes\n");
+		ctx->tx_modulus = USB_CDC_NCM_NDP_ALIGN_MIN_SIZE;
+	}
+
+	/* verify the payload remainder */
+	if (ctx->tx_remainder >= ctx->tx_modulus) {
+		pr_debug("Using default transmit remainder: 0 bytes\n");
+		ctx->tx_remainder = 0;
+	}
+
+	/* adjust TX-remainder according to NCM specification. */
+	ctx->tx_remainder = ((ctx->tx_remainder - ETH_HLEN) &
+						(ctx->tx_modulus - 1));
+
+	/* additional configuration */
+
+	/* set CRC Mode */
+	req.bmRequestType = USB_TYPE_CLASS | USB_DIR_OUT | USB_RECIP_INTERFACE;
+	req.bNotificationType = USB_CDC_SET_CRC_MODE;
+	req.wValue = cpu_to_le16(USB_CDC_NCM_CRC_NOT_APPENDED);
+	req.wIndex = cpu_to_le16(iface_no);
+	req.wLength = 0;
+
+	err = cdc_ncm_do_request(ctx, &req, NULL, 0, NULL, 1000);
+	if (err)
+		pr_debug("Setting CRC mode off failed\n");
+
+	/* set NTB format */
+	req.bmRequestType = USB_TYPE_CLASS | USB_DIR_OUT | USB_RECIP_INTERFACE;
+	req.bNotificationType = USB_CDC_SET_NTB_FORMAT;
+	req.wValue = cpu_to_le16(USB_CDC_NCM_NTB16_FORMAT);
+	req.wIndex = cpu_to_le16(iface_no);
+	req.wLength = 0;
+
+	err = cdc_ncm_do_request(ctx, &req, NULL, 0, NULL, 1000);
+	if (err)
+		pr_debug("Setting NTB format to 16-bit failed\n");
+
+	/* set Max Datagram Size (MTU) */
+	req.bmRequestType = USB_TYPE_CLASS | USB_DIR_IN | USB_RECIP_INTERFACE;
+	req.bNotificationType = USB_CDC_GET_MAX_DATAGRAM_SIZE;
+	req.wValue = 0;
+	req.wIndex = cpu_to_le16(iface_no);
+	req.wLength = cpu_to_le16(2);
+
+	err = cdc_ncm_do_request(ctx, &req, &max_datagram_size, 0, NULL, 1000);
+	if (err) {
+		pr_debug(" GET_MAX_DATAGRAM_SIZE failed, using size=%u\n",
+			 CDC_NCM_MIN_DATAGRAM_SIZE);
+		/* use default */
+		ctx->max_datagram_size = CDC_NCM_MIN_DATAGRAM_SIZE;
+	} else {
+		ctx->max_datagram_size = le16_to_cpu(max_datagram_size);
+
+		if (ctx->max_datagram_size < CDC_NCM_MIN_DATAGRAM_SIZE)
+			ctx->max_datagram_size = CDC_NCM_MIN_DATAGRAM_SIZE;
+		else if (ctx->max_datagram_size > CDC_NCM_MAX_DATAGRAM_SIZE)
+			ctx->max_datagram_size = CDC_NCM_MAX_DATAGRAM_SIZE;
+	}
+
+	if (ctx->netdev->mtu != (ctx->max_datagram_size - ETH_HLEN))
+		ctx->netdev->mtu = ctx->max_datagram_size - ETH_HLEN;
+
+	return 0;
+}
+
+static void
+cdc_ncm_find_endpoints(struct cdc_ncm_ctx *ctx, struct usb_interface *intf)
+{
+	struct usb_host_endpoint *e;
+	u8 ep;
+
+	for (ep = 0; ep < intf->cur_altsetting->desc.bNumEndpoints; ep++) {
+
+		e = intf->cur_altsetting->endpoint + ep;
+		switch (e->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
+		case USB_ENDPOINT_XFER_INT:
+			if (usb_endpoint_dir_in(&e->desc)) {
+				if (ctx->status_ep == NULL)
+					ctx->status_ep = e;
+			}
+			break;
+
+		case USB_ENDPOINT_XFER_BULK:
+			if (usb_endpoint_dir_in(&e->desc)) {
+				if (ctx->in_ep == NULL)
+					ctx->in_ep = e;
+			} else {
+				if (ctx->out_ep == NULL)
+					ctx->out_ep = e;
+			}
+			break;
+
+		default:
+			break;
+		}
+	}
+}
+
+static void cdc_ncm_free(struct cdc_ncm_ctx *ctx)
+{
+	if (ctx == NULL)
+		return;
+
+	del_timer_sync(&ctx->tx_timer);
+
+	if (ctx->data_claimed) {
+		usb_set_intfdata(ctx->data, NULL);
+		usb_driver_release_interface(driver_of(ctx->intf), ctx->data);
+	}
+
+	if (ctx->control_claimed) {
+		usb_set_intfdata(ctx->control, NULL);
+		usb_driver_release_interface(driver_of(ctx->intf),
+								ctx->control);
+	}
+
+	if (ctx->tx_rem_skb != NULL) {
+		dev_kfree_skb_any(ctx->tx_rem_skb);
+		ctx->tx_rem_skb = NULL;
+	}
+
+	if (ctx->tx_curr_skb != NULL) {
+		dev_kfree_skb_any(ctx->tx_curr_skb);
+		ctx->tx_curr_skb = NULL;
+	}
+
+	kfree(ctx);
+}
+
+static int cdc_ncm_bind(struct usbnet *dev, struct usb_interface *intf)
+{
+	struct cdc_ncm_ctx *ctx;
+	struct usb_driver *driver;
+	u8 *buf;
+	int len;
+	int temp;
+	u8 iface_no;
+
+	ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
+	if (ctx == NULL)
+		goto error;
+
+	memset(ctx, 0, sizeof(*ctx));
+
+	init_timer(&ctx->tx_timer);
+	spin_lock_init(&ctx->mtx);
+	ctx->netdev = dev->net;
+
+	/* store ctx pointer in device data field */
+	dev->data[0] = (unsigned long)ctx;
+
+	/* get some pointers */
+	driver = driver_of(intf);
+	buf = intf->cur_altsetting->extra;
+	len = intf->cur_altsetting->extralen;
+
+	ctx->udev = dev->udev;
+	ctx->intf = intf;
+
+	/* parse through descriptors associated with control interface */
+	while ((len > 0) && (buf[0] > 2) && (buf[0] <= len)) {
+
+		if (buf[1] != USB_DT_CS_INTERFACE)
+			goto advance;
+
+		switch (buf[2]) {
+		case USB_CDC_UNION_TYPE:
+			if (buf[0] < sizeof(*(ctx->union_desc)))
+				break;
+
+			ctx->union_desc =
+					(const struct usb_cdc_union_desc *)buf;
+
+			ctx->control = usb_ifnum_to_if(dev->udev,
+					ctx->union_desc->bMasterInterface0);
+			ctx->data = usb_ifnum_to_if(dev->udev,
+					ctx->union_desc->bSlaveInterface0);
+			break;
+
+		case USB_CDC_ETHERNET_TYPE:
+			if (buf[0] < sizeof(*(ctx->ether_desc)))
+				break;
+
+			ctx->ether_desc =
+					(const struct usb_cdc_ether_desc *)buf;
+
+			dev->hard_mtu =
+				le16_to_cpu(ctx->ether_desc->wMaxSegmentSize);
+
+			if (dev->hard_mtu <
+			    (CDC_NCM_MIN_DATAGRAM_SIZE - ETH_HLEN))
+				dev->hard_mtu =
+					CDC_NCM_MIN_DATAGRAM_SIZE - ETH_HLEN;
+
+			else if (dev->hard_mtu >
+				 (CDC_NCM_MAX_DATAGRAM_SIZE - ETH_HLEN))
+				dev->hard_mtu =
+					CDC_NCM_MAX_DATAGRAM_SIZE - ETH_HLEN;
+			break;
+
+		case USB_CDC_NCM_TYPE:
+			if (buf[0] < sizeof(*(ctx->func_desc)))
+				break;
+
+			ctx->func_desc = (const struct usb_cdc_ncm_desc *)buf;
+			break;
+
+		default:
+			break;
+		}
+advance:
+		/* advance to next descriptor */
+		temp = buf[0];
+		buf += temp;
+		len -= temp;
+	}
+
+	/* check if we got everything */
+	if ((ctx->control == NULL) || (ctx->data == NULL) ||
+	    (ctx->ether_desc == NULL))
+		goto error;
+
+	/* claim interfaces, if any */
+	if (ctx->data != intf) {
+		temp = usb_driver_claim_interface(driver, ctx->data, dev);
+		if (temp)
+			goto error;
+		ctx->data_claimed = 1;
+	}
+
+	if (ctx->control != intf) {
+		temp = usb_driver_claim_interface(driver, ctx->control, dev);
+		if (temp)
+			goto error;
+		ctx->control_claimed = 1;
+	}
+
+	iface_no = ctx->data->cur_altsetting->desc.bInterfaceNumber;
+
+	/* reset data interface */
+	temp = usb_set_interface(dev->udev, iface_no, 0);
+	if (temp)
+		goto error;
+
+	/* initialize data interface */
+	if (cdc_ncm_setup(ctx))
+		goto error;
+
+	/* configure data interface */
+	temp = usb_set_interface(dev->udev, iface_no, 1);
+	if (temp)
+		goto error;
+
+	cdc_ncm_find_endpoints(ctx, ctx->data);
+	cdc_ncm_find_endpoints(ctx, ctx->control);
+
+	if ((ctx->in_ep == NULL) || (ctx->out_ep == NULL) ||
+	    (ctx->status_ep == NULL))
+		goto error;
+
+	dev->net->ethtool_ops = &cdc_ncm_ethtool_ops;
+
+	usb_set_intfdata(ctx->data, dev);
+	usb_set_intfdata(ctx->control, dev);
+	usb_set_intfdata(ctx->intf, dev);
+
+	temp = usbnet_get_ethernet_addr(dev, ctx->ether_desc->iMACAddress);
+	if (temp)
+		goto error;
+
+	dev_info(&dev->udev->dev, "MAC-Address: "
+				"0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x\n",
+				dev->net->dev_addr[0], dev->net->dev_addr[1],
+				dev->net->dev_addr[2], dev->net->dev_addr[3],
+				dev->net->dev_addr[4], dev->net->dev_addr[5]);
+
+	dev->in = usb_rcvbulkpipe(dev->udev,
+		ctx->in_ep->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
+	dev->out = usb_sndbulkpipe(dev->udev,
+		ctx->out_ep->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
+	dev->status = ctx->status_ep;
+	dev->rx_urb_size = ctx->rx_max;
+
+	/*
+	 * We should get an event when network connection is "connected" or
+	 * "disconnected". Set network connection in "disconnected" state
+	 * (carrier is OFF) during attach, so the IP network stack does not
+	 * start IPv6 negotiation and more.
+	 */
+	netif_carrier_off(dev->net);
+	ctx->tx_speed = ctx->rx_speed = 0;
+	return 0;
+
+error:
+	cdc_ncm_free((struct cdc_ncm_ctx *)dev->data[0]);
+	dev->data[0] = 0;
+	dev_info(&dev->udev->dev, "Descriptor failure\n");
+	return -ENODEV;
+}
+
+static void cdc_ncm_unbind(struct usbnet *dev, struct usb_interface *intf)
+{
+	struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
+	struct usb_driver *driver;
+
+	if (ctx == NULL)
+		return;		/* no setup */
+
+	driver = driver_of(intf);
+
+	usb_set_intfdata(ctx->data, NULL);
+	usb_set_intfdata(ctx->control, NULL);
+	usb_set_intfdata(ctx->intf, NULL);
+
+	/* release interfaces, if any */
+	if (ctx->data_claimed) {
+		usb_driver_release_interface(driver, ctx->data);
+		ctx->data_claimed = 0;
+	}
+
+	if (ctx->control_claimed) {
+		usb_driver_release_interface(driver, ctx->control);
+		ctx->control_claimed = 0;
+	}
+
+	cdc_ncm_free(ctx);
+}
+
+static void cdc_ncm_zero_fill(u8 *ptr, u32 first, u32 end, u32 max)
+{
+	if (first >= max)
+		return;
+	if (first >= end)
+		return;
+	if (end > max)
+		end = max;
+	memset(ptr + first, 0, end - first);
+}
+
+static struct sk_buff *
+cdc_ncm_fill_tx_frame(struct cdc_ncm_ctx *ctx, struct sk_buff *skb)
+{
+	struct sk_buff *skb_out;
+	u32 rem;
+	u32 offset;
+	u32 last_offset;
+	u16 n = 0;
+	u8 timeout = 0;
+
+	/* if there is a remaining skb, it gets priority */
+	if (skb != NULL)
+		swap(skb, ctx->tx_rem_skb);
+	else
+		timeout = 1;
+
+	/*
+	 * +----------------+
+	 * | skb_out        |
+	 * +----------------+
+	 *           ^ offset
+	 *        ^ last_offset
+	 */
+
+	/* check if we are resuming an OUT skb */
+	if (ctx->tx_curr_skb != NULL) {
+		/* pop variables */
+		skb_out = ctx->tx_curr_skb;
+		offset = ctx->tx_curr_offset;
+		last_offset = ctx->tx_curr_last_offset;
+		n = ctx->tx_curr_frame_num;
+
+	} else {
+		/* reset variables */
+		skb_out = alloc_skb(ctx->tx_max, GFP_ATOMIC);
+		if (skb_out == NULL) {
+			if (skb != NULL) {
+				dev_kfree_skb_any(skb);
+				ctx->netdev->stats.tx_dropped++;
+			}
+			goto exit_no_skb;
+		}
+
+		/* make room for NTH and NDP */
+		offset = ALIGN(sizeof(struct usb_cdc_ncm_nth16),
+					ctx->tx_ndp_modulus) +
+					sizeof(struct usb_cdc_ncm_ndp16) +
+					(ctx->tx_max_datagrams + 1) *
+					sizeof(struct usb_cdc_ncm_dpe16);
+
+		/* store last valid offset before alignment */
+		last_offset = offset;
+		/* align first Datagram offset correctly */
+		offset = ALIGN(offset, ctx->tx_modulus) + ctx->tx_remainder;
+		/* zero buffer till the first IP datagram */
+		cdc_ncm_zero_fill(skb_out->data, 0, offset, offset);
+		n = 0;
+		ctx->tx_curr_frame_num = 0;
+	}
+
+	for (; n < ctx->tx_max_datagrams; n++) {
+		/* check if end of transmit buffer is reached */
+		if (offset >= ctx->tx_max)
+			break;
+
+		/* compute maximum buffer size */
+		rem = ctx->tx_max - offset;
+
+		if (skb == NULL) {
+			skb = ctx->tx_rem_skb;
+			ctx->tx_rem_skb = NULL;
+
+			/* check for end of skb */
+			if (skb == NULL)
+				break;
+		}
+
+		if (skb->len > rem) {
+			if (n == 0) {
+				/* won't fit, MTU problem? */
+				dev_kfree_skb_any(skb);
+				skb = NULL;
+				ctx->netdev->stats.tx_dropped++;
+			} else {
+				/* no room for skb - store for later */
+				if (ctx->tx_rem_skb != NULL) {
+					dev_kfree_skb_any(ctx->tx_rem_skb);
+					ctx->netdev->stats.tx_dropped++;
+				}
+				ctx->tx_rem_skb = skb;
+				skb = NULL;
+
+				/* loop one more time */
+				timeout = 1;
+			}
+			break;
+		}
+
+		memcpy(((u8 *)skb_out->data) + offset, skb->data, skb->len);
+
+		ctx->tx_ncm.dpe16[n].wDatagramLength = cpu_to_le16(skb->len);
+		ctx->tx_ncm.dpe16[n].wDatagramIndex = cpu_to_le16(offset);
+
+		/* update offset */
+		offset += skb->len;
+
+		/* store last valid offset before alignment */
+		last_offset = offset;
+
+		/* align offset correctly */
+		offset = ALIGN(offset, ctx->tx_modulus) + ctx->tx_remainder;
+
+		/* zero padding */
+		cdc_ncm_zero_fill(skb_out->data, last_offset, offset,
+								ctx->tx_max);
+		dev_kfree_skb_any(skb);
+		skb = NULL;
+	}
+
+	/* free up any dangling skb */
+	if (skb != NULL) {
+		dev_kfree_skb_any(skb);
+		skb = NULL;
+		ctx->netdev->stats.tx_dropped++;
+	}
+
+	ctx->tx_curr_frame_num = n;
+
+	if (n == 0) {
+		/* wait for more frames */
+		/* push variables */
+		ctx->tx_curr_skb = skb_out;
+		ctx->tx_curr_offset = offset;
+		ctx->tx_curr_last_offset = last_offset;
+		goto exit_no_skb;
+
+	} else if ((n < ctx->tx_max_datagrams) && (timeout == 0)) {
+		/* wait for more frames */
+		/* push variables */
+		ctx->tx_curr_skb = skb_out;
+		ctx->tx_curr_offset = offset;
+		ctx->tx_curr_last_offset = last_offset;
+		/* set the pending count */
+		if (n < CDC_NCM_RESTART_TIMER_DATAGRAM_CNT)
+			ctx->tx_timer_pending = 2;
+		goto exit_no_skb;
+
+	} else {
+		/* frame goes out */
+		/* variables will be reset at next call */
+	}
+
+	/* check for overflow */
+	if (last_offset > ctx->tx_max)
+		last_offset = ctx->tx_max;
+
+	/* revert offset */
+	offset = last_offset;
+
+	/*
+	 * If collected data size is less or equal CDC_NCM_MIN_TX_PKT bytes,
+	 * we send buffers as it is. If we get more data, it would be more
+	 * efficient for USB HS mobile device with DMA engine to receive a full
+	 * size NTB, than canceling DMA transfer and receiving a short packet.
+	 */
+	if (offset > CDC_NCM_MIN_TX_PKT)
+		offset = ctx->tx_max;
+
+	/* final zero padding */
+	cdc_ncm_zero_fill(skb_out->data, last_offset, offset, ctx->tx_max);
+
+	/* store last offset */
+	last_offset = offset;
+
+	if ((last_offset < ctx->tx_max) && ((last_offset %
+			le16_to_cpu(ctx->out_ep->desc.wMaxPacketSize)) == 0)) {
+		/* force short packet */
+		*(((u8 *)skb_out->data) + last_offset) = 0;
+		last_offset++;
+	}
+
+	/* zero the rest of the DPEs plus the last NULL entry */
+	for (; n <= CDC_NCM_DPT_DATAGRAMS_MAX; n++) {
+		ctx->tx_ncm.dpe16[n].wDatagramLength = 0;
+		ctx->tx_ncm.dpe16[n].wDatagramIndex = 0;
+	}
+
+	/* fill out 16-bit NTB header */
+	ctx->tx_ncm.nth16.dwSignature = cpu_to_le32(USB_CDC_NCM_NTH16_SIGN);
+	ctx->tx_ncm.nth16.wHeaderLength =
+					cpu_to_le16(sizeof(ctx->tx_ncm.nth16));
+	ctx->tx_ncm.nth16.wSequence = cpu_to_le16(ctx->tx_seq);
+	ctx->tx_ncm.nth16.wBlockLength = cpu_to_le16(last_offset);
+	ctx->tx_ncm.nth16.wFpIndex = ALIGN(sizeof(struct usb_cdc_ncm_nth16),
+							ctx->tx_ndp_modulus);
+
+	memcpy(skb_out->data, &(ctx->tx_ncm.nth16), sizeof(ctx->tx_ncm.nth16));
+	ctx->tx_seq++;
+
+	/* fill out 16-bit NDP table */
+	ctx->tx_ncm.ndp16.dwSignature =
+				cpu_to_le32(USB_CDC_NCM_NDP16_NOCRC_SIGN);
+	rem = sizeof(ctx->tx_ncm.ndp16) + ((ctx->tx_curr_frame_num + 1) *
+					sizeof(struct usb_cdc_ncm_dpe16));
+	ctx->tx_ncm.ndp16.wLength = cpu_to_le16(rem);
+	ctx->tx_ncm.ndp16.wNextFpIndex = 0; /* reserved */
+
+	memcpy(((u8 *)skb_out->data) + ctx->tx_ncm.nth16.wFpIndex,
+						&(ctx->tx_ncm.ndp16),
+						sizeof(ctx->tx_ncm.ndp16));
+
+	memcpy(((u8 *)skb_out->data) + ctx->tx_ncm.nth16.wFpIndex +
+					sizeof(ctx->tx_ncm.ndp16),
+					&(ctx->tx_ncm.dpe16),
+					(ctx->tx_curr_frame_num + 1) *
+					sizeof(struct usb_cdc_ncm_dpe16));
+
+	/* set frame length */
+	skb_put(skb_out, last_offset);
+
+	/* return skb */
+	ctx->tx_curr_skb = NULL;
+	return skb_out;
+
+exit_no_skb:
+	return NULL;
+}
+
+static void cdc_ncm_tx_timeout_start(struct cdc_ncm_ctx *ctx)
+{
+	/* start timer, if not already started */
+	if (timer_pending(&ctx->tx_timer) == 0) {
+		ctx->tx_timer.function = &cdc_ncm_tx_timeout;
+		ctx->tx_timer.data = (unsigned long)ctx;
+		ctx->tx_timer.expires = jiffies + ((HZ + 999) / 1000);
+		add_timer(&ctx->tx_timer);
+	}
+}
+
+static void cdc_ncm_tx_timeout(unsigned long arg)
+{
+	struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)arg;
+	u8 restart;
+
+	spin_lock(&ctx->mtx);
+	if (ctx->tx_timer_pending != 0) {
+		ctx->tx_timer_pending--;
+		restart = 1;
+	} else
+		restart = 0;
+
+	spin_unlock(&ctx->mtx);
+
+	if (restart)
+		cdc_ncm_tx_timeout_start(ctx);
+	else if (ctx->netdev != NULL)
+		usbnet_start_xmit(NULL, ctx->netdev);
+}
+
+static struct sk_buff *
+cdc_ncm_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags)
+{
+	struct sk_buff *skb_out;
+	struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
+	u8 need_timer = 0;
+
+	/*
+	 * The Ethernet API we are using does not support transmitting
+	 * multiple Ethernet frames in a single call. This driver will
+	 * accumulate multiple Ethernet frames and send out a larger
+	 * USB frame when the USB buffer is full or when a single jiffies
+	 * timeout happens.
+	 */
+	if (ctx == NULL)
+		goto error;
+
+	spin_lock(&ctx->mtx);
+	skb_out = cdc_ncm_fill_tx_frame(ctx, skb);
+	if (ctx->tx_curr_skb != NULL)
+		need_timer = 1;
+	spin_unlock(&ctx->mtx);
+
+	/* Start timer, if there is a remaining skb */
+	if (need_timer)
+		cdc_ncm_tx_timeout_start(ctx);
+
+	if (skb_out)
+		dev->net->stats.tx_packets += ctx->tx_curr_frame_num;
+	return skb_out;
+
+error:
+	if (skb != NULL)
+		dev_kfree_skb_any(skb);
+
+	return NULL;
+}
+
+static int cdc_ncm_rx_fixup(struct usbnet *dev, struct sk_buff *skb_in)
+{
+	struct sk_buff *skb;
+	struct cdc_ncm_ctx *ctx;
+	int sumlen;
+	int actlen;
+	int temp;
+	int nframes;
+	int x;
+	int offset;
+
+	ctx = (struct cdc_ncm_ctx *)dev->data[0];
+	if (ctx == NULL)
+		goto error;
+
+	actlen = skb_in->len;
+	sumlen = CDC_NCM_NTB_MAX_SIZE_RX;
+
+	if (actlen < (sizeof(ctx->rx_ncm.nth16) + sizeof(ctx->rx_ncm.ndp16))) {
+		pr_debug("frame too short\n");
+		goto error;
+	}
+
+	memcpy(&(ctx->rx_ncm.nth16), ((u8 *)skb_in->data),
+						sizeof(ctx->rx_ncm.nth16));
+
+	if (le32_to_cpu(ctx->rx_ncm.nth16.dwSignature) !=
+	    USB_CDC_NCM_NTH16_SIGN) {
+		pr_debug("invalid NTH16 signature <%u>\n",
+			 le32_to_cpu(ctx->rx_ncm.nth16.dwSignature));
+		goto error;
+	}
+
+	temp = le16_to_cpu(ctx->rx_ncm.nth16.wBlockLength);
+	if (temp > sumlen) {
+		pr_debug("unsupported NTB block length %u/%u\n", temp, sumlen);
+		goto error;
+	}
+
+	temp = le16_to_cpu(ctx->rx_ncm.nth16.wFpIndex);
+	if ((temp + sizeof(ctx->rx_ncm.ndp16)) > actlen) {
+		pr_debug("invalid DPT16 index\n");
+		goto error;
+	}
+
+	memcpy(&(ctx->rx_ncm.ndp16), ((u8 *)skb_in->data) + temp,
+						sizeof(ctx->rx_ncm.ndp16));
+
+	if (le32_to_cpu(ctx->rx_ncm.ndp16.dwSignature) !=
+	    USB_CDC_NCM_NDP16_NOCRC_SIGN) {
+		pr_debug("invalid DPT16 signature <%u>\n",
+			 le32_to_cpu(ctx->rx_ncm.ndp16.dwSignature));
+		goto error;
+	}
+
+	if (le16_to_cpu(ctx->rx_ncm.ndp16.wLength) <
+	    USB_CDC_NCM_NDP16_LENGTH_MIN) {
+		pr_debug("invalid DPT16 length <%u>\n",
+			 le32_to_cpu(ctx->rx_ncm.ndp16.dwSignature));
+		goto error;
+	}
+
+	nframes = ((le16_to_cpu(ctx->rx_ncm.ndp16.wLength) -
+					sizeof(struct usb_cdc_ncm_ndp16)) /
+					sizeof(struct usb_cdc_ncm_dpe16));
+	nframes--; /* we process NDP entries except for the last one */
+
+	pr_debug("nframes = %u\n", nframes);
+
+	temp += sizeof(ctx->rx_ncm.ndp16);
+
+	if ((temp + nframes * (sizeof(struct usb_cdc_ncm_dpe16))) > actlen) {
+		pr_debug("Invalid nframes = %d\n", nframes);
+		goto error;
+	}
+
+	if (nframes > CDC_NCM_DPT_DATAGRAMS_MAX) {
+		pr_debug("Truncating number of frames from %u to %u\n",
+					nframes, CDC_NCM_DPT_DATAGRAMS_MAX);
+		nframes = CDC_NCM_DPT_DATAGRAMS_MAX;
+	}
+
+	memcpy(&(ctx->rx_ncm.dpe16), ((u8 *)skb_in->data) + temp,
+				nframes * (sizeof(struct usb_cdc_ncm_dpe16)));
+
+	for (x = 0; x < nframes; x++) {
+		offset = le16_to_cpu(ctx->rx_ncm.dpe16[x].wDatagramIndex);
+		temp = le16_to_cpu(ctx->rx_ncm.dpe16[x].wDatagramLength);
+
+		/*
+		 * CDC NCM ch. 3.7
+		 * All entries after first NULL entry are to be ignored
+		 */
+		if ((offset == 0) || (temp == 0)) {
+			if (!x)
+				goto error; /* empty NTB */
+			break;
+		}
+
+		/* sanity checking */
+		if (((offset + temp) > actlen) ||
+		    (temp > CDC_NCM_MAX_DATAGRAM_SIZE) || (temp < ETH_HLEN)) {
+			pr_debug("invalid frame detected (ignored)"
+				"offset[%u]=%u, length=%u, skb=%p\n",
+							x, offset, temp, skb);
+			if (!x)
+				goto error;
+			break;
+
+		} else {
+			skb = skb_clone(skb_in, GFP_ATOMIC);
+			skb->len = temp;
+			skb->data = ((u8 *)skb_in->data) + offset;
+			skb_set_tail_pointer(skb, temp);
+			usbnet_skb_return(dev, skb);
+		}
+	}
+	return 1;
+error:
+	return 0;
+}
+
+static void
+cdc_ncm_speed_change(struct cdc_ncm_ctx *ctx,
+		     struct connection_speed_change *data)
+{
+	uint32_t rx_speed = le32_to_cpu(data->USBitRate);
+	uint32_t tx_speed = le32_to_cpu(data->DSBitRate);
+
+	/*
+	 * Currently the USB-NET API does not support reporting the actual
+	 * device speed. Do print it instead.
+	 */
+	if ((tx_speed != ctx->tx_speed) || (rx_speed != ctx->rx_speed)) {
+		ctx->tx_speed = tx_speed;
+		ctx->rx_speed = rx_speed;
+
+		if ((tx_speed > 1000000) && (rx_speed > 1000000)) {
+			printk(KERN_INFO KBUILD_MODNAME
+				": %s: %u mbit/s downlink "
+				"%u mbit/s uplink\n",
+				ctx->netdev->name,
+				(unsigned int)(rx_speed / 1000000U),
+				(unsigned int)(tx_speed / 1000000U));
+		} else {
+			printk(KERN_INFO KBUILD_MODNAME
+				": %s: %u kbit/s downlink "
+				"%u kbit/s uplink\n",
+				ctx->netdev->name,
+				(unsigned int)(rx_speed / 1000U),
+				(unsigned int)(tx_speed / 1000U));
+		}
+	}
+}
+
+static void cdc_ncm_status(struct usbnet *dev, struct urb *urb)
+{
+	struct cdc_ncm_ctx *ctx;
+	struct usb_cdc_notification *event;
+
+	ctx = (struct cdc_ncm_ctx *)dev->data[0];
+
+	if (urb->actual_length < sizeof(*event))
+		return;
+
+	/* test for split data in 8-byte chunks */
+	if (test_and_clear_bit(EVENT_STS_SPLIT, &dev->flags)) {
+		cdc_ncm_speed_change(ctx,
+		      (struct connection_speed_change *)urb->transfer_buffer);
+		return;
+	}
+
+	event = urb->transfer_buffer;
+
+	switch (event->bNotificationType) {
+	case USB_CDC_NOTIFY_NETWORK_CONNECTION:
+		/*
+		 * According to the CDC NCM specification ch.7.1
+		 * USB_CDC_NOTIFY_NETWORK_CONNECTION notification shall be
+		 * sent by device after USB_CDC_NOTIFY_SPEED_CHANGE.
+		 */
+		ctx->connected = event->wValue;
+
+		printk(KERN_INFO KBUILD_MODNAME ": %s: network connection:"
+			" %sconnected\n",
+			ctx->netdev->name, ctx->connected ? "" : "dis");
+
+		if (ctx->connected)
+			netif_carrier_on(dev->net);
+		else {
+			netif_carrier_off(dev->net);
+			ctx->tx_speed = ctx->rx_speed = 0;
+		}
+		break;
+
+	case USB_CDC_NOTIFY_SPEED_CHANGE:
+		if (urb->actual_length <
+		    (sizeof(*event) + sizeof(struct connection_speed_change)))
+			set_bit(EVENT_STS_SPLIT, &dev->flags);
+		else
+			cdc_ncm_speed_change(ctx,
+				(struct connection_speed_change *) &event[1]);
+		break;
+
+	default:
+		dev_err(&dev->udev->dev, "NCM: unexpected "
+			"notification 0x%02x!\n", event->bNotificationType);
+		break;
+	}
+}
+
+static int cdc_ncm_check_connect(struct usbnet *dev)
+{
+	struct cdc_ncm_ctx *ctx;
+
+	ctx = (struct cdc_ncm_ctx *)dev->data[0];
+	if (ctx == NULL)
+		return 1;	/* disconnected */
+
+	return !ctx->connected;
+}
+
+static int
+cdc_ncm_probe(struct usb_interface *udev, const struct usb_device_id *prod)
+{
+	return usbnet_probe(udev, prod);
+}
+
+static void cdc_ncm_disconnect(struct usb_interface *intf)
+{
+	struct usbnet *dev = usb_get_intfdata(intf);
+
+	if (dev == NULL)
+		return;		/* already disconnected */
+
+	usbnet_disconnect(intf);
+}
+
+static int cdc_ncm_manage_power(struct usbnet *dev, int status)
+{
+	dev->intf->needs_remote_wakeup = status;
+	return 0;
+}
+
+static const struct driver_info cdc_ncm_info = {
+	.description = "CDC NCM",
+	.flags = FLAG_NO_SETINT | FLAG_MULTI_PACKET,
+	.bind = cdc_ncm_bind,
+	.unbind = cdc_ncm_unbind,
+	.check_connect = cdc_ncm_check_connect,
+	.manage_power = cdc_ncm_manage_power,
+	.status = cdc_ncm_status,
+	.rx_fixup = cdc_ncm_rx_fixup,
+	.tx_fixup = cdc_ncm_tx_fixup,
+};
+
+static struct usb_driver cdc_ncm_driver = {
+	.name = "cdc_ncm",
+	.id_table = cdc_devs,
+	.probe = cdc_ncm_probe,
+	.disconnect = cdc_ncm_disconnect,
+	.suspend = usbnet_suspend,
+	.resume = usbnet_resume,
+	.supports_autosuspend = 1,
+};
+
+static struct ethtool_ops cdc_ncm_ethtool_ops = {
+	.get_drvinfo = cdc_ncm_get_drvinfo,
+	.get_link = usbnet_get_link,
+	.get_msglevel = usbnet_get_msglevel,
+	.set_msglevel = usbnet_set_msglevel,
+	.get_settings = usbnet_get_settings,
+	.set_settings = usbnet_set_settings,
+	.nway_reset = usbnet_nway_reset,
+};
+
+static int __init cdc_ncm_init(void)
+{
+	printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION "\n");
+	return usb_register(&cdc_ncm_driver);
+}
+
+module_init(cdc_ncm_init);
+
+static void __exit cdc_ncm_exit(void)
+{
+	usb_deregister(&cdc_ncm_driver);
+}
+
+module_exit(cdc_ncm_exit);
+
+MODULE_AUTHOR("Hans Petter Selasky");
+MODULE_DESCRIPTION("USB CDC NCM host driver");
+MODULE_LICENSE("Dual BSD/GPL");
-- 
1.7.3.2


^ permalink raw reply related

* Re: multi bpf filter will impact performance?
From: Eric Dumazet @ 2010-11-30  9:34 UTC (permalink / raw)
  To: Rui; +Cc: netdev
In-Reply-To: <AANLkTikx68M43+vv+Rav_HCJMJnuc15TtuBgmbv2xP=U@mail.gmail.com>

Le mardi 30 novembre 2010 à 17:22 +0800, Rui a écrit :
> hi
> 
> I did a test with an intel X520 10Gnic, HP DL380 G6,  to see how the
> bpf filter will impact the performance.
> 
> kernel .2.6.32 SLES11+SP1, original ixgbe driver
> 

Could you try latest net-next-2.6, we optimized bpf a bit lately

commit 93aaae2e01e57483256b7da05c9a7ebd65ad4686
Author: Eric Dumazet <eric.dumazet@gmail.com>
Date:   Fri Nov 19 09:49:59 2010 -0800

    filter: optimize sk_run_filter
    


> step 0:
> launch 4 tcpdump processes,each applied a filter to filter out some
> GTP-U packets. seen with 'tcpdump -d', the bpf code has about 100
> lines.
> 
> #!/bin/sh
> PCAP_FRAMES=32000 ./tcpdump_MMAP -i eth4 'udp dst port 2152 and (
> (((ether[48:1]&0x07)>0) and
> (((ether[66:1]+ether[67:1]+ether[68:1]+ether[69:1]+ether[70:1]+ether[71:1]+ether[72:1]+ether[73:1])&0x03)==0))
> or (((ether[48:1]&0x07)==0) and
> (((ether[62:1]+ether[63:1]+ether[64:1]+ether[65:1]+ether[66:1]+ether[67:1]+ether[68:1]+ether[69:1])&0x03)==0))
> ) ' -w /dev/null -s 4096 2>f1.log &
> PCAP_FRAMES=32000 ./tcpdump_MMAP -i eth4 'udp dst port 2152 and (
> (((ether[48:1]&0x07)>0) and
> (((ether[66:1]+ether[67:1]+ether[68:1]+ether[69:1]+ether[70:1]+ether[71:1]+ether[72:1]+ether[73:1])&0x03)==1))
> or (((ether[48:1]&0x07)==0) and
> (((ether[62:1]+ether[63:1]+ether[64:1]+ether[65:1]+ether[66:1]+ether[67:1]+ether[68:1]+ether[69:1])&0x03)==1))
> ) ' -w /dev/null -s 4096 2>f2.log &
> PCAP_FRAMES=32000 ./tcpdump_MMAP -i eth4 'udp dst port 2152 and (
> (((ether[48:1]&0x07)>0) and
> (((ether[66:1]+ether[67:1]+ether[68:1]+ether[69:1]+ether[70:1]+ether[71:1]+ether[72:1]+ether[73:1])&0x03)==2))
> or (((ether[48:1]&0x07)==0) and
> (((ether[62:1]+ether[63:1]+ether[64:1]+ether[65:1]+ether[66:1]+ether[67:1]+ether[68:1]+ether[69:1])&0x03)==2))
> ) ' -w /dev/null -s 4096 2>f3.log &
> PCAP_FRAMES=32000 ./tcpdump_MMAP -i eth4 'udp dst port 2152 and (
> (((ether[48:1]&0x07)>0) and
> (((ether[66:1]+ether[67:1]+ether[68:1]+ether[69:1]+ether[70:1]+ether[71:1]+ether[72:1]+ether[73:1])&0x03)==3))
> or (((ether[48:1]&0x07)==0) and
> (((ether[62:1]+ether[63:1]+ether[64:1]+ether[65:1]+ether[66:1]+ether[67:1]+ether[68:1]+ether[69:1])&0x03)==3))
> ) ' -w /dev/null -s 4096 2>f4.log &
> 
> 

Hmm, do you receive trafic on several queues of your card ?

Do you have 4 cpus running ?

grep eth /proc/interrupts


> step1:
> use stress test equipment to generate traffic >1.2Gbps
> 
> 
> step2:
> type 'ifconfig eth4'
> saw many packets dropped
> 
> step3:
> type 'sar -n DEV 1', the incoming throughput limited at 800Mbps
> 
> 
> my questions:
> 
> Q1. the bpf filter is run one by one? will only one filter be executed
> for one sock? (so that the tcpdump corresponding kernel part will run
> filter in parallel?)
> 

bpf filter is run on behalf of the softirq processing.

> Q2. performance is bad? any idea to improve it?
> 

multiqueue card : split each IRQ on a separate cpu.

If not multiqueue card : use RPS on a recent kernel to split the load on
several cpus.

Use a filter against the queue, instead of doing a hash code yourself in
the bpf. (code added in commit d19742fb (linux-2.6.33)

(you need to tweak libpcap to use SKF_AD_QUEUE instruction)

commit d19742fb1c68e6db83b76e06dea5a374c99e104f
Author: Eric Dumazet <eric.dumazet@gmail.com>
Date:   Tue Oct 20 01:06:22 2009 -0700

    filter: Add SKF_AD_QUEUE instruction
    
    It can help being able to filter packets on their queue_mapping.
    
    If filter performance is not good, we could add a "numqueue" field
    in struct packet_type, so that netif_nit_deliver() and other functions
    can directly ignore packets with not expected queue number.
    
    Lets experiment this simple filter extension first.






^ permalink raw reply

* Re: [PATCH v2 4/4] kthread: use kthread_create_on_cpu()
From: David Howells @ 2010-11-30  9:38 UTC (permalink / raw)
  To: Eric Dumazet
  Cc: dhowells, Andi Kleen, Andrew Morton, linux-kernel, netdev,
	David Miller, Tejun Heo, Rusty Russell, linux-arch
In-Reply-To: <1291043719.3435.981.camel@edumazet-laptop>

Eric Dumazet <eric.dumazet@gmail.com> wrote:

> +		p = kthread_create_on_cpu(run_ksoftirqd, hcpu, hotcpu,
> +					  "ksoftirqd/%d", hotcpu);

Does kthread_create_on_cpu() need to take hotcpu twice?  Can one of the
arguments be folded into the other?

David

^ permalink raw reply

* Re: [PATCH] Net-ethtool : Allow ethtool to set interface in loopback mode.
From: Simon Horman @ 2010-11-30  9:48 UTC (permalink / raw)
  To: Mahesh Bandewar; +Cc: David Miller, linux-netdev
In-Reply-To: <AANLkTikVaVv4fkLom+NSQgOUzCd2i3mbHkBNQ6PD4d9Y@mail.gmail.com>

On Tue, Nov 30, 2010 at 12:00:29AM -0800, Mahesh Bandewar wrote:
> This patch enables ethtool to set the loopback mode on a given
> interface. This is the reworked version of earlier submit (which I
> don't have reference to). By configuring the interface in loopback
> mode in conjunction with a policy route / rule, a userland application
> can stress the egress / ingress path exposing the flows of the change
> in progress and potentially help developer(s) understand the impact of
> those changes without even sending a packet out on the network.
> 
> Following set of commands illustrates one such example -
>     a) ifconfig eth1 192.168.1.1

         Given that b) and c) use ip it seems to me that it would
	 make sense to use i for a) too. 

	 ip addr add 192.168.1.1/24 dev eth1

>     b) ip -4 rule add from all iif eth1 lookup 250
>     c) ip -4 route add local 0/0 dev lo proto kernel scope host table 250
>     d) arp -Ds 192.168.1.100 eth1
>     e) arp -Ds 192.168.1.200 eth1
>     f) sysctl -w net.ipv4.ip_nonlocal_bind=1
>     g) sysctl -w net.ipv4.conf.all.accept_local=1
>     # Assuming that the machine has 8 cores
>     h) taskset 000f netserver -L 192.168.1.200
>     i) taskset 00f0 netperf -t TCP_CRR -L 192.168.1.100 -H 192.168.1.200 -l 30

^ permalink raw reply

* Re: [PATCH v2 4/4] kthread: use kthread_create_on_cpu()
From: Eric Dumazet @ 2010-11-30  9:59 UTC (permalink / raw)
  To: David Howells
  Cc: Andi Kleen, Andrew Morton, linux-kernel, netdev, David Miller,
	Tejun Heo, Rusty Russell, linux-arch
In-Reply-To: <15903.1291109892@redhat.com>

Le mardi 30 novembre 2010 à 09:38 +0000, David Howells a écrit :
> Eric Dumazet <eric.dumazet@gmail.com> wrote:
> 
> > +		p = kthread_create_on_cpu(run_ksoftirqd, hcpu, hotcpu,
> > +					  "ksoftirqd/%d", hotcpu);
> 
> Does kthread_create_on_cpu() need to take hotcpu twice?  Can one of the
> arguments be folded into the other?
> 
> David

The second one is used in a printf() like to build a string, its not
really part of the API..

Caller could do instead :

char name[32];
sprintf(name, "ksoftirqd/%d", whatever_id);
p = kthread_create_on_cpu(run_ksoftirqd, hcpu, hotcpu, name);

^ permalink raw reply

* Re: multi bpf filter will impact performance?
From: Eric Dumazet @ 2010-11-30 10:01 UTC (permalink / raw)
  To: Rui; +Cc: netdev
In-Reply-To: <AANLkTikx68M43+vv+Rav_HCJMJnuc15TtuBgmbv2xP=U@mail.gmail.com>

Le mardi 30 novembre 2010 à 17:22 +0800, Rui a écrit :

> step 0:
> launch 4 tcpdump processes,each applied a filter to filter out some
> GTP-U packets. seen with 'tcpdump -d', the bpf code has about 100
> lines.

So each incoming packet has to go through your 4 filters, thats a total
of ~400 bpf instructions. (a bit less in average because of the
conditionnal branches)




^ permalink raw reply

* [PATCH] bonding: add the sysfs interface to see RLB hash table
From: Taku Izumi @ 2010-11-30 10:01 UTC (permalink / raw)
  To: netdev@vger.kernel.org, Jay Vosburgh


This patch provides the sysfs interface to see RLB hash table
like the following:

# cat /sys/class/net/bond0/bonding/rlb_hash_table

SourceIP        DestinationIP   Destination MAC   DEV
 10.124.196.205  10.124.196. 81 00:19:99:XX:XX:XX eth3
 10.124.196.205  10.124.196.222 00:0a:79:XX:XX:XX eth0
 10.124.196.205  10.124.196. 75 00:15:17:XX:XX:XX eth4
 10.124.196.205  10.124.196.  1 00:21:d8:XX:XX:XX eth3
 10.124.196.205  10.124.196.205 ff:ff:ff:ff:ff:ff eth0


This is helpful to check if the receive load balancing works as expected.

Signed-off-by: Taku Izumi <izumi.taku@jp.fujitsu.com>

---
 drivers/net/bonding/bond_sysfs.c |   56 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 56 insertions(+)

Index: net-next/drivers/net/bonding/bond_sysfs.c
===================================================================
--- net-next.orig/drivers/net/bonding/bond_sysfs.c
+++ net-next/drivers/net/bonding/bond_sysfs.c
@@ -43,6 +43,7 @@
 #include <linux/nsproxy.h>

 #include "bonding.h"
+#include "bond_alb.h"

 #define to_dev(obj)	container_of(obj, struct device, kobj)
 #define to_bond(cd)	((struct bonding *)(netdev_priv(to_net_dev(cd))))
@@ -1643,6 +1644,60 @@ out:
 static DEVICE_ATTR(resend_igmp, S_IRUGO | S_IWUSR,
 		   bonding_show_resend_igmp, bonding_store_resend_igmp);

+/*
+ *  Show RLB hash table
+ */
+#define RLB_NULL_INDEX  0xffffffff
+static ssize_t bonding_show_rlb_hashtable(struct device *d,
+					  struct device_attribute *attr,
+					  char *buf)
+{
+	int count = 0;
+	struct bonding *bond = to_bond(d);
+	struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
+	struct rlb_client_info *client_info;
+	u32 hash_index;
+
+	if (bond->params.mode != BOND_MODE_ALB)
+		return count;
+
+	count += sprintf(buf + count, "SourceIP        "
+		"DestinationIP   Destination MAC   DEV\n");
+
+	spin_lock_bh(&(BOND_ALB_INFO(bond).rx_hashtbl_lock));
+
+	hash_index = bond_info->rx_hashtbl_head;
+	for (; hash_index != RLB_NULL_INDEX; hash_index = client_info->next) {
+		client_info = &(bond_info->rx_hashtbl[hash_index]);
+
+		count += sprintf(buf + count,
+			"%3d.%3d.%3d.%3d %3d.%3d.%3d.%3d "
+			"%02x:%02x:%02x:%02x:%02x:%02x %s\n",
+			client_info->ip_src & 0xff,
+			(client_info->ip_src >> 8) & 0xff,
+			(client_info->ip_src >> 16) & 0xff,
+			(client_info->ip_src >> 24) & 0xff,
+			client_info->ip_dst & 0xff,
+			(client_info->ip_dst >> 8) & 0xff,
+			(client_info->ip_dst >> 16) & 0xff,
+			(client_info->ip_dst >> 24) & 0xff,
+			client_info->mac_dst[0],
+			client_info->mac_dst[1],
+			client_info->mac_dst[2],
+			client_info->mac_dst[3],
+			client_info->mac_dst[4],
+			client_info->mac_dst[5],
+			client_info->slave->dev->name);
+	}
+
+	spin_unlock_bh(&(BOND_ALB_INFO(bond).rx_hashtbl_lock));
+
+	return count;
+
+}
+static DEVICE_ATTR(rlb_hash_table, S_IRUGO, bonding_show_rlb_hashtable, NULL);
+
+
 static struct attribute *per_bond_attrs[] = {
 	&dev_attr_slaves.attr,
 	&dev_attr_mode.attr,
@@ -1671,6 +1726,7 @@ static struct attribute *per_bond_attrs[
 	&dev_attr_queue_id.attr,
 	&dev_attr_all_slaves_active.attr,
 	&dev_attr_resend_igmp.attr,
+	&dev_attr_rlb_hash_table.attr,
 	NULL,
 };



^ permalink raw reply

* Re: [PATCH] bonding: add the sysfs interface to see RLB hash table
From: Eric Dumazet @ 2010-11-30 10:10 UTC (permalink / raw)
  To: Taku Izumi; +Cc: netdev@vger.kernel.org, Jay Vosburgh
In-Reply-To: <4CF4CB85.4010708@jp.fujitsu.com>

Le mardi 30 novembre 2010 à 19:01 +0900, Taku Izumi a écrit :
> This patch provides the sysfs interface to see RLB hash table
> like the following:
> 
> # cat /sys/class/net/bond0/bonding/rlb_hash_table
> 
> SourceIP        DestinationIP   Destination MAC   DEV
>  10.124.196.205  10.124.196. 81 00:19:99:XX:XX:XX eth3
>  10.124.196.205  10.124.196.222 00:0a:79:XX:XX:XX eth0
>  10.124.196.205  10.124.196. 75 00:15:17:XX:XX:XX eth4
>  10.124.196.205  10.124.196.  1 00:21:d8:XX:XX:XX eth3
>  10.124.196.205  10.124.196.205 ff:ff:ff:ff:ff:ff eth0
> 

why spaces in IP addresses ?

> 
> This is helpful to check if the receive load balancing works as expected.
> 
> Signed-off-by: Taku Izumi <izumi.taku@jp.fujitsu.com>
> 
> ---
>  drivers/net/bonding/bond_sysfs.c |   56 +++++++++++++++++++++++++++++++++++++++
>  1 file changed, 56 insertions(+)
> 
> Index: net-next/drivers/net/bonding/bond_sysfs.c
> ===================================================================
> --- net-next.orig/drivers/net/bonding/bond_sysfs.c
> +++ net-next/drivers/net/bonding/bond_sysfs.c
> @@ -43,6 +43,7 @@
>  #include <linux/nsproxy.h>
> 
>  #include "bonding.h"
> +#include "bond_alb.h"
> 
>  #define to_dev(obj)	container_of(obj, struct device, kobj)
>  #define to_bond(cd)	((struct bonding *)(netdev_priv(to_net_dev(cd))))
> @@ -1643,6 +1644,60 @@ out:
>  static DEVICE_ATTR(resend_igmp, S_IRUGO | S_IWUSR,
>  		   bonding_show_resend_igmp, bonding_store_resend_igmp);
> 
> +/*
> + *  Show RLB hash table
> + */
> +#define RLB_NULL_INDEX  0xffffffff
> +static ssize_t bonding_show_rlb_hashtable(struct device *d,
> +					  struct device_attribute *attr,
> +					  char *buf)
> +{
> +	int count = 0;
> +	struct bonding *bond = to_bond(d);
> +	struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
> +	struct rlb_client_info *client_info;
> +	u32 hash_index;
> +
> +	if (bond->params.mode != BOND_MODE_ALB)
> +		return count;
> +
> +	count += sprintf(buf + count, "SourceIP        "
> +		"DestinationIP   Destination MAC   DEV\n");
> +
> +	spin_lock_bh(&(BOND_ALB_INFO(bond).rx_hashtbl_lock));
> +
> +	hash_index = bond_info->rx_hashtbl_head;
> +	for (; hash_index != RLB_NULL_INDEX; hash_index = client_info->next) {
> +		client_info = &(bond_info->rx_hashtbl[hash_index]);
> +
> +		count += sprintf(buf + count,
> +			"%3d.%3d.%3d.%3d %3d.%3d.%3d.%3d "
> +			"%02x:%02x:%02x:%02x:%02x:%02x %s\n",


Oh well, I guess you dont read Joe patches on netdev ;)

Please take a look at %pI4 and %pM

sprintf(buf + count, "%pI4 %pI4 %pM %s\n", ...)


> +			client_info->ip_src & 0xff,
> +			(client_info->ip_src >> 8) & 0xff,
> +			(client_info->ip_src >> 16) & 0xff,
> +			(client_info->ip_src >> 24) & 0xff,
> +			client_info->ip_dst & 0xff,
> +			(client_info->ip_dst >> 8) & 0xff,
> +			(client_info->ip_dst >> 16) & 0xff,
> +			(client_info->ip_dst >> 24) & 0xff,
> +			client_info->mac_dst[0],
> +			client_info->mac_dst[1],
> +			client_info->mac_dst[2],
> +			client_info->mac_dst[3],
> +			client_info->mac_dst[4],
> +			client_info->mac_dst[5],
> +			client_info->slave->dev->name);
> +	}
> +


^ permalink raw reply

* Get the credentials from the socket peer file struct
From: Laszlo Papp @ 2010-11-30 10:13 UTC (permalink / raw)
  To: netdev

Hi,

How can I get the socket peer file struct ?
I would like to implement a new ioctl in my kernelspace code (similar
to SO_PEERCRED), but to get all the credentials.

The file struct of the socket struct has a cred struct members, but
that is for the local file struct, not from the peer file struct.

I tried to grok the documentation, but I do not entirely understand
the 'struct sock' internals.
(http://lxr.free-electrons.com/source/include/net/sock.h?v=2.6.32;a=arm#L144)
SO_PEERCRED just picks 'sk_peercred' struct ucred structure up from
there, but I need a more fine-tuned const struct cred structure in
this special case.

I am not subscrobed for the list, so please add me into the 'CC'
field. Thank you in advance!

Best Regards,
Laszlo Papp

^ permalink raw reply

* [PATCH] stmmac: priv->lock can be used uninitialized
From: Vlad Lungu @ 2010-11-30  8:52 UTC (permalink / raw)
  To: netdev; +Cc: peppe.cavallaro, davem, Vlad Lungu

To reproduce: if connman (http://connman.net/) is started,
inserting the stmmac module triggers a "BUG: spinlock bad magic on CPU#0".

Registering the device in stmmac_probe() sends a notification to connman
which brings the interface up before the lock is initialized.

Signed-off-by: Vlad Lungu <vlad.lungu@windriver.com>
---
 drivers/net/stmmac/stmmac_main.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/net/stmmac/stmmac_main.c b/drivers/net/stmmac/stmmac_main.c
index 730a6fd..e960501 100644
--- a/drivers/net/stmmac/stmmac_main.c
+++ b/drivers/net/stmmac/stmmac_main.c
@@ -1516,6 +1516,8 @@ static int stmmac_probe(struct net_device *dev)
 		pr_warning("\tno valid MAC address;"
 			"please, use ifconfig or nwhwconfig!\n");
 
+	spin_lock_init(&priv->lock);
+
 	ret = register_netdev(dev);
 	if (ret) {
 		pr_err("%s: ERROR %i registering the device\n",
@@ -1527,8 +1529,6 @@ static int stmmac_probe(struct net_device *dev)
 	    dev->name, (dev->features & NETIF_F_SG) ? "on" : "off",
 	    (dev->features & NETIF_F_HW_CSUM) ? "on" : "off");
 
-	spin_lock_init(&priv->lock);
-
 	return ret;
 }
 
-- 
1.6.0.2


^ permalink raw reply related


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