Coverage Report

Created: 2026-03-02 06:37

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