Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright 2017 6WIND S.A.
3 : : * Copyright 2017 Mellanox Technologies, Ltd
4 : : */
5 : :
6 : : #include <errno.h>
7 : : #include <string.h>
8 : : #include <unistd.h>
9 : : #include <sys/queue.h>
10 : : #include <sys/resource.h>
11 : :
12 : : #include <rte_byteorder.h>
13 : : #include <rte_jhash.h>
14 : : #include <rte_thash.h>
15 : : #include <rte_random.h>
16 : : #include <rte_malloc.h>
17 : : #include <rte_eth_tap.h>
18 : : #include <rte_uuid.h>
19 : :
20 : : #include <tap_flow.h>
21 : : #include <tap_tcmsgs.h>
22 : : #include <tap_rss.h>
23 : :
24 : : #ifdef HAVE_BPF_RSS
25 : : /* Workaround for warning in bpftool generated skeleton code */
26 : : __rte_diagnostic_push
27 : : __rte_diagnostic_ignored_wcast_qual
28 : : #include "tap_rss.skel.h"
29 : : __rte_diagnostic_pop
30 : : #endif
31 : :
32 : : #define ISOLATE_HANDLE 1
33 : : #define REMOTE_PROMISCUOUS_HANDLE 2
34 : :
35 : : struct rte_flow {
36 : : LIST_ENTRY(rte_flow) next; /* Pointer to the next rte_flow structure */
37 : : struct rte_flow *remote_flow; /* associated remote flow */
38 : : struct tap_nlmsg msg;
39 : : };
40 : :
41 : : struct convert_data {
42 : : uint16_t eth_type;
43 : : uint16_t ip_proto;
44 : : uint8_t vlan;
45 : : struct rte_flow *flow;
46 : : };
47 : :
48 : : struct remote_rule {
49 : : struct rte_flow_attr attr;
50 : : struct rte_flow_item items[2];
51 : : struct rte_flow_action actions[2];
52 : : int mirred;
53 : : };
54 : :
55 : : struct action_data {
56 : : char id[16];
57 : :
58 : : union {
59 : : struct tc_gact gact;
60 : : struct tc_mirred mirred;
61 : : struct skbedit {
62 : : struct tc_skbedit skbedit;
63 : : uint16_t queue;
64 : : uint32_t mark;
65 : : } skbedit;
66 : : #ifdef HAVE_BPF_RSS
67 : : struct bpf {
68 : : struct tc_act_bpf bpf;
69 : : uint32_t map_key;
70 : : int bpf_fd;
71 : : const char *annotation;
72 : : } bpf;
73 : : #endif
74 : : };
75 : : };
76 : :
77 : : static int tap_flow_create_eth(const struct rte_flow_item *item, struct convert_data *info);
78 : : static int tap_flow_create_vlan(const struct rte_flow_item *item, struct convert_data *info);
79 : : static int tap_flow_create_ipv4(const struct rte_flow_item *item, struct convert_data *info);
80 : : static int tap_flow_create_ipv6(const struct rte_flow_item *item, struct convert_data *info);
81 : : static int tap_flow_create_udp(const struct rte_flow_item *item, struct convert_data *info);
82 : : static int tap_flow_create_tcp(const struct rte_flow_item *item, struct convert_data *info);
83 : : static int
84 : : tap_flow_validate(struct rte_eth_dev *dev,
85 : : const struct rte_flow_attr *attr,
86 : : const struct rte_flow_item items[],
87 : : const struct rte_flow_action actions[],
88 : : struct rte_flow_error *error);
89 : :
90 : : static struct rte_flow *
91 : : tap_flow_create(struct rte_eth_dev *dev,
92 : : const struct rte_flow_attr *attr,
93 : : const struct rte_flow_item items[],
94 : : const struct rte_flow_action actions[],
95 : : struct rte_flow_error *error);
96 : :
97 : : static void
98 : : tap_flow_free(struct pmd_internals *pmd,
99 : : struct rte_flow *flow);
100 : :
101 : : static int
102 : : tap_flow_destroy(struct rte_eth_dev *dev,
103 : : struct rte_flow *flow,
104 : : struct rte_flow_error *error);
105 : :
106 : : static int
107 : : tap_flow_isolate(struct rte_eth_dev *dev,
108 : : int set,
109 : : struct rte_flow_error *error);
110 : :
111 : : #ifdef HAVE_BPF_RSS
112 : : static int rss_enable(struct pmd_internals *pmd, struct rte_flow_error *error);
113 : : static int rss_add_actions(struct rte_flow *flow, struct pmd_internals *pmd,
114 : : const struct rte_flow_action_rss *rss,
115 : : struct rte_flow_error *error);
116 : : #endif
117 : :
118 : : static const struct rte_flow_ops tap_flow_ops = {
119 : : .validate = tap_flow_validate,
120 : : .create = tap_flow_create,
121 : : .destroy = tap_flow_destroy,
122 : : .flush = tap_flow_flush,
123 : : .isolate = tap_flow_isolate,
124 : : };
125 : :
126 : : /* Static initializer for items. */
127 : : #define ITEMS(...) \
128 : : (const enum rte_flow_item_type []){ \
129 : : __VA_ARGS__, RTE_FLOW_ITEM_TYPE_END, \
130 : : }
131 : :
132 : : /* Structure to generate a simple graph of layers supported by the NIC. */
133 : : struct tap_flow_items {
134 : : /* Bit-mask corresponding to what is supported for this item. */
135 : : const void *mask;
136 : : const unsigned int mask_sz; /* Bit-mask size in bytes. */
137 : : /*
138 : : * Bit-mask corresponding to the default mask, if none is provided
139 : : * along with the item.
140 : : */
141 : : const void *default_mask;
142 : : /* Conversion function from rte_flow to netlink attributes. */
143 : : int (*convert)(const struct rte_flow_item *item, struct convert_data *info);
144 : :
145 : : /* List of possible following items. */
146 : : const enum rte_flow_item_type *const items;
147 : : };
148 : :
149 : : /* Graph of supported items and associated actions. */
150 : : static const struct tap_flow_items tap_flow_items[] = {
151 : : [RTE_FLOW_ITEM_TYPE_END] = {
152 : : .items = ITEMS(RTE_FLOW_ITEM_TYPE_ETH),
153 : : },
154 : : [RTE_FLOW_ITEM_TYPE_ETH] = {
155 : : .items = ITEMS(
156 : : RTE_FLOW_ITEM_TYPE_VLAN,
157 : : RTE_FLOW_ITEM_TYPE_IPV4,
158 : : RTE_FLOW_ITEM_TYPE_IPV6),
159 : : .mask = &(const struct rte_flow_item_eth){
160 : : .hdr.dst_addr.addr_bytes = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
161 : : .hdr.src_addr.addr_bytes = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
162 : : .hdr.ether_type = -1,
163 : : },
164 : : .mask_sz = sizeof(struct rte_flow_item_eth),
165 : : .default_mask = &rte_flow_item_eth_mask,
166 : : .convert = tap_flow_create_eth,
167 : : },
168 : : [RTE_FLOW_ITEM_TYPE_VLAN] = {
169 : : .items = ITEMS(RTE_FLOW_ITEM_TYPE_IPV4,
170 : : RTE_FLOW_ITEM_TYPE_IPV6),
171 : : .mask = &(const struct rte_flow_item_vlan){
172 : : /* DEI matching is not supported */
173 : : #if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
174 : : .hdr.vlan_tci = 0xffef,
175 : : #else
176 : : .hdr.vlan_tci = 0xefff,
177 : : #endif
178 : : .hdr.eth_proto = -1,
179 : : },
180 : : .mask_sz = sizeof(struct rte_flow_item_vlan),
181 : : .default_mask = &rte_flow_item_vlan_mask,
182 : : .convert = tap_flow_create_vlan,
183 : : },
184 : : [RTE_FLOW_ITEM_TYPE_IPV4] = {
185 : : .items = ITEMS(RTE_FLOW_ITEM_TYPE_UDP,
186 : : RTE_FLOW_ITEM_TYPE_TCP),
187 : : .mask = &(const struct rte_flow_item_ipv4){
188 : : .hdr = {
189 : : .src_addr = -1,
190 : : .dst_addr = -1,
191 : : .next_proto_id = -1,
192 : : },
193 : : },
194 : : .mask_sz = sizeof(struct rte_flow_item_ipv4),
195 : : .default_mask = &rte_flow_item_ipv4_mask,
196 : : .convert = tap_flow_create_ipv4,
197 : : },
198 : : [RTE_FLOW_ITEM_TYPE_IPV6] = {
199 : : .items = ITEMS(RTE_FLOW_ITEM_TYPE_UDP,
200 : : RTE_FLOW_ITEM_TYPE_TCP),
201 : : .mask = &(const struct rte_flow_item_ipv6){
202 : : .hdr = {
203 : : .src_addr = RTE_IPV6_MASK_FULL,
204 : : .dst_addr = RTE_IPV6_MASK_FULL,
205 : : .proto = -1,
206 : : },
207 : : },
208 : : .mask_sz = sizeof(struct rte_flow_item_ipv6),
209 : : .default_mask = &rte_flow_item_ipv6_mask,
210 : : .convert = tap_flow_create_ipv6,
211 : : },
212 : : [RTE_FLOW_ITEM_TYPE_UDP] = {
213 : : .mask = &(const struct rte_flow_item_udp){
214 : : .hdr = {
215 : : .src_port = -1,
216 : : .dst_port = -1,
217 : : },
218 : : },
219 : : .mask_sz = sizeof(struct rte_flow_item_udp),
220 : : .default_mask = &rte_flow_item_udp_mask,
221 : : .convert = tap_flow_create_udp,
222 : : },
223 : : [RTE_FLOW_ITEM_TYPE_TCP] = {
224 : : .mask = &(const struct rte_flow_item_tcp){
225 : : .hdr = {
226 : : .src_port = -1,
227 : : .dst_port = -1,
228 : : },
229 : : },
230 : : .mask_sz = sizeof(struct rte_flow_item_tcp),
231 : : .default_mask = &rte_flow_item_tcp_mask,
232 : : .convert = tap_flow_create_tcp,
233 : : },
234 : : };
235 : :
236 : : /*
237 : : * TC rules, by growing priority
238 : : *
239 : : * Remote netdevice Tap netdevice
240 : : * +-------------+-------------+ +-------------+-------------+
241 : : * | Ingress | Egress | | Ingress | Egress |
242 : : * |-------------|-------------| |-------------|-------------|
243 : : * | | \ / | | | REMOTE TX | prio 1
244 : : * | | \ / | | | \ / | prio 2
245 : : * | EXPLICIT | \ / | | EXPLICIT | \ / | .
246 : : * | | \ / | | | \ / | .
247 : : * | RULES | X | | RULES | X | .
248 : : * | . | / \ | | . | / \ | .
249 : : * | . | / \ | | . | / \ | .
250 : : * | . | / \ | | . | / \ | .
251 : : * | . | / \ | | . | / \ | .
252 : : *
253 : : * .... .... .... ....
254 : : *
255 : : * | . | \ / | | . | \ / | .
256 : : * | . | \ / | | . | \ / | .
257 : : * | | \ / | | | \ / |
258 : : * | LOCAL_MAC | \ / | | \ / | \ / | last prio - 5
259 : : * | PROMISC | X | | \ / | X | last prio - 4
260 : : * | ALLMULTI | / \ | | X | / \ | last prio - 3
261 : : * | BROADCAST | / \ | | / \ | / \ | last prio - 2
262 : : * | BROADCASTV6 | / \ | | / \ | / \ | last prio - 1
263 : : * | xx | / \ | | ISOLATE | / \ | last prio
264 : : * +-------------+-------------+ +-------------+-------------+
265 : : *
266 : : * The implicit flow rules are stored in a list in with mandatorily the last two
267 : : * being the ISOLATE and REMOTE_TX rules. e.g.:
268 : : *
269 : : * LOCAL_MAC -> BROADCAST -> BROADCASTV6 -> REMOTE_TX -> ISOLATE -> NULL
270 : : *
271 : : * That enables tap_flow_isolate() to remove implicit rules by popping the list
272 : : * head and remove it as long as it applies on the remote netdevice. The
273 : : * implicit rule for TX redirection is not removed, as isolate concerns only
274 : : * incoming traffic.
275 : : */
276 : :
277 : : static struct remote_rule implicit_rte_flows[TAP_REMOTE_MAX_IDX] = {
278 : : [TAP_REMOTE_LOCAL_MAC] = {
279 : : .attr = {
280 : : .group = MAX_GROUP,
281 : : .priority = PRIORITY_MASK - TAP_REMOTE_LOCAL_MAC,
282 : : .ingress = 1,
283 : : },
284 : : .items[0] = {
285 : : .type = RTE_FLOW_ITEM_TYPE_ETH,
286 : : .mask = &(const struct rte_flow_item_eth){
287 : : .hdr.dst_addr.addr_bytes = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
288 : : },
289 : : },
290 : : .items[1] = {
291 : : .type = RTE_FLOW_ITEM_TYPE_END,
292 : : },
293 : : .mirred = TCA_EGRESS_REDIR,
294 : : },
295 : : [TAP_REMOTE_BROADCAST] = {
296 : : .attr = {
297 : : .group = MAX_GROUP,
298 : : .priority = PRIORITY_MASK - TAP_REMOTE_BROADCAST,
299 : : .ingress = 1,
300 : : },
301 : : .items[0] = {
302 : : .type = RTE_FLOW_ITEM_TYPE_ETH,
303 : : .mask = &(const struct rte_flow_item_eth){
304 : : .hdr.dst_addr.addr_bytes = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
305 : : },
306 : : .spec = &(const struct rte_flow_item_eth){
307 : : .hdr.dst_addr.addr_bytes = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
308 : : },
309 : : },
310 : : .items[1] = {
311 : : .type = RTE_FLOW_ITEM_TYPE_END,
312 : : },
313 : : .mirred = TCA_EGRESS_MIRROR,
314 : : },
315 : : [TAP_REMOTE_BROADCASTV6] = {
316 : : .attr = {
317 : : .group = MAX_GROUP,
318 : : .priority = PRIORITY_MASK - TAP_REMOTE_BROADCASTV6,
319 : : .ingress = 1,
320 : : },
321 : : .items[0] = {
322 : : .type = RTE_FLOW_ITEM_TYPE_ETH,
323 : : .mask = &(const struct rte_flow_item_eth){
324 : : .hdr.dst_addr.addr_bytes = { 0x33, 0x33, 0x00, 0x00, 0x00, 0x00 },
325 : : },
326 : : .spec = &(const struct rte_flow_item_eth){
327 : : .hdr.dst_addr.addr_bytes = { 0x33, 0x33, 0x00, 0x00, 0x00, 0x00 },
328 : : },
329 : : },
330 : : .items[1] = {
331 : : .type = RTE_FLOW_ITEM_TYPE_END,
332 : : },
333 : : .mirred = TCA_EGRESS_MIRROR,
334 : : },
335 : : [TAP_REMOTE_PROMISC] = {
336 : : .attr = {
337 : : .group = MAX_GROUP,
338 : : .priority = PRIORITY_MASK - TAP_REMOTE_PROMISC,
339 : : .ingress = 1,
340 : : },
341 : : .items[0] = {
342 : : .type = RTE_FLOW_ITEM_TYPE_VOID,
343 : : },
344 : : .items[1] = {
345 : : .type = RTE_FLOW_ITEM_TYPE_END,
346 : : },
347 : : .mirred = TCA_EGRESS_MIRROR,
348 : : },
349 : : [TAP_REMOTE_ALLMULTI] = {
350 : : .attr = {
351 : : .group = MAX_GROUP,
352 : : .priority = PRIORITY_MASK - TAP_REMOTE_ALLMULTI,
353 : : .ingress = 1,
354 : : },
355 : : .items[0] = {
356 : : .type = RTE_FLOW_ITEM_TYPE_ETH,
357 : : .mask = &(const struct rte_flow_item_eth){
358 : : .hdr.dst_addr.addr_bytes = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 },
359 : : },
360 : : .spec = &(const struct rte_flow_item_eth){
361 : : .hdr.dst_addr.addr_bytes = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 },
362 : : },
363 : : },
364 : : .items[1] = {
365 : : .type = RTE_FLOW_ITEM_TYPE_END,
366 : : },
367 : : .mirred = TCA_EGRESS_MIRROR,
368 : : },
369 : : [TAP_REMOTE_TX] = {
370 : : .attr = {
371 : : .group = 0,
372 : : .priority = TAP_REMOTE_TX,
373 : : .egress = 1,
374 : : },
375 : : .items[0] = {
376 : : .type = RTE_FLOW_ITEM_TYPE_VOID,
377 : : },
378 : : .items[1] = {
379 : : .type = RTE_FLOW_ITEM_TYPE_END,
380 : : },
381 : : .mirred = TCA_EGRESS_MIRROR,
382 : : },
383 : : [TAP_ISOLATE] = {
384 : : .attr = {
385 : : .group = MAX_GROUP,
386 : : .priority = PRIORITY_MASK - TAP_ISOLATE,
387 : : .ingress = 1,
388 : : },
389 : : .items[0] = {
390 : : .type = RTE_FLOW_ITEM_TYPE_VOID,
391 : : },
392 : : .items[1] = {
393 : : .type = RTE_FLOW_ITEM_TYPE_END,
394 : : },
395 : : },
396 : : };
397 : :
398 : : /**
399 : : * Make as much checks as possible on an Ethernet item, and if a flow is
400 : : * provided, fill it appropriately with Ethernet info.
401 : : *
402 : : * @param[in] item
403 : : * Item specification.
404 : : * @param[in, out] data
405 : : * Additional data structure to tell next layers we've been here.
406 : : *
407 : : * @return
408 : : * 0 if checks are alright, -1 otherwise.
409 : : */
410 : : static int
411 : 0 : tap_flow_create_eth(const struct rte_flow_item *item, struct convert_data *info)
412 : : {
413 : 0 : const struct rte_flow_item_eth *spec = item->spec;
414 : 0 : const struct rte_flow_item_eth *mask = item->mask;
415 : 0 : struct rte_flow *flow = info->flow;
416 : : struct tap_nlmsg *msg;
417 : :
418 : : /* use default mask if none provided */
419 [ # # ]: 0 : if (!mask)
420 : : mask = tap_flow_items[RTE_FLOW_ITEM_TYPE_ETH].default_mask;
421 : : /* TC does not support eth_type masking. Only accept if exact match. */
422 [ # # ]: 0 : if (mask->hdr.ether_type && mask->hdr.ether_type != 0xffff)
423 : : return -1;
424 [ # # ]: 0 : if (!spec)
425 : : return 0;
426 : : /* store eth_type for consistency if ipv4/6 pattern item comes next */
427 [ # # ]: 0 : if (spec->hdr.ether_type & mask->hdr.ether_type)
428 : 0 : info->eth_type = spec->hdr.ether_type;
429 [ # # ]: 0 : if (!flow)
430 : : return 0;
431 [ # # ]: 0 : msg = &flow->msg;
432 [ # # ]: 0 : if (!rte_is_zero_ether_addr(&mask->hdr.dst_addr)) {
433 : 0 : tap_nlattr_add(msg, TCA_FLOWER_KEY_ETH_DST, RTE_ETHER_ADDR_LEN,
434 : 0 : &spec->hdr.dst_addr.addr_bytes);
435 : 0 : tap_nlattr_add(msg, TCA_FLOWER_KEY_ETH_DST_MASK, RTE_ETHER_ADDR_LEN,
436 : 0 : &mask->hdr.dst_addr.addr_bytes);
437 : : }
438 [ # # ]: 0 : if (!rte_is_zero_ether_addr(&mask->hdr.src_addr)) {
439 : 0 : tap_nlattr_add(msg, TCA_FLOWER_KEY_ETH_SRC, RTE_ETHER_ADDR_LEN,
440 : 0 : &spec->hdr.src_addr.addr_bytes);
441 : 0 : tap_nlattr_add(msg, TCA_FLOWER_KEY_ETH_SRC_MASK, RTE_ETHER_ADDR_LEN,
442 : 0 : &mask->hdr.src_addr.addr_bytes);
443 : : }
444 : : return 0;
445 : : }
446 : :
447 : : /**
448 : : * Make as much checks as possible on a VLAN item, and if a flow is provided,
449 : : * fill it appropriately with VLAN info.
450 : : *
451 : : * @param[in] item
452 : : * Item specification.
453 : : * @param[in, out] data
454 : : * Additional data structure to tell next layers we've been here.
455 : : *
456 : : * @return
457 : : * 0 if checks are alright, -1 otherwise.
458 : : */
459 : : static int
460 : 0 : tap_flow_create_vlan(const struct rte_flow_item *item, struct convert_data *info)
461 : : {
462 : 0 : const struct rte_flow_item_vlan *spec = item->spec;
463 : 0 : const struct rte_flow_item_vlan *mask = item->mask;
464 : 0 : struct rte_flow *flow = info->flow;
465 : : struct tap_nlmsg *msg;
466 : :
467 : : /* use default mask if none provided */
468 [ # # ]: 0 : if (!mask)
469 : : mask = tap_flow_items[RTE_FLOW_ITEM_TYPE_VLAN].default_mask;
470 : : /* Outer TPID cannot be matched. */
471 [ # # ]: 0 : if (info->eth_type)
472 : : return -1;
473 : : /* Double-tagging not supported. */
474 [ # # ]: 0 : if (info->vlan)
475 : : return -1;
476 : 0 : info->vlan = 1;
477 [ # # ]: 0 : if (mask->hdr.eth_proto) {
478 : : /* TC does not support partial eth_type masking */
479 [ # # ]: 0 : if (mask->hdr.eth_proto != RTE_BE16(0xffff))
480 : : return -1;
481 : 0 : info->eth_type = spec->hdr.eth_proto;
482 : : }
483 [ # # ]: 0 : if (!flow)
484 : : return 0;
485 : 0 : msg = &flow->msg;
486 : 0 : msg->t.tcm_info = TC_H_MAKE(msg->t.tcm_info, htons(ETH_P_8021Q));
487 : : #define VLAN_PRIO(tci) ((tci) >> 13)
488 : : #define VLAN_ID(tci) ((tci) & 0xfff)
489 [ # # ]: 0 : if (!spec)
490 : : return 0;
491 [ # # ]: 0 : if (spec->hdr.vlan_tci) {
492 [ # # ]: 0 : uint16_t tci = ntohs(spec->hdr.vlan_tci) & mask->hdr.vlan_tci;
493 : 0 : uint16_t prio = VLAN_PRIO(tci);
494 : 0 : uint8_t vid = VLAN_ID(tci);
495 : :
496 [ # # ]: 0 : if (prio)
497 : 0 : tap_nlattr_add8(msg, TCA_FLOWER_KEY_VLAN_PRIO, prio);
498 [ # # ]: 0 : if (vid)
499 : 0 : tap_nlattr_add16(msg, TCA_FLOWER_KEY_VLAN_ID, vid);
500 : : }
501 : : return 0;
502 : : }
503 : :
504 : : /**
505 : : * Make as much checks as possible on an IPv4 item, and if a flow is provided,
506 : : * fill it appropriately with IPv4 info.
507 : : *
508 : : * @param[in] item
509 : : * Item specification.
510 : : * @param[in, out] data
511 : : * Additional data structure to tell next layers we've been here.
512 : : *
513 : : * @return
514 : : * 0 if checks are alright, -1 otherwise.
515 : : */
516 : : static int
517 : 0 : tap_flow_create_ipv4(const struct rte_flow_item *item, struct convert_data *info)
518 : : {
519 : 0 : const struct rte_flow_item_ipv4 *spec = item->spec;
520 : 0 : const struct rte_flow_item_ipv4 *mask = item->mask;
521 : 0 : struct rte_flow *flow = info->flow;
522 : : struct tap_nlmsg *msg;
523 : :
524 : : /* use default mask if none provided */
525 [ # # ]: 0 : if (!mask)
526 : : mask = tap_flow_items[RTE_FLOW_ITEM_TYPE_IPV4].default_mask;
527 : : /* check that previous eth type is compatible with ipv4 */
528 [ # # # # ]: 0 : if (info->eth_type && info->eth_type != htons(ETH_P_IP))
529 : : return -1;
530 : : /* store ip_proto for consistency if udp/tcp pattern item comes next */
531 [ # # ]: 0 : if (spec)
532 : 0 : info->ip_proto = spec->hdr.next_proto_id;
533 [ # # ]: 0 : if (!flow)
534 : : return 0;
535 : 0 : msg = &flow->msg;
536 [ # # ]: 0 : if (!info->eth_type)
537 : 0 : info->eth_type = htons(ETH_P_IP);
538 [ # # ]: 0 : if (!spec)
539 : : return 0;
540 [ # # ]: 0 : if (mask->hdr.dst_addr) {
541 : 0 : tap_nlattr_add32(msg, TCA_FLOWER_KEY_IPV4_DST, spec->hdr.dst_addr);
542 : 0 : tap_nlattr_add32(msg, TCA_FLOWER_KEY_IPV4_DST_MASK, mask->hdr.dst_addr);
543 : : }
544 [ # # ]: 0 : if (mask->hdr.src_addr) {
545 : 0 : tap_nlattr_add32(msg, TCA_FLOWER_KEY_IPV4_SRC, spec->hdr.src_addr);
546 : 0 : tap_nlattr_add32(msg, TCA_FLOWER_KEY_IPV4_SRC_MASK, mask->hdr.src_addr);
547 : : }
548 [ # # ]: 0 : if (spec->hdr.next_proto_id)
549 : 0 : tap_nlattr_add8(msg, TCA_FLOWER_KEY_IP_PROTO, spec->hdr.next_proto_id);
550 : : return 0;
551 : : }
552 : :
553 : : /**
554 : : * Make as much checks as possible on an IPv6 item, and if a flow is provided,
555 : : * fill it appropriately with IPv6 info.
556 : : *
557 : : * @param[in] item
558 : : * Item specification.
559 : : * @param[in, out] data
560 : : * Additional data structure to tell next layers we've been here.
561 : : *
562 : : * @return
563 : : * 0 if checks are alright, -1 otherwise.
564 : : */
565 : : static int
566 : 0 : tap_flow_create_ipv6(const struct rte_flow_item *item, struct convert_data *info)
567 : : {
568 : 0 : const struct rte_flow_item_ipv6 *spec = item->spec;
569 : 0 : const struct rte_flow_item_ipv6 *mask = item->mask;
570 : 0 : struct rte_flow *flow = info->flow;
571 : 0 : uint8_t empty_addr[16] = { 0 };
572 : : struct tap_nlmsg *msg;
573 : :
574 : : /* use default mask if none provided */
575 [ # # ]: 0 : if (!mask)
576 : : mask = tap_flow_items[RTE_FLOW_ITEM_TYPE_IPV6].default_mask;
577 : : /* check that previous eth type is compatible with ipv6 */
578 [ # # # # ]: 0 : if (info->eth_type && info->eth_type != htons(ETH_P_IPV6))
579 : : return -1;
580 : : /* store ip_proto for consistency if udp/tcp pattern item comes next */
581 [ # # ]: 0 : if (spec)
582 : 0 : info->ip_proto = spec->hdr.proto;
583 [ # # ]: 0 : if (!flow)
584 : : return 0;
585 : 0 : msg = &flow->msg;
586 [ # # ]: 0 : if (!info->eth_type)
587 : 0 : info->eth_type = htons(ETH_P_IPV6);
588 [ # # ]: 0 : if (!spec)
589 : : return 0;
590 [ # # ]: 0 : if (memcmp(&mask->hdr.dst_addr, empty_addr, 16)) {
591 : 0 : tap_nlattr_add(msg, TCA_FLOWER_KEY_IPV6_DST, sizeof(spec->hdr.dst_addr),
592 : 0 : &spec->hdr.dst_addr);
593 : 0 : tap_nlattr_add(msg, TCA_FLOWER_KEY_IPV6_DST_MASK, sizeof(mask->hdr.dst_addr),
594 : : &mask->hdr.dst_addr);
595 : : }
596 [ # # ]: 0 : if (memcmp(&mask->hdr.src_addr, empty_addr, 16)) {
597 : 0 : tap_nlattr_add(msg, TCA_FLOWER_KEY_IPV6_SRC, sizeof(spec->hdr.src_addr),
598 : 0 : &spec->hdr.src_addr);
599 : 0 : tap_nlattr_add(msg, TCA_FLOWER_KEY_IPV6_SRC_MASK, sizeof(mask->hdr.src_addr),
600 : : &mask->hdr.src_addr);
601 : : }
602 [ # # ]: 0 : if (spec->hdr.proto)
603 : 0 : tap_nlattr_add8(msg, TCA_FLOWER_KEY_IP_PROTO, spec->hdr.proto);
604 : : return 0;
605 : : }
606 : :
607 : : /**
608 : : * Make as much checks as possible on a UDP item, and if a flow is provided,
609 : : * fill it appropriately with UDP info.
610 : : *
611 : : * @param[in] item
612 : : * Item specification.
613 : : * @param[in, out] data
614 : : * Additional data structure to tell next layers we've been here.
615 : : *
616 : : * @return
617 : : * 0 if checks are alright, -1 otherwise.
618 : : */
619 : : static int
620 : 0 : tap_flow_create_udp(const struct rte_flow_item *item, struct convert_data *info)
621 : : {
622 : 0 : const struct rte_flow_item_udp *spec = item->spec;
623 : 0 : const struct rte_flow_item_udp *mask = item->mask;
624 : 0 : struct rte_flow *flow = info->flow;
625 : : struct tap_nlmsg *msg;
626 : :
627 : : /* use default mask if none provided */
628 [ # # ]: 0 : if (!mask)
629 : : mask = tap_flow_items[RTE_FLOW_ITEM_TYPE_UDP].default_mask;
630 : : /* check that previous ip_proto is compatible with udp */
631 [ # # ]: 0 : if (info->ip_proto && info->ip_proto != IPPROTO_UDP)
632 : : return -1;
633 : : /* TC does not support UDP port masking. Only accept if exact match. */
634 [ # # ]: 0 : if ((mask->hdr.src_port && mask->hdr.src_port != 0xffff) ||
635 [ # # ]: 0 : (mask->hdr.dst_port && mask->hdr.dst_port != 0xffff))
636 : : return -1;
637 [ # # ]: 0 : if (!flow)
638 : : return 0;
639 : 0 : msg = &flow->msg;
640 : 0 : tap_nlattr_add8(msg, TCA_FLOWER_KEY_IP_PROTO, IPPROTO_UDP);
641 [ # # ]: 0 : if (!spec)
642 : : return 0;
643 [ # # ]: 0 : if (mask->hdr.dst_port)
644 : 0 : tap_nlattr_add16(msg, TCA_FLOWER_KEY_UDP_DST, spec->hdr.dst_port);
645 [ # # ]: 0 : if (mask->hdr.src_port)
646 : 0 : tap_nlattr_add16(msg, TCA_FLOWER_KEY_UDP_SRC, spec->hdr.src_port);
647 : : return 0;
648 : : }
649 : :
650 : : /**
651 : : * Make as much checks as possible on a TCP item, and if a flow is provided,
652 : : * fill it appropriately with TCP info.
653 : : *
654 : : * @param[in] item
655 : : * Item specification.
656 : : * @param[in, out] data
657 : : * Additional data structure to tell next layers we've been here.
658 : : *
659 : : * @return
660 : : * 0 if checks are alright, -1 otherwise.
661 : : */
662 : : static int
663 : 0 : tap_flow_create_tcp(const struct rte_flow_item *item, struct convert_data *info)
664 : : {
665 : 0 : const struct rte_flow_item_tcp *spec = item->spec;
666 : 0 : const struct rte_flow_item_tcp *mask = item->mask;
667 : 0 : struct rte_flow *flow = info->flow;
668 : : struct tap_nlmsg *msg;
669 : :
670 : : /* use default mask if none provided */
671 [ # # ]: 0 : if (!mask)
672 : : mask = tap_flow_items[RTE_FLOW_ITEM_TYPE_TCP].default_mask;
673 : : /* check that previous ip_proto is compatible with tcp */
674 [ # # ]: 0 : if (info->ip_proto && info->ip_proto != IPPROTO_TCP)
675 : : return -1;
676 : : /* TC does not support TCP port masking. Only accept if exact match. */
677 [ # # ]: 0 : if ((mask->hdr.src_port && mask->hdr.src_port != 0xffff) ||
678 [ # # ]: 0 : (mask->hdr.dst_port && mask->hdr.dst_port != 0xffff))
679 : : return -1;
680 [ # # ]: 0 : if (!flow)
681 : : return 0;
682 : 0 : msg = &flow->msg;
683 : 0 : tap_nlattr_add8(msg, TCA_FLOWER_KEY_IP_PROTO, IPPROTO_TCP);
684 [ # # ]: 0 : if (!spec)
685 : : return 0;
686 [ # # ]: 0 : if (mask->hdr.dst_port)
687 : 0 : tap_nlattr_add16(msg, TCA_FLOWER_KEY_TCP_DST, spec->hdr.dst_port);
688 [ # # ]: 0 : if (mask->hdr.src_port)
689 : 0 : tap_nlattr_add16(msg, TCA_FLOWER_KEY_TCP_SRC, spec->hdr.src_port);
690 : : return 0;
691 : : }
692 : :
693 : : /**
694 : : * Check support for a given item.
695 : : *
696 : : * @param[in] item
697 : : * Item specification.
698 : : * @param size
699 : : * Bit-Mask size in bytes.
700 : : * @param[in] supported_mask
701 : : * Bit-mask covering supported fields to compare with spec, last and mask in
702 : : * \item.
703 : : * @param[in] default_mask
704 : : * Bit-mask default mask if none is provided in \item.
705 : : *
706 : : * @return
707 : : * 0 on success.
708 : : */
709 : : static int
710 : 0 : tap_flow_item_validate(const struct rte_flow_item *item,
711 : : unsigned int size,
712 : : const uint8_t *supported_mask,
713 : : const uint8_t *default_mask)
714 : : {
715 : : int ret = 0;
716 : :
717 : : /* An empty layer is allowed, as long as all fields are NULL */
718 [ # # # # : 0 : if (!item->spec && (item->mask || item->last))
# # ]
719 : : return -1;
720 : : /* Is the item spec compatible with what the NIC supports? */
721 [ # # # # ]: 0 : if (item->spec && !item->mask) {
722 : : unsigned int i;
723 : : const uint8_t *spec = item->spec;
724 : :
725 [ # # ]: 0 : for (i = 0; i < size; ++i)
726 [ # # ]: 0 : if ((spec[i] | supported_mask[i]) != supported_mask[i])
727 : : return -1;
728 : : /* Is the default mask compatible with what the NIC supports? */
729 [ # # ]: 0 : for (i = 0; i < size; i++)
730 [ # # ]: 0 : if ((default_mask[i] | supported_mask[i]) !=
731 : : supported_mask[i])
732 : : return -1;
733 : : }
734 : : /* Is the item last compatible with what the NIC supports? */
735 [ # # # # ]: 0 : if (item->last && !item->mask) {
736 : : unsigned int i;
737 : : const uint8_t *spec = item->last;
738 : :
739 [ # # ]: 0 : for (i = 0; i < size; ++i)
740 [ # # ]: 0 : if ((spec[i] | supported_mask[i]) != supported_mask[i])
741 : : return -1;
742 : : }
743 : : /* Is the item mask compatible with what the NIC supports? */
744 [ # # ]: 0 : if (item->mask) {
745 : : unsigned int i;
746 : : const uint8_t *spec = item->mask;
747 : :
748 [ # # ]: 0 : for (i = 0; i < size; ++i)
749 [ # # ]: 0 : if ((spec[i] | supported_mask[i]) != supported_mask[i])
750 : : return -1;
751 : : }
752 : : /**
753 : : * Once masked, Are item spec and item last equal?
754 : : * TC does not support range so anything else is invalid.
755 : : */
756 [ # # # # ]: 0 : if (item->spec && item->last) {
757 : 0 : uint8_t spec[size];
758 : 0 : uint8_t last[size];
759 : : const uint8_t *apply = default_mask;
760 : : unsigned int i;
761 : :
762 [ # # ]: 0 : if (item->mask)
763 : : apply = item->mask;
764 [ # # ]: 0 : for (i = 0; i < size; ++i) {
765 : 0 : spec[i] = ((const uint8_t *)item->spec)[i] & apply[i];
766 : 0 : last[i] = ((const uint8_t *)item->last)[i] & apply[i];
767 : : }
768 : 0 : ret = memcmp(spec, last, size);
769 : : }
770 : : return ret;
771 : : }
772 : :
773 : : /**
774 : : * Configure the kernel with a TC action and its configured parameters
775 : : * Handled actions: "gact", "mirred", "skbedit", "bpf"
776 : : *
777 : : * @param[in] flow
778 : : * Pointer to rte flow containing the netlink message
779 : : *
780 : : * @param[in, out] act_index
781 : : * Pointer to action sequence number in the TC command
782 : : *
783 : : * @param[in] adata
784 : : * Pointer to struct holding the action parameters
785 : : *
786 : : * @return
787 : : * -1 on failure, 0 on success
788 : : */
789 : : static int
790 : 0 : add_action(struct rte_flow *flow, size_t *act_index, struct action_data *adata)
791 : : {
792 : 0 : struct tap_nlmsg *msg = &flow->msg;
793 : :
794 [ # # ]: 0 : if (tap_nlattr_nested_start(msg, (*act_index)++) < 0)
795 : : return -1;
796 : :
797 : 0 : tap_nlattr_add(msg, TCA_ACT_KIND, strlen(adata->id) + 1, adata->id);
798 [ # # ]: 0 : if (tap_nlattr_nested_start(msg, TCA_ACT_OPTIONS) < 0)
799 : : return -1;
800 [ # # ]: 0 : if (strcmp("gact", adata->id) == 0) {
801 : 0 : tap_nlattr_add(msg, TCA_GACT_PARMS, sizeof(adata->gact), &adata->gact);
802 [ # # ]: 0 : } else if (strcmp("mirred", adata->id) == 0) {
803 [ # # ]: 0 : if (adata->mirred.eaction == TCA_EGRESS_MIRROR)
804 : 0 : adata->mirred.action = TC_ACT_PIPE;
805 : : else /* REDIRECT */
806 : 0 : adata->mirred.action = TC_ACT_STOLEN;
807 : 0 : tap_nlattr_add(msg, TCA_MIRRED_PARMS, sizeof(adata->mirred), &adata->mirred);
808 [ # # ]: 0 : } else if (strcmp("skbedit", adata->id) == 0) {
809 : 0 : tap_nlattr_add(msg, TCA_SKBEDIT_PARMS, sizeof(adata->skbedit.skbedit),
810 : 0 : &adata->skbedit.skbedit);
811 [ # # ]: 0 : if (adata->skbedit.mark)
812 : 0 : tap_nlattr_add32(msg, TCA_SKBEDIT_MARK, adata->skbedit.mark);
813 : : else
814 : 0 : tap_nlattr_add16(msg, TCA_SKBEDIT_QUEUE_MAPPING, adata->skbedit.queue);
815 [ # # ]: 0 : } else if (strcmp("bpf", adata->id) == 0) {
816 : : #ifdef HAVE_BPF_RSS
817 : : tap_nlattr_add32(msg, TCA_ACT_BPF_FD, adata->bpf.bpf_fd);
818 : : tap_nlattr_add(msg, TCA_ACT_BPF_NAME, strlen(adata->bpf.annotation) + 1,
819 : : adata->bpf.annotation);
820 : : tap_nlattr_add(msg, TCA_ACT_BPF_PARMS, sizeof(adata->bpf.bpf), &adata->bpf.bpf);
821 : : #else
822 : 0 : TAP_LOG(ERR, "Internal error: bpf requested but not supported");
823 : 0 : return -1;
824 : : #endif
825 : : } else {
826 : 0 : TAP_LOG(ERR, "Internal error: unknown action: %s", adata->id);
827 : 0 : return -1;
828 : : }
829 : 0 : tap_nlattr_nested_finish(msg); /* nested TCA_ACT_OPTIONS */
830 : 0 : tap_nlattr_nested_finish(msg); /* nested act_index */
831 : 0 : return 0;
832 : : }
833 : :
834 : : /**
835 : : * Helper function to send a series of TC actions to the kernel
836 : : *
837 : : * @param[in] flow
838 : : * Pointer to rte flow containing the netlink message
839 : : *
840 : : * @param[in] nb_actions
841 : : * Number of actions in an array of action structs
842 : : *
843 : : * @param[in] data
844 : : * Pointer to an array of action structs
845 : : *
846 : : * @param[in] classifier_actions
847 : : * The classifier on behave of which the actions are configured
848 : : *
849 : : * @return
850 : : * -1 on failure, 0 on success
851 : : */
852 : : static int
853 : 0 : add_actions(struct rte_flow *flow, int nb_actions, struct action_data *data,
854 : : int classifier_action)
855 : : {
856 : 0 : struct tap_nlmsg *msg = &flow->msg;
857 : 0 : size_t act_index = 1;
858 : : int i;
859 : :
860 [ # # ]: 0 : if (tap_nlattr_nested_start(msg, classifier_action) < 0)
861 : : return -1;
862 [ # # ]: 0 : for (i = 0; i < nb_actions; i++)
863 [ # # ]: 0 : if (add_action(flow, &act_index, data + i) < 0)
864 : : return -1;
865 : 0 : tap_nlattr_nested_finish(msg); /* nested TCA_FLOWER_ACT */
866 : 0 : return 0;
867 : : }
868 : :
869 : : /**
870 : : * Validate a flow supported by TC.
871 : : * If flow param is not NULL, then also fill the netlink message inside.
872 : : *
873 : : * @param pmd
874 : : * Pointer to private structure.
875 : : * @param[in] attr
876 : : * Flow rule attributes.
877 : : * @param[in] pattern
878 : : * Pattern specification (list terminated by the END pattern item).
879 : : * @param[in] actions
880 : : * Associated actions (list terminated by the END action).
881 : : * @param[out] error
882 : : * Perform verbose error reporting if not NULL.
883 : : * @param[in, out] flow
884 : : * Flow structure to update.
885 : : * @param[in] mirred
886 : : * If set to TCA_EGRESS_REDIR, provided actions will be replaced with a
887 : : * redirection to the tap netdevice, and the TC rule will be configured
888 : : * on the remote netdevice in pmd.
889 : : * If set to TCA_EGRESS_MIRROR, provided actions will be replaced with a
890 : : * mirroring to the tap netdevice, and the TC rule will be configured
891 : : * on the remote netdevice in pmd. Matching packets will thus be duplicated.
892 : : * If set to 0, the standard behavior is to be used: set correct actions for
893 : : * the TC rule, and apply it on the tap netdevice.
894 : : *
895 : : * @return
896 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
897 : : */
898 : : static int
899 : 0 : priv_flow_process(struct pmd_internals *pmd,
900 : : const struct rte_flow_attr *attr,
901 : : const struct rte_flow_item items[],
902 : : const struct rte_flow_action actions[],
903 : : struct rte_flow_error *error,
904 : : struct rte_flow *flow,
905 : : int mirred)
906 : : {
907 : : const struct tap_flow_items *cur_item = tap_flow_items;
908 : 0 : struct convert_data data = {
909 : : .eth_type = 0,
910 : : .ip_proto = 0,
911 : : .flow = flow,
912 : : };
913 : : int action = 0; /* Only one action authorized for now */
914 : :
915 [ # # ]: 0 : if (attr->transfer) {
916 : 0 : rte_flow_error_set(
917 : : error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ATTR_TRANSFER,
918 : : NULL, "transfer is not supported");
919 : 0 : return -rte_errno;
920 : : }
921 [ # # ]: 0 : if (attr->group > MAX_GROUP) {
922 : 0 : rte_flow_error_set(
923 : : error, EINVAL, RTE_FLOW_ERROR_TYPE_ATTR_GROUP,
924 : : NULL, "group value too big: cannot exceed 15");
925 : 0 : return -rte_errno;
926 : : }
927 [ # # ]: 0 : if (attr->priority > MAX_PRIORITY) {
928 : 0 : rte_flow_error_set(
929 : : error, EINVAL, RTE_FLOW_ERROR_TYPE_ATTR_PRIORITY,
930 : : NULL, "priority value too big");
931 : 0 : return -rte_errno;
932 [ # # ]: 0 : } else if (flow) {
933 : 0 : uint16_t group = attr->group << GROUP_SHIFT;
934 : 0 : uint16_t prio = group | (attr->priority +
935 : 0 : RSS_PRIORITY_OFFSET + PRIORITY_OFFSET);
936 : 0 : flow->msg.t.tcm_info = TC_H_MAKE(prio << 16,
937 : : flow->msg.t.tcm_info);
938 : : }
939 [ # # ]: 0 : if (flow) {
940 [ # # ]: 0 : if (mirred) {
941 : : /*
942 : : * If attr->ingress, the rule applies on remote ingress
943 : : * to match incoming packets
944 : : * If attr->egress, the rule applies on tap ingress (as
945 : : * seen from the kernel) to deal with packets going out
946 : : * from the DPDK app.
947 : : */
948 : 0 : flow->msg.t.tcm_parent = TC_H_MAKE(TC_H_INGRESS, 0);
949 : : } else {
950 : : /* Standard rule on tap egress (kernel standpoint). */
951 : 0 : flow->msg.t.tcm_parent =
952 : : TC_H_MAKE(MULTIQ_MAJOR_HANDLE, 0);
953 : : }
954 : : /* use flower filter type */
955 : 0 : tap_nlattr_add(&flow->msg, TCA_KIND, sizeof("flower"), "flower");
956 [ # # ]: 0 : if (tap_nlattr_nested_start(&flow->msg, TCA_OPTIONS) < 0) {
957 : 0 : rte_flow_error_set(error, ENOMEM, RTE_FLOW_ERROR_TYPE_ACTION,
958 : : actions, "could not allocated netlink msg");
959 : 0 : goto exit_return_error;
960 : : }
961 : : }
962 [ # # ]: 0 : for (; items->type != RTE_FLOW_ITEM_TYPE_END; ++items) {
963 : : const struct tap_flow_items *token = NULL;
964 : : unsigned int i;
965 : : int err = 0;
966 : :
967 [ # # ]: 0 : if (items->type == RTE_FLOW_ITEM_TYPE_VOID)
968 : 0 : continue;
969 : : for (i = 0;
970 [ # # ]: 0 : cur_item->items &&
971 [ # # ]: 0 : cur_item->items[i] != RTE_FLOW_ITEM_TYPE_END;
972 : 0 : ++i) {
973 [ # # ]: 0 : if (cur_item->items[i] == items->type) {
974 : 0 : token = &tap_flow_items[items->type];
975 : 0 : break;
976 : : }
977 : : }
978 [ # # ]: 0 : if (!token)
979 : 0 : goto exit_item_not_supported;
980 : : cur_item = token;
981 : 0 : err = tap_flow_item_validate(
982 : 0 : items, cur_item->mask_sz,
983 : 0 : (const uint8_t *)cur_item->mask,
984 : 0 : (const uint8_t *)cur_item->default_mask);
985 [ # # ]: 0 : if (err)
986 : 0 : goto exit_item_not_supported;
987 [ # # # # ]: 0 : if (flow && cur_item->convert) {
988 : 0 : err = cur_item->convert(items, &data);
989 [ # # ]: 0 : if (err)
990 : 0 : goto exit_item_not_supported;
991 : : }
992 : : }
993 [ # # ]: 0 : if (flow) {
994 [ # # ]: 0 : if (data.vlan) {
995 : 0 : tap_nlattr_add16(&flow->msg, TCA_FLOWER_KEY_ETH_TYPE, htons(ETH_P_8021Q));
996 : 0 : tap_nlattr_add16(&flow->msg, TCA_FLOWER_KEY_VLAN_ETH_TYPE,
997 [ # # ]: 0 : data.eth_type ? data.eth_type : htons(ETH_P_ALL));
998 [ # # ]: 0 : } else if (data.eth_type) {
999 : 0 : tap_nlattr_add16(&flow->msg, TCA_FLOWER_KEY_ETH_TYPE, data.eth_type);
1000 : : }
1001 : : }
1002 [ # # ]: 0 : if (mirred && flow) {
1003 : 0 : struct action_data adata = {
1004 : : .id = "mirred",
1005 : : .mirred = {
1006 : : .eaction = mirred,
1007 : : },
1008 : : };
1009 : :
1010 : : /*
1011 : : * If attr->egress && mirred, then this is a special
1012 : : * case where the rule must be applied on the tap, to
1013 : : * redirect packets coming from the DPDK App, out
1014 : : * through the remote netdevice.
1015 : : */
1016 [ # # ]: 0 : adata.mirred.ifindex = attr->ingress ? pmd->if_index :
1017 : 0 : pmd->remote_if_index;
1018 [ # # ]: 0 : if (mirred == TCA_EGRESS_MIRROR)
1019 : 0 : adata.mirred.action = TC_ACT_PIPE;
1020 : : else
1021 : 0 : adata.mirred.action = TC_ACT_STOLEN;
1022 [ # # ]: 0 : if (add_actions(flow, 1, &adata, TCA_FLOWER_ACT) < 0)
1023 : 0 : goto exit_action_not_supported;
1024 : : else
1025 : 0 : goto end;
1026 : : }
1027 : 0 : actions:
1028 [ # # ]: 0 : for (; actions->type != RTE_FLOW_ACTION_TYPE_END; ++actions) {
1029 : : int err = 0;
1030 : :
1031 [ # # ]: 0 : if (actions->type == RTE_FLOW_ACTION_TYPE_VOID) {
1032 : 0 : continue;
1033 [ # # ]: 0 : } else if (actions->type == RTE_FLOW_ACTION_TYPE_DROP) {
1034 [ # # ]: 0 : if (action)
1035 : 0 : goto exit_action_not_supported;
1036 : : action = 1;
1037 [ # # ]: 0 : if (flow) {
1038 : 0 : struct action_data adata = {
1039 : : .id = "gact",
1040 : : .gact = {
1041 : : .action = TC_ACT_SHOT,
1042 : : },
1043 : : };
1044 : :
1045 : 0 : err = add_actions(flow, 1, &adata,
1046 : : TCA_FLOWER_ACT);
1047 : : }
1048 [ # # ]: 0 : } else if (actions->type == RTE_FLOW_ACTION_TYPE_PASSTHRU) {
1049 [ # # ]: 0 : if (action)
1050 : 0 : goto exit_action_not_supported;
1051 : : action = 1;
1052 [ # # ]: 0 : if (flow) {
1053 : 0 : struct action_data adata = {
1054 : : .id = "gact",
1055 : : .gact = {
1056 : : /* continue */
1057 : : .action = TC_ACT_UNSPEC,
1058 : : },
1059 : : };
1060 : :
1061 : 0 : err = add_actions(flow, 1, &adata, TCA_FLOWER_ACT);
1062 : : }
1063 [ # # ]: 0 : } else if (actions->type == RTE_FLOW_ACTION_TYPE_QUEUE) {
1064 : 0 : const struct rte_flow_action_queue *queue =
1065 : : (const struct rte_flow_action_queue *)
1066 : : actions->conf;
1067 : :
1068 [ # # ]: 0 : if (action)
1069 : 0 : goto exit_action_not_supported;
1070 : : action = 1;
1071 [ # # ]: 0 : if (queue->index >= pmd->dev->data->nb_rx_queues) {
1072 : 0 : rte_flow_error_set(error, ERANGE,
1073 : : RTE_FLOW_ERROR_TYPE_ACTION, actions,
1074 : : "queue index out of range");
1075 : 0 : goto exit_return_error;
1076 : : }
1077 [ # # ]: 0 : if (flow) {
1078 : 0 : struct action_data adata = {
1079 : : .id = "skbedit",
1080 : : .skbedit = {
1081 : : .skbedit = {
1082 : : .action = TC_ACT_PIPE,
1083 : : },
1084 : : .queue = queue->index,
1085 : : },
1086 : : };
1087 : :
1088 : 0 : err = add_actions(flow, 1, &adata,
1089 : : TCA_FLOWER_ACT);
1090 : : }
1091 : : #ifdef HAVE_BPF_RSS
1092 : : } else if (actions->type == RTE_FLOW_ACTION_TYPE_RSS) {
1093 : : const struct rte_flow_action_rss *rss =
1094 : : (const struct rte_flow_action_rss *)
1095 : : actions->conf;
1096 : :
1097 : : if (action++)
1098 : : goto exit_action_not_supported;
1099 : :
1100 : : if (pmd->rss == NULL) {
1101 : : err = rss_enable(pmd, error);
1102 : : if (err)
1103 : : goto exit_return_error;
1104 : : }
1105 : : if (flow)
1106 : : err = rss_add_actions(flow, pmd, rss, error);
1107 : : #endif
1108 : : } else {
1109 : 0 : goto exit_action_not_supported;
1110 : : }
1111 [ # # ]: 0 : if (err)
1112 : 0 : goto exit_return_error;
1113 : : }
1114 : : /* When fate is unknown, drop traffic. */
1115 [ # # ]: 0 : if (!action) {
1116 : : static const struct rte_flow_action drop[] = {
1117 : : { .type = RTE_FLOW_ACTION_TYPE_DROP, },
1118 : : { .type = RTE_FLOW_ACTION_TYPE_END, },
1119 : : };
1120 : :
1121 : : actions = drop;
1122 : 0 : goto actions;
1123 : : }
1124 : 0 : end:
1125 [ # # ]: 0 : if (flow)
1126 : 0 : tap_nlattr_nested_finish(&flow->msg); /* nested TCA_OPTIONS */
1127 : : return 0;
1128 : 0 : exit_item_not_supported:
1129 : 0 : rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ITEM,
1130 : : items, "item not supported");
1131 : 0 : return -rte_errno;
1132 : 0 : exit_action_not_supported:
1133 : 0 : rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION,
1134 : : actions, "action not supported");
1135 : 0 : exit_return_error:
1136 : 0 : return -rte_errno;
1137 : : }
1138 : :
1139 : :
1140 : :
1141 : : /**
1142 : : * Validate a flow.
1143 : : *
1144 : : * @see rte_flow_validate()
1145 : : * @see rte_flow_ops
1146 : : */
1147 : : static int
1148 : 0 : tap_flow_validate(struct rte_eth_dev *dev,
1149 : : const struct rte_flow_attr *attr,
1150 : : const struct rte_flow_item items[],
1151 : : const struct rte_flow_action actions[],
1152 : : struct rte_flow_error *error)
1153 : : {
1154 : 0 : struct pmd_internals *pmd = dev->data->dev_private;
1155 : :
1156 : 0 : return priv_flow_process(pmd, attr, items, actions, error, NULL, 0);
1157 : : }
1158 : :
1159 : : /**
1160 : : * Set a unique handle in a flow.
1161 : : *
1162 : : * The kernel supports TC rules with equal priority, as long as they use the
1163 : : * same matching fields (e.g.: dst mac and ipv4) with different values (and
1164 : : * full mask to ensure no collision is possible).
1165 : : * In those rules, the handle (uint32_t) is the part that would identify
1166 : : * specifically each rule.
1167 : : *
1168 : : * Use jhash of the flow pointer to make a unique handle.
1169 : : *
1170 : : * @param[in, out] flow
1171 : : * The flow that needs its handle set.
1172 : : */
1173 : : static void
1174 : 0 : tap_flow_set_handle(struct rte_flow *flow)
1175 : : {
1176 : : union {
1177 : : struct rte_flow *flow;
1178 : : uint32_t words[sizeof(flow) / sizeof(uint32_t)];
1179 : 0 : } tmp = {
1180 : : .flow = flow,
1181 : : };
1182 : : uint32_t handle;
1183 : : static uint64_t hash_seed;
1184 : :
1185 [ # # ]: 0 : if (hash_seed == 0)
1186 : 0 : hash_seed = rte_rand();
1187 : :
1188 : 0 : handle = rte_jhash_32b(tmp.words, sizeof(flow) / sizeof(uint32_t), hash_seed);
1189 : :
1190 : : /* must be at least 1 to avoid letting the kernel choose one for us */
1191 : : if (!handle)
1192 : : handle = 1;
1193 : 0 : flow->msg.t.tcm_handle = handle;
1194 : 0 : }
1195 : :
1196 : : /**
1197 : : * Free the flow opened file descriptors and allocated memory
1198 : : *
1199 : : * @param[in] flow
1200 : : * Pointer to the flow to free
1201 : : *
1202 : : */
1203 : : static void
1204 : : tap_flow_free(struct pmd_internals *pmd __rte_unused, struct rte_flow *flow)
1205 : : {
1206 : : if (!flow)
1207 : : return;
1208 : :
1209 : : #ifdef HAVE_BPF_RSS
1210 : : struct tap_rss *rss = pmd->rss;
1211 : : if (rss)
1212 : : bpf_map__delete_elem(rss->maps.rss_map,
1213 : : &flow->msg.t.tcm_handle, sizeof(uint32_t), 0);
1214 : : #endif
1215 : : /* Free flow allocated memory */
1216 : 0 : rte_free(flow);
1217 : : }
1218 : :
1219 : : /**
1220 : : * Create a flow.
1221 : : *
1222 : : * @see rte_flow_create()
1223 : : * @see rte_flow_ops
1224 : : */
1225 : : static struct rte_flow *
1226 : 0 : tap_flow_create(struct rte_eth_dev *dev,
1227 : : const struct rte_flow_attr *attr,
1228 : : const struct rte_flow_item items[],
1229 : : const struct rte_flow_action actions[],
1230 : : struct rte_flow_error *error)
1231 : : {
1232 : 0 : struct pmd_internals *pmd = dev->data->dev_private;
1233 : : struct rte_flow *remote_flow = NULL;
1234 : : struct rte_flow *flow = NULL;
1235 : : struct tap_nlmsg *msg = NULL;
1236 : : int err;
1237 : :
1238 [ # # ]: 0 : if (!pmd->if_index) {
1239 : 0 : rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_HANDLE,
1240 : : NULL,
1241 : : "can't create rule, ifindex not found");
1242 : 0 : goto fail;
1243 : : }
1244 : : /*
1245 : : * No rules configured through standard rte_flow should be set on the
1246 : : * priorities used by implicit rules.
1247 : : */
1248 [ # # ]: 0 : if ((attr->group == MAX_GROUP) &&
1249 [ # # ]: 0 : attr->priority > (MAX_PRIORITY - TAP_REMOTE_MAX_IDX)) {
1250 : 0 : rte_flow_error_set(
1251 : : error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ATTR_PRIORITY,
1252 : : NULL, "priority value too big");
1253 : 0 : goto fail;
1254 : : }
1255 : 0 : flow = rte_zmalloc(__func__, sizeof(struct rte_flow), 0);
1256 [ # # ]: 0 : if (!flow) {
1257 : 0 : rte_flow_error_set(error, ENOMEM, RTE_FLOW_ERROR_TYPE_HANDLE,
1258 : : NULL, "cannot allocate memory for rte_flow");
1259 : 0 : goto fail;
1260 : : }
1261 : 0 : msg = &flow->msg;
1262 : 0 : tc_init_msg(msg, pmd->if_index, RTM_NEWTFILTER,
1263 : : NLM_F_REQUEST | NLM_F_ACK | NLM_F_EXCL | NLM_F_CREATE);
1264 : 0 : msg->t.tcm_info = TC_H_MAKE(0, htons(ETH_P_ALL));
1265 : 0 : tap_flow_set_handle(flow);
1266 [ # # ]: 0 : if (priv_flow_process(pmd, attr, items, actions, error, flow, 0))
1267 : 0 : goto fail;
1268 : 0 : err = tap_nl_send(pmd->nlsk_fd, &msg->nh);
1269 [ # # ]: 0 : if (err < 0) {
1270 : 0 : rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_HANDLE,
1271 : : NULL, "couldn't send request to kernel");
1272 : 0 : goto fail;
1273 : : }
1274 : 0 : err = tap_nl_recv_ack(pmd->nlsk_fd);
1275 [ # # ]: 0 : if (err < 0) {
1276 : 0 : TAP_LOG(ERR,
1277 : : "Kernel refused TC filter rule creation (%d): %s",
1278 : : errno, strerror(errno));
1279 : 0 : rte_flow_error_set(error, EEXIST, RTE_FLOW_ERROR_TYPE_HANDLE,
1280 : : NULL,
1281 : : "overlapping rules or Kernel too old for flower support");
1282 : 0 : goto fail;
1283 : : }
1284 [ # # ]: 0 : LIST_INSERT_HEAD(&pmd->flows, flow, next);
1285 : : /**
1286 : : * If a remote device is configured, a TC rule with identical items for
1287 : : * matching must be set on that device, with a single action: redirect
1288 : : * to the local pmd->if_index.
1289 : : */
1290 [ # # ]: 0 : if (pmd->remote_if_index) {
1291 : 0 : remote_flow = rte_zmalloc(__func__, sizeof(struct rte_flow), 0);
1292 [ # # ]: 0 : if (!remote_flow) {
1293 : 0 : rte_flow_error_set(
1294 : : error, ENOMEM, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
1295 : : "cannot allocate memory for rte_flow");
1296 : 0 : goto fail;
1297 : : }
1298 : 0 : msg = &remote_flow->msg;
1299 : : /* set the rule if_index for the remote netdevice */
1300 : 0 : tc_init_msg(
1301 : 0 : msg, pmd->remote_if_index, RTM_NEWTFILTER,
1302 : : NLM_F_REQUEST | NLM_F_ACK | NLM_F_EXCL | NLM_F_CREATE);
1303 : 0 : msg->t.tcm_info = TC_H_MAKE(0, htons(ETH_P_ALL));
1304 : 0 : tap_flow_set_handle(remote_flow);
1305 [ # # ]: 0 : if (priv_flow_process(pmd, attr, items, NULL,
1306 : : error, remote_flow, TCA_EGRESS_REDIR)) {
1307 : 0 : rte_flow_error_set(
1308 : : error, ENOMEM, RTE_FLOW_ERROR_TYPE_HANDLE,
1309 : : NULL, "rte flow rule validation failed");
1310 : 0 : goto fail;
1311 : : }
1312 : 0 : err = tap_nl_send(pmd->nlsk_fd, &msg->nh);
1313 [ # # ]: 0 : if (err < 0) {
1314 : 0 : rte_flow_error_set(
1315 : : error, ENOMEM, RTE_FLOW_ERROR_TYPE_HANDLE,
1316 : : NULL, "Failure sending nl request");
1317 : 0 : goto fail;
1318 : : }
1319 : 0 : err = tap_nl_recv_ack(pmd->nlsk_fd);
1320 [ # # ]: 0 : if (err < 0) {
1321 : 0 : TAP_LOG(ERR,
1322 : : "Kernel refused TC filter rule creation (%d): %s",
1323 : : errno, strerror(errno));
1324 : 0 : rte_flow_error_set(
1325 : : error, ENOMEM, RTE_FLOW_ERROR_TYPE_HANDLE,
1326 : : NULL,
1327 : : "overlapping rules or Kernel too old for flower support");
1328 : 0 : goto fail;
1329 : : }
1330 : 0 : flow->remote_flow = remote_flow;
1331 : : }
1332 : : return flow;
1333 : 0 : fail:
1334 : 0 : rte_free(remote_flow);
1335 [ # # ]: 0 : if (flow)
1336 : : tap_flow_free(pmd, flow);
1337 : : return NULL;
1338 : : }
1339 : :
1340 : : /**
1341 : : * Destroy a flow using pointer to pmd_internal.
1342 : : *
1343 : : * @param[in, out] pmd
1344 : : * Pointer to private structure.
1345 : : * @param[in] flow
1346 : : * Pointer to the flow to destroy.
1347 : : * @param[in, out] error
1348 : : * Pointer to the flow error handler
1349 : : *
1350 : : * @return 0 if the flow could be destroyed, -1 otherwise.
1351 : : */
1352 : : static int
1353 : 0 : tap_flow_destroy_pmd(struct pmd_internals *pmd,
1354 : : struct rte_flow *flow,
1355 : : struct rte_flow_error *error)
1356 : : {
1357 : 0 : struct rte_flow *remote_flow = flow->remote_flow;
1358 : : int ret = 0;
1359 : :
1360 [ # # ]: 0 : LIST_REMOVE(flow, next);
1361 : 0 : flow->msg.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
1362 : 0 : flow->msg.nh.nlmsg_type = RTM_DELTFILTER;
1363 : :
1364 : 0 : ret = tap_nl_send(pmd->nlsk_fd, &flow->msg.nh);
1365 [ # # ]: 0 : if (ret < 0) {
1366 : 0 : rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_HANDLE,
1367 : : NULL, "couldn't send request to kernel");
1368 : 0 : goto end;
1369 : : }
1370 : 0 : ret = tap_nl_recv_ack(pmd->nlsk_fd);
1371 : : /* If errno is ENOENT, the rule is already no longer in the kernel. */
1372 [ # # # # ]: 0 : if (ret < 0 && errno == ENOENT)
1373 : : ret = 0;
1374 [ # # ]: 0 : if (ret < 0) {
1375 : 0 : TAP_LOG(ERR,
1376 : : "Kernel refused TC filter rule deletion (%d): %s",
1377 : : errno, strerror(errno));
1378 : 0 : rte_flow_error_set(
1379 : : error, ENOTSUP, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
1380 : : "couldn't receive kernel ack to our request");
1381 : 0 : goto end;
1382 : : }
1383 : :
1384 [ # # ]: 0 : if (remote_flow) {
1385 : 0 : remote_flow->msg.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
1386 : 0 : remote_flow->msg.nh.nlmsg_type = RTM_DELTFILTER;
1387 : :
1388 : 0 : ret = tap_nl_send(pmd->nlsk_fd, &remote_flow->msg.nh);
1389 [ # # ]: 0 : if (ret < 0) {
1390 : 0 : rte_flow_error_set(
1391 : : error, ENOMEM, RTE_FLOW_ERROR_TYPE_HANDLE,
1392 : : NULL, "Failure sending nl request");
1393 : 0 : goto end;
1394 : : }
1395 : 0 : ret = tap_nl_recv_ack(pmd->nlsk_fd);
1396 [ # # # # ]: 0 : if (ret < 0 && errno == ENOENT)
1397 : : ret = 0;
1398 [ # # ]: 0 : if (ret < 0) {
1399 : 0 : TAP_LOG(ERR,
1400 : : "Kernel refused TC filter rule deletion (%d): %s",
1401 : : errno, strerror(errno));
1402 : 0 : rte_flow_error_set(
1403 : : error, ENOMEM, RTE_FLOW_ERROR_TYPE_HANDLE,
1404 : : NULL, "Failure trying to receive nl ack");
1405 : 0 : goto end;
1406 : : }
1407 : : }
1408 : 0 : end:
1409 : 0 : rte_free(remote_flow);
1410 : : tap_flow_free(pmd, flow);
1411 : 0 : return ret;
1412 : : }
1413 : :
1414 : : /**
1415 : : * Destroy a flow.
1416 : : *
1417 : : * @see rte_flow_destroy()
1418 : : * @see rte_flow_ops
1419 : : */
1420 : : static int
1421 : 0 : tap_flow_destroy(struct rte_eth_dev *dev,
1422 : : struct rte_flow *flow,
1423 : : struct rte_flow_error *error)
1424 : : {
1425 : 0 : struct pmd_internals *pmd = dev->data->dev_private;
1426 : :
1427 : 0 : return tap_flow_destroy_pmd(pmd, flow, error);
1428 : : }
1429 : :
1430 : : /**
1431 : : * Enable/disable flow isolation.
1432 : : *
1433 : : * @see rte_flow_isolate()
1434 : : * @see rte_flow_ops
1435 : : */
1436 : : static int
1437 : 0 : tap_flow_isolate(struct rte_eth_dev *dev,
1438 : : int set,
1439 : : struct rte_flow_error *error __rte_unused)
1440 : : {
1441 : 0 : struct pmd_internals *pmd = dev->data->dev_private;
1442 : 0 : struct pmd_process_private *process_private = dev->process_private;
1443 : :
1444 : : /* normalize 'set' variable to contain 0 or 1 values */
1445 [ # # ]: 0 : if (set)
1446 : : set = 1;
1447 : : /* if already in the right isolation mode - nothing to do */
1448 [ # # ]: 0 : if ((set ^ pmd->flow_isolate) == 0)
1449 : : return 0;
1450 : : /* mark the isolation mode for tap_flow_implicit_create() */
1451 : 0 : pmd->flow_isolate = set;
1452 : : /*
1453 : : * If netdevice is there, setup appropriate flow rules immediately.
1454 : : * Otherwise it will be set when bringing up the netdevice (tun_alloc).
1455 : : */
1456 [ # # ]: 0 : if (process_private->fds[0] == -1)
1457 : : return 0;
1458 : :
1459 [ # # ]: 0 : if (set) {
1460 : : struct rte_flow *remote_flow;
1461 : :
1462 : : while (1) {
1463 : 0 : remote_flow = LIST_FIRST(&pmd->implicit_flows);
1464 [ # # ]: 0 : if (!remote_flow)
1465 : : break;
1466 : : /*
1467 : : * Remove all implicit rules on the remote.
1468 : : * Keep the local rule to redirect packets on TX.
1469 : : * Keep also the last implicit local rule: ISOLATE.
1470 : : */
1471 [ # # ]: 0 : if (remote_flow->msg.t.tcm_ifindex == pmd->if_index)
1472 : : break;
1473 [ # # ]: 0 : if (tap_flow_destroy_pmd(pmd, remote_flow, NULL) < 0)
1474 : 0 : goto error;
1475 : : }
1476 : : /* Switch the TC rule according to pmd->flow_isolate */
1477 [ # # ]: 0 : if (tap_flow_implicit_create(pmd, TAP_ISOLATE) == -1)
1478 : 0 : goto error;
1479 : : } else {
1480 : : /* Switch the TC rule according to pmd->flow_isolate */
1481 [ # # ]: 0 : if (tap_flow_implicit_create(pmd, TAP_ISOLATE) == -1)
1482 : 0 : goto error;
1483 [ # # ]: 0 : if (!pmd->remote_if_index)
1484 : : return 0;
1485 [ # # ]: 0 : if (tap_flow_implicit_create(pmd, TAP_REMOTE_TX) < 0)
1486 : 0 : goto error;
1487 [ # # ]: 0 : if (tap_flow_implicit_create(pmd, TAP_REMOTE_LOCAL_MAC) < 0)
1488 : 0 : goto error;
1489 [ # # ]: 0 : if (tap_flow_implicit_create(pmd, TAP_REMOTE_BROADCAST) < 0)
1490 : 0 : goto error;
1491 [ # # ]: 0 : if (tap_flow_implicit_create(pmd, TAP_REMOTE_BROADCASTV6) < 0)
1492 : 0 : goto error;
1493 [ # # # # ]: 0 : if (dev->data->promiscuous &&
1494 : 0 : tap_flow_implicit_create(pmd, TAP_REMOTE_PROMISC) < 0)
1495 : 0 : goto error;
1496 [ # # # # ]: 0 : if (dev->data->all_multicast &&
1497 : 0 : tap_flow_implicit_create(pmd, TAP_REMOTE_ALLMULTI) < 0)
1498 : 0 : goto error;
1499 : : }
1500 : : return 0;
1501 : 0 : error:
1502 : 0 : pmd->flow_isolate = 0;
1503 : 0 : return rte_flow_error_set(
1504 : : error, ENOTSUP, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
1505 : : "TC rule creation failed");
1506 : : }
1507 : :
1508 : : /**
1509 : : * Destroy all flows.
1510 : : *
1511 : : * @see rte_flow_flush()
1512 : : * @see rte_flow_ops
1513 : : */
1514 : : int
1515 : 0 : tap_flow_flush(struct rte_eth_dev *dev, struct rte_flow_error *error)
1516 : : {
1517 : 0 : struct pmd_internals *pmd = dev->data->dev_private;
1518 : : struct rte_flow *flow;
1519 : :
1520 [ # # ]: 0 : while (!LIST_EMPTY(&pmd->flows)) {
1521 : : flow = LIST_FIRST(&pmd->flows);
1522 [ # # ]: 0 : if (tap_flow_destroy(dev, flow, error) < 0)
1523 : : return -1;
1524 : : }
1525 : : return 0;
1526 : : }
1527 : :
1528 : : /**
1529 : : * Add an implicit flow rule on the remote device to make sure traffic gets to
1530 : : * the tap netdevice from there.
1531 : : *
1532 : : * @param pmd
1533 : : * Pointer to private structure.
1534 : : * @param[in] idx
1535 : : * The idx in the implicit_rte_flows array specifying which rule to apply.
1536 : : *
1537 : : * @return -1 if the rule couldn't be applied, 0 otherwise.
1538 : : */
1539 : 0 : int tap_flow_implicit_create(struct pmd_internals *pmd,
1540 : : enum implicit_rule_index idx)
1541 : : {
1542 : : uint16_t flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_EXCL | NLM_F_CREATE;
1543 : 0 : struct rte_flow_action *actions = implicit_rte_flows[idx].actions;
1544 : 0 : struct rte_flow_action isolate_actions[2] = {
1545 : : [1] = {
1546 : : .type = RTE_FLOW_ACTION_TYPE_END,
1547 : : },
1548 : : };
1549 : 0 : struct rte_flow_item *items = implicit_rte_flows[idx].items;
1550 : 0 : struct rte_flow_attr *attr = &implicit_rte_flows[idx].attr;
1551 : 0 : struct rte_flow_item_eth eth_local = { .hdr.ether_type = 0 };
1552 : 0 : unsigned int if_index = pmd->remote_if_index;
1553 : : struct rte_flow *remote_flow = NULL;
1554 : : struct tap_nlmsg *msg = NULL;
1555 : : int err = 0;
1556 : 0 : struct rte_flow_item items_local[2] = {
1557 : : [0] = {
1558 : 0 : .type = items[0].type,
1559 : : .spec = ð_local,
1560 : 0 : .mask = items[0].mask,
1561 : : },
1562 : : [1] = {
1563 : 0 : .type = items[1].type,
1564 : : }
1565 : : };
1566 : :
1567 : 0 : remote_flow = rte_zmalloc(__func__, sizeof(struct rte_flow), 0);
1568 [ # # ]: 0 : if (!remote_flow) {
1569 : 0 : TAP_LOG(ERR, "Cannot allocate memory for rte_flow");
1570 : 0 : goto fail;
1571 : : }
1572 : 0 : msg = &remote_flow->msg;
1573 [ # # ]: 0 : if (idx == TAP_REMOTE_TX) {
1574 : 0 : if_index = pmd->if_index;
1575 [ # # ]: 0 : } else if (idx == TAP_ISOLATE) {
1576 : 0 : if_index = pmd->if_index;
1577 : : /* Don't be exclusive for this rule, it can be changed later. */
1578 : : flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_CREATE;
1579 : 0 : isolate_actions[0].type = pmd->flow_isolate ?
1580 [ # # ]: 0 : RTE_FLOW_ACTION_TYPE_DROP :
1581 : : RTE_FLOW_ACTION_TYPE_PASSTHRU;
1582 : : actions = isolate_actions;
1583 [ # # ]: 0 : } else if (idx == TAP_REMOTE_LOCAL_MAC) {
1584 : : /*
1585 : : * eth addr couldn't be set in implicit_rte_flows[] as it is not
1586 : : * known at compile time.
1587 : : */
1588 : 0 : memcpy(ð_local.hdr.dst_addr, &pmd->eth_addr, sizeof(pmd->eth_addr));
1589 : : items = items_local;
1590 : : }
1591 : 0 : tc_init_msg(msg, if_index, RTM_NEWTFILTER, flags);
1592 : 0 : msg->t.tcm_info = TC_H_MAKE(0, htons(ETH_P_ALL));
1593 : : /*
1594 : : * The ISOLATE rule is always present and must have a static handle, as
1595 : : * the action is changed whether the feature is enabled (DROP) or
1596 : : * disabled (PASSTHRU).
1597 : : * There is just one REMOTE_PROMISCUOUS rule in all cases. It should
1598 : : * have a static handle such that adding it twice will fail with EEXIST
1599 : : * with any kernel version. Remark: old kernels may falsely accept the
1600 : : * same REMOTE_PROMISCUOUS rules if they had different handles.
1601 : : */
1602 [ # # ]: 0 : if (idx == TAP_ISOLATE)
1603 : 0 : remote_flow->msg.t.tcm_handle = ISOLATE_HANDLE;
1604 [ # # ]: 0 : else if (idx == TAP_REMOTE_PROMISC)
1605 : 0 : remote_flow->msg.t.tcm_handle = REMOTE_PROMISCUOUS_HANDLE;
1606 : : else
1607 : 0 : tap_flow_set_handle(remote_flow);
1608 [ # # ]: 0 : if (priv_flow_process(pmd, attr, items, actions, NULL,
1609 : : remote_flow, implicit_rte_flows[idx].mirred)) {
1610 : 0 : TAP_LOG(ERR, "rte flow rule validation failed");
1611 : 0 : goto fail;
1612 : : }
1613 : 0 : err = tap_nl_send(pmd->nlsk_fd, &msg->nh);
1614 [ # # ]: 0 : if (err < 0) {
1615 : 0 : TAP_LOG(ERR, "Failure sending nl request");
1616 : 0 : goto fail;
1617 : : }
1618 : 0 : err = tap_nl_recv_ack(pmd->nlsk_fd);
1619 [ # # ]: 0 : if (err < 0) {
1620 : : /* Silently ignore re-entering existing rule */
1621 [ # # ]: 0 : if (errno == EEXIST)
1622 : 0 : goto success;
1623 : 0 : TAP_LOG(ERR,
1624 : : "Kernel refused TC filter rule creation (%d): %s",
1625 : : errno, strerror(errno));
1626 : 0 : goto fail;
1627 : : }
1628 [ # # ]: 0 : LIST_INSERT_HEAD(&pmd->implicit_flows, remote_flow, next);
1629 : : success:
1630 : : return 0;
1631 : 0 : fail:
1632 : 0 : rte_free(remote_flow);
1633 : 0 : return -1;
1634 : : }
1635 : :
1636 : : /**
1637 : : * Remove specific implicit flow rule on the remote device.
1638 : : *
1639 : : * @param[in, out] pmd
1640 : : * Pointer to private structure.
1641 : : * @param[in] idx
1642 : : * The idx in the implicit_rte_flows array specifying which rule to remove.
1643 : : *
1644 : : * @return -1 if one of the implicit rules couldn't be created, 0 otherwise.
1645 : : */
1646 : 0 : int tap_flow_implicit_destroy(struct pmd_internals *pmd,
1647 : : enum implicit_rule_index idx)
1648 : : {
1649 : : struct rte_flow *remote_flow;
1650 : : int cur_prio = -1;
1651 : 0 : int idx_prio = implicit_rte_flows[idx].attr.priority + PRIORITY_OFFSET;
1652 : :
1653 : 0 : for (remote_flow = LIST_FIRST(&pmd->implicit_flows);
1654 [ # # ]: 0 : remote_flow;
1655 : 0 : remote_flow = LIST_NEXT(remote_flow, next)) {
1656 : 0 : cur_prio = (remote_flow->msg.t.tcm_info >> 16) & PRIORITY_MASK;
1657 [ # # ]: 0 : if (cur_prio != idx_prio)
1658 : : continue;
1659 : 0 : return tap_flow_destroy_pmd(pmd, remote_flow, NULL);
1660 : : }
1661 : : return 0;
1662 : : }
1663 : :
1664 : : /**
1665 : : * Destroy all implicit flows.
1666 : : *
1667 : : * @see rte_flow_flush()
1668 : : */
1669 : : int
1670 : 0 : tap_flow_implicit_flush(struct pmd_internals *pmd, struct rte_flow_error *error)
1671 : : {
1672 : : struct rte_flow *remote_flow;
1673 : :
1674 [ # # ]: 0 : while (!LIST_EMPTY(&pmd->implicit_flows)) {
1675 : : remote_flow = LIST_FIRST(&pmd->implicit_flows);
1676 [ # # ]: 0 : if (tap_flow_destroy_pmd(pmd, remote_flow, error) < 0)
1677 : : return -1;
1678 : : }
1679 : : return 0;
1680 : : }
1681 : :
1682 : : /**
1683 : : * Cleanup when device is closed
1684 : : */
1685 : 0 : void tap_flow_bpf_destroy(struct pmd_internals *pmd __rte_unused)
1686 : : {
1687 : : #ifdef HAVE_BPF_RSS
1688 : : tap_rss__destroy(pmd->rss);
1689 : : pmd->rss = NULL;
1690 : : #endif
1691 : 0 : }
1692 : :
1693 : : #ifdef HAVE_BPF_RSS
1694 : : /**
1695 : : * Enable RSS on tap: create TC rules for queuing.
1696 : : *
1697 : : * @param[in, out] pmd
1698 : : * Pointer to private structure.
1699 : : *
1700 : : * @param[in] attr
1701 : : * Pointer to rte_flow to get flow group
1702 : : *
1703 : : * @param[out] error
1704 : : * Pointer to error reporting if not NULL.
1705 : : *
1706 : : * @return 0 on success, negative value on failure.
1707 : : */
1708 : : static int rss_enable(struct pmd_internals *pmd, struct rte_flow_error *error)
1709 : : {
1710 : : int err;
1711 : :
1712 : : /* Load the BPF program (defined in tap_bpf.h from skeleton) */
1713 : : pmd->rss = tap_rss__open_and_load();
1714 : : if (pmd->rss == NULL) {
1715 : : TAP_LOG(ERR, "Failed to load BPF object: %s", strerror(errno));
1716 : : rte_flow_error_set(error, errno, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
1717 : : "BPF object could not be loaded");
1718 : : return -errno;
1719 : : }
1720 : :
1721 : : /* Attach the maps defined in BPF program */
1722 : : err = tap_rss__attach(pmd->rss);
1723 : : if (err < 0) {
1724 : : TAP_LOG(ERR, "Failed to attach BPF object: %d", err);
1725 : : rte_flow_error_set(error, -err, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
1726 : : "BPF object could not be attached");
1727 : : tap_flow_bpf_destroy(pmd);
1728 : : return err;
1729 : : }
1730 : :
1731 : : return 0;
1732 : : }
1733 : :
1734 : : /* Default RSS hash key also used by mlx devices */
1735 : : static const uint8_t rss_hash_default_key[] = {
1736 : : 0x2c, 0xc6, 0x81, 0xd1,
1737 : : 0x5b, 0xdb, 0xf4, 0xf7,
1738 : : 0xfc, 0xa2, 0x83, 0x19,
1739 : : 0xdb, 0x1a, 0x3e, 0x94,
1740 : : 0x6b, 0x9e, 0x38, 0xd9,
1741 : : 0x2c, 0x9c, 0x03, 0xd1,
1742 : : 0xad, 0x99, 0x44, 0xa7,
1743 : : 0xd9, 0x56, 0x3d, 0x59,
1744 : : 0x06, 0x3c, 0x25, 0xf3,
1745 : : 0xfc, 0x1f, 0xdc, 0x2a,
1746 : : };
1747 : :
1748 : : /**
1749 : : * Add RSS hash calculations and queue selection
1750 : : *
1751 : : * @param[in, out] pmd
1752 : : * Pointer to internal structure. Used to set/get RSS map fd
1753 : : *
1754 : : * @param[in] rss
1755 : : * Pointer to RSS flow actions
1756 : : *
1757 : : * @param[out] error
1758 : : * Pointer to error reporting if not NULL.
1759 : : *
1760 : : * @return 0 on success, negative value on failure
1761 : : */
1762 : : static int rss_add_actions(struct rte_flow *flow, struct pmd_internals *pmd,
1763 : : const struct rte_flow_action_rss *rss,
1764 : : struct rte_flow_error *error)
1765 : : {
1766 : : const struct bpf_program *rss_prog = pmd->rss->progs.rss_flow_action;
1767 : : struct rss_key rss_entry = { };
1768 : : const uint8_t *key_in;
1769 : : uint32_t hash_type = 0;
1770 : : uint32_t handle = flow->msg.t.tcm_handle;
1771 : : unsigned int i;
1772 : : int err;
1773 : :
1774 : : /* Check supported RSS features */
1775 : : if (rss->func != RTE_ETH_HASH_FUNCTION_DEFAULT)
1776 : : return rte_flow_error_set
1777 : : (error, ENOTSUP, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
1778 : : "non-default RSS hash functions are not supported");
1779 : : if (rss->level)
1780 : : return rte_flow_error_set
1781 : : (error, ENOTSUP, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
1782 : : "a nonzero RSS encapsulation level is not supported");
1783 : :
1784 : : if (rss->queue_num == 0 || rss->queue_num >= TAP_MAX_QUEUES)
1785 : : return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
1786 : : "invalid number of queues");
1787 : :
1788 : : /*
1789 : : * Follow the semantics of RSS key (see rte_ethdev.h)
1790 : : * There are two valid cases:
1791 : : * 1. key_length of zero, and key must be NULL;
1792 : : * this uses the default driver key.
1793 : : *
1794 : : * 2. key_length is the TAP_RSS_HASH_KEY_SIZE (40 bytes)
1795 : : * and the key must not be NULL.
1796 : : *
1797 : : * Anything else is an error.
1798 : : */
1799 : : if (rss->key_len == 0) {
1800 : : if (rss->key != NULL)
1801 : : return rte_flow_error_set(error, ENOTSUP,
1802 : : RTE_FLOW_ERROR_TYPE_ACTION_CONF,
1803 : : &rss->key_len, "RSS hash key length 0");
1804 : : key_in = rss_hash_default_key;
1805 : : } else {
1806 : : if (rss->key_len != TAP_RSS_HASH_KEY_SIZE)
1807 : : return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1808 : : NULL, "RSS hash invalid key length");
1809 : : if (rss->key == NULL)
1810 : : return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1811 : : NULL, "RSS hash key is NULL");
1812 : : key_in = rss->key;
1813 : : }
1814 : :
1815 : : if (rss->types & TAP_RSS_HF_MASK)
1816 : : return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1817 : : NULL, "RSS hash type not supported");
1818 : :
1819 : : if (rss->types & (RTE_ETH_RSS_NONFRAG_IPV4_UDP | RTE_ETH_RSS_NONFRAG_IPV4_TCP))
1820 : : hash_type |= RTE_BIT32(HASH_FIELD_IPV4_L3_L4);
1821 : : else if (rss->types & (RTE_ETH_RSS_IPV4 | RTE_ETH_RSS_FRAG_IPV4))
1822 : : hash_type |= RTE_BIT32(HASH_FIELD_IPV4_L3);
1823 : :
1824 : : if (rss->types & (RTE_ETH_RSS_NONFRAG_IPV6_UDP | RTE_ETH_RSS_NONFRAG_IPV6_TCP))
1825 : : hash_type |= RTE_BIT32(HASH_FIELD_IPV6_L3_L4);
1826 : : else if (rss->types & (RTE_ETH_RSS_IPV6 | RTE_ETH_RSS_FRAG_IPV6 | RTE_ETH_RSS_IPV6_EX))
1827 : : hash_type |= RTE_BIT32(HASH_FIELD_IPV6_L3);
1828 : :
1829 : : rss_entry.hash_fields = hash_type;
1830 : : rte_convert_rss_key((const uint32_t *)key_in, (uint32_t *)rss_entry.key,
1831 : : TAP_RSS_HASH_KEY_SIZE);
1832 : :
1833 : : /* Update RSS map entry with queues */
1834 : : rss_entry.nb_queues = rss->queue_num;
1835 : : for (i = 0; i < rss->queue_num; i++)
1836 : : rss_entry.queues[i] = rss->queue[i];
1837 : :
1838 : :
1839 : : /* Add this way for BPF to find entry in map */
1840 : : err = bpf_map__update_elem(pmd->rss->maps.rss_map,
1841 : : &handle, sizeof(handle),
1842 : : &rss_entry, sizeof(rss_entry), 0);
1843 : : if (err) {
1844 : : TAP_LOG(ERR,
1845 : : "Failed to update BPF map entry %#x (%d): %s",
1846 : : handle, errno, strerror(errno));
1847 : : rte_flow_error_set(
1848 : : error, ENOTSUP, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
1849 : : "Kernel too old or not configured "
1850 : : "to support BPF maps updates");
1851 : :
1852 : : return -ENOTSUP;
1853 : : }
1854 : :
1855 : : /* Add actions to mark packet then run the RSS BPF program */
1856 : : struct action_data adata[] = {
1857 : : {
1858 : : .id = "skbedit",
1859 : : .skbedit = {
1860 : : .skbedit.action = TC_ACT_PIPE,
1861 : : .mark = handle,
1862 : : },
1863 : : },
1864 : : {
1865 : : .id = "bpf",
1866 : : .bpf = {
1867 : : .bpf.action = TC_ACT_PIPE,
1868 : : .annotation = "tap_rss",
1869 : : .bpf_fd = bpf_program__fd(rss_prog),
1870 : : },
1871 : : },
1872 : : };
1873 : :
1874 : : return add_actions(flow, RTE_DIM(adata), adata, TCA_FLOWER_ACT);
1875 : : }
1876 : : #endif
1877 : :
1878 : : /**
1879 : : * Get rte_flow operations.
1880 : : *
1881 : : * @param dev
1882 : : * Pointer to Ethernet device structure.
1883 : : * @param ops
1884 : : * Pointer to operation-specific structure.
1885 : : *
1886 : : * @return
1887 : : * 0 on success, negative errno value on failure.
1888 : : */
1889 : : int
1890 : 0 : tap_dev_flow_ops_get(struct rte_eth_dev *dev __rte_unused,
1891 : : const struct rte_flow_ops **ops)
1892 : : {
1893 : 0 : *ops = &tap_flow_ops;
1894 : 0 : return 0;
1895 : : }
|