From patchwork Wed Oct 14 12:06:27 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stuart Haslam X-Patchwork-Id: 54909 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-lb0-f198.google.com (mail-lb0-f198.google.com [209.85.217.198]) by patches.linaro.org (Postfix) with ESMTPS id 80B8E23012 for ; Wed, 14 Oct 2015 12:08:12 +0000 (UTC) Received: by lbcao8 with SMTP id ao8sf24714945lbc.1 for ; Wed, 14 Oct 2015 05:08:11 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:delivered-to:delivered-to:from:to:date :message-id:in-reply-to:references:subject:precedence:list-id :list-unsubscribe:list-archive:list-post:list-help:list-subscribe :mime-version:content-type:content-transfer-encoding:errors-to :sender:x-original-sender:x-original-authentication-results :mailing-list; bh=ux0Xmd4Sk2/6CBFsN8UN0OlsCz9jttNBTprUP9f00Ao=; b=UmzRARgFN4es+j86fRI9YEThNRrTDM8SzVMMdLZ0dXM9Z7slnph0G2UsNQDiLH26eX 3ZTEuIVWDHAAomGaNvh5DD2QAKtKDgC6Ei5LBDWNlDj+64k1ewOvVt6WlSVG9AUdC7MT 4WwQIbr0hbOWF0CJw09oqEb+jnEI8FgVgw061oydWz41vGdjo865rp/ZTkhRC2yIVve4 GSzoiHzH01qY6tgdd6BwIQku8wGEEjj5QCQvdSO+OpcvK2XkKRdkCc7DgkqmkdqRNNKg zRp6mNRmPD7Q4i0Rhgwyo1KrT7ZC975P0XT8RDVJhkUOR1ylIIHAXKUKSJzlY0QZppse UvTQ== X-Gm-Message-State: ALoCoQlnOXhT/d+nlsr5uQXsZlPdV1PNqhnN2PH1y2VSq+WgpfawQwQyHIpYeM0OKG0NDJCsTUDy X-Received: by 10.194.94.66 with SMTP id da2mr676587wjb.7.1444824491279; Wed, 14 Oct 2015 05:08:11 -0700 (PDT) X-BeenThere: patchwork-forward@linaro.org Received: by 10.25.153.196 with SMTP id b187ls32929lfe.80.gmail; Wed, 14 Oct 2015 05:08:11 -0700 (PDT) X-Received: by 10.25.159.16 with SMTP id i16mr903047lfe.63.1444824491107; Wed, 14 Oct 2015 05:08:11 -0700 (PDT) Received: from mail-lb0-f176.google.com (mail-lb0-f176.google.com. [209.85.217.176]) by mx.google.com with ESMTPS id j7si5333676lbd.92.2015.10.14.05.08.11 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 14 Oct 2015 05:08:11 -0700 (PDT) Received-SPF: pass (google.com: domain of patch+caf_=patchwork-forward=linaro.org@linaro.org designates 209.85.217.176 as permitted sender) client-ip=209.85.217.176; Received: by lbwr8 with SMTP id r8so44336727lbw.2 for ; Wed, 14 Oct 2015 05:08:11 -0700 (PDT) X-Received: by 10.112.199.137 with SMTP id jk9mr1421564lbc.86.1444824490923; Wed, 14 Oct 2015 05:08:10 -0700 (PDT) X-Forwarded-To: patchwork-forward@linaro.org X-Forwarded-For: patch@linaro.org patchwork-forward@linaro.org Delivered-To: patch@linaro.org Received: by 10.112.59.35 with SMTP id w3csp2691497lbq; Wed, 14 Oct 2015 05:08:09 -0700 (PDT) X-Received: by 10.140.218.133 with SMTP id o127mr3631777qhb.4.1444824489474; Wed, 14 Oct 2015 05:08:09 -0700 (PDT) Received: from lists.linaro.org (lists.linaro.org. [54.225.227.206]) by mx.google.com with ESMTP id x130si2957271qha.40.2015.10.14.05.08.09; Wed, 14 Oct 2015 05:08:09 -0700 (PDT) Received-SPF: pass (google.com: domain of lng-odp-bounces@lists.linaro.org designates 54.225.227.206 as permitted sender) client-ip=54.225.227.206; Received: by lists.linaro.org (Postfix, from userid 109) id 0395C61B7D; Wed, 14 Oct 2015 12:08:09 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on ip-10-142-244-252 X-Spam-Level: X-Spam-Status: No, score=-2.6 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_LOW, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, URIBL_BLOCKED autolearn=disabled version=3.4.0 Received: from [127.0.0.1] (localhost [127.0.0.1]) by lists.linaro.org (Postfix) with ESMTP id 1EA2161C7B; Wed, 14 Oct 2015 12:06:55 +0000 (UTC) X-Original-To: lng-odp@lists.linaro.org Delivered-To: lng-odp@lists.linaro.org Received: by lists.linaro.org (Postfix, from userid 109) id C534661C7B; Wed, 14 Oct 2015 12:06:45 +0000 (UTC) Received: from mail-wi0-f172.google.com (mail-wi0-f172.google.com [209.85.212.172]) by lists.linaro.org (Postfix) with ESMTPS id 4002761B6B for ; Wed, 14 Oct 2015 12:06:43 +0000 (UTC) Received: by wijq8 with SMTP id q8so78394980wij.0 for ; Wed, 14 Oct 2015 05:06:42 -0700 (PDT) X-Received: by 10.194.184.73 with SMTP id es9mr4320394wjc.122.1444824402108; Wed, 14 Oct 2015 05:06:42 -0700 (PDT) Received: from e106441.emea.arm.com ([2001:41d0:a:3cb4::abcd]) by smtp.gmail.com with ESMTPSA id gn9sm2638958wib.0.2015.10.14.05.06.41 (version=TLSv1/SSLv3 cipher=OTHER); Wed, 14 Oct 2015 05:06:41 -0700 (PDT) From: Stuart Haslam To: lng-odp@lists.linaro.org Date: Wed, 14 Oct 2015 13:06:27 +0100 Message-Id: <1444824388-25708-4-git-send-email-stuart.haslam@linaro.org> X-Mailer: git-send-email 2.1.1 In-Reply-To: <1444824388-25708-1-git-send-email-stuart.haslam@linaro.org> References: <1444824388-25708-1-git-send-email-stuart.haslam@linaro.org> X-Topics: patch Subject: [lng-odp] [PATCHv3 3/4] linux-generic: pktio: add pcap pktio type X-BeenThere: lng-odp@lists.linaro.org X-Mailman-Version: 2.1.16 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: , List-Help: , List-Subscribe: , MIME-Version: 1.0 Errors-To: lng-odp-bounces@lists.linaro.org Sender: "lng-odp" X-Removed-Original-Auth: Dkim didn't pass. X-Original-Sender: stuart.haslam@linaro.org X-Original-Authentication-Results: mx.google.com; spf=pass (google.com: domain of patch+caf_=patchwork-forward=linaro.org@linaro.org designates 209.85.217.176 as permitted sender) smtp.mailfrom=patch+caf_=patchwork-forward=linaro.org@linaro.org Mailing-list: list patchwork-forward@linaro.org; contact patchwork-forward+owners@linaro.org X-Google-Group-Id: 836684582541 Create a new pktio type that allows for reading from and writing to a pcap capture file. This is intended to be used as a simple way of injecting test packets into an application for functional testing and can be used as it is with some of the existing example applications. To use this interface the name passed to odp_pktio_open() must begin with "pcap:" and be in the format; pcap:in=test.pcap:out=test_out.pcap:loops=10 in the name of the input pcap file. If no input file is given attempts to receive from the pktio will just return no packets. out the name of the output pcap file. If no output file is given any packets transmitted over the interface will just be freed. loops the number of times to iterate through the input file, set to 0 to loop indefinitely. The default value is 1. Signed-off-by: Stuart Haslam --- platform/linux-generic/Makefile.am | 4 + .../linux-generic/include/odp_packet_io_internal.h | 21 ++ platform/linux-generic/m4/configure.m4 | 1 + platform/linux-generic/m4/odp_pcap.m4 | 15 + platform/linux-generic/pktio/io_ops.c | 3 + platform/linux-generic/pktio/pcap.c | 377 +++++++++++++++++++++ 6 files changed, 421 insertions(+) create mode 100644 platform/linux-generic/m4/odp_pcap.m4 create mode 100644 platform/linux-generic/pktio/pcap.c diff --git a/platform/linux-generic/Makefile.am b/platform/linux-generic/Makefile.am index 2a71d32..dfb5a91 100644 --- a/platform/linux-generic/Makefile.am +++ b/platform/linux-generic/Makefile.am @@ -175,3 +175,7 @@ EXTRA_DIST = \ arch/linux/odp_time_cycles.c \ arch/mips64/odp_time_cycles.c \ arch/x86/odp_time_cycles.c + +if HAVE_PCAP +__LIB__libodp_la_SOURCES += pktio/pcap.c +endif diff --git a/platform/linux-generic/include/odp_packet_io_internal.h b/platform/linux-generic/include/odp_packet_io_internal.h index 590b816..4745bd5 100644 --- a/platform/linux-generic/include/odp_packet_io_internal.h +++ b/platform/linux-generic/include/odp_packet_io_internal.h @@ -40,6 +40,21 @@ typedef struct { odp_bool_t promisc; /**< promiscuous mode state */ } pkt_loop_t; +#ifdef HAVE_PCAP +typedef struct { + char *fname_rx; /**< name of pcap file for rx */ + char *fname_tx; /**< name of pcap file for tx */ + void *rx; /**< rx pcap handle */ + void *tx; /**< tx pcap handle */ + void *tx_dump; /**< tx pcap dumper handle */ + odp_pool_t pool; /**< rx pool */ + unsigned char *buf; /**< per-pktio temp buffer */ + int loops; /**< number of times to loop rx pcap */ + int loop_cnt; /**< number of loops completed */ + odp_bool_t promisc; /**< promiscuous mode state */ +} pkt_pcap_t; +#endif + struct pktio_entry { const struct pktio_if_ops *ops; /**< Implementation specific methods */ odp_ticketlock_t lock; /**< entry ticketlock */ @@ -54,6 +69,9 @@ struct pktio_entry { pkt_sock_mmap_t pkt_sock_mmap; /**< using socket mmap * API for IO */ pkt_netmap_t pkt_nm; /**< using netmap API for IO */ +#ifdef HAVE_PCAP + pkt_pcap_t pkt_pcap; /**< Using pcap for IO */ +#endif }; enum { STATE_START = 0, @@ -130,6 +148,9 @@ extern const pktio_if_ops_t netmap_pktio_ops; extern const pktio_if_ops_t sock_mmsg_pktio_ops; extern const pktio_if_ops_t sock_mmap_pktio_ops; extern const pktio_if_ops_t loopback_pktio_ops; +#ifdef HAVE_PCAP +extern const pktio_if_ops_t pcap_pktio_ops; +#endif extern const pktio_if_ops_t * const pktio_if_ops[]; #ifdef __cplusplus diff --git a/platform/linux-generic/m4/configure.m4 b/platform/linux-generic/m4/configure.m4 index f2d42f1..df6dc64 100644 --- a/platform/linux-generic/m4/configure.m4 +++ b/platform/linux-generic/m4/configure.m4 @@ -19,6 +19,7 @@ AC_LINK_IFELSE( m4_include([platform/linux-generic/m4/odp_pthread.m4]) m4_include([platform/linux-generic/m4/odp_openssl.m4]) m4_include([platform/linux-generic/m4/odp_netmap.m4]) +m4_include([platform/linux-generic/m4/odp_pcap.m4]) AC_CONFIG_FILES([platform/linux-generic/Makefile platform/linux-generic/test/Makefile diff --git a/platform/linux-generic/m4/odp_pcap.m4 b/platform/linux-generic/m4/odp_pcap.m4 new file mode 100644 index 0000000..734b790 --- /dev/null +++ b/platform/linux-generic/m4/odp_pcap.m4 @@ -0,0 +1,15 @@ +######################################################################### +# Check for libpcap availability +######################################################################### +have_pcap=no +AC_CHECK_HEADER(pcap/pcap.h, + [AC_CHECK_HEADER(pcap/bpf.h, + [AC_CHECK_LIB(pcap, pcap_open_offline, have_pcap=yes, [])], + [])], +[]) + +AM_CONDITIONAL([HAVE_PCAP], [test $have_pcap = yes]) +if test $have_pcap == yes; then + AM_CFLAGS="$AM_CFLAGS -DHAVE_PCAP" + LIBS="$LIBS -lpcap" +fi diff --git a/platform/linux-generic/pktio/io_ops.c b/platform/linux-generic/pktio/io_ops.c index bd4cc48..3b344e6 100644 --- a/platform/linux-generic/pktio/io_ops.c +++ b/platform/linux-generic/pktio/io_ops.c @@ -15,6 +15,9 @@ const pktio_if_ops_t * const pktio_if_ops[] = { #ifdef ODP_NETMAP &netmap_pktio_ops, #endif +#ifdef HAVE_PCAP + &pcap_pktio_ops, +#endif &sock_mmap_pktio_ops, &sock_mmsg_pktio_ops, NULL diff --git a/platform/linux-generic/pktio/pcap.c b/platform/linux-generic/pktio/pcap.c new file mode 100644 index 0000000..91720ba --- /dev/null +++ b/platform/linux-generic/pktio/pcap.c @@ -0,0 +1,377 @@ +/* Copyright (c) 2015, Linaro Limited + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/** + * @file + * + * PCAP pktio type + * + * This file provides a pktio interface that allows for reading from + * and writing to pcap capture files. It is intended to be used as + * simple way of injecting test packets into an application for the + * purpose of functional testing. + * + * To use this interface the name passed to odp_pktio_open() must begin + * with "pcap:" and be in the format; + * + * pcap:in=test.pcap:out=test_out.pcap:loops=10 + * + * in the name of the input pcap file. If no input file is given + * attempts to receive from the pktio will just return no + * packets. If an input file is specified it must exist and be + * a readable pcap file with a link type of DLT_EN10MB. + * out the name of the output pcap file. If no output file is + * given any packets transmitted over the interface will just + * be freed. If an output file is specified and the file + * doesn't exist it will be created, if it does exist it will + * be overwritten. + * loops the number of times to iterate through the input file, set + * to 0 to loop indefinitely. The default value is 1. + * + * The total length of the string is limited by PKTIO_NAME_LEN. + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include +#include +#include + +#include + +#include +#include +#include + +#define PKTIO_PCAP_MTU (64 * 1024) +static const char pcap_mac[] = {0x02, 0xe9, 0x34, 0x80, 0x73, 0x04}; + +static int _pcapif_parse_devname(pkt_pcap_t *pcap, const char *devname) +{ + char *tok; + char in[PKTIO_NAME_LEN]; + + if (strncmp(devname, "pcap:", 5) != 0) + return -1; + + snprintf(in, sizeof(in), "%s", devname); + + for (tok = strtok(in + 5, ":"); tok; tok = strtok(NULL, ":")) { + if (strncmp(tok, "in=", 3) == 0 && !pcap->fname_rx) { + tok += 3; + pcap->fname_rx = strdup(tok); + } else if (strncmp(tok, "out=", 4) == 0 && !pcap->fname_tx) { + tok += 4; + pcap->fname_tx = strdup(tok); + } else if (strncmp(tok, "loops=", 6) == 0) { + pcap->loops = atoi(tok + 6); + if (pcap->loops < 0) { + ODP_ERR("invalid loop count\n"); + return -1; + } + } + } + + return 0; +} + +static int _pcapif_init_rx(pkt_pcap_t *pcap) +{ + char errbuf[PCAP_ERRBUF_SIZE]; + int linktype; + + pcap->rx = pcap_open_offline(pcap->fname_rx, errbuf); + if (!pcap->rx) { + ODP_ERR("failed to open pcap file %s (%s)\n", + pcap->fname_rx, errbuf); + return -1; + } + + linktype = pcap_datalink(pcap->rx); + if (linktype != DLT_EN10MB) { + ODP_ERR("unsupported datalink type: %d\n", linktype); + return -1; + } + + return 0; +} + +static int _pcapif_init_tx(pkt_pcap_t *pcap) +{ + pcap_t *tx = pcap->rx; + + if (!tx) { + /* if there is no rx pcap_t already open for rx, a dummy + * one needs to be opened for writing the dump */ + tx = pcap_open_dead(DLT_EN10MB, PKTIO_PCAP_MTU); + if (!tx) { + ODP_ERR("failed to open TX dump\n"); + return -1; + } + + pcap->tx = tx; + } + + pcap->buf = malloc(PKTIO_PCAP_MTU); + if (!pcap->buf) { + ODP_ERR("failed to malloc temp buffer\n"); + return -1; + } + + pcap->tx_dump = pcap_dump_open(tx, pcap->fname_tx); + if (!pcap->tx_dump) { + ODP_ERR("failed to open dump file %s (%s)\n", + pcap->fname_tx, pcap_geterr(tx)); + return -1; + } + + return pcap_dump_flush(pcap->tx_dump); +} + +static int pcapif_init(odp_pktio_t id ODP_UNUSED, pktio_entry_t *pktio_entry, + const char *devname, odp_pool_t pool) +{ + pkt_pcap_t *pcap = &pktio_entry->s.pkt_pcap; + int ret; + + memset(pcap, 0, sizeof(pkt_pcap_t)); + pcap->loop_cnt = 1; + pcap->loops = 1; + pcap->pool = pool; + pcap->promisc = 1; + + ret = _pcapif_parse_devname(pcap, devname); + + if (ret == 0 && pcap->fname_rx) + ret = _pcapif_init_rx(pcap); + + if (ret == 0 && pcap->fname_tx) + ret = _pcapif_init_tx(pcap); + + if (ret == 0 && (!pcap->rx && !pcap->tx_dump)) + ret = -1; + + return ret; +} + +static int pcapif_close(pktio_entry_t *pktio_entry) +{ + pkt_pcap_t *pcap = &pktio_entry->s.pkt_pcap; + + if (pcap->tx_dump) + pcap_dump_close(pcap->tx_dump); + + if (pcap->tx) + pcap_close(pcap->tx); + + if (pcap->rx) + pcap_close(pcap->rx); + + free(pcap->buf); + free(pcap->fname_rx); + free(pcap->fname_tx); + + return 0; +} + +static int _pcapif_reopen(pkt_pcap_t *pcap) +{ + char errbuf[PCAP_ERRBUF_SIZE]; + + if (pcap->loops != 0 && ++pcap->loop_cnt >= pcap->loops) + return 1; + + if (pcap->rx) + pcap_close(pcap->rx); + + pcap->rx = pcap_open_offline(pcap->fname_rx, errbuf); + if (!pcap->rx) { + ODP_ERR("failed to reopen pcap file %s (%s)\n", + pcap->fname_rx, errbuf); + return 1; + } + + return 0; +} + +static int pcapif_recv_pkt(pktio_entry_t *pktio_entry, odp_packet_t pkts[], + unsigned len) +{ + unsigned i; + struct pcap_pkthdr *hdr; + const u_char *data; + odp_packet_t pkt; + uint32_t pkt_len; + pkt_pcap_t *pcap = &pktio_entry->s.pkt_pcap; + + ODP_ASSERT(pktio_entry->s.state == STATE_START); + + if (!pcap->rx) + return 0; + + pkt = ODP_PACKET_INVALID; + pkt_len = 0; + + for (i = 0; i < len; ) { + int ret; + + if (pkt == ODP_PACKET_INVALID) { + pkt = _odp_packet_alloc(pcap->pool); + if (odp_unlikely(pkt == ODP_PACKET_INVALID)) + break; + pkt_len = odp_packet_len(pkt); + } + + ret = pcap_next_ex(pcap->rx, &hdr, &data); + + /* end of file, attempt to reopen if within loop limit */ + if (ret == -2 && _pcapif_reopen(pcap) == 0) + continue; + + if (ret != 1) + break; + + if (!odp_packet_pull_tail(pkt, pkt_len - hdr->caplen)) { + ODP_ERR("failed to pull tail: pkt_len: %d caplen: %d\n", + pkt_len, hdr->caplen); + break; + } + + if (odp_packet_copydata_in(pkt, 0, hdr->caplen, data) != 0) { + ODP_ERR("failed to copy packet data\n"); + break; + } + + _odp_packet_reset_parse(pkt); + pkts[i] = pkt; + pkt = ODP_PACKET_INVALID; + + i++; + } + + if (pkt != ODP_PACKET_INVALID) + odp_packet_free(pkt); + + return i; +} + +static int _pcapif_dump_pkt(pkt_pcap_t *pcap, odp_packet_t pkt) +{ + struct pcap_pkthdr hdr; + + if (!pcap->tx_dump) + return 0; + + hdr.caplen = odp_packet_len(pkt); + hdr.len = hdr.caplen; + (void)gettimeofday(&hdr.ts, NULL); + + if (odp_packet_copydata_out(pkt, 0, hdr.len, pcap->buf) != 0) + return -1; + + pcap_dump(pcap->tx_dump, &hdr, pcap->buf); + (void)pcap_dump_flush(pcap->tx_dump); + + return 0; +} + +static int pcapif_send_pkt(pktio_entry_t *pktio_entry, odp_packet_t pkts[], + unsigned len) +{ + pkt_pcap_t *pcap = &pktio_entry->s.pkt_pcap; + unsigned i; + + ODP_ASSERT(pktio_entry->s.state == STATE_START); + + for (i = 0; i < len; ++i) { + if (odp_packet_len(pkts[i]) > PKTIO_PCAP_MTU) { + if (i == 0) + return -1; + break; + } + + if (_pcapif_dump_pkt(pcap, pkts[i]) != 0) + break; + + odp_packet_free(pkts[i]); + } + + return i; +} + +static int pcapif_mtu_get(pktio_entry_t *pktio_entry ODP_UNUSED) +{ + return PKTIO_PCAP_MTU; +} + +static int pcapif_mac_addr_get(pktio_entry_t *pktio_entry ODP_UNUSED, + void *mac_addr) +{ + memcpy(mac_addr, pcap_mac, ODPH_ETHADDR_LEN); + + return ODPH_ETHADDR_LEN; +} + +static int pcapif_promisc_mode_set(pktio_entry_t *pktio_entry, + odp_bool_t enable) +{ + char filter_exp[64] = {0}; + struct bpf_program bpf; + pkt_pcap_t *pcap = &pktio_entry->s.pkt_pcap; + + if (!pcap->rx) { + pcap->promisc = enable; + return 0; + } + + if (!enable) { + char mac_str[18]; + + snprintf(mac_str, sizeof(mac_str), + "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx", + pcap_mac[0], pcap_mac[1], pcap_mac[2], + pcap_mac[3], pcap_mac[4], pcap_mac[5]); + + snprintf(filter_exp, sizeof(filter_exp), + "ether dst %s or broadcast or multicast", + mac_str); + } + + if (pcap_compile(pcap->rx, &bpf, filter_exp, + 0, PCAP_NETMASK_UNKNOWN) != 0) { + ODP_ERR("failed to compile promisc mode filter: %s\n", + pcap_geterr(pcap->rx)); + return -1; + } + + if (pcap_setfilter(pcap->rx, &bpf) != 0) { + ODP_ERR("failed to set promisc mode filter: %s\n", + pcap_geterr(pcap->rx)); + return -1; + } + + pcap->promisc = enable; + + return 0; +} + +static int pcapif_promisc_mode_get(pktio_entry_t *pktio_entry) +{ + return pktio_entry->s.pkt_pcap.promisc; +} + +const pktio_if_ops_t pcap_pktio_ops = { + .open = pcapif_init, + .close = pcapif_close, + .recv = pcapif_recv_pkt, + .send = pcapif_send_pkt, + .mtu_get = pcapif_mtu_get, + .promisc_mode_set = pcapif_promisc_mode_set, + .promisc_mode_get = pcapif_promisc_mode_get, + .mac_get = pcapif_mac_addr_get +};