Skip to content

Commit ab10dcc

Browse files
gfreewinddavem330
authored andcommitted
rps: Inspect PPTP encapsulated by GRE to get flow hash
The PPTP is encapsulated by GRE header with that GRE_VERSION bits must contain one. But current GRE RPS needs the GRE_VERSION must be zero. So RPS does not work for PPTP traffic. In my test environment, there are four MIPS cores, and all traffic are passed through by PPTP. As a result, only one core is 100% busy while other three cores are very idle. After this patch, the usage of four cores are balanced well. Signed-off-by: Gao Feng <[email protected]> Reviewed-by: Philip Prindeville <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 084c953 commit ab10dcc

File tree

5 files changed

+135
-71
lines changed

5 files changed

+135
-71
lines changed

drivers/net/ppp/pptp.c

+1-35
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
#include <net/icmp.h>
3838
#include <net/route.h>
3939
#include <net/gre.h>
40+
#include <net/pptp.h>
4041

4142
#include <linux/uaccess.h>
4243

@@ -53,41 +54,6 @@ static struct proto pptp_sk_proto __read_mostly;
5354
static const struct ppp_channel_ops pptp_chan_ops;
5455
static const struct proto_ops pptp_ops;
5556

56-
#define PPP_LCP_ECHOREQ 0x09
57-
#define PPP_LCP_ECHOREP 0x0A
58-
#define SC_RCV_BITS (SC_RCV_B7_1|SC_RCV_B7_0|SC_RCV_ODDP|SC_RCV_EVNP)
59-
60-
#define MISSING_WINDOW 20
61-
#define WRAPPED(curseq, lastseq)\
62-
((((curseq) & 0xffffff00) == 0) &&\
63-
(((lastseq) & 0xffffff00) == 0xffffff00))
64-
65-
#define PPTP_GRE_PROTO 0x880B
66-
#define PPTP_GRE_VER 0x1
67-
68-
#define PPTP_GRE_FLAG_C 0x80
69-
#define PPTP_GRE_FLAG_R 0x40
70-
#define PPTP_GRE_FLAG_K 0x20
71-
#define PPTP_GRE_FLAG_S 0x10
72-
#define PPTP_GRE_FLAG_A 0x80
73-
74-
#define PPTP_GRE_IS_C(f) ((f)&PPTP_GRE_FLAG_C)
75-
#define PPTP_GRE_IS_R(f) ((f)&PPTP_GRE_FLAG_R)
76-
#define PPTP_GRE_IS_K(f) ((f)&PPTP_GRE_FLAG_K)
77-
#define PPTP_GRE_IS_S(f) ((f)&PPTP_GRE_FLAG_S)
78-
#define PPTP_GRE_IS_A(f) ((f)&PPTP_GRE_FLAG_A)
79-
80-
#define PPTP_HEADER_OVERHEAD (2+sizeof(struct pptp_gre_header))
81-
struct pptp_gre_header {
82-
u8 flags;
83-
u8 ver;
84-
__be16 protocol;
85-
__be16 payload_len;
86-
__be16 call_id;
87-
__be32 seq;
88-
__be32 ack;
89-
} __packed;
90-
9157
static struct pppox_sock *lookup_chan(u16 call_id, __be32 s_addr)
9258
{
9359
struct pppox_sock *sock;

include/net/gre.h

+9-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,15 @@
77
struct gre_base_hdr {
88
__be16 flags;
99
__be16 protocol;
10-
};
10+
} __packed;
11+
12+
struct gre_full_hdr {
13+
struct gre_base_hdr fixed_header;
14+
__be16 csum;
15+
__be16 reserved1;
16+
__be32 key;
17+
__be32 seq;
18+
} __packed;
1119
#define GRE_HEADER_SECTION 4
1220

1321
#define GREPROTO_CISCO 0

include/net/pptp.h

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
#ifndef _NET_PPTP_H
2+
#define _NET_PPTP_H
3+
4+
#define PPP_LCP_ECHOREQ 0x09
5+
#define PPP_LCP_ECHOREP 0x0A
6+
#define SC_RCV_BITS (SC_RCV_B7_1|SC_RCV_B7_0|SC_RCV_ODDP|SC_RCV_EVNP)
7+
8+
#define MISSING_WINDOW 20
9+
#define WRAPPED(curseq, lastseq)\
10+
((((curseq) & 0xffffff00) == 0) &&\
11+
(((lastseq) & 0xffffff00) == 0xffffff00))
12+
13+
#define PPTP_GRE_PROTO 0x880B
14+
#define PPTP_GRE_VER 0x1
15+
16+
#define PPTP_GRE_FLAG_C 0x80
17+
#define PPTP_GRE_FLAG_R 0x40
18+
#define PPTP_GRE_FLAG_K 0x20
19+
#define PPTP_GRE_FLAG_S 0x10
20+
#define PPTP_GRE_FLAG_A 0x80
21+
22+
#define PPTP_GRE_IS_C(f) ((f)&PPTP_GRE_FLAG_C)
23+
#define PPTP_GRE_IS_R(f) ((f)&PPTP_GRE_FLAG_R)
24+
#define PPTP_GRE_IS_K(f) ((f)&PPTP_GRE_FLAG_K)
25+
#define PPTP_GRE_IS_S(f) ((f)&PPTP_GRE_FLAG_S)
26+
#define PPTP_GRE_IS_A(f) ((f)&PPTP_GRE_FLAG_A)
27+
28+
#define PPTP_HEADER_OVERHEAD (2+sizeof(struct pptp_gre_header))
29+
struct pptp_gre_header {
30+
u8 flags;
31+
u8 ver;
32+
__be16 protocol;
33+
__be16 payload_len;
34+
__be16 call_id;
35+
__be32 seq;
36+
__be32 ack;
37+
} __packed;
38+
39+
40+
#endif

include/uapi/linux/if_tunnel.h

+6-1
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,14 @@
2424
#define GRE_SEQ __cpu_to_be16(0x1000)
2525
#define GRE_STRICT __cpu_to_be16(0x0800)
2626
#define GRE_REC __cpu_to_be16(0x0700)
27-
#define GRE_FLAGS __cpu_to_be16(0x00F8)
27+
#define GRE_ACK __cpu_to_be16(0x0080)
28+
#define GRE_FLAGS __cpu_to_be16(0x0078)
2829
#define GRE_VERSION __cpu_to_be16(0x0007)
2930

31+
#define GRE_VERSION_1 __cpu_to_be16(0x0001)
32+
#define GRE_PROTO_PPP __cpu_to_be16(0x880b)
33+
#define GRE_PPTP_KEY_MASK __cpu_to_be32(0xffff)
34+
3035
struct ip_tunnel_parm {
3136
char name[IFNAMSIZ];
3237
int link;

net/core/flow_dissector.c

+79-34
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
#include <linux/if_vlan.h>
77
#include <net/ip.h>
88
#include <net/ipv6.h>
9+
#include <net/gre.h>
10+
#include <net/pptp.h>
911
#include <linux/igmp.h>
1012
#include <linux/icmp.h>
1113
#include <linux/sctp.h>
@@ -338,32 +340,42 @@ bool __skb_flow_dissect(const struct sk_buff *skb,
338340
ip_proto_again:
339341
switch (ip_proto) {
340342
case IPPROTO_GRE: {
341-
struct gre_hdr {
342-
__be16 flags;
343-
__be16 proto;
344-
} *hdr, _hdr;
343+
struct gre_base_hdr *hdr, _hdr;
344+
u16 gre_ver;
345+
int offset = 0;
345346

346347
hdr = __skb_header_pointer(skb, nhoff, sizeof(_hdr), data, hlen, &_hdr);
347348
if (!hdr)
348349
goto out_bad;
349-
/*
350-
* Only look inside GRE if version zero and no
351-
* routing
352-
*/
353-
if (hdr->flags & (GRE_VERSION | GRE_ROUTING))
350+
351+
/* Only look inside GRE without routing */
352+
if (hdr->flags & GRE_ROUTING)
354353
break;
355354

356-
proto = hdr->proto;
357-
nhoff += 4;
355+
/* Only look inside GRE for version 0 and 1 */
356+
gre_ver = ntohs(hdr->flags & GRE_VERSION);
357+
if (gre_ver > 1)
358+
break;
359+
360+
proto = hdr->protocol;
361+
if (gre_ver) {
362+
/* Version1 must be PPTP, and check the flags */
363+
if (!(proto == GRE_PROTO_PPP && (hdr->flags & GRE_KEY)))
364+
break;
365+
}
366+
367+
offset += sizeof(struct gre_base_hdr);
368+
358369
if (hdr->flags & GRE_CSUM)
359-
nhoff += 4;
370+
offset += sizeof(((struct gre_full_hdr *)0)->csum) +
371+
sizeof(((struct gre_full_hdr *)0)->reserved1);
372+
360373
if (hdr->flags & GRE_KEY) {
361374
const __be32 *keyid;
362375
__be32 _keyid;
363376

364-
keyid = __skb_header_pointer(skb, nhoff, sizeof(_keyid),
377+
keyid = __skb_header_pointer(skb, nhoff + offset, sizeof(_keyid),
365378
data, hlen, &_keyid);
366-
367379
if (!keyid)
368380
goto out_bad;
369381

@@ -372,32 +384,65 @@ bool __skb_flow_dissect(const struct sk_buff *skb,
372384
key_keyid = skb_flow_dissector_target(flow_dissector,
373385
FLOW_DISSECTOR_KEY_GRE_KEYID,
374386
target_container);
375-
key_keyid->keyid = *keyid;
387+
if (gre_ver == 0)
388+
key_keyid->keyid = *keyid;
389+
else
390+
key_keyid->keyid = *keyid & GRE_PPTP_KEY_MASK;
376391
}
377-
nhoff += 4;
392+
offset += sizeof(((struct gre_full_hdr *)0)->key);
378393
}
394+
379395
if (hdr->flags & GRE_SEQ)
380-
nhoff += 4;
381-
if (proto == htons(ETH_P_TEB)) {
382-
const struct ethhdr *eth;
383-
struct ethhdr _eth;
384-
385-
eth = __skb_header_pointer(skb, nhoff,
386-
sizeof(_eth),
387-
data, hlen, &_eth);
388-
if (!eth)
396+
offset += sizeof(((struct pptp_gre_header *)0)->seq);
397+
398+
if (gre_ver == 0) {
399+
if (proto == htons(ETH_P_TEB)) {
400+
const struct ethhdr *eth;
401+
struct ethhdr _eth;
402+
403+
eth = __skb_header_pointer(skb, nhoff + offset,
404+
sizeof(_eth),
405+
data, hlen, &_eth);
406+
if (!eth)
407+
goto out_bad;
408+
proto = eth->h_proto;
409+
offset += sizeof(*eth);
410+
411+
/* Cap headers that we access via pointers at the
412+
* end of the Ethernet header as our maximum alignment
413+
* at that point is only 2 bytes.
414+
*/
415+
if (NET_IP_ALIGN)
416+
hlen = (nhoff + offset);
417+
}
418+
} else { /* version 1, must be PPTP */
419+
u8 _ppp_hdr[PPP_HDRLEN];
420+
u8 *ppp_hdr;
421+
422+
if (hdr->flags & GRE_ACK)
423+
offset += sizeof(((struct pptp_gre_header *)0)->ack);
424+
425+
ppp_hdr = skb_header_pointer(skb, nhoff + offset,
426+
sizeof(_ppp_hdr), _ppp_hdr);
427+
if (!ppp_hdr)
389428
goto out_bad;
390-
proto = eth->h_proto;
391-
nhoff += sizeof(*eth);
392-
393-
/* Cap headers that we access via pointers at the
394-
* end of the Ethernet header as our maximum alignment
395-
* at that point is only 2 bytes.
396-
*/
397-
if (NET_IP_ALIGN)
398-
hlen = nhoff;
429+
430+
switch (PPP_PROTOCOL(ppp_hdr)) {
431+
case PPP_IP:
432+
proto = htons(ETH_P_IP);
433+
break;
434+
case PPP_IPV6:
435+
proto = htons(ETH_P_IPV6);
436+
break;
437+
default:
438+
/* Could probably catch some more like MPLS */
439+
break;
440+
}
441+
442+
offset += PPP_HDRLEN;
399443
}
400444

445+
nhoff += offset;
401446
key_control->flags |= FLOW_DIS_ENCAPSULATION;
402447
if (flags & FLOW_DISSECTOR_F_STOP_AT_ENCAP)
403448
goto out_good;

0 commit comments

Comments
 (0)