Coverage Report

Created: 2026-07-16 06:13

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/openvswitch/lib/netdev-native-tnl.c
Line
Count
Source
1
/*
2
 * Copyright (c) 2016 Nicira, Inc.
3
 * Copyright (c) 2016 Red Hat, Inc.
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
20
#include "netdev-native-tnl.h"
21
22
#include <errno.h>
23
#include <fcntl.h>
24
#include <sys/socket.h>
25
#include <net/if.h>
26
#include <sys/types.h>
27
#include <netinet/in.h>
28
#include <netinet/ip.h>
29
#include <netinet/ip6.h>
30
#include <sys/ioctl.h>
31
32
#include <stdlib.h>
33
#include <sys/time.h>
34
35
#include "byte-order.h"
36
#include "coverage.h"
37
#include "csum.h"
38
#include "dp-packet.h"
39
#include "dpif-offload.h"
40
#include "netdev.h"
41
#include "netdev-vport.h"
42
#include "netdev-vport-private.h"
43
#include "odp-netlink.h"
44
#include "packets.h"
45
#include "seq.h"
46
#include "unaligned.h"
47
#include "unixctl.h"
48
#include "util.h"
49
#include "openvswitch/vlog.h"
50
51
VLOG_DEFINE_THIS_MODULE(native_tnl);
52
static struct vlog_rate_limit err_rl = VLOG_RATE_LIMIT_INIT(60, 5);
53
54
COVERAGE_DEFINE(native_tnl_l3csum_checked);
55
COVERAGE_DEFINE(native_tnl_l3csum_err);
56
COVERAGE_DEFINE(native_tnl_l4csum_checked);
57
COVERAGE_DEFINE(native_tnl_l4csum_err);
58
59
0
#define VXLAN_HLEN   (sizeof(struct udp_header) +         \
60
0
                      sizeof(struct vxlanhdr))
61
62
0
#define GENEVE_BASE_HLEN   (sizeof(struct udp_header) +         \
63
0
                            sizeof(struct genevehdr))
64
65
0
#define GTPU_HLEN   (sizeof(struct udp_header) +        \
66
0
                     sizeof(struct gtpuhdr))
67
68
uint16_t tnl_udp_port_min = 32768;
69
uint16_t tnl_udp_port_max = 61000;
70
71
ovs_be16
72
netdev_tnl_get_src_port(struct dp_packet *packet)
73
0
{
74
0
    uint32_t hash;
75
76
0
    if (OVS_LIKELY(dp_packet_rss_valid(packet))) {
77
0
        hash = dp_packet_get_rss_hash(packet);
78
0
    } else {
79
0
        struct flow flow;
80
81
0
        flow_extract(packet, &flow);
82
0
        hash = flow_hash_5tuple(&flow, 0);
83
84
0
        dp_packet_set_rss_hash(packet, hash);
85
0
    }
86
87
0
    hash = ((uint64_t) hash * (tnl_udp_port_max - tnl_udp_port_min)) >> 32;
88
89
0
    return htons(hash + tnl_udp_port_min);
90
0
}
91
92
static void *
93
ip_extract_tnl_md(struct dp_packet *packet, struct flow_tnl *tnl,
94
                  unsigned int *hlen)
95
0
{
96
0
    void *nh;
97
0
    struct ip_header *ip;
98
0
    struct ovs_16aligned_ip6_hdr *ip6;
99
0
    void *l4;
100
0
    int l3_size;
101
102
0
    nh = dp_packet_l3(packet);
103
0
    ip = nh;
104
0
    ip6 = nh;
105
0
    l4 = dp_packet_l4(packet);
106
107
0
    if (!nh || !l4) {
108
0
        return NULL;
109
0
    }
110
111
0
    *hlen = sizeof(struct eth_header);
112
113
0
    l3_size = dp_packet_size(packet) -
114
0
              ((char *)nh - (char *)dp_packet_data(packet));
115
116
0
    if (IP_VER(ip->ip_ihl_ver) == 4) {
117
0
        bool bad_csum = dp_packet_ip_checksum_bad(packet);
118
0
        ovs_be32 ip_src, ip_dst;
119
120
        /* A packet coming from a network device might have the
121
         * csum already checked. In this case, skip the check. */
122
0
        if (OVS_UNLIKELY(!bad_csum && dp_packet_ip_checksum_unknown(packet))) {
123
0
            COVERAGE_INC(native_tnl_l3csum_checked);
124
0
            if (csum(ip, IP_IHL(ip->ip_ihl_ver) * 4)) {
125
0
                dp_packet_ip_checksum_set_bad(packet);
126
0
                bad_csum = true;
127
0
            } else {
128
0
                dp_packet_ip_checksum_set_good(packet);
129
0
            }
130
0
        }
131
0
        if (OVS_UNLIKELY(bad_csum)) {
132
0
            COVERAGE_INC(native_tnl_l3csum_err);
133
0
            VLOG_WARN_RL(&err_rl, "ip packet has invalid checksum");
134
0
            return NULL;
135
0
        }
136
137
0
        if (ntohs(ip->ip_tot_len) > l3_size) {
138
0
            VLOG_WARN_RL(&err_rl, "ip packet is truncated (IP length %d, actual %d)",
139
0
                         ntohs(ip->ip_tot_len), l3_size);
140
0
            return NULL;
141
0
        }
142
0
        if (IP_IHL(ip->ip_ihl_ver) * 4 > sizeof(struct ip_header)) {
143
0
            VLOG_WARN_RL(&err_rl, "ip options not supported on tunnel packets "
144
0
                         "(%d bytes)", IP_IHL(ip->ip_ihl_ver) * 4);
145
0
            return NULL;
146
0
        }
147
148
0
        ip_src = get_16aligned_be32(&ip->ip_src);
149
0
        ip_dst = get_16aligned_be32(&ip->ip_dst);
150
151
0
        tnl->ip_src = ip_src;
152
0
        tnl->ip_dst = ip_dst;
153
0
        tnl->ip_tos = ip->ip_tos;
154
0
        tnl->ip_ttl = ip->ip_ttl;
155
156
0
        if (ip->ip_frag_off & htons(IP_DF)) {
157
0
            tnl->flags |= FLOW_TNL_F_DONT_FRAGMENT;
158
0
        }
159
160
0
        *hlen += IP_HEADER_LEN;
161
162
0
    } else if (IP_VER(ip->ip_ihl_ver) == 6) {
163
0
        ovs_be32 tc_flow = get_16aligned_be32(&ip6->ip6_flow);
164
165
0
        memcpy(tnl->ipv6_src.s6_addr, ip6->ip6_src.be16, sizeof ip6->ip6_src);
166
0
        memcpy(tnl->ipv6_dst.s6_addr, ip6->ip6_dst.be16, sizeof ip6->ip6_dst);
167
168
0
        tnl->ip_tos = ntohl(tc_flow) >> 20;
169
0
        tnl->ip_ttl = ip6->ip6_hlim;
170
171
0
        *hlen += packet->l4_ofs - packet->l3_ofs;
172
173
0
    } else {
174
0
        VLOG_WARN_RL(&err_rl, "ipv4 packet has invalid version (%d)",
175
0
                     IP_VER(ip->ip_ihl_ver));
176
0
        return NULL;
177
0
    }
178
179
0
    return l4;
180
0
}
181
182
/* Pushes the 'size' bytes of 'header' into the headroom of 'packet',
183
 * reallocating the packet if necessary.  'header' should contain an Ethernet
184
 * header, followed by an IPv4 header (without options), and an L4 header.
185
 *
186
 * This function sets the IP header's ip_tot_len field (which should be zeroed
187
 * as part of 'header') and puts its value into '*ip_tot_size' as well.  Also
188
 * updates IP header checksum if not offloaded, as well as the l3 and l4
189
 * offsets in the 'packet'.
190
 *
191
 * Return pointer to the L4 header added to 'packet'. */
192
void *
193
netdev_tnl_push_ip_header(struct dp_packet *packet, const void *header,
194
                          int size, int *ip_tot_size, ovs_be32 ipv6_label)
195
0
{
196
0
    struct eth_header *eth;
197
0
    struct ip_header *ip;
198
0
    struct ovs_16aligned_ip6_hdr *ip6;
199
200
0
    eth = dp_packet_push_uninit(packet, size);
201
0
    *ip_tot_size = dp_packet_size(packet) - sizeof (struct eth_header);
202
203
0
    memcpy(eth, header, size);
204
    /* The encapsulated packet has type Ethernet. Adjust dp_packet. */
205
0
    packet->packet_type = htonl(PT_ETH);
206
0
    dp_packet_reset_offsets(packet);
207
0
    packet->l3_ofs = sizeof (struct eth_header);
208
209
0
    if (netdev_tnl_is_header_ipv6(header)) {
210
0
        ip6 = netdev_tnl_ipv6_hdr(eth);
211
0
        *ip_tot_size -= IPV6_HEADER_LEN;
212
0
        ip6->ip6_plen = htons(*ip_tot_size);
213
0
        packet_set_ipv6_flow_label(&ip6->ip6_flow, ipv6_label);
214
0
        dp_packet_ip_checksum_set_unknown(packet);
215
216
0
        packet->l4_ofs = dp_packet_size(packet) - *ip_tot_size;
217
218
0
        return ip6 + 1;
219
0
    } else {
220
0
        ip = netdev_tnl_ip_hdr(eth);
221
0
        ip->ip_tot_len = htons(*ip_tot_size);
222
0
        *ip_tot_size -= IP_HEADER_LEN;
223
        /* Postpone checksum to when the packet is pushed to the port. */
224
0
        dp_packet_ip_checksum_set_partial(packet);
225
226
0
        packet->l4_ofs = dp_packet_size(packet) - *ip_tot_size;
227
228
0
        return ip + 1;
229
0
    }
230
0
}
231
232
static void *
233
udp_extract_tnl_md(struct dp_packet *packet, struct flow_tnl *tnl,
234
                   unsigned int *hlen)
235
0
{
236
0
    struct udp_header *udp;
237
238
0
    udp = ip_extract_tnl_md(packet, tnl, hlen);
239
0
    if (!udp) {
240
0
        return NULL;
241
0
    }
242
243
0
    if (udp->udp_csum) {
244
0
        bool bad_csum = dp_packet_l4_checksum_bad(packet);
245
246
0
        if (OVS_UNLIKELY(!bad_csum && dp_packet_l4_checksum_unknown(packet))) {
247
0
            uint32_t csum;
248
0
            COVERAGE_INC(native_tnl_l4csum_checked);
249
0
            if (netdev_tnl_is_header_ipv6(dp_packet_data(packet))) {
250
0
                csum = packet_csum_pseudoheader6(dp_packet_l3(packet));
251
0
            } else {
252
0
                csum = packet_csum_pseudoheader(dp_packet_l3(packet));
253
0
            }
254
255
0
            csum = csum_continue(csum, udp, dp_packet_size(packet) -
256
0
                                 ((const unsigned char *)udp -
257
0
                                  (const unsigned char *)dp_packet_eth(packet)
258
0
                                 ));
259
0
            if (csum_finish(csum)) {
260
0
                dp_packet_l4_checksum_set_bad(packet);
261
0
                bad_csum = true;
262
0
            } else {
263
0
                dp_packet_l4_checksum_set_good(packet);
264
0
            }
265
0
        }
266
0
        if (OVS_UNLIKELY(bad_csum)) {
267
0
            COVERAGE_INC(native_tnl_l4csum_err);
268
0
            return NULL;
269
0
        }
270
0
        tnl->flags |= FLOW_TNL_F_CSUM;
271
0
    }
272
273
0
    tnl->tp_src = udp->udp_src;
274
0
    tnl->tp_dst = udp->udp_dst;
275
276
0
    return udp + 1;
277
0
}
278
279
static void
280
tnl_ol_push(struct dp_packet *packet,
281
            const struct ovs_action_push_tnl *data)
282
0
{
283
0
    packet->offloads <<= DP_PACKET_OL_SHIFT_COUNT;
284
285
0
    if (data->tnl_type == OVS_VPORT_TYPE_GENEVE) {
286
0
        dp_packet_tunnel_set_geneve(packet);
287
0
    } else if (data->tnl_type == OVS_VPORT_TYPE_VXLAN) {
288
0
        dp_packet_tunnel_set_vxlan(packet);
289
0
    } else if (data->tnl_type == OVS_VPORT_TYPE_GRE ||
290
0
               data->tnl_type == OVS_VPORT_TYPE_IP6GRE) {
291
0
        dp_packet_tunnel_set_gre(packet);
292
0
    }
293
0
}
294
295
static void
296
tnl_ol_pop(struct dp_packet *packet, int off)
297
0
{
298
0
    packet->offloads >>= DP_PACKET_OL_SHIFT_COUNT;
299
300
0
    dp_packet_reset_packet(packet, off);
301
0
}
302
303
void
304
netdev_tnl_push_udp_header(const struct netdev *netdev OVS_UNUSED,
305
                           const struct netdev *ingress_netdev,
306
                           struct dp_packet *packet,
307
                           const struct ovs_action_push_tnl *data)
308
0
{
309
0
    uint16_t l3_ofs = packet->l3_ofs;
310
0
    uint16_t l4_ofs = packet->l4_ofs;
311
0
    struct udp_header *udp;
312
0
    ovs_be16 udp_src;
313
0
    int ip_tot_size;
314
315
    /* We may need to re-calculate the hash and this has to be done before
316
     * modifying the packet. */
317
0
    if (!ingress_netdev || !dpif_offload_netdev_udp_tnl_get_src_port(
318
0
                               ingress_netdev, packet, &udp_src)) {
319
0
        udp_src = netdev_tnl_get_src_port(packet);
320
0
    }
321
322
0
    tnl_ol_push(packet, data);
323
0
    udp = netdev_tnl_push_ip_header(packet, data->header, data->header_len,
324
0
                                    &ip_tot_size, 0);
325
326
0
    udp->udp_src = udp_src;
327
0
    udp->udp_len = htons(ip_tot_size);
328
329
0
    dp_packet_l4_proto_set_udp(packet);
330
0
    if (udp->udp_csum) {
331
0
        dp_packet_l4_checksum_set_partial(packet);
332
0
    } else {
333
0
        dp_packet_l4_checksum_set_good(packet);
334
0
    }
335
336
0
    if (l3_ofs != UINT16_MAX) {
337
0
        packet->inner_l3_ofs = l3_ofs + data->header_len;
338
0
    }
339
0
    if (l4_ofs != UINT16_MAX) {
340
0
        packet->inner_l4_ofs = l4_ofs + data->header_len;
341
0
    }
342
0
}
343
344
static void *
345
eth_build_header(struct ovs_action_push_tnl *data,
346
                 const struct netdev_tnl_build_header_params *params)
347
0
{
348
0
    uint16_t eth_proto = params->is_ipv6 ? ETH_TYPE_IPV6 : ETH_TYPE_IP;
349
0
    struct eth_header *eth;
350
351
0
    memset(data->header, 0, sizeof data->header);
352
353
0
    eth = (struct eth_header *)data->header;
354
0
    eth->eth_dst = params->dmac;
355
0
    eth->eth_src = params->smac;
356
0
    eth->eth_type = htons(eth_proto);
357
0
    data->header_len = sizeof(struct eth_header);
358
0
    return eth + 1;
359
0
}
360
361
void *
362
netdev_tnl_ip_build_header(struct ovs_action_push_tnl *data,
363
                           const struct netdev_tnl_build_header_params *params,
364
                           uint8_t next_proto, ovs_be32 ipv6_label)
365
0
{
366
0
    void *l3;
367
368
0
    l3 = eth_build_header(data, params);
369
0
    if (!params->is_ipv6) {
370
0
        ovs_be32 ip_src = in6_addr_get_mapped_ipv4(params->s_ip);
371
0
        struct ip_header *ip;
372
373
0
        ip = (struct ip_header *) l3;
374
375
0
        ip->ip_ihl_ver = IP_IHL_VER(5, 4);
376
0
        ip->ip_tos = params->flow->tunnel.ip_tos;
377
0
        ip->ip_ttl = params->flow->tunnel.ip_ttl;
378
0
        ip->ip_proto = next_proto;
379
0
        put_16aligned_be32(&ip->ip_src, ip_src);
380
0
        put_16aligned_be32(&ip->ip_dst, params->flow->tunnel.ip_dst);
381
382
0
        ip->ip_frag_off = (params->flow->tunnel.flags & FLOW_TNL_F_DONT_FRAGMENT) ?
383
0
                          htons(IP_DF) : 0;
384
385
        /* The checksum will be calculated when the headers are pushed
386
         * to the packet if offloading is not enabled. */
387
388
0
        data->header_len += IP_HEADER_LEN;
389
0
        return ip + 1;
390
0
    } else {
391
0
        struct ovs_16aligned_ip6_hdr *ip6;
392
393
0
        ip6 = (struct ovs_16aligned_ip6_hdr *) l3;
394
395
0
        put_16aligned_be32(&ip6->ip6_flow, htonl(6 << 28) |
396
0
                           htonl(params->flow->tunnel.ip_tos << 20) |
397
0
                           (ipv6_label & htonl(IPV6_LABEL_MASK)));
398
0
        ip6->ip6_hlim = params->flow->tunnel.ip_ttl;
399
0
        ip6->ip6_nxt = next_proto;
400
0
        memcpy(&ip6->ip6_src, params->s_ip, sizeof(ovs_be32[4]));
401
0
        memcpy(&ip6->ip6_dst, &params->flow->tunnel.ipv6_dst, sizeof(ovs_be32[4]));
402
403
0
        data->header_len += IPV6_HEADER_LEN;
404
0
        return ip6 + 1;
405
0
    }
406
0
}
407
408
static void *
409
udp_build_header(const struct netdev_tunnel_config *tnl_cfg,
410
                 struct ovs_action_push_tnl *data,
411
                 const struct netdev_tnl_build_header_params *params)
412
0
{
413
0
    struct udp_header *udp;
414
415
0
    udp = netdev_tnl_ip_build_header(data, params, IPPROTO_UDP, 0);
416
0
    udp->udp_dst = tnl_cfg->dst_port;
417
418
0
    if (params->flow->tunnel.flags & FLOW_TNL_F_CSUM) {
419
        /* Write a value in now to mark that we should compute the checksum
420
         * later. 0xffff is handy because it is transparent to the
421
         * calculation. */
422
0
        udp->udp_csum = htons(0xffff);
423
0
    }
424
0
    data->header_len += sizeof *udp;
425
0
    return udp + 1;
426
0
}
427
428
static int
429
gre_header_len(ovs_be16 flags)
430
0
{
431
0
    int hlen = 4;
432
433
0
    if (flags & htons(GRE_CSUM)) {
434
0
        hlen += 4;
435
0
    }
436
0
    if (flags & htons(GRE_KEY)) {
437
0
        hlen += 4;
438
0
    }
439
0
    if (flags & htons(GRE_SEQ)) {
440
0
        hlen += 4;
441
0
    }
442
0
    return hlen;
443
0
}
444
445
static int
446
parse_gre_header(struct dp_packet *packet,
447
                 struct flow_tnl *tnl)
448
0
{
449
0
    const struct gre_base_hdr *greh;
450
0
    ovs_16aligned_be32 *options;
451
0
    int hlen;
452
0
    unsigned int ulen;
453
0
    uint16_t greh_protocol;
454
455
0
    greh = ip_extract_tnl_md(packet, tnl, &ulen);
456
0
    if (!greh) {
457
0
        return -EINVAL;
458
0
    }
459
460
0
    if (greh->flags & ~(htons(GRE_CSUM | GRE_KEY | GRE_SEQ))) {
461
0
        return -EINVAL;
462
0
    }
463
464
0
    hlen = ulen + gre_header_len(greh->flags);
465
0
    if (hlen > dp_packet_size(packet)) {
466
0
        return -EINVAL;
467
0
    }
468
469
0
    options = (ovs_16aligned_be32 *)(greh + 1);
470
0
    if (greh->flags & htons(GRE_CSUM)) {
471
0
        ovs_be16 pkt_csum;
472
473
0
        pkt_csum = csum(greh, dp_packet_size(packet) -
474
0
                              ((const unsigned char *)greh -
475
0
                               (const unsigned char *)dp_packet_eth(packet)));
476
0
        if (pkt_csum) {
477
0
            return -EINVAL;
478
0
        }
479
0
        tnl->flags |= FLOW_TNL_F_CSUM;
480
0
        options++;
481
0
    }
482
483
0
    if (greh->flags & htons(GRE_KEY)) {
484
0
        tnl->tun_id = be32_to_be64(get_16aligned_be32(options));
485
0
        tnl->flags |= FLOW_TNL_F_KEY;
486
0
        options++;
487
0
    }
488
489
0
    if (greh->flags & htons(GRE_SEQ)) {
490
0
        options++;
491
0
    }
492
493
    /* Set the new packet type depending on the GRE protocol field. */
494
0
    greh_protocol = ntohs(greh->protocol);
495
0
    if (greh_protocol == ETH_TYPE_TEB) {
496
0
        packet->packet_type = htonl(PT_ETH);
497
0
    } else if (greh_protocol >= ETH_TYPE_MIN) {
498
        /* Allow all GRE protocol values above 0x5ff as Ethertypes. */
499
0
        packet->packet_type = PACKET_TYPE_BE(OFPHTN_ETHERTYPE, greh_protocol);
500
0
    } else {
501
0
        return -EINVAL;
502
0
    }
503
504
0
    return hlen;
505
0
}
506
507
struct dp_packet *
508
netdev_gre_pop_header(struct dp_packet *packet)
509
0
{
510
0
    const void *data_dp = dp_packet_data(packet);
511
0
    struct pkt_metadata *md = &packet->md;
512
0
    struct flow_tnl *tnl = &md->tunnel;
513
0
    int hlen = sizeof(struct eth_header) + 4;
514
515
0
    ovs_assert(data_dp);
516
517
0
    hlen += netdev_tnl_is_header_ipv6(data_dp) ?
518
0
            IPV6_HEADER_LEN : IP_HEADER_LEN;
519
520
0
    pkt_metadata_init_tnl(md);
521
0
    if (hlen > dp_packet_size(packet)) {
522
0
        goto err;
523
0
    }
524
525
0
    hlen = parse_gre_header(packet, tnl);
526
0
    if (hlen < 0) {
527
0
        goto err;
528
0
    }
529
530
0
    tnl_ol_pop(packet, hlen);
531
532
0
    return packet;
533
0
err:
534
0
    dp_packet_delete(packet);
535
0
    return NULL;
536
0
}
537
538
void
539
netdev_gre_push_header(const struct netdev *netdev,
540
                       const struct netdev *ingress_netdev OVS_UNUSED,
541
                       struct dp_packet *packet,
542
                       const struct ovs_action_push_tnl *data)
543
0
{
544
0
    struct netdev_vport *dev = netdev_vport_cast(netdev);
545
0
    uint16_t l3_ofs = packet->l3_ofs;
546
0
    uint16_t l4_ofs = packet->l4_ofs;
547
0
    struct gre_base_hdr *greh;
548
0
    int ip_tot_size;
549
550
0
    tnl_ol_push(packet, data);
551
552
0
    greh = netdev_tnl_push_ip_header(packet, data->header, data->header_len,
553
0
                                     &ip_tot_size, 0);
554
555
0
    if (greh->flags & htons(GRE_CSUM)) {
556
0
        ovs_be16 *csum_opt = (ovs_be16 *) (greh + 1);
557
0
        *csum_opt = csum(greh, ip_tot_size);
558
0
    }
559
560
0
    if (greh->flags & htons(GRE_SEQ)) {
561
0
        if (!dp_packet_get_tso_segsz(packet)) {
562
            /* Last 4 bytes are GRE seqno. */
563
0
            int seq_ofs = gre_header_len(greh->flags) - 4;
564
0
            ovs_16aligned_be32 *seq_opt =
565
0
                ALIGNED_CAST(ovs_16aligned_be32 *, (char *) greh + seq_ofs);
566
567
0
            put_16aligned_be32(seq_opt,
568
0
                               htonl(atomic_count_inc(&dev->gre_seqno)));
569
0
        } else {
570
0
            VLOG_WARN_RL(&err_rl, "Cannot use GRE Sequence numbers with TSO.");
571
0
        }
572
0
    }
573
574
0
    if (l3_ofs != UINT16_MAX) {
575
0
        packet->inner_l3_ofs = l3_ofs + data->header_len;
576
0
    }
577
0
    if (l4_ofs != UINT16_MAX) {
578
0
        packet->inner_l4_ofs = l4_ofs + data->header_len;
579
0
    }
580
0
}
581
582
int
583
netdev_gre_build_header(const struct netdev *netdev,
584
                        struct ovs_action_push_tnl *data,
585
                        const struct netdev_tnl_build_header_params *params)
586
0
{
587
0
    const struct netdev_tunnel_config *tnl_cfg;
588
0
    struct gre_base_hdr *greh;
589
0
    ovs_16aligned_be32 *options;
590
0
    unsigned int hlen;
591
592
0
    greh = netdev_tnl_ip_build_header(data, params, IPPROTO_GRE, 0);
593
594
0
    if (params->flow->packet_type == htonl(PT_ETH)) {
595
0
        greh->protocol = htons(ETH_TYPE_TEB);
596
0
    } else if (pt_ns(params->flow->packet_type) == OFPHTN_ETHERTYPE) {
597
0
        greh->protocol = pt_ns_type_be(params->flow->packet_type);
598
0
    } else {
599
0
        return EINVAL;
600
0
    }
601
0
    greh->flags = 0;
602
603
0
    options = (ovs_16aligned_be32 *) (greh + 1);
604
0
    if (params->flow->tunnel.flags & FLOW_TNL_F_CSUM) {
605
0
        greh->flags |= htons(GRE_CSUM);
606
0
        put_16aligned_be32(options, 0);
607
0
        options++;
608
0
    }
609
610
0
    tnl_cfg = netdev_get_tunnel_config(netdev);
611
612
0
    if (tnl_cfg->out_key_present) {
613
0
        greh->flags |= htons(GRE_KEY);
614
0
        put_16aligned_be32(options, be64_to_be32(params->flow->tunnel.tun_id));
615
0
        options++;
616
0
    }
617
618
0
    if (tnl_cfg->set_seq) {
619
0
        greh->flags |= htons(GRE_SEQ);
620
        /* seqno is updated at push header */
621
0
        options++;
622
0
    }
623
624
0
    hlen = (uint8_t *) options - (uint8_t *) greh;
625
626
0
    data->header_len += hlen;
627
0
    if (!params->is_ipv6) {
628
0
        data->tnl_type = OVS_VPORT_TYPE_GRE;
629
0
    } else {
630
0
        data->tnl_type = OVS_VPORT_TYPE_IP6GRE;
631
0
    }
632
0
    return 0;
633
0
}
634
635
struct dp_packet *
636
netdev_erspan_pop_header(struct dp_packet *packet)
637
0
{
638
0
    const struct gre_base_hdr *greh;
639
0
    const struct erspan_base_hdr *ersh;
640
0
    struct pkt_metadata *md = &packet->md;
641
0
    struct flow_tnl *tnl = &md->tunnel;
642
0
    int hlen = sizeof(struct eth_header);
643
0
    unsigned int ulen;
644
0
    uint16_t greh_protocol;
645
646
0
    hlen += netdev_tnl_is_header_ipv6(dp_packet_data(packet)) ?
647
0
            IPV6_HEADER_LEN : IP_HEADER_LEN;
648
649
0
    pkt_metadata_init_tnl(md);
650
0
    if (hlen > dp_packet_size(packet)) {
651
0
        goto err;
652
0
    }
653
654
0
    greh = ip_extract_tnl_md(packet, tnl, &ulen);
655
0
    if (!greh) {
656
0
        goto err;
657
0
    }
658
659
0
    greh_protocol = ntohs(greh->protocol);
660
0
    if (greh_protocol != ETH_TYPE_ERSPAN1 &&
661
0
        greh_protocol != ETH_TYPE_ERSPAN2) {
662
0
        goto err;
663
0
    }
664
665
0
    if (greh->flags & ~htons(GRE_SEQ)) {
666
0
        goto err;
667
0
    }
668
669
0
    ersh = ERSPAN_HDR(greh);
670
0
    tnl->tun_id = be16_to_be64(htons(get_sid(ersh)));
671
0
    tnl->erspan_ver = ersh->ver;
672
673
0
    if (ersh->ver == 1) {
674
0
        ovs_16aligned_be32 *index = ALIGNED_CAST(ovs_16aligned_be32 *,
675
0
                                                 ersh + 1);
676
0
        tnl->erspan_idx = ntohl(get_16aligned_be32(index));
677
0
        tnl->flags |= FLOW_TNL_F_KEY;
678
0
        hlen = ulen + ERSPAN_GREHDR_LEN + sizeof *ersh + ERSPAN_V1_MDSIZE;
679
0
    } else if (ersh->ver == 2) {
680
0
        struct erspan_md2 *md2 = ALIGNED_CAST(struct erspan_md2 *, ersh + 1);
681
0
        tnl->erspan_dir = md2->dir;
682
0
        tnl->erspan_hwid = get_hwid(md2);
683
0
        tnl->flags |= FLOW_TNL_F_KEY;
684
0
        hlen = ulen + ERSPAN_GREHDR_LEN + sizeof *ersh + ERSPAN_V2_MDSIZE;
685
0
    } else {
686
0
        VLOG_WARN_RL(&err_rl, "ERSPAN version error %d", ersh->ver);
687
0
        goto err;
688
0
    }
689
690
0
    if (hlen > dp_packet_size(packet)) {
691
0
        goto err;
692
0
    }
693
694
0
    tnl_ol_pop(packet, hlen);
695
696
0
    return packet;
697
0
err:
698
0
    dp_packet_delete(packet);
699
0
    return NULL;
700
0
}
701
702
void
703
netdev_erspan_push_header(const struct netdev *netdev,
704
                          const struct netdev *ingress_netdev OVS_UNUSED,
705
                          struct dp_packet *packet,
706
                          const struct ovs_action_push_tnl *data)
707
0
{
708
0
    struct netdev_vport *dev = netdev_vport_cast(netdev);
709
0
    struct erspan_base_hdr *ersh;
710
0
    struct gre_base_hdr *greh;
711
0
    struct erspan_md2 *md2;
712
0
    int ip_tot_size;
713
714
0
    greh = netdev_tnl_push_ip_header(packet, data->header, data->header_len,
715
0
                                     &ip_tot_size, 0);
716
717
    /* update GRE seqno */
718
0
    ovs_16aligned_be32 *seqno = (ovs_16aligned_be32 *) (greh + 1);
719
0
    put_16aligned_be32(seqno, htonl(atomic_count_inc(&dev->gre_seqno)));
720
721
    /* update v2 timestamp */
722
0
    if (greh->protocol == htons(ETH_TYPE_ERSPAN2)) {
723
0
        ersh = ERSPAN_HDR(greh);
724
0
        md2 = ALIGNED_CAST(struct erspan_md2 *, ersh + 1);
725
0
        put_16aligned_be32(&md2->timestamp, get_erspan_ts(ERSPAN_100US));
726
0
    }
727
0
}
728
729
int
730
netdev_erspan_build_header(const struct netdev *netdev,
731
                           struct ovs_action_push_tnl *data,
732
                           const struct netdev_tnl_build_header_params *params)
733
0
{
734
0
    const struct netdev_tunnel_config *tnl_cfg;
735
0
    struct gre_base_hdr *greh;
736
0
    struct erspan_base_hdr *ersh;
737
0
    unsigned int hlen;
738
0
    uint32_t tun_id;
739
0
    int erspan_ver;
740
0
    uint16_t sid;
741
742
0
    greh = netdev_tnl_ip_build_header(data, params, IPPROTO_GRE, 0);
743
0
    ersh = ERSPAN_HDR(greh);
744
745
0
    tun_id = ntohl(be64_to_be32(params->flow->tunnel.tun_id));
746
    /* ERSPAN only has 10-bit session ID */
747
0
    if (tun_id & ~ERSPAN_SID_MASK) {
748
0
        return EINVAL;
749
0
    } else {
750
0
        sid = (uint16_t) tun_id;
751
0
    }
752
753
0
    tnl_cfg = netdev_get_tunnel_config(netdev);
754
755
0
    if (tnl_cfg->erspan_ver_flow) {
756
0
        erspan_ver = params->flow->tunnel.erspan_ver;
757
0
    } else {
758
0
        erspan_ver = tnl_cfg->erspan_ver;
759
0
    }
760
761
0
    if (erspan_ver == 1) {
762
0
        greh->protocol = htons(ETH_TYPE_ERSPAN1);
763
0
        greh->flags = htons(GRE_SEQ);
764
0
        ersh->ver = 1;
765
0
        set_sid(ersh, sid);
766
767
0
        uint32_t erspan_idx = (tnl_cfg->erspan_idx_flow
768
0
                          ? params->flow->tunnel.erspan_idx
769
0
                          : tnl_cfg->erspan_idx);
770
0
        put_16aligned_be32(ALIGNED_CAST(ovs_16aligned_be32 *, ersh + 1),
771
0
                           htonl(erspan_idx));
772
773
0
        hlen = ERSPAN_GREHDR_LEN + sizeof *ersh + ERSPAN_V1_MDSIZE;
774
0
    } else if (erspan_ver == 2) {
775
0
        struct erspan_md2 *md2 = ALIGNED_CAST(struct erspan_md2 *, ersh + 1);
776
777
0
        greh->protocol = htons(ETH_TYPE_ERSPAN2);
778
0
        greh->flags = htons(GRE_SEQ);
779
0
        ersh->ver = 2;
780
0
        set_sid(ersh, sid);
781
782
0
        md2->sgt = 0; /* security group tag */
783
0
        md2->gra = 0;
784
0
        put_16aligned_be32(&md2->timestamp, 0);
785
786
0
        if (tnl_cfg->erspan_hwid_flow) {
787
0
            set_hwid(md2, params->flow->tunnel.erspan_hwid);
788
0
        } else {
789
0
            set_hwid(md2, tnl_cfg->erspan_hwid);
790
0
        }
791
792
0
        if (tnl_cfg->erspan_dir_flow) {
793
0
            md2->dir = params->flow->tunnel.erspan_dir;
794
0
        } else {
795
0
            md2->dir = tnl_cfg->erspan_dir;
796
0
        }
797
798
0
        hlen = ERSPAN_GREHDR_LEN + sizeof *ersh + ERSPAN_V2_MDSIZE;
799
0
    } else {
800
0
        VLOG_WARN_RL(&err_rl, "ERSPAN version error %d", tnl_cfg->erspan_ver);
801
0
        return EINVAL;
802
0
    }
803
804
0
    data->header_len += hlen;
805
806
0
    if (params->is_ipv6) {
807
0
        data->tnl_type = OVS_VPORT_TYPE_IP6ERSPAN;
808
0
    } else {
809
0
        data->tnl_type = OVS_VPORT_TYPE_ERSPAN;
810
0
    }
811
0
    return 0;
812
0
}
813
814
struct dp_packet *
815
netdev_gtpu_pop_header(struct dp_packet *packet)
816
0
{
817
0
    struct pkt_metadata *md = &packet->md;
818
0
    struct flow_tnl *tnl = &md->tunnel;
819
0
    struct gtpuhdr *gtph;
820
0
    unsigned int gtpu_hlen;
821
0
    unsigned int hlen;
822
823
0
    ovs_assert(packet->l3_ofs > 0);
824
0
    ovs_assert(packet->l4_ofs > 0);
825
826
0
    pkt_metadata_init_tnl(md);
827
0
    if (GTPU_HLEN > dp_packet_l4_size(packet)) {
828
0
        goto err;
829
0
    }
830
831
0
    gtph = udp_extract_tnl_md(packet, tnl, &hlen);
832
0
    if (!gtph) {
833
0
        goto err;
834
0
    }
835
836
0
    tnl->gtpu_flags = gtph->md.flags;
837
0
    tnl->gtpu_msgtype = gtph->md.msgtype;
838
0
    tnl->tun_id = be32_to_be64(get_16aligned_be32(&gtph->teid));
839
840
0
    if (tnl->gtpu_msgtype == GTPU_MSGTYPE_GPDU) {
841
0
        struct ip_header *ip;
842
843
0
        if (gtph->md.flags & GTPU_S_MASK) {
844
0
            gtpu_hlen = GTPU_HLEN + sizeof(struct gtpuhdr_opt);
845
0
        } else {
846
0
            gtpu_hlen = GTPU_HLEN;
847
0
        }
848
0
        ip = ALIGNED_CAST(struct ip_header *, (char *)gtph + gtpu_hlen);
849
850
0
        if (IP_VER(ip->ip_ihl_ver) == 4) {
851
0
            packet->packet_type = htonl(PT_IPV4);
852
0
        } else if (IP_VER(ip->ip_ihl_ver) == 6) {
853
0
            packet->packet_type = htonl(PT_IPV6);
854
0
        } else {
855
0
            VLOG_WARN_RL(&err_rl, "GTP-U: Receive non-IP packet.");
856
0
        }
857
0
        tnl_ol_pop(packet, hlen + gtpu_hlen);
858
0
    } else {
859
        /* non-GPDU GTP-U messages, ex: echo request, end marker.
860
         * Users should redirect these packets to controller, or.
861
         * any application that handles GTP-U messages, so keep
862
         * the original packet.
863
         */
864
0
        packet->packet_type = htonl(PT_ETH);
865
0
        VLOG_WARN_ONCE("Receive non-GPDU msgtype: %"PRIu8,
866
0
                       gtph->md.msgtype);
867
0
    }
868
869
0
    return packet;
870
871
0
err:
872
0
    dp_packet_delete(packet);
873
0
    return NULL;
874
0
}
875
876
void
877
netdev_gtpu_push_header(const struct netdev *netdev,
878
                        const struct netdev *ingress_netdev OVS_UNUSED,
879
                        struct dp_packet *packet,
880
                        const struct ovs_action_push_tnl *data)
881
0
{
882
0
    struct netdev_vport *dev = netdev_vport_cast(netdev);
883
0
    struct udp_header *udp;
884
0
    struct gtpuhdr *gtpuh;
885
0
    ovs_be16 udp_src;
886
0
    int ip_tot_size;
887
0
    unsigned int payload_len;
888
889
    /* We may need to re-calculate the hash and this has to be done before
890
     * modifying the packet. */
891
0
    udp_src = netdev_tnl_get_src_port(packet);
892
893
0
    payload_len = dp_packet_size(packet);
894
0
    udp = netdev_tnl_push_ip_header(packet, data->header, data->header_len,
895
0
                                    &ip_tot_size, 0);
896
0
    udp->udp_src = udp_src;
897
0
    udp->udp_len = htons(ip_tot_size);
898
    /* Postpone checksum to the egress netdev. */
899
0
    dp_packet_l4_proto_set_udp(packet);
900
0
    dp_packet_l4_checksum_set_partial(packet);
901
902
0
    gtpuh = ALIGNED_CAST(struct gtpuhdr *, udp + 1);
903
904
0
    if (gtpuh->md.flags & GTPU_S_MASK) {
905
0
        ovs_be16 *seqno = ALIGNED_CAST(ovs_be16 *, gtpuh + 1);
906
0
        *seqno = htons(atomic_count_inc(&dev->gre_seqno));
907
0
        payload_len += sizeof(struct gtpuhdr_opt);
908
0
    }
909
0
    gtpuh->len = htons(payload_len);
910
0
}
911
912
int
913
netdev_gtpu_build_header(const struct netdev *netdev,
914
                         struct ovs_action_push_tnl *data,
915
                         const struct netdev_tnl_build_header_params *params)
916
0
{
917
0
    const struct netdev_tunnel_config *tnl_cfg;
918
0
    struct gtpuhdr *gtph;
919
0
    unsigned int gtpu_hlen;
920
921
0
    tnl_cfg = netdev_get_tunnel_config(netdev);
922
923
0
    gtph = udp_build_header(tnl_cfg, data, params);
924
925
    /* Set to default if not set in flow. */
926
0
    gtph->md.flags = params->flow->tunnel.gtpu_flags ?
927
0
                     params->flow->tunnel.gtpu_flags : GTPU_FLAGS_DEFAULT;
928
0
    gtph->md.msgtype = params->flow->tunnel.gtpu_msgtype ?
929
0
                       params->flow->tunnel.gtpu_msgtype : GTPU_MSGTYPE_GPDU;
930
0
    put_16aligned_be32(&gtph->teid,
931
0
                       be64_to_be32(params->flow->tunnel.tun_id));
932
933
0
    gtpu_hlen = sizeof *gtph;
934
0
    if (tnl_cfg->set_seq) {
935
0
        gtph->md.flags |= GTPU_S_MASK;
936
0
        gtpu_hlen += sizeof(struct gtpuhdr_opt);
937
0
    }
938
939
0
    data->header_len += gtpu_hlen;
940
0
    data->tnl_type = OVS_VPORT_TYPE_GTPU;
941
942
0
    return 0;
943
0
}
944
945
int
946
netdev_srv6_build_header(const struct netdev *netdev,
947
                         struct ovs_action_push_tnl *data,
948
                         const struct netdev_tnl_build_header_params *params)
949
0
{
950
0
    const struct netdev_tunnel_config *tnl_cfg;
951
0
    union ovs_16aligned_in6_addr *s;
952
0
    const struct in6_addr *segs;
953
0
    struct srv6_base_hdr *srh;
954
0
    ovs_be16 dl_type;
955
0
    int nr_segs;
956
0
    int i;
957
958
0
    tnl_cfg = netdev_get_tunnel_config(netdev);
959
0
    if (tnl_cfg->srv6_num_segs) {
960
0
        nr_segs = tnl_cfg->srv6_num_segs;
961
0
        segs = tnl_cfg->srv6_segs;
962
0
    } else {
963
        /*
964
         * If explicit segment list setting is omitted, tunnel destination
965
         * is considered to be the first segment list.
966
         */
967
0
        nr_segs = 1;
968
0
        segs = &params->flow->tunnel.ipv6_dst;
969
0
    }
970
971
0
    if (!ipv6_addr_equals(&segs[0], &params->flow->tunnel.ipv6_dst)) {
972
0
        return EINVAL;
973
0
    }
974
975
    /* Writes the netdev_srv6_flowlabel enum value to the ipv6
976
     * flowlabel field. It must later be replaced by a valid value
977
     * in the header push. */
978
0
    srh = netdev_tnl_ip_build_header(data, params, IPPROTO_ROUTING,
979
0
                                     htonl(tnl_cfg->srv6_flowlabel));
980
981
0
    srh->rt_hdr.segments_left = nr_segs - 1;
982
0
    srh->rt_hdr.type = IPV6_SRCRT_TYPE_4;
983
0
    srh->rt_hdr.hdrlen = 2 * nr_segs;
984
0
    srh->last_entry = nr_segs - 1;
985
0
    srh->flags = 0;
986
0
    srh->tag = 0;
987
988
0
    dl_type = params->flow->dl_type;
989
0
    if (dl_type == htons(ETH_TYPE_IP)) {
990
0
        srh->rt_hdr.nexthdr = IPPROTO_IPIP;
991
0
    } else if (dl_type == htons(ETH_TYPE_IPV6)) {
992
0
        srh->rt_hdr.nexthdr = IPPROTO_IPV6;
993
0
    } else {
994
0
        return EOPNOTSUPP;
995
0
    }
996
997
0
    s = (union ovs_16aligned_in6_addr *) (srh + 1);
998
0
    for (i = 0; i < nr_segs; i++) {
999
        /* Segment list is written to the header in reverse order. */
1000
0
        memcpy(s, &segs[nr_segs - i - 1], sizeof *s);
1001
0
        s++;
1002
0
    }
1003
1004
0
    data->header_len += sizeof *srh + 8 * srh->rt_hdr.hdrlen;
1005
0
    data->tnl_type = OVS_VPORT_TYPE_SRV6;
1006
1007
0
    return 0;
1008
0
}
1009
1010
void
1011
netdev_srv6_push_header(const struct netdev *netdev OVS_UNUSED,
1012
                        const struct netdev *ingress_netdev OVS_UNUSED,
1013
                        struct dp_packet *packet,
1014
                        const struct ovs_action_push_tnl *data)
1015
0
{
1016
0
    struct ovs_16aligned_ip6_hdr *inner_ip6, *outer_ip6;
1017
0
    enum netdev_srv6_flowlabel srv6_flowlabel;
1018
0
    ovs_be32 ipv6_label = 0;
1019
0
    int ip_tot_size;
1020
0
    uint32_t flow;
1021
1022
0
    inner_ip6 = dp_packet_l3(packet);
1023
0
    outer_ip6 = netdev_tnl_ipv6_hdr((void *) data->header);
1024
0
    srv6_flowlabel = ntohl(get_16aligned_be32(&outer_ip6->ip6_flow)) &
1025
0
                     IPV6_LABEL_MASK;
1026
1027
0
    switch (srv6_flowlabel) {
1028
0
    case SRV6_FLOWLABEL_COPY:
1029
0
        flow = ntohl(get_16aligned_be32(&inner_ip6->ip6_flow));
1030
0
        ipv6_label = (flow >> 28) == 6 ? htonl(flow & IPV6_LABEL_MASK) : 0;
1031
0
        break;
1032
1033
0
    case SRV6_FLOWLABEL_ZERO:
1034
0
        ipv6_label = 0;
1035
0
        break;
1036
1037
0
    case SRV6_FLOWLABEL_COMPUTE:
1038
0
        ipv6_label = htonl(dp_packet_get_rss_hash(packet) & IPV6_LABEL_MASK);
1039
0
        break;
1040
0
    }
1041
1042
0
    netdev_tnl_push_ip_header(packet, data->header,
1043
0
                              data->header_len, &ip_tot_size, ipv6_label);
1044
0
}
1045
1046
struct dp_packet *
1047
netdev_srv6_pop_header(struct dp_packet *packet)
1048
0
{
1049
0
    const struct ovs_16aligned_ip6_hdr *nh = dp_packet_l3(packet);
1050
0
    struct pkt_metadata *md = &packet->md;
1051
0
    struct flow_tnl *tnl = &md->tunnel;
1052
0
    const struct ip6_rt_hdr *rt_hdr;
1053
0
    uint8_t nw_proto = nh->ip6_nxt;
1054
0
    const void *data = nh + 1;
1055
0
    uint8_t nw_frag = 0;
1056
0
    unsigned int hlen;
1057
0
    size_t size;
1058
1059
    /*
1060
     * Verifies that the routing header is present in the IPv6
1061
     * extension headers and that its type is SRv6.
1062
     */
1063
0
    size = dp_packet_l3_size(packet);
1064
0
    if (size < IPV6_HEADER_LEN) {
1065
0
        goto err;
1066
0
    }
1067
0
    size -= IPV6_HEADER_LEN;
1068
1069
0
    if (!parse_ipv6_ext_hdrs(&data, &size, &nw_proto, &nw_frag,
1070
0
                             NULL, &rt_hdr)) {
1071
0
        goto err;
1072
0
    }
1073
1074
0
    if (!rt_hdr || rt_hdr->type != IPV6_SRCRT_TYPE_4) {
1075
0
        goto err;
1076
0
    }
1077
1078
0
    if (rt_hdr->segments_left > 0) {
1079
0
        VLOG_WARN_RL(&err_rl, "invalid srv6 segments_left=%d\n",
1080
0
                     rt_hdr->segments_left);
1081
0
        goto err;
1082
0
    }
1083
1084
0
    if (rt_hdr->nexthdr == IPPROTO_IPIP) {
1085
0
        packet->packet_type = htonl(PT_IPV4);
1086
0
    } else if (rt_hdr->nexthdr == IPPROTO_IPV6) {
1087
0
        packet->packet_type = htonl(PT_IPV6);
1088
0
    } else {
1089
0
        goto err;
1090
0
    }
1091
1092
0
    pkt_metadata_init_tnl(md);
1093
0
    if (!ip_extract_tnl_md(packet, tnl, &hlen)) {
1094
0
        goto err;
1095
0
    }
1096
1097
0
    tnl_ol_pop(packet, hlen);
1098
1099
0
    return packet;
1100
0
err:
1101
0
    dp_packet_delete(packet);
1102
0
    return NULL;
1103
0
}
1104
1105
struct dp_packet *
1106
netdev_vxlan_pop_header(struct dp_packet *packet)
1107
0
{
1108
0
    struct pkt_metadata *md = &packet->md;
1109
0
    struct flow_tnl *tnl = &md->tunnel;
1110
0
    struct vxlanhdr *vxh;
1111
0
    unsigned int hlen;
1112
0
    ovs_be32 vx_flags;
1113
0
    enum packet_type next_pt = PT_ETH;
1114
1115
0
    ovs_assert(packet->l3_ofs > 0);
1116
0
    ovs_assert(packet->l4_ofs > 0);
1117
1118
0
    pkt_metadata_init_tnl(md);
1119
0
    if (VXLAN_HLEN > dp_packet_l4_size(packet)) {
1120
0
        goto err;
1121
0
    }
1122
1123
0
    vxh = udp_extract_tnl_md(packet, tnl, &hlen);
1124
0
    if (!vxh) {
1125
0
        goto err;
1126
0
    }
1127
1128
0
    vx_flags = get_16aligned_be32(&vxh->vx_flags);
1129
0
    if (vx_flags & htonl(VXLAN_HF_GPE)) {
1130
0
        vx_flags &= htonl(~VXLAN_GPE_USED_BITS);
1131
        /* Drop the OAM packets */
1132
0
        if (vxh->vx_gpe.flags & VXLAN_GPE_FLAGS_O) {
1133
0
            goto err;
1134
0
        }
1135
0
        switch (vxh->vx_gpe.next_protocol) {
1136
0
        case VXLAN_GPE_NP_IPV4:
1137
0
            next_pt = PT_IPV4;
1138
0
            break;
1139
0
        case VXLAN_GPE_NP_IPV6:
1140
0
            next_pt = PT_IPV6;
1141
0
            break;
1142
0
        case VXLAN_GPE_NP_NSH:
1143
0
            next_pt = PT_NSH;
1144
0
            break;
1145
0
        case VXLAN_GPE_NP_ETHERNET:
1146
0
            next_pt = PT_ETH;
1147
0
            break;
1148
0
        default:
1149
0
            goto err;
1150
0
        }
1151
0
    }
1152
1153
0
    if (vx_flags != htonl(VXLAN_FLAGS) ||
1154
0
       (get_16aligned_be32(&vxh->vx_vni) & htonl(0xff))) {
1155
0
        VLOG_WARN_RL(&err_rl, "invalid vxlan flags=%#x vni=%#x\n",
1156
0
                     ntohl(vx_flags),
1157
0
                     ntohl(get_16aligned_be32(&vxh->vx_vni)));
1158
0
        goto err;
1159
0
    }
1160
0
    tnl->tun_id = htonll(ntohl(get_16aligned_be32(&vxh->vx_vni)) >> 8);
1161
0
    tnl->flags |= FLOW_TNL_F_KEY;
1162
1163
0
    packet->packet_type = htonl(next_pt);
1164
0
    tnl_ol_pop(packet, hlen + VXLAN_HLEN);
1165
0
    if (next_pt != PT_ETH) {
1166
0
        packet->l3_ofs = 0;
1167
0
    }
1168
1169
0
    return packet;
1170
0
err:
1171
0
    dp_packet_delete(packet);
1172
0
    return NULL;
1173
0
}
1174
1175
int
1176
netdev_vxlan_build_header(const struct netdev *netdev,
1177
                          struct ovs_action_push_tnl *data,
1178
                          const struct netdev_tnl_build_header_params *params)
1179
0
{
1180
0
    const struct netdev_tunnel_config *tnl_cfg;
1181
0
    struct vxlanhdr *vxh;
1182
1183
0
    tnl_cfg = netdev_get_tunnel_config(netdev);
1184
1185
0
    vxh = udp_build_header(tnl_cfg, data, params);
1186
1187
0
    if (tnl_cfg->exts & (1 << OVS_VXLAN_EXT_GPE)) {
1188
0
        put_16aligned_be32(&vxh->vx_flags, htonl(VXLAN_FLAGS | VXLAN_HF_GPE));
1189
0
        put_16aligned_be32(&vxh->vx_vni,
1190
0
                           htonl(ntohll(params->flow->tunnel.tun_id) << 8));
1191
0
        if (params->flow->packet_type == htonl(PT_ETH)) {
1192
0
            vxh->vx_gpe.next_protocol = VXLAN_GPE_NP_ETHERNET;
1193
0
        } else if (pt_ns(params->flow->packet_type) == OFPHTN_ETHERTYPE) {
1194
0
            switch (pt_ns_type(params->flow->packet_type)) {
1195
0
            case ETH_TYPE_IP:
1196
0
                vxh->vx_gpe.next_protocol = VXLAN_GPE_NP_IPV4;
1197
0
                break;
1198
0
            case ETH_TYPE_IPV6:
1199
0
                vxh->vx_gpe.next_protocol = VXLAN_GPE_NP_IPV6;
1200
0
                break;
1201
0
            case ETH_TYPE_NSH:
1202
0
                vxh->vx_gpe.next_protocol = VXLAN_GPE_NP_NSH;
1203
0
                break;
1204
0
            case ETH_TYPE_TEB:
1205
0
                vxh->vx_gpe.next_protocol = VXLAN_GPE_NP_ETHERNET;
1206
0
                break;
1207
0
            default:
1208
0
                return EINVAL;
1209
0
            }
1210
0
        } else {
1211
0
            return EINVAL;
1212
0
        }
1213
0
    } else {
1214
0
        put_16aligned_be32(&vxh->vx_flags, htonl(VXLAN_FLAGS));
1215
0
        put_16aligned_be32(&vxh->vx_vni,
1216
0
                           htonl(ntohll(params->flow->tunnel.tun_id) << 8));
1217
0
    }
1218
1219
0
    data->header_len += sizeof *vxh;
1220
0
    data->tnl_type = OVS_VPORT_TYPE_VXLAN;
1221
0
    return 0;
1222
0
}
1223
1224
struct dp_packet *
1225
netdev_geneve_pop_header(struct dp_packet *packet)
1226
0
{
1227
0
    struct pkt_metadata *md = &packet->md;
1228
0
    struct flow_tnl *tnl = &md->tunnel;
1229
0
    struct genevehdr *gnh;
1230
0
    unsigned int hlen, opts_len, ulen;
1231
1232
0
    pkt_metadata_init_tnl(md);
1233
0
    if (GENEVE_BASE_HLEN > dp_packet_l4_size(packet)) {
1234
0
        VLOG_WARN_RL(&err_rl, "geneve packet too small: min header=%u packet size=%"PRIuSIZE"\n",
1235
0
                     (unsigned int)GENEVE_BASE_HLEN, dp_packet_l4_size(packet));
1236
0
        goto err;
1237
0
    }
1238
1239
0
    gnh = udp_extract_tnl_md(packet, tnl, &ulen);
1240
0
    if (!gnh) {
1241
0
        goto err;
1242
0
    }
1243
1244
0
    opts_len = gnh->opt_len * 4;
1245
0
    hlen = ulen + GENEVE_BASE_HLEN + opts_len;
1246
0
    if (hlen > dp_packet_size(packet)) {
1247
0
        VLOG_WARN_RL(&err_rl, "geneve packet too small: header len=%u packet size=%u\n",
1248
0
                     hlen, dp_packet_size(packet));
1249
0
        goto err;
1250
0
    }
1251
1252
0
    if (gnh->ver != 0) {
1253
0
        VLOG_WARN_RL(&err_rl, "unknown geneve version: %"PRIu8"\n", gnh->ver);
1254
0
        goto err;
1255
0
    }
1256
1257
0
    if (gnh->proto_type != htons(ETH_TYPE_TEB)) {
1258
0
        VLOG_WARN_RL(&err_rl, "unknown geneve encapsulated protocol: %#x\n",
1259
0
                     ntohs(gnh->proto_type));
1260
0
        goto err;
1261
0
    }
1262
1263
0
    tnl->flags |= gnh->oam ? FLOW_TNL_F_OAM : 0;
1264
0
    tnl->tun_id = htonll(ntohl(get_16aligned_be32(&gnh->vni)) >> 8);
1265
0
    tnl->flags |= FLOW_TNL_F_KEY;
1266
1267
0
    memcpy(tnl->metadata.opts.gnv, gnh->options, opts_len);
1268
0
    tnl->metadata.present.len = opts_len;
1269
0
    tnl->flags |= FLOW_TNL_F_UDPIF;
1270
1271
0
    packet->packet_type = htonl(PT_ETH);
1272
0
    tnl_ol_pop(packet, hlen);
1273
1274
0
    return packet;
1275
0
err:
1276
0
    dp_packet_delete(packet);
1277
0
    return NULL;
1278
0
}
1279
1280
int
1281
netdev_geneve_build_header(const struct netdev *netdev,
1282
                           struct ovs_action_push_tnl *data,
1283
                           const struct netdev_tnl_build_header_params *params)
1284
0
{
1285
0
    struct genevehdr *gnh;
1286
0
    int opt_len;
1287
0
    bool crit_opt;
1288
1289
0
    gnh = udp_build_header(netdev_get_tunnel_config(netdev), data, params);
1290
1291
0
    put_16aligned_be32(&gnh->vni, htonl(ntohll(params->flow->tunnel.tun_id) << 8));
1292
1293
0
    opt_len = tun_metadata_to_geneve_header(&params->flow->tunnel,
1294
0
                                            gnh->options, &crit_opt);
1295
1296
0
    gnh->opt_len = opt_len / 4;
1297
0
    gnh->oam = !!(params->flow->tunnel.flags & FLOW_TNL_F_OAM);
1298
0
    gnh->critical = crit_opt ? 1 : 0;
1299
0
    gnh->proto_type = htons(ETH_TYPE_TEB);
1300
1301
0
    data->header_len += sizeof *gnh + opt_len;
1302
0
    data->tnl_type = OVS_VPORT_TYPE_GENEVE;
1303
0
    return 0;
1304
0
}
1305
1306

1307
void
1308
netdev_tnl_egress_port_range(struct unixctl_conn *conn, int argc,
1309
                             const char *argv[], void *aux OVS_UNUSED)
1310
0
{
1311
0
    int val1, val2;
1312
1313
0
    if (argc < 3) {
1314
0
        struct ds ds = DS_EMPTY_INITIALIZER;
1315
1316
0
        ds_put_format(&ds, "Tunnel UDP source port range: %"PRIu16"-%"PRIu16"\n",
1317
0
                            tnl_udp_port_min, tnl_udp_port_max);
1318
1319
0
        unixctl_command_reply(conn, ds_cstr(&ds));
1320
0
        ds_destroy(&ds);
1321
0
        return;
1322
0
    }
1323
1324
0
    if (argc != 3) {
1325
0
        return;
1326
0
    }
1327
1328
0
    val1 = atoi(argv[1]);
1329
0
    if (val1 <= 0 || val1 > UINT16_MAX) {
1330
0
        unixctl_command_reply(conn, "Invalid min.");
1331
0
        return;
1332
0
    }
1333
0
    val2 = atoi(argv[2]);
1334
0
    if (val2 <= 0 || val2 > UINT16_MAX) {
1335
0
        unixctl_command_reply(conn, "Invalid max.");
1336
0
        return;
1337
0
    }
1338
1339
0
    if (val1 > val2) {
1340
0
        tnl_udp_port_min = val2;
1341
0
        tnl_udp_port_max = val1;
1342
0
    } else {
1343
0
        tnl_udp_port_min = val1;
1344
0
        tnl_udp_port_max = val2;
1345
0
    }
1346
0
    seq_change(tnl_conf_seq);
1347
1348
0
    unixctl_command_reply(conn, "OK");
1349
0
}