IAVF Fixes
cover IAVF Fixes
An assortment of IAVF flow-related memory leak fixes and cleanups.
Anatoly Burakov (7):
net/iavf: fix memory leak in flow teardown net/iavf: fix null engine for egress security flows net/iavf: fix generic flow error-path leaks net/iavf: fix flow subscription metadata leaks net/iavf: fix hash flow metadata leaks net/iavf: fix IPsec flow metadata leaks net/iavf: do not store ethdev pointer
drivers/net/intel/iavf/iavf.h | 9 +- drivers/net/intel/iavf/iavf_ethdev.c | 13 +- drivers/net/intel/iavf/iavf_fdir.c | 3 - drivers/net/intel/iavf/iavf_fsub.c | 7 +- drivers/net/intel/iavf/iavf_generic_flow.c | 58 +++---- drivers/net/intel/iavf/iavf_generic_flow.h | 4 +- drivers/net/intel/iavf/iavf_hash.c | 24 ++- drivers/net/intel/iavf/iavf_ipsec_crypto.c | 191 +++++++++++++++++---- drivers/net/intel/iavf/iavf_ipsec_crypto.h | 4 +- drivers/net/intel/iavf/iavf_vchnl.c | 7 +- 10 files changed, 222 insertions(+), 98 deletions(-)
Signature · 1 line
2.52.0
PATCH 2/7 net/iavf: fix null engine for egress security flows
Egress security flows bypass the flow parsers and are inserted with a NULL engine pointer. The create path then dereferences that pointer when logging the new flow, and other engine-based operations cannot handle the flow consistently.
Register an egress security engine and route these flows through the normal parser and lifecycle callbacks. Egress flows own no rule and require no hardware teardown.
--- drivers/net/intel/iavf/iavf_generic_flow.c | 44 ++----- drivers/net/intel/iavf/iavf_generic_flow.h | 2 +- drivers/net/intel/iavf/iavf_ipsec_crypto.c | 130 +++++++++++++++++++-- 3 files changed, 133 insertions(+), 43 deletions(-)
drivers/net/intel/iavf/iavf_generic_flow.c +12 -32
@@ -1903,7 +1903,8 @@ iavf_register_parser(struct iavf_flow_parser *parser, } }TAILQ_INSERT_HEAD (list, parser_node, node); - }else if (parser->engine->type ==IAVF_FLOW_ENGINE_IPSEC_CRYPTO ) { + }else if (parser->engine->type ==IAVF_FLOW_ENGINE_IPSEC_CRYPTO || + parser->engine->type ==IAVF_FLOW_ENGINE_IPSEC_EGRESS ) { list = &vf->ipsec_crypto_parser_list;TAILQ_INSERT_HEAD (list, parser_node, node); }else if (parser->engine->type ==IAVF_FLOW_ENGINE_FSUB ) {
@@ -1932,7 +1933,8 @@ iavf_unregister_parser(struct iavf_flow_parser *parser,else if ((parser->engine->type ==IAVF_FLOW_ENGINE_FDIR ) || (parser->engine->type ==IAVF_FLOW_ENGINE_FSUB )) list = &vf->dist_parser_list; -else if (parser->engine->type ==IAVF_FLOW_ENGINE_IPSEC_CRYPTO ) +else if (parser->engine->type ==IAVF_FLOW_ENGINE_IPSEC_CRYPTO || + parser->engine->type ==IAVF_FLOW_ENGINE_IPSEC_EGRESS ) list = &vf->ipsec_crypto_parser_list;if (list ==NULL )
@@ -2220,12 +2222,6 @@ iavf_flow_create(struct rte_eth_dev *dev,return flow; } -/* Special case for inline crypto egress flows */ -if (attr->egress && actions[0 ].type ==RTE_FLOW_ACTION_TYPE_SECURITY ) { - flow->is_ipsec_egress_flow = true; - goto tailq_insert; - } - ret =iavf_flow_process_filter (dev, flow, attr, pattern, actions, &engine, iavf_parse_engine_create, error);if (ret <0 ) {
@@ -2236,7 +2232,6 @@ iavf_flow_create(struct rte_eth_dev *dev, } flow->engine = engine; -tailq_insert:rte_spinlock_lock (&vf->flow_ops_lock);TAILQ_INSERT_TAIL (&vf->flow_list, flow, node);rte_spinlock_unlock (&vf->flow_ops_lock);
@@ -2252,14 +2247,7 @@ iavf_flow_is_valid(struct rte_flow *flow)struct iavf_flow_engine *engine;void *temp; -if (flow ==NULL ) -return false; - -/* these flows don't use engines */ -if (flow->is_ipsec_egress_flow) -return true; - -if (flow->engine) { +if (flow !=NULL && flow->engine !=NULL ) { RTE_TAILQ_FOREACH_SAFE(engine, &engine_list, node, temp) {if (engine == flow->engine)return true;
@@ -2277,26 +2265,17 @@ iavf_flow_destroy(struct rte_eth_dev *dev,struct iavf_adapter *ad =IAVF_DEV_PRIVATE_TO_ADAPTER (dev->data->dev_private);struct iavf_info *vf =IAVF_DEV_PRIVATE_TO_VF (ad); -bool need_destroy;int ret =0 ; -if (!iavf_flow_is_valid (flow)) { +if (!iavf_flow_is_valid (flow) || flow->engine->destroy ==NULL ) {rte_flow_error_set (error,EINVAL ,RTE_FLOW_ERROR_TYPE_HANDLE ,NULL ,"Invalid flow destroy" );return -rte_errno; } - need_destroy = !flow->is_ipsec_egress_flow; - -if (need_destroy && flow->engine->destroy ==NULL ) { -return rte_flow_error_set (error,EINVAL , -RTE_FLOW_ERROR_TYPE_HANDLE ,NULL , -"Invalid flow destroy" ); - }rte_spinlock_lock (&vf->flow_ops_lock); -if (need_destroy) - ret = flow->engine->destroy (ad, flow, error); + ret = flow->engine->destroy (ad, flow, error);if (!ret) {TAILQ_REMOVE (&vf->flow_list, flow, node);
@@ -2415,16 +2394,17 @@ iavf_flow_dev_dump(struct rte_eth_dev *dev,if (flow !=NULL && f != flow)continue ; -/* this should not happen */ -if (f->engine ==NULL || f->rule ==NULL ) { +if (!iavf_flow_is_valid (f)) {PMD_DRV_LOG (DEBUG ,"Invalid flow" );continue ; } found = true; - rule_size = f->engine->rule_size; - rule_data = f->rule; +if (f->rule !=NULL ) { + rule_size = f->engine->rule_size; + rule_data = f->rule; + } iavf_flow_dump_blob(file, f->engine->name != NULL ?
drivers/net/intel/iavf/iavf_generic_flow.h +1 -1
@@ -481,6 +481,7 @@ enum iavf_flow_engine_type {IAVF_FLOW_ENGINE_FDIR ,IAVF_FLOW_ENGINE_HASH ,IAVF_FLOW_ENGINE_FSUB , +IAVF_FLOW_ENGINE_IPSEC_EGRESS , IAVF_FLOW_ENGINE_MAX, };
@@ -503,7 +504,6 @@ TAILQ_HEAD(iavf_engine_list, iavf_flow_engine);/* Struct to store flow created. */ struct rte_flow {TAILQ_ENTRY (rte_flow) node; -bool is_ipsec_egress_flow;struct iavf_flow_engine *engine;void *rule; };
drivers/net/intel/iavf/iavf_ipsec_crypto.c +120 -10
155 lines not on this page · raw message
Signature · 1 line
2.52.0
PATCH 1/7 net/iavf: fix memory leak in flow teardown
In reply to Anatoly BurakovFlow uninit skips hardware teardown during a PF-initiated reset, but only the hash engine provides a callback to free its rule. FDIR, flow subscription and IPsec rules are therefore leaked. Conversely, hash destroy removes its rule from hardware but frees only the flow handle.
Free the rule alongside the flow handle in the generic destroy and uninit paths. Remove the engine-specific rule frees and the redundant free callback, so both paths have the same software ownership.
--- drivers/net/intel/iavf/iavf_fdir.c | 3 --- drivers/net/intel/iavf/iavf_fsub.c | 3 --- drivers/net/intel/iavf/iavf_generic_flow.c | 4 ++-- drivers/net/intel/iavf/iavf_generic_flow.h | 2 -- drivers/net/intel/iavf/iavf_hash.c | 9 --------- drivers/net/intel/iavf/iavf_ipsec_crypto.c | 1 - 6 files changed, 2 insertions(+), 20 deletions(-)
drivers/net/intel/iavf/iavf_fdir.c +0 -3
@@ -406,9 +406,6 @@ iavf_fdir_destroy(struct iavf_adapter *ad,if (filter->mark_flag ==1 )iavf_fdir_rx_proc_enable (ad,0 ); - flow->rule =NULL ; -rte_free (filter); -return 0 ; }
drivers/net/intel/iavf/iavf_fsub.c +0 -3
@@ -120,9 +120,6 @@ iavf_fsub_destroy(struct iavf_adapter *ad, struct rte_flow *flow,return -rte_errno; } - flow->rule =NULL ; -rte_free (filter); -return ret; }
drivers/net/intel/iavf/iavf_generic_flow.c +2 -2
@@ -1851,8 +1851,7 @@ iavf_flow_uninit(struct iavf_adapter *ad)/* Remove all flows */ while ((p_flow =TAILQ_FIRST (&vf->flow_list))) {TAILQ_REMOVE (&vf->flow_list, p_flow, node); -if (p_flow->engine->free) - p_flow->engine->free (p_flow); +rte_free (p_flow->rule);rte_free (p_flow); }
@@ -2301,6 +2300,7 @@ iavf_flow_destroy(struct rte_eth_dev *dev,if (!ret) {TAILQ_REMOVE (&vf->flow_list, flow, node); +rte_free (flow->rule);rte_free (flow); }else {PMD_DRV_LOG (ERR ,"Failed to destroy flow" );
drivers/net/intel/iavf/iavf_generic_flow.h +0 -2
@@ -465,7 +465,6 @@ typedef int (*engine_query_t)(struct iavf_adapter *ad,struct rte_flow *flow, struct rte_flow_query_count *count, struct rte_flow_error *error); -typedef void (*engine_free_t ) (struct rte_flow *flow); typedef int (*parse_pattern_action_t)(struct iavf_adapter *ad, struct iavf_pattern_match_item *array, uint32_t array_len,
@@ -494,7 +493,6 @@ struct iavf_flow_engine {engine_create_t create;engine_destroy_t destroy;engine_query_t query_count; -engine_free_t free;const char *name;enum iavf_flow_engine_type type;size_t rule_size;
drivers/net/intel/iavf/iavf_hash.c +0 -9
@@ -79,8 +79,6 @@ iavf_hash_destroy(struct iavf_adapter *ad, struct rte_flow *flow, struct rte_flow_error *error);static void iavf_hash_uninit_parser (struct iavf_adapter *ad); -static void -iavf_hash_free (struct rte_flow *flow); static int iavf_hash_parse_pattern_action(struct iavf_adapter *ad, struct iavf_pattern_match_item *array,
@@ -682,7 +680,6 @@ static struct iavf_flow_engine iavf_hash_engine = { .create = iavf_hash_create, .destroy = iavf_hash_destroy, .uninit = iavf_hash_uninit_parser, - .free = iavf_hash_free, .name = "hash", .type = IAVF_FLOW_ENGINE_HASH, .rule_size = sizeof(struct virtchnl_rss_cfg),
@@ -1670,9 +1667,3 @@ iavf_hash_uninit(struct iavf_adapter *ad)if (iavf_rss_hash_set (ad, rss_conf->rss_hf, false))PMD_DRV_LOG (ERR ,"fail to delete default RSS" ); } - -static void -iavf_hash_free (struct rte_flow *flow) -{ -rte_free (flow->rule); -}
drivers/net/intel/iavf/iavf_ipsec_crypto.c +0 -1
@@ -1919,7 +1919,6 @@ iavf_ipsec_flow_destroy(struct iavf_adapter *ad,iavf_ipsec_crypto_security_policy_delete (ad, ipsec_flow->is_ipv4, ipsec_flow->id); -rte_free (ipsec_flow);return 0 ; }
Signature · 1 line
2.52.0
PATCH 4/7 net/iavf: fix flow subscription metadata leaks
In reply to Anatoly BurakovFlow subscription parsing allocates metadata for create and validate. The create callback leaks it when rule allocation or subscription fails, and the validate callback never frees it.
Release the metadata on both create failure paths and after validation.
--- drivers/net/intel/iavf/iavf_fsub.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/net/intel/iavf/iavf_fsub.c +3 -1
@@ -81,7 +81,7 @@ iavf_fsub_create(struct iavf_adapter *ad, struct rte_flow *flow,rte_flow_error_set (error,ENOMEM ,RTE_FLOW_ERROR_TYPE_HANDLE ,NULL ,"Failed to allocate memory for fsub rule" ); -return -rte_errno; + goto free_entry; } ret =iavf_flow_sub (ad, filter);
@@ -99,6 +99,7 @@ iavf_fsub_create(struct iavf_adapter *ad, struct rte_flow *flow,return ret; free_entry: +rte_free (meta);rte_free (rule);return -rte_errno; }
@@ -133,6 +134,7 @@ iavf_fsub_validation(struct iavf_adapter *ad,int ret; ret =iavf_flow_sub_check (ad, filter); +rte_free (filter);if (ret) { rte_flow_error_set(error, -ret, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
Signature · 1 line
2.52.0
PATCH 5/7 net/iavf: fix hash flow metadata leaks
In reply to Anatoly BurakovHash flow parsing allocates RSS metadata, but validation has no callback to release it. Creation also leaks the metadata if rule allocation or the request to add the RSS rule fails.
Add a validation callback to release the parsed metadata, and free it on both creation failure paths. Parsing already checks the RSS inputs; validation does not add or remove a rule.
--- drivers/net/intel/iavf/iavf_hash.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+)
drivers/net/intel/iavf/iavf_hash.c +15 -0
@@ -80,6 +80,9 @@ iavf_hash_destroy(struct iavf_adapter *ad, struct rte_flow *flow,static void iavf_hash_uninit_parser (struct iavf_adapter *ad);static int +iavf_hash_validation (struct iavf_adapter *ad,struct rte_flow *flow, +void *meta,struct rte_flow_error *error); +static int iavf_hash_parse_pattern_action(struct iavf_adapter *ad, struct iavf_pattern_match_item *array, uint32_t array_len,
@@ -680,6 +683,7 @@ static struct iavf_flow_engine iavf_hash_engine = { .create = iavf_hash_create, .destroy = iavf_hash_destroy, .uninit = iavf_hash_uninit_parser, + .validation = iavf_hash_validation, .name = "hash", .type = IAVF_FLOW_ENGINE_HASH, .rule_size = sizeof(struct virtchnl_rss_cfg),
@@ -1579,6 +1583,15 @@ iavf_hash_parse_pattern_action(struct iavf_adapter *ad,return ret; } +static int +iavf_hash_validation(__rte_unused struct iavf_adapter *ad, + __rte_unused struct rte_flow *flow, void *meta, + __rte_unused struct rte_flow_error *error) +{ +rte_free (meta); +return 0 ; +} + static int iavf_hash_create(__rte_unused struct iavf_adapter *ad, __rte_unused struct rte_flow *flow, void *meta,
@@ -1594,6 +1607,7 @@ iavf_hash_create(__rte_unused struct iavf_adapter *ad,rte_flow_error_set (error,EINVAL ,RTE_FLOW_ERROR_TYPE_HANDLE ,NULL ,"No memory for rss rule" ); +rte_free (meta);return -ENOMEM ; }
@@ -1609,6 +1623,7 @@ iavf_hash_create(__rte_unused struct iavf_adapter *ad,RTE_FLOW_ERROR_TYPE_HANDLE ,NULL , "Failed to add rss rule.");rte_free (rss_cfg); +rte_free (meta);return -rte_errno; }
Signature · 1 line
2.52.0
PATCH 3/7 net/iavf: fix generic flow error-path leaks
In reply to Anatoly BurakovIf a flow engine fails to initialize, parsers registered by earlier engines remain allocated. Pattern matching also leaks its item array when allocation of the match result fails.
Unwind registered parsers on flow initialization failure and free the item array on match-result allocation failure.
--- drivers/net/intel/iavf/iavf_generic_flow.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)
drivers/net/intel/iavf/iavf_generic_flow.c +8 -2
@@ -1821,17 +1821,22 @@ iavf_flow_init(struct iavf_adapter *ad)if (engine->init ==NULL ) {PMD_INIT_LOG (ERR ,"Invalid engine type (%d)" , engine->type); -return -ENOTSUP ; + ret = -ENOTSUP ; + goto err; } ret = engine->init (ad);if (ret && ret != -ENOTSUP ) {PMD_INIT_LOG (ERR ,"Failed to initialize engine %d" , engine->type); -return ret; + goto err; } }return 0 ; + +err: +iavf_flow_uninit (ad); +return ret; }void
@@ -2048,6 +2053,7 @@ iavf_search_pattern_match_item(const struct rte_flow_item pattern[],if (!pattern_match_item) {rte_flow_error_set (error,ENOMEM ,RTE_FLOW_ERROR_TYPE_HANDLE ,NULL ,"Failed to allocate memory." ); +rte_free (items);return NULL ; }
Signature · 1 line
2.52.0
PATCH 6/7 net/iavf: fix IPsec flow metadata leaks
In reply to Anatoly BurakovIPsec flow parsing leaves the pattern-match item allocated. Validation has no callback to release the parsed flow item, and creation leaks it when adding the security policy fails.
Free the pattern-match item after parsing, add a validation callback to release the parsed flow item, and free it if policy creation fails. Report a parsing error when no flow item was produced.
--- drivers/net/intel/iavf/iavf_ipsec_crypto.c | 40 +++++++++++++++++----- 1 file changed, 32 insertions(+), 8 deletions(-)
drivers/net/intel/iavf/iavf_ipsec_crypto.c +32 -8
@@ -1893,6 +1893,7 @@ iavf_ipsec_flow_create(struct iavf_adapter *ad, }if (flow_id <1 ) { +rte_free (ipsec_flow);rte_flow_error_set (error,EINVAL ,RTE_FLOW_ERROR_TYPE_UNSPECIFIED ,NULL ,"Failed to add SA." );
@@ -1923,6 +1924,16 @@ iavf_ipsec_flow_destroy(struct iavf_adapter *ad,return 0 ; } +static int +iavf_ipsec_flow_validation(__rte_unused struct iavf_adapter *ad, + __rte_unused struct rte_flow *flow, +void *meta, + __rte_unused struct rte_flow_error *error) +{ +rte_free (meta); +return 0 ; +} + static int iavf_ipsec_flow_parse(struct iavf_adapter *ad, struct iavf_pattern_match_item *array,
@@ -1942,6 +1953,7 @@ iavf_ipsec_flow_parse(struct iavf_adapter *ad, .max_actions = 1, };struct iavf_pattern_match_item *item =NULL ; +struct iavf_ipsec_flow_item *fi =NULL ;int ret =-1 ; ret =ci_flow_check_attr (attr,NULL , error);
@@ -1953,17 +1965,28 @@ iavf_ipsec_flow_parse(struct iavf_adapter *ad,return ret; item =iavf_search_pattern_match_item (pattern, array, array_len, error); -if (item && item->meta) { +if (item ==NULL ) +return -rte_errno; + +if (item->meta !=NULL ) {const struct rte_security_session *session = parsed_actions.actions[0 ]->conf;uint32_t type = (uint64_t )(item->meta); -struct iavf_ipsec_flow_item *fi = -iavf_ipsec_flow_item_parse (ad->vf.eth_dev, pattern, session, type); -if (fi && meta) { - *meta = fi; - ret =0 ; - } + + fi =iavf_ipsec_flow_item_parse (ad->vf.eth_dev, pattern, session, type); } -return ret; +rte_free (item); + +if (fi ==NULL ) +return rte_flow_error_set (error,EINVAL , +RTE_FLOW_ERROR_TYPE_ACTION ,NULL , +"Invalid IPsec flow." ); + +if (meta !=NULL ) + *meta = fi; +else +rte_free (fi); + +return 0 ; }/*
@@ -2060,6 +2083,7 @@ static struct iavf_flow_engine iavf_ipsec_flow_engine = { .uninit = iavf_ipsec_flow_uninit, .create = iavf_ipsec_flow_create, .destroy = iavf_ipsec_flow_destroy, + .validation = iavf_ipsec_flow_validation, .name = "ipsec_crypto", .type = IAVF_FLOW_ENGINE_IPSEC_CRYPTO, .rule_size = sizeof(struct iavf_ipsec_flow_item),
Signature · 1 line
2.52.0
PATCH 7/7 net/iavf: do not store ethdev pointer
In reply to Anatoly BurakovWe should not be storing rte_eth_dev pointers in shared memory, because rte_eth_dev pointers are process local. To address that, remove the pointer from iavf_info, replace it with rte_eth_devices-based lookup, and rework the call paths to either use that lookup, or not require ethdev pointer in the first place.
--- drivers/net/intel/iavf/iavf.h | 9 ++++++-- drivers/net/intel/iavf/iavf_ethdev.c | 13 ++++++------ drivers/net/intel/iavf/iavf_ipsec_crypto.c | 24 +++++++++++----------- drivers/net/intel/iavf/iavf_ipsec_crypto.h | 4 ++-- drivers/net/intel/iavf/iavf_vchnl.c | 7 ++++--- 5 files changed, 31 insertions(+), 26 deletions(-)
drivers/net/intel/iavf/iavf.h +7 -2
@@ -7,6 +7,7 @@#include <sys/queue.h> +#include <ethdev_driver.h> #include <rte_kvargs.h> #include <rte_tm_driver.h>
@@ -293,8 +294,6 @@ struct iavf_info {struct iavf_qtc_map *qtc_map;struct iavf_tm_conf tm_conf; -struct rte_eth_dev *eth_dev; -RTE_ATOMIC (bool )in_reset_recovery;bool reset_pending;bool pf_reset_in_progress;
@@ -408,6 +407,12 @@ struct iavf_adapter {uint16_t tpid;/* VLAN tag identifier */ }; +static inline struct rte_eth_dev * +iavf_get_eth_dev (struct iavf_adapter *adapter) +{ +return &rte_eth_devices[adapter->dev_data->port_id]; +} +/* IAVF_DEV_PRIVATE_TO */ #define IAVF_DEV_PRIVATE_TO_ADAPTER (adapter) \ ((struct iavf_adapter *)adapter)
drivers/net/intel/iavf/iavf_ethdev.c +6 -7
@@ -326,6 +326,7 @@ static void iavf_dev_watchdog(void *cb_arg) {struct iavf_adapter *adapter = cb_arg; +struct rte_eth_dev *dev =iavf_get_eth_dev (adapter);struct iavf_hw *hw =IAVF_DEV_PRIVATE_TO_HW (adapter);int vfr_inprogress =0 , rc =0 ;
@@ -339,7 +340,7 @@ iavf_dev_watchdog(void *cb_arg)if (!vfr_inprogress) {PMD_DRV_LOG (INFO ,"VF \"%s\" reset has completed" , - adapter->vf.eth_dev->data->name); + dev->data->name); adapter->vf.vf_reset = false;iavf_set_no_poll (adapter, false); }
@@ -350,14 +351,14 @@ iavf_dev_watchdog(void *cb_arg)if (vfr_inprogress) {PMD_DRV_LOG (INFO ,"VF \"%s\" reset event detected by watchdog" , - adapter->vf.eth_dev->data->name); + dev->data->name);/* enter reset state with VFLR event */ adapter->vf.vf_reset = true;iavf_set_no_poll (adapter, false); adapter->vf.link_up = false; -iavf_dev_event_post (adapter->vf.eth_dev,RTE_ETH_EVENT_INTR_RESET , +iavf_dev_event_post (dev,RTE_ETH_EVENT_INTR_RESET ,NULL ,0 ); } }
@@ -365,11 +366,11 @@ iavf_dev_watchdog(void *cb_arg)if (adapter->devargs.watchdog_period) {/* re-alarm watchdog */ rc =rte_eal_alarm_set (adapter->devargs.watchdog_period, - &iavf_dev_watchdog, cb_arg); + &iavf_dev_watchdog, dev);if (rc)PMD_DRV_LOG (ERR ,"Failed \"%s\" to reset device watchdog alarm" , - adapter->vf.eth_dev->data->name); + dev->data->name); } }
@@ -2674,8 +2675,6 @@ iavf_init_vf(struct rte_eth_dev *dev)struct iavf_hw *hw =IAVF_DEV_PRIVATE_TO_HW (dev->data->dev_private);struct iavf_info *vf =IAVF_DEV_PRIVATE_TO_VF (dev->data->dev_private); - vf->eth_dev = dev; - err =iavf_parse_devargs (dev);if (err) {PMD_INIT_LOG (ERR ,"Failed to parse devargs" );
drivers/net/intel/iavf/iavf_ipsec_crypto.c +12 -12
@@ -689,11 +689,9 @@ iavf_ipsec_crypto_session_create(void *device,* returns: 1 if valid */ uint32_t -iavf_ipsec_crypto_action_valid (struct rte_eth_dev *ethdev, +iavf_ipsec_crypto_action_valid (struct iavf_adapter *adapter,const struct rte_security_session *session,uint32_t spi) { -struct iavf_adapter *adapter = -IAVF_DEV_PRIVATE_TO_ADAPTER (ethdev->data->dev_private);const struct iavf_security_session *sess = (const void *)session->driver_priv_data;/* verify we have a valid session and that it belong to this adapter */
@@ -1502,24 +1500,25 @@ static struct rte_security_ops iavf_ipsec_crypto_ops = {int iavf_security_ctx_create (struct iavf_adapter *adapter) { +struct rte_eth_dev *dev =iavf_get_eth_dev (adapter);struct rte_security_ctx *sctx; sctx =rte_malloc ("security_ctx" ,sizeof (struct rte_security_ctx ),0 );if (sctx ==NULL )return -ENOMEM ; - sctx->device = adapter->vf.eth_dev; + sctx->device = dev; sctx->ops = &iavf_ipsec_crypto_ops; sctx->sess_cnt =0 ; - adapter->vf.eth_dev->security_ctx = sctx; + dev->security_ctx = sctx;if (adapter->security_ctx ==NULL ) { adapter->security_ctx =rte_malloc ("iavf_security_ctx" ,sizeof (struct iavf_security_ctx ),0 );if (adapter->security_ctx ==NULL ) { -rte_free (adapter->vf.eth_dev->security_ctx); - adapter->vf.eth_dev->security_ctx =NULL ; +rte_free (dev->security_ctx); + dev->security_ctx =NULL ;return -ENOMEM ; } }
@@ -1565,7 +1564,8 @@ iavf_security_get_pkt_md_offset(struct iavf_adapter *adapter)int iavf_security_ctx_destroy (struct iavf_adapter *adapter) { -struct rte_security_ctx *sctx = adapter->vf.eth_dev->security_ctx; +struct rte_eth_dev *dev =iavf_get_eth_dev (adapter); +struct rte_security_ctx *sctx = dev->security_ctx;struct iavf_security_ctx *iavf_sctx = adapter->security_ctx;if (iavf_sctx ==NULL )
@@ -1578,7 +1578,7 @@ iavf_security_ctx_destroy(struct iavf_adapter *adapter)rte_free (sctx); adapter->security_ctx =NULL ; - adapter->vf.eth_dev->security_ctx =NULL ; + dev->security_ctx =NULL ;return 0 ; }
@@ -1748,7 +1748,7 @@ parse_udp_item(const struct rte_flow_item_udp *item, struct rte_udp_hdr *udp) }static struct iavf_ipsec_flow_item * -iavf_ipsec_flow_item_parse (struct rte_eth_dev *ethdev, +iavf_ipsec_flow_item_parse (struct iavf_adapter *adapter,const struct rte_flow_item pattern[],const struct rte_security_session *session,uint32_t type)
@@ -1819,7 +1819,7 @@ iavf_ipsec_flow_item_parse(struct rte_eth_dev *ethdev, goto flow_cleanup; } -if (!iavf_ipsec_crypto_action_valid (ethdev, session, +if (!iavf_ipsec_crypto_action_valid (adapter, session, ipsec_flow->spi)) goto flow_cleanup;
@@ -1972,7 +1972,7 @@ iavf_ipsec_flow_parse(struct iavf_adapter *ad,const struct rte_security_session *session = parsed_actions.actions[0 ]->conf;uint32_t type = (uint64_t )(item->meta); - fi =iavf_ipsec_flow_item_parse (ad->vf.eth_dev, pattern, session, type); + fi =iavf_ipsec_flow_item_parse (ad, pattern, session, type); }rte_free (item);
drivers/net/intel/iavf/iavf_ipsec_crypto.h +2 -2
@@ -127,13 +127,13 @@ int iavf_security_get_pkt_md_offset(struct iavf_adapter *adapter);/** * Destroy security context */ -int iavf_security_ctx_destroy (struct iavf_adapter *adapterv); +int iavf_security_ctx_destroy (struct iavf_adapter *adapter);/** * Verify that the inline IPsec Crypto action is valid for this device */ uint32_t -iavf_ipsec_crypto_action_valid (struct rte_eth_dev *ethdev, +iavf_ipsec_crypto_action_valid (struct iavf_adapter *adapter,const struct rte_security_session *session,uint32_t spi);/**
drivers/net/intel/iavf/iavf_vchnl.c +4 -3
@@ -314,13 +314,14 @@ iavf_read_msg_from_pf(struct iavf_adapter *adapter, uint16_t buf_len, opcode, vf->cmd_retval);if (opcode ==VIRTCHNL_OP_EVENT ) { +struct rte_eth_dev *dev =iavf_get_eth_dev (adapter);struct virtchnl_pf_event *vpe = (struct virtchnl_pf_event *)event.msg_buf; result =IAVF_MSG_SYS ;switch (vpe->event) {case VIRTCHNL_EVENT_LINK_CHANGE : -iavf_handle_link_change_event (vf->eth_dev, vpe); +iavf_handle_link_change_event (dev, vpe);break ;case VIRTCHNL_EVENT_RESET_IMPENDING :/*
@@ -335,8 +336,8 @@ iavf_read_msg_from_pf(struct iavf_adapter *adapter, uint16_t buf_len,iavf_set_no_poll (adapter, false);iavf_dev_watchdog_enable (adapter);if (adapter->devargs.no_poll_on_link_down) -iavf_dev_tx_drain (vf->eth_dev); -iavf_dev_event_post (vf->eth_dev, +iavf_dev_tx_drain (dev); +iavf_dev_event_post (dev,RTE_ETH_EVENT_INTR_RESET ,NULL ,0 ); }
Signature · 1 line
2.52.0
RE: [PATCH v1 5/7] net/iavf: fix hash flow metadata leaks
In reply to Anatoly BurakovQuoted 78 lines
-----Original Message-----
From: Anatoly Burakov <[email protected]>
Sent: 14 October 2026 20:49
To: [email protected]
Subject: [PATCH v1 5/7] net/iavf: fix hash flow metadata leaksHash flow parsing allocates RSS metadata, but validation has no callback to release it. Creation also leaks the metadata if rule allocation or the request to add the RSS rule fails.
Add a validation callback to release the parsed metadata, and free it on both creation failure paths. Parsing already checks the RSS inputs; validation does not add or remove a rule.
Fixes 7be10c3004be ("net/iavf: add RSS configuration for VF")Fixes 215a247b5f33 ("net/iavf: refactor hash flow")Signed-off-by Anatoly Burakov <[email protected]>--- drivers/net/intel/iavf/iavf_hash.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+)drivers/net/intel/iavf/iavf_hash.c +0
-0@@ -80,6 +80,9 @@ iavf_hash_destroy(struct iavf_adapter *ad, struct rte_flow *flow, static void iavf_hash_uninit_parser(struct iavf_adapter *ad);static int
drivers/net/intel/iavf/iavf_hash.c +3
-0+iavf_hash_validation(struct iavf_adapter *ad, struct rte_flow *flow, + void *meta, struct rte_flow_error *error); static int iavf_hash_parse_pattern_action(struct iavf_adapter *ad, struct iavf_pattern_match_item *array, uint32_t array_len,@@ -680,6 +683,7 @@ static struct iavf_flow_engine iavf_hash_engine = { .create = iavf_hash_create, .destroy = iavf_hash_destroy, .uninit = iavf_hash_uninit_parser, + .validation = iavf_hash_validation, .name = "hash", .type = IAVF_FLOW_ENGINE_HASH, .rule_size = sizeof(struct virtchnl_rss_cfg), @@ -1579,6 +1583,15 @@iavf_hash_parse_pattern_action(struct
iavf_adapter*ad,drivers/net/intel/iavf/iavf_hash.c +11
-1return ret; } +static int +iavf_hash_validation(__rte_unused struct iavf_adapter *ad, + __rte_unused struct rte_flow *flow, void *meta, + __rte_unused struct rte_flow_error *error) { +rte_free (meta); +return 0 ; +} + static int iavf_hash_create(__rte_unused struct iavf_adapter *ad, __rte_unused struct rte_flow *flow, void *meta, @@ -1594,6 +1607,7 @@ iavf_hash_create(__rte_unused struct iavf_adapter *ad, rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_HANDLE, NULL, "No memory for rss rule"); +rte_free (meta);return -ENOMEM ; }@@ -1609,6 +1623,7 @@ iavf_hash_create(__rte_unused struct iavf_adapter *ad,RTE_FLOW_ERROR_TYPE_HANDLE ,NULL , "Failed to add rss rule.");rte_free (rss_cfg); +rte_free (meta);return -rte_errno; } --
Quoted 1 line
2.52.0
Hi Anatoly,
I had submitted similar fix in this patch earlier.
https://patches.dpdk.org/project/dpdk/patch/[email protected]/
Thanks,
Anurag M
Re: [PATCH v1 5/7] net/iavf: fix hash flow metadata leaks
Quoted 82 lines · Anurag
Quoted 78 lines
-----Original Message-----
From: Anatoly Burakov <[email protected]>
Sent: 14 October 2026 20:49
To: [email protected]
Subject: [PATCH v1 5/7] net/iavf: fix hash flow metadata leaksHash flow parsing allocates RSS metadata, but validation has no callback to release it. Creation also leaks the metadata if rule allocation or the request to add the RSS rule fails.
Add a validation callback to release the parsed metadata, and free it on both creation failure paths. Parsing already checks the RSS inputs; validation does not add or remove a rule.
Fixes 7be10c3004be ("net/iavf: add RSS configuration for VF")Fixes 215a247b5f33 ("net/iavf: refactor hash flow")Signed-off-by Anatoly Burakov <[email protected]>--- drivers/net/intel/iavf/iavf_hash.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+)drivers/net/intel/iavf/iavf_hash.c +0
-0@@ -80,6 +80,9 @@ iavf_hash_destroy(struct iavf_adapter *ad, struct rte_flow *flow, static void iavf_hash_uninit_parser(struct iavf_adapter *ad);static int
drivers/net/intel/iavf/iavf_hash.c +3
-0+iavf_hash_validation(struct iavf_adapter *ad, struct rte_flow *flow, + void *meta, struct rte_flow_error *error); static int iavf_hash_parse_pattern_action(struct iavf_adapter *ad, struct iavf_pattern_match_item *array, uint32_t array_len,@@ -680,6 +683,7 @@ static struct iavf_flow_engine iavf_hash_engine = { .create = iavf_hash_create, .destroy = iavf_hash_destroy, .uninit = iavf_hash_uninit_parser, + .validation = iavf_hash_validation, .name = "hash", .type = IAVF_FLOW_ENGINE_HASH, .rule_size = sizeof(struct virtchnl_rss_cfg), @@ -1579,6 +1583,15 @@iavf_hash_parse_pattern_action(struct
iavf_adapter*ad,
return ret;
}drivers/net/intel/iavf/iavf_hash.c +11
-1+static int +iavf_hash_validation(__rte_unused struct iavf_adapter *ad, + __rte_unused struct rte_flow *flow, void *meta, + __rte_unused struct rte_flow_error *error) { +rte_free (meta); +return 0 ; +} + static int iavf_hash_create(__rte_unused struct iavf_adapter *ad, __rte_unused struct rte_flow *flow, void *meta, @@ -1594,6 +1607,7 @@ iavf_hash_create(__rte_unused struct iavf_adapter *ad, rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_HANDLE, NULL, "No memory for rss rule"); +rte_free (meta);return -ENOMEM ; }@@ -1609,6 +1623,7 @@ iavf_hash_create(__rte_unused struct iavf_adapter *ad,RTE_FLOW_ERROR_TYPE_HANDLE ,NULL , "Failed to add rss rule.");rte_free (rss_cfg); +rte_free (meta);return -rte_errno; } --Quoted 1 line
2.52.0
Hi Anatoly,
Quoted 5 lines
I had submitted similar fix in this patch earlier.
https://patches.dpdk.org/project/dpdk/patch/[email protected]/Thanks,
Anurag M
Thanks, I didn't see it before! Your patch fixes some things mine doesn't, and vice versa, so what I'll do (if you don't mind!) is I'll respin my patchset and include your patch with my additions.
Signature · 2 lines
Thanks, Anatoly
v2 cover IAVF Fixes
In reply to Anatoly BurakovAn assortment of IAVF flow-related memory leak fixes and cleanups.
v1 -> v2:
- Integrated Anurag's earlier fix [1] into the patchset
- Reworked generic flow to have centralized memory management
- Reordered some patches
- Integrated the IRQ leaks patchset [2] [3]
- Reworked IPsec fix
[1] https://patches.dpdk.org/project/dpdk/patch/[email protected]/
[2] https://patches.dpdk.org/project/dpdk/patch/809e0c5b2ab57f1b14c68be8ac34e70cbbe82233.1792053236.git.anatoly.burakov@intel.com/
[3] https://patches.dpdk.org/project/dpdk/patch/5488d85c2ded08838becaee6de8328694ee00234.1792053236.git.anatoly.burakov@intel.com/
Anatoly Burakov (8):
net/iavf: keep device stopped if start fails net/iavf: do not store ethdev pointer net/iavf: fix false success on flow validation net/iavf: fix memory leaks around IRQ resources net/iavf: fix generic flow error-path leaks net/iavf: centralize memory management for flows net/iavf: fix null engine for egress security flows net/iavf: fix IPsec flow metadata leaks
Anurag Mandal (1):
net/iavf: fix memory leak in raw pattern parsing
drivers/net/intel/iavf/iavf.h | 14 +- drivers/net/intel/iavf/iavf_ethdev.c | 42 +++-- drivers/net/intel/iavf/iavf_fdir.c | 68 ++++---- drivers/net/intel/iavf/iavf_fsub.c | 23 +-- drivers/net/intel/iavf/iavf_generic_flow.c | 95 ++++++------ drivers/net/intel/iavf/iavf_generic_flow.h | 4 +- drivers/net/intel/iavf/iavf_hash.c | 80 +++------- drivers/net/intel/iavf/iavf_ipsec_crypto.c | 171 +++++++++++++++++---- drivers/net/intel/iavf/iavf_ipsec_crypto.h | 4 +- drivers/net/intel/iavf/iavf_vchnl.c | 7 +- 10 files changed, 296 insertions(+), 212 deletions(-)
Signature · 1 line
2.52.0
PATCH v2 1/9 net/iavf: keep device stopped if start fails
Currently, iavf_dev_start() clears adapter->stopped before several operations that can fail. A subsequent iavf_dev_stop() then disables interrupts and stops and resets queues even though startup did not complete.
Mark the adapter running only after startup succeeds, and return early from stop when it is already stopped.
--- drivers/net/intel/iavf/iavf_ethdev.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-)
drivers/net/intel/iavf/iavf_ethdev.c +4 -5
@@ -1039,8 +1039,6 @@ iavf_dev_start(struct rte_eth_dev *dev)if (adapter->closed)return -1 ; - adapter->stopped =0 ; - vf->max_pkt_len = dev->data->mtu +IAVF_ETH_OVERHEAD ; vf->num_queue_pairs =RTE_MAX (dev->data->nb_rx_queues, dev->data->nb_tx_queues);
@@ -1112,6 +1110,7 @@ iavf_dev_start(struct rte_eth_dev *dev) }iavf_phc_sync_alarm_start (dev); + adapter->stopped =0 ;/* An explicit start supersedes any pending deferred start */ vf->start_pending = false;
@@ -1135,13 +1134,13 @@ iavf_dev_stop(struct rte_eth_dev *dev)if (adapter->closed)return -1 ; +if (adapter->stopped ==1 ) +return 0 ; +if (!(vf->vf_res->vf_cap_flags &VIRTCHNL_VF_OFFLOAD_WB_ON_ITR ) && dev->data->dev_conf.intr_conf.rxq !=0 )rte_intr_disable (intr_handle); -if (adapter->stopped ==1 ) -return 0 ; -iavf_phc_sync_alarm_stop (dev);/* Disable the interrupt for Rx */
Signature · 1 line
2.52.0
PATCH v2 2/9 net/iavf: do not store ethdev pointer
In reply to Anatoly BurakovWe should not be storing rte_eth_dev pointers in shared memory, because rte_eth_dev pointers are process local. To address that, remove the pointer from iavf_info, replace it with rte_eth_devices-based lookup, and rework the call paths to either use that lookup, or not require ethdev pointer in the first place.
--- drivers/net/intel/iavf/iavf.h | 9 ++++++-- drivers/net/intel/iavf/iavf_ethdev.c | 13 ++++++------ drivers/net/intel/iavf/iavf_ipsec_crypto.c | 24 +++++++++++----------- drivers/net/intel/iavf/iavf_ipsec_crypto.h | 4 ++-- drivers/net/intel/iavf/iavf_vchnl.c | 7 ++++--- 5 files changed, 31 insertions(+), 26 deletions(-)
drivers/net/intel/iavf/iavf.h +7 -2
@@ -7,6 +7,7 @@#include <sys/queue.h> +#include <ethdev_driver.h> #include <rte_kvargs.h> #include <rte_tm_driver.h>
@@ -293,8 +294,6 @@ struct iavf_info {struct iavf_qtc_map *qtc_map;struct iavf_tm_conf tm_conf; -struct rte_eth_dev *eth_dev; -RTE_ATOMIC (bool )in_reset_recovery;bool reset_pending;bool pf_reset_in_progress;
@@ -408,6 +407,12 @@ struct iavf_adapter {uint16_t tpid;/* VLAN tag identifier */ }; +static inline struct rte_eth_dev * +iavf_get_eth_dev (struct iavf_adapter *adapter) +{ +return &rte_eth_devices[adapter->dev_data->port_id]; +} +/* IAVF_DEV_PRIVATE_TO */ #define IAVF_DEV_PRIVATE_TO_ADAPTER (adapter) \ ((struct iavf_adapter *)adapter)
drivers/net/intel/iavf/iavf_ethdev.c +6 -7
@@ -326,6 +326,7 @@ static void iavf_dev_watchdog(void *cb_arg) {struct iavf_adapter *adapter = cb_arg; +struct rte_eth_dev *dev =iavf_get_eth_dev (adapter);struct iavf_hw *hw =IAVF_DEV_PRIVATE_TO_HW (adapter);int vfr_inprogress =0 , rc =0 ;
@@ -339,7 +340,7 @@ iavf_dev_watchdog(void *cb_arg)if (!vfr_inprogress) {PMD_DRV_LOG (INFO ,"VF \"%s\" reset has completed" , - adapter->vf.eth_dev->data->name); + dev->data->name); adapter->vf.vf_reset = false;iavf_set_no_poll (adapter, false); }
@@ -350,14 +351,14 @@ iavf_dev_watchdog(void *cb_arg)if (vfr_inprogress) {PMD_DRV_LOG (INFO ,"VF \"%s\" reset event detected by watchdog" , - adapter->vf.eth_dev->data->name); + dev->data->name);/* enter reset state with VFLR event */ adapter->vf.vf_reset = true;iavf_set_no_poll (adapter, false); adapter->vf.link_up = false; -iavf_dev_event_post (adapter->vf.eth_dev,RTE_ETH_EVENT_INTR_RESET , +iavf_dev_event_post (dev,RTE_ETH_EVENT_INTR_RESET ,NULL ,0 ); } }
@@ -365,11 +366,11 @@ iavf_dev_watchdog(void *cb_arg)if (adapter->devargs.watchdog_period) {/* re-alarm watchdog */ rc =rte_eal_alarm_set (adapter->devargs.watchdog_period, - &iavf_dev_watchdog, cb_arg); + &iavf_dev_watchdog, dev);if (rc)PMD_DRV_LOG (ERR ,"Failed \"%s\" to reset device watchdog alarm" , - adapter->vf.eth_dev->data->name); + dev->data->name); } }
@@ -2669,8 +2670,6 @@ iavf_init_vf(struct rte_eth_dev *dev)struct iavf_hw *hw =IAVF_DEV_PRIVATE_TO_HW (dev->data->dev_private);struct iavf_info *vf =IAVF_DEV_PRIVATE_TO_VF (dev->data->dev_private); - vf->eth_dev = dev; - err =iavf_parse_devargs (dev);if (err) {PMD_INIT_LOG (ERR ,"Failed to parse devargs" );
drivers/net/intel/iavf/iavf_ipsec_crypto.c +12 -12
@@ -689,11 +689,9 @@ iavf_ipsec_crypto_session_create(void *device,* returns: 1 if valid */ uint32_t -iavf_ipsec_crypto_action_valid (struct rte_eth_dev *ethdev, +iavf_ipsec_crypto_action_valid (struct iavf_adapter *adapter,const struct rte_security_session *session,uint32_t spi) { -struct iavf_adapter *adapter = -IAVF_DEV_PRIVATE_TO_ADAPTER (ethdev->data->dev_private);const struct iavf_security_session *sess = (const void *)session->driver_priv_data;/* verify we have a valid session and that it belong to this adapter */
@@ -1502,24 +1500,25 @@ static struct rte_security_ops iavf_ipsec_crypto_ops = {int iavf_security_ctx_create (struct iavf_adapter *adapter) { +struct rte_eth_dev *dev =iavf_get_eth_dev (adapter);struct rte_security_ctx *sctx; sctx =rte_malloc ("security_ctx" ,sizeof (struct rte_security_ctx ),0 );if (sctx ==NULL )return -ENOMEM ; - sctx->device = adapter->vf.eth_dev; + sctx->device = dev; sctx->ops = &iavf_ipsec_crypto_ops; sctx->sess_cnt =0 ; - adapter->vf.eth_dev->security_ctx = sctx; + dev->security_ctx = sctx;if (adapter->security_ctx ==NULL ) { adapter->security_ctx =rte_malloc ("iavf_security_ctx" ,sizeof (struct iavf_security_ctx ),0 );if (adapter->security_ctx ==NULL ) { -rte_free (adapter->vf.eth_dev->security_ctx); - adapter->vf.eth_dev->security_ctx =NULL ; +rte_free (dev->security_ctx); + dev->security_ctx =NULL ;return -ENOMEM ; } }
@@ -1565,7 +1564,8 @@ iavf_security_get_pkt_md_offset(struct iavf_adapter *adapter)int iavf_security_ctx_destroy (struct iavf_adapter *adapter) { -struct rte_security_ctx *sctx = adapter->vf.eth_dev->security_ctx; +struct rte_eth_dev *dev =iavf_get_eth_dev (adapter); +struct rte_security_ctx *sctx = dev->security_ctx;struct iavf_security_ctx *iavf_sctx = adapter->security_ctx;if (iavf_sctx ==NULL )
@@ -1578,7 +1578,7 @@ iavf_security_ctx_destroy(struct iavf_adapter *adapter)rte_free (sctx); adapter->security_ctx =NULL ; - adapter->vf.eth_dev->security_ctx =NULL ; + dev->security_ctx =NULL ;return 0 ; }
@@ -1748,7 +1748,7 @@ parse_udp_item(const struct rte_flow_item_udp *item, struct rte_udp_hdr *udp) }static struct iavf_ipsec_flow_item * -iavf_ipsec_flow_item_parse (struct rte_eth_dev *ethdev, +iavf_ipsec_flow_item_parse (struct iavf_adapter *adapter,const struct rte_flow_item pattern[],const struct rte_security_session *session,uint32_t type)
@@ -1819,7 +1819,7 @@ iavf_ipsec_flow_item_parse(struct rte_eth_dev *ethdev, goto flow_cleanup; } -if (!iavf_ipsec_crypto_action_valid (ethdev, session, +if (!iavf_ipsec_crypto_action_valid (adapter, session, ipsec_flow->spi)) goto flow_cleanup;
@@ -1967,7 +1967,7 @@ iavf_ipsec_flow_parse(struct iavf_adapter *ad,const struct rte_security_session *session = parsed_actions.actions[0 ]->conf;uint32_t type = (uint64_t )(item->meta);struct iavf_ipsec_flow_item *fi = -iavf_ipsec_flow_item_parse (ad->vf.eth_dev, pattern, session, type); +iavf_ipsec_flow_item_parse (ad, pattern, session, type);if (fi && meta) { *meta = fi; ret =0 ;
drivers/net/intel/iavf/iavf_ipsec_crypto.h +2 -2
@@ -127,13 +127,13 @@ int iavf_security_get_pkt_md_offset(struct iavf_adapter *adapter);/** * Destroy security context */ -int iavf_security_ctx_destroy (struct iavf_adapter *adapterv); +int iavf_security_ctx_destroy (struct iavf_adapter *adapter);/** * Verify that the inline IPsec Crypto action is valid for this device */ uint32_t -iavf_ipsec_crypto_action_valid (struct rte_eth_dev *ethdev, +iavf_ipsec_crypto_action_valid (struct iavf_adapter *adapter,const struct rte_security_session *session,uint32_t spi);/**
drivers/net/intel/iavf/iavf_vchnl.c +4 -3
@@ -314,13 +314,14 @@ iavf_read_msg_from_pf(struct iavf_adapter *adapter, uint16_t buf_len, opcode, vf->cmd_retval);if (opcode ==VIRTCHNL_OP_EVENT ) { +struct rte_eth_dev *dev =iavf_get_eth_dev (adapter);struct virtchnl_pf_event *vpe = (struct virtchnl_pf_event *)event.msg_buf; result =IAVF_MSG_SYS ;switch (vpe->event) {case VIRTCHNL_EVENT_LINK_CHANGE : -iavf_handle_link_change_event (vf->eth_dev, vpe); +iavf_handle_link_change_event (dev, vpe);break ;case VIRTCHNL_EVENT_RESET_IMPENDING :/*
@@ -335,8 +336,8 @@ iavf_read_msg_from_pf(struct iavf_adapter *adapter, uint16_t buf_len,iavf_set_no_poll (adapter, false);iavf_dev_watchdog_enable (adapter);if (adapter->devargs.no_poll_on_link_down) -iavf_dev_tx_drain (vf->eth_dev); -iavf_dev_event_post (vf->eth_dev, +iavf_dev_tx_drain (dev); +iavf_dev_event_post (dev,RTE_ETH_EVENT_INTR_RESET ,NULL ,0 ); }
Signature · 1 line
2.52.0
PATCH v2 3/9 net/iavf: fix false success on flow validation
In reply to Anatoly Burakoviavf_parse_engine_validate() sets an error when validation fails, but then returns the engine pointer. iavf_flow_process_filter() treats a non-NULL engine as success, so rte_flow_validate() can accept an invalid flow.
Return NULL on validation failure and return the engine only after validation succeeds.
--- drivers/net/intel/iavf/iavf_generic_flow.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
drivers/net/intel/iavf/iavf_generic_flow.c +3 -2
@@ -2134,10 +2134,11 @@ iavf_parse_engine_validate(struct iavf_adapter *ad,rte_flow_error_set (error,EINVAL ,RTE_FLOW_ERROR_TYPE_HANDLE ,NULL ,"Validation failed" ); -break ; +return NULL ; } +return engine; } -return engine; +return NULL ; }
Signature · 1 line
2.52.0
PATCH v2 4/9 net/iavf: fix memory leak in raw pattern parsing
In reply to Anatoly BurakovFrom: Anurag Mandal <[email protected]>
If mask buffer allocation fails in iavf_hash_parse_raw_pattern(), the previously allocated packet buffer is leaked.
Free the packet buffer before returning the allocation error.
---
Notes:
The API was removed in 92ef4b8f1688 ("ethdev: remove deprecated shared counter attribute")
However, it may not be reasonable to pin a Fixline on that commit because that would imply that it *should have* updated ice driver's plubmbing to not support shared counters any more, which I do not believe is reasonable. I'm leaving this note for posterity and in case it is determined that the Fixline is needed after all.
drivers/net/intel/iavf/iavf_hash.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/net/intel/iavf/iavf_hash.c +3 -1
@@ -918,8 +918,10 @@ iavf_hash_parse_raw_pattern(const struct rte_flow_item *item,return -ENOMEM ; msk_buf =rte_zmalloc (NULL , pkt_len,0 ); -if (!msk_buf) +if (!msk_buf) { +rte_free (pkt_buf);return -ENOMEM ; + }/* convert string to int array */ for (i =0 , j =0 ; i < spec_len; i +=2 , j++) {
Signature · 1 line
2.52.0
PATCH v2 5/9 net/iavf: fix memory leaks around IRQ resources
In reply to Anatoly Burakoviavf_config_rx_queues_irqs() allocates a queue-vector map and may enable eventfds and allocate an interrupt vector list. If queue startup then fails, those resources remain allocated. The queue-vector map is also retained after a normal stop, leaking it across start/stop cycles.
Release the resources on failed startup and free the queue-vector map on stop. Clean up eventfds when interrupt setup fails as well.
--- drivers/net/intel/iavf/iavf_ethdev.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-)
drivers/net/intel/iavf/iavf_ethdev.c +18 -4
@@ -863,7 +863,7 @@ static int iavf_config_rx_queues_irqs(struct rte_eth_dev *dev,if (rte_intr_cap_multiple (intr_handle) && dev->data->dev_conf.intr_conf.rxq) {if (rte_intr_efd_enable (intr_handle, dev->data->nb_rx_queues)) -return -1 ; + goto efd_alloc_err; }if (rte_intr_dp_is_en (intr_handle)) {
@@ -871,7 +871,7 @@ static int iavf_config_rx_queues_irqs(struct rte_eth_dev *dev, dev->data->nb_rx_queues)) {PMD_DRV_LOG (ERR ,"Failed to allocate %d rx intr_vec" , dev->data->nb_rx_queues); -return -1 ; + goto qv_map_alloc_err; } }
@@ -981,6 +981,8 @@ static int iavf_config_rx_queues_irqs(struct rte_eth_dev *dev, qv_map_alloc_err:rte_intr_vec_list_free (intr_handle); +efd_alloc_err: +rte_intr_efd_disable (intr_handle);return -1 ; }
@@ -1034,12 +1036,15 @@ iavf_dev_start(struct rte_eth_dev *dev)struct rte_intr_handle *intr_handle = dev->intr_handle;uint16_t num_queue_pairs;uint16_t index =0 ; +bool wb_on_itr;PMD_INIT_FUNC_TRACE ();if (adapter->closed)return -1 ; + wb_on_itr = (vf->vf_res->vf_cap_flags &VIRTCHNL_VF_OFFLOAD_WB_ON_ITR ) !=0 ; + vf->max_pkt_len = dev->data->mtu +IAVF_ETH_OVERHEAD ; vf->num_queue_pairs =RTE_MAX (dev->data->nb_rx_queues, dev->data->nb_tx_queues);
@@ -1089,7 +1094,7 @@ iavf_dev_start(struct rte_eth_dev *dev) }/* re-enable intr again, because efd assign may change */ if (dev->data->dev_conf.intr_conf.rxq !=0 ) { -if (vf->vf_res->vf_cap_flags &VIRTCHNL_VF_OFFLOAD_WB_ON_ITR ) +if (wb_on_itr)rte_intr_disable (intr_handle);rte_intr_enable (intr_handle); }
@@ -1107,7 +1112,7 @@ iavf_dev_start(struct rte_eth_dev *dev)if (iavf_start_queues (dev) !=0 ) {PMD_DRV_LOG (ERR ,"enable queues failed" ); - goto error; + goto irq_error; }iavf_phc_sync_alarm_start (dev);
@@ -1118,6 +1123,13 @@ iavf_dev_start(struct rte_eth_dev *dev)return 0 ; +irq_error: +if (!wb_on_itr && dev->data->dev_conf.intr_conf.rxq !=0 ) +rte_intr_disable (intr_handle); +rte_intr_efd_disable (intr_handle); +rte_intr_vec_list_free (intr_handle); +rte_free (vf->qv_map); + vf->qv_map =NULL ; error:return -1 ; }
@@ -1150,6 +1162,8 @@ iavf_dev_stop(struct rte_eth_dev *dev)rte_intr_vec_list_free (intr_handle);iavf_stop_queues (dev); +rte_free (vf->qv_map); + vf->qv_map =NULL ; adapter->stopped =1 ; dev->data->dev_started =0 ;
Signature · 1 line
2.52.0
PATCH v2 6/9 net/iavf: fix generic flow error-path leaks
In reply to Anatoly BurakovIf a flow engine fails to initialize, parsers registered by earlier engines remain allocated. Pattern matching also leaks its item array when allocation of the match result fails.
Unwind registered parsers on flow initialization failure and free the item array on match-result allocation failure.
--- drivers/net/intel/iavf/iavf_generic_flow.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)
drivers/net/intel/iavf/iavf_generic_flow.c +8 -2
@@ -1821,17 +1821,22 @@ iavf_flow_init(struct iavf_adapter *ad)if (engine->init ==NULL ) {PMD_INIT_LOG (ERR ,"Invalid engine type (%d)" , engine->type); -return -ENOTSUP ; + ret = -ENOTSUP ; + goto err; } ret = engine->init (ad);if (ret && ret != -ENOTSUP ) {PMD_INIT_LOG (ERR ,"Failed to initialize engine %d" , engine->type); -return ret; + goto err; } }return 0 ; + +err: +iavf_flow_uninit (ad); +return ret; }void
@@ -2047,6 +2052,7 @@ iavf_search_pattern_match_item(const struct rte_flow_item pattern[],if (!pattern_match_item) {rte_flow_error_set (error,ENOMEM ,RTE_FLOW_ERROR_TYPE_HANDLE ,NULL ,"Failed to allocate memory." ); +rte_free (items);return NULL ; }
Signature · 1 line
2.52.0
PATCH v2 7/9 net/iavf: centralize memory management for flows
In reply to Anatoly BurakovFlow engines currently distribute rule allocation and cleanup between the parser, engine create and destroy callbacks, and generic flow code. This leads to a lot of potential for memory leaks and bugs. In particular, one of the issues currently present is that when PF initiates reset, we are meant to just drop all flows without sending any virtchnl commands, but because not all engines implement the free callback, some flows will be leaked.
To address that specific leak as well as all other potential leaks due to misuse of memory by engines, use parser-allocated rule objects as the persistent rules and centralize their lifetime in the generic flow layer. This requires fixing all engines to not manage their own memory:
- Allocate the final FDIR rule in the parser, use it for action checks, and remove the per-VF scratch configuration.
- Have FSUB create adopt its parser-produced rule instead of allocating and copying a second object.
- Build the final RSS configuration in the parser and remove the intermediate RSS metadata, including its unused raw-pattern flag.
- Let generic flow code free rules on validate, create failure, successful destroy, and uninit; remove engine-specific free callbacks and rule frees from destroy callbacks.
--- drivers/net/intel/iavf/iavf.h | 5 -- drivers/net/intel/iavf/iavf_fdir.c | 68 +++++++++---------- drivers/net/intel/iavf/iavf_fsub.c | 23 +------ drivers/net/intel/iavf/iavf_generic_flow.c | 36 ++++++++-- drivers/net/intel/iavf/iavf_generic_flow.h | 2 - drivers/net/intel/iavf/iavf_hash.c | 76 +++++++--------------- drivers/net/intel/iavf/iavf_ipsec_crypto.c | 1 - 7 files changed, 88 insertions(+), 123 deletions(-)
drivers/net/intel/iavf/iavf.h +0 -5
@@ -155,10 +155,6 @@ struct iavf_fdir_conf {uint32_t mark_flag; }; -struct iavf_fdir_info { -struct iavf_fdir_conf conf; -}; -struct iavf_fsub_conf {struct virtchnl_flow_sub sub_fltr;struct virtchnl_flow_unsub unsub_fltr;
@@ -286,7 +282,6 @@ struct iavf_info {struct iavf_parser_list dist_parser_list;struct iavf_parser_list ipsec_crypto_parser_list; -struct iavf_fdir_info fdir;/* flow director info */ /* indicate large VF support enabled or not */ bool lv_enabled;
drivers/net/intel/iavf/iavf_fdir.c +35 -33
138 lines not on this page · raw message
drivers/net/intel/iavf/iavf_fsub.c +2 -21
@@ -73,34 +73,18 @@ iavf_fsub_create(struct iavf_adapter *ad, struct rte_flow *flow, void *meta, struct rte_flow_error *error) { struct iavf_fsub_conf *filter = meta; -struct iavf_fsub_conf *rule;int ret; - rule =rte_zmalloc ("fsub_entry" ,sizeof (*rule),0 ); -if (!rule) { -rte_flow_error_set (error,ENOMEM , -RTE_FLOW_ERROR_TYPE_HANDLE ,NULL , -"Failed to allocate memory for fsub rule" ); -return -rte_errno; - } - ret =iavf_flow_sub (ad, filter);if (ret) {rte_flow_error_set (error, -ret,RTE_FLOW_ERROR_TYPE_HANDLE ,NULL ,"Failed to subscribe flow rule." ); - goto free_entry; +return -rte_errno; } -memcpy (rule, filter,sizeof (*rule)); - flow->rule = rule; - -rte_free (meta); + flow->rule = filter;return ret; - -free_entry: -rte_free (rule); -return -rte_errno; } static int
@@ -120,9 +104,6 @@ iavf_fsub_destroy(struct iavf_adapter *ad, struct rte_flow *flow,return -rte_errno; } - flow->rule =NULL ; -rte_free (filter); -return ret; }
drivers/net/intel/iavf/iavf_generic_flow.c +29 -7
@@ -46,6 +46,13 @@ static int iavf_flow_dev_dump(struct rte_eth_dev *dev,FILE *file, struct rte_flow_error *error); +static void +iavf_flow_free (struct rte_flow *flow) +{ +rte_free (flow->rule); +rte_free (flow); +} +const struct rte_flow_ops iavf_flow_ops = { .validate = iavf_flow_validate, .create = iavf_flow_create,
@@ -1856,9 +1863,7 @@ iavf_flow_uninit(struct iavf_adapter *ad)/* Remove all flows */ while ((p_flow =TAILQ_FIRST (&vf->flow_list))) {TAILQ_REMOVE (&vf->flow_list, p_flow, node); -if (p_flow->engine->free) - p_flow->engine->free (p_flow); -rte_free (p_flow); +iavf_flow_free (p_flow); }/* Cleanup parser list */
@@ -2092,6 +2097,7 @@ iavf_parse_engine_create(struct iavf_adapter *ad,void *meta =NULL ; RTE_TAILQ_FOREACH_SAFE(parser_node, parser_list, node, temp) { + meta =NULL ; if (parser_node->parser->parse_pattern_action(ad, parser_node->parser->array, parser_node->parser->array_len,
@@ -2101,8 +2107,17 @@ iavf_parse_engine_create(struct iavf_adapter *ad, engine = parser_node->parser->engine;RTE_ASSERT (engine->create !=NULL ); -if (!(engine->create (ad, flow, meta, error))) +if (engine->create (ad, flow, meta, error) ==0 ) { +if (flow->rule != meta) +rte_free (meta);return engine; + } + +if (flow->rule !=NULL && flow->rule != meta) +rte_free (flow->rule); +rte_free (meta); + flow->rule =NULL ; + meta =NULL ; }return NULL ; }
@@ -2120,8 +2135,10 @@ iavf_parse_engine_validate(struct iavf_adapter *ad,struct iavf_flow_parser_node *parser_node;void *temp;void *meta =NULL ; +int ret; RTE_TAILQ_FOREACH_SAFE(parser_node, parser_list, node, temp) { + meta =NULL ; if (parser_node->parser->parse_pattern_action(ad, parser_node->parser->array, parser_node->parser->array_len,
@@ -2130,13 +2147,18 @@ iavf_parse_engine_validate(struct iavf_adapter *ad, engine = parser_node->parser->engine;if (engine->validation ==NULL ) { +rte_free (meta); + meta =NULL ;rte_flow_error_set (error,EINVAL ,RTE_FLOW_ERROR_TYPE_HANDLE ,NULL ,"Validation not support" );continue ; } -if (engine->validation (ad, flow, meta, error)) { + ret = engine->validation (ad, flow, meta, error); +rte_free (meta); + meta =NULL ; +if (ret !=0 ) {rte_flow_error_set (error,EINVAL ,RTE_FLOW_ERROR_TYPE_HANDLE ,NULL ,"Validation failed" );
@@ -2238,7 +2260,7 @@ iavf_flow_create(struct rte_eth_dev *dev, &engine, iavf_parse_engine_create, error);if (ret <0 ) {PMD_DRV_LOG (ERR ,"Failed to create flow" ); -rte_free (flow); +iavf_flow_free (flow); flow =NULL ; goto free_flow; }
@@ -2308,7 +2330,7 @@ iavf_flow_destroy(struct rte_eth_dev *dev,if (!ret) {TAILQ_REMOVE (&vf->flow_list, flow, node); -rte_free (flow); +iavf_flow_free (flow); }else {PMD_DRV_LOG (ERR ,"Failed to destroy flow" ); }
drivers/net/intel/iavf/iavf_generic_flow.h +0 -2
@@ -465,7 +465,6 @@ typedef int (*engine_query_t)(struct iavf_adapter *ad,struct rte_flow *flow, struct rte_flow_query_count *count, struct rte_flow_error *error); -typedef void (*engine_free_t ) (struct rte_flow *flow); typedef int (*parse_pattern_action_t)(struct iavf_adapter *ad, struct iavf_pattern_match_item *array, uint32_t array_len,
@@ -494,7 +493,6 @@ struct iavf_flow_engine {engine_create_t create;engine_destroy_t destroy;engine_query_t query_count; -engine_free_t free;const char *name;enum iavf_flow_engine_type type;size_t rule_size;
drivers/net/intel/iavf/iavf_hash.c +22 -54
173 lines not on this page · raw message
drivers/net/intel/iavf/iavf_ipsec_crypto.c +0 -1
@@ -1919,7 +1919,6 @@ iavf_ipsec_flow_destroy(struct iavf_adapter *ad,iavf_ipsec_crypto_security_policy_delete (ad, ipsec_flow->is_ipv4, ipsec_flow->id); -rte_free (ipsec_flow);return 0 ; }
Signature · 1 line
2.52.0
PATCH v2 8/9 net/iavf: fix null engine for egress security flows
In reply to Anatoly BurakovEgress security flows bypass the flow parsers and are inserted with a NULL engine pointer. The create path then dereferences that pointer when logging the new flow, and other engine-based operations cannot handle the flow consistently.
Register an egress security engine and route these flows through the normal parser and lifecycle callbacks. Egress flows own no rule and require no hardware teardown.
--- drivers/net/intel/iavf/iavf_generic_flow.c | 44 +++----- drivers/net/intel/iavf/iavf_generic_flow.h | 2 +- drivers/net/intel/iavf/iavf_ipsec_crypto.c | 120 +++++++++++++++++++-- 3 files changed, 123 insertions(+), 43 deletions(-)
drivers/net/intel/iavf/iavf_generic_flow.c +12 -32
@@ -1914,7 +1914,8 @@ iavf_register_parser(struct iavf_flow_parser *parser, } }TAILQ_INSERT_HEAD (list, parser_node, node); - }else if (parser->engine->type ==IAVF_FLOW_ENGINE_IPSEC_CRYPTO ) { + }else if (parser->engine->type ==IAVF_FLOW_ENGINE_IPSEC_CRYPTO || + parser->engine->type ==IAVF_FLOW_ENGINE_IPSEC_EGRESS ) { list = &vf->ipsec_crypto_parser_list;TAILQ_INSERT_HEAD (list, parser_node, node); }else if (parser->engine->type ==IAVF_FLOW_ENGINE_FSUB ) {
@@ -1943,7 +1944,8 @@ iavf_unregister_parser(struct iavf_flow_parser *parser,else if ((parser->engine->type ==IAVF_FLOW_ENGINE_FDIR ) || (parser->engine->type ==IAVF_FLOW_ENGINE_FSUB )) list = &vf->dist_parser_list; -else if (parser->engine->type ==IAVF_FLOW_ENGINE_IPSEC_CRYPTO ) +else if (parser->engine->type ==IAVF_FLOW_ENGINE_IPSEC_CRYPTO || + parser->engine->type ==IAVF_FLOW_ENGINE_IPSEC_EGRESS ) list = &vf->ipsec_crypto_parser_list;if (list ==NULL )
@@ -2250,12 +2252,6 @@ iavf_flow_create(struct rte_eth_dev *dev,return flow; } -/* Special case for inline crypto egress flows */ -if (attr->egress && actions[0 ].type ==RTE_FLOW_ACTION_TYPE_SECURITY ) { - flow->is_ipsec_egress_flow = true; - goto tailq_insert; - } - ret =iavf_flow_process_filter (dev, flow, attr, pattern, actions, &engine, iavf_parse_engine_create, error);if (ret <0 ) {
@@ -2266,7 +2262,6 @@ iavf_flow_create(struct rte_eth_dev *dev, } flow->engine = engine; -tailq_insert:rte_spinlock_lock (&vf->flow_ops_lock);TAILQ_INSERT_TAIL (&vf->flow_list, flow, node);rte_spinlock_unlock (&vf->flow_ops_lock);
@@ -2282,14 +2277,7 @@ iavf_flow_is_valid(struct rte_flow *flow)struct iavf_flow_engine *engine;void *temp; -if (flow ==NULL ) -return false; - -/* these flows don't use engines */ -if (flow->is_ipsec_egress_flow) -return true; - -if (flow->engine) { +if (flow !=NULL && flow->engine !=NULL ) { RTE_TAILQ_FOREACH_SAFE(engine, &engine_list, node, temp) {if (engine == flow->engine)return true;
@@ -2307,26 +2295,17 @@ iavf_flow_destroy(struct rte_eth_dev *dev,struct iavf_adapter *ad =IAVF_DEV_PRIVATE_TO_ADAPTER (dev->data->dev_private);struct iavf_info *vf =IAVF_DEV_PRIVATE_TO_VF (ad); -bool need_destroy;int ret =0 ; -if (!iavf_flow_is_valid (flow)) { +if (!iavf_flow_is_valid (flow) || flow->engine->destroy ==NULL ) {rte_flow_error_set (error,EINVAL ,RTE_FLOW_ERROR_TYPE_HANDLE ,NULL ,"Invalid flow destroy" );return -rte_errno; } - need_destroy = !flow->is_ipsec_egress_flow; - -if (need_destroy && flow->engine->destroy ==NULL ) { -return rte_flow_error_set (error,EINVAL , -RTE_FLOW_ERROR_TYPE_HANDLE ,NULL , -"Invalid flow destroy" ); - }rte_spinlock_lock (&vf->flow_ops_lock); -if (need_destroy) - ret = flow->engine->destroy (ad, flow, error); + ret = flow->engine->destroy (ad, flow, error);if (!ret) {TAILQ_REMOVE (&vf->flow_list, flow, node);
@@ -2444,16 +2423,17 @@ iavf_flow_dev_dump(struct rte_eth_dev *dev,if (flow !=NULL && f != flow)continue ; -/* this should not happen */ -if (f->engine ==NULL || f->rule ==NULL ) { +if (!iavf_flow_is_valid (f)) {PMD_DRV_LOG (DEBUG ,"Invalid flow" );continue ; } found = true; - rule_size = f->engine->rule_size; - rule_data = f->rule; +if (f->rule !=NULL ) { + rule_size = f->engine->rule_size; + rule_data = f->rule; + } iavf_flow_dump_blob(file, f->engine->name != NULL ?
drivers/net/intel/iavf/iavf_generic_flow.h +1 -1
@@ -481,6 +481,7 @@ enum iavf_flow_engine_type {IAVF_FLOW_ENGINE_FDIR ,IAVF_FLOW_ENGINE_HASH ,IAVF_FLOW_ENGINE_FSUB , +IAVF_FLOW_ENGINE_IPSEC_EGRESS , IAVF_FLOW_ENGINE_MAX, };
@@ -503,7 +504,6 @@ TAILQ_HEAD(iavf_engine_list, iavf_flow_engine);/* Struct to store flow created. */ struct rte_flow {TAILQ_ENTRY (rte_flow) node; -bool is_ipsec_egress_flow;struct iavf_flow_engine *engine;void *rule; };
drivers/net/intel/iavf/iavf_ipsec_crypto.c +110 -10
145 lines not on this page · raw message
Signature · 1 line
2.52.0
PATCH v2 9/9 net/iavf: fix IPsec flow metadata leaks
In reply to Anatoly BurakovIPsec flow parsing leaves the pattern-match item allocated after extracting its metadata. It also leaves the parsed flow item allocated when no metadata output is requested.
Free the pattern-match item after parsing and free the parsed flow item when it cannot be returned to the caller. Propagate pattern-match failure and report a parsing error when no flow item was produced.
--- drivers/net/intel/iavf/iavf_ipsec_crypto.c | 28 +++++++++++++++------- 1 file changed, 20 insertions(+), 8 deletions(-)
drivers/net/intel/iavf/iavf_ipsec_crypto.c +20 -8
@@ -1942,6 +1942,7 @@ iavf_ipsec_flow_parse(struct iavf_adapter *ad, .max_actions = 1, };struct iavf_pattern_match_item *item =NULL ; +struct iavf_ipsec_flow_item *fi =NULL ;int ret =-1 ; ret =ci_flow_check_attr (attr,NULL , error);
@@ -1953,17 +1954,28 @@ iavf_ipsec_flow_parse(struct iavf_adapter *ad,return ret; item =iavf_search_pattern_match_item (pattern, array, array_len, error); -if (item && item->meta) { +if (item ==NULL ) +return -rte_errno; + +if (item->meta !=NULL ) {const struct rte_security_session *session = parsed_actions.actions[0 ]->conf;uint32_t type = (uint64_t )(item->meta); -struct iavf_ipsec_flow_item *fi = -iavf_ipsec_flow_item_parse (ad, pattern, session, type); -if (fi && meta) { - *meta = fi; - ret =0 ; - } + + fi =iavf_ipsec_flow_item_parse (ad, pattern, session, type); } -return ret; +rte_free (item); + +if (fi ==NULL ) +return rte_flow_error_set (error,EINVAL , +RTE_FLOW_ERROR_TYPE_ACTION ,NULL , +"Invalid IPsec flow." ); + +if (meta !=NULL ) + *meta = fi; +else +rte_free (fi); + +return 0 ; }/*
Signature · 1 line
2.52.0
Re: [PATCH v2 4/9] net/iavf: fix memory leak in raw pattern parsing
In reply to Anatoly BurakovQuoted 1 line · Anatoly Burakov
The API was removed in
92ef4b8f1688("ethdev: remove deprecated shared counter attribute") However, it may not be reasonable to pin a Fixline on that commit because that would imply that it *should have*updated ice driver's plubmbing to not support shared counters any more, which I do not believe is reasonable. I'm leaving this note for posterity and in case it is determined that the Fixline is needed after all.
This was accidentally included. It belongs in a different patch in a different driver, but git notes doesn't handle rebases very well...
Signature · 2 lines
Thanks, Anatoly
v3 cover IAVF Fixes
In reply to Anatoly BurakovAn assortment of IAVF flow-related memory leak fixes and cleanups.
v2 -> v3:
- Rebase on top of latest next-net-intel including Anurag's fix [1]
- Dropped remnants of Anurag's patch [1] as it's now in the tree
- Fixed PF reset path still tearing down RSS when it shouldn't
- Fixed hash engine checking for VF reset when that's no longer necessary
v1 -> v2:
- Integrated Anurag's earlier fix [1] into the patchset
- Reworked generic flow to have centralized memory management
- Reordered some patches
- Integrated the IRQ leaks patchset [2] [3]
- Reworked IPsec fix
[1] https://patches.dpdk.org/project/dpdk/patch/[email protected]/
[2] https://patches.dpdk.org/project/dpdk/patch/809e0c5b2ab57f1b14c68be8ac34e70cbbe82233.1792053236.git.anatoly.burakov@intel.com/
[3] https://patches.dpdk.org/project/dpdk/patch/5488d85c2ded08838becaee6de8328694ee00234.1792053236.git.anatoly.burakov@intel.com/
Anatoly Burakov (10):
net/iavf: keep device stopped if start fails net/iavf: do not store ethdev pointer net/iavf: fix false success on flow validation net/iavf: fix memory leaks around IRQ resources net/iavf: fix generic flow error-path leaks net/iavf: centralize memory management for flows net/iavf: skip RSS teardown during PF-initiated reset net/iavf: remove redundant reset checks from RSS engine net/iavf: fix null engine for egress security flows net/iavf: fix IPsec flow metadata leaks
drivers/net/intel/iavf/iavf.h | 14 +- drivers/net/intel/iavf/iavf_ethdev.c | 50 +++--- drivers/net/intel/iavf/iavf_fdir.c | 68 ++++---- drivers/net/intel/iavf/iavf_fsub.c | 23 +-- drivers/net/intel/iavf/iavf_generic_flow.c | 95 ++++++------ drivers/net/intel/iavf/iavf_generic_flow.h | 4 +- drivers/net/intel/iavf/iavf_hash.c | 103 ++++--------- drivers/net/intel/iavf/iavf_ipsec_crypto.c | 171 +++++++++++++++++---- drivers/net/intel/iavf/iavf_ipsec_crypto.h | 4 +- drivers/net/intel/iavf/iavf_vchnl.c | 7 +- 10 files changed, 303 insertions(+), 236 deletions(-)
Signature · 1 line
2.52.0
PATCH v3 1/10 net/iavf: keep device stopped if start fails
Currently, iavf_dev_start() clears adapter->stopped before several operations that can fail. A subsequent iavf_dev_stop() then disables interrupts and stops and resets queues even though startup did not complete.
Mark the adapter running only after startup succeeds, and return early from stop when it is already stopped.
--- drivers/net/intel/iavf/iavf_ethdev.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-)
drivers/net/intel/iavf/iavf_ethdev.c +4 -5
@@ -1039,8 +1039,6 @@ iavf_dev_start(struct rte_eth_dev *dev)if (adapter->closed)return -1 ; - adapter->stopped =0 ; - vf->max_pkt_len = dev->data->mtu +IAVF_ETH_OVERHEAD ; vf->num_queue_pairs =RTE_MAX (dev->data->nb_rx_queues, dev->data->nb_tx_queues);
@@ -1112,6 +1110,7 @@ iavf_dev_start(struct rte_eth_dev *dev) }iavf_phc_sync_alarm_start (dev); + adapter->stopped =0 ;/* An explicit start supersedes any pending deferred start */ vf->start_pending = false;
@@ -1135,13 +1134,13 @@ iavf_dev_stop(struct rte_eth_dev *dev)if (adapter->closed)return -1 ; +if (adapter->stopped ==1 ) +return 0 ; +if (!(vf->vf_res->vf_cap_flags &VIRTCHNL_VF_OFFLOAD_WB_ON_ITR ) && dev->data->dev_conf.intr_conf.rxq !=0 )rte_intr_disable (intr_handle); -if (adapter->stopped ==1 ) -return 0 ; -iavf_phc_sync_alarm_stop (dev);/* Disable the interrupt for Rx */
Signature · 1 line
2.52.0
PATCH v3 2/10 net/iavf: do not store ethdev pointer
In reply to Anatoly BurakovWe should not be storing rte_eth_dev pointers in shared memory, because rte_eth_dev pointers are process local. To address that, remove the pointer from iavf_info, replace it with rte_eth_devices-based lookup, and rework the call paths to either use that lookup, or not require ethdev pointer in the first place.
--- drivers/net/intel/iavf/iavf.h | 9 ++++++-- drivers/net/intel/iavf/iavf_ethdev.c | 13 ++++++------ drivers/net/intel/iavf/iavf_ipsec_crypto.c | 24 +++++++++++----------- drivers/net/intel/iavf/iavf_ipsec_crypto.h | 4 ++-- drivers/net/intel/iavf/iavf_vchnl.c | 7 ++++--- 5 files changed, 31 insertions(+), 26 deletions(-)
drivers/net/intel/iavf/iavf.h +7 -2
@@ -7,6 +7,7 @@#include <sys/queue.h> +#include <ethdev_driver.h> #include <rte_kvargs.h> #include <rte_tm_driver.h>
@@ -293,8 +294,6 @@ struct iavf_info {struct iavf_qtc_map *qtc_map;struct iavf_tm_conf tm_conf; -struct rte_eth_dev *eth_dev; -RTE_ATOMIC (bool )in_reset_recovery;bool reset_pending;bool pf_reset_in_progress;
@@ -408,6 +407,12 @@ struct iavf_adapter {uint16_t tpid;/* VLAN tag identifier */ }; +static inline struct rte_eth_dev * +iavf_get_eth_dev (struct iavf_adapter *adapter) +{ +return &rte_eth_devices[adapter->dev_data->port_id]; +} +/* IAVF_DEV_PRIVATE_TO */ #define IAVF_DEV_PRIVATE_TO_ADAPTER (adapter) \ ((struct iavf_adapter *)adapter)
drivers/net/intel/iavf/iavf_ethdev.c +6 -7
@@ -326,6 +326,7 @@ static void iavf_dev_watchdog(void *cb_arg) {struct iavf_adapter *adapter = cb_arg; +struct rte_eth_dev *dev =iavf_get_eth_dev (adapter);struct iavf_hw *hw =IAVF_DEV_PRIVATE_TO_HW (adapter);int vfr_inprogress =0 , rc =0 ;
@@ -339,7 +340,7 @@ iavf_dev_watchdog(void *cb_arg)if (!vfr_inprogress) {PMD_DRV_LOG (INFO ,"VF \"%s\" reset has completed" , - adapter->vf.eth_dev->data->name); + dev->data->name); adapter->vf.vf_reset = false;iavf_set_no_poll (adapter, false); }
@@ -350,14 +351,14 @@ iavf_dev_watchdog(void *cb_arg)if (vfr_inprogress) {PMD_DRV_LOG (INFO ,"VF \"%s\" reset event detected by watchdog" , - adapter->vf.eth_dev->data->name); + dev->data->name);/* enter reset state with VFLR event */ adapter->vf.vf_reset = true;iavf_set_no_poll (adapter, false); adapter->vf.link_up = false; -iavf_dev_event_post (adapter->vf.eth_dev,RTE_ETH_EVENT_INTR_RESET , +iavf_dev_event_post (dev,RTE_ETH_EVENT_INTR_RESET ,NULL ,0 ); } }
@@ -365,11 +366,11 @@ iavf_dev_watchdog(void *cb_arg)if (adapter->devargs.watchdog_period) {/* re-alarm watchdog */ rc =rte_eal_alarm_set (adapter->devargs.watchdog_period, - &iavf_dev_watchdog, cb_arg); + &iavf_dev_watchdog, dev);if (rc)PMD_DRV_LOG (ERR ,"Failed \"%s\" to reset device watchdog alarm" , - adapter->vf.eth_dev->data->name); + dev->data->name); } }
@@ -2669,8 +2670,6 @@ iavf_init_vf(struct rte_eth_dev *dev)struct iavf_hw *hw =IAVF_DEV_PRIVATE_TO_HW (dev->data->dev_private);struct iavf_info *vf =IAVF_DEV_PRIVATE_TO_VF (dev->data->dev_private); - vf->eth_dev = dev; - err =iavf_parse_devargs (dev);if (err) {PMD_INIT_LOG (ERR ,"Failed to parse devargs" );
drivers/net/intel/iavf/iavf_ipsec_crypto.c +12 -12
@@ -689,11 +689,9 @@ iavf_ipsec_crypto_session_create(void *device,* returns: 1 if valid */ uint32_t -iavf_ipsec_crypto_action_valid (struct rte_eth_dev *ethdev, +iavf_ipsec_crypto_action_valid (struct iavf_adapter *adapter,const struct rte_security_session *session,uint32_t spi) { -struct iavf_adapter *adapter = -IAVF_DEV_PRIVATE_TO_ADAPTER (ethdev->data->dev_private);const struct iavf_security_session *sess = (const void *)session->driver_priv_data;/* verify we have a valid session and that it belong to this adapter */
@@ -1502,24 +1500,25 @@ static struct rte_security_ops iavf_ipsec_crypto_ops = {int iavf_security_ctx_create (struct iavf_adapter *adapter) { +struct rte_eth_dev *dev =iavf_get_eth_dev (adapter);struct rte_security_ctx *sctx; sctx =rte_malloc ("security_ctx" ,sizeof (struct rte_security_ctx ),0 );if (sctx ==NULL )return -ENOMEM ; - sctx->device = adapter->vf.eth_dev; + sctx->device = dev; sctx->ops = &iavf_ipsec_crypto_ops; sctx->sess_cnt =0 ; - adapter->vf.eth_dev->security_ctx = sctx; + dev->security_ctx = sctx;if (adapter->security_ctx ==NULL ) { adapter->security_ctx =rte_malloc ("iavf_security_ctx" ,sizeof (struct iavf_security_ctx ),0 );if (adapter->security_ctx ==NULL ) { -rte_free (adapter->vf.eth_dev->security_ctx); - adapter->vf.eth_dev->security_ctx =NULL ; +rte_free (dev->security_ctx); + dev->security_ctx =NULL ;return -ENOMEM ; } }
@@ -1565,7 +1564,8 @@ iavf_security_get_pkt_md_offset(struct iavf_adapter *adapter)int iavf_security_ctx_destroy (struct iavf_adapter *adapter) { -struct rte_security_ctx *sctx = adapter->vf.eth_dev->security_ctx; +struct rte_eth_dev *dev =iavf_get_eth_dev (adapter); +struct rte_security_ctx *sctx = dev->security_ctx;struct iavf_security_ctx *iavf_sctx = adapter->security_ctx;if (iavf_sctx ==NULL )
@@ -1578,7 +1578,7 @@ iavf_security_ctx_destroy(struct iavf_adapter *adapter)rte_free (sctx); adapter->security_ctx =NULL ; - adapter->vf.eth_dev->security_ctx =NULL ; + dev->security_ctx =NULL ;return 0 ; }
@@ -1748,7 +1748,7 @@ parse_udp_item(const struct rte_flow_item_udp *item, struct rte_udp_hdr *udp) }static struct iavf_ipsec_flow_item * -iavf_ipsec_flow_item_parse (struct rte_eth_dev *ethdev, +iavf_ipsec_flow_item_parse (struct iavf_adapter *adapter,const struct rte_flow_item pattern[],const struct rte_security_session *session,uint32_t type)
@@ -1819,7 +1819,7 @@ iavf_ipsec_flow_item_parse(struct rte_eth_dev *ethdev, goto flow_cleanup; } -if (!iavf_ipsec_crypto_action_valid (ethdev, session, +if (!iavf_ipsec_crypto_action_valid (adapter, session, ipsec_flow->spi)) goto flow_cleanup;
@@ -1967,7 +1967,7 @@ iavf_ipsec_flow_parse(struct iavf_adapter *ad,const struct rte_security_session *session = parsed_actions.actions[0 ]->conf;uint32_t type = (uint64_t )(item->meta);struct iavf_ipsec_flow_item *fi = -iavf_ipsec_flow_item_parse (ad->vf.eth_dev, pattern, session, type); +iavf_ipsec_flow_item_parse (ad, pattern, session, type);if (fi && meta) { *meta = fi; ret =0 ;
drivers/net/intel/iavf/iavf_ipsec_crypto.h +2 -2
@@ -127,13 +127,13 @@ int iavf_security_get_pkt_md_offset(struct iavf_adapter *adapter);/** * Destroy security context */ -int iavf_security_ctx_destroy (struct iavf_adapter *adapterv); +int iavf_security_ctx_destroy (struct iavf_adapter *adapter);/** * Verify that the inline IPsec Crypto action is valid for this device */ uint32_t -iavf_ipsec_crypto_action_valid (struct rte_eth_dev *ethdev, +iavf_ipsec_crypto_action_valid (struct iavf_adapter *adapter,const struct rte_security_session *session,uint32_t spi);/**
drivers/net/intel/iavf/iavf_vchnl.c +4 -3
@@ -314,13 +314,14 @@ iavf_read_msg_from_pf(struct iavf_adapter *adapter, uint16_t buf_len, opcode, vf->cmd_retval);if (opcode ==VIRTCHNL_OP_EVENT ) { +struct rte_eth_dev *dev =iavf_get_eth_dev (adapter);struct virtchnl_pf_event *vpe = (struct virtchnl_pf_event *)event.msg_buf; result =IAVF_MSG_SYS ;switch (vpe->event) {case VIRTCHNL_EVENT_LINK_CHANGE : -iavf_handle_link_change_event (vf->eth_dev, vpe); +iavf_handle_link_change_event (dev, vpe);break ;case VIRTCHNL_EVENT_RESET_IMPENDING :/*
@@ -335,8 +336,8 @@ iavf_read_msg_from_pf(struct iavf_adapter *adapter, uint16_t buf_len,iavf_set_no_poll (adapter, false);iavf_dev_watchdog_enable (adapter);if (adapter->devargs.no_poll_on_link_down) -iavf_dev_tx_drain (vf->eth_dev); -iavf_dev_event_post (vf->eth_dev, +iavf_dev_tx_drain (dev); +iavf_dev_event_post (dev,RTE_ETH_EVENT_INTR_RESET ,NULL ,0 ); }
Signature · 1 line
2.52.0
PATCH v3 3/10 net/iavf: fix false success on flow validation
In reply to Anatoly Burakoviavf_parse_engine_validate() sets an error when validation fails, but then returns the engine pointer. iavf_flow_process_filter() treats a non-NULL engine as success, so rte_flow_validate() can accept an invalid flow.
Return NULL on validation failure and return the engine only after validation succeeds.
--- drivers/net/intel/iavf/iavf_generic_flow.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
drivers/net/intel/iavf/iavf_generic_flow.c +3 -2
@@ -2134,10 +2134,11 @@ iavf_parse_engine_validate(struct iavf_adapter *ad,rte_flow_error_set (error,EINVAL ,RTE_FLOW_ERROR_TYPE_HANDLE ,NULL ,"Validation failed" ); -break ; +return NULL ; } +return engine; } -return engine; +return NULL ; }
Signature · 1 line
2.52.0
PATCH v3 4/10 net/iavf: fix memory leaks around IRQ resources
In reply to Anatoly Burakoviavf_config_rx_queues_irqs() allocates a queue-vector map and may enable eventfds and allocate an interrupt vector list. If queue startup then fails, those resources remain allocated. The queue-vector map is also retained after a normal stop, leaking it across start/stop cycles.
Release the resources on failed startup and free the queue-vector map on stop. Clean up eventfds when interrupt setup fails as well.
--- drivers/net/intel/iavf/iavf_ethdev.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-)
drivers/net/intel/iavf/iavf_ethdev.c +18 -4
@@ -863,7 +863,7 @@ static int iavf_config_rx_queues_irqs(struct rte_eth_dev *dev,if (rte_intr_cap_multiple (intr_handle) && dev->data->dev_conf.intr_conf.rxq) {if (rte_intr_efd_enable (intr_handle, dev->data->nb_rx_queues)) -return -1 ; + goto efd_alloc_err; }if (rte_intr_dp_is_en (intr_handle)) {
@@ -871,7 +871,7 @@ static int iavf_config_rx_queues_irqs(struct rte_eth_dev *dev, dev->data->nb_rx_queues)) {PMD_DRV_LOG (ERR ,"Failed to allocate %d rx intr_vec" , dev->data->nb_rx_queues); -return -1 ; + goto qv_map_alloc_err; } }
@@ -981,6 +981,8 @@ static int iavf_config_rx_queues_irqs(struct rte_eth_dev *dev, qv_map_alloc_err:rte_intr_vec_list_free (intr_handle); +efd_alloc_err: +rte_intr_efd_disable (intr_handle);return -1 ; }
@@ -1034,12 +1036,15 @@ iavf_dev_start(struct rte_eth_dev *dev)struct rte_intr_handle *intr_handle = dev->intr_handle;uint16_t num_queue_pairs;uint16_t index =0 ; +bool wb_on_itr;PMD_INIT_FUNC_TRACE ();if (adapter->closed)return -1 ; + wb_on_itr = (vf->vf_res->vf_cap_flags &VIRTCHNL_VF_OFFLOAD_WB_ON_ITR ) !=0 ; + vf->max_pkt_len = dev->data->mtu +IAVF_ETH_OVERHEAD ; vf->num_queue_pairs =RTE_MAX (dev->data->nb_rx_queues, dev->data->nb_tx_queues);
@@ -1089,7 +1094,7 @@ iavf_dev_start(struct rte_eth_dev *dev) }/* re-enable intr again, because efd assign may change */ if (dev->data->dev_conf.intr_conf.rxq !=0 ) { -if (vf->vf_res->vf_cap_flags &VIRTCHNL_VF_OFFLOAD_WB_ON_ITR ) +if (wb_on_itr)rte_intr_disable (intr_handle);rte_intr_enable (intr_handle); }
@@ -1107,7 +1112,7 @@ iavf_dev_start(struct rte_eth_dev *dev)if (iavf_start_queues (dev) !=0 ) {PMD_DRV_LOG (ERR ,"enable queues failed" ); - goto error; + goto irq_error; }iavf_phc_sync_alarm_start (dev);
@@ -1118,6 +1123,13 @@ iavf_dev_start(struct rte_eth_dev *dev)return 0 ; +irq_error: +if (!wb_on_itr && dev->data->dev_conf.intr_conf.rxq !=0 ) +rte_intr_disable (intr_handle); +rte_intr_efd_disable (intr_handle); +rte_intr_vec_list_free (intr_handle); +rte_free (vf->qv_map); + vf->qv_map =NULL ; error:return -1 ; }
@@ -1150,6 +1162,8 @@ iavf_dev_stop(struct rte_eth_dev *dev)rte_intr_vec_list_free (intr_handle);iavf_stop_queues (dev); +rte_free (vf->qv_map); + vf->qv_map =NULL ; adapter->stopped =1 ; dev->data->dev_started =0 ;
Signature · 1 line
2.52.0
PATCH v3 5/10 net/iavf: fix generic flow error-path leaks
In reply to Anatoly BurakovIf a flow engine fails to initialize, parsers registered by earlier engines remain allocated. Pattern matching also leaks its item array when allocation of the match result fails.
Unwind registered parsers on flow initialization failure and free the item array on match-result allocation failure.
--- drivers/net/intel/iavf/iavf_generic_flow.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)
drivers/net/intel/iavf/iavf_generic_flow.c +8 -2
@@ -1821,17 +1821,22 @@ iavf_flow_init(struct iavf_adapter *ad)if (engine->init ==NULL ) {PMD_INIT_LOG (ERR ,"Invalid engine type (%d)" , engine->type); -return -ENOTSUP ; + ret = -ENOTSUP ; + goto err; } ret = engine->init (ad);if (ret && ret != -ENOTSUP ) {PMD_INIT_LOG (ERR ,"Failed to initialize engine %d" , engine->type); -return ret; + goto err; } }return 0 ; + +err: +iavf_flow_uninit (ad); +return ret; }void
@@ -2047,6 +2052,7 @@ iavf_search_pattern_match_item(const struct rte_flow_item pattern[],if (!pattern_match_item) {rte_flow_error_set (error,ENOMEM ,RTE_FLOW_ERROR_TYPE_HANDLE ,NULL ,"Failed to allocate memory." ); +rte_free (items);return NULL ; }
Signature · 1 line
2.52.0
PATCH v3 6/10 net/iavf: centralize memory management for flows
In reply to Anatoly BurakovFlow engines currently distribute rule allocation and cleanup between the parser, engine create and destroy callbacks, and generic flow code. This leads to a lot of potential for memory leaks and bugs. In particular, one of the issues currently present is that when PF initiates reset, we are meant to just drop all flows without sending any virtchnl commands, but because not all engines implement the free callback, some flows will be leaked.
To address that specific leak as well as all other potential leaks due to misuse of memory by engines, use parser-allocated rule objects as the persistent rules and centralize their lifetime in the generic flow layer. This requires fixing all engines to not manage their own memory:
- Allocate the final FDIR rule in the parser, use it for action checks, and remove the per-VF scratch configuration.
- Have FSUB create adopt its parser-produced rule instead of allocating and copying a second object.
- Build the final RSS configuration in the parser and remove the intermediate RSS metadata, including its unused raw-pattern flag.
- Let generic flow code free rules on validate, create failure, successful destroy, and uninit; remove engine-specific free callbacks and rule frees from destroy callbacks.
--- drivers/net/intel/iavf/iavf.h | 5 -- drivers/net/intel/iavf/iavf_fdir.c | 68 +++++++-------- drivers/net/intel/iavf/iavf_fsub.c | 23 +---- drivers/net/intel/iavf/iavf_generic_flow.c | 36 ++++++-- drivers/net/intel/iavf/iavf_generic_flow.h | 2 - drivers/net/intel/iavf/iavf_hash.c | 99 +++++++--------------- drivers/net/intel/iavf/iavf_ipsec_crypto.c | 1 - 7 files changed, 97 insertions(+), 137 deletions(-)
drivers/net/intel/iavf/iavf.h +0 -5
@@ -155,10 +155,6 @@ struct iavf_fdir_conf {uint32_t mark_flag; }; -struct iavf_fdir_info { -struct iavf_fdir_conf conf; -}; -struct iavf_fsub_conf {struct virtchnl_flow_sub sub_fltr;struct virtchnl_flow_unsub unsub_fltr;
@@ -286,7 +282,6 @@ struct iavf_info {struct iavf_parser_list dist_parser_list;struct iavf_parser_list ipsec_crypto_parser_list; -struct iavf_fdir_info fdir;/* flow director info */ /* indicate large VF support enabled or not */ bool lv_enabled;
drivers/net/intel/iavf/iavf_fdir.c +35 -33
138 lines not on this page · raw message
drivers/net/intel/iavf/iavf_fsub.c +2 -21
@@ -73,34 +73,18 @@ iavf_fsub_create(struct iavf_adapter *ad, struct rte_flow *flow, void *meta, struct rte_flow_error *error) { struct iavf_fsub_conf *filter = meta; -struct iavf_fsub_conf *rule;int ret; - rule =rte_zmalloc ("fsub_entry" ,sizeof (*rule),0 ); -if (!rule) { -rte_flow_error_set (error,ENOMEM , -RTE_FLOW_ERROR_TYPE_HANDLE ,NULL , -"Failed to allocate memory for fsub rule" ); -return -rte_errno; - } - ret =iavf_flow_sub (ad, filter);if (ret) {rte_flow_error_set (error, -ret,RTE_FLOW_ERROR_TYPE_HANDLE ,NULL ,"Failed to subscribe flow rule." ); - goto free_entry; +return -rte_errno; } -memcpy (rule, filter,sizeof (*rule)); - flow->rule = rule; - -rte_free (meta); + flow->rule = filter;return ret; - -free_entry: -rte_free (rule); -return -rte_errno; } static int
@@ -120,9 +104,6 @@ iavf_fsub_destroy(struct iavf_adapter *ad, struct rte_flow *flow,return -rte_errno; } - flow->rule =NULL ; -rte_free (filter); -return ret; }
drivers/net/intel/iavf/iavf_generic_flow.c +29 -7
@@ -46,6 +46,13 @@ static int iavf_flow_dev_dump(struct rte_eth_dev *dev,FILE *file, struct rte_flow_error *error); +static void +iavf_flow_free (struct rte_flow *flow) +{ +rte_free (flow->rule); +rte_free (flow); +} +const struct rte_flow_ops iavf_flow_ops = { .validate = iavf_flow_validate, .create = iavf_flow_create,
@@ -1856,9 +1863,7 @@ iavf_flow_uninit(struct iavf_adapter *ad)/* Remove all flows */ while ((p_flow =TAILQ_FIRST (&vf->flow_list))) {TAILQ_REMOVE (&vf->flow_list, p_flow, node); -if (p_flow->engine->free) - p_flow->engine->free (p_flow); -rte_free (p_flow); +iavf_flow_free (p_flow); }/* Cleanup parser list */
@@ -2092,6 +2097,7 @@ iavf_parse_engine_create(struct iavf_adapter *ad,void *meta =NULL ; RTE_TAILQ_FOREACH_SAFE(parser_node, parser_list, node, temp) { + meta =NULL ; if (parser_node->parser->parse_pattern_action(ad, parser_node->parser->array, parser_node->parser->array_len,
@@ -2101,8 +2107,17 @@ iavf_parse_engine_create(struct iavf_adapter *ad, engine = parser_node->parser->engine;RTE_ASSERT (engine->create !=NULL ); -if (!(engine->create (ad, flow, meta, error))) +if (engine->create (ad, flow, meta, error) ==0 ) { +if (flow->rule != meta) +rte_free (meta);return engine; + } + +if (flow->rule !=NULL && flow->rule != meta) +rte_free (flow->rule); +rte_free (meta); + flow->rule =NULL ; + meta =NULL ; }return NULL ; }
@@ -2120,8 +2135,10 @@ iavf_parse_engine_validate(struct iavf_adapter *ad,struct iavf_flow_parser_node *parser_node;void *temp;void *meta =NULL ; +int ret; RTE_TAILQ_FOREACH_SAFE(parser_node, parser_list, node, temp) { + meta =NULL ; if (parser_node->parser->parse_pattern_action(ad, parser_node->parser->array, parser_node->parser->array_len,
@@ -2130,13 +2147,18 @@ iavf_parse_engine_validate(struct iavf_adapter *ad, engine = parser_node->parser->engine;if (engine->validation ==NULL ) { +rte_free (meta); + meta =NULL ;rte_flow_error_set (error,EINVAL ,RTE_FLOW_ERROR_TYPE_HANDLE ,NULL ,"Validation not support" );continue ; } -if (engine->validation (ad, flow, meta, error)) { + ret = engine->validation (ad, flow, meta, error); +rte_free (meta); + meta =NULL ; +if (ret !=0 ) {rte_flow_error_set (error,EINVAL ,RTE_FLOW_ERROR_TYPE_HANDLE ,NULL ,"Validation failed" );
@@ -2238,7 +2260,7 @@ iavf_flow_create(struct rte_eth_dev *dev, &engine, iavf_parse_engine_create, error);if (ret <0 ) {PMD_DRV_LOG (ERR ,"Failed to create flow" ); -rte_free (flow); +iavf_flow_free (flow); flow =NULL ; goto free_flow; }
@@ -2308,7 +2330,7 @@ iavf_flow_destroy(struct rte_eth_dev *dev,if (!ret) {TAILQ_REMOVE (&vf->flow_list, flow, node); -rte_free (flow); +iavf_flow_free (flow); }else {PMD_DRV_LOG (ERR ,"Failed to destroy flow" ); }
drivers/net/intel/iavf/iavf_generic_flow.h +0 -2
@@ -465,7 +465,6 @@ typedef int (*engine_query_t)(struct iavf_adapter *ad,struct rte_flow *flow, struct rte_flow_query_count *count, struct rte_flow_error *error); -typedef void (*engine_free_t ) (struct rte_flow *flow); typedef int (*parse_pattern_action_t)(struct iavf_adapter *ad, struct iavf_pattern_match_item *array, uint32_t array_len,
@@ -494,7 +493,6 @@ struct iavf_flow_engine {engine_create_t create;engine_destroy_t destroy;engine_query_t query_count; -engine_free_t free;const char *name;enum iavf_flow_engine_type type;size_t rule_size;
drivers/net/intel/iavf/iavf_hash.c +31 -68
206 lines not on this page · raw message
drivers/net/intel/iavf/iavf_ipsec_crypto.c +0 -1
@@ -1919,7 +1919,6 @@ iavf_ipsec_flow_destroy(struct iavf_adapter *ad,iavf_ipsec_crypto_security_policy_delete (ad, ipsec_flow->is_ipv4, ipsec_flow->id); -rte_free (ipsec_flow);return 0 ; }
Signature · 1 line
2.52.0
PATCH v3 7/10 net/iavf: skip RSS teardown during PF-initiated reset
In reply to Anatoly BurakovDuring PF-initiated reset recovery, iavf_dev_close() skips flow flush to avoid sending virtchnl messages to the PF. However, iavf_hash_uninit() is still called unconditionally, even though any existing RSS configuration is now invalid because of PF-initiated reset.
Move the RSS teardown under the same pf_reset_in_progress check as flow flush, so that no RSS configuration messages are sent during PF-initiated reset recovery.
--- drivers/net/intel/iavf/iavf_ethdev.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
drivers/net/intel/iavf/iavf_ethdev.c +4 -4
@@ -3254,12 +3254,12 @@ iavf_dev_close(struct rte_eth_dev *dev)/* free iAVF security device context all related resources */ iavf_security_ctx_destroy (adapter); -/* remove RSS configuration */ -iavf_hash_uninit (adapter); -/* Skip the virtchnl-emitting teardown on a PF-initiated reset */ -if (!vf->pf_reset_in_progress) +if (!vf->pf_reset_in_progress) { +/* remove RSS configuration */ +iavf_hash_uninit (adapter);iavf_flow_flush (dev,NULL ); + }iavf_flow_uninit (adapter);/*
Signature · 1 line
2.52.0
PATCH v3 8/10 net/iavf: remove redundant reset checks from RSS engine
In reply to Anatoly BurakovThe RSS engine checks vf_reset during init, destroy and uninit to avoid sending virtchnl commands while the VF is resetting. These checks are no longer needed:
- iavf_hash_init() only registers the parser and sends no commands.
- iavf_dev_close() skips both flow flush and RSS teardown during PF-initiated reset recovery.
- the generic flow layer frees rule memory without relying on engine callbacks.
- iavf_execute_vf_cmd() already refuses to send commands while vf_reset is set.
Remove these checks as they are no longer needed.
--- drivers/net/intel/iavf/iavf_hash.c | 10 ---------- 1 file changed, 10 deletions(-)
drivers/net/intel/iavf/iavf_hash.c +0 -10
@@ -762,9 +762,6 @@ iavf_hash_init(struct iavf_adapter *ad)struct iavf_flow_parser *parser;int ret; -if (vf->vf_reset) -return -EIO ; -if (!vf->vf_res)return -EINVAL ;
@@ -1601,13 +1598,9 @@ iavf_hash_destroy(__rte_unused struct iavf_adapter *ad,struct rte_flow *flow, __rte_unused struct rte_flow_error *error) { - struct iavf_info *vf = IAVF_DEV_PRIVATE_TO_VF(ad); struct virtchnl_rss_cfg *rss_cfg;int ret =0 ; -if (vf->vf_reset) -return 0 ; - rss_cfg = (struct virtchnl_rss_cfg *)flow->rule; ret =iavf_add_del_rss_cfg (ad, rss_cfg, false);
@@ -1633,9 +1626,6 @@ iavf_hash_uninit(struct iavf_adapter *ad)struct iavf_info *vf =IAVF_DEV_PRIVATE_TO_VF (ad);struct rte_eth_rss_conf *rss_conf; -if (vf->vf_reset) -return ; -if (!vf->vf_res)return ;
Signature · 1 line
2.52.0
PATCH v3 9/10 net/iavf: fix null engine for egress security flows
In reply to Anatoly BurakovEgress security flows bypass the flow parsers and are inserted with a NULL engine pointer. The create path then dereferences that pointer when logging the new flow, and other engine-based operations cannot handle the flow consistently.
Register an egress security engine and route these flows through the normal parser and lifecycle callbacks. Egress flows own no rule and require no hardware teardown.
--- drivers/net/intel/iavf/iavf_generic_flow.c | 44 +++----- drivers/net/intel/iavf/iavf_generic_flow.h | 2 +- drivers/net/intel/iavf/iavf_ipsec_crypto.c | 120 +++++++++++++++++++-- 3 files changed, 123 insertions(+), 43 deletions(-)
drivers/net/intel/iavf/iavf_generic_flow.c +12 -32
@@ -1914,7 +1914,8 @@ iavf_register_parser(struct iavf_flow_parser *parser, } }TAILQ_INSERT_HEAD (list, parser_node, node); - }else if (parser->engine->type ==IAVF_FLOW_ENGINE_IPSEC_CRYPTO ) { + }else if (parser->engine->type ==IAVF_FLOW_ENGINE_IPSEC_CRYPTO || + parser->engine->type ==IAVF_FLOW_ENGINE_IPSEC_EGRESS ) { list = &vf->ipsec_crypto_parser_list;TAILQ_INSERT_HEAD (list, parser_node, node); }else if (parser->engine->type ==IAVF_FLOW_ENGINE_FSUB ) {
@@ -1943,7 +1944,8 @@ iavf_unregister_parser(struct iavf_flow_parser *parser,else if ((parser->engine->type ==IAVF_FLOW_ENGINE_FDIR ) || (parser->engine->type ==IAVF_FLOW_ENGINE_FSUB )) list = &vf->dist_parser_list; -else if (parser->engine->type ==IAVF_FLOW_ENGINE_IPSEC_CRYPTO ) +else if (parser->engine->type ==IAVF_FLOW_ENGINE_IPSEC_CRYPTO || + parser->engine->type ==IAVF_FLOW_ENGINE_IPSEC_EGRESS ) list = &vf->ipsec_crypto_parser_list;if (list ==NULL )
@@ -2250,12 +2252,6 @@ iavf_flow_create(struct rte_eth_dev *dev,return flow; } -/* Special case for inline crypto egress flows */ -if (attr->egress && actions[0 ].type ==RTE_FLOW_ACTION_TYPE_SECURITY ) { - flow->is_ipsec_egress_flow = true; - goto tailq_insert; - } - ret =iavf_flow_process_filter (dev, flow, attr, pattern, actions, &engine, iavf_parse_engine_create, error);if (ret <0 ) {
@@ -2266,7 +2262,6 @@ iavf_flow_create(struct rte_eth_dev *dev, } flow->engine = engine; -tailq_insert:rte_spinlock_lock (&vf->flow_ops_lock);TAILQ_INSERT_TAIL (&vf->flow_list, flow, node);rte_spinlock_unlock (&vf->flow_ops_lock);
@@ -2282,14 +2277,7 @@ iavf_flow_is_valid(struct rte_flow *flow)struct iavf_flow_engine *engine;void *temp; -if (flow ==NULL ) -return false; - -/* these flows don't use engines */ -if (flow->is_ipsec_egress_flow) -return true; - -if (flow->engine) { +if (flow !=NULL && flow->engine !=NULL ) { RTE_TAILQ_FOREACH_SAFE(engine, &engine_list, node, temp) {if (engine == flow->engine)return true;
@@ -2307,26 +2295,17 @@ iavf_flow_destroy(struct rte_eth_dev *dev,struct iavf_adapter *ad =IAVF_DEV_PRIVATE_TO_ADAPTER (dev->data->dev_private);struct iavf_info *vf =IAVF_DEV_PRIVATE_TO_VF (ad); -bool need_destroy;int ret =0 ; -if (!iavf_flow_is_valid (flow)) { +if (!iavf_flow_is_valid (flow) || flow->engine->destroy ==NULL ) {rte_flow_error_set (error,EINVAL ,RTE_FLOW_ERROR_TYPE_HANDLE ,NULL ,"Invalid flow destroy" );return -rte_errno; } - need_destroy = !flow->is_ipsec_egress_flow; - -if (need_destroy && flow->engine->destroy ==NULL ) { -return rte_flow_error_set (error,EINVAL , -RTE_FLOW_ERROR_TYPE_HANDLE ,NULL , -"Invalid flow destroy" ); - }rte_spinlock_lock (&vf->flow_ops_lock); -if (need_destroy) - ret = flow->engine->destroy (ad, flow, error); + ret = flow->engine->destroy (ad, flow, error);if (!ret) {TAILQ_REMOVE (&vf->flow_list, flow, node);
@@ -2444,16 +2423,17 @@ iavf_flow_dev_dump(struct rte_eth_dev *dev,if (flow !=NULL && f != flow)continue ; -/* this should not happen */ -if (f->engine ==NULL || f->rule ==NULL ) { +if (!iavf_flow_is_valid (f)) {PMD_DRV_LOG (DEBUG ,"Invalid flow" );continue ; } found = true; - rule_size = f->engine->rule_size; - rule_data = f->rule; +if (f->rule !=NULL ) { + rule_size = f->engine->rule_size; + rule_data = f->rule; + } iavf_flow_dump_blob(file, f->engine->name != NULL ?
drivers/net/intel/iavf/iavf_generic_flow.h +1 -1
@@ -481,6 +481,7 @@ enum iavf_flow_engine_type {IAVF_FLOW_ENGINE_FDIR ,IAVF_FLOW_ENGINE_HASH ,IAVF_FLOW_ENGINE_FSUB , +IAVF_FLOW_ENGINE_IPSEC_EGRESS , IAVF_FLOW_ENGINE_MAX, };
@@ -503,7 +504,6 @@ TAILQ_HEAD(iavf_engine_list, iavf_flow_engine);/* Struct to store flow created. */ struct rte_flow {TAILQ_ENTRY (rte_flow) node; -bool is_ipsec_egress_flow;struct iavf_flow_engine *engine;void *rule; };
drivers/net/intel/iavf/iavf_ipsec_crypto.c +110 -10
145 lines not on this page · raw message
Signature · 1 line
2.52.0
PATCH v3 10/10 net/iavf: fix IPsec flow metadata leaks
In reply to Anatoly BurakovIPsec flow parsing leaves the pattern-match item allocated after extracting its metadata. It also leaves the parsed flow item allocated when no metadata output is requested.
Free the pattern-match item after parsing and free the parsed flow item when it cannot be returned to the caller. Propagate pattern-match failure and report a parsing error when no flow item was produced.
--- drivers/net/intel/iavf/iavf_ipsec_crypto.c | 28 +++++++++++++++------- 1 file changed, 20 insertions(+), 8 deletions(-)
drivers/net/intel/iavf/iavf_ipsec_crypto.c +20 -8
@@ -1942,6 +1942,7 @@ iavf_ipsec_flow_parse(struct iavf_adapter *ad, .max_actions = 1, };struct iavf_pattern_match_item *item =NULL ; +struct iavf_ipsec_flow_item *fi =NULL ;int ret =-1 ; ret =ci_flow_check_attr (attr,NULL , error);
@@ -1953,17 +1954,28 @@ iavf_ipsec_flow_parse(struct iavf_adapter *ad,return ret; item =iavf_search_pattern_match_item (pattern, array, array_len, error); -if (item && item->meta) { +if (item ==NULL ) +return -rte_errno; + +if (item->meta !=NULL ) {const struct rte_security_session *session = parsed_actions.actions[0 ]->conf;uint32_t type = (uint64_t )(item->meta); -struct iavf_ipsec_flow_item *fi = -iavf_ipsec_flow_item_parse (ad, pattern, session, type); -if (fi && meta) { - *meta = fi; - ret =0 ; - } + + fi =iavf_ipsec_flow_item_parse (ad, pattern, session, type); } -return ret; +rte_free (item); + +if (fi ==NULL ) +return rte_flow_error_set (error,EINVAL , +RTE_FLOW_ERROR_TYPE_ACTION ,NULL , +"Invalid IPsec flow." ); + +if (meta !=NULL ) + *meta = fi; +else +rte_free (fi); + +return 0 ; }/*
Signature · 1 line
2.52.0
Re: [PATCH v3 10/10] net/iavf: fix IPsec flow metadata leaks
Quoted 8 lines · Anatoly Burakov
IPsec flow parsing leaves the pattern-match item allocated after extracting its metadata. It also leaves the parsed flow item allocated when no metadata output is requested.
Free the pattern-match item after parsing and free the parsed flow item when it cannot be returned to the caller. Propagate pattern-match failure and report a parsing error when no flow item was produced.
Quoted 5 lines
Fixes 6bc987ecb860 ("net/iavf: support IPsec inline crypto")Signed-off-by Anatoly Burakov<[email protected]>---
Re: [PATCH v3 09/10] net/iavf: fix null engine for egress security flows
In reply to Anatoly BurakovQuoted 9 lines · Anatoly Burakov
Egress security flows bypass the flow parsers and are inserted with a NULL
enginepointer. The create path then dereferences that pointer when logging the new flow, and other engine-based operations cannot handle the flow consistently.Register an egress security engine and route these flows through the normal parser and lifecycle callbacks. Egress flows own no rule and require no hardware teardown.
Quoted 5 lines
Fixes e783da175250 ("net/iavf: fix memory leak on egress IPsec flows")Signed-off-by Anatoly Burakov<[email protected]>---
v4 cover IAVF Fixes
In reply to Anatoly BurakovAn assortment of IAVF flow-related memory leak fixes and cleanups.
v3 -> v4:
- Fixed watchdog crash in commit 2
v2 -> v3:
- Rebase on top of latest next-net-intel including Anurag's fix [1]
- Dropped remnants of Anurag's patch [1] as it's now in the tree
- Fixed PF reset path still tearing down RSS when it shouldn't
- Fixed hash engine checking for VF reset when that's no longer necessary
v1 -> v2:
- Integrated Anurag's earlier fix [1] into the patchset
- Reworked generic flow to have centralized memory management
- Reordered some patches
- Integrated the IRQ leaks patchset [2] [3]
- Reworked IPsec fix
[1] https://patches.dpdk.org/project/dpdk/patch/[email protected]/
[2] https://patches.dpdk.org/project/dpdk/patch/809e0c5b2ab57f1b14c68be8ac34e70cbbe82233.1792053236.git.anatoly.burakov@intel.com/
[3] https://patches.dpdk.org/project/dpdk/patch/5488d85c2ded08838becaee6de8328694ee00234.1792053236.git.anatoly.burakov@intel.com/
Anatoly Burakov (10):
net/iavf: keep device stopped if start fails net/iavf: do not store ethdev pointer net/iavf: fix false success on flow validation net/iavf: fix memory leaks around IRQ resources net/iavf: fix generic flow error-path leaks net/iavf: centralize memory management for flows net/iavf: skip RSS teardown during PF-initiated reset net/iavf: remove redundant reset checks from RSS engine net/iavf: fix null engine for egress security flows net/iavf: fix IPsec flow metadata leaks
drivers/net/intel/iavf/iavf.h | 14 +- drivers/net/intel/iavf/iavf_ethdev.c | 48 +++--- drivers/net/intel/iavf/iavf_fdir.c | 68 ++++---- drivers/net/intel/iavf/iavf_fsub.c | 23 +-- drivers/net/intel/iavf/iavf_generic_flow.c | 95 ++++++------ drivers/net/intel/iavf/iavf_generic_flow.h | 4 +- drivers/net/intel/iavf/iavf_hash.c | 103 ++++--------- drivers/net/intel/iavf/iavf_ipsec_crypto.c | 171 +++++++++++++++++---- drivers/net/intel/iavf/iavf_ipsec_crypto.h | 4 +- drivers/net/intel/iavf/iavf_vchnl.c | 7 +- 10 files changed, 302 insertions(+), 235 deletions(-)
Signature · 1 line
2.52.0
PATCH v4 1/10 net/iavf: keep device stopped if start fails
Currently, iavf_dev_start() clears adapter->stopped before several operations that can fail. A subsequent iavf_dev_stop() then disables interrupts and stops and resets queues even though startup did not complete.
Mark the adapter running only after startup succeeds, and return early from stop when it is already stopped.
--- drivers/net/intel/iavf/iavf_ethdev.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-)
drivers/net/intel/iavf/iavf_ethdev.c +4 -5
@@ -1039,8 +1039,6 @@ iavf_dev_start(struct rte_eth_dev *dev)if (adapter->closed)return -1 ; - adapter->stopped =0 ; - vf->max_pkt_len = dev->data->mtu +IAVF_ETH_OVERHEAD ; vf->num_queue_pairs =RTE_MAX (dev->data->nb_rx_queues, dev->data->nb_tx_queues);
@@ -1112,6 +1110,7 @@ iavf_dev_start(struct rte_eth_dev *dev) }iavf_phc_sync_alarm_start (dev); + adapter->stopped =0 ;/* An explicit start supersedes any pending deferred start */ vf->start_pending = false;
@@ -1135,13 +1134,13 @@ iavf_dev_stop(struct rte_eth_dev *dev)if (adapter->closed)return -1 ; +if (adapter->stopped ==1 ) +return 0 ; +if (!(vf->vf_res->vf_cap_flags &VIRTCHNL_VF_OFFLOAD_WB_ON_ITR ) && dev->data->dev_conf.intr_conf.rxq !=0 )rte_intr_disable (intr_handle); -if (adapter->stopped ==1 ) -return 0 ; -iavf_phc_sync_alarm_stop (dev);/* Disable the interrupt for Rx */
Signature · 1 line
2.52.0
PATCH v4 2/10 net/iavf: do not store ethdev pointer
In reply to Anatoly BurakovWe should not be storing rte_eth_dev pointers in shared memory, because rte_eth_dev pointers are process local. To address that, remove the pointer from iavf_info, replace it with rte_eth_devices-based lookup, and rework the call paths to either use that lookup, or not require ethdev pointer in the first place.
--- drivers/net/intel/iavf/iavf.h | 9 ++++++-- drivers/net/intel/iavf/iavf_ethdev.c | 11 +++++----- drivers/net/intel/iavf/iavf_ipsec_crypto.c | 24 +++++++++++----------- drivers/net/intel/iavf/iavf_ipsec_crypto.h | 4 ++-- drivers/net/intel/iavf/iavf_vchnl.c | 7 ++++--- 5 files changed, 30 insertions(+), 25 deletions(-)
drivers/net/intel/iavf/iavf.h +7 -2
@@ -7,6 +7,7 @@#include <sys/queue.h> +#include <ethdev_driver.h> #include <rte_kvargs.h> #include <rte_tm_driver.h>
@@ -293,8 +294,6 @@ struct iavf_info {struct iavf_qtc_map *qtc_map;struct iavf_tm_conf tm_conf; -struct rte_eth_dev *eth_dev; -RTE_ATOMIC (bool )in_reset_recovery;bool reset_pending;bool pf_reset_in_progress;
@@ -408,6 +407,12 @@ struct iavf_adapter {uint16_t tpid;/* VLAN tag identifier */ }; +static inline struct rte_eth_dev * +iavf_get_eth_dev (struct iavf_adapter *adapter) +{ +return &rte_eth_devices[adapter->dev_data->port_id]; +} +/* IAVF_DEV_PRIVATE_TO */ #define IAVF_DEV_PRIVATE_TO_ADAPTER (adapter) \ ((struct iavf_adapter *)adapter)
drivers/net/intel/iavf/iavf_ethdev.c +5 -6
@@ -326,6 +326,7 @@ static void iavf_dev_watchdog(void *cb_arg) {struct iavf_adapter *adapter = cb_arg; +struct rte_eth_dev *dev =iavf_get_eth_dev (adapter);struct iavf_hw *hw =IAVF_DEV_PRIVATE_TO_HW (adapter);int vfr_inprogress =0 , rc =0 ;
@@ -339,7 +340,7 @@ iavf_dev_watchdog(void *cb_arg)if (!vfr_inprogress) {PMD_DRV_LOG (INFO ,"VF \"%s\" reset has completed" , - adapter->vf.eth_dev->data->name); + dev->data->name); adapter->vf.vf_reset = false;iavf_set_no_poll (adapter, false); }
@@ -350,14 +351,14 @@ iavf_dev_watchdog(void *cb_arg)if (vfr_inprogress) {PMD_DRV_LOG (INFO ,"VF \"%s\" reset event detected by watchdog" , - adapter->vf.eth_dev->data->name); + dev->data->name);/* enter reset state with VFLR event */ adapter->vf.vf_reset = true;iavf_set_no_poll (adapter, false); adapter->vf.link_up = false; -iavf_dev_event_post (adapter->vf.eth_dev,RTE_ETH_EVENT_INTR_RESET , +iavf_dev_event_post (dev,RTE_ETH_EVENT_INTR_RESET ,NULL ,0 ); } }
@@ -369,7 +370,7 @@ iavf_dev_watchdog(void *cb_arg)if (rc)PMD_DRV_LOG (ERR ,"Failed \"%s\" to reset device watchdog alarm" , - adapter->vf.eth_dev->data->name); + dev->data->name); } }
@@ -2669,8 +2670,6 @@ iavf_init_vf(struct rte_eth_dev *dev)struct iavf_hw *hw =IAVF_DEV_PRIVATE_TO_HW (dev->data->dev_private);struct iavf_info *vf =IAVF_DEV_PRIVATE_TO_VF (dev->data->dev_private); - vf->eth_dev = dev; - err =iavf_parse_devargs (dev);if (err) {PMD_INIT_LOG (ERR ,"Failed to parse devargs" );
drivers/net/intel/iavf/iavf_ipsec_crypto.c +12 -12
@@ -689,11 +689,9 @@ iavf_ipsec_crypto_session_create(void *device,* returns: 1 if valid */ uint32_t -iavf_ipsec_crypto_action_valid (struct rte_eth_dev *ethdev, +iavf_ipsec_crypto_action_valid (struct iavf_adapter *adapter,const struct rte_security_session *session,uint32_t spi) { -struct iavf_adapter *adapter = -IAVF_DEV_PRIVATE_TO_ADAPTER (ethdev->data->dev_private);const struct iavf_security_session *sess = (const void *)session->driver_priv_data;/* verify we have a valid session and that it belong to this adapter */
@@ -1502,24 +1500,25 @@ static struct rte_security_ops iavf_ipsec_crypto_ops = {int iavf_security_ctx_create (struct iavf_adapter *adapter) { +struct rte_eth_dev *dev =iavf_get_eth_dev (adapter);struct rte_security_ctx *sctx; sctx =rte_malloc ("security_ctx" ,sizeof (struct rte_security_ctx ),0 );if (sctx ==NULL )return -ENOMEM ; - sctx->device = adapter->vf.eth_dev; + sctx->device = dev; sctx->ops = &iavf_ipsec_crypto_ops; sctx->sess_cnt =0 ; - adapter->vf.eth_dev->security_ctx = sctx; + dev->security_ctx = sctx;if (adapter->security_ctx ==NULL ) { adapter->security_ctx =rte_malloc ("iavf_security_ctx" ,sizeof (struct iavf_security_ctx ),0 );if (adapter->security_ctx ==NULL ) { -rte_free (adapter->vf.eth_dev->security_ctx); - adapter->vf.eth_dev->security_ctx =NULL ; +rte_free (dev->security_ctx); + dev->security_ctx =NULL ;return -ENOMEM ; } }
@@ -1565,7 +1564,8 @@ iavf_security_get_pkt_md_offset(struct iavf_adapter *adapter)int iavf_security_ctx_destroy (struct iavf_adapter *adapter) { -struct rte_security_ctx *sctx = adapter->vf.eth_dev->security_ctx; +struct rte_eth_dev *dev =iavf_get_eth_dev (adapter); +struct rte_security_ctx *sctx = dev->security_ctx;struct iavf_security_ctx *iavf_sctx = adapter->security_ctx;if (iavf_sctx ==NULL )
@@ -1578,7 +1578,7 @@ iavf_security_ctx_destroy(struct iavf_adapter *adapter)rte_free (sctx); adapter->security_ctx =NULL ; - adapter->vf.eth_dev->security_ctx =NULL ; + dev->security_ctx =NULL ;return 0 ; }
@@ -1748,7 +1748,7 @@ parse_udp_item(const struct rte_flow_item_udp *item, struct rte_udp_hdr *udp) }static struct iavf_ipsec_flow_item * -iavf_ipsec_flow_item_parse (struct rte_eth_dev *ethdev, +iavf_ipsec_flow_item_parse (struct iavf_adapter *adapter,const struct rte_flow_item pattern[],const struct rte_security_session *session,uint32_t type)
@@ -1819,7 +1819,7 @@ iavf_ipsec_flow_item_parse(struct rte_eth_dev *ethdev, goto flow_cleanup; } -if (!iavf_ipsec_crypto_action_valid (ethdev, session, +if (!iavf_ipsec_crypto_action_valid (adapter, session, ipsec_flow->spi)) goto flow_cleanup;
@@ -1967,7 +1967,7 @@ iavf_ipsec_flow_parse(struct iavf_adapter *ad,const struct rte_security_session *session = parsed_actions.actions[0 ]->conf;uint32_t type = (uint64_t )(item->meta);struct iavf_ipsec_flow_item *fi = -iavf_ipsec_flow_item_parse (ad->vf.eth_dev, pattern, session, type); +iavf_ipsec_flow_item_parse (ad, pattern, session, type);if (fi && meta) { *meta = fi; ret =0 ;
drivers/net/intel/iavf/iavf_ipsec_crypto.h +2 -2
@@ -127,13 +127,13 @@ int iavf_security_get_pkt_md_offset(struct iavf_adapter *adapter);/** * Destroy security context */ -int iavf_security_ctx_destroy (struct iavf_adapter *adapterv); +int iavf_security_ctx_destroy (struct iavf_adapter *adapter);/** * Verify that the inline IPsec Crypto action is valid for this device */ uint32_t -iavf_ipsec_crypto_action_valid (struct rte_eth_dev *ethdev, +iavf_ipsec_crypto_action_valid (struct iavf_adapter *adapter,const struct rte_security_session *session,uint32_t spi);/**
drivers/net/intel/iavf/iavf_vchnl.c +4 -3
@@ -314,13 +314,14 @@ iavf_read_msg_from_pf(struct iavf_adapter *adapter, uint16_t buf_len, opcode, vf->cmd_retval);if (opcode ==VIRTCHNL_OP_EVENT ) { +struct rte_eth_dev *dev =iavf_get_eth_dev (adapter);struct virtchnl_pf_event *vpe = (struct virtchnl_pf_event *)event.msg_buf; result =IAVF_MSG_SYS ;switch (vpe->event) {case VIRTCHNL_EVENT_LINK_CHANGE : -iavf_handle_link_change_event (vf->eth_dev, vpe); +iavf_handle_link_change_event (dev, vpe);break ;case VIRTCHNL_EVENT_RESET_IMPENDING :/*
@@ -335,8 +336,8 @@ iavf_read_msg_from_pf(struct iavf_adapter *adapter, uint16_t buf_len,iavf_set_no_poll (adapter, false);iavf_dev_watchdog_enable (adapter);if (adapter->devargs.no_poll_on_link_down) -iavf_dev_tx_drain (vf->eth_dev); -iavf_dev_event_post (vf->eth_dev, +iavf_dev_tx_drain (dev); +iavf_dev_event_post (dev,RTE_ETH_EVENT_INTR_RESET ,NULL ,0 ); }
Signature · 1 line
2.52.0
PATCH v4 3/10 net/iavf: fix false success on flow validation
In reply to Anatoly Burakoviavf_parse_engine_validate() sets an error when validation fails, but then returns the engine pointer. iavf_flow_process_filter() treats a non-NULL engine as success, so rte_flow_validate() can accept an invalid flow.
Return NULL on validation failure and return the engine only after validation succeeds.
--- drivers/net/intel/iavf/iavf_generic_flow.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
drivers/net/intel/iavf/iavf_generic_flow.c +3 -2
@@ -2134,10 +2134,11 @@ iavf_parse_engine_validate(struct iavf_adapter *ad,rte_flow_error_set (error,EINVAL ,RTE_FLOW_ERROR_TYPE_HANDLE ,NULL ,"Validation failed" ); -break ; +return NULL ; } +return engine; } -return engine; +return NULL ; }
Signature · 1 line
2.52.0
PATCH v4 4/10 net/iavf: fix memory leaks around IRQ resources
In reply to Anatoly Burakoviavf_config_rx_queues_irqs() allocates a queue-vector map and may enable eventfds and allocate an interrupt vector list. If queue startup then fails, those resources remain allocated. The queue-vector map is also retained after a normal stop, leaking it across start/stop cycles.
Release the resources on failed startup and free the queue-vector map on stop. Clean up eventfds when interrupt setup fails as well.
--- drivers/net/intel/iavf/iavf_ethdev.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-)
drivers/net/intel/iavf/iavf_ethdev.c +18 -4
@@ -863,7 +863,7 @@ static int iavf_config_rx_queues_irqs(struct rte_eth_dev *dev,if (rte_intr_cap_multiple (intr_handle) && dev->data->dev_conf.intr_conf.rxq) {if (rte_intr_efd_enable (intr_handle, dev->data->nb_rx_queues)) -return -1 ; + goto efd_alloc_err; }if (rte_intr_dp_is_en (intr_handle)) {
@@ -871,7 +871,7 @@ static int iavf_config_rx_queues_irqs(struct rte_eth_dev *dev, dev->data->nb_rx_queues)) {PMD_DRV_LOG (ERR ,"Failed to allocate %d rx intr_vec" , dev->data->nb_rx_queues); -return -1 ; + goto qv_map_alloc_err; } }
@@ -981,6 +981,8 @@ static int iavf_config_rx_queues_irqs(struct rte_eth_dev *dev, qv_map_alloc_err:rte_intr_vec_list_free (intr_handle); +efd_alloc_err: +rte_intr_efd_disable (intr_handle);return -1 ; }
@@ -1034,12 +1036,15 @@ iavf_dev_start(struct rte_eth_dev *dev)struct rte_intr_handle *intr_handle = dev->intr_handle;uint16_t num_queue_pairs;uint16_t index =0 ; +bool wb_on_itr;PMD_INIT_FUNC_TRACE ();if (adapter->closed)return -1 ; + wb_on_itr = (vf->vf_res->vf_cap_flags &VIRTCHNL_VF_OFFLOAD_WB_ON_ITR ) !=0 ; + vf->max_pkt_len = dev->data->mtu +IAVF_ETH_OVERHEAD ; vf->num_queue_pairs =RTE_MAX (dev->data->nb_rx_queues, dev->data->nb_tx_queues);
@@ -1089,7 +1094,7 @@ iavf_dev_start(struct rte_eth_dev *dev) }/* re-enable intr again, because efd assign may change */ if (dev->data->dev_conf.intr_conf.rxq !=0 ) { -if (vf->vf_res->vf_cap_flags &VIRTCHNL_VF_OFFLOAD_WB_ON_ITR ) +if (wb_on_itr)rte_intr_disable (intr_handle);rte_intr_enable (intr_handle); }
@@ -1107,7 +1112,7 @@ iavf_dev_start(struct rte_eth_dev *dev)if (iavf_start_queues (dev) !=0 ) {PMD_DRV_LOG (ERR ,"enable queues failed" ); - goto error; + goto irq_error; }iavf_phc_sync_alarm_start (dev);
@@ -1118,6 +1123,13 @@ iavf_dev_start(struct rte_eth_dev *dev)return 0 ; +irq_error: +if (!wb_on_itr && dev->data->dev_conf.intr_conf.rxq !=0 ) +rte_intr_disable (intr_handle); +rte_intr_efd_disable (intr_handle); +rte_intr_vec_list_free (intr_handle); +rte_free (vf->qv_map); + vf->qv_map =NULL ; error:return -1 ; }
@@ -1150,6 +1162,8 @@ iavf_dev_stop(struct rte_eth_dev *dev)rte_intr_vec_list_free (intr_handle);iavf_stop_queues (dev); +rte_free (vf->qv_map); + vf->qv_map =NULL ; adapter->stopped =1 ; dev->data->dev_started =0 ;
Signature · 1 line
2.52.0
PATCH v4 5/10 net/iavf: fix generic flow error-path leaks
In reply to Anatoly BurakovIf a flow engine fails to initialize, parsers registered by earlier engines remain allocated. Pattern matching also leaks its item array when allocation of the match result fails.
Unwind registered parsers on flow initialization failure and free the item array on match-result allocation failure.
--- drivers/net/intel/iavf/iavf_generic_flow.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)
drivers/net/intel/iavf/iavf_generic_flow.c +8 -2
@@ -1821,17 +1821,22 @@ iavf_flow_init(struct iavf_adapter *ad)if (engine->init ==NULL ) {PMD_INIT_LOG (ERR ,"Invalid engine type (%d)" , engine->type); -return -ENOTSUP ; + ret = -ENOTSUP ; + goto err; } ret = engine->init (ad);if (ret && ret != -ENOTSUP ) {PMD_INIT_LOG (ERR ,"Failed to initialize engine %d" , engine->type); -return ret; + goto err; } }return 0 ; + +err: +iavf_flow_uninit (ad); +return ret; }void
@@ -2047,6 +2052,7 @@ iavf_search_pattern_match_item(const struct rte_flow_item pattern[],if (!pattern_match_item) {rte_flow_error_set (error,ENOMEM ,RTE_FLOW_ERROR_TYPE_HANDLE ,NULL ,"Failed to allocate memory." ); +rte_free (items);return NULL ; }
Signature · 1 line
2.52.0
PATCH v4 6/10 net/iavf: centralize memory management for flows
In reply to Anatoly BurakovFlow engines currently distribute rule allocation and cleanup between the parser, engine create and destroy callbacks, and generic flow code. This leads to a lot of potential for memory leaks and bugs. In particular, one of the issues currently present is that when PF initiates reset, we are meant to just drop all flows without sending any virtchnl commands, but because not all engines implement the free callback, some flows will be leaked.
To address that specific leak as well as all other potential leaks due to misuse of memory by engines, use parser-allocated rule objects as the persistent rules and centralize their lifetime in the generic flow layer. This requires fixing all engines to not manage their own memory:
- Allocate the final FDIR rule in the parser, use it for action checks, and remove the per-VF scratch configuration.
- Have FSUB create adopt its parser-produced rule instead of allocating and copying a second object.
- Build the final RSS configuration in the parser and remove the intermediate RSS metadata, including its unused raw-pattern flag.
- Let generic flow code free rules on validate, create failure, successful destroy, and uninit; remove engine-specific free callbacks and rule frees from destroy callbacks.
--- drivers/net/intel/iavf/iavf.h | 5 -- drivers/net/intel/iavf/iavf_fdir.c | 68 +++++++-------- drivers/net/intel/iavf/iavf_fsub.c | 23 +---- drivers/net/intel/iavf/iavf_generic_flow.c | 36 ++++++-- drivers/net/intel/iavf/iavf_generic_flow.h | 2 - drivers/net/intel/iavf/iavf_hash.c | 99 +++++++--------------- drivers/net/intel/iavf/iavf_ipsec_crypto.c | 1 - 7 files changed, 97 insertions(+), 137 deletions(-)
drivers/net/intel/iavf/iavf.h +0 -5
@@ -155,10 +155,6 @@ struct iavf_fdir_conf {uint32_t mark_flag; }; -struct iavf_fdir_info { -struct iavf_fdir_conf conf; -}; -struct iavf_fsub_conf {struct virtchnl_flow_sub sub_fltr;struct virtchnl_flow_unsub unsub_fltr;
@@ -286,7 +282,6 @@ struct iavf_info {struct iavf_parser_list dist_parser_list;struct iavf_parser_list ipsec_crypto_parser_list; -struct iavf_fdir_info fdir;/* flow director info */ /* indicate large VF support enabled or not */ bool lv_enabled;
drivers/net/intel/iavf/iavf_fdir.c +35 -33
138 lines not on this page · raw message
drivers/net/intel/iavf/iavf_fsub.c +2 -21
@@ -73,34 +73,18 @@ iavf_fsub_create(struct iavf_adapter *ad, struct rte_flow *flow, void *meta, struct rte_flow_error *error) { struct iavf_fsub_conf *filter = meta; -struct iavf_fsub_conf *rule;int ret; - rule =rte_zmalloc ("fsub_entry" ,sizeof (*rule),0 ); -if (!rule) { -rte_flow_error_set (error,ENOMEM , -RTE_FLOW_ERROR_TYPE_HANDLE ,NULL , -"Failed to allocate memory for fsub rule" ); -return -rte_errno; - } - ret =iavf_flow_sub (ad, filter);if (ret) {rte_flow_error_set (error, -ret,RTE_FLOW_ERROR_TYPE_HANDLE ,NULL ,"Failed to subscribe flow rule." ); - goto free_entry; +return -rte_errno; } -memcpy (rule, filter,sizeof (*rule)); - flow->rule = rule; - -rte_free (meta); + flow->rule = filter;return ret; - -free_entry: -rte_free (rule); -return -rte_errno; } static int
@@ -120,9 +104,6 @@ iavf_fsub_destroy(struct iavf_adapter *ad, struct rte_flow *flow,return -rte_errno; } - flow->rule =NULL ; -rte_free (filter); -return ret; }
drivers/net/intel/iavf/iavf_generic_flow.c +29 -7
@@ -46,6 +46,13 @@ static int iavf_flow_dev_dump(struct rte_eth_dev *dev,FILE *file, struct rte_flow_error *error); +static void +iavf_flow_free (struct rte_flow *flow) +{ +rte_free (flow->rule); +rte_free (flow); +} +const struct rte_flow_ops iavf_flow_ops = { .validate = iavf_flow_validate, .create = iavf_flow_create,
@@ -1856,9 +1863,7 @@ iavf_flow_uninit(struct iavf_adapter *ad)/* Remove all flows */ while ((p_flow =TAILQ_FIRST (&vf->flow_list))) {TAILQ_REMOVE (&vf->flow_list, p_flow, node); -if (p_flow->engine->free) - p_flow->engine->free (p_flow); -rte_free (p_flow); +iavf_flow_free (p_flow); }/* Cleanup parser list */
@@ -2092,6 +2097,7 @@ iavf_parse_engine_create(struct iavf_adapter *ad,void *meta =NULL ; RTE_TAILQ_FOREACH_SAFE(parser_node, parser_list, node, temp) { + meta =NULL ; if (parser_node->parser->parse_pattern_action(ad, parser_node->parser->array, parser_node->parser->array_len,
@@ -2101,8 +2107,17 @@ iavf_parse_engine_create(struct iavf_adapter *ad, engine = parser_node->parser->engine;RTE_ASSERT (engine->create !=NULL ); -if (!(engine->create (ad, flow, meta, error))) +if (engine->create (ad, flow, meta, error) ==0 ) { +if (flow->rule != meta) +rte_free (meta);return engine; + } + +if (flow->rule !=NULL && flow->rule != meta) +rte_free (flow->rule); +rte_free (meta); + flow->rule =NULL ; + meta =NULL ; }return NULL ; }
@@ -2120,8 +2135,10 @@ iavf_parse_engine_validate(struct iavf_adapter *ad,struct iavf_flow_parser_node *parser_node;void *temp;void *meta =NULL ; +int ret; RTE_TAILQ_FOREACH_SAFE(parser_node, parser_list, node, temp) { + meta =NULL ; if (parser_node->parser->parse_pattern_action(ad, parser_node->parser->array, parser_node->parser->array_len,
@@ -2130,13 +2147,18 @@ iavf_parse_engine_validate(struct iavf_adapter *ad, engine = parser_node->parser->engine;if (engine->validation ==NULL ) { +rte_free (meta); + meta =NULL ;rte_flow_error_set (error,EINVAL ,RTE_FLOW_ERROR_TYPE_HANDLE ,NULL ,"Validation not support" );continue ; } -if (engine->validation (ad, flow, meta, error)) { + ret = engine->validation (ad, flow, meta, error); +rte_free (meta); + meta =NULL ; +if (ret !=0 ) {rte_flow_error_set (error,EINVAL ,RTE_FLOW_ERROR_TYPE_HANDLE ,NULL ,"Validation failed" );
@@ -2238,7 +2260,7 @@ iavf_flow_create(struct rte_eth_dev *dev, &engine, iavf_parse_engine_create, error);if (ret <0 ) {PMD_DRV_LOG (ERR ,"Failed to create flow" ); -rte_free (flow); +iavf_flow_free (flow); flow =NULL ; goto free_flow; }
@@ -2308,7 +2330,7 @@ iavf_flow_destroy(struct rte_eth_dev *dev,if (!ret) {TAILQ_REMOVE (&vf->flow_list, flow, node); -rte_free (flow); +iavf_flow_free (flow); }else {PMD_DRV_LOG (ERR ,"Failed to destroy flow" ); }
drivers/net/intel/iavf/iavf_generic_flow.h +0 -2
@@ -465,7 +465,6 @@ typedef int (*engine_query_t)(struct iavf_adapter *ad,struct rte_flow *flow, struct rte_flow_query_count *count, struct rte_flow_error *error); -typedef void (*engine_free_t ) (struct rte_flow *flow); typedef int (*parse_pattern_action_t)(struct iavf_adapter *ad, struct iavf_pattern_match_item *array, uint32_t array_len,
@@ -494,7 +493,6 @@ struct iavf_flow_engine {engine_create_t create;engine_destroy_t destroy;engine_query_t query_count; -engine_free_t free;const char *name;enum iavf_flow_engine_type type;size_t rule_size;
drivers/net/intel/iavf/iavf_hash.c +31 -68
206 lines not on this page · raw message
drivers/net/intel/iavf/iavf_ipsec_crypto.c +0 -1
@@ -1919,7 +1919,6 @@ iavf_ipsec_flow_destroy(struct iavf_adapter *ad,iavf_ipsec_crypto_security_policy_delete (ad, ipsec_flow->is_ipv4, ipsec_flow->id); -rte_free (ipsec_flow);return 0 ; }
Signature · 1 line
2.52.0
PATCH v4 7/10 net/iavf: skip RSS teardown during PF-initiated reset
In reply to Anatoly BurakovDuring PF-initiated reset recovery, iavf_dev_close() skips flow flush to avoid sending virtchnl messages to the PF. However, iavf_hash_uninit() is still called unconditionally, even though any existing RSS configuration is now invalid because of PF-initiated reset.
Move the RSS teardown under the same pf_reset_in_progress check as flow flush, so that no RSS configuration messages are sent during PF-initiated reset recovery.
--- drivers/net/intel/iavf/iavf_ethdev.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
drivers/net/intel/iavf/iavf_ethdev.c +4 -4
@@ -3246,12 +3246,12 @@ iavf_dev_close(struct rte_eth_dev *dev)/* free iAVF security device context all related resources */ iavf_security_ctx_destroy (adapter); -/* remove RSS configuration */ -iavf_hash_uninit (adapter); -/* Skip the virtchnl-emitting teardown on a PF-initiated reset */ -if (!vf->pf_reset_in_progress) +if (!vf->pf_reset_in_progress) { +/* remove RSS configuration */ +iavf_hash_uninit (adapter);iavf_flow_flush (dev,NULL ); + }iavf_flow_uninit (adapter);/*
Signature · 1 line
2.52.0
PATCH v4 8/10 net/iavf: remove redundant reset checks from RSS engine
In reply to Anatoly BurakovThe RSS engine checks vf_reset during init, destroy and uninit to avoid sending virtchnl commands while the VF is resetting. These checks are no longer needed:
- iavf_hash_init() only registers the parser and sends no commands.
- iavf_dev_close() skips both flow flush and RSS teardown during PF-initiated reset recovery.
- the generic flow layer frees rule memory without relying on engine callbacks.
- iavf_execute_vf_cmd() already refuses to send commands while vf_reset is set.
Remove these checks as they are no longer needed.
--- drivers/net/intel/iavf/iavf_hash.c | 10 ---------- 1 file changed, 10 deletions(-)
drivers/net/intel/iavf/iavf_hash.c +0 -10
@@ -762,9 +762,6 @@ iavf_hash_init(struct iavf_adapter *ad)struct iavf_flow_parser *parser;int ret; -if (vf->vf_reset) -return -EIO ; -if (!vf->vf_res)return -EINVAL ;
@@ -1601,13 +1598,9 @@ iavf_hash_destroy(__rte_unused struct iavf_adapter *ad,struct rte_flow *flow, __rte_unused struct rte_flow_error *error) { - struct iavf_info *vf = IAVF_DEV_PRIVATE_TO_VF(ad); struct virtchnl_rss_cfg *rss_cfg;int ret =0 ; -if (vf->vf_reset) -return 0 ; - rss_cfg = (struct virtchnl_rss_cfg *)flow->rule; ret =iavf_add_del_rss_cfg (ad, rss_cfg, false);
@@ -1633,9 +1626,6 @@ iavf_hash_uninit(struct iavf_adapter *ad)struct iavf_info *vf =IAVF_DEV_PRIVATE_TO_VF (ad);struct rte_eth_rss_conf *rss_conf; -if (vf->vf_reset) -return ; -if (!vf->vf_res)return ;
Signature · 1 line
2.52.0
PATCH v4 9/10 net/iavf: fix null engine for egress security flows
In reply to Anatoly BurakovEgress security flows bypass the flow parsers and are inserted with a NULL engine pointer. The create path then dereferences that pointer when logging the new flow, and other engine-based operations cannot handle the flow consistently.
Register an egress security engine and route these flows through the normal parser and lifecycle callbacks. Egress flows own no rule and require no hardware teardown.
--- drivers/net/intel/iavf/iavf_generic_flow.c | 44 +++----- drivers/net/intel/iavf/iavf_generic_flow.h | 2 +- drivers/net/intel/iavf/iavf_ipsec_crypto.c | 120 +++++++++++++++++++-- 3 files changed, 123 insertions(+), 43 deletions(-)
drivers/net/intel/iavf/iavf_generic_flow.c +12 -32
@@ -1914,7 +1914,8 @@ iavf_register_parser(struct iavf_flow_parser *parser, } }TAILQ_INSERT_HEAD (list, parser_node, node); - }else if (parser->engine->type ==IAVF_FLOW_ENGINE_IPSEC_CRYPTO ) { + }else if (parser->engine->type ==IAVF_FLOW_ENGINE_IPSEC_CRYPTO || + parser->engine->type ==IAVF_FLOW_ENGINE_IPSEC_EGRESS ) { list = &vf->ipsec_crypto_parser_list;TAILQ_INSERT_HEAD (list, parser_node, node); }else if (parser->engine->type ==IAVF_FLOW_ENGINE_FSUB ) {
@@ -1943,7 +1944,8 @@ iavf_unregister_parser(struct iavf_flow_parser *parser,else if ((parser->engine->type ==IAVF_FLOW_ENGINE_FDIR ) || (parser->engine->type ==IAVF_FLOW_ENGINE_FSUB )) list = &vf->dist_parser_list; -else if (parser->engine->type ==IAVF_FLOW_ENGINE_IPSEC_CRYPTO ) +else if (parser->engine->type ==IAVF_FLOW_ENGINE_IPSEC_CRYPTO || + parser->engine->type ==IAVF_FLOW_ENGINE_IPSEC_EGRESS ) list = &vf->ipsec_crypto_parser_list;if (list ==NULL )
@@ -2250,12 +2252,6 @@ iavf_flow_create(struct rte_eth_dev *dev,return flow; } -/* Special case for inline crypto egress flows */ -if (attr->egress && actions[0 ].type ==RTE_FLOW_ACTION_TYPE_SECURITY ) { - flow->is_ipsec_egress_flow = true; - goto tailq_insert; - } - ret =iavf_flow_process_filter (dev, flow, attr, pattern, actions, &engine, iavf_parse_engine_create, error);if (ret <0 ) {
@@ -2266,7 +2262,6 @@ iavf_flow_create(struct rte_eth_dev *dev, } flow->engine = engine; -tailq_insert:rte_spinlock_lock (&vf->flow_ops_lock);TAILQ_INSERT_TAIL (&vf->flow_list, flow, node);rte_spinlock_unlock (&vf->flow_ops_lock);
@@ -2282,14 +2277,7 @@ iavf_flow_is_valid(struct rte_flow *flow)struct iavf_flow_engine *engine;void *temp; -if (flow ==NULL ) -return false; - -/* these flows don't use engines */ -if (flow->is_ipsec_egress_flow) -return true; - -if (flow->engine) { +if (flow !=NULL && flow->engine !=NULL ) { RTE_TAILQ_FOREACH_SAFE(engine, &engine_list, node, temp) {if (engine == flow->engine)return true;
@@ -2307,26 +2295,17 @@ iavf_flow_destroy(struct rte_eth_dev *dev,struct iavf_adapter *ad =IAVF_DEV_PRIVATE_TO_ADAPTER (dev->data->dev_private);struct iavf_info *vf =IAVF_DEV_PRIVATE_TO_VF (ad); -bool need_destroy;int ret =0 ; -if (!iavf_flow_is_valid (flow)) { +if (!iavf_flow_is_valid (flow) || flow->engine->destroy ==NULL ) {rte_flow_error_set (error,EINVAL ,RTE_FLOW_ERROR_TYPE_HANDLE ,NULL ,"Invalid flow destroy" );return -rte_errno; } - need_destroy = !flow->is_ipsec_egress_flow; - -if (need_destroy && flow->engine->destroy ==NULL ) { -return rte_flow_error_set (error,EINVAL , -RTE_FLOW_ERROR_TYPE_HANDLE ,NULL , -"Invalid flow destroy" ); - }rte_spinlock_lock (&vf->flow_ops_lock); -if (need_destroy) - ret = flow->engine->destroy (ad, flow, error); + ret = flow->engine->destroy (ad, flow, error);if (!ret) {TAILQ_REMOVE (&vf->flow_list, flow, node);
@@ -2444,16 +2423,17 @@ iavf_flow_dev_dump(struct rte_eth_dev *dev,if (flow !=NULL && f != flow)continue ; -/* this should not happen */ -if (f->engine ==NULL || f->rule ==NULL ) { +if (!iavf_flow_is_valid (f)) {PMD_DRV_LOG (DEBUG ,"Invalid flow" );continue ; } found = true; - rule_size = f->engine->rule_size; - rule_data = f->rule; +if (f->rule !=NULL ) { + rule_size = f->engine->rule_size; + rule_data = f->rule; + } iavf_flow_dump_blob(file, f->engine->name != NULL ?
drivers/net/intel/iavf/iavf_generic_flow.h +1 -1
@@ -481,6 +481,7 @@ enum iavf_flow_engine_type {IAVF_FLOW_ENGINE_FDIR ,IAVF_FLOW_ENGINE_HASH ,IAVF_FLOW_ENGINE_FSUB , +IAVF_FLOW_ENGINE_IPSEC_EGRESS , IAVF_FLOW_ENGINE_MAX, };
@@ -503,7 +504,6 @@ TAILQ_HEAD(iavf_engine_list, iavf_flow_engine);/* Struct to store flow created. */ struct rte_flow {TAILQ_ENTRY (rte_flow) node; -bool is_ipsec_egress_flow;struct iavf_flow_engine *engine;void *rule; };
drivers/net/intel/iavf/iavf_ipsec_crypto.c +110 -10
145 lines not on this page · raw message
Signature · 1 line
2.52.0
PATCH v4 10/10 net/iavf: fix IPsec flow metadata leaks
In reply to Anatoly BurakovIPsec flow parsing leaves the pattern-match item allocated after extracting its metadata. It also leaves the parsed flow item allocated when no metadata output is requested.
Free the pattern-match item after parsing and free the parsed flow item when it cannot be returned to the caller. Propagate pattern-match failure and report a parsing error when no flow item was produced.
--- drivers/net/intel/iavf/iavf_ipsec_crypto.c | 28 +++++++++++++++------- 1 file changed, 20 insertions(+), 8 deletions(-)
drivers/net/intel/iavf/iavf_ipsec_crypto.c +20 -8
@@ -1942,6 +1942,7 @@ iavf_ipsec_flow_parse(struct iavf_adapter *ad, .max_actions = 1, };struct iavf_pattern_match_item *item =NULL ; +struct iavf_ipsec_flow_item *fi =NULL ;int ret =-1 ; ret =ci_flow_check_attr (attr,NULL , error);
@@ -1953,17 +1954,28 @@ iavf_ipsec_flow_parse(struct iavf_adapter *ad,return ret; item =iavf_search_pattern_match_item (pattern, array, array_len, error); -if (item && item->meta) { +if (item ==NULL ) +return -rte_errno; + +if (item->meta !=NULL ) {const struct rte_security_session *session = parsed_actions.actions[0 ]->conf;uint32_t type = (uint64_t )(item->meta); -struct iavf_ipsec_flow_item *fi = -iavf_ipsec_flow_item_parse (ad, pattern, session, type); -if (fi && meta) { - *meta = fi; - ret =0 ; - } + + fi =iavf_ipsec_flow_item_parse (ad, pattern, session, type); } -return ret; +rte_free (item); + +if (fi ==NULL ) +return rte_flow_error_set (error,EINVAL , +RTE_FLOW_ERROR_TYPE_ACTION ,NULL , +"Invalid IPsec flow." ); + +if (meta !=NULL ) + *meta = fi; +else +rte_free (fi); + +return 0 ; }/*
Signature · 1 line
2.52.0
Re: [PATCH v4 01/10] net/iavf: keep device stopped if start fails
In reply to Anatoly BurakovQuoted 8 lines · Anatoly Burakov
Currently,
iavf_dev_start()clearsadapter->stoppedbefore several operations that can fail. A subsequentiavf_dev_stop()then disables interrupts and stops and resets queues even though startup did not complete.Mark the adapter running only after startup succeeds, and return early from stop when it is already stopped.
Quoted 8 lines
Fixes 69dd4c3d0898 ("net/avf: enable queue and device")Signed-off-by Anatoly Burakov <[email protected]>--- drivers/net/intel/iavf/iavf_ethdev.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-)
Re: [PATCH v4 02/10] net/iavf: do not store ethdev pointer
In reply to Anatoly BurakovQuoted 6 lines · Anatoly Burakov
We should not be storing
rte_eth_devpointers in shared memory, becauserte_eth_devpointers are process local. To address that, remove the pointer fromiavf_info, replace it withrte_eth_devices-based lookup, and rework the call paths to either use that lookup, or not require ethdev pointer in the first place.
Quoted 9 lines
Signed-off-by Anatoly Burakov <[email protected]>--- drivers/net/intel/iavf/iavf.h | 9 ++++++-- drivers/net/intel/iavf/iavf_ethdev.c | 11 +++++----- drivers/net/intel/iavf/iavf_ipsec_crypto.c | 24 +++++++++++----------- drivers/net/intel/iavf/iavf_ipsec_crypto.h | 4 ++-- drivers/net/intel/iavf/iavf_vchnl.c | 7 ++++--- 5 files changed, 30 insertions(+), 25 deletions(-)
Re: [PATCH v4 03/10] net/iavf: fix false success on flow validation
In reply to Anatoly BurakovQuoted 8 lines · Anatoly Burakov
iavf_parse_engine_validate()sets an error when validation fails, but then returns the engine pointer.iavf_flow_process_filter()treats a non-NULL engine as success, sorte_flow_validate()can accept an invalid flow.Return
NULLon validation failure and return the engine only after validation succeeds.
Quoted 8 lines
Fixes ff2d0c345c3b ("net/iavf: support generic flow API")Signed-off-by Anatoly Burakov <[email protected]>--- drivers/net/intel/iavf/iavf_generic_flow.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
Re: [PATCH v4 04/10] net/iavf: fix memory leaks around IRQ resources
In reply to Anatoly BurakovQuoted 21 lines · Anatoly Burakov
iavf_config_rx_queues_irqs()allocates a queue-vector map and may enable eventfds and allocate an interrupt vector list. If queue startup then fails, those resources remain allocated. The queue-vector map is also retained after a normal stop, leaking it across start/stop cycles.Release the resources on failed startup and free the queue-vector map on stop. Clean up eventfds when interrupt setup fails as well.
Fixes f593944fc988 ("net/iavf: enable IRQ mapping configuration for large VF")Signed-off-by Anatoly Burakov <[email protected]>--- drivers/net/intel/iavf/iavf_ethdev.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-)drivers/net/intel/iavf/iavf_ethdev.c +0
-0
drivers/net/intel/iavf/iavf_ethdev.c static int iavf_config_rx_queues_irqs(struct rte_eth_dev *dev, · line 867
Quoted 6 lines
drivers/net/intel/iavf/iavf_ethdev.c +1
-1@@ -863,7 +863,7 @@ static int iavf_config_rx_queues_irqs(struct rte_eth_dev *dev,if (rte_intr_cap_multiple (intr_handle) && dev->data->dev_conf.intr_conf.rxq) {if (rte_intr_efd_enable (intr_handle, dev->data->nb_rx_queues)) -return -1 ; + goto efd_alloc_err; }
This change doesn't make sense to me. If the enable fails, we should not need to call disable when handling that error.
Independently AI review flags this that you might want to consider:
Info
Pre-existing and not introduced by this commit: the new failure branch at iavf_ethdev.c:866 calls cleanup after rte_intr_efd_enable() fails, but that helper can create eventfds before returning an error and before recording the completed count at eal_interrupts.c:1580. The cleanup closes only the recorded eventfds at eal_interrupts.c:1623, so a partial allocation failure can still leak descriptors. Track and release partially created eventfds in the helper or cleanup path. Confidence: 9/10.
Quoted 80 lines
drivers/net/intel/iavf/iavf_ethdev.c +17
-3if (rte_intr_dp_is_en (intr_handle)) {@@ -871,7 +871,7 @@ static int iavf_config_rx_queues_irqs(struct rte_eth_dev *dev, dev->data->nb_rx_queues)) {PMD_DRV_LOG (ERR ,"Failed to allocate %d rx intr_vec" , dev->data->nb_rx_queues); -return -1 ; + goto qv_map_alloc_err; } }@@ -981,6 +981,8 @@ static int iavf_config_rx_queues_irqs(struct rte_eth_dev *dev, qv_map_alloc_err:rte_intr_vec_list_free (intr_handle); +efd_alloc_err: +rte_intr_efd_disable (intr_handle);return -1 ; }@@ -1034,12 +1036,15 @@ iavf_dev_start(struct rte_eth_dev *dev)struct rte_intr_handle *intr_handle = dev->intr_handle;uint16_t num_queue_pairs;uint16_t index =0 ; +bool wb_on_itr;PMD_INIT_FUNC_TRACE ();if (adapter->closed)return -1 ; + wb_on_itr = (vf->vf_res->vf_cap_flags &VIRTCHNL_VF_OFFLOAD_WB_ON_ITR ) !=0 ; + vf->max_pkt_len = dev->data->mtu +IAVF_ETH_OVERHEAD ; vf->num_queue_pairs =RTE_MAX (dev->data->nb_rx_queues, dev->data->nb_tx_queues);@@ -1089,7 +1094,7 @@ iavf_dev_start(struct rte_eth_dev *dev) }/* re-enable intr again, because efd assign may change */ if (dev->data->dev_conf.intr_conf.rxq !=0 ) { -if (vf->vf_res->vf_cap_flags &VIRTCHNL_VF_OFFLOAD_WB_ON_ITR ) +if (wb_on_itr)rte_intr_disable (intr_handle);rte_intr_enable (intr_handle); }@@ -1107,7 +1112,7 @@ iavf_dev_start(struct rte_eth_dev *dev)if (iavf_start_queues (dev) !=0 ) {PMD_DRV_LOG (ERR ,"enable queues failed" ); - goto error; + goto irq_error; }iavf_phc_sync_alarm_start (dev);@@ -1118,6 +1123,13 @@ iavf_dev_start(struct rte_eth_dev *dev)return 0 ; +irq_error: +if (!wb_on_itr && dev->data->dev_conf.intr_conf.rxq !=0 ) +rte_intr_disable (intr_handle); +rte_intr_efd_disable (intr_handle); +rte_intr_vec_list_free (intr_handle); +rte_free (vf->qv_map); + vf->qv_map =NULL ; error:return -1 ; }@@ -1150,6 +1162,8 @@ iavf_dev_stop(struct rte_eth_dev *dev)rte_intr_vec_list_free (intr_handle);iavf_stop_queues (dev); +rte_free (vf->qv_map); + vf->qv_map =NULL ; adapter->stopped =1 ; dev->data->dev_started =0 ;Signature · 1 line
2.52.0
Re: [PATCH v4 05/10] net/iavf: fix generic flow error-path leaks
In reply to Anatoly BurakovQuoted 7 lines · Anatoly Burakov
If a flow engine fails to initialize, parsers registered by earlier engines remain allocated. Pattern matching also leaks its item array when allocation of the match result fails.
Unwind registered parsers on flow initialization failure and free the item array on match-result allocation failure.
Quoted 8 lines
Fixes ff2d0c345c3b ("net/iavf: support generic flow API")Signed-off-by Anatoly Burakov <[email protected]>--- drivers/net/intel/iavf/iavf_generic_flow.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)
Re: [PATCH v4 06/10] net/iavf: centralize memory management for flows
In reply to Anatoly BurakovQuoted 29 lines · Anatoly Burakov
Flow engines currently distribute rule allocation and cleanup between the parser, engine create and destroy callbacks, and generic flow code. This leads to a lot of potential for memory leaks and bugs. In particular, one of the issues currently present is that when PF initiates reset, we are meant to just drop all flows without sending any virtchnl commands, but because not all engines implement the
freecallback, some flows will be leaked.To address that specific leak as well as all other potential leaks due to misuse of memory by engines, use parser-allocated rule objects as the persistent rules and centralize their lifetime in the generic flow layer. This requires fixing all engines to not manage their own memory:
- Allocate the final FDIR rule in the parser, use it for action checks, and remove the per-VF scratch configuration.
- Have FSUB create adopt its parser-produced rule instead of allocating and copying a second object.
- Build the final RSS configuration in the parser and remove the intermediate RSS metadata, including its unused raw-pattern flag.
- Let generic flow code free rules on validate, create failure, successful destroy, and uninit; remove engine-specific free callbacks and rule frees from destroy callbacks.Fixes 4dad1a6815d6 ("net/iavf: skip flow flush during PF-initiated reset")Fixes ff2d0c345c3b ("net/iavf: support generic flow API")Signed-off-by Anurag Mandal <[email protected]>Signed-off-by Anatoly Burakov <[email protected]>
Quoted 10 lines
--- drivers/net/intel/iavf/iavf.h | 5 -- drivers/net/intel/iavf/iavf_fdir.c | 68 +++++++-------- drivers/net/intel/iavf/iavf_fsub.c | 23 +---- drivers/net/intel/iavf/iavf_generic_flow.c | 36 ++++++-- drivers/net/intel/iavf/iavf_generic_flow.h | 2 - drivers/net/intel/iavf/iavf_hash.c | 99 +++++++--------------- drivers/net/intel/iavf/iavf_ipsec_crypto.c | 1 - 7 files changed, 97 insertions(+), 137 deletions(-)
Re: [PATCH v4 07/10] net/iavf: skip RSS teardown during PF-initiated reset
In reply to Anatoly BurakovQuoted 9 lines · Anatoly Burakov
During PF-initiated reset recovery,
iavf_dev_close()skips flow flush to avoid sending virtchnl messages to the PF. However,iavf_hash_uninit()is still called unconditionally, even though any existing RSS configuration is now invalid because of PF-initiated reset.Move the RSS teardown under the same
pf_reset_in_progresscheck as flow flush, so that no RSS configuration messages are sent during PF-initiated reset recovery.
Quoted 8 lines
Fixes 4dad1a6815d6 ("net/iavf: skip flow flush during PF-initiated reset")Signed-off-by Anatoly Burakov <[email protected]>--- drivers/net/intel/iavf/iavf_ethdev.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
Re: [PATCH v4 08/10] net/iavf: remove redundant reset checks from RSS engine
In reply to Anatoly BurakovQuoted 12 lines · Anatoly Burakov
The RSS engine checks
vf_resetduring init, destroy and uninit to avoid sending virtchnl commands while the VF is resetting. These checks are no longer needed:-
iavf_hash_init()only registers the parser and sends no commands.
-iavf_dev_close()skips both flow flush and RSS teardown during PF-initiated reset recovery.
- the generic flow layer frees rule memory without relying on engine callbacks.
-iavf_execute_vf_cmd()already refuses to send commands whilevf_resetis set.
Quoted 6 lines
Remove these checks as they are no longer needed.
Signed-off-by Anatoly Burakov <[email protected]>--- drivers/net/intel/iavf/iavf_hash.c | 10 ---------- 1 file changed, 10 deletions(-)
v5 cover IAVF Fixes
In reply to Anatoly BurakovAn assortment of IAVF flow-related memory leak fixes and cleanups.
v4 -> v5:
- Dropped the unnecessary EFD disable from patch 4
v3 -> v4:
- Fixed watchdog crash in commit 2
v2 -> v3:
- Rebase on top of latest next-net-intel including Anurag's fix [1]
- Dropped remnants of Anurag's patch [1] as it's now in the tree
- Fixed PF reset path still tearing down RSS when it shouldn't
- Fixed hash engine checking for VF reset when that's no longer necessary
v1 -> v2:
- Integrated Anurag's earlier fix [1] into the patchset
- Reworked generic flow to have centralized memory management
- Reordered some patches
- Integrated the IRQ leaks patchset [2] [3]
- Reworked IPsec fix
[1] https://patches.dpdk.org/project/dpdk/patch/[email protected]/
[2] https://patches.dpdk.org/project/dpdk/patch/809e0c5b2ab57f1b14c68be8ac34e70cbbe82233.1792053236.git.anatoly.burakov@intel.com/
[3] https://patches.dpdk.org/project/dpdk/patch/5488d85c2ded08838becaee6de8328694ee00234.1792053236.git.anatoly.burakov@intel.com/
Anatoly Burakov (10):
net/iavf: keep device stopped if start fails net/iavf: do not store ethdev pointer net/iavf: fix false success on flow validation net/iavf: fix memory leaks around IRQ resources net/iavf: fix generic flow error-path leaks net/iavf: centralize memory management for flows net/iavf: skip RSS teardown during PF-initiated reset net/iavf: remove redundant reset checks from RSS engine net/iavf: fix null engine for egress security flows net/iavf: fix IPsec flow metadata leaks
drivers/net/intel/iavf/iavf.h | 14 +- drivers/net/intel/iavf/iavf_ethdev.c | 45 ++++-- drivers/net/intel/iavf/iavf_fdir.c | 68 ++++---- drivers/net/intel/iavf/iavf_fsub.c | 23 +-- drivers/net/intel/iavf/iavf_generic_flow.c | 95 ++++++------ drivers/net/intel/iavf/iavf_generic_flow.h | 4 +- drivers/net/intel/iavf/iavf_hash.c | 103 ++++--------- drivers/net/intel/iavf/iavf_ipsec_crypto.c | 171 +++++++++++++++++---- drivers/net/intel/iavf/iavf_ipsec_crypto.h | 4 +- drivers/net/intel/iavf/iavf_vchnl.c | 7 +- 10 files changed, 300 insertions(+), 234 deletions(-)
Signature · 1 line
2.52.0
PATCH v5 1/10 net/iavf: keep device stopped if start fails
Currently, iavf_dev_start() clears adapter->stopped before several operations that can fail. A subsequent iavf_dev_stop() then disables interrupts and stops and resets queues even though startup did not complete.
Mark the adapter running only after startup succeeds, and return early from stop when it is already stopped.
--- drivers/net/intel/iavf/iavf_ethdev.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-)
drivers/net/intel/iavf/iavf_ethdev.c +4 -5
@@ -1039,8 +1039,6 @@ iavf_dev_start(struct rte_eth_dev *dev)if (adapter->closed)return -1 ; - adapter->stopped =0 ; - vf->max_pkt_len = dev->data->mtu +IAVF_ETH_OVERHEAD ; vf->num_queue_pairs =RTE_MAX (dev->data->nb_rx_queues, dev->data->nb_tx_queues);
@@ -1112,6 +1110,7 @@ iavf_dev_start(struct rte_eth_dev *dev) }iavf_phc_sync_alarm_start (dev); + adapter->stopped =0 ;/* An explicit start supersedes any pending deferred start */ vf->start_pending = false;
@@ -1135,13 +1134,13 @@ iavf_dev_stop(struct rte_eth_dev *dev)if (adapter->closed)return -1 ; +if (adapter->stopped ==1 ) +return 0 ; +if (!(vf->vf_res->vf_cap_flags &VIRTCHNL_VF_OFFLOAD_WB_ON_ITR ) && dev->data->dev_conf.intr_conf.rxq !=0 )rte_intr_disable (intr_handle); -if (adapter->stopped ==1 ) -return 0 ; -iavf_phc_sync_alarm_stop (dev);/* Disable the interrupt for Rx */
Signature · 1 line
2.52.0
PATCH v5 2/10 net/iavf: do not store ethdev pointer
In reply to Anatoly BurakovWe should not be storing rte_eth_dev pointers in shared memory, because rte_eth_dev pointers are process local. To address that, remove the pointer from iavf_info, replace it with rte_eth_devices-based lookup, and rework the call paths to either use that lookup, or not require ethdev pointer in the first place.
--- drivers/net/intel/iavf/iavf.h | 9 ++++++-- drivers/net/intel/iavf/iavf_ethdev.c | 11 +++++----- drivers/net/intel/iavf/iavf_ipsec_crypto.c | 24 +++++++++++----------- drivers/net/intel/iavf/iavf_ipsec_crypto.h | 4 ++-- drivers/net/intel/iavf/iavf_vchnl.c | 7 ++++--- 5 files changed, 30 insertions(+), 25 deletions(-)
drivers/net/intel/iavf/iavf.h +7 -2
@@ -7,6 +7,7 @@#include <sys/queue.h> +#include <ethdev_driver.h> #include <rte_kvargs.h> #include <rte_tm_driver.h>
@@ -293,8 +294,6 @@ struct iavf_info {struct iavf_qtc_map *qtc_map;struct iavf_tm_conf tm_conf; -struct rte_eth_dev *eth_dev; -RTE_ATOMIC (bool )in_reset_recovery;bool reset_pending;bool pf_reset_in_progress;
@@ -408,6 +407,12 @@ struct iavf_adapter {uint16_t tpid;/* VLAN tag identifier */ }; +static inline struct rte_eth_dev * +iavf_get_eth_dev (struct iavf_adapter *adapter) +{ +return &rte_eth_devices[adapter->dev_data->port_id]; +} +/* IAVF_DEV_PRIVATE_TO */ #define IAVF_DEV_PRIVATE_TO_ADAPTER (adapter) \ ((struct iavf_adapter *)adapter)
drivers/net/intel/iavf/iavf_ethdev.c +5 -6
@@ -326,6 +326,7 @@ static void iavf_dev_watchdog(void *cb_arg) {struct iavf_adapter *adapter = cb_arg; +struct rte_eth_dev *dev =iavf_get_eth_dev (adapter);struct iavf_hw *hw =IAVF_DEV_PRIVATE_TO_HW (adapter);int vfr_inprogress =0 , rc =0 ;
@@ -339,7 +340,7 @@ iavf_dev_watchdog(void *cb_arg)if (!vfr_inprogress) {PMD_DRV_LOG (INFO ,"VF \"%s\" reset has completed" , - adapter->vf.eth_dev->data->name); + dev->data->name); adapter->vf.vf_reset = false;iavf_set_no_poll (adapter, false); }
@@ -350,14 +351,14 @@ iavf_dev_watchdog(void *cb_arg)if (vfr_inprogress) {PMD_DRV_LOG (INFO ,"VF \"%s\" reset event detected by watchdog" , - adapter->vf.eth_dev->data->name); + dev->data->name);/* enter reset state with VFLR event */ adapter->vf.vf_reset = true;iavf_set_no_poll (adapter, false); adapter->vf.link_up = false; -iavf_dev_event_post (adapter->vf.eth_dev,RTE_ETH_EVENT_INTR_RESET , +iavf_dev_event_post (dev,RTE_ETH_EVENT_INTR_RESET ,NULL ,0 ); } }
@@ -369,7 +370,7 @@ iavf_dev_watchdog(void *cb_arg)if (rc)PMD_DRV_LOG (ERR ,"Failed \"%s\" to reset device watchdog alarm" , - adapter->vf.eth_dev->data->name); + dev->data->name); } }
@@ -2669,8 +2670,6 @@ iavf_init_vf(struct rte_eth_dev *dev)struct iavf_hw *hw =IAVF_DEV_PRIVATE_TO_HW (dev->data->dev_private);struct iavf_info *vf =IAVF_DEV_PRIVATE_TO_VF (dev->data->dev_private); - vf->eth_dev = dev; - err =iavf_parse_devargs (dev);if (err) {PMD_INIT_LOG (ERR ,"Failed to parse devargs" );
drivers/net/intel/iavf/iavf_ipsec_crypto.c +12 -12
@@ -689,11 +689,9 @@ iavf_ipsec_crypto_session_create(void *device,* returns: 1 if valid */ uint32_t -iavf_ipsec_crypto_action_valid (struct rte_eth_dev *ethdev, +iavf_ipsec_crypto_action_valid (struct iavf_adapter *adapter,const struct rte_security_session *session,uint32_t spi) { -struct iavf_adapter *adapter = -IAVF_DEV_PRIVATE_TO_ADAPTER (ethdev->data->dev_private);const struct iavf_security_session *sess = (const void *)session->driver_priv_data;/* verify we have a valid session and that it belong to this adapter */
@@ -1502,24 +1500,25 @@ static struct rte_security_ops iavf_ipsec_crypto_ops = {int iavf_security_ctx_create (struct iavf_adapter *adapter) { +struct rte_eth_dev *dev =iavf_get_eth_dev (adapter);struct rte_security_ctx *sctx; sctx =rte_malloc ("security_ctx" ,sizeof (struct rte_security_ctx ),0 );if (sctx ==NULL )return -ENOMEM ; - sctx->device = adapter->vf.eth_dev; + sctx->device = dev; sctx->ops = &iavf_ipsec_crypto_ops; sctx->sess_cnt =0 ; - adapter->vf.eth_dev->security_ctx = sctx; + dev->security_ctx = sctx;if (adapter->security_ctx ==NULL ) { adapter->security_ctx =rte_malloc ("iavf_security_ctx" ,sizeof (struct iavf_security_ctx ),0 );if (adapter->security_ctx ==NULL ) { -rte_free (adapter->vf.eth_dev->security_ctx); - adapter->vf.eth_dev->security_ctx =NULL ; +rte_free (dev->security_ctx); + dev->security_ctx =NULL ;return -ENOMEM ; } }
@@ -1565,7 +1564,8 @@ iavf_security_get_pkt_md_offset(struct iavf_adapter *adapter)int iavf_security_ctx_destroy (struct iavf_adapter *adapter) { -struct rte_security_ctx *sctx = adapter->vf.eth_dev->security_ctx; +struct rte_eth_dev *dev =iavf_get_eth_dev (adapter); +struct rte_security_ctx *sctx = dev->security_ctx;struct iavf_security_ctx *iavf_sctx = adapter->security_ctx;if (iavf_sctx ==NULL )
@@ -1578,7 +1578,7 @@ iavf_security_ctx_destroy(struct iavf_adapter *adapter)rte_free (sctx); adapter->security_ctx =NULL ; - adapter->vf.eth_dev->security_ctx =NULL ; + dev->security_ctx =NULL ;return 0 ; }
@@ -1748,7 +1748,7 @@ parse_udp_item(const struct rte_flow_item_udp *item, struct rte_udp_hdr *udp) }static struct iavf_ipsec_flow_item * -iavf_ipsec_flow_item_parse (struct rte_eth_dev *ethdev, +iavf_ipsec_flow_item_parse (struct iavf_adapter *adapter,const struct rte_flow_item pattern[],const struct rte_security_session *session,uint32_t type)
@@ -1819,7 +1819,7 @@ iavf_ipsec_flow_item_parse(struct rte_eth_dev *ethdev, goto flow_cleanup; } -if (!iavf_ipsec_crypto_action_valid (ethdev, session, +if (!iavf_ipsec_crypto_action_valid (adapter, session, ipsec_flow->spi)) goto flow_cleanup;
@@ -1967,7 +1967,7 @@ iavf_ipsec_flow_parse(struct iavf_adapter *ad,const struct rte_security_session *session = parsed_actions.actions[0 ]->conf;uint32_t type = (uint64_t )(item->meta);struct iavf_ipsec_flow_item *fi = -iavf_ipsec_flow_item_parse (ad->vf.eth_dev, pattern, session, type); +iavf_ipsec_flow_item_parse (ad, pattern, session, type);if (fi && meta) { *meta = fi; ret =0 ;
drivers/net/intel/iavf/iavf_ipsec_crypto.h +2 -2
@@ -127,13 +127,13 @@ int iavf_security_get_pkt_md_offset(struct iavf_adapter *adapter);/** * Destroy security context */ -int iavf_security_ctx_destroy (struct iavf_adapter *adapterv); +int iavf_security_ctx_destroy (struct iavf_adapter *adapter);/** * Verify that the inline IPsec Crypto action is valid for this device */ uint32_t -iavf_ipsec_crypto_action_valid (struct rte_eth_dev *ethdev, +iavf_ipsec_crypto_action_valid (struct iavf_adapter *adapter,const struct rte_security_session *session,uint32_t spi);/**
drivers/net/intel/iavf/iavf_vchnl.c +4 -3
@@ -314,13 +314,14 @@ iavf_read_msg_from_pf(struct iavf_adapter *adapter, uint16_t buf_len, opcode, vf->cmd_retval);if (opcode ==VIRTCHNL_OP_EVENT ) { +struct rte_eth_dev *dev =iavf_get_eth_dev (adapter);struct virtchnl_pf_event *vpe = (struct virtchnl_pf_event *)event.msg_buf; result =IAVF_MSG_SYS ;switch (vpe->event) {case VIRTCHNL_EVENT_LINK_CHANGE : -iavf_handle_link_change_event (vf->eth_dev, vpe); +iavf_handle_link_change_event (dev, vpe);break ;case VIRTCHNL_EVENT_RESET_IMPENDING :/*
@@ -335,8 +336,8 @@ iavf_read_msg_from_pf(struct iavf_adapter *adapter, uint16_t buf_len,iavf_set_no_poll (adapter, false);iavf_dev_watchdog_enable (adapter);if (adapter->devargs.no_poll_on_link_down) -iavf_dev_tx_drain (vf->eth_dev); -iavf_dev_event_post (vf->eth_dev, +iavf_dev_tx_drain (dev); +iavf_dev_event_post (dev,RTE_ETH_EVENT_INTR_RESET ,NULL ,0 ); }
Signature · 1 line
2.52.0
PATCH v5 3/10 net/iavf: fix false success on flow validation
In reply to Anatoly Burakoviavf_parse_engine_validate() sets an error when validation fails, but then returns the engine pointer. iavf_flow_process_filter() treats a non-NULL engine as success, so rte_flow_validate() can accept an invalid flow.
Return NULL on validation failure and return the engine only after validation succeeds.
--- drivers/net/intel/iavf/iavf_generic_flow.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
drivers/net/intel/iavf/iavf_generic_flow.c +3 -2
@@ -2134,10 +2134,11 @@ iavf_parse_engine_validate(struct iavf_adapter *ad,rte_flow_error_set (error,EINVAL ,RTE_FLOW_ERROR_TYPE_HANDLE ,NULL ,"Validation failed" ); -break ; +return NULL ; } +return engine; } -return engine; +return NULL ; }
Signature · 1 line
2.52.0
PATCH v5 4/10 net/iavf: fix memory leaks around IRQ resources
In reply to Anatoly Burakoviavf_config_rx_queues_irqs() allocates a queue-vector map and may enable eventfds and allocate an interrupt vector list. If queue startup then fails, those resources remain allocated. The queue-vector map is also retained after a normal stop, leaking it across start/stop cycles.
Release the resources on failed startup and free the queue-vector map on stop.
--- drivers/net/intel/iavf/iavf_ethdev.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-)
drivers/net/intel/iavf/iavf_ethdev.c +16 -3
@@ -871,7 +871,7 @@ static int iavf_config_rx_queues_irqs(struct rte_eth_dev *dev, dev->data->nb_rx_queues)) {PMD_DRV_LOG (ERR ,"Failed to allocate %d rx intr_vec" , dev->data->nb_rx_queues); -return -1 ; + goto qv_map_alloc_err; } }
@@ -981,6 +981,7 @@ static int iavf_config_rx_queues_irqs(struct rte_eth_dev *dev, qv_map_alloc_err:rte_intr_vec_list_free (intr_handle); +rte_intr_efd_disable (intr_handle);return -1 ; }
@@ -1034,12 +1035,15 @@ iavf_dev_start(struct rte_eth_dev *dev)struct rte_intr_handle *intr_handle = dev->intr_handle;uint16_t num_queue_pairs;uint16_t index =0 ; +bool wb_on_itr;PMD_INIT_FUNC_TRACE ();if (adapter->closed)return -1 ; + wb_on_itr = (vf->vf_res->vf_cap_flags &VIRTCHNL_VF_OFFLOAD_WB_ON_ITR ) !=0 ; + vf->max_pkt_len = dev->data->mtu +IAVF_ETH_OVERHEAD ; vf->num_queue_pairs =RTE_MAX (dev->data->nb_rx_queues, dev->data->nb_tx_queues);
@@ -1089,7 +1093,7 @@ iavf_dev_start(struct rte_eth_dev *dev) }/* re-enable intr again, because efd assign may change */ if (dev->data->dev_conf.intr_conf.rxq !=0 ) { -if (vf->vf_res->vf_cap_flags &VIRTCHNL_VF_OFFLOAD_WB_ON_ITR ) +if (wb_on_itr)rte_intr_disable (intr_handle);rte_intr_enable (intr_handle); }
@@ -1107,7 +1111,7 @@ iavf_dev_start(struct rte_eth_dev *dev)if (iavf_start_queues (dev) !=0 ) {PMD_DRV_LOG (ERR ,"enable queues failed" ); - goto error; + goto irq_error; }iavf_phc_sync_alarm_start (dev);
@@ -1118,6 +1122,13 @@ iavf_dev_start(struct rte_eth_dev *dev)return 0 ; +irq_error: +if (!wb_on_itr && dev->data->dev_conf.intr_conf.rxq !=0 ) +rte_intr_disable (intr_handle); +rte_intr_efd_disable (intr_handle); +rte_intr_vec_list_free (intr_handle); +rte_free (vf->qv_map); + vf->qv_map =NULL ; error:return -1 ; }
@@ -1150,6 +1161,8 @@ iavf_dev_stop(struct rte_eth_dev *dev)rte_intr_vec_list_free (intr_handle);iavf_stop_queues (dev); +rte_free (vf->qv_map); + vf->qv_map =NULL ; adapter->stopped =1 ; dev->data->dev_started =0 ;
Signature · 1 line
2.52.0
PATCH v5 5/10 net/iavf: fix generic flow error-path leaks
In reply to Anatoly BurakovIf a flow engine fails to initialize, parsers registered by earlier engines remain allocated. Pattern matching also leaks its item array when allocation of the match result fails.
Unwind registered parsers on flow initialization failure and free the item array on match-result allocation failure.
--- drivers/net/intel/iavf/iavf_generic_flow.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)
drivers/net/intel/iavf/iavf_generic_flow.c +8 -2
@@ -1821,17 +1821,22 @@ iavf_flow_init(struct iavf_adapter *ad)if (engine->init ==NULL ) {PMD_INIT_LOG (ERR ,"Invalid engine type (%d)" , engine->type); -return -ENOTSUP ; + ret = -ENOTSUP ; + goto err; } ret = engine->init (ad);if (ret && ret != -ENOTSUP ) {PMD_INIT_LOG (ERR ,"Failed to initialize engine %d" , engine->type); -return ret; + goto err; } }return 0 ; + +err: +iavf_flow_uninit (ad); +return ret; }void
@@ -2047,6 +2052,7 @@ iavf_search_pattern_match_item(const struct rte_flow_item pattern[],if (!pattern_match_item) {rte_flow_error_set (error,ENOMEM ,RTE_FLOW_ERROR_TYPE_HANDLE ,NULL ,"Failed to allocate memory." ); +rte_free (items);return NULL ; }
Signature · 1 line
2.52.0
PATCH v5 6/10 net/iavf: centralize memory management for flows
In reply to Anatoly BurakovFlow engines currently distribute rule allocation and cleanup between the parser, engine create and destroy callbacks, and generic flow code. This leads to a lot of potential for memory leaks and bugs. In particular, one of the issues currently present is that when PF initiates reset, we are meant to just drop all flows without sending any virtchnl commands, but because not all engines implement the free callback, some flows will be leaked.
To address that specific leak as well as all other potential leaks due to misuse of memory by engines, use parser-allocated rule objects as the persistent rules and centralize their lifetime in the generic flow layer. This requires fixing all engines to not manage their own memory:
- Allocate the final FDIR rule in the parser, use it for action checks, and remove the per-VF scratch configuration.
- Have FSUB create adopt its parser-produced rule instead of allocating and copying a second object.
- Build the final RSS configuration in the parser and remove the intermediate RSS metadata, including its unused raw-pattern flag.
- Let generic flow code free rules on validate, create failure, successful destroy, and uninit; remove engine-specific free callbacks and rule frees from destroy callbacks.
--- drivers/net/intel/iavf/iavf.h | 5 -- drivers/net/intel/iavf/iavf_fdir.c | 68 +++++++-------- drivers/net/intel/iavf/iavf_fsub.c | 23 +---- drivers/net/intel/iavf/iavf_generic_flow.c | 36 ++++++-- drivers/net/intel/iavf/iavf_generic_flow.h | 2 - drivers/net/intel/iavf/iavf_hash.c | 99 +++++++--------------- drivers/net/intel/iavf/iavf_ipsec_crypto.c | 1 - 7 files changed, 97 insertions(+), 137 deletions(-)
drivers/net/intel/iavf/iavf.h +0 -5
@@ -155,10 +155,6 @@ struct iavf_fdir_conf {uint32_t mark_flag; }; -struct iavf_fdir_info { -struct iavf_fdir_conf conf; -}; -struct iavf_fsub_conf {struct virtchnl_flow_sub sub_fltr;struct virtchnl_flow_unsub unsub_fltr;
@@ -286,7 +282,6 @@ struct iavf_info {struct iavf_parser_list dist_parser_list;struct iavf_parser_list ipsec_crypto_parser_list; -struct iavf_fdir_info fdir;/* flow director info */ /* indicate large VF support enabled or not */ bool lv_enabled;
drivers/net/intel/iavf/iavf_fdir.c +35 -33
138 lines not on this page · raw message
drivers/net/intel/iavf/iavf_fsub.c +2 -21
@@ -73,34 +73,18 @@ iavf_fsub_create(struct iavf_adapter *ad, struct rte_flow *flow, void *meta, struct rte_flow_error *error) { struct iavf_fsub_conf *filter = meta; -struct iavf_fsub_conf *rule;int ret; - rule =rte_zmalloc ("fsub_entry" ,sizeof (*rule),0 ); -if (!rule) { -rte_flow_error_set (error,ENOMEM , -RTE_FLOW_ERROR_TYPE_HANDLE ,NULL , -"Failed to allocate memory for fsub rule" ); -return -rte_errno; - } - ret =iavf_flow_sub (ad, filter);if (ret) {rte_flow_error_set (error, -ret,RTE_FLOW_ERROR_TYPE_HANDLE ,NULL ,"Failed to subscribe flow rule." ); - goto free_entry; +return -rte_errno; } -memcpy (rule, filter,sizeof (*rule)); - flow->rule = rule; - -rte_free (meta); + flow->rule = filter;return ret; - -free_entry: -rte_free (rule); -return -rte_errno; } static int
@@ -120,9 +104,6 @@ iavf_fsub_destroy(struct iavf_adapter *ad, struct rte_flow *flow,return -rte_errno; } - flow->rule =NULL ; -rte_free (filter); -return ret; }
drivers/net/intel/iavf/iavf_generic_flow.c +29 -7
@@ -46,6 +46,13 @@ static int iavf_flow_dev_dump(struct rte_eth_dev *dev,FILE *file, struct rte_flow_error *error); +static void +iavf_flow_free (struct rte_flow *flow) +{ +rte_free (flow->rule); +rte_free (flow); +} +const struct rte_flow_ops iavf_flow_ops = { .validate = iavf_flow_validate, .create = iavf_flow_create,
@@ -1856,9 +1863,7 @@ iavf_flow_uninit(struct iavf_adapter *ad)/* Remove all flows */ while ((p_flow =TAILQ_FIRST (&vf->flow_list))) {TAILQ_REMOVE (&vf->flow_list, p_flow, node); -if (p_flow->engine->free) - p_flow->engine->free (p_flow); -rte_free (p_flow); +iavf_flow_free (p_flow); }/* Cleanup parser list */
@@ -2092,6 +2097,7 @@ iavf_parse_engine_create(struct iavf_adapter *ad,void *meta =NULL ; RTE_TAILQ_FOREACH_SAFE(parser_node, parser_list, node, temp) { + meta =NULL ; if (parser_node->parser->parse_pattern_action(ad, parser_node->parser->array, parser_node->parser->array_len,
@@ -2101,8 +2107,17 @@ iavf_parse_engine_create(struct iavf_adapter *ad, engine = parser_node->parser->engine;RTE_ASSERT (engine->create !=NULL ); -if (!(engine->create (ad, flow, meta, error))) +if (engine->create (ad, flow, meta, error) ==0 ) { +if (flow->rule != meta) +rte_free (meta);return engine; + } + +if (flow->rule !=NULL && flow->rule != meta) +rte_free (flow->rule); +rte_free (meta); + flow->rule =NULL ; + meta =NULL ; }return NULL ; }
@@ -2120,8 +2135,10 @@ iavf_parse_engine_validate(struct iavf_adapter *ad,struct iavf_flow_parser_node *parser_node;void *temp;void *meta =NULL ; +int ret; RTE_TAILQ_FOREACH_SAFE(parser_node, parser_list, node, temp) { + meta =NULL ; if (parser_node->parser->parse_pattern_action(ad, parser_node->parser->array, parser_node->parser->array_len,
@@ -2130,13 +2147,18 @@ iavf_parse_engine_validate(struct iavf_adapter *ad, engine = parser_node->parser->engine;if (engine->validation ==NULL ) { +rte_free (meta); + meta =NULL ;rte_flow_error_set (error,EINVAL ,RTE_FLOW_ERROR_TYPE_HANDLE ,NULL ,"Validation not support" );continue ; } -if (engine->validation (ad, flow, meta, error)) { + ret = engine->validation (ad, flow, meta, error); +rte_free (meta); + meta =NULL ; +if (ret !=0 ) {rte_flow_error_set (error,EINVAL ,RTE_FLOW_ERROR_TYPE_HANDLE ,NULL ,"Validation failed" );
@@ -2238,7 +2260,7 @@ iavf_flow_create(struct rte_eth_dev *dev, &engine, iavf_parse_engine_create, error);if (ret <0 ) {PMD_DRV_LOG (ERR ,"Failed to create flow" ); -rte_free (flow); +iavf_flow_free (flow); flow =NULL ; goto free_flow; }
@@ -2308,7 +2330,7 @@ iavf_flow_destroy(struct rte_eth_dev *dev,if (!ret) {TAILQ_REMOVE (&vf->flow_list, flow, node); -rte_free (flow); +iavf_flow_free (flow); }else {PMD_DRV_LOG (ERR ,"Failed to destroy flow" ); }
drivers/net/intel/iavf/iavf_generic_flow.h +0 -2
@@ -465,7 +465,6 @@ typedef int (*engine_query_t)(struct iavf_adapter *ad,struct rte_flow *flow, struct rte_flow_query_count *count, struct rte_flow_error *error); -typedef void (*engine_free_t ) (struct rte_flow *flow); typedef int (*parse_pattern_action_t)(struct iavf_adapter *ad, struct iavf_pattern_match_item *array, uint32_t array_len,
@@ -494,7 +493,6 @@ struct iavf_flow_engine {engine_create_t create;engine_destroy_t destroy;engine_query_t query_count; -engine_free_t free;const char *name;enum iavf_flow_engine_type type;size_t rule_size;
drivers/net/intel/iavf/iavf_hash.c +31 -68
206 lines not on this page · raw message
drivers/net/intel/iavf/iavf_ipsec_crypto.c +0 -1
@@ -1919,7 +1919,6 @@ iavf_ipsec_flow_destroy(struct iavf_adapter *ad,iavf_ipsec_crypto_security_policy_delete (ad, ipsec_flow->is_ipv4, ipsec_flow->id); -rte_free (ipsec_flow);return 0 ; }
Signature · 1 line
2.52.0
PATCH v5 7/10 net/iavf: skip RSS teardown during PF-initiated reset
In reply to Anatoly BurakovDuring PF-initiated reset recovery, iavf_dev_close() skips flow flush to avoid sending virtchnl messages to the PF. However, iavf_hash_uninit() is still called unconditionally, even though any existing RSS configuration is now invalid because of PF-initiated reset.
Move the RSS teardown under the same pf_reset_in_progress check as flow flush, so that no RSS configuration messages are sent during PF-initiated reset recovery.
--- drivers/net/intel/iavf/iavf_ethdev.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
drivers/net/intel/iavf/iavf_ethdev.c +4 -4
@@ -3245,12 +3245,12 @@ iavf_dev_close(struct rte_eth_dev *dev)/* free iAVF security device context all related resources */ iavf_security_ctx_destroy (adapter); -/* remove RSS configuration */ -iavf_hash_uninit (adapter); -/* Skip the virtchnl-emitting teardown on a PF-initiated reset */ -if (!vf->pf_reset_in_progress) +if (!vf->pf_reset_in_progress) { +/* remove RSS configuration */ +iavf_hash_uninit (adapter);iavf_flow_flush (dev,NULL ); + }iavf_flow_uninit (adapter);/*
Signature · 1 line
2.52.0
PATCH v5 8/10 net/iavf: remove redundant reset checks from RSS engine
In reply to Anatoly BurakovThe RSS engine checks vf_reset during init, destroy and uninit to avoid sending virtchnl commands while the VF is resetting. These checks are no longer needed:
- iavf_hash_init() only registers the parser and sends no commands.
- iavf_dev_close() skips both flow flush and RSS teardown during PF-initiated reset recovery.
- the generic flow layer frees rule memory without relying on engine callbacks.
- iavf_execute_vf_cmd() already refuses to send commands while vf_reset is set.
Remove these checks as they are no longer needed.
--- drivers/net/intel/iavf/iavf_hash.c | 10 ---------- 1 file changed, 10 deletions(-)
drivers/net/intel/iavf/iavf_hash.c +0 -10
@@ -762,9 +762,6 @@ iavf_hash_init(struct iavf_adapter *ad)struct iavf_flow_parser *parser;int ret; -if (vf->vf_reset) -return -EIO ; -if (!vf->vf_res)return -EINVAL ;
@@ -1601,13 +1598,9 @@ iavf_hash_destroy(__rte_unused struct iavf_adapter *ad,struct rte_flow *flow, __rte_unused struct rte_flow_error *error) { - struct iavf_info *vf = IAVF_DEV_PRIVATE_TO_VF(ad); struct virtchnl_rss_cfg *rss_cfg;int ret =0 ; -if (vf->vf_reset) -return 0 ; - rss_cfg = (struct virtchnl_rss_cfg *)flow->rule; ret =iavf_add_del_rss_cfg (ad, rss_cfg, false);
@@ -1633,9 +1626,6 @@ iavf_hash_uninit(struct iavf_adapter *ad)struct iavf_info *vf =IAVF_DEV_PRIVATE_TO_VF (ad);struct rte_eth_rss_conf *rss_conf; -if (vf->vf_reset) -return ; -if (!vf->vf_res)return ;
Signature · 1 line
2.52.0
PATCH v5 9/10 net/iavf: fix null engine for egress security flows
In reply to Anatoly BurakovEgress security flows bypass the flow parsers and are inserted with a NULL engine pointer. The create path then dereferences that pointer when logging the new flow, and other engine-based operations cannot handle the flow consistently.
Register an egress security engine and route these flows through the normal parser and lifecycle callbacks. Egress flows own no rule and require no hardware teardown.
--- drivers/net/intel/iavf/iavf_generic_flow.c | 44 +++----- drivers/net/intel/iavf/iavf_generic_flow.h | 2 +- drivers/net/intel/iavf/iavf_ipsec_crypto.c | 120 +++++++++++++++++++-- 3 files changed, 123 insertions(+), 43 deletions(-)
drivers/net/intel/iavf/iavf_generic_flow.c +12 -32
@@ -1914,7 +1914,8 @@ iavf_register_parser(struct iavf_flow_parser *parser, } }TAILQ_INSERT_HEAD (list, parser_node, node); - }else if (parser->engine->type ==IAVF_FLOW_ENGINE_IPSEC_CRYPTO ) { + }else if (parser->engine->type ==IAVF_FLOW_ENGINE_IPSEC_CRYPTO || + parser->engine->type ==IAVF_FLOW_ENGINE_IPSEC_EGRESS ) { list = &vf->ipsec_crypto_parser_list;TAILQ_INSERT_HEAD (list, parser_node, node); }else if (parser->engine->type ==IAVF_FLOW_ENGINE_FSUB ) {
@@ -1943,7 +1944,8 @@ iavf_unregister_parser(struct iavf_flow_parser *parser,else if ((parser->engine->type ==IAVF_FLOW_ENGINE_FDIR ) || (parser->engine->type ==IAVF_FLOW_ENGINE_FSUB )) list = &vf->dist_parser_list; -else if (parser->engine->type ==IAVF_FLOW_ENGINE_IPSEC_CRYPTO ) +else if (parser->engine->type ==IAVF_FLOW_ENGINE_IPSEC_CRYPTO || + parser->engine->type ==IAVF_FLOW_ENGINE_IPSEC_EGRESS ) list = &vf->ipsec_crypto_parser_list;if (list ==NULL )
@@ -2250,12 +2252,6 @@ iavf_flow_create(struct rte_eth_dev *dev,return flow; } -/* Special case for inline crypto egress flows */ -if (attr->egress && actions[0 ].type ==RTE_FLOW_ACTION_TYPE_SECURITY ) { - flow->is_ipsec_egress_flow = true; - goto tailq_insert; - } - ret =iavf_flow_process_filter (dev, flow, attr, pattern, actions, &engine, iavf_parse_engine_create, error);if (ret <0 ) {
@@ -2266,7 +2262,6 @@ iavf_flow_create(struct rte_eth_dev *dev, } flow->engine = engine; -tailq_insert:rte_spinlock_lock (&vf->flow_ops_lock);TAILQ_INSERT_TAIL (&vf->flow_list, flow, node);rte_spinlock_unlock (&vf->flow_ops_lock);
@@ -2282,14 +2277,7 @@ iavf_flow_is_valid(struct rte_flow *flow)struct iavf_flow_engine *engine;void *temp; -if (flow ==NULL ) -return false; - -/* these flows don't use engines */ -if (flow->is_ipsec_egress_flow) -return true; - -if (flow->engine) { +if (flow !=NULL && flow->engine !=NULL ) { RTE_TAILQ_FOREACH_SAFE(engine, &engine_list, node, temp) {if (engine == flow->engine)return true;
@@ -2307,26 +2295,17 @@ iavf_flow_destroy(struct rte_eth_dev *dev,struct iavf_adapter *ad =IAVF_DEV_PRIVATE_TO_ADAPTER (dev->data->dev_private);struct iavf_info *vf =IAVF_DEV_PRIVATE_TO_VF (ad); -bool need_destroy;int ret =0 ; -if (!iavf_flow_is_valid (flow)) { +if (!iavf_flow_is_valid (flow) || flow->engine->destroy ==NULL ) {rte_flow_error_set (error,EINVAL ,RTE_FLOW_ERROR_TYPE_HANDLE ,NULL ,"Invalid flow destroy" );return -rte_errno; } - need_destroy = !flow->is_ipsec_egress_flow; - -if (need_destroy && flow->engine->destroy ==NULL ) { -return rte_flow_error_set (error,EINVAL , -RTE_FLOW_ERROR_TYPE_HANDLE ,NULL , -"Invalid flow destroy" ); - }rte_spinlock_lock (&vf->flow_ops_lock); -if (need_destroy) - ret = flow->engine->destroy (ad, flow, error); + ret = flow->engine->destroy (ad, flow, error);if (!ret) {TAILQ_REMOVE (&vf->flow_list, flow, node);
@@ -2444,16 +2423,17 @@ iavf_flow_dev_dump(struct rte_eth_dev *dev,if (flow !=NULL && f != flow)continue ; -/* this should not happen */ -if (f->engine ==NULL || f->rule ==NULL ) { +if (!iavf_flow_is_valid (f)) {PMD_DRV_LOG (DEBUG ,"Invalid flow" );continue ; } found = true; - rule_size = f->engine->rule_size; - rule_data = f->rule; +if (f->rule !=NULL ) { + rule_size = f->engine->rule_size; + rule_data = f->rule; + } iavf_flow_dump_blob(file, f->engine->name != NULL ?
drivers/net/intel/iavf/iavf_generic_flow.h +1 -1
@@ -481,6 +481,7 @@ enum iavf_flow_engine_type {IAVF_FLOW_ENGINE_FDIR ,IAVF_FLOW_ENGINE_HASH ,IAVF_FLOW_ENGINE_FSUB , +IAVF_FLOW_ENGINE_IPSEC_EGRESS , IAVF_FLOW_ENGINE_MAX, };
@@ -503,7 +504,6 @@ TAILQ_HEAD(iavf_engine_list, iavf_flow_engine);/* Struct to store flow created. */ struct rte_flow {TAILQ_ENTRY (rte_flow) node; -bool is_ipsec_egress_flow;struct iavf_flow_engine *engine;void *rule; };
drivers/net/intel/iavf/iavf_ipsec_crypto.c +110 -10
145 lines not on this page · raw message
Signature · 1 line
2.52.0
PATCH v5 10/10 net/iavf: fix IPsec flow metadata leaks
In reply to Anatoly BurakovIPsec flow parsing leaves the pattern-match item allocated after extracting its metadata. It also leaves the parsed flow item allocated when no metadata output is requested.
Free the pattern-match item after parsing and free the parsed flow item when it cannot be returned to the caller. Propagate pattern-match failure and report a parsing error when no flow item was produced.
--- drivers/net/intel/iavf/iavf_ipsec_crypto.c | 28 +++++++++++++++------- 1 file changed, 20 insertions(+), 8 deletions(-)
drivers/net/intel/iavf/iavf_ipsec_crypto.c +20 -8
@@ -1942,6 +1942,7 @@ iavf_ipsec_flow_parse(struct iavf_adapter *ad, .max_actions = 1, };struct iavf_pattern_match_item *item =NULL ; +struct iavf_ipsec_flow_item *fi =NULL ;int ret =-1 ; ret =ci_flow_check_attr (attr,NULL , error);
@@ -1953,17 +1954,28 @@ iavf_ipsec_flow_parse(struct iavf_adapter *ad,return ret; item =iavf_search_pattern_match_item (pattern, array, array_len, error); -if (item && item->meta) { +if (item ==NULL ) +return -rte_errno; + +if (item->meta !=NULL ) {const struct rte_security_session *session = parsed_actions.actions[0 ]->conf;uint32_t type = (uint64_t )(item->meta); -struct iavf_ipsec_flow_item *fi = -iavf_ipsec_flow_item_parse (ad, pattern, session, type); -if (fi && meta) { - *meta = fi; - ret =0 ; - } + + fi =iavf_ipsec_flow_item_parse (ad, pattern, session, type); } -return ret; +rte_free (item); + +if (fi ==NULL ) +return rte_flow_error_set (error,EINVAL , +RTE_FLOW_ERROR_TYPE_ACTION ,NULL , +"Invalid IPsec flow." ); + +if (meta !=NULL ) + *meta = fi; +else +rte_free (fi); + +return 0 ; }/*
Signature · 1 line
2.52.0
Re: [PATCH v5 04/10] net/iavf: fix memory leaks around IRQ resources
In reply to Anatoly BurakovQuoted 8 lines · Anatoly Burakov
iavf_config_rx_queues_irqs()allocates a queue-vector map and may enable eventfds and allocate an interrupt vector list. If queue startup then fails, those resources remain allocated. The queue-vector map is also retained after a normal stop, leaking it across start/stop cycles.Release the resources on failed startup and free the queue-vector map on stop.
Quoted 8 lines
Fixes f593944fc988 ("net/iavf: enable IRQ mapping configuration for large VF")Signed-off-by Anatoly Burakov <[email protected]>--- drivers/net/intel/iavf/iavf_ethdev.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-)
Quoted 5 lines · Anatoly Burakov
An assortment of IAVF flow-related memory leak fixes and cleanups.
v4 -> v5:
- Dropped the unnecessary EFD disable from patch 4
Series applied to dpdk-next-net-intel.
Thanks,
/Bruce