diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile
index 7f3196a..1e8b68d 100644
--- a/tools/testing/selftests/bpf/Makefile
+++ b/tools/testing/selftests/bpf/Makefile
@@ -66,7 +66,8 @@ TEST_PROGS := test_kmod.sh \
 	test_tc_tunnel.sh \
 	test_tc_edt.sh \
 	test_xdping.sh \
-	test_bpftool_build.sh
+	test_bpftool_build.sh \
+	test_bpftool_pcap.sh
 
 TEST_PROGS_EXTENDED := with_addr.sh \
 	with_tunnels.sh \
diff --git a/tools/testing/selftests/bpf/progs/bpftool_pcap_tc.c b/tools/testing/selftests/bpf/progs/bpftool_pcap_tc.c
new file mode 100644
index 0000000..b51f8fc
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/bpftool_pcap_tc.c
@@ -0,0 +1,41 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. */
+
+#include <stddef.h>
+#include <linux/ptrace.h>
+#include <linux/bpf.h>
+#include <linux/pkt_cls.h>
+
+#include <bpf_helpers.h>
+
+#define KBUILD_MODNAME "foo"
+
+struct bpf_map_def SEC("maps") pcap_data_map = {
+	.type = BPF_MAP_TYPE_PERF_EVENT_ARRAY,
+	.key_size = sizeof(int),
+	.value_size = sizeof(int),
+	.max_entries = 1024,
+};
+
+struct bpf_map_def SEC("maps") pcap_conf_map = {
+	.type = BPF_MAP_TYPE_ARRAY,
+	.key_size = sizeof(int),
+	.value_size = sizeof(struct bpf_pcap_hdr),
+	.max_entries = 1,
+};
+
+SEC("tc_pcap")
+int tc_pcap(struct __sk_buff *skb)
+{
+	struct bpf_pcap_hdr *conf;
+	int key = 0;
+
+	conf = bpf_map_lookup_elem(&pcap_conf_map, &key);
+	if (!conf)
+		return 0;
+
+	bpf_pcap(skb, conf->cap_len, &pcap_data_map, conf->protocol,
+		 conf->flags);
+
+	return TC_ACT_OK;
+}
diff --git a/tools/testing/selftests/bpf/progs/bpftool_pcap_xdp.c b/tools/testing/selftests/bpf/progs/bpftool_pcap_xdp.c
new file mode 100644
index 0000000..a7d6866
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/bpftool_pcap_xdp.c
@@ -0,0 +1,39 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. */
+
+#include <stddef.h>
+#include <linux/bpf.h>
+
+#include <bpf_helpers.h>
+
+#define KBUILD_MODNAME "foo"
+
+struct bpf_map_def SEC("maps") pcap_data_map = {
+	.type = BPF_MAP_TYPE_PERF_EVENT_ARRAY,
+	.key_size = sizeof(int),
+	.value_size = sizeof(int),
+	.max_entries = 1024,
+};
+
+struct bpf_map_def SEC("maps") pcap_conf_map = {
+	.type = BPF_MAP_TYPE_ARRAY,
+	.key_size = sizeof(int),
+	.value_size = sizeof(struct bpf_pcap_hdr),
+	.max_entries = 1,
+};
+
+SEC("xdp_pcap")
+int xdp_pcap(struct xdp_md *ctx)
+{
+	struct bpf_pcap_hdr *conf;
+	int key = 0;
+
+	conf = bpf_map_lookup_elem(&pcap_conf_map, &key);
+	if (!conf)
+		return 0;
+
+	bpf_pcap(ctx, conf->cap_len, &pcap_data_map, conf->protocol,
+		 conf->flags);
+
+	return XDP_PASS;
+}
diff --git a/tools/testing/selftests/bpf/test_bpftool_pcap.sh b/tools/testing/selftests/bpf/test_bpftool_pcap.sh
new file mode 100755
index 0000000..92b5438
--- /dev/null
+++ b/tools/testing/selftests/bpf/test_bpftool_pcap.sh
@@ -0,0 +1,132 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+
+readonly src="../../../../"
+readonly bpftool="${src}/tools/bpf/bpftool/bpftool"
+readonly capfile="/tmp/cap.$$"
+readonly ns="ns-$$"
+readonly badport="5555"
+readonly addr1="192.168.1.1"
+readonly addr2="192.168.1.2"
+readonly pinpath="/sys/fs/bpf/"
+readonly veth1="${ns}-veth1"
+readonly veth2="${ns}-veth2"
+# 24 bytes for the pcap header
+readonly cap_minsize=24
+readonly caplens="0 8192"
+readonly addrs="127.0.0.1 ::1"
+readonly devs="none lo"
+
+cleanup() {
+  iptables -D INPUT -p tcp --dport $badport -j DROP
+  ip6tables -D INPUT -p tcp --dport $badport -j DROP
+  ip netns del $ns 2>/dev/null
+  rm -f $capfile
+}
+
+verify_capture() {
+  capsize=$(stat -c '%s' $capfile)
+  if [[ $capsize -le $cap_minsize ]]; then
+    exit 1
+  fi
+  if [[ $no_tcpdump == 0 ]]; then
+    count=$(tcpdump -lnr $capfile $1 2>/dev/null)
+    if [[ -z "$count" ]]; then
+      exit 1
+    fi
+  fi
+}
+
+which tcpdump 2>&1 > /dev/null
+no_tcpdump=$?
+
+pcap_supported=$(bpftool pcap help >/dev/null 2>&1)
+if [[ $? -ne 0 ]]; then
+	echo "no pcap support in bpftool, cannot test feature."
+	exit 0
+fi
+
+set -e
+
+trap cleanup EXIT
+
+iptables -A INPUT -p tcp --dport $badport -j DROP
+ip6tables -A INPUT -p tcp --dport $badport -j DROP
+
+# Test "bpftool pcap trace" - kprobe, tracepoint tracing
+for probe in kprobe tracepoint; do
+  for dev in $devs; do
+    devarg=
+    if [[ $dev != "none" ]]; then
+      devarg="dev $dev"
+    fi
+    args="$probe:kfree_skb proto ip data_out $capfile $devarg"
+    echo "Test trace $args"
+    for caplen in $caplens ; do
+      for progname in none $probe ; do
+        progpath=
+        if [[ $progname != "none" ]]; then
+          progpath=${bpftool}_pcap_${probe}.o
+        fi
+        allargs="$progpath $args len $caplen"
+        for addr in $addrs ; do
+          $bpftool pcap trace $allargs &
+          bpftool_pid=$!
+          set +e
+          timeout 2 nc $addr $badport 2>/dev/null
+          kill -TERM $bpftool_pid
+          set -e
+          sleep 1
+          verify_capture "host $addr and port $badport"
+          rm -f $capfile
+        done
+      done
+    done
+    echo "Test trace $args: PASS"
+  done
+done
+
+# Test "bpftool pcap prog" - skb, xdp program tracing
+ip netns add $ns
+ip link add dev $veth2 netns $ns type veth peer name $veth1
+ip link set $veth1 up
+ip addr add ${addr1}/24 dev $veth1
+ip -netns $ns link set $veth2 up
+ip netns exec $ns ip addr add ${addr2}/24 dev $veth2
+
+for prog in tc xdp ; do
+  if [[ $prog == tc ]]; then
+    ip netns exec $ns tc qdisc add dev $veth2 clsact
+    ip netns exec $ns tc filter add dev $veth2 ingress bpf da \
+      obj bpftool_pcap_${prog}.o sec ${prog}_pcap
+    id=$(ip netns exec $ns tc filter show dev $veth2 ingress | \
+         awk '/direct-action/ { for(i=1;i<=NF;i++)if($i=="id")print $(i+1)}')
+  else
+    ip netns exec $ns ip link set dev $veth2 xdp obj bpftool_pcap_${prog}.o \
+      sec ${prog}_pcap
+    id=$(ip netns exec $ns ip link show $veth2 | awk '/prog\/xdp/ { print $3 }')
+    sleep 5
+  fi
+  args="id $id data_out $capfile"
+  echo "Test prog $args"
+  for caplen in $caplens ; do
+    allargs="$args len $caplen"
+    $bpftool pcap prog $allargs &
+    bpftool_pid=$!
+    set +e
+    ping -q -c 5 $addr2 1>/dev/null
+    kill -TERM $bpftool_pid
+    set -e
+    sleep 1
+    verify_capture "host $addr1"
+    rm -f $capfile
+  done
+  if [[ $prog == tc ]]; then
+    ip netns exec $ns tc qdisc del dev $veth2 clsact
+    sleep 1
+  else
+    ip netns exec $ns ip link set dev $veth2 xdp off
+  fi
+  echo "Test trace $args: PASS"
+done
