xref: /dpdk/drivers/net/cnxk/cn10k_flow.c (revision 14598b31ed7c6a63bdb59a04bd6778586b86474e)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(C) 2020 Marvell.
3  */
4 #include "cn10k_flow.h"
5 #include "cn10k_ethdev.h"
6 #include "cn10k_rx.h"
7 #include "cnxk_ethdev_mcs.h"
8 #include <cnxk_flow.h>
9 
10 static int
cn10k_mtr_connect(struct rte_eth_dev * eth_dev,uint32_t mtr_id)11 cn10k_mtr_connect(struct rte_eth_dev *eth_dev, uint32_t mtr_id)
12 {
13 	return nix_mtr_connect(eth_dev, mtr_id);
14 }
15 
16 static int
cn10k_mtr_destroy(struct rte_eth_dev * eth_dev,uint32_t mtr_id)17 cn10k_mtr_destroy(struct rte_eth_dev *eth_dev, uint32_t mtr_id)
18 {
19 	struct rte_mtr_error mtr_error;
20 
21 	return nix_mtr_destroy(eth_dev, mtr_id, &mtr_error);
22 }
23 
24 static int
cn10k_mtr_configure(struct rte_eth_dev * eth_dev,const struct rte_flow_action actions[])25 cn10k_mtr_configure(struct rte_eth_dev *eth_dev,
26 		    const struct rte_flow_action actions[])
27 {
28 	uint32_t mtr_id = 0xffff, prev_mtr_id = 0xffff, next_mtr_id = 0xffff;
29 	const struct rte_flow_action_meter *mtr_conf;
30 	const struct rte_flow_action_queue *q_conf;
31 	const struct rte_flow_action_rss *rss_conf;
32 	struct cnxk_mtr_policy_node *policy;
33 	bool is_mtr_act = false;
34 	int tree_level = 0;
35 	int rc = -EINVAL, i;
36 
37 	for (i = 0; actions[i].type != RTE_FLOW_ACTION_TYPE_END; i++) {
38 		if (actions[i].type == RTE_FLOW_ACTION_TYPE_METER) {
39 			mtr_conf = (const struct rte_flow_action_meter
40 					    *)(actions[i].conf);
41 			mtr_id = mtr_conf->mtr_id;
42 			is_mtr_act = true;
43 		}
44 		if (actions[i].type == RTE_FLOW_ACTION_TYPE_QUEUE) {
45 			q_conf = (const struct rte_flow_action_queue
46 					  *)(actions[i].conf);
47 			if (is_mtr_act)
48 				nix_mtr_rq_update(eth_dev, mtr_id, 1,
49 						  &q_conf->index);
50 		}
51 		if (actions[i].type == RTE_FLOW_ACTION_TYPE_RSS) {
52 			rss_conf = (const struct rte_flow_action_rss
53 					    *)(actions[i].conf);
54 			if (is_mtr_act)
55 				nix_mtr_rq_update(eth_dev, mtr_id,
56 						  rss_conf->queue_num,
57 						  rss_conf->queue);
58 		}
59 	}
60 
61 	if (!is_mtr_act)
62 		return rc;
63 
64 	prev_mtr_id = mtr_id;
65 	next_mtr_id = mtr_id;
66 	while (next_mtr_id != 0xffff) {
67 		rc = nix_mtr_validate(eth_dev, next_mtr_id);
68 		if (rc)
69 			return rc;
70 
71 		rc = nix_mtr_policy_act_get(eth_dev, next_mtr_id, &policy);
72 		if (rc)
73 			return rc;
74 
75 		rc = nix_mtr_color_action_validate(eth_dev, mtr_id,
76 						   &prev_mtr_id, &next_mtr_id,
77 						   policy, &tree_level);
78 		if (rc)
79 			return rc;
80 	}
81 
82 	return nix_mtr_configure(eth_dev, mtr_id);
83 }
84 
85 static int
cn10k_rss_action_validate(struct rte_eth_dev * eth_dev,const struct rte_flow_attr * attr,const struct rte_flow_action * act)86 cn10k_rss_action_validate(struct rte_eth_dev *eth_dev,
87 			  const struct rte_flow_attr *attr,
88 			  const struct rte_flow_action *act)
89 {
90 	const struct rte_flow_action_rss *rss;
91 
92 	if (act == NULL)
93 		return -EINVAL;
94 
95 	rss = (const struct rte_flow_action_rss *)act->conf;
96 
97 	if (attr->egress) {
98 		plt_err("No support of RSS in egress");
99 		return -EINVAL;
100 	}
101 
102 	if (eth_dev->data->dev_conf.rxmode.mq_mode != RTE_ETH_MQ_RX_RSS) {
103 		plt_err("multi-queue mode is disabled");
104 		return -ENOTSUP;
105 	}
106 
107 	if (!rss || !rss->queue_num) {
108 		plt_err("no valid queues");
109 		return -EINVAL;
110 	}
111 
112 	if (rss->func != RTE_ETH_HASH_FUNCTION_DEFAULT) {
113 		plt_err("non-default RSS hash functions are not supported");
114 		return -ENOTSUP;
115 	}
116 
117 	if (rss->key_len && rss->key_len > ROC_NIX_RSS_KEY_LEN) {
118 		plt_err("RSS hash key too large");
119 		return -ENOTSUP;
120 	}
121 
122 	return 0;
123 }
124 
125 struct rte_flow *
cn10k_flow_create(struct rte_eth_dev * eth_dev,const struct rte_flow_attr * attr,const struct rte_flow_item pattern[],const struct rte_flow_action actions[],struct rte_flow_error * error)126 cn10k_flow_create(struct rte_eth_dev *eth_dev, const struct rte_flow_attr *attr,
127 		  const struct rte_flow_item pattern[],
128 		  const struct rte_flow_action actions[],
129 		  struct rte_flow_error *error)
130 {
131 	struct cnxk_eth_dev *dev = cnxk_eth_pmd_priv(eth_dev);
132 	const struct rte_flow_action *action_rss = NULL;
133 	const struct rte_flow_action_meter *mtr = NULL;
134 	const struct rte_flow_action *act_q = NULL;
135 	struct roc_npc *npc = &dev->npc;
136 	struct roc_npc_flow *flow;
137 	void *mcs_flow = NULL;
138 	int vtag_actions = 0;
139 	uint32_t req_act = 0;
140 	int mark_actions;
141 	int i, rc;
142 
143 	for (i = 0; actions[i].type != RTE_FLOW_ACTION_TYPE_END; i++) {
144 		if (actions[i].type == RTE_FLOW_ACTION_TYPE_METER)
145 			req_act |= ROC_NPC_ACTION_TYPE_METER;
146 
147 		if (actions[i].type == RTE_FLOW_ACTION_TYPE_QUEUE) {
148 			req_act |= ROC_NPC_ACTION_TYPE_QUEUE;
149 			act_q = &actions[i];
150 		}
151 		if (actions[i].type == RTE_FLOW_ACTION_TYPE_RSS) {
152 			req_act |= ROC_NPC_ACTION_TYPE_RSS;
153 			action_rss = &actions[i];
154 		}
155 	}
156 
157 	if (req_act & ROC_NPC_ACTION_TYPE_METER) {
158 		if ((req_act & ROC_NPC_ACTION_TYPE_RSS) &&
159 		    ((req_act & ROC_NPC_ACTION_TYPE_QUEUE))) {
160 			return NULL;
161 		}
162 		if (req_act & ROC_NPC_ACTION_TYPE_RSS) {
163 			rc = cn10k_rss_action_validate(eth_dev, attr,
164 						       action_rss);
165 			if (rc)
166 				return NULL;
167 		} else if (req_act & ROC_NPC_ACTION_TYPE_QUEUE) {
168 			const struct rte_flow_action_queue *act_queue;
169 			act_queue = (const struct rte_flow_action_queue *)
170 					    act_q->conf;
171 			if (act_queue->index > eth_dev->data->nb_rx_queues)
172 				return NULL;
173 		} else {
174 			return NULL;
175 		}
176 	}
177 	for (i = 0; actions[i].type != RTE_FLOW_ACTION_TYPE_END; i++) {
178 		if (actions[i].type == RTE_FLOW_ACTION_TYPE_METER) {
179 			mtr = (const struct rte_flow_action_meter *)actions[i]
180 				      .conf;
181 			rc = cn10k_mtr_configure(eth_dev, actions);
182 			if (rc) {
183 				rte_flow_error_set(error, rc,
184 					RTE_FLOW_ERROR_TYPE_ACTION, NULL,
185 					"Failed to configure mtr ");
186 				return NULL;
187 			}
188 			break;
189 		}
190 	}
191 
192 	if (actions[0].type == RTE_FLOW_ACTION_TYPE_SECURITY &&
193 	    cnxk_eth_macsec_sess_get_by_sess(dev, actions[0].conf) != NULL) {
194 		rc = cnxk_mcs_flow_configure(eth_dev, attr, pattern, actions, error, &mcs_flow);
195 		if (rc) {
196 			rte_flow_error_set(error, rc, RTE_FLOW_ERROR_TYPE_ACTION, NULL,
197 					   "Failed to configure mcs flow");
198 			return NULL;
199 		}
200 		return (struct rte_flow *)mcs_flow;
201 	}
202 
203 	flow = cnxk_flow_create(eth_dev, attr, pattern, actions, error);
204 	if (!flow) {
205 		if (mtr)
206 			nix_mtr_chain_reset(eth_dev, mtr->mtr_id);
207 
208 		return NULL;
209 	} else {
210 		if (mtr)
211 			cn10k_mtr_connect(eth_dev, mtr->mtr_id);
212 	}
213 
214 	mark_actions = roc_npc_mark_actions_get(npc);
215 	if (mark_actions) {
216 		dev->rx_offload_flags |= NIX_RX_OFFLOAD_MARK_UPDATE_F;
217 		cn10k_eth_set_rx_function(eth_dev);
218 	}
219 
220 	vtag_actions = roc_npc_vtag_actions_get(npc);
221 
222 	if (vtag_actions) {
223 		dev->rx_offload_flags |= NIX_RX_OFFLOAD_VLAN_STRIP_F;
224 		cn10k_eth_set_rx_function(eth_dev);
225 	}
226 
227 	return (struct rte_flow *)flow;
228 }
229 
230 int
cn10k_flow_info_get(struct rte_eth_dev * dev,struct rte_flow_port_info * port_info,struct rte_flow_queue_info * queue_info,struct rte_flow_error * err)231 cn10k_flow_info_get(struct rte_eth_dev *dev, struct rte_flow_port_info *port_info,
232 		    struct rte_flow_queue_info *queue_info, struct rte_flow_error *err)
233 {
234 	RTE_SET_USED(dev);
235 	RTE_SET_USED(err);
236 
237 	memset(port_info, 0, sizeof(*port_info));
238 	memset(queue_info, 0, sizeof(*queue_info));
239 
240 	port_info->max_nb_counters = CN10K_NPC_COUNTERS_MAX;
241 	port_info->max_nb_meters = CNXK_NIX_MTR_COUNT_MAX;
242 
243 	return 0;
244 }
245 
246 int
cn10k_flow_destroy(struct rte_eth_dev * eth_dev,struct rte_flow * rte_flow,struct rte_flow_error * error)247 cn10k_flow_destroy(struct rte_eth_dev *eth_dev, struct rte_flow *rte_flow,
248 		   struct rte_flow_error *error)
249 {
250 	struct roc_npc_flow *flow = (struct roc_npc_flow *)rte_flow;
251 	struct cnxk_eth_dev *dev = cnxk_eth_pmd_priv(eth_dev);
252 	struct roc_npc *npc = &dev->npc;
253 	int vtag_actions = 0;
254 	int mark_actions;
255 	uint16_t match_id;
256 	uint32_t mtr_id;
257 	int rc;
258 
259 	match_id = (flow->npc_action >> NPC_RX_ACT_MATCH_OFFSET) &
260 		   NPC_RX_ACT_MATCH_MASK;
261 	if (match_id) {
262 		mark_actions = roc_npc_mark_actions_sub_return(npc, 1);
263 		if (mark_actions == 0) {
264 			dev->rx_offload_flags &= ~NIX_RX_OFFLOAD_MARK_UPDATE_F;
265 			cn10k_eth_set_rx_function(eth_dev);
266 		}
267 	}
268 
269 	vtag_actions = roc_npc_vtag_actions_get(npc);
270 	if (vtag_actions) {
271 		if (flow->nix_intf == ROC_NPC_INTF_RX) {
272 			vtag_actions = roc_npc_vtag_actions_sub_return(npc, 1);
273 			if (vtag_actions == 0) {
274 				dev->rx_offload_flags &=
275 					~NIX_RX_OFFLOAD_VLAN_STRIP_F;
276 				cn10k_eth_set_rx_function(eth_dev);
277 			}
278 		}
279 	}
280 
281 	if (cnxk_eth_macsec_sess_get_by_sess(dev, (void *)flow) != NULL) {
282 		rc = cnxk_mcs_flow_destroy(dev, (void *)flow);
283 		if (rc < 0)
284 			rte_flow_error_set(error, rc, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
285 					NULL, "Failed to free mcs flow");
286 		return rc;
287 	}
288 
289 	mtr_id = flow->mtr_id;
290 	rc = cnxk_flow_destroy(eth_dev, flow, error);
291 	if (!rc && mtr_id != ROC_NIX_MTR_ID_INVALID) {
292 		rc = cn10k_mtr_destroy(eth_dev, mtr_id);
293 		if (rc) {
294 			rte_flow_error_set(error, ENXIO,
295 				RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
296 				"Meter attached to this flow does not exist");
297 		}
298 	}
299 	return rc;
300 }
301