diff --git a/include/dpdk.h b/include/dpdk.h index bf77fc2ef..e409f5ec9 100644 --- a/include/dpdk.h +++ b/include/dpdk.h @@ -56,6 +56,9 @@ #include #include #include +#ifdef DPVS_CFG_I40E_PMD +#include +#endif #include "mbuf.h" typedef uint8_t lcoreid_t; diff --git a/patch/dpdk-stable-17.11.2/0003-net-i40e-support-input-set-configuration.patch b/patch/dpdk-stable-17.11.2/0003-net-i40e-support-input-set-configuration.patch new file mode 100644 index 000000000..a3822096a --- /dev/null +++ b/patch/dpdk-stable-17.11.2/0003-net-i40e-support-input-set-configuration.patch @@ -0,0 +1,335 @@ +From 6e9d7a7ef10f896cf7fc7f9335d50ad8ba1d8f1d Mon Sep 17 00:00:00 2001 +From: Beilei Xing +Date: Mon, 8 Jan 2018 11:09:13 +0800 +Subject: [PATCH] net/i40e: support input set configuration + +This patch supports getting/setting input set info for +RSS, FDIR, and FDIR flexible payload. It also adds some +helper functions for input set configuration. + +Signed-off-by: Beilei Xing +Acked-by: Qi Zhang +--- + drivers/net/i40e/rte_pmd_i40e.c | 141 ++++++++++++++++++++++ + drivers/net/i40e/rte_pmd_i40e.h | 138 +++++++++++++++++++++ + drivers/net/i40e/rte_pmd_i40e_version.map | 3 + + 3 files changed, 282 insertions(+) + +diff --git a/drivers/net/i40e/rte_pmd_i40e.c b/drivers/net/i40e/rte_pmd_i40e.c +index 947f13b86..55ae2fefb 100644 +--- a/drivers/net/i40e/rte_pmd_i40e.c ++++ b/drivers/net/i40e/rte_pmd_i40e.c +@@ -2956,3 +2956,144 @@ int rte_pmd_i40e_flow_add_del_packet_template( + + return i40e_flow_add_del_fdir_filter(dev, &filter_conf, add); + } ++ ++int ++rte_pmd_i40e_inset_get(uint16_t port, uint8_t pctype, ++ struct rte_pmd_i40e_inset *inset, ++ enum rte_pmd_i40e_inset_type inset_type) ++{ ++ struct rte_eth_dev *dev; ++ struct i40e_hw *hw; ++ uint64_t inset_reg; ++ uint32_t mask_reg[2]; ++ int i; ++ ++ RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV); ++ ++ dev = &rte_eth_devices[port]; ++ ++ if (!is_i40e_supported(dev)) ++ return -ENOTSUP; ++ ++ if (pctype > 63) ++ return -EINVAL; ++ ++ hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private); ++ memset(inset, 0, sizeof(struct rte_pmd_i40e_inset)); ++ ++ switch (inset_type) { ++ case INSET_HASH: ++ /* Get input set */ ++ inset_reg = ++ i40e_read_rx_ctl(hw, I40E_GLQF_HASH_INSET(1, pctype)); ++ inset_reg <<= I40E_32_BIT_WIDTH; ++ inset_reg |= ++ i40e_read_rx_ctl(hw, I40E_GLQF_HASH_INSET(0, pctype)); ++ /* Get field mask */ ++ mask_reg[0] = ++ i40e_read_rx_ctl(hw, I40E_GLQF_HASH_MSK(0, pctype)); ++ mask_reg[1] = ++ i40e_read_rx_ctl(hw, I40E_GLQF_HASH_MSK(1, pctype)); ++ break; ++ case INSET_FDIR: ++ inset_reg = ++ i40e_read_rx_ctl(hw, I40E_PRTQF_FD_INSET(pctype, 1)); ++ inset_reg <<= I40E_32_BIT_WIDTH; ++ inset_reg |= ++ i40e_read_rx_ctl(hw, I40E_PRTQF_FD_INSET(pctype, 0)); ++ mask_reg[0] = ++ i40e_read_rx_ctl(hw, I40E_GLQF_FD_MSK(0, pctype)); ++ mask_reg[1] = ++ i40e_read_rx_ctl(hw, I40E_GLQF_FD_MSK(1, pctype)); ++ break; ++ case INSET_FDIR_FLX: ++ inset_reg = ++ i40e_read_rx_ctl(hw, I40E_PRTQF_FD_FLXINSET(pctype)); ++ mask_reg[0] = ++ i40e_read_rx_ctl(hw, I40E_PRTQF_FD_MSK(pctype, 0)); ++ mask_reg[1] = ++ i40e_read_rx_ctl(hw, I40E_PRTQF_FD_MSK(pctype, 1)); ++ break; ++ default: ++ PMD_DRV_LOG(ERR, "Unsupported input set type."); ++ return -EINVAL; ++ } ++ ++ inset->inset = inset_reg; ++ ++ for (i = 0; i < 2; i++) { ++ inset->mask[i].field_idx = ((mask_reg[i] >> 16) & 0x3F); ++ inset->mask[i].mask = mask_reg[i] & 0xFFFF; ++ } ++ ++ return 0; ++} ++ ++int ++rte_pmd_i40e_inset_set(uint16_t port, uint8_t pctype, ++ struct rte_pmd_i40e_inset *inset, ++ enum rte_pmd_i40e_inset_type inset_type) ++{ ++ struct rte_eth_dev *dev; ++ struct i40e_hw *hw; ++ uint64_t inset_reg; ++ uint32_t mask_reg[2]; ++ int i; ++ ++ RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV); ++ ++ dev = &rte_eth_devices[port]; ++ ++ if (!is_i40e_supported(dev)) ++ return -ENOTSUP; ++ ++ if (pctype > 63) ++ return -EINVAL; ++ ++ hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private); ++ ++ /* Clear mask first */ ++ for (i = 0; i < 2; i++) ++ i40e_check_write_reg(hw, I40E_GLQF_FD_MSK(i, pctype), 0); ++ ++ inset_reg = inset->inset; ++ for (i = 0; i < 2; i++) ++ mask_reg[i] = (inset->mask[i].field_idx << 16) | ++ inset->mask[i].mask; ++ ++ switch (inset_type) { ++ case INSET_HASH: ++ i40e_check_write_reg(hw, I40E_GLQF_HASH_INSET(0, pctype), ++ (uint32_t)(inset_reg & UINT32_MAX)); ++ i40e_check_write_reg(hw, I40E_GLQF_HASH_INSET(1, pctype), ++ (uint32_t)((inset_reg >> ++ I40E_32_BIT_WIDTH) & UINT32_MAX)); ++ for (i = 0; i < 2; i++) ++ i40e_check_write_reg(hw, I40E_GLQF_HASH_MSK(i, pctype), ++ mask_reg[i]); ++ break; ++ case INSET_FDIR: ++ i40e_check_write_reg(hw, I40E_PRTQF_FD_INSET(pctype, 0), ++ (uint32_t)(inset_reg & UINT32_MAX)); ++ i40e_check_write_reg(hw, I40E_PRTQF_FD_INSET(pctype, 1), ++ (uint32_t)((inset_reg >> ++ I40E_32_BIT_WIDTH) & UINT32_MAX)); ++ for (i = 0; i < 2; i++) ++ i40e_check_write_reg(hw, I40E_GLQF_FD_MSK(i, pctype), ++ mask_reg[i]); ++ break; ++ case INSET_FDIR_FLX: ++ i40e_check_write_reg(hw, I40E_PRTQF_FD_FLXINSET(pctype), ++ (uint32_t)(inset_reg & UINT32_MAX)); ++ for (i = 0; i < 2; i++) ++ i40e_check_write_reg(hw, I40E_PRTQF_FD_MSK(pctype, i), ++ mask_reg[i]); ++ break; ++ default: ++ PMD_DRV_LOG(ERR, "Unsupported input set type."); ++ return -EINVAL; ++ } ++ ++ I40E_WRITE_FLUSH(hw); ++ return 0; ++} +diff --git a/drivers/net/i40e/rte_pmd_i40e.h b/drivers/net/i40e/rte_pmd_i40e.h +index 7ca37b197..1bdb68a28 100644 +--- a/drivers/net/i40e/rte_pmd_i40e.h ++++ b/drivers/net/i40e/rte_pmd_i40e.h +@@ -289,6 +289,23 @@ struct rte_pmd_i40e_pkt_template_conf { + uint32_t soft_id; + }; + ++enum rte_pmd_i40e_inset_type { ++ INSET_NONE = 0, ++ INSET_HASH, ++ INSET_FDIR, ++ INSET_FDIR_FLX, ++}; ++ ++struct rte_pmd_i40e_inset_mask { ++ uint8_t field_idx; ++ uint16_t mask; ++}; ++ ++struct rte_pmd_i40e_inset { ++ uint64_t inset; ++ struct rte_pmd_i40e_inset_mask mask[2]; ++}; ++ + /** + * Add or remove raw packet template filter to Flow Director. + * +@@ -905,4 +922,125 @@ int rte_pmd_i40e_query_vfid_by_mac(uint16_t port, + int rte_pmd_i40e_rss_queue_region_conf(uint16_t port_id, + enum rte_pmd_i40e_queue_region_op op_type, void *arg); + ++int rte_pmd_i40e_cfg_hash_inset(uint16_t port, ++ uint64_t pctype, uint64_t inset); ++ ++/** ++ * Get input set ++ * ++ * @param port ++ * The port identifier of the Ethernet device. ++ * @param pctype ++ * HW pctype. ++ * @param inset ++ * Buffer for input set info. ++ * @param inset_type ++ * Type of input set. ++ * @return ++ * - (0) if successful. ++ * - (-ENODEV) if *port* invalid. ++ * - (-EINVAL) if bad parameter. ++ * - (-ENOTSUP) if operation not supported. ++ */ ++int rte_pmd_i40e_inset_get(uint16_t port, uint8_t pctype, ++ struct rte_pmd_i40e_inset *inset, ++ enum rte_pmd_i40e_inset_type inset_type); ++ ++/** ++ * Set input set ++ * ++ * @param port ++ * The port identifier of the Ethernet device. ++ * @param pctype ++ * HW pctype. ++ * @param inset ++ * Input set info. ++ * @param inset_type ++ * Type of input set. ++ * @return ++ * - (0) if successful. ++ * - (-ENODEV) if *port* invalid. ++ * - (-EINVAL) if bad parameter. ++ * - (-ENOTSUP) if operation not supported. ++ */ ++int rte_pmd_i40e_inset_set(uint16_t port, uint8_t pctype, ++ struct rte_pmd_i40e_inset *inset, ++ enum rte_pmd_i40e_inset_type inset_type); ++ ++/** ++ * Get bit value for some field index ++ * ++ * @param inset ++ * Input set value. ++ * @param field_idx ++ * Field index for input set. ++ * @return ++ * - (1) if set. ++ * - (0) if cleared. ++ */ ++static inline int ++rte_pmd_i40e_inset_field_get(uint64_t inset, uint8_t field_idx) ++{ ++ uint8_t bit_idx; ++ ++ if (field_idx > 63) ++ return 0; ++ ++ bit_idx = 63 - field_idx; ++ if (inset & (1ULL << bit_idx)) ++ return 1; ++ ++ return 0; ++} ++ ++/** ++ * Set bit value for some field index ++ * ++ * @param inset ++ * Input set value. ++ * @param field_idx ++ * Field index for input set. ++ * @return ++ * - (-1) if failed. ++ * - (0) if success. ++ */ ++static inline int ++rte_pmd_i40e_inset_field_set(uint64_t *inset, uint8_t field_idx) ++{ ++ uint8_t bit_idx; ++ ++ if (field_idx > 63) ++ return -1; ++ ++ bit_idx = 63 - field_idx; ++ *inset = *inset | (1ULL << bit_idx); ++ ++ return 0; ++} ++ ++/** ++ * Clear bit value for some field index ++ * ++ * @param inset ++ * Input set value. ++ * @param field_idx ++ * Field index for input set. ++ * @return ++ * - (-1) if failed. ++ * - (0) if success. ++ */ ++static inline int ++rte_pmd_i40e_inset_field_clear(uint64_t *inset, uint8_t field_idx) ++{ ++ uint8_t bit_idx; ++ ++ if (field_idx > 63) ++ return -1; ++ ++ bit_idx = 63 - field_idx; ++ *inset = *inset & ~(1ULL << bit_idx); ++ ++ return 0; ++} ++ + #endif /* _PMD_I40E_H_ */ +diff --git a/drivers/net/i40e/rte_pmd_i40e_version.map b/drivers/net/i40e/rte_pmd_i40e_version.map +index ebbd24e03..5a5956176 100644 +--- a/drivers/net/i40e/rte_pmd_i40e_version.map ++++ b/drivers/net/i40e/rte_pmd_i40e_version.map +@@ -57,4 +57,7 @@ DPDK_17.11 { + rte_pmd_i40e_query_vfid_by_mac; + rte_pmd_i40e_rss_queue_region_conf; + ++ rte_pmd_i40e_inset_get; ++ rte_pmd_i40e_inset_set ++ + } DPDK_17.08; +-- +2.19.0 + diff --git a/src/config.mk b/src/config.mk index c90186d42..6d72ad93d 100644 --- a/src/config.mk +++ b/src/config.mk @@ -24,6 +24,7 @@ CFLAGS += -D DPVS_MAX_SOCKET=2 CFLAGS += -D DPVS_MAX_LCORE=64 +#CFLAGS += -D DPVS_CFG_I40E_PMD #CFLAGS += -D CONFIG_DPVS_NEIGH_DEBUG #CFLAGS += -D CONFIG_RECORD_BIG_LOOP #CFLAGS += -D CONFIG_DPVS_SAPOOL_DEBUG diff --git a/src/netif.c b/src/netif.c index a9021d5f5..5b41608a6 100644 --- a/src/netif.c +++ b/src/netif.c @@ -3236,6 +3236,90 @@ static inline void port_mtu_set(struct netif_port *port) port->mtu = mtu; } +#ifdef DPVS_CFG_I40E_PMD +/* + * i40e supports getting/setting input set info for RSS, FDIR, and FDIR flexible payload. + * Supported by commit https://github.com/DPDK/dpdk/commit/97bd4ef9a0fecfc660231d9547f94a8df616e8df. + * + * Example for configure non fragement IPv4 TCP input set by testpmd: + * 1. port config 0 pctype 33 fdir_inset clear all + * 2. port config 0 pctype 33 fdir_inset set field 27 + * 3. port config 0 pctype 33 fdir_inset set field 28 + * 4. flow_director_filter 0 mode IP add flow ipv4-tcp dst [LIP] fwd queue [queue_id] fd_id 1 + * + * Based on testpmd example, this function set dst port field mask and i40e can be used in FNAT and SNAT. + */ +static int __cfg_ipv4_input_set(uint16_t port_id, uint8_t pctype, uint16_t dport_mask) +{ + int ret; + struct rte_pmd_i40e_inset inset; + + memset(&inset, 0, sizeof(inset)); + ret = rte_pmd_i40e_inset_set(port_id, pctype, &inset, INSET_FDIR); + if (ret) { + RTE_LOG(ERR, NETIF, "Failed to clear input set.\n"); + return ret; + } + + // enable flow director input set for dst ip and dst port and use dst port mask + ret = rte_pmd_i40e_inset_get(port_id, pctype, &inset, INSET_FDIR); + if (ret) { + RTE_LOG(ERR, NETIF, "Failed to get input set.\n"); + return ret; + } + /* + * For field index, please refer to Table 7-12 in flowing link. + * https://www.intel.com/content/dam/www/public/us/en/documents/datasheets/xl710-10-40-controller-datasheet.pdf + */ + rte_pmd_i40e_inset_field_set(&inset.inset, 27); + rte_pmd_i40e_inset_field_set(&inset.inset, 28); + rte_pmd_i40e_inset_field_set(&inset.inset, 30); + inset.mask[0].field_idx = 30; + inset.mask[0].mask = dport_mask; + ret = rte_pmd_i40e_inset_set(port_id, pctype, &inset, INSET_FDIR); + if (ret) { + RTE_LOG(ERR, NETIF, "Failed to set input set.\n"); + } + + return ret; +} + +// I40E_FILTER_PCTYPE_NONF_IPV4_TCP is defined in i40e_type.h +static inline int __add_tcp_input_set(uint16_t port_id, uint16_t dport_mask) +{ + return __cfg_ipv4_input_set(port_id, 33, dport_mask); // I40E_FILTER_PCTYPE_NONF_IPV4_TCP = 33 +} + +// I40E_FILTER_PCTYPE_NONF_IPV4_UDP is defined in i40e_type.h +static inline int __add_udp_input_set(uint16_t port_id, uint16_t dport_mask) +{ + return __cfg_ipv4_input_set(port_id, 31, dport_mask); // I40E_FILTER_PCTYPE_NONF_IPV4_UDP = 31 +} + +/* + * use input set to configure FDIR for i40e NIC + * */ +static int netif_port_cfg_input_set(struct netif_port *port) { + int ret; + uint16_t dport_mask; + + // for input set mask, bit 0 means mask and it's little endian + dport_mask = ~ntohs(port->dev_conf.fdir_conf.mask.dst_port_mask); + ret = __add_tcp_input_set(port->id, dport_mask); + if (ret) { + RTE_LOG(ERR, NETIF, "Failed to add tcp input set.\n"); + return ret; + } + ret = __add_udp_input_set(port->id, dport_mask); + if (ret) { + RTE_LOG(ERR, NETIF, "Failed to add udp input set.\n"); + return ret; + } + + return ret; +} +#endif + /* * fdir mask must be set according to configured slave lcore number * */ @@ -3535,6 +3619,14 @@ int netif_port_start(struct netif_port *port) return EDPVS_DPDKAPIFAIL; } +#ifdef DPVS_CFG_I40E_PMD + ret = netif_port_cfg_input_set(port); + if (ret < 0) { + RTE_LOG(ERR, NETIF, "%s: fail to cfg input set %s\n", __func__, port->name); + return EDPVS_DPDKAPIFAIL; + } +#endif + // wait the device link up RTE_LOG(INFO, NETIF, "Waiting for %s link up, be patient ...\n", port->name); for (ii = 0; ii < wait_link_up_msecs; ii++) {