* Re: [PATCH] act_mirred: cleanup and optimization
From: Patrick McHardy @ 2009-11-13 7:13 UTC (permalink / raw)
To: xiaosuo; +Cc: Jamal Hadi Salim, Stephen Hemminger, David S. Miller, netdev
In-Reply-To: <4AFCF06B.1090602@gmail.com>
Changli Gao wrote:
> act_mirred: cleanup and optimization.
>
> cleanup and optimization.
> 1. don't let go back using goto.
> 2. move checking if eaction is valid in tcf_mirred_init().
> 3. don't call skb_act_clone() until it is necessary.
> 4. one exit of the critical context.
> 5. allow eaction is TCA_INGRESS_MIRROR & TCA_INGRESS_REDIR.
>
> if (parm->ifindex) {
> - dev = __dev_get_by_index(&init_net, parm->ifindex);
> + dev = dev_get_by_index(&init_net, parm->ifindex);
> if (dev == NULL)
> return -ENODEV;
This change is not mentioned in the changelog and introduces a
leak. Please split your patches into reasonable portions doing
one change at a time.
^ permalink raw reply
* Re: [net-next-2.6 PATCH] net: fast consecutive name allocation
From: Eric Dumazet @ 2009-11-13 7:09 UTC (permalink / raw)
To: Stephen Hemminger; +Cc: Octavian Purdila, netdev
In-Reply-To: <20091112222608.79d90e9e@nehalam>
Stephen Hemminger a écrit :
> No one has give a reasonable use case for this network device name
> explosion, what is the benchmark doing this nosense, and how do I
> get paid to do it...
>
> But I have to say no for another reason. You cause the kernel to choose
> a different name for the case where a device is deleted or renamed.
> The old code would find and fill the hole when a new device was added.
>
> Since this is a semantic ABI change, the kind that drives users nuts.
>
Yes, I see your point Stephen, but it would be trivial to skip already
used devices as well with litle change.
^ permalink raw reply
* Re: Problem with VLANs and via-velocity driver
From: Patrick McHardy @ 2009-11-13 6:40 UTC (permalink / raw)
To: Kevin Shanahan; +Cc: netdev
In-Reply-To: <20091113033217.GQ838@cubit>
Kevin Shanahan wrote:
> Hi,
>
> I've had some problems with getting a fairly simple (I thought) VLAN
> configuration working with the on board Via NICs on my Via M700
> board. Looks like as soon as a tagged VLAN interface is added, the
> underlying "raw" (untagged) interface stops responding.
>
> ...
>
> A bit of searching found a few references to similar problems going
> back a few years (2005, 2007). Sounded like there were some driver
> issues, but it wasn't clear from the messages I found whether they
> were believed to be fixed or not. I tried the same test using a
> differnt NIC with the tg3 driver and there were no problems, so it
> looks to me like it's still a via-velocity issue. Unfortunately I
> don't have room to add NICs to this machine and need to use the on
> board Via hardware.
There's some special-casing for VID 0 in velocity_init_cam_filter().
Does "ip link add link eth0 type vlan id 0" make any difference?
If not, does "ip link set eth0 promisc on"?
^ permalink raw reply
* [PATCH] netfilter: nf_log: fix sleeping function called from invalid context in seq_show()
From: Wu Fengguang @ 2009-11-13 6:36 UTC (permalink / raw)
To: Patrick McHardy; +Cc: LKML, Yin, Kangkai, netdev
[ 171.925285] BUG: sleeping function called from invalid context at kernel/mutex.c:280
[ 171.925296] in_atomic(): 1, irqs_disabled(): 0, pid: 671, name: grep
[ 171.925306] 2 locks held by grep/671:
[ 171.925312] #0: (&p->lock){+.+.+.}, at: [<c10b8acd>] seq_read+0x25/0x36c
[ 171.925340] #1: (rcu_read_lock){.+.+..}, at: [<c1391dac>] seq_start+0x0/0x44
[ 171.925372] Pid: 671, comm: grep Not tainted 2.6.31.6-4-netbook #3
[ 171.925380] Call Trace:
[ 171.925398] [<c105104e>] ? __debug_show_held_locks+0x1e/0x20
[ 171.925414] [<c10264ac>] __might_sleep+0xfb/0x102
[ 171.925430] [<c1461521>] mutex_lock_nested+0x1c/0x2ad
[ 171.925444] [<c1391c9e>] seq_show+0x74/0x127
[ 171.925456] [<c10b8c5c>] seq_read+0x1b4/0x36c
[ 171.925469] [<c10b8aa8>] ? seq_read+0x0/0x36c
[ 171.925483] [<c10d5c8e>] proc_reg_read+0x60/0x74
[ 171.925496] [<c10d5c2e>] ? proc_reg_read+0x0/0x74
[ 171.925510] [<c10a4468>] vfs_read+0x87/0x110
[ 171.925523] [<c10a458a>] sys_read+0x3b/0x60
[ 171.925538] [<c1002a49>] syscall_call+0x7/0xb
Fix it by replacing RCU with nf_log_mutex.
CC: Patrick McHardy <kaber@trash.net>
Reported-by: "Yin, Kangkai" <kangkai.yin@intel.com>
Signed-off-by: Wu Fengguang <fengguang.wu@intel.com>
---
net/netfilter/nf_log.c | 18 +++++-------------
1 file changed, 5 insertions(+), 13 deletions(-)
--- sound-2.6.orig/net/netfilter/nf_log.c 2009-11-13 13:47:14.000000000 +0800
+++ sound-2.6/net/netfilter/nf_log.c 2009-11-13 13:49:23.000000000 +0800
@@ -128,9 +128,8 @@ EXPORT_SYMBOL(nf_log_packet);
#ifdef CONFIG_PROC_FS
static void *seq_start(struct seq_file *seq, loff_t *pos)
- __acquires(RCU)
{
- rcu_read_lock();
+ mutex_lock(&nf_log_mutex);
if (*pos >= ARRAY_SIZE(nf_loggers))
return NULL;
@@ -149,9 +148,8 @@ static void *seq_next(struct seq_file *s
}
static void seq_stop(struct seq_file *s, void *v)
- __releases(RCU)
{
- rcu_read_unlock();
+ mutex_unlock(&nf_log_mutex);
}
static int seq_show(struct seq_file *s, void *v)
@@ -161,7 +159,7 @@ static int seq_show(struct seq_file *s,
struct nf_logger *t;
int ret;
- logger = rcu_dereference(nf_loggers[*pos]);
+ logger = nf_loggers[*pos];
if (!logger)
ret = seq_printf(s, "%2lld NONE (", *pos);
@@ -171,22 +169,16 @@ static int seq_show(struct seq_file *s,
if (ret < 0)
return ret;
- mutex_lock(&nf_log_mutex);
list_for_each_entry(t, &nf_loggers_l[*pos], list[*pos]) {
ret = seq_printf(s, "%s", t->name);
- if (ret < 0) {
- mutex_unlock(&nf_log_mutex);
+ if (ret < 0)
return ret;
- }
if (&t->list[*pos] != nf_loggers_l[*pos].prev) {
ret = seq_printf(s, ",");
- if (ret < 0) {
- mutex_unlock(&nf_log_mutex);
+ if (ret < 0)
return ret;
- }
}
}
- mutex_unlock(&nf_log_mutex);
return seq_printf(s, ")\n");
}
^ permalink raw reply
* (unknown)
From: Wu Fengguang @ 2009-11-13 6:35 UTC (permalink / raw)
To: Patrick McHardy; +Cc: LKML, Yin, Kangkai, netdev
netfilter: nf_log: fix sleeping function called from invalid context in seq_show()
[ 171.925285] BUG: sleeping function called from invalid context at kernel/mutex.c:280
[ 171.925296] in_atomic(): 1, irqs_disabled(): 0, pid: 671, name: grep
[ 171.925306] 2 locks held by grep/671:
[ 171.925312] #0: (&p->lock){+.+.+.}, at: [<c10b8acd>] seq_read+0x25/0x36c
[ 171.925340] #1: (rcu_read_lock){.+.+..}, at: [<c1391dac>] seq_start+0x0/0x44
[ 171.925372] Pid: 671, comm: grep Not tainted 2.6.31.6-4-netbook #3
[ 171.925380] Call Trace:
[ 171.925398] [<c105104e>] ? __debug_show_held_locks+0x1e/0x20
[ 171.925414] [<c10264ac>] __might_sleep+0xfb/0x102
[ 171.925430] [<c1461521>] mutex_lock_nested+0x1c/0x2ad
[ 171.925444] [<c1391c9e>] seq_show+0x74/0x127
[ 171.925456] [<c10b8c5c>] seq_read+0x1b4/0x36c
[ 171.925469] [<c10b8aa8>] ? seq_read+0x0/0x36c
[ 171.925483] [<c10d5c8e>] proc_reg_read+0x60/0x74
[ 171.925496] [<c10d5c2e>] ? proc_reg_read+0x0/0x74
[ 171.925510] [<c10a4468>] vfs_read+0x87/0x110
[ 171.925523] [<c10a458a>] sys_read+0x3b/0x60
[ 171.925538] [<c1002a49>] syscall_call+0x7/0xb
Fix it by replacing RCU with nf_log_mutex.
CC: Patrick McHardy <kaber@trash.net>
Reported-by: "Yin, Kangkai" <kangkai.yin@intel.com>
Signed-off-by: Wu Fengguang <fengguang.wu@intel.com>
---
net/netfilter/nf_log.c | 18 +++++-------------
1 file changed, 5 insertions(+), 13 deletions(-)
--- sound-2.6.orig/net/netfilter/nf_log.c 2009-11-13 13:47:14.000000000 +0800
+++ sound-2.6/net/netfilter/nf_log.c 2009-11-13 13:49:23.000000000 +0800
@@ -128,9 +128,8 @@ EXPORT_SYMBOL(nf_log_packet);
#ifdef CONFIG_PROC_FS
static void *seq_start(struct seq_file *seq, loff_t *pos)
- __acquires(RCU)
{
- rcu_read_lock();
+ mutex_lock(&nf_log_mutex);
if (*pos >= ARRAY_SIZE(nf_loggers))
return NULL;
@@ -149,9 +148,8 @@ static void *seq_next(struct seq_file *s
}
static void seq_stop(struct seq_file *s, void *v)
- __releases(RCU)
{
- rcu_read_unlock();
+ mutex_unlock(&nf_log_mutex);
}
static int seq_show(struct seq_file *s, void *v)
@@ -161,7 +159,7 @@ static int seq_show(struct seq_file *s,
struct nf_logger *t;
int ret;
- logger = rcu_dereference(nf_loggers[*pos]);
+ logger = nf_loggers[*pos];
if (!logger)
ret = seq_printf(s, "%2lld NONE (", *pos);
@@ -171,22 +169,16 @@ static int seq_show(struct seq_file *s,
if (ret < 0)
return ret;
- mutex_lock(&nf_log_mutex);
list_for_each_entry(t, &nf_loggers_l[*pos], list[*pos]) {
ret = seq_printf(s, "%s", t->name);
- if (ret < 0) {
- mutex_unlock(&nf_log_mutex);
+ if (ret < 0)
return ret;
- }
if (&t->list[*pos] != nf_loggers_l[*pos].prev) {
ret = seq_printf(s, ",");
- if (ret < 0) {
- mutex_unlock(&nf_log_mutex);
+ if (ret < 0)
return ret;
- }
}
}
- mutex_unlock(&nf_log_mutex);
return seq_printf(s, ")\n");
}
^ permalink raw reply
* Re: [net-next-2.6 PATCH v6 4/7 RFC] TCPCT part 1d: define TCP cookie option, extend existing struct's
From: Eric Dumazet @ 2009-11-13 6:32 UTC (permalink / raw)
To: William Allen Simpson; +Cc: Linux Kernel Network Developers
In-Reply-To: <4AFCE65C.2010104@gmail.com>
William Allen Simpson a écrit :
> Data structures are carefully composed to require minimal additions.
> For example, the struct tcp_options_received cookie_plus variable fits
> between existing 16-bit and 8-bit variables, requiring no additional
> space (taking alignment into consideration). There are no additions to
> tcp_request_sock, and only 1 pointer in tcp_sock.
>
> This is a significantly revised implementation of an earlier (year-old)
> patch that no longer applies cleanly, with permission of the original
> author (Adam Langley):
>
> http://thread.gmane.org/gmane.linux.network/102586
>
> The principle difference is using a TCP option to carry the cookie nonce,
> instead of a user configured offset in the data. This is more flexible and
> less subject to user configuration error. Such a cookie option has been
> suggested for many years, and is also useful without SYN data, allowing
> several related concepts to use the same extension option.
>
> "Re: SYN floods (was: does history repeat itself?)", September 9, 1996.
> http://www.merit.net/mail.archives/nanog/1996-09/msg00235.html
>
> "Re: what a new TCP header might look like", May 12, 1998.
> ftp://ftp.isi.edu/end2end/end2end-interest-1998.mail
>
> These functions will also be used in subsequent patches that implement
> additional features.
>
> Requires:
> TCPCT part 1a: add request_values parameter for sending SYNACK
> TCPCT part 1b: generate Responder Cookie
> TCPCT part 1c: sysctl_tcp_cookie_size, socket option
> TCP_COOKIE_TRANSACTIONS
>
> Signed-off-by: William.Allen.Simpson@gmail.com
> ---
> include/linux/tcp.h | 29 ++++++++++++++++----
> include/net/tcp.h | 72
> +++++++++++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 95 insertions(+), 6 deletions(-)
>
+/**
+ * A tcp_sock contains a pointer to the current value, and this is cloned to
+ * the tcp_timewait_sock.
+ *
+ * @cookie_pair: variable data from the option exchange.
+ *
+ * @cookie_desired: user specified tcpct_cookie_desired. Zero
+ * indicates default (sysctl_tcp_cookie_size).
+ * After cookie sent, remembers size of cookie.
+ * Range 0, TCP_COOKIE_MIN to TCP_COOKIE_MAX.
+ *
+ * @s_data_desired: user specified tcpct_s_data_desired. When the
+ * constant payload is specified (@s_data_constant),
+ * holds its length instead.
+ * Range 0 to TCP_MSS_DESIRED.
+ *
+ * @s_data_payload: constant data that is to be included in the
+ * payload of SYN or SYNACK segments when the
+ * cookie option is present.
+ */
Thanks for this kerneldoc William ;)
But header should be :
/**
* struct tcp_cookie_values - Some description...
^ permalink raw reply
* Re: [net-next-2.6 PATCH v6 2/7 RFC] TCPCT part 1b: generate Responder Cookie
From: Joe Perches @ 2009-11-13 6:26 UTC (permalink / raw)
To: William Allen Simpson; +Cc: Linux Kernel Network Developers
In-Reply-To: <4AFCDDC4.1090606@gmail.com>
On Thu, 2009-11-12 at 23:17 -0500, William Allen Simpson wrote:
> +int tcp_cookie_generator(u32 *bakery)
> +{
> + unsigned long jiffy = jiffies;
> +
> + if (unlikely(time_after_eq(jiffy, tcp_secret_generating->expires))) {
> + spin_lock_bh(&tcp_secret_locker);
> + if (!time_after_eq(jiffy, tcp_secret_generating->expires)) {
> + /* refreshed by another */
> + spin_unlock_bh(&tcp_secret_locker);
> + memcpy(bakery,
> + &tcp_secret_generating->secrets[0],
> + sizeof(tcp_secret_generating->secrets));
> + } else {
> + u32 secrets[COOKIE_WORKSPACE_WORDS];
Rather than using stack, could you use
u32 *secrets = &tcp_secret_secondary->secrets[0];
^ permalink raw reply
* Re: [net-next-2.6 PATCH] net: fast consecutive name allocation
From: Stephen Hemminger @ 2009-11-13 6:26 UTC (permalink / raw)
To: Eric Dumazet; +Cc: Octavian Purdila, netdev
In-Reply-To: <4AFCF8D3.6090905@gmail.com>
On Fri, 13 Nov 2009 07:12:35 +0100
Eric Dumazet <eric.dumazet@gmail.com> wrote:
> Octavian Purdila a écrit :
> > On Friday 13 November 2009 07:01:14 you wrote:
> >> This patch speeds up the network device name allocation for the case
> >> where a significant number of devices of the same type are created
> >> consecutively.
> >>
> >> Tests performed on a PPC750 @ 800Mhz machine with per device sysctl
> >> and sysfs entries disabled:
> >>
> >> Without the patch With the patch
> >>
> >> real 0m 43.43s real 0m 0.49s
> >> user 0m 0.00s user 0m 0.00s
> >> sys 0m 43.43s sys 0m 0.48s
> >>
> >
No one has give a reasonable use case for this network device name
explosion, what is the benchmark doing this nosense, and how do I
get paid to do it...
But I have to say no for another reason. You cause the kernel to choose
a different name for the case where a device is deleted or renamed.
The old code would find and fill the hole when a new device was added.
Since this is a semantic ABI change, the kind that drives users nuts.
--
^ permalink raw reply
* Re: [net-next-2.6 PATCH v6 2/7 RFC] TCPCT part 1b: generate Responder Cookie
From: Eric Dumazet @ 2009-11-13 6:21 UTC (permalink / raw)
To: William Allen Simpson; +Cc: Linux Kernel Network Developers
In-Reply-To: <4AFCDDC4.1090606@gmail.com>
William Allen Simpson a écrit :
> Define (missing) hash message size for SHA1.
>
> Define hashing size constants specific to TCP cookies, and add new
> function.
>
> Maintain global secret values for tcp_cookie_generator().
>
> This is a significantly revised implementation of earlier (15-year-old)
> Photuris [RFC-2522] code for the KA9Q cooperative multitasking platform.
>
> Linux RCU technique appears to be well-suited to this application, though
> neither of the circular queue items are freed.
>
> These functions will also be used in subsequent patches that implement
> additional features.
>
> Signed-off-by: William.Allen.Simpson@gmail.com
> ---
> include/linux/cryptohash.h | 1 +
> include/net/tcp.h | 8 +++
> net/ipv4/tcp.c | 146
> ++++++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 155 insertions(+), 0 deletions(-)
>
Small point :
+ if (unlikely(time_after_eq(jiffy, tcp_secret_generating->expires))) {
+ spin_lock_bh(&tcp_secret_locker);
+ if (!time_after_eq(jiffy, tcp_secret_generating->expires)) {
+ /* refreshed by another */
+ spin_unlock_bh(&tcp_secret_locker);
+ memcpy(bakery,
+ &tcp_secret_generating->secrets[0],
+ sizeof(tcp_secret_generating->secrets));
Technically speaking, you should perform the memcpy() before spin_unlock_bh()
+ if (unlikely(time_after_eq(jiffy, tcp_secret_generating->expires))) {
+ spin_lock_bh(&tcp_secret_locker);
+ if (!time_after_eq(jiffy, tcp_secret_generating->expires)) {
+ /* refreshed by another */
+ memcpy(bakery,
+ &tcp_secret_generating->secrets[0],
+ sizeof(tcp_secret_generating->secrets));
+ spin_unlock_bh(&tcp_secret_locker);
^ permalink raw reply
* Re: [PATCH] ifb: add multi-queue support
From: Changli Gao @ 2009-11-13 6:16 UTC (permalink / raw)
To: Eric Dumazet
Cc: David S. Miller, Stephen Hemminger, Patrick McHardy, Tom Herbert,
netdev
In-Reply-To: <4AFCF50D.6040106@gmail.com>
2009/11/13 Eric Dumazet <eric.dumazet@gmail.com>:
>
> Messy ? Because of few tests added in code, and branches always
> correctly predicted ?
>
> Still some people might rely on tasklet instead of workqueues
> and added scheduler stress and latency penalty. Tasklet are softirq
> and normally are processed a few nanosecs later than RX softirq,
> on the same CPU, while with your workqueue, I guess the scheduler will
> try to not migrate it, so we add a penalty for light to moderate load.
>
> I guess this new ifb mode would be a regression for them ?
>
> If you dont want to maintain a compatibility mode, maybe you
> should introduce a complete new driver, drivers/net/ifbmq.c or ifbwq.c
>
> (multiqueue or workqueue references)
>
It sounds a good idea.
--
Regards,
Changli Gao(xiaosuo@gmail.com)
^ permalink raw reply
* Re: [net-next-2.6 PATCH] net: fast consecutive name allocation
From: Eric Dumazet @ 2009-11-13 6:12 UTC (permalink / raw)
To: Octavian Purdila; +Cc: netdev
In-Reply-To: <200911130720.19671.opurdila@ixiacom.com>
Octavian Purdila a écrit :
> On Friday 13 November 2009 07:01:14 you wrote:
>> This patch speeds up the network device name allocation for the case
>> where a significant number of devices of the same type are created
>> consecutively.
>>
>> Tests performed on a PPC750 @ 800Mhz machine with per device sysctl
>> and sysfs entries disabled:
>>
>> Without the patch With the patch
>>
>> real 0m 43.43s real 0m 0.49s
>> user 0m 0.00s user 0m 0.00s
>> sys 0m 43.43s sys 0m 0.48s
>>
>
> Oops, pasting root prompts (e.g. # modprobe ....) directly into the git commit message is not a good idea :) Here it is again, with the full commit message.
>
> [net-next-2.6 PATCH] net: fast consecutive name allocation
>
> This patch speeds up the network device name allocation for the case
> where a significant number of devices of the same type are created
> consecutively.
>
> Tests performed on a PPC750 @ 800Mhz machine with per device sysctl
> and sysfs entries disabled:
>
> $ time insmod /lib/modules/dummy.ko numdummies=8000
>
> Without the patch With the patch
>
> real 0m 43.43s real 0m 0.49s
> user 0m 0.00s user 0m 0.00s
> sys 0m 43.43s sys 0m 0.48s
>
> Signed-off-by: Octavian Purdila <opurdila@ixiacom.com>
> ---
Honestly I dont like this bloat.
Changing dummy.c is trivial, and you can allocate 100.000.000 dummies if you want now :)
I not tested yet this patch but here it is :
[PATCH] dummy: Allow more than 32768 dummies
And speedup name allocation : O(N) instead of O(N^2)
Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
---
drivers/net/dummy.c | 8 +++++---
1 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/drivers/net/dummy.c b/drivers/net/dummy.c
index 37dcfdc..f600c4c 100644
--- a/drivers/net/dummy.c
+++ b/drivers/net/dummy.c
@@ -107,12 +107,14 @@ static struct rtnl_link_ops dummy_link_ops __read_mostly = {
module_param(numdummies, int, 0);
MODULE_PARM_DESC(numdummies, "Number of dummy pseudo devices");
-static int __init dummy_init_one(void)
+static int __init dummy_init_one(int i)
{
struct net_device *dev_dummy;
int err;
+ char name[IFNAMSIZ];
- dev_dummy = alloc_netdev(0, "dummy%d", dummy_setup);
+ snprintf(name, IFNAMSIZ, "dummy%d", i);
+ dev_dummy = alloc_netdev(0, name, dummy_setup);
if (!dev_dummy)
return -ENOMEM;
@@ -139,7 +141,7 @@ static int __init dummy_init_module(void)
err = __rtnl_link_register(&dummy_link_ops);
for (i = 0; i < numdummies && !err; i++)
- err = dummy_init_one();
+ err = dummy_init_one(i);
if (err < 0)
__rtnl_link_unregister(&dummy_link_ops);
rtnl_unlock();
^ permalink raw reply related
* Re: [PATCH] ifb: add multi-queue support
From: Eric Dumazet @ 2009-11-13 5:56 UTC (permalink / raw)
To: Changli Gao
Cc: David S. Miller, Stephen Hemminger, Patrick McHardy, Tom Herbert,
netdev
In-Reply-To: <412e6f7f0911121726t47874807g2223d2f1141818f5@mail.gmail.com>
Changli Gao a écrit :
> 2009/11/12 Eric Dumazet <eric.dumazet@gmail.com>:
>> I believe this patch is fine, but maybe Jarek concern about workqueue
>> vs tasklet should be addressed...
>>
>> We could use the previous handling in case numtxqs==1 , ie use a tasklet
>> instead of a work queue ?
>
> I don't think it is a good idea. If we do so, the code will be messy,
> and lost the flexibility of process. In fact, latency isn't a problem
> when system load isn't high, and when system load is high (due to too
> many NIC IRQs), throughput and interaction is more important, and the
> current linux networking subsystem just dose so through the softirqd
> mechanism.
>
Messy ? Because of few tests added in code, and branches always
correctly predicted ?
Still some people might rely on tasklet instead of workqueues
and added scheduler stress and latency penalty. Tasklet are softirq
and normally are processed a few nanosecs later than RX softirq,
on the same CPU, while with your workqueue, I guess the scheduler will
try to not migrate it, so we add a penalty for light to moderate load.
I guess this new ifb mode would be a regression for them ?
If you dont want to maintain a compatibility mode, maybe you
should introduce a complete new driver, drivers/net/ifbmq.c or ifbwq.c
(multiqueue or workqueue references)
^ permalink raw reply
* [net-next-2.6 PATCH v6 7/7 RFC] TCPCT part 1g: Responder Cookie => Initiator
From: William Allen Simpson @ 2009-11-13 5:53 UTC (permalink / raw)
To: Linux Kernel Network Developers
In-Reply-To: <4AFCDA9E.8050003@gmail.com>
[-- Attachment #1: Type: text/plain, Size: 1264 bytes --]
Calculate and format TCP_COOKIE SYNACK option.
Process optional SYNACK data.
This is a significantly revised implementation of an earlier (year-old)
patch that no longer applies cleanly, with permission of the original
author (Adam Langley):
http://thread.gmane.org/gmane.linux.network/102586
Requires:
TCPCT part 1a: add request_values parameter for sending SYNACK
TCPCT part 1b: generate Responder Cookie
TCPCT part 1c: sysctl_tcp_cookie_size, socket option TCP_COOKIE_TRANSACTIONS
TCPCT part 1d: define TCP cookie option, extend existing struct's
TCPCT part 1e: implement socket option TCP_COOKIE_TRANSACTIONS
TCPCT part 1f: Initiator Cookie => Responder
Signed-off-by: William.Allen.Simpson@gmail.com
---
include/linux/tcp.h | 11 ++++++
include/net/tcp.h | 1 +
net/ipv4/syncookies.c | 5 ++-
net/ipv4/tcp_input.c | 84 ++++++++++++++++++++++++++++++++++++++++------
net/ipv4/tcp_ipv4.c | 46 +++++++++++++++++++++++--
net/ipv4/tcp_minisocks.c | 14 ++++---
net/ipv4/tcp_output.c | 75 ++++++++++++++++++++++++++++++++++++++--
net/ipv6/syncookies.c | 5 ++-
net/ipv6/tcp_ipv6.c | 51 +++++++++++++++++++++++++++-
9 files changed, 261 insertions(+), 31 deletions(-)
[-- Attachment #2: TCPCT+1g6.patch --]
[-- Type: text/plain, Size: 18598 bytes --]
diff --git a/include/linux/tcp.h b/include/linux/tcp.h
index 6c5ff66..bbedc80 100644
--- a/include/linux/tcp.h
+++ b/include/linux/tcp.h
@@ -223,6 +223,17 @@ static inline unsigned int tcp_optlen(const struct sk_buff *skb)
return (tcp_hdr(skb)->doff - 5) * 4;
}
+static inline unsigned int tcp_header_len_th(const struct tcphdr *th)
+{
+ return th->doff * 4;
+}
+
+/* When doff is bad, this could be negative. */
+static inline int tcp_option_len_th(const struct tcphdr *th)
+{
+ return (int)(th->doff * 4) - sizeof(*th);
+}
+
/* This defines a selective acknowledgement block. */
struct tcp_sack_block_wire {
__be32 start_seq;
diff --git a/include/net/tcp.h b/include/net/tcp.h
index 3a4c840..14796c4 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -407,6 +407,7 @@ extern int tcp_recvmsg(struct kiocb *iocb, struct sock *sk,
extern void tcp_parse_options(struct sk_buff *skb,
struct tcp_options_received *opt_rx,
+ u8 **hvpp,
int estab,
struct dst_entry *dst);
diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c
index 3146cc4..26399ad 100644
--- a/net/ipv4/syncookies.c
+++ b/net/ipv4/syncookies.c
@@ -253,6 +253,8 @@ EXPORT_SYMBOL(cookie_check_timestamp);
struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb,
struct ip_options *opt)
{
+ struct tcp_options_received tcp_opt;
+ u8 *hash_location;
struct inet_request_sock *ireq;
struct tcp_request_sock *treq;
struct tcp_sock *tp = tcp_sk(sk);
@@ -263,7 +265,6 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb,
int mss;
struct rtable *rt;
__u8 rcv_wscale;
- struct tcp_options_received tcp_opt;
if (!sysctl_tcp_syncookies || !th->ack)
goto out;
@@ -341,7 +342,7 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb,
/* check for timestamp cookie support */
memset(&tcp_opt, 0, sizeof(tcp_opt));
- tcp_parse_options(skb, &tcp_opt, 0, &rt->u.dst);
+ tcp_parse_options(skb, &tcp_opt, &hash_location, 0, &rt->u.dst);
if (tcp_opt.saw_tstamp)
cookie_check_timestamp(&tcp_opt);
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index cc306ac..104fe2d 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -3698,7 +3698,7 @@ old_ack:
* the fast version below fails.
*/
void tcp_parse_options(struct sk_buff *skb, struct tcp_options_received *opt_rx,
- int estab, struct dst_entry *dst)
+ u8 **hvpp, int estab, struct dst_entry *dst)
{
unsigned char *ptr;
struct tcphdr *th = tcp_hdr(skb);
@@ -3785,6 +3785,19 @@ void tcp_parse_options(struct sk_buff *skb, struct tcp_options_received *opt_rx,
*/
break;
#endif
+ case TCPOPT_COOKIE:
+ /* This option carries 3 different lengths.
+ */
+ if (TCPOLEN_COOKIE_MAX >= opsize
+ && TCPOLEN_COOKIE_MIN <= opsize) {
+ opt_rx->cookie_plus = opsize;
+ *hvpp = ptr;
+ } else if (TCPOLEN_COOKIE_PAIR == opsize) {
+ /* not yet implemented */
+ } else if (TCPOLEN_COOKIE_BASE == opsize) {
+ /* not yet implemented */
+ }
+ break;
}
ptr += opsize-2;
@@ -3813,17 +3826,20 @@ static int tcp_parse_aligned_timestamp(struct tcp_sock *tp, struct tcphdr *th)
* If it is wrong it falls back on tcp_parse_options().
*/
static int tcp_fast_parse_options(struct sk_buff *skb, struct tcphdr *th,
- struct tcp_sock *tp)
+ struct tcp_sock *tp, u8 **hvpp)
{
- if (th->doff == sizeof(struct tcphdr) >> 2) {
+ /* In the spirit of fast parsing, compare doff directly to constant
+ * values. Because equality is used, short doff can be ignored here.
+ */
+ if (th->doff == (sizeof(*th) / 4)) {
tp->rx_opt.saw_tstamp = 0;
return 0;
} else if (tp->rx_opt.tstamp_ok &&
- th->doff == (sizeof(struct tcphdr)>>2)+(TCPOLEN_TSTAMP_ALIGNED>>2)) {
+ th->doff == ((sizeof(*th) + TCPOLEN_TSTAMP_ALIGNED) / 4)) {
if (tcp_parse_aligned_timestamp(tp, th))
return 1;
}
- tcp_parse_options(skb, &tp->rx_opt, 1, NULL);
+ tcp_parse_options(skb, &tp->rx_opt, hvpp, 1, NULL);
return 1;
}
@@ -5077,11 +5093,13 @@ out:
static int tcp_validate_incoming(struct sock *sk, struct sk_buff *skb,
struct tcphdr *th, int syn_inerr)
{
+ u8 *hash_location;
struct tcp_sock *tp = tcp_sk(sk);
/* RFC1323: H1. Apply PAWS check first. */
- if (tcp_fast_parse_options(skb, th, tp) && tp->rx_opt.saw_tstamp &&
- tcp_paws_discard(sk, skb)) {
+ if (tcp_fast_parse_options(skb, th, tp, &hash_location)
+ && tp->rx_opt.saw_tstamp
+ && tcp_paws_discard(sk, skb)) {
if (!th->rst) {
NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_PAWSESTABREJECTED);
tcp_send_dupack(sk, skb);
@@ -5368,12 +5386,15 @@ discard:
static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb,
struct tcphdr *th, unsigned len)
{
- struct tcp_sock *tp = tcp_sk(sk);
+ u8 *hash_location;
struct inet_connection_sock *icsk = inet_csk(sk);
- int saved_clamp = tp->rx_opt.mss_clamp;
+ struct tcp_sock *tp = tcp_sk(sk);
struct dst_entry *dst = __sk_dst_get(sk);
+ struct tcp_cookie_values *cvp = tp->cookie_values;
+ int saved_clamp = tp->rx_opt.mss_clamp;
+ int queued = 0;
- tcp_parse_options(skb, &tp->rx_opt, 0, dst);
+ tcp_parse_options(skb, &tp->rx_opt, &hash_location, 0, dst);
if (th->ack) {
/* rfc793:
@@ -5470,6 +5491,44 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb,
* Change state from SYN-SENT only after copied_seq
* is initialized. */
tp->copied_seq = tp->rcv_nxt;
+
+ if (cvp != NULL
+ && cvp->cookie_pair_size > 0
+ && tp->rx_opt.cookie_plus > 0) {
+ int cookie_size = tp->rx_opt.cookie_plus
+ - TCPOLEN_COOKIE_BASE;
+ int cookie_pair_size = cookie_size
+ + cvp->cookie_desired;
+
+ /* A cookie extension option was sent and returned.
+ * Note that each incoming SYNACK replaces the
+ * Responder cookie. The initial exchange is most
+ * fragile, as protection against spoofing relies
+ * entirely upon the sequence and timestamp (above).
+ * This replacement strategy allows the correct pair to
+ * pass through, while any others will be filtered via
+ * Responder verification later.
+ */
+ if (sizeof(cvp->cookie_pair) >= cookie_pair_size) {
+ memcpy(&cvp->cookie_pair[cvp->cookie_desired],
+ hash_location, cookie_size);
+ cvp->cookie_pair_size = cookie_pair_size;
+ }
+
+ if (tcp_header_len_th(th) < skb->len) {
+ /* Queue incoming transaction data. */
+ __skb_pull(skb, tcp_header_len_th(th));
+ __skb_queue_tail(&sk->sk_receive_queue, skb);
+ skb_set_owner_r(skb, sk);
+ sk->sk_data_ready(sk, 0);
+ cvp->s_data_in = 1; /* true */
+ queued = 1; /* should be amount? */
+ tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq;
+ tp->rcv_wup = TCP_SKB_CB(skb)->end_seq;
+ tp->copied_seq = TCP_SKB_CB(skb)->seq + 1;
+ }
+ }
+
smp_mb();
tcp_set_state(sk, TCP_ESTABLISHED);
@@ -5521,11 +5580,14 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb,
TCP_DELACK_MAX, TCP_RTO_MAX);
discard:
- __kfree_skb(skb);
+ if (queued == 0)
+ __kfree_skb(skb);
return 0;
} else {
tcp_send_ack(sk);
}
+ if (queued > 0)
+ return 0; /* amount queued? */
return -1;
}
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 2ae1985..1597b66 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -1213,9 +1213,12 @@ static struct timewait_sock_ops tcp_timewait_sock_ops = {
int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
{
+ struct tcp_extend_values tmp_ext;
struct tcp_options_received tmp_opt;
+ u8 *hash_location;
struct request_sock *req;
struct inet_request_sock *ireq;
+ struct tcp_sock *tp = tcp_sk(sk);
struct dst_entry *dst = NULL;
__be32 saddr = ip_hdr(skb)->saddr;
__be32 daddr = ip_hdr(skb)->daddr;
@@ -1271,15 +1274,49 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
tcp_clear_options(&tmp_opt);
tmp_opt.mss_clamp = TCP_MSS_DEFAULT;
- tmp_opt.user_mss = tcp_sk(sk)->rx_opt.user_mss;
+ tmp_opt.user_mss = tp->rx_opt.user_mss;
+ tcp_parse_options(skb, &tmp_opt, &hash_location, 0, dst);
+
+ if (tmp_opt.cookie_plus > 0
+ && tmp_opt.saw_tstamp
+ && !tp->rx_opt.cookie_out_never
+ && (sysctl_tcp_cookie_size > 0
+ || (tp->cookie_values != NULL
+ && tp->cookie_values->cookie_desired > 0))) {
+ u8 *c;
+ u32 *mess = &tmp_ext.cookie_bakery[COOKIE_DIGEST_WORDS];
+ int l = tmp_opt.cookie_plus - TCPOLEN_COOKIE_BASE;
+
+ if (tcp_cookie_generator(&tmp_ext.cookie_bakery[0]) != 0)
+ goto drop_and_release;
+
+ /* Secret recipe starts with IP addresses */
+ *mess++ ^= daddr;
+ *mess++ ^= saddr;
- tcp_parse_options(skb, &tmp_opt, 0, dst);
+ /* plus variable length Initiator Cookie */
+ c = (u8 *)mess;
+ while (l-- > 0)
+ *c++ ^= *hash_location++;
+
+#ifdef CONFIG_SYN_COOKIES
+ want_cookie = 0; /* not our kind of cookie */
+#endif
+ tmp_ext.cookie_out_never = 0; /* false */
+ tmp_ext.cookie_plus = tmp_opt.cookie_plus;
+ } else if (!tp->rx_opt.cookie_in_always) {
+ /* redundant indications, but ensure initialization. */
+ tmp_ext.cookie_out_never = 1; /* true */
+ tmp_ext.cookie_plus = 0;
+ } else {
+ goto drop_and_release;
+ }
+ tmp_ext.cookie_in_always = tp->rx_opt.cookie_in_always;
if (want_cookie && !tmp_opt.saw_tstamp)
tcp_clear_options(&tmp_opt);
tmp_opt.tstamp_ok = tmp_opt.saw_tstamp;
-
tcp_openreq_init(req, &tmp_opt, skb);
if (security_inet_conn_request(sk, skb, req))
@@ -1339,7 +1376,8 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
}
tcp_rsk(req)->snt_isn = isn;
- if (__tcp_v4_send_synack(sk, dst, req, NULL)
+ if (__tcp_v4_send_synack(sk, dst, req,
+ (struct request_values *)&tmp_ext)
|| want_cookie)
goto drop_and_free;
diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c
index 2b50da8..7b01ea0 100644
--- a/net/ipv4/tcp_minisocks.c
+++ b/net/ipv4/tcp_minisocks.c
@@ -96,13 +96,14 @@ enum tcp_tw_status
tcp_timewait_state_process(struct inet_timewait_sock *tw, struct sk_buff *skb,
const struct tcphdr *th)
{
- struct tcp_timewait_sock *tcptw = tcp_twsk((struct sock *)tw);
struct tcp_options_received tmp_opt;
+ u8 *hash_location;
+ struct tcp_timewait_sock *tcptw = tcp_twsk((struct sock *)tw);
int paws_reject = 0;
if (th->doff > (sizeof(*th) >> 2) && tcptw->tw_ts_recent_stamp) {
tmp_opt.tstamp_ok = 1;
- tcp_parse_options(skb, &tmp_opt, 1, NULL);
+ tcp_parse_options(skb, &tmp_opt, &hash_location, 1, NULL);
if (tmp_opt.saw_tstamp) {
tmp_opt.ts_recent = tcptw->tw_ts_recent;
@@ -523,15 +524,16 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb,
struct request_sock *req,
struct request_sock **prev)
{
+ struct tcp_options_received tmp_opt;
+ u8 *hash_location;
+ struct sock *child;
const struct tcphdr *th = tcp_hdr(skb);
__be32 flg = tcp_flag_word(th) & (TCP_FLAG_RST|TCP_FLAG_SYN|TCP_FLAG_ACK);
int paws_reject = 0;
- struct tcp_options_received tmp_opt;
- struct sock *child;
- if ((th->doff > (sizeof(struct tcphdr)>>2)) && (req->ts_recent)) {
+ if ((th->doff > (sizeof(*th) >> 2)) && (req->ts_recent)) {
tmp_opt.tstamp_ok = 1;
- tcp_parse_options(skb, &tmp_opt, 1, NULL);
+ tcp_parse_options(skb, &tmp_opt, &hash_location, 1, NULL);
if (tmp_opt.saw_tstamp) {
tmp_opt.ts_recent = req->ts_recent;
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index e1553d3..18708d3 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -661,9 +661,14 @@ static unsigned tcp_synack_options(struct sock *sk,
struct request_sock *req,
unsigned mss, struct sk_buff *skb,
struct tcp_out_options *opts,
- struct tcp_md5sig_key **md5) {
- unsigned size = 0;
+ struct tcp_md5sig_key **md5,
+ struct tcp_extend_values *xvp)
+{
struct inet_request_sock *ireq = inet_rsk(req);
+ unsigned size = 0;
+ u8 cookie_plus = (xvp != NULL && !xvp->cookie_out_never)
+ ? xvp->cookie_plus
+ : 0;
char doing_ts;
#ifdef CONFIG_TCP_MD5SIG
@@ -702,6 +707,28 @@ static unsigned tcp_synack_options(struct sock *sk,
size += TCPOLEN_SACKPERM_ALIGNED;
}
+ /* Similar rationale to tcp_syn_options() applies here, too.
+ * If the <SYN> options fit, the same options should fit now!
+ */
+ if (*md5 == NULL
+ && doing_ts
+ && cookie_plus > TCPOLEN_COOKIE_BASE) {
+ int need = cookie_plus; /* has TCPOLEN_COOKIE_BASE */
+ int remaining = MAX_TCP_OPTION_SPACE - size;
+
+ if (0x2 & need) {
+ /* 32-bit multiple */
+ need += 2; /* NOPs */
+ }
+ if (need <= remaining) {
+ opts->options |= OPTION_COOKIE_EXTENSION;
+ opts->hash_size = cookie_plus - TCPOLEN_COOKIE_BASE;
+ size += need;
+ } else {
+ /* There's no error return, so flag it. */
+ xvp->cookie_out_never = 1; /* true */
+ }
+ }
return size;
}
@@ -2371,6 +2398,7 @@ struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst,
struct request_values *rvp)
{
struct tcp_out_options opts;
+ struct tcp_extend_values *xvp = tcp_xv(rvp);
struct inet_request_sock *ireq = inet_rsk(req);
struct tcp_sock *tp = tcp_sk(sk);
struct tcphdr *th;
@@ -2414,8 +2442,8 @@ struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst,
#endif
TCP_SKB_CB(skb)->when = tcp_time_stamp;
tcp_header_size = tcp_synack_options(sk, req, mss,
- skb, &opts, &md5) +
- sizeof(struct tcphdr);
+ skb, &opts, &md5, xvp)
+ + sizeof(*th);
skb_push(skb, tcp_header_size);
skb_reset_transport_header(skb);
@@ -2432,6 +2460,45 @@ struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst,
*/
tcp_init_nondata_skb(skb, tcp_rsk(req)->snt_isn,
TCPCB_FLAG_SYN | TCPCB_FLAG_ACK);
+
+ if (OPTION_COOKIE_EXTENSION & opts.options) {
+ const struct tcp_cookie_values *cvp = tp->cookie_values;
+
+ if (cvp != NULL
+ && cvp->s_data_constant
+ && cvp->s_data_desired > 0) {
+ u8 *buf = skb_put(skb, cvp->s_data_desired);
+
+ /* copy data directly from the listening socket. */
+ memcpy(buf, cvp->s_data_payload, cvp->s_data_desired);
+ TCP_SKB_CB(skb)->end_seq += cvp->s_data_desired;
+ }
+
+ if (opts.hash_size > 0) {
+ __u32 workspace[SHA_WORKSPACE_WORDS];
+ u32 *mess = &xvp->cookie_bakery[COOKIE_DIGEST_WORDS];
+ u32 *tail = &mess[COOKIE_MESSAGE_WORDS-1];
+
+ /* Secret recipe depends on the Timestamp, (future)
+ * Sequence and Acknowledgment Numbers, Initiator
+ * Cookie, and others handled by IP variant caller.
+ */
+ *tail-- ^= opts.tsval;
+ *tail-- ^= tcp_rsk(req)->rcv_isn + 1;
+ *tail-- ^= TCP_SKB_CB(skb)->seq + 1;
+
+ /* recommended */
+ *tail-- ^= ((th->dest << 16) | th->source);
+ *tail-- ^= (u32)cvp; /* per sockopt */
+
+ sha_transform((__u32 *)&xvp->cookie_bakery[0],
+ (char *)mess,
+ &workspace[0]);
+ opts.hash_location =
+ (__u8 *)&xvp->cookie_bakery[0];
+ }
+ }
+
th->seq = htonl(TCP_SKB_CB(skb)->seq);
th->ack_seq = htonl(tcp_rsk(req)->rcv_isn + 1);
diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c
index 612fc53..5b9af50 100644
--- a/net/ipv6/syncookies.c
+++ b/net/ipv6/syncookies.c
@@ -159,6 +159,8 @@ static inline int cookie_check(struct sk_buff *skb, __u32 cookie)
struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb)
{
+ struct tcp_options_received tcp_opt;
+ u8 *hash_location;
struct inet_request_sock *ireq;
struct inet6_request_sock *ireq6;
struct tcp_request_sock *treq;
@@ -171,7 +173,6 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb)
int mss;
struct dst_entry *dst;
__u8 rcv_wscale;
- struct tcp_options_received tcp_opt;
if (!sysctl_tcp_syncookies || !th->ack)
goto out;
@@ -254,7 +255,7 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb)
/* check for timestamp cookie support */
memset(&tcp_opt, 0, sizeof(tcp_opt));
- tcp_parse_options(skb, &tcp_opt, 0, dst);
+ tcp_parse_options(skb, &tcp_opt, &hash_location, 0, dst);
if (tcp_opt.saw_tstamp)
cookie_check_timestamp(&tcp_opt);
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 2b16f9a..5005ba2 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -1162,7 +1162,9 @@ static struct sock *tcp_v6_hnd_req(struct sock *sk,struct sk_buff *skb)
*/
static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
{
+ struct tcp_extend_values tmp_ext;
struct tcp_options_received tmp_opt;
+ u8 *hash_location;
struct request_sock *req;
struct inet6_request_sock *treq;
struct ipv6_pinfo *np = inet6_sk(sk);
@@ -1206,8 +1208,52 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
tcp_clear_options(&tmp_opt);
tmp_opt.mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr);
tmp_opt.user_mss = tp->rx_opt.user_mss;
+ tcp_parse_options(skb, &tmp_opt, &hash_location, 0, dst);
+
+ if (tmp_opt.cookie_plus > 0
+ && tmp_opt.saw_tstamp
+ && !tp->rx_opt.cookie_out_never
+ && (sysctl_tcp_cookie_size > 0
+ || (tp->cookie_values != NULL
+ && tp->cookie_values->cookie_desired > 0))) {
+ u8 *c;
+ u32 *d;
+ u32 *mess = &tmp_ext.cookie_bakery[COOKIE_DIGEST_WORDS];
+ int l = tmp_opt.cookie_plus - TCPOLEN_COOKIE_BASE;
+
+ if (tcp_cookie_generator(&tmp_ext.cookie_bakery[0]) != 0)
+ goto drop_and_free;
+
+ /* Secret recipe starts with IP addresses */
+ d = &ipv6_hdr(skb)->daddr.s6_addr32[0];
+ *mess++ ^= *d++;
+ *mess++ ^= *d++;
+ *mess++ ^= *d++;
+ *mess++ ^= *d++;
+ d = &ipv6_hdr(skb)->saddr.s6_addr32[0];
+ *mess++ ^= *d++;
+ *mess++ ^= *d++;
+ *mess++ ^= *d++;
+ *mess++ ^= *d++;
+
+ /* plus variable length Initiator Cookie */
+ c = (u8 *)mess;
+ while (l-- > 0)
+ *c++ ^= *hash_location++;
- tcp_parse_options(skb, &tmp_opt, 0, dst);
+#ifdef CONFIG_SYN_COOKIES
+ want_cookie = 0; /* not our kind of cookie */
+#endif
+ tmp_ext.cookie_out_never = 0; /* false */
+ tmp_ext.cookie_plus = tmp_opt.cookie_plus;
+ } else if (!tp->rx_opt.cookie_in_always) {
+ /* redundant indications, but ensure initialization. */
+ tmp_ext.cookie_out_never = 1; /* true */
+ tmp_ext.cookie_plus = 0;
+ } else {
+ goto drop_and_free;
+ }
+ tmp_ext.cookie_in_always = tp->rx_opt.cookie_in_always;
if (want_cookie && !tmp_opt.saw_tstamp)
tcp_clear_options(&tmp_opt);
@@ -1244,7 +1290,8 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
security_inet_conn_request(sk, skb, req);
- if (tcp_v6_send_synack(sk, req, NULL)
+ if (tcp_v6_send_synack(sk, req,
+ (struct request_values *)&tmp_ext)
|| want_cookie)
goto drop_and_free;
--
1.6.3.3
^ permalink raw reply related
* [net-next-2.6 PATCH v6 6/7 RFC] TCPCT part 1f: Initiator Cookie => Responder
From: William Allen Simpson @ 2009-11-13 5:40 UTC (permalink / raw)
To: Linux Kernel Network Developers
In-Reply-To: <4AFCDA9E.8050003@gmail.com>
[-- Attachment #1: Type: text/plain, Size: 783 bytes --]
Calculate and format TCP_COOKIE SYN option.
Create (and destroy) cookie data structures.
This is a significantly revised implementation of an earlier (year-old)
patch that no longer applies cleanly, with permission of the original
author (Adam Langley):
http://thread.gmane.org/gmane.linux.network/102586
Requires:
TCPCT part 1c: sysctl_tcp_cookie_size, socket option TCP_COOKIE_TRANSACTIONS
TCPCT part 1d: define TCP cookie option, extend existing struct's
Signed-off-by: William.Allen.Simpson@gmail.com
---
net/ipv4/tcp_ipv4.c | 20 +++++
net/ipv4/tcp_minisocks.c | 45 +++++++++--
net/ipv4/tcp_output.c | 182 ++++++++++++++++++++++++++++++++++++++++------
net/ipv6/tcp_ipv6.c | 13 +++
4 files changed, 228 insertions(+), 32 deletions(-)
[-- Attachment #2: TCPCT+1f6.patch --]
[-- Type: text/plain, Size: 13998 bytes --]
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 094231b..2ae1985 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -1834,6 +1834,19 @@ static int tcp_v4_init_sock(struct sock *sk)
tp->af_specific = &tcp_sock_ipv4_specific;
#endif
+ /* TCP Cookie Transactions */
+ if (sysctl_tcp_cookie_size > 0) {
+ /* Default, cookies without s_data. */
+ tp->cookie_values =
+ kzalloc(sizeof(*tp->cookie_values),
+ sk->sk_allocation);
+ if (tp->cookie_values != NULL)
+ kref_init(&tp->cookie_values->kref);
+ }
+ /* Presumed zeroed, in order of appearance:
+ * cookie_in_always, cookie_out_never,
+ * s_data_constant, s_data_in, s_data_out
+ */
sk->sk_sndbuf = sysctl_tcp_wmem[1];
sk->sk_rcvbuf = sysctl_tcp_rmem[1];
@@ -1887,6 +1900,13 @@ void tcp_v4_destroy_sock(struct sock *sk)
sk->sk_sndmsg_page = NULL;
}
+ /* TCP Cookie Transactions */
+ if (tp->cookie_values != NULL) {
+ kref_put(&tp->cookie_values->kref,
+ tcp_cookie_values_release);
+ tp->cookie_values = NULL;
+ }
+
percpu_counter_dec(&tcp_sockets_allocated);
}
diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c
index 7a42990..2b50da8 100644
--- a/net/ipv4/tcp_minisocks.c
+++ b/net/ipv4/tcp_minisocks.c
@@ -389,14 +389,42 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct request_sock *req,
const struct inet_request_sock *ireq = inet_rsk(req);
struct tcp_request_sock *treq = tcp_rsk(req);
struct inet_connection_sock *newicsk = inet_csk(newsk);
- struct tcp_sock *newtp;
+ struct tcp_sock *newtp = tcp_sk(newsk);
+ struct tcp_sock *oldtp = tcp_sk(sk);
+ struct tcp_cookie_values *oldcvp = oldtp->cookie_values;
+
+ /* TCP Cookie Transactions require space for the cookie pair,
+ * as it differs for each connection. There is no need to
+ * copy any s_data stored at the original socket. Failure
+ * will prevent resuming the connection.
+ *
+ * Presumed copied, in order of appearance:
+ * cookie_in_always, cookie_out_never
+ */
+ if (oldcvp != NULL) {
+ struct tcp_cookie_values *newcvp =
+ kzalloc(sizeof(*newtp->cookie_values),
+ GFP_ATOMIC);
+
+ if (newcvp != NULL) {
+ kref_init(&newcvp->kref);
+ newcvp->cookie_desired =
+ oldcvp->cookie_desired;
+ newtp->cookie_values = newcvp;
+ } else {
+ /* Not Yet Implemented */
+ newtp->cookie_values = NULL;
+ }
+ }
/* Now setup tcp_sock */
- newtp = tcp_sk(newsk);
newtp->pred_flags = 0;
- newtp->rcv_wup = newtp->copied_seq = newtp->rcv_nxt = treq->rcv_isn + 1;
- newtp->snd_sml = newtp->snd_una = newtp->snd_nxt = treq->snt_isn + 1;
- newtp->snd_up = treq->snt_isn + 1;
+
+ newtp->rcv_wup = newtp->copied_seq =
+ newtp->rcv_nxt = treq->rcv_isn + 1;
+
+ newtp->snd_sml = newtp->snd_una = newtp->snd_nxt =
+ newtp->snd_up = treq->snt_isn + 1 + tcp_s_data_size(oldtp);
tcp_prequeue_init(newtp);
@@ -429,8 +457,8 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct request_sock *req,
tcp_set_ca_state(newsk, TCP_CA_Open);
tcp_init_xmit_timers(newsk);
skb_queue_head_init(&newtp->out_of_order_queue);
- newtp->write_seq = treq->snt_isn + 1;
- newtp->pushed_seq = newtp->write_seq;
+ newtp->write_seq = newtp->pushed_seq =
+ treq->snt_isn + 1 + tcp_s_data_size(oldtp);
newtp->rx_opt.saw_tstamp = 0;
@@ -596,7 +624,8 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb,
* Invalid ACK: reset will be sent by listening socket
*/
if ((flg & TCP_FLAG_ACK) &&
- (TCP_SKB_CB(skb)->ack_seq != tcp_rsk(req)->snt_isn + 1))
+ (TCP_SKB_CB(skb)->ack_seq != tcp_rsk(req)->snt_isn + 1 +
+ tcp_s_data_size(tcp_sk(sk))))
return sk;
/* Also, it would be not so bad idea to check rcv_tsecr, which
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index e59fa5a..e1553d3 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -370,15 +370,45 @@ static inline int tcp_urg_mode(const struct tcp_sock *tp)
#define OPTION_TS (1 << 1)
#define OPTION_MD5 (1 << 2)
#define OPTION_WSCALE (1 << 3)
+#define OPTION_COOKIE_EXTENSION (1 << 4)
struct tcp_out_options {
u8 options; /* bit field of OPTION_* */
u8 ws; /* window scale, 0 to disable */
+ u8 hash_size; /* bytes in hash */
u8 num_sack_blocks; /* number of SACK blocks to include */
u16 mss; /* 0 to disable */
__u32 tsval, tsecr; /* need to include OPTION_TS */
+ __u8 *hash_location; /* temporary pointer, overloaded */
};
+/* The sysctl int routines are generic, so check consistency here.
+ */
+static u8 tcp_cookie_size_check(u8 desired)
+{
+ if (desired > 0) {
+ /* previously specified */
+ return desired;
+ }
+ if (sysctl_tcp_cookie_size <= 0) {
+ /* no default specified */
+ return 0;
+ }
+ if (sysctl_tcp_cookie_size < TCP_COOKIE_MIN) {
+ /* value too small, increase to minimum */
+ return TCP_COOKIE_MIN;
+ }
+ if (sysctl_tcp_cookie_size > TCP_COOKIE_MAX) {
+ /* value too large, decrease to maximum */
+ return TCP_COOKIE_MAX;
+ }
+ if (0x1 & sysctl_tcp_cookie_size) {
+ /* 8-bit multiple, illegal, fix it */
+ return (u8)(sysctl_tcp_cookie_size + 0x1);
+ }
+ return (u8)sysctl_tcp_cookie_size;
+}
+
/* Write previously computed TCP options to the packet.
*
* Beware: Something in the Internet is very sensitive to the ordering of
@@ -393,17 +423,34 @@ struct tcp_out_options {
* (but it may well be that other scenarios fail similarly).
*/
static void tcp_options_write(__be32 *ptr, struct tcp_sock *tp,
- const struct tcp_out_options *opts,
- __u8 **md5_hash) {
- if (unlikely(OPTION_MD5 & opts->options)) {
- *ptr++ = htonl((TCPOPT_NOP << 24) |
- (TCPOPT_NOP << 16) |
- (TCPOPT_MD5SIG << 8) |
- TCPOLEN_MD5SIG);
- *md5_hash = (__u8 *)ptr;
+ struct tcp_out_options *opts)
+{
+ u8 options = opts->options; /* mungable copy */
+
+ /* Having both authentication and cookies for security is redundant,
+ * and there's certainly not enough room. Instead, the cookie-less
+ * extension variant is proposed.
+ *
+ * Consider the pessimal case with authentication. The options
+ * could look like:
+ * COOKIE|MD5(20) + MSS(4) + SACK|TS(12) + WSCALE(4) == 40
+ */
+ if (unlikely(OPTION_MD5 & options)) {
+ if (unlikely(OPTION_COOKIE_EXTENSION & options)) {
+ *ptr++ = htonl((TCPOPT_COOKIE << 24) |
+ (TCPOLEN_COOKIE_BASE << 16) |
+ (TCPOPT_MD5SIG << 8) |
+ TCPOLEN_MD5SIG);
+ } else {
+ *ptr++ = htonl((TCPOPT_NOP << 24) |
+ (TCPOPT_NOP << 16) |
+ (TCPOPT_MD5SIG << 8) |
+ TCPOLEN_MD5SIG);
+ }
+ options &= ~OPTION_COOKIE_EXTENSION;
+ /* overload cookie hash location */
+ opts->hash_location = (__u8 *)ptr;
ptr += 4;
- } else {
- *md5_hash = NULL;
}
if (unlikely(opts->mss)) {
@@ -412,12 +459,13 @@ static void tcp_options_write(__be32 *ptr, struct tcp_sock *tp,
opts->mss);
}
- if (likely(OPTION_TS & opts->options)) {
- if (unlikely(OPTION_SACK_ADVERTISE & opts->options)) {
+ if (likely(OPTION_TS & options)) {
+ if (unlikely(OPTION_SACK_ADVERTISE & options)) {
*ptr++ = htonl((TCPOPT_SACK_PERM << 24) |
(TCPOLEN_SACK_PERM << 16) |
(TCPOPT_TIMESTAMP << 8) |
TCPOLEN_TIMESTAMP);
+ options &= ~OPTION_SACK_ADVERTISE;
} else {
*ptr++ = htonl((TCPOPT_NOP << 24) |
(TCPOPT_NOP << 16) |
@@ -428,15 +476,52 @@ static void tcp_options_write(__be32 *ptr, struct tcp_sock *tp,
*ptr++ = htonl(opts->tsecr);
}
- if (unlikely(OPTION_SACK_ADVERTISE & opts->options &&
- !(OPTION_TS & opts->options))) {
+ /* Specification requires after timestamp, so do it now.
+ *
+ * Consider the pessimal case without authentication. The options
+ * could look like:
+ * MSS(4) + SACK|TS(12) + COOKIE(20) + WSCALE(4) == 40
+ */
+ if (unlikely(OPTION_COOKIE_EXTENSION & options)) {
+ __u8 *cookie_copy = opts->hash_location;
+ u8 cookie_size = opts->hash_size;
+
+ if (unlikely(0x1 & cookie_size)) {
+ /* 8-bit multiple, illegal, ignore */
+ cookie_size = 0;
+ } else if (likely(0x2 & cookie_size)) {
+ __u8 *p = (__u8 *)ptr;
+
+ /* 16-bit multiple */
+ *p++ = TCPOPT_COOKIE;
+ *p++ = TCPOLEN_COOKIE_BASE + cookie_size;
+ *p++ = *cookie_copy++;
+ *p++ = *cookie_copy++;
+ ptr++;
+ cookie_size -= 2;
+ } else {
+ /* 32-bit multiple */
+ *ptr++ = htonl(((TCPOPT_NOP << 24) |
+ (TCPOPT_NOP << 16) |
+ (TCPOPT_COOKIE << 8) |
+ TCPOLEN_COOKIE_BASE) +
+ cookie_size);
+ }
+
+ if (cookie_size > 0) {
+ memcpy(ptr, cookie_copy, cookie_size);
+ ptr += (cookie_size >> 2);
+ }
+ }
+
+ if (unlikely(OPTION_SACK_ADVERTISE & options)) {
*ptr++ = htonl((TCPOPT_NOP << 24) |
(TCPOPT_NOP << 16) |
(TCPOPT_SACK_PERM << 8) |
TCPOLEN_SACK_PERM);
}
- if (unlikely(OPTION_WSCALE & opts->options)) {
+ if (unlikely(OPTION_WSCALE & options)) {
*ptr++ = htonl((TCPOPT_NOP << 24) |
(TCPOPT_WINDOW << 16) |
(TCPOLEN_WINDOW << 8) |
@@ -471,8 +556,12 @@ static unsigned tcp_syn_options(struct sock *sk, struct sk_buff *skb,
struct tcp_out_options *opts,
struct tcp_md5sig_key **md5) {
struct tcp_sock *tp = tcp_sk(sk);
- unsigned size = 0;
+ struct tcp_cookie_values *cvp = tp->cookie_values;
struct dst_entry *dst = __sk_dst_get(sk);
+ unsigned size = 0;
+ u8 cookie_size = (!tp->rx_opt.cookie_out_never && cvp != NULL)
+ ? tcp_cookie_size_check(cvp->cookie_desired)
+ : 0;
#ifdef CONFIG_TCP_MD5SIG
*md5 = tp->af_specific->md5_lookup(sk, sk);
@@ -517,6 +606,53 @@ static unsigned tcp_syn_options(struct sock *sk, struct sk_buff *skb,
size += TCPOLEN_SACKPERM_ALIGNED;
}
+ /* Note that timestamps are required by the specification.
+ *
+ * Odd numbers of bytes are prohibited by the specification, ensuring
+ * that the cookie is 16-bit aligned, and the resulting cookie pair is
+ * 32-bit aligned.
+ */
+ if (*md5 == NULL
+ && (OPTION_TS & opts->options)
+ && cookie_size > 0) {
+ int need = TCPOLEN_COOKIE_BASE + cookie_size;
+ int remaining = MAX_TCP_OPTION_SPACE - size;
+
+ if (0x2 & need) {
+ /* 32-bit multiple */
+ need += 2; /* NOPs */
+
+ if (need > remaining) {
+ /* try shrinking cookie to fit */
+ cookie_size -= 2;
+ need -= 4;
+ }
+ }
+ while (need > remaining && TCP_COOKIE_MIN <= cookie_size) {
+ cookie_size -= 4;
+ need -= 4;
+ }
+ if (TCP_COOKIE_MIN <= cookie_size) {
+ opts->options |= OPTION_COOKIE_EXTENSION;
+ opts->hash_location = (__u8 *)&cvp->cookie_pair[0];
+ opts->hash_size = cookie_size;
+
+ /* Remember for future incarnations. */
+ cvp->cookie_desired = cookie_size;
+
+ if (cvp->cookie_desired != cvp->cookie_pair_size) {
+ /* Currently use random bytes as a nonce,
+ * assuming these are completely unpredictable
+ * by hostile users of the same system.
+ */
+ get_random_bytes(&cvp->cookie_pair[0],
+ cookie_size);
+ cvp->cookie_pair_size = cookie_size;
+ }
+
+ size += need;
+ }
+ }
return size;
}
@@ -632,7 +768,6 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it,
struct tcp_out_options opts;
unsigned tcp_options_size, tcp_header_size;
struct tcp_md5sig_key *md5;
- __u8 *md5_hash_location;
struct tcphdr *th;
int err;
@@ -703,7 +838,7 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it,
}
}
- tcp_options_write((__be32 *)(th + 1), tp, &opts, &md5_hash_location);
+ tcp_options_write((__be32 *)(th + 1), tp, &opts);
if (likely((tcb->flags & TCPCB_FLAG_SYN) == 0))
TCP_ECN_send(sk, skb, tcp_header_size);
@@ -711,7 +846,7 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it,
/* Calculate the MD5 hash, as we have all we need now */
if (md5) {
sk->sk_route_caps &= ~NETIF_F_GSO_MASK;
- tp->af_specific->calc_md5_hash(md5_hash_location,
+ tp->af_specific->calc_md5_hash(opts.hash_location,
md5, sk, NULL, skb);
}
#endif
@@ -2235,14 +2370,13 @@ struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst,
struct request_sock *req,
struct request_values *rvp)
{
+ struct tcp_out_options opts;
struct inet_request_sock *ireq = inet_rsk(req);
struct tcp_sock *tp = tcp_sk(sk);
struct tcphdr *th;
- int tcp_header_size;
- struct tcp_out_options opts;
struct sk_buff *skb;
struct tcp_md5sig_key *md5;
- __u8 *md5_hash_location;
+ int tcp_header_size;
int mss;
skb = sock_wmalloc(sk, MAX_TCP_HEADER + 15, 1, GFP_ATOMIC);
@@ -2303,14 +2437,14 @@ struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst,
/* RFC1323: The window in SYN & SYN/ACK segments is never scaled. */
th->window = htons(min(req->rcv_wnd, 65535U));
- tcp_options_write((__be32 *)(th + 1), tp, &opts, &md5_hash_location);
+ tcp_options_write((__be32 *)(th + 1), tp, &opts);
th->doff = (tcp_header_size >> 2);
TCP_INC_STATS(sock_net(sk), TCP_MIB_OUTSEGS);
#ifdef CONFIG_TCP_MD5SIG
/* Okay, we have all we need - do the md5 hash if needed */
if (md5) {
- tcp_rsk(req)->af_specific->calc_md5_hash(md5_hash_location,
+ tcp_rsk(req)->af_specific->calc_md5_hash(opts.hash_location,
md5, NULL, req, skb);
}
#endif
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 3e327bc..2b16f9a 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -1865,6 +1865,19 @@ static int tcp_v6_init_sock(struct sock *sk)
tp->af_specific = &tcp_sock_ipv6_specific;
#endif
+ /* TCP Cookie Transactions */
+ if (sysctl_tcp_cookie_size > 0) {
+ /* Default, cookies without s_data. */
+ tp->cookie_values =
+ kzalloc(sizeof(*tp->cookie_values),
+ sk->sk_allocation);
+ if (tp->cookie_values != NULL)
+ kref_init(&tp->cookie_values->kref);
+ }
+ /* Presumed zeroed, in order of appearance:
+ * cookie_in_always, cookie_out_never,
+ * s_data_constant, s_data_in, s_data_out
+ */
sk->sk_sndbuf = sysctl_tcp_wmem[1];
sk->sk_rcvbuf = sysctl_tcp_rmem[1];
--
1.6.3.3
^ permalink raw reply related
* [PATCH] act_mirred: cleanup and optimization
From: Changli Gao @ 2009-11-13 5:36 UTC (permalink / raw)
To: Jamal Hadi Salim; +Cc: Stephen Hemminger, David S. Miller, netdev, xiaosuo
act_mirred: cleanup and optimization.
cleanup and optimization.
1. don't let go back using goto.
2. move checking if eaction is valid in tcf_mirred_init().
3. don't call skb_act_clone() until it is necessary.
4. one exit of the critical context.
5. allow eaction is TCA_INGRESS_MIRROR & TCA_INGRESS_REDIR.
Signed-off-by: Changli Gao <xiaosuo@gmail.com>
----
net/sched/act_mirred.c | 121
++++++++++++++++++++++++++-----------------------
1 file changed, 65 insertions(+), 56 deletions(-)
diff --git a/net/sched/act_mirred.c b/net/sched/act_mirred.c
index b9aaab4..1e8b042 100644
--- a/net/sched/act_mirred.c
+++ b/net/sched/act_mirred.c
@@ -8,8 +8,6 @@
*
* Authors: Jamal Hadi Salim (2002-4)
*
- * TODO: Add ingress support (and socket redirect support)
- *
*/
#include <linux/types.h>
@@ -65,52 +63,63 @@ static int tcf_mirred_init(struct nlattr *nla, struct nlattr *est,
struct tc_mirred *parm;
struct tcf_mirred *m;
struct tcf_common *pc;
- struct net_device *dev = NULL;
- int ret = 0, err;
- int ok_push = 0;
+ struct net_device *dev;
+ int ret, ok_push = 0;
if (nla == NULL)
return -EINVAL;
-
- err = nla_parse_nested(tb, TCA_MIRRED_MAX, nla, mirred_policy);
- if (err < 0)
- return err;
-
+ ret = nla_parse_nested(tb, TCA_MIRRED_MAX, nla, mirred_policy);
+ if (ret < 0)
+ return ret;
if (tb[TCA_MIRRED_PARMS] == NULL)
return -EINVAL;
parm = nla_data(tb[TCA_MIRRED_PARMS]);
-
+ switch (parm->eaction) {
+ case TCA_EGRESS_MIRROR:
+ case TCA_EGRESS_REDIR:
+ case TCA_INGRESS_MIRROR:
+ case TCA_INGRESS_REDIR:
+ break;
+ default:
+ return -EINVAL;
+ }
if (parm->ifindex) {
- dev = __dev_get_by_index(&init_net, parm->ifindex);
+ dev = dev_get_by_index(&init_net, parm->ifindex);
if (dev == NULL)
return -ENODEV;
switch (dev->type) {
- case ARPHRD_TUNNEL:
- case ARPHRD_TUNNEL6:
- case ARPHRD_SIT:
- case ARPHRD_IPGRE:
- case ARPHRD_VOID:
- case ARPHRD_NONE:
- ok_push = 0;
- break;
- default:
- ok_push = 1;
- break;
+ case ARPHRD_TUNNEL:
+ case ARPHRD_TUNNEL6:
+ case ARPHRD_SIT:
+ case ARPHRD_IPGRE:
+ case ARPHRD_VOID:
+ case ARPHRD_NONE:
+ ok_push = 0;
+ break;
+ default:
+ ok_push = 1;
+ break;
}
+ } else {
+ dev = NULL;
}
pc = tcf_hash_check(parm->index, a, bind, &mirred_hash_info);
if (!pc) {
- if (!parm->ifindex)
+ if (dev == NULL)
return -EINVAL;
pc = tcf_hash_create(parm->index, est, a, sizeof(*m), bind,
&mirred_idx_gen, &mirred_hash_info);
- if (IS_ERR(pc))
- return PTR_ERR(pc);
+ if (IS_ERR(pc)) {
+ dev_put(dev);
+ return PTR_ERR(pc);
+ }
ret = ACT_P_CREATED;
} else {
if (!ovr) {
tcf_mirred_release(to_mirred(pc), bind);
+ if (dev != NULL)
+ dev_put(dev);
return -EEXIST;
}
}
@@ -119,12 +128,11 @@ static int tcf_mirred_init(struct nlattr *nla, struct nlattr *est,
spin_lock_bh(&m->tcf_lock);
m->tcf_action = parm->action;
m->tcfm_eaction = parm->eaction;
- if (parm->ifindex) {
+ if (dev != NULL) {
m->tcfm_ifindex = parm->ifindex;
if (ret != ACT_P_CREATED)
dev_put(m->tcfm_dev);
m->tcfm_dev = dev;
- dev_hold(dev);
m->tcfm_ok_push = ok_push;
}
spin_unlock_bh(&m->tcf_lock);
@@ -146,59 +154,60 @@ static int tcf_mirred_cleanup(struct tc_action *a, int bind)
static int tcf_mirred(struct sk_buff *skb, struct tc_action *a,
struct tcf_result *res)
{
- struct tcf_mirred *m = a->priv;
struct net_device *dev;
- struct sk_buff *skb2 = NULL;
- u32 at = G_TC_AT(skb->tc_verd);
+ struct sk_buff *skb2;
+ u32 at;
+ struct tcf_mirred *m = a->priv;
+ int retval, err = 1;
spin_lock(&m->tcf_lock);
-
- dev = m->tcfm_dev;
m->tcf_tm.lastuse = jiffies;
- if (!(dev->flags&IFF_UP) ) {
+ dev = m->tcfm_dev;
+ if (!(dev->flags & IFF_UP) ) {
if (net_ratelimit())
printk("mirred to Houston: device %s is gone!\n",
dev->name);
-bad_mirred:
- if (skb2 != NULL)
- kfree_skb(skb2);
- m->tcf_qstats.overlimits++;
- m->tcf_bstats.bytes += qdisc_pkt_len(skb);
- m->tcf_bstats.packets++;
- spin_unlock(&m->tcf_lock);
- /* should we be asking for packet to be dropped?
- * may make sense for redirect case only
- */
- return TC_ACT_SHOT;
+ goto out;
}
skb2 = skb_act_clone(skb, GFP_ATOMIC);
if (skb2 == NULL)
- goto bad_mirred;
- if (m->tcfm_eaction != TCA_EGRESS_MIRROR &&
- m->tcfm_eaction != TCA_EGRESS_REDIR) {
- if (net_ratelimit())
- printk("tcf_mirred unknown action %d\n",
- m->tcfm_eaction);
- goto bad_mirred;
- }
+ goto out;
m->tcf_bstats.bytes += qdisc_pkt_len(skb2);
m->tcf_bstats.packets++;
- if (!(at & AT_EGRESS))
+ at = G_TC_AT(skb->tc_verd);
+ if (!(at & AT_EGRESS)) {
if (m->tcfm_ok_push)
skb_push(skb2, skb2->dev->hard_header_len);
+ }
/* mirror is always swallowed */
- if (m->tcfm_eaction != TCA_EGRESS_MIRROR)
+ if (m->tcfm_eaction != TCA_EGRESS_MIRROR &&
+ m->tcfm_eaction != TCA_INGRESS_MIRROR)
skb2->tc_verd = SET_TC_FROM(skb2->tc_verd, at);
skb2->dev = dev;
skb2->iif = skb->dev->ifindex;
dev_queue_xmit(skb2);
+ err = 0;
+
+out:
+ if (err) {
+ m->tcf_qstats.overlimits++;
+ m->tcf_bstats.bytes += qdisc_pkt_len(skb);
+ m->tcf_bstats.packets++;
+ /* should we be asking for packet to be dropped?
+ * may make sense for redirect case only
+ */
+ retval = TC_ACT_SHOT;
+ } else {
+ retval = m->tcf_action;
+ }
spin_unlock(&m->tcf_lock);
- return m->tcf_action;
+
+ return retval;
}
static int tcf_mirred_dump(struct sk_buff *skb, struct tc_action *a, int bind, int ref)
^ permalink raw reply related
* Re: [net-next-2.6 PATCH] net: fast consecutive name allocation
From: Octavian Purdila @ 2009-11-13 5:20 UTC (permalink / raw)
To: netdev
In-Reply-To: <200911130701.14847.opurdila@ixiacom.com>
On Friday 13 November 2009 07:01:14 you wrote:
> This patch speeds up the network device name allocation for the case
> where a significant number of devices of the same type are created
> consecutively.
>
> Tests performed on a PPC750 @ 800Mhz machine with per device sysctl
> and sysfs entries disabled:
>
> Without the patch With the patch
>
> real 0m 43.43s real 0m 0.49s
> user 0m 0.00s user 0m 0.00s
> sys 0m 43.43s sys 0m 0.48s
>
Oops, pasting root prompts (e.g. # modprobe ....) directly into the git commit message is not a good idea :) Here it is again, with the full commit message.
[net-next-2.6 PATCH] net: fast consecutive name allocation
This patch speeds up the network device name allocation for the case
where a significant number of devices of the same type are created
consecutively.
Tests performed on a PPC750 @ 800Mhz machine with per device sysctl
and sysfs entries disabled:
$ time insmod /lib/modules/dummy.ko numdummies=8000
Without the patch With the patch
real 0m 43.43s real 0m 0.49s
user 0m 0.00s user 0m 0.00s
sys 0m 43.43s sys 0m 0.48s
Signed-off-by: Octavian Purdila <opurdila@ixiacom.com>
---
include/net/net_namespace.h | 3 +++
net/core/dev.c | 23 ++++++++++++++++++++++-
2 files changed, 25 insertions(+), 1 deletions(-)
diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h
index 0addd45..39c65a2 100644
--- a/include/net/net_namespace.h
+++ b/include/net/net_namespace.h
@@ -56,6 +56,9 @@ struct net {
struct list_head dev_base_head;
struct hlist_head *dev_name_head;
struct hlist_head *dev_index_head;
+ /* fast consecutive name allocation (e.g. eth0, eth1, ...) */
+ char fcna_name[IFNAMSIZ];
+ int fcna_no;
/* core fib_rules */
struct list_head rules_ops;
diff --git a/net/core/dev.c b/net/core/dev.c
index ad8e320..008e3c7 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -226,8 +226,12 @@ static int list_netdevice(struct net_device *dev)
*/
static void unlist_netdevice(struct net_device *dev)
{
+ struct net *net = dev_net(dev);
+
ASSERT_RTNL();
+ net->fcna_no = -1;
+
/* Unlink dev from the device chain */
write_lock_bh(&dev_base_lock);
list_del_rcu(&dev->dev_list);
@@ -872,6 +876,16 @@ static int __dev_alloc_name(struct net *net, const char *name, char *buf)
if (p[1] != 'd' || strchr(p + 2, '%'))
return -EINVAL;
+ /* avoid fast allocation for strange templates like "fan%dcy" */
+ if (net->fcna_no >= 0 && p[2] == 0 &&
+ net->fcna_name[p - name] == 0 &&
+ memcmp(name, net->fcna_name, p - name) == 0) {
+ snprintf(buf, IFNAMSIZ, name, ++net->fcna_no);
+ if (!__dev_get_by_name(net, buf))
+ return net->fcna_no;
+ net->fcna_no = -1;
+ }
+
/* Use one page as a bit array of possible slots */
inuse = (unsigned long *) get_zeroed_page(GFP_ATOMIC);
if (!inuse)
@@ -894,8 +908,15 @@ static int __dev_alloc_name(struct net *net, const char *name, char *buf)
}
snprintf(buf, IFNAMSIZ, name, i);
- if (!__dev_get_by_name(net, buf))
+ if (!__dev_get_by_name(net, buf)) {
+ if (p[2] == 0) {
+ memcpy(net->fcna_name, name, p - name);
+ net->fcna_name[p - name] = 0;
+ net->fcna_no = i;
+ } else
+ net->fcna_no = -1;
return i;
+ }
/* It is possible to run out of possible slots
* when the name is long and there isn't enough space left
--
1.5.6.5
^ permalink raw reply related
* [net-next-2.6 PATCH v6 5/7 RFC] TCPCT part 1e: implement socket option TCP_COOKIE_TRANSACTIONS
From: William Allen Simpson @ 2009-11-13 5:10 UTC (permalink / raw)
To: Linux Kernel Network Developers
In-Reply-To: <4AFCDA9E.8050003@gmail.com>
[-- Attachment #1: Type: text/plain, Size: 868 bytes --]
Provide per socket control of the TCP cookie option and SYN/SYNACK data.
This is a straightforward re-implementation of an earlier (year-old)
patch that no longer applies cleanly, with permission of the original
author (Adam Langley):
http://thread.gmane.org/gmane.linux.network/102586
The principle difference is using a TCP option to carry the cookie nonce,
instead of a user configured offset in the data.
Allocations have been rearranged to avoid requiring GFP_ATOMIC.
Requires:
net: TCP_MSS_DEFAULT, TCP_MSS_DESIRED
TCPCT part 1c: sysctl_tcp_cookie_size, socket option TCP_COOKIE_TRANSACTIONS
TCPCT part 1d: define TCP cookie option, extend existing struct's
Signed-off-by: William.Allen.Simpson@gmail.com
---
net/ipv4/tcp.c | 133 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 131 insertions(+), 2 deletions(-)
[-- Attachment #2: TCPCT+1e6.patch --]
[-- Type: text/plain, Size: 4406 bytes --]
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 3ae01bf..3424499 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -2079,8 +2079,9 @@ static int do_tcp_setsockopt(struct sock *sk, int level,
int val;
int err = 0;
- /* This is a string value all the others are int's */
- if (optname == TCP_CONGESTION) {
+ /* These are data/string values, all the others are ints */
+ switch (optname) {
+ case TCP_CONGESTION: {
char name[TCP_CA_NAME_MAX];
if (optlen < 1)
@@ -2097,6 +2098,93 @@ static int do_tcp_setsockopt(struct sock *sk, int level,
release_sock(sk);
return err;
}
+ case TCP_COOKIE_TRANSACTIONS: {
+ struct tcp_cookie_transactions ctd;
+ struct tcp_cookie_values *cvp = NULL;
+
+ if (sizeof(ctd) > optlen)
+ return -EINVAL;
+ if (copy_from_user(&ctd, optval, sizeof(ctd)))
+ return -EFAULT;
+
+ if (ctd.tcpct_used > sizeof(ctd.tcpct_value)
+ || ctd.tcpct_s_data_desired > TCP_MSS_DESIRED)
+ return -EINVAL;
+
+ if (ctd.tcpct_cookie_desired == 0) {
+ /* default to global value */
+ } else if ((0x1 & ctd.tcpct_cookie_desired)
+ || ctd.tcpct_cookie_desired > TCP_COOKIE_MAX
+ || ctd.tcpct_cookie_desired < TCP_COOKIE_MIN) {
+ return -EINVAL;
+ }
+
+ if (TCP_COOKIE_OUT_NEVER & ctd.tcpct_flags) {
+ /* Supercedes all other values */
+ lock_sock(sk);
+ if (tp->cookie_values != NULL) {
+ kref_put(&tp->cookie_values->kref,
+ tcp_cookie_values_release);
+ tp->cookie_values = NULL;
+ }
+ tp->rx_opt.cookie_in_always = 0; /* false */
+ tp->rx_opt.cookie_out_never = 1; /* true */
+ release_sock(sk);
+ return err;
+ }
+
+ /* Allocate ancillary memory before locking.
+ */
+ if (ctd.tcpct_used > 0
+ || (tp->cookie_values == NULL
+ && (sysctl_tcp_cookie_size > 0
+ || ctd.tcpct_cookie_desired > 0
+ || ctd.tcpct_s_data_desired > 0))) {
+ cvp = kzalloc(sizeof(*cvp) + ctd.tcpct_used,
+ GFP_KERNEL);
+ if (cvp == NULL)
+ return -ENOMEM;
+ }
+ lock_sock(sk);
+ tp->rx_opt.cookie_in_always =
+ (TCP_COOKIE_IN_ALWAYS & ctd.tcpct_flags);
+ tp->rx_opt.cookie_out_never = 0; /* false */
+
+ if (tp->cookie_values != NULL) {
+ if (cvp != NULL) {
+ /* Changed values are recorded by a changed
+ * pointer, ensuring the cookie will differ,
+ * without separately hashing each value later.
+ */
+ kref_put(&tp->cookie_values->kref,
+ tcp_cookie_values_release);
+ kref_init(&cvp->kref);
+ tp->cookie_values = cvp;
+ } else {
+ cvp = tp->cookie_values;
+ }
+ }
+ if (cvp != NULL) {
+ cvp->cookie_desired = ctd.tcpct_cookie_desired;
+
+ if (ctd.tcpct_used > 0) {
+ memcpy(cvp->s_data_payload, ctd.tcpct_value,
+ ctd.tcpct_used);
+ cvp->s_data_desired = ctd.tcpct_used;
+ cvp->s_data_constant = 1; /* true */
+ } else {
+ /* No constant payload data. */
+ cvp->s_data_desired = ctd.tcpct_s_data_desired;
+ cvp->s_data_constant = 0; /* false */
+ }
+ }
+ release_sock(sk);
+ return err;
+ }
+ default:
+ /* fallthru */
+ break;
+ };
if (optlen < sizeof(int))
return -EINVAL;
@@ -2421,6 +2509,47 @@ static int do_tcp_getsockopt(struct sock *sk, int level,
if (copy_to_user(optval, icsk->icsk_ca_ops->name, len))
return -EFAULT;
return 0;
+
+ case TCP_COOKIE_TRANSACTIONS: {
+ struct tcp_cookie_transactions ctd;
+ struct tcp_cookie_values *cvp = tp->cookie_values;
+
+ if (get_user(len, optlen))
+ return -EFAULT;
+ if (len < sizeof(ctd))
+ return -EINVAL;
+
+ memset(&ctd, 0, sizeof(ctd));
+ ctd.tcpct_flags = (tp->rx_opt.cookie_in_always
+ ? TCP_COOKIE_IN_ALWAYS : 0)
+ + (tp->rx_opt.cookie_out_never
+ ? TCP_COOKIE_OUT_NEVER : 0);
+
+ if (cvp != NULL) {
+ ctd.tcpct_flags += (cvp->s_data_in
+ ? TCP_S_DATA_IN : 0)
+ + (cvp->s_data_out
+ ? TCP_S_DATA_OUT : 0);
+
+ ctd.tcpct_cookie_desired = cvp->cookie_desired;
+ ctd.tcpct_s_data_desired = cvp->s_data_desired;
+
+ /* Cookie(s) saved, return as nonce */
+ if (sizeof(ctd.tcpct_value) < cvp->cookie_pair_size) {
+ /* impossible? */
+ return -EINVAL;
+ }
+ memcpy(&ctd.tcpct_value[0], &cvp->cookie_pair[0],
+ cvp->cookie_pair_size);
+ ctd.tcpct_used = cvp->cookie_pair_size;
+ }
+
+ if (put_user(sizeof(ctd), optlen))
+ return -EFAULT;
+ if (copy_to_user(optval, &ctd, sizeof(ctd)))
+ return -EFAULT;
+ return 0;
+ }
default:
return -ENOPROTOOPT;
}
--
1.6.3.3
^ permalink raw reply related
* Re: Subject: [PATCH 2/6] bna: Brocade 10Gb Ethernet device driver
From: Stephen Hemminger @ 2009-11-13 5:08 UTC (permalink / raw)
To: Rasesh Mody; +Cc: netdev, adapter_linux_open_src_team
In-Reply-To: <200911130346.nAD3kqjM001055@blc-10-10.brocade.com>
On Thu, 12 Nov 2009 19:46:52 -0800
Rasesh Mody <rmody@brocade.com> wrote:
> +/*
> + * Copyright (c) 2006-2009 Brocade Communications Systems, Inc.
> + * All rights reserved
> + * www.brocade.com
> + *
> + * See LICENSE.bna for copyright and licensing details.
> + */
> +
I don't see LICENSE.bna in any of the patches.
--
^ permalink raw reply
* Re: Subject: [PATCH 5/6] bna: Brocade 10Gb Ethernet device driver
From: Stephen Hemminger @ 2009-11-13 5:07 UTC (permalink / raw)
To: Rasesh Mody; +Cc: netdev, adapter_linux_open_src_team
In-Reply-To: <200911130346.nAD3kquT001065@blc-10-10.brocade.com>
On Thu, 12 Nov 2009 19:46:52 -0800
Rasesh Mody <rmody@brocade.com> wrote:
> +
> +#define wwn_t u64
> +#define lun_t u64
No need for obfuscation, at least use a typedef.
> +
> +#define WWN_NULL (0)
Why is NULL not good enuf
> +#define FC_SYMNAME_MAX 256 /* max name server symbolic name size */
> +#define FC_ALPA_MAX 128
> +
> +#pragma pack(1)
> +
> +#define MAC_ADDRLEN (6)
> +struct mac { u8 mac[MAC_ADDRLEN]; };
Cant you use ETH_ALEN instead?
--
^ permalink raw reply
* Re: Subject: [PATCH 3/6] bna: Brocade 10Gb Ethernet device driver
From: Stephen Hemminger @ 2009-11-13 5:05 UTC (permalink / raw)
To: Rasesh Mody; +Cc: netdev, adapter_linux_open_src_team
In-Reply-To: <200911130346.nAD3kqsL001058@blc-10-10.brocade.com>
On Thu, 12 Nov 2009 19:46:52 -0800
Rasesh Mody <rmody@brocade.com> wrote:
> +
> +#ifndef __BIGENDIAN
> +#define bna_dma_addr64(_x) swab64((_x))
> +#else
> +#define bna_dma_addr64(_x) (_x)
> +#endif
> +
This should be cpu_to_le64 and any data with byte order
dependency should be declared leXX etc. Then sparse tool can
check for misuse of endian.
--
^ permalink raw reply
* [net-next-2.6 PATCH] net: fast consecutive name allocation
From: Octavian Purdila @ 2009-11-13 5:01 UTC (permalink / raw)
To: netdev
[-- Attachment #1: Type: text/plain, Size: 621 bytes --]
This patch speeds up the network device name allocation for the case
where a significant number of devices of the same type are created
consecutively.
Tests performed on a PPC750 @ 800Mhz machine with per device sysctl
and sysfs entries disabled:
Without the patch With the patch
real 0m 43.43s real 0m 0.49s
user 0m 0.00s user 0m 0.00s
sys 0m 43.43s sys 0m 0.48s
Signed-off-by: Octavian Purdila <opurdila@ixiacom.com>
---
include/net/net_namespace.h | 3 +++
net/core/dev.c | 23 ++++++++++++++++++++++-
2 files changed, 25 insertions(+), 1 deletions(-)
[-- Attachment #2: 3ad8e007a0c929204c3ee7e7afa309e2e53b5b8a.diff --]
[-- Type: text/x-patch, Size: 2073 bytes --]
diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h
index 0addd45..39c65a2 100644
--- a/include/net/net_namespace.h
+++ b/include/net/net_namespace.h
@@ -56,6 +56,9 @@ struct net {
struct list_head dev_base_head;
struct hlist_head *dev_name_head;
struct hlist_head *dev_index_head;
+ /* fast consecutive name allocation (e.g. eth0, eth1, ...) */
+ char fcna_name[IFNAMSIZ];
+ int fcna_no;
/* core fib_rules */
struct list_head rules_ops;
diff --git a/net/core/dev.c b/net/core/dev.c
index ad8e320..008e3c7 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -226,8 +226,12 @@ static int list_netdevice(struct net_device *dev)
*/
static void unlist_netdevice(struct net_device *dev)
{
+ struct net *net = dev_net(dev);
+
ASSERT_RTNL();
+ net->fcna_no = -1;
+
/* Unlink dev from the device chain */
write_lock_bh(&dev_base_lock);
list_del_rcu(&dev->dev_list);
@@ -872,6 +876,16 @@ static int __dev_alloc_name(struct net *net, const char *name, char *buf)
if (p[1] != 'd' || strchr(p + 2, '%'))
return -EINVAL;
+ /* avoid fast allocation for strange templates like "fan%dcy" */
+ if (net->fcna_no >= 0 && p[2] == 0 &&
+ net->fcna_name[p - name] == 0 &&
+ memcmp(name, net->fcna_name, p - name) == 0) {
+ snprintf(buf, IFNAMSIZ, name, ++net->fcna_no);
+ if (!__dev_get_by_name(net, buf))
+ return net->fcna_no;
+ net->fcna_no = -1;
+ }
+
/* Use one page as a bit array of possible slots */
inuse = (unsigned long *) get_zeroed_page(GFP_ATOMIC);
if (!inuse)
@@ -894,8 +908,15 @@ static int __dev_alloc_name(struct net *net, const char *name, char *buf)
}
snprintf(buf, IFNAMSIZ, name, i);
- if (!__dev_get_by_name(net, buf))
+ if (!__dev_get_by_name(net, buf)) {
+ if (p[2] == 0) {
+ memcpy(net->fcna_name, name, p - name);
+ net->fcna_name[p - name] = 0;
+ net->fcna_no = i;
+ } else
+ net->fcna_no = -1;
return i;
+ }
/* It is possible to run out of possible slots
* when the name is long and there isn't enough space left
^ permalink raw reply related
* Re: Subject: [PATCH 5/6] bna: Brocade 10Gb Ethernet device driver
From: Stephen Hemminger @ 2009-11-13 5:03 UTC (permalink / raw)
To: Rasesh Mody; +Cc: netdev, adapter_linux_open_src_team
In-Reply-To: <200911130346.nAD3kquT001065@blc-10-10.brocade.com>
On Thu, 12 Nov 2009 19:46:52 -0800
Rasesh Mody <rmody@brocade.com> wrote:
> +#define bfa_cb_queue(__bfa, __hcb_qe, __cbfn, __cbarg) do { \
> + (__hcb_qe)->cbfn = (__cbfn); \
> + (__hcb_qe)->cbarg = (__cbarg); \
> + list_add_tail(&(__hcb_qe)->qe, &(__bfa)->comp_q); \
> +} while (0)
> +
> +#define bfa_cb_dequeue(__hcb_qe) list_del(&(__hcb_qe)->qe)
> +
> +#define bfa_cb_queue_once(__bfa, __hcb_qe, __cbfn, __cbarg) do { \
> + (__hcb_qe)->cbfn = (__cbfn); \
> + (__hcb_qe)->cbarg = (__cbarg); \
> + if (!(__hcb_qe)->once) { \
> + list_add_tail((__hcb_qe), &(__bfa)->comp_q); \
> + (__hcb_qe)->once = true; \
> + } \
> +} while (0)
> +
> +#define bfa_cb_queue_done(__hcb_qe) do { \
> + (__hcb_qe)->once = false; \
> +} while (0)
> +
Could these be inline functions or are they typeless macros?
--
^ permalink raw reply
* Re: [net-next-2.6 PATCH v6 1/7 RFC] TCPCT part 1a: add request_values parameter for sending SYNACK
From: Ilpo Järvinen @ 2009-11-13 4:54 UTC (permalink / raw)
To: William Allen Simpson; +Cc: Linux Kernel Network Developers
In-Reply-To: <4AFCDB9D.6050804@gmail.com>
On Thu, 12 Nov 2009, William Allen Simpson wrote:
> Add optional function parameters associated with sending SYNACK.
> These parameters are not needed after sending SYNACK, and are not
> used for retransmission. Avoids extending struct tcp_request_sock,
> and avoids allocating kernel memory.
>
> Also affects DCCP as it uses common struct request_sock_ops,
> but this parameter is currently reserved for future use.
>
> Signed-off-by: William.Allen.Simpson@gmail.com
> Acked-by: Eric Dumazet <eric.dumazet@gmail.com>
> ---
> include/net/request_sock.h | 8 +++++++-
> include/net/tcp.h | 3 ++-
> net/dccp/ipv4.c | 5 +++--
> net/dccp/ipv6.c | 5 +++--
> net/dccp/minisocks.c | 2 +-
> net/ipv4/inet_connection_sock.c | 2 +-
> net/ipv4/tcp_ipv4.c | 19 +++++++++++--------
> net/ipv4/tcp_minisocks.c | 2 +-
> net/ipv4/tcp_output.c | 3 ++-
> net/ipv6/tcp_ipv6.c | 28 +++++++++++++---------------
> 10 files changed, 44 insertions(+), 33 deletions(-)
>
> diff --git a/include/net/request_sock.h b/include/net/request_sock.h
> index c719084..c9b50eb 100644
> --- a/include/net/request_sock.h
> +++ b/include/net/request_sock.h
> @@ -27,13 +27,19 @@ struct sk_buff;
> struct dst_entry;
> struct proto;
>
> +/* empty to "strongly type" an otherwise void parameter.
> + */
> +struct request_values {
> +};
> +
> struct request_sock_ops {
> int family;
> int obj_size;
> struct kmem_cache *slab;
> char *slab_name;
> int (*rtx_syn_ack)(struct sock *sk,
> - struct request_sock *req);
> + struct request_sock *req,
> + struct request_values *rvp);
> void (*send_ack)(struct sock *sk, struct sk_buff *skb,
> struct request_sock *req);
> void (*send_reset)(struct sock *sk,
> diff --git a/include/net/tcp.h b/include/net/tcp.h
> index 325bfcf..ec183fd 100644
> --- a/include/net/tcp.h
> +++ b/include/net/tcp.h
> @@ -440,7 +440,8 @@ extern int tcp_connect(struct sock *sk);
>
> extern struct sk_buff * tcp_make_synack(struct sock *sk,
> struct dst_entry *dst,
> - struct request_sock *req);
> + struct request_sock *req,
> + struct request_values *rvp);
>
> extern int tcp_disconnect(struct sock *sk, int flags);
>
> diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c
> index 2423a08..efbcfdc 100644
> --- a/net/dccp/ipv4.c
> +++ b/net/dccp/ipv4.c
> @@ -477,7 +477,8 @@ static struct dst_entry* dccp_v4_route_skb(struct net *net, struct sock *sk,
> return &rt->u.dst;
> }
>
> -static int dccp_v4_send_response(struct sock *sk, struct request_sock *req)
> +static int dccp_v4_send_response(struct sock *sk, struct request_sock *req,
> + struct request_values *rv_unused)
> {
> int err = -1;
> struct sk_buff *skb;
> @@ -626,7 +627,7 @@ int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
> dreq->dreq_iss = dccp_v4_init_sequence(skb);
> dreq->dreq_service = service;
>
> - if (dccp_v4_send_response(sk, req))
> + if (dccp_v4_send_response(sk, req, NULL))
> goto drop_and_free;
>
> inet_csk_reqsk_queue_hash_add(sk, req, DCCP_TIMEOUT_INIT);
> diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c
> index 50ea91a..6574215 100644
> --- a/net/dccp/ipv6.c
> +++ b/net/dccp/ipv6.c
> @@ -241,7 +241,8 @@ out:
> }
>
>
> -static int dccp_v6_send_response(struct sock *sk, struct request_sock *req)
> +static int dccp_v6_send_response(struct sock *sk, struct request_sock *req,
> + struct request_values *rv_unused)
> {
> struct inet6_request_sock *ireq6 = inet6_rsk(req);
> struct ipv6_pinfo *np = inet6_sk(sk);
> @@ -468,7 +469,7 @@ static int dccp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
> dreq->dreq_iss = dccp_v6_init_sequence(skb);
> dreq->dreq_service = service;
>
> - if (dccp_v6_send_response(sk, req))
> + if (dccp_v6_send_response(sk, req, NULL))
> goto drop_and_free;
>
> inet6_csk_reqsk_queue_hash_add(sk, req, DCCP_TIMEOUT_INIT);
> diff --git a/net/dccp/minisocks.c b/net/dccp/minisocks.c
> index 5ca49ce..af226a0 100644
> --- a/net/dccp/minisocks.c
> +++ b/net/dccp/minisocks.c
> @@ -184,7 +184,7 @@ struct sock *dccp_check_req(struct sock *sk, struct sk_buff *skb,
> * counter (backoff, monitored by dccp_response_timer).
> */
> req->retrans++;
> - req->rsk_ops->rtx_syn_ack(sk, req);
> + req->rsk_ops->rtx_syn_ack(sk, req, NULL);
> }
> /* Network Duplicate, discard packet */
> return NULL;
> diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c
> index 26fb50e..ad098d6 100644
> --- a/net/ipv4/inet_connection_sock.c
> +++ b/net/ipv4/inet_connection_sock.c
> @@ -531,7 +531,7 @@ void inet_csk_reqsk_queue_prune(struct sock *parent,
> &expire, &resend);
> if (!expire &&
> (!resend ||
> - !req->rsk_ops->rtx_syn_ack(parent, req) ||
> + !req->rsk_ops->rtx_syn_ack(parent, req, NULL) ||
> inet_rsk(req)->acked)) {
> unsigned long timeo;
>
> diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
> index cf7f208..094231b 100644
> --- a/net/ipv4/tcp_ipv4.c
> +++ b/net/ipv4/tcp_ipv4.c
> @@ -742,8 +742,9 @@ static void tcp_v4_reqsk_send_ack(struct sock *sk, struct sk_buff *skb,
> * This still operates on a request_sock only, not on a big
> * socket.
> */
> -static int __tcp_v4_send_synack(struct sock *sk, struct request_sock *req,
> - struct dst_entry *dst)
> +static int __tcp_v4_send_synack(struct sock *sk, struct dst_entry *dst,
> + struct request_sock *req,
> + struct request_values *rvp)
> {
> const struct inet_request_sock *ireq = inet_rsk(req);
> int err = -1;
> @@ -753,7 +754,7 @@ static int __tcp_v4_send_synack(struct sock *sk, struct request_sock *req,
> if (!dst && (dst = inet_csk_route_req(sk, req)) == NULL)
> return -1;
>
> - skb = tcp_make_synack(sk, dst, req);
> + skb = tcp_make_synack(sk, dst, req, rvp);
>
> if (skb) {
> struct tcphdr *th = tcp_hdr(skb);
> @@ -774,9 +775,10 @@ static int __tcp_v4_send_synack(struct sock *sk, struct request_sock *req,
> return err;
> }
>
> -static int tcp_v4_send_synack(struct sock *sk, struct request_sock *req)
> +static int tcp_v4_send_synack(struct sock *sk, struct request_sock *req,
> + struct request_values *rvp)
> {
> - return __tcp_v4_send_synack(sk, req, NULL);
> + return __tcp_v4_send_synack(sk, NULL, req, rvp);
> }
>
> /*
> @@ -1211,13 +1213,13 @@ static struct timewait_sock_ops tcp_timewait_sock_ops = {
>
> int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
> {
> - struct inet_request_sock *ireq;
> struct tcp_options_received tmp_opt;
> struct request_sock *req;
> + struct inet_request_sock *ireq;
> + struct dst_entry *dst = NULL;
> __be32 saddr = ip_hdr(skb)->saddr;
> __be32 daddr = ip_hdr(skb)->daddr;
> __u32 isn = TCP_SKB_CB(skb)->when;
> - struct dst_entry *dst = NULL;
> #ifdef CONFIG_SYN_COOKIES
> int want_cookie = 0;
> #else
> @@ -1337,7 +1339,8 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
> }
> tcp_rsk(req)->snt_isn = isn;
>
> - if (__tcp_v4_send_synack(sk, req, dst) || want_cookie)
> + if (__tcp_v4_send_synack(sk, dst, req, NULL)
> + || want_cookie)
> goto drop_and_free;
>
> inet_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT);
> diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c
> index 4be2228..7a42990 100644
> --- a/net/ipv4/tcp_minisocks.c
> +++ b/net/ipv4/tcp_minisocks.c
> @@ -537,7 +537,7 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb,
> * Enforce "SYN-ACK" according to figure 8, figure 6
> * of RFC793, fixed by RFC1122.
> */
> - req->rsk_ops->rtx_syn_ack(sk, req);
> + req->rsk_ops->rtx_syn_ack(sk, req, NULL);
> return NULL;
> }
>
> diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
> index 616c686..1151cb8 100644
> --- a/net/ipv4/tcp_output.c
> +++ b/net/ipv4/tcp_output.c
> @@ -2224,7 +2224,8 @@ int tcp_send_synack(struct sock *sk)
>
> /* Prepare a SYN-ACK. */
> struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst,
> - struct request_sock *req)
> + struct request_sock *req,
> + struct request_values *rvp)
> {
> struct inet_request_sock *ireq = inet_rsk(req);
> struct tcp_sock *tp = tcp_sk(sk);
> diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
> index de70909..3e327bc 100644
> --- a/net/ipv6/tcp_ipv6.c
> +++ b/net/ipv6/tcp_ipv6.c
> @@ -461,7 +461,8 @@ out:
> }
>
>
> -static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req)
> +static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req,
> + struct request_values *rvp)
> {
> struct inet6_request_sock *treq = inet6_rsk(req);
> struct ipv6_pinfo *np = inet6_sk(sk);
> @@ -499,7 +500,7 @@ static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req)
> if ((err = xfrm_lookup(sock_net(sk), &dst, &fl, sk, 0)) < 0)
> goto done;
>
> - skb = tcp_make_synack(sk, dst, req);
> + skb = tcp_make_synack(sk, dst, req, rvp);
> if (skb) {
> struct tcphdr *th = tcp_hdr(skb);
>
> @@ -1161,13 +1162,13 @@ static struct sock *tcp_v6_hnd_req(struct sock *sk,struct sk_buff *skb)
> */
> static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
> {
> + struct tcp_options_received tmp_opt;
> + struct request_sock *req;
> struct inet6_request_sock *treq;
> struct ipv6_pinfo *np = inet6_sk(sk);
> - struct tcp_options_received tmp_opt;
> struct tcp_sock *tp = tcp_sk(sk);
> - struct request_sock *req = NULL;
> - __u32 isn = TCP_SKB_CB(skb)->when;
> struct dst_entry *dst = __sk_dst_get(sk);
> + __u32 isn = TCP_SKB_CB(skb)->when;
> #ifdef CONFIG_SYN_COOKIES
> int want_cookie = 0;
> #else
> @@ -1239,23 +1240,20 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
>
> isn = tcp_v6_init_sequence(skb);
> }
> -
> tcp_rsk(req)->snt_isn = isn;
>
> security_inet_conn_request(sk, skb, req);
>
> - if (tcp_v6_send_synack(sk, req))
> - goto drop;
> + if (tcp_v6_send_synack(sk, req, NULL)
> + || want_cookie)
This fits to one line very well. There were other unnecessary line-breaks
too (might have been in another patch than this).
However, in cases where you really would have to split lines in if
statement. Please move || (or &&) to the end of the previous line and use
matching indent level on the line below (in this example the text is
matching already, so it is just about converting || into spaces here).
...As was mentioned by somebody already earlier.
Splitting of 1-3 is quite ok, the rest haven't arrived yet.
> + goto drop_and_free;
>
> - if (!want_cookie) {
> - inet6_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT);
> - return 0;
> - }
> + inet6_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT);
> + return 0;
>
> +drop_and_free:
> + reqsk_free(req);
> drop:
> - if (req)
> - reqsk_free(req);
> -
> return 0; /* don't send reset */
> }
>
> --
> 1.6.3.3
>
--
i.
^ permalink raw reply
* [net-next-2.6 PATCH v6 4/7 RFC] TCPCT part 1d: define TCP cookie option, extend existing struct's
From: William Allen Simpson @ 2009-11-13 4:53 UTC (permalink / raw)
To: Linux Kernel Network Developers
In-Reply-To: <4AFCDA9E.8050003@gmail.com>
[-- Attachment #1: Type: text/plain, Size: 1702 bytes --]
Data structures are carefully composed to require minimal additions.
For example, the struct tcp_options_received cookie_plus variable fits
between existing 16-bit and 8-bit variables, requiring no additional
space (taking alignment into consideration). There are no additions to
tcp_request_sock, and only 1 pointer in tcp_sock.
This is a significantly revised implementation of an earlier (year-old)
patch that no longer applies cleanly, with permission of the original
author (Adam Langley):
http://thread.gmane.org/gmane.linux.network/102586
The principle difference is using a TCP option to carry the cookie nonce,
instead of a user configured offset in the data. This is more flexible and
less subject to user configuration error. Such a cookie option has been
suggested for many years, and is also useful without SYN data, allowing
several related concepts to use the same extension option.
"Re: SYN floods (was: does history repeat itself?)", September 9, 1996.
http://www.merit.net/mail.archives/nanog/1996-09/msg00235.html
"Re: what a new TCP header might look like", May 12, 1998.
ftp://ftp.isi.edu/end2end/end2end-interest-1998.mail
These functions will also be used in subsequent patches that implement
additional features.
Requires:
TCPCT part 1a: add request_values parameter for sending SYNACK
TCPCT part 1b: generate Responder Cookie
TCPCT part 1c: sysctl_tcp_cookie_size, socket option TCP_COOKIE_TRANSACTIONS
Signed-off-by: William.Allen.Simpson@gmail.com
---
include/linux/tcp.h | 29 ++++++++++++++++----
include/net/tcp.h | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 95 insertions(+), 6 deletions(-)
[-- Attachment #2: TCPCT+1d6.patch --]
[-- Type: text/plain, Size: 6048 bytes --]
diff --git a/include/linux/tcp.h b/include/linux/tcp.h
index eaa3113..6c5ff66 100644
--- a/include/linux/tcp.h
+++ b/include/linux/tcp.h
@@ -247,31 +247,38 @@ struct tcp_options_received {
sack_ok : 4, /* SACK seen on SYN packet */
snd_wscale : 4, /* Window scaling received from sender */
rcv_wscale : 4; /* Window scaling to send to receiver */
-/* SACKs data */
+ u8 cookie_plus:6, /* bytes in authenticator/cookie option */
+ cookie_out_never:1,
+ cookie_in_always:1;
u8 num_sacks; /* Number of SACK blocks */
- u16 user_mss; /* mss requested by user in ioctl */
+ u16 user_mss; /* mss requested by user in ioctl */
u16 mss_clamp; /* Maximal mss, negotiated at connection setup */
};
static inline void tcp_clear_options(struct tcp_options_received *rx_opt)
{
- rx_opt->tstamp_ok = rx_opt->sack_ok = rx_opt->wscale_ok = rx_opt->snd_wscale = 0;
+ rx_opt->tstamp_ok = rx_opt->sack_ok = 0;
+ rx_opt->wscale_ok = rx_opt->snd_wscale = 0;
+ rx_opt->cookie_plus = 0;
}
/* This is the max number of SACKS that we'll generate and process. It's safe
- * to increse this, although since:
+ * to increase this, although since:
* size = TCPOLEN_SACK_BASE_ALIGNED (4) + n * TCPOLEN_SACK_PERBLOCK (8)
* only four options will fit in a standard TCP header */
#define TCP_NUM_SACKS 4
+struct tcp_cookie_values;
+struct tcp_request_sock_ops;
+
struct tcp_request_sock {
struct inet_request_sock req;
#ifdef CONFIG_TCP_MD5SIG
/* Only used by TCP MD5 Signature so far. */
const struct tcp_request_sock_ops *af_specific;
#endif
- u32 rcv_isn;
- u32 snt_isn;
+ u32 rcv_isn;
+ u32 snt_isn;
};
static inline struct tcp_request_sock *tcp_rsk(const struct request_sock *req)
@@ -441,6 +448,12 @@ struct tcp_sock {
/* TCP MD5 Signature Option information */
struct tcp_md5sig_info *md5sig_info;
#endif
+
+ /* When the cookie options are generated and exchanged, then this
+ * object holds a reference to them (cookie_values->kref). Also
+ * contains related tcp_cookie_transactions fields.
+ */
+ struct tcp_cookie_values *cookie_values;
};
static inline struct tcp_sock *tcp_sk(const struct sock *sk)
@@ -459,6 +472,10 @@ struct tcp_timewait_sock {
u16 tw_md5_keylen;
u8 tw_md5_key[TCP_MD5SIG_MAXKEYLEN];
#endif
+ /* Few sockets in timewait have cookies; in that case, then this
+ * object holds a reference to them (tw_cookie_values->kref).
+ */
+ struct tcp_cookie_values *tw_cookie_values;
};
static inline struct tcp_timewait_sock *tcp_twsk(const struct sock *sk)
diff --git a/include/net/tcp.h b/include/net/tcp.h
index 738b65f..3a4c840 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -30,6 +30,7 @@
#include <linux/dmaengine.h>
#include <linux/crypto.h>
#include <linux/cryptohash.h>
+#include <linux/kref.h>
#include <net/inet_connection_sock.h>
#include <net/inet_timewait_sock.h>
@@ -164,6 +165,7 @@ extern void tcp_time_wait(struct sock *sk, int state, int timeo);
#define TCPOPT_SACK 5 /* SACK Block */
#define TCPOPT_TIMESTAMP 8 /* Better RTT estimations/PAWS */
#define TCPOPT_MD5SIG 19 /* MD5 Signature (RFC2385) */
+#define TCPOPT_COOKIE 253 /* Cookie extension (experimental) */
/*
* TCP option lengths
@@ -174,6 +176,10 @@ extern void tcp_time_wait(struct sock *sk, int state, int timeo);
#define TCPOLEN_SACK_PERM 2
#define TCPOLEN_TIMESTAMP 10
#define TCPOLEN_MD5SIG 18
+#define TCPOLEN_COOKIE_BASE 2 /* Cookie-less header extension */
+#define TCPOLEN_COOKIE_PAIR 3 /* Cookie pair header extension */
+#define TCPOLEN_COOKIE_MIN (TCPOLEN_COOKIE_BASE+TCP_COOKIE_MIN)
+#define TCPOLEN_COOKIE_MAX (TCPOLEN_COOKIE_BASE+TCP_COOKIE_MAX)
/* But this is what stacks really send out. */
#define TCPOLEN_TSTAMP_ALIGNED 12
@@ -1482,6 +1488,72 @@ struct tcp_request_sock_ops {
extern int tcp_cookie_generator(u32 *bakery);
+/**
+ * A tcp_sock contains a pointer to the current value, and this is cloned to
+ * the tcp_timewait_sock.
+ *
+ * @cookie_pair: variable data from the option exchange.
+ *
+ * @cookie_desired: user specified tcpct_cookie_desired. Zero
+ * indicates default (sysctl_tcp_cookie_size).
+ * After cookie sent, remembers size of cookie.
+ * Range 0, TCP_COOKIE_MIN to TCP_COOKIE_MAX.
+ *
+ * @s_data_desired: user specified tcpct_s_data_desired. When the
+ * constant payload is specified (@s_data_constant),
+ * holds its length instead.
+ * Range 0 to TCP_MSS_DESIRED.
+ *
+ * @s_data_payload: constant data that is to be included in the
+ * payload of SYN or SYNACK segments when the
+ * cookie option is present.
+ */
+struct tcp_cookie_values {
+ struct kref kref;
+ u8 cookie_pair[TCP_COOKIE_PAIR_SIZE];
+ u8 cookie_pair_size;
+ u8 cookie_desired;
+ u16 s_data_desired:11,
+ s_data_constant:1,
+ s_data_in:1,
+ s_data_out:1,
+ s_data_unused:2;
+ u8 s_data_payload[0];
+};
+
+static inline void tcp_cookie_values_release(struct kref *kref)
+{
+ kfree(container_of(kref, struct tcp_cookie_values, kref));
+}
+
+/* The length of constant payload data. Note that s_data_desired is
+ * overloaded, depending on s_data_constant: either the length of constant
+ * data (returned here) or the limit on variable data.
+ */
+static inline int tcp_s_data_size(const struct tcp_sock *tp)
+{
+ return (tp->cookie_values != NULL && tp->cookie_values->s_data_constant)
+ ? tp->cookie_values->s_data_desired
+ : 0;
+}
+
+/* As tcp_request_sock has already been extended in other places, the
+ * only remaining method is to pass stack values along as function
+ * parameters. These parameters are not needed after sending SYNACK.
+ */
+struct tcp_extend_values {
+ struct request_values rv;
+ u32 cookie_bakery[COOKIE_WORKSPACE_WORDS];
+ u8 cookie_plus:6,
+ cookie_out_never:1,
+ cookie_in_always:1;
+};
+
+static inline struct tcp_extend_values *tcp_xv(struct request_values *rvp)
+{
+ return (struct tcp_extend_values *)rvp;
+}
+
extern void tcp_v4_init(void);
extern void tcp_init(void);
--
1.6.3.3
^ permalink raw reply related
* [net-next-2.6 PATCH] ixgbe: Flush the LSC mask change to prevent repeated interrupts
From: Jeff Kirsher @ 2009-11-13 4:47 UTC (permalink / raw)
To: davem; +Cc: netdev, gospo, Shannon Nelson, Jeff Kirsher
From: Nelson, Shannon <shannon.nelson@intel.com>
Signed-off-by: Shannon Nelson <shannon.nelson@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
drivers/net/ixgbe/ixgbe_main.c | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c
index afd49e0..0489286 100644
--- a/drivers/net/ixgbe/ixgbe_main.c
+++ b/drivers/net/ixgbe/ixgbe_main.c
@@ -1204,6 +1204,7 @@ static void ixgbe_check_lsc(struct ixgbe_adapter *adapter)
adapter->link_check_timeout = jiffies;
if (!test_bit(__IXGBE_DOWN, &adapter->state)) {
IXGBE_WRITE_REG(hw, IXGBE_EIMC, IXGBE_EIMC_LSC);
+ IXGBE_WRITE_FLUSH(hw);
schedule_work(&adapter->watchdog_task);
}
}
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox