Date: Mon, 5 Sep 2011 15:51:32 +0900 From: Takuya ASADA <syuu@dokukino.com> To: jfv@freebsd.org, freebsd-net@freebsd.org Subject: Adding Flow Director sysctls to ixgbe(4) Message-ID: <CALG4x-W99OZxd=1ZDvW4=MBqeE3RPOazc7jc_3O30X-Pou3k8Q@mail.gmail.com>
next in thread | raw e-mail | index | archive | help
[-- Attachment #1 --]
Hi,
I implemented Ethernet Flow Director sysctls to ixgbe(4), here's a detail:
- Adding removing signature filter
On linux version of ixgbe driver, it has ability to set/remove perfect
filter from userland using ethtool command.
I implemented similar feature, but on sysctl, and not perfect filter
but signature filter(which means hash collision may occurs).
Following command adds a signature filter on ix0 for
10.0.0.2:47390/tcp -> 10.0.0.1:22/tcp, queueing Rx queue 10.
$ sysctl dev.ix.0.set_fdir_signature="tcpv4 10.0.0.2:47390 10.0.0.1:22 10"
Clearing a filter takes similar values but not includes queue number:
$ sysctl dev.ix.0.clear_fdir_signature="tcpv4 10.0.0.2:47390 10.0.0.1:22"
- Statistics of Flow Director
These sysctls poll fdir statistics register:
dev.ix.*.mac_stats.fdirfree_free
dev.ix.*.mac_stats.fdirfree_coll
dev.ix.*.mac_stats.fdirustat_add
dev.ix.*.mac_stats.fdirustat_remove
dev.ix.*.mac_stats.fdirfstat_fadd
dev.ix.*.mac_stats.fdirfstat_fremove
dev.ix.*.mac_stats.fdirmatch
dev.ix.*.mac_stats.fdirmiss
And I divided "#ifdef IXGBE_FDIR" to "#ifdef IXGBE_FDIR" and "#ifdef
IXGBE_FDIR_ATR".
If only IXGBE_FDIR is defined, only set_fdir_signature sysctl sets
signature filters.
If IXGBE_FDIR and IXGBE_FDIR_ATR are defined, ixgbe_atr also sets
signature filters automatically.
Which means even if you set a filter with specific queue number via
sysctl, ixgbe_atr will override the queue number.
[-- Attachment #2 --]
Index: ixgbe.c
===================================================================
--- ixgbe.c (revision 225013)
+++ ixgbe.c (working copy)
@@ -37,6 +37,11 @@
#include "opt_inet6.h"
#endif
+/*
+#define IXGBE_FDIR 1
+#define IXGBE_FDIR_ATR 1
+*/
+
#include "ixgbe.h"
/*********************************************************************
@@ -153,6 +158,8 @@
static int ixgbe_xmit(struct tx_ring *, struct mbuf **);
static int ixgbe_set_flowcntl(SYSCTL_HANDLER_ARGS);
static int ixgbe_set_advertise(SYSCTL_HANDLER_ARGS);
+static int ixgbe_set_fdir_signature(SYSCTL_HANDLER_ARGS);
+static int ixgbe_clear_fdir_signature(SYSCTL_HANDLER_ARGS);
static int ixgbe_dma_malloc(struct adapter *, bus_size_t,
struct ixgbe_dma_alloc *, int);
static void ixgbe_dma_free(struct adapter *, struct ixgbe_dma_alloc *);
@@ -191,8 +198,10 @@
static void ixgbe_handle_msf(void *, int);
static void ixgbe_handle_mod(void *, int);
+#ifdef IXGBE_FDIR_ATR
+static void ixgbe_atr(struct tx_ring *, struct mbuf *);
+#endif
#ifdef IXGBE_FDIR
-static void ixgbe_atr(struct tx_ring *, struct mbuf *);
static void ixgbe_reinit_fdir(void *, int);
#endif
@@ -292,7 +301,7 @@
/* Keep running tab on them for sanity check */
static int ixgbe_total_ports;
-#ifdef IXGBE_FDIR
+#ifdef IXGBE_FDIR_ATR
/*
** For Flow Director: this is the
** number of TX packets we sample
@@ -303,6 +312,8 @@
** setting this to 0.
*/
static int atr_sample_rate = 20;
+#endif
+#ifdef IXGBE_FDIR
/*
** Flow Director actually 'steals'
** part of the packet buffer as its
@@ -416,6 +427,16 @@
OID_AUTO, "enable_aim", CTLTYPE_INT|CTLFLAG_RW,
&ixgbe_enable_aim, 1, "Interrupt Moderation");
+ SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
+ SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
+ OID_AUTO, "set_fdir_signature", CTLTYPE_STRING | CTLFLAG_WR,
+ adapter, 0, ixgbe_set_fdir_signature, "A", "Set Flow Director Signature");
+
+ SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
+ SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
+ OID_AUTO, "clear_fdir_signature", CTLTYPE_STRING | CTLFLAG_WR,
+ adapter, 0, ixgbe_clear_fdir_signature, "A", "Clear Flow Director Signature");
+
/* Set up the timer callout */
callout_init_mtx(&adapter->timer, &adapter->core_mtx, 0);
@@ -1685,7 +1706,7 @@
cmd_type_len |= IXGBE_ADVTXD_MAC_TSTAMP;
#endif
-#ifdef IXGBE_FDIR
+#ifdef IXGBE_FDIR_ATR
/* Do the flow director magic */
if ((txr->atr_sample) && (!adapter->fdir_reinit)) {
++txr->atr_count;
@@ -2836,7 +2857,7 @@
txbuf->eop_index = -1;
}
-#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;
@@ -3216,7 +3237,7 @@
return TRUE;
}
-#ifdef IXGBE_FDIR
+#ifdef IXGBE_FDIR_ATR
/*
** This routine parses packet headers so that Flow
** Director can make a hashed filter table entry
@@ -4151,7 +4172,7 @@
u32 rsc, ptype;
u16 hlen, plen, hdr, vtag;
bool eop;
-
+
/* Sync the ring. */
bus_dmamap_sync(rxr->rxdma.dma_tag, rxr->rxdma.dma_map,
BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
@@ -4933,6 +4954,30 @@
adapter->stats.fcoedwtc += IXGBE_READ_REG(hw, IXGBE_FCOEDWTC);
}
+ /* Only read fdir on 82599 */
+ if (hw->mac.type != ixgbe_mac_82598EB) {
+ 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 */
ifp->if_ipackets = adapter->stats.gprc;
ifp->if_opackets = adapter->stats.gptc;
@@ -5301,6 +5346,32 @@
SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "fc_dword_txd",
CTLFLAG_RD, &stats->fcoedwtc,
"FCoE DWords 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,
+ "");
}
/*
@@ -5392,3 +5463,133 @@
return (error);
}
+
+static int
+ixgbe_fdir_parse_address(char *string, struct in_addr *ip, int *port)
+{
+ char *token;
+ int error;
+
+ token = strsep(&string, ":");
+ if (!token)
+ return (EINVAL);
+
+ error = inet_aton(token, ip);
+ if (error != 1)
+ return (error);
+
+ token = strsep(&string, ":");
+ if (!token)
+ return (EINVAL);
+
+ *port = strtol(token, NULL, 0);
+ if (*port <= 0)
+ return (EINVAL);
+
+ return (0);
+}
+
+static int
+ixgbe_fdir_parse_sysctl(char *string, union ixgbe_atr_hash_dword *input,
+ union ixgbe_atr_hash_dword *common, int *que_index)
+{
+ char *token;
+ struct in_addr src_ip, dst_ip;
+ int src_port = 0, dst_port = 0;
+ int error;
+
+ token = strsep(&string, " ");
+ if (!token)
+ return (EINVAL);
+
+ if (!strcmp(token, "tcpv4"))
+ input->formatted.flow_type ^= IXGBE_ATR_FLOW_TYPE_TCPV4;
+ else if (!strcmp(token, "udpv4"))
+ input->formatted.flow_type ^= IXGBE_ATR_FLOW_TYPE_UDPV4;
+ else
+ return (EINVAL);
+
+ token = strsep(&string, " ");
+ if (!token)
+ return (EINVAL);
+
+ error = ixgbe_fdir_parse_address(token, &src_ip, &src_port);
+ if (error)
+ return (error);
+
+ common->port.src ^= htons(src_port);
+
+ token = strsep(&string, " ");
+ if (!token)
+ return (EINVAL);
+
+ error = ixgbe_fdir_parse_address(token, &dst_ip, &dst_port);
+ if (error)
+ return (error);
+
+ common->port.dst ^= htons(dst_port);
+ common->flex_bytes ^= htons(ETHERTYPE_IP);
+ common->ip ^= src_ip.s_addr ^ dst_ip.s_addr;
+
+ if (que_index != NULL) {
+ token = strsep(&string, " ");
+ if (!token)
+ return (EINVAL);
+ *que_index = strtol(token, NULL, 0);
+ }
+
+ return (0);
+}
+
+static int
+ixgbe_set_fdir_signature(SYSCTL_HANDLER_ARGS)
+{
+ char buf[1024] = {0,};
+ struct adapter *adapter;
+ union ixgbe_atr_hash_dword input = {.dword = 0};
+ union ixgbe_atr_hash_dword common = {.dword = 0};
+ int que_index;
+ int error;
+
+ adapter = (struct adapter *) arg1;
+ error = sysctl_handle_string(oidp, buf, sizeof(buf), req);
+ if (error)
+ return (error);
+ if (buf[0] == '\0')
+ return (0);
+
+ error = ixgbe_fdir_parse_sysctl(buf, &input, &common, &que_index);
+ if (error)
+ return (error);
+
+ ixgbe_fdir_add_signature_filter_82599(&adapter->hw,
+ input, common, que_index);
+
+ return (0);
+}
+
+static int
+ixgbe_clear_fdir_signature(SYSCTL_HANDLER_ARGS)
+{
+ char buf[1024] = {0,};
+ struct adapter *adapter;
+ union ixgbe_atr_hash_dword input = {.dword = 0};
+ union ixgbe_atr_hash_dword common = {.dword = 0};
+ int error;
+
+ adapter = (struct adapter *) arg1;
+ error = sysctl_handle_string(oidp, buf, sizeof(buf), req);
+ if (error)
+ return (error);
+ if (buf[0] == '\0')
+ return (0);
+
+ error = ixgbe_fdir_parse_sysctl(buf, &input, &common, NULL);
+ if (error)
+ return (error);
+
+ ixgbe_fdir_clear_signature_filter_82599(&adapter->hw,
+ input, common);
+
+ return (0);
+}
Index: ixgbe_type.h
===================================================================
--- ixgbe_type.h (revision 225013)
+++ ixgbe_type.h (working copy)
@@ -2588,6 +2588,8 @@
u64 qbtc[16];
u64 qprdc[16];
u64 pxon2offc[8];
+ u64 fdirfree_free;
+ u64 fdirfree_coll;
u64 fdirustat_add;
u64 fdirustat_remove;
u64 fdirfstat_fadd;
Index: ixgbe_82599.c
===================================================================
--- ixgbe_82599.c (revision 225013)
+++ ixgbe_82599.c (working copy)
@@ -1242,6 +1242,7 @@
/* Move the flexible bytes to use the ethertype - shift 6 words */
fdirctrl |= (0x6 << IXGBE_FDIRCTRL_FLEX_SHIFT);
+ fdirctrl |= IXGBE_FDIRCTRL_REPORT_STATUS;
/* Prime the keys for hashing */
IXGBE_WRITE_REG(hw, IXGBE_FDIRHKEY, IXGBE_ATR_BUCKET_HASH_KEY);
@@ -1552,7 +1553,7 @@
}
/**
- * ixgbe_atr_add_signature_filter_82599 - Adds a signature hash filter
+ * ixgbe_fdir_add_signature_filter_82599 - Adds a signature hash filter
* @hw: pointer to hardware structure
* @stream: input bitstream
* @queue: queue index to direct traffic to
@@ -1604,6 +1605,56 @@
}
/**
+ * ixgbe_fdir_clear_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_clear_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;
+}
+
+/**
* ixgbe_get_fdirtcpm_82599 - generate a tcp port from atr_input_masks
* @input_mask: mask to be bit swapped
*
@@ -2164,5 +2215,3 @@
out:
return lesm_enabled;
}
-
-
Index: ixgbe_api.h
===================================================================
--- ixgbe_api.h (revision 225013)
+++ ixgbe_api.h (working copy)
@@ -127,6 +127,9 @@
union ixgbe_atr_hash_dword input,
union ixgbe_atr_hash_dword common,
u8 queue);
+s32 ixgbe_fdir_clear_signature_filter_82599(struct ixgbe_hw *hw,
+ union ixgbe_atr_hash_dword input,
+ union ixgbe_atr_hash_dword common);
s32 ixgbe_fdir_add_perfect_filter_82599(struct ixgbe_hw *hw,
union ixgbe_atr_input *input,
struct ixgbe_atr_input_masks *masks,
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?CALG4x-W99OZxd=1ZDvW4=MBqeE3RPOazc7jc_3O30X-Pou3k8Q>
