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"