kern/182512: ixgbetool: Flow Director configuration tool for ixgbe(4)

Takuya ASADA syuu at FreeBSD.org
Mon Sep 30 12:10:00 UTC 2013


>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:


More information about the freebsd-bugs mailing list