* [PATCH net-next 3/3] Add capability to retrieve plug-in module EEPROM
From: Stuart Hodgson @ 2012-04-19 15:39 UTC (permalink / raw)
To: netdev
Cc: Ben Hutchings, bruce.w.allan, decot, alexander.h.duyck, davem,
linux-kernel
Currently allows for SFP+ eeprom to be returned using the ethtool API.
This can be extended in future to handle different eeprom formats
and sizes
Signed-off-by: Stuart Hodgson <smhodgson@solarflare.com>
---
drivers/net/ethernet/sfc/ethtool.c | 35 ++++++++++
drivers/net/ethernet/sfc/mcdi_phy.c | 111 +++++++++++++++++++++++++++++++++
drivers/net/ethernet/sfc/net_driver.h | 5 ++
3 files changed, 151 insertions(+), 0 deletions(-)
diff --git a/drivers/net/ethernet/sfc/ethtool.c b/drivers/net/ethernet/sfc/ethtool.c
index f22f45f..60e718f 100644
--- a/drivers/net/ethernet/sfc/ethtool.c
+++ b/drivers/net/ethernet/sfc/ethtool.c
@@ -1108,6 +1108,39 @@ static int efx_ethtool_set_rxfh_indir(struct net_device *net_dev,
return 0;
}
+static int efx_ethtool_get_module_eeprom(struct net_device *net_dev,
+ struct ethtool_eeprom *ee,
+ u8 *data)
+{
+ struct efx_nic *efx = netdev_priv(net_dev);
+ int ret;
+
+ if (!efx->phy_op || !efx->phy_op->get_module_eeprom)
+ return -EOPNOTSUPP;
+
+ mutex_lock(&efx->mac_lock);
+ ret = efx->phy_op->get_module_eeprom(efx, ee, data);
+ mutex_unlock(&efx->mac_lock);
+
+ return ret;
+}
+
+static int efx_ethtool_get_module_info(struct net_device *net_dev,
+ struct ethtool_modinfo *modinfo)
+{
+ struct efx_nic *efx = netdev_priv(net_dev);
+ int ret;
+
+ if (!efx->phy_op || !efx->phy_op->get_module_info)
+ return 0;
+
+ mutex_lock(&efx->mac_lock);
+ ret = efx->phy_op->get_module_info(efx, modinfo);
+ mutex_unlock(&efx->mac_lock);
+
+ return ret;
+}
+
const struct ethtool_ops efx_ethtool_ops = {
.get_settings = efx_ethtool_get_settings,
.set_settings = efx_ethtool_set_settings,
@@ -1137,4 +1170,6 @@ const struct ethtool_ops efx_ethtool_ops = {
.get_rxfh_indir_size = efx_ethtool_get_rxfh_indir_size,
.get_rxfh_indir = efx_ethtool_get_rxfh_indir,
.set_rxfh_indir = efx_ethtool_set_rxfh_indir,
+ .get_module_info = efx_ethtool_get_module_info,
+ .get_module_eeprom = efx_ethtool_get_module_eeprom,
};
diff --git a/drivers/net/ethernet/sfc/mcdi_phy.c b/drivers/net/ethernet/sfc/mcdi_phy.c
index 7bcad89..4bac56c 100644
--- a/drivers/net/ethernet/sfc/mcdi_phy.c
+++ b/drivers/net/ethernet/sfc/mcdi_phy.c
@@ -304,6 +304,26 @@ static u32 mcdi_to_ethtool_media(u32 media)
}
}
+static u32 mcdi_to_module_eeprom_len(u32 media)
+{
+ switch (media) {
+ case MC_CMD_MEDIA_SFP_PLUS:
+ return ETH_MODULE_SFF_8079_LEN;
+ default:
+ return 0;
+ }
+}
+
+static u32 mcdi_to_module_eeprom_type(u32 media)
+{
+ switch (media) {
+ case MC_CMD_MEDIA_SFP_PLUS:
+ return ETH_MODULE_SFF_8079;
+ default:
+ return 0;
+ }
+}
+
static int efx_mcdi_phy_probe(struct efx_nic *efx)
{
struct efx_mcdi_phy_data *phy_data;
@@ -739,6 +759,95 @@ static const char *efx_mcdi_phy_test_name(struct efx_nic *efx,
return NULL;
}
+#define SFP_PAGE_SIZE 128
+#define SFP_NUM_PAGES 2
+static int efx_mcdi_phy_get_module_eeprom(struct efx_nic *efx,
+ struct ethtool_eeprom *ee, u8 *data)
+{
+ u8 outbuf[MC_CMD_GET_PHY_MEDIA_INFO_OUT_LENMAX];
+ u8 inbuf[MC_CMD_GET_PHY_MEDIA_INFO_IN_LEN];
+ size_t outlen;
+ int rc;
+ unsigned int payload_len;
+ unsigned int copied = 0;
+ unsigned int space_remaining = ee->len;
+ unsigned int page;
+ unsigned int page_off;
+ unsigned int to_copy;
+ u8 *user_data = data;
+
+ if (ee->offset > (SFP_PAGE_SIZE * SFP_NUM_PAGES))
+ return -EINVAL;
+
+ page_off = (ee->offset % SFP_PAGE_SIZE);
+ page = (ee->offset > SFP_PAGE_SIZE) ? 1 : 0;
+
+ while (space_remaining && (page < SFP_NUM_PAGES)) {
+
+ MCDI_SET_DWORD(inbuf, GET_PHY_MEDIA_INFO_IN_PAGE, page);
+
+ rc = efx_mcdi_rpc(efx, MC_CMD_GET_PHY_MEDIA_INFO,
+ inbuf, sizeof(inbuf),
+ outbuf, sizeof(outbuf),
+ &outlen);
+
+ if (rc)
+ return rc;
+
+ /* Copy as much as we can into data */
+ if (outlen < SFP_PAGE_SIZE ||
+ outlen < MC_CMD_GET_PHY_MEDIA_INFO_OUT_LENMIN ||
+ outlen > MC_CMD_GET_PHY_MEDIA_INFO_OUT_LENMAX)
+ return -EIO;
+
+ payload_len = MCDI_DWORD(outbuf,
+ GET_PHY_MEDIA_INFO_OUT_DATALEN);
+
+ payload_len -= page_off;
+ to_copy = (space_remaining < payload_len) ?
+ space_remaining : payload_len;
+
+ memcpy(user_data,
+ (outbuf + page_off +
+ MC_CMD_GET_PHY_MEDIA_INFO_OUT_DATA_OFST),
+ to_copy);
+
+ space_remaining -= to_copy;
+ user_data += to_copy;
+ copied += to_copy;
+ page_off = 0;
+ page++;
+ }
+
+ ee->len = copied;
+
+ return 0;
+}
+
+static int efx_mcdi_phy_get_module_info(struct efx_nic *efx,
+ struct ethtool_modinfo *modinfo)
+{
+ /* This will return a length of the eeprom
+ * type of the module that was detected during the probe,
+ * if not modules inserted then phy_data will be NULL */
+ struct efx_mcdi_phy_data *phy_cfg;
+
+ phy_cfg = efx->phy_data;
+ modinfo->eeprom_len = 0;
+ modinfo->type = 0;
+
+ switch (phy_cfg->media) {
+ case MC_CMD_MEDIA_SFP_PLUS:
+ modinfo->type = ETH_MODULE_SFF_8079;
+ modinfo->eeprom_len = ETH_MODULE_SFF_8079_LEN;
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
const struct efx_phy_operations efx_mcdi_phy_ops = {
.probe = efx_mcdi_phy_probe,
.init = efx_port_dummy_op_int,
@@ -751,4 +860,6 @@ const struct efx_phy_operations efx_mcdi_phy_ops = {
.test_alive = efx_mcdi_phy_test_alive,
.run_tests = efx_mcdi_phy_run_tests,
.test_name = efx_mcdi_phy_test_name,
+ .get_module_eeprom = efx_mcdi_phy_get_module_eeprom,
+ .get_module_info = efx_mcdi_phy_get_module_info,
};
diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h
index f0385e1..0af8c47 100644
--- a/drivers/net/ethernet/sfc/net_driver.h
+++ b/drivers/net/ethernet/sfc/net_driver.h
@@ -522,6 +522,11 @@ struct efx_phy_operations {
int (*test_alive) (struct efx_nic *efx);
const char *(*test_name) (struct efx_nic *efx, unsigned int index);
int (*run_tests) (struct efx_nic *efx, int *results, unsigned flags);
+ int (*get_module_eeprom) (struct efx_nic *efx,
+ struct ethtool_eeprom *ee,
+ u8 *data);
+ int (*get_module_info) (struct efx_nic *efx,
+ struct ethtool_modinfo *modinfo);
};
/**
--
1.7.1
^ permalink raw reply related
* [PATCH net-next 1/3] Add capability to retrieve plug-in module EEPROM
From: Stuart Hodgson @ 2012-04-19 15:39 UTC (permalink / raw)
To: netdev
Cc: Ben Hutchings, bruce.w.allan, decot, alexander.h.duyck, davem,
linux-kernel
We want to support reading module (SFP+, XFP, ...) EEPROMs as well as
NIC EEPROMs. They will need a different command number and driver
operation, but the structure and arguments will be the same and so we
can share most of the code here.
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
Signed-off-by: Stuart Hodgson <smhodgson@solarflare.com>
---
net/core/ethtool.c | 24 +++++++++++++++++-------
1 files changed, 17 insertions(+), 7 deletions(-)
diff --git a/net/core/ethtool.c b/net/core/ethtool.c
index beacdd9..ca7698f 100644
--- a/net/core/ethtool.c
+++ b/net/core/ethtool.c
@@ -751,18 +751,17 @@ static int ethtool_get_link(struct net_device *dev, char __user *useraddr)
return 0;
}
-static int ethtool_get_eeprom(struct net_device *dev, void __user *useraddr)
+static int ethtool_get_any_eeprom(struct net_device *dev, void __user *useraddr,
+ int (*getter)(struct net_device *,
+ struct ethtool_eeprom *, u8 *),
+ u32 total_len)
{
struct ethtool_eeprom eeprom;
- const struct ethtool_ops *ops = dev->ethtool_ops;
void __user *userbuf = useraddr + sizeof(eeprom);
u32 bytes_remaining;
u8 *data;
int ret = 0;
- if (!ops->get_eeprom || !ops->get_eeprom_len)
- return -EOPNOTSUPP;
-
if (copy_from_user(&eeprom, useraddr, sizeof(eeprom)))
return -EFAULT;
@@ -771,7 +770,7 @@ static int ethtool_get_eeprom(struct net_device *dev, void __user *useraddr)
return -EINVAL;
/* Check for exceeding total eeprom len */
- if (eeprom.offset + eeprom.len > ops->get_eeprom_len(dev))
+ if (eeprom.offset + eeprom.len > total_len)
return -EINVAL;
data = kmalloc(PAGE_SIZE, GFP_USER);
@@ -782,7 +781,7 @@ static int ethtool_get_eeprom(struct net_device *dev, void __user *useraddr)
while (bytes_remaining > 0) {
eeprom.len = min(bytes_remaining, (u32)PAGE_SIZE);
- ret = ops->get_eeprom(dev, &eeprom, data);
+ ret = getter(dev, &eeprom, data);
if (ret)
break;
if (copy_to_user(userbuf, data, eeprom.len)) {
@@ -803,6 +802,17 @@ static int ethtool_get_eeprom(struct net_device *dev, void __user *useraddr)
return ret;
}
+static int ethtool_get_eeprom(struct net_device *dev, void __user *useraddr)
+{
+ const struct ethtool_ops *ops = dev->ethtool_ops;
+
+ if (!ops->get_eeprom || !ops->get_eeprom_len)
+ return -EOPNOTSUPP;
+
+ return ethtool_get_any_eeprom(dev, useraddr, ops->get_eeprom,
+ ops->get_eeprom_len(dev));
+}
+
static int ethtool_set_eeprom(struct net_device *dev, void __user *useraddr)
{
struct ethtool_eeprom eeprom;
--
1.7.1
^ permalink raw reply related
* Re: [net-next 1/4 (V3)] net: ethtool: add the EEE support
From: Ben Hutchings @ 2012-04-19 15:30 UTC (permalink / raw)
To: Giuseppe CAVALLARO; +Cc: netdev, rayagond, davem
In-Reply-To: <4F900C08.5000906@st.com>
On Thu, 2012-04-19 at 14:58 +0200, Giuseppe CAVALLARO wrote:
> Hello Ben,
>
> On 4/16/2012 7:41 AM, Giuseppe CAVALLARO wrote:
> [snip]
> >> What I meant is that userland should be able to find out (a), and,
> >> *separately*, either (b) or (c). That is, there must be at least 2
> >> separate flags for this. In fact, I explicitly requested you define
> >> supported/advertising/lp_advertising bitmasks for EEE link modes just
> >> like we have for autonegotiation. But you've made no substantive
> >> changes in response to my review, aside from dropping the added field in
> >> ethtool_cmd.
> >
> > Sorry Ben but I believed that (c) was enough.
> >
> >> What you're submitting just isn't good enough for a generic interface,
> >> as the ethtool API is supposed to be. It's not even a good interface to
> >> your driver.
> >
> > yes! I'll rework this and provide new patches asap.
>
> sorry if I disturb you but I want to be sure to avoid to forget
> something else in the next EEE patches (avoiding to continuously disturb
> you).
>
> I'm changing the code for getting/setting the EEE capability and trying
> to follow your suggestions.
>
> The "get" will show the following things; this is a bit different of the
> points "a" "b" and "c" we had discussed. Maybe, this could also be a
> more complete (*) .
> The ethtool (see output below as example) could report the phy
> (supported/advertised/lp_advertised) and mac eee capabilities separately.
Sounds reasonable.
> The "set" will be useful for some eth devices (like the stmmac) that can
> stop/enable internally the eee capability (at mac level).
I don't know much about EEE, but shouldn't the driver take care of
configuring the MAC for this whenever the PHY is set to advertise EEE
capability?
> What do you think?
>
> Regards
> Peppe
>
> ----
>
> # ./ethtool eth0
> Settings for eth0:
>
> [snip]
>
> Current message level: 0x0000003f (63)
> drv probe link timer ifdown ifup
> Link detected: yes
> Energy-Efficient Ethernet: -------------------------
> MAC supports: yes |-> related to MAC side |
> phy supports modes: ... |-> from MMD 3.20 |
> phy advertising modes: ... |-> from MMD 7.60 |
> LP advertising modes: ... |-> from MMD 7.61 |
> --------------------------
> (*)
> PS. The "..." above means that we can actually dump: 100BASE-TX EEE etc
> for each advertising modes and also for phy support (reg 3.20).
Yes, that's the sort of information I would expect to see (but try to be
consistent with the wording used for AN).
The EEE advertising mask presumably should be changeable similarly to
the AN advertising mask ('ethtool -s <devname> eeeadv <mask>'). But I
don't know how the two advertising masks interact. Is one supposed to
be a subset of the other? Currently ethtool automatically changes the
AN advertising mask in response to a speed/duplex change; should it also
try to change the EEE advertising mask?
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: filter: Just In Time compiler for sparc
From: Sam Ravnborg @ 2012-04-19 15:29 UTC (permalink / raw)
To: David Miller; +Cc: netdev, sparclinux
In-Reply-To: <20120417.164400.89608576188768018.davem@davemloft.net>
>
> >> + select HAVE_BPF_JIT
> > If we sorted this block of select then the chances
> > for merge conflict would be smaller.
> > But this is not this patch to do so.
>
> I also think we should create an arch/sparc/Kbuild for sparc
> too, just like x86 has.
I will look into both issues.
But only after the merge window to avoid conflicts.
Sam
^ permalink raw reply
* Re: [PATCH 1/2] workqueue: Catch more locking problems with flush_work()
From: Tejun Heo @ 2012-04-19 15:28 UTC (permalink / raw)
To: Stephen Boyd; +Cc: linux-kernel, netdev, Ben Dooks
In-Reply-To: <1334805958-29119-1-git-send-email-sboyd@codeaurora.org>
On Wed, Apr 18, 2012 at 08:25:57PM -0700, Stephen Boyd wrote:
> @@ -2513,8 +2513,11 @@ bool flush_work(struct work_struct *work)
> wait_for_completion(&barr.done);
> destroy_work_on_stack(&barr.work);
> return true;
> - } else
> + } else {
> + lock_map_acquire(&work->lockdep_map);
> + lock_map_release(&work->lockdep_map);
> return false;
We don't have this annotation when start_flush_work() succeeds either,
right? IOW, would lockdep trigger when an actual deadlock happens?
If not, why not add the acquire/release() before flush_work() does
anything?
Thanks.
--
tejun
^ permalink raw reply
* RE: [PATCH] net/hyperv: Adding cancellation to ensure rndis filter is closed
From: Haiyang Zhang @ 2012-04-19 15:18 UTC (permalink / raw)
To: Wenqi Ma, netdev@vger.kernel.org; +Cc: davem@davemloft.net, KY Srinivasan
In-Reply-To: <1334831977-5553-1-git-send-email-wenqi_ma@trendmicro.com.cn>
> -----Original Message-----
> From: Wenqi Ma [mailto:wenqi_ma@trendmicro.com.cn]
> Sent: Thursday, April 19, 2012 6:40 AM
> To: netdev@vger.kernel.org
> Cc: davem@davemloft.net; Haiyang Zhang; Wenqi Ma
> Subject: [PATCH] net/hyperv: Adding cancellation to ensure rndis filter is
> closed
>
> Although the network interface is down, the RX packets number which
> could be observed by ifconfig may keep on increasing.
>
> This is because the WORK scheduled in netvsc_set_multicast_list()
> may be executed after netvsc_close(). That means the rndis filter
> may be re-enabled by do_set_multicast() even if it was closed by
> netvsc_close().
>
> By canceling possible WORK before close the rndis filter, the issue
> could be never happened.
>
> Signed-off-by: Wenqi Ma <wenqi_ma@trendmicro.com.cn>
> Reviewed-by: Wei Yongjun <yongjun_wei@trendmicro.com.cn>
> ---
> drivers/net/hyperv/netvsc_drv.c | 38 ++++++++++++++--------------------
> ----
> 1 files changed, 14 insertions(+), 24 deletions(-)
Thank you for the patch.
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
^ permalink raw reply
* Re: [net-next 1/4 (V3)] net: ethtool: add the EEE support
From: Ben Hutchings @ 2012-04-19 15:14 UTC (permalink / raw)
To: Yuval Mintz
Cc: Giuseppe CAVALLARO, netdev@vger.kernel.org,
rayagond@vayavyalabs.com, davem@davemloft.net
In-Reply-To: <4F9017C6.8070400@broadcom.com>
On Thu, 2012-04-19 at 16:48 +0300, Yuval Mintz wrote:
> Hi Peppe,
>
> > The "set" will be useful for some eth devices (like the stmmac) that can
> > stop/enable internally the eee capability (at mac level).
>
> If you're already implementing this interface, don't you think it might be
> prudent to create an implementation that can do more than enable/disable
> the interface?
[...]
It's not necessary for anyone to *implement* all of this now, but the
interface should certainly cover any settings that users may reasonably
want to read and configure. As with most ethtool 'set' operations, any
implementation (driver) can disallow changing any or all settings
(-EOPNOTSUPP or -EINVAL) if it's difficult or impossible to implement
them.
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: NULL pointer dereference at __ip_route_output_key
From: Yevgen Pronenko @ 2012-04-19 14:58 UTC (permalink / raw)
To: netdev
Hello David,
> 2798 of net/ipv4/route.c:
>
>> dev_out = FIB_RES_DEV(res);
>> fl4->flowi4_oif = dev_out->ifindex;
>
> and we are thus OOPS'ing on the dev_out->ifindex.
>
> Unfortunately I've never seen a report like this. If the reporter
> can reproduce, you can try to extract more information by doing
> something like this right after the dev_out assignment:
I observed a crash in exactly the same place recently.
wlan: disconnected
Unable to handle kernel NULL pointer dereference at virtual address 00000070
cfg80211: Calling CRDA to update world regulatory domain
pgd = d67a4000
[00000070] *pgd=9f144831, *pte=00000000, *ppte=00000000
Internal error: Oops: 17 [#1] PREEMPT SMP
Modules linked in: wlan(P) cfg80211 [last unloaded: wlan]
CPU: 0 Tainted: P W (3.0.8+1.0.21100-01783-gb40b976 #1)
PC is at __ip_route_output_key+0x49c/0x78c
LR is at fib_rules_lookup+0x16c/0x174
pc : [<c05fb848>] lr : [<c05bcaf4>] psr: 60000013
sp : d6899bb0 ip : d6899bc4 fp : 00000000
r10: 00000000 r9 : 00000000 r8 : 479047c2
r7 : 00000000 r6 : 00000000 r5 : d6899bc4 r4 : d6899c64
r3 : cdc04600 r2 : 0415c05e r1 : cdc04600 r0 : fa2410ac
Flags: nZCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment user
Control: 10c5787d Table: 9daa406a DAC: 00000015
...
[<c05fb848>] (__ip_route_output_key+0x49c/0x78c) from [<c05fbb4c>]
(ip_route_output_flow+0x14/0x50)
[<c05fbb4c>] (ip_route_output_flow+0x14/0x50) from [<c0623ff0>]
(udp_sendmsg+0x358/0x72c)
[<c0623ff0>] (udp_sendmsg+0x358/0x72c) from [<c06701b4>]
(udpv6_sendmsg+0x154/0x8d8)
[<c06701b4>] (udpv6_sendmsg+0x154/0x8d8) from [<c062b8a0>]
(inet_sendmsg+0xac/0xb4)
[<c062b8a0>] (inet_sendmsg+0xac/0xb4) from [<c0597ed4>]
(sock_sendmsg+0xa0/0xbc)
[<c0597ed4>] (sock_sendmsg+0xa0/0xbc) from [<c05985ec>]
(sys_sendto+0xbc/0xfc)
[<c05985ec>] (sys_sendto+0xbc/0xfc) from [<c0105e60>]
(ret_fast_syscall+0x0/0x30)
Analyzing the dump I found that FIB_RES_DEV(res) macros in the line
mentioned above returned NULL.
I was able to dump a content of related structures in memory:
res: struct fib_result {
prefixlen = 0 '\000',
nh_sel = 0 '\000',
type = 1 '\001',
scope = 0 '\000',
struct fib_info *fi = 0xcdc04600
-> {
fib_hash = {
next = 0x100100,
pprev = 0x200200
},
fib_lhash = {
next = 0x0,
pprev = 0x0
},
fib_net = 0xc0da8000,
fib_treeref = 0,
fib_clntref = {
counter = 0
},
fib_flags = 0,
fib_dead = 1 '\001',
fib_protocol = 3 '\003',
fib_scope = 0 '\000',
fib_prefsrc = 0,
fib_priority = 314,
fib_metrics = 0xc0da88a0,
fib_nhs = 1,
rcu = {
next = 0xc9df30e8,
func = 0x34
},
fib_nh = 0xcdc0463c
}
struct fib_table *table = 0xd88684c0
-> {
tb_hlist = {
next = 0x0,
pprev = 0xd9ab5bf8
},
tb_id = 254,
tb_default = -1,
tb_num_default = 1,
tb_data = 0xd88684d4
}
struct list_head *fa_head = 0xd7e13554
-> {
next = 0xd7e13554,
prev = 0xd7e13554
}
struct fib_rule *r = 0xd7e05300
-> {
list = {
next = 0xd7e05780,
prev = 0xd9b13500
},
refcnt = {
counter = 1
},
iifindex = 0,
oifindex = 0,
mark = 0,
mark_mask = 0,
pref = 32766,
flags = 0,
table = 254,
action = 1 '\001',
target = 0,
ctarget = 0x0,
iifname =
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000",
oifname =
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000",
rcu = {
next = 0x0,
func = 0
},
fr_net = 0xc0da8000
}
}
Here is the content of res.fi->fib_nh:
struct fib_nh {
nh_dev = 0x0,
nh_hash = {
next = 0x100100,
pprev = 0x200200
},
nh_parent = 0xcdc04600,
nh_flags = 0,
nh_scope = 253 '\375',
nh_oif = 14,
nh_gw = 18878636,
nh_saddr = 4196667564,
nh_saddr_genid = 68534366
}
As you can see, there is a NULL in res.fi->fib_nh.nh_dev. One more thing
which looks suspicious for me is that res.fi->fib_dead is 1 here. And
the crash happened just after shutting down a WLAN interface (the last
string in the kernel log was "wlan: disconnected").
Having that, is it possible there is a race between network resources
deallocation and a route lookup procedure?
The crash was observed only once and I am not able to reproduce it, but
I have a crash dump, so I can grep it for additional information (kernel
logs, values of variables, etc).
Here is the basic information about the system:
RELEASE: 3.0.8+1.0.21100-01783-gb40b976
VERSION: #1 SMP PREEMPT Thu Apr 12 06:19:58 2012
MACHINE: armv7l (unknown Mhz)
Yevgen Pronenko.
^ permalink raw reply
* Re: RTM_NEWLINK not received by application when connecting multiple devices simultaneously
From: Kristian Evensen @ 2012-04-19 15:07 UTC (permalink / raw)
To: Stephen Hemminger; +Cc: Ben Greear, netdev
In-Reply-To: <20120419075452.379f711b@s6510.linuxnetplumber.net>
Thank you very much for both your replies.
>>
>> Multiple netlink msgs can be received in each read of a netlink
>> socket. Maybe you are only processing the first one?
Yes, my code does this. I also some debug output for the test
"nlmsg_flags & NLM_F_MULTI", but it never evaluates to true.
> I recommend using the libmnl library instead of the older
> libnetlink. The code is cleaner and it handles error cases better.
> In libmnl there is a callback interface for parsing
> netlink messages.
Thank you for the tip, I will try this as it will make my code much cleaner.
Btw, I hadnt paid attention the age of the package I used. However,
upgrading to the latest available in the Debian repository (20120319)
does not have an effect.
-Kristian
^ permalink raw reply
* Re: RTM_NEWLINK not received by application when connecting multiple devices simultaneously
From: Stephen Hemminger @ 2012-04-19 14:54 UTC (permalink / raw)
To: Ben Greear; +Cc: Kristian Evensen, netdev
In-Reply-To: <4F90208E.6070201@candelatech.com>
On Thu, 19 Apr 2012 07:26:22 -0700
Ben Greear <greearb@candelatech.com> wrote:
> On 04/19/2012 04:44 AM, Kristian Evensen wrote:
> > Hello,
>
> > The application works as intended when I connect interfaces one by
> > one. However, if I connect two interfaces "simultaneously", the
> > RTM_NEWLINK message for one of the interfaces is sometimes not
> > received. Nothing arrives at the handle. It seems to be random which
> > RTM_NEWLINK actually arrives. I have only been able to recreate this
> > problem when connecting two USB 3G modems and automatically dialing
> > the ISP, but I assume it would happen with other technologies as well.
> > What puzzles me, is that both RTM_NEWLINK messages are seen by for
> > example ip monitor. This has led me to conclusion that there is a bug
> > in my application, and my question is therefore, are there any common
> > mistakes one can make or things to forget that would cause a message
> > to get lost or not be received, or does anyone have any tips on where
> > I can start looking?
>
> Multiple netlink msgs can be received in each read of a netlink
> socket. Maybe you are only processing the first one?
I recommend using the libmnl library instead of the older
libnetlink. The code is cleaner and it handles error cases better.
In libmnl there is a callback interface for parsing
netlink messages.
^ permalink raw reply
* Re: [PATCH] NET: bcm63xx_enet: move phy_(dis)connect into probe/remove
From: Jonas Gorski @ 2012-04-19 14:52 UTC (permalink / raw)
To: mbizon; +Cc: netdev, Florian Fainelli, Eric Dumazet, David S. Miller
In-Reply-To: <1334842380.5185.29.camel@sakura.staff.proxad.net>
On 19 April 2012 15:33, Maxime Bizon <mbizon@freebox.fr> wrote:
>
> On Wed, 2012-04-18 at 21:30 +0200, Jonas Gorski wrote:
>>
>> The phy state machine will start in PHY_READY after phy_connect, which
>> will result in NOPs, so no call to bcm_enet_adjust_phy_link() after
>> _probe() and before _open(). The state machine starts doing real work
>> only after calling phy_start(), which happens only after the dma
>> register accesses in open(). So no race here.
>
> If I read the phylib code correctly, after phy_connect() the phy is in
> READY state, and you can access it via ethtool.
Yes, but none of the ethtool functions cause register writes in the
priv->has_phy = true case when in PHY_READY or PHY_HALTED state. All
they do is modify the phy_device's settings.
The settings only get taken over when the phy is started and the
phy_state_machine is running, so after phy_start() was and before
phy_stop().
In the priv->has_phy = false case they do cause register writes since
bcm_enet_adjust_link() might get called, but these never use the phy
state machine, so my patch does not change anything there.
Jonas
^ permalink raw reply
* Re: [PATCH net-next] nf_bridge: remove holes in struct nf_bridge_info
From: Stephen Hemminger @ 2012-04-19 14:52 UTC (permalink / raw)
To: Eric Dumazet; +Cc: David Miller, netdev
In-Reply-To: <1334827165.2395.63.camel@edumazet-glaptop>
On Thu, 19 Apr 2012 11:19:25 +0200
Eric Dumazet <eric.dumazet@gmail.com> wrote:
> From: Eric Dumazet <edumazet@google.com>
>
> Put use & mask on same location to avoid two holes on 64bit arches
>
> Signed-off-by: Eric Dumazet <edumazet@google.com>
Acked-by: Stephen Hemminger <shemminger@vyatta.com>
^ permalink raw reply
* Re: RTM_NEWLINK not received by application when connecting multiple devices simultaneously
From: Ben Greear @ 2012-04-19 14:26 UTC (permalink / raw)
To: Kristian Evensen; +Cc: netdev
In-Reply-To: <CAKfDRXj+mydkzNFC8q2aE_JWHp3ie0cijC-itkm6sHLuZr98Fw@mail.gmail.com>
On 04/19/2012 04:44 AM, Kristian Evensen wrote:
> Hello,
> The application works as intended when I connect interfaces one by
> one. However, if I connect two interfaces "simultaneously", the
> RTM_NEWLINK message for one of the interfaces is sometimes not
> received. Nothing arrives at the handle. It seems to be random which
> RTM_NEWLINK actually arrives. I have only been able to recreate this
> problem when connecting two USB 3G modems and automatically dialing
> the ISP, but I assume it would happen with other technologies as well.
> What puzzles me, is that both RTM_NEWLINK messages are seen by for
> example ip monitor. This has led me to conclusion that there is a bug
> in my application, and my question is therefore, are there any common
> mistakes one can make or things to forget that would cause a message
> to get lost or not be received, or does anyone have any tips on where
> I can start looking?
Multiple netlink msgs can be received in each read of a netlink
socket. Maybe you are only processing the first one?
Thanks,
Ben
--
Ben Greear <greearb@candelatech.com>
Candela Technologies Inc http://www.candelatech.com
^ permalink raw reply
* Re: [PATCH v2 net-next] tcp: avoid expensive pskb_expand_head() calls
From: Eric Dumazet @ 2012-04-19 14:10 UTC (permalink / raw)
To: Ilpo Järvinen
Cc: Neal Cardwell, David Miller, netdev, Tom Herbert,
Maciej Żenczykowski, Yuchung Cheng
In-Reply-To: <1334843527.2395.182.camel@edumazet-glaptop>
On Thu, 2012-04-19 at 15:52 +0200, Eric Dumazet wrote:
> And disabling GRO on receiver definitely demonstrates the problem, even
> with a single flow. (and performance drops from 9410 Mbit to 6050 Mbit)
That insane.
Performance drops so much because we _drop_ incoming ACKS :
< TCPSackShifted: 39117
< TCPSackMerged: 16500
< TCPSackShiftFallback: 5092
< TCPBacklogDrop: 27965
---
> TCPSackShifted: 35122
> TCPSackMerged: 16368
> TCPSackShiftFallback: 4889
> TCPBacklogDrop: 23247
Hmm, maybe we should reduce skb->truesize for small packets before
queueing them in socket backlog...
^ permalink raw reply
* Re: [net-next 1/4 (V3)] net: ethtool: add the EEE support
From: Yuval Mintz @ 2012-04-19 13:48 UTC (permalink / raw)
To: Giuseppe CAVALLARO
Cc: Ben Hutchings, netdev@vger.kernel.org, rayagond@vayavyalabs.com,
davem@davemloft.net
In-Reply-To: <4F900C08.5000906@st.com>
Hi Peppe,
> The "set" will be useful for some eth devices (like the stmmac) that can
> stop/enable internally the eee capability (at mac level).
If you're already implementing this interface, don't you think it might be
prudent to create an implementation that can do more than enable/disable
the interface?
I think users would like a method for configuring some of the EEE's variables,
mainly controlling the timers affecting the generation of an LPI request,
as such control might have a direct consequence on the effectiveness of their
energy savings (less time for generation ==> better energy savings, with a
possible latency penalty).
Thanks,
Yuval
^ permalink raw reply
* Re: [PATCH v2 net-next] tcp: avoid expensive pskb_expand_head() calls
From: Eric Dumazet @ 2012-04-19 13:52 UTC (permalink / raw)
To: Ilpo Järvinen
Cc: Neal Cardwell, David Miller, netdev, Tom Herbert,
Maciej Żenczykowski, Yuchung Cheng
In-Reply-To: <1334841481.2395.175.camel@edumazet-glaptop>
On Thu, 2012-04-19 at 15:18 +0200, Eric Dumazet wrote:
> On Thu, 2012-04-19 at 13:30 +0200, Eric Dumazet wrote:
>
> > I'll provide a v3 anyway with more performance data, I setup two cards
> > in PCI x8 slots to get full bandwidth.
>
> Incidentally, using PCI x8 slots dont anymore trigger the slow path on
> unpatched kernel and a single flow (~9410 Mbits)
>
> It seems we are lucky enough to TX complete sent clones before trying to
> tcp_trim_head() when processing ACK
>
> Sounds like a timing issue, and fact that drivers batches TX completions
> and RX completions.
>
> Also BQL might have changed things a bit here (ixgbe is BQL enabled)
>
> Only if I start several concurrent flows I see the pskb_expand_head()
> overhead.
>
>
And disabling GRO on receiver definitely demonstrates the problem, even
with a single flow. (and performance drops from 9410 Mbit to 6050 Mbit)
^ permalink raw reply
* [PATCH 6/6] tcp: Repair connection-time negotiated parameters
From: Pavel Emelyanov @ 2012-04-19 13:41 UTC (permalink / raw)
To: Linux Netdev List, David Miller
In-Reply-To: <4F901572.4040009@parallels.com>
There are options, which are set up on a socket while performing
TCP handshake. Need to resurrect them on a socket while repairing.
A new sockoption accepts a buffer and parses it. The buffer should
be CODE:VALUE sequence of bytes, where CODE is standard option
code and VALUE is the respective value.
Only 4 options should be handled on repaired socket.
To read 3 out of 4 of these options the TCP_INFO sockoption can be
used. An ability to get the last one (the mss_clamp) was added by
the previous patch.
Now the restore. Three of these options -- timestamp_ok, mss_clamp
and snd_wscale -- are just restored on a coket.
The sack_ok flags has 2 issues. First, whether or not to do sacks
at all. This flag is just read and set back. No other sack info is
saved or restored, since according to the standart and the code
dropping all sack-ed segments is OK, the sender will resubmit them
again, so after the repair we will probably experience a pause in
connection. Next, the fack bit. It's just set back on a socket if
the respective sysctl is set. No collected stats about packets flow
is preserved. As far as I see (plz, correct me if I'm wrong) the
fack-based congestion algorithm survives dropping all of the stats
and repairs itself eventually, probably losing the performance for
that period.
Signed-off-by: Pavel Emelyanov <xemul@openvz.org>
---
include/linux/tcp.h | 1 +
net/ipv4/tcp.c | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 72 insertions(+), 0 deletions(-)
diff --git a/include/linux/tcp.h b/include/linux/tcp.h
index 4e90e6a..9865936 100644
--- a/include/linux/tcp.h
+++ b/include/linux/tcp.h
@@ -109,6 +109,7 @@ enum {
#define TCP_REPAIR 19 /* TCP sock is under repair right now */
#define TCP_REPAIR_QUEUE 20
#define TCP_QUEUE_SEQ 21
+#define TCP_REPAIR_OPTIONS 22
enum {
TCP_NO_QUEUE,
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index b4e690d..3ce3bd0 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -2218,6 +2218,68 @@ static inline int tcp_can_repair_sock(struct sock *sk)
((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_ESTABLISHED));
}
+static int tcp_repair_options_est(struct tcp_sock *tp, char __user *optbuf, unsigned int len)
+{
+ /*
+ * Options are stored in CODE:VALUE form where CODE is 8bit and VALUE
+ * fits the respective TCPOLEN_ size
+ */
+
+ while (len > 0) {
+ u8 opcode;
+
+ if (get_user(opcode, optbuf))
+ return -EFAULT;
+
+ optbuf++;
+ len--;
+
+ switch (opcode) {
+ case TCPOPT_MSS: {
+ u16 in_mss;
+
+ if (len < sizeof(in_mss))
+ return -ENODATA;
+ if (get_user(in_mss, optbuf))
+ return -EFAULT;
+
+ tp->rx_opt.mss_clamp = in_mss;
+
+ optbuf += sizeof(in_mss);
+ len -= sizeof(in_mss);
+ break;
+ }
+ case TCPOPT_WINDOW: {
+ u8 wscale;
+
+ if (len < sizeof(wscale))
+ return -ENODATA;
+ if (get_user(wscale, optbuf))
+ return -EFAULT;
+
+ if (wscale > 14)
+ return -EFBIG;
+
+ tp->rx_opt.snd_wscale = wscale;
+
+ optbuf += sizeof(wscale);
+ len -= sizeof(wscale);
+ break;
+ }
+ case TCPOPT_SACK_PERM:
+ tp->rx_opt.sack_ok |= TCP_SACK_SEEN;
+ if (sysctl_tcp_fack)
+ tcp_enable_fack(tp);
+ break;
+ case TCPOPT_TIMESTAMP:
+ tp->rx_opt.tstamp_ok = 1;
+ break;
+ }
+ }
+
+ return 0;
+}
+
/*
* Socket option code for TCP.
*/
@@ -2426,6 +2488,15 @@ static int do_tcp_setsockopt(struct sock *sk, int level,
err = -EINVAL;
break;
+ case TCP_REPAIR_OPTIONS:
+ if (!tp->repair)
+ err = -EINVAL;
+ else if (sk->sk_state == TCP_ESTABLISHED)
+ err = tcp_repair_options_est(tp, optval, optlen);
+ else
+ err = -EPERM;
+ break;
+
case TCP_CORK:
/* When set indicates to always queue non-full frames.
* Later the user clears this option and we transmit
--
1.5.5.6
^ permalink raw reply related
* [PATCH 5/6] tcp: Report mss_clamp with TCP_MAXSEG option in repair mode
From: Pavel Emelyanov @ 2012-04-19 13:41 UTC (permalink / raw)
To: Linux Netdev List, David Miller
In-Reply-To: <4F901572.4040009@parallels.com>
The mss_clamp is the only connection-time negotiated option which
cannot be obtained from the user space. Make the TCP_MAXSEG sockopt
report one in the repair mode.
Signed-off-by: Pavel Emelyanov <xemul@openvz.org>
---
net/ipv4/tcp.c | 2 ++
1 files changed, 2 insertions(+), 0 deletions(-)
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 47e2f49..b4e690d 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -2659,6 +2659,8 @@ static int do_tcp_getsockopt(struct sock *sk, int level,
val = tp->mss_cache;
if (!val && ((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_LISTEN)))
val = tp->rx_opt.user_mss;
+ if (tp->repair)
+ val = tp->rx_opt.mss_clamp;
break;
case TCP_NODELAY:
val = !!(tp->nonagle&TCP_NAGLE_OFF);
--
1.5.5.6
^ permalink raw reply related
* [PATCH 4/6] tcp: Repair socket queues
From: Pavel Emelyanov @ 2012-04-19 13:41 UTC (permalink / raw)
To: Linux Netdev List, David Miller
In-Reply-To: <4F901572.4040009@parallels.com>
Reading queues under repair mode is done with recvmsg call.
The queue-under-repair set by TCP_REPAIR_QUEUE option is used
to determine which queue should be read. Thus both send and
receive queue can be read with this.
Caller must pass the MSG_PEEK flag.
Writing to queues is done with sendmsg call and yet again --
the repair-queue option can be used to push data into the
receive queue.
When putting an skb into receive queue a zero tcp header is
appented to its head to address the tcp_hdr(skb)->syn and
the ->fin checks by the (after repair) tcp_recvmsg. These
flags flags are both set to zero and that's why.
The fin cannot be met in the queue while reading the source
socket, since the repair only works for closed/established
sockets and queueing fin packet always changes its state.
The syn in the queue denotes that the respective skb's seq
is "off-by-one" as compared to the actual payload lenght. Thus,
at the rcv queue refill we can just drop this flag and set the
skb's sequences to precice values.
When the repair mode is turned off, the write queue seqs are
updated so that the whole queue is considered to be 'already sent,
waiting for ACKs' (write_seq = snd_nxt <= snd_una). From the
protocol POV the send queue looks like it was sent, but the data
between the write_seq and snd_nxt is lost in the network.
This helps to avoid another sockoption for setting the snd_nxt
sequence. Leaving the whole queue in a 'not yet sent' state (as
it will be after sendmsg-s) will not allow to receive any acks
from the peer since the ack_seq will be after the snd_nxt. Thus
even the ack for the window probe will be dropped and the
connection will be 'locked' with the zero peer window.
Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
---
net/ipv4/tcp.c | 89 +++++++++++++++++++++++++++++++++++++++++++++++--
net/ipv4/tcp_output.c | 1 +
2 files changed, 87 insertions(+), 3 deletions(-)
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index e38d6f2..47e2f49 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -912,6 +912,39 @@ static inline int select_size(const struct sock *sk, bool sg)
return tmp;
}
+static int tcp_send_rcvq(struct sock *sk, struct msghdr *msg, size_t size)
+{
+ struct sk_buff *skb;
+ struct tcp_skb_cb *cb;
+ struct tcphdr *th;
+
+ skb = alloc_skb(size + sizeof(*th), sk->sk_allocation);
+ if (!skb)
+ goto err;
+
+ th = (struct tcphdr *)skb_put(skb, sizeof(*th));
+ skb_reset_transport_header(skb);
+ memset(th, 0, sizeof(*th));
+
+ if (memcpy_fromiovec(skb_put(skb, size), msg->msg_iov, size))
+ goto err_free;
+
+ cb = TCP_SKB_CB(skb);
+
+ TCP_SKB_CB(skb)->seq = tcp_sk(sk)->rcv_nxt;
+ TCP_SKB_CB(skb)->end_seq = TCP_SKB_CB(skb)->seq + size;
+ TCP_SKB_CB(skb)->ack_seq = tcp_sk(sk)->snd_una - 1;
+
+ tcp_queue_rcv(sk, skb, sizeof(*th));
+
+ return size;
+
+err_free:
+ kfree_skb(skb);
+err:
+ return -ENOMEM;
+}
+
int tcp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
size_t size)
{
@@ -933,6 +966,19 @@ int tcp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
if ((err = sk_stream_wait_connect(sk, &timeo)) != 0)
goto out_err;
+ if (unlikely(tp->repair)) {
+ if (tp->repair_queue == TCP_RECV_QUEUE) {
+ copied = tcp_send_rcvq(sk, msg, size);
+ goto out;
+ }
+
+ err = -EINVAL;
+ if (tp->repair_queue == TCP_NO_QUEUE)
+ goto out_err;
+
+ /* 'common' sending to sendq */
+ }
+
/* This should be in poll */
clear_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags);
@@ -1089,7 +1135,7 @@ new_segment:
if ((seglen -= copy) == 0 && iovlen == 0)
goto out;
- if (skb->len < max || (flags & MSG_OOB))
+ if (skb->len < max || (flags & MSG_OOB) || unlikely(tp->repair))
continue;
if (forced_push(tp)) {
@@ -1102,7 +1148,7 @@ new_segment:
wait_for_sndbuf:
set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
wait_for_memory:
- if (copied)
+ if (copied && likely(!tp->repair))
tcp_push(sk, flags & ~MSG_MORE, mss_now, TCP_NAGLE_PUSH);
if ((err = sk_stream_wait_memory(sk, &timeo)) != 0)
@@ -1113,7 +1159,7 @@ wait_for_memory:
}
out:
- if (copied)
+ if (copied && likely(!tp->repair))
tcp_push(sk, flags, mss_now, tp->nonagle);
release_sock(sk);
return copied;
@@ -1187,6 +1233,24 @@ static int tcp_recv_urg(struct sock *sk, struct msghdr *msg, int len, int flags)
return -EAGAIN;
}
+static int tcp_peek_sndq(struct sock *sk, struct msghdr *msg, int len)
+{
+ struct sk_buff *skb;
+ int copied = 0, err = 0;
+
+ /* XXX -- need to support SO_PEEK_OFF */
+
+ skb_queue_walk(&sk->sk_write_queue, skb) {
+ err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, skb->len);
+ if (err)
+ break;
+
+ copied += skb->len;
+ }
+
+ return err ?: copied;
+}
+
/* Clean up the receive buffer for full frames taken by the user,
* then send an ACK if necessary. COPIED is the number of bytes
* tcp_recvmsg has given to the user so far, it speeds up the
@@ -1432,6 +1496,21 @@ int tcp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
if (flags & MSG_OOB)
goto recv_urg;
+ if (unlikely(tp->repair)) {
+ err = -EPERM;
+ if (!(flags & MSG_PEEK))
+ goto out;
+
+ if (tp->repair_queue == TCP_SEND_QUEUE)
+ goto recv_sndq;
+
+ err = -EINVAL;
+ if (tp->repair_queue == TCP_NO_QUEUE)
+ goto out;
+
+ /* 'common' recv queue MSG_PEEK-ing */
+ }
+
seq = &tp->copied_seq;
if (flags & MSG_PEEK) {
peek_seq = tp->copied_seq;
@@ -1783,6 +1862,10 @@ out:
recv_urg:
err = tcp_recv_urg(sk, msg, len, flags);
goto out;
+
+recv_sndq:
+ err = tcp_peek_sndq(sk, msg, len);
+ goto out;
}
EXPORT_SYMBOL(tcp_recvmsg);
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index fa442a6..57a834c 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -2796,6 +2796,7 @@ void tcp_send_window_probe(struct sock *sk)
{
if (sk->sk_state == TCP_ESTABLISHED) {
tcp_sk(sk)->snd_wl1 = tcp_sk(sk)->rcv_nxt - 1;
+ tcp_sk(sk)->snd_nxt = tcp_sk(sk)->write_seq;
tcp_xmit_probe_skb(sk, 0);
}
}
--
1.5.5.6
^ permalink raw reply related
* [PATCH 3/6] tcp: Initial repair mode
From: Pavel Emelyanov @ 2012-04-19 13:40 UTC (permalink / raw)
To: Linux Netdev List, David Miller
In-Reply-To: <4F901572.4040009@parallels.com>
This includes (according the the previous description):
* TCP_REPAIR sockoption
This one just puts the socket in/out of the repair mode.
Allowed for CAP_NET_ADMIN and for closed/establised sockets only.
When repair mode is turned off and the socket happens to be in
the established state the window probe is sent to the peer to
'unlock' the connection.
* TCP_REPAIR_QUEUE sockoption
This one sets the queue which we're about to repair. The
'no-queue' is set by default.
* TCP_QUEUE_SEQ socoption
Sets the write_seq/rcv_nxt of a selected repaired queue.
Allowed for TCP_CLOSE-d sockets only. When the socket changes
its state the other seq-s are changed by the kernel according
to the protocol rules (most of the existing code is actually
reused).
* Ability to forcibly bind a socket to a port
The sk->sk_reuse is set to SK_FORCE_REUSE.
* Immediate connect modification
The connect syscall initializes the connection, then directly jumps
to the code which finalizes it.
* Silent close modification
The close just aborts the connection (similar to SO_LINGER with 0
time) but without sending any FIN/RST-s to peer.
Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
---
include/linux/tcp.h | 14 +++++++++-
include/net/tcp.h | 2 +
net/ipv4/tcp.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++++-
net/ipv4/tcp_ipv4.c | 19 +++++++++++--
net/ipv4/tcp_output.c | 16 +++++++++--
5 files changed, 111 insertions(+), 8 deletions(-)
diff --git a/include/linux/tcp.h b/include/linux/tcp.h
index b6c62d2..4e90e6a 100644
--- a/include/linux/tcp.h
+++ b/include/linux/tcp.h
@@ -106,6 +106,16 @@ enum {
#define TCP_THIN_LINEAR_TIMEOUTS 16 /* Use linear timeouts for thin streams*/
#define TCP_THIN_DUPACK 17 /* Fast retrans. after 1 dupack */
#define TCP_USER_TIMEOUT 18 /* How long for loss retry before timeout */
+#define TCP_REPAIR 19 /* TCP sock is under repair right now */
+#define TCP_REPAIR_QUEUE 20
+#define TCP_QUEUE_SEQ 21
+
+enum {
+ TCP_NO_QUEUE,
+ TCP_RECV_QUEUE,
+ TCP_SEND_QUEUE,
+ TCP_QUEUES_NR,
+};
/* for TCP_INFO socket option */
#define TCPI_OPT_TIMESTAMPS 1
@@ -353,7 +363,9 @@ struct tcp_sock {
u8 nonagle : 4,/* Disable Nagle algorithm? */
thin_lto : 1,/* Use linear timeouts for thin streams */
thin_dupack : 1,/* Fast retransmit on first dupack */
- unused : 2;
+ repair : 1,
+ unused : 1;
+ u8 repair_queue;
/* RTT measurement */
u32 srtt; /* smoothed round trip time << 3 */
diff --git a/include/net/tcp.h b/include/net/tcp.h
index 633fde2..b4ccb8a 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -612,6 +612,8 @@ static inline u32 tcp_receive_window(const struct tcp_sock *tp)
*/
extern u32 __tcp_select_window(struct sock *sk);
+void tcp_send_window_probe(struct sock *sk);
+
/* TCP timestamps are only 32-bits, this causes a slight
* complication on 64-bit systems since we store a snapshot
* of jiffies in the buffer control blocks below. We decided
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index bb4200f..e38d6f2 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -1935,7 +1935,9 @@ void tcp_close(struct sock *sk, long timeout)
* advertise a zero window, then kill -9 the FTP client, wheee...
* Note: timeout is always zero in such a case.
*/
- if (data_was_unread) {
+ if (unlikely(tcp_sk(sk)->repair)) {
+ sk->sk_prot->disconnect(sk, 0);
+ } else if (data_was_unread) {
/* Unread data was tossed, zap the connection. */
NET_INC_STATS_USER(sock_net(sk), LINUX_MIB_TCPABORTONCLOSE);
tcp_set_state(sk, TCP_CLOSE);
@@ -2074,6 +2076,8 @@ int tcp_disconnect(struct sock *sk, int flags)
/* ABORT function of RFC793 */
if (old_state == TCP_LISTEN) {
inet_csk_listen_stop(sk);
+ } else if (unlikely(tp->repair)) {
+ sk->sk_err = ECONNABORTED;
} else if (tcp_need_reset(old_state) ||
(tp->snd_nxt != tp->write_seq &&
(1 << old_state) & (TCPF_CLOSING | TCPF_LAST_ACK))) {
@@ -2125,6 +2129,12 @@ int tcp_disconnect(struct sock *sk, int flags)
}
EXPORT_SYMBOL(tcp_disconnect);
+static inline int tcp_can_repair_sock(struct sock *sk)
+{
+ return capable(CAP_NET_ADMIN) &&
+ ((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_ESTABLISHED));
+}
+
/*
* Socket option code for TCP.
*/
@@ -2297,6 +2307,42 @@ static int do_tcp_setsockopt(struct sock *sk, int level,
tp->thin_dupack = val;
break;
+ case TCP_REPAIR:
+ if (!tcp_can_repair_sock(sk))
+ err = -EPERM;
+ else if (val == 1) {
+ tp->repair = 1;
+ sk->sk_reuse = SK_FORCE_REUSE;
+ tp->repair_queue = TCP_NO_QUEUE;
+ } else if (val == 0) {
+ tp->repair = 0;
+ sk->sk_reuse = SK_NO_REUSE;
+ tcp_send_window_probe(sk);
+ } else
+ err = -EINVAL;
+
+ break;
+
+ case TCP_REPAIR_QUEUE:
+ if (!tp->repair)
+ err = -EPERM;
+ else if (val < TCP_QUEUES_NR)
+ tp->repair_queue = val;
+ else
+ err = -EINVAL;
+ break;
+
+ case TCP_QUEUE_SEQ:
+ if (sk->sk_state != TCP_CLOSE)
+ err = -EPERM;
+ else if (tp->repair_queue == TCP_SEND_QUEUE)
+ tp->write_seq = val;
+ else if (tp->repair_queue == TCP_RECV_QUEUE)
+ tp->rcv_nxt = val;
+ else
+ err = -EINVAL;
+ break;
+
case TCP_CORK:
/* When set indicates to always queue non-full frames.
* Later the user clears this option and we transmit
@@ -2632,6 +2678,26 @@ static int do_tcp_getsockopt(struct sock *sk, int level,
val = tp->thin_dupack;
break;
+ case TCP_REPAIR:
+ val = tp->repair;
+ break;
+
+ case TCP_REPAIR_QUEUE:
+ if (tp->repair)
+ val = tp->repair_queue;
+ else
+ return -EINVAL;
+ break;
+
+ case TCP_QUEUE_SEQ:
+ if (tp->repair_queue == TCP_SEND_QUEUE)
+ val = tp->write_seq;
+ else if (tp->repair_queue == TCP_RECV_QUEUE)
+ val = tp->rcv_nxt;
+ else
+ return -EINVAL;
+ break;
+
case TCP_USER_TIMEOUT:
val = jiffies_to_msecs(icsk->icsk_user_timeout);
break;
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 0cb86ce..ba6dad8 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -138,6 +138,14 @@ int tcp_twsk_unique(struct sock *sk, struct sock *sktw, void *twp)
}
EXPORT_SYMBOL_GPL(tcp_twsk_unique);
+static int tcp_repair_connect(struct sock *sk)
+{
+ tcp_connect_init(sk);
+ tcp_finish_connect(sk, NULL);
+
+ return 0;
+}
+
/* This will initiate an outgoing connection. */
int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
{
@@ -196,7 +204,8 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
/* Reset inherited state */
tp->rx_opt.ts_recent = 0;
tp->rx_opt.ts_recent_stamp = 0;
- tp->write_seq = 0;
+ if (likely(!tp->repair))
+ tp->write_seq = 0;
}
if (tcp_death_row.sysctl_tw_recycle &&
@@ -247,7 +256,7 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
sk->sk_gso_type = SKB_GSO_TCPV4;
sk_setup_caps(sk, &rt->dst);
- if (!tp->write_seq)
+ if (!tp->write_seq && likely(!tp->repair))
tp->write_seq = secure_tcp_sequence_number(inet->inet_saddr,
inet->inet_daddr,
inet->inet_sport,
@@ -255,7 +264,11 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
inet->inet_id = tp->write_seq ^ jiffies;
- err = tcp_connect(sk);
+ if (likely(!tp->repair))
+ err = tcp_connect(sk);
+ else
+ err = tcp_repair_connect(sk);
+
rt = NULL;
if (err)
goto failure;
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index db126a6..fa442a6 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -2617,9 +2617,11 @@ void tcp_connect_init(struct sock *sk)
tp->snd_sml = tp->write_seq;
tp->snd_up = tp->write_seq;
tp->snd_nxt = tp->write_seq;
- tp->rcv_nxt = 0;
- tp->rcv_wup = 0;
- tp->copied_seq = 0;
+
+ if (likely(!tp->repair))
+ tp->rcv_nxt = 0;
+ tp->rcv_wup = tp->rcv_nxt;
+ tp->copied_seq = tp->rcv_nxt;
inet_csk(sk)->icsk_rto = TCP_TIMEOUT_INIT;
inet_csk(sk)->icsk_retransmits = 0;
@@ -2790,6 +2792,14 @@ static int tcp_xmit_probe_skb(struct sock *sk, int urgent)
return tcp_transmit_skb(sk, skb, 0, GFP_ATOMIC);
}
+void tcp_send_window_probe(struct sock *sk)
+{
+ if (sk->sk_state == TCP_ESTABLISHED) {
+ tcp_sk(sk)->snd_wl1 = tcp_sk(sk)->rcv_nxt - 1;
+ tcp_xmit_probe_skb(sk, 0);
+ }
+}
+
/* Initiate keepalive or window probe from timer. */
int tcp_write_wakeup(struct sock *sk)
{
--
1.5.5.6
^ permalink raw reply related
* [PATCH 2/6] tcp: Move code around
From: Pavel Emelyanov @ 2012-04-19 13:40 UTC (permalink / raw)
To: Linux Netdev List, David Miller
In-Reply-To: <4F901572.4040009@parallels.com>
This is just the preparation patch, which makes the needed for
TCP repair code ready for use.
Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
---
include/net/tcp.h | 3 ++
net/ipv4/tcp.c | 2 +-
net/ipv4/tcp_input.c | 81 +++++++++++++++++++++++++++++--------------------
net/ipv4/tcp_output.c | 4 +-
4 files changed, 54 insertions(+), 36 deletions(-)
diff --git a/include/net/tcp.h b/include/net/tcp.h
index d5984e3..633fde2 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -435,6 +435,9 @@ extern struct sk_buff * tcp_make_synack(struct sock *sk, struct dst_entry *dst,
struct request_values *rvp);
extern int tcp_disconnect(struct sock *sk, int flags);
+void tcp_connect_init(struct sock *sk);
+void tcp_finish_connect(struct sock *sk, struct sk_buff *skb);
+void tcp_queue_rcv(struct sock *sk, struct sk_buff *skb, int hdrlen);
/* From syncookies.c */
extern __u32 syncookie_secret[2][16-4+SHA_DIGEST_WORDS];
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index c53e8a8..bb4200f 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -919,7 +919,7 @@ int tcp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
struct tcp_sock *tp = tcp_sk(sk);
struct sk_buff *skb;
int iovlen, flags, err, copied;
- int mss_now, size_goal;
+ int mss_now = 0, size_goal;
bool sg;
long timeo;
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 99448f0..37e1c5c 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -5325,6 +5325,14 @@ discard:
return 0;
}
+void tcp_queue_rcv(struct sock *sk, struct sk_buff *skb, int hdrlen)
+{
+ __skb_pull(skb, hdrlen);
+ __skb_queue_tail(&sk->sk_receive_queue, skb);
+ skb_set_owner_r(skb, sk);
+ tcp_sk(sk)->rcv_nxt = TCP_SKB_CB(skb)->end_seq;
+}
+
/*
* TCP receive function for the ESTABLISHED state.
*
@@ -5490,10 +5498,7 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPHPHITS);
/* Bulk data transfer: receiver */
- __skb_pull(skb, tcp_header_len);
- __skb_queue_tail(&sk->sk_receive_queue, skb);
- skb_set_owner_r(skb, sk);
- tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq;
+ tcp_queue_rcv(sk, skb, tcp_header_len);
}
tcp_event_data_recv(sk, skb);
@@ -5559,6 +5564,44 @@ discard:
}
EXPORT_SYMBOL(tcp_rcv_established);
+void tcp_finish_connect(struct sock *sk, struct sk_buff *skb)
+{
+ struct tcp_sock *tp = tcp_sk(sk);
+ struct inet_connection_sock *icsk = inet_csk(sk);
+
+ tcp_set_state(sk, TCP_ESTABLISHED);
+
+ if (skb != NULL)
+ security_inet_conn_established(sk, skb);
+
+ /* Make sure socket is routed, for correct metrics. */
+ icsk->icsk_af_ops->rebuild_header(sk);
+
+ tcp_init_metrics(sk);
+
+ tcp_init_congestion_control(sk);
+
+ /* Prevent spurious tcp_cwnd_restart() on first data
+ * packet.
+ */
+ tp->lsndtime = tcp_time_stamp;
+
+ tcp_init_buffer_space(sk);
+
+ if (sock_flag(sk, SOCK_KEEPOPEN))
+ inet_csk_reset_keepalive_timer(sk, keepalive_time_when(tp));
+
+ if (!tp->rx_opt.snd_wscale)
+ __tcp_fast_path_on(tp, tp->snd_wnd);
+ else
+ tp->pred_flags = 0;
+
+ if (!sock_flag(sk, SOCK_DEAD)) {
+ sk->sk_state_change(sk);
+ sk_wake_async(sk, SOCK_WAKE_IO, POLL_OUT);
+ }
+}
+
static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb,
const struct tcphdr *th, unsigned int len)
{
@@ -5691,36 +5734,8 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb,
}
smp_mb();
- tcp_set_state(sk, TCP_ESTABLISHED);
-
- security_inet_conn_established(sk, skb);
-
- /* Make sure socket is routed, for correct metrics. */
- icsk->icsk_af_ops->rebuild_header(sk);
-
- tcp_init_metrics(sk);
- tcp_init_congestion_control(sk);
-
- /* Prevent spurious tcp_cwnd_restart() on first data
- * packet.
- */
- tp->lsndtime = tcp_time_stamp;
-
- tcp_init_buffer_space(sk);
-
- if (sock_flag(sk, SOCK_KEEPOPEN))
- inet_csk_reset_keepalive_timer(sk, keepalive_time_when(tp));
-
- if (!tp->rx_opt.snd_wscale)
- __tcp_fast_path_on(tp, tp->snd_wnd);
- else
- tp->pred_flags = 0;
-
- if (!sock_flag(sk, SOCK_DEAD)) {
- sk->sk_state_change(sk);
- sk_wake_async(sk, SOCK_WAKE_IO, POLL_OUT);
- }
+ tcp_finish_connect(sk, skb);
if (sk->sk_write_pending ||
icsk->icsk_accept_queue.rskq_defer_accept ||
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index de8790c..db126a6 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -2561,7 +2561,7 @@ struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst,
EXPORT_SYMBOL(tcp_make_synack);
/* Do all connect socket setups that can be done AF independent. */
-static void tcp_connect_init(struct sock *sk)
+void tcp_connect_init(struct sock *sk)
{
const struct dst_entry *dst = __sk_dst_get(sk);
struct tcp_sock *tp = tcp_sk(sk);
@@ -2616,6 +2616,7 @@ static void tcp_connect_init(struct sock *sk)
tp->snd_una = tp->write_seq;
tp->snd_sml = tp->write_seq;
tp->snd_up = tp->write_seq;
+ tp->snd_nxt = tp->write_seq;
tp->rcv_nxt = 0;
tp->rcv_wup = 0;
tp->copied_seq = 0;
@@ -2641,7 +2642,6 @@ int tcp_connect(struct sock *sk)
/* Reserve space for headers. */
skb_reserve(buff, MAX_TCP_HEADER);
- tp->snd_nxt = tp->write_seq;
tcp_init_nondata_skb(buff, tp->write_seq++, TCPHDR_SYN);
TCP_ECN_send_syn(sk, buff);
--
1.5.5.6
^ permalink raw reply related
* [PATCH 1/6] sock: Introduce named constants for sk_reuse
From: Pavel Emelyanov @ 2012-04-19 13:39 UTC (permalink / raw)
To: Linux Netdev List, David Miller
In-Reply-To: <4F901572.4040009@parallels.com>
Name them in a "backward compatible" manner, i.e. reuse or not
are still 1 and 0 respectively. The reuse value of 2 means that
the socket with it will forcibly reuse everyone else's port.
Signed-off-by: Pavel Emelyanov <xemul@openvz.org>
---
drivers/block/drbd/drbd_receiver.c | 6 +++---
drivers/scsi/iscsi_tcp.c | 2 +-
drivers/staging/ramster/cluster/tcp.c | 2 +-
fs/ocfs2/cluster/tcp.c | 2 +-
include/net/sock.h | 11 +++++++++++
net/core/sock.c | 2 +-
net/econet/af_econet.c | 4 ++--
net/ipv4/af_inet.c | 2 +-
net/ipv4/inet_connection_sock.c | 3 +++
net/ipv6/af_inet6.c | 2 +-
net/netfilter/ipvs/ip_vs_sync.c | 2 +-
net/rds/tcp_listen.c | 2 +-
net/sunrpc/svcsock.c | 2 +-
13 files changed, 28 insertions(+), 14 deletions(-)
diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c
index 43beaca..436f519 100644
--- a/drivers/block/drbd/drbd_receiver.c
+++ b/drivers/block/drbd/drbd_receiver.c
@@ -664,7 +664,7 @@ static struct socket *drbd_wait_for_connect(struct drbd_conf *mdev)
timeo = mdev->net_conf->try_connect_int * HZ;
timeo += (random32() & 1) ? timeo / 7 : -timeo / 7; /* 28.5% random jitter */
- s_listen->sk->sk_reuse = 1; /* SO_REUSEADDR */
+ s_listen->sk->sk_reuse = SK_CAN_REUSE; /* SO_REUSEADDR */
s_listen->sk->sk_rcvtimeo = timeo;
s_listen->sk->sk_sndtimeo = timeo;
drbd_setbufsize(s_listen, mdev->net_conf->sndbuf_size,
@@ -841,8 +841,8 @@ retry:
}
} while (1);
- msock->sk->sk_reuse = 1; /* SO_REUSEADDR */
- sock->sk->sk_reuse = 1; /* SO_REUSEADDR */
+ msock->sk->sk_reuse = SK_CAN_REUSE; /* SO_REUSEADDR */
+ sock->sk->sk_reuse = SK_CAN_REUSE; /* SO_REUSEADDR */
sock->sk->sk_allocation = GFP_NOIO;
msock->sk->sk_allocation = GFP_NOIO;
diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c
index 453a740..9220861 100644
--- a/drivers/scsi/iscsi_tcp.c
+++ b/drivers/scsi/iscsi_tcp.c
@@ -662,7 +662,7 @@ iscsi_sw_tcp_conn_bind(struct iscsi_cls_session *cls_session,
/* setup Socket parameters */
sk = sock->sk;
- sk->sk_reuse = 1;
+ sk->sk_reuse = SK_CAN_REUSE;
sk->sk_sndtimeo = 15 * HZ; /* FIXME: make it configurable */
sk->sk_allocation = GFP_ATOMIC;
diff --git a/drivers/staging/ramster/cluster/tcp.c b/drivers/staging/ramster/cluster/tcp.c
index 3af1b2c..b9721c1 100644
--- a/drivers/staging/ramster/cluster/tcp.c
+++ b/drivers/staging/ramster/cluster/tcp.c
@@ -2106,7 +2106,7 @@ static int r2net_open_listening_sock(__be32 addr, __be16 port)
r2net_listen_sock = sock;
INIT_WORK(&r2net_listen_work, r2net_accept_many);
- sock->sk->sk_reuse = 1;
+ sock->sk->sk_reuse = SK_CAN_REUSE;
ret = sock->ops->bind(sock, (struct sockaddr *)&sin, sizeof(sin));
if (ret < 0) {
printk(KERN_ERR "ramster: Error %d while binding socket at "
diff --git a/fs/ocfs2/cluster/tcp.c b/fs/ocfs2/cluster/tcp.c
index 044e7b5..1bfe880 100644
--- a/fs/ocfs2/cluster/tcp.c
+++ b/fs/ocfs2/cluster/tcp.c
@@ -2005,7 +2005,7 @@ static int o2net_open_listening_sock(__be32 addr, __be16 port)
o2net_listen_sock = sock;
INIT_WORK(&o2net_listen_work, o2net_accept_many);
- sock->sk->sk_reuse = 1;
+ sock->sk->sk_reuse = SK_CAN_REUSE;
ret = sock->ops->bind(sock, (struct sockaddr *)&sin, sizeof(sin));
if (ret < 0) {
printk(KERN_ERR "o2net: Error %d while binding socket at "
diff --git a/include/net/sock.h b/include/net/sock.h
index a6ba1f8..4cdb9b3 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -376,6 +376,17 @@ struct sock {
void (*sk_destruct)(struct sock *sk);
};
+/*
+ * SK_CAN_REUSE and SK_NO_REUSE on a socket mean that the socket is OK
+ * or not whether his port will be reused by someone else. SK_FORCE_REUSE
+ * on a socket means that the socket will reuse everybody else's port
+ * without looking at the other's sk_reuse value.
+ */
+
+#define SK_NO_REUSE 0
+#define SK_CAN_REUSE 1
+#define SK_FORCE_REUSE 2
+
static inline int sk_peek_offset(struct sock *sk, int flags)
{
if ((flags & MSG_PEEK) && (sk->sk_peek_off >= 0))
diff --git a/net/core/sock.c b/net/core/sock.c
index c7e60ea..679c5bb 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -561,7 +561,7 @@ int sock_setsockopt(struct socket *sock, int level, int optname,
sock_valbool_flag(sk, SOCK_DBG, valbool);
break;
case SO_REUSEADDR:
- sk->sk_reuse = valbool;
+ sk->sk_reuse = (valbool ? SK_CAN_REUSE : SK_NO_REUSE);
break;
case SO_TYPE:
case SO_PROTOCOL:
diff --git a/net/econet/af_econet.c b/net/econet/af_econet.c
index 71b5edc..fa14ca7 100644
--- a/net/econet/af_econet.c
+++ b/net/econet/af_econet.c
@@ -617,7 +617,7 @@ static int econet_create(struct net *net, struct socket *sock, int protocol,
if (sk == NULL)
goto out;
- sk->sk_reuse = 1;
+ sk->sk_reuse = SK_CAN_REUSE;
sock->ops = &econet_ops;
sock_init_data(sock, sk);
@@ -1012,7 +1012,7 @@ static int __init aun_udp_initialise(void)
return error;
}
- udpsock->sk->sk_reuse = 1;
+ udpsock->sk->sk_reuse = SK_CAN_REUSE;
udpsock->sk->sk_allocation = GFP_ATOMIC; /* we're going to call it
from interrupts */
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index 3744c1c..c8f7aee 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -350,7 +350,7 @@ lookup_protocol:
err = 0;
sk->sk_no_check = answer_no_check;
if (INET_PROTOSW_REUSE & answer_flags)
- sk->sk_reuse = 1;
+ sk->sk_reuse = SK_CAN_REUSE;
inet = inet_sk(sk);
inet->is_icsk = (INET_PROTOSW_ICSK & answer_flags) != 0;
diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c
index 7d972f6..95e6159 100644
--- a/net/ipv4/inet_connection_sock.c
+++ b/net/ipv4/inet_connection_sock.c
@@ -182,6 +182,9 @@ have_snum:
goto tb_not_found;
tb_found:
if (!hlist_empty(&tb->owners)) {
+ if (sk->sk_reuse == SK_FORCE_REUSE)
+ goto success;
+
if (tb->fastreuse > 0 &&
sk->sk_reuse && sk->sk_state != TCP_LISTEN &&
smallest_size == -1) {
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index 8ed1b93..499e74e 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -180,7 +180,7 @@ lookup_protocol:
err = 0;
sk->sk_no_check = answer_no_check;
if (INET_PROTOSW_REUSE & answer_flags)
- sk->sk_reuse = 1;
+ sk->sk_reuse = SK_CAN_REUSE;
inet = inet_sk(sk);
inet->is_icsk = (INET_PROTOSW_ICSK & answer_flags) != 0;
diff --git a/net/netfilter/ipvs/ip_vs_sync.c b/net/netfilter/ipvs/ip_vs_sync.c
index f4e0b6c..bf5e538 100644
--- a/net/netfilter/ipvs/ip_vs_sync.c
+++ b/net/netfilter/ipvs/ip_vs_sync.c
@@ -1368,7 +1368,7 @@ static struct socket *make_receive_sock(struct net *net)
*/
sk_change_net(sock->sk, net);
/* it is equivalent to the REUSEADDR option in user-space */
- sock->sk->sk_reuse = 1;
+ sock->sk->sk_reuse = SK_CAN_REUSE;
result = sock->ops->bind(sock, (struct sockaddr *) &mcast_addr,
sizeof(struct sockaddr));
diff --git a/net/rds/tcp_listen.c b/net/rds/tcp_listen.c
index 8b5cc4a..7298137 100644
--- a/net/rds/tcp_listen.c
+++ b/net/rds/tcp_listen.c
@@ -145,7 +145,7 @@ int rds_tcp_listen_init(void)
if (ret < 0)
goto out;
- sock->sk->sk_reuse = 1;
+ sock->sk->sk_reuse = SK_CAN_REUSE;
rds_tcp_nonagle(sock);
write_lock_bh(&sock->sk->sk_callback_lock);
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
index 824d32f..f0132b2 100644
--- a/net/sunrpc/svcsock.c
+++ b/net/sunrpc/svcsock.c
@@ -1556,7 +1556,7 @@ static struct svc_xprt *svc_create_socket(struct svc_serv *serv,
(char *)&val, sizeof(val));
if (type == SOCK_STREAM)
- sock->sk->sk_reuse = 1; /* allow address reuse */
+ sock->sk->sk_reuse = SK_CAN_REUSE; /* allow address reuse */
error = kernel_bind(sock, sin, len);
if (error < 0)
goto bummer;
--
1.5.5.6
^ permalink raw reply related
* [PATCH net-next 0/6] TCP connection repair (v4)
From: Pavel Emelyanov @ 2012-04-19 13:38 UTC (permalink / raw)
To: Linux Netdev List, David Miller
Hi!
Attempt #4 with an API for TCP connection recreation (previous one is
at http://lists.openwall.net/netdev/2012/03/28/84) re-based on the
today's net-next tree.
Changes since v3:
* Added repair for TCP options negotiated during 3WHS process, pointed
out by Li Yu. The explanation of how this happens is in patch #6.
* Named constant for sk_reuse values as proposed by Ben Hutching.
* Off-by-one in repair-queue sockoption caught by Ben.
Thanks,
Pavel
^ permalink raw reply
* Re: [PATCH] NET: bcm63xx_enet: move phy_(dis)connect into probe/remove
From: Maxime Bizon @ 2012-04-19 13:33 UTC (permalink / raw)
To: Jonas Gorski; +Cc: netdev, Florian Fainelli, Eric Dumazet, David S. Miller
In-Reply-To: <CAOiHx=khEqKaAsD++=0BXEzutaWCgi-30B=6hYyLChfkAaHXXA@mail.gmail.com>
On Wed, 2012-04-18 at 21:30 +0200, Jonas Gorski wrote:
>
> The phy state machine will start in PHY_READY after phy_connect, which
> will result in NOPs, so no call to bcm_enet_adjust_phy_link() after
> _probe() and before _open(). The state machine starts doing real work
> only after calling phy_start(), which happens only after the dma
> register accesses in open(). So no race here.
If I read the phylib code correctly, after phy_connect() the phy is in
READY state, and you can access it via ethtool.
--
Maxime
^ permalink raw reply
* Re: rx_dropped packets stop with tcpdump running
From: Eric Dumazet @ 2012-04-19 13:28 UTC (permalink / raw)
To: Marco Berizzi; +Cc: netdev
In-Reply-To: <1334841865.2395.177.camel@edumazet-glaptop>
On Thu, 2012-04-19 at 15:24 +0200, Eric Dumazet wrote:
> When linux receives a packet with no protocol handler, we increment the
> rx_dropped counter.
>
> When you start a tcpdump, all packets are handled, so we dont increment
> rx_dropped for this reason anymore.
>
>
Its done since 2.6.37 (commit caf586e5)
^ 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