Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 487884eb authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'mlx5-ntuple-steering'



Saeed Mahameed says:

====================
Mellanox 100G mlx5 ethtool ntuple steering

This series adds Ethernet ethtool ntuple steering 'ethtool -N|U' and exposes two more
counter sets to Ethtool statistics, RDMA vport and global flow control statistics.

We start from three refactoring patches of the flow steering infrastructure
    - mlx5_add_flow_rule will now receive mlx5 flow spec to simplify and reduce
      number of parameters
    - All low level steering objects are now wrapped in mlx5_flow_steering structure
      for better encapsulation
    - Flow steering object will now be removed properly and generically rather than
      traversing on a well-known steering tree objects

Patch#4 adds the infrastructure and the data structures needed for the ethtool ntuple
steering, all implemented in a new file 'en_fs_ethtool.c'.  Add the support for set_rxnfc
ethtool callback to add/remove/replace a flow spec of ethter type L2.

Patch#5 adds the support for L3/L4 flow specs and a higher priority in favor for L3/L4
rules when interleaving with L2 rules.

Patch#6 adds the support for get_rxnfc ethtool callback.

Patch#7,8 adds RDMA vport and global flow control statistics.

Applied on top: 8186f6e3 ('net-next: mediatek: fix compile error inside mtk_poll_controller()')
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 019d0c99 e989d5a5
Loading
Loading
Loading
Loading
+9 −12
Original line number Diff line number Diff line
@@ -1528,21 +1528,18 @@ static struct mlx5_ib_flow_handler *create_flow_rule(struct mlx5_ib_dev *dev,
{
	struct mlx5_flow_table	*ft = ft_prio->flow_table;
	struct mlx5_ib_flow_handler *handler;
	struct mlx5_flow_spec *spec;
	void *ib_flow = flow_attr + 1;
	u8 match_criteria_enable = 0;
	unsigned int spec_index;
	u32 *match_c;
	u32 *match_v;
	u32 action;
	int err = 0;

	if (!is_valid_attr(flow_attr))
		return ERR_PTR(-EINVAL);

	match_c = kzalloc(MLX5_ST_SZ_BYTES(fte_match_param), GFP_KERNEL);
	match_v = kzalloc(MLX5_ST_SZ_BYTES(fte_match_param), GFP_KERNEL);
	spec = mlx5_vzalloc(sizeof(*spec));
	handler = kzalloc(sizeof(*handler), GFP_KERNEL);
	if (!handler || !match_c || !match_v) {
	if (!handler || !spec) {
		err = -ENOMEM;
		goto free;
	}
@@ -1550,7 +1547,8 @@ static struct mlx5_ib_flow_handler *create_flow_rule(struct mlx5_ib_dev *dev,
	INIT_LIST_HEAD(&handler->list);

	for (spec_index = 0; spec_index < flow_attr->num_of_specs; spec_index++) {
		err = parse_flow_attr(match_c, match_v, ib_flow);
		err = parse_flow_attr(spec->match_criteria,
				      spec->match_value, ib_flow);
		if (err < 0)
			goto free;

@@ -1558,11 +1556,11 @@ static struct mlx5_ib_flow_handler *create_flow_rule(struct mlx5_ib_dev *dev,
	}

	/* Outer header support only */
	match_criteria_enable = (!outer_header_zero(match_c)) << 0;
	spec->match_criteria_enable = (!outer_header_zero(spec->match_criteria))
		<< 0;
	action = dst ? MLX5_FLOW_CONTEXT_ACTION_FWD_DEST :
		MLX5_FLOW_CONTEXT_ACTION_FWD_NEXT_PRIO;
	handler->rule = mlx5_add_flow_rule(ft, match_criteria_enable,
					   match_c, match_v,
	handler->rule = mlx5_add_flow_rule(ft, spec,
					   action,
					   MLX5_FS_DEFAULT_FLOW_TAG,
					   dst);
@@ -1578,8 +1576,7 @@ static struct mlx5_ib_flow_handler *create_flow_rule(struct mlx5_ib_dev *dev,
free:
	if (err)
		kfree(handler);
	kfree(match_c);
	kfree(match_v);
	kvfree(spec);
	return err ? ERR_PTR(err) : handler;
}

+1 −1
Original line number Diff line number Diff line
@@ -8,6 +8,6 @@ mlx5_core-y := main.o cmd.o debugfs.o fw.o eq.o uar.o pagealloc.o \
mlx5_core-$(CONFIG_MLX5_CORE_EN) += wq.o eswitch.o eswitch_offloads.o \
		en_main.o en_common.o en_fs.o en_ethtool.o en_tx.o \
		en_rx.o en_rx_am.o en_txrx.o en_clock.o vxlan.o \
		en_tc.o en_arfs.o en_rep.o
		en_tc.o en_arfs.o en_rep.o en_fs_ethtool.o

mlx5_core-$(CONFIG_MLX5_CORE_EN_DCB) +=  en_dcbnl.o
+26 −0
Original line number Diff line number Diff line
@@ -544,8 +544,24 @@ enum {
	MLX5E_ARFS_FT_LEVEL
};

struct mlx5e_ethtool_table {
	struct mlx5_flow_table *ft;
	int                    num_rules;
};

#define ETHTOOL_NUM_L3_L4_FTS 7
#define ETHTOOL_NUM_L2_FTS 4

struct mlx5e_ethtool_steering {
	struct mlx5e_ethtool_table      l3_l4_ft[ETHTOOL_NUM_L3_L4_FTS];
	struct mlx5e_ethtool_table      l2_ft[ETHTOOL_NUM_L2_FTS];
	struct list_head                rules;
	int                             tot_num_rules;
};

struct mlx5e_flow_steering {
	struct mlx5_flow_namespace      *ns;
	struct mlx5e_ethtool_steering   ethtool;
	struct mlx5e_tc_table           tc;
	struct mlx5e_vlan_table         vlan;
	struct mlx5e_l2_table           l2;
@@ -701,6 +717,16 @@ int mlx5e_create_flow_steering(struct mlx5e_priv *priv);
void mlx5e_destroy_flow_steering(struct mlx5e_priv *priv);
void mlx5e_init_l2_addr(struct mlx5e_priv *priv);
void mlx5e_destroy_flow_table(struct mlx5e_flow_table *ft);
int mlx5e_ethtool_get_flow(struct mlx5e_priv *priv, struct ethtool_rxnfc *info,
			   int location);
int mlx5e_ethtool_get_all_flows(struct mlx5e_priv *priv,
				struct ethtool_rxnfc *info, u32 *rule_locs);
int mlx5e_ethtool_flow_replace(struct mlx5e_priv *priv,
			       struct ethtool_rx_flow_spec *fs);
int mlx5e_ethtool_flow_remove(struct mlx5e_priv *priv,
			      int location);
void mlx5e_ethtool_init_steering(struct mlx5e_priv *priv);
void mlx5e_ethtool_cleanup_steering(struct mlx5e_priv *priv);
void mlx5e_set_rx_mode_work(struct work_struct *work);

void mlx5e_fill_hwstamp(struct mlx5e_tstamp *clock, u64 timestamp,
+29 −39
Original line number Diff line number Diff line
@@ -175,15 +175,12 @@ static int arfs_add_default_rule(struct mlx5e_priv *priv,
{
	struct arfs_table *arfs_t = &priv->fs.arfs.arfs_tables[type];
	struct mlx5_flow_destination dest;
	u8 match_criteria_enable = 0;
	struct mlx5e_tir *tir = priv->indir_tir;
	u32 *match_criteria;
	u32 *match_value;
	struct mlx5_flow_spec *spec;
	int err = 0;

	match_value	= mlx5_vzalloc(MLX5_ST_SZ_BYTES(fte_match_param));
	match_criteria	= mlx5_vzalloc(MLX5_ST_SZ_BYTES(fte_match_param));
	if (!match_value || !match_criteria) {
	spec = mlx5_vzalloc(sizeof(*spec));
	if (!spec) {
		netdev_err(priv->netdev, "%s: alloc failed\n", __func__);
		err = -ENOMEM;
		goto out;
@@ -208,8 +205,7 @@ static int arfs_add_default_rule(struct mlx5e_priv *priv,
		goto out;
	}

	arfs_t->default_rule = mlx5_add_flow_rule(arfs_t->ft.t, match_criteria_enable,
						  match_criteria, match_value,
	arfs_t->default_rule = mlx5_add_flow_rule(arfs_t->ft.t, spec,
						  MLX5_FLOW_CONTEXT_ACTION_FWD_DEST,
						  MLX5_FS_DEFAULT_FLOW_TAG,
						  &dest);
@@ -220,8 +216,7 @@ static int arfs_add_default_rule(struct mlx5e_priv *priv,
			   __func__, type);
	}
out:
	kvfree(match_criteria);
	kvfree(match_value);
	kvfree(spec);
	return err;
}

@@ -475,23 +470,20 @@ static struct mlx5_flow_rule *arfs_add_rule(struct mlx5e_priv *priv,
	struct mlx5_flow_rule *rule = NULL;
	struct mlx5_flow_destination dest;
	struct arfs_table *arfs_table;
	u8 match_criteria_enable = 0;
	struct mlx5_flow_spec *spec;
	struct mlx5_flow_table *ft;
	u32 *match_criteria;
	u32 *match_value;
	int err = 0;

	match_value	= mlx5_vzalloc(MLX5_ST_SZ_BYTES(fte_match_param));
	match_criteria	= mlx5_vzalloc(MLX5_ST_SZ_BYTES(fte_match_param));
	if (!match_value || !match_criteria) {
	spec = mlx5_vzalloc(sizeof(*spec));
	if (!spec) {
		netdev_err(priv->netdev, "%s: alloc failed\n", __func__);
		err = -ENOMEM;
		goto out;
	}
	match_criteria_enable = MLX5_MATCH_OUTER_HEADERS;
	MLX5_SET_TO_ONES(fte_match_param, match_criteria,
	spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS;
	MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria,
			 outer_headers.ethertype);
	MLX5_SET(fte_match_param, match_value, outer_headers.ethertype,
	MLX5_SET(fte_match_param, spec->match_value, outer_headers.ethertype,
		 ntohs(tuple->etype));
	arfs_table = arfs_get_table(arfs, tuple->ip_proto, tuple->etype);
	if (!arfs_table) {
@@ -501,59 +493,58 @@ static struct mlx5_flow_rule *arfs_add_rule(struct mlx5e_priv *priv,

	ft = arfs_table->ft.t;
	if (tuple->ip_proto == IPPROTO_TCP) {
		MLX5_SET_TO_ONES(fte_match_param, match_criteria,
		MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria,
				 outer_headers.tcp_dport);
		MLX5_SET_TO_ONES(fte_match_param, match_criteria,
		MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria,
				 outer_headers.tcp_sport);
		MLX5_SET(fte_match_param, match_value, outer_headers.tcp_dport,
		MLX5_SET(fte_match_param, spec->match_value, outer_headers.tcp_dport,
			 ntohs(tuple->dst_port));
		MLX5_SET(fte_match_param, match_value, outer_headers.tcp_sport,
		MLX5_SET(fte_match_param, spec->match_value, outer_headers.tcp_sport,
			 ntohs(tuple->src_port));
	} else {
		MLX5_SET_TO_ONES(fte_match_param, match_criteria,
		MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria,
				 outer_headers.udp_dport);
		MLX5_SET_TO_ONES(fte_match_param, match_criteria,
		MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria,
				 outer_headers.udp_sport);
		MLX5_SET(fte_match_param, match_value, outer_headers.udp_dport,
		MLX5_SET(fte_match_param, spec->match_value, outer_headers.udp_dport,
			 ntohs(tuple->dst_port));
		MLX5_SET(fte_match_param, match_value, outer_headers.udp_sport,
		MLX5_SET(fte_match_param, spec->match_value, outer_headers.udp_sport,
			 ntohs(tuple->src_port));
	}
	if (tuple->etype == htons(ETH_P_IP)) {
		memcpy(MLX5_ADDR_OF(fte_match_param, match_value,
		memcpy(MLX5_ADDR_OF(fte_match_param, spec->match_value,
				    outer_headers.src_ipv4_src_ipv6.ipv4_layout.ipv4),
		       &tuple->src_ipv4,
		       4);
		memcpy(MLX5_ADDR_OF(fte_match_param, match_value,
		memcpy(MLX5_ADDR_OF(fte_match_param, spec->match_value,
				    outer_headers.dst_ipv4_dst_ipv6.ipv4_layout.ipv4),
		       &tuple->dst_ipv4,
		       4);
		MLX5_SET_TO_ONES(fte_match_param, match_criteria,
		MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria,
				 outer_headers.src_ipv4_src_ipv6.ipv4_layout.ipv4);
		MLX5_SET_TO_ONES(fte_match_param, match_criteria,
		MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria,
				 outer_headers.dst_ipv4_dst_ipv6.ipv4_layout.ipv4);
	} else {
		memcpy(MLX5_ADDR_OF(fte_match_param, match_value,
		memcpy(MLX5_ADDR_OF(fte_match_param, spec->match_value,
				    outer_headers.src_ipv4_src_ipv6.ipv6_layout.ipv6),
		       &tuple->src_ipv6,
		       16);
		memcpy(MLX5_ADDR_OF(fte_match_param, match_value,
		memcpy(MLX5_ADDR_OF(fte_match_param, spec->match_value,
				    outer_headers.dst_ipv4_dst_ipv6.ipv6_layout.ipv6),
		       &tuple->dst_ipv6,
		       16);
		memset(MLX5_ADDR_OF(fte_match_param, match_criteria,
		memset(MLX5_ADDR_OF(fte_match_param, spec->match_criteria,
				    outer_headers.src_ipv4_src_ipv6.ipv6_layout.ipv6),
		       0xff,
		       16);
		memset(MLX5_ADDR_OF(fte_match_param, match_criteria,
		memset(MLX5_ADDR_OF(fte_match_param, spec->match_criteria,
				    outer_headers.dst_ipv4_dst_ipv6.ipv6_layout.ipv6),
		       0xff,
		       16);
	}
	dest.type = MLX5_FLOW_DESTINATION_TYPE_TIR;
	dest.tir_num = priv->direct_tir[arfs_rule->rxq].tirn;
	rule = mlx5_add_flow_rule(ft, match_criteria_enable, match_criteria,
				  match_value, MLX5_FLOW_CONTEXT_ACTION_FWD_DEST,
	rule = mlx5_add_flow_rule(ft, spec, MLX5_FLOW_CONTEXT_ACTION_FWD_DEST,
				  MLX5_FS_DEFAULT_FLOW_TAG,
				  &dest);
	if (IS_ERR(rule)) {
@@ -563,8 +554,7 @@ static struct mlx5_flow_rule *arfs_add_rule(struct mlx5e_priv *priv,
	}

out:
	kvfree(match_criteria);
	kvfree(match_value);
	kvfree(spec);
	return err ? ERR_PTR(err) : rule;
}

+62 −3
Original line number Diff line number Diff line
@@ -139,6 +139,18 @@ static unsigned long mlx5e_query_pfc_combined(struct mlx5e_priv *priv)
	return err ? 0 : pfc_en_tx | pfc_en_rx;
}

static bool mlx5e_query_global_pause_combined(struct mlx5e_priv *priv)
{
	struct mlx5_core_dev *mdev = priv->mdev;
	u32 rx_pause;
	u32 tx_pause;
	int err;

	err = mlx5_query_port_pause(mdev, &rx_pause, &tx_pause);

	return err ? false : rx_pause | tx_pause;
}

#define MLX5E_NUM_Q_CNTRS(priv) (NUM_Q_COUNTERS * (!!priv->q_counter))
#define MLX5E_NUM_RQ_STATS(priv) \
	(NUM_RQ_STATS * priv->params.num_channels * \
@@ -147,7 +159,7 @@ static unsigned long mlx5e_query_pfc_combined(struct mlx5e_priv *priv)
	(NUM_SQ_STATS * priv->params.num_channels * priv->params.num_tc * \
	 test_bit(MLX5E_STATE_OPENED, &priv->state))
#define MLX5E_NUM_PFC_COUNTERS(priv) \
	(hweight8(mlx5e_query_pfc_combined(priv)) * \
	((mlx5e_query_global_pause_combined(priv) + hweight8(mlx5e_query_pfc_combined(priv))) * \
	  NUM_PPORT_PER_PRIO_PFC_COUNTERS)

static int mlx5e_get_sset_count(struct net_device *dev, int sset)
@@ -210,8 +222,18 @@ static void mlx5e_fill_stats_strings(struct mlx5e_priv *priv, uint8_t *data)
	pfc_combined = mlx5e_query_pfc_combined(priv);
	for_each_set_bit(prio, &pfc_combined, NUM_PPORT_PRIO) {
		for (i = 0; i < NUM_PPORT_PER_PRIO_PFC_COUNTERS; i++) {
			char pfc_string[ETH_GSTRING_LEN];

			snprintf(pfc_string, sizeof(pfc_string), "prio%d", prio);
			sprintf(data + (idx++) * ETH_GSTRING_LEN,
				pport_per_prio_pfc_stats_desc[i].format, prio);
				pport_per_prio_pfc_stats_desc[i].format, pfc_string);
		}
	}

	if (mlx5e_query_global_pause_combined(priv)) {
		for (i = 0; i < NUM_PPORT_PER_PRIO_PFC_COUNTERS; i++) {
			sprintf(data + (idx++) * ETH_GSTRING_LEN,
				pport_per_prio_pfc_stats_desc[i].format, "global");
		}
	}

@@ -306,6 +328,13 @@ static void mlx5e_get_ethtool_stats(struct net_device *dev,
		}
	}

	if (mlx5e_query_global_pause_combined(priv)) {
		for (i = 0; i < NUM_PPORT_PER_PRIO_PFC_COUNTERS; i++) {
			data[idx++] = MLX5E_READ_CTR64_BE(&priv->stats.pport.per_prio_counters[0],
							  pport_per_prio_pfc_stats_desc, 0);
		}
	}

	if (!test_bit(MLX5E_STATE_OPENED, &priv->state))
		return;

@@ -931,6 +960,15 @@ static int mlx5e_get_rxnfc(struct net_device *netdev,
	case ETHTOOL_GRXRINGS:
		info->data = priv->params.num_channels;
		break;
	case ETHTOOL_GRXCLSRLCNT:
		info->rule_cnt = priv->fs.ethtool.tot_num_rules;
		break;
	case ETHTOOL_GRXCLSRULE:
		err = mlx5e_ethtool_get_flow(priv, info, info->fs.location);
		break;
	case ETHTOOL_GRXCLSRLALL:
		err = mlx5e_ethtool_get_all_flows(priv, info, rule_locs);
		break;
	default:
		err = -EOPNOTSUPP;
		break;
@@ -1368,6 +1406,26 @@ static u32 mlx5e_get_priv_flags(struct net_device *netdev)
	return priv->pflags;
}

static int mlx5e_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd)
{
	int err = 0;
	struct mlx5e_priv *priv = netdev_priv(dev);

	switch (cmd->cmd) {
	case ETHTOOL_SRXCLSRLINS:
		err = mlx5e_ethtool_flow_replace(priv, &cmd->fs);
		break;
	case ETHTOOL_SRXCLSRLDEL:
		err = mlx5e_ethtool_flow_remove(priv, cmd->fs.location);
		break;
	default:
		err = -EOPNOTSUPP;
		break;
	}

	return err;
}

const struct ethtool_ops mlx5e_ethtool_ops = {
	.get_drvinfo       = mlx5e_get_drvinfo,
	.get_link          = ethtool_op_get_link,
@@ -1387,6 +1445,7 @@ const struct ethtool_ops mlx5e_ethtool_ops = {
	.get_rxfh          = mlx5e_get_rxfh,
	.set_rxfh          = mlx5e_set_rxfh,
	.get_rxnfc         = mlx5e_get_rxnfc,
	.set_rxnfc         = mlx5e_set_rxnfc,
	.get_tunable       = mlx5e_get_tunable,
	.set_tunable       = mlx5e_set_tunable,
	.get_pauseparam    = mlx5e_get_pauseparam,
Loading