Netdev List
 help / color / mirror / Atom feed
* Re: [PATCH v1] net: filter: Just In Time compiler
From: Eric Dumazet @ 2011-04-03  9:04 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, acme
In-Reply-To: <20110402.224344.191403947.davem@davemloft.net>

Le samedi 02 avril 2011 à 22:43 -0700, David Miller a écrit :
> From: Eric Dumazet <eric.dumazet@gmail.com>
> Date: Sun, 03 Apr 2011 00:28:21 +0200
> 
> > In order to speedup packet filtering, here is an implementation of a JIT
> > compiler for x86_64
> 
> Looks great.  Of course, everything should sit under arch/${ARCH}/ in the
> end, but this is an excellent proof of concept!

Yes. The real thing would be to implement iptables as JIT ;)



^ permalink raw reply

* Re: [PATCH v2] vlan: convert VLAN devices to use ndo_fix_features()
From: David Miller @ 2011-04-03  5:50 UTC (permalink / raw)
  To: mirq-linux; +Cc: netdev, jesse, kaber, john.r.fastabend, eric.dumazet
In-Reply-To: <20110402144141.0666C1389B@rere.qmqm.pl>

From: Michał Mirosław <mirq-linux@rere.qmqm.pl>
Date: Sat,  2 Apr 2011 16:41:41 +0200 (CEST)

> Note: get_flags was actually broken, because it should return the
> flags capped with vlan_features. This is now done implicitly by
> limiting netdev->hw_features.
> 
> RX checksumming offload control is (and was) broken, as there was no way
> before to say whether it's done for tagged packets.
> 
> Signed-off-by: Michał Mirosław <mirq-linux@rere.qmqm.pl>

Applied.

^ permalink raw reply

* Re: [PATCH] net: Call netdev_features_change() from netdev_update_features()
From: David Miller @ 2011-04-03  5:50 UTC (permalink / raw)
  To: mirq-linux; +Cc: netdev, bhutchings, jesse
In-Reply-To: <20110402144141.0192613909@rere.qmqm.pl>

From: Michał Mirosław <mirq-linux@rere.qmqm.pl>
Date: Sat,  2 Apr 2011 16:41:40 +0200 (CEST)

> Issue FEAT_CHANGE notification when features are changed by
> netdev_update_features().  This will allow changes made by extra constraints
> on e.g. MTU change to be properly propagated like changes via ethtool.
> 
> Signed-off-by: Michał Mirosław <mirq-linux@rere.qmqm.pl>

Applied.

^ permalink raw reply

* Re: [PATCH v1] net: filter: Just In Time compiler
From: David Miller @ 2011-04-03  5:43 UTC (permalink / raw)
  To: eric.dumazet; +Cc: netdev, acme
In-Reply-To: <1301783301.2837.77.camel@edumazet-laptop>

From: Eric Dumazet <eric.dumazet@gmail.com>
Date: Sun, 03 Apr 2011 00:28:21 +0200

> In order to speedup packet filtering, here is an implementation of a JIT
> compiler for x86_64

Looks great.  Of course, everything should sit under arch/${ARCH}/ in the
end, but this is an excellent proof of concept!

^ permalink raw reply

* Re: [PATCH v1] net: filter: Just In Time compiler
From: Eric Dumazet @ 2011-04-03  5:41 UTC (permalink / raw)
  To: Hagen Paul Pfeifer; +Cc: David Miller, netdev, Arnaldo Carvalho de Melo
In-Reply-To: <20110402225002.GJ3108@nuttenaction>

Le dimanche 03 avril 2011 à 00:50 +0200, Hagen Paul Pfeifer a écrit :
> * Eric Dumazet | 2011-04-03 00:28:21 [+0200]:
> 
> >In order to speedup packet filtering, here is an implementation of a JIT
> >compiler for x86_64
> 
> Great work! Eric, do you have some numbers? For a trivial "ret" filter the
> performance gain should be marginal - if any. But what with complex filter
> rules? And as said last time: libpcap optimizer seems to be target number one
> for optimization. Again: great work!

Preliminary performance results are good, even for basic filter.

(I changed the AND operator to be able to use "and $imm8,%al" for
typical net addr/[24-31] operations, and "and $imm16,%ax" for
addr/[16-23] ones)

case BPF_S_ALU_AND_K:
	if (K >= 0xFFFFFF00) {
		EMIT2(0x24, K & 0xFF); /* and imm8,%al */
	} else if (K >= 0xFFFF0000) {
		EMIT2(0x66, 0x25);	/* and imm16,%ax */
		EMIT2(K, 2);
	} else {
		EMIT1_off32(0x25, K);	/* and imm32,%eax */
	}
	break;


dummy0 udpflood, and following basic active tcpdump, catching no frames
(condition is not met)

# tcpdump -p -n -s 0 -i dummy0 net 192.168.2.0/24 -d
(000) ldh      [12]
(001) jeq      #0x800           jt 2	jf 8
(002) ld       [26]
(003) and      #0xffffff00
(004) jeq      #0xc0a80200      jt 16	jf 5
(005) ld       [30]
(006) and      #0xffffff00
(007) jeq      #0xc0a80200      jt 16	jf 17
(008) jeq      #0x806           jt 10	jf 9
(009) jeq      #0x8035          jt 10	jf 17
(010) ld       [28]
(011) and      #0xffffff00
(012) jeq      #0xc0a80200      jt 16	jf 13
(013) ld       [38]
(014) and      #0xffffff00
(015) jeq      #0xc0a80200      jt 16	jf 17
(016) ret      #65535
(017) ret      #0

flen=18 proglen=147 pass=3 image=ffffffffa00b5000
JIT code: ffffffffa00b5000: 55 48 89 e5 48 83 ec 60 48 89 5d f8 44 8b 4f 60
JIT code: ffffffffa00b5010: 44 2b 4f 64 4c 8b 87 b8 00 00 00 be 0c 00 00 00
JIT code: ffffffffa00b5020: e8 24 dc 2e e1 3d 00 08 00 00 75 28 be 1a 00 00
JIT code: ffffffffa00b5030: 00 e8 fe db 2e e1 24 00 3d 00 02 a8 c0 74 49 be
JIT code: ffffffffa00b5040: 1e 00 00 00 e8 eb db 2e e1 24 00 3d 00 02 a8 c0
JIT code: ffffffffa00b5050: 74 36 eb 3b 3d 06 08 00 00 74 07 3d 35 80 00 00
JIT code: ffffffffa00b5060: 75 2d be 1c 00 00 00 e8 c8 db 2e e1 24 00 3d 00
JIT code: ffffffffa00b5070: 02 a8 c0 74 13 be 26 00 00 00 e8 b5 db 2e e1 24
JIT code: ffffffffa00b5080: 00 3d 00 02 a8 c0 75 07 b8 ff ff 00 00 eb 02 31
JIT code: ffffffffa00b5090: c0 c9 c3

Benchmark :
ifconfig dummy0 10.2.2.2 netmask 255.255.255.0 up

1) Baseline (no active tcpdump)

# time /root/udpflood -f -l 10000000 10.2.2.1

real	0m7.941s
user	0m0.823s
sys	0m7.103s

2) Time with normal filtering (JIT disabled)

# time /root/udpflood -f -l 10000000 10.2.2.1

real	0m10.165s
user	0m1.000s
sys	0m9.149s


3) JIT enabled

# time /root/udpflood -f -l 10000000 10.2.2.1

real	0m9.615s
user	0m1.022s
sys	0m8.578s

Thats about 50ns saved per invocation, on a E5540  @ 2.53GHz

We could get better results if we inline the fastpath of ld/ldh/ldb,
instead of calling helpers. (In this case, avoiding three call/ret
instructions pair).




^ permalink raw reply

* Re: [PATCH v2] ROSE: prevent heap corruption with bad facilities
From: Ben Hutchings @ 2011-04-03  4:23 UTC (permalink / raw)
  To: Jiri Bohac; +Cc: Dan Rosenberg, ralf, davem, netdev, security
In-Reply-To: <20110331180225.GA6677@midget.suse.cz>

[-- Attachment #1: Type: text/plain, Size: 1505 bytes --]

On Thu, 2011-03-31 at 20:02 +0200, Jiri Bohac wrote:
[...]
> This last hunk does not look correct. In the default branch of
> the switch, you set len = 1, which means 
> 	p += 2; facilities_len -= 2.
> 
> The original code does 
> 	facilities_len--; p++;
> ... and it looks correct. So, to get the old behaviour back:
> 
> diff --git a/net/rose/rose_subr.c b/net/rose/rose_subr.c
> index f6c71ca..9777700 100644
> --- a/net/rose/rose_subr.c
> +++ b/net/rose/rose_subr.c
> @@ -418,7 +418,7 @@ int rose_parse_facilities(unsigned char *p, unsigned packet_len,
>  
>  		default:
>  			printk(KERN_DEBUG "ROSE: rose_parse_facilities - unknown facilities family %02X\n", *p);
> -			len = 1;
> +			len = 0;
>  			break;
>  		}

Yes, agreed.

> However, I wonder how much sense it makes to continue parsing the
> facilities if an unknown facility family appears. We don't know
> the length of its data, so we will interpret each 16 bytes a new
> facilities header, hopefully soon bailing out on *p != 0x00.
>
> In case of a long packet where every other byte is zero, the loop
> will spam the kernel log with the printk ... which could probably
> be classified as a security problem on its own. So how about the
> following instead? I have no idea if this breaks some rose
> specification, though. 
[...]

I don't know any more than you do; maybe Ralf knows or can find out.

Ben.

-- 
Ben Hutchings
Once a job is fouled up, anything done to improve it makes it worse.

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 828 bytes --]

^ permalink raw reply

* Re: extending feature word.
From: Mahesh Bandewar @ 2011-04-03  3:09 UTC (permalink / raw)
  To: Michał Mirosław; +Cc: linux-netdev, Ben Hutchings, David Miller
In-Reply-To: <20110402124207.GB3147@rere.qmqm.pl>

On Sat, Apr 2, 2011 at 5:42 AM, Michał Mirosław <mirq-linux@rere.qmqm.pl> wrote:
> On Fri, Apr 01, 2011 at 07:07:05PM -0700, Mahesh Bandewar wrote:
>> Thanks for your comments on my loop-back patch. I was looking at the
>> code today from the perspective of extending various "features" for
>> word to an array of words and as Michael has pointed out, it's a huge
>> change. So I'm thinking on the following lines
>> (include/linux/netdevice.h)
>>
>> +#define DEV_FEATURE_WORDS      2
>> +#define LEGACY_FEATURE_WORD    0
>>        /* currently active device features */
>> -       u32                     features;
>> +       u32                     features[DEV_FEATURE_WORDS];
>>        /* user-changeable features */
>> -       u32                     hw_features;
>> +       u32                     hw_features[DEV_FEATURE_WORDS];
>>        /* user-requested features */
>> -       u32                     wanted_features;
>> +       u32                     wanted_features[DEV_FEATURE_WORDS];
>>        /* VLAN feature mask */
>> -       u32                     vlan_features;
>> +       u32                     vlan_features[DEV_FEATURE_WORDS];
>> +#define legacy_features                features[LEGACY_FEATURE_WORD]
>> +#define legacy_hw_features     hw_features[LEGACY_FEATURE_WORD]
>> +#define legacy_wanted_features wanted_features[LEGACY_FEATURE_WORD]
>> +#define legacy_vlan_features    vlan_features[LEGACY_FEATURE_WORD]
>>
>>
>> So that it will be a matter of -
>>
>> s/features/legacy_features/
>> s/hw_features/legacy_hw_features/
>> s/wanted_features/legacy_wanted_features/
>> s/vlan_features/legacy_vlan_features/
>>
>> to start with as a first step. Once this is done, legacy_* can be
>> changed with respective arrays and modified as per the need. Comments?
>
> You could just s/features/features[0]/ as well. Why the extra hiding?
>
I was thinking that features[0] is really a short term solution sine
there are only couple of bits left in this word and any new will have
to be added into the next word. So eventually it should be managed
properly at all these places where we'll replace it with features[0].
So it's a nice indication that this was the legacy way of dealing and
need to be altered for additional bits (especially where we see
legacy_* stuff) where ever required.

On the other hand replacing with features[0] breaks the NETDEVICE_SHOW
macro in net/core/net-sysfs.c and need to be expanded manually.

> If you want to split the work, it would be clearer to first convert
> hw_features and wanted_features (with all the core code touching it -
> this is the easy part), then vlan_features (this includes drivers'
> and VLAN code) and then features (it's all over).
>
I like the idea of splitting but it will be only useful when all of it
is done and not partially, isn't it? Or am I missing something?

> Best Regards,
> Michał Mirosław
>

^ permalink raw reply

* Re: [PATCH v1] net: filter: Just In Time compiler
From: Ben Hutchings @ 2011-04-02 22:53 UTC (permalink / raw)
  To: Eric Dumazet; +Cc: David Miller, netdev, Arnaldo Carvalho de Melo
In-Reply-To: <1301783301.2837.77.camel@edumazet-laptop>

On Sun, 2011-04-03 at 00:28 +0200, Eric Dumazet wrote:
> In order to speedup packet filtering, here is an implementation of a JIT
> compiler for x86_64

Then put it under arch/x86!

[...]
> diff --git a/net/Kconfig b/net/Kconfig
> index 79cabf1..04a1726 100644
> --- a/net/Kconfig
> +++ b/net/Kconfig
> @@ -232,6 +232,11 @@ config XPS
>  	depends on SMP && SYSFS && USE_GENERIC_SMP_HELPERS
>  	default y
>  
> +config BPF_JIT
> +	boolean
> +	depends on X86_64
> +	default y
[...]

This should presumably be:
	depends on HAVE_BPF_JIT
while arch/x86/Kconfig would define HAVE_BPF_JIT.

Ben.

-- 
Ben Hutchings, Senior Software Engineer, Solarflare
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.


^ permalink raw reply

* Re: [PATCH v1] net: filter: Just In Time compiler
From: Hagen Paul Pfeifer @ 2011-04-02 22:50 UTC (permalink / raw)
  To: Eric Dumazet; +Cc: David Miller, netdev, Arnaldo Carvalho de Melo
In-Reply-To: <1301783301.2837.77.camel@edumazet-laptop>

* Eric Dumazet | 2011-04-03 00:28:21 [+0200]:

>In order to speedup packet filtering, here is an implementation of a JIT
>compiler for x86_64

Great work! Eric, do you have some numbers? For a trivial "ret" filter the
performance gain should be marginal - if any. But what with complex filter
rules? And as said last time: libpcap optimizer seems to be target number one
for optimization. Again: great work!

Hagen

^ permalink raw reply

* [PATCH v1] net: filter: Just In Time compiler
From: Eric Dumazet @ 2011-04-02 22:28 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, Arnaldo Carvalho de Melo

In order to speedup packet filtering, here is an implementation of a JIT
compiler for x86_64

It is disabled by default, and must be enabled by the admin.

echo 1 >/proc/sys/net/core/bpf_jit_enable

It uses module_alloc() and module_free() to get memory in the 2GB text
kernel range since we call helpers functions from the generated code.

EAX : BPF A accumulator
EBX : BPF X accumulator
RDI : pointer to skb   (first argument given to JIT function)
RBP : frame pointer (even if CONFIG_FRAME_POINTER=n)
r9d : skb->len - skb->data_len (headlen)
r8  : skb->data

To get a trace of generated code, use :

echo 2 >/proc/sys/net/core/bpf_jit_enable

Example of generated code :

flen=14 proglen=139 pass=3 image=ffffffffa00d5000
JIT code: ffffffffa00d5000: 55 48 89 e5 48 83 ec 60 48 89 5d f8 44 8b 4f 60
JIT code: ffffffffa00d5010: 44 2b 4f 64 4c 8b 87 b8 00 00 00 be 0c 00 00 00
JIT code: ffffffffa00d5020: e8 24 1b 2f e1 3d 00 08 00 00 75 24 be 1a 00 00
JIT code: ffffffffa00d5030: 00 e8 fe 1a 2f e1 3d 01 00 a8 c0 74 43 be 1e 00
JIT code: ffffffffa00d5040: 00 00 e8 ed 1a 2f e1 3d 01 00 a8 c0 74 32 eb 37
JIT code: ffffffffa00d5050: 3d 06 08 00 00 74 07 3d 35 80 00 00 75 29 be 1c
JIT code: ffffffffa00d5060: 00 00 00 e8 cc 1a 2f e1 3d 01 00 a8 c0 74 11 be
JIT code: ffffffffa00d5070: 26 00 00 00 e8 bb 1a 2f e1 3d 01 00 a8 c0 75 07
JIT code: ffffffffa00d5080: b8 ff ff 00 00 eb 02 31 c0 c9 c3
# tcpdump -p -n -s 0 -i eth1 host 192.168.0.1 -d
(000) ldh      [12]
(001) jeq      #0x800           jt 2	jf 6
(002) ld       [26]
(003) jeq      #0xc0a80001      jt 12	jf 4
(004) ld       [30]
(005) jeq      #0xc0a80001      jt 12	jf 13
(006) jeq      #0x806           jt 8	jf 7
(007) jeq      #0x8035          jt 8	jf 13
(008) ld       [28]
(009) jeq      #0xc0a80001      jt 12	jf 10
(010) ld       [38]
(011) jeq      #0xc0a80001      jt 12	jf 13
(012) ret      #65535
(013) ret      #0

Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
Cc: Arnaldo Carvalho de Melo <acme@infradead.org>
---
perf tool might need some changes to take into account JIT.

 Documentation/sysctl/net.txt |   11 
 include/linux/filter.h       |   76 +++
 include/linux/netdevice.h    |    1 
 net/Kconfig                  |    5 
 net/core/Makefile            |    2 
 net/core/bpf_jit.S           |  142 +++++++
 net/core/bpf_jit_comp.c      |  636 +++++++++++++++++++++++++++++++++
 net/core/filter.c            |   65 ---
 net/core/sysctl_net_core.c   |    9 
 net/packet/af_packet.c       |    2 
 10 files changed, 888 insertions(+), 61 deletions(-)

diff --git a/Documentation/sysctl/net.txt b/Documentation/sysctl/net.txt
index cbd05ff..3201a70 100644
--- a/Documentation/sysctl/net.txt
+++ b/Documentation/sysctl/net.txt
@@ -32,6 +32,17 @@ Table : Subdirectories in /proc/sys/net
 1. /proc/sys/net/core - Network core options
 -------------------------------------------------------
 
+bpf_jit_enable
+--------------
+
+This enables Berkeley Packet Filter Just in Time compiler.
+Currently supported on x86_64 architecture, bpf_jit provides a framework
+to speed packet filtering, the one used by tcpdump/libpcap for example.
+Values :
+	0 - disable the JIT (default value)
+	1 - enable the JIT
+	2 - enable the JIT and ask the compiler to emit traces on kernel log.
+
 rmem_default
 ------------
 
diff --git a/include/linux/filter.h b/include/linux/filter.h
index 45266b7..4609b85 100644
--- a/include/linux/filter.h
+++ b/include/linux/filter.h
@@ -135,6 +135,8 @@ struct sk_filter
 {
 	atomic_t		refcnt;
 	unsigned int         	len;	/* Number of filter blocks */
+	unsigned int		(*bpf_func)(const struct sk_buff *skb,
+					    const struct sock_filter *filter);
 	struct rcu_head		rcu;
 	struct sock_filter     	insns[0];
 };
@@ -153,6 +155,80 @@ extern unsigned int sk_run_filter(const struct sk_buff *skb,
 extern int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk);
 extern int sk_detach_filter(struct sock *sk);
 extern int sk_chk_filter(struct sock_filter *filter, int flen);
+
+#ifdef CONFIG_BPF_JIT
+extern void bpf_jit_compile(struct sk_filter *fp);
+extern void bpf_jit_free(struct sk_filter *fp);
+#define SK_RUN_FILTER(FILTER, SKB) (*FILTER->bpf_func)(SKB, FILTER->insns)
+#else
+static inline void bpf_jit_compile(struct sk_filter *fp)
+{
+}
+static inline void bpf_jit_free(struct sk_filter *fp)
+{
+}
+#define SK_RUN_FILTER(FILTER, SKB) sk_run_filter(SKB, FILTER->insns)
+#endif
+
+enum {
+	BPF_S_RET_K = 1,
+	BPF_S_RET_A,
+	BPF_S_ALU_ADD_K,
+	BPF_S_ALU_ADD_X,
+	BPF_S_ALU_SUB_K,
+	BPF_S_ALU_SUB_X,
+	BPF_S_ALU_MUL_K,
+	BPF_S_ALU_MUL_X,
+	BPF_S_ALU_DIV_X,
+	BPF_S_ALU_AND_K,
+	BPF_S_ALU_AND_X,
+	BPF_S_ALU_OR_K,
+	BPF_S_ALU_OR_X,
+	BPF_S_ALU_LSH_K,
+	BPF_S_ALU_LSH_X,
+	BPF_S_ALU_RSH_K,
+	BPF_S_ALU_RSH_X,
+	BPF_S_ALU_NEG,
+	BPF_S_LD_W_ABS,
+	BPF_S_LD_H_ABS,
+	BPF_S_LD_B_ABS,
+	BPF_S_LD_W_LEN,
+	BPF_S_LD_W_IND,
+	BPF_S_LD_H_IND,
+	BPF_S_LD_B_IND,
+	BPF_S_LD_IMM,
+	BPF_S_LDX_W_LEN,
+	BPF_S_LDX_B_MSH,
+	BPF_S_LDX_IMM,
+	BPF_S_MISC_TAX,
+	BPF_S_MISC_TXA,
+	BPF_S_ALU_DIV_K,
+	BPF_S_LD_MEM,
+	BPF_S_LDX_MEM,
+	BPF_S_ST,
+	BPF_S_STX,
+	BPF_S_JMP_JA,
+	BPF_S_JMP_JEQ_K,
+	BPF_S_JMP_JEQ_X,
+	BPF_S_JMP_JGE_K,
+	BPF_S_JMP_JGE_X,
+	BPF_S_JMP_JGT_K,
+	BPF_S_JMP_JGT_X,
+	BPF_S_JMP_JSET_K,
+	BPF_S_JMP_JSET_X,
+	/* Ancillary data */
+	BPF_S_ANC_PROTOCOL,
+	BPF_S_ANC_PKTTYPE,
+	BPF_S_ANC_IFINDEX,
+	BPF_S_ANC_NLATTR,
+	BPF_S_ANC_NLATTR_NEST,
+	BPF_S_ANC_MARK,
+	BPF_S_ANC_QUEUE,
+	BPF_S_ANC_HATYPE,
+	BPF_S_ANC_RXHASH,
+	BPF_S_ANC_CPU,
+};
+
 #endif /* __KERNEL__ */
 
 #endif /* __LINUX_FILTER_H__ */
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 5eeb2cd..7381196 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -2513,6 +2513,7 @@ extern struct rtnl_link_stats64 *dev_get_stats(struct net_device *dev,
 extern int		netdev_max_backlog;
 extern int		netdev_tstamp_prequeue;
 extern int		weight_p;
+extern int		bpf_jit_enable;
 extern int		netdev_set_master(struct net_device *dev, struct net_device *master);
 extern int netdev_set_bond_master(struct net_device *dev,
 				  struct net_device *master);
diff --git a/net/Kconfig b/net/Kconfig
index 79cabf1..04a1726 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -232,6 +232,11 @@ config XPS
 	depends on SMP && SYSFS && USE_GENERIC_SMP_HELPERS
 	default y
 
+config BPF_JIT
+	boolean
+	depends on X86_64
+	default y
+
 menu "Network testing"
 
 config NET_PKTGEN
diff --git a/net/core/Makefile b/net/core/Makefile
index 8a04dd2..a217995 100644
--- a/net/core/Makefile
+++ b/net/core/Makefile
@@ -19,3 +19,5 @@ obj-$(CONFIG_FIB_RULES) += fib_rules.o
 obj-$(CONFIG_TRACEPOINTS) += net-traces.o
 obj-$(CONFIG_NET_DROP_MONITOR) += drop_monitor.o
 obj-$(CONFIG_NETWORK_PHY_TIMESTAMPING) += timestamping.o
+obj-$(CONFIG_X86_64) += bpf_jit.o
+obj-$(CONFIG_BPF_JIT) += bpf_jit_comp.o
diff --git a/net/core/bpf_jit.S b/net/core/bpf_jit.S
new file mode 100644
index 0000000..a0a9843
--- /dev/null
+++ b/net/core/bpf_jit.S
@@ -0,0 +1,142 @@
+/* bpf_jit.S : BPF JIT helper functions
+ *
+ * Copyright (C) 2011 Eric Dumazet (eric.dumazet@gmail.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2
+ * of the License.
+ */
+#include <linux/linkage.h>
+#include <asm/dwarf2.h>
+
+/*
+ * Calling convention :
+ * rdi : skb pointer
+ * esi : offset of byte(s) to fetch in skb (can be scratched)
+ * r8  : copy of skb->data
+ * r9d : hlen = skb->len - skb->data_len
+ */
+#define SKBDATA	%r8
+
+sk_load_word_ind:
+	.globl	sk_load_word_ind
+
+	add	%ebx,%esi	/* offset += X */
+#	test    %esi,%esi	/* if (offset < 0) goto bpf_error; */
+	js	bpf_error
+
+sk_load_word:
+	.globl	sk_load_word
+
+	mov	%r9d,%eax		# hlen
+	sub	%esi,%eax		# hlen - offset
+	cmp	$3,%eax
+	jle	bpf_slow_path_word
+	mov     (SKBDATA,%rsi),%eax
+	bswap   %eax  			/* ntohl() */
+	ret
+
+
+sk_load_half_ind:
+	.globl sk_load_half_ind
+
+	add	%ebx,%esi	/* offset += X */
+	js	bpf_error
+
+sk_load_half:
+	.globl	sk_load_half
+
+	mov	%r9d,%eax
+	sub	%esi,%eax		#	hlen - offset
+	cmp	$1,%eax
+	jle	bpf_slow_path_half
+	movzwl	(SKBDATA,%rsi),%eax
+	rol	$8,%ax			# ntohs()
+	ret
+
+sk_load_byte_ind:
+	.globl sk_load_byte_ind
+	add	%ebx,%esi	/* offset += X */
+	js	bpf_error
+
+sk_load_byte:
+	.globl	sk_load_byte
+
+	cmp	%esi,%r9d   /* if (offset >= hlen) goto bpf_slow_path_byte */
+	jle	bpf_slow_path_byte
+	movzbl	(SKBDATA,%rsi),%eax
+	ret
+
+/**
+ * sk_load_byte_msh - BPF_S_LDX_B_MSH helper
+ *
+ * Implements BPF_S_LDX_B_MSH : ldxb  4*([offset]&0xf)
+ * Must preserve A accumulator (%eax)
+ * Inputs : %esi is the offset value, already known positive
+ */
+ENTRY(sk_load_byte_msh)
+	CFI_STARTPROC
+	cmp	%esi,%r9d      /* if (offset >= hlen) goto bpf_slow_path_byte_msh */
+	jle	bpf_slow_path_byte_msh
+	movzbl	(SKBDATA,%rsi),%ebx
+	and	$15,%bl
+	shl	$2,%bl
+	ret
+	CFI_ENDPROC
+ENDPROC(sk_load_byte_msh)
+
+bpf_error:
+# force a return 0 from jit handler
+	xor		%eax,%eax
+	mov		-8(%rbp),%rbx
+	leaveq
+	ret
+
+/* rsi contains offset and can be scratched */
+#define bpf_slow_path_common(LEN)		\
+	push	%rdi;    /* save skb */		\
+	push	%r9;				\
+	push	SKBDATA;			\
+/* rsi already has offset */			\
+	mov	$LEN,%ecx;	/* len */	\
+	lea	-12(%rbp),%rdx;			\
+	call	skb_copy_bits;			\
+	test    %eax,%eax;			\
+	pop	SKBDATA;			\
+	pop	%r9;				\
+	pop	%rdi
+
+
+bpf_slow_path_word:
+	bpf_slow_path_common(4)
+	js	bpf_error
+	mov	-12(%rbp),%eax
+	bswap	%eax
+	ret
+
+bpf_slow_path_half:
+	bpf_slow_path_common(2)
+	js	bpf_error
+	mov	-12(%rbp),%ax
+	rol	$8,%ax
+	movzwl	%ax,%eax		
+	ret
+
+bpf_slow_path_byte:
+	bpf_slow_path_common(1)
+	js	bpf_error
+	movzbl	-12(%rbp),%eax
+	ret
+
+bpf_slow_path_byte_msh:
+	xchg	%eax,%ebx /* dont lose A , X is about to be scratched */
+	bpf_slow_path_common(1)
+	js	bpf_error
+	movzbl	-12(%rbp),%eax
+	and	$15,%al
+	shl	$2,%al
+	xchg	%eax,%ebx
+	ret
+
+
diff --git a/net/core/bpf_jit_comp.c b/net/core/bpf_jit_comp.c
new file mode 100644
index 0000000..bd90315
--- /dev/null
+++ b/net/core/bpf_jit_comp.c
@@ -0,0 +1,636 @@
+/* bpf_jit_comp.c : BPF JIT compiler
+ *
+ * Copyright (C) 2011 Eric Dumazet (eric.dumazet@gmail.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2
+ * of the License.
+ */
+#include <linux/moduleloader.h>
+#include <asm/cacheflush.h>
+#include <linux/netdevice.h>
+#include <linux/filter.h>
+
+/*
+ * Conventions :
+ *  EAX : BPF A accumulator
+ *  EBX : BPF X accumulator
+ *  RDI : pointer to skb   (first argument given to JIT function)
+ *  RBP : frame pointer (even if CONFIG_FRAME_POINTER=n)
+ *  r9d : skb->len - skb->data_len (headlen)
+ *  r8  : skb->data
+ */
+int bpf_jit_enable __read_mostly;
+
+/*
+ * assembly code in net/core/bpf_jit.S
+ */
+extern u8 sk_load_word[], sk_load_half[], sk_load_byte[], sk_load_byte_msh[];
+extern u8 sk_load_word_ind[], sk_load_half_ind[], sk_load_byte_ind[];
+
+static inline u8 *emit_code(u8 *ptr, u32 bytes, unsigned int len)
+{
+	if (len == 1)
+		*ptr = bytes;
+	else if (len == 2)
+		*(u16 *)ptr = bytes;
+	else {
+		*(u32 *)ptr = bytes;
+		barrier();
+	}
+	return ptr + len;
+}
+
+#define EMIT(bytes, len)	do { prog = emit_code(prog, bytes, len); } while (0)
+
+#define EMIT1(b1)		EMIT(b1, 1)
+#define EMIT2(b1, b2)		EMIT((b1) + ((b2) << 8), 2)
+#define EMIT3(b1, b2, b3)	EMIT((b1) + ((b2) << 8) + ((b3) << 16), 3)
+#define EMIT4(b1, b2, b3, b4)   EMIT((b1) + ((b2) << 8) + ((b3) << 16) + ((b4) << 24), 4) 
+#define EMIT1_off32(b1, off)	do { EMIT1(b1); EMIT(off, 4);} while (0)
+
+#define CLEAR_A() EMIT2(0x31, 0xc0) /* xor %eax,%eax */
+#define CLEAR_X() EMIT2(0x31, 0xdb) /* xor %ebx,%ebx */
+
+static inline bool is_imm8(int value)
+{
+	return value <= 127 && value >= -128;
+}
+
+static inline bool is_near(int offset)
+{
+	return offset <= 127 && offset >= -128;
+}
+
+#define EMIT_JMP(offset)						\
+do {									\
+	if (offset) {							\
+		if (is_near(offset))					\
+			EMIT2(0xeb, offset); /* jmp .+off8 */		\
+		else							\
+			EMIT1_off32(0xe9, offset); /* jmp .+off32 */	\
+	}								\
+} while (0)
+	
+/* list of x86 cond jumps (. + s8)
+ * Add 0x10 (and an extra 0x0f) to generate far jumps (. + s32)
+ */
+#define X86_JB  0x72
+#define X86_JAE 0x73
+#define X86_JE  0x74
+#define X86_JNE 0x75
+#define X86_JBE 0x76
+#define X86_JA  0x77
+
+#define EMIT_COND_JMP(op, offset)				\
+do {								\
+	if (is_near(offset))					\
+		EMIT2(op, offset); /* jxx .+off8 */		\
+	else {							\
+		EMIT2(0x0f, op + 0x10);				\
+		EMIT(offset, 4); /* jxx .+off32 */		\
+	}							\
+} while (0)
+
+#define COND_SEL(CODE, TOP, FOP)	\
+	case CODE:			\
+		t_op = TOP;		\
+		f_op = FOP;		\
+		goto cond_branch
+
+
+#define SEEN_DATAREF 1 /* might call external helpers */
+#define SEEN_XREG    2 /* ebx is used */
+#define SEEN_MEM     4 /* use mem[] for temporary storage */
+
+static inline void bpf_flush_icache(void *start, void *end)
+{
+	mm_segment_t old_fs = get_fs();
+
+	set_fs(KERNEL_DS);
+	smp_wmb();
+	flush_icache_range((unsigned long)start, (unsigned long)end);
+	set_fs(old_fs);
+}
+
+
+void bpf_jit_compile(struct sk_filter *fp)
+{
+	u8 temp[64];
+	u8 *prog;
+	unsigned int proglen, oldproglen = 0;
+	int ilen, i;
+	int t_offset, f_offset;
+	u8 t_op, f_op, seen = 0, pass;
+	u8 *image = NULL;
+	u8 *func;
+	int pc_ret0 = -1; /* bpf index of first RET #0 instruction (if any) */
+	unsigned int cleanup_addr;
+	unsigned int *addrs;
+	const struct sock_filter *filter = fp->insns;
+	int flen = fp->len;
+
+	if (!bpf_jit_enable)
+		return;
+
+	addrs = kmalloc(flen * sizeof(*addrs), GFP_KERNEL);
+	if (addrs == NULL)
+		return;
+
+	/* Before first pass, make a rough estimation of addrs[]
+	 * each bpf instruction is translated to less than 64 bytes
+	 */
+	for (proglen = 0, i = 0; i < flen; i++) {
+		proglen += 64;
+		addrs[i] = proglen;
+	}
+	cleanup_addr = proglen; /* epilogue address */
+
+	for (pass = 0; pass < 10; pass++) {
+		/* no prologue/epilogue for trivial filters (RET something) */
+		proglen = 0;
+		prog = temp;
+
+		if (seen) {
+			EMIT4(0x55, 0x48, 0x89, 0xe5); /* push %rbp; mov %rsp,%rbp */
+			EMIT4(0x48, 0x83, 0xec, 96);	/* subq  $96,%rsp	*/
+			/* note : must save %rbx in case bpf_error is hit */
+			if (seen & (SEEN_XREG | SEEN_DATAREF))
+				EMIT4(0x48, 0x89, 0x5d, 0xf8); /* mov %rbx, -8(%rbp) */
+			if (seen & SEEN_XREG)
+				CLEAR_X(); /* make sure we dont leek kernel memory */
+
+			/*
+			 * If this filter needs to access skb data,
+			 * loads r9 and r8 with :
+			 *  r9 = skb->len - skb->data_len
+			 *  r8 = skb->data
+			 */
+			if (seen & SEEN_DATAREF) {
+				if (offsetof(struct sk_buff, len) <= 127)
+					/* mov    off8(%rdi),%r9d */
+					EMIT4(0x44, 0x8b, 0x4f, offsetof(struct sk_buff, len));
+				else {
+					/* mov    off32(%rdi),%r9d */
+					EMIT3(0x44, 0x8b, 0x8f);
+					EMIT(offsetof(struct sk_buff, len), 4);
+				}
+				if (is_imm8(offsetof(struct sk_buff, data_len)))
+					/* sub    off8(%rdi),%r9d */
+					EMIT4(0x44, 0x2b, 0x4f, offsetof(struct sk_buff, data_len));
+				else {
+					EMIT3(0x44, 0x2b, 0x8f);
+					EMIT(offsetof(struct sk_buff, data_len), 4);
+				}
+
+				if (is_imm8(offsetof(struct sk_buff, data)))
+					/* mov off8(%rdi),%r8 */
+					EMIT4(0x4c, 0x8b, 0x47, offsetof(struct sk_buff, data));
+				else {
+					/* mov off32(%rdi),%r8 */
+					EMIT3(0x4c, 0x8b, 0x87);
+					EMIT(offsetof(struct sk_buff, data), 4);
+				}
+			}
+		}
+
+		switch (filter[0].code) {
+		case BPF_S_RET_K:
+		case BPF_S_LD_W_LEN:
+		case BPF_S_ANC_PROTOCOL:
+		case BPF_S_ANC_IFINDEX:
+		case BPF_S_ANC_MARK:
+		case BPF_S_ANC_RXHASH:
+		case BPF_S_ANC_CPU:
+		case BPF_S_LD_W_ABS:
+		case BPF_S_LD_H_ABS:
+		case BPF_S_LD_B_ABS:
+			/* first instruction sets A register (or is RET 'constant') */
+			break;
+		default:
+			CLEAR_A(); /* A = 0 */
+		}
+
+		for (i = 0; i < flen; i++) {
+			unsigned int K = filter[i].k;
+
+			switch (filter[i].code) {
+			case BPF_S_ALU_ADD_X: /* A += X; */
+				seen |= SEEN_XREG;
+				EMIT2(0x01, 0xd8);		/* add %ebx,%eax */
+				break;
+			case BPF_S_ALU_ADD_K: /* A += K; */
+				if (!K)
+					break;
+				if (is_imm8(K))
+					EMIT3(0x83, 0xc0, K);	/* add imm8,%eax */
+				else
+					EMIT1_off32(0x05, K);	/* add imm32,%eax */
+				break;
+			case BPF_S_ALU_SUB_X: /* A -= X; */
+				seen |= SEEN_XREG;
+				EMIT2(0x29, 0xd8);		/* sub    %ebx,%eax */
+				break;
+			case BPF_S_ALU_SUB_K: /* A -= K */
+				if (!K)
+					break;
+				if (is_imm8(K))
+					EMIT3(0x83, 0xe8, K); /* sub imm8,%eax */
+				else
+					EMIT1_off32(0x2d, K); /* sub imm32,%eax */
+				break;
+			case BPF_S_ALU_MUL_X: /* A *= X; */
+				seen |= SEEN_XREG;
+				EMIT3(0x0f, 0xaf, 0xc3);	/* imul %ebx,%eax */
+				break;
+			case BPF_S_ALU_MUL_K: /* A *= K */
+				if (is_imm8(K))
+					EMIT3(0x6b, 0xc0, K); /* imul imm8,%eax,%eax */
+				else {
+					EMIT2(0x69, 0xc0);		/* imul imm32,%eax */
+					EMIT(K, 4);
+				}
+				break;
+			case BPF_S_ALU_DIV_X: /* A /= X; */
+				seen |= SEEN_XREG;
+				EMIT2(0x85, 0xdb);	/* test %ebx,%ebx */
+				if (pc_ret0 != -1)
+					EMIT_COND_JMP(X86_JE, addrs[pc_ret0] - (addrs[i] - 4));
+				else {
+					EMIT_COND_JMP(X86_JNE, 2 + 5);
+					CLEAR_A();
+					EMIT1_off32(0xe9, cleanup_addr - (addrs[i] - 4)); /* jmp .+off32 */
+				}
+				EMIT4(0x31, 0xd2, 0xf7, 0xf3); /* xor %edx,%edx; div %ebx */
+				break;
+			case BPF_S_ALU_DIV_K: /* A = reciprocal_divide(A, K); */
+				EMIT3(0x48, 0x69, 0xc0); /* imul imm32,%rax,%rax */
+				EMIT(K, 4);
+				EMIT4(0x48, 0xc1, 0xe8, 0x20); /* shr $0x20,%rax */
+				break;
+			case BPF_S_ALU_AND_X:
+				seen |= SEEN_XREG;
+				EMIT2(0x21, 0xd8);		/* and %ebx,%eax */
+				break;
+			case BPF_S_ALU_AND_K:
+				if (is_imm8(K))
+					EMIT3(0x83, 0xe0, K);	/* and imm8,%eax */
+				else
+					EMIT1_off32(0x25, K);	/* and imm32,%eax */
+				break;
+			case BPF_S_ALU_OR_X:
+				seen |= SEEN_XREG;
+				EMIT2(0x09, 0xd8);		/* or %ebx,%eax */
+				break;
+			case BPF_S_ALU_OR_K:
+				if (is_imm8(K))
+					EMIT3(0x83, 0xc8, K); /* or imm8,%eax */
+				else
+					EMIT1_off32(0x0d, K);	/* or imm32,%eax */
+				break;
+			case BPF_S_ALU_LSH_X: /* A <<= X; */
+				seen |= SEEN_XREG;
+				EMIT4(0x89, 0xd9, 0xd3, 0xe0);	/* mov %ebx,%ecx; shl %cl,%eax */
+				break;
+			case BPF_S_ALU_LSH_K:
+				if (K == 0)
+					break;
+				else if (K == 1)
+					EMIT2(0xd1, 0xe0); /* shl %eax */
+				else
+					EMIT3(0xc1, 0xe0, K);
+				break;
+			case BPF_S_ALU_RSH_X: /* A >>= X; */
+				seen |= SEEN_XREG;
+				EMIT4(0x89, 0xd9, 0xd3, 0xe8);	/* mov %ebx,%ecx; shr %cl,%eax */
+				break;
+			case BPF_S_ALU_RSH_K: /* A >>= K; */
+				if (K == 0)
+					break;
+				else if (K == 1)
+					EMIT2(0xd1, 0xe8); /* shr %eax */
+				else
+					EMIT3(0xc1, 0xe8, K);
+				break;
+			case BPF_S_ALU_NEG:
+				EMIT2(0xf7, 0xd8);		/* neg %eax */
+				break;
+			case BPF_S_RET_K:
+				if (!K) {
+					if (pc_ret0 == -1)
+						pc_ret0 = i;
+					CLEAR_A();
+				} else {
+					EMIT1_off32(0xb8, K);	/* mov $imm32,%eax */
+				}
+				/* fallinto */
+			case BPF_S_RET_A:
+				if (seen) {
+					if (i != flen - 1) {
+						EMIT_JMP(cleanup_addr - addrs[i]);
+						break;
+					}
+					if (seen & SEEN_XREG)
+						EMIT4(0x48, 0x8b, 0x5d, 0xf8);  /* mov  -8(%rbp),%rbx */
+					EMIT1(0xc9);		/* leaveq */
+				}
+				EMIT1(0xc3);		/* ret */
+				break;
+			case BPF_S_MISC_TAX: /* X = A */
+				seen |= SEEN_XREG;
+				EMIT2(0x89, 0xc3);	/* mov    %eax,%ebx */
+				break;
+			case BPF_S_MISC_TXA: /* A = X */
+				seen |= SEEN_XREG;
+				EMIT2(0x89, 0xd8);	/* mov    %ebx,%eax */
+				break;
+			case BPF_S_LD_IMM: /* A = K */
+				if (!K)
+					CLEAR_A();
+				else
+					EMIT1_off32(0xb8, K); /* mov $imm32,%eax */
+				break;
+			case BPF_S_LDX_IMM: /* X = K */
+				seen |= SEEN_XREG;
+				if (!K)
+					CLEAR_X();
+				else
+					EMIT1_off32(0xbb, K); /* mov $imm32,%ebx */
+				break;
+			case BPF_S_LD_MEM: /* A = mem[K] : mov off8(%rbp),%eax */
+				seen |= SEEN_MEM;
+				EMIT3(0x8b, 0x45, 0xf0 - K*4);
+				break;
+			case BPF_S_LDX_MEM: /* X = mem[K] : mov off8(%rbp),%ebx */
+				seen |= SEEN_XREG | SEEN_MEM;
+				EMIT3(0x8b, 0x5d, 0xf0 - K*4);
+				break;
+			case BPF_S_ST: /* mem[K] = A : mov %eax,off8(%rbp) */
+				seen |= SEEN_MEM;
+				EMIT3(0x89, 0x45, 0xf0 - K*4);
+				break;
+			case BPF_S_STX: /* mem[K] = X : mov %ebx,off8(%rbp) */
+				seen |= SEEN_XREG | SEEN_MEM;
+				EMIT3(0x89, 0x5d, 0xf0 - K*4);
+				break;
+			case BPF_S_LD_W_LEN: /*	A = skb->len; */
+				BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, len) != 4);
+				if (is_imm8(offsetof(struct sk_buff, len)))
+					/* mov    off8(%rdi),%eax */
+					EMIT3(0x8b, 0x47, offsetof(struct sk_buff, len));
+				else {
+					EMIT2(0x8b, 0x87);
+					EMIT(offsetof(struct sk_buff, len), 4);
+				}
+				break;
+			case BPF_S_LDX_W_LEN: /* X = skb->len; */
+				seen |= SEEN_XREG;
+				if (is_imm8(offsetof(struct sk_buff, len)))
+					/* mov off8(%rdi),%ebx */
+					EMIT3(0x8b, 0x5f, offsetof(struct sk_buff, len));
+				else {
+					EMIT2(0x8b, 0x9f);
+					EMIT(offsetof(struct sk_buff, len), 4);
+				}
+				break;
+			case BPF_S_ANC_PROTOCOL: /* A = ntohs(skb->protocol); */
+				BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, protocol) != 2);
+				if (is_imm8(offsetof(struct sk_buff, protocol))) {
+					/* movzwl off8(%rdi),%eax */
+					EMIT4(0x0f, 0xb7, 0x47, offsetof(struct sk_buff, protocol));
+				} else {
+					EMIT3(0x0f, 0xb7, 0x87); /* movzwl off32(%rdi),%eax */
+					EMIT(offsetof(struct sk_buff, protocol), 4);
+				}
+				EMIT2(0x86, 0xc4); /* ntohs() : xchg   %al,%ah */
+				break;
+			case BPF_S_ANC_IFINDEX:
+				if (is_imm8(offsetof(struct sk_buff, dev))) {
+					/* movq off8(%rdi),%rax */
+					EMIT4(0x48, 0x8b, 0x47, offsetof(struct sk_buff, dev));
+				} else {
+					EMIT3(0x48, 0x8b, 0x87); /* movq off32(%rdi),%rax */
+					EMIT(offsetof(struct sk_buff, dev), 4);
+				}
+				EMIT3(0x48, 0x85, 0xc0);	/* test %rax,%rax */
+				EMIT_COND_JMP(X86_JE, cleanup_addr - (addrs[i] - 6));
+				BUILD_BUG_ON(FIELD_SIZEOF(struct net_device, ifindex) != 4);
+				EMIT2(0x8b, 0x80);	/* mov off32(%rax),%eax */
+				EMIT(offsetof(struct net_device, ifindex), 4);
+				break;
+			case BPF_S_ANC_MARK:
+				BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, mark) != 4);
+				if (is_imm8(offsetof(struct sk_buff, mark))) {
+					/* mov off8(%rdi),%eax */
+					EMIT3(0x8b, 0x47, offsetof(struct sk_buff, mark));
+				} else {
+					EMIT2(0x8b, 0x87);
+					EMIT(offsetof(struct sk_buff, mark), 4);
+				}
+				break;
+			case BPF_S_ANC_RXHASH:
+				BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, rxhash) != 4);
+				if (is_imm8(offsetof(struct sk_buff, rxhash))) {
+					/* mov off8(%rdi),%eax */
+					EMIT3(0x8b, 0x47, offsetof(struct sk_buff, rxhash));
+				} else {
+					EMIT2(0x8b, 0x87);
+					EMIT(offsetof(struct sk_buff, rxhash), 4);
+				}
+				break;
+			case BPF_S_ANC_CPU:
+#ifdef CONFIG_SMP
+				EMIT4(0x65, 0x8b, 0x04, 0x25); /* mov %gs:off32,%eax */
+				EMIT((u32)&cpu_number, 4); /* A = smp_processor_id(); */
+#else
+				CLEAR_A();
+#endif
+				break;
+			case BPF_S_LD_W_ABS:
+				func = sk_load_word;
+common_load:			seen |= SEEN_DATAREF;
+				if ((int)K < 0)
+					goto out;
+				t_offset = func - (image + addrs[i]);
+				EMIT1_off32(0xbe, K); /* mov imm32,%esi */
+				EMIT1_off32(0xe8, t_offset); /* call */
+				break;
+			case BPF_S_LD_H_ABS:
+				func = sk_load_half;
+				goto common_load;
+			case BPF_S_LD_B_ABS:
+				func = sk_load_byte;
+				goto common_load;
+			case BPF_S_LDX_B_MSH:
+				if ((int)K < 0) {
+					if (pc_ret0 != -1) {
+						EMIT_JMP(addrs[pc_ret0] - addrs[i]);
+						break;
+					}
+					CLEAR_A();
+					EMIT_JMP(cleanup_addr - addrs[i]);
+					break;
+				}
+				seen |= SEEN_DATAREF | SEEN_XREG;
+				t_offset = sk_load_byte_msh - (image + addrs[i]);
+				EMIT1_off32(0xbe, K);	/* mov imm32,%esi */
+				EMIT1_off32(0xe8, t_offset); /* call sk_load_byte_msh */
+				break;
+			case BPF_S_LD_W_IND:
+				func = sk_load_word_ind;
+common_load_ind:		seen |= SEEN_DATAREF | SEEN_XREG;
+				t_offset = func - (image + addrs[i]);
+				EMIT1_off32(0xbe, K);	/* mov imm32,%esi   */
+				EMIT1_off32(0xe8, t_offset);	/* call sk_load_xxx_ind */
+				break;
+			case BPF_S_LD_H_IND:
+				func = sk_load_half_ind;
+				goto common_load_ind;
+			case BPF_S_LD_B_IND:
+				func = sk_load_byte_ind;
+				goto common_load_ind;
+			case BPF_S_JMP_JA:
+				t_offset = addrs[i + K] - addrs[i];
+				EMIT_JMP(t_offset);
+				break;
+			COND_SEL(BPF_S_JMP_JGT_K, X86_JA, X86_JBE);
+			COND_SEL(BPF_S_JMP_JGE_K, X86_JAE, X86_JB);
+			COND_SEL(BPF_S_JMP_JEQ_K, X86_JE, X86_JNE);
+			COND_SEL(BPF_S_JMP_JSET_K,X86_JNE, X86_JE);
+			COND_SEL(BPF_S_JMP_JGT_X, X86_JA, X86_JBE);
+			COND_SEL(BPF_S_JMP_JGE_X, X86_JAE, X86_JB);
+			COND_SEL(BPF_S_JMP_JEQ_X, X86_JE, X86_JNE);
+			COND_SEL(BPF_S_JMP_JSET_X,X86_JNE, X86_JE);
+
+cond_branch:			f_offset = addrs[i + filter[i].jf] - addrs[i];
+				t_offset = addrs[i + filter[i].jt] - addrs[i];
+
+				/* same targets, can avoid doing the test :) */
+				if (filter[i].jt == filter[i].jf) {
+					EMIT_JMP(t_offset);
+					break;
+				}
+
+				switch (filter[i].code) {
+				case BPF_S_JMP_JGT_X:
+				case BPF_S_JMP_JGE_X:
+				case BPF_S_JMP_JEQ_X:
+					seen |= SEEN_XREG;
+					EMIT2(0x39, 0xd8); /* cmp %ebx,%eax */
+					break;
+				case BPF_S_JMP_JSET_X:
+					seen |= SEEN_XREG;
+					EMIT2(0x85, 0xd8); /* test %ebx,%eax */
+					break;
+				case BPF_S_JMP_JEQ_K:
+					if (K == 0) {
+						EMIT2(0x85, 0xc0); /* test   %eax,%eax */
+						break;
+					}
+				case BPF_S_JMP_JGT_K:
+				case BPF_S_JMP_JGE_K:
+					if (K <= 127)
+						EMIT3(0x83, 0xf8, K); /* cmp imm8,%eax */
+					else
+						EMIT1_off32(0x3d, K); /* cmp imm32,%eax */
+					break;
+				case BPF_S_JMP_JSET_K:
+					if (K <= 0xFF)
+						EMIT2(0xa8, K); /* test imm8,%al */
+					else if (!(K & 0xFFFF00FF))
+						EMIT3(0xf6, 0xc4, K >> 8); /* test imm8,%ah */
+					else if (K <= 0xFFFF) {
+						EMIT2(0x66, 0xa9); /* test imm16,%ax */
+						EMIT(K, 2);
+					} else {
+						EMIT1_off32(0xa9, K); /* test imm32,%eax */
+					}
+					break;
+				}
+				if (filter[i].jt != 0) {
+					if (filter[i].jf)
+						t_offset += is_near(f_offset) ? 2 : 6;
+					EMIT_COND_JMP(t_op, t_offset);
+					if (filter[i].jf)
+						EMIT_JMP(f_offset);
+					break;
+				}
+				EMIT_COND_JMP(f_op, f_offset);
+				break;
+			default:
+				/* hmm, too complex filter, give up with jit compiler */
+				goto out;
+			}
+			ilen = prog - temp;
+			if (image) {
+				if (unlikely(proglen + ilen > oldproglen)) {
+					pr_err("bpb_jit_compile fatal error\n");
+					kfree(addrs);
+					module_free(NULL, image);
+					return;
+				}
+				memcpy(image + proglen, temp, ilen);
+			}
+			proglen += ilen;
+			addrs[i] = proglen;
+			prog = temp;
+		}
+		/* last bpf instruction is always a RET :
+		 * use it to give the cleanup instruction(s) addr
+		 */
+		cleanup_addr = proglen - 1; /* ret */
+		if (seen)
+			cleanup_addr -= 1; /* leaveq */
+		if (seen & SEEN_XREG)
+			cleanup_addr -= 4; /* mov  -8(%rbp),%rbx */
+
+		if (image) {
+			WARN_ON(proglen != oldproglen);
+			break;
+		}
+		if (proglen == oldproglen) {
+			image = module_alloc(max_t(unsigned int,
+						   proglen,
+						   sizeof(struct work_struct)));
+			if (!image)
+				goto out;
+		}
+		oldproglen = proglen;
+	}
+	if (bpf_jit_enable > 1)
+		pr_err("flen=%d proglen=%u pass=%d image=%p\n",
+		       flen, proglen, pass, image);
+
+	if (image) {
+		if (bpf_jit_enable > 1)
+			print_hex_dump(KERN_ERR, "JIT code: ", DUMP_PREFIX_ADDRESS,
+				       16, 1, image, proglen, false);
+
+		bpf_flush_icache(image, image + proglen);
+
+		fp->bpf_func = (void *)image;
+	}
+out:
+	kfree(addrs);
+	return;
+}
+
+static void jit_free_defer(struct work_struct *arg)
+{
+	module_free(NULL, arg);
+}
+
+/* run from softirq, we must use a work_struct to call
+ * module_free() from process context
+ */
+void bpf_jit_free(struct sk_filter *fp)
+{
+	if (fp->bpf_func != sk_run_filter) {
+		struct work_struct *work = (struct work_struct *)fp->bpf_func;
+
+		INIT_WORK(work, jit_free_defer);
+		schedule_work(work);
+	}
+}
+
diff --git a/net/core/filter.c b/net/core/filter.c
index 232b187..e63a794 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -39,65 +39,6 @@
 #include <linux/filter.h>
 #include <linux/reciprocal_div.h>
 
-enum {
-	BPF_S_RET_K = 1,
-	BPF_S_RET_A,
-	BPF_S_ALU_ADD_K,
-	BPF_S_ALU_ADD_X,
-	BPF_S_ALU_SUB_K,
-	BPF_S_ALU_SUB_X,
-	BPF_S_ALU_MUL_K,
-	BPF_S_ALU_MUL_X,
-	BPF_S_ALU_DIV_X,
-	BPF_S_ALU_AND_K,
-	BPF_S_ALU_AND_X,
-	BPF_S_ALU_OR_K,
-	BPF_S_ALU_OR_X,
-	BPF_S_ALU_LSH_K,
-	BPF_S_ALU_LSH_X,
-	BPF_S_ALU_RSH_K,
-	BPF_S_ALU_RSH_X,
-	BPF_S_ALU_NEG,
-	BPF_S_LD_W_ABS,
-	BPF_S_LD_H_ABS,
-	BPF_S_LD_B_ABS,
-	BPF_S_LD_W_LEN,
-	BPF_S_LD_W_IND,
-	BPF_S_LD_H_IND,
-	BPF_S_LD_B_IND,
-	BPF_S_LD_IMM,
-	BPF_S_LDX_W_LEN,
-	BPF_S_LDX_B_MSH,
-	BPF_S_LDX_IMM,
-	BPF_S_MISC_TAX,
-	BPF_S_MISC_TXA,
-	BPF_S_ALU_DIV_K,
-	BPF_S_LD_MEM,
-	BPF_S_LDX_MEM,
-	BPF_S_ST,
-	BPF_S_STX,
-	BPF_S_JMP_JA,
-	BPF_S_JMP_JEQ_K,
-	BPF_S_JMP_JEQ_X,
-	BPF_S_JMP_JGE_K,
-	BPF_S_JMP_JGE_X,
-	BPF_S_JMP_JGT_K,
-	BPF_S_JMP_JGT_X,
-	BPF_S_JMP_JSET_K,
-	BPF_S_JMP_JSET_X,
-	/* Ancillary data */
-	BPF_S_ANC_PROTOCOL,
-	BPF_S_ANC_PKTTYPE,
-	BPF_S_ANC_IFINDEX,
-	BPF_S_ANC_NLATTR,
-	BPF_S_ANC_NLATTR_NEST,
-	BPF_S_ANC_MARK,
-	BPF_S_ANC_QUEUE,
-	BPF_S_ANC_HATYPE,
-	BPF_S_ANC_RXHASH,
-	BPF_S_ANC_CPU,
-};
-
 /* No hurry in this branch */
 static void *__load_pointer(const struct sk_buff *skb, int k, unsigned int size)
 {
@@ -145,7 +86,7 @@ int sk_filter(struct sock *sk, struct sk_buff *skb)
 	rcu_read_lock();
 	filter = rcu_dereference(sk->sk_filter);
 	if (filter) {
-		unsigned int pkt_len = sk_run_filter(skb, filter->insns);
+		unsigned int pkt_len = SK_RUN_FILTER(filter, skb);
 
 		err = pkt_len ? pskb_trim(skb, pkt_len) : -EPERM;
 	}
@@ -638,6 +579,7 @@ void sk_filter_release_rcu(struct rcu_head *rcu)
 {
 	struct sk_filter *fp = container_of(rcu, struct sk_filter, rcu);
 
+	bpf_jit_free(fp);
 	kfree(fp);
 }
 EXPORT_SYMBOL(sk_filter_release_rcu);
@@ -672,6 +614,7 @@ int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk)
 
 	atomic_set(&fp->refcnt, 1);
 	fp->len = fprog->len;
+	fp->bpf_func = sk_run_filter;
 
 	err = sk_chk_filter(fp->insns, fp->len);
 	if (err) {
@@ -679,6 +622,8 @@ int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk)
 		return err;
 	}
 
+	bpf_jit_compile(fp);
+
 	old_fp = rcu_dereference_protected(sk->sk_filter,
 					   sock_owned_by_user(sk));
 	rcu_assign_pointer(sk->sk_filter, fp);
diff --git a/net/core/sysctl_net_core.c b/net/core/sysctl_net_core.c
index 385b609..a829e3f 100644
--- a/net/core/sysctl_net_core.c
+++ b/net/core/sysctl_net_core.c
@@ -122,6 +122,15 @@ static struct ctl_table net_core_table[] = {
 		.mode		= 0644,
 		.proc_handler	= proc_dointvec
 	},
+#ifdef CONFIG_BPF_JIT
+	{
+		.procname	= "bpf_jit_enable",
+		.data		= &bpf_jit_enable,
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= proc_dointvec
+	},
+#endif
 	{
 		.procname	= "netdev_tstamp_prequeue",
 		.data		= &netdev_tstamp_prequeue,
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index b5362e9..549527b 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -538,7 +538,7 @@ static inline unsigned int run_filter(const struct sk_buff *skb,
 	rcu_read_lock();
 	filter = rcu_dereference(sk->sk_filter);
 	if (filter != NULL)
-		res = sk_run_filter(skb, filter->insns);
+		res = SK_RUN_FILTER(filter, skb);
 	rcu_read_unlock();
 
 	return res;



^ permalink raw reply related

* Re: tcp: disallow bind() to reuse addr/port regression in 2.6.38
From: Eric Dumazet @ 2011-04-02 21:18 UTC (permalink / raw)
  To: Cyril Bonté
  Cc: Willy Tarreau, netdev, Daniel Baluta, Gaspar Chilingarov,
	Charles Duffy
In-Reply-To: <201104022300.33826.cyril.bonte@free.fr>

Le samedi 02 avril 2011 à 23:00 +0200, Cyril Bonté a écrit :
> Le samedi 2 avril 2011 22:37:27, Willy Tarreau a écrit :
> > On Sat, Apr 02, 2011 at 09:44:55PM +0200, Eric Dumazet wrote:
> > > Is Cyril program running OK on FreeBsd ?
> > 
> > I don't think so, as from memories, both FreeBSD and OpenBSD fail
> > on isten() after a shutdown(SHUT_RD), hence the strange looking
> > shut+listen+shut sequence you noticed (in order to detect whether
> > listen will work again or not).
> 
> Well, I've just tested it on FreeBSD 8.1.
> As Willy said, the listen() fails but what I observe is that as soon as 
> shutdown(SHUT_RW) is called, it is possible to bind a new socket on the same 
> port. A modified version of the program to sleep after the shutdown shows that 
> launching 3 processes in parallel (delayed to let them bind then shutdown) 
> will give 3 connections in CLOSE state.
> 

Yes, but as soon as shutdown(SHUT_RDWR) is called on socket fd1, is this
same socket reusable ?

Maybe the only possible action is a close(fd1), and socket not any more
bound.

Man page on shutdown() is a bit silent, and makes sense for non
listening sockets.




^ permalink raw reply

* Re: tcp: disallow bind() to reuse addr/port regression in 2.6.38
From: Cyril Bonté @ 2011-04-02 21:00 UTC (permalink / raw)
  To: Eric Dumazet
  Cc: Willy Tarreau, netdev, Daniel Baluta, Gaspar Chilingarov,
	Charles Duffy
In-Reply-To: <20110402203727.GI5552@1wt.eu>

Le samedi 2 avril 2011 22:37:27, Willy Tarreau a écrit :
> On Sat, Apr 02, 2011 at 09:44:55PM +0200, Eric Dumazet wrote:
> > Is Cyril program running OK on FreeBsd ?
> 
> I don't think so, as from memories, both FreeBSD and OpenBSD fail
> on isten() after a shutdown(SHUT_RD), hence the strange looking
> shut+listen+shut sequence you noticed (in order to detect whether
> listen will work again or not).

Well, I've just tested it on FreeBSD 8.1.
As Willy said, the listen() fails but what I observe is that as soon as 
shutdown(SHUT_RW) is called, it is possible to bind a new socket on the same 
port. A modified version of the program to sleep after the shutdown shows that 
launching 3 processes in parallel (delayed to let them bind then shutdown) 
will give 3 connections in CLOSE state.

-- 
Cyril Bonté

^ permalink raw reply

* Re: tcp: disallow bind() to reuse addr/port regression in 2.6.38
From: Willy Tarreau @ 2011-04-02 20:37 UTC (permalink / raw)
  To: Eric Dumazet
  Cc: Cyril Bonté, netdev, Daniel Baluta, Gaspar Chilingarov,
	Charles Duffy
In-Reply-To: <1301773495.2837.26.camel@edumazet-laptop>

On Sat, Apr 02, 2011 at 09:44:55PM +0200, Eric Dumazet wrote:
> Le samedi 02 avril 2011 à 21:15 +0200, Willy Tarreau a écrit :
> > Hi Eric,
> > 
> > On Sat, Apr 02, 2011 at 08:46:11PM +0200, Cyril Bonté wrote:
> > > Le samedi 2 avril 2011 20:10:48, Eric Dumazet a écrit :
> > > > Le samedi 02 avril 2011 à 20:01 +0200, Cyril Bonté a écrit :
> > > > (...)
> > > > > > 		if (shutdown(listenfd, SHUT_WR) == 0 &&
> > > > > 		
> > > > > 		    listen(listenfd, 1024) == 0 &&
> > > > > 		    shutdown(listenfd, SHUT_RD) == 0) {
> > > > > 			
> > > > > 			printf("shutdown OK\n");
> > > > > 		
> > > > > 		}
> > > > > 	
> > > > > 	}
> > > > > 	exit(0);
> > > > > 
> > > > > }
> > > > 
> > > > Wow, not clear what this is doing....
> > > > 
> > > > for sure the listen() call is not needed ?
> > > > 
> > > > And the shutdown(listenfd, SHUT_WR) is clearly useless too.
> > > 
> > > Well, I'm not the best one to explain that part but from what i read in the 
> > > comments of this part of code, both listen and SHUT_WR are used to detect 
> > > errors on various OS (OpenBSD, Solaris, ...).
> > > 
> > > > I feel you only needed the shutdown(listenfd, SHUT_RD) call.
> > > > 
> > > > Why haproxy needs to setup a second listening socket on same port ?
> > > 
> > > I simplified the test case, which is far from what haproxy do (just forgot to 
> > > explain the real behaviour).
> > > To reload the configuration, a new haproxy process is launched, sending a 
> > > signal to the previous one and asking it to free the ports for a while (the 
> > > shutdown part in the test). The new process then tries to bind the ports, 
> > > which worked until 2.6.38 (if an error occurs, a new signal is sent to the 
> > > previous process to listen to its sockets again).
> > 
> > Indeed, here's what normally happens when haproxy reloads.
> > 
> > New process is loaded with a new config. Once the config correctly parses,
> > it sends a signal to the previous process asking it to temporarily release
> > its listening ports so that the new one can bind, hence the shutdown(SHUT_RD)
> > performed in the old process.
> > 
> > Then the new process can grab the ports and listen to them. Once that's OK,
> > it sends another signal to the old process telling it it can go away. But
> > if the new process failed to completely start (eg: could not grab one port),
> > then it sends a third signal to the old process asking it to rebind the port
> > and serve them again, and the new one dies with an error.
> > 
> > That way, the service is never interrupted even if the new config fails
> > late, because the old process has the ability to rebind to the port it
> > temporarily released.
> > 
> > Now with 2.6.38, as Cyril diagnosed it, the new bind() fails when the
> > old process has just performed its shutdown(SHUT_RD), preventing the
> > new process from binding to the ports until the old process has
> > definitely closed them.
> > 
> > The behaviour is very useful, because the old process might have lost
> > its privileges, it will not have to rebind to the socket, just listen
> > on it again since it is never closed.
> > 
> > This is quite embarrassing, because this code used to work for the
> > last 10 years, at least since kernel 2.2, and maybe even 2.0, I don't
> > remember.
> > 
> > I'm not sure what the original intent of the patch was, not what was
> > the reported issue, but maybe we could find a way to both fix the
> > reported issue (if any) and restore the old behaviour in order not
> > to break existing programs.
> > 
> > Best regards,
> > Willy
> > 
> 
> I wish it was that simple....
> 
> http://www.spinics.net/lists/netdev/msg151551.html

What a mess :-(

I've been used to actively bind() to source ip:ports when dealing with that
number of connections, because I've long noticed that the port auto-selection
did not work once all source ports were used on at least one IP address.
Managing a source port list in user space is no big deal when you have to
support hundreds of thousands of connections, as there are harder issues
to deal with :-/

> Is Cyril program running OK on FreeBsd ?

I don't think so, as from memories, both FreeBSD and OpenBSD fail
on isten() after a shutdown(SHUT_RD), hence the strange looking
shut+listen+shut sequence you noticed (in order to detect whether
listen will work again or not).

I'm just wondering the relation between the SHUT_RD listen sockets
that we catch by accident and the issue that was the initial goal
of the patch regarding outgoing sockets. All this is not very clear
to me yet.

Regards,
Willy


^ permalink raw reply

* Re: tcp: disallow bind() to reuse addr/port regression in 2.6.38
From: Eric Dumazet @ 2011-04-02 19:44 UTC (permalink / raw)
  To: Willy Tarreau
  Cc: Cyril Bonté, netdev, Daniel Baluta, Gaspar Chilingarov,
	Charles Duffy
In-Reply-To: <20110402191516.GG5552@1wt.eu>

Le samedi 02 avril 2011 à 21:15 +0200, Willy Tarreau a écrit :
> Hi Eric,
> 
> On Sat, Apr 02, 2011 at 08:46:11PM +0200, Cyril Bonté wrote:
> > Le samedi 2 avril 2011 20:10:48, Eric Dumazet a écrit :
> > > Le samedi 02 avril 2011 à 20:01 +0200, Cyril Bonté a écrit :
> > > (...)
> > > > > 		if (shutdown(listenfd, SHUT_WR) == 0 &&
> > > > 		
> > > > 		    listen(listenfd, 1024) == 0 &&
> > > > 		    shutdown(listenfd, SHUT_RD) == 0) {
> > > > 			
> > > > 			printf("shutdown OK\n");
> > > > 		
> > > > 		}
> > > > 	
> > > > 	}
> > > > 	exit(0);
> > > > 
> > > > }
> > > 
> > > Wow, not clear what this is doing....
> > > 
> > > for sure the listen() call is not needed ?
> > > 
> > > And the shutdown(listenfd, SHUT_WR) is clearly useless too.
> > 
> > Well, I'm not the best one to explain that part but from what i read in the 
> > comments of this part of code, both listen and SHUT_WR are used to detect 
> > errors on various OS (OpenBSD, Solaris, ...).
> > 
> > > I feel you only needed the shutdown(listenfd, SHUT_RD) call.
> > > 
> > > Why haproxy needs to setup a second listening socket on same port ?
> > 
> > I simplified the test case, which is far from what haproxy do (just forgot to 
> > explain the real behaviour).
> > To reload the configuration, a new haproxy process is launched, sending a 
> > signal to the previous one and asking it to free the ports for a while (the 
> > shutdown part in the test). The new process then tries to bind the ports, 
> > which worked until 2.6.38 (if an error occurs, a new signal is sent to the 
> > previous process to listen to its sockets again).
> 
> Indeed, here's what normally happens when haproxy reloads.
> 
> New process is loaded with a new config. Once the config correctly parses,
> it sends a signal to the previous process asking it to temporarily release
> its listening ports so that the new one can bind, hence the shutdown(SHUT_RD)
> performed in the old process.
> 
> Then the new process can grab the ports and listen to them. Once that's OK,
> it sends another signal to the old process telling it it can go away. But
> if the new process failed to completely start (eg: could not grab one port),
> then it sends a third signal to the old process asking it to rebind the port
> and serve them again, and the new one dies with an error.
> 
> That way, the service is never interrupted even if the new config fails
> late, because the old process has the ability to rebind to the port it
> temporarily released.
> 
> Now with 2.6.38, as Cyril diagnosed it, the new bind() fails when the
> old process has just performed its shutdown(SHUT_RD), preventing the
> new process from binding to the ports until the old process has
> definitely closed them.
> 
> The behaviour is very useful, because the old process might have lost
> its privileges, it will not have to rebind to the socket, just listen
> on it again since it is never closed.
> 
> This is quite embarrassing, because this code used to work for the
> last 10 years, at least since kernel 2.2, and maybe even 2.0, I don't
> remember.
> 
> I'm not sure what the original intent of the patch was, not what was
> the reported issue, but maybe we could find a way to both fix the
> reported issue (if any) and restore the old behaviour in order not
> to break existing programs.
> 
> Best regards,
> Willy
> 

I wish it was that simple....

http://www.spinics.net/lists/netdev/msg151551.html

Is Cyril program running OK on FreeBsd ?




^ permalink raw reply

* Re: tcp: disallow bind() to reuse addr/port regression in 2.6.38
From: Willy Tarreau @ 2011-04-02 19:15 UTC (permalink / raw)
  To: Cyril Bonté
  Cc: Eric Dumazet, netdev, Daniel Baluta, Gaspar Chilingarov,
	Charles Duffy
In-Reply-To: <201104022046.11701.cyril.bonte@free.fr>

Hi Eric,

On Sat, Apr 02, 2011 at 08:46:11PM +0200, Cyril Bonté wrote:
> Le samedi 2 avril 2011 20:10:48, Eric Dumazet a écrit :
> > Le samedi 02 avril 2011 à 20:01 +0200, Cyril Bonté a écrit :
> > (...)
> > > > 		if (shutdown(listenfd, SHUT_WR) == 0 &&
> > > 		
> > > 		    listen(listenfd, 1024) == 0 &&
> > > 		    shutdown(listenfd, SHUT_RD) == 0) {
> > > 			
> > > 			printf("shutdown OK\n");
> > > 		
> > > 		}
> > > 	
> > > 	}
> > > 	exit(0);
> > > 
> > > }
> > 
> > Wow, not clear what this is doing....
> > 
> > for sure the listen() call is not needed ?
> > 
> > And the shutdown(listenfd, SHUT_WR) is clearly useless too.
> 
> Well, I'm not the best one to explain that part but from what i read in the 
> comments of this part of code, both listen and SHUT_WR are used to detect 
> errors on various OS (OpenBSD, Solaris, ...).
> 
> > I feel you only needed the shutdown(listenfd, SHUT_RD) call.
> > 
> > Why haproxy needs to setup a second listening socket on same port ?
> 
> I simplified the test case, which is far from what haproxy do (just forgot to 
> explain the real behaviour).
> To reload the configuration, a new haproxy process is launched, sending a 
> signal to the previous one and asking it to free the ports for a while (the 
> shutdown part in the test). The new process then tries to bind the ports, 
> which worked until 2.6.38 (if an error occurs, a new signal is sent to the 
> previous process to listen to its sockets again).

Indeed, here's what normally happens when haproxy reloads.

New process is loaded with a new config. Once the config correctly parses,
it sends a signal to the previous process asking it to temporarily release
its listening ports so that the new one can bind, hence the shutdown(SHUT_RD)
performed in the old process.

Then the new process can grab the ports and listen to them. Once that's OK,
it sends another signal to the old process telling it it can go away. But
if the new process failed to completely start (eg: could not grab one port),
then it sends a third signal to the old process asking it to rebind the port
and serve them again, and the new one dies with an error.

That way, the service is never interrupted even if the new config fails
late, because the old process has the ability to rebind to the port it
temporarily released.

Now with 2.6.38, as Cyril diagnosed it, the new bind() fails when the
old process has just performed its shutdown(SHUT_RD), preventing the
new process from binding to the ports until the old process has
definitely closed them.

The behaviour is very useful, because the old process might have lost
its privileges, it will not have to rebind to the socket, just listen
on it again since it is never closed.

This is quite embarrassing, because this code used to work for the
last 10 years, at least since kernel 2.2, and maybe even 2.0, I don't
remember.

I'm not sure what the original intent of the patch was, not what was
the reported issue, but maybe we could find a way to both fix the
reported issue (if any) and restore the old behaviour in order not
to break existing programs.

Best regards,
Willy


^ permalink raw reply

* Re: tcp: disallow bind() to reuse addr/port regression in 2.6.38
From: Cyril Bonté @ 2011-04-02 18:46 UTC (permalink / raw)
  To: Eric Dumazet
  Cc: netdev, Daniel Baluta, Gaspar Chilingarov, Charles Duffy,
	Willy Tarreau
In-Reply-To: <1301767848.2837.14.camel@edumazet-laptop>

Le samedi 2 avril 2011 20:10:48, Eric Dumazet a écrit :
> Le samedi 02 avril 2011 à 20:01 +0200, Cyril Bonté a écrit :
> (...)
> > > 		if (shutdown(listenfd, SHUT_WR) == 0 &&
> > 		
> > 		    listen(listenfd, 1024) == 0 &&
> > 		    shutdown(listenfd, SHUT_RD) == 0) {
> > 			
> > 			printf("shutdown OK\n");
> > 		
> > 		}
> > 	
> > 	}
> > 	exit(0);
> > 
> > }
> 
> Wow, not clear what this is doing....
> 
> for sure the listen() call is not needed ?
> 
> And the shutdown(listenfd, SHUT_WR) is clearly useless too.

Well, I'm not the best one to explain that part but from what i read in the 
comments of this part of code, both listen and SHUT_WR are used to detect 
errors on various OS (OpenBSD, Solaris, ...).

> I feel you only needed the shutdown(listenfd, SHUT_RD) call.
> 
> Why haproxy needs to setup a second listening socket on same port ?

I simplified the test case, which is far from what haproxy do (just forgot to 
explain the real behaviour).
To reload the configuration, a new haproxy process is launched, sending a 
signal to the previous one and asking it to free the ports for a while (the 
shutdown part in the test). The new process then tries to bind the ports, 
which worked until 2.6.38 (if an error occurs, a new signal is sent to the 
previous process to listen to its sockets again).

-- 
Cyril Bonté

^ permalink raw reply

* Re: [patch net-next-2.6] net: vlan: make non-hw-accel rx path similar to hw-accel
From: Jiri Pirko @ 2011-04-02 18:27 UTC (permalink / raw)
  To: Stephen Hemminger
  Cc: netdev, davem, kaber, fubar, eric.dumazet, nicolas.2p.debian,
	andy, xiaosuo, jesse
In-Reply-To: <20110402085524.6692131a@nehalam>

Sat, Apr 02, 2011 at 05:55:24PM CEST, shemminger@linux-foundation.org wrote:
>On Sat,  2 Apr 2011 12:26:06 +0200
>Jiri Pirko <jpirko@redhat.com> wrote:
>
>> Now there are 2 paths for rx vlan frames. When rx-vlan-hw-accel is
>> enabled, skb is untagged by NIC, vlan_tci is set and the skb gets into
>> vlan code in __netif_receive_skb - vlan_hwaccel_do_receive.
>> 
>> For non-rx-vlan-hw-accel however, tagged skb goes thru whole
>> __netif_receive_skb, it's untagged in ptype_base hander and reinjected
>> 
>> This incosistency is fixed by this patch. Vlan untagging happens early in
>> __netif_receive_skb so the rest of code (ptype_all handlers, rx_handlers)
>> see the skb like it was untagged by hw.
>> 
>> Signed-off-by: Jiri Pirko <jpirko@redhat.com>
>> ---
>>  include/linux/if_vlan.h |   10 ++-
>>  net/8021q/vlan.c        |    8 --
>>  net/8021q/vlan.h        |    2 -
>>  net/8021q/vlan_core.c   |   86 +++++++++++++++++++++++-
>>  net/8021q/vlan_dev.c    |  173 -----------------------------------------------
>>  net/core/dev.c          |    8 ++-
>>  6 files changed, 100 insertions(+), 187 deletions(-)
>> 
>> diff --git a/include/linux/if_vlan.h b/include/linux/if_vlan.h
>> index 635e1fa..998b299 100644
>> --- a/include/linux/if_vlan.h
>> +++ b/include/linux/if_vlan.h
>> @@ -132,7 +132,8 @@ extern u16 vlan_dev_vlan_id(const struct net_device *dev);
>>  
>>  extern int __vlan_hwaccel_rx(struct sk_buff *skb, struct vlan_group *grp,
>>  			     u16 vlan_tci, int polling);
>> -extern bool vlan_hwaccel_do_receive(struct sk_buff **skb);
>> +extern bool vlan_do_receive(struct sk_buff **skb);
>> +extern struct sk_buff *vlan_untag(struct sk_buff *skb);
>>  extern gro_result_t
>>  vlan_gro_receive(struct napi_struct *napi, struct vlan_group *grp,
>>  		 unsigned int vlan_tci, struct sk_buff *skb);
>> @@ -166,13 +167,18 @@ static inline int __vlan_hwaccel_rx(struct sk_buff *skb, struct vlan_group *grp,
>>  	return NET_XMIT_SUCCESS;
>>  }
>>  
>> -static inline bool vlan_hwaccel_do_receive(struct sk_buff **skb)
>> +static inline bool vlan_do_receive(struct sk_buff **skb)
>>  {
>>  	if ((*skb)->vlan_tci & VLAN_VID_MASK)
>>  		(*skb)->pkt_type = PACKET_OTHERHOST;
>>  	return false;
>>  }
>
>Why the added unnecessary indirection

I do not understand what do you mean.

>
>
>> +inline struct sk_buff *vlan_untag(struct sk_buff *skb)
>> +{
>> +	return skb;
>> +}
>
>This adds no value.

Nod, it should not. That's why this is in else of:
#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)

>
>>  static inline gro_result_t
>>  vlan_gro_receive(struct napi_struct *napi, struct vlan_group *grp,
>>  		 unsigned int vlan_tci, struct sk_buff *skb)
>> diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c
>> index 7850412..59f0a9d 100644
>> --- a/net/8021q/vlan.c
>> +++ b/net/8021q/vlan.c
>> @@ -49,11 +49,6 @@ const char vlan_version[] = DRV_VERSION;
>>  static const char vlan_copyright[] = "Ben Greear <greearb@candelatech.com>";
>>  static const char vlan_buggyright[] = "David S. Miller <davem@redhat.com>";
>>  
>> -static struct packet_type vlan_packet_type __read_mostly = {
>> -	.type = cpu_to_be16(ETH_P_8021Q),
>> -	.func = vlan_skb_recv, /* VLAN receive method */
>> -};
>> -
>>  /* End of global variables definitions. */
>>  
>>  static void vlan_group_free(struct vlan_group *grp)
>> @@ -688,7 +683,6 @@ static int __init vlan_proto_init(void)
>>  	if (err < 0)
>>  		goto err4;
>>  
>> -	dev_add_pack(&vlan_packet_type);
>>  	vlan_ioctl_set(vlan_ioctl_handler);
>>  	return 0;
>>  
>> @@ -709,8 +703,6 @@ static void __exit vlan_cleanup_module(void)
>>  
>>  	unregister_netdevice_notifier(&vlan_notifier_block);
>>  
>> -	dev_remove_pack(&vlan_packet_type);
>> -
>>  	unregister_pernet_subsys(&vlan_net_ops);
>>  	rcu_barrier(); /* Wait for completion of call_rcu()'s */
>>  
>> diff --git a/net/8021q/vlan.h b/net/8021q/vlan.h
>> index 5687c9b..c3408de 100644
>> --- a/net/8021q/vlan.h
>> +++ b/net/8021q/vlan.h
>> @@ -75,8 +75,6 @@ static inline struct vlan_dev_info *vlan_dev_info(const struct net_device *dev)
>>  }
>>  
>>  /* found in vlan_dev.c */
>> -int vlan_skb_recv(struct sk_buff *skb, struct net_device *dev,
>> -		  struct packet_type *ptype, struct net_device *orig_dev);
>>  void vlan_dev_set_ingress_priority(const struct net_device *dev,
>>  				   u32 skb_prio, u16 vlan_prio);
>>  int vlan_dev_set_egress_priority(const struct net_device *dev,
>> diff --git a/net/8021q/vlan_core.c b/net/8021q/vlan_core.c
>> index ce8e3ab..bc83ecc 100644
>> --- a/net/8021q/vlan_core.c
>> +++ b/net/8021q/vlan_core.c
>> @@ -4,7 +4,7 @@
>>  #include <linux/netpoll.h>
>>  #include "vlan.h"
>>  
>> -bool vlan_hwaccel_do_receive(struct sk_buff **skbp)
>> +bool vlan_do_receive(struct sk_buff **skbp)
>>  {
>>  	struct sk_buff *skb = *skbp;
>>  	u16 vlan_id = skb->vlan_tci & VLAN_VID_MASK;
>> @@ -88,3 +88,87 @@ gro_result_t vlan_gro_frags(struct napi_struct *napi, struct vlan_group *grp,
>>  	return napi_gro_frags(napi);
>>  }
>>  EXPORT_SYMBOL(vlan_gro_frags);
>> +
>> +static inline struct sk_buff *vlan_check_reorder_header(struct sk_buff *skb)
>> +{
>> +	if (vlan_dev_info(skb->dev)->flags & VLAN_FLAG_REORDER_HDR) {
>> +		if (skb_cow(skb, skb_headroom(skb)) < 0)
>> +			skb = NULL;
>> +		if (skb) {
>> +			/* Lifted from Gleb's VLAN code... */
>> +			memmove(skb->data - ETH_HLEN,
>> +				skb->data - VLAN_ETH_HLEN, 12);
>> +			skb->mac_header += VLAN_HLEN;
>> +		}
>> +	}
>> +	return skb;
>> +}
>
>Do not mark code as 'static inline' let compiler decide.

I just moved this function from vlan_dev.c as it is. No problem to
change this.

>
>> +static inline void vlan_set_encap_proto(struct sk_buff *skb,
>> +					struct vlan_hdr *vhdr)
>> +{
>> +	__be16 proto;
>> +	unsigned char *rawp;
>> +
>> +	/*
>> +	 * Was a VLAN packet, grab the encapsulated protocol, which the layer
>> +	 * three protocols care about.
>> +	 */
>> +
>> +	proto = vhdr->h_vlan_encapsulated_proto;
>> +	if (ntohs(proto) >= 1536) {
>> +		skb->protocol = proto;
>> +		return;
>> +	}
>> +
>> +	rawp = skb->data;
>> +	if (*(unsigned short *) rawp == 0xFFFF)
>> +		/*
>> +		 * This is a magic hack to spot IPX packets. Older Novell
>> +		 * breaks the protocol design and runs IPX over 802.3 without
>> +		 * an 802.2 LLC layer. We look for FFFF which isn't a used
>> +		 * 802.2 SSAP/DSAP. This won't work for fault tolerant netware
>> +		 * but does for the rest.
>> +		 */
>> +		skb->protocol = htons(ETH_P_802_3);
>> +	else
>> +		/*
>> +		 * Real 802.2 LLC
>> +		 */
>> +		skb->protocol = htons(ETH_P_802_2);
>> +}
>
>What about doublely tagged packets?

No problem. Once they are untagged and reinjected they are untagged
again and reinjected again:

-> __netif_reveive_skb
vlan_untag
vlan_do_receive
-> __netif_receive_skb
vlan_untag
vlan_do_receive


>
>> +struct sk_buff *vlan_untag(struct sk_buff *skb)
>> +{
>> +	struct vlan_hdr *vhdr;
>> +	u16 vlan_tci;
>> +
>> +	if (unlikely(vlan_tx_tag_present(skb))) {
>> +		/* vlan_tci is already set-up so leave this for another time */
>> +		return skb;
>> +	}
>> +
>> +	skb = skb_share_check(skb, GFP_ATOMIC);
>> +	if (unlikely(!skb))
>> +		goto err_free;
>> +
>> +	if (unlikely(!pskb_may_pull(skb, VLAN_HLEN)))
>> +		goto err_free;
>> +
>> +	vhdr = (struct vlan_hdr *) skb->data;
>> +	vlan_tci = ntohs(vhdr->h_vlan_TCI);
>> +	__vlan_hwaccel_put_tag(skb, vlan_tci);
>> +
>> +	skb_pull_rcsum(skb, VLAN_HLEN);
>> +	vlan_set_encap_proto(skb, vhdr);
>> +
>> +	skb = vlan_check_reorder_header(skb);
>> +	if (unlikely(!skb))
>> +		goto err_free;
>> +
>> +	return skb;
>> +
>> +err_free:
>> +	kfree_skb(skb);
>> +	return NULL;
>> +}
>> diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c
>> index e34ea9e..b4f061f 100644
>> --- a/net/8021q/vlan_dev.c
>> +++ b/net/8021q/vlan_dev.c
>> @@ -65,179 +65,6 @@ static int vlan_dev_rebuild_header(struct sk_buff *skb)
>>  	return 0;
>>  }
>>  
>> -static inline struct sk_buff *vlan_check_reorder_header(struct sk_buff *skb)
>> -{
>> -	if (vlan_dev_info(skb->dev)->flags & VLAN_FLAG_REORDER_HDR) {
>> -		if (skb_cow(skb, skb_headroom(skb)) < 0)
>> -			skb = NULL;
>> -		if (skb) {
>> -			/* Lifted from Gleb's VLAN code... */
>> -			memmove(skb->data - ETH_HLEN,
>> -				skb->data - VLAN_ETH_HLEN, 12);
>> -			skb->mac_header += VLAN_HLEN;
>> -		}
>> -	}
>> -
>> -	return skb;
>> -}
>> -
>> -static inline void vlan_set_encap_proto(struct sk_buff *skb,
>> -		struct vlan_hdr *vhdr)
>> -{
>> -	__be16 proto;
>> -	unsigned char *rawp;
>> -
>> -	/*
>> -	 * Was a VLAN packet, grab the encapsulated protocol, which the layer
>> -	 * three protocols care about.
>> -	 */
>> -
>> -	proto = vhdr->h_vlan_encapsulated_proto;
>> -	if (ntohs(proto) >= 1536) {
>> -		skb->protocol = proto;
>> -		return;
>> -	}
>> -
>> -	rawp = skb->data;
>> -	if (*(unsigned short *)rawp == 0xFFFF)
>> -		/*
>> -		 * This is a magic hack to spot IPX packets. Older Novell
>> -		 * breaks the protocol design and runs IPX over 802.3 without
>> -		 * an 802.2 LLC layer. We look for FFFF which isn't a used
>> -		 * 802.2 SSAP/DSAP. This won't work for fault tolerant netware
>> -		 * but does for the rest.
>> -		 */
>> -		skb->protocol = htons(ETH_P_802_3);
>> -	else
>> -		/*
>> -		 * Real 802.2 LLC
>> -		 */
>> -		skb->protocol = htons(ETH_P_802_2);
>> -}
>> -
>> -/*
>> - *	Determine the packet's protocol ID. The rule here is that we
>> - *	assume 802.3 if the type field is short enough to be a length.
>> - *	This is normal practice and works for any 'now in use' protocol.
>> - *
>> - *  Also, at this point we assume that we ARE dealing exclusively with
>> - *  VLAN packets, or packets that should be made into VLAN packets based
>> - *  on a default VLAN ID.
>> - *
>> - *  NOTE:  Should be similar to ethernet/eth.c.
>> - *
>> - *  SANITY NOTE:  This method is called when a packet is moving up the stack
>> - *                towards userland.  To get here, it would have already passed
>> - *                through the ethernet/eth.c eth_type_trans() method.
>> - *  SANITY NOTE 2: We are referencing to the VLAN_HDR frields, which MAY be
>> - *                 stored UNALIGNED in the memory.  RISC systems don't like
>> - *                 such cases very much...
>> - *  SANITY NOTE 2a: According to Dave Miller & Alexey, it will always be
>> - *  		    aligned, so there doesn't need to be any of the unaligned
>> - *  		    stuff.  It has been commented out now...  --Ben
>> - *
>> - */
>> -int vlan_skb_recv(struct sk_buff *skb, struct net_device *dev,
>> -		  struct packet_type *ptype, struct net_device *orig_dev)
>> -{
>> -	struct vlan_hdr *vhdr;
>> -	struct vlan_pcpu_stats *rx_stats;
>> -	struct net_device *vlan_dev;
>> -	u16 vlan_id;
>> -	u16 vlan_tci;
>> -
>> -	skb = skb_share_check(skb, GFP_ATOMIC);
>> -	if (skb == NULL)
>> -		goto err_free;
>> -
>> -	if (unlikely(!pskb_may_pull(skb, VLAN_HLEN)))
>> -		goto err_free;
>> -
>> -	vhdr = (struct vlan_hdr *)skb->data;
>> -	vlan_tci = ntohs(vhdr->h_vlan_TCI);
>> -	vlan_id = vlan_tci & VLAN_VID_MASK;
>> -
>> -	rcu_read_lock();
>> -	vlan_dev = vlan_find_dev(dev, vlan_id);
>> -
>> -	/* If the VLAN device is defined, we use it.
>> -	 * If not, and the VID is 0, it is a 802.1p packet (not
>> -	 * really a VLAN), so we will just netif_rx it later to the
>> -	 * original interface, but with the skb->proto set to the
>> -	 * wrapped proto: we do nothing here.
>> -	 */
>> -
>> -	if (!vlan_dev) {
>> -		if (vlan_id) {
>> -			pr_debug("%s: ERROR: No net_device for VID: %u on dev: %s\n",
>> -				 __func__, vlan_id, dev->name);
>> -			goto err_unlock;
>> -		}
>> -		rx_stats = NULL;
>> -	} else {
>> -		skb->dev = vlan_dev;
>> -
>> -		rx_stats = this_cpu_ptr(vlan_dev_info(skb->dev)->vlan_pcpu_stats);
>> -
>> -		u64_stats_update_begin(&rx_stats->syncp);
>> -		rx_stats->rx_packets++;
>> -		rx_stats->rx_bytes += skb->len;
>> -
>> -		skb->priority = vlan_get_ingress_priority(skb->dev, vlan_tci);
>> -
>> -		pr_debug("%s: priority: %u for TCI: %hu\n",
>> -			 __func__, skb->priority, vlan_tci);
>> -
>> -		switch (skb->pkt_type) {
>> -		case PACKET_BROADCAST:
>> -			/* Yeah, stats collect these together.. */
>> -			/* stats->broadcast ++; // no such counter :-( */
>> -			break;
>> -
>> -		case PACKET_MULTICAST:
>> -			rx_stats->rx_multicast++;
>> -			break;
>> -
>> -		case PACKET_OTHERHOST:
>> -			/* Our lower layer thinks this is not local, let's make
>> -			 * sure.
>> -			 * This allows the VLAN to have a different MAC than the
>> -			 * underlying device, and still route correctly.
>> -			 */
>> -			if (!compare_ether_addr(eth_hdr(skb)->h_dest,
>> -						skb->dev->dev_addr))
>> -				skb->pkt_type = PACKET_HOST;
>> -			break;
>> -		default:
>> -			break;
>> -		}
>> -		u64_stats_update_end(&rx_stats->syncp);
>> -	}
>> -
>> -	skb_pull_rcsum(skb, VLAN_HLEN);
>> -	vlan_set_encap_proto(skb, vhdr);
>> -
>> -	if (vlan_dev) {
>> -		skb = vlan_check_reorder_header(skb);
>> -		if (!skb) {
>> -			rx_stats->rx_errors++;
>> -			goto err_unlock;
>> -		}
>> -	}
>> -
>> -	netif_rx(skb);
>> -
>> -	rcu_read_unlock();
>> -	return NET_RX_SUCCESS;
>> -
>> -err_unlock:
>> -	rcu_read_unlock();
>> -err_free:
>> -	atomic_long_inc(&dev->rx_dropped);
>> -	kfree_skb(skb);
>> -	return NET_RX_DROP;
>> -}
>> -
>>  static inline u16
>>  vlan_dev_get_egress_qos_mask(struct net_device *dev, struct sk_buff *skb)
>>  {
>> diff --git a/net/core/dev.c b/net/core/dev.c
>> index 3da9fb0..bfe9fce 100644
>> --- a/net/core/dev.c
>> +++ b/net/core/dev.c
>> @@ -3130,6 +3130,12 @@ another_round:
>>  
>>  	__this_cpu_inc(softnet_data.processed);
>>  
>> +	if (skb->protocol == cpu_to_be16(ETH_P_8021Q)) {
>> +		skb = vlan_untag(skb);
>> +		if (unlikely(!skb))
>> +			goto out;
>> +	}
>
>This becomes a NOP, why is it here?

Sorry but I probably do not understand what you mean. This piece of code
does untagging for non-hw-accel + multiply tagged frames.

>
>
>>  #ifdef CONFIG_NET_CLS_ACT
>>  	if (skb->tc_verd & TC_NCLS) {
>>  		skb->tc_verd = CLR_TC_NCLS(skb->tc_verd);
>> @@ -3177,7 +3183,7 @@ ncls:
>>  			ret = deliver_skb(skb, pt_prev, orig_dev);
>>  			pt_prev = NULL;
>>  		}
>> -		if (vlan_hwaccel_do_receive(&skb)) {
>> +		if (vlan_do_receive(&skb)) {
>>  			ret = __netif_receive_skb(skb);
>>  			goto out;
>>  		} else if (unlikely(!skb))
>
>
>Why rename the function?

I this it is correct because this function is no longer hwaccel-specific
since non-hw-accel path is using it as well.

Regards,

Jirka

>
>

^ permalink raw reply

* Re: [PATCH] bonding-tlb: better balance when choosing slaves
From: Jay Vosburgh @ 2011-04-02 18:25 UTC (permalink / raw)
  To: Weiping Pan(潘卫平)
  Cc: Andy Gospodarek, open list:BONDING DRIVER, open list
In-Reply-To: <1301753395-1205-1-git-send-email-panweiping3@gmail.com>


>tlb_get_least_loaded_slave() always chooses slave from
>bonding->first_slave, that gives the beginnig slaves more chances to be used.
>
>Let tlb_get_least_loaded_slave() chooses slave from a random positon in the
>slave list, make all slaves transmit packets more balanced.

	If outgoing traffic is not being starved (i.e., connections are
being balanced such that they are stacking up on one slave but
under-utilizing another), then I don't understand what benefit this has.

	There is already some degree of randomness, as peers will be
assigned in the order that packets are transmitted to them after each
rebalance.  The busiest peers will tend to be on the earlier slaves, and
vice versa, but I'm not sure this is a bad thing.

	Does this have any real gain other than making the rx/tx
statistics for the slaves more equal over time?

	I haven't measured it, but I would expect that for small numbers
of peers, having them tend to stay on the same slaves over time is
probably a good thing.

	-J

>Signed-off-by: Weiping Pan(潘卫平) <panweiping3@gmail.com>
>---
> drivers/net/bonding/bond_alb.c |   17 +++++++++++++++--
> 1 files changed, 15 insertions(+), 2 deletions(-)
>
>diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c
>index 9bc5de3..9fa64b0 100644
>--- a/drivers/net/bonding/bond_alb.c
>+++ b/drivers/net/bonding/bond_alb.c
>@@ -36,6 +36,7 @@
> #include <linux/if_bonding.h>
> #include <linux/if_vlan.h>
> #include <linux/in.h>
>+#include <linux/random.h>
> #include <net/ipx.h>
> #include <net/arp.h>
> #include <net/ipv6.h>
>@@ -206,15 +207,27 @@ static long long compute_gap(struct slave *slave)
> /* Caller must hold bond lock for read */
> static struct slave *tlb_get_least_loaded_slave(struct bonding *bond)
> {
>-	struct slave *slave, *least_loaded;
>+	struct slave *slave, *least_loaded, *start_slave;
> 	long long max_gap;
> 	int i;
>+	u8 n;
>
> 	least_loaded = NULL;
>+	start_slave = bond->first_slave;
> 	max_gap = LLONG_MIN;
>+        
>+	get_random_bytes(&n, 1);
>+
>+	if (bond->slave_cnt == 0)
>+		return NULL;
>+	n = n % bond->slave_cnt;
>+
>+	for (i=0; i<n; ++i) {
>+		start_slave = start_slave->next;
>+	}
>
> 	/* Find the slave with the largest gap */
>-	bond_for_each_slave(bond, slave, i) {
>+	bond_for_each_slave_from(bond, slave, i, start_slave) {
> 		if (SLAVE_IS_OK(slave)) {
> 			long long gap = compute_gap(slave);
>
>-- 
>1.7.4
>

---
	-Jay Vosburgh, IBM Linux Technology Center, fubar@us.ibm.com

^ permalink raw reply

* Re: tcp: disallow bind() to reuse addr/port regression in 2.6.38
From: Eric Dumazet @ 2011-04-02 18:10 UTC (permalink / raw)
  To: Cyril Bonté
  Cc: netdev, Daniel Baluta, Gaspar Chilingarov, Charles Duffy,
	Willy Tarreau
In-Reply-To: <201104022001.48144.cyril.bonte@free.fr>

Le samedi 02 avril 2011 à 20:01 +0200, Cyril Bonté a écrit :
> Hi All,
> 
> (2nd try to fix the mailing list address)
> 
> It has been reported that kernel 2.6.38 prevented the load balancer haproxy to 
> reload. After reading the kernel Changelog, it looks like the following commit 
> has a negative side effect on the the way haproxy "pauses" its listening 
> sockets to start a new process :
> 
> http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=c191a836a908d1dd6b40c503741f91b914de3348
> 
> Disabling the TCPF_CLOSE flag condition reallows to work as before. I guess 
> this was done for good reasons (Sorry, I haven't found the thread about that 
> commit in the archives yet) but other applications may also be impacted by 
> this change.
> 
> I add Willy Tarreau to the CC to open the discussion.
> 

> 		if (shutdown(listenfd, SHUT_WR) == 0 &&
> 		    listen(listenfd, 1024) == 0 &&
> 		    shutdown(listenfd, SHUT_RD) == 0) {
> 			printf("shutdown OK\n");
> 		}
> 	}
> 	exit(0);
> }
> 

Wow, not clear what this is doing.... 

for sure the listen() call is not needed ?

And the shutdown(listenfd, SHUT_WR) is clearly useless too.

I feel you only needed the shutdown(listenfd, SHUT_RD) call.

Why haproxy needs to setup a second listening socket on same port ?



^ permalink raw reply

* tcp: disallow bind() to reuse addr/port regression in 2.6.38
From: Cyril Bonté @ 2011-04-02 18:01 UTC (permalink / raw)
  To: netdev
  Cc: Eric Dumazet, Daniel Baluta, Gaspar Chilingarov, Charles Duffy,
	Willy Tarreau

Hi All,

(2nd try to fix the mailing list address)

It has been reported that kernel 2.6.38 prevented the load balancer haproxy to 
reload. After reading the kernel Changelog, it looks like the following commit 
has a negative side effect on the the way haproxy "pauses" its listening 
sockets to start a new process :

http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=c191a836a908d1dd6b40c503741f91b914de3348

Disabling the TCPF_CLOSE flag condition reallows to work as before. I guess 
this was done for good reasons (Sorry, I haven't found the thread about that 
commit in the archives yet) but other applications may also be impacted by 
this change.

I add Willy Tarreau to the CC to open the discussion.

Here is a simple test case to reproduce the issue (with kernel 2.6.38, it will 
fail on the second loop whereas it works with previous kernel versions) :
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <stdio.h>
#include <strings.h>

int main(int argc, char**argv)
{
	int listenfd;
	struct sockaddr_in servaddr;
	int i;
	int one = 1;
	
	for (i = 0; i < 2; i++)
	{
		printf("LOOP %d...\n", i + 1);
		listenfd=socket(AF_INET,SOCK_STREAM,0);

		setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,(char *)&one,sizeof(one));

		bzero(&servaddr,sizeof(servaddr));
		servaddr.sin_family = AF_INET;
		servaddr.sin_addr.s_addr=htonl(INADDR_ANY);
		servaddr.sin_port=htons(32000);

		if (bind(listenfd,(struct sockaddr *)&servaddr,sizeof(servaddr)) != 0)
		{
			perror("bind");
			exit(1);
		}

		if (listen(listenfd,1024) != 0)
		{
			perror("listen");
			exit(1);
		}

		if (shutdown(listenfd, SHUT_WR) == 0 &&
		    listen(listenfd, 1024) == 0 &&
		    shutdown(listenfd, SHUT_RD) == 0) {
			printf("shutdown OK\n");
		}
	}
	exit(0);
}

-- 
Cyril Bonté

^ permalink raw reply

* Re: Support e1000 M88 PHY registers in -d
From: Ben Hutchings @ 2011-04-02 16:24 UTC (permalink / raw)
  To: Anthony DeRobertis; +Cc: e1000-devel, netdev, 574574
In-Reply-To: <20100319043229.24908.99968.reportbug@Feynman.home>

Anthony,

I'm now upstream maintainer for ethtool so I've picked up your patch
again.

On Fri, 2010-03-19 at 00:32 -0400, Anthony DeRobertis wrote:
> Package: ethtool
> Version: 1:2.6.33-1
> Severity: wishlist
> 
> The M88 PHY registers contain useful information like the cable length
> estimate and the MDI/MDIX status. The attached patch makes -d dump
> them.

Patches for ethtool should include a commit message and Signed-off-by
line, as in the Linux kernel.  See sections 2 and 12 of
<http://www.kernel.org/doc/Documentation/SubmittingPatches>.  They
should be sent to this address and to netdev.

I'm forwarding this patch to netdev and the e1000 developers for review.

Ben.

[...]
> diff -rdbU3 ethtool-2.6.33/e1000.c ethtool-2.6.33.new//e1000.c
> --- ethtool-2.6.33/e1000.c      2009-02-08 18:52:12.000000000 -0500
> +++ ethtool-2.6.33.new//e1000.c 2010-03-19 00:26:33.044052610 -0400
> @@ -110,6 +110,61 @@
>  #define E1000_TCTL_RTLC   0x01000000    /* Re-transmit on late collision */
>  #define E1000_TCTL_NRTU   0x02000000    /* No Re-transmit on underrun */
>  
> +/* M88E1000 PHY Specific Status Register */
> +#define M88_PSSR_JABBER             0x0001 /* 1=Jabber */
> +#define M88_PSSR_REV_POLARITY       0x0002 /* 1=Polarity reversed */
> +#define M88_PSSR_DOWNSHIFT          0x0020 /* 1=Downshifted */
> +#define M88_PSSR_MDIX               0x0040 /* 1=MDIX; 0=MDI */
> +#define M88_PSSR_CABLE_LENGTH       0x0380 /* 0=<50M;1=50-80M;2=80-110M;
> +                                            * 3=110-140M;4=>140M */
> +#define M88_PSSR_LINK               0x0400 /* 1=Link up, 0=Link down */
> +#define M88_PSSR_SPD_DPLX_RESOLVED  0x0800 /* 1=Speed & Duplex resolved */
> +#define M88_PSSR_PAGE_RCVD          0x1000 /* 1=Page received */
> +#define M88_PSSR_DPLX               0x2000 /* 1=Duplex 0=Half Duplex */
> +#define M88_PSSR_SPEED              0xC000 /* Speed, bits 14:15 */
> +#define M88_PSSR_10MBS              0x0000 /* 00=10Mbs */
> +#define M88_PSSR_100MBS             0x4000 /* 01=100Mbs */
> +#define M88_PSSR_1000MBS            0x8000 /* 10=1000Mbs */
> +
> +#define M88_PSSR_CL_0_50     (0<<7)
> +#define M88_PSSR_CL_50_80    (1<<7)
> +#define M88_PSSR_CL_80_110   (2<<7)
> +#define M88_PSSR_CL_110_140  (3<<7)
> +#define M88_PSSR_CL_140_PLUS (4<<7)
> +
> +/* M88E1000 PHY Specific Control Register */
> +#define M88_PSCR_JABBER_DISABLE    0x0001  /* 1=Jabber Function disabled */
> +#define M88_PSCR_POLARITY_REVERSAL 0x0002  /* 1=Polarity Reversal enabled */
> +#define M88_PSCR_SQE_TEST          0x0004  /* 1=SQE Test enabled */
> +#define M88_PSCR_CLK125_DISABLE    0x0010  /* 1=CLK125 low,
> +                                            * 0=CLK125 toggling
> +                                            */
> +#define M88_PSCR_MDI_MASK         0x0060
> +#define M88_PSCR_MDI_MANUAL_MODE  0x0000   /* MDI Crossover Mode bits 6:5 */
> +                                          /* Manual MDI configuration */
> +#define M88_PSCR_MDIX_MANUAL_MODE 0x0020   /* Manual MDIX configuration */
> +#define M88_PSCR_AUTO_X_1000T     0x0040   /* 1000BASE-T: Auto crossover,
> +                                            *  100BASE-TX/10BASE-T:
> +                                            *  MDI Mode
> +                                            */
> +#define M88_PSCR_AUTO_X_MODE      0x0060   /* Auto crossover enabled
> +                                            * all speeds.
> +                                            */
> +#define M88_PSCR_10BT_EXT_DIST_ENABLE 0x0080
> +                                   /* 1=Enable Extended 10BASE-T distance
> +                                    * (Lower 10BASE-T RX Threshold)
> +                                    * 0=Normal 10BASE-T RX Threshold */
> +#define M88_PSCR_MII_5BIT_ENABLE      0x0100
> +                                   /* 1=5-Bit interface in 100BASE-TX
> +                                    * 0=MII interface in 100BASE-TX */
> +#define M88_PSCR_SCRAMBLER_DISABLE    0x0200       /* 1=Scrambler disable */
> +#define M88_PSCR_FORCE_LINK_GOOD      0x0400       /* 1=Force link good */
> +#define M88_PSCR_ASSERT_CRS_ON_TX     0x0800       /* 1=Assert CRS on Transmit */
> +
> +#define M88_PSCR_POLARITY_REVERSAL_SHIFT    1
> +#define M88_PSCR_AUTO_X_MODE_SHIFT          5
> +#define M88_PSCR_10BT_EXT_DIST_ENABLE_SHIFT 7
> +
>  /* PCI Device IDs */
>  #define E1000_DEV_ID_82542                    0x1000
>  #define E1000_DEV_ID_82543GC_FIBER            0x1001
> @@ -515,6 +570,72 @@
>                 regs_buff[12] == 1 ? "IGP" :
>                 regs_buff[12] == 2 ? "IGP2" : "unknown" );
>  
> +       if (0 == regs_buff[12]) {
> +               reg = regs_buff[13];
> +               fprintf(stdout,
> +                       "M88 PHY STATUS REGISTER:                 0x%08X\n"
> +                       "      Jabber:                            %s\n"
> +                       "      Polarity:                          %s\n"
> +                       "      Downshifted:                       %s\n"
> +                       "      MDI/MDIX:                          %s\n"
> +                       "      Cable Length Estimate:             %s meters\n"
> +                       "      Link State:                        %s\n"
> +                       "      Speed & Duplex Resolved:           %s\n"
> +                       "      Page Received:                     %s\n"
> +                       "      Duplex:                            %s\n"
> +                       "      Speed:                             %s mbps\n",
> +                       reg,
> +                       reg & M88_PSSR_JABBER       ? "yes"     : "no",
> +                       reg & M88_PSSR_REV_POLARITY ? "reverse" : "normal",
> +                       reg & M88_PSSR_DOWNSHIFT    ? "yes"     : "no",
> +                       reg & M88_PSSR_MDIX         ? "MDIX"    : "MDI",
> +                       ((reg & M88_PSSR_CABLE_LENGTH)==M88_PSSR_CL_0_50 ? "0-50"
> +                               : (reg & M88_PSSR_CABLE_LENGTH)==M88_PSSR_CL_50_80 ? "50-80"
> +                               : (reg & M88_PSSR_CABLE_LENGTH)==M88_PSSR_CL_80_110 ? "80-110"
> +                               : (reg & M88_PSSR_CABLE_LENGTH)==M88_PSSR_CL_110_140? "110-140"
> +                               : (reg & M88_PSSR_CABLE_LENGTH)==M88_PSSR_CL_140_PLUS ? "140+"
> +                               : "unknown"),
> +                       reg & M88_PSSR_LINK              ? "Up"      : "Down",
> +                       reg & M88_PSSR_SPD_DPLX_RESOLVED ? "Yes"     : "No",
> +                       reg & M88_PSSR_PAGE_RCVD         ? "Yes"     : "No",
> +                       reg & M88_PSSR_DPLX              ? "Full"    : "Half",
> +                       ((reg & M88_PSSR_SPEED)==M88_PSSR_10MBS        ? "10"
> +                               : (reg & M88_PSSR_SPEED)==M88_PSSR_100MBS  ? "100"
> +                               : (reg & M88_PSSR_SPEED)==M88_PSSR_1000MBS ? "1000"
> +                               : "unknown")
> +               );
> +
> +               reg = regs_buff[17];
> +               fprintf(stdout,
> +                       "M88 PHY CONTROL REGISTER:                0x%08X\n"
> +                       "      Jabber funtion:                    %s\n"
> +                       "      Auto-polarity:                     %s\n"
> +                       "      SQE Test:                          %s\n"
> +                       "      CLK125:                            %s\n"
> +                       "      Auto-MDIX:                         %s\n"
> +                       "      Extended 10Base-T Distance:        %s\n"
> +                       "      100Base-TX Interface:              %s\n"
> +                       "      Scrambler:                         %s\n"
> +                       "      Force Link Good:                   %s\n"
> +                       "      Assert CRS on Transmit:            %s\n",
> +                       reg,
> +                       reg & M88_PSCR_JABBER_DISABLE    ? "disabled" : "enabled",
> +                       reg & M88_PSCR_POLARITY_REVERSAL ? "enabled"  : "disabled",
> +                       reg & M88_PSCR_SQE_TEST          ? "enabled"  : "disabled",
> +                       reg & M88_PSCR_CLK125_DISABLE    ? "disabled" : "enabled",
> +                       ((reg & M88_PSCR_MDI_MASK)==M88_PSCR_MDI_MANUAL_MODE ? "force MDI"
> +                               : (reg & M88_PSCR_MDI_MASK)==M88_PSCR_MDIX_MANUAL_MODE ? "force MDIX"
> +                               : (reg & M88_PSCR_MDI_MASK)==M88_PSCR_AUTO_X_1000T ? "1000 auto, 10/100 MDI"
> +                               : (reg & M88_PSCR_MDI_MASK)==M88_PSCR_AUTO_X_MODE ? "auto"
> +                               : "wtf"),
> +                       reg & M88_PSCR_10BT_EXT_DIST_ENABLE ? "enabled" : "disabled",
> +                       reg & M88_PSCR_MII_5BIT_ENABLE ? "5-bit" : "MII",
> +                       reg & M88_PSCR_SCRAMBLER_DISABLE ? "disabled" : "enabled",
> +                       reg & M88_PSCR_FORCE_LINK_GOOD ? "forced" : "disabled",
> +                       reg & M88_PSCR_ASSERT_CRS_ON_TX ? "enabled" : "disabled"
> +               );
> +       }
> +
>         return 0;
>  }
>   
-- 
Ben Hutchings, Senior Software Engineer, Solarflare
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.


------------------------------------------------------------------------------
Create and publish websites with WebMatrix
Use the most popular FREE web apps or write code yourself; 
WebMatrix provides all the features you need to develop and 
publish your website. http://p.sf.net/sfu/ms-webmatrix-sf
_______________________________________________
E1000-devel mailing list
E1000-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/e1000-devel
To learn more about Intel&#174; Ethernet, visit http://communities.intel.com/community/wired

^ permalink raw reply

* Re: [patch net-next-2.6] net: vlan: make non-hw-accel rx path similar to hw-accel
From: Stephen Hemminger @ 2011-04-02 15:55 UTC (permalink / raw)
  To: Jiri Pirko
  Cc: netdev, davem, kaber, fubar, eric.dumazet, nicolas.2p.debian,
	andy, xiaosuo, jesse
In-Reply-To: <1301739966-7604-1-git-send-email-jpirko@redhat.com>

On Sat,  2 Apr 2011 12:26:06 +0200
Jiri Pirko <jpirko@redhat.com> wrote:

> Now there are 2 paths for rx vlan frames. When rx-vlan-hw-accel is
> enabled, skb is untagged by NIC, vlan_tci is set and the skb gets into
> vlan code in __netif_receive_skb - vlan_hwaccel_do_receive.
> 
> For non-rx-vlan-hw-accel however, tagged skb goes thru whole
> __netif_receive_skb, it's untagged in ptype_base hander and reinjected
> 
> This incosistency is fixed by this patch. Vlan untagging happens early in
> __netif_receive_skb so the rest of code (ptype_all handlers, rx_handlers)
> see the skb like it was untagged by hw.
> 
> Signed-off-by: Jiri Pirko <jpirko@redhat.com>
> ---
>  include/linux/if_vlan.h |   10 ++-
>  net/8021q/vlan.c        |    8 --
>  net/8021q/vlan.h        |    2 -
>  net/8021q/vlan_core.c   |   86 +++++++++++++++++++++++-
>  net/8021q/vlan_dev.c    |  173 -----------------------------------------------
>  net/core/dev.c          |    8 ++-
>  6 files changed, 100 insertions(+), 187 deletions(-)
> 
> diff --git a/include/linux/if_vlan.h b/include/linux/if_vlan.h
> index 635e1fa..998b299 100644
> --- a/include/linux/if_vlan.h
> +++ b/include/linux/if_vlan.h
> @@ -132,7 +132,8 @@ extern u16 vlan_dev_vlan_id(const struct net_device *dev);
>  
>  extern int __vlan_hwaccel_rx(struct sk_buff *skb, struct vlan_group *grp,
>  			     u16 vlan_tci, int polling);
> -extern bool vlan_hwaccel_do_receive(struct sk_buff **skb);
> +extern bool vlan_do_receive(struct sk_buff **skb);
> +extern struct sk_buff *vlan_untag(struct sk_buff *skb);
>  extern gro_result_t
>  vlan_gro_receive(struct napi_struct *napi, struct vlan_group *grp,
>  		 unsigned int vlan_tci, struct sk_buff *skb);
> @@ -166,13 +167,18 @@ static inline int __vlan_hwaccel_rx(struct sk_buff *skb, struct vlan_group *grp,
>  	return NET_XMIT_SUCCESS;
>  }
>  
> -static inline bool vlan_hwaccel_do_receive(struct sk_buff **skb)
> +static inline bool vlan_do_receive(struct sk_buff **skb)
>  {
>  	if ((*skb)->vlan_tci & VLAN_VID_MASK)
>  		(*skb)->pkt_type = PACKET_OTHERHOST;
>  	return false;
>  }

Why the added unnecessary indirection


> +inline struct sk_buff *vlan_untag(struct sk_buff *skb)
> +{
> +	return skb;
> +}

This adds no value.

>  static inline gro_result_t
>  vlan_gro_receive(struct napi_struct *napi, struct vlan_group *grp,
>  		 unsigned int vlan_tci, struct sk_buff *skb)
> diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c
> index 7850412..59f0a9d 100644
> --- a/net/8021q/vlan.c
> +++ b/net/8021q/vlan.c
> @@ -49,11 +49,6 @@ const char vlan_version[] = DRV_VERSION;
>  static const char vlan_copyright[] = "Ben Greear <greearb@candelatech.com>";
>  static const char vlan_buggyright[] = "David S. Miller <davem@redhat.com>";
>  
> -static struct packet_type vlan_packet_type __read_mostly = {
> -	.type = cpu_to_be16(ETH_P_8021Q),
> -	.func = vlan_skb_recv, /* VLAN receive method */
> -};
> -
>  /* End of global variables definitions. */
>  
>  static void vlan_group_free(struct vlan_group *grp)
> @@ -688,7 +683,6 @@ static int __init vlan_proto_init(void)
>  	if (err < 0)
>  		goto err4;
>  
> -	dev_add_pack(&vlan_packet_type);
>  	vlan_ioctl_set(vlan_ioctl_handler);
>  	return 0;
>  
> @@ -709,8 +703,6 @@ static void __exit vlan_cleanup_module(void)
>  
>  	unregister_netdevice_notifier(&vlan_notifier_block);
>  
> -	dev_remove_pack(&vlan_packet_type);
> -
>  	unregister_pernet_subsys(&vlan_net_ops);
>  	rcu_barrier(); /* Wait for completion of call_rcu()'s */
>  
> diff --git a/net/8021q/vlan.h b/net/8021q/vlan.h
> index 5687c9b..c3408de 100644
> --- a/net/8021q/vlan.h
> +++ b/net/8021q/vlan.h
> @@ -75,8 +75,6 @@ static inline struct vlan_dev_info *vlan_dev_info(const struct net_device *dev)
>  }
>  
>  /* found in vlan_dev.c */
> -int vlan_skb_recv(struct sk_buff *skb, struct net_device *dev,
> -		  struct packet_type *ptype, struct net_device *orig_dev);
>  void vlan_dev_set_ingress_priority(const struct net_device *dev,
>  				   u32 skb_prio, u16 vlan_prio);
>  int vlan_dev_set_egress_priority(const struct net_device *dev,
> diff --git a/net/8021q/vlan_core.c b/net/8021q/vlan_core.c
> index ce8e3ab..bc83ecc 100644
> --- a/net/8021q/vlan_core.c
> +++ b/net/8021q/vlan_core.c
> @@ -4,7 +4,7 @@
>  #include <linux/netpoll.h>
>  #include "vlan.h"
>  
> -bool vlan_hwaccel_do_receive(struct sk_buff **skbp)
> +bool vlan_do_receive(struct sk_buff **skbp)
>  {
>  	struct sk_buff *skb = *skbp;
>  	u16 vlan_id = skb->vlan_tci & VLAN_VID_MASK;
> @@ -88,3 +88,87 @@ gro_result_t vlan_gro_frags(struct napi_struct *napi, struct vlan_group *grp,
>  	return napi_gro_frags(napi);
>  }
>  EXPORT_SYMBOL(vlan_gro_frags);
> +
> +static inline struct sk_buff *vlan_check_reorder_header(struct sk_buff *skb)
> +{
> +	if (vlan_dev_info(skb->dev)->flags & VLAN_FLAG_REORDER_HDR) {
> +		if (skb_cow(skb, skb_headroom(skb)) < 0)
> +			skb = NULL;
> +		if (skb) {
> +			/* Lifted from Gleb's VLAN code... */
> +			memmove(skb->data - ETH_HLEN,
> +				skb->data - VLAN_ETH_HLEN, 12);
> +			skb->mac_header += VLAN_HLEN;
> +		}
> +	}
> +	return skb;
> +}

Do not mark code as 'static inline' let compiler decide.

> +static inline void vlan_set_encap_proto(struct sk_buff *skb,
> +					struct vlan_hdr *vhdr)
> +{
> +	__be16 proto;
> +	unsigned char *rawp;
> +
> +	/*
> +	 * Was a VLAN packet, grab the encapsulated protocol, which the layer
> +	 * three protocols care about.
> +	 */
> +
> +	proto = vhdr->h_vlan_encapsulated_proto;
> +	if (ntohs(proto) >= 1536) {
> +		skb->protocol = proto;
> +		return;
> +	}
> +
> +	rawp = skb->data;
> +	if (*(unsigned short *) rawp == 0xFFFF)
> +		/*
> +		 * This is a magic hack to spot IPX packets. Older Novell
> +		 * breaks the protocol design and runs IPX over 802.3 without
> +		 * an 802.2 LLC layer. We look for FFFF which isn't a used
> +		 * 802.2 SSAP/DSAP. This won't work for fault tolerant netware
> +		 * but does for the rest.
> +		 */
> +		skb->protocol = htons(ETH_P_802_3);
> +	else
> +		/*
> +		 * Real 802.2 LLC
> +		 */
> +		skb->protocol = htons(ETH_P_802_2);
> +}

What about doublely tagged packets?

> +struct sk_buff *vlan_untag(struct sk_buff *skb)
> +{
> +	struct vlan_hdr *vhdr;
> +	u16 vlan_tci;
> +
> +	if (unlikely(vlan_tx_tag_present(skb))) {
> +		/* vlan_tci is already set-up so leave this for another time */
> +		return skb;
> +	}
> +
> +	skb = skb_share_check(skb, GFP_ATOMIC);
> +	if (unlikely(!skb))
> +		goto err_free;
> +
> +	if (unlikely(!pskb_may_pull(skb, VLAN_HLEN)))
> +		goto err_free;
> +
> +	vhdr = (struct vlan_hdr *) skb->data;
> +	vlan_tci = ntohs(vhdr->h_vlan_TCI);
> +	__vlan_hwaccel_put_tag(skb, vlan_tci);
> +
> +	skb_pull_rcsum(skb, VLAN_HLEN);
> +	vlan_set_encap_proto(skb, vhdr);
> +
> +	skb = vlan_check_reorder_header(skb);
> +	if (unlikely(!skb))
> +		goto err_free;
> +
> +	return skb;
> +
> +err_free:
> +	kfree_skb(skb);
> +	return NULL;
> +}
> diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c
> index e34ea9e..b4f061f 100644
> --- a/net/8021q/vlan_dev.c
> +++ b/net/8021q/vlan_dev.c
> @@ -65,179 +65,6 @@ static int vlan_dev_rebuild_header(struct sk_buff *skb)
>  	return 0;
>  }
>  
> -static inline struct sk_buff *vlan_check_reorder_header(struct sk_buff *skb)
> -{
> -	if (vlan_dev_info(skb->dev)->flags & VLAN_FLAG_REORDER_HDR) {
> -		if (skb_cow(skb, skb_headroom(skb)) < 0)
> -			skb = NULL;
> -		if (skb) {
> -			/* Lifted from Gleb's VLAN code... */
> -			memmove(skb->data - ETH_HLEN,
> -				skb->data - VLAN_ETH_HLEN, 12);
> -			skb->mac_header += VLAN_HLEN;
> -		}
> -	}
> -
> -	return skb;
> -}
> -
> -static inline void vlan_set_encap_proto(struct sk_buff *skb,
> -		struct vlan_hdr *vhdr)
> -{
> -	__be16 proto;
> -	unsigned char *rawp;
> -
> -	/*
> -	 * Was a VLAN packet, grab the encapsulated protocol, which the layer
> -	 * three protocols care about.
> -	 */
> -
> -	proto = vhdr->h_vlan_encapsulated_proto;
> -	if (ntohs(proto) >= 1536) {
> -		skb->protocol = proto;
> -		return;
> -	}
> -
> -	rawp = skb->data;
> -	if (*(unsigned short *)rawp == 0xFFFF)
> -		/*
> -		 * This is a magic hack to spot IPX packets. Older Novell
> -		 * breaks the protocol design and runs IPX over 802.3 without
> -		 * an 802.2 LLC layer. We look for FFFF which isn't a used
> -		 * 802.2 SSAP/DSAP. This won't work for fault tolerant netware
> -		 * but does for the rest.
> -		 */
> -		skb->protocol = htons(ETH_P_802_3);
> -	else
> -		/*
> -		 * Real 802.2 LLC
> -		 */
> -		skb->protocol = htons(ETH_P_802_2);
> -}
> -
> -/*
> - *	Determine the packet's protocol ID. The rule here is that we
> - *	assume 802.3 if the type field is short enough to be a length.
> - *	This is normal practice and works for any 'now in use' protocol.
> - *
> - *  Also, at this point we assume that we ARE dealing exclusively with
> - *  VLAN packets, or packets that should be made into VLAN packets based
> - *  on a default VLAN ID.
> - *
> - *  NOTE:  Should be similar to ethernet/eth.c.
> - *
> - *  SANITY NOTE:  This method is called when a packet is moving up the stack
> - *                towards userland.  To get here, it would have already passed
> - *                through the ethernet/eth.c eth_type_trans() method.
> - *  SANITY NOTE 2: We are referencing to the VLAN_HDR frields, which MAY be
> - *                 stored UNALIGNED in the memory.  RISC systems don't like
> - *                 such cases very much...
> - *  SANITY NOTE 2a: According to Dave Miller & Alexey, it will always be
> - *  		    aligned, so there doesn't need to be any of the unaligned
> - *  		    stuff.  It has been commented out now...  --Ben
> - *
> - */
> -int vlan_skb_recv(struct sk_buff *skb, struct net_device *dev,
> -		  struct packet_type *ptype, struct net_device *orig_dev)
> -{
> -	struct vlan_hdr *vhdr;
> -	struct vlan_pcpu_stats *rx_stats;
> -	struct net_device *vlan_dev;
> -	u16 vlan_id;
> -	u16 vlan_tci;
> -
> -	skb = skb_share_check(skb, GFP_ATOMIC);
> -	if (skb == NULL)
> -		goto err_free;
> -
> -	if (unlikely(!pskb_may_pull(skb, VLAN_HLEN)))
> -		goto err_free;
> -
> -	vhdr = (struct vlan_hdr *)skb->data;
> -	vlan_tci = ntohs(vhdr->h_vlan_TCI);
> -	vlan_id = vlan_tci & VLAN_VID_MASK;
> -
> -	rcu_read_lock();
> -	vlan_dev = vlan_find_dev(dev, vlan_id);
> -
> -	/* If the VLAN device is defined, we use it.
> -	 * If not, and the VID is 0, it is a 802.1p packet (not
> -	 * really a VLAN), so we will just netif_rx it later to the
> -	 * original interface, but with the skb->proto set to the
> -	 * wrapped proto: we do nothing here.
> -	 */
> -
> -	if (!vlan_dev) {
> -		if (vlan_id) {
> -			pr_debug("%s: ERROR: No net_device for VID: %u on dev: %s\n",
> -				 __func__, vlan_id, dev->name);
> -			goto err_unlock;
> -		}
> -		rx_stats = NULL;
> -	} else {
> -		skb->dev = vlan_dev;
> -
> -		rx_stats = this_cpu_ptr(vlan_dev_info(skb->dev)->vlan_pcpu_stats);
> -
> -		u64_stats_update_begin(&rx_stats->syncp);
> -		rx_stats->rx_packets++;
> -		rx_stats->rx_bytes += skb->len;
> -
> -		skb->priority = vlan_get_ingress_priority(skb->dev, vlan_tci);
> -
> -		pr_debug("%s: priority: %u for TCI: %hu\n",
> -			 __func__, skb->priority, vlan_tci);
> -
> -		switch (skb->pkt_type) {
> -		case PACKET_BROADCAST:
> -			/* Yeah, stats collect these together.. */
> -			/* stats->broadcast ++; // no such counter :-( */
> -			break;
> -
> -		case PACKET_MULTICAST:
> -			rx_stats->rx_multicast++;
> -			break;
> -
> -		case PACKET_OTHERHOST:
> -			/* Our lower layer thinks this is not local, let's make
> -			 * sure.
> -			 * This allows the VLAN to have a different MAC than the
> -			 * underlying device, and still route correctly.
> -			 */
> -			if (!compare_ether_addr(eth_hdr(skb)->h_dest,
> -						skb->dev->dev_addr))
> -				skb->pkt_type = PACKET_HOST;
> -			break;
> -		default:
> -			break;
> -		}
> -		u64_stats_update_end(&rx_stats->syncp);
> -	}
> -
> -	skb_pull_rcsum(skb, VLAN_HLEN);
> -	vlan_set_encap_proto(skb, vhdr);
> -
> -	if (vlan_dev) {
> -		skb = vlan_check_reorder_header(skb);
> -		if (!skb) {
> -			rx_stats->rx_errors++;
> -			goto err_unlock;
> -		}
> -	}
> -
> -	netif_rx(skb);
> -
> -	rcu_read_unlock();
> -	return NET_RX_SUCCESS;
> -
> -err_unlock:
> -	rcu_read_unlock();
> -err_free:
> -	atomic_long_inc(&dev->rx_dropped);
> -	kfree_skb(skb);
> -	return NET_RX_DROP;
> -}
> -
>  static inline u16
>  vlan_dev_get_egress_qos_mask(struct net_device *dev, struct sk_buff *skb)
>  {
> diff --git a/net/core/dev.c b/net/core/dev.c
> index 3da9fb0..bfe9fce 100644
> --- a/net/core/dev.c
> +++ b/net/core/dev.c
> @@ -3130,6 +3130,12 @@ another_round:
>  
>  	__this_cpu_inc(softnet_data.processed);
>  
> +	if (skb->protocol == cpu_to_be16(ETH_P_8021Q)) {
> +		skb = vlan_untag(skb);
> +		if (unlikely(!skb))
> +			goto out;
> +	}

This becomes a NOP, why is it here?


>  #ifdef CONFIG_NET_CLS_ACT
>  	if (skb->tc_verd & TC_NCLS) {
>  		skb->tc_verd = CLR_TC_NCLS(skb->tc_verd);
> @@ -3177,7 +3183,7 @@ ncls:
>  			ret = deliver_skb(skb, pt_prev, orig_dev);
>  			pt_prev = NULL;
>  		}
> -		if (vlan_hwaccel_do_receive(&skb)) {
> +		if (vlan_do_receive(&skb)) {
>  			ret = __netif_receive_skb(skb);
>  			goto out;
>  		} else if (unlikely(!skb))


Why rename the function?



^ permalink raw reply

* [PATCH v2] vlan: convert VLAN devices to use ndo_fix_features()
From: Michał Mirosław @ 2011-04-02 14:41 UTC (permalink / raw)
  To: netdev
  Cc: Jesse Gross, Patrick McHardy, David S. Miller, John Fastabend,
	Eric Dumazet
In-Reply-To: <20110402122857.GA3147@rere.qmqm.pl>

Note: get_flags was actually broken, because it should return the
flags capped with vlan_features. This is now done implicitly by
limiting netdev->hw_features.

RX checksumming offload control is (and was) broken, as there was no way
before to say whether it's done for tagged packets.

Signed-off-by: Michał Mirosław <mirq-linux@rere.qmqm.pl>
---
 net/8021q/vlan.c     |    8 ++------
 net/8021q/vlan_dev.c |   50 ++++++++++++++------------------------------------
 2 files changed, 16 insertions(+), 42 deletions(-)

changes from v1:
 - folded netdev_features_change() in vlan_transfer_features()
   This now depends on patch titled:
	net: Call netdev_features_change() from netdev_update_features()

diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c
index 7850412..e47600b 100644
--- a/net/8021q/vlan.c
+++ b/net/8021q/vlan.c
@@ -327,10 +327,6 @@ static void vlan_sync_address(struct net_device *dev,
 static void vlan_transfer_features(struct net_device *dev,
 				   struct net_device *vlandev)
 {
-	u32 old_features = vlandev->features;
-
-	vlandev->features &= ~dev->vlan_features;
-	vlandev->features |= dev->features & dev->vlan_features;
 	vlandev->gso_max_size = dev->gso_max_size;
 
 	if (dev->features & NETIF_F_HW_VLAN_TX)
@@ -341,8 +337,8 @@ static void vlan_transfer_features(struct net_device *dev,
 #if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE)
 	vlandev->fcoe_ddp_xid = dev->fcoe_ddp_xid;
 #endif
-	if (old_features != vlandev->features)
-		netdev_features_change(vlandev);
+
+	netdev_update_features(vlandev);
 }
 
 static void __vlan_device_event(struct net_device *dev, unsigned long event)
diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c
index e34ea9e..b84a46b 100644
--- a/net/8021q/vlan_dev.c
+++ b/net/8021q/vlan_dev.c
@@ -704,8 +704,8 @@ static int vlan_dev_init(struct net_device *dev)
 					  (1<<__LINK_STATE_DORMANT))) |
 		      (1<<__LINK_STATE_PRESENT);
 
-	dev->features |= real_dev->features & real_dev->vlan_features;
-	dev->features |= NETIF_F_LLTX;
+	dev->hw_features = real_dev->vlan_features & NETIF_F_ALL_TX_OFFLOADS;
+	dev->features |= real_dev->vlan_features | NETIF_F_LLTX;
 	dev->gso_max_size = real_dev->gso_max_size;
 
 	/* ipv6 shared card related stuff */
@@ -759,6 +759,17 @@ static void vlan_dev_uninit(struct net_device *dev)
 	}
 }
 
+static u32 vlan_dev_fix_features(struct net_device *dev, u32 features)
+{
+	struct net_device *real_dev = vlan_dev_info(dev)->real_dev;
+
+	features &= (real_dev->features | NETIF_F_LLTX);
+	if (dev_ethtool_get_rx_csum(real_dev))
+		features |= NETIF_F_RXCSUM;
+
+	return features;
+}
+
 static int vlan_ethtool_get_settings(struct net_device *dev,
 				     struct ethtool_cmd *cmd)
 {
@@ -774,18 +785,6 @@ static void vlan_ethtool_get_drvinfo(struct net_device *dev,
 	strcpy(info->fw_version, "N/A");
 }
 
-static u32 vlan_ethtool_get_rx_csum(struct net_device *dev)
-{
-	const struct vlan_dev_info *vlan = vlan_dev_info(dev);
-	return dev_ethtool_get_rx_csum(vlan->real_dev);
-}
-
-static u32 vlan_ethtool_get_flags(struct net_device *dev)
-{
-	const struct vlan_dev_info *vlan = vlan_dev_info(dev);
-	return dev_ethtool_get_flags(vlan->real_dev);
-}
-
 static struct rtnl_link_stats64 *vlan_dev_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
 {
 
@@ -823,32 +822,10 @@ static struct rtnl_link_stats64 *vlan_dev_get_stats64(struct net_device *dev, st
 	return stats;
 }
 
-static int vlan_ethtool_set_tso(struct net_device *dev, u32 data)
-{
-       if (data) {
-		struct net_device *real_dev = vlan_dev_info(dev)->real_dev;
-
-		/* Underlying device must support TSO for VLAN-tagged packets
-		 * and must have TSO enabled now.
-		 */
-		if (!(real_dev->vlan_features & NETIF_F_TSO))
-			return -EOPNOTSUPP;
-		if (!(real_dev->features & NETIF_F_TSO))
-			return -EINVAL;
-		dev->features |= NETIF_F_TSO;
-	} else {
-		dev->features &= ~NETIF_F_TSO;
-	}
-	return 0;
-}
-
 static const struct ethtool_ops vlan_ethtool_ops = {
 	.get_settings	        = vlan_ethtool_get_settings,
 	.get_drvinfo	        = vlan_ethtool_get_drvinfo,
 	.get_link		= ethtool_op_get_link,
-	.get_rx_csum		= vlan_ethtool_get_rx_csum,
-	.get_flags		= vlan_ethtool_get_flags,
-	.set_tso                = vlan_ethtool_set_tso,
 };
 
 static const struct net_device_ops vlan_netdev_ops = {
@@ -874,6 +851,7 @@ static const struct net_device_ops vlan_netdev_ops = {
 	.ndo_fcoe_get_wwn	= vlan_dev_fcoe_get_wwn,
 	.ndo_fcoe_ddp_target	= vlan_dev_fcoe_ddp_target,
 #endif
+	.ndo_fix_features	= vlan_dev_fix_features,
 };
 
 void vlan_setup(struct net_device *dev)
-- 
1.7.2.5


^ permalink raw reply related

* [PATCH] net: Call netdev_features_change() from netdev_update_features()
From: Michał Mirosław @ 2011-04-02 14:41 UTC (permalink / raw)
  To: netdev; +Cc: David S. Miller, Ben Hutchings, Jesse Gross

Issue FEAT_CHANGE notification when features are changed by
netdev_update_features().  This will allow changes made by extra constraints
on e.g. MTU change to be properly propagated like changes via ethtool.

Signed-off-by: Michał Mirosław <mirq-linux@rere.qmqm.pl>
---
 include/linux/netdevice.h |    1 +
 net/core/dev.c            |   23 +++++++++++++++++------
 net/core/ethtool.c        |    6 +++---
 3 files changed, 21 insertions(+), 9 deletions(-)

diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 0249fe7..a4664cc 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -2550,6 +2550,7 @@ static inline u32 netdev_get_wanted_features(struct net_device *dev)
 }
 u32 netdev_increment_features(u32 all, u32 one, u32 mask);
 u32 netdev_fix_features(struct net_device *dev, u32 features);
+int __netdev_update_features(struct net_device *dev);
 void netdev_update_features(struct net_device *dev);
 
 void netif_stacked_transfer_operstate(const struct net_device *rootdev,
diff --git a/net/core/dev.c b/net/core/dev.c
index 3da9fb0..02f5637 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -5236,7 +5236,7 @@ u32 netdev_fix_features(struct net_device *dev, u32 features)
 }
 EXPORT_SYMBOL(netdev_fix_features);
 
-void netdev_update_features(struct net_device *dev)
+int __netdev_update_features(struct net_device *dev)
 {
 	u32 features;
 	int err = 0;
@@ -5250,7 +5250,7 @@ void netdev_update_features(struct net_device *dev)
 	features = netdev_fix_features(dev, features);
 
 	if (dev->features == features)
-		return;
+		return 0;
 
 	netdev_info(dev, "Features changed: 0x%08x -> 0x%08x\n",
 		dev->features, features);
@@ -5258,12 +5258,23 @@ void netdev_update_features(struct net_device *dev)
 	if (dev->netdev_ops->ndo_set_features)
 		err = dev->netdev_ops->ndo_set_features(dev, features);
 
-	if (!err)
-		dev->features = features;
-	else if (err < 0)
+	if (unlikely(err < 0)) {
 		netdev_err(dev,
 			"set_features() failed (%d); wanted 0x%08x, left 0x%08x\n",
 			err, features, dev->features);
+		return -1;
+	}
+
+	if (!err)
+		dev->features = features;
+
+	return 1;
+}
+
+void netdev_update_features(struct net_device *dev)
+{
+	if (__netdev_update_features(dev))
+		netdev_features_change(dev);
 }
 EXPORT_SYMBOL(netdev_update_features);
 
@@ -5430,7 +5441,7 @@ int register_netdevice(struct net_device *dev)
 		goto err_uninit;
 	dev->reg_state = NETREG_REGISTERED;
 
-	netdev_update_features(dev);
+	__netdev_update_features(dev);
 
 	/*
 	 *	Default initial state at registry is that the
diff --git a/net/core/ethtool.c b/net/core/ethtool.c
index 74ead9e..439e4b0 100644
--- a/net/core/ethtool.c
+++ b/net/core/ethtool.c
@@ -317,7 +317,7 @@ static int ethtool_set_features(struct net_device *dev, void __user *useraddr)
 
 	dev->wanted_features &= ~features[0].valid;
 	dev->wanted_features |= features[0].valid & features[0].requested;
-	netdev_update_features(dev);
+	__netdev_update_features(dev);
 
 	if ((dev->wanted_features ^ dev->features) & features[0].valid)
 		ret |= ETHTOOL_F_WISH;
@@ -499,7 +499,7 @@ static int ethtool_set_one_feature(struct net_device *dev,
 		else
 			dev->wanted_features &= ~mask;
 
-		netdev_update_features(dev);
+		__netdev_update_features(dev);
 		return 0;
 	}
 
@@ -551,7 +551,7 @@ int __ethtool_set_flags(struct net_device *dev, u32 data)
 	dev->wanted_features =
 		(dev->wanted_features & ~changed) | data;
 
-	netdev_update_features(dev);
+	__netdev_update_features(dev);
 
 	return 0;
 }
-- 
1.7.2.5


^ permalink raw reply related

* [PATCH] bonding-tlb: better balance when choosing slaves
From: Weiping Pan(潘卫平) @ 2011-04-02 14:09 UTC (permalink / raw)
  Cc: Weiping Pan , Jay Vosburgh, Andy Gospodarek,
	open list:BONDING DRIVER, open list

tlb_get_least_loaded_slave() always chooses slave from
bonding->first_slave, that gives the beginnig slaves more chances to be used.

Let tlb_get_least_loaded_slave() chooses slave from a random positon in the
slave list, make all slaves transmit packets more balanced.

Signed-off-by: Weiping Pan(潘卫平) <panweiping3@gmail.com>
---
 drivers/net/bonding/bond_alb.c |   17 +++++++++++++++--
 1 files changed, 15 insertions(+), 2 deletions(-)

diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c
index 9bc5de3..9fa64b0 100644
--- a/drivers/net/bonding/bond_alb.c
+++ b/drivers/net/bonding/bond_alb.c
@@ -36,6 +36,7 @@
 #include <linux/if_bonding.h>
 #include <linux/if_vlan.h>
 #include <linux/in.h>
+#include <linux/random.h>
 #include <net/ipx.h>
 #include <net/arp.h>
 #include <net/ipv6.h>
@@ -206,15 +207,27 @@ static long long compute_gap(struct slave *slave)
 /* Caller must hold bond lock for read */
 static struct slave *tlb_get_least_loaded_slave(struct bonding *bond)
 {
-	struct slave *slave, *least_loaded;
+	struct slave *slave, *least_loaded, *start_slave;
 	long long max_gap;
 	int i;
+	u8 n;
 
 	least_loaded = NULL;
+	start_slave = bond->first_slave;
 	max_gap = LLONG_MIN;
+        
+	get_random_bytes(&n, 1);
+
+	if (bond->slave_cnt == 0)
+		return NULL;
+	n = n % bond->slave_cnt;
+
+	for (i=0; i<n; ++i) {
+		start_slave = start_slave->next;
+	}
 
 	/* Find the slave with the largest gap */
-	bond_for_each_slave(bond, slave, i) {
+	bond_for_each_slave_from(bond, slave, i, start_slave) {
 		if (SLAVE_IS_OK(slave)) {
 			long long gap = compute_gap(slave);
 
-- 
1.7.4

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox