From patchwork Fri Mar 22 23:40:18 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Peter Oskolkov X-Patchwork-Id: 1061763 X-Patchwork-Delegate: bpf@iogearbox.net Return-Path: X-Original-To: patchwork-incoming-netdev@ozlabs.org Delivered-To: patchwork-incoming-netdev@ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netdev-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=google.com header.i=@google.com header.b="dnwIGhSp"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 44R0X56yl8z9sS8 for ; Sat, 23 Mar 2019 10:40:37 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726589AbfCVXk1 (ORCPT ); Fri, 22 Mar 2019 19:40:27 -0400 Received: from mail-vs1-f73.google.com ([209.85.217.73]:50837 "EHLO mail-vs1-f73.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726910AbfCVXk0 (ORCPT ); Fri, 22 Mar 2019 19:40:26 -0400 Received: by mail-vs1-f73.google.com with SMTP id b68so1112299vsb.17 for ; Fri, 22 Mar 2019 16:40:26 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:message-id:mime-version:subject:from:to:cc; bh=PZra7rmKQL+k4tdBtTMN82t+lKMYWKZNR8QUSSzsFso=; b=dnwIGhSpTlC2V/dhInqMZRd7cSQk3DrxC3xYQYmpoh5ifqiTopTrPzDsrL6CKTToLf XXVkPUoGPZwMqeouxa0aAudS4dQj2hjRe9I1KICzwxSN5xcXcbwIzbjmiDhOw3MMzBkO GjmQrDqiNpMERd65Owihaw0QYtYk99A73qcoiC9yVYTJ8AZaqGd3LTEaovQtT66u7Vny pBTJdOpFn89S4dGy6DbAr5rlJBChADypq9btLXwkV+EjRnMTjHmcuG3t1AtOwQnx9N17 twn5WbDwZB8TuVQdXdtkBbziOY0VRk+O4ZUc3XlEdwK8Uo7jyBgcMfXeCO9WZ2Ec8pVF VTMA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:message-id:mime-version:subject:from:to:cc; bh=PZra7rmKQL+k4tdBtTMN82t+lKMYWKZNR8QUSSzsFso=; b=ceCUcl+BvLZQEmq3vww0PLIKx8m6LQZixxbXOxTkJG/FcuvXLGlDaMdo7SDGCsYgRH rsNHkhiXZFUullZvvbKv4J0vrGU/b60OwQaJdiTMI15ZxZGScpT9ujRdlBedrfFf8cre htdAZsAXPbfJ9tuW35o7sZn/PSkcyxZJtmVaV9kuRGExZNT+R/nnNJg0VYB9B+vSkDq7 Q8as4o3sxLiiP48AH3YzRm3oazaBiLQkUBZ4Mooxs8gD8QJYgj3CPnOSHkOZupGEai7j Sh82EXycVBYtv7i20PcqzkHKzviQizsqXqXumjsL93bD0CEV/fe5s30NlHxnVMGf1slx eUhw== X-Gm-Message-State: APjAAAUIqB2aSeXYQ51xSdZ3qJ1/SMTKHY7bbqnE8UWi5IscdLuUExbZ ja6+kKxazFPmfEJP5QeKRpUlvENr X-Google-Smtp-Source: APXvYqwvsW3+pDre+A2MDpCD7wUjic8TGXHtsMaApbA6SsKo+lX0RYwU8BzMWW4QLJCSMbIuf8I34vGl X-Received: by 2002:ab0:2653:: with SMTP id q19mr6144254uao.76.1553298026018; Fri, 22 Mar 2019 16:40:26 -0700 (PDT) Date: Fri, 22 Mar 2019 16:40:18 -0700 Message-Id: <20190322234019.229181-1-posk@google.com> Mime-Version: 1.0 X-Mailer: git-send-email 2.21.0.392.gf8f6787159e-goog Subject: [PATCH bpf-next 1/2] bpf: make bpf_skb_ecn_set_ce callable from BPF_PROG_TYPE_SCHED_ACT From: Peter Oskolkov To: Alexei Starovoitov , Daniel Borkmann , netdev@vger.kernel.org, bpf@vger.kernel.org Cc: Peter Oskolkov , Peter Oskolkov Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org This helper is useful if a bpf tc filter sets skb->tstamp. Signed-off-by: Peter Oskolkov --- net/core/filter.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/core/filter.c b/net/core/filter.c index c1d19b074d6c..0a972fbf60df 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -5959,6 +5959,8 @@ tc_cls_act_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) return &bpf_skc_lookup_tcp_proto; case BPF_FUNC_tcp_check_syncookie: return &bpf_tcp_check_syncookie_proto; + case BPF_FUNC_skb_ecn_set_ce: + return &bpf_skb_ecn_set_ce_proto; #endif default: return bpf_base_func_proto(func_id); From patchwork Fri Mar 22 23:40:19 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Peter Oskolkov X-Patchwork-Id: 1061764 X-Patchwork-Delegate: bpf@iogearbox.net Return-Path: X-Original-To: patchwork-incoming-netdev@ozlabs.org Delivered-To: patchwork-incoming-netdev@ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netdev-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=google.com header.i=@google.com header.b="TK0f0rn0"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 44R0X70t9hz9sSL for ; Sat, 23 Mar 2019 10:40:39 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727628AbfCVXkc (ORCPT ); Fri, 22 Mar 2019 19:40:32 -0400 Received: from mail-pg1-f201.google.com ([209.85.215.201]:35302 "EHLO mail-pg1-f201.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726910AbfCVXkc (ORCPT ); Fri, 22 Mar 2019 19:40:32 -0400 Received: by mail-pg1-f201.google.com with SMTP id f12so3533382pgs.2 for ; Fri, 22 Mar 2019 16:40:31 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=kaFNt4drXY8Ri1z9COrHkNJcAac+VrmyY76kwGaQXDI=; b=TK0f0rn0uFkJEsP9F2lqu19GF7d+dbQIlNXTqSQlzaQw/XTzZE/Qby6xh+XgFS8ybG t7lo/+L3GlzBk/pELA06VGak1qCwqIZ3+s9t5JGQFrTTNp2Syh/O0NEINnxlF9mhfPKr fXnJ07PzibSLhY7oLqGOPmC+ykV4EpjLh8Wi/9KtBrxVDp1No146plDC6XTdWoa1Dr4a od+DmRFpTfH7nCCvL5Z4cVBaxOdZPYr7rJrOkNeYDekAZpDFks4/YrxzoaYU5H+Vg/Zp Rrn0uhkVGHwzyErMXegdDlMh8KM5IOpvqOBjCx1jpKLwSeriJXwGaWKndiUhbB+yfmdM M4NQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=kaFNt4drXY8Ri1z9COrHkNJcAac+VrmyY76kwGaQXDI=; b=WomjSSHQfLZOHXNmtJDPjOM/W16SvBVZRCnb38LMJZjsRTl0onmvMaXNm8Pu8PLn5k wp7Zp4uqE74p6J5fjUMaajB9Zq5qNkh9xMOnTbq1tZv3MzvCK0jUaD/V/DTZDomYFtwC gwpTCv/GbTqqenahc//pcgFbvHPbGtm+4i7WuFCgFtB/DSA1HnPXpbuisfTCcNCJReMw Ip96IeNudBd7XzCyX1SwLH68ixnxS+niRP3J+n+yngYhKaZFOfIgFKNWOGshh6R+FzPN 7FGDOJ2PjKBYvuUO8kGVL+1Vw9mXCqiM8ia02D/NyAG5XA0Ix1bE6AUaZ6sj70iVyPC4 CyHA== X-Gm-Message-State: APjAAAV2Ob2q7eVQ9iqxmohIPsfR3xUXsBy3sSPdBFULN+k7uiMC1RT1 2YARzktQLNKd3KmggIvS1062IEOs X-Google-Smtp-Source: APXvYqy+83+83ayEnQn5zhKEp5BI6p5ewdsPpo4prtFSkyUDKNOxA+oIEGl7gpZ95w3TTslwvJgLSHTp X-Received: by 2002:a63:31ce:: with SMTP id x197mr11584199pgx.69.1553298031190; Fri, 22 Mar 2019 16:40:31 -0700 (PDT) Date: Fri, 22 Mar 2019 16:40:19 -0700 In-Reply-To: <20190322234019.229181-1-posk@google.com> Message-Id: <20190322234019.229181-2-posk@google.com> Mime-Version: 1.0 References: <20190322234019.229181-1-posk@google.com> X-Mailer: git-send-email 2.21.0.392.gf8f6787159e-goog Subject: [PATCH bpf-next 2/2] selftests: bpf: tc-bpf flow shaping with EDT From: Peter Oskolkov To: Alexei Starovoitov , Daniel Borkmann , netdev@vger.kernel.org, bpf@vger.kernel.org Cc: Peter Oskolkov , Peter Oskolkov Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Add a small test that shows how to shape a TCP flow in tc-bpf with EDT and ECN. Signed-off-by: Peter Oskolkov --- tools/testing/selftests/bpf/Makefile | 3 +- .../testing/selftests/bpf/progs/test_tc_edt.c | 109 ++++++++++++++++++ tools/testing/selftests/bpf/test_tc_edt.sh | 99 ++++++++++++++++ 3 files changed, 210 insertions(+), 1 deletion(-) create mode 100644 tools/testing/selftests/bpf/progs/test_tc_edt.c create mode 100755 tools/testing/selftests/bpf/test_tc_edt.sh diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile index cdcc54ddf4b9..77b73b892136 100644 --- a/tools/testing/selftests/bpf/Makefile +++ b/tools/testing/selftests/bpf/Makefile @@ -53,7 +53,8 @@ TEST_PROGS := test_kmod.sh \ test_xdp_vlan.sh \ test_lwt_ip_encap.sh \ test_tcp_check_syncookie.sh \ - test_tc_tunnel.sh + test_tc_tunnel.sh \ + test_tc_edt.sh TEST_PROGS_EXTENDED := with_addr.sh \ with_tunnels.sh \ diff --git a/tools/testing/selftests/bpf/progs/test_tc_edt.c b/tools/testing/selftests/bpf/progs/test_tc_edt.c new file mode 100644 index 000000000000..3af64c470d64 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/test_tc_edt.c @@ -0,0 +1,109 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include +#include +#include +#include +#include +#include +#include "bpf_helpers.h" +#include "bpf_endian.h" + +/* the maximum delay we are willing to add (drop packets beyond that) */ +#define TIME_HORIZON_NS (2000 * 1000 * 1000) +#define NS_PER_SEC 1000000000 +#define ECN_HORIZON_NS 5000000 +#define THROTTLE_RATE_BPS (5 * 1000 * 1000) + +/* flow_key => last_tstamp timestamp used */ +struct bpf_map_def SEC("maps") flow_map = { + .type = BPF_MAP_TYPE_HASH, + .key_size = sizeof(uint32_t), + .value_size = sizeof(uint64_t), + .max_entries = 1, +}; + +static inline int throttle_flow(struct __sk_buff *skb) +{ + int key = 0; + uint64_t *last_tstamp = bpf_map_lookup_elem(&flow_map, &key); + uint64_t delay_ns = ((uint64_t)skb->len) * NS_PER_SEC / + THROTTLE_RATE_BPS; + uint64_t now = bpf_ktime_get_ns(); + uint64_t tstamp, next_tstamp = 0; + + if (last_tstamp) + next_tstamp = *last_tstamp + delay_ns; + + tstamp = skb->tstamp; + if (tstamp < now) + tstamp = now; + + /* should we throttle? */ + if (next_tstamp <= tstamp) { + if (bpf_map_update_elem(&flow_map, &key, &tstamp, BPF_ANY)) + return TC_ACT_SHOT; + return TC_ACT_OK; + } + + /* do not queue past the time horizon */ + if (next_tstamp - now >= TIME_HORIZON_NS) + return TC_ACT_SHOT; + + /* set ecn bit, if needed */ + if (next_tstamp - now >= ECN_HORIZON_NS) + bpf_skb_ecn_set_ce(skb); + + if (bpf_map_update_elem(&flow_map, &key, &next_tstamp, BPF_EXIST)) + return TC_ACT_SHOT; + skb->tstamp = next_tstamp; + + return TC_ACT_OK; +} + +static inline int handle_tcp(struct __sk_buff *skb, struct tcphdr *tcp) +{ + void *data_end = (void *)(long)skb->data_end; + + /* drop malformed packets */ + if ((void *)(tcp + 1) > data_end) + return TC_ACT_SHOT; + + if (tcp->dest == bpf_htons(9000)) + return throttle_flow(skb); + + return TC_ACT_OK; +} + +static inline int handle_ipv4(struct __sk_buff *skb) +{ + void *data_end = (void *)(long)skb->data_end; + void *data = (void *)(long)skb->data; + struct iphdr *iph; + uint32_t ihl; + + /* drop malformed packets */ + if (data + sizeof(struct ethhdr) > data_end) + return TC_ACT_SHOT; + iph = (struct iphdr *)(data + sizeof(struct ethhdr)); + if ((void *)(iph + 1) > data_end) + return TC_ACT_SHOT; + ihl = iph->ihl * 4; + if (((void *)iph) + ihl > data_end) + return TC_ACT_SHOT; + + if (iph->protocol == IPPROTO_TCP) + return handle_tcp(skb, (struct tcphdr *)(((void *)iph) + ihl)); + + return TC_ACT_OK; +} + +SEC("cls_test") int tc_prog(struct __sk_buff *skb) +{ + if (skb->protocol == bpf_htons(ETH_P_IP)) + return handle_ipv4(skb); + + return TC_ACT_OK; +} + +char __license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/test_tc_edt.sh b/tools/testing/selftests/bpf/test_tc_edt.sh new file mode 100755 index 000000000000..f38567ef694b --- /dev/null +++ b/tools/testing/selftests/bpf/test_tc_edt.sh @@ -0,0 +1,99 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 +# +# This test installs a TC bpf program that throttles a TCP flow +# with dst port = 9000 down to 5MBps. Then it measures actual +# throughput of the flow. + +if [[ $EUID -ne 0 ]]; then + echo "This script must be run as root" + echo "FAIL" + exit 1 +fi + +# check that nc, dd, and timeout are present +command -v nc >/dev/null 2>&1 || \ + { echo >&2 "nc is not available"; exit 1; } +command -v dd >/dev/null 2>&1 || \ + { echo >&2 "nc is not available"; exit 1; } +command -v timeout >/dev/null 2>&1 || \ + { echo >&2 "timeout is not available"; exit 1; } + +readonly NS_SRC="ns-src-$(mktemp -u XXXXXX)" +readonly NS_DST="ns-dst-$(mktemp -u XXXXXX)" + +readonly IP_SRC="172.16.1.100" +readonly IP_DST="172.16.2.100" + +cleanup() +{ + ip netns del ${NS_SRC} + ip netns del ${NS_DST} +} + +trap cleanup EXIT + +set -e # exit on error + +ip netns add "${NS_SRC}" +ip netns add "${NS_DST}" +ip link add veth_src type veth peer name veth_dst +ip link set veth_src netns ${NS_SRC} +ip link set veth_dst netns ${NS_DST} + +ip -netns ${NS_SRC} addr add ${IP_SRC}/24 dev veth_src +ip -netns ${NS_DST} addr add ${IP_DST}/24 dev veth_dst + +ip -netns ${NS_SRC} link set dev veth_src up +ip -netns ${NS_DST} link set dev veth_dst up + +ip -netns ${NS_SRC} route add ${IP_DST}/32 dev veth_src +ip -netns ${NS_DST} route add ${IP_SRC}/32 dev veth_dst + +# set up TC on TX +ip netns exec ${NS_SRC} tc qdisc add dev veth_src root fq +ip netns exec ${NS_SRC} tc qdisc add dev veth_src clsact +ip netns exec ${NS_SRC} tc filter add dev veth_src egress \ + bpf da obj test_tc_edt.o sec cls_test + + +# start the listener +ip netns exec ${NS_DST} bash -c \ + "nc -4 -l -s ${IP_DST} -p 9000 >/dev/null &" +declare -i NC_PID=$! +sleep 1 + +declare -ir TIMEOUT=20 +declare -ir EXPECTED_BPS=5000000 + +# run the load, capture RX bytes on DST +declare -ir RX_BYTES_START=$( ip netns exec ${NS_DST} \ + cat /sys/class/net/veth_dst/statistics/rx_bytes ) + +set +e +ip netns exec ${NS_SRC} bash -c "timeout ${TIMEOUT} dd if=/dev/zero \ + bs=1000 count=1000000 > /dev/tcp/${IP_DST}/9000 2>/dev/null" +set -e + +declare -ir RX_BYTES_END=$( ip netns exec ${NS_DST} \ + cat /sys/class/net/veth_dst/statistics/rx_bytes ) + +declare -ir ACTUAL_BPS=$(( ($RX_BYTES_END - $RX_BYTES_START) / $TIMEOUT )) + +echo $TIMEOUT $ACTUAL_BPS $EXPECTED_BPS | \ + awk '{printf "elapsed: %d sec; bps difference: %.2f%%\n", + $1, ($2-$3)*100.0/$3}' + +# Pass the test if the actual bps is within 1% of the expected bps. +# The difference is usually about 0.1% on a 20-sec test, and ==> zero +# the longer the test runs. +declare -ir RES=$( echo $ACTUAL_BPS $EXPECTED_BPS | \ + awk 'function abs(x){return ((x < 0.0) ? -x : x)} + {if (abs(($1-$2)*100.0/$2) > 1.0) { print "1" } + else { print "0"} }' ) +if [ "${RES}" == "0" ] ; then + echo "PASS" +else + echo "FAIL" + exit 1 +fi