From: Stephen Hemminger <stephen@networkplumber.org>
To: dev@dpdk.org
Cc: Stephen Hemminger <stephen@networkplumber.org>
Subject: [dpdk-dev] [RFC 8/8] app/capture: add packet capture using pcapng
Date: Mon, 7 Oct 2019 09:52:32 -0700 [thread overview]
Message-ID: <20191007165232.14535-9-stephen@networkplumber.org> (raw)
In-Reply-To: <20191007165232.14535-1-stephen@networkplumber.org>
New application (dpdk-capture) with syntax analogous to tshark's
dumpcap command. It runs as a secondary process and produces
capture output in pcapng format.
It does not use DPDK style EAL arguments; instead the flags
are meant to be the same as dumpcap.
The program depends on libpcap since it uses the pcap_compile()
function to compile a string into a BPF program.
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
app/Makefile | 1 +
app/capture/Makefile | 19 ++
app/capture/main.c | 675 ++++++++++++++++++++++++++++++++++++++++
app/capture/meson.build | 22 ++
app/meson.build | 1 +
config/common_base | 5 +
6 files changed, 723 insertions(+)
create mode 100644 app/capture/Makefile
create mode 100644 app/capture/main.c
create mode 100644 app/capture/meson.build
diff --git a/app/Makefile b/app/Makefile
index 28acbceca904..509cd7f4de13 100644
--- a/app/Makefile
+++ b/app/Makefile
@@ -7,6 +7,7 @@ DIRS-$(CONFIG_RTE_APP_TEST) += test
DIRS-$(CONFIG_RTE_TEST_PMD) += test-pmd
DIRS-$(CONFIG_RTE_PROC_INFO) += proc-info
DIRS-$(CONFIG_RTE_LIBRTE_PDUMP) += pdump
+DIRS-$(CONFIG_RTE_APP_CAPTURE) += capture
DIRS-$(CONFIG_RTE_LIBRTE_ACL) += test-acl
DIRS-$(CONFIG_RTE_LIBRTE_CMDLINE) += test-cmdline
DIRS-$(CONFIG_RTE_LIBRTE_PIPELINE) += test-pipeline
diff --git a/app/capture/Makefile b/app/capture/Makefile
new file mode 100644
index 000000000000..78ff7d2e97bf
--- /dev/null
+++ b/app/capture/Makefile
@@ -0,0 +1,19 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2019 Microsoft Corporation
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+ifeq ($(CONFIG_RTE_LIBRTE_PCAPNG),y)
+
+APP = dpdk-capture
+
+CFLAGS += -DALLOW_EXPERIMENTAL_API
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS)
+LDLIBS += -lpcap
+
+SRCS-y := main.c
+
+include $(RTE_SDK)/mk/rte.app.mk
+
+endif
diff --git a/app/capture/main.c b/app/capture/main.c
new file mode 100644
index 000000000000..394c1edcc01b
--- /dev/null
+++ b/app/capture/main.c
@@ -0,0 +1,675 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2019 Microsoft Corporation
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <string.h>
+#include <inttypes.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/utsname.h>
+#include <fcntl.h>
+#include <sys/queue.h>
+#include <net/if.h>
+
+#include <rte_eal.h>
+#include <rte_version.h>
+#include <rte_alarm.h>
+#include <rte_ether.h>
+#include <rte_ethdev.h>
+#include <rte_mempool.h>
+#include <rte_pdump.h>
+#include <rte_string_fns.h>
+#include <rte_malloc.h>
+#include <rte_pcapng.h>
+
+#include <pcap/pcap.h>
+
+#define RING_NAME "capture-ring"
+#define MONITOR_INTERVAL (500 * 1000)
+#define MBUF_POOL_CACHE_SIZE 32
+#define BURST_SIZE 32
+#define SLEEP_THRESHOLD 1000
+
+static const char *prog;
+static volatile bool quit_signal;
+static bool group_read;
+static bool quiet;
+static bool promiscuous_mode = true;
+static bool use_pcapng = true;
+static char *output_name;
+static const char *filter_str;
+static unsigned int ring_size = 2048;
+static uint64_t packet_count, packets_received;
+static const char *capture_comment;
+static uint16_t snaplen = UINT16_MAX;
+static bool dump_bpf;
+
+struct interface {
+ uint64_t received;
+ uint64_t dropped;
+ uint16_t port;
+ char name[RTE_ETH_NAME_MAX_LEN];
+
+ struct rte_rxtx_callback *rx_cb[RTE_MAX_QUEUES_PER_PORT];
+
+ TAILQ_ENTRY(interface) next;
+};
+
+TAILQ_HEAD(interface_list, interface);
+struct interface_list interfaces = TAILQ_HEAD_INITIALIZER(interfaces);
+
+static struct interface *port2intf[RTE_MAX_ETHPORTS];
+
+static void usage(void)
+{
+ printf("Usage: %s [options] ...\n\n", prog);
+ printf("Interface:\n"
+ " -i <interface> name or port index of interface\n"
+ " -f <capture filter> packet filter in libpcap filter syntax\n"
+ " -s <snaplen> packet snapshot length (default: infinite)\n"
+ " -p don't put interface in promiscuous mode\n"
+ " -D print list of interfaces and exit\n"
+ " -d print generated BPF code for capture filter\n"
+ " -S print statistics for each interface\n\n");
+ printf("Stop condition:\n"
+ " -c <packet count> stop after N packets (default: infinite)\n\n");
+ printf("Output file:\n"
+ " -w <filename> name of file to save (default: tempfile)\n"
+ " -g enable group read access of output file\n"
+ " -n use pcapng format instead of pcap (default)\n"
+ " -P use libpcap format instead of pcapng\n"
+ " --capture-comment <comment>\n"
+ " add capture comment to output file\n");
+ printf("Miscellaneous\n"
+ " -N <packet limit> maximum number of packets buffered (default: %u)\n",
+ ring_size);
+ printf(" -q don't report packet capture counts\n"
+ " -v print version information and exit\n"
+ " -h display this help and exit\n");
+}
+
+static void version(void)
+{
+ printf("%s 1.0 (DPDK %s)\n", prog, rte_version());
+}
+
+/* Parse numeric argument from command line */
+static unsigned int get_uint(const char *arg, const char *name,
+ unsigned int limit)
+{
+ unsigned long u;
+ char *endp;
+
+ u = strtoul(arg, &endp, 0);
+ if (*arg == '\0' || *endp != '\0')
+ rte_exit(EXIT_FAILURE,
+ "Specified %s \"%s\" is not a valid number\n",
+ name, arg);
+ if (limit && u > limit)
+ rte_exit(EXIT_FAILURE,
+ "Specified %s \"%s\" is too large (greater than %u)\n",
+ name, arg, limit);
+
+ return u;
+}
+
+/* Add interface to list of interfaces to capture */
+static void add_interface(uint16_t port, const char *name)
+{
+ struct interface *intf;
+
+ intf = malloc(sizeof(*intf));
+ if (!intf)
+ rte_exit(EXIT_FAILURE, "no memory for interface\n");
+
+ memset(intf, 0, sizeof(*intf));
+ strlcpy(intf->name, name, sizeof(intf->name));
+
+ printf("Capturing on '%s'\n", name);
+
+ port2intf[port] = intf;
+ TAILQ_INSERT_TAIL(&interfaces, intf, next);
+}
+
+/* Select all valid DPDK interfaces */
+static void select_all_interfaces(void)
+{
+ char name[RTE_ETH_NAME_MAX_LEN];
+ uint16_t p;
+
+ RTE_ETH_FOREACH_DEV(p) {
+ if (rte_eth_dev_get_name_by_port(p, name) < 0)
+ continue;
+ add_interface(p, name);
+ }
+}
+
+/*
+ * Choose interface to capture if no -i option given.
+ * Select the first DPDK port, this matches what dumpcap does.
+ */
+static void set_default_interface(void)
+{
+ char name[RTE_ETH_NAME_MAX_LEN];
+ uint16_t p;
+
+ RTE_ETH_FOREACH_DEV(p) {
+ if (rte_eth_dev_get_name_by_port(p, name) < 0)
+ continue;
+ add_interface(p, name);
+ return;
+ }
+ rte_exit(EXIT_FAILURE, "No usable interfaces found\n");
+}
+
+/* Lookup interface by name or port and add it to the list */
+static void select_interface(const char *arg)
+{
+ uint16_t port;
+
+ if (strcmp(arg, "*"))
+ select_all_interfaces();
+ else if (rte_eth_dev_get_port_by_name(arg, &port) == 0)
+ add_interface(port, arg);
+ else {
+ char name[RTE_ETH_NAME_MAX_LEN];
+
+ port = get_uint(arg, "port_number", UINT16_MAX);
+ if (rte_eth_dev_get_name_by_port(port, name) < 0)
+ rte_exit(EXIT_FAILURE, "Invalid port number %u\n",
+ port);
+ add_interface(port, name);
+ }
+}
+
+/* Display list of possible interfaces that can be used. */
+static void show_interfaces(void)
+{
+ char name[RTE_ETH_NAME_MAX_LEN];
+ uint16_t p;
+
+ RTE_ETH_FOREACH_DEV(p) {
+ if (rte_eth_dev_get_name_by_port(p, name) < 0)
+ continue;
+ printf("%u. %s\n", p, name);
+ }
+}
+
+static struct bpf_insn *compile_filter(uint32_t *len)
+{
+ struct bpf_program fcode;
+ pcap_t *pcap;
+ void *fmem;
+ size_t sz;
+
+ pcap = pcap_open_dead(DLT_EN10MB, snaplen);
+ if (!pcap)
+ rte_exit(EXIT_FAILURE, "can not open pcap\n");
+
+ if (pcap_compile(pcap, &fcode, filter_str,
+ 1, PCAP_NETMASK_UNKNOWN) != 0)
+ rte_exit(EXIT_FAILURE, "pcap filter string not valid (%s)\n",
+ pcap_geterr(pcap));
+
+ /*
+ * Need to put filter in shared memory where it can
+ * be read by primary process.
+ */
+ *len = fcode.bf_len;
+ sz = fcode.bf_len * sizeof(struct bpf_insn);
+ fmem = rte_malloc("pcap_filter", sz, 0);
+ if (!fmem)
+ rte_exit(EXIT_FAILURE, "rte_malloc for filter failed\n");
+
+ rte_memcpy(fmem, fcode.bf_insns, sz);
+ pcap_freecode(&fcode);
+ pcap_close(pcap);
+
+ return fmem;
+}
+
+static void dump_filter(const struct bpf_insn *insn, uint32_t len)
+{
+ unsigned int i;
+
+ if (insn == NULL)
+ rte_exit(EXIT_FAILURE, "no filter specified\n");
+
+ for (i = 0; i < len; insn++, i++)
+ printf("%s\n", bpf_image(insn, i));
+
+ exit(0);
+}
+
+/*
+ * Parse command line options.
+ * These are chosen to be similar to dumpcap command.
+ */
+static void parse_opts(int argc, char **argv)
+{
+ static const struct option long_options[] = {
+ { "capture-comment", required_argument, NULL, 0 },
+ { "help", no_argument, NULL, 'h' },
+ { "version", no_argument, NULL, 'v' },
+ { NULL },
+ };
+ int option_index, c;
+
+ for (;;) {
+ c = getopt_long(argc, argv, "i:f:ds:c:w:gN:pqvhDnP",
+ long_options, &option_index);
+ if (c == -1)
+ break;
+
+ switch (c) {
+ case 0:
+ switch (option_index) {
+ case 0:
+ capture_comment = optarg;
+ break;
+ default:
+ usage();
+ exit(1);
+ }
+ break;
+ case 'i':
+ select_interface(optarg);
+ break;
+ case 'f':
+ filter_str = optarg;
+ break;
+ case 'd':
+ dump_bpf = true;
+ break;
+ case 's':
+ snaplen = get_uint(optarg, "snap_len", 0);
+ break;
+ case 'D':
+ show_interfaces();
+ exit(0);
+ case 'c':
+ packet_count = get_uint(optarg, "packet_count", 0);
+ break;
+ case 'w':
+ output_name = optarg;
+ break;
+ case 'g':
+ group_read = true;
+ break;
+ case 'N':
+ ring_size = get_uint(optarg, "packet_limit", 0);
+ break;
+ case 'p':
+ promiscuous_mode = false;
+ break;
+ case 'q':
+ quiet = true;
+ break;
+ case 'n':
+ use_pcapng = true;
+ break;
+ case 'P':
+ use_pcapng = false;
+ break;
+ case 'v':
+ version();
+ exit(0);
+ case 'h':
+ usage();
+ exit(0);
+ default:
+ fprintf(stderr, "Invalid option: %s", argv[optind - 1]);
+ usage();
+ exit(1);
+ }
+ }
+}
+
+static void
+signal_handler(int sig_num __rte_unused)
+{
+ quit_signal = 1;
+}
+
+static void
+cleanup_pdump_resources(void)
+{
+ struct interface *intf;
+
+ TAILQ_FOREACH(intf, &interfaces, next) {
+ rte_pdump_disable(intf->port,
+ RTE_PDUMP_ALL_QUEUES, RTE_PDUMP_FLAG_RXTX);
+ if (promiscuous_mode)
+ rte_eth_promiscuous_disable(intf->port);
+ }
+}
+
+/* Alarm signal handler, used to check that primary process */
+static void
+monitor_primary(void *arg __rte_unused)
+{
+ if (quit_signal)
+ return;
+
+ if (rte_eal_primary_proc_alive(NULL)) {
+ rte_eal_alarm_set(MONITOR_INTERVAL, monitor_primary, NULL);
+ return;
+ }
+
+ fprintf(stderr, "Primary process is no longer active, exiting...\n");
+ quit_signal = 1;
+}
+
+/* Setup handler to check when primary exits. */
+static void
+enable_primary_monitor(void)
+{
+ int ret;
+
+ /* Once primary exits, so will pdump. */
+ ret = rte_eal_alarm_set(MONITOR_INTERVAL, monitor_primary, NULL);
+ if (ret < 0)
+ fprintf(stderr, "Fail to enable monitor:%d\n", ret);
+}
+
+static void
+disable_primary_monitor(void)
+{
+ int ret;
+
+ ret = rte_eal_alarm_cancel(monitor_primary, NULL);
+ if (ret < 0)
+ fprintf(stderr, "Fail to disable monitor:%d\n", ret);
+}
+
+static void
+print_pdump_stats(void)
+{
+ struct interface *intf;
+
+ fputc('\n', stderr);
+ TAILQ_FOREACH(intf, &interfaces, next) {
+ fprintf(stderr, "Packets received/dropped on interface '%s': "
+ "%"PRIu64 "/%" PRIu64 "\n", intf->name,
+ intf->received, intf->dropped);
+ }
+}
+
+/*
+ * Start DPDK EAL with arguments.
+ * Unlike most DPDK programs, for usabilty,
+ * the arguments to EAL do not come from user command line.
+ */
+static void dpdk_init(void)
+{
+ const char *args[] = {
+ prog,
+ "--log-level", "error",
+ "--proc-type", "secondary",
+ };
+ int eal_argc = RTE_DIM(args);
+ char **eal_argv;
+ size_t i;
+
+ /* Make a mutable copy of args because... */
+ eal_argv = calloc(sizeof(char *), RTE_DIM(args) + 1);
+ if (!eal_argv)
+ rte_exit(EXIT_FAILURE, "EAL arg alloc failed\n");
+
+ for (i = 0; i < RTE_DIM(args); i++)
+ eal_argv[i] = strdup(args[i]);
+
+ if (rte_eal_init(eal_argc, eal_argv) < 0)
+ rte_panic("EAL init failed\n");
+
+ if (rte_eth_dev_count_avail() == 0)
+ rte_exit(EXIT_FAILURE, "No Ethernet ports - bye\n");
+}
+
+/* Create packet ring shared between callbacks and process */
+static struct rte_ring *create_ring(void)
+{
+ struct rte_ring *pring;
+ size_t size, log2;
+
+ /* Find next power of 2 >= size. */
+ size = ring_size;
+ log2 = sizeof(size) * 8 - __builtin_clzl(size - 1);
+ size = 1u << log2;
+
+ if (size != ring_size) {
+ fprintf(stderr, "Ring size %u rounded up to %zu\n",
+ ring_size, size);
+ ring_size = size;
+ }
+
+ pring = rte_ring_lookup(RING_NAME);
+ if (pring == NULL) {
+ pring = rte_ring_create(RING_NAME, ring_size,
+ rte_socket_id(), 0);
+ if (pring == NULL)
+ rte_exit(EXIT_FAILURE, "Could not create ring :%s\n",
+ rte_strerror(rte_errno));
+ }
+ return pring;
+}
+
+static struct rte_mempool *create_mempool(void)
+{
+ static const char pool_name[] = "capture_mbufs";
+ size_t num_mbufs = 2 * ring_size;
+ struct rte_mempool *mp;
+
+ mp = rte_mempool_lookup(pool_name);
+ if (mp)
+ return mp;
+
+ mp = rte_pktmbuf_pool_create_by_ops(pool_name, num_mbufs,
+ MBUF_POOL_CACHE_SIZE, 0,
+ RTE_MIN(snaplen,
+ RTE_MBUF_DEFAULT_BUF_SIZE),
+ rte_socket_id(), "ring_mp_sc");
+ if (mp == NULL)
+ rte_exit(EXIT_FAILURE,
+ "Mempool (%s) creation failed: %s\n", pool_name,
+ rte_strerror(rte_errno));
+
+ return mp;
+}
+
+static rte_pcapng_t *create_output(void)
+{
+ int fd;
+
+ /* If no filename specified make a tempfile name */
+ if (output_name == NULL) {
+ struct interface *intf;
+ struct tm *tm;
+ time_t now;
+ char ts[32];
+
+ intf = TAILQ_FIRST(&interfaces);
+ now = time(NULL);
+ tm = localtime(&now);
+ if (!tm)
+ rte_panic("localtime failed\n");
+
+ strftime(ts, sizeof(ts), "%Y%m%d%H%M%S", tm);
+ if (asprintf(&output_name, "/tmp/%s_%u_%s_%s.pcapng",
+ prog, intf->port, intf->name, ts) < 0)
+ rte_panic("asprintf failed\n");
+ }
+
+ if (strcmp(output_name, "-") == 0)
+ fd = STDOUT_FILENO;
+ else {
+ mode_t mode = group_read ? 0640 : 0600;
+
+ fd = open(output_name, O_WRONLY | O_APPEND | O_CREAT, mode);
+ if (fd < 0)
+ rte_exit(EXIT_FAILURE, "Can not open \"%s\": %s\n",
+ output_name, strerror(errno));
+ }
+
+ return rte_pcapng_fdopen(fd, NULL, NULL, prog, capture_comment, 0);
+}
+
+/*
+ * Take list of interfaces (from command line)
+ * and put records for them at start of capture file.
+ */
+static void dump_interfaces(rte_pcapng_t *out)
+{
+ struct interface *intf;
+
+ TAILQ_FOREACH(intf, &interfaces, next)
+ rte_pcapng_add_interface(out, intf->port, NULL, 0);
+}
+
+static void enable_pdump(struct rte_ring *r, struct rte_mempool *mp,
+ const struct bpf_insn *filter, uint32_t filter_len)
+{
+ struct interface *intf;
+ int ret;
+
+ TAILQ_FOREACH(intf, &interfaces, next) {
+ if (promiscuous_mode)
+ rte_eth_promiscuous_enable(intf->port);
+
+ ret = rte_pdump_enable(intf->port,
+ RTE_PDUMP_ALL_QUEUES,
+ snaplen,
+ RTE_PDUMP_FLAG_RXTX,
+ snaplen,
+ r, mp, filter, filter_len);
+ if (ret < 0)
+ rte_exit(EXIT_FAILURE,
+ "Packet dump enable failed: %s\n",
+ rte_strerror(rte_errno));
+ }
+}
+
+/*
+ * Show current count of captured packets
+ * with backspaces to overwrite last value.
+ */
+static void show_count(uint64_t count)
+{
+ unsigned int i;
+ static unsigned int bt;
+
+ for (i = 0; i < bt; i++)
+ fputc('\b', stderr);
+
+ bt = fprintf(stderr, "%"PRIu64" ", count);
+}
+
+/* Process all packets in ring and dump to capture file */
+static void process_ring(rte_pcapng_t *out, struct rte_ring *r)
+{
+ struct rte_mbuf *pkts[BURST_SIZE];
+ unsigned int i, avail, n;
+ static unsigned int empty_count;
+
+ n = rte_ring_sc_dequeue_burst(r, (void **) pkts, BURST_SIZE,
+ &avail);
+ if (n == 0) {
+ /* don't consume endless amounts of cpu if idle */
+ if (empty_count < SLEEP_THRESHOLD)
+ ++empty_count;
+ else
+ usleep(10);
+ return;
+ }
+
+ empty_count = (avail == 0);
+
+ for (i = 0; i < n; i++) {
+ struct rte_mbuf *m = pkts[i];
+ struct interface *intf;
+
+ intf = port2intf[m->port];
+ if (likely(intf)) {
+ rte_pcapng_dump_packet(out, m->port, m,
+ RTE_PCAPNG_DIR_UNKNOWN, NULL);
+ ++intf->received;
+ }
+ rte_pktmbuf_free(m);
+ }
+
+ packets_received += n;
+
+ if (!quiet)
+ show_count(packets_received);
+}
+
+int main(int argc, char **argv)
+{
+ struct rte_ring *r;
+ struct rte_mempool *mp;
+ rte_pcapng_t *out;
+ struct bpf_insn *bpf_filter = NULL;
+ uint32_t bpf_len = 0;
+
+ prog = basename(argv[0]);
+ dpdk_init();
+
+ parse_opts(argc, argv);
+
+ if (filter_str)
+ bpf_filter = compile_filter(&bpf_len);
+
+ if (dump_bpf)
+ dump_filter(bpf_filter, bpf_len);
+
+ if (TAILQ_EMPTY(&interfaces))
+ set_default_interface();
+
+ r = create_ring();
+ mp = create_mempool();
+ out = create_output();
+ if (out == NULL)
+ rte_exit(EXIT_FAILURE, "can not open output file: %s\n",
+ rte_strerror(rte_errno));
+
+ dump_interfaces(out);
+
+ enable_pdump(r, mp, bpf_filter, bpf_len);
+
+ signal(SIGINT, signal_handler);
+ signal(SIGPIPE, SIG_IGN);
+
+ enable_primary_monitor();
+
+ if (!quiet) {
+ fprintf(stderr, "Packets captured: ");
+ show_count(0);
+ }
+
+ while (!quit_signal) {
+ process_ring(out, r);
+
+ if (packet_count != 0 && packets_received >= packet_count)
+ break;
+ }
+
+ disable_primary_monitor();
+
+ print_pdump_stats();
+
+ rte_pcapng_close(out);
+
+ cleanup_pdump_resources();
+ rte_free(bpf_filter);
+ rte_ring_free(r);
+ rte_mempool_free(mp);
+
+ return rte_eal_cleanup() ? EXIT_FAILURE : 0;
+}
diff --git a/app/capture/meson.build b/app/capture/meson.build
new file mode 100644
index 000000000000..9558f10562bd
--- /dev/null
+++ b/app/capture/meson.build
@@ -0,0 +1,22 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2019 Microsoft Corporation
+pcap_dep = dependency('pcap', required: false)
+if pcap_dep.found()
+ build = true
+else
+ # pcap got a pkg-config file only in 1.9.0 and before that meson uses
+ # an internal pcap-config finder, which is not compatible with
+ # cross-compilation, so try to fallback to find_library
+ pcap_dep = cc.find_library('pcap', required: false)
+ if pcap_dep.found() and cc.has_header('pcap.h', dependencies: pcap_dep)
+ build = true
+ pkgconfig_extra_libs += '-lpcap'
+ else
+ build = false
+ reason = 'missing dependency, "libpcap"'
+ endif
+endif
+
+sources = files('main.c')
+ext_deps += pcap_dep
+deps += ['ethdev', 'pdump', 'pcapng']
diff --git a/app/meson.build b/app/meson.build
index b0e6afbbe9d9..a33198182133 100644
--- a/app/meson.build
+++ b/app/meson.build
@@ -6,6 +6,7 @@ if is_windows
endif
apps = [
+ 'capture',
'pdump',
'proc-info',
'test-acl',
diff --git a/config/common_base b/config/common_base
index 0ccfcfae377d..e1bab8e77988 100644
--- a/config/common_base
+++ b/config/common_base
@@ -1073,3 +1073,8 @@ CONFIG_RTE_APP_CRYPTO_PERF=y
# Compile the eventdev application
#
CONFIG_RTE_APP_EVENTDEV=y
+
+#
+# Compile the capture application
+#
+CONFIG_RTE_APP_CAPTURE=n
--
2.20.1
prev parent reply other threads:[~2019-10-07 16:54 UTC|newest]
Thread overview: 20+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-10-07 16:52 [dpdk-dev] [RFC 0/8] Packet Capture enhancements Stephen Hemminger
2019-10-07 16:52 ` [dpdk-dev] [RFC 1/8] pdump: use new pktmbuf copy function Stephen Hemminger
2019-10-07 16:52 ` [dpdk-dev] [RFC 2/8] pdump: use dynamic logtype Stephen Hemminger
2019-10-07 16:52 ` [dpdk-dev] [RFC 3/8] pdump: tag copied mbuf with port Stephen Hemminger
2019-10-07 16:52 ` [dpdk-dev] [RFC 4/8] pdump: stamp packets with current timestamp Stephen Hemminger
2019-10-07 16:52 ` [dpdk-dev] [RFC 5/8] pdump: add classic BPF filtering Stephen Hemminger
2019-10-07 17:07 ` Jerin Jacob
2019-10-07 17:33 ` Stephen Hemminger
2019-10-07 19:33 ` Jerin Jacob
2019-10-07 21:45 ` Stephen Hemminger
2019-10-08 3:47 ` Jerin Jacob
2019-10-08 4:01 ` Stephen Hemminger
2019-10-08 4:15 ` Jerin Jacob
2019-10-08 4:22 ` Stephen Hemminger
2019-10-08 21:08 ` Morten Brørup
2019-10-09 8:21 ` Ananyev, Konstantin
2019-10-09 14:59 ` Stephen Hemminger
2019-10-07 16:52 ` [dpdk-dev] [RFC 6/8] pdump: add packet header truncation Stephen Hemminger
2019-10-07 16:52 ` [dpdk-dev] [RFC 7/8] pcapng: add new library for writing pcapng files Stephen Hemminger
2019-10-07 16:52 ` Stephen Hemminger [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20191007165232.14535-9-stephen@networkplumber.org \
--to=stephen@networkplumber.org \
--cc=dev@dpdk.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.