>Number:         182512
>Category:       kern
>Synopsis:       ixgbetool: Flow Director configuration tool for ixgbe(4)
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Mon Sep 30 12:10:00 UTC 2013
>Closed-Date:
>Last-Modified:
>Originator:     Takuya ASADA
>Release:        10-CURRENT
>Organization:
>Environment:
>Description:
This patch provides a configuration tool for "Ethernet Flow Director", which is 
ixgbe(4) feature which assigns specific flow to specific RX queue.

Here're usage of ixgbetool:
- add a filter
ixgbetool ix0 add_sig_filter tcpv4 10.1.0.1 34763 10.1.0.2 22 3
- show filters
ixgbetool ix0 show_sig_filter
- del a filter
ixgbetool ix0 del_sig_filter 1

Also, character device(/dev/ix*) and ioctls are added on ixgbe(4) to 
communicate with ixgbetool.
>How-To-Repeat:

>Fix:


Patch attached with submission follows:

diff --git a/sys/dev/ixgbe/ixgbe.c b/sys/dev/ixgbe/ixgbe.c
index b65df72..adefb14 100644
--- a/sys/dev/ixgbe/ixgbe.c
+++ b/sys/dev/ixgbe/ixgbe.c
@@ -35,6 +35,7 @@
 
 #include "opt_inet.h"
 #include "opt_inet6.h"
+ 
 #include "ixgbe.h"
 
 /*********************************************************************
@@ -200,7 +201,9 @@ static void ixgbe_handle_msf(void *, int);
 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
 
@@ -224,6 +227,19 @@ static driver_t ixgbe_driver = {
        "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);
 
@@ -317,6 +333,7 @@ static bool ixgbe_rsc_enable = FALSE;
 static int ixgbe_total_ports;
 
 #ifdef IXGBE_FDIR
+#ifdef IXGBE_FDIR_ATR
 /*
 ** For Flow Director: this is the
 ** number of TX packets we sample
@@ -327,6 +344,7 @@ static int ixgbe_total_ports;
 ** setting this to 0.
 */
 static int atr_sample_rate = 20;
+#endif
 /* 
 ** Flow Director actually 'steals'
 ** part of the packet buffer as its
@@ -401,6 +419,20 @@ ixgbe_probe(device_t dev)
        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
  *
@@ -604,6 +636,14 @@ ixgbe_attach(device_t dev)
 #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:
@@ -1812,7 +1852,7 @@ retry:
                return (error);
        }
 
-#ifdef IXGBE_FDIR
+#ifdef IXGBE_FDIR_ATR
        /* Do the flow director magic */
        if ((txr->atr_sample) && (!adapter->fdir_reinit)) {
                ++txr->atr_count;
@@ -3059,7 +3099,7 @@ ixgbe_setup_transmit_ring(struct tx_ring *txr)
                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;
@@ -3479,7 +3519,7 @@ ixgbe_tso_setup(struct tx_ring *txr, struct mbuf *mp,
        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 
@@ -5270,13 +5310,33 @@ ixgbe_update_stats_counters(struct adapter *adapter)
        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 */
@@ -5642,6 +5702,32 @@ ixgbe_add_hw_stats(struct adapter *adapter)
        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,
+               "");
 }
 
 /*
@@ -5803,3 +5889,137 @@ ixgbe_disable_rx_drop(struct adapter *adapter)
                IXGBE_WRITE_REG(hw, IXGBE_SRRCTL(i), srrctl);
        }
 }
+
+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);
+}
+
diff --git a/sys/dev/ixgbe/ixgbe.h b/sys/dev/ixgbe/ixgbe.h
index 77b72ed..064b510 100644
--- a/sys/dev/ixgbe/ixgbe.h
+++ b/sys/dev/ixgbe/ixgbe.h
@@ -88,8 +88,11 @@
 #include <sys/pcpu.h>
 #include <sys/smp.h>
 #include <machine/smp.h>
+#include <sys/conf.h>
+#include <sys/priv.h>
 
 #include "ixgbe_api.h"
+#include "ixgbe_ioctl.h"
 
 /* Tunables */
 
@@ -468,8 +471,17 @@ struct adapter {
        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
diff --git a/sys/dev/ixgbe/ixgbe_82599.c b/sys/dev/ixgbe/ixgbe_82599.c
index 3cc8cd7..72ea5ea 100644
--- a/sys/dev/ixgbe/ixgbe_82599.c
+++ b/sys/dev/ixgbe/ixgbe_82599.c
@@ -1482,7 +1482,8 @@ s32 ixgbe_init_fdir_signature_82599(struct ixgbe_hw *hw, 
u32 fdirctrl)
         *  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 @@ s32 ixgbe_fdir_add_signature_filter_82599(struct 
ixgbe_hw *hw,
        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); \
diff --git a/sys/dev/ixgbe/ixgbe_api.h b/sys/dev/ixgbe/ixgbe_api.h
index 91023ae..77c6427 100644
--- a/sys/dev/ixgbe/ixgbe_api.h
+++ b/sys/dev/ixgbe/ixgbe_api.h
@@ -144,6 +144,9 @@ s32 ixgbe_fdir_add_signature_filter_82599(struct ixgbe_hw 
*hw,
                                          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,
diff --git a/sys/dev/ixgbe/ixgbe_ioctl.h b/sys/dev/ixgbe/ixgbe_ioctl.h
new file mode 100644
index 0000000..12f1522
--- /dev/null
+++ b/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
+
diff --git a/sys/dev/ixgbe/ixgbe_type.h b/sys/dev/ixgbe/ixgbe_type.h
index 49f5bc0..c5f29bb 100644
--- a/sys/dev/ixgbe/ixgbe_type.h
+++ b/sys/dev/ixgbe/ixgbe_type.h
@@ -2997,6 +2997,8 @@ struct ixgbe_hw_stats {
        u64 qbtc[16];
        u64 qprdc[16];
        u64 pxon2offc[8];
+       u64 fdirfree_free;
+       u64 fdirfree_coll;
        u64 fdirustat_add;
        u64 fdirustat_remove;
        u64 fdirfstat_fadd;
diff --git a/tools/tools/ixgbetool/Makefile b/tools/tools/ixgbetool/Makefile
new file mode 100644
index 0000000..0695e93
--- /dev/null
+++ b/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 <bsd.prog.mk>
diff --git a/tools/tools/ixgbetool/ixgbetool.c 
b/tools/tools/ixgbetool/ixgbetool.c
new file mode 100644
index 0000000..11cb2be
--- /dev/null
+++ b/tools/tools/ixgbetool/ixgbetool.c
@@ -0,0 +1,211 @@
+/**************************************************************************
+
+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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/ioctl.h>
+#include <ixgbe_ioctl.h>
+
+static void
+usage(void)
+{
+       fprintf(stderr, "Usage: ixgbetool <ifname> [operation]\n");
+       fprintf(stderr, "\tadd_sig_filter <proto> <src_ip> <src_port> <dst_ip> 
<dst_port> <que_index>\n");
+       fprintf(stderr, "\tshow_sig_filter\n");
+       fprintf(stderr, "\tdel_sig_filter <id>\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);
+}
+


>Release-Note:
>Audit-Trail:
>Unformatted:
_______________________________________________
[email protected] mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-bugs
To unsubscribe, send any mail to "[email protected]"

Reply via email to