Index: sys/dev/ixgbe/ixgbe.h =================================================================== --- sys/dev/ixgbe/ixgbe.h +++ sys/dev/ixgbe/ixgbe.h @@ -90,8 +90,11 @@ #include #include #include +#include +#include #include "ixgbe_api.h" +#include "ixgbe_ioctl.h" /* Tunables */ @@ -457,8 +460,17 @@ unsigned long link_irq; struct ixgbe_hw_stats stats; + + struct cdev *cdev; + TAILQ_HEAD(, ix_filter_entry) filter_list; + struct mtx filter_mtx; + unsigned next_filter_id; }; +struct ix_filter_entry { + TAILQ_ENTRY(ix_filter_entry) link; + struct ix_filter filter; +}; /* Precision Time Sync (IEEE 1588) defines */ #define ETHERTYPE_IEEE1588 0x88F7 Index: sys/dev/ixgbe/ixgbe.c =================================================================== --- sys/dev/ixgbe/ixgbe.c +++ sys/dev/ixgbe/ixgbe.c @@ -205,7 +205,9 @@ static void ixgbe_handle_mod(void *, int); #ifdef IXGBE_FDIR +#ifdef IXGBE_FDIR_ATR static void ixgbe_atr(struct tx_ring *, struct mbuf *); +#endif static void ixgbe_reinit_fdir(void *, int); #endif @@ -229,6 +231,19 @@ "ix", ixgbe_methods, sizeof(struct adapter), }; +static d_ioctl_t ixgbe_extension_ioctl; +static d_open_t ixgbe_extension_open; +static d_close_t ixgbe_extension_close; + +static struct cdevsw ixgbe_cdevsw = { + .d_version = D_VERSION, + .d_flags = 0, + .d_open = ixgbe_extension_open, + .d_close = ixgbe_extension_close, + .d_ioctl = ixgbe_extension_ioctl, + .d_name = "ixgbe", +}; + devclass_t ixgbe_devclass; DRIVER_MODULE(ixgbe, pci, ixgbe_driver, ixgbe_devclass, 0, 0); @@ -337,6 +352,7 @@ static int ixgbe_total_ports; #ifdef IXGBE_FDIR +#ifdef IXGBE_FDIR_ATR /* ** For Flow Director: this is the ** number of TX packets we sample @@ -347,6 +363,7 @@ ** setting this to 0. */ static int atr_sample_rate = 20; +#endif /* ** Flow Director actually 'steals' ** part of the packet buffer as its @@ -421,6 +438,20 @@ return (ENXIO); } +static int +ixgbe_makedev(struct adapter *adapter) +{ + adapter->cdev = make_dev(&ixgbe_cdevsw, adapter->ifp->if_dunit, + UID_ROOT, GID_WHEEL, 0600, "%s", if_name(adapter->ifp)); + + if (adapter->cdev == NULL) + return (ENOMEM); + + adapter->cdev->si_drv1 = (void *)adapter; + + return (0); +} + /********************************************************************* * Device initialization routine * @@ -624,6 +655,14 @@ #ifdef DEV_NETMAP ixgbe_netmap_attach(adapter); #endif /* DEV_NETMAP */ + + error = ixgbe_makedev(adapter); + if (error) + goto err_late; + + mtx_init(&adapter->filter_mtx, "filter_mtx", NULL, MTX_DEF); + TAILQ_INIT(&adapter->filter_list); + INIT_DEBUGOUT("ixgbe_attach: end"); return (0); err_late: @@ -1860,7 +1899,7 @@ return (error); } -#ifdef IXGBE_FDIR +#ifdef IXGBE_FDIR_ATR /* Do the flow director magic */ if ((txr->atr_sample) && (!adapter->fdir_reinit)) { ++txr->atr_count; @@ -3169,7 +3208,7 @@ txbuf->eop = NULL; } -#ifdef IXGBE_FDIR +#ifdef IXGBE_FDIR_ATR /* Set the rate at which we sample packets */ if (adapter->hw.mac.type != ixgbe_mac_82598EB) txr->atr_sample = atr_sample_rate; @@ -3589,7 +3628,7 @@ return (0); } -#ifdef IXGBE_FDIR +#ifdef IXGBE_FDIR_ATR /* ** This routine parses packet headers so that Flow ** Director can make a hashed filter table entry @@ -5489,13 +5528,33 @@ adapter->stats.xec += IXGBE_READ_REG(hw, IXGBE_XEC); adapter->stats.fccrc += IXGBE_READ_REG(hw, IXGBE_FCCRC); adapter->stats.fclast += IXGBE_READ_REG(hw, IXGBE_FCLAST); - /* Only read FCOE on 82599 */ + /* Only read FCOE/FDIR on 82599 */ if (hw->mac.type != ixgbe_mac_82598EB) { adapter->stats.fcoerpdc += IXGBE_READ_REG(hw, IXGBE_FCOERPDC); adapter->stats.fcoeprc += IXGBE_READ_REG(hw, IXGBE_FCOEPRC); adapter->stats.fcoeptc += IXGBE_READ_REG(hw, IXGBE_FCOEPTC); adapter->stats.fcoedwrc += IXGBE_READ_REG(hw, IXGBE_FCOEDWRC); adapter->stats.fcoedwtc += IXGBE_READ_REG(hw, IXGBE_FCOEDWTC); + adapter->stats.fdirfree_free = + (IXGBE_READ_REG(hw, IXGBE_FDIRFREE) & IXGBE_FDIRFREE_FREE_MASK) + >> IXGBE_FDIRFREE_FREE_SHIFT; + adapter->stats.fdirfree_coll = + (IXGBE_READ_REG(hw, IXGBE_FDIRFREE) & IXGBE_FDIRFREE_COLL_MASK) + >> IXGBE_FDIRFREE_COLL_SHIFT; + adapter->stats.fdirustat_add += + (IXGBE_READ_REG(hw, IXGBE_FDIRUSTAT) & IXGBE_FDIRUSTAT_ADD_MASK) + >> IXGBE_FDIRUSTAT_ADD_SHIFT; + adapter->stats.fdirustat_remove += + (IXGBE_READ_REG(hw, IXGBE_FDIRUSTAT) & IXGBE_FDIRUSTAT_REMOVE_MASK) + >> IXGBE_FDIRUSTAT_REMOVE_SHIFT; + adapter->stats.fdirfstat_fadd += + (IXGBE_READ_REG(hw, IXGBE_FDIRFSTAT) & IXGBE_FDIRFSTAT_FADD_MASK) + >> IXGBE_FDIRFSTAT_FADD_SHIFT; + adapter->stats.fdirfstat_fremove += + (IXGBE_READ_REG(hw, IXGBE_FDIRFSTAT) & IXGBE_FDIRFSTAT_FREMOVE_MASK) + >> IXGBE_FDIRFSTAT_FREMOVE_SHIFT; + adapter->stats.fdirmatch += IXGBE_READ_REG(hw, IXGBE_FDIRMATCH); + adapter->stats.fdirmiss += IXGBE_READ_REG(hw, IXGBE_FDIRMISS); } /* Fill out the OS statistics structure */ @@ -5861,6 +5920,32 @@ SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_1024_1522", CTLFLAG_RD, &stats->ptc1522, "1024-1522 byte frames transmitted"); + + /* fdir stats */ + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "fdirfree_free", + CTLFLAG_RD, &stats->fdirfree_free, + ""); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "fdirfree_coll", + CTLFLAG_RD, &stats->fdirfree_coll, + ""); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "fdirustat_add", + CTLFLAG_RD, &stats->fdirustat_add, + ""); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "fdirustat_remove", + CTLFLAG_RD, &stats->fdirustat_remove, + ""); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "fdirfstat_fadd", + CTLFLAG_RD, &stats->fdirfstat_fadd, + ""); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "fdirfstat_fremove", + CTLFLAG_RD, &stats->fdirfstat_fremove, + ""); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "fdirmatch", + CTLFLAG_RD, &stats->fdirmatch, + ""); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "fdirmiss", + CTLFLAG_RD, &stats->fdirmiss, + ""); } /* @@ -6011,6 +6096,140 @@ } } +static int +ixgbe_extension_open(struct cdev *dev, int flags, int fmp, struct thread *td) +{ + return (0); +} + +static int +ixgbe_extension_close(struct cdev *dev, int flags, int fmt, struct thread *td) +{ + return (0); +} + +static struct ix_filter_entry * +ixgbe_find_filter(struct adapter *adapter, unsigned id) +{ + struct ix_filter_entry *entry; + + TAILQ_FOREACH(entry, &adapter->filter_list, link) + if (entry->filter.id == id) + return entry; + return NULL; +} + +static int +ixgbe_extension_ioctl(struct cdev *dev, unsigned long cmd, caddr_t data, + int fflag, struct thread *td) +{ + struct adapter *adapter = (struct adapter *)dev->si_drv1; + int error = 0; + + if (priv_check(td, PRIV_DRIVER)) { + return (EPERM); + } + + mtx_lock(&adapter->filter_mtx); + switch (cmd) { + case IXGBE_ADD_SIGFILTER: { + struct ix_filter *filter = (struct ix_filter *)data; + struct ix_filter_entry *entry; + union ixgbe_atr_hash_dword input = {.dword = 0}; + union ixgbe_atr_hash_dword common = {.dword = 0}; + + switch (filter->proto) { + case IXGBE_FILTER_PROTO_TCPV4: + input.formatted.flow_type ^= IXGBE_ATR_FLOW_TYPE_TCPV4; + break; + case IXGBE_FILTER_PROTO_UDPV4: + input.formatted.flow_type ^= IXGBE_ATR_FLOW_TYPE_UDPV4; + break; + default: + error = EINVAL; + goto out; + } + common.port.src ^= htons(filter->src_port); + common.port.dst ^= htons(filter->dst_port); + common.flex_bytes ^= htons(ETHERTYPE_IP); + common.ip ^= filter->src_ip.s_addr ^ filter->dst_ip.s_addr; + + entry = malloc(sizeof(*entry), M_DEVBUF, M_NOWAIT | M_ZERO); + if (!entry) { + error = ENOMEM; + goto out; + } + memcpy(&entry->filter, filter, sizeof(entry->filter)); + entry->filter.id = adapter->next_filter_id++; + TAILQ_INSERT_TAIL(&adapter->filter_list, entry, link); + + ixgbe_fdir_add_signature_filter_82599(&adapter->hw, + input, common, filter->que_index); + break; + } + case IXGBE_GET_SIGFILTER: { + struct ix_filter *filter = (struct ix_filter *)data; + struct ix_filter_entry *entry; + + entry = ixgbe_find_filter(adapter, filter->id); + if (entry) + memcpy(filter, &entry->filter, sizeof(*filter)); + else + error = ENOENT; + break; + }; + case IXGBE_CLR_SIGFILTER: { + unsigned *id = (unsigned *)data; + struct ix_filter_entry *entry; + union ixgbe_atr_hash_dword input = {.dword = 0}; + union ixgbe_atr_hash_dword common = {.dword = 0}; + + entry = ixgbe_find_filter(adapter, *id); + if (!entry) { + error = ENOENT; + goto out; + } + + switch (entry->filter.proto) { + case IXGBE_FILTER_PROTO_TCPV4: + input.formatted.flow_type ^= IXGBE_ATR_FLOW_TYPE_TCPV4; + break; + case IXGBE_FILTER_PROTO_UDPV4: + input.formatted.flow_type ^= IXGBE_ATR_FLOW_TYPE_UDPV4; + break; + default: + error = EINVAL; + goto out; + } + common.port.src ^= htons(entry->filter.src_port); + common.port.dst ^= htons(entry->filter.dst_port); + common.flex_bytes ^= htons(ETHERTYPE_IP); + common.ip ^= entry->filter.src_ip.s_addr + ^ entry->filter.dst_ip.s_addr; + + ixgbe_fdir_erase_signature_filter_82599(&adapter->hw, + input, common); + + TAILQ_REMOVE(&adapter->filter_list, entry, link); + break; + } + case IXGBE_GET_SIGFILTER_LEN: { + unsigned *id = (unsigned *)data; + + *id = adapter->next_filter_id; + break; + } + default: + error = EOPNOTSUPP; + break; + } + +out: + mtx_unlock(&adapter->filter_mtx); + return (error); +} + + static void ixgbe_disable_rx_drop(struct adapter *adapter) { Index: sys/dev/ixgbe/ixgbe_82599.c =================================================================== --- sys/dev/ixgbe/ixgbe_82599.c +++ sys/dev/ixgbe/ixgbe_82599.c @@ -1482,7 +1482,8 @@ * Set the maximum length per hash bucket to 0xA filters * Send interrupt when 64 filters are left */ - fdirctrl |= (0x6 << IXGBE_FDIRCTRL_FLEX_SHIFT) | + fdirctrl |= IXGBE_FDIRCTRL_REPORT_STATUS | + (0x6 << IXGBE_FDIRCTRL_FLEX_SHIFT) | (0xA << IXGBE_FDIRCTRL_MAX_LENGTH_SHIFT) | (4 << IXGBE_FDIRCTRL_FULL_THRESH_SHIFT); @@ -1667,6 +1668,56 @@ return IXGBE_SUCCESS; } +/** + * ixgbe_fdir_erase_signature_filter_82599 - Adds a signature hash filter + * @hw: pointer to hardware structure + * @stream: input bitstream + * @queue: queue index to direct traffic to + **/ +s32 ixgbe_fdir_erase_signature_filter_82599(struct ixgbe_hw *hw, + union ixgbe_atr_hash_dword input, + union ixgbe_atr_hash_dword common) +{ + u64 fdirhashcmd; + u32 fdircmd; + + DEBUGFUNC("ixgbe_fdir_clear_signature_filter_82599"); + + /* + * Get the flow_type in order to program FDIRCMD properly + * lowest 2 bits are FDIRCMD.L4TYPE, third lowest bit is FDIRCMD.IPV6 + */ + switch (input.formatted.flow_type) { + case IXGBE_ATR_FLOW_TYPE_TCPV4: + case IXGBE_ATR_FLOW_TYPE_UDPV4: + case IXGBE_ATR_FLOW_TYPE_SCTPV4: + case IXGBE_ATR_FLOW_TYPE_TCPV6: + case IXGBE_ATR_FLOW_TYPE_UDPV6: + case IXGBE_ATR_FLOW_TYPE_SCTPV6: + break; + default: + DEBUGOUT(" Error on flow type input\n"); + return IXGBE_ERR_CONFIG; + } + + /* configure FDIRCMD register */ + fdircmd = IXGBE_FDIRCMD_CMD_REMOVE_FLOW | + IXGBE_FDIRCMD_LAST | IXGBE_FDIRCMD_QUEUE_EN; + fdircmd |= input.formatted.flow_type << IXGBE_FDIRCMD_FLOW_TYPE_SHIFT; + + /* + * The lower 32-bits of fdirhashcmd is for FDIRHASH, the upper 32-bits + * is for FDIRCMD. Then do a 64-bit register write from FDIRHASH. + */ + fdirhashcmd = (u64)fdircmd << 32; + fdirhashcmd |= ixgbe_atr_compute_sig_hash_82599(input, common); + IXGBE_WRITE_REG64(hw, IXGBE_FDIRHASH, fdirhashcmd); + + DEBUGOUT1("Tx hash=%x\n", (u32)fdirhashcmd); + + return IXGBE_SUCCESS; +} + #define IXGBE_COMPUTE_BKT_HASH_ITERATION(_n) \ do { \ u32 n = (_n); \ Index: sys/dev/ixgbe/ixgbe_api.h =================================================================== --- sys/dev/ixgbe/ixgbe_api.h +++ sys/dev/ixgbe/ixgbe_api.h @@ -144,6 +144,9 @@ union ixgbe_atr_hash_dword input, union ixgbe_atr_hash_dword common, u8 queue); +s32 ixgbe_fdir_erase_signature_filter_82599(struct ixgbe_hw *hw, + union ixgbe_atr_hash_dword input, + union ixgbe_atr_hash_dword common); s32 ixgbe_fdir_set_input_mask_82599(struct ixgbe_hw *hw, union ixgbe_atr_input *input_mask); s32 ixgbe_fdir_write_perfect_filter_82599(struct ixgbe_hw *hw, Index: sys/dev/ixgbe/ixgbe_ioctl.h =================================================================== --- /dev/null +++ sys/dev/ixgbe/ixgbe_ioctl.h @@ -0,0 +1,63 @@ +/************************************************************************** + +Copyright (c) 2013 Takuya ASADA +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Neither the name of the Chelsio Corporation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +$FreeBSD$ + +***************************************************************************/ + +#ifndef __IXGBEIOCTL_H__ +#define __IXGBEIOCTL_H__ + +enum { + IX_ADD_SIGFILTER = 0x0, + IX_GET_SIGFILTER, + IX_CLR_SIGFILTER, + IX_GET_SIGFILTER_LEN +}; + +enum { + IXGBE_FILTER_PROTO_TCPV4, + IXGBE_FILTER_PROTO_UDPV4 +}; + +struct ix_filter { + unsigned id; + int proto; + struct in_addr src_ip; + int src_port; + struct in_addr dst_ip; + int dst_port; + int que_index; +}; + +#define IXGBE_ADD_SIGFILTER _IOW('i', IX_ADD_SIGFILTER, struct ix_filter) +#define IXGBE_GET_SIGFILTER _IOWR('i', IX_GET_SIGFILTER, struct ix_filter) +#define IXGBE_CLR_SIGFILTER _IOW('i', IX_CLR_SIGFILTER, unsigned) +#define IXGBE_GET_SIGFILTER_LEN _IOR('i', IX_GET_SIGFILTER_LEN, unsigned) + +#endif + Index: sys/dev/ixgbe/ixgbe_type.h =================================================================== --- sys/dev/ixgbe/ixgbe_type.h +++ sys/dev/ixgbe/ixgbe_type.h @@ -2997,6 +2997,8 @@ u64 qbtc[16]; u64 qprdc[16]; u64 pxon2offc[8]; + u64 fdirfree_free; + u64 fdirfree_coll; u64 fdirustat_add; u64 fdirustat_remove; u64 fdirfstat_fadd; Index: tools/tools/ixgbetool/Makefile =================================================================== --- /dev/null +++ tools/tools/ixgbetool/Makefile @@ -0,0 +1,9 @@ +# $FreeBSD$ + +PROG= ixgbetool +SRCS= ixgbetool.c +NO_MAN= +CFLAGS+= -I${.CURDIR}/../../../sys/dev/ixgbe -I. +BINDIR?= /usr/sbin + +.include @@ -0,0 +1,9 @@ +# $FreeBSD$ + +PROG= ixgbetool +SRCS= ixgbetool.c +NO_MAN= +CFLAGS+= -I${.CURDIR}/../../../sys/dev/ixgbe -I. +BINDIR?= /usr/sbin + +.include Index: tools/tools/ixgbetool/ixgbetool.c =================================================================== --- /dev/null +++ tools/tools/ixgbetool/ixgbetool.c @@ -0,0 +1,210 @@ +/************************************************************************** + +Copyright (c) 2013, Takuya ASADA. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. Neither the name of the Chelsio Corporation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + + +***************************************************************************/ +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void +usage(void) +{ + fprintf(stderr, "Usage: ixgbetool [operation]\n"); + fprintf(stderr, "\tadd_sig_filter \n"); + fprintf(stderr, "\tshow_sig_filter\n"); + fprintf(stderr, "\tdel_sig_filter \n"); +} + +static int +doit(const char *iff_name, unsigned long cmd, void *data) +{ + int fd = 0; + int err; + char buf[64]; + + snprintf(buf, 64, "/dev/%s", iff_name); + if ((fd = open(buf, O_RDWR)) < 0) + return -1; + + err = ioctl(fd, cmd, data) < 0 ? -1 : 0; + close(fd); + return err; +} + +static int +add_sig_filter(int argc, char *argv[], char *ifname) +{ + struct ix_filter filter; + int error; + + if (argc != 9) + return -1; + + if (!strcmp(argv[3], "tcpv4")) + filter.proto = IXGBE_FILTER_PROTO_TCPV4; + else if (!strcmp(argv[3], "udpv4")) + filter.proto = IXGBE_FILTER_PROTO_UDPV4; + else + return -1; + error = inet_aton(argv[4], &filter.src_ip); + if (error != 1) + return error; + errno = 0; + filter.src_port = strtol(argv[5], NULL, 0); + if (errno) + return errno; + error = inet_aton(argv[6], &filter.dst_ip); + if (error != 1) + return error; + errno = 0; + filter.dst_port = strtol(argv[7], NULL, 0); + if (errno) + return errno; + errno = 0; + filter.que_index = strtol(argv[8], NULL, 0); + if (errno) + return errno; + + error = doit(ifname, IXGBE_ADD_SIGFILTER, (void *)&filter); + if (error) + perror("ioctl"); + return 0; +} + +static inline const char * +filter_proto_str(int proto) +{ + const char *str; + + switch (proto) { + case IXGBE_FILTER_PROTO_TCPV4: + str = "tcpv4"; + break; + case IXGBE_FILTER_PROTO_UDPV4: + str = "udpv4"; + break; + default: + str = "(inval)"; + } + return str; +} + +static int +show_sig_filter(int argc, char *argv[], char *ifname) +{ + unsigned i; + unsigned len; + int error; + + if (argc != 3) + return -1; + + error = doit(ifname, IXGBE_GET_SIGFILTER_LEN, (void *)&len); + if (error) + perror("ioctl"); + + for (i = 0; i < len; i++) { + struct ix_filter filter; + filter.id = i; + error = doit(ifname, IXGBE_GET_SIGFILTER, (void *)&filter); + if (error) + continue; + printf("id: %u\n", filter.id); + printf("proto: %s\n", filter_proto_str(filter.proto)); + printf("src_ip: %s\n", inet_ntoa(filter.src_ip)); + printf("src_port: %d\n", filter.src_port); + printf("dst_ip: %s\n", inet_ntoa(filter.dst_ip)); + printf("dst_port: %d\n", filter.dst_port); + printf("que_index: %d\n", filter.que_index); + printf("\n"); + } + return 0; +} + +static int +del_sig_filter(int argc, char *argv[], char *ifname) +{ + unsigned id; + int error; + + if (argc != 4) + return -1; + + errno = 0; + id = strtoul(argv[3], NULL, 0); + if (errno) + return errno; + + error = doit(ifname, IXGBE_CLR_SIGFILTER, (void *)&id); + if (error) + perror("ioctl"); + return 0; +} + +int +main(int argc, char *argv[]) +{ + int ret; + char *ifname; + + if (argc < 3) { + usage(); + exit(1); + } + ifname = argv[1]; + if (!strcmp(argv[2], "add_sig_filter")) + ret = add_sig_filter(argc, argv, ifname); + else if (!strcmp(argv[2], "show_sig_filter")) + ret = show_sig_filter(argc, argv, ifname); + else if (!strcmp(argv[2], "del_sig_filter")) + ret = del_sig_filter(argc, argv, ifname); + else + ret = -1; + + if (ret) + usage(); + + return (ret); +} @@ -0,0 +1,210 @@ +/************************************************************************** + +Copyright (c) 2013, Takuya ASADA. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. Neither the name of the Chelsio Corporation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + + +***************************************************************************/ +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void +usage(void) +{ + fprintf(stderr, "Usage: ixgbetool [operation]\n"); + fprintf(stderr, "\tadd_sig_filter \n"); + fprintf(stderr, "\tshow_sig_filter\n"); + fprintf(stderr, "\tdel_sig_filter \n"); +} + +static int +doit(const char *iff_name, unsigned long cmd, void *data) +{ + int fd = 0; + int err; + char buf[64]; + + snprintf(buf, 64, "/dev/%s", iff_name); + if ((fd = open(buf, O_RDWR)) < 0) + return -1; + + err = ioctl(fd, cmd, data) < 0 ? -1 : 0; + close(fd); + return err; +} + +static int +add_sig_filter(int argc, char *argv[], char *ifname) +{ + struct ix_filter filter; + int error; + + if (argc != 9) + return -1; + + if (!strcmp(argv[3], "tcpv4")) + filter.proto = IXGBE_FILTER_PROTO_TCPV4; + else if (!strcmp(argv[3], "udpv4")) + filter.proto = IXGBE_FILTER_PROTO_UDPV4; + else + return -1; + error = inet_aton(argv[4], &filter.src_ip); + if (error != 1) + return error; + errno = 0; + filter.src_port = strtol(argv[5], NULL, 0); + if (errno) + return errno; + error = inet_aton(argv[6], &filter.dst_ip); + if (error != 1) + return error; + errno = 0; + filter.dst_port = strtol(argv[7], NULL, 0); + if (errno) + return errno; + errno = 0; + filter.que_index = strtol(argv[8], NULL, 0); + if (errno) + return errno; + + error = doit(ifname, IXGBE_ADD_SIGFILTER, (void *)&filter); + if (error) + perror("ioctl"); + return 0; +} + +static inline const char * +filter_proto_str(int proto) +{ + const char *str; + + switch (proto) { + case IXGBE_FILTER_PROTO_TCPV4: + str = "tcpv4"; + break; + case IXGBE_FILTER_PROTO_UDPV4: + str = "udpv4"; + break; + default: + str = "(inval)"; + } + return str; +} + +static int +show_sig_filter(int argc, char *argv[], char *ifname) +{ + unsigned i; + unsigned len; + int error; + + if (argc != 3) + return -1; + + error = doit(ifname, IXGBE_GET_SIGFILTER_LEN, (void *)&len); + if (error) + perror("ioctl"); + + for (i = 0; i < len; i++) { + struct ix_filter filter; + filter.id = i; + error = doit(ifname, IXGBE_GET_SIGFILTER, (void *)&filter); + if (error) + continue; + printf("id: %u\n", filter.id); + printf("proto: %s\n", filter_proto_str(filter.proto)); + printf("src_ip: %s\n", inet_ntoa(filter.src_ip)); + printf("src_port: %d\n", filter.src_port); + printf("dst_ip: %s\n", inet_ntoa(filter.dst_ip)); + printf("dst_port: %d\n", filter.dst_port); + printf("que_index: %d\n", filter.que_index); + printf("\n"); + } + return 0; +} + +static int +del_sig_filter(int argc, char *argv[], char *ifname) +{ + unsigned id; + int error; + + if (argc != 4) + return -1; + + errno = 0; + id = strtoul(argv[3], NULL, 0); + if (errno) + return errno; + + error = doit(ifname, IXGBE_CLR_SIGFILTER, (void *)&id); + if (error) + perror("ioctl"); + return 0; +} + +int +main(int argc, char *argv[]) +{ + int ret; + char *ifname; + + if (argc < 3) { + usage(); + exit(1); + } + ifname = argv[1]; + if (!strcmp(argv[2], "add_sig_filter")) + ret = add_sig_filter(argc, argv, ifname); + else if (!strcmp(argv[2], "show_sig_filter")) + ret = show_sig_filter(argc, argv, ifname); + else if (!strcmp(argv[2], "del_sig_filter")) + ret = del_sig_filter(argc, argv, ifname); + else + ret = -1; + + if (ret) + usage(); + + return (ret); +}