Coverage Report

Created: 2025-07-18 06:07

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