* Re: [PATCH v2 0/4] net: Revive fixed link support
From: David Miller @ 2009-07-22 16:20 UTC (permalink / raw)
To: grant.likely; +Cc: avorontsov, afleming, netdev, linuxppc-dev, leoli
In-Reply-To: <fa686aa40907181137v4a0ed1ednfed3194d1308296a@mail.gmail.com>
From: Grant Likely <grant.likely@secretlab.ca>
Date: Sat, 18 Jul 2009 12:37:34 -0600
> Awesome. Dave, can you please pick up this series?
Sure thing.
^ permalink raw reply
* Re: [PATCH] softirq: tasklet_hrtimer
From: Linus Torvalds @ 2009-07-22 16:01 UTC (permalink / raw)
To: Peter Zijlstra; +Cc: David Miller, tglx, netdev, linux-kernel, kaber
In-Reply-To: <1248265724.27058.1366.camel@twins>
On Wed, 22 Jul 2009, Peter Zijlstra wrote:
>
> Stick tasklets and hrtimers together to provide an in-softirq hrtimer
> experience.
>
> Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Looks ok by me now.
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Thanks,
Linus
^ permalink raw reply
* Re: b44: device restarts on heavy load
From: David Miller @ 2009-07-22 15:56 UTC (permalink / raw)
To: info; +Cc: netdev
In-Reply-To: <4A37B60C.7000303@dupondje.be>
From: Jean-Louis Dupond <info@dupondje.be>
Date: Tue, 16 Jun 2009 17:11:08 +0200
> To be more precise, the error is ISTAT_RFO 0x00004000 /* Receive FIFO
> Overflow */
The problem is that we need to know if a receive FIFO overflow
puts the chip into a state where it must be reset.
And until we know that, we cannot simply exclude that condition
from the reset test.
^ permalink raw reply
* Re: [PATCH 1/1] veth: don't free priv->status until dev->destructor (v2)
From: Serge E. Hallyn @ 2009-07-22 15:55 UTC (permalink / raw)
To: Stephen Hemminger
Cc: David Miller, containers, sachinp, netdev, matthltc, linux-kernel
In-Reply-To: <20090720142542.4fb12c12@nehalam>
Quoting Stephen Hemminger (shemminger@vyatta.com):
> On Wed, 15 Jul 2009 08:50:12 -0700 (PDT)
> David Miller <davem@davemloft.net> wrote:
>
> > From: "Serge E. Hallyn" <serue@us.ibm.com>
> > Date: Fri, 26 Jun 2009 11:24:18 -0500
> >
> > > I haven't been able to reproduce the original oops though (been
> > > trying to cat the stats sysfs files while rmmoding veth, to no
> > > avail, and haven't found an original bug report or testcase), so
> > > can't verify whether this patch prevents the original oops.
> >
> > If you 'cat' it you're unlikely to trigger the oops.
> >
> > You have to hold the sysfs files open, and then elsewhere do the
> > rmmod, wait, and then continue with some access to those open sysfs
> > file descriptors (f.e. do some reads).
Yup, I was doing that too, but couldn't reproduce as yet.
> > I'd also need this patch to be against current sources as they'll
> > never apply since I did the revert quite some time ago.
> >
> > Thanks.
Ok, thanks - I'll generate a new patch against a fresh pull when
I can confirm that it actually solves the problem.
> My usual way of doing this is:
>
> # (sleep 30; cat /sys/class/net/ethX/statistics/tx_bytes) &
> # rmmod the_buggy_driver
>
> wait...
Can you oops the kernel this way on latest netns?
thanks,
-serge
^ permalink raw reply
* Re: [PATCH V2 net-next-2.6] net: relax dst refcnt in input path
From: Eric Dumazet @ 2009-07-22 15:40 UTC (permalink / raw)
To: Patrick McHardy; +Cc: David S. Miller, Linux Netdev List, Mark McLoughlin
In-Reply-To: <4A6708A6.1090200@trash.net>
Patrick McHardy a écrit :
> Eric Dumazet wrote:
>> diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c
>> index db46b4b..23e974b 100644
>> --- a/net/ipv4/ip_input.c
>> +++ b/net/ipv4/ip_input.c
>> @@ -331,7 +331,7 @@ static int ip_rcv_finish(struct sk_buff *skb)
>> */
>> if (skb_dst(skb) == NULL) {
>> int err = ip_route_input(skb, iph->daddr, iph->saddr, iph->tos,
>> - skb->dev);
>> + skb->dev, 1);
>> if (unlikely(err)) {
>> if (err == -EHOSTUNREACH)
>> IP_INC_STATS_BH(dev_net(skb->dev),
>
>
> The packet might get queued by netfilter after this. I think this needs
> another skb_dst_force() in __nf_queue().
Yes, thanks for catching this !
[PATCH net-next-2.6] net: relax dst refcnt in input path
One serious point of contention in network stack is the IP route cache
refcounts in input path, on SMP setups.
On stress situation, one cpu (say A) handles network softirq RX processing.
When a packet is received, we need to find a dst_entry, take
a reference on this dst_entry and associate skb to this dst_entry.
skb is queued on a socket receive queue.
When application (running from another CPU B) dequeues this packet,
it has to release the dst_entry, which refcount is hot and dirty on
another CPU A cache, involving an expensive cache line ping-pong.
Back in November 2008, we tried to keep this cache line only
in CPU A (commit 70355602879229c6f8bd694ec9c0814222bc4936)
(net: release skb->dst in sock_queue_rcv_skb()), but we had
to revert this commit because it broke IP_PKTINFO handling,
as noticed by Mark McLoughlin
Then David suggested not taking the reference at the first place,
which this patch does when possible.
We prepared this work with commit adf30907 (net: skb->dst accessors),
introducing accessors to work on skb->dst
We now can use the low order bit of skb->_skb_dst to tell
if a reference was taken on dst for this skb
Then we add a new 'noref' parameter to ip_route_input(), to tell
this function to take or not a reference count on found dst.
We make ip_rcv_finish() calls ip_route_input() with noref=1.
When queueing a skb to socket receive queue, we drop dst
unless IP_CMSG_PKTINFO is set.
This is done in ip_queue_rcv_skb(), a new wrapper around
sock_queue_rcv_skb(), for UDP (IPV4/IPV6) and RAW (IPV4)
In sock_queue_rcv_skb(), we check if skb has still a dst,
because we must take a reference on it unless already done.
(The dequeuing might be done long time after queueing, and
RCU wont protect dst that long)
skb_dst_drop() is called from tcp_data_queue() for TCP,
regardless of IP_CMSG_PKTINFO (not meaningfull for tcp)
Net effect of this patch is avoiding two atomic ops per
incoming packet, on possibly contented cache lines.
V2: Forwarding is taken into account by changes in dev_queue_xmit(),
forcing a dst refcount on !IFF_XMIT_DST_RELEASE devices.
V3: As pointed by Patrick, we must force a dst refcount in
__nf_queue(), before queueing a packet.
Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
---
include/linux/skbuff.h | 35 +++++++++++++++++++++++++++-
include/net/dst.h | 45 ++++++++++++++++++++++++++++++++----
include/net/ip.h | 1
include/net/route.h | 3 +-
net/bridge/br_netfilter.c | 2 -
net/core/dev.c | 18 ++++++++++++--
net/core/skbuff.c | 2 -
net/core/sock.c | 4 +++
net/ipv4/arp.c | 2 -
net/ipv4/icmp.c | 8 +++---
net/ipv4/ip_input.c | 2 -
net/ipv4/ip_options.c | 11 ++++----
net/ipv4/ip_sockglue.c | 16 ++++++++++++
net/ipv4/netfilter.c | 8 +++---
net/ipv4/raw.c | 2 -
net/ipv4/route.c | 15 ++++++++----
net/ipv4/tcp_input.c | 1
net/ipv4/udp.c | 2 -
net/ipv4/xfrm4_input.c | 2 -
net/ipv6/ip6_tunnel.c | 2 -
net/ipv6/udp.c | 2 -
net/netfilter/nf_queue.c | 1
22 files changed, 148 insertions(+), 36 deletions(-)
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index f2c69a2..9d14368 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -426,13 +426,46 @@ extern void skb_dma_unmap(struct device *dev, struct sk_buff *skb,
enum dma_data_direction dir);
#endif
+/*
+ * skb might have a dst pointer attached, refcounted or not
+ * _skb_dst low order bit is set if refcount was taken
+ */
+#define SKB_DST_REFTAKEN 1UL
+#define SKB_DST_PTRMASK ~1UL
+/**
+ * skb_dst - returns skb dst
+ * @skb: buffer
+ *
+ * Returns skb dst, regardless of reference taken or not.
+ */
static inline struct dst_entry *skb_dst(const struct sk_buff *skb)
{
- return (struct dst_entry *)skb->_skb_dst;
+ return (struct dst_entry *)(skb->_skb_dst & SKB_DST_PTRMASK);
}
+/**
+ * skb_dst_set - sets skb dst
+ * @skb: buffer
+ * @dst: dst entry
+ *
+ * Sets skb dst, assuming a reference was taken on dst and should
+ * be released by skb_dst_drop()
+ */
static inline void skb_dst_set(struct sk_buff *skb, struct dst_entry *dst)
{
+ skb->_skb_dst = (unsigned long)dst | SKB_DST_REFTAKEN;
+}
+
+/**
+ * skb_dst_set_noref - sets skb dst, without a reference
+ * @skb: buffer
+ * @dst: dst entry
+ *
+ * Sets skb dst, assuming a reference was not taken on dst
+ * skb_dst_drop() should not dst_release() this dst
+ */
+static inline void skb_dst_set_noref(struct sk_buff *skb, struct dst_entry *dst)
+{
skb->_skb_dst = (unsigned long)dst;
}
diff --git a/include/net/dst.h b/include/net/dst.h
index 7fc409c..9c3f0fc 100644
--- a/include/net/dst.h
+++ b/include/net/dst.h
@@ -179,13 +179,18 @@ static inline void dst_hold(struct dst_entry * dst)
atomic_inc(&dst->__refcnt);
}
-static inline void dst_use(struct dst_entry *dst, unsigned long time)
+static inline void dst_use_noref(struct dst_entry *dst, unsigned long time)
{
- dst_hold(dst);
dst->__use++;
dst->lastuse = time;
}
+static inline void dst_use(struct dst_entry *dst, unsigned long time)
+{
+ dst_hold(dst);
+ dst_use_noref(dst, time);
+}
+
static inline
struct dst_entry * dst_clone(struct dst_entry * dst)
{
@@ -195,13 +200,45 @@ struct dst_entry * dst_clone(struct dst_entry * dst)
}
extern void dst_release(struct dst_entry *dst);
+
+static inline void __skb_dst_drop(unsigned long _skb_dst)
+{
+ if (_skb_dst & SKB_DST_REFTAKEN)
+ dst_release((struct dst_entry *)(_skb_dst & SKB_DST_PTRMASK));
+}
+/**
+ * skb_dst_drop - drops skb dst
+ * @skb: buffer
+ *
+ * Drops dst reference count if low order bit is set.
+ */
static inline void skb_dst_drop(struct sk_buff *skb)
{
- if (skb->_skb_dst)
- dst_release(skb_dst(skb));
+ __skb_dst_drop(skb->_skb_dst);
skb->_skb_dst = 0UL;
}
+static inline void skb_dst_copy(struct sk_buff *nskb, const struct sk_buff *oskb)
+{
+ nskb->_skb_dst = oskb->_skb_dst;
+ if (nskb->_skb_dst & SKB_DST_REFTAKEN)
+ dst_clone(skb_dst(nskb));
+}
+
+/**
+ * skb_dst_force - makes sure skb dst is refcounted
+ * @skb: buffer
+ *
+ * If dst is not yet refcounted, let's do it
+ */
+static inline void skb_dst_force(struct sk_buff *skb)
+{
+ if (!(skb->_skb_dst & SKB_DST_REFTAKEN)) {
+ dst_clone(skb_dst(skb));
+ skb->_skb_dst |= SKB_DST_REFTAKEN;
+ }
+}
+
/* Children define the path of the packet through the
* Linux networking. Thus, destinations are stackable.
*/
diff --git a/include/net/ip.h b/include/net/ip.h
index 72c3692..ec94680 100644
--- a/include/net/ip.h
+++ b/include/net/ip.h
@@ -378,6 +378,7 @@ extern int ip_options_rcv_srr(struct sk_buff *skb);
* Functions provided by ip_sockglue.c
*/
+extern int ip_queue_rcv_skb(struct sock *sk, struct sk_buff *skb);
extern void ip_cmsg_recv(struct msghdr *msg, struct sk_buff *skb);
extern int ip_cmsg_send(struct net *net,
struct msghdr *msg, struct ipcm_cookie *ipc);
diff --git a/include/net/route.h b/include/net/route.h
index 40f6346..726df35 100644
--- a/include/net/route.h
+++ b/include/net/route.h
@@ -115,7 +115,8 @@ extern void rt_cache_flush(struct net *net, int how);
extern int __ip_route_output_key(struct net *, struct rtable **, const struct flowi *flp);
extern int ip_route_output_key(struct net *, struct rtable **, struct flowi *flp);
extern int ip_route_output_flow(struct net *, struct rtable **rp, struct flowi *flp, struct sock *sk, int flags);
-extern int ip_route_input(struct sk_buff*, __be32 dst, __be32 src, u8 tos, struct net_device *devin);
+extern int ip_route_input(struct sk_buff*, __be32 dst, __be32 src, u8 tos,
+ struct net_device *devin, int noref);
extern unsigned short ip_rt_frag_needed(struct net *net, struct iphdr *iph, unsigned short new_mtu, struct net_device *dev);
extern void ip_rt_send_redirect(struct sk_buff *skb);
diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c
index 4fde742..5c88c83 100644
--- a/net/bridge/br_netfilter.c
+++ b/net/bridge/br_netfilter.c
@@ -349,7 +349,7 @@ static int br_nf_pre_routing_finish(struct sk_buff *skb)
}
nf_bridge->mask ^= BRNF_NF_BRIDGE_PREROUTING;
if (dnat_took_place(skb)) {
- if ((err = ip_route_input(skb, iph->daddr, iph->saddr, iph->tos, dev))) {
+ if ((err = ip_route_input(skb, iph->daddr, iph->saddr, iph->tos, dev, 1))) {
struct flowi fl = {
.nl_u = {
.ip4_u = {
diff --git a/net/core/dev.c b/net/core/dev.c
index dca8b50..e47280d 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -1700,9 +1700,15 @@ int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
* If device doesnt need skb->dst, release it right now while
* its hot in this cpu cache
*/
- if (dev->priv_flags & IFF_XMIT_DST_RELEASE)
- skb_dst_drop(skb);
-
+ if (skb_dst(skb)) {
+ if (dev->priv_flags & IFF_XMIT_DST_RELEASE)
+ skb_dst_drop(skb);
+ else
+ /*
+ * make sure dst was refcounted by caller
+ */
+ WARN_ON(!(skb->_skb_dst & SKB_DST_REFTAKEN));
+ }
rc = ops->ndo_start_xmit(skb, dev);
if (rc == NETDEV_TX_OK)
txq_trans_update(txq);
@@ -1861,6 +1867,12 @@ gso:
if (q->enqueue) {
spinlock_t *root_lock = qdisc_lock(q);
+ /*
+ * before queueing skb, we must enforce a refcounted dst
+ */
+ if (!(dev->priv_flags & IFF_XMIT_DST_RELEASE))
+ skb_dst_force(skb);
+
spin_lock(root_lock);
if (unlikely(test_bit(__QDISC_STATE_DEACTIVATED, &q->state))) {
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 9e0597d..37b1fc0 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -530,7 +530,7 @@ static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old)
new->transport_header = old->transport_header;
new->network_header = old->network_header;
new->mac_header = old->mac_header;
- skb_dst_set(new, dst_clone(skb_dst(old)));
+ skb_dst_copy(new, old);
#ifdef CONFIG_XFRM
new->sp = secpath_get(old->sp);
#endif
diff --git a/net/core/sock.c b/net/core/sock.c
index d9eec15..2d1cf4c 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -304,6 +304,10 @@ int sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
* from the queue.
*/
skb_len = skb->len;
+ /*
+ * If we still have a dst entry linked, make sure we refcounted it
+ */
+ skb_dst_force(skb);
skb_queue_tail(&sk->sk_receive_queue, skb);
diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c
index c29d75d..ff436be 100644
--- a/net/ipv4/arp.c
+++ b/net/ipv4/arp.c
@@ -812,7 +812,7 @@ static int arp_process(struct sk_buff *skb)
}
if (arp->ar_op == htons(ARPOP_REQUEST) &&
- ip_route_input(skb, tip, sip, 0, dev) == 0) {
+ ip_route_input(skb, tip, sip, 0, dev, 0) == 0) {
rt = skb_rtable(skb);
addr_type = rt->rt_type;
diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c
index 97c410e..08e68d0 100644
--- a/net/ipv4/icmp.c
+++ b/net/ipv4/icmp.c
@@ -584,20 +584,20 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info)
err = __ip_route_output_key(net, &rt2, &fl);
else {
struct flowi fl2 = {};
- struct dst_entry *odst;
+ unsigned long odst;
fl2.fl4_dst = fl.fl4_src;
if (ip_route_output_key(net, &rt2, &fl2))
goto relookup_failed;
/* Ugh! */
- odst = skb_dst(skb_in);
+ odst = skb_in->_skb_dst; /* save old dst */
err = ip_route_input(skb_in, fl.fl4_dst, fl.fl4_src,
- RT_TOS(tos), rt2->u.dst.dev);
+ RT_TOS(tos), rt2->u.dst.dev, 0);
dst_release(&rt2->u.dst);
rt2 = skb_rtable(skb_in);
- skb_dst_set(skb_in, odst);
+ skb_in->_skb_dst = odst; /* restore old dst */
}
if (err)
diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c
index db46b4b..23e974b 100644
--- a/net/ipv4/ip_input.c
+++ b/net/ipv4/ip_input.c
@@ -331,7 +331,7 @@ static int ip_rcv_finish(struct sk_buff *skb)
*/
if (skb_dst(skb) == NULL) {
int err = ip_route_input(skb, iph->daddr, iph->saddr, iph->tos,
- skb->dev);
+ skb->dev, 1);
if (unlikely(err)) {
if (err == -EHOSTUNREACH)
IP_INC_STATS_BH(dev_net(skb->dev),
diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c
index 94bf105..e45abbd 100644
--- a/net/ipv4/ip_options.c
+++ b/net/ipv4/ip_options.c
@@ -600,6 +600,7 @@ int ip_options_rcv_srr(struct sk_buff *skb)
unsigned char *optptr = skb_network_header(skb) + opt->srr;
struct rtable *rt = skb_rtable(skb);
struct rtable *rt2;
+ unsigned long odst;
int err;
if (!opt->srr)
@@ -623,16 +624,16 @@ int ip_options_rcv_srr(struct sk_buff *skb)
}
memcpy(&nexthop, &optptr[srrptr-1], 4);
- rt = skb_rtable(skb);
+ odst = skb->_skb_dst;
skb_dst_set(skb, NULL);
- err = ip_route_input(skb, nexthop, iph->saddr, iph->tos, skb->dev);
+ err = ip_route_input(skb, nexthop, iph->saddr, iph->tos, skb->dev, 0);
rt2 = skb_rtable(skb);
if (err || (rt2->rt_type != RTN_UNICAST && rt2->rt_type != RTN_LOCAL)) {
- ip_rt_put(rt2);
- skb_dst_set(skb, &rt->u.dst);
+ skb_dst_drop(skb);
+ skb->_skb_dst = odst;
return -EINVAL;
}
- ip_rt_put(rt);
+ __skb_dst_drop(odst);
if (rt2->rt_type != RTN_LOCAL)
break;
/* Superfast 8) loopback forward */
diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c
index fc7993e..7349554 100644
--- a/net/ipv4/ip_sockglue.c
+++ b/net/ipv4/ip_sockglue.c
@@ -946,6 +946,22 @@ e_inval:
return -EINVAL;
}
+/**
+ * ip_queue_rcv_skb - Queue an skb into sock receive queue
+ * @sk: socket
+ * @skb: buffer
+ *
+ * Queues an skb into socket receive queue. If IP_CMSG_PKTINFO option
+ * is not set, we drop skb dst entry now.
+ */
+int ip_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
+{
+ if (!(inet_sk(sk)->cmsg_flags & IP_CMSG_PKTINFO))
+ skb_dst_drop(skb);
+ return sock_queue_rcv_skb(sk, skb);
+}
+EXPORT_SYMBOL(ip_queue_rcv_skb);
+
int ip_setsockopt(struct sock *sk, int level,
int optname, char __user *optval, int optlen)
{
diff --git a/net/ipv4/netfilter.c b/net/ipv4/netfilter.c
index 1725dc0..7eb2a20 100644
--- a/net/ipv4/netfilter.c
+++ b/net/ipv4/netfilter.c
@@ -16,7 +16,7 @@ int ip_route_me_harder(struct sk_buff *skb, unsigned addr_type)
const struct iphdr *iph = ip_hdr(skb);
struct rtable *rt;
struct flowi fl = {};
- struct dst_entry *odst;
+ unsigned long odst;
unsigned int hh_len;
unsigned int type;
@@ -50,14 +50,14 @@ int ip_route_me_harder(struct sk_buff *skb, unsigned addr_type)
if (ip_route_output_key(net, &rt, &fl) != 0)
return -1;
- odst = skb_dst(skb);
+ odst = skb->_skb_dst;
if (ip_route_input(skb, iph->daddr, iph->saddr,
- RT_TOS(iph->tos), rt->u.dst.dev) != 0) {
+ RT_TOS(iph->tos), rt->u.dst.dev, 0) != 0) {
dst_release(&rt->u.dst);
return -1;
}
dst_release(&rt->u.dst);
- dst_release(odst);
+ __skb_dst_drop(odst);
}
if (skb_dst(skb)->error)
diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c
index 2979f14..ccccd91 100644
--- a/net/ipv4/raw.c
+++ b/net/ipv4/raw.c
@@ -291,7 +291,7 @@ static int raw_rcv_skb(struct sock * sk, struct sk_buff * skb)
{
/* Charge it to the socket. */
- if (sock_queue_rcv_skb(sk, skb) < 0) {
+ if (ip_queue_rcv_skb(sk, skb) < 0) {
atomic_inc(&sk->sk_drops);
kfree_skb(skb);
return NET_RX_DROP;
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 278f46f..e66d85d 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -2255,7 +2255,7 @@ martian_source:
}
int ip_route_input(struct sk_buff *skb, __be32 daddr, __be32 saddr,
- u8 tos, struct net_device *dev)
+ u8 tos, struct net_device *dev, int noref)
{
struct rtable * rth;
unsigned hash;
@@ -2281,10 +2281,15 @@ int ip_route_input(struct sk_buff *skb, __be32 daddr, __be32 saddr,
rth->fl.mark == skb->mark &&
net_eq(dev_net(rth->u.dst.dev), net) &&
!rt_is_expired(rth)) {
- dst_use(&rth->u.dst, jiffies);
+ if (noref) {
+ dst_use_noref(&rth->u.dst, jiffies);
+ skb_dst_set_noref(skb, &rth->u.dst);
+ } else {
+ dst_use(&rth->u.dst, jiffies);
+ skb_dst_set(skb, &rth->u.dst);
+ }
RT_CACHE_STAT_INC(in_hit);
rcu_read_unlock();
- skb_dst_set(skb, &rth->u.dst);
return 0;
}
RT_CACHE_STAT_INC(in_hlist_search);
@@ -2944,7 +2949,7 @@ static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void
skb->protocol = htons(ETH_P_IP);
skb->dev = dev;
local_bh_disable();
- err = ip_route_input(skb, dst, src, rtm->rtm_tos, dev);
+ err = ip_route_input(skb, dst, src, rtm->rtm_tos, dev, 0);
local_bh_enable();
rt = skb_rtable(skb);
@@ -3008,7 +3013,7 @@ int ip_rt_dump(struct sk_buff *skb, struct netlink_callback *cb)
continue;
if (rt_is_expired(rt))
continue;
- skb_dst_set(skb, dst_clone(&rt->u.dst));
+ skb_dst_set_noref(skb, &rt->u.dst);
if (rt_fill_info(net, skb, NETLINK_CB(cb->skb).pid,
cb->nlh->nlmsg_seq, RTM_NEWROUTE,
1, NLM_F_MULTI) <= 0) {
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 2bdb0da..32fb9c6 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -4297,6 +4297,7 @@ static void tcp_data_queue(struct sock *sk, struct sk_buff *skb)
if (TCP_SKB_CB(skb)->seq == TCP_SKB_CB(skb)->end_seq)
goto drop;
+ skb_dst_drop(skb);
__skb_pull(skb, th->doff * 4);
TCP_ECN_accept_cwr(tp, skb);
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index 29ebb0d..094f1ad 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -1024,7 +1024,7 @@ static int __udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
int is_udplite = IS_UDPLITE(sk);
int rc;
- if ((rc = sock_queue_rcv_skb(sk, skb)) < 0) {
+ if ((rc = ip_queue_rcv_skb(sk, skb)) < 0) {
/* Note that an ENOMEM error is charged twice */
if (rc == -ENOMEM) {
UDP_INC_STATS_BH(sock_net(sk), UDP_MIB_RCVBUFERRORS,
diff --git a/net/ipv4/xfrm4_input.c b/net/ipv4/xfrm4_input.c
index f9f922a..fd5310b 100644
--- a/net/ipv4/xfrm4_input.c
+++ b/net/ipv4/xfrm4_input.c
@@ -27,7 +27,7 @@ static inline int xfrm4_rcv_encap_finish(struct sk_buff *skb)
const struct iphdr *iph = ip_hdr(skb);
if (ip_route_input(skb, iph->daddr, iph->saddr, iph->tos,
- skb->dev))
+ skb->dev, 1))
goto drop;
}
return dst_input(skb);
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
index a1d6045..94a23b9 100644
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -564,7 +564,7 @@ ip4ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
} else {
ip_rt_put(rt);
if (ip_route_input(skb2, eiph->daddr, eiph->saddr, eiph->tos,
- skb2->dev) ||
+ skb2->dev, 0) ||
skb_dst(skb2)->dev->type != ARPHRD_TUNNEL)
goto out;
}
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index d79fa67..5732ff5 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -385,7 +385,7 @@ int udpv6_queue_rcv_skb(struct sock * sk, struct sk_buff *skb)
goto drop;
}
- if ((rc = sock_queue_rcv_skb(sk,skb)) < 0) {
+ if ((rc = ip_queue_rcv_skb(sk, skb)) < 0) {
/* Note that an ENOMEM error is charged twice */
if (rc == -ENOMEM) {
UDP6_INC_STATS_BH(sock_net(sk),
diff --git a/net/netfilter/nf_queue.c b/net/netfilter/nf_queue.c
index 3a6fd77..38fa876 100644
--- a/net/netfilter/nf_queue.c
+++ b/net/netfilter/nf_queue.c
@@ -169,6 +169,7 @@ static int __nf_queue(struct sk_buff *skb,
dev_hold(physoutdev);
}
#endif
+ skb_dst_force(skb);
afinfo->saveroute(skb, entry);
status = qh->outfn(entry, queuenum);
^ permalink raw reply related
* Re: the maximal speed of pktgen with 1Gbps NIC
From: Ben Hutchings @ 2009-07-22 15:12 UTC (permalink / raw)
To: Jesper Dangaard Brouer; +Cc: jon_zhou, netdev
In-Reply-To: <Pine.LNX.4.64.0907221448570.18880@tyr.diku.dk>
On Wed, 2009-07-22 at 14:56 +0200, Jesper Dangaard Brouer wrote:
> On Wed, 22 Jul 2009, jon_zhou@agilent.com wrote:
>
> > anyone knows the maximal speed of pktgen with 1Gbps NIC?
>
> You are limited by the number of packets per second (pps) your machine can
> generate. This limitation is given by the CPU speed and the NIC used.
>
> The maximum pps I have seen with pktgen at 1Gbit/s is 1200 kpps.
>
> 1Gbit/s wire speed pps with 64 bytes packets is approx 1953 kpps.
> (1000*10^6/(64*8) = 1953125)
[...]
You need to take the inter-packet gap into consideration too.
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: [PATCH] softirq: tasklet_hrtimer
From: David Miller @ 2009-07-22 15:39 UTC (permalink / raw)
To: peterz; +Cc: torvalds, tglx, netdev, linux-kernel, kaber
In-Reply-To: <1248265724.27058.1366.camel@twins>
From: Peter Zijlstra <peterz@infradead.org>
Date: Wed, 22 Jul 2009 14:28:44 +0200
> Thomas, will you take this?
>
> ---
> Subject: softirq: tasklet_hrtimer
> From: Peter Zijlstra <a.p.zijlstra@chello.nl>
> Date: Wed Jul 22 14:18:35 CEST 2009
>
> Stick tasklets and hrtimers together to provide an in-softirq hrtimer
> experience.
>
> Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Acked-by: David S. Miller <davem@davemloft.net>
^ permalink raw reply
* [PATCH] NET / skge: Enable WoL by default if supported
From: Rafael J. Wysocki @ 2009-07-22 12:58 UTC (permalink / raw)
To: Stephen Hemminger; +Cc: netdev, pm list, Michael Guntsche, LKML
From: Rafael J. Wysocki <rjw@sisk.pl>
If skge hardware is capable of waking up the system from sleep,
enable magic packet WoL during driver initialisation.
This makes WoL work without calling 'ethtool -s ethX wol g'
for each adapter.
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Tested-by: Michael Guntsche <mike@it-loops.com>
---
drivers/net/skge.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
Index: linux-2.6/drivers/net/skge.c
===================================================================
--- linux-2.6.orig/drivers/net/skge.c
+++ linux-2.6/drivers/net/skge.c
@@ -3856,8 +3856,10 @@ static struct net_device *skge_devinit(s
skge->speed = -1;
skge->advertising = skge_supported_modes(hw);
- if (device_may_wakeup(&hw->pdev->dev))
+ if (device_can_wakeup(&hw->pdev->dev)) {
skge->wol = wol_supported(hw) & WAKE_MAGIC;
+ device_set_wakeup_enable(&hw->pdev->dev, skge->wol);
+ }
hw->dev[port] = dev;
^ permalink raw reply
* Re: the maximal speed of pktgen with 1Gbps NIC
From: Jesper Dangaard Brouer @ 2009-07-22 12:56 UTC (permalink / raw)
To: jon_zhou; +Cc: netdev
In-Reply-To: <60230E21F17E384C9BF0B9C98D9E3FDC04BDC92E@sgp-sg-mb02.sgp.agilent.com>
On Wed, 22 Jul 2009, jon_zhou@agilent.com wrote:
> anyone knows the maximal speed of pktgen with 1Gbps NIC?
You are limited by the number of packets per second (pps) your machine can
generate. This limitation is given by the CPU speed and the NIC used.
The maximum pps I have seen with pktgen at 1Gbit/s is 1200 kpps.
1Gbit/s wire speed pps with 64 bytes packets is approx 1953 kpps.
(1000*10^6/(64*8) = 1953125)
> on my pc, the maximal speed is 500 Mbps when the packet size is 100 bytes(with boardcom 5755)
cat /proc/net/pktgen/ethXX to see how many pps pktgen is generating.
Quick calc tells me you a doing 625 kpps (500*10^6/(100*8) = 625000).
Cheers,
Jesper Brouer
--
-------------------------------------------------------------------
MSc. Master of Computer Science
Dept. of Computer Science, University of Copenhagen
Author of http://www.adsl-optimizer.dk
-------------------------------------------------------------------
^ permalink raw reply
* ixgbe: panic in ixgbe_clean_rx_irq()
From: Jesper Dangaard Brouer @ 2009-07-22 12:44 UTC (permalink / raw)
To: Waskiewicz Jr, Peter P; +Cc: netdev@vger.kernel.org
Hi Peter,
Got a panic from the ixgbe driver on my 82599 based NICs, while running
two pktgen tests (1500 bytes packets) against the machine.
Kernel: 2.6.31-rc1-net-2.6-00122-ge594e96 with preemption
The panic occurs in ixgbe_clean_rx_irq+0x319/0x53b
Using objdump I can see that it seems to occur in an inlined function
ixgbe_transform_rsc_queue() in objdump "line" "2811:"
(ixgbe_clean_rx_irq starts 0x24f8 + 0x319 = 0x2811)
static inline struct sk_buff *ixgbe_transform_rsc_queue(struct sk_buff *skb)
{
unsigned int frag_list_size = 0;
while (skb->prev) {
2811: 48 8b 7b 08 mov 0x8(%rbx),%rdi
2815: 48 85 ff test %rdi,%rdi
2818: 75 e9 jne 2803 <ixgbe_clean_rx_irq+0x30b>
frag_list_size += skb->len;
skb->prev = NULL;
skb = prev;
}
skb_shinfo(skb)->frag_list = skb->next;
281a: 48 8b 03 mov (%rbx),%rax
281d: 8b 8b c8 00 00 00 mov 0xc8(%rbx),%ecx
2823: 48 8b 93 d0 00 00 00 mov 0xd0(%rbx),%rdx
282a: 48 89 44 0a 20 mov %rax,0x20(%rdx,%rcx,1)
skb->next = NULL;
282f: 48 c7 03 00 00 00 00 movq $0x0,(%rbx)
skb->len += frag_list_size;
2836: 01 73 60 add %esi,0x60(%rbx)
skb->data_len += frag_list_size;
2839: 01 73 64 add %esi,0x64(%rbx)
skb->truesize += frag_list_size;
283c: 01 b3 e0 00 00 00 add %esi,0xe0(%rbx)
}
Let me know if you want the objdump, its quite large.
--
Med venlig hilsen / Best regards
Jesper Brouer
ComX Networks A/S
Linux Network developer
Cand. Scient Datalog / MSc.
Author of http://adsl-optimizer.dk
LinkedIn: http://www.linkedin.com/in/brouer
root@firesoul:~#
[ 9437.550709] general protection fault: 0000 [#1] PREEMPT SMP
[ 9437.567818] last sysfs file: /sys/devices/system/cpu/cpu7/cpufreq/scaling_governor
[ 9437.590784] CPU 6
[ 9437.596933] Modules linked in: asus_atk0110 ixgbe hwmon mdio r8169
[ 9437.615601] Pid: 0, comm: swapper Not tainted 2.6.31-rc1-net-2.6-00122-ge594e96 #8 System Product Name
[ 9437.643775] RIP: 0010:[<ffffffffa001a811>] [<ffffffffa001a811>] ixgbe_clean_rx_irq+0x319/0x53b [ixgbe]
[ 9437.672232] RSP: 0018:ffff880001925dc0 EFLAGS: 00010202
[ 9437.688275] RAX: 0000000000000000 RBX: 0100000000000000 RCX: ffff8800b2974000
[ 9437.709794] RDX: ffffc90011db7d20 RSI: 00000000000005dc RDI: 0100000000000000
[ 9437.731310] RBP: ffff880001925e50 R08: ffff8800af797c00 R09: ffff880080000000
[ 9437.752825] R10: ffff8800af797548 R11: ffff880001925da0 R12: ffffc90011db7cf8
[ 9437.774341] R13: ffff88003766c640 R14: ffff8800ba8ea580 R15: 0000000040000073
[ 9437.795856] FS: 0000000000000000(0000) GS:ffff880001922000(0000) knlGS:0000000000000000
[ 9437.820385] CS: 0010 DS: 0018 ES: 0018 CR0: 000000008005003b
[ 9437.837724] CR2: 00007f54f87a1315 CR3: 0000000001001000 CR4: 00000000000006a0
[ 9437.859244] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
[ 9437.880759] DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400
[ 9437.902276] Process swapper (pid: 0, threadinfo ffff8800bef02000, task ffff8800beef1e00)
[ 9437.926803] Stack:
[ 9437.932942] 0000004001925de0 ffff880001925e6c ffff8800bb2cf500 ffff8800be572000
[ 9437.954743] <0> ffff8800b2976530 ffff8800b2976540 00000254ad917000 0000002a00000000
[ 9437.978016] <0> 000005dc00000002 000005b200000001 ffff8800bb2cf510 0000000000000254
[ 9438.001963] Call Trace:
[ 9438.009411] <IRQ>
[ 9438.015833] [<ffffffffa001aa81>] ixgbe_clean_rxonly+0x4e/0xd2 [ixgbe]
[ 9438.035534] [<ffffffff8138a7b5>] net_rx_action+0xb2/0x234
[ 9438.052099] [<ffffffff8103fb35>] __do_softirq+0x10c/0x211
[ 9438.068668] [<ffffffff8100cc2c>] call_softirq+0x1c/0x28
[ 9438.084717] [<ffffffff8100de84>] do_softirq+0x34/0x72
[ 9438.100243] [<ffffffff8103f83f>] irq_exit+0x36/0x85
[ 9438.115250] [<ffffffff8100d75f>] do_IRQ+0xa6/0xbd
[ 9438.129738] [<ffffffff8100c493>] ret_from_intr+0x0/0xa
[ 9438.145524] <EOI>
[ 9438.151946] [<ffffffff81012355>] ? mwait_idle+0x89/0x9f
[ 9438.167991] [<ffffffff81012348>] ? mwait_idle+0x7c/0x9f
[ 9438.187996] [<ffffffff8142c948>] ? atomic_notifier_call_chain+0xf/0x11
[ 9438.207953] [<ffffffff8100aedb>] ? cpu_idle+0x4f/0xb3
[ 9438.223479] [<ffffffff81424478>] ? start_secondary+0x17f/0x184
[ 9438.241350] Code: 48 eb 09 48 6b 55 c8 28 49 03 55 08 41 f6 c7 02 74 60 31 f6 48 83 7b 08 00 75 10 eb 3f 03 73 60 48 c7 43 08 00
00 00 00 48 89 fb <48> 8b 7b 08 48 85 ff 75 e9 48 8b 03 8b 8b c8 00 00 00 48 8b 93
[ 9438.298386] RIP [<ffffffffa001a811>] ixgbe_clean_rx_irq+0x319/0x53b [ixgbe]
[ 9438.319652] RSP <ffff880001925dc0>
[ 9438.330593] ---[ end trace f60de63a65a43085 ]---
[ 9438.344593] Kernel panic - not syncing: Fatal exception in interrupt
[ 9438.363810] Pid: 0, comm: swapper Tainted: G D 2.6.31-rc1-net-2.6-00122-ge594e96 #8
[ 9438.389159] Call Trace:
[ 9438.396655] <IRQ> [<ffffffff81427c6b>] panic+0xaa/0x155
[ 9438.413056] [<ffffffff8103f88c>] ? irq_exit+0x83/0x85
[ 9438.428627] [<ffffffff8100c493>] ? ret_from_intr+0x0/0xa
[ 9438.444975] [<ffffffff8142b039>] ? oops_end+0x6b/0xba
[ 9438.460543] [<ffffffff8142b078>] oops_end+0xaa/0xba
[ 9438.475589] [<ffffffff8100f0d1>] die+0x55/0x5e
[ 9438.489332] [<ffffffff8142ac8e>] do_general_protection+0x123/0x12b
[ 9438.508288] [<ffffffff813b39ad>] ? ip_rcv+0x2a7/0x2de
[ 9438.523853] [<ffffffff8142a5df>] general_protection+0x1f/0x30
[ 9438.541509] [<ffffffffa001a811>] ? ixgbe_clean_rx_irq+0x319/0x53b [ixgbe]
[ 9438.562298] [<ffffffffa001aa81>] ixgbe_clean_rxonly+0x4e/0xd2 [ixgbe]
[ 9438.582036] [<ffffffff8138a7b5>] net_rx_action+0xb2/0x234
[ 9438.598641] [<ffffffff8103fb35>] __do_softirq+0x10c/0x211
[ 9438.615250] [<ffffffff8100cc2c>] call_softirq+0x1c/0x28
[ 9438.631337] [<ffffffff8100de84>] do_softirq+0x34/0x72
[ 9438.646904] [<ffffffff8103f83f>] irq_exit+0x36/0x85
[ 9438.661949] [<ffffffff8100d75f>] do_IRQ+0xa6/0xbd
[ 9438.676476] [<ffffffff8100c493>] ret_from_intr+0x0/0xa
[ 9438.692303] <EOI> [<ffffffff81012355>] ? mwait_idle+0x89/0x9f
[ 9438.710264] [<ffffffff81012348>] ? mwait_idle+0x7c/0x9f
[ 9438.726354] [<ffffffff8142c948>] ? atomic_notifier_call_chain+0xf/0x11
[ 9438.746348] [<ffffffff8100aedb>] ? cpu_idle+0x4f/0xb3
[ 9438.761914] [<ffffffff81424478>] ? start_secondary+0x17f/0x184
^ permalink raw reply
* Re: [PATCH V2 net-next-2.6] net: relax dst refcnt in input path
From: Patrick McHardy @ 2009-07-22 12:40 UTC (permalink / raw)
To: Eric Dumazet; +Cc: David S. Miller, Linux Netdev List, Mark McLoughlin
In-Reply-To: <4A670469.2050404@gmail.com>
Eric Dumazet wrote:
> diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c
> index db46b4b..23e974b 100644
> --- a/net/ipv4/ip_input.c
> +++ b/net/ipv4/ip_input.c
> @@ -331,7 +331,7 @@ static int ip_rcv_finish(struct sk_buff *skb)
> */
> if (skb_dst(skb) == NULL) {
> int err = ip_route_input(skb, iph->daddr, iph->saddr, iph->tos,
> - skb->dev);
> + skb->dev, 1);
> if (unlikely(err)) {
> if (err == -EHOSTUNREACH)
> IP_INC_STATS_BH(dev_net(skb->dev),
The packet might get queued by netfilter after this. I think this needs
another skb_dst_force() in __nf_queue().
^ permalink raw reply
* [PATCH] sky2: Avoid transmitting during sky2_restart()
From: Mike McCormack @ 2009-07-22 12:39 UTC (permalink / raw)
To: Stephen Hemminger; +Cc: netdev
Hi Stephen,
I've improved this patch a little to stop the transmit queue before
starting to return NETDEV_TX_BUSY in sky2_xmit_frame().
If you have any suggestions for how to get rid of the
SKY2_HW_RESTARTING state please let me know. As far as I can tell,
the queue cannot be stopped during a restart using netif_stop_queue
and netif_tx_lock, as those functions are used elsewhere in the code.
thanks,
Mike
---
Block the transmit queue during sky2_restart().
Don't free transmit packets in sky2_status_intr() during restart,
as they'll be free'd in sky2_tx_clean()
Signed-off-by: Mike McCormack <mikem@ring3k.org>
---
drivers/net/sky2.c | 19 ++++++++++++++++++-
drivers/net/sky2.h | 1 +
2 files changed, 19 insertions(+), 1 deletions(-)
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c
index 661abd0..826d764 100644
--- a/drivers/net/sky2.c
+++ b/drivers/net/sky2.c
@@ -1533,6 +1533,8 @@ static inline int tx_dist(unsigned tail, unsigned head)
/* Number of list elements available for next tx */
static inline int tx_avail(const struct sky2_port *sky2)
{
+ if (unlikely(sky2->hw->flags & SKY2_HW_RESTARTING))
+ return 0;
return sky2->tx_pending - tx_dist(sky2->tx_cons, sky2->tx_prod);
}
@@ -2359,7 +2361,8 @@ static inline void sky2_tx_done(struct
net_device *dev, u16 last)
{
struct sky2_port *sky2 = netdev_priv(dev);
- if (netif_running(dev)) {
+ if (netif_running(dev) &&
+ !(sky2->hw->flags & SKY2_HW_RESTARTING)) {
netif_tx_lock(dev);
sky2_tx_complete(sky2, last);
netif_tx_unlock(dev);
@@ -3074,6 +3077,17 @@ static void sky2_restart(struct work_struct *work)
int i, err;
rtnl_lock();
+
+ /* stop transmit queues */
+ napi_disable(&hw->napi);
+ for (i = 0; i < hw->ports; i++) {
+ dev = hw->dev[i];
+ if (netif_running(dev))
+ netif_stop_queue(dev);
+ }
+ hw->flags |= SKY2_HW_RESTARTING;
+ napi_enable (&hw->napi);
+
for (i = 0; i < hw->ports; i++) {
dev = hw->dev[i];
if (netif_running(dev))
@@ -3085,6 +3099,7 @@ static void sky2_restart(struct work_struct *work)
sky2_reset(hw);
sky2_write32(hw, B0_IMSK, Y2_IS_BASE);
napi_enable(&hw->napi);
+ hw->flags &= ~SKY2_HW_RESTARTING;
for (i = 0; i < hw->ports; i++) {
dev = hw->dev[i];
@@ -3095,6 +3110,8 @@ static void sky2_restart(struct work_struct *work)
dev->name, err);
dev_close(dev);
}
+ else
+ netif_wake_queue(dev);
}
}
diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h
index b5549c9..e71c161 100644
--- a/drivers/net/sky2.h
+++ b/drivers/net/sky2.h
@@ -2073,6 +2073,7 @@ struct sky2_hw {
#define SKY2_HW_NEW_LE 0x00000020 /* new LSOv2 format */
#define SKY2_HW_AUTO_TX_SUM 0x00000040 /* new IP decode for Tx */
#define SKY2_HW_ADV_POWER_CTL 0x00000080 /* additional PHY power regs */
+#define SKY2_HW_RESTARTING 0x00000100 /* true while restarting */
u8 chip_id;
u8 chip_rev;
--
1.5.6.5
^ permalink raw reply related
* [PATCH] softirq: tasklet_hrtimer
From: Peter Zijlstra @ 2009-07-22 12:28 UTC (permalink / raw)
To: David Miller; +Cc: torvalds, tglx, netdev, linux-kernel, kaber
In-Reply-To: <20090721.201855.32703627.davem@davemloft.net>
Thomas, will you take this?
---
Subject: softirq: tasklet_hrtimer
From: Peter Zijlstra <a.p.zijlstra@chello.nl>
Date: Wed Jul 22 14:18:35 CEST 2009
Stick tasklets and hrtimers together to provide an in-softirq hrtimer
experience.
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
---
include/linux/interrupt.h | 11 +++++++++++
kernel/softirq.c | 44 +++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 54 insertions(+), 1 deletion(-)
Index: linux-2.6/include/linux/interrupt.h
===================================================================
--- linux-2.6.orig/include/linux/interrupt.h
+++ linux-2.6/include/linux/interrupt.h
@@ -14,6 +14,7 @@
#include <linux/irqflags.h>
#include <linux/smp.h>
#include <linux/percpu.h>
+#include <linux/hrtimer.h>
#include <asm/atomic.h>
#include <asm/ptrace.h>
@@ -517,6 +518,16 @@ extern void tasklet_kill_immediate(struc
extern void tasklet_init(struct tasklet_struct *t,
void (*func)(unsigned long), unsigned long data);
+struct tasklet_hrtimer {
+ struct hrtimer timer;
+ struct tasklet_struct tasklet;
+ enum hrtimer_restart (*function)(struct hrtimer *);
+};
+
+void tasklet_hrtimer_init(struct tasklet_hrtimer *ttimer,
+ enum hrtimer_restart (*function)(struct hrtimer *),
+ clockid_t which_clock, enum hrtimer_mode mode);
+
/*
* Autoprobing for irqs:
*
Index: linux-2.6/kernel/softirq.c
===================================================================
--- linux-2.6.orig/kernel/softirq.c
+++ linux-2.6/kernel/softirq.c
@@ -345,7 +345,9 @@ void open_softirq(int nr, void (*action)
softirq_vec[nr].action = action;
}
-/* Tasklets */
+/*
+ * Tasklets
+ */
struct tasklet_head
{
struct tasklet_struct *head;
@@ -493,6 +495,46 @@ void tasklet_kill(struct tasklet_struct
EXPORT_SYMBOL(tasklet_kill);
+/*
+ * tasklet_hrtimer
+ */
+
+static enum hrtimer_restart __hrtimer_tasklet_trampoline(struct hrtimer *timer)
+{
+ struct tasklet_hrtimer *ttimer =
+ container_of(timer, struct tasklet_hrtimer, timer);
+
+ tasklet_hi_schedule(&ttimer->tasklet);
+
+ return HRTIMER_NORESTART;
+}
+
+static void __tasklet_hrtimer_trampoline(unsigned long data)
+{
+ struct tasklet_hrtimer *ttimer = (void *)data;
+ enum hrtimer_restart restart;
+
+ restart = ttimer->function(&ttimer->timer);
+ if (restart != HRTIMER_NORESTART)
+ hrtimer_restart(&ttimer->timer);
+}
+
+void tasklet_hrtimer_init(struct tasklet_hrtimer *ttimer,
+ enum hrtimer_restart (*function)(struct hrtimer *),
+ clockid_t which_clock, enum hrtimer_mode mode)
+{
+ hrtimer_init(&ttimer->timer, which_clock, mode);
+ ttimer->timer.function = __hrtimer_tasklet_trampoline;
+ tasklet_init(&ttimer->tasklet, __tasklet_hrtimer_trampoline,
+ (unsigned long)ttimer);
+ ttimer->function = function;
+}
+EXPORT_SYMBOL_GPL(tasklet_hrtimer_init);
+
+/*
+ * Remote softirq bits
+ */
+
DEFINE_PER_CPU(struct list_head [NR_SOFTIRQS], softirq_work_list);
EXPORT_PER_CPU_SYMBOL(softirq_work_list);
^ permalink raw reply
* Re: [PATCH] 3c589_cs: re-initialize the multicast in the tc589_reset
From: Ken Kawasaki @ 2009-07-22 12:23 UTC (permalink / raw)
To: David Miller; +Cc: netdev
In-Reply-To: <20090720.082906.101507247.davem@davemloft.net>
On Mon, 20 Jul 2009 08:29:06 -0700 (PDT)
David Miller <davem@davemloft.net> wrote:
> > 3c589_cs:
> > re-initialize the multicast in the tc589_reset,
> > and spin_lock the set_multicast_list function.
> >
> > Signed-off-by: Ken Kawasaki <ken_kawasaki@spring.nifty.jp>
>
> Applied, but you really need to fix your coding style.
>
> I know perhaps you were trying to be consistent with the
> rest of this driver, but when adding completely new code
> the conventions of the rest of the kernel ought to be
> followed, for example:
>
> > +static void set_multicast_list(struct net_device *dev)
> > +{
> > + struct el3_private *priv = netdev_priv(dev);
> > + unsigned long flags;
> > +
> > + spin_lock_irqsave(&priv->lock, flags);
> > + set_rx_mode(dev);
> > + spin_unlock_irqrestore(&priv->lock, flags);
> > +}
>
> One tab should begin each statement in this function, and
> spin_lock and spin_unlock lines had unnecessary trailing
> whitespace.
>
> I fixed all of this up when applying your patch, but I
> absolutely will not do so next time.
OK.
Thanks!
^ permalink raw reply
* [PATCH V2 net-next-2.6] net: relax dst refcnt in input path
From: Eric Dumazet @ 2009-07-22 12:22 UTC (permalink / raw)
To: David S. Miller; +Cc: Linux Netdev List, Mark McLoughlin
In-Reply-To: <4A66201D.9070103@gmail.com>
Here is V2 of this patch, taking into account forwarding.
dev_queue_xmit() was called with skb with non refcounted dst,
so this could be problematic, since dst could be freed, after
we left rcu read lock section, while skb waiting on output queue.
I added a WARN_ON() in dev_hard_start_xmit() to catch 'leaks' :
/*
* If device doesnt need skb->dst, release it right now while
* its hot in this cpu cache
*/
if (skb_dst(skb)) {
if (dev->priv_flags & IFF_XMIT_DST_RELEASE)
skb_dst_drop(skb);
else
/*
* make sure dst was refcounted by caller
*/
WARN_ON(!(skb->_skb_dst & SKB_DST_REFTAKEN));
}
Then in dev_queue_xmit(), we force a refcount on !IFF_XMIT_DST_RELEASE devices
Thank you
[PATCH net-next-2.6] net: relax dst refcnt in input path
One serious point of contention in network stack is the IP route cache
refcounts in input path, on SMP setups.
On stress situation, one cpu (say A) handles network softirq RX processing.
When a packet is received, we need to find a dst_entry, take
a reference on this dst_entry and associate skb to this dst_entry.
skb is queued on a socket receive queue.
When application (running from another CPU B) dequeues this packet,
it has to release the dst_entry, which refcount is hot and dirty on
another CPU A cache, involving an expensive cache line ping-pong.
Back in November 2008, we tried to keep this cache line only
in CPU A (commit 70355602879229c6f8bd694ec9c0814222bc4936)
(net: release skb->dst in sock_queue_rcv_skb()), but we had
to revert this commit because it broke IP_PKTINFO handling,
as noticed by Mark McLoughlin
Then David suggested not taking the reference at the first place,
which this patch does when possible.
We prepared this work with commit adf30907 (net: skb->dst accessors),
introducing accessors to work on skb->dst
We now can use the low order bit of skb->_skb_dst to tell
if a reference was taken on dst for this skb
Then we add a new 'noref' parameter to ip_route_input(), to tell
this function to take or not a reference count on found dst.
We make ip_rcv_finish() calls ip_route_input() with noref=1.
When queueing a skb to socket receive queue, we drop dst
unless IP_CMSG_PKTINFO is set.
This is done in ip_queue_rcv_skb(), a new wrapper around
sock_queue_rcv_skb(), for UDP (IPV4/IPV6) and RAW (IPV4)
In sock_queue_rcv_skb(), we check if skb has still a dst,
because we must take a reference on it unless already done.
(The dequeuing might be done long time after queueing, and
RCU wont protect dst that long)
skb_dst_drop() is called from tcp_data_queue() for TCP,
regardless of IP_CMSG_PKTINFO (not meaningfull for tcp)
Net effect of this patch is avoiding two atomic ops per
incoming packet, on possibly contented cache lines.
V2: Forwarding is taken into account by changes in dev_queue_xmit(),
forcing a dst refcount on !IFF_XMIT_DST_RELEASE devices.
Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
---
include/linux/skbuff.h | 35 +++++++++++++++++++++++++++-
include/net/dst.h | 45 ++++++++++++++++++++++++++++++++----
include/net/ip.h | 1
include/net/route.h | 3 +-
net/bridge/br_netfilter.c | 2 -
net/core/dev.c | 18 ++++++++++++--
net/core/skbuff.c | 2 -
net/core/sock.c | 4 +++
net/ipv4/arp.c | 2 -
net/ipv4/icmp.c | 8 +++---
net/ipv4/ip_input.c | 2 -
net/ipv4/ip_options.c | 11 ++++----
net/ipv4/ip_sockglue.c | 16 ++++++++++++
net/ipv4/netfilter.c | 8 +++---
net/ipv4/raw.c | 2 -
net/ipv4/route.c | 15 ++++++++----
net/ipv4/tcp_input.c | 1
net/ipv4/udp.c | 2 -
net/ipv4/xfrm4_input.c | 2 -
net/ipv6/ip6_tunnel.c | 2 -
net/ipv6/udp.c | 2 -
21 files changed, 147 insertions(+), 36 deletions(-)
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index f2c69a2..9d14368 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -426,13 +426,46 @@ extern void skb_dma_unmap(struct device *dev, struct sk_buff *skb,
enum dma_data_direction dir);
#endif
+/*
+ * skb might have a dst pointer attached, refcounted or not
+ * _skb_dst low order bit is set if refcount was taken
+ */
+#define SKB_DST_REFTAKEN 1UL
+#define SKB_DST_PTRMASK ~1UL
+/**
+ * skb_dst - returns skb dst
+ * @skb: buffer
+ *
+ * Returns skb dst, regardless of reference taken or not.
+ */
static inline struct dst_entry *skb_dst(const struct sk_buff *skb)
{
- return (struct dst_entry *)skb->_skb_dst;
+ return (struct dst_entry *)(skb->_skb_dst & SKB_DST_PTRMASK);
}
+/**
+ * skb_dst_set - sets skb dst
+ * @skb: buffer
+ * @dst: dst entry
+ *
+ * Sets skb dst, assuming a reference was taken on dst and should
+ * be released by skb_dst_drop()
+ */
static inline void skb_dst_set(struct sk_buff *skb, struct dst_entry *dst)
{
+ skb->_skb_dst = (unsigned long)dst | SKB_DST_REFTAKEN;
+}
+
+/**
+ * skb_dst_set_noref - sets skb dst, without a reference
+ * @skb: buffer
+ * @dst: dst entry
+ *
+ * Sets skb dst, assuming a reference was not taken on dst
+ * skb_dst_drop() should not dst_release() this dst
+ */
+static inline void skb_dst_set_noref(struct sk_buff *skb, struct dst_entry *dst)
+{
skb->_skb_dst = (unsigned long)dst;
}
diff --git a/include/net/dst.h b/include/net/dst.h
index 7fc409c..9c3f0fc 100644
--- a/include/net/dst.h
+++ b/include/net/dst.h
@@ -179,13 +179,18 @@ static inline void dst_hold(struct dst_entry * dst)
atomic_inc(&dst->__refcnt);
}
-static inline void dst_use(struct dst_entry *dst, unsigned long time)
+static inline void dst_use_noref(struct dst_entry *dst, unsigned long time)
{
- dst_hold(dst);
dst->__use++;
dst->lastuse = time;
}
+static inline void dst_use(struct dst_entry *dst, unsigned long time)
+{
+ dst_hold(dst);
+ dst_use_noref(dst, time);
+}
+
static inline
struct dst_entry * dst_clone(struct dst_entry * dst)
{
@@ -195,13 +200,45 @@ struct dst_entry * dst_clone(struct dst_entry * dst)
}
extern void dst_release(struct dst_entry *dst);
+
+static inline void __skb_dst_drop(unsigned long _skb_dst)
+{
+ if (_skb_dst & SKB_DST_REFTAKEN)
+ dst_release((struct dst_entry *)(_skb_dst & SKB_DST_PTRMASK));
+}
+/**
+ * skb_dst_drop - drops skb dst
+ * @skb: buffer
+ *
+ * Drops dst reference count if low order bit is set.
+ */
static inline void skb_dst_drop(struct sk_buff *skb)
{
- if (skb->_skb_dst)
- dst_release(skb_dst(skb));
+ __skb_dst_drop(skb->_skb_dst);
skb->_skb_dst = 0UL;
}
+static inline void skb_dst_copy(struct sk_buff *nskb, const struct sk_buff *oskb)
+{
+ nskb->_skb_dst = oskb->_skb_dst;
+ if (nskb->_skb_dst & SKB_DST_REFTAKEN)
+ dst_clone(skb_dst(nskb));
+}
+
+/**
+ * skb_dst_force - makes sure skb dst is refcounted
+ * @skb: buffer
+ *
+ * If dst is not yet refcounted, let's do it
+ */
+static inline void skb_dst_force(struct sk_buff *skb)
+{
+ if (!(skb->_skb_dst & SKB_DST_REFTAKEN)) {
+ dst_clone(skb_dst(skb));
+ skb->_skb_dst |= SKB_DST_REFTAKEN;
+ }
+}
+
/* Children define the path of the packet through the
* Linux networking. Thus, destinations are stackable.
*/
diff --git a/include/net/ip.h b/include/net/ip.h
index 72c3692..ec94680 100644
--- a/include/net/ip.h
+++ b/include/net/ip.h
@@ -378,6 +378,7 @@ extern int ip_options_rcv_srr(struct sk_buff *skb);
* Functions provided by ip_sockglue.c
*/
+extern int ip_queue_rcv_skb(struct sock *sk, struct sk_buff *skb);
extern void ip_cmsg_recv(struct msghdr *msg, struct sk_buff *skb);
extern int ip_cmsg_send(struct net *net,
struct msghdr *msg, struct ipcm_cookie *ipc);
diff --git a/include/net/route.h b/include/net/route.h
index 40f6346..726df35 100644
--- a/include/net/route.h
+++ b/include/net/route.h
@@ -115,7 +115,8 @@ extern void rt_cache_flush(struct net *net, int how);
extern int __ip_route_output_key(struct net *, struct rtable **, const struct flowi *flp);
extern int ip_route_output_key(struct net *, struct rtable **, struct flowi *flp);
extern int ip_route_output_flow(struct net *, struct rtable **rp, struct flowi *flp, struct sock *sk, int flags);
-extern int ip_route_input(struct sk_buff*, __be32 dst, __be32 src, u8 tos, struct net_device *devin);
+extern int ip_route_input(struct sk_buff*, __be32 dst, __be32 src, u8 tos,
+ struct net_device *devin, int noref);
extern unsigned short ip_rt_frag_needed(struct net *net, struct iphdr *iph, unsigned short new_mtu, struct net_device *dev);
extern void ip_rt_send_redirect(struct sk_buff *skb);
diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c
index 4fde742..5c88c83 100644
--- a/net/bridge/br_netfilter.c
+++ b/net/bridge/br_netfilter.c
@@ -349,7 +349,7 @@ static int br_nf_pre_routing_finish(struct sk_buff *skb)
}
nf_bridge->mask ^= BRNF_NF_BRIDGE_PREROUTING;
if (dnat_took_place(skb)) {
- if ((err = ip_route_input(skb, iph->daddr, iph->saddr, iph->tos, dev))) {
+ if ((err = ip_route_input(skb, iph->daddr, iph->saddr, iph->tos, dev, 1))) {
struct flowi fl = {
.nl_u = {
.ip4_u = {
diff --git a/net/core/dev.c b/net/core/dev.c
index dca8b50..e47280d 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -1700,9 +1700,15 @@ int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
* If device doesnt need skb->dst, release it right now while
* its hot in this cpu cache
*/
- if (dev->priv_flags & IFF_XMIT_DST_RELEASE)
- skb_dst_drop(skb);
-
+ if (skb_dst(skb)) {
+ if (dev->priv_flags & IFF_XMIT_DST_RELEASE)
+ skb_dst_drop(skb);
+ else
+ /*
+ * make sure dst was refcounted by caller
+ */
+ WARN_ON(!(skb->_skb_dst & SKB_DST_REFTAKEN));
+ }
rc = ops->ndo_start_xmit(skb, dev);
if (rc == NETDEV_TX_OK)
txq_trans_update(txq);
@@ -1861,6 +1867,12 @@ gso:
if (q->enqueue) {
spinlock_t *root_lock = qdisc_lock(q);
+ /*
+ * before queueing skb, we must enforce a refcounted dst
+ */
+ if (!(dev->priv_flags & IFF_XMIT_DST_RELEASE))
+ skb_dst_force(skb);
+
spin_lock(root_lock);
if (unlikely(test_bit(__QDISC_STATE_DEACTIVATED, &q->state))) {
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 9e0597d..37b1fc0 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -530,7 +530,7 @@ static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old)
new->transport_header = old->transport_header;
new->network_header = old->network_header;
new->mac_header = old->mac_header;
- skb_dst_set(new, dst_clone(skb_dst(old)));
+ skb_dst_copy(new, old);
#ifdef CONFIG_XFRM
new->sp = secpath_get(old->sp);
#endif
diff --git a/net/core/sock.c b/net/core/sock.c
index d9eec15..2d1cf4c 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -304,6 +304,10 @@ int sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
* from the queue.
*/
skb_len = skb->len;
+ /*
+ * If we still have a dst entry linked, make sure we refcounted it
+ */
+ skb_dst_force(skb);
skb_queue_tail(&sk->sk_receive_queue, skb);
diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c
index c29d75d..ff436be 100644
--- a/net/ipv4/arp.c
+++ b/net/ipv4/arp.c
@@ -812,7 +812,7 @@ static int arp_process(struct sk_buff *skb)
}
if (arp->ar_op == htons(ARPOP_REQUEST) &&
- ip_route_input(skb, tip, sip, 0, dev) == 0) {
+ ip_route_input(skb, tip, sip, 0, dev, 0) == 0) {
rt = skb_rtable(skb);
addr_type = rt->rt_type;
diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c
index 97c410e..08e68d0 100644
--- a/net/ipv4/icmp.c
+++ b/net/ipv4/icmp.c
@@ -584,20 +584,20 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info)
err = __ip_route_output_key(net, &rt2, &fl);
else {
struct flowi fl2 = {};
- struct dst_entry *odst;
+ unsigned long odst;
fl2.fl4_dst = fl.fl4_src;
if (ip_route_output_key(net, &rt2, &fl2))
goto relookup_failed;
/* Ugh! */
- odst = skb_dst(skb_in);
+ odst = skb_in->_skb_dst; /* save old dst */
err = ip_route_input(skb_in, fl.fl4_dst, fl.fl4_src,
- RT_TOS(tos), rt2->u.dst.dev);
+ RT_TOS(tos), rt2->u.dst.dev, 0);
dst_release(&rt2->u.dst);
rt2 = skb_rtable(skb_in);
- skb_dst_set(skb_in, odst);
+ skb_in->_skb_dst = odst; /* restore old dst */
}
if (err)
diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c
index db46b4b..23e974b 100644
--- a/net/ipv4/ip_input.c
+++ b/net/ipv4/ip_input.c
@@ -331,7 +331,7 @@ static int ip_rcv_finish(struct sk_buff *skb)
*/
if (skb_dst(skb) == NULL) {
int err = ip_route_input(skb, iph->daddr, iph->saddr, iph->tos,
- skb->dev);
+ skb->dev, 1);
if (unlikely(err)) {
if (err == -EHOSTUNREACH)
IP_INC_STATS_BH(dev_net(skb->dev),
diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c
index 94bf105..e45abbd 100644
--- a/net/ipv4/ip_options.c
+++ b/net/ipv4/ip_options.c
@@ -600,6 +600,7 @@ int ip_options_rcv_srr(struct sk_buff *skb)
unsigned char *optptr = skb_network_header(skb) + opt->srr;
struct rtable *rt = skb_rtable(skb);
struct rtable *rt2;
+ unsigned long odst;
int err;
if (!opt->srr)
@@ -623,16 +624,16 @@ int ip_options_rcv_srr(struct sk_buff *skb)
}
memcpy(&nexthop, &optptr[srrptr-1], 4);
- rt = skb_rtable(skb);
+ odst = skb->_skb_dst;
skb_dst_set(skb, NULL);
- err = ip_route_input(skb, nexthop, iph->saddr, iph->tos, skb->dev);
+ err = ip_route_input(skb, nexthop, iph->saddr, iph->tos, skb->dev, 0);
rt2 = skb_rtable(skb);
if (err || (rt2->rt_type != RTN_UNICAST && rt2->rt_type != RTN_LOCAL)) {
- ip_rt_put(rt2);
- skb_dst_set(skb, &rt->u.dst);
+ skb_dst_drop(skb);
+ skb->_skb_dst = odst;
return -EINVAL;
}
- ip_rt_put(rt);
+ __skb_dst_drop(odst);
if (rt2->rt_type != RTN_LOCAL)
break;
/* Superfast 8) loopback forward */
diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c
index fc7993e..7349554 100644
--- a/net/ipv4/ip_sockglue.c
+++ b/net/ipv4/ip_sockglue.c
@@ -946,6 +946,22 @@ e_inval:
return -EINVAL;
}
+/**
+ * ip_queue_rcv_skb - Queue an skb into sock receive queue
+ * @sk: socket
+ * @skb: buffer
+ *
+ * Queues an skb into socket receive queue. If IP_CMSG_PKTINFO option
+ * is not set, we drop skb dst entry now.
+ */
+int ip_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
+{
+ if (!(inet_sk(sk)->cmsg_flags & IP_CMSG_PKTINFO))
+ skb_dst_drop(skb);
+ return sock_queue_rcv_skb(sk, skb);
+}
+EXPORT_SYMBOL(ip_queue_rcv_skb);
+
int ip_setsockopt(struct sock *sk, int level,
int optname, char __user *optval, int optlen)
{
diff --git a/net/ipv4/netfilter.c b/net/ipv4/netfilter.c
index 1725dc0..7eb2a20 100644
--- a/net/ipv4/netfilter.c
+++ b/net/ipv4/netfilter.c
@@ -16,7 +16,7 @@ int ip_route_me_harder(struct sk_buff *skb, unsigned addr_type)
const struct iphdr *iph = ip_hdr(skb);
struct rtable *rt;
struct flowi fl = {};
- struct dst_entry *odst;
+ unsigned long odst;
unsigned int hh_len;
unsigned int type;
@@ -50,14 +50,14 @@ int ip_route_me_harder(struct sk_buff *skb, unsigned addr_type)
if (ip_route_output_key(net, &rt, &fl) != 0)
return -1;
- odst = skb_dst(skb);
+ odst = skb->_skb_dst;
if (ip_route_input(skb, iph->daddr, iph->saddr,
- RT_TOS(iph->tos), rt->u.dst.dev) != 0) {
+ RT_TOS(iph->tos), rt->u.dst.dev, 0) != 0) {
dst_release(&rt->u.dst);
return -1;
}
dst_release(&rt->u.dst);
- dst_release(odst);
+ __skb_dst_drop(odst);
}
if (skb_dst(skb)->error)
diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c
index 2979f14..ccccd91 100644
--- a/net/ipv4/raw.c
+++ b/net/ipv4/raw.c
@@ -291,7 +291,7 @@ static int raw_rcv_skb(struct sock * sk, struct sk_buff * skb)
{
/* Charge it to the socket. */
- if (sock_queue_rcv_skb(sk, skb) < 0) {
+ if (ip_queue_rcv_skb(sk, skb) < 0) {
atomic_inc(&sk->sk_drops);
kfree_skb(skb);
return NET_RX_DROP;
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 278f46f..e66d85d 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -2255,7 +2255,7 @@ martian_source:
}
int ip_route_input(struct sk_buff *skb, __be32 daddr, __be32 saddr,
- u8 tos, struct net_device *dev)
+ u8 tos, struct net_device *dev, int noref)
{
struct rtable * rth;
unsigned hash;
@@ -2281,10 +2281,15 @@ int ip_route_input(struct sk_buff *skb, __be32 daddr, __be32 saddr,
rth->fl.mark == skb->mark &&
net_eq(dev_net(rth->u.dst.dev), net) &&
!rt_is_expired(rth)) {
- dst_use(&rth->u.dst, jiffies);
+ if (noref) {
+ dst_use_noref(&rth->u.dst, jiffies);
+ skb_dst_set_noref(skb, &rth->u.dst);
+ } else {
+ dst_use(&rth->u.dst, jiffies);
+ skb_dst_set(skb, &rth->u.dst);
+ }
RT_CACHE_STAT_INC(in_hit);
rcu_read_unlock();
- skb_dst_set(skb, &rth->u.dst);
return 0;
}
RT_CACHE_STAT_INC(in_hlist_search);
@@ -2944,7 +2949,7 @@ static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void
skb->protocol = htons(ETH_P_IP);
skb->dev = dev;
local_bh_disable();
- err = ip_route_input(skb, dst, src, rtm->rtm_tos, dev);
+ err = ip_route_input(skb, dst, src, rtm->rtm_tos, dev, 0);
local_bh_enable();
rt = skb_rtable(skb);
@@ -3008,7 +3013,7 @@ int ip_rt_dump(struct sk_buff *skb, struct netlink_callback *cb)
continue;
if (rt_is_expired(rt))
continue;
- skb_dst_set(skb, dst_clone(&rt->u.dst));
+ skb_dst_set_noref(skb, &rt->u.dst);
if (rt_fill_info(net, skb, NETLINK_CB(cb->skb).pid,
cb->nlh->nlmsg_seq, RTM_NEWROUTE,
1, NLM_F_MULTI) <= 0) {
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 2bdb0da..32fb9c6 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -4297,6 +4297,7 @@ static void tcp_data_queue(struct sock *sk, struct sk_buff *skb)
if (TCP_SKB_CB(skb)->seq == TCP_SKB_CB(skb)->end_seq)
goto drop;
+ skb_dst_drop(skb);
__skb_pull(skb, th->doff * 4);
TCP_ECN_accept_cwr(tp, skb);
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index 29ebb0d..094f1ad 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -1024,7 +1024,7 @@ static int __udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
int is_udplite = IS_UDPLITE(sk);
int rc;
- if ((rc = sock_queue_rcv_skb(sk, skb)) < 0) {
+ if ((rc = ip_queue_rcv_skb(sk, skb)) < 0) {
/* Note that an ENOMEM error is charged twice */
if (rc == -ENOMEM) {
UDP_INC_STATS_BH(sock_net(sk), UDP_MIB_RCVBUFERRORS,
diff --git a/net/ipv4/xfrm4_input.c b/net/ipv4/xfrm4_input.c
index f9f922a..fd5310b 100644
--- a/net/ipv4/xfrm4_input.c
+++ b/net/ipv4/xfrm4_input.c
@@ -27,7 +27,7 @@ static inline int xfrm4_rcv_encap_finish(struct sk_buff *skb)
const struct iphdr *iph = ip_hdr(skb);
if (ip_route_input(skb, iph->daddr, iph->saddr, iph->tos,
- skb->dev))
+ skb->dev, 1))
goto drop;
}
return dst_input(skb);
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
index a1d6045..94a23b9 100644
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -564,7 +564,7 @@ ip4ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
} else {
ip_rt_put(rt);
if (ip_route_input(skb2, eiph->daddr, eiph->saddr, eiph->tos,
- skb2->dev) ||
+ skb2->dev, 0) ||
skb_dst(skb2)->dev->type != ARPHRD_TUNNEL)
goto out;
}
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index d79fa67..5732ff5 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -385,7 +385,7 @@ int udpv6_queue_rcv_skb(struct sock * sk, struct sk_buff *skb)
goto drop;
}
- if ((rc = sock_queue_rcv_skb(sk,skb)) < 0) {
+ if ((rc = ip_queue_rcv_skb(sk, skb)) < 0) {
/* Note that an ENOMEM error is charged twice */
if (rc == -ENOMEM) {
UDP6_INC_STATS_BH(sock_net(sk),
^ permalink raw reply related
* Re: [PATCH] net: KS8851 needs to depend on MII
From: Ben Dooks @ 2009-07-22 11:19 UTC (permalink / raw)
To: Alexander Beregalov; +Cc: netdev, David S. Miller
In-Reply-To: <1248261411-12533-1-git-send-email-a.beregalov@gmail.com>
Alexander Beregalov wrote:
> fix this build error when CONFIG_MII is not set
> drivers/net/ks8851.c:999: undefined reference to `generic_mii_ioctl'
> drivers/net/ks8851.c:1050: undefined reference to `mii_link_ok'
> drivers/net/ks8851.c:1056: undefined reference to `mii_nway_restart'
> drivers/net/ks8851.c:1044: undefined reference to `mii_ethtool_sset'
> drivers/net/ks8851.c:1038: undefined reference to `mii_ethtool_gset'
thanks, my test system has an DM9000 so that selected CONFIG_MII for me.
> Signed-off-by: Alexander Beregalov <a.beregalov@gmail.com>
Acked-by: Ben Dooks <ben@simtec.co.uk>
> ---
> drivers/net/Kconfig | 1 +
> 1 files changed, 1 insertions(+), 0 deletions(-)
>
> diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
> index 1dbaffd..3ed49f1 100644
> --- a/drivers/net/Kconfig
> +++ b/drivers/net/Kconfig
> @@ -1732,6 +1732,7 @@ config KS8842
> config KS8851
> tristate "Micrel KS8851 SPI"
> depends on SPI
> + select MII
> help
> SPI driver for Micrel KS8851 SPI attached network chip.
>
--
Ben Dooks, Software Engineer, Simtec Electronics
http://www.simtec.co.uk/
^ permalink raw reply
* [PATCH] be2net: Bug fix in the non-lro path. Size of received packet was not updated in statistics properly.
From: Ajit Khaparde @ 2009-07-22 11:19 UTC (permalink / raw)
To: David Miller; +Cc: netdev
This patch fixes a bug in the non-lro path.
Wrong size of received packet was being passed for updating receive statistics.
This patch is against the net-2.6 git.
Thanks
-Ajit
Signed-off-by: Ajit Khaparde <ajitk@serverengines.com>
---
drivers/net/benet/be_main.c | 8 ++++----
1 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c
index c43f6a1..dea3155 100644
--- a/drivers/net/benet/be_main.c
+++ b/drivers/net/benet/be_main.c
@@ -667,7 +667,7 @@ static void skb_fill_rx_data(struct be_adapter *adapter,
struct be_queue_info *rxq = &adapter->rx_obj.q;
struct be_rx_page_info *page_info;
u16 rxq_idx, i, num_rcvd, j;
- u32 pktsize, hdr_len, curr_frag_len;
+ u32 pktsize, hdr_len, curr_frag_len, size;
u8 *start;
rxq_idx = AMAP_GET_BITS(struct amap_eth_rx_compl, fragndx, rxcp);
@@ -708,12 +708,13 @@ static void skb_fill_rx_data(struct be_adapter *adapter,
}
/* More frags present for this completion */
- pktsize -= curr_frag_len; /* account for above copied frag */
+ size = pktsize;
for (i = 1, j = 0; i < num_rcvd; i++) {
+ size -= curr_frag_len;
index_inc(&rxq_idx, rxq->len);
page_info = get_rx_page_info(adapter, rxq_idx);
- curr_frag_len = min(pktsize, rx_frag_size);
+ curr_frag_len = min(size, rx_frag_size);
/* Coalesce all frags from the same physical page in one slot */
if (page_info->page_offset == 0) {
@@ -731,7 +732,6 @@ static void skb_fill_rx_data(struct be_adapter *adapter,
skb_shinfo(skb)->frags[j].size += curr_frag_len;
skb->len += curr_frag_len;
skb->data_len += curr_frag_len;
- pktsize -= curr_frag_len;
memset(page_info, 0, sizeof(*page_info));
}
--
1.6.0.4
^ permalink raw reply related
* Re: [RFC] IPv6 route replacement
From: YOSHIFUJI Hideaki @ 2009-07-22 11:09 UTC (permalink / raw)
To: Jiri Pirko; +Cc: netdev, davem, pekkas, kaber, yoshfuji
In-Reply-To: <20090722095040.GC3517@psychotron.englab.brq.redhat.com>
Hi,
Jiri Pirko wrote:
> Now do you think this is the right behaviour? I would expect the first route to
> be replaced. The same result is when you do "ip -6 route replace"
Well, even in IPv4 you cannot change metric;
same route can be installed e.g., for manual
backup route entry.
But well, NLM_F_REPLACE handler is completely
missing in IPv6. I think we are okay with
"replace" (NLM_F_CREATE|NLM_F_REPLACE) but we
could return "no such route" for "change"
(NLM_F_REPLACE).
--yoshfuji
^ permalink raw reply
* [PATCH] net: KS8851 needs to depend on MII
From: Alexander Beregalov @ 2009-07-22 11:16 UTC (permalink / raw)
To: linux-next, netdev, David Miller, ben; +Cc: Alexander Beregalov
fix this build error when CONFIG_MII is not set
drivers/net/ks8851.c:999: undefined reference to `generic_mii_ioctl'
drivers/net/ks8851.c:1050: undefined reference to `mii_link_ok'
drivers/net/ks8851.c:1056: undefined reference to `mii_nway_restart'
drivers/net/ks8851.c:1044: undefined reference to `mii_ethtool_sset'
drivers/net/ks8851.c:1038: undefined reference to `mii_ethtool_gset'
Signed-off-by: Alexander Beregalov <a.beregalov@gmail.com>
---
drivers/net/Kconfig | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 1dbaffd..3ed49f1 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -1732,6 +1732,7 @@ config KS8842
config KS8851
tristate "Micrel KS8851 SPI"
depends on SPI
+ select MII
help
SPI driver for Micrel KS8851 SPI attached network chip.
--
1.6.3.3
^ permalink raw reply related
* Re: [PATCH] USB host CDC Phonet network interface driver
From: Rémi Denis-Courmont @ 2009-07-22 11:07 UTC (permalink / raw)
To: ext Marcel Holtmann
Cc: Alan Cox, Oliver Neukum, ext Dan Williams, netdev@vger.kernel.org,
linux-usb@vger.kernel.org
In-Reply-To: <1248254134.28545.111.camel@violet>
On Wednesday 22 July 2009 12:15:34 ext Marcel Holtmann wrote:
> Hi Alan,
>
> > > The AT stuff is really problematic. Look at the hoops ISDN and software
> > > modem drivers go through to emulate AT commands. I know even of a
> > > CDC-ACM modem which can't deal with AT commands inline (that's within
> > > spec). It seems to me we should have a modem API in kernel.
> >
> > For devices which don't deal in AT commands probably but for devices
> > whose firmware provides an AT command interface over serial I would
> > disagree.
>
> I fully agree here. Even if you think you get AT commands under control,
> you really won't in the end. That standard is so wildly mis-interpreted
> that it is not even funny anymore.
Possibly. Does anyone known of any "species" bypassing AT commands entirely,
other than Phonet? as far as GPRS is concerned?
--
Rémi Denis-Courmont
Nokia Devices R&D, Maemo Software, Helsinki
^ permalink raw reply
* [RFC] IPv6 route replacement
From: Jiri Pirko @ 2009-07-22 9:50 UTC (permalink / raw)
To: netdev; +Cc: davem, pekkas, yoshfuji, kaber
Hello guys.
I would like to hear your opinion on the following:
[root@f11 ~]# ip -6 route list 3ffe::1:1
[root@f11 ~]# ip -6 route add 3ffe::1:1 via fe80::20c:29ff:fe4c:3108 dev eth0 metric 1024
[root@f11 ~]# ip -6 route list 3ffe::1:1
3ffe::1:1 via fe80::20c:29ff:fe4c:3108 dev eth0 metric 1024 mtu 1500 advmss 1440 hoplimit 4294967295
[root@f11 ~]# ip -6 route change 3ffe::1:1 via fe80::20c:29ff:fe4c:3108 dev eth0 metric 100
[root@f11 ~]# ip -6 route list 3ffe::1:1
3ffe::1:1 via fe80::20c:29ff:fe4c:3108 dev eth0 metric 100 mtu 1500 advmss 1440 hoplimit 4294967295
3ffe::1:1 via fe80::20c:29ff:fe4c:3108 dev eth0 metric 1024 mtu 1500 advmss 1440 hoplimit 4294967295
[root@f11 ~]#
Now do you think this is the right behaviour? I would expect the first route to
be replaced. The same result is when you do "ip -6 route replace"
Thanks
Jirka
^ permalink raw reply
* Re: r8169 not advertising 1000mbit after suspend anymore
From: sbenni @ 2009-07-22 9:41 UTC (permalink / raw)
To: Francois Romieu; +Cc: netdev
In-Reply-To: <20090721223741.GA24735@electric-eye.fr.zoreil.com>
On Wed, 22 Jul 2009 00:37:41 +0200
Francois Romieu <romieu@fr.zoreil.com> wrote:
> Benjamin S. <sbenni@gmx.de> :
> [...]
> > I have a Gigabyte GA-MA78G-DS3H mainboard with a RTL8111/8168B Realtek
> > Gigabit Ethernet Controller. Until first suspend everything works as
> > expected, but after suspend only 100mbit are used instead of 1000.
>
> Which kernel do you use ?
2.6.30
> > mii-tool after setting speed to 1000 with "ethtool -s eth0 speed 1000":
> > eth0: negotiated 1000baseT-FD flow-control, link ok
> [snip]
>
> At which point it works correctly again, right ?
Yes. After resetting speed with ethtool file transfers with 25MB/s
between my router and my computer are possible again.
>
> At least some 8168 appear to lose the link settings :o/
>
> Please send the XID line of the offender taken from dmesg.
[ 2.802073] r8169 Gigabit Ethernet driver 2.3LK-NAPI loaded
[ 2.802132] r8169 0000:02:00.0: PCI INT A -> GSI 18 (level, low) -> IRQ 18
[ 2.802186] r8169 0000:02:00.0: setting latency timer to 64
[ 2.802255] r8169 0000:02:00.0: irq 26 for MSI/MSI-X
[ 2.802334] PM: Adding info for No Bus:eth0
[ 2.802620] eth0: RTL8168c/8111c at 0xffffc20000668000, 00:1f:d0:53:f6:89, XID 3c4000c0 IRQ 26
Benjamin
^ permalink raw reply
* Re: [PATCH 1/1] ipv4: IP_RECVERR should also enqueue source quench messages
From: Andi Kleen @ 2009-07-22 9:32 UTC (permalink / raw)
To: David Miller; +Cc: hagen, netdev
In-Reply-To: <20090721.200729.212201103.davem@davemloft.net>
David Miller <davem@davemloft.net> writes:
>
> I'm almost entirely sure that this behavior is intentional.
I could also imagine that changing it could break some existing
applications that do not expect to see source quenchs here.
-Andi
--
ak@linux.intel.com -- Speaking for myself only.
^ permalink raw reply
* Re: [PATCH] USB host CDC Phonet network interface driver
From: Marcel Holtmann @ 2009-07-22 9:15 UTC (permalink / raw)
To: Alan Cox
Cc: Oliver Neukum, Rémi Denis-Courmont, ext Dan Williams,
netdev@vger.kernel.org, linux-usb@vger.kernel.org
In-Reply-To: <20090722101102.4aba96bd@lxorguk.ukuu.org.uk>
Hi Alan,
> > The AT stuff is really problematic. Look at the hoops ISDN and software
> > modem drivers go through to emulate AT commands. I know even of a CDC-ACM
> > modem which can't deal with AT commands inline (that's within spec).
> > It seems to me we should have a modem API in kernel.
>
> For devices which don't deal in AT commands probably but for devices
> whose firmware provides an AT command interface over serial I would
> disagree.
I fully agree here. Even if you think you get AT commands under control,
you really won't in the end. That standard is so wildly mis-interpreted
that it is not even funny anymore.
Regards
Marcel
^ permalink raw reply
* Re: [PATCH] USB host CDC Phonet network interface driver
From: Alan Cox @ 2009-07-22 9:11 UTC (permalink / raw)
To: Oliver Neukum
Cc: Rémi Denis-Courmont, ext Dan Williams,
netdev@vger.kernel.org, linux-usb@vger.kernel.org,
ext Marcel Holtmann
In-Reply-To: <200907221041.51995.oliver@neukum.org>
> The AT stuff is really problematic. Look at the hoops ISDN and software
> modem drivers go through to emulate AT commands. I know even of a CDC-ACM
> modem which can't deal with AT commands inline (that's within spec).
> It seems to me we should have a modem API in kernel.
For devices which don't deal in AT commands probably but for devices
whose firmware provides an AT command interface over serial I would
disagree.
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox