Coverage Report

Created: 2023-03-26 07:41

/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 "csum.h"
37
#include "dp-packet.h"
38
#include "netdev.h"
39
#include "netdev-vport.h"
40
#include "netdev-vport-private.h"
41
#include "odp-netlink.h"
42
#include "packets.h"
43
#include "seq.h"
44
#include "unaligned.h"
45
#include "unixctl.h"
46
#include "openvswitch/vlog.h"
47
48
VLOG_DEFINE_THIS_MODULE(native_tnl);
49
static struct vlog_rate_limit err_rl = VLOG_RATE_LIMIT_INIT(60, 5);
50
51
0
#define VXLAN_HLEN   (sizeof(struct udp_header) +         \
52
0
                      sizeof(struct vxlanhdr))
53
54
0
#define GENEVE_BASE_HLEN   (sizeof(struct udp_header) +         \
55
0
                            sizeof(struct genevehdr))
56
57
0
#define GTPU_HLEN   (sizeof(struct udp_header) +        \
58
0
                     sizeof(struct gtpuhdr))
59
60
uint16_t tnl_udp_port_min = 32768;
61
uint16_t tnl_udp_port_max = 61000;
62
63
void *
64
netdev_tnl_ip_extract_tnl_md(struct dp_packet *packet, struct flow_tnl *tnl,
65
                  unsigned int *hlen)
66
0
{
67
0
    void *nh;
68
0
    struct ip_header *ip;
69
0
    struct ovs_16aligned_ip6_hdr *ip6;
70
0
    void *l4;
71
0
    int l3_size;
72
73
0
    nh = dp_packet_l3(packet);
74
0
    ip = nh;
75
0
    ip6 = nh;
76
0
    l4 = dp_packet_l4(packet);
77
78
0
    if (!nh || !l4) {
79
0
        return NULL;
80
0
    }
81
82
0
    *hlen = sizeof(struct eth_header);
83
84
0
    l3_size = dp_packet_size(packet) -
85
0
              ((char *)nh - (char *)dp_packet_data(packet));
86
87
0
    if (IP_VER(ip->ip_ihl_ver) == 4) {
88
89
0
        ovs_be32 ip_src, ip_dst;
90
91
0
        if (OVS_UNLIKELY(!dp_packet_ip_checksum_valid(packet))) {
92
0
            if (csum(ip, IP_IHL(ip->ip_ihl_ver) * 4)) {
93
0
                VLOG_WARN_RL(&err_rl, "ip packet has invalid checksum");
94
0
                return NULL;
95
0
            }
96
0
        }
97
98
0
        if (ntohs(ip->ip_tot_len) > l3_size) {
99
0
            VLOG_WARN_RL(&err_rl, "ip packet is truncated (IP length %d, actual %d)",
100
0
                         ntohs(ip->ip_tot_len), l3_size);
101
0
            return NULL;
102
0
        }
103
0
        if (IP_IHL(ip->ip_ihl_ver) * 4 > sizeof(struct ip_header)) {
104
0
            VLOG_WARN_RL(&err_rl, "ip options not supported on tunnel packets "
105
0
                         "(%d bytes)", IP_IHL(ip->ip_ihl_ver) * 4);
106
0
            return NULL;
107
0
        }
108
109
0
        ip_src = get_16aligned_be32(&ip->ip_src);
110
0
        ip_dst = get_16aligned_be32(&ip->ip_dst);
111
112
0
        tnl->ip_src = ip_src;
113
0
        tnl->ip_dst = ip_dst;
114
0
        tnl->ip_tos = ip->ip_tos;
115
0
        tnl->ip_ttl = ip->ip_ttl;
116
117
0
        *hlen += IP_HEADER_LEN;
118
119
0
    } else if (IP_VER(ip->ip_ihl_ver) == 6) {
120
0
        ovs_be32 tc_flow = get_16aligned_be32(&ip6->ip6_flow);
121
122
0
        memcpy(tnl->ipv6_src.s6_addr, ip6->ip6_src.be16, sizeof ip6->ip6_src);
123
0
        memcpy(tnl->ipv6_dst.s6_addr, ip6->ip6_dst.be16, sizeof ip6->ip6_dst);
124
125
0
        tnl->ip_tos = ntohl(tc_flow) >> 20;
126
0
        tnl->ip_ttl = ip6->ip6_hlim;
127
128
0
        *hlen += packet->l4_ofs - packet->l3_ofs;
129
130
0
    } else {
131
0
        VLOG_WARN_RL(&err_rl, "ipv4 packet has invalid version (%d)",
132
0
                     IP_VER(ip->ip_ihl_ver));
133
0
        return NULL;
134
0
    }
135
136
0
    return l4;
137
0
}
138
139
/* Pushes the 'size' bytes of 'header' into the headroom of 'packet',
140
 * reallocating the packet if necessary.  'header' should contain an Ethernet
141
 * header, followed by an IPv4 header (without options), and an L4 header.
142
 *
143
 * This function sets the IP header's ip_tot_len field (which should be zeroed
144
 * as part of 'header') and puts its value into '*ip_tot_size' as well.  Also
145
 * updates IP header checksum, as well as the l3 and l4 offsets in 'packet'.
146
 *
147
 * Return pointer to the L4 header added to 'packet'. */
148
void *
149
netdev_tnl_push_ip_header(struct dp_packet *packet,
150
               const void *header, int size, int *ip_tot_size)
151
0
{
152
0
    struct eth_header *eth;
153
0
    struct ip_header *ip;
154
0
    struct ovs_16aligned_ip6_hdr *ip6;
155
156
0
    eth = dp_packet_push_uninit(packet, size);
157
0
    *ip_tot_size = dp_packet_size(packet) - sizeof (struct eth_header);
158
159
0
    memcpy(eth, header, size);
160
    /* The encapsulated packet has type Ethernet. Adjust dp_packet. */
161
0
    packet->packet_type = htonl(PT_ETH);
162
0
    dp_packet_reset_offsets(packet);
163
0
    packet->l3_ofs = sizeof (struct eth_header);
164
165
0
    if (netdev_tnl_is_header_ipv6(header)) {
166
0
        ip6 = netdev_tnl_ipv6_hdr(eth);
167
0
        *ip_tot_size -= IPV6_HEADER_LEN;
168
0
        ip6->ip6_plen = htons(*ip_tot_size);
169
0
        packet->l4_ofs = dp_packet_size(packet) - *ip_tot_size;
170
0
        return ip6 + 1;
171
0
    } else {
172
0
        ip = netdev_tnl_ip_hdr(eth);
173
0
        ip->ip_tot_len = htons(*ip_tot_size);
174
0
        ip->ip_csum = recalc_csum16(ip->ip_csum, 0, ip->ip_tot_len);
175
0
        *ip_tot_size -= IP_HEADER_LEN;
176
0
        packet->l4_ofs = dp_packet_size(packet) - *ip_tot_size;
177
0
        return ip + 1;
178
0
    }
179
0
}
180
181
static void *
182
udp_extract_tnl_md(struct dp_packet *packet, struct flow_tnl *tnl,
183
                   unsigned int *hlen)
184
0
{
185
0
    struct udp_header *udp;
186
187
0
    udp = netdev_tnl_ip_extract_tnl_md(packet, tnl, hlen);
188
0
    if (!udp) {
189
0
        return NULL;
190
0
    }
191
192
0
    if (udp->udp_csum) {
193
0
        if (OVS_UNLIKELY(!dp_packet_l4_checksum_valid(packet))) {
194
0
            uint32_t csum;
195
0
            if (netdev_tnl_is_header_ipv6(dp_packet_data(packet))) {
196
0
                csum = packet_csum_pseudoheader6(dp_packet_l3(packet));
197
0
            } else {
198
0
                csum = packet_csum_pseudoheader(dp_packet_l3(packet));
199
0
            }
200
201
0
            csum = csum_continue(csum, udp, dp_packet_size(packet) -
202
0
                                 ((const unsigned char *)udp -
203
0
                                  (const unsigned char *)dp_packet_eth(packet)
204
0
                                 ));
205
0
            if (csum_finish(csum)) {
206
0
                return NULL;
207
0
            }
208
0
        }
209
0
        tnl->flags |= FLOW_TNL_F_CSUM;
210
0
    }
211
212
0
    tnl->tp_src = udp->udp_src;
213
0
    tnl->tp_dst = udp->udp_dst;
214
215
0
    return udp + 1;
216
0
}
217
218
static void
219
netdev_tnl_calc_udp_csum(struct udp_header *udp, struct dp_packet *packet,
220
                         int ip_tot_size)
221
0
{
222
0
    uint32_t csum;
223
224
0
    if (netdev_tnl_is_header_ipv6(dp_packet_data(packet))) {
225
0
        csum = packet_csum_pseudoheader6(netdev_tnl_ipv6_hdr(
226
0
                                         dp_packet_data(packet)));
227
0
    } else {
228
0
        csum = packet_csum_pseudoheader(netdev_tnl_ip_hdr(
229
0
                                        dp_packet_data(packet)));
230
0
    }
231
232
0
    csum = csum_continue(csum, udp, ip_tot_size);
233
0
    udp->udp_csum = csum_finish(csum);
234
235
0
    if (!udp->udp_csum) {
236
0
        udp->udp_csum = htons(0xffff);
237
0
    }
238
0
}
239
240
void
241
netdev_tnl_push_udp_header(const struct netdev *netdev OVS_UNUSED,
242
                           struct dp_packet *packet,
243
                           const struct ovs_action_push_tnl *data)
244
0
{
245
0
    struct udp_header *udp;
246
0
    int ip_tot_size;
247
248
0
    udp = netdev_tnl_push_ip_header(packet, data->header, data->header_len, &ip_tot_size);
249
250
    /* set udp src port */
251
0
    udp->udp_src = netdev_tnl_get_src_port(packet);
252
0
    udp->udp_len = htons(ip_tot_size);
253
254
0
    if (udp->udp_csum) {
255
0
        netdev_tnl_calc_udp_csum(udp, packet, ip_tot_size);
256
0
    }
257
0
}
258
259
static void *
260
eth_build_header(struct ovs_action_push_tnl *data,
261
                 const struct netdev_tnl_build_header_params *params)
262
0
{
263
0
    uint16_t eth_proto = params->is_ipv6 ? ETH_TYPE_IPV6 : ETH_TYPE_IP;
264
0
    struct eth_header *eth;
265
266
0
    memset(data->header, 0, sizeof data->header);
267
268
0
    eth = (struct eth_header *)data->header;
269
0
    eth->eth_dst = params->dmac;
270
0
    eth->eth_src = params->smac;
271
0
    eth->eth_type = htons(eth_proto);
272
0
    data->header_len = sizeof(struct eth_header);
273
0
    return eth + 1;
274
0
}
275
276
void *
277
netdev_tnl_ip_build_header(struct ovs_action_push_tnl *data,
278
                           const struct netdev_tnl_build_header_params *params,
279
                           uint8_t next_proto)
280
0
{
281
0
    void *l3;
282
283
0
    l3 = eth_build_header(data, params);
284
0
    if (!params->is_ipv6) {
285
0
        ovs_be32 ip_src = in6_addr_get_mapped_ipv4(params->s_ip);
286
0
        struct ip_header *ip;
287
288
0
        ip = (struct ip_header *) l3;
289
290
0
        ip->ip_ihl_ver = IP_IHL_VER(5, 4);
291
0
        ip->ip_tos = params->flow->tunnel.ip_tos;
292
0
        ip->ip_ttl = params->flow->tunnel.ip_ttl;
293
0
        ip->ip_proto = next_proto;
294
0
        put_16aligned_be32(&ip->ip_src, ip_src);
295
0
        put_16aligned_be32(&ip->ip_dst, params->flow->tunnel.ip_dst);
296
297
0
        ip->ip_frag_off = (params->flow->tunnel.flags & FLOW_TNL_F_DONT_FRAGMENT) ?
298
0
                          htons(IP_DF) : 0;
299
300
        /* Checksum has already been zeroed by eth_build_header. */
301
0
        ip->ip_csum = csum(ip, sizeof *ip);
302
303
0
        data->header_len += IP_HEADER_LEN;
304
0
        return ip + 1;
305
0
    } else {
306
0
        struct ovs_16aligned_ip6_hdr *ip6;
307
308
0
        ip6 = (struct ovs_16aligned_ip6_hdr *) l3;
309
310
0
        put_16aligned_be32(&ip6->ip6_flow, htonl(6 << 28) |
311
0
                           htonl(params->flow->tunnel.ip_tos << 20));
312
0
        ip6->ip6_hlim = params->flow->tunnel.ip_ttl;
313
0
        ip6->ip6_nxt = next_proto;
314
0
        memcpy(&ip6->ip6_src, params->s_ip, sizeof(ovs_be32[4]));
315
0
        memcpy(&ip6->ip6_dst, &params->flow->tunnel.ipv6_dst, sizeof(ovs_be32[4]));
316
317
0
        data->header_len += IPV6_HEADER_LEN;
318
0
        return ip6 + 1;
319
0
    }
320
0
}
321
322
static void *
323
udp_build_header(struct netdev_tunnel_config *tnl_cfg,
324
                 struct ovs_action_push_tnl *data,
325
                 const struct netdev_tnl_build_header_params *params)
326
0
{
327
0
    struct udp_header *udp;
328
329
0
    udp = netdev_tnl_ip_build_header(data, params, IPPROTO_UDP);
330
0
    udp->udp_dst = tnl_cfg->dst_port;
331
332
0
    if (params->is_ipv6 || params->flow->tunnel.flags & FLOW_TNL_F_CSUM) {
333
        /* Write a value in now to mark that we should compute the checksum
334
         * later. 0xffff is handy because it is transparent to the
335
         * calculation. */
336
0
        udp->udp_csum = htons(0xffff);
337
0
    }
338
0
    data->header_len += sizeof *udp;
339
0
    return udp + 1;
340
0
}
341
342
static int
343
gre_header_len(ovs_be16 flags)
344
0
{
345
0
    int hlen = 4;
346
347
0
    if (flags & htons(GRE_CSUM)) {
348
0
        hlen += 4;
349
0
    }
350
0
    if (flags & htons(GRE_KEY)) {
351
0
        hlen += 4;
352
0
    }
353
0
    if (flags & htons(GRE_SEQ)) {
354
0
        hlen += 4;
355
0
    }
356
0
    return hlen;
357
0
}
358
359
static int
360
parse_gre_header(struct dp_packet *packet,
361
                 struct flow_tnl *tnl)
362
0
{
363
0
    const struct gre_base_hdr *greh;
364
0
    ovs_16aligned_be32 *options;
365
0
    int hlen;
366
0
    unsigned int ulen;
367
0
    uint16_t greh_protocol;
368
369
0
    greh = netdev_tnl_ip_extract_tnl_md(packet, tnl, &ulen);
370
0
    if (!greh) {
371
0
        return -EINVAL;
372
0
    }
373
374
0
    if (greh->flags & ~(htons(GRE_CSUM | GRE_KEY | GRE_SEQ))) {
375
0
        return -EINVAL;
376
0
    }
377
378
0
    hlen = ulen + gre_header_len(greh->flags);
379
0
    if (hlen > dp_packet_size(packet)) {
380
0
        return -EINVAL;
381
0
    }
382
383
0
    options = (ovs_16aligned_be32 *)(greh + 1);
384
0
    if (greh->flags & htons(GRE_CSUM)) {
385
0
        ovs_be16 pkt_csum;
386
387
0
        pkt_csum = csum(greh, dp_packet_size(packet) -
388
0
                              ((const unsigned char *)greh -
389
0
                               (const unsigned char *)dp_packet_eth(packet)));
390
0
        if (pkt_csum) {
391
0
            return -EINVAL;
392
0
        }
393
0
        tnl->flags = FLOW_TNL_F_CSUM;
394
0
        options++;
395
0
    }
396
397
0
    if (greh->flags & htons(GRE_KEY)) {
398
0
        tnl->tun_id = be32_to_be64(get_16aligned_be32(options));
399
0
        tnl->flags |= FLOW_TNL_F_KEY;
400
0
        options++;
401
0
    }
402
403
0
    if (greh->flags & htons(GRE_SEQ)) {
404
0
        options++;
405
0
    }
406
407
    /* Set the new packet type depending on the GRE protocol field. */
408
0
    greh_protocol = ntohs(greh->protocol);
409
0
    if (greh_protocol == ETH_TYPE_TEB) {
410
0
        packet->packet_type = htonl(PT_ETH);
411
0
    } else if (greh_protocol >= ETH_TYPE_MIN) {
412
        /* Allow all GRE protocol values above 0x5ff as Ethertypes. */
413
0
        packet->packet_type = PACKET_TYPE_BE(OFPHTN_ETHERTYPE, greh_protocol);
414
0
    } else {
415
0
        return -EINVAL;
416
0
    }
417
418
0
    return hlen;
419
0
}
420
421
struct dp_packet *
422
netdev_gre_pop_header(struct dp_packet *packet)
423
0
{
424
0
    struct pkt_metadata *md = &packet->md;
425
0
    struct flow_tnl *tnl = &md->tunnel;
426
0
    int hlen = sizeof(struct eth_header) + 4;
427
428
0
    hlen += netdev_tnl_is_header_ipv6(dp_packet_data(packet)) ?
429
0
            IPV6_HEADER_LEN : IP_HEADER_LEN;
430
431
0
    pkt_metadata_init_tnl(md);
432
0
    if (hlen > dp_packet_size(packet)) {
433
0
        goto err;
434
0
    }
435
436
0
    hlen = parse_gre_header(packet, tnl);
437
0
    if (hlen < 0) {
438
0
        goto err;
439
0
    }
440
441
0
    dp_packet_reset_packet(packet, hlen);
442
443
0
    return packet;
444
0
err:
445
0
    dp_packet_delete(packet);
446
0
    return NULL;
447
0
}
448
449
void
450
netdev_gre_push_header(const struct netdev *netdev,
451
                       struct dp_packet *packet,
452
                       const struct ovs_action_push_tnl *data)
453
0
{
454
0
    struct netdev_vport *dev = netdev_vport_cast(netdev);
455
0
    struct netdev_tunnel_config *tnl_cfg;
456
0
    struct gre_base_hdr *greh;
457
0
    int ip_tot_size;
458
459
0
    greh = netdev_tnl_push_ip_header(packet, data->header, data->header_len, &ip_tot_size);
460
461
0
    if (greh->flags & htons(GRE_CSUM)) {
462
0
        ovs_be16 *csum_opt = (ovs_be16 *) (greh + 1);
463
0
        *csum_opt = csum(greh, ip_tot_size);
464
0
    }
465
466
0
    if (greh->flags & htons(GRE_SEQ)) {
467
        /* Last 4 byte is GRE seqno */
468
0
        int seq_ofs = gre_header_len(greh->flags) - 4;
469
0
        ovs_16aligned_be32 *seq_opt =
470
0
            ALIGNED_CAST(ovs_16aligned_be32 *, (char *)greh + seq_ofs);
471
0
        tnl_cfg = &dev->tnl_cfg;
472
0
        put_16aligned_be32(seq_opt, htonl(tnl_cfg->seqno++));
473
0
    }
474
0
}
475
476
int
477
netdev_gre_build_header(const struct netdev *netdev,
478
                        struct ovs_action_push_tnl *data,
479
                        const struct netdev_tnl_build_header_params *params)
480
0
{
481
0
    struct netdev_vport *dev = netdev_vport_cast(netdev);
482
0
    struct netdev_tunnel_config *tnl_cfg;
483
0
    struct gre_base_hdr *greh;
484
0
    ovs_16aligned_be32 *options;
485
0
    unsigned int hlen;
486
487
    /* XXX: RCUfy tnl_cfg. */
488
0
    ovs_mutex_lock(&dev->mutex);
489
0
    tnl_cfg = &dev->tnl_cfg;
490
491
0
    greh = netdev_tnl_ip_build_header(data, params, IPPROTO_GRE);
492
493
0
    if (params->flow->packet_type == htonl(PT_ETH)) {
494
0
        greh->protocol = htons(ETH_TYPE_TEB);
495
0
    } else if (pt_ns(params->flow->packet_type) == OFPHTN_ETHERTYPE) {
496
0
        greh->protocol = pt_ns_type_be(params->flow->packet_type);
497
0
    } else {
498
0
        ovs_mutex_unlock(&dev->mutex);
499
0
        return 1;
500
0
    }
501
0
    greh->flags = 0;
502
503
0
    options = (ovs_16aligned_be32 *) (greh + 1);
504
0
    if (params->flow->tunnel.flags & FLOW_TNL_F_CSUM) {
505
0
        greh->flags |= htons(GRE_CSUM);
506
0
        put_16aligned_be32(options, 0);
507
0
        options++;
508
0
    }
509
510
0
    if (tnl_cfg->out_key_present) {
511
0
        greh->flags |= htons(GRE_KEY);
512
0
        put_16aligned_be32(options, be64_to_be32(params->flow->tunnel.tun_id));
513
0
        options++;
514
0
    }
515
516
0
    if (tnl_cfg->set_seq) {
517
0
        greh->flags |= htons(GRE_SEQ);
518
        /* seqno is updated at push header */
519
0
        options++;
520
0
    }
521
522
0
    ovs_mutex_unlock(&dev->mutex);
523
524
0
    hlen = (uint8_t *) options - (uint8_t *) greh;
525
526
0
    data->header_len += hlen;
527
0
    if (!params->is_ipv6) {
528
0
        data->tnl_type = OVS_VPORT_TYPE_GRE;
529
0
    } else {
530
0
        data->tnl_type = OVS_VPORT_TYPE_IP6GRE;
531
0
    }
532
0
    return 0;
533
0
}
534
535
struct dp_packet *
536
netdev_erspan_pop_header(struct dp_packet *packet)
537
0
{
538
0
    const struct gre_base_hdr *greh;
539
0
    const struct erspan_base_hdr *ersh;
540
0
    struct pkt_metadata *md = &packet->md;
541
0
    struct flow_tnl *tnl = &md->tunnel;
542
0
    int hlen = sizeof(struct eth_header);
543
0
    unsigned int ulen;
544
0
    uint16_t greh_protocol;
545
546
0
    hlen += netdev_tnl_is_header_ipv6(dp_packet_data(packet)) ?
547
0
            IPV6_HEADER_LEN : IP_HEADER_LEN;
548
549
0
    pkt_metadata_init_tnl(md);
550
0
    if (hlen > dp_packet_size(packet)) {
551
0
        goto err;
552
0
    }
553
554
0
    greh = netdev_tnl_ip_extract_tnl_md(packet, tnl, &ulen);
555
0
    if (!greh) {
556
0
        goto err;
557
0
    }
558
559
0
    greh_protocol = ntohs(greh->protocol);
560
0
    if (greh_protocol != ETH_TYPE_ERSPAN1 &&
561
0
        greh_protocol != ETH_TYPE_ERSPAN2) {
562
0
        goto err;
563
0
    }
564
565
0
    if (greh->flags & ~htons(GRE_SEQ)) {
566
0
        goto err;
567
0
    }
568
569
0
    ersh = ERSPAN_HDR(greh);
570
0
    tnl->tun_id = be16_to_be64(htons(get_sid(ersh)));
571
0
    tnl->erspan_ver = ersh->ver;
572
573
0
    if (ersh->ver == 1) {
574
0
        ovs_16aligned_be32 *index = ALIGNED_CAST(ovs_16aligned_be32 *,
575
0
                                                 ersh + 1);
576
0
        tnl->erspan_idx = ntohl(get_16aligned_be32(index));
577
0
        tnl->flags |= FLOW_TNL_F_KEY;
578
0
        hlen = ulen + ERSPAN_GREHDR_LEN + sizeof *ersh + ERSPAN_V1_MDSIZE;
579
0
    } else if (ersh->ver == 2) {
580
0
        struct erspan_md2 *md2 = ALIGNED_CAST(struct erspan_md2 *, ersh + 1);
581
0
        tnl->erspan_dir = md2->dir;
582
0
        tnl->erspan_hwid = get_hwid(md2);
583
0
        tnl->flags |= FLOW_TNL_F_KEY;
584
0
        hlen = ulen + ERSPAN_GREHDR_LEN + sizeof *ersh + ERSPAN_V2_MDSIZE;
585
0
    } else {
586
0
        VLOG_WARN_RL(&err_rl, "ERSPAN version error %d", ersh->ver);
587
0
        goto err;
588
0
    }
589
590
0
    if (hlen > dp_packet_size(packet)) {
591
0
        goto err;
592
0
    }
593
594
0
    dp_packet_reset_packet(packet, hlen);
595
596
0
    return packet;
597
0
err:
598
0
    dp_packet_delete(packet);
599
0
    return NULL;
600
0
}
601
602
void
603
netdev_erspan_push_header(const struct netdev *netdev,
604
                          struct dp_packet *packet,
605
                          const struct ovs_action_push_tnl *data)
606
0
{
607
0
    struct netdev_vport *dev = netdev_vport_cast(netdev);
608
0
    struct netdev_tunnel_config *tnl_cfg;
609
0
    struct erspan_base_hdr *ersh;
610
0
    struct gre_base_hdr *greh;
611
0
    struct erspan_md2 *md2;
612
0
    int ip_tot_size;
613
614
0
    greh = netdev_tnl_push_ip_header(packet, data->header,
615
0
                                     data->header_len, &ip_tot_size);
616
617
    /* update GRE seqno */
618
0
    tnl_cfg = &dev->tnl_cfg;
619
0
    ovs_16aligned_be32 *seqno = (ovs_16aligned_be32 *) (greh + 1);
620
0
    put_16aligned_be32(seqno, htonl(tnl_cfg->seqno++));
621
622
    /* update v2 timestamp */
623
0
    if (greh->protocol == htons(ETH_TYPE_ERSPAN2)) {
624
0
        ersh = ERSPAN_HDR(greh);
625
0
        md2 = ALIGNED_CAST(struct erspan_md2 *, ersh + 1);
626
0
        put_16aligned_be32(&md2->timestamp, get_erspan_ts(ERSPAN_100US));
627
0
    }
628
0
}
629
630
int
631
netdev_erspan_build_header(const struct netdev *netdev,
632
                           struct ovs_action_push_tnl *data,
633
                           const struct netdev_tnl_build_header_params *params)
634
0
{
635
0
    struct netdev_vport *dev = netdev_vport_cast(netdev);
636
0
    struct netdev_tunnel_config *tnl_cfg;
637
0
    struct gre_base_hdr *greh;
638
0
    struct erspan_base_hdr *ersh;
639
0
    unsigned int hlen;
640
0
    uint32_t tun_id;
641
0
    int erspan_ver;
642
0
    uint16_t sid;
643
644
    /* XXX: RCUfy tnl_cfg. */
645
0
    ovs_mutex_lock(&dev->mutex);
646
0
    tnl_cfg = &dev->tnl_cfg;
647
0
    greh = netdev_tnl_ip_build_header(data, params, IPPROTO_GRE);
648
0
    ersh = ERSPAN_HDR(greh);
649
650
0
    tun_id = ntohl(be64_to_be32(params->flow->tunnel.tun_id));
651
    /* ERSPAN only has 10-bit session ID */
652
0
    if (tun_id & ~ERSPAN_SID_MASK) {
653
0
        ovs_mutex_unlock(&dev->mutex);
654
0
        return 1;
655
0
    } else {
656
0
        sid = (uint16_t) tun_id;
657
0
    }
658
659
0
    if (tnl_cfg->erspan_ver_flow) {
660
0
        erspan_ver = params->flow->tunnel.erspan_ver;
661
0
    } else {
662
0
        erspan_ver = tnl_cfg->erspan_ver;
663
0
    }
664
665
0
    if (erspan_ver == 1) {
666
0
        greh->protocol = htons(ETH_TYPE_ERSPAN1);
667
0
        greh->flags = htons(GRE_SEQ);
668
0
        ersh->ver = 1;
669
0
        set_sid(ersh, sid);
670
671
0
        uint32_t erspan_idx = (tnl_cfg->erspan_idx_flow
672
0
                          ? params->flow->tunnel.erspan_idx
673
0
                          : tnl_cfg->erspan_idx);
674
0
        put_16aligned_be32(ALIGNED_CAST(ovs_16aligned_be32 *, ersh + 1),
675
0
                           htonl(erspan_idx));
676
677
0
        hlen = ERSPAN_GREHDR_LEN + sizeof *ersh + ERSPAN_V1_MDSIZE;
678
0
    } else if (erspan_ver == 2) {
679
0
        struct erspan_md2 *md2 = ALIGNED_CAST(struct erspan_md2 *, ersh + 1);
680
681
0
        greh->protocol = htons(ETH_TYPE_ERSPAN2);
682
0
        greh->flags = htons(GRE_SEQ);
683
0
        ersh->ver = 2;
684
0
        set_sid(ersh, sid);
685
686
0
        md2->sgt = 0; /* security group tag */
687
0
        md2->gra = 0;
688
0
        put_16aligned_be32(&md2->timestamp, 0);
689
690
0
        if (tnl_cfg->erspan_hwid_flow) {
691
0
            set_hwid(md2, params->flow->tunnel.erspan_hwid);
692
0
        } else {
693
0
            set_hwid(md2, tnl_cfg->erspan_hwid);
694
0
        }
695
696
0
        if (tnl_cfg->erspan_dir_flow) {
697
0
            md2->dir = params->flow->tunnel.erspan_dir;
698
0
        } else {
699
0
            md2->dir = tnl_cfg->erspan_dir;
700
0
        }
701
702
0
        hlen = ERSPAN_GREHDR_LEN + sizeof *ersh + ERSPAN_V2_MDSIZE;
703
0
    } else {
704
0
        VLOG_WARN_RL(&err_rl, "ERSPAN version error %d", tnl_cfg->erspan_ver);
705
0
        ovs_mutex_unlock(&dev->mutex);
706
0
        return 1;
707
0
    }
708
709
0
    ovs_mutex_unlock(&dev->mutex);
710
711
0
    data->header_len += hlen;
712
713
0
    if (params->is_ipv6) {
714
0
        data->tnl_type = OVS_VPORT_TYPE_IP6ERSPAN;
715
0
    } else {
716
0
        data->tnl_type = OVS_VPORT_TYPE_ERSPAN;
717
0
    }
718
0
    return 0;
719
0
}
720
721
struct dp_packet *
722
netdev_gtpu_pop_header(struct dp_packet *packet)
723
0
{
724
0
    struct pkt_metadata *md = &packet->md;
725
0
    struct flow_tnl *tnl = &md->tunnel;
726
0
    struct gtpuhdr *gtph;
727
0
    unsigned int gtpu_hlen;
728
0
    unsigned int hlen;
729
730
0
    ovs_assert(packet->l3_ofs > 0);
731
0
    ovs_assert(packet->l4_ofs > 0);
732
733
0
    pkt_metadata_init_tnl(md);
734
0
    if (GTPU_HLEN > dp_packet_l4_size(packet)) {
735
0
        goto err;
736
0
    }
737
738
0
    gtph = udp_extract_tnl_md(packet, tnl, &hlen);
739
0
    if (!gtph) {
740
0
        goto err;
741
0
    }
742
743
0
    tnl->gtpu_flags = gtph->md.flags;
744
0
    tnl->gtpu_msgtype = gtph->md.msgtype;
745
0
    tnl->tun_id = be32_to_be64(get_16aligned_be32(&gtph->teid));
746
747
0
    if (tnl->gtpu_msgtype == GTPU_MSGTYPE_GPDU) {
748
0
        struct ip_header *ip;
749
750
0
        if (gtph->md.flags & GTPU_S_MASK) {
751
0
            gtpu_hlen = GTPU_HLEN + sizeof(struct gtpuhdr_opt);
752
0
        } else {
753
0
            gtpu_hlen = GTPU_HLEN;
754
0
        }
755
0
        ip = ALIGNED_CAST(struct ip_header *, (char *)gtph + gtpu_hlen);
756
757
0
        if (IP_VER(ip->ip_ihl_ver) == 4) {
758
0
            packet->packet_type = htonl(PT_IPV4);
759
0
        } else if (IP_VER(ip->ip_ihl_ver) == 6) {
760
0
            packet->packet_type = htonl(PT_IPV6);
761
0
        } else {
762
0
            VLOG_WARN_RL(&err_rl, "GTP-U: Receive non-IP packet.");
763
0
        }
764
0
        dp_packet_reset_packet(packet, hlen + gtpu_hlen);
765
0
    } else {
766
        /* non-GPDU GTP-U messages, ex: echo request, end marker.
767
         * Users should redirect these packets to controller, or.
768
         * any application that handles GTP-U messages, so keep
769
         * the original packet.
770
         */
771
0
        packet->packet_type = htonl(PT_ETH);
772
0
        VLOG_WARN_ONCE("Receive non-GPDU msgtype: %"PRIu8,
773
0
                       gtph->md.msgtype);
774
0
    }
775
776
0
    return packet;
777
778
0
err:
779
0
    dp_packet_delete(packet);
780
0
    return NULL;
781
0
}
782
783
void
784
netdev_gtpu_push_header(const struct netdev *netdev,
785
                        struct dp_packet *packet,
786
                        const struct ovs_action_push_tnl *data)
787
0
{
788
0
    struct netdev_vport *dev = netdev_vport_cast(netdev);
789
0
    struct netdev_tunnel_config *tnl_cfg;
790
0
    struct udp_header *udp;
791
0
    struct gtpuhdr *gtpuh;
792
0
    int ip_tot_size;
793
0
    unsigned int payload_len;
794
795
0
    payload_len = dp_packet_size(packet);
796
0
    udp = netdev_tnl_push_ip_header(packet, data->header,
797
0
                                    data->header_len, &ip_tot_size);
798
0
    udp->udp_src = netdev_tnl_get_src_port(packet);
799
0
    udp->udp_len = htons(ip_tot_size);
800
0
    netdev_tnl_calc_udp_csum(udp, packet, ip_tot_size);
801
802
0
    gtpuh = ALIGNED_CAST(struct gtpuhdr *, udp + 1);
803
804
0
    tnl_cfg = &dev->tnl_cfg;
805
0
    if (tnl_cfg->set_seq) {
806
0
        ovs_be16 *seqno = ALIGNED_CAST(ovs_be16 *, gtpuh + 1);
807
0
        *seqno = htons(tnl_cfg->seqno++);
808
0
        payload_len += sizeof(struct gtpuhdr_opt);
809
0
    }
810
0
    gtpuh->len = htons(payload_len);
811
0
}
812
813
int
814
netdev_gtpu_build_header(const struct netdev *netdev,
815
                         struct ovs_action_push_tnl *data,
816
                         const struct netdev_tnl_build_header_params *params)
817
0
{
818
0
    struct netdev_vport *dev = netdev_vport_cast(netdev);
819
0
    struct netdev_tunnel_config *tnl_cfg;
820
0
    struct gtpuhdr *gtph;
821
0
    unsigned int gtpu_hlen;
822
823
0
    ovs_mutex_lock(&dev->mutex);
824
0
    tnl_cfg = &dev->tnl_cfg;
825
0
    gtph = udp_build_header(tnl_cfg, data, params);
826
827
    /* Set to default if not set in flow. */
828
0
    gtph->md.flags = params->flow->tunnel.gtpu_flags ?
829
0
                     params->flow->tunnel.gtpu_flags : GTPU_FLAGS_DEFAULT;
830
0
    gtph->md.msgtype = params->flow->tunnel.gtpu_msgtype ?
831
0
                       params->flow->tunnel.gtpu_msgtype : GTPU_MSGTYPE_GPDU;
832
0
    put_16aligned_be32(&gtph->teid,
833
0
                       be64_to_be32(params->flow->tunnel.tun_id));
834
835
0
    gtpu_hlen = sizeof *gtph;
836
0
    if (tnl_cfg->set_seq) {
837
0
        gtph->md.flags |= GTPU_S_MASK;
838
0
        gtpu_hlen += sizeof(struct gtpuhdr_opt);
839
0
    }
840
0
    ovs_mutex_unlock(&dev->mutex);
841
842
0
    data->header_len += gtpu_hlen;
843
0
    data->tnl_type = OVS_VPORT_TYPE_GTPU;
844
845
0
    return 0;
846
0
}
847
848
struct dp_packet *
849
netdev_vxlan_pop_header(struct dp_packet *packet)
850
0
{
851
0
    struct pkt_metadata *md = &packet->md;
852
0
    struct flow_tnl *tnl = &md->tunnel;
853
0
    struct vxlanhdr *vxh;
854
0
    unsigned int hlen;
855
0
    ovs_be32 vx_flags;
856
0
    enum packet_type next_pt = PT_ETH;
857
858
0
    ovs_assert(packet->l3_ofs > 0);
859
0
    ovs_assert(packet->l4_ofs > 0);
860
861
0
    pkt_metadata_init_tnl(md);
862
0
    if (VXLAN_HLEN > dp_packet_l4_size(packet)) {
863
0
        goto err;
864
0
    }
865
866
0
    vxh = udp_extract_tnl_md(packet, tnl, &hlen);
867
0
    if (!vxh) {
868
0
        goto err;
869
0
    }
870
871
0
    vx_flags = get_16aligned_be32(&vxh->vx_flags);
872
0
    if (vx_flags & htonl(VXLAN_HF_GPE)) {
873
0
        vx_flags &= htonl(~VXLAN_GPE_USED_BITS);
874
        /* Drop the OAM packets */
875
0
        if (vxh->vx_gpe.flags & VXLAN_GPE_FLAGS_O) {
876
0
            goto err;
877
0
        }
878
0
        switch (vxh->vx_gpe.next_protocol) {
879
0
        case VXLAN_GPE_NP_IPV4:
880
0
            next_pt = PT_IPV4;
881
0
            break;
882
0
        case VXLAN_GPE_NP_IPV6:
883
0
            next_pt = PT_IPV6;
884
0
            break;
885
0
        case VXLAN_GPE_NP_NSH:
886
0
            next_pt = PT_NSH;
887
0
            break;
888
0
        case VXLAN_GPE_NP_ETHERNET:
889
0
            next_pt = PT_ETH;
890
0
            break;
891
0
        default:
892
0
            goto err;
893
0
        }
894
0
    }
895
896
0
    if (vx_flags != htonl(VXLAN_FLAGS) ||
897
0
       (get_16aligned_be32(&vxh->vx_vni) & htonl(0xff))) {
898
0
        VLOG_WARN_RL(&err_rl, "invalid vxlan flags=%#x vni=%#x\n",
899
0
                     ntohl(vx_flags),
900
0
                     ntohl(get_16aligned_be32(&vxh->vx_vni)));
901
0
        goto err;
902
0
    }
903
0
    tnl->tun_id = htonll(ntohl(get_16aligned_be32(&vxh->vx_vni)) >> 8);
904
0
    tnl->flags |= FLOW_TNL_F_KEY;
905
906
0
    packet->packet_type = htonl(next_pt);
907
0
    dp_packet_reset_packet(packet, hlen + VXLAN_HLEN);
908
0
    if (next_pt != PT_ETH) {
909
0
        packet->l3_ofs = 0;
910
0
    }
911
912
0
    return packet;
913
0
err:
914
0
    dp_packet_delete(packet);
915
0
    return NULL;
916
0
}
917
918
int
919
netdev_vxlan_build_header(const struct netdev *netdev,
920
                          struct ovs_action_push_tnl *data,
921
                          const struct netdev_tnl_build_header_params *params)
922
0
{
923
0
    struct netdev_vport *dev = netdev_vport_cast(netdev);
924
0
    struct netdev_tunnel_config *tnl_cfg;
925
0
    struct vxlanhdr *vxh;
926
927
    /* XXX: RCUfy tnl_cfg. */
928
0
    ovs_mutex_lock(&dev->mutex);
929
0
    tnl_cfg = &dev->tnl_cfg;
930
931
0
    vxh = udp_build_header(tnl_cfg, data, params);
932
933
0
    if (tnl_cfg->exts & (1 << OVS_VXLAN_EXT_GPE)) {
934
0
        put_16aligned_be32(&vxh->vx_flags, htonl(VXLAN_FLAGS | VXLAN_HF_GPE));
935
0
        put_16aligned_be32(&vxh->vx_vni,
936
0
                           htonl(ntohll(params->flow->tunnel.tun_id) << 8));
937
0
        if (params->flow->packet_type == htonl(PT_ETH)) {
938
0
            vxh->vx_gpe.next_protocol = VXLAN_GPE_NP_ETHERNET;
939
0
        } else if (pt_ns(params->flow->packet_type) == OFPHTN_ETHERTYPE) {
940
0
            switch (pt_ns_type(params->flow->packet_type)) {
941
0
            case ETH_TYPE_IP:
942
0
                vxh->vx_gpe.next_protocol = VXLAN_GPE_NP_IPV4;
943
0
                break;
944
0
            case ETH_TYPE_IPV6:
945
0
                vxh->vx_gpe.next_protocol = VXLAN_GPE_NP_IPV6;
946
0
                break;
947
0
            case ETH_TYPE_NSH:
948
0
                vxh->vx_gpe.next_protocol = VXLAN_GPE_NP_NSH;
949
0
                break;
950
0
            case ETH_TYPE_TEB:
951
0
                vxh->vx_gpe.next_protocol = VXLAN_GPE_NP_ETHERNET;
952
0
                break;
953
0
            default:
954
0
                goto drop;
955
0
            }
956
0
        } else {
957
0
            goto drop;
958
0
        }
959
0
    } else {
960
0
        put_16aligned_be32(&vxh->vx_flags, htonl(VXLAN_FLAGS));
961
0
        put_16aligned_be32(&vxh->vx_vni,
962
0
                           htonl(ntohll(params->flow->tunnel.tun_id) << 8));
963
0
    }
964
965
0
    ovs_mutex_unlock(&dev->mutex);
966
0
    data->header_len += sizeof *vxh;
967
0
    data->tnl_type = OVS_VPORT_TYPE_VXLAN;
968
0
    return 0;
969
970
0
drop:
971
0
    ovs_mutex_unlock(&dev->mutex);
972
0
    return 1;
973
0
}
974
975
struct dp_packet *
976
netdev_geneve_pop_header(struct dp_packet *packet)
977
0
{
978
0
    struct pkt_metadata *md = &packet->md;
979
0
    struct flow_tnl *tnl = &md->tunnel;
980
0
    struct genevehdr *gnh;
981
0
    unsigned int hlen, opts_len, ulen;
982
983
0
    pkt_metadata_init_tnl(md);
984
0
    if (GENEVE_BASE_HLEN > dp_packet_l4_size(packet)) {
985
0
        VLOG_WARN_RL(&err_rl, "geneve packet too small: min header=%u packet size=%"PRIuSIZE"\n",
986
0
                     (unsigned int)GENEVE_BASE_HLEN, dp_packet_l4_size(packet));
987
0
        goto err;
988
0
    }
989
990
0
    gnh = udp_extract_tnl_md(packet, tnl, &ulen);
991
0
    if (!gnh) {
992
0
        goto err;
993
0
    }
994
995
0
    opts_len = gnh->opt_len * 4;
996
0
    hlen = ulen + GENEVE_BASE_HLEN + opts_len;
997
0
    if (hlen > dp_packet_size(packet)) {
998
0
        VLOG_WARN_RL(&err_rl, "geneve packet too small: header len=%u packet size=%u\n",
999
0
                     hlen, dp_packet_size(packet));
1000
0
        goto err;
1001
0
    }
1002
1003
0
    if (gnh->ver != 0) {
1004
0
        VLOG_WARN_RL(&err_rl, "unknown geneve version: %"PRIu8"\n", gnh->ver);
1005
0
        goto err;
1006
0
    }
1007
1008
0
    if (gnh->proto_type != htons(ETH_TYPE_TEB)) {
1009
0
        VLOG_WARN_RL(&err_rl, "unknown geneve encapsulated protocol: %#x\n",
1010
0
                     ntohs(gnh->proto_type));
1011
0
        goto err;
1012
0
    }
1013
1014
0
    tnl->flags |= gnh->oam ? FLOW_TNL_F_OAM : 0;
1015
0
    tnl->tun_id = htonll(ntohl(get_16aligned_be32(&gnh->vni)) >> 8);
1016
0
    tnl->flags |= FLOW_TNL_F_KEY;
1017
1018
0
    memcpy(tnl->metadata.opts.gnv, gnh->options, opts_len);
1019
0
    tnl->metadata.present.len = opts_len;
1020
0
    tnl->flags |= FLOW_TNL_F_UDPIF;
1021
1022
0
    packet->packet_type = htonl(PT_ETH);
1023
0
    dp_packet_reset_packet(packet, hlen);
1024
1025
0
    return packet;
1026
0
err:
1027
0
    dp_packet_delete(packet);
1028
0
    return NULL;
1029
0
}
1030
1031
int
1032
netdev_geneve_build_header(const struct netdev *netdev,
1033
                           struct ovs_action_push_tnl *data,
1034
                           const struct netdev_tnl_build_header_params *params)
1035
0
{
1036
0
    struct netdev_vport *dev = netdev_vport_cast(netdev);
1037
0
    struct netdev_tunnel_config *tnl_cfg;
1038
0
    struct genevehdr *gnh;
1039
0
    int opt_len;
1040
0
    bool crit_opt;
1041
1042
    /* XXX: RCUfy tnl_cfg. */
1043
0
    ovs_mutex_lock(&dev->mutex);
1044
0
    tnl_cfg = &dev->tnl_cfg;
1045
1046
0
    gnh = udp_build_header(tnl_cfg, data, params);
1047
1048
0
    put_16aligned_be32(&gnh->vni, htonl(ntohll(params->flow->tunnel.tun_id) << 8));
1049
1050
0
    ovs_mutex_unlock(&dev->mutex);
1051
1052
0
    opt_len = tun_metadata_to_geneve_header(&params->flow->tunnel,
1053
0
                                            gnh->options, &crit_opt);
1054
1055
0
    gnh->opt_len = opt_len / 4;
1056
0
    gnh->oam = !!(params->flow->tunnel.flags & FLOW_TNL_F_OAM);
1057
0
    gnh->critical = crit_opt ? 1 : 0;
1058
0
    gnh->proto_type = htons(ETH_TYPE_TEB);
1059
1060
0
    data->header_len += sizeof *gnh + opt_len;
1061
0
    data->tnl_type = OVS_VPORT_TYPE_GENEVE;
1062
0
    return 0;
1063
0
}
1064
1065

1066
void
1067
netdev_tnl_egress_port_range(struct unixctl_conn *conn, int argc,
1068
                             const char *argv[], void *aux OVS_UNUSED)
1069
0
{
1070
0
    int val1, val2;
1071
1072
0
    if (argc < 3) {
1073
0
        struct ds ds = DS_EMPTY_INITIALIZER;
1074
1075
0
        ds_put_format(&ds, "Tunnel UDP source port range: %"PRIu16"-%"PRIu16"\n",
1076
0
                            tnl_udp_port_min, tnl_udp_port_max);
1077
1078
0
        unixctl_command_reply(conn, ds_cstr(&ds));
1079
0
        ds_destroy(&ds);
1080
0
        return;
1081
0
    }
1082
1083
0
    if (argc != 3) {
1084
0
        return;
1085
0
    }
1086
1087
0
    val1 = atoi(argv[1]);
1088
0
    if (val1 <= 0 || val1 > UINT16_MAX) {
1089
0
        unixctl_command_reply(conn, "Invalid min.");
1090
0
        return;
1091
0
    }
1092
0
    val2 = atoi(argv[2]);
1093
0
    if (val2 <= 0 || val2 > UINT16_MAX) {
1094
0
        unixctl_command_reply(conn, "Invalid max.");
1095
0
        return;
1096
0
    }
1097
1098
0
    if (val1 > val2) {
1099
0
        tnl_udp_port_min = val2;
1100
0
        tnl_udp_port_max = val1;
1101
0
    } else {
1102
0
        tnl_udp_port_min = val1;
1103
0
        tnl_udp_port_max = val2;
1104
0
    }
1105
0
    seq_change(tnl_conf_seq);
1106
1107
0
    unixctl_command_reply(conn, "OK");
1108
0
}