LCOV - code coverage report
Current view: top level - lib - netdev-native-tnl.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 231 302 76.5 %
Date: 2016-09-14 01:02:56 Functions: 17 18 94.4 %
Branches: 60 124 48.4 %

           Branch data     Line data    Source code
       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 <netinet/in.h>
      27                 :            : #include <netinet/ip.h>
      28                 :            : #include <netinet/ip6.h>
      29                 :            : #include <sys/ioctl.h>
      30                 :            : 
      31                 :            : #include <errno.h>
      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                 :      20190 : VLOG_DEFINE_THIS_MODULE(native_tnl);
      49                 :            : static 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                 :            : 
      57                 :            : uint16_t tnl_udp_port_min = 32768;
      58                 :            : uint16_t tnl_udp_port_max = 61000;
      59                 :            : 
      60                 :            : void *
      61                 :       1932 : netdev_tnl_ip_extract_tnl_md(struct dp_packet *packet, struct flow_tnl *tnl,
      62                 :            :                   unsigned int *hlen)
      63                 :            : {
      64                 :            :     void *nh;
      65                 :            :     struct ip_header *ip;
      66                 :            :     struct ovs_16aligned_ip6_hdr *ip6;
      67                 :            :     void *l4;
      68                 :            :     int l3_size;
      69                 :            : 
      70                 :       1932 :     nh = dp_packet_l3(packet);
      71                 :       1932 :     ip = nh;
      72                 :       1932 :     ip6 = nh;
      73                 :       1932 :     l4 = dp_packet_l4(packet);
      74                 :            : 
      75 [ +  - ][ -  + ]:       1932 :     if (!nh || !l4) {
      76                 :          0 :         return NULL;
      77                 :            :     }
      78                 :            : 
      79                 :       1932 :     *hlen = sizeof(struct eth_header);
      80                 :            : 
      81                 :       1932 :     l3_size = dp_packet_size(packet) -
      82                 :       1932 :               ((char *)nh - (char *)dp_packet_data(packet));
      83                 :            : 
      84         [ +  + ]:       1932 :     if (IP_VER(ip->ip_ihl_ver) == 4) {
      85                 :            : 
      86                 :            :         ovs_be32 ip_src, ip_dst;
      87                 :            : 
      88         [ -  + ]:       1929 :         if (csum(ip, IP_IHL(ip->ip_ihl_ver) * 4)) {
      89         [ #  # ]:          0 :             VLOG_WARN_RL(&err_rl, "ip packet has invalid checksum");
      90                 :          0 :             return NULL;
      91                 :            :         }
      92                 :            : 
      93         [ -  + ]:       1929 :         if (ntohs(ip->ip_tot_len) > l3_size) {
      94         [ #  # ]:          0 :             VLOG_WARN_RL(&err_rl, "ip packet is truncated (IP length %d, actual %d)",
      95                 :            :                          ntohs(ip->ip_tot_len), l3_size);
      96                 :          0 :             return NULL;
      97                 :            :         }
      98         [ -  + ]:       1929 :         if (IP_IHL(ip->ip_ihl_ver) * 4 > sizeof(struct ip_header)) {
      99         [ #  # ]:          0 :             VLOG_WARN_RL(&err_rl, "ip options not supported on tunnel packets "
     100                 :            :                          "(%d bytes)", IP_IHL(ip->ip_ihl_ver) * 4);
     101                 :          0 :             return NULL;
     102                 :            :         }
     103                 :            : 
     104                 :       1929 :         ip_src = get_16aligned_be32(&ip->ip_src);
     105                 :       1929 :         ip_dst = get_16aligned_be32(&ip->ip_dst);
     106                 :            : 
     107                 :       1929 :         tnl->ip_src = ip_src;
     108                 :       1929 :         tnl->ip_dst = ip_dst;
     109                 :       1929 :         tnl->ip_tos = ip->ip_tos;
     110                 :       1929 :         tnl->ip_ttl = ip->ip_ttl;
     111                 :            : 
     112                 :       1929 :         *hlen += IP_HEADER_LEN;
     113                 :            : 
     114         [ +  - ]:          3 :     } else if (IP_VER(ip->ip_ihl_ver) == 6) {
     115                 :          3 :         ovs_be32 tc_flow = get_16aligned_be32(&ip6->ip6_flow);
     116                 :            : 
     117                 :          3 :         memcpy(tnl->ipv6_src.s6_addr, ip6->ip6_src.be16, sizeof ip6->ip6_src);
     118                 :          3 :         memcpy(tnl->ipv6_dst.s6_addr, ip6->ip6_dst.be16, sizeof ip6->ip6_dst);
     119                 :            : 
     120                 :          3 :         tnl->ip_tos = ntohl(tc_flow) >> 20;
     121                 :          3 :         tnl->ip_ttl = ip6->ip6_hlim;
     122                 :            : 
     123                 :          3 :         *hlen += IPV6_HEADER_LEN;
     124                 :            : 
     125                 :            :     } else {
     126         [ #  # ]:          0 :         VLOG_WARN_RL(&err_rl, "ipv4 packet has invalid version (%d)",
     127                 :            :                      IP_VER(ip->ip_ihl_ver));
     128                 :          0 :         return NULL;
     129                 :            :     }
     130                 :            : 
     131                 :       1932 :     return l4;
     132                 :            : }
     133                 :            : 
     134                 :            : /* Pushes the 'size' bytes of 'header' into the headroom of 'packet',
     135                 :            :  * reallocating the packet if necessary.  'header' should contain an Ethernet
     136                 :            :  * header, followed by an IPv4 header (without options), and an L4 header.
     137                 :            :  *
     138                 :            :  * This function sets the IP header's ip_tot_len field (which should be zeroed
     139                 :            :  * as part of 'header') and puts its value into '*ip_tot_size' as well.  Also
     140                 :            :  * updates IP header checksum.
     141                 :            :  *
     142                 :            :  * Return pointer to the L4 header added to 'packet'. */
     143                 :            : void *
     144                 :       1927 : netdev_tnl_push_ip_header(struct dp_packet *packet,
     145                 :            :                const void *header, int size, int *ip_tot_size)
     146                 :            : {
     147                 :            :     struct eth_header *eth;
     148                 :            :     struct ip_header *ip;
     149                 :            :     struct ovs_16aligned_ip6_hdr *ip6;
     150                 :            : 
     151                 :       1927 :     eth = dp_packet_push_uninit(packet, size);
     152                 :       1927 :     *ip_tot_size = dp_packet_size(packet) - sizeof (struct eth_header);
     153                 :            : 
     154                 :       1927 :     memcpy(eth, header, size);
     155                 :            : 
     156         [ +  + ]:       1927 :     if (netdev_tnl_is_header_ipv6(header)) {
     157                 :          1 :         ip6 = netdev_tnl_ipv6_hdr(eth);
     158                 :          1 :         *ip_tot_size -= IPV6_HEADER_LEN;
     159                 :          1 :         ip6->ip6_plen = htons(*ip_tot_size);
     160                 :          1 :         return ip6 + 1;
     161                 :            :     } else {
     162                 :       1926 :         ip = netdev_tnl_ip_hdr(eth);
     163                 :       1926 :         ip->ip_tot_len = htons(*ip_tot_size);
     164                 :       1926 :         ip->ip_csum = recalc_csum16(ip->ip_csum, 0, ip->ip_tot_len);
     165                 :       1926 :         *ip_tot_size -= IP_HEADER_LEN;
     166                 :       1926 :         return ip + 1;
     167                 :            :     }
     168                 :            : }
     169                 :            : 
     170                 :            : static void *
     171                 :       1898 : udp_extract_tnl_md(struct dp_packet *packet, struct flow_tnl *tnl,
     172                 :            :                    unsigned int *hlen)
     173                 :            : {
     174                 :            :     struct udp_header *udp;
     175                 :            : 
     176                 :       1898 :     udp = netdev_tnl_ip_extract_tnl_md(packet, tnl, hlen);
     177         [ -  + ]:       1898 :     if (!udp) {
     178                 :          0 :         return NULL;
     179                 :            :     }
     180                 :            : 
     181         [ +  + ]:       1898 :     if (udp->udp_csum) {
     182                 :            :         uint32_t csum;
     183         [ -  + ]:       1855 :         if (netdev_tnl_is_header_ipv6(dp_packet_data(packet))) {
     184                 :          0 :             csum = packet_csum_pseudoheader6(dp_packet_l3(packet));
     185                 :            :         } else {
     186                 :       1855 :             csum = packet_csum_pseudoheader(dp_packet_l3(packet));
     187                 :            :         }
     188                 :            : 
     189                 :       3710 :         csum = csum_continue(csum, udp, dp_packet_size(packet) -
     190                 :       3710 :                              ((const unsigned char *)udp -
     191                 :       1855 :                               (const unsigned char *)dp_packet_l2(packet)));
     192         [ -  + ]:       1855 :         if (csum_finish(csum)) {
     193                 :          0 :             return NULL;
     194                 :            :         }
     195                 :       1855 :         tnl->flags |= FLOW_TNL_F_CSUM;
     196                 :            :     }
     197                 :            : 
     198                 :       1898 :     tnl->tp_src = udp->udp_src;
     199                 :       1898 :     tnl->tp_dst = udp->udp_dst;
     200                 :            : 
     201                 :       1898 :     return udp + 1;
     202                 :            : }
     203                 :            : 
     204                 :            : 
     205                 :            : void
     206                 :       1899 : netdev_tnl_push_udp_header(struct dp_packet *packet,
     207                 :            :                            const struct ovs_action_push_tnl *data)
     208                 :            : {
     209                 :            :     struct udp_header *udp;
     210                 :            :     int ip_tot_size;
     211                 :            : 
     212                 :       1899 :     udp = netdev_tnl_push_ip_header(packet, data->header, data->header_len, &ip_tot_size);
     213                 :            : 
     214                 :            :     /* set udp src port */
     215                 :       1899 :     udp->udp_src = netdev_tnl_get_src_port(packet);
     216                 :       1899 :     udp->udp_len = htons(ip_tot_size);
     217                 :            : 
     218         [ +  + ]:       1899 :     if (udp->udp_csum) {
     219                 :            :         uint32_t csum;
     220         [ +  + ]:       1856 :         if (netdev_tnl_is_header_ipv6(dp_packet_data(packet))) {
     221                 :          1 :             csum = packet_csum_pseudoheader6(netdev_tnl_ipv6_hdr(dp_packet_data(packet)));
     222                 :            :         } else {
     223                 :       1855 :             csum = packet_csum_pseudoheader(netdev_tnl_ip_hdr(dp_packet_data(packet)));
     224                 :            :         }
     225                 :            : 
     226                 :       1856 :         csum = csum_continue(csum, udp, ip_tot_size);
     227                 :       1856 :         udp->udp_csum = csum_finish(csum);
     228                 :            : 
     229         [ -  + ]:       1856 :         if (!udp->udp_csum) {
     230                 :          0 :             udp->udp_csum = htons(0xffff);
     231                 :            :         }
     232                 :            :     }
     233                 :       1899 : }
     234                 :            : 
     235                 :            : static void *
     236                 :       2407 : eth_build_header(struct ovs_action_push_tnl *data,
     237                 :            :                  const struct netdev_tnl_build_header_params *params)
     238                 :            : {
     239         [ +  + ]:       2407 :     uint16_t eth_proto = params->is_ipv6 ? ETH_TYPE_IPV6 : ETH_TYPE_IP;
     240                 :            :     struct eth_header *eth;
     241                 :            : 
     242                 :       2407 :     memset(data->header, 0, sizeof data->header);
     243                 :            : 
     244                 :       2407 :     eth = (struct eth_header *)data->header;
     245                 :       2407 :     eth->eth_dst = params->dmac;
     246                 :       2407 :     eth->eth_src = params->smac;
     247                 :       2407 :     eth->eth_type = htons(eth_proto);
     248                 :       2407 :     data->header_len = sizeof(struct eth_header);
     249                 :       2407 :     return eth + 1;
     250                 :            : }
     251                 :            : 
     252                 :            : void *
     253                 :       2407 : netdev_tnl_ip_build_header(struct ovs_action_push_tnl *data,
     254                 :            :                            const struct netdev_tnl_build_header_params *params,
     255                 :            :                            uint8_t next_proto)
     256                 :            : {
     257                 :            :     void *l3;
     258                 :            : 
     259                 :       2407 :     l3 = eth_build_header(data, params);
     260         [ +  + ]:       2407 :     if (!params->is_ipv6) {
     261                 :       2391 :         ovs_be32 ip_src = in6_addr_get_mapped_ipv4(params->s_ip);
     262                 :            :         struct ip_header *ip;
     263                 :            : 
     264                 :       2391 :         ip = (struct ip_header *) l3;
     265                 :            : 
     266                 :       2391 :         ip->ip_ihl_ver = IP_IHL_VER(5, 4);
     267                 :       2391 :         ip->ip_tos = params->flow->tunnel.ip_tos;
     268                 :       2391 :         ip->ip_ttl = params->flow->tunnel.ip_ttl;
     269                 :       2391 :         ip->ip_proto = next_proto;
     270                 :       2391 :         put_16aligned_be32(&ip->ip_src, ip_src);
     271                 :       2391 :         put_16aligned_be32(&ip->ip_dst, params->flow->tunnel.ip_dst);
     272                 :            : 
     273         [ +  - ]:       2391 :         ip->ip_frag_off = (params->flow->tunnel.flags & FLOW_TNL_F_DONT_FRAGMENT) ?
     274                 :            :                           htons(IP_DF) : 0;
     275                 :            : 
     276                 :            :         /* Checksum has already been zeroed by eth_build_header. */
     277                 :       2391 :         ip->ip_csum = csum(ip, sizeof *ip);
     278                 :            : 
     279                 :       2391 :         data->header_len += IP_HEADER_LEN;
     280                 :       2391 :         return ip + 1;
     281                 :            :     } else {
     282                 :            :         struct ovs_16aligned_ip6_hdr *ip6;
     283                 :            : 
     284                 :         16 :         ip6 = (struct ovs_16aligned_ip6_hdr *) l3;
     285                 :            : 
     286                 :         32 :         put_16aligned_be32(&ip6->ip6_flow, htonl(6 << 28) |
     287                 :         16 :                            htonl(params->flow->tunnel.ip_tos << 20));
     288                 :         16 :         ip6->ip6_hlim = params->flow->tunnel.ip_ttl;
     289                 :         16 :         ip6->ip6_nxt = next_proto;
     290                 :         16 :         memcpy(&ip6->ip6_src, params->s_ip, sizeof(ovs_be32[4]));
     291                 :         16 :         memcpy(&ip6->ip6_dst, &params->flow->tunnel.ipv6_dst, sizeof(ovs_be32[4]));
     292                 :            : 
     293                 :         16 :         data->header_len += IPV6_HEADER_LEN;
     294                 :         16 :         return ip6 + 1;
     295                 :            :     }
     296                 :            : }
     297                 :            : 
     298                 :            : static void *
     299                 :       2317 : udp_build_header(struct netdev_tunnel_config *tnl_cfg,
     300                 :            :                  struct ovs_action_push_tnl *data,
     301                 :            :                  const struct netdev_tnl_build_header_params *params)
     302                 :            : {
     303                 :            :     struct udp_header *udp;
     304                 :            : 
     305                 :       2317 :     udp = netdev_tnl_ip_build_header(data, params, IPPROTO_UDP);
     306                 :       2317 :     udp->udp_dst = tnl_cfg->dst_port;
     307                 :            : 
     308 [ +  + ][ +  + ]:       2317 :     if (params->is_ipv6 || params->flow->tunnel.flags & FLOW_TNL_F_CSUM) {
     309                 :            :         /* Write a value in now to mark that we should compute the checksum
     310                 :            :          * later. 0xffff is handy because it is transparent to the
     311                 :            :          * calculation. */
     312                 :       2241 :         udp->udp_csum = htons(0xffff);
     313                 :            :     }
     314                 :       2317 :     data->header_len += sizeof *udp;
     315                 :       2317 :     return udp + 1;
     316                 :            : }
     317                 :            : 
     318                 :            : static int
     319                 :         32 : gre_header_len(ovs_be16 flags)
     320                 :            : {
     321                 :         32 :     int hlen = 4;
     322                 :            : 
     323         [ -  + ]:         32 :     if (flags & htons(GRE_CSUM)) {
     324                 :          0 :         hlen += 4;
     325                 :            :     }
     326         [ +  + ]:         32 :     if (flags & htons(GRE_KEY)) {
     327                 :          2 :         hlen += 4;
     328                 :            :     }
     329         [ -  + ]:         32 :     if (flags & htons(GRE_SEQ)) {
     330                 :          0 :         hlen += 4;
     331                 :            :     }
     332                 :         32 :     return hlen;
     333                 :            : }
     334                 :            : 
     335                 :            : static int
     336                 :         34 : parse_gre_header(struct dp_packet *packet,
     337                 :            :                  struct flow_tnl *tnl)
     338                 :            : {
     339                 :            :     const struct gre_base_hdr *greh;
     340                 :            :     ovs_16aligned_be32 *options;
     341                 :            :     int hlen;
     342                 :            :     unsigned int ulen;
     343                 :            : 
     344                 :         34 :     greh = netdev_tnl_ip_extract_tnl_md(packet, tnl, &ulen);
     345         [ -  + ]:         34 :     if (!greh) {
     346                 :          0 :         return -EINVAL;
     347                 :            :     }
     348                 :            : 
     349         [ -  + ]:         34 :     if (greh->flags & ~(htons(GRE_CSUM | GRE_KEY | GRE_SEQ))) {
     350                 :          0 :         return -EINVAL;
     351                 :            :     }
     352                 :            : 
     353         [ +  + ]:         34 :     if (greh->protocol != htons(ETH_TYPE_TEB)) {
     354                 :          2 :         return -EINVAL;
     355                 :            :     }
     356                 :            : 
     357                 :         32 :     hlen = ulen + gre_header_len(greh->flags);
     358         [ -  + ]:         32 :     if (hlen > dp_packet_size(packet)) {
     359                 :          0 :         return -EINVAL;
     360                 :            :     }
     361                 :            : 
     362                 :         32 :     options = (ovs_16aligned_be32 *)(greh + 1);
     363         [ -  + ]:         32 :     if (greh->flags & htons(GRE_CSUM)) {
     364                 :            :         ovs_be16 pkt_csum;
     365                 :            : 
     366                 :          0 :         pkt_csum = csum(greh, dp_packet_size(packet) -
     367                 :          0 :                               ((const unsigned char *)greh -
     368                 :          0 :                                (const unsigned char *)dp_packet_l2(packet)));
     369         [ #  # ]:          0 :         if (pkt_csum) {
     370                 :          0 :             return -EINVAL;
     371                 :            :         }
     372                 :          0 :         tnl->flags = FLOW_TNL_F_CSUM;
     373                 :          0 :         options++;
     374                 :            :     }
     375                 :            : 
     376         [ +  + ]:         32 :     if (greh->flags & htons(GRE_KEY)) {
     377                 :          2 :         tnl->tun_id = be32_to_be64(get_16aligned_be32(options));
     378                 :          2 :         tnl->flags |= FLOW_TNL_F_KEY;
     379                 :          2 :         options++;
     380                 :            :     }
     381                 :            : 
     382         [ -  + ]:         32 :     if (greh->flags & htons(GRE_SEQ)) {
     383                 :          0 :         options++;
     384                 :            :     }
     385                 :            : 
     386                 :         34 :     return hlen;
     387                 :            : }
     388                 :            : 
     389                 :            : struct dp_packet *
     390                 :         34 : netdev_gre_pop_header(struct dp_packet *packet)
     391                 :            : {
     392                 :         34 :     struct pkt_metadata *md = &packet->md;
     393                 :         34 :     struct flow_tnl *tnl = &md->tunnel;
     394                 :         34 :     int hlen = sizeof(struct eth_header) + 4;
     395                 :            : 
     396                 :         34 :     hlen += netdev_tnl_is_header_ipv6(dp_packet_data(packet)) ?
     397         [ +  + ]:         34 :             IPV6_HEADER_LEN : IP_HEADER_LEN;
     398                 :            : 
     399                 :         34 :     pkt_metadata_init_tnl(md);
     400         [ -  + ]:         34 :     if (hlen > dp_packet_size(packet)) {
     401                 :          0 :         goto err;
     402                 :            :     }
     403                 :            : 
     404                 :         34 :     hlen = parse_gre_header(packet, tnl);
     405         [ +  + ]:         34 :     if (hlen < 0) {
     406                 :          2 :         goto err;
     407                 :            :     }
     408                 :            : 
     409                 :         32 :     dp_packet_reset_packet(packet, hlen);
     410                 :            : 
     411                 :         32 :     return packet;
     412                 :            : err:
     413                 :          2 :     dp_packet_delete(packet);
     414                 :          2 :     return NULL;
     415                 :            : }
     416                 :            : 
     417                 :            : void
     418                 :         28 : netdev_gre_push_header(struct dp_packet *packet,
     419                 :            :                        const struct ovs_action_push_tnl *data)
     420                 :            : {
     421                 :            :     struct gre_base_hdr *greh;
     422                 :            :     int ip_tot_size;
     423                 :            : 
     424                 :         28 :     greh = netdev_tnl_push_ip_header(packet, data->header, data->header_len, &ip_tot_size);
     425                 :            : 
     426         [ -  + ]:         28 :     if (greh->flags & htons(GRE_CSUM)) {
     427                 :          0 :         ovs_be16 *csum_opt = (ovs_be16 *) (greh + 1);
     428                 :          0 :         *csum_opt = csum(greh, ip_tot_size);
     429                 :            :     }
     430                 :         28 : }
     431                 :            : 
     432                 :            : int
     433                 :         90 : netdev_gre_build_header(const struct netdev *netdev,
     434                 :            :                         struct ovs_action_push_tnl *data,
     435                 :            :                         const struct netdev_tnl_build_header_params *params)
     436                 :            : {
     437                 :         90 :     struct netdev_vport *dev = netdev_vport_cast(netdev);
     438                 :            :     struct netdev_tunnel_config *tnl_cfg;
     439                 :            :     struct gre_base_hdr *greh;
     440                 :            :     ovs_16aligned_be32 *options;
     441                 :            :     unsigned int hlen;
     442                 :            : 
     443                 :            :     /* XXX: RCUfy tnl_cfg. */
     444                 :         90 :     ovs_mutex_lock(&dev->mutex);
     445                 :         90 :     tnl_cfg = &dev->tnl_cfg;
     446                 :            : 
     447                 :         90 :     greh = netdev_tnl_ip_build_header(data, params, IPPROTO_GRE);
     448                 :            : 
     449                 :         90 :     greh->protocol = htons(ETH_TYPE_TEB);
     450                 :         90 :     greh->flags = 0;
     451                 :            : 
     452                 :         90 :     options = (ovs_16aligned_be32 *) (greh + 1);
     453         [ -  + ]:         90 :     if (params->flow->tunnel.flags & FLOW_TNL_F_CSUM) {
     454                 :          0 :         greh->flags |= htons(GRE_CSUM);
     455                 :          0 :         put_16aligned_be32(options, 0);
     456                 :          0 :         options++;
     457                 :            :     }
     458                 :            : 
     459         [ +  + ]:         90 :     if (tnl_cfg->out_key_present) {
     460                 :         10 :         greh->flags |= htons(GRE_KEY);
     461                 :         10 :         put_16aligned_be32(options, be64_to_be32(params->flow->tunnel.tun_id));
     462                 :         10 :         options++;
     463                 :            :     }
     464                 :            : 
     465                 :         90 :     ovs_mutex_unlock(&dev->mutex);
     466                 :            : 
     467                 :         90 :     hlen = (uint8_t *) options - (uint8_t *) greh;
     468                 :            : 
     469                 :         90 :     data->header_len += hlen;
     470                 :         90 :     data->tnl_type = OVS_VPORT_TYPE_GRE;
     471                 :         90 :     return 0;
     472                 :            : }
     473                 :            : 
     474                 :            : struct dp_packet *
     475                 :         41 : netdev_vxlan_pop_header(struct dp_packet *packet)
     476                 :            : {
     477                 :         41 :     struct pkt_metadata *md = &packet->md;
     478                 :         41 :     struct flow_tnl *tnl = &md->tunnel;
     479                 :            :     struct vxlanhdr *vxh;
     480                 :            :     unsigned int hlen;
     481                 :            : 
     482                 :         41 :     pkt_metadata_init_tnl(md);
     483         [ -  + ]:         41 :     if (VXLAN_HLEN > dp_packet_l4_size(packet)) {
     484                 :          0 :         goto err;
     485                 :            :     }
     486                 :            : 
     487                 :         41 :     vxh = udp_extract_tnl_md(packet, tnl, &hlen);
     488         [ -  + ]:         41 :     if (!vxh) {
     489                 :          0 :         goto err;
     490                 :            :     }
     491                 :            : 
     492   [ +  -  -  + ]:         82 :     if (get_16aligned_be32(&vxh->vx_flags) != htonl(VXLAN_FLAGS) ||
     493                 :         41 :        (get_16aligned_be32(&vxh->vx_vni) & htonl(0xff))) {
     494         [ #  # ]:          0 :         VLOG_WARN_RL(&err_rl, "invalid vxlan flags=%#x vni=%#x\n",
     495                 :            :                      ntohl(get_16aligned_be32(&vxh->vx_flags)),
     496                 :            :                      ntohl(get_16aligned_be32(&vxh->vx_vni)));
     497                 :          0 :         goto err;
     498                 :            :     }
     499                 :         41 :     tnl->tun_id = htonll(ntohl(get_16aligned_be32(&vxh->vx_vni)) >> 8);
     500                 :         41 :     tnl->flags |= FLOW_TNL_F_KEY;
     501                 :            : 
     502                 :         41 :     dp_packet_reset_packet(packet, hlen + VXLAN_HLEN);
     503                 :            : 
     504                 :         41 :     return packet;
     505                 :            : err:
     506                 :          0 :     dp_packet_delete(packet);
     507                 :         41 :     return NULL;
     508                 :            : }
     509                 :            : 
     510                 :            : int
     511                 :         79 : netdev_vxlan_build_header(const struct netdev *netdev,
     512                 :            :                           struct ovs_action_push_tnl *data,
     513                 :            :                           const struct netdev_tnl_build_header_params *params)
     514                 :            : {
     515                 :         79 :     struct netdev_vport *dev = netdev_vport_cast(netdev);
     516                 :            :     struct netdev_tunnel_config *tnl_cfg;
     517                 :            :     struct vxlanhdr *vxh;
     518                 :            : 
     519                 :            :     /* XXX: RCUfy tnl_cfg. */
     520                 :         79 :     ovs_mutex_lock(&dev->mutex);
     521                 :         79 :     tnl_cfg = &dev->tnl_cfg;
     522                 :            : 
     523                 :         79 :     vxh = udp_build_header(tnl_cfg, data, params);
     524                 :            : 
     525                 :         79 :     put_16aligned_be32(&vxh->vx_flags, htonl(VXLAN_FLAGS));
     526                 :         79 :     put_16aligned_be32(&vxh->vx_vni, htonl(ntohll(params->flow->tunnel.tun_id) << 8));
     527                 :            : 
     528                 :         79 :     ovs_mutex_unlock(&dev->mutex);
     529                 :         79 :     data->header_len += sizeof *vxh;
     530                 :         79 :     data->tnl_type = OVS_VPORT_TYPE_VXLAN;
     531                 :         79 :     return 0;
     532                 :            : }
     533                 :            : 
     534                 :            : struct dp_packet *
     535                 :       1857 : netdev_geneve_pop_header(struct dp_packet *packet)
     536                 :            : {
     537                 :       1857 :     struct pkt_metadata *md = &packet->md;
     538                 :       1857 :     struct flow_tnl *tnl = &md->tunnel;
     539                 :            :     struct genevehdr *gnh;
     540                 :            :     unsigned int hlen, opts_len, ulen;
     541                 :            : 
     542                 :       1857 :     pkt_metadata_init_tnl(md);
     543         [ -  + ]:       1857 :     if (GENEVE_BASE_HLEN > dp_packet_l4_size(packet)) {
     544         [ #  # ]:          0 :         VLOG_WARN_RL(&err_rl, "geneve packet too small: min header=%u packet size=%"PRIuSIZE"\n",
     545                 :            :                      (unsigned int)GENEVE_BASE_HLEN, dp_packet_l4_size(packet));
     546                 :          0 :         goto err;
     547                 :            :     }
     548                 :            : 
     549                 :       1857 :     gnh = udp_extract_tnl_md(packet, tnl, &ulen);
     550         [ -  + ]:       1857 :     if (!gnh) {
     551                 :          0 :         goto err;
     552                 :            :     }
     553                 :            : 
     554                 :       1857 :     opts_len = gnh->opt_len * 4;
     555                 :       1857 :     hlen = ulen + GENEVE_BASE_HLEN + opts_len;
     556         [ -  + ]:       1857 :     if (hlen > dp_packet_size(packet)) {
     557         [ #  # ]:          0 :         VLOG_WARN_RL(&err_rl, "geneve packet too small: header len=%u packet size=%u\n",
     558                 :            :                      hlen, dp_packet_size(packet));
     559                 :          0 :         goto err;
     560                 :            :     }
     561                 :            : 
     562         [ -  + ]:       1857 :     if (gnh->ver != 0) {
     563         [ #  # ]:          0 :         VLOG_WARN_RL(&err_rl, "unknown geneve version: %"PRIu8"\n", gnh->ver);
     564                 :          0 :         goto err;
     565                 :            :     }
     566                 :            : 
     567         [ -  + ]:       1857 :     if (gnh->proto_type != htons(ETH_TYPE_TEB)) {
     568         [ #  # ]:          0 :         VLOG_WARN_RL(&err_rl, "unknown geneve encapsulated protocol: %#x\n",
     569                 :            :                      ntohs(gnh->proto_type));
     570                 :          0 :         goto err;
     571                 :            :     }
     572                 :            : 
     573                 :       1857 :     tnl->flags |= gnh->oam ? FLOW_TNL_F_OAM : 0;
     574                 :       1857 :     tnl->tun_id = htonll(ntohl(get_16aligned_be32(&gnh->vni)) >> 8);
     575                 :       1857 :     tnl->flags |= FLOW_TNL_F_KEY;
     576                 :            : 
     577                 :       1857 :     memcpy(tnl->metadata.opts.gnv, gnh->options, opts_len);
     578                 :       1857 :     tnl->metadata.present.len = opts_len;
     579                 :       1857 :     tnl->flags |= FLOW_TNL_F_UDPIF;
     580                 :            : 
     581                 :       1857 :     dp_packet_reset_packet(packet, hlen);
     582                 :            : 
     583                 :       1857 :     return packet;
     584                 :            : err:
     585                 :          0 :     dp_packet_delete(packet);
     586                 :       1857 :     return NULL;
     587                 :            : }
     588                 :            : 
     589                 :            : int
     590                 :       2238 : netdev_geneve_build_header(const struct netdev *netdev,
     591                 :            :                            struct ovs_action_push_tnl *data,
     592                 :            :                            const struct netdev_tnl_build_header_params *params)
     593                 :            : {
     594                 :       2238 :     struct netdev_vport *dev = netdev_vport_cast(netdev);
     595                 :            :     struct netdev_tunnel_config *tnl_cfg;
     596                 :            :     struct genevehdr *gnh;
     597                 :            :     int opt_len;
     598                 :            :     bool crit_opt;
     599                 :            : 
     600                 :            :     /* XXX: RCUfy tnl_cfg. */
     601                 :       2238 :     ovs_mutex_lock(&dev->mutex);
     602                 :       2238 :     tnl_cfg = &dev->tnl_cfg;
     603                 :            : 
     604                 :       2238 :     gnh = udp_build_header(tnl_cfg, data, params);
     605                 :            : 
     606                 :       2238 :     put_16aligned_be32(&gnh->vni, htonl(ntohll(params->flow->tunnel.tun_id) << 8));
     607                 :            : 
     608                 :       2238 :     ovs_mutex_unlock(&dev->mutex);
     609                 :            : 
     610                 :       2238 :     opt_len = tun_metadata_to_geneve_header(&params->flow->tunnel,
     611                 :       2238 :                                             gnh->options, &crit_opt);
     612                 :            : 
     613                 :       2238 :     gnh->opt_len = opt_len / 4;
     614                 :       2238 :     gnh->oam = !!(params->flow->tunnel.flags & FLOW_TNL_F_OAM);
     615                 :       2238 :     gnh->critical = crit_opt ? 1 : 0;
     616                 :       2238 :     gnh->proto_type = htons(ETH_TYPE_TEB);
     617                 :            : 
     618                 :       2238 :     data->header_len += sizeof *gnh + opt_len;
     619                 :       2238 :     data->tnl_type = OVS_VPORT_TYPE_GENEVE;
     620                 :       2238 :     return 0;
     621                 :            : }
     622                 :            : 
     623                 :            : 
     624                 :            : void
     625                 :          0 : netdev_tnl_egress_port_range(struct unixctl_conn *conn, int argc,
     626                 :            :                              const char *argv[], void *aux OVS_UNUSED)
     627                 :            : {
     628                 :            :     int val1, val2;
     629                 :            : 
     630         [ #  # ]:          0 :     if (argc < 3) {
     631                 :          0 :         struct ds ds = DS_EMPTY_INITIALIZER;
     632                 :            : 
     633                 :          0 :         ds_put_format(&ds, "Tunnel UDP source port range: %"PRIu16"-%"PRIu16"\n",
     634                 :            :                             tnl_udp_port_min, tnl_udp_port_max);
     635                 :            : 
     636                 :          0 :         unixctl_command_reply(conn, ds_cstr(&ds));
     637                 :          0 :         ds_destroy(&ds);
     638                 :          0 :         return;
     639                 :            :     }
     640                 :            : 
     641         [ #  # ]:          0 :     if (argc != 3) {
     642                 :          0 :         return;
     643                 :            :     }
     644                 :            : 
     645                 :          0 :     val1 = atoi(argv[1]);
     646 [ #  # ][ #  # ]:          0 :     if (val1 <= 0 || val1 > UINT16_MAX) {
     647                 :          0 :         unixctl_command_reply(conn, "Invalid min.");
     648                 :          0 :         return;
     649                 :            :     }
     650                 :          0 :     val2 = atoi(argv[2]);
     651 [ #  # ][ #  # ]:          0 :     if (val2 <= 0 || val2 > UINT16_MAX) {
     652                 :          0 :         unixctl_command_reply(conn, "Invalid max.");
     653                 :          0 :         return;
     654                 :            :     }
     655                 :            : 
     656         [ #  # ]:          0 :     if (val1 > val2) {
     657                 :          0 :         tnl_udp_port_min = val2;
     658                 :          0 :         tnl_udp_port_max = val1;
     659                 :            :     } else {
     660                 :          0 :         tnl_udp_port_min = val1;
     661                 :          0 :         tnl_udp_port_max = val2;
     662                 :            :     }
     663                 :          0 :     seq_change(tnl_conf_seq);
     664                 :            : 
     665                 :          0 :     unixctl_command_reply(conn, "OK");
     666                 :            : }

Generated by: LCOV version 1.12