]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | /*- |
2 | * BSD LICENSE | |
3 | * | |
4 | * Copyright(c) 2010-2016 Intel Corporation. All rights reserved. | |
5 | * All rights reserved. | |
6 | * | |
7 | * Redistribution and use in source and binary forms, with or without | |
8 | * modification, are permitted provided that the following conditions | |
9 | * are met: | |
10 | * | |
11 | * * Redistributions of source code must retain the above copyright | |
12 | * notice, this list of conditions and the following disclaimer. | |
13 | * * Redistributions in binary form must reproduce the above copyright | |
14 | * notice, this list of conditions and the following disclaimer in | |
15 | * the documentation and/or other materials provided with the | |
16 | * distribution. | |
17 | * * Neither the name of Intel Corporation nor the names of its | |
18 | * contributors may be used to endorse or promote products derived | |
19 | * from this software without specific prior written permission. | |
20 | * | |
21 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
22 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
23 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
24 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
25 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
26 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
27 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
28 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
29 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
30 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
31 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
32 | */ | |
33 | ||
34 | #include <string.h> | |
35 | ||
36 | #include <rte_common.h> | |
37 | #include <rte_malloc.h> | |
38 | #include <rte_cycles.h> | |
39 | #include <rte_table_array.h> | |
40 | #include <rte_byteorder.h> | |
41 | #include <rte_ip.h> | |
42 | ||
43 | #include "pipeline_actions_common.h" | |
44 | #include "pipeline_flow_actions_be.h" | |
45 | #include "parser.h" | |
46 | #include "hash_func.h" | |
47 | ||
48 | int | |
49 | pipeline_fa_flow_params_set_default(struct pipeline_fa_flow_params *params) | |
50 | { | |
51 | uint32_t i; | |
52 | ||
53 | if (params == NULL) | |
54 | return -1; | |
55 | ||
56 | for (i = 0; i < PIPELINE_FA_N_TC_MAX; i++) { | |
57 | struct rte_meter_trtcm_params *m = ¶ms->m[i]; | |
58 | ||
59 | m->cir = 1; | |
60 | m->cbs = 1; | |
61 | m->pir = 1; | |
62 | m->pbs = 2; | |
63 | } | |
64 | ||
65 | for (i = 0; i < PIPELINE_FA_N_TC_MAX; i++) { | |
66 | struct pipeline_fa_policer_params *p = ¶ms->p[i]; | |
67 | uint32_t j; | |
68 | ||
69 | for (j = 0; j < e_RTE_METER_COLORS; j++) { | |
70 | struct pipeline_fa_policer_action *a = &p->action[j]; | |
71 | ||
72 | a->drop = 0; | |
73 | a->color = (enum rte_meter_color) j; | |
74 | } | |
75 | } | |
76 | ||
77 | params->port_id = 0; | |
78 | ||
79 | return 0; | |
80 | } | |
81 | ||
82 | struct dscp_entry { | |
83 | uint32_t traffic_class; | |
84 | enum rte_meter_color color; | |
85 | }; | |
86 | ||
87 | struct pipeline_flow_actions { | |
88 | struct pipeline p; | |
89 | struct pipeline_fa_params params; | |
90 | pipeline_msg_req_handler custom_handlers[PIPELINE_FA_MSG_REQS]; | |
91 | ||
92 | struct dscp_entry dscp[PIPELINE_FA_N_DSCP]; | |
93 | } __rte_cache_aligned; | |
94 | ||
95 | static void * | |
96 | pipeline_fa_msg_req_custom_handler(struct pipeline *p, void *msg); | |
97 | ||
98 | static pipeline_msg_req_handler handlers[] = { | |
99 | [PIPELINE_MSG_REQ_PING] = | |
100 | pipeline_msg_req_ping_handler, | |
101 | [PIPELINE_MSG_REQ_STATS_PORT_IN] = | |
102 | pipeline_msg_req_stats_port_in_handler, | |
103 | [PIPELINE_MSG_REQ_STATS_PORT_OUT] = | |
104 | pipeline_msg_req_stats_port_out_handler, | |
105 | [PIPELINE_MSG_REQ_STATS_TABLE] = | |
106 | pipeline_msg_req_stats_table_handler, | |
107 | [PIPELINE_MSG_REQ_PORT_IN_ENABLE] = | |
108 | pipeline_msg_req_port_in_enable_handler, | |
109 | [PIPELINE_MSG_REQ_PORT_IN_DISABLE] = | |
110 | pipeline_msg_req_port_in_disable_handler, | |
111 | [PIPELINE_MSG_REQ_CUSTOM] = | |
112 | pipeline_fa_msg_req_custom_handler, | |
113 | }; | |
114 | ||
115 | static void * | |
116 | pipeline_fa_msg_req_flow_config_handler(struct pipeline *p, void *msg); | |
117 | ||
118 | static void * | |
119 | pipeline_fa_msg_req_flow_config_bulk_handler(struct pipeline *p, void *msg); | |
120 | ||
121 | static void * | |
122 | pipeline_fa_msg_req_dscp_config_handler(struct pipeline *p, void *msg); | |
123 | ||
124 | static void * | |
125 | pipeline_fa_msg_req_policer_stats_read_handler(struct pipeline *p, void *msg); | |
126 | ||
127 | static pipeline_msg_req_handler custom_handlers[] = { | |
128 | [PIPELINE_FA_MSG_REQ_FLOW_CONFIG] = | |
129 | pipeline_fa_msg_req_flow_config_handler, | |
130 | [PIPELINE_FA_MSG_REQ_FLOW_CONFIG_BULK] = | |
131 | pipeline_fa_msg_req_flow_config_bulk_handler, | |
132 | [PIPELINE_FA_MSG_REQ_DSCP_CONFIG] = | |
133 | pipeline_fa_msg_req_dscp_config_handler, | |
134 | [PIPELINE_FA_MSG_REQ_POLICER_STATS_READ] = | |
135 | pipeline_fa_msg_req_policer_stats_read_handler, | |
136 | }; | |
137 | ||
138 | /* | |
139 | * Flow table | |
140 | */ | |
141 | struct meter_policer { | |
142 | struct rte_meter_trtcm meter; | |
143 | struct pipeline_fa_policer_params policer; | |
144 | struct pipeline_fa_policer_stats stats; | |
145 | }; | |
146 | ||
147 | struct flow_table_entry { | |
148 | struct rte_pipeline_table_entry head; | |
149 | struct meter_policer mp[PIPELINE_FA_N_TC_MAX]; | |
150 | }; | |
151 | ||
152 | static int | |
153 | flow_table_entry_set_meter(struct flow_table_entry *entry, | |
154 | uint32_t meter_id, | |
155 | struct pipeline_fa_flow_params *params) | |
156 | { | |
157 | struct rte_meter_trtcm *meter = &entry->mp[meter_id].meter; | |
158 | struct rte_meter_trtcm_params *meter_params = ¶ms->m[meter_id]; | |
159 | ||
160 | return rte_meter_trtcm_config(meter, meter_params); | |
161 | } | |
162 | ||
163 | static void | |
164 | flow_table_entry_set_policer(struct flow_table_entry *entry, | |
165 | uint32_t policer_id, | |
166 | struct pipeline_fa_flow_params *params) | |
167 | { | |
168 | struct pipeline_fa_policer_params *p0 = &entry->mp[policer_id].policer; | |
169 | struct pipeline_fa_policer_params *p1 = ¶ms->p[policer_id]; | |
170 | ||
171 | memcpy(p0, p1, sizeof(*p0)); | |
172 | } | |
173 | ||
174 | static void | |
175 | flow_table_entry_set_port_id(struct pipeline_flow_actions *p, | |
176 | struct flow_table_entry *entry, | |
177 | struct pipeline_fa_flow_params *params) | |
178 | { | |
179 | entry->head.action = RTE_PIPELINE_ACTION_PORT; | |
180 | entry->head.port_id = p->p.port_out_id[params->port_id]; | |
181 | } | |
182 | ||
183 | static int | |
184 | flow_table_entry_set_default(struct pipeline_flow_actions *p, | |
185 | struct flow_table_entry *entry) | |
186 | { | |
187 | struct pipeline_fa_flow_params params; | |
188 | uint32_t i; | |
189 | ||
190 | pipeline_fa_flow_params_set_default(¶ms); | |
191 | ||
192 | memset(entry, 0, sizeof(*entry)); | |
193 | ||
194 | flow_table_entry_set_port_id(p, entry, ¶ms); | |
195 | ||
196 | for (i = 0; i < PIPELINE_FA_N_TC_MAX; i++) { | |
197 | int status; | |
198 | ||
199 | status = flow_table_entry_set_meter(entry, i, ¶ms); | |
200 | if (status) | |
201 | return status; | |
202 | } | |
203 | ||
204 | for (i = 0; i < PIPELINE_FA_N_TC_MAX; i++) | |
205 | flow_table_entry_set_policer(entry, i, ¶ms); | |
206 | ||
207 | return 0; | |
208 | } | |
209 | ||
210 | static inline uint64_t | |
211 | pkt_work( | |
212 | struct rte_mbuf *pkt, | |
213 | struct rte_pipeline_table_entry *table_entry, | |
214 | void *arg, | |
215 | uint64_t time) | |
216 | { | |
217 | struct pipeline_flow_actions *p = arg; | |
218 | struct flow_table_entry *entry = | |
219 | (struct flow_table_entry *) table_entry; | |
220 | ||
221 | struct ipv4_hdr *pkt_ip = (struct ipv4_hdr *) | |
222 | RTE_MBUF_METADATA_UINT32_PTR(pkt, p->params.ip_hdr_offset); | |
223 | enum rte_meter_color *pkt_color = (enum rte_meter_color *) | |
224 | RTE_MBUF_METADATA_UINT32_PTR(pkt, p->params.color_offset); | |
225 | ||
226 | /* Read (IP header) */ | |
227 | uint32_t total_length = rte_bswap16(pkt_ip->total_length); | |
228 | uint32_t dscp = pkt_ip->type_of_service >> 2; | |
229 | ||
230 | uint32_t tc = p->dscp[dscp].traffic_class; | |
231 | enum rte_meter_color color = p->dscp[dscp].color; | |
232 | ||
233 | struct rte_meter_trtcm *meter = &entry->mp[tc].meter; | |
234 | struct pipeline_fa_policer_params *policer = &entry->mp[tc].policer; | |
235 | struct pipeline_fa_policer_stats *stats = &entry->mp[tc].stats; | |
236 | ||
237 | /* Read (entry), compute */ | |
238 | enum rte_meter_color color2 = rte_meter_trtcm_color_aware_check(meter, | |
239 | time, | |
240 | total_length, | |
241 | color); | |
242 | ||
243 | enum rte_meter_color color3 = policer->action[color2].color; | |
244 | uint64_t drop = policer->action[color2].drop; | |
245 | ||
246 | /* Read (entry), write (entry, color) */ | |
247 | stats->n_pkts[color3] += drop ^ 1LLU; | |
248 | stats->n_pkts_drop += drop; | |
249 | *pkt_color = color3; | |
250 | ||
251 | return drop; | |
252 | } | |
253 | ||
254 | static inline uint64_t | |
255 | pkt4_work( | |
256 | struct rte_mbuf **pkts, | |
257 | struct rte_pipeline_table_entry **table_entries, | |
258 | void *arg, | |
259 | uint64_t time) | |
260 | { | |
261 | struct pipeline_flow_actions *p = arg; | |
262 | ||
263 | struct flow_table_entry *entry0 = | |
264 | (struct flow_table_entry *) table_entries[0]; | |
265 | struct flow_table_entry *entry1 = | |
266 | (struct flow_table_entry *) table_entries[1]; | |
267 | struct flow_table_entry *entry2 = | |
268 | (struct flow_table_entry *) table_entries[2]; | |
269 | struct flow_table_entry *entry3 = | |
270 | (struct flow_table_entry *) table_entries[3]; | |
271 | ||
272 | struct ipv4_hdr *pkt0_ip = (struct ipv4_hdr *) | |
273 | RTE_MBUF_METADATA_UINT32_PTR(pkts[0], p->params.ip_hdr_offset); | |
274 | struct ipv4_hdr *pkt1_ip = (struct ipv4_hdr *) | |
275 | RTE_MBUF_METADATA_UINT32_PTR(pkts[1], p->params.ip_hdr_offset); | |
276 | struct ipv4_hdr *pkt2_ip = (struct ipv4_hdr *) | |
277 | RTE_MBUF_METADATA_UINT32_PTR(pkts[2], p->params.ip_hdr_offset); | |
278 | struct ipv4_hdr *pkt3_ip = (struct ipv4_hdr *) | |
279 | RTE_MBUF_METADATA_UINT32_PTR(pkts[3], p->params.ip_hdr_offset); | |
280 | ||
281 | enum rte_meter_color *pkt0_color = (enum rte_meter_color *) | |
282 | RTE_MBUF_METADATA_UINT32_PTR(pkts[0], p->params.color_offset); | |
283 | enum rte_meter_color *pkt1_color = (enum rte_meter_color *) | |
284 | RTE_MBUF_METADATA_UINT32_PTR(pkts[1], p->params.color_offset); | |
285 | enum rte_meter_color *pkt2_color = (enum rte_meter_color *) | |
286 | RTE_MBUF_METADATA_UINT32_PTR(pkts[2], p->params.color_offset); | |
287 | enum rte_meter_color *pkt3_color = (enum rte_meter_color *) | |
288 | RTE_MBUF_METADATA_UINT32_PTR(pkts[3], p->params.color_offset); | |
289 | ||
290 | /* Read (IP header) */ | |
291 | uint32_t total_length0 = rte_bswap16(pkt0_ip->total_length); | |
292 | uint32_t dscp0 = pkt0_ip->type_of_service >> 2; | |
293 | ||
294 | uint32_t total_length1 = rte_bswap16(pkt1_ip->total_length); | |
295 | uint32_t dscp1 = pkt1_ip->type_of_service >> 2; | |
296 | ||
297 | uint32_t total_length2 = rte_bswap16(pkt2_ip->total_length); | |
298 | uint32_t dscp2 = pkt2_ip->type_of_service >> 2; | |
299 | ||
300 | uint32_t total_length3 = rte_bswap16(pkt3_ip->total_length); | |
301 | uint32_t dscp3 = pkt3_ip->type_of_service >> 2; | |
302 | ||
303 | uint32_t tc0 = p->dscp[dscp0].traffic_class; | |
304 | enum rte_meter_color color0 = p->dscp[dscp0].color; | |
305 | ||
306 | uint32_t tc1 = p->dscp[dscp1].traffic_class; | |
307 | enum rte_meter_color color1 = p->dscp[dscp1].color; | |
308 | ||
309 | uint32_t tc2 = p->dscp[dscp2].traffic_class; | |
310 | enum rte_meter_color color2 = p->dscp[dscp2].color; | |
311 | ||
312 | uint32_t tc3 = p->dscp[dscp3].traffic_class; | |
313 | enum rte_meter_color color3 = p->dscp[dscp3].color; | |
314 | ||
315 | struct rte_meter_trtcm *meter0 = &entry0->mp[tc0].meter; | |
316 | struct pipeline_fa_policer_params *policer0 = &entry0->mp[tc0].policer; | |
317 | struct pipeline_fa_policer_stats *stats0 = &entry0->mp[tc0].stats; | |
318 | ||
319 | struct rte_meter_trtcm *meter1 = &entry1->mp[tc1].meter; | |
320 | struct pipeline_fa_policer_params *policer1 = &entry1->mp[tc1].policer; | |
321 | struct pipeline_fa_policer_stats *stats1 = &entry1->mp[tc1].stats; | |
322 | ||
323 | struct rte_meter_trtcm *meter2 = &entry2->mp[tc2].meter; | |
324 | struct pipeline_fa_policer_params *policer2 = &entry2->mp[tc2].policer; | |
325 | struct pipeline_fa_policer_stats *stats2 = &entry2->mp[tc2].stats; | |
326 | ||
327 | struct rte_meter_trtcm *meter3 = &entry3->mp[tc3].meter; | |
328 | struct pipeline_fa_policer_params *policer3 = &entry3->mp[tc3].policer; | |
329 | struct pipeline_fa_policer_stats *stats3 = &entry3->mp[tc3].stats; | |
330 | ||
331 | /* Read (entry), compute, write (entry) */ | |
332 | enum rte_meter_color color2_0 = rte_meter_trtcm_color_aware_check( | |
333 | meter0, | |
334 | time, | |
335 | total_length0, | |
336 | color0); | |
337 | ||
338 | enum rte_meter_color color2_1 = rte_meter_trtcm_color_aware_check( | |
339 | meter1, | |
340 | time, | |
341 | total_length1, | |
342 | color1); | |
343 | ||
344 | enum rte_meter_color color2_2 = rte_meter_trtcm_color_aware_check( | |
345 | meter2, | |
346 | time, | |
347 | total_length2, | |
348 | color2); | |
349 | ||
350 | enum rte_meter_color color2_3 = rte_meter_trtcm_color_aware_check( | |
351 | meter3, | |
352 | time, | |
353 | total_length3, | |
354 | color3); | |
355 | ||
356 | enum rte_meter_color color3_0 = policer0->action[color2_0].color; | |
357 | enum rte_meter_color color3_1 = policer1->action[color2_1].color; | |
358 | enum rte_meter_color color3_2 = policer2->action[color2_2].color; | |
359 | enum rte_meter_color color3_3 = policer3->action[color2_3].color; | |
360 | ||
361 | uint64_t drop0 = policer0->action[color2_0].drop; | |
362 | uint64_t drop1 = policer1->action[color2_1].drop; | |
363 | uint64_t drop2 = policer2->action[color2_2].drop; | |
364 | uint64_t drop3 = policer3->action[color2_3].drop; | |
365 | ||
366 | /* Read (entry), write (entry, color) */ | |
367 | stats0->n_pkts[color3_0] += drop0 ^ 1LLU; | |
368 | stats0->n_pkts_drop += drop0; | |
369 | ||
370 | stats1->n_pkts[color3_1] += drop1 ^ 1LLU; | |
371 | stats1->n_pkts_drop += drop1; | |
372 | ||
373 | stats2->n_pkts[color3_2] += drop2 ^ 1LLU; | |
374 | stats2->n_pkts_drop += drop2; | |
375 | ||
376 | stats3->n_pkts[color3_3] += drop3 ^ 1LLU; | |
377 | stats3->n_pkts_drop += drop3; | |
378 | ||
379 | *pkt0_color = color3_0; | |
380 | *pkt1_color = color3_1; | |
381 | *pkt2_color = color3_2; | |
382 | *pkt3_color = color3_3; | |
383 | ||
384 | return drop0 | (drop1 << 1) | (drop2 << 2) | (drop3 << 3); | |
385 | } | |
386 | ||
387 | PIPELINE_TABLE_AH_HIT_DROP_TIME(fa_table_ah_hit, pkt_work, pkt4_work); | |
388 | ||
389 | static rte_pipeline_table_action_handler_hit | |
390 | get_fa_table_ah_hit(__rte_unused struct pipeline_flow_actions *p) | |
391 | { | |
392 | return fa_table_ah_hit; | |
393 | } | |
394 | ||
395 | /* | |
396 | * Argument parsing | |
397 | */ | |
398 | int | |
399 | pipeline_fa_parse_args(struct pipeline_fa_params *p, | |
400 | struct pipeline_params *params) | |
401 | { | |
402 | uint32_t n_flows_present = 0; | |
403 | uint32_t n_meters_per_flow_present = 0; | |
404 | uint32_t flow_id_offset_present = 0; | |
405 | uint32_t ip_hdr_offset_present = 0; | |
406 | uint32_t color_offset_present = 0; | |
407 | uint32_t i; | |
408 | ||
409 | /* Default values */ | |
410 | p->n_meters_per_flow = 1; | |
411 | p->dscp_enabled = 0; | |
412 | ||
413 | for (i = 0; i < params->n_args; i++) { | |
414 | char *arg_name = params->args_name[i]; | |
415 | char *arg_value = params->args_value[i]; | |
416 | ||
417 | /* n_flows */ | |
418 | if (strcmp(arg_name, "n_flows") == 0) { | |
419 | int status; | |
420 | ||
421 | PIPELINE_PARSE_ERR_DUPLICATE( | |
422 | n_flows_present == 0, params->name, | |
423 | arg_name); | |
424 | n_flows_present = 1; | |
425 | ||
426 | status = parser_read_uint32(&p->n_flows, | |
427 | arg_value); | |
428 | PIPELINE_PARSE_ERR_INV_VAL(((status != -EINVAL) && | |
429 | (p->n_flows != 0)), params->name, | |
430 | arg_name, arg_value); | |
431 | PIPELINE_PARSE_ERR_OUT_RNG((status != -ERANGE), | |
432 | params->name, arg_name, arg_value); | |
433 | ||
434 | continue; | |
435 | } | |
436 | ||
437 | /* n_meters_per_flow */ | |
438 | if (strcmp(arg_name, "n_meters_per_flow") == 0) { | |
439 | int status; | |
440 | ||
441 | PIPELINE_PARSE_ERR_DUPLICATE( | |
442 | n_meters_per_flow_present == 0, | |
443 | params->name, arg_name); | |
444 | n_meters_per_flow_present = 1; | |
445 | ||
446 | status = parser_read_uint32(&p->n_meters_per_flow, | |
447 | arg_value); | |
448 | PIPELINE_PARSE_ERR_INV_VAL(((status != -EINVAL) && | |
449 | (p->n_meters_per_flow != 0)), | |
450 | params->name, arg_name, arg_value); | |
451 | PIPELINE_PARSE_ERR_OUT_RNG(((status != -ERANGE) && | |
452 | (p->n_meters_per_flow <= | |
453 | PIPELINE_FA_N_TC_MAX)), params->name, | |
454 | arg_name, arg_value); | |
455 | ||
456 | continue; | |
457 | } | |
458 | ||
459 | /* flow_id_offset */ | |
460 | if (strcmp(arg_name, "flow_id_offset") == 0) { | |
461 | int status; | |
462 | ||
463 | PIPELINE_PARSE_ERR_DUPLICATE( | |
464 | flow_id_offset_present == 0, | |
465 | params->name, arg_name); | |
466 | flow_id_offset_present = 1; | |
467 | ||
468 | status = parser_read_uint32(&p->flow_id_offset, | |
469 | arg_value); | |
470 | PIPELINE_PARSE_ERR_INV_VAL((status != -EINVAL), | |
471 | params->name, arg_name, arg_value); | |
472 | PIPELINE_PARSE_ERR_OUT_RNG((status != -ERANGE), | |
473 | params->name, arg_name, arg_value); | |
474 | ||
475 | continue; | |
476 | } | |
477 | ||
478 | /* ip_hdr_offset */ | |
479 | if (strcmp(arg_name, "ip_hdr_offset") == 0) { | |
480 | int status; | |
481 | ||
482 | PIPELINE_PARSE_ERR_DUPLICATE( | |
483 | ip_hdr_offset_present == 0, | |
484 | params->name, arg_name); | |
485 | ip_hdr_offset_present = 1; | |
486 | ||
487 | status = parser_read_uint32(&p->ip_hdr_offset, | |
488 | arg_value); | |
489 | PIPELINE_PARSE_ERR_INV_VAL((status != -EINVAL), | |
490 | params->name, arg_name, arg_value); | |
491 | PIPELINE_PARSE_ERR_OUT_RNG((status != -ERANGE), | |
492 | params->name, arg_name, arg_value); | |
493 | ||
494 | continue; | |
495 | } | |
496 | ||
497 | /* color_offset */ | |
498 | if (strcmp(arg_name, "color_offset") == 0) { | |
499 | int status; | |
500 | ||
501 | PIPELINE_PARSE_ERR_DUPLICATE( | |
502 | color_offset_present == 0, params->name, | |
503 | arg_name); | |
504 | color_offset_present = 1; | |
505 | ||
506 | status = parser_read_uint32(&p->color_offset, | |
507 | arg_value); | |
508 | PIPELINE_PARSE_ERR_INV_VAL((status != -EINVAL), | |
509 | params->name, arg_name, arg_value); | |
510 | PIPELINE_PARSE_ERR_OUT_RNG((status != -ERANGE), | |
511 | params->name, arg_name, arg_value); | |
512 | ||
513 | p->dscp_enabled = 1; | |
514 | ||
515 | continue; | |
516 | } | |
517 | ||
518 | /* Unknown argument */ | |
519 | PIPELINE_PARSE_ERR_INV_ENT(0, params->name, arg_name); | |
520 | } | |
521 | ||
522 | /* Check that mandatory arguments are present */ | |
523 | PIPELINE_PARSE_ERR_MANDATORY((n_flows_present), params->name, | |
524 | "n_flows"); | |
525 | PIPELINE_PARSE_ERR_MANDATORY((flow_id_offset_present), | |
526 | params->name, "flow_id_offset"); | |
527 | PIPELINE_PARSE_ERR_MANDATORY((ip_hdr_offset_present), | |
528 | params->name, "ip_hdr_offset"); | |
529 | PIPELINE_PARSE_ERR_MANDATORY((color_offset_present), params->name, | |
530 | "color_offset"); | |
531 | ||
532 | return 0; | |
533 | } | |
534 | ||
535 | static void | |
536 | dscp_init(struct pipeline_flow_actions *p) | |
537 | { | |
538 | uint32_t i; | |
539 | ||
540 | for (i = 0; i < PIPELINE_FA_N_DSCP; i++) { | |
541 | p->dscp[i].traffic_class = 0; | |
542 | p->dscp[i].color = e_RTE_METER_GREEN; | |
543 | } | |
544 | } | |
545 | ||
546 | static void *pipeline_fa_init(struct pipeline_params *params, | |
547 | __rte_unused void *arg) | |
548 | { | |
549 | struct pipeline *p; | |
550 | struct pipeline_flow_actions *p_fa; | |
551 | uint32_t size, i; | |
552 | ||
553 | /* Check input arguments */ | |
554 | if (params == NULL) | |
555 | return NULL; | |
556 | ||
557 | if (params->n_ports_in != params->n_ports_out) | |
558 | return NULL; | |
559 | ||
560 | /* Memory allocation */ | |
561 | size = RTE_CACHE_LINE_ROUNDUP( | |
562 | sizeof(struct pipeline_flow_actions)); | |
563 | p = rte_zmalloc(NULL, size, RTE_CACHE_LINE_SIZE); | |
564 | if (p == NULL) | |
565 | return NULL; | |
566 | p_fa = (struct pipeline_flow_actions *) p; | |
567 | ||
568 | strcpy(p->name, params->name); | |
569 | p->log_level = params->log_level; | |
570 | ||
571 | PLOG(p, HIGH, "Flow actions"); | |
572 | ||
573 | /* Parse arguments */ | |
574 | if (pipeline_fa_parse_args(&p_fa->params, params)) | |
575 | return NULL; | |
576 | ||
577 | dscp_init(p_fa); | |
578 | ||
579 | /* Pipeline */ | |
580 | { | |
581 | struct rte_pipeline_params pipeline_params = { | |
582 | .name = params->name, | |
583 | .socket_id = params->socket_id, | |
584 | .offset_port_id = 0, | |
585 | }; | |
586 | ||
587 | p->p = rte_pipeline_create(&pipeline_params); | |
588 | if (p->p == NULL) { | |
589 | rte_free(p); | |
590 | return NULL; | |
591 | } | |
592 | } | |
593 | ||
594 | /* Input ports */ | |
595 | p->n_ports_in = params->n_ports_in; | |
596 | for (i = 0; i < p->n_ports_in; i++) { | |
597 | struct rte_pipeline_port_in_params port_params = { | |
598 | .ops = pipeline_port_in_params_get_ops( | |
599 | ¶ms->port_in[i]), | |
600 | .arg_create = pipeline_port_in_params_convert( | |
601 | ¶ms->port_in[i]), | |
602 | .f_action = NULL, | |
603 | .arg_ah = NULL, | |
604 | .burst_size = params->port_in[i].burst_size, | |
605 | }; | |
606 | ||
607 | int status = rte_pipeline_port_in_create(p->p, | |
608 | &port_params, | |
609 | &p->port_in_id[i]); | |
610 | ||
611 | if (status) { | |
612 | rte_pipeline_free(p->p); | |
613 | rte_free(p); | |
614 | return NULL; | |
615 | } | |
616 | } | |
617 | ||
618 | /* Output ports */ | |
619 | p->n_ports_out = params->n_ports_out; | |
620 | for (i = 0; i < p->n_ports_out; i++) { | |
621 | struct rte_pipeline_port_out_params port_params = { | |
622 | .ops = pipeline_port_out_params_get_ops( | |
623 | ¶ms->port_out[i]), | |
624 | .arg_create = pipeline_port_out_params_convert( | |
625 | ¶ms->port_out[i]), | |
626 | .f_action = NULL, | |
627 | .arg_ah = NULL, | |
628 | }; | |
629 | ||
630 | int status = rte_pipeline_port_out_create(p->p, | |
631 | &port_params, | |
632 | &p->port_out_id[i]); | |
633 | ||
634 | if (status) { | |
635 | rte_pipeline_free(p->p); | |
636 | rte_free(p); | |
637 | return NULL; | |
638 | } | |
639 | } | |
640 | ||
641 | /* Tables */ | |
642 | p->n_tables = 1; | |
643 | { | |
644 | struct rte_table_array_params table_array_params = { | |
645 | .n_entries = p_fa->params.n_flows, | |
646 | .offset = p_fa->params.flow_id_offset, | |
647 | }; | |
648 | ||
649 | struct rte_pipeline_table_params table_params = { | |
650 | .ops = &rte_table_array_ops, | |
651 | .arg_create = &table_array_params, | |
652 | .f_action_hit = get_fa_table_ah_hit(p_fa), | |
653 | .f_action_miss = NULL, | |
654 | .arg_ah = p_fa, | |
655 | .action_data_size = | |
656 | sizeof(struct flow_table_entry) - | |
657 | sizeof(struct rte_pipeline_table_entry), | |
658 | }; | |
659 | ||
660 | int status; | |
661 | ||
662 | status = rte_pipeline_table_create(p->p, | |
663 | &table_params, | |
664 | &p->table_id[0]); | |
665 | ||
666 | if (status) { | |
667 | rte_pipeline_free(p->p); | |
668 | rte_free(p); | |
669 | return NULL; | |
670 | } | |
671 | } | |
672 | ||
673 | /* Connecting input ports to tables */ | |
674 | for (i = 0; i < p->n_ports_in; i++) { | |
675 | int status = rte_pipeline_port_in_connect_to_table(p->p, | |
676 | p->port_in_id[i], | |
677 | p->table_id[0]); | |
678 | ||
679 | if (status) { | |
680 | rte_pipeline_free(p->p); | |
681 | rte_free(p); | |
682 | return NULL; | |
683 | } | |
684 | } | |
685 | ||
686 | /* Enable input ports */ | |
687 | for (i = 0; i < p->n_ports_in; i++) { | |
688 | int status = rte_pipeline_port_in_enable(p->p, | |
689 | p->port_in_id[i]); | |
690 | ||
691 | if (status) { | |
692 | rte_pipeline_free(p->p); | |
693 | rte_free(p); | |
694 | return NULL; | |
695 | } | |
696 | } | |
697 | ||
698 | /* Initialize table entries */ | |
699 | for (i = 0; i < p_fa->params.n_flows; i++) { | |
700 | struct rte_table_array_key key = { | |
701 | .pos = i, | |
702 | }; | |
703 | ||
704 | struct flow_table_entry entry; | |
705 | struct rte_pipeline_table_entry *entry_ptr; | |
706 | int key_found, status; | |
707 | ||
708 | flow_table_entry_set_default(p_fa, &entry); | |
709 | ||
710 | status = rte_pipeline_table_entry_add(p->p, | |
711 | p->table_id[0], | |
712 | &key, | |
713 | (struct rte_pipeline_table_entry *) &entry, | |
714 | &key_found, | |
715 | &entry_ptr); | |
716 | ||
717 | if (status) { | |
718 | rte_pipeline_free(p->p); | |
719 | rte_free(p); | |
720 | return NULL; | |
721 | } | |
722 | } | |
723 | ||
724 | /* Check pipeline consistency */ | |
725 | if (rte_pipeline_check(p->p) < 0) { | |
726 | rte_pipeline_free(p->p); | |
727 | rte_free(p); | |
728 | return NULL; | |
729 | } | |
730 | ||
731 | /* Message queues */ | |
732 | p->n_msgq = params->n_msgq; | |
733 | for (i = 0; i < p->n_msgq; i++) | |
734 | p->msgq_in[i] = params->msgq_in[i]; | |
735 | for (i = 0; i < p->n_msgq; i++) | |
736 | p->msgq_out[i] = params->msgq_out[i]; | |
737 | ||
738 | /* Message handlers */ | |
739 | memcpy(p->handlers, handlers, sizeof(p->handlers)); | |
740 | memcpy(p_fa->custom_handlers, | |
741 | custom_handlers, | |
742 | sizeof(p_fa->custom_handlers)); | |
743 | ||
744 | return p; | |
745 | } | |
746 | ||
747 | static int | |
748 | pipeline_fa_free(void *pipeline) | |
749 | { | |
750 | struct pipeline *p = (struct pipeline *) pipeline; | |
751 | ||
752 | /* Check input arguments */ | |
753 | if (p == NULL) | |
754 | return -1; | |
755 | ||
756 | /* Free resources */ | |
757 | rte_pipeline_free(p->p); | |
758 | rte_free(p); | |
759 | return 0; | |
760 | } | |
761 | ||
762 | static int | |
763 | pipeline_fa_timer(void *pipeline) | |
764 | { | |
765 | struct pipeline *p = (struct pipeline *) pipeline; | |
766 | ||
767 | pipeline_msg_req_handle(p); | |
768 | rte_pipeline_flush(p->p); | |
769 | ||
770 | return 0; | |
771 | } | |
772 | ||
773 | void * | |
774 | pipeline_fa_msg_req_custom_handler(struct pipeline *p, void *msg) | |
775 | { | |
776 | struct pipeline_flow_actions *p_fa = | |
777 | (struct pipeline_flow_actions *) p; | |
778 | struct pipeline_custom_msg_req *req = msg; | |
779 | pipeline_msg_req_handler f_handle; | |
780 | ||
781 | f_handle = (req->subtype < PIPELINE_FA_MSG_REQS) ? | |
782 | p_fa->custom_handlers[req->subtype] : | |
783 | pipeline_msg_req_invalid_handler; | |
784 | ||
785 | if (f_handle == NULL) | |
786 | f_handle = pipeline_msg_req_invalid_handler; | |
787 | ||
788 | return f_handle(p, req); | |
789 | } | |
790 | ||
791 | void * | |
792 | pipeline_fa_msg_req_flow_config_handler(struct pipeline *p, void *msg) | |
793 | { | |
794 | struct pipeline_flow_actions *p_fa = (struct pipeline_flow_actions *) p; | |
795 | struct pipeline_fa_flow_config_msg_req *req = msg; | |
796 | struct pipeline_fa_flow_config_msg_rsp *rsp = msg; | |
797 | struct flow_table_entry *entry; | |
798 | uint32_t mask, i; | |
799 | ||
800 | /* Set flow table entry to default if not configured before */ | |
801 | if (req->entry_ptr == NULL) { | |
802 | struct rte_table_array_key key = { | |
803 | .pos = req->flow_id % p_fa->params.n_flows, | |
804 | }; | |
805 | ||
806 | struct flow_table_entry default_entry; | |
807 | ||
808 | int key_found, status; | |
809 | ||
810 | flow_table_entry_set_default(p_fa, &default_entry); | |
811 | ||
812 | status = rte_pipeline_table_entry_add(p->p, | |
813 | p->table_id[0], | |
814 | &key, | |
815 | (struct rte_pipeline_table_entry *) &default_entry, | |
816 | &key_found, | |
817 | (struct rte_pipeline_table_entry **) &entry); | |
818 | if (status) { | |
819 | rsp->status = -1; | |
820 | return rsp; | |
821 | } | |
822 | } else | |
823 | entry = (struct flow_table_entry *) req->entry_ptr; | |
824 | ||
825 | /* Meter */ | |
826 | for (i = 0, mask = 1; i < PIPELINE_FA_N_TC_MAX; i++, mask <<= 1) { | |
827 | int status; | |
828 | ||
829 | if ((mask & req->meter_update_mask) == 0) | |
830 | continue; | |
831 | ||
832 | status = flow_table_entry_set_meter(entry, i, &req->params); | |
833 | if (status) { | |
834 | rsp->status = -1; | |
835 | return rsp; | |
836 | } | |
837 | } | |
838 | ||
839 | /* Policer */ | |
840 | for (i = 0, mask = 1; i < PIPELINE_FA_N_TC_MAX; i++, mask <<= 1) { | |
841 | if ((mask & req->policer_update_mask) == 0) | |
842 | continue; | |
843 | ||
844 | flow_table_entry_set_policer(entry, i, &req->params); | |
845 | } | |
846 | ||
847 | /* Port */ | |
848 | if (req->port_update) | |
849 | flow_table_entry_set_port_id(p_fa, entry, &req->params); | |
850 | ||
851 | /* Response */ | |
852 | rsp->status = 0; | |
853 | rsp->entry_ptr = (void *) entry; | |
854 | return rsp; | |
855 | } | |
856 | ||
857 | void * | |
858 | pipeline_fa_msg_req_flow_config_bulk_handler(struct pipeline *p, void *msg) | |
859 | { | |
860 | struct pipeline_flow_actions *p_fa = (struct pipeline_flow_actions *) p; | |
861 | struct pipeline_fa_flow_config_bulk_msg_req *req = msg; | |
862 | struct pipeline_fa_flow_config_bulk_msg_rsp *rsp = msg; | |
863 | uint32_t i; | |
864 | ||
865 | for (i = 0; i < req->n_flows; i++) { | |
866 | struct flow_table_entry *entry; | |
867 | uint32_t j, mask; | |
868 | ||
869 | /* Set flow table entry to default if not configured before */ | |
870 | if (req->entry_ptr[i] == NULL) { | |
871 | struct rte_table_array_key key = { | |
872 | .pos = req->flow_id[i] % p_fa->params.n_flows, | |
873 | }; | |
874 | ||
875 | struct flow_table_entry entry_to_add; | |
876 | ||
877 | int key_found, status; | |
878 | ||
879 | flow_table_entry_set_default(p_fa, &entry_to_add); | |
880 | ||
881 | status = rte_pipeline_table_entry_add(p->p, | |
882 | p->table_id[0], | |
883 | &key, | |
884 | (struct rte_pipeline_table_entry *) &entry_to_add, | |
885 | &key_found, | |
886 | (struct rte_pipeline_table_entry **) &entry); | |
887 | if (status) { | |
888 | rsp->n_flows = i; | |
889 | return rsp; | |
890 | } | |
891 | ||
892 | req->entry_ptr[i] = (void *) entry; | |
893 | } else | |
894 | entry = (struct flow_table_entry *) req->entry_ptr[i]; | |
895 | ||
896 | /* Meter */ | |
897 | for (j = 0, mask = 1; | |
898 | j < PIPELINE_FA_N_TC_MAX; | |
899 | j++, mask <<= 1) { | |
900 | int status; | |
901 | ||
902 | if ((mask & req->meter_update_mask) == 0) | |
903 | continue; | |
904 | ||
905 | status = flow_table_entry_set_meter(entry, | |
906 | j, &req->params[i]); | |
907 | if (status) { | |
908 | rsp->n_flows = i; | |
909 | return rsp; | |
910 | } | |
911 | } | |
912 | ||
913 | /* Policer */ | |
914 | for (j = 0, mask = 1; | |
915 | j < PIPELINE_FA_N_TC_MAX; | |
916 | j++, mask <<= 1) { | |
917 | if ((mask & req->policer_update_mask) == 0) | |
918 | continue; | |
919 | ||
920 | flow_table_entry_set_policer(entry, | |
921 | j, &req->params[i]); | |
922 | } | |
923 | ||
924 | /* Port */ | |
925 | if (req->port_update) | |
926 | flow_table_entry_set_port_id(p_fa, | |
927 | entry, &req->params[i]); | |
928 | } | |
929 | ||
930 | /* Response */ | |
931 | rsp->n_flows = i; | |
932 | return rsp; | |
933 | } | |
934 | ||
935 | void * | |
936 | pipeline_fa_msg_req_dscp_config_handler(struct pipeline *p, void *msg) | |
937 | { | |
938 | struct pipeline_flow_actions *p_fa = (struct pipeline_flow_actions *) p; | |
939 | struct pipeline_fa_dscp_config_msg_req *req = msg; | |
940 | struct pipeline_fa_dscp_config_msg_rsp *rsp = msg; | |
941 | ||
942 | /* Check request */ | |
943 | if ((req->dscp >= PIPELINE_FA_N_DSCP) || | |
944 | (req->traffic_class >= PIPELINE_FA_N_TC_MAX) || | |
945 | (req->color >= e_RTE_METER_COLORS)) { | |
946 | rsp->status = -1; | |
947 | return rsp; | |
948 | } | |
949 | ||
950 | p_fa->dscp[req->dscp].traffic_class = req->traffic_class; | |
951 | p_fa->dscp[req->dscp].color = req->color; | |
952 | rsp->status = 0; | |
953 | return rsp; | |
954 | } | |
955 | ||
956 | void * | |
957 | pipeline_fa_msg_req_policer_stats_read_handler(__rte_unused struct pipeline *p, | |
958 | void *msg) | |
959 | { | |
960 | struct pipeline_fa_policer_stats_msg_req *req = msg; | |
961 | struct pipeline_fa_policer_stats_msg_rsp *rsp = msg; | |
962 | ||
963 | struct flow_table_entry *entry = req->entry_ptr; | |
964 | uint32_t policer_id = req->policer_id; | |
965 | int clear = req->clear; | |
966 | ||
967 | /* Check request */ | |
968 | if ((req->entry_ptr == NULL) || | |
969 | (req->policer_id >= PIPELINE_FA_N_TC_MAX)) { | |
970 | rsp->status = -1; | |
971 | return rsp; | |
972 | } | |
973 | ||
974 | memcpy(&rsp->stats, | |
975 | &entry->mp[policer_id].stats, | |
976 | sizeof(rsp->stats)); | |
977 | if (clear) | |
978 | memset(&entry->mp[policer_id].stats, | |
979 | 0, sizeof(entry->mp[policer_id].stats)); | |
980 | rsp->status = 0; | |
981 | return rsp; | |
982 | } | |
983 | ||
984 | struct pipeline_be_ops pipeline_flow_actions_be_ops = { | |
985 | .f_init = pipeline_fa_init, | |
986 | .f_free = pipeline_fa_free, | |
987 | .f_run = NULL, | |
988 | .f_timer = pipeline_fa_timer, | |
989 | }; |