Coverage Report

Created: 2025-07-01 06:50

/src/openvswitch/lib/tc.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (c) 2009-2017 Nicira, Inc.
3
 * Copyright (c) 2016 Mellanox Technologies, Ltd.
4
 *
5
 * Licensed under the Apache License, Version 2.0 (the "License");
6
 * you may not use this file except in compliance with the License.
7
 * You may obtain a copy of the License at:
8
 *
9
 *     http://www.apache.org/licenses/LICENSE-2.0
10
 *
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 */
17
18
#include <config.h>
19
#include "tc.h"
20
21
#include <errno.h>
22
#include <linux/if_ether.h>
23
#include <linux/if_packet.h>
24
#include <linux/rtnetlink.h>
25
#include <linux/tc_act/tc_csum.h>
26
#include <linux/tc_act/tc_gact.h>
27
#include <linux/tc_act/tc_mirred.h>
28
#include <linux/tc_act/tc_mpls.h>
29
#include <linux/tc_act/tc_pedit.h>
30
#include <linux/tc_act/tc_skbedit.h>
31
#include <linux/tc_act/tc_tunnel_key.h>
32
#include <linux/tc_act/tc_vlan.h>
33
#include <linux/tc_act/tc_ct.h>
34
#include <linux/gen_stats.h>
35
#include <net/if.h>
36
#include <unistd.h>
37
38
#include "byte-order.h"
39
#include "coverage.h"
40
#include "netlink-socket.h"
41
#include "netlink.h"
42
#include "odp-util.h"
43
#include "openvswitch/ofpbuf.h"
44
#include "openvswitch/util.h"
45
#include "openvswitch/vlog.h"
46
#include "packets.h"
47
#include "timeval.h"
48
#include "unaligned.h"
49
50
0
#define MAX_PEDIT_OFFSETS 32
51
52
#ifndef TCM_IFINDEX_MAGIC_BLOCK
53
#define TCM_IFINDEX_MAGIC_BLOCK (0xFFFFFFFFU)
54
#endif
55
56
#ifndef TCA_DUMP_FLAGS_TERSE
57
0
#define TCA_DUMP_FLAGS_TERSE (1 << 0)
58
#endif
59
60
#if TCA_MAX < 15
61
0
#define TCA_CHAIN 11
62
0
#define TCA_INGRESS_BLOCK 13
63
0
#define TCA_DUMP_FLAGS 15
64
#endif
65
66
#ifndef RTM_GETCHAIN
67
#define RTM_GETCHAIN 102
68
#endif
69
70
VLOG_DEFINE_THIS_MODULE(tc);
71
72
COVERAGE_DEFINE(tc_netlink_malformed_reply);
73
74
static struct vlog_rate_limit error_rl = VLOG_RATE_LIMIT_INIT(60, 5);
75
76
static enum tc_offload_policy tc_policy = TC_POLICY_NONE;
77
78
struct tc_pedit_key_ex {
79
    enum pedit_header_type htype;
80
    enum pedit_cmd cmd;
81
};
82
83
struct flower_key_to_pedit {
84
    enum pedit_header_type htype;
85
    int offset;
86
    int flower_offset;
87
    int size;
88
    int boundary_shift;
89
};
90
91
struct tc_flow_stats {
92
    uint64_t n_packets;
93
    uint64_t n_bytes;
94
};
95
96
static struct flower_key_to_pedit flower_pedit_map[] = {
97
    {
98
        TCA_PEDIT_KEY_EX_HDR_TYPE_IP4,
99
        12,
100
        offsetof(struct tc_flower_key, ipv4.ipv4_src),
101
        MEMBER_SIZEOF(struct tc_flower_key, ipv4.ipv4_src),
102
        0
103
    }, {
104
        TCA_PEDIT_KEY_EX_HDR_TYPE_IP4,
105
        16,
106
        offsetof(struct tc_flower_key, ipv4.ipv4_dst),
107
        MEMBER_SIZEOF(struct tc_flower_key, ipv4.ipv4_dst),
108
        0
109
    }, {
110
        TCA_PEDIT_KEY_EX_HDR_TYPE_IP4,
111
        8,
112
        offsetof(struct tc_flower_key, ipv4.rewrite_ttl),
113
        MEMBER_SIZEOF(struct tc_flower_key, ipv4.rewrite_ttl),
114
        0
115
    }, {
116
        TCA_PEDIT_KEY_EX_HDR_TYPE_IP4,
117
        1,
118
        offsetof(struct tc_flower_key, ipv4.rewrite_tos),
119
        MEMBER_SIZEOF(struct tc_flower_key, ipv4.rewrite_tos),
120
        0
121
    }, {
122
        TCA_PEDIT_KEY_EX_HDR_TYPE_IP6,
123
        7,
124
        offsetof(struct tc_flower_key, ipv6.rewrite_hlimit),
125
        MEMBER_SIZEOF(struct tc_flower_key, ipv6.rewrite_hlimit),
126
        0
127
    }, {
128
        TCA_PEDIT_KEY_EX_HDR_TYPE_IP6,
129
        8,
130
        offsetof(struct tc_flower_key, ipv6.ipv6_src),
131
        MEMBER_SIZEOF(struct tc_flower_key, ipv6.ipv6_src),
132
        0
133
    }, {
134
        TCA_PEDIT_KEY_EX_HDR_TYPE_IP6,
135
        24,
136
        offsetof(struct tc_flower_key, ipv6.ipv6_dst),
137
        MEMBER_SIZEOF(struct tc_flower_key, ipv6.ipv6_dst),
138
        0
139
    }, {
140
        TCA_PEDIT_KEY_EX_HDR_TYPE_IP6,
141
        0,
142
        offsetof(struct tc_flower_key, ipv6.rewrite_tclass),
143
        MEMBER_SIZEOF(struct tc_flower_key, ipv6.rewrite_tclass),
144
        4
145
    }, {
146
        TCA_PEDIT_KEY_EX_HDR_TYPE_ETH,
147
        6,
148
        offsetof(struct tc_flower_key, src_mac),
149
        MEMBER_SIZEOF(struct tc_flower_key, src_mac),
150
        0
151
    }, {
152
        TCA_PEDIT_KEY_EX_HDR_TYPE_ETH,
153
        0,
154
        offsetof(struct tc_flower_key, dst_mac),
155
        MEMBER_SIZEOF(struct tc_flower_key, dst_mac),
156
        0
157
    }, {
158
        TCA_PEDIT_KEY_EX_HDR_TYPE_ETH,
159
        12,
160
        offsetof(struct tc_flower_key, eth_type),
161
        MEMBER_SIZEOF(struct tc_flower_key, eth_type),
162
        0
163
    }, {
164
        TCA_PEDIT_KEY_EX_HDR_TYPE_TCP,
165
        0,
166
        offsetof(struct tc_flower_key, tcp_src),
167
        MEMBER_SIZEOF(struct tc_flower_key, tcp_src),
168
        0
169
    }, {
170
        TCA_PEDIT_KEY_EX_HDR_TYPE_TCP,
171
        2,
172
        offsetof(struct tc_flower_key, tcp_dst),
173
        MEMBER_SIZEOF(struct tc_flower_key, tcp_dst),
174
        0
175
    }, {
176
        TCA_PEDIT_KEY_EX_HDR_TYPE_UDP,
177
        0,
178
        offsetof(struct tc_flower_key, udp_src),
179
        MEMBER_SIZEOF(struct tc_flower_key, udp_src),
180
        0
181
    }, {
182
        TCA_PEDIT_KEY_EX_HDR_TYPE_UDP,
183
        2,
184
        offsetof(struct tc_flower_key, udp_dst),
185
        MEMBER_SIZEOF(struct tc_flower_key, udp_dst),
186
        0
187
    },
188
};
189
190
static inline int
191
csum_update_flag(struct tc_flower *flower,
192
                 enum pedit_header_type htype);
193
194
struct tcmsg *
195
tc_make_request(int ifindex, int type, unsigned int flags,
196
                struct ofpbuf *request)
197
0
{
198
0
    struct tcmsg *tcmsg;
199
200
0
    ofpbuf_init(request, 512);
201
0
    nl_msg_put_nlmsghdr(request, sizeof *tcmsg, type, NLM_F_REQUEST | flags);
202
0
    tcmsg = ofpbuf_put_zeros(request, sizeof *tcmsg);
203
0
    tcmsg->tcm_family = AF_UNSPEC;
204
0
    tcmsg->tcm_ifindex = ifindex;
205
    /* Caller should fill in tcmsg->tcm_handle. */
206
    /* Caller should fill in tcmsg->tcm_parent. */
207
208
0
    return tcmsg;
209
0
}
210
211
struct tcamsg *
212
tc_make_action_request(int type, unsigned int flags,
213
                       struct ofpbuf *request)
214
0
{
215
0
    struct tcamsg *tcamsg;
216
217
0
    ofpbuf_init(request, 512);
218
0
    nl_msg_put_nlmsghdr(request, sizeof *tcamsg, type, NLM_F_REQUEST | flags);
219
0
    tcamsg = ofpbuf_put_zeros(request, sizeof *tcamsg);
220
0
    tcamsg->tca_family = AF_UNSPEC;
221
222
0
    return tcamsg;
223
0
}
224
225
static void request_from_tcf_id(struct tcf_id *id, uint16_t eth_type,
226
                                int type, unsigned int flags,
227
                                struct ofpbuf *request)
228
0
{
229
0
    int ifindex = id->block_id ? TCM_IFINDEX_MAGIC_BLOCK : id->ifindex;
230
0
    uint32_t ingress_parent = id->block_id ? : TC_INGRESS_PARENT;
231
0
    struct tcmsg *tcmsg;
232
233
0
    tcmsg = tc_make_request(ifindex, type, flags, request);
234
0
    tcmsg->tcm_parent = (id->hook == TC_EGRESS) ?
235
0
                        TC_EGRESS_PARENT : ingress_parent;
236
0
    tcmsg->tcm_info = tc_make_handle(id->prio, eth_type);
237
0
    tcmsg->tcm_handle = id->handle;
238
239
0
    if (id->chain) {
240
0
        nl_msg_put_u32(request, TCA_CHAIN, id->chain);
241
0
    }
242
0
}
243
244
int
245
tc_transact(struct ofpbuf *request, struct ofpbuf **replyp)
246
0
{
247
0
    int error = nl_transact(NETLINK_ROUTE, request, replyp);
248
0
    ofpbuf_uninit(request);
249
0
    return error;
250
0
}
251
252
/* Adds or deletes a root qdisc on device with specified ifindex.
253
 *
254
 * The tc_qdisc_hook parameter determines if the qdisc is added on device
255
 * ingress or egress.
256
 *
257
 * If tc_qdisc_hook is TC_INGRESS, this function is equivalent to running the
258
 * following when 'add' is true:
259
 *     /sbin/tc qdisc add dev <devname> handle ffff: ingress
260
 *
261
 * This function is equivalent to running the following when 'add' is false:
262
 *     /sbin/tc qdisc del dev <devname> handle ffff: ingress
263
 *
264
 * If tc_qdisc_hook is TC_EGRESS, this function is equivalent to:
265
 *     /sbin/tc qdisc (add|del) dev <devname> handle ffff: clsact
266
 *
267
 * Where dev <devname> is the device with specified ifindex name.
268
 *
269
 * The configuration and stats may be seen with the following command:
270
 *     /sbin/tc -s qdisc show dev <devname>
271
 *
272
 * If block_id is greater than 0, then the ingress qdisc is added to a block.
273
 * In this case, it is equivalent to running (when 'add' is true):
274
 *     /sbin/tc qdisc add dev <devname> ingress_block <block_id> ingress
275
 *
276
 * Returns 0 if successful, otherwise a positive errno value.
277
 */
278
int
279
tc_add_del_qdisc(int ifindex, bool add, uint32_t block_id,
280
                 enum tc_qdisc_hook hook)
281
0
{
282
0
    struct ofpbuf request;
283
0
    struct tcmsg *tcmsg;
284
0
    int error;
285
0
    int type = add ? RTM_NEWQDISC : RTM_DELQDISC;
286
0
    int flags = add ? NLM_F_EXCL | NLM_F_CREATE : 0;
287
288
0
    tcmsg = tc_make_request(ifindex, type, flags, &request);
289
290
0
    if (hook == TC_EGRESS) {
291
0
        tcmsg->tcm_handle = TC_H_MAKE(TC_H_CLSACT, 0);
292
0
        tcmsg->tcm_parent = TC_H_CLSACT;
293
0
        nl_msg_put_string(&request, TCA_KIND, "clsact");
294
0
    } else {
295
0
        tcmsg->tcm_handle = TC_H_MAKE(TC_H_INGRESS, 0);
296
0
        tcmsg->tcm_parent = TC_H_INGRESS;
297
0
        nl_msg_put_string(&request, TCA_KIND, "ingress");
298
0
    }
299
300
0
    nl_msg_put_unspec(&request, TCA_OPTIONS, NULL, 0);
301
0
    if (hook == TC_INGRESS && block_id) {
302
0
        nl_msg_put_u32(&request, TCA_INGRESS_BLOCK, block_id);
303
0
    }
304
305
0
    error = tc_transact(&request, NULL);
306
0
    if (error) {
307
        /* If we're deleting the qdisc, don't worry about some of the
308
         * error conditions. */
309
0
        if (!add && (error == ENOENT || error == EINVAL)) {
310
0
            return 0;
311
0
        }
312
0
        return error;
313
0
    }
314
315
0
    return 0;
316
0
}
317
318
static const struct nl_policy tca_policy[] = {
319
    [TCA_KIND] = { .type = NL_A_STRING, .optional = false, },
320
    [TCA_OPTIONS] = { .type = NL_A_NESTED, .optional = false, },
321
    [TCA_CHAIN] = { .type = NL_A_U32, .optional = true, },
322
    [TCA_STATS] = { .type = NL_A_UNSPEC,
323
                    .min_len = sizeof(struct tc_stats), .optional = true, },
324
    [TCA_STATS2] = { .type = NL_A_NESTED, .optional = true, },
325
};
326
327
static const struct nl_policy tca_chain_policy[] = {
328
    [TCA_CHAIN] = { .type = NL_A_U32, .optional = false, },
329
};
330
331
static const struct nl_policy tca_flower_policy[] = {
332
    [TCA_FLOWER_CLASSID] = { .type = NL_A_U32, .optional = true, },
333
    [TCA_FLOWER_INDEV] = { .type = NL_A_STRING, .max_len = IFNAMSIZ,
334
                           .optional = true, },
335
    [TCA_FLOWER_KEY_ETH_SRC] = { .type = NL_A_UNSPEC,
336
                                 .min_len = ETH_ALEN, .optional = true, },
337
    [TCA_FLOWER_KEY_ETH_DST] = { .type = NL_A_UNSPEC,
338
                                 .min_len = ETH_ALEN, .optional = true, },
339
    [TCA_FLOWER_KEY_ETH_SRC_MASK] = { .type = NL_A_UNSPEC,
340
                                      .min_len = ETH_ALEN,
341
                                      .optional = true, },
342
    [TCA_FLOWER_KEY_ETH_DST_MASK] = { .type = NL_A_UNSPEC,
343
                                      .min_len = ETH_ALEN,
344
                                      .optional = true, },
345
    [TCA_FLOWER_KEY_ETH_TYPE] = { .type = NL_A_U16, .optional = false, },
346
    [TCA_FLOWER_KEY_ARP_SIP] = { .type = NL_A_U32, .optional = true, },
347
    [TCA_FLOWER_KEY_ARP_TIP] = { .type = NL_A_U32, .optional = true, },
348
    [TCA_FLOWER_KEY_ARP_SHA] = { .type = NL_A_UNSPEC,
349
                                 .min_len = ETH_ALEN,
350
                                 .optional = true, },
351
    [TCA_FLOWER_KEY_ARP_THA] = { .type = NL_A_UNSPEC,
352
                                 .min_len = ETH_ALEN,
353
                                 .optional = true, },
354
    [TCA_FLOWER_KEY_ARP_OP] = { .type = NL_A_U8, .optional = true, },
355
    [TCA_FLOWER_KEY_ARP_SIP_MASK] = { .type = NL_A_U32, .optional = true, },
356
    [TCA_FLOWER_KEY_ARP_TIP_MASK] = { .type = NL_A_U32, .optional = true, },
357
    [TCA_FLOWER_KEY_ARP_SHA_MASK] = { .type = NL_A_UNSPEC,
358
                                      .min_len = ETH_ALEN,
359
                                      .optional = true, },
360
    [TCA_FLOWER_KEY_ARP_THA_MASK] = { .type = NL_A_UNSPEC,
361
                                      .min_len = ETH_ALEN,
362
                                      .optional = true, },
363
    [TCA_FLOWER_KEY_ARP_OP_MASK] = { .type = NL_A_U8, .optional = true, },
364
    [TCA_FLOWER_FLAGS] = { .type = NL_A_U32, .optional = false, },
365
    [TCA_FLOWER_ACT] = { .type = NL_A_NESTED, .optional = false, },
366
    [TCA_FLOWER_KEY_IP_PROTO] = { .type = NL_A_U8, .optional = true, },
367
    [TCA_FLOWER_KEY_IPV4_SRC] = { .type = NL_A_U32, .optional = true, },
368
    [TCA_FLOWER_KEY_IPV4_DST] = {.type = NL_A_U32, .optional = true, },
369
    [TCA_FLOWER_KEY_IPV4_SRC_MASK] = { .type = NL_A_U32, .optional = true, },
370
    [TCA_FLOWER_KEY_IPV4_DST_MASK] = { .type = NL_A_U32, .optional = true, },
371
    [TCA_FLOWER_KEY_IPV6_SRC] = { .type = NL_A_UNSPEC,
372
                                  .min_len = sizeof(struct in6_addr),
373
                                  .optional = true, },
374
    [TCA_FLOWER_KEY_IPV6_DST] = { .type = NL_A_UNSPEC,
375
                                  .min_len = sizeof(struct in6_addr),
376
                                  .optional = true, },
377
    [TCA_FLOWER_KEY_IPV6_SRC_MASK] = { .type = NL_A_UNSPEC,
378
                                       .min_len = sizeof(struct in6_addr),
379
                                       .optional = true, },
380
    [TCA_FLOWER_KEY_IPV6_DST_MASK] = { .type = NL_A_UNSPEC,
381
                                       .min_len = sizeof(struct in6_addr),
382
                                       .optional = true, },
383
    [TCA_FLOWER_KEY_TCP_SRC] = { .type = NL_A_U16, .optional = true, },
384
    [TCA_FLOWER_KEY_TCP_DST] = { .type = NL_A_U16, .optional = true, },
385
    [TCA_FLOWER_KEY_TCP_SRC_MASK] = { .type = NL_A_U16, .optional = true, },
386
    [TCA_FLOWER_KEY_TCP_DST_MASK] = { .type = NL_A_U16, .optional = true, },
387
    [TCA_FLOWER_KEY_UDP_SRC] = { .type = NL_A_U16, .optional = true, },
388
    [TCA_FLOWER_KEY_UDP_DST] = { .type = NL_A_U16, .optional = true, },
389
    [TCA_FLOWER_KEY_UDP_SRC_MASK] = { .type = NL_A_U16, .optional = true, },
390
    [TCA_FLOWER_KEY_UDP_DST_MASK] = { .type = NL_A_U16, .optional = true, },
391
    [TCA_FLOWER_KEY_SCTP_SRC] = { .type = NL_A_U16, .optional = true, },
392
    [TCA_FLOWER_KEY_SCTP_DST] = { .type = NL_A_U16, .optional = true, },
393
    [TCA_FLOWER_KEY_SCTP_SRC_MASK] = { .type = NL_A_U16, .optional = true, },
394
    [TCA_FLOWER_KEY_SCTP_DST_MASK] = { .type = NL_A_U16, .optional = true, },
395
    [TCA_FLOWER_KEY_MPLS_TTL] = { .type = NL_A_U8, .optional = true, },
396
    [TCA_FLOWER_KEY_MPLS_TC] = { .type = NL_A_U8, .optional = true, },
397
    [TCA_FLOWER_KEY_MPLS_BOS] = { .type = NL_A_U8, .optional = true, },
398
    [TCA_FLOWER_KEY_MPLS_LABEL] = { .type = NL_A_U32, .optional = true, },
399
    [TCA_FLOWER_KEY_VLAN_ID] = { .type = NL_A_U16, .optional = true, },
400
    [TCA_FLOWER_KEY_VLAN_PRIO] = { .type = NL_A_U8, .optional = true, },
401
    [TCA_FLOWER_KEY_VLAN_ETH_TYPE] = { .type = NL_A_U16, .optional = true, },
402
    [TCA_FLOWER_KEY_ENC_KEY_ID] = { .type = NL_A_U32, .optional = true, },
403
    [TCA_FLOWER_KEY_ENC_IPV4_SRC] = { .type = NL_A_U32, .optional = true, },
404
    [TCA_FLOWER_KEY_ENC_IPV4_DST] = { .type = NL_A_U32, .optional = true, },
405
    [TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK] = { .type = NL_A_U32,
406
                                           .optional = true, },
407
    [TCA_FLOWER_KEY_ENC_IPV4_DST_MASK] = { .type = NL_A_U32,
408
                                           .optional = true, },
409
    [TCA_FLOWER_KEY_ENC_IPV6_SRC] = { .type = NL_A_UNSPEC,
410
                                      .min_len = sizeof(struct in6_addr),
411
                                      .optional = true, },
412
    [TCA_FLOWER_KEY_ENC_IPV6_DST] = { .type = NL_A_UNSPEC,
413
                                      .min_len = sizeof(struct in6_addr),
414
                                      .optional = true, },
415
    [TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK] = { .type = NL_A_UNSPEC,
416
                                           .min_len = sizeof(struct in6_addr),
417
                                           .optional = true, },
418
    [TCA_FLOWER_KEY_ENC_IPV6_DST_MASK] = { .type = NL_A_UNSPEC,
419
                                           .min_len = sizeof(struct in6_addr),
420
                                           .optional = true, },
421
    [TCA_FLOWER_KEY_ENC_UDP_SRC_PORT] = { .type = NL_A_U16,
422
                                          .optional = true, },
423
    [TCA_FLOWER_KEY_ENC_UDP_SRC_PORT_MASK] = { .type = NL_A_U16,
424
                                               .optional = true, },
425
    [TCA_FLOWER_KEY_ENC_UDP_DST_PORT] = { .type = NL_A_U16,
426
                                          .optional = true, },
427
    [TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK] = { .type = NL_A_U16,
428
                                               .optional = true, },
429
    [TCA_FLOWER_KEY_FLAGS] = { .type = NL_A_BE32, .optional = true, },
430
    [TCA_FLOWER_KEY_FLAGS_MASK] = { .type = NL_A_BE32, .optional = true, },
431
    [TCA_FLOWER_KEY_IP_TTL] = { .type = NL_A_U8,
432
                                .optional = true, },
433
    [TCA_FLOWER_KEY_IP_TTL_MASK] = { .type = NL_A_U8,
434
                                     .optional = true, },
435
    [TCA_FLOWER_KEY_IP_TOS] = { .type = NL_A_U8,
436
                                .optional = true, },
437
    [TCA_FLOWER_KEY_IP_TOS_MASK] = { .type = NL_A_U8,
438
                                     .optional = true, },
439
    [TCA_FLOWER_KEY_TCP_FLAGS] = { .type = NL_A_U16,
440
                                   .optional = true, },
441
    [TCA_FLOWER_KEY_TCP_FLAGS_MASK] = { .type = NL_A_U16,
442
                                        .optional = true, },
443
    [TCA_FLOWER_KEY_CVLAN_ID] = { .type = NL_A_U16, .optional = true, },
444
    [TCA_FLOWER_KEY_CVLAN_PRIO] = { .type = NL_A_U8, .optional = true, },
445
    [TCA_FLOWER_KEY_CVLAN_ETH_TYPE] = { .type = NL_A_U16, .optional = true, },
446
    [TCA_FLOWER_KEY_ENC_IP_TOS] = { .type = NL_A_U8,
447
                                    .optional = true, },
448
    [TCA_FLOWER_KEY_ENC_IP_TOS_MASK] = { .type = NL_A_U8,
449
                                         .optional = true, },
450
    [TCA_FLOWER_KEY_ENC_IP_TTL] = { .type = NL_A_U8,
451
                                    .optional = true, },
452
    [TCA_FLOWER_KEY_ENC_IP_TTL_MASK] = { .type = NL_A_U8,
453
                                         .optional = true, },
454
    [TCA_FLOWER_KEY_ENC_OPTS] = { .type = NL_A_NESTED, .optional = true, },
455
    [TCA_FLOWER_KEY_ENC_OPTS_MASK] = { .type = NL_A_NESTED,
456
                                       .optional = true, },
457
    [TCA_FLOWER_KEY_ENC_FLAGS] = { .type = NL_A_BE32, .optional = true, },
458
    [TCA_FLOWER_KEY_ENC_FLAGS_MASK] = { .type = NL_A_BE32,
459
                                        .optional = true, },
460
    [TCA_FLOWER_KEY_CT_STATE] = { .type = NL_A_U16, .optional = true, },
461
    [TCA_FLOWER_KEY_CT_STATE_MASK] = { .type = NL_A_U16, .optional = true, },
462
    [TCA_FLOWER_KEY_CT_ZONE] = { .type = NL_A_U16, .optional = true, },
463
    [TCA_FLOWER_KEY_CT_ZONE_MASK] = { .type = NL_A_U16, .optional = true, },
464
    [TCA_FLOWER_KEY_CT_MARK] = { .type = NL_A_U32, .optional = true, },
465
    [TCA_FLOWER_KEY_CT_MARK_MASK] = { .type = NL_A_U32, .optional = true, },
466
    [TCA_FLOWER_KEY_CT_LABELS] = { .type = NL_A_U128, .optional = true, },
467
    [TCA_FLOWER_KEY_CT_LABELS_MASK] = { .type = NL_A_U128,
468
                                        .optional = true, },
469
    [TCA_FLOWER_KEY_ICMPV4_CODE] = { .type = NL_A_U8,
470
                                     .optional = true, },
471
    [TCA_FLOWER_KEY_ICMPV4_CODE_MASK] = { .type = NL_A_U8,
472
                                          .optional = true, },
473
    [TCA_FLOWER_KEY_ICMPV4_TYPE] = { .type = NL_A_U8,
474
                                     .optional = true, },
475
    [TCA_FLOWER_KEY_ICMPV4_TYPE_MASK] = { .type = NL_A_U8,
476
                                          .optional = true, },
477
    [TCA_FLOWER_KEY_ICMPV6_CODE] = { .type = NL_A_U8,
478
                                     .optional = true, },
479
    [TCA_FLOWER_KEY_ICMPV6_CODE_MASK] = { .type = NL_A_U8,
480
                                          .optional = true, },
481
    [TCA_FLOWER_KEY_ICMPV6_TYPE] = { .type = NL_A_U8,
482
                                     .optional = true, },
483
    [TCA_FLOWER_KEY_ICMPV6_TYPE_MASK] = { .type = NL_A_U8,
484
                                          .optional = true, },
485
};
486
487
static const struct nl_policy tca_flower_terse_policy[] = {
488
    [TCA_FLOWER_FLAGS] = { .type = NL_A_U32, .optional = false, },
489
    [TCA_FLOWER_ACT] = { .type = NL_A_NESTED, .optional = false, },
490
};
491
492
static void
493
nl_parse_flower_arp(struct nlattr **attrs, struct tc_flower *flower)
494
0
{
495
0
    const struct eth_addr *eth;
496
497
0
    if (attrs[TCA_FLOWER_KEY_ARP_SIP_MASK]) {
498
0
        flower->key.arp.spa =
499
0
            nl_attr_get_be32(attrs[TCA_FLOWER_KEY_ARP_SIP]);
500
0
        flower->mask.arp.spa =
501
0
            nl_attr_get_be32(attrs[TCA_FLOWER_KEY_ARP_SIP_MASK]);
502
0
    }
503
0
    if (attrs[TCA_FLOWER_KEY_ARP_TIP_MASK]) {
504
0
        flower->key.arp.tpa =
505
0
            nl_attr_get_be32(attrs[TCA_FLOWER_KEY_ARP_TIP]);
506
0
        flower->mask.arp.tpa =
507
0
            nl_attr_get_be32(attrs[TCA_FLOWER_KEY_ARP_TIP_MASK]);
508
0
    }
509
0
    if (attrs[TCA_FLOWER_KEY_ARP_SHA_MASK]) {
510
0
        eth = nl_attr_get_unspec(attrs[TCA_FLOWER_KEY_ARP_SHA], ETH_ALEN);
511
0
        memcpy(&flower->key.arp.sha, eth, sizeof flower->key.arp.sha);
512
513
0
        eth = nl_attr_get_unspec(attrs[TCA_FLOWER_KEY_ARP_SHA_MASK], ETH_ALEN);
514
0
        memcpy(&flower->mask.arp.sha, eth, sizeof flower->mask.arp.sha);
515
0
    }
516
0
    if (attrs[TCA_FLOWER_KEY_ARP_THA_MASK]) {
517
0
        eth = nl_attr_get_unspec(attrs[TCA_FLOWER_KEY_ARP_THA], ETH_ALEN);
518
0
        memcpy(&flower->key.arp.tha, eth, sizeof flower->key.arp.tha);
519
520
0
        eth = nl_attr_get_unspec(attrs[TCA_FLOWER_KEY_ARP_THA_MASK], ETH_ALEN);
521
0
        memcpy(&flower->mask.arp.tha, eth, sizeof flower->mask.arp.tha);
522
0
    }
523
0
    if (attrs[TCA_FLOWER_KEY_ARP_OP_MASK]) {
524
0
        flower->key.arp.opcode =
525
0
            nl_attr_get_u8(attrs[TCA_FLOWER_KEY_ARP_OP]);
526
0
        flower->mask.arp.opcode =
527
0
            nl_attr_get_u8(attrs[TCA_FLOWER_KEY_ARP_OP_MASK]);
528
0
    }
529
0
}
530
531
static void
532
nl_parse_flower_eth(struct nlattr **attrs, struct tc_flower *flower)
533
0
{
534
0
    const struct eth_addr *eth;
535
536
0
    if (attrs[TCA_FLOWER_KEY_ETH_SRC_MASK]) {
537
0
        eth = nl_attr_get_unspec(attrs[TCA_FLOWER_KEY_ETH_SRC], ETH_ALEN);
538
0
        memcpy(&flower->key.src_mac, eth, sizeof flower->key.src_mac);
539
540
0
        eth = nl_attr_get_unspec(attrs[TCA_FLOWER_KEY_ETH_SRC_MASK], ETH_ALEN);
541
0
        memcpy(&flower->mask.src_mac, eth, sizeof flower->mask.src_mac);
542
0
    }
543
0
    if (attrs[TCA_FLOWER_KEY_ETH_DST_MASK]) {
544
0
        eth = nl_attr_get_unspec(attrs[TCA_FLOWER_KEY_ETH_DST], ETH_ALEN);
545
0
        memcpy(&flower->key.dst_mac, eth, sizeof flower->key.dst_mac);
546
547
0
        eth = nl_attr_get_unspec(attrs[TCA_FLOWER_KEY_ETH_DST_MASK], ETH_ALEN);
548
0
        memcpy(&flower->mask.dst_mac, eth, sizeof flower->mask.dst_mac);
549
0
    }
550
0
}
551
552
static void
553
nl_parse_flower_mpls(struct nlattr **attrs, struct tc_flower *flower)
554
0
{
555
0
    uint8_t ttl, tc, bos;
556
0
    uint32_t label;
557
558
0
    if (!eth_type_mpls(flower->key.eth_type)) {
559
0
        return;
560
0
    }
561
562
0
    flower->key.encap_eth_type[0] =
563
0
        nl_attr_get_be16(attrs[TCA_FLOWER_KEY_ETH_TYPE]);
564
0
    flower->key.mpls_lse = 0;
565
0
    flower->mask.mpls_lse = 0;
566
567
0
    if (attrs[TCA_FLOWER_KEY_MPLS_TTL]) {
568
0
        ttl = nl_attr_get_u8(attrs[TCA_FLOWER_KEY_MPLS_TTL]);
569
0
        set_mpls_lse_ttl(&flower->key.mpls_lse, ttl);
570
0
        set_mpls_lse_ttl(&flower->mask.mpls_lse, 0xff);
571
0
    }
572
573
0
    if (attrs[TCA_FLOWER_KEY_MPLS_BOS]) {
574
0
        bos = nl_attr_get_u8(attrs[TCA_FLOWER_KEY_MPLS_BOS]);
575
0
        set_mpls_lse_bos(&flower->key.mpls_lse, bos);
576
0
        set_mpls_lse_bos(&flower->mask.mpls_lse, 0xff);
577
0
    }
578
579
0
    if (attrs[TCA_FLOWER_KEY_MPLS_TC]) {
580
0
        tc = nl_attr_get_u8(attrs[TCA_FLOWER_KEY_MPLS_TC]);
581
0
        set_mpls_lse_tc(&flower->key.mpls_lse, tc);
582
0
        set_mpls_lse_tc(&flower->mask.mpls_lse, 0xff);
583
0
    }
584
585
0
    if (attrs[TCA_FLOWER_KEY_MPLS_LABEL]) {
586
0
        label = nl_attr_get_u32(attrs[TCA_FLOWER_KEY_MPLS_LABEL]);
587
0
        set_mpls_lse_label(&flower->key.mpls_lse, htonl(label));
588
0
        set_mpls_lse_label(&flower->mask.mpls_lse, OVS_BE32_MAX);
589
0
    }
590
0
}
591
592
static void
593
nl_parse_flower_vlan(struct nlattr **attrs, struct tc_flower *flower)
594
0
{
595
0
    ovs_be16 encap_ethtype;
596
597
0
    if (!eth_type_vlan(flower->key.eth_type)) {
598
0
        return;
599
0
    }
600
601
0
    flower->key.encap_eth_type[0] =
602
0
        nl_attr_get_be16(attrs[TCA_FLOWER_KEY_ETH_TYPE]);
603
0
    flower->mask.encap_eth_type[0] = CONSTANT_HTONS(0xffff);
604
605
0
    if (attrs[TCA_FLOWER_KEY_VLAN_ID]) {
606
0
        flower->key.vlan_id[0] =
607
0
            nl_attr_get_u16(attrs[TCA_FLOWER_KEY_VLAN_ID]);
608
0
        flower->mask.vlan_id[0] = VLAN_VID_MASK >> VLAN_VID_SHIFT;
609
0
    }
610
0
    if (attrs[TCA_FLOWER_KEY_VLAN_PRIO]) {
611
0
        flower->key.vlan_prio[0] =
612
0
            nl_attr_get_u8(attrs[TCA_FLOWER_KEY_VLAN_PRIO]);
613
0
        flower->mask.vlan_prio[0] = VLAN_PCP_MASK >> VLAN_PCP_SHIFT;
614
0
    }
615
616
0
    if (!attrs[TCA_FLOWER_KEY_VLAN_ETH_TYPE]) {
617
0
        return;
618
0
    }
619
620
0
    encap_ethtype = nl_attr_get_be16(attrs[TCA_FLOWER_KEY_VLAN_ETH_TYPE]);
621
0
    if (!eth_type_vlan(encap_ethtype)) {
622
0
        return;
623
0
    }
624
625
0
    flower->key.encap_eth_type[1] = flower->key.encap_eth_type[0];
626
0
    flower->mask.encap_eth_type[1] = CONSTANT_HTONS(0xffff);
627
0
    flower->key.encap_eth_type[0] = encap_ethtype;
628
629
0
    if (attrs[TCA_FLOWER_KEY_CVLAN_ID]) {
630
0
        flower->key.vlan_id[1] =
631
0
            nl_attr_get_u16(attrs[TCA_FLOWER_KEY_CVLAN_ID]);
632
0
        flower->mask.vlan_id[1] = VLAN_VID_MASK >> VLAN_VID_SHIFT;
633
0
    }
634
0
    if (attrs[TCA_FLOWER_KEY_CVLAN_PRIO]) {
635
0
        flower->key.vlan_prio[1] =
636
0
            nl_attr_get_u8(attrs[TCA_FLOWER_KEY_CVLAN_PRIO]);
637
0
        flower->mask.vlan_prio[1] = VLAN_PCP_MASK >> VLAN_PCP_SHIFT;
638
0
    }
639
0
}
640
641
static int
642
nl_parse_geneve_key(const struct nlattr *in_nlattr,
643
                    struct tun_metadata *metadata)
644
0
{
645
0
    struct geneve_opt *opt = NULL;
646
0
    const struct ofpbuf *msg;
647
0
    uint16_t last_opt_type;
648
0
    struct nlattr *nla;
649
0
    struct ofpbuf buf;
650
0
    size_t left;
651
0
    int cnt;
652
653
0
    nl_attr_get_nested(in_nlattr, &buf);
654
0
    msg = &buf;
655
656
0
    last_opt_type = TCA_FLOWER_KEY_ENC_OPT_GENEVE_UNSPEC;
657
0
    cnt = 0;
658
0
    NL_ATTR_FOR_EACH (nla, left, ofpbuf_at(msg, 0, 0), msg->size) {
659
0
        uint16_t type = nl_attr_type(nla);
660
661
0
        switch (type) {
662
0
        case TCA_FLOWER_KEY_ENC_OPT_GENEVE_CLASS:
663
0
            if (cnt && last_opt_type != TCA_FLOWER_KEY_ENC_OPT_GENEVE_DATA) {
664
0
                VLOG_ERR_RL(&error_rl, "failed to parse tun options class");
665
0
                return EINVAL;
666
0
            }
667
668
0
            opt = &metadata->opts.gnv[cnt];
669
0
            opt->opt_class = nl_attr_get_be16(nla);
670
0
            cnt += sizeof(struct geneve_opt) / 4;
671
0
            metadata->present.len += sizeof(struct geneve_opt);
672
0
            last_opt_type = TCA_FLOWER_KEY_ENC_OPT_GENEVE_CLASS;
673
0
            break;
674
0
        case TCA_FLOWER_KEY_ENC_OPT_GENEVE_TYPE:
675
0
            if (last_opt_type != TCA_FLOWER_KEY_ENC_OPT_GENEVE_CLASS) {
676
0
                VLOG_ERR_RL(&error_rl, "failed to parse tun options type");
677
0
                return EINVAL;
678
0
            }
679
680
0
            opt->type = nl_attr_get_u8(nla);
681
0
            last_opt_type = TCA_FLOWER_KEY_ENC_OPT_GENEVE_TYPE;
682
0
            break;
683
0
        case TCA_FLOWER_KEY_ENC_OPT_GENEVE_DATA:
684
0
            if (last_opt_type != TCA_FLOWER_KEY_ENC_OPT_GENEVE_TYPE) {
685
0
                VLOG_ERR_RL(&error_rl, "failed to parse tun options data");
686
0
                return EINVAL;
687
0
            }
688
689
0
            opt->length = nl_attr_get_size(nla) / 4;
690
0
            memcpy(opt + 1, nl_attr_get_unspec(nla, 1), opt->length * 4);
691
0
            cnt += opt->length;
692
0
            metadata->present.len += opt->length * 4;
693
0
            last_opt_type = TCA_FLOWER_KEY_ENC_OPT_GENEVE_DATA;
694
0
            break;
695
0
        }
696
0
    }
697
698
0
    if (last_opt_type != TCA_FLOWER_KEY_ENC_OPT_GENEVE_DATA) {
699
0
        VLOG_ERR_RL(&error_rl, "failed to parse tun options without data");
700
0
        return EINVAL;
701
0
    }
702
703
0
    return 0;
704
0
}
705
706
static int
707
nl_parse_vxlan_key(const struct nlattr *in_nlattr,
708
                   struct tc_flower_tunnel *tunnel)
709
0
{
710
0
    const struct ofpbuf *msg;
711
0
    struct nlattr *nla;
712
0
    struct ofpbuf buf;
713
0
    uint32_t gbp_raw;
714
0
    size_t left;
715
716
0
    nl_attr_get_nested(in_nlattr, &buf);
717
0
    msg = &buf;
718
719
0
    NL_ATTR_FOR_EACH (nla, left, ofpbuf_at(msg, 0, 0), msg->size) {
720
0
        uint16_t type = nl_attr_type(nla);
721
722
0
        switch (type) {
723
0
        case TCA_FLOWER_KEY_ENC_OPT_VXLAN_GBP:
724
0
            gbp_raw = nl_attr_get_u32(nla);
725
0
            odp_decode_gbp_raw(gbp_raw, &tunnel->gbp.id,
726
0
                               &tunnel->gbp.flags);
727
0
            tunnel->gbp.id_present = true;
728
0
            break;
729
0
        default:
730
0
            VLOG_WARN_RL(&error_rl, "failed to parse vxlan tun options");
731
0
            return EINVAL;
732
0
        }
733
0
    }
734
735
0
    return 0;
736
0
}
737
738
static int
739
nl_parse_flower_tunnel_opts(struct nlattr *options,
740
                            struct tc_flower_tunnel *tunnel)
741
0
{
742
0
    const struct ofpbuf *msg;
743
0
    struct nlattr *nla;
744
0
    struct ofpbuf buf;
745
0
    size_t left;
746
0
    int err;
747
748
0
    nl_attr_get_nested(options, &buf);
749
0
    msg = &buf;
750
751
0
    NL_ATTR_FOR_EACH (nla, left, ofpbuf_at(msg, 0, 0), msg->size) {
752
0
        uint16_t type = nl_attr_type(nla);
753
0
        switch (type) {
754
0
        case TCA_FLOWER_KEY_ENC_OPTS_GENEVE:
755
0
            err = nl_parse_geneve_key(nla, &tunnel->metadata);
756
0
            if (err) {
757
0
                return err;
758
0
            }
759
760
0
            break;
761
0
        case TCA_FLOWER_KEY_ENC_OPTS_VXLAN:
762
0
            err = nl_parse_vxlan_key(nla, tunnel);
763
0
            if (err) {
764
0
                return err;
765
0
            }
766
767
0
            break;
768
0
        }
769
0
    }
770
771
0
    return 0;
772
0
}
773
774
static int
775
flower_tun_geneve_opt_check_len(struct tun_metadata *key,
776
                                struct tun_metadata *mask)
777
0
{
778
0
    const struct geneve_opt *opt, *opt_mask;
779
0
    int len, cnt = 0;
780
781
0
    if (key->present.len != mask->present.len) {
782
0
        goto bad_length;
783
0
    }
784
785
0
    len = key->present.len;
786
0
    while (len) {
787
0
        opt = &key->opts.gnv[cnt];
788
0
        opt_mask = &mask->opts.gnv[cnt];
789
790
0
        if (opt->length != opt_mask->length) {
791
0
            goto bad_length;
792
0
        }
793
794
0
        cnt += sizeof(struct geneve_opt) / 4 + opt->length;
795
0
        len -= sizeof(struct geneve_opt) + opt->length * 4;
796
0
    }
797
798
0
    return 0;
799
800
0
bad_length:
801
0
    VLOG_ERR_RL(&error_rl,
802
0
                "failed to parse tun options; key/mask length differ");
803
0
    return EINVAL;
804
0
}
805
806
static int
807
nl_parse_flower_tunnel(struct nlattr **attrs, struct tc_flower *flower)
808
0
{
809
0
    int err;
810
811
0
    if (attrs[TCA_FLOWER_KEY_ENC_KEY_ID]) {
812
0
        ovs_be32 id = nl_attr_get_be32(attrs[TCA_FLOWER_KEY_ENC_KEY_ID]);
813
814
0
        flower->key.tunnel.id = be32_to_be64(id);
815
0
        flower->mask.tunnel.id = OVS_BE64_MAX;
816
0
    }
817
0
    if (attrs[TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK]) {
818
0
        flower->mask.tunnel.ipv4.ipv4_src =
819
0
            nl_attr_get_be32(attrs[TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK]);
820
0
        flower->key.tunnel.ipv4.ipv4_src =
821
0
            nl_attr_get_be32(attrs[TCA_FLOWER_KEY_ENC_IPV4_SRC]);
822
0
    }
823
0
    if (attrs[TCA_FLOWER_KEY_ENC_IPV4_DST_MASK]) {
824
0
        flower->mask.tunnel.ipv4.ipv4_dst =
825
0
            nl_attr_get_be32(attrs[TCA_FLOWER_KEY_ENC_IPV4_DST_MASK]);
826
0
        flower->key.tunnel.ipv4.ipv4_dst =
827
0
            nl_attr_get_be32(attrs[TCA_FLOWER_KEY_ENC_IPV4_DST]);
828
0
    }
829
0
    if (attrs[TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK]) {
830
0
        flower->mask.tunnel.ipv6.ipv6_src =
831
0
            nl_attr_get_in6_addr(attrs[TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK]);
832
0
        flower->key.tunnel.ipv6.ipv6_src =
833
0
            nl_attr_get_in6_addr(attrs[TCA_FLOWER_KEY_ENC_IPV6_SRC]);
834
0
    }
835
0
    if (attrs[TCA_FLOWER_KEY_ENC_IPV6_DST_MASK]) {
836
0
        flower->mask.tunnel.ipv6.ipv6_dst =
837
0
            nl_attr_get_in6_addr(attrs[TCA_FLOWER_KEY_ENC_IPV6_DST_MASK]);
838
0
        flower->key.tunnel.ipv6.ipv6_dst =
839
0
            nl_attr_get_in6_addr(attrs[TCA_FLOWER_KEY_ENC_IPV6_DST]);
840
0
    }
841
0
    if (attrs[TCA_FLOWER_KEY_ENC_UDP_SRC_PORT_MASK]) {
842
0
        flower->mask.tunnel.tp_src =
843
0
            nl_attr_get_be16(attrs[TCA_FLOWER_KEY_ENC_UDP_SRC_PORT_MASK]);
844
0
        flower->key.tunnel.tp_src =
845
0
            nl_attr_get_be16(attrs[TCA_FLOWER_KEY_ENC_UDP_SRC_PORT]);
846
0
    }
847
0
    if (attrs[TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK]) {
848
0
        flower->mask.tunnel.tp_dst =
849
0
            nl_attr_get_be16(attrs[TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK]);
850
0
        flower->key.tunnel.tp_dst =
851
0
            nl_attr_get_be16(attrs[TCA_FLOWER_KEY_ENC_UDP_DST_PORT]);
852
0
    }
853
0
    if (attrs[TCA_FLOWER_KEY_ENC_IP_TOS_MASK]) {
854
0
        flower->key.tunnel.tos =
855
0
            nl_attr_get_u8(attrs[TCA_FLOWER_KEY_ENC_IP_TOS]);
856
0
        flower->mask.tunnel.tos =
857
0
            nl_attr_get_u8(attrs[TCA_FLOWER_KEY_ENC_IP_TOS_MASK]);
858
0
    }
859
0
    if (attrs[TCA_FLOWER_KEY_ENC_IP_TTL_MASK]) {
860
0
        flower->key.tunnel.ttl =
861
0
            nl_attr_get_u8(attrs[TCA_FLOWER_KEY_ENC_IP_TTL]);
862
0
        flower->mask.tunnel.ttl =
863
0
            nl_attr_get_u8(attrs[TCA_FLOWER_KEY_ENC_IP_TTL_MASK]);
864
0
    }
865
866
0
    if (!is_all_zeros(&flower->mask.tunnel, sizeof flower->mask.tunnel) ||
867
0
        !is_all_zeros(&flower->key.tunnel, sizeof flower->key.tunnel)) {
868
0
        flower->tunnel = true;
869
0
    }
870
871
0
    if (attrs[TCA_FLOWER_KEY_ENC_FLAGS_MASK]) {
872
0
        flower->key.tunnel.tc_enc_flags = ntohl(
873
0
            nl_attr_get_be32(attrs[TCA_FLOWER_KEY_ENC_FLAGS]));
874
0
        flower->mask.tunnel.tc_enc_flags = ntohl(
875
0
            nl_attr_get_be32(attrs[TCA_FLOWER_KEY_ENC_FLAGS_MASK]));
876
0
    }
877
878
0
    if (attrs[TCA_FLOWER_KEY_ENC_OPTS] &&
879
0
        attrs[TCA_FLOWER_KEY_ENC_OPTS_MASK]) {
880
0
         err = nl_parse_flower_tunnel_opts(attrs[TCA_FLOWER_KEY_ENC_OPTS],
881
0
                                           &flower->key.tunnel);
882
0
         if (err) {
883
0
             return err;
884
0
         }
885
886
0
         err = nl_parse_flower_tunnel_opts(attrs[TCA_FLOWER_KEY_ENC_OPTS_MASK],
887
0
                                           &flower->mask.tunnel);
888
0
         if (err) {
889
0
             return err;
890
0
         }
891
892
0
         err = flower_tun_geneve_opt_check_len(&flower->key.tunnel.metadata,
893
0
                                               &flower->mask.tunnel.metadata);
894
0
         if (err) {
895
0
             return err;
896
0
         }
897
0
    } else if (attrs[TCA_FLOWER_KEY_ENC_OPTS]) {
898
0
        VLOG_ERR_RL(&error_rl,
899
0
                    "failed to parse tun options; no mask supplied");
900
0
        return EINVAL;
901
0
    } else if (attrs[TCA_FLOWER_KEY_ENC_OPTS_MASK]) {
902
0
        VLOG_ERR_RL(&error_rl, "failed to parse tun options; no key supplied");
903
0
        return EINVAL;
904
0
    }
905
906
0
    return 0;
907
0
}
908
909
static void
910
0
nl_parse_flower_ct_match(struct nlattr **attrs, struct tc_flower *flower) {
911
0
    struct tc_flower_key *key = &flower->key;
912
0
    struct tc_flower_key *mask = &flower->mask;
913
0
    struct nlattr *attr_key, *attr_mask;
914
915
0
    attr_key = attrs[TCA_FLOWER_KEY_CT_STATE];
916
0
    attr_mask = attrs[TCA_FLOWER_KEY_CT_STATE_MASK];
917
0
    if (attr_mask) {
918
0
        key->ct_state = nl_attr_get_u16(attr_key);
919
0
        mask->ct_state = nl_attr_get_u16(attr_mask);
920
0
    }
921
922
0
    attr_key = attrs[TCA_FLOWER_KEY_CT_ZONE];
923
0
    attr_mask = attrs[TCA_FLOWER_KEY_CT_ZONE_MASK];
924
0
    if (attrs[TCA_FLOWER_KEY_CT_ZONE_MASK]) {
925
0
        key->ct_zone = nl_attr_get_u16(attr_key);
926
0
        mask->ct_zone = nl_attr_get_u16(attr_mask);
927
0
    }
928
929
0
    attr_key = attrs[TCA_FLOWER_KEY_CT_MARK];
930
0
    attr_mask = attrs[TCA_FLOWER_KEY_CT_MARK_MASK];
931
0
    if (attrs[TCA_FLOWER_KEY_CT_MARK_MASK]) {
932
0
        key->ct_mark = nl_attr_get_u32(attr_key);
933
0
        mask->ct_mark = nl_attr_get_u32(attr_mask);
934
0
    }
935
936
0
    attr_key = attrs[TCA_FLOWER_KEY_CT_LABELS];
937
0
    attr_mask = attrs[TCA_FLOWER_KEY_CT_LABELS_MASK];
938
0
    if (attrs[TCA_FLOWER_KEY_CT_LABELS_MASK]) {
939
0
        key->ct_label = nl_attr_get_u128(attr_key);
940
0
        mask->ct_label = nl_attr_get_u128(attr_mask);
941
0
    }
942
0
}
943
944
static void
945
0
nl_parse_flower_ip(struct nlattr **attrs, struct tc_flower *flower) {
946
0
    uint8_t ip_proto = 0;
947
0
    struct tc_flower_key *key = &flower->key;
948
0
    struct tc_flower_key *mask = &flower->mask;
949
950
0
    if (attrs[TCA_FLOWER_KEY_IP_PROTO]) {
951
0
        ip_proto = nl_attr_get_u8(attrs[TCA_FLOWER_KEY_IP_PROTO]);
952
0
        key->ip_proto = ip_proto;
953
0
        mask->ip_proto = UINT8_MAX;
954
0
    }
955
956
0
    if (attrs[TCA_FLOWER_KEY_FLAGS_MASK]) {
957
0
        key->flags = ntohl(nl_attr_get_be32(attrs[TCA_FLOWER_KEY_FLAGS]));
958
0
        mask->flags =
959
0
                ntohl(nl_attr_get_be32(attrs[TCA_FLOWER_KEY_FLAGS_MASK]));
960
0
    }
961
962
0
    if (attrs[TCA_FLOWER_KEY_IPV4_SRC_MASK]) {
963
0
        key->ipv4.ipv4_src =
964
0
            nl_attr_get_be32(attrs[TCA_FLOWER_KEY_IPV4_SRC]);
965
0
        mask->ipv4.ipv4_src =
966
0
            nl_attr_get_be32(attrs[TCA_FLOWER_KEY_IPV4_SRC_MASK]);
967
0
    }
968
0
    if (attrs[TCA_FLOWER_KEY_IPV4_DST_MASK]) {
969
0
        key->ipv4.ipv4_dst =
970
0
            nl_attr_get_be32(attrs[TCA_FLOWER_KEY_IPV4_DST]);
971
0
        mask->ipv4.ipv4_dst =
972
0
            nl_attr_get_be32(attrs[TCA_FLOWER_KEY_IPV4_DST_MASK]);
973
0
    }
974
0
    if (attrs[TCA_FLOWER_KEY_IPV6_SRC_MASK]) {
975
0
        struct nlattr *attr = attrs[TCA_FLOWER_KEY_IPV6_SRC];
976
0
        struct nlattr *attr_mask = attrs[TCA_FLOWER_KEY_IPV6_SRC_MASK];
977
978
0
        key->ipv6.ipv6_src = nl_attr_get_in6_addr(attr);
979
0
        mask->ipv6.ipv6_src = nl_attr_get_in6_addr(attr_mask);
980
0
    }
981
0
    if (attrs[TCA_FLOWER_KEY_IPV6_DST_MASK]) {
982
0
        struct nlattr *attr = attrs[TCA_FLOWER_KEY_IPV6_DST];
983
0
        struct nlattr *attr_mask = attrs[TCA_FLOWER_KEY_IPV6_DST_MASK];
984
985
0
        key->ipv6.ipv6_dst = nl_attr_get_in6_addr(attr);
986
0
        mask->ipv6.ipv6_dst = nl_attr_get_in6_addr(attr_mask);
987
0
    }
988
989
0
    if (ip_proto == IPPROTO_TCP) {
990
0
        if (attrs[TCA_FLOWER_KEY_TCP_SRC_MASK]) {
991
0
            key->tcp_src =
992
0
                nl_attr_get_be16(attrs[TCA_FLOWER_KEY_TCP_SRC]);
993
0
            mask->tcp_src =
994
0
                nl_attr_get_be16(attrs[TCA_FLOWER_KEY_TCP_SRC_MASK]);
995
0
        }
996
0
        if (attrs[TCA_FLOWER_KEY_TCP_DST_MASK]) {
997
0
            key->tcp_dst =
998
0
                nl_attr_get_be16(attrs[TCA_FLOWER_KEY_TCP_DST]);
999
0
            mask->tcp_dst =
1000
0
                nl_attr_get_be16(attrs[TCA_FLOWER_KEY_TCP_DST_MASK]);
1001
0
        }
1002
0
        if (attrs[TCA_FLOWER_KEY_TCP_FLAGS_MASK]) {
1003
0
            key->tcp_flags =
1004
0
                nl_attr_get_be16(attrs[TCA_FLOWER_KEY_TCP_FLAGS]);
1005
0
            mask->tcp_flags =
1006
0
                nl_attr_get_be16(attrs[TCA_FLOWER_KEY_TCP_FLAGS_MASK]);
1007
0
        }
1008
0
    } else if (ip_proto == IPPROTO_UDP) {
1009
0
        if (attrs[TCA_FLOWER_KEY_UDP_SRC_MASK]) {
1010
0
            key->udp_src = nl_attr_get_be16(attrs[TCA_FLOWER_KEY_UDP_SRC]);
1011
0
            mask->udp_src =
1012
0
                nl_attr_get_be16(attrs[TCA_FLOWER_KEY_UDP_SRC_MASK]);
1013
0
        }
1014
0
        if (attrs[TCA_FLOWER_KEY_UDP_DST_MASK]) {
1015
0
            key->udp_dst = nl_attr_get_be16(attrs[TCA_FLOWER_KEY_UDP_DST]);
1016
0
            mask->udp_dst =
1017
0
                nl_attr_get_be16(attrs[TCA_FLOWER_KEY_UDP_DST_MASK]);
1018
0
        }
1019
0
    } else if (ip_proto == IPPROTO_SCTP) {
1020
0
        if (attrs[TCA_FLOWER_KEY_SCTP_SRC_MASK]) {
1021
0
            key->sctp_src = nl_attr_get_be16(attrs[TCA_FLOWER_KEY_SCTP_SRC]);
1022
0
            mask->sctp_src =
1023
0
                nl_attr_get_be16(attrs[TCA_FLOWER_KEY_SCTP_SRC_MASK]);
1024
0
        }
1025
0
        if (attrs[TCA_FLOWER_KEY_SCTP_DST_MASK]) {
1026
0
            key->sctp_dst = nl_attr_get_be16(attrs[TCA_FLOWER_KEY_SCTP_DST]);
1027
0
            mask->sctp_dst =
1028
0
                nl_attr_get_be16(attrs[TCA_FLOWER_KEY_SCTP_DST_MASK]);
1029
0
        }
1030
0
    } else if (ip_proto == IPPROTO_ICMP) {
1031
0
        if (attrs[TCA_FLOWER_KEY_ICMPV4_CODE_MASK]) {
1032
0
            key->icmp_code =
1033
0
               nl_attr_get_u8(attrs[TCA_FLOWER_KEY_ICMPV4_CODE]);
1034
0
            mask->icmp_code =
1035
0
                nl_attr_get_u8(attrs[TCA_FLOWER_KEY_ICMPV4_CODE_MASK]);
1036
0
        }
1037
0
        if (attrs[TCA_FLOWER_KEY_ICMPV4_TYPE_MASK]) {
1038
0
            key->icmp_type = nl_attr_get_u8(attrs[TCA_FLOWER_KEY_ICMPV4_TYPE]);
1039
0
            mask->icmp_type =
1040
0
                nl_attr_get_u8(attrs[TCA_FLOWER_KEY_ICMPV4_TYPE_MASK]);
1041
0
        }
1042
0
    } else if (ip_proto == IPPROTO_ICMPV6) {
1043
0
        if (attrs[TCA_FLOWER_KEY_ICMPV6_CODE_MASK]) {
1044
0
            key->icmp_code = nl_attr_get_u8(attrs[TCA_FLOWER_KEY_ICMPV6_CODE]);
1045
0
            mask->icmp_code =
1046
0
                 nl_attr_get_u8(attrs[TCA_FLOWER_KEY_ICMPV6_CODE_MASK]);
1047
0
        }
1048
0
        if (attrs[TCA_FLOWER_KEY_ICMPV6_TYPE_MASK]) {
1049
0
            key->icmp_type = nl_attr_get_u8(attrs[TCA_FLOWER_KEY_ICMPV6_TYPE]);
1050
0
            mask->icmp_type =
1051
0
                nl_attr_get_u8(attrs[TCA_FLOWER_KEY_ICMPV6_TYPE_MASK]);
1052
0
        }
1053
0
    }
1054
1055
0
    if (attrs[TCA_FLOWER_KEY_IP_TTL_MASK]) {
1056
0
        key->ip_ttl = nl_attr_get_u8(attrs[TCA_FLOWER_KEY_IP_TTL]);
1057
0
        mask->ip_ttl = nl_attr_get_u8(attrs[TCA_FLOWER_KEY_IP_TTL_MASK]);
1058
0
    }
1059
1060
0
    if (attrs[TCA_FLOWER_KEY_IP_TOS_MASK]) {
1061
0
        key->ip_tos = nl_attr_get_u8(attrs[TCA_FLOWER_KEY_IP_TOS]);
1062
0
        mask->ip_tos = nl_attr_get_u8(attrs[TCA_FLOWER_KEY_IP_TOS_MASK]);
1063
0
    }
1064
1065
0
    nl_parse_flower_ct_match(attrs, flower);
1066
0
}
1067
1068
static enum tc_offloaded_state
1069
nl_get_flower_offloaded_state(struct nlattr **attrs)
1070
0
{
1071
0
    uint32_t flower_flags = 0;
1072
1073
0
    if (attrs[TCA_FLOWER_FLAGS]) {
1074
0
        flower_flags = nl_attr_get_u32(attrs[TCA_FLOWER_FLAGS]);
1075
0
        if (flower_flags & TCA_CLS_FLAGS_NOT_IN_HW) {
1076
0
            return TC_OFFLOADED_STATE_NOT_IN_HW;
1077
0
        } else if (flower_flags & TCA_CLS_FLAGS_IN_HW) {
1078
0
            return TC_OFFLOADED_STATE_IN_HW;
1079
0
        }
1080
0
    }
1081
0
    return TC_OFFLOADED_STATE_UNDEFINED;
1082
0
}
1083
1084
static void
1085
nl_parse_flower_flags(struct nlattr **attrs, struct tc_flower *flower)
1086
0
{
1087
0
    flower->offloaded_state = nl_get_flower_offloaded_state(attrs);
1088
0
}
1089
1090
static void
1091
nl_parse_action_pc(uint32_t action_pc, struct tc_action *action)
1092
0
{
1093
0
    if (action_pc == TC_ACT_STOLEN) {
1094
0
        action->jump_action = JUMP_ACTION_STOP;
1095
0
    } else if (action_pc & TC_ACT_JUMP) {
1096
0
        action->jump_action = action_pc & TC_ACT_EXT_VAL_MASK;
1097
0
    } else {
1098
0
        action->jump_action = 0;
1099
0
    }
1100
0
}
1101
1102
static const struct nl_policy pedit_policy[] = {
1103
            [TCA_PEDIT_PARMS_EX] = { .type = NL_A_UNSPEC,
1104
                                     .min_len = sizeof(struct tc_pedit),
1105
                                     .optional = false, },
1106
            [TCA_PEDIT_KEYS_EX]   = { .type = NL_A_NESTED,
1107
                                      .optional = false, },
1108
};
1109
1110
static int
1111
nl_parse_act_pedit(struct nlattr *options, struct tc_flower *flower)
1112
0
{
1113
0
    struct tc_action *action = &flower->actions[flower->action_count++];
1114
0
    struct nlattr *pe_attrs[ARRAY_SIZE(pedit_policy)];
1115
0
    const struct tc_pedit *pe;
1116
0
    const struct tc_pedit_key *keys;
1117
0
    const struct nlattr *nla, *keys_ex, *ex_type;
1118
0
    const void *keys_attr;
1119
0
    char *rewrite_key = (void *) &action->rewrite.key;
1120
0
    char *rewrite_mask = (void *) &action->rewrite.mask;
1121
0
    size_t keys_ex_size, left;
1122
0
    int type, i = 0, err;
1123
1124
0
    if (!nl_parse_nested(options, pedit_policy, pe_attrs,
1125
0
                         ARRAY_SIZE(pedit_policy))) {
1126
0
        VLOG_ERR_RL(&error_rl, "failed to parse pedit action options");
1127
0
        return EPROTO;
1128
0
    }
1129
1130
0
    pe = nl_attr_get_unspec(pe_attrs[TCA_PEDIT_PARMS_EX], sizeof *pe);
1131
0
    keys = pe->keys;
1132
0
    keys_attr = pe_attrs[TCA_PEDIT_KEYS_EX];
1133
0
    keys_ex = nl_attr_get(keys_attr);
1134
0
    keys_ex_size = nl_attr_get_size(keys_attr);
1135
1136
0
    NL_ATTR_FOR_EACH (nla, left, keys_ex, keys_ex_size) {
1137
0
        if (i >= pe->nkeys) {
1138
0
            break;
1139
0
        }
1140
1141
0
        if (nl_attr_type(nla) != TCA_PEDIT_KEY_EX) {
1142
0
            VLOG_ERR_RL(&error_rl, "unable to parse legacy pedit type: %d",
1143
0
                        nl_attr_type(nla));
1144
0
            return EOPNOTSUPP;
1145
0
        }
1146
1147
0
        ex_type = nl_attr_find_nested(nla, TCA_PEDIT_KEY_EX_HTYPE);
1148
0
        if (!ex_type) {
1149
0
            return EOPNOTSUPP;
1150
0
        }
1151
1152
0
        type = nl_attr_get_u16(ex_type);
1153
1154
0
        err = csum_update_flag(flower, type);
1155
0
        if (err) {
1156
0
            return err;
1157
0
        }
1158
1159
0
        for (int j = 0; j < ARRAY_SIZE(flower_pedit_map); j++) {
1160
0
            struct flower_key_to_pedit *m = &flower_pedit_map[j];
1161
0
            int flower_off = m->flower_offset;
1162
0
            int sz = m->size;
1163
0
            int mf = m->offset;
1164
0
            int ef = ROUND_UP(mf, 4);
1165
1166
0
            if (m->htype != type) {
1167
0
               continue;
1168
0
            }
1169
1170
            /* check overlap between current pedit key, which is always
1171
             * 4 bytes (range [off, off + 3]), and a map entry in
1172
             * flower_pedit_map sf = ROUND_DOWN(mf, 4)
1173
             * (range [sf|mf, (mf + sz - 1)|ef]) */
1174
0
            if ((keys->off >= mf && keys->off < mf + sz)
1175
0
                || (keys->off + 3 >= mf && keys->off + 3 < ef)) {
1176
0
                int diff = flower_off + (keys->off - mf);
1177
0
                ovs_be32 *dst = (void *) (rewrite_key + diff);
1178
0
                ovs_be32 *dst_m = (void *) (rewrite_mask + diff);
1179
0
                ovs_be32 mask, mask_word, data_word, val;
1180
0
                uint32_t zero_bits;
1181
1182
0
                mask_word = htonl(ntohl(keys->mask) << m->boundary_shift);
1183
0
                data_word = htonl(ntohl(keys->val) << m->boundary_shift);
1184
0
                mask = ~(mask_word);
1185
1186
0
                if (keys->off < mf) {
1187
0
                    zero_bits = 8 * (mf - keys->off);
1188
0
                    mask &= htonl(UINT32_MAX >> zero_bits);
1189
0
                } else if (keys->off + 4 > mf + m->size) {
1190
0
                    zero_bits = 8 * (keys->off + 4 - mf - m->size);
1191
0
                    mask &= htonl(UINT32_MAX << zero_bits);
1192
0
                }
1193
1194
0
                val = get_unaligned_be32(dst_m);
1195
0
                val |= mask;
1196
0
                put_unaligned_be32(dst_m, val);
1197
1198
0
                val = get_unaligned_be32(dst);
1199
0
                val |= data_word & mask;
1200
0
                put_unaligned_be32(dst, val);
1201
0
            }
1202
0
        }
1203
1204
0
        keys++;
1205
0
        i++;
1206
0
    }
1207
1208
0
    action->type = TC_ACT_PEDIT;
1209
1210
0
    nl_parse_action_pc(pe->action, action);
1211
0
    return 0;
1212
0
}
1213
1214
static const struct nl_policy tunnel_key_policy[] = {
1215
    [TCA_TUNNEL_KEY_PARMS] = { .type = NL_A_UNSPEC,
1216
                               .min_len = sizeof(struct tc_tunnel_key),
1217
                               .optional = false, },
1218
    [TCA_TUNNEL_KEY_ENC_IPV4_SRC] = { .type = NL_A_U32, .optional = true, },
1219
    [TCA_TUNNEL_KEY_ENC_IPV4_DST] = { .type = NL_A_U32, .optional = true, },
1220
    [TCA_TUNNEL_KEY_ENC_IPV6_SRC] = { .type = NL_A_UNSPEC,
1221
                                      .min_len = sizeof(struct in6_addr),
1222
                                      .optional = true, },
1223
    [TCA_TUNNEL_KEY_ENC_IPV6_DST] = { .type = NL_A_UNSPEC,
1224
                                      .min_len = sizeof(struct in6_addr),
1225
                                      .optional = true, },
1226
    [TCA_TUNNEL_KEY_ENC_KEY_ID] = { .type = NL_A_U32, .optional = true, },
1227
    [TCA_TUNNEL_KEY_ENC_DST_PORT] = { .type = NL_A_U16, .optional = true, },
1228
    [TCA_TUNNEL_KEY_ENC_TOS] = { .type = NL_A_U8, .optional = true, },
1229
    [TCA_TUNNEL_KEY_ENC_TTL] = { .type = NL_A_U8, .optional = true, },
1230
    [TCA_TUNNEL_KEY_ENC_OPTS] = { .type = NL_A_NESTED, .optional = true, },
1231
    [TCA_TUNNEL_KEY_NO_CSUM] = { .type = NL_A_U8, .optional = true, },
1232
    [TCA_TUNNEL_KEY_NO_FRAG] = { .type = NL_A_FLAG, .optional = true, },
1233
};
1234
1235
static int
1236
nl_parse_act_geneve_opts(const struct nlattr *in_nlattr,
1237
                         struct tc_action *action)
1238
0
{
1239
0
    struct geneve_opt *opt = NULL;
1240
0
    const struct ofpbuf *msg;
1241
0
    uint16_t last_opt_type;
1242
0
    struct nlattr *nla;
1243
0
    struct ofpbuf buf;
1244
0
    size_t left;
1245
0
    int cnt;
1246
1247
0
    nl_attr_get_nested(in_nlattr, &buf);
1248
0
    msg = &buf;
1249
1250
0
    last_opt_type = TCA_TUNNEL_KEY_ENC_OPT_GENEVE_UNSPEC;
1251
0
    cnt = 0;
1252
0
    NL_ATTR_FOR_EACH (nla, left, ofpbuf_at(msg, 0, 0), msg->size) {
1253
0
        uint16_t type = nl_attr_type(nla);
1254
1255
0
        switch (type) {
1256
0
        case TCA_TUNNEL_KEY_ENC_OPT_GENEVE_CLASS:
1257
0
            if (cnt && last_opt_type != TCA_TUNNEL_KEY_ENC_OPT_GENEVE_DATA) {
1258
0
                VLOG_ERR_RL(&error_rl,
1259
0
                            "failed to parse action geneve options class");
1260
0
                return EINVAL;
1261
0
            }
1262
1263
0
            opt = &action->encap.data.opts.gnv[cnt];
1264
0
            opt->opt_class = nl_attr_get_be16(nla);
1265
0
            cnt += sizeof(struct geneve_opt) / 4;
1266
0
            action->encap.data.present.len += sizeof(struct geneve_opt);
1267
0
            last_opt_type = TCA_TUNNEL_KEY_ENC_OPT_GENEVE_CLASS;
1268
0
            break;
1269
0
        case TCA_TUNNEL_KEY_ENC_OPT_GENEVE_TYPE:
1270
0
            if (last_opt_type != TCA_TUNNEL_KEY_ENC_OPT_GENEVE_CLASS) {
1271
0
                VLOG_ERR_RL(&error_rl,
1272
0
                            "failed to parse action geneve options type");
1273
0
                return EINVAL;
1274
0
            }
1275
1276
0
            opt->type = nl_attr_get_u8(nla);
1277
0
            last_opt_type = TCA_TUNNEL_KEY_ENC_OPT_GENEVE_TYPE;
1278
0
            break;
1279
0
        case TCA_TUNNEL_KEY_ENC_OPT_GENEVE_DATA:
1280
0
            if (last_opt_type != TCA_TUNNEL_KEY_ENC_OPT_GENEVE_TYPE) {
1281
0
                VLOG_ERR_RL(&error_rl,
1282
0
                            "failed to parse action geneve options data");
1283
0
                return EINVAL;
1284
0
            }
1285
1286
0
            opt->length = nl_attr_get_size(nla) / 4;
1287
0
            memcpy(opt + 1, nl_attr_get_unspec(nla, 1), opt->length * 4);
1288
0
            cnt += opt->length;
1289
0
            action->encap.data.present.len += opt->length * 4;
1290
0
            last_opt_type = TCA_TUNNEL_KEY_ENC_OPT_GENEVE_DATA;
1291
0
            break;
1292
0
        }
1293
0
    }
1294
1295
0
    if (last_opt_type != TCA_TUNNEL_KEY_ENC_OPT_GENEVE_DATA) {
1296
0
        VLOG_ERR_RL(&error_rl,
1297
0
                   "failed to parse action geneve options without data");
1298
0
        return EINVAL;
1299
0
    }
1300
1301
0
    return 0;
1302
0
}
1303
1304
static int
1305
nl_parse_act_vxlan_opts(struct nlattr *in_nlattr, struct tc_action *action)
1306
0
{
1307
0
    const struct ofpbuf *msg;
1308
0
    struct nlattr *nla;
1309
0
    struct ofpbuf buf;
1310
0
    size_t left;
1311
1312
0
    nl_attr_get_nested(in_nlattr, &buf);
1313
0
    msg = &buf;
1314
1315
0
    NL_ATTR_FOR_EACH (nla, left, ofpbuf_at(msg, 0, 0), msg->size) {
1316
0
        uint16_t type = nl_attr_type(nla);
1317
0
        int32_t gbp_raw;
1318
1319
0
        switch (type) {
1320
0
        case TCA_FLOWER_KEY_ENC_OPT_VXLAN_GBP:
1321
0
            gbp_raw = nl_attr_get_u32(nla);
1322
0
            odp_decode_gbp_raw(gbp_raw, &action->encap.gbp.id,
1323
0
                               &action->encap.gbp.flags);
1324
0
            action->encap.gbp.id_present = true;
1325
1326
0
            break;
1327
0
        }
1328
0
    }
1329
1330
0
    return 0;
1331
0
}
1332
1333
static int
1334
nl_parse_act_tunnel_opts(struct nlattr *options, struct tc_action *action)
1335
0
{
1336
0
    const struct ofpbuf *msg;
1337
0
    struct nlattr *nla;
1338
0
    struct ofpbuf buf;
1339
0
    size_t left;
1340
0
    int err;
1341
1342
0
    if (!options) {
1343
0
        return 0;
1344
0
    }
1345
1346
0
    nl_attr_get_nested(options, &buf);
1347
0
    msg = &buf;
1348
1349
0
    NL_ATTR_FOR_EACH (nla, left, ofpbuf_at(msg, 0, 0), msg->size) {
1350
0
        uint16_t type = nl_attr_type(nla);
1351
0
        switch (type) {
1352
0
        case TCA_TUNNEL_KEY_ENC_OPTS_GENEVE:
1353
0
            err = nl_parse_act_geneve_opts(nla, action);
1354
0
            if (err) {
1355
0
                return err;
1356
0
            }
1357
0
            break;
1358
0
        case TCA_TUNNEL_KEY_ENC_OPTS_VXLAN:
1359
0
            err = nl_parse_act_vxlan_opts(nla, action);
1360
0
            if (err) {
1361
0
                return err;
1362
0
            }
1363
0
            break;
1364
0
        }
1365
0
    }
1366
1367
0
    return 0;
1368
0
}
1369
1370
static int
1371
nl_parse_act_tunnel_key(struct nlattr *options, struct tc_flower *flower)
1372
0
{
1373
0
    struct nlattr *tun_attrs[ARRAY_SIZE(tunnel_key_policy)];
1374
0
    const struct nlattr *tun_parms;
1375
0
    const struct tc_tunnel_key *tun;
1376
0
    struct tc_action *action;
1377
0
    int err;
1378
1379
0
    if (!nl_parse_nested(options, tunnel_key_policy, tun_attrs,
1380
0
                ARRAY_SIZE(tunnel_key_policy))) {
1381
0
        VLOG_ERR_RL(&error_rl, "failed to parse tunnel_key action options");
1382
0
        return EPROTO;
1383
0
    }
1384
1385
0
    tun_parms = tun_attrs[TCA_TUNNEL_KEY_PARMS];
1386
0
    tun = nl_attr_get_unspec(tun_parms, sizeof *tun);
1387
0
    if (tun->t_action == TCA_TUNNEL_KEY_ACT_SET) {
1388
0
        struct nlattr *id = tun_attrs[TCA_TUNNEL_KEY_ENC_KEY_ID];
1389
0
        struct nlattr *dst_port = tun_attrs[TCA_TUNNEL_KEY_ENC_DST_PORT];
1390
0
        struct nlattr *ipv4_src = tun_attrs[TCA_TUNNEL_KEY_ENC_IPV4_SRC];
1391
0
        struct nlattr *ipv4_dst = tun_attrs[TCA_TUNNEL_KEY_ENC_IPV4_DST];
1392
0
        struct nlattr *ipv6_src = tun_attrs[TCA_TUNNEL_KEY_ENC_IPV6_SRC];
1393
0
        struct nlattr *ipv6_dst = tun_attrs[TCA_TUNNEL_KEY_ENC_IPV6_DST];
1394
0
        struct nlattr *tos = tun_attrs[TCA_TUNNEL_KEY_ENC_TOS];
1395
0
        struct nlattr *ttl = tun_attrs[TCA_TUNNEL_KEY_ENC_TTL];
1396
0
        struct nlattr *tun_opt = tun_attrs[TCA_TUNNEL_KEY_ENC_OPTS];
1397
0
        struct nlattr *no_csum = tun_attrs[TCA_TUNNEL_KEY_NO_CSUM];
1398
0
        struct nlattr *no_frag = tun_attrs[TCA_TUNNEL_KEY_NO_FRAG];
1399
1400
0
        action = &flower->actions[flower->action_count++];
1401
0
        action->type = TC_ACT_ENCAP;
1402
0
        action->encap.ipv4.ipv4_src = ipv4_src ? nl_attr_get_be32(ipv4_src) : 0;
1403
0
        action->encap.ipv4.ipv4_dst = ipv4_dst ? nl_attr_get_be32(ipv4_dst) : 0;
1404
0
        if (ipv6_src) {
1405
0
            action->encap.ipv6.ipv6_src = nl_attr_get_in6_addr(ipv6_src);
1406
0
        }
1407
0
        if (ipv6_dst) {
1408
0
            action->encap.ipv6.ipv6_dst = nl_attr_get_in6_addr(ipv6_dst);
1409
0
        }
1410
0
        action->encap.id = id ? be32_to_be64(nl_attr_get_be32(id)) : 0;
1411
0
        action->encap.id_present = id ? true : false;
1412
0
        action->encap.tp_dst = dst_port ? nl_attr_get_be16(dst_port) : 0;
1413
0
        action->encap.tos = tos ? nl_attr_get_u8(tos) : 0;
1414
0
        action->encap.ttl = ttl ? nl_attr_get_u8(ttl) : 0;
1415
0
        action->encap.no_csum = no_csum ? nl_attr_get_u8(no_csum) : 0;
1416
0
        action->encap.dont_fragment = no_frag ? true : false;
1417
1418
0
        err = nl_parse_act_tunnel_opts(tun_opt, action);
1419
0
        if (err) {
1420
0
            return err;
1421
0
        }
1422
0
        nl_parse_action_pc(tun->action, action);
1423
0
    } else if (tun->t_action == TCA_TUNNEL_KEY_ACT_RELEASE) {
1424
0
        flower->tunnel = true;
1425
0
    } else {
1426
0
        VLOG_ERR_RL(&error_rl, "unknown tunnel actions: %d, %d",
1427
0
                    tun->action, tun->t_action);
1428
0
        return EINVAL;
1429
0
    }
1430
0
    return 0;
1431
0
}
1432
1433
static const struct nl_policy gact_policy[] = {
1434
    [TCA_GACT_PARMS] = { .type = NL_A_UNSPEC,
1435
                         .min_len = sizeof(struct tc_gact),
1436
                         .optional = false, },
1437
    [TCA_GACT_TM] = { .type = NL_A_UNSPEC,
1438
                      .min_len = sizeof(struct tcf_t),
1439
                      .optional = false, },
1440
};
1441
1442
static int
1443
get_user_hz(void)
1444
0
{
1445
0
    static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER;
1446
0
    static int user_hz = 100;
1447
1448
0
    if (ovsthread_once_start(&once)) {
1449
0
        user_hz = sysconf(_SC_CLK_TCK);
1450
0
        ovsthread_once_done(&once);
1451
0
    }
1452
1453
0
    return user_hz;
1454
0
}
1455
1456
static void
1457
nl_parse_tcf(const struct tcf_t *tm, struct tc_flower *flower)
1458
0
{
1459
0
    uint64_t lastused;
1460
1461
    /* On creation both tm->install and tm->lastuse are set to jiffies
1462
     * by the kernel. So if both values are the same, the flow has not been
1463
     * used yet.
1464
     *
1465
     * Note that tm->firstuse can not be used due to some kernel bug, i.e.,
1466
     * hardware offloaded flows do not update tm->firstuse. */
1467
0
    if (tm->lastuse == tm->install) {
1468
0
        lastused = 0;
1469
0
    } else {
1470
0
        lastused = time_msec() - (tm->lastuse * 1000 / get_user_hz());
1471
0
    }
1472
1473
0
    if (flower->lastused < lastused) {
1474
0
        flower->lastused = lastused;
1475
0
    }
1476
0
}
1477
1478
static int
1479
nl_parse_act_gact(struct nlattr *options, struct tc_flower *flower)
1480
0
{
1481
0
    struct nlattr *gact_attrs[ARRAY_SIZE(gact_policy)];
1482
0
    const struct tc_gact *p;
1483
0
    struct nlattr *gact_parms;
1484
0
    struct tc_action *action;
1485
0
    struct tcf_t tm;
1486
1487
0
    if (!nl_parse_nested(options, gact_policy, gact_attrs,
1488
0
                         ARRAY_SIZE(gact_policy))) {
1489
0
        VLOG_ERR_RL(&error_rl, "failed to parse gact action options");
1490
0
        return EPROTO;
1491
0
    }
1492
1493
0
    gact_parms = gact_attrs[TCA_GACT_PARMS];
1494
0
    p = nl_attr_get_unspec(gact_parms, sizeof *p);
1495
1496
0
    if (TC_ACT_EXT_CMP(p->action, TC_ACT_GOTO_CHAIN)) {
1497
0
        action = &flower->actions[flower->action_count++];
1498
0
        action->chain = p->action & TC_ACT_EXT_VAL_MASK;
1499
0
        action->type = TC_ACT_GOTO;
1500
0
        nl_parse_action_pc(p->action, action);
1501
0
    } else if (p->action != TC_ACT_SHOT) {
1502
0
        VLOG_ERR_RL(&error_rl, "unknown gact action: %d", p->action);
1503
0
        return EINVAL;
1504
0
    }
1505
1506
0
    memcpy(&tm, nl_attr_get_unspec(gact_attrs[TCA_GACT_TM], sizeof tm),
1507
0
           sizeof tm);
1508
0
    nl_parse_tcf(&tm, flower);
1509
1510
0
    return 0;
1511
0
}
1512
1513
static const struct nl_policy police_policy[] = {
1514
    [TCA_POLICE_TBF] = { .type = NL_A_UNSPEC,
1515
                         .min_len = sizeof(struct tc_police),
1516
                         .optional = false, },
1517
    [TCA_POLICE_RATE] = { .type = NL_A_UNSPEC,
1518
                          .min_len = 1024,
1519
                          .optional = true, },
1520
    [TCA_POLICE_RATE64] = { .type = NL_A_U32,
1521
                            .optional = true, },
1522
    [TCA_POLICE_PEAKRATE] = { .type = NL_A_UNSPEC,
1523
                              .min_len = 1024,
1524
                              .optional = true, },
1525
    [TCA_POLICE_AVRATE] = { .type = NL_A_U32,
1526
                            .optional = true, },
1527
    [TCA_POLICE_RESULT] = { .type = NL_A_U32,
1528
                            .optional = true, },
1529
    [TCA_POLICE_TM] = { .type = NL_A_UNSPEC,
1530
                        .min_len = sizeof(struct tcf_t),
1531
                        .optional = true, },
1532
};
1533
1534
static int
1535
nl_parse_act_police(const struct nlattr *options, struct tc_flower *flower)
1536
0
{
1537
0
    struct nlattr *police_attrs[ARRAY_SIZE(police_policy)] = {};
1538
0
    const struct tc_police *police;
1539
0
    struct nlattr *police_result;
1540
0
    struct tc_action *action;
1541
0
    struct nlattr *police_tm;
1542
0
    struct tcf_t tm;
1543
1544
0
    if (!nl_parse_nested(options, police_policy, police_attrs,
1545
0
                         ARRAY_SIZE(police_policy))) {
1546
0
        VLOG_ERR_RL(&error_rl, "Failed to parse police action options");
1547
0
        return EPROTO;
1548
0
    }
1549
1550
0
    police = nl_attr_get_unspec(police_attrs[TCA_POLICE_TBF], sizeof *police);
1551
0
    action = &flower->actions[flower->action_count++];
1552
1553
0
    police_result = police_attrs[TCA_POLICE_RESULT];
1554
0
    if (police_result && !tc_is_meter_index(police->index)) {
1555
0
        action->type = TC_ACT_POLICE_MTU;
1556
0
        action->police.mtu = police->mtu;
1557
1558
0
        uint32_t action_pc = nl_attr_get_u32(police_result);
1559
0
        if (action_pc & TC_ACT_JUMP) {
1560
0
            action->police.result_jump = action_pc & TC_ACT_EXT_VAL_MASK;
1561
0
        } else {
1562
0
            action->police.result_jump = JUMP_ACTION_STOP;
1563
0
        }
1564
0
    } else {
1565
0
        action->type = TC_ACT_POLICE;
1566
0
        action->police.index = police->index;
1567
0
    }
1568
1569
0
    police_tm = police_attrs[TCA_POLICE_TM];
1570
0
    if (police_tm) {
1571
0
        memcpy(&tm, nl_attr_get_unspec(police_tm, sizeof tm), sizeof tm);
1572
0
        nl_parse_tcf(&tm, flower);
1573
0
    }
1574
1575
0
    nl_parse_action_pc(police->action, action);
1576
0
    return 0;
1577
0
}
1578
1579
static const struct nl_policy mirred_policy[] = {
1580
    [TCA_MIRRED_PARMS] = { .type = NL_A_UNSPEC,
1581
                           .min_len = sizeof(struct tc_mirred),
1582
                           .optional = false, },
1583
    [TCA_MIRRED_TM] = { .type = NL_A_UNSPEC,
1584
                        .min_len = sizeof(struct tcf_t),
1585
                        .optional = false, },
1586
};
1587
1588
static int
1589
nl_parse_act_mirred(struct nlattr *options, struct tc_flower *flower)
1590
0
{
1591
1592
0
    struct nlattr *mirred_attrs[ARRAY_SIZE(mirred_policy)];
1593
0
    const struct tc_mirred *m;
1594
0
    const struct nlattr *mirred_parms;
1595
0
    struct nlattr *mirred_tm;
1596
0
    struct tc_action *action;
1597
0
    struct tcf_t tm;
1598
1599
0
    if (!nl_parse_nested(options, mirred_policy, mirred_attrs,
1600
0
                         ARRAY_SIZE(mirred_policy))) {
1601
0
        VLOG_ERR_RL(&error_rl, "failed to parse mirred action options");
1602
0
        return EPROTO;
1603
0
    }
1604
1605
0
    mirred_parms = mirred_attrs[TCA_MIRRED_PARMS];
1606
0
    m = nl_attr_get_unspec(mirred_parms, sizeof *m);
1607
1608
0
    if (m->eaction != TCA_EGRESS_REDIR && m->eaction != TCA_EGRESS_MIRROR &&
1609
0
        m->eaction != TCA_INGRESS_REDIR && m->eaction != TCA_INGRESS_MIRROR) {
1610
0
        VLOG_ERR_RL(&error_rl, "unknown mirred action: %d, %d, %d",
1611
0
                    m->action, m->eaction, m->ifindex);
1612
0
        return EINVAL;
1613
0
    }
1614
1615
0
    action = &flower->actions[flower->action_count++];
1616
0
    action->out.ifindex_out = m->ifindex;
1617
0
    if (m->eaction == TCA_INGRESS_REDIR || m->eaction == TCA_INGRESS_MIRROR) {
1618
0
        action->out.ingress = true;
1619
0
    } else {
1620
0
        action->out.ingress = false;
1621
0
    }
1622
0
    action->type = TC_ACT_OUTPUT;
1623
1624
0
    mirred_tm = mirred_attrs[TCA_MIRRED_TM];
1625
0
    memcpy(&tm, nl_attr_get_unspec(mirred_tm, sizeof tm), sizeof tm);
1626
1627
0
    nl_parse_tcf(&tm, flower);
1628
0
    nl_parse_action_pc(m->action, action);
1629
0
    return 0;
1630
0
}
1631
1632
static const struct nl_policy ct_policy[] = {
1633
    [TCA_CT_PARMS] = { .type = NL_A_UNSPEC,
1634
                              .min_len = sizeof(struct tc_ct),
1635
                              .optional = false, },
1636
    [TCA_CT_ACTION] = { .type = NL_A_U16,
1637
                         .optional = true, },
1638
    [TCA_CT_ZONE] = { .type = NL_A_U16,
1639
                      .optional = true, },
1640
    [TCA_CT_MARK] = { .type = NL_A_U32,
1641
                       .optional = true, },
1642
    [TCA_CT_MARK_MASK] = { .type = NL_A_U32,
1643
                            .optional = true, },
1644
    [TCA_CT_LABELS] = { .type = NL_A_UNSPEC,
1645
                         .optional = true, },
1646
    [TCA_CT_LABELS_MASK] = { .type = NL_A_UNSPEC,
1647
                              .optional = true, },
1648
    [TCA_CT_NAT_IPV4_MIN] = { .type = NL_A_U32,
1649
                              .optional = true, },
1650
    [TCA_CT_NAT_IPV4_MAX] = { .type = NL_A_U32,
1651
                              .optional = true, },
1652
    [TCA_CT_NAT_IPV6_MIN] = { .min_len = sizeof(struct in6_addr),
1653
                              .type = NL_A_UNSPEC,
1654
                              .optional = true },
1655
    [TCA_CT_NAT_IPV6_MAX] = { .min_len = sizeof(struct in6_addr),
1656
                              .type = NL_A_UNSPEC,
1657
                               .optional = true },
1658
    [TCA_CT_NAT_PORT_MIN] = { .type = NL_A_U16,
1659
                              .optional = true, },
1660
    [TCA_CT_NAT_PORT_MAX] = { .type = NL_A_U16,
1661
                              .optional = true, },
1662
    [TCA_CT_TM] = { .type = NL_A_UNSPEC,
1663
                    .min_len = sizeof(struct tcf_t),
1664
                    .optional = true, },
1665
};
1666
1667
static int
1668
nl_parse_act_ct(struct nlattr *options, struct tc_flower *flower)
1669
0
{
1670
0
    struct nlattr *ct_attrs[ARRAY_SIZE(ct_policy)];
1671
0
    const struct nlattr *ct_parms;
1672
0
    struct tc_action *action;
1673
0
    const struct tc_ct *ct;
1674
0
    uint16_t ct_action = 0;
1675
0
    struct tcf_t tm;
1676
1677
0
    if (!nl_parse_nested(options, ct_policy, ct_attrs,
1678
0
                         ARRAY_SIZE(ct_policy))) {
1679
0
        VLOG_ERR_RL(&error_rl, "failed to parse ct action options");
1680
0
        return EPROTO;
1681
0
    }
1682
1683
0
    ct_parms = ct_attrs[TCA_CT_PARMS];
1684
0
    ct = nl_attr_get_unspec(ct_parms, sizeof *ct);
1685
1686
0
    if (ct_attrs[TCA_CT_ACTION]) {
1687
0
        ct_action = nl_attr_get_u16(ct_attrs[TCA_CT_ACTION]);
1688
0
    }
1689
1690
0
    action = &flower->actions[flower->action_count++];
1691
0
    action->ct.clear = ct_action & TCA_CT_ACT_CLEAR;
1692
0
    if (!action->ct.clear) {
1693
0
        struct nlattr *zone = ct_attrs[TCA_CT_ZONE];
1694
0
        struct nlattr *mark = ct_attrs[TCA_CT_MARK];
1695
0
        struct nlattr *mark_mask = ct_attrs[TCA_CT_MARK_MASK];
1696
0
        struct nlattr *label = ct_attrs[TCA_CT_LABELS];
1697
0
        struct nlattr *label_mask = ct_attrs[TCA_CT_LABELS_MASK];
1698
1699
0
        action->ct.commit = ct_action & TCA_CT_ACT_COMMIT;
1700
0
        action->ct.force = ct_action & TCA_CT_ACT_FORCE;
1701
1702
0
        action->ct.zone = zone ? nl_attr_get_u16(zone) : 0;
1703
0
        action->ct.mark = mark ? nl_attr_get_u32(mark) : 0;
1704
0
        action->ct.mark_mask = mark_mask ? nl_attr_get_u32(mark_mask) : 0;
1705
0
        action->ct.label = label? nl_attr_get_u128(label) : OVS_U128_ZERO;
1706
0
        action->ct.label_mask = label_mask ?
1707
0
                                nl_attr_get_u128(label_mask) : OVS_U128_ZERO;
1708
1709
0
        if (ct_action & TCA_CT_ACT_NAT) {
1710
0
            struct nlattr *ipv4_min = ct_attrs[TCA_CT_NAT_IPV4_MIN];
1711
0
            struct nlattr *ipv4_max = ct_attrs[TCA_CT_NAT_IPV4_MAX];
1712
0
            struct nlattr *ipv6_min = ct_attrs[TCA_CT_NAT_IPV6_MIN];
1713
0
            struct nlattr *ipv6_max = ct_attrs[TCA_CT_NAT_IPV6_MAX];
1714
0
            struct nlattr *port_min = ct_attrs[TCA_CT_NAT_PORT_MIN];
1715
0
            struct nlattr *port_max = ct_attrs[TCA_CT_NAT_PORT_MAX];
1716
1717
0
            action->ct.nat_type = TC_NAT_RESTORE;
1718
0
            if (ct_action & TCA_CT_ACT_NAT_SRC) {
1719
0
                action->ct.nat_type = TC_NAT_SRC;
1720
0
            } else if (ct_action & TCA_CT_ACT_NAT_DST) {
1721
0
                action->ct.nat_type = TC_NAT_DST;
1722
0
            }
1723
1724
0
            if (ipv4_min) {
1725
0
                action->ct.range.ip_family = AF_INET;
1726
0
                action->ct.range.ipv4.min = nl_attr_get_be32(ipv4_min);
1727
0
                if (ipv4_max) {
1728
0
                    ovs_be32 addr = nl_attr_get_be32(ipv4_max);
1729
1730
0
                    if (action->ct.range.ipv4.min != addr) {
1731
0
                        action->ct.range.ipv4.max = addr;
1732
0
                    }
1733
0
                }
1734
0
            } else if (ipv6_min) {
1735
0
                action->ct.range.ip_family = AF_INET6;
1736
0
                action->ct.range.ipv6.min
1737
0
                    = nl_attr_get_in6_addr(ipv6_min);
1738
0
                if (ipv6_max) {
1739
0
                    struct in6_addr addr = nl_attr_get_in6_addr(ipv6_max);
1740
1741
0
                    if (!ipv6_addr_equals(&action->ct.range.ipv6.min, &addr)) {
1742
0
                        action->ct.range.ipv6.max = addr;
1743
0
                    }
1744
0
                }
1745
0
            }
1746
1747
0
            if (port_min) {
1748
0
                action->ct.range.port.min = nl_attr_get_be16(port_min);
1749
0
                if (port_max) {
1750
0
                    action->ct.range.port.max = nl_attr_get_be16(port_max);
1751
0
                    if (action->ct.range.port.min ==
1752
0
                        action->ct.range.port.max) {
1753
0
                        action->ct.range.port.max = 0;
1754
0
                    }
1755
0
                }
1756
0
            }
1757
0
        }
1758
0
    }
1759
0
    action->type = TC_ACT_CT;
1760
1761
0
    if (ct_attrs[TCA_CT_TM]) {
1762
0
        memcpy(&tm, nl_attr_get_unspec(ct_attrs[TCA_CT_TM], sizeof tm),
1763
0
               sizeof tm);
1764
0
        nl_parse_tcf(&tm, flower);
1765
0
    }
1766
0
    nl_parse_action_pc(ct->action, action);
1767
0
    return 0;
1768
0
}
1769
1770
static const struct nl_policy vlan_policy[] = {
1771
    [TCA_VLAN_PARMS] = { .type = NL_A_UNSPEC,
1772
                         .min_len = sizeof(struct tc_vlan),
1773
                         .optional = false, },
1774
    [TCA_VLAN_PUSH_VLAN_ID] = { .type = NL_A_U16, .optional = true, },
1775
    [TCA_VLAN_PUSH_VLAN_PROTOCOL] = { .type = NL_A_U16, .optional = true, },
1776
    [TCA_VLAN_PUSH_VLAN_PRIORITY] = { .type = NL_A_U8, .optional = true, },
1777
};
1778
1779
static int
1780
nl_parse_act_vlan(struct nlattr *options, struct tc_flower *flower)
1781
0
{
1782
0
    struct nlattr *vlan_attrs[ARRAY_SIZE(vlan_policy)];
1783
0
    const struct tc_vlan *v;
1784
0
    const struct nlattr *vlan_parms;
1785
0
    struct tc_action *action;
1786
1787
0
    if (!nl_parse_nested(options, vlan_policy, vlan_attrs,
1788
0
                         ARRAY_SIZE(vlan_policy))) {
1789
0
        VLOG_ERR_RL(&error_rl, "failed to parse vlan action options");
1790
0
        return EPROTO;
1791
0
    }
1792
1793
0
    action = &flower->actions[flower->action_count++];
1794
0
    vlan_parms = vlan_attrs[TCA_VLAN_PARMS];
1795
0
    v = nl_attr_get_unspec(vlan_parms, sizeof *v);
1796
0
    if (v->v_action == TCA_VLAN_ACT_PUSH) {
1797
0
        struct nlattr *vlan_tpid = vlan_attrs[TCA_VLAN_PUSH_VLAN_PROTOCOL];
1798
0
        struct nlattr *vlan_id = vlan_attrs[TCA_VLAN_PUSH_VLAN_ID];
1799
0
        struct nlattr *vlan_prio = vlan_attrs[TCA_VLAN_PUSH_VLAN_PRIORITY];
1800
1801
0
        action->vlan.vlan_push_tpid = nl_attr_get_be16(vlan_tpid);
1802
0
        action->vlan.vlan_push_id = nl_attr_get_u16(vlan_id);
1803
0
        action->vlan.vlan_push_prio = vlan_prio ? nl_attr_get_u8(vlan_prio) : 0;
1804
0
        action->type = TC_ACT_VLAN_PUSH;
1805
0
    } else if (v->v_action == TCA_VLAN_ACT_POP) {
1806
0
        action->type = TC_ACT_VLAN_POP;
1807
0
    } else {
1808
0
        VLOG_ERR_RL(&error_rl, "unknown vlan action: %d, %d",
1809
0
                    v->action, v->v_action);
1810
0
        return EINVAL;
1811
0
    }
1812
1813
0
    nl_parse_action_pc(v->action, action);
1814
0
    return 0;
1815
0
}
1816
1817
static const struct nl_policy mpls_policy[] = {
1818
    [TCA_MPLS_PARMS] = { .type = NL_A_UNSPEC,
1819
                         .min_len = sizeof(struct tc_mpls),
1820
                         .optional = false, },
1821
    [TCA_MPLS_PROTO] = { .type = NL_A_U16, .optional = true, },
1822
    [TCA_MPLS_LABEL] = { .type = NL_A_U32, .optional = true, },
1823
    [TCA_MPLS_TC] = { .type = NL_A_U8, .optional = true, },
1824
    [TCA_MPLS_TTL] = { .type = NL_A_U8, .optional = true, },
1825
    [TCA_MPLS_BOS] = { .type = NL_A_U8, .optional = true, },
1826
};
1827
1828
static int
1829
nl_parse_act_mpls(struct nlattr *options, struct tc_flower *flower)
1830
0
{
1831
0
    struct nlattr *mpls_attrs[ARRAY_SIZE(mpls_policy)];
1832
0
    const struct nlattr *mpls_parms;
1833
0
    struct nlattr *mpls_proto;
1834
0
    struct nlattr *mpls_label;
1835
0
    struct tc_action *action;
1836
0
    const struct tc_mpls *m;
1837
0
    struct nlattr *mpls_ttl;
1838
0
    struct nlattr *mpls_bos;
1839
0
    struct nlattr *mpls_tc;
1840
1841
0
    if (!nl_parse_nested(options, mpls_policy, mpls_attrs,
1842
0
                         ARRAY_SIZE(mpls_policy))) {
1843
0
        VLOG_ERR_RL(&error_rl, "failed to parse mpls action options");
1844
0
        return EPROTO;
1845
0
    }
1846
1847
0
    action = &flower->actions[flower->action_count++];
1848
0
    mpls_parms = mpls_attrs[TCA_MPLS_PARMS];
1849
0
    m = nl_attr_get_unspec(mpls_parms, sizeof *m);
1850
1851
0
    switch (m->m_action) {
1852
0
    case TCA_MPLS_ACT_POP:
1853
0
        mpls_proto = mpls_attrs[TCA_MPLS_PROTO];
1854
0
        if (mpls_proto) {
1855
0
            action->mpls.proto = nl_attr_get_be16(mpls_proto);
1856
0
        }
1857
0
        action->type = TC_ACT_MPLS_POP;
1858
0
        break;
1859
0
    case TCA_MPLS_ACT_PUSH:
1860
0
        mpls_proto = mpls_attrs[TCA_MPLS_PROTO];
1861
0
        if (mpls_proto) {
1862
0
            action->mpls.proto = nl_attr_get_be16(mpls_proto);
1863
0
        }
1864
0
        mpls_label = mpls_attrs[TCA_MPLS_LABEL];
1865
0
        if (mpls_label) {
1866
0
            action->mpls.label = nl_attr_get_u32(mpls_label);
1867
0
        }
1868
0
        mpls_tc = mpls_attrs[TCA_MPLS_TC];
1869
0
        if (mpls_tc) {
1870
0
            action->mpls.tc = nl_attr_get_u8(mpls_tc);
1871
0
        }
1872
0
        mpls_ttl = mpls_attrs[TCA_MPLS_TTL];
1873
0
        if (mpls_ttl) {
1874
0
            action->mpls.ttl = nl_attr_get_u8(mpls_ttl);
1875
0
        }
1876
0
        mpls_bos = mpls_attrs[TCA_MPLS_BOS];
1877
0
        if (mpls_bos) {
1878
0
            action->mpls.bos = nl_attr_get_u8(mpls_bos);
1879
0
        }
1880
0
        action->type = TC_ACT_MPLS_PUSH;
1881
0
        break;
1882
0
    case TCA_MPLS_ACT_MODIFY:
1883
0
        mpls_label = mpls_attrs[TCA_MPLS_LABEL];
1884
0
        if (mpls_label) {
1885
0
            action->mpls.label = nl_attr_get_u32(mpls_label);
1886
0
        }
1887
0
        mpls_tc = mpls_attrs[TCA_MPLS_TC];
1888
0
        if (mpls_tc) {
1889
0
            action->mpls.tc = nl_attr_get_u8(mpls_tc);
1890
0
        }
1891
0
        mpls_ttl = mpls_attrs[TCA_MPLS_TTL];
1892
0
        if (mpls_ttl) {
1893
0
            action->mpls.ttl = nl_attr_get_u8(mpls_ttl);
1894
0
        }
1895
0
        mpls_bos = mpls_attrs[TCA_MPLS_BOS];
1896
0
        if (mpls_bos) {
1897
0
            action->mpls.bos = nl_attr_get_u8(mpls_bos);
1898
0
        }
1899
0
        action->type = TC_ACT_MPLS_SET;
1900
0
        break;
1901
0
    default:
1902
0
        VLOG_ERR_RL(&error_rl, "unknown mpls action: %d, %d",
1903
0
                    m->action, m->m_action);
1904
0
        return EINVAL;
1905
0
    }
1906
1907
0
    nl_parse_action_pc(m->action, action);
1908
0
    return 0;
1909
0
}
1910
1911
static const struct nl_policy csum_policy[] = {
1912
    [TCA_CSUM_PARMS] = { .type = NL_A_UNSPEC,
1913
                         .min_len = sizeof(struct tc_csum),
1914
                         .optional = false, },
1915
};
1916
1917
static int
1918
nl_parse_act_csum(struct nlattr *options, struct tc_flower *flower)
1919
0
{
1920
0
    struct nlattr *csum_attrs[ARRAY_SIZE(csum_policy)];
1921
0
    const struct tc_csum *c;
1922
0
    const struct nlattr *csum_parms;
1923
1924
0
    if (!nl_parse_nested(options, csum_policy, csum_attrs,
1925
0
                         ARRAY_SIZE(csum_policy))) {
1926
0
        VLOG_ERR_RL(&error_rl, "failed to parse csum action options");
1927
0
        return EPROTO;
1928
0
    }
1929
1930
0
    csum_parms = csum_attrs[TCA_CSUM_PARMS];
1931
0
    c = nl_attr_get_unspec(csum_parms, sizeof *c);
1932
1933
    /* sanity checks */
1934
0
    if (c->update_flags != flower->csum_update_flags) {
1935
0
        VLOG_WARN_RL(&error_rl,
1936
0
                     "expected different act csum flags: 0x%x != 0x%x",
1937
0
                     flower->csum_update_flags, c->update_flags);
1938
0
        return EINVAL;
1939
0
    }
1940
0
    flower->csum_update_flags = 0; /* so we know csum was handled */
1941
1942
0
    if (flower->needs_full_ip_proto_mask
1943
0
        && flower->mask.ip_proto != UINT8_MAX) {
1944
0
        VLOG_WARN_RL(&error_rl, "expected full matching on flower ip_proto");
1945
0
        return EINVAL;
1946
0
    }
1947
1948
    /* The action_pc should be set on the previous action. */
1949
0
    if (flower->action_count < TCA_ACT_MAX_NUM) {
1950
0
        struct tc_action *action = &flower->actions[flower->action_count];
1951
1952
0
        nl_parse_action_pc(c->action, action);
1953
0
    }
1954
0
    return 0;
1955
0
}
1956
1957
static const struct nl_policy act_policy[] = {
1958
    [TCA_ACT_KIND] = { .type = NL_A_STRING, .optional = false, },
1959
    [TCA_ACT_COOKIE] = { .type = NL_A_UNSPEC, .optional = true, },
1960
    [TCA_ACT_OPTIONS] = { .type = NL_A_NESTED, .optional = true, },
1961
    [TCA_ACT_STATS] = { .type = NL_A_NESTED, .optional = false, },
1962
};
1963
1964
static int
1965
nl_parse_action_stats(struct nlattr *act_stats,
1966
                      struct ovs_flow_stats *stats_sw,
1967
                      struct ovs_flow_stats *stats_hw,
1968
                      struct ovs_flow_stats *stats_dropped)
1969
0
{
1970
0
    struct tc_flow_stats s_sw = {0}, s_hw = {0};
1971
0
    const struct gnet_stats_queue *qs = NULL;
1972
0
    uint16_t prev_type = __TCA_STATS_MAX;
1973
0
    const struct nlattr *nla;
1974
0
    unsigned int seen = 0;
1975
0
    size_t left;
1976
1977
    /* Cannot use nl_parse_nested due to duplicate attributes. */
1978
0
    NL_NESTED_FOR_EACH (nla, left, act_stats) {
1979
0
        struct gnet_stats_basic stats_basic;
1980
0
        uint16_t type = nl_attr_type(nla);
1981
1982
0
        seen |= 1 << type;
1983
1984
0
        switch (type) {
1985
0
        case TCA_STATS_BASIC:
1986
0
            memcpy(&stats_basic, nl_attr_get_unspec(nla, sizeof stats_basic),
1987
0
                   sizeof stats_basic);
1988
0
            s_sw.n_packets = stats_basic.packets;
1989
0
            s_sw.n_bytes = stats_basic.bytes;
1990
0
            break;
1991
1992
0
        case TCA_STATS_BASIC_HW:
1993
0
            memcpy(&stats_basic, nl_attr_get_unspec(nla, sizeof stats_basic),
1994
0
                   sizeof stats_basic);
1995
0
            s_hw.n_packets = stats_basic.packets;
1996
0
            s_hw.n_bytes = stats_basic.bytes;
1997
0
            break;
1998
1999
0
        case TCA_STATS_QUEUE:
2000
0
            qs = nl_attr_get_unspec(nla, sizeof *qs);
2001
0
            break;
2002
2003
0
        case TCA_STATS_PKT64:
2004
0
            if (prev_type == TCA_STATS_BASIC) {
2005
0
                s_sw.n_packets = nl_attr_get_u64(nla);
2006
0
            } else if (prev_type == TCA_STATS_BASIC_HW) {
2007
0
                s_hw.n_packets = nl_attr_get_u64(nla);
2008
0
            } else {
2009
0
                goto err;
2010
0
            }
2011
0
            break;
2012
2013
0
        default:
2014
0
            break;
2015
0
        }
2016
0
        prev_type = type;
2017
0
    }
2018
2019
0
    if (!(seen & (1 << TCA_STATS_BASIC))) {
2020
0
        goto err;
2021
0
    }
2022
2023
0
    if (seen & (1 << TCA_STATS_BASIC_HW)) {
2024
0
        s_sw.n_packets = s_sw.n_packets - s_hw.n_packets;
2025
0
        s_sw.n_bytes = s_sw.n_bytes - s_hw.n_bytes;
2026
2027
0
        if (s_hw.n_packets > get_32aligned_u64(&stats_hw->n_packets)) {
2028
0
            put_32aligned_u64(&stats_hw->n_packets, s_hw.n_packets);
2029
0
            put_32aligned_u64(&stats_hw->n_bytes, s_hw.n_bytes);
2030
0
        }
2031
0
    }
2032
2033
0
    if (s_sw.n_packets > get_32aligned_u64(&stats_sw->n_packets)) {
2034
0
        put_32aligned_u64(&stats_sw->n_packets, s_sw.n_packets);
2035
0
        put_32aligned_u64(&stats_sw->n_bytes, s_sw.n_bytes);
2036
0
    }
2037
2038
0
    if (stats_dropped && qs) {
2039
0
        put_32aligned_u64(&stats_dropped->n_packets, qs->drops);
2040
0
    }
2041
2042
0
    return 0;
2043
2044
0
err:
2045
0
    VLOG_ERR_RL(&error_rl, "Failed to parse action stats policy");
2046
0
    return EPROTO;
2047
0
}
2048
2049
static int
2050
nl_parse_single_action(struct nlattr *action, struct tc_flower *flower,
2051
                       bool terse, bool *csum)
2052
0
{
2053
0
    struct nlattr *act_options;
2054
0
    struct nlattr *act_cookie;
2055
0
    const char *act_kind;
2056
0
    struct nlattr *action_attrs[ARRAY_SIZE(act_policy)];
2057
0
    int err = 0;
2058
2059
0
    if (!nl_parse_nested(action, act_policy, action_attrs,
2060
0
                         ARRAY_SIZE(act_policy)) ||
2061
0
        (!terse && !action_attrs[TCA_ACT_OPTIONS])) {
2062
0
        VLOG_ERR_RL(&error_rl, "failed to parse single action options");
2063
0
        return EPROTO;
2064
0
    }
2065
2066
0
    *csum = false;
2067
0
    act_kind = nl_attr_get_string(action_attrs[TCA_ACT_KIND]);
2068
0
    act_options = action_attrs[TCA_ACT_OPTIONS];
2069
0
    act_cookie = action_attrs[TCA_ACT_COOKIE];
2070
2071
0
    if (terse) {
2072
        /* Terse dump doesn't provide act options attribute. */
2073
0
    } else if (!strcmp(act_kind, "gact")) {
2074
0
        err = nl_parse_act_gact(act_options, flower);
2075
0
    } else if (!strcmp(act_kind, "mirred")) {
2076
0
        err = nl_parse_act_mirred(act_options, flower);
2077
0
    } else if (!strcmp(act_kind, "vlan")) {
2078
0
        err = nl_parse_act_vlan(act_options, flower);
2079
0
    } else if (!strcmp(act_kind, "mpls")) {
2080
0
        err = nl_parse_act_mpls(act_options, flower);
2081
0
    } else if (!strcmp(act_kind, "tunnel_key")) {
2082
0
        err = nl_parse_act_tunnel_key(act_options, flower);
2083
0
    } else if (!strcmp(act_kind, "pedit")) {
2084
0
        err = nl_parse_act_pedit(act_options, flower);
2085
0
    } else if (!strcmp(act_kind, "csum")) {
2086
0
        nl_parse_act_csum(act_options, flower);
2087
0
        *csum = true;
2088
0
    } else if (!strcmp(act_kind, "skbedit")) {
2089
        /* Added for TC rule only (not in OvS rule) so ignore. */
2090
0
    } else if (!strcmp(act_kind, "ct")) {
2091
0
        nl_parse_act_ct(act_options, flower);
2092
0
    } else if (!strcmp(act_kind, "police")) {
2093
0
        nl_parse_act_police(act_options, flower);
2094
0
    } else {
2095
0
        VLOG_ERR_RL(&error_rl, "unknown tc action kind: %s", act_kind);
2096
0
        err = EINVAL;
2097
0
    }
2098
2099
0
    if (err) {
2100
0
        return err;
2101
0
    }
2102
2103
0
    if (act_cookie) {
2104
0
        flower->act_cookie.data = nl_attr_get(act_cookie);
2105
0
        flower->act_cookie.len = nl_attr_get_size(act_cookie);
2106
0
    }
2107
2108
0
    return nl_parse_action_stats(action_attrs[TCA_ACT_STATS],
2109
0
                                 &flower->stats_sw, &flower->stats_hw, NULL);
2110
0
}
2111
2112
int
2113
tc_parse_action_stats(struct nlattr *action, struct ovs_flow_stats *stats_sw,
2114
                      struct ovs_flow_stats *stats_hw,
2115
                      struct ovs_flow_stats *stats_dropped)
2116
0
{
2117
0
    struct nlattr *action_attrs[ARRAY_SIZE(act_policy)];
2118
2119
0
    if (!nl_parse_nested(action, act_policy, action_attrs,
2120
0
                         ARRAY_SIZE(act_policy))) {
2121
0
        VLOG_ERR_RL(&error_rl, "Failed to parse single action options");
2122
0
        return EPROTO;
2123
0
    }
2124
2125
0
    return nl_parse_action_stats(action_attrs[TCA_ACT_STATS], stats_sw,
2126
0
                                 stats_hw, stats_dropped);
2127
0
}
2128
2129
0
#define TCA_ACT_MIN_PRIO 1
2130
2131
static int
2132
nl_parse_flower_actions(struct nlattr **attrs, struct tc_flower *flower,
2133
                        bool terse)
2134
0
{
2135
0
    const struct nlattr *actions = attrs[TCA_FLOWER_ACT];
2136
0
    static struct nl_policy actions_orders_policy[TCA_ACT_MAX_NUM + 1] = {};
2137
0
    struct nlattr *actions_orders[ARRAY_SIZE(actions_orders_policy)];
2138
0
    const int max_size = ARRAY_SIZE(actions_orders_policy);
2139
0
    int previous_action_count = 0;
2140
0
    bool need_jump_adjust = false;
2141
0
    int jump_adjust = 0;
2142
0
    bool csum = false;
2143
2144
0
    for (int i = TCA_ACT_MIN_PRIO; i < max_size; i++) {
2145
0
        actions_orders_policy[i].type = NL_A_NESTED;
2146
0
        actions_orders_policy[i].optional = true;
2147
0
    }
2148
2149
0
    if (!nl_parse_nested(actions, actions_orders_policy, actions_orders,
2150
0
                         ARRAY_SIZE(actions_orders_policy))) {
2151
0
        VLOG_ERR_RL(&error_rl, "failed to parse flower order of actions");
2152
0
        return EPROTO;
2153
0
    }
2154
2155
0
    for (int i = TCA_ACT_MIN_PRIO; i < max_size; i++) {
2156
0
        if (actions_orders[i]) {
2157
0
            int err;
2158
2159
0
            if (flower->action_count >= TCA_ACT_MAX_NUM) {
2160
0
                VLOG_DBG_RL(&error_rl, "Can only support %d actions", TCA_ACT_MAX_NUM);
2161
0
                return EOPNOTSUPP;
2162
0
            }
2163
0
            err = nl_parse_single_action(actions_orders[i], flower, terse,
2164
0
                                         &csum);
2165
2166
0
            if (flower->action_count == previous_action_count) {
2167
2168
0
                struct tc_action *action;
2169
2170
                /* We had no update on the TC action count, which means
2171
                 * we had a none TC type action. So need to adjust existing
2172
                 * jump offsets. */
2173
0
                jump_adjust++;
2174
2175
0
                if (need_jump_adjust || (csum && flower->action_count > 0)) {
2176
2177
0
                    if (csum && flower->action_count > 0) {
2178
                        /* The csum action is special as it might carry
2179
                         * a jump count for the previous TC_ACT and therefore
2180
                         * should be adjusted with jump_adjust as it got
2181
                         * copied. */
2182
0
                        action = &flower->actions[flower->action_count - 1];
2183
0
                        if (action->jump_action
2184
0
                            && action->jump_action != JUMP_ACTION_STOP) {
2185
0
                            action->jump_action -= (jump_adjust - 1);
2186
0
                        }
2187
0
                    }
2188
2189
0
                    for (int j = 0; j < flower->action_count; j++) {
2190
0
                        action = &flower->actions[j];
2191
2192
0
                        if (action->type == TC_ACT_POLICE_MTU
2193
0
                            && action->police.result_jump != JUMP_ACTION_STOP
2194
0
                            && (action->police.result_jump - 1) >
2195
0
                            flower->action_count) {
2196
2197
0
                            action->police.result_jump--;
2198
0
                        }
2199
2200
0
                        if (action->jump_action
2201
0
                            && action->jump_action != JUMP_ACTION_STOP
2202
0
                            && (action->jump_action - 1) >
2203
0
                            flower->action_count) {
2204
2205
0
                            action->jump_action--;
2206
0
                        }
2207
0
                    }
2208
0
                }
2209
0
            } else {
2210
0
                struct tc_action *action;
2211
2212
0
                action = &flower->actions[previous_action_count];
2213
0
                if (action->type == TC_ACT_POLICE_MTU &&
2214
0
                    action->police.result_jump != JUMP_ACTION_STOP) {
2215
0
                    action->police.result_jump -= jump_adjust;
2216
0
                    need_jump_adjust = true;
2217
0
                }
2218
2219
0
                if (action->jump_action
2220
0
                    && action->jump_action != JUMP_ACTION_STOP) {
2221
0
                    action->jump_action -= jump_adjust;
2222
0
                    need_jump_adjust = true;
2223
0
                }
2224
2225
0
                previous_action_count = flower->action_count;
2226
0
            }
2227
2228
0
            if (err) {
2229
0
                return err;
2230
0
            }
2231
0
        }
2232
0
    }
2233
2234
0
    if (flower->csum_update_flags) {
2235
0
        VLOG_WARN_RL(&error_rl,
2236
0
                     "expected act csum with flags: 0x%x",
2237
0
                     flower->csum_update_flags);
2238
0
        return EINVAL;
2239
0
    }
2240
2241
0
    return 0;
2242
0
}
2243
2244
static int
2245
nl_parse_flower_options(struct nlattr *nl_options, struct tc_flower *flower,
2246
                        bool terse)
2247
0
{
2248
0
    struct nlattr *attrs[ARRAY_SIZE(tca_flower_policy)];
2249
0
    int err;
2250
2251
0
    if (terse) {
2252
0
        if (!nl_parse_nested(nl_options, tca_flower_terse_policy,
2253
0
                             attrs, ARRAY_SIZE(tca_flower_terse_policy))) {
2254
0
            VLOG_ERR_RL(&error_rl, "failed to parse flower classifier terse options");
2255
0
            return EPROTO;
2256
0
        }
2257
0
        goto skip_flower_opts;
2258
0
    }
2259
2260
0
    if (!nl_parse_nested(nl_options, tca_flower_policy,
2261
0
                         attrs, ARRAY_SIZE(tca_flower_policy))) {
2262
0
        VLOG_ERR_RL(&error_rl, "failed to parse flower classifier options");
2263
0
        return EPROTO;
2264
0
    }
2265
2266
0
    nl_parse_flower_eth(attrs, flower);
2267
0
    nl_parse_flower_arp(attrs, flower);
2268
0
    nl_parse_flower_mpls(attrs, flower);
2269
0
    nl_parse_flower_vlan(attrs, flower);
2270
0
    nl_parse_flower_ip(attrs, flower);
2271
0
    err = nl_parse_flower_tunnel(attrs, flower);
2272
0
    if (err) {
2273
0
        return err;
2274
0
    }
2275
2276
0
skip_flower_opts:
2277
0
    nl_parse_flower_flags(attrs, flower);
2278
0
    return nl_parse_flower_actions(attrs, flower, terse);
2279
0
}
2280
2281
int
2282
parse_netlink_to_tc_flower(struct ofpbuf *reply, struct tcf_id *id,
2283
                           struct tc_flower *flower, bool terse)
2284
0
{
2285
0
    struct ofpbuf b = ofpbuf_const_initializer(reply->data, reply->size);
2286
0
    struct nlmsghdr *nlmsg = ofpbuf_try_pull(&b, sizeof *nlmsg);
2287
0
    struct tcmsg *tc = ofpbuf_try_pull(&b, sizeof *tc);
2288
0
    struct nlattr *ta[ARRAY_SIZE(tca_policy)];
2289
0
    const char *kind;
2290
2291
0
    if (!nlmsg || !tc) {
2292
0
        COVERAGE_INC(tc_netlink_malformed_reply);
2293
0
        return EPROTO;
2294
0
    }
2295
2296
0
    memset(flower, 0, sizeof *flower);
2297
2298
0
    flower->key.eth_type = (OVS_FORCE ovs_be16) tc_get_minor(tc->tcm_info);
2299
0
    flower->mask.eth_type = OVS_BE16_MAX;
2300
0
    id->prio = tc_get_major(tc->tcm_info);
2301
0
    id->handle = tc->tcm_handle;
2302
2303
0
    if (id->prio == TC_RESERVED_PRIORITY_POLICE) {
2304
0
        return 0;
2305
0
    }
2306
2307
0
    if (!id->handle) {
2308
0
        return EAGAIN;
2309
0
    }
2310
2311
0
    if (!nl_policy_parse(&b, 0, tca_policy, ta, ARRAY_SIZE(ta))) {
2312
0
        VLOG_ERR_RL(&error_rl, "failed to parse tca policy");
2313
0
        return EPROTO;
2314
0
    }
2315
2316
0
    if (ta[TCA_CHAIN]) {
2317
0
        id->chain = nl_attr_get_u32(ta[TCA_CHAIN]);
2318
0
    }
2319
2320
0
    kind = nl_attr_get_string(ta[TCA_KIND]);
2321
0
    if (strcmp(kind, "flower")) {
2322
0
        VLOG_DBG_ONCE("Unsupported filter: %s", kind);
2323
0
        return EPROTO;
2324
0
    }
2325
2326
0
    return nl_parse_flower_options(ta[TCA_OPTIONS], flower, terse);
2327
0
}
2328
2329
int
2330
parse_netlink_to_tc_chain(struct ofpbuf *reply, uint32_t *chain)
2331
0
{
2332
0
    struct ofpbuf b = ofpbuf_const_initializer(reply->data, reply->size);
2333
0
    struct nlmsghdr *nlmsg = ofpbuf_try_pull(&b, sizeof *nlmsg);
2334
0
    struct tcmsg *tc = ofpbuf_try_pull(&b, sizeof *tc);
2335
0
    struct nlattr *ta[ARRAY_SIZE(tca_chain_policy)];
2336
2337
0
    if (!nlmsg || !tc) {
2338
0
        COVERAGE_INC(tc_netlink_malformed_reply);
2339
0
        return EPROTO;
2340
0
    }
2341
2342
0
    if (!nl_policy_parse(&b, 0, tca_chain_policy, ta, ARRAY_SIZE(ta))) {
2343
0
        VLOG_ERR_RL(&error_rl, "failed to parse tca chain policy");
2344
0
        return EINVAL;
2345
0
    }
2346
2347
0
   *chain = nl_attr_get_u32(ta[TCA_CHAIN]);
2348
2349
0
    return 0;
2350
0
}
2351
2352
int
2353
tc_dump_flower_start(struct tcf_id *id, struct nl_dump *dump, bool terse)
2354
0
{
2355
0
    struct ofpbuf request;
2356
2357
0
    request_from_tcf_id(id, 0, RTM_GETTFILTER, NLM_F_DUMP, &request);
2358
0
    if (terse) {
2359
0
        struct nla_bitfield32 dump_flags = { TCA_DUMP_FLAGS_TERSE,
2360
0
                                             TCA_DUMP_FLAGS_TERSE };
2361
2362
0
        nl_msg_put_unspec(&request, TCA_DUMP_FLAGS, &dump_flags,
2363
0
                          sizeof dump_flags);
2364
0
    }
2365
0
    nl_dump_start(dump, NETLINK_ROUTE, &request);
2366
0
    ofpbuf_uninit(&request);
2367
2368
0
    return 0;
2369
0
}
2370
2371
int
2372
tc_dump_tc_chain_start(struct tcf_id *id, struct nl_dump *dump)
2373
0
{
2374
0
    struct ofpbuf request;
2375
2376
0
    request_from_tcf_id(id, 0, RTM_GETCHAIN, NLM_F_DUMP, &request);
2377
0
    nl_dump_start(dump, NETLINK_ROUTE, &request);
2378
0
    ofpbuf_uninit(&request);
2379
2380
0
    return 0;
2381
0
}
2382
2383
int
2384
tc_dump_tc_action_start(char *name, struct nl_dump *dump)
2385
0
{
2386
0
    size_t offset, root_offset;
2387
0
    struct ofpbuf request;
2388
2389
0
    tc_make_action_request(RTM_GETACTION, NLM_F_DUMP, &request);
2390
0
    root_offset = nl_msg_start_nested(&request, TCA_ACT_TAB);
2391
0
    offset = nl_msg_start_nested(&request, 1);
2392
0
    nl_msg_put_string(&request, TCA_ACT_KIND, name);
2393
0
    nl_msg_end_nested(&request, offset);
2394
0
    nl_msg_end_nested(&request, root_offset);
2395
2396
0
    nl_dump_start(dump, NETLINK_ROUTE, &request);
2397
0
    ofpbuf_uninit(&request);
2398
2399
0
    return 0;
2400
0
}
2401
2402
int
2403
parse_netlink_to_tc_policer(struct ofpbuf *reply, uint32_t police_idx[])
2404
0
{
2405
0
    static struct nl_policy actions_orders_policy[TCA_ACT_MAX_PRIO] = {};
2406
0
    struct ofpbuf b = ofpbuf_const_initializer(reply->data, reply->size);
2407
0
    struct nlattr *actions_orders[ARRAY_SIZE(actions_orders_policy)];
2408
0
    struct nlmsghdr *nlmsg = ofpbuf_try_pull(&b, sizeof *nlmsg);
2409
0
    const int max_size = ARRAY_SIZE(actions_orders_policy);
2410
0
    struct tcamsg *tca = ofpbuf_try_pull(&b, sizeof *tca);
2411
0
    const struct nlattr *actions;
2412
0
    struct tc_flower flower;
2413
0
    int i, cnt = 0;
2414
0
    int err;
2415
2416
0
    if (!nlmsg || !tca) {
2417
0
        COVERAGE_INC(tc_netlink_malformed_reply);
2418
0
        return EPROTO;
2419
0
    }
2420
2421
0
    for (i = 0; i < max_size; i++) {
2422
0
        actions_orders_policy[i].type = NL_A_NESTED;
2423
0
        actions_orders_policy[i].optional = true;
2424
0
    }
2425
2426
0
    actions = nl_attr_find(&b, 0, TCA_ACT_TAB);
2427
0
    if (!actions || !nl_parse_nested(actions, actions_orders_policy,
2428
0
                                     actions_orders, max_size)) {
2429
0
        VLOG_ERR_RL(&error_rl,
2430
0
                    "Failed to parse actions in netlink to policer");
2431
0
        return EPROTO;
2432
0
    }
2433
2434
0
    for (i = 0; i < TCA_ACT_MAX_PRIO; i++) {
2435
0
        if (actions_orders[i]) {
2436
0
            bool csum;
2437
2438
0
            memset(&flower, 0, sizeof(struct tc_flower));
2439
0
            err = nl_parse_single_action(actions_orders[i], &flower, false,
2440
0
                                         &csum);
2441
0
            if (err || flower.actions[0].type != TC_ACT_POLICE) {
2442
0
                continue;
2443
0
            }
2444
0
            if (flower.actions[0].police.index) {
2445
0
                police_idx[cnt++] = flower.actions[0].police.index;
2446
0
            }
2447
0
        }
2448
0
    }
2449
2450
0
    return 0;
2451
0
}
2452
2453
int
2454
tc_del_filter(struct tcf_id *id, const char *kind)
2455
0
{
2456
0
    struct ofpbuf request;
2457
2458
0
    request_from_tcf_id(id, 0, RTM_DELTFILTER, NLM_F_ACK, &request);
2459
0
    if (kind) {
2460
0
        nl_msg_put_string(&request, TCA_KIND, kind);
2461
0
    }
2462
0
    return tc_transact(&request, NULL);
2463
0
}
2464
2465
int
2466
tc_del_flower_filter(struct tcf_id *id)
2467
0
{
2468
0
    return tc_del_filter(id, "flower");
2469
0
}
2470
2471
int
2472
tc_get_flower(struct tcf_id *id, struct tc_flower *flower)
2473
0
{
2474
0
    struct ofpbuf request;
2475
0
    struct ofpbuf *reply;
2476
0
    int error;
2477
2478
0
    request_from_tcf_id(id, 0, RTM_GETTFILTER, NLM_F_ECHO, &request);
2479
0
    nl_msg_put_string(&request, TCA_KIND, "flower");
2480
0
    error = tc_transact(&request, &reply);
2481
0
    if (error) {
2482
0
        return error;
2483
0
    }
2484
2485
0
    error = parse_netlink_to_tc_flower(reply, id, flower, false);
2486
0
    ofpbuf_delete(reply);
2487
0
    return error;
2488
0
}
2489
2490
static int
2491
tc_get_tc_cls_policy(enum tc_offload_policy policy)
2492
0
{
2493
0
    if (policy == TC_POLICY_SKIP_HW) {
2494
0
        return TCA_CLS_FLAGS_SKIP_HW;
2495
0
    } else if (policy == TC_POLICY_SKIP_SW) {
2496
0
        return TCA_CLS_FLAGS_SKIP_SW;
2497
0
    }
2498
2499
0
    return 0;
2500
0
}
2501
2502
static void
2503
nl_msg_put_act_csum(struct ofpbuf *request, uint32_t flags, uint32_t action_pc)
2504
0
{
2505
0
    size_t offset;
2506
2507
0
    nl_msg_put_string(request, TCA_ACT_KIND, "csum");
2508
0
    offset = nl_msg_start_nested(request, TCA_ACT_OPTIONS);
2509
0
    {
2510
0
        struct tc_csum parm = { .action = action_pc,
2511
0
                                .update_flags = flags };
2512
2513
0
        nl_msg_put_unspec(request, TCA_CSUM_PARMS, &parm, sizeof parm);
2514
0
    }
2515
0
    nl_msg_end_nested(request, offset);
2516
0
}
2517
2518
static void
2519
nl_msg_put_act_pedit(struct ofpbuf *request, struct tc_pedit *parm,
2520
                     struct tc_pedit_key_ex *ex, uint32_t action_pc)
2521
0
{
2522
0
    size_t ksize = sizeof *parm + parm->nkeys * sizeof(struct tc_pedit_key);
2523
0
    size_t offset, offset_keys_ex, offset_key;
2524
0
    int i;
2525
2526
0
    nl_msg_put_string(request, TCA_ACT_KIND, "pedit");
2527
0
    offset = nl_msg_start_nested(request, TCA_ACT_OPTIONS);
2528
0
    {
2529
0
        parm->action = action_pc;
2530
2531
0
        nl_msg_put_unspec(request, TCA_PEDIT_PARMS_EX, parm, ksize);
2532
0
        offset_keys_ex = nl_msg_start_nested(request, TCA_PEDIT_KEYS_EX);
2533
0
        for (i = 0; i < parm->nkeys; i++, ex++) {
2534
0
            offset_key = nl_msg_start_nested(request, TCA_PEDIT_KEY_EX);
2535
0
            nl_msg_put_u16(request, TCA_PEDIT_KEY_EX_HTYPE, ex->htype);
2536
0
            nl_msg_put_u16(request, TCA_PEDIT_KEY_EX_CMD, ex->cmd);
2537
0
            nl_msg_end_nested(request, offset_key);
2538
0
        }
2539
0
        nl_msg_end_nested(request, offset_keys_ex);
2540
0
    }
2541
0
    nl_msg_end_nested(request, offset);
2542
0
}
2543
2544
static void
2545
nl_msg_put_act_push_vlan(struct ofpbuf *request, ovs_be16 tpid,
2546
                         uint16_t vid, uint8_t prio, uint32_t action_pc)
2547
0
{
2548
0
    size_t offset;
2549
2550
0
    nl_msg_put_string(request, TCA_ACT_KIND, "vlan");
2551
0
    offset = nl_msg_start_nested(request, TCA_ACT_OPTIONS);
2552
0
    {
2553
0
        struct tc_vlan parm = { .action = action_pc,
2554
0
                                .v_action = TCA_VLAN_ACT_PUSH };
2555
2556
0
        nl_msg_put_unspec(request, TCA_VLAN_PARMS, &parm, sizeof parm);
2557
0
        nl_msg_put_be16(request, TCA_VLAN_PUSH_VLAN_PROTOCOL, tpid);
2558
0
        nl_msg_put_u16(request, TCA_VLAN_PUSH_VLAN_ID, vid);
2559
0
        nl_msg_put_u8(request, TCA_VLAN_PUSH_VLAN_PRIORITY, prio);
2560
0
    }
2561
0
    nl_msg_end_nested(request, offset);
2562
0
}
2563
2564
static void
2565
nl_msg_put_act_pop_vlan(struct ofpbuf *request, uint32_t action_pc)
2566
0
{
2567
0
    size_t offset;
2568
2569
0
    nl_msg_put_string(request, TCA_ACT_KIND, "vlan");
2570
0
    offset = nl_msg_start_nested(request, TCA_ACT_OPTIONS);
2571
0
    {
2572
0
        struct tc_vlan parm = { .action = action_pc,
2573
0
                                .v_action = TCA_VLAN_ACT_POP };
2574
2575
0
        nl_msg_put_unspec(request, TCA_VLAN_PARMS, &parm, sizeof parm);
2576
0
    }
2577
0
    nl_msg_end_nested(request, offset);
2578
0
}
2579
2580
static void
2581
nl_msg_put_act_pop_mpls(struct ofpbuf *request, ovs_be16 proto,
2582
                        uint32_t action_pc)
2583
0
{
2584
0
    size_t offset;
2585
2586
0
    nl_msg_put_string(request, TCA_ACT_KIND, "mpls");
2587
0
    offset = nl_msg_start_nested(request, TCA_ACT_OPTIONS | NLA_F_NESTED);
2588
0
    {
2589
0
        struct tc_mpls parm = { .action = action_pc,
2590
0
                                .m_action = TCA_MPLS_ACT_POP };
2591
2592
0
        nl_msg_put_unspec(request, TCA_MPLS_PARMS, &parm, sizeof parm);
2593
0
        nl_msg_put_be16(request, TCA_MPLS_PROTO, proto);
2594
0
    }
2595
0
    nl_msg_end_nested(request, offset);
2596
0
}
2597
2598
static void
2599
nl_msg_put_act_push_mpls(struct ofpbuf *request, ovs_be16 proto,
2600
                         uint32_t label, uint8_t tc, uint8_t ttl, uint8_t bos,
2601
                         uint32_t action_pc)
2602
0
{
2603
0
    size_t offset;
2604
2605
0
    nl_msg_put_string(request, TCA_ACT_KIND, "mpls");
2606
0
    offset = nl_msg_start_nested(request, TCA_ACT_OPTIONS | NLA_F_NESTED);
2607
0
    {
2608
0
        struct tc_mpls parm = { .action = action_pc,
2609
0
                                .m_action = TCA_MPLS_ACT_PUSH };
2610
2611
0
        nl_msg_put_unspec(request, TCA_MPLS_PARMS, &parm, sizeof parm);
2612
0
        nl_msg_put_be16(request, TCA_MPLS_PROTO, proto);
2613
0
        nl_msg_put_u32(request, TCA_MPLS_LABEL, label);
2614
0
        nl_msg_put_u8(request, TCA_MPLS_TC, tc);
2615
0
        nl_msg_put_u8(request, TCA_MPLS_TTL, ttl);
2616
0
        nl_msg_put_u8(request, TCA_MPLS_BOS, bos);
2617
0
    }
2618
0
    nl_msg_end_nested(request, offset);
2619
0
}
2620
2621
static void
2622
nl_msg_put_act_set_mpls(struct ofpbuf *request, uint32_t label, uint8_t tc,
2623
                        uint8_t ttl, uint8_t bos, uint32_t action_pc)
2624
0
{
2625
0
    size_t offset;
2626
2627
0
    nl_msg_put_string(request, TCA_ACT_KIND, "mpls");
2628
0
    offset = nl_msg_start_nested(request, TCA_ACT_OPTIONS | NLA_F_NESTED);
2629
0
    {
2630
0
        struct tc_mpls parm = { .action = action_pc,
2631
0
                                .m_action = TCA_MPLS_ACT_MODIFY };
2632
2633
0
        nl_msg_put_unspec(request, TCA_MPLS_PARMS, &parm, sizeof parm);
2634
0
        nl_msg_put_u32(request, TCA_MPLS_LABEL, label);
2635
0
        nl_msg_put_u8(request, TCA_MPLS_TC, tc);
2636
0
        nl_msg_put_u8(request, TCA_MPLS_TTL, ttl);
2637
0
        nl_msg_put_u8(request, TCA_MPLS_BOS, bos);
2638
0
    }
2639
0
    nl_msg_end_nested(request, offset);
2640
0
}
2641
2642
static void
2643
nl_msg_put_act_tunnel_key_release(struct ofpbuf *request)
2644
0
{
2645
0
    size_t offset;
2646
2647
0
    nl_msg_put_string(request, TCA_ACT_KIND, "tunnel_key");
2648
0
    offset = nl_msg_start_nested(request, TCA_ACT_OPTIONS);
2649
0
    {
2650
0
        struct tc_tunnel_key tun = { .action = TC_ACT_PIPE,
2651
0
                                     .t_action = TCA_TUNNEL_KEY_ACT_RELEASE };
2652
2653
0
        nl_msg_put_unspec(request, TCA_TUNNEL_KEY_PARMS, &tun, sizeof tun);
2654
0
    }
2655
0
    nl_msg_end_nested(request, offset);
2656
0
}
2657
2658
static void
2659
nl_msg_put_act_tunnel_geneve_option(struct ofpbuf *request,
2660
                                    struct tun_metadata *tun_metadata)
2661
0
{
2662
0
    const struct geneve_opt *opt;
2663
0
    size_t outer, inner;
2664
0
    int len, cnt = 0;
2665
2666
0
    len = tun_metadata->present.len;
2667
0
    if (!len) {
2668
0
        return;
2669
0
    }
2670
2671
0
    outer = nl_msg_start_nested(request, TCA_TUNNEL_KEY_ENC_OPTS);
2672
2673
0
    while (len) {
2674
0
        opt = &tun_metadata->opts.gnv[cnt];
2675
0
        inner = nl_msg_start_nested(request, TCA_TUNNEL_KEY_ENC_OPTS_GENEVE);
2676
2677
0
        nl_msg_put_be16(request, TCA_TUNNEL_KEY_ENC_OPT_GENEVE_CLASS,
2678
0
                        opt->opt_class);
2679
0
        nl_msg_put_u8(request, TCA_TUNNEL_KEY_ENC_OPT_GENEVE_TYPE, opt->type);
2680
0
        nl_msg_put_unspec(request, TCA_TUNNEL_KEY_ENC_OPT_GENEVE_DATA, opt + 1,
2681
0
                          opt->length * 4);
2682
2683
0
        cnt += sizeof(struct geneve_opt) / 4 + opt->length;
2684
0
        len -= sizeof(struct geneve_opt) + opt->length * 4;
2685
2686
0
        nl_msg_end_nested(request, inner);
2687
0
    }
2688
2689
0
    nl_msg_end_nested(request, outer);
2690
0
}
2691
2692
static void
2693
nl_msg_put_act_tunnel_vxlan_opts(struct ofpbuf *request,
2694
                                 struct tc_action_encap *encap)
2695
0
{
2696
0
    size_t outer, inner;
2697
0
    uint32_t gbp_raw;
2698
2699
0
    if (!encap->gbp.id_present) {
2700
0
        return;
2701
0
    }
2702
2703
0
    gbp_raw = odp_encode_gbp_raw(encap->gbp.flags,
2704
0
                                 encap->gbp.id);
2705
0
    outer = nl_msg_start_nested_with_flag(request, TCA_TUNNEL_KEY_ENC_OPTS);
2706
0
    inner = nl_msg_start_nested_with_flag(request,
2707
0
                                          TCA_TUNNEL_KEY_ENC_OPTS_VXLAN);
2708
0
    nl_msg_put_u32(request, TCA_TUNNEL_KEY_ENC_OPT_VXLAN_GBP, gbp_raw);
2709
0
    nl_msg_end_nested(request, inner);
2710
0
    nl_msg_end_nested(request, outer);
2711
0
}
2712
2713
static void
2714
nl_msg_put_act_tunnel_key_set(struct ofpbuf *request,
2715
                              struct tc_action_encap *encap,
2716
                              uint32_t action_pc)
2717
0
{
2718
0
    size_t offset;
2719
2720
0
    nl_msg_put_string(request, TCA_ACT_KIND, "tunnel_key");
2721
0
    offset = nl_msg_start_nested(request, TCA_ACT_OPTIONS);
2722
0
    {
2723
0
        struct tc_tunnel_key tun = { .action = action_pc,
2724
0
                                     .t_action = TCA_TUNNEL_KEY_ACT_SET };
2725
2726
0
        nl_msg_put_unspec(request, TCA_TUNNEL_KEY_PARMS, &tun, sizeof tun);
2727
2728
0
        ovs_be32 id32 = be64_to_be32(encap->id);
2729
0
        if (encap->id_present) {
2730
0
            nl_msg_put_be32(request, TCA_TUNNEL_KEY_ENC_KEY_ID, id32);
2731
0
        }
2732
0
        if (encap->ipv4.ipv4_dst) {
2733
0
            nl_msg_put_be32(request, TCA_TUNNEL_KEY_ENC_IPV4_SRC,
2734
0
                            encap->ipv4.ipv4_src);
2735
0
            nl_msg_put_be32(request, TCA_TUNNEL_KEY_ENC_IPV4_DST,
2736
0
                            encap->ipv4.ipv4_dst);
2737
0
        } else if (ipv6_addr_is_set(&encap->ipv6.ipv6_dst)) {
2738
0
            nl_msg_put_in6_addr(request, TCA_TUNNEL_KEY_ENC_IPV6_DST,
2739
0
                                &encap->ipv6.ipv6_dst);
2740
0
            nl_msg_put_in6_addr(request, TCA_TUNNEL_KEY_ENC_IPV6_SRC,
2741
0
                                &encap->ipv6.ipv6_src);
2742
0
        }
2743
0
        if (encap->tos) {
2744
0
            nl_msg_put_u8(request, TCA_TUNNEL_KEY_ENC_TOS, encap->tos);
2745
0
        }
2746
0
        if (encap->ttl) {
2747
0
            nl_msg_put_u8(request, TCA_TUNNEL_KEY_ENC_TTL, encap->ttl);
2748
0
        }
2749
0
        if (encap->tp_dst) {
2750
0
            nl_msg_put_be16(request, TCA_TUNNEL_KEY_ENC_DST_PORT,
2751
0
                            encap->tp_dst);
2752
0
        }
2753
0
        if (encap->dont_fragment) {
2754
0
            nl_msg_put_flag(request, TCA_TUNNEL_KEY_NO_FRAG);
2755
0
        }
2756
0
        nl_msg_put_act_tunnel_vxlan_opts(request, encap);
2757
0
        nl_msg_put_act_tunnel_geneve_option(request, &encap->data);
2758
0
        nl_msg_put_u8(request, TCA_TUNNEL_KEY_NO_CSUM, encap->no_csum);
2759
0
    }
2760
0
    nl_msg_end_nested(request, offset);
2761
0
}
2762
2763
static void
2764
nl_msg_put_act_gact(struct ofpbuf *request, uint32_t chain)
2765
0
{
2766
0
    size_t offset;
2767
2768
0
    nl_msg_put_string(request, TCA_ACT_KIND, "gact");
2769
0
    offset = nl_msg_start_nested(request, TCA_ACT_OPTIONS);
2770
0
    {
2771
0
        struct tc_gact p = { .action = TC_ACT_SHOT };
2772
2773
0
        if (chain) {
2774
0
            p.action = TC_ACT_GOTO_CHAIN | chain;
2775
0
        }
2776
2777
0
        nl_msg_put_unspec(request, TCA_GACT_PARMS, &p, sizeof p);
2778
0
    }
2779
0
    nl_msg_end_nested(request, offset);
2780
0
}
2781
2782
static void
2783
nl_msg_put_act_police_index(struct ofpbuf *request, uint32_t police_idx,
2784
                            uint32_t action_pc)
2785
0
{
2786
0
    struct tc_police police;
2787
0
    size_t offset;
2788
2789
0
    memset(&police, 0, sizeof police);
2790
0
    police.index = police_idx;
2791
0
    police.action = action_pc;
2792
2793
0
    nl_msg_put_string(request, TCA_ACT_KIND, "police");
2794
0
    offset = nl_msg_start_nested(request, TCA_ACT_OPTIONS);
2795
0
    nl_msg_put_unspec(request, TCA_POLICE_TBF, &police, sizeof police);
2796
0
    nl_msg_put_u32(request, TCA_POLICE_RESULT, action_pc);
2797
0
    nl_msg_end_nested(request, offset);
2798
0
}
2799
2800
static void
2801
nl_msg_put_act_ct(struct ofpbuf *request, struct tc_action *action,
2802
                  uint32_t action_pc)
2803
0
{
2804
0
    uint16_t ct_action = 0;
2805
0
    size_t offset;
2806
2807
0
    nl_msg_put_string(request, TCA_ACT_KIND, "ct");
2808
0
    offset = nl_msg_start_nested(request, TCA_ACT_OPTIONS | NLA_F_NESTED);
2809
0
    {
2810
0
        struct tc_ct ct = {
2811
0
            .action = action_pc,
2812
0
        };
2813
2814
0
        if (!action->ct.clear) {
2815
0
            if (action->ct.zone) {
2816
0
                nl_msg_put_u16(request, TCA_CT_ZONE, action->ct.zone);
2817
0
            }
2818
2819
0
            if (!is_all_zeros(&action->ct.label_mask,
2820
0
                              sizeof action->ct.label_mask)) {
2821
0
                nl_msg_put_u128(request, TCA_CT_LABELS,
2822
0
                                action->ct.label);
2823
0
                nl_msg_put_u128(request, TCA_CT_LABELS_MASK,
2824
0
                                action->ct.label_mask);
2825
0
            }
2826
2827
0
            if (action->ct.mark_mask) {
2828
0
                nl_msg_put_u32(request, TCA_CT_MARK,
2829
0
                               action->ct.mark);
2830
0
                nl_msg_put_u32(request, TCA_CT_MARK_MASK,
2831
0
                               action->ct.mark_mask);
2832
0
            }
2833
2834
0
            if (action->ct.commit) {
2835
0
                ct_action = TCA_CT_ACT_COMMIT;
2836
0
                if (action->ct.force) {
2837
0
                    ct_action |= TCA_CT_ACT_FORCE;
2838
0
                }
2839
0
            }
2840
2841
0
            if (action->ct.nat_type) {
2842
0
                ct_action |= TCA_CT_ACT_NAT;
2843
2844
0
                if (action->ct.nat_type == TC_NAT_SRC) {
2845
0
                    ct_action |= TCA_CT_ACT_NAT_SRC;
2846
0
                } else if (action->ct.nat_type == TC_NAT_DST) {
2847
0
                    ct_action |= TCA_CT_ACT_NAT_DST;
2848
0
                }
2849
2850
0
                if (action->ct.range.ip_family == AF_INET) {
2851
0
                    nl_msg_put_be32(request, TCA_CT_NAT_IPV4_MIN,
2852
0
                                    action->ct.range.ipv4.min);
2853
0
                    if (action->ct.range.ipv4.max) {
2854
0
                        nl_msg_put_be32(request, TCA_CT_NAT_IPV4_MAX,
2855
0
                                    action->ct.range.ipv4.max);
2856
0
                    }
2857
0
                } else if (action->ct.range.ip_family == AF_INET6) {
2858
2859
0
                    nl_msg_put_in6_addr(request, TCA_CT_NAT_IPV6_MIN,
2860
0
                                        &action->ct.range.ipv6.min);
2861
0
                    if (ipv6_addr_is_set(&action->ct.range.ipv6.max)) {
2862
0
                        nl_msg_put_in6_addr(request, TCA_CT_NAT_IPV6_MAX,
2863
0
                                            &action->ct.range.ipv6.max);
2864
0
                    }
2865
0
                }
2866
2867
0
                if (action->ct.range.port.min) {
2868
0
                    nl_msg_put_be16(request, TCA_CT_NAT_PORT_MIN,
2869
0
                                    action->ct.range.port.min);
2870
0
                    if (action->ct.range.port.max) {
2871
0
                        nl_msg_put_be16(request, TCA_CT_NAT_PORT_MAX,
2872
0
                                        action->ct.range.port.max);
2873
0
                    }
2874
0
                }
2875
0
            }
2876
0
        } else {
2877
0
            ct_action = TCA_CT_ACT_CLEAR;
2878
0
        }
2879
2880
0
        nl_msg_put_u16(request, TCA_CT_ACTION, ct_action);
2881
0
        nl_msg_put_unspec(request, TCA_CT_PARMS, &ct, sizeof ct);
2882
0
    }
2883
0
    nl_msg_end_nested(request, offset);
2884
0
}
2885
2886
static void
2887
nl_msg_put_act_skbedit_to_host(struct ofpbuf *request)
2888
0
{
2889
0
    size_t offset;
2890
2891
0
    nl_msg_put_string(request, TCA_ACT_KIND, "skbedit");
2892
0
    offset = nl_msg_start_nested(request, TCA_ACT_OPTIONS);
2893
0
    {
2894
0
        struct tc_skbedit s = { .action = TC_ACT_PIPE };
2895
2896
0
        nl_msg_put_unspec(request, TCA_SKBEDIT_PARMS, &s, sizeof s);
2897
0
        nl_msg_put_be16(request, TCA_SKBEDIT_PTYPE, PACKET_HOST);
2898
0
    }
2899
0
    nl_msg_end_nested(request, offset);
2900
0
}
2901
2902
static void
2903
nl_msg_put_act_mirred(struct ofpbuf *request, int ifindex, int action,
2904
                      int eaction)
2905
0
{
2906
0
    size_t offset;
2907
2908
0
    nl_msg_put_string(request, TCA_ACT_KIND, "mirred");
2909
0
    offset = nl_msg_start_nested(request, TCA_ACT_OPTIONS);
2910
0
    {
2911
0
        struct tc_mirred m = { .action = action,
2912
0
                               .eaction = eaction,
2913
0
                               .ifindex = ifindex };
2914
2915
0
        nl_msg_put_unspec(request, TCA_MIRRED_PARMS, &m, sizeof m);
2916
0
    }
2917
0
    nl_msg_end_nested(request, offset);
2918
0
}
2919
2920
static inline void
2921
0
nl_msg_put_act_cookie(struct ofpbuf *request, struct tc_cookie *ck) {
2922
0
    if (ck->len) {
2923
0
        nl_msg_put_unspec(request, TCA_ACT_COOKIE, ck->data, ck->len);
2924
0
    }
2925
0
}
2926
2927
static inline void
2928
0
nl_msg_put_act_flags(struct ofpbuf *request) {
2929
0
    struct nla_bitfield32 act_flags = { TCA_ACT_FLAGS_NO_PERCPU_STATS,
2930
0
                                        TCA_ACT_FLAGS_NO_PERCPU_STATS };
2931
2932
0
    nl_msg_put_unspec(request, TCA_ACT_FLAGS, &act_flags, sizeof act_flags);
2933
0
}
2934
2935
/* Given flower, a key_to_pedit map entry, calculates the rest,
2936
 * where:
2937
 *
2938
 * mask, data - pointers of where read the first word of flower->key/mask.
2939
 * current_offset - which offset to use for the first pedit action.
2940
 * cnt - max pedits actions to use.
2941
 * first_word_mask/last_word_mask - the mask to use for the first/last read
2942
 * (as we read entire words). */
2943
static void
2944
calc_offsets(struct tc_action *action, struct flower_key_to_pedit *m,
2945
             int *cur_offset, int *cnt, ovs_be32 *last_word_mask,
2946
             ovs_be32 *first_word_mask, ovs_be32 **mask, ovs_be32 **data)
2947
0
{
2948
0
    int start_offset, max_offset, total_size;
2949
0
    int diff, right_zero_bits, left_zero_bits;
2950
0
    char *rewrite_key = (void *) &action->rewrite.key;
2951
0
    char *rewrite_mask = (void *) &action->rewrite.mask;
2952
2953
0
    max_offset = m->offset + m->size;
2954
0
    start_offset = ROUND_DOWN(m->offset, 4);
2955
0
    diff = m->offset - start_offset;
2956
0
    total_size = max_offset - start_offset;
2957
0
    right_zero_bits = 8 * (4 - ((max_offset % 4) ? : 4));
2958
0
    left_zero_bits = 8 * (m->offset - start_offset);
2959
2960
0
    *cur_offset = start_offset;
2961
0
    *cnt = (total_size / 4) + (total_size % 4 ? 1 : 0);
2962
0
    *last_word_mask = htonl(UINT32_MAX << right_zero_bits);
2963
0
    *first_word_mask = htonl(UINT32_MAX >> left_zero_bits);
2964
0
    *data = (void *) (rewrite_key + m->flower_offset - diff);
2965
0
    *mask = (void *) (rewrite_mask + m->flower_offset - diff);
2966
0
}
2967
2968
static inline int
2969
csum_update_flag(struct tc_flower *flower,
2970
0
                 enum pedit_header_type htype) {
2971
    /* Explictily specifiy the csum flags so HW can return EOPNOTSUPP
2972
     * if it doesn't support a checksum recalculation of some headers.
2973
     * And since OVS allows a flow such as
2974
     * eth(dst=<mac>),eth_type(0x0800) actions=set(ipv4(src=<new_ip>))
2975
     * we need to force a more specific flow as this can, for example,
2976
     * need a recalculation of icmp checksum if the packet that passes
2977
     * is ICMPv6 and tcp checksum if its tcp.
2978
     *
2979
     * This section of the code must be kept in sync with the pre-check
2980
     * function in netdev-offload-tc.c, tc_will_add_l4_checksum(). */
2981
2982
0
    switch (htype) {
2983
0
    case TCA_PEDIT_KEY_EX_HDR_TYPE_IP4:
2984
0
        flower->csum_update_flags |= TCA_CSUM_UPDATE_FLAG_IPV4HDR;
2985
        /* Fall through. */
2986
0
    case TCA_PEDIT_KEY_EX_HDR_TYPE_IP6:
2987
0
    case TCA_PEDIT_KEY_EX_HDR_TYPE_TCP:
2988
0
    case TCA_PEDIT_KEY_EX_HDR_TYPE_UDP:
2989
0
        if (flower->key.ip_proto == IPPROTO_TCP) {
2990
0
            flower->needs_full_ip_proto_mask = true;
2991
0
            flower->csum_update_flags |= TCA_CSUM_UPDATE_FLAG_TCP;
2992
0
        } else if (flower->key.ip_proto == IPPROTO_UDP) {
2993
0
            flower->needs_full_ip_proto_mask = true;
2994
0
            flower->csum_update_flags |= TCA_CSUM_UPDATE_FLAG_UDP;
2995
0
        } else if (flower->key.ip_proto == IPPROTO_ICMP ||
2996
0
                   flower->key.ip_proto == IPPROTO_IGMP ||
2997
0
                   flower->key.ip_proto == IPPROTO_SCTP ||
2998
0
                   flower->key.ip_proto == IPPROTO_IPIP ||
2999
0
                   flower->key.ip_proto == IPPROTO_GRE) {
3000
0
            flower->needs_full_ip_proto_mask = true;
3001
0
        } else if (flower->key.ip_proto == IPPROTO_ICMPV6) {
3002
0
            flower->needs_full_ip_proto_mask = true;
3003
0
            flower->csum_update_flags |= TCA_CSUM_UPDATE_FLAG_ICMP;
3004
0
        } else if (flower->key.ip_proto == IPPROTO_UDPLITE) {
3005
0
            flower->needs_full_ip_proto_mask = true;
3006
0
            flower->csum_update_flags |= TCA_CSUM_UPDATE_FLAG_UDPLITE;
3007
0
        } else {
3008
0
            VLOG_WARN_RL(&error_rl,
3009
0
                         "can't offload rewrite of IP/IPV6 with ip_proto: %d",
3010
0
                         flower->key.ip_proto);
3011
0
            break;
3012
0
        }
3013
        /* Fall through. */
3014
0
    case TCA_PEDIT_KEY_EX_HDR_TYPE_ETH:
3015
0
        return 0; /* success */
3016
3017
0
    case TCA_PEDIT_KEY_EX_HDR_TYPE_NETWORK:
3018
0
    case __PEDIT_HDR_TYPE_MAX:
3019
0
    default:
3020
0
        break;
3021
0
    }
3022
3023
0
    return EOPNOTSUPP;
3024
0
}
3025
3026
static bool
3027
rewrite_pedits_need_csum_update(struct tc_action *action)
3028
0
{
3029
0
    int i, j;
3030
3031
0
    for (i = 0; i < ARRAY_SIZE(flower_pedit_map); i++) {
3032
0
        struct flower_key_to_pedit *m = &flower_pedit_map[i];
3033
0
        ovs_be32 *mask, *data, first_word_mask, last_word_mask;
3034
0
        int cnt = 0, cur_offset = 0;
3035
3036
0
        if (!m->size) {
3037
0
            continue;
3038
0
        }
3039
3040
0
        calc_offsets(action, m, &cur_offset, &cnt, &last_word_mask,
3041
0
                     &first_word_mask, &mask, &data);
3042
3043
0
        for (j = 0; j < cnt; j++,  mask++) {
3044
0
            ovs_be32 mask_word = get_unaligned_be32(mask);
3045
3046
0
            if (j == 0) {
3047
0
                mask_word &= first_word_mask;
3048
0
            }
3049
0
            if (j == cnt - 1) {
3050
0
                mask_word &= last_word_mask;
3051
0
            }
3052
0
            if (!mask_word) {
3053
0
                continue;
3054
0
            }
3055
3056
0
            switch (m->htype) {
3057
0
            case TCA_PEDIT_KEY_EX_HDR_TYPE_IP4:
3058
0
            case TCA_PEDIT_KEY_EX_HDR_TYPE_IP6:
3059
0
            case TCA_PEDIT_KEY_EX_HDR_TYPE_TCP:
3060
0
            case TCA_PEDIT_KEY_EX_HDR_TYPE_UDP:
3061
0
                return true;
3062
0
            case TCA_PEDIT_KEY_EX_HDR_TYPE_NETWORK:
3063
0
            case TCA_PEDIT_KEY_EX_HDR_TYPE_ETH:
3064
0
            case __PEDIT_HDR_TYPE_MAX:
3065
0
                break;
3066
0
            }
3067
0
        }
3068
0
    }
3069
0
    return false;
3070
0
}
3071
3072
static int
3073
nl_msg_put_flower_rewrite_pedits(struct ofpbuf *request,
3074
                                 struct tc_flower *flower,
3075
                                 struct tc_action *action,
3076
                                 uint32_t action_pc)
3077
0
{
3078
0
    union {
3079
0
        struct tc_pedit sel;
3080
0
        uint8_t buffer[sizeof(struct tc_pedit)
3081
0
                       + MAX_PEDIT_OFFSETS * sizeof(struct tc_pedit_key)];
3082
0
    } sel;
3083
0
    struct tc_pedit_key_ex keys_ex[MAX_PEDIT_OFFSETS];
3084
0
    int i, j, err;
3085
3086
0
    memset(&sel, 0, sizeof sel);
3087
0
    memset(keys_ex, 0, sizeof keys_ex);
3088
3089
0
    for (i = 0; i < ARRAY_SIZE(flower_pedit_map); i++) {
3090
0
        struct flower_key_to_pedit *m = &flower_pedit_map[i];
3091
0
        struct tc_pedit_key *pedit_key = NULL;
3092
0
        struct tc_pedit_key_ex *pedit_key_ex = NULL;
3093
0
        ovs_be32 *mask, *data, first_word_mask, last_word_mask;
3094
0
        int cnt = 0, cur_offset = 0;
3095
3096
0
        if (!m->size) {
3097
0
            continue;
3098
0
        }
3099
3100
0
        calc_offsets(action, m, &cur_offset, &cnt, &last_word_mask,
3101
0
                     &first_word_mask, &mask, &data);
3102
3103
0
        for (j = 0; j < cnt; j++,  mask++, data++, cur_offset += 4) {
3104
0
            ovs_be32 mask_word = get_unaligned_be32(mask);
3105
0
            ovs_be32 data_word = get_unaligned_be32(data);
3106
3107
0
            if (j == 0) {
3108
0
                mask_word &= first_word_mask;
3109
0
            }
3110
0
            if (j == cnt - 1) {
3111
0
                mask_word &= last_word_mask;
3112
0
            }
3113
0
            if (!mask_word) {
3114
0
                continue;
3115
0
            }
3116
0
            if (sel.sel.nkeys == MAX_PEDIT_OFFSETS) {
3117
0
                VLOG_WARN_RL(&error_rl, "reached too many pedit offsets: %d",
3118
0
                             MAX_PEDIT_OFFSETS);
3119
0
                return EOPNOTSUPP;
3120
0
            }
3121
3122
0
            pedit_key = &sel.sel.keys[sel.sel.nkeys];
3123
0
            pedit_key_ex = &keys_ex[sel.sel.nkeys];
3124
0
            pedit_key_ex->cmd = TCA_PEDIT_KEY_EX_CMD_SET;
3125
0
            pedit_key_ex->htype = m->htype;
3126
0
            pedit_key->off = cur_offset;
3127
0
            mask_word = htonl(ntohl(mask_word) >> m->boundary_shift);
3128
0
            data_word = htonl(ntohl(data_word) >> m->boundary_shift);
3129
0
            pedit_key->mask = ~mask_word;
3130
0
            pedit_key->val = data_word & mask_word;
3131
0
            sel.sel.nkeys++;
3132
3133
0
            err = csum_update_flag(flower, m->htype);
3134
0
            if (err) {
3135
0
                return err;
3136
0
            }
3137
3138
0
            if (flower->needs_full_ip_proto_mask) {
3139
0
                flower->mask.ip_proto = UINT8_MAX;
3140
0
            }
3141
0
        }
3142
0
    }
3143
0
    nl_msg_put_act_pedit(request, &sel.sel, keys_ex,
3144
0
                         flower->csum_update_flags ? TC_ACT_PIPE : action_pc);
3145
3146
0
    return 0;
3147
0
}
3148
3149
static void
3150
nl_msg_put_flower_acts_release(struct ofpbuf *request, uint16_t act_index)
3151
0
{
3152
0
    size_t act_offset;
3153
3154
0
    act_offset = nl_msg_start_nested(request, act_index);
3155
0
    nl_msg_put_act_tunnel_key_release(request);
3156
0
    nl_msg_put_act_flags(request);
3157
0
    nl_msg_end_nested(request, act_offset);
3158
0
}
3159
3160
/* Aggregates all previous successive pedit actions csum_update_flags
3161
 * to flower->csum_update_flags. Only append one csum action to the
3162
 * last pedit action. */
3163
static void
3164
nl_msg_put_csum_act(struct ofpbuf *request, struct tc_flower *flower,
3165
                    uint32_t action_pc, uint16_t *act_index)
3166
0
{
3167
0
    size_t act_offset;
3168
3169
    /* No pedit actions or processed already. */
3170
0
    if (!flower->csum_update_flags) {
3171
0
        return;
3172
0
    }
3173
3174
0
    act_offset = nl_msg_start_nested(request, (*act_index)++);
3175
0
    nl_msg_put_act_csum(request, flower->csum_update_flags, action_pc);
3176
0
    nl_msg_put_act_flags(request);
3177
0
    nl_msg_end_nested(request, act_offset);
3178
3179
    /* Clear it. So we can have another series of pedit actions. */
3180
0
    flower->csum_update_flags = 0;
3181
0
}
3182
3183
static int
3184
get_action_index_for_tc_actions(struct tc_flower *flower, uint16_t act_index,
3185
                                struct tc_action *action, int action_count,
3186
                                bool tunnel_key_released)
3187
0
{
3188
0
    bool need_csum = false;
3189
3190
0
    if (action_count < 0) {
3191
        /* Only forward jumps are supported */
3192
0
        return -EINVAL;
3193
0
    }
3194
3195
0
    for (int i = 0; i < action_count; i++, action++) {
3196
0
        if (action->type != TC_ACT_PEDIT && need_csum) {
3197
0
            need_csum = false;
3198
0
            act_index++;
3199
0
        }
3200
3201
0
        switch (action->type) {
3202
3203
0
        case TC_ACT_OUTPUT:
3204
0
            if (!tunnel_key_released && flower->tunnel) {
3205
0
                act_index++;
3206
0
                tunnel_key_released = true;
3207
0
            }
3208
0
            if (action->out.ingress) {
3209
0
                act_index++;
3210
0
            }
3211
0
            act_index++;
3212
0
            break;
3213
3214
0
        case TC_ACT_ENCAP:
3215
0
            if (!tunnel_key_released && flower->tunnel) {
3216
0
                act_index++;
3217
0
                tunnel_key_released = true;
3218
0
            }
3219
0
            act_index++;
3220
0
            break;
3221
3222
0
        case TC_ACT_PEDIT:
3223
0
            if (!need_csum) {
3224
0
                need_csum = rewrite_pedits_need_csum_update(action);
3225
0
            }
3226
0
            if (i == (action_count - 1) && need_csum) {
3227
0
                need_csum = false;
3228
0
                act_index++;
3229
0
            }
3230
0
            act_index++;
3231
0
            break;
3232
3233
0
        case TC_ACT_POLICE:
3234
0
        case TC_ACT_POLICE_MTU:
3235
0
        case TC_ACT_VLAN_POP:
3236
0
        case TC_ACT_VLAN_PUSH:
3237
0
        case TC_ACT_MPLS_POP:
3238
0
        case TC_ACT_MPLS_PUSH:
3239
0
        case TC_ACT_MPLS_SET:
3240
0
        case TC_ACT_GOTO:
3241
0
        case TC_ACT_CT:
3242
            /* Increase act_index by one if we are sure this type of action
3243
             * will only add one tc action in the kernel. */
3244
0
            act_index++;
3245
0
            break;
3246
3247
            /* If we can't determine how many tc actions will be added by the
3248
             * kernel return -EOPNOTSUPP.
3249
             *
3250
             * Please do NOT add a default case. */
3251
0
        }
3252
0
    }
3253
3254
0
    return act_index;
3255
0
}
3256
3257
static int
3258
nl_msg_put_act_police_mtu(struct ofpbuf *request, struct tc_flower *flower,
3259
                          struct tc_action *action, uint32_t action_pc,
3260
                          int action_index, uint16_t act_index, bool released)
3261
0
{
3262
0
    uint32_t tc_action;
3263
0
    size_t offset;
3264
3265
0
    if (action->police.result_jump != JUMP_ACTION_STOP) {
3266
0
        int jump_index;
3267
0
        int action_count = action->police.result_jump - action_index - 1;
3268
3269
0
        jump_index = get_action_index_for_tc_actions(flower,
3270
0
                                                     act_index - 1,
3271
0
                                                     action + 1,
3272
0
                                                     action_count,
3273
0
                                                     released);
3274
0
        if (jump_index < 0) {
3275
0
            return -jump_index;
3276
0
        }
3277
0
        tc_action = TC_ACT_JUMP | (jump_index & TC_ACT_EXT_VAL_MASK);
3278
0
    } else {
3279
0
        tc_action = TC_ACT_STOLEN;
3280
0
    }
3281
3282
0
    nl_msg_put_string(request, TCA_ACT_KIND, "police");
3283
0
    offset = nl_msg_start_nested(request, TCA_ACT_OPTIONS);
3284
0
    {
3285
0
        struct tc_police p = { .action = action_pc,
3286
0
            .mtu = action->police.mtu };
3287
3288
0
        nl_msg_put_unspec(request, TCA_POLICE_TBF, &p, sizeof p);
3289
3290
        /* The value in jump_action is the total number of TC_ACT_*
3291
         * we need to jump, not the actual number of TCA_ACT_KIND
3292
         * (act_index) actions. As certain TC_ACT_* actions can be
3293
         * translated into multiple TCA_ACT_KIND ones.
3294
         *
3295
         * See nl_msg_put_flower_acts() below for more details. */
3296
0
        nl_msg_put_u32(request, TCA_POLICE_RESULT, tc_action);
3297
0
    }
3298
0
    nl_msg_end_nested(request, offset);
3299
0
    return 0;
3300
0
}
3301
3302
static int
3303
nl_msg_put_flower_acts(struct ofpbuf *request, struct tc_flower *flower)
3304
0
{
3305
0
    bool ingress, released = false;
3306
0
    size_t offset;
3307
0
    size_t act_offset;
3308
0
    uint16_t act_index = 1;
3309
0
    struct tc_action *action;
3310
0
    int i, ifindex = 0;
3311
3312
0
    offset = nl_msg_start_nested(request, TCA_FLOWER_ACT);
3313
0
    {
3314
0
        int error;
3315
0
        uint32_t prev_action_pc = TC_ACT_PIPE;
3316
3317
0
        action = flower->actions;
3318
0
        for (i = 0; i < flower->action_count; i++, action++) {
3319
0
            uint32_t action_pc; /* Programmatic Control */
3320
3321
0
            if (!action->jump_action) {
3322
0
                if (i == flower->action_count - 1) {
3323
0
                    action_pc = TC_ACT_SHOT;
3324
0
                } else {
3325
0
                    action_pc = TC_ACT_PIPE;
3326
0
                }
3327
0
            } else if (action->jump_action == JUMP_ACTION_STOP) {
3328
0
                action_pc = TC_ACT_STOLEN;
3329
0
            } else {
3330
                /* The value in jump_action is the total number of TC_ACT_*
3331
                 * we need to jump, not the actual number of TCA_ACT_KIND
3332
                 * (act_index) actions. As certain TC_ACT_* actions can be
3333
                 * translated into multiple TCA_ACT_KIND ones.
3334
                 *
3335
                 * If we can determine the number of actual actions being
3336
                 * inserted we will update the count, if not we will return
3337
                 * -EOPNOTSUPP.
3338
                 */
3339
0
                int jump_index;
3340
0
                int act_index_start = act_index - 1;
3341
0
                int action_count = (action->jump_action &
3342
0
                                    TC_ACT_EXT_VAL_MASK) - i;
3343
3344
0
                if (flower->csum_update_flags &&
3345
0
                    (action->type != TC_ACT_PEDIT
3346
0
                     || prev_action_pc & TC_ACT_JUMP)) {
3347
0
                    act_index_start++;
3348
0
                }
3349
3350
0
                jump_index = get_action_index_for_tc_actions(flower,
3351
0
                                                             act_index_start,
3352
0
                                                             action,
3353
0
                                                             action_count,
3354
0
                                                             released);
3355
0
                if (jump_index < 0) {
3356
0
                    return -jump_index;
3357
0
                }
3358
3359
0
                action_pc = TC_ACT_JUMP | jump_index;
3360
0
            }
3361
3362
0
            if (action->type != TC_ACT_PEDIT || prev_action_pc & TC_ACT_JUMP) {
3363
0
                nl_msg_put_csum_act(request, flower, prev_action_pc,
3364
0
                                    &act_index);
3365
0
            }
3366
3367
0
            switch (action->type) {
3368
0
            case TC_ACT_PEDIT: {
3369
0
                act_offset = nl_msg_start_nested(request, act_index++);
3370
0
                error = nl_msg_put_flower_rewrite_pedits(request, flower,
3371
0
                                                         action, action_pc);
3372
0
                if (error) {
3373
0
                    return error;
3374
0
                }
3375
0
                nl_msg_end_nested(request, act_offset);
3376
3377
0
                if (i == flower->action_count - 1) {
3378
                    /* If this is the last action check csum calc again. */
3379
0
                    nl_msg_put_csum_act(request, flower, action_pc,
3380
0
                                        &act_index);
3381
0
                }
3382
0
            }
3383
0
            break;
3384
0
            case TC_ACT_ENCAP: {
3385
0
                if (!released && flower->tunnel) {
3386
0
                    nl_msg_put_flower_acts_release(request, act_index++);
3387
0
                    released = true;
3388
0
                }
3389
3390
0
                act_offset = nl_msg_start_nested(request, act_index++);
3391
0
                nl_msg_put_act_tunnel_key_set(request, &action->encap,
3392
0
                                              action_pc);
3393
0
                nl_msg_put_act_flags(request);
3394
0
                nl_msg_end_nested(request, act_offset);
3395
0
            }
3396
0
            break;
3397
0
            case TC_ACT_VLAN_POP: {
3398
0
                act_offset = nl_msg_start_nested(request, act_index++);
3399
0
                nl_msg_put_act_pop_vlan(request, action_pc);
3400
0
                nl_msg_put_act_flags(request);
3401
0
                nl_msg_end_nested(request, act_offset);
3402
0
            }
3403
0
            break;
3404
0
            case TC_ACT_VLAN_PUSH: {
3405
0
                act_offset = nl_msg_start_nested(request, act_index++);
3406
0
                nl_msg_put_act_push_vlan(request,
3407
0
                                         action->vlan.vlan_push_tpid,
3408
0
                                         action->vlan.vlan_push_id,
3409
0
                                         action->vlan.vlan_push_prio,
3410
0
                                         action_pc);
3411
0
                nl_msg_put_act_flags(request);
3412
0
                nl_msg_end_nested(request, act_offset);
3413
0
            }
3414
0
            break;
3415
0
            case TC_ACT_MPLS_POP: {
3416
0
                act_offset = nl_msg_start_nested(request, act_index++);
3417
0
                nl_msg_put_act_pop_mpls(request, action->mpls.proto,
3418
0
                                        action_pc);
3419
0
                nl_msg_end_nested(request, act_offset);
3420
0
            }
3421
0
            break;
3422
0
            case TC_ACT_MPLS_PUSH: {
3423
0
                act_offset = nl_msg_start_nested(request, act_index++);
3424
0
                nl_msg_put_act_push_mpls(request, action->mpls.proto,
3425
0
                                         action->mpls.label, action->mpls.tc,
3426
0
                                         action->mpls.ttl, action->mpls.bos,
3427
0
                                         action_pc);
3428
0
                nl_msg_end_nested(request, act_offset);
3429
0
            }
3430
0
            break;
3431
0
            case TC_ACT_MPLS_SET: {
3432
0
                act_offset = nl_msg_start_nested(request, act_index++);
3433
0
                nl_msg_put_act_set_mpls(request, action->mpls.label,
3434
0
                                        action->mpls.tc, action->mpls.ttl,
3435
0
                                        action->mpls.bos, action_pc);
3436
0
                nl_msg_end_nested(request, act_offset);
3437
0
            }
3438
0
            break;
3439
0
            case TC_ACT_OUTPUT: {
3440
0
                if (!released && flower->tunnel) {
3441
0
                    nl_msg_put_flower_acts_release(request, act_index++);
3442
0
                    released = true;
3443
0
                }
3444
3445
0
                ingress = action->out.ingress;
3446
0
                ifindex = action->out.ifindex_out;
3447
0
                if (ifindex < 1) {
3448
0
                    VLOG_ERR_RL(&error_rl, "%s: invalid ifindex: %d, type: %d",
3449
0
                                __func__, ifindex, action->type);
3450
0
                    return EINVAL;
3451
0
                }
3452
3453
0
                if (ingress) {
3454
                    /* If redirecting to ingress (internal port) ensure
3455
                     * pkt_type on skb is set to PACKET_HOST. */
3456
0
                    act_offset = nl_msg_start_nested(request, act_index++);
3457
0
                    nl_msg_put_act_skbedit_to_host(request);
3458
0
                    nl_msg_end_nested(request, act_offset);
3459
0
                }
3460
3461
0
                act_offset = nl_msg_start_nested(request, act_index++);
3462
0
                if (i == flower->action_count - 1) {
3463
0
                    if (ingress) {
3464
0
                        nl_msg_put_act_mirred(request, ifindex, TC_ACT_STOLEN,
3465
0
                                              TCA_INGRESS_REDIR);
3466
0
                    } else {
3467
0
                        nl_msg_put_act_mirred(request, ifindex, TC_ACT_STOLEN,
3468
0
                                              TCA_EGRESS_REDIR);
3469
0
                    }
3470
0
                    action->jump_action = JUMP_ACTION_STOP;
3471
0
                } else {
3472
0
                    if (ingress) {
3473
0
                        nl_msg_put_act_mirred(request, ifindex, action_pc,
3474
0
                                              TCA_INGRESS_MIRROR);
3475
0
                    } else {
3476
0
                        nl_msg_put_act_mirred(request, ifindex, action_pc,
3477
0
                                              TCA_EGRESS_MIRROR);
3478
0
                    }
3479
0
                }
3480
0
                nl_msg_put_act_cookie(request, &flower->act_cookie);
3481
0
                nl_msg_put_act_flags(request);
3482
0
                nl_msg_end_nested(request, act_offset);
3483
0
            }
3484
0
            break;
3485
0
            case TC_ACT_GOTO: {
3486
0
                if (released) {
3487
                    /* We don't support tunnel release + output + goto
3488
                     * for now, as next chain by default will try and match
3489
                     * the tunnel metadata that was released/unset.
3490
                     *
3491
                     * This will happen with tunnel + mirror ports.
3492
                     */
3493
0
                    return -EOPNOTSUPP;
3494
0
                }
3495
3496
0
                act_offset = nl_msg_start_nested(request, act_index++);
3497
0
                nl_msg_put_act_gact(request, action->chain);
3498
0
                nl_msg_put_act_cookie(request, &flower->act_cookie);
3499
0
                nl_msg_end_nested(request, act_offset);
3500
0
            }
3501
0
            break;
3502
0
            case TC_ACT_CT: {
3503
0
                act_offset = nl_msg_start_nested(request, act_index++);
3504
0
                nl_msg_put_act_ct(request, action, action_pc);
3505
0
                nl_msg_put_act_cookie(request, &flower->act_cookie);
3506
0
                nl_msg_end_nested(request, act_offset);
3507
0
            }
3508
0
            break;
3509
0
            case TC_ACT_POLICE: {
3510
0
                act_offset = nl_msg_start_nested(request, act_index++);
3511
0
                nl_msg_put_act_police_index(request, action->police.index,
3512
0
                                            action_pc);
3513
0
                nl_msg_end_nested(request, act_offset);
3514
0
            }
3515
0
            break;
3516
0
            case TC_ACT_POLICE_MTU: {
3517
0
                act_offset = nl_msg_start_nested(request, act_index++);
3518
0
                if (nl_msg_put_act_police_mtu(request, flower, action,
3519
0
                                              action_pc, i, act_index,
3520
0
                                              released)) {
3521
0
                    return -EOPNOTSUPP;
3522
0
                }
3523
0
                nl_msg_put_act_cookie(request, &flower->act_cookie);
3524
0
                nl_msg_put_act_flags(request);
3525
0
                nl_msg_end_nested(request, act_offset);
3526
0
            }
3527
0
            break;
3528
0
            }
3529
3530
0
            prev_action_pc = action_pc;
3531
0
        }
3532
0
    }
3533
3534
0
    if (!flower->action_count) {
3535
0
        act_offset = nl_msg_start_nested(request, act_index++);
3536
0
        nl_msg_put_act_gact(request, 0);
3537
0
        nl_msg_put_act_cookie(request, &flower->act_cookie);
3538
0
        nl_msg_put_act_flags(request);
3539
0
        nl_msg_end_nested(request, act_offset);
3540
0
    }
3541
0
    nl_msg_end_nested(request, offset);
3542
3543
0
    return 0;
3544
0
}
3545
3546
static void
3547
nl_msg_put_masked_value(struct ofpbuf *request, uint16_t type,
3548
                        uint16_t mask_type, const void *data,
3549
                        const void *mask_data, size_t len)
3550
0
{
3551
0
    if (mask_type != TCA_FLOWER_UNSPEC) {
3552
0
        if (is_all_zeros(mask_data, len)) {
3553
0
            return;
3554
0
        }
3555
0
        nl_msg_put_unspec(request, mask_type, mask_data, len);
3556
0
    }
3557
0
    nl_msg_put_unspec(request, type, data, len);
3558
0
}
3559
3560
static void
3561
nl_msg_put_flower_geneve(struct ofpbuf *request,
3562
                         const struct tc_flower_tunnel *tunnel)
3563
0
{
3564
0
    const struct tun_metadata *metadata = &tunnel->metadata;
3565
0
    const struct geneve_opt *opt;
3566
0
    int len, cnt = 0;
3567
0
    size_t offset;
3568
3569
0
    len = metadata->present.len;
3570
0
    while (len) {
3571
0
        opt = &metadata->opts.gnv[cnt];
3572
0
        offset = nl_msg_start_nested(request, TCA_FLOWER_KEY_ENC_OPTS_GENEVE);
3573
3574
0
        nl_msg_put_be16(request, TCA_FLOWER_KEY_ENC_OPT_GENEVE_CLASS,
3575
0
                        opt->opt_class);
3576
0
        nl_msg_put_u8(request, TCA_FLOWER_KEY_ENC_OPT_GENEVE_TYPE, opt->type);
3577
0
        nl_msg_put_unspec(request, TCA_FLOWER_KEY_ENC_OPT_GENEVE_DATA, opt + 1,
3578
0
                          opt->length * 4);
3579
3580
0
        cnt += sizeof(struct geneve_opt) / 4 + opt->length;
3581
0
        len -= sizeof(struct geneve_opt) + opt->length * 4;
3582
3583
0
        nl_msg_end_nested(request, offset);
3584
0
    }
3585
0
}
3586
3587
static void
3588
nl_msg_put_flower_vxlan_tun_opts(struct ofpbuf *request,
3589
                                 const struct tc_flower_tunnel *tunnel)
3590
0
{
3591
0
    uint32_t gbp_raw;
3592
0
    size_t offset;
3593
3594
0
    if (!tunnel->gbp.id_present) {
3595
0
        return;
3596
0
    }
3597
3598
0
    gbp_raw = odp_encode_gbp_raw(tunnel->gbp.flags, tunnel->gbp.id);
3599
0
    offset = nl_msg_start_nested_with_flag(request,
3600
0
                                           TCA_FLOWER_KEY_ENC_OPTS_VXLAN);
3601
0
    nl_msg_put_u32(request, TCA_FLOWER_KEY_ENC_OPT_VXLAN_GBP, gbp_raw);
3602
0
    nl_msg_end_nested(request, offset);
3603
0
}
3604
3605
static void
3606
nl_msg_put_flower_tunnel_opts(struct ofpbuf *request, uint16_t type,
3607
                              struct tc_flower_tunnel *tunnel)
3608
0
{
3609
0
    size_t outer;
3610
3611
0
    if (!tunnel->metadata.present.len && !tunnel->gbp.id_present) {
3612
0
        return;
3613
0
    }
3614
3615
0
    outer = nl_msg_start_nested(request, type);
3616
0
    nl_msg_put_flower_geneve(request, tunnel);
3617
0
    nl_msg_put_flower_vxlan_tun_opts(request, tunnel);
3618
0
    nl_msg_end_nested(request, outer);
3619
0
}
3620
3621
static void
3622
nl_msg_put_flower_tunnel(struct ofpbuf *request, struct tc_flower *flower)
3623
0
{
3624
0
    ovs_be32 ipv4_src_mask = flower->mask.tunnel.ipv4.ipv4_src;
3625
0
    ovs_be32 ipv4_dst_mask = flower->mask.tunnel.ipv4.ipv4_dst;
3626
0
    ovs_be32 ipv4_src = flower->key.tunnel.ipv4.ipv4_src;
3627
0
    ovs_be32 ipv4_dst = flower->key.tunnel.ipv4.ipv4_dst;
3628
0
    struct in6_addr *ipv6_src_mask = &flower->mask.tunnel.ipv6.ipv6_src;
3629
0
    struct in6_addr *ipv6_dst_mask = &flower->mask.tunnel.ipv6.ipv6_dst;
3630
0
    struct in6_addr *ipv6_src = &flower->key.tunnel.ipv6.ipv6_src;
3631
0
    struct in6_addr *ipv6_dst = &flower->key.tunnel.ipv6.ipv6_dst;
3632
0
    ovs_be32 id = be64_to_be32(flower->key.tunnel.id);
3633
0
    ovs_be32 enc_flags = htonl(flower->key.tunnel.tc_enc_flags);
3634
0
    ovs_be16 tp_src = flower->key.tunnel.tp_src;
3635
0
    ovs_be16 tp_dst = flower->key.tunnel.tp_dst;
3636
0
    uint8_t tos = flower->key.tunnel.tos;
3637
0
    uint8_t ttl = flower->key.tunnel.ttl;
3638
0
    uint8_t tos_mask = flower->mask.tunnel.tos;
3639
0
    uint8_t ttl_mask = flower->mask.tunnel.ttl;
3640
0
    ovs_be64 id_mask = flower->mask.tunnel.id;
3641
0
    ovs_be32 enc_flags_mask = htonl(flower->mask.tunnel.tc_enc_flags);
3642
0
    ovs_be16 tp_src_mask = flower->mask.tunnel.tp_src;
3643
0
    ovs_be16 tp_dst_mask = flower->mask.tunnel.tp_dst;
3644
3645
0
    if (ipv4_dst_mask || ipv4_src_mask) {
3646
0
        nl_msg_put_be32(request, TCA_FLOWER_KEY_ENC_IPV4_DST_MASK,
3647
0
                        ipv4_dst_mask);
3648
0
        nl_msg_put_be32(request, TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK,
3649
0
                        ipv4_src_mask);
3650
0
        nl_msg_put_be32(request, TCA_FLOWER_KEY_ENC_IPV4_DST, ipv4_dst);
3651
0
        nl_msg_put_be32(request, TCA_FLOWER_KEY_ENC_IPV4_SRC, ipv4_src);
3652
0
    } else if (ipv6_addr_is_set(ipv6_dst_mask) ||
3653
0
               ipv6_addr_is_set(ipv6_src_mask)) {
3654
0
        nl_msg_put_in6_addr(request, TCA_FLOWER_KEY_ENC_IPV6_DST_MASK,
3655
0
                            ipv6_dst_mask);
3656
0
        nl_msg_put_in6_addr(request, TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK,
3657
0
                            ipv6_src_mask);
3658
0
        nl_msg_put_in6_addr(request, TCA_FLOWER_KEY_ENC_IPV6_DST, ipv6_dst);
3659
0
        nl_msg_put_in6_addr(request, TCA_FLOWER_KEY_ENC_IPV6_SRC, ipv6_src);
3660
0
    }
3661
0
    if (tos_mask) {
3662
0
        nl_msg_put_u8(request, TCA_FLOWER_KEY_ENC_IP_TOS, tos);
3663
0
        nl_msg_put_u8(request, TCA_FLOWER_KEY_ENC_IP_TOS_MASK, tos_mask);
3664
0
    }
3665
0
    if (ttl_mask) {
3666
0
        nl_msg_put_u8(request, TCA_FLOWER_KEY_ENC_IP_TTL, ttl);
3667
0
        nl_msg_put_u8(request, TCA_FLOWER_KEY_ENC_IP_TTL_MASK, ttl_mask);
3668
0
    }
3669
0
    if (tp_src_mask) {
3670
0
        nl_msg_put_be16(request, TCA_FLOWER_KEY_ENC_UDP_SRC_PORT, tp_src);
3671
0
        nl_msg_put_be16(request, TCA_FLOWER_KEY_ENC_UDP_SRC_PORT_MASK,
3672
0
                        tp_src_mask);
3673
0
    }
3674
0
    if (tp_dst_mask) {
3675
0
        nl_msg_put_be16(request, TCA_FLOWER_KEY_ENC_UDP_DST_PORT, tp_dst);
3676
0
        nl_msg_put_be16(request, TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK,
3677
0
                        tp_dst_mask);
3678
0
    }
3679
0
    if (enc_flags_mask) {
3680
0
        nl_msg_put_be32(request, TCA_FLOWER_KEY_ENC_FLAGS, enc_flags);
3681
0
        nl_msg_put_be32(request, TCA_FLOWER_KEY_ENC_FLAGS_MASK,
3682
0
                        enc_flags_mask);
3683
0
    }
3684
0
    if (id_mask) {
3685
0
        nl_msg_put_be32(request, TCA_FLOWER_KEY_ENC_KEY_ID, id);
3686
0
    }
3687
0
    nl_msg_put_flower_tunnel_opts(request, TCA_FLOWER_KEY_ENC_OPTS,
3688
0
                                  &flower->key.tunnel);
3689
0
    nl_msg_put_flower_tunnel_opts(request, TCA_FLOWER_KEY_ENC_OPTS_MASK,
3690
0
                                  &flower->mask.tunnel);
3691
0
}
3692
3693
#define FLOWER_PUT_MASKED_VALUE(member, type) \
3694
0
    nl_msg_put_masked_value(request, type, type##_MASK, &flower->key.member, \
3695
0
                            &flower->mask.member, sizeof flower->key.member)
3696
3697
static int
3698
nl_msg_put_flower_options(struct ofpbuf *request, struct tc_flower *flower)
3699
0
{
3700
3701
0
    uint16_t host_eth_type = ntohs(flower->key.eth_type);
3702
0
    bool is_vlan = eth_type_vlan(flower->key.eth_type);
3703
0
    bool is_qinq = is_vlan && eth_type_vlan(flower->key.encap_eth_type[0]);
3704
0
    bool is_mpls = eth_type_mpls(flower->key.eth_type);
3705
0
    enum tc_offload_policy policy = flower->tc_policy;
3706
0
    int err;
3707
3708
    /* need to parse acts first as some acts require changing the matching
3709
     * see csum_update_flag()  */
3710
0
    err  = nl_msg_put_flower_acts(request, flower);
3711
0
    if (err) {
3712
0
        return err;
3713
0
    }
3714
3715
0
    if (is_vlan) {
3716
0
        if (is_qinq) {
3717
0
            host_eth_type = ntohs(flower->key.encap_eth_type[1]);
3718
0
        } else {
3719
0
            host_eth_type = ntohs(flower->key.encap_eth_type[0]);
3720
0
        }
3721
0
    }
3722
3723
0
    if (is_mpls) {
3724
0
        host_eth_type = ntohs(flower->key.encap_eth_type[0]);
3725
0
    }
3726
3727
0
    FLOWER_PUT_MASKED_VALUE(dst_mac, TCA_FLOWER_KEY_ETH_DST);
3728
0
    FLOWER_PUT_MASKED_VALUE(src_mac, TCA_FLOWER_KEY_ETH_SRC);
3729
3730
0
    if (host_eth_type == ETH_P_ARP) {
3731
0
        FLOWER_PUT_MASKED_VALUE(arp.spa, TCA_FLOWER_KEY_ARP_SIP);
3732
0
        FLOWER_PUT_MASKED_VALUE(arp.tpa, TCA_FLOWER_KEY_ARP_TIP);
3733
0
        FLOWER_PUT_MASKED_VALUE(arp.sha, TCA_FLOWER_KEY_ARP_SHA);
3734
0
        FLOWER_PUT_MASKED_VALUE(arp.tha, TCA_FLOWER_KEY_ARP_THA);
3735
0
        FLOWER_PUT_MASKED_VALUE(arp.opcode, TCA_FLOWER_KEY_ARP_OP);
3736
0
    }
3737
3738
0
    if (host_eth_type == ETH_P_IP || host_eth_type == ETH_P_IPV6) {
3739
0
        FLOWER_PUT_MASKED_VALUE(ip_ttl, TCA_FLOWER_KEY_IP_TTL);
3740
0
        FLOWER_PUT_MASKED_VALUE(ip_tos, TCA_FLOWER_KEY_IP_TOS);
3741
3742
0
        if (flower->mask.ip_proto && flower->key.ip_proto) {
3743
0
            nl_msg_put_u8(request, TCA_FLOWER_KEY_IP_PROTO,
3744
0
                          flower->key.ip_proto);
3745
0
        }
3746
3747
0
        if (flower->mask.flags) {
3748
0
            nl_msg_put_be32(request, TCA_FLOWER_KEY_FLAGS,
3749
0
                           htonl(flower->key.flags));
3750
0
            nl_msg_put_be32(request, TCA_FLOWER_KEY_FLAGS_MASK,
3751
0
                           htonl(flower->mask.flags));
3752
0
        }
3753
3754
0
        if (flower->key.ip_proto == IPPROTO_UDP) {
3755
0
            FLOWER_PUT_MASKED_VALUE(udp_src, TCA_FLOWER_KEY_UDP_SRC);
3756
0
            FLOWER_PUT_MASKED_VALUE(udp_dst, TCA_FLOWER_KEY_UDP_DST);
3757
0
        } else if (flower->key.ip_proto == IPPROTO_TCP) {
3758
0
            FLOWER_PUT_MASKED_VALUE(tcp_src, TCA_FLOWER_KEY_TCP_SRC);
3759
0
            FLOWER_PUT_MASKED_VALUE(tcp_dst, TCA_FLOWER_KEY_TCP_DST);
3760
0
            FLOWER_PUT_MASKED_VALUE(tcp_flags, TCA_FLOWER_KEY_TCP_FLAGS);
3761
0
        } else if (flower->key.ip_proto == IPPROTO_SCTP) {
3762
0
            FLOWER_PUT_MASKED_VALUE(sctp_src, TCA_FLOWER_KEY_SCTP_SRC);
3763
0
            FLOWER_PUT_MASKED_VALUE(sctp_dst, TCA_FLOWER_KEY_SCTP_DST);
3764
0
        } else if (flower->key.ip_proto == IPPROTO_ICMP) {
3765
0
            FLOWER_PUT_MASKED_VALUE(icmp_code, TCA_FLOWER_KEY_ICMPV4_CODE);
3766
0
            FLOWER_PUT_MASKED_VALUE(icmp_type, TCA_FLOWER_KEY_ICMPV4_TYPE);
3767
0
        } else if (flower->key.ip_proto == IPPROTO_ICMPV6) {
3768
0
            FLOWER_PUT_MASKED_VALUE(icmp_code, TCA_FLOWER_KEY_ICMPV6_CODE);
3769
0
            FLOWER_PUT_MASKED_VALUE(icmp_type, TCA_FLOWER_KEY_ICMPV6_TYPE);
3770
0
        }
3771
0
    }
3772
3773
0
    FLOWER_PUT_MASKED_VALUE(ct_state, TCA_FLOWER_KEY_CT_STATE);
3774
0
    FLOWER_PUT_MASKED_VALUE(ct_zone, TCA_FLOWER_KEY_CT_ZONE);
3775
0
    FLOWER_PUT_MASKED_VALUE(ct_mark, TCA_FLOWER_KEY_CT_MARK);
3776
0
    FLOWER_PUT_MASKED_VALUE(ct_label, TCA_FLOWER_KEY_CT_LABELS);
3777
3778
0
    if (host_eth_type == ETH_P_IP) {
3779
0
            FLOWER_PUT_MASKED_VALUE(ipv4.ipv4_src, TCA_FLOWER_KEY_IPV4_SRC);
3780
0
            FLOWER_PUT_MASKED_VALUE(ipv4.ipv4_dst, TCA_FLOWER_KEY_IPV4_DST);
3781
0
    } else if (host_eth_type == ETH_P_IPV6) {
3782
0
            FLOWER_PUT_MASKED_VALUE(ipv6.ipv6_src, TCA_FLOWER_KEY_IPV6_SRC);
3783
0
            FLOWER_PUT_MASKED_VALUE(ipv6.ipv6_dst, TCA_FLOWER_KEY_IPV6_DST);
3784
0
    }
3785
3786
0
    nl_msg_put_be16(request, TCA_FLOWER_KEY_ETH_TYPE, flower->key.eth_type);
3787
3788
0
    if (is_mpls) {
3789
0
        if (mpls_lse_to_ttl(flower->mask.mpls_lse)) {
3790
0
            nl_msg_put_u8(request, TCA_FLOWER_KEY_MPLS_TTL,
3791
0
                          mpls_lse_to_ttl(flower->key.mpls_lse));
3792
0
        }
3793
0
        if (mpls_lse_to_tc(flower->mask.mpls_lse)) {
3794
0
            nl_msg_put_u8(request, TCA_FLOWER_KEY_MPLS_TC,
3795
0
                          mpls_lse_to_tc(flower->key.mpls_lse));
3796
0
        }
3797
0
        if (mpls_lse_to_bos(flower->mask.mpls_lse)) {
3798
0
            nl_msg_put_u8(request, TCA_FLOWER_KEY_MPLS_BOS,
3799
0
                          mpls_lse_to_bos(flower->key.mpls_lse));
3800
0
        }
3801
0
        if (mpls_lse_to_label(flower->mask.mpls_lse)) {
3802
0
            nl_msg_put_u32(request, TCA_FLOWER_KEY_MPLS_LABEL,
3803
0
                           mpls_lse_to_label(flower->key.mpls_lse));
3804
0
        }
3805
0
    }
3806
3807
0
    if (is_vlan) {
3808
0
        if (flower->mask.vlan_id[0]) {
3809
0
            nl_msg_put_u16(request, TCA_FLOWER_KEY_VLAN_ID,
3810
0
                           flower->key.vlan_id[0]);
3811
0
        }
3812
0
        if (flower->mask.vlan_prio[0]) {
3813
0
            nl_msg_put_u8(request, TCA_FLOWER_KEY_VLAN_PRIO,
3814
0
                          flower->key.vlan_prio[0]);
3815
0
        }
3816
0
        if (flower->key.encap_eth_type[0]) {
3817
0
            nl_msg_put_be16(request, TCA_FLOWER_KEY_VLAN_ETH_TYPE,
3818
0
                            flower->key.encap_eth_type[0]);
3819
0
        }
3820
3821
0
        if (is_qinq) {
3822
0
            if (flower->mask.vlan_id[1]) {
3823
0
                nl_msg_put_u16(request, TCA_FLOWER_KEY_CVLAN_ID,
3824
0
                               flower->key.vlan_id[1]);
3825
0
            }
3826
0
            if (flower->mask.vlan_prio[1]) {
3827
0
                nl_msg_put_u8(request, TCA_FLOWER_KEY_CVLAN_PRIO,
3828
0
                              flower->key.vlan_prio[1]);
3829
0
            }
3830
0
            if (flower->key.encap_eth_type[1]) {
3831
0
                nl_msg_put_be16(request, TCA_FLOWER_KEY_CVLAN_ETH_TYPE,
3832
0
                                flower->key.encap_eth_type[1]);
3833
0
            }
3834
0
        }
3835
0
    }
3836
3837
0
    if (policy == TC_POLICY_NONE) {
3838
0
        policy = tc_policy;
3839
0
    }
3840
3841
0
    nl_msg_put_u32(request, TCA_FLOWER_FLAGS, tc_get_tc_cls_policy(policy));
3842
3843
0
    if (flower->tunnel) {
3844
0
        nl_msg_put_flower_tunnel(request, flower);
3845
0
    }
3846
3847
0
    return 0;
3848
0
}
3849
3850
static void
3851
log_tc_flower_match(const char *msg,
3852
                    const struct tc_flower *a,
3853
                    const struct tc_flower *b)
3854
0
{
3855
0
    uint8_t key_a[sizeof(struct tc_flower_key)];
3856
0
    uint8_t key_b[sizeof(struct tc_flower_key)];
3857
0
    struct ds s = DS_EMPTY_INITIALIZER;
3858
3859
0
    for (int i = 0; i < sizeof a->key; i++) {
3860
0
        uint8_t mask_a = ((uint8_t *) &a->mask)[i];
3861
0
        uint8_t mask_b = ((uint8_t *) &b->mask)[i];
3862
3863
0
        key_a[i] = ((uint8_t *) &a->key)[i] & mask_a;
3864
0
        key_b[i] = ((uint8_t *) &b->key)[i] & mask_b;
3865
0
    }
3866
0
    ds_put_cstr(&s, "\nExpected Mask:\n");
3867
0
    ds_put_sparse_hex_dump(&s, &a->mask, sizeof a->mask, 0, false);
3868
0
    ds_put_cstr(&s, "\nReceived Mask:\n");
3869
0
    ds_put_sparse_hex_dump(&s, &b->mask, sizeof b->mask, 0, false);
3870
0
    ds_put_cstr(&s, "\nExpected Key:\n");
3871
0
    ds_put_sparse_hex_dump(&s, &a->key, sizeof a->key, 0, false);
3872
0
    ds_put_cstr(&s, "\nReceived Key:\n");
3873
0
    ds_put_sparse_hex_dump(&s, &b->key, sizeof b->key, 0, false);
3874
0
    ds_put_cstr(&s, "\nExpected Masked Key:\n");
3875
0
    ds_put_sparse_hex_dump(&s, key_a, sizeof key_a, 0, false);
3876
0
    ds_put_cstr(&s, "\nReceived Masked Key:\n");
3877
0
    ds_put_sparse_hex_dump(&s, key_b, sizeof key_b, 0, false);
3878
3879
0
    if (a->action_count != b->action_count) {
3880
        /* If action count is not equal, we print all actions to see which
3881
         * ones are missing. */
3882
0
        const struct tc_action *action;
3883
0
        int i;
3884
3885
0
        ds_put_cstr(&s, "\nExpected Actions:\n");
3886
0
        for (i = 0, action = a->actions; i < a->action_count; i++, action++) {
3887
0
            ds_put_format(&s, " - %d -\n", i);
3888
0
            ds_put_sparse_hex_dump(&s, action, sizeof *action, 0, false);
3889
0
        }
3890
0
        ds_put_cstr(&s, "\nReceived Actions:\n");
3891
0
        for (i = 0, action = b->actions; i < b->action_count; i++, action++) {
3892
0
            ds_put_format(&s, " - %d -\n", i);
3893
0
            ds_put_sparse_hex_dump(&s, action, sizeof *action, 0, false);
3894
0
        }
3895
0
    } else {
3896
        /* Only dump the delta in actions. */
3897
0
        const struct tc_action *action_a = a->actions;
3898
0
        const struct tc_action *action_b = b->actions;
3899
3900
0
        for (int i = 0; i < a->action_count; i++, action_a++, action_b++) {
3901
0
            if (memcmp(action_a, action_b, sizeof *action_a)) {
3902
0
                ds_put_format(&s, "\nAction %d mismatch:\n"
3903
0
                                  " - Expected Action:\n", i);
3904
0
                ds_put_sparse_hex_dump(&s, action_a, sizeof *action_a,
3905
0
                                       0, false);
3906
0
                ds_put_cstr(&s, " - Received Action:\n");
3907
0
                ds_put_sparse_hex_dump(&s, action_b, sizeof *action_b,
3908
0
                                       0, false);
3909
0
            }
3910
0
        }
3911
0
    }
3912
0
    VLOG_DBG_RL(&error_rl, "%s%s", msg, ds_cstr(&s));
3913
0
    ds_destroy(&s);
3914
0
}
3915
3916
static bool
3917
cmp_tc_flower_match_action(const struct tc_flower *a,
3918
                           const struct tc_flower *b)
3919
0
{
3920
0
    if (memcmp(&a->mask, &b->mask, sizeof a->mask)) {
3921
0
        log_tc_flower_match("tc flower compare failed mask compare:", a, b);
3922
0
        return false;
3923
0
    }
3924
3925
    /* We can not memcmp() the key as some keys might be set while the mask
3926
     * is not.*/
3927
3928
0
    for (int i = 0; i < sizeof a->key; i++) {
3929
0
        uint8_t mask = ((uint8_t *)&a->mask)[i];
3930
0
        uint8_t key_a = ((uint8_t *)&a->key)[i] & mask;
3931
0
        uint8_t key_b = ((uint8_t *)&b->key)[i] & mask;
3932
3933
0
        if (key_a != key_b) {
3934
0
            log_tc_flower_match("tc flower compare failed masked key compare:",
3935
0
                                a, b);
3936
0
            return false;
3937
0
        }
3938
0
    }
3939
3940
    /* Compare the actions. */
3941
0
    const struct tc_action *action_a = a->actions;
3942
0
    const struct tc_action *action_b = b->actions;
3943
3944
0
    if (a->action_count != b->action_count) {
3945
0
        log_tc_flower_match("tc flower compare failed action length check",
3946
0
                            a, b);
3947
0
        return false;
3948
0
    }
3949
3950
0
    for (int i = 0; i < a->action_count; i++, action_a++, action_b++) {
3951
0
        if (memcmp(action_a, action_b, sizeof *action_a)) {
3952
0
            log_tc_flower_match("tc flower compare failed action compare",
3953
0
                                a, b);
3954
0
            return false;
3955
0
        }
3956
0
    }
3957
3958
0
    return true;
3959
0
}
3960
3961
int
3962
tc_replace_flower(struct tcf_id *id, struct tc_flower *flower)
3963
0
{
3964
0
    struct ofpbuf request;
3965
0
    struct ofpbuf *reply;
3966
0
    int error = 0;
3967
0
    size_t basic_offset;
3968
0
    uint16_t eth_type = (OVS_FORCE uint16_t) flower->key.eth_type;
3969
3970
0
    request_from_tcf_id(id, eth_type, RTM_NEWTFILTER,
3971
0
                        NLM_F_CREATE | NLM_F_ECHO, &request);
3972
3973
0
    nl_msg_put_string(&request, TCA_KIND, "flower");
3974
0
    basic_offset = nl_msg_start_nested(&request, TCA_OPTIONS);
3975
0
    {
3976
0
        error = nl_msg_put_flower_options(&request, flower);
3977
3978
0
        if (error) {
3979
0
            ofpbuf_uninit(&request);
3980
0
            return error;
3981
0
        }
3982
0
    }
3983
0
    nl_msg_end_nested(&request, basic_offset);
3984
3985
0
    error = tc_transact(&request, &reply);
3986
0
    if (!error) {
3987
0
        struct ofpbuf b = ofpbuf_const_initializer(reply->data, reply->size);
3988
0
        struct nlmsghdr *nlmsg = ofpbuf_try_pull(&b, sizeof *nlmsg);
3989
0
        struct tcmsg *tc = ofpbuf_try_pull(&b, sizeof *tc);
3990
0
        bool is_probe = id->prio == TC_RESERVED_PRIORITY_FEATURE_PROBE;
3991
3992
0
        if (!nlmsg || !tc) {
3993
0
            COVERAGE_INC(tc_netlink_malformed_reply);
3994
0
            ofpbuf_delete(reply);
3995
0
            return EPROTO;
3996
0
        }
3997
3998
0
        id->prio = tc_get_major(tc->tcm_info);
3999
0
        id->handle = tc->tcm_handle;
4000
4001
0
        if (id->prio != TC_RESERVED_PRIORITY_POLICE) {
4002
0
            struct tc_flower flower_out;
4003
0
            struct tcf_id id_out;
4004
0
            int ret;
4005
4006
0
            ret = parse_netlink_to_tc_flower(reply, &id_out, &flower_out,
4007
0
                                             false);
4008
4009
0
            if (ret || !cmp_tc_flower_match_action(flower, &flower_out)) {
4010
0
                if (is_probe) {
4011
0
                    error = EINVAL;
4012
0
                } else {
4013
0
                    VLOG_WARN_RL(&error_rl, "Kernel flower acknowledgment "
4014
0
                                            "does not match request!  Set "
4015
0
                                            "dpif_netlink to dbg to see "
4016
0
                                            "which rule caused this error.");
4017
0
                }
4018
0
            }
4019
0
        }
4020
0
        ofpbuf_delete(reply);
4021
0
    }
4022
4023
0
    return error;
4024
0
}
4025
4026
void
4027
tc_set_policy(const char *policy)
4028
0
{
4029
0
    if (!policy) {
4030
0
        return;
4031
0
    }
4032
4033
0
    if (!strcmp(policy, "skip_sw")) {
4034
0
        tc_policy = TC_POLICY_SKIP_SW;
4035
0
    } else if (!strcmp(policy, "skip_hw")) {
4036
0
        tc_policy = TC_POLICY_SKIP_HW;
4037
0
    } else if (!strcmp(policy, "none")) {
4038
0
        tc_policy = TC_POLICY_NONE;
4039
0
    } else {
4040
0
        VLOG_WARN("tc: Invalid policy '%s'", policy);
4041
0
        return;
4042
0
    }
4043
4044
0
    VLOG_INFO("tc: Using policy '%s'", policy);
4045
0
}
4046
4047
void
4048
nl_msg_put_act_tc_policy_flag(struct ofpbuf *request)
4049
0
{
4050
0
    int flag = 0;
4051
4052
0
    if (!request) {
4053
0
        return;
4054
0
    }
4055
4056
0
    if (tc_policy == TC_POLICY_SKIP_HW) {
4057
0
        flag = TCA_ACT_FLAGS_SKIP_HW;
4058
0
    } else if (tc_policy == TC_POLICY_SKIP_SW) {
4059
0
        flag = TCA_ACT_FLAGS_SKIP_SW;
4060
0
    }
4061
4062
0
    if (flag) {
4063
0
        struct nla_bitfield32 flags = { flag, flag };
4064
0
        nl_msg_put_unspec(request, TCA_ACT_FLAGS, &flags, sizeof flags);
4065
0
    }
4066
0
}