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 : : /*
710 : : * Maximum size of a flow item in bytes.
711 : : * Must be larger than all supported rte_flow_item_* structures
712 : : * (currently the largest is rte_flow_item_ipv6 at ~44 bytes).
713 : : */
714 : : #define TAP_FLOW_ITEM_MAX_SIZE 128
715 : :
716 : : static int
717 : 0 : tap_flow_item_validate(const struct rte_flow_item *item,
718 : : unsigned int size,
719 : : const uint8_t *supported_mask,
720 : : const uint8_t *default_mask)
721 : : {
722 : : int ret = 0;
723 : :
724 : : /* An empty layer is allowed, as long as all fields are NULL */
725 [ # # # # : 0 : if (!item->spec && (item->mask || item->last))
# # ]
726 : : return -1;
727 : : /* Is the item spec compatible with what the NIC supports? */
728 [ # # # # ]: 0 : if (item->spec && !item->mask) {
729 : : unsigned int i;
730 : : const uint8_t *spec = item->spec;
731 : :
732 [ # # ]: 0 : for (i = 0; i < size; ++i)
733 [ # # ]: 0 : if ((spec[i] | supported_mask[i]) != supported_mask[i])
734 : : return -1;
735 : : /* Is the default mask compatible with what the NIC supports? */
736 [ # # ]: 0 : for (i = 0; i < size; i++)
737 [ # # ]: 0 : if ((default_mask[i] | supported_mask[i]) !=
738 : : supported_mask[i])
739 : : return -1;
740 : : }
741 : : /* Is the item last compatible with what the NIC supports? */
742 [ # # # # ]: 0 : if (item->last && !item->mask) {
743 : : unsigned int i;
744 : : const uint8_t *spec = item->last;
745 : :
746 [ # # ]: 0 : for (i = 0; i < size; ++i)
747 [ # # ]: 0 : if ((spec[i] | supported_mask[i]) != supported_mask[i])
748 : : return -1;
749 : : }
750 : : /* Is the item mask compatible with what the NIC supports? */
751 [ # # ]: 0 : if (item->mask) {
752 : : unsigned int i;
753 : : const uint8_t *spec = item->mask;
754 : :
755 [ # # ]: 0 : for (i = 0; i < size; ++i)
756 [ # # ]: 0 : if ((spec[i] | supported_mask[i]) != supported_mask[i])
757 : : return -1;
758 : : }
759 : : /**
760 : : * Once masked, Are item spec and item last equal?
761 : : * TC does not support range so anything else is invalid.
762 : : */
763 [ # # # # ]: 0 : if (item->spec && item->last) {
764 : : uint8_t spec[TAP_FLOW_ITEM_MAX_SIZE];
765 : : uint8_t last[TAP_FLOW_ITEM_MAX_SIZE];
766 : : const uint8_t *apply = default_mask;
767 : : unsigned int i;
768 : :
769 [ # # ]: 0 : if (size > TAP_FLOW_ITEM_MAX_SIZE)
770 : 0 : return -1;
771 [ # # ]: 0 : if (item->mask)
772 : : apply = item->mask;
773 [ # # ]: 0 : for (i = 0; i < size; ++i) {
774 : 0 : spec[i] = ((const uint8_t *)item->spec)[i] & apply[i];
775 : 0 : last[i] = ((const uint8_t *)item->last)[i] & apply[i];
776 : : }
777 : 0 : ret = memcmp(spec, last, size);
778 : : }
779 : : return ret;
780 : : }
781 : :
782 : : /**
783 : : * Configure the kernel with a TC action and its configured parameters
784 : : * Handled actions: "gact", "mirred", "skbedit", "bpf"
785 : : *
786 : : * @param[in] flow
787 : : * Pointer to rte flow containing the netlink message
788 : : *
789 : : * @param[in, out] act_index
790 : : * Pointer to action sequence number in the TC command
791 : : *
792 : : * @param[in] adata
793 : : * Pointer to struct holding the action parameters
794 : : *
795 : : * @return
796 : : * -1 on failure, 0 on success
797 : : */
798 : : static int
799 : 0 : add_action(struct rte_flow *flow, size_t *act_index, struct action_data *adata)
800 : : {
801 : 0 : struct tap_nlmsg *msg = &flow->msg;
802 : :
803 [ # # ]: 0 : if (tap_nlattr_nested_start(msg, (*act_index)++) < 0)
804 : : return -1;
805 : :
806 : 0 : tap_nlattr_add(msg, TCA_ACT_KIND, strlen(adata->id) + 1, adata->id);
807 [ # # ]: 0 : if (tap_nlattr_nested_start(msg, TCA_ACT_OPTIONS) < 0)
808 : : return -1;
809 [ # # ]: 0 : if (strcmp("gact", adata->id) == 0) {
810 : 0 : tap_nlattr_add(msg, TCA_GACT_PARMS, sizeof(adata->gact), &adata->gact);
811 [ # # ]: 0 : } else if (strcmp("mirred", adata->id) == 0) {
812 [ # # ]: 0 : if (adata->mirred.eaction == TCA_EGRESS_MIRROR)
813 : 0 : adata->mirred.action = TC_ACT_PIPE;
814 : : else /* REDIRECT */
815 : 0 : adata->mirred.action = TC_ACT_STOLEN;
816 : 0 : tap_nlattr_add(msg, TCA_MIRRED_PARMS, sizeof(adata->mirred), &adata->mirred);
817 [ # # ]: 0 : } else if (strcmp("skbedit", adata->id) == 0) {
818 : 0 : tap_nlattr_add(msg, TCA_SKBEDIT_PARMS, sizeof(adata->skbedit.skbedit),
819 : 0 : &adata->skbedit.skbedit);
820 [ # # ]: 0 : if (adata->skbedit.mark)
821 : 0 : tap_nlattr_add32(msg, TCA_SKBEDIT_MARK, adata->skbedit.mark);
822 : : else
823 : 0 : tap_nlattr_add16(msg, TCA_SKBEDIT_QUEUE_MAPPING, adata->skbedit.queue);
824 [ # # ]: 0 : } else if (strcmp("bpf", adata->id) == 0) {
825 : : #ifdef HAVE_BPF_RSS
826 : : tap_nlattr_add32(msg, TCA_ACT_BPF_FD, adata->bpf.bpf_fd);
827 : : tap_nlattr_add(msg, TCA_ACT_BPF_NAME, strlen(adata->bpf.annotation) + 1,
828 : : adata->bpf.annotation);
829 : : tap_nlattr_add(msg, TCA_ACT_BPF_PARMS, sizeof(adata->bpf.bpf), &adata->bpf.bpf);
830 : : #else
831 : 0 : TAP_LOG(ERR, "Internal error: bpf requested but not supported");
832 : 0 : return -1;
833 : : #endif
834 : : } else {
835 : 0 : TAP_LOG(ERR, "Internal error: unknown action: %s", adata->id);
836 : 0 : return -1;
837 : : }
838 : 0 : tap_nlattr_nested_finish(msg); /* nested TCA_ACT_OPTIONS */
839 : 0 : tap_nlattr_nested_finish(msg); /* nested act_index */
840 : 0 : return 0;
841 : : }
842 : :
843 : : /**
844 : : * Helper function to send a series of TC actions to the kernel
845 : : *
846 : : * @param[in] flow
847 : : * Pointer to rte flow containing the netlink message
848 : : *
849 : : * @param[in] nb_actions
850 : : * Number of actions in an array of action structs
851 : : *
852 : : * @param[in] data
853 : : * Pointer to an array of action structs
854 : : *
855 : : * @param[in] classifier_actions
856 : : * The classifier on behave of which the actions are configured
857 : : *
858 : : * @return
859 : : * -1 on failure, 0 on success
860 : : */
861 : : static int
862 : 0 : add_actions(struct rte_flow *flow, int nb_actions, struct action_data *data,
863 : : int classifier_action)
864 : : {
865 : 0 : struct tap_nlmsg *msg = &flow->msg;
866 : 0 : size_t act_index = 1;
867 : : int i;
868 : :
869 [ # # ]: 0 : if (tap_nlattr_nested_start(msg, classifier_action) < 0)
870 : : return -1;
871 [ # # ]: 0 : for (i = 0; i < nb_actions; i++)
872 [ # # ]: 0 : if (add_action(flow, &act_index, data + i) < 0)
873 : : return -1;
874 : 0 : tap_nlattr_nested_finish(msg); /* nested TCA_FLOWER_ACT */
875 : 0 : return 0;
876 : : }
877 : :
878 : : /**
879 : : * Validate a flow supported by TC.
880 : : * If flow param is not NULL, then also fill the netlink message inside.
881 : : *
882 : : * @param pmd
883 : : * Pointer to private structure.
884 : : * @param[in] attr
885 : : * Flow rule attributes.
886 : : * @param[in] pattern
887 : : * Pattern specification (list terminated by the END pattern item).
888 : : * @param[in] actions
889 : : * Associated actions (list terminated by the END action).
890 : : * @param[out] error
891 : : * Perform verbose error reporting if not NULL.
892 : : * @param[in, out] flow
893 : : * Flow structure to update.
894 : : * @param[in] mirred
895 : : * If set to TCA_EGRESS_REDIR, provided actions will be replaced with a
896 : : * redirection to the tap netdevice, and the TC rule will be configured
897 : : * on the remote netdevice in pmd.
898 : : * If set to TCA_EGRESS_MIRROR, provided actions will be replaced with a
899 : : * mirroring to the tap netdevice, and the TC rule will be configured
900 : : * on the remote netdevice in pmd. Matching packets will thus be duplicated.
901 : : * If set to 0, the standard behavior is to be used: set correct actions for
902 : : * the TC rule, and apply it on the tap netdevice.
903 : : *
904 : : * @return
905 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
906 : : */
907 : : static int
908 : 0 : priv_flow_process(struct pmd_internals *pmd,
909 : : const struct rte_flow_attr *attr,
910 : : const struct rte_flow_item items[],
911 : : const struct rte_flow_action actions[],
912 : : struct rte_flow_error *error,
913 : : struct rte_flow *flow,
914 : : int mirred)
915 : : {
916 : : const struct tap_flow_items *cur_item = tap_flow_items;
917 : 0 : struct convert_data data = {
918 : : .eth_type = 0,
919 : : .ip_proto = 0,
920 : : .flow = flow,
921 : : };
922 : : int action = 0; /* Only one action authorized for now */
923 : :
924 [ # # ]: 0 : if (attr->transfer) {
925 : 0 : rte_flow_error_set(
926 : : error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ATTR_TRANSFER,
927 : : NULL, "transfer is not supported");
928 : 0 : return -rte_errno;
929 : : }
930 [ # # ]: 0 : if (attr->group > MAX_GROUP) {
931 : 0 : rte_flow_error_set(
932 : : error, EINVAL, RTE_FLOW_ERROR_TYPE_ATTR_GROUP,
933 : : NULL, "group value too big: cannot exceed 15");
934 : 0 : return -rte_errno;
935 : : }
936 [ # # ]: 0 : if (attr->priority > MAX_PRIORITY) {
937 : 0 : rte_flow_error_set(
938 : : error, EINVAL, RTE_FLOW_ERROR_TYPE_ATTR_PRIORITY,
939 : : NULL, "priority value too big");
940 : 0 : return -rte_errno;
941 [ # # ]: 0 : } else if (flow) {
942 : 0 : uint16_t group = attr->group << GROUP_SHIFT;
943 : 0 : uint16_t prio = group | (attr->priority +
944 : 0 : RSS_PRIORITY_OFFSET + PRIORITY_OFFSET);
945 : 0 : flow->msg.t.tcm_info = TC_H_MAKE(prio << 16,
946 : : flow->msg.t.tcm_info);
947 : : }
948 [ # # ]: 0 : if (flow) {
949 [ # # ]: 0 : if (mirred) {
950 : : /*
951 : : * If attr->ingress, the rule applies on remote ingress
952 : : * to match incoming packets
953 : : * If attr->egress, the rule applies on tap ingress (as
954 : : * seen from the kernel) to deal with packets going out
955 : : * from the DPDK app.
956 : : */
957 : 0 : flow->msg.t.tcm_parent = TC_H_MAKE(TC_H_INGRESS, 0);
958 : : } else {
959 : : /* Standard rule on tap egress (kernel standpoint). */
960 : 0 : flow->msg.t.tcm_parent =
961 : : TC_H_MAKE(MULTIQ_MAJOR_HANDLE, 0);
962 : : }
963 : : /* use flower filter type */
964 : 0 : tap_nlattr_add(&flow->msg, TCA_KIND, sizeof("flower"), "flower");
965 [ # # ]: 0 : if (tap_nlattr_nested_start(&flow->msg, TCA_OPTIONS) < 0) {
966 : 0 : rte_flow_error_set(error, ENOMEM, RTE_FLOW_ERROR_TYPE_ACTION,
967 : : actions, "could not allocated netlink msg");
968 : 0 : goto exit_return_error;
969 : : }
970 : : }
971 [ # # ]: 0 : for (; items->type != RTE_FLOW_ITEM_TYPE_END; ++items) {
972 : : const struct tap_flow_items *token = NULL;
973 : : unsigned int i;
974 : : int err = 0;
975 : :
976 [ # # ]: 0 : if (items->type == RTE_FLOW_ITEM_TYPE_VOID)
977 : 0 : continue;
978 : : for (i = 0;
979 [ # # ]: 0 : cur_item->items &&
980 [ # # ]: 0 : cur_item->items[i] != RTE_FLOW_ITEM_TYPE_END;
981 : 0 : ++i) {
982 [ # # ]: 0 : if (cur_item->items[i] == items->type) {
983 : 0 : token = &tap_flow_items[items->type];
984 : 0 : break;
985 : : }
986 : : }
987 [ # # ]: 0 : if (!token)
988 : 0 : goto exit_item_not_supported;
989 : : cur_item = token;
990 : 0 : err = tap_flow_item_validate(
991 : 0 : items, cur_item->mask_sz,
992 : 0 : (const uint8_t *)cur_item->mask,
993 : 0 : (const uint8_t *)cur_item->default_mask);
994 [ # # ]: 0 : if (err)
995 : 0 : goto exit_item_not_supported;
996 [ # # # # ]: 0 : if (flow && cur_item->convert) {
997 : 0 : err = cur_item->convert(items, &data);
998 [ # # ]: 0 : if (err)
999 : 0 : goto exit_item_not_supported;
1000 : : }
1001 : : }
1002 [ # # ]: 0 : if (flow) {
1003 [ # # ]: 0 : if (data.vlan) {
1004 : 0 : tap_nlattr_add16(&flow->msg, TCA_FLOWER_KEY_ETH_TYPE, htons(ETH_P_8021Q));
1005 : 0 : tap_nlattr_add16(&flow->msg, TCA_FLOWER_KEY_VLAN_ETH_TYPE,
1006 [ # # ]: 0 : data.eth_type ? data.eth_type : htons(ETH_P_ALL));
1007 [ # # ]: 0 : } else if (data.eth_type) {
1008 : 0 : tap_nlattr_add16(&flow->msg, TCA_FLOWER_KEY_ETH_TYPE, data.eth_type);
1009 : : }
1010 : : }
1011 [ # # ]: 0 : if (mirred && flow) {
1012 : 0 : struct action_data adata = {
1013 : : .id = "mirred",
1014 : : .mirred = {
1015 : : .eaction = mirred,
1016 : : },
1017 : : };
1018 : :
1019 : : /*
1020 : : * If attr->egress && mirred, then this is a special
1021 : : * case where the rule must be applied on the tap, to
1022 : : * redirect packets coming from the DPDK App, out
1023 : : * through the remote netdevice.
1024 : : */
1025 [ # # ]: 0 : adata.mirred.ifindex = attr->ingress ? pmd->if_index :
1026 : 0 : pmd->remote_if_index;
1027 [ # # ]: 0 : if (mirred == TCA_EGRESS_MIRROR)
1028 : 0 : adata.mirred.action = TC_ACT_PIPE;
1029 : : else
1030 : 0 : adata.mirred.action = TC_ACT_STOLEN;
1031 [ # # ]: 0 : if (add_actions(flow, 1, &adata, TCA_FLOWER_ACT) < 0)
1032 : 0 : goto exit_action_not_supported;
1033 : : else
1034 : 0 : goto end;
1035 : : }
1036 : 0 : actions:
1037 [ # # ]: 0 : for (; actions->type != RTE_FLOW_ACTION_TYPE_END; ++actions) {
1038 : : int err = 0;
1039 : :
1040 [ # # ]: 0 : if (actions->type == RTE_FLOW_ACTION_TYPE_VOID) {
1041 : 0 : continue;
1042 [ # # ]: 0 : } else if (actions->type == RTE_FLOW_ACTION_TYPE_DROP) {
1043 [ # # ]: 0 : if (action)
1044 : 0 : goto exit_action_not_supported;
1045 : : action = 1;
1046 [ # # ]: 0 : if (flow) {
1047 : 0 : struct action_data adata = {
1048 : : .id = "gact",
1049 : : .gact = {
1050 : : .action = TC_ACT_SHOT,
1051 : : },
1052 : : };
1053 : :
1054 : 0 : err = add_actions(flow, 1, &adata,
1055 : : TCA_FLOWER_ACT);
1056 : : }
1057 [ # # ]: 0 : } else if (actions->type == RTE_FLOW_ACTION_TYPE_PASSTHRU) {
1058 [ # # ]: 0 : if (action)
1059 : 0 : goto exit_action_not_supported;
1060 : : action = 1;
1061 [ # # ]: 0 : if (flow) {
1062 : 0 : struct action_data adata = {
1063 : : .id = "gact",
1064 : : .gact = {
1065 : : /* continue */
1066 : : .action = TC_ACT_UNSPEC,
1067 : : },
1068 : : };
1069 : :
1070 : 0 : err = add_actions(flow, 1, &adata, TCA_FLOWER_ACT);
1071 : : }
1072 [ # # ]: 0 : } else if (actions->type == RTE_FLOW_ACTION_TYPE_QUEUE) {
1073 : 0 : const struct rte_flow_action_queue *queue =
1074 : : (const struct rte_flow_action_queue *)
1075 : : actions->conf;
1076 : :
1077 [ # # ]: 0 : if (action)
1078 : 0 : goto exit_action_not_supported;
1079 : : action = 1;
1080 [ # # ]: 0 : if (queue->index >= pmd->dev->data->nb_rx_queues) {
1081 : 0 : rte_flow_error_set(error, ERANGE,
1082 : : RTE_FLOW_ERROR_TYPE_ACTION, actions,
1083 : : "queue index out of range");
1084 : 0 : goto exit_return_error;
1085 : : }
1086 [ # # ]: 0 : if (flow) {
1087 : 0 : struct action_data adata = {
1088 : : .id = "skbedit",
1089 : : .skbedit = {
1090 : : .skbedit = {
1091 : : .action = TC_ACT_PIPE,
1092 : : },
1093 : : .queue = queue->index,
1094 : : },
1095 : : };
1096 : :
1097 : 0 : err = add_actions(flow, 1, &adata,
1098 : : TCA_FLOWER_ACT);
1099 : : }
1100 : : #ifdef HAVE_BPF_RSS
1101 : : } else if (actions->type == RTE_FLOW_ACTION_TYPE_RSS) {
1102 : : const struct rte_flow_action_rss *rss =
1103 : : (const struct rte_flow_action_rss *)
1104 : : actions->conf;
1105 : :
1106 : : if (action++)
1107 : : goto exit_action_not_supported;
1108 : :
1109 : : if (pmd->rss == NULL) {
1110 : : err = rss_enable(pmd, error);
1111 : : if (err)
1112 : : goto exit_return_error;
1113 : : }
1114 : : if (flow)
1115 : : err = rss_add_actions(flow, pmd, rss, error);
1116 : : #endif
1117 : : } else {
1118 : 0 : goto exit_action_not_supported;
1119 : : }
1120 [ # # ]: 0 : if (err)
1121 : 0 : goto exit_return_error;
1122 : : }
1123 : : /* When fate is unknown, drop traffic. */
1124 [ # # ]: 0 : if (!action) {
1125 : : static const struct rte_flow_action drop[] = {
1126 : : { .type = RTE_FLOW_ACTION_TYPE_DROP, },
1127 : : { .type = RTE_FLOW_ACTION_TYPE_END, },
1128 : : };
1129 : :
1130 : : actions = drop;
1131 : 0 : goto actions;
1132 : : }
1133 : 0 : end:
1134 [ # # ]: 0 : if (flow)
1135 : 0 : tap_nlattr_nested_finish(&flow->msg); /* nested TCA_OPTIONS */
1136 : : return 0;
1137 : 0 : exit_item_not_supported:
1138 : 0 : rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ITEM,
1139 : : items, "item not supported");
1140 : 0 : return -rte_errno;
1141 : 0 : exit_action_not_supported:
1142 : 0 : rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION,
1143 : : actions, "action not supported");
1144 : 0 : exit_return_error:
1145 : 0 : return -rte_errno;
1146 : : }
1147 : :
1148 : :
1149 : :
1150 : : /**
1151 : : * Validate a flow.
1152 : : *
1153 : : * @see rte_flow_validate()
1154 : : * @see rte_flow_ops
1155 : : */
1156 : : static int
1157 : 0 : tap_flow_validate(struct rte_eth_dev *dev,
1158 : : const struct rte_flow_attr *attr,
1159 : : const struct rte_flow_item items[],
1160 : : const struct rte_flow_action actions[],
1161 : : struct rte_flow_error *error)
1162 : : {
1163 : 0 : struct pmd_internals *pmd = dev->data->dev_private;
1164 : :
1165 : 0 : return priv_flow_process(pmd, attr, items, actions, error, NULL, 0);
1166 : : }
1167 : :
1168 : : /**
1169 : : * Set a unique handle in a flow.
1170 : : *
1171 : : * The kernel supports TC rules with equal priority, as long as they use the
1172 : : * same matching fields (e.g.: dst mac and ipv4) with different values (and
1173 : : * full mask to ensure no collision is possible).
1174 : : * In those rules, the handle (uint32_t) is the part that would identify
1175 : : * specifically each rule.
1176 : : *
1177 : : * Use jhash of the flow pointer to make a unique handle.
1178 : : *
1179 : : * @param[in, out] flow
1180 : : * The flow that needs its handle set.
1181 : : */
1182 : : static void
1183 : 0 : tap_flow_set_handle(struct rte_flow *flow)
1184 : : {
1185 : : union {
1186 : : struct rte_flow *flow;
1187 : : uint32_t words[sizeof(flow) / sizeof(uint32_t)];
1188 : 0 : } tmp = {
1189 : : .flow = flow,
1190 : : };
1191 : : uint32_t handle;
1192 : : static uint64_t hash_seed;
1193 : :
1194 [ # # ]: 0 : if (hash_seed == 0)
1195 : 0 : hash_seed = rte_rand();
1196 : :
1197 : 0 : handle = rte_jhash_32b(tmp.words, sizeof(flow) / sizeof(uint32_t), hash_seed);
1198 : :
1199 : : /* must be at least 1 to avoid letting the kernel choose one for us */
1200 : : if (!handle)
1201 : : handle = 1;
1202 : 0 : flow->msg.t.tcm_handle = handle;
1203 : 0 : }
1204 : :
1205 : : /**
1206 : : * Free the flow opened file descriptors and allocated memory
1207 : : *
1208 : : * @param[in] flow
1209 : : * Pointer to the flow to free
1210 : : *
1211 : : */
1212 : : static void
1213 : : tap_flow_free(struct pmd_internals *pmd __rte_unused, struct rte_flow *flow)
1214 : : {
1215 [ # # ]: 0 : if (!flow)
1216 : : return;
1217 : :
1218 : : #ifdef HAVE_BPF_RSS
1219 : : struct tap_rss *rss = pmd->rss;
1220 : : if (rss)
1221 : : bpf_map__delete_elem(rss->maps.rss_map,
1222 : : &flow->msg.t.tcm_handle, sizeof(uint32_t), 0);
1223 : : #endif
1224 : : /* Free flow allocated memory */
1225 : 0 : rte_free(flow);
1226 : : }
1227 : :
1228 : : /**
1229 : : * Create a flow.
1230 : : *
1231 : : * @see rte_flow_create()
1232 : : * @see rte_flow_ops
1233 : : */
1234 : : static struct rte_flow *
1235 : 0 : tap_flow_create(struct rte_eth_dev *dev,
1236 : : const struct rte_flow_attr *attr,
1237 : : const struct rte_flow_item items[],
1238 : : const struct rte_flow_action actions[],
1239 : : struct rte_flow_error *error)
1240 : : {
1241 : 0 : struct pmd_internals *pmd = dev->data->dev_private;
1242 : : struct rte_flow *remote_flow = NULL;
1243 : : struct rte_flow *flow = NULL;
1244 : : struct tap_nlmsg *msg = NULL;
1245 : : int err;
1246 : :
1247 [ # # # # ]: 0 : if (pmd->flow_init == 0 && tap_flow_init(pmd) < 0) {
1248 : 0 : rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_HANDLE,
1249 : : NULL,
1250 : : "can't create rule, qdisc not initialized");
1251 : 0 : goto fail;
1252 : : }
1253 [ # # ]: 0 : if (!pmd->if_index) {
1254 : 0 : rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_HANDLE,
1255 : : NULL,
1256 : : "can't create rule, ifindex not found");
1257 : 0 : goto fail;
1258 : : }
1259 : : /*
1260 : : * No rules configured through standard rte_flow should be set on the
1261 : : * priorities used by implicit rules.
1262 : : */
1263 [ # # ]: 0 : if ((attr->group == MAX_GROUP) &&
1264 [ # # ]: 0 : attr->priority > (MAX_PRIORITY - TAP_REMOTE_MAX_IDX)) {
1265 : 0 : rte_flow_error_set(
1266 : : error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ATTR_PRIORITY,
1267 : : NULL, "priority value too big");
1268 : 0 : goto fail;
1269 : : }
1270 : 0 : flow = rte_zmalloc(__func__, sizeof(struct rte_flow), 0);
1271 [ # # ]: 0 : if (!flow) {
1272 : 0 : rte_flow_error_set(error, ENOMEM, RTE_FLOW_ERROR_TYPE_HANDLE,
1273 : : NULL, "cannot allocate memory for rte_flow");
1274 : 0 : goto fail;
1275 : : }
1276 : 0 : msg = &flow->msg;
1277 : 0 : tc_init_msg(msg, pmd->if_index, RTM_NEWTFILTER,
1278 : : NLM_F_REQUEST | NLM_F_ACK | NLM_F_EXCL | NLM_F_CREATE);
1279 : 0 : msg->t.tcm_info = TC_H_MAKE(0, htons(ETH_P_ALL));
1280 : 0 : tap_flow_set_handle(flow);
1281 [ # # ]: 0 : if (priv_flow_process(pmd, attr, items, actions, error, flow, 0))
1282 : 0 : goto fail;
1283 : 0 : err = tap_nl_send(pmd->nlsk_fd, &msg->nh);
1284 [ # # ]: 0 : if (err < 0) {
1285 : 0 : rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_HANDLE,
1286 : : NULL, "couldn't send request to kernel");
1287 : 0 : goto fail;
1288 : : }
1289 : 0 : err = tap_nl_recv_ack(pmd->nlsk_fd);
1290 [ # # ]: 0 : if (err < 0) {
1291 : 0 : TAP_LOG(ERR,
1292 : : "Kernel refused TC filter rule creation (%d): %s",
1293 : : errno, strerror(errno));
1294 : 0 : rte_flow_error_set(error, EEXIST, RTE_FLOW_ERROR_TYPE_HANDLE,
1295 : : NULL,
1296 : : "overlapping rules or Kernel too old for flower support");
1297 : 0 : goto fail;
1298 : : }
1299 [ # # ]: 0 : LIST_INSERT_HEAD(&pmd->flows, flow, next);
1300 : : /**
1301 : : * If a remote device is configured, a TC rule with identical items for
1302 : : * matching must be set on that device, with a single action: redirect
1303 : : * to the local pmd->if_index.
1304 : : */
1305 [ # # ]: 0 : if (pmd->remote_if_index) {
1306 : 0 : remote_flow = rte_zmalloc(__func__, sizeof(struct rte_flow), 0);
1307 [ # # ]: 0 : if (!remote_flow) {
1308 : 0 : rte_flow_error_set(
1309 : : error, ENOMEM, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
1310 : : "cannot allocate memory for rte_flow");
1311 : 0 : goto fail_remove;
1312 : : }
1313 : 0 : msg = &remote_flow->msg;
1314 : : /* set the rule if_index for the remote netdevice */
1315 : 0 : tc_init_msg(
1316 : 0 : msg, pmd->remote_if_index, RTM_NEWTFILTER,
1317 : : NLM_F_REQUEST | NLM_F_ACK | NLM_F_EXCL | NLM_F_CREATE);
1318 : 0 : msg->t.tcm_info = TC_H_MAKE(0, htons(ETH_P_ALL));
1319 : 0 : tap_flow_set_handle(remote_flow);
1320 [ # # ]: 0 : if (priv_flow_process(pmd, attr, items, NULL,
1321 : : error, remote_flow, TCA_EGRESS_REDIR)) {
1322 : 0 : rte_flow_error_set(
1323 : : error, ENOMEM, RTE_FLOW_ERROR_TYPE_HANDLE,
1324 : : NULL, "rte flow rule validation failed");
1325 : 0 : goto fail_remove;
1326 : : }
1327 : 0 : err = tap_nl_send(pmd->nlsk_fd, &msg->nh);
1328 [ # # ]: 0 : if (err < 0) {
1329 : 0 : rte_flow_error_set(
1330 : : error, ENOMEM, RTE_FLOW_ERROR_TYPE_HANDLE,
1331 : : NULL, "Failure sending nl request");
1332 : 0 : goto fail_remove;
1333 : : }
1334 : 0 : err = tap_nl_recv_ack(pmd->nlsk_fd);
1335 [ # # ]: 0 : if (err < 0) {
1336 : 0 : TAP_LOG(ERR,
1337 : : "Kernel refused TC filter rule creation (%d): %s",
1338 : : errno, strerror(errno));
1339 : 0 : rte_flow_error_set(
1340 : : error, ENOMEM, RTE_FLOW_ERROR_TYPE_HANDLE,
1341 : : NULL,
1342 : : "overlapping rules or Kernel too old for flower support");
1343 : 0 : goto fail_remove;
1344 : : }
1345 : 0 : flow->remote_flow = remote_flow;
1346 : : }
1347 : : return flow;
1348 : :
1349 : 0 : fail_remove:
1350 : : /* Delete the local TC rule that was already installed */
1351 : 0 : flow->msg.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
1352 : 0 : flow->msg.nh.nlmsg_type = RTM_DELTFILTER;
1353 [ # # ]: 0 : if (tap_nl_send(pmd->nlsk_fd, &flow->msg.nh) >= 0)
1354 : 0 : tap_nl_recv_ack(pmd->nlsk_fd);
1355 [ # # ]: 0 : LIST_REMOVE(flow, next);
1356 : 0 : fail:
1357 : 0 : rte_free(remote_flow);
1358 : : tap_flow_free(pmd, flow);
1359 : : return NULL;
1360 : : }
1361 : :
1362 : : /**
1363 : : * Destroy a flow using pointer to pmd_internal.
1364 : : *
1365 : : * @param[in, out] pmd
1366 : : * Pointer to private structure.
1367 : : * @param[in] flow
1368 : : * Pointer to the flow to destroy.
1369 : : * @param[in, out] error
1370 : : * Pointer to the flow error handler
1371 : : *
1372 : : * @return 0 if the flow could be destroyed, -1 otherwise.
1373 : : */
1374 : : static int
1375 : 0 : tap_flow_destroy_pmd(struct pmd_internals *pmd,
1376 : : struct rte_flow *flow,
1377 : : struct rte_flow_error *error)
1378 : : {
1379 : 0 : struct rte_flow *remote_flow = flow->remote_flow;
1380 : : int ret = 0;
1381 : :
1382 [ # # ]: 0 : LIST_REMOVE(flow, next);
1383 : 0 : flow->msg.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
1384 : 0 : flow->msg.nh.nlmsg_type = RTM_DELTFILTER;
1385 : :
1386 : 0 : ret = tap_nl_send(pmd->nlsk_fd, &flow->msg.nh);
1387 [ # # ]: 0 : if (ret < 0) {
1388 : 0 : rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_HANDLE,
1389 : : NULL, "couldn't send request to kernel");
1390 : 0 : goto end;
1391 : : }
1392 : 0 : ret = tap_nl_recv_ack(pmd->nlsk_fd);
1393 : : /* If errno is ENOENT, the rule is already no longer in the kernel. */
1394 [ # # # # ]: 0 : if (ret < 0 && errno == ENOENT)
1395 : : ret = 0;
1396 [ # # ]: 0 : if (ret < 0) {
1397 : 0 : TAP_LOG(ERR,
1398 : : "Kernel refused TC filter rule deletion (%d): %s",
1399 : : errno, strerror(errno));
1400 : 0 : rte_flow_error_set(
1401 : : error, ENOTSUP, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
1402 : : "couldn't receive kernel ack to our request");
1403 : 0 : goto end;
1404 : : }
1405 : :
1406 [ # # ]: 0 : if (remote_flow) {
1407 : 0 : remote_flow->msg.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
1408 : 0 : remote_flow->msg.nh.nlmsg_type = RTM_DELTFILTER;
1409 : :
1410 : 0 : ret = tap_nl_send(pmd->nlsk_fd, &remote_flow->msg.nh);
1411 [ # # ]: 0 : if (ret < 0) {
1412 : 0 : rte_flow_error_set(
1413 : : error, ENOMEM, RTE_FLOW_ERROR_TYPE_HANDLE,
1414 : : NULL, "Failure sending nl request");
1415 : 0 : goto end;
1416 : : }
1417 : 0 : ret = tap_nl_recv_ack(pmd->nlsk_fd);
1418 [ # # # # ]: 0 : if (ret < 0 && errno == ENOENT)
1419 : : ret = 0;
1420 [ # # ]: 0 : if (ret < 0) {
1421 : 0 : TAP_LOG(ERR,
1422 : : "Kernel refused TC filter rule deletion (%d): %s",
1423 : : errno, strerror(errno));
1424 : 0 : rte_flow_error_set(
1425 : : error, ENOMEM, RTE_FLOW_ERROR_TYPE_HANDLE,
1426 : : NULL, "Failure trying to receive nl ack");
1427 : 0 : goto end;
1428 : : }
1429 : : }
1430 : 0 : end:
1431 : 0 : rte_free(remote_flow);
1432 : : tap_flow_free(pmd, flow);
1433 : 0 : return ret;
1434 : : }
1435 : :
1436 : : /**
1437 : : * Destroy a flow.
1438 : : *
1439 : : * @see rte_flow_destroy()
1440 : : * @see rte_flow_ops
1441 : : */
1442 : : static int
1443 : 0 : tap_flow_destroy(struct rte_eth_dev *dev,
1444 : : struct rte_flow *flow,
1445 : : struct rte_flow_error *error)
1446 : : {
1447 : 0 : struct pmd_internals *pmd = dev->data->dev_private;
1448 : :
1449 : 0 : return tap_flow_destroy_pmd(pmd, flow, error);
1450 : : }
1451 : :
1452 : : /**
1453 : : * Enable/disable flow isolation.
1454 : : *
1455 : : * @see rte_flow_isolate()
1456 : : * @see rte_flow_ops
1457 : : */
1458 : : static int
1459 : 0 : tap_flow_isolate(struct rte_eth_dev *dev,
1460 : : int set,
1461 : : struct rte_flow_error *error __rte_unused)
1462 : : {
1463 : 0 : struct pmd_internals *pmd = dev->data->dev_private;
1464 : 0 : struct pmd_process_private *process_private = dev->process_private;
1465 : :
1466 : : /* normalize 'set' variable to contain 0 or 1 values */
1467 [ # # ]: 0 : if (set)
1468 : : set = 1;
1469 : : /* if already in the right isolation mode - nothing to do */
1470 [ # # ]: 0 : if ((set ^ pmd->flow_isolate) == 0)
1471 : : return 0;
1472 : : /* mark the isolation mode for tap_flow_implicit_create() */
1473 : 0 : pmd->flow_isolate = set;
1474 : : /*
1475 : : * If netdevice is there, setup appropriate flow rules immediately.
1476 : : * Otherwise it will be set when bringing up the netdevice (tun_alloc).
1477 : : */
1478 [ # # ]: 0 : if (process_private->fds[0] == -1)
1479 : : return 0;
1480 : :
1481 [ # # ]: 0 : if (set) {
1482 : : struct rte_flow *remote_flow;
1483 : :
1484 : : while (1) {
1485 : 0 : remote_flow = LIST_FIRST(&pmd->implicit_flows);
1486 [ # # ]: 0 : if (!remote_flow)
1487 : : break;
1488 : : /*
1489 : : * Remove all implicit rules on the remote.
1490 : : * Keep the local rule to redirect packets on TX.
1491 : : * Keep also the last implicit local rule: ISOLATE.
1492 : : */
1493 [ # # ]: 0 : if (remote_flow->msg.t.tcm_ifindex == pmd->if_index)
1494 : : break;
1495 [ # # ]: 0 : if (tap_flow_destroy_pmd(pmd, remote_flow, NULL) < 0)
1496 : 0 : goto error;
1497 : : }
1498 : : /* Switch the TC rule according to pmd->flow_isolate */
1499 [ # # ]: 0 : if (tap_flow_implicit_create(pmd, TAP_ISOLATE) == -1)
1500 : 0 : goto error;
1501 : : } else {
1502 : : /* Switch the TC rule according to pmd->flow_isolate */
1503 [ # # ]: 0 : if (tap_flow_implicit_create(pmd, TAP_ISOLATE) == -1)
1504 : 0 : goto error;
1505 [ # # ]: 0 : if (!pmd->remote_if_index)
1506 : : return 0;
1507 [ # # ]: 0 : if (tap_flow_implicit_create(pmd, TAP_REMOTE_TX) < 0)
1508 : 0 : goto error;
1509 [ # # ]: 0 : if (tap_flow_implicit_create(pmd, TAP_REMOTE_LOCAL_MAC) < 0)
1510 : 0 : goto error;
1511 [ # # ]: 0 : if (tap_flow_implicit_create(pmd, TAP_REMOTE_BROADCAST) < 0)
1512 : 0 : goto error;
1513 [ # # ]: 0 : if (tap_flow_implicit_create(pmd, TAP_REMOTE_BROADCASTV6) < 0)
1514 : 0 : goto error;
1515 [ # # # # ]: 0 : if (dev->data->promiscuous &&
1516 : 0 : tap_flow_implicit_create(pmd, TAP_REMOTE_PROMISC) < 0)
1517 : 0 : goto error;
1518 [ # # # # ]: 0 : if (dev->data->all_multicast &&
1519 : 0 : tap_flow_implicit_create(pmd, TAP_REMOTE_ALLMULTI) < 0)
1520 : 0 : goto error;
1521 : : }
1522 : : return 0;
1523 : 0 : error:
1524 : 0 : pmd->flow_isolate = 0;
1525 : 0 : return rte_flow_error_set(
1526 : : error, ENOTSUP, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
1527 : : "TC rule creation failed");
1528 : : }
1529 : :
1530 : : /**
1531 : : * Destroy all flows.
1532 : : *
1533 : : * @see rte_flow_flush()
1534 : : * @see rte_flow_ops
1535 : : */
1536 : : int
1537 : 4 : tap_flow_flush(struct rte_eth_dev *dev, struct rte_flow_error *error)
1538 : : {
1539 : 4 : struct pmd_internals *pmd = dev->data->dev_private;
1540 : : struct rte_flow *flow;
1541 : :
1542 [ - + ]: 4 : while (!LIST_EMPTY(&pmd->flows)) {
1543 : : flow = LIST_FIRST(&pmd->flows);
1544 [ # # ]: 0 : if (tap_flow_destroy(dev, flow, error) < 0)
1545 : : return -1;
1546 : : }
1547 : : return 0;
1548 : : }
1549 : :
1550 : : /**
1551 : : * Add an implicit flow rule on the remote device to make sure traffic gets to
1552 : : * the tap netdevice from there.
1553 : : *
1554 : : * @param pmd
1555 : : * Pointer to private structure.
1556 : : * @param[in] idx
1557 : : * The idx in the implicit_rte_flows array specifying which rule to apply.
1558 : : *
1559 : : * @return -1 if the rule couldn't be applied, 0 otherwise.
1560 : : */
1561 : 0 : int tap_flow_implicit_create(struct pmd_internals *pmd,
1562 : : enum implicit_rule_index idx)
1563 : : {
1564 : : uint16_t flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_EXCL | NLM_F_CREATE;
1565 : 0 : struct rte_flow_action *actions = implicit_rte_flows[idx].actions;
1566 : 0 : struct rte_flow_action isolate_actions[2] = {
1567 : : [1] = {
1568 : : .type = RTE_FLOW_ACTION_TYPE_END,
1569 : : },
1570 : : };
1571 : 0 : struct rte_flow_item *items = implicit_rte_flows[idx].items;
1572 : 0 : struct rte_flow_attr *attr = &implicit_rte_flows[idx].attr;
1573 : 0 : struct rte_flow_item_eth eth_local = { .hdr.ether_type = 0 };
1574 : 0 : unsigned int if_index = pmd->remote_if_index;
1575 : : struct rte_flow *remote_flow = NULL;
1576 : : struct tap_nlmsg *msg = NULL;
1577 : : int err = 0;
1578 : 0 : struct rte_flow_item items_local[2] = {
1579 : : [0] = {
1580 : 0 : .type = items[0].type,
1581 : : .spec = ð_local,
1582 : 0 : .mask = items[0].mask,
1583 : : },
1584 : : [1] = {
1585 : 0 : .type = items[1].type,
1586 : : }
1587 : : };
1588 : :
1589 : 0 : remote_flow = rte_zmalloc(__func__, sizeof(struct rte_flow), 0);
1590 [ # # ]: 0 : if (!remote_flow) {
1591 : 0 : TAP_LOG(ERR, "Cannot allocate memory for rte_flow");
1592 : 0 : goto fail;
1593 : : }
1594 : 0 : msg = &remote_flow->msg;
1595 [ # # ]: 0 : if (idx == TAP_REMOTE_TX) {
1596 : 0 : if_index = pmd->if_index;
1597 [ # # ]: 0 : } else if (idx == TAP_ISOLATE) {
1598 : 0 : if_index = pmd->if_index;
1599 : : /* Don't be exclusive for this rule, it can be changed later. */
1600 : : flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_CREATE;
1601 : 0 : isolate_actions[0].type = pmd->flow_isolate ?
1602 [ # # ]: 0 : RTE_FLOW_ACTION_TYPE_DROP :
1603 : : RTE_FLOW_ACTION_TYPE_PASSTHRU;
1604 : : actions = isolate_actions;
1605 [ # # ]: 0 : } else if (idx == TAP_REMOTE_LOCAL_MAC) {
1606 : : /*
1607 : : * eth addr couldn't be set in implicit_rte_flows[] as it is not
1608 : : * known at compile time.
1609 : : */
1610 : 0 : memcpy(ð_local.hdr.dst_addr, &pmd->eth_addr, sizeof(pmd->eth_addr));
1611 : : items = items_local;
1612 : : }
1613 : 0 : tc_init_msg(msg, if_index, RTM_NEWTFILTER, flags);
1614 : 0 : msg->t.tcm_info = TC_H_MAKE(0, htons(ETH_P_ALL));
1615 : : /*
1616 : : * The ISOLATE rule is always present and must have a static handle, as
1617 : : * the action is changed whether the feature is enabled (DROP) or
1618 : : * disabled (PASSTHRU).
1619 : : * There is just one REMOTE_PROMISCUOUS rule in all cases. It should
1620 : : * have a static handle such that adding it twice will fail with EEXIST
1621 : : * with any kernel version. Remark: old kernels may falsely accept the
1622 : : * same REMOTE_PROMISCUOUS rules if they had different handles.
1623 : : */
1624 [ # # ]: 0 : if (idx == TAP_ISOLATE)
1625 : 0 : remote_flow->msg.t.tcm_handle = ISOLATE_HANDLE;
1626 [ # # ]: 0 : else if (idx == TAP_REMOTE_PROMISC)
1627 : 0 : remote_flow->msg.t.tcm_handle = REMOTE_PROMISCUOUS_HANDLE;
1628 : : else
1629 : 0 : tap_flow_set_handle(remote_flow);
1630 [ # # ]: 0 : if (priv_flow_process(pmd, attr, items, actions, NULL,
1631 : : remote_flow, implicit_rte_flows[idx].mirred)) {
1632 : 0 : TAP_LOG(ERR, "rte flow rule validation failed");
1633 : 0 : goto fail;
1634 : : }
1635 : 0 : err = tap_nl_send(pmd->nlsk_fd, &msg->nh);
1636 [ # # ]: 0 : if (err < 0) {
1637 : 0 : TAP_LOG(ERR, "Failure sending nl request");
1638 : 0 : goto fail;
1639 : : }
1640 : 0 : err = tap_nl_recv_ack(pmd->nlsk_fd);
1641 [ # # ]: 0 : if (err < 0) {
1642 : : /* Silently ignore re-entering existing rule */
1643 [ # # ]: 0 : if (errno == EEXIST) {
1644 : 0 : rte_free(remote_flow);
1645 : 0 : goto success;
1646 : : }
1647 : 0 : TAP_LOG(ERR,
1648 : : "Kernel refused TC filter rule creation (%d): %s",
1649 : : errno, strerror(errno));
1650 : 0 : goto fail;
1651 : : }
1652 [ # # ]: 0 : LIST_INSERT_HEAD(&pmd->implicit_flows, remote_flow, next);
1653 : : success:
1654 : : return 0;
1655 : 0 : fail:
1656 : 0 : rte_free(remote_flow);
1657 : 0 : return -1;
1658 : : }
1659 : :
1660 : : /**
1661 : : * Remove specific implicit flow rule on the remote device.
1662 : : *
1663 : : * @param[in, out] pmd
1664 : : * Pointer to private structure.
1665 : : * @param[in] idx
1666 : : * The idx in the implicit_rte_flows array specifying which rule to remove.
1667 : : *
1668 : : * @return -1 if one of the implicit rules couldn't be created, 0 otherwise.
1669 : : */
1670 : 0 : int tap_flow_implicit_destroy(struct pmd_internals *pmd,
1671 : : enum implicit_rule_index idx)
1672 : : {
1673 : : struct rte_flow *remote_flow;
1674 : : int cur_prio = -1;
1675 : 0 : int idx_prio = implicit_rte_flows[idx].attr.priority + PRIORITY_OFFSET;
1676 : :
1677 : 0 : for (remote_flow = LIST_FIRST(&pmd->implicit_flows);
1678 [ # # ]: 0 : remote_flow;
1679 : 0 : remote_flow = LIST_NEXT(remote_flow, next)) {
1680 : 0 : cur_prio = (remote_flow->msg.t.tcm_info >> 16) & PRIORITY_MASK;
1681 [ # # ]: 0 : if (cur_prio != idx_prio)
1682 : : continue;
1683 : 0 : return tap_flow_destroy_pmd(pmd, remote_flow, NULL);
1684 : : }
1685 : : return 0;
1686 : : }
1687 : :
1688 : : /**
1689 : : * Destroy all implicit flows.
1690 : : *
1691 : : * @see rte_flow_flush()
1692 : : */
1693 : : int
1694 : 4 : tap_flow_implicit_flush(struct pmd_internals *pmd, struct rte_flow_error *error)
1695 : : {
1696 : : struct rte_flow *remote_flow;
1697 : :
1698 [ - + ]: 4 : while (!LIST_EMPTY(&pmd->implicit_flows)) {
1699 : : remote_flow = LIST_FIRST(&pmd->implicit_flows);
1700 [ # # ]: 0 : if (tap_flow_destroy_pmd(pmd, remote_flow, error) < 0)
1701 : : return -1;
1702 : : }
1703 : : return 0;
1704 : : }
1705 : :
1706 : : /**
1707 : : * Cleanup when device is closed
1708 : : */
1709 : 4 : void tap_flow_bpf_destroy(struct pmd_internals *pmd __rte_unused)
1710 : : {
1711 : : #ifdef HAVE_BPF_RSS
1712 : : tap_rss__destroy(pmd->rss);
1713 : : pmd->rss = NULL;
1714 : : #endif
1715 : 4 : }
1716 : :
1717 : : #ifdef HAVE_BPF_RSS
1718 : : /**
1719 : : * Enable RSS on tap: create TC rules for queuing.
1720 : : *
1721 : : * @param[in, out] pmd
1722 : : * Pointer to private structure.
1723 : : *
1724 : : * @param[in] attr
1725 : : * Pointer to rte_flow to get flow group
1726 : : *
1727 : : * @param[out] error
1728 : : * Pointer to error reporting if not NULL.
1729 : : *
1730 : : * @return 0 on success, negative value on failure.
1731 : : */
1732 : : static int rss_enable(struct pmd_internals *pmd, struct rte_flow_error *error)
1733 : : {
1734 : : int err;
1735 : :
1736 : : /* Load the BPF program (defined in tap_bpf.h from skeleton) */
1737 : : pmd->rss = tap_rss__open_and_load();
1738 : : if (pmd->rss == NULL) {
1739 : : TAP_LOG(ERR, "Failed to load BPF object: %s", strerror(errno));
1740 : : rte_flow_error_set(error, errno, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
1741 : : "BPF object could not be loaded");
1742 : : return -errno;
1743 : : }
1744 : :
1745 : : /* Attach the maps defined in BPF program */
1746 : : err = tap_rss__attach(pmd->rss);
1747 : : if (err < 0) {
1748 : : TAP_LOG(ERR, "Failed to attach BPF object: %d", err);
1749 : : rte_flow_error_set(error, -err, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
1750 : : "BPF object could not be attached");
1751 : : tap_flow_bpf_destroy(pmd);
1752 : : return err;
1753 : : }
1754 : :
1755 : : return 0;
1756 : : }
1757 : :
1758 : : /* Default RSS hash key also used by mlx devices */
1759 : : static const uint8_t rss_hash_default_key[] = {
1760 : : 0x2c, 0xc6, 0x81, 0xd1,
1761 : : 0x5b, 0xdb, 0xf4, 0xf7,
1762 : : 0xfc, 0xa2, 0x83, 0x19,
1763 : : 0xdb, 0x1a, 0x3e, 0x94,
1764 : : 0x6b, 0x9e, 0x38, 0xd9,
1765 : : 0x2c, 0x9c, 0x03, 0xd1,
1766 : : 0xad, 0x99, 0x44, 0xa7,
1767 : : 0xd9, 0x56, 0x3d, 0x59,
1768 : : 0x06, 0x3c, 0x25, 0xf3,
1769 : : 0xfc, 0x1f, 0xdc, 0x2a,
1770 : : };
1771 : :
1772 : : /**
1773 : : * Add RSS hash calculations and queue selection
1774 : : *
1775 : : * @param[in, out] pmd
1776 : : * Pointer to internal structure. Used to set/get RSS map fd
1777 : : *
1778 : : * @param[in] rss
1779 : : * Pointer to RSS flow actions
1780 : : *
1781 : : * @param[out] error
1782 : : * Pointer to error reporting if not NULL.
1783 : : *
1784 : : * @return 0 on success, negative value on failure
1785 : : */
1786 : : static int rss_add_actions(struct rte_flow *flow, struct pmd_internals *pmd,
1787 : : const struct rte_flow_action_rss *rss,
1788 : : struct rte_flow_error *error)
1789 : : {
1790 : : const struct bpf_program *rss_prog = pmd->rss->progs.rss_flow_action;
1791 : : struct rss_key rss_entry = { };
1792 : : const uint8_t *key_in;
1793 : : uint32_t hash_type = 0;
1794 : : uint32_t handle = flow->msg.t.tcm_handle;
1795 : : unsigned int i;
1796 : : int err;
1797 : :
1798 : : /* Check supported RSS features */
1799 : : if (rss->func != RTE_ETH_HASH_FUNCTION_DEFAULT)
1800 : : return rte_flow_error_set
1801 : : (error, ENOTSUP, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
1802 : : "non-default RSS hash functions are not supported");
1803 : : if (rss->level)
1804 : : return rte_flow_error_set
1805 : : (error, ENOTSUP, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
1806 : : "a nonzero RSS encapsulation level is not supported");
1807 : :
1808 : : if (rss->queue_num == 0 || rss->queue_num >= TAP_MAX_QUEUES)
1809 : : return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
1810 : : "invalid number of queues");
1811 : :
1812 : : /*
1813 : : * Follow the semantics of RSS key (see rte_ethdev.h)
1814 : : * There are two valid cases:
1815 : : * 1. key_length of zero, and key must be NULL;
1816 : : * this uses the default driver key.
1817 : : *
1818 : : * 2. key_length is the TAP_RSS_HASH_KEY_SIZE (40 bytes)
1819 : : * and the key must not be NULL.
1820 : : *
1821 : : * Anything else is an error.
1822 : : */
1823 : : if (rss->key_len == 0) {
1824 : : if (rss->key != NULL)
1825 : : return rte_flow_error_set(error, ENOTSUP,
1826 : : RTE_FLOW_ERROR_TYPE_ACTION_CONF,
1827 : : &rss->key_len, "RSS hash key length 0");
1828 : : key_in = rss_hash_default_key;
1829 : : } else {
1830 : : if (rss->key_len != TAP_RSS_HASH_KEY_SIZE)
1831 : : return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1832 : : NULL, "RSS hash invalid key length");
1833 : : if (rss->key == NULL)
1834 : : return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1835 : : NULL, "RSS hash key is NULL");
1836 : : key_in = rss->key;
1837 : : }
1838 : :
1839 : : if (rss->types & TAP_RSS_HF_MASK)
1840 : : return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1841 : : NULL, "RSS hash type not supported");
1842 : :
1843 : : if (rss->types & (RTE_ETH_RSS_NONFRAG_IPV4_UDP | RTE_ETH_RSS_NONFRAG_IPV4_TCP))
1844 : : hash_type |= RTE_BIT32(HASH_FIELD_IPV4_L3_L4);
1845 : : else if (rss->types & (RTE_ETH_RSS_IPV4 | RTE_ETH_RSS_FRAG_IPV4))
1846 : : hash_type |= RTE_BIT32(HASH_FIELD_IPV4_L3);
1847 : :
1848 : : if (rss->types & (RTE_ETH_RSS_NONFRAG_IPV6_UDP | RTE_ETH_RSS_NONFRAG_IPV6_TCP))
1849 : : hash_type |= RTE_BIT32(HASH_FIELD_IPV6_L3_L4);
1850 : : else if (rss->types & (RTE_ETH_RSS_IPV6 | RTE_ETH_RSS_FRAG_IPV6 | RTE_ETH_RSS_IPV6_EX))
1851 : : hash_type |= RTE_BIT32(HASH_FIELD_IPV6_L3);
1852 : :
1853 : : rss_entry.hash_fields = hash_type;
1854 : : rte_convert_rss_key((const uint32_t *)key_in, (uint32_t *)rss_entry.key,
1855 : : TAP_RSS_HASH_KEY_SIZE);
1856 : :
1857 : : /* Update RSS map entry with queues */
1858 : : rss_entry.nb_queues = rss->queue_num;
1859 : : for (i = 0; i < rss->queue_num; i++)
1860 : : rss_entry.queues[i] = rss->queue[i];
1861 : :
1862 : :
1863 : : /* Add this way for BPF to find entry in map */
1864 : : err = bpf_map__update_elem(pmd->rss->maps.rss_map,
1865 : : &handle, sizeof(handle),
1866 : : &rss_entry, sizeof(rss_entry), 0);
1867 : : if (err) {
1868 : : TAP_LOG(ERR,
1869 : : "Failed to update BPF map entry %#x (%d): %s",
1870 : : handle, errno, strerror(errno));
1871 : : rte_flow_error_set(
1872 : : error, ENOTSUP, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
1873 : : "Kernel too old or not configured "
1874 : : "to support BPF maps updates");
1875 : :
1876 : : return -ENOTSUP;
1877 : : }
1878 : :
1879 : : /* Add actions to mark packet then run the RSS BPF program */
1880 : : struct action_data adata[] = {
1881 : : {
1882 : : .id = "skbedit",
1883 : : .skbedit = {
1884 : : .skbedit.action = TC_ACT_PIPE,
1885 : : .mark = handle,
1886 : : },
1887 : : },
1888 : : {
1889 : : .id = "bpf",
1890 : : .bpf = {
1891 : : .bpf.action = TC_ACT_PIPE,
1892 : : .annotation = "tap_rss",
1893 : : .bpf_fd = bpf_program__fd(rss_prog),
1894 : : },
1895 : : },
1896 : : };
1897 : :
1898 : : return add_actions(flow, RTE_DIM(adata), adata, TCA_FLOWER_ACT);
1899 : : }
1900 : : #endif
1901 : :
1902 : : int
1903 : 0 : tap_flow_init(struct pmd_internals *pmd)
1904 : : {
1905 [ # # ]: 0 : if (qdisc_create_multiq(pmd->nlsk_fd, pmd->if_index) < 0) {
1906 : 0 : TAP_LOG(ERR, "%s: failed to create multiq qdisc.",
1907 : : pmd->name);
1908 : 0 : return -1;
1909 : : }
1910 : :
1911 [ # # ]: 0 : if (qdisc_create_ingress(pmd->nlsk_fd, pmd->if_index) < 0) {
1912 : 0 : TAP_LOG(ERR, "%s: failed to create ingress qdisc.",
1913 : : pmd->name);
1914 : 0 : return -1;
1915 : : }
1916 : :
1917 : 0 : pmd->flow_init = 1;
1918 : :
1919 : 0 : return 0;
1920 : : }
1921 : :
1922 : : /**
1923 : : * Get rte_flow operations.
1924 : : *
1925 : : * @param dev
1926 : : * Pointer to Ethernet device structure.
1927 : : * @param ops
1928 : : * Pointer to operation-specific structure.
1929 : : *
1930 : : * @return
1931 : : * 0 on success, negative errno value on failure.
1932 : : */
1933 : : int
1934 : 0 : tap_dev_flow_ops_get(struct rte_eth_dev *dev __rte_unused,
1935 : : const struct rte_flow_ops **ops)
1936 : : {
1937 : 0 : *ops = &tap_flow_ops;
1938 : 0 : return 0;
1939 : : }
|