Coverage Report

Created: 2025-10-10 06:39

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