Coverage Report

Created: 2025-07-11 06:12

/src/openvswitch/lib/netdev-offload-tc.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (c) 2016 Mellanox Technologies, Ltd.
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at:
7
 *
8
 *     http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
17
#include <config.h>
18
19
#include <errno.h>
20
#include <linux/if_ether.h>
21
22
#include "ccmap.h"
23
#include "dpif.h"
24
#include "hash.h"
25
#include "id-pool.h"
26
#include "openvswitch/hmap.h"
27
#include "openvswitch/match.h"
28
#include "openvswitch/ofpbuf.h"
29
#include "openvswitch/thread.h"
30
#include "openvswitch/types.h"
31
#include "openvswitch/util.h"
32
#include "openvswitch/vlog.h"
33
#include "netdev-linux.h"
34
#include "netdev-offload-provider.h"
35
#include "netdev-provider.h"
36
#include "netdev-vport.h"
37
#include "netlink.h"
38
#include "netlink-socket.h"
39
#include "odp-netlink.h"
40
#include "odp-util.h"
41
#include "tc.h"
42
#include "unaligned.h"
43
#include "util.h"
44
#include "dpif-provider.h"
45
46
VLOG_DEFINE_THIS_MODULE(netdev_offload_tc);
47
48
static struct vlog_rate_limit error_rl = VLOG_RATE_LIMIT_INIT(60, 5);
49
static struct vlog_rate_limit warn_rl = VLOG_RATE_LIMIT_INIT(10, 2);
50
51
static struct hmap ufid_to_tc = HMAP_INITIALIZER(&ufid_to_tc);
52
static struct hmap tc_to_ufid = HMAP_INITIALIZER(&tc_to_ufid);
53
static bool multi_mask_per_prio = false;
54
static bool block_support = false;
55
static uint16_t ct_state_support;
56
static bool vxlan_gbp_support = false;
57
static bool enc_flags_support = false;
58
59
struct netlink_field {
60
    int offset;
61
    int flower_offset;
62
    int size;
63
};
64
65
struct chain_node {
66
    struct hmap_node node;
67
    uint32_t chain;
68
};
69
70
struct meter_police_mapping_data {
71
    struct hmap_node meter_id_node;
72
    struct hmap_node police_idx_node;
73
    uint32_t meter_id;
74
    uint32_t police_idx;
75
};
76
77
struct policer_node {
78
    struct hmap_node node;
79
    uint32_t police_idx;
80
};
81
82
/* ccmap and protective mutex for counting recirculation id (chain) usage. */
83
static struct ovs_mutex used_chains_mutex = OVS_MUTEX_INITIALIZER;
84
static struct ccmap used_chains OVS_GUARDED;
85
86
/* Protects below meter police ids pool. */
87
static struct ovs_mutex meter_police_ids_mutex = OVS_MUTEX_INITIALIZER;
88
static struct id_pool *meter_police_ids OVS_GUARDED_BY(meter_police_ids_mutex);
89
/* Protects below meter hashmaps. */
90
static struct ovs_mutex meter_mutex = OVS_MUTEX_INITIALIZER;
91
static struct hmap meter_id_to_police_idx OVS_GUARDED_BY(meter_mutex)
92
    = HMAP_INITIALIZER(&meter_id_to_police_idx);
93
static struct hmap police_idx_to_meter_id OVS_GUARDED_BY(meter_mutex)
94
    = HMAP_INITIALIZER(&police_idx_to_meter_id);
95
96
static int meter_id_lookup(uint32_t meter_id, uint32_t *police_idx);
97
static int police_idx_lookup(uint32_t police_idx, uint32_t *meter_id);
98
99
static int netdev_tc_parse_nl_actions(struct netdev *netdev,
100
                                      struct tc_flower *flower,
101
                                      struct offload_info *info,
102
                                      const struct nlattr *actions,
103
                                      size_t actions_len,
104
                                      bool *recirc_act, bool more_actions,
105
                                      struct tc_action **need_jump_update);
106
107
static void parse_tc_flower_to_stats(struct tc_flower *flower,
108
                                     struct dpif_flow_stats *stats);
109
110
static int get_ufid_adjust_stats(const ovs_u128 *ufid,
111
                                 struct dpif_flow_stats *stats);
112
113
static bool
114
is_internal_port(const char *type)
115
0
{
116
0
    return !strcmp(type, "internal");
117
0
}
118
119
static enum tc_qdisc_hook
120
get_tc_qdisc_hook(struct netdev *netdev)
121
0
{
122
0
    return is_internal_port(netdev_get_type(netdev)) ? TC_EGRESS : TC_INGRESS;
123
0
}
124
125
static struct netlink_field set_flower_map[][4] = {
126
    [OVS_KEY_ATTR_IPV4] = {
127
        { offsetof(struct ovs_key_ipv4, ipv4_src),
128
          offsetof(struct tc_flower_key, ipv4.ipv4_src),
129
          MEMBER_SIZEOF(struct tc_flower_key, ipv4.ipv4_src)
130
        },
131
        { offsetof(struct ovs_key_ipv4, ipv4_dst),
132
          offsetof(struct tc_flower_key, ipv4.ipv4_dst),
133
          MEMBER_SIZEOF(struct tc_flower_key, ipv4.ipv4_dst)
134
        },
135
        { offsetof(struct ovs_key_ipv4, ipv4_ttl),
136
          offsetof(struct tc_flower_key, ipv4.rewrite_ttl),
137
          MEMBER_SIZEOF(struct tc_flower_key, ipv4.rewrite_ttl)
138
        },
139
        { offsetof(struct ovs_key_ipv4, ipv4_tos),
140
          offsetof(struct tc_flower_key, ipv4.rewrite_tos),
141
          MEMBER_SIZEOF(struct tc_flower_key, ipv4.rewrite_tos)
142
        },
143
    },
144
    [OVS_KEY_ATTR_IPV6] = {
145
        { offsetof(struct ovs_key_ipv6, ipv6_src),
146
          offsetof(struct tc_flower_key, ipv6.ipv6_src),
147
          MEMBER_SIZEOF(struct tc_flower_key, ipv6.ipv6_src)
148
        },
149
        { offsetof(struct ovs_key_ipv6, ipv6_dst),
150
          offsetof(struct tc_flower_key, ipv6.ipv6_dst),
151
          MEMBER_SIZEOF(struct tc_flower_key, ipv6.ipv6_dst)
152
        },
153
        { offsetof(struct ovs_key_ipv6, ipv6_hlimit),
154
          offsetof(struct tc_flower_key, ipv6.rewrite_hlimit),
155
          MEMBER_SIZEOF(struct tc_flower_key, ipv6.rewrite_hlimit)
156
        },
157
        { offsetof(struct ovs_key_ipv6, ipv6_tclass),
158
          offsetof(struct tc_flower_key, ipv6.rewrite_tclass),
159
          MEMBER_SIZEOF(struct tc_flower_key, ipv6.rewrite_tclass)
160
        },
161
    },
162
    [OVS_KEY_ATTR_ETHERNET] = {
163
        { offsetof(struct ovs_key_ethernet, eth_src),
164
          offsetof(struct tc_flower_key, src_mac),
165
          MEMBER_SIZEOF(struct tc_flower_key, src_mac)
166
        },
167
        { offsetof(struct ovs_key_ethernet, eth_dst),
168
          offsetof(struct tc_flower_key, dst_mac),
169
          MEMBER_SIZEOF(struct tc_flower_key, dst_mac)
170
        },
171
    },
172
    [OVS_KEY_ATTR_ETHERTYPE] = {
173
        { 0,
174
          offsetof(struct tc_flower_key, eth_type),
175
          MEMBER_SIZEOF(struct tc_flower_key, eth_type)
176
        },
177
    },
178
    [OVS_KEY_ATTR_TCP] = {
179
        { offsetof(struct ovs_key_tcp, tcp_src),
180
          offsetof(struct tc_flower_key, tcp_src),
181
          MEMBER_SIZEOF(struct tc_flower_key, tcp_src)
182
        },
183
        { offsetof(struct ovs_key_tcp, tcp_dst),
184
          offsetof(struct tc_flower_key, tcp_dst),
185
          MEMBER_SIZEOF(struct tc_flower_key, tcp_dst)
186
        },
187
    },
188
    [OVS_KEY_ATTR_UDP] = {
189
        { offsetof(struct ovs_key_udp, udp_src),
190
          offsetof(struct tc_flower_key, udp_src),
191
          MEMBER_SIZEOF(struct tc_flower_key, udp_src)
192
        },
193
        { offsetof(struct ovs_key_udp, udp_dst),
194
          offsetof(struct tc_flower_key, udp_dst),
195
          MEMBER_SIZEOF(struct tc_flower_key, udp_dst)
196
        },
197
    },
198
};
199
200
static struct ovs_mutex ufid_lock = OVS_MUTEX_INITIALIZER;
201
202
/**
203
 * struct ufid_tc_data - data entry for ufid-tc hashmaps.
204
 * @ufid_to_tc_node: Element in @ufid_to_tc hash table by ufid key.
205
 * @tc_to_ufid_node: Element in @tc_to_ufid hash table by tcf_id key.
206
 * @ufid: ufid assigned to the flow
207
 * @id: tc filter id (tcf_id)
208
 * @netdev: netdev associated with the tc rule
209
 * @adjust_stats: When flow gets updated with new actions, we need to adjust
210
 *                the reported stats to include previous values as the hardware
211
 *                rule is removed and re-added. This stats copy is used for it.
212
 * @chain_goto: If a TC jump action exists for the flow, the target chain it
213
 *              jumps to is stored here.  Only a single goto action is stored,
214
 *              as TC supports only one goto action per flow (there is no
215
 *              return mechanism).
216
 */
217
struct ufid_tc_data {
218
    struct hmap_node ufid_to_tc_node;
219
    struct hmap_node tc_to_ufid_node;
220
    ovs_u128 ufid;
221
    struct tcf_id id;
222
    struct netdev *netdev;
223
    struct dpif_flow_stats adjust_stats;
224
    uint32_t chain_goto;
225
};
226
227
static void
228
del_ufid_tc_mapping_unlocked(const ovs_u128 *ufid)
229
0
{
230
0
    size_t ufid_hash = hash_bytes(ufid, sizeof *ufid, 0);
231
0
    struct ufid_tc_data *data;
232
233
0
    HMAP_FOR_EACH_WITH_HASH (data, ufid_to_tc_node, ufid_hash, &ufid_to_tc) {
234
0
        if (ovs_u128_equals(*ufid, data->ufid)) {
235
0
            break;
236
0
        }
237
0
    }
238
239
0
    if (!data) {
240
0
        return;
241
0
    }
242
243
0
    hmap_remove(&ufid_to_tc, &data->ufid_to_tc_node);
244
0
    hmap_remove(&tc_to_ufid, &data->tc_to_ufid_node);
245
0
    netdev_close(data->netdev);
246
247
0
    if (data->chain_goto) {
248
0
        ovs_mutex_lock(&used_chains_mutex);
249
0
        ccmap_dec(&used_chains, data->chain_goto);
250
0
        ovs_mutex_unlock(&used_chains_mutex);
251
0
    }
252
253
0
    free(data);
254
0
}
255
256
/* Remove matching ufid entry from ufid-tc hashmaps. */
257
static void
258
del_ufid_tc_mapping(const ovs_u128 *ufid)
259
0
{
260
0
    ovs_mutex_lock(&ufid_lock);
261
0
    del_ufid_tc_mapping_unlocked(ufid);
262
0
    ovs_mutex_unlock(&ufid_lock);
263
0
}
264
265
static void
266
netdev_tc_adjust_stats(struct dpif_flow_stats *stats,
267
                       const struct dpif_flow_stats *adjust_stats)
268
0
{
269
    /* Do not try to restore the stats->used, as in terse mode dumps TC doesn't
270
     * report TCA_ACT_OPTIONS, so the 'lastused' value is not available, hence
271
     * we report used as 0.
272
     * tcp_flags is not collected by tc, so no need to update it. */
273
0
    stats->n_bytes += adjust_stats->n_bytes;
274
0
    stats->n_packets += adjust_stats->n_packets;
275
0
}
276
277
/* Wrapper function to delete filter and ufid tc mapping */
278
static int
279
del_filter_and_ufid_mapping(struct tcf_id *id, const ovs_u128 *ufid,
280
                            struct dpif_flow_stats *stats)
281
0
{
282
0
    struct tc_flower flower;
283
0
    int err;
284
285
0
    if (stats) {
286
0
        memset(stats, 0, sizeof *stats);
287
0
        if (!tc_get_flower(id, &flower)) {
288
0
            struct dpif_flow_stats adjust_stats;
289
290
0
            parse_tc_flower_to_stats(&flower, stats);
291
0
            if (!get_ufid_adjust_stats(ufid, &adjust_stats)) {
292
0
                netdev_tc_adjust_stats(stats, &adjust_stats);
293
0
            }
294
0
        }
295
0
    }
296
297
0
    err = tc_del_flower_filter(id);
298
0
    if (!err || err == ENODEV) {
299
0
        del_ufid_tc_mapping(ufid);
300
0
        return 0;
301
0
    }
302
0
    return err;
303
0
}
304
305
/* Add ufid entry to ufid_to_tc hashmap. */
306
static void
307
add_ufid_tc_mapping(struct netdev *netdev, const ovs_u128 *ufid,
308
                    struct tcf_id *id, struct dpif_flow_stats *stats,
309
                    uint32_t chain_goto)
310
0
{
311
0
    struct ufid_tc_data *new_data = xzalloc(sizeof *new_data);
312
0
    size_t ufid_hash = hash_bytes(ufid, sizeof *ufid, 0);
313
0
    size_t tc_hash;
314
315
0
    tc_hash = hash_int(hash_int(id->prio, id->handle), id->ifindex);
316
0
    tc_hash = hash_int(id->chain, tc_hash);
317
318
0
    new_data->ufid = *ufid;
319
0
    new_data->id = *id;
320
0
    new_data->netdev = netdev_ref(netdev);
321
0
    new_data->chain_goto = chain_goto;
322
323
0
    if (stats) {
324
0
        new_data->adjust_stats = *stats;
325
0
    }
326
327
0
    ovs_mutex_lock(&ufid_lock);
328
0
    hmap_insert(&ufid_to_tc, &new_data->ufid_to_tc_node, ufid_hash);
329
0
    hmap_insert(&tc_to_ufid, &new_data->tc_to_ufid_node, tc_hash);
330
0
    ovs_mutex_unlock(&ufid_lock);
331
0
}
332
333
/* Get tc id from ufid_to_tc hashmap.
334
 *
335
 * Returns 0 if successful and fills id.
336
 * Otherwise returns the error.
337
 */
338
static int
339
get_ufid_tc_mapping(const ovs_u128 *ufid, struct tcf_id *id)
340
0
{
341
0
    size_t ufid_hash = hash_bytes(ufid, sizeof *ufid, 0);
342
0
    struct ufid_tc_data *data;
343
344
0
    ovs_mutex_lock(&ufid_lock);
345
0
    HMAP_FOR_EACH_WITH_HASH (data, ufid_to_tc_node, ufid_hash, &ufid_to_tc) {
346
0
        if (ovs_u128_equals(*ufid, data->ufid)) {
347
0
            *id = data->id;
348
0
            ovs_mutex_unlock(&ufid_lock);
349
0
            return 0;
350
0
        }
351
0
    }
352
0
    ovs_mutex_unlock(&ufid_lock);
353
354
0
    return ENOENT;
355
0
}
356
357
/* Get adjust_stats from ufid_to_tc hashmap.
358
 *
359
 * Returns 0 if successful and fills stats with adjust_stats.
360
 * Otherwise returns the error.
361
*/
362
static int
363
get_ufid_adjust_stats(const ovs_u128 *ufid, struct dpif_flow_stats *stats)
364
0
{
365
0
    size_t ufid_hash = hash_bytes(ufid, sizeof *ufid, 0);
366
0
    struct ufid_tc_data *data;
367
368
0
    ovs_mutex_lock(&ufid_lock);
369
0
    HMAP_FOR_EACH_WITH_HASH (data, ufid_to_tc_node, ufid_hash, &ufid_to_tc) {
370
0
        if (ovs_u128_equals(*ufid, data->ufid)) {
371
0
            *stats = data->adjust_stats;
372
0
            ovs_mutex_unlock(&ufid_lock);
373
0
            return 0;
374
0
        }
375
0
    }
376
0
    ovs_mutex_unlock(&ufid_lock);
377
378
0
    return ENOENT;
379
0
}
380
381
/* Find ufid entry in ufid_to_tc hashmap using tcf_id id.
382
 * The result is saved in ufid.
383
 *
384
 * Returns true on success.
385
 */
386
static bool
387
find_ufid(struct netdev *netdev, struct tcf_id *id, ovs_u128 *ufid)
388
0
{
389
0
    struct ufid_tc_data *data;
390
0
    size_t tc_hash;
391
392
0
    tc_hash = hash_int(hash_int(id->prio, id->handle), id->ifindex);
393
0
    tc_hash = hash_int(id->chain, tc_hash);
394
395
0
    ovs_mutex_lock(&ufid_lock);
396
0
    HMAP_FOR_EACH_WITH_HASH (data, tc_to_ufid_node, tc_hash,  &tc_to_ufid) {
397
0
        if (netdev == data->netdev && is_tcf_id_eq(&data->id, id)) {
398
0
            *ufid = data->ufid;
399
0
            break;
400
0
        }
401
0
    }
402
0
    ovs_mutex_unlock(&ufid_lock);
403
404
0
    return (data != NULL);
405
0
}
406
407
struct prio_map_data {
408
    struct hmap_node node;
409
    struct tc_flower_key mask;
410
    ovs_be16 protocol;
411
    uint16_t prio;
412
};
413
414
static uint16_t
415
get_next_available_prio(ovs_be16 protocol)
416
0
{
417
0
    static uint16_t last_prio = TC_RESERVED_PRIORITY_MAX;
418
419
0
    if (multi_mask_per_prio) {
420
0
        if (protocol == htons(ETH_P_IP)) {
421
0
            return TC_RESERVED_PRIORITY_IPV4;
422
0
        } else if (protocol == htons(ETH_P_IPV6)) {
423
0
            return TC_RESERVED_PRIORITY_IPV6;
424
0
        } else if (protocol == htons(ETH_P_8021Q)) {
425
0
            return TC_RESERVED_PRIORITY_VLAN;
426
0
        }
427
0
    }
428
429
    /* last_prio can overflow if there will be many different kinds of
430
     * flows which shouldn't happen organically. */
431
0
    if (last_prio == TC_MAX_PRIORITY) {
432
0
        return TC_RESERVED_PRIORITY_NONE;
433
0
    }
434
435
0
    return ++last_prio;
436
0
}
437
438
/* Get free prio for tc flower
439
 * If prio is already allocated for mask/eth_type combination then return it.
440
 * If not assign new prio.
441
 *
442
 * Return prio on success or 0 if we are out of prios.
443
 */
444
static uint16_t
445
get_prio_for_tc_flower(struct tc_flower *flower)
446
0
{
447
0
    static struct hmap prios = HMAP_INITIALIZER(&prios);
448
0
    static struct ovs_mutex prios_lock = OVS_MUTEX_INITIALIZER;
449
0
    size_t key_len = sizeof(struct tc_flower_key);
450
0
    size_t hash = hash_int((OVS_FORCE uint32_t) flower->key.eth_type, 0);
451
0
    struct prio_map_data *data;
452
0
    struct prio_map_data *new_data;
453
0
    uint16_t prio;
454
455
0
    if (!multi_mask_per_prio) {
456
0
        hash = hash_bytes(&flower->mask, key_len, hash);
457
0
    }
458
459
    /* We can use the same prio for same mask/eth combination but must have
460
     * different prio if not. Flower classifier will reject same prio for
461
     * different mask combination unless multi mask per prio is supported. */
462
0
    ovs_mutex_lock(&prios_lock);
463
0
    HMAP_FOR_EACH_WITH_HASH (data, node, hash, &prios) {
464
0
        if ((multi_mask_per_prio
465
0
             || !memcmp(&flower->mask, &data->mask, key_len))
466
0
            && data->protocol == flower->key.eth_type) {
467
0
            ovs_mutex_unlock(&prios_lock);
468
0
            return data->prio;
469
0
        }
470
0
    }
471
472
0
    prio = get_next_available_prio(flower->key.eth_type);
473
0
    if (prio == TC_RESERVED_PRIORITY_NONE) {
474
0
        ovs_mutex_unlock(&prios_lock);
475
0
        return prio;
476
0
    }
477
478
0
    new_data = xzalloc(sizeof *new_data);
479
0
    memcpy(&new_data->mask, &flower->mask, key_len);
480
0
    new_data->prio = prio;
481
0
    new_data->protocol = flower->key.eth_type;
482
0
    hmap_insert(&prios, &new_data->node, hash);
483
0
    ovs_mutex_unlock(&prios_lock);
484
485
0
    return prio;
486
0
}
487
488
static uint32_t
489
get_block_id_from_netdev(struct netdev *netdev)
490
0
{
491
0
    if (block_support) {
492
0
        return netdev_get_block_id(netdev);
493
0
    }
494
495
0
    return 0;
496
0
}
497
498
static int
499
get_chains_from_netdev(struct netdev *netdev, struct tcf_id *id,
500
                       struct hmap *map)
501
0
{
502
0
    struct netdev_flow_dump *dump;
503
0
    struct chain_node *chain_node;
504
0
    struct ofpbuf rbuffer, reply;
505
0
    uint32_t chain;
506
0
    size_t hash;
507
0
    int err;
508
509
0
    dump = xzalloc(sizeof *dump);
510
0
    dump->nl_dump = xzalloc(sizeof *dump->nl_dump);
511
0
    dump->netdev = netdev_ref(netdev);
512
513
0
    ofpbuf_init(&rbuffer, NL_DUMP_BUFSIZE);
514
0
    tc_dump_tc_chain_start(id, dump->nl_dump);
515
516
0
    while (nl_dump_next(dump->nl_dump, &reply, &rbuffer)) {
517
0
        if (parse_netlink_to_tc_chain(&reply, &chain)) {
518
0
            continue;
519
0
        }
520
521
0
        chain_node = xzalloc(sizeof *chain_node);
522
0
        chain_node->chain = chain;
523
0
        hash = hash_int(chain, 0);
524
0
        hmap_insert(map, &chain_node->node, hash);
525
0
    }
526
527
0
    err = nl_dump_done(dump->nl_dump);
528
0
    ofpbuf_uninit(&rbuffer);
529
0
    netdev_close(netdev);
530
0
    free(dump->nl_dump);
531
0
    free(dump);
532
533
0
    return err;
534
0
}
535
536
static int
537
delete_chains_from_netdev(struct netdev *netdev, struct tcf_id *id)
538
0
{
539
0
    struct chain_node *chain_node;
540
0
    struct hmap map;
541
0
    int error;
542
543
0
    hmap_init(&map);
544
0
    error = get_chains_from_netdev(netdev, id, &map);
545
546
0
    if (!error) {
547
        /* Flush rules explicitly needed when we work with ingress_block,
548
         * so we will not fail with reattaching block to bond iface, for ex.
549
         */
550
0
        HMAP_FOR_EACH_POP (chain_node, node, &map) {
551
0
            id->chain = chain_node->chain;
552
            /* Delete empty chain doesn't seem to work with
553
             * tc_del_flower_filter() so use tc_del_filter()
554
             * without specifying TCA_KIND.
555
             */
556
0
            tc_del_filter(id, NULL);
557
0
            free(chain_node);
558
0
        }
559
0
    }
560
561
0
    hmap_destroy(&map);
562
0
    return error;
563
0
}
564
565
static int
566
netdev_tc_flow_flush(struct netdev *netdev)
567
0
{
568
0
    struct ufid_tc_data *data;
569
0
    int err;
570
571
0
    ovs_mutex_lock(&ufid_lock);
572
0
    HMAP_FOR_EACH_SAFE (data, tc_to_ufid_node, &tc_to_ufid) {
573
0
        if (data->netdev != netdev) {
574
0
            continue;
575
0
        }
576
577
0
        err = tc_del_flower_filter(&data->id);
578
0
        if (!err) {
579
0
            del_ufid_tc_mapping_unlocked(&data->ufid);
580
0
        }
581
0
    }
582
0
    ovs_mutex_unlock(&ufid_lock);
583
584
0
    return 0;
585
0
}
586
587
static int
588
netdev_tc_flow_dump_create(struct netdev *netdev,
589
                           struct netdev_flow_dump **dump_out,
590
                           bool terse)
591
0
{
592
0
    enum tc_qdisc_hook hook = get_tc_qdisc_hook(netdev);
593
0
    struct netdev_flow_dump *dump;
594
0
    uint32_t block_id = 0;
595
0
    struct tcf_id id;
596
0
    int prio = 0;
597
0
    int ifindex;
598
599
0
    ifindex = netdev_get_ifindex(netdev);
600
0
    if (ifindex < 0) {
601
0
        VLOG_ERR_RL(&error_rl, "dump_create: failed to get ifindex for %s: %s",
602
0
                    netdev_get_name(netdev), ovs_strerror(-ifindex));
603
0
        return -ifindex;
604
0
    }
605
606
0
    block_id = get_block_id_from_netdev(netdev);
607
0
    dump = xzalloc(sizeof *dump);
608
0
    dump->nl_dump = xzalloc(sizeof *dump->nl_dump);
609
0
    dump->netdev = netdev_ref(netdev);
610
0
    dump->terse = terse;
611
612
0
    id = tc_make_tcf_id(ifindex, block_id, prio, hook);
613
0
    tc_dump_flower_start(&id, dump->nl_dump, terse);
614
615
0
    *dump_out = dump;
616
617
0
    return 0;
618
0
}
619
620
static int
621
netdev_tc_flow_dump_destroy(struct netdev_flow_dump *dump)
622
0
{
623
0
    nl_dump_done(dump->nl_dump);
624
0
    netdev_close(dump->netdev);
625
0
    free(dump->nl_dump);
626
0
    free(dump);
627
0
    return 0;
628
0
}
629
630
static void
631
parse_flower_rewrite_to_netlink_action(struct ofpbuf *buf,
632
                                       struct tc_action *action)
633
0
{
634
0
    char *mask = (char *) &action->rewrite.mask;
635
0
    char *data = (char *) &action->rewrite.key;
636
637
0
    for (int type = 0; type < ARRAY_SIZE(set_flower_map); type++) {
638
0
        char *put = NULL;
639
0
        size_t nested = 0;
640
0
        int len = ovs_flow_key_attr_lens[type].len;
641
642
0
        if (len <= 0) {
643
0
            continue;
644
0
        }
645
646
0
        for (int j = 0; j < ARRAY_SIZE(set_flower_map[type]); j++) {
647
0
            struct netlink_field *f = &set_flower_map[type][j];
648
649
0
            if (!f->size) {
650
0
                break;
651
0
            }
652
653
0
            if (!is_all_zeros(mask + f->flower_offset, f->size)) {
654
0
                if (!put) {
655
0
                    nested = nl_msg_start_nested(buf,
656
0
                                                 OVS_ACTION_ATTR_SET_MASKED);
657
0
                    put = nl_msg_put_unspec_zero(buf, type, len * 2);
658
0
                }
659
660
0
                memcpy(put + f->offset, data + f->flower_offset, f->size);
661
0
                memcpy(put + len + f->offset,
662
0
                       mask + f->flower_offset, f->size);
663
0
            }
664
0
        }
665
666
0
        if (put) {
667
0
            nl_msg_end_nested(buf, nested);
668
0
        }
669
0
    }
670
0
}
671
672
static void parse_tc_flower_geneve_opts(struct tc_action *action,
673
                                        struct ofpbuf *buf)
674
0
{
675
0
    int tun_opt_len = action->encap.data.present.len;
676
0
    size_t geneve_off;
677
0
    int idx = 0;
678
679
0
    if (!tun_opt_len) {
680
0
        return;
681
0
    }
682
683
0
    geneve_off = nl_msg_start_nested(buf, OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS);
684
0
    while (tun_opt_len) {
685
0
        struct geneve_opt *opt;
686
687
0
        opt = &action->encap.data.opts.gnv[idx];
688
0
        nl_msg_put(buf, opt, sizeof(struct geneve_opt) + opt->length * 4);
689
0
        idx += sizeof(struct geneve_opt) / 4 + opt->length;
690
0
        tun_opt_len -= sizeof(struct geneve_opt) + opt->length * 4;
691
0
    }
692
0
    nl_msg_end_nested(buf, geneve_off);
693
0
}
694
695
static int
696
parse_tc_flower_vxlan_tun_opts(struct tc_action *action, struct ofpbuf *buf)
697
0
{
698
0
    size_t gbp_off;
699
0
    uint32_t gbp_raw;
700
701
0
    if (!action->encap.gbp.id_present) {
702
0
        return 0;
703
0
    }
704
0
    if (!vxlan_gbp_support) {
705
0
        return -EOPNOTSUPP;
706
0
    }
707
708
0
    gbp_off = nl_msg_start_nested(buf, OVS_TUNNEL_KEY_ATTR_VXLAN_OPTS);
709
0
    gbp_raw = odp_encode_gbp_raw(action->encap.gbp.flags,
710
0
                                 action->encap.gbp.id);
711
0
    nl_msg_put_u32(buf, OVS_VXLAN_EXT_GBP, gbp_raw);
712
0
    nl_msg_end_nested(buf, gbp_off);
713
0
    return 0;
714
0
}
715
716
static void
717
flower_tun_opt_to_match(struct match *match, struct tc_flower *flower)
718
0
{
719
0
    struct geneve_opt *opt, *opt_mask;
720
0
    int len, cnt = 0;
721
722
    /* Options are always in UDPIF format in the 'flower'. */
723
0
    match->flow.tunnel.flags |= FLOW_TNL_F_UDPIF;
724
0
    match->wc.masks.tunnel.flags |= FLOW_TNL_F_UDPIF;
725
726
0
    match->flow.tunnel.metadata.present.len =
727
0
           flower->key.tunnel.metadata.present.len;
728
    /* In the 'flower' mask len is an actual length, not a mask.  But in the
729
     * 'match' it is an actual mask, so should be an exact match, because TC
730
     * will always match on the exact value. */
731
0
    match->wc.masks.tunnel.metadata.present.len = 0xff;
732
733
0
    if (!flower->key.tunnel.metadata.present.len) {
734
        /* No options present. */
735
0
        return;
736
0
    }
737
738
0
    memcpy(match->flow.tunnel.metadata.opts.gnv,
739
0
           flower->key.tunnel.metadata.opts.gnv,
740
0
           flower->key.tunnel.metadata.present.len);
741
0
    memcpy(match->wc.masks.tunnel.metadata.opts.gnv,
742
0
           flower->mask.tunnel.metadata.opts.gnv,
743
0
           flower->mask.tunnel.metadata.present.len);
744
745
    /* Fixing up 'length' fields of particular options, since these are
746
     * also not masks, but actual lengths in the 'flower' structure. */
747
0
    len = flower->key.tunnel.metadata.present.len;
748
0
    while (len) {
749
0
        opt = &match->flow.tunnel.metadata.opts.gnv[cnt];
750
0
        opt_mask = &match->wc.masks.tunnel.metadata.opts.gnv[cnt];
751
752
        /* "Exact" match as set in tun_metadata_to_geneve_mask__(). */
753
0
        opt_mask->length = 0x1f;
754
755
0
        cnt += sizeof(struct geneve_opt) / 4 + opt->length;
756
0
        len -= sizeof(struct geneve_opt) + opt->length * 4;
757
0
    }
758
0
}
759
760
static void
761
flower_tun_enc_flags_to_match(struct match *match, struct tc_flower *flower)
762
0
{
763
0
    uint32_t tc_flags = flower->key.tunnel.tc_enc_flags;
764
0
    uint32_t tc_mask = flower->mask.tunnel.tc_enc_flags;
765
0
    uint16_t *m_flags = &match->flow.tunnel.flags;
766
0
    uint16_t *m_mask = &match->wc.masks.tunnel.flags;
767
768
0
    if (tc_mask & TCA_FLOWER_KEY_FLAGS_TUNNEL_OAM) {
769
0
        if (tc_flags & TCA_FLOWER_KEY_FLAGS_TUNNEL_OAM) {
770
0
            *m_flags |= FLOW_TNL_F_OAM;
771
0
        }
772
0
        *m_mask |= FLOW_TNL_F_OAM;
773
0
    }
774
775
0
    if (tc_mask & TCA_FLOWER_KEY_FLAGS_TUNNEL_DONT_FRAGMENT) {
776
0
        if (tc_flags & TCA_FLOWER_KEY_FLAGS_TUNNEL_DONT_FRAGMENT) {
777
0
            *m_flags |= FLOW_TNL_F_DONT_FRAGMENT;
778
0
        }
779
0
        *m_mask |= FLOW_TNL_F_DONT_FRAGMENT;
780
0
    }
781
782
0
    if (tc_mask & TCA_FLOWER_KEY_FLAGS_TUNNEL_CSUM) {
783
0
        if (tc_flags & TCA_FLOWER_KEY_FLAGS_TUNNEL_CSUM) {
784
0
            *m_flags |= FLOW_TNL_F_CSUM;
785
0
        }
786
0
        *m_mask |= FLOW_TNL_F_CSUM;
787
0
    }
788
0
}
789
790
static void
791
parse_tc_flower_to_stats(struct tc_flower *flower,
792
                         struct dpif_flow_stats *stats)
793
0
{
794
0
    if (!stats) {
795
0
        return;
796
0
    }
797
798
0
    memset(stats, 0, sizeof *stats);
799
0
    stats->n_packets = get_32aligned_u64(&flower->stats_sw.n_packets);
800
0
    stats->n_packets += get_32aligned_u64(&flower->stats_hw.n_packets);
801
0
    stats->n_bytes = get_32aligned_u64(&flower->stats_sw.n_bytes);
802
0
    stats->n_bytes += get_32aligned_u64(&flower->stats_hw.n_bytes);
803
0
    stats->used = flower->lastused;
804
0
}
805
806
static void
807
parse_tc_flower_to_attrs(struct tc_flower *flower,
808
                         struct dpif_flow_attrs *attrs)
809
0
{
810
0
    attrs->offloaded = (flower->offloaded_state == TC_OFFLOADED_STATE_IN_HW ||
811
0
                        flower->offloaded_state ==
812
0
                        TC_OFFLOADED_STATE_UNDEFINED);
813
0
    attrs->dp_layer = "tc";
814
0
    attrs->dp_extra_info = NULL;
815
0
}
816
817
static int
818
parse_tc_flower_terse_to_match(struct tc_flower *flower,
819
                               struct match *match,
820
                               struct dpif_flow_stats *stats,
821
                               struct dpif_flow_attrs *attrs)
822
0
{
823
0
    match_init_catchall(match);
824
825
0
    parse_tc_flower_to_stats(flower, stats);
826
0
    parse_tc_flower_to_attrs(flower, attrs);
827
828
0
    return 0;
829
0
}
830
831
static int
832
parse_tc_flower_to_actions__(struct tc_flower *flower, struct ofpbuf *buf,
833
                             int start_index, int max_index)
834
0
{
835
0
    struct tc_action *action;
836
0
    int i;
837
838
0
    if (max_index <= 0 || max_index > flower->action_count) {
839
0
        max_index = flower->action_count;
840
0
    }
841
842
0
    for (i = start_index; i < max_index; i++) {
843
0
        action = &flower->actions[i];
844
845
0
        switch (action->type) {
846
0
        case TC_ACT_VLAN_POP: {
847
0
            nl_msg_put_flag(buf, OVS_ACTION_ATTR_POP_VLAN);
848
0
        }
849
0
        break;
850
0
        case TC_ACT_VLAN_PUSH: {
851
0
            struct ovs_action_push_vlan *push;
852
853
0
            push = nl_msg_put_unspec_zero(buf, OVS_ACTION_ATTR_PUSH_VLAN,
854
0
                                          sizeof *push);
855
0
            push->vlan_tpid = action->vlan.vlan_push_tpid;
856
0
            push->vlan_tci = htons(action->vlan.vlan_push_id
857
0
                                   | (action->vlan.vlan_push_prio << 13)
858
0
                                   | VLAN_CFI);
859
0
        }
860
0
        break;
861
0
        case TC_ACT_MPLS_POP: {
862
0
            nl_msg_put_be16(buf, OVS_ACTION_ATTR_POP_MPLS,
863
0
                            action->mpls.proto);
864
0
        }
865
0
        break;
866
0
        case TC_ACT_MPLS_PUSH: {
867
0
            struct ovs_action_push_mpls *push;
868
0
            ovs_be32 mpls_lse = 0;
869
870
0
            flow_set_mpls_lse_label(&mpls_lse, action->mpls.label);
871
0
            flow_set_mpls_lse_tc(&mpls_lse, action->mpls.tc);
872
0
            flow_set_mpls_lse_ttl(&mpls_lse, action->mpls.ttl);
873
0
            flow_set_mpls_lse_bos(&mpls_lse, action->mpls.bos);
874
875
0
            push = nl_msg_put_unspec_zero(buf, OVS_ACTION_ATTR_PUSH_MPLS,
876
0
                                          sizeof *push);
877
0
            push->mpls_ethertype = action->mpls.proto;
878
0
            push->mpls_lse = mpls_lse;
879
0
        }
880
0
        break;
881
0
        case TC_ACT_MPLS_SET: {
882
0
            size_t set_offset = nl_msg_start_nested(buf,
883
0
                                                    OVS_ACTION_ATTR_SET);
884
0
            struct ovs_key_mpls *set_mpls;
885
0
            ovs_be32 mpls_lse = 0;
886
887
0
            flow_set_mpls_lse_label(&mpls_lse, action->mpls.label);
888
0
            flow_set_mpls_lse_tc(&mpls_lse, action->mpls.tc);
889
0
            flow_set_mpls_lse_ttl(&mpls_lse, action->mpls.ttl);
890
0
            flow_set_mpls_lse_bos(&mpls_lse, action->mpls.bos);
891
892
0
            set_mpls = nl_msg_put_unspec_zero(buf, OVS_KEY_ATTR_MPLS,
893
0
                                              sizeof *set_mpls);
894
0
            set_mpls->mpls_lse = mpls_lse;
895
0
            nl_msg_end_nested(buf, set_offset);
896
0
        }
897
0
        break;
898
0
        case TC_ACT_PEDIT: {
899
0
            parse_flower_rewrite_to_netlink_action(buf, action);
900
0
        }
901
0
        break;
902
0
        case TC_ACT_ENCAP: {
903
0
            size_t set_offset = nl_msg_start_nested(buf, OVS_ACTION_ATTR_SET);
904
0
            size_t tunnel_offset =
905
0
                nl_msg_start_nested(buf, OVS_KEY_ATTR_TUNNEL);
906
0
            int ret;
907
908
0
            if (action->encap.id_present) {
909
0
                nl_msg_put_be64(buf, OVS_TUNNEL_KEY_ATTR_ID, action->encap.id);
910
0
            }
911
0
            if (action->encap.ipv4.ipv4_src) {
912
0
                nl_msg_put_be32(buf, OVS_TUNNEL_KEY_ATTR_IPV4_SRC,
913
0
                                action->encap.ipv4.ipv4_src);
914
0
            }
915
0
            if (action->encap.ipv4.ipv4_dst) {
916
0
                nl_msg_put_be32(buf, OVS_TUNNEL_KEY_ATTR_IPV4_DST,
917
0
                                action->encap.ipv4.ipv4_dst);
918
0
            }
919
0
            if (ipv6_addr_is_set(&action->encap.ipv6.ipv6_src)) {
920
0
                nl_msg_put_in6_addr(buf, OVS_TUNNEL_KEY_ATTR_IPV6_SRC,
921
0
                                    &action->encap.ipv6.ipv6_src);
922
0
            }
923
0
            if (ipv6_addr_is_set(&action->encap.ipv6.ipv6_dst)) {
924
0
                nl_msg_put_in6_addr(buf, OVS_TUNNEL_KEY_ATTR_IPV6_DST,
925
0
                                    &action->encap.ipv6.ipv6_dst);
926
0
            }
927
0
            if (action->encap.tos) {
928
0
                nl_msg_put_u8(buf, OVS_TUNNEL_KEY_ATTR_TOS,
929
0
                              action->encap.tos);
930
0
            }
931
0
            if (action->encap.ttl) {
932
0
                nl_msg_put_u8(buf, OVS_TUNNEL_KEY_ATTR_TTL,
933
0
                              action->encap.ttl);
934
0
            }
935
0
            if (action->encap.tp_dst) {
936
0
                nl_msg_put_be16(buf, OVS_TUNNEL_KEY_ATTR_TP_DST,
937
0
                                action->encap.tp_dst);
938
0
            }
939
0
            if (!action->encap.no_csum) {
940
0
                nl_msg_put_flag(buf, OVS_TUNNEL_KEY_ATTR_CSUM);
941
0
            }
942
0
            if (action->encap.dont_fragment) {
943
0
                nl_msg_put_flag(buf, OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT);
944
0
            }
945
0
            ret = parse_tc_flower_vxlan_tun_opts(action, buf);
946
0
            if (ret) {
947
0
                return ret;
948
0
            }
949
0
            parse_tc_flower_geneve_opts(action, buf);
950
0
            nl_msg_end_nested(buf, tunnel_offset);
951
0
            nl_msg_end_nested(buf, set_offset);
952
0
        }
953
0
        break;
954
0
        case TC_ACT_OUTPUT: {
955
0
            odp_port_t outport = 0;
956
957
0
            if (action->out.ifindex_out) {
958
0
                outport =
959
0
                    netdev_ifindex_to_odp_port(action->out.ifindex_out);
960
0
                if (!outport) {
961
0
                    return -ENOENT;
962
0
                }
963
0
            }
964
0
            nl_msg_put_u32(buf, OVS_ACTION_ATTR_OUTPUT, odp_to_u32(outport));
965
0
        }
966
0
        break;
967
0
        case TC_ACT_CT: {
968
0
            size_t ct_offset;
969
970
0
            if (action->ct.clear) {
971
0
                nl_msg_put_flag(buf, OVS_ACTION_ATTR_CT_CLEAR);
972
0
                break;
973
0
            }
974
975
0
            ct_offset = nl_msg_start_nested(buf, OVS_ACTION_ATTR_CT);
976
977
0
            if (action->ct.commit) {
978
0
                if (action->ct.force) {
979
0
                    nl_msg_put_flag(buf, OVS_CT_ATTR_FORCE_COMMIT);
980
0
                } else {
981
0
                    nl_msg_put_flag(buf, OVS_CT_ATTR_COMMIT);
982
0
                }
983
0
            }
984
985
0
            if (action->ct.zone) {
986
0
                nl_msg_put_u16(buf, OVS_CT_ATTR_ZONE, action->ct.zone);
987
0
            }
988
989
0
            if (action->ct.mark_mask) {
990
0
                uint32_t mark_and_mask[2] = { action->ct.mark,
991
0
                                              action->ct.mark_mask };
992
0
                nl_msg_put_unspec(buf, OVS_CT_ATTR_MARK, &mark_and_mask,
993
0
                                  sizeof mark_and_mask);
994
0
            }
995
996
0
            if (!ovs_u128_is_zero(action->ct.label_mask)) {
997
0
                struct {
998
0
                    ovs_u128 key;
999
0
                    ovs_u128 mask;
1000
0
                } ct_label = {
1001
0
                    .key = action->ct.label,
1002
0
                    .mask = action->ct.label_mask,
1003
0
                };
1004
1005
0
                nl_msg_put_unspec(buf, OVS_CT_ATTR_LABELS,
1006
0
                                  &ct_label, sizeof ct_label);
1007
0
            }
1008
1009
0
            if (action->ct.nat_type) {
1010
0
                size_t nat_offset = nl_msg_start_nested(buf,
1011
0
                                                        OVS_CT_ATTR_NAT);
1012
1013
0
                if (action->ct.nat_type == TC_NAT_SRC) {
1014
0
                    nl_msg_put_flag(buf, OVS_NAT_ATTR_SRC);
1015
0
                } else if (action->ct.nat_type == TC_NAT_DST) {
1016
0
                    nl_msg_put_flag(buf, OVS_NAT_ATTR_DST);
1017
0
                }
1018
1019
0
                if (action->ct.range.ip_family == AF_INET) {
1020
0
                    nl_msg_put_be32(buf, OVS_NAT_ATTR_IP_MIN,
1021
0
                                    action->ct.range.ipv4.min);
1022
0
                    nl_msg_put_be32(buf, OVS_NAT_ATTR_IP_MAX,
1023
0
                                    action->ct.range.ipv4.max);
1024
0
                } else if (action->ct.range.ip_family == AF_INET6) {
1025
0
                    nl_msg_put_in6_addr(buf, OVS_NAT_ATTR_IP_MIN,
1026
0
                                        &action->ct.range.ipv6.min);
1027
0
                    nl_msg_put_in6_addr(buf, OVS_NAT_ATTR_IP_MAX,
1028
0
                                        &action->ct.range.ipv6.max);
1029
0
                }
1030
1031
0
                if (action->ct.range.port.min) {
1032
0
                    nl_msg_put_u16(buf, OVS_NAT_ATTR_PROTO_MIN,
1033
0
                                   ntohs(action->ct.range.port.min));
1034
0
                    if (action->ct.range.port.max) {
1035
0
                        nl_msg_put_u16(buf, OVS_NAT_ATTR_PROTO_MAX,
1036
0
                                       ntohs(action->ct.range.port.max));
1037
0
                    }
1038
0
                }
1039
1040
0
                nl_msg_end_nested(buf, nat_offset);
1041
0
            }
1042
1043
0
            nl_msg_end_nested(buf, ct_offset);
1044
0
        }
1045
0
        break;
1046
0
        case TC_ACT_GOTO: {
1047
0
            nl_msg_put_u32(buf, OVS_ACTION_ATTR_RECIRC, action->chain);
1048
0
        }
1049
0
        break;
1050
0
        case TC_ACT_POLICE: {
1051
0
            uint32_t meter_id;
1052
1053
0
            if (police_idx_lookup(action->police.index, &meter_id)) {
1054
0
                return -ENOENT;
1055
0
            }
1056
0
            nl_msg_put_u32(buf, OVS_ACTION_ATTR_METER, meter_id);
1057
0
        }
1058
0
        break;
1059
0
        case TC_ACT_POLICE_MTU: {
1060
0
            size_t offset, act_offset;
1061
0
            uint32_t jump;
1062
1063
0
            offset = nl_msg_start_nested(buf,
1064
0
                                         OVS_ACTION_ATTR_CHECK_PKT_LEN);
1065
1066
0
            nl_msg_put_u16(buf, OVS_CHECK_PKT_LEN_ATTR_PKT_LEN,
1067
0
                           action->police.mtu);
1068
1069
0
            act_offset = nl_msg_start_nested(
1070
0
                buf, OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_GREATER);
1071
0
            i = parse_tc_flower_to_actions__(flower, buf, i + 1,
1072
0
                                             action->police.result_jump);
1073
0
            if (i < 0) {
1074
0
                return i;
1075
0
            }
1076
0
            nl_msg_end_nested(buf, act_offset);
1077
1078
0
            act_offset = nl_msg_start_nested(
1079
0
                buf, OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_LESS_EQUAL);
1080
1081
0
            jump = flower->actions[i - 1].jump_action;
1082
0
            if (jump == JUMP_ACTION_STOP) {
1083
0
                jump = max_index;
1084
0
            }
1085
0
            if (jump != 0) {
1086
0
                i = parse_tc_flower_to_actions__(flower, buf, i, jump);
1087
0
                if (i < 0) {
1088
0
                    return i;
1089
0
                }
1090
0
            }
1091
0
            nl_msg_end_nested(buf, act_offset);
1092
1093
0
            i--;
1094
0
            nl_msg_end_nested(buf, offset);
1095
0
        }
1096
0
        break;
1097
0
        }
1098
1099
0
        if (action->jump_action && action->type != TC_ACT_POLICE_MTU) {
1100
            /* If there is a jump, it means this was the end of an action
1101
             * set and we need to end this branch. */
1102
0
            i++;
1103
0
            break;
1104
0
        }
1105
0
    }
1106
0
    return i;
1107
0
}
1108
1109
static int
1110
parse_tc_flower_to_actions(struct tc_flower *flower,
1111
                           struct ofpbuf *buf)
1112
0
{
1113
0
    return parse_tc_flower_to_actions__(flower, buf, 0, 0);
1114
0
}
1115
1116
static int
1117
parse_tc_flower_to_match(const struct netdev *netdev,
1118
                         struct tc_flower *flower,
1119
                         struct match *match,
1120
                         struct nlattr **actions,
1121
                         struct dpif_flow_stats *stats,
1122
                         struct dpif_flow_attrs *attrs,
1123
                         struct ofpbuf *buf,
1124
                         bool terse)
1125
0
{
1126
0
    struct tc_flower_key *key = &flower->key;
1127
0
    struct tc_flower_key *mask = &flower->mask;
1128
0
    size_t act_off;
1129
0
    int err;
1130
1131
0
    if (terse) {
1132
0
        return parse_tc_flower_terse_to_match(flower, match, stats, attrs);
1133
0
    }
1134
1135
0
    ofpbuf_clear(buf);
1136
1137
0
    match_init_catchall(match);
1138
0
    match_set_dl_src_masked(match, key->src_mac, mask->src_mac);
1139
0
    match_set_dl_dst_masked(match, key->dst_mac, mask->dst_mac);
1140
1141
0
    if (eth_type_vlan(key->eth_type)) {
1142
0
        match->flow.vlans[0].tpid = key->eth_type;
1143
0
        match->wc.masks.vlans[0].tpid = OVS_BE16_MAX;
1144
0
        match_set_dl_vlan(match, htons(key->vlan_id[0]), 0);
1145
0
        match_set_dl_vlan_pcp(match, key->vlan_prio[0], 0);
1146
1147
0
        if (eth_type_vlan(key->encap_eth_type[0])) {
1148
0
            match_set_dl_vlan(match, htons(key->vlan_id[1]), 1);
1149
0
            match_set_dl_vlan_pcp(match, key->vlan_prio[1], 1);
1150
0
            match_set_dl_type(match, key->encap_eth_type[1]);
1151
0
            match->flow.vlans[1].tpid = key->encap_eth_type[0];
1152
0
            match->wc.masks.vlans[1].tpid = OVS_BE16_MAX;
1153
0
        } else {
1154
0
            match_set_dl_type(match, key->encap_eth_type[0]);
1155
0
        }
1156
0
        flow_fix_vlan_tpid(&match->flow);
1157
0
    } else if (eth_type_mpls(key->eth_type)) {
1158
0
        match->flow.mpls_lse[0] = key->mpls_lse & mask->mpls_lse;
1159
0
        match->wc.masks.mpls_lse[0] = mask->mpls_lse;
1160
0
        match_set_dl_type(match, key->encap_eth_type[0]);
1161
0
    } else if (key->eth_type == htons(ETH_TYPE_ARP)) {
1162
0
        match_set_arp_sha_masked(match, key->arp.sha, mask->arp.sha);
1163
0
        match_set_arp_tha_masked(match, key->arp.tha, mask->arp.tha);
1164
0
        match_set_arp_spa_masked(match, key->arp.spa, mask->arp.spa);
1165
0
        match_set_arp_tpa_masked(match, key->arp.tpa, mask->arp.tpa);
1166
0
        match_set_arp_opcode_masked(match, key->arp.opcode,
1167
0
                                    mask->arp.opcode);
1168
0
        match_set_dl_type(match, key->eth_type);
1169
0
    } else {
1170
0
        match_set_dl_type(match, key->eth_type);
1171
0
    }
1172
1173
0
    if (is_ip_any(&match->flow)) {
1174
0
        if (key->ip_proto) {
1175
0
            match_set_nw_proto(match, key->ip_proto);
1176
0
        }
1177
1178
0
        match_set_nw_tos_masked(match, key->ip_tos, mask->ip_tos);
1179
0
        match_set_nw_ttl_masked(match, key->ip_ttl, mask->ip_ttl);
1180
1181
0
        if (mask->flags) {
1182
0
            uint8_t flags = 0;
1183
0
            uint8_t flags_mask = 0;
1184
1185
0
            if (mask->flags & TCA_FLOWER_KEY_FLAGS_IS_FRAGMENT) {
1186
0
                if (key->flags & TCA_FLOWER_KEY_FLAGS_IS_FRAGMENT) {
1187
0
                    flags |= FLOW_NW_FRAG_ANY;
1188
0
                }
1189
0
                flags_mask |= FLOW_NW_FRAG_ANY;
1190
0
            }
1191
1192
0
            if (mask->flags & TCA_FLOWER_KEY_FLAGS_FRAG_IS_FIRST) {
1193
0
                if (!(key->flags & TCA_FLOWER_KEY_FLAGS_FRAG_IS_FIRST)) {
1194
0
                    flags |= FLOW_NW_FRAG_LATER;
1195
0
                }
1196
0
                flags_mask |= FLOW_NW_FRAG_LATER;
1197
0
            }
1198
1199
0
            match_set_nw_frag_masked(match, flags, flags_mask);
1200
0
        }
1201
1202
0
        match_set_nw_src_masked(match, key->ipv4.ipv4_src, mask->ipv4.ipv4_src);
1203
0
        match_set_nw_dst_masked(match, key->ipv4.ipv4_dst, mask->ipv4.ipv4_dst);
1204
1205
0
        match_set_ipv6_src_masked(match,
1206
0
                                  &key->ipv6.ipv6_src, &mask->ipv6.ipv6_src);
1207
0
        match_set_ipv6_dst_masked(match,
1208
0
                                  &key->ipv6.ipv6_dst, &mask->ipv6.ipv6_dst);
1209
1210
0
        if (key->ip_proto == IPPROTO_TCP) {
1211
0
            match_set_tp_dst_masked(match, key->tcp_dst, mask->tcp_dst);
1212
0
            match_set_tp_src_masked(match, key->tcp_src, mask->tcp_src);
1213
0
            match_set_tcp_flags_masked(match, key->tcp_flags, mask->tcp_flags);
1214
0
        } else if (key->ip_proto == IPPROTO_UDP) {
1215
0
            match_set_tp_dst_masked(match, key->udp_dst, mask->udp_dst);
1216
0
            match_set_tp_src_masked(match, key->udp_src, mask->udp_src);
1217
0
        } else if (key->ip_proto == IPPROTO_SCTP) {
1218
0
            match_set_tp_dst_masked(match, key->sctp_dst, mask->sctp_dst);
1219
0
            match_set_tp_src_masked(match, key->sctp_src, mask->sctp_src);
1220
0
        } else if (key->ip_proto == IPPROTO_ICMP ||
1221
0
                   key->ip_proto == IPPROTO_ICMPV6) {
1222
0
            match_set_tp_dst_masked(match, htons(key->icmp_code),
1223
0
                                    htons(mask->icmp_code));
1224
0
            match_set_tp_src_masked(match, htons(key->icmp_type),
1225
0
                                    htons(mask->icmp_type));
1226
0
        }
1227
1228
0
        if (mask->ct_state) {
1229
0
            uint8_t ct_statev = 0, ct_statem = 0;
1230
1231
0
            if (mask->ct_state & TCA_FLOWER_KEY_CT_FLAGS_NEW) {
1232
0
                if (key->ct_state & TCA_FLOWER_KEY_CT_FLAGS_NEW) {
1233
0
                    ct_statev |= OVS_CS_F_NEW;
1234
0
                }
1235
0
                ct_statem |= OVS_CS_F_NEW;
1236
0
            }
1237
1238
0
            if (mask->ct_state & TCA_FLOWER_KEY_CT_FLAGS_ESTABLISHED) {
1239
0
                if (key->ct_state & TCA_FLOWER_KEY_CT_FLAGS_ESTABLISHED) {
1240
0
                    ct_statev |= OVS_CS_F_ESTABLISHED;
1241
0
                }
1242
0
                ct_statem |= OVS_CS_F_ESTABLISHED;
1243
0
            }
1244
1245
0
            if (mask->ct_state & TCA_FLOWER_KEY_CT_FLAGS_TRACKED) {
1246
0
                if (key->ct_state & TCA_FLOWER_KEY_CT_FLAGS_TRACKED) {
1247
0
                    ct_statev |= OVS_CS_F_TRACKED;
1248
0
                }
1249
0
                ct_statem |= OVS_CS_F_TRACKED;
1250
0
            }
1251
1252
0
            if (mask->ct_state & TCA_FLOWER_KEY_CT_FLAGS_REPLY) {
1253
0
                if (key->ct_state & TCA_FLOWER_KEY_CT_FLAGS_REPLY) {
1254
0
                    ct_statev |= OVS_CS_F_REPLY_DIR;
1255
0
                }
1256
0
                ct_statem |= OVS_CS_F_REPLY_DIR;
1257
0
            }
1258
1259
0
            if (mask->ct_state & TCA_FLOWER_KEY_CT_FLAGS_INVALID) {
1260
0
                if (key->ct_state & TCA_FLOWER_KEY_CT_FLAGS_INVALID) {
1261
0
                    ct_statev |= OVS_CS_F_INVALID;
1262
0
                }
1263
0
                ct_statem |= OVS_CS_F_INVALID;
1264
0
            }
1265
1266
0
            if (mask->ct_state & TCA_FLOWER_KEY_CT_FLAGS_RELATED) {
1267
0
                if (key->ct_state & TCA_FLOWER_KEY_CT_FLAGS_RELATED) {
1268
0
                    ct_statev |= OVS_CS_F_RELATED;
1269
0
                }
1270
0
                ct_statem |= OVS_CS_F_RELATED;
1271
0
            }
1272
1273
0
            match_set_ct_state_masked(match, ct_statev, ct_statem);
1274
0
        }
1275
1276
0
        match_set_ct_zone_masked(match, key->ct_zone, mask->ct_zone);
1277
0
        match_set_ct_mark_masked(match, key->ct_mark, mask->ct_mark);
1278
0
        match_set_ct_label_masked(match, key->ct_label, mask->ct_label);
1279
0
    }
1280
1281
0
    if (flower->tunnel) {
1282
0
        if (flower->mask.tunnel.id) {
1283
0
            match_set_tun_id(match, flower->key.tunnel.id);
1284
0
            match->flow.tunnel.flags |= FLOW_TNL_F_KEY;
1285
0
        }
1286
0
        if (flower->mask.tunnel.ipv4.ipv4_dst ||
1287
0
            flower->mask.tunnel.ipv4.ipv4_src) {
1288
0
            match_set_tun_dst_masked(match,
1289
0
                                     flower->key.tunnel.ipv4.ipv4_dst,
1290
0
                                     flower->mask.tunnel.ipv4.ipv4_dst);
1291
0
            match_set_tun_src_masked(match,
1292
0
                                     flower->key.tunnel.ipv4.ipv4_src,
1293
0
                                     flower->mask.tunnel.ipv4.ipv4_src);
1294
0
        } else if (ipv6_addr_is_set(&flower->mask.tunnel.ipv6.ipv6_dst) ||
1295
0
                   ipv6_addr_is_set(&flower->mask.tunnel.ipv6.ipv6_src)) {
1296
0
            match_set_tun_ipv6_dst_masked(match,
1297
0
                                          &flower->key.tunnel.ipv6.ipv6_dst,
1298
0
                                          &flower->mask.tunnel.ipv6.ipv6_dst);
1299
0
            match_set_tun_ipv6_src_masked(match,
1300
0
                                          &flower->key.tunnel.ipv6.ipv6_src,
1301
0
                                          &flower->mask.tunnel.ipv6.ipv6_src);
1302
0
        }
1303
0
        if (flower->mask.tunnel.tos) {
1304
0
            match_set_tun_tos_masked(match, flower->key.tunnel.tos,
1305
0
                                     flower->mask.tunnel.tos);
1306
0
        }
1307
0
        if (flower->mask.tunnel.ttl) {
1308
0
            match_set_tun_ttl_masked(match, flower->key.tunnel.ttl,
1309
0
                                     flower->mask.tunnel.ttl);
1310
0
        }
1311
0
        if (flower->mask.tunnel.tp_src) {
1312
0
            match_set_tun_tp_dst_masked(match, flower->key.tunnel.tp_src,
1313
0
                                        flower->mask.tunnel.tp_src);
1314
0
        }
1315
0
        if (flower->mask.tunnel.tp_dst) {
1316
0
            match_set_tun_tp_dst_masked(match, flower->key.tunnel.tp_dst,
1317
0
                                        flower->mask.tunnel.tp_dst);
1318
0
        }
1319
0
        if (flower->mask.tunnel.gbp.id) {
1320
0
            match_set_tun_gbp_id_masked(match, flower->key.tunnel.gbp.id,
1321
0
                                        flower->mask.tunnel.gbp.id);
1322
0
        }
1323
0
        if (flower->mask.tunnel.gbp.flags) {
1324
0
            match_set_tun_gbp_flags_masked(match,
1325
0
                                           flower->key.tunnel.gbp.flags,
1326
0
                                           flower->mask.tunnel.gbp.flags);
1327
0
        }
1328
0
        if (flower->mask.tunnel.tc_enc_flags) {
1329
0
            flower_tun_enc_flags_to_match(match, flower);
1330
0
        }
1331
1332
0
        if (!strcmp(netdev_get_type(netdev), "geneve")) {
1333
0
            flower_tun_opt_to_match(match, flower);
1334
0
        }
1335
0
    }
1336
1337
0
    act_off = nl_msg_start_nested(buf, OVS_FLOW_ATTR_ACTIONS);
1338
0
    err = parse_tc_flower_to_actions(flower, buf);
1339
0
    if (err < 0) {
1340
0
        return -err;
1341
0
    }
1342
0
    nl_msg_end_nested(buf, act_off);
1343
1344
0
    *actions = ofpbuf_at_assert(buf, act_off, sizeof(struct nlattr));
1345
1346
0
    parse_tc_flower_to_stats(flower, stats);
1347
0
    parse_tc_flower_to_attrs(flower, attrs);
1348
1349
0
    return 0;
1350
0
}
1351
1352
static bool
1353
netdev_tc_flow_dump_next(struct netdev_flow_dump *dump,
1354
                         struct match *match,
1355
                         struct nlattr **actions,
1356
                         struct dpif_flow_stats *stats,
1357
                         struct dpif_flow_attrs *attrs,
1358
                         ovs_u128 *ufid,
1359
                         struct ofpbuf *rbuffer,
1360
                         struct ofpbuf *wbuffer)
1361
0
{
1362
0
    struct netdev *netdev = dump->netdev;
1363
0
    struct ofpbuf nl_flow;
1364
0
    struct tcf_id id;
1365
1366
0
    id = tc_make_tcf_id(netdev_get_ifindex(netdev),
1367
0
                        get_block_id_from_netdev(netdev),
1368
0
                        0, /* prio */
1369
0
                        get_tc_qdisc_hook(netdev));
1370
1371
0
    while (nl_dump_next(dump->nl_dump, &nl_flow, rbuffer)) {
1372
0
        struct dpif_flow_stats adjust_stats;
1373
0
        struct tc_flower flower;
1374
1375
0
        if (parse_netlink_to_tc_flower(&nl_flow, &id, &flower, dump->terse)) {
1376
0
            continue;
1377
0
        }
1378
1379
0
        if (parse_tc_flower_to_match(netdev, &flower, match, actions,
1380
0
                                     stats, attrs, wbuffer, dump->terse)) {
1381
0
            continue;
1382
0
        }
1383
1384
0
        if (flower.act_cookie.len >= sizeof *ufid) {
1385
0
            *ufid = get_32aligned_u128(flower.act_cookie.data);
1386
0
        } else if (!find_ufid(netdev, &id, ufid)) {
1387
0
            continue;
1388
0
        }
1389
1390
0
        if (!get_ufid_adjust_stats(ufid, &adjust_stats)) {
1391
0
            netdev_tc_adjust_stats(stats, &adjust_stats);
1392
0
        }
1393
1394
0
        match->wc.masks.in_port.odp_port = u32_to_odp(UINT32_MAX);
1395
0
        match->flow.in_port.odp_port = dump->port;
1396
0
        match_set_recirc_id(match, id.chain);
1397
1398
0
        return true;
1399
0
    }
1400
1401
0
    return false;
1402
0
}
1403
1404
static int
1405
parse_mpls_set_action(struct tc_flower *flower, struct tc_action *action,
1406
                      const struct nlattr *set)
1407
0
{
1408
0
        const struct ovs_key_mpls *mpls_set = nl_attr_get(set);
1409
1410
0
        action->mpls.label = mpls_lse_to_label(mpls_set->mpls_lse);
1411
0
        action->mpls.tc = mpls_lse_to_tc(mpls_set->mpls_lse);
1412
0
        action->mpls.ttl = mpls_lse_to_ttl(mpls_set->mpls_lse);
1413
0
        action->mpls.bos = mpls_lse_to_bos(mpls_set->mpls_lse);
1414
0
        action->type = TC_ACT_MPLS_SET;
1415
0
        flower->action_count++;
1416
1417
0
        return 0;
1418
0
}
1419
1420
static int
1421
parse_put_flow_nat_action(struct tc_action *action,
1422
                          const struct nlattr *nat,
1423
                          size_t nat_len)
1424
0
{
1425
0
    const struct nlattr *nat_attr;
1426
0
    size_t nat_left;
1427
1428
0
    action->ct.nat_type = TC_NAT_RESTORE;
1429
0
    NL_ATTR_FOR_EACH_UNSAFE (nat_attr, nat_left, nat, nat_len) {
1430
0
        switch (nl_attr_type(nat_attr)) {
1431
0
            case OVS_NAT_ATTR_SRC: {
1432
0
                action->ct.nat_type = TC_NAT_SRC;
1433
0
            };
1434
0
            break;
1435
0
            case OVS_NAT_ATTR_DST: {
1436
0
                action->ct.nat_type = TC_NAT_DST;
1437
0
            };
1438
0
            break;
1439
0
            case OVS_NAT_ATTR_IP_MIN: {
1440
0
                if (nl_attr_get_size(nat_attr) == sizeof(ovs_be32)) {
1441
0
                    ovs_be32 addr = nl_attr_get_be32(nat_attr);
1442
1443
0
                    action->ct.range.ipv4.min = addr;
1444
0
                    action->ct.range.ip_family = AF_INET;
1445
0
                } else {
1446
0
                    struct in6_addr addr = nl_attr_get_in6_addr(nat_attr);
1447
1448
0
                    action->ct.range.ipv6.min = addr;
1449
0
                    action->ct.range.ip_family = AF_INET6;
1450
0
                }
1451
0
            };
1452
0
            break;
1453
0
            case OVS_NAT_ATTR_IP_MAX: {
1454
0
                if (nl_attr_get_size(nat_attr) == sizeof(ovs_be32)) {
1455
0
                    ovs_be32 addr = nl_attr_get_be32(nat_attr);
1456
1457
0
                    action->ct.range.ipv4.max = addr;
1458
0
                    action->ct.range.ip_family = AF_INET;
1459
0
                } else {
1460
0
                    struct in6_addr addr = nl_attr_get_in6_addr(nat_attr);
1461
1462
0
                    action->ct.range.ipv6.max = addr;
1463
0
                    action->ct.range.ip_family = AF_INET6;
1464
0
                }
1465
0
            };
1466
0
            break;
1467
0
            case OVS_NAT_ATTR_PROTO_MIN: {
1468
0
                action->ct.range.port.min = htons(nl_attr_get_u16(nat_attr));
1469
0
            };
1470
0
            break;
1471
0
            case OVS_NAT_ATTR_PROTO_MAX: {
1472
0
                action->ct.range.port.max = htons(nl_attr_get_u16(nat_attr));
1473
0
            };
1474
0
            break;
1475
0
        }
1476
0
    }
1477
0
    return 0;
1478
0
}
1479
1480
static int
1481
parse_put_flow_ct_action(struct tc_flower *flower,
1482
                         struct tc_action *action,
1483
                         const struct nlattr *ct,
1484
                         size_t ct_len)
1485
0
{
1486
0
        const struct nlattr *ct_attr;
1487
0
        size_t ct_left;
1488
0
        int err;
1489
1490
0
        NL_ATTR_FOR_EACH_UNSAFE (ct_attr, ct_left, ct, ct_len) {
1491
0
            switch (nl_attr_type(ct_attr)) {
1492
0
                case OVS_CT_ATTR_COMMIT: {
1493
0
                    action->ct.commit = true;
1494
0
                }
1495
0
                break;
1496
0
                case OVS_CT_ATTR_FORCE_COMMIT: {
1497
0
                    action->ct.commit = true;
1498
0
                    action->ct.force = true;
1499
0
                }
1500
0
                break;
1501
0
                case OVS_CT_ATTR_ZONE: {
1502
0
                    action->ct.zone = nl_attr_get_u16(ct_attr);
1503
0
                }
1504
0
                break;
1505
0
                case OVS_CT_ATTR_NAT: {
1506
0
                    const struct nlattr *nat = nl_attr_get(ct_attr);
1507
0
                    const size_t nat_len = nl_attr_get_size(ct_attr);
1508
1509
0
                    err = parse_put_flow_nat_action(action, nat, nat_len);
1510
0
                    if (err) {
1511
0
                        return err;
1512
0
                    }
1513
0
                }
1514
0
                break;
1515
0
                case OVS_CT_ATTR_MARK: {
1516
0
                    const struct {
1517
0
                        uint32_t key;
1518
0
                        uint32_t mask;
1519
0
                    } *ct_mark;
1520
1521
0
                    ct_mark = nl_attr_get_unspec(ct_attr, sizeof *ct_mark);
1522
0
                    action->ct.mark = ct_mark->key;
1523
0
                    action->ct.mark_mask = ct_mark->mask;
1524
0
                }
1525
0
                break;
1526
0
                case OVS_CT_ATTR_LABELS: {
1527
0
                    const struct {
1528
0
                        ovs_32aligned_u128 key;
1529
0
                        ovs_32aligned_u128 mask;
1530
0
                    } *ct_label;
1531
1532
0
                    ct_label = nl_attr_get_unspec(ct_attr, sizeof *ct_label);
1533
0
                    action->ct.label = get_32aligned_u128(&ct_label->key);
1534
0
                    action->ct.label_mask =
1535
0
                        get_32aligned_u128(&ct_label->mask);
1536
0
                }
1537
0
                break;
1538
                /* The following option we do not support in tc-ct, and should
1539
                 * not be ignored for proper operation. */
1540
0
                case OVS_CT_ATTR_HELPER:
1541
0
                    return EOPNOTSUPP;
1542
0
            }
1543
0
        }
1544
1545
0
        action->type = TC_ACT_CT;
1546
0
        flower->action_count++;
1547
0
        return 0;
1548
0
}
1549
1550
/* This function returns true if the tc layer will add a l4 checksum action
1551
 * for this set action.  Refer to the csum_update_flag() function for
1552
 * detailed logic.  Note that even the kernel only supports updating TCP,
1553
 * UDP and ICMPv6.
1554
 */
1555
static bool
1556
tc_will_add_l4_checksum(struct tc_flower *flower, int type)
1557
0
{
1558
0
    switch (type) {
1559
0
    case OVS_KEY_ATTR_IPV4:
1560
0
    case OVS_KEY_ATTR_IPV6:
1561
0
    case OVS_KEY_ATTR_TCP:
1562
0
    case OVS_KEY_ATTR_UDP:
1563
0
        switch (flower->key.ip_proto) {
1564
0
        case IPPROTO_TCP:
1565
0
        case IPPROTO_UDP:
1566
0
        case IPPROTO_ICMPV6:
1567
0
        case IPPROTO_UDPLITE:
1568
0
            return true;
1569
0
        }
1570
0
        break;
1571
0
    }
1572
0
    return false;
1573
0
}
1574
1575
static int
1576
parse_put_flow_set_masked_action(struct tc_flower *flower,
1577
                                 struct tc_action *action,
1578
                                 const struct nlattr *set,
1579
                                 size_t set_len,
1580
                                 bool hasmask)
1581
0
{
1582
0
    static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 20);
1583
0
    uint64_t set_stub[1024 / 8];
1584
0
    struct ofpbuf set_buf = OFPBUF_STUB_INITIALIZER(set_stub);
1585
0
    char *set_data, *set_mask;
1586
0
    char *key = (char *) &action->rewrite.key;
1587
0
    char *mask = (char *) &action->rewrite.mask;
1588
0
    const struct nlattr *attr;
1589
0
    int i, j, type;
1590
0
    size_t size;
1591
1592
    /* copy so we can set attr mask to 0 for used ovs key struct members  */
1593
0
    attr = ofpbuf_put(&set_buf, set, set_len);
1594
1595
0
    type = nl_attr_type(attr);
1596
0
    size = nl_attr_get_size(attr) / 2;
1597
0
    set_data = CONST_CAST(char *, nl_attr_get(attr));
1598
0
    set_mask = set_data + size;
1599
1600
0
    if (type >= ARRAY_SIZE(set_flower_map)
1601
0
        || !set_flower_map[type][0].size) {
1602
0
        VLOG_DBG_RL(&rl, "unsupported set action type: %d", type);
1603
0
        ofpbuf_uninit(&set_buf);
1604
0
        return EOPNOTSUPP;
1605
0
    }
1606
1607
0
    if (flower->key.flags & TCA_FLOWER_KEY_FLAGS_IS_FRAGMENT
1608
0
        && tc_will_add_l4_checksum(flower, type)) {
1609
0
        VLOG_DBG_RL(&rl, "set action type %d not supported on fragments "
1610
0
                    "due to checksum limitation", type);
1611
0
        ofpbuf_uninit(&set_buf);
1612
0
        return EOPNOTSUPP;
1613
0
    }
1614
1615
0
    for (i = 0; i < ARRAY_SIZE(set_flower_map[type]); i++) {
1616
0
        struct netlink_field *f = &set_flower_map[type][i];
1617
1618
0
        if (!f->size) {
1619
0
            break;
1620
0
        }
1621
1622
        /* copy masked value */
1623
0
        for (j = 0; j < f->size; j++) {
1624
0
            char maskval = hasmask ? set_mask[f->offset + j] : 0xFF;
1625
1626
0
            key[f->flower_offset + j] = maskval & set_data[f->offset + j];
1627
0
            mask[f->flower_offset + j] = maskval;
1628
1629
0
        }
1630
1631
        /* set its mask to 0 to show it's been used. */
1632
0
        if (hasmask) {
1633
0
            memset(set_mask + f->offset, 0, f->size);
1634
0
        }
1635
0
    }
1636
1637
0
    if (hasmask && !is_all_zeros(set_mask, size)) {
1638
0
        VLOG_DBG_RL(&rl, "unsupported sub attribute of set action type %d",
1639
0
                    type);
1640
0
        ofpbuf_uninit(&set_buf);
1641
0
        return EOPNOTSUPP;
1642
0
    }
1643
1644
0
    ofpbuf_uninit(&set_buf);
1645
0
    action->type = TC_ACT_PEDIT;
1646
0
    flower->action_count++;
1647
0
    return 0;
1648
0
}
1649
1650
static int
1651
parse_put_flow_set_action(struct tc_flower *flower, struct tc_action *action,
1652
                          const struct nlattr *set, size_t set_len)
1653
0
{
1654
0
    static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 20);
1655
0
    const struct nlattr *tunnel;
1656
0
    const struct nlattr *tun_attr;
1657
0
    size_t tun_left, tunnel_len;
1658
1659
0
    if (nl_attr_type(set) == OVS_KEY_ATTR_MPLS) {
1660
0
        return parse_mpls_set_action(flower, action, set);
1661
0
    }
1662
1663
0
    if (nl_attr_type(set) != OVS_KEY_ATTR_TUNNEL) {
1664
0
            return parse_put_flow_set_masked_action(flower, action, set,
1665
0
                                                    set_len, false);
1666
0
    }
1667
1668
0
    tunnel = nl_attr_get(set);
1669
0
    tunnel_len = nl_attr_get_size(set);
1670
1671
0
    action->type = TC_ACT_ENCAP;
1672
0
    action->encap.id_present = false;
1673
0
    action->encap.gbp.id_present = false;
1674
0
    action->encap.no_csum = 1;
1675
0
    flower->action_count++;
1676
0
    NL_ATTR_FOR_EACH_UNSAFE(tun_attr, tun_left, tunnel, tunnel_len) {
1677
0
        switch (nl_attr_type(tun_attr)) {
1678
0
        case OVS_TUNNEL_KEY_ATTR_ID: {
1679
0
            action->encap.id = nl_attr_get_be64(tun_attr);
1680
0
            action->encap.id_present = true;
1681
0
        }
1682
0
        break;
1683
0
        case OVS_TUNNEL_KEY_ATTR_IPV4_SRC: {
1684
0
            action->encap.ipv4.ipv4_src = nl_attr_get_be32(tun_attr);
1685
0
        }
1686
0
        break;
1687
0
        case OVS_TUNNEL_KEY_ATTR_IPV4_DST: {
1688
0
            action->encap.ipv4.ipv4_dst = nl_attr_get_be32(tun_attr);
1689
0
        }
1690
0
        break;
1691
0
        case OVS_TUNNEL_KEY_ATTR_TOS: {
1692
0
            action->encap.tos = nl_attr_get_u8(tun_attr);
1693
0
        }
1694
0
        break;
1695
0
        case OVS_TUNNEL_KEY_ATTR_TTL: {
1696
0
            action->encap.ttl = nl_attr_get_u8(tun_attr);
1697
0
        }
1698
0
        break;
1699
0
        case OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT: {
1700
0
            if (enc_flags_support) {
1701
0
                action->encap.dont_fragment = true;
1702
0
            } else {
1703
                /* For kernels not supporting the DF flag, we ignoring the
1704
                 * configuration requested by the user.  This to keep the old,
1705
                 * incorrect behaviour, and allow tunnels to be offloaded by
1706
                 * TC with these kernels. */
1707
0
            }
1708
0
        }
1709
0
        break;
1710
0
        case OVS_TUNNEL_KEY_ATTR_CSUM: {
1711
0
            action->encap.no_csum = 0;
1712
0
        }
1713
0
        break;
1714
0
        case OVS_TUNNEL_KEY_ATTR_IPV6_SRC: {
1715
0
            action->encap.ipv6.ipv6_src =
1716
0
                nl_attr_get_in6_addr(tun_attr);
1717
0
        }
1718
0
        break;
1719
0
        case OVS_TUNNEL_KEY_ATTR_IPV6_DST: {
1720
0
            action->encap.ipv6.ipv6_dst =
1721
0
                nl_attr_get_in6_addr(tun_attr);
1722
0
        }
1723
0
        break;
1724
0
        case OVS_TUNNEL_KEY_ATTR_TP_SRC: {
1725
            /* There is no corresponding attribute in TC. */
1726
0
            VLOG_DBG_RL(&rl, "unsupported tunnel key attribute TP_SRC");
1727
0
            return EOPNOTSUPP;
1728
0
        }
1729
0
        break;
1730
0
        case OVS_TUNNEL_KEY_ATTR_TP_DST: {
1731
0
            action->encap.tp_dst = nl_attr_get_be16(tun_attr);
1732
0
        }
1733
0
        break;
1734
0
        case OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS: {
1735
0
            memcpy(action->encap.data.opts.gnv, nl_attr_get(tun_attr),
1736
0
                   nl_attr_get_size(tun_attr));
1737
0
            action->encap.data.present.len = nl_attr_get_size(tun_attr);
1738
0
        }
1739
0
        break;
1740
0
        case OVS_TUNNEL_KEY_ATTR_VXLAN_OPTS: {
1741
0
            if (!vxlan_gbp_support) {
1742
0
                return EOPNOTSUPP;
1743
0
            }
1744
0
            if (odp_vxlan_tun_opts_from_attr(tun_attr,
1745
0
                                             &action->encap.gbp.id,
1746
0
                                             &action->encap.gbp.flags,
1747
0
                                             &action->encap.gbp.id_present)) {
1748
0
                VLOG_ERR_RL(&rl, "error parsing VXLAN options");
1749
0
                return EINVAL;
1750
0
            }
1751
0
        }
1752
0
        break;
1753
0
        default:
1754
0
            VLOG_DBG_RL(&rl, "unsupported tunnel key attribute %d",
1755
0
                        nl_attr_type(tun_attr));
1756
0
            return EOPNOTSUPP;
1757
0
        }
1758
0
    }
1759
1760
0
    return 0;
1761
0
}
1762
1763
static bool
1764
is_ipv6_fragment_and_masked(const struct flow *key, const struct flow *mask)
1765
0
{
1766
0
    if (key->dl_type != htons(ETH_P_IPV6)) {
1767
0
        return false;
1768
0
    }
1769
0
    if (mask->nw_proto && key->nw_proto == IPPROTO_FRAGMENT) {
1770
0
        return true;
1771
0
    }
1772
0
    if (key->nw_frag & (mask->nw_frag & FLOW_NW_FRAG_ANY)) {
1773
0
        return true;
1774
0
    }
1775
0
    return false;
1776
0
}
1777
1778
static int
1779
test_key_and_mask(struct match *match)
1780
0
{
1781
0
    static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 20);
1782
0
    const struct flow *key = &match->flow;
1783
0
    struct flow *mask = &match->wc.masks;
1784
1785
0
    if (mask->pkt_mark) {
1786
0
        VLOG_DBG_RL(&rl, "offloading attribute pkt_mark isn't supported");
1787
0
        return EOPNOTSUPP;
1788
0
    }
1789
1790
0
    if (mask->dp_hash) {
1791
0
        VLOG_DBG_RL(&rl, "offloading attribute dp_hash isn't supported");
1792
0
        return EOPNOTSUPP;
1793
0
    }
1794
1795
0
    if (mask->conj_id) {
1796
0
        VLOG_DBG_RL(&rl, "offloading attribute conj_id isn't supported");
1797
0
        return EOPNOTSUPP;
1798
0
    }
1799
1800
0
    if (mask->skb_priority) {
1801
0
        VLOG_DBG_RL(&rl, "offloading attribute skb_priority isn't supported");
1802
0
        return EOPNOTSUPP;
1803
0
    }
1804
1805
0
    if (mask->actset_output) {
1806
0
        VLOG_DBG_RL(&rl,
1807
0
                    "offloading attribute actset_output isn't supported");
1808
0
        return EOPNOTSUPP;
1809
0
    }
1810
1811
0
    if (mask->packet_type && key->packet_type) {
1812
0
        VLOG_DBG_RL(&rl, "offloading attribute packet_type isn't supported");
1813
0
        return EOPNOTSUPP;
1814
0
    }
1815
0
    mask->packet_type = 0;
1816
1817
0
    for (int i = 0; i < FLOW_N_REGS; i++) {
1818
0
        if (mask->regs[i]) {
1819
0
            VLOG_DBG_RL(&rl,
1820
0
                        "offloading attribute regs[%d] isn't supported", i);
1821
0
            return EOPNOTSUPP;
1822
0
        }
1823
0
    }
1824
1825
0
    if (mask->metadata) {
1826
0
        VLOG_DBG_RL(&rl, "offloading attribute metadata isn't supported");
1827
0
        return EOPNOTSUPP;
1828
0
    }
1829
1830
0
    if (mask->nw_tos) {
1831
0
        VLOG_DBG_RL(&rl, "offloading attribute nw_tos isn't supported");
1832
0
        return EOPNOTSUPP;
1833
0
    }
1834
1835
0
    for (int i = 1; i < FLOW_MAX_MPLS_LABELS; i++) {
1836
0
        if (mask->mpls_lse[i]) {
1837
0
            VLOG_DBG_RL(&rl, "offloading multiple mpls_lses isn't supported");
1838
0
            return EOPNOTSUPP;
1839
0
        }
1840
0
    }
1841
1842
0
    if (key->dl_type == htons(ETH_TYPE_IP) &&
1843
0
               key->nw_proto == IPPROTO_IGMP) {
1844
0
        if (mask->tp_src) {
1845
0
            VLOG_DBG_RL(&rl,
1846
0
                        "offloading attribute igmp_type isn't supported");
1847
0
            return EOPNOTSUPP;
1848
0
        }
1849
0
        if (mask->tp_dst) {
1850
0
            VLOG_DBG_RL(&rl,
1851
0
                        "offloading attribute igmp_code isn't supported");
1852
0
            return EOPNOTSUPP;
1853
0
        }
1854
0
    } else if (key->dl_type == htons(OFP_DL_TYPE_NOT_ETH_TYPE)) {
1855
0
        VLOG_DBG_RL(&rl,
1856
0
                    "offloading of non-ethernet packets isn't supported");
1857
0
        return EOPNOTSUPP;
1858
0
    }
1859
1860
0
    if (is_ipv6_fragment_and_masked(key, mask)) {
1861
0
        VLOG_DBG_RL(&rl, "offloading of IPv6 fragments isn't supported");
1862
0
        return EOPNOTSUPP;
1863
0
    }
1864
1865
0
    if (!is_all_zeros(mask, sizeof *mask)) {
1866
0
        if (!VLOG_DROP_DBG(&rl)) {
1867
0
            struct ds ds = DS_EMPTY_INITIALIZER;
1868
1869
0
            ds_put_cstr(&ds,
1870
0
                        "offloading isn't supported, unknown attribute\n"
1871
0
                        "Unused mask bits:\n");
1872
0
            ds_put_sparse_hex_dump(&ds, mask, sizeof *mask, 0, false);
1873
1874
0
            VLOG_DBG("%s", ds_cstr(&ds));
1875
0
            ds_destroy(&ds);
1876
0
        }
1877
0
        return EOPNOTSUPP;
1878
0
    }
1879
1880
0
    return 0;
1881
0
}
1882
1883
static int
1884
flower_match_to_tun_opt(struct tc_flower *flower, const struct flow_tnl *tnl,
1885
                        struct flow_tnl *tnl_mask)
1886
0
{
1887
0
    struct geneve_opt *opt, *opt_mask;
1888
0
    int tot_opt_len, len, cnt = 0;
1889
1890
    /* 'flower' always has an exact match on tunnel metadata length, so having
1891
     * it in a wrong format is not acceptable unless it is empty. */
1892
0
    if (!(tnl->flags & FLOW_TNL_F_UDPIF)) {
1893
0
        if (tnl->metadata.present.map) {
1894
            /* XXX: Add non-UDPIF format parsing here? */
1895
0
            VLOG_WARN_RL(&warn_rl, "Tunnel options are in the wrong format.");
1896
0
        } else {
1897
            /* There are no options, that equals for them to be in UDPIF format
1898
             * with a zero 'len'.  Clearing the 'map' mask as consumed.
1899
             * No need to explicitly set 'len' to zero in the 'flower'. */
1900
0
            tnl_mask->flags &= ~FLOW_TNL_F_UDPIF;
1901
0
            memset(&tnl_mask->metadata.present.map, 0,
1902
0
                   sizeof tnl_mask->metadata.present.map);
1903
0
        }
1904
0
        return 0;
1905
0
    }
1906
1907
0
    tnl_mask->flags &= ~FLOW_TNL_F_UDPIF;
1908
1909
0
    flower->key.tunnel.metadata.present.len = tnl->metadata.present.len;
1910
    /* Copying from the key and not from the mask, since in the 'flower'
1911
     * the length for a mask is not a mask, but the actual length.  TC
1912
     * will use an exact match for the length. */
1913
0
    flower->mask.tunnel.metadata.present.len = tnl->metadata.present.len;
1914
0
    memset(&tnl_mask->metadata.present.len, 0,
1915
0
           sizeof tnl_mask->metadata.present.len);
1916
1917
0
    if (!tnl->metadata.present.len) {
1918
0
        return 0;
1919
0
    }
1920
1921
0
    memcpy(flower->key.tunnel.metadata.opts.gnv, tnl->metadata.opts.gnv,
1922
0
           tnl->metadata.present.len);
1923
0
    memcpy(flower->mask.tunnel.metadata.opts.gnv, tnl_mask->metadata.opts.gnv,
1924
0
           tnl->metadata.present.len);
1925
1926
0
    memset(tnl_mask->metadata.opts.gnv, 0, tnl->metadata.present.len);
1927
1928
    /* Fixing up 'length' fields of particular options, since these are
1929
     * also not masks, but actual lengths in the 'flower' structure. */
1930
0
    len = flower->key.tunnel.metadata.present.len;
1931
0
    while (len) {
1932
0
        if (len < sizeof *opt) {
1933
0
            return EOPNOTSUPP;
1934
0
        }
1935
1936
0
        opt = &flower->key.tunnel.metadata.opts.gnv[cnt];
1937
0
        tot_opt_len = sizeof *opt + opt->length * 4;
1938
0
        if (len < tot_opt_len) {
1939
0
            return EOPNOTSUPP;
1940
0
        }
1941
1942
0
        opt_mask = &flower->mask.tunnel.metadata.opts.gnv[cnt];
1943
1944
0
        opt_mask->length = opt->length;
1945
1946
0
        cnt += sizeof(struct geneve_opt) / 4 + opt->length;
1947
0
        len -= sizeof(struct geneve_opt) + opt->length * 4;
1948
0
    }
1949
1950
0
    return 0;
1951
0
}
1952
1953
static void
1954
parse_match_ct_state_to_flower(struct tc_flower *flower, struct match *match)
1955
0
{
1956
0
    const struct flow *key = &match->flow;
1957
0
    struct flow *mask = &match->wc.masks;
1958
1959
0
    if (!ct_state_support) {
1960
0
        return;
1961
0
    }
1962
1963
0
    if ((ct_state_support & mask->ct_state) == mask->ct_state) {
1964
0
        if (mask->ct_state & OVS_CS_F_NEW) {
1965
0
            if (key->ct_state & OVS_CS_F_NEW) {
1966
0
                flower->key.ct_state |= TCA_FLOWER_KEY_CT_FLAGS_NEW;
1967
0
            }
1968
0
            flower->mask.ct_state |= TCA_FLOWER_KEY_CT_FLAGS_NEW;
1969
0
            mask->ct_state &= ~OVS_CS_F_NEW;
1970
0
        }
1971
1972
0
        if (mask->ct_state & OVS_CS_F_ESTABLISHED) {
1973
0
            if (key->ct_state & OVS_CS_F_ESTABLISHED) {
1974
0
                flower->key.ct_state |= TCA_FLOWER_KEY_CT_FLAGS_ESTABLISHED;
1975
0
            }
1976
0
            flower->mask.ct_state |= TCA_FLOWER_KEY_CT_FLAGS_ESTABLISHED;
1977
0
            mask->ct_state &= ~OVS_CS_F_ESTABLISHED;
1978
0
        }
1979
1980
0
        if (mask->ct_state & OVS_CS_F_TRACKED) {
1981
0
            if (key->ct_state & OVS_CS_F_TRACKED) {
1982
0
                flower->key.ct_state |= TCA_FLOWER_KEY_CT_FLAGS_TRACKED;
1983
0
            }
1984
0
            flower->mask.ct_state |= TCA_FLOWER_KEY_CT_FLAGS_TRACKED;
1985
0
            mask->ct_state &= ~OVS_CS_F_TRACKED;
1986
0
        }
1987
1988
0
        if (mask->ct_state & OVS_CS_F_REPLY_DIR) {
1989
0
            if (key->ct_state & OVS_CS_F_REPLY_DIR) {
1990
0
                flower->key.ct_state |= TCA_FLOWER_KEY_CT_FLAGS_REPLY;
1991
0
            }
1992
0
            flower->mask.ct_state |= TCA_FLOWER_KEY_CT_FLAGS_REPLY;
1993
0
            mask->ct_state &= ~OVS_CS_F_REPLY_DIR;
1994
0
        }
1995
1996
0
        if (mask->ct_state & OVS_CS_F_INVALID) {
1997
0
            if (key->ct_state & OVS_CS_F_INVALID) {
1998
0
                flower->key.ct_state |= TCA_FLOWER_KEY_CT_FLAGS_INVALID;
1999
0
            }
2000
0
            flower->mask.ct_state |= TCA_FLOWER_KEY_CT_FLAGS_INVALID;
2001
0
            mask->ct_state &= ~OVS_CS_F_INVALID;
2002
0
        }
2003
2004
0
        if (mask->ct_state & OVS_CS_F_RELATED) {
2005
0
            if (key->ct_state & OVS_CS_F_RELATED) {
2006
0
                flower->key.ct_state |= TCA_FLOWER_KEY_CT_FLAGS_RELATED;
2007
0
            }
2008
0
            flower->mask.ct_state |= TCA_FLOWER_KEY_CT_FLAGS_RELATED;
2009
0
            mask->ct_state &= ~OVS_CS_F_RELATED;
2010
0
        }
2011
2012
0
        if (flower->key.ct_state & TCA_FLOWER_KEY_CT_FLAGS_ESTABLISHED) {
2013
0
            flower->key.ct_state &= ~(TCA_FLOWER_KEY_CT_FLAGS_NEW);
2014
0
            flower->mask.ct_state &= ~(TCA_FLOWER_KEY_CT_FLAGS_NEW);
2015
0
        }
2016
2017
0
        if (flower->key.ct_state &&
2018
0
            !(flower->key.ct_state & TCA_FLOWER_KEY_CT_FLAGS_TRACKED)) {
2019
0
            flower->key.ct_state |= TCA_FLOWER_KEY_CT_FLAGS_TRACKED;
2020
0
            flower->mask.ct_state |= TCA_FLOWER_KEY_CT_FLAGS_TRACKED;
2021
0
        }
2022
0
    }
2023
2024
0
    if (mask->ct_zone) {
2025
0
        flower->key.ct_zone = key->ct_zone;
2026
0
        flower->mask.ct_zone = mask->ct_zone;
2027
0
        mask->ct_zone = 0;
2028
0
    }
2029
2030
0
    if (mask->ct_mark) {
2031
0
        flower->key.ct_mark = key->ct_mark;
2032
0
        flower->mask.ct_mark = mask->ct_mark;
2033
0
        mask->ct_mark = 0;
2034
0
    }
2035
2036
0
    if (!ovs_u128_is_zero(mask->ct_label)) {
2037
0
        flower->key.ct_label = key->ct_label;
2038
0
        flower->mask.ct_label = mask->ct_label;
2039
0
        mask->ct_label = OVS_U128_ZERO;
2040
0
    }
2041
0
}
2042
2043
2044
static int
2045
parse_check_pkt_len_action(struct netdev *netdev, struct tc_flower *flower,
2046
                           struct offload_info *info, struct tc_action *action,
2047
                           const struct nlattr *nla, bool last_action,
2048
                           struct tc_action **need_jump_update,
2049
                           bool *recirc_act)
2050
0
{
2051
0
    struct tc_action *ge_jump_update = NULL, *le_jump_update = NULL;
2052
0
    const struct nlattr *nl_actions;
2053
0
    int err, le_offset, gt_offset;
2054
0
    uint16_t pkt_len;
2055
2056
0
    static const struct nl_policy ovs_cpl_policy[] = {
2057
0
        [OVS_CHECK_PKT_LEN_ATTR_PKT_LEN] = { .type = NL_A_U16 },
2058
0
        [OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_GREATER] = { .type = NL_A_NESTED },
2059
0
        [OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_LESS_EQUAL]
2060
0
            = { .type = NL_A_NESTED },
2061
0
    };
2062
0
    struct nlattr *a[ARRAY_SIZE(ovs_cpl_policy)];
2063
2064
0
    if (!nl_parse_nested(nla, ovs_cpl_policy, a, ARRAY_SIZE(a))) {
2065
0
        VLOG_INFO("Received invalid formatted OVS_ACTION_ATTR_CHECK_PKT_LEN!");
2066
0
        return EOPNOTSUPP;
2067
0
    }
2068
2069
0
    if (!a[OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_GREATER] ||
2070
0
        !a[OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_LESS_EQUAL]) {
2071
0
        VLOG_INFO("Received invalid OVS_CHECK_PKT_LEN_ATTR_ACTION_IF_*!");
2072
0
        return EOPNOTSUPP;
2073
0
    }
2074
2075
0
    pkt_len = nl_attr_get_u16(a[OVS_CHECK_PKT_LEN_ATTR_PKT_LEN]);
2076
2077
    /* Add the police mtu action first in the allocated slot. */
2078
0
    action->police.mtu = pkt_len;
2079
0
    action->type = TC_ACT_POLICE_MTU;
2080
0
    le_offset = flower->action_count++;
2081
2082
    /* Parse and add the greater than action(s).
2083
     * NOTE: The last_action parameter means that there are no more actions
2084
     *       after the if () then ... else () case. */
2085
0
    nl_actions = a[OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_GREATER];
2086
0
    err = netdev_tc_parse_nl_actions(netdev, flower, info,
2087
0
                                     nl_attr_get(nl_actions),
2088
0
                                     nl_attr_get_size(nl_actions),
2089
0
                                     recirc_act, !last_action,
2090
0
                                     &ge_jump_update);
2091
0
    if (err) {
2092
0
        return err;
2093
0
    }
2094
2095
    /* Update goto offset for le actions. */
2096
0
    flower->actions[le_offset].police.result_jump = flower->action_count;
2097
2098
0
    gt_offset = flower->action_count;
2099
2100
    /* Parse and add the less than action(s). */
2101
0
    nl_actions = a[OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_LESS_EQUAL];
2102
0
    err = netdev_tc_parse_nl_actions(netdev, flower, info,
2103
0
                                     nl_attr_get(nl_actions),
2104
0
                                     nl_attr_get_size(nl_actions),
2105
0
                                     recirc_act, !last_action,
2106
0
                                     &le_jump_update);
2107
2108
0
    if (gt_offset == flower->action_count && last_action) {
2109
        /* No le actions where added, fix gt offset. */
2110
0
        flower->actions[le_offset].police.result_jump = JUMP_ACTION_STOP;
2111
0
    }
2112
2113
    /* Update goto offset for gt actions to skip the le ones. */
2114
0
    if (last_action) {
2115
0
        flower->actions[gt_offset - 1].jump_action = JUMP_ACTION_STOP;
2116
2117
0
        if (need_jump_update) {
2118
0
            *need_jump_update = NULL;
2119
0
        }
2120
0
    } else {
2121
0
        if (gt_offset == flower->action_count) {
2122
0
            flower->actions[gt_offset - 1].jump_action = 0;
2123
0
        } else {
2124
0
            flower->actions[gt_offset - 1].jump_action = flower->action_count;
2125
0
        }
2126
        /* If we have nested if() else () the if actions jump over the else
2127
         * and will end-up in the outer else () case, which it should have
2128
         * skipped. To void this we return the "potential" inner if() goto to
2129
         * need_jump_update, so it can be updated on return!
2130
         */
2131
0
        if (need_jump_update) {
2132
0
            *need_jump_update = &flower->actions[gt_offset - 1];
2133
0
        }
2134
0
    }
2135
2136
0
    if (le_jump_update != NULL) {
2137
0
        le_jump_update->jump_action =
2138
0
            flower->actions[gt_offset - 1].jump_action;
2139
0
    }
2140
0
    if (ge_jump_update != NULL) {
2141
0
        ge_jump_update->jump_action =
2142
0
            flower->actions[gt_offset - 1].jump_action;
2143
0
    }
2144
2145
0
    if (err) {
2146
0
        return err;
2147
0
    }
2148
2149
0
    return 0;
2150
0
}
2151
2152
static int
2153
netdev_tc_parse_nl_actions(struct netdev *netdev, struct tc_flower *flower,
2154
                           struct offload_info *info,
2155
                           const struct nlattr *actions, size_t actions_len,
2156
                           bool *recirc_act, bool more_actions,
2157
                           struct tc_action **need_jump_update)
2158
0
{
2159
0
    static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 20);
2160
0
    const struct nlattr *nla;
2161
0
    size_t left;
2162
2163
0
    NL_ATTR_FOR_EACH (nla, left, actions, actions_len) {
2164
0
        struct tc_action *action;
2165
0
        int err;
2166
2167
0
        if (flower->action_count >= TCA_ACT_MAX_NUM) {
2168
0
            VLOG_DBG_RL(&rl, "Can only support %d actions", TCA_ACT_MAX_NUM);
2169
0
            return EOPNOTSUPP;
2170
0
        }
2171
2172
0
        action = &flower->actions[flower->action_count];
2173
2174
0
        if (nl_attr_type(nla) == OVS_ACTION_ATTR_OUTPUT) {
2175
0
            odp_port_t port = nl_attr_get_odp_port(nla);
2176
0
            struct netdev *outdev = netdev_ports_get(
2177
0
                                        port, netdev_get_dpif_type(netdev));
2178
2179
0
            if (!outdev) {
2180
0
                VLOG_DBG_RL(&rl, "Can't find netdev for output port %d", port);
2181
0
                return ENODEV;
2182
0
            }
2183
2184
0
            if (!netdev_flow_api_equals(netdev, outdev)) {
2185
0
                VLOG_DBG_RL(&rl,
2186
0
                            "Flow API provider mismatch between ingress (%s) "
2187
0
                            "and egress (%s) ports",
2188
0
                            netdev_get_name(netdev), netdev_get_name(outdev));
2189
0
                netdev_close(outdev);
2190
0
                return EOPNOTSUPP;
2191
0
            }
2192
2193
0
            action->out.ifindex_out = netdev_get_ifindex(outdev);
2194
0
            if (action->out.ifindex_out < 0) {
2195
0
                VLOG_DBG_RL(&rl,
2196
0
                            "Can't find ifindex for output port %s, error %d",
2197
0
                            netdev_get_name(outdev), action->out.ifindex_out);
2198
0
                netdev_close(outdev);
2199
0
                return -action->out.ifindex_out;
2200
0
            }
2201
2202
0
            action->out.ingress = is_internal_port(netdev_get_type(outdev));
2203
0
            action->type = TC_ACT_OUTPUT;
2204
0
            flower->action_count++;
2205
0
            netdev_close(outdev);
2206
0
        } else if (nl_attr_type(nla) == OVS_ACTION_ATTR_PUSH_VLAN) {
2207
0
            const struct ovs_action_push_vlan *vlan_push = nl_attr_get(nla);
2208
2209
0
            action->vlan.vlan_push_tpid = vlan_push->vlan_tpid;
2210
0
            action->vlan.vlan_push_id = vlan_tci_to_vid(vlan_push->vlan_tci);
2211
0
            action->vlan.vlan_push_prio = vlan_tci_to_pcp(vlan_push->vlan_tci);
2212
0
            action->type = TC_ACT_VLAN_PUSH;
2213
0
            flower->action_count++;
2214
0
        } else if (nl_attr_type(nla) == OVS_ACTION_ATTR_POP_VLAN) {
2215
0
            action->type = TC_ACT_VLAN_POP;
2216
0
            flower->action_count++;
2217
0
        } else if (nl_attr_type(nla) == OVS_ACTION_ATTR_PUSH_MPLS) {
2218
0
            const struct ovs_action_push_mpls *mpls_push = nl_attr_get(nla);
2219
2220
0
            action->mpls.proto = mpls_push->mpls_ethertype;
2221
0
            action->mpls.label = mpls_lse_to_label(mpls_push->mpls_lse);
2222
0
            action->mpls.tc = mpls_lse_to_tc(mpls_push->mpls_lse);
2223
0
            action->mpls.ttl = mpls_lse_to_ttl(mpls_push->mpls_lse);
2224
0
            action->mpls.bos = mpls_lse_to_bos(mpls_push->mpls_lse);
2225
0
            action->type = TC_ACT_MPLS_PUSH;
2226
0
            flower->action_count++;
2227
0
        } else if (nl_attr_type(nla) == OVS_ACTION_ATTR_POP_MPLS) {
2228
0
            action->mpls.proto = nl_attr_get_be16(nla);
2229
0
            action->type = TC_ACT_MPLS_POP;
2230
0
            flower->action_count++;
2231
0
        } else if (nl_attr_type(nla) == OVS_ACTION_ATTR_SET) {
2232
0
            const struct nlattr *set = nl_attr_get(nla);
2233
0
            const size_t set_len = nl_attr_get_size(nla);
2234
2235
0
            err = parse_put_flow_set_action(flower, action, set, set_len);
2236
0
            if (err) {
2237
0
                return err;
2238
0
            }
2239
0
        } else if (nl_attr_type(nla) == OVS_ACTION_ATTR_SET_MASKED) {
2240
0
            const struct nlattr *set = nl_attr_get(nla);
2241
0
            const size_t set_len = nl_attr_get_size(nla);
2242
2243
0
            err = parse_put_flow_set_masked_action(flower, action, set,
2244
0
                                                   set_len, true);
2245
0
            if (err) {
2246
0
                return err;
2247
0
            }
2248
0
        } else if (nl_attr_type(nla) == OVS_ACTION_ATTR_CT) {
2249
0
            const struct nlattr *ct = nl_attr_get(nla);
2250
0
            const size_t ct_len = nl_attr_get_size(nla);
2251
2252
0
            if (!ct_state_support) {
2253
0
                return -EOPNOTSUPP;
2254
0
            }
2255
2256
0
            err = parse_put_flow_ct_action(flower, action, ct, ct_len);
2257
0
            if (err) {
2258
0
                return err;
2259
0
            }
2260
0
        } else if (nl_attr_type(nla) == OVS_ACTION_ATTR_CT_CLEAR) {
2261
0
            action->type = TC_ACT_CT;
2262
0
            action->ct.clear = true;
2263
0
            flower->action_count++;
2264
0
        } else if (nl_attr_type(nla) == OVS_ACTION_ATTR_RECIRC) {
2265
0
            action->type = TC_ACT_GOTO;
2266
0
            action->chain = nl_attr_get_u32(nla);
2267
0
            flower->action_count++;
2268
0
            *recirc_act = true;
2269
0
        } else if (nl_attr_type(nla) == OVS_ACTION_ATTR_DROP) {
2270
0
            action->type = TC_ACT_GOTO;
2271
0
            action->chain = 0;  /* 0 is reserved and not used by recirc. */
2272
0
            flower->action_count++;
2273
0
        } else if (nl_attr_type(nla) == OVS_ACTION_ATTR_METER) {
2274
0
            uint32_t police_index, meter_id;
2275
2276
0
            meter_id = nl_attr_get_u32(nla);
2277
0
            if (meter_id_lookup(meter_id, &police_index)) {
2278
0
                return EOPNOTSUPP;
2279
0
            }
2280
0
            action->type = TC_ACT_POLICE;
2281
0
            action->police.index = police_index;
2282
0
            flower->action_count++;
2283
0
        } else if (nl_attr_type(nla) == OVS_ACTION_ATTR_CHECK_PKT_LEN) {
2284
0
            err = parse_check_pkt_len_action(netdev, flower, info, action, nla,
2285
0
                                             nl_attr_len_pad(nla,
2286
0
                                                             left) >= left
2287
0
                                             && !more_actions,
2288
0
                                             need_jump_update,
2289
0
                                             recirc_act);
2290
0
            if (err) {
2291
0
                return err;
2292
0
            }
2293
0
        } else {
2294
0
            VLOG_DBG_RL(&rl, "unsupported put action type: %d",
2295
0
                        nl_attr_type(nla));
2296
0
            return EOPNOTSUPP;
2297
0
        }
2298
0
    }
2299
0
    return 0;
2300
0
}
2301
2302
static int
2303
netdev_tc_flow_put(struct netdev *netdev, struct match *match,
2304
                   struct nlattr *actions, size_t actions_len,
2305
                   const ovs_u128 *ufid, struct offload_info *info,
2306
                   struct dpif_flow_stats *stats)
2307
0
{
2308
0
    static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 20);
2309
0
    enum tc_qdisc_hook hook = get_tc_qdisc_hook(netdev);
2310
0
    struct tc_flower flower;
2311
0
    const struct flow *key = &match->flow;
2312
0
    struct flow *mask = &match->wc.masks;
2313
0
    const struct flow_tnl *tnl = &match->flow.tunnel;
2314
0
    struct flow_tnl *tnl_mask = &mask->tunnel;
2315
0
    struct dpif_flow_stats adjust_stats;
2316
0
    bool exact_match_on_dl_type;
2317
0
    bool recirc_act = false;
2318
0
    uint32_t block_id = 0;
2319
0
    struct tcf_id id;
2320
0
    uint32_t chain;
2321
0
    int prio = 0;
2322
0
    int ifindex;
2323
0
    int err;
2324
2325
0
    ifindex = netdev_get_ifindex(netdev);
2326
0
    if (ifindex < 0) {
2327
0
        VLOG_ERR_RL(&error_rl, "flow_put: failed to get ifindex for %s: %s",
2328
0
                    netdev_get_name(netdev), ovs_strerror(-ifindex));
2329
0
        return -ifindex;
2330
0
    }
2331
2332
0
    memset(&flower, 0, sizeof flower);
2333
2334
0
    exact_match_on_dl_type = mask->dl_type == htons(0xffff);
2335
0
    chain = key->recirc_id;
2336
0
    mask->recirc_id = 0;
2337
2338
0
    if (chain) {
2339
        /* If we match on a recirculation ID, we must ensure the previous
2340
         * flow is also in the TC datapath; otherwise, the entry is useless,
2341
         * as the related packets will be handled by upcalls. */
2342
0
        if (!ccmap_find(&used_chains, chain)) {
2343
0
            VLOG_DBG_RL(&rl, "match for chain %u failed due to non-existing "
2344
0
                        "goto chain action", chain);
2345
0
            return EOPNOTSUPP;
2346
0
        }
2347
0
    }
2348
2349
0
    if (flow_tnl_dst_is_set(&key->tunnel) ||
2350
0
        flow_tnl_src_is_set(&key->tunnel)) {
2351
0
        VLOG_DBG_RL(&rl,
2352
0
                    "tunnel: id %#" PRIx64 " src " IP_FMT
2353
0
                    " dst " IP_FMT " tp_src %d tp_dst %d",
2354
0
                    ntohll(tnl->tun_id),
2355
0
                    IP_ARGS(tnl->ip_src), IP_ARGS(tnl->ip_dst),
2356
0
                    ntohs(tnl->tp_src), ntohs(tnl->tp_dst));
2357
0
        flower.key.tunnel.id = tnl->tun_id;
2358
0
        flower.key.tunnel.ipv4.ipv4_src = tnl->ip_src;
2359
0
        flower.key.tunnel.ipv4.ipv4_dst = tnl->ip_dst;
2360
0
        flower.key.tunnel.ipv6.ipv6_src = tnl->ipv6_src;
2361
0
        flower.key.tunnel.ipv6.ipv6_dst = tnl->ipv6_dst;
2362
0
        flower.key.tunnel.tos = tnl->ip_tos;
2363
0
        flower.key.tunnel.ttl = tnl->ip_ttl;
2364
0
        flower.key.tunnel.tp_src = tnl->tp_src;
2365
0
        flower.key.tunnel.tp_dst = tnl->tp_dst;
2366
0
        flower.key.tunnel.gbp.id = tnl->gbp_id;
2367
0
        flower.key.tunnel.gbp.flags = tnl->gbp_flags;
2368
0
        flower.key.tunnel.gbp.id_present = !!tnl_mask->gbp_id;
2369
2370
0
        flower.mask.tunnel.ipv4.ipv4_src = tnl_mask->ip_src;
2371
0
        flower.mask.tunnel.ipv4.ipv4_dst = tnl_mask->ip_dst;
2372
0
        flower.mask.tunnel.ipv6.ipv6_src = tnl_mask->ipv6_src;
2373
0
        flower.mask.tunnel.ipv6.ipv6_dst = tnl_mask->ipv6_dst;
2374
0
        flower.mask.tunnel.tos = tnl_mask->ip_tos;
2375
0
        flower.mask.tunnel.ttl = tnl_mask->ip_ttl;
2376
0
        flower.mask.tunnel.tp_src = tnl_mask->tp_src;
2377
        /* XXX: We should be setting the mask from 'tnl_mask->tp_dst' here, but
2378
         * some hardware drivers (mlx5) doesn't support masked matches and will
2379
         * refuse to offload such flows keeping them in software path.
2380
         * Degrading the flow down to exact match for now as a workaround. */
2381
0
        flower.mask.tunnel.tp_dst = OVS_BE16_MAX;
2382
0
        flower.mask.tunnel.id = (tnl->flags & FLOW_TNL_F_KEY) ? tnl_mask->tun_id : 0;
2383
0
        flower.mask.tunnel.gbp.id = tnl_mask->gbp_id;
2384
0
        flower.mask.tunnel.gbp.flags = tnl_mask->gbp_flags;
2385
0
        flower.mask.tunnel.gbp.id_present = !!tnl_mask->gbp_id;
2386
2387
0
        memset(&tnl_mask->ip_src, 0, sizeof tnl_mask->ip_src);
2388
0
        memset(&tnl_mask->ip_dst, 0, sizeof tnl_mask->ip_dst);
2389
0
        memset(&tnl_mask->ipv6_src, 0, sizeof tnl_mask->ipv6_src);
2390
0
        memset(&tnl_mask->ipv6_dst, 0, sizeof tnl_mask->ipv6_dst);
2391
0
        memset(&tnl_mask->ip_tos, 0, sizeof tnl_mask->ip_tos);
2392
0
        memset(&tnl_mask->ip_ttl, 0, sizeof tnl_mask->ip_ttl);
2393
0
        memset(&tnl_mask->tp_src, 0, sizeof tnl_mask->tp_src);
2394
0
        memset(&tnl_mask->tp_dst, 0, sizeof tnl_mask->tp_dst);
2395
2396
0
        memset(&tnl_mask->tun_id, 0, sizeof tnl_mask->tun_id);
2397
0
        memset(&tnl_mask->gbp_id, 0, sizeof tnl_mask->gbp_id);
2398
0
        memset(&tnl_mask->gbp_flags, 0, sizeof tnl_mask->gbp_flags);
2399
0
        tnl_mask->flags &= ~FLOW_TNL_F_KEY;
2400
2401
0
        if (enc_flags_support) {
2402
0
            if (tnl_mask->flags & FLOW_TNL_F_OAM) {
2403
0
                if (tnl->flags & FLOW_TNL_F_OAM) {
2404
0
                    flower.key.tunnel.tc_enc_flags |=
2405
0
                        TCA_FLOWER_KEY_FLAGS_TUNNEL_OAM;
2406
0
                }
2407
0
                flower.mask.tunnel.tc_enc_flags |=
2408
0
                    TCA_FLOWER_KEY_FLAGS_TUNNEL_OAM;
2409
0
                tnl_mask->flags &= ~FLOW_TNL_F_OAM;
2410
0
            }
2411
0
            if (tnl_mask->flags & FLOW_TNL_F_DONT_FRAGMENT) {
2412
0
                if (tnl->flags & FLOW_TNL_F_DONT_FRAGMENT) {
2413
0
                    flower.key.tunnel.tc_enc_flags |=
2414
0
                        TCA_FLOWER_KEY_FLAGS_TUNNEL_DONT_FRAGMENT;
2415
0
                }
2416
0
                flower.mask.tunnel.tc_enc_flags |=
2417
0
                    TCA_FLOWER_KEY_FLAGS_TUNNEL_DONT_FRAGMENT;
2418
0
                tnl_mask->flags &= ~FLOW_TNL_F_DONT_FRAGMENT;
2419
0
            }
2420
0
            if (tnl_mask->flags & FLOW_TNL_F_CSUM) {
2421
0
                if (tnl->flags & FLOW_TNL_F_CSUM) {
2422
0
                    flower.key.tunnel.tc_enc_flags |=
2423
0
                        TCA_FLOWER_KEY_FLAGS_TUNNEL_CSUM;
2424
0
                }
2425
0
                flower.mask.tunnel.tc_enc_flags |=
2426
0
                    TCA_FLOWER_KEY_FLAGS_TUNNEL_CSUM;
2427
0
                tnl_mask->flags &= ~FLOW_TNL_F_CSUM;
2428
0
            }
2429
0
        } else {
2430
            /* For kernels not supporting the encapsulation flags we're
2431
             * ignoring DF and CSUM flags configuration requested by the user.
2432
             * This to keep the old, incorrect behaviour, and allow tunnels to
2433
             * be offloaded by TC with these kernels. */
2434
0
            tnl_mask->flags &= ~(FLOW_TNL_F_DONT_FRAGMENT | FLOW_TNL_F_CSUM);
2435
0
        }
2436
2437
0
        if (!strcmp(netdev_get_type(netdev), "geneve")) {
2438
0
            err = flower_match_to_tun_opt(&flower, tnl, tnl_mask);
2439
0
            if (err) {
2440
0
                VLOG_WARN_RL(&warn_rl, "Unable to parse geneve options");
2441
0
                return err;
2442
0
            }
2443
0
        }
2444
0
        flower.tunnel = true;
2445
0
    } else {
2446
        /* There is no tunnel metadata to match on, but there could be some
2447
         * mask bits set due to flow translation artifacts.  Clear them. */
2448
0
        memset(&mask->tunnel, 0, sizeof mask->tunnel);
2449
0
    }
2450
2451
0
    flower.key.eth_type = key->dl_type;
2452
0
    flower.mask.eth_type = mask->dl_type;
2453
0
    if (mask->mpls_lse[0]) {
2454
0
        flower.key.mpls_lse = key->mpls_lse[0];
2455
0
        flower.mask.mpls_lse = mask->mpls_lse[0];
2456
0
        flower.key.encap_eth_type[0] = flower.key.eth_type;
2457
0
    }
2458
0
    mask->mpls_lse[0] = 0;
2459
2460
0
    if (mask->vlans[0].tpid && eth_type_vlan(key->vlans[0].tpid)) {
2461
0
        flower.key.encap_eth_type[0] = flower.key.eth_type;
2462
0
        flower.mask.encap_eth_type[0] = CONSTANT_HTONS(0xffff);
2463
0
        flower.key.eth_type = key->vlans[0].tpid;
2464
0
        flower.mask.eth_type = mask->vlans[0].tpid;
2465
0
    }
2466
0
    if (mask->vlans[0].tci) {
2467
0
        ovs_be16 vid_mask = mask->vlans[0].tci & htons(VLAN_VID_MASK);
2468
0
        ovs_be16 pcp_mask = mask->vlans[0].tci & htons(VLAN_PCP_MASK);
2469
0
        ovs_be16 cfi = mask->vlans[0].tci & htons(VLAN_CFI);
2470
2471
0
        if (cfi && key->vlans[0].tci & htons(VLAN_CFI)
2472
0
            && (!vid_mask || vid_mask == htons(VLAN_VID_MASK))
2473
0
            && (!pcp_mask || pcp_mask == htons(VLAN_PCP_MASK))
2474
0
            && (vid_mask || pcp_mask)) {
2475
0
            if (vid_mask) {
2476
0
                flower.key.vlan_id[0] = vlan_tci_to_vid(key->vlans[0].tci);
2477
0
                flower.mask.vlan_id[0] = vlan_tci_to_vid(mask->vlans[0].tci);
2478
0
                VLOG_DBG_RL(&rl, "vlan_id[0]: %d\n", flower.key.vlan_id[0]);
2479
0
            }
2480
0
            if (pcp_mask) {
2481
0
                flower.key.vlan_prio[0] = vlan_tci_to_pcp(key->vlans[0].tci);
2482
0
                flower.mask.vlan_prio[0] = vlan_tci_to_pcp(mask->vlans[0].tci);
2483
0
                VLOG_DBG_RL(&rl, "vlan_prio[0]: %d\n",
2484
0
                            flower.key.vlan_prio[0]);
2485
0
            }
2486
0
        } else if (mask->vlans[0].tci == htons(0xffff) &&
2487
0
                   ntohs(key->vlans[0].tci) == 0) {
2488
            /* exact && no vlan */
2489
0
        } else {
2490
            /* partial mask */
2491
0
            return EOPNOTSUPP;
2492
0
        }
2493
0
    }
2494
2495
0
    if (mask->vlans[1].tpid && eth_type_vlan(key->vlans[1].tpid)) {
2496
0
        flower.key.encap_eth_type[1] = flower.key.encap_eth_type[0];
2497
0
        flower.mask.encap_eth_type[1] = flower.mask.encap_eth_type[0];
2498
0
        flower.key.encap_eth_type[0] = key->vlans[1].tpid;
2499
0
        flower.mask.encap_eth_type[0] = mask->vlans[1].tpid;
2500
0
    }
2501
0
    if (mask->vlans[1].tci) {
2502
0
        ovs_be16 vid_mask = mask->vlans[1].tci & htons(VLAN_VID_MASK);
2503
0
        ovs_be16 pcp_mask = mask->vlans[1].tci & htons(VLAN_PCP_MASK);
2504
0
        ovs_be16 cfi = mask->vlans[1].tci & htons(VLAN_CFI);
2505
2506
0
        if (cfi && key->vlans[1].tci & htons(VLAN_CFI)
2507
0
            && (!vid_mask || vid_mask == htons(VLAN_VID_MASK))
2508
0
            && (!pcp_mask || pcp_mask == htons(VLAN_PCP_MASK))
2509
0
            && (vid_mask || pcp_mask)) {
2510
0
            if (vid_mask) {
2511
0
                flower.key.vlan_id[1] = vlan_tci_to_vid(key->vlans[1].tci);
2512
0
                flower.mask.vlan_id[1] = vlan_tci_to_vid(mask->vlans[1].tci);
2513
0
                VLOG_DBG_RL(&rl, "vlan_id[1]: %d", flower.key.vlan_id[1]);
2514
0
            }
2515
0
            if (pcp_mask) {
2516
0
                flower.key.vlan_prio[1] = vlan_tci_to_pcp(key->vlans[1].tci);
2517
0
                flower.mask.vlan_prio[1] = vlan_tci_to_pcp(mask->vlans[1].tci);
2518
0
                VLOG_DBG_RL(&rl, "vlan_prio[1]: %d", flower.key.vlan_prio[1]);
2519
0
            }
2520
0
        } else if (mask->vlans[1].tci == htons(0xffff) &&
2521
0
                   ntohs(key->vlans[1].tci) == 0) {
2522
            /* exact && no vlan */
2523
0
        } else {
2524
            /* partial mask */
2525
0
            return EOPNOTSUPP;
2526
0
        }
2527
0
    }
2528
0
    memset(mask->vlans, 0, sizeof mask->vlans);
2529
2530
0
    flower.key.dst_mac = key->dl_dst;
2531
0
    flower.mask.dst_mac = mask->dl_dst;
2532
0
    flower.key.src_mac = key->dl_src;
2533
0
    flower.mask.src_mac = mask->dl_src;
2534
0
    memset(&mask->dl_dst, 0, sizeof mask->dl_dst);
2535
0
    memset(&mask->dl_src, 0, sizeof mask->dl_src);
2536
0
    mask->dl_type = 0;
2537
0
    mask->in_port.odp_port = 0;
2538
2539
0
    if (exact_match_on_dl_type && key->dl_type == htons(ETH_P_ARP)) {
2540
0
            flower.key.arp.spa = key->nw_src;
2541
0
            flower.key.arp.tpa = key->nw_dst;
2542
0
            flower.key.arp.sha = key->arp_sha;
2543
0
            flower.key.arp.tha = key->arp_tha;
2544
0
            flower.key.arp.opcode = key->nw_proto;
2545
0
            flower.mask.arp.spa = mask->nw_src;
2546
0
            flower.mask.arp.tpa = mask->nw_dst;
2547
0
            flower.mask.arp.sha = mask->arp_sha;
2548
0
            flower.mask.arp.tha = mask->arp_tha;
2549
0
            flower.mask.arp.opcode = mask->nw_proto;
2550
2551
0
            mask->nw_src = 0;
2552
0
            mask->nw_dst = 0;
2553
0
            mask->nw_proto = 0;
2554
0
            memset(&mask->arp_sha, 0, sizeof mask->arp_sha);
2555
0
            memset(&mask->arp_tha, 0, sizeof mask->arp_tha);
2556
0
    }
2557
2558
0
    if (exact_match_on_dl_type && is_ip_any(key)
2559
0
        && !is_ipv6_fragment_and_masked(key, mask)) {
2560
0
        flower.key.ip_proto = key->nw_proto;
2561
0
        flower.mask.ip_proto = mask->nw_proto;
2562
0
        mask->nw_proto = 0;
2563
0
        flower.key.ip_tos = key->nw_tos;
2564
0
        flower.mask.ip_tos = mask->nw_tos;
2565
0
        mask->nw_tos = 0;
2566
0
        flower.key.ip_ttl = key->nw_ttl;
2567
0
        flower.mask.ip_ttl = mask->nw_ttl;
2568
0
        mask->nw_ttl = 0;
2569
2570
0
        if (mask->nw_frag & FLOW_NW_FRAG_ANY) {
2571
0
            flower.mask.flags |= TCA_FLOWER_KEY_FLAGS_IS_FRAGMENT;
2572
2573
0
            if (key->nw_frag & FLOW_NW_FRAG_ANY) {
2574
0
                flower.key.flags |= TCA_FLOWER_KEY_FLAGS_IS_FRAGMENT;
2575
2576
0
                if (mask->nw_frag & FLOW_NW_FRAG_LATER) {
2577
0
                    flower.mask.flags |= TCA_FLOWER_KEY_FLAGS_FRAG_IS_FIRST;
2578
2579
0
                    if (!(key->nw_frag & FLOW_NW_FRAG_LATER)) {
2580
0
                        flower.key.flags |= TCA_FLOWER_KEY_FLAGS_FRAG_IS_FIRST;
2581
0
                    }
2582
0
                }
2583
0
            }
2584
2585
0
            mask->nw_frag = 0;
2586
0
        } else {
2587
            /* This scenario should not occur.  Currently, all installed IP DP
2588
             * flows perform a fully masked match on the fragmentation bits.
2589
             * However, since TC depends on this behavior, we return EOPNOTSUPP
2590
             * for now in case this behavior changes in the future. */
2591
0
            return EOPNOTSUPP;
2592
0
        }
2593
2594
0
        if (key->nw_proto == IPPROTO_TCP) {
2595
0
            flower.key.tcp_dst = key->tp_dst;
2596
0
            flower.mask.tcp_dst = mask->tp_dst;
2597
0
            flower.key.tcp_src = key->tp_src;
2598
0
            flower.mask.tcp_src = mask->tp_src;
2599
0
            flower.key.tcp_flags = key->tcp_flags;
2600
0
            flower.mask.tcp_flags = mask->tcp_flags;
2601
0
            mask->tp_src = 0;
2602
0
            mask->tp_dst = 0;
2603
0
            mask->tcp_flags = 0;
2604
0
        } else if (key->nw_proto == IPPROTO_UDP) {
2605
0
            flower.key.udp_dst = key->tp_dst;
2606
0
            flower.mask.udp_dst = mask->tp_dst;
2607
0
            flower.key.udp_src = key->tp_src;
2608
0
            flower.mask.udp_src = mask->tp_src;
2609
0
            mask->tp_src = 0;
2610
0
            mask->tp_dst = 0;
2611
0
        } else if (key->nw_proto == IPPROTO_SCTP) {
2612
0
            flower.key.sctp_dst = key->tp_dst;
2613
0
            flower.mask.sctp_dst = mask->tp_dst;
2614
0
            flower.key.sctp_src = key->tp_src;
2615
0
            flower.mask.sctp_src = mask->tp_src;
2616
0
            mask->tp_src = 0;
2617
0
            mask->tp_dst = 0;
2618
0
        } else if (key->nw_proto == IPPROTO_ICMP ||
2619
0
                   key->nw_proto == IPPROTO_ICMPV6) {
2620
0
            flower.key.icmp_code = (uint8_t) ntohs(key->tp_dst);
2621
0
            flower.mask.icmp_code = (uint8_t) ntohs (mask->tp_dst);
2622
0
            flower.key.icmp_type = (uint8_t) ntohs(key->tp_src);
2623
0
            flower.mask.icmp_type = (uint8_t) ntohs(mask->tp_src);
2624
0
            mask->tp_src = 0;
2625
0
            mask->tp_dst = 0;
2626
0
        }
2627
2628
0
        if (key->dl_type == htons(ETH_P_IP)) {
2629
0
            flower.key.ipv4.ipv4_src = key->nw_src;
2630
0
            flower.mask.ipv4.ipv4_src = mask->nw_src;
2631
0
            flower.key.ipv4.ipv4_dst = key->nw_dst;
2632
0
            flower.mask.ipv4.ipv4_dst = mask->nw_dst;
2633
0
            mask->nw_src = 0;
2634
0
            mask->nw_dst = 0;
2635
0
        } else if (key->dl_type == htons(ETH_P_IPV6)) {
2636
0
            flower.key.ipv6.ipv6_src = key->ipv6_src;
2637
0
            flower.mask.ipv6.ipv6_src = mask->ipv6_src;
2638
0
            flower.key.ipv6.ipv6_dst = key->ipv6_dst;
2639
0
            flower.mask.ipv6.ipv6_dst = mask->ipv6_dst;
2640
0
            memset(&mask->ipv6_src, 0, sizeof mask->ipv6_src);
2641
0
            memset(&mask->ipv6_dst, 0, sizeof mask->ipv6_dst);
2642
0
        }
2643
0
    }
2644
2645
0
    parse_match_ct_state_to_flower(&flower, match);
2646
2647
    /* ignore exact match on skb_mark of 0. */
2648
0
    if (mask->pkt_mark == UINT32_MAX && !key->pkt_mark) {
2649
0
        mask->pkt_mark = 0;
2650
0
    }
2651
2652
0
    err = test_key_and_mask(match);
2653
0
    if (err) {
2654
0
        return err;
2655
0
    }
2656
2657
    /* Parse all (nested) actions. */
2658
0
    err = netdev_tc_parse_nl_actions(netdev, &flower, info,
2659
0
                                     actions, actions_len, &recirc_act,
2660
0
                                     false, NULL);
2661
0
    if (err) {
2662
0
        return err;
2663
0
    }
2664
2665
0
    if ((chain || recirc_act) && !info->recirc_id_shared_with_tc) {
2666
0
        VLOG_DBG_RL(&rl, "flow_put: recirc_id sharing not supported");
2667
0
        return EOPNOTSUPP;
2668
0
    }
2669
2670
0
    memset(&adjust_stats, 0, sizeof adjust_stats);
2671
0
    if (get_ufid_tc_mapping(ufid, &id) == 0) {
2672
0
        VLOG_DBG_RL(&rl, "updating old handle: %d prio: %d",
2673
0
                    id.handle, id.prio);
2674
0
        info->tc_modify_flow_deleted = !del_filter_and_ufid_mapping(
2675
0
            &id, ufid, &adjust_stats);
2676
0
    }
2677
2678
0
    prio = get_prio_for_tc_flower(&flower);
2679
0
    if (prio == 0) {
2680
0
        VLOG_ERR_RL(&rl, "couldn't get tc prio: %s", ovs_strerror(ENOSPC));
2681
0
        return ENOSPC;
2682
0
    }
2683
2684
0
    flower.act_cookie.data = ufid;
2685
0
    flower.act_cookie.len = sizeof *ufid;
2686
2687
0
    block_id = get_block_id_from_netdev(netdev);
2688
0
    id = tc_make_tcf_id_chain(ifindex, block_id, chain, prio, hook);
2689
0
    err = tc_replace_flower(&id, &flower);
2690
0
    if (!err) {
2691
0
        uint32_t chain_goto = 0;
2692
2693
0
        if (stats) {
2694
0
            memset(stats, 0, sizeof *stats);
2695
0
            netdev_tc_adjust_stats(stats, &adjust_stats);
2696
0
        }
2697
2698
0
        if (recirc_act) {
2699
0
            struct tc_action *action = flower.actions;
2700
2701
0
            for (int i = 0; i < flower.action_count; i++, action++) {
2702
                /* If action->chain is zero, this is not a true "goto"
2703
                 * (recirculation) action, but rather a drop action.
2704
                 * Since it does not involve recirculation handling,
2705
                 * it should be ignored. */
2706
0
                if (action->type == TC_ACT_GOTO && action->chain) {
2707
0
                    chain_goto = action->chain;
2708
0
                    ovs_mutex_lock(&used_chains_mutex);
2709
0
                    ccmap_inc(&used_chains, chain_goto);
2710
0
                    ovs_mutex_unlock(&used_chains_mutex);
2711
0
                    break;
2712
0
                }
2713
0
            }
2714
0
        }
2715
2716
0
        add_ufid_tc_mapping(netdev, ufid, &id, &adjust_stats, chain_goto);
2717
0
    }
2718
2719
0
    return err;
2720
0
}
2721
2722
static int
2723
netdev_tc_flow_get(struct netdev *netdev,
2724
                   struct match *match,
2725
                   struct nlattr **actions,
2726
                   const ovs_u128 *ufid,
2727
                   struct dpif_flow_stats *stats,
2728
                   struct dpif_flow_attrs *attrs,
2729
                   struct ofpbuf *buf)
2730
0
{
2731
0
    static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 20);
2732
0
    struct tc_flower flower;
2733
0
    odp_port_t in_port;
2734
0
    struct tcf_id id;
2735
0
    int err;
2736
2737
0
    err = get_ufid_tc_mapping(ufid, &id);
2738
0
    if (err) {
2739
0
        return err;
2740
0
    }
2741
2742
0
    VLOG_DBG_RL(&rl, "flow get (dev %s prio %d handle %d block_id %d)",
2743
0
                netdev_get_name(netdev), id.prio, id.handle, id.block_id);
2744
2745
0
    err = tc_get_flower(&id, &flower);
2746
0
    if (err) {
2747
0
        VLOG_ERR_RL(&error_rl,
2748
0
                    "flow get failed (dev %s prio %d handle %d): %s",
2749
0
                    netdev_get_name(netdev), id.prio, id.handle,
2750
0
                    ovs_strerror(err));
2751
0
        return err;
2752
0
    }
2753
2754
0
    in_port = netdev_ifindex_to_odp_port(id.ifindex);
2755
0
    err = parse_tc_flower_to_match(netdev, &flower, match, actions,
2756
0
                                   stats, attrs, buf, false);
2757
0
    if (err) {
2758
0
        VLOG_ERR_RL(&error_rl,
2759
0
                    "flow get parse failed (dev %s prio %d handle %d): %s",
2760
0
                    netdev_get_name(netdev), id.prio, id.handle,
2761
0
                    ovs_strerror(err));
2762
0
        return err;
2763
0
    }
2764
2765
0
    if (stats) {
2766
0
        struct dpif_flow_stats adjust_stats;
2767
2768
0
        if (!get_ufid_adjust_stats(ufid, &adjust_stats)) {
2769
0
            netdev_tc_adjust_stats(stats, &adjust_stats);
2770
0
        }
2771
0
    }
2772
0
    match->wc.masks.in_port.odp_port = u32_to_odp(UINT32_MAX);
2773
0
    match->flow.in_port.odp_port = in_port;
2774
0
    match_set_recirc_id(match, id.chain);
2775
2776
0
    return 0;
2777
0
}
2778
2779
static int
2780
netdev_tc_flow_del(struct netdev *netdev OVS_UNUSED,
2781
                   const ovs_u128 *ufid,
2782
                   struct dpif_flow_stats *stats)
2783
0
{
2784
0
    struct tcf_id id;
2785
0
    int error;
2786
2787
0
    error = get_ufid_tc_mapping(ufid, &id);
2788
0
    if (error) {
2789
0
        return error;
2790
0
    }
2791
2792
0
    return del_filter_and_ufid_mapping(&id, ufid, stats);
2793
0
}
2794
2795
static int
2796
netdev_tc_get_n_flows(struct netdev *netdev, uint64_t *n_flows)
2797
0
{
2798
0
    struct ufid_tc_data *data;
2799
0
    uint64_t total = 0;
2800
2801
0
    ovs_mutex_lock(&ufid_lock);
2802
0
    HMAP_FOR_EACH (data, tc_to_ufid_node, &tc_to_ufid) {
2803
0
        if (data->netdev == netdev) {
2804
0
            total++;
2805
0
        }
2806
0
    }
2807
0
    ovs_mutex_unlock(&ufid_lock);
2808
2809
0
    *n_flows = total;
2810
0
    return 0;
2811
0
}
2812
2813
static void
2814
probe_multi_mask_per_prio(int ifindex)
2815
0
{
2816
0
    struct tc_flower flower;
2817
0
    struct tcf_id id1, id2;
2818
0
    int block_id = 0;
2819
0
    int prio = 1;
2820
0
    int error;
2821
2822
0
    error = tc_add_del_qdisc(ifindex, true, block_id, TC_INGRESS);
2823
0
    if (error) {
2824
0
        return;
2825
0
    }
2826
2827
0
    memset(&flower, 0, sizeof flower);
2828
2829
0
    flower.tc_policy = TC_POLICY_SKIP_HW;
2830
0
    flower.key.eth_type = htons(ETH_P_IP);
2831
0
    flower.mask.eth_type = OVS_BE16_MAX;
2832
0
    memset(&flower.key.dst_mac, 0x11, sizeof flower.key.dst_mac);
2833
0
    memset(&flower.mask.dst_mac, 0xff, sizeof flower.mask.dst_mac);
2834
2835
0
    id1 = tc_make_tcf_id(ifindex, block_id, prio, TC_INGRESS);
2836
0
    error = tc_replace_flower(&id1, &flower);
2837
0
    if (error) {
2838
0
        goto out;
2839
0
    }
2840
2841
0
    memset(&flower.key.src_mac, 0x11, sizeof flower.key.src_mac);
2842
0
    memset(&flower.mask.src_mac, 0xff, sizeof flower.mask.src_mac);
2843
2844
0
    id2 = tc_make_tcf_id(ifindex, block_id, prio, TC_INGRESS);
2845
0
    error = tc_replace_flower(&id2, &flower);
2846
0
    tc_del_flower_filter(&id1);
2847
2848
0
    if (error) {
2849
0
        goto out;
2850
0
    }
2851
2852
0
    tc_del_flower_filter(&id2);
2853
2854
0
    multi_mask_per_prio = true;
2855
0
    VLOG_INFO("probe tc: multiple masks on single tc prio is supported.");
2856
2857
0
out:
2858
0
    tc_add_del_qdisc(ifindex, false, block_id, TC_INGRESS);
2859
0
}
2860
2861
2862
static int
2863
probe_insert_ct_state_rule(int ifindex, uint16_t ct_state, struct tcf_id *id)
2864
0
{
2865
0
    int prio = TC_RESERVED_PRIORITY_MAX + 1;
2866
0
    struct tc_flower flower;
2867
2868
0
    memset(&flower, 0, sizeof flower);
2869
0
    flower.key.ct_state = ct_state;
2870
0
    flower.mask.ct_state = ct_state;
2871
0
    flower.tc_policy = TC_POLICY_SKIP_HW;
2872
0
    flower.key.eth_type = htons(ETH_P_IP);
2873
0
    flower.mask.eth_type = OVS_BE16_MAX;
2874
2875
0
    *id = tc_make_tcf_id(ifindex, 0, prio, TC_INGRESS);
2876
0
    return tc_replace_flower(id, &flower);
2877
0
}
2878
2879
static void
2880
probe_ct_state_support(int ifindex)
2881
0
{
2882
0
    struct tc_flower flower;
2883
0
    uint16_t ct_state;
2884
0
    struct tcf_id id;
2885
0
    int error;
2886
2887
0
    error = tc_add_del_qdisc(ifindex, true, 0, TC_INGRESS);
2888
0
    if (error) {
2889
0
        return;
2890
0
    }
2891
2892
    /* Test for base ct_state match support */
2893
0
    ct_state = TCA_FLOWER_KEY_CT_FLAGS_NEW | TCA_FLOWER_KEY_CT_FLAGS_TRACKED;
2894
0
    error = probe_insert_ct_state_rule(ifindex, ct_state, &id);
2895
0
    if (error) {
2896
0
        goto out;
2897
0
    }
2898
2899
0
    error = tc_get_flower(&id, &flower);
2900
0
    if (error || flower.mask.ct_state != ct_state) {
2901
0
        goto out_del;
2902
0
    }
2903
2904
0
    tc_del_flower_filter(&id);
2905
0
    ct_state_support = OVS_CS_F_NEW |
2906
0
                       OVS_CS_F_ESTABLISHED |
2907
0
                       OVS_CS_F_TRACKED |
2908
0
                       OVS_CS_F_RELATED;
2909
2910
    /* Test for reject, ct_state >= MAX */
2911
0
    ct_state = ~0;
2912
0
    error = probe_insert_ct_state_rule(ifindex, ct_state, &id);
2913
0
    if (!error) {
2914
        /* No reject, can't continue probing other flags */
2915
0
        goto out_del;
2916
0
    }
2917
2918
0
    tc_del_flower_filter(&id);
2919
2920
    /* Test for ct_state INVALID support */
2921
0
    memset(&flower, 0, sizeof flower);
2922
0
    ct_state = TCA_FLOWER_KEY_CT_FLAGS_TRACKED |
2923
0
               TCA_FLOWER_KEY_CT_FLAGS_INVALID;
2924
0
    error = probe_insert_ct_state_rule(ifindex, ct_state, &id);
2925
0
    if (error) {
2926
0
        goto out;
2927
0
    }
2928
2929
0
    tc_del_flower_filter(&id);
2930
0
    ct_state_support |= OVS_CS_F_INVALID;
2931
2932
    /* Test for ct_state REPLY support */
2933
0
    memset(&flower, 0, sizeof flower);
2934
0
    ct_state = TCA_FLOWER_KEY_CT_FLAGS_TRACKED |
2935
0
               TCA_FLOWER_KEY_CT_FLAGS_ESTABLISHED |
2936
0
               TCA_FLOWER_KEY_CT_FLAGS_REPLY;
2937
0
    error = probe_insert_ct_state_rule(ifindex, ct_state, &id);
2938
0
    if (error) {
2939
0
        goto out;
2940
0
    }
2941
2942
0
    ct_state_support |= OVS_CS_F_REPLY_DIR;
2943
2944
0
out_del:
2945
0
    tc_del_flower_filter(&id);
2946
0
out:
2947
0
    tc_add_del_qdisc(ifindex, false, 0, TC_INGRESS);
2948
0
    VLOG_INFO("probe tc: supported ovs ct_state bits: 0x%x", ct_state_support);
2949
0
}
2950
2951
static void
2952
probe_tc_block_support(int ifindex)
2953
0
{
2954
0
    struct tc_flower flower;
2955
0
    uint32_t block_id = 1;
2956
0
    struct tcf_id id;
2957
0
    int prio = 0;
2958
0
    int error;
2959
2960
0
    error = tc_add_del_qdisc(ifindex, true, block_id, TC_INGRESS);
2961
0
    if (error) {
2962
0
        return;
2963
0
    }
2964
2965
0
    memset(&flower, 0, sizeof flower);
2966
2967
0
    flower.tc_policy = TC_POLICY_SKIP_HW;
2968
0
    flower.key.eth_type = htons(ETH_P_IP);
2969
0
    flower.mask.eth_type = OVS_BE16_MAX;
2970
0
    memset(&flower.key.dst_mac, 0x11, sizeof flower.key.dst_mac);
2971
0
    memset(&flower.mask.dst_mac, 0xff, sizeof flower.mask.dst_mac);
2972
2973
0
    id = tc_make_tcf_id(ifindex, block_id, prio, TC_INGRESS);
2974
0
    error = tc_replace_flower(&id, &flower);
2975
2976
0
    tc_add_del_qdisc(ifindex, false, block_id, TC_INGRESS);
2977
2978
0
    if (!error) {
2979
0
        block_support = true;
2980
0
        VLOG_INFO("probe tc: block offload is supported.");
2981
0
    }
2982
0
}
2983
2984
static void
2985
probe_vxlan_gbp_support(int ifindex)
2986
0
{
2987
0
    struct tc_flower flower;
2988
0
    struct tcf_id id;
2989
0
    int block_id = 0;
2990
0
    int prio = 1;
2991
0
    int error;
2992
2993
0
    error = tc_add_del_qdisc(ifindex, true, block_id, TC_INGRESS);
2994
0
    if (error) {
2995
0
        return;
2996
0
    }
2997
2998
0
    memset(&flower, 0, sizeof flower);
2999
3000
0
    flower.tc_policy = TC_POLICY_SKIP_HW;
3001
0
    flower.key.eth_type = htons(ETH_P_IP);
3002
0
    flower.mask.eth_type = OVS_BE16_MAX;
3003
0
    flower.tunnel = true;
3004
0
    flower.mask.tunnel.id = OVS_BE64_MAX;
3005
0
    flower.mask.tunnel.ipv4.ipv4_src = OVS_BE32_MAX;
3006
0
    flower.mask.tunnel.ipv4.ipv4_dst = OVS_BE32_MAX;
3007
0
    flower.mask.tunnel.tp_dst = OVS_BE16_MAX;
3008
0
    flower.mask.tunnel.gbp.id = OVS_BE16_MAX;
3009
0
    flower.key.tunnel.ipv4.ipv4_src = htonl(0x01010101);
3010
0
    flower.key.tunnel.ipv4.ipv4_dst = htonl(0x01010102);
3011
0
    flower.key.tunnel.tp_dst = htons(46354);
3012
0
    flower.key.tunnel.gbp.id = htons(512);
3013
3014
0
    id = tc_make_tcf_id(ifindex, block_id, prio, TC_INGRESS);
3015
0
    error = tc_replace_flower(&id, &flower);
3016
0
    if (error) {
3017
0
        goto out;
3018
0
    }
3019
3020
0
    tc_del_flower_filter(&id);
3021
3022
0
    vxlan_gbp_support = true;
3023
0
    VLOG_INFO("probe tc: vxlan gbp is supported.");
3024
3025
0
out:
3026
0
    tc_add_del_qdisc(ifindex, false, block_id, TC_INGRESS);
3027
0
}
3028
3029
static void
3030
probe_enc_flags_support(int ifindex)
3031
0
{
3032
0
    struct tc_flower flower;
3033
0
    struct tcf_id id;
3034
0
    int block_id = 0;
3035
0
    int prio = TC_RESERVED_PRIORITY_FEATURE_PROBE;
3036
0
    int error;
3037
3038
0
    error = tc_add_del_qdisc(ifindex, true, block_id, TC_INGRESS);
3039
0
    if (error) {
3040
0
        return;
3041
0
    }
3042
3043
0
    memset(&flower, 0, sizeof flower);
3044
0
    flower.tc_policy = TC_POLICY_SKIP_HW;
3045
0
    flower.key.eth_type = htons(ETH_P_IP);
3046
0
    flower.mask.eth_type = OVS_BE16_MAX;
3047
0
    flower.tunnel = true;
3048
0
    flower.mask.tunnel.id = OVS_BE64_MAX;
3049
0
    flower.mask.tunnel.ipv4.ipv4_src = OVS_BE32_MAX;
3050
0
    flower.mask.tunnel.ipv4.ipv4_dst = OVS_BE32_MAX;
3051
0
    flower.mask.tunnel.tp_dst = OVS_BE16_MAX;
3052
0
    flower.mask.tunnel.tc_enc_flags = TCA_FLOWER_KEY_FLAGS_TUNNEL_CRIT_OPT;
3053
0
    flower.key.tunnel.ipv4.ipv4_src = htonl(0x01010101);
3054
0
    flower.key.tunnel.ipv4.ipv4_dst = htonl(0x01010102);
3055
0
    flower.key.tunnel.tp_dst = htons(46354);
3056
0
    flower.key.tunnel.tc_enc_flags = TCA_FLOWER_KEY_FLAGS_TUNNEL_CRIT_OPT;
3057
3058
0
    id = tc_make_tcf_id(ifindex, block_id, prio, TC_INGRESS);
3059
0
    error = tc_replace_flower(&id, &flower);
3060
0
    if (error) {
3061
0
        goto out;
3062
0
    }
3063
3064
0
    tc_del_flower_filter(&id);
3065
3066
0
    enc_flags_support = true;
3067
0
    VLOG_INFO("probe tc: enc flags are supported.");
3068
0
out:
3069
0
    tc_add_del_qdisc(ifindex, false, block_id, TC_INGRESS);
3070
0
}
3071
3072
static int
3073
tc_get_policer_action_ids(struct hmap *map)
3074
0
{
3075
0
    uint32_t police_idx[TCA_ACT_MAX_PRIO];
3076
0
    struct policer_node *policer_node;
3077
0
    struct netdev_flow_dump *dump;
3078
0
    struct ofpbuf rbuffer, reply;
3079
0
    size_t hash;
3080
0
    int i, err;
3081
3082
0
    dump = xzalloc(sizeof *dump);
3083
0
    dump->nl_dump = xzalloc(sizeof *dump->nl_dump);
3084
3085
0
    ofpbuf_init(&rbuffer, NL_DUMP_BUFSIZE);
3086
0
    tc_dump_tc_action_start("police", dump->nl_dump);
3087
3088
0
    while (nl_dump_next(dump->nl_dump, &reply, &rbuffer)) {
3089
0
        memset(police_idx, 0, sizeof police_idx);
3090
0
        if (parse_netlink_to_tc_policer(&reply, police_idx)) {
3091
0
            continue;
3092
0
        }
3093
3094
0
        for (i = 0; i < TCA_ACT_MAX_PRIO; i++) {
3095
0
            if (!police_idx[i]) {
3096
0
                break;
3097
0
            }
3098
0
            policer_node = xzalloc(sizeof *policer_node);
3099
0
            policer_node->police_idx = police_idx[i];
3100
0
            hash = hash_int(police_idx[i], 0);
3101
0
            hmap_insert(map, &policer_node->node, hash);
3102
0
        }
3103
0
    }
3104
3105
0
    err = nl_dump_done(dump->nl_dump);
3106
0
    ofpbuf_uninit(&rbuffer);
3107
0
    free(dump->nl_dump);
3108
0
    free(dump);
3109
3110
0
    return err;
3111
0
}
3112
3113
static void
3114
tc_cleanup_policer_actions(struct id_pool *police_ids,
3115
                          uint32_t id_min, uint32_t id_max)
3116
0
{
3117
0
    struct policer_node *policer_node;
3118
0
    unsigned int unusable_ids = 0;
3119
0
    uint32_t police_idx;
3120
0
    struct hmap map;
3121
0
    int err;
3122
3123
0
    hmap_init(&map);
3124
0
    tc_get_policer_action_ids(&map);
3125
3126
0
    HMAP_FOR_EACH_POP (policer_node, node, &map) {
3127
0
        police_idx = policer_node->police_idx;
3128
0
        if (police_idx >= id_min && police_idx <= id_max) {
3129
0
            err = tc_del_policer_action(police_idx, NULL);
3130
0
            if (err && err != ENOENT) {
3131
                /* Don't use this police any more. */
3132
0
                id_pool_add(police_ids, police_idx);
3133
3134
0
                unusable_ids++;
3135
0
                VLOG_DBG("Policer index %u could not be freed for OVS, "
3136
0
                         "error %d", police_idx, err);
3137
0
            }
3138
0
        }
3139
0
        free(policer_node);
3140
0
    }
3141
3142
0
    if (unusable_ids) {
3143
0
        VLOG_WARN("Full policer index pool allocation failed, "
3144
0
                  "%u indexes are unavailable", unusable_ids);
3145
0
    }
3146
3147
0
    hmap_destroy(&map);
3148
0
}
3149
3150
static int
3151
netdev_tc_init_flow_api(struct netdev *netdev)
3152
0
{
3153
0
    static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER;
3154
0
    enum tc_qdisc_hook hook = get_tc_qdisc_hook(netdev);
3155
0
    static bool get_chain_supported = true;
3156
0
    uint32_t block_id = 0;
3157
0
    struct tcf_id id;
3158
0
    int ifindex;
3159
0
    int error;
3160
3161
0
    if (netdev_vport_is_vport_class(netdev->netdev_class)
3162
0
        && strcmp(netdev_get_dpif_type(netdev), "system")) {
3163
0
        VLOG_DBG("%s: vport doesn't belong to the system datapath. Skipping.",
3164
0
                 netdev_get_name(netdev));
3165
0
        return EOPNOTSUPP;
3166
0
    }
3167
3168
0
    ifindex = netdev_get_ifindex(netdev);
3169
0
    if (ifindex < 0) {
3170
0
        VLOG_INFO("init: failed to get ifindex for %s: %s",
3171
0
                  netdev_get_name(netdev), ovs_strerror(-ifindex));
3172
0
        return -ifindex;
3173
0
    }
3174
3175
0
    block_id = get_block_id_from_netdev(netdev);
3176
0
    id = tc_make_tcf_id(ifindex, block_id, 0, hook);
3177
3178
0
    if (get_chain_supported) {
3179
0
        if (delete_chains_from_netdev(netdev, &id)) {
3180
0
            get_chain_supported = false;
3181
0
        }
3182
0
    }
3183
3184
    /* fallback here if delete chains fail */
3185
0
    if (!get_chain_supported) {
3186
0
        tc_del_flower_filter(&id);
3187
0
    }
3188
3189
    /* make sure there is no ingress/egress qdisc */
3190
0
    tc_add_del_qdisc(ifindex, false, 0, hook);
3191
3192
0
    if (ovsthread_once_start(&once)) {
3193
0
        ccmap_init(&used_chains);
3194
3195
0
        probe_tc_block_support(ifindex);
3196
        /* Need to re-fetch block id as it depends on feature availability. */
3197
0
        block_id = get_block_id_from_netdev(netdev);
3198
3199
0
        probe_multi_mask_per_prio(ifindex);
3200
0
        probe_ct_state_support(ifindex);
3201
0
        probe_vxlan_gbp_support(ifindex);
3202
0
        probe_enc_flags_support(ifindex);
3203
3204
0
        ovs_mutex_lock(&meter_police_ids_mutex);
3205
0
        meter_police_ids = id_pool_create(METER_POLICE_IDS_BASE,
3206
0
                            METER_POLICE_IDS_MAX - METER_POLICE_IDS_BASE + 1);
3207
0
        tc_cleanup_policer_actions(meter_police_ids, METER_POLICE_IDS_BASE,
3208
0
                                   METER_POLICE_IDS_MAX);
3209
0
        ovs_mutex_unlock(&meter_police_ids_mutex);
3210
3211
0
        ovsthread_once_done(&once);
3212
0
    }
3213
3214
0
    error = tc_add_del_qdisc(ifindex, true, block_id, hook);
3215
3216
0
    if (error && error != EEXIST) {
3217
0
        VLOG_INFO("failed adding ingress qdisc required for offloading "
3218
0
                  "on %s: %s",
3219
0
                  netdev_get_name(netdev), ovs_strerror(error));
3220
0
        return error;
3221
0
    }
3222
3223
0
    VLOG_INFO("added ingress qdisc to %s", netdev_get_name(netdev));
3224
3225
0
    return 0;
3226
0
}
3227
3228
static struct meter_police_mapping_data *
3229
meter_id_find_locked(uint32_t meter_id)
3230
    OVS_REQUIRES(meter_mutex)
3231
0
{
3232
0
    struct meter_police_mapping_data *data;
3233
0
    size_t hash = hash_int(meter_id, 0);
3234
3235
0
    HMAP_FOR_EACH_WITH_HASH (data, meter_id_node, hash,
3236
0
                             &meter_id_to_police_idx) {
3237
0
        if (data->meter_id == meter_id) {
3238
0
            return data;
3239
0
        }
3240
0
    }
3241
3242
0
    return NULL;
3243
0
}
3244
3245
static int
3246
meter_id_lookup(uint32_t meter_id, uint32_t *police_idx)
3247
0
{
3248
0
    struct meter_police_mapping_data *data;
3249
3250
0
    ovs_mutex_lock(&meter_mutex);
3251
0
    data = meter_id_find_locked(meter_id);
3252
0
    if (data) {
3253
0
        *police_idx = data->police_idx;
3254
0
    }
3255
0
    ovs_mutex_unlock(&meter_mutex);
3256
3257
0
    return data ? 0 : ENOENT;
3258
0
}
3259
3260
static int
3261
police_idx_lookup(uint32_t police_idx, uint32_t *meter_id)
3262
0
{
3263
0
    struct meter_police_mapping_data *data;
3264
0
    size_t hash = hash_int(police_idx, 0);
3265
0
    int err = ENOENT;
3266
3267
0
    ovs_mutex_lock(&meter_mutex);
3268
0
    HMAP_FOR_EACH_WITH_HASH (data, police_idx_node, hash,
3269
0
                             &police_idx_to_meter_id) {
3270
0
        if (data->police_idx == police_idx) {
3271
0
            *meter_id = data->meter_id;
3272
0
            err = 0;
3273
0
            break;
3274
0
        }
3275
0
    }
3276
0
    ovs_mutex_unlock(&meter_mutex);
3277
3278
0
    return err;
3279
0
}
3280
3281
static void
3282
meter_id_insert(uint32_t meter_id, uint32_t police_idx)
3283
0
{
3284
0
    struct meter_police_mapping_data *data;
3285
3286
0
    ovs_mutex_lock(&meter_mutex);
3287
0
    data = xzalloc(sizeof *data);
3288
0
    data->meter_id = meter_id;
3289
0
    data->police_idx = police_idx;
3290
0
    hmap_insert(&meter_id_to_police_idx, &data->meter_id_node,
3291
0
                hash_int(meter_id, 0));
3292
0
    hmap_insert(&police_idx_to_meter_id, &data->police_idx_node,
3293
0
                hash_int(police_idx, 0));
3294
0
    ovs_mutex_unlock(&meter_mutex);
3295
0
}
3296
3297
static void
3298
meter_id_remove(uint32_t meter_id)
3299
0
{
3300
0
    struct meter_police_mapping_data *data;
3301
3302
0
    ovs_mutex_lock(&meter_mutex);
3303
0
    data = meter_id_find_locked(meter_id);
3304
0
    if (data) {
3305
0
        hmap_remove(&meter_id_to_police_idx, &data->meter_id_node);
3306
0
        hmap_remove(&police_idx_to_meter_id, &data->police_idx_node);
3307
0
        free(data);
3308
0
    }
3309
0
    ovs_mutex_unlock(&meter_mutex);
3310
0
}
3311
3312
static bool
3313
meter_alloc_police_index(uint32_t *police_index)
3314
0
{
3315
0
    bool ret;
3316
3317
0
    ovs_mutex_lock(&meter_police_ids_mutex);
3318
0
    ret = id_pool_alloc_id(meter_police_ids, police_index);
3319
0
    ovs_mutex_unlock(&meter_police_ids_mutex);
3320
3321
0
    return ret;
3322
0
}
3323
3324
static void
3325
meter_free_police_index(uint32_t police_index)
3326
0
{
3327
0
    ovs_mutex_lock(&meter_police_ids_mutex);
3328
0
    id_pool_free_id(meter_police_ids, police_index);
3329
0
    ovs_mutex_unlock(&meter_police_ids_mutex);
3330
0
}
3331
3332
static int
3333
meter_tc_set_policer(ofproto_meter_id meter_id,
3334
                     struct ofputil_meter_config *config)
3335
0
{
3336
0
    uint32_t police_index;
3337
0
    uint32_t rate, burst;
3338
0
    bool add_policer;
3339
0
    int err;
3340
3341
0
    if (!config->bands || config->n_bands < 1 ||
3342
0
        config->bands[0].type != OFPMBT13_DROP) {
3343
0
        return 0;
3344
0
    }
3345
3346
0
    rate = config->bands[0].rate;
3347
0
    if (config->flags & OFPMF13_BURST) {
3348
0
        burst = config->bands[0].burst_size;
3349
0
    } else {
3350
0
        burst = config->bands[0].rate;
3351
0
    }
3352
3353
0
    add_policer = (meter_id_lookup(meter_id.uint32, &police_index) == ENOENT);
3354
0
    if (add_policer) {
3355
0
        if (!meter_alloc_police_index(&police_index)) {
3356
0
            VLOG_WARN_RL(&warn_rl, "No free police index for meter id %u",
3357
0
                         meter_id.uint32);
3358
0
            return ENOENT;
3359
0
        }
3360
0
    }
3361
3362
0
    err = tc_add_policer_action(police_index,
3363
0
                                (config->flags & OFPMF13_KBPS) ? rate : 0,
3364
0
                                (config->flags & OFPMF13_KBPS) ? burst : 0,
3365
0
                                (config->flags & OFPMF13_PKTPS) ? rate : 0,
3366
0
                                (config->flags & OFPMF13_PKTPS) ? burst : 0,
3367
0
                                !add_policer);
3368
0
    if (err) {
3369
0
        VLOG_WARN_RL(&warn_rl,
3370
0
                     "Failed to %s police %u for meter id %u: %s",
3371
0
                     add_policer ? "add" : "modify",
3372
0
                     police_index, meter_id.uint32, ovs_strerror(err));
3373
0
    }
3374
3375
0
    if (add_policer) {
3376
0
        if (!err) {
3377
0
            meter_id_insert(meter_id.uint32, police_index);
3378
0
        } else {
3379
0
            meter_free_police_index(police_index);
3380
0
        }
3381
0
    }
3382
3383
0
    return err;
3384
0
}
3385
3386
static int
3387
meter_tc_get_policer(ofproto_meter_id meter_id,
3388
                     struct ofputil_meter_stats *stats)
3389
0
{
3390
0
    uint32_t police_index;
3391
0
    int err = ENOENT;
3392
3393
0
    if (!meter_id_lookup(meter_id.uint32, &police_index)) {
3394
0
        err = tc_get_policer_action(police_index, stats);
3395
0
        if (err) {
3396
0
            VLOG_WARN_RL(&warn_rl,
3397
0
                         "Failed to get police %u stats for meter %u: %s",
3398
0
                         police_index, meter_id.uint32, ovs_strerror(err));
3399
0
        }
3400
0
    }
3401
3402
0
    return err;
3403
0
}
3404
3405
static int
3406
meter_tc_del_policer(ofproto_meter_id meter_id,
3407
                     struct ofputil_meter_stats *stats)
3408
0
{
3409
0
    uint32_t police_index;
3410
0
    int err = ENOENT;
3411
3412
0
    if (!meter_id_lookup(meter_id.uint32, &police_index)) {
3413
0
        err = tc_del_policer_action(police_index, stats);
3414
0
        if (err && err != ENOENT) {
3415
0
            VLOG_ERR_RL(&error_rl,
3416
0
                        "Failed to del police %u for meter %u: %s",
3417
0
                        police_index, meter_id.uint32, ovs_strerror(err));
3418
0
        } else {
3419
0
            meter_free_police_index(police_index);
3420
0
        }
3421
0
        meter_id_remove(meter_id.uint32);
3422
0
    }
3423
3424
0
    return err;
3425
0
}
3426
3427
const struct netdev_flow_api netdev_offload_tc = {
3428
   .type = "linux_tc",
3429
   .flow_flush = netdev_tc_flow_flush,
3430
   .flow_dump_create = netdev_tc_flow_dump_create,
3431
   .flow_dump_destroy = netdev_tc_flow_dump_destroy,
3432
   .flow_dump_next = netdev_tc_flow_dump_next,
3433
   .flow_put = netdev_tc_flow_put,
3434
   .flow_get = netdev_tc_flow_get,
3435
   .flow_del = netdev_tc_flow_del,
3436
   .flow_get_n_flows = netdev_tc_get_n_flows,
3437
   .meter_set = meter_tc_set_policer,
3438
   .meter_get = meter_tc_get_policer,
3439
   .meter_del = meter_tc_del_policer,
3440
   .init_flow_api = netdev_tc_init_flow_api,
3441
};