[Intel-wired-lan] [next-queue PATCH v2 8/8] igb: Add support for adding offloaded clsflower filters

Jakub Kicinski kubakici at wp.pl
Mon Mar 5 21:13:50 UTC 2018


On Fri,  2 Mar 2018 10:43:44 -0800, Vinicius Costa Gomes wrote:
> This allows filters added by tc-flower and specifying MAC addresses,
> Ethernet types, and the VLAN priority field, to be offloaded to the
> controller.
> 
> This reuses most of the infrastructure used by ethtool, ethtool can be
> used to read these filters, but modification and deletion can only be
> done via tc-flower.
> 
> Signed-off-by: Vinicius Costa Gomes <vinicius.gomes at intel.com>
> ---
>  drivers/net/ethernet/intel/igb/igb.h      |   2 +
>  drivers/net/ethernet/intel/igb/igb_main.c | 176 +++++++++++++++++++++++++++++-
>  2 files changed, 176 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/net/ethernet/intel/igb/igb.h b/drivers/net/ethernet/intel/igb/igb.h
> index 43ce6d64f693..0edd3a74d043 100644
> --- a/drivers/net/ethernet/intel/igb/igb.h
> +++ b/drivers/net/ethernet/intel/igb/igb.h
> @@ -463,6 +463,7 @@ struct igb_nfc_input {
>  struct igb_nfc_filter {
>  	struct hlist_node nfc_node;
>  	struct igb_nfc_input filter;
> +	unsigned long cookie;
>  	u16 etype_reg_index;
>  	u16 sw_idx;
>  	u16 action;
> @@ -601,6 +602,7 @@ struct igb_adapter {
>  
>  	/* RX network flow classification support */
>  	struct hlist_head nfc_filter_list;
> +	struct hlist_head cls_flower_list;
>  	unsigned int nfc_filter_count;
>  	/* lock for RX network flow classification filter */
>  	spinlock_t nfc_lock;
> diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c
> index b5a6bd37bb16..cbd2048b9110 100644
> --- a/drivers/net/ethernet/intel/igb/igb_main.c
> +++ b/drivers/net/ethernet/intel/igb/igb_main.c
> @@ -2397,6 +2397,12 @@ static int igb_set_features(struct net_device *netdev,
>  			hlist_del(&rule->nfc_node);
>  			kfree(rule);
>  		}
> +		hlist_for_each_entry_safe(rule, node2,
> +					  &adapter->cls_flower_list, nfc_node) {
> +			igb_erase_filter(adapter, rule);
> +			hlist_del(&rule->nfc_node);
> +			kfree(rule);
> +		}

Hm.  I don't think you should flush cls filters when someone disables
NTUPLE.  (a) ntuple is independent, (b) the in_hw flag will no longer
reflect the actual state of the system.

>  		spin_unlock(&adapter->nfc_lock);
>  		adapter->nfc_filter_count = 0;
>  	}
> @@ -2497,16 +2503,179 @@ static int igb_offload_cbs(struct igb_adapter *adapter,
>  	return 0;
>  }
>  
> +#define ETHER_TYPE_FULL_MASK ((__force __be16)~0)
> +
> +static int igb_parse_cls_flower(struct igb_adapter *adapter,
> +				struct tc_cls_flower_offload *f,
> +				int traffic_class,
> +				struct igb_nfc_filter *input)
> +{
> +	if (f->dissector->used_keys &
> +	    ~(BIT(FLOW_DISSECTOR_KEY_BASIC) |
> +	      BIT(FLOW_DISSECTOR_KEY_CONTROL) |
> +	      BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
> +	      BIT(FLOW_DISSECTOR_KEY_VLAN))) {
> +		dev_err(&adapter->pdev->dev, "Unsupported key used: 0x%x\n",
> +			f->dissector->used_keys);

This will probably trigger for opportunistic offload (non-skip_sw) and
confuse users.

> +		return -EOPNOTSUPP;
> +	}
> +
> +	if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_ETH_ADDRS)) {
> +		struct flow_dissector_key_eth_addrs *key =
> +			skb_flow_dissector_target(f->dissector,
> +						  FLOW_DISSECTOR_KEY_ETH_ADDRS,
> +						  f->key);
> +
> +		struct flow_dissector_key_eth_addrs *mask =
> +			skb_flow_dissector_target(f->dissector,
> +						  FLOW_DISSECTOR_KEY_ETH_ADDRS,
> +						  f->mask);

You can do the assignment on separate lines to avoid strange variable
declaration.

> +		if (is_broadcast_ether_addr(mask->dst)) {
> +			input->filter.match_flags |=
> +				IGB_FILTER_FLAG_DST_MAC_ADDR;
> +			ether_addr_copy(input->filter.dst_addr, key->dst);
> +		}
> +
> +		if (is_broadcast_ether_addr(mask->src)) {
> +			input->filter.match_flags |=
> +				IGB_FILTER_FLAG_SRC_MAC_ADDR;
> +			ether_addr_copy(input->filter.src_addr, key->src);
> +		}

If the mask is not full you need to reject the filter, I don't think
you can just ignore the MAC if it's masked..

Same two comments for conditions below.

> +	}
> +
> +	if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_BASIC)) {
> +		struct flow_dissector_key_basic *key =
> +			skb_flow_dissector_target(f->dissector,
> +						  FLOW_DISSECTOR_KEY_BASIC,
> +						  f->key);
> +
> +		struct flow_dissector_key_basic *mask =
> +			skb_flow_dissector_target(f->dissector,
> +						  FLOW_DISSECTOR_KEY_BASIC,
> +						  f->mask);
> +
> +		if (mask->n_proto == ETHER_TYPE_FULL_MASK) {
> +			input->filter.match_flags |=
> +				IGB_FILTER_FLAG_ETHER_TYPE;
> +			input->filter.etype = key->n_proto;
> +		}
> +	}
> +
> +	if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_VLAN)) {
> +		struct flow_dissector_key_vlan *key =
> +			skb_flow_dissector_target(f->dissector,
> +						  FLOW_DISSECTOR_KEY_VLAN,
> +						  f->key);
> +		struct flow_dissector_key_vlan *mask =
> +			skb_flow_dissector_target(f->dissector,
> +						  FLOW_DISSECTOR_KEY_VLAN,
> +						  f->mask);
> +
> +		if (mask->vlan_priority) {
> +			input->filter.match_flags |= IGB_FILTER_FLAG_VLAN_TCI;
> +			input->filter.vlan_tci = key->vlan_priority;
> +		}
> +	}
> +
> +	input->action = traffic_class;
> +	input->cookie = f->cookie;
> +
> +	return 0;
> +}
> +
>  static int igb_configure_clsflower(struct igb_adapter *adapter,
>  				   struct tc_cls_flower_offload *cls_flower)
>  {
> -	return -EOPNOTSUPP;
> +	struct igb_nfc_filter *filter, *f;
> +	int err, tc;
> +
> +	if (!(adapter->netdev->hw_features & NETIF_F_NTUPLE))
> +		return -EOPNOTSUPP;

I'd rather there wasn't dependency on NTUPLEs for cls offloads.

> +	tc = tc_classid_to_hwtc(adapter->netdev, cls_flower->classid);
> +	if (tc < 0) {
> +		dev_err(&adapter->pdev->dev, "Invalid traffic class\n");
> +		return -EINVAL;
> +	}
> +
> +	filter = kzalloc(sizeof(*filter), GFP_KERNEL);
> +	if (!filter)
> +		return -ENOMEM;
> +
> +	err = igb_parse_cls_flower(adapter, cls_flower, tc, filter);
> +	if (err < 0) {
> +		dev_err(&adapter->pdev->dev, "Invalid cls_flower filter\n");
> +		goto err_parse;
> +	}
> +
> +	spin_lock(&adapter->nfc_lock);
> +
> +	hlist_for_each_entry(f, &adapter->nfc_filter_list, nfc_node) {
> +		if (!memcmp(&f->filter, &filter->filter, sizeof(f->filter))) {
> +			err = -EEXIST;
> +			dev_err(&adapter->pdev->dev,
> +				"This filter is already set in ethtool\n");

Consider using extack too, maybe?

> +			goto err_locked;
> +		}
> +	}
> +
> +	hlist_for_each_entry(f, &adapter->cls_flower_list, nfc_node) {
> +		if (!memcmp(&f->filter, &filter->filter, sizeof(f->filter))) {
> +			err = -EEXIST;
> +			dev_err(&adapter->pdev->dev,
> +				"This filter is already set in cls_flower\n");
> +			goto err_locked;
> +		}
> +	}
> +
> +	err = igb_add_filter(adapter, filter);
> +	if (err < 0)
> +		goto err_locked;
> +
> +	hlist_add_head(&filter->nfc_node, &adapter->cls_flower_list);
> +
> +	spin_unlock(&adapter->nfc_lock);
> +
> +	return 0;
> +
> +err_locked:
> +	spin_unlock(&adapter->nfc_lock);
> +
> +err_parse:
> +	kfree(filter);
> +
> +	return err;
>  }



More information about the Intel-wired-lan mailing list