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:53 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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).