From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-8.8 required=3.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH,MAILING_LIST_MULTI,SIGNED_OFF_BY, SPF_PASS,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 8D046C43381 for ; Wed, 20 Mar 2019 14:50:00 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 4ACAC2146E for ; Wed, 20 Mar 2019 14:50:00 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="M8VijONY" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728160AbfCTOt7 (ORCPT ); Wed, 20 Mar 2019 10:49:59 -0400 Received: from mail-qk1-f195.google.com ([209.85.222.195]:36134 "EHLO mail-qk1-f195.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728122AbfCTOt6 (ORCPT ); Wed, 20 Mar 2019 10:49:58 -0400 Received: by mail-qk1-f195.google.com with SMTP id k130so14276730qke.3 for ; Wed, 20 Mar 2019 07:49:56 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=EVkQH9TIoV+1q3Epsvck3/7871VvUAEPdctkmkJgc84=; b=M8VijONYGads1yfAcfvzTUanBMEfL8v+c/mZRz91CCXmfLxCax6hkrXNwYKuMhsNlp 0l5RTdbvy0iW+FGS9Us2Z0IwM1Fvrf/dqTUvXGfjQOMHSScHjWl4Aj1pc72cwO1GwLRK 2ToQxxFd/60bP0Q/bhYiKEcJMmKIAoFjZhbuzPbmDubumn+Pe8wXeAlFgDMMQ43rwhJ5 r4uQvVm2b4ljdCzRcsoFEI1W4Pl6cx3BZBYbqS0Say7+EtZgvkitMPXpDhNt+ARqr7G+ vXtUbSt4IJrmyzRpwxyo2b8FCA0x2lCrwB0+jD6GmXqmorTaqppX8GJ6gb77+ULZNCM2 daAA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=EVkQH9TIoV+1q3Epsvck3/7871VvUAEPdctkmkJgc84=; b=TWlqxSJKYU8V/AMkMYCWj1AQmSqWE/heQNBPrxgZX1IIIEqjHMyakjVlHdAAOFJ6s1 j6Xz1EpJUDDLwGGxTATnC/xlNe9cKz/KVTyP0xVbJGAeRLC6mTjzrfip9HxJzF3lD4rf 3Sgs77sAyjKKErWRwckgcya3pdP7BZxwXO9Spfb6aMxWuQSN9NDUfEvuNGb5nS+Y8S/l obwW8nffTqiStONzjJrmvAHC0r4lLG6aQhv8E9mumRxpM0svTq0Kkj5dYaeVXTG2xkqo v3KMbB4Bs3GplhzrrlpZ7A3x7mKoQ7NqXy05qtb5aKpS3XMtDjo2Pmr6l9FJ5ge9baOq kiJQ== X-Gm-Message-State: APjAAAWtwuPDkH9esCR34BBFMYJEB3+2ukx/uErIzvkrO+GSEIbeyOFO y04AUbNvG7TdIBn4GLhfwry5EGmj X-Google-Smtp-Source: APXvYqyYpU2MO9WX8QYv/D26x5O/jsqWrDzb59ReNSMU2c9mD430GgTMjLd2jcjMozXmT01qkz3bng== X-Received: by 2002:ae9:f71a:: with SMTP id s26mr6779453qkg.299.1553093395867; Wed, 20 Mar 2019 07:49:55 -0700 (PDT) Received: from willemb1.nyc.corp.google.com ([2620:0:1003:315:3fa1:a34c:1128:1d39]) by smtp.gmail.com with ESMTPSA id x201sm1142257qkb.92.2019.03.20.07.49.54 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 20 Mar 2019 07:49:54 -0700 (PDT) From: Willem de Bruijn To: netdev@vger.kernel.org Cc: ast@kernel.org, daniel@iogearbox.net, sdf@google.com, posk@google.com, Willem de Bruijn Subject: [PATCH bpf-next 05/13] selftests/bpf: extend bpf tunnel test with gre Date: Wed, 20 Mar 2019 10:49:36 -0400 Message-Id: <20190320144944.147862-6-willemdebruijn.kernel@gmail.com> X-Mailer: git-send-email 2.21.0.225.g810b269d1ac-goog In-Reply-To: <20190320144944.147862-1-willemdebruijn.kernel@gmail.com> References: <20190320144944.147862-1-willemdebruijn.kernel@gmail.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org From: Willem de Bruijn GRE is a commonly used protocol. Add GRE cases for both IPv4 and IPv6. It also inserts different sized headers, which can expose some unexpected edge cases. Signed-off-by: Willem de Bruijn --- .../selftests/bpf/progs/test_tc_tunnel.c | 148 +++++++++++++----- tools/testing/selftests/bpf/test_tc_tunnel.sh | 21 ++- 2 files changed, 123 insertions(+), 46 deletions(-) diff --git a/tools/testing/selftests/bpf/progs/test_tc_tunnel.c b/tools/testing/selftests/bpf/progs/test_tc_tunnel.c index 591f540ce513d..900c5653105fe 100644 --- a/tools/testing/selftests/bpf/progs/test_tc_tunnel.c +++ b/tools/testing/selftests/bpf/progs/test_tc_tunnel.c @@ -2,6 +2,9 @@ /* In-place tunneling */ +#include +#include + #include #include #include @@ -17,6 +20,18 @@ static const int cfg_port = 8000; +struct grev4hdr { + struct iphdr ip; + __be16 flags; + __be16 protocol; +} __attribute__((packed)); + +struct grev6hdr { + struct ipv6hdr ip; + __be16 flags; + __be16 protocol; +} __attribute__((packed)); + static __always_inline void set_ipv4_csum(struct iphdr *iph) { __u16 *iph16 = (__u16 *)iph; @@ -32,10 +47,12 @@ static __always_inline void set_ipv4_csum(struct iphdr *iph) iph->check = ~((csum & 0xffff) + (csum >> 16)); } -static int encap_ipv4(struct __sk_buff *skb) +static __always_inline int encap_ipv4(struct __sk_buff *skb, bool with_gre) { - struct iphdr iph_outer, iph_inner; + struct grev4hdr h_outer; + struct iphdr iph_inner; struct tcphdr tcph; + int olen; if (bpf_skb_load_bytes(skb, ETH_HLEN, &iph_inner, sizeof(iph_inner)) < 0) @@ -52,24 +69,33 @@ static int encap_ipv4(struct __sk_buff *skb) if (tcph.dest != __bpf_constant_htons(cfg_port)) return TC_ACT_OK; + olen = with_gre ? sizeof(h_outer) : sizeof(h_outer.ip); + /* add room between mac and network header */ - if (bpf_skb_adjust_room(skb, sizeof(iph_outer), BPF_ADJ_ROOM_NET, 0)) + if (bpf_skb_adjust_room(skb, olen, BPF_ADJ_ROOM_NET, 0)) return TC_ACT_SHOT; /* prepare new outer network header */ - iph_outer = iph_inner; - iph_outer.protocol = IPPROTO_IPIP; - iph_outer.tot_len = bpf_htons(sizeof(iph_outer) + - bpf_htons(iph_outer.tot_len)); - set_ipv4_csum(&iph_outer); + h_outer.ip = iph_inner; + h_outer.ip.tot_len = bpf_htons(olen + + bpf_htons(h_outer.ip.tot_len)); + if (with_gre) { + h_outer.ip.protocol = IPPROTO_GRE; + h_outer.protocol = bpf_htons(ETH_P_IP); + h_outer.flags = 0; + } else { + h_outer.ip.protocol = IPPROTO_IPIP; + } + + set_ipv4_csum((void *)&h_outer.ip); /* store new outer network header */ - if (bpf_skb_store_bytes(skb, ETH_HLEN, &iph_outer, sizeof(iph_outer), + if (bpf_skb_store_bytes(skb, ETH_HLEN, &h_outer, olen, BPF_F_INVALIDATE_HASH) < 0) return TC_ACT_SHOT; /* bpf_skb_adjust_room has moved header to start of room: restore */ - if (bpf_skb_store_bytes(skb, ETH_HLEN + sizeof(iph_outer), + if (bpf_skb_store_bytes(skb, ETH_HLEN + olen, &iph_inner, sizeof(iph_inner), BPF_F_INVALIDATE_HASH) < 0) return TC_ACT_SHOT; @@ -77,10 +103,12 @@ static int encap_ipv4(struct __sk_buff *skb) return TC_ACT_OK; } -static int encap_ipv6(struct __sk_buff *skb) +static __always_inline int encap_ipv6(struct __sk_buff *skb, bool with_gre) { - struct ipv6hdr iph_outer, iph_inner; + struct ipv6hdr iph_inner; + struct grev6hdr h_outer; struct tcphdr tcph; + int olen; if (bpf_skb_load_bytes(skb, ETH_HLEN, &iph_inner, sizeof(iph_inner)) < 0) @@ -94,23 +122,31 @@ static int encap_ipv6(struct __sk_buff *skb) if (tcph.dest != __bpf_constant_htons(cfg_port)) return TC_ACT_OK; + olen = with_gre ? sizeof(h_outer) : sizeof(h_outer.ip); + /* add room between mac and network header */ - if (bpf_skb_adjust_room(skb, sizeof(iph_outer), BPF_ADJ_ROOM_NET, 0)) + if (bpf_skb_adjust_room(skb, olen, BPF_ADJ_ROOM_NET, 0)) return TC_ACT_SHOT; /* prepare new outer network header */ - iph_outer = iph_inner; - iph_outer.nexthdr = IPPROTO_IPV6; - iph_outer.payload_len = bpf_htons(sizeof(iph_outer) + - bpf_ntohs(iph_outer.payload_len)); + h_outer.ip = iph_inner; + h_outer.ip.payload_len = bpf_htons(olen + + bpf_ntohs(h_outer.ip.payload_len)); + if (with_gre) { + h_outer.ip.nexthdr = IPPROTO_GRE; + h_outer.protocol = bpf_htons(ETH_P_IPV6); + h_outer.flags = 0; + } else { + h_outer.ip.nexthdr = IPPROTO_IPV6; + } /* store new outer network header */ - if (bpf_skb_store_bytes(skb, ETH_HLEN, &iph_outer, sizeof(iph_outer), + if (bpf_skb_store_bytes(skb, ETH_HLEN, &h_outer, olen, BPF_F_INVALIDATE_HASH) < 0) return TC_ACT_SHOT; /* bpf_skb_adjust_room has moved header to start of room: restore */ - if (bpf_skb_store_bytes(skb, ETH_HLEN + sizeof(iph_outer), + if (bpf_skb_store_bytes(skb, ETH_HLEN + olen, &iph_inner, sizeof(iph_inner), BPF_F_INVALIDATE_HASH) < 0) return TC_ACT_SHOT; @@ -118,28 +154,63 @@ static int encap_ipv6(struct __sk_buff *skb) return TC_ACT_OK; } -SEC("encap") -int encap_f(struct __sk_buff *skb) +SEC("encap_ipip") +int __encap_ipip(struct __sk_buff *skb) { - switch (skb->protocol) { - case __bpf_constant_htons(ETH_P_IP): - return encap_ipv4(skb); - case __bpf_constant_htons(ETH_P_IPV6): - return encap_ipv6(skb); - default: - /* does not match, ignore */ + if (skb->protocol == __bpf_constant_htons(ETH_P_IP)) + return encap_ipv4(skb, false); + else return TC_ACT_OK; - } } -static int decap_internal(struct __sk_buff *skb, int off, int len) +SEC("encap_gre") +int __encap_gre(struct __sk_buff *skb) { - char buf[sizeof(struct ipv6hdr)]; + if (skb->protocol == __bpf_constant_htons(ETH_P_IP)) + return encap_ipv4(skb, true); + else + return TC_ACT_OK; +} - if (bpf_skb_load_bytes(skb, off + len, &buf, len) < 0) +SEC("encap_ip6tnl") +int __encap_ip6tnl(struct __sk_buff *skb) +{ + if (skb->protocol == __bpf_constant_htons(ETH_P_IPV6)) + return encap_ipv6(skb, false); + else + return TC_ACT_OK; +} + +SEC("encap_ip6gre") +int __encap_ip6gre(struct __sk_buff *skb) +{ + if (skb->protocol == __bpf_constant_htons(ETH_P_IPV6)) + return encap_ipv6(skb, true); + else return TC_ACT_OK; +} - if (bpf_skb_adjust_room(skb, -len, BPF_ADJ_ROOM_NET, 0)) +static int decap_internal(struct __sk_buff *skb, int off, int len, char proto) +{ + char buf[sizeof(struct grev6hdr)]; + int olen; + + switch (proto) { + case IPPROTO_IPIP: + case IPPROTO_IPV6: + olen = len; + break; + case IPPROTO_GRE: + olen = len + 4 /* gre hdr */; + break; + default: + return TC_ACT_OK; + } + + if (bpf_skb_load_bytes(skb, off + olen, &buf, olen) < 0) + return TC_ACT_OK; + + if (bpf_skb_adjust_room(skb, -olen, BPF_ADJ_ROOM_NET, 0)) return TC_ACT_SHOT; /* bpf_skb_adjust_room has moved outer over inner header: restore */ @@ -157,10 +228,11 @@ static int decap_ipv4(struct __sk_buff *skb) sizeof(iph_outer)) < 0) return TC_ACT_OK; - if (iph_outer.ihl != 5 || iph_outer.protocol != IPPROTO_IPIP) + if (iph_outer.ihl != 5) return TC_ACT_OK; - return decap_internal(skb, ETH_HLEN, sizeof(iph_outer)); + return decap_internal(skb, ETH_HLEN, sizeof(iph_outer), + iph_outer.protocol); } static int decap_ipv6(struct __sk_buff *skb) @@ -171,10 +243,8 @@ static int decap_ipv6(struct __sk_buff *skb) sizeof(iph_outer)) < 0) return TC_ACT_OK; - if (iph_outer.nexthdr != IPPROTO_IPV6) - return TC_ACT_OK; - - return decap_internal(skb, ETH_HLEN, sizeof(iph_outer)); + return decap_internal(skb, ETH_HLEN, sizeof(iph_outer), + iph_outer.nexthdr); } SEC("decap") diff --git a/tools/testing/selftests/bpf/test_tc_tunnel.sh b/tools/testing/selftests/bpf/test_tc_tunnel.sh index 7b1758f3006b0..c78922048610b 100755 --- a/tools/testing/selftests/bpf/test_tc_tunnel.sh +++ b/tools/testing/selftests/bpf/test_tc_tunnel.sh @@ -54,30 +54,36 @@ set -e # no arguments: automated test, run all if [[ "$#" -eq "0" ]]; then echo "ipip" - $0 ipv4 + $0 ipv4 ipip echo "ip6ip6" - $0 ipv6 + $0 ipv6 ip6tnl + + echo "ip gre" + $0 ipv4 gre + + echo "ip6 gre" + $0 ipv6 ip6gre echo "OK. All tests passed" exit 0 fi -if [[ "$#" -ne "1" ]]; then +if [[ "$#" -ne "2" ]]; then echo "Usage: $0" - echo " or: $0 " + echo " or: $0 " exit 1 fi case "$1" in "ipv4") - readonly tuntype=ipip + readonly tuntype=$2 readonly addr1="${ns1_v4}" readonly addr2="${ns2_v4}" readonly netcat_opt=-4 ;; "ipv6") - readonly tuntype=ip6tnl + readonly tuntype=$2 readonly addr1="${ns1_v6}" readonly addr2="${ns2_v6}" readonly netcat_opt=-6 @@ -103,7 +109,8 @@ client_connect # client can no longer connect ip netns exec "${ns1}" tc qdisc add dev veth1 clsact ip netns exec "${ns1}" tc filter add dev veth1 egress \ - bpf direct-action object-file ./test_tc_tunnel.o section encap + bpf direct-action object-file ./test_tc_tunnel.o \ + section "encap_${tuntype}" echo "test bpf encap without decap (expect failure)" server_listen ! client_connect -- 2.21.0.225.g810b269d1ac-goog