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