Building a better rte_flow parser
Subsystems (2)
PATCH v4 7/24 net/ixgbe: reimplement ethertype parser
In reply to Anatoly BurakovUse the new flow graph API and the common parsing framework to implement flow parser for ethertype.
The old ethertype parser was accepting certain things that were later rejected by the actual ethertype installation code, in particular DROP action as well as dst MAC address filtering. This was removed from the graph parser.
--- drivers/net/intel/ixgbe/ixgbe_ethdev.c | 92 ------ drivers/net/intel/ixgbe/ixgbe_ethdev.h | 4 - drivers/net/intel/ixgbe/ixgbe_flow.c | 220 +------------ drivers/net/intel/ixgbe/ixgbe_flow.h | 8 + .../net/intel/ixgbe/ixgbe_flow_ethertype.c | 299 ++++++++++++++++++ drivers/net/intel/ixgbe/meson.build | 1 + 6 files changed, 314 insertions(+), 310 deletions(-) create mode 100644 drivers/net/intel/ixgbe/ixgbe_flow_ethertype.c
drivers/net/intel/ixgbe/ixgbe_ethdev.c +0 -92
@@ -6850,20 +6850,6 @@ ixgbe_ethertype_filter_program(struct ixgbe_hw *hw, uint8_t idx,IXGBE_WRITE_FLUSH (hw); } -static int -ixgbe_ethertype_table_lookup (const struct ixgbe_ethertype_table *table, -uint16_t ethertype) -{ -int idx; - -for (idx =0 ; idx <IXGBE_MAX_ETQF_FILTERS ; idx++) { -if (table->entries[idx].used && - table->entries[idx].ethertype == ethertype) -return idx; - } -return -ENOENT ; -} -int ixgbe_ethertype_table_add (struct ixgbe_ethertype_table *table,uint16_t ethertype,uint32_t etqf,uint32_t etqs)
@@ -6901,42 +6887,6 @@ ixgbe_ethertype_table_del(struct ixgbe_ethertype_table *table, uint8_t idx)return 0 ; } -int -ixgbe_add_del_ethertype_filter (struct ixgbe_adapter *adapter, -struct rte_eth_ethertype_filter *filter,bool add) -{ -struct ixgbe_hw *hw =IXGBE_DEV_PRIVATE_TO_HW (adapter); -struct ixgbe_ethertype_table *table = - &IXGBE_DEV_PRIVATE_TO_FILTER_INFO (adapter)->ethertype_table; -uint32_t etqf, etqs; -int idx; - -if (filter->queue >=IXGBE_MAX_RX_QUEUE_NUM || - filter->ether_type ==RTE_ETHER_TYPE_IPV4 || - filter->ether_type ==RTE_ETHER_TYPE_IPV6 || - filter->flags & (RTE_ETHTYPE_FLAGS_MAC |RTE_ETHTYPE_FLAGS_DROP )) -return -EINVAL ; - -if (add) { - etqf =IXGBE_ETQF_FILTER_EN | filter->ether_type; - etqs =IXGBE_ETQS_QUEUE_EN | - (((uint32_t )filter->queue <<IXGBE_ETQS_RX_QUEUE_SHIFT ) & -IXGBE_ETQS_RX_QUEUE ); - idx =ixgbe_ethertype_table_add (table, filter->ether_type, etqf, etqs); -if (idx <0 ) -return idx; - }else { - idx =ixgbe_ethertype_table_lookup (table, filter->ether_type); -if (idx <0 ) -return idx; -ixgbe_ethertype_table_del (table, idx); - etqf =0 ; - etqs =0 ; - } -ixgbe_ethertype_filter_program (hw, idx, etqf, etqs); -return 0 ; -} -static int ixgbe_dev_flow_ops_get(__rte_unused struct rte_eth_dev *dev,const struct rte_flow_ops **ops)
@@ -8399,27 +8349,6 @@ ixgbe_ntuple_filter_restore(struct rte_eth_dev *dev) } } -/* restore ethernet type filter */ -static inline void -ixgbe_ethertype_filter_restore (struct rte_eth_dev *dev) -{ -struct ixgbe_hw *hw =IXGBE_DEV_PRIVATE_TO_HW (dev->data->dev_private); -struct ixgbe_filter_info *filter_info = -IXGBE_DEV_PRIVATE_TO_FILTER_INFO (dev->data->dev_private); -int i; - -for (i =0 ; i <IXGBE_MAX_ETQF_FILTERS ; i++) { -/* skip over entries not managed by rte_flow */ -if (i == filter_info->timesync_idx || - i == filter_info->antispoof_idx|| - !filter_info->ethertype_table.entries[i].used) -continue ; -ixgbe_ethertype_filter_program (hw, i, - filter_info->ethertype_table.entries[i].etqf, - filter_info->ethertype_table.entries[i].etqs); - } -} -/* restore SYN filter */ static inline void ixgbe_syn_filter_restore (struct rte_eth_dev *dev)
@@ -8475,7 +8404,6 @@ static int ixgbe_filter_restore(struct rte_eth_dev *dev) {ixgbe_ntuple_filter_restore (dev); -ixgbe_ethertype_filter_restore (dev);ixgbe_syn_filter_restore (dev);ixgbe_fdir_filter_restore (dev);ixgbe_l2_tn_filter_restore (dev);
@@ -8514,26 +8442,6 @@ ixgbe_clear_all_ntuple_filter(struct rte_eth_dev *dev)ixgbe_remove_5tuple_filter (adapter, p_5tuple); } -/* remove all the ether type filters */ -void -ixgbe_clear_all_ethertype_filter (struct rte_eth_dev *dev) -{ -struct ixgbe_hw *hw =IXGBE_DEV_PRIVATE_TO_HW (dev->data->dev_private); -struct ixgbe_filter_info *filter_info = -IXGBE_DEV_PRIVATE_TO_FILTER_INFO (dev->data->dev_private); -int i; - -for (i =0 ; i <IXGBE_MAX_ETQF_FILTERS ; i++) { -/* only clear rte_flow filters */ -if (!filter_info->ethertype_table.entries[i].used || - (filter_info->timesync_installed && i == filter_info->timesync_idx) || - (filter_info->antispoof_installed && i == filter_info->antispoof_idx)) -continue ; -ixgbe_ethertype_table_del (&filter_info->ethertype_table, i); -ixgbe_ethertype_filter_program (hw, i,0 ,0 ); - } -} -/* remove the SYN filter */ void ixgbe_clear_syn_filter (struct rte_eth_dev *dev)
drivers/net/intel/ixgbe/ixgbe_ethdev.h +0 -4
@@ -676,9 +676,6 @@ bool ixgbe_rss_update_sp(enum ixgbe_mac_type mac_type);int ixgbe_add_del_ntuple_filter (struct ixgbe_adapter *adapter,struct rte_eth_ntuple_filter *filter,bool add); -int ixgbe_add_del_ethertype_filter (struct ixgbe_adapter *adapter, -struct rte_eth_ethertype_filter *filter, -bool add);int ixgbe_syn_filter_set (struct ixgbe_adapter *adapter,struct rte_eth_syn_filter *filter,bool add);
@@ -759,7 +756,6 @@ int ixgbe_clear_all_fdir_filter(struct rte_eth_dev *dev);extern const struct rte_flow_ops ixgbe_flow_ops; -void ixgbe_clear_all_ethertype_filter (struct rte_eth_dev *dev);void ixgbe_clear_all_ntuple_filter (struct rte_eth_dev *dev);void ixgbe_clear_syn_filter (struct rte_eth_dev *dev);int ixgbe_clear_all_l2_tn_filter (struct rte_eth_dev *dev);
drivers/net/intel/ixgbe/ixgbe_flow.c +6 -214
296 lines not on this page · raw message
drivers/net/intel/ixgbe/ixgbe_flow.h +8 -0
@@ -5,8 +5,16 @@#ifndef _IXGBE_FLOW_H_#define _IXGBE_FLOW_H_ +#include "../common/flow_check.h" #include "../common/flow_engine.h" +int +ixgbe_flow_actions_check (const struct ci_flow_actions *actions, +const struct ci_flow_actions_check_param *param, +struct rte_flow_error *error); +extern const struct ci_flow_engine_list ixgbe_flow_engine_list; +extern const struct ci_flow_engine ixgbe_ethertype_flow_engine; +#endif /* _IXGBE_FLOW_H_ */
drivers/net/intel/ixgbe/ixgbe_flow_ethertype.c new file +299 -0
299 lines not on this page · raw message
drivers/net/intel/ixgbe/meson.build +1 -0
@@ -26,6 +26,7 @@ sources += files( 'ixgbe_ethdev.c', 'ixgbe_fdir.c', 'ixgbe_flow.c', + 'ixgbe_flow_ethertype.c', 'ixgbe_ipsec.c', 'ixgbe_pf.c', 'ixgbe_rxtx.c',
Signature · 1 line
2.52.0
PATCH v4 8/24 net/ixgbe: fix syn filter priority
In reply to Anatoly BurakovIn rte_flow API, 0 means highest priority. Fix SYN filter priority being wrongly set to lower priority when API requests priority 0.
--- drivers/net/intel/ixgbe/ixgbe_flow.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
drivers/net/intel/ixgbe/ixgbe_flow.c +3 -3
@@ -804,10 +804,10 @@ cons_parse_syn_filter(const struct rte_flow_attr *attr, const struct rte_flow_it filter->queue = q_act->index;/* Support 2 priorities, the lowest or highest. */ -if (!attr->priority) { - filter->hig_pri =0 ; - }else if (attr->priority == (uint32_t )~0U ) { +if (attr->priority ==0 ) { filter->hig_pri =1 ; + }else if (attr->priority == (uint32_t )~0U ) { + filter->hig_pri =0 ; }else {memset (filter,0 ,sizeof (struct rte_eth_syn_filter )); rte_flow_error_set(error, EINVAL,
Signature · 1 line
2.52.0
PATCH v4 9/24 net/ixgbe: reimplement syn parser
In reply to Anatoly BurakovUse the new flow graph API and the common parsing framework to implement flow parser for SYN.
As a result of this migration, queue index validation has changed:
- queue is now validated at parse time against the configured number of Rx queues (nb_rx_queues), rather than at install time against the hardware maximum (IXGBE_MAX_RX_QUEUE_NUM)
- the per-function queue bound check in ixgbe_syn_filter_set() has been removed as it is no longer needed
The syn filter tracking infrastructure is moved completely inside the new engine and is removed from the rest of the driver.
--- drivers/net/intel/ixgbe/ixgbe_ethdev.c | 70 +---- drivers/net/intel/ixgbe/ixgbe_ethdev.h | 7 +- drivers/net/intel/ixgbe/ixgbe_flow.c | 249 +----------------- drivers/net/intel/ixgbe/ixgbe_flow.h | 1 + drivers/net/intel/ixgbe/ixgbe_flow_syn.c | 312 +++++++++++++++++++++++ drivers/net/intel/ixgbe/meson.build | 1 + 6 files changed, 319 insertions(+), 321 deletions(-) create mode 100644 drivers/net/intel/ixgbe/ixgbe_flow_syn.c
drivers/net/intel/ixgbe/ixgbe_ethdev.c +2 -68
@@ -6463,43 +6463,11 @@ ixgbevf_set_default_mac_addr(struct rte_eth_dev *dev,return 0 ; } -int -ixgbe_syn_filter_set (struct ixgbe_adapter *adapter, -struct rte_eth_syn_filter *filter, -bool add) +void +ixgbe_syn_filter_program (struct ixgbe_hw *hw,uint32_t synqf) { -struct ixgbe_hw *hw =IXGBE_DEV_PRIVATE_TO_HW (adapter); -struct ixgbe_filter_info *filter_info = -IXGBE_DEV_PRIVATE_TO_FILTER_INFO (adapter); -uint32_t syn_info; -uint32_t synqf; - -if (filter->queue >=IXGBE_MAX_RX_QUEUE_NUM ) -return -EINVAL ; - - syn_info = filter_info->syn_info; - -if (add) { -if (syn_info &IXGBE_SYN_FILTER_ENABLE ) -return -EINVAL ; - synqf = (uint32_t )(((filter->queue <<IXGBE_SYN_FILTER_QUEUE_SHIFT ) & -IXGBE_SYN_FILTER_QUEUE ) |IXGBE_SYN_FILTER_ENABLE ); - -if (filter->hig_pri) - synqf |=IXGBE_SYN_FILTER_SYNQFP ; -else - synqf &= ~IXGBE_SYN_FILTER_SYNQFP ; - }else { - synqf =IXGBE_READ_REG (hw,IXGBE_SYNQF ); -if (!(syn_info &IXGBE_SYN_FILTER_ENABLE )) -return -ENOENT ; - synqf &= ~(IXGBE_SYN_FILTER_QUEUE |IXGBE_SYN_FILTER_ENABLE ); - } - - filter_info->syn_info = synqf;IXGBE_WRITE_REG (hw,IXGBE_SYNQF , synqf);IXGBE_WRITE_FLUSH (hw); -return 0 ; }
@@ -8349,23 +8317,6 @@ ixgbe_ntuple_filter_restore(struct rte_eth_dev *dev) } } -/* restore SYN filter */ -static inline void -ixgbe_syn_filter_restore (struct rte_eth_dev *dev) -{ -struct ixgbe_hw *hw =IXGBE_DEV_PRIVATE_TO_HW (dev->data->dev_private); -struct ixgbe_filter_info *filter_info = -IXGBE_DEV_PRIVATE_TO_FILTER_INFO (dev->data->dev_private); -uint32_t synqf; - - synqf = filter_info->syn_info; - -if (synqf &IXGBE_SYN_FILTER_ENABLE ) { -IXGBE_WRITE_REG (hw,IXGBE_SYNQF , synqf); -IXGBE_WRITE_FLUSH (hw); - } -} -/* restore L2 tunnel filter */ static inline void ixgbe_l2_tn_filter_restore (struct rte_eth_dev *dev)
@@ -8404,7 +8355,6 @@ static int ixgbe_filter_restore(struct rte_eth_dev *dev) {ixgbe_ntuple_filter_restore (dev); -ixgbe_syn_filter_restore (dev);ixgbe_fdir_filter_restore (dev);ixgbe_l2_tn_filter_restore (dev);ixgbe_rss_filter_restore (dev);
@@ -8442,22 +8392,6 @@ ixgbe_clear_all_ntuple_filter(struct rte_eth_dev *dev)ixgbe_remove_5tuple_filter (adapter, p_5tuple); } -/* remove the SYN filter */ -void -ixgbe_clear_syn_filter (struct rte_eth_dev *dev) -{ -struct ixgbe_hw *hw =IXGBE_DEV_PRIVATE_TO_HW (dev->data->dev_private); -struct ixgbe_filter_info *filter_info = -IXGBE_DEV_PRIVATE_TO_FILTER_INFO (dev->data->dev_private); - -if (filter_info->syn_info &IXGBE_SYN_FILTER_ENABLE ) { - filter_info->syn_info =0 ; - -IXGBE_WRITE_REG (hw,IXGBE_SYNQF ,0 ); -IXGBE_WRITE_FLUSH (hw); - } -} -/* remove all the L2 tunnel filters */ int ixgbe_clear_all_l2_tn_filter (struct rte_eth_dev *dev)
drivers/net/intel/ixgbe/ixgbe_ethdev.h +1 -6
@@ -311,8 +311,6 @@ struct ixgbe_filter_info {/* Bit mask for every used 5tuple filter */ uint32_t fivetuple_mask[IXGBE_5TUPLE_ARRAY_SIZE ];struct ixgbe_5tuple_filter_list fivetuple_list; -/* store the SYN filter info */ -uint32_t syn_info;/* store the rss filter info */ struct ixgbe_rte_flow_rss_conf rss_info;/* shared EtherType (ETQF) slot table */
@@ -676,15 +674,13 @@ bool ixgbe_rss_update_sp(enum ixgbe_mac_type mac_type);int ixgbe_add_del_ntuple_filter (struct ixgbe_adapter *adapter,struct rte_eth_ntuple_filter *filter,bool add); -int ixgbe_syn_filter_set (struct ixgbe_adapter *adapter, -struct rte_eth_syn_filter *filter, -bool add);void ixgbe_ethertype_filter_program (struct ixgbe_hw *hw,uint8_t idx,uint32_t etqf,uint32_t etqs);int ixgbe_ethertype_table_add (struct ixgbe_ethertype_table *table,uint16_t ethertype,uint32_t etqf,uint32_t etqs);int ixgbe_ethertype_table_del (struct ixgbe_ethertype_table *table,uint8_t idx); +void ixgbe_syn_filter_program (struct ixgbe_hw *hw,uint32_t synqf);/** * l2 tunnel configuration.
@@ -757,7 +753,6 @@ int ixgbe_clear_all_fdir_filter(struct rte_eth_dev *dev);extern const struct rte_flow_ops ixgbe_flow_ops;void ixgbe_clear_all_ntuple_filter (struct rte_eth_dev *dev); -void ixgbe_clear_syn_filter (struct rte_eth_dev *dev);int ixgbe_clear_all_l2_tn_filter (struct rte_eth_dev *dev);int ixgbe_disable_sec_tx_path_generic (struct ixgbe_hw *hw);
drivers/net/intel/ixgbe/ixgbe_flow.c +2 -247
318 lines not on this page · raw message
drivers/net/intel/ixgbe/ixgbe_flow.h +1 -0
@@ -16,5 +16,6 @@ ixgbe_flow_actions_check(const struct ci_flow_actions *actions,extern const struct ci_flow_engine_list ixgbe_flow_engine_list;extern const struct ci_flow_engine ixgbe_ethertype_flow_engine; +extern const struct ci_flow_engine ixgbe_syn_flow_engine;#endif /* _IXGBE_FLOW_H_ */
drivers/net/intel/ixgbe/ixgbe_flow_syn.c new file +312 -0
312 lines not on this page · raw message
drivers/net/intel/ixgbe/meson.build +1 -0
@@ -27,6 +27,7 @@ sources += files( 'ixgbe_fdir.c', 'ixgbe_flow.c', 'ixgbe_flow_ethertype.c', + 'ixgbe_flow_syn.c', 'ixgbe_ipsec.c', 'ixgbe_pf.c', 'ixgbe_rxtx.c',
Signature · 1 line
2.52.0
PATCH v4 10/24 net/ixgbe: reimplement L2 tunnel parser
In reply to Anatoly BurakovUse the new flow graph API and the common parsing framework to implement flow parser for L2 tunnel.
There are two L2-tag-related features in the driver: the global per-port one, and the one that can direct traffic to specific queues (the one the engine targets). The former is left completely untouched, while the latter one is migrated to use engine infrastructure and use internal tracking.
--- drivers/net/intel/ixgbe/ixgbe_ethdev.c | 251 +--------------- drivers/net/intel/ixgbe/ixgbe_ethdev.h | 26 +- drivers/net/intel/ixgbe/ixgbe_flow.c | 210 +------------- drivers/net/intel/ixgbe/ixgbe_flow.h | 1 + drivers/net/intel/ixgbe/ixgbe_flow_l2tun.c | 322 +++++++++++++++++++++ drivers/net/intel/ixgbe/meson.build | 1 + 6 files changed, 332 insertions(+), 479 deletions(-) create mode 100644 drivers/net/intel/ixgbe/ixgbe_flow_l2tun.c
drivers/net/intel/ixgbe/ixgbe_ethdev.c +3 -248
@@ -150,7 +150,6 @@ static int eth_ixgbe_dev_uninit(struct rte_eth_dev *eth_dev);static int ixgbe_fdir_filter_init (struct rte_eth_dev *eth_dev);static int ixgbe_fdir_filter_uninit (struct rte_eth_dev *eth_dev);static int ixgbe_l2_tn_filter_init (struct rte_eth_dev *eth_dev); -static int ixgbe_l2_tn_filter_uninit (struct rte_eth_dev *eth_dev);static int ixgbe_ntuple_filter_uninit (struct rte_eth_dev *eth_dev);static int ixgbe_dev_configure (struct rte_eth_dev *dev);static int ixgbe_dev_start (struct rte_eth_dev *dev);
@@ -1284,7 +1283,7 @@ eth_ixgbe_dev_init(struct rte_eth_dev *eth_dev, void *init_params __rte_unused) ret =ci_flow_engine_conf_init (&ad->flow_engine_conf, &ixgbe_flow_engine_list, eth_dev->data);if (ret) - goto err_flow_engine_conf_init; + goto err_l2_tn_filter_init;/* initialize flow filter lists */ ixgbe_filterlist_init (eth_dev);
@@ -1297,8 +1296,6 @@ eth_ixgbe_dev_init(struct rte_eth_dev *eth_dev, void *init_params __rte_unused)return 0 ; -err_flow_engine_conf_init: -ixgbe_l2_tn_filter_uninit (eth_dev); err_l2_tn_filter_init:ixgbe_fdir_filter_uninit (eth_dev); err_fdir_filter_init:
@@ -1368,25 +1365,6 @@ static int ixgbe_fdir_filter_uninit(struct rte_eth_dev *eth_dev)return 0 ; } -static int ixgbe_l2_tn_filter_uninit (struct rte_eth_dev *eth_dev) -{ -struct ixgbe_l2_tn_info *l2_tn_info = -IXGBE_DEV_PRIVATE_TO_L2_TN_INFO (eth_dev->data->dev_private); -struct ixgbe_l2_tn_filter *l2_tn_filter; - -rte_free (l2_tn_info->hash_map); -rte_hash_free (l2_tn_info->hash_handle); - -while ((l2_tn_filter =TAILQ_FIRST (&l2_tn_info->l2_tn_list))) { -TAILQ_REMOVE (&l2_tn_info->l2_tn_list, - l2_tn_filter, - entries); -rte_free (l2_tn_filter); - } - -return 0 ; -} -static int ixgbe_fdir_filter_init (struct rte_eth_dev *eth_dev) { struct ixgbe_hw_fdir_info *fdir_info =
@@ -1432,34 +1410,7 @@ static int ixgbe_l2_tn_filter_init(struct rte_eth_dev *eth_dev) {struct ixgbe_l2_tn_info *l2_tn_info =IXGBE_DEV_PRIVATE_TO_L2_TN_INFO (eth_dev->data->dev_private); -char l2_tn_hash_name[RTE_HASH_NAMESIZE ]; -struct rte_hash_parameters l2_tn_hash_params = { - .name = l2_tn_hash_name, - .entries =IXGBE_MAX_L2_TN_FILTER_NUM , - .key_len =sizeof (struct ixgbe_l2_tn_key ), - .hash_func = rte_hash_crc, - .hash_func_init_val =0 , - .socket_id =rte_socket_id (), - }; -TAILQ_INIT (&l2_tn_info->l2_tn_list); -snprintf (l2_tn_hash_name,RTE_HASH_NAMESIZE , -"l2_tn_%s" , eth_dev->device->name); - l2_tn_info->hash_handle =rte_hash_create (&l2_tn_hash_params); -if (!l2_tn_info->hash_handle) { -PMD_INIT_LOG (ERR ,"Failed to create L2 TN hash table!" ); -return -EINVAL ; - } - l2_tn_info->hash_map =rte_zmalloc ("ixgbe" , -sizeof (struct ixgbe_l2_tn_filter *) * -IXGBE_MAX_L2_TN_FILTER_NUM , -0 ); -if (!l2_tn_info->hash_map) { -PMD_INIT_LOG (ERR , -"Failed to allocate memory for L2 TN hash map!" ); -rte_hash_free (l2_tn_info->hash_handle); -return -ENOMEM ; - } l2_tn_info->e_tag_en = FALSE; l2_tn_info->e_tag_fwd_en = FALSE; l2_tn_info->e_tag_ether_type =RTE_ETHER_TYPE_ETAG ;
@@ -3100,9 +3051,6 @@ ixgbe_dev_close(struct rte_eth_dev *dev)/* remove all the fdir filters & hash */ ixgbe_fdir_filter_uninit (dev); -/* remove all the L2 tunnel filters & hash */ -ixgbe_l2_tn_filter_uninit (dev); -/* Remove all ntuple filters of the device */ ixgbe_ntuple_filter_uninit (dev);
@@ -7693,7 +7641,7 @@ ixgbe_e_tag_enable(struct ixgbe_hw *hw)return 0 ; } -static int +int ixgbe_e_tag_filter_del (struct ixgbe_adapter *adapter,struct ixgbe_l2_tunnel_conf *l2_tunnel) {
@@ -7730,7 +7678,7 @@ ixgbe_e_tag_filter_del(struct ixgbe_adapter *adapter,return ret; } -static int +int ixgbe_e_tag_filter_add (struct ixgbe_adapter *adapter,struct ixgbe_l2_tunnel_conf *l2_tunnel) {
@@ -7772,154 +7720,6 @@ ixgbe_e_tag_filter_add(struct ixgbe_adapter *adapter,return -EINVAL ; } -static inline struct ixgbe_l2_tn_filter * -ixgbe_l2_tn_filter_lookup (struct ixgbe_l2_tn_info *l2_tn_info, -struct ixgbe_l2_tn_key *key) -{ -int ret; - - ret =rte_hash_lookup (l2_tn_info->hash_handle, (const void *)key); -if (ret <0 ) -return NULL ; - -return l2_tn_info->hash_map[ret]; -} - -static inline int -ixgbe_insert_l2_tn_filter (struct ixgbe_l2_tn_info *l2_tn_info, -struct ixgbe_l2_tn_filter *l2_tn_filter) -{ -int ret; - - ret =rte_hash_add_key (l2_tn_info->hash_handle, - &l2_tn_filter->key); - -if (ret <0 ) { -PMD_DRV_LOG (ERR , -"Failed to insert L2 tunnel filter" -" to hash table %d!" , - ret); -return ret; - } - - l2_tn_info->hash_map[ret] = l2_tn_filter; - -TAILQ_INSERT_TAIL (&l2_tn_info->l2_tn_list, l2_tn_filter, entries); - -return 0 ; -} - -static inline int -ixgbe_remove_l2_tn_filter (struct ixgbe_l2_tn_info *l2_tn_info, -struct ixgbe_l2_tn_key *key) -{ -int ret; -struct ixgbe_l2_tn_filter *l2_tn_filter; - - ret =rte_hash_del_key (l2_tn_info->hash_handle, key); - -if (ret <0 ) { -PMD_DRV_LOG (ERR , -"No such L2 tunnel filter to delete %d!" , - ret); -return ret; - } - - l2_tn_filter = l2_tn_info->hash_map[ret]; - l2_tn_info->hash_map[ret] =NULL ; - -TAILQ_REMOVE (&l2_tn_info->l2_tn_list, l2_tn_filter, entries); -rte_free (l2_tn_filter); - -return 0 ; -} - -/* Add l2 tunnel filter */ -int -ixgbe_dev_l2_tunnel_filter_add (struct ixgbe_adapter *adapter, -struct ixgbe_l2_tunnel_conf *l2_tunnel, -bool restore) -{ -int ret; -struct ixgbe_l2_tn_info *l2_tn_info = -IXGBE_DEV_PRIVATE_TO_L2_TN_INFO (adapter); -struct ixgbe_l2_tn_key key; -struct ixgbe_l2_tn_filter *node; - -if (!restore) { - key.l2_tn_type = l2_tunnel->l2_tunnel_type; - key.tn_id = l2_tunnel->tunnel_id; - - node =ixgbe_l2_tn_filter_lookup (l2_tn_info, &key); - -if (node) { -PMD_DRV_LOG (ERR , -"The L2 tunnel filter already exists!" ); -return -EINVAL ; - } - - node =rte_zmalloc ("ixgbe_l2_tn" , -sizeof (struct ixgbe_l2_tn_filter ), -0 ); -if (!node) -return -ENOMEM ; - -memcpy (&node->key, - &key, -sizeof (struct ixgbe_l2_tn_key )); - node->pool = l2_tunnel->pool; - ret =ixgbe_insert_l2_tn_filter (l2_tn_info, node); -if (ret <0 ) { -rte_free (node); -return ret; - } - } - -switch (l2_tunnel->l2_tunnel_type) { -case RTE_ETH_L2_TUNNEL_TYPE_E_TAG : - ret =ixgbe_e_tag_filter_add (adapter, l2_tunnel); -break ; -default : -PMD_DRV_LOG (ERR ,"Invalid tunnel type" ); - ret = -EINVAL ; -break ; - } - -if ((!restore) && (ret <0 )) - (void )ixgbe_remove_l2_tn_filter (l2_tn_info, &key); - -return ret; -} - -/* Delete l2 tunnel filter */ -int -ixgbe_dev_l2_tunnel_filter_del (struct ixgbe_adapter *adapter, -struct ixgbe_l2_tunnel_conf *l2_tunnel) -{ -int ret; -struct ixgbe_l2_tn_info *l2_tn_info = -IXGBE_DEV_PRIVATE_TO_L2_TN_INFO (adapter); -struct ixgbe_l2_tn_key key; - - key.l2_tn_type = l2_tunnel->l2_tunnel_type; - key.tn_id = l2_tunnel->tunnel_id; - ret =ixgbe_remove_l2_tn_filter (l2_tn_info, &key); -if (ret <0 ) -return ret; - -switch (l2_tunnel->l2_tunnel_type) { -case RTE_ETH_L2_TUNNEL_TYPE_E_TAG : - ret =ixgbe_e_tag_filter_del (adapter, l2_tunnel); -break ; -default : -PMD_DRV_LOG (ERR ,"Invalid tunnel type" ); - ret = -EINVAL ; -break ; - } - -return ret; -} -static int ixgbe_e_tag_forwarding_en_dis (struct rte_eth_dev *dev,bool en) {
@@ -8317,26 +8117,6 @@ ixgbe_ntuple_filter_restore(struct rte_eth_dev *dev) } } -/* restore L2 tunnel filter */ -static inline void -ixgbe_l2_tn_filter_restore (struct rte_eth_dev *dev) -{ -struct ixgbe_adapter *adapter = -IXGBE_DEV_PRIVATE_TO_ADAPTER (dev->data->dev_private); -struct ixgbe_l2_tn_info *l2_tn_info = -IXGBE_DEV_PRIVATE_TO_L2_TN_INFO (adapter); -struct ixgbe_l2_tn_filter *node; -struct ixgbe_l2_tunnel_conf l2_tn_conf; - - TAILQ_FOREACH(node, &l2_tn_info->l2_tn_list, entries) { - l2_tn_conf.l2_tunnel_type = node->key.l2_tn_type; - l2_tn_conf.tunnel_id = node->key.tn_id; - l2_tn_conf.pool = node->pool; - (void )ixgbe_dev_l2_tunnel_filter_add (adapter, - &l2_tn_conf, TRUE); - } -} -/* restore rss filter */ static inline void ixgbe_rss_filter_restore (struct rte_eth_dev *dev)
@@ -8356,7 +8136,6 @@ ixgbe_filter_restore(struct rte_eth_dev *dev) {ixgbe_ntuple_filter_restore (dev);ixgbe_fdir_filter_restore (dev); -ixgbe_l2_tn_filter_restore (dev);ixgbe_rss_filter_restore (dev);return 0 ;
@@ -8392,30 +8171,6 @@ ixgbe_clear_all_ntuple_filter(struct rte_eth_dev *dev)ixgbe_remove_5tuple_filter (adapter, p_5tuple); } -/* remove all the L2 tunnel filters */ -int -ixgbe_clear_all_l2_tn_filter (struct rte_eth_dev *dev) -{ -struct ixgbe_adapter *adapter = -IXGBE_DEV_PRIVATE_TO_ADAPTER (dev->data->dev_private); -struct ixgbe_l2_tn_info *l2_tn_info = -IXGBE_DEV_PRIVATE_TO_L2_TN_INFO (dev->data->dev_private); -struct ixgbe_l2_tn_filter *l2_tn_filter; -struct ixgbe_l2_tunnel_conf l2_tn_conf; -int ret =0 ; - -while ((l2_tn_filter =TAILQ_FIRST (&l2_tn_info->l2_tn_list))) { - l2_tn_conf.l2_tunnel_type = l2_tn_filter->key.l2_tn_type; - l2_tn_conf.tunnel_id = l2_tn_filter->key.tn_id; - l2_tn_conf.pool = l2_tn_filter->pool; - ret =ixgbe_dev_l2_tunnel_filter_del (adapter, &l2_tn_conf); -if (ret <0 ) -return ret; - } - -return 0 ; -} -void ixgbe_dev_macsec_setting_save (struct rte_eth_dev *dev,struct ixgbe_macsec_setting *macsec_setting)
drivers/net/intel/ixgbe/ixgbe_ethdev.h +4 -22
@@ -323,23 +323,7 @@ struct ixgbe_filter_info {uint8_t antispoof_idx; }; -struct ixgbe_l2_tn_key { -enum rte_eth_tunnel_type l2_tn_type; -uint32_t tn_id; -}; - -struct ixgbe_l2_tn_filter { -TAILQ_ENTRY (ixgbe_l2_tn_filter) entries; -struct ixgbe_l2_tn_key key; -uint32_t pool; -}; - -TAILQ_HEAD (ixgbe_l2_tn_filter_list, ixgbe_l2_tn_filter); -struct ixgbe_l2_tn_info { -struct ixgbe_l2_tn_filter_list l2_tn_list; -struct ixgbe_l2_tn_filter **hash_map; -struct rte_hash *hash_handle;bool e_tag_en;/* e-tag enabled */ bool e_tag_fwd_en;/* e-tag based forwarding enabled */ uint16_t e_tag_ether_type;/* ether type for e-tag */
@@ -694,12 +678,11 @@ struct ixgbe_l2_tunnel_conf { };int -ixgbe_dev_l2_tunnel_filter_add (struct ixgbe_adapter *adapter, -struct ixgbe_l2_tunnel_conf *l2_tunnel, -bool restore); +ixgbe_e_tag_filter_add (struct ixgbe_adapter *adapter, +struct ixgbe_l2_tunnel_conf *l2_tunnel);int -ixgbe_dev_l2_tunnel_filter_del (struct ixgbe_adapter *adapter, -struct ixgbe_l2_tunnel_conf *l2_tunnel); +ixgbe_e_tag_filter_del (struct ixgbe_adapter *adapter, +struct ixgbe_l2_tunnel_conf *l2_tunnel);void ixgbe_filterlist_init (struct rte_eth_dev *dev);void ixgbe_filterlist_flush (struct rte_eth_dev *dev);/*
@@ -753,7 +736,6 @@ int ixgbe_clear_all_fdir_filter(struct rte_eth_dev *dev);extern const struct rte_flow_ops ixgbe_flow_ops;void ixgbe_clear_all_ntuple_filter (struct rte_eth_dev *dev); -int ixgbe_clear_all_l2_tn_filter (struct rte_eth_dev *dev);int ixgbe_disable_sec_tx_path_generic (struct ixgbe_hw *hw);
drivers/net/intel/ixgbe/ixgbe_flow.c +1 -209
276 lines not on this page · raw message
drivers/net/intel/ixgbe/ixgbe_flow.h +1 -0
@@ -17,5 +17,6 @@ extern const struct ci_flow_engine_list ixgbe_flow_engine_list;extern const struct ci_flow_engine ixgbe_ethertype_flow_engine;extern const struct ci_flow_engine ixgbe_syn_flow_engine; +extern const struct ci_flow_engine ixgbe_l2_tunnel_flow_engine;#endif /* _IXGBE_FLOW_H_ */
drivers/net/intel/ixgbe/ixgbe_flow_l2tun.c new file +322 -0
322 lines not on this page · raw message
drivers/net/intel/ixgbe/meson.build +1 -0
@@ -28,6 +28,7 @@ sources += files( 'ixgbe_flow.c', 'ixgbe_flow_ethertype.c', 'ixgbe_flow_syn.c', + 'ixgbe_flow_l2tun.c', 'ixgbe_ipsec.c', 'ixgbe_pf.c', 'ixgbe_rxtx.c',
Signature · 1 line
2.52.0
PATCH v4 11/24 net/ixgbe: fix ntuple filter priority
In reply to Anatoly BurakovCurrently, handling of ntuple filter priority is incorrect: it directly translates values inside the valid range (001b-111b), and clamps all invalid to 1. This leads to equivalence between rte_flow highest priority value (0), and rte_flow lower priority values (8+), both of which are mapped to 1 (lowest priority), while the 1-7 range is reversed (in ntuple, 111b is highest priority, but in rte_flow it is the lowest).
Fix the calculation by
- Translating highest rte_flow priority to highest ntuple priority
- Only clamping low priority values to 1 (lowest priority)
- Reversing the 1-7 mapping to preserve semantic meaning
--- drivers/net/intel/ixgbe/ixgbe_flow.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-)
drivers/net/intel/ixgbe/ixgbe_flow.c +16 -3
@@ -209,6 +209,7 @@ cons_parse_ntuple_filter(const struct rte_flow_attr *attr,const struct rte_flow_item_vlan *vlan_mask;struct rte_flow_item_eth eth_null;struct rte_flow_item_vlan vlan_null; +uint16_t priority;/* Priority must be 16-bit */ if (attr->priority >UINT16_MAX ) {
@@ -503,9 +504,21 @@ cons_parse_ntuple_filter(const struct rte_flow_attr *attr, filter->queue = q_act->index; - filter->priority = (uint16_t )attr->priority; -if (attr->priority <IXGBE_MIN_N_TUPLE_PRIO || attr->priority >IXGBE_MAX_N_TUPLE_PRIO ) - filter->priority =1 ; +/* +* rte_flow priority: 0 through UINT32_MAX, 0 is highest +* +* ntuple priority: 001b through 111b, 111b is highest +* +* which means we need to transform priority from rte_flow to ntuple: +* +* 1) clamp max value +* 2) reverse +* 3) add min value +*/ + priority =RTE_MIN (IXGBE_MAX_N_TUPLE_PRIO -1 , (uint16_t )attr->priority); + priority =IXGBE_MAX_N_TUPLE_PRIO -1 - priority; + priority +=IXGBE_MIN_N_TUPLE_PRIO ; + filter->priority = priority;return 0 ; }
Signature · 1 line
2.52.0
PATCH v4 12/24 net/ixgbe: reimplement ntuple parser
In reply to Anatoly BurakovUse the new flow graph API and the common parsing framework to implement flow parser for ntuple.
The 5tuple filter tracking infrastructure is moved completely inside the new engine and is removed from the rest of the driver.
--- drivers/net/intel/ixgbe/ixgbe_ethdev.c | 348 +--------- drivers/net/intel/ixgbe/ixgbe_ethdev.h | 28 +- drivers/net/intel/ixgbe/ixgbe_flow.c | 478 +------------- drivers/net/intel/ixgbe/ixgbe_flow.h | 1 + drivers/net/intel/ixgbe/ixgbe_flow_ntuple.c | 694 ++++++++++++++++++++ drivers/net/intel/ixgbe/meson.build | 1 + 6 files changed, 724 insertions(+), 826 deletions(-) create mode 100644 drivers/net/intel/ixgbe/ixgbe_flow_ntuple.c
drivers/net/intel/ixgbe/ixgbe_ethdev.c +23 -325
@@ -150,7 +150,6 @@ static int eth_ixgbe_dev_uninit(struct rte_eth_dev *eth_dev);static int ixgbe_fdir_filter_init (struct rte_eth_dev *eth_dev);static int ixgbe_fdir_filter_uninit (struct rte_eth_dev *eth_dev);static int ixgbe_l2_tn_filter_init (struct rte_eth_dev *eth_dev); -static int ixgbe_ntuple_filter_uninit (struct rte_eth_dev *eth_dev);static int ixgbe_dev_configure (struct rte_eth_dev *dev);static int ixgbe_dev_start (struct rte_eth_dev *dev);static int ixgbe_dev_stop (struct rte_eth_dev *dev);
@@ -301,10 +300,6 @@ static int ixgbevf_add_mac_addr(struct rte_eth_dev *dev,static void ixgbevf_remove_mac_addr (struct rte_eth_dev *dev,uint32_t index);static int ixgbevf_set_default_mac_addr (struct rte_eth_dev *dev,struct rte_ether_addr *mac_addr); -static int ixgbe_add_5tuple_filter (struct ixgbe_adapter *adapter, -struct ixgbe_5tuple_filter *filter); -static void ixgbe_remove_5tuple_filter (struct ixgbe_adapter *adapter, -struct ixgbe_5tuple_filter *filter);static int ixgbe_dev_flow_ops_get (struct rte_eth_dev *dev,const struct rte_flow_ops **ops);static int ixgbevf_dev_set_mtu (struct rte_eth_dev *dev,uint16_t mtu);
@@ -1266,9 +1261,6 @@ eth_ixgbe_dev_init(struct rte_eth_dev *eth_dev, void *init_params __rte_unused)memset (filter_info,0 ,sizeof (struct ixgbe_filter_info )); -/* initialize 5tuple filter list */ -TAILQ_INIT (&filter_info->fivetuple_list); -/* initialize flow director filter list & hash */ ret =ixgbe_fdir_filter_init (eth_dev);if (ret)
@@ -1328,24 +1320,6 @@ eth_ixgbe_dev_uninit(struct rte_eth_dev *eth_dev)return 0 ; } -static int ixgbe_ntuple_filter_uninit (struct rte_eth_dev *eth_dev) -{ -struct ixgbe_filter_info *filter_info = -IXGBE_DEV_PRIVATE_TO_FILTER_INFO (eth_dev->data->dev_private); -struct ixgbe_5tuple_filter *p_5tuple; - -while ((p_5tuple =TAILQ_FIRST (&filter_info->fivetuple_list))) { -TAILQ_REMOVE (&filter_info->fivetuple_list, - p_5tuple, - entries); -rte_free (p_5tuple); - } -memset (filter_info->fivetuple_mask,0 , -sizeof (uint32_t ) *IXGBE_5TUPLE_ARRAY_SIZE ); - -return 0 ; -} -static int ixgbe_fdir_filter_uninit (struct rte_eth_dev *eth_dev) { struct ixgbe_hw_fdir_info *fdir_info =
@@ -3051,9 +3025,6 @@ ixgbe_dev_close(struct rte_eth_dev *dev)/* remove all the fdir filters & hash */ ixgbe_fdir_filter_uninit (dev); -/* Remove all ntuple filters of the device */ -ixgbe_ntuple_filter_uninit (dev); -/* clear all the filters list */ ixgbe_filterlist_flush (dev);
@@ -6418,134 +6389,50 @@ ixgbe_syn_filter_program(struct ixgbe_hw *hw, uint32_t synqf)IXGBE_WRITE_FLUSH (hw); } - -static inline enum ixgbe_5tuple_protocol -convert_protocol_type (uint8_t protocol_value) +/* program a single ntuple (5-tuple) filter slot into hardware */ +void +ixgbe_ntuple_filter_program (struct ixgbe_hw *hw,uint16_t index, +const struct ixgbe_5tuple_filter_info *filter_info, +uint16_t queue) { -if (protocol_value ==IPPROTO_TCP ) -return IXGBE_FILTER_PROTOCOL_TCP ; -else if (protocol_value ==IPPROTO_UDP ) -return IXGBE_FILTER_PROTOCOL_UDP ; -else if (protocol_value ==IPPROTO_SCTP ) -return IXGBE_FILTER_PROTOCOL_SCTP ; -else -return IXGBE_FILTER_PROTOCOL_NONE ; -} - -/* inject a 5-tuple filter to HW */ -static inline void -ixgbe_inject_5tuple_filter (struct ixgbe_adapter *adapter, -struct ixgbe_5tuple_filter *filter) -{ -struct ixgbe_hw *hw =IXGBE_DEV_PRIVATE_TO_HW (adapter); -int i;uint32_t ftqf, sdpqf;uint32_t l34timir =0 ;uint8_t mask =0xff ; - i = filter->index; + sdpqf = (uint32_t )(filter_info->dst_port <<IXGBE_SDPQF_DSTPORT_SHIFT ); + sdpqf = sdpqf | (filter_info->src_port &IXGBE_SDPQF_SRCPORT ); - sdpqf = (uint32_t )(filter->filter_info.dst_port << -IXGBE_SDPQF_DSTPORT_SHIFT ); - sdpqf = sdpqf | (filter->filter_info.src_port &IXGBE_SDPQF_SRCPORT ); - - ftqf = (uint32_t )(filter->filter_info.proto & -IXGBE_FTQF_PROTOCOL_MASK ); - ftqf |= (uint32_t )((filter->filter_info.priority & + ftqf = (uint32_t )(filter_info->proto &IXGBE_FTQF_PROTOCOL_MASK ); + ftqf |= (uint32_t )((filter_info->priority &IXGBE_FTQF_PRIORITY_MASK ) <<IXGBE_FTQF_PRIORITY_SHIFT ); -if (filter->filter_info.src_ip_mask ==0 )/* 0 means compare. */ +if (filter_info->src_ip_mask ==0 )/* 0 means compare. */ mask &=IXGBE_FTQF_SOURCE_ADDR_MASK ; -if (filter->filter_info.dst_ip_mask ==0 ) +if (filter_info->dst_ip_mask ==0 ) mask &=IXGBE_FTQF_DEST_ADDR_MASK ; -if (filter->filter_info.src_port_mask ==0 ) +if (filter_info->src_port_mask ==0 ) mask &=IXGBE_FTQF_SOURCE_PORT_MASK ; -if (filter->filter_info.dst_port_mask ==0 ) +if (filter_info->dst_port_mask ==0 ) mask &=IXGBE_FTQF_DEST_PORT_MASK ; -if (filter->filter_info.proto_mask ==0 ) +if (filter_info->proto_mask ==0 ) mask &=IXGBE_FTQF_PROTOCOL_COMP_MASK ; ftqf |= mask <<IXGBE_FTQF_5TUPLE_MASK_SHIFT ; ftqf |=IXGBE_FTQF_POOL_MASK_EN ; ftqf |=IXGBE_FTQF_QUEUE_ENABLE ; -IXGBE_WRITE_REG (hw,IXGBE_DAQF (i), filter->filter_info.dst_ip); -IXGBE_WRITE_REG (hw,IXGBE_SAQF (i), filter->filter_info.src_ip); -IXGBE_WRITE_REG (hw,IXGBE_SDPQF (i), sdpqf); -IXGBE_WRITE_REG (hw,IXGBE_FTQF (i), ftqf); +IXGBE_WRITE_REG (hw,IXGBE_DAQF (index), filter_info->dst_ip); +IXGBE_WRITE_REG (hw,IXGBE_SAQF (index), filter_info->src_ip); +IXGBE_WRITE_REG (hw,IXGBE_SDPQF (index), sdpqf); +IXGBE_WRITE_REG (hw,IXGBE_FTQF (index), ftqf); l34timir |=IXGBE_L34T_IMIR_RESERVE ; - l34timir |= (uint32_t )(filter->queue << -IXGBE_L34T_IMIR_QUEUE_SHIFT ); -IXGBE_WRITE_REG (hw,IXGBE_L34T_IMIR (i), l34timir); + l34timir |= (uint32_t )(queue <<IXGBE_L34T_IMIR_QUEUE_SHIFT ); +IXGBE_WRITE_REG (hw,IXGBE_L34T_IMIR (index), l34timir); } -/* -* add a 5tuple filter -* -* @param -* dev: Pointer to struct rte_eth_dev. -* index: the index the filter allocates. -* filter: pointer to the filter that will be added. -* rx_queue: the queue id the filter assigned to. -* -* @return -* - On success, zero. -* - On failure, a negative value. -*/ -static int -ixgbe_add_5tuple_filter (struct ixgbe_adapter *adapter, -struct ixgbe_5tuple_filter *filter) +/* clear a single ntuple (5-tuple) filter slot from hardware */ +void +ixgbe_ntuple_filter_clear (struct ixgbe_hw *hw,uint16_t index) { -struct ixgbe_filter_info *filter_info = -IXGBE_DEV_PRIVATE_TO_FILTER_INFO (adapter); -int i, idx, shift; - -/* -* look for an unused 5tuple filter index, -* and insert the filter to list. -*/ -for (i =0 ; i <IXGBE_MAX_FTQF_FILTERS ; i++) { - idx = i / (sizeof (uint32_t ) *NBBY ); - shift = i % (sizeof (uint32_t ) *NBBY ); -if (!(filter_info->fivetuple_mask[idx] & (1 << shift))) { - filter_info->fivetuple_mask[idx] |=1 << shift; - filter->index = i; -TAILQ_INSERT_TAIL (&filter_info->fivetuple_list, - filter, - entries); -break ; - } - } -if (i >=IXGBE_MAX_FTQF_FILTERS ) { -PMD_DRV_LOG (ERR ,"5tuple filters are full." ); -return -ENOSYS ; - } - -ixgbe_inject_5tuple_filter (adapter, filter); - -return 0 ; -} - -/* -* remove a 5tuple filter -* -* @param -* dev: Pointer to struct rte_eth_dev. -* filter: the pointer of the filter will be removed. -*/ -static void -ixgbe_remove_5tuple_filter (struct ixgbe_adapter *adapter, -struct ixgbe_5tuple_filter *filter) -{ -struct ixgbe_hw *hw =IXGBE_DEV_PRIVATE_TO_HW (adapter); -struct ixgbe_filter_info *filter_info = -IXGBE_DEV_PRIVATE_TO_FILTER_INFO (adapter); -uint16_t index = filter->index; - - filter_info->fivetuple_mask[index / (sizeof (uint32_t ) *NBBY )] &= - ~(1 << (index % (sizeof (uint32_t ) *NBBY ))); -TAILQ_REMOVE (&filter_info->fivetuple_list, filter, entries); -rte_free (filter); -IXGBE_WRITE_REG (hw,IXGBE_DAQF (index),0 );IXGBE_WRITE_REG (hw,IXGBE_SAQF (index),0 );IXGBE_WRITE_REG (hw,IXGBE_SDPQF (index),0 );
@@ -6598,165 +6485,6 @@ ixgbevf_dev_set_mtu(struct rte_eth_dev *dev, uint16_t mtu)return 0 ; } -static inline struct ixgbe_5tuple_filter * -ixgbe_5tuple_filter_lookup (struct ixgbe_5tuple_filter_list *filter_list, -struct ixgbe_5tuple_filter_info *key) -{ -struct ixgbe_5tuple_filter *it; - - TAILQ_FOREACH(it, filter_list, entries) { -if (memcmp (key, &it->filter_info, -sizeof (struct ixgbe_5tuple_filter_info )) ==0 ) { -return it; - } - } -return NULL ; -} - -/* translate elements in struct rte_eth_ntuple_filter to struct ixgbe_5tuple_filter_info*/ -static inline int -ntuple_filter_to_5tuple (struct rte_eth_ntuple_filter *filter, -struct ixgbe_5tuple_filter_info *filter_info) -{ -if (filter->queue >=IXGBE_MAX_RX_QUEUE_NUM || - filter->priority >IXGBE_5TUPLE_MAX_PRI || - filter->priority <IXGBE_5TUPLE_MIN_PRI ) -return -EINVAL ; - -switch (filter->dst_ip_mask) { -case UINT32_MAX : - filter_info->dst_ip_mask =0 ; - filter_info->dst_ip = filter->dst_ip; -break ; -case 0 : - filter_info->dst_ip_mask =1 ; -break ; -default : -PMD_DRV_LOG (ERR ,"invalid dst_ip mask." ); -return -EINVAL ; - } - -switch (filter->src_ip_mask) { -case UINT32_MAX : - filter_info->src_ip_mask =0 ; - filter_info->src_ip = filter->src_ip; -break ; -case 0 : - filter_info->src_ip_mask =1 ; -break ; -default : -PMD_DRV_LOG (ERR ,"invalid src_ip mask." ); -return -EINVAL ; - } - -switch (filter->dst_port_mask) { -case UINT16_MAX : - filter_info->dst_port_mask =0 ; - filter_info->dst_port = filter->dst_port; -break ; -case 0 : - filter_info->dst_port_mask =1 ; -break ; -default : -PMD_DRV_LOG (ERR ,"invalid dst_port mask." ); -return -EINVAL ; - } - -switch (filter->src_port_mask) { -case UINT16_MAX : - filter_info->src_port_mask =0 ; - filter_info->src_port = filter->src_port; -break ; -case 0 : - filter_info->src_port_mask =1 ; -break ; -default : -PMD_DRV_LOG (ERR ,"invalid src_port mask." ); -return -EINVAL ; - } - -switch (filter->proto_mask) { -case UINT8_MAX : - filter_info->proto_mask =0 ; - filter_info->proto = -convert_protocol_type (filter->proto); -break ; -case 0 : - filter_info->proto_mask =1 ; -break ; -default : -PMD_DRV_LOG (ERR ,"invalid protocol mask." ); -return -EINVAL ; - } - - filter_info->priority = (uint8_t )filter->priority; -return 0 ; -} - -/* -* add or delete a ntuple filter -* -* @param -* dev: Pointer to struct rte_eth_dev. -* ntuple_filter: Pointer to struct rte_eth_ntuple_filter -* add: if true, add filter, if false, remove filter -* -* @return -* - On success, zero. -* - On failure, a negative value. -*/ -int -ixgbe_add_del_ntuple_filter (struct ixgbe_adapter *adapter, -struct rte_eth_ntuple_filter *ntuple_filter, -bool add) -{ -struct ixgbe_filter_info *filter_info = -IXGBE_DEV_PRIVATE_TO_FILTER_INFO (adapter); -struct ixgbe_5tuple_filter_info filter_5tuple; -struct ixgbe_5tuple_filter *filter; -int ret; - -if (ntuple_filter->flags !=RTE_5TUPLE_FLAGS ) { -PMD_DRV_LOG (ERR ,"only 5tuple is supported." ); -return -EINVAL ; - } - -memset (&filter_5tuple,0 ,sizeof (struct ixgbe_5tuple_filter_info )); - ret =ntuple_filter_to_5tuple (ntuple_filter, &filter_5tuple); -if (ret <0 ) -return ret; - - filter =ixgbe_5tuple_filter_lookup (&filter_info->fivetuple_list, - &filter_5tuple); -if (filter !=NULL && add) { -PMD_DRV_LOG (ERR ,"filter exists." ); -return -EEXIST ; - } -if (filter ==NULL && !add) { -PMD_DRV_LOG (ERR ,"filter doesn't exist." ); -return -ENOENT ; - } - -if (add) { - filter =rte_zmalloc ("ixgbe_5tuple_filter" , -sizeof (struct ixgbe_5tuple_filter ),0 ); -if (filter ==NULL ) -return -ENOMEM ; -memcpy (&filter->filter_info, - &filter_5tuple, -sizeof (struct ixgbe_5tuple_filter_info )); - filter->queue = ntuple_filter->queue; - ret =ixgbe_add_5tuple_filter (adapter, filter); -if (ret <0 ) { -rte_free (filter); -return ret; - } - }else -ixgbe_remove_5tuple_filter (adapter, filter); - -return 0 ; -} -void ixgbe_ethertype_filter_program (struct ixgbe_hw *hw,uint8_t idx,uint32_t etqf,uint32_t etqs)
@@ -8102,21 +7830,6 @@ int ixgbe_enable_sec_tx_path_generic(struct ixgbe_hw *hw)return IXGBE_SUCCESS ; } -/* restore n-tuple filter */ -static inline void -ixgbe_ntuple_filter_restore (struct rte_eth_dev *dev) -{ -struct ixgbe_adapter *adapter = -IXGBE_DEV_PRIVATE_TO_ADAPTER (dev->data->dev_private); -struct ixgbe_filter_info *filter_info = -IXGBE_DEV_PRIVATE_TO_FILTER_INFO (dev->data->dev_private); -struct ixgbe_5tuple_filter *node; - - TAILQ_FOREACH(node, &filter_info->fivetuple_list, entries) { -ixgbe_inject_5tuple_filter (adapter, node); - } -} -/* restore rss filter */ static inline void ixgbe_rss_filter_restore (struct rte_eth_dev *dev)
@@ -8134,7 +7847,6 @@ ixgbe_rss_filter_restore(struct rte_eth_dev *dev)static int ixgbe_filter_restore (struct rte_eth_dev *dev) { -ixgbe_ntuple_filter_restore (dev);ixgbe_fdir_filter_restore (dev);ixgbe_rss_filter_restore (dev);
@@ -8157,20 +7869,6 @@ ixgbe_l2_tunnel_conf(struct rte_eth_dev *dev) (void )ixgbe_update_e_tag_eth_type (hw, l2_tn_info->e_tag_ether_type); } -/* remove all the n-tuple filters */ -void -ixgbe_clear_all_ntuple_filter (struct rte_eth_dev *dev) -{ -struct ixgbe_adapter *adapter = -IXGBE_DEV_PRIVATE_TO_ADAPTER (dev->data->dev_private); -struct ixgbe_filter_info *filter_info = -IXGBE_DEV_PRIVATE_TO_FILTER_INFO (dev->data->dev_private); -struct ixgbe_5tuple_filter *p_5tuple; - -while ((p_5tuple =TAILQ_FIRST (&filter_info->fivetuple_list))) -ixgbe_remove_5tuple_filter (adapter, p_5tuple); -} -void ixgbe_dev_macsec_setting_save (struct rte_eth_dev *dev,struct ixgbe_macsec_setting *macsec_setting)
drivers/net/intel/ixgbe/ixgbe_ethdev.h +4 -24
@@ -100,8 +100,6 @@#define IXGBE_L34T_IMIR_LLI 0x00100000#define IXGBE_L34T_IMIR_QUEUE 0x0FE00000#define IXGBE_L34T_IMIR_QUEUE_SHIFT 21 -#define IXGBE_5TUPLE_MAX_PRI 7 -#define IXGBE_5TUPLE_MIN_PRI 1/* The overhead from MTU to max frame size. */ #define IXGBE_ETH_OVERHEAD (RTE_ETHER_HDR_LEN + RTE_ETHER_CRC_LEN)
@@ -265,8 +263,6 @@ enum ixgbe_5tuple_protocol { IXGBE_FILTER_PROTOCOL_NONE, }; -TAILQ_HEAD (ixgbe_5tuple_filter_list, ixgbe_5tuple_filter); -struct ixgbe_5tuple_filter_info {uint32_t dst_ip;uint32_t src_ip;
@@ -282,18 +278,6 @@ struct ixgbe_5tuple_filter_info { proto_mask:1 ;/* if mask is 1b, do not compare protocol. */ }; -/* 5tuple filter structure */ -struct ixgbe_5tuple_filter { -TAILQ_ENTRY (ixgbe_5tuple_filter) entries; -uint16_t index;/* the index of 5tuple filter */ -struct ixgbe_5tuple_filter_info filter_info; -uint16_t queue;/* rx queue assigned to */ -}; - -#define IXGBE_5TUPLE_ARRAY_SIZE \ - (RTE_ALIGN(IXGBE_MAX_FTQF_FILTERS, (sizeof(uint32_t) * NBBY)) / \ - (sizeof(uint32_t) * NBBY)) -/* Shared EtherType (ETQF) filter table. */ struct ixgbe_ethertype_table { struct ixgbe_ethertype_entry {
@@ -308,9 +292,6 @@ struct ixgbe_ethertype_table {* Structure to store filters' info. */ struct ixgbe_filter_info { -/* Bit mask for every used 5tuple filter */ -uint32_t fivetuple_mask[IXGBE_5TUPLE_ARRAY_SIZE ]; -struct ixgbe_5tuple_filter_list fivetuple_list;/* store the rss filter info */ struct ixgbe_rte_flow_rss_conf rss_info;/* shared EtherType (ETQF) slot table */
@@ -655,9 +636,10 @@ uint32_t ixgbe_rssrk_reg_get(enum ixgbe_mac_type mac_type, uint8_t i);bool ixgbe_rss_update_sp (enum ixgbe_mac_type mac_type); -int ixgbe_add_del_ntuple_filter (struct ixgbe_adapter *adapter, -struct rte_eth_ntuple_filter *filter, -bool add); +void ixgbe_ntuple_filter_program (struct ixgbe_hw *hw,uint16_t index, +const struct ixgbe_5tuple_filter_info *filter_info, +uint16_t queue); +void ixgbe_ntuple_filter_clear (struct ixgbe_hw *hw,uint16_t index);void ixgbe_ethertype_filter_program (struct ixgbe_hw *hw,uint8_t idx,uint32_t etqf,uint32_t etqs);
@@ -735,8 +717,6 @@ int ixgbe_clear_all_fdir_filter(struct rte_eth_dev *dev);extern const struct rte_flow_ops ixgbe_flow_ops; -void ixgbe_clear_all_ntuple_filter (struct rte_eth_dev *dev); -int ixgbe_disable_sec_tx_path_generic (struct ixgbe_hw *hw);int ixgbe_enable_sec_tx_path_generic (struct ixgbe_hw *hw);
drivers/net/intel/ixgbe/ixgbe_flow.c +1 -477
568 lines not on this page · raw message
drivers/net/intel/ixgbe/ixgbe_flow.h +1 -0
@@ -18,5 +18,6 @@ extern const struct ci_flow_engine_list ixgbe_flow_engine_list;extern const struct ci_flow_engine ixgbe_ethertype_flow_engine;extern const struct ci_flow_engine ixgbe_syn_flow_engine;extern const struct ci_flow_engine ixgbe_l2_tunnel_flow_engine; +extern const struct ci_flow_engine ixgbe_ntuple_flow_engine;#endif /* _IXGBE_FLOW_H_ */
drivers/net/intel/ixgbe/ixgbe_flow_ntuple.c new file +694 -0
694 lines not on this page · raw message
drivers/net/intel/ixgbe/meson.build +1 -0
@@ -29,6 +29,7 @@ sources += files( 'ixgbe_flow_ethertype.c', 'ixgbe_flow_syn.c', 'ixgbe_flow_l2tun.c', + 'ixgbe_flow_ntuple.c', 'ixgbe_ipsec.c', 'ixgbe_pf.c', 'ixgbe_rxtx.c',
Signature · 1 line
2.52.0
PATCH v4 13/24 net/ixgbe: reimplement security parser
In reply to Anatoly BurakovUse the new flow graph API and common flow engine infrastructure to implement flow parser for security filter. As a result, flow item checks have become more stringent:
- Mask is now explicitly validated to not have unsupported items in it, when previously they were ignored
- Mask is also validated to mask src/dst addresses, as otherwise it is inconsistent with rte_flow API
- The security engine was only looking for IPv4/IPv6 pattern items and completely ignored both prefix and suffix. This logic has been replaced by allowing [ETH]/IP/[UDP|ESP] patterns, as is used in ipsec-gw app
Previously, security parser was a special case, now it is a first class citizen. All decryption SA tracking has been moved into the engine, as the engine is now the authoritative source of new Rx flows and the state of the Rx SA table (the Tx SA table is still up to IPsec code to manage).
Because IPsec code does not manage the Rx SA table now, a synchronization mechanism is needed to prevent IPsec code from deallocating a security session when it is still referenced by security flows, so the security session is now atomically refcounted. For Tx, the refcount is effectively a noop, whereas for Rx it is now managed by rte_flow security engine.
--- drivers/net/intel/ixgbe/ixgbe_ethdev.h | 2 - drivers/net/intel/ixgbe/ixgbe_flow.c | 120 +--- drivers/net/intel/ixgbe/ixgbe_flow.h | 1 + drivers/net/intel/ixgbe/ixgbe_flow_security.c | 586 ++++++++++++++++++ drivers/net/intel/ixgbe/ixgbe_ipsec.c | 361 +++++------ drivers/net/intel/ixgbe/ixgbe_ipsec.h | 50 +- drivers/net/intel/ixgbe/meson.build | 1 + 7 files changed, 773 insertions(+), 348 deletions(-) create mode 100644 drivers/net/intel/ixgbe/ixgbe_flow_security.c
drivers/net/intel/ixgbe/ixgbe_ethdev.h +0 -2
@@ -313,8 +313,6 @@ struct ixgbe_l2_tn_info {struct rte_flow {struct ci_flow flow;enum rte_filter_type filter_type; -/* security flows are not rte_filter_type */ -bool is_security;void *rule; };
drivers/net/intel/ixgbe/ixgbe_flow.c +2 -118
174 lines not on this page · raw message
drivers/net/intel/ixgbe/ixgbe_flow.h +1 -0
@@ -19,5 +19,6 @@ extern const struct ci_flow_engine ixgbe_ethertype_flow_engine;extern const struct ci_flow_engine ixgbe_syn_flow_engine;extern const struct ci_flow_engine ixgbe_l2_tunnel_flow_engine;extern const struct ci_flow_engine ixgbe_ntuple_flow_engine; +extern const struct ci_flow_engine ixgbe_security_flow_engine;#endif /* _IXGBE_FLOW_H_ */
drivers/net/intel/ixgbe/ixgbe_flow_security.c new file +586 -0
586 lines not on this page · raw message
drivers/net/intel/ixgbe/ixgbe_ipsec.c +161 -200
444 lines not on this page · raw message
drivers/net/intel/ixgbe/ixgbe_ipsec.h +22 -28
91 lines not on this page · raw message
drivers/net/intel/ixgbe/meson.build +1 -0
@@ -30,6 +30,7 @@ sources += files( 'ixgbe_flow_syn.c', 'ixgbe_flow_l2tun.c', 'ixgbe_flow_ntuple.c', + 'ixgbe_flow_security.c', 'ixgbe_ipsec.c', 'ixgbe_pf.c', 'ixgbe_rxtx.c',
Signature · 1 line
2.52.0
PATCH v4 14/24 net/ixgbe: reimplement FDIR parser
In reply to Anatoly BurakovUse the new flow graph API and the common parsing framework to implement flow parser for flow director.
The FDIR flow tracking is moved inside the new engine, and the FDIR code is refactored to not mix software tracking with HW writes, remove redundant state and configuration stages, and structure the state storage better.
--- drivers/net/intel/ixgbe/ixgbe_ethdev.c | 118 +- drivers/net/intel/ixgbe/ixgbe_ethdev.h | 102 +- drivers/net/intel/ixgbe/ixgbe_fdir.c | 606 ++---- drivers/net/intel/ixgbe/ixgbe_flow.c | 1595 +--------------- drivers/net/intel/ixgbe/ixgbe_flow.h | 2 + drivers/net/intel/ixgbe/ixgbe_flow_fdir.c | 1626 +++++++++++++++++ .../net/intel/ixgbe/ixgbe_rxtx_vec_common.c | 4 +- drivers/net/intel/ixgbe/meson.build | 1 + 8 files changed, 1923 insertions(+), 2131 deletions(-) create mode 100644 drivers/net/intel/ixgbe/ixgbe_flow_fdir.c
drivers/net/intel/ixgbe/ixgbe_ethdev.c +54 -64
@@ -147,8 +147,6 @@ static const char * const ixgbevf_valid_arguments[] = {static int eth_ixgbe_dev_init (struct rte_eth_dev *eth_dev,void *init_params);static int eth_ixgbe_dev_uninit (struct rte_eth_dev *eth_dev); -static int ixgbe_fdir_filter_init (struct rte_eth_dev *eth_dev); -static int ixgbe_fdir_filter_uninit (struct rte_eth_dev *eth_dev);static int ixgbe_l2_tn_filter_init (struct rte_eth_dev *eth_dev);static int ixgbe_dev_configure (struct rte_eth_dev *dev);static int ixgbe_dev_start (struct rte_eth_dev *dev);
@@ -1008,7 +1006,7 @@ ixgbe_parse_devargs(struct ixgbe_adapter *adapter, &pballoc) != 0) ret = -EINVAL ; else - adapter->fdir_conf.pballoc = pballoc; + adapter->fdir_hw_config.pballoc = pballoc; }rte_kvargs_free (kvlist);
@@ -1261,11 +1259,6 @@ eth_ixgbe_dev_init(struct rte_eth_dev *eth_dev, void *init_params __rte_unused)memset (filter_info,0 ,sizeof (struct ixgbe_filter_info )); -/* initialize flow director filter list & hash */ - ret =ixgbe_fdir_filter_init (eth_dev); -if (ret) - goto err_fdir_filter_init; -/* initialize l2 tunnel filter list & hash */ ret =ixgbe_l2_tn_filter_init (eth_dev);if (ret)
@@ -1289,8 +1282,6 @@ eth_ixgbe_dev_init(struct rte_eth_dev *eth_dev, void *init_params __rte_unused)return 0 ; err_l2_tn_filter_init: -ixgbe_fdir_filter_uninit (eth_dev); -err_fdir_filter_init:ixgbe_disable_intr (hw);rte_intr_disable (intr_handle); rte_intr_callback_unregister(intr_handle,
@@ -1320,31 +1311,25 @@ eth_ixgbe_dev_uninit(struct rte_eth_dev *eth_dev)return 0 ; } -static int ixgbe_fdir_filter_uninit (struct rte_eth_dev *eth_dev) +void +ixgbe_fdir_state_detach (struct ixgbe_fdir_state *state) { -struct ixgbe_hw_fdir_info *fdir_info = -IXGBE_DEV_PRIVATE_TO_FDIR_INFO (eth_dev->data->dev_private); -struct ixgbe_fdir_filter *fdir_filter; +if (!ci_usage_count_release (&state->engine_use_count)) +return ; -rte_free (fdir_info->hash_map); -rte_hash_free (fdir_info->hash_handle); +rte_hash_free (state->hash_handle); -while ((fdir_filter =TAILQ_FIRST (&fdir_info->fdir_list))) { -TAILQ_REMOVE (&fdir_info->fdir_list, - fdir_filter, - entries); -rte_free (fdir_filter); - } - -return 0 ; +/* erase mask state as well */ + *state = (struct ixgbe_fdir_state ){0 }; } -static int ixgbe_fdir_filter_init (struct rte_eth_dev *eth_dev) +struct ixgbe_fdir_state * +ixgbe_fdir_state_attach (struct rte_eth_dev_data *dev_data) { -struct ixgbe_hw_fdir_info *fdir_info = -IXGBE_DEV_PRIVATE_TO_FDIR_INFO (eth_dev->data->dev_private); +struct ixgbe_adapter *adapter =IXGBE_DEV_PRIVATE_TO_ADAPTER (dev_data->dev_private); +struct ixgbe_fdir_state *state = &adapter->fdir_state;char fdir_hash_name[RTE_HASH_NAMESIZE ]; -struct rte_hash_parameters fdir_hash_params = { +struct rte_hash_parameters hash_params = { .name = fdir_hash_name, .entries =IXGBE_MAX_FDIR_FILTER_NUM , .key_len =sizeof (union ixgbe_atr_input ),
@@ -1353,31 +1338,28 @@ static int ixgbe_fdir_filter_init(struct rte_eth_dev *eth_dev) .socket_id = rte_socket_id(), }; -TAILQ_INIT (&fdir_info->fdir_list); -snprintf (fdir_hash_name,RTE_HASH_NAMESIZE , -"fdir_%s" , eth_dev->device->name); - fdir_info->hash_handle =rte_hash_create (&fdir_hash_params); -if (!fdir_info->hash_handle) { -PMD_INIT_LOG (ERR ,"Failed to create fdir hash table!" ); -return -EINVAL ; - } - fdir_info->hash_map =rte_zmalloc ("ixgbe" , -sizeof (struct ixgbe_fdir_filter *) * -IXGBE_MAX_FDIR_FILTER_NUM , -0 ); -if (!fdir_info->hash_map) { -PMD_INIT_LOG (ERR , -"Failed to allocate memory for fdir hash map!" ); -rte_hash_free (fdir_info->hash_handle); -return -ENOMEM ; - } - fdir_info->n_flows =0 ; - fdir_info->mask_added = FALSE; +snprintf (fdir_hash_name,RTE_HASH_NAMESIZE ,"ixgbe_fdir_hash_%s" , + dev_data->name); + +if (ci_usage_count_claim (&state->engine_use_count)) { +struct rte_hash *hash_handle; + + hash_handle =rte_hash_create (&hash_params); -/* drop queue is always fixed */ -IXGBE_DEV_FDIR_CONF (eth_dev)->drop_queue =IXGBE_FDIR_DROP_QUEUE ; +if (hash_handle ==NULL ) { +PMD_INIT_LOG (ERR ,"Failed to create fdir hash table!" ); +ci_usage_count_release (&state->engine_use_count); +return NULL ; + } + + state->hash_handle = hash_handle; + state->config.mode =RTE_FDIR_MODE_NONE ; + +/* set up default values for the mask */ +ixgbe_fdir_mask_set_default (&state->mask_conf.mask); + } -return 0 ; +return state; }static int ixgbe_l2_tn_filter_init (struct rte_eth_dev *eth_dev)
@@ -2174,9 +2156,27 @@ ixgbe_check_mq_mode(struct rte_eth_dev *dev) {struct rte_eth_conf *dev_conf = &dev->data->dev_conf;struct ixgbe_hw *hw =IXGBE_DEV_PRIVATE_TO_HW (dev->data->dev_private); +struct ixgbe_adapter *adapter =IXGBE_DEV_PRIVATE_TO_ADAPTER (dev->data->dev_private);uint16_t nb_rx_q = dev->data->nb_rx_queues;uint16_t nb_tx_q = dev->data->nb_tx_queues; +/* DCB-family modes reprogram RXPBSIZE and clash with FDIR's own use of it */ +switch (dev_conf->rxmode.mq_mode) { +case RTE_ETH_MQ_RX_VMDQ_DCB : +case RTE_ETH_MQ_RX_DCB : +case RTE_ETH_MQ_RX_DCB_RSS : +case RTE_ETH_MQ_RX_VMDQ_DCB_RSS : +if (adapter->fdir_state.config.mode !=RTE_FDIR_MODE_NONE ) { +PMD_INIT_LOG (ERR ,"Cannot use DCB mq_mode %d while " +"flow director rules are active." , + dev_conf->rxmode.mq_mode); +return -EINVAL ; + } +break ; +default : +break ; + } +if (RTE_ETH_DEV_SRIOV (dev).active !=0 ) {/* check multi-queue mode */ switch (dev_conf->rxmode.mq_mode) {
@@ -2497,7 +2497,6 @@ ixgbe_dev_start(struct rte_eth_dev *dev)struct ixgbe_adapter *adapter =IXGBE_DEV_PRIVATE_TO_ADAPTER (dev->data->dev_private);struct ixgbe_hw *hw =IXGBE_DEV_PRIVATE_TO_HW (adapter); -struct rte_eth_fdir_conf *fdir_conf =IXGBE_DEV_FDIR_CONF (dev);struct ixgbe_vf_info *vfinfo = *IXGBE_DEV_PRIVATE_TO_P_VFDATA (dev->data->dev_private);struct rte_pci_device *pci_dev =RTE_CLASS_TO_BUS_DEVICE (dev, *pci_dev);
@@ -2602,14 +2601,6 @@ ixgbe_dev_start(struct rte_eth_dev *dev)/* Configure DCB hw */ ixgbe_configure_dcb (dev); -if (fdir_conf->mode !=RTE_FDIR_MODE_NONE ) { -struct ixgbe_hw_fdir_info *info = -IXGBE_DEV_PRIVATE_TO_FDIR_INFO (adapter); - err =ixgbe_fdir_configure (dev, fdir_conf, &info->mask); -if (err) - goto error; - } -/* Restore vf rate limit */ if (vfinfo !=NULL ) {for (vf =0 ; vf < pci_dev->max_vfs; vf++)
@@ -2878,6 +2869,9 @@ ixgbe_dev_stop(struct rte_eth_dev *dev)/* reset hierarchy commit */ tm_conf->committed = false; +/* the reset above wiped the flow director setup, kept flows are replayed on start */ +ixgbe_fdir_hw_invalidate (dev); + adapter->rss_reta_updated =0 ; hw->adapter_stopped = true;
@@ -3022,9 +3016,6 @@ ixgbe_dev_close(struct rte_eth_dev *dev)/* uninitialize PF if max_vfs not zero */ ixgbe_pf_host_uninit (dev); -/* remove all the fdir filters & hash */ -ixgbe_fdir_filter_uninit (dev); -/* clear all the filters list */ ixgbe_filterlist_flush (dev);
@@ -7847,7 +7838,6 @@ ixgbe_rss_filter_restore(struct rte_eth_dev *dev)static int ixgbe_filter_restore (struct rte_eth_dev *dev) { -ixgbe_fdir_filter_restore (dev);ixgbe_rss_filter_restore (dev);return 0 ;
drivers/net/intel/ixgbe/ixgbe_ethdev.h +56 -46
165 lines not on this page · raw message
drivers/net/intel/ixgbe/ixgbe_fdir.c +179 -427
802 lines not on this page · raw message
drivers/net/intel/ixgbe/ixgbe_flow.c +3 -1592
1,664 lines not on this page · raw message
drivers/net/intel/ixgbe/ixgbe_flow.h +2 -0
@@ -20,5 +20,7 @@ extern const struct ci_flow_engine ixgbe_syn_flow_engine;extern const struct ci_flow_engine ixgbe_l2_tunnel_flow_engine;extern const struct ci_flow_engine ixgbe_ntuple_flow_engine;extern const struct ci_flow_engine ixgbe_security_flow_engine; +extern const struct ci_flow_engine ixgbe_fdir_flow_engine; +extern const struct ci_flow_engine ixgbe_fdir_tunnel_flow_engine;#endif /* _IXGBE_FLOW_H_ */
drivers/net/intel/ixgbe/ixgbe_flow_fdir.c new file +1626 -0
160 lines not on this page · raw message
drivers/net/intel/ixgbe/ixgbe_rxtx_vec_common.c +2 -2
Lines of this file are not shown. View the raw message.
The rest of this diff is not shown. View the raw message.
Signature · 1 line
2.52.0
Part of the diff is not shown here. View the raw message.
PATCH v4 15/24 net/ixgbe: don't embed RSS conf in filter structs
In reply to Anatoly BurakovCurrently, the RSS configuration driver structure directly embeds rte_flow RSS configuration item, which makes it so 1) the structure actually has duplicate data (or, to be more precise, a local copy of data pointed to by the RSS conf), and 2) direct struct assignments don't work because the RSS conf contains pointers.
Fix the structure to not embed RSS conf, and instead just store the data directly, so that we can perform struct assignments without any problems with poiinters.
--- drivers/net/intel/ixgbe/ixgbe_ethdev.c | 2 +- drivers/net/intel/ixgbe/ixgbe_ethdev.h | 18 ++++---- drivers/net/intel/ixgbe/ixgbe_flow.c | 37 +++++++++------- drivers/net/intel/ixgbe/ixgbe_rxtx.c | 61 ++++++++++++-------------- 4 files changed, 59 insertions(+), 59 deletions(-)
drivers/net/intel/ixgbe/ixgbe_ethdev.c +1 -1
@@ -7830,7 +7830,7 @@ ixgbe_rss_filter_restore(struct rte_eth_dev *dev)struct ixgbe_filter_info *filter_info =IXGBE_DEV_PRIVATE_TO_FILTER_INFO (adapter); -if (filter_info->rss_info.conf.queue_num) +if (filter_info->rss_info.queue_num)ixgbe_config_rss_filter (adapter, &filter_info->rss_info, TRUE); }
drivers/net/intel/ixgbe/ixgbe_ethdev.h +9 -9
@@ -209,9 +209,11 @@ struct ixgbe_fdir_state {struct ixgbe_fdir_mask_state mask_conf; }; -struct ixgbe_rte_flow_rss_conf { -struct rte_flow_action_rss conf;/**< RSS parameters. */ -uint8_t key[IXGBE_HKEY_MAX_INDEX *sizeof (uint32_t )];/* Hash key. */ +struct ixgbe_rss_conf { +uint64_t types;/**< RSS hash types. */ +uint32_t key_len;/**< Hash key length, 0 for default key. */ +uint32_t queue_num;/**< Number of entries in queue. */ +uint8_t key[IXGBE_HKEY_MAX_INDEX *sizeof (uint32_t )];/**< Hash key. */ uint16_t queue[IXGBE_MAX_RX_QUEUE_NUM ];/**< Queues indices to use. */ };
@@ -299,7 +301,7 @@ struct ixgbe_ethertype_table {*/ struct ixgbe_filter_info {/* store the rss filter info */ -struct ixgbe_rte_flow_rss_conf rss_info; +struct ixgbe_rss_conf rss_info;/* shared EtherType (ETQF) slot table */ struct ixgbe_ethertype_table ethertype_table;/* 1588 timestamping ETQF slot (valid when timesync_installed) */
@@ -738,12 +740,10 @@ void ixgbe_tm_conf_init(struct rte_eth_dev *dev);void ixgbe_tm_conf_uninit (struct rte_eth_dev *dev);int ixgbe_set_queue_rate_limit (struct rte_eth_dev *dev,uint16_t queue_idx,uint32_t tx_rate); -int ixgbe_rss_conf_init (struct ixgbe_rte_flow_rss_conf *out, -const struct rte_flow_action_rss *in); -int ixgbe_action_rss_same (const struct rte_flow_action_rss *comp, -const struct rte_flow_action_rss *with); +int ixgbe_rss_conf_init (struct ixgbe_rss_conf *out, +const struct rte_flow_action_rss *in);int ixgbe_config_rss_filter (struct ixgbe_adapter *adapter, -struct ixgbe_rte_flow_rss_conf *conf,bool add); +const struct ixgbe_rss_conf *conf,bool add);void ixgbe_dev_macsec_register_enable (struct rte_eth_dev *dev,struct ixgbe_macsec_setting *macsec_setting);
drivers/net/intel/ixgbe/ixgbe_flow.c +21 -16
@@ -57,7 +57,7 @@ struct ixgbe_filter_ele_base {/* rss filter list structure */ struct ixgbe_rss_conf_ele {struct ixgbe_filter_ele_base base; -struct ixgbe_rte_flow_rss_conf filter_info; +struct ixgbe_rss_conf filter_info; };/* ixgbe_flow memory list structure */ struct ixgbe_flow_mem {
@@ -140,7 +140,8 @@ ixgbe_flow_actions_check_rss(const struct ci_flow_actions *parsed_actions,const struct rte_flow_action *action = parsed_actions->actions[0 ];const struct rte_flow_action_rss *rss_act = action->conf;struct rte_eth_dev_data *dev_data = param->driver_ctx; -const size_t rss_key_len =sizeof (((struct ixgbe_rte_flow_rss_conf *)0 )->key); +const size_t rss_key_len =sizeof (((struct ixgbe_rss_conf *)0 )->key); +const size_t rss_queue_max =RTE_DIM (((struct ixgbe_rss_conf *)0 )->queue);size_t q_idx, q;/* check if queue list is not empty */
@@ -149,6 +150,11 @@ ixgbe_flow_actions_check_rss(const struct ci_flow_actions *parsed_actions,RTE_FLOW_ERROR_TYPE_ACTION_CONF , rss_act, "RSS queue list is empty"); } +if (rss_act->queue_num > rss_queue_max) { +return rte_flow_error_set (error,ENOTSUP , +RTE_FLOW_ERROR_TYPE_ACTION_CONF , rss_act, +"RSS queue list is too long" ); + }/* check if each RSS queue is valid */ for (q_idx =0 ; q_idx < rss_act->queue_num; q_idx++) {
@@ -185,7 +191,7 @@ static int ixgbe_parse_rss_filter(struct rte_eth_dev *dev, const struct rte_flow_attr *attr, const struct rte_flow_action actions[], - struct ixgbe_rte_flow_rss_conf *rss_conf, + struct ixgbe_rss_conf *rss_conf, struct rte_flow_error *error) { struct ci_flow_actions parsed_actions;
@@ -199,8 +205,8 @@ ixgbe_parse_rss_filter(struct rte_eth_dev *dev, .check = ixgbe_flow_actions_check_rss, .max_actions = 1, }; +const struct rte_flow_action_rss *rss_act;int ret; -const struct rte_flow_action *action;/* validate attributes */ ret =ci_flow_check_attr (attr,NULL , error);
@@ -211,12 +217,14 @@ ixgbe_parse_rss_filter(struct rte_eth_dev *dev, ret =ci_flow_check_actions (actions, &ap_param, &parsed_actions, error);if (ret)return ret; - action = parsed_actions.actions[0 ]; + rss_act = parsed_actions.actions[0 ]->conf; -if (ixgbe_rss_conf_init (rss_conf, action->conf)) -return rte_flow_error_set (error,EINVAL , -RTE_FLOW_ERROR_TYPE_ACTION ,NULL , + ret =ixgbe_rss_conf_init (rss_conf, rss_act); +if (ret) { +return rte_flow_error_set (error, -ret, +RTE_FLOW_ERROR_TYPE_ACTION_CONF , rss_act,"RSS context initialization failure" ); + }return 0 ; }
@@ -230,7 +238,7 @@ ixgbe_clear_rss_filter(struct rte_eth_dev *dev)struct ixgbe_filter_info *filter_info =IXGBE_DEV_PRIVATE_TO_FILTER_INFO (dev->data->dev_private); -if (filter_info->rss_info.conf.queue_num) +if (filter_info->rss_info.queue_num)ixgbe_config_rss_filter (adapter, &filter_info->rss_info, FALSE); }
@@ -275,7 +283,7 @@ ixgbe_flow_create(struct rte_eth_dev *dev, {int ret;struct ixgbe_adapter *adapter =IXGBE_DEV_PRIVATE_TO_ADAPTER (dev->data->dev_private); -struct ixgbe_rte_flow_rss_conf rss_conf; +struct ixgbe_rss_conf rss_conf = {0 };struct rte_flow *flow =NULL ;struct ixgbe_rss_conf_ele *rss_filter_ptr;struct ixgbe_flow_mem *ixgbe_flow_mem_ptr;
@@ -303,7 +311,6 @@ ixgbe_flow_create(struct rte_eth_dev *dev,TAILQ_INSERT_TAIL (&adapter->flow_list, &ixgbe_flow_mem_ptr->base, entries); -memset (&rss_conf,0 ,sizeof (struct ixgbe_rte_flow_rss_conf )); ret =ixgbe_parse_rss_filter (dev, attr, actions, &rss_conf, error);if (!ret) {
@@ -319,8 +326,7 @@ ixgbe_flow_create(struct rte_eth_dev *dev,rte_free (rss_filter_ptr); goto out; } -ixgbe_rss_conf_init (&rss_filter_ptr->filter_info, - &rss_conf.conf); + rss_filter_ptr->filter_info = rss_conf; flow->rule = rss_filter_ptr; flow->filter_type =RTE_ETH_FILTER_HASH ;return flow;
@@ -350,7 +356,7 @@ ixgbe_flow_validate(struct rte_eth_dev *dev, struct rte_flow_error *error) {struct ixgbe_adapter *ad =IXGBE_DEV_PRIVATE_TO_ADAPTER (dev->data->dev_private); -struct ixgbe_rte_flow_rss_conf rss_conf; +struct ixgbe_rss_conf rss_conf = {0 };int ret;/* try the new flow engine first */
@@ -360,7 +366,6 @@ ixgbe_flow_validate(struct rte_eth_dev *dev,/* fall back to legacy engines */ -memset (&rss_conf,0 ,sizeof (struct ixgbe_rte_flow_rss_conf )); ret =ixgbe_parse_rss_filter (dev, attr, actions, &rss_conf, error);
@@ -488,7 +493,7 @@ ixgbe_flow_rule_size(const struct rte_flow *flow)case RTE_ETH_FILTER_L2_TUNNEL :return sizeof (struct ixgbe_l2_tunnel_conf );case RTE_ETH_FILTER_HASH : -return sizeof (struct ixgbe_rte_flow_rss_conf ); +return sizeof (struct ixgbe_rss_conf );default :return 0 ; }
drivers/net/intel/ixgbe/ixgbe_rxtx.c +28 -33
114 lines not on this page · raw message
Signature · 1 line
2.52.0
PATCH v4 16/24 net/ixgbe: reimplement hash parser
In reply to Anatoly BurakovUse the new flow graph API and the common parsing framework to implement flow parser for RSS configuration.
RSS flow parser doesn't really parse any "flows", it was completely ignoring the flow patterns and was only looking at actions. It will therefore not specify a pattern graph and will match NULL pattern, empty patterns (START -> END), and ANY patterns (START -> ANY -> END).
RSS was the last engine using "filter list", so that is now removed. The RSS engine filter tracking was also moved completely into the new engine, and all of the "filter list" infrastructure is removed for good.
--- drivers/net/intel/ixgbe/ixgbe_ethdev.c | 30 -- drivers/net/intel/ixgbe/ixgbe_ethdev.h | 16 +- drivers/net/intel/ixgbe/ixgbe_flow.c | 423 +--------------------- drivers/net/intel/ixgbe/ixgbe_flow.h | 1 + drivers/net/intel/ixgbe/ixgbe_flow_hash.c | 216 +++++++++++ drivers/net/intel/ixgbe/ixgbe_rxtx.c | 43 +-- drivers/net/intel/ixgbe/meson.build | 1 + 7 files changed, 239 insertions(+), 491 deletions(-) create mode 100644 drivers/net/intel/ixgbe/ixgbe_flow_hash.c
drivers/net/intel/ixgbe/ixgbe_ethdev.c +0 -30
@@ -344,7 +344,6 @@ static int ixgbe_dev_udp_tunnel_port_add(struct rte_eth_dev *dev, struct rte_eth_udp_tunnel *udp_tunnel);static int ixgbe_dev_udp_tunnel_port_del (struct rte_eth_dev *dev,struct rte_eth_udp_tunnel *udp_tunnel); -static int ixgbe_filter_restore (struct rte_eth_dev *dev);static void ixgbe_l2_tunnel_conf (struct rte_eth_dev *dev);static int ixgbe_wait_for_link_up (struct ixgbe_hw *hw); static int devarg_handle_int(__rte_unused const char *key, const char *value,
@@ -1270,9 +1269,6 @@ eth_ixgbe_dev_init(struct rte_eth_dev *eth_dev, void *init_params __rte_unused)if (ret) goto err_l2_tn_filter_init; -/* initialize flow filter lists */ -ixgbe_filterlist_init (eth_dev); -/* initialize bandwidth configuration info */ memset (bw_conf,0 ,sizeof (struct ixgbe_bw_conf ));
@@ -2759,7 +2755,6 @@ ixgbe_dev_start(struct rte_eth_dev *dev)/* resume enabled intr since hw reset */ ixgbe_enable_intr (dev);ixgbe_l2_tunnel_conf (dev); -ixgbe_filter_restore (dev);if (tm_conf->root && !tm_conf->committed) PMD_DRV_LOG(WARNING,
@@ -3016,9 +3011,6 @@ ixgbe_dev_close(struct rte_eth_dev *dev)/* uninitialize PF if max_vfs not zero */ ixgbe_pf_host_uninit (dev); -/* clear all the filters list */ -ixgbe_filterlist_flush (dev); -/* Remove all Traffic Manager configuration */ ixgbe_tm_conf_uninit (dev);
@@ -7821,28 +7813,6 @@ int ixgbe_enable_sec_tx_path_generic(struct ixgbe_hw *hw)return IXGBE_SUCCESS ; } -/* restore rss filter */ -static inline void -ixgbe_rss_filter_restore (struct rte_eth_dev *dev) -{ -struct ixgbe_adapter *adapter = -IXGBE_DEV_PRIVATE_TO_ADAPTER (dev->data->dev_private); -struct ixgbe_filter_info *filter_info = -IXGBE_DEV_PRIVATE_TO_FILTER_INFO (adapter); - -if (filter_info->rss_info.queue_num) -ixgbe_config_rss_filter (adapter, - &filter_info->rss_info, TRUE); -} - -static int -ixgbe_filter_restore (struct rte_eth_dev *dev) -{ -ixgbe_rss_filter_restore (dev); - -return 0 ; -} -static void ixgbe_l2_tunnel_conf (struct rte_eth_dev *dev) {
drivers/net/intel/ixgbe/ixgbe_ethdev.h +4 -12
@@ -300,8 +300,6 @@ struct ixgbe_ethertype_table {* Structure to store filters' info. */ struct ixgbe_filter_info { -/* store the rss filter info */ -struct ixgbe_rss_conf rss_info;/* shared EtherType (ETQF) slot table */ struct ixgbe_ethertype_table ethertype_table;/* 1588 timestamping ETQF slot (valid when timesync_installed) */
@@ -318,10 +316,9 @@ struct ixgbe_l2_tn_info {uint16_t e_tag_ether_type;/* ether type for e-tag */ }; +/* no driver-specific data needed */ struct rte_flow {struct ci_flow flow; -enum rte_filter_type filter_type; -void *rule; };struct ixgbe_macsec_setting {
@@ -429,9 +426,6 @@ struct ixgbe_tm_conf {bool committed; }; -struct ixgbe_filter_ele_base ; -TAILQ_HEAD (ixgbe_filter_ele_list, ixgbe_filter_ele_base); -/* * Structure to store private data for each driver instance (for each port). */
@@ -453,7 +447,6 @@ struct ixgbe_adapter {struct ixgbe_bypass_info bps;#endif /* RTE_LIBRTE_IXGBE_BYPASS */ struct ixgbe_filter_info filter; -struct ixgbe_filter_ele_list flow_list;struct ixgbe_l2_tn_info l2_tn;struct ixgbe_bw_conf bw_conf;struct ixgbe_ipsec ipsec;
@@ -669,8 +662,6 @@ ixgbe_e_tag_filter_add(struct ixgbe_adapter *adapter,int ixgbe_e_tag_filter_del (struct ixgbe_adapter *adapter,struct ixgbe_l2_tunnel_conf *l2_tunnel); -void ixgbe_filterlist_init (struct rte_eth_dev *dev); -void ixgbe_filterlist_flush (struct rte_eth_dev *dev);/* * Flow director function prototypes */
@@ -742,8 +733,9 @@ int ixgbe_set_queue_rate_limit(struct rte_eth_dev *dev, uint16_t queue_idx, uint32_t tx_rate);int ixgbe_rss_conf_init (struct ixgbe_rss_conf *out,const struct rte_flow_action_rss *in); -int ixgbe_config_rss_filter (struct ixgbe_adapter *adapter, -const struct ixgbe_rss_conf *conf,bool add); +void ixgbe_hw_rss_filter_program (struct ixgbe_hw *hw, +const struct ixgbe_rss_conf *conf); +void ixgbe_hw_rss_filter_clear (struct ixgbe_hw *hw);void ixgbe_dev_macsec_register_enable (struct rte_eth_dev *dev,struct ixgbe_macsec_setting *macsec_setting);
drivers/net/intel/ixgbe/ixgbe_flow.c +8 -415
484 lines not on this page · raw message
drivers/net/intel/ixgbe/ixgbe_flow.h +1 -0
@@ -22,5 +22,6 @@ extern const struct ci_flow_engine ixgbe_ntuple_flow_engine;extern const struct ci_flow_engine ixgbe_security_flow_engine;extern const struct ci_flow_engine ixgbe_fdir_flow_engine;extern const struct ci_flow_engine ixgbe_fdir_tunnel_flow_engine; +extern const struct ci_flow_engine ixgbe_hash_flow_engine;#endif /* _IXGBE_FLOW_H_ */
drivers/net/intel/ixgbe/ixgbe_flow_hash.c new file +216 -0
216 lines not on this page · raw message
drivers/net/intel/ixgbe/ixgbe_rxtx.c +9 -34
70 lines not on this page · raw message
drivers/net/intel/ixgbe/meson.build +1 -0
@@ -32,6 +32,7 @@ sources += files( 'ixgbe_flow_ntuple.c', 'ixgbe_flow_security.c', 'ixgbe_flow_fdir.c', + 'ixgbe_flow_hash.c', 'ixgbe_ipsec.c', 'ixgbe_pf.c', 'ixgbe_rxtx.c',
Signature · 1 line
2.52.0
PATCH v4 17/24 net/ixgbe: advertise flow keep capability
In reply to Anatoly BurakovThe ixgbe driver's rte_flow implementation has always endeavored to keep flows across device restart, however it never advertised this capability. Advertise it explicitly.
--- doc/guides/rel_notes/release_26_11.rst | 7 +++++-- drivers/net/intel/ixgbe/ixgbe_ethdev.c | 3 +++ 2 files changed, 8 insertions(+), 2 deletions(-)
doc/guides/rel_notes/release_26_11.rst +5 -2
@@ -103,8 +103,11 @@ New Features * **Updated Intel ixgbe driver.** - Added ``fdir_buffer_size`` devarg to select the Flow Director table size - (``64k``, ``128k`` or ``256k``) at probe time. The default remains ``64k``. + * Added ``fdir_buffer_size`` devarg to select the Flow Director table size + (``64k``, ``128k`` or ``256k``) at probe time. The default remains ``64k``. + + * Advertised ``RTE_ETH_DEV_CAPA_FLOW_RULE_KEEP`` capability, + as flow rules were already kept across device restart. * **Updated NXP DPAA2 ethernet driver.**
drivers/net/intel/ixgbe/ixgbe_ethdev.c +3 -0
@@ -3914,6 +3914,9 @@ ixgbe_dev_info_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info) dev_info->reta_size =ixgbe_reta_size_get (hw->mac.type); dev_info->flow_type_rss_offloads =IXGBE_RSS_OFFLOAD_ALL ; +/* rte_flow rules are kept across dev_stop/dev_start and replayed on start */ + dev_info->dev_capa |=RTE_ETH_DEV_CAPA_FLOW_RULE_KEEP ; + dev_info->speed_capa =RTE_ETH_LINK_SPEED_1G |RTE_ETH_LINK_SPEED_10G ;if (hw->device_id ==IXGBE_DEV_ID_X550EM_A_1G_T || hw->device_id ==IXGBE_DEV_ID_X550EM_A_1G_T_L )
Signature · 1 line
2.52.0
PATCH v4 18/24 net/i40e: add support for common flow parsing
In reply to Anatoly BurakovImplement support for common flow parsing infrastructure in preparation for migration of flow engines.
Currently, i40e explicitly clears KEEP_FLOW capability flag, meaning that it advertises that all flows are flushed on dev stop. However, in practice i40e actually restores all flows on dev start, so while we will not (yet) advertise the KEEP_FLOW capability flag, we will also not flush the flows on dev stop with the new engines, and instead replay them.
--- drivers/net/intel/i40e/i40e_ethdev.c | 21 +++++++++++ drivers/net/intel/i40e/i40e_ethdev.h | 5 +++ drivers/net/intel/i40e/i40e_flow.c | 53 +++++++++++++++++++++++++++- drivers/net/intel/i40e/i40e_flow.h | 12 +++++++ 4 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 drivers/net/intel/i40e/i40e_flow.h
drivers/net/intel/i40e/i40e_ethdev.c +21 -0
@@ -42,6 +42,9 @@#include "i40e_regs.h" #include "rte_pmd_i40e.h" #include "i40e_hash.h" +#include "i40e_flow.h" + +#include "../common/flow_engine.h" #define ETH_I40E_FLOATING_VEB_ARG "enable_floating_veb"#define ETH_I40E_FLOATING_VEB_LIST_ARG "floating_veb_list"
@@ -1838,6 +1841,12 @@ eth_i40e_dev_init(struct rte_eth_dev *dev, void *init_params __rte_unused)if (ret <0 ) goto err_init_fdir_filter_list; +/* initialize flow engine configuration */ + ret =ci_flow_engine_conf_init (&pf->flow_engine_conf, + &i40e_flow_engine_list, dev->data); +if (ret <0 ) + goto err_flow_engine_conf_init; +/* initialize queue region configuration */ i40e_init_queue_region_conf (dev);
@@ -1846,6 +1855,12 @@ eth_i40e_dev_init(struct rte_eth_dev *dev, void *init_params __rte_unused)return 0 ; +err_flow_engine_conf_init: +rte_free (pf->fdir.fdir_flow_pool.bitmap); +rte_free (pf->fdir.fdir_flow_pool.pool); +rte_free (pf->fdir.fdir_filter_array); +rte_free (pf->fdir.hash_map); +rte_hash_free (pf->fdir.hash_table); err_init_fdir_filter_list:rte_hash_free (pf->tunnel.hash_table);rte_free (pf->tunnel.hash_map);
@@ -2613,6 +2628,8 @@ i40e_dev_start(struct rte_eth_dev *dev)/* Set the max frame size to HW*/ i40e_aq_set_mac_config (hw, max_frame_size, TRUE, false,0 ,NULL ); +ci_flow_replay (&pf->flow_engine_conf); +return I40E_SUCCESS ; tx_err:
@@ -2715,6 +2732,10 @@ i40e_dev_close(struct rte_eth_dev *dev) ret =i40e_dev_stop (dev); +/* free the flows and reset flow config */ +ci_flow_cleanup (&pf->flow_engine_conf); +ci_flow_engine_conf_reset (&pf->flow_engine_conf); +i40e_dev_free_queues (dev);/* Disable interrupt */
drivers/net/intel/i40e/i40e_ethdev.h +5 -0
@@ -21,6 +21,8 @@#include "base/i40e_type.h" #include "base/virtchnl.h" +#include "../common/flow_engine.h" +#define I40E_AQ_LEN 32#define I40E_AQ_BUF_SZ 4096/* Number of queues per TC should be one of 1, 2, 4, 8, 16, 32, 64 */
@@ -278,6 +280,7 @@ enum i40e_flxpld_layer_idx {* Struct to store flow created. */ struct rte_flow { +struct ci_flow base;TAILQ_ENTRY (rte_flow) node;enum rte_filter_type filter_type;void *rule;
@@ -1182,6 +1185,8 @@ struct i40e_pf {/* The floating enable flag for the specific VF */ bool floating_veb_list[I40E_MAX_VF ];struct i40e_flow_list flow_list; +/* flow engine configuration */ +struct ci_flow_engine_conf flow_engine_conf;bool mpls_replace_flag;/* 1 - MPLS filter replace is done */ bool gtp_replace_flag;/* 1 - GTP-C/U filter replace is done */ bool qinq_replace_flag;/* QINQ filter replace is done */
drivers/net/intel/i40e/i40e_flow.c +52 -1
107 lines not on this page · raw message
drivers/net/intel/i40e/i40e_flow.h new file +12 -0
@@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: BSD-3-Clause +* Copyright(c) 2026 Intel Corporation +*/ + +#ifndef _I40E_FLOW_H_ +#define _I40E_FLOW_H_ + +#include "../common/flow_engine.h" + +extern const struct ci_flow_engine_list i40e_flow_engine_list; + +#endif /* _I40E_FLOW_H_ */
Signature · 1 line
2.52.0
PATCH v4 19/24 net/i40e: reimplement ethertype parser
In reply to Anatoly BurakovUse the new flow graph API and the common parsing framework to implement flow parser for Ethertype.
The ethertype filter tracking has been moved completely inside the new engine, and the ethertype code is refactored to enabled that use case by decoupling hardware writes from software tracking.
--- drivers/net/intel/i40e/i40e_ethdev.c | 260 +------------- drivers/net/intel/i40e/i40e_ethdev.h | 30 +- drivers/net/intel/i40e/i40e_flow.c | 298 +--------------- drivers/net/intel/i40e/i40e_flow.h | 4 + drivers/net/intel/i40e/i40e_flow_ethertype.c | 351 +++++++++++++++++++ drivers/net/intel/i40e/meson.build | 1 + 6 files changed, 370 insertions(+), 574 deletions(-) create mode 100644 drivers/net/intel/i40e/i40e_flow_ethertype.c
drivers/net/intel/i40e/i40e_ethdev.c +2 -258
@@ -392,12 +392,6 @@ static int i40e_set_default_mac_addr(struct rte_eth_dev *dev,static int i40e_dev_mtu_set (struct rte_eth_dev *dev,uint16_t mtu); -static int i40e_ethertype_filter_convert ( -const struct rte_eth_ethertype_filter *input, -struct i40e_ethertype_filter *filter); -static int i40e_sw_ethertype_filter_insert (struct i40e_pf *pf, -struct i40e_ethertype_filter *filter); -static int i40e_tunnel_filter_convert (struct i40e_aqc_cloud_filters_element_bb *cld_filter,struct i40e_tunnel_filter *tunnel_filter);
@@ -405,7 +399,6 @@ static int i40e_sw_tunnel_filter_insert(struct i40e_pf *pf, struct i40e_tunnel_filter *tunnel_filter);static int i40e_cloud_filter_qinq_create (struct i40e_pf *pf); -static void i40e_ethertype_filter_restore (struct i40e_pf *pf);static void i40e_tunnel_filter_restore (struct i40e_pf *pf);static void i40e_filter_restore (struct i40e_pf *pf);static void i40e_notify_all_vfs_link_status (struct rte_eth_dev *dev);
@@ -1003,51 +996,6 @@ config_floating_veb(struct rte_eth_dev *dev)#define I40E_L2_TAGS_S_TAG_SHIFT 1#define I40E_L2_TAGS_S_TAG_MASK I40E_MASK(0x1, I40E_L2_TAGS_S_TAG_SHIFT) -static int -i40e_init_ethtype_filter_list (struct rte_eth_dev *dev) -{ -struct i40e_pf *pf =I40E_DEV_PRIVATE_TO_PF (dev->data->dev_private); -struct i40e_ethertype_rule *ethertype_rule = &pf->ethertype; -char ethertype_hash_name[RTE_HASH_NAMESIZE ]; -int ret; - -struct rte_hash_parameters ethertype_hash_params = { - .name = ethertype_hash_name, - .entries =I40E_MAX_ETHERTYPE_FILTER_NUM , - .key_len =sizeof (struct i40e_ethertype_filter_input ), - .hash_func = rte_hash_crc, - .hash_func_init_val =0 , - .socket_id =rte_socket_id (), - }; - -/* Initialize ethertype filter rule list and hash */ -TAILQ_INIT (ðertype_rule->ethertype_list); -snprintf (ethertype_hash_name,RTE_HASH_NAMESIZE , -"ethertype_%s" , dev->device->name); - ethertype_rule->hash_table =rte_hash_create (ðertype_hash_params); -if (!ethertype_rule->hash_table) { -PMD_INIT_LOG (ERR ,"Failed to create ethertype hash table!" ); -return -EINVAL ; - } - ethertype_rule->hash_map =rte_zmalloc ("i40e_ethertype_hash_map" , -sizeof (struct i40e_ethertype_filter *) * -I40E_MAX_ETHERTYPE_FILTER_NUM , -0 ); -if (!ethertype_rule->hash_map) { -PMD_INIT_LOG (ERR , -"Failed to allocate memory for ethertype hash map!" ); - ret = -ENOMEM ; - goto err_ethertype_hash_map_alloc; - } - -return 0 ; - -err_ethertype_hash_map_alloc: -rte_hash_free (ethertype_rule->hash_table); - -return ret; -} -static int i40e_init_tunnel_filter_list (struct rte_eth_dev *dev) {
@@ -1831,9 +1779,6 @@ eth_i40e_dev_init(struct rte_eth_dev *dev, void *init_params __rte_unused)/* Initialize the filter invalidation configuration */ i40e_init_filter_invalidation (pf); - ret =i40e_init_ethtype_filter_list (dev); -if (ret <0 ) - goto err_init_ethtype_filter_list; ret =i40e_init_tunnel_filter_list (dev);if (ret <0 ) goto err_init_tunnel_filter_list;
@@ -1865,9 +1810,6 @@ eth_i40e_dev_init(struct rte_eth_dev *dev, void *init_params __rte_unused)rte_hash_free (pf->tunnel.hash_table);rte_free (pf->tunnel.hash_map); err_init_tunnel_filter_list: -rte_hash_free (pf->ethertype.hash_table); -rte_free (pf->ethertype.hash_map); -err_init_ethtype_filter_list:rte_intr_callback_unregister (intr_handle, i40e_dev_interrupt_handler, dev);rte_free (dev->data->mac_addrs);
@@ -1890,24 +1832,6 @@ eth_i40e_dev_init(struct rte_eth_dev *dev, void *init_params __rte_unused)return ret; } -static void -i40e_rm_ethtype_filter_list (struct i40e_pf *pf) -{ -struct i40e_ethertype_filter *p_ethertype; -struct i40e_ethertype_rule *ethertype_rule; - - ethertype_rule = &pf->ethertype; -/* Remove all ethertype filter rules and hash */ -rte_free (ethertype_rule->hash_map); -rte_hash_free (ethertype_rule->hash_table); - -while ((p_ethertype =TAILQ_FIRST (ðertype_rule->ethertype_list))) { -TAILQ_REMOVE (ðertype_rule->ethertype_list, - p_ethertype, rules); -rte_free (p_ethertype); - } -} -static void i40e_rm_tunnel_filter_list (struct i40e_pf *pf) {
@@ -2805,7 +2729,6 @@ i40e_dev_close(struct rte_eth_dev *dev)i40e_msec_delay (500 ); }while (retries++ <5 ); -i40e_rm_ethtype_filter_list (pf);i40e_rm_tunnel_filter_list (pf);i40e_rm_fdir_filter_list (pf);
@@ -9891,130 +9814,16 @@ i40e_set_hash_inset(struct i40e_hw *hw, uint64_t input_set,return 0 ; } -/* Convert ethertype filter structure */ -static int -i40e_ethertype_filter_convert (const struct rte_eth_ethertype_filter *input, -struct i40e_ethertype_filter *filter) -{ -memcpy (&filter->input.mac_addr, &input->mac_addr, -RTE_ETHER_ADDR_LEN ); - filter->input.ether_type = input->ether_type; - filter->flags = input->flags; - filter->queue = input->queue; - -return 0 ; -} - -/* Check if there exists the ethertype filter */ -struct i40e_ethertype_filter * -i40e_sw_ethertype_filter_lookup (struct i40e_ethertype_rule *ethertype_rule, -const struct i40e_ethertype_filter_input *input) -{ -int ret; - - ret =rte_hash_lookup (ethertype_rule->hash_table, (const void *)input); -if (ret <0 ) -return NULL ; - -return ethertype_rule->hash_map[ret]; -} - -/* Add ethertype filter in SW list */ -static int -i40e_sw_ethertype_filter_insert (struct i40e_pf *pf, -struct i40e_ethertype_filter *filter) -{ -struct i40e_ethertype_rule *rule = &pf->ethertype; -int ret; - - ret =rte_hash_add_key (rule->hash_table, &filter->input); -if (ret <0 ) { -PMD_DRV_LOG (ERR , -"Failed to insert ethertype filter" -" to hash table %d!" , - ret); -return ret; - } - rule->hash_map[ret] = filter; - -TAILQ_INSERT_TAIL (&rule->ethertype_list, filter, rules); - -return 0 ; -} - -/* Delete ethertype filter in SW list */ int -i40e_sw_ethertype_filter_del (struct i40e_pf *pf, -struct i40e_ethertype_filter_input *input) -{ -struct i40e_ethertype_rule *rule = &pf->ethertype; -struct i40e_ethertype_filter *filter; -int ret; - - ret =rte_hash_del_key (rule->hash_table, input); -if (ret <0 ) { -PMD_DRV_LOG (ERR , -"Failed to delete ethertype filter" -" to hash table %d!" , - ret); -return ret; - } - filter = rule->hash_map[ret]; - rule->hash_map[ret] =NULL ; - -TAILQ_REMOVE (&rule->ethertype_list, filter, rules); -rte_free (filter); - -return 0 ; -} - -/* -* Configure ethertype filter, which can director packet by filtering -* with mac address and ether_type or only ether_type -*/ -int -i40e_ethertype_filter_set (struct i40e_pf *pf, +i40e_ethertype_filter_program (struct i40e_pf *pf,struct rte_eth_ethertype_filter *filter,bool add) {struct i40e_hw *hw =I40E_PF_TO_HW (pf); -struct i40e_ethertype_rule *ethertype_rule = &pf->ethertype; -struct i40e_ethertype_filter *ethertype_filter, *node; -struct i40e_ethertype_filter check_filter;struct i40e_control_filter_stats stats;uint16_t flags =0 ;int ret; -if (filter->queue >= pf->dev_data->nb_rx_queues) { -PMD_DRV_LOG (ERR ,"Invalid queue ID" ); -return -EINVAL ; - } -if (filter->ether_type ==RTE_ETHER_TYPE_IPV4 || - filter->ether_type ==RTE_ETHER_TYPE_IPV6 ) { -PMD_DRV_LOG (ERR , -"unsupported ether_type(0x%04x) in control packet filter." , - filter->ether_type); -return -EINVAL ; - } -if (filter->ether_type ==RTE_ETHER_TYPE_VLAN ) -PMD_DRV_LOG (WARNING , -"filter vlan ether_type in first tag is not supported." ); - -/* Check if there is the filter in SW list */ -memset (&check_filter,0 ,sizeof (check_filter)); -i40e_ethertype_filter_convert (filter, &check_filter); - node =i40e_sw_ethertype_filter_lookup (ethertype_rule, - &check_filter.input); -if (add && node) { -PMD_DRV_LOG (ERR ,"Conflict with existing ethertype rules!" ); -return -EINVAL ; - } - -if (!add && !node) { -PMD_DRV_LOG (ERR ,"There's no corresponding ethertype filter!" ); -return -EINVAL ; - } -if (!(filter->flags &RTE_ETHTYPE_FLAGS_MAC )) flags |=I40E_AQC_ADD_CONTROL_PACKET_FLAGS_IGNORE_MAC ;if (filter->flags &RTE_ETHTYPE_FLAGS_DROP )
@@ -10035,25 +9844,7 @@ i40e_ethertype_filter_set(struct i40e_pf *pf,if (ret <0 )return -ENOSYS ; -/* Add or delete a filter in SW list */ -if (add) { - ethertype_filter =rte_zmalloc ("ethertype_filter" , -sizeof (*ethertype_filter),0 ); -if (ethertype_filter ==NULL ) { -PMD_DRV_LOG (ERR ,"Failed to alloc memory." ); -return -ENOMEM ; - } - -memcpy (ethertype_filter, &check_filter, -sizeof (check_filter)); - ret =i40e_sw_ethertype_filter_insert (pf, ethertype_filter); -if (ret <0 ) -rte_free (ethertype_filter); - }else { - ret =i40e_sw_ethertype_filter_del (pf, &node->input); - } - -return ret; +return 0 ; } static int
@@ -11624,52 +11415,6 @@ i40e_dev_mtu_set(struct rte_eth_dev *dev, uint16_t mtu __rte_unused)return 0 ; } -/* Restore ethertype filter */ -static void -i40e_ethertype_filter_restore (struct i40e_pf *pf) -{ -struct i40e_hw *hw =I40E_PF_TO_HW (pf); -struct i40e_ethertype_filter_list - *ethertype_list = &pf->ethertype.ethertype_list; -struct i40e_ethertype_filter *f; -struct i40e_control_filter_stats stats; -enum i40e_status_code ret; -uint16_t flags; -bool stats_valid = false; - - TAILQ_FOREACH(f, ethertype_list, rules) { - flags =0 ; -if (!(f->flags &RTE_ETHTYPE_FLAGS_MAC )) - flags |=I40E_AQC_ADD_CONTROL_PACKET_FLAGS_IGNORE_MAC ; -if (f->flags &RTE_ETHTYPE_FLAGS_DROP ) - flags |=I40E_AQC_ADD_CONTROL_PACKET_FLAGS_DROP ; - flags |=I40E_AQC_ADD_CONTROL_PACKET_FLAGS_TO_QUEUE ; - - ret =i40e_aq_add_rem_control_packet_filter (hw, - f->input.mac_addr.addr_bytes, - f->input.ether_type, - flags, pf->main_vsi->seid, - f->queue,1 , &stats,NULL ); -if (ret !=I40E_SUCCESS ) { -PMD_DRV_LOG (ERR , -"Failed to restore ethertype filter, ether_type=0x%04x, queue=%u, vsi_seid=%u, err %d" , - f->input.ether_type, f->queue, - pf->main_vsi->seid, ret); -continue ; - } - - stats_valid = true; - } - -if (stats_valid) { -PMD_DRV_LOG (INFO ,"Ethertype filter:" -" mac_etype_used = %u, etype_used = %u," -" mac_etype_free = %u, etype_free = %u" , - stats.mac_etype_used, stats.etype_used, - stats.mac_etype_free, stats.etype_free); - } -} -/* Restore tunnel filter */ static void i40e_tunnel_filter_restore (struct i40e_pf *pf)
@@ -11728,7 +11473,6 @@ i40e_tunnel_filter_restore(struct i40e_pf *pf)static void i40e_filter_restore (struct i40e_pf *pf) { -i40e_ethertype_filter_restore (pf);i40e_tunnel_filter_restore (pf);i40e_fdir_filter_restore (pf); (void )i40e_hash_filter_restore (pf);
drivers/net/intel/i40e/i40e_ethdev.h +1 -29
@@ -805,27 +805,6 @@ struct i40e_fdir_info {/* Ethertype filter number HW supports */ #define I40E_MAX_ETHERTYPE_FILTER_NUM 768 -/* Ethertype filter struct */ -struct i40e_ethertype_filter_input { -struct rte_ether_addr mac_addr;/* Mac address to match */ -uint16_t ether_type;/* Ether type to match */ -}; - -struct i40e_ethertype_filter { -TAILQ_ENTRY (i40e_ethertype_filter) rules; -struct i40e_ethertype_filter_input input; -uint16_t flags;/* Flags from RTE_ETHTYPE_FLAGS_* */ -uint16_t queue;/* Queue assigned to when match */ -}; - -TAILQ_HEAD (i40e_ethertype_filter_list, i40e_ethertype_filter); - -struct i40e_ethertype_rule { -struct i40e_ethertype_filter_list ethertype_list; -struct i40e_ethertype_filter **hash_map; -struct rte_hash *hash_table; -}; -/* queue region info */ struct i40e_queue_region_info {/* the region id for this configuration */
@@ -1176,7 +1155,6 @@ struct i40e_pf {struct i40e_vmdq_info *vmdq;struct i40e_fdir_info fdir;/* flow director info */ -struct i40e_ethertype_rule ethertype;/* Ethertype filter rule */ struct i40e_tunnel_rule tunnel;/* Tunnel filter rule */ struct i40e_rss_conf_list rss_config_list;/* RSS rule list */ struct i40e_queue_regions queue_region;/* queue region info */
@@ -1325,7 +1303,6 @@ extern const struct rte_flow_ops i40e_flow_ops;struct i40e_filter_ctx {union { -struct rte_eth_ethertype_filter ethertype_filter;struct i40e_fdir_filter_conf fdir_filter;struct i40e_tunnel_filter_conf consistent_tunnel_filter;struct i40e_rte_flow_rss_conf rss_conf;
@@ -1407,11 +1384,6 @@ int i40e_rx_burst_mode_get(struct rte_eth_dev *dev, uint16_t queue_id, struct rte_eth_burst_mode *mode);int i40e_tx_burst_mode_get (struct rte_eth_dev *dev,uint16_t queue_id,struct rte_eth_burst_mode *mode); -struct i40e_ethertype_filter * -i40e_sw_ethertype_filter_lookup (struct i40e_ethertype_rule *ethertype_rule, -const struct i40e_ethertype_filter_input *input); -int i40e_sw_ethertype_filter_del (struct i40e_pf *pf, -struct i40e_ethertype_filter_input *input);int i40e_sw_fdir_filter_del (struct i40e_pf *pf,struct i40e_fdir_input *input); struct i40e_tunnel_filter *
@@ -1420,7 +1392,7 @@ i40e_sw_tunnel_filter_lookup(struct i40e_tunnel_rule *tunnel_rule,int i40e_sw_tunnel_filter_del (struct i40e_pf *pf,struct i40e_tunnel_filter_input *input);uint64_t i40e_get_default_input_set (uint16_t pctype); -int i40e_ethertype_filter_set (struct i40e_pf *pf, +int i40e_ethertype_filter_program (struct i40e_pf *pf,struct rte_eth_ethertype_filter *filter,bool add); struct rte_flow *
drivers/net/intel/i40e/i40e_flow.c +11 -287
398 lines not on this page · raw message
drivers/net/intel/i40e/i40e_flow.h +4 -0
@@ -7,6 +7,10 @@#include "../common/flow_engine.h" +int i40e_get_outer_vlan (struct i40e_pf *pf,uint16_t *tpid); +extern const struct ci_flow_engine_list i40e_flow_engine_list; +extern const struct ci_flow_engine i40e_flow_engine_ethertype; +#endif /* _I40E_FLOW_H_ */
drivers/net/intel/i40e/i40e_flow_ethertype.c new file +351 -0
351 lines not on this page · raw message
drivers/net/intel/i40e/meson.build +1 -0
@@ -33,6 +33,7 @@ sources += files( 'i40e_pf.c', 'i40e_fdir.c', 'i40e_flow.c', + 'i40e_flow_ethertype.c', 'i40e_tm.c', 'i40e_hash.c', 'i40e_vf_representor.c',
Signature · 1 line
2.52.0
PATCH v4 20/24 net/i40e: refactor FDIR engine infrastructure
In reply to Anatoly BurakovCurrently, there are multiple problems with how i40e flow directory feature is implemented, both in terms of how it works with rte_flow, and how it integrates with the PMD-specific packet template API.
For one, these two subsystems, while using shared infrastructure, do not really interact or cooperate, and are built on top of special cases in FDIR path. More specifically, the packet template code does not store its packet in the hash map, and has a different hashing scheme, yet it still registers itself in FDIR flow list, hash table, and hash map. This list is then used by dev_start to restore FDIR filters that user has inserted into the list. These filters, as written, cannot be reprogrammed that way because the information a filter restore function would need is lost on insert (the packet pointer is not added to the hash map).
Another issue is that while rte_flow FDIR code does lazy FDIR init on first added flow, the packet template API does not, even though it too relies on the same hardware feature, nor does it ever do teardown on last FDIR flow.
Yet another issue is how the "filter restore" code itself is implemented, namely that currently it simply does not work. When doing filter restore, the driver will walk every FDIR filter stored in the TAILQ, and attempt to program it. However, inside the program function, there is a deduplication check (to see if flow being installed is already present in the flow hash table), which fails because the flows we are programming come from the same list that is being checked for deduplication, which makes the entire filter restore a no-op.
The FDIR filter programming code itself also has a number of readability problems as well as being otherwise hard to use - SW bookkeeping, validation, and flow programming is interspersed within the code, and it is difficult to reason about what happens when the code is called from this or that context.
So, this refactor does the following:
- Reorganize FDIR internals to track packet templates and rte_flow FDIR flows separately
- Refactor FDIR init/teardown to always happen on first/last rule, so that whichever API happens to call FDIR first, the state is consistent
- Rework the FDIR code to disentangle FDIR flow rule programming, Flex PIT checks, SW bookkeeping, etc. from each other
- Remove both the rte_flow FDIR TAILQ and the hash map (filter array) structure, because they are redundant (information about the flow is already stored in the rte_flow flow list, and hash_map structure only stored pointers to data we also have in that same list)
- Fix FDIR filter restore to replay all configuration correctly, as well as re-init the FDIR queue enablement tracking
- Rework the internal FDIR global state data structure to make a little more sense by grouping things that belong together into structures
Additionally, there was a delay mechanism at flow director rule program time, as when programming a rule we might not know if it's actually possible to install the rule, because space for the rules may come either from our own pool, or it may come from a pool that is shared with other VSI's. However, it only makes sense to wait on rule create (i.e. when it is programmed into the hardware for the first time), but not when we are replaying or removing these rules. So, adjust the waiting mechanism to only wait on FDIR rule creation.
--- drivers/net/intel/i40e/i40e_ethdev.c | 169 +--- drivers/net/intel/i40e/i40e_ethdev.h | 128 ++- drivers/net/intel/i40e/i40e_fdir.c | 1173 +++++++++++++++++-------- drivers/net/intel/i40e/i40e_flow.c | 136 +-- drivers/net/intel/i40e/rte_pmd_i40e.c | 6 +- 5 files changed, 966 insertions(+), 646 deletions(-)
drivers/net/intel/i40e/i40e_ethdev.c +14 -155
@@ -1041,129 +1041,6 @@ i40e_init_tunnel_filter_list(struct rte_eth_dev *dev)return ret; } -static int -i40e_init_fdir_filter_list (struct rte_eth_dev *dev) -{ -struct i40e_pf *pf =I40E_DEV_PRIVATE_TO_PF (dev->data->dev_private); -struct i40e_hw *hw =I40E_PF_TO_HW (pf); -struct i40e_fdir_info *fdir_info = &pf->fdir; -char fdir_hash_name[RTE_HASH_NAMESIZE ]; -uint32_t alloc = hw->func_caps.fd_filters_guaranteed; -uint32_t best = hw->func_caps.fd_filters_best_effort; -enum i40e_filter_pctype pctype; -struct rte_bitmap *bmp =NULL ; -uint32_t bmp_size; -void *mem =NULL ; -uint32_t i =0 ; -int ret; - -struct rte_hash_parameters fdir_hash_params = { - .name = fdir_hash_name, - .entries =I40E_MAX_FDIR_FILTER_NUM , - .key_len =sizeof (struct i40e_fdir_input ), - .hash_func = rte_hash_crc, - .hash_func_init_val =0 , - .socket_id =rte_socket_id (), - }; - -/* Initialize flow director filter rule list and hash */ -TAILQ_INIT (&fdir_info->fdir_list); -snprintf (fdir_hash_name,RTE_HASH_NAMESIZE , -"fdir_%s" , dev->device->name); - fdir_info->hash_table =rte_hash_create (&fdir_hash_params); -if (!fdir_info->hash_table) { -PMD_INIT_LOG (ERR ,"Failed to create fdir hash table!" ); -return -EINVAL ; - } - - fdir_info->hash_map =rte_zmalloc ("i40e_fdir_hash_map" , -sizeof (struct i40e_fdir_filter *) * -I40E_MAX_FDIR_FILTER_NUM , -0 ); -if (!fdir_info->hash_map) { -PMD_INIT_LOG (ERR , -"Failed to allocate memory for fdir hash map!" ); - ret = -ENOMEM ; - goto err_fdir_hash_map_alloc; - } - - fdir_info->fdir_filter_array =rte_zmalloc ("fdir_filter" , -sizeof (struct i40e_fdir_filter ) * -I40E_MAX_FDIR_FILTER_NUM , -0 ); - -if (!fdir_info->fdir_filter_array) { -PMD_INIT_LOG (ERR , -"Failed to allocate memory for fdir filter array!" ); - ret = -ENOMEM ; - goto err_fdir_filter_array_alloc; - } - -for (pctype =I40E_FILTER_PCTYPE_NONF_IPV4_UDP ; - pctype <=I40E_FILTER_PCTYPE_L2_PAYLOAD ; pctype++) - pf->fdir.flow_count[pctype] =0 ; - - fdir_info->fdir_space_size = alloc + best; - fdir_info->fdir_actual_cnt =0 ; - fdir_info->fdir_guarantee_total_space = alloc; - fdir_info->fdir_guarantee_free_space = - fdir_info->fdir_guarantee_total_space; - -PMD_DRV_LOG (INFO ,"FDIR guarantee space: %u, best_effort space %u." , alloc, best); - - fdir_info->fdir_flow_pool.pool = -rte_zmalloc ("i40e_fdir_entry" , -sizeof (struct i40e_fdir_entry ) * - fdir_info->fdir_space_size, -0 ); - -if (!fdir_info->fdir_flow_pool.pool) { -PMD_INIT_LOG (ERR , -"Failed to allocate memory for bitmap flow!" ); - ret = -ENOMEM ; - goto err_fdir_bitmap_flow_alloc; - } - -for (i =0 ; i < fdir_info->fdir_space_size; i++) - fdir_info->fdir_flow_pool.pool[i].idx = i; - - bmp_size = -rte_bitmap_get_memory_footprint (fdir_info->fdir_space_size); - mem =rte_zmalloc ("fdir_bmap" , bmp_size,RTE_CACHE_LINE_SIZE ); -if (mem ==NULL ) { -PMD_INIT_LOG (ERR , -"Failed to allocate memory for fdir bitmap!" ); - ret = -ENOMEM ; - goto err_fdir_mem_alloc; - } - bmp =rte_bitmap_init (fdir_info->fdir_space_size, mem, bmp_size); -if (bmp ==NULL ) { -PMD_INIT_LOG (ERR , -"Failed to initialization fdir bitmap!" ); - ret = -ENOMEM ; - goto err_fdir_bmp_alloc; - } -for (i =0 ; i < fdir_info->fdir_space_size; i++) -rte_bitmap_set (bmp, i); - - fdir_info->fdir_flow_pool.bitmap = bmp; - -return 0 ; - -err_fdir_bmp_alloc: -rte_free (mem); -err_fdir_mem_alloc: -rte_free (fdir_info->fdir_flow_pool.pool); -err_fdir_bitmap_flow_alloc: -rte_free (fdir_info->fdir_filter_array); -err_fdir_filter_array_alloc: -rte_free (fdir_info->hash_map); -err_fdir_hash_map_alloc: -rte_hash_free (fdir_info->hash_table); - -return ret; -} -static void i40e_init_customized_info (struct i40e_pf *pf) {
@@ -1782,9 +1659,9 @@ eth_i40e_dev_init(struct rte_eth_dev *dev, void *init_params __rte_unused) ret =i40e_init_tunnel_filter_list (dev);if (ret <0 ) goto err_init_tunnel_filter_list; - ret =i40e_init_fdir_filter_list (dev); + ret =i40e_fdir_flow_store_init (dev);if (ret <0 ) - goto err_init_fdir_filter_list; + goto err_init_fdir_flow_store;/* initialize flow engine configuration */ ret = ci_flow_engine_conf_init(&pf->flow_engine_conf,
@@ -1801,12 +1678,8 @@ eth_i40e_dev_init(struct rte_eth_dev *dev, void *init_params __rte_unused)return 0 ; err_flow_engine_conf_init: -rte_free (pf->fdir.fdir_flow_pool.bitmap); -rte_free (pf->fdir.fdir_flow_pool.pool); -rte_free (pf->fdir.fdir_filter_array); -rte_free (pf->fdir.hash_map); -rte_hash_free (pf->fdir.hash_table); -err_init_fdir_filter_list: +i40e_fdir_flow_store_free (&pf->fdir); +err_init_fdir_flow_store:rte_hash_free (pf->tunnel.hash_table);rte_free (pf->tunnel.hash_map); err_init_tunnel_filter_list:
@@ -1849,32 +1722,13 @@ i40e_rm_tunnel_filter_list(struct i40e_pf *pf) } } -static void -i40e_rm_fdir_filter_list (struct i40e_pf *pf) -{ -struct i40e_fdir_filter *p_fdir; -struct i40e_fdir_info *fdir_info; - - fdir_info = &pf->fdir; - -/* Remove all flow director rules */ -while ((p_fdir =TAILQ_FIRST (&fdir_info->fdir_list))) -TAILQ_REMOVE (&fdir_info->fdir_list, p_fdir, rules); -} -static void i40e_fdir_memory_cleanup (struct i40e_pf *pf) { -struct i40e_fdir_info *fdir_info; +struct i40e_fdir_info *fdir_info = &pf->fdir; - fdir_info = &pf->fdir; - -/* flow director memory cleanup */ -rte_free (fdir_info->hash_map); -rte_hash_free (fdir_info->hash_table); -rte_free (fdir_info->fdir_flow_pool.bitmap); -rte_free (fdir_info->fdir_flow_pool.pool); -rte_free (fdir_info->fdir_filter_array); +i40e_fdir_flow_store_free (fdir_info); +i40e_fdir_tmpl_store_free (fdir_info); }void i40e_flex_payload_reg_set_default (struct i40e_hw *hw)
@@ -2659,6 +2513,7 @@ i40e_dev_close(struct rte_eth_dev *dev)/* free the flows and reset flow config */ ci_flow_cleanup (&pf->flow_engine_conf);ci_flow_engine_conf_reset (&pf->flow_engine_conf); +i40e_fdir_teardown (pf);i40e_dev_free_queues (dev);
@@ -2730,7 +2585,6 @@ i40e_dev_close(struct rte_eth_dev *dev) }while (retries++ <5 );i40e_rm_tunnel_filter_list (pf); -i40e_rm_fdir_filter_list (pf);/* Remove all flows */ while ((p_flow =TAILQ_FIRST (&pf->flow_list))) {
@@ -9758,7 +9612,12 @@ i40e_filter_input_set_init(struct i40e_pf *pf)/* store the default input set */ if (!pf->support_multi_driver) pf->hash_input_set[pctype] = input_set; - pf->fdir.input_set[pctype] = input_set; + { +struct i40e_fdir_pctype_state *state = + &pf->fdir.flows.pctype[pctype]; + + state->input_set = input_set; + } } }
drivers/net/intel/i40e/i40e_ethdev.h +89 -39
186 lines not on this page · raw message
drivers/net/intel/i40e/i40e_fdir.c +811 -362
1,513 lines not on this page · raw message
drivers/net/intel/i40e/i40e_flow.c +48 -88
210 lines not on this page · raw message
drivers/net/intel/i40e/rte_pmd_i40e.c +4 -2
@@ -3044,7 +3044,7 @@ int rte_pmd_i40e_flow_add_del_packet_template( uint8_t add) {struct rte_eth_dev *dev = &rte_eth_devices[port]; -struct i40e_fdir_filter_conf filter_conf; +struct i40e_fdir_filter filter_conf;RTE_ETH_VALID_PORTID_OR_ERR_RET (port, -ENODEV );
@@ -3068,7 +3068,9 @@ int rte_pmd_i40e_flow_add_del_packet_template( (enum i40e_fdir_status )conf->action.report_status; filter_conf.action.flex_off = conf->action.flex_off; -return i40e_flow_add_del_fdir_filter (dev, &filter_conf, add); +if (add) +return i40e_fdir_tmpl_add (dev, &filter_conf); +return i40e_fdir_tmpl_del (dev, &filter_conf); }RTE_EXPORT_SYMBOL (rte_pmd_i40e_inset_get)
Signature · 1 line
2.52.0
PATCH v4 21/24 net/i40e: reimplement FDIR parser
In reply to Anatoly BurakovUse the new flow graph API and the common parsing framework to implement flow parser for flow director.
As a result of transitioning to more formalized validation, some checks have become more stringent. In particular, some protocols (such as SCTP) were previously accepting non-zero or invalid masks and either ignoring them or misinterpreting them to mean "fully masked". This has now been corrected.
The FDIR engine in i40e has also relied on a custom memory allocation scheme for fdir flows - also migrated to the new infrastructure.
Finally, some of the FDIR infrastructure has been migrated into the new flow engine, so that the engine itself is managing its own allocator and its own flow deduplication scheme, and the FDIR storage and programming has been refactored to manage flow programming with better separation between various parts of the flow programming process.
--- drivers/net/intel/i40e/i40e_ethdev.c | 26 +- drivers/net/intel/i40e/i40e_ethdev.h | 125 +- drivers/net/intel/i40e/i40e_fdir.c | 691 ++------ drivers/net/intel/i40e/i40e_flow.c | 1921 +------------------- drivers/net/intel/i40e/i40e_flow.h | 5 + drivers/net/intel/i40e/i40e_flow_fdir.c | 2154 +++++++++++++++++++++++ drivers/net/intel/i40e/meson.build | 1 + drivers/net/intel/i40e/rte_pmd_i40e.c | 6 + 8 files changed, 2409 insertions(+), 2520 deletions(-) create mode 100644 drivers/net/intel/i40e/i40e_flow_fdir.c
drivers/net/intel/i40e/i40e_ethdev.c +4 -22
@@ -1659,9 +1659,7 @@ eth_i40e_dev_init(struct rte_eth_dev *dev, void *init_params __rte_unused) ret =i40e_init_tunnel_filter_list (dev);if (ret <0 ) goto err_init_tunnel_filter_list; - ret =i40e_fdir_flow_store_init (dev); -if (ret <0 ) - goto err_init_fdir_flow_store; +i40e_fdir_flow_store_init (dev);/* initialize flow engine configuration */ ret = ci_flow_engine_conf_init(&pf->flow_engine_conf,
@@ -1678,8 +1676,6 @@ eth_i40e_dev_init(struct rte_eth_dev *dev, void *init_params __rte_unused)return 0 ; err_flow_engine_conf_init: -i40e_fdir_flow_store_free (&pf->fdir); -err_init_fdir_flow_store:rte_hash_free (pf->tunnel.hash_table);rte_free (pf->tunnel.hash_map); err_init_tunnel_filter_list:
@@ -1722,15 +1718,6 @@ i40e_rm_tunnel_filter_list(struct i40e_pf *pf) } } -static void -i40e_fdir_memory_cleanup (struct i40e_pf *pf) -{ -struct i40e_fdir_info *fdir_info = &pf->fdir; - -i40e_fdir_flow_store_free (fdir_info); -i40e_fdir_tmpl_store_free (fdir_info); -} -void i40e_flex_payload_reg_set_default (struct i40e_hw *hw) {/*
@@ -2513,7 +2500,7 @@ i40e_dev_close(struct rte_eth_dev *dev)/* free the flows and reset flow config */ ci_flow_cleanup (&pf->flow_engine_conf);ci_flow_engine_conf_reset (&pf->flow_engine_conf); -i40e_fdir_teardown (pf); +i40e_fdir_cleanup (dev);i40e_dev_free_queues (dev);
@@ -2589,14 +2576,9 @@ i40e_dev_close(struct rte_eth_dev *dev)/* Remove all flows */ while ((p_flow =TAILQ_FIRST (&pf->flow_list))) {TAILQ_REMOVE (&pf->flow_list, p_flow, node); -/* Do not free FDIR flows since they are static allocated */ -if (p_flow->filter_type !=RTE_ETH_FILTER_FDIR ) -rte_free (p_flow); +rte_free (p_flow); } -/* release the fdir static allocated memory */ -i40e_fdir_memory_cleanup (pf); -/* Remove all Traffic Manager configuration */ i40e_tm_conf_uninit (dev);
@@ -9614,7 +9596,7 @@ i40e_filter_input_set_init(struct i40e_pf *pf) pf->hash_input_set[pctype] = input_set; {struct i40e_fdir_pctype_state *state = - &pf->fdir.flows.pctype[pctype]; + &pf->fdir.fdir_state.pctype[pctype]; state->input_set = input_set; }
drivers/net/intel/i40e/i40e_ethdev.h +63 -62
205 lines not on this page · raw message
drivers/net/intel/i40e/i40e_fdir.c +166 -525
1,008 lines not on this page · raw message
drivers/net/intel/i40e/i40e_flow.c +10 -1911
1,723 lines not on this page · raw message
drivers/net/intel/i40e/i40e_flow_fdir.c new file +2154 -0
2,154 lines not on this page · raw message
The rest of this diff is not shown. View the raw message.
Signature · 1 line
2.52.0
Part of the diff is not shown here. View the raw message.
PATCH v4 22/24 net/i40e: reimplement tunnel parsers
In reply to Anatoly BurakovUse the new flow graph API and the common parsing framework to implement flow parser for tunnel filters: QinQ, VXLAN, NVGRE, MPLS, GTP, and L4.
As a result of transitioning to more formalized validation, some checks have become more stringent:
- VLAN TCI mask is now required to be fully masked (all-ones); previously the mask was only checked for eth_proto and any non-zero vlan_tci mask value was silently accepted
- For QinQ, VLAN TCI mask is now required whereas previously it was ignored
- Old code did not check for whether fields other than ports are masked (they are now rejected)
- Old code did not check for whether src/ports are fully masked (masks other than full are now rejected)
- Old code used spec to decide which port to copy (as a result, it was not possible to match port 0 - this is now allowed)
Tunnel engine now also share a refcounted global state, and track all flows and do deduplication inside the engine.
--- drivers/net/intel/i40e/i40e_ethdev.c | 1056 ++--------- drivers/net/intel/i40e/i40e_ethdev.h | 84 +- drivers/net/intel/i40e/i40e_flow.c | 1702 +----------------- drivers/net/intel/i40e/i40e_flow.h | 6 + drivers/net/intel/i40e/i40e_flow_tunnel.c | 1958 +++++++++++++++++++++ drivers/net/intel/i40e/meson.build | 1 + 6 files changed, 2178 insertions(+), 2629 deletions(-) create mode 100644 drivers/net/intel/i40e/i40e_flow_tunnel.c
drivers/net/intel/i40e/i40e_ethdev.c +163 -893
@@ -392,14 +392,6 @@ static int i40e_set_default_mac_addr(struct rte_eth_dev *dev,static int i40e_dev_mtu_set (struct rte_eth_dev *dev,uint16_t mtu); -static int i40e_tunnel_filter_convert ( -struct i40e_aqc_cloud_filters_element_bb *cld_filter, -struct i40e_tunnel_filter *tunnel_filter); -static int i40e_sw_tunnel_filter_insert (struct i40e_pf *pf, -struct i40e_tunnel_filter *tunnel_filter); -static int i40e_cloud_filter_qinq_create (struct i40e_pf *pf); - -static void i40e_tunnel_filter_restore (struct i40e_pf *pf);static void i40e_filter_restore (struct i40e_pf *pf);static void i40e_notify_all_vfs_link_status (struct rte_eth_dev *dev); static int i40e_fec_get_capability(struct rte_eth_dev *dev,
@@ -996,49 +988,43 @@ config_floating_veb(struct rte_eth_dev *dev)#define I40E_L2_TAGS_S_TAG_SHIFT 1#define I40E_L2_TAGS_S_TAG_MASK I40E_MASK(0x1, I40E_L2_TAGS_S_TAG_SHIFT) -static int -i40e_init_tunnel_filter_list (struct rte_eth_dev *dev) +struct i40e_tunnel_state * +i40e_tunnel_state_attach (struct rte_eth_dev_data *dev_data) { -struct i40e_pf *pf =I40E_DEV_PRIVATE_TO_PF (dev->data->dev_private); -struct i40e_tunnel_rule *tunnel_rule = &pf->tunnel; -char tunnel_hash_name[RTE_HASH_NAMESIZE ]; -int ret; - -struct rte_hash_parameters tunnel_hash_params = { +struct i40e_pf *pf =I40E_DEV_PRIVATE_TO_PF (dev_data->dev_private); +struct i40e_tunnel_state *state = &pf->tunnel_state; +char tunnel_hash_name[RTE_HASH_NAMESIZE ] = {0 }; +struct rte_hash_parameters hash_params = { .name = tunnel_hash_name, .entries =I40E_MAX_TUNNEL_FILTER_NUM , - .key_len =sizeof (struct i40e_tunnel_filter_input ), + .key_len =sizeof (struct i40e_tunnel_filter_match_key ), .hash_func = rte_hash_crc, .hash_func_init_val =0 , .socket_id =rte_socket_id (), }; -/* Initialize tunnel filter rule list and hash */ -TAILQ_INIT (&tunnel_rule->tunnel_list); -snprintf (tunnel_hash_name,RTE_HASH_NAMESIZE , -"tunnel_%s" , dev->device->name); - tunnel_rule->hash_table =rte_hash_create (&tunnel_hash_params); -if (!tunnel_rule->hash_table) { -PMD_INIT_LOG (ERR ,"Failed to create tunnel hash table!" ); -return -EINVAL ; - } - tunnel_rule->hash_map =rte_zmalloc ("i40e_tunnel_hash_map" , -sizeof (struct i40e_tunnel_filter *) * -I40E_MAX_TUNNEL_FILTER_NUM , -0 ); -if (!tunnel_rule->hash_map) { -PMD_INIT_LOG (ERR , -"Failed to allocate memory for tunnel hash map!" ); - ret = -ENOMEM ; - goto err_tunnel_hash_map_alloc; +snprintf (tunnel_hash_name,RTE_HASH_NAMESIZE ,"i40e_tunnel_hash_%s" , dev_data->name); + +if (ci_usage_count_claim (&state->use_count)) { + state->hash_table =rte_hash_create (&hash_params); +if (state->hash_table ==NULL ) { +PMD_DRV_LOG (ERR ,"Failed to create tunnel hash table" ); +ci_usage_count_release (&state->use_count); +return NULL ; + } } -return 0 ; +return state; +} -err_tunnel_hash_map_alloc: -rte_hash_free (tunnel_rule->hash_table); +void +i40e_tunnel_state_detach (struct i40e_tunnel_state *state) +{ +if (!ci_usage_count_release (&state->use_count)) +return ; -return ret; +rte_hash_free (state->hash_table); + state->hash_table =NULL ; } static void
@@ -1656,10 +1642,9 @@ eth_i40e_dev_init(struct rte_eth_dev *dev, void *init_params __rte_unused)/* Initialize the filter invalidation configuration */ i40e_init_filter_invalidation (pf); - ret =i40e_init_tunnel_filter_list (dev); -if (ret <0 ) - goto err_init_tunnel_filter_list;i40e_fdir_flow_store_init (dev); +/* after device init, tunnel configuration is in its default state */ + pf->tunnel_state = (struct i40e_tunnel_state ){0 };/* initialize flow engine configuration */ ret = ci_flow_engine_conf_init(&pf->flow_engine_conf,
@@ -1676,9 +1661,6 @@ eth_i40e_dev_init(struct rte_eth_dev *dev, void *init_params __rte_unused)return 0 ; err_flow_engine_conf_init: -rte_hash_free (pf->tunnel.hash_table); -rte_free (pf->tunnel.hash_map); -err_init_tunnel_filter_list:rte_intr_callback_unregister (intr_handle, i40e_dev_interrupt_handler, dev);rte_free (dev->data->mac_addrs);
@@ -1701,23 +1683,6 @@ eth_i40e_dev_init(struct rte_eth_dev *dev, void *init_params __rte_unused)return ret; } -static void -i40e_rm_tunnel_filter_list (struct i40e_pf *pf) -{ -struct i40e_tunnel_filter *p_tunnel; -struct i40e_tunnel_rule *tunnel_rule; - - tunnel_rule = &pf->tunnel; -/* Remove all tunnel director rules and hash */ -rte_free (tunnel_rule->hash_map); -rte_hash_free (tunnel_rule->hash_table); - -while ((p_tunnel =TAILQ_FIRST (&tunnel_rule->tunnel_list))) { -TAILQ_REMOVE (&tunnel_rule->tunnel_list, p_tunnel, rules); -rte_free (p_tunnel); - } -} -void i40e_flex_payload_reg_set_default (struct i40e_hw *hw) {/*
@@ -2571,8 +2536,6 @@ i40e_dev_close(struct rte_eth_dev *dev)i40e_msec_delay (500 ); }while (retries++ <5 ); -i40e_rm_tunnel_filter_list (pf); -/* Remove all flows */ while ((p_flow =TAILQ_FIRST (&pf->flow_list))) {TAILQ_REMOVE (&pf->flow_list, p_flow, node);
@@ -7719,569 +7682,76 @@ i40e_dev_get_filter_type(uint16_t filter_type, uint16_t *flag)return 0 ; } -/* Convert tunnel filter structure */ -static int -i40e_tunnel_filter_convert ( -struct i40e_aqc_cloud_filters_element_bb *cld_filter, -struct i40e_tunnel_filter *tunnel_filter) -{ -rte_ether_addr_copy ((struct rte_ether_addr *) - &cld_filter->element.outer_mac, - (struct rte_ether_addr *)&tunnel_filter->input.outer_mac); -rte_ether_addr_copy ((struct rte_ether_addr *) - &cld_filter->element.inner_mac, - (struct rte_ether_addr *)&tunnel_filter->input.inner_mac); - tunnel_filter->input.inner_vlan = cld_filter->element.inner_vlan; -if ((rte_le_to_cpu_16 (cld_filter->element.flags) & -I40E_AQC_ADD_CLOUD_FLAGS_IPV6 ) == -I40E_AQC_ADD_CLOUD_FLAGS_IPV6 ) - tunnel_filter->input.ip_type =I40E_TUNNEL_IPTYPE_IPV6 ; -else - tunnel_filter->input.ip_type =I40E_TUNNEL_IPTYPE_IPV4 ; - tunnel_filter->input.flags = cld_filter->element.flags; - tunnel_filter->input.tenant_id = cld_filter->element.tenant_id; - tunnel_filter->queue = cld_filter->element.queue_number; -memcpy (tunnel_filter->input.general_fields, - cld_filter->general_fields, -sizeof (cld_filter->general_fields)); - -return 0 ; -} - -/* Check if there exists the tunnel filter */ -struct i40e_tunnel_filter * -i40e_sw_tunnel_filter_lookup (struct i40e_tunnel_rule *tunnel_rule, -const struct i40e_tunnel_filter_input *input) -{ -int ret; - - ret =rte_hash_lookup (tunnel_rule->hash_table, (const void *)input); -if (ret <0 ) -return NULL ; - -return tunnel_rule->hash_map[ret]; -} - -/* Add a tunnel filter into the SW list */ -static int -i40e_sw_tunnel_filter_insert (struct i40e_pf *pf, -struct i40e_tunnel_filter *tunnel_filter) -{ -struct i40e_tunnel_rule *rule = &pf->tunnel; -int ret; - - ret =rte_hash_add_key (rule->hash_table, &tunnel_filter->input); -if (ret <0 ) { -PMD_DRV_LOG (ERR , -"Failed to insert tunnel filter to hash table %d!" , - ret); -return ret; - } - rule->hash_map[ret] = tunnel_filter; - -TAILQ_INSERT_TAIL (&rule->tunnel_list, tunnel_filter, rules); - -return 0 ; -} - -/* Delete a tunnel filter from the SW list */ int -i40e_sw_tunnel_filter_del (struct i40e_pf *pf, -struct i40e_tunnel_filter_input *input) +i40e_tunnel_filter_replace (struct i40e_pf *pf, +const struct i40e_tunnel_filter_replacement *replacement) { -struct i40e_tunnel_rule *rule = &pf->tunnel; -struct i40e_tunnel_filter *tunnel_filter; +struct i40e_aqc_replace_cloud_filters_cmd_buf buffer = {0 }; +struct i40e_aqc_replace_cloud_filters_cmd command = { + .valid_flags = replacement->valid_flags, + .old_filter_type = replacement->old_filter_type, + .new_filter_type = replacement->new_filter_type, + .tr_bit = replacement->tr_bit, + .tr_bit2 = replacement->tr_bit2, + }; +struct i40e_hw *hw =I40E_PF_TO_HW (pf); +struct rte_eth_dev *dev = &rte_eth_devices[pf->dev_data->port_id];int ret; - ret =rte_hash_del_key (rule->hash_table, input); -if (ret <0 ) { -PMD_DRV_LOG (ERR , -"Failed to delete tunnel filter to hash table %d!" , - ret); -return ret; +if (pf->support_multi_driver) { +PMD_DRV_LOG (ERR ,"Replacing tunnel filters is not supported." ); +return I40E_NOT_SUPPORTED ; } - tunnel_filter = rule->hash_map[ret]; - rule->hash_map[ret] =NULL ; -TAILQ_REMOVE (&rule->tunnel_list, tunnel_filter, rules); -rte_free (tunnel_filter); +memcpy (buffer.data, replacement->data,sizeof (replacement->data)); + ret =i40e_aq_replace_cloud_filters (hw, &command, &buffer); +if (ret !=I40E_SUCCESS ) +return ret; + +PMD_DRV_LOG (WARNING ,"i40e device %s changed %s filter type." +" original: 0x%x, new: 0x%x" , + dev->device->name, + (command.valid_flags &I40E_AQC_REPLACE_CLOUD_FILTER ) !=0 ? +"cloud" :"cloud l1" , + command.old_filter_type, command.new_filter_type);return 0 ; } -#define I40E_AQC_REPLACE_CLOUD_CMD_INPUT_TR_WORD0 0x48 -#define I40E_TR_VXLAN_GRE_KEY_MASK 0x4 -#define I40E_TR_GENEVE_KEY_MASK 0x8 -#define I40E_TR_GENERIC_UDP_TUNNEL_MASK 0x40 -#define I40E_TR_GRE_KEY_MASK 0x400 -#define I40E_TR_GRE_KEY_WITH_XSUM_MASK 0x800 -#define I40E_TR_GRE_NO_KEY_MASK 0x8000 -#define I40E_AQC_REPLACE_CLOUD_CMD_INPUT_PORT_TR_WORD0 0x49 -#define I40E_AQC_REPLACE_CLOUD_CMD_INPUT_DIRECTION_WORD0 0x41 -#define I40E_AQC_REPLACE_CLOUD_CMD_INPUT_INGRESS_WORD0 0x80#define I40E_DIRECTION_INGRESS_KEY 0x8000#define I40E_TR_L4_TYPE_TCP 0x2#define I40E_TR_L4_TYPE_UDP 0x4#define I40E_TR_L4_TYPE_SCTP 0x8 -static enum -i40e_status_code i40e_replace_mpls_l1_filter (struct i40e_pf *pf) -{ -struct i40e_aqc_replace_cloud_filters_cmd filter_replace; -struct i40e_aqc_replace_cloud_filters_cmd_buf filter_replace_buf; -struct i40e_hw *hw =I40E_PF_TO_HW (pf); -struct rte_eth_dev *dev = &rte_eth_devices[pf->dev_data->port_id]; -enum i40e_status_code status =I40E_SUCCESS ; - -if (pf->support_multi_driver) { -PMD_DRV_LOG (ERR ,"Replace l1 filter is not supported." ); -return I40E_NOT_SUPPORTED ; - } - -memset (&filter_replace,0 , -sizeof (struct i40e_aqc_replace_cloud_filters_cmd )); -memset (&filter_replace_buf,0 , -sizeof (struct i40e_aqc_replace_cloud_filters_cmd_buf )); - -/* create L1 filter */ - filter_replace.old_filter_type = -I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_IMAC ; - filter_replace.new_filter_type =I40E_AQC_ADD_L1_FILTER_0X11 ; - filter_replace.tr_bit =0 ; - -/* Prepare the buffer, 3 entries */ - filter_replace_buf.data[0 ] = -I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_TEID_WORD0 ; - filter_replace_buf.data[0 ] |= -I40E_AQC_REPLACE_CLOUD_CMD_INPUT_VALIDATED ; - filter_replace_buf.data[2 ] =0xFF ; - filter_replace_buf.data[3 ] =0xFF ; - filter_replace_buf.data[4 ] = -I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_TEID_WORD1 ; - filter_replace_buf.data[4 ] |= -I40E_AQC_REPLACE_CLOUD_CMD_INPUT_VALIDATED ; - filter_replace_buf.data[7 ] =0xF0 ; - filter_replace_buf.data[8 ] - =I40E_AQC_REPLACE_CLOUD_CMD_INPUT_TR_WORD0 ; - filter_replace_buf.data[8 ] |= -I40E_AQC_REPLACE_CLOUD_CMD_INPUT_VALIDATED ; - filter_replace_buf.data[10 ] =I40E_TR_VXLAN_GRE_KEY_MASK | -I40E_TR_GENEVE_KEY_MASK | -I40E_TR_GENERIC_UDP_TUNNEL_MASK ; - filter_replace_buf.data[11 ] = (I40E_TR_GRE_KEY_MASK | -I40E_TR_GRE_KEY_WITH_XSUM_MASK | -I40E_TR_GRE_NO_KEY_MASK ) >>8 ; - - status =i40e_aq_replace_cloud_filters (hw, &filter_replace, - &filter_replace_buf); -if (!status && (filter_replace.old_filter_type != - filter_replace.new_filter_type)) -PMD_DRV_LOG (WARNING ,"i40e device %s changed cloud l1 type." -" original: 0x%x, new: 0x%x" , - dev->device->name, - filter_replace.old_filter_type, - filter_replace.new_filter_type); - -return status; -} - -static enum -i40e_status_code i40e_replace_mpls_cloud_filter (struct i40e_pf *pf) -{ -struct i40e_aqc_replace_cloud_filters_cmd filter_replace; -struct i40e_aqc_replace_cloud_filters_cmd_buf filter_replace_buf; -struct i40e_hw *hw =I40E_PF_TO_HW (pf); -struct rte_eth_dev *dev = &rte_eth_devices[pf->dev_data->port_id]; -enum i40e_status_code status =I40E_SUCCESS ; - -if (pf->support_multi_driver) { -PMD_DRV_LOG (ERR ,"Replace cloud filter is not supported." ); -return I40E_NOT_SUPPORTED ; - } - -/* For MPLSoUDP */ -memset (&filter_replace,0 , -sizeof (struct i40e_aqc_replace_cloud_filters_cmd )); -memset (&filter_replace_buf,0 , -sizeof (struct i40e_aqc_replace_cloud_filters_cmd_buf )); - filter_replace.valid_flags =I40E_AQC_REPLACE_CLOUD_FILTER | -I40E_AQC_MIRROR_CLOUD_FILTER ; - filter_replace.old_filter_type =I40E_AQC_ADD_CLOUD_FILTER_IIP ; - filter_replace.new_filter_type = -I40E_AQC_ADD_CLOUD_FILTER_0X11 ; -/* Prepare the buffer, 2 entries */ - filter_replace_buf.data[0 ] =I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_STAG ; - filter_replace_buf.data[0 ] |= -I40E_AQC_REPLACE_CLOUD_CMD_INPUT_VALIDATED ; - filter_replace_buf.data[4 ] =I40E_AQC_ADD_L1_FILTER_0X11 ; - filter_replace_buf.data[4 ] |= -I40E_AQC_REPLACE_CLOUD_CMD_INPUT_VALIDATED ; - status =i40e_aq_replace_cloud_filters (hw, &filter_replace, - &filter_replace_buf); -if (status <0 ) -return status; -if (filter_replace.old_filter_type != - filter_replace.new_filter_type) -PMD_DRV_LOG (WARNING ,"i40e device %s changed cloud filter type." -" original: 0x%x, new: 0x%x" , - dev->device->name, - filter_replace.old_filter_type, - filter_replace.new_filter_type); - -/* For MPLSoGRE */ -memset (&filter_replace,0 , -sizeof (struct i40e_aqc_replace_cloud_filters_cmd )); -memset (&filter_replace_buf,0 , -sizeof (struct i40e_aqc_replace_cloud_filters_cmd_buf )); - - filter_replace.valid_flags =I40E_AQC_REPLACE_CLOUD_FILTER | -I40E_AQC_MIRROR_CLOUD_FILTER ; - filter_replace.old_filter_type =I40E_AQC_ADD_CLOUD_FILTER_IMAC ; - filter_replace.new_filter_type = -I40E_AQC_ADD_CLOUD_FILTER_0X12 ; -/* Prepare the buffer, 2 entries */ - filter_replace_buf.data[0 ] =I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_STAG ; - filter_replace_buf.data[0 ] |= -I40E_AQC_REPLACE_CLOUD_CMD_INPUT_VALIDATED ; - filter_replace_buf.data[4 ] =I40E_AQC_ADD_L1_FILTER_0X11 ; - filter_replace_buf.data[4 ] |= -I40E_AQC_REPLACE_CLOUD_CMD_INPUT_VALIDATED ; - - status =i40e_aq_replace_cloud_filters (hw, &filter_replace, - &filter_replace_buf); -if (!status && (filter_replace.old_filter_type != - filter_replace.new_filter_type)) -PMD_DRV_LOG (WARNING ,"i40e device %s changed cloud filter type." -" original: 0x%x, new: 0x%x" , - dev->device->name, - filter_replace.old_filter_type, - filter_replace.new_filter_type); - -return status; -} - -static enum i40e_status_code -i40e_replace_gtp_l1_filter (struct i40e_pf *pf) -{ -struct i40e_aqc_replace_cloud_filters_cmd filter_replace; -struct i40e_aqc_replace_cloud_filters_cmd_buf filter_replace_buf; -struct i40e_hw *hw =I40E_PF_TO_HW (pf); -struct rte_eth_dev *dev = &rte_eth_devices[pf->dev_data->port_id]; -enum i40e_status_code status =I40E_SUCCESS ; - -if (pf->support_multi_driver) { -PMD_DRV_LOG (ERR ,"Replace l1 filter is not supported." ); -return I40E_NOT_SUPPORTED ; - } - -/* For GTP-C */ -memset (&filter_replace,0 , -sizeof (struct i40e_aqc_replace_cloud_filters_cmd )); -memset (&filter_replace_buf,0 , -sizeof (struct i40e_aqc_replace_cloud_filters_cmd_buf )); -/* create L1 filter */ - filter_replace.old_filter_type = -I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_IMAC ; - filter_replace.new_filter_type =I40E_AQC_ADD_L1_FILTER_0X12 ; - filter_replace.tr_bit =I40E_AQC_NEW_TR_22 | -I40E_AQC_REPLACE_CLOUD_CMD_INPUT_VALIDATED ; -/* Prepare the buffer, 2 entries */ - filter_replace_buf.data[0 ] = -I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_TEID_WORD0 ; - filter_replace_buf.data[0 ] |= -I40E_AQC_REPLACE_CLOUD_CMD_INPUT_VALIDATED ; - filter_replace_buf.data[2 ] =0xFF ; - filter_replace_buf.data[3 ] =0xFF ; - filter_replace_buf.data[4 ] = -I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_TEID_WORD1 ; - filter_replace_buf.data[4 ] |= -I40E_AQC_REPLACE_CLOUD_CMD_INPUT_VALIDATED ; - filter_replace_buf.data[6 ] =0xFF ; - filter_replace_buf.data[7 ] =0xFF ; - status =i40e_aq_replace_cloud_filters (hw, &filter_replace, - &filter_replace_buf); -if (status <0 ) -return status; -if (filter_replace.old_filter_type != - filter_replace.new_filter_type) -PMD_DRV_LOG (WARNING ,"i40e device %s changed cloud l1 type." -" original: 0x%x, new: 0x%x" , - dev->device->name, - filter_replace.old_filter_type, - filter_replace.new_filter_type); - -/* for GTP-U */ -memset (&filter_replace,0 , -sizeof (struct i40e_aqc_replace_cloud_filters_cmd )); -memset (&filter_replace_buf,0 , -sizeof (struct i40e_aqc_replace_cloud_filters_cmd_buf )); -/* create L1 filter */ - filter_replace.old_filter_type = -I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_TUNNLE_KEY ; - filter_replace.new_filter_type =I40E_AQC_ADD_L1_FILTER_0X13 ; - filter_replace.tr_bit =I40E_AQC_NEW_TR_21 | -I40E_AQC_REPLACE_CLOUD_CMD_INPUT_VALIDATED ; -/* Prepare the buffer, 2 entries */ - filter_replace_buf.data[0 ] = -I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_TEID_WORD0 ; - filter_replace_buf.data[0 ] |= -I40E_AQC_REPLACE_CLOUD_CMD_INPUT_VALIDATED ; - filter_replace_buf.data[2 ] =0xFF ; - filter_replace_buf.data[3 ] =0xFF ; - filter_replace_buf.data[4 ] = -I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_TEID_WORD1 ; - filter_replace_buf.data[4 ] |= -I40E_AQC_REPLACE_CLOUD_CMD_INPUT_VALIDATED ; - filter_replace_buf.data[6 ] =0xFF ; - filter_replace_buf.data[7 ] =0xFF ; - - status =i40e_aq_replace_cloud_filters (hw, &filter_replace, - &filter_replace_buf); -if (!status && (filter_replace.old_filter_type != - filter_replace.new_filter_type)) -PMD_DRV_LOG (WARNING ,"i40e device %s changed cloud l1 type." -" original: 0x%x, new: 0x%x" , - dev->device->name, - filter_replace.old_filter_type, - filter_replace.new_filter_type); - -return status; -} - -static enum -i40e_status_code i40e_replace_gtp_cloud_filter (struct i40e_pf *pf) -{ -struct i40e_aqc_replace_cloud_filters_cmd filter_replace; -struct i40e_aqc_replace_cloud_filters_cmd_buf filter_replace_buf; -struct i40e_hw *hw =I40E_PF_TO_HW (pf); -struct rte_eth_dev *dev = &rte_eth_devices[pf->dev_data->port_id]; -enum i40e_status_code status =I40E_SUCCESS ; - -if (pf->support_multi_driver) { -PMD_DRV_LOG (ERR ,"Replace cloud filter is not supported." ); -return I40E_NOT_SUPPORTED ; - } - -/* for GTP-C */ -memset (&filter_replace,0 , -sizeof (struct i40e_aqc_replace_cloud_filters_cmd )); -memset (&filter_replace_buf,0 , -sizeof (struct i40e_aqc_replace_cloud_filters_cmd_buf )); - filter_replace.valid_flags =I40E_AQC_REPLACE_CLOUD_FILTER ; - filter_replace.old_filter_type =I40E_AQC_ADD_CLOUD_FILTER_IMAC_IVLAN ; - filter_replace.new_filter_type = -I40E_AQC_ADD_CLOUD_FILTER_0X11 ; -/* Prepare the buffer, 2 entries */ - filter_replace_buf.data[0 ] =I40E_AQC_ADD_L1_FILTER_0X12 ; - filter_replace_buf.data[0 ] |= -I40E_AQC_REPLACE_CLOUD_CMD_INPUT_VALIDATED ; - filter_replace_buf.data[4 ] =I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_STAG ; - filter_replace_buf.data[4 ] |= -I40E_AQC_REPLACE_CLOUD_CMD_INPUT_VALIDATED ; - status =i40e_aq_replace_cloud_filters (hw, &filter_replace, - &filter_replace_buf); -if (status <0 ) -return status; -if (filter_replace.old_filter_type != - filter_replace.new_filter_type) -PMD_DRV_LOG (WARNING ,"i40e device %s changed cloud filter type." -" original: 0x%x, new: 0x%x" , - dev->device->name, - filter_replace.old_filter_type, - filter_replace.new_filter_type); - -/* for GTP-U */ -memset (&filter_replace,0 , -sizeof (struct i40e_aqc_replace_cloud_filters_cmd )); -memset (&filter_replace_buf,0 , -sizeof (struct i40e_aqc_replace_cloud_filters_cmd_buf )); - filter_replace.valid_flags =I40E_AQC_REPLACE_CLOUD_FILTER ; - filter_replace.old_filter_type = -I40E_AQC_ADD_CLOUD_FILTER_IMAC_IVLAN_TEN_ID ; - filter_replace.new_filter_type = -I40E_AQC_ADD_CLOUD_FILTER_0X12 ; -/* Prepare the buffer, 2 entries */ - filter_replace_buf.data[0 ] =I40E_AQC_ADD_L1_FILTER_0X13 ; - filter_replace_buf.data[0 ] |= -I40E_AQC_REPLACE_CLOUD_CMD_INPUT_VALIDATED ; - filter_replace_buf.data[4 ] =I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_STAG ; - filter_replace_buf.data[4 ] |= -I40E_AQC_REPLACE_CLOUD_CMD_INPUT_VALIDATED ; - - status =i40e_aq_replace_cloud_filters (hw, &filter_replace, - &filter_replace_buf); -if (!status && (filter_replace.old_filter_type != - filter_replace.new_filter_type)) -PMD_DRV_LOG (WARNING ,"i40e device %s changed cloud filter type." -" original: 0x%x, new: 0x%x" , - dev->device->name, - filter_replace.old_filter_type, - filter_replace.new_filter_type); - -return status; -} - -static enum i40e_status_code -i40e_replace_port_l1_filter (struct i40e_pf *pf, -enum i40e_l4_port_type l4_port_type) -{ -struct i40e_aqc_replace_cloud_filters_cmd_buf filter_replace_buf; -struct i40e_aqc_replace_cloud_filters_cmd filter_replace; -enum i40e_status_code status =I40E_SUCCESS ; -struct i40e_hw *hw =I40E_PF_TO_HW (pf); -struct rte_eth_dev *dev = &rte_eth_devices[pf->dev_data->port_id]; - -if (pf->support_multi_driver) { -PMD_DRV_LOG (ERR ,"Replace l1 filter is not supported." ); -return I40E_NOT_SUPPORTED ; - } - -memset (&filter_replace,0 , -sizeof (struct i40e_aqc_replace_cloud_filters_cmd )); -memset (&filter_replace_buf,0 , -sizeof (struct i40e_aqc_replace_cloud_filters_cmd_buf )); - -/* create L1 filter */ -if (l4_port_type ==I40E_L4_PORT_TYPE_SRC ) { - filter_replace.old_filter_type = -I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_TUNNLE_KEY ; - filter_replace.new_filter_type =I40E_AQC_ADD_L1_FILTER_0X11 ; - filter_replace_buf.data[8 ] = -I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_SRC_PORT ; - }else { - filter_replace.old_filter_type = -I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_STAG_IVLAN ; - filter_replace.new_filter_type =I40E_AQC_ADD_L1_FILTER_0X10 ; - filter_replace_buf.data[8 ] = -I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_DST_PORT ; - } - - filter_replace.tr_bit =0 ; -/* Prepare the buffer, 3 entries */ - filter_replace_buf.data[0 ] = -I40E_AQC_REPLACE_CLOUD_CMD_INPUT_DIRECTION_WORD0 ; - filter_replace_buf.data[0 ] |= -I40E_AQC_REPLACE_CLOUD_CMD_INPUT_VALIDATED ; - filter_replace_buf.data[2 ] =0x00 ; - filter_replace_buf.data[3 ] = -I40E_AQC_REPLACE_CLOUD_CMD_INPUT_INGRESS_WORD0 ; - filter_replace_buf.data[4 ] = -I40E_AQC_REPLACE_CLOUD_CMD_INPUT_PORT_TR_WORD0 ; - filter_replace_buf.data[4 ] |= -I40E_AQC_REPLACE_CLOUD_CMD_INPUT_VALIDATED ; - filter_replace_buf.data[5 ] =0x00 ; - filter_replace_buf.data[6 ] =I40E_TR_L4_TYPE_UDP | -I40E_TR_L4_TYPE_TCP | -I40E_TR_L4_TYPE_SCTP ; - filter_replace_buf.data[7 ] =0x00 ; - filter_replace_buf.data[8 ] |= -I40E_AQC_REPLACE_CLOUD_CMD_INPUT_VALIDATED ; - filter_replace_buf.data[9 ] =0x00 ; - filter_replace_buf.data[10 ] =0xFF ; - filter_replace_buf.data[11 ] =0xFF ; - - status =i40e_aq_replace_cloud_filters (hw, &filter_replace, - &filter_replace_buf); -if (!status && filter_replace.old_filter_type != - filter_replace.new_filter_type) -PMD_DRV_LOG (WARNING ,"i40e device %s changed cloud l1 type." -" original: 0x%x, new: 0x%x" , - dev->device->name, - filter_replace.old_filter_type, - filter_replace.new_filter_type); - -return status; -} - -static enum i40e_status_code -i40e_replace_port_cloud_filter (struct i40e_pf *pf, -enum i40e_l4_port_type l4_port_type) -{ -struct i40e_aqc_replace_cloud_filters_cmd_buf filter_replace_buf; -struct i40e_aqc_replace_cloud_filters_cmd filter_replace; -enum i40e_status_code status =I40E_SUCCESS ; -struct i40e_hw *hw =I40E_PF_TO_HW (pf); -struct rte_eth_dev *dev = &rte_eth_devices[pf->dev_data->port_id]; - -if (pf->support_multi_driver) { -PMD_DRV_LOG (ERR ,"Replace cloud filter is not supported." ); -return I40E_NOT_SUPPORTED ; - } - -memset (&filter_replace,0 , -sizeof (struct i40e_aqc_replace_cloud_filters_cmd )); -memset (&filter_replace_buf,0 , -sizeof (struct i40e_aqc_replace_cloud_filters_cmd_buf )); - -if (l4_port_type ==I40E_L4_PORT_TYPE_SRC ) { - filter_replace.old_filter_type =I40E_AQC_ADD_CLOUD_FILTER_IIP ; - filter_replace.new_filter_type = -I40E_AQC_ADD_CLOUD_FILTER_0X11 ; - filter_replace_buf.data[4 ] =I40E_AQC_ADD_CLOUD_FILTER_0X11 ; - }else { - filter_replace.old_filter_type =I40E_AQC_ADD_CLOUD_FILTER_OIP ; - filter_replace.new_filter_type = -I40E_AQC_ADD_CLOUD_FILTER_0X10 ; - filter_replace_buf.data[4 ] =I40E_AQC_ADD_CLOUD_FILTER_0X10 ; - } - - filter_replace.valid_flags =I40E_AQC_REPLACE_CLOUD_FILTER ; - filter_replace.tr_bit =0 ; -/* Prepare the buffer, 2 entries */ - filter_replace_buf.data[0 ] =I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_STAG ; - filter_replace_buf.data[0 ] |= -I40E_AQC_REPLACE_CLOUD_CMD_INPUT_VALIDATED ; - filter_replace_buf.data[4 ] |= -I40E_AQC_REPLACE_CLOUD_CMD_INPUT_VALIDATED ; - status =i40e_aq_replace_cloud_filters (hw, &filter_replace, - &filter_replace_buf); - -if (!status && filter_replace.old_filter_type != - filter_replace.new_filter_type) -PMD_DRV_LOG (WARNING ,"i40e device %s changed cloud filter type." -" original: 0x%x, new: 0x%x" , - dev->device->name, - filter_replace.old_filter_type, - filter_replace.new_filter_type); - -return status; -} - -int -i40e_dev_consistent_tunnel_filter_set (struct i40e_pf *pf, -struct i40e_tunnel_filter_conf *tunnel_filter, -uint8_t add) +static int +i40e_tunnel_filter_convert_conf (struct i40e_pf *pf, +struct i40e_tunnel_filter_conf *tunnel_filter, +struct i40e_aqc_cloud_filters_element_bb *cld_filter, +struct i40e_vsi **vsi,bool *big_buffer) {uint16_t ip_type;uint32_t ipv4_addr, ipv4_addr_le;uint8_t i, tun_type =0 ;/* internal variable to convert ipv6 byte order */ uint32_t convert_ipv6[4 ]; -int val, ret =0 ; +int val;struct i40e_pf_vf *vf =NULL ; -struct i40e_hw *hw =I40E_PF_TO_HW (pf); -struct i40e_vsi *vsi; -struct i40e_aqc_cloud_filters_element_bb cld_filter = {0 }; -struct i40e_tunnel_rule *tunnel_rule = &pf->tunnel; -struct i40e_tunnel_filter *node; -struct i40e_tunnel_filter check_filter;/* Check if filter exists */ uint32_t teid_le; -bool big_buffer =0 ;rte_ether_addr_copy (&tunnel_filter->outer_mac, - (struct rte_ether_addr *)&cld_filter.element.outer_mac); + (struct rte_ether_addr *)&cld_filter->element.outer_mac);rte_ether_addr_copy (&tunnel_filter->inner_mac, - (struct rte_ether_addr *)&cld_filter.element.inner_mac); + (struct rte_ether_addr *)&cld_filter->element.inner_mac); - cld_filter.element.inner_vlan = + cld_filter->element.inner_vlan =rte_cpu_to_le_16 (tunnel_filter->inner_vlan);if (tunnel_filter->ip_type ==I40E_TUNNEL_IPTYPE_IPV4 ) { ip_type =I40E_AQC_ADD_CLOUD_FLAGS_IPV4 ; ipv4_addr =rte_be_to_cpu_32 (tunnel_filter->ip_addr.ipv4_addr); ipv4_addr_le =rte_cpu_to_le_32 (ipv4_addr); -memcpy (&cld_filter.element.ipaddr.v4.data, +memcpy (&cld_filter->element.ipaddr.v4.data, &ipv4_addr_le, -sizeof (cld_filter.element.ipaddr.v4.data)); +sizeof (cld_filter->element.ipaddr.v4.data)); }else { ip_type =I40E_AQC_ADD_CLOUD_FLAGS_IPV6 ;for (i =0 ; i <4 ; i++) {
@@ -8289,9 +7759,9 @@ i40e_dev_consistent_tunnel_filter_set(struct i40e_pf *pf,rte_cpu_to_le_32 (rte_be_to_cpu_32 ( tunnel_filter->ip_addr.ipv6_addr[i])); } -memcpy (&cld_filter.element.ipaddr.v6.data, +memcpy (&cld_filter->element.ipaddr.v6.data, &convert_ipv6, -sizeof (cld_filter.element.ipaddr.v6.data)); +sizeof (cld_filter->element.ipaddr.v6.data)); }/* check tunneled type */
@@ -8306,139 +7776,96 @@ i40e_dev_consistent_tunnel_filter_set(struct i40e_pf *pf, tun_type =I40E_AQC_ADD_CLOUD_TNL_TYPE_IP ;break ;case I40E_TUNNEL_TYPE_MPLSoUDP: -if (!pf->mpls_replace_flag) { -i40e_replace_mpls_l1_filter (pf); -i40e_replace_mpls_cloud_filter (pf); - pf->mpls_replace_flag =1 ; - } teid_le =rte_cpu_to_le_32 (tunnel_filter->tenant_id); - cld_filter.general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X11_WORD0 ] = + cld_filter->general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X11_WORD0 ] = teid_le >>4 ; - cld_filter.general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X11_WORD1 ] = + cld_filter->general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X11_WORD1 ] = (teid_le &0xF ) <<12 ; - cld_filter.general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X11_WORD2 ] = + cld_filter->general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X11_WORD2 ] =0x40 ; - big_buffer =1 ; + *big_buffer =1 ; tun_type =I40E_AQC_ADD_CLOUD_TNL_TYPE_MPLSOUDP ;break ;case I40E_TUNNEL_TYPE_MPLSoGRE: -if (!pf->mpls_replace_flag) { -i40e_replace_mpls_l1_filter (pf); -i40e_replace_mpls_cloud_filter (pf); - pf->mpls_replace_flag =1 ; - } teid_le =rte_cpu_to_le_32 (tunnel_filter->tenant_id); - cld_filter.general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X11_WORD0 ] = + cld_filter->general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X11_WORD0 ] = teid_le >>4 ; - cld_filter.general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X11_WORD1 ] = + cld_filter->general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X11_WORD1 ] = (teid_le &0xF ) <<12 ; - cld_filter.general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X11_WORD2 ] = + cld_filter->general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X11_WORD2 ] =0x0 ; - big_buffer =1 ; + *big_buffer =1 ; tun_type =I40E_AQC_ADD_CLOUD_TNL_TYPE_MPLSOGRE ;break ;case I40E_TUNNEL_TYPE_GTPC : -if (!pf->gtp_replace_flag) { -i40e_replace_gtp_l1_filter (pf); -i40e_replace_gtp_cloud_filter (pf); - pf->gtp_replace_flag =1 ; - } teid_le =rte_cpu_to_le_32 (tunnel_filter->tenant_id); - cld_filter.general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X12_WORD0 ] = + cld_filter->general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X12_WORD0 ] = (teid_le >>16 ) &0xFFFF ; - cld_filter.general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X12_WORD1 ] = + cld_filter->general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X12_WORD1 ] = teid_le &0xFFFF ; - cld_filter.general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X12_WORD2 ] = + cld_filter->general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X12_WORD2 ] =0x0 ; - big_buffer =1 ; + *big_buffer =1 ;break ;case I40E_TUNNEL_TYPE_GTPU : -if (!pf->gtp_replace_flag) { -i40e_replace_gtp_l1_filter (pf); -i40e_replace_gtp_cloud_filter (pf); - pf->gtp_replace_flag =1 ; - } teid_le =rte_cpu_to_le_32 (tunnel_filter->tenant_id); - cld_filter.general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X13_WORD0 ] = + cld_filter->general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X13_WORD0 ] = (teid_le >>16 ) &0xFFFF ; - cld_filter.general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X13_WORD1 ] = + cld_filter->general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X13_WORD1 ] = teid_le &0xFFFF ; - cld_filter.general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X13_WORD2 ] = + cld_filter->general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X13_WORD2 ] =0x0 ; - big_buffer =1 ; + *big_buffer =1 ;break ;case I40E_TUNNEL_TYPE_QINQ : -if (!pf->qinq_replace_flag) { - ret =i40e_cloud_filter_qinq_create (pf); -if (ret <0 ) { -PMD_DRV_LOG (ERR ,"Failed to create QinQ tunnel filter." ); -/* ret is a raw i40e_status_code, not an errno */ -return -ENOTSUP ; - } - pf->qinq_replace_flag =1 ; - }/* Add in the General fields the values of * the Outer and Inner VLAN * Big Buffer should be set, see changes in * i40e_aq_add_cloud_filters */ - cld_filter.general_fields[0 ] = tunnel_filter->inner_vlan; - cld_filter.general_fields[1 ] = tunnel_filter->outer_vlan; - big_buffer =1 ; + cld_filter->general_fields[0 ] = tunnel_filter->inner_vlan; + cld_filter->general_fields[1 ] = tunnel_filter->outer_vlan; + *big_buffer =1 ;break ;case I40E_CLOUD_TYPE_UDP :case I40E_CLOUD_TYPE_TCP :case I40E_CLOUD_TYPE_SCTP :if (tunnel_filter->l4_port_type ==I40E_L4_PORT_TYPE_SRC ) { -if (!pf->sport_replace_flag) { -i40e_replace_port_l1_filter (pf, - tunnel_filter->l4_port_type); -i40e_replace_port_cloud_filter (pf, - tunnel_filter->l4_port_type); - pf->sport_replace_flag =1 ; - } teid_le =rte_cpu_to_le_32 (tunnel_filter->tenant_id); - cld_filter.general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X11_WORD0 ] = + cld_filter->general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X11_WORD0 ] =I40E_DIRECTION_INGRESS_KEY ;if (tunnel_filter->tunnel_type ==I40E_CLOUD_TYPE_UDP ) - cld_filter.general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X11_WORD1 ] = + cld_filter->general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X11_WORD1 ] =I40E_TR_L4_TYPE_UDP ;else if (tunnel_filter->tunnel_type ==I40E_CLOUD_TYPE_TCP ) - cld_filter.general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X11_WORD1 ] = + cld_filter->general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X11_WORD1 ] =I40E_TR_L4_TYPE_TCP ;else - cld_filter.general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X11_WORD1 ] = + cld_filter->general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X11_WORD1 ] =I40E_TR_L4_TYPE_SCTP ; - cld_filter.general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X11_WORD2 ] = + cld_filter->general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X11_WORD2 ] = (teid_le >>16 ) &0xFFFF ; - big_buffer =1 ; + *big_buffer =1 ; }else { -if (!pf->dport_replace_flag) { -i40e_replace_port_l1_filter (pf, - tunnel_filter->l4_port_type); -i40e_replace_port_cloud_filter (pf, - tunnel_filter->l4_port_type); - pf->dport_replace_flag =1 ; - } teid_le =rte_cpu_to_le_32 (tunnel_filter->tenant_id); - cld_filter.general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X10_WORD0 ] = + cld_filter->general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X10_WORD0 ] =I40E_DIRECTION_INGRESS_KEY ;if (tunnel_filter->tunnel_type ==I40E_CLOUD_TYPE_UDP ) - cld_filter.general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X10_WORD1 ] = + cld_filter->general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X10_WORD1 ] =I40E_TR_L4_TYPE_UDP ;else if (tunnel_filter->tunnel_type ==I40E_CLOUD_TYPE_TCP ) - cld_filter.general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X10_WORD1 ] = + cld_filter->general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X10_WORD1 ] =I40E_TR_L4_TYPE_TCP ;else - cld_filter.general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X10_WORD1 ] = + cld_filter->general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X10_WORD1 ] =I40E_TR_L4_TYPE_SCTP ; - cld_filter.general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X10_WORD2 ] = + cld_filter->general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X10_WORD2 ] = (teid_le >>16 ) &0xFFFF ; - big_buffer =1 ; + *big_buffer =1 ; }break ;
@@ -8449,74 +7876,111 @@ i40e_dev_consistent_tunnel_filter_set(struct i40e_pf *pf, }if (tunnel_filter->tunnel_type == I40E_TUNNEL_TYPE_MPLSoUDP) - cld_filter.element.flags = + cld_filter->element.flags =I40E_AQC_ADD_CLOUD_FILTER_0X11 ;else if (tunnel_filter->tunnel_type == I40E_TUNNEL_TYPE_MPLSoGRE) - cld_filter.element.flags = + cld_filter->element.flags =I40E_AQC_ADD_CLOUD_FILTER_0X12 ;else if (tunnel_filter->tunnel_type ==I40E_TUNNEL_TYPE_GTPC ) - cld_filter.element.flags = + cld_filter->element.flags =I40E_AQC_ADD_CLOUD_FILTER_0X11 ;else if (tunnel_filter->tunnel_type ==I40E_TUNNEL_TYPE_GTPU ) - cld_filter.element.flags = + cld_filter->element.flags =I40E_AQC_ADD_CLOUD_FILTER_0X12 ;else if (tunnel_filter->tunnel_type ==I40E_TUNNEL_TYPE_QINQ ) - cld_filter.element.flags |= + cld_filter->element.flags |=I40E_AQC_ADD_CLOUD_FILTER_0X10 ;else if (tunnel_filter->tunnel_type ==I40E_CLOUD_TYPE_UDP || tunnel_filter->tunnel_type ==I40E_CLOUD_TYPE_TCP || tunnel_filter->tunnel_type ==I40E_CLOUD_TYPE_SCTP ) {if (tunnel_filter->l4_port_type ==I40E_L4_PORT_TYPE_SRC ) - cld_filter.element.flags |= + cld_filter->element.flags |=I40E_AQC_ADD_CLOUD_FILTER_0X11 ;else - cld_filter.element.flags |= + cld_filter->element.flags |=I40E_AQC_ADD_CLOUD_FILTER_0X10 ; }else { val =i40e_dev_get_filter_type (tunnel_filter->filter_type, - &cld_filter.element.flags); + &cld_filter->element.flags);if (val <0 ) {return -EINVAL ; } } - cld_filter.element.flags |= + cld_filter->element.flags |=rte_cpu_to_le_16 (I40E_AQC_ADD_CLOUD_FLAGS_TO_QUEUE | ip_type | (tun_type <<I40E_AQC_ADD_CLOUD_TNL_TYPE_SHIFT )); - cld_filter.element.tenant_id =rte_cpu_to_le_32 (tunnel_filter->tenant_id); - cld_filter.element.queue_number = + cld_filter->element.tenant_id =rte_cpu_to_le_32 (tunnel_filter->tenant_id); + cld_filter->element.queue_number =rte_cpu_to_le_16 (tunnel_filter->queue_id);if (!tunnel_filter->is_to_vf) - vsi = pf->main_vsi; + *vsi = pf->main_vsi;else {if (tunnel_filter->vf_id >= pf->vf_num) {PMD_DRV_LOG (ERR ,"Invalid argument." );return -EINVAL ; } vf = &pf->vfs[tunnel_filter->vf_id]; - vsi = vf->vsi; + *vsi = vf->vsi; } -/* Check if there is the filter in SW list */ -memset (&check_filter,0 ,sizeof (check_filter)); -i40e_tunnel_filter_convert (&cld_filter, &check_filter); - check_filter.is_to_vf = tunnel_filter->is_to_vf; - check_filter.vf_id = tunnel_filter->vf_id; - node =i40e_sw_tunnel_filter_lookup (tunnel_rule, &check_filter.input); -if (add && node) { -PMD_DRV_LOG (ERR ,"Conflict with existing tunnel rules!" ); -return -EINVAL ; - } +return 0 ; +} -if (!add && !node) { -PMD_DRV_LOG (ERR ,"There's no corresponding tunnel filter!" ); -return -EINVAL ; - } +int +i40e_tunnel_filter_match_key_get (struct i40e_pf *pf, +struct i40e_tunnel_filter_conf *tunnel_filter, +struct i40e_tunnel_filter_match_key *input) +{ +struct i40e_aqc_cloud_filters_element_bb cld_filter = {0 }; +struct i40e_vsi *vsi; +bool big_buffer =0 ; +int ret; + + ret =i40e_tunnel_filter_convert_conf (pf, tunnel_filter, &cld_filter, + &vsi, &big_buffer); +if (ret !=0 ) +return ret; + +rte_ether_addr_copy ((struct rte_ether_addr *) + &cld_filter.element.outer_mac, + (struct rte_ether_addr *)&input->outer_mac); +rte_ether_addr_copy ((struct rte_ether_addr *) + &cld_filter.element.inner_mac, + (struct rte_ether_addr *)&input->inner_mac); + input->inner_vlan = cld_filter.element.inner_vlan; +if ((rte_le_to_cpu_16 (cld_filter.element.flags) & +I40E_AQC_ADD_CLOUD_FLAGS_IPV6 ) == +I40E_AQC_ADD_CLOUD_FLAGS_IPV6 ) + input->ip_type =I40E_TUNNEL_IPTYPE_IPV6 ; +else + input->ip_type =I40E_TUNNEL_IPTYPE_IPV4 ; + input->flags = cld_filter.element.flags; + input->tenant_id = cld_filter.element.tenant_id; +memcpy (input->general_fields, cld_filter.general_fields, +sizeof (cld_filter.general_fields)); + +return 0 ; +} + +int +i40e_tunnel_filter_program (struct i40e_pf *pf, +struct i40e_tunnel_filter_conf *tunnel_filter, +uint8_t add) +{ +struct i40e_hw *hw =I40E_PF_TO_HW (pf); +struct i40e_aqc_cloud_filters_element_bb cld_filter = {0 }; +struct i40e_vsi *vsi; +bool big_buffer =0 ; +int ret; + + ret =i40e_tunnel_filter_convert_conf (pf, tunnel_filter, &cld_filter, + &vsi, &big_buffer); +if (ret !=0 ) +return ret;if (add) { -struct i40e_tunnel_filter *tunnel; -if (big_buffer) ret =i40e_aq_add_cloud_filters_bb (hw, vsi->seid, &cld_filter,1 );
@@ -8527,16 +7991,6 @@ i40e_dev_consistent_tunnel_filter_set(struct i40e_pf *pf,PMD_DRV_LOG (ERR ,"Failed to add a tunnel filter." );return -ENOTSUP ; } - tunnel =rte_zmalloc ("tunnel_filter" ,sizeof (*tunnel),0 ); -if (tunnel ==NULL ) { -PMD_DRV_LOG (ERR ,"Failed to alloc memory." ); -return -ENOMEM ; - } - -memcpy (tunnel, &check_filter,sizeof (check_filter)); - ret =i40e_sw_tunnel_filter_insert (pf, tunnel); -if (ret <0 ) -rte_free (tunnel); }else {if (big_buffer) ret = i40e_aq_rem_cloud_filters_bb(
@@ -8548,7 +8002,6 @@ i40e_dev_consistent_tunnel_filter_set(struct i40e_pf *pf,PMD_DRV_LOG (ERR ,"Failed to delete a tunnel filter." );return -ENOTSUP ; } - ret =i40e_sw_tunnel_filter_del (pf, &node->input); }return ret;
@@ -11256,65 +10709,9 @@ i40e_dev_mtu_set(struct rte_eth_dev *dev, uint16_t mtu __rte_unused)return 0 ; } -/* Restore tunnel filter */ -static void -i40e_tunnel_filter_restore (struct i40e_pf *pf) -{ -struct i40e_hw *hw =I40E_PF_TO_HW (pf); -struct i40e_vsi *vsi; -struct i40e_pf_vf *vf; -struct i40e_tunnel_filter_list - *tunnel_list = &pf->tunnel.tunnel_list; -struct i40e_tunnel_filter *f; -struct i40e_aqc_cloud_filters_element_bb cld_filter; -bool big_buffer =0 ; - - TAILQ_FOREACH(f, tunnel_list, rules) { -if (!f->is_to_vf) - vsi = pf->main_vsi; -else { - vf = &pf->vfs[f->vf_id]; - vsi = vf->vsi; - } -memset (&cld_filter,0 ,sizeof (cld_filter)); -rte_ether_addr_copy ((struct rte_ether_addr *) - &f->input.outer_mac, - (struct rte_ether_addr *)&cld_filter.element.outer_mac); -rte_ether_addr_copy ((struct rte_ether_addr *) - &f->input.inner_mac, - (struct rte_ether_addr *)&cld_filter.element.inner_mac); - cld_filter.element.inner_vlan = f->input.inner_vlan; - cld_filter.element.flags = f->input.flags; - cld_filter.element.tenant_id = f->input.tenant_id; - cld_filter.element.queue_number = f->queue; -memcpy (cld_filter.general_fields, - f->input.general_fields, -sizeof (f->input.general_fields)); - -if (((f->input.flags & -I40E_AQC_ADD_CLOUD_FILTER_0X11 ) == -I40E_AQC_ADD_CLOUD_FILTER_0X11 ) || - ((f->input.flags & -I40E_AQC_ADD_CLOUD_FILTER_0X12 ) == -I40E_AQC_ADD_CLOUD_FILTER_0X12 ) || - ((f->input.flags & -I40E_AQC_ADD_CLOUD_FILTER_0X10 ) == -I40E_AQC_ADD_CLOUD_FILTER_0X10 )) - big_buffer =1 ; - -if (big_buffer) -i40e_aq_add_cloud_filters_bb (hw, - vsi->seid, &cld_filter,1 ); -else -i40e_aq_add_cloud_filters (hw, vsi->seid, - &cld_filter.element,1 ); - } -} -static void i40e_filter_restore (struct i40e_pf *pf) { -i40e_tunnel_filter_restore (pf);i40e_fdir_filter_restore (pf); (void )i40e_hash_filter_restore (pf); }
@@ -11747,133 +11144,6 @@ i40e_update_customized_info(struct rte_eth_dev *dev, uint8_t *pkg,free (proto); } -/* Create a QinQ cloud filter -* -* The Fortville NIC has limited resources for tunnel filters, -* so we can only reuse existing filters. -* -* In step 1 we define which Field Vector fields can be used for -* filter types. -* As we do not have the inner tag defined as a field, -* we have to define it first, by reusing one of L1 entries. -* -* In step 2 we are replacing one of existing filter types with -* a new one for QinQ. -* As we reusing L1 and replacing L2, some of the default filter -* types will disappear,which depends on L1 and L2 entries we reuse. -* -* Step 1: Create L1 filter of outer vlan (12b) + inner vlan (12b) -* -* 1. Create L1 filter of outer vlan (12b) which will be in use -* later when we define the cloud filter. -* a. Valid_flags.replace_cloud = 0 -* b. Old_filter = 10 (Stag_Inner_Vlan) -* c. New_filter = 0x10 -* d. TR bit = 0xff (optional, not used here) -* e. Buffer – 2 entries: -* i. Byte 0 = 8 (outer vlan FV index). -* Byte 1 = 0 (rsv) -* Byte 2-3 = 0x0fff -* ii. Byte 0 = 37 (inner vlan FV index). -* Byte 1 =0 (rsv) -* Byte 2-3 = 0x0fff -* -* Step 2: -* 2. Create cloud filter using two L1 filters entries: stag and -* new filter(outer vlan+ inner vlan) -* a. Valid_flags.replace_cloud = 1 -* b. Old_filter = 1 (instead of outer IP) -* c. New_filter = 0x10 -* d. Buffer – 2 entries: -* i. Byte 0 = 0x80 | 7 (valid | Stag). -* Byte 1-3 = 0 (rsv) -* ii. Byte 8 = 0x80 | 0x10 (valid | new l1 filter step1) -* Byte 9-11 = 0 (rsv) -*/ -static int -i40e_cloud_filter_qinq_create (struct i40e_pf *pf) -{ -int ret = -ENOTSUP ; -struct i40e_aqc_replace_cloud_filters_cmd filter_replace; -struct i40e_aqc_replace_cloud_filters_cmd_buf filter_replace_buf; -struct i40e_hw *hw =I40E_PF_TO_HW (pf); -struct rte_eth_dev *dev = &rte_eth_devices[pf->dev_data->port_id]; - -if (pf->support_multi_driver) { -PMD_DRV_LOG (ERR ,"Replace cloud filter is not supported." ); -return ret; - } - -/* Init */ -memset (&filter_replace,0 , -sizeof (struct i40e_aqc_replace_cloud_filters_cmd )); -memset (&filter_replace_buf,0 , -sizeof (struct i40e_aqc_replace_cloud_filters_cmd_buf )); - -/* create L1 filter */ - filter_replace.old_filter_type = -I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_STAG_IVLAN ; - filter_replace.new_filter_type =I40E_AQC_ADD_CLOUD_FILTER_0X10 ; - filter_replace.tr_bit =0 ; - -/* Prepare the buffer, 2 entries */ - filter_replace_buf.data[0 ] =I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_VLAN ; - filter_replace_buf.data[0 ] |= -I40E_AQC_REPLACE_CLOUD_CMD_INPUT_VALIDATED ; -/* Field Vector 12b mask */ - filter_replace_buf.data[2 ] =0xff ; - filter_replace_buf.data[3 ] =0x0f ; - filter_replace_buf.data[4 ] = -I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_INNER_VLAN ; - filter_replace_buf.data[4 ] |= -I40E_AQC_REPLACE_CLOUD_CMD_INPUT_VALIDATED ; -/* Field Vector 12b mask */ - filter_replace_buf.data[6 ] =0xff ; - filter_replace_buf.data[7 ] =0x0f ; - ret =i40e_aq_replace_cloud_filters (hw, &filter_replace, - &filter_replace_buf); -if (ret !=I40E_SUCCESS ) -return ret; - -if (filter_replace.old_filter_type != - filter_replace.new_filter_type) -PMD_DRV_LOG (WARNING ,"i40e device %s changed cloud l1 type." -" original: 0x%x, new: 0x%x" , - dev->device->name, - filter_replace.old_filter_type, - filter_replace.new_filter_type); - -/* Apply the second L2 cloud filter */ -memset (&filter_replace,0 , -sizeof (struct i40e_aqc_replace_cloud_filters_cmd )); -memset (&filter_replace_buf,0 , -sizeof (struct i40e_aqc_replace_cloud_filters_cmd_buf )); - -/* create L2 filter, input for L2 filter will be L1 filter */ - filter_replace.valid_flags =I40E_AQC_REPLACE_CLOUD_FILTER ; - filter_replace.old_filter_type =I40E_AQC_ADD_CLOUD_FILTER_OIP ; - filter_replace.new_filter_type =I40E_AQC_ADD_CLOUD_FILTER_0X10 ; - -/* Prepare the buffer, 2 entries */ - filter_replace_buf.data[0 ] =I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_STAG ; - filter_replace_buf.data[0 ] |= -I40E_AQC_REPLACE_CLOUD_CMD_INPUT_VALIDATED ; - filter_replace_buf.data[4 ] =I40E_AQC_ADD_CLOUD_FILTER_0X10 ; - filter_replace_buf.data[4 ] |= -I40E_AQC_REPLACE_CLOUD_CMD_INPUT_VALIDATED ; - ret =i40e_aq_replace_cloud_filters (hw, &filter_replace, - &filter_replace_buf); -if (!ret && (filter_replace.old_filter_type != - filter_replace.new_filter_type)) -PMD_DRV_LOG (WARNING ,"i40e device %s changed cloud filter type." -" original: 0x%x, new: 0x%x" , - dev->device->name, - filter_replace.old_filter_type, - filter_replace.new_filter_type); - -return ret; -} -static int i40e_fec_get_capability (struct rte_eth_dev *dev, struct rte_eth_fec_capa *speed_fec_capa, __rte_unused unsigned int num)
drivers/net/intel/i40e/i40e_ethdev.h +43 -41
133 lines not on this page · raw message
drivers/net/intel/i40e/i40e_flow.c +7 -1695
1,579 lines not on this page · raw message
drivers/net/intel/i40e/i40e_flow_tunnel.c new file +1958 -0
1,958 lines not on this page · raw message
The rest of this diff is not shown. View the raw message.
Signature · 1 line
2.52.0
Part of the diff is not shown here. View the raw message.
PATCH v4 23/24 net/i40e: reimplement hash parser
In reply to Anatoly BurakovUse the new flow graph API and the common parsing framework to implement flow parser for RSS.
The RSS parser was bypassing the other generic infrastructure, probably because it was very convoluted and did not map onto that model very well. It has now been made a first-class citizen.
The hash parser is multiple engines that share state, so each engine will attach to the shared refcounted RSS configuration state.
Additionally, this is the final engine in i40e, so remaining legacy flow infrastructure has been removed.
--- drivers/net/intel/i40e/i40e_ethdev.c | 34 +- drivers/net/intel/i40e/i40e_ethdev.h | 36 +- drivers/net/intel/i40e/i40e_flow.c | 289 +---- drivers/net/intel/i40e/i40e_flow.h | 3 + drivers/net/intel/i40e/i40e_flow_hash.c | 1454 +++++++++++++++++++++++ drivers/net/intel/i40e/i40e_hash.c | 1212 +------------------ drivers/net/intel/i40e/i40e_hash.h | 19 +- drivers/net/intel/i40e/meson.build | 1 + 8 files changed, 1565 insertions(+), 1483 deletions(-) create mode 100644 drivers/net/intel/i40e/i40e_flow_hash.c
drivers/net/intel/i40e/i40e_ethdev.c +21 -13
@@ -1027,6 +1027,27 @@ i40e_tunnel_state_detach(struct i40e_tunnel_state *state) state->hash_table =NULL ; } +struct i40e_rss_state * +i40e_rss_state_attach (struct rte_eth_dev_data *dev_data) +{ +struct i40e_pf *pf =I40E_DEV_PRIVATE_TO_PF (dev_data->dev_private); +struct i40e_rss_state *state = &pf->rss_state; + +if (ci_usage_count_claim (&state->use_count)) +TAILQ_INIT (&state->list); + +return state; +} + +void +i40e_rss_state_detach (struct i40e_rss_state *state) +{ +if (!ci_usage_count_release (&state->use_count)) +return ; + + *state = (struct i40e_rss_state ){0 }; +} +static void i40e_init_customized_info (struct i40e_pf *pf) {
@@ -1630,9 +1651,6 @@ eth_i40e_dev_init(struct rte_eth_dev *dev, void *init_params __rte_unused)*/ i40e_add_tx_flow_control_drop_filter (pf); -/* initialize RSS rule list */ -TAILQ_INIT (&pf->rss_config_list); -/* initialize Traffic Manager configuration */ i40e_tm_conf_init (dev);
@@ -1775,8 +1793,6 @@ i40e_dev_configure(struct rte_eth_dev *dev) } } -TAILQ_INIT (&pf->flow_list); -return 0 ; err_dcb:
@@ -2444,7 +2460,6 @@ i40e_dev_close(struct rte_eth_dev *dev)struct rte_pci_device *pci_dev =RTE_CLASS_TO_BUS_DEVICE (dev, *pci_dev);struct rte_intr_handle *intr_handle = pci_dev->intr_handle;struct i40e_filter_control_settings settings; -struct rte_flow *p_flow;uint32_t reg;int i;int ret;
@@ -2536,12 +2551,6 @@ i40e_dev_close(struct rte_eth_dev *dev)i40e_msec_delay (500 ); }while (retries++ <5 ); -/* Remove all flows */ -while ((p_flow =TAILQ_FIRST (&pf->flow_list))) { -TAILQ_REMOVE (&pf->flow_list, p_flow, node); -rte_free (p_flow); - } -/* Remove all Traffic Manager configuration */ i40e_tm_conf_uninit (dev);
@@ -10713,7 +10722,6 @@ static void i40e_filter_restore(struct i40e_pf *pf) {i40e_fdir_filter_restore (pf); - (void )i40e_hash_filter_restore (pf); }bool
drivers/net/intel/i40e/i40e_ethdev.h +18 -18
@@ -282,9 +282,6 @@ enum i40e_flxpld_layer_idx {*/ struct rte_flow {struct ci_flow base; -TAILQ_ENTRY (rte_flow) node; -enum rte_filter_type filter_type; -void *rule; };/**
@@ -993,8 +990,6 @@ struct i40e_tunnel_filter_conf {uint16_t vf_id;/**< VF id, available when is_to_vf is 1. */ }; -TAILQ_HEAD (i40e_flow_list, rte_flow); -/* Struct to store Traffic Manager shaper profile. */ struct i40e_tm_shaper_profile {TAILQ_ENTRY (i40e_tm_shaper_profile) node;
@@ -1081,7 +1076,7 @@ struct i40e_customized_pctype {#define I40E_RSS_KEY_LEN ((I40E_PFQF_HKEY_MAX_INDEX + 1) * sizeof(uint32_t)) -struct i40e_rte_flow_rss_conf { +struct i40e_rss_conf {enum rte_eth_hash_function func;uint64_t types;/**< Specific RSS hash types (see RTE_ETH_RSS_*). */ uint32_t key_len;/**< Hash key length in bytes. */
@@ -1116,14 +1111,23 @@ struct i40e_rss_filter_data {uint64_t reset_symmetric_pctypes; }; -/* RSS filter list structure */ -struct i40e_rss_filter { -TAILQ_ENTRY (i40e_rss_filter) next; -struct i40e_rte_flow_rss_conf rss_filter_info; +/* +* Tracking entry for a registered RSS flow: points back to the flow that +* owns the rss_conf, plus the metadata recording which HW state it owns. +*/ +struct i40e_rss_flow_node { +TAILQ_ENTRY (i40e_rss_flow_node) next; +struct ci_flow *flow;struct i40e_rss_filter_data filter_data; }; -TAILQ_HEAD (i40e_rss_conf_list, i40e_rss_filter); +TAILQ_HEAD (i40e_rss_node_list, i40e_rss_flow_node); + +/* RSS flow engine shared state, attached/detached by the RSS engines */ +struct i40e_rss_state { +ci_usage_count_t use_count; +struct i40e_rss_node_list list; +};struct i40e_vf_msg_cfg {/* maximal VF message during a statistic period */
@@ -1200,13 +1204,12 @@ struct i40e_pf {struct i40e_fdir_info fdir;/* flow director info */ struct i40e_tunnel_state tunnel_state;/* tunnel flow engine state */ -struct i40e_rss_conf_list rss_config_list;/* RSS rule list */ +struct i40e_rss_state rss_state;/* RSS flow engine state */ struct i40e_queue_regions queue_region;/* queue region info */ struct i40e_fc_conf fc_conf;/* Flow control conf */ bool floating_veb;/* The flag to use the floating VEB */ /* The floating enable flag for the specific VF */ bool floating_veb_list[I40E_MAX_VF ]; -struct i40e_flow_list flow_list;/* flow engine configuration */ struct ci_flow_engine_conf flow_engine_conf;struct i40e_tm_conf tm_conf;
@@ -1339,11 +1342,6 @@ struct i40e_vf_representor {extern const struct rte_flow_ops i40e_flow_ops; -struct i40e_filter_ctx { -struct i40e_rte_flow_rss_conf rss_conf; -enum rte_filter_type type; -}; -int i40e_dev_switch_queues (struct i40e_pf *pf,bool on);int i40e_vsi_release (struct i40e_vsi *vsi); struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf,
@@ -1456,6 +1454,8 @@ int i40e_tunnel_filter_match_key_get(struct i40e_pf *pf, struct i40e_tunnel_filter_match_key *out);struct i40e_tunnel_state *i40e_tunnel_state_attach (struct rte_eth_dev_data *dev_data);void i40e_tunnel_state_detach (struct i40e_tunnel_state *state); +struct i40e_rss_state *i40e_rss_state_attach (struct rte_eth_dev_data *dev_data); +void i40e_rss_state_detach (struct i40e_rss_state *state);int i40e_tunnel_filter_program (struct i40e_pf *pf,struct i40e_tunnel_filter_conf *tunnel_filter,uint8_t add);
drivers/net/intel/i40e/i40e_flow.c +10 -279
347 lines not on this page · raw message
drivers/net/intel/i40e/i40e_flow.h +3 -0
@@ -23,5 +23,8 @@ extern const struct ci_flow_engine i40e_flow_engine_tunnel_nvgre;extern const struct ci_flow_engine i40e_flow_engine_tunnel_mpls;extern const struct ci_flow_engine i40e_flow_engine_tunnel_gtp;extern const struct ci_flow_engine i40e_flow_engine_tunnel_l4; +extern const struct ci_flow_engine i40e_flow_engine_hash_pattern; +extern const struct ci_flow_engine i40e_flow_engine_hash_vlan; +extern const struct ci_flow_engine i40e_flow_engine_hash_empty;#endif /* _I40E_FLOW_H_ */
drivers/net/intel/i40e/i40e_flow_hash.c new file +1454 -0
1,454 lines not on this page · raw message
drivers/net/intel/i40e/i40e_hash.c +52 -1160
1,035 lines not on this page · raw message
The rest of this diff is not shown. View the raw message.
Signature · 1 line
2.52.0
Part of the diff is not shown here. View the raw message.
PATCH v4 24/24 net/i40e: advertise flow keep capability
In reply to Anatoly BurakovThe i40e driver's rte_flow implementation has always endeavored to keep flows across device restart, however it never advertised this capability. Advertise it explicitly.
--- doc/guides/rel_notes/release_26_11.rst | 5 +++++ drivers/net/intel/i40e/i40e_ethdev.c | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-)
doc/guides/rel_notes/release_26_11.rst +5 -0
@@ -109,6 +109,11 @@ New Features * Advertised ``RTE_ETH_DEV_CAPA_FLOW_RULE_KEEP`` capability, as flow rules were already kept across device restart. +* **Updated Intel i40e driver.** + + * Advertised ``RTE_ETH_DEV_CAPA_FLOW_RULE_KEEP`` capability, + as flow rules were already kept across device restart. + * **Updated NXP DPAA2 ethernet driver.** * Added the inner IP header to the RSS hash so tunneled traffic is
drivers/net/intel/i40e/i40e_ethdev.c +2 -1
@@ -3631,7 +3631,8 @@ i40e_dev_info_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info) dev_info->dev_capa =RTE_ETH_DEV_CAPA_RUNTIME_RX_QUEUE_SETUP |RTE_ETH_DEV_CAPA_RUNTIME_TX_QUEUE_SETUP ; - dev_info->dev_capa &= ~RTE_ETH_DEV_CAPA_FLOW_RULE_KEEP ; +/* rte_flow rules are kept across dev_stop/dev_start and replayed on start */ + dev_info->dev_capa |=RTE_ETH_DEV_CAPA_FLOW_RULE_KEEP ; dev_info->hash_key_size = (I40E_PFQF_HKEY_MAX_INDEX +1 ) *sizeof (uint32_t );
Signature · 1 line
2.52.0
v5 cover Building a better rte_flow parser
In reply to Anatoly BurakovMost rte_flow parsers in DPDK suffer from huge implementation complexity because even though 99% of what people use rte_flow parsers for is parsing protocol graphs, no parser is written explicitly as a graph. This patchset attempts to suggest a viable model to build rte_flow parsers as graphs, by offering a library to build rte_flow parser graphs without too much boilerplate and complexity.
Most of the patchset is about Intel drivers, but they are meant as reimplementations as well as examples for the rest of the community to assess how to build parsers using this new infrastructure. I expect the first three patches will be of most interest to non-Intel reviewers, as they deal with building two reusable parser architecture pieces.
The first piece is a new flow graph helper in ethdev. Its purpose is deliberately narrow: it targets the protocol-graph part of rte_flow pattern parsing, where drivers walk packet headers and validate legal item sequences and parameters. That does not cover all possible rte_flow features, especially more exotic flow items, but it does cover a large and widely shared part of what existing drivers need to do. Or, to put it in other words, the only flow items this infrastructure *doesn't* cover is things that do not lend themselves well to be parsed as a graph of protocol headers (e.g. conntrack items). Everything else should be covered or cover-able. In practice, just about all drivers will benefit from graph parsing as all but one of them implement only the protocol stack parts, which are the ones targeted by the graph helper.
The second piece is a reusable flow engine framework for Intel Ethernet drivers. This is kept Intel-local because I do not feel it is even appropriate to define such a framework for all drivers to use in the first place. Even so, the intent is to establish a cleaner parser architecture with a defined interaction model, explicit memory ownership rules, locking, initialization sequence, implementations of rte_flow API entry points, flow replay and memory cleanup, and engine definitions that do not block secondary-process-safe usage. It is my hope that this would serve as a model for other drivers to follow, expand on, rework, and improve, so that maybe down the line we *might* have a common rte_flow infrastructure for drivers to use.
Most of the rest of the series is parser reimplementation, but that is mainly the vehicle for demonstrating and validating those two pieces. ixgbe and i40e are wired into the new common parsing path, and their existing parsers are migrated incrementally to the graph-based model. Besides reducing ad hoc parser code, this also makes validation more explicit and more consistent. In a few places that means invalid inputs that were previously ignored, deferred, or interpreted loosely are now rejected earlier and more strictly, without any increase in code complexity (in fact, with marked *decrease* of it!).
v4 -> v5:
- Fixed ixgbe ntuple parsing of L4 protocol flows
- Rebased on top of latest ixgbe changes
- Revised ixgbe FDIR refactoring to have less duplication
v3 -> v4:
- Added a "get default mask" flow API
- Simplified graph constraints implementation
- Made flow graph a compiled unit instead of header-only library
- Reworked all graph engines to use default flow mask if user didn't provide one
- Split out ixgbe ethertype refactor into a separate patch
- Split out SYN and ntuple priority fixes as separate patches
- Refactored ixgbe RSS configuration structure
- Address Vladimir's feedback for specific engines
- Address Stephen's comments
- Reduced the number of comments in code
v2 -> v3:
- Rebase on top of latest next-net-intel
- Cleanup pass on naming of engines and hash tables
- Added more logging to flow engine initializations
- Introduced a lightweight refcount to initialize shared resources
- Some small refactors in how ixgbe flow director engine keeps its state
- Fixed typos in documentation
v1 -> v2:
- Renamed rte_flow_graph to flow_graph
- Addressed some comments from Stephen's AI review
- Removed the rte_flow_conv hack on account of Stephen's upcoming patches making the API stable
- Split up "flow_install" into register and install steps, which enabled two new use cases: cleanup of memory without HW deregistration, and flow configuration replay after dev_start
- More aggressive refactoring of all engines on account of new pieces of infrastructure, which allows for reduced complexity of implementation
- Combined i40e tunnel engine patches into one patch
- Added i40e flow director refactoring to cleanly support the new API as well as the legacy PMD-specific API
RFC -> v1:
- Fixed a lot of bugs, concurrency issues, and init/uninit sequence problems in Intel common flow engine implementation
- Fixed a few copypaste errors in various engines
- Improved comment documentation and flow engine docs
Anatoly Burakov (25):
ethdev: add default mask query to flow
ethdev: add flow graph API net/intel/common: add flow engines infrastructure net/intel/common: add utility functions net/ixgbe: add support for common flow parsing net/ixgbe: make ethertype filter table dynamic net/ixgbe: reimplement ethertype parser net/ixgbe: fix syn filter priority net/ixgbe: reimplement syn parser net/ixgbe: reimplement L2 tunnel parser net/ixgbe: fix ntuple filter priority net/ixgbe: fix protocol-only ntuple parsing net/ixgbe: reimplement ntuple parser net/ixgbe: reimplement security parser net/ixgbe: reimplement FDIR parser net/ixgbe: don't embed RSS conf in filter structs net/ixgbe: reimplement hash parser net/ixgbe: advertise flow keep capability net/i40e: add support for common flow parsing net/i40e: reimplement ethertype parser net/i40e: refactor FDIR engine infrastructure net/i40e: reimplement FDIR parser net/i40e: reimplement tunnel parsers net/i40e: reimplement hash parser net/i40e: advertise flow keep capability
doc/guides/prog_guide/ethdev/flow_graph.rst | 750 +++ doc/guides/prog_guide/ethdev/index.rst | 1 + doc/guides/rel_notes/release_26_11.rst | 22 +- drivers/net/intel/common/flow_engine.h | 1429 ++++++ drivers/net/intel/common/flow_util.h | 263 ++ drivers/net/intel/i40e/i40e_ethdev.c | 1523 +----- drivers/net/intel/i40e/i40e_ethdev.h | 322 +- drivers/net/intel/i40e/i40e_fdir.c | 1126 +++-- drivers/net/intel/i40e/i40e_flow.c | 4185 +---------------- drivers/net/intel/i40e/i40e_flow.h | 30 + drivers/net/intel/i40e/i40e_flow_ethertype.c | 351 ++ drivers/net/intel/i40e/i40e_flow_fdir.c | 2154 +++++++++ drivers/net/intel/i40e/i40e_flow_hash.c | 1454 ++++++ drivers/net/intel/i40e/i40e_flow_tunnel.c | 1958 ++++++++ drivers/net/intel/i40e/i40e_hash.c | 1212 +---- drivers/net/intel/i40e/i40e_hash.h | 19 +- drivers/net/intel/i40e/meson.build | 4 + drivers/net/intel/i40e/rte_pmd_i40e.c | 12 +- drivers/net/intel/ixgbe/ixgbe_ethdev.c | 1014 +--- drivers/net/intel/ixgbe/ixgbe_ethdev.h | 285 +- drivers/net/intel/ixgbe/ixgbe_fdir.c | 610 +-- drivers/net/intel/ixgbe/ixgbe_flow.c | 3243 +------------ drivers/net/intel/ixgbe/ixgbe_flow.h | 27 + .../net/intel/ixgbe/ixgbe_flow_ethertype.c | 299 ++ drivers/net/intel/ixgbe/ixgbe_flow_fdir.c | 1602 +++++++ drivers/net/intel/ixgbe/ixgbe_flow_hash.c | 216 + drivers/net/intel/ixgbe/ixgbe_flow_l2tun.c | 322 ++ drivers/net/intel/ixgbe/ixgbe_flow_ntuple.c | 694 +++ drivers/net/intel/ixgbe/ixgbe_flow_security.c | 586 +++ drivers/net/intel/ixgbe/ixgbe_flow_syn.c | 312 ++ drivers/net/intel/ixgbe/ixgbe_ipsec.c | 361 +- drivers/net/intel/ixgbe/ixgbe_ipsec.h | 50 +- drivers/net/intel/ixgbe/ixgbe_pf.c | 49 +- drivers/net/intel/ixgbe/ixgbe_rxtx.c | 80 +- .../net/intel/ixgbe/ixgbe_rxtx_vec_common.c | 4 +- drivers/net/intel/ixgbe/meson.build | 7 + lib/ethdev/flow_graph.c | 263 ++ lib/ethdev/flow_graph.h | 149 + lib/ethdev/meson.build | 2 + lib/ethdev/rte_flow.c | 207 +- lib/ethdev/rte_flow.h | 15 + 41 files changed, 14849 insertions(+), 12363 deletions(-) create mode 100644 doc/guides/prog_guide/ethdev/flow_graph.rst create mode 100644 drivers/net/intel/common/flow_engine.h create mode 100644 drivers/net/intel/common/flow_util.h create mode 100644 drivers/net/intel/i40e/i40e_flow.h create mode 100644 drivers/net/intel/i40e/i40e_flow_ethertype.c create mode 100644 drivers/net/intel/i40e/i40e_flow_fdir.c create mode 100644 drivers/net/intel/i40e/i40e_flow_hash.c create mode 100644 drivers/net/intel/i40e/i40e_flow_tunnel.c create mode 100644 drivers/net/intel/ixgbe/ixgbe_flow.h create mode 100644 drivers/net/intel/ixgbe/ixgbe_flow_ethertype.c create mode 100644 drivers/net/intel/ixgbe/ixgbe_flow_fdir.c create mode 100644 drivers/net/intel/ixgbe/ixgbe_flow_hash.c create mode 100644 drivers/net/intel/ixgbe/ixgbe_flow_l2tun.c create mode 100644 drivers/net/intel/ixgbe/ixgbe_flow_ntuple.c create mode 100644 drivers/net/intel/ixgbe/ixgbe_flow_security.c create mode 100644 drivers/net/intel/ixgbe/ixgbe_flow_syn.c create mode 100644 lib/ethdev/flow_graph.c create mode 100644 lib/ethdev/flow_graph.h
Signature · 1 line
2.52.0
PATCH v5 1/25 ethdev: add default mask query to flow
The rte_flow API defines that if the mask provided with the flow item is NULL, a default mask should be used where applicable. There is no API to get such mask, so add this API to rte_flow.
--- doc/guides/rel_notes/release_26_11.rst | 5 + lib/ethdev/rte_flow.c | 207 ++++++++++++++++++------- lib/ethdev/rte_flow.h | 15 ++ 3 files changed, 167 insertions(+), 60 deletions(-)
doc/guides/rel_notes/release_26_11.rst +5 -0
@@ -64,6 +64,11 @@ New Features Added ``rte_vlan_insert_tpid()`` to the net library. +* **Added flow item default mask lookup.** + + Added ``RTE_FLOW_CONV_OP_ITEM_DEFAULT_MASK_PTR`` conversion operation + to ``rte_flow_conv()`` to retrieve the default mask of a flow item type. + * **Updated AF_XDP driver.** * Changed the default device plugin endpoint path used when
lib/ethdev/rte_flow.c +147 -60
246 lines not on this page · raw message
lib/ethdev/rte_flow.h +15 -0
@@ -4411,6 +4411,21 @@ enum rte_flow_conv_op {* @code const char ** @endcode */ RTE_FLOW_CONV_OP_ACTION_NAME_PTR , + +/** +* Convert item type to pointer to its default mask. +* +* Writes a pointer to rte_flow_item_{name}_mask to @p dst, +* or NULL if the item type has no default mask. The mask itself is not +* copied; instead, a unique pointer to an internal static constant +* storage is written to @p dst. +* +* - @p src type: +* @code (const void *)enum rte_flow_item_type @endcode +* - @p dst type: +* @code const void ** @endcode +*/ + RTE_FLOW_CONV_OP_ITEM_DEFAULT_MASK_PTR, };/**
Signature · 1 line
2.52.0
Re: [PATCH v5 01/25] ethdev: add default mask query to flow
07/10/2026 12:49, Anatoly Burakov:
Quoted 5 lines
The
rte_flowAPI defines that if the mask provided with the flow item is NULL, a default mask should be used where applicable. There is no API to get such mask, so add this API torte_flow.Signed-off-by Anatoly Burakov <[email protected]>
It fills a gap in the API.
Thanks
PATCH v5 2/25 ethdev: add flow graph API
In reply to Anatoly BurakovThis commit adds a flow graph parsing API. This is a helper API intended to help ethdev drivers implement rte_flow parsers, as common usages map to graph traversal problem very well.
Features provided by the API:
- Flow graph, edge, and node definitions
- Graph traversal logic
- Declarative validation against common flow item types
- Per-node validation and state processing callbacks
--- doc/guides/prog_guide/ethdev/flow_graph.rst | 750 ++++++++++++++++++++ doc/guides/prog_guide/ethdev/index.rst | 1 + doc/guides/rel_notes/release_26_11.rst | 5 + lib/ethdev/flow_graph.c | 263 +++++++ lib/ethdev/flow_graph.h | 149 ++++ lib/ethdev/meson.build | 2 + 6 files changed, 1170 insertions(+) create mode 100644 doc/guides/prog_guide/ethdev/flow_graph.rst create mode 100644 lib/ethdev/flow_graph.c create mode 100644 lib/ethdev/flow_graph.h
doc/guides/prog_guide/ethdev/flow_graph.rst new file +750 -0
@@ -0,0 +1,750 @@ +.. SPDX-License-Identifier: BSD-3-Clause + Copyright(c) 2026 Intel Corporation + +Flow Graph Parser +================= + +Introduction +------------ + +The flow graph parser is a helper library for PMD drivers that implements ``rte_flow`` pattern matching. +It lets a driver declare the protocol sequences it supports as a directed graph of nodes and edges. +It then validates and extracts fields from an ``rte_flow_item`` pattern in a single traversal. + +The library is declared in ``flow_graph.h`` and built as part of ethdev. +It is an internal API, available to drivers only. +Parse diagnostics are logged at debug level using the ethdev log type. + +Scope and Limitations +~~~~~~~~~~~~~~~~~~~~~ + +Because the parser is graph-based, it is well suited for matching *protocol stacks*. +These are sequences of protocol headers such as ``ETH / IPv4 / TCP``. +Any pattern that can be expressed as "from protocol A, transitions to protocol B or C are allowed" fits naturally into the graph model. + +The library is **not** designed to cover every ``rte_flow`` item type. +Items that do not represent a position in a protocol stack do not have a natural place in a protocol graph. +This includes conntrack state, meter color, and other metadata items. +Such items are best handled outside the graph, either before or after the graph parse call. + +Defining a Graph +---------------- + +A graph consists of three parts: + +1. An **enum** that assigns a numeric index to every node. +2. A **node array** (``struct flow_graph_node[]``) indexed by that enum. +3. An **edge array** (``struct flow_graph_edge[]``) also indexed by that enum, describing allowed transitions. + +These parts are bundled together in a ``struct flow_graph``. + +The running example used throughout this guide models the following protocol graph:: + + START -> ETH -> [VLAN] -> (IPv4 | IPv6) -> [(TCP | UDP | SCTP)] -> END + +Brackets ``[...]`` denote optional items. +Parentheses ``(...)`` denote a required choice between alternatives. +The key ideas are: + +* ``ETH`` is required after ``START``. +* After ``ETH``, an optional ``VLAN`` may appear, but the pattern must then see an IP layer. +* After an IP layer, an optional transport layer may appear; it may be TCP, UDP, or SCTP, after which the pattern reaches ``END``. + +Node Enum +~~~~~~~~~ + +Every node needs a stable index. +The first node **must** be at index ``FLOW_GRAPH_NODE_FIRST`` (which is 0). +This is the *start node*. +It is used only as a traversal anchor and must not carry callbacks. + +.. code-block:: c + + enum example_node_id { + EXAMPLE_NODE_START = FLOW_GRAPH_NODE_FIRST, + EXAMPLE_NODE_ETH, + EXAMPLE_NODE_VLAN, + EXAMPLE_NODE_IPV4, + EXAMPLE_NODE_IPV6, + EXAMPLE_NODE_TCP, + EXAMPLE_NODE_UDP, + EXAMPLE_NODE_SCTP, + EXAMPLE_NODE_END, + /* keep last */ + EXAMPLE_NODE_MAX, + }; + +Node Definitions +~~~~~~~~~~~~~~~~ + +Each node maps to one ``rte_flow_item_type``. +It can also carry a *validate* callback, a *process* callback, and a set of *constraints*. +The the ``END`` node can also have callbacks to perform end-of-match processing. + +A minimal skeleton (callbacks and constraints are added in later sections): + +.. code-block:: c + + const struct flow_graph example_graph = { + .nodes = (struct flow_graph_node[]){ + [EXAMPLE_NODE_START] = { + .name = "START", + /* Start node: no type, no callbacks */ + }, + [EXAMPLE_NODE_ETH] = { + .name = "ETH", + .type = RTE_FLOW_ITEM_TYPE_ETH, + }, + [EXAMPLE_NODE_VLAN] = { + .name = "VLAN", + .type = RTE_FLOW_ITEM_TYPE_VLAN, + }, + [EXAMPLE_NODE_IPV4] = { + .name = "IPV4", + .type = RTE_FLOW_ITEM_TYPE_IPV4, + }, + [EXAMPLE_NODE_IPV6] = { + .name = "IPV6", + .type = RTE_FLOW_ITEM_TYPE_IPV6, + }, + [EXAMPLE_NODE_TCP] = { + .name = "TCP", + .type = RTE_FLOW_ITEM_TYPE_TCP, + }, + [EXAMPLE_NODE_UDP] = { + .name = "UDP", + .type = RTE_FLOW_ITEM_TYPE_UDP, + }, + [EXAMPLE_NODE_SCTP] = { + .name = "SCTP", + .type = RTE_FLOW_ITEM_TYPE_SCTP, + }, + [EXAMPLE_NODE_END] = { + .name = "END", + .type = RTE_FLOW_ITEM_TYPE_END, + }, + }, + }; + +Edge Definitions +~~~~~~~~~~~~~~~~ + +Edges express which nodes may follow the current one. +Every edge list is terminated by the ``FLOW_GRAPH_NODE_EDGE_END`` sentinel. +All non-``END`` nodes **must** have an edge list. +The ``END`` node itself does not need one. + +.. code-block:: c + + const struct flow_graph example_graph = { + .nodes = (struct flow_graph_node[]){ + /* ... same nodes as above ... */ + }, + .edges = (struct flow_graph_edge[]){ + [EXAMPLE_NODE_START] = { + .next = (size_t[]){ + EXAMPLE_NODE_ETH, + FLOW_GRAPH_NODE_EDGE_END, + }, + }, + [EXAMPLE_NODE_ETH] = { + .next = (size_t[]){ + EXAMPLE_NODE_VLAN, + EXAMPLE_NODE_IPV4, + EXAMPLE_NODE_IPV6, + FLOW_GRAPH_NODE_EDGE_END, + }, + }, + [EXAMPLE_NODE_VLAN] = { + .next = (size_t[]){ + EXAMPLE_NODE_IPV4, + EXAMPLE_NODE_IPV6, + FLOW_GRAPH_NODE_EDGE_END, + }, + }, + [EXAMPLE_NODE_IPV4] = { + .next = (size_t[]){ + EXAMPLE_NODE_TCP, + EXAMPLE_NODE_UDP, + EXAMPLE_NODE_SCTP, + EXAMPLE_NODE_END, + FLOW_GRAPH_NODE_EDGE_END, + }, + }, + [EXAMPLE_NODE_IPV6] = { + .next = (size_t[]){ + EXAMPLE_NODE_TCP, + EXAMPLE_NODE_UDP, + EXAMPLE_NODE_SCTP, + EXAMPLE_NODE_END, + FLOW_GRAPH_NODE_EDGE_END, + }, + }, + [EXAMPLE_NODE_TCP] = { + .next = (size_t[]){ + EXAMPLE_NODE_END, + FLOW_GRAPH_NODE_EDGE_END, + }, + }, + [EXAMPLE_NODE_UDP] = { + .next = (size_t[]){ + EXAMPLE_NODE_END, + FLOW_GRAPH_NODE_EDGE_END, + }, + }, + [EXAMPLE_NODE_SCTP] = { + .next = (size_t[]){ + EXAMPLE_NODE_END, + FLOW_GRAPH_NODE_EDGE_END, + }, + }, + }, + }; + +Reading the edges back: + +* From ``START``, the parser can only reach ``ETH``, which makes ``ETH`` required. +* From ``ETH``, the parser can reach ``VLAN``, ``IPV4``, or ``IPV6``, which makes ``VLAN`` optional. +* From ``IPV4`` or ``IPV6``, the parser can reach ``TCP``, ``UDP``, ``SCTP``, or ``END``, which makes the transport layer optional. + +Assembling the Graph +~~~~~~~~~~~~~~~~~~~~ + +With nodes and edges defined inline, assembling the graph is just a matter of +combining the two arrays into a single compound literal: + +.. code-block:: c + + const struct flow_graph example_graph = { + .nodes = (struct flow_graph_node[]){ + [EXAMPLE_NODE_START] = { + .name = "START" + }, + [EXAMPLE_NODE_ETH] = { + .name = "ETH", + .type = RTE_FLOW_ITEM_TYPE_ETH + }, + /* ... remaining nodes ... */ + [EXAMPLE_NODE_END] = { + .name = "END", + .type = RTE_FLOW_ITEM_TYPE_END + }, + }, + .edges = (struct flow_graph_edge[]){ + [EXAMPLE_NODE_START] = { + .next = (size_t[]){ + EXAMPLE_NODE_ETH, + FLOW_GRAPH_NODE_EDGE_END + } + }, + /* ... remaining edges ... */ + }, + }; + +Callbacks +--------- + +The graph calls up to two callbacks on every visited node: *validate* and *process*. + +Both callbacks share the same return convention. +On success they must return ``0``. +On failure they must call ``rte_flow_error_set`` to record a descriptive error and return its result. + +Validate Callback +~~~~~~~~~~~~~~~~~ + +.. code-block:: c + + typedef int (*flow_graph_node_validate_fn)( + const void *ctx, + const struct rte_flow_item *item, + struct rte_flow_error *error); + +This callback receives a **read-only** context pointer. +The canonical intent is that it should check whether the item's spec, mask, and last values are acceptable for the driver. +On failure it returns the result of ``rte_flow_error_set`` (see the return convention above). + +It is recommended to use this callback for **all checks that can reject a rule**. +This includes unsupported mask bits, conflicting field combinations, hardware limitations, and other applicable criteria. + +Process Callback +~~~~~~~~~~~~~~~~ + +.. code-block:: c + + typedef int (*flow_graph_node_process_fn)( + void *ctx, + const struct rte_flow_item *item, + struct rte_flow_error *error); + +This callback receives a **mutable** context pointer. +The canonical expectation is that it should extract the fields needed for hardware programming. +It should then store extracted data in the driver's context structure. +On the rare failure path it returns the result of ``rte_flow_error_set`` (see the return convention above). + +It is recommended to use this callback for the **happy path**. +For example, it can copy addresses, ports, and protocol IDs into the driver context so they can be programmed later. + +Defining a Context Structure +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The opaque ``ctx`` pointer passed to every callback is driver-defined. +A typical context accumulates the parsed protocol fields: + +.. code-block:: c + + struct example_parsed_flow { + /* L2 */ + struct rte_ether_addr dst_mac; + bool has_vlan; + uint16_t vlan_tci; + + /* L3 */ + bool is_ipv6; + rte_be32_t ipv4_src; + rte_be32_t ipv4_dst; + uint8_t ipv6_src[16]; + uint8_t ipv6_dst[16]; + + /* L4 */ + enum rte_flow_item_type l4_proto; + rte_be16_t src_port; + rte_be16_t dst_port; + }; + +These fields are meant to reflect the structure used by the driver to programming hardware with. + +Callback Example +~~~~~~~~~~~~~~~~ + +Below is a validate/process pair for the IPv4 node. +The validate callback rejects unsupported mask bits. +The process callback copies addresses into the context: + +.. code-block:: c + + static int + example_validate_ipv4(const void *ctx __rte_unused, + const struct rte_flow_item *item, + struct rte_flow_error *error) + { + const struct rte_flow_item_ipv4 *mask = item->mask; + + /* spec is guaranteed by node constraints, mask may be NULL */ + if (mask == NULL) + rte_flow_conv(RTE_FLOW_CONV_OP_ITEM_DEFAULT_MASK_PTR, &mask, sizeof(mask), + (const void *)(uintptr_t)item->type, NULL); + + if (mask->hdr.version_ihl || + mask->hdr.type_of_service || + mask->hdr.total_length || + mask->hdr.packet_id || + mask->hdr.fragment_offset || + mask->hdr.time_to_live || + mask->hdr.next_proto_id || + mask->hdr.hdr_checksum) { + return rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, item, + "Only src/dst addresses supported"); + } + return 0; + } + + static int + example_process_ipv4(void *ctx, + const struct rte_flow_item *item, + struct rte_flow_error *error __rte_unused) + { + struct example_parsed_flow *parsed = ctx; + const struct rte_flow_item_ipv4 *spec = item->spec; + + parsed->is_ipv6 = false; + if (spec != NULL) { + parsed->ipv4_src = spec->hdr.src_addr; + parsed->ipv4_dst = spec->hdr.dst_addr; + } + return 0; + } + +Add the callbacks to the node definition: + +.. code-block:: c + + [EXAMPLE_NODE_IPV4] = { + .name = "IPV4", + .type = RTE_FLOW_ITEM_TYPE_IPV4, + .validate = example_validate_ipv4, + .process = example_process_ipv4, + }, + +Node Constraints +---------------- + +Many nodes share common requirements about which combination of ``spec``, ``mask``, and ``last`` pointers an item must carry. +Instead of checking these in every validate callback, they can be declared via the ``constraints`` field. +The field uses ``flow_graph_node_expect`` flags. + +Available constraint flags (may be ORed together): + +``FLOW_GRAPH_NODE_EXPECT_NONE`` + Default. Any valid combination is accepted (empty, spec with optional mask, + or spec and last with optional mask). + +``FLOW_GRAPH_NODE_EXPECT_EMPTY`` + The item must have ``spec == NULL``, ``mask == NULL``, and + ``last == NULL``. + +``FLOW_GRAPH_NODE_EXPECT_SPEC`` + ``spec`` is required, ``mask`` is optional; ``last`` must be NULL. + +``FLOW_GRAPH_NODE_EXPECT_RANGE`` + ``spec`` and ``last`` are required, ``mask`` is optional. + +Items that are invalid per the rte_flow API (``mask`` or ``last`` without ``spec``) +are always rejected, regardless of node constraints. +When ``spec`` is set but ``mask`` is NULL, the item type's default mask applies +(see ``RTE_FLOW_CONV_OP_ITEM_DEFAULT_MASK_PTR``). + +Multiple flags can be ORed together. +The item is accepted if **any one** of the flagged constraints is satisfied. +The purpose is to express the difference between "must" (i.e. accept ONLY this), and "may" (i.e. accept this OR that). + +For example, an IPv4 node that requires a spec, with or without an explicit mask: + +.. code-block:: c + + [EXAMPLE_NODE_IPV4] = { + .name = "IPV4", + .type = RTE_FLOW_ITEM_TYPE_IPV4, + .validate = example_validate_ipv4, + .process = example_process_ipv4, + .constraints = FLOW_GRAPH_NODE_EXPECT_SPEC, + }, + +An Ethernet node that may appear empty (no spec/mask) or with spec+mask: + +.. code-block:: c + + [EXAMPLE_NODE_ETH] = { + .name = "ETH", + .type = RTE_FLOW_ITEM_TYPE_ETH, + .validate = example_validate_eth, + .process = example_process_eth, + .constraints = FLOW_GRAPH_NODE_EXPECT_EMPTY | + FLOW_GRAPH_NODE_EXPECT_SPEC, + }, + +Constraints are checked **before** the validate callback is invoked. + +Ignoring Item Types +~~~~~~~~~~~~~~~~~~~ + +The ``ignore_nodes`` field on ``struct flow_graph`` is an optional complement to node constraints. +When the pattern may contain item types that are irrelevant to the driver, list them in ``ignore_nodes``. +For example, metadata items like ``RTE_FLOW_ITEM_TYPE_MARK`` do not represent a protocol header. +The parser skips ignored items silently without advancing the current graph position: + +.. code-block:: c + + const struct flow_graph example_graph = { + /* ... nodes and edges ... */ + .ignore_nodes = (enum rte_flow_item_type[]){ + RTE_FLOW_ITEM_TYPE_MARK, + RTE_FLOW_ITEM_TYPE_END, + }, + }; + +``RTE_FLOW_ITEM_TYPE_VOID`` is always ignored regardless of this list. +Omit ``ignore_nodes`` entirely when no additional item types need to be skipped. + +Calling the Parser +------------------ + +``flow_graph_parse`` walks the pattern against the graph: + +.. code-block:: c + + int + flow_graph_parse(const struct flow_graph *graph, + const struct rte_flow_item *pattern, + struct rte_flow_error *error, + void *ctx); + +A typical call site looks like this: + +.. code-block:: c + + struct example_parsed_flow parsed; + int ret; + + memset(&parsed, 0, sizeof(parsed)); + + ret = flow_graph_parse(&example_graph, pattern, error, &parsed); + if (ret != 0) + return ret; + + /* 'parsed' now contains the extracted protocol fields */ + +The function returns success or failure, with ``error`` populated. + +Error conditions: + +* **Graph is NULL** — for example, when the graph pointer itself is not provided. +* **Pattern is NULL**. +* **Unsupported transition** — when an item type has no matching edge from the current node. + This is the primary way the graph rejects unsupported protocol sequences. +* **Constraint failure** — when the spec, mask, and last combination does not satisfy the node's declared constraints. +* **Validate callback failure** — when driver-specific validation rejects the item. +* **Process callback failure** — when driver-specific extraction path fails. + +.. warning:: + + Malformed graph tables (for example invalid node indices, missing sentinels, + or otherwise inconsistent driver-defined graph structures) are considered to be a driver implementation bug. + Graphs are trusted by default: driver-owned graph structures are expected to be valid and are not fully validated. + +The traversal processes items in order, skipping ignored types. +After the last non-``END`` item, the parser looks for an ``END`` node reachable from the current position. +It then visits that node and runs its callbacks, if any. +This means drivers can attach a process callback to the ``END`` node for post-traversal finalization. + +Putting It All Together +----------------------- + +The complete graph definition with callbacks and constraints: + +.. code-block:: c + + const struct flow_graph example_graph = { + .nodes = (struct flow_graph_node[]){ + [EXAMPLE_NODE_START] = { + .name = "START", + }, + [EXAMPLE_NODE_ETH] = { + .name = "ETH", + .type = RTE_FLOW_ITEM_TYPE_ETH, + .validate = example_validate_eth, + .process = example_process_eth, + .constraints = FLOW_GRAPH_NODE_EXPECT_EMPTY + | FLOW_GRAPH_NODE_EXPECT_SPEC, + }, + [EXAMPLE_NODE_VLAN] = { + .name = "VLAN", + .type = RTE_FLOW_ITEM_TYPE_VLAN, + .process = example_process_vlan, + .constraints = FLOW_GRAPH_NODE_EXPECT_SPEC, + }, + [EXAMPLE_NODE_IPV4] = { + .name = "IPV4", + .type = RTE_FLOW_ITEM_TYPE_IPV4, + .validate = example_validate_ipv4, + .process = example_process_ipv4, + .constraints = FLOW_GRAPH_NODE_EXPECT_SPEC, + }, + [EXAMPLE_NODE_IPV6] = { + .name = "IPV6", + .type = RTE_FLOW_ITEM_TYPE_IPV6, + .validate = example_validate_ipv6, + .process = example_process_ipv6, + .constraints = FLOW_GRAPH_NODE_EXPECT_SPEC, + }, + [EXAMPLE_NODE_TCP] = { + .name = "TCP", + .type = RTE_FLOW_ITEM_TYPE_TCP, + .validate = example_validate_tcp, + .process = example_process_tcp, + .constraints = FLOW_GRAPH_NODE_EXPECT_SPEC, + }, + [EXAMPLE_NODE_UDP] = { + .name = "UDP", + .type = RTE_FLOW_ITEM_TYPE_UDP, + .validate = example_validate_udp, + .process = example_process_udp, + .constraints = FLOW_GRAPH_NODE_EXPECT_SPEC, + }, + [EXAMPLE_NODE_SCTP] = { + .name = "SCTP", + .type = RTE_FLOW_ITEM_TYPE_SCTP, + .process = example_process_sctp, + .constraints = FLOW_GRAPH_NODE_EXPECT_EMPTY + | FLOW_GRAPH_NODE_EXPECT_SPEC, + }, + [EXAMPLE_NODE_END] = { + .name = "END", + .type = RTE_FLOW_ITEM_TYPE_END, + }, + }, + .edges = (struct flow_graph_edge[]){ + [EXAMPLE_NODE_START] = { + .next = (size_t[]){ + EXAMPLE_NODE_ETH, + FLOW_GRAPH_NODE_EDGE_END, + }, + }, + [EXAMPLE_NODE_ETH] = { + .next = (size_t[]){ + EXAMPLE_NODE_VLAN, + EXAMPLE_NODE_IPV4, + EXAMPLE_NODE_IPV6, + FLOW_GRAPH_NODE_EDGE_END, + }, + }, + [EXAMPLE_NODE_VLAN] = { + .next = (size_t[]){ + EXAMPLE_NODE_IPV4, + EXAMPLE_NODE_IPV6, + FLOW_GRAPH_NODE_EDGE_END, + }, + }, + [EXAMPLE_NODE_IPV4] = { + .next = (size_t[]){ + EXAMPLE_NODE_TCP, + EXAMPLE_NODE_UDP, + EXAMPLE_NODE_SCTP, + EXAMPLE_NODE_END, + FLOW_GRAPH_NODE_EDGE_END, + }, + }, + [EXAMPLE_NODE_IPV6] = { + .next = (size_t[]){ + EXAMPLE_NODE_TCP, + EXAMPLE_NODE_UDP, + EXAMPLE_NODE_SCTP, + EXAMPLE_NODE_END, + FLOW_GRAPH_NODE_EDGE_END, + }, + }, + [EXAMPLE_NODE_TCP] = { + .next = (size_t[]){ + EXAMPLE_NODE_END, + FLOW_GRAPH_NODE_EDGE_END, + }, + }, + [EXAMPLE_NODE_UDP] = { + .next = (size_t[]){ + EXAMPLE_NODE_END, + FLOW_GRAPH_NODE_EDGE_END, + }, + }, + [EXAMPLE_NODE_SCTP] = { + .next = (size_t[]){ + EXAMPLE_NODE_END, + FLOW_GRAPH_NODE_EDGE_END, + }, + }, + }, + }; + + +Tunnel Graphs and Repeated Item Types +------------------------------------- + +Tunneled patterns often repeat the same ``rte_flow_item_type`` in outer and inner headers. +A simple representative example is a TCP-IPv4 over GTP-U pattern:: + + ETH -> IPV4 -> UDP -> GTPU -> IPV4 -> TCP + +The graph library supports this naturally. +Multiple nodes may use the same ``type`` value, as long as they are distinct nodes in the graph and reached through different edges. + +For tunnel parsing, the recommended style is to model repeated protocol types as separate inner/outer nodes, for example ``OUTER_IPV4`` and ``INNER_IPV4``. +This makes the graph intent explicit, keeps callback logic clear, and avoids unexpected graph paths due to loops. + +.. code-block:: c + + enum tunnel_node_id { + TUNNEL_NODE_START = FLOW_GRAPH_NODE_FIRST, + TUNNEL_NODE_ETH, + TUNNEL_NODE_OUTER_IPV4, + TUNNEL_NODE_TCP, + TUNNEL_NODE_UDP, + TUNNEL_NODE_GTPU, + TUNNEL_NODE_INNER_IPV4, + TUNNEL_NODE_END, + TUNNEL_NODE_MAX, + }; + + const struct flow_graph tunnel_graph = { + .nodes = (struct flow_graph_node[]){ + /* Minimal topology example: callbacks and constraints are omitted. */ + [TUNNEL_NODE_START] = { .name = "START" }, + [TUNNEL_NODE_ETH] = { + .name = "ETH", + .type = RTE_FLOW_ITEM_TYPE_ETH, + }, + [TUNNEL_NODE_OUTER_IPV4] = { + .name = "OUTER_IPV4", + .type = RTE_FLOW_ITEM_TYPE_IPV4, + }, + [TUNNEL_NODE_UDP] = { + .name = "UDP", + .type = RTE_FLOW_ITEM_TYPE_UDP, + }, + [TUNNEL_NODE_GTPU] = { + .name = "GTPU", + .type = RTE_FLOW_ITEM_TYPE_GTPU, + }, + [TUNNEL_NODE_INNER_IPV4] = { + .name = "INNER_IPV4", + .type = RTE_FLOW_ITEM_TYPE_IPV4, + }, + [TUNNEL_NODE_TCP] = { + .name = "TCP", + .type = RTE_FLOW_ITEM_TYPE_TCP, + }, + [TUNNEL_NODE_END] = { + .name = "END", + .type = RTE_FLOW_ITEM_TYPE_END, + }, + }, + .edges = (struct flow_graph_edge[]){ + [TUNNEL_NODE_START] = { + .next = (size_t[]){ + TUNNEL_NODE_ETH, + FLOW_GRAPH_NODE_EDGE_END, + }, + }, + [TUNNEL_NODE_ETH] = { + .next = (size_t[]){ + TUNNEL_NODE_OUTER_IPV4, + FLOW_GRAPH_NODE_EDGE_END, + }, + }, + [TUNNEL_NODE_OUTER_IPV4] = { + .next = (size_t[]){ + TUNNEL_NODE_UDP, + FLOW_GRAPH_NODE_EDGE_END, + }, + }, + [TUNNEL_NODE_UDP] = { + .next = (size_t[]){ + TUNNEL_NODE_GTPU, + FLOW_GRAPH_NODE_EDGE_END, + }, + }, + [TUNNEL_NODE_GTPU] = { + .next = (size_t[]){ + TUNNEL_NODE_INNER_IPV4, + FLOW_GRAPH_NODE_EDGE_END, + }, + }, + [TUNNEL_NODE_INNER_IPV4] = { + .next = (size_t[]){ + TUNNEL_NODE_TCP, + FLOW_GRAPH_NODE_EDGE_END, + }, + }, + [TUNNEL_NODE_TCP] = { + .next = (size_t[]){ + TUNNEL_NODE_END, + FLOW_GRAPH_NODE_EDGE_END, + }, + }, + }, + }; + +In other words, traversal follows graph edges (node-to-node), while node matching is done against each candidate node's ``rte_flow_item_type``. +That combination allows repeated protocol layers to be represented cleanly with separate nodes for different parsing contexts. + +Although arbitrary loops are possible in the graph, tunnel protocol graphs are usually easier to reason about when repeated item types are split into explicit inner/outer nodes. +It is not recommended to create loops in the graph, as these loops will be unbounded.
doc/guides/prog_guide/ethdev/index.rst +1 -0
@@ -10,6 +10,7 @@ Ethernet Device Library ethdev switch_representation flow_offload + flow_graph traffic_metering_and_policing traffic_management qos_framework
doc/guides/rel_notes/release_26_11.rst +5 -0
@@ -69,6 +69,11 @@ New Features Added ``RTE_FLOW_CONV_OP_ITEM_DEFAULT_MASK_PTR`` conversion operation to ``rte_flow_conv()`` to retrieve the default mask of a flow item type. +* **Added internal ethdev flow graph parser helper API.** + + Added internal ``flow_graph`` API in ethdev + for PMD drivers to build graph-based flow pattern parsers. + * **Updated AF_XDP driver.** * Changed the default device plugin endpoint path used when
lib/ethdev/flow_graph.c new file +263 -0
263 lines not on this page · raw message
lib/ethdev/flow_graph.h new file +149 -0
149 lines not on this page · raw message
lib/ethdev/meson.build +2 -0
@@ -6,6 +6,7 @@ sources = files( 'ethdev_private.c', 'ethdev_profile.c', 'ethdev_trace_points.c', + 'flow_graph.c', 'rte_class_eth.c', 'rte_ethdev.c', 'rte_ethdev_cman.c',
@@ -40,6 +41,7 @@ driver_sdk_headers += files( 'ethdev_pci.h', 'ethdev_vdev.h', 'rte_flow_driver.h', + 'flow_graph.h', 'rte_mtr_driver.h', 'rte_tm_driver.h', )
Signature · 1 line
2.52.0
PATCH v5 3/25 net/intel/common: add flow engines infrastructure
In reply to Anatoly BurakovCurrent implementation of flow engines in various drivers have a few issues that need to be corrected.
For one, some of them are fundamentally incompatible with secondary processes, because the flow engine registration and creation will allocate structures in shared memory but use process-local pointers to point to flow engines and pattern tables.
For another, a lot of them are needlessly complicated and rely on a separation between patterns and parsing that is hard to reason about and
maintain: they do not define memory ownership model, they do not define the way in which we approach parameter and pattern parsing, and they occasionally do weird things like passing around pointers-to-void-pointers or even using pointers as integer values.
Another common problem is extremely convoluted internal tracking, flow installation, flow replay, and cleanup code. This infrastructure is usually done in an ad-hoc manner that has a lot of boilerplate.
These issues can be corrected, but because of how much code there is to the current infrastructure and how tightly coupled it is, it would be easier to just build new one from scratch, and gradually migrate all engines to use it. This patch is intended as a first step towards that goal, and defines both common data types to be used by all rte_flow parsers, as well as the interaction model that is to be followed by all drivers.
We define a set of structures that will represent:
- Defined rte_flow parsing interaction model and code flow (ops struct)
- Defined memory allocation and ownership model for all engines
- Scratch space format for all engines (variably allocated typed struct)
- Flow rule format for all engines (variably allocated typed struct)
- Engine definitions that are compatible with secondary process model
- Implementations of common rte_flow operations
- Various supporting infrastructure for parser customization, e.g. hooks
- Support for using custom allocation (e.g. for mempool-based alloc)
- Support for replaying all flows to restore HW state
- Support for removing all flows without modifying HW state
The design intent is heavily documented right inside the header and is to be considered authoritative design document for how to build rte_flow parsers for Intel Ethernet drivers going forward.
--- drivers/net/intel/common/flow_engine.h | 1429 ++++++++++++++++++++++++ 1 file changed, 1429 insertions(+) create mode 100644 drivers/net/intel/common/flow_engine.h
drivers/net/intel/common/flow_engine.h new file +1429 -0
@@ -0,0 +1,1429 @@ +/* SPDX-License-Identifier: BSD-3-Clause +* Copyright(c) 2026 Intel Corporation +*/ + +#ifndef _COMMON_INTEL_FLOW_ENGINE_H_ +#define _COMMON_INTEL_FLOW_ENGINE_H_ + +#include <stddef.h> +#include <stdio.h> +#include <sys/queue.h> + +#include <rte_bitops.h> +#include <rte_errno.h> +#include <rte_malloc.h> + +#include <ethdev_driver.h> +#include <rte_flow.h> +#include <flow_graph.h> +#include <rte_tailq.h> +#include <rte_rwlock.h> +#include <rte_hexdump.h> + +#include "log.h" + +/* +* This is a common header for Intel Ethernet drivers' flow engine +* implementations. It defines the interfaces and data structures required to +* implement flow rule engines that plug into the drivers' flow handling logic. +* +* Design considerations: +* +* 1. Ease of implementation +* +* The flow engine interface is kept simple, with obvious defaults (not +* specifying something leads to the most expected behavior in context). The +* point is not to produce a monstrous driver-within-a-driver framework, but to +* make engine definitions follow semantic expectations of what the engine does. +* +* All boilerplate (flow management, engine enablement tracking, etc.) is +* handled by the common flow infrastructure, so an engine only needs to parse +* and install/uninstall flow rules. Drivers are expected to use other common +* flow utilities where applicable (e.g. flow_util.h, flow_check.h). +* +* 2. Full secondary process compatibility +* +* To support rte_flow operations in secondary processes, the engines enabled +* for a driver instance are tracked and resolved at runtime. The engine index +* (its position in the engine list) is used as a bit position in a +* driver-specific 64-bit field of enabled engines, so engine definitions can +* live in read-only memory shared by primary and secondary processes. For this +* to be safe, engine lists and definitions must be immutable for process +* lifetime (declare them as const). +* +* This does not mean every driver supports rte_flow in secondary processes - +* that is still up to each driver. It only ensures the framework itself does not +* prevent it. +* +* Engine callbacks must not access or retain a `struct rte_eth_dev *`, as it is +* process-local; use the process-independent `struct rte_eth_dev_data *` +* provided by the framework instead. +* +* The per-instance engine configuration is set up and torn down exclusively by +* `ci_flow_engine_conf_init()` and `ci_flow_engine_conf_reset()`, which should +* only be called by the primary process at device setup/teardown. +* +* 3. Flow object lifecycle is framework-owned +* +* Engines should treat framework-provided context and flow objects as storage +* they fill in, not storage they own: engine logic focuses on the contents of +* flow data, while object lifetime is managed by the framework. Engines may +* still allocate auxiliary data, but only where the framework guarantees a +* matching teardown call that lets the engine release it. +* +* 4. Pattern parsing: flow_graph and pattern_parse callback +* +* The flow engine framework works hand-in-hand with the `flow_graph` parsing +* infrastructure. Each engine may provide a pattern graph that is used to match +* the flow pattern and extract relevant data into the engine context provided +* by the framework. +* +* Engines may also provide a `pattern_parse` callback that is invoked before +* the graph parser runs. This allows engines to handle pattern items that don't +* fit neatly into the graph model (e.g. FUZZY items that can appear at any +* position), or to bypass the graph parser entirely with custom parsing. +* +* Pattern contents cannot be ignored. This is by design, as ignoring them is +* considered rte_flow API misuse. By default, even in the empty fallback case, +* a meaningful pattern (one that is not empty or ANY) is treated as an error. +* +* 5. Setup, teardown, and flow list lifecycle ordering +* +* The expected sequence of calls for a driver instance is: +* +* - `ci_flow_engine_conf_init()` should run from the driver's `dev_init` path. +* +* - At `dev_close`, `ci_flow_cleanup()` should run first to drop all flows and +* their internal tracking, followed by `ci_flow_engine_conf_reset()`. +* +* - Devices may or may not advertise `RTE_ETH_DEV_CAPA_FLOW_RULE_KEEP`, i.e. +* support for keeping flow rules across a `dev_stop`/`dev_start` cycle. +* +* - If the device does not advertise this capability, flows must be flushed +* via `ci_flow_flush()` as the first step of `dev_stop()` (flushing later +* may interfere with flow uninstall). +* +* - If the flows are kept but device loses its hardware state across a +* `dev_stop`/`dev_start` cycle, the driver should call `ci_flow_replay()` as +* the last step of `dev_start`. +*/ + +struct ci_flow_engine_ops ; +struct ci_flow_engine_ctx ; +struct ci_flow_engine ; +struct ci_flow_engine_ref ; +struct ci_flow_engine_list ; +struct ci_flow_engine_conf ; +struct ci_flow ; + +/* +* Flow engine ops. +* +* Each flow engine provides a set of operations that make up the flow engine +* pipeline. Each stage has a setup step (run when a flow is created) and, +* where applicable, a teardown step (run when a flow is removed). Operations +* are compositions of stages: setup steps run in forward order, teardown steps +* in reverse. Optional callbacks are shown in [brackets]. +* +* - Allocation stage +* setup: [flow_alloc] teardown: [flow_free] +* Engine-specific flow object allocation. Skipped on the validate path. +* +* - Parse stage +* setup: ctx_init -> [pattern_parse] -> [graph parser] -> +* [ctx_finalize] -> [ctx_to_flow] +* teardown: (none) +* Interprets the request into the flow structure. Must NOT allocate. +* +* - Track stage +* setup: [flow_register] teardown: [flow_unregister] +* Updates driver-internal state. Permitted to allocate. +* +* - Apply stage +* setup: [flow_install] teardown: [flow_uninstall] +* Programs the hardware. Must NOT allocate. +* +* Typical operation sequences: +* +* - rte_flow_create: Allocation -> Parse -> Track -> Apply (setup) +* - rte_flow_validate: Parse +* - rte_flow_destroy: Apply -> Track -> Allocation (teardown) +* - rte_flow_flush: Apply -> Track -> Allocation (teardown, per flow) +* - ci_flow_replay: Apply (setup, per flow) +* - ci_flow_cleanup: Track -> Allocation (teardown, per flow) +* +* 1) Engine availability and lifecycle +* +* Availability is checked by the driver at init time. The criteria are up to +* the driver (hardware capability bits, PHY type, devargs, etc.). If +* `engine_init` is not implemented, the engine is always available. +* +* If `priv_size` is non-zero, the framework allocates a zeroed private block +* and passes it to engine_init/engine_uninit. Each allocated flow also carries +* a pointer to this per-device data in `flow->engine_priv`. +* +* 2) Input parsing +* +* `ctx_init` is mandatory and is the gateway for processing actions and +* attributes into engine context. +* +* Patterns are matched against the pattern graph in `ci_flow_engine`, the +* `pattern_parse` callback, or both: +* +* - graph only: graph parser runs +* - callback only: pattern_parse runs +* - callback + graph: pattern_parse runs, then graph parser runs +* - neither: empty fallback matcher is used +* +* The empty fallback matcher accepts only a NULL pattern, an empty pattern +* (start -> end), or an ANY-only pattern (start -> any -> end). +* +* In callback + graph mode, the callback does not consume items: the graph +* parser sees the same pattern, so the graph should list the relevant +* `ignore_nodes`. +* +* 3) Rule finalization +* +* `ctx_finalize` is an optional final consistency check between parsed +* action/attribute data and pattern-derived data, and a place for any other +* post-parse work. +* +* 4) Rule materialization +* +* `ctx_to_flow` translates the parsed context into the engine-specific flow +* rule. The rule should contain only what is needed for installation or +* querying; temporary data belongs in the build context. +* +* 5) Rule lifecycle hooks +* +* `flow_alloc`/`flow_free` are optional. If `flow_alloc` is absent or returns +* NULL, the framework falls back to rte_zmalloc. `flow_free` is required if +* `flow_alloc` is provided. +* +* `flow_register`/`flow_unregister` (Track) and `flow_install`/`flow_uninstall` +* (Apply) are optional. Register/unregister must be both defined or both NULL. +* +* Engines own only engine-specific fields. Common `ci_flow` fields (engine_idx, +* engine_priv, fallback_alloc, etc.) belong to the framework and must not be +* modified. +* +* IMPORTANT: by the time Track and Apply run, the engine has already accepted +* the flow. A failure in `flow_register` or `flow_install` (e.g. resource +* exhaustion) is a hard failure: no other engines are tried. Any check +* intrinsic to the pattern that would prevent tracking or installation must +* therefore be done at the parse stage. +* +* 6) Memory ownership and allocation policy +* +* An engine may allocate in exactly three places: +* +* - engine init: engine-wide resources used by other callbacks (e.g. a mempool +* from which `flow_alloc` takes flow objects) +* - flow alloc: memory for the flow itself (e.g. a mempool object), plus +* allocator-associated bookkeeping. It must not produce anything the parse +* stage depends on, because `rte_flow_validate()` bypasses `flow_alloc`. +* - flow register: the only per-flow callback that may allocate memory and +* store the pointer in the flow object or driver-internal structures. This is +* where "parsing the flow" ends and "updating driver state" begins. +* +* Parse callbacks (`ctx_init`, `pattern_parse`, `ctx_finalize`, `ctx_to_flow`) +* and `flow_install` must not allocate. These steps may fail with no +* teardown. +* +* 7) Flow query +* +* `flow_query` is optional. If not provided, querying the rule fails. +* +* 8) Concurrency model +* +* The framework serializes access to each driver instance's flow state with a +* single rwlock. Create, destroy and flush take it exclusively; validate and +* query take it shared. Parse callbacks (ctx_init, pattern_parse, +* ctx_finalize, ctx_to_flow) can therefore run concurrently on the validate +* path, as can flow_query, and must treat shared engine state (including +* engine_priv) as read-only. State mutation belongs in the write-locked +* callbacks (engine_init/engine_uninit, flow_alloc/flow_free, +* flow_register/flow_unregister, flow_install/flow_uninstall). +*/ +struct ci_flow_engine_ops { +/* engine init callback - can be NULL */ +int (*engine_init)(const struct ci_flow_engine *engine, +struct rte_eth_dev_data *dev_data, +void *priv); +/* engine uninit callback - can be NULL */ +void (*engine_uninit)(const struct ci_flow_engine *engine, +void *priv); +/* allocation callback for flow rules - can be NULL */ +struct ci_flow *(*flow_alloc)(const struct ci_flow_engine *engine, +struct rte_eth_dev_data *dev_data, +void *priv); +/* deallocation callback for flow rules - can be NULL */ +void (*flow_free)(struct ci_flow *flow, +struct rte_eth_dev_data *dev_data, +void *priv); +/* initialize engine context from flow attr/actions - mandatory */ +int (*ctx_init)(const struct rte_flow_action actions[], +const struct rte_flow_attr *attr, +struct ci_flow_engine_ctx *ctx, +struct rte_flow_error *error); +/* pattern parsing callback - can be NULL */ +int (*pattern_parse)(struct ci_flow_engine_ctx *ctx, +const struct rte_flow_item pattern[], +struct rte_flow_error *error); +/* final pass before converting context to flow - can be NULL */ +int (*ctx_finalize)(struct ci_flow_engine_ctx *ctx, +struct rte_flow_error *error); +/* initialize flow rule from parsed context - can be NULL */ +int (*ctx_to_flow)(const struct ci_flow_engine_ctx *ctx, +struct ci_flow *flow, +struct rte_flow_error *error); +/* track a flow rule in driver-internal state - can be NULL */ +int (*flow_register)(struct ci_flow *flow, +struct rte_flow_error *error); +/* untrack a flow rule from driver-internal state - can be NULL */ +int (*flow_unregister)(struct ci_flow *flow, +struct rte_flow_error *error); +/* install a flow rule to hardware - can be NULL */ +int (*flow_install)(struct ci_flow *flow, +struct rte_flow_error *error); +/* uninstall a flow rule from hardware - can be NULL */ +int (*flow_uninstall)(struct ci_flow *flow, +struct rte_flow_error *error); +/* query flow - can be NULL */ +int (*flow_query)(struct ci_flow *flow, +const struct rte_flow_action *action, +void *data, +struct rte_flow_error *error); +}; + +/* base parse context; engine contexts must start with this struct */ +struct ci_flow_engine_ctx { +/* ethernet device this context belongs to */ +struct rte_eth_dev_data *dev_data; +/* per-engine private data, same pointer as flow->engine_priv */ +void *engine_priv; +/* original flow attributes, as passed by the caller */ +const struct rte_flow_attr *attr; +/* original flow pattern, as passed by the caller */ +const struct rte_flow_item *pattern; +/* original flow actions, as passed by the caller */ +const struct rte_flow_action *actions; +}; + +/* +* Common definition for flow rules. +* +* A flow rule has three layers of data: +* +* 1) Common data (`ci_flow`, defined here) +* 2) Driver-specific data +* 3) Engine-specific data +* +* `ci_flow` holds the fields common to all drivers and engines. Some are used +* internally by the framework (e.g. list linkage), others are provided as a +* basic service for engines' convenience (e.g. a reference to the owning +* device). +* +* Each driver defines its own `rte_flow` structure, which must start with +* `ci_flow`, followed by driver-specific fields. Each engine may in turn define +* its own flow structure, which must start with the driver's `rte_flow`, +* followed by engine-specific fields. +* +* IMPORTANT: +* +* All of these structures are referred to by the same pointer and can be safely +* cast between each other *as long as* each one has its parent structure as its +* first member: +* +* struct rte_flow { +* struct ci_flow base; +* ...driver-specific fields... +* }; +* +* struct ixgbe_fdir_flow { +* struct rte_flow base; +* ...engine-specific fields... +* }; +* +* struct ci_flow *flow = ...; +* struct rte_flow *rte_flow = (struct rte_flow *)flow; +* struct ixgbe_fdir_flow *es_flow = (struct ixgbe_fdir_flow *)flow; +* +* Each engine provides a `flow_size` field giving the memory required for its +* flow structure. The driver must set it for every engine, as it is used to size +* flow allocations. An engine that needs nothing beyond the driver's `rte_flow` +* should use `sizeof(struct rte_flow)`. +* +* Engine references and engine_idx: +* +* Every flow stores its engine index as the engine type discriminator. Runtime +* code rebuilds a `ci_flow_engine_ref` (engine pointer + index) from the +* immutable engine list and this index. This means: +* +* - The framework only ever works with immutable engine definitions/lists. +* - No pointer-to-index lookups are needed after flow creation. +* - Secondary processes work correctly: the index is the stable identity, while +* pointer values are only meaningful within the shared immutable engine list. +* +* Treat engine references as the basic building block when handling engine +* pointers and indices. +* +* Per-engine private data (engine_priv): +* +* Each flow carries a pointer to engine-private data, such as custom allocation +* structures used with flow_alloc/flow_free. +* +* Fallback allocation: +* +* If a driver-provided `flow_alloc` returns NULL, the framework falls back to +* rte_zmalloc(). The `fallback_alloc` flag then routes deallocation to +* rte_free(). Consequently, `flow_alloc` returning NULL is *not* treated as an +* error. +*/ +struct ci_flow { +/* linkage in the per-device flow list */ +TAILQ_ENTRY (ci_flow) node; +/* device this flow belongs to */ +struct rte_eth_dev_data *dev_data; +/* index of engine this flow was created by */ +size_t engine_idx; +/* per-engine private data pointer, set by the framework at alloc time */ +void *engine_priv; +/* set if flow_alloc returned NULL and rte_zmalloc() was used instead */ +bool fallback_alloc; +}; + +/* flow engine definition */ +struct ci_flow_engine { +/* engine name */ +const char *name; +/* size of engine parse context, can be omitted */ +size_t ctx_size; +/* size of engine flow struct, at least sizeof(struct ci_flow) */ +size_t flow_size; +/* size of per-device engine private data, can be omitted */ +size_t priv_size; +/* ops for this flow engine */ +const struct ci_flow_engine_ops *ops; +/* pattern graph this engine supports, can be omitted */ +const struct flow_graph *graph; +}; + +/* engine reference: immutable engine pointer paired with its list index */ +struct ci_flow_engine_ref { +/* engine definition */ +const struct ci_flow_engine *engine; +/* index of the engine in the driver's engine list */ +size_t engine_idx; +}; + +#define CI_FLOW_ENGINE_MAX 64 + +/* flow engine list definition */ +struct ci_flow_engine_list { +/* NULL-terminated immutable array of flow engine pointers */ +const struct ci_flow_engine *const engines[CI_FLOW_ENGINE_MAX ]; +}; + +/* per-device engine configuration */ +struct ci_flow_engine_conf { +/* lock protecting the config and the flow list */ +rte_rwlock_t config_lock; +/* list of flows created on this device */ + TAILQ_HEAD(ci_flow_list, ci_flow) flows; +/* bitmask of enabled engines, bit N set if engine at index N is enabled */ +uint64_t enabled_engines; +/* back-reference to device data */ +struct rte_eth_dev_data *dev_data; +/* reference to the driver's engine list */ +const struct ci_flow_engine_list *engines; +/* per-engine private data pointers, indexed by engine index */ +void *engine_priv[CI_FLOW_ENGINE_MAX ]; +}; + +/* caller must hold config lock */ +static inline struct ci_flow_engine_ref +ci_flow_engine_ref_from_idx (const struct ci_flow_engine_conf *engine_conf, +const size_t engine_idx) +{ +/* check if valid reference can be constructed at all */ +if (engine_conf ==NULL || engine_conf->engines ==NULL || + engine_idx >=CI_FLOW_ENGINE_MAX ) { +return (struct ci_flow_engine_ref ) { + .engine =NULL , + .engine_idx =CI_FLOW_ENGINE_MAX + }; + } +/* the inputs are valid, but there may be no engine */ +if (engine_conf->engines->engines[engine_idx] ==NULL ) { +return (struct ci_flow_engine_ref ) { + .engine =NULL , + .engine_idx =CI_FLOW_ENGINE_MAX + }; + } + +return (struct ci_flow_engine_ref ) { + .engine = engine_conf->engines->engines[engine_idx], + .engine_idx = engine_idx, + }; +} + +#define CI_FLOW_ENGINE_REF_FOREACH (engine_ref, engine_conf) \ + for (size_t __ci_flow_engine_idx = 0; \ + __ci_flow_engine_idx < CI_FLOW_ENGINE_MAX && \ + (((engine_ref) = ci_flow_engine_ref_from_idx((engine_conf), \ + __ci_flow_engine_idx)).engine != NULL); \ + __ci_flow_engine_idx++) + +static inline bool +ci_flow_engine_is_valid (const struct ci_flow_engine *engine) +{ +if (engine ==NULL ) +return false; +if (engine->name ==NULL ) +return false; +if (engine->ops ==NULL ) +return false; +if (engine->ops->ctx_init ==NULL ) +return false; +/* flow size cannot be less than ci_flow */ +if (engine->flow_size <sizeof (struct ci_flow )) +return false; +/* alloc and free must both be defined or NULL */ +if ((engine->ops->flow_alloc ==NULL ) != (engine->ops->flow_free ==NULL )) +return false; +/* register and unregister must both be defined or NULL */ +if ((engine->ops->flow_register ==NULL ) != (engine->ops->flow_unregister ==NULL )) +return false; +return true; +} + +/* caller must hold config lock */ +static inline bool +ci_flow_engine_is_enabled (const struct ci_flow_engine_conf *conf, +const size_t engine_idx) +{ +return (conf->enabled_engines &RTE_BIT64 (engine_idx)) !=0 ; +} + +/* caller must hold config lock */ +static inline void +ci_flow_engine_set_enabled (struct ci_flow_engine_conf *conf,const size_t engine_idx, +bool enabled) +{ +if (enabled) + conf->enabled_engines |=RTE_BIT64 (engine_idx); +else + conf->enabled_engines &= ~RTE_BIT64 (engine_idx); +} + +static inline struct ci_flow * +ci_flow_alloc (const struct ci_flow_engine_conf *engine_conf, +struct ci_flow_engine_ref engine_ref) +{ +const struct ci_flow_engine *engine = engine_ref.engine; +void *priv = engine_conf->engine_priv[engine_ref.engine_idx]; +struct ci_flow *flow =NULL ; +bool fallback = false; + +/* if engine has an allocator callback, try it first */ +if (engine->ops->flow_alloc !=NULL ) + flow = engine->ops->flow_alloc (engine, engine_conf->dev_data, priv); +/* if allocator callback is not defined or failed, use default allocator */ +if (flow ==NULL ) { + flow = (struct ci_flow *)rte_zmalloc (NULL , engine->flow_size,0 ); + +/* if callback exists and we're here, allocation has fallen back */ +if (flow !=NULL && engine->ops->flow_alloc !=NULL ) + fallback = true; + } +if (flow !=NULL ) { +/* initialize the commont part */ +memset (flow,0 ,sizeof (struct ci_flow )); + flow->fallback_alloc = fallback; + flow->engine_idx = engine_ref.engine_idx; + flow->dev_data = engine_conf->dev_data; + flow->engine_priv = priv; + } +return flow; +} + +static inline void +ci_flow_free (struct ci_flow_engine_ref engine_ref,struct ci_flow *flow) +{ +const struct ci_flow_engine *engine = engine_ref.engine; + +if (engine->ops->flow_free !=NULL && !flow->fallback_alloc) + engine->ops->flow_free (flow, flow->dev_data, flow->engine_priv); +else +rte_free (flow); +} + +/* Track stage - caller must hold config lock */ +static inline int +ci_flow_register (struct ci_flow_engine_ref engine_ref, +struct ci_flow *flow, +struct rte_flow_error *error) +{ +const struct ci_flow_engine *engine = engine_ref.engine; + +if (engine->ops->flow_register !=NULL ) +return engine->ops->flow_register (flow, error); + +return 0 ; +} + +/* Track stage - caller must hold config lock */ +static inline int +ci_flow_unregister (struct ci_flow_engine_ref engine_ref, +struct ci_flow *flow, +struct rte_flow_error *error) +{ +const struct ci_flow_engine *engine = engine_ref.engine; + +if (engine->ops->flow_unregister !=NULL ) +return engine->ops->flow_unregister (flow, error); + +return 0 ; +} + +/* caller must hold config lock */ +static inline int +ci_flow_engine_init (struct ci_flow_engine_conf *engine_conf, +struct ci_flow_engine_ref engine_ref) +{ +const struct ci_flow_engine *engine = engine_ref.engine; +void *priv =NULL ; +int ret; + +if (engine->priv_size >0 ) { + priv =rte_zmalloc (engine->name, engine->priv_size,0 ); +if (priv ==NULL ) { + ret = -ENOMEM ; + goto err; + } + } + +if (engine->ops->engine_init !=NULL ) { + ret = engine->ops->engine_init (engine, engine_conf->dev_data, priv); +if (ret !=0 ) + goto err; + } + engine_conf->engine_priv[engine_ref.engine_idx] = priv; +return 0 ; +err: +rte_free (priv); +return ret; +} + +/* caller must hold config lock */ +static inline void +ci_flow_engine_uninit (struct ci_flow_engine_conf *engine_conf, +struct ci_flow_engine_ref engine_ref) +{ +const struct ci_flow_engine *engine = engine_ref.engine; +void *priv; + + priv = engine_conf->engine_priv[engine_ref.engine_idx]; + +CI_DRV_LOG (DEBUG ,"engine '%s': uninit" , engine->name); +/* ignore uninit errors */ +if (engine->ops->engine_uninit !=NULL ) + engine->ops->engine_uninit (engine, priv); + +rte_free (priv); + engine_conf->engine_priv[engine_ref.engine_idx] =NULL ; +} + +/* caller must serialize teardown */ +static inline void +ci_flow_engine_conf_reset (struct ci_flow_engine_conf *engine_conf) +{ +struct ci_flow_engine_ref engine_ref; +struct ci_flow *flow, *tmp; + +/* should be empty by now */ + RTE_TAILQ_FOREACH_SAFE(flow, &engine_conf->flows, node, tmp) { +struct rte_flow_error unreg_error = {0 }; +int unreg_ret; + +TAILQ_REMOVE (&engine_conf->flows, flow, node); +/* only valid flows are ever in the list */ + engine_ref =ci_flow_engine_ref_from_idx (engine_conf, flow->engine_idx); + unreg_ret =ci_flow_unregister (engine_ref, flow, &unreg_error); +if (unreg_ret !=0 ) +CI_DRV_LOG (DEBUG ,"engine '%s': failed to unregister flow: %s" , + engine_ref.engine->name, unreg_error.message); +ci_flow_free (engine_ref, flow); + } + + CI_FLOW_ENGINE_REF_FOREACH(engine_ref, engine_conf) { +if (!ci_flow_engine_is_enabled (engine_conf, engine_ref.engine_idx)) +continue ; +/* ignore errors */ +ci_flow_engine_uninit (engine_conf, engine_ref); +ci_flow_engine_set_enabled (engine_conf, + engine_ref.engine_idx, false); + } + + engine_conf->dev_data =NULL ; + engine_conf->engines =NULL ; +} + +/* caller must serialize initialization */ +static inline int +ci_flow_engine_conf_init (struct ci_flow_engine_conf *engine_conf, +const struct ci_flow_engine_list *engine_list, +struct rte_eth_dev_data *dev_data) +{ +struct ci_flow_engine_ref engine_ref; + +if (engine_conf ==NULL || engine_list ==NULL || dev_data ==NULL ) +return -1 ; + +rte_rwlock_init (&engine_conf->config_lock); + + engine_conf->dev_data = dev_data; + engine_conf->engines = engine_list; + +TAILQ_INIT (&engine_conf->flows); + + CI_FLOW_ENGINE_REF_FOREACH(engine_ref, engine_conf) { +if (!ci_flow_engine_is_valid (engine_ref.engine)) { +CI_DRV_LOG (DEBUG ,"engine[%zu]: invalid, skipping" , + engine_ref.engine_idx); +continue ; + } +int ret =ci_flow_engine_init (engine_conf, engine_ref); + +if (ret !=0 ) { +if (ret == -ENOTSUP ) +CI_DRV_LOG (DEBUG ,"engine '%s': not supported, skipping" , + engine_ref.engine->name); +else +CI_DRV_LOG (ERR ,"engine '%s': init failed (%d: %s), skipping" , + engine_ref.engine->name, ret,rte_strerror (-ret)); +continue ; + } + +ci_flow_engine_set_enabled (engine_conf, + engine_ref.engine_idx, true); +CI_DRV_LOG (DEBUG ,"engine '%s': enabled" , engine_ref.engine->name); + } +return 0 ; +} + +/* caller must hold config lock */ +static inline bool +ci_flow_is_valid (const struct ci_flow *flow, +const struct ci_flow_engine_conf *engine_conf) +{ +if (flow ==NULL ) +return false; +if (engine_conf ==NULL || engine_conf->dev_data ==NULL || + engine_conf->engines ==NULL ) +return false; +if (flow->dev_data != engine_conf->dev_data) +return false; +if (flow->engine_idx >=CI_FLOW_ENGINE_MAX ) +return false; +if (!ci_flow_engine_is_enabled (engine_conf, flow->engine_idx)) +return false; +return true; +} + +/* accepts only empty and ANY-only patterns */ +enum ci_flow_empty_graph_node_id { +CI_FLOW_EMPTY_GRAPH_NODE_START =FLOW_GRAPH_NODE_FIRST , +CI_FLOW_EMPTY_GRAPH_NODE_ANY , +CI_FLOW_EMPTY_GRAPH_NODE_END , +}; + +static const struct flow_graph ci_flow_empty_graph = { + .nodes = (struct flow_graph_node []) { + [CI_FLOW_EMPTY_GRAPH_NODE_START ] = { + .name ="START" , + }, + [CI_FLOW_EMPTY_GRAPH_NODE_ANY ] = { + .name ="ANY" , + .type =RTE_FLOW_ITEM_TYPE_ANY , + .constraints =FLOW_GRAPH_NODE_EXPECT_EMPTY , + }, + [CI_FLOW_EMPTY_GRAPH_NODE_END ] = { + .name ="END" , + .type =RTE_FLOW_ITEM_TYPE_END , + }, + }, + .edges = (struct flow_graph_edge []) { + [CI_FLOW_EMPTY_GRAPH_NODE_START ] = { + .next = (size_t []) { +CI_FLOW_EMPTY_GRAPH_NODE_ANY , +CI_FLOW_EMPTY_GRAPH_NODE_END , +FLOW_GRAPH_NODE_EDGE_END , + }, + }, + [CI_FLOW_EMPTY_GRAPH_NODE_ANY ] = { + .next = (size_t []) { +CI_FLOW_EMPTY_GRAPH_NODE_END , +FLOW_GRAPH_NODE_EDGE_END , + }, + }, + } +}; + +/* concrete pattern-matching mode selected from graph/callback presence */ +enum ci_match_type { +CI_MATCH_EMPTY ,/* no graph, no callback */ +CI_MATCH_CALLBACK ,/* callback only */ +CI_MATCH_GRAPH ,/* graph only */ +CI_MATCH_ALL ,/* callback + graph */ +}; + +/* caller must hold config lock */ +static inline int +ci_flow_match (const struct ci_flow_engine *engine, +const struct rte_flow_item pattern[], +struct ci_flow_engine_ctx *ctx, +enum ci_match_type match_type, +struct rte_flow_error *error) +{ +switch (match_type) { +case CI_MATCH_EMPTY : +/* for empty matching, NULL pattern is not an error */ +if (pattern !=NULL ) { +return flow_graph_parse (&ci_flow_empty_graph, + pattern, error, ctx); + } +return 0 ; + +case CI_MATCH_CALLBACK : +if (pattern ==NULL ) { +return rte_flow_error_set (error,EINVAL , +RTE_FLOW_ERROR_TYPE_ITEM ,NULL , +"Pattern cannot be NULL" ); + } +return engine->ops->pattern_parse (ctx, pattern, error); + +case CI_MATCH_GRAPH : +if (pattern ==NULL ) { +return rte_flow_error_set (error,EINVAL , +RTE_FLOW_ERROR_TYPE_ITEM ,NULL , +"Pattern cannot be NULL" ); + } +return flow_graph_parse (engine->graph, pattern, error, ctx); + +case CI_MATCH_ALL : + { +int ret; + +if (pattern ==NULL ) { +return rte_flow_error_set (error,EINVAL , +RTE_FLOW_ERROR_TYPE_ITEM ,NULL , +"Pattern cannot be NULL" ); + } + ret = engine->ops->pattern_parse (ctx, pattern, error); +if (ret !=0 ) +return ret; +return flow_graph_parse (engine->graph, pattern, error, ctx); + } + +default : +return rte_flow_error_set (error,EINVAL , +RTE_FLOW_ERROR_TYPE_ITEM ,NULL , +"Invalid match type" ); + } +} + +/* caller must hold config lock */ +static inline int +ci_flow_parse (const struct ci_flow_engine_conf *engine_conf, +const struct ci_flow_engine *engine, +const struct rte_flow_attr *attr, +const struct rte_flow_item pattern[], +const struct rte_flow_action actions[], +struct ci_flow *flow, +struct rte_flow_error *error) +{ +enum ci_match_type match_type; +struct ci_flow_engine_ctx *ctx; +int ret =0 ; + +/* +* Matching mode depends on whether a pattern graph and/or a +* pattern_parse callback are provided: +* +* - graph only: match against the graph. This is the expected default; +* no special handling of pattern items. +* +* - graph + callback: the callback preprocesses the pattern, then the +* graph engine does the matching. The graph is expected to have an +* ignore list to skip nodes not meant for it. +* +* - callback only: fully custom pattern parsing. +* +* - neither: match against an empty graph, for engines that don't care +* about the pattern. Default behavior accepts a NULL pattern and +* END or ANY -> END patterns, and rejects anything else (so the +* pattern is still checked, not ignored). +*/ + match_type = engine->graph ==NULL ? + (engine->ops->pattern_parse ==NULL ?CI_MATCH_EMPTY :CI_MATCH_CALLBACK ) : + (engine->ops->pattern_parse ==NULL ?CI_MATCH_GRAPH :CI_MATCH_ALL ); + +CI_DRV_LOG (DEBUG ,"engine '%s': parsing flow" , engine->name); + + ctx = (struct ci_flow_engine_ctx *)calloc (1 , +RTE_MAX (engine->ctx_size,sizeof (struct ci_flow_engine_ctx ))); +if (ctx ==NULL ) { +return rte_flow_error_set (error,ENOMEM , +RTE_FLOW_ERROR_TYPE_HANDLE ,NULL , +"Failed to allocate memory for rule engine context" ); + } + ctx->dev_data = engine_conf->dev_data; + ctx->engine_priv = flow->engine_priv; + ctx->attr = attr; + ctx->pattern = pattern; + ctx->actions = actions; + flow->dev_data = engine_conf->dev_data; + + ret = engine->ops->ctx_init (actions, attr, ctx, error); +if (ret !=0 ) + goto free_ctx; + + ret =ci_flow_match (engine, pattern, ctx, match_type, error); +if (ret !=0 ) + goto free_ctx; + +if (engine->ops->ctx_finalize !=NULL ) + ret = engine->ops->ctx_finalize (ctx, error); +if (ret !=0 ) + goto free_ctx; + +if (engine->ops->ctx_to_flow !=NULL ) { + ret = engine->ops->ctx_to_flow (ctx, flow, error); +if (ret !=0 ) + goto free_ctx; + } + ret =0 ; + +free_ctx: +free (ctx); +return ret; +} + +/* Apply stage - caller must hold config lock */ +static inline int +ci_flow_install (struct ci_flow_engine_ref engine_ref, +struct ci_flow *flow, +struct rte_flow_error *error) +{ +const struct ci_flow_engine *engine = engine_ref.engine; + +if (engine->ops->flow_install !=NULL ) +return engine->ops->flow_install (flow, error); + +return 0 ; +} + +/* Apply stage - caller must hold config lock */ +static inline int +ci_flow_uninstall (struct ci_flow_engine_ref engine_ref, +struct ci_flow *flow, +struct rte_flow_error *error) +{ +const struct ci_flow_engine *engine = engine_ref.engine; + +if (engine->ops->flow_uninstall !=NULL ) +return engine->ops->flow_uninstall (flow, error); + +return 0 ; +} + +/* Default rte_flow op implementations. These take the config lock internally. */ + +static inline struct rte_flow * +ci_flow_create (struct ci_flow_engine_conf *engine_conf, +const struct rte_flow_attr *attr, +const struct rte_flow_item pattern[], +const struct rte_flow_action actions[], +struct rte_flow_error *error) +{ +struct ci_flow_engine_ref engine_ref; +struct ci_flow *flow =NULL ; +int ret; + +if (attr ==NULL || actions ==NULL ) { +CI_DRV_LOG (DEBUG ,"attr or actions is NULL" ); +rte_flow_error_set (error,EINVAL , +RTE_FLOW_ERROR_TYPE_ATTR ,NULL , +"Attributes and actions cannot be NULL" ); +return NULL ; + } + +rte_rwlock_write_lock (&engine_conf->config_lock); + + CI_FLOW_ENGINE_REF_FOREACH(engine_ref, engine_conf) { +if (!ci_flow_engine_is_enabled (engine_conf, engine_ref.engine_idx)) +continue ; + + flow =ci_flow_alloc (engine_conf, engine_ref); +if (flow ==NULL ) { +CI_DRV_LOG (DEBUG ,"engine '%s': failed to allocate flow" , + engine_ref.engine->name); +rte_flow_error_set (error,ENOMEM , +RTE_FLOW_ERROR_TYPE_HANDLE ,NULL , +"Failed to allocate memory for flow rule" ); +/* this is a serious error so don't continue */ + goto unlock; + } + + ret =ci_flow_parse (engine_conf, engine_ref.engine, attr, pattern, + actions, flow, error); + +/* parsing failed - free the flow and try next engine */ +if (ret !=0 ) { +ci_flow_free (engine_ref, flow); +if (error !=NULL ) +CI_DRV_LOG (DEBUG ,"engine '%s' rejected flow: %s" , + engine_ref.engine->name, error->message); +else +CI_DRV_LOG (DEBUG ,"engine '%s' rejected flow" , + engine_ref.engine->name); +continue ; + } + +CI_DRV_LOG (DEBUG ,"engine '%s' accepted flow, committing" , + engine_ref.engine->name); + + ret =ci_flow_register (engine_ref, flow, error); +if (ret !=0 ) { +/* track failed after parse accepted - do not try other engines */ +if (error !=NULL ) +CI_DRV_LOG (DEBUG ,"engine '%s' register failed: %s" , + engine_ref.engine->name, error->message); +else +CI_DRV_LOG (DEBUG ,"engine '%s' register failed" , + engine_ref.engine->name); +ci_flow_free (engine_ref, flow); + flow =NULL ; + goto unlock; + } + + ret =ci_flow_install (engine_ref, flow, error); +if (ret !=0 ) { +struct rte_flow_error unreg_error = {0 }; +int unreg_ret; + +/* install failed after parse accepted - do not try other engines */ +if (error !=NULL ) +CI_DRV_LOG (DEBUG ,"engine '%s' install failed: %s" , + engine_ref.engine->name, error->message); +else +CI_DRV_LOG (DEBUG ,"engine '%s' install failed" , + engine_ref.engine->name); +/* separate error struct to preserve the install error */ + unreg_ret =ci_flow_unregister (engine_ref, flow, &unreg_error); +if (unreg_ret !=0 ) +CI_DRV_LOG (DEBUG ,"engine '%s': failed to unregister: %s" , + engine_ref.engine->name, unreg_error.message); +ci_flow_free (engine_ref, flow); + flow =NULL ; + goto unlock; + } + +CI_DRV_LOG (DEBUG ,"flow installed by engine '%s'" , + engine_ref.engine->name); +TAILQ_INSERT_TAIL (&engine_conf->flows, flow, node); + goto unlock; + } + +CI_DRV_LOG (DEBUG ,"no engine accepted the flow" ); + flow =NULL ; +rte_flow_error_set (error,ENOTSUP , +RTE_FLOW_ERROR_TYPE_UNSPECIFIED ,NULL , +"No flow engine could handle the requested flow" ); +unlock: +rte_rwlock_write_unlock (&engine_conf->config_lock); + +return (struct rte_flow *)flow; +} + +static inline int +ci_flow_validate (struct ci_flow_engine_conf *engine_conf, +const struct rte_flow_attr *attr, +const struct rte_flow_item pattern[], +const struct rte_flow_action actions[], +struct rte_flow_error *error) +{ +struct ci_flow_engine_ref engine_ref; +int ret; + +if (attr ==NULL || actions ==NULL ) { +CI_DRV_LOG (DEBUG ,"attr or actions is NULL" ); +return rte_flow_error_set (error,EINVAL , +RTE_FLOW_ERROR_TYPE_ATTR ,NULL , +"Attributes and actions cannot be NULL" ); + } + +rte_rwlock_read_lock (&engine_conf->config_lock); + + CI_FLOW_ENGINE_REF_FOREACH(engine_ref, engine_conf) { +struct ci_flow *flow; + +if (!ci_flow_engine_is_enabled (engine_conf, engine_ref.engine_idx)) +continue ; + +/* flow is not kept, so skip the engine allocator */ + flow = (struct ci_flow *)calloc (1 , engine_ref.engine->flow_size); +if (flow ==NULL ) { +CI_DRV_LOG (DEBUG ,"engine '%s': failed to allocate flow" , + engine_ref.engine->name); + ret =rte_flow_error_set (error,ENOMEM , +RTE_FLOW_ERROR_TYPE_HANDLE ,NULL , +"Failed to allocate memory for flow rule" ); + goto unlock; + } + flow->fallback_alloc = false; + flow->engine_idx = engine_ref.engine_idx; + flow->dev_data = engine_conf->dev_data; + flow->engine_priv = engine_conf->engine_priv[engine_ref.engine_idx]; + + ret =ci_flow_parse (engine_conf, engine_ref.engine, attr, pattern, + actions, flow, error); +free (flow); + +if (ret ==0 ) { +CI_DRV_LOG (DEBUG ,"engine '%s' accepted flow" , + engine_ref.engine->name); + goto unlock; + }else if (error !=NULL ) { +CI_DRV_LOG (DEBUG ,"engine '%s' rejected flow: %s" , + engine_ref.engine->name, error->message); + }else { +CI_DRV_LOG (DEBUG ,"engine '%s' rejected flow" , + engine_ref.engine->name); + } + } +CI_DRV_LOG (DEBUG ,"no engine accepted the flow" ); + ret =rte_flow_error_set (error,ENOTSUP , +RTE_FLOW_ERROR_TYPE_UNSPECIFIED ,NULL , +"No flow engine could handle the requested flow" ); +unlock: +rte_rwlock_read_unlock (&engine_conf->config_lock); +return ret; +} + +static inline int +ci_flow_destroy (struct ci_flow_engine_conf *engine_conf, +struct rte_flow *rte_flow, +struct rte_flow_error *error) +{ +struct ci_flow *flow = (struct ci_flow *)rte_flow; +struct ci_flow_engine_ref engine_ref; +struct rte_flow_error unreg_error = {0 }; +int unreg_ret, ret =0 ; + +if (rte_flow ==NULL ) { +CI_DRV_LOG (DEBUG ,"flow handle is NULL" ); +return rte_flow_error_set (error,EINVAL , +RTE_FLOW_ERROR_TYPE_HANDLE ,NULL , +"Flow handle cannot be NULL" ); + } + +rte_rwlock_write_lock (&engine_conf->config_lock); + +if (!ci_flow_is_valid (flow, engine_conf)) { +CI_DRV_LOG (DEBUG ,"invalid flow handle" ); + ret =rte_flow_error_set (error,EINVAL , +RTE_FLOW_ERROR_TYPE_HANDLE ,NULL , +"Invalid flow handle" ); + goto unlock; + } + engine_ref =ci_flow_engine_ref_from_idx (engine_conf, flow->engine_idx); +CI_DRV_LOG (DEBUG ,"uninstalling flow (engine '%s')" , + engine_ref.engine->name); + + ret =ci_flow_uninstall (engine_ref, flow, error); + +if (ret !=0 ) { +if (error !=NULL ) +CI_DRV_LOG (DEBUG ,"uninstall failed: %s" , error->message); +else +CI_DRV_LOG (DEBUG ,"uninstall failed" ); + goto unlock; + } + +/* hardware is already clean, so untrack failure is not fatal */ + unreg_ret =ci_flow_unregister (engine_ref, flow, &unreg_error); +if (unreg_ret !=0 ) +CI_DRV_LOG (DEBUG ,"engine '%s': failed to unregister flow: %s" , + engine_ref.engine->name, unreg_error.message); + +TAILQ_REMOVE (&engine_conf->flows, flow, node); +ci_flow_free (engine_ref, flow); +unlock: +rte_rwlock_write_unlock (&engine_conf->config_lock); + +return ret; +} + +static inline int +ci_flow_flush (struct ci_flow_engine_conf *engine_conf, +struct rte_flow_error *error) +{ +struct ci_flow *flow, *tmp; + +CI_DRV_LOG (DEBUG ,"removing all flows" ); + +rte_rwlock_write_lock (&engine_conf->config_lock); + + RTE_TAILQ_FOREACH_SAFE(flow, &engine_conf->flows, node, tmp) { +struct ci_flow_engine_ref engine_ref; +struct rte_flow_error unreg_error = {0 }; +int uninstall_ret; +int unreg_ret; + +/* this shouldn't happen */ +if (!ci_flow_is_valid (flow, engine_conf)) +continue ; + + engine_ref =ci_flow_engine_ref_from_idx (engine_conf, + flow->engine_idx); + + uninstall_ret =ci_flow_uninstall (engine_ref, flow, error); + +/* flush must not stop halfway, so failures are only logged */ +if (uninstall_ret !=0 ) { +if (error !=NULL ) +CI_DRV_LOG (DEBUG ,"engine '%s': failed to uninstall flow: %s" , + engine_ref.engine->name, error->message); +else +CI_DRV_LOG (DEBUG ,"engine '%s': failed to uninstall flow" , + engine_ref.engine->name); + } + + unreg_ret =ci_flow_unregister (engine_ref, flow, &unreg_error); +if (unreg_ret !=0 ) +CI_DRV_LOG (DEBUG ,"engine '%s': failed to untrack flow: %s" , + engine_ref.engine->name, unreg_error.message); + +TAILQ_REMOVE (&engine_conf->flows, flow, node); +ci_flow_free (engine_ref, flow); + } + +rte_rwlock_write_unlock (&engine_conf->config_lock); + +return 0 ; +} + +static inline int +ci_flow_query (struct ci_flow_engine_conf *engine_conf, +struct rte_flow *rte_flow, +const struct rte_flow_action *action, +void *data, +struct rte_flow_error *error) +{ +struct ci_flow *flow = (struct ci_flow *)rte_flow; +struct ci_flow_engine_ref engine_ref; +int ret; + +if (action ==NULL || data ==NULL ) { +CI_DRV_LOG (DEBUG ,"action or data is NULL" ); +return rte_flow_error_set (error,EINVAL , +RTE_FLOW_ERROR_TYPE_ACTION ,NULL , +"Action or data cannot be NULL" ); + } + +rte_rwlock_read_lock (&engine_conf->config_lock); + +if (!ci_flow_is_valid (flow, engine_conf)) { +CI_DRV_LOG (DEBUG ,"invalid flow handle" ); + ret =rte_flow_error_set (error,EINVAL , +RTE_FLOW_ERROR_TYPE_HANDLE ,NULL , +"Invalid flow handle" ); + goto unlock; + } + engine_ref =ci_flow_engine_ref_from_idx (engine_conf, flow->engine_idx); +if (engine_ref.engine->ops->flow_query !=NULL ) { + ret = engine_ref.engine->ops->flow_query (flow, action, data, error); + +if (ret !=0 && error !=NULL ) +CI_DRV_LOG (DEBUG ,"engine '%s' query failed: %s" , + engine_ref.engine->name, error->message); +else if (ret !=0 ) +CI_DRV_LOG (DEBUG ,"engine '%s' query failed" , + engine_ref.engine->name); + }else { +CI_DRV_LOG (DEBUG ,"engine '%s' does not support querying" , + engine_ref.engine->name); + ret =rte_flow_error_set (error,ENOTSUP , +RTE_FLOW_ERROR_TYPE_UNSPECIFIED ,NULL , +"Flow engine does not support querying" ); + } +unlock: +rte_rwlock_read_unlock (&engine_conf->config_lock); + +return ret; +} + +#define CI_FLOW_DUMP_CHUNK_BYTES 32 + +static inline void +ci_flow_dump_one (FILE *file,const char *driver,const char *engine, +const void *data,size_t data_len) +{ +const uint8_t *raw = (const uint8_t *)data; +const size_t nchunks = + (data_len +CI_FLOW_DUMP_CHUNK_BYTES -1 ) / +CI_FLOW_DUMP_CHUNK_BYTES ; +char title[64 ]; +size_t ci; + +fprintf (file,"FLOW DUMP: driver=%s engine=%s\n" , driver, engine); +fprintf (file,"FLOW DUMP: DATA size=%zu chunks=%zu chunk_bytes=%d\n" , + data_len, nchunks,CI_FLOW_DUMP_CHUNK_BYTES ); + +for (ci =0 ; ci < nchunks; ci++) { +const size_t off = ci *CI_FLOW_DUMP_CHUNK_BYTES ; +const size_t clen = +RTE_MIN ((size_t )CI_FLOW_DUMP_CHUNK_BYTES , + data_len - off); +snprintf (title,sizeof (title),"FLOW DUMP: chunk %03zu/%03zu" , + ci +1 , nchunks); +rte_memdump (file, title, raw + off, clen); + } +} + +/* rte_flow_dev_dump implementation */ +static inline int +ci_flow_dump (struct ci_flow_engine_conf *engine_conf, +struct rte_flow *flow, +FILE *file, +struct rte_flow_error *error) +{ +struct ci_flow_engine_ref engine_ref; +struct ci_flow *cur; +bool found = false; + const char *driver_name = +#ifdef RTE_COMPONENT_NAME +RTE_STR (RTE_COMPONENT_NAME ); +#else +"unknown" ; +#endif + +rte_rwlock_read_lock (&engine_conf->config_lock); + + TAILQ_FOREACH(cur, &engine_conf->flows, node) { +const void *data; +size_t data_len; + +if (flow !=NULL && (struct rte_flow *)cur != flow) +continue ; + +if (!ci_flow_is_valid (cur, engine_conf)) { +CI_DRV_LOG (DEBUG ,"invalid flow handle: %p, skipping" , cur); +continue ; + } + + found = true; + + engine_ref =ci_flow_engine_ref_from_idx (engine_conf, cur->engine_idx); + + data =RTE_PTR_ADD (cur,sizeof (struct ci_flow )); + data_len = engine_ref.engine->flow_size -sizeof (struct ci_flow ); + +/* skipping explicitly keeps static analyzers quiet */ +if (data_len ==0 ) { +CI_DRV_LOG (DEBUG ,"flow data length is 0, skipping dump" ); +continue ; + } + +ci_flow_dump_one (file, driver_name, engine_ref.engine->name, + data, data_len); + } + +rte_rwlock_read_unlock (&engine_conf->config_lock); + +if (flow !=NULL && !found) { +return rte_flow_error_set (error,ENOENT , +RTE_FLOW_ERROR_TYPE_HANDLE ,NULL , +"Flow not found" ); + } + +return 0 ; +} + +/* Driver lifecycle helpers. These take the config lock internally. */ + +/* reinstall kept flows to hardware */ +static inline int +ci_flow_replay (struct ci_flow_engine_conf *engine_conf) +{ +struct rte_flow_error error = {0 }; +struct ci_flow *flow; + +CI_DRV_LOG (DEBUG ,"replaying all flows" ); + +rte_rwlock_write_lock (&engine_conf->config_lock); + + TAILQ_FOREACH(flow, &engine_conf->flows, node) { +struct ci_flow_engine_ref engine_ref; +int install_ret; + +/* this shouldn't happen */ +if (!ci_flow_is_valid (flow, engine_conf)) +continue ; + + engine_ref =ci_flow_engine_ref_from_idx (engine_conf, + flow->engine_idx); + + install_ret =ci_flow_install (engine_ref, flow, &error); +if (install_ret !=0 ) { +CI_DRV_LOG (DEBUG ,"engine '%s': failed to install flow: %s" , + engine_ref.engine->name, error.message); + } + } + +rte_rwlock_write_unlock (&engine_conf->config_lock); + +return 0 ; +} + +/* drop all flows without touching the hardware */ +static inline int +ci_flow_cleanup (struct ci_flow_engine_conf *engine_conf) +{ +struct rte_flow_error error = {0 }; +struct ci_flow *flow, *tmp; + +CI_DRV_LOG (DEBUG ,"cleaning up all flows" ); + +rte_rwlock_write_lock (&engine_conf->config_lock); + + RTE_TAILQ_FOREACH_SAFE(flow, &engine_conf->flows, node, tmp) { +struct ci_flow_engine_ref engine_ref; +int unregister_ret; + +/* this shouldn't happen */ +if (!ci_flow_is_valid (flow, engine_conf)) +continue ; + + engine_ref =ci_flow_engine_ref_from_idx (engine_conf, + flow->engine_idx); + + unregister_ret =ci_flow_unregister (engine_ref, flow, &error); +if (unregister_ret !=0 ) { +CI_DRV_LOG (DEBUG ,"engine '%s': failed to untrack flow: %s" , + engine_ref.engine->name, error.message); + } + +TAILQ_REMOVE (&engine_conf->flows, flow, node); +ci_flow_free (engine_ref, flow); + } + +rte_rwlock_write_unlock (&engine_conf->config_lock); + +return 0 ; +} + +#endif /* _COMMON_INTEL_FLOW_ENGINE_H_ */
Signature · 1 line
2.52.0
PATCH v5 4/25 net/intel/common: add utility functions
In reply to Anatoly BurakovA lot of parsers will rely on doing the same things over and over, so create a header with utility functions to aid in writing parsers.
--- drivers/net/intel/common/flow_util.h | 263 +++++++++++++++++++++++++++ 1 file changed, 263 insertions(+) create mode 100644 drivers/net/intel/common/flow_util.h
drivers/net/intel/common/flow_util.h new file +263 -0
@@ -0,0 +1,263 @@ +/* SPDX-License-Identifier: BSD-3-Clause +* Copyright(c) 2025 Intel Corporation +*/ + +#ifndef _COMMON_INTEL_FLOW_UTIL_H_ +#define _COMMON_INTEL_FLOW_UTIL_H_ + +#include <stdint.h> +#include <stdbool.h> +#include <string.h> + +#include <rte_debug.h> +#include <rte_flow.h> + +/* +* Utility functions primarily intended for flow parsers. +*/ + +/** +* Get the effective mask of a flow item. +* +* @param item +* Flow item. +* @return +* - NULL if spec is NULL +* - item->mask if mask is not NULL +* - default mask for the item type if mask is NULL +* - NULL if the item type has no default mask +*/ +static inline const void * +ci_flow_item_mask (const struct rte_flow_item *item) +{ +const void *mask; + +if (item->spec ==NULL ) +return NULL ; +if (item->mask !=NULL ) +return item->mask; +if (rte_flow_conv (RTE_FLOW_CONV_OP_ITEM_DEFAULT_MASK_PTR , &mask,sizeof (mask), + (const void *)(uintptr_t )item->type,NULL ) <0 ) +return NULL ; +return mask; +} + +/* +* Simplistic usage counter. Not thread-safe, not atomic. +*/ +typedef uint32_t ci_usage_count_t ; + +/** +* Claim a usage. Returns true if this is the first usage. +* +* @param counter +* Usage counter to claim. +* @return +* true if this is the first usage, false otherwise. +*/ +static inline bool +ci_usage_count_claim (ci_usage_count_t *counter) +{ +#ifdef CI_DEBUG +if (*counter ==UINT32_MAX ) +rte_panic ("ci usage counter overflow\n" ); +#endif +return (*counter)++ ==0 ; +} + +/** +* Release a usage. Returns true if this was the last usage. +* +* @param counter +* Usage counter to release. +* @return +* true if this was the last usage, false otherwise. +*/ +static inline bool +ci_usage_count_release (ci_usage_count_t *counter) +{ +#ifdef CI_DEBUG +if (*counter ==0 ) +rte_panic ("ci usage counter underflow\n" ); +#endif +return --(*counter) ==0 ; +} + +/** +* Test whether the currently claimed usage is the last one. +* +* @param counter +* Usage counter to test. +* @return +* true if the current usage is the last one, false otherwise. +*/ +static inline bool +ci_usage_count_is_last (const ci_usage_count_t *counter) +{ +return *counter ==1 ; +} + +/** +* Check if memory region is filled with a specific byte value. +* +* @param ptr +* Pointer to memory region. +* @param len +* Length in bytes. +* @param val +* Byte value to check (e.g. 0x00 or 0xFF). +* @return +* true if all bytes equal val, false otherwise. +*/ +static inline bool +ci_is_all_byte (const void *ptr,size_t len,uint8_t val) +{ +const uint8_t *bytes = (const uint8_t *)ptr; +const uint32_t pattern32 =0x01010101U * val; +size_t i =0 ; + +/* Process 4-byte chunks using memcpy */ +for (; i +4 <= len; i +=4 ) { +uint32_t chunk; +memcpy (&chunk, bytes + i,4 ); +if (chunk != pattern32) +return false; + } + +/* Process remaining bytes */ +for (; i < len; i++) { +if (bytes[i] != val) +return false; + } + +return true; +} + +/** +* Check if bytes are all 0x00 OR all 0xFF. +* +* @param ptr +* Pointer to memory region. +* @param len +* Length in bytes. +* @return +* true if all bytes are 0x00 OR all bytes are 0xFF, false otherwise. +*/ +static inline bool +ci_is_all_zero_or_masked (const void *ptr,size_t len) +{ +const uint8_t *bytes = (const uint8_t *)ptr; +uint8_t first_val; + +/* zero length cannot be valid */ +if (len ==0 ) +return false; + + first_val = bytes[0 ]; + +if (first_val !=0x00 && first_val !=0xFF ) +return false; + +return ci_is_all_byte (ptr, len, first_val); +} + +/** +* Check if a value has no bits outside the mask, and within the mask is +* either all-zero or all-one. +* +* This is intended for bitfields e.g. VLAN_TCI. For byte-aligned fields, +* use CI_FIELD_IS_ZERO_OR_MASKED below. +* +* @param value +* Data value to check. +* @param mask +* Mask to compare against. +* @return +* true if the value is either all-zero or fully masked, false otherwise. +*/ +static inline bool +ci_is_zero_or_masked (uint64_t value,uint64_t mask) +{ +return value ==0 || value == mask; +} + +/** +* Check if a struct field is fully masked or unmasked. +* +* @param field_ptr +* Pointer to the mask field (e.g. ð_mask->hdr.src_addr). +*/ +#define CI_FIELD_IS_ZERO_OR_MASKED (field_ptr) \ + ci_is_all_zero_or_masked((field_ptr), sizeof(*(field_ptr))) + +/** +* Check if a struct field is all 0x00. +* +* @param field_ptr +* Pointer to the mask field (e.g. ð_mask->hdr.src_addr). +*/ +#define CI_FIELD_IS_ZERO (field_ptr) \ + ci_is_all_byte((field_ptr), sizeof(*(field_ptr)), 0x00) + +/** +* Check if a struct field is all 0xFF. +* +* @param field_ptr +* Pointer to the mask field (e.g. ð_mask->hdr.src_addr). +*/ +#define CI_FIELD_IS_MASKED (field_ptr) \ + ci_is_all_byte((field_ptr), sizeof(*(field_ptr)), 0xFF) + +/** +* Convert 24-bit big-endian value to host byte order. +* +* Used to extract 24-bit big-endian values (e.g. VXLAN VNI). +* +* @param val +* Pointer to 3-byte big-endian value. +* @return +* Value in host byte order. +*/ +static inline uint32_t +ci_be24_to_cpu (const uint8_t val[3 ]) +{ +return (val[0 ] <<16 ) | (val[1 ] <<8 ) | val[2 ]; +} + +/** +* Check if a character is a valid hexadecimal digit. +* +* @param c +* Character to check. +* @return +* true if c is in [0-9a-fA-F], false otherwise. +*/ +static inline bool +ci_is_hex_char (unsigned char c) +{ +return ((c >='0' && c <='9' ) || + (c >='a' && c <='f' ) || + (c >='A' && c <='F' )); +} + +/** +* Convert hex character to 4-bit value. +* +* @param c +* Hex character ('0'-'9', 'a'-'f', 'A'-'F'). +* @return +* Value 0-15, or 0 if invalid. +*/ +static inline unsigned char +ci_hex_char_to_nibble (unsigned char c) +{ +if (c >='0' && c <='9' ) +return c -'0' ; +if (c >='a' && c <='f' ) +return c -'a' +10 ; +if (c >='A' && c <='F' ) +return c -'A' +10 ; +return 0 ; +} + +#endif /* _COMMON_INTEL_FLOW_UTIL_H_ */
Signature · 1 line
2.52.0
PATCH v5 5/25 net/ixgbe: add support for common flow parsing
In reply to Anatoly BurakovImplement support for common flow parsing infrastructure in preparation for migration of flow engines. The following features are enabled:
- Conf init on dev_init
- Conf uninit on dev_close
- Flow cleanup on dev_close
- Flow replay on dev_start
--- drivers/net/intel/ixgbe/ixgbe_ethdev.c | 22 ++++++++++- drivers/net/intel/ixgbe/ixgbe_ethdev.h | 5 +++ drivers/net/intel/ixgbe/ixgbe_flow.c | 54 +++++++++++++++++++++++++- drivers/net/intel/ixgbe/ixgbe_flow.h | 12 ++++++ 4 files changed, 90 insertions(+), 3 deletions(-) create mode 100644 drivers/net/intel/ixgbe/ixgbe_flow.h
drivers/net/intel/ixgbe/ixgbe_ethdev.c +20 -2
@@ -47,6 +47,7 @@#include "base/ixgbe_phy.h" #include "ixgbe_osdep.h" #include "ixgbe_regs.h" +#include "ixgbe_flow.h" /* * High threshold controlling when to start sending XOFF frames. Must be at
@@ -1279,6 +1280,12 @@ eth_ixgbe_dev_init(struct rte_eth_dev *eth_dev, void *init_params __rte_unused)if (ret) goto err_l2_tn_filter_init; +/* initialize flow engine configuration */ + ret =ci_flow_engine_conf_init (&ad->flow_engine_conf, + &ixgbe_flow_engine_list, eth_dev->data); +if (ret) + goto err_flow_engine_conf_init; +/* initialize flow filter lists */ ixgbe_filterlist_init (eth_dev);
@@ -1290,6 +1297,8 @@ eth_ixgbe_dev_init(struct rte_eth_dev *eth_dev, void *init_params __rte_unused)return 0 ; +err_flow_engine_conf_init: +ixgbe_l2_tn_filter_uninit (eth_dev); err_l2_tn_filter_init:ixgbe_fdir_filter_uninit (eth_dev); err_fdir_filter_init:
@@ -2859,6 +2868,9 @@ ixgbe_dev_start(struct rte_eth_dev *dev)if (macsec_setting->offload_en)ixgbe_dev_macsec_register_enable (dev, macsec_setting); +/* re-install kept flows to hardware */ +ci_flow_replay (&adapter->flow_engine_conf); +return 0 ; error:
@@ -3038,8 +3050,8 @@ ixgbe_dev_set_link_down(struct rte_eth_dev *dev)static int ixgbe_dev_close (struct rte_eth_dev *dev) { -struct ixgbe_hw *hw = -IXGBE_DEV_PRIVATE_TO_HW (dev->data->dev_private); +struct ixgbe_adapter *ad = dev->data->dev_private; +struct ixgbe_hw *hw =IXGBE_DEV_PRIVATE_TO_HW (ad);struct rte_pci_device *pci_dev =RTE_CLASS_TO_BUS_DEVICE (dev, *pci_dev);struct rte_intr_handle *intr_handle = pci_dev->intr_handle;int retries =0 ;
@@ -3106,6 +3118,12 @@ ixgbe_dev_close(struct rte_eth_dev *dev)rte_free (dev->security_ctx); dev->security_ctx =NULL ; +/* drop all flows */ +ci_flow_cleanup (&ad->flow_engine_conf); + +/* reset flow engines */ +ci_flow_engine_conf_reset (&ad->flow_engine_conf); +return ret; }
drivers/net/intel/ixgbe/ixgbe_ethdev.h +5 -0
@@ -22,6 +22,8 @@#include <bus_pci_driver.h> #include <rte_tm_driver.h> +#include "../common/flow_engine.h" +/* need update link, bit flag */ #define IXGBE_FLAG_NEED_LINK_UPDATE (uint32_t)(1 << 0)#define IXGBE_FLAG_MAILBOX (uint32_t)(1 << 1)
@@ -342,6 +344,7 @@ struct ixgbe_l2_tn_info { };struct rte_flow { +struct ci_flow flow;enum rte_filter_type filter_type;/* security flows are not rte_filter_type */ bool is_security;
@@ -487,6 +490,8 @@ struct ixgbe_adapter {struct rte_timecounter tx_tstamp_tc;struct ixgbe_tm_conf tm_conf; +struct ci_flow_engine_conf flow_engine_conf; +/* For RSS reta table update */ uint8_t rss_reta_updated;
drivers/net/intel/ixgbe/ixgbe_flow.c +53 -1
104 lines not on this page · raw message
drivers/net/intel/ixgbe/ixgbe_flow.h new file +12 -0
@@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: BSD-3-Clause +* Copyright(c) 2026 Intel Corporation +*/ + +#ifndef _IXGBE_FLOW_H_ +#define _IXGBE_FLOW_H_ + +#include "../common/flow_engine.h" + +extern const struct ci_flow_engine_list ixgbe_flow_engine_list; + +#endif /* _IXGBE_FLOW_H_ */
Signature · 1 line
2.52.0
PATCH v5 6/25 net/ixgbe: make ethertype filter table dynamic
In reply to Anatoly BurakovCurrently, when installing Ethertype filters, some of the filters will be installed at a fixed offset into the Ethertype filter table (such as timesync filter), which interferes with rte_flow-provided Ethertype flows which install into "first available slot" without checking if the slot was actually "available".
Rework the Ethertype filter infrastructure to reserve Ethertype filter slots dynamically in a centralized manner, so that timesync, anti-spoof, and rte_flow provided Ethertype filters do not step on each others' toes.
--- drivers/net/intel/ixgbe/ixgbe_ethdev.c | 205 +++++++++++++++---------- drivers/net/intel/ixgbe/ixgbe_ethdev.h | 85 +++------- drivers/net/intel/ixgbe/ixgbe_pf.c | 49 +++--- 3 files changed, 172 insertions(+), 167 deletions(-)
drivers/net/intel/ixgbe/ixgbe_ethdev.c +124 -81
@@ -6856,77 +6856,99 @@ ixgbe_add_del_ntuple_filter(struct ixgbe_adapter *adapter,return 0 ; } +void +ixgbe_ethertype_filter_program (struct ixgbe_hw *hw,uint8_t idx, +uint32_t etqf,uint32_t etqs) +{ +IXGBE_WRITE_REG (hw,IXGBE_ETQF (idx), etqf); +IXGBE_WRITE_REG (hw,IXGBE_ETQS (idx), etqs); +IXGBE_WRITE_FLUSH (hw); +} + +static int +ixgbe_ethertype_table_lookup (const struct ixgbe_ethertype_table *table, +uint16_t ethertype) +{ +int idx; + +for (idx =0 ; idx <IXGBE_MAX_ETQF_FILTERS ; idx++) { +if (table->entries[idx].used && + table->entries[idx].ethertype == ethertype) +return idx; + } +return -ENOENT ; +} + +int +ixgbe_ethertype_table_add (struct ixgbe_ethertype_table *table, +uint16_t ethertype,uint32_t etqf,uint32_t etqs) +{ +int free_idx =-1 ; +int i; + +for (i =0 ; i <IXGBE_MAX_ETQF_FILTERS ; i++) { +if (table->entries[i].used) { +if (table->entries[i].ethertype == ethertype) +return -EEXIST ; + }else if (free_idx <0 ) { + free_idx = i; + } + } +if (free_idx <0 ) +return -ENOSPC ; + + table->entries[free_idx].ethertype = ethertype; + table->entries[free_idx].etqf = etqf; + table->entries[free_idx].etqs = etqs; + table->entries[free_idx].used = true; + +return free_idx; +} + +int +ixgbe_ethertype_table_del (struct ixgbe_ethertype_table *table,uint8_t idx) +{ +if (idx >=IXGBE_MAX_ETQF_FILTERS || !table->entries[idx].used) +return -ENOENT ; + + table->entries[idx] = (struct ixgbe_ethertype_entry ){0 }; + +return 0 ; +} +int ixgbe_add_del_ethertype_filter (struct ixgbe_adapter *adapter, -struct rte_eth_ethertype_filter *filter, -bool add) +struct rte_eth_ethertype_filter *filter,bool add) {struct ixgbe_hw *hw =IXGBE_DEV_PRIVATE_TO_HW (adapter); -struct ixgbe_filter_info *filter_info = -IXGBE_DEV_PRIVATE_TO_FILTER_INFO (adapter); -uint32_t etqf =0 ; -uint32_t etqs =0 ; -int ret; -struct ixgbe_ethertype_filter ethertype_filter; +struct ixgbe_ethertype_table *table = + &IXGBE_DEV_PRIVATE_TO_FILTER_INFO (adapter)->ethertype_table; +uint32_t etqf, etqs; +int idx; -if (filter->queue >=IXGBE_MAX_RX_QUEUE_NUM ) +if (filter->queue >=IXGBE_MAX_RX_QUEUE_NUM || + filter->ether_type ==RTE_ETHER_TYPE_IPV4 || + filter->ether_type ==RTE_ETHER_TYPE_IPV6 || + filter->flags & (RTE_ETHTYPE_FLAGS_MAC |RTE_ETHTYPE_FLAGS_DROP ))return -EINVAL ; -if (filter->ether_type ==RTE_ETHER_TYPE_IPV4 || - filter->ether_type ==RTE_ETHER_TYPE_IPV6 ) { -PMD_DRV_LOG (ERR ,"unsupported ether_type(0x%04x) in" -" ethertype filter." , filter->ether_type); -return -EINVAL ; - } - -if (filter->flags &RTE_ETHTYPE_FLAGS_MAC ) { -PMD_DRV_LOG (ERR ,"mac compare is unsupported." ); -return -EINVAL ; - } -if (filter->flags &RTE_ETHTYPE_FLAGS_DROP ) { -PMD_DRV_LOG (ERR ,"drop option is unsupported." ); -return -EINVAL ; - } - - ret =ixgbe_ethertype_filter_lookup (filter_info, filter->ether_type); -if (ret >=0 && add) { -PMD_DRV_LOG (ERR ,"ethertype (0x%04x) filter exists." , - filter->ether_type); -return -EEXIST ; - } -if (ret <0 && !add) { -PMD_DRV_LOG (ERR ,"ethertype (0x%04x) filter doesn't exist." , - filter->ether_type); -return -ENOENT ; - } -if (add) { - etqf =IXGBE_ETQF_FILTER_EN ; - etqf |= (uint32_t )filter->ether_type; - etqs |= (uint32_t )((filter->queue << -IXGBE_ETQS_RX_QUEUE_SHIFT ) & -IXGBE_ETQS_RX_QUEUE ); - etqs |=IXGBE_ETQS_QUEUE_EN ; - - ethertype_filter.ethertype = filter->ether_type; - ethertype_filter.etqf = etqf; - ethertype_filter.etqs = etqs; - ethertype_filter.conf = FALSE; - ret =ixgbe_ethertype_filter_insert (filter_info, - ðertype_filter); -if (ret <0 ) { -PMD_DRV_LOG (ERR ,"ethertype filters are full." ); -return -ENOSPC ; - } + etqf =IXGBE_ETQF_FILTER_EN | filter->ether_type; + etqs =IXGBE_ETQS_QUEUE_EN | + (((uint32_t )filter->queue <<IXGBE_ETQS_RX_QUEUE_SHIFT ) & +IXGBE_ETQS_RX_QUEUE ); + idx =ixgbe_ethertype_table_add (table, filter->ether_type, etqf, etqs); +if (idx <0 ) +return idx; }else { - ret =ixgbe_ethertype_filter_remove (filter_info, (uint8_t )ret); -if (ret <0 ) -return -ENOSYS ; + idx =ixgbe_ethertype_table_lookup (table, filter->ether_type); +if (idx <0 ) +return idx; +ixgbe_ethertype_table_del (table, idx); + etqf =0 ; + etqs =0 ; } -IXGBE_WRITE_REG (hw,IXGBE_ETQF (ret), etqf); -IXGBE_WRITE_REG (hw,IXGBE_ETQS (ret), etqs); -IXGBE_WRITE_FLUSH (hw); - +ixgbe_ethertype_filter_program (hw, idx, etqf, etqs);return 0 ; }
@@ -7163,12 +7185,29 @@ static int ixgbe_timesync_enable(struct rte_eth_dev *dev) {struct ixgbe_hw *hw =IXGBE_DEV_PRIVATE_TO_HW (dev->data->dev_private); +struct ixgbe_filter_info *filter_info = +IXGBE_DEV_PRIVATE_TO_FILTER_INFO (dev->data->dev_private);uint32_t tsync_ctl;uint32_t tsauxc; +uint32_t etqf;struct timespec ts; +int idx;memset (&ts,0 ,sizeof (struct timespec )); +/* Reserve the shared ETQF slot before changing timestamp hardware. */ + etqf =RTE_ETHER_TYPE_1588 |IXGBE_ETQF_FILTER_EN |IXGBE_ETQF_1588 ; +if (!filter_info->timesync_installed) { + idx =ixgbe_ethertype_table_add (&filter_info->ethertype_table, +RTE_ETHER_TYPE_1588 , etqf,0 ); +if (idx <0 ) { +PMD_DRV_LOG (ERR ,"no free ETQF slot for 1588 timestamping" ); +return idx; + } + filter_info->timesync_idx = idx; + filter_info->timesync_installed = true; + } +/* get current system time */ clock_gettime (CLOCK_REALTIME , &ts);
@@ -7186,10 +7225,7 @@ ixgbe_timesync_enable(struct rte_eth_dev *dev)ixgbe_start_timecounters (dev);/* Enable L2 filtering of IEEE1588/802.1AS Ethernet frame types. */ -IXGBE_WRITE_REG (hw,IXGBE_ETQF (IXGBE_ETQF_FILTER_1588 ), - (RTE_ETHER_TYPE_1588 | -IXGBE_ETQF_FILTER_EN | -IXGBE_ETQF_1588 )); +ixgbe_ethertype_filter_program (hw, filter_info->timesync_idx, etqf,0 );/* Enable timestamping of received PTP packets. */ tsync_ctl =IXGBE_READ_REG (hw,IXGBE_TSYNCRXCTL );
@@ -7213,6 +7249,8 @@ static int ixgbe_timesync_disable(struct rte_eth_dev *dev) {struct ixgbe_hw *hw =IXGBE_DEV_PRIVATE_TO_HW (dev->data->dev_private); +struct ixgbe_filter_info *filter_info = +IXGBE_DEV_PRIVATE_TO_FILTER_INFO (dev->data->dev_private);uint32_t tsync_ctl;/* Disable timestamping of transmitted PTP packets. */
@@ -7226,7 +7264,12 @@ ixgbe_timesync_disable(struct rte_eth_dev *dev)IXGBE_WRITE_REG (hw,IXGBE_TSYNCRXCTL , tsync_ctl);/* Disable L2 filtering of IEEE1588/802.1AS Ethernet frame types. */ -IXGBE_WRITE_REG (hw,IXGBE_ETQF (IXGBE_ETQF_FILTER_1588 ),0 ); +if (filter_info->timesync_installed) { +ixgbe_ethertype_filter_program (hw, filter_info->timesync_idx,0 ,0 ); +ixgbe_ethertype_table_del (&filter_info->ethertype_table, + filter_info->timesync_idx); + filter_info->timesync_installed = false; + }/* Stop incrementing the System Time registers. */ IXGBE_WRITE_REG (hw,IXGBE_TIMINCA ,0 );
@@ -8381,13 +8424,14 @@ ixgbe_ethertype_filter_restore(struct rte_eth_dev *dev)int i;for (i =0 ; i <IXGBE_MAX_ETQF_FILTERS ; i++) { -if (filter_info->ethertype_mask & (1 << i)) { -IXGBE_WRITE_REG (hw,IXGBE_ETQF (i), - filter_info->ethertype_filters[i].etqf); -IXGBE_WRITE_REG (hw,IXGBE_ETQS (i), - filter_info->ethertype_filters[i].etqs); -IXGBE_WRITE_FLUSH (hw); - } +/* skip over entries not managed by rte_flow */ +if (i == filter_info->timesync_idx || + i == filter_info->antispoof_idx|| + !filter_info->ethertype_table.entries[i].used) +continue ; +ixgbe_ethertype_filter_program (hw, i, + filter_info->ethertype_table.entries[i].etqf, + filter_info->ethertype_table.entries[i].etqs); } }
@@ -8495,14 +8539,13 @@ ixgbe_clear_all_ethertype_filter(struct rte_eth_dev *dev)int i;for (i =0 ; i <IXGBE_MAX_ETQF_FILTERS ; i++) { -if (filter_info->ethertype_mask & (1 << i) && - !filter_info->ethertype_filters[i].conf) { - (void )ixgbe_ethertype_filter_remove (filter_info, - (uint8_t )i); -IXGBE_WRITE_REG (hw,IXGBE_ETQF (i),0 ); -IXGBE_WRITE_REG (hw,IXGBE_ETQS (i),0 ); -IXGBE_WRITE_FLUSH (hw); - } +/* only clear rte_flow filters */ +if (!filter_info->ethertype_table.entries[i].used || + (filter_info->timesync_installed && i == filter_info->timesync_idx) || + (filter_info->antispoof_installed && i == filter_info->antispoof_idx)) +continue ; +ixgbe_ethertype_table_del (&filter_info->ethertype_table, i); +ixgbe_ethertype_filter_program (hw, i,0 ,0 ); } }
drivers/net/intel/ixgbe/ixgbe_ethdev.h +22 -63
113 lines not on this page · raw message
drivers/net/intel/ixgbe/ixgbe_pf.c +26 -23
76 lines not on this page · raw message
Signature · 1 line
2.52.0
PATCH v5 7/25 net/ixgbe: reimplement ethertype parser
In reply to Anatoly BurakovUse the new flow graph API and the common parsing framework to implement flow parser for ethertype.
The old ethertype parser was accepting certain things that were later rejected by the actual ethertype installation code, in particular DROP action as well as dst MAC address filtering. This was removed from the graph parser.
--- drivers/net/intel/ixgbe/ixgbe_ethdev.c | 92 ------ drivers/net/intel/ixgbe/ixgbe_ethdev.h | 4 - drivers/net/intel/ixgbe/ixgbe_flow.c | 220 +------------ drivers/net/intel/ixgbe/ixgbe_flow.h | 8 + .../net/intel/ixgbe/ixgbe_flow_ethertype.c | 299 ++++++++++++++++++ drivers/net/intel/ixgbe/meson.build | 1 + 6 files changed, 314 insertions(+), 310 deletions(-) create mode 100644 drivers/net/intel/ixgbe/ixgbe_flow_ethertype.c
drivers/net/intel/ixgbe/ixgbe_ethdev.c +0 -92
@@ -6865,20 +6865,6 @@ ixgbe_ethertype_filter_program(struct ixgbe_hw *hw, uint8_t idx,IXGBE_WRITE_FLUSH (hw); } -static int -ixgbe_ethertype_table_lookup (const struct ixgbe_ethertype_table *table, -uint16_t ethertype) -{ -int idx; - -for (idx =0 ; idx <IXGBE_MAX_ETQF_FILTERS ; idx++) { -if (table->entries[idx].used && - table->entries[idx].ethertype == ethertype) -return idx; - } -return -ENOENT ; -} -int ixgbe_ethertype_table_add (struct ixgbe_ethertype_table *table,uint16_t ethertype,uint32_t etqf,uint32_t etqs)
@@ -6916,42 +6902,6 @@ ixgbe_ethertype_table_del(struct ixgbe_ethertype_table *table, uint8_t idx)return 0 ; } -int -ixgbe_add_del_ethertype_filter (struct ixgbe_adapter *adapter, -struct rte_eth_ethertype_filter *filter,bool add) -{ -struct ixgbe_hw *hw =IXGBE_DEV_PRIVATE_TO_HW (adapter); -struct ixgbe_ethertype_table *table = - &IXGBE_DEV_PRIVATE_TO_FILTER_INFO (adapter)->ethertype_table; -uint32_t etqf, etqs; -int idx; - -if (filter->queue >=IXGBE_MAX_RX_QUEUE_NUM || - filter->ether_type ==RTE_ETHER_TYPE_IPV4 || - filter->ether_type ==RTE_ETHER_TYPE_IPV6 || - filter->flags & (RTE_ETHTYPE_FLAGS_MAC |RTE_ETHTYPE_FLAGS_DROP )) -return -EINVAL ; - -if (add) { - etqf =IXGBE_ETQF_FILTER_EN | filter->ether_type; - etqs =IXGBE_ETQS_QUEUE_EN | - (((uint32_t )filter->queue <<IXGBE_ETQS_RX_QUEUE_SHIFT ) & -IXGBE_ETQS_RX_QUEUE ); - idx =ixgbe_ethertype_table_add (table, filter->ether_type, etqf, etqs); -if (idx <0 ) -return idx; - }else { - idx =ixgbe_ethertype_table_lookup (table, filter->ether_type); -if (idx <0 ) -return idx; -ixgbe_ethertype_table_del (table, idx); - etqf =0 ; - etqs =0 ; - } -ixgbe_ethertype_filter_program (hw, idx, etqf, etqs); -return 0 ; -} -static int ixgbe_dev_flow_ops_get(__rte_unused struct rte_eth_dev *dev,const struct rte_flow_ops **ops)
@@ -8414,27 +8364,6 @@ ixgbe_ntuple_filter_restore(struct rte_eth_dev *dev) } } -/* restore ethernet type filter */ -static inline void -ixgbe_ethertype_filter_restore (struct rte_eth_dev *dev) -{ -struct ixgbe_hw *hw =IXGBE_DEV_PRIVATE_TO_HW (dev->data->dev_private); -struct ixgbe_filter_info *filter_info = -IXGBE_DEV_PRIVATE_TO_FILTER_INFO (dev->data->dev_private); -int i; - -for (i =0 ; i <IXGBE_MAX_ETQF_FILTERS ; i++) { -/* skip over entries not managed by rte_flow */ -if (i == filter_info->timesync_idx || - i == filter_info->antispoof_idx|| - !filter_info->ethertype_table.entries[i].used) -continue ; -ixgbe_ethertype_filter_program (hw, i, - filter_info->ethertype_table.entries[i].etqf, - filter_info->ethertype_table.entries[i].etqs); - } -} -/* restore SYN filter */ static inline void ixgbe_syn_filter_restore (struct rte_eth_dev *dev)
@@ -8490,7 +8419,6 @@ static int ixgbe_filter_restore(struct rte_eth_dev *dev) {ixgbe_ntuple_filter_restore (dev); -ixgbe_ethertype_filter_restore (dev);ixgbe_syn_filter_restore (dev);ixgbe_fdir_filter_restore (dev);ixgbe_l2_tn_filter_restore (dev);
@@ -8529,26 +8457,6 @@ ixgbe_clear_all_ntuple_filter(struct rte_eth_dev *dev)ixgbe_remove_5tuple_filter (adapter, p_5tuple); } -/* remove all the ether type filters */ -void -ixgbe_clear_all_ethertype_filter (struct rte_eth_dev *dev) -{ -struct ixgbe_hw *hw =IXGBE_DEV_PRIVATE_TO_HW (dev->data->dev_private); -struct ixgbe_filter_info *filter_info = -IXGBE_DEV_PRIVATE_TO_FILTER_INFO (dev->data->dev_private); -int i; - -for (i =0 ; i <IXGBE_MAX_ETQF_FILTERS ; i++) { -/* only clear rte_flow filters */ -if (!filter_info->ethertype_table.entries[i].used || - (filter_info->timesync_installed && i == filter_info->timesync_idx) || - (filter_info->antispoof_installed && i == filter_info->antispoof_idx)) -continue ; -ixgbe_ethertype_table_del (&filter_info->ethertype_table, i); -ixgbe_ethertype_filter_program (hw, i,0 ,0 ); - } -} -/* remove the SYN filter */ void ixgbe_clear_syn_filter (struct rte_eth_dev *dev)
drivers/net/intel/ixgbe/ixgbe_ethdev.h +0 -4
@@ -676,9 +676,6 @@ bool ixgbe_rss_update_sp(enum ixgbe_mac_type mac_type);int ixgbe_add_del_ntuple_filter (struct ixgbe_adapter *adapter,struct rte_eth_ntuple_filter *filter,bool add); -int ixgbe_add_del_ethertype_filter (struct ixgbe_adapter *adapter, -struct rte_eth_ethertype_filter *filter, -bool add);int ixgbe_syn_filter_set (struct ixgbe_adapter *adapter,struct rte_eth_syn_filter *filter,bool add);
@@ -760,7 +757,6 @@ int ixgbe_clear_all_fdir_filter(struct rte_eth_dev *dev);extern const struct rte_flow_ops ixgbe_flow_ops; -void ixgbe_clear_all_ethertype_filter (struct rte_eth_dev *dev);void ixgbe_clear_all_ntuple_filter (struct rte_eth_dev *dev);void ixgbe_clear_syn_filter (struct rte_eth_dev *dev);int ixgbe_clear_all_l2_tn_filter (struct rte_eth_dev *dev);
drivers/net/intel/ixgbe/ixgbe_flow.c +6 -214
296 lines not on this page · raw message
drivers/net/intel/ixgbe/ixgbe_flow.h +8 -0
@@ -5,8 +5,16 @@#ifndef _IXGBE_FLOW_H_#define _IXGBE_FLOW_H_ +#include "../common/flow_check.h" #include "../common/flow_engine.h" +int +ixgbe_flow_actions_check (const struct ci_flow_actions *actions, +const struct ci_flow_actions_check_param *param, +struct rte_flow_error *error); +extern const struct ci_flow_engine_list ixgbe_flow_engine_list; +extern const struct ci_flow_engine ixgbe_ethertype_flow_engine; +#endif /* _IXGBE_FLOW_H_ */
drivers/net/intel/ixgbe/ixgbe_flow_ethertype.c new file +299 -0
299 lines not on this page · raw message
drivers/net/intel/ixgbe/meson.build +1 -0
@@ -26,6 +26,7 @@ sources += files( 'ixgbe_ethdev.c', 'ixgbe_fdir.c', 'ixgbe_flow.c', + 'ixgbe_flow_ethertype.c', 'ixgbe_ipsec.c', 'ixgbe_pf.c', 'ixgbe_rxtx.c',
Signature · 1 line
2.52.0
PATCH v5 8/25 net/ixgbe: fix syn filter priority
In reply to Anatoly BurakovIn rte_flow API, 0 means highest priority. Fix SYN filter priority being wrongly set to lower priority when API requests priority 0.
--- drivers/net/intel/ixgbe/ixgbe_flow.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
drivers/net/intel/ixgbe/ixgbe_flow.c +3 -3
@@ -804,10 +804,10 @@ cons_parse_syn_filter(const struct rte_flow_attr *attr, const struct rte_flow_it filter->queue = q_act->index;/* Support 2 priorities, the lowest or highest. */ -if (!attr->priority) { - filter->hig_pri =0 ; - }else if (attr->priority == (uint32_t )~0U ) { +if (attr->priority ==0 ) { filter->hig_pri =1 ; + }else if (attr->priority == (uint32_t )~0U ) { + filter->hig_pri =0 ; }else {memset (filter,0 ,sizeof (struct rte_eth_syn_filter )); rte_flow_error_set(error, EINVAL,
Signature · 1 line
2.52.0
PATCH v5 9/25 net/ixgbe: reimplement syn parser
In reply to Anatoly BurakovUse the new flow graph API and the common parsing framework to implement flow parser for SYN.
As a result of this migration, queue index validation has changed:
- queue is now validated at parse time against the configured number of Rx queues (nb_rx_queues), rather than at install time against the hardware maximum (IXGBE_MAX_RX_QUEUE_NUM)
- the per-function queue bound check in ixgbe_syn_filter_set() has been removed as it is no longer needed
The syn filter tracking infrastructure is moved completely inside the new engine and is removed from the rest of the driver.
--- drivers/net/intel/ixgbe/ixgbe_ethdev.c | 70 +---- drivers/net/intel/ixgbe/ixgbe_ethdev.h | 7 +- drivers/net/intel/ixgbe/ixgbe_flow.c | 249 +----------------- drivers/net/intel/ixgbe/ixgbe_flow.h | 1 + drivers/net/intel/ixgbe/ixgbe_flow_syn.c | 312 +++++++++++++++++++++++ drivers/net/intel/ixgbe/meson.build | 1 + 6 files changed, 319 insertions(+), 321 deletions(-) create mode 100644 drivers/net/intel/ixgbe/ixgbe_flow_syn.c
drivers/net/intel/ixgbe/ixgbe_ethdev.c +2 -68
@@ -6478,43 +6478,11 @@ ixgbevf_set_default_mac_addr(struct rte_eth_dev *dev,return 0 ; } -int -ixgbe_syn_filter_set (struct ixgbe_adapter *adapter, -struct rte_eth_syn_filter *filter, -bool add) +void +ixgbe_syn_filter_program (struct ixgbe_hw *hw,uint32_t synqf) { -struct ixgbe_hw *hw =IXGBE_DEV_PRIVATE_TO_HW (adapter); -struct ixgbe_filter_info *filter_info = -IXGBE_DEV_PRIVATE_TO_FILTER_INFO (adapter); -uint32_t syn_info; -uint32_t synqf; - -if (filter->queue >=IXGBE_MAX_RX_QUEUE_NUM ) -return -EINVAL ; - - syn_info = filter_info->syn_info; - -if (add) { -if (syn_info &IXGBE_SYN_FILTER_ENABLE ) -return -EINVAL ; - synqf = (uint32_t )(((filter->queue <<IXGBE_SYN_FILTER_QUEUE_SHIFT ) & -IXGBE_SYN_FILTER_QUEUE ) |IXGBE_SYN_FILTER_ENABLE ); - -if (filter->hig_pri) - synqf |=IXGBE_SYN_FILTER_SYNQFP ; -else - synqf &= ~IXGBE_SYN_FILTER_SYNQFP ; - }else { - synqf =IXGBE_READ_REG (hw,IXGBE_SYNQF ); -if (!(syn_info &IXGBE_SYN_FILTER_ENABLE )) -return -ENOENT ; - synqf &= ~(IXGBE_SYN_FILTER_QUEUE |IXGBE_SYN_FILTER_ENABLE ); - } - - filter_info->syn_info = synqf;IXGBE_WRITE_REG (hw,IXGBE_SYNQF , synqf);IXGBE_WRITE_FLUSH (hw); -return 0 ; }
@@ -8364,23 +8332,6 @@ ixgbe_ntuple_filter_restore(struct rte_eth_dev *dev) } } -/* restore SYN filter */ -static inline void -ixgbe_syn_filter_restore (struct rte_eth_dev *dev) -{ -struct ixgbe_hw *hw =IXGBE_DEV_PRIVATE_TO_HW (dev->data->dev_private); -struct ixgbe_filter_info *filter_info = -IXGBE_DEV_PRIVATE_TO_FILTER_INFO (dev->data->dev_private); -uint32_t synqf; - - synqf = filter_info->syn_info; - -if (synqf &IXGBE_SYN_FILTER_ENABLE ) { -IXGBE_WRITE_REG (hw,IXGBE_SYNQF , synqf); -IXGBE_WRITE_FLUSH (hw); - } -} -/* restore L2 tunnel filter */ static inline void ixgbe_l2_tn_filter_restore (struct rte_eth_dev *dev)
@@ -8419,7 +8370,6 @@ static int ixgbe_filter_restore(struct rte_eth_dev *dev) {ixgbe_ntuple_filter_restore (dev); -ixgbe_syn_filter_restore (dev);ixgbe_fdir_filter_restore (dev);ixgbe_l2_tn_filter_restore (dev);ixgbe_rss_filter_restore (dev);
@@ -8457,22 +8407,6 @@ ixgbe_clear_all_ntuple_filter(struct rte_eth_dev *dev)ixgbe_remove_5tuple_filter (adapter, p_5tuple); } -/* remove the SYN filter */ -void -ixgbe_clear_syn_filter (struct rte_eth_dev *dev) -{ -struct ixgbe_hw *hw =IXGBE_DEV_PRIVATE_TO_HW (dev->data->dev_private); -struct ixgbe_filter_info *filter_info = -IXGBE_DEV_PRIVATE_TO_FILTER_INFO (dev->data->dev_private); - -if (filter_info->syn_info &IXGBE_SYN_FILTER_ENABLE ) { - filter_info->syn_info =0 ; - -IXGBE_WRITE_REG (hw,IXGBE_SYNQF ,0 ); -IXGBE_WRITE_FLUSH (hw); - } -} -/* remove all the L2 tunnel filters */ int ixgbe_clear_all_l2_tn_filter (struct rte_eth_dev *dev)
drivers/net/intel/ixgbe/ixgbe_ethdev.h +1 -6
@@ -311,8 +311,6 @@ struct ixgbe_filter_info {/* Bit mask for every used 5tuple filter */ uint32_t fivetuple_mask[IXGBE_5TUPLE_ARRAY_SIZE ];struct ixgbe_5tuple_filter_list fivetuple_list; -/* store the SYN filter info */ -uint32_t syn_info;/* store the rss filter info */ struct ixgbe_rte_flow_rss_conf rss_info;/* shared EtherType (ETQF) slot table */
@@ -676,15 +674,13 @@ bool ixgbe_rss_update_sp(enum ixgbe_mac_type mac_type);int ixgbe_add_del_ntuple_filter (struct ixgbe_adapter *adapter,struct rte_eth_ntuple_filter *filter,bool add); -int ixgbe_syn_filter_set (struct ixgbe_adapter *adapter, -struct rte_eth_syn_filter *filter, -bool add);void ixgbe_ethertype_filter_program (struct ixgbe_hw *hw,uint8_t idx,uint32_t etqf,uint32_t etqs);int ixgbe_ethertype_table_add (struct ixgbe_ethertype_table *table,uint16_t ethertype,uint32_t etqf,uint32_t etqs);int ixgbe_ethertype_table_del (struct ixgbe_ethertype_table *table,uint8_t idx); +void ixgbe_syn_filter_program (struct ixgbe_hw *hw,uint32_t synqf);/** * l2 tunnel configuration.
@@ -758,7 +754,6 @@ int ixgbe_clear_all_fdir_filter(struct rte_eth_dev *dev);extern const struct rte_flow_ops ixgbe_flow_ops;void ixgbe_clear_all_ntuple_filter (struct rte_eth_dev *dev); -void ixgbe_clear_syn_filter (struct rte_eth_dev *dev);int ixgbe_clear_all_l2_tn_filter (struct rte_eth_dev *dev);int ixgbe_disable_sec_tx_path_generic (struct ixgbe_hw *hw);
drivers/net/intel/ixgbe/ixgbe_flow.c +2 -247
318 lines not on this page · raw message
drivers/net/intel/ixgbe/ixgbe_flow.h +1 -0
@@ -16,5 +16,6 @@ ixgbe_flow_actions_check(const struct ci_flow_actions *actions,extern const struct ci_flow_engine_list ixgbe_flow_engine_list;extern const struct ci_flow_engine ixgbe_ethertype_flow_engine; +extern const struct ci_flow_engine ixgbe_syn_flow_engine;#endif /* _IXGBE_FLOW_H_ */
drivers/net/intel/ixgbe/ixgbe_flow_syn.c new file +312 -0
312 lines not on this page · raw message
drivers/net/intel/ixgbe/meson.build +1 -0
@@ -27,6 +27,7 @@ sources += files( 'ixgbe_fdir.c', 'ixgbe_flow.c', 'ixgbe_flow_ethertype.c', + 'ixgbe_flow_syn.c', 'ixgbe_ipsec.c', 'ixgbe_pf.c', 'ixgbe_rxtx.c',
Signature · 1 line
2.52.0
PATCH v5 10/25 net/ixgbe: reimplement L2 tunnel parser
In reply to Anatoly BurakovUse the new flow graph API and the common parsing framework to implement flow parser for L2 tunnel.
There are two L2-tag-related features in the driver: the global per-port one, and the one that can direct traffic to specific queues (the one the engine targets). The former is left completely untouched, while the latter one is migrated to use engine infrastructure and use internal tracking.
--- drivers/net/intel/ixgbe/ixgbe_ethdev.c | 251 +--------------- drivers/net/intel/ixgbe/ixgbe_ethdev.h | 26 +- drivers/net/intel/ixgbe/ixgbe_flow.c | 210 +------------- drivers/net/intel/ixgbe/ixgbe_flow.h | 1 + drivers/net/intel/ixgbe/ixgbe_flow_l2tun.c | 322 +++++++++++++++++++++ drivers/net/intel/ixgbe/meson.build | 1 + 6 files changed, 332 insertions(+), 479 deletions(-) create mode 100644 drivers/net/intel/ixgbe/ixgbe_flow_l2tun.c
drivers/net/intel/ixgbe/ixgbe_ethdev.c +3 -248
@@ -150,7 +150,6 @@ static int eth_ixgbe_dev_uninit(struct rte_eth_dev *eth_dev);static int ixgbe_fdir_filter_init (struct rte_eth_dev *eth_dev);static int ixgbe_fdir_filter_uninit (struct rte_eth_dev *eth_dev);static int ixgbe_l2_tn_filter_init (struct rte_eth_dev *eth_dev); -static int ixgbe_l2_tn_filter_uninit (struct rte_eth_dev *eth_dev);static int ixgbe_ntuple_filter_uninit (struct rte_eth_dev *eth_dev);static int ixgbe_dev_configure (struct rte_eth_dev *dev);static int ixgbe_dev_start (struct rte_eth_dev *dev);
@@ -1284,7 +1283,7 @@ eth_ixgbe_dev_init(struct rte_eth_dev *eth_dev, void *init_params __rte_unused) ret =ci_flow_engine_conf_init (&ad->flow_engine_conf, &ixgbe_flow_engine_list, eth_dev->data);if (ret) - goto err_flow_engine_conf_init; + goto err_l2_tn_filter_init;/* initialize flow filter lists */ ixgbe_filterlist_init (eth_dev);
@@ -1297,8 +1296,6 @@ eth_ixgbe_dev_init(struct rte_eth_dev *eth_dev, void *init_params __rte_unused)return 0 ; -err_flow_engine_conf_init: -ixgbe_l2_tn_filter_uninit (eth_dev); err_l2_tn_filter_init:ixgbe_fdir_filter_uninit (eth_dev); err_fdir_filter_init:
@@ -1368,25 +1365,6 @@ static int ixgbe_fdir_filter_uninit(struct rte_eth_dev *eth_dev)return 0 ; } -static int ixgbe_l2_tn_filter_uninit (struct rte_eth_dev *eth_dev) -{ -struct ixgbe_l2_tn_info *l2_tn_info = -IXGBE_DEV_PRIVATE_TO_L2_TN_INFO (eth_dev->data->dev_private); -struct ixgbe_l2_tn_filter *l2_tn_filter; - -rte_free (l2_tn_info->hash_map); -rte_hash_free (l2_tn_info->hash_handle); - -while ((l2_tn_filter =TAILQ_FIRST (&l2_tn_info->l2_tn_list))) { -TAILQ_REMOVE (&l2_tn_info->l2_tn_list, - l2_tn_filter, - entries); -rte_free (l2_tn_filter); - } - -return 0 ; -} -static int ixgbe_fdir_filter_init (struct rte_eth_dev *eth_dev) { struct ixgbe_hw_fdir_info *fdir_info =
@@ -1432,34 +1410,7 @@ static int ixgbe_l2_tn_filter_init(struct rte_eth_dev *eth_dev) {struct ixgbe_l2_tn_info *l2_tn_info =IXGBE_DEV_PRIVATE_TO_L2_TN_INFO (eth_dev->data->dev_private); -char l2_tn_hash_name[RTE_HASH_NAMESIZE ]; -struct rte_hash_parameters l2_tn_hash_params = { - .name = l2_tn_hash_name, - .entries =IXGBE_MAX_L2_TN_FILTER_NUM , - .key_len =sizeof (struct ixgbe_l2_tn_key ), - .hash_func = rte_hash_crc, - .hash_func_init_val =0 , - .socket_id =rte_socket_id (), - }; -TAILQ_INIT (&l2_tn_info->l2_tn_list); -snprintf (l2_tn_hash_name,RTE_HASH_NAMESIZE , -"l2_tn_%s" , eth_dev->device->name); - l2_tn_info->hash_handle =rte_hash_create (&l2_tn_hash_params); -if (!l2_tn_info->hash_handle) { -PMD_INIT_LOG (ERR ,"Failed to create L2 TN hash table!" ); -return -EINVAL ; - } - l2_tn_info->hash_map =rte_zmalloc ("ixgbe" , -sizeof (struct ixgbe_l2_tn_filter *) * -IXGBE_MAX_L2_TN_FILTER_NUM , -0 ); -if (!l2_tn_info->hash_map) { -PMD_INIT_LOG (ERR , -"Failed to allocate memory for L2 TN hash map!" ); -rte_hash_free (l2_tn_info->hash_handle); -return -ENOMEM ; - } l2_tn_info->e_tag_en = FALSE; l2_tn_info->e_tag_fwd_en = FALSE; l2_tn_info->e_tag_ether_type =RTE_ETHER_TYPE_ETAG ;
@@ -3103,9 +3054,6 @@ ixgbe_dev_close(struct rte_eth_dev *dev)/* remove all the fdir filters & hash */ ixgbe_fdir_filter_uninit (dev); -/* remove all the L2 tunnel filters & hash */ -ixgbe_l2_tn_filter_uninit (dev); -/* Remove all ntuple filters of the device */ ixgbe_ntuple_filter_uninit (dev);
@@ -7708,7 +7656,7 @@ ixgbe_e_tag_enable(struct ixgbe_hw *hw)return 0 ; } -static int +int ixgbe_e_tag_filter_del (struct ixgbe_adapter *adapter,struct ixgbe_l2_tunnel_conf *l2_tunnel) {
@@ -7745,7 +7693,7 @@ ixgbe_e_tag_filter_del(struct ixgbe_adapter *adapter,return ret; } -static int +int ixgbe_e_tag_filter_add (struct ixgbe_adapter *adapter,struct ixgbe_l2_tunnel_conf *l2_tunnel) {
@@ -7787,154 +7735,6 @@ ixgbe_e_tag_filter_add(struct ixgbe_adapter *adapter,return -EINVAL ; } -static inline struct ixgbe_l2_tn_filter * -ixgbe_l2_tn_filter_lookup (struct ixgbe_l2_tn_info *l2_tn_info, -struct ixgbe_l2_tn_key *key) -{ -int ret; - - ret =rte_hash_lookup (l2_tn_info->hash_handle, (const void *)key); -if (ret <0 ) -return NULL ; - -return l2_tn_info->hash_map[ret]; -} - -static inline int -ixgbe_insert_l2_tn_filter (struct ixgbe_l2_tn_info *l2_tn_info, -struct ixgbe_l2_tn_filter *l2_tn_filter) -{ -int ret; - - ret =rte_hash_add_key (l2_tn_info->hash_handle, - &l2_tn_filter->key); - -if (ret <0 ) { -PMD_DRV_LOG (ERR , -"Failed to insert L2 tunnel filter" -" to hash table %d!" , - ret); -return ret; - } - - l2_tn_info->hash_map[ret] = l2_tn_filter; - -TAILQ_INSERT_TAIL (&l2_tn_info->l2_tn_list, l2_tn_filter, entries); - -return 0 ; -} - -static inline int -ixgbe_remove_l2_tn_filter (struct ixgbe_l2_tn_info *l2_tn_info, -struct ixgbe_l2_tn_key *key) -{ -int ret; -struct ixgbe_l2_tn_filter *l2_tn_filter; - - ret =rte_hash_del_key (l2_tn_info->hash_handle, key); - -if (ret <0 ) { -PMD_DRV_LOG (ERR , -"No such L2 tunnel filter to delete %d!" , - ret); -return ret; - } - - l2_tn_filter = l2_tn_info->hash_map[ret]; - l2_tn_info->hash_map[ret] =NULL ; - -TAILQ_REMOVE (&l2_tn_info->l2_tn_list, l2_tn_filter, entries); -rte_free (l2_tn_filter); - -return 0 ; -} - -/* Add l2 tunnel filter */ -int -ixgbe_dev_l2_tunnel_filter_add (struct ixgbe_adapter *adapter, -struct ixgbe_l2_tunnel_conf *l2_tunnel, -bool restore) -{ -int ret; -struct ixgbe_l2_tn_info *l2_tn_info = -IXGBE_DEV_PRIVATE_TO_L2_TN_INFO (adapter); -struct ixgbe_l2_tn_key key; -struct ixgbe_l2_tn_filter *node; - -if (!restore) { - key.l2_tn_type = l2_tunnel->l2_tunnel_type; - key.tn_id = l2_tunnel->tunnel_id; - - node =ixgbe_l2_tn_filter_lookup (l2_tn_info, &key); - -if (node) { -PMD_DRV_LOG (ERR , -"The L2 tunnel filter already exists!" ); -return -EINVAL ; - } - - node =rte_zmalloc ("ixgbe_l2_tn" , -sizeof (struct ixgbe_l2_tn_filter ), -0 ); -if (!node) -return -ENOMEM ; - -memcpy (&node->key, - &key, -sizeof (struct ixgbe_l2_tn_key )); - node->pool = l2_tunnel->pool; - ret =ixgbe_insert_l2_tn_filter (l2_tn_info, node); -if (ret <0 ) { -rte_free (node); -return ret; - } - } - -switch (l2_tunnel->l2_tunnel_type) { -case RTE_ETH_L2_TUNNEL_TYPE_E_TAG : - ret =ixgbe_e_tag_filter_add (adapter, l2_tunnel); -break ; -default : -PMD_DRV_LOG (ERR ,"Invalid tunnel type" ); - ret = -EINVAL ; -break ; - } - -if ((!restore) && (ret <0 )) - (void )ixgbe_remove_l2_tn_filter (l2_tn_info, &key); - -return ret; -} - -/* Delete l2 tunnel filter */ -int -ixgbe_dev_l2_tunnel_filter_del (struct ixgbe_adapter *adapter, -struct ixgbe_l2_tunnel_conf *l2_tunnel) -{ -int ret; -struct ixgbe_l2_tn_info *l2_tn_info = -IXGBE_DEV_PRIVATE_TO_L2_TN_INFO (adapter); -struct ixgbe_l2_tn_key key; - - key.l2_tn_type = l2_tunnel->l2_tunnel_type; - key.tn_id = l2_tunnel->tunnel_id; - ret =ixgbe_remove_l2_tn_filter (l2_tn_info, &key); -if (ret <0 ) -return ret; - -switch (l2_tunnel->l2_tunnel_type) { -case RTE_ETH_L2_TUNNEL_TYPE_E_TAG : - ret =ixgbe_e_tag_filter_del (adapter, l2_tunnel); -break ; -default : -PMD_DRV_LOG (ERR ,"Invalid tunnel type" ); - ret = -EINVAL ; -break ; - } - -return ret; -} -static int ixgbe_e_tag_forwarding_en_dis (struct rte_eth_dev *dev,bool en) {
@@ -8332,26 +8132,6 @@ ixgbe_ntuple_filter_restore(struct rte_eth_dev *dev) } } -/* restore L2 tunnel filter */ -static inline void -ixgbe_l2_tn_filter_restore (struct rte_eth_dev *dev) -{ -struct ixgbe_adapter *adapter = -IXGBE_DEV_PRIVATE_TO_ADAPTER (dev->data->dev_private); -struct ixgbe_l2_tn_info *l2_tn_info = -IXGBE_DEV_PRIVATE_TO_L2_TN_INFO (adapter); -struct ixgbe_l2_tn_filter *node; -struct ixgbe_l2_tunnel_conf l2_tn_conf; - - TAILQ_FOREACH(node, &l2_tn_info->l2_tn_list, entries) { - l2_tn_conf.l2_tunnel_type = node->key.l2_tn_type; - l2_tn_conf.tunnel_id = node->key.tn_id; - l2_tn_conf.pool = node->pool; - (void )ixgbe_dev_l2_tunnel_filter_add (adapter, - &l2_tn_conf, TRUE); - } -} -/* restore rss filter */ static inline void ixgbe_rss_filter_restore (struct rte_eth_dev *dev)
@@ -8371,7 +8151,6 @@ ixgbe_filter_restore(struct rte_eth_dev *dev) {ixgbe_ntuple_filter_restore (dev);ixgbe_fdir_filter_restore (dev); -ixgbe_l2_tn_filter_restore (dev);ixgbe_rss_filter_restore (dev);return 0 ;
@@ -8407,30 +8186,6 @@ ixgbe_clear_all_ntuple_filter(struct rte_eth_dev *dev)ixgbe_remove_5tuple_filter (adapter, p_5tuple); } -/* remove all the L2 tunnel filters */ -int -ixgbe_clear_all_l2_tn_filter (struct rte_eth_dev *dev) -{ -struct ixgbe_adapter *adapter = -IXGBE_DEV_PRIVATE_TO_ADAPTER (dev->data->dev_private); -struct ixgbe_l2_tn_info *l2_tn_info = -IXGBE_DEV_PRIVATE_TO_L2_TN_INFO (dev->data->dev_private); -struct ixgbe_l2_tn_filter *l2_tn_filter; -struct ixgbe_l2_tunnel_conf l2_tn_conf; -int ret =0 ; - -while ((l2_tn_filter =TAILQ_FIRST (&l2_tn_info->l2_tn_list))) { - l2_tn_conf.l2_tunnel_type = l2_tn_filter->key.l2_tn_type; - l2_tn_conf.tunnel_id = l2_tn_filter->key.tn_id; - l2_tn_conf.pool = l2_tn_filter->pool; - ret =ixgbe_dev_l2_tunnel_filter_del (adapter, &l2_tn_conf); -if (ret <0 ) -return ret; - } - -return 0 ; -} -void ixgbe_dev_macsec_setting_save (struct rte_eth_dev *dev,struct ixgbe_macsec_setting *macsec_setting)
drivers/net/intel/ixgbe/ixgbe_ethdev.h +4 -22
@@ -323,23 +323,7 @@ struct ixgbe_filter_info {uint8_t antispoof_idx; }; -struct ixgbe_l2_tn_key { -enum rte_eth_tunnel_type l2_tn_type; -uint32_t tn_id; -}; - -struct ixgbe_l2_tn_filter { -TAILQ_ENTRY (ixgbe_l2_tn_filter) entries; -struct ixgbe_l2_tn_key key; -uint32_t pool; -}; - -TAILQ_HEAD (ixgbe_l2_tn_filter_list, ixgbe_l2_tn_filter); -struct ixgbe_l2_tn_info { -struct ixgbe_l2_tn_filter_list l2_tn_list; -struct ixgbe_l2_tn_filter **hash_map; -struct rte_hash *hash_handle;bool e_tag_en;/* e-tag enabled */ bool e_tag_fwd_en;/* e-tag based forwarding enabled */ uint16_t e_tag_ether_type;/* ether type for e-tag */
@@ -694,12 +678,11 @@ struct ixgbe_l2_tunnel_conf { };int -ixgbe_dev_l2_tunnel_filter_add (struct ixgbe_adapter *adapter, -struct ixgbe_l2_tunnel_conf *l2_tunnel, -bool restore); +ixgbe_e_tag_filter_add (struct ixgbe_adapter *adapter, +struct ixgbe_l2_tunnel_conf *l2_tunnel);int -ixgbe_dev_l2_tunnel_filter_del (struct ixgbe_adapter *adapter, -struct ixgbe_l2_tunnel_conf *l2_tunnel); +ixgbe_e_tag_filter_del (struct ixgbe_adapter *adapter, +struct ixgbe_l2_tunnel_conf *l2_tunnel);void ixgbe_filterlist_init (struct rte_eth_dev *dev);void ixgbe_filterlist_flush (struct rte_eth_dev *dev);/*
@@ -754,7 +737,6 @@ int ixgbe_clear_all_fdir_filter(struct rte_eth_dev *dev);extern const struct rte_flow_ops ixgbe_flow_ops;void ixgbe_clear_all_ntuple_filter (struct rte_eth_dev *dev); -int ixgbe_clear_all_l2_tn_filter (struct rte_eth_dev *dev);int ixgbe_disable_sec_tx_path_generic (struct ixgbe_hw *hw);
drivers/net/intel/ixgbe/ixgbe_flow.c +1 -209
276 lines not on this page · raw message
drivers/net/intel/ixgbe/ixgbe_flow.h +1 -0
@@ -17,5 +17,6 @@ extern const struct ci_flow_engine_list ixgbe_flow_engine_list;extern const struct ci_flow_engine ixgbe_ethertype_flow_engine;extern const struct ci_flow_engine ixgbe_syn_flow_engine; +extern const struct ci_flow_engine ixgbe_l2_tunnel_flow_engine;#endif /* _IXGBE_FLOW_H_ */
drivers/net/intel/ixgbe/ixgbe_flow_l2tun.c new file +322 -0
322 lines not on this page · raw message
drivers/net/intel/ixgbe/meson.build +1 -0
@@ -28,6 +28,7 @@ sources += files( 'ixgbe_flow.c', 'ixgbe_flow_ethertype.c', 'ixgbe_flow_syn.c', + 'ixgbe_flow_l2tun.c', 'ixgbe_ipsec.c', 'ixgbe_pf.c', 'ixgbe_rxtx.c',
Signature · 1 line
2.52.0
PATCH v5 11/25 net/ixgbe: fix ntuple filter priority
In reply to Anatoly BurakovCurrently, handling of ntuple filter priority is incorrect: it directly translates values inside the valid range (001b-111b), and clamps all invalid to 1. This leads to equivalence between rte_flow highest priority value (0), and rte_flow lower priority values (8+), both of which are mapped to 1 (lowest priority), while the 1-7 range is reversed (in ntuple, 111b is highest priority, but in rte_flow it is the lowest).
Fix the calculation by
- Translating highest rte_flow priority to highest ntuple priority
- Only clamping low priority values to 1 (lowest priority)
- Reversing the 1-7 mapping to preserve semantic meaning
--- drivers/net/intel/ixgbe/ixgbe_flow.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-)
drivers/net/intel/ixgbe/ixgbe_flow.c +16 -3
@@ -209,6 +209,7 @@ cons_parse_ntuple_filter(const struct rte_flow_attr *attr,const struct rte_flow_item_vlan *vlan_mask;struct rte_flow_item_eth eth_null;struct rte_flow_item_vlan vlan_null; +uint16_t priority;/* Priority must be 16-bit */ if (attr->priority >UINT16_MAX ) {
@@ -503,9 +504,21 @@ cons_parse_ntuple_filter(const struct rte_flow_attr *attr, filter->queue = q_act->index; - filter->priority = (uint16_t )attr->priority; -if (attr->priority <IXGBE_MIN_N_TUPLE_PRIO || attr->priority >IXGBE_MAX_N_TUPLE_PRIO ) - filter->priority =1 ; +/* +* rte_flow priority: 0 through UINT32_MAX, 0 is highest +* +* ntuple priority: 001b through 111b, 111b is highest +* +* which means we need to transform priority from rte_flow to ntuple: +* +* 1) clamp max value +* 2) reverse +* 3) add min value +*/ + priority =RTE_MIN (IXGBE_MAX_N_TUPLE_PRIO -1 , (uint16_t )attr->priority); + priority =IXGBE_MAX_N_TUPLE_PRIO -1 - priority; + priority +=IXGBE_MIN_N_TUPLE_PRIO ; + filter->priority = priority;return 0 ; }
Signature · 1 line
2.52.0
PATCH v5 12/25 net/ixgbe: fix protocol-only ntuple parsing
In reply to Anatoly BurakovCurrently, when parsing ntuple flows, we may hit an empty L4 protocol item (i.e. one that does not have a mask or spec), in which case we just skip to the end. However, we do not set a protocol mask, which means we will not be matching L4 flows even though the flow structure implies that we should.
Fix it by setting up match-by-protocol when we have an empty L4 flow.
Additionally, there's a separate issue with how empty L4 protocol items are handled in that once we see one, we do not check whether there's anything else past it, and instead go straight to exit. This means that we might have any other flow item after L4 (e.g. ipv4 / tcp / gtp) and this will be silently accepted. Fix by enforcing that last item is END.
--- drivers/net/intel/ixgbe/ixgbe_flow.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-)
drivers/net/intel/ixgbe/ixgbe_flow.c +21 -1
@@ -358,9 +358,28 @@ cons_parse_ntuple_filter(const struct rte_flow_attr *attr,return -rte_errno; } +/* an empty L4 item still implies its protocol */ if ((item->type !=RTE_FLOW_ITEM_TYPE_END ) && (!item->spec && !item->mask)) { - goto action; +uint8_t proto; + +if (item->type ==RTE_FLOW_ITEM_TYPE_TCP ) + proto =IPPROTO_TCP ; +else if (item->type ==RTE_FLOW_ITEM_TYPE_UDP ) + proto =IPPROTO_UDP ; +else + proto =IPPROTO_SCTP ; + +if (filter->proto_mask !=0 && filter->proto != proto) { + *filter = (struct rte_eth_ntuple_filter ){0 }; +rte_flow_error_set (error,EINVAL , +RTE_FLOW_ERROR_TYPE_ITEM , + item,"L4 item conflicts with IPv4 protocol" ); +return -rte_errno; + } + filter->proto = proto; + filter->proto_mask =UINT8_MAX ; + goto check_end; }/* get the TCP/UDP/SCTP info */
@@ -490,6 +509,7 @@ cons_parse_ntuple_filter(const struct rte_flow_attr *attr, goto action; } +check_end:/* check if the next not void item is END */ item =next_no_void_pattern (pattern, item);if (item->type !=RTE_FLOW_ITEM_TYPE_END ) {
Signature · 1 line
2.52.0
PATCH v5 13/25 net/ixgbe: reimplement ntuple parser
In reply to Anatoly BurakovUse the new flow graph API and the common parsing framework to implement flow parser for ntuple.
The 5tuple filter tracking infrastructure is moved completely inside the new engine and is removed from the rest of the driver.
--- drivers/net/intel/ixgbe/ixgbe_ethdev.c | 348 +--------- drivers/net/intel/ixgbe/ixgbe_ethdev.h | 28 +- drivers/net/intel/ixgbe/ixgbe_flow.c | 498 +------------- drivers/net/intel/ixgbe/ixgbe_flow.h | 1 + drivers/net/intel/ixgbe/ixgbe_flow_ntuple.c | 694 ++++++++++++++++++++ drivers/net/intel/ixgbe/meson.build | 1 + 6 files changed, 724 insertions(+), 846 deletions(-) create mode 100644 drivers/net/intel/ixgbe/ixgbe_flow_ntuple.c
drivers/net/intel/ixgbe/ixgbe_ethdev.c +23 -325
@@ -150,7 +150,6 @@ static int eth_ixgbe_dev_uninit(struct rte_eth_dev *eth_dev);static int ixgbe_fdir_filter_init (struct rte_eth_dev *eth_dev);static int ixgbe_fdir_filter_uninit (struct rte_eth_dev *eth_dev);static int ixgbe_l2_tn_filter_init (struct rte_eth_dev *eth_dev); -static int ixgbe_ntuple_filter_uninit (struct rte_eth_dev *eth_dev);static int ixgbe_dev_configure (struct rte_eth_dev *dev);static int ixgbe_dev_start (struct rte_eth_dev *dev);static int ixgbe_dev_stop (struct rte_eth_dev *dev);
@@ -301,10 +300,6 @@ static int ixgbevf_add_mac_addr(struct rte_eth_dev *dev,static void ixgbevf_remove_mac_addr (struct rte_eth_dev *dev,uint32_t index);static int ixgbevf_set_default_mac_addr (struct rte_eth_dev *dev,struct rte_ether_addr *mac_addr); -static int ixgbe_add_5tuple_filter (struct ixgbe_adapter *adapter, -struct ixgbe_5tuple_filter *filter); -static void ixgbe_remove_5tuple_filter (struct ixgbe_adapter *adapter, -struct ixgbe_5tuple_filter *filter);static int ixgbe_dev_flow_ops_get (struct rte_eth_dev *dev,const struct rte_flow_ops **ops);static int ixgbevf_dev_set_mtu (struct rte_eth_dev *dev,uint16_t mtu);
@@ -1266,9 +1261,6 @@ eth_ixgbe_dev_init(struct rte_eth_dev *eth_dev, void *init_params __rte_unused)memset (filter_info,0 ,sizeof (struct ixgbe_filter_info )); -/* initialize 5tuple filter list */ -TAILQ_INIT (&filter_info->fivetuple_list); -/* initialize flow director filter list & hash */ ret =ixgbe_fdir_filter_init (eth_dev);if (ret)
@@ -1328,24 +1320,6 @@ eth_ixgbe_dev_uninit(struct rte_eth_dev *eth_dev)return 0 ; } -static int ixgbe_ntuple_filter_uninit (struct rte_eth_dev *eth_dev) -{ -struct ixgbe_filter_info *filter_info = -IXGBE_DEV_PRIVATE_TO_FILTER_INFO (eth_dev->data->dev_private); -struct ixgbe_5tuple_filter *p_5tuple; - -while ((p_5tuple =TAILQ_FIRST (&filter_info->fivetuple_list))) { -TAILQ_REMOVE (&filter_info->fivetuple_list, - p_5tuple, - entries); -rte_free (p_5tuple); - } -memset (filter_info->fivetuple_mask,0 , -sizeof (uint32_t ) *IXGBE_5TUPLE_ARRAY_SIZE ); - -return 0 ; -} -static int ixgbe_fdir_filter_uninit (struct rte_eth_dev *eth_dev) { struct ixgbe_hw_fdir_info *fdir_info =
@@ -3054,9 +3028,6 @@ ixgbe_dev_close(struct rte_eth_dev *dev)/* remove all the fdir filters & hash */ ixgbe_fdir_filter_uninit (dev); -/* Remove all ntuple filters of the device */ -ixgbe_ntuple_filter_uninit (dev); -/* clear all the filters list */ ixgbe_filterlist_flush (dev);
@@ -6433,134 +6404,50 @@ ixgbe_syn_filter_program(struct ixgbe_hw *hw, uint32_t synqf)IXGBE_WRITE_FLUSH (hw); } - -static inline enum ixgbe_5tuple_protocol -convert_protocol_type (uint8_t protocol_value) +/* program a single ntuple (5-tuple) filter slot into hardware */ +void +ixgbe_ntuple_filter_program (struct ixgbe_hw *hw,uint16_t index, +const struct ixgbe_5tuple_filter_info *filter_info, +uint16_t queue) { -if (protocol_value ==IPPROTO_TCP ) -return IXGBE_FILTER_PROTOCOL_TCP ; -else if (protocol_value ==IPPROTO_UDP ) -return IXGBE_FILTER_PROTOCOL_UDP ; -else if (protocol_value ==IPPROTO_SCTP ) -return IXGBE_FILTER_PROTOCOL_SCTP ; -else -return IXGBE_FILTER_PROTOCOL_NONE ; -} - -/* inject a 5-tuple filter to HW */ -static inline void -ixgbe_inject_5tuple_filter (struct ixgbe_adapter *adapter, -struct ixgbe_5tuple_filter *filter) -{ -struct ixgbe_hw *hw =IXGBE_DEV_PRIVATE_TO_HW (adapter); -int i;uint32_t ftqf, sdpqf;uint32_t l34timir =0 ;uint8_t mask =0xff ; - i = filter->index; + sdpqf = (uint32_t )(filter_info->dst_port <<IXGBE_SDPQF_DSTPORT_SHIFT ); + sdpqf = sdpqf | (filter_info->src_port &IXGBE_SDPQF_SRCPORT ); - sdpqf = (uint32_t )(filter->filter_info.dst_port << -IXGBE_SDPQF_DSTPORT_SHIFT ); - sdpqf = sdpqf | (filter->filter_info.src_port &IXGBE_SDPQF_SRCPORT ); - - ftqf = (uint32_t )(filter->filter_info.proto & -IXGBE_FTQF_PROTOCOL_MASK ); - ftqf |= (uint32_t )((filter->filter_info.priority & + ftqf = (uint32_t )(filter_info->proto &IXGBE_FTQF_PROTOCOL_MASK ); + ftqf |= (uint32_t )((filter_info->priority &IXGBE_FTQF_PRIORITY_MASK ) <<IXGBE_FTQF_PRIORITY_SHIFT ); -if (filter->filter_info.src_ip_mask ==0 )/* 0 means compare. */ +if (filter_info->src_ip_mask ==0 )/* 0 means compare. */ mask &=IXGBE_FTQF_SOURCE_ADDR_MASK ; -if (filter->filter_info.dst_ip_mask ==0 ) +if (filter_info->dst_ip_mask ==0 ) mask &=IXGBE_FTQF_DEST_ADDR_MASK ; -if (filter->filter_info.src_port_mask ==0 ) +if (filter_info->src_port_mask ==0 ) mask &=IXGBE_FTQF_SOURCE_PORT_MASK ; -if (filter->filter_info.dst_port_mask ==0 ) +if (filter_info->dst_port_mask ==0 ) mask &=IXGBE_FTQF_DEST_PORT_MASK ; -if (filter->filter_info.proto_mask ==0 ) +if (filter_info->proto_mask ==0 ) mask &=IXGBE_FTQF_PROTOCOL_COMP_MASK ; ftqf |= mask <<IXGBE_FTQF_5TUPLE_MASK_SHIFT ; ftqf |=IXGBE_FTQF_POOL_MASK_EN ; ftqf |=IXGBE_FTQF_QUEUE_ENABLE ; -IXGBE_WRITE_REG (hw,IXGBE_DAQF (i), filter->filter_info.dst_ip); -IXGBE_WRITE_REG (hw,IXGBE_SAQF (i), filter->filter_info.src_ip); -IXGBE_WRITE_REG (hw,IXGBE_SDPQF (i), sdpqf); -IXGBE_WRITE_REG (hw,IXGBE_FTQF (i), ftqf); +IXGBE_WRITE_REG (hw,IXGBE_DAQF (index), filter_info->dst_ip); +IXGBE_WRITE_REG (hw,IXGBE_SAQF (index), filter_info->src_ip); +IXGBE_WRITE_REG (hw,IXGBE_SDPQF (index), sdpqf); +IXGBE_WRITE_REG (hw,IXGBE_FTQF (index), ftqf); l34timir |=IXGBE_L34T_IMIR_RESERVE ; - l34timir |= (uint32_t )(filter->queue << -IXGBE_L34T_IMIR_QUEUE_SHIFT ); -IXGBE_WRITE_REG (hw,IXGBE_L34T_IMIR (i), l34timir); + l34timir |= (uint32_t )(queue <<IXGBE_L34T_IMIR_QUEUE_SHIFT ); +IXGBE_WRITE_REG (hw,IXGBE_L34T_IMIR (index), l34timir); } -/* -* add a 5tuple filter -* -* @param -* dev: Pointer to struct rte_eth_dev. -* index: the index the filter allocates. -* filter: pointer to the filter that will be added. -* rx_queue: the queue id the filter assigned to. -* -* @return -* - On success, zero. -* - On failure, a negative value. -*/ -static int -ixgbe_add_5tuple_filter (struct ixgbe_adapter *adapter, -struct ixgbe_5tuple_filter *filter) +/* clear a single ntuple (5-tuple) filter slot from hardware */ +void +ixgbe_ntuple_filter_clear (struct ixgbe_hw *hw,uint16_t index) { -struct ixgbe_filter_info *filter_info = -IXGBE_DEV_PRIVATE_TO_FILTER_INFO (adapter); -int i, idx, shift; - -/* -* look for an unused 5tuple filter index, -* and insert the filter to list. -*/ -for (i =0 ; i <IXGBE_MAX_FTQF_FILTERS ; i++) { - idx = i / (sizeof (uint32_t ) *NBBY ); - shift = i % (sizeof (uint32_t ) *NBBY ); -if (!(filter_info->fivetuple_mask[idx] & (1 << shift))) { - filter_info->fivetuple_mask[idx] |=1 << shift; - filter->index = i; -TAILQ_INSERT_TAIL (&filter_info->fivetuple_list, - filter, - entries); -break ; - } - } -if (i >=IXGBE_MAX_FTQF_FILTERS ) { -PMD_DRV_LOG (ERR ,"5tuple filters are full." ); -return -ENOSYS ; - } - -ixgbe_inject_5tuple_filter (adapter, filter); - -return 0 ; -} - -/* -* remove a 5tuple filter -* -* @param -* dev: Pointer to struct rte_eth_dev. -* filter: the pointer of the filter will be removed. -*/ -static void -ixgbe_remove_5tuple_filter (struct ixgbe_adapter *adapter, -struct ixgbe_5tuple_filter *filter) -{ -struct ixgbe_hw *hw =IXGBE_DEV_PRIVATE_TO_HW (adapter); -struct ixgbe_filter_info *filter_info = -IXGBE_DEV_PRIVATE_TO_FILTER_INFO (adapter); -uint16_t index = filter->index; - - filter_info->fivetuple_mask[index / (sizeof (uint32_t ) *NBBY )] &= - ~(1 << (index % (sizeof (uint32_t ) *NBBY ))); -TAILQ_REMOVE (&filter_info->fivetuple_list, filter, entries); -rte_free (filter); -IXGBE_WRITE_REG (hw,IXGBE_DAQF (index),0 );IXGBE_WRITE_REG (hw,IXGBE_SAQF (index),0 );IXGBE_WRITE_REG (hw,IXGBE_SDPQF (index),0 );
@@ -6613,165 +6500,6 @@ ixgbevf_dev_set_mtu(struct rte_eth_dev *dev, uint16_t mtu)return 0 ; } -static inline struct ixgbe_5tuple_filter * -ixgbe_5tuple_filter_lookup (struct ixgbe_5tuple_filter_list *filter_list, -struct ixgbe_5tuple_filter_info *key) -{ -struct ixgbe_5tuple_filter *it; - - TAILQ_FOREACH(it, filter_list, entries) { -if (memcmp (key, &it->filter_info, -sizeof (struct ixgbe_5tuple_filter_info )) ==0 ) { -return it; - } - } -return NULL ; -} - -/* translate elements in struct rte_eth_ntuple_filter to struct ixgbe_5tuple_filter_info*/ -static inline int -ntuple_filter_to_5tuple (struct rte_eth_ntuple_filter *filter, -struct ixgbe_5tuple_filter_info *filter_info) -{ -if (filter->queue >=IXGBE_MAX_RX_QUEUE_NUM || - filter->priority >IXGBE_5TUPLE_MAX_PRI || - filter->priority <IXGBE_5TUPLE_MIN_PRI ) -return -EINVAL ; - -switch (filter->dst_ip_mask) { -case UINT32_MAX : - filter_info->dst_ip_mask =0 ; - filter_info->dst_ip = filter->dst_ip; -break ; -case 0 : - filter_info->dst_ip_mask =1 ; -break ; -default : -PMD_DRV_LOG (ERR ,"invalid dst_ip mask." ); -return -EINVAL ; - } - -switch (filter->src_ip_mask) { -case UINT32_MAX : - filter_info->src_ip_mask =0 ; - filter_info->src_ip = filter->src_ip; -break ; -case 0 : - filter_info->src_ip_mask =1 ; -break ; -default : -PMD_DRV_LOG (ERR ,"invalid src_ip mask." ); -return -EINVAL ; - } - -switch (filter->dst_port_mask) { -case UINT16_MAX : - filter_info->dst_port_mask =0 ; - filter_info->dst_port = filter->dst_port; -break ; -case 0 : - filter_info->dst_port_mask =1 ; -break ; -default : -PMD_DRV_LOG (ERR ,"invalid dst_port mask." ); -return -EINVAL ; - } - -switch (filter->src_port_mask) { -case UINT16_MAX : - filter_info->src_port_mask =0 ; - filter_info->src_port = filter->src_port; -break ; -case 0 : - filter_info->src_port_mask =1 ; -break ; -default : -PMD_DRV_LOG (ERR ,"invalid src_port mask." ); -return -EINVAL ; - } - -switch (filter->proto_mask) { -case UINT8_MAX : - filter_info->proto_mask =0 ; - filter_info->proto = -convert_protocol_type (filter->proto); -break ; -case 0 : - filter_info->proto_mask =1 ; -break ; -default : -PMD_DRV_LOG (ERR ,"invalid protocol mask." ); -return -EINVAL ; - } - - filter_info->priority = (uint8_t )filter->priority; -return 0 ; -} - -/* -* add or delete a ntuple filter -* -* @param -* dev: Pointer to struct rte_eth_dev. -* ntuple_filter: Pointer to struct rte_eth_ntuple_filter -* add: if true, add filter, if false, remove filter -* -* @return -* - On success, zero. -* - On failure, a negative value. -*/ -int -ixgbe_add_del_ntuple_filter (struct ixgbe_adapter *adapter, -struct rte_eth_ntuple_filter *ntuple_filter, -bool add) -{ -struct ixgbe_filter_info *filter_info = -IXGBE_DEV_PRIVATE_TO_FILTER_INFO (adapter); -struct ixgbe_5tuple_filter_info filter_5tuple; -struct ixgbe_5tuple_filter *filter; -int ret; - -if (ntuple_filter->flags !=RTE_5TUPLE_FLAGS ) { -PMD_DRV_LOG (ERR ,"only 5tuple is supported." ); -return -EINVAL ; - } - -memset (&filter_5tuple,0 ,sizeof (struct ixgbe_5tuple_filter_info )); - ret =ntuple_filter_to_5tuple (ntuple_filter, &filter_5tuple); -if (ret <0 ) -return ret; - - filter =ixgbe_5tuple_filter_lookup (&filter_info->fivetuple_list, - &filter_5tuple); -if (filter !=NULL && add) { -PMD_DRV_LOG (ERR ,"filter exists." ); -return -EEXIST ; - } -if (filter ==NULL && !add) { -PMD_DRV_LOG (ERR ,"filter doesn't exist." ); -return -ENOENT ; - } - -if (add) { - filter =rte_zmalloc ("ixgbe_5tuple_filter" , -sizeof (struct ixgbe_5tuple_filter ),0 ); -if (filter ==NULL ) -return -ENOMEM ; -memcpy (&filter->filter_info, - &filter_5tuple, -sizeof (struct ixgbe_5tuple_filter_info )); - filter->queue = ntuple_filter->queue; - ret =ixgbe_add_5tuple_filter (adapter, filter); -if (ret <0 ) { -rte_free (filter); -return ret; - } - }else -ixgbe_remove_5tuple_filter (adapter, filter); - -return 0 ; -} -void ixgbe_ethertype_filter_program (struct ixgbe_hw *hw,uint8_t idx,uint32_t etqf,uint32_t etqs)
@@ -8117,21 +7845,6 @@ int ixgbe_enable_sec_tx_path_generic(struct ixgbe_hw *hw)return IXGBE_SUCCESS ; } -/* restore n-tuple filter */ -static inline void -ixgbe_ntuple_filter_restore (struct rte_eth_dev *dev) -{ -struct ixgbe_adapter *adapter = -IXGBE_DEV_PRIVATE_TO_ADAPTER (dev->data->dev_private); -struct ixgbe_filter_info *filter_info = -IXGBE_DEV_PRIVATE_TO_FILTER_INFO (dev->data->dev_private); -struct ixgbe_5tuple_filter *node; - - TAILQ_FOREACH(node, &filter_info->fivetuple_list, entries) { -ixgbe_inject_5tuple_filter (adapter, node); - } -} -/* restore rss filter */ static inline void ixgbe_rss_filter_restore (struct rte_eth_dev *dev)
@@ -8149,7 +7862,6 @@ ixgbe_rss_filter_restore(struct rte_eth_dev *dev)static int ixgbe_filter_restore (struct rte_eth_dev *dev) { -ixgbe_ntuple_filter_restore (dev);ixgbe_fdir_filter_restore (dev);ixgbe_rss_filter_restore (dev);
@@ -8172,20 +7884,6 @@ ixgbe_l2_tunnel_conf(struct rte_eth_dev *dev) (void )ixgbe_update_e_tag_eth_type (hw, l2_tn_info->e_tag_ether_type); } -/* remove all the n-tuple filters */ -void -ixgbe_clear_all_ntuple_filter (struct rte_eth_dev *dev) -{ -struct ixgbe_adapter *adapter = -IXGBE_DEV_PRIVATE_TO_ADAPTER (dev->data->dev_private); -struct ixgbe_filter_info *filter_info = -IXGBE_DEV_PRIVATE_TO_FILTER_INFO (dev->data->dev_private); -struct ixgbe_5tuple_filter *p_5tuple; - -while ((p_5tuple =TAILQ_FIRST (&filter_info->fivetuple_list))) -ixgbe_remove_5tuple_filter (adapter, p_5tuple); -} -void ixgbe_dev_macsec_setting_save (struct rte_eth_dev *dev,struct ixgbe_macsec_setting *macsec_setting)
drivers/net/intel/ixgbe/ixgbe_ethdev.h +4 -24
@@ -100,8 +100,6 @@#define IXGBE_L34T_IMIR_LLI 0x00100000#define IXGBE_L34T_IMIR_QUEUE 0x0FE00000#define IXGBE_L34T_IMIR_QUEUE_SHIFT 21 -#define IXGBE_5TUPLE_MAX_PRI 7 -#define IXGBE_5TUPLE_MIN_PRI 1/* The overhead from MTU to max frame size. */ #define IXGBE_ETH_OVERHEAD (RTE_ETHER_HDR_LEN + RTE_ETHER_CRC_LEN)
@@ -265,8 +263,6 @@ enum ixgbe_5tuple_protocol { IXGBE_FILTER_PROTOCOL_NONE, }; -TAILQ_HEAD (ixgbe_5tuple_filter_list, ixgbe_5tuple_filter); -struct ixgbe_5tuple_filter_info {uint32_t dst_ip;uint32_t src_ip;
@@ -282,18 +278,6 @@ struct ixgbe_5tuple_filter_info { proto_mask:1 ;/* if mask is 1b, do not compare protocol. */ }; -/* 5tuple filter structure */ -struct ixgbe_5tuple_filter { -TAILQ_ENTRY (ixgbe_5tuple_filter) entries; -uint16_t index;/* the index of 5tuple filter */ -struct ixgbe_5tuple_filter_info filter_info; -uint16_t queue;/* rx queue assigned to */ -}; - -#define IXGBE_5TUPLE_ARRAY_SIZE \ - (RTE_ALIGN(IXGBE_MAX_FTQF_FILTERS, (sizeof(uint32_t) * NBBY)) / \ - (sizeof(uint32_t) * NBBY)) -/* Shared EtherType (ETQF) filter table. */ struct ixgbe_ethertype_table { struct ixgbe_ethertype_entry {
@@ -308,9 +292,6 @@ struct ixgbe_ethertype_table {* Structure to store filters' info. */ struct ixgbe_filter_info { -/* Bit mask for every used 5tuple filter */ -uint32_t fivetuple_mask[IXGBE_5TUPLE_ARRAY_SIZE ]; -struct ixgbe_5tuple_filter_list fivetuple_list;/* store the rss filter info */ struct ixgbe_rte_flow_rss_conf rss_info;/* shared EtherType (ETQF) slot table */
@@ -655,9 +636,10 @@ uint32_t ixgbe_rssrk_reg_get(enum ixgbe_mac_type mac_type, uint8_t i);bool ixgbe_rss_update_sp (enum ixgbe_mac_type mac_type); -int ixgbe_add_del_ntuple_filter (struct ixgbe_adapter *adapter, -struct rte_eth_ntuple_filter *filter, -bool add); +void ixgbe_ntuple_filter_program (struct ixgbe_hw *hw,uint16_t index, +const struct ixgbe_5tuple_filter_info *filter_info, +uint16_t queue); +void ixgbe_ntuple_filter_clear (struct ixgbe_hw *hw,uint16_t index);void ixgbe_ethertype_filter_program (struct ixgbe_hw *hw,uint8_t idx,uint32_t etqf,uint32_t etqs);
@@ -736,8 +718,6 @@ int ixgbe_clear_all_fdir_filter(struct rte_eth_dev *dev);extern const struct rte_flow_ops ixgbe_flow_ops; -void ixgbe_clear_all_ntuple_filter (struct rte_eth_dev *dev); -int ixgbe_disable_sec_tx_path_generic (struct ixgbe_hw *hw);int ixgbe_enable_sec_tx_path_generic (struct ixgbe_hw *hw);
drivers/net/intel/ixgbe/ixgbe_flow.c +1 -497
588 lines not on this page · raw message
drivers/net/intel/ixgbe/ixgbe_flow.h +1 -0
@@ -18,5 +18,6 @@ extern const struct ci_flow_engine_list ixgbe_flow_engine_list;extern const struct ci_flow_engine ixgbe_ethertype_flow_engine;extern const struct ci_flow_engine ixgbe_syn_flow_engine;extern const struct ci_flow_engine ixgbe_l2_tunnel_flow_engine; +extern const struct ci_flow_engine ixgbe_ntuple_flow_engine;#endif /* _IXGBE_FLOW_H_ */
drivers/net/intel/ixgbe/ixgbe_flow_ntuple.c new file +694 -0
694 lines not on this page · raw message
drivers/net/intel/ixgbe/meson.build +1 -0
@@ -29,6 +29,7 @@ sources += files( 'ixgbe_flow_ethertype.c', 'ixgbe_flow_syn.c', 'ixgbe_flow_l2tun.c', + 'ixgbe_flow_ntuple.c', 'ixgbe_ipsec.c', 'ixgbe_pf.c', 'ixgbe_rxtx.c',
Signature · 1 line
2.52.0
PATCH v5 14/25 net/ixgbe: reimplement security parser
In reply to Anatoly BurakovUse the new flow graph API and common flow engine infrastructure to implement flow parser for security filter. As a result, flow item checks have become more stringent:
- Mask is now explicitly validated to not have unsupported items in it, when previously they were ignored
- Mask is also validated to mask src/dst addresses, as otherwise it is inconsistent with rte_flow API
- The security engine was only looking for IPv4/IPv6 pattern items and completely ignored both prefix and suffix. This logic has been replaced by allowing [ETH]/IP/[UDP|ESP] patterns, as is used in ipsec-gw app
Previously, security parser was a special case, now it is a first class citizen. All decryption SA tracking has been moved into the engine, as the engine is now the authoritative source of new Rx flows and the state of the Rx SA table (the Tx SA table is still up to IPsec code to manage).
Because IPsec code does not manage the Rx SA table now, a synchronization mechanism is needed to prevent IPsec code from deallocating a security session when it is still referenced by security flows, so the security session is now atomically refcounted. For Tx, the refcount is effectively a noop, whereas for Rx it is now managed by rte_flow security engine.
--- drivers/net/intel/ixgbe/ixgbe_ethdev.h | 2 - drivers/net/intel/ixgbe/ixgbe_flow.c | 120 +--- drivers/net/intel/ixgbe/ixgbe_flow.h | 1 + drivers/net/intel/ixgbe/ixgbe_flow_security.c | 586 ++++++++++++++++++ drivers/net/intel/ixgbe/ixgbe_ipsec.c | 361 +++++------ drivers/net/intel/ixgbe/ixgbe_ipsec.h | 50 +- drivers/net/intel/ixgbe/meson.build | 1 + 7 files changed, 773 insertions(+), 348 deletions(-) create mode 100644 drivers/net/intel/ixgbe/ixgbe_flow_security.c
drivers/net/intel/ixgbe/ixgbe_ethdev.h +0 -2
@@ -313,8 +313,6 @@ struct ixgbe_l2_tn_info {struct rte_flow {struct ci_flow flow;enum rte_filter_type filter_type; -/* security flows are not rte_filter_type */ -bool is_security;void *rule; };
drivers/net/intel/ixgbe/ixgbe_flow.c +2 -118
174 lines not on this page · raw message
drivers/net/intel/ixgbe/ixgbe_flow.h +1 -0
@@ -19,5 +19,6 @@ extern const struct ci_flow_engine ixgbe_ethertype_flow_engine;extern const struct ci_flow_engine ixgbe_syn_flow_engine;extern const struct ci_flow_engine ixgbe_l2_tunnel_flow_engine;extern const struct ci_flow_engine ixgbe_ntuple_flow_engine; +extern const struct ci_flow_engine ixgbe_security_flow_engine;#endif /* _IXGBE_FLOW_H_ */
drivers/net/intel/ixgbe/ixgbe_flow_security.c new file +586 -0
586 lines not on this page · raw message
drivers/net/intel/ixgbe/ixgbe_ipsec.c +161 -200
444 lines not on this page · raw message
drivers/net/intel/ixgbe/ixgbe_ipsec.h +22 -28
91 lines not on this page · raw message
drivers/net/intel/ixgbe/meson.build +1 -0
@@ -30,6 +30,7 @@ sources += files( 'ixgbe_flow_syn.c', 'ixgbe_flow_l2tun.c', 'ixgbe_flow_ntuple.c', + 'ixgbe_flow_security.c', 'ixgbe_ipsec.c', 'ixgbe_pf.c', 'ixgbe_rxtx.c',
Signature · 1 line
2.52.0
PATCH v5 15/25 net/ixgbe: reimplement FDIR parser
In reply to Anatoly BurakovUse the new flow graph API and the common parsing framework to implement flow parser for flow director.
The FDIR flow tracking is moved inside the new engine, and the FDIR code is refactored to not mix software tracking with HW writes, remove redundant state and configuration stages, and structure the state storage better.
--- drivers/net/intel/ixgbe/ixgbe_ethdev.c | 117 +- drivers/net/intel/ixgbe/ixgbe_ethdev.h | 98 +- drivers/net/intel/ixgbe/ixgbe_fdir.c | 610 ++----- drivers/net/intel/ixgbe/ixgbe_flow.c | 1605 +---------------- drivers/net/intel/ixgbe/ixgbe_flow.h | 2 + drivers/net/intel/ixgbe/ixgbe_flow_fdir.c | 1602 ++++++++++++++++ .../net/intel/ixgbe/ixgbe_rxtx_vec_common.c | 4 +- drivers/net/intel/ixgbe/meson.build | 1 + 8 files changed, 1894 insertions(+), 2145 deletions(-) create mode 100644 drivers/net/intel/ixgbe/ixgbe_flow_fdir.c
drivers/net/intel/ixgbe/ixgbe_ethdev.c +53 -64
@@ -147,8 +147,6 @@ static const char * const ixgbevf_valid_arguments[] = {static int eth_ixgbe_dev_init (struct rte_eth_dev *eth_dev,void *init_params);static int eth_ixgbe_dev_uninit (struct rte_eth_dev *eth_dev); -static int ixgbe_fdir_filter_init (struct rte_eth_dev *eth_dev); -static int ixgbe_fdir_filter_uninit (struct rte_eth_dev *eth_dev);static int ixgbe_l2_tn_filter_init (struct rte_eth_dev *eth_dev);static int ixgbe_dev_configure (struct rte_eth_dev *dev);static int ixgbe_dev_start (struct rte_eth_dev *dev);
@@ -1008,7 +1006,7 @@ ixgbe_parse_devargs(struct ixgbe_adapter *adapter, &pballoc) != 0) ret = -EINVAL ; else - adapter->fdir_conf.pballoc = pballoc; + adapter->fdir_hw_config.pballoc = pballoc; }rte_kvargs_free (kvlist);
@@ -1261,11 +1259,6 @@ eth_ixgbe_dev_init(struct rte_eth_dev *eth_dev, void *init_params __rte_unused)memset (filter_info,0 ,sizeof (struct ixgbe_filter_info )); -/* initialize flow director filter list & hash */ - ret =ixgbe_fdir_filter_init (eth_dev); -if (ret) - goto err_fdir_filter_init; -/* initialize l2 tunnel filter list & hash */ ret =ixgbe_l2_tn_filter_init (eth_dev);if (ret)
@@ -1289,8 +1282,6 @@ eth_ixgbe_dev_init(struct rte_eth_dev *eth_dev, void *init_params __rte_unused)return 0 ; err_l2_tn_filter_init: -ixgbe_fdir_filter_uninit (eth_dev); -err_fdir_filter_init:ixgbe_disable_intr (hw);rte_intr_disable (intr_handle); rte_intr_callback_unregister(intr_handle,
@@ -1320,31 +1311,24 @@ eth_ixgbe_dev_uninit(struct rte_eth_dev *eth_dev)return 0 ; } -static int ixgbe_fdir_filter_uninit (struct rte_eth_dev *eth_dev) +void +ixgbe_fdir_state_detach (struct ixgbe_fdir_state *state) { -struct ixgbe_hw_fdir_info *fdir_info = -IXGBE_DEV_PRIVATE_TO_FDIR_INFO (eth_dev->data->dev_private); -struct ixgbe_fdir_filter *fdir_filter; +if (!ci_usage_count_release (&state->engine_use_count)) +return ; -rte_free (fdir_info->hash_map); -rte_hash_free (fdir_info->hash_handle); +rte_hash_free (state->hash_handle); -while ((fdir_filter =TAILQ_FIRST (&fdir_info->fdir_list))) { -TAILQ_REMOVE (&fdir_info->fdir_list, - fdir_filter, - entries); -rte_free (fdir_filter); - } - -return 0 ; + *state = (struct ixgbe_fdir_state ){0 }; } -static int ixgbe_fdir_filter_init (struct rte_eth_dev *eth_dev) +struct ixgbe_fdir_state * +ixgbe_fdir_state_attach (struct rte_eth_dev_data *dev_data) { -struct ixgbe_hw_fdir_info *fdir_info = -IXGBE_DEV_PRIVATE_TO_FDIR_INFO (eth_dev->data->dev_private); +struct ixgbe_adapter *adapter =IXGBE_DEV_PRIVATE_TO_ADAPTER (dev_data->dev_private); +struct ixgbe_fdir_state *state = &adapter->fdir_state;char fdir_hash_name[RTE_HASH_NAMESIZE ]; -struct rte_hash_parameters fdir_hash_params = { +struct rte_hash_parameters hash_params = { .name = fdir_hash_name, .entries =IXGBE_MAX_FDIR_FILTER_NUM , .key_len =sizeof (union ixgbe_atr_input ),
@@ -1353,31 +1337,28 @@ static int ixgbe_fdir_filter_init(struct rte_eth_dev *eth_dev) .socket_id = rte_socket_id(), }; -TAILQ_INIT (&fdir_info->fdir_list); -snprintf (fdir_hash_name,RTE_HASH_NAMESIZE , -"fdir_%s" , eth_dev->device->name); - fdir_info->hash_handle =rte_hash_create (&fdir_hash_params); -if (!fdir_info->hash_handle) { -PMD_INIT_LOG (ERR ,"Failed to create fdir hash table!" ); -return -EINVAL ; - } - fdir_info->hash_map =rte_zmalloc ("ixgbe" , -sizeof (struct ixgbe_fdir_filter *) * -IXGBE_MAX_FDIR_FILTER_NUM , -0 ); -if (!fdir_info->hash_map) { -PMD_INIT_LOG (ERR , -"Failed to allocate memory for fdir hash map!" ); -rte_hash_free (fdir_info->hash_handle); -return -ENOMEM ; - } - fdir_info->n_flows =0 ; - fdir_info->mask_added = FALSE; +snprintf (fdir_hash_name,RTE_HASH_NAMESIZE ,"ixgbe_fdir_hash_%s" , + dev_data->name); + +if (ci_usage_count_claim (&state->engine_use_count)) { +struct rte_hash *hash_handle; + + hash_handle =rte_hash_create (&hash_params); -/* drop queue is always fixed */ -IXGBE_DEV_FDIR_CONF (eth_dev)->drop_queue =IXGBE_FDIR_DROP_QUEUE ; +if (hash_handle ==NULL ) { +PMD_INIT_LOG (ERR ,"Failed to create fdir hash table!" ); +ci_usage_count_release (&state->engine_use_count); +return NULL ; + } + + state->hash_handle = hash_handle; + state->config.mode =RTE_FDIR_MODE_NONE ; + +/* set up default values for the mask */ +ixgbe_fdir_mask_set_default (&state->mask_conf.mask); + } -return 0 ; +return state; }static int ixgbe_l2_tn_filter_init (struct rte_eth_dev *eth_dev)
@@ -2177,9 +2158,27 @@ ixgbe_check_mq_mode(struct rte_eth_dev *dev) {struct rte_eth_conf *dev_conf = &dev->data->dev_conf;struct ixgbe_hw *hw =IXGBE_DEV_PRIVATE_TO_HW (dev->data->dev_private); +struct ixgbe_adapter *adapter =IXGBE_DEV_PRIVATE_TO_ADAPTER (dev->data->dev_private);uint16_t nb_rx_q = dev->data->nb_rx_queues;uint16_t nb_tx_q = dev->data->nb_tx_queues; +/* DCB-family modes reprogram RXPBSIZE and clash with FDIR's own use of it */ +switch (dev_conf->rxmode.mq_mode) { +case RTE_ETH_MQ_RX_VMDQ_DCB : +case RTE_ETH_MQ_RX_DCB : +case RTE_ETH_MQ_RX_DCB_RSS : +case RTE_ETH_MQ_RX_VMDQ_DCB_RSS : +if (adapter->fdir_state.config.mode !=RTE_FDIR_MODE_NONE ) { +PMD_INIT_LOG (ERR ,"Cannot use DCB mq_mode %d while " +"flow director rules are active." , + dev_conf->rxmode.mq_mode); +return -EINVAL ; + } +break ; +default : +break ; + } +if (RTE_ETH_DEV_SRIOV (dev).active !=0 ) {/* check multi-queue mode */ switch (dev_conf->rxmode.mq_mode) {
@@ -2500,7 +2499,6 @@ ixgbe_dev_start(struct rte_eth_dev *dev)struct ixgbe_adapter *adapter =IXGBE_DEV_PRIVATE_TO_ADAPTER (dev->data->dev_private);struct ixgbe_hw *hw =IXGBE_DEV_PRIVATE_TO_HW (adapter); -struct rte_eth_fdir_conf *fdir_conf =IXGBE_DEV_FDIR_CONF (dev);struct ixgbe_vf_info *vfinfo = *IXGBE_DEV_PRIVATE_TO_P_VFDATA (dev->data->dev_private);struct rte_pci_device *pci_dev =RTE_CLASS_TO_BUS_DEVICE (dev, *pci_dev);
@@ -2605,14 +2603,6 @@ ixgbe_dev_start(struct rte_eth_dev *dev)/* Configure DCB hw */ ixgbe_configure_dcb (dev); -if (fdir_conf->mode !=RTE_FDIR_MODE_NONE ) { -struct ixgbe_hw_fdir_info *info = -IXGBE_DEV_PRIVATE_TO_FDIR_INFO (adapter); - err =ixgbe_fdir_configure (dev, fdir_conf, &info->mask); -if (err) - goto error; - } -/* Restore vf rate limit */ if (vfinfo !=NULL ) {for (vf =0 ; vf < pci_dev->max_vfs; vf++)
@@ -2881,6 +2871,9 @@ ixgbe_dev_stop(struct rte_eth_dev *dev)/* reset hierarchy commit */ tm_conf->committed = false; +/* reinit fdir on next flow replay */ +ixgbe_fdir_hw_invalidate (dev); + adapter->rss_reta_updated =0 ; hw->adapter_stopped = true;
@@ -3025,9 +3018,6 @@ ixgbe_dev_close(struct rte_eth_dev *dev)/* uninitialize PF if max_vfs not zero */ ixgbe_pf_host_uninit (dev); -/* remove all the fdir filters & hash */ -ixgbe_fdir_filter_uninit (dev); -/* clear all the filters list */ ixgbe_filterlist_flush (dev);
@@ -7862,7 +7852,6 @@ ixgbe_rss_filter_restore(struct rte_eth_dev *dev)static int ixgbe_filter_restore (struct rte_eth_dev *dev) { -ixgbe_fdir_filter_restore (dev);ixgbe_rss_filter_restore (dev);return 0 ;
drivers/net/intel/ixgbe/ixgbe_ethdev.h +50 -48
165 lines not on this page · raw message
drivers/net/intel/ixgbe/ixgbe_fdir.c +181 -429
799 lines not on this page · raw message
drivers/net/intel/ixgbe/ixgbe_flow.c +3 -1602
1,674 lines not on this page · raw message
drivers/net/intel/ixgbe/ixgbe_flow.h +2 -0
@@ -20,5 +20,7 @@ extern const struct ci_flow_engine ixgbe_syn_flow_engine;extern const struct ci_flow_engine ixgbe_l2_tunnel_flow_engine;extern const struct ci_flow_engine ixgbe_ntuple_flow_engine;extern const struct ci_flow_engine ixgbe_security_flow_engine; +extern const struct ci_flow_engine ixgbe_fdir_flow_engine; +extern const struct ci_flow_engine ixgbe_fdir_tunnel_flow_engine;#endif /* _IXGBE_FLOW_H_ */
drivers/net/intel/ixgbe/ixgbe_flow_fdir.c new file +1602 -0
154 lines not on this page · raw message
drivers/net/intel/ixgbe/ixgbe_rxtx_vec_common.c +2 -2
Lines of this file are not shown. View the raw message.
The rest of this diff is not shown. View the raw message.
Signature · 1 line
2.52.0
Part of the diff is not shown here. View the raw message.
PATCH v5 16/25 net/ixgbe: don't embed RSS conf in filter structs
In reply to Anatoly BurakovCurrently, the RSS configuration driver structure directly embeds rte_flow RSS configuration item, which makes it so 1) the structure actually has duplicate data (or, to be more precise, a local copy of data pointed to by the RSS conf), and 2) direct struct assignments don't work because the RSS conf contains pointers.
Fix the structure to not embed RSS conf, and instead just store the data directly, so that we can perform struct assignments without any problems with poiinters.
--- drivers/net/intel/ixgbe/ixgbe_ethdev.c | 2 +- drivers/net/intel/ixgbe/ixgbe_ethdev.h | 18 ++++---- drivers/net/intel/ixgbe/ixgbe_flow.c | 37 +++++++++------- drivers/net/intel/ixgbe/ixgbe_rxtx.c | 61 ++++++++++++-------------- 4 files changed, 59 insertions(+), 59 deletions(-)
drivers/net/intel/ixgbe/ixgbe_ethdev.c +1 -1
@@ -7844,7 +7844,7 @@ ixgbe_rss_filter_restore(struct rte_eth_dev *dev)struct ixgbe_filter_info *filter_info =IXGBE_DEV_PRIVATE_TO_FILTER_INFO (adapter); -if (filter_info->rss_info.conf.queue_num) +if (filter_info->rss_info.queue_num)ixgbe_config_rss_filter (adapter, &filter_info->rss_info, TRUE); }
drivers/net/intel/ixgbe/ixgbe_ethdev.h +9 -9
@@ -210,9 +210,11 @@ struct ixgbe_fdir_state {struct ixgbe_fdir_stats stats; }; -struct ixgbe_rte_flow_rss_conf { -struct rte_flow_action_rss conf;/**< RSS parameters. */ -uint8_t key[IXGBE_HKEY_MAX_INDEX *sizeof (uint32_t )];/* Hash key. */ +struct ixgbe_rss_conf { +uint64_t types;/**< RSS hash types. */ +uint32_t key_len;/**< Hash key length, 0 for default key. */ +uint32_t queue_num;/**< Number of entries in queue. */ +uint8_t key[IXGBE_HKEY_MAX_INDEX *sizeof (uint32_t )];/**< Hash key. */ uint16_t queue[IXGBE_MAX_RX_QUEUE_NUM ];/**< Queues indices to use. */ };
@@ -300,7 +302,7 @@ struct ixgbe_ethertype_table {*/ struct ixgbe_filter_info {/* store the rss filter info */ -struct ixgbe_rte_flow_rss_conf rss_info; +struct ixgbe_rss_conf rss_info;/* shared EtherType (ETQF) slot table */ struct ixgbe_ethertype_table ethertype_table;/* 1588 timestamping ETQF slot (valid when timesync_installed) */
@@ -731,12 +733,10 @@ void ixgbe_tm_conf_init(struct rte_eth_dev *dev);void ixgbe_tm_conf_uninit (struct rte_eth_dev *dev);int ixgbe_set_queue_rate_limit (struct rte_eth_dev *dev,uint16_t queue_idx,uint32_t tx_rate); -int ixgbe_rss_conf_init (struct ixgbe_rte_flow_rss_conf *out, -const struct rte_flow_action_rss *in); -int ixgbe_action_rss_same (const struct rte_flow_action_rss *comp, -const struct rte_flow_action_rss *with); +int ixgbe_rss_conf_init (struct ixgbe_rss_conf *out, +const struct rte_flow_action_rss *in);int ixgbe_config_rss_filter (struct ixgbe_adapter *adapter, -struct ixgbe_rte_flow_rss_conf *conf,bool add); +const struct ixgbe_rss_conf *conf,bool add);void ixgbe_dev_macsec_register_enable (struct rte_eth_dev *dev,struct ixgbe_macsec_setting *macsec_setting);
drivers/net/intel/ixgbe/ixgbe_flow.c +21 -16
@@ -57,7 +57,7 @@ struct ixgbe_filter_ele_base {/* rss filter list structure */ struct ixgbe_rss_conf_ele {struct ixgbe_filter_ele_base base; -struct ixgbe_rte_flow_rss_conf filter_info; +struct ixgbe_rss_conf filter_info; };/* ixgbe_flow memory list structure */ struct ixgbe_flow_mem {
@@ -140,7 +140,8 @@ ixgbe_flow_actions_check_rss(const struct ci_flow_actions *parsed_actions,const struct rte_flow_action *action = parsed_actions->actions[0 ];const struct rte_flow_action_rss *rss_act = action->conf;struct rte_eth_dev_data *dev_data = param->driver_ctx; -const size_t rss_key_len =sizeof (((struct ixgbe_rte_flow_rss_conf *)0 )->key); +const size_t rss_key_len =sizeof (((struct ixgbe_rss_conf *)0 )->key); +const size_t rss_queue_max =RTE_DIM (((struct ixgbe_rss_conf *)0 )->queue);size_t q_idx, q;/* check if queue list is not empty */
@@ -149,6 +150,11 @@ ixgbe_flow_actions_check_rss(const struct ci_flow_actions *parsed_actions,RTE_FLOW_ERROR_TYPE_ACTION_CONF , rss_act, "RSS queue list is empty"); } +if (rss_act->queue_num > rss_queue_max) { +return rte_flow_error_set (error,ENOTSUP , +RTE_FLOW_ERROR_TYPE_ACTION_CONF , rss_act, +"RSS queue list is too long" ); + }/* check if each RSS queue is valid */ for (q_idx =0 ; q_idx < rss_act->queue_num; q_idx++) {
@@ -185,7 +191,7 @@ static int ixgbe_parse_rss_filter(struct rte_eth_dev *dev, const struct rte_flow_attr *attr, const struct rte_flow_action actions[], - struct ixgbe_rte_flow_rss_conf *rss_conf, + struct ixgbe_rss_conf *rss_conf, struct rte_flow_error *error) { struct ci_flow_actions parsed_actions;
@@ -199,8 +205,8 @@ ixgbe_parse_rss_filter(struct rte_eth_dev *dev, .check = ixgbe_flow_actions_check_rss, .max_actions = 1, }; +const struct rte_flow_action_rss *rss_act;int ret; -const struct rte_flow_action *action;/* validate attributes */ ret =ci_flow_check_attr (attr,NULL , error);
@@ -211,12 +217,14 @@ ixgbe_parse_rss_filter(struct rte_eth_dev *dev, ret =ci_flow_check_actions (actions, &ap_param, &parsed_actions, error);if (ret)return ret; - action = parsed_actions.actions[0 ]; + rss_act = parsed_actions.actions[0 ]->conf; -if (ixgbe_rss_conf_init (rss_conf, action->conf)) -return rte_flow_error_set (error,EINVAL , -RTE_FLOW_ERROR_TYPE_ACTION ,NULL , + ret =ixgbe_rss_conf_init (rss_conf, rss_act); +if (ret) { +return rte_flow_error_set (error, -ret, +RTE_FLOW_ERROR_TYPE_ACTION_CONF , rss_act,"RSS context initialization failure" ); + }return 0 ; }
@@ -230,7 +238,7 @@ ixgbe_clear_rss_filter(struct rte_eth_dev *dev)struct ixgbe_filter_info *filter_info =IXGBE_DEV_PRIVATE_TO_FILTER_INFO (dev->data->dev_private); -if (filter_info->rss_info.conf.queue_num) +if (filter_info->rss_info.queue_num)ixgbe_config_rss_filter (adapter, &filter_info->rss_info, FALSE); }
@@ -275,7 +283,7 @@ ixgbe_flow_create(struct rte_eth_dev *dev, {int ret;struct ixgbe_adapter *adapter =IXGBE_DEV_PRIVATE_TO_ADAPTER (dev->data->dev_private); -struct ixgbe_rte_flow_rss_conf rss_conf; +struct ixgbe_rss_conf rss_conf = {0 };struct rte_flow *flow =NULL ;struct ixgbe_rss_conf_ele *rss_filter_ptr;struct ixgbe_flow_mem *ixgbe_flow_mem_ptr;
@@ -303,7 +311,6 @@ ixgbe_flow_create(struct rte_eth_dev *dev,TAILQ_INSERT_TAIL (&adapter->flow_list, &ixgbe_flow_mem_ptr->base, entries); -memset (&rss_conf,0 ,sizeof (struct ixgbe_rte_flow_rss_conf )); ret =ixgbe_parse_rss_filter (dev, attr, actions, &rss_conf, error);if (!ret) {
@@ -319,8 +326,7 @@ ixgbe_flow_create(struct rte_eth_dev *dev,rte_free (rss_filter_ptr); goto out; } -ixgbe_rss_conf_init (&rss_filter_ptr->filter_info, - &rss_conf.conf); + rss_filter_ptr->filter_info = rss_conf; flow->rule = rss_filter_ptr; flow->filter_type =RTE_ETH_FILTER_HASH ;return flow;
@@ -350,7 +356,7 @@ ixgbe_flow_validate(struct rte_eth_dev *dev, struct rte_flow_error *error) {struct ixgbe_adapter *ad =IXGBE_DEV_PRIVATE_TO_ADAPTER (dev->data->dev_private); -struct ixgbe_rte_flow_rss_conf rss_conf; +struct ixgbe_rss_conf rss_conf = {0 };int ret;/* try the new flow engine first */
@@ -360,7 +366,6 @@ ixgbe_flow_validate(struct rte_eth_dev *dev,/* fall back to legacy engines */ -memset (&rss_conf,0 ,sizeof (struct ixgbe_rte_flow_rss_conf )); ret =ixgbe_parse_rss_filter (dev, attr, actions, &rss_conf, error);
@@ -488,7 +493,7 @@ ixgbe_flow_rule_size(const struct rte_flow *flow)case RTE_ETH_FILTER_L2_TUNNEL :return sizeof (struct ixgbe_l2_tunnel_conf );case RTE_ETH_FILTER_HASH : -return sizeof (struct ixgbe_rte_flow_rss_conf ); +return sizeof (struct ixgbe_rss_conf );default :return 0 ; }
drivers/net/intel/ixgbe/ixgbe_rxtx.c +28 -33
114 lines not on this page · raw message
Signature · 1 line
2.52.0
PATCH v5 17/25 net/ixgbe: reimplement hash parser
In reply to Anatoly BurakovUse the new flow graph API and the common parsing framework to implement flow parser for RSS configuration.
RSS flow parser doesn't really parse any "flows", it was completely ignoring the flow patterns and was only looking at actions. It will therefore not specify a pattern graph and will match NULL pattern, empty patterns (START -> END), and ANY patterns (START -> ANY -> END).
RSS was the last engine using "filter list", so that is now removed. The RSS engine filter tracking was also moved completely into the new engine, and all of the "filter list" infrastructure is removed for good.
--- drivers/net/intel/ixgbe/ixgbe_ethdev.c | 30 -- drivers/net/intel/ixgbe/ixgbe_ethdev.h | 16 +- drivers/net/intel/ixgbe/ixgbe_flow.c | 423 +--------------------- drivers/net/intel/ixgbe/ixgbe_flow.h | 1 + drivers/net/intel/ixgbe/ixgbe_flow_hash.c | 216 +++++++++++ drivers/net/intel/ixgbe/ixgbe_rxtx.c | 43 +-- drivers/net/intel/ixgbe/meson.build | 1 + 7 files changed, 239 insertions(+), 491 deletions(-) create mode 100644 drivers/net/intel/ixgbe/ixgbe_flow_hash.c
drivers/net/intel/ixgbe/ixgbe_ethdev.c +0 -30
@@ -344,7 +344,6 @@ static int ixgbe_dev_udp_tunnel_port_add(struct rte_eth_dev *dev, struct rte_eth_udp_tunnel *udp_tunnel);static int ixgbe_dev_udp_tunnel_port_del (struct rte_eth_dev *dev,struct rte_eth_udp_tunnel *udp_tunnel); -static int ixgbe_filter_restore (struct rte_eth_dev *dev);static void ixgbe_l2_tunnel_conf (struct rte_eth_dev *dev);static int ixgbe_wait_for_link_up (struct ixgbe_hw *hw); static int devarg_handle_int(__rte_unused const char *key, const char *value,
@@ -1270,9 +1269,6 @@ eth_ixgbe_dev_init(struct rte_eth_dev *eth_dev, void *init_params __rte_unused)if (ret) goto err_l2_tn_filter_init; -/* initialize flow filter lists */ -ixgbe_filterlist_init (eth_dev); -/* initialize bandwidth configuration info */ memset (bw_conf,0 ,sizeof (struct ixgbe_bw_conf ));
@@ -2761,7 +2757,6 @@ ixgbe_dev_start(struct rte_eth_dev *dev)/* resume enabled intr since hw reset */ ixgbe_enable_intr (dev);ixgbe_l2_tunnel_conf (dev); -ixgbe_filter_restore (dev);if (tm_conf->root && !tm_conf->committed) PMD_DRV_LOG(WARNING,
@@ -3018,9 +3013,6 @@ ixgbe_dev_close(struct rte_eth_dev *dev)/* uninitialize PF if max_vfs not zero */ ixgbe_pf_host_uninit (dev); -/* clear all the filters list */ -ixgbe_filterlist_flush (dev); -/* Remove all Traffic Manager configuration */ ixgbe_tm_conf_uninit (dev);
@@ -7835,28 +7827,6 @@ int ixgbe_enable_sec_tx_path_generic(struct ixgbe_hw *hw)return IXGBE_SUCCESS ; } -/* restore rss filter */ -static inline void -ixgbe_rss_filter_restore (struct rte_eth_dev *dev) -{ -struct ixgbe_adapter *adapter = -IXGBE_DEV_PRIVATE_TO_ADAPTER (dev->data->dev_private); -struct ixgbe_filter_info *filter_info = -IXGBE_DEV_PRIVATE_TO_FILTER_INFO (adapter); - -if (filter_info->rss_info.queue_num) -ixgbe_config_rss_filter (adapter, - &filter_info->rss_info, TRUE); -} - -static int -ixgbe_filter_restore (struct rte_eth_dev *dev) -{ -ixgbe_rss_filter_restore (dev); - -return 0 ; -} -static void ixgbe_l2_tunnel_conf (struct rte_eth_dev *dev) {
drivers/net/intel/ixgbe/ixgbe_ethdev.h +4 -12
@@ -301,8 +301,6 @@ struct ixgbe_ethertype_table {* Structure to store filters' info. */ struct ixgbe_filter_info { -/* store the rss filter info */ -struct ixgbe_rss_conf rss_info;/* shared EtherType (ETQF) slot table */ struct ixgbe_ethertype_table ethertype_table;/* 1588 timestamping ETQF slot (valid when timesync_installed) */
@@ -319,10 +317,9 @@ struct ixgbe_l2_tn_info {uint16_t e_tag_ether_type;/* ether type for e-tag */ }; +/* no driver-specific data needed */ struct rte_flow {struct ci_flow flow; -enum rte_filter_type filter_type; -void *rule; };struct ixgbe_macsec_setting {
@@ -430,9 +427,6 @@ struct ixgbe_tm_conf {bool committed; }; -struct ixgbe_filter_ele_base ; -TAILQ_HEAD (ixgbe_filter_ele_list, ixgbe_filter_ele_base); -/* * Structure to store private data for each driver instance (for each port). */
@@ -453,7 +447,6 @@ struct ixgbe_adapter {struct ixgbe_bypass_info bps;#endif /* RTE_LIBRTE_IXGBE_BYPASS */ struct ixgbe_filter_info filter; -struct ixgbe_filter_ele_list flow_list;struct ixgbe_l2_tn_info l2_tn;struct ixgbe_bw_conf bw_conf;struct ixgbe_ipsec ipsec;
@@ -666,8 +659,6 @@ ixgbe_e_tag_filter_add(struct ixgbe_adapter *adapter,int ixgbe_e_tag_filter_del (struct ixgbe_adapter *adapter,struct ixgbe_l2_tunnel_conf *l2_tunnel); -void ixgbe_filterlist_init (struct rte_eth_dev *dev); -void ixgbe_filterlist_flush (struct rte_eth_dev *dev);/* * Flow director function prototypes */
@@ -735,8 +726,9 @@ int ixgbe_set_queue_rate_limit(struct rte_eth_dev *dev, uint16_t queue_idx, uint32_t tx_rate);int ixgbe_rss_conf_init (struct ixgbe_rss_conf *out,const struct rte_flow_action_rss *in); -int ixgbe_config_rss_filter (struct ixgbe_adapter *adapter, -const struct ixgbe_rss_conf *conf,bool add); +void ixgbe_hw_rss_filter_program (struct ixgbe_hw *hw, +const struct ixgbe_rss_conf *conf); +void ixgbe_hw_rss_filter_clear (struct ixgbe_hw *hw);void ixgbe_dev_macsec_register_enable (struct rte_eth_dev *dev,struct ixgbe_macsec_setting *macsec_setting);
drivers/net/intel/ixgbe/ixgbe_flow.c +8 -415
484 lines not on this page · raw message
drivers/net/intel/ixgbe/ixgbe_flow.h +1 -0
@@ -22,5 +22,6 @@ extern const struct ci_flow_engine ixgbe_ntuple_flow_engine;extern const struct ci_flow_engine ixgbe_security_flow_engine;extern const struct ci_flow_engine ixgbe_fdir_flow_engine;extern const struct ci_flow_engine ixgbe_fdir_tunnel_flow_engine; +extern const struct ci_flow_engine ixgbe_hash_flow_engine;#endif /* _IXGBE_FLOW_H_ */
drivers/net/intel/ixgbe/ixgbe_flow_hash.c new file +216 -0
216 lines not on this page · raw message
drivers/net/intel/ixgbe/ixgbe_rxtx.c +9 -34
70 lines not on this page · raw message
drivers/net/intel/ixgbe/meson.build +1 -0
@@ -32,6 +32,7 @@ sources += files( 'ixgbe_flow_ntuple.c', 'ixgbe_flow_security.c', 'ixgbe_flow_fdir.c', + 'ixgbe_flow_hash.c', 'ixgbe_ipsec.c', 'ixgbe_pf.c', 'ixgbe_rxtx.c',
Signature · 1 line
2.52.0
PATCH v5 18/25 net/ixgbe: advertise flow keep capability
In reply to Anatoly BurakovThe ixgbe driver's rte_flow implementation has always endeavored to keep flows across device restart, however it never advertised this capability. Advertise it explicitly.
--- doc/guides/rel_notes/release_26_11.rst | 7 +++++-- drivers/net/intel/ixgbe/ixgbe_ethdev.c | 3 +++ 2 files changed, 8 insertions(+), 2 deletions(-)
doc/guides/rel_notes/release_26_11.rst +5 -2
@@ -103,8 +103,11 @@ New Features * **Updated Intel ixgbe driver.** - Added ``fdir_buffer_size`` devarg to select the Flow Director table size - (``64k``, ``128k`` or ``256k``) at probe time. The default remains ``64k``. + * Added ``fdir_buffer_size`` devarg to select the Flow Director table size + (``64k``, ``128k`` or ``256k``) at probe time. The default remains ``64k``. + + * Advertised ``RTE_ETH_DEV_CAPA_FLOW_RULE_KEEP`` capability, + as flow rules were already kept across device restart. * **Updated NXP DPAA2 ethernet driver.**
drivers/net/intel/ixgbe/ixgbe_ethdev.c +3 -0
@@ -3916,6 +3916,9 @@ ixgbe_dev_info_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info) dev_info->reta_size =ixgbe_reta_size_get (hw->mac.type); dev_info->flow_type_rss_offloads =IXGBE_RSS_OFFLOAD_ALL ; +/* rte_flow rules are kept across dev_stop/dev_start and replayed on start */ + dev_info->dev_capa |=RTE_ETH_DEV_CAPA_FLOW_RULE_KEEP ; + dev_info->speed_capa =RTE_ETH_LINK_SPEED_1G |RTE_ETH_LINK_SPEED_10G ;if (hw->device_id ==IXGBE_DEV_ID_X550EM_A_1G_T || hw->device_id ==IXGBE_DEV_ID_X550EM_A_1G_T_L )
Signature · 1 line
2.52.0
PATCH v5 19/25 net/i40e: add support for common flow parsing
In reply to Anatoly BurakovImplement support for common flow parsing infrastructure in preparation for migration of flow engines.
Currently, i40e explicitly clears KEEP_FLOW capability flag, meaning that it advertises that all flows are flushed on dev stop. However, in practice i40e actually restores all flows on dev start, so while we will not (yet) advertise the KEEP_FLOW capability flag, we will also not flush the flows on dev stop with the new engines, and instead replay them.
--- drivers/net/intel/i40e/i40e_ethdev.c | 21 +++++++++++ drivers/net/intel/i40e/i40e_ethdev.h | 5 +++ drivers/net/intel/i40e/i40e_flow.c | 53 +++++++++++++++++++++++++++- drivers/net/intel/i40e/i40e_flow.h | 12 +++++++ 4 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 drivers/net/intel/i40e/i40e_flow.h
drivers/net/intel/i40e/i40e_ethdev.c +21 -0
@@ -42,6 +42,9 @@#include "i40e_regs.h" #include "rte_pmd_i40e.h" #include "i40e_hash.h" +#include "i40e_flow.h" + +#include "../common/flow_engine.h" #define ETH_I40E_FLOATING_VEB_ARG "enable_floating_veb"#define ETH_I40E_FLOATING_VEB_LIST_ARG "floating_veb_list"
@@ -1838,6 +1841,12 @@ eth_i40e_dev_init(struct rte_eth_dev *dev, void *init_params __rte_unused)if (ret <0 ) goto err_init_fdir_filter_list; +/* initialize flow engine configuration */ + ret =ci_flow_engine_conf_init (&pf->flow_engine_conf, + &i40e_flow_engine_list, dev->data); +if (ret <0 ) + goto err_flow_engine_conf_init; +/* initialize queue region configuration */ i40e_init_queue_region_conf (dev);
@@ -1846,6 +1855,12 @@ eth_i40e_dev_init(struct rte_eth_dev *dev, void *init_params __rte_unused)return 0 ; +err_flow_engine_conf_init: +rte_free (pf->fdir.fdir_flow_pool.bitmap); +rte_free (pf->fdir.fdir_flow_pool.pool); +rte_free (pf->fdir.fdir_filter_array); +rte_free (pf->fdir.hash_map); +rte_hash_free (pf->fdir.hash_table); err_init_fdir_filter_list:rte_hash_free (pf->tunnel.hash_table);rte_free (pf->tunnel.hash_map);
@@ -2613,6 +2628,8 @@ i40e_dev_start(struct rte_eth_dev *dev)/* Set the max frame size to HW*/ i40e_aq_set_mac_config (hw, max_frame_size, TRUE, false,0 ,NULL ); +ci_flow_replay (&pf->flow_engine_conf); +return I40E_SUCCESS ; tx_err:
@@ -2715,6 +2732,10 @@ i40e_dev_close(struct rte_eth_dev *dev) ret =i40e_dev_stop (dev); +/* free the flows and reset flow config */ +ci_flow_cleanup (&pf->flow_engine_conf); +ci_flow_engine_conf_reset (&pf->flow_engine_conf); +i40e_dev_free_queues (dev);/* Disable interrupt */
drivers/net/intel/i40e/i40e_ethdev.h +5 -0
@@ -21,6 +21,8 @@#include "base/i40e_type.h" #include "base/virtchnl.h" +#include "../common/flow_engine.h" +#define I40E_AQ_LEN 32#define I40E_AQ_BUF_SZ 4096/* Number of queues per TC should be one of 1, 2, 4, 8, 16, 32, 64 */
@@ -278,6 +280,7 @@ enum i40e_flxpld_layer_idx {* Struct to store flow created. */ struct rte_flow { +struct ci_flow base;TAILQ_ENTRY (rte_flow) node;enum rte_filter_type filter_type;void *rule;
@@ -1182,6 +1185,8 @@ struct i40e_pf {/* The floating enable flag for the specific VF */ bool floating_veb_list[I40E_MAX_VF ];struct i40e_flow_list flow_list; +/* flow engine configuration */ +struct ci_flow_engine_conf flow_engine_conf;bool mpls_replace_flag;/* 1 - MPLS filter replace is done */ bool gtp_replace_flag;/* 1 - GTP-C/U filter replace is done */ bool qinq_replace_flag;/* QINQ filter replace is done */
drivers/net/intel/i40e/i40e_flow.c +52 -1
107 lines not on this page · raw message
drivers/net/intel/i40e/i40e_flow.h new file +12 -0
@@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: BSD-3-Clause +* Copyright(c) 2026 Intel Corporation +*/ + +#ifndef _I40E_FLOW_H_ +#define _I40E_FLOW_H_ + +#include "../common/flow_engine.h" + +extern const struct ci_flow_engine_list i40e_flow_engine_list; + +#endif /* _I40E_FLOW_H_ */
Signature · 1 line
2.52.0
PATCH v5 20/25 net/i40e: reimplement ethertype parser
In reply to Anatoly BurakovUse the new flow graph API and the common parsing framework to implement flow parser for Ethertype.
The ethertype filter tracking has been moved completely inside the new engine, and the ethertype code is refactored to enabled that use case by decoupling hardware writes from software tracking.
--- drivers/net/intel/i40e/i40e_ethdev.c | 260 +------------- drivers/net/intel/i40e/i40e_ethdev.h | 30 +- drivers/net/intel/i40e/i40e_flow.c | 298 +--------------- drivers/net/intel/i40e/i40e_flow.h | 4 + drivers/net/intel/i40e/i40e_flow_ethertype.c | 351 +++++++++++++++++++ drivers/net/intel/i40e/meson.build | 1 + 6 files changed, 370 insertions(+), 574 deletions(-) create mode 100644 drivers/net/intel/i40e/i40e_flow_ethertype.c
drivers/net/intel/i40e/i40e_ethdev.c +2 -258
@@ -392,12 +392,6 @@ static int i40e_set_default_mac_addr(struct rte_eth_dev *dev,static int i40e_dev_mtu_set (struct rte_eth_dev *dev,uint16_t mtu); -static int i40e_ethertype_filter_convert ( -const struct rte_eth_ethertype_filter *input, -struct i40e_ethertype_filter *filter); -static int i40e_sw_ethertype_filter_insert (struct i40e_pf *pf, -struct i40e_ethertype_filter *filter); -static int i40e_tunnel_filter_convert (struct i40e_aqc_cloud_filters_element_bb *cld_filter,struct i40e_tunnel_filter *tunnel_filter);
@@ -405,7 +399,6 @@ static int i40e_sw_tunnel_filter_insert(struct i40e_pf *pf, struct i40e_tunnel_filter *tunnel_filter);static int i40e_cloud_filter_qinq_create (struct i40e_pf *pf); -static void i40e_ethertype_filter_restore (struct i40e_pf *pf);static void i40e_tunnel_filter_restore (struct i40e_pf *pf);static void i40e_filter_restore (struct i40e_pf *pf);static void i40e_notify_all_vfs_link_status (struct rte_eth_dev *dev);
@@ -1003,51 +996,6 @@ config_floating_veb(struct rte_eth_dev *dev)#define I40E_L2_TAGS_S_TAG_SHIFT 1#define I40E_L2_TAGS_S_TAG_MASK I40E_MASK(0x1, I40E_L2_TAGS_S_TAG_SHIFT) -static int -i40e_init_ethtype_filter_list (struct rte_eth_dev *dev) -{ -struct i40e_pf *pf =I40E_DEV_PRIVATE_TO_PF (dev->data->dev_private); -struct i40e_ethertype_rule *ethertype_rule = &pf->ethertype; -char ethertype_hash_name[RTE_HASH_NAMESIZE ]; -int ret; - -struct rte_hash_parameters ethertype_hash_params = { - .name = ethertype_hash_name, - .entries =I40E_MAX_ETHERTYPE_FILTER_NUM , - .key_len =sizeof (struct i40e_ethertype_filter_input ), - .hash_func = rte_hash_crc, - .hash_func_init_val =0 , - .socket_id =rte_socket_id (), - }; - -/* Initialize ethertype filter rule list and hash */ -TAILQ_INIT (ðertype_rule->ethertype_list); -snprintf (ethertype_hash_name,RTE_HASH_NAMESIZE , -"ethertype_%s" , dev->device->name); - ethertype_rule->hash_table =rte_hash_create (ðertype_hash_params); -if (!ethertype_rule->hash_table) { -PMD_INIT_LOG (ERR ,"Failed to create ethertype hash table!" ); -return -EINVAL ; - } - ethertype_rule->hash_map =rte_zmalloc ("i40e_ethertype_hash_map" , -sizeof (struct i40e_ethertype_filter *) * -I40E_MAX_ETHERTYPE_FILTER_NUM , -0 ); -if (!ethertype_rule->hash_map) { -PMD_INIT_LOG (ERR , -"Failed to allocate memory for ethertype hash map!" ); - ret = -ENOMEM ; - goto err_ethertype_hash_map_alloc; - } - -return 0 ; - -err_ethertype_hash_map_alloc: -rte_hash_free (ethertype_rule->hash_table); - -return ret; -} -static int i40e_init_tunnel_filter_list (struct rte_eth_dev *dev) {
@@ -1831,9 +1779,6 @@ eth_i40e_dev_init(struct rte_eth_dev *dev, void *init_params __rte_unused)/* Initialize the filter invalidation configuration */ i40e_init_filter_invalidation (pf); - ret =i40e_init_ethtype_filter_list (dev); -if (ret <0 ) - goto err_init_ethtype_filter_list; ret =i40e_init_tunnel_filter_list (dev);if (ret <0 ) goto err_init_tunnel_filter_list;
@@ -1865,9 +1810,6 @@ eth_i40e_dev_init(struct rte_eth_dev *dev, void *init_params __rte_unused)rte_hash_free (pf->tunnel.hash_table);rte_free (pf->tunnel.hash_map); err_init_tunnel_filter_list: -rte_hash_free (pf->ethertype.hash_table); -rte_free (pf->ethertype.hash_map); -err_init_ethtype_filter_list:rte_intr_callback_unregister (intr_handle, i40e_dev_interrupt_handler, dev);rte_free (dev->data->mac_addrs);
@@ -1890,24 +1832,6 @@ eth_i40e_dev_init(struct rte_eth_dev *dev, void *init_params __rte_unused)return ret; } -static void -i40e_rm_ethtype_filter_list (struct i40e_pf *pf) -{ -struct i40e_ethertype_filter *p_ethertype; -struct i40e_ethertype_rule *ethertype_rule; - - ethertype_rule = &pf->ethertype; -/* Remove all ethertype filter rules and hash */ -rte_free (ethertype_rule->hash_map); -rte_hash_free (ethertype_rule->hash_table); - -while ((p_ethertype =TAILQ_FIRST (ðertype_rule->ethertype_list))) { -TAILQ_REMOVE (ðertype_rule->ethertype_list, - p_ethertype, rules); -rte_free (p_ethertype); - } -} -static void i40e_rm_tunnel_filter_list (struct i40e_pf *pf) {
@@ -2805,7 +2729,6 @@ i40e_dev_close(struct rte_eth_dev *dev)i40e_msec_delay (500 ); }while (retries++ <5 ); -i40e_rm_ethtype_filter_list (pf);i40e_rm_tunnel_filter_list (pf);i40e_rm_fdir_filter_list (pf);
@@ -9891,130 +9814,16 @@ i40e_set_hash_inset(struct i40e_hw *hw, uint64_t input_set,return 0 ; } -/* Convert ethertype filter structure */ -static int -i40e_ethertype_filter_convert (const struct rte_eth_ethertype_filter *input, -struct i40e_ethertype_filter *filter) -{ -memcpy (&filter->input.mac_addr, &input->mac_addr, -RTE_ETHER_ADDR_LEN ); - filter->input.ether_type = input->ether_type; - filter->flags = input->flags; - filter->queue = input->queue; - -return 0 ; -} - -/* Check if there exists the ethertype filter */ -struct i40e_ethertype_filter * -i40e_sw_ethertype_filter_lookup (struct i40e_ethertype_rule *ethertype_rule, -const struct i40e_ethertype_filter_input *input) -{ -int ret; - - ret =rte_hash_lookup (ethertype_rule->hash_table, (const void *)input); -if (ret <0 ) -return NULL ; - -return ethertype_rule->hash_map[ret]; -} - -/* Add ethertype filter in SW list */ -static int -i40e_sw_ethertype_filter_insert (struct i40e_pf *pf, -struct i40e_ethertype_filter *filter) -{ -struct i40e_ethertype_rule *rule = &pf->ethertype; -int ret; - - ret =rte_hash_add_key (rule->hash_table, &filter->input); -if (ret <0 ) { -PMD_DRV_LOG (ERR , -"Failed to insert ethertype filter" -" to hash table %d!" , - ret); -return ret; - } - rule->hash_map[ret] = filter; - -TAILQ_INSERT_TAIL (&rule->ethertype_list, filter, rules); - -return 0 ; -} - -/* Delete ethertype filter in SW list */ int -i40e_sw_ethertype_filter_del (struct i40e_pf *pf, -struct i40e_ethertype_filter_input *input) -{ -struct i40e_ethertype_rule *rule = &pf->ethertype; -struct i40e_ethertype_filter *filter; -int ret; - - ret =rte_hash_del_key (rule->hash_table, input); -if (ret <0 ) { -PMD_DRV_LOG (ERR , -"Failed to delete ethertype filter" -" to hash table %d!" , - ret); -return ret; - } - filter = rule->hash_map[ret]; - rule->hash_map[ret] =NULL ; - -TAILQ_REMOVE (&rule->ethertype_list, filter, rules); -rte_free (filter); - -return 0 ; -} - -/* -* Configure ethertype filter, which can director packet by filtering -* with mac address and ether_type or only ether_type -*/ -int -i40e_ethertype_filter_set (struct i40e_pf *pf, +i40e_ethertype_filter_program (struct i40e_pf *pf,struct rte_eth_ethertype_filter *filter,bool add) {struct i40e_hw *hw =I40E_PF_TO_HW (pf); -struct i40e_ethertype_rule *ethertype_rule = &pf->ethertype; -struct i40e_ethertype_filter *ethertype_filter, *node; -struct i40e_ethertype_filter check_filter;struct i40e_control_filter_stats stats;uint16_t flags =0 ;int ret; -if (filter->queue >= pf->dev_data->nb_rx_queues) { -PMD_DRV_LOG (ERR ,"Invalid queue ID" ); -return -EINVAL ; - } -if (filter->ether_type ==RTE_ETHER_TYPE_IPV4 || - filter->ether_type ==RTE_ETHER_TYPE_IPV6 ) { -PMD_DRV_LOG (ERR , -"unsupported ether_type(0x%04x) in control packet filter." , - filter->ether_type); -return -EINVAL ; - } -if (filter->ether_type ==RTE_ETHER_TYPE_VLAN ) -PMD_DRV_LOG (WARNING , -"filter vlan ether_type in first tag is not supported." ); - -/* Check if there is the filter in SW list */ -memset (&check_filter,0 ,sizeof (check_filter)); -i40e_ethertype_filter_convert (filter, &check_filter); - node =i40e_sw_ethertype_filter_lookup (ethertype_rule, - &check_filter.input); -if (add && node) { -PMD_DRV_LOG (ERR ,"Conflict with existing ethertype rules!" ); -return -EINVAL ; - } - -if (!add && !node) { -PMD_DRV_LOG (ERR ,"There's no corresponding ethertype filter!" ); -return -EINVAL ; - } -if (!(filter->flags &RTE_ETHTYPE_FLAGS_MAC )) flags |=I40E_AQC_ADD_CONTROL_PACKET_FLAGS_IGNORE_MAC ;if (filter->flags &RTE_ETHTYPE_FLAGS_DROP )
@@ -10035,25 +9844,7 @@ i40e_ethertype_filter_set(struct i40e_pf *pf,if (ret <0 )return -ENOSYS ; -/* Add or delete a filter in SW list */ -if (add) { - ethertype_filter =rte_zmalloc ("ethertype_filter" , -sizeof (*ethertype_filter),0 ); -if (ethertype_filter ==NULL ) { -PMD_DRV_LOG (ERR ,"Failed to alloc memory." ); -return -ENOMEM ; - } - -memcpy (ethertype_filter, &check_filter, -sizeof (check_filter)); - ret =i40e_sw_ethertype_filter_insert (pf, ethertype_filter); -if (ret <0 ) -rte_free (ethertype_filter); - }else { - ret =i40e_sw_ethertype_filter_del (pf, &node->input); - } - -return ret; +return 0 ; } static int
@@ -11624,52 +11415,6 @@ i40e_dev_mtu_set(struct rte_eth_dev *dev, uint16_t mtu __rte_unused)return 0 ; } -/* Restore ethertype filter */ -static void -i40e_ethertype_filter_restore (struct i40e_pf *pf) -{ -struct i40e_hw *hw =I40E_PF_TO_HW (pf); -struct i40e_ethertype_filter_list - *ethertype_list = &pf->ethertype.ethertype_list; -struct i40e_ethertype_filter *f; -struct i40e_control_filter_stats stats; -enum i40e_status_code ret; -uint16_t flags; -bool stats_valid = false; - - TAILQ_FOREACH(f, ethertype_list, rules) { - flags =0 ; -if (!(f->flags &RTE_ETHTYPE_FLAGS_MAC )) - flags |=I40E_AQC_ADD_CONTROL_PACKET_FLAGS_IGNORE_MAC ; -if (f->flags &RTE_ETHTYPE_FLAGS_DROP ) - flags |=I40E_AQC_ADD_CONTROL_PACKET_FLAGS_DROP ; - flags |=I40E_AQC_ADD_CONTROL_PACKET_FLAGS_TO_QUEUE ; - - ret =i40e_aq_add_rem_control_packet_filter (hw, - f->input.mac_addr.addr_bytes, - f->input.ether_type, - flags, pf->main_vsi->seid, - f->queue,1 , &stats,NULL ); -if (ret !=I40E_SUCCESS ) { -PMD_DRV_LOG (ERR , -"Failed to restore ethertype filter, ether_type=0x%04x, queue=%u, vsi_seid=%u, err %d" , - f->input.ether_type, f->queue, - pf->main_vsi->seid, ret); -continue ; - } - - stats_valid = true; - } - -if (stats_valid) { -PMD_DRV_LOG (INFO ,"Ethertype filter:" -" mac_etype_used = %u, etype_used = %u," -" mac_etype_free = %u, etype_free = %u" , - stats.mac_etype_used, stats.etype_used, - stats.mac_etype_free, stats.etype_free); - } -} -/* Restore tunnel filter */ static void i40e_tunnel_filter_restore (struct i40e_pf *pf)
@@ -11728,7 +11473,6 @@ i40e_tunnel_filter_restore(struct i40e_pf *pf)static void i40e_filter_restore (struct i40e_pf *pf) { -i40e_ethertype_filter_restore (pf);i40e_tunnel_filter_restore (pf);i40e_fdir_filter_restore (pf); (void )i40e_hash_filter_restore (pf);
drivers/net/intel/i40e/i40e_ethdev.h +1 -29
@@ -805,27 +805,6 @@ struct i40e_fdir_info {/* Ethertype filter number HW supports */ #define I40E_MAX_ETHERTYPE_FILTER_NUM 768 -/* Ethertype filter struct */ -struct i40e_ethertype_filter_input { -struct rte_ether_addr mac_addr;/* Mac address to match */ -uint16_t ether_type;/* Ether type to match */ -}; - -struct i40e_ethertype_filter { -TAILQ_ENTRY (i40e_ethertype_filter) rules; -struct i40e_ethertype_filter_input input; -uint16_t flags;/* Flags from RTE_ETHTYPE_FLAGS_* */ -uint16_t queue;/* Queue assigned to when match */ -}; - -TAILQ_HEAD (i40e_ethertype_filter_list, i40e_ethertype_filter); - -struct i40e_ethertype_rule { -struct i40e_ethertype_filter_list ethertype_list; -struct i40e_ethertype_filter **hash_map; -struct rte_hash *hash_table; -}; -/* queue region info */ struct i40e_queue_region_info {/* the region id for this configuration */
@@ -1176,7 +1155,6 @@ struct i40e_pf {struct i40e_vmdq_info *vmdq;struct i40e_fdir_info fdir;/* flow director info */ -struct i40e_ethertype_rule ethertype;/* Ethertype filter rule */ struct i40e_tunnel_rule tunnel;/* Tunnel filter rule */ struct i40e_rss_conf_list rss_config_list;/* RSS rule list */ struct i40e_queue_regions queue_region;/* queue region info */
@@ -1325,7 +1303,6 @@ extern const struct rte_flow_ops i40e_flow_ops;struct i40e_filter_ctx {union { -struct rte_eth_ethertype_filter ethertype_filter;struct i40e_fdir_filter_conf fdir_filter;struct i40e_tunnel_filter_conf consistent_tunnel_filter;struct i40e_rte_flow_rss_conf rss_conf;
@@ -1407,11 +1384,6 @@ int i40e_rx_burst_mode_get(struct rte_eth_dev *dev, uint16_t queue_id, struct rte_eth_burst_mode *mode);int i40e_tx_burst_mode_get (struct rte_eth_dev *dev,uint16_t queue_id,struct rte_eth_burst_mode *mode); -struct i40e_ethertype_filter * -i40e_sw_ethertype_filter_lookup (struct i40e_ethertype_rule *ethertype_rule, -const struct i40e_ethertype_filter_input *input); -int i40e_sw_ethertype_filter_del (struct i40e_pf *pf, -struct i40e_ethertype_filter_input *input);int i40e_sw_fdir_filter_del (struct i40e_pf *pf,struct i40e_fdir_input *input); struct i40e_tunnel_filter *
@@ -1420,7 +1392,7 @@ i40e_sw_tunnel_filter_lookup(struct i40e_tunnel_rule *tunnel_rule,int i40e_sw_tunnel_filter_del (struct i40e_pf *pf,struct i40e_tunnel_filter_input *input);uint64_t i40e_get_default_input_set (uint16_t pctype); -int i40e_ethertype_filter_set (struct i40e_pf *pf, +int i40e_ethertype_filter_program (struct i40e_pf *pf,struct rte_eth_ethertype_filter *filter,bool add); struct rte_flow *
drivers/net/intel/i40e/i40e_flow.c +11 -287
398 lines not on this page · raw message
drivers/net/intel/i40e/i40e_flow.h +4 -0
@@ -7,6 +7,10 @@#include "../common/flow_engine.h" +int i40e_get_outer_vlan (struct i40e_pf *pf,uint16_t *tpid); +extern const struct ci_flow_engine_list i40e_flow_engine_list; +extern const struct ci_flow_engine i40e_flow_engine_ethertype; +#endif /* _I40E_FLOW_H_ */
drivers/net/intel/i40e/i40e_flow_ethertype.c new file +351 -0
351 lines not on this page · raw message
drivers/net/intel/i40e/meson.build +1 -0
@@ -33,6 +33,7 @@ sources += files( 'i40e_pf.c', 'i40e_fdir.c', 'i40e_flow.c', + 'i40e_flow_ethertype.c', 'i40e_tm.c', 'i40e_hash.c', 'i40e_vf_representor.c',
Signature · 1 line
2.52.0
PATCH v5 21/25 net/i40e: refactor FDIR engine infrastructure
In reply to Anatoly BurakovCurrently, there are multiple problems with how i40e flow directory feature is implemented, both in terms of how it works with rte_flow, and how it integrates with the PMD-specific packet template API.
For one, these two subsystems, while using shared infrastructure, do not really interact or cooperate, and are built on top of special cases in FDIR path. More specifically, the packet template code does not store its packet in the hash map, and has a different hashing scheme, yet it still registers itself in FDIR flow list, hash table, and hash map. This list is then used by dev_start to restore FDIR filters that user has inserted into the list. These filters, as written, cannot be reprogrammed that way because the information a filter restore function would need is lost on insert (the packet pointer is not added to the hash map).
Another issue is that while rte_flow FDIR code does lazy FDIR init on first added flow, the packet template API does not, even though it too relies on the same hardware feature, nor does it ever do teardown on last FDIR flow.
Yet another issue is how the "filter restore" code itself is implemented, namely that currently it simply does not work. When doing filter restore, the driver will walk every FDIR filter stored in the TAILQ, and attempt to program it. However, inside the program function, there is a deduplication check (to see if flow being installed is already present in the flow hash table), which fails because the flows we are programming come from the same list that is being checked for deduplication, which makes the entire filter restore a no-op.
The FDIR filter programming code itself also has a number of readability problems as well as being otherwise hard to use - SW bookkeeping, validation, and flow programming is interspersed within the code, and it is difficult to reason about what happens when the code is called from this or that context.
So, this refactor does the following:
- Reorganize FDIR internals to track packet templates and rte_flow FDIR flows separately
- Refactor FDIR init/teardown to always happen on first/last rule, so that whichever API happens to call FDIR first, the state is consistent
- Rework the FDIR code to disentangle FDIR flow rule programming, Flex PIT checks, SW bookkeeping, etc. from each other
- Remove both the rte_flow FDIR TAILQ and the hash map (filter array) structure, because they are redundant (information about the flow is already stored in the rte_flow flow list, and hash_map structure only stored pointers to data we also have in that same list)
- Fix FDIR filter restore to replay all configuration correctly, as well as re-init the FDIR queue enablement tracking
- Rework the internal FDIR global state data structure to make a little more sense by grouping things that belong together into structures
Additionally, there was a delay mechanism at flow director rule program time, as when programming a rule we might not know if it's actually possible to install the rule, because space for the rules may come either from our own pool, or it may come from a pool that is shared with other VSI's. However, it only makes sense to wait on rule create (i.e. when it is programmed into the hardware for the first time), but not when we are replaying or removing these rules. So, adjust the waiting mechanism to only wait on FDIR rule creation.
--- drivers/net/intel/i40e/i40e_ethdev.c | 169 +--- drivers/net/intel/i40e/i40e_ethdev.h | 128 ++- drivers/net/intel/i40e/i40e_fdir.c | 1173 +++++++++++++++++-------- drivers/net/intel/i40e/i40e_flow.c | 136 +-- drivers/net/intel/i40e/rte_pmd_i40e.c | 6 +- 5 files changed, 966 insertions(+), 646 deletions(-)
drivers/net/intel/i40e/i40e_ethdev.c +14 -155
@@ -1041,129 +1041,6 @@ i40e_init_tunnel_filter_list(struct rte_eth_dev *dev)return ret; } -static int -i40e_init_fdir_filter_list (struct rte_eth_dev *dev) -{ -struct i40e_pf *pf =I40E_DEV_PRIVATE_TO_PF (dev->data->dev_private); -struct i40e_hw *hw =I40E_PF_TO_HW (pf); -struct i40e_fdir_info *fdir_info = &pf->fdir; -char fdir_hash_name[RTE_HASH_NAMESIZE ]; -uint32_t alloc = hw->func_caps.fd_filters_guaranteed; -uint32_t best = hw->func_caps.fd_filters_best_effort; -enum i40e_filter_pctype pctype; -struct rte_bitmap *bmp =NULL ; -uint32_t bmp_size; -void *mem =NULL ; -uint32_t i =0 ; -int ret; - -struct rte_hash_parameters fdir_hash_params = { - .name = fdir_hash_name, - .entries =I40E_MAX_FDIR_FILTER_NUM , - .key_len =sizeof (struct i40e_fdir_input ), - .hash_func = rte_hash_crc, - .hash_func_init_val =0 , - .socket_id =rte_socket_id (), - }; - -/* Initialize flow director filter rule list and hash */ -TAILQ_INIT (&fdir_info->fdir_list); -snprintf (fdir_hash_name,RTE_HASH_NAMESIZE , -"fdir_%s" , dev->device->name); - fdir_info->hash_table =rte_hash_create (&fdir_hash_params); -if (!fdir_info->hash_table) { -PMD_INIT_LOG (ERR ,"Failed to create fdir hash table!" ); -return -EINVAL ; - } - - fdir_info->hash_map =rte_zmalloc ("i40e_fdir_hash_map" , -sizeof (struct i40e_fdir_filter *) * -I40E_MAX_FDIR_FILTER_NUM , -0 ); -if (!fdir_info->hash_map) { -PMD_INIT_LOG (ERR , -"Failed to allocate memory for fdir hash map!" ); - ret = -ENOMEM ; - goto err_fdir_hash_map_alloc; - } - - fdir_info->fdir_filter_array =rte_zmalloc ("fdir_filter" , -sizeof (struct i40e_fdir_filter ) * -I40E_MAX_FDIR_FILTER_NUM , -0 ); - -if (!fdir_info->fdir_filter_array) { -PMD_INIT_LOG (ERR , -"Failed to allocate memory for fdir filter array!" ); - ret = -ENOMEM ; - goto err_fdir_filter_array_alloc; - } - -for (pctype =I40E_FILTER_PCTYPE_NONF_IPV4_UDP ; - pctype <=I40E_FILTER_PCTYPE_L2_PAYLOAD ; pctype++) - pf->fdir.flow_count[pctype] =0 ; - - fdir_info->fdir_space_size = alloc + best; - fdir_info->fdir_actual_cnt =0 ; - fdir_info->fdir_guarantee_total_space = alloc; - fdir_info->fdir_guarantee_free_space = - fdir_info->fdir_guarantee_total_space; - -PMD_DRV_LOG (INFO ,"FDIR guarantee space: %u, best_effort space %u." , alloc, best); - - fdir_info->fdir_flow_pool.pool = -rte_zmalloc ("i40e_fdir_entry" , -sizeof (struct i40e_fdir_entry ) * - fdir_info->fdir_space_size, -0 ); - -if (!fdir_info->fdir_flow_pool.pool) { -PMD_INIT_LOG (ERR , -"Failed to allocate memory for bitmap flow!" ); - ret = -ENOMEM ; - goto err_fdir_bitmap_flow_alloc; - } - -for (i =0 ; i < fdir_info->fdir_space_size; i++) - fdir_info->fdir_flow_pool.pool[i].idx = i; - - bmp_size = -rte_bitmap_get_memory_footprint (fdir_info->fdir_space_size); - mem =rte_zmalloc ("fdir_bmap" , bmp_size,RTE_CACHE_LINE_SIZE ); -if (mem ==NULL ) { -PMD_INIT_LOG (ERR , -"Failed to allocate memory for fdir bitmap!" ); - ret = -ENOMEM ; - goto err_fdir_mem_alloc; - } - bmp =rte_bitmap_init (fdir_info->fdir_space_size, mem, bmp_size); -if (bmp ==NULL ) { -PMD_INIT_LOG (ERR , -"Failed to initialization fdir bitmap!" ); - ret = -ENOMEM ; - goto err_fdir_bmp_alloc; - } -for (i =0 ; i < fdir_info->fdir_space_size; i++) -rte_bitmap_set (bmp, i); - - fdir_info->fdir_flow_pool.bitmap = bmp; - -return 0 ; - -err_fdir_bmp_alloc: -rte_free (mem); -err_fdir_mem_alloc: -rte_free (fdir_info->fdir_flow_pool.pool); -err_fdir_bitmap_flow_alloc: -rte_free (fdir_info->fdir_filter_array); -err_fdir_filter_array_alloc: -rte_free (fdir_info->hash_map); -err_fdir_hash_map_alloc: -rte_hash_free (fdir_info->hash_table); - -return ret; -} -static void i40e_init_customized_info (struct i40e_pf *pf) {
@@ -1782,9 +1659,9 @@ eth_i40e_dev_init(struct rte_eth_dev *dev, void *init_params __rte_unused) ret =i40e_init_tunnel_filter_list (dev);if (ret <0 ) goto err_init_tunnel_filter_list; - ret =i40e_init_fdir_filter_list (dev); + ret =i40e_fdir_flow_store_init (dev);if (ret <0 ) - goto err_init_fdir_filter_list; + goto err_init_fdir_flow_store;/* initialize flow engine configuration */ ret = ci_flow_engine_conf_init(&pf->flow_engine_conf,
@@ -1801,12 +1678,8 @@ eth_i40e_dev_init(struct rte_eth_dev *dev, void *init_params __rte_unused)return 0 ; err_flow_engine_conf_init: -rte_free (pf->fdir.fdir_flow_pool.bitmap); -rte_free (pf->fdir.fdir_flow_pool.pool); -rte_free (pf->fdir.fdir_filter_array); -rte_free (pf->fdir.hash_map); -rte_hash_free (pf->fdir.hash_table); -err_init_fdir_filter_list: +i40e_fdir_flow_store_free (&pf->fdir); +err_init_fdir_flow_store:rte_hash_free (pf->tunnel.hash_table);rte_free (pf->tunnel.hash_map); err_init_tunnel_filter_list:
@@ -1849,32 +1722,13 @@ i40e_rm_tunnel_filter_list(struct i40e_pf *pf) } } -static void -i40e_rm_fdir_filter_list (struct i40e_pf *pf) -{ -struct i40e_fdir_filter *p_fdir; -struct i40e_fdir_info *fdir_info; - - fdir_info = &pf->fdir; - -/* Remove all flow director rules */ -while ((p_fdir =TAILQ_FIRST (&fdir_info->fdir_list))) -TAILQ_REMOVE (&fdir_info->fdir_list, p_fdir, rules); -} -static void i40e_fdir_memory_cleanup (struct i40e_pf *pf) { -struct i40e_fdir_info *fdir_info; +struct i40e_fdir_info *fdir_info = &pf->fdir; - fdir_info = &pf->fdir; - -/* flow director memory cleanup */ -rte_free (fdir_info->hash_map); -rte_hash_free (fdir_info->hash_table); -rte_free (fdir_info->fdir_flow_pool.bitmap); -rte_free (fdir_info->fdir_flow_pool.pool); -rte_free (fdir_info->fdir_filter_array); +i40e_fdir_flow_store_free (fdir_info); +i40e_fdir_tmpl_store_free (fdir_info); }void i40e_flex_payload_reg_set_default (struct i40e_hw *hw)
@@ -2659,6 +2513,7 @@ i40e_dev_close(struct rte_eth_dev *dev)/* free the flows and reset flow config */ ci_flow_cleanup (&pf->flow_engine_conf);ci_flow_engine_conf_reset (&pf->flow_engine_conf); +i40e_fdir_teardown (pf);i40e_dev_free_queues (dev);
@@ -2730,7 +2585,6 @@ i40e_dev_close(struct rte_eth_dev *dev) }while (retries++ <5 );i40e_rm_tunnel_filter_list (pf); -i40e_rm_fdir_filter_list (pf);/* Remove all flows */ while ((p_flow =TAILQ_FIRST (&pf->flow_list))) {
@@ -9758,7 +9612,12 @@ i40e_filter_input_set_init(struct i40e_pf *pf)/* store the default input set */ if (!pf->support_multi_driver) pf->hash_input_set[pctype] = input_set; - pf->fdir.input_set[pctype] = input_set; + { +struct i40e_fdir_pctype_state *state = + &pf->fdir.flows.pctype[pctype]; + + state->input_set = input_set; + } } }
drivers/net/intel/i40e/i40e_ethdev.h +89 -39
186 lines not on this page · raw message
drivers/net/intel/i40e/i40e_fdir.c +811 -362
1,513 lines not on this page · raw message
drivers/net/intel/i40e/i40e_flow.c +48 -88
210 lines not on this page · raw message
drivers/net/intel/i40e/rte_pmd_i40e.c +4 -2
@@ -3044,7 +3044,7 @@ int rte_pmd_i40e_flow_add_del_packet_template( uint8_t add) {struct rte_eth_dev *dev = &rte_eth_devices[port]; -struct i40e_fdir_filter_conf filter_conf; +struct i40e_fdir_filter filter_conf;RTE_ETH_VALID_PORTID_OR_ERR_RET (port, -ENODEV );
@@ -3068,7 +3068,9 @@ int rte_pmd_i40e_flow_add_del_packet_template( (enum i40e_fdir_status )conf->action.report_status; filter_conf.action.flex_off = conf->action.flex_off; -return i40e_flow_add_del_fdir_filter (dev, &filter_conf, add); +if (add) +return i40e_fdir_tmpl_add (dev, &filter_conf); +return i40e_fdir_tmpl_del (dev, &filter_conf); }RTE_EXPORT_SYMBOL (rte_pmd_i40e_inset_get)
Signature · 1 line
2.52.0
PATCH v5 22/25 net/i40e: reimplement FDIR parser
In reply to Anatoly BurakovUse the new flow graph API and the common parsing framework to implement flow parser for flow director.
As a result of transitioning to more formalized validation, some checks have become more stringent. In particular, some protocols (such as SCTP) were previously accepting non-zero or invalid masks and either ignoring them or misinterpreting them to mean "fully masked". This has now been corrected.
The FDIR engine in i40e has also relied on a custom memory allocation scheme for fdir flows - also migrated to the new infrastructure.
Finally, some of the FDIR infrastructure has been migrated into the new flow engine, so that the engine itself is managing its own allocator and its own flow deduplication scheme, and the FDIR storage and programming has been refactored to manage flow programming with better separation between various parts of the flow programming process.
--- drivers/net/intel/i40e/i40e_ethdev.c | 26 +- drivers/net/intel/i40e/i40e_ethdev.h | 125 +- drivers/net/intel/i40e/i40e_fdir.c | 691 ++------ drivers/net/intel/i40e/i40e_flow.c | 1921 +------------------- drivers/net/intel/i40e/i40e_flow.h | 5 + drivers/net/intel/i40e/i40e_flow_fdir.c | 2154 +++++++++++++++++++++++ drivers/net/intel/i40e/meson.build | 1 + drivers/net/intel/i40e/rte_pmd_i40e.c | 6 + 8 files changed, 2409 insertions(+), 2520 deletions(-) create mode 100644 drivers/net/intel/i40e/i40e_flow_fdir.c
drivers/net/intel/i40e/i40e_ethdev.c +4 -22
@@ -1659,9 +1659,7 @@ eth_i40e_dev_init(struct rte_eth_dev *dev, void *init_params __rte_unused) ret =i40e_init_tunnel_filter_list (dev);if (ret <0 ) goto err_init_tunnel_filter_list; - ret =i40e_fdir_flow_store_init (dev); -if (ret <0 ) - goto err_init_fdir_flow_store; +i40e_fdir_flow_store_init (dev);/* initialize flow engine configuration */ ret = ci_flow_engine_conf_init(&pf->flow_engine_conf,
@@ -1678,8 +1676,6 @@ eth_i40e_dev_init(struct rte_eth_dev *dev, void *init_params __rte_unused)return 0 ; err_flow_engine_conf_init: -i40e_fdir_flow_store_free (&pf->fdir); -err_init_fdir_flow_store:rte_hash_free (pf->tunnel.hash_table);rte_free (pf->tunnel.hash_map); err_init_tunnel_filter_list:
@@ -1722,15 +1718,6 @@ i40e_rm_tunnel_filter_list(struct i40e_pf *pf) } } -static void -i40e_fdir_memory_cleanup (struct i40e_pf *pf) -{ -struct i40e_fdir_info *fdir_info = &pf->fdir; - -i40e_fdir_flow_store_free (fdir_info); -i40e_fdir_tmpl_store_free (fdir_info); -} -void i40e_flex_payload_reg_set_default (struct i40e_hw *hw) {/*
@@ -2513,7 +2500,7 @@ i40e_dev_close(struct rte_eth_dev *dev)/* free the flows and reset flow config */ ci_flow_cleanup (&pf->flow_engine_conf);ci_flow_engine_conf_reset (&pf->flow_engine_conf); -i40e_fdir_teardown (pf); +i40e_fdir_cleanup (dev);i40e_dev_free_queues (dev);
@@ -2589,14 +2576,9 @@ i40e_dev_close(struct rte_eth_dev *dev)/* Remove all flows */ while ((p_flow =TAILQ_FIRST (&pf->flow_list))) {TAILQ_REMOVE (&pf->flow_list, p_flow, node); -/* Do not free FDIR flows since they are static allocated */ -if (p_flow->filter_type !=RTE_ETH_FILTER_FDIR ) -rte_free (p_flow); +rte_free (p_flow); } -/* release the fdir static allocated memory */ -i40e_fdir_memory_cleanup (pf); -/* Remove all Traffic Manager configuration */ i40e_tm_conf_uninit (dev);
@@ -9614,7 +9596,7 @@ i40e_filter_input_set_init(struct i40e_pf *pf) pf->hash_input_set[pctype] = input_set; {struct i40e_fdir_pctype_state *state = - &pf->fdir.flows.pctype[pctype]; + &pf->fdir.fdir_state.pctype[pctype]; state->input_set = input_set; }
drivers/net/intel/i40e/i40e_ethdev.h +63 -62
205 lines not on this page · raw message
drivers/net/intel/i40e/i40e_fdir.c +166 -525
1,008 lines not on this page · raw message
drivers/net/intel/i40e/i40e_flow.c +10 -1911
1,723 lines not on this page · raw message
drivers/net/intel/i40e/i40e_flow_fdir.c new file +2154 -0
2,154 lines not on this page · raw message
The rest of this diff is not shown. View the raw message.
Signature · 1 line
2.52.0
Part of the diff is not shown here. View the raw message.
PATCH v5 23/25 net/i40e: reimplement tunnel parsers
In reply to Anatoly BurakovUse the new flow graph API and the common parsing framework to implement flow parser for tunnel filters: QinQ, VXLAN, NVGRE, MPLS, GTP, and L4.
As a result of transitioning to more formalized validation, some checks have become more stringent:
- VLAN TCI mask is now required to be fully masked (all-ones); previously the mask was only checked for eth_proto and any non-zero vlan_tci mask value was silently accepted
- For QinQ, VLAN TCI mask is now required whereas previously it was ignored
- Old code did not check for whether fields other than ports are masked (they are now rejected)
- Old code did not check for whether src/ports are fully masked (masks other than full are now rejected)
- Old code used spec to decide which port to copy (as a result, it was not possible to match port 0 - this is now allowed)
Tunnel engine now also share a refcounted global state, and track all flows and do deduplication inside the engine.
--- drivers/net/intel/i40e/i40e_ethdev.c | 1056 ++--------- drivers/net/intel/i40e/i40e_ethdev.h | 84 +- drivers/net/intel/i40e/i40e_flow.c | 1702 +----------------- drivers/net/intel/i40e/i40e_flow.h | 6 + drivers/net/intel/i40e/i40e_flow_tunnel.c | 1958 +++++++++++++++++++++ drivers/net/intel/i40e/meson.build | 1 + 6 files changed, 2178 insertions(+), 2629 deletions(-) create mode 100644 drivers/net/intel/i40e/i40e_flow_tunnel.c
drivers/net/intel/i40e/i40e_ethdev.c +163 -893
@@ -392,14 +392,6 @@ static int i40e_set_default_mac_addr(struct rte_eth_dev *dev,static int i40e_dev_mtu_set (struct rte_eth_dev *dev,uint16_t mtu); -static int i40e_tunnel_filter_convert ( -struct i40e_aqc_cloud_filters_element_bb *cld_filter, -struct i40e_tunnel_filter *tunnel_filter); -static int i40e_sw_tunnel_filter_insert (struct i40e_pf *pf, -struct i40e_tunnel_filter *tunnel_filter); -static int i40e_cloud_filter_qinq_create (struct i40e_pf *pf); - -static void i40e_tunnel_filter_restore (struct i40e_pf *pf);static void i40e_filter_restore (struct i40e_pf *pf);static void i40e_notify_all_vfs_link_status (struct rte_eth_dev *dev); static int i40e_fec_get_capability(struct rte_eth_dev *dev,
@@ -996,49 +988,43 @@ config_floating_veb(struct rte_eth_dev *dev)#define I40E_L2_TAGS_S_TAG_SHIFT 1#define I40E_L2_TAGS_S_TAG_MASK I40E_MASK(0x1, I40E_L2_TAGS_S_TAG_SHIFT) -static int -i40e_init_tunnel_filter_list (struct rte_eth_dev *dev) +struct i40e_tunnel_state * +i40e_tunnel_state_attach (struct rte_eth_dev_data *dev_data) { -struct i40e_pf *pf =I40E_DEV_PRIVATE_TO_PF (dev->data->dev_private); -struct i40e_tunnel_rule *tunnel_rule = &pf->tunnel; -char tunnel_hash_name[RTE_HASH_NAMESIZE ]; -int ret; - -struct rte_hash_parameters tunnel_hash_params = { +struct i40e_pf *pf =I40E_DEV_PRIVATE_TO_PF (dev_data->dev_private); +struct i40e_tunnel_state *state = &pf->tunnel_state; +char tunnel_hash_name[RTE_HASH_NAMESIZE ] = {0 }; +struct rte_hash_parameters hash_params = { .name = tunnel_hash_name, .entries =I40E_MAX_TUNNEL_FILTER_NUM , - .key_len =sizeof (struct i40e_tunnel_filter_input ), + .key_len =sizeof (struct i40e_tunnel_filter_match_key ), .hash_func = rte_hash_crc, .hash_func_init_val =0 , .socket_id =rte_socket_id (), }; -/* Initialize tunnel filter rule list and hash */ -TAILQ_INIT (&tunnel_rule->tunnel_list); -snprintf (tunnel_hash_name,RTE_HASH_NAMESIZE , -"tunnel_%s" , dev->device->name); - tunnel_rule->hash_table =rte_hash_create (&tunnel_hash_params); -if (!tunnel_rule->hash_table) { -PMD_INIT_LOG (ERR ,"Failed to create tunnel hash table!" ); -return -EINVAL ; - } - tunnel_rule->hash_map =rte_zmalloc ("i40e_tunnel_hash_map" , -sizeof (struct i40e_tunnel_filter *) * -I40E_MAX_TUNNEL_FILTER_NUM , -0 ); -if (!tunnel_rule->hash_map) { -PMD_INIT_LOG (ERR , -"Failed to allocate memory for tunnel hash map!" ); - ret = -ENOMEM ; - goto err_tunnel_hash_map_alloc; +snprintf (tunnel_hash_name,RTE_HASH_NAMESIZE ,"i40e_tunnel_hash_%s" , dev_data->name); + +if (ci_usage_count_claim (&state->use_count)) { + state->hash_table =rte_hash_create (&hash_params); +if (state->hash_table ==NULL ) { +PMD_DRV_LOG (ERR ,"Failed to create tunnel hash table" ); +ci_usage_count_release (&state->use_count); +return NULL ; + } } -return 0 ; +return state; +} -err_tunnel_hash_map_alloc: -rte_hash_free (tunnel_rule->hash_table); +void +i40e_tunnel_state_detach (struct i40e_tunnel_state *state) +{ +if (!ci_usage_count_release (&state->use_count)) +return ; -return ret; +rte_hash_free (state->hash_table); + state->hash_table =NULL ; } static void
@@ -1656,10 +1642,9 @@ eth_i40e_dev_init(struct rte_eth_dev *dev, void *init_params __rte_unused)/* Initialize the filter invalidation configuration */ i40e_init_filter_invalidation (pf); - ret =i40e_init_tunnel_filter_list (dev); -if (ret <0 ) - goto err_init_tunnel_filter_list;i40e_fdir_flow_store_init (dev); +/* after device init, tunnel configuration is in its default state */ + pf->tunnel_state = (struct i40e_tunnel_state ){0 };/* initialize flow engine configuration */ ret = ci_flow_engine_conf_init(&pf->flow_engine_conf,
@@ -1676,9 +1661,6 @@ eth_i40e_dev_init(struct rte_eth_dev *dev, void *init_params __rte_unused)return 0 ; err_flow_engine_conf_init: -rte_hash_free (pf->tunnel.hash_table); -rte_free (pf->tunnel.hash_map); -err_init_tunnel_filter_list:rte_intr_callback_unregister (intr_handle, i40e_dev_interrupt_handler, dev);rte_free (dev->data->mac_addrs);
@@ -1701,23 +1683,6 @@ eth_i40e_dev_init(struct rte_eth_dev *dev, void *init_params __rte_unused)return ret; } -static void -i40e_rm_tunnel_filter_list (struct i40e_pf *pf) -{ -struct i40e_tunnel_filter *p_tunnel; -struct i40e_tunnel_rule *tunnel_rule; - - tunnel_rule = &pf->tunnel; -/* Remove all tunnel director rules and hash */ -rte_free (tunnel_rule->hash_map); -rte_hash_free (tunnel_rule->hash_table); - -while ((p_tunnel =TAILQ_FIRST (&tunnel_rule->tunnel_list))) { -TAILQ_REMOVE (&tunnel_rule->tunnel_list, p_tunnel, rules); -rte_free (p_tunnel); - } -} -void i40e_flex_payload_reg_set_default (struct i40e_hw *hw) {/*
@@ -2571,8 +2536,6 @@ i40e_dev_close(struct rte_eth_dev *dev)i40e_msec_delay (500 ); }while (retries++ <5 ); -i40e_rm_tunnel_filter_list (pf); -/* Remove all flows */ while ((p_flow =TAILQ_FIRST (&pf->flow_list))) {TAILQ_REMOVE (&pf->flow_list, p_flow, node);
@@ -7719,569 +7682,76 @@ i40e_dev_get_filter_type(uint16_t filter_type, uint16_t *flag)return 0 ; } -/* Convert tunnel filter structure */ -static int -i40e_tunnel_filter_convert ( -struct i40e_aqc_cloud_filters_element_bb *cld_filter, -struct i40e_tunnel_filter *tunnel_filter) -{ -rte_ether_addr_copy ((struct rte_ether_addr *) - &cld_filter->element.outer_mac, - (struct rte_ether_addr *)&tunnel_filter->input.outer_mac); -rte_ether_addr_copy ((struct rte_ether_addr *) - &cld_filter->element.inner_mac, - (struct rte_ether_addr *)&tunnel_filter->input.inner_mac); - tunnel_filter->input.inner_vlan = cld_filter->element.inner_vlan; -if ((rte_le_to_cpu_16 (cld_filter->element.flags) & -I40E_AQC_ADD_CLOUD_FLAGS_IPV6 ) == -I40E_AQC_ADD_CLOUD_FLAGS_IPV6 ) - tunnel_filter->input.ip_type =I40E_TUNNEL_IPTYPE_IPV6 ; -else - tunnel_filter->input.ip_type =I40E_TUNNEL_IPTYPE_IPV4 ; - tunnel_filter->input.flags = cld_filter->element.flags; - tunnel_filter->input.tenant_id = cld_filter->element.tenant_id; - tunnel_filter->queue = cld_filter->element.queue_number; -memcpy (tunnel_filter->input.general_fields, - cld_filter->general_fields, -sizeof (cld_filter->general_fields)); - -return 0 ; -} - -/* Check if there exists the tunnel filter */ -struct i40e_tunnel_filter * -i40e_sw_tunnel_filter_lookup (struct i40e_tunnel_rule *tunnel_rule, -const struct i40e_tunnel_filter_input *input) -{ -int ret; - - ret =rte_hash_lookup (tunnel_rule->hash_table, (const void *)input); -if (ret <0 ) -return NULL ; - -return tunnel_rule->hash_map[ret]; -} - -/* Add a tunnel filter into the SW list */ -static int -i40e_sw_tunnel_filter_insert (struct i40e_pf *pf, -struct i40e_tunnel_filter *tunnel_filter) -{ -struct i40e_tunnel_rule *rule = &pf->tunnel; -int ret; - - ret =rte_hash_add_key (rule->hash_table, &tunnel_filter->input); -if (ret <0 ) { -PMD_DRV_LOG (ERR , -"Failed to insert tunnel filter to hash table %d!" , - ret); -return ret; - } - rule->hash_map[ret] = tunnel_filter; - -TAILQ_INSERT_TAIL (&rule->tunnel_list, tunnel_filter, rules); - -return 0 ; -} - -/* Delete a tunnel filter from the SW list */ int -i40e_sw_tunnel_filter_del (struct i40e_pf *pf, -struct i40e_tunnel_filter_input *input) +i40e_tunnel_filter_replace (struct i40e_pf *pf, +const struct i40e_tunnel_filter_replacement *replacement) { -struct i40e_tunnel_rule *rule = &pf->tunnel; -struct i40e_tunnel_filter *tunnel_filter; +struct i40e_aqc_replace_cloud_filters_cmd_buf buffer = {0 }; +struct i40e_aqc_replace_cloud_filters_cmd command = { + .valid_flags = replacement->valid_flags, + .old_filter_type = replacement->old_filter_type, + .new_filter_type = replacement->new_filter_type, + .tr_bit = replacement->tr_bit, + .tr_bit2 = replacement->tr_bit2, + }; +struct i40e_hw *hw =I40E_PF_TO_HW (pf); +struct rte_eth_dev *dev = &rte_eth_devices[pf->dev_data->port_id];int ret; - ret =rte_hash_del_key (rule->hash_table, input); -if (ret <0 ) { -PMD_DRV_LOG (ERR , -"Failed to delete tunnel filter to hash table %d!" , - ret); -return ret; +if (pf->support_multi_driver) { +PMD_DRV_LOG (ERR ,"Replacing tunnel filters is not supported." ); +return I40E_NOT_SUPPORTED ; } - tunnel_filter = rule->hash_map[ret]; - rule->hash_map[ret] =NULL ; -TAILQ_REMOVE (&rule->tunnel_list, tunnel_filter, rules); -rte_free (tunnel_filter); +memcpy (buffer.data, replacement->data,sizeof (replacement->data)); + ret =i40e_aq_replace_cloud_filters (hw, &command, &buffer); +if (ret !=I40E_SUCCESS ) +return ret; + +PMD_DRV_LOG (WARNING ,"i40e device %s changed %s filter type." +" original: 0x%x, new: 0x%x" , + dev->device->name, + (command.valid_flags &I40E_AQC_REPLACE_CLOUD_FILTER ) !=0 ? +"cloud" :"cloud l1" , + command.old_filter_type, command.new_filter_type);return 0 ; } -#define I40E_AQC_REPLACE_CLOUD_CMD_INPUT_TR_WORD0 0x48 -#define I40E_TR_VXLAN_GRE_KEY_MASK 0x4 -#define I40E_TR_GENEVE_KEY_MASK 0x8 -#define I40E_TR_GENERIC_UDP_TUNNEL_MASK 0x40 -#define I40E_TR_GRE_KEY_MASK 0x400 -#define I40E_TR_GRE_KEY_WITH_XSUM_MASK 0x800 -#define I40E_TR_GRE_NO_KEY_MASK 0x8000 -#define I40E_AQC_REPLACE_CLOUD_CMD_INPUT_PORT_TR_WORD0 0x49 -#define I40E_AQC_REPLACE_CLOUD_CMD_INPUT_DIRECTION_WORD0 0x41 -#define I40E_AQC_REPLACE_CLOUD_CMD_INPUT_INGRESS_WORD0 0x80#define I40E_DIRECTION_INGRESS_KEY 0x8000#define I40E_TR_L4_TYPE_TCP 0x2#define I40E_TR_L4_TYPE_UDP 0x4#define I40E_TR_L4_TYPE_SCTP 0x8 -static enum -i40e_status_code i40e_replace_mpls_l1_filter (struct i40e_pf *pf) -{ -struct i40e_aqc_replace_cloud_filters_cmd filter_replace; -struct i40e_aqc_replace_cloud_filters_cmd_buf filter_replace_buf; -struct i40e_hw *hw =I40E_PF_TO_HW (pf); -struct rte_eth_dev *dev = &rte_eth_devices[pf->dev_data->port_id]; -enum i40e_status_code status =I40E_SUCCESS ; - -if (pf->support_multi_driver) { -PMD_DRV_LOG (ERR ,"Replace l1 filter is not supported." ); -return I40E_NOT_SUPPORTED ; - } - -memset (&filter_replace,0 , -sizeof (struct i40e_aqc_replace_cloud_filters_cmd )); -memset (&filter_replace_buf,0 , -sizeof (struct i40e_aqc_replace_cloud_filters_cmd_buf )); - -/* create L1 filter */ - filter_replace.old_filter_type = -I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_IMAC ; - filter_replace.new_filter_type =I40E_AQC_ADD_L1_FILTER_0X11 ; - filter_replace.tr_bit =0 ; - -/* Prepare the buffer, 3 entries */ - filter_replace_buf.data[0 ] = -I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_TEID_WORD0 ; - filter_replace_buf.data[0 ] |= -I40E_AQC_REPLACE_CLOUD_CMD_INPUT_VALIDATED ; - filter_replace_buf.data[2 ] =0xFF ; - filter_replace_buf.data[3 ] =0xFF ; - filter_replace_buf.data[4 ] = -I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_TEID_WORD1 ; - filter_replace_buf.data[4 ] |= -I40E_AQC_REPLACE_CLOUD_CMD_INPUT_VALIDATED ; - filter_replace_buf.data[7 ] =0xF0 ; - filter_replace_buf.data[8 ] - =I40E_AQC_REPLACE_CLOUD_CMD_INPUT_TR_WORD0 ; - filter_replace_buf.data[8 ] |= -I40E_AQC_REPLACE_CLOUD_CMD_INPUT_VALIDATED ; - filter_replace_buf.data[10 ] =I40E_TR_VXLAN_GRE_KEY_MASK | -I40E_TR_GENEVE_KEY_MASK | -I40E_TR_GENERIC_UDP_TUNNEL_MASK ; - filter_replace_buf.data[11 ] = (I40E_TR_GRE_KEY_MASK | -I40E_TR_GRE_KEY_WITH_XSUM_MASK | -I40E_TR_GRE_NO_KEY_MASK ) >>8 ; - - status =i40e_aq_replace_cloud_filters (hw, &filter_replace, - &filter_replace_buf); -if (!status && (filter_replace.old_filter_type != - filter_replace.new_filter_type)) -PMD_DRV_LOG (WARNING ,"i40e device %s changed cloud l1 type." -" original: 0x%x, new: 0x%x" , - dev->device->name, - filter_replace.old_filter_type, - filter_replace.new_filter_type); - -return status; -} - -static enum -i40e_status_code i40e_replace_mpls_cloud_filter (struct i40e_pf *pf) -{ -struct i40e_aqc_replace_cloud_filters_cmd filter_replace; -struct i40e_aqc_replace_cloud_filters_cmd_buf filter_replace_buf; -struct i40e_hw *hw =I40E_PF_TO_HW (pf); -struct rte_eth_dev *dev = &rte_eth_devices[pf->dev_data->port_id]; -enum i40e_status_code status =I40E_SUCCESS ; - -if (pf->support_multi_driver) { -PMD_DRV_LOG (ERR ,"Replace cloud filter is not supported." ); -return I40E_NOT_SUPPORTED ; - } - -/* For MPLSoUDP */ -memset (&filter_replace,0 , -sizeof (struct i40e_aqc_replace_cloud_filters_cmd )); -memset (&filter_replace_buf,0 , -sizeof (struct i40e_aqc_replace_cloud_filters_cmd_buf )); - filter_replace.valid_flags =I40E_AQC_REPLACE_CLOUD_FILTER | -I40E_AQC_MIRROR_CLOUD_FILTER ; - filter_replace.old_filter_type =I40E_AQC_ADD_CLOUD_FILTER_IIP ; - filter_replace.new_filter_type = -I40E_AQC_ADD_CLOUD_FILTER_0X11 ; -/* Prepare the buffer, 2 entries */ - filter_replace_buf.data[0 ] =I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_STAG ; - filter_replace_buf.data[0 ] |= -I40E_AQC_REPLACE_CLOUD_CMD_INPUT_VALIDATED ; - filter_replace_buf.data[4 ] =I40E_AQC_ADD_L1_FILTER_0X11 ; - filter_replace_buf.data[4 ] |= -I40E_AQC_REPLACE_CLOUD_CMD_INPUT_VALIDATED ; - status =i40e_aq_replace_cloud_filters (hw, &filter_replace, - &filter_replace_buf); -if (status <0 ) -return status; -if (filter_replace.old_filter_type != - filter_replace.new_filter_type) -PMD_DRV_LOG (WARNING ,"i40e device %s changed cloud filter type." -" original: 0x%x, new: 0x%x" , - dev->device->name, - filter_replace.old_filter_type, - filter_replace.new_filter_type); - -/* For MPLSoGRE */ -memset (&filter_replace,0 , -sizeof (struct i40e_aqc_replace_cloud_filters_cmd )); -memset (&filter_replace_buf,0 , -sizeof (struct i40e_aqc_replace_cloud_filters_cmd_buf )); - - filter_replace.valid_flags =I40E_AQC_REPLACE_CLOUD_FILTER | -I40E_AQC_MIRROR_CLOUD_FILTER ; - filter_replace.old_filter_type =I40E_AQC_ADD_CLOUD_FILTER_IMAC ; - filter_replace.new_filter_type = -I40E_AQC_ADD_CLOUD_FILTER_0X12 ; -/* Prepare the buffer, 2 entries */ - filter_replace_buf.data[0 ] =I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_STAG ; - filter_replace_buf.data[0 ] |= -I40E_AQC_REPLACE_CLOUD_CMD_INPUT_VALIDATED ; - filter_replace_buf.data[4 ] =I40E_AQC_ADD_L1_FILTER_0X11 ; - filter_replace_buf.data[4 ] |= -I40E_AQC_REPLACE_CLOUD_CMD_INPUT_VALIDATED ; - - status =i40e_aq_replace_cloud_filters (hw, &filter_replace, - &filter_replace_buf); -if (!status && (filter_replace.old_filter_type != - filter_replace.new_filter_type)) -PMD_DRV_LOG (WARNING ,"i40e device %s changed cloud filter type." -" original: 0x%x, new: 0x%x" , - dev->device->name, - filter_replace.old_filter_type, - filter_replace.new_filter_type); - -return status; -} - -static enum i40e_status_code -i40e_replace_gtp_l1_filter (struct i40e_pf *pf) -{ -struct i40e_aqc_replace_cloud_filters_cmd filter_replace; -struct i40e_aqc_replace_cloud_filters_cmd_buf filter_replace_buf; -struct i40e_hw *hw =I40E_PF_TO_HW (pf); -struct rte_eth_dev *dev = &rte_eth_devices[pf->dev_data->port_id]; -enum i40e_status_code status =I40E_SUCCESS ; - -if (pf->support_multi_driver) { -PMD_DRV_LOG (ERR ,"Replace l1 filter is not supported." ); -return I40E_NOT_SUPPORTED ; - } - -/* For GTP-C */ -memset (&filter_replace,0 , -sizeof (struct i40e_aqc_replace_cloud_filters_cmd )); -memset (&filter_replace_buf,0 , -sizeof (struct i40e_aqc_replace_cloud_filters_cmd_buf )); -/* create L1 filter */ - filter_replace.old_filter_type = -I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_IMAC ; - filter_replace.new_filter_type =I40E_AQC_ADD_L1_FILTER_0X12 ; - filter_replace.tr_bit =I40E_AQC_NEW_TR_22 | -I40E_AQC_REPLACE_CLOUD_CMD_INPUT_VALIDATED ; -/* Prepare the buffer, 2 entries */ - filter_replace_buf.data[0 ] = -I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_TEID_WORD0 ; - filter_replace_buf.data[0 ] |= -I40E_AQC_REPLACE_CLOUD_CMD_INPUT_VALIDATED ; - filter_replace_buf.data[2 ] =0xFF ; - filter_replace_buf.data[3 ] =0xFF ; - filter_replace_buf.data[4 ] = -I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_TEID_WORD1 ; - filter_replace_buf.data[4 ] |= -I40E_AQC_REPLACE_CLOUD_CMD_INPUT_VALIDATED ; - filter_replace_buf.data[6 ] =0xFF ; - filter_replace_buf.data[7 ] =0xFF ; - status =i40e_aq_replace_cloud_filters (hw, &filter_replace, - &filter_replace_buf); -if (status <0 ) -return status; -if (filter_replace.old_filter_type != - filter_replace.new_filter_type) -PMD_DRV_LOG (WARNING ,"i40e device %s changed cloud l1 type." -" original: 0x%x, new: 0x%x" , - dev->device->name, - filter_replace.old_filter_type, - filter_replace.new_filter_type); - -/* for GTP-U */ -memset (&filter_replace,0 , -sizeof (struct i40e_aqc_replace_cloud_filters_cmd )); -memset (&filter_replace_buf,0 , -sizeof (struct i40e_aqc_replace_cloud_filters_cmd_buf )); -/* create L1 filter */ - filter_replace.old_filter_type = -I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_TUNNLE_KEY ; - filter_replace.new_filter_type =I40E_AQC_ADD_L1_FILTER_0X13 ; - filter_replace.tr_bit =I40E_AQC_NEW_TR_21 | -I40E_AQC_REPLACE_CLOUD_CMD_INPUT_VALIDATED ; -/* Prepare the buffer, 2 entries */ - filter_replace_buf.data[0 ] = -I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_TEID_WORD0 ; - filter_replace_buf.data[0 ] |= -I40E_AQC_REPLACE_CLOUD_CMD_INPUT_VALIDATED ; - filter_replace_buf.data[2 ] =0xFF ; - filter_replace_buf.data[3 ] =0xFF ; - filter_replace_buf.data[4 ] = -I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_TEID_WORD1 ; - filter_replace_buf.data[4 ] |= -I40E_AQC_REPLACE_CLOUD_CMD_INPUT_VALIDATED ; - filter_replace_buf.data[6 ] =0xFF ; - filter_replace_buf.data[7 ] =0xFF ; - - status =i40e_aq_replace_cloud_filters (hw, &filter_replace, - &filter_replace_buf); -if (!status && (filter_replace.old_filter_type != - filter_replace.new_filter_type)) -PMD_DRV_LOG (WARNING ,"i40e device %s changed cloud l1 type." -" original: 0x%x, new: 0x%x" , - dev->device->name, - filter_replace.old_filter_type, - filter_replace.new_filter_type); - -return status; -} - -static enum -i40e_status_code i40e_replace_gtp_cloud_filter (struct i40e_pf *pf) -{ -struct i40e_aqc_replace_cloud_filters_cmd filter_replace; -struct i40e_aqc_replace_cloud_filters_cmd_buf filter_replace_buf; -struct i40e_hw *hw =I40E_PF_TO_HW (pf); -struct rte_eth_dev *dev = &rte_eth_devices[pf->dev_data->port_id]; -enum i40e_status_code status =I40E_SUCCESS ; - -if (pf->support_multi_driver) { -PMD_DRV_LOG (ERR ,"Replace cloud filter is not supported." ); -return I40E_NOT_SUPPORTED ; - } - -/* for GTP-C */ -memset (&filter_replace,0 , -sizeof (struct i40e_aqc_replace_cloud_filters_cmd )); -memset (&filter_replace_buf,0 , -sizeof (struct i40e_aqc_replace_cloud_filters_cmd_buf )); - filter_replace.valid_flags =I40E_AQC_REPLACE_CLOUD_FILTER ; - filter_replace.old_filter_type =I40E_AQC_ADD_CLOUD_FILTER_IMAC_IVLAN ; - filter_replace.new_filter_type = -I40E_AQC_ADD_CLOUD_FILTER_0X11 ; -/* Prepare the buffer, 2 entries */ - filter_replace_buf.data[0 ] =I40E_AQC_ADD_L1_FILTER_0X12 ; - filter_replace_buf.data[0 ] |= -I40E_AQC_REPLACE_CLOUD_CMD_INPUT_VALIDATED ; - filter_replace_buf.data[4 ] =I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_STAG ; - filter_replace_buf.data[4 ] |= -I40E_AQC_REPLACE_CLOUD_CMD_INPUT_VALIDATED ; - status =i40e_aq_replace_cloud_filters (hw, &filter_replace, - &filter_replace_buf); -if (status <0 ) -return status; -if (filter_replace.old_filter_type != - filter_replace.new_filter_type) -PMD_DRV_LOG (WARNING ,"i40e device %s changed cloud filter type." -" original: 0x%x, new: 0x%x" , - dev->device->name, - filter_replace.old_filter_type, - filter_replace.new_filter_type); - -/* for GTP-U */ -memset (&filter_replace,0 , -sizeof (struct i40e_aqc_replace_cloud_filters_cmd )); -memset (&filter_replace_buf,0 , -sizeof (struct i40e_aqc_replace_cloud_filters_cmd_buf )); - filter_replace.valid_flags =I40E_AQC_REPLACE_CLOUD_FILTER ; - filter_replace.old_filter_type = -I40E_AQC_ADD_CLOUD_FILTER_IMAC_IVLAN_TEN_ID ; - filter_replace.new_filter_type = -I40E_AQC_ADD_CLOUD_FILTER_0X12 ; -/* Prepare the buffer, 2 entries */ - filter_replace_buf.data[0 ] =I40E_AQC_ADD_L1_FILTER_0X13 ; - filter_replace_buf.data[0 ] |= -I40E_AQC_REPLACE_CLOUD_CMD_INPUT_VALIDATED ; - filter_replace_buf.data[4 ] =I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_STAG ; - filter_replace_buf.data[4 ] |= -I40E_AQC_REPLACE_CLOUD_CMD_INPUT_VALIDATED ; - - status =i40e_aq_replace_cloud_filters (hw, &filter_replace, - &filter_replace_buf); -if (!status && (filter_replace.old_filter_type != - filter_replace.new_filter_type)) -PMD_DRV_LOG (WARNING ,"i40e device %s changed cloud filter type." -" original: 0x%x, new: 0x%x" , - dev->device->name, - filter_replace.old_filter_type, - filter_replace.new_filter_type); - -return status; -} - -static enum i40e_status_code -i40e_replace_port_l1_filter (struct i40e_pf *pf, -enum i40e_l4_port_type l4_port_type) -{ -struct i40e_aqc_replace_cloud_filters_cmd_buf filter_replace_buf; -struct i40e_aqc_replace_cloud_filters_cmd filter_replace; -enum i40e_status_code status =I40E_SUCCESS ; -struct i40e_hw *hw =I40E_PF_TO_HW (pf); -struct rte_eth_dev *dev = &rte_eth_devices[pf->dev_data->port_id]; - -if (pf->support_multi_driver) { -PMD_DRV_LOG (ERR ,"Replace l1 filter is not supported." ); -return I40E_NOT_SUPPORTED ; - } - -memset (&filter_replace,0 , -sizeof (struct i40e_aqc_replace_cloud_filters_cmd )); -memset (&filter_replace_buf,0 , -sizeof (struct i40e_aqc_replace_cloud_filters_cmd_buf )); - -/* create L1 filter */ -if (l4_port_type ==I40E_L4_PORT_TYPE_SRC ) { - filter_replace.old_filter_type = -I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_TUNNLE_KEY ; - filter_replace.new_filter_type =I40E_AQC_ADD_L1_FILTER_0X11 ; - filter_replace_buf.data[8 ] = -I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_SRC_PORT ; - }else { - filter_replace.old_filter_type = -I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_STAG_IVLAN ; - filter_replace.new_filter_type =I40E_AQC_ADD_L1_FILTER_0X10 ; - filter_replace_buf.data[8 ] = -I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_DST_PORT ; - } - - filter_replace.tr_bit =0 ; -/* Prepare the buffer, 3 entries */ - filter_replace_buf.data[0 ] = -I40E_AQC_REPLACE_CLOUD_CMD_INPUT_DIRECTION_WORD0 ; - filter_replace_buf.data[0 ] |= -I40E_AQC_REPLACE_CLOUD_CMD_INPUT_VALIDATED ; - filter_replace_buf.data[2 ] =0x00 ; - filter_replace_buf.data[3 ] = -I40E_AQC_REPLACE_CLOUD_CMD_INPUT_INGRESS_WORD0 ; - filter_replace_buf.data[4 ] = -I40E_AQC_REPLACE_CLOUD_CMD_INPUT_PORT_TR_WORD0 ; - filter_replace_buf.data[4 ] |= -I40E_AQC_REPLACE_CLOUD_CMD_INPUT_VALIDATED ; - filter_replace_buf.data[5 ] =0x00 ; - filter_replace_buf.data[6 ] =I40E_TR_L4_TYPE_UDP | -I40E_TR_L4_TYPE_TCP | -I40E_TR_L4_TYPE_SCTP ; - filter_replace_buf.data[7 ] =0x00 ; - filter_replace_buf.data[8 ] |= -I40E_AQC_REPLACE_CLOUD_CMD_INPUT_VALIDATED ; - filter_replace_buf.data[9 ] =0x00 ; - filter_replace_buf.data[10 ] =0xFF ; - filter_replace_buf.data[11 ] =0xFF ; - - status =i40e_aq_replace_cloud_filters (hw, &filter_replace, - &filter_replace_buf); -if (!status && filter_replace.old_filter_type != - filter_replace.new_filter_type) -PMD_DRV_LOG (WARNING ,"i40e device %s changed cloud l1 type." -" original: 0x%x, new: 0x%x" , - dev->device->name, - filter_replace.old_filter_type, - filter_replace.new_filter_type); - -return status; -} - -static enum i40e_status_code -i40e_replace_port_cloud_filter (struct i40e_pf *pf, -enum i40e_l4_port_type l4_port_type) -{ -struct i40e_aqc_replace_cloud_filters_cmd_buf filter_replace_buf; -struct i40e_aqc_replace_cloud_filters_cmd filter_replace; -enum i40e_status_code status =I40E_SUCCESS ; -struct i40e_hw *hw =I40E_PF_TO_HW (pf); -struct rte_eth_dev *dev = &rte_eth_devices[pf->dev_data->port_id]; - -if (pf->support_multi_driver) { -PMD_DRV_LOG (ERR ,"Replace cloud filter is not supported." ); -return I40E_NOT_SUPPORTED ; - } - -memset (&filter_replace,0 , -sizeof (struct i40e_aqc_replace_cloud_filters_cmd )); -memset (&filter_replace_buf,0 , -sizeof (struct i40e_aqc_replace_cloud_filters_cmd_buf )); - -if (l4_port_type ==I40E_L4_PORT_TYPE_SRC ) { - filter_replace.old_filter_type =I40E_AQC_ADD_CLOUD_FILTER_IIP ; - filter_replace.new_filter_type = -I40E_AQC_ADD_CLOUD_FILTER_0X11 ; - filter_replace_buf.data[4 ] =I40E_AQC_ADD_CLOUD_FILTER_0X11 ; - }else { - filter_replace.old_filter_type =I40E_AQC_ADD_CLOUD_FILTER_OIP ; - filter_replace.new_filter_type = -I40E_AQC_ADD_CLOUD_FILTER_0X10 ; - filter_replace_buf.data[4 ] =I40E_AQC_ADD_CLOUD_FILTER_0X10 ; - } - - filter_replace.valid_flags =I40E_AQC_REPLACE_CLOUD_FILTER ; - filter_replace.tr_bit =0 ; -/* Prepare the buffer, 2 entries */ - filter_replace_buf.data[0 ] =I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_STAG ; - filter_replace_buf.data[0 ] |= -I40E_AQC_REPLACE_CLOUD_CMD_INPUT_VALIDATED ; - filter_replace_buf.data[4 ] |= -I40E_AQC_REPLACE_CLOUD_CMD_INPUT_VALIDATED ; - status =i40e_aq_replace_cloud_filters (hw, &filter_replace, - &filter_replace_buf); - -if (!status && filter_replace.old_filter_type != - filter_replace.new_filter_type) -PMD_DRV_LOG (WARNING ,"i40e device %s changed cloud filter type." -" original: 0x%x, new: 0x%x" , - dev->device->name, - filter_replace.old_filter_type, - filter_replace.new_filter_type); - -return status; -} - -int -i40e_dev_consistent_tunnel_filter_set (struct i40e_pf *pf, -struct i40e_tunnel_filter_conf *tunnel_filter, -uint8_t add) +static int +i40e_tunnel_filter_convert_conf (struct i40e_pf *pf, +struct i40e_tunnel_filter_conf *tunnel_filter, +struct i40e_aqc_cloud_filters_element_bb *cld_filter, +struct i40e_vsi **vsi,bool *big_buffer) {uint16_t ip_type;uint32_t ipv4_addr, ipv4_addr_le;uint8_t i, tun_type =0 ;/* internal variable to convert ipv6 byte order */ uint32_t convert_ipv6[4 ]; -int val, ret =0 ; +int val;struct i40e_pf_vf *vf =NULL ; -struct i40e_hw *hw =I40E_PF_TO_HW (pf); -struct i40e_vsi *vsi; -struct i40e_aqc_cloud_filters_element_bb cld_filter = {0 }; -struct i40e_tunnel_rule *tunnel_rule = &pf->tunnel; -struct i40e_tunnel_filter *node; -struct i40e_tunnel_filter check_filter;/* Check if filter exists */ uint32_t teid_le; -bool big_buffer =0 ;rte_ether_addr_copy (&tunnel_filter->outer_mac, - (struct rte_ether_addr *)&cld_filter.element.outer_mac); + (struct rte_ether_addr *)&cld_filter->element.outer_mac);rte_ether_addr_copy (&tunnel_filter->inner_mac, - (struct rte_ether_addr *)&cld_filter.element.inner_mac); + (struct rte_ether_addr *)&cld_filter->element.inner_mac); - cld_filter.element.inner_vlan = + cld_filter->element.inner_vlan =rte_cpu_to_le_16 (tunnel_filter->inner_vlan);if (tunnel_filter->ip_type ==I40E_TUNNEL_IPTYPE_IPV4 ) { ip_type =I40E_AQC_ADD_CLOUD_FLAGS_IPV4 ; ipv4_addr =rte_be_to_cpu_32 (tunnel_filter->ip_addr.ipv4_addr); ipv4_addr_le =rte_cpu_to_le_32 (ipv4_addr); -memcpy (&cld_filter.element.ipaddr.v4.data, +memcpy (&cld_filter->element.ipaddr.v4.data, &ipv4_addr_le, -sizeof (cld_filter.element.ipaddr.v4.data)); +sizeof (cld_filter->element.ipaddr.v4.data)); }else { ip_type =I40E_AQC_ADD_CLOUD_FLAGS_IPV6 ;for (i =0 ; i <4 ; i++) {
@@ -8289,9 +7759,9 @@ i40e_dev_consistent_tunnel_filter_set(struct i40e_pf *pf,rte_cpu_to_le_32 (rte_be_to_cpu_32 ( tunnel_filter->ip_addr.ipv6_addr[i])); } -memcpy (&cld_filter.element.ipaddr.v6.data, +memcpy (&cld_filter->element.ipaddr.v6.data, &convert_ipv6, -sizeof (cld_filter.element.ipaddr.v6.data)); +sizeof (cld_filter->element.ipaddr.v6.data)); }/* check tunneled type */
@@ -8306,139 +7776,96 @@ i40e_dev_consistent_tunnel_filter_set(struct i40e_pf *pf, tun_type =I40E_AQC_ADD_CLOUD_TNL_TYPE_IP ;break ;case I40E_TUNNEL_TYPE_MPLSoUDP: -if (!pf->mpls_replace_flag) { -i40e_replace_mpls_l1_filter (pf); -i40e_replace_mpls_cloud_filter (pf); - pf->mpls_replace_flag =1 ; - } teid_le =rte_cpu_to_le_32 (tunnel_filter->tenant_id); - cld_filter.general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X11_WORD0 ] = + cld_filter->general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X11_WORD0 ] = teid_le >>4 ; - cld_filter.general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X11_WORD1 ] = + cld_filter->general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X11_WORD1 ] = (teid_le &0xF ) <<12 ; - cld_filter.general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X11_WORD2 ] = + cld_filter->general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X11_WORD2 ] =0x40 ; - big_buffer =1 ; + *big_buffer =1 ; tun_type =I40E_AQC_ADD_CLOUD_TNL_TYPE_MPLSOUDP ;break ;case I40E_TUNNEL_TYPE_MPLSoGRE: -if (!pf->mpls_replace_flag) { -i40e_replace_mpls_l1_filter (pf); -i40e_replace_mpls_cloud_filter (pf); - pf->mpls_replace_flag =1 ; - } teid_le =rte_cpu_to_le_32 (tunnel_filter->tenant_id); - cld_filter.general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X11_WORD0 ] = + cld_filter->general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X11_WORD0 ] = teid_le >>4 ; - cld_filter.general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X11_WORD1 ] = + cld_filter->general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X11_WORD1 ] = (teid_le &0xF ) <<12 ; - cld_filter.general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X11_WORD2 ] = + cld_filter->general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X11_WORD2 ] =0x0 ; - big_buffer =1 ; + *big_buffer =1 ; tun_type =I40E_AQC_ADD_CLOUD_TNL_TYPE_MPLSOGRE ;break ;case I40E_TUNNEL_TYPE_GTPC : -if (!pf->gtp_replace_flag) { -i40e_replace_gtp_l1_filter (pf); -i40e_replace_gtp_cloud_filter (pf); - pf->gtp_replace_flag =1 ; - } teid_le =rte_cpu_to_le_32 (tunnel_filter->tenant_id); - cld_filter.general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X12_WORD0 ] = + cld_filter->general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X12_WORD0 ] = (teid_le >>16 ) &0xFFFF ; - cld_filter.general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X12_WORD1 ] = + cld_filter->general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X12_WORD1 ] = teid_le &0xFFFF ; - cld_filter.general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X12_WORD2 ] = + cld_filter->general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X12_WORD2 ] =0x0 ; - big_buffer =1 ; + *big_buffer =1 ;break ;case I40E_TUNNEL_TYPE_GTPU : -if (!pf->gtp_replace_flag) { -i40e_replace_gtp_l1_filter (pf); -i40e_replace_gtp_cloud_filter (pf); - pf->gtp_replace_flag =1 ; - } teid_le =rte_cpu_to_le_32 (tunnel_filter->tenant_id); - cld_filter.general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X13_WORD0 ] = + cld_filter->general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X13_WORD0 ] = (teid_le >>16 ) &0xFFFF ; - cld_filter.general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X13_WORD1 ] = + cld_filter->general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X13_WORD1 ] = teid_le &0xFFFF ; - cld_filter.general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X13_WORD2 ] = + cld_filter->general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X13_WORD2 ] =0x0 ; - big_buffer =1 ; + *big_buffer =1 ;break ;case I40E_TUNNEL_TYPE_QINQ : -if (!pf->qinq_replace_flag) { - ret =i40e_cloud_filter_qinq_create (pf); -if (ret <0 ) { -PMD_DRV_LOG (ERR ,"Failed to create QinQ tunnel filter." ); -/* ret is a raw i40e_status_code, not an errno */ -return -ENOTSUP ; - } - pf->qinq_replace_flag =1 ; - }/* Add in the General fields the values of * the Outer and Inner VLAN * Big Buffer should be set, see changes in * i40e_aq_add_cloud_filters */ - cld_filter.general_fields[0 ] = tunnel_filter->inner_vlan; - cld_filter.general_fields[1 ] = tunnel_filter->outer_vlan; - big_buffer =1 ; + cld_filter->general_fields[0 ] = tunnel_filter->inner_vlan; + cld_filter->general_fields[1 ] = tunnel_filter->outer_vlan; + *big_buffer =1 ;break ;case I40E_CLOUD_TYPE_UDP :case I40E_CLOUD_TYPE_TCP :case I40E_CLOUD_TYPE_SCTP :if (tunnel_filter->l4_port_type ==I40E_L4_PORT_TYPE_SRC ) { -if (!pf->sport_replace_flag) { -i40e_replace_port_l1_filter (pf, - tunnel_filter->l4_port_type); -i40e_replace_port_cloud_filter (pf, - tunnel_filter->l4_port_type); - pf->sport_replace_flag =1 ; - } teid_le =rte_cpu_to_le_32 (tunnel_filter->tenant_id); - cld_filter.general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X11_WORD0 ] = + cld_filter->general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X11_WORD0 ] =I40E_DIRECTION_INGRESS_KEY ;if (tunnel_filter->tunnel_type ==I40E_CLOUD_TYPE_UDP ) - cld_filter.general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X11_WORD1 ] = + cld_filter->general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X11_WORD1 ] =I40E_TR_L4_TYPE_UDP ;else if (tunnel_filter->tunnel_type ==I40E_CLOUD_TYPE_TCP ) - cld_filter.general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X11_WORD1 ] = + cld_filter->general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X11_WORD1 ] =I40E_TR_L4_TYPE_TCP ;else - cld_filter.general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X11_WORD1 ] = + cld_filter->general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X11_WORD1 ] =I40E_TR_L4_TYPE_SCTP ; - cld_filter.general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X11_WORD2 ] = + cld_filter->general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X11_WORD2 ] = (teid_le >>16 ) &0xFFFF ; - big_buffer =1 ; + *big_buffer =1 ; }else { -if (!pf->dport_replace_flag) { -i40e_replace_port_l1_filter (pf, - tunnel_filter->l4_port_type); -i40e_replace_port_cloud_filter (pf, - tunnel_filter->l4_port_type); - pf->dport_replace_flag =1 ; - } teid_le =rte_cpu_to_le_32 (tunnel_filter->tenant_id); - cld_filter.general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X10_WORD0 ] = + cld_filter->general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X10_WORD0 ] =I40E_DIRECTION_INGRESS_KEY ;if (tunnel_filter->tunnel_type ==I40E_CLOUD_TYPE_UDP ) - cld_filter.general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X10_WORD1 ] = + cld_filter->general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X10_WORD1 ] =I40E_TR_L4_TYPE_UDP ;else if (tunnel_filter->tunnel_type ==I40E_CLOUD_TYPE_TCP ) - cld_filter.general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X10_WORD1 ] = + cld_filter->general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X10_WORD1 ] =I40E_TR_L4_TYPE_TCP ;else - cld_filter.general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X10_WORD1 ] = + cld_filter->general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X10_WORD1 ] =I40E_TR_L4_TYPE_SCTP ; - cld_filter.general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X10_WORD2 ] = + cld_filter->general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X10_WORD2 ] = (teid_le >>16 ) &0xFFFF ; - big_buffer =1 ; + *big_buffer =1 ; }break ;
@@ -8449,74 +7876,111 @@ i40e_dev_consistent_tunnel_filter_set(struct i40e_pf *pf, }if (tunnel_filter->tunnel_type == I40E_TUNNEL_TYPE_MPLSoUDP) - cld_filter.element.flags = + cld_filter->element.flags =I40E_AQC_ADD_CLOUD_FILTER_0X11 ;else if (tunnel_filter->tunnel_type == I40E_TUNNEL_TYPE_MPLSoGRE) - cld_filter.element.flags = + cld_filter->element.flags =I40E_AQC_ADD_CLOUD_FILTER_0X12 ;else if (tunnel_filter->tunnel_type ==I40E_TUNNEL_TYPE_GTPC ) - cld_filter.element.flags = + cld_filter->element.flags =I40E_AQC_ADD_CLOUD_FILTER_0X11 ;else if (tunnel_filter->tunnel_type ==I40E_TUNNEL_TYPE_GTPU ) - cld_filter.element.flags = + cld_filter->element.flags =I40E_AQC_ADD_CLOUD_FILTER_0X12 ;else if (tunnel_filter->tunnel_type ==I40E_TUNNEL_TYPE_QINQ ) - cld_filter.element.flags |= + cld_filter->element.flags |=I40E_AQC_ADD_CLOUD_FILTER_0X10 ;else if (tunnel_filter->tunnel_type ==I40E_CLOUD_TYPE_UDP || tunnel_filter->tunnel_type ==I40E_CLOUD_TYPE_TCP || tunnel_filter->tunnel_type ==I40E_CLOUD_TYPE_SCTP ) {if (tunnel_filter->l4_port_type ==I40E_L4_PORT_TYPE_SRC ) - cld_filter.element.flags |= + cld_filter->element.flags |=I40E_AQC_ADD_CLOUD_FILTER_0X11 ;else - cld_filter.element.flags |= + cld_filter->element.flags |=I40E_AQC_ADD_CLOUD_FILTER_0X10 ; }else { val =i40e_dev_get_filter_type (tunnel_filter->filter_type, - &cld_filter.element.flags); + &cld_filter->element.flags);if (val <0 ) {return -EINVAL ; } } - cld_filter.element.flags |= + cld_filter->element.flags |=rte_cpu_to_le_16 (I40E_AQC_ADD_CLOUD_FLAGS_TO_QUEUE | ip_type | (tun_type <<I40E_AQC_ADD_CLOUD_TNL_TYPE_SHIFT )); - cld_filter.element.tenant_id =rte_cpu_to_le_32 (tunnel_filter->tenant_id); - cld_filter.element.queue_number = + cld_filter->element.tenant_id =rte_cpu_to_le_32 (tunnel_filter->tenant_id); + cld_filter->element.queue_number =rte_cpu_to_le_16 (tunnel_filter->queue_id);if (!tunnel_filter->is_to_vf) - vsi = pf->main_vsi; + *vsi = pf->main_vsi;else {if (tunnel_filter->vf_id >= pf->vf_num) {PMD_DRV_LOG (ERR ,"Invalid argument." );return -EINVAL ; } vf = &pf->vfs[tunnel_filter->vf_id]; - vsi = vf->vsi; + *vsi = vf->vsi; } -/* Check if there is the filter in SW list */ -memset (&check_filter,0 ,sizeof (check_filter)); -i40e_tunnel_filter_convert (&cld_filter, &check_filter); - check_filter.is_to_vf = tunnel_filter->is_to_vf; - check_filter.vf_id = tunnel_filter->vf_id; - node =i40e_sw_tunnel_filter_lookup (tunnel_rule, &check_filter.input); -if (add && node) { -PMD_DRV_LOG (ERR ,"Conflict with existing tunnel rules!" ); -return -EINVAL ; - } +return 0 ; +} -if (!add && !node) { -PMD_DRV_LOG (ERR ,"There's no corresponding tunnel filter!" ); -return -EINVAL ; - } +int +i40e_tunnel_filter_match_key_get (struct i40e_pf *pf, +struct i40e_tunnel_filter_conf *tunnel_filter, +struct i40e_tunnel_filter_match_key *input) +{ +struct i40e_aqc_cloud_filters_element_bb cld_filter = {0 }; +struct i40e_vsi *vsi; +bool big_buffer =0 ; +int ret; + + ret =i40e_tunnel_filter_convert_conf (pf, tunnel_filter, &cld_filter, + &vsi, &big_buffer); +if (ret !=0 ) +return ret; + +rte_ether_addr_copy ((struct rte_ether_addr *) + &cld_filter.element.outer_mac, + (struct rte_ether_addr *)&input->outer_mac); +rte_ether_addr_copy ((struct rte_ether_addr *) + &cld_filter.element.inner_mac, + (struct rte_ether_addr *)&input->inner_mac); + input->inner_vlan = cld_filter.element.inner_vlan; +if ((rte_le_to_cpu_16 (cld_filter.element.flags) & +I40E_AQC_ADD_CLOUD_FLAGS_IPV6 ) == +I40E_AQC_ADD_CLOUD_FLAGS_IPV6 ) + input->ip_type =I40E_TUNNEL_IPTYPE_IPV6 ; +else + input->ip_type =I40E_TUNNEL_IPTYPE_IPV4 ; + input->flags = cld_filter.element.flags; + input->tenant_id = cld_filter.element.tenant_id; +memcpy (input->general_fields, cld_filter.general_fields, +sizeof (cld_filter.general_fields)); + +return 0 ; +} + +int +i40e_tunnel_filter_program (struct i40e_pf *pf, +struct i40e_tunnel_filter_conf *tunnel_filter, +uint8_t add) +{ +struct i40e_hw *hw =I40E_PF_TO_HW (pf); +struct i40e_aqc_cloud_filters_element_bb cld_filter = {0 }; +struct i40e_vsi *vsi; +bool big_buffer =0 ; +int ret; + + ret =i40e_tunnel_filter_convert_conf (pf, tunnel_filter, &cld_filter, + &vsi, &big_buffer); +if (ret !=0 ) +return ret;if (add) { -struct i40e_tunnel_filter *tunnel; -if (big_buffer) ret =i40e_aq_add_cloud_filters_bb (hw, vsi->seid, &cld_filter,1 );
@@ -8527,16 +7991,6 @@ i40e_dev_consistent_tunnel_filter_set(struct i40e_pf *pf,PMD_DRV_LOG (ERR ,"Failed to add a tunnel filter." );return -ENOTSUP ; } - tunnel =rte_zmalloc ("tunnel_filter" ,sizeof (*tunnel),0 ); -if (tunnel ==NULL ) { -PMD_DRV_LOG (ERR ,"Failed to alloc memory." ); -return -ENOMEM ; - } - -memcpy (tunnel, &check_filter,sizeof (check_filter)); - ret =i40e_sw_tunnel_filter_insert (pf, tunnel); -if (ret <0 ) -rte_free (tunnel); }else {if (big_buffer) ret = i40e_aq_rem_cloud_filters_bb(
@@ -8548,7 +8002,6 @@ i40e_dev_consistent_tunnel_filter_set(struct i40e_pf *pf,PMD_DRV_LOG (ERR ,"Failed to delete a tunnel filter." );return -ENOTSUP ; } - ret =i40e_sw_tunnel_filter_del (pf, &node->input); }return ret;
@@ -11256,65 +10709,9 @@ i40e_dev_mtu_set(struct rte_eth_dev *dev, uint16_t mtu __rte_unused)return 0 ; } -/* Restore tunnel filter */ -static void -i40e_tunnel_filter_restore (struct i40e_pf *pf) -{ -struct i40e_hw *hw =I40E_PF_TO_HW (pf); -struct i40e_vsi *vsi; -struct i40e_pf_vf *vf; -struct i40e_tunnel_filter_list - *tunnel_list = &pf->tunnel.tunnel_list; -struct i40e_tunnel_filter *f; -struct i40e_aqc_cloud_filters_element_bb cld_filter; -bool big_buffer =0 ; - - TAILQ_FOREACH(f, tunnel_list, rules) { -if (!f->is_to_vf) - vsi = pf->main_vsi; -else { - vf = &pf->vfs[f->vf_id]; - vsi = vf->vsi; - } -memset (&cld_filter,0 ,sizeof (cld_filter)); -rte_ether_addr_copy ((struct rte_ether_addr *) - &f->input.outer_mac, - (struct rte_ether_addr *)&cld_filter.element.outer_mac); -rte_ether_addr_copy ((struct rte_ether_addr *) - &f->input.inner_mac, - (struct rte_ether_addr *)&cld_filter.element.inner_mac); - cld_filter.element.inner_vlan = f->input.inner_vlan; - cld_filter.element.flags = f->input.flags; - cld_filter.element.tenant_id = f->input.tenant_id; - cld_filter.element.queue_number = f->queue; -memcpy (cld_filter.general_fields, - f->input.general_fields, -sizeof (f->input.general_fields)); - -if (((f->input.flags & -I40E_AQC_ADD_CLOUD_FILTER_0X11 ) == -I40E_AQC_ADD_CLOUD_FILTER_0X11 ) || - ((f->input.flags & -I40E_AQC_ADD_CLOUD_FILTER_0X12 ) == -I40E_AQC_ADD_CLOUD_FILTER_0X12 ) || - ((f->input.flags & -I40E_AQC_ADD_CLOUD_FILTER_0X10 ) == -I40E_AQC_ADD_CLOUD_FILTER_0X10 )) - big_buffer =1 ; - -if (big_buffer) -i40e_aq_add_cloud_filters_bb (hw, - vsi->seid, &cld_filter,1 ); -else -i40e_aq_add_cloud_filters (hw, vsi->seid, - &cld_filter.element,1 ); - } -} -static void i40e_filter_restore (struct i40e_pf *pf) { -i40e_tunnel_filter_restore (pf);i40e_fdir_filter_restore (pf); (void )i40e_hash_filter_restore (pf); }
@@ -11747,133 +11144,6 @@ i40e_update_customized_info(struct rte_eth_dev *dev, uint8_t *pkg,free (proto); } -/* Create a QinQ cloud filter -* -* The Fortville NIC has limited resources for tunnel filters, -* so we can only reuse existing filters. -* -* In step 1 we define which Field Vector fields can be used for -* filter types. -* As we do not have the inner tag defined as a field, -* we have to define it first, by reusing one of L1 entries. -* -* In step 2 we are replacing one of existing filter types with -* a new one for QinQ. -* As we reusing L1 and replacing L2, some of the default filter -* types will disappear,which depends on L1 and L2 entries we reuse. -* -* Step 1: Create L1 filter of outer vlan (12b) + inner vlan (12b) -* -* 1. Create L1 filter of outer vlan (12b) which will be in use -* later when we define the cloud filter. -* a. Valid_flags.replace_cloud = 0 -* b. Old_filter = 10 (Stag_Inner_Vlan) -* c. New_filter = 0x10 -* d. TR bit = 0xff (optional, not used here) -* e. Buffer – 2 entries: -* i. Byte 0 = 8 (outer vlan FV index). -* Byte 1 = 0 (rsv) -* Byte 2-3 = 0x0fff -* ii. Byte 0 = 37 (inner vlan FV index). -* Byte 1 =0 (rsv) -* Byte 2-3 = 0x0fff -* -* Step 2: -* 2. Create cloud filter using two L1 filters entries: stag and -* new filter(outer vlan+ inner vlan) -* a. Valid_flags.replace_cloud = 1 -* b. Old_filter = 1 (instead of outer IP) -* c. New_filter = 0x10 -* d. Buffer – 2 entries: -* i. Byte 0 = 0x80 | 7 (valid | Stag). -* Byte 1-3 = 0 (rsv) -* ii. Byte 8 = 0x80 | 0x10 (valid | new l1 filter step1) -* Byte 9-11 = 0 (rsv) -*/ -static int -i40e_cloud_filter_qinq_create (struct i40e_pf *pf) -{ -int ret = -ENOTSUP ; -struct i40e_aqc_replace_cloud_filters_cmd filter_replace; -struct i40e_aqc_replace_cloud_filters_cmd_buf filter_replace_buf; -struct i40e_hw *hw =I40E_PF_TO_HW (pf); -struct rte_eth_dev *dev = &rte_eth_devices[pf->dev_data->port_id]; - -if (pf->support_multi_driver) { -PMD_DRV_LOG (ERR ,"Replace cloud filter is not supported." ); -return ret; - } - -/* Init */ -memset (&filter_replace,0 , -sizeof (struct i40e_aqc_replace_cloud_filters_cmd )); -memset (&filter_replace_buf,0 , -sizeof (struct i40e_aqc_replace_cloud_filters_cmd_buf )); - -/* create L1 filter */ - filter_replace.old_filter_type = -I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_STAG_IVLAN ; - filter_replace.new_filter_type =I40E_AQC_ADD_CLOUD_FILTER_0X10 ; - filter_replace.tr_bit =0 ; - -/* Prepare the buffer, 2 entries */ - filter_replace_buf.data[0 ] =I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_VLAN ; - filter_replace_buf.data[0 ] |= -I40E_AQC_REPLACE_CLOUD_CMD_INPUT_VALIDATED ; -/* Field Vector 12b mask */ - filter_replace_buf.data[2 ] =0xff ; - filter_replace_buf.data[3 ] =0x0f ; - filter_replace_buf.data[4 ] = -I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_INNER_VLAN ; - filter_replace_buf.data[4 ] |= -I40E_AQC_REPLACE_CLOUD_CMD_INPUT_VALIDATED ; -/* Field Vector 12b mask */ - filter_replace_buf.data[6 ] =0xff ; - filter_replace_buf.data[7 ] =0x0f ; - ret =i40e_aq_replace_cloud_filters (hw, &filter_replace, - &filter_replace_buf); -if (ret !=I40E_SUCCESS ) -return ret; - -if (filter_replace.old_filter_type != - filter_replace.new_filter_type) -PMD_DRV_LOG (WARNING ,"i40e device %s changed cloud l1 type." -" original: 0x%x, new: 0x%x" , - dev->device->name, - filter_replace.old_filter_type, - filter_replace.new_filter_type); - -/* Apply the second L2 cloud filter */ -memset (&filter_replace,0 , -sizeof (struct i40e_aqc_replace_cloud_filters_cmd )); -memset (&filter_replace_buf,0 , -sizeof (struct i40e_aqc_replace_cloud_filters_cmd_buf )); - -/* create L2 filter, input for L2 filter will be L1 filter */ - filter_replace.valid_flags =I40E_AQC_REPLACE_CLOUD_FILTER ; - filter_replace.old_filter_type =I40E_AQC_ADD_CLOUD_FILTER_OIP ; - filter_replace.new_filter_type =I40E_AQC_ADD_CLOUD_FILTER_0X10 ; - -/* Prepare the buffer, 2 entries */ - filter_replace_buf.data[0 ] =I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_STAG ; - filter_replace_buf.data[0 ] |= -I40E_AQC_REPLACE_CLOUD_CMD_INPUT_VALIDATED ; - filter_replace_buf.data[4 ] =I40E_AQC_ADD_CLOUD_FILTER_0X10 ; - filter_replace_buf.data[4 ] |= -I40E_AQC_REPLACE_CLOUD_CMD_INPUT_VALIDATED ; - ret =i40e_aq_replace_cloud_filters (hw, &filter_replace, - &filter_replace_buf); -if (!ret && (filter_replace.old_filter_type != - filter_replace.new_filter_type)) -PMD_DRV_LOG (WARNING ,"i40e device %s changed cloud filter type." -" original: 0x%x, new: 0x%x" , - dev->device->name, - filter_replace.old_filter_type, - filter_replace.new_filter_type); - -return ret; -} -static int i40e_fec_get_capability (struct rte_eth_dev *dev, struct rte_eth_fec_capa *speed_fec_capa, __rte_unused unsigned int num)
drivers/net/intel/i40e/i40e_ethdev.h +43 -41
133 lines not on this page · raw message
drivers/net/intel/i40e/i40e_flow.c +7 -1695
1,579 lines not on this page · raw message
drivers/net/intel/i40e/i40e_flow_tunnel.c new file +1958 -0
1,958 lines not on this page · raw message
The rest of this diff is not shown. View the raw message.
Signature · 1 line
2.52.0
Part of the diff is not shown here. View the raw message.
PATCH v5 24/25 net/i40e: reimplement hash parser
In reply to Anatoly BurakovUse the new flow graph API and the common parsing framework to implement flow parser for RSS.
The RSS parser was bypassing the other generic infrastructure, probably because it was very convoluted and did not map onto that model very well. It has now been made a first-class citizen.
The hash parser is multiple engines that share state, so each engine will attach to the shared refcounted RSS configuration state.
Additionally, this is the final engine in i40e, so remaining legacy flow infrastructure has been removed.
--- drivers/net/intel/i40e/i40e_ethdev.c | 34 +- drivers/net/intel/i40e/i40e_ethdev.h | 36 +- drivers/net/intel/i40e/i40e_flow.c | 289 +---- drivers/net/intel/i40e/i40e_flow.h | 3 + drivers/net/intel/i40e/i40e_flow_hash.c | 1454 +++++++++++++++++++++++ drivers/net/intel/i40e/i40e_hash.c | 1212 +------------------ drivers/net/intel/i40e/i40e_hash.h | 19 +- drivers/net/intel/i40e/meson.build | 1 + 8 files changed, 1565 insertions(+), 1483 deletions(-) create mode 100644 drivers/net/intel/i40e/i40e_flow_hash.c
drivers/net/intel/i40e/i40e_ethdev.c +21 -13
@@ -1027,6 +1027,27 @@ i40e_tunnel_state_detach(struct i40e_tunnel_state *state) state->hash_table =NULL ; } +struct i40e_rss_state * +i40e_rss_state_attach (struct rte_eth_dev_data *dev_data) +{ +struct i40e_pf *pf =I40E_DEV_PRIVATE_TO_PF (dev_data->dev_private); +struct i40e_rss_state *state = &pf->rss_state; + +if (ci_usage_count_claim (&state->use_count)) +TAILQ_INIT (&state->list); + +return state; +} + +void +i40e_rss_state_detach (struct i40e_rss_state *state) +{ +if (!ci_usage_count_release (&state->use_count)) +return ; + + *state = (struct i40e_rss_state ){0 }; +} +static void i40e_init_customized_info (struct i40e_pf *pf) {
@@ -1630,9 +1651,6 @@ eth_i40e_dev_init(struct rte_eth_dev *dev, void *init_params __rte_unused)*/ i40e_add_tx_flow_control_drop_filter (pf); -/* initialize RSS rule list */ -TAILQ_INIT (&pf->rss_config_list); -/* initialize Traffic Manager configuration */ i40e_tm_conf_init (dev);
@@ -1775,8 +1793,6 @@ i40e_dev_configure(struct rte_eth_dev *dev) } } -TAILQ_INIT (&pf->flow_list); -return 0 ; err_dcb:
@@ -2444,7 +2460,6 @@ i40e_dev_close(struct rte_eth_dev *dev)struct rte_pci_device *pci_dev =RTE_CLASS_TO_BUS_DEVICE (dev, *pci_dev);struct rte_intr_handle *intr_handle = pci_dev->intr_handle;struct i40e_filter_control_settings settings; -struct rte_flow *p_flow;uint32_t reg;int i;int ret;
@@ -2536,12 +2551,6 @@ i40e_dev_close(struct rte_eth_dev *dev)i40e_msec_delay (500 ); }while (retries++ <5 ); -/* Remove all flows */ -while ((p_flow =TAILQ_FIRST (&pf->flow_list))) { -TAILQ_REMOVE (&pf->flow_list, p_flow, node); -rte_free (p_flow); - } -/* Remove all Traffic Manager configuration */ i40e_tm_conf_uninit (dev);
@@ -10713,7 +10722,6 @@ static void i40e_filter_restore(struct i40e_pf *pf) {i40e_fdir_filter_restore (pf); - (void )i40e_hash_filter_restore (pf); }bool
drivers/net/intel/i40e/i40e_ethdev.h +18 -18
@@ -282,9 +282,6 @@ enum i40e_flxpld_layer_idx {*/ struct rte_flow {struct ci_flow base; -TAILQ_ENTRY (rte_flow) node; -enum rte_filter_type filter_type; -void *rule; };/**
@@ -993,8 +990,6 @@ struct i40e_tunnel_filter_conf {uint16_t vf_id;/**< VF id, available when is_to_vf is 1. */ }; -TAILQ_HEAD (i40e_flow_list, rte_flow); -/* Struct to store Traffic Manager shaper profile. */ struct i40e_tm_shaper_profile {TAILQ_ENTRY (i40e_tm_shaper_profile) node;
@@ -1081,7 +1076,7 @@ struct i40e_customized_pctype {#define I40E_RSS_KEY_LEN ((I40E_PFQF_HKEY_MAX_INDEX + 1) * sizeof(uint32_t)) -struct i40e_rte_flow_rss_conf { +struct i40e_rss_conf {enum rte_eth_hash_function func;uint64_t types;/**< Specific RSS hash types (see RTE_ETH_RSS_*). */ uint32_t key_len;/**< Hash key length in bytes. */
@@ -1116,14 +1111,23 @@ struct i40e_rss_filter_data {uint64_t reset_symmetric_pctypes; }; -/* RSS filter list structure */ -struct i40e_rss_filter { -TAILQ_ENTRY (i40e_rss_filter) next; -struct i40e_rte_flow_rss_conf rss_filter_info; +/* +* Tracking entry for a registered RSS flow: points back to the flow that +* owns the rss_conf, plus the metadata recording which HW state it owns. +*/ +struct i40e_rss_flow_node { +TAILQ_ENTRY (i40e_rss_flow_node) next; +struct ci_flow *flow;struct i40e_rss_filter_data filter_data; }; -TAILQ_HEAD (i40e_rss_conf_list, i40e_rss_filter); +TAILQ_HEAD (i40e_rss_node_list, i40e_rss_flow_node); + +/* RSS flow engine shared state, attached/detached by the RSS engines */ +struct i40e_rss_state { +ci_usage_count_t use_count; +struct i40e_rss_node_list list; +};struct i40e_vf_msg_cfg {/* maximal VF message during a statistic period */
@@ -1200,13 +1204,12 @@ struct i40e_pf {struct i40e_fdir_info fdir;/* flow director info */ struct i40e_tunnel_state tunnel_state;/* tunnel flow engine state */ -struct i40e_rss_conf_list rss_config_list;/* RSS rule list */ +struct i40e_rss_state rss_state;/* RSS flow engine state */ struct i40e_queue_regions queue_region;/* queue region info */ struct i40e_fc_conf fc_conf;/* Flow control conf */ bool floating_veb;/* The flag to use the floating VEB */ /* The floating enable flag for the specific VF */ bool floating_veb_list[I40E_MAX_VF ]; -struct i40e_flow_list flow_list;/* flow engine configuration */ struct ci_flow_engine_conf flow_engine_conf;struct i40e_tm_conf tm_conf;
@@ -1339,11 +1342,6 @@ struct i40e_vf_representor {extern const struct rte_flow_ops i40e_flow_ops; -struct i40e_filter_ctx { -struct i40e_rte_flow_rss_conf rss_conf; -enum rte_filter_type type; -}; -int i40e_dev_switch_queues (struct i40e_pf *pf,bool on);int i40e_vsi_release (struct i40e_vsi *vsi); struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf,
@@ -1456,6 +1454,8 @@ int i40e_tunnel_filter_match_key_get(struct i40e_pf *pf, struct i40e_tunnel_filter_match_key *out);struct i40e_tunnel_state *i40e_tunnel_state_attach (struct rte_eth_dev_data *dev_data);void i40e_tunnel_state_detach (struct i40e_tunnel_state *state); +struct i40e_rss_state *i40e_rss_state_attach (struct rte_eth_dev_data *dev_data); +void i40e_rss_state_detach (struct i40e_rss_state *state);int i40e_tunnel_filter_program (struct i40e_pf *pf,struct i40e_tunnel_filter_conf *tunnel_filter,uint8_t add);
drivers/net/intel/i40e/i40e_flow.c +10 -279
347 lines not on this page · raw message
drivers/net/intel/i40e/i40e_flow.h +3 -0
@@ -23,5 +23,8 @@ extern const struct ci_flow_engine i40e_flow_engine_tunnel_nvgre;extern const struct ci_flow_engine i40e_flow_engine_tunnel_mpls;extern const struct ci_flow_engine i40e_flow_engine_tunnel_gtp;extern const struct ci_flow_engine i40e_flow_engine_tunnel_l4; +extern const struct ci_flow_engine i40e_flow_engine_hash_pattern; +extern const struct ci_flow_engine i40e_flow_engine_hash_vlan; +extern const struct ci_flow_engine i40e_flow_engine_hash_empty;#endif /* _I40E_FLOW_H_ */
drivers/net/intel/i40e/i40e_flow_hash.c new file +1454 -0
1,454 lines not on this page · raw message
drivers/net/intel/i40e/i40e_hash.c +52 -1160
1,035 lines not on this page · raw message
The rest of this diff is not shown. View the raw message.
Signature · 1 line
2.52.0
Part of the diff is not shown here. View the raw message.
PATCH v5 25/25 net/i40e: advertise flow keep capability
In reply to Anatoly BurakovThe i40e driver's rte_flow implementation has always endeavored to keep flows across device restart, however it never advertised this capability. Advertise it explicitly.
--- doc/guides/rel_notes/release_26_11.rst | 5 +++++ drivers/net/intel/i40e/i40e_ethdev.c | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-)
doc/guides/rel_notes/release_26_11.rst +5 -0
@@ -109,6 +109,11 @@ New Features * Advertised ``RTE_ETH_DEV_CAPA_FLOW_RULE_KEEP`` capability, as flow rules were already kept across device restart. +* **Updated Intel i40e driver.** + + * Advertised ``RTE_ETH_DEV_CAPA_FLOW_RULE_KEEP`` capability, + as flow rules were already kept across device restart. + * **Updated NXP DPAA2 ethernet driver.** * Added the inner IP header to the RSS hash so tunneled traffic is
drivers/net/intel/i40e/i40e_ethdev.c +2 -1
@@ -3631,7 +3631,8 @@ i40e_dev_info_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info) dev_info->dev_capa =RTE_ETH_DEV_CAPA_RUNTIME_RX_QUEUE_SETUP |RTE_ETH_DEV_CAPA_RUNTIME_TX_QUEUE_SETUP ; - dev_info->dev_capa &= ~RTE_ETH_DEV_CAPA_FLOW_RULE_KEEP ; +/* rte_flow rules are kept across dev_stop/dev_start and replayed on start */ + dev_info->dev_capa |=RTE_ETH_DEV_CAPA_FLOW_RULE_KEEP ; dev_info->hash_key_size = (I40E_PFQF_HKEY_MAX_INDEX +1 ) *sizeof (uint32_t );
Signature · 1 line
2.52.0
v6 cover Building a better rte_flow parser
In reply to Anatoly BurakovMost rte_flow parsers in DPDK suffer from huge implementation complexity because even though 99% of what people use rte_flow parsers for is parsing protocol graphs, no parser is written explicitly as a graph. This patchset attempts to suggest a viable model to build rte_flow parsers as graphs, by offering a library to build rte_flow parser graphs without too much boilerplate and complexity.
Most of the patchset is about Intel drivers, but they are meant as reimplementations as well as examples for the rest of the community to assess how to build parsers using this new infrastructure. I expect the first three patches will be of most interest to non-Intel reviewers, as they deal with building two reusable parser architecture pieces.
The first piece is a new flow graph helper in ethdev. Its purpose is deliberately narrow: it targets the protocol-graph part of rte_flow pattern parsing, where drivers walk packet headers and validate legal item sequences and parameters. That does not cover all possible rte_flow features, especially more exotic flow items, but it does cover a large and widely shared part of what existing drivers need to do. Or, to put it in other words, the only flow items this infrastructure *doesn't* cover is things that do not lend themselves well to be parsed as a graph of protocol headers (e.g. conntrack items). Everything else should be covered or cover-able. In practice, just about all drivers will benefit from graph parsing as all but one of them implement only the protocol stack parts, which are the ones targeted by the graph helper.
The second piece is a reusable flow engine framework for Intel Ethernet drivers. This is kept Intel-local because I do not feel it is even appropriate to define such a framework for all drivers to use in the first place. Even so, the intent is to establish a cleaner parser architecture with a defined interaction model, explicit memory ownership rules, locking, initialization sequence, implementations of rte_flow API entry points, flow replay and memory cleanup, and engine definitions that do not block secondary-process-safe usage. It is my hope that this would serve as a model for other drivers to follow, expand on, rework, and improve, so that maybe down the line we *might* have a common rte_flow infrastructure for drivers to use.
Most of the rest of the series is parser reimplementation, but that is mainly the vehicle for demonstrating and validating those two pieces. ixgbe and i40e are wired into the new common parsing path, and their existing parsers are migrated incrementally to the graph-based model. Besides reducing ad hoc parser code, this also makes validation more explicit and more consistent. In a few places that means invalid inputs that were previously ignored, deferred, or interpreted loosely are now rejected earlier and more strictly, without any increase in code complexity (in fact, with marked *decrease* of it!).
v5 -> v6:
- Renamed all underscored functions in flow graph
- Reclassified cleanup/replay as engine conf operations
- Added better logging to flow graph parse function
v4 -> v5:
- Fixed ixgbe ntuple parsing of L4 protocol flows
- Rebased on top of latest ixgbe changes
- Revised ixgbe FDIR refactoring to have less duplication
v3 -> v4:
- Added a "get default mask" flow API
- Simplified graph constraints implementation
- Made flow graph a compiled unit instead of header-only library
- Reworked all graph engines to use default flow mask if user didn't provide one
- Split out ixgbe ethertype refactor into a separate patch
- Split out SYN and ntuple priority fixes as separate patches
- Refactored ixgbe RSS configuration structure
- Address Vladimir's feedback for specific engines
- Address Stephen's comments
- Reduced the number of comments in code
v2 -> v3:
- Rebase on top of latest next-net-intel
- Cleanup pass on naming of engines and hash tables
- Added more logging to flow engine initializations
- Introduced a lightweight refcount to initialize shared resources
- Some small refactors in how ixgbe flow director engine keeps its state
- Fixed typos in documentation
v1 -> v2:
- Renamed rte_flow_graph to flow_graph
- Addressed some comments from Stephen's AI review
- Removed the rte_flow_conv hack on account of Stephen's upcoming patches making the API stable
- Split up "flow_install" into register and install steps, which enabled two new use cases: cleanup of memory without HW deregistration, and flow configuration replay after dev_start
- More aggressive refactoring of all engines on account of new pieces of infrastructure, which allows for reduced complexity of implementation
- Combined i40e tunnel engine patches into one patch
- Added i40e flow director refactoring to cleanly support the new API as well as the legacy PMD-specific API
RFC -> v1:
- Fixed a lot of bugs, concurrency issues, and init/uninit sequence problems in Intel common flow engine implementation
- Fixed a few copypaste errors in various engines
- Improved comment documentation and flow engine docs
Anatoly Burakov (25):
ethdev: add default mask query to flow
ethdev: add flow graph API net/intel/common: add flow engines infrastructure net/intel/common: add utility functions net/ixgbe: add support for common flow parsing net/ixgbe: make ethertype filter table dynamic net/ixgbe: reimplement ethertype parser net/ixgbe: fix syn filter priority net/ixgbe: reimplement syn parser net/ixgbe: reimplement L2 tunnel parser net/ixgbe: fix ntuple filter priority net/ixgbe: fix protocol-only ntuple parsing net/ixgbe: reimplement ntuple parser net/ixgbe: reimplement security parser net/ixgbe: reimplement FDIR parser net/ixgbe: don't embed RSS conf in filter structs net/ixgbe: reimplement hash parser net/ixgbe: advertise flow keep capability net/i40e: add support for common flow parsing net/i40e: reimplement ethertype parser net/i40e: refactor FDIR engine infrastructure net/i40e: reimplement FDIR parser net/i40e: reimplement tunnel parsers net/i40e: reimplement hash parser net/i40e: advertise flow keep capability
doc/guides/prog_guide/ethdev/flow_graph.rst | 750 +++ doc/guides/prog_guide/ethdev/index.rst | 1 + doc/guides/rel_notes/release_26_11.rst | 22 +- drivers/net/intel/common/flow_engine.h | 1423 ++++++ drivers/net/intel/common/flow_util.h | 263 ++ drivers/net/intel/i40e/i40e_ethdev.c | 1523 +----- drivers/net/intel/i40e/i40e_ethdev.h | 322 +- drivers/net/intel/i40e/i40e_fdir.c | 1126 +++-- drivers/net/intel/i40e/i40e_flow.c | 4185 +---------------- drivers/net/intel/i40e/i40e_flow.h | 30 + drivers/net/intel/i40e/i40e_flow_ethertype.c | 351 ++ drivers/net/intel/i40e/i40e_flow_fdir.c | 2154 +++++++++ drivers/net/intel/i40e/i40e_flow_hash.c | 1454 ++++++ drivers/net/intel/i40e/i40e_flow_tunnel.c | 1958 ++++++++ drivers/net/intel/i40e/i40e_hash.c | 1212 +---- drivers/net/intel/i40e/i40e_hash.h | 19 +- drivers/net/intel/i40e/meson.build | 4 + drivers/net/intel/i40e/rte_pmd_i40e.c | 12 +- drivers/net/intel/ixgbe/ixgbe_ethdev.c | 1014 +--- drivers/net/intel/ixgbe/ixgbe_ethdev.h | 285 +- drivers/net/intel/ixgbe/ixgbe_fdir.c | 610 +-- drivers/net/intel/ixgbe/ixgbe_flow.c | 3243 +------------ drivers/net/intel/ixgbe/ixgbe_flow.h | 27 + .../net/intel/ixgbe/ixgbe_flow_ethertype.c | 299 ++ drivers/net/intel/ixgbe/ixgbe_flow_fdir.c | 1602 +++++++ drivers/net/intel/ixgbe/ixgbe_flow_hash.c | 216 + drivers/net/intel/ixgbe/ixgbe_flow_l2tun.c | 322 ++ drivers/net/intel/ixgbe/ixgbe_flow_ntuple.c | 694 +++ drivers/net/intel/ixgbe/ixgbe_flow_security.c | 586 +++ drivers/net/intel/ixgbe/ixgbe_flow_syn.c | 312 ++ drivers/net/intel/ixgbe/ixgbe_ipsec.c | 361 +- drivers/net/intel/ixgbe/ixgbe_ipsec.h | 50 +- drivers/net/intel/ixgbe/ixgbe_pf.c | 49 +- drivers/net/intel/ixgbe/ixgbe_rxtx.c | 80 +- .../net/intel/ixgbe/ixgbe_rxtx_vec_common.c | 4 +- drivers/net/intel/ixgbe/meson.build | 7 + lib/ethdev/flow_graph.c | 273 ++ lib/ethdev/flow_graph.h | 149 + lib/ethdev/meson.build | 2 + lib/ethdev/rte_flow.c | 207 +- lib/ethdev/rte_flow.h | 15 + 41 files changed, 14853 insertions(+), 12363 deletions(-) create mode 100644 doc/guides/prog_guide/ethdev/flow_graph.rst create mode 100644 drivers/net/intel/common/flow_engine.h create mode 100644 drivers/net/intel/common/flow_util.h create mode 100644 drivers/net/intel/i40e/i40e_flow.h create mode 100644 drivers/net/intel/i40e/i40e_flow_ethertype.c create mode 100644 drivers/net/intel/i40e/i40e_flow_fdir.c create mode 100644 drivers/net/intel/i40e/i40e_flow_hash.c create mode 100644 drivers/net/intel/i40e/i40e_flow_tunnel.c create mode 100644 drivers/net/intel/ixgbe/ixgbe_flow.h create mode 100644 drivers/net/intel/ixgbe/ixgbe_flow_ethertype.c create mode 100644 drivers/net/intel/ixgbe/ixgbe_flow_fdir.c create mode 100644 drivers/net/intel/ixgbe/ixgbe_flow_hash.c create mode 100644 drivers/net/intel/ixgbe/ixgbe_flow_l2tun.c create mode 100644 drivers/net/intel/ixgbe/ixgbe_flow_ntuple.c create mode 100644 drivers/net/intel/ixgbe/ixgbe_flow_security.c create mode 100644 drivers/net/intel/ixgbe/ixgbe_flow_syn.c create mode 100644 lib/ethdev/flow_graph.c create mode 100644 lib/ethdev/flow_graph.h
Signature · 1 line
2.52.0
PATCH v6 1/25 ethdev: add default mask query to flow
The rte_flow API defines that if the mask provided with the flow item is NULL, a default mask should be used where applicable. There is no API to get such mask, so add this API to rte_flow.
--- doc/guides/rel_notes/release_26_11.rst | 5 + lib/ethdev/rte_flow.c | 207 ++++++++++++++++++------- lib/ethdev/rte_flow.h | 15 ++ 3 files changed, 167 insertions(+), 60 deletions(-)
doc/guides/rel_notes/release_26_11.rst +5 -0
@@ -64,6 +64,11 @@ New Features Added ``rte_vlan_insert_tpid()`` to the net library. +* **Added flow item default mask lookup.** + + Added ``RTE_FLOW_CONV_OP_ITEM_DEFAULT_MASK_PTR`` conversion operation + to ``rte_flow_conv()`` to retrieve the default mask of a flow item type. + * **Updated AF_XDP driver.** * Changed the default device plugin endpoint path used when
lib/ethdev/rte_flow.c +147 -60
246 lines not on this page · raw message
lib/ethdev/rte_flow.h +15 -0
@@ -4411,6 +4411,21 @@ enum rte_flow_conv_op {* @code const char ** @endcode */ RTE_FLOW_CONV_OP_ACTION_NAME_PTR , + +/** +* Convert item type to pointer to its default mask. +* +* Writes a pointer to rte_flow_item_{name}_mask to @p dst, +* or NULL if the item type has no default mask. The mask itself is not +* copied; instead, a unique pointer to an internal static constant +* storage is written to @p dst. +* +* - @p src type: +* @code (const void *)enum rte_flow_item_type @endcode +* - @p dst type: +* @code const void ** @endcode +*/ + RTE_FLOW_CONV_OP_ITEM_DEFAULT_MASK_PTR, };/**
Signature · 1 line
2.52.0
Re: [PATCH v6 01/25] ethdev: add default mask query to flow
Quoted 8 lines · Anatoly Burakov
The
rte_flowAPI defines that if the mask provided with the flow item is NULL, a default mask should be used where applicable. There is no API to get such mask, so add this API torte_flow.Signed-off-by Anatoly Burakov <[email protected]>Acked-by Thomas Monjalon <[email protected]>---
Signature · 2 lines
Regards, Vladimir