linux/arch/um/drivers/vector_transports.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2017 - Cambridge Greys Limited
   3 * Copyright (C) 2011 - 2014 Cisco Systems Inc
   4 * Licensed under the GPL.
   5 */
   6
   7#include <linux/etherdevice.h>
   8#include <linux/netdevice.h>
   9#include <linux/skbuff.h>
  10#include <linux/slab.h>
  11#include <asm/byteorder.h>
  12#include <uapi/linux/ip.h>
  13#include <uapi/linux/virtio_net.h>
  14#include <linux/virtio_net.h>
  15#include <linux/virtio_byteorder.h>
  16#include <linux/netdev_features.h>
  17#include "vector_user.h"
  18#include "vector_kern.h"
  19
  20#define GOOD_LINEAR 512
  21#define GSO_ERROR "Incoming GSO frames and GRO disabled on the interface"
  22
  23struct gre_minimal_header {
  24        uint16_t header;
  25        uint16_t arptype;
  26};
  27
  28
  29struct uml_gre_data {
  30        uint32_t rx_key;
  31        uint32_t tx_key;
  32        uint32_t sequence;
  33
  34        bool ipv6;
  35        bool has_sequence;
  36        bool pin_sequence;
  37        bool checksum;
  38        bool key;
  39        struct gre_minimal_header expected_header;
  40
  41        uint32_t checksum_offset;
  42        uint32_t key_offset;
  43        uint32_t sequence_offset;
  44
  45};
  46
  47struct uml_l2tpv3_data {
  48        uint64_t rx_cookie;
  49        uint64_t tx_cookie;
  50        uint64_t rx_session;
  51        uint64_t tx_session;
  52        uint32_t counter;
  53
  54        bool udp;
  55        bool ipv6;
  56        bool has_counter;
  57        bool pin_counter;
  58        bool cookie;
  59        bool cookie_is_64;
  60
  61        uint32_t cookie_offset;
  62        uint32_t session_offset;
  63        uint32_t counter_offset;
  64};
  65
  66static int l2tpv3_form_header(uint8_t *header,
  67        struct sk_buff *skb, struct vector_private *vp)
  68{
  69        struct uml_l2tpv3_data *td = vp->transport_data;
  70        uint32_t *counter;
  71
  72        if (td->udp)
  73                *(uint32_t *) header = cpu_to_be32(L2TPV3_DATA_PACKET);
  74        (*(uint32_t *) (header + td->session_offset)) = td->tx_session;
  75
  76        if (td->cookie) {
  77                if (td->cookie_is_64)
  78                        (*(uint64_t *)(header + td->cookie_offset)) =
  79                                td->tx_cookie;
  80                else
  81                        (*(uint32_t *)(header + td->cookie_offset)) =
  82                                td->tx_cookie;
  83        }
  84        if (td->has_counter) {
  85                counter = (uint32_t *)(header + td->counter_offset);
  86                if (td->pin_counter) {
  87                        *counter = 0;
  88                } else {
  89                        td->counter++;
  90                        *counter = cpu_to_be32(td->counter);
  91                }
  92        }
  93        return 0;
  94}
  95
  96static int gre_form_header(uint8_t *header,
  97                struct sk_buff *skb, struct vector_private *vp)
  98{
  99        struct uml_gre_data *td = vp->transport_data;
 100        uint32_t *sequence;
 101        *((uint32_t *) header) = *((uint32_t *) &td->expected_header);
 102        if (td->key)
 103                (*(uint32_t *) (header + td->key_offset)) = td->tx_key;
 104        if (td->has_sequence) {
 105                sequence = (uint32_t *)(header + td->sequence_offset);
 106                if (td->pin_sequence)
 107                        *sequence = 0;
 108                else
 109                        *sequence = cpu_to_be32(++td->sequence);
 110        }
 111        return 0;
 112}
 113
 114static int raw_form_header(uint8_t *header,
 115                struct sk_buff *skb, struct vector_private *vp)
 116{
 117        struct virtio_net_hdr *vheader = (struct virtio_net_hdr *) header;
 118
 119        virtio_net_hdr_from_skb(
 120                skb,
 121                vheader,
 122                virtio_legacy_is_little_endian(),
 123                false,
 124                0
 125        );
 126
 127        return 0;
 128}
 129
 130static int l2tpv3_verify_header(
 131        uint8_t *header, struct sk_buff *skb, struct vector_private *vp)
 132{
 133        struct uml_l2tpv3_data *td = vp->transport_data;
 134        uint32_t *session;
 135        uint64_t cookie;
 136
 137        if ((!td->udp) && (!td->ipv6))
 138                header += sizeof(struct iphdr) /* fix for ipv4 raw */;
 139
 140        /* we do not do a strict check for "data" packets as per
 141         * the RFC spec because the pure IP spec does not have
 142         * that anyway.
 143         */
 144
 145        if (td->cookie) {
 146                if (td->cookie_is_64)
 147                        cookie = *(uint64_t *)(header + td->cookie_offset);
 148                else
 149                        cookie = *(uint32_t *)(header + td->cookie_offset);
 150                if (cookie != td->rx_cookie) {
 151                        if (net_ratelimit())
 152                                netdev_err(vp->dev, "uml_l2tpv3: unknown cookie id");
 153                        return -1;
 154                }
 155        }
 156        session = (uint32_t *) (header + td->session_offset);
 157        if (*session != td->rx_session) {
 158                if (net_ratelimit())
 159                        netdev_err(vp->dev, "uml_l2tpv3: session mismatch");
 160                return -1;
 161        }
 162        return 0;
 163}
 164
 165static int gre_verify_header(
 166        uint8_t *header, struct sk_buff *skb, struct vector_private *vp)
 167{
 168
 169        uint32_t key;
 170        struct uml_gre_data *td = vp->transport_data;
 171
 172        if (!td->ipv6)
 173                header += sizeof(struct iphdr) /* fix for ipv4 raw */;
 174
 175        if (*((uint32_t *) header) != *((uint32_t *) &td->expected_header)) {
 176                if (net_ratelimit())
 177                        netdev_err(vp->dev, "header type disagreement, expecting %0x, got %0x",
 178                                *((uint32_t *) &td->expected_header),
 179                                *((uint32_t *) header)
 180                        );
 181                return -1;
 182        }
 183
 184        if (td->key) {
 185                key = (*(uint32_t *)(header + td->key_offset));
 186                if (key != td->rx_key) {
 187                        if (net_ratelimit())
 188                                netdev_err(vp->dev, "unknown key id %0x, expecting %0x",
 189                                                key, td->rx_key);
 190                        return -1;
 191                }
 192        }
 193        return 0;
 194}
 195
 196static int raw_verify_header(
 197        uint8_t *header, struct sk_buff *skb, struct vector_private *vp)
 198{
 199        struct virtio_net_hdr *vheader = (struct virtio_net_hdr *) header;
 200
 201        if ((vheader->gso_type != VIRTIO_NET_HDR_GSO_NONE) &&
 202                (vp->req_size != 65536)) {
 203                if (net_ratelimit())
 204                        netdev_err(
 205                                vp->dev,
 206                                GSO_ERROR
 207                );
 208        }
 209        if ((vheader->flags & VIRTIO_NET_HDR_F_DATA_VALID) > 0)
 210                return 1;
 211
 212        virtio_net_hdr_to_skb(skb, vheader, virtio_legacy_is_little_endian());
 213        return 0;
 214}
 215
 216static bool get_uint_param(
 217        struct arglist *def, char *param, unsigned int *result)
 218{
 219        char *arg = uml_vector_fetch_arg(def, param);
 220
 221        if (arg != NULL) {
 222                if (kstrtoint(arg, 0, result) == 0)
 223                        return true;
 224        }
 225        return false;
 226}
 227
 228static bool get_ulong_param(
 229        struct arglist *def, char *param, unsigned long *result)
 230{
 231        char *arg = uml_vector_fetch_arg(def, param);
 232
 233        if (arg != NULL) {
 234                if (kstrtoul(arg, 0, result) == 0)
 235                        return true;
 236                return true;
 237        }
 238        return false;
 239}
 240
 241static int build_gre_transport_data(struct vector_private *vp)
 242{
 243        struct uml_gre_data *td;
 244        int temp_int;
 245        int temp_rx;
 246        int temp_tx;
 247
 248        vp->transport_data = kmalloc(sizeof(struct uml_gre_data), GFP_KERNEL);
 249        if (vp->transport_data == NULL)
 250                return -ENOMEM;
 251        td = vp->transport_data;
 252        td->sequence = 0;
 253
 254        td->expected_header.arptype = GRE_IRB;
 255        td->expected_header.header = 0;
 256
 257        vp->form_header = &gre_form_header;
 258        vp->verify_header = &gre_verify_header;
 259        vp->header_size = 4;
 260        td->key_offset = 4;
 261        td->sequence_offset = 4;
 262        td->checksum_offset = 4;
 263
 264        td->ipv6 = false;
 265        if (get_uint_param(vp->parsed, "v6", &temp_int)) {
 266                if (temp_int > 0)
 267                        td->ipv6 = true;
 268        }
 269        td->key = false;
 270        if (get_uint_param(vp->parsed, "rx_key", &temp_rx)) {
 271                if (get_uint_param(vp->parsed, "tx_key", &temp_tx)) {
 272                        td->key = true;
 273                        td->expected_header.header |= GRE_MODE_KEY;
 274                        td->rx_key = cpu_to_be32(temp_rx);
 275                        td->tx_key = cpu_to_be32(temp_tx);
 276                        vp->header_size += 4;
 277                        td->sequence_offset += 4;
 278                } else {
 279                        return -EINVAL;
 280                }
 281        }
 282
 283        td->sequence = false;
 284        if (get_uint_param(vp->parsed, "sequence", &temp_int)) {
 285                if (temp_int > 0) {
 286                        vp->header_size += 4;
 287                        td->has_sequence = true;
 288                        td->expected_header.header |= GRE_MODE_SEQUENCE;
 289                        if (get_uint_param(
 290                                vp->parsed, "pin_sequence", &temp_int)) {
 291                                if (temp_int > 0)
 292                                        td->pin_sequence = true;
 293                        }
 294                }
 295        }
 296        vp->rx_header_size = vp->header_size;
 297        if (!td->ipv6)
 298                vp->rx_header_size += sizeof(struct iphdr);
 299        return 0;
 300}
 301
 302static int build_l2tpv3_transport_data(struct vector_private *vp)
 303{
 304
 305        struct uml_l2tpv3_data *td;
 306        int temp_int, temp_rxs, temp_txs;
 307        unsigned long temp_rx;
 308        unsigned long temp_tx;
 309
 310        vp->transport_data = kmalloc(
 311                sizeof(struct uml_l2tpv3_data), GFP_KERNEL);
 312
 313        if (vp->transport_data == NULL)
 314                return -ENOMEM;
 315
 316        td = vp->transport_data;
 317
 318        vp->form_header = &l2tpv3_form_header;
 319        vp->verify_header = &l2tpv3_verify_header;
 320        td->counter = 0;
 321
 322        vp->header_size = 4;
 323        td->session_offset = 0;
 324        td->cookie_offset = 4;
 325        td->counter_offset = 4;
 326
 327
 328        td->ipv6 = false;
 329        if (get_uint_param(vp->parsed, "v6", &temp_int)) {
 330                if (temp_int > 0)
 331                        td->ipv6 = true;
 332        }
 333
 334        if (get_uint_param(vp->parsed, "rx_session", &temp_rxs)) {
 335                if (get_uint_param(vp->parsed, "tx_session", &temp_txs)) {
 336                        td->tx_session = cpu_to_be32(temp_txs);
 337                        td->rx_session = cpu_to_be32(temp_rxs);
 338                } else {
 339                        return -EINVAL;
 340                }
 341        } else {
 342                return -EINVAL;
 343        }
 344
 345        td->cookie_is_64  = false;
 346        if (get_uint_param(vp->parsed, "cookie64", &temp_int)) {
 347                if (temp_int > 0)
 348                        td->cookie_is_64  = true;
 349        }
 350        td->cookie = false;
 351        if (get_ulong_param(vp->parsed, "rx_cookie", &temp_rx)) {
 352                if (get_ulong_param(vp->parsed, "tx_cookie", &temp_tx)) {
 353                        td->cookie = true;
 354                        if (td->cookie_is_64) {
 355                                td->rx_cookie = cpu_to_be64(temp_rx);
 356                                td->tx_cookie = cpu_to_be64(temp_tx);
 357                                vp->header_size += 8;
 358                                td->counter_offset += 8;
 359                        } else {
 360                                td->rx_cookie = cpu_to_be32(temp_rx);
 361                                td->tx_cookie = cpu_to_be32(temp_tx);
 362                                vp->header_size += 4;
 363                                td->counter_offset += 4;
 364                        }
 365                } else {
 366                        return -EINVAL;
 367                }
 368        }
 369
 370        td->has_counter = false;
 371        if (get_uint_param(vp->parsed, "counter", &temp_int)) {
 372                if (temp_int > 0) {
 373                        td->has_counter = true;
 374                        vp->header_size += 4;
 375                        if (get_uint_param(
 376                                vp->parsed, "pin_counter", &temp_int)) {
 377                                if (temp_int > 0)
 378                                        td->pin_counter = true;
 379                        }
 380                }
 381        }
 382
 383        if (get_uint_param(vp->parsed, "udp", &temp_int)) {
 384                if (temp_int > 0) {
 385                        td->udp = true;
 386                        vp->header_size += 4;
 387                        td->counter_offset += 4;
 388                        td->session_offset += 4;
 389                        td->cookie_offset += 4;
 390                }
 391        }
 392
 393        vp->rx_header_size = vp->header_size;
 394        if ((!td->ipv6) && (!td->udp))
 395                vp->rx_header_size += sizeof(struct iphdr);
 396
 397        return 0;
 398}
 399
 400static int build_raw_transport_data(struct vector_private *vp)
 401{
 402        if (uml_raw_enable_vnet_headers(vp->fds->rx_fd)) {
 403                if (!uml_raw_enable_vnet_headers(vp->fds->tx_fd))
 404                        return -1;
 405                vp->form_header = &raw_form_header;
 406                vp->verify_header = &raw_verify_header;
 407                vp->header_size = sizeof(struct virtio_net_hdr);
 408                vp->rx_header_size = sizeof(struct virtio_net_hdr);
 409                vp->dev->hw_features |= (NETIF_F_TSO | NETIF_F_GRO);
 410                vp->dev->features |=
 411                        (NETIF_F_RXCSUM | NETIF_F_HW_CSUM |
 412                                NETIF_F_TSO | NETIF_F_GRO);
 413                netdev_info(
 414                        vp->dev,
 415                        "raw: using vnet headers for tso and tx/rx checksum"
 416                );
 417        }
 418        return 0;
 419}
 420
 421static int build_tap_transport_data(struct vector_private *vp)
 422{
 423        if (uml_raw_enable_vnet_headers(vp->fds->rx_fd)) {
 424                vp->form_header = &raw_form_header;
 425                vp->verify_header = &raw_verify_header;
 426                vp->header_size = sizeof(struct virtio_net_hdr);
 427                vp->rx_header_size = sizeof(struct virtio_net_hdr);
 428                vp->dev->hw_features |=
 429                        (NETIF_F_TSO | NETIF_F_GSO | NETIF_F_GRO);
 430                vp->dev->features |=
 431                        (NETIF_F_RXCSUM | NETIF_F_HW_CSUM |
 432                                NETIF_F_TSO | NETIF_F_GSO | NETIF_F_GRO);
 433                netdev_info(
 434                        vp->dev,
 435                        "tap/raw: using vnet headers for tso and tx/rx checksum"
 436                );
 437        } else {
 438                return 0; /* do not try to enable tap too if raw failed */
 439        }
 440        if (uml_tap_enable_vnet_headers(vp->fds->tx_fd))
 441                return 0;
 442        return -1;
 443}
 444
 445int build_transport_data(struct vector_private *vp)
 446{
 447        char *transport = uml_vector_fetch_arg(vp->parsed, "transport");
 448
 449        if (strncmp(transport, TRANS_GRE, TRANS_GRE_LEN) == 0)
 450                return build_gre_transport_data(vp);
 451        if (strncmp(transport, TRANS_L2TPV3, TRANS_L2TPV3_LEN) == 0)
 452                return build_l2tpv3_transport_data(vp);
 453        if (strncmp(transport, TRANS_RAW, TRANS_RAW_LEN) == 0)
 454                return build_raw_transport_data(vp);
 455        if (strncmp(transport, TRANS_TAP, TRANS_TAP_LEN) == 0)
 456                return build_tap_transport_data(vp);
 457        return 0;
 458}
 459
 460