* Re: [RFC v2 2/2] net: Add support for NTB virtual ethernet device
From: Jiri Pirko @ 2012-07-30 20:09 UTC (permalink / raw)
To: Jon Mason; +Cc: linux-kernel, netdev, linux-pci, Dave Jiang
In-Reply-To: <20120730181910.GB987@jonmason-lab>
Mon, Jul 30, 2012 at 08:19:11PM CEST, jon.mason@intel.com wrote:
>On Mon, Jul 30, 2012 at 04:02:16PM +0200, Jiri Pirko wrote:
>> Mon, Jul 30, 2012 at 02:26:34AM CEST, jon.mason@intel.com wrote:
>> >+static int __devinit ntb_netdev_probe(struct pci_dev *pdev)
>> >+{
>> >+ struct net_device *ndev;
>> >+ struct ntb_netdev *dev;
>> >+ int rc;
>> >+
>> >+ ndev = alloc_etherdev(sizeof(struct ntb_netdev));
>> >+ if (!ndev)
>> >+ return -ENOMEM;
>> >+
>> >+ dev = netdev_priv(ndev);
>> >+ dev->ndev = ndev;
>> >+ dev->pdev = pdev;
>> >+ BUG_ON(!dev->pdev);
>> >+ ndev->features = NETIF_F_HIGHDMA;
>> >+
>> >+ //ndev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
>> ^^ I guess you forgot to un-comment this.
>
>Oops. An easy fix. Anything else?
The rest looks good to me.
>
>Thanks,
>Jon
^ permalink raw reply
* [PATCH 1/2] drivers: net: ethernet: cpsw: Add SOC dependency support for cpsw dependent modules
From: Mugunthan V N @ 2012-07-30 20:17 UTC (permalink / raw)
To: netdev; +Cc: davem, Mugunthan V N
In-Reply-To: <1343679434-2369-1-git-send-email-mugunthanvnm@ti.com>
cpsw is dependent on davinci_cpdma and davinci_mdio, so adding SOC support for
dependent modules
Signed-off-by: Mugunthan V N <mugunthanvnm@ti.com>
---
drivers/net/ethernet/ti/Kconfig | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/ti/Kconfig b/drivers/net/ethernet/ti/Kconfig
index 1b173a6..b26cbda 100644
--- a/drivers/net/ethernet/ti/Kconfig
+++ b/drivers/net/ethernet/ti/Kconfig
@@ -32,7 +32,7 @@ config TI_DAVINCI_EMAC
config TI_DAVINCI_MDIO
tristate "TI DaVinci MDIO Support"
- depends on ARM && ( ARCH_DAVINCI || ARCH_OMAP3 )
+ depends on ARM && ( ARCH_DAVINCI || ARCH_OMAP3 || SOC_AM33XX )
select PHYLIB
---help---
This driver supports TI's DaVinci MDIO module.
@@ -42,7 +42,7 @@ config TI_DAVINCI_MDIO
config TI_DAVINCI_CPDMA
tristate "TI DaVinci CPDMA Support"
- depends on ARM && ( ARCH_DAVINCI || ARCH_OMAP3 )
+ depends on ARM && ( ARCH_DAVINCI || ARCH_OMAP3 || SOC_AM33XX )
---help---
This driver supports TI's DaVinci CPDMA dma engine.
--
1.7.0.4
^ permalink raw reply related
* [PATCH 2/2] drivers: net: ethernet: cpsw: Add device tree support to CPSW
From: Mugunthan V N @ 2012-07-30 20:17 UTC (permalink / raw)
To: netdev; +Cc: davem, Mugunthan V N
In-Reply-To: <1343679434-2369-1-git-send-email-mugunthanvnm@ti.com>
This patch adds device tree support for cpsw driver
Signed-off-by: Mugunthan V N <mugunthanvnm@ti.com>
---
Documentation/devicetree/bindings/net/cpsw.txt | 104 ++++++++++++++
drivers/net/ethernet/ti/cpsw.c | 174 +++++++++++++++++++++++-
2 files changed, 272 insertions(+), 6 deletions(-)
create mode 100644 Documentation/devicetree/bindings/net/cpsw.txt
diff --git a/Documentation/devicetree/bindings/net/cpsw.txt b/Documentation/devicetree/bindings/net/cpsw.txt
new file mode 100644
index 0000000..acca48c
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/cpsw.txt
@@ -0,0 +1,104 @@
+TI SoC Ethernet Switch Controller Device Tree Bindings
+------------------------------------------------------
+
+Required properties:
+- compatible : Should be "ti,cpsw"
+- reg : physical base address and size of the cpsw
+ registers map
+- interrupts : property with a value describing the interrupt
+ number
+- interrupt-parent : The parent interrupt controller
+- cpdma_channels : Specifies number of channels in CPDMA
+- host_port_no : Specifies host port shift
+- cpdma_reg_ofs : Specifies CPDMA submodule register offset
+- ale_reg_ofs : Specifies ALE submodule register offset
+- ale_entries : Specifies No of entries ALE can hold
+- host_port_reg_ofs : Specifies host port register offset
+- hw_stats_reg_ofs : Specifies hardware statistics register offset
+- bd_ram_ofs : Specifies internal desciptor RAM offset
+- bd_ram_size : Specifies internal descriptor RAM size
+- rx_descs : Specifies number of Rx descriptors
+- mac_control : Specifies Default MAC control register content
+ for the specific platform
+- slaves : Specifies number for slaves
+- slave_reg_ofs : Specifies slave register offset
+- sliver_reg_ofs : Specifies slave sliver register offset
+- phy_id : Specifies slave phy id
+- mac-address : Specifies slave MAC address
+
+Optional properties:
+- ti,hwmods : Must be "cpgmac0"
+- no_bd_ram : Must be 0 or 1
+
+Note: "ti,hwmods" field is used to fetch the base address and irq
+resources from TI, omap hwmod data base during device registration.
+Future plan is to migrate hwmod data base contents into device tree
+blob so that, all the required data will be used from device tree dts
+file.
+
+Examples:
+
+ mac: ethernet@4A100000 {
+ compatible = "ti,cpsw";
+ reg = <0x4A100000 0x1000>;
+ interrupts = <55 0x4>;
+ interrupt-parent = <&intc>;
+ cpdma_channels = 8;
+ host_port_no = 0;
+ cpdma_reg_ofs = 0x800;
+ ale_reg_ofs = 0xd00;
+ ale_entries = 1024;
+ host_port_reg_ofs = 0x108;
+ hw_stats_reg_ofs = 0x900;
+ bd_ram_ofs = 0x2000;
+ bd_ram_size = 0x2000;
+ no_bd_ram = 0;
+ rx_descs = 64;
+ mac_control = 0x20;
+ slaves = 2;
+ slave@0 {
+ slave_reg_ofs = 0x208;
+ sliver_reg_ofs = 0xd80;
+ phy_id = "davinci_mdio-0:00"
+ mac-address = [00 04 9F 01 1B B8];
+ };
+ slave@1 {
+ slave_reg_ofs = 0x208;
+ sliver_reg_ofs = 0xd80;
+ phy_id = "davinci_mdio-0:01"
+ mac-address = [00 04 9F 01 1B B9];
+ };
+ };
+
+(or)
+
+ mac: ethernet@4A100000 {
+ compatible = "ti,cpsw";
+ ti,hwmods = "cpgmac0";
+ cpdma_channels = 8;
+ host_port_no = 0;
+ cpdma_reg_ofs = 0x800;
+ ale_reg_ofs = 0xd00;
+ ale_entries = 1024;
+ host_port_reg_ofs = 0x108;
+ hw_stats_reg_ofs = 0x900;
+ bd_ram_ofs = 0x2000;
+ bd_ram_size = 0x2000;
+ no_bd_ram = 0;
+ rx_descs = 64;
+ mac_control = 0x20;
+ slaves = 2;
+ slave@0 {
+ slave_reg_ofs = 0x208;
+ sliver_reg_ofs = 0xd80;
+ phy_id = "davinci_mdio-0:00"
+ mac-address = [00 04 9F 01 1B B8];
+ };
+ slave@1 {
+ slave_reg_ofs = 0x208;
+ sliver_reg_ofs = 0xd80;
+ phy_id = "davinci_mdio-0:01"
+ mac-address = [00 04 9F 01 1B B9];
+ };
+
+ };
diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c
index 1e5d85b..0cbc0e5 100644
--- a/drivers/net/ethernet/ti/cpsw.c
+++ b/drivers/net/ethernet/ti/cpsw.c
@@ -28,6 +28,9 @@
#include <linux/workqueue.h>
#include <linux/delay.h>
#include <linux/pm_runtime.h>
+#include <linux/of.h>
+#include <linux/of_net.h>
+#include <linux/of_device.h>
#include <linux/platform_data/cpsw.h>
@@ -709,6 +712,158 @@ static void cpsw_slave_init(struct cpsw_slave *slave, struct cpsw_priv *priv)
slave->sliver = regs + data->sliver_reg_ofs;
}
+static int cpsw_probe_dt(struct cpsw_platform_data *data,
+ struct platform_device *pdev)
+{
+ struct device_node *node = pdev->dev.of_node;
+ struct device_node *slave_node;
+ int i = 0, ret;
+ u32 prop;
+
+ if (!node)
+ return -EINVAL;
+
+ if (of_property_read_u32(node, "slaves", &prop)) {
+ pr_err("Missing slaves property in the DT.\n");
+ return -EINVAL;
+ }
+ data->slaves = prop;
+
+ data->slave_data = kzalloc(sizeof(struct cpsw_slave_data) *
+ data->slaves, GFP_KERNEL);
+ if (!data->slave_data) {
+ pr_err("Could not allocate slave memory.\n");
+ return -EINVAL;
+ }
+
+ data->no_bd_ram = of_property_read_bool(node, "no_bd_ram");
+
+ if (of_property_read_u32(node, "cpdma_channels", &prop)) {
+ pr_err("Missing cpdma_channels property in the DT.\n");
+ ret = -EINVAL;
+ goto error_ret;
+ }
+ data->channels = prop;
+
+ if (of_property_read_u32(node, "host_port_no", &prop)) {
+ pr_err("Missing host_port_no property in the DT.\n");
+ ret = -EINVAL;
+ goto error_ret;
+ }
+ data->host_port_num = prop;
+
+ if (of_property_read_u32(node, "cpdma_reg_ofs", &prop)) {
+ pr_err("Missing cpdma_reg_ofs property in the DT.\n");
+ ret = -EINVAL;
+ goto error_ret;
+ }
+ data->cpdma_reg_ofs = prop;
+
+ if (of_property_read_u32(node, "cpdma_sram_ofs", &prop)) {
+ pr_err("Missing cpdma_sram_ofs property in the DT.\n");
+ ret = -EINVAL;
+ goto error_ret;
+ }
+ data->cpdma_sram_ofs = prop;
+
+ if (of_property_read_u32(node, "ale_reg_ofs", &prop)) {
+ pr_err("Missing ale_reg_ofs property in the DT.\n");
+ ret = -EINVAL;
+ goto error_ret;
+ }
+ data->ale_reg_ofs = prop;
+
+ if (of_property_read_u32(node, "ale_entries", &prop)) {
+ pr_err("Missing ale_entries property in the DT.\n");
+ ret = -EINVAL;
+ goto error_ret;
+ }
+ data->ale_entries = prop;
+
+ if (of_property_read_u32(node, "host_port_reg_ofs", &prop)) {
+ pr_err("Missing host_port_reg_ofs property in the DT.\n");
+ ret = -EINVAL;
+ goto error_ret;
+ }
+ data->host_port_reg_ofs = prop;
+
+ if (of_property_read_u32(node, "hw_stats_reg_ofs", &prop)) {
+ pr_err("Missing hw_stats_reg_ofs property in the DT.\n");
+ ret = -EINVAL;
+ goto error_ret;
+ }
+ data->hw_stats_reg_ofs = prop;
+
+ if (of_property_read_u32(node, "bd_ram_ofs", &prop)) {
+ pr_err("Missing bd_ram_ofs property in the DT.\n");
+ ret = -EINVAL;
+ goto error_ret;
+ }
+ data->bd_ram_ofs = prop;
+
+ if (of_property_read_u32(node, "bd_ram_size", &prop)) {
+ pr_err("Missing bd_ram_size property in the DT.\n");
+ ret = -EINVAL;
+ goto error_ret;
+ }
+ data->bd_ram_size = prop;
+
+ if (of_property_read_u32(node, "rx_descs", &prop)) {
+ pr_err("Missing rx_descs property in the DT.\n");
+ ret = -EINVAL;
+ goto error_ret;
+ }
+ data->rx_descs = prop;
+
+ if (of_property_read_u32(node, "mac_control", &prop)) {
+ pr_err("Missing mac_control property in the DT.\n");
+ ret = -EINVAL;
+ goto error_ret;
+ }
+ data->mac_control = prop;
+
+ for_each_child_of_node(node, slave_node) {
+ struct cpsw_slave_data *slave_data = data->slave_data + i;
+ const char *phy_id = NULL;
+ const void *mac_addr = NULL;
+
+ if (of_property_read_string(slave_node, "phy_id", &phy_id)) {
+ pr_err("Missing slave[%d] phy_id property\n", i);
+ ret = -EINVAL;
+ goto error_ret;
+ }
+ slave_data->phy_id = phy_id;
+
+ if (of_property_read_u32(slave_node, "slave_reg_ofs", &prop)) {
+ pr_err("Missing slave[%d] slave_reg_ofs property\n", i);
+ ret = -EINVAL;
+ goto error_ret;
+ }
+ slave_data->slave_reg_ofs = prop;
+
+ if (of_property_read_u32(slave_node, "sliver_reg_ofs",
+ &prop)) {
+ pr_err("Missing slave[%d] sliver_reg_ofs property\n",
+ i);
+ ret = -EINVAL;
+ goto error_ret;
+ }
+ slave_data->sliver_reg_ofs = prop;
+
+ mac_addr = of_get_mac_address(slave_node);
+ if (mac_addr)
+ memcpy(slave_data->mac_addr, mac_addr, ETH_ALEN);
+
+ i++;
+ }
+
+ return 0;
+
+error_ret:
+ kfree(data->slave_data);
+ return ret;
+}
+
static int __devinit cpsw_probe(struct platform_device *pdev)
{
struct cpsw_platform_data *data = pdev->dev.platform_data;
@@ -720,11 +875,6 @@ static int __devinit cpsw_probe(struct platform_device *pdev)
struct resource *res;
int ret = 0, i, k = 0;
- if (!data) {
- pr_err("platform data missing\n");
- return -ENODEV;
- }
-
ndev = alloc_etherdev(sizeof(struct cpsw_priv));
if (!ndev) {
pr_err("error allocating net_device\n");
@@ -734,13 +884,19 @@ static int __devinit cpsw_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, ndev);
priv = netdev_priv(ndev);
spin_lock_init(&priv->lock);
- priv->data = *data;
priv->pdev = pdev;
priv->ndev = ndev;
priv->dev = &ndev->dev;
priv->msg_enable = netif_msg_init(debug_level, CPSW_DEBUG);
priv->rx_packet_max = max(rx_packet_max, 128);
+ if (cpsw_probe_dt(&priv->data, pdev)) {
+ pr_err("cpsw: platform data missing\n");
+ ret = -ENODEV;
+ goto clean_ndev_ret;
+ }
+ data = &priv->data;
+
if (is_valid_ether_addr(data->slave_data[0].mac_addr)) {
memcpy(priv->mac_addr, data->slave_data[0].mac_addr, ETH_ALEN);
pr_info("Detected MACID = %pM", priv->mac_addr);
@@ -996,11 +1152,17 @@ static const struct dev_pm_ops cpsw_pm_ops = {
.resume = cpsw_resume,
};
+static const struct of_device_id cpsw_of_mtable[] = {
+ { .compatible = "ti,cpsw", },
+ { /* sentinel */ },
+};
+
static struct platform_driver cpsw_driver = {
.driver = {
.name = "cpsw",
.owner = THIS_MODULE,
.pm = &cpsw_pm_ops,
+ .of_match_table = of_match_ptr(cpsw_of_mtable),
},
.probe = cpsw_probe,
.remove = __devexit_p(cpsw_remove),
--
1.7.0.4
^ permalink raw reply related
* [PATCH 0/2] Add device tree support and resolving SOC dependency to cpsw driver
From: Mugunthan V N @ 2012-07-30 20:17 UTC (permalink / raw)
To: netdev; +Cc: davem, Mugunthan V N
This patch set adds SOC dependency for CPSW dependent modules and adds support
for device tree for CPSW driver
Mugunthan V N (2):
drivers: net: ethernet: cpsw: Add SOC dependency support for cpsw
dependent modules
drivers: net: ethernet: cpsw: Add device tree support to CPSW
Documentation/devicetree/bindings/net/cpsw.txt | 104 ++++++++++++++
drivers/net/ethernet/ti/Kconfig | 4 +-
drivers/net/ethernet/ti/cpsw.c | 174 +++++++++++++++++++++++-
3 files changed, 274 insertions(+), 8 deletions(-)
create mode 100644 Documentation/devicetree/bindings/net/cpsw.txt
^ permalink raw reply
* Re: [PATCH net 1/2] tcp: Limit number of segments generated by GSO per skb
From: Ben Greear @ 2012-07-30 21:00 UTC (permalink / raw)
To: Ben Hutchings; +Cc: David Miller, netdev, linux-net-drivers
In-Reply-To: <1343677270.2667.31.camel@bwh-desktop.uk.solarflarecom.com>
On 07/30/2012 12:41 PM, Ben Hutchings wrote:
> On Mon, 2012-07-30 at 10:23 -0700, Ben Greear wrote:
>> On 07/30/2012 10:16 AM, Ben Hutchings wrote:
>>> A peer (or local user) may cause TCP to use a nominal MSS of as little
>>> as 88 (actual MSS of 76 with timestamps). Given that we have a
>>> sufficiently prodigious local sender and the peer ACKs quickly enough,
>>> it is nevertheless possible to grow the window for such a connection
>>> to the point that we will try to send just under 64K at once. This
>>> results in a single skb that expands to 861 segments.
>>>
>>> In some drivers with TSO support, such an skb will require hundreds of
>>> DMA descriptors; a substantial fraction of a TX ring or even more than
>>> a full ring. The TX queue selected for the skb may stall and trigger
>>> the TX watchdog repeatedly (since the problem skb will be retried
>>> after the TX reset). This particularly affects sfc, for which the
>>> issue is designated as CVE-2012-3412. However it may be that some
>>> hardware or firmware also fails to handle such an extreme TSO request
>>> correctly.
>>>
>>> Therefore, limit the number of segments per skb to 100. This should
>>> make no difference to behaviour unless the actual MSS is less than
>>> about 700.
>>
>> Please do not do this...or at least allow over-rides. We love
>> the trick of seting very small MSS and making the NICs generate
>> huge numbers of small TCP frames with efficient user-space
>> logic. We use this for stateful TCP load testing when high
>> numbers of tcp packets-per-second is desired.
>
> Please test whether this actually makes a difference - my suspicion is
> that 100 segments per skb is easily enough to prevent the host being a
> bottleneck.
Any CPU I can save I can use for other tasks. If we can use the
NIC's offload features to segment pkts, then we get near linear
increase in pkts-per-second by adding NICs..at least up to whatever
the total bandwidth of the system is...
If you want to have the OS default to a safe value, that is
fine by me..but please give us a tunable so that we can get
the old behaviour.
It's always possible I'm not the only one using this,
and I think it would be considered bad form to break
existing features and provide no work-around.
Thanks,
Ben
>
>> Intel NICs, including 10G, work just fine with minimal MSS
>> in this scenario.
>
> I'll leave this to the Intel maintainers to answer.
>
> Ben.
>
--
Ben Greear <greearb@candelatech.com>
Candela Technologies Inc http://www.candelatech.com
^ permalink raw reply
* [PATCH net] net: Remove unused variables in rt_cache_stat
From: Vijay Subramanian @ 2012-07-30 21:45 UTC (permalink / raw)
To: netdev; +Cc: davem, Vijay Subramanian
With the removal of the routing cache, some variables in rt_cache_stat are no
longer used. Remove them from rt_cache_stat and do not print them out in
/proc/net/stat/rt_cache.
Signed-off-by: Vijay Subramanian <subramanian.vijay@gmail.com>
---
checkpatch complains that the seq_printf line is over 80 chars which was already
the case. I left it as is to aid in grepping the sources.
include/net/route.h | 8 --------
net/ipv4/route.c | 16 +++-------------
2 files changed, 3 insertions(+), 21 deletions(-)
diff --git a/include/net/route.h b/include/net/route.h
index 8c52bc6..69e54f9 100644
--- a/include/net/route.h
+++ b/include/net/route.h
@@ -84,22 +84,14 @@ struct ip_rt_acct {
};
struct rt_cache_stat {
- unsigned int in_hit;
unsigned int in_slow_tot;
unsigned int in_slow_mc;
unsigned int in_no_route;
unsigned int in_brd;
unsigned int in_martian_dst;
unsigned int in_martian_src;
- unsigned int out_hit;
unsigned int out_slow_tot;
unsigned int out_slow_mc;
- unsigned int gc_total;
- unsigned int gc_ignored;
- unsigned int gc_goal_miss;
- unsigned int gc_dst_overflow;
- unsigned int in_hlist_search;
- unsigned int out_hlist_search;
};
extern struct ip_rt_acct __percpu *ip_rt_acct;
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index fc1a81c..114a6c9 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -298,14 +298,12 @@ static int rt_cpu_seq_show(struct seq_file *seq, void *v)
struct rt_cache_stat *st = v;
if (v == SEQ_START_TOKEN) {
- seq_printf(seq, "entries in_hit in_slow_tot in_slow_mc in_no_route in_brd in_martian_dst in_martian_src out_hit out_slow_tot out_slow_mc gc_total gc_ignored gc_goal_miss gc_dst_overflow in_hlist_search out_hlist_search\n");
+ seq_printf(seq, "entries in_slow_tot in_slow_mc in_no_route in_brd in_martian_dst in_martian_src out_slow_tot out_slow_mc\n");
return 0;
}
- seq_printf(seq,"%08x %08x %08x %08x %08x %08x %08x %08x "
- " %08x %08x %08x %08x %08x %08x %08x %08x %08x \n",
+ seq_printf(seq, "%08x %08x %08x %08x %08x %08x %08x %08x %08x\n",
dst_entries_get_slow(&ipv4_dst_ops),
- st->in_hit,
st->in_slow_tot,
st->in_slow_mc,
st->in_no_route,
@@ -313,16 +311,8 @@ static int rt_cpu_seq_show(struct seq_file *seq, void *v)
st->in_martian_dst,
st->in_martian_src,
- st->out_hit,
st->out_slow_tot,
- st->out_slow_mc,
-
- st->gc_total,
- st->gc_ignored,
- st->gc_goal_miss,
- st->gc_dst_overflow,
- st->in_hlist_search,
- st->out_hlist_search
+ st->out_slow_mc
);
return 0;
}
--
1.7.0.4
^ permalink raw reply related
* Re: [PATCH net 1/2] tcp: Limit number of segments generated by GSO per skb
From: David Miller @ 2012-07-30 21:46 UTC (permalink / raw)
To: bhutchings; +Cc: eric.dumazet, netdev, linux-net-drivers
In-Reply-To: <1343676952.2667.26.camel@bwh-desktop.uk.solarflarecom.com>
From: Ben Hutchings <bhutchings@solarflare.com>
Date: Mon, 30 Jul 2012 20:35:52 +0100
> On Mon, 2012-07-30 at 19:31 +0200, Eric Dumazet wrote:
>> Or you could introduce a new wk->sk_gso_max_segments, that your sfc
>> driver sets to whatever limit ?
>
> Yes, that's another option.
This is how I want this handled.
^ permalink raw reply
* Re: [PATCH net] net: Remove unused variables in rt_cache_stat
From: David Miller @ 2012-07-30 21:52 UTC (permalink / raw)
To: subramanian.vijay; +Cc: netdev
In-Reply-To: <1343684750-2987-1-git-send-email-subramanian.vijay@gmail.com>
From: Vijay Subramanian <subramanian.vijay@gmail.com>
Date: Mon, 30 Jul 2012 14:45:50 -0700
> With the removal of the routing cache, some variables in rt_cache_stat are no
> longer used. Remove them from rt_cache_stat and do not print them out in
> /proc/net/stat/rt_cache.
>
> Signed-off-by: Vijay Subramanian <subramanian.vijay@gmail.com>
> ---
> checkpatch complains that the seq_printf line is over 80 chars which was already
> the case. I left it as is to aid in grepping the sources.
You cannot make this change, these fields are exported via procfs and
therefore you will break any application that is parsing the existing
layout.
^ permalink raw reply
* Re: [PATCH] codel: refine one condition to avoid a nul rec_inv_sqrt
From: David Miller @ 2012-07-30 21:54 UTC (permalink / raw)
To: eric.dumazet; +Cc: netdev, lp2s1h
In-Reply-To: <1343631141.2626.13293.camel@edumazet-glaptop>
From: Eric Dumazet <eric.dumazet@gmail.com>
Date: Mon, 30 Jul 2012 08:52:21 +0200
> From: Eric Dumazet <edumazet@google.com>
>
> One condition before codel_Newton_step() was not good if
> we never left the dropping state for a flow. As a result
> rec_inv_sqrt was 0, instead of the ~0 initial value.
>
> codel control law was then set to a very aggressive mode, dropping
> many packets before reaching 'target' and recovering from this problem.
>
> To keep codel_vars_init() as efficient as possible, refine
> the condition to make sure rec_inv_sqrt initial value is correct
>
> Many thanks to Anton Mich for discovering the issue and suggesting
> a fix.
>
> Reported-by: Anton Mich <lp2s1h@gmail.com>
> Signed-off-by: Eric Dumazet <edumazet@google.com>
Applied and queued up for -stable.
^ permalink raw reply
* Re: [PATCH] net: TCP early demux cleanup
From: David Miller @ 2012-07-30 21:54 UTC (permalink / raw)
To: eric.dumazet; +Cc: netdev
In-Reply-To: <1343631973.2626.13317.camel@edumazet-glaptop>
From: Eric Dumazet <eric.dumazet@gmail.com>
Date: Mon, 30 Jul 2012 09:06:13 +0200
> From: Eric Dumazet <edumazet@google.com>
>
> early_demux() handlers should be called in RCU context, and as we
> use skb_dst_set_noref(skb, dst), caller must not exit from RCU context
> before dst use (skb_dst(skb)) or release (skb_drop(dst))
>
> Therefore, rcu_read_lock()/rcu_read_unlock() pairs around
> ->early_demux() are confusing and not needed :
>
> Protocol handlers are already in an RCU read lock section.
> (__netif_receive_skb() does the rcu_read_lock() )
>
> Signed-off-by: Eric Dumazet <edumazet@google.com>
I wondered about this very issue when I wrote this code, thanks
for clearing things up.
Applied.
^ permalink raw reply
* Re: [PATCH] net: ipv4: fix RCU races on dst refcounts
From: David Miller @ 2012-07-30 21:56 UTC (permalink / raw)
To: eric.dumazet; +Cc: netdev
In-Reply-To: <1343640037.21269.15.camel@edumazet-glaptop>
From: Eric Dumazet <eric.dumazet@gmail.com>
Date: Mon, 30 Jul 2012 11:20:37 +0200
> From: Eric Dumazet <edumazet@google.com>
>
> commit c6cffba4ffa2 (ipv4: Fix input route performance regression.)
> added various fatal races with dst refcounts.
>
> crashes happen on tcp workloads if routes are added/deleted at the same
> time.
>
> The dst_free() calls from free_fib_info_rcu() are clearly racy.
>
> We need instead regular dst refcounting (dst_release()) and make
> sure dst_release() is aware of RCU grace periods :
>
> Add DST_RCU_FREE flag so that dst_release() respects an RCU grace period
> before dst destruction for cached dst
>
> Introduce a new inet_sk_rx_dst_set() helper, using atomic_inc_not_zero()
> to make sure we dont increase a zero refcount (On a dst currently
> waiting an rcu grace period before destruction)
>
> rt_cache_route() must take a reference on the new cached route, and
> release it if was not able to install it.
>
> With this patch, my machines survive various benchmarks.
>
> Signed-off-by: Eric Dumazet <edumazet@google.com>
I'm applying this patch, however:
> +static inline void inet_sk_rx_dst_set(struct sock *sk, const struct sk_buff *skb)
> +{
> + struct dst_entry *dst = skb_dst(skb);
> +
> + if (atomic_inc_not_zero(&dst->__refcnt)) {
> + if (!(dst->flags & DST_RCU_FREE))
> + dst->flags |= DST_RCU_FREE;
> +
> + sk->sk_rx_dst = dst;
> + inet_sk(sk)->rx_dst_ifindex = skb->skb_iif;
> + }
> +}
This is not safe.
We cannot allow clients outside of the DST providers make non-atomic
changes to the dst attributes, as you are here with this dst->flags
modification.
Make this "needs RCU liberation" indication at the spot where we get
rid of sk->sk_rx_dst, make a dst_release_rcu() or somthing like that.
^ permalink raw reply
* Re: [PATCH] ipv4: remove rt_cache_rebuild_count
From: David Miller @ 2012-07-30 21:56 UTC (permalink / raw)
To: eric.dumazet; +Cc: netdev
In-Reply-To: <1343668469.21269.26.camel@edumazet-glaptop>
From: Eric Dumazet <eric.dumazet@gmail.com>
Date: Mon, 30 Jul 2012 19:14:29 +0200
> From: Eric Dumazet <edumazet@google.com>
>
> After IP route cache removal, rt_cache_rebuild_count is no longer
> used.
>
> Signed-off-by: Eric Dumazet <edumazet@google.com>
Applied.
^ permalink raw reply
* Re: [PATCH] bridge: make port attributes const
From: David Miller @ 2012-07-30 21:56 UTC (permalink / raw)
To: shemminger; +Cc: netdev
In-Reply-To: <20120730115549.0d53d8cb@nehalam.linuxnetplumber.net>
From: Stephen Hemminger <shemminger@vyatta.com>
Date: Mon, 30 Jul 2012 11:55:49 -0700
> Simple table that can be marked const.
>
> Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
Applied.
^ permalink raw reply
* Re: [PATCH net 1/2] tcp: Limit number of segments generated by GSO per skb
From: Ben Hutchings @ 2012-07-30 22:20 UTC (permalink / raw)
To: David Miller; +Cc: eric.dumazet, netdev, linux-net-drivers
In-Reply-To: <20120730.144632.478408817308488569.davem@davemloft.net>
On Mon, 2012-07-30 at 14:46 -0700, David Miller wrote:
> From: Ben Hutchings <bhutchings@solarflare.com>
> Date: Mon, 30 Jul 2012 20:35:52 +0100
>
> > On Mon, 2012-07-30 at 19:31 +0200, Eric Dumazet wrote:
> >> Or you could introduce a new wk->sk_gso_max_segments, that your sfc
> >> driver sets to whatever limit ?
> >
> > Yes, that's another option.
>
> This is how I want this handled.
How should that be applied in the GRO-forwarding case?
Ben.
--
Ben Hutchings, Staff Engineer, Solarflare
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 net 1/2] tcp: Limit number of segments generated by GSO per skb
From: Stephen Hemminger @ 2012-07-30 22:50 UTC (permalink / raw)
To: Ben Hutchings; +Cc: David Miller, eric.dumazet, netdev, linux-net-drivers
In-Reply-To: <1343686857.2667.60.camel@bwh-desktop.uk.solarflarecom.com>
On Mon, 30 Jul 2012 23:20:57 +0100
Ben Hutchings <bhutchings@solarflare.com> wrote:
> On Mon, 2012-07-30 at 14:46 -0700, David Miller wrote:
> > From: Ben Hutchings <bhutchings@solarflare.com>
> > Date: Mon, 30 Jul 2012 20:35:52 +0100
> >
> > > On Mon, 2012-07-30 at 19:31 +0200, Eric Dumazet wrote:
> > >> Or you could introduce a new wk->sk_gso_max_segments, that your sfc
> > >> driver sets to whatever limit ?
> > >
> > > Yes, that's another option.
> >
> > This is how I want this handled.
>
> How should that be applied in the GRO-forwarding case?
>
> Ben.
>
Why not make max_frags a property of the device?
Something like the following untested idea:
diff --git a/net/core/dev.c b/net/core/dev.c
index 0ebaea1..bfb005b 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -2159,14 +2159,16 @@ EXPORT_SYMBOL(netif_skb_features);
* at least one of fragments is in highmem and device does not
* support DMA from it.
*/
-static inline int skb_needs_linearize(struct sk_buff *skb,
- int features)
+static inline bool skb_needs_linearize(struct sk_buff *skb,
+ int features, unsigned int maxfrags)
{
- return skb_is_nonlinear(skb) &&
- ((skb_has_frag_list(skb) &&
- !(features & NETIF_F_FRAGLIST)) ||
- (skb_shinfo(skb)->nr_frags &&
- !(features & NETIF_F_SG)));
+ if (!skb_is_nonlinear(skb))
+ return false;
+
+ if (skb_has_frag_list(skb))
+ return !(features & NETIF_F_FRAGLIST);
+ else
+ return skb_shinfo(skb)->nr_frags > maxfrags;
}
int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
@@ -2206,7 +2208,7 @@ int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
if (skb->next)
goto gso;
} else {
- if (skb_needs_linearize(skb, features) &&
+ if (skb_needs_linearize(skb, features, dev->max_frags) &&
__skb_linearize(skb))
goto out_kfree_skb;
@@ -5544,6 +5546,20 @@ int register_netdevice(struct net_device *dev)
dev->features |= NETIF_F_SOFT_FEATURES;
dev->wanted_features = dev->features & dev->hw_features;
+ if (dev->max_frags > 0) {
+ if (!(features & NETIF_F_SG)) {
+ netdev_dbg(dev,
+ "Resetting max fragments since no NETIF_F_SG\n");
+ dev->max_frags = 0;
+ }
+ } else {
+ /* If device has not set maximum number of fragments
+ * then assume it can take any number of them
+ */
+ if (features & NETIF_F_SG)
+ dev->max_frags = MAX_SKB_FRAGS;
+ }
+
/* Turn on no cache copy if HW is doing checksum */
if (!(dev->flags & IFF_LOOPBACK)) {
dev->hw_features |= NETIF_F_NOCACHE_COPY;
^ permalink raw reply related
* Re: [PATCH net 1/2] tcp: Limit number of segments generated by GSO per skb
From: Ben Hutchings @ 2012-07-30 23:07 UTC (permalink / raw)
To: Stephen Hemminger; +Cc: David Miller, eric.dumazet, netdev, linux-net-drivers
In-Reply-To: <20120730155026.7460a9a6@nehalam.linuxnetplumber.net>
On Mon, 2012-07-30 at 15:50 -0700, Stephen Hemminger wrote:
> On Mon, 30 Jul 2012 23:20:57 +0100
> Ben Hutchings <bhutchings@solarflare.com> wrote:
>
> > On Mon, 2012-07-30 at 14:46 -0700, David Miller wrote:
> > > From: Ben Hutchings <bhutchings@solarflare.com>
> > > Date: Mon, 30 Jul 2012 20:35:52 +0100
> > >
> > > > On Mon, 2012-07-30 at 19:31 +0200, Eric Dumazet wrote:
> > > >> Or you could introduce a new wk->sk_gso_max_segments, that your sfc
> > > >> driver sets to whatever limit ?
> > > >
> > > > Yes, that's another option.
> > >
> > > This is how I want this handled.
> >
> > How should that be applied in the GRO-forwarding case?
> >
> > Ben.
> >
> Why not make max_frags a property of the device?
[...]
This has nothing to do with the number of input fragments. But I think
you're on the right track - this can be checked in netif_skb_features()
or something like that.
Ben.
--
Ben Hutchings, Staff Engineer, Solarflare
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] net: ipv4: fix RCU races on dst refcounts
From: David Miller @ 2012-07-31 0:40 UTC (permalink / raw)
To: eric.dumazet; +Cc: netdev
In-Reply-To: <20120730.145637.906924670032055493.davem@davemloft.net>
From: David Miller <davem@davemloft.net>
Date: Mon, 30 Jul 2012 14:56:37 -0700 (PDT)
> From: Eric Dumazet <eric.dumazet@gmail.com>
> Date: Mon, 30 Jul 2012 11:20:37 +0200
>
>> From: Eric Dumazet <edumazet@google.com>
>>
>> We need instead regular dst refcounting (dst_release()) and make
>> sure dst_release() is aware of RCU grace periods :
Eric, we really cannot do this.
We absolutely must call dst_free() directly when cached entries
are flushed.
Your delayed scheme using dst_release() doesn't work, it exposes us to
the "stale netdevice references" issue even for cached entries. This
exact issue is why I moved away from a dst_release() based scheme to
a !DST_NOCACHE + dst_free() one.
dst_free() is special. It is special in that if there are existing
references, it adds the dst onto the generic GC list of busy dsts in
net/core/dst.c
This is important, because it means that even if references are still
held on the dst, we will still be able to purge spurious netdevice
references when those netdevices try to go down or unregister
themselves.
You can't defer the dst_free() to the final refcount drop like your
code does now. A socket, or other dst caching entity, can hold onto
the dst forever, do no socket operations at all, and therefore hold
onto a netdevice for an infinite amount of time.
Look at how net/core/dst.c:dst_dev_event() walks dst_busy_list.
That's why we must propagate cached dsts into dst_busy_list no later
than when we trim them from ->nh_rth_{input,output}
I noticed this because I'm trying to work on a fix the lingering dst
netdevice reference problem for non-cached dsts.
^ permalink raw reply
* [PATCH 0/2] ipv4: Fix dangling netdev refs
From: David Miller @ 2012-07-31 1:23 UTC (permalink / raw)
To: eric.dumazet; +Cc: netdev
Eric, this should give you an idea of what I was working on.
It really assumes the universe in place before your change last
night. It is very likely we'll have to revert it and look for
another solution to the problem you were trying to solve. And
actually I don't understand the actual bug very well.
I can only assume that the core issue was that, unlike back when
we had the routing cache, the fib_info nexthops are not persistent
memory like the routing cache hash table was?
Otherwise I can see absolutely no change in reference counting and
dst destruction logic between the routing cache, and how I modified
fib_info nexthop cached routes to behave.
Anyways, the first patch caches routes in the nexthop exception
entries.
And the second patch has a global list for uncached routes so we
can purge netdevice references properly when such devices are
unregistered.
Signed-off-by: David S. Miller <davem@davemloft.net>
^ permalink raw reply
* [PATCH 1/2] ipv4: Cache routes in nexthop exception entries.
From: David Miller @ 2012-07-31 1:23 UTC (permalink / raw)
To: eric.dumazet; +Cc: netdev
Signed-off-by: David S. Miller <davem@davemloft.net>
---
include/net/ip_fib.h | 1 +
net/ipv4/fib_semantics.c | 4 +++
net/ipv4/route.c | 82 ++++++++++++++++++++++++++----------------------
3 files changed, 49 insertions(+), 38 deletions(-)
diff --git a/include/net/ip_fib.h b/include/net/ip_fib.h
index e69c3a4..c4770fc 100644
--- a/include/net/ip_fib.h
+++ b/include/net/ip_fib.h
@@ -54,6 +54,7 @@ struct fib_nh_exception {
u32 fnhe_pmtu;
__be32 fnhe_gw;
unsigned long fnhe_expires;
+ struct rtable *fnhe_rth;
unsigned long fnhe_stamp;
};
diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c
index e55171f..eaccdb5 100644
--- a/net/ipv4/fib_semantics.c
+++ b/net/ipv4/fib_semantics.c
@@ -153,6 +153,10 @@ static void free_nh_exceptions(struct fib_nh *nh)
struct fib_nh_exception *next;
next = rcu_dereference_protected(fnhe->fnhe_next, 1);
+
+ if (fnhe->fnhe_rth)
+ dst_release(&fnhe->fnhe_rth->dst);
+
kfree(fnhe);
fnhe = next;
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index d6eabcf..e2abb0d 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -587,7 +587,7 @@ static void ip_rt_build_flow_key(struct flowi4 *fl4, const struct sock *sk,
build_sk_flow_key(fl4, sk);
}
-static DEFINE_SEQLOCK(fnhe_seqlock);
+static DEFINE_SPINLOCK(fnhe_lock);
static struct fib_nh_exception *fnhe_oldest(struct fnhe_hash_bucket *hash)
{
@@ -599,6 +599,10 @@ static struct fib_nh_exception *fnhe_oldest(struct fnhe_hash_bucket *hash)
if (time_before(fnhe->fnhe_stamp, oldest->fnhe_stamp))
oldest = fnhe;
}
+ if (oldest->fnhe_rth) {
+ dst_release(&oldest->fnhe_rth->dst);
+ oldest->fnhe_rth = NULL;
+ }
return oldest;
}
@@ -620,7 +624,7 @@ static void update_or_create_fnhe(struct fib_nh *nh, __be32 daddr, __be32 gw,
int depth;
u32 hval = fnhe_hashfun(daddr);
- write_seqlock_bh(&fnhe_seqlock);
+ spin_lock_bh(&fnhe_lock);
hash = nh->nh_exceptions;
if (!hash) {
@@ -667,7 +671,7 @@ static void update_or_create_fnhe(struct fib_nh *nh, __be32 daddr, __be32 gw,
fnhe->fnhe_stamp = jiffies;
out_unlock:
- write_sequnlock_bh(&fnhe_seqlock);
+ spin_unlock_bh(&fnhe_lock);
return;
}
@@ -1167,36 +1171,37 @@ static struct fib_nh_exception *find_exception(struct fib_nh *nh, __be32 daddr)
static void rt_bind_exception(struct rtable *rt, struct fib_nh_exception *fnhe,
__be32 daddr)
{
- __be32 fnhe_daddr, gw;
- unsigned long expires;
- unsigned int seq;
- u32 pmtu;
-
-restart:
- seq = read_seqbegin(&fnhe_seqlock);
- fnhe_daddr = fnhe->fnhe_daddr;
- gw = fnhe->fnhe_gw;
- pmtu = fnhe->fnhe_pmtu;
- expires = fnhe->fnhe_expires;
- if (read_seqretry(&fnhe_seqlock, seq))
- goto restart;
-
- if (daddr != fnhe_daddr)
- return;
+ spin_lock_bh(&fnhe_lock);
+
+ if (daddr == fnhe->fnhe_daddr) {
+ struct rtable *orig;
- if (pmtu) {
- unsigned long diff = expires - jiffies;
+ if (fnhe->fnhe_pmtu) {
+ unsigned long expires = fnhe->fnhe_expires;
+ unsigned long diff = expires - jiffies;
- if (time_before(jiffies, expires)) {
- rt->rt_pmtu = pmtu;
- dst_set_expires(&rt->dst, diff);
+ if (time_before(jiffies, expires)) {
+ rt->rt_pmtu = fnhe->fnhe_pmtu;
+ dst_set_expires(&rt->dst, diff);
+ }
}
+ if (fnhe->fnhe_gw) {
+ rt->rt_flags |= RTCF_REDIRECTED;
+ rt->rt_gateway = fnhe->fnhe_gw;
+ }
+
+ orig = fnhe->fnhe_rth;
+ if (orig)
+ dst_release(&orig->dst);
+
+ rt->dst.flags |= DST_RCU_FREE;
+ dst_hold(&rt->dst);
+ fnhe->fnhe_rth = rt;
+
+ fnhe->fnhe_stamp = jiffies;
}
- if (gw) {
- rt->rt_flags |= RTCF_REDIRECTED;
- rt->rt_gateway = gw;
- }
- fnhe->fnhe_stamp = jiffies;
+
+ spin_unlock_bh(&fnhe_lock);
}
static void rt_cache_route(struct fib_nh *nh, struct rtable *rt)
@@ -1236,13 +1241,13 @@ static void rt_set_nexthop(struct rtable *rt, __be32 daddr,
if (nh->nh_gw && nh->nh_scope == RT_SCOPE_LINK)
rt->rt_gateway = nh->nh_gw;
- if (unlikely(fnhe))
- rt_bind_exception(rt, fnhe, daddr);
dst_init_metrics(&rt->dst, fi->fib_metrics, true);
#ifdef CONFIG_IP_ROUTE_CLASSID
rt->dst.tclassid = nh->nh_tclassid;
#endif
- if (!(rt->dst.flags & DST_NOCACHE))
+ if (unlikely(fnhe))
+ rt_bind_exception(rt, fnhe, daddr);
+ else if (!(rt->dst.flags & DST_NOCACHE))
rt_cache_route(nh, rt);
}
@@ -1741,18 +1746,19 @@ static struct rtable *__mkroute_output(const struct fib_result *res,
fnhe = NULL;
if (fi) {
fnhe = find_exception(&FIB_RES_NH(*res), fl4->daddr);
- if (!fnhe) {
+ if (fnhe)
+ rth = fnhe->fnhe_rth;
+ else
rth = FIB_RES_NH(*res).nh_rth_output;
- if (rt_cache_valid(rth)) {
- dst_hold(&rth->dst);
- return rth;
- }
+ if (rt_cache_valid(rth)) {
+ dst_hold(&rth->dst);
+ return rth;
}
}
rth = rt_dst_alloc(dev_out,
IN_DEV_CONF_GET(in_dev, NOPOLICY),
IN_DEV_CONF_GET(in_dev, NOXFRM),
- fi && !fnhe);
+ fi);
if (!rth)
return ERR_PTR(-ENOBUFS);
--
1.7.11.2
^ permalink raw reply related
* [PATCH 2/2] ipv4: Properly purge netdev references on uncached routes.
From: David Miller @ 2012-07-31 1:23 UTC (permalink / raw)
To: eric.dumazet; +Cc: netdev
When a device is unregistered, we have to purge all of the
references to it that may exist in the entire system.
If a route is uncached, we currently have no way of accomplishing
this.
So create a global list that is scanned when a network device goes
down. This mirrors the logic in net/core/dst.c's dst_ifdown().
Signed-off-by: David S. Miller <davem@davemloft.net>
---
include/net/route.h | 3 +++
net/ipv4/fib_frontend.c | 1 +
net/ipv4/route.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++---
net/ipv4/xfrm4_policy.c | 1 +
4 files changed, 69 insertions(+), 4 deletions(-)
diff --git a/include/net/route.h b/include/net/route.h
index 8c52bc6..776a27f 100644
--- a/include/net/route.h
+++ b/include/net/route.h
@@ -57,6 +57,8 @@ struct rtable {
/* Miscellaneous cached information */
u32 rt_pmtu;
+
+ struct list_head rt_uncached;
};
static inline bool rt_is_input_route(const struct rtable *rt)
@@ -107,6 +109,7 @@ extern struct ip_rt_acct __percpu *ip_rt_acct;
struct in_device;
extern int ip_rt_init(void);
extern void rt_cache_flush(struct net *net, int how);
+extern void rt_flush_dev(struct net_device *dev);
extern struct rtable *__ip_route_output_key(struct net *, struct flowi4 *flp);
extern struct rtable *ip_route_output_flow(struct net *, struct flowi4 *flp,
struct sock *sk);
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c
index 8732cc7..c43ae3f 100644
--- a/net/ipv4/fib_frontend.c
+++ b/net/ipv4/fib_frontend.c
@@ -1046,6 +1046,7 @@ static int fib_netdev_event(struct notifier_block *this, unsigned long event, vo
if (event == NETDEV_UNREGISTER) {
fib_disable_ip(dev, 2, -1);
+ rt_flush_dev(dev);
return NOTIFY_DONE;
}
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index e2abb0d..7111fce 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -147,6 +147,7 @@ static void ip_rt_update_pmtu(struct dst_entry *dst, struct sock *sk,
struct sk_buff *skb, u32 mtu);
static void ip_do_redirect(struct dst_entry *dst, struct sock *sk,
struct sk_buff *skb);
+static void ipv4_dst_destroy(struct dst_entry *dst);
static void ipv4_dst_ifdown(struct dst_entry *dst, struct net_device *dev,
int how)
@@ -170,6 +171,7 @@ static struct dst_ops ipv4_dst_ops = {
.default_advmss = ipv4_default_advmss,
.mtu = ipv4_mtu,
.cow_metrics = ipv4_cow_metrics,
+ .destroy = ipv4_dst_destroy,
.ifdown = ipv4_dst_ifdown,
.negative_advice = ipv4_negative_advice,
.link_failure = ipv4_link_failure,
@@ -1168,9 +1170,11 @@ static struct fib_nh_exception *find_exception(struct fib_nh *nh, __be32 daddr)
return NULL;
}
-static void rt_bind_exception(struct rtable *rt, struct fib_nh_exception *fnhe,
+static bool rt_bind_exception(struct rtable *rt, struct fib_nh_exception *fnhe,
__be32 daddr)
{
+ bool ret = false;
+
spin_lock_bh(&fnhe_lock);
if (daddr == fnhe->fnhe_daddr) {
@@ -1199,14 +1203,18 @@ static void rt_bind_exception(struct rtable *rt, struct fib_nh_exception *fnhe,
fnhe->fnhe_rth = rt;
fnhe->fnhe_stamp = jiffies;
+ ret = true;
}
spin_unlock_bh(&fnhe_lock);
+
+ return ret;
}
-static void rt_cache_route(struct fib_nh *nh, struct rtable *rt)
+static bool rt_cache_route(struct fib_nh *nh, struct rtable *rt)
{
struct rtable *orig, *prev, **p = &nh->nh_rth_output;
+ bool ret = true;
if (rt_is_input_route(rt))
p = &nh->nh_rth_input;
@@ -1221,6 +1229,48 @@ static void rt_cache_route(struct fib_nh *nh, struct rtable *rt)
dst_release(&orig->dst);
} else {
dst_release(&rt->dst);
+ ret = false;
+ }
+
+ return ret;
+}
+
+static DEFINE_SPINLOCK(rt_uncached_lock);
+static LIST_HEAD(rt_uncached_list);
+
+static void rt_add_uncached_list(struct rtable *rt)
+{
+ spin_lock_bh(&rt_uncached_lock);
+ list_add_tail(&rt->rt_uncached, &rt_uncached_list);
+ spin_unlock_bh(&rt_uncached_lock);
+}
+
+static void ipv4_dst_destroy(struct dst_entry *dst)
+{
+ struct rtable *rt = (struct rtable *) dst;
+
+ if (dst->flags & DST_NOCACHE) {
+ spin_lock_bh(&rt_uncached_lock);
+ list_del(&rt->rt_uncached);
+ spin_unlock_bh(&rt_uncached_lock);
+ }
+}
+
+void rt_flush_dev(struct net_device *dev)
+{
+ if (!list_empty(&rt_uncached_list)) {
+ struct net *net = dev_net(dev);
+ struct rtable *rt;
+
+ spin_lock_bh(&rt_uncached_lock);
+ list_for_each_entry(rt, &rt_uncached_list, rt_uncached) {
+ if (rt->dst.dev != dev)
+ continue;
+ rt->dst.dev = net->loopback_dev;
+ dev_hold(rt->dst.dev);
+ dev_put(dev);
+ }
+ spin_unlock_bh(&rt_uncached_lock);
}
}
@@ -1236,6 +1286,8 @@ static void rt_set_nexthop(struct rtable *rt, __be32 daddr,
struct fib_nh_exception *fnhe,
struct fib_info *fi, u16 type, u32 itag)
{
+ bool cached = false;
+
if (fi) {
struct fib_nh *nh = &FIB_RES_NH(*res);
@@ -1246,10 +1298,12 @@ static void rt_set_nexthop(struct rtable *rt, __be32 daddr,
rt->dst.tclassid = nh->nh_tclassid;
#endif
if (unlikely(fnhe))
- rt_bind_exception(rt, fnhe, daddr);
+ cached = rt_bind_exception(rt, fnhe, daddr);
else if (!(rt->dst.flags & DST_NOCACHE))
- rt_cache_route(nh, rt);
+ cached = rt_cache_route(nh, rt);
}
+ if (unlikely(!cached))
+ rt_add_uncached_list(rt);
#ifdef CONFIG_IP_ROUTE_CLASSID
#ifdef CONFIG_IP_MULTIPLE_TABLES
@@ -1316,6 +1370,7 @@ static int ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr,
rth->rt_iif = 0;
rth->rt_pmtu = 0;
rth->rt_gateway = 0;
+ INIT_LIST_HEAD(&rth->rt_uncached);
if (our) {
rth->dst.input= ip_local_deliver;
rth->rt_flags |= RTCF_LOCAL;
@@ -1441,6 +1496,7 @@ static int __mkroute_input(struct sk_buff *skb,
rth->rt_iif = 0;
rth->rt_pmtu = 0;
rth->rt_gateway = 0;
+ INIT_LIST_HEAD(&rth->rt_uncached);
rth->dst.input = ip_forward;
rth->dst.output = ip_output;
@@ -1607,6 +1663,7 @@ local_input:
rth->rt_iif = 0;
rth->rt_pmtu = 0;
rth->rt_gateway = 0;
+ INIT_LIST_HEAD(&rth->rt_uncached);
if (res.type == RTN_UNREACHABLE) {
rth->dst.input= ip_error;
rth->dst.error= -err;
@@ -1771,6 +1828,7 @@ static struct rtable *__mkroute_output(const struct fib_result *res,
rth->rt_iif = orig_oif ? : 0;
rth->rt_pmtu = 0;
rth->rt_gateway = 0;
+ INIT_LIST_HEAD(&rth->rt_uncached);
RT_CACHE_STAT_INC(out_slow_tot);
@@ -2050,6 +2108,8 @@ struct dst_entry *ipv4_blackhole_route(struct net *net, struct dst_entry *dst_or
rt->rt_type = ort->rt_type;
rt->rt_gateway = ort->rt_gateway;
+ INIT_LIST_HEAD(&rt->rt_uncached);
+
dst_free(new);
}
diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c
index c628184..681ea2f 100644
--- a/net/ipv4/xfrm4_policy.c
+++ b/net/ipv4/xfrm4_policy.c
@@ -92,6 +92,7 @@ static int xfrm4_fill_dst(struct xfrm_dst *xdst, struct net_device *dev,
xdst->u.rt.rt_type = rt->rt_type;
xdst->u.rt.rt_gateway = rt->rt_gateway;
xdst->u.rt.rt_pmtu = rt->rt_pmtu;
+ INIT_LIST_HEAD(&xdst->u.rt.rt_uncached);
return 0;
}
--
1.7.11.2
^ permalink raw reply related
* [PATCHv2 net 0/3] Prevent extreme TSO parameters from stalling TX queues
From: Ben Hutchings @ 2012-07-31 1:51 UTC (permalink / raw)
To: David Miller
Cc: netdev, linux-net-drivers, Ben Greear, Eric Dumazet,
Stephen Hemminger
The following changes fix a potential DoS by peers or local users on
network interfaces using the sfc driver (and possibly others) with TSO
enabled (as it is by default).
Please apply patches 1 and 2 to the net tree and your stable update
queue. I'm not sure whether patch 3 is really important.
Ben.
Ben Hutchings (3):
net: Allow driver to limit number of GSO segments per skb
sfc: Fix maximum number of TSO segments and minimum TX queue size
tcp: Apply device TSO segment limit earlier
drivers/net/ethernet/sfc/efx.c | 6 ++++++
drivers/net/ethernet/sfc/efx.h | 14 ++++++++++----
drivers/net/ethernet/sfc/ethtool.c | 16 +++++++++++-----
drivers/net/ethernet/sfc/tx.c | 19 +++++++++++++++++++
include/linux/netdevice.h | 2 ++
include/net/sock.h | 2 ++
net/core/dev.c | 4 ++++
net/core/sock.c | 1 +
net/ipv4/tcp.c | 4 +++-
net/ipv4/tcp_cong.c | 3 ++-
net/ipv4/tcp_output.c | 21 ++++++++++++---------
11 files changed, 72 insertions(+), 20 deletions(-)
--
1.7.7.6
--
Ben Hutchings, Staff Engineer, Solarflare
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
* [PATCHv2 net 1/3] net: Allow driver to limit number of GSO segments per skb
From: Ben Hutchings @ 2012-07-31 1:57 UTC (permalink / raw)
To: David Miller
Cc: netdev, linux-net-drivers, Ben Greear, Eric Dumazet,
Stephen Hemminger
In-Reply-To: <1343699476.2667.69.camel@bwh-desktop.uk.solarflarecom.com>
A peer (or local user) may cause TCP to use a nominal MSS of as little
as 88 (actual MSS of 76 with timestamps). Given that we have a
sufficiently prodigious local sender and the peer ACKs quickly enough,
it is nevertheless possible to grow the window for such a connection
to the point that we will try to send just under 64K at once. This
results in a single skb that expands to 861 segments.
In some drivers with TSO support, such an skb will require hundreds of
DMA descriptors; a substantial fraction of a TX ring or even more than
a full ring. The TX queue selected for the skb may stall and trigger
the TX watchdog repeatedly (since the problem skb will be retried
after the TX reset). This particularly affects sfc, for which the
issue is designated as CVE-2012-3412.
Therefore:
1. Add the field net_device::gso_max_segs holding the device-specific
limit.
2. In netif_skb_features(), if the number of segments is too high then
mask out GSO features to force fall back to software GSO.
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
include/linux/netdevice.h | 2 ++
net/core/dev.c | 4 ++++
2 files changed, 6 insertions(+), 0 deletions(-)
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index eb06e58..a9db4f3 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -1300,6 +1300,8 @@ struct net_device {
/* for setting kernel sock attribute on TCP connection setup */
#define GSO_MAX_SIZE 65536
unsigned int gso_max_size;
+#define GSO_MAX_SEGS 65535
+ u16 gso_max_segs;
#ifdef CONFIG_DCB
/* Data Center Bridging netlink ops */
diff --git a/net/core/dev.c b/net/core/dev.c
index 0ebaea1..4020646 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -2133,6 +2133,9 @@ netdev_features_t netif_skb_features(struct sk_buff *skb)
__be16 protocol = skb->protocol;
netdev_features_t features = skb->dev->features;
+ if (skb_shinfo(skb)->gso_segs > skb->dev->gso_max_segs)
+ features &= ~NETIF_F_GSO_MASK;
+
if (protocol == htons(ETH_P_8021Q)) {
struct vlan_ethhdr *veh = (struct vlan_ethhdr *)skb->data;
protocol = veh->h_vlan_encapsulated_proto;
@@ -5942,6 +5945,7 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name,
dev_net_set(dev, &init_net);
dev->gso_max_size = GSO_MAX_SIZE;
+ dev->gso_max_segs = GSO_MAX_SEGS;
INIT_LIST_HEAD(&dev->napi_list);
INIT_LIST_HEAD(&dev->unreg_list);
--
1.7.7.6
--
Ben Hutchings, Staff Engineer, Solarflare
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 related
* [PATCHv2 net 2/3] sfc: Fix maximum number of TSO segments and minimum TX queue size
From: Ben Hutchings @ 2012-07-31 1:57 UTC (permalink / raw)
To: David Miller
Cc: netdev, linux-net-drivers, Ben Greear, Eric Dumazet,
Stephen Hemminger
In-Reply-To: <1343699476.2667.69.camel@bwh-desktop.uk.solarflarecom.com>
Currently an skb requiring TSO may not fit within a minimum-size TX
queue. The TX queue selected for the skb may stall and trigger the TX
watchdog repeatedly (since the problem skb will be retried after the
TX reset). This issue is designated as CVE-2012-3412.
Set the maximum number of TSO segments for our devices to 100. This
should make no difference to behaviour unless the actual MSS is less
than about 700. Increase the minimum TX queue size accordingly to
allow for 2 worst-case skbs, so that there will definitely be space
to add an skb after we wake a queue.
To avoid invalidating existing configurations, change
efx_ethtool_set_ringparam() to fix up values that are too small rather
than returning -EINVAL.
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
drivers/net/ethernet/sfc/efx.c | 6 ++++++
drivers/net/ethernet/sfc/efx.h | 14 ++++++++++----
drivers/net/ethernet/sfc/ethtool.c | 16 +++++++++++-----
drivers/net/ethernet/sfc/tx.c | 19 +++++++++++++++++++
4 files changed, 46 insertions(+), 9 deletions(-)
diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c
index 70554a1..65a8d49 100644
--- a/drivers/net/ethernet/sfc/efx.c
+++ b/drivers/net/ethernet/sfc/efx.c
@@ -1503,6 +1503,11 @@ static int efx_probe_all(struct efx_nic *efx)
goto fail2;
}
+ BUILD_BUG_ON(EFX_DEFAULT_DMAQ_SIZE < EFX_RXQ_MIN_ENT);
+ if (WARN_ON(EFX_DEFAULT_DMAQ_SIZE < EFX_TXQ_MIN_ENT(efx))) {
+ rc = -EINVAL;
+ goto fail3;
+ }
efx->rxq_entries = efx->txq_entries = EFX_DEFAULT_DMAQ_SIZE;
rc = efx_probe_filters(efx);
@@ -2070,6 +2075,7 @@ static int efx_register_netdev(struct efx_nic *efx)
net_dev->irq = efx->pci_dev->irq;
net_dev->netdev_ops = &efx_netdev_ops;
SET_ETHTOOL_OPS(net_dev, &efx_ethtool_ops);
+ net_dev->gso_max_segs = EFX_TSO_MAX_SEGS;
rtnl_lock();
diff --git a/drivers/net/ethernet/sfc/efx.h b/drivers/net/ethernet/sfc/efx.h
index be8f915..70755c9 100644
--- a/drivers/net/ethernet/sfc/efx.h
+++ b/drivers/net/ethernet/sfc/efx.h
@@ -30,6 +30,7 @@ extern netdev_tx_t
efx_enqueue_skb(struct efx_tx_queue *tx_queue, struct sk_buff *skb);
extern void efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index);
extern int efx_setup_tc(struct net_device *net_dev, u8 num_tc);
+extern unsigned int efx_tx_max_skb_descs(struct efx_nic *efx);
/* RX */
extern int efx_probe_rx_queue(struct efx_rx_queue *rx_queue);
@@ -52,10 +53,15 @@ extern void efx_schedule_slow_fill(struct efx_rx_queue *rx_queue);
#define EFX_MAX_EVQ_SIZE 16384UL
#define EFX_MIN_EVQ_SIZE 512UL
-/* The smallest [rt]xq_entries that the driver supports. Callers of
- * efx_wake_queue() assume that they can subsequently send at least one
- * skb. Falcon/A1 may require up to three descriptors per skb_frag. */
-#define EFX_MIN_RING_SIZE (roundup_pow_of_two(2 * 3 * MAX_SKB_FRAGS))
+/* Maximum number of TCP segments we support for soft-TSO */
+#define EFX_TSO_MAX_SEGS 100
+
+/* The smallest [rt]xq_entries that the driver supports. RX minimum
+ * is a bit arbitrary. For TX, we must have space for at least 2
+ * TSO skbs.
+ */
+#define EFX_RXQ_MIN_ENT 128U
+#define EFX_TXQ_MIN_ENT(efx) (2 * efx_tx_max_skb_descs(efx))
/* Filters */
extern int efx_probe_filters(struct efx_nic *efx);
diff --git a/drivers/net/ethernet/sfc/ethtool.c b/drivers/net/ethernet/sfc/ethtool.c
index 10536f9..8cba2df 100644
--- a/drivers/net/ethernet/sfc/ethtool.c
+++ b/drivers/net/ethernet/sfc/ethtool.c
@@ -680,21 +680,27 @@ static int efx_ethtool_set_ringparam(struct net_device *net_dev,
struct ethtool_ringparam *ring)
{
struct efx_nic *efx = netdev_priv(net_dev);
+ u32 txq_entries;
if (ring->rx_mini_pending || ring->rx_jumbo_pending ||
ring->rx_pending > EFX_MAX_DMAQ_SIZE ||
ring->tx_pending > EFX_MAX_DMAQ_SIZE)
return -EINVAL;
- if (ring->rx_pending < EFX_MIN_RING_SIZE ||
- ring->tx_pending < EFX_MIN_RING_SIZE) {
+ if (ring->rx_pending < EFX_RXQ_MIN_ENT) {
netif_err(efx, drv, efx->net_dev,
- "TX and RX queues cannot be smaller than %ld\n",
- EFX_MIN_RING_SIZE);
+ "RX queues cannot be smaller than %u\n",
+ EFX_RXQ_MIN_ENT);
return -EINVAL;
}
- return efx_realloc_channels(efx, ring->rx_pending, ring->tx_pending);
+ txq_entries = max(ring->tx_pending, EFX_TXQ_MIN_ENT(efx));
+ if (txq_entries != ring->tx_pending)
+ netif_warn(efx, drv, efx->net_dev,
+ "increasing TX queue size to minimum of %u\n",
+ txq_entries);
+
+ return efx_realloc_channels(efx, ring->rx_pending, txq_entries);
}
static int efx_ethtool_set_pauseparam(struct net_device *net_dev,
diff --git a/drivers/net/ethernet/sfc/tx.c b/drivers/net/ethernet/sfc/tx.c
index 9b225a7..1871343 100644
--- a/drivers/net/ethernet/sfc/tx.c
+++ b/drivers/net/ethernet/sfc/tx.c
@@ -119,6 +119,25 @@ efx_max_tx_len(struct efx_nic *efx, dma_addr_t dma_addr)
return len;
}
+unsigned int efx_tx_max_skb_descs(struct efx_nic *efx)
+{
+ /* Header and payload descriptor for each output segment, plus
+ * one for every input fragment boundary within a segment
+ */
+ unsigned int max_descs = EFX_TSO_MAX_SEGS * 2 + MAX_SKB_FRAGS;
+
+ /* Possibly one more per segment for the alignment workaround */
+ if (EFX_WORKAROUND_5391(efx))
+ max_descs += EFX_TSO_MAX_SEGS;
+
+ /* Possibly more for PCIe page boundaries within input fragments */
+ if (PAGE_SIZE > EFX_PAGE_SIZE)
+ max_descs += max_t(unsigned int, MAX_SKB_FRAGS,
+ DIV_ROUND_UP(GSO_MAX_SIZE, EFX_PAGE_SIZE));
+
+ return max_descs;
+}
+
/*
* Add a socket buffer to a TX queue
*
--
1.7.7.6
--
Ben Hutchings, Staff Engineer, Solarflare
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 related
* [PATCHv2 net 3/3] tcp: Apply device TSO segment limit earlier
From: Ben Hutchings @ 2012-07-31 2:11 UTC (permalink / raw)
To: David Miller
Cc: netdev, linux-net-drivers, Ben Greear, Eric Dumazet,
Stephen Hemminger
In-Reply-To: <1343699476.2667.69.camel@bwh-desktop.uk.solarflarecom.com>
Cache the device gso_max_segs in sock::sk_gso_max_segs and use it to
limit the size of TSO skbs. This avoids the need to fall back to
software GSO for local TCP senders.
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
This is similar to v1 patch 1, but using the device's gso_max_segs
instead of a constant. It also covers a couple of additional cases
where sk_gso_max_size is currently used. It improves performance in the
case that the limit is reached, but this may not be worth doing if
legitimate peers don't cause us to hit that limit.
Ben.
include/net/sock.h | 2 ++
net/core/sock.c | 1 +
net/ipv4/tcp.c | 4 +++-
net/ipv4/tcp_cong.c | 3 ++-
net/ipv4/tcp_output.c | 21 ++++++++++++---------
5 files changed, 20 insertions(+), 11 deletions(-)
diff --git a/include/net/sock.h b/include/net/sock.h
index e067f8c..25a823a 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -218,6 +218,7 @@ struct cg_proto;
* @sk_route_nocaps: forbidden route capabilities (e.g NETIF_F_GSO_MASK)
* @sk_gso_type: GSO type (e.g. %SKB_GSO_TCPV4)
* @sk_gso_max_size: Maximum GSO segment size to build
+ * @sk_gso_max_segs: Maximum number of GSO segments
* @sk_lingertime: %SO_LINGER l_linger setting
* @sk_backlog: always used with the per-socket spinlock held
* @sk_callback_lock: used with the callbacks in the end of this struct
@@ -338,6 +339,7 @@ struct sock {
netdev_features_t sk_route_nocaps;
int sk_gso_type;
unsigned int sk_gso_max_size;
+ u16 sk_gso_max_segs;
int sk_rcvlowat;
unsigned long sk_lingertime;
struct sk_buff_head sk_error_queue;
diff --git a/net/core/sock.c b/net/core/sock.c
index 2676a88..34cc7bb 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -1403,6 +1403,7 @@ void sk_setup_caps(struct sock *sk, struct dst_entry *dst)
} else {
sk->sk_route_caps |= NETIF_F_SG | NETIF_F_HW_CSUM;
sk->sk_gso_max_size = dst->dev->gso_max_size;
+ sk->sk_gso_max_segs = dst->dev->gso_max_segs;
}
}
}
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index e7e6eea..2109ff4 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -811,7 +811,9 @@ static unsigned int tcp_xmit_size_goal(struct sock *sk, u32 mss_now,
old_size_goal + mss_now > xmit_size_goal)) {
xmit_size_goal = old_size_goal;
} else {
- tp->xmit_size_goal_segs = xmit_size_goal / mss_now;
+ tp->xmit_size_goal_segs =
+ min_t(u16, xmit_size_goal / mss_now,
+ sk->sk_gso_max_segs);
xmit_size_goal = tp->xmit_size_goal_segs * mss_now;
}
}
diff --git a/net/ipv4/tcp_cong.c b/net/ipv4/tcp_cong.c
index 4d4db16..1432cdb 100644
--- a/net/ipv4/tcp_cong.c
+++ b/net/ipv4/tcp_cong.c
@@ -291,7 +291,8 @@ bool tcp_is_cwnd_limited(const struct sock *sk, u32 in_flight)
left = tp->snd_cwnd - in_flight;
if (sk_can_gso(sk) &&
left * sysctl_tcp_tso_win_divisor < tp->snd_cwnd &&
- left * tp->mss_cache < sk->sk_gso_max_size)
+ left * tp->mss_cache < sk->sk_gso_max_size &&
+ left < sk->sk_gso_max_segs)
return true;
return left <= tcp_max_tso_deferred_mss(tp);
}
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index 33cd065..0c9db8f 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -1522,21 +1522,21 @@ static void tcp_cwnd_validate(struct sock *sk)
* when we would be allowed to send the split-due-to-Nagle skb fully.
*/
static unsigned int tcp_mss_split_point(const struct sock *sk, const struct sk_buff *skb,
- unsigned int mss_now, unsigned int cwnd)
+ unsigned int mss_now, unsigned int max_segs)
{
const struct tcp_sock *tp = tcp_sk(sk);
- u32 needed, window, cwnd_len;
+ u32 needed, window, max_len;
window = tcp_wnd_end(tp) - TCP_SKB_CB(skb)->seq;
- cwnd_len = mss_now * cwnd;
+ max_len = mss_now * max_segs;
- if (likely(cwnd_len <= window && skb != tcp_write_queue_tail(sk)))
- return cwnd_len;
+ if (likely(max_len <= window && skb != tcp_write_queue_tail(sk)))
+ return max_len;
needed = min(skb->len, window);
- if (cwnd_len <= needed)
- return cwnd_len;
+ if (max_len <= needed)
+ return max_len;
return needed - needed % mss_now;
}
@@ -1765,7 +1765,8 @@ static bool tcp_tso_should_defer(struct sock *sk, struct sk_buff *skb)
limit = min(send_win, cong_win);
/* If a full-sized TSO skb can be sent, do it. */
- if (limit >= sk->sk_gso_max_size)
+ if (limit >= min_t(unsigned int, sk->sk_gso_max_size,
+ sk->sk_gso_max_segs * tp->mss_cache))
goto send_now;
/* Middle in queue won't get any more data, full sendable already? */
@@ -1999,7 +2000,9 @@ static bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle,
limit = mss_now;
if (tso_segs > 1 && !tcp_urg_mode(tp))
limit = tcp_mss_split_point(sk, skb, mss_now,
- cwnd_quota);
+ min_t(unsigned int,
+ cwnd_quota,
+ sk->sk_gso_max_segs));
if (skb->len > limit &&
unlikely(tso_fragment(sk, skb, limit, mss_now, gfp)))
--
1.7.7.6
--
Ben Hutchings, Staff Engineer, Solarflare
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 related
* Re: [RFC v2 1/2] PCI-Express Non-Transparent Bridge Support
From: Jianbin Kang @ 2012-07-31 3:35 UTC (permalink / raw)
To: Jon Mason; +Cc: Bjorn Helgaas, linux-kernel, netdev, linux-pci, Dave Jiang
In-Reply-To: <20120730181542.GA987@jonmason-lab>
> I've tried to make it all generic enough that non-Intel NTBs should plug in with
> minimal changes to ntb_hw.c. If their design is too divergent, then a slight
> redesign of ntb_hw.c might be necessary. But from what I've seen of other
> designs on the internet, they appear to be extremely similar. The transport and
> client drivers were written with the hardware abstracted away as much as
> possible to prevent the need to modify it for different hardware. If there is
> anything which is Intel hardware specific, I'd be happy to change it to make it
> more generic.
In ntb_process_tx(), ntb uses hard-coding 'memcpy_toio' to copy data
to remote.
Is it better to provide a function pointer like 'tx()' and call qp->tx().
memcpy_toio is a slow operation. Some hardware can setup a dma
transfer and wait.
IMHO, the best way is to handle tx in async mode. But it requires
lots of modification.
^ 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