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>
