[PATCH] net/ixgbe: fix leak of filters on flow create

Bruce Richardson bruce.richardson at intel.com
Fri Sep 18 13:40:10 CEST 2026


On Mon, Sep 14, 2026 at 09:38:36PM +0800, Zhang Tengfei wrote:
> ixgbe_flow_create() programs ntuple, ethertype, SYN, FDIR, L2 tunnel and
> RSS filters into hardware before allocating the software flow object.
> If that allocation fails, create returns an error but leaves the
> hardware filter installed. The application has no handle to destroy it.
> 
> Allocate the software copy first, then program the hardware. On a
> programming failure, free the copy. Set ENOMEM when allocation fails
> so the error path does not report success.
> 
> L2 tunnel add failures now return immediately instead of falling
> through to RSS parsing, which cannot succeed for a VF/PF E-tag rule
> and overwrote the original error.
> 
> Fixes: 72c135a89f80 ("net/ixgbe: create consistent filter")
> Cc: stable at dpdk.org
> 
> Signed-off-by: Zhang Tengfei <zhtfdev at gmail.com>
> ---
Acked-by: Bruce Richardson <bruce.richardson at intel.com>

This patch needs rebase though. The memcpy calls in the driver have been
replaced by struct assignments. Will try updating on apply.

>  drivers/net/intel/ixgbe/ixgbe_flow.c | 164 +++++++++++++++------------
>  1 file changed, 90 insertions(+), 74 deletions(-)
> 
> diff --git a/drivers/net/intel/ixgbe/ixgbe_flow.c b/drivers/net/intel/ixgbe/ixgbe_flow.c
> index 6868893d46..e572a1f21a 100644
> --- a/drivers/net/intel/ixgbe/ixgbe_flow.c
> +++ b/drivers/net/intel/ixgbe/ixgbe_flow.c
> @@ -2858,68 +2858,73 @@ ixgbe_flow_create(struct rte_eth_dev *dev,
>  			actions, &ntuple_filter, error);
>  
>  	if (!ret) {
> +		ntuple_filter_ptr = rte_zmalloc("ixgbe_ntuple_filter",
> +			sizeof(struct ixgbe_ntuple_filter_ele), 0);
> +		if (!ntuple_filter_ptr) {
> +			PMD_DRV_LOG(ERR, "failed to allocate memory");
> +			ret = -ENOMEM;
> +			goto out;
> +		}
> +		memcpy(&ntuple_filter_ptr->filter_info,
> +			&ntuple_filter,
> +			sizeof(struct rte_eth_ntuple_filter));
>  		ret = ixgbe_add_del_ntuple_filter(adapter, &ntuple_filter, TRUE);
> -		if (!ret) {
> -			ntuple_filter_ptr = rte_zmalloc("ixgbe_ntuple_filter",
> -				sizeof(struct ixgbe_ntuple_filter_ele), 0);
> -			if (!ntuple_filter_ptr) {
> -				PMD_DRV_LOG(ERR, "failed to allocate memory");
> -				goto out;
> -			}
> -			memcpy(&ntuple_filter_ptr->filter_info,
> -				&ntuple_filter,
> -				sizeof(struct rte_eth_ntuple_filter));
> -			flow->rule = ntuple_filter_ptr;
> -			flow->filter_type = RTE_ETH_FILTER_NTUPLE;
> -			return flow;
> +		if (ret) {
> +			rte_free(ntuple_filter_ptr);
> +			goto out;
>  		}
> -		goto out;
> +		flow->rule = ntuple_filter_ptr;
> +		flow->filter_type = RTE_ETH_FILTER_NTUPLE;
> +		return flow;
>  	}
>  
>  	memset(&ethertype_filter, 0, sizeof(struct rte_eth_ethertype_filter));
>  	ret = ixgbe_parse_ethertype_filter(dev, attr, pattern,
>  				actions, &ethertype_filter, error);
>  	if (!ret) {
> +		ethertype_filter_ptr = rte_zmalloc("ixgbe_ethertype_filter",
> +			sizeof(struct ixgbe_ethertype_filter_ele), 0);
> +		if (!ethertype_filter_ptr) {
> +			PMD_DRV_LOG(ERR, "failed to allocate memory");
> +			ret = -ENOMEM;
> +			goto out;
> +		}
> +		memcpy(&ethertype_filter_ptr->filter_info,
> +			&ethertype_filter,
> +			sizeof(struct rte_eth_ethertype_filter));
>  		ret = ixgbe_add_del_ethertype_filter(adapter,
>  				&ethertype_filter, TRUE);
> -		if (!ret) {
> -			ethertype_filter_ptr = rte_zmalloc(
> -				"ixgbe_ethertype_filter",
> -				sizeof(struct ixgbe_ethertype_filter_ele), 0);
> -			if (!ethertype_filter_ptr) {
> -				PMD_DRV_LOG(ERR, "failed to allocate memory");
> -				goto out;
> -			}
> -			memcpy(&ethertype_filter_ptr->filter_info,
> -				&ethertype_filter,
> -				sizeof(struct rte_eth_ethertype_filter));
> -			flow->rule = ethertype_filter_ptr;
> -			flow->filter_type = RTE_ETH_FILTER_ETHERTYPE;
> -			return flow;
> +		if (ret) {
> +			rte_free(ethertype_filter_ptr);
> +			goto out;
>  		}
> -		goto out;
> +		flow->rule = ethertype_filter_ptr;
> +		flow->filter_type = RTE_ETH_FILTER_ETHERTYPE;
> +		return flow;
>  	}
>  
>  	memset(&syn_filter, 0, sizeof(struct rte_eth_syn_filter));
>  	ret = ixgbe_parse_syn_filter(dev, attr, pattern,
>  				actions, &syn_filter, error);
>  	if (!ret) {
> +		syn_filter_ptr = rte_zmalloc("ixgbe_syn_filter",
> +			sizeof(struct ixgbe_eth_syn_filter_ele), 0);
> +		if (!syn_filter_ptr) {
> +			PMD_DRV_LOG(ERR, "failed to allocate memory");
> +			ret = -ENOMEM;
> +			goto out;
> +		}
> +		memcpy(&syn_filter_ptr->filter_info,
> +			&syn_filter,
> +			sizeof(struct rte_eth_syn_filter));
>  		ret = ixgbe_syn_filter_set(adapter, &syn_filter, TRUE);
> -		if (!ret) {
> -			syn_filter_ptr = rte_zmalloc("ixgbe_syn_filter",
> -				sizeof(struct ixgbe_eth_syn_filter_ele), 0);
> -			if (!syn_filter_ptr) {
> -				PMD_DRV_LOG(ERR, "failed to allocate memory");
> -				goto out;
> -			}
> -			memcpy(&syn_filter_ptr->filter_info,
> -				&syn_filter,
> -				sizeof(struct rte_eth_syn_filter));
> -			flow->rule = syn_filter_ptr;
> -			flow->filter_type = RTE_ETH_FILTER_SYN;
> -			return flow;
> +		if (ret) {
> +			rte_free(syn_filter_ptr);
> +			goto out;
>  		}
> -		goto out;
> +		flow->rule = syn_filter_ptr;
> +		flow->filter_type = RTE_ETH_FILTER_SYN;
> +		return flow;
>  	}
>  
>  	memset(&fdir_rule, 0, sizeof(struct ixgbe_fdir_rule));
> @@ -2929,17 +2934,21 @@ ixgbe_flow_create(struct rte_eth_dev *dev,
>  		struct rte_eth_fdir_conf *fdir_conf = IXGBE_DEV_FDIR_CONF(dev);
>  		bool first_mask = false;
>  
> -		ret = ixgbe_fdir_flow_program(dev, adapter, &fdir_rule,
> -			&first_mask, error);
> -		if (ret)
> -			goto out;
> -
>  		fdir_rule_ptr = rte_zmalloc("ixgbe_fdir_filter",
>  				sizeof(struct ixgbe_fdir_rule_ele), 0);
>  		if (!fdir_rule_ptr) {
>  			PMD_DRV_LOG(ERR, "failed to allocate memory");
> +			ret = -ENOMEM;
> +			goto out;
> +		}
> +
> +		ret = ixgbe_fdir_flow_program(dev, adapter, &fdir_rule,
> +			&first_mask, error);
> +		if (ret) {
> +			rte_free(fdir_rule_ptr);
>  			goto out;
>  		}
> +
>  		/* update global state */
>  		if (first_mask) {
>  			fdir_info->mask_added = TRUE;
> @@ -2961,41 +2970,48 @@ ixgbe_flow_create(struct rte_eth_dev *dev,
>  	ret = ixgbe_parse_l2_tn_filter(dev, attr, pattern,
>  					actions, &l2_tn_filter, error);
>  	if (!ret) {
> -		ret = ixgbe_dev_l2_tunnel_filter_add(adapter, &l2_tn_filter, FALSE);
> -		if (!ret) {
> -			l2_tn_filter_ptr = rte_zmalloc("ixgbe_l2_tn_filter",
> -				sizeof(struct ixgbe_eth_l2_tunnel_conf_ele), 0);
> -			if (!l2_tn_filter_ptr) {
> -				PMD_DRV_LOG(ERR, "failed to allocate memory");
> -				goto out;
> -			}
> -			memcpy(&l2_tn_filter_ptr->filter_info,
> -				&l2_tn_filter,
> -				sizeof(struct ixgbe_l2_tunnel_conf));
> -			flow->rule = l2_tn_filter_ptr;
> -			flow->filter_type = RTE_ETH_FILTER_L2_TUNNEL;
> -			return flow;
> +		l2_tn_filter_ptr = rte_zmalloc("ixgbe_l2_tn_filter",
> +			sizeof(struct ixgbe_eth_l2_tunnel_conf_ele), 0);
> +		if (!l2_tn_filter_ptr) {
> +			PMD_DRV_LOG(ERR, "failed to allocate memory");
> +			ret = -ENOMEM;
> +			goto out;
>  		}
> +		memcpy(&l2_tn_filter_ptr->filter_info,
> +			&l2_tn_filter,
> +			sizeof(struct ixgbe_l2_tunnel_conf));
> +		ret = ixgbe_dev_l2_tunnel_filter_add(adapter, &l2_tn_filter,
> +						     FALSE);
> +		if (ret) {
> +			rte_free(l2_tn_filter_ptr);
> +			goto out;
> +		}
> +		flow->rule = l2_tn_filter_ptr;
> +		flow->filter_type = RTE_ETH_FILTER_L2_TUNNEL;
> +		return flow;
>  	}
>  
>  	memset(&rss_conf, 0, sizeof(struct ixgbe_rte_flow_rss_conf));
>  	ret = ixgbe_parse_rss_filter(dev, attr,
>  					actions, &rss_conf, error);
>  	if (!ret) {
> +		rss_filter_ptr = rte_zmalloc("ixgbe_rss_filter",
> +			sizeof(struct ixgbe_rss_conf_ele), 0);
> +		if (!rss_filter_ptr) {
> +			PMD_DRV_LOG(ERR, "failed to allocate memory");
> +			ret = -ENOMEM;
> +			goto out;
> +		}
>  		ret = ixgbe_config_rss_filter(adapter, &rss_conf, TRUE);
> -		if (!ret) {
> -			rss_filter_ptr = rte_zmalloc("ixgbe_rss_filter",
> -				sizeof(struct ixgbe_rss_conf_ele), 0);
> -			if (!rss_filter_ptr) {
> -				PMD_DRV_LOG(ERR, "failed to allocate memory");
> -				goto out;
> -			}
> -			ixgbe_rss_conf_init(&rss_filter_ptr->filter_info,
> -					    &rss_conf.conf);
> -			flow->rule = rss_filter_ptr;
> -			flow->filter_type = RTE_ETH_FILTER_HASH;
> -			return flow;
> +		if (ret) {
> +			rte_free(rss_filter_ptr);
> +			goto out;
>  		}
> +		ixgbe_rss_conf_init(&rss_filter_ptr->filter_info,
> +				    &rss_conf.conf);
> +		flow->rule = rss_filter_ptr;
> +		flow->filter_type = RTE_ETH_FILTER_HASH;
> +		return flow;
>  	}
>  
>  out:
> -- 
> 2.55.0
> 


More information about the stable mailing list