lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Date:	Thu, 4 Aug 2016 21:11:11 +0800
From:	Feng Gao <gfree.wind@...il.com>
To:	Philp Prindeville <philipp@...fish-solutions.com>
Cc:	fgao@...vckh6395k16k5.yundunddos.com,
	"David S. Miller" <davem@...emloft.net>,
	Stephen Hemminger <stephen@...workplumber.org>,
	Pravin B Shelar <pshelar@...ira.com>,
	Tom Herbert <tom@...bertland.com>,
	Alex Duyck <aduyck@...antis.com>,
	Linux Kernel Network Developers <netdev@...r.kernel.org>
Subject: Re: [PATCH v3 1/1] rps: Inspect PPTP encapsulated by GRE to get flow hash

The link is https://patchwork.ozlabs.org/patch/655695/

Best Regards
Feng

On Thu, Aug 4, 2016 at 3:37 PM, Feng Gao <gfree.wind@...il.com> wrote:
> Hi Tom & Philp,
>
> The v4 patch is sent already.
> Could you help review again please?
>
> Tom,
> I follow your modification.
>
> Philp,
> I define one new struct gre_full_hdr which contains the completed gre
> header, for example, csum, key, and so on.
> And these members are not defined in gre_base_hdr.
> It is only used to offset the sizeof type.
>
> BTW, I find the struct and macro about pptp and gre  are redundant.
> I want to refactor them in other patches.
>
> On Thu, Aug 4, 2016 at 8:33 AM, Philp Prindeville
> <philipp@...fish-solutions.com> wrote:
>> Inline
>>
>>
>>
>> On 08/03/2016 05:58 PM, Feng Gao wrote:
>>>
>>> inline comment.
>>> There are two comments that I am not clear.
>>>
>>> Best Regards
>>> Feng
>>>
>>> On Thu, Aug 4, 2016 at 4:43 AM, Philip Prindeville
>>> <philipp@...fish-solutions.com> wrote:
>>>>
>>>> Inline…
>>>>
>>>>> On Aug 3, 2016, at 8:52 AM, fgao@...vckh6395k16k5.yundunddos.com wrote:
>>>>>
>>>>> From: Gao Feng <fgao@...ai8.com>
>>>>>
>>>>> 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 <fgao@...ai8.com>
>>>>> ---
>>>>> v3: 1) Move struct pptp_gre_header defination into new file pptp.h
>>>>>      2) Use sizeof GRE and PPTP type instead of literal value;
>>>>>      3) Remove strict flag check for PPTP to robust;
>>>>>      4) Consolidate the codes again;
>>>>> v2: Update according to Tom and Philp's advice.
>>>>>      1) Consolidate the codes with GRE version 0 path;
>>>>>      2) Use PPP_PROTOCOL to get ppp protol;
>>>>>      3) Set the FLOW_DIS_ENCAPSULATION flag;
>>>>> v1: Intial patch
>>>>>
>>>>> drivers/net/ppp/pptp.c         |  36 +----------
>>>>> include/net/pptp.h             |  40 ++++++++++++
>>>>> include/uapi/linux/if_tunnel.h |   7 +-
>>>>> net/core/flow_dissector.c      | 141
>>>>> +++++++++++++++++++++++++----------------
>>>>> 4 files changed, 134 insertions(+), 90 deletions(-)
>>>>> create mode 100644 include/net/pptp.h
>>>>>
>>>>> diff --git a/drivers/net/ppp/pptp.c b/drivers/net/ppp/pptp.c
>>>>> index ae0905e..3e68dbc 100644
>>>>> --- a/drivers/net/ppp/pptp.c
>>>>> +++ b/drivers/net/ppp/pptp.c
>>>>> @@ -37,6 +37,7 @@
>>>>> #include <net/icmp.h>
>>>>> #include <net/route.h>
>>>>> #include <net/gre.h>
>>>>> +#include <net/pptp.h>
>>>>>
>>>>> #include <linux/uaccess.h>
>>>>>
>>>>> @@ -53,41 +54,6 @@ static struct proto pptp_sk_proto __read_mostly;
>>>>> static const struct ppp_channel_ops pptp_chan_ops;
>>>>> static const struct proto_ops pptp_ops;
>>>>>
>>>>> -#define PPP_LCP_ECHOREQ 0x09
>>>>> -#define PPP_LCP_ECHOREP 0x0A
>>>>> -#define SC_RCV_BITS  (SC_RCV_B7_1|SC_RCV_B7_0|SC_RCV_ODDP|SC_RCV_EVNP)
>>>>> -
>>>>> -#define MISSING_WINDOW 20
>>>>> -#define WRAPPED(curseq, lastseq)\
>>>>> -     ((((curseq) & 0xffffff00) == 0) &&\
>>>>> -     (((lastseq) & 0xffffff00) == 0xffffff00))
>>>>> -
>>>>> -#define PPTP_GRE_PROTO  0x880B
>>>>> -#define PPTP_GRE_VER    0x1
>>>>> -
>>>>> -#define PPTP_GRE_FLAG_C      0x80
>>>>> -#define PPTP_GRE_FLAG_R      0x40
>>>>> -#define PPTP_GRE_FLAG_K      0x20
>>>>> -#define PPTP_GRE_FLAG_S      0x10
>>>>> -#define PPTP_GRE_FLAG_A      0x80
>>>>> -
>>>>> -#define PPTP_GRE_IS_C(f) ((f)&PPTP_GRE_FLAG_C)
>>>>> -#define PPTP_GRE_IS_R(f) ((f)&PPTP_GRE_FLAG_R)
>>>>> -#define PPTP_GRE_IS_K(f) ((f)&PPTP_GRE_FLAG_K)
>>>>> -#define PPTP_GRE_IS_S(f) ((f)&PPTP_GRE_FLAG_S)
>>>>> -#define PPTP_GRE_IS_A(f) ((f)&PPTP_GRE_FLAG_A)
>>>>> -
>>>>> -#define PPTP_HEADER_OVERHEAD (2+sizeof(struct pptp_gre_header))
>>>>> -struct pptp_gre_header {
>>>>> -     u8  flags;
>>>>> -     u8  ver;
>>>>> -     __be16 protocol;
>>>>> -     __be16 payload_len;
>>>>> -     __be16 call_id;
>>>>> -     __be32 seq;
>>>>> -     __be32 ack;
>>>>> -} __packed;
>>>>> -
>>>>> static struct pppox_sock *lookup_chan(u16 call_id, __be32 s_addr)
>>>>> {
>>>>>        struct pppox_sock *sock;
>>>>> diff --git a/include/net/pptp.h b/include/net/pptp.h
>>>>> new file mode 100644
>>>>> index 0000000..301d3e2
>>>>> --- /dev/null
>>>>> +++ b/include/net/pptp.h
>>>>> @@ -0,0 +1,40 @@
>>>>> +#ifndef _NET_PPTP_H
>>>>> +#define _NET_PPTP_H
>>>>> +
>>>>> +#define PPP_LCP_ECHOREQ 0x09
>>>>> +#define PPP_LCP_ECHOREP 0x0A
>>>>> +#define SC_RCV_BITS
>>>>> (SC_RCV_B7_1|SC_RCV_B7_0|SC_RCV_ODDP|SC_RCV_EVNP)
>>>>> +
>>>>> +#define MISSING_WINDOW 20
>>>>> +#define WRAPPED(curseq, lastseq)\
>>>>> +     ((((curseq) & 0xffffff00) == 0) &&\
>>>>> +     (((lastseq) & 0xffffff00) == 0xffffff00))
>>>>> +
>>>>> +#define PPTP_GRE_PROTO  0x880B
>>>>> +#define PPTP_GRE_VER    0x1
>>>>
>>>> What about macros for accessing the lower 3 bits of the version?
>>>
>>> There is already one macro "GRE_VERSION" as the mask to get version.
>>
>>
>> Yup, sorry.  Missed that.
>>
>>
>>
>>>
>>>>
>>>>> +
>>>>> +#define PPTP_GRE_FLAG_C 0x80
>>>>> +#define PPTP_GRE_FLAG_R 0x40
>>>>> +#define PPTP_GRE_FLAG_K 0x20
>>>>> +#define PPTP_GRE_FLAG_S 0x10
>>>>> +#define PPTP_GRE_FLAG_A 0x80
>>>>> +
>>>>> +#define PPTP_GRE_IS_C(f) ((f)&PPTP_GRE_FLAG_C)
>>>>> +#define PPTP_GRE_IS_R(f) ((f)&PPTP_GRE_FLAG_R)
>>>>> +#define PPTP_GRE_IS_K(f) ((f)&PPTP_GRE_FLAG_K)
>>>>> +#define PPTP_GRE_IS_S(f) ((f)&PPTP_GRE_FLAG_S)
>>>>> +#define PPTP_GRE_IS_A(f) ((f)&PPTP_GRE_FLAG_A)
>>>>> +
>>>>> +#define PPTP_HEADER_OVERHEAD (2+sizeof(struct pptp_gre_header))
>>>>> +struct pptp_gre_header {
>>>>> +     u8  flags;
>>>>> +     u8  ver;
>>>>> +     __be16 protocol;
>>>>> +     __be16 payload_len;
>>>>> +     __be16 call_id;
>>>>> +     __be32 seq;
>>>>> +     __be32 ack;
>>>>> +} __packed;
>>>>
>>>>
>>>> What about a definition of a V0 (RFC-1701) packet?  We’re handling both,
>>>> so it makes sense to define both.
>>>
>>> I don't get you. The struct "gre_base_hdr" is defined in gre.h. Do you
>>> mean define them in same file ?
>>
>>
>> Sorry, I phrased that poorly.  Yes, they're both defined (in different
>> headers)... but when you're parsing the v0 header you're not referencing the
>> gre_base_hdr members to calculate your offsets.
>>
>> -Philip
>>
>>
>>
>>>
>>>>
>>>>> +
>>>>> +
>>>>> +#endif
>>>>> diff --git a/include/uapi/linux/if_tunnel.h
>>>>> b/include/uapi/linux/if_tunnel.h
>>>>> index 1046f55..7d889db 100644
>>>>> --- a/include/uapi/linux/if_tunnel.h
>>>>> +++ b/include/uapi/linux/if_tunnel.h
>>>>> @@ -24,9 +24,14 @@
>>>>> #define GRE_SEQ               __cpu_to_be16(0x1000)
>>>>> #define GRE_STRICT    __cpu_to_be16(0x0800)
>>>>> #define GRE_REC               __cpu_to_be16(0x0700)
>>>>> -#define GRE_FLAGS    __cpu_to_be16(0x00F8)
>>>>> +#define GRE_ACK              __cpu_to_be16(0x0080)
>>>>> +#define GRE_FLAGS    __cpu_to_be16(0x0078)
>>>>> #define GRE_VERSION   __cpu_to_be16(0x0007)
>>>>>
>>>>> +#define GRE_VERSION_1        __cpu_to_be16(0x0001)
>>>>> +#define GRE_PROTO_PPP        __cpu_to_be16(0x880b)
>>>>> +
>>>>> +
>>>>> struct ip_tunnel_parm {
>>>>>        char                    name[IFNAMSIZ];
>>>>>        int                     link;
>>>>> diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c
>>>>> index 61ad43f..52b7c3c 100644
>>>>> --- a/net/core/flow_dissector.c
>>>>> +++ b/net/core/flow_dissector.c
>>>>> @@ -6,6 +6,8 @@
>>>>> #include <linux/if_vlan.h>
>>>>> #include <net/ip.h>
>>>>> #include <net/ipv6.h>
>>>>> +#include <net/gre.h>
>>>>> +#include <net/pptp.h>
>>>>> #include <linux/igmp.h>
>>>>> #include <linux/icmp.h>
>>>>> #include <linux/sctp.h>
>>>>> @@ -338,71 +340,102 @@ mpls:
>>>>> ip_proto_again:
>>>>>        switch (ip_proto) {
>>>>>        case IPPROTO_GRE: {
>>>>> -             struct gre_hdr {
>>>>> -                     __be16 flags;
>>>>> -                     __be16 proto;
>>>>> -             } *hdr, _hdr;
>>>>> +             struct gre_base_hdr *hdr, _hdr;
>>>>>
>>>>>                hdr = __skb_header_pointer(skb, nhoff, sizeof(_hdr),
>>>>> data, hlen, &_hdr);
>>>>>                if (!hdr)
>>>>>                        goto out_bad;
>>>>> -             /*
>>>>> -              * Only look inside GRE if version zero and no
>>>>> -              * routing
>>>>> -              */
>>>>> -             if (hdr->flags & (GRE_VERSION | GRE_ROUTING))
>>>>> -                     break;
>>>>>
>>>>> -             proto = hdr->proto;
>>>>> -             nhoff += 4;
>>>>> -             if (hdr->flags & GRE_CSUM)
>>>>> -                     nhoff += 4;
>>>>> -             if (hdr->flags & GRE_KEY) {
>>>>> -                     const __be32 *keyid;
>>>>> -                     __be32 _keyid;
>>>>> +             /* Only look inside GRE without routing */
>>>>> +             if (!(hdr->flags & GRE_ROUTING)) {
>>>>> +                     int offset = 0;
>>>>>
>>>>> -                     keyid = __skb_header_pointer(skb, nhoff,
>>>>> sizeof(_keyid),
>>>>> -                                                  data, hlen, &_keyid);
>>>>> +                     proto = hdr->protocol;
>>>>>
>>>>> -                     if (!keyid)
>>>>> -                             goto out_bad;
>>>>> +                     if (hdr->flags & GRE_VERSION) {
>>>>> +                             /* Maybe PPTP in GRE */
>>>>> +                             if (!(proto == GRE_PROTO_PPP &&
>>>>> (hdr->flags & GRE_KEY) &&
>>>>> +                                  (hdr->flags & GRE_VERSION) ==
>>>>> GRE_VERSION_1))
>>>>> +                                     break;
>>>>> +                     }
>>>>>
>>>>> -                     if (dissector_uses_key(flow_dissector,
>>>>> -
>>>>> FLOW_DISSECTOR_KEY_GRE_KEYID)) {
>>>>> -                             key_keyid =
>>>>> skb_flow_dissector_target(flow_dissector,
>>>>> -
>>>>> FLOW_DISSECTOR_KEY_GRE_KEYID,
>>>>> -
>>>>> target_container);
>>>>> -                             key_keyid->keyid = *keyid;
>>>>> +                     offset += sizeof(struct gre_base_hdr);
>>>>> +
>>>>> +                     if (hdr->flags & GRE_CSUM)
>>>>> +                             offset += sizeof(__be32);
>>>>
>>>>
>>>> This doesn’t tell me as much as taking the sizeof() of the particular
>>>> field (by name) in the packet that you’re skipping.  Best way to do this is
>>>> naming the field in the structure…
>>>>
>>>>
>>>>> +
>>>>> +                     if (hdr->flags & GRE_KEY) {
>>>>> +                             const __be32 *keyid;
>>>>> +                             __be32 _keyid;
>>>>> +
>>>>> +                             keyid = __skb_header_pointer(skb, nhoff +
>>>>> offset, sizeof(_keyid),
>>>>> +                                                          data, hlen,
>>>>> &_keyid);
>>>>> +
>>>>> +                             if (!keyid)
>>>>> +                                     goto out_bad;
>>>>> +
>>>>> +                             if (dissector_uses_key(flow_dissector,
>>>>> +
>>>>> FLOW_DISSECTOR_KEY_GRE_KEYID)) {
>>>>> +                                     key_keyid =
>>>>> skb_flow_dissector_target(flow_dissector,
>>>>> +
>>>>> FLOW_DISSECTOR_KEY_GRE_KEYID,
>>>>> +
>>>>> target_container);
>>>>> +                                     key_keyid->keyid = *keyid;
>>>>> +                             }
>>>>> +                             offset += sizeof(_keyid);
>>>>
>>>>
>>>> Same issue here.
>>>>
>>>>
>>>>>                        }
>>>>> -                     nhoff += 4;
>>>>> -             }
>>>>> -             if (hdr->flags & GRE_SEQ)
>>>>> -                     nhoff += 4;
>>>>> -             if (proto == htons(ETH_P_TEB)) {
>>>>> -                     const struct ethhdr *eth;
>>>>> -                     struct ethhdr _eth;
>>>>> -
>>>>> -                     eth = __skb_header_pointer(skb, nhoff,
>>>>> -                                                sizeof(_eth),
>>>>> -                                                data, hlen, &_eth);
>>>>> -                     if (!eth)
>>>>> -                             goto out_bad;
>>>>> -                     proto = eth->h_proto;
>>>>> -                     nhoff += sizeof(*eth);
>>>>> -
>>>>> -                     /* Cap headers that we access via pointers at the
>>>>> -                      * end of the Ethernet header as our maximum
>>>>> alignment
>>>>> -                      * at that point is only 2 bytes.
>>>>> -                      */
>>>>> -                     if (NET_IP_ALIGN)
>>>>> -                             hlen = nhoff;
>>>>> -             }
>>>>>
>>>>> -             key_control->flags |= FLOW_DIS_ENCAPSULATION;
>>>>> -             if (flags & FLOW_DISSECTOR_F_STOP_AT_ENCAP)
>>>>> -                     goto out_good;
>>>>> +                     if (hdr->flags & GRE_SEQ)
>>>>> +                             offset += sizeof(((struct pptp_gre_header
>>>>> *)0)->seq);
>>>>> +
>>>>> +                     if (hdr->flags & GRE_ACK)
>>>>> +                             offset += sizeof(((struct pptp_gre_header
>>>>> *)0)->ack);
>>>>
>>>>
>>>> Much better.
>>>>
>>>> -Philip
>>>>
>>>>
>>>>> +
>>>>> +                     if (proto == GRE_PROTO_PPP) {
>>>>> +                             u8 _ppp_hdr[PPP_HDRLEN];
>>>>> +                             u8 *ppp_hdr;
>>>>> +
>>>>> +                             ppp_hdr = skb_header_pointer(skb, nhoff +
>>>>> offset,
>>>>> +
>>>>> sizeof(_ppp_hdr), _ppp_hdr);
>>>>> +                             if (!ppp_hdr)
>>>>> +                                     goto out_bad;
>>>>> +
>>>>> +                             proto = PPP_PROTOCOL(ppp_hdr);
>>>>> +                             if (proto == PPP_IP)
>>>>> +                                     proto = htons(ETH_P_IP);
>>>>> +                             else if (proto == PPP_IPV6)
>>>>> +                                     proto = htons(ETH_P_IPV6);
>>>>> +                             else
>>>>> +                                     break;
>>>>> +
>>>>> +                             offset += PPP_HDRLEN;
>>>>> +                     } else if (proto == htons(ETH_P_TEB)) {
>>>>> +                             const struct ethhdr *eth;
>>>>> +                             struct ethhdr _eth;
>>>>> +
>>>>> +                             eth = __skb_header_pointer(skb, nhoff +
>>>>> offset,
>>>>> +                                                        sizeof(_eth),
>>>>> +                                                        data, hlen,
>>>>> &_eth);
>>>>> +                             if (!eth)
>>>>> +                                     goto out_bad;
>>>>> +                             proto = eth->h_proto;
>>>>> +                             offset += sizeof(*eth);
>>>>> +
>>>>> +                             /* Cap headers that we access via pointers
>>>>> at the
>>>>> +                              * end of the Ethernet header as our
>>>>> maximum alignment
>>>>> +                              * at that point is only 2 bytes.
>>>>> +                              */
>>>>> +                             if (NET_IP_ALIGN)
>>>>> +                                     hlen = (nhoff + offset);
>>>>> +                     }
>>>>>
>>>>> -             goto again;
>>>>> +                     nhoff += offset;
>>>>> +                     key_control->flags |= FLOW_DIS_ENCAPSULATION;
>>>>> +                     if (flags & FLOW_DISSECTOR_F_STOP_AT_ENCAP)
>>>>> +                             goto out_good;
>>>>> +
>>>>> +                     goto again;
>>>>> +             }
>>>>> +             break;
>>>>>        }
>>>>>        case NEXTHDR_HOP:
>>>>>        case NEXTHDR_ROUTING:
>>>>> --
>>>>> 1.9.1
>>>>>
>>

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ