You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge git://git.kernel.org/pub/scm/linux/kernel/git/rw/uml
Pull UML updates from Richard Weinberger: - a new and faster epoll based IRQ controller and NIC driver - misc fixes and janitorial updates * git://git.kernel.org/pub/scm/linux/kernel/git/rw/uml: Fix vector raw inintialization logic Migrate vector timers to new timer API um: Compile with modern headers um: vector: Fix an error handling path in 'vector_parse()' um: vector: Fix a memory allocation check um: vector: fix missing unlock on error in vector_net_open() um: Add missing EXPORT for free_irq_by_fd() High Performance UML Vector Network Driver Epoll based IRQ controller um: Use POSIX ucontext_t instead of struct ucontext um: time: Use timespec64 for persistent clock um: Restore symbol versions for __memcpy and memcpy
This commit is contained in:
@@ -109,6 +109,17 @@ config UML_NET_DAEMON
|
||||
more than one without conflict. If you don't need UML networking,
|
||||
say N.
|
||||
|
||||
config UML_NET_VECTOR
|
||||
bool "Vector I/O high performance network devices"
|
||||
depends on UML_NET
|
||||
help
|
||||
This User-Mode Linux network driver uses multi-message send
|
||||
and receive functions. The host running the UML guest must have
|
||||
a linux kernel version above 3.0 and a libc version > 2.13.
|
||||
This driver provides tap, raw, gre and l2tpv3 network transports
|
||||
with up to 4 times higher network throughput than the UML network
|
||||
drivers.
|
||||
|
||||
config UML_NET_VDE
|
||||
bool "VDE transport"
|
||||
depends on UML_NET
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
slip-objs := slip_kern.o slip_user.o
|
||||
slirp-objs := slirp_kern.o slirp_user.o
|
||||
daemon-objs := daemon_kern.o daemon_user.o
|
||||
vector-objs := vector_kern.o vector_user.o vector_transports.o
|
||||
umcast-objs := umcast_kern.o umcast_user.o
|
||||
net-objs := net_kern.o net_user.o
|
||||
mconsole-objs := mconsole_kern.o mconsole_user.o
|
||||
@@ -43,6 +44,7 @@ obj-$(CONFIG_STDERR_CONSOLE) += stderr_console.o
|
||||
obj-$(CONFIG_UML_NET_SLIP) += slip.o slip_common.o
|
||||
obj-$(CONFIG_UML_NET_SLIRP) += slirp.o slip_common.o
|
||||
obj-$(CONFIG_UML_NET_DAEMON) += daemon.o
|
||||
obj-$(CONFIG_UML_NET_VECTOR) += vector.o
|
||||
obj-$(CONFIG_UML_NET_VDE) += vde.o
|
||||
obj-$(CONFIG_UML_NET_MCAST) += umcast.o
|
||||
obj-$(CONFIG_UML_NET_PCAP) += pcap.o
|
||||
@@ -61,7 +63,7 @@ obj-$(CONFIG_BLK_DEV_COW_COMMON) += cow_user.o
|
||||
obj-$(CONFIG_UML_RANDOM) += random.o
|
||||
|
||||
# pcap_user.o must be added explicitly.
|
||||
USER_OBJS := fd.o null.o pty.o tty.o xterm.o slip_common.o pcap_user.o vde_user.o
|
||||
USER_OBJS := fd.o null.o pty.o tty.o xterm.o slip_common.o pcap_user.o vde_user.o vector_user.o
|
||||
CFLAGS_null.o = -DDEV_NULL=$(DEV_NULL_PATH)
|
||||
|
||||
include arch/um/scripts/Makefile.rules
|
||||
|
||||
@@ -171,56 +171,19 @@ int enable_chan(struct line *line)
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Items are added in IRQ context, when free_irq can't be called, and
|
||||
* removed in process context, when it can.
|
||||
* This handles interrupt sources which disappear, and which need to
|
||||
* be permanently disabled. This is discovered in IRQ context, but
|
||||
* the freeing of the IRQ must be done later.
|
||||
*/
|
||||
static DEFINE_SPINLOCK(irqs_to_free_lock);
|
||||
static LIST_HEAD(irqs_to_free);
|
||||
|
||||
void free_irqs(void)
|
||||
{
|
||||
struct chan *chan;
|
||||
LIST_HEAD(list);
|
||||
struct list_head *ele;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&irqs_to_free_lock, flags);
|
||||
list_splice_init(&irqs_to_free, &list);
|
||||
spin_unlock_irqrestore(&irqs_to_free_lock, flags);
|
||||
|
||||
list_for_each(ele, &list) {
|
||||
chan = list_entry(ele, struct chan, free_list);
|
||||
|
||||
if (chan->input && chan->enabled)
|
||||
um_free_irq(chan->line->driver->read_irq, chan);
|
||||
if (chan->output && chan->enabled)
|
||||
um_free_irq(chan->line->driver->write_irq, chan);
|
||||
chan->enabled = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void close_one_chan(struct chan *chan, int delay_free_irq)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
if (!chan->opened)
|
||||
return;
|
||||
|
||||
if (delay_free_irq) {
|
||||
spin_lock_irqsave(&irqs_to_free_lock, flags);
|
||||
list_add(&chan->free_list, &irqs_to_free);
|
||||
spin_unlock_irqrestore(&irqs_to_free_lock, flags);
|
||||
}
|
||||
else {
|
||||
if (chan->input && chan->enabled)
|
||||
um_free_irq(chan->line->driver->read_irq, chan);
|
||||
if (chan->output && chan->enabled)
|
||||
um_free_irq(chan->line->driver->write_irq, chan);
|
||||
chan->enabled = 0;
|
||||
}
|
||||
/* we can safely call free now - it will be marked
|
||||
* as free and freed once the IRQ stopped processing
|
||||
*/
|
||||
if (chan->input && chan->enabled)
|
||||
um_free_irq(chan->line->driver->read_irq, chan);
|
||||
if (chan->output && chan->enabled)
|
||||
um_free_irq(chan->line->driver->write_irq, chan);
|
||||
chan->enabled = 0;
|
||||
if (chan->ops->close != NULL)
|
||||
(*chan->ops->close)(chan->fd, chan->data);
|
||||
|
||||
|
||||
@@ -284,7 +284,7 @@ int line_setup_irq(int fd, int input, int output, struct line *line, void *data)
|
||||
if (err)
|
||||
return err;
|
||||
if (output)
|
||||
err = um_request_irq(driver->write_irq, fd, IRQ_WRITE,
|
||||
err = um_request_irq(driver->write_irq, fd, IRQ_NONE,
|
||||
line_write_interrupt, IRQF_SHARED,
|
||||
driver->write_irq_name, data);
|
||||
return err;
|
||||
|
||||
@@ -288,7 +288,7 @@ static void uml_net_user_timer_expire(struct timer_list *t)
|
||||
#endif
|
||||
}
|
||||
|
||||
static void setup_etheraddr(struct net_device *dev, char *str)
|
||||
void uml_net_setup_etheraddr(struct net_device *dev, char *str)
|
||||
{
|
||||
unsigned char *addr = dev->dev_addr;
|
||||
char *end;
|
||||
@@ -412,7 +412,7 @@ static void eth_configure(int n, void *init, char *mac,
|
||||
*/
|
||||
snprintf(dev->name, sizeof(dev->name), "eth%d", n);
|
||||
|
||||
setup_etheraddr(dev, mac);
|
||||
uml_net_setup_etheraddr(dev, mac);
|
||||
|
||||
printk(KERN_INFO "Netdevice %d (%pM) : ", n, dev->dev_addr);
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <linux/miscdevice.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <init.h>
|
||||
#include <irq_kern.h>
|
||||
#include <os.h>
|
||||
|
||||
@@ -154,7 +155,14 @@ err_out_cleanup_hw:
|
||||
/*
|
||||
* rng_cleanup - shutdown RNG module
|
||||
*/
|
||||
static void __exit rng_cleanup (void)
|
||||
|
||||
static void cleanup(void)
|
||||
{
|
||||
free_irq_by_fd(random_fd);
|
||||
os_close_file(random_fd);
|
||||
}
|
||||
|
||||
static void __exit rng_cleanup(void)
|
||||
{
|
||||
os_close_file(random_fd);
|
||||
misc_deregister (&rng_miscdev);
|
||||
@@ -162,6 +170,7 @@ static void __exit rng_cleanup (void)
|
||||
|
||||
module_init (rng_init);
|
||||
module_exit (rng_cleanup);
|
||||
__uml_exitcall(cleanup);
|
||||
|
||||
MODULE_DESCRIPTION("UML Host Random Number Generator (RNG) driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
@@ -1587,11 +1587,11 @@ int io_thread(void *arg)
|
||||
|
||||
do {
|
||||
res = os_write_file(kernel_fd, ((char *) io_req_buffer) + written, n);
|
||||
if (res > 0) {
|
||||
if (res >= 0) {
|
||||
written += res;
|
||||
} else {
|
||||
if (res != -EAGAIN) {
|
||||
printk("io_thread - read failed, fd = %d, "
|
||||
printk("io_thread - write failed, fd = %d, "
|
||||
"err = %d\n", kernel_fd, -n);
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* Copyright (C) 2002 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
|
||||
* Licensed under the GPL
|
||||
*/
|
||||
|
||||
#ifndef __UM_VECTOR_KERN_H
|
||||
#define __UM_VECTOR_KERN_H
|
||||
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/socket.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include "vector_user.h"
|
||||
|
||||
/* Queue structure specially adapted for multiple enqueue/dequeue
|
||||
* in a mmsgrecv/mmsgsend context
|
||||
*/
|
||||
|
||||
/* Dequeue method */
|
||||
|
||||
#define QUEUE_SENDMSG 0
|
||||
#define QUEUE_SENDMMSG 1
|
||||
|
||||
#define VECTOR_RX 1
|
||||
#define VECTOR_TX (1 << 1)
|
||||
#define VECTOR_BPF (1 << 2)
|
||||
#define VECTOR_QDISC_BYPASS (1 << 3)
|
||||
|
||||
#define ETH_MAX_PACKET 1500
|
||||
#define ETH_HEADER_OTHER 32 /* just in case someone decides to go mad on QnQ */
|
||||
|
||||
struct vector_queue {
|
||||
struct mmsghdr *mmsg_vector;
|
||||
void **skbuff_vector;
|
||||
/* backlink to device which owns us */
|
||||
struct net_device *dev;
|
||||
spinlock_t head_lock;
|
||||
spinlock_t tail_lock;
|
||||
int queue_depth, head, tail, max_depth, max_iov_frags;
|
||||
short options;
|
||||
};
|
||||
|
||||
struct vector_estats {
|
||||
uint64_t rx_queue_max;
|
||||
uint64_t rx_queue_running_average;
|
||||
uint64_t tx_queue_max;
|
||||
uint64_t tx_queue_running_average;
|
||||
uint64_t rx_encaps_errors;
|
||||
uint64_t tx_timeout_count;
|
||||
uint64_t tx_restart_queue;
|
||||
uint64_t tx_kicks;
|
||||
uint64_t tx_flow_control_xon;
|
||||
uint64_t tx_flow_control_xoff;
|
||||
uint64_t rx_csum_offload_good;
|
||||
uint64_t rx_csum_offload_errors;
|
||||
uint64_t sg_ok;
|
||||
uint64_t sg_linearized;
|
||||
};
|
||||
|
||||
#define VERIFY_HEADER_NOK -1
|
||||
#define VERIFY_HEADER_OK 0
|
||||
#define VERIFY_CSUM_OK 1
|
||||
|
||||
struct vector_private {
|
||||
struct list_head list;
|
||||
spinlock_t lock;
|
||||
struct net_device *dev;
|
||||
|
||||
int unit;
|
||||
|
||||
/* Timeout timer in TX */
|
||||
|
||||
struct timer_list tl;
|
||||
|
||||
/* Scheduled "remove device" work */
|
||||
struct work_struct reset_tx;
|
||||
struct vector_fds *fds;
|
||||
|
||||
struct vector_queue *rx_queue;
|
||||
struct vector_queue *tx_queue;
|
||||
|
||||
int rx_irq;
|
||||
int tx_irq;
|
||||
|
||||
struct arglist *parsed;
|
||||
|
||||
void *transport_data; /* transport specific params if needed */
|
||||
|
||||
int max_packet;
|
||||
int req_size; /* different from max packet - used for TSO */
|
||||
int headroom;
|
||||
|
||||
int options;
|
||||
|
||||
/* remote address if any - some transports will leave this as null */
|
||||
|
||||
int header_size;
|
||||
int rx_header_size;
|
||||
int coalesce;
|
||||
|
||||
void *header_rxbuffer;
|
||||
void *header_txbuffer;
|
||||
|
||||
int (*form_header)(uint8_t *header,
|
||||
struct sk_buff *skb, struct vector_private *vp);
|
||||
int (*verify_header)(uint8_t *header,
|
||||
struct sk_buff *skb, struct vector_private *vp);
|
||||
|
||||
spinlock_t stats_lock;
|
||||
|
||||
struct tasklet_struct tx_poll;
|
||||
bool rexmit_scheduled;
|
||||
bool opened;
|
||||
bool in_write_poll;
|
||||
|
||||
/* ethtool stats */
|
||||
|
||||
struct vector_estats estats;
|
||||
void *bpf;
|
||||
|
||||
char user[0];
|
||||
};
|
||||
|
||||
extern int build_transport_data(struct vector_private *vp);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,458 @@
|
||||
/*
|
||||
* Copyright (C) 2017 - Cambridge Greys Limited
|
||||
* Copyright (C) 2011 - 2014 Cisco Systems Inc
|
||||
* Licensed under the GPL.
|
||||
*/
|
||||
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/slab.h>
|
||||
#include <asm/byteorder.h>
|
||||
#include <uapi/linux/ip.h>
|
||||
#include <uapi/linux/virtio_net.h>
|
||||
#include <linux/virtio_net.h>
|
||||
#include <linux/virtio_byteorder.h>
|
||||
#include <linux/netdev_features.h>
|
||||
#include "vector_user.h"
|
||||
#include "vector_kern.h"
|
||||
|
||||
#define GOOD_LINEAR 512
|
||||
#define GSO_ERROR "Incoming GSO frames and GRO disabled on the interface"
|
||||
|
||||
struct gre_minimal_header {
|
||||
uint16_t header;
|
||||
uint16_t arptype;
|
||||
};
|
||||
|
||||
|
||||
struct uml_gre_data {
|
||||
uint32_t rx_key;
|
||||
uint32_t tx_key;
|
||||
uint32_t sequence;
|
||||
|
||||
bool ipv6;
|
||||
bool has_sequence;
|
||||
bool pin_sequence;
|
||||
bool checksum;
|
||||
bool key;
|
||||
struct gre_minimal_header expected_header;
|
||||
|
||||
uint32_t checksum_offset;
|
||||
uint32_t key_offset;
|
||||
uint32_t sequence_offset;
|
||||
|
||||
};
|
||||
|
||||
struct uml_l2tpv3_data {
|
||||
uint64_t rx_cookie;
|
||||
uint64_t tx_cookie;
|
||||
uint64_t rx_session;
|
||||
uint64_t tx_session;
|
||||
uint32_t counter;
|
||||
|
||||
bool udp;
|
||||
bool ipv6;
|
||||
bool has_counter;
|
||||
bool pin_counter;
|
||||
bool cookie;
|
||||
bool cookie_is_64;
|
||||
|
||||
uint32_t cookie_offset;
|
||||
uint32_t session_offset;
|
||||
uint32_t counter_offset;
|
||||
};
|
||||
|
||||
static int l2tpv3_form_header(uint8_t *header,
|
||||
struct sk_buff *skb, struct vector_private *vp)
|
||||
{
|
||||
struct uml_l2tpv3_data *td = vp->transport_data;
|
||||
uint32_t *counter;
|
||||
|
||||
if (td->udp)
|
||||
*(uint32_t *) header = cpu_to_be32(L2TPV3_DATA_PACKET);
|
||||
(*(uint32_t *) (header + td->session_offset)) = td->tx_session;
|
||||
|
||||
if (td->cookie) {
|
||||
if (td->cookie_is_64)
|
||||
(*(uint64_t *)(header + td->cookie_offset)) =
|
||||
td->tx_cookie;
|
||||
else
|
||||
(*(uint32_t *)(header + td->cookie_offset)) =
|
||||
td->tx_cookie;
|
||||
}
|
||||
if (td->has_counter) {
|
||||
counter = (uint32_t *)(header + td->counter_offset);
|
||||
if (td->pin_counter) {
|
||||
*counter = 0;
|
||||
} else {
|
||||
td->counter++;
|
||||
*counter = cpu_to_be32(td->counter);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gre_form_header(uint8_t *header,
|
||||
struct sk_buff *skb, struct vector_private *vp)
|
||||
{
|
||||
struct uml_gre_data *td = vp->transport_data;
|
||||
uint32_t *sequence;
|
||||
*((uint32_t *) header) = *((uint32_t *) &td->expected_header);
|
||||
if (td->key)
|
||||
(*(uint32_t *) (header + td->key_offset)) = td->tx_key;
|
||||
if (td->has_sequence) {
|
||||
sequence = (uint32_t *)(header + td->sequence_offset);
|
||||
if (td->pin_sequence)
|
||||
*sequence = 0;
|
||||
else
|
||||
*sequence = cpu_to_be32(++td->sequence);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int raw_form_header(uint8_t *header,
|
||||
struct sk_buff *skb, struct vector_private *vp)
|
||||
{
|
||||
struct virtio_net_hdr *vheader = (struct virtio_net_hdr *) header;
|
||||
|
||||
virtio_net_hdr_from_skb(
|
||||
skb,
|
||||
vheader,
|
||||
virtio_legacy_is_little_endian(),
|
||||
false
|
||||
);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l2tpv3_verify_header(
|
||||
uint8_t *header, struct sk_buff *skb, struct vector_private *vp)
|
||||
{
|
||||
struct uml_l2tpv3_data *td = vp->transport_data;
|
||||
uint32_t *session;
|
||||
uint64_t cookie;
|
||||
|
||||
if ((!td->udp) && (!td->ipv6))
|
||||
header += sizeof(struct iphdr) /* fix for ipv4 raw */;
|
||||
|
||||
/* we do not do a strict check for "data" packets as per
|
||||
* the RFC spec because the pure IP spec does not have
|
||||
* that anyway.
|
||||
*/
|
||||
|
||||
if (td->cookie) {
|
||||
if (td->cookie_is_64)
|
||||
cookie = *(uint64_t *)(header + td->cookie_offset);
|
||||
else
|
||||
cookie = *(uint32_t *)(header + td->cookie_offset);
|
||||
if (cookie != td->rx_cookie) {
|
||||
if (net_ratelimit())
|
||||
netdev_err(vp->dev, "uml_l2tpv3: unknown cookie id");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
session = (uint32_t *) (header + td->session_offset);
|
||||
if (*session != td->rx_session) {
|
||||
if (net_ratelimit())
|
||||
netdev_err(vp->dev, "uml_l2tpv3: session mismatch");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gre_verify_header(
|
||||
uint8_t *header, struct sk_buff *skb, struct vector_private *vp)
|
||||
{
|
||||
|
||||
uint32_t key;
|
||||
struct uml_gre_data *td = vp->transport_data;
|
||||
|
||||
if (!td->ipv6)
|
||||
header += sizeof(struct iphdr) /* fix for ipv4 raw */;
|
||||
|
||||
if (*((uint32_t *) header) != *((uint32_t *) &td->expected_header)) {
|
||||
if (net_ratelimit())
|
||||
netdev_err(vp->dev, "header type disagreement, expecting %0x, got %0x",
|
||||
*((uint32_t *) &td->expected_header),
|
||||
*((uint32_t *) header)
|
||||
);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (td->key) {
|
||||
key = (*(uint32_t *)(header + td->key_offset));
|
||||
if (key != td->rx_key) {
|
||||
if (net_ratelimit())
|
||||
netdev_err(vp->dev, "unknown key id %0x, expecting %0x",
|
||||
key, td->rx_key);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int raw_verify_header(
|
||||
uint8_t *header, struct sk_buff *skb, struct vector_private *vp)
|
||||
{
|
||||
struct virtio_net_hdr *vheader = (struct virtio_net_hdr *) header;
|
||||
|
||||
if ((vheader->gso_type != VIRTIO_NET_HDR_GSO_NONE) &&
|
||||
(vp->req_size != 65536)) {
|
||||
if (net_ratelimit())
|
||||
netdev_err(
|
||||
vp->dev,
|
||||
GSO_ERROR
|
||||
);
|
||||
}
|
||||
if ((vheader->flags & VIRTIO_NET_HDR_F_DATA_VALID) > 0)
|
||||
return 1;
|
||||
|
||||
virtio_net_hdr_to_skb(skb, vheader, virtio_legacy_is_little_endian());
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool get_uint_param(
|
||||
struct arglist *def, char *param, unsigned int *result)
|
||||
{
|
||||
char *arg = uml_vector_fetch_arg(def, param);
|
||||
|
||||
if (arg != NULL) {
|
||||
if (kstrtoint(arg, 0, result) == 0)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool get_ulong_param(
|
||||
struct arglist *def, char *param, unsigned long *result)
|
||||
{
|
||||
char *arg = uml_vector_fetch_arg(def, param);
|
||||
|
||||
if (arg != NULL) {
|
||||
if (kstrtoul(arg, 0, result) == 0)
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static int build_gre_transport_data(struct vector_private *vp)
|
||||
{
|
||||
struct uml_gre_data *td;
|
||||
int temp_int;
|
||||
int temp_rx;
|
||||
int temp_tx;
|
||||
|
||||
vp->transport_data = kmalloc(sizeof(struct uml_gre_data), GFP_KERNEL);
|
||||
if (vp->transport_data == NULL)
|
||||
return -ENOMEM;
|
||||
td = vp->transport_data;
|
||||
td->sequence = 0;
|
||||
|
||||
td->expected_header.arptype = GRE_IRB;
|
||||
td->expected_header.header = 0;
|
||||
|
||||
vp->form_header = &gre_form_header;
|
||||
vp->verify_header = &gre_verify_header;
|
||||
vp->header_size = 4;
|
||||
td->key_offset = 4;
|
||||
td->sequence_offset = 4;
|
||||
td->checksum_offset = 4;
|
||||
|
||||
td->ipv6 = false;
|
||||
if (get_uint_param(vp->parsed, "v6", &temp_int)) {
|
||||
if (temp_int > 0)
|
||||
td->ipv6 = true;
|
||||
}
|
||||
td->key = false;
|
||||
if (get_uint_param(vp->parsed, "rx_key", &temp_rx)) {
|
||||
if (get_uint_param(vp->parsed, "tx_key", &temp_tx)) {
|
||||
td->key = true;
|
||||
td->expected_header.header |= GRE_MODE_KEY;
|
||||
td->rx_key = cpu_to_be32(temp_rx);
|
||||
td->tx_key = cpu_to_be32(temp_tx);
|
||||
vp->header_size += 4;
|
||||
td->sequence_offset += 4;
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
td->sequence = false;
|
||||
if (get_uint_param(vp->parsed, "sequence", &temp_int)) {
|
||||
if (temp_int > 0) {
|
||||
vp->header_size += 4;
|
||||
td->has_sequence = true;
|
||||
td->expected_header.header |= GRE_MODE_SEQUENCE;
|
||||
if (get_uint_param(
|
||||
vp->parsed, "pin_sequence", &temp_int)) {
|
||||
if (temp_int > 0)
|
||||
td->pin_sequence = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
vp->rx_header_size = vp->header_size;
|
||||
if (!td->ipv6)
|
||||
vp->rx_header_size += sizeof(struct iphdr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int build_l2tpv3_transport_data(struct vector_private *vp)
|
||||
{
|
||||
|
||||
struct uml_l2tpv3_data *td;
|
||||
int temp_int, temp_rxs, temp_txs;
|
||||
unsigned long temp_rx;
|
||||
unsigned long temp_tx;
|
||||
|
||||
vp->transport_data = kmalloc(
|
||||
sizeof(struct uml_l2tpv3_data), GFP_KERNEL);
|
||||
|
||||
if (vp->transport_data == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
td = vp->transport_data;
|
||||
|
||||
vp->form_header = &l2tpv3_form_header;
|
||||
vp->verify_header = &l2tpv3_verify_header;
|
||||
td->counter = 0;
|
||||
|
||||
vp->header_size = 4;
|
||||
td->session_offset = 0;
|
||||
td->cookie_offset = 4;
|
||||
td->counter_offset = 4;
|
||||
|
||||
|
||||
td->ipv6 = false;
|
||||
if (get_uint_param(vp->parsed, "v6", &temp_int)) {
|
||||
if (temp_int > 0)
|
||||
td->ipv6 = true;
|
||||
}
|
||||
|
||||
if (get_uint_param(vp->parsed, "rx_session", &temp_rxs)) {
|
||||
if (get_uint_param(vp->parsed, "tx_session", &temp_txs)) {
|
||||
td->tx_session = cpu_to_be32(temp_txs);
|
||||
td->rx_session = cpu_to_be32(temp_rxs);
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
td->cookie_is_64 = false;
|
||||
if (get_uint_param(vp->parsed, "cookie64", &temp_int)) {
|
||||
if (temp_int > 0)
|
||||
td->cookie_is_64 = true;
|
||||
}
|
||||
td->cookie = false;
|
||||
if (get_ulong_param(vp->parsed, "rx_cookie", &temp_rx)) {
|
||||
if (get_ulong_param(vp->parsed, "tx_cookie", &temp_tx)) {
|
||||
td->cookie = true;
|
||||
if (td->cookie_is_64) {
|
||||
td->rx_cookie = cpu_to_be64(temp_rx);
|
||||
td->tx_cookie = cpu_to_be64(temp_tx);
|
||||
vp->header_size += 8;
|
||||
td->counter_offset += 8;
|
||||
} else {
|
||||
td->rx_cookie = cpu_to_be32(temp_rx);
|
||||
td->tx_cookie = cpu_to_be32(temp_tx);
|
||||
vp->header_size += 4;
|
||||
td->counter_offset += 4;
|
||||
}
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
td->has_counter = false;
|
||||
if (get_uint_param(vp->parsed, "counter", &temp_int)) {
|
||||
if (temp_int > 0) {
|
||||
td->has_counter = true;
|
||||
vp->header_size += 4;
|
||||
if (get_uint_param(
|
||||
vp->parsed, "pin_counter", &temp_int)) {
|
||||
if (temp_int > 0)
|
||||
td->pin_counter = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (get_uint_param(vp->parsed, "udp", &temp_int)) {
|
||||
if (temp_int > 0) {
|
||||
td->udp = true;
|
||||
vp->header_size += 4;
|
||||
td->counter_offset += 4;
|
||||
td->session_offset += 4;
|
||||
td->cookie_offset += 4;
|
||||
}
|
||||
}
|
||||
|
||||
vp->rx_header_size = vp->header_size;
|
||||
if ((!td->ipv6) && (!td->udp))
|
||||
vp->rx_header_size += sizeof(struct iphdr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int build_raw_transport_data(struct vector_private *vp)
|
||||
{
|
||||
if (uml_raw_enable_vnet_headers(vp->fds->rx_fd)) {
|
||||
if (!uml_raw_enable_vnet_headers(vp->fds->tx_fd))
|
||||
return -1;
|
||||
vp->form_header = &raw_form_header;
|
||||
vp->verify_header = &raw_verify_header;
|
||||
vp->header_size = sizeof(struct virtio_net_hdr);
|
||||
vp->rx_header_size = sizeof(struct virtio_net_hdr);
|
||||
vp->dev->hw_features |= (NETIF_F_TSO | NETIF_F_GRO);
|
||||
vp->dev->features |=
|
||||
(NETIF_F_RXCSUM | NETIF_F_HW_CSUM |
|
||||
NETIF_F_TSO | NETIF_F_GRO);
|
||||
netdev_info(
|
||||
vp->dev,
|
||||
"raw: using vnet headers for tso and tx/rx checksum"
|
||||
);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int build_tap_transport_data(struct vector_private *vp)
|
||||
{
|
||||
if (uml_raw_enable_vnet_headers(vp->fds->rx_fd)) {
|
||||
vp->form_header = &raw_form_header;
|
||||
vp->verify_header = &raw_verify_header;
|
||||
vp->header_size = sizeof(struct virtio_net_hdr);
|
||||
vp->rx_header_size = sizeof(struct virtio_net_hdr);
|
||||
vp->dev->hw_features |=
|
||||
(NETIF_F_TSO | NETIF_F_GSO | NETIF_F_GRO);
|
||||
vp->dev->features |=
|
||||
(NETIF_F_RXCSUM | NETIF_F_HW_CSUM |
|
||||
NETIF_F_TSO | NETIF_F_GSO | NETIF_F_GRO);
|
||||
netdev_info(
|
||||
vp->dev,
|
||||
"tap/raw: using vnet headers for tso and tx/rx checksum"
|
||||
);
|
||||
} else {
|
||||
return 0; /* do not try to enable tap too if raw failed */
|
||||
}
|
||||
if (uml_tap_enable_vnet_headers(vp->fds->tx_fd))
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int build_transport_data(struct vector_private *vp)
|
||||
{
|
||||
char *transport = uml_vector_fetch_arg(vp->parsed, "transport");
|
||||
|
||||
if (strncmp(transport, TRANS_GRE, TRANS_GRE_LEN) == 0)
|
||||
return build_gre_transport_data(vp);
|
||||
if (strncmp(transport, TRANS_L2TPV3, TRANS_L2TPV3_LEN) == 0)
|
||||
return build_l2tpv3_transport_data(vp);
|
||||
if (strncmp(transport, TRANS_RAW, TRANS_RAW_LEN) == 0)
|
||||
return build_raw_transport_data(vp);
|
||||
if (strncmp(transport, TRANS_TAP, TRANS_TAP_LEN) == 0)
|
||||
return build_tap_transport_data(vp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright (C) 2002 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
|
||||
* Licensed under the GPL
|
||||
*/
|
||||
|
||||
#ifndef __UM_VECTOR_USER_H
|
||||
#define __UM_VECTOR_USER_H
|
||||
|
||||
#define MAXVARGS 20
|
||||
|
||||
#define TOKEN_IFNAME "ifname"
|
||||
|
||||
#define TRANS_RAW "raw"
|
||||
#define TRANS_RAW_LEN strlen(TRANS_RAW)
|
||||
|
||||
#define TRANS_TAP "tap"
|
||||
#define TRANS_TAP_LEN strlen(TRANS_TAP)
|
||||
|
||||
|
||||
#define TRANS_GRE "gre"
|
||||
#define TRANS_GRE_LEN strlen(TRANS_RAW)
|
||||
|
||||
#define TRANS_L2TPV3 "l2tpv3"
|
||||
#define TRANS_L2TPV3_LEN strlen(TRANS_L2TPV3)
|
||||
|
||||
#ifndef IPPROTO_GRE
|
||||
#define IPPROTO_GRE 0x2F
|
||||
#endif
|
||||
|
||||
#define GRE_MODE_CHECKSUM cpu_to_be16(8 << 12) /* checksum */
|
||||
#define GRE_MODE_RESERVED cpu_to_be16(4 << 12) /* unused */
|
||||
#define GRE_MODE_KEY cpu_to_be16(2 << 12) /* KEY present */
|
||||
#define GRE_MODE_SEQUENCE cpu_to_be16(1 << 12) /* sequence */
|
||||
|
||||
#define GRE_IRB cpu_to_be16(0x6558)
|
||||
|
||||
#define L2TPV3_DATA_PACKET 0x30000
|
||||
|
||||
/* IANA-assigned IP protocol ID for L2TPv3 */
|
||||
|
||||
#ifndef IPPROTO_L2TP
|
||||
#define IPPROTO_L2TP 0x73
|
||||
#endif
|
||||
|
||||
struct arglist {
|
||||
int numargs;
|
||||
char *tokens[MAXVARGS];
|
||||
char *values[MAXVARGS];
|
||||
};
|
||||
|
||||
/* Separating read and write FDs allows us to have different
|
||||
* rx and tx method. Example - read tap via raw socket using
|
||||
* recvmmsg, write using legacy tap write calls
|
||||
*/
|
||||
|
||||
struct vector_fds {
|
||||
int rx_fd;
|
||||
int tx_fd;
|
||||
void *remote_addr;
|
||||
int remote_addr_size;
|
||||
};
|
||||
|
||||
#define VECTOR_READ 1
|
||||
#define VECTOR_WRITE (1 < 1)
|
||||
#define VECTOR_HEADERS (1 < 2)
|
||||
|
||||
extern struct arglist *uml_parse_vector_ifspec(char *arg);
|
||||
|
||||
extern struct vector_fds *uml_vector_user_open(
|
||||
int unit,
|
||||
struct arglist *parsed
|
||||
);
|
||||
|
||||
extern char *uml_vector_fetch_arg(
|
||||
struct arglist *ifspec,
|
||||
char *token
|
||||
);
|
||||
|
||||
extern int uml_vector_recvmsg(int fd, void *hdr, int flags);
|
||||
extern int uml_vector_sendmsg(int fd, void *hdr, int flags);
|
||||
extern int uml_vector_writev(int fd, void *hdr, int iovcount);
|
||||
extern int uml_vector_sendmmsg(
|
||||
int fd, void *msgvec,
|
||||
unsigned int vlen,
|
||||
unsigned int flags
|
||||
);
|
||||
extern int uml_vector_recvmmsg(
|
||||
int fd,
|
||||
void *msgvec,
|
||||
unsigned int vlen,
|
||||
unsigned int flags
|
||||
);
|
||||
extern void *uml_vector_default_bpf(int fd, void *mac);
|
||||
extern int uml_vector_attach_bpf(int fd, void *bpf, int bpf_len);
|
||||
extern bool uml_raw_enable_qdisc_bypass(int fd);
|
||||
extern bool uml_raw_enable_vnet_headers(int fd);
|
||||
extern bool uml_tap_enable_vnet_headers(int fd);
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1 @@
|
||||
#include <asm-generic/asm-prototypes.h>
|
||||
@@ -18,7 +18,19 @@
|
||||
#define XTERM_IRQ 13
|
||||
#define RANDOM_IRQ 14
|
||||
|
||||
#ifdef CONFIG_UML_NET_VECTOR
|
||||
|
||||
#define VECTOR_BASE_IRQ 15
|
||||
#define VECTOR_IRQ_SPACE 8
|
||||
|
||||
#define LAST_IRQ (VECTOR_IRQ_SPACE + VECTOR_BASE_IRQ)
|
||||
|
||||
#else
|
||||
|
||||
#define LAST_IRQ RANDOM_IRQ
|
||||
|
||||
#endif
|
||||
|
||||
#define NR_IRQS (LAST_IRQ + 1)
|
||||
|
||||
#endif
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#define __IRQ_USER_H__
|
||||
|
||||
#include <sysdep/ptrace.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
struct irq_fd {
|
||||
struct irq_fd *next;
|
||||
@@ -15,10 +16,17 @@ struct irq_fd {
|
||||
int type;
|
||||
int irq;
|
||||
int events;
|
||||
int current_events;
|
||||
bool active;
|
||||
bool pending;
|
||||
bool purge;
|
||||
};
|
||||
|
||||
enum { IRQ_READ, IRQ_WRITE };
|
||||
#define IRQ_READ 0
|
||||
#define IRQ_WRITE 1
|
||||
#define IRQ_NONE 2
|
||||
#define MAX_IRQ_TYPE (IRQ_NONE + 1)
|
||||
|
||||
|
||||
|
||||
struct siginfo;
|
||||
extern void sigio_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs);
|
||||
|
||||
@@ -65,5 +65,7 @@ extern int tap_setup_common(char *str, char *type, char **dev_name,
|
||||
char **mac_out, char **gate_addr);
|
||||
extern void register_transport(struct transport *new);
|
||||
extern unsigned short eth_protocol(struct sk_buff *skb);
|
||||
extern void uml_net_setup_etheraddr(struct net_device *dev, char *str);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -290,15 +290,16 @@ extern void halt_skas(void);
|
||||
extern void reboot_skas(void);
|
||||
|
||||
/* irq.c */
|
||||
extern int os_waiting_for_events(struct irq_fd *active_fds);
|
||||
extern int os_create_pollfd(int fd, int events, void *tmp_pfd, int size_tmpfds);
|
||||
extern void os_free_irq_by_cb(int (*test)(struct irq_fd *, void *), void *arg,
|
||||
struct irq_fd *active_fds, struct irq_fd ***last_irq_ptr2);
|
||||
extern void os_free_irq_later(struct irq_fd *active_fds,
|
||||
int irq, void *dev_id);
|
||||
extern int os_get_pollfd(int i);
|
||||
extern void os_set_pollfd(int i, int fd);
|
||||
extern int os_waiting_for_events_epoll(void);
|
||||
extern void *os_epoll_get_data_pointer(int index);
|
||||
extern int os_epoll_triggered(int index, int events);
|
||||
extern int os_event_mask(int irq_type);
|
||||
extern int os_setup_epoll(void);
|
||||
extern int os_add_epoll_fd(int events, int fd, void *data);
|
||||
extern int os_mod_epoll_fd(int events, int fd, void *data);
|
||||
extern int os_del_epoll_fd(int fd);
|
||||
extern void os_set_ioignore(void);
|
||||
extern void os_close_epoll_fd(void);
|
||||
|
||||
/* sigio.c */
|
||||
extern int add_sigio_fd(int fd);
|
||||
|
||||
+320
-185
File diff suppressed because it is too large
Load Diff
@@ -121,12 +121,12 @@ static void __init um_timer_setup(void)
|
||||
clockevents_register_device(&timer_clockevent);
|
||||
}
|
||||
|
||||
void read_persistent_clock(struct timespec *ts)
|
||||
void read_persistent_clock64(struct timespec64 *ts)
|
||||
{
|
||||
long long nsecs = os_persistent_clock_emulation();
|
||||
|
||||
set_normalized_timespec(ts, nsecs / NSEC_PER_SEC,
|
||||
nsecs % NSEC_PER_SEC);
|
||||
set_normalized_timespec64(ts, nsecs / NSEC_PER_SEC,
|
||||
nsecs % NSEC_PER_SEC);
|
||||
}
|
||||
|
||||
void __init time_init(void)
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <sys/mount.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/sysmacros.h>
|
||||
#include <sys/un.h>
|
||||
#include <sys/types.h>
|
||||
#include <os.h>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user