* [PATCH net-next 1/1] bnx2: Add PCI Advanced Error Reporting support.
From: Benjamin Li @ 2010-08-23 3:45 UTC (permalink / raw)
To: netdev@vger.kernel.org; +Cc: John Feeney, Michael Chan, Benjamin Li
In-Reply-To: <1282535153-18291-1-git-send-email-benli@broadcom.com>
From: John Feeney <jfeeney@redhat.com>
Signed-off-by: John Feeney <jfeeney@redhat.com>
Signed-off-by: Michael Chan <mchan@broadcom.com>
Signed-off-by: Benjamin Li <benli@broadcom.com>
---
drivers/net/bnx2.c | 44 ++++++++++++++++++++++++++++++++++----------
1 files changed, 34 insertions(+), 10 deletions(-)
diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c
index e6a803f..a0e02aa 100644
--- a/drivers/net/bnx2.c
+++ b/drivers/net/bnx2.c
@@ -49,6 +49,7 @@
#include <linux/cache.h>
#include <linux/firmware.h>
#include <linux/log2.h>
+#include <linux/aer.h>
#if defined(CONFIG_CNIC) || defined(CONFIG_CNIC_MODULE)
#define BCM_CNIC 1
@@ -7890,6 +7891,7 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
int rc, i, j;
u32 reg;
u64 dma_mask, persist_dma_mask;
+ int err;
SET_NETDEV_DEV(dev, &pdev->dev);
bp = netdev_priv(dev);
@@ -7925,6 +7927,14 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
goto err_out_disable;
}
+ /* AER (Advanced Error Reporting) hooks */
+ err = pci_enable_pcie_error_reporting(pdev);
+ if (err) {
+ dev_err(&pdev->dev, "pci_enable_pcie_error_reporting failed "
+ "0x%x\n", err);
+ /* non-fatal, continue */
+ }
+
pci_set_master(pdev);
pci_save_state(pdev);
@@ -8246,6 +8256,7 @@ err_out_unmap:
}
err_out_release:
+ pci_disable_pcie_error_reporting(pdev);
pci_release_regions(pdev);
err_out_disable:
@@ -8436,6 +8447,9 @@ bnx2_remove_one(struct pci_dev *pdev)
kfree(bp->temp_stats_blk);
free_netdev(dev);
+
+ pci_disable_pcie_error_reporting(pdev);
+
pci_release_regions(pdev);
pci_disable_device(pdev);
pci_set_drvdata(pdev, NULL);
@@ -8527,25 +8541,35 @@ static pci_ers_result_t bnx2_io_slot_reset(struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev);
struct bnx2 *bp = netdev_priv(dev);
+ pci_ers_result_t result;
+ int err;
rtnl_lock();
if (pci_enable_device(pdev)) {
dev_err(&pdev->dev,
"Cannot re-enable PCI device after reset\n");
- rtnl_unlock();
- return PCI_ERS_RESULT_DISCONNECT;
+ result = PCI_ERS_RESULT_DISCONNECT;
+ } else {
+ pci_set_master(pdev);
+ pci_restore_state(pdev);
+ pci_save_state(pdev);
+
+ if (netif_running(dev)) {
+ bnx2_set_power_state(bp, PCI_D0);
+ bnx2_init_nic(bp, 1);
+ }
+ result = PCI_ERS_RESULT_RECOVERED;
}
- pci_set_master(pdev);
- pci_restore_state(pdev);
- pci_save_state(pdev);
+ rtnl_unlock();
- if (netif_running(dev)) {
- bnx2_set_power_state(bp, PCI_D0);
- bnx2_init_nic(bp, 1);
+ err = pci_cleanup_aer_uncorrect_error_status(pdev);
+ if (err) {
+ dev_err(&pdev->dev,
+ "pci_cleanup_aer_uncorrect_error_status failed 0x%0x\n",
+ err); /* non-fatal, continue */
}
- rtnl_unlock();
- return PCI_ERS_RESULT_RECOVERED;
+ return result;
}
/**
--
1.6.1.2
^ permalink raw reply related
* Re: [PATCH] mlx4: use bitmap library
From: David Miller @ 2010-08-23 3:52 UTC (permalink / raw)
To: akinobu.mita; +Cc: netdev, rolandd
In-Reply-To: <1282382688-5786-1-git-send-email-akinobu.mita@gmail.com>
From: Akinobu Mita <akinobu.mita@gmail.com>
Date: Sat, 21 Aug 2010 18:24:48 +0900
> Use bitmap_set() and bitmap_clear()
>
> Signed-off-by: Akinobu Mita <akinobu.mita@gmail.com>
Unlike loops calling set_bit() and clear_bit(), bitmap_set() and
bitmap_clear() are not atomic.
Are you sure this is ok here?
^ permalink raw reply
* Re: [PATCH] net: 802.1q: make vlan_hwaccel_do_receive() return void
From: David Miller @ 2010-08-23 4:03 UTC (permalink / raw)
To: xiaosuo; +Cc: kaber, netdev, herbert
In-Reply-To: <1282519918-10874-1-git-send-email-xiaosuo@gmail.com>
From: Changli Gao <xiaosuo@gmail.com>
Date: Mon, 23 Aug 2010 07:31:58 +0800
> @@ -2841,8 +2841,8 @@ static int __netif_receive_skb(struct sk_buff *skb)
> if (!netdev_tstamp_prequeue)
> net_timestamp_check(skb);
>
> - if (vlan_tx_tag_present(skb) && vlan_hwaccel_do_receive(skb))
> - return NET_RX_SUCCESS;
> + if (vlan_tx_tag_present(skb))
> + vlan_hwaccel_do_receive(skb);
>
Ok, I see how this happened. The code here first came from
Patrick:
commit 9b22ea560957de1484e6b3e8538f7eef202e3596
...
net: fix packet socket delivery in rx irq handler
And back then vlan_hwaccel_do_receive() returned "-1" and freed the
packet if cb->dev was NULL.
Herbert then added the GRO containers in:
commit e1c096e251e52773afeffbbcb74d0a072be47ea3
...
vlan: Add GRO interfaces
where skb->dev now stores what cb->dev used to, and the "-1"
return and cb->dev check were thus removed.
Anyways, with how things stand now this patch looks fine and
I'll apply it to net-next-2.6, thanks!
^ permalink raw reply
* Re: [rfc] bridge: is PACKET_LOOPBACK unlikely()?
From: David Miller @ 2010-08-23 4:14 UTC (permalink / raw)
To: horms; +Cc: netdev, bridge, jpirko, shemminger, jesse
In-Reply-To: <20100823033532.GA28463@verge.net.au>
From: Simon Horman <horms@verge.net.au>
Date: Mon, 23 Aug 2010 12:35:32 +0900
> While looking at using netdev_rx_handler_register for openvswitch Jesse
> Gross suggested that an unlikely() might be worthwhile in that code.
> I'm interested to see if its appropriate for the bridge code.
>
> Cc: Jesse Gross <jesse@nicira.com>
> Signed-off-by: Simon Horman <horms@verge.net.au>
Seems reasonable to me, applied to net-next-2.6
^ permalink raw reply
* Re: [PATCH net-next 1/1] bnx2: Add PCI Advanced Error Reporting support.
From: David Miller @ 2010-08-23 4:14 UTC (permalink / raw)
To: benli; +Cc: netdev, jfeeney, mchan
In-Reply-To: <1282535153-18291-2-git-send-email-benli@broadcom.com>
From: "Benjamin Li" <benli@broadcom.com>
Date: Sun, 22 Aug 2010 20:45:53 -0700
> From: John Feeney <jfeeney@redhat.com>
>
> Signed-off-by: John Feeney <jfeeney@redhat.com>
> Signed-off-by: Michael Chan <mchan@broadcom.com>
> Signed-off-by: Benjamin Li <benli@broadcom.com>
Applied.
^ permalink raw reply
* Re: [PATCH] net: rds: remove duplication type definitions
From: David Miller @ 2010-08-23 4:14 UTC (permalink / raw)
To: xiaosuo; +Cc: linux-kernel, netdev
In-Reply-To: <1282531319-13083-1-git-send-email-xiaosuo@gmail.com>
From: Changli Gao <xiaosuo@gmail.com>
Date: Mon, 23 Aug 2010 10:41:59 +0800
> __be* are defined in linux/types.h now, and in fact, rds.h isn't exported
> to user space even.
>
> Signed-off-by: Changli Gao <xiaosuo@gmail.com>
Applied to net-next-2.6
^ permalink raw reply
* Re: [PATCH] net: define __packed for the userspace code
From: David Miller @ 2010-08-23 4:16 UTC (permalink / raw)
To: xiaosuo; +Cc: arnd, eric.dumazet, linux-kernel, netdev
In-Reply-To: <20100822.193609.35028164.davem@davemloft.net>
From: David Miller <davem@davemloft.net>
Date: Sun, 22 Aug 2010 19:36:09 -0700 (PDT)
> From: Changli Gao <xiaosuo@gmail.com>
> Date: Mon, 23 Aug 2010 10:29:49 +0800
>
>> Do you mean that use the __attribute__((packed)) annotation in all of
>> these files:
>>
>> localhost linux # grep "\<__packed\>" usr/include/ -r | uniq
>> usr/include/linux/if_hippi.h:} __packed;
>> usr/include/linux/if_fddi.h:} __packed;
>> usr/include/linux/nbd.h:} __packed;
>> usr/include/linux/ncp.h:} __packed;
>> usr/include/linux/rfkill.h:} __packed;
>> usr/include/linux/if_pppox.h:} __packed;
>> usr/include/linux/phonet.h:} __packed;
>> usr/include/linux/ipv6.h:} __packed; /* required for some archs */
>> usr/include/linux/ipv6.h:} __packed;
>> usr/include/linux/if_ether.h:} __packed;
>
> It seems so, yes.
Changli I applied your patch to convert these __packed tags back to
the original expansion.
Thanks!
^ permalink raw reply
* Re: [PATCH] mlx4: use bitmap library
From: Akinobu Mita @ 2010-08-23 4:21 UTC (permalink / raw)
To: David Miller; +Cc: netdev, rolandd
In-Reply-To: <20100822.205231.116364886.davem@davemloft.net>
2010/8/23 David Miller <davem@davemloft.net>:
> From: Akinobu Mita <akinobu.mita@gmail.com>
> Date: Sat, 21 Aug 2010 18:24:48 +0900
>
>> Use bitmap_set() and bitmap_clear()
>>
>> Signed-off-by: Akinobu Mita <akinobu.mita@gmail.com>
>
> Unlike loops calling set_bit() and clear_bit(), bitmap_set() and
> bitmap_clear() are not atomic.
>
> Are you sure this is ok here?
>
I think this ok. Because the bitmap region is searched by
bitmap_find_next_zero_area() which cannot be atomic and
setting and clearing the bitmap region is protected by bitmap->lock
(except for initialization of the bitmap in mlx4_bitmap_init).
This change should be done when I submitted commit
43ff8b60853793fb0155b3e465739d2170c3aa2f ("mlx4: use
bitmap_find_next_zero_area")
at the same time.
I'll recheck this is ok and update the commit message for this change,
then resubmit the patch.
^ permalink raw reply
* Re: [PATCH] mlx4: use bitmap library
From: David Miller @ 2010-08-23 4:26 UTC (permalink / raw)
To: akinobu.mita; +Cc: netdev, rolandd
In-Reply-To: <AANLkTinNf1vsQqR34Qeh4jO-xt7m1wYWGC9-dA6mU+__@mail.gmail.com>
From: Akinobu Mita <akinobu.mita@gmail.com>
Date: Mon, 23 Aug 2010 13:21:55 +0900
> I'll recheck this is ok and update the commit message for this change,
> then resubmit the patch.
Ok, thank you.
^ permalink raw reply
* Re: [PATCH] bridge: netfilter: fix a memory leak
From: David Miller @ 2010-08-23 4:36 UTC (permalink / raw)
To: xiaosuo; +Cc: shemminger, bridge, netdev
In-Reply-To: <1282280596-18992-1-git-send-email-xiaosuo@gmail.com>
From: Changli Gao <xiaosuo@gmail.com>
Date: Fri, 20 Aug 2010 13:03:16 +0800
> nf_bridge_alloc() always reset the skb->nf_bridge, so we should always
> put the old one. skb->nf_bridge->use is initialized in nf_bridge_alloc(),
> so we don't need to initialize it again.
>
> Signed-off-by: Changli Gao <xiaosuo@gmail.com>
We just memcpy()'d 'nf_bridge' to 'tmp', that why the ->use count is
going to be something other than '1'. It now has the ->use count that
'nf_bridge' did.
And that is why we must explicitly do atomic_set() on 'tmp'.
^ permalink raw reply
* Re: [PATCH -next] isdn/avm: fix build when PCMCIA is not enabled
From: David Miller @ 2010-08-23 4:37 UTC (permalink / raw)
To: randy.dunlap; +Cc: sfr, calle, isdn, linux-next, linux-kernel, netdev
In-Reply-To: <20100819100723.d0c0578e.randy.dunlap@oracle.com>
From: Randy Dunlap <randy.dunlap@oracle.com>
Date: Thu, 19 Aug 2010 10:07:23 -0700
> From: Randy Dunlap <randy.dunlap@oracle.com>
>
> Why wouldn't kconfig symbol ISDN_DRV_AVMB1_B1PCMCIA also depend on
> PCMCIA?
>
> Fix build for PCMCIA not enabled:
...
> Signed-off-by: Randy Dunlap <randy.dunlap@oracle.com>
Applied to net-2.6, thanks Randy.
^ permalink raw reply
* Re: [PATCH] bridge: netfilter: fix a memory leak
From: Changli Gao @ 2010-08-23 4:40 UTC (permalink / raw)
To: David Miller; +Cc: shemminger, bridge, netdev
In-Reply-To: <20100822.213632.191389158.davem@davemloft.net>
On Mon, Aug 23, 2010 at 12:36 PM, David Miller <davem@davemloft.net> wrote:
> From: Changli Gao <xiaosuo@gmail.com>
> Date: Fri, 20 Aug 2010 13:03:16 +0800
>
>> nf_bridge_alloc() always reset the skb->nf_bridge, so we should always
>> put the old one. skb->nf_bridge->use is initialized in nf_bridge_alloc(),
>> so we don't need to initialize it again.
>>
>> Signed-off-by: Changli Gao <xiaosuo@gmail.com>
>
> We just memcpy()'d 'nf_bridge' to 'tmp', that why the ->use count is
> going to be something other than '1'. It now has the ->use count that
> 'nf_bridge' did.
>
> And that is why we must explicitly do atomic_set() on 'tmp'.
>
Oops, thanks. I'll post a update.
--
Regards,
Changli Gao(xiaosuo@gmail.com)
^ permalink raw reply
* Re: [PATCH] tcp: allow effective reduction of TCP's rcv-buffer via setsockopt
From: David Miller @ 2010-08-23 4:44 UTC (permalink / raw)
To: hagen; +Cc: netdev, kaber, eric.dumazet, ilpo.jarvinen
In-Reply-To: <1282235585-14206-1-git-send-email-hagen@jauu.net>
From: Hagen Paul Pfeifer <hagen@jauu.net>
Date: Thu, 19 Aug 2010 18:33:05 +0200
> Via setsockopt it is possible to reduce the socket RX buffer
> (SO_RCVBUF). TCP method to select the initial window and window scaling
> option in tcp_select_initial_window() currently misbehaves and do not
> consider a reduced RX socket buffer via setsockopt.
>
> Even though the server's RX buffer is reduced via setsockopt() to 256
> byte (Initial Window 384 byte => 256 * 2 - (256 * 2 / 4)) the window
> scale option is still 7:
>
> 192.168.1.38.40676 > 78.47.222.210.5001: Flags [S], seq 2577214362, win 5840, options [mss 1460,sackOK,TS val 338417 ecr 0,nop,wscale 0], length 0
> 78.47.222.210.5001 > 192.168.1.38.40676: Flags [S.], seq 1570631029, ack 2577214363, win 384, options [mss 1452,sackOK,TS val 2435248895 ecr 338417,nop,wscale 7], length 0
> 192.168.1.38.40676 > 78.47.222.210.5001: Flags [.], ack 1, win 5840, options [nop,nop,TS val 338421 ecr 2435248895], length 0
>
> Within tcp_select_initial_window() the original space argument - a
> representation of the rx buffer size - is expanded during
> tcp_select_initial_window(). Only sysctl_tcp_rmem[2], sysctl_rmem_max
> and window_clamp are considered to calculate the initial window.
>
> This patch adjust the window_clamp argument if the user explicitly
> reduce the receive buffer.
>
> Signed-off-by: Hagen Paul Pfeifer <hagen@jauu.net>
Applied, thanks.
^ permalink raw reply
* Re: [PATCH 1/2] xen: use less generic names in netfront driver.
From: David Miller @ 2010-08-23 4:44 UTC (permalink / raw)
To: ian.campbell; +Cc: netdev, jeremy, xen-devel, jeremy.fitzhardinge
In-Reply-To: <1282210070-7745-1-git-send-email-ian.campbell@citrix.com>
From: Ian Campbell <ian.campbell@citrix.com>
Date: Thu, 19 Aug 2010 10:27:49 +0100
> All Xen frontend drivers have a couple of identically named functions which
> makes figuring out which device went wrong from a stacktrace harder than it
> needs to be. Rename them to something specificto the device type.
>
> Signed-off-by: Ian Campbell <ian.campbell@citrix.com>
> Cc: Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com>
Applied.
^ permalink raw reply
* Re: [Patch 2/2] mlx4: remove num_lro parameter
From: David Miller @ 2010-08-23 4:45 UTC (permalink / raw)
To: amwang; +Cc: netdev, bhutchings, Ramkrishna.Vepa, sgruszka
In-Reply-To: <20100818075540.5926.9432.sendpatchset@localhost.localdomain>
From: Amerigo Wang <amwang@redhat.com>
Date: Wed, 18 Aug 2010 03:51:18 -0400
>
> As suggested by David, this parameter can die, we can use ethtool
> to turn LRO on/off. Compile tests only.
>
> Signed-off-by: WANG Cong <amwang@redhat.com>
Applied.
^ permalink raw reply
* [PATCH v2] bridge: netfilter: fix a memory leak
From: Changli Gao @ 2010-08-23 5:03 UTC (permalink / raw)
To: David S. Miller; +Cc: Stephen Hemminger, bridge, netdev, Changli Gao
nf_bridge_alloc() always reset the skb->nf_bridge, so we should always
put the old one.
Signed-off-by: Changli Gao <xiaosuo@gmail.com>
---
v2: Should init tmp->use again because memcpy() overwrite it.
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c
index 2c911c0..5ed00bd 100644
--- a/net/bridge/br_netfilter.c
+++ b/net/bridge/br_netfilter.c
@@ -162,8 +162,8 @@ static inline struct nf_bridge_info *nf_bridge_unshare(struct sk_buff *skb)
if (tmp) {
memcpy(tmp, nf_bridge, sizeof(struct nf_bridge_info));
atomic_set(&tmp->use, 1);
- nf_bridge_put(nf_bridge);
}
+ nf_bridge_put(nf_bridge);
nf_bridge = tmp;
}
return nf_bridge;
^ permalink raw reply related
* [PATCH] xps-mq: Transmit Packet Steering for multiqueue
From: Tom Herbert @ 2010-08-23 5:39 UTC (permalink / raw)
To: davem, netdev; +Cc: eric.dumazet
This patch implements transmit packet steering (XPS) for multiqueue
devices. XPS selects a transmit queue during packet transmission based
on configuration. This is done by mapping the CPU transmitting the
packet to a queue. This is the transmit side analogue to RPS-- where
RPS is selecting a CPU based on receive queue, XPS selects a queue
based on the CPU (previously there was an XPS patch from Eric
Dumazet, but that might more appropriately be called transmit completion
steering).
Each transmit queue can be associated with a number of CPUs which will
used the queue to send packets. This is configured as a CPU mask on a
per queue basis in:
/sys/class/net/eth<n>/queues/tx-<n>/xps_cpus
The mappings are stored per device in an inverted data structure that
maps CPUs to queues. In the netdevice structure this is an array of
num_possible_cpu structures where each array entry contains a bit map
of queues which that CPU can use.
We also allow the mapping of a socket to queue to be modified, for
instance if a thread is scheduled on a different CPU the desired queue
for transmitting packets would likely change. To maintain in order
packet transmission a flag (ooo_okay) has been added to the sk_buf
structure. If a transport layer sets this flag on a packet, the
transmit queue can be changed for this socket. Presumably, the
transport would set this is there was no possbility of creating ooo
packets (for instance there are no packets in flight for the socket).
This patch includes the modification in TCP output for setting this
flag.
The benefits of XPS are improved locality in the per queue data
strutures. Also, transmit completions are more likely to be done
nearer to the sending thread so this should promote locality back
to the socket (e.g. UDP). The benefits of XPS are dependent on
cache hierarchy, application load, and other factors. XPS would
nominally be configured so that a queue would only be shared by CPUs
which are sharing a cache, the degenerative configuration woud be that
each CPU has it's own queue.
Below are some benchmark results which show the potential benfit of
this patch. The netperf test has 500 instances of netperf TCP_RR test
with 1 byte req. and resp.
bnx2x on 16 core AMD
XPS (16 queues, 1 TX queue per CPU) 1015K at 99% CPU
No XPS (16 queues) 1127K at 98% CPU
Signed-off-by: Tom Herbert <therbert@google.com>
---
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 46c36ff..0ff6c9f 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -497,6 +497,12 @@ struct netdev_queue {
struct Qdisc *qdisc;
unsigned long state;
struct Qdisc *qdisc_sleeping;
+#ifdef CONFIG_RPS
+ struct kobject kobj;
+ struct netdev_queue *first;
+ atomic_t count;
+#endif
+
/*
* write mostly part
*/
@@ -524,6 +530,22 @@ struct rps_map {
#define RPS_MAP_SIZE(_num) (sizeof(struct rps_map) + (_num * sizeof(u16)))
/*
+ * This structure holds an XPS map which can be of variable length. queues
+ * is an array of num_possible_cpus entries, where each entry is a mask of
+ * queues for that CPU (up to num_tx_queues bits for device).
+ */
+struct xps_map {
+ struct rcu_head rcu;
+ unsigned long queues[0];
+};
+
+#define QUEUE_MASK_SIZE(dev) (BITS_TO_LONGS(dev->num_tx_queues))
+#define XPS_MAP_SIZE(dev) (sizeof(struct xps_map) + (num_possible_cpus() * \
+ QUEUE_MASK_SIZE(dev) * sizeof(unsigned long)))
+#define XPS_ENTRY(map, offset, dev) \
+ (&map->queues[offset * QUEUE_MASK_SIZE(dev)])
+
+/*
* The rps_dev_flow structure contains the mapping of a flow to a CPU and the
* tail pointer for that CPU's input queue at the time of last enqueue.
*/
@@ -978,6 +1000,9 @@ struct net_device {
void *rx_handler_data;
struct netdev_queue *_tx ____cacheline_aligned_in_smp;
+#ifdef CONFIG_RPS
+ struct xps_map *xps_maps;
+#endif
/* Number of TX queues allocated at alloc_netdev_mq() time */
unsigned int num_tx_queues;
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index f067c95..146df6f 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -381,6 +381,7 @@ struct sk_buff {
#else
__u8 deliver_no_wcard:1;
#endif
+ __u8 ooo_okay:1;
kmemcheck_bitfield_end(flags2);
/* 0/14 bit hole */
diff --git a/net/core/dev.c b/net/core/dev.c
index da584f5..d23f9c4 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -2054,6 +2054,60 @@ static inline u16 dev_cap_txqueue(struct net_device *dev, u16 queue_index)
return queue_index;
}
+static inline int get_xps_queue(struct net_device *dev, struct sk_buff *skb,
+ int queue_index)
+{
+ struct xps_map *maps;
+ int cpu = smp_processor_id();
+ u32 hash;
+ unsigned long *queues;
+ int weight, select;
+
+ rcu_read_lock();
+ maps = rcu_dereference(dev->xps_maps);
+
+ if (!maps) {
+ rcu_read_unlock();
+ return queue_index;
+ }
+
+ queues = XPS_ENTRY(maps, cpu, dev);
+
+ if (queue_index >= 0) {
+ if (test_bit(queue_index, queues)) {
+ rcu_read_unlock();
+ return queue_index;
+ }
+ }
+
+ weight = bitmap_weight(queues, dev->real_num_tx_queues);
+ switch (weight) {
+ case 0:
+ break;
+ case 1:
+ queue_index =
+ find_first_bit(queues, dev->real_num_tx_queues);
+ break;
+ default:
+ if (skb->sk && skb->sk->sk_hash)
+ hash = skb->sk->sk_hash;
+ else
+ hash = (__force u16) skb->protocol ^ skb->rxhash;
+ hash = jhash_1word(hash, hashrnd);
+
+ select = ((u64) hash * weight) >> 32;
+ queue_index =
+ find_first_bit(queues, dev->real_num_tx_queues);
+ while (select--)
+ queue_index = find_next_bit(queues,
+ dev->real_num_tx_queues, queue_index);
+ break;
+ }
+
+ rcu_read_unlock();
+ return queue_index;
+}
+
static struct netdev_queue *dev_pick_tx(struct net_device *dev,
struct sk_buff *skb)
{
@@ -2061,23 +2115,30 @@ static struct netdev_queue *dev_pick_tx(struct net_device *dev,
struct sock *sk = skb->sk;
queue_index = sk_tx_queue_get(sk);
- if (queue_index < 0) {
+
+ if (queue_index < 0 || (skb->ooo_okay && dev->real_num_tx_queues > 1)) {
const struct net_device_ops *ops = dev->netdev_ops;
+ int old_index = queue_index;
if (ops->ndo_select_queue) {
queue_index = ops->ndo_select_queue(dev, skb);
queue_index = dev_cap_txqueue(dev, queue_index);
} else {
- queue_index = 0;
- if (dev->real_num_tx_queues > 1)
- queue_index = skb_tx_hash(dev, skb);
+ if (dev->real_num_tx_queues > 1) {
+ queue_index = get_xps_queue(dev,
+ skb, queue_index);
+ if (queue_index < 0)
+ queue_index = skb_tx_hash(dev, skb);
+ } else
+ queue_index = 0;
+ }
- if (sk) {
- struct dst_entry *dst = rcu_dereference_check(sk->sk_dst_cache, 1);
+ if ((queue_index != old_index) && sk) {
+ struct dst_entry *dst =
+ rcu_dereference_check(sk->sk_dst_cache, 1);
- if (dst && skb_dst(skb) == dst)
- sk_tx_queue_set(sk, queue_index);
- }
+ if (dst && skb_dst(skb) == dst)
+ sk_tx_queue_set(sk, queue_index);
}
}
@@ -5429,6 +5490,15 @@ struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name,
}
#ifdef CONFIG_RPS
+ atomic_set(&tx->count, queue_count);
+
+ /*
+ * Set a pointer to first element in the array which holds the
+ * reference count.
+ */
+ for (i = 0; i < queue_count; i++)
+ tx[i].first = tx;
+
rx = kcalloc(queue_count, sizeof(struct netdev_rx_queue), GFP_KERNEL);
if (!rx) {
printk(KERN_ERR "alloc_netdev: Unable to allocate "
@@ -5506,7 +5576,9 @@ void free_netdev(struct net_device *dev)
release_net(dev_net(dev));
+#ifndef CONFIG_RPS
kfree(dev->_tx);
+#endif
/* Flush device addresses */
dev_addr_flush(dev);
diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c
index af4dfba..661c481 100644
--- a/net/core/net-sysfs.c
+++ b/net/core/net-sysfs.c
@@ -742,34 +742,295 @@ static int rx_queue_add_kobject(struct net_device *net, int index)
return error;
}
-static int rx_queue_register_kobjects(struct net_device *net)
+/*
+ * netdev_queue sysfs structures and functions.
+ */
+struct netdev_queue_attribute {
+ struct attribute attr;
+ ssize_t (*show)(struct netdev_queue *queue,
+ struct netdev_queue_attribute *attr, char *buf);
+ ssize_t (*store)(struct netdev_queue *queue,
+ struct netdev_queue_attribute *attr, const char *buf, size_t len);
+};
+#define to_netdev_queue_attr(_attr) container_of(_attr, \
+ struct netdev_queue_attribute, attr)
+
+#define to_netdev_queue(obj) container_of(obj, struct netdev_queue, kobj)
+
+static ssize_t netdev_queue_attr_show(struct kobject *kobj,
+ struct attribute *attr, char *buf)
+{
+ struct netdev_queue_attribute *attribute = to_netdev_queue_attr(attr);
+ struct netdev_queue *queue = to_netdev_queue(kobj);
+
+ if (!attribute->show)
+ return -EIO;
+
+ return attribute->show(queue, attribute, buf);
+}
+
+static ssize_t netdev_queue_attr_store(struct kobject *kobj,
+ struct attribute *attr,
+ const char *buf, size_t count)
+{
+ struct netdev_queue_attribute *attribute = to_netdev_queue_attr(attr);
+ struct netdev_queue *queue = to_netdev_queue(kobj);
+
+ if (!attribute->store)
+ return -EIO;
+
+ return attribute->store(queue, attribute, buf, count);
+}
+
+static struct sysfs_ops netdev_queue_sysfs_ops = {
+ .show = netdev_queue_attr_show,
+ .store = netdev_queue_attr_store,
+};
+
+static inline unsigned int get_netdev_queue_index(struct netdev_queue *queue)
{
+ struct net_device *dev = queue->dev;
+ int i;
+
+ for (i = 0; i < dev->num_tx_queues; i++)
+ if (queue == &dev->_tx[i])
+ break;
+
+ BUG_ON(i >= dev->num_tx_queues);
+
+ return i;
+}
+
+static ssize_t show_xps_map(struct netdev_queue *queue,
+ struct netdev_queue_attribute *attribute, char *buf)
+{
+ struct net_device *dev = queue->dev;
+ struct xps_map *maps;
+ cpumask_var_t mask;
+ unsigned long *qmask, index;
+ size_t len = 0;
int i;
+ unsigned int qmask_size = QUEUE_MASK_SIZE(dev);
+
+ if (!zalloc_cpumask_var(&mask, GFP_KERNEL))
+ return -ENOMEM;
+
+ index = get_netdev_queue_index(queue);
+
+ rcu_read_lock();
+ maps = rcu_dereference(dev->xps_maps);
+ if (maps) {
+ qmask = maps->queues;
+ for (i = 0; i < num_possible_cpus(); i++) {
+ if (test_bit(index, qmask))
+ cpumask_set_cpu(i, mask);
+ qmask += qmask_size;
+ }
+ }
+ len += cpumask_scnprintf(buf + len, PAGE_SIZE, mask);
+ if (PAGE_SIZE - len < 3) {
+ rcu_read_unlock();
+ free_cpumask_var(mask);
+ return -EINVAL;
+ }
+ rcu_read_unlock();
+
+ free_cpumask_var(mask);
+ len += sprintf(buf + len, "\n");
+ return len;
+}
+
+static void xps_map_release(struct rcu_head *rcu)
+{
+ struct xps_map *map = container_of(rcu, struct xps_map, rcu);
+
+ kfree(map);
+}
+
+static DEFINE_MUTEX(xps_map_lock);
+
+static ssize_t store_xps_map(struct netdev_queue *queue,
+ struct netdev_queue_attribute *attribute,
+ const char *buf, size_t len)
+{
+ struct net_device *dev = queue->dev;
+ struct xps_map *maps;
+ cpumask_var_t mask;
+ int err, i, nonempty = 0;
+ unsigned long *qmask, index;
+ unsigned int qmask_size = QUEUE_MASK_SIZE(dev);
+
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ if (!alloc_cpumask_var(&mask, GFP_KERNEL))
+ return -ENOMEM;
+
+ err = bitmap_parse(buf, len, cpumask_bits(mask), nr_cpumask_bits);
+ if (err) {
+ free_cpumask_var(mask);
+ return err;
+ }
+
+ mutex_lock(&xps_map_lock);
+
+ maps = dev->xps_maps;
+ if (!maps) {
+ if (!cpumask_weight(mask)) {
+ mutex_unlock(&xps_map_lock);
+ free_cpumask_var(mask);
+ return 0;
+ }
+ maps = kzalloc(XPS_MAP_SIZE(dev), GFP_KERNEL);
+ if (!maps) {
+ mutex_unlock(&xps_map_lock);
+ free_cpumask_var(mask);
+ return -ENOMEM;
+ }
+ rcu_assign_pointer(dev->xps_maps, maps);
+ }
+
+ index = get_netdev_queue_index(queue);
+
+ qmask = maps->queues;
+ for (i = 0; i < num_possible_cpus(); i++) {
+ if (cpu_isset(i, *mask) && cpu_online(i)) {
+ set_bit(index, qmask);
+ nonempty = 1;
+ } else
+ clear_bit(index, qmask);
+ if (!nonempty &&
+ bitmap_weight(qmask, dev->real_num_tx_queues))
+ nonempty = 1;
+ qmask += qmask_size;
+ }
+
+ if (!nonempty) {
+ rcu_assign_pointer(dev->xps_maps, NULL);
+ call_rcu(&maps->rcu, xps_map_release);
+ }
+
+ mutex_unlock(&xps_map_lock);
+
+ free_cpumask_var(mask);
+ return len;
+}
+
+static struct netdev_queue_attribute xps_cpus_attribute =
+ __ATTR(xps_cpus, S_IRUGO | S_IWUSR, show_xps_map, store_xps_map);
+
+static struct attribute *netdev_queue_default_attrs[] = {
+ &xps_cpus_attribute.attr,
+ NULL
+};
+
+static void netdev_queue_release(struct kobject *kobj)
+{
+ struct netdev_queue *queue = to_netdev_queue(kobj);
+ struct net_device *dev = queue->dev;
+ struct netdev_queue *first = queue->first;
+ struct xps_map *maps;
+ unsigned long *qmask, index;
+ int i, nonempty = 0;
+ unsigned int qmask_size = QUEUE_MASK_SIZE(dev);
+
+ index = get_netdev_queue_index(queue);
+
+ mutex_lock(&xps_map_lock);
+
+ maps = dev->xps_maps;
+
+ if (maps) {
+ qmask = maps->queues;
+ for (i = 0; i < num_possible_cpus(); i++) {
+ clear_bit(index, qmask);
+ if (!nonempty &&
+ bitmap_weight(qmask, dev->real_num_tx_queues))
+ nonempty = 1;
+ qmask += qmask_size;
+ }
+
+ if (!nonempty) {
+ rcu_assign_pointer(dev->xps_maps, NULL);
+ call_rcu(&maps->rcu, xps_map_release);
+ }
+ }
+ mutex_unlock(&xps_map_lock);
+
+ if (atomic_dec_and_test(&first->count)) {
+ kfree(first);
+ dev_put(dev);
+ }
+}
+
+static struct kobj_type netdev_queue_ktype = {
+ .sysfs_ops = &netdev_queue_sysfs_ops,
+ .release = netdev_queue_release,
+ .default_attrs = netdev_queue_default_attrs,
+};
+
+static int netdev_queue_add_kobject(struct net_device *net, int index)
+{
+ struct netdev_queue *queue = net->_tx + index;
+ struct kobject *kobj = &queue->kobj;
+ int error = 0;
+
+ kobj->kset = net->queues_kset;
+ error = kobject_init_and_add(kobj, &netdev_queue_ktype, NULL,
+ "tx-%u", index);
+ if (error) {
+ kobject_put(kobj);
+ return error;
+ }
+
+ kobject_uevent(kobj, KOBJ_ADD);
+
+ return error;
+}
+
+static int register_queue_kobjects(struct net_device *net)
+{
+ int rx = 0, tx = 0;
int error = 0;
net->queues_kset = kset_create_and_add("queues",
NULL, &net->dev.kobj);
if (!net->queues_kset)
return -ENOMEM;
- for (i = 0; i < net->num_rx_queues; i++) {
- error = rx_queue_add_kobject(net, i);
+
+ for (rx = 0; rx < net->num_rx_queues; rx++) {
+ error = rx_queue_add_kobject(net, rx);
if (error)
- break;
+ goto error;
}
- if (error)
- while (--i >= 0)
- kobject_put(&net->_rx[i].kobj);
+ for (tx = 0; tx < net->num_tx_queues; tx++) {
+ error = netdev_queue_add_kobject(net, tx);
+ if (error)
+ goto error;
+ }
+ dev_hold(net);
+
+ return error;
+
+error:
+ while (--rx >= 0)
+ kobject_put(&net->_rx[rx].kobj);
+
+ while (--tx >= 0)
+ kobject_put(&net->_tx[tx].kobj);
return error;
}
-static void rx_queue_remove_kobjects(struct net_device *net)
+static void remove_queue_kobjects(struct net_device *net)
{
int i;
for (i = 0; i < net->num_rx_queues; i++)
kobject_put(&net->_rx[i].kobj);
+ for (i = 0; i < net->num_tx_queues; i++)
+ kobject_put(&net->_tx[i].kobj);
kset_unregister(net->queues_kset);
}
#endif /* CONFIG_RPS */
@@ -871,7 +1132,7 @@ void netdev_unregister_kobject(struct net_device * net)
kobject_get(&dev->kobj);
#ifdef CONFIG_RPS
- rx_queue_remove_kobjects(net);
+ remove_queue_kobjects(net);
#endif
device_del(dev);
@@ -912,7 +1173,7 @@ int netdev_register_kobject(struct net_device *net)
return error;
#ifdef CONFIG_RPS
- error = rx_queue_register_kobjects(net);
+ error = register_queue_kobjects(net);
if (error) {
device_del(dev);
return error;
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index de3bd84..80c1928 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -828,8 +828,10 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it,
&md5);
tcp_header_size = tcp_options_size + sizeof(struct tcphdr);
- if (tcp_packets_in_flight(tp) == 0)
+ if (tcp_packets_in_flight(tp) == 0) {
tcp_ca_event(sk, CA_EVENT_TX_START);
+ skb->ooo_okay = 1;
+ }
skb_push(skb, tcp_header_size);
skb_reset_transport_header(skb);
^ permalink raw reply related
* netdev-2.6 [PATCH 0/5] dccp: ccid-2/3 code clean up; TCP RTT estimator
From: Gerrit Renker @ 2010-08-23 5:41 UTC (permalink / raw)
To: davem; +Cc: dccp, netdev
In-Reply-To: <20100820.004005.58446090.davem@davemloft.net>
Dear Dave,
please would you consider consider the following DCCP CCID-2/3 set (applies to
netdev-2.6): it does code clean-up and adds a better RTO estimation to CCID-2.
Patch #1: aggregates the cosmetic changes (whitespace, documentation etc.).
Patch #2: removes redundant test for CCID block in LISTEN state. As a byproduct
of integrating the feature-negotiation changeset last year, that test
is now redundant, simplifying the code.
Patch #3: removes a sanity-check function from CCID-2 and provides a (lengthy)
explanation why this test is indeed redundant.
Patch #4: simplifies and consolidates the code to rearm the CCID-2 RTO timer.
Patch #5: replaces the broken CCID-2 RTT estimator algorithm with a better one
('better' means "stolen from the TCP code", this was not done blindly
but as a result of testing, it may even be possible to later share
the RTT estimation code between TCP and CCID-2).
All patches have been in the test tree at git://eden-feed.erg.abdn.ac.uk
for more than 2 years and compile independently.
^ permalink raw reply
* [PATCH 4/5] dccp ccid-2: Simplify dec_pipe and rearming of RTO timer
From: Gerrit Renker @ 2010-08-23 5:41 UTC (permalink / raw)
To: davem; +Cc: dccp, netdev, Gerrit Renker
In-Reply-To: <1282542100-5799-4-git-send-email-gerrit@erg.abdn.ac.uk>
This removes the dec_pipe function and improves the way the RTO timer is rearmed
when a new acknowledgment comes in.
Details and justification for removal:
--------------------------------------
1) The BUG_ON in dec_pipe is never triggered: pipe is only decremented for TX
history entries between tail and head, for which it had previously been
incremented in tx_packet_sent; and it is not decremented twice for the same
entry, since it is
- either decremented when a corresponding Ack Vector cell in state 0 or 1
was received (and then ccid2s_acked==1),
- or it is decremented when ccid2s_acked==0, as part of the loss detection
in tx_packet_recv (and hence it can not have been decremented earlier).
2) Restarting the RTO timer happens for every single entry in each Ack Vector
parsed by tx_packet_recv (according to RFC 4340, 11.4 this can happen up to
16192 times per Ack Vector).
3) The RTO timer should not be restarted when all outstanding data has been
acknowledged. This is currently done similar to (2), in dec_pipe, when
pipe has reached 0.
The patch onsolidates the code which rearms the RTO timer, combining the
segments from new_ack and dec_pipe. As a result, the code becomes clearer
(compare with tcp_rearm_rto()).
Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
---
net/dccp/ccids/ccid2.c | 27 ++++++++-------------------
1 files changed, 8 insertions(+), 19 deletions(-)
--- a/net/dccp/ccids/ccid2.c
+++ b/net/dccp/ccids/ccid2.c
@@ -413,23 +413,6 @@ static inline void ccid2_new_ack(struct sock *sk,
hc->tx_srtt, hc->tx_rttvar,
hc->tx_rto, HZ, r);
}
-
- /* we got a new ack, so re-start RTO timer */
- ccid2_hc_tx_kill_rto_timer(sk);
- ccid2_start_rto_timer(sk);
-}
-
-static void ccid2_hc_tx_dec_pipe(struct sock *sk)
-{
- struct ccid2_hc_tx_sock *hc = ccid2_hc_tx_sk(sk);
-
- if (hc->tx_pipe == 0)
- DCCP_BUG("pipe == 0");
- else
- hc->tx_pipe--;
-
- if (hc->tx_pipe == 0)
- ccid2_hc_tx_kill_rto_timer(sk);
}
static void ccid2_congestion_event(struct sock *sk, struct ccid2_seq *seqp)
@@ -572,7 +555,7 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
seqp->ccid2s_acked = 1;
ccid2_pr_debug("Got ack for %llu\n",
(unsigned long long)seqp->ccid2s_seq);
- ccid2_hc_tx_dec_pipe(sk);
+ hc->tx_pipe--;
}
if (seqp == hc->tx_seqt) {
done = 1;
@@ -629,7 +612,7 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
* one ack vector.
*/
ccid2_congestion_event(sk, seqp);
- ccid2_hc_tx_dec_pipe(sk);
+ hc->tx_pipe--;
}
if (seqp == hc->tx_seqt)
break;
@@ -646,6 +629,12 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
hc->tx_seqt = hc->tx_seqt->ccid2s_next;
}
+
+ /* restart RTO timer if not all outstanding data has been acked */
+ if (hc->tx_pipe == 0)
+ sk_stop_timer(sk, &hc->tx_rtotimer);
+ else
+ sk_reset_timer(sk, &hc->tx_rtotimer, jiffies + hc->tx_rto);
}
static int ccid2_hc_tx_init(struct ccid *ccid, struct sock *sk)
^ permalink raw reply
* [PATCH 2/5] dccp ccid-3: No more CCID control blocks in LISTEN state
From: Gerrit Renker @ 2010-08-23 5:41 UTC (permalink / raw)
To: davem; +Cc: dccp, netdev, Gerrit Renker
In-Reply-To: <1282542100-5799-2-git-send-email-gerrit@erg.abdn.ac.uk>
The CCIDs are activated as last of the features, at the end of the handshake,
were the LISTEN state of the master socket is inherited into the server
state of the child socket. Thus, the only states visible to CCIDs now are
OPEN/PARTOPEN, and the closing states.
This allows to remove tests which were previously necessary to protect
against referencing a socket in the listening state (in CCID-3), but which
now have become redundant.
As a further byproduct of enabling the CCIDs only after the connection has been
fully established, several typecast-initialisations of ccid3_hc_{rx,tx}_sock
can now be eliminated:
* the CCID is loaded, so it is not necessary to test if it is NULL,
* if it is possible to load a CCID and leave the private area NULL, then this
is a bug, which should crash loudly - and earlier,
* the test for state==OPEN || state==PARTOPEN now reduces only to the closing
phase (e.g. when the node has received an unexpected Reset).
Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
net/dccp/ccids/ccid3.c | 40 +++++++---------------------------------
1 files changed, 7 insertions(+), 33 deletions(-)
--- a/net/dccp/ccids/ccid3.c
+++ b/net/dccp/ccids/ccid3.c
@@ -564,29 +564,17 @@ static void ccid3_hc_tx_exit(struct sock *sk)
static void ccid3_hc_tx_get_info(struct sock *sk, struct tcp_info *info)
{
- struct ccid3_hc_tx_sock *hc;
-
- /* Listen socks doesn't have a private CCID block */
- if (sk->sk_state == DCCP_LISTEN)
- return;
-
- hc = ccid3_hc_tx_sk(sk);
- info->tcpi_rto = hc->tx_t_rto;
- info->tcpi_rtt = hc->tx_rtt;
+ info->tcpi_rto = ccid3_hc_tx_sk(sk)->tx_t_rto;
+ info->tcpi_rtt = ccid3_hc_tx_sk(sk)->tx_rtt;
}
static int ccid3_hc_tx_getsockopt(struct sock *sk, const int optname, int len,
u32 __user *optval, int __user *optlen)
{
- const struct ccid3_hc_tx_sock *hc;
+ const struct ccid3_hc_tx_sock *hc = ccid3_hc_tx_sk(sk);
struct tfrc_tx_info tfrc;
const void *val;
- /* Listen socks doesn't have a private CCID block */
- if (sk->sk_state == DCCP_LISTEN)
- return -EINVAL;
-
- hc = ccid3_hc_tx_sk(sk);
switch (optname) {
case DCCP_SOCKOPT_CCID_TX_INFO:
if (len < sizeof(tfrc))
@@ -706,14 +694,12 @@ static void ccid3_hc_rx_send_feedback(struct sock *sk,
static int ccid3_hc_rx_insert_options(struct sock *sk, struct sk_buff *skb)
{
- const struct ccid3_hc_rx_sock *hc;
+ const struct ccid3_hc_rx_sock *hc = ccid3_hc_rx_sk(sk);
__be32 x_recv, pinv;
if (!(sk->sk_state == DCCP_OPEN || sk->sk_state == DCCP_PARTOPEN))
return 0;
- hc = ccid3_hc_rx_sk(sk);
-
if (dccp_packet_without_ack(skb))
return 0;
@@ -876,30 +862,18 @@ static void ccid3_hc_rx_exit(struct sock *sk)
static void ccid3_hc_rx_get_info(struct sock *sk, struct tcp_info *info)
{
- const struct ccid3_hc_rx_sock *hc;
-
- /* Listen socks doesn't have a private CCID block */
- if (sk->sk_state == DCCP_LISTEN)
- return;
-
- hc = ccid3_hc_rx_sk(sk);
- info->tcpi_ca_state = hc->rx_state;
+ info->tcpi_ca_state = ccid3_hc_rx_sk(sk)->rx_state;
info->tcpi_options |= TCPI_OPT_TIMESTAMPS;
- info->tcpi_rcv_rtt = hc->rx_rtt;
+ info->tcpi_rcv_rtt = ccid3_hc_rx_sk(sk)->rx_rtt;
}
static int ccid3_hc_rx_getsockopt(struct sock *sk, const int optname, int len,
u32 __user *optval, int __user *optlen)
{
- const struct ccid3_hc_rx_sock *hc;
+ const struct ccid3_hc_rx_sock *hc = ccid3_hc_rx_sk(sk);
struct tfrc_rx_info rx_info;
const void *val;
- /* Listen socks doesn't have a private CCID block */
- if (sk->sk_state == DCCP_LISTEN)
- return -EINVAL;
-
- hc = ccid3_hc_rx_sk(sk);
switch (optname) {
case DCCP_SOCKOPT_CCID_RX_INFO:
if (len < sizeof(rx_info))
^ permalink raw reply
* [PATCH 1/5] ccid: ccid-2/3 code cosmetics
From: Gerrit Renker @ 2010-08-23 5:41 UTC (permalink / raw)
To: davem; +Cc: dccp, netdev, Gerrit Renker
In-Reply-To: <1282542100-5799-1-git-send-email-gerrit@erg.abdn.ac.uk>
This patch collects cosmetics-only changes to separate these from
code changes:
* update with regard to CodingStyle and whitespace changes,
* documentation:
- adding/revising comments,
- remove CCID-3 RX socket documentation which is either
duplicate or refers to fields that no longer exist,
* expand embedded tfrc_tx_info struct inline for consistency,
removing indirections via #define.
Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
---
net/dccp/ccids/ccid2.c | 4 ++--
net/dccp/ccids/ccid3.h | 19 +++++++------------
net/dccp/ccids/ccid3.c | 30 ++++++++++++++++++------------
3 files changed, 27 insertions(+), 26 deletions(-)
--- a/net/dccp/ccids/ccid2.c
+++ b/net/dccp/ccids/ccid2.c
@@ -193,8 +193,8 @@ static void ccid2_hc_tx_rto_expire(unsigned long data)
hc->tx_ssthresh = hc->tx_cwnd / 2;
if (hc->tx_ssthresh < 2)
hc->tx_ssthresh = 2;
- hc->tx_cwnd = 1;
- hc->tx_pipe = 0;
+ hc->tx_cwnd = 1;
+ hc->tx_pipe = 0;
/* clear state about stuff we sent */
hc->tx_seqt = hc->tx_seqh;
--- a/net/dccp/ccids/ccid3.h
+++ b/net/dccp/ccids/ccid3.h
@@ -95,14 +95,13 @@ enum ccid3_hc_tx_states {
* @tx_options_received: Parsed set of retrieved options
*/
struct ccid3_hc_tx_sock {
- struct tfrc_tx_info tx_tfrc;
-#define tx_x tx_tfrc.tfrctx_x
-#define tx_x_recv tx_tfrc.tfrctx_x_recv
-#define tx_x_calc tx_tfrc.tfrctx_x_calc
-#define tx_rtt tx_tfrc.tfrctx_rtt
-#define tx_p tx_tfrc.tfrctx_p
-#define tx_t_rto tx_tfrc.tfrctx_rto
-#define tx_t_ipi tx_tfrc.tfrctx_ipi
+ u64 tx_x;
+ u64 tx_x_recv;
+ u32 tx_x_calc;
+ u32 tx_rtt;
+ u32 tx_p;
+ u32 tx_t_rto;
+ u32 tx_t_ipi;
u16 tx_s;
enum ccid3_hc_tx_states tx_state:8;
u8 tx_last_win_count;
@@ -131,16 +130,12 @@ enum ccid3_hc_rx_states {
/**
* struct ccid3_hc_rx_sock - CCID3 receiver half-connection socket
- * @rx_x_recv: Receiver estimate of send rate (RFC 3448 4.3)
- * @rx_rtt: Receiver estimate of rtt (non-standard)
- * @rx_p: Current loss event rate (RFC 3448 5.4)
* @rx_last_counter: Tracks window counter (RFC 4342, 8.1)
* @rx_state: Receiver state, one of %ccid3_hc_rx_states
* @rx_bytes_recv: Total sum of DCCP payload bytes
* @rx_x_recv: Receiver estimate of send rate (RFC 3448, sec. 4.3)
* @rx_rtt: Receiver estimate of RTT
* @rx_tstamp_last_feedback: Time at which last feedback was sent
- * @rx_tstamp_last_ack: Time at which last feedback was sent
* @rx_hist: Packet history (loss detection + RTT sampling)
* @rx_li_hist: Loss Interval database
* @rx_s: Received packet size in bytes
--- a/net/dccp/ccids/ccid3.c
+++ b/net/dccp/ccids/ccid3.c
@@ -218,9 +218,9 @@ static void ccid3_hc_tx_no_feedback_timer(unsigned long data)
/*
* Determine new allowed sending rate X as per draft rfc3448bis-00, 4.4
+ * RTO is 0 if and only if no feedback has been received yet.
*/
- if (hc->tx_t_rto == 0 || /* no feedback received yet */
- hc->tx_p == 0) {
+ if (hc->tx_t_rto == 0 || hc->tx_p == 0) {
/* halve send rate directly */
hc->tx_x = max(hc->tx_x / 2,
@@ -256,7 +256,7 @@ static void ccid3_hc_tx_no_feedback_timer(unsigned long data)
* Set new timeout for the nofeedback timer.
* See comments in packet_recv() regarding the value of t_RTO.
*/
- if (unlikely(hc->tx_t_rto == 0)) /* no feedback yet */
+ if (unlikely(hc->tx_t_rto == 0)) /* no feedback received yet */
t_nfb = TFRC_INITIAL_TIMEOUT;
else
t_nfb = max(hc->tx_t_rto, 2 * hc->tx_t_ipi);
@@ -372,7 +372,7 @@ static void ccid3_hc_tx_packet_sent(struct sock *sk, int more,
static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
{
struct ccid3_hc_tx_sock *hc = ccid3_hc_tx_sk(sk);
- struct ccid3_options_received *opt_recv;
+ struct ccid3_options_received *opt_recv = &hc->tx_options_received;
ktime_t now;
unsigned long t_nfb;
u32 pinv, r_sample;
@@ -386,7 +386,6 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
hc->tx_state != TFRC_SSTATE_NO_FBACK)
return;
- opt_recv = &hc->tx_options_received;
now = ktime_get_real();
/* Estimate RTT from history if ACK number is valid */
@@ -489,11 +488,9 @@ static int ccid3_hc_tx_parse_options(struct sock *sk, unsigned char option,
int rc = 0;
const struct dccp_sock *dp = dccp_sk(sk);
struct ccid3_hc_tx_sock *hc = ccid3_hc_tx_sk(sk);
- struct ccid3_options_received *opt_recv;
+ struct ccid3_options_received *opt_recv = &hc->tx_options_received;
__be32 opt_val;
- opt_recv = &hc->tx_options_received;
-
if (opt_recv->ccid3or_seqno != dp->dccps_gsr) {
opt_recv->ccid3or_seqno = dp->dccps_gsr;
opt_recv->ccid3or_loss_event_rate = ~0;
@@ -582,6 +579,7 @@ static int ccid3_hc_tx_getsockopt(struct sock *sk, const int optname, int len,
u32 __user *optval, int __user *optlen)
{
const struct ccid3_hc_tx_sock *hc;
+ struct tfrc_tx_info tfrc;
const void *val;
/* Listen socks doesn't have a private CCID block */
@@ -591,10 +589,17 @@ static int ccid3_hc_tx_getsockopt(struct sock *sk, const int optname, int len,
hc = ccid3_hc_tx_sk(sk);
switch (optname) {
case DCCP_SOCKOPT_CCID_TX_INFO:
- if (len < sizeof(hc->tx_tfrc))
+ if (len < sizeof(tfrc))
return -EINVAL;
- len = sizeof(hc->tx_tfrc);
- val = &hc->tx_tfrc;
+ tfrc.tfrctx_x = hc->tx_x;
+ tfrc.tfrctx_x_recv = hc->tx_x_recv;
+ tfrc.tfrctx_x_calc = hc->tx_x_calc;
+ tfrc.tfrctx_rtt = hc->tx_rtt;
+ tfrc.tfrctx_p = hc->tx_p;
+ tfrc.tfrctx_rto = hc->tx_t_rto;
+ tfrc.tfrctx_ipi = hc->tx_t_ipi;
+ len = sizeof(tfrc);
+ val = &tfrc;
break;
default:
return -ENOPROTOOPT;
@@ -749,10 +754,11 @@ static u32 ccid3_first_li(struct sock *sk)
x_recv = scaled_div32(hc->rx_bytes_recv, delta);
if (x_recv == 0) { /* would also trigger divide-by-zero */
DCCP_WARN("X_recv==0\n");
- if ((x_recv = hc->rx_x_recv) == 0) {
+ if (hc->rx_x_recv == 0) {
DCCP_BUG("stored value of X_recv is zero");
return ~0U;
}
+ x_recv = hc->rx_x_recv;
}
fval = scaled_div(hc->rx_s, hc->rx_rtt);
^ permalink raw reply
* [PATCH 3/5] dccp ccid-2: Remove redundant sanity tests
From: Gerrit Renker @ 2010-08-23 5:41 UTC (permalink / raw)
To: davem; +Cc: dccp, netdev, Gerrit Renker
In-Reply-To: <1282542100-5799-3-git-send-email-gerrit@erg.abdn.ac.uk>
This removes the ccid2_hc_tx_check_sanity function: it is redundant.
Details:
========
The tx_check_sanity function performs three tests:
1) it checks that the circular TX list is sorted
- in ascending order of sequence number (ccid2s_seq)
- and time (ccid2s_sent),
- in the direction from `tail' (hctx_seqt) to `head' (hctx_seqh);
2) it ensures that the entire list has the length seqbufc * CCID2_SEQBUF_LEN;
3) it ensures that pipe equals the number of packets that were not
marked `acked' (ccid2s_acked) between `tail' and `head'.
The following argues that each of these tests is redundant, this can be verified
by going through the code.
(1) is not necessary, since both time and GSS increase from one packet to the
next, so that subsequent insertions in tx_packet_sent (which advance the `head'
pointer) will be in ascending order of time and sequence number.
In (2), the length of the list is always equal to seqbufc times CCID2_SEQBUF_LEN
(set to 1024) unless allocation caused an earlier failure, because:
* at initialisation (tx_init), there is one chunk of size 1024 and seqbufc=1;
* subsequent calls to tx_alloc_seq take place whenever head->next == tail in
tx_packet_sent; then a new chunk of size 1024 is inserted between head and
tail, and seqbufc is incremented by one.
To show that (3) is redundant requires looking at two cases.
The `pipe' variable of the TX socket is incremented only in tx_packet_sent, and
decremented in tx_packet_recv. When head == tail (TX history empty) then pipe
should be 0, which is the case directly after initialisation and after a
retransmission timeout has occurred (ccid2_hc_tx_rto_expire).
The first case involves parsing Ack Vectors for packets recorded in the live
portion of the buffer, between tail and head. For each packet marked by the
receiver as received (state 0) or ECN-marked (state 1), pipe is decremented by
one, so for all such packets the BUG_ON in tx_check_sanity will not trigger.
The second case is the loss detection in the second half of tx_packet_recv,
below the comment "Check for NUMDUPACK".
The first while-loop here ensures that the sequence number of `seqp' is either
above or equal to `high_ack', or otherwise equal to the highest sequence number
sent so far (of the entry head->prev, as head points to the next unsent entry).
The next while-loop ("while (1)") counts the number of acked packets starting
from that position of seqp, going backwards in the direction from head->prev to
tail. If NUMDUPACK=3 such packets were counted within this loop, `seqp' points
to the last acknowledged packet of these, and the "if (done == NUMDUPACK)" block
is entered next.
The while-loop contained within that block in turn traverses the list backwards,
from head to tail; the position of `seqp' is saved in the variable `last_acked'.
For each packet not marked as `acked', a congestion event is triggered within
the loop, and pipe is decremented. The loop terminates when `seqp' has reached
`tail', whereupon tail is set to the position previously stored in `last_acked'.
Thus, between `last_acked' and the previous position of `tail',
- pipe has been decremented earlier if the packet was marked as state 0 or 1;
- pipe was decremented if the packet was not marked as acked.
That is, pipe has been decremented by the number of packets between `last_acked'
and the previous position of `tail'. As a consequence, pipe now again reflects
the number of packets which have not (yet) been acked between the new position
of tail (at `last_acked') and head->prev, or 0 if head==tail. The result is that
the BUG_ON condition in check_sanity will also not be triggered, hence the test
(3) is also redundant.
Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
---
net/dccp/ccids/ccid2.c | 52 ------------------------------------------------
1 files changed, 0 insertions(+), 52 deletions(-)
--- a/net/dccp/ccids/ccid2.c
+++ b/net/dccp/ccids/ccid2.c
@@ -33,51 +33,8 @@
#ifdef CONFIG_IP_DCCP_CCID2_DEBUG
static int ccid2_debug;
#define ccid2_pr_debug(format, a...) DCCP_PR_DEBUG(ccid2_debug, format, ##a)
-
-static void ccid2_hc_tx_check_sanity(const struct ccid2_hc_tx_sock *hc)
-{
- int len = 0;
- int pipe = 0;
- struct ccid2_seq *seqp = hc->tx_seqh;
-
- /* there is data in the chain */
- if (seqp != hc->tx_seqt) {
- seqp = seqp->ccid2s_prev;
- len++;
- if (!seqp->ccid2s_acked)
- pipe++;
-
- while (seqp != hc->tx_seqt) {
- struct ccid2_seq *prev = seqp->ccid2s_prev;
-
- len++;
- if (!prev->ccid2s_acked)
- pipe++;
-
- /* packets are sent sequentially */
- BUG_ON(dccp_delta_seqno(seqp->ccid2s_seq,
- prev->ccid2s_seq ) >= 0);
- BUG_ON(time_before(seqp->ccid2s_sent,
- prev->ccid2s_sent));
-
- seqp = prev;
- }
- }
-
- BUG_ON(pipe != hc->tx_pipe);
- ccid2_pr_debug("len of chain=%d\n", len);
-
- do {
- seqp = seqp->ccid2s_prev;
- len++;
- } while (seqp != hc->tx_seqh);
-
- ccid2_pr_debug("total len=%d\n", len);
- BUG_ON(len != hc->tx_seqbufc * CCID2_SEQBUF_LEN);
-}
#else
#define ccid2_pr_debug(format, a...)
-#define ccid2_hc_tx_check_sanity(hc)
#endif
static int ccid2_hc_tx_alloc_seq(struct ccid2_hc_tx_sock *hc)
@@ -178,8 +135,6 @@ static void ccid2_hc_tx_rto_expire(unsigned long data)
ccid2_pr_debug("RTO_EXPIRE\n");
- ccid2_hc_tx_check_sanity(hc);
-
/* back-off timer */
hc->tx_rto <<= 1;
@@ -204,7 +159,6 @@ static void ccid2_hc_tx_rto_expire(unsigned long data)
hc->tx_rpseq = 0;
hc->tx_rpdupack = -1;
ccid2_change_l_ack_ratio(sk, 1);
- ccid2_hc_tx_check_sanity(hc);
out:
bh_unlock_sock(sk);
sock_put(sk);
@@ -312,7 +266,6 @@ static void ccid2_hc_tx_packet_sent(struct sock *sk, int more, unsigned int len)
}
} while (0);
ccid2_pr_debug("=========\n");
- ccid2_hc_tx_check_sanity(hc);
#endif
}
@@ -510,7 +463,6 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
int done = 0;
unsigned int maxincr = 0;
- ccid2_hc_tx_check_sanity(hc);
/* check reverse path congestion */
seqno = DCCP_SKB_CB(skb)->dccpd_seq;
@@ -694,8 +646,6 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
hc->tx_seqt = hc->tx_seqt->ccid2s_next;
}
-
- ccid2_hc_tx_check_sanity(hc);
}
static int ccid2_hc_tx_init(struct ccid *ccid, struct sock *sk)
@@ -730,8 +680,6 @@ static int ccid2_hc_tx_init(struct ccid *ccid, struct sock *sk)
hc->tx_last_cong = jiffies;
setup_timer(&hc->tx_rtotimer, ccid2_hc_tx_rto_expire,
(unsigned long)sk);
-
- ccid2_hc_tx_check_sanity(hc);
return 0;
}
^ permalink raw reply
* [PATCH 5/5] dccp ccid-2: Replace broken RTT estimator with better algorithm
From: Gerrit Renker @ 2010-08-23 5:41 UTC (permalink / raw)
To: davem; +Cc: dccp, netdev, Gerrit Renker
In-Reply-To: <1282542100-5799-5-git-send-email-gerrit@erg.abdn.ac.uk>
The current CCID-2 RTT estimator code is in parts broken and lags behind the
suggestions in RFC2988 of using scaled variants for SRTT/RTTVAR.
That code is replaced by the present patch, which reuses the Linux TCP RTT
estimator code.
Further details:
----------------
1. The minimum RTO of previously one second has been replaced with TCP's, since
RFC4341, sec. 5 says that the minimum of 1 sec. (suggested in RFC2988, 2.4)
is not necessary. Instead, the TCP_RTO_MIN is used, which agrees with DCCP's
concept of a default RTT (RFC 4340, 3.4).
2. The maximum RTO has been set to DCCP_RTO_MAX (64 sec), which agrees with
RFC2988, (2.5).
3. De-inlined the function ccid2_new_ack().
4. Added a FIXME: the RTT is sampled several times per Ack Vector, which will
give the wrong estimate. It should be replaced with one sample per Ack.
However, at the moment this can not be resolved easily, since
- it depends on TX history code (which also needs some work),
- the cleanest solution is not to use the `sent' time at all (saves 4 bytes
per entry) and use DCCP timestamps / elapsed time to estimated the RTT,
which however is non-trivial to get right (but needs to be done).
Reasons for reusing the Linux TCP estimator algorithm:
------------------------------------------------------
Some time was spent to find a better alternative, using basic RFC2988 as a first
step. Further analysis and experimentation showed that the Linux TCP RTO
estimator is superior to a basic RFC2988 implementation. A summary is on
http://www.erg.abdn.ac.uk/users/gerrit/dccp/notes/ccid2/rto_estimator/
In addition, this estimator fared well in a recent empirical evaluation:
Rewaskar, Sushant, Jasleen Kaur and F. Donelson Smith.
A Performance Study of Loss Detection/Recovery in Real-world TCP
Implementations. Proceedings of 15th IEEE International
Conference on Network Protocols (ICNP-07), 2007.
Thus there is significant benefit in reusing the existing TCP code.
Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
---
net/dccp/ccids/ccid2.h | 20 ++++--
net/dccp/ccids/ccid2.c | 169 ++++++++++++++++++++++++++---------------------
2 files changed, 108 insertions(+), 81 deletions(-)
--- a/net/dccp/ccids/ccid2.h
+++ b/net/dccp/ccids/ccid2.h
@@ -42,7 +42,12 @@ struct ccid2_seq {
* struct ccid2_hc_tx_sock - CCID2 TX half connection
* @tx_{cwnd,ssthresh,pipe}: as per RFC 4341, section 5
* @tx_packets_acked: Ack counter for deriving cwnd growth (RFC 3465)
- * @tx_lastrtt: time RTT was last measured
+ * @tx_srtt: smoothed RTT estimate, scaled by 2^3
+ * @tx_mdev: smoothed RTT variation, scaled by 2^2
+ * @tx_mdev_max: maximum of @mdev during one flight
+ * @tx_rttvar: moving average/maximum of @mdev_max
+ * @tx_rto: RTO value deriving from SRTT and RTTVAR (RFC 2988)
+ * @tx_rtt_seq: to decay RTTVAR at most once per flight
* @tx_rpseq: last consecutive seqno
* @tx_rpdupack: dupacks since rpseq
*/
@@ -55,11 +60,16 @@ struct ccid2_hc_tx_sock {
int tx_seqbufc;
struct ccid2_seq *tx_seqh;
struct ccid2_seq *tx_seqt;
- long tx_rto;
- long tx_srtt;
- long tx_rttvar;
- unsigned long tx_lastrtt;
+
+ /* RTT measurement: variables/principles are the same as in TCP */
+ u32 tx_srtt,
+ tx_mdev,
+ tx_mdev_max,
+ tx_rttvar,
+ tx_rto;
+ u64 tx_rtt_seq:48;
struct timer_list tx_rtotimer;
+
u64 tx_rpseq;
int tx_rpdupack;
unsigned long tx_last_cong;
--- a/net/dccp/ccids/ccid2.c
+++ b/net/dccp/ccids/ccid2.c
@@ -113,19 +113,12 @@ static void ccid2_change_l_ack_ratio(struct sock *sk, u32 val)
dp->dccps_l_ack_ratio = val;
}
-static void ccid2_change_srtt(struct ccid2_hc_tx_sock *hc, long val)
-{
- ccid2_pr_debug("change SRTT to %ld\n", val);
- hc->tx_srtt = val;
-}
-
static void ccid2_start_rto_timer(struct sock *sk);
static void ccid2_hc_tx_rto_expire(unsigned long data)
{
struct sock *sk = (struct sock *)data;
struct ccid2_hc_tx_sock *hc = ccid2_hc_tx_sk(sk);
- long s;
bh_lock_sock(sk);
if (sock_owned_by_user(sk)) {
@@ -137,10 +130,8 @@ static void ccid2_hc_tx_rto_expire(unsigned long data)
/* back-off timer */
hc->tx_rto <<= 1;
-
- s = hc->tx_rto / HZ;
- if (s > 60)
- hc->tx_rto = 60 * HZ;
+ if (hc->tx_rto > DCCP_RTO_MAX)
+ hc->tx_rto = DCCP_RTO_MAX;
ccid2_start_rto_timer(sk);
@@ -168,7 +159,7 @@ static void ccid2_start_rto_timer(struct sock *sk)
{
struct ccid2_hc_tx_sock *hc = ccid2_hc_tx_sk(sk);
- ccid2_pr_debug("setting RTO timeout=%ld\n", hc->tx_rto);
+ ccid2_pr_debug("setting RTO timeout=%u\n", hc->tx_rto);
BUG_ON(timer_pending(&hc->tx_rtotimer));
sk_reset_timer(sk, &hc->tx_rtotimer, jiffies + hc->tx_rto);
@@ -339,9 +330,86 @@ static void ccid2_hc_tx_kill_rto_timer(struct sock *sk)
ccid2_pr_debug("deleted RTO timer\n");
}
-static inline void ccid2_new_ack(struct sock *sk,
- struct ccid2_seq *seqp,
- unsigned int *maxincr)
+/**
+ * ccid2_rtt_estimator - Sample RTT and compute RTO using RFC2988 algorithm
+ * This code is almost identical with TCP's tcp_rtt_estimator(), since
+ * - it has a higher sampling frequency (recommended by RFC 1323),
+ * - the RTO does not collapse into RTT due to RTTVAR going towards zero,
+ * - it is simple (cf. more complex proposals such as Eifel timer or research
+ * which suggests that the gain should be set according to window size),
+ * - in tests it was found to work well with CCID2 [gerrit].
+ */
+static void ccid2_rtt_estimator(struct sock *sk, const long mrtt)
+{
+ struct ccid2_hc_tx_sock *hc = ccid2_hc_tx_sk(sk);
+ long m = mrtt ? : 1;
+
+ if (hc->tx_srtt == 0) {
+ /* First measurement m */
+ hc->tx_srtt = m << 3;
+ hc->tx_mdev = m << 1;
+
+ hc->tx_mdev_max = max(TCP_RTO_MIN, hc->tx_mdev);
+ hc->tx_rttvar = hc->tx_mdev_max;
+ hc->tx_rtt_seq = dccp_sk(sk)->dccps_gss;
+ } else {
+ /* Update scaled SRTT as SRTT += 1/8 * (m - SRTT) */
+ m -= (hc->tx_srtt >> 3);
+ hc->tx_srtt += m;
+
+ /* Similarly, update scaled mdev with regard to |m| */
+ if (m < 0) {
+ m = -m;
+ m -= (hc->tx_mdev >> 2);
+ /*
+ * This neutralises RTO increase when RTT < SRTT - mdev
+ * (see P. Sarolahti, A. Kuznetsov,"Congestion Control
+ * in Linux TCP", USENIX 2002, pp. 49-62).
+ */
+ if (m > 0)
+ m >>= 3;
+ } else {
+ m -= (hc->tx_mdev >> 2);
+ }
+ hc->tx_mdev += m;
+
+ if (hc->tx_mdev > hc->tx_mdev_max) {
+ hc->tx_mdev_max = hc->tx_mdev;
+ if (hc->tx_mdev_max > hc->tx_rttvar)
+ hc->tx_rttvar = hc->tx_mdev_max;
+ }
+
+ /*
+ * Decay RTTVAR at most once per flight, exploiting that
+ * 1) pipe <= cwnd <= Sequence_Window = W (RFC 4340, 7.5.2)
+ * 2) AWL = GSS-W+1 <= GAR <= GSS (RFC 4340, 7.5.1)
+ * GAR is a useful bound for FlightSize = pipe.
+ * AWL is probably too low here, as it over-estimates pipe.
+ */
+ if (after48(dccp_sk(sk)->dccps_gar, hc->tx_rtt_seq)) {
+ if (hc->tx_mdev_max < hc->tx_rttvar)
+ hc->tx_rttvar -= (hc->tx_rttvar -
+ hc->tx_mdev_max) >> 2;
+ hc->tx_rtt_seq = dccp_sk(sk)->dccps_gss;
+ hc->tx_mdev_max = TCP_RTO_MIN;
+ }
+ }
+
+ /*
+ * Set RTO from SRTT and RTTVAR
+ * As in TCP, 4 * RTTVAR >= TCP_RTO_MIN, giving a minimum RTO of 200 ms.
+ * This agrees with RFC 4341, 5:
+ * "Because DCCP does not retransmit data, DCCP does not require
+ * TCP's recommended minimum timeout of one second".
+ */
+ hc->tx_rto = (hc->tx_srtt >> 3) + hc->tx_rttvar;
+
+ if (hc->tx_rto > DCCP_RTO_MAX)
+ hc->tx_rto = DCCP_RTO_MAX;
+}
+
+static void ccid2_new_ack(struct sock *sk, struct ccid2_seq *seqp,
+ unsigned int *maxincr)
{
struct ccid2_hc_tx_sock *hc = ccid2_hc_tx_sk(sk);
@@ -355,64 +423,15 @@ static inline void ccid2_new_ack(struct sock *sk,
hc->tx_cwnd += 1;
hc->tx_packets_acked = 0;
}
-
- /* update RTO */
- if (hc->tx_srtt == -1 ||
- time_after(jiffies, hc->tx_lastrtt + hc->tx_srtt)) {
- unsigned long r = (long)jiffies - (long)seqp->ccid2s_sent;
- int s;
-
- /* first measurement */
- if (hc->tx_srtt == -1) {
- ccid2_pr_debug("R: %lu Time=%lu seq=%llu\n",
- r, jiffies,
- (unsigned long long)seqp->ccid2s_seq);
- ccid2_change_srtt(hc, r);
- hc->tx_rttvar = r >> 1;
- } else {
- /* RTTVAR */
- long tmp = hc->tx_srtt - r;
- long srtt;
-
- if (tmp < 0)
- tmp *= -1;
-
- tmp >>= 2;
- hc->tx_rttvar *= 3;
- hc->tx_rttvar >>= 2;
- hc->tx_rttvar += tmp;
-
- /* SRTT */
- srtt = hc->tx_srtt;
- srtt *= 7;
- srtt >>= 3;
- tmp = r >> 3;
- srtt += tmp;
- ccid2_change_srtt(hc, srtt);
- }
- s = hc->tx_rttvar << 2;
- /* clock granularity is 1 when based on jiffies */
- if (!s)
- s = 1;
- hc->tx_rto = hc->tx_srtt + s;
-
- /* must be at least a second */
- s = hc->tx_rto / HZ;
- /* DCCP doesn't require this [but I like it cuz my code sux] */
-#if 1
- if (s < 1)
- hc->tx_rto = HZ;
-#endif
- /* max 60 seconds */
- if (s > 60)
- hc->tx_rto = HZ * 60;
-
- hc->tx_lastrtt = jiffies;
-
- ccid2_pr_debug("srtt: %ld rttvar: %ld rto: %ld (HZ=%d) R=%lu\n",
- hc->tx_srtt, hc->tx_rttvar,
- hc->tx_rto, HZ, r);
- }
+ /*
+ * FIXME: RTT is sampled several times per acknowledgment (for each
+ * entry in the Ack Vector), instead of once per Ack (as in TCP SACK).
+ * This causes the RTT to be over-estimated, since the older entries
+ * in the Ack Vector have earlier sending times.
+ * The cleanest solution is to not use the ccid2s_sent field at all
+ * and instead use DCCP timestamps: requires changes in other places.
+ */
+ ccid2_rtt_estimator(sk, jiffies - seqp->ccid2s_sent);
}
static void ccid2_congestion_event(struct sock *sk, struct ccid2_seq *seqp)
@@ -662,9 +681,7 @@ static int ccid2_hc_tx_init(struct ccid *ccid, struct sock *sk)
if (ccid2_hc_tx_alloc_seq(hc))
return -ENOMEM;
- hc->tx_rto = 3 * HZ;
- ccid2_change_srtt(hc, -1);
- hc->tx_rttvar = -1;
+ hc->tx_rto = DCCP_TIMEOUT_INIT;
hc->tx_rpdupack = -1;
hc->tx_last_cong = jiffies;
setup_timer(&hc->tx_rtotimer, ccid2_hc_tx_rto_expire,
^ permalink raw reply
* RE: Dead Config Option STMMAC_ETH?
From: Peppe CAVALLARO @ 2010-08-23 7:13 UTC (permalink / raw)
To: Christian Dietrich, David S. Miller, netdev@vger.kernel.org,
"linux-kernel@vger.kernel.or
Cc: vamos-dev@i4.informatik.uni-erlangen.de
In-Reply-To: <86r5i6vegw.fsf@peer.zerties.org>
Hi Christian,
> -----Original Message-----
> From: Christian Dietrich [mailto:qy03fugy@stud.informatik.uni-erlangen.de]
> Sent: Tuesday, August 10, 2010 2:29 PM
> To: David S. Miller; Peppe CAVALLARO; netdev@vger.kernel.org; linux-
> kernel@vger.kernel.org
> Cc: vamos-dev@i4.informatik.uni-erlangen.de
> Subject: Dead Config Option STMMAC_ETH?
>
> Hi all!
>
> As part of the VAMOS[0] research project at the University of
> Erlangen we are looking at multiple integrity errors in linux'
> configuration system.
>
> I've been running a check on the drivers/net/stmmac sourcetree for
> config Items not defined in Kconfig and found such a case. Sourcecode
> blocks depending on these Items are not reachable from a vanilla
> kernel -- dead code. I've seen such dead blocks made on purpose
> e.g. while integrating new features into the kernel but generally
> they're just useless.
>
> As far as i can see in drivers/net/stmmac/Kconfig STMMAC_ETH and several
> depending flags are dead in the linux vanilla kernel, because it depends
> on CPU_SUBTYPE_ST40, but there isn't a Kconfig option for that. But
> f96691872439ab2071171d4531c4a95b5d493ae5 suggests, that support for this
> ST40 plattform was removed in 2007.
>
> There seems to be, that there was much effort on the stmmac drivers in
> the last few months, so i just wanted to ask if this problem is known.
There is effort on this driver: currently the driver fully works on STM platforms and starts working on ARM (SPEAr Kernels).
The driver Kconfig actually depends on the CPU_SUBTYPE_ST40 but it built on x86 if remove this dependency (just verified).
In the past, I added this dependency because the driver was initially tested on ST kernels (where we continue to have the CPU_SUBTYPE_ST40) but I can review it if you like.
Regards,
Peppe
> Regards
>
> Christian Dietrich
>
> [0] http://vamos1.informatik.uni-erlangen.de
> --
> (λ x . x x) (λ x . x x) -- See how beatiful the lambda is
> No documentation is better than bad documentation
> -- Das Ausdrucken dieser Mail wird urheberrechtlich verfolgt.
^ permalink raw reply
* [PATCH] net: Rename skb_has_frags to skb_has_frag_list
From: David Miller @ 2010-08-23 7:14 UTC (permalink / raw)
To: netdev
SKBs can be "fragmented" in two ways, via a page array (called
skb_shinfo(skb)->frags[]) and via a list of SKBs (called
skb_shinfo(skb)->frag_list).
Since skb_has_frags() tests the latter, it's name is confusing
since it sounds more like it's testing the former.
Signed-off-by: David S. Miller <davem@davemloft.net>
---
I was reading over the GRO code and found this helper function's
name confusing as hell. Committed to net-next-2.6
include/linux/netdevice.h | 2 +-
include/linux/skbuff.h | 4 ++--
net/core/dev.c | 4 ++--
net/core/skbuff.c | 18 +++++++++---------
net/ipv4/ip_fragment.c | 2 +-
net/ipv4/ip_output.c | 2 +-
net/ipv6/ip6_output.c | 2 +-
net/ipv6/netfilter/nf_conntrack_reasm.c | 2 +-
net/ipv6/reassembly.c | 2 +-
9 files changed, 19 insertions(+), 19 deletions(-)
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 46c36ff..ce2de8b 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -2191,7 +2191,7 @@ static inline int net_gso_ok(int features, int gso_type)
static inline int skb_gso_ok(struct sk_buff *skb, int features)
{
return net_gso_ok(features, skb_shinfo(skb)->gso_type) &&
- (!skb_has_frags(skb) || (features & NETIF_F_FRAGLIST));
+ (!skb_has_frag_list(skb) || (features & NETIF_F_FRAGLIST));
}
static inline int netif_needs_gso(struct net_device *dev, struct sk_buff *skb)
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index f067c95..f900ffc 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -1120,7 +1120,7 @@ extern void skb_add_rx_frag(struct sk_buff *skb, int i, struct page *page,
int off, int size);
#define SKB_PAGE_ASSERT(skb) BUG_ON(skb_shinfo(skb)->nr_frags)
-#define SKB_FRAG_ASSERT(skb) BUG_ON(skb_has_frags(skb))
+#define SKB_FRAG_ASSERT(skb) BUG_ON(skb_has_frag_list(skb))
#define SKB_LINEAR_ASSERT(skb) BUG_ON(skb_is_nonlinear(skb))
#ifdef NET_SKBUFF_DATA_USES_OFFSET
@@ -1784,7 +1784,7 @@ static inline int pskb_trim_rcsum(struct sk_buff *skb, unsigned int len)
skb = skb->prev)
-static inline bool skb_has_frags(const struct sk_buff *skb)
+static inline bool skb_has_frag_list(const struct sk_buff *skb)
{
return skb_shinfo(skb)->frag_list != NULL;
}
diff --git a/net/core/dev.c b/net/core/dev.c
index d569f88..859e30f 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -1930,7 +1930,7 @@ static inline int skb_needs_linearize(struct sk_buff *skb,
struct net_device *dev)
{
return skb_is_nonlinear(skb) &&
- ((skb_has_frags(skb) && !(dev->features & NETIF_F_FRAGLIST)) ||
+ ((skb_has_frag_list(skb) && !(dev->features & NETIF_F_FRAGLIST)) ||
(skb_shinfo(skb)->nr_frags && (!(dev->features & NETIF_F_SG) ||
illegal_highdma(dev, skb))));
}
@@ -3090,7 +3090,7 @@ enum gro_result dev_gro_receive(struct napi_struct *napi, struct sk_buff *skb)
if (!(skb->dev->features & NETIF_F_GRO) || netpoll_rx_on(skb))
goto normal;
- if (skb_is_gso(skb) || skb_has_frags(skb))
+ if (skb_is_gso(skb) || skb_has_frag_list(skb))
goto normal;
rcu_read_lock();
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 99ef721..e2535fb 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -340,7 +340,7 @@ static void skb_release_data(struct sk_buff *skb)
put_page(skb_shinfo(skb)->frags[i].page);
}
- if (skb_has_frags(skb))
+ if (skb_has_frag_list(skb))
skb_drop_fraglist(skb);
kfree(skb->head);
@@ -759,7 +759,7 @@ struct sk_buff *pskb_copy(struct sk_buff *skb, gfp_t gfp_mask)
skb_shinfo(n)->nr_frags = i;
}
- if (skb_has_frags(skb)) {
+ if (skb_has_frag_list(skb)) {
skb_shinfo(n)->frag_list = skb_shinfo(skb)->frag_list;
skb_clone_fraglist(n);
}
@@ -822,7 +822,7 @@ int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail,
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++)
get_page(skb_shinfo(skb)->frags[i].page);
- if (skb_has_frags(skb))
+ if (skb_has_frag_list(skb))
skb_clone_fraglist(skb);
skb_release_data(skb);
@@ -1099,7 +1099,7 @@ drop_pages:
for (; i < nfrags; i++)
put_page(skb_shinfo(skb)->frags[i].page);
- if (skb_has_frags(skb))
+ if (skb_has_frag_list(skb))
skb_drop_fraglist(skb);
goto done;
}
@@ -1194,7 +1194,7 @@ unsigned char *__pskb_pull_tail(struct sk_buff *skb, int delta)
/* Optimization: no fragments, no reasons to preestimate
* size of pulled pages. Superb.
*/
- if (!skb_has_frags(skb))
+ if (!skb_has_frag_list(skb))
goto pull_pages;
/* Estimate size of pulled pages. */
@@ -2323,7 +2323,7 @@ next_skb:
st->frag_data = NULL;
}
- if (st->root_skb == st->cur_skb && skb_has_frags(st->root_skb)) {
+ if (st->root_skb == st->cur_skb && skb_has_frag_list(st->root_skb)) {
st->cur_skb = skb_shinfo(st->root_skb)->frag_list;
st->frag_idx = 0;
goto next_skb;
@@ -2889,7 +2889,7 @@ int skb_cow_data(struct sk_buff *skb, int tailbits, struct sk_buff **trailer)
return -ENOMEM;
/* Easy case. Most of packets will go this way. */
- if (!skb_has_frags(skb)) {
+ if (!skb_has_frag_list(skb)) {
/* A little of trouble, not enough of space for trailer.
* This should not happen, when stack is tuned to generate
* good frames. OK, on miss we reallocate and reserve even more
@@ -2924,7 +2924,7 @@ int skb_cow_data(struct sk_buff *skb, int tailbits, struct sk_buff **trailer)
if (skb1->next == NULL && tailbits) {
if (skb_shinfo(skb1)->nr_frags ||
- skb_has_frags(skb1) ||
+ skb_has_frag_list(skb1) ||
skb_tailroom(skb1) < tailbits)
ntail = tailbits + 128;
}
@@ -2933,7 +2933,7 @@ int skb_cow_data(struct sk_buff *skb, int tailbits, struct sk_buff **trailer)
skb_cloned(skb1) ||
ntail ||
skb_shinfo(skb1)->nr_frags ||
- skb_has_frags(skb1)) {
+ skb_has_frag_list(skb1)) {
struct sk_buff *skb2;
/* Fuck, we are miserable poor guys... */
diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c
index b7c4165..f4dc879 100644
--- a/net/ipv4/ip_fragment.c
+++ b/net/ipv4/ip_fragment.c
@@ -542,7 +542,7 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev,
/* If the first fragment is fragmented itself, we split
* it to two chunks: the first with data and paged part
* and the second, holding only fragments. */
- if (skb_has_frags(head)) {
+ if (skb_has_frag_list(head)) {
struct sk_buff *clone;
int i, plen = 0;
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index e807492..6d2753c 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -487,7 +487,7 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
* LATER: this step can be merged to real generation of fragments,
* we can switch to copy when see the first bad fragment.
*/
- if (skb_has_frags(skb)) {
+ if (skb_has_frag_list(skb)) {
struct sk_buff *frag;
int first_len = skb_pagelen(skb);
int truesizes = 0;
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index d40b330..1838927 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -637,7 +637,7 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
}
mtu -= hlen + sizeof(struct frag_hdr);
- if (skb_has_frags(skb)) {
+ if (skb_has_frag_list(skb)) {
int first_len = skb_pagelen(skb);
int truesizes = 0;
diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c
index 13ef5bc..089c598 100644
--- a/net/ipv6/netfilter/nf_conntrack_reasm.c
+++ b/net/ipv6/netfilter/nf_conntrack_reasm.c
@@ -413,7 +413,7 @@ nf_ct_frag6_reasm(struct nf_ct_frag6_queue *fq, struct net_device *dev)
/* If the first fragment is fragmented itself, we split
* it to two chunks: the first with data and paged part
* and the second, holding only fragments. */
- if (skb_has_frags(head)) {
+ if (skb_has_frag_list(head)) {
struct sk_buff *clone;
int i, plen = 0;
diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c
index 545c414..8aea3f3 100644
--- a/net/ipv6/reassembly.c
+++ b/net/ipv6/reassembly.c
@@ -499,7 +499,7 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev,
/* If the first fragment is fragmented itself, we split
* it to two chunks: the first with data and paged part
* and the second, holding only fragments. */
- if (skb_has_frags(head)) {
+ if (skb_has_frag_list(head)) {
struct sk_buff *clone;
int i, plen = 0;
--
1.7.2.2
^ permalink raw reply related
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