Merge pull request #438 from brendangregg/master
fix -p
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 94172b0..f79a2cb 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -39,6 +39,22 @@
include_directories("${DIR}/../tools/clang/include")
ENDFOREACH()
+# Set to non-zero if system installs kernel headers with split source and build
+# directories in /lib/modules/`uname -r`/. This is the case for debian and
+# suse, to the best of my knowledge.
+if(BCC_KERNEL_HAS_SOURCE_DIR)
+ set(BCC_KERNEL_HAS_SOURCE_DIR 1)
+ set(BCC_KERNEL_MODULES_SUFFIX "source")
+else()
+ set(BCC_KERNEL_HAS_SOURCE_DIR 0)
+endif()
+
+# Similar to above, set to custom value if kernel headers in
+# /lib/modules/`uname -r` sit in a different location than build/.
+if(NOT DEFINED BCC_KERNEL_MODULES_SUFFIX)
+ set(BCC_KERNEL_MODULES_SUFFIX "build")
+endif()
+
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall")
endif()
diff --git a/INSTALL.md b/INSTALL.md
index 8a144b1..307165e 100644
--- a/INSTALL.md
+++ b/INSTALL.md
@@ -13,7 +13,8 @@
## Kernel Configuration
In general, to use these features, a Linux kernel version 4.1 or newer is
-required. In addition, the following flags should be set:
+required. In addition, the kernel should have been compiled with the following
+flags set:
```
CONFIG_BPF=y
@@ -28,6 +29,9 @@
CONFIG_BPF_EVENTS=y
```
+Kernel compile flags can usually be checked by looking at `/proc/config.gz` or
+`/boot/config-<kernel-version>`.
+
# Packages
## Ubuntu - Binary
@@ -61,7 +65,7 @@
Test it:
`sudo python /usr/share/bcc/examples/hello_world.py`
-`sudo python /usr/share/bcc/examples/task_switch.py`
+`sudo python /usr/share/bcc/examples/tracing/task_switch.py`
(Optional) Install pyroute2 for additional networking features
```bash
diff --git a/src/cc/CMakeLists.txt b/src/cc/CMakeLists.txt
index 197f320..8781b9b 100644
--- a/src/cc/CMakeLists.txt
+++ b/src/cc/CMakeLists.txt
@@ -32,8 +32,13 @@
endif()
endif()
-add_library(bcc SHARED bpf_common.cc bpf_module.cc libbpf.c perf_reader.c shared_table.cc exported_files.cc)
-set_target_properties(bcc PROPERTIES VERSION ${REVISION_LAST} SOVERSION 0)
+add_library(bcc-shared SHARED bpf_common.cc bpf_module.cc libbpf.c perf_reader.c shared_table.cc exported_files.cc)
+set_target_properties(bcc-shared PROPERTIES VERSION ${REVISION_LAST} SOVERSION 0)
+set_target_properties(bcc-shared PROPERTIES OUTPUT_NAME bcc)
+
+add_library(bcc-loader-static libbpf.c perf_reader.c)
+add_library(bcc-static STATIC bpf_common.cc bpf_module.cc shared_table.cc exported_files.cc)
+set_target_properties(bcc-static PROPERTIES OUTPUT_NAME bcc)
# BPF is still experimental otherwise it should be available
#llvm_map_components_to_libnames(llvm_libs bpf mcjit irreader passes)
@@ -45,9 +50,10 @@
${libclangAST} ${libclangLex} ${libclangBasic})
# Link against LLVM libraries
-target_link_libraries(bcc b_frontend clang_frontend ${clang_libs} ${llvm_libs} LLVMBPFCodeGen)
+target_link_libraries(bcc-shared b_frontend clang_frontend ${clang_libs} ${llvm_libs} LLVMBPFCodeGen)
+target_link_libraries(bcc-static b_frontend clang_frontend bcc-loader-static ${clang_libs} ${llvm_libs} LLVMBPFCodeGen)
-install(TARGETS bcc LIBRARY COMPONENT libbcc
+install(TARGETS bcc-shared LIBRARY COMPONENT libbcc
DESTINATION ${CMAKE_INSTALL_LIBDIR})
install(FILES bpf_common.h bpf_module.h ../libbpf.h COMPONENT libbcc
DESTINATION include/bcc)
diff --git a/src/cc/compat/linux/bpf.h b/src/cc/compat/linux/bpf.h
index 9ea2d22..6496f98 100644
--- a/src/cc/compat/linux/bpf.h
+++ b/src/cc/compat/linux/bpf.h
@@ -81,6 +81,9 @@
BPF_MAP_TYPE_ARRAY,
BPF_MAP_TYPE_PROG_ARRAY,
BPF_MAP_TYPE_PERF_EVENT_ARRAY,
+ BPF_MAP_TYPE_PERCPU_HASH,
+ BPF_MAP_TYPE_PERCPU_ARRAY,
+ BPF_MAP_TYPE_STACK_TRACE,
};
enum bpf_prog_type {
@@ -269,9 +272,61 @@
* Return: 0 on success
*/
BPF_FUNC_perf_event_output,
+ BPF_FUNC_skb_load_bytes,
+
+ /**
+ * bpf_get_stackid(ctx, map, flags) - walk user or kernel stack and return id
+ * @ctx: struct pt_regs*
+ * @map: pointer to stack_trace map
+ * @flags: bits 0-7 - numer of stack frames to skip
+ * bit 8 - collect user stack instead of kernel
+ * bit 9 - compare stacks by hash only
+ * bit 10 - if two different stacks hash into the same stackid
+ * discard old
+ * other bits - reserved
+ * Return: >= 0 stackid on success or negative error
+ */
+ BPF_FUNC_get_stackid,
+
+ /**
+ * bpf_csum_diff(from, from_size, to, to_size, seed) - calculate csum diff
+ * @from: raw from buffer
+ * @from_size: length of from buffer
+ * @to: raw to buffer
+ * @to_size: length of to buffer
+ * @seed: optional seed
+ * Return: csum result
+ */
+ BPF_FUNC_csum_diff,
__BPF_FUNC_MAX_ID,
};
+/* All flags used by eBPF helper functions, placed here. */
+
+/* BPF_FUNC_skb_store_bytes flags. */
+#define BPF_F_RECOMPUTE_CSUM (1ULL << 0)
+
+/* BPF_FUNC_l3_csum_replace and BPF_FUNC_l4_csum_replace flags.
+ * First 4 bits are for passing the header field size.
+ */
+#define BPF_F_HDR_FIELD_MASK 0xfULL
+
+/* BPF_FUNC_l4_csum_replace flags. */
+#define BPF_F_PSEUDO_HDR (1ULL << 4)
+#define BPF_F_MARK_MANGLED_0 (1ULL << 5)
+
+/* BPF_FUNC_clone_redirect and BPF_FUNC_redirect flags. */
+#define BPF_F_INGRESS (1ULL << 0)
+
+/* BPF_FUNC_skb_set_tunnel_key and BPF_FUNC_skb_get_tunnel_key flags. */
+#define BPF_F_TUNINFO_IPV6 (1ULL << 0)
+
+/* BPF_FUNC_get_stackid flags. */
+#define BPF_F_SKIP_FIELD_MASK 0xffULL
+#define BPF_F_USER_STACK (1ULL << 8)
+#define BPF_F_FAST_STACK_CMP (1ULL << 9)
+#define BPF_F_REUSE_STACKID (1ULL << 10)
+
/* user accessible mirror of in-kernel sk_buff.
* new fields can only be added to the end of this structure
*/
@@ -295,7 +350,12 @@
struct bpf_tunnel_key {
__u32 tunnel_id;
- __u32 remote_ipv4;
+ union {
+ __u32 remote_ipv4;
+ __u32 remote_ipv6[4];
+ };
+ __u8 tunnel_tos;
+ __u8 tunnel_ttl;
};
#endif /* _UAPI__LINUX_BPF_H__ */
diff --git a/src/cc/export/helpers.h b/src/cc/export/helpers.h
index 070a2bb..3ae55d6 100644
--- a/src/cc/export/helpers.h
+++ b/src/cc/export/helpers.h
@@ -25,6 +25,12 @@
#error "CONFIG_BPF_SYSCALL is undefined, please check your .config or ask your Linux distro to enable this feature"
#endif
+#ifdef PERF_MAX_STACK_DEPTH
+#define BPF_MAX_STACK_DEPTH PERF_MAX_STACK_DEPTH
+#else
+#define BPF_MAX_STACK_DEPTH 127
+#endif
+
/* helper macro to place programs, maps, license in
* different sections in elf_bpf file. Section names
* are interpreted by elf_bpf loader
@@ -42,6 +48,7 @@
int (*delete) (_key_type *); \
void (*call) (void *, int index); \
void (*increment) (_key_type); \
+ int (*get_stackid) (void *, u64); \
_leaf_type data[_max_entries]; \
}; \
__attribute__((section("maps/" _table_type))) \
@@ -104,6 +111,13 @@
#define BPF_HISTOGRAM(...) \
BPF_HISTX(__VA_ARGS__, BPF_HIST3, BPF_HIST2, BPF_HIST1)(__VA_ARGS__)
+struct bpf_stacktrace {
+ u64 ip[BPF_MAX_STACK_DEPTH];
+};
+
+#define BPF_STACK_TRACE(_name, _max_entries) \
+ BPF_TABLE("stacktrace", int, struct bpf_stacktrace, _name, _max_entries);
+
// packet parsing state machine helpers
#define cursor_advance(_cursor, _len) \
({ void *_tmp = _cursor; _cursor += _len; _tmp; })
@@ -165,6 +179,20 @@
static int (*bpf_perf_event_output)(void *ctx, void *map, u32 index, void *data, u32 size) =
(void *) BPF_FUNC_perf_event_output;
#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,5,0)
+static int (*bpf_skb_load_bytes)(void *ctx, int offset, void *to, u32 len) =
+ (void *) BPF_FUNC_skb_load_bytes;
+#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,6,0)
+static int (*bpf_get_stackid_)(void *ctx, void *map, u64 flags) =
+ (void *) BPF_FUNC_get_stackid;
+static inline __attribute__((always_inline))
+int bpf_get_stackid(uintptr_t map, void *ctx, u64 flags) {
+ return bpf_get_stackid_(ctx, (void *)map, flags);
+}
+static int (*bpf_csum_diff)(void *from, u64 from_size, void *to, u64 to_size, u64 seed) =
+ (void *) BPF_FUNC_csum_diff;
+#endif
/* llvm builtin functions that eBPF C program may use to
* emit BPF_LD_ABS and BPF_LD_IND instructions
diff --git a/src/cc/export/proto.h b/src/cc/export/proto.h
index b2f50ed..40e209d 100644
--- a/src/cc/export/proto.h
+++ b/src/cc/export/proto.h
@@ -61,6 +61,37 @@
unsigned int dst; // byte 16
} BPF_PACKET_HEADER;
+struct icmp_t {
+ unsigned char type;
+ unsigned char code;
+ unsigned short checksum;
+} BPF_PACKET_HEADER;
+
+struct ip6_t {
+ unsigned int ver:4;
+ unsigned int priority:8;
+ unsigned int flow_label:20;
+ unsigned short payload_len;
+ unsigned char next_header;
+ unsigned char hop_limit;
+ unsigned long long src_hi;
+ unsigned long long src_lo;
+ unsigned long long dst_hi;
+ unsigned long long dst_lo;
+} BPF_PACKET_HEADER;
+
+struct ip6_opt_t {
+ unsigned char next_header;
+ unsigned char ext_len;
+ unsigned char pad[6];
+} BPF_PACKET_HEADER;
+
+struct icmp6_t {
+ unsigned char type;
+ unsigned char code;
+ unsigned short checksum;
+} BPF_PACKET_HEADER;
+
struct udp_t {
unsigned short sport;
unsigned short dport;
diff --git a/src/cc/frontends/clang/CMakeLists.txt b/src/cc/frontends/clang/CMakeLists.txt
index 514df49..6e01bc0 100644
--- a/src/cc/frontends/clang/CMakeLists.txt
+++ b/src/cc/frontends/clang/CMakeLists.txt
@@ -1,4 +1,6 @@
# Copyright (c) PLUMgrid, Inc.
# Licensed under the Apache License, Version 2.0 (the "License")
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DKERNEL_MODULES_SUFFIX='\"${BCC_KERNEL_MODULES_SUFFIX}\"'")
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DKERNEL_HAS_SOURCE_DIR=${BCC_KERNEL_HAS_SOURCE_DIR}")
add_library(clang_frontend loader.cc b_frontend_action.cc kbuild_helper.cc)
diff --git a/src/cc/frontends/clang/b_frontend_action.cc b/src/cc/frontends/clang/b_frontend_action.cc
index cbd91bd..bc5ede2 100644
--- a/src/cc/frontends/clang/b_frontend_action.cc
+++ b/src/cc/frontends/clang/b_frontend_action.cc
@@ -315,6 +315,8 @@
string prefix, suffix;
string map_update_policy = "BPF_ANY";
string txt;
+ auto rewrite_start = Call->getLocStart();
+ auto rewrite_end = Call->getLocEnd();
if (memb_name == "lookup_or_init") {
map_update_policy = "BPF_NOEXIST";
string name = Ref->getDecl()->getName();
@@ -352,6 +354,19 @@
Call->getArg(2)->getLocEnd()));
txt = "bpf_perf_event_output(" + arg0 + ", bpf_pseudo_fd(1, " + fd + ")";
txt += ", bpf_get_smp_processor_id(), " + args_other + ")";
+ } else if (memb_name == "get_stackid") {
+ if (table_it->type == BPF_MAP_TYPE_STACK_TRACE) {
+ string arg0 = rewriter_.getRewrittenText(SourceRange(Call->getArg(0)->getLocStart(),
+ Call->getArg(0)->getLocEnd()));
+ txt = "bpf_get_stackid(";
+ txt += "bpf_pseudo_fd(1, " + fd + "), " + arg0;
+ rewrite_end = Call->getArg(0)->getLocEnd();
+ } else {
+ unsigned diag_id = C.getDiagnostics().getCustomDiagID(DiagnosticsEngine::Error,
+ "get_stackid only available on stacktrace maps");
+ C.getDiagnostics().Report(Call->getLocStart(), diag_id);
+ return false;
+ }
} else {
if (memb_name == "lookup") {
prefix = "bpf_map_lookup_elem";
@@ -377,12 +392,12 @@
txt = prefix + args + suffix;
}
- if (!rewriter_.isRewritable(Call->getLocStart())) {
+ if (!rewriter_.isRewritable(rewrite_start) || !rewriter_.isRewritable(rewrite_end)) {
C.getDiagnostics().Report(Call->getLocStart(), diag::err_expected)
<< "use of map function not in a macro";
return false;
}
- rewriter_.ReplaceText(SourceRange(Call->getLocStart(), Call->getLocEnd()), txt);
+ rewriter_.ReplaceText(SourceRange(rewrite_start, rewrite_end), txt);
return true;
}
}
@@ -578,6 +593,8 @@
} else if (A->getName() == "maps/perf_array") {
if (KERNEL_VERSION(major,minor,0) >= KERNEL_VERSION(4,3,0))
map_type = BPF_MAP_TYPE_PERF_EVENT_ARRAY;
+ } else if (A->getName() == "maps/stacktrace") {
+ map_type = BPF_MAP_TYPE_STACK_TRACE;
} else if (A->getName() == "maps/extern") {
is_extern = true;
table.fd = SharedTables::instance()->lookup_fd(table.name);
diff --git a/src/cc/frontends/clang/kbuild_helper.cc b/src/cc/frontends/clang/kbuild_helper.cc
index dc1675b..3cb55df 100644
--- a/src/cc/frontends/clang/kbuild_helper.cc
+++ b/src/cc/frontends/clang/kbuild_helper.cc
@@ -22,7 +22,7 @@
using std::string;
using std::vector;
-KBuildHelper::KBuildHelper() {
+KBuildHelper::KBuildHelper(const std::string &kdir) : kdir_(kdir) {
}
// read the flags from cache or learn
@@ -58,6 +58,19 @@
cflags->push_back("-nostdinc");
cflags->push_back("-isystem");
cflags->push_back("/virtual/lib/clang/include");
+
+ // some module build directories split headers between source/ and build/
+ if (KERNEL_HAS_SOURCE_DIR) {
+ cflags->push_back("-I" + kdir_ + "/build/arch/"+arch+"/include");
+ cflags->push_back("-I" + kdir_ + "/build/arch/"+arch+"/include/generated/uapi");
+ cflags->push_back("-I" + kdir_ + "/build/arch/"+arch+"/include/generated");
+ cflags->push_back("-I" + kdir_ + "/build/include");
+ cflags->push_back("-I" + kdir_ + "/build/./arch/"+arch+"/include/uapi");
+ cflags->push_back("-I" + kdir_ + "/build/arch/"+arch+"/include/generated/uapi");
+ cflags->push_back("-I" + kdir_ + "/build/include/uapi");
+ cflags->push_back("-I" + kdir_ + "/build/include/generated/uapi");
+ }
+
cflags->push_back("-I./arch/"+arch+"/include");
cflags->push_back("-Iarch/"+arch+"/include/generated/uapi");
cflags->push_back("-Iarch/"+arch+"/include/generated");
@@ -71,6 +84,7 @@
cflags->push_back("-D__KERNEL__");
cflags->push_back("-Wno-unused-value");
cflags->push_back("-Wno-pointer-sign");
+
return 0;
}
diff --git a/src/cc/frontends/clang/kbuild_helper.h b/src/cc/frontends/clang/kbuild_helper.h
index 6f93dec..3cbc0f6 100644
--- a/src/cc/frontends/clang/kbuild_helper.h
+++ b/src/cc/frontends/clang/kbuild_helper.h
@@ -33,13 +33,13 @@
// Helper with pushd/popd semantics
class DirStack {
public:
- explicit DirStack(const char *dst) : ok_(false) {
+ explicit DirStack(const std::string &dst) : ok_(false) {
if (getcwd(cwd_, sizeof(cwd_)) == NULL) {
::perror("getcwd");
return;
}
- if (::chdir(dst)) {
- fprintf(stderr, "chdir(%s): %s\n", dst, strerror(errno));
+ if (::chdir(dst.c_str())) {
+ fprintf(stderr, "chdir(%s): %s\n", dst.c_str(), strerror(errno));
return;
}
ok_ = true;
@@ -94,8 +94,10 @@
// case we eventually support non-root user programs, cache in $HOME.
class KBuildHelper {
public:
- KBuildHelper();
+ explicit KBuildHelper(const std::string &kdir);
int get_flags(const char *uname_machine, std::vector<std::string> *cflags);
+ private:
+ std::string kdir_;
};
} // namespace ebpf
diff --git a/src/cc/frontends/clang/loader.cc b/src/cc/frontends/clang/loader.cc
index a138d93..6a0d025 100644
--- a/src/cc/frontends/clang/loader.cc
+++ b/src/cc/frontends/clang/loader.cc
@@ -82,11 +82,10 @@
unique_ptr<llvm::MemoryBuffer> main_buf;
struct utsname un;
uname(&un);
- char kdir[256];
- snprintf(kdir, sizeof(kdir), "%s/%s/build", KERNEL_MODULES_DIR, un.release);
+ string kdir = string(KERNEL_MODULES_DIR) + "/" + un.release;
// clang needs to run inside the kernel dir
- DirStack dstack(kdir);
+ DirStack dstack(kdir + "/" + KERNEL_MODULES_SUFFIX);
if (!dstack.ok())
return -1;
@@ -106,7 +105,7 @@
"-Wno-gnu-variable-sized-type-not-at-end",
"-x", "c", "-c", abs_file.c_str()});
- KBuildHelper kbuild_helper;
+ KBuildHelper kbuild_helper(kdir);
vector<string> kflags;
if (kbuild_helper.get_flags(un.machine, &kflags))
return -1;
diff --git a/src/python/bcc/table.py b/src/python/bcc/table.py
index 26fa868..c33cb39 100644
--- a/src/python/bcc/table.py
+++ b/src/python/bcc/table.py
@@ -22,6 +22,9 @@
BPF_MAP_TYPE_ARRAY = 2
BPF_MAP_TYPE_PROG_ARRAY = 3
BPF_MAP_TYPE_PERF_EVENT_ARRAY = 4
+BPF_MAP_TYPE_PERCPU_HASH = 5
+BPF_MAP_TYPE_PERCPU_ARRAY = 6
+BPF_MAP_TYPE_STACK_TRACE = 7
stars_max = 40
@@ -85,6 +88,12 @@
t = ProgArray(bpf, map_id, map_fd, keytype, leaftype)
elif ttype == BPF_MAP_TYPE_PERF_EVENT_ARRAY:
t = PerfEventArray(bpf, map_id, map_fd, keytype, leaftype)
+ elif ttype == BPF_MAP_TYPE_PERCPU_HASH:
+ t = PerCpuHashTable(bpf, map_id, map_fd, keytype, leaftype)
+ elif ttype == BPF_MAP_TYPE_PERCPU_ARRAY:
+ t = PerCpuArray(bpf, map_id, map_fd, keytype, leaftype)
+ elif ttype == BPF_MAP_TYPE_STACK_TRACE:
+ t = StackTrace(bpf, map_id, map_fd, keytype, leaftype)
if t == None:
raise Exception("Unknown table type %d" % ttype)
return t
@@ -393,3 +402,30 @@
lib.perf_reader_free(reader)
del(self.bpf.open_kprobes()[(id(self), key)])
del self._cbs[key]
+
+class PerCpuHashTable(TableBase):
+ def __init__(self, *args, **kwargs):
+ raise Exception("Unsupported")
+
+class PerCpuArray(ArrayBase):
+ def __init__(self, *args, **kwargs):
+ raise Exception("Unsupported")
+
+class StackTrace(TableBase):
+ def __init__(self, *args, **kwargs):
+ super(StackTrace, self).__init__(*args, **kwargs)
+
+ def __len__(self):
+ i = 0
+ for k in self: i += 1
+ return i
+
+ def __delitem__(self, key):
+ key_p = ct.pointer(key)
+ res = lib.bpf_delete_elem(self.map_fd, ct.cast(key_p, ct.c_void_p))
+ if res < 0:
+ raise KeyError
+
+ def clear(self):
+ pass
+
diff --git a/tests/cc/CMakeLists.txt b/tests/cc/CMakeLists.txt
index 95916a3..3f84da1 100644
--- a/tests/cc/CMakeLists.txt
+++ b/tests/cc/CMakeLists.txt
@@ -1,50 +1,9 @@
# Copyright (c) PLUMgrid, Inc.
# Licensed under the Apache License, Version 2.0 (the "License")
-find_program(ARPING arping)
-if(ARPING STREQUAL "ARPING-NOTFOUND")
- message(WARNING "Recommended test program 'arping' not found")
-endif()
-find_program(NETPERF netperf)
-if(NETPERF STREQUAL "NETPERF-NOTFOUND")
- message(WARNING "Recommended test program 'netperf' not found")
-endif()
-find_program(IPERF iperf)
-if(IPERF STREQUAL "IPERF-NOTFOUND")
- message(WARNING "Recommended test program 'iperf' not found")
-endif()
+include_directories(${CMAKE_SOURCE_DIR}/src/cc)
-add_test(NAME py_test_stat1_b WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
- COMMAND ${TEST_WRAPPER} py_stat1_b namespace ${CMAKE_CURRENT_SOURCE_DIR}/test_stat1.py test_stat1.b proto.b)
-add_test(NAME py_test_stat1_c WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
- COMMAND ${TEST_WRAPPER} py_stat1_c namespace ${CMAKE_CURRENT_SOURCE_DIR}/test_stat1.py test_stat1.c)
-#add_test(NAME py_test_xlate1_b WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
-# COMMAND ${TEST_WRAPPER} py_xlate1_b namespace ${CMAKE_CURRENT_SOURCE_DIR}/test_xlate1.py test_xlate1.b proto.b)
-add_test(NAME py_test_xlate1_c WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
- COMMAND ${TEST_WRAPPER} py_xlate1_c namespace ${CMAKE_CURRENT_SOURCE_DIR}/test_xlate1.py test_xlate1.c)
-add_test(NAME py_test_call1 WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
- COMMAND ${TEST_WRAPPER} py_call1_c namespace ${CMAKE_CURRENT_SOURCE_DIR}/test_call1.py test_call1.c)
-add_test(NAME py_test_trace1 WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
- COMMAND ${TEST_WRAPPER} py_trace1 sudo ${CMAKE_CURRENT_SOURCE_DIR}/test_trace1.py test_trace1.b kprobe.b)
-add_test(NAME py_test_trace2 WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
- COMMAND ${TEST_WRAPPER} py_trace2 sudo ${CMAKE_CURRENT_SOURCE_DIR}/test_trace2.py)
-add_test(NAME py_test_trace3_c WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
- COMMAND ${TEST_WRAPPER} py_trace3_c sudo ${CMAKE_CURRENT_SOURCE_DIR}/test_trace3.py test_trace3.c)
-add_test(NAME py_test_trace4 WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
- COMMAND ${TEST_WRAPPER} py_trace4 sudo ${CMAKE_CURRENT_SOURCE_DIR}/test_trace4.py)
-add_test(NAME py_test_probe_count WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
- COMMAND ${TEST_WRAPPER} py_probe_count sudo ${CMAKE_CURRENT_SOURCE_DIR}/test_probe_count.py)
-add_test(NAME py_test_brb WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
- COMMAND ${TEST_WRAPPER} py_brb_c sudo ${CMAKE_CURRENT_SOURCE_DIR}/test_brb.py test_brb.c)
-add_test(NAME py_test_brb2 WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
- COMMAND ${TEST_WRAPPER} py_brb2_c sudo ${CMAKE_CURRENT_SOURCE_DIR}/test_brb2.py test_brb2.c)
-add_test(NAME py_test_clang WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
- COMMAND ${TEST_WRAPPER} py_clang sudo ${CMAKE_CURRENT_SOURCE_DIR}/test_clang.py)
-add_test(NAME py_test_histogram WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
- COMMAND ${TEST_WRAPPER} py_histogram sudo ${CMAKE_CURRENT_SOURCE_DIR}/test_histogram.py)
-add_test(NAME py_test_callchain WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
- COMMAND ${TEST_WRAPPER} py_callchain sudo ${CMAKE_CURRENT_SOURCE_DIR}/test_callchain.py)
-add_test(NAME py_array WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
- COMMAND ${TEST_WRAPPER} py_array sudo ${CMAKE_CURRENT_SOURCE_DIR}/test_array.py)
-add_test(NAME py_uprobes WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
- COMMAND ${TEST_WRAPPER} py_uprobes sudo ${CMAKE_CURRENT_SOURCE_DIR}/test_uprobes.py)
+add_executable(test_static test_static.c)
+target_link_libraries(test_static bcc-static)
+
+add_test(NAME c_test_static COMMAND ${TEST_WRAPPER} c_test_static sudo ${CMAKE_CURRENT_BINARY_DIR}/test_static)
diff --git a/tests/cc/test_static.c b/tests/cc/test_static.c
new file mode 100644
index 0000000..4af8b93
--- /dev/null
+++ b/tests/cc/test_static.c
@@ -0,0 +1,6 @@
+#include "bpf_common.h"
+
+int main(int argc, char **argv) {
+ void *mod = bpf_module_create_c_from_string("BPF_TABLE(\"array\", int, int, stats, 10);\n", 4, NULL, 0);
+ return !(mod != NULL);
+}
diff --git a/tests/python/CMakeLists.txt b/tests/python/CMakeLists.txt
index 911abbf..04421c9 100644
--- a/tests/python/CMakeLists.txt
+++ b/tests/python/CMakeLists.txt
@@ -1,5 +1,55 @@
# Copyright (c) PLUMgrid, Inc.
# Licensed under the Apache License, Version 2.0 (the "License")
+find_program(ARPING arping)
+if(ARPING STREQUAL "ARPING-NOTFOUND")
+ message(WARNING "Recommended test program 'arping' not found")
+endif()
+find_program(NETPERF netperf)
+if(NETPERF STREQUAL "NETPERF-NOTFOUND")
+ message(WARNING "Recommended test program 'netperf' not found")
+endif()
+find_program(IPERF iperf)
+if(IPERF STREQUAL "IPERF-NOTFOUND")
+ message(WARNING "Recommended test program 'iperf' not found")
+endif()
+
+add_test(NAME py_test_stat1_b WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+ COMMAND ${TEST_WRAPPER} py_stat1_b namespace ${CMAKE_CURRENT_SOURCE_DIR}/test_stat1.py test_stat1.b proto.b)
+add_test(NAME py_test_stat1_c WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+ COMMAND ${TEST_WRAPPER} py_stat1_c namespace ${CMAKE_CURRENT_SOURCE_DIR}/test_stat1.py test_stat1.c)
+#add_test(NAME py_test_xlate1_b WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+# COMMAND ${TEST_WRAPPER} py_xlate1_b namespace ${CMAKE_CURRENT_SOURCE_DIR}/test_xlate1.py test_xlate1.b proto.b)
+add_test(NAME py_test_xlate1_c WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+ COMMAND ${TEST_WRAPPER} py_xlate1_c namespace ${CMAKE_CURRENT_SOURCE_DIR}/test_xlate1.py test_xlate1.c)
+add_test(NAME py_test_call1 WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+ COMMAND ${TEST_WRAPPER} py_call1_c namespace ${CMAKE_CURRENT_SOURCE_DIR}/test_call1.py test_call1.c)
+add_test(NAME py_test_trace1 WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+ COMMAND ${TEST_WRAPPER} py_trace1 sudo ${CMAKE_CURRENT_SOURCE_DIR}/test_trace1.py test_trace1.b kprobe.b)
+add_test(NAME py_test_trace2 WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+ COMMAND ${TEST_WRAPPER} py_trace2 sudo ${CMAKE_CURRENT_SOURCE_DIR}/test_trace2.py)
+add_test(NAME py_test_trace3_c WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+ COMMAND ${TEST_WRAPPER} py_trace3_c sudo ${CMAKE_CURRENT_SOURCE_DIR}/test_trace3.py test_trace3.c)
+add_test(NAME py_test_trace4 WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+ COMMAND ${TEST_WRAPPER} py_trace4 sudo ${CMAKE_CURRENT_SOURCE_DIR}/test_trace4.py)
+add_test(NAME py_test_probe_count WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+ COMMAND ${TEST_WRAPPER} py_probe_count sudo ${CMAKE_CURRENT_SOURCE_DIR}/test_probe_count.py)
+add_test(NAME py_test_brb WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+ COMMAND ${TEST_WRAPPER} py_brb_c sudo ${CMAKE_CURRENT_SOURCE_DIR}/test_brb.py test_brb.c)
+add_test(NAME py_test_brb2 WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+ COMMAND ${TEST_WRAPPER} py_brb2_c sudo ${CMAKE_CURRENT_SOURCE_DIR}/test_brb2.py test_brb2.c)
+add_test(NAME py_test_clang WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+ COMMAND ${TEST_WRAPPER} py_clang sudo ${CMAKE_CURRENT_SOURCE_DIR}/test_clang.py)
+add_test(NAME py_test_histogram WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+ COMMAND ${TEST_WRAPPER} py_histogram sudo ${CMAKE_CURRENT_SOURCE_DIR}/test_histogram.py)
+add_test(NAME py_test_callchain WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+ COMMAND ${TEST_WRAPPER} py_callchain sudo ${CMAKE_CURRENT_SOURCE_DIR}/test_callchain.py)
+add_test(NAME py_array WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+ COMMAND ${TEST_WRAPPER} py_array sudo ${CMAKE_CURRENT_SOURCE_DIR}/test_array.py)
+add_test(NAME py_uprobes WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+ COMMAND ${TEST_WRAPPER} py_uprobes sudo ${CMAKE_CURRENT_SOURCE_DIR}/test_uprobes.py)
+add_test(NAME py_test_stackid WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+ COMMAND ${TEST_WRAPPER} py_stackid sudo ${CMAKE_CURRENT_SOURCE_DIR}/test_stackid.py)
+
add_test(NAME py_test_dump_func WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMAND ${TEST_WRAPPER} py_dump_func simple ${CMAKE_CURRENT_SOURCE_DIR}/test_dump_func.py)
diff --git a/tests/cc/kprobe.b b/tests/python/kprobe.b
similarity index 100%
rename from tests/cc/kprobe.b
rename to tests/python/kprobe.b
diff --git a/tests/cc/proto.b b/tests/python/proto.b
similarity index 100%
rename from tests/cc/proto.b
rename to tests/python/proto.b
diff --git a/tests/cc/simulation.py b/tests/python/simulation.py
similarity index 100%
rename from tests/cc/simulation.py
rename to tests/python/simulation.py
diff --git a/tests/cc/test_array.py b/tests/python/test_array.py
similarity index 100%
rename from tests/cc/test_array.py
rename to tests/python/test_array.py
diff --git a/tests/cc/test_brb.c b/tests/python/test_brb.c
similarity index 100%
rename from tests/cc/test_brb.c
rename to tests/python/test_brb.c
diff --git a/tests/cc/test_brb.py b/tests/python/test_brb.py
similarity index 100%
rename from tests/cc/test_brb.py
rename to tests/python/test_brb.py
diff --git a/tests/cc/test_brb2.c b/tests/python/test_brb2.c
similarity index 100%
rename from tests/cc/test_brb2.c
rename to tests/python/test_brb2.c
diff --git a/tests/cc/test_brb2.py b/tests/python/test_brb2.py
similarity index 100%
rename from tests/cc/test_brb2.py
rename to tests/python/test_brb2.py
diff --git a/tests/cc/test_call1.c b/tests/python/test_call1.c
similarity index 100%
rename from tests/cc/test_call1.c
rename to tests/python/test_call1.c
diff --git a/tests/cc/test_call1.py b/tests/python/test_call1.py
similarity index 100%
rename from tests/cc/test_call1.py
rename to tests/python/test_call1.py
diff --git a/tests/cc/test_callchain.py b/tests/python/test_callchain.py
similarity index 100%
rename from tests/cc/test_callchain.py
rename to tests/python/test_callchain.py
diff --git a/tests/cc/test_clang.py b/tests/python/test_clang.py
similarity index 100%
rename from tests/cc/test_clang.py
rename to tests/python/test_clang.py
diff --git a/tests/cc/test_clang_complex.c b/tests/python/test_clang_complex.c
similarity index 100%
rename from tests/cc/test_clang_complex.c
rename to tests/python/test_clang_complex.c
diff --git a/tests/cc/test_histogram.py b/tests/python/test_histogram.py
similarity index 100%
rename from tests/cc/test_histogram.py
rename to tests/python/test_histogram.py
diff --git a/tests/cc/test_probe_count.py b/tests/python/test_probe_count.py
similarity index 100%
rename from tests/cc/test_probe_count.py
rename to tests/python/test_probe_count.py
diff --git a/tests/python/test_stackid.py b/tests/python/test_stackid.py
new file mode 100755
index 0000000..8079a37
--- /dev/null
+++ b/tests/python/test_stackid.py
@@ -0,0 +1,54 @@
+#!/usr/bin/python
+# Copyright (c) PLUMgrid, Inc.
+# Licensed under the Apache License, Version 2.0 (the "License")
+
+import bcc
+import distutils.version
+import os
+import unittest
+
+def kernel_version_ge(major, minor):
+ # True if running kernel is >= X.Y
+ version = distutils.version.LooseVersion(os.uname()[2]).version
+ if version[0] > major:
+ return True
+ if version[0] < major:
+ return False
+ if minor and version[1] < minor:
+ return False
+ return True
+
+
+@unittest.skipUnless(kernel_version_ge(4,6), "requires kernel >= 4.6")
+class TestStackid(unittest.TestCase):
+ def test_simple(self):
+ b = bcc.BPF(text="""
+#include <uapi/linux/ptrace.h>
+#include <linux/bpf.h>
+BPF_STACK_TRACE(stack_traces, 10240);
+BPF_HASH(stack_entries, int, int);
+BPF_HASH(stub);
+int kprobe__htab_map_delete_elem(struct pt_regs *ctx, struct bpf_map *map, u64 *k) {
+ int id = stack_traces.get_stackid(ctx, BPF_F_REUSE_STACKID);
+ if (id < 0)
+ return 0;
+ int key = 1;
+ stack_entries.update(&key, &id);
+ return 0;
+}
+""")
+ stub = b["stub"]
+ stack_traces = b["stack_traces"]
+ stack_entries = b["stack_entries"]
+ try: del stub[stub.Key(1)]
+ except: pass
+ k = stack_entries.Key(1)
+ self.assertIn(k, stack_entries)
+ stackid = stack_entries[k]
+ self.assertIsNotNone(stackid)
+ stack = stack_traces[stackid].ip
+ self.assertEqual(b.ksym(stack[0]), "htab_map_delete_elem")
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/tests/cc/test_stat1.b b/tests/python/test_stat1.b
similarity index 100%
rename from tests/cc/test_stat1.b
rename to tests/python/test_stat1.b
diff --git a/tests/cc/test_stat1.c b/tests/python/test_stat1.c
similarity index 100%
rename from tests/cc/test_stat1.c
rename to tests/python/test_stat1.c
diff --git a/tests/cc/test_stat1.py b/tests/python/test_stat1.py
similarity index 100%
rename from tests/cc/test_stat1.py
rename to tests/python/test_stat1.py
diff --git a/tests/cc/test_trace1.b b/tests/python/test_trace1.b
similarity index 100%
rename from tests/cc/test_trace1.b
rename to tests/python/test_trace1.b
diff --git a/tests/cc/test_trace1.py b/tests/python/test_trace1.py
similarity index 100%
rename from tests/cc/test_trace1.py
rename to tests/python/test_trace1.py
diff --git a/tests/cc/test_trace2.b b/tests/python/test_trace2.b
similarity index 100%
rename from tests/cc/test_trace2.b
rename to tests/python/test_trace2.b
diff --git a/tests/cc/test_trace2.c b/tests/python/test_trace2.c
similarity index 100%
rename from tests/cc/test_trace2.c
rename to tests/python/test_trace2.c
diff --git a/tests/cc/test_trace2.py b/tests/python/test_trace2.py
similarity index 100%
rename from tests/cc/test_trace2.py
rename to tests/python/test_trace2.py
diff --git a/tests/cc/test_trace3.c b/tests/python/test_trace3.c
similarity index 100%
rename from tests/cc/test_trace3.c
rename to tests/python/test_trace3.c
diff --git a/tests/cc/test_trace3.py b/tests/python/test_trace3.py
similarity index 100%
rename from tests/cc/test_trace3.py
rename to tests/python/test_trace3.py
diff --git a/tests/cc/test_trace4.py b/tests/python/test_trace4.py
similarity index 100%
rename from tests/cc/test_trace4.py
rename to tests/python/test_trace4.py
diff --git a/tests/cc/test_uprobes.py b/tests/python/test_uprobes.py
similarity index 100%
rename from tests/cc/test_uprobes.py
rename to tests/python/test_uprobes.py
diff --git a/tests/cc/test_xlate1.b b/tests/python/test_xlate1.b
similarity index 100%
rename from tests/cc/test_xlate1.b
rename to tests/python/test_xlate1.b
diff --git a/tests/cc/test_xlate1.c b/tests/python/test_xlate1.c
similarity index 100%
rename from tests/cc/test_xlate1.c
rename to tests/python/test_xlate1.c
diff --git a/tests/cc/test_xlate1.py b/tests/python/test_xlate1.py
similarity index 100%
rename from tests/cc/test_xlate1.py
rename to tests/python/test_xlate1.py
diff --git a/tools/biosnoop.py b/tools/biosnoop.py
index 702c97b..3030e19 100755
--- a/tools/biosnoop.py
+++ b/tools/biosnoop.py
@@ -154,7 +154,7 @@
if event.rwflag == 0:
rwflg = "R"
- if not re.match('\?', event.name):
+ if not re.match(b'\?', event.name):
val = event.sector
if start_ts == 0:
diff --git a/tools/dcstat.py b/tools/dcstat.py
index b526a43..0da3967 100755
--- a/tools/dcstat.py
+++ b/tools/dcstat.py
@@ -103,7 +103,7 @@
# header
print("%-8s " % "TIME", end="")
-for stype, idx in sorted(stats.iteritems(), key=lambda (k, v): (v, k)):
+for stype, idx in sorted(stats.items(), key=lambda k_v: (k_v[1], k_v[0])):
print(" %8s" % (stype + "/s"), end="")
print(" %8s" % "HIT%")
@@ -123,7 +123,7 @@
print("%-8s: " % strftime("%H:%M:%S"), end="")
# print each statistic as a column
- for stype, idx in sorted(stats.iteritems(), key=lambda (k, v): (v, k)):
+ for stype, idx in sorted(stats.items(), key=lambda k_v: (k_v[1], k_v[0])):
try:
val = b["stats"][c_int(idx)].value / interval
print(" %8d" % val, end="")
diff --git a/tools/memleak.py b/tools/memleak.py
index 7100050..b5f272d 100755
--- a/tools/memleak.py
+++ b/tools/memleak.py
@@ -385,7 +385,7 @@
count_so_far = 0
while True:
if trace_all:
- print bpf_program.trace_fields()
+ print(bpf_program.trace_fields())
else:
try:
sleep(interval)
diff --git a/tools/stacksnoop.py b/tools/stacksnoop.py
index d8ced4e..3bf4732 100755
--- a/tools/stacksnoop.py
+++ b/tools/stacksnoop.py
@@ -93,7 +93,7 @@
if args.pid:
bpf_text = bpf_text.replace('FILTER',
('u32 pid; pid = bpf_get_current_pid_tgid(); ' +
- 'if (pid != %s) { return 0; }') % (args.pid))
+ 'if (pid != %s) { return; }') % (args.pid))
else:
bpf_text = bpf_text.replace('FILTER', '')
if debug: