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.
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,
_______________________________________________
freebsd-net@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-net
To unsubscribe, send any mail to "freebsd-net-unsubscr...@freebsd.org"

Reply via email to