Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 7 Oct 2013 16:01:58 +0900
From:      Takuya ASADA <syuu@dokukino.com>
To:        "freebsd-net@freebsd.org" <freebsd-net@freebsd.org>
Subject:   Re: Adding Flow Director sysctls to ixgbe(4) (was: netmap: traffic distribution)
Message-ID:  <CALG4x-WWqrf2Laen=zmUuiO1OCv1O2UHqV8NugnXN3BEkex%2B7g@mail.gmail.com>
In-Reply-To: <CALG4x-Xf27oEOA9K5j%2BRRndFe1VbDowpTti8a8qwu1mRaB4BkQ@mail.gmail.com>
References:  <CALCpEUHcpoJoo_gqjyDzosE1bJ_J=o3uqUuyYJA8dWZdjMrNTA@mail.gmail.com> <CAJ-VmompkSY-tU2SysaEf6p1uJPmcMeXKJ6_EZ_DJiYTQXbUzw@mail.gmail.com> <CALG4x-XowXNze82jvFX84X0=d7MRucpJbUeExug9y7XsaZXkSw@mail.gmail.com> <CALCpEUHoVJgmYptMp6Q%2BY%2BDgbxgujN8e7TcANUi1De_fnkOZ_w@mail.gmail.com> <CALG4x-Xf27oEOA9K5j%2BRRndFe1VbDowpTti8a8qwu1mRaB4BkQ@mail.gmail.com>

next in thread | previous in thread | raw e-mail | index | archive | help

[-- Attachment #1 --]
Hi,

This is updated version of "ixgbetool" patch.
Here's improved feature list:
- signature filter list feature available
- user-defined filter can be use with an ATR.
To enable it, add "hw.ixgbe.cooperative_atr=1" on /boot/loader.conf

Usage is as follows:
ixgbetool <ifname> [operation]
    add_sig_filter <proto> <src_ip> <src_port> <dst_ip> <dst_port>
<que_index>
    show_sig_filter
    del_sig_filter <id>


2013/9/30 Takuya ASADA <syuu@dokukino.com>

> Hi,
>
> I just implemented device specific ioctl with device specific
> configuration tool.
> It still doesn't support some important features such as:
>  - FDIR enable / disable via sysctl or tunable params
>  - ATR enable / disable via sysctl or tunable params
>  - IPv6 support on signature filter
>  - signature filter list
>  - support perfect filter
> But, at least it can configure signature filter manually.
>
> Usage is as follows:
> Usage: ixgbetool <ifname> [operation]
> add_sig_filter <proto> <src_ip> <src_port> <dst_ip> <dst_port> <que_index>
>  del_sig_filter <proto> <src_ip> <src_port> <dst_ip> <dst_port>
>
>
> 2013/9/28 hiren panchasara <hiren.panchasara@gmail.com>
>
>>
>>
>>
>> On Fri, Sep 27, 2013 at 1:58 AM, Takuya ASADA <syuu@dokukino.com> wrote:
>>
>>> 2013/9/27 Adrian Chadd <adrian@freebsd.org>
>>>
>>>> On 27 September 2013 00:43, hiren panchasara <
>>>> hiren.panchasara@gmail.com> wrote:
>>>>
>>>>
>>>>> Takuya,
>>>>>
>>>>> I see a lot of responses/comments on proposed changes. Was anything
>>>>> decided
>>>>> at the end of it? As far as I can tell, its still not committed to the
>>>>> tree.
>>>>>
>>>>
>>>> I'd rather see an ioctl API for that chipset and then have a separate
>>>> tool program it for now.
>>>>
>>>
>>> Ah, like cxgbetool and cxgbe? (it has device specific tool and ioctls)
>>> http://svnweb.freebsd.org/base/head/tools/tools/cxgbetool/
>>>
>>
>> Something like this for ixgbe would be nice to start with, imo.
>>
>> Cheers,
>> Hiren
>>
>>> http://svnweb.freebsd.org/base/head/sys/dev/cxgb/
>>>
>>>
>>>> So, how bout we hack that up? :)
>>>>
>>>
>>>  Sound's interesting ;-)
>>> Could you tell me more detail about your idea?
>>>
>>>
>>
>

[-- Attachment #2 --]
diff --git a/sys/conf/files b/sys/conf/files
index a370cfa..9e5ada7 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -1734,6 +1734,8 @@ dev/ixgbe/ixgbe_dcb_82598.c	optional ixgbe inet \
 	compile-with "${NORMAL_C} -I$S/dev/ixgbe"
 dev/ixgbe/ixgbe_dcb_82599.c	optional ixgbe inet \
 	compile-with "${NORMAL_C} -I$S/dev/ixgbe"
+dev/ixgbe/ixgbe_ufilter.c	optional ixgbe inet \
+	compile-with "${NORMAL_C} -I$S/dev/ixgbe -DSMP -DIXGBE_FDIR"
 dev/jme/if_jme.c		optional jme pci
 dev/joy/joy.c			optional joy
 dev/joy/joy_isa.c		optional joy isa
diff --git a/sys/dev/ixgbe/ixgbe.c b/sys/dev/ixgbe/ixgbe.c
index b65df72..40d948b 100644
--- a/sys/dev/ixgbe/ixgbe.c
+++ b/sys/dev/ixgbe/ixgbe.c
@@ -326,7 +326,8 @@ static int ixgbe_total_ports;
 ** This feature can be disabled by 
 ** setting this to 0.
 */
-static int atr_sample_rate = 20;
+int ixgbe_atr_sample_rate = 20;
+TUNABLE_INT("hw.ixgbe.atr_sample_rate", &ixgbe_atr_sample_rate);
 /* 
 ** Flow Director actually 'steals'
 ** part of the packet buffer as its
@@ -442,6 +443,13 @@ ixgbe_attach(device_t dev)
 			OID_AUTO, "enable_aim", CTLTYPE_INT|CTLFLAG_RW,
 			&ixgbe_enable_aim, 1, "Interrupt Moderation");
 
+#ifdef IXGBE_FDIR
+        SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
+			SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
+			OID_AUTO, "atr_sample_rate", CTLTYPE_INT|CTLFLAG_RD,
+			&ixgbe_atr_sample_rate, 20, "ATR sample rate");
+#endif
+
 	/*
 	** Allow a kind of speed control by forcing the autoneg
 	** advertised speed list to only a certain value, this
@@ -604,6 +612,13 @@ ixgbe_attach(device_t dev)
 #ifdef DEV_NETMAP
 	ixgbe_netmap_attach(adapter);
 #endif /* DEV_NETMAP */
+
+#ifdef IXGBE_FDIR
+	error = ixgbe_ufilter_attach(adapter);
+	if (error)
+		goto err_late;
+#endif
+
 	INIT_DEBUGOUT("ixgbe_attach: end");
 	return (0);
 err_late:
@@ -693,6 +708,10 @@ ixgbe_detach(device_t dev)
 	ixgbe_free_receive_structures(adapter);
 	free(adapter->mta, M_DEVBUF);
 
+#ifdef IXGBE_FDIR
+	ixgbe_ufilter_detach(adapter);
+#endif
+
 	IXGBE_CORE_LOCK_DESTROY(adapter);
 	return (0);
 }
@@ -1816,7 +1835,7 @@ retry:
 	/* Do the flow director magic */
 	if ((txr->atr_sample) && (!adapter->fdir_reinit)) {
 		++txr->atr_count;
-		if (txr->atr_count >= atr_sample_rate) {
+		if (txr->atr_count >= ixgbe_atr_sample_rate) {
 			ixgbe_atr(txr, m_head);
 			txr->atr_count = 0;
 		}
@@ -3062,7 +3081,7 @@ ixgbe_setup_transmit_ring(struct tx_ring *txr)
 #ifdef IXGBE_FDIR
 	/* Set the rate at which we sample packets */
 	if (adapter->hw.mac.type != ixgbe_mac_82598EB)
-		txr->atr_sample = atr_sample_rate;
+		txr->atr_sample = ixgbe_atr_sample_rate;
 #endif
 
 	/* Set number of descriptors available */
@@ -3546,6 +3565,13 @@ ixgbe_atr(struct tx_ring *txr, struct mbuf *mp)
 	common.ip ^= ip->ip_src.s_addr ^ ip->ip_dst.s_addr;
 
 	que = &adapter->queues[txr->me];
+
+	if (ixgbe_cooperative_atr) {
+		u32 hash;
+		hash = ixgbe_atr_compute_sig_hash_82599(input, common);
+		if (ixgbe_ufilter_exists(adapter, hash))
+			return;
+	}
 	/*
 	** This assumes the Rx queue and Tx
 	** queue are bound to the same CPU
diff --git a/sys/dev/ixgbe/ixgbe.h b/sys/dev/ixgbe/ixgbe.h
index 77b72ed..0ba0523 100644
--- a/sys/dev/ixgbe/ixgbe.h
+++ b/sys/dev/ixgbe/ixgbe.h
@@ -90,6 +90,7 @@
 #include <machine/smp.h>
 
 #include "ixgbe_api.h"
+#include "ixgbe_ufilter.h"
 
 /* Tunables */
 
@@ -468,8 +469,11 @@ struct adapter {
 	unsigned long		link_irq;
 
 	struct ixgbe_hw_stats 	stats;
-};
 
+#ifdef IXGBE_FDIR
+	struct ixgbe_ufilter	ufilter;
+#endif
+};
 
 /* Precision Time Sync (IEEE 1588) defines */
 #define ETHERTYPE_IEEE1588      0x88F7
@@ -540,4 +544,8 @@ ixgbe_rx_unrefreshed(struct rx_ring *rxr)
 		    rxr->next_to_refresh - 1);
 }       
 
+#ifdef IXGBE_FDIR
+extern int ixgbe_atr_sample_rate;
+#endif
+
 #endif /* _IXGBE_H_ */
diff --git a/sys/dev/ixgbe/ixgbe_82599.c b/sys/dev/ixgbe/ixgbe_82599.c
index 3cc8cd7..74d3ae9 100644
--- a/sys/dev/ixgbe/ixgbe_82599.c
+++ b/sys/dev/ixgbe/ixgbe_82599.c
@@ -1667,6 +1667,55 @@ s32 ixgbe_fdir_add_signature_filter_82599(struct ixgbe_hw *hw,
 	return IXGBE_SUCCESS;
 }
 
+/**
+ *  ixgbe_fdir_erase_signature_filter_82599 - Erase a signature hash filter
+ *  @hw: pointer to hardware structure
+ *  @stream: input bitstream
+ **/
+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_erase_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_ufilter.c b/sys/dev/ixgbe/ixgbe_ufilter.c
new file mode 100644
index 0000000..e5d4462
--- /dev/null
+++ b/sys/dev/ixgbe/ixgbe_ufilter.c
@@ -0,0 +1,260 @@
+
+#include "ixgbe.h"
+#include <sys/conf.h>
+#include <sys/priv.h>
+
+#ifdef IXGBE_FDIR
+static d_open_t ixgbe_ufilter_open;
+static d_close_t ixgbe_ufilter_close;
+static d_ioctl_t ixgbe_ufilter_ioctl;
+static struct cdevsw cdevsw = {
+       .d_version =    D_VERSION,
+       .d_flags =      0,
+       .d_open =       ixgbe_ufilter_open,
+       .d_close =      ixgbe_ufilter_close,
+       .d_ioctl =      ixgbe_ufilter_ioctl,
+       .d_name =       "ix",
+};
+
+static int ufilter_hash_size = 65536;
+TUNABLE_INT("hw.ixgbe.ufilter_hash_size", &ufilter_hash_size);
+int ixgbe_cooperative_atr = 0;
+TUNABLE_INT("hw.ixgbe.cooperative_atr", &ixgbe_cooperative_atr);
+
+static inline void
+list_insert(struct ixgbe_ufilter *ufilter, struct ufilter_kentry *ke)
+{
+	TAILQ_INSERT_TAIL(&ufilter->list, ke, tq_link);
+}
+
+static inline void
+list_remove(struct ixgbe_ufilter *ufilter, struct ufilter_kentry *ke)
+{
+	TAILQ_REMOVE(&ufilter->list, ke, tq_link);
+}
+
+static inline struct ufilter_kentry *
+list_find(struct ixgbe_ufilter *ufilter, unsigned id)
+{
+	struct ufilter_kentry *ke;
+
+	TAILQ_FOREACH(ke, &ufilter->list, tq_link)
+		if (ke->e.id == id)
+			return (ke);
+	return (NULL);
+}
+
+static inline void
+list_freeall(struct ixgbe_ufilter *ufilter)
+{
+	struct ufilter_kentry *ke, *t;
+
+	TAILQ_FOREACH_SAFE(ke, &ufilter->list, tq_link, t)
+		free(ke, M_DEVBUF);
+}
+
+static inline void
+hash_insert(struct ixgbe_ufilter *ufilter, struct ufilter_kentry *ke)
+{
+	int bucket;
+	
+	bucket = ke->hash & ufilter->hashmask;
+	rm_wlock(&ufilter->hashlock);
+	LIST_INSERT_HEAD(&ufilter->hash[bucket], ke, li_link);
+	rm_wunlock(&ufilter->hashlock);
+}
+
+static inline void
+hash_remove(struct ixgbe_ufilter *ufilter, struct ufilter_kentry *ke)
+{
+	int bucket;
+
+	bucket = ke->hash & ufilter->hashmask;
+	rm_wlock(&ufilter->hashlock);
+	LIST_REMOVE(ke, li_link);
+	free(ke, M_DEVBUF);
+	rm_wunlock(&ufilter->hashlock);
+}
+
+int
+ixgbe_ufilter_exists(struct adapter *adapter, u32 hash)
+{
+	struct ixgbe_ufilter *ufilter = &adapter->ufilter;
+	int bucket;
+	struct rm_priotracker tracker;
+	struct ufilter_kentry *ke;
+	int found = 0;
+
+	bucket = hash & ufilter->hashmask;
+	rm_rlock(&ufilter->hashlock, &tracker);
+	LIST_FOREACH(ke, &ufilter->hash[bucket], li_link) {
+		if (ke->hash == hash) {
+			found++;
+			break;
+		}
+	}
+	rm_runlock(&ufilter->hashlock, &tracker);
+
+	return (found);
+}
+
+int
+ixgbe_ufilter_attach(struct adapter *adapter)
+{
+	adapter->ufilter.cdev = make_dev(&cdevsw, adapter->ifp->if_dunit,
+	    UID_ROOT, GID_WHEEL, 0600, "%s", if_name(adapter->ifp));
+	if (adapter->ufilter.cdev == NULL)
+		return (ENOMEM);
+
+	adapter->ufilter.cdev->si_drv1 = (void *)adapter;
+		
+	mtx_init(&adapter->ufilter.mtx, "ufilter_mtx", NULL, MTX_DEF);
+	TAILQ_INIT(&adapter->ufilter.list);
+	if (ixgbe_cooperative_atr) {
+		adapter->ufilter.hash = hashinit(ufilter_hash_size, M_DEVBUF,
+			&adapter->ufilter.hashmask);
+		rm_init_flags(&adapter->ufilter.hashlock, "ufilter_hashlock", 
+			RM_NOWITNESS);
+	}
+        SYSCTL_ADD_INT(device_get_sysctl_ctx(adapter->dev),
+			SYSCTL_CHILDREN(device_get_sysctl_tree(adapter->dev)),
+			OID_AUTO, "ufilter_hash_size", CTLTYPE_INT|CTLFLAG_RD,
+			&ufilter_hash_size, 20, "ufilter hashtable size");
+        SYSCTL_ADD_INT(device_get_sysctl_ctx(adapter->dev),
+			SYSCTL_CHILDREN(device_get_sysctl_tree(adapter->dev)),
+			OID_AUTO, "cooperative_atr", CTLTYPE_INT|CTLFLAG_RD,
+			&ixgbe_cooperative_atr, 20, "cooperative ATR");
+
+	return (0);
+}
+
+int
+ixgbe_ufilter_detach(struct adapter *adapter)
+{
+	list_freeall(&adapter->ufilter);
+	if (ixgbe_cooperative_atr) {
+		rm_destroy(&adapter->ufilter.hashlock);
+		hashdestroy(adapter->ufilter.hash, M_DEVBUF, 
+			adapter->ufilter.hashmask);
+	}
+	mtx_destroy(&adapter->ufilter.mtx);
+	if (adapter->ufilter.cdev)
+		destroy_dev(adapter->ufilter.cdev);
+	return (0);
+}
+
+static int
+ixgbe_ufilter_open(struct cdev *dev, int flags, int fmp, struct thread *td)
+{
+       return (0);
+}
+
+static int
+ixgbe_ufilter_close(struct cdev *dev, int flags, int fmt, struct thread *td)
+{
+       return (0);
+}
+
+static int
+ixgbe_ufilter_ioctl(struct cdev *dev, unsigned long cmd, caddr_t data,
+    int fflag, struct thread *td)
+{
+	struct adapter *adapter = (struct adapter *)dev->si_drv1;
+	struct ixgbe_ufilter *ufilter = &adapter->ufilter;
+	int error = 0;
+
+	if (priv_check(td, PRIV_DRIVER)) {
+		return (EPERM);
+	}
+
+	if (!ixgbe_cooperative_atr && ixgbe_atr_sample_rate)
+		return (ENODEV);
+
+	mtx_lock(&ufilter->mtx);
+	switch (cmd) {
+	case IXGBE_ADD_SIGFILTER: {
+		struct ufilter_entry *e = (struct ufilter_entry *)data;
+		struct ufilter_kentry *ke;
+		union ixgbe_atr_hash_dword input = {.dword = 0};
+		union ixgbe_atr_hash_dword common = {.dword = 0};
+
+		switch (e->proto) {
+		case UFILTER_PROTO_TCPV4:
+			input.formatted.flow_type ^= IXGBE_ATR_FLOW_TYPE_TCPV4;
+			break;
+		case UFILTER_PROTO_UDPV4:
+			input.formatted.flow_type ^= IXGBE_ATR_FLOW_TYPE_UDPV4;
+			break;
+		default:
+			error = EINVAL;
+			goto out;
+		}
+		common.port.src ^= htons(e->src_port);
+		common.port.dst ^= htons(e->dst_port);
+		common.flex_bytes ^= htons(ETHERTYPE_IP);
+		common.ip ^= e->src_ip.s_addr ^ e->dst_ip.s_addr;
+
+		ke = malloc(sizeof(*ke), M_DEVBUF, M_NOWAIT | M_ZERO);
+		if (!ke) {
+			error = ENOMEM;
+			goto out;
+		}
+		memcpy(&ke->e, e, sizeof(ke->e));
+		ke->e.id = ufilter->next_id++;
+		ke->input = input;
+		ke->common = common;
+		if (ixgbe_cooperative_atr) {
+			ke->hash = ixgbe_atr_compute_sig_hash_82599(input, 
+				common);
+			hash_insert(ufilter, ke);
+		}
+		list_insert(ufilter, ke);
+		ixgbe_fdir_add_signature_filter_82599(&adapter->hw,
+			input, common, e->que_index);
+		break;
+	}
+	case IXGBE_GET_SIGFILTER: {
+		struct ufilter_entry *e = (struct ufilter_entry *)data;
+		struct ufilter_kentry *ke;
+
+		ke = list_find(ufilter, e->id);
+		if (ke)
+			memcpy(e, &ke->e, sizeof(*e));
+		else
+			error = ENOENT;
+		break;
+	};
+	case IXGBE_CLR_SIGFILTER: {
+		unsigned *id = (unsigned *)data;
+		struct ufilter_kentry *ke;
+
+		ke = list_find(ufilter, *id);
+		if (!ke) {
+			error = ENOENT;
+			goto out;
+		}
+
+		if (ixgbe_cooperative_atr)
+			hash_remove(ufilter, ke);
+		list_remove(ufilter, ke);
+
+		ixgbe_fdir_erase_signature_filter_82599(&adapter->hw,
+			ke->input, ke->common);
+		break;
+	}
+	case IXGBE_GET_SIGFILTER_LEN: {
+		unsigned *id = (unsigned *)data;
+		
+		*id = ufilter->next_id;
+		break;
+	}
+	default:
+		error = EOPNOTSUPP;
+		break;
+	}
+
+out:
+	mtx_unlock(&ufilter->mtx);
+	return (error);
+}
+#endif /* IXGBE_FDIR */
diff --git a/sys/dev/ixgbe/ixgbe_ufilter.h b/sys/dev/ixgbe/ixgbe_ufilter.h
new file mode 100644
index 0000000..a2e8334
--- /dev/null
+++ b/sys/dev/ixgbe/ixgbe_ufilter.h
@@ -0,0 +1,86 @@
+/**************************************************************************
+
+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 __IXGBEUFILTER_H__
+#define __IXGBEUFILTER_H__
+
+enum {
+	UFILTER_PROTO_TCPV4,
+	UFILTER_PROTO_UDPV4
+};
+
+struct ufilter_entry {
+	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', 0x0, struct ufilter_entry)
+#define IXGBE_GET_SIGFILTER	_IOWR('i', 0x1, struct ufilter_entry)
+#define IXGBE_CLR_SIGFILTER	_IOW('i', 0x2, unsigned)
+#define IXGBE_GET_SIGFILTER_LEN _IOR('i', 0x3, unsigned)
+
+#ifdef _KERNEL
+#ifdef IXGBE_FDIR
+#include <sys/rmlock.h>
+
+struct ufilter_kentry {
+	struct ufilter_entry e;
+	TAILQ_ENTRY(ufilter_kentry) tq_link;
+	LIST_ENTRY(ufilter_kentry) li_link;
+	union ixgbe_atr_hash_dword input;
+	union ixgbe_atr_hash_dword common;
+	u32 hash;
+};
+
+struct ixgbe_ufilter {
+	struct cdev		*cdev;
+	TAILQ_HEAD(, ufilter_kentry) list;
+	struct mtx		mtx;
+	unsigned		next_id;
+	LIST_HEAD(, ufilter_kentry) *hash;
+	u_long			hashmask;
+	struct rmlock		hashlock;
+};
+
+struct adapter;
+int ixgbe_ufilter_attach(struct adapter *adapter);
+int ixgbe_ufilter_detach(struct adapter *adapter);
+extern int ixgbe_cooperative_atr;
+int ixgbe_ufilter_exists(struct adapter *adapter, u32 hash);
+#endif /* IXGBE_FDIR */
+#endif /* _KERNEL */
+#endif /* __IXGBEUFILTER_H__ */
+
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..f5b61f5
--- /dev/null
+++ b/tools/tools/ixgbetool/ixgbetool.c
@@ -0,0 +1,236 @@
+/**************************************************************************
+
+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 <sys/sysctl.h>
+#include <ixgbe_ufilter.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 
+add_sig_filter(int fd, int argc, char *argv[])
+{
+	struct ufilter_entry filter;
+	int error;
+
+	if (argc != 9) 
+		return -1;
+
+	if (!strcmp(argv[3], "tcpv4"))
+		filter.proto = UFILTER_PROTO_TCPV4;
+	else if (!strcmp(argv[3], "udpv4"))
+		filter.proto = UFILTER_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 = ioctl(fd, IXGBE_ADD_SIGFILTER, &filter);
+	if (error) {
+		perror("ixgbetool");
+		close(fd);
+		exit(1);
+	}
+	return 0;
+}
+
+static inline const char *
+filter_proto_str(int proto)
+{
+	const char *str;
+
+	switch (proto) {
+	case UFILTER_PROTO_TCPV4:
+		str = "tcpv4";
+		break;
+	case UFILTER_PROTO_UDPV4:
+		str = "udpv4";
+		break;
+	default:
+		str = "(inval)";
+	}
+	return str;
+}
+
+static int 
+show_sig_filter(int fd, int argc, char *argv[])
+{
+	unsigned i;
+	unsigned len;
+	int error;
+
+	if (argc != 3) 
+		return -1;
+
+	error = ioctl(fd, IXGBE_GET_SIGFILTER_LEN, &len);
+	if (error) {
+		perror("ixgbetool");
+		close(fd);
+		exit(1);
+	}
+
+	for (i = 0; i < len; i++) {
+		struct ufilter_entry filter;
+
+		filter.id = i;
+		error = ioctl(fd, IXGBE_GET_SIGFILTER, &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 fd, int argc, char *argv[])
+{
+	unsigned id;
+	int error;
+
+	if (argc != 4) 
+		return -1;
+
+	errno = 0;
+	id = strtoul(argv[3], NULL, 0);
+	if (errno)
+		return errno;
+
+	error = ioctl(fd, IXGBE_CLR_SIGFILTER, &id);
+	if (error) {
+		perror("ixgbetool");
+		close(fd);
+		exit(1);
+	}
+	return 0;
+}
+
+int 
+main(int argc, char *argv[])
+{
+	int ret;
+	char buf[64];
+	int fd;
+	int ifno;
+	int coop_atr;
+	int atr;
+	size_t coop_atr_size = sizeof(coop_atr);
+	size_t atr_size = sizeof(atr);
+
+	if (argc < 3) {
+		usage();
+		exit(1);
+	}
+	snprintf(buf, sizeof(buf), "/dev/%s", argv[1]);
+	if ((fd = open(buf, O_RDWR)) < 0) {
+		perror("ixgbetool");
+		exit(1);
+	}
+	sscanf(argv[1], "ix%d", &ifno);
+	snprintf(buf, sizeof(buf), "dev.ix.%d.cooperative_atr", ifno);
+	ret = sysctlbyname(buf, &coop_atr, &coop_atr_size, NULL, 0);
+	if (ret) {
+		perror("ixgbetool");
+		exit(1);
+	}
+	snprintf(buf, sizeof(buf), "dev.ix.%d.atr_sample_rate", ifno);
+	ret = sysctlbyname(buf, &atr, &atr_size, NULL, 0);
+	if (ret) {
+		perror("ixgbetool");
+		exit(1);
+	}
+	if (!coop_atr && atr) {
+		printf("To use user defined filter, you need to add 'hw.ixgbe.cooperative_atr=1' on /boot/loader.conf and reboot\n");
+		close(fd);
+		exit(1);
+	}
+	if (!strcmp(argv[2], "add_sig_filter"))
+		ret = add_sig_filter(fd, argc, argv);
+	else if (!strcmp(argv[2], "show_sig_filter"))
+		ret = show_sig_filter(fd, argc, argv);
+	else if (!strcmp(argv[2], "del_sig_filter"))
+		ret = del_sig_filter(fd, argc, argv);
+	else 
+		ret = -1;
+
+	if (ret)
+		usage();
+
+	close(fd);
+
+	return (ret);
+}
+

Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?CALG4x-WWqrf2Laen=zmUuiO1OCv1O2UHqV8NugnXN3BEkex%2B7g>