2 * Copyright (c) 2016 Nicira, Inc.
3 * Copyright (c) 2016 Red Hat, Inc.
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:
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
20 #include "netdev-native-tnl.h"
24 #include <sys/socket.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>
35 #include "byte-order.h"
37 #include "dp-packet.h"
39 #include "netdev-vport.h"
40 #include "netdev-vport-private.h"
41 #include "odp-netlink.h"
44 #include "unaligned.h"
46 #include "openvswitch/vlog.h"
48 VLOG_DEFINE_THIS_MODULE(native_tnl
);
49 static struct vlog_rate_limit err_rl
= VLOG_RATE_LIMIT_INIT(60, 5);
51 #define VXLAN_HLEN (sizeof(struct udp_header) + \
52 sizeof(struct vxlanhdr))
54 #define GENEVE_BASE_HLEN (sizeof(struct udp_header) + \
55 sizeof(struct genevehdr))
57 #define GTPU_HLEN (sizeof(struct udp_header) + \
58 sizeof(struct gtpuhdr))
60 uint16_t tnl_udp_port_min
= 32768;
61 uint16_t tnl_udp_port_max
= 61000;
64 netdev_tnl_ip_extract_tnl_md(struct dp_packet
*packet
, struct flow_tnl
*tnl
,
69 struct ovs_16aligned_ip6_hdr
*ip6
;
73 nh
= dp_packet_l3(packet
);
76 l4
= dp_packet_l4(packet
);
82 *hlen
= sizeof(struct eth_header
);
84 l3_size
= dp_packet_size(packet
) -
85 ((char *)nh
- (char *)dp_packet_data(packet
));
87 if (IP_VER(ip
->ip_ihl_ver
) == 4) {
89 ovs_be32 ip_src
, ip_dst
;
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");
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
);
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);
109 ip_src
= get_16aligned_be32(&ip
->ip_src
);
110 ip_dst
= get_16aligned_be32(&ip
->ip_dst
);
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
;
117 *hlen
+= IP_HEADER_LEN
;
119 } else if (IP_VER(ip
->ip_ihl_ver
) == 6) {
120 ovs_be32 tc_flow
= get_16aligned_be32(&ip6
->ip6_flow
);
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
);
125 tnl
->ip_tos
= ntohl(tc_flow
) >> 20;
126 tnl
->ip_ttl
= ip6
->ip6_hlim
;
128 *hlen
+= packet
->l4_ofs
- packet
->l3_ofs
;
131 VLOG_WARN_RL(&err_rl
, "ipv4 packet has invalid version (%d)",
132 IP_VER(ip
->ip_ihl_ver
));
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.
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'.
147 * Return pointer to the L4 header added to 'packet'. */
149 netdev_tnl_push_ip_header(struct dp_packet
*packet
,
150 const void *header
, int size
, int *ip_tot_size
)
152 struct eth_header
*eth
;
153 struct ip_header
*ip
;
154 struct ovs_16aligned_ip6_hdr
*ip6
;
156 eth
= dp_packet_push_uninit(packet
, size
);
157 *ip_tot_size
= dp_packet_size(packet
) - sizeof (struct eth_header
);
159 memcpy(eth
, header
, size
);
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
);
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
);
169 packet
->l4_ofs
= dp_packet_size(packet
) - *ip_tot_size
;
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
;
176 packet
->l4_ofs
= dp_packet_size(packet
) - *ip_tot_size
;
182 udp_extract_tnl_md(struct dp_packet
*packet
, struct flow_tnl
*tnl
,
185 struct udp_header
*udp
;
187 udp
= netdev_tnl_ip_extract_tnl_md(packet
, tnl
, hlen
);
193 if (OVS_UNLIKELY(!dp_packet_l4_checksum_valid(packet
))) {
195 if (netdev_tnl_is_header_ipv6(dp_packet_data(packet
))) {
196 csum
= packet_csum_pseudoheader6(dp_packet_l3(packet
));
198 csum
= packet_csum_pseudoheader(dp_packet_l3(packet
));
201 csum
= csum_continue(csum
, udp
, dp_packet_size(packet
) -
202 ((const unsigned char *)udp
-
203 (const unsigned char *)dp_packet_eth(packet
)
205 if (csum_finish(csum
)) {
209 tnl
->flags
|= FLOW_TNL_F_CSUM
;
212 tnl
->tp_src
= udp
->udp_src
;
213 tnl
->tp_dst
= udp
->udp_dst
;
219 netdev_tnl_calc_udp_csum(struct udp_header
*udp
, struct dp_packet
*packet
,
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
)));
228 csum
= packet_csum_pseudoheader(netdev_tnl_ip_hdr(
229 dp_packet_data(packet
)));
232 csum
= csum_continue(csum
, udp
, ip_tot_size
);
233 udp
->udp_csum
= csum_finish(csum
);
235 if (!udp
->udp_csum
) {
236 udp
->udp_csum
= htons(0xffff);
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
)
245 struct udp_header
*udp
;
248 udp
= netdev_tnl_push_ip_header(packet
, data
->header
, data
->header_len
, &ip_tot_size
);
250 /* set udp src port */
251 udp
->udp_src
= netdev_tnl_get_src_port(packet
);
252 udp
->udp_len
= htons(ip_tot_size
);
255 netdev_tnl_calc_udp_csum(udp
, packet
, ip_tot_size
);
260 eth_build_header(struct ovs_action_push_tnl
*data
,
261 const struct netdev_tnl_build_header_params
*params
)
263 uint16_t eth_proto
= params
->is_ipv6
? ETH_TYPE_IPV6
: ETH_TYPE_IP
;
264 struct eth_header
*eth
;
266 memset(data
->header
, 0, sizeof data
->header
);
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
);
277 netdev_tnl_ip_build_header(struct ovs_action_push_tnl
*data
,
278 const struct netdev_tnl_build_header_params
*params
,
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
;
288 ip
= (struct ip_header
*) l3
;
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
);
297 ip
->ip_frag_off
= (params
->flow
->tunnel
.flags
& FLOW_TNL_F_DONT_FRAGMENT
) ?
300 /* Checksum has already been zeroed by eth_build_header. */
301 ip
->ip_csum
= csum(ip
, sizeof *ip
);
303 data
->header_len
+= IP_HEADER_LEN
;
306 struct ovs_16aligned_ip6_hdr
*ip6
;
308 ip6
= (struct ovs_16aligned_ip6_hdr
*) l3
;
310 put_16aligned_be32(&ip6
->ip6_flow
, htonl(6 << 28) |
311 htonl(params
->flow
->tunnel
.ip_tos
<< 20));
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
, ¶ms
->flow
->tunnel
.ipv6_dst
, sizeof(ovs_be32
[4]));
317 data
->header_len
+= IPV6_HEADER_LEN
;
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
)
327 struct udp_header
*udp
;
329 udp
= netdev_tnl_ip_build_header(data
, params
, IPPROTO_UDP
);
330 udp
->udp_dst
= tnl_cfg
->dst_port
;
332 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
336 udp
->udp_csum
= htons(0xffff);
338 data
->header_len
+= sizeof *udp
;
343 gre_header_len(ovs_be16 flags
)
347 if (flags
& htons(GRE_CSUM
)) {
350 if (flags
& htons(GRE_KEY
)) {
353 if (flags
& htons(GRE_SEQ
)) {
360 parse_gre_header(struct dp_packet
*packet
,
361 struct flow_tnl
*tnl
)
363 const struct gre_base_hdr
*greh
;
364 ovs_16aligned_be32
*options
;
367 uint16_t greh_protocol
;
369 greh
= netdev_tnl_ip_extract_tnl_md(packet
, tnl
, &ulen
);
374 if (greh
->flags
& ~(htons(GRE_CSUM
| GRE_KEY
| GRE_SEQ
))) {
378 hlen
= ulen
+ gre_header_len(greh
->flags
);
379 if (hlen
> dp_packet_size(packet
)) {
383 options
= (ovs_16aligned_be32
*)(greh
+ 1);
384 if (greh
->flags
& htons(GRE_CSUM
)) {
387 pkt_csum
= csum(greh
, dp_packet_size(packet
) -
388 ((const unsigned char *)greh
-
389 (const unsigned char *)dp_packet_eth(packet
)));
393 tnl
->flags
= FLOW_TNL_F_CSUM
;
397 if (greh
->flags
& htons(GRE_KEY
)) {
398 tnl
->tun_id
= be32_to_be64(get_16aligned_be32(options
));
399 tnl
->flags
|= FLOW_TNL_F_KEY
;
403 if (greh
->flags
& htons(GRE_SEQ
)) {
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
);
422 netdev_gre_pop_header(struct dp_packet
*packet
)
424 struct pkt_metadata
*md
= &packet
->md
;
425 struct flow_tnl
*tnl
= &md
->tunnel
;
426 int hlen
= sizeof(struct eth_header
) + 4;
428 hlen
+= netdev_tnl_is_header_ipv6(dp_packet_data(packet
)) ?
429 IPV6_HEADER_LEN
: IP_HEADER_LEN
;
431 pkt_metadata_init_tnl(md
);
432 if (hlen
> dp_packet_size(packet
)) {
436 hlen
= parse_gre_header(packet
, tnl
);
441 dp_packet_reset_packet(packet
, hlen
);
445 dp_packet_delete(packet
);
450 netdev_gre_push_header(const struct netdev
*netdev
,
451 struct dp_packet
*packet
,
452 const struct ovs_action_push_tnl
*data
)
454 struct netdev_vport
*dev
= netdev_vport_cast(netdev
);
455 struct netdev_tunnel_config
*tnl_cfg
;
456 struct gre_base_hdr
*greh
;
459 greh
= netdev_tnl_push_ip_header(packet
, data
->header
, data
->header_len
, &ip_tot_size
);
461 if (greh
->flags
& htons(GRE_CSUM
)) {
462 ovs_be16
*csum_opt
= (ovs_be16
*) (greh
+ 1);
463 *csum_opt
= csum(greh
, ip_tot_size
);
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
++));
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
)
481 struct netdev_vport
*dev
= netdev_vport_cast(netdev
);
482 struct netdev_tunnel_config
*tnl_cfg
;
483 struct gre_base_hdr
*greh
;
484 ovs_16aligned_be32
*options
;
487 /* XXX: RCUfy tnl_cfg. */
488 ovs_mutex_lock(&dev
->mutex
);
489 tnl_cfg
= &dev
->tnl_cfg
;
491 greh
= netdev_tnl_ip_build_header(data
, params
, IPPROTO_GRE
);
493 if (params
->flow
->packet_type
== htonl(PT_ETH
)) {
494 greh
->protocol
= htons(ETH_TYPE_TEB
);
495 } else if (pt_ns(params
->flow
->packet_type
) == OFPHTN_ETHERTYPE
) {
496 greh
->protocol
= pt_ns_type_be(params
->flow
->packet_type
);
498 ovs_mutex_unlock(&dev
->mutex
);
503 options
= (ovs_16aligned_be32
*) (greh
+ 1);
504 if (params
->flow
->tunnel
.flags
& FLOW_TNL_F_CSUM
) {
505 greh
->flags
|= htons(GRE_CSUM
);
506 put_16aligned_be32(options
, 0);
510 if (tnl_cfg
->out_key_present
) {
511 greh
->flags
|= htons(GRE_KEY
);
512 put_16aligned_be32(options
, be64_to_be32(params
->flow
->tunnel
.tun_id
));
516 if (tnl_cfg
->set_seq
) {
517 greh
->flags
|= htons(GRE_SEQ
);
518 /* seqno is updated at push header */
522 ovs_mutex_unlock(&dev
->mutex
);
524 hlen
= (uint8_t *) options
- (uint8_t *) greh
;
526 data
->header_len
+= hlen
;
527 if (!params
->is_ipv6
) {
528 data
->tnl_type
= OVS_VPORT_TYPE_GRE
;
530 data
->tnl_type
= OVS_VPORT_TYPE_IP6GRE
;
536 netdev_erspan_pop_header(struct dp_packet
*packet
)
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
);
544 uint16_t greh_protocol
;
546 hlen
+= netdev_tnl_is_header_ipv6(dp_packet_data(packet
)) ?
547 IPV6_HEADER_LEN
: IP_HEADER_LEN
;
549 pkt_metadata_init_tnl(md
);
550 if (hlen
> dp_packet_size(packet
)) {
554 greh
= netdev_tnl_ip_extract_tnl_md(packet
, tnl
, &ulen
);
559 greh_protocol
= ntohs(greh
->protocol
);
560 if (greh_protocol
!= ETH_TYPE_ERSPAN1
&&
561 greh_protocol
!= ETH_TYPE_ERSPAN2
) {
565 if (greh
->flags
& ~htons(GRE_SEQ
)) {
569 ersh
= ERSPAN_HDR(greh
);
570 tnl
->tun_id
= be16_to_be64(htons(get_sid(ersh
)));
571 tnl
->erspan_ver
= ersh
->ver
;
573 if (ersh
->ver
== 1) {
574 ovs_16aligned_be32
*index
= ALIGNED_CAST(ovs_16aligned_be32
*,
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
;
586 VLOG_WARN_RL(&err_rl
, "ERSPAN version error %d", ersh
->ver
);
590 if (hlen
> dp_packet_size(packet
)) {
594 dp_packet_reset_packet(packet
, hlen
);
598 dp_packet_delete(packet
);
603 netdev_erspan_push_header(const struct netdev
*netdev
,
604 struct dp_packet
*packet
,
605 const struct ovs_action_push_tnl
*data
)
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
;
614 greh
= netdev_tnl_push_ip_header(packet
, data
->header
,
615 data
->header_len
, &ip_tot_size
);
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
++));
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
));
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
)
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
;
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
);
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
);
656 sid
= (uint16_t) tun_id
;
659 if (tnl_cfg
->erspan_ver_flow
) {
660 erspan_ver
= params
->flow
->tunnel
.erspan_ver
;
662 erspan_ver
= tnl_cfg
->erspan_ver
;
665 if (erspan_ver
== 1) {
666 greh
->protocol
= htons(ETH_TYPE_ERSPAN1
);
667 greh
->flags
= htons(GRE_SEQ
);
671 uint32_t erspan_idx
= (tnl_cfg
->erspan_idx_flow
672 ? params
->flow
->tunnel
.erspan_idx
673 : tnl_cfg
->erspan_idx
);
674 put_16aligned_be32(ALIGNED_CAST(ovs_16aligned_be32
*, ersh
+ 1),
677 hlen
= ERSPAN_GREHDR_LEN
+ sizeof *ersh
+ ERSPAN_V1_MDSIZE
;
678 } else if (erspan_ver
== 2) {
679 struct erspan_md2
*md2
= ALIGNED_CAST(struct erspan_md2
*, ersh
+ 1);
681 greh
->protocol
= htons(ETH_TYPE_ERSPAN2
);
682 greh
->flags
= htons(GRE_SEQ
);
686 md2
->sgt
= 0; /* security group tag */
688 put_16aligned_be32(&md2
->timestamp
, 0);
690 if (tnl_cfg
->erspan_hwid_flow
) {
691 set_hwid(md2
, params
->flow
->tunnel
.erspan_hwid
);
693 set_hwid(md2
, tnl_cfg
->erspan_hwid
);
696 if (tnl_cfg
->erspan_dir_flow
) {
697 md2
->dir
= params
->flow
->tunnel
.erspan_dir
;
699 md2
->dir
= tnl_cfg
->erspan_dir
;
702 hlen
= ERSPAN_GREHDR_LEN
+ sizeof *ersh
+ ERSPAN_V2_MDSIZE
;
704 VLOG_WARN_RL(&err_rl
, "ERSPAN version error %d", tnl_cfg
->erspan_ver
);
705 ovs_mutex_unlock(&dev
->mutex
);
709 ovs_mutex_unlock(&dev
->mutex
);
711 data
->header_len
+= hlen
;
713 if (params
->is_ipv6
) {
714 data
->tnl_type
= OVS_VPORT_TYPE_IP6ERSPAN
;
716 data
->tnl_type
= OVS_VPORT_TYPE_ERSPAN
;
722 netdev_gtpu_pop_header(struct dp_packet
*packet
)
724 struct pkt_metadata
*md
= &packet
->md
;
725 struct flow_tnl
*tnl
= &md
->tunnel
;
726 struct gtpuhdr
*gtph
;
727 unsigned int gtpu_hlen
;
730 ovs_assert(packet
->l3_ofs
> 0);
731 ovs_assert(packet
->l4_ofs
> 0);
733 pkt_metadata_init_tnl(md
);
734 if (GTPU_HLEN
> dp_packet_l4_size(packet
)) {
738 gtph
= udp_extract_tnl_md(packet
, tnl
, &hlen
);
743 tnl
->gtpu_flags
= gtph
->md
.flags
;
744 tnl
->gtpu_msgtype
= gtph
->md
.msgtype
;
745 tnl
->tun_id
= be32_to_be64(get_16aligned_be32(>ph
->teid
));
747 if (tnl
->gtpu_msgtype
== GTPU_MSGTYPE_GPDU
) {
748 struct ip_header
*ip
;
750 if (gtph
->md
.flags
& GTPU_S_MASK
) {
751 gtpu_hlen
= GTPU_HLEN
+ sizeof(struct gtpuhdr_opt
);
753 gtpu_hlen
= GTPU_HLEN
;
755 ip
= ALIGNED_CAST(struct ip_header
*, (char *)gtph
+ gtpu_hlen
);
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
);
762 VLOG_WARN_RL(&err_rl
, "GTP-U: Receive non-IP packet.");
764 dp_packet_reset_packet(packet
, hlen
+ gtpu_hlen
);
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.
771 packet
->packet_type
= htonl(PT_ETH
);
772 VLOG_WARN_ONCE("Receive non-GPDU msgtype: %"PRIu8
,
779 dp_packet_delete(packet
);
784 netdev_gtpu_push_header(const struct netdev
*netdev
,
785 struct dp_packet
*packet
,
786 const struct ovs_action_push_tnl
*data
)
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
;
793 unsigned int payload_len
;
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
);
802 gtpuh
= ALIGNED_CAST(struct gtpuhdr
*, udp
+ 1);
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
);
810 gtpuh
->len
= htons(payload_len
);
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
)
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
;
823 ovs_mutex_lock(&dev
->mutex
);
824 tnl_cfg
= &dev
->tnl_cfg
;
825 gtph
= udp_build_header(tnl_cfg
, data
, params
);
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(>ph
->teid
,
833 be64_to_be32(params
->flow
->tunnel
.tun_id
));
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
);
840 ovs_mutex_unlock(&dev
->mutex
);
842 data
->header_len
+= gtpu_hlen
;
843 data
->tnl_type
= OVS_VPORT_TYPE_GTPU
;
849 netdev_vxlan_pop_header(struct dp_packet
*packet
)
851 struct pkt_metadata
*md
= &packet
->md
;
852 struct flow_tnl
*tnl
= &md
->tunnel
;
853 struct vxlanhdr
*vxh
;
856 enum packet_type next_pt
= PT_ETH
;
858 ovs_assert(packet
->l3_ofs
> 0);
859 ovs_assert(packet
->l4_ofs
> 0);
861 pkt_metadata_init_tnl(md
);
862 if (VXLAN_HLEN
> dp_packet_l4_size(packet
)) {
866 vxh
= udp_extract_tnl_md(packet
, tnl
, &hlen
);
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
) {
878 switch (vxh
->vx_gpe
.next_protocol
) {
879 case VXLAN_GPE_NP_IPV4
:
882 case VXLAN_GPE_NP_IPV6
:
885 case VXLAN_GPE_NP_NSH
:
888 case VXLAN_GPE_NP_ETHERNET
:
896 if (vx_flags
!= htonl(VXLAN_FLAGS
) ||
897 (get_16aligned_be32(&vxh
->vx_vni
) & htonl(0xff))) {
898 VLOG_WARN_RL(&err_rl
, "invalid vxlan flags=%#x vni=%#x\n",
900 ntohl(get_16aligned_be32(&vxh
->vx_vni
)));
903 tnl
->tun_id
= htonll(ntohl(get_16aligned_be32(&vxh
->vx_vni
)) >> 8);
904 tnl
->flags
|= FLOW_TNL_F_KEY
;
906 packet
->packet_type
= htonl(next_pt
);
907 dp_packet_reset_packet(packet
, hlen
+ VXLAN_HLEN
);
908 if (next_pt
!= PT_ETH
) {
914 dp_packet_delete(packet
);
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
)
923 struct netdev_vport
*dev
= netdev_vport_cast(netdev
);
924 struct netdev_tunnel_config
*tnl_cfg
;
925 struct vxlanhdr
*vxh
;
927 /* XXX: RCUfy tnl_cfg. */
928 ovs_mutex_lock(&dev
->mutex
);
929 tnl_cfg
= &dev
->tnl_cfg
;
931 vxh
= udp_build_header(tnl_cfg
, data
, params
);
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));
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
)) {
942 vxh
->vx_gpe
.next_protocol
= VXLAN_GPE_NP_IPV4
;
945 vxh
->vx_gpe
.next_protocol
= VXLAN_GPE_NP_IPV6
;
948 vxh
->vx_gpe
.next_protocol
= VXLAN_GPE_NP_NSH
;
951 vxh
->vx_gpe
.next_protocol
= VXLAN_GPE_NP_ETHERNET
;
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));
965 ovs_mutex_unlock(&dev
->mutex
);
966 data
->header_len
+= sizeof *vxh
;
967 data
->tnl_type
= OVS_VPORT_TYPE_VXLAN
;
971 ovs_mutex_unlock(&dev
->mutex
);
976 netdev_geneve_pop_header(struct dp_packet
*packet
)
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
;
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
));
990 gnh
= udp_extract_tnl_md(packet
, tnl
, &ulen
);
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
));
1003 if (gnh
->ver
!= 0) {
1004 VLOG_WARN_RL(&err_rl
, "unknown geneve version: %"PRIu8
"\n", gnh
->ver
);
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
));
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
;
1018 memcpy(tnl
->metadata
.opts
.gnv
, gnh
->options
, opts_len
);
1019 tnl
->metadata
.present
.len
= opts_len
;
1020 tnl
->flags
|= FLOW_TNL_F_UDPIF
;
1022 packet
->packet_type
= htonl(PT_ETH
);
1023 dp_packet_reset_packet(packet
, hlen
);
1027 dp_packet_delete(packet
);
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
)
1036 struct netdev_vport
*dev
= netdev_vport_cast(netdev
);
1037 struct netdev_tunnel_config
*tnl_cfg
;
1038 struct genevehdr
*gnh
;
1042 /* XXX: RCUfy tnl_cfg. */
1043 ovs_mutex_lock(&dev
->mutex
);
1044 tnl_cfg
= &dev
->tnl_cfg
;
1046 gnh
= udp_build_header(tnl_cfg
, data
, params
);
1048 put_16aligned_be32(&gnh
->vni
, htonl(ntohll(params
->flow
->tunnel
.tun_id
) << 8));
1050 ovs_mutex_unlock(&dev
->mutex
);
1052 opt_len
= tun_metadata_to_geneve_header(¶ms
->flow
->tunnel
,
1053 gnh
->options
, &crit_opt
);
1055 gnh
->opt_len
= opt_len
/ 4;
1056 gnh
->oam
= !!(params
->flow
->tunnel
.flags
& FLOW_TNL_F_OAM
);
1057 gnh
->critical
= crit_opt
? 1 : 0;
1058 gnh
->proto_type
= htons(ETH_TYPE_TEB
);
1060 data
->header_len
+= sizeof *gnh
+ opt_len
;
1061 data
->tnl_type
= OVS_VPORT_TYPE_GENEVE
;
1067 netdev_tnl_egress_port_range(struct unixctl_conn
*conn
, int argc
,
1068 const char *argv
[], void *aux OVS_UNUSED
)
1073 struct ds ds
= DS_EMPTY_INITIALIZER
;
1075 ds_put_format(&ds
, "Tunnel UDP source port range: %"PRIu16
"-%"PRIu16
"\n",
1076 tnl_udp_port_min
, tnl_udp_port_max
);
1078 unixctl_command_reply(conn
, ds_cstr(&ds
));
1087 val1
= atoi(argv
[1]);
1088 if (val1
<= 0 || val1
> UINT16_MAX
) {
1089 unixctl_command_reply(conn
, "Invalid min.");
1092 val2
= atoi(argv
[2]);
1093 if (val2
<= 0 || val2
> UINT16_MAX
) {
1094 unixctl_command_reply(conn
, "Invalid max.");
1099 tnl_udp_port_min
= val2
;
1100 tnl_udp_port_max
= val1
;
1102 tnl_udp_port_min
= val1
;
1103 tnl_udp_port_max
= val2
;
1105 seq_change(tnl_conf_seq
);
1107 unixctl_command_reply(conn
, "OK");