cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

vector_transports.c (11946B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Copyright (C) 2017 - Cambridge Greys Limited
      4 * Copyright (C) 2011 - 2014 Cisco Systems Inc
      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_hybrid_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 hybrid: 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
    445static int build_tap_transport_data(struct vector_private *vp)
    446{
    447	/* "Pure" tap uses the same fd for rx and tx */
    448	if (uml_tap_enable_vnet_headers(vp->fds->tx_fd)) {
    449		vp->form_header = &raw_form_header;
    450		vp->verify_header = &raw_verify_header;
    451		vp->header_size = sizeof(struct virtio_net_hdr);
    452		vp->rx_header_size = sizeof(struct virtio_net_hdr);
    453		vp->dev->hw_features |=
    454			(NETIF_F_TSO | NETIF_F_GSO | NETIF_F_GRO);
    455		vp->dev->features |=
    456			(NETIF_F_RXCSUM | NETIF_F_HW_CSUM |
    457				NETIF_F_TSO | NETIF_F_GSO | NETIF_F_GRO);
    458		netdev_info(
    459			vp->dev,
    460			"tap: using vnet headers for tso and tx/rx checksum"
    461		);
    462		return 0;
    463	}
    464	return -1;
    465}
    466
    467
    468static int build_bess_transport_data(struct vector_private *vp)
    469{
    470	vp->form_header = NULL;
    471	vp->verify_header = NULL;
    472	vp->header_size = 0;
    473	vp->rx_header_size = 0;
    474	return 0;
    475}
    476
    477int build_transport_data(struct vector_private *vp)
    478{
    479	char *transport = uml_vector_fetch_arg(vp->parsed, "transport");
    480
    481	if (strncmp(transport, TRANS_GRE, TRANS_GRE_LEN) == 0)
    482		return build_gre_transport_data(vp);
    483	if (strncmp(transport, TRANS_L2TPV3, TRANS_L2TPV3_LEN) == 0)
    484		return build_l2tpv3_transport_data(vp);
    485	if (strncmp(transport, TRANS_RAW, TRANS_RAW_LEN) == 0)
    486		return build_raw_transport_data(vp);
    487	if (strncmp(transport, TRANS_TAP, TRANS_TAP_LEN) == 0)
    488		return build_tap_transport_data(vp);
    489	if (strncmp(transport, TRANS_HYBRID, TRANS_HYBRID_LEN) == 0)
    490		return build_hybrid_transport_data(vp);
    491	if (strncmp(transport, TRANS_BESS, TRANS_BESS_LEN) == 0)
    492		return build_bess_transport_data(vp);
    493	return 0;
    494}
    495