endif
ifdef V3_CONFIG_VNET
- v3vee-objs += palacios-vnet.o palacios-vnet-bridge.o
+ v3vee-objs += palacios-vnet.o \
+ palacios-vnet-ctrl.o \
+ palacios-vnet-brg.o
endif
ifdef V3_CONFIG_PACKET
for (i = 0; i < sizeof(v3_minor_map); i++) {
if (v3_minor_map[i] != 0xff) {
for (j = 0; j < 8; j++) {
- if (!v3_minor_map[i] & (0x1 << j)) {
+ if (!(v3_minor_map[i] & (0x1 << j))) {
avail = 1;
v3_minor_map[i] |= (0x1 << j);
break;
guest->img_size = user_image.size;
printk("Allocating kernel memory for guest image (%llu bytes)\n", user_image.size);
- guest->img = kmalloc(guest->img_size, GFP_KERNEL);
+ guest->img = vmalloc(guest->img_size);
if (IS_ERR(guest->img)) {
printk("Error: Could not allocate space for guest image\n");
#endif
#ifdef V3_CONFIG_VNET
- palacios_init_vnet();
+ palacios_vnet_init();
#endif
#ifdef V3_CONFIG_HOST_DEVICE
palacios_deinit_stream();
#endif
+#ifdef V3_CONFIG_SOCKET
+ palacios_socket_deinit();
+#endif
+
+#ifdef V3_CONFIG_PACKET
+ palacios_deinit_packet(NULL);
+#endif
+
+#ifdef V3_CONFIG_VNET
+ palacios_vnet_deinit();
+#endif
+
palacios_deinit_mm();
printk("Palacios Module Mallocs = %d, Frees = %d\n", mod_allocs, mod_frees);
#include "palacios.h"
#include "palacios-graphics-console.h"
+#include <linux/vmalloc.h>
/*
printk("palacios: allocating %u bytes for %u by %u by %u buffer\n",
mem, desired_spec->width, desired_spec->height, desired_spec->bytes_per_pixel);
- gc->data = kmalloc(mem,GFP_KERNEL);
+ gc->data = vmalloc(mem);
if (!(gc->data)) {
printk("palacios: unable to allocate memory for frame buffer\n");
*/
-#define V3_VM_HOST_DEV_CONNECT 512+1
+#define V3_VM_HOST_DEV_CONNECT (10244+1)
/* to detemine whether a host request is available, poll the fd for read */
/* make a request for reading/writing guest or injecting irq */
/* the arguemnt is a pointer to a palacios_host_dev_user_op struct */
/* return is negative on error, positive to indicate bytes read/written or irq injected*/
-#define V3_HOST_DEV_USER_REQUEST_PUSH_IOCTL 1
+#define V3_HOST_DEV_USER_REQUEST_PUSH_IOCTL (10244+2)
/* find out the size of the current host request, if one is pending */
/* you find out if one is pending by read poll/select on the fd */
/* the argument is a pointer to a uint64_t that will give the total size */
/* ioctl returns 1 if a request is ready, 0 if there is no request */
/* -EFAULT if there is a an error */
-#define V3_HOST_DEV_HOST_REQUEST_SIZE_IOCTL 2
+#define V3_HOST_DEV_HOST_REQUEST_SIZE_IOCTL (10244+3)
/* get the current host request, if one is available */
/* the argument is a pointer to a palacios_host_dev_host_request_response */
/* of the needed size */
/* ioctl returns 1 if a request is ready+copied, 0 if there is no request */
/* -EFAULT if there is a an error */
-#define V3_HOST_DEV_HOST_REQUEST_PULL_IOCTL 3
+#define V3_HOST_DEV_HOST_REQUEST_PULL_IOCTL (10244+4)
/* write back the response to the previously pulled host request */
/* the argument is a pointer to a palacios_host_dev_host_request_response */
-#define V3_HOST_DEV_USER_RESPONSE_PUSH_IOCTL 4
+#define V3_HOST_DEV_USER_RESPONSE_PUSH_IOCTL (10244+5)
#ifdef __KERNEL__
return 0;
}
+
static int host_dev_ioctl(struct inode *ip, struct file *fp, unsigned int val, unsigned long arg)
{
void __user *argp = (void __user *)arg;
struct palacios_host_device_user *dev = fp->private_data;
+
if (!dev->connected) {
return -EFAULT;
}
}
spin_unlock_irqrestore(&(dev->lock),f);
-
+
return 1; // have request for you
}
}
+
+
static struct file_operations host_dev_fops = {
.poll = host_dev_poll,
.release = host_dev_release,
spin_unlock_irqrestore(&(dev->lock),f);
return 0;
}
-
+
// resize request and response in case they will need it
palacios_resize_reqresp(&(dev->req),len,0); // make room for data
#define __PALACIOS_PACKET_H__
int palacios_init_packet(const char * eth_dev);
+int palacios_deinit_packet(void);
#endif
INIT_LIST_HEAD(&global_sockets);
return 0;
}
+
+void palacios_socket_deinit( void ) {
+ if (!list_empty(&(global_sockets))) {
+ printk("Error removing module with open sockets\n");
+ }
+}
+
#define __PALACIOS_SOCKET_H__
int palacios_socket_init(void);
+int palacios_socket_deinit(void);
#endif
printk("palacios: launching vm\n");
-#if V3_CONFIG_EXT_INSPECTOR
+#ifdef V3_CONFIG_EXT_INSPECTOR
inspect_vm(guest);
#endif
--- /dev/null
+/*
+ Palacios VNET Host Bridge
+ (c) Lei Xia, 2010
+ */
+#include <linux/spinlock.h>
+#include <linux/seq_file.h>
+#include <linux/proc_fs.h>
+#include <asm/uaccess.h>
+#include <linux/inet.h>
+#include <linux/kthread.h>
+
+#include <linux/netdevice.h>
+#include <linux/ip.h>
+#include <linux/in.h>
+#include <linux/net.h>
+#include <linux/string.h>
+#include <linux/preempt.h>
+#include <linux/sched.h>
+#include <asm/msr.h>
+
+#include <vnet/vnet.h>
+#include <vnet/vnet_hashtable.h>
+#include "palacios-vnet.h"
+
+#define VNET_SERVER_PORT 9000
+
+struct vnet_link {
+ uint32_t dst_ip;
+ uint16_t dst_port;
+
+ struct socket * sock;
+ struct sockaddr_in sock_addr;
+ vnet_brg_proto_t sock_proto;
+
+ struct nic_statistics stats;
+
+ uint32_t idx;
+
+ struct list_head node;
+};
+
+
+struct vnet_brg_state {
+ uint8_t status;
+
+ uint32_t num_links;
+ uint32_t link_idx;
+ struct list_head link_list;
+ struct hashtable *ip2link;
+
+ spinlock_t lock;
+
+ struct socket * serv_sock;
+ struct sockaddr_in serv_addr;
+ vnet_brg_proto_t serv_proto;
+
+ struct task_struct * serv_thread;
+
+ void * brg_data; /* private data from vnet_core */
+
+ struct vnet_brg_stats stats;
+};
+
+
+static struct vnet_brg_state vnet_brg_s;
+
+
+int vnet_brg_stats(struct vnet_brg_stats * stats){
+ memcpy(stats, &(vnet_brg_s.stats), sizeof(*stats));
+
+ return 0;
+}
+
+static inline struct vnet_link * _link_by_ip(uint32_t ip) {
+ return (struct vnet_link *)vnet_htable_search(vnet_brg_s.ip2link, (addr_t)&ip);
+}
+
+static inline struct vnet_link * _link_by_idx(int idx) {
+ struct vnet_link * link = NULL;
+
+ list_for_each_entry(link, &(vnet_brg_s.link_list), node) {
+
+ if (link->idx == idx) {
+ return link;
+ }
+ }
+ return NULL;
+}
+
+
+static void _delete_link(struct vnet_link * link){
+ unsigned long flags;
+
+ link->sock->ops->release(link->sock);
+
+ spin_lock_irqsave(&(vnet_brg_s.lock), flags);
+ list_del(&(link->node));
+ vnet_htable_remove(vnet_brg_s.ip2link, (addr_t)&(link->dst_ip), 0);
+ vnet_brg_s.num_links --;
+ spin_unlock_irqrestore(&(vnet_brg_s.lock), flags);
+
+ printk("VNET Bridge: Link deleted, ip 0x%x, port: %d, idx: %d\n",
+ link->dst_ip,
+ link->dst_port,
+ link->idx);
+
+ kfree(link);
+ link = NULL;
+}
+
+void vnet_brg_delete_link(uint32_t idx){
+ struct vnet_link * link = _link_by_idx(idx);
+
+ if(link){
+ _delete_link(link);
+ }
+}
+
+static void deinit_links_list(void){
+ struct vnet_link * link;
+
+ list_for_each_entry(link, &(vnet_brg_s.link_list), node) {
+ _delete_link(link);
+ }
+}
+
+static uint32_t _create_link(struct vnet_link * link) {
+ int err;
+ unsigned long flags;
+ int protocol;
+
+ switch(link->sock_proto){
+ case UDP:
+ protocol = IPPROTO_UDP;
+ break;
+ case TCP:
+ protocol = IPPROTO_TCP;
+ break;
+
+ default:
+ printk("Unsupported VNET Server Protocol\n");
+ return -1;
+ }
+
+ if ((err = sock_create(AF_INET, SOCK_DGRAM, protocol, &link->sock)) < 0) {
+ printk("Could not create socket for VNET Link, error %d\n", err);
+ return -1;
+ }
+
+ memset(&link->sock_addr, 0, sizeof(struct sockaddr));
+
+ link->sock_addr.sin_family = AF_INET;
+ link->sock_addr.sin_addr.s_addr = link->dst_ip;
+ link->sock_addr.sin_port = htons(link->dst_port);
+
+ if ((err = link->sock->ops->connect(link->sock, (struct sockaddr *)&(link->sock_addr), sizeof(struct sockaddr), 0) < 0)) {
+ printk("Could not connect to remote VNET Server, error %d\n", err);
+ return -1;
+ }
+
+ spin_lock_irqsave(&(vnet_brg_s.lock), flags);
+ list_add(&(link->node), &(vnet_brg_s.link_list));
+ vnet_brg_s.num_links ++;
+ link->idx = ++ vnet_brg_s.link_idx;
+ vnet_htable_insert(vnet_brg_s.ip2link, (addr_t)&(link->dst_ip), (addr_t)link);
+ spin_unlock_irqrestore(&(vnet_brg_s.lock), flags);
+
+ printk("VNET Bridge: Link created, ip 0x%x, port: %d, idx: %d, link: %p, protocol: %s\n",
+ link->dst_ip,
+ link->dst_port,
+ link->idx,
+ link,
+ ((link->sock_proto==UDP)?"UDP":"TCP"));
+
+ return link->idx;
+}
+
+
+uint32_t vnet_brg_add_link(uint32_t ip, uint16_t port, vnet_brg_proto_t proto){
+ struct vnet_link * new_link = NULL;
+ uint32_t idx;
+
+ new_link = kmalloc(sizeof(struct vnet_link), GFP_KERNEL);
+ if (!new_link) {
+ return -1;
+ }
+ memset(new_link, 0, sizeof(struct vnet_link));
+
+ new_link->dst_ip = ip;
+ new_link->dst_port = port;
+ new_link->sock_proto = proto;
+
+ idx = _create_link(new_link);
+ if (idx < 0) {
+ printk("Could not create link\n");
+ kfree(new_link);
+ return -1;
+ }
+
+ return idx;
+}
+
+
+int vnet_brg_link_stats(uint32_t link_idx, struct nic_statistics * stats){
+ struct vnet_link * link;
+
+ link = _link_by_idx(link_idx);
+ if(!link){
+ return -1;
+ }
+
+ memcpy(stats, &(link->stats), sizeof(*stats));
+
+ return 0;
+}
+
+
+static int
+_udp_send(struct socket * sock,
+ struct sockaddr_in * addr,
+ unsigned char * buf, int len) {
+ struct msghdr msg;
+ struct iovec iov;
+ mm_segment_t oldfs;
+ int size = 0;
+
+
+ if (sock->sk == NULL) {
+ return 0;
+ }
+
+ iov.iov_base = buf;
+ iov.iov_len = len;
+
+ msg.msg_flags = 0;
+ msg.msg_name = addr;
+ msg.msg_namelen = sizeof(struct sockaddr_in);
+ msg.msg_control = NULL;
+ msg.msg_controllen = 0;
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ msg.msg_control = NULL;
+
+ oldfs = get_fs();
+ set_fs(KERNEL_DS);
+ size = sock_sendmsg(sock, &msg, len);
+ set_fs(oldfs);
+
+ return size;
+}
+
+
+
+static int
+_udp_recv(struct socket * sock,
+ struct sockaddr_in * addr,
+ unsigned char * buf, int len) {
+ struct msghdr msg;
+ struct iovec iov;
+ mm_segment_t oldfs;
+ int size = 0;
+
+ if (sock->sk == NULL) {
+ return 0;
+ }
+
+ iov.iov_base = buf;
+ iov.iov_len = len;
+
+ msg.msg_flags = 0;
+ msg.msg_name = addr;
+ msg.msg_namelen = sizeof(struct sockaddr_in);
+ msg.msg_control = NULL;
+ msg.msg_controllen = 0;
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ msg.msg_control = NULL;
+
+ oldfs = get_fs();
+ set_fs(KERNEL_DS);
+ size = sock_recvmsg(sock, &msg, len, msg.msg_flags);
+
+ set_fs(oldfs);
+
+ return size;
+}
+
+/* send packets to VNET core */
+static int
+send_to_palacios(unsigned char * buf,
+ int len,
+ int link_id){
+ struct v3_vnet_pkt pkt;
+ pkt.size = len;
+ pkt.src_type = LINK_EDGE;
+ pkt.src_id = link_id;
+ memcpy(pkt.header, buf, ETHERNET_HEADER_LEN);
+ pkt.data = buf;
+
+ if(net_debug >= 2){
+ printk("VNET Lnx Bridge: send pkt to VNET core (size: %d, src_id: %d, src_type: %d)\n",
+ pkt.size, pkt.src_id, pkt.src_type);
+ if(net_debug >= 4){
+ print_hex_dump(NULL, "pkt_data: ", 0, 20, 20, pkt.data, pkt.size, 0);
+ }
+ }
+
+ vnet_brg_s.stats.pkt_to_vmm ++;
+
+ return v3_vnet_send_pkt(&pkt, NULL, 1);
+}
+
+
+/* send packet to extern network */
+static int
+bridge_send_pkt(struct v3_vm_info * vm,
+ struct v3_vnet_pkt * pkt,
+ void * private_data) {
+ struct vnet_link * link;
+
+ if(net_debug >= 2){
+ printk("VNET Lnx Host Bridge: packet received from VNET Core ... pkt size: %d, link: %d\n",
+ pkt->size,
+ pkt->dst_id);
+ if(net_debug >= 4){
+ print_hex_dump(NULL, "pkt_data: ", 0, 20, 20, pkt->data, pkt->size, 0);
+ }
+ }
+
+ vnet_brg_s.stats.pkt_from_vmm ++;
+
+ link = _link_by_idx(pkt->dst_id);
+ if (link != NULL) {
+ switch(link->sock_proto){
+ case UDP:
+ _udp_send(link->sock, &(link->sock_addr), pkt->data, pkt->size);
+ vnet_brg_s.stats.pkt_to_phy ++;
+ break;
+ case TCP:
+ vnet_brg_s.stats.pkt_to_phy ++;
+ break;
+
+ default:
+ printk("VNET Server: Invalid Link Protocol\n");
+ vnet_brg_s.stats.pkt_drop_vmm ++;
+ }
+ link->stats.tx_bytes += pkt->size;
+ link->stats.tx_pkts ++;
+ } else {
+ printk("VNET Bridge Linux Host: wrong dst link, idx: %d, discards the packet\n", pkt->dst_id);
+ vnet_brg_s.stats.pkt_drop_vmm ++;
+ }
+
+ return 0;
+}
+
+
+static int init_vnet_serv(void) {
+ int protocol;
+ int err;
+
+ switch(vnet_brg_s.serv_proto){
+ case UDP:
+ protocol = IPPROTO_UDP;
+ break;
+ case TCP:
+ protocol = IPPROTO_TCP;
+ break;
+
+ default:
+ printk("Unsupported VNET Server Protocol\n");
+ return -1;
+ }
+
+ if ((err = sock_create(AF_INET, SOCK_DGRAM, protocol, &vnet_brg_s.serv_sock)) < 0) {
+ printk("Could not create VNET server socket, error: %d\n", err);
+ return -1;
+ }
+
+ memset(&vnet_brg_s.serv_addr, 0, sizeof(struct sockaddr));
+
+ vnet_brg_s.serv_addr.sin_family = AF_INET;
+ vnet_brg_s.serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
+ vnet_brg_s.serv_addr.sin_port = htons(VNET_SERVER_PORT);
+
+ if ((err = vnet_brg_s.serv_sock->ops->bind(vnet_brg_s.serv_sock, (struct sockaddr *)&(vnet_brg_s.serv_addr), sizeof(struct sockaddr))) < 0) {
+ printk("Could not bind VNET server socket to port %d, error: %d\n", VNET_SERVER_PORT, err);
+ return -1;
+ }
+
+ printk("VNET server bind to port: %d\n", VNET_SERVER_PORT);
+
+ if(vnet_brg_s.serv_proto == TCP){
+ if((err = vnet_brg_s.serv_sock->ops->listen(vnet_brg_s.serv_sock, 32)) < 0){
+ printk("VNET Server error listening on port %d, error %d\n", VNET_SERVER_PORT, err);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static int _udp_server(void * arg) {
+ unsigned char * pkt;
+ struct sockaddr_in pkt_addr;
+ struct vnet_link * link = NULL;
+ int len;
+
+ printk("Palacios VNET Bridge: UDP receiving server ..... \n");
+
+ pkt = kmalloc(MAX_PACKET_LEN, GFP_KERNEL);
+ while (!kthread_should_stop()) {
+
+ len = _udp_recv(vnet_brg_s.serv_sock, &pkt_addr, pkt, MAX_PACKET_LEN);
+ if(len < 0) {
+ printk("Receive error: Could not get packet, error %d\n", len);
+ continue;
+ }
+
+ link = _link_by_ip(pkt_addr.sin_addr.s_addr);
+ if (link == NULL){
+ printk("VNET Server: No VNET Link match the src IP\n");
+ vnet_brg_s.stats.pkt_drop_phy ++;
+ continue;
+ }
+
+ vnet_brg_s.stats.pkt_from_phy ++;
+ link->stats.rx_bytes += len;
+ link->stats.rx_pkts ++;
+
+ send_to_palacios(pkt, len, link->idx);
+ }
+
+ kfree(pkt);
+
+ return 0;
+}
+
+
+static int _rx_server(void * arg) {
+
+ if(vnet_brg_s.serv_proto == UDP){
+ _udp_server(NULL);
+ }else if(vnet_brg_s.serv_proto == TCP) {
+ //accept new connection
+ //use select to receive pkt from physical network
+ //or create new kthread to handle each connection?
+ }else {
+ printk ("VNET Server: Unsupported Protocol\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static inline unsigned int hash_fn(addr_t hdr_ptr) {
+ return vnet_hash_buffer((uint8_t *)hdr_ptr, sizeof(uint32_t));
+}
+
+static inline int hash_eq(addr_t key1, addr_t key2) {
+ return (memcmp((uint8_t *)key1, (uint8_t *)key2, sizeof(uint32_t)) == 0);
+}
+
+
+int vnet_bridge_init(void) {
+ struct v3_vnet_bridge_ops bridge_ops;
+
+ if(vnet_brg_s.status != 0) {
+ return -1;
+ }
+ vnet_brg_s.status = 1;
+
+ memset(&vnet_brg_s, 0, sizeof(struct vnet_brg_state));
+
+ INIT_LIST_HEAD(&(vnet_brg_s.link_list));
+ spin_lock_init(&(vnet_brg_s.lock));
+
+ vnet_brg_s.serv_proto = UDP;
+
+ vnet_brg_s.ip2link = vnet_create_htable(10, hash_fn, hash_eq);
+ if(vnet_brg_s.ip2link == NULL){
+ printk("Failure to initiate VNET link hashtable\n");
+ return -1;
+ }
+
+ if(init_vnet_serv() < 0){
+ printk("Failure to initiate VNET server\n");
+ return -1;
+ }
+
+ vnet_brg_s.serv_thread = kthread_run(_rx_server, NULL, "vnet-server");
+
+ bridge_ops.input = bridge_send_pkt;
+ bridge_ops.poll = NULL;
+
+ if( v3_vnet_add_bridge(NULL, &bridge_ops, HOST_LNX_BRIDGE, NULL) < 0){
+ printk("VNET LNX Bridge: Fails to register bridge to VNET core");
+ }
+
+ printk("VNET Linux Bridge initiated\n");
+
+ return 0;
+}
+
+
+void vnet_bridge_deinit(void){
+
+ v3_vnet_del_bridge(HOST_LNX_BRIDGE);
+
+ kthread_stop(vnet_brg_s.serv_thread);
+ vnet_brg_s.serv_sock->ops->release(vnet_brg_s.serv_sock);
+
+ deinit_links_list();
+
+ vnet_free_htable(vnet_brg_s.ip2link, 0, 0);
+
+ vnet_brg_s.status = 0;
+}
+
+
/*
- Palacios VNET Host Bridge
+ Palacios VNET Control Module
(c) Lei Xia, 2010
*/
#include <linux/spinlock.h>
#define VNET_SERVER_PORT 9000
-struct palacios_vnet_route {
+struct vnet_route_iter {
struct v3_vnet_route route;
-
- int route_idx;
+ uint32_t idx;
struct list_head node;
};
-typedef enum {UDP, TCP, RAW, NONE} vnet_bridge_proto_t;
-struct vnet_link {
+struct vnet_link_iter {
uint32_t dst_ip;
uint16_t dst_port;
-
- struct socket * sock;
- struct sockaddr_in sock_addr;
- vnet_bridge_proto_t sock_proto;
-
- unsigned int pkt_rx, pkt_tx;
- uint64_t bytes_rx, bytes_tx;
-
- int link_idx;
+ vnet_brg_proto_t proto;
+ uint32_t idx;
struct list_head node;
};
-struct palacios_vnet_state {
- uint32_t num_routes;
- uint32_t num_links;
-
+struct vnet_ctrl_state {
uint8_t status;
+ uint32_t num_links;
+ uint32_t num_routes;
+
struct list_head route_list;
- struct list_head link_list;
-
- struct hashtable *ip2link; /* map IP to its Link */
+ struct list_head link_iter_list;
spinlock_t lock;
- struct socket * serv_sock;
- struct sockaddr_in serv_addr;
- vnet_bridge_proto_t serv_proto;
-
- /* Socket Receiving Thread */
- struct task_struct * serv_thread;
-
- unsigned int pkt_from_vmm, pkt_to_vmm, pkt_drop_vmm;
- unsigned int pkt_from_phy, pkt_to_phy, pkt_drop_phy;
+ struct proc_dir_entry * vnet_proc_root;
};
-static struct palacios_vnet_state vnet_state;
-
-
-static inline struct vnet_link * link_by_ip(uint32_t ip) {
- return (struct vnet_link *)vnet_htable_search(vnet_state.ip2link, (addr_t)&ip);
-}
-
-static inline struct vnet_link * link_by_idx(int idx) {
- struct vnet_link * link = NULL;
-
- list_for_each_entry(link, &(vnet_state.link_list), node) {
-
- if (link->link_idx == idx) {
- return link;
- }
- }
- return NULL;
-}
-
-static inline struct palacios_vnet_route * route_by_idx(int idx) {
- struct palacios_vnet_route * route = NULL;
-
- list_for_each_entry(route, &(vnet_state.route_list), node) {
-
- if (route->route_idx == idx) {
- return route;
- }
- }
-
- return NULL;
-}
+static struct vnet_ctrl_state vnet_ctrl_s;
static int parse_mac_str(char * str, uint8_t * qual, uint8_t * mac) {
}
-/* Format:
- * add src-MAC dst-MAC dst-TYPE [dst-ID] src-TYPE [src-ID]
- *
- * src-MAC = dst-MAC = not-MAC|any|none|MAC
- * dst-TYPE = edge|interface
- * src-TYPE = edge|interface|any
- * dst-ID = src-ID = IP|MAC
- * MAC=xx:xx:xx:xx:xx:xx
- * IP = xxx.xxx.xxx.xxx
- */
+static inline struct vnet_link_iter * link_by_ip(uint32_t ip) {
+ struct vnet_link_iter * link = NULL;
+
+ list_for_each_entry(link, &(vnet_ctrl_s.link_iter_list), node) {
+
+ if (link->dst_ip == ip) {
+ return link;
+ }
+ }
+
+ return NULL;
+}
+
+static inline struct vnet_link_iter * link_by_idx(int idx) {
+ struct vnet_link_iter * link = NULL;
+
+ list_for_each_entry(link, &(vnet_ctrl_s.link_iter_list), node) {
+ if (link->idx == idx) {
+ return link;
+ }
+ }
+
+ return NULL;
+}
+
+
static int parse_route_str(char * str, struct v3_vnet_route * route) {
char * token = NULL;
- struct vnet_link *link = NULL;
+ struct vnet_link_iter * link = NULL;
// src MAC
token = strsep(&str, " ");
link = link_by_ip(link_ip);
if (link != NULL){
- route->dst_id = link->link_idx;
+ route->dst_id = link->idx;
}else{
printk("can not find dst link %s\n", token);
return -1;
}
- printk("link_ip = %d, link_id = %d\n", link_ip, link->link_idx);
+ printk("link_ip = %d, link_id = %d\n", link_ip, link->idx);
} else if (route->dst_type == LINK_INTERFACE) {
uint8_t mac[ETH_ALEN];
link = link_by_ip(src_ip);
if (link != NULL){
- route->src_id = link->link_idx;
+ route->src_id = link->idx;
}else{
printk("can not find src link %s\n", token);
return -1;
}
-
-
static void * route_seq_start(struct seq_file * s, loff_t * pos) {
- struct palacios_vnet_route * route_iter = NULL;
+ struct vnet_route_iter * route_iter = NULL;
loff_t i = 0;
-
- if (*pos >= vnet_state.num_routes) {
+ if (*pos >= vnet_ctrl_s.num_routes) {
return NULL;
}
- list_for_each_entry(route_iter, &(vnet_state.route_list), node) {
-
+ list_for_each_entry(route_iter, &(vnet_ctrl_s.route_list), node) {
if (i == *pos) {
break;
}
}
-static void * link_seq_start(struct seq_file * s, loff_t * pos) {
- struct vnet_link * link_iter = NULL;
- loff_t i = 0;
-
- if (*pos >= vnet_state.num_links) {
- return NULL;
- }
-
- list_for_each_entry(link_iter, &(vnet_state.link_list), node) {
-
- if (i == *pos) {
- break;
- }
-
- i++;
- }
-
- return link_iter;
-}
-
-
-
static void * route_seq_next(struct seq_file * s, void * v, loff_t * pos) {
- struct palacios_vnet_route * route_iter = NULL;
+ struct vnet_route_iter * route_iter = NULL;
- route_iter = list_entry(((struct palacios_vnet_route *)v)->node.next, struct palacios_vnet_route, node);
+ route_iter = list_entry(((struct vnet_route_iter *)v)->node.next, struct vnet_route_iter, node);
// Check if the list has looped
- if (&(route_iter->node) == &(vnet_state.route_list)) {
+ if (&(route_iter->node) == &(vnet_ctrl_s.route_list)) {
return NULL;
}
return route_iter;
}
+static void route_seq_stop(struct seq_file * s, void * v) {
-static void * link_seq_next(struct seq_file * s, void * v, loff_t * pos) {
- struct vnet_link * link_iter = NULL;
+ return;
+}
-
- link_iter = list_entry(((struct vnet_link *)v)->node.next, struct vnet_link, node);
+static void * link_seq_start(struct seq_file * s, loff_t * pos) {
+ struct vnet_link_iter * link_iter = NULL;
+ loff_t i = 0;
- // Check if the list has looped
- if (&(link_iter->node) == &(vnet_state.link_list)) {
+ if (*pos >= vnet_ctrl_s.num_links) {
return NULL;
}
- *pos += 1;
-
- return link_iter;
-}
-
-
-static void route_seq_stop(struct seq_file * s, void * v) {
-
- return;
-}
-
+ list_for_each_entry(link_iter, &(vnet_ctrl_s.link_iter_list), node) {
+ if (i == *pos) {
+ break;
+ }
-static void link_seq_stop(struct seq_file * s, void * v) {
+ i++;
+ }
- return;
+ return link_iter;
}
static int route_seq_show(struct seq_file * s, void * v) {
- struct palacios_vnet_route * route_iter = v;
+ struct vnet_route_iter * route_iter = v;
struct v3_vnet_route * route = &(route_iter->route);
- seq_printf(s, "%d:\t", route_iter->route_idx);
+ seq_printf(s, "%d:\t", route_iter->idx);
seq_printf(s, "\nSrc:\t");
switch (route->src_mac_qual) {
seq_printf(s, "\nDst-Type:\t");
switch (route->dst_type) {
case LINK_EDGE: {
- struct vnet_link * link = (struct vnet_link *)link_by_idx(route->dst_id);
+ struct vnet_link_iter * link = (struct vnet_link_iter *)link_by_idx(route->dst_id);
seq_printf(s, "EDGE %pI4", &link->dst_ip);
break;
}
seq_printf(s, "\nSrc-Type:\t");
switch (route->src_type) {
case LINK_EDGE: {
- struct vnet_link * link = (struct vnet_link *)link_by_idx(route->src_id);
+ struct vnet_link_iter * link = (struct vnet_link_iter *)link_by_idx(route->src_id);
seq_printf(s, "EDGE %pI4", &link->dst_ip);
break;
}
break;
}
-
seq_printf(s, "\n");
return 0;
}
+static void * link_seq_next(struct seq_file * s, void * v, loff_t * pos) {
+ struct vnet_link_iter * link_iter = NULL;
+
+ link_iter = list_entry(((struct vnet_link_iter *)v)->node.next, struct vnet_link_iter, node);
+
+ // Check if the list has looped
+ if (&(link_iter->node) == &(vnet_ctrl_s.link_iter_list)) {
+ return NULL;
+ }
+
+ *pos += 1;
+
+ return link_iter;
+}
+
+static void link_seq_stop(struct seq_file * s, void * v) {
+
+ return;
+}
static int link_seq_show(struct seq_file * s, void * v) {
- struct vnet_link * link_iter = v;
+ struct vnet_link_iter * link_iter = v;
+ struct nic_statistics stats;
+
+ vnet_brg_link_stats(link_iter->idx, &stats);
- seq_printf(s, "%d:\t%pI4\t%d\n\t\tReceived Pkts: %d, Received Bytes %lld\n\t\tSent Pkts: %d, Sent Bytes: %lld\n\n",
- link_iter->link_idx,
+ seq_printf(s, "%d:\t%pI4\t%d\n\t\tReceived Pkts: %lld, Received Bytes %lld\n\t\tSent Pkts: %lld, Sent Bytes: %lld\n\n",
+ link_iter->idx,
&link_iter->dst_ip,
link_iter->dst_port,
- link_iter->pkt_rx,
- link_iter->bytes_rx,
- link_iter->pkt_tx,
- link_iter->bytes_tx);
+ stats.rx_pkts,
+ stats.rx_bytes,
+ stats.tx_pkts,
+ stats.tx_bytes);
return 0;
}
return seq_open(file, &link_seq_ops);
}
-static int inject_route(struct palacios_vnet_route * route) {
- unsigned long flags;
- v3_vnet_add_route(route->route);
- spin_lock_irqsave(&(vnet_state.lock), flags);
- list_add(&(route->node), &(vnet_state.route_list));
- route->route_idx = vnet_state.num_routes++;
- spin_unlock_irqrestore(&(vnet_state.lock), flags);
+static int inject_route(struct vnet_route_iter * route) {
+ unsigned long flags;
+
+ route->idx = v3_vnet_add_route(route->route);
+
+ spin_lock_irqsave(&(vnet_ctrl_s.lock), flags);
+ list_add(&(route->node), &(vnet_ctrl_s.route_list));
+ vnet_ctrl_s.num_routes ++;
+ spin_unlock_irqrestore(&(vnet_ctrl_s.lock), flags);
- printk("Palacios-vnet: One route added to VNET core\n");
+ printk("VNET Control: One route added to VNET core\n");
return 0;
}
+
+static void delete_route(struct vnet_route_iter * route) {
+ unsigned long flags;
+
+ v3_vnet_del_route(route->idx);
+
+ spin_lock_irqsave(&(vnet_ctrl_s.lock), flags);
+ list_del(&(route->node));
+ vnet_ctrl_s.num_routes --;
+ spin_unlock_irqrestore(&(vnet_ctrl_s.lock), flags);
+
+ printk("VNET Control: Route %d deleted from VNET\n", route->idx);
+
+ kfree(route);
+ route = NULL;
+}
+
+
+/* Format:
+ * add src-MAC dst-MAC dst-TYPE [dst-ID] src-TYPE [src-ID]
+ *
+ * src-MAC = dst-MAC = not-MAC|any|none|MAC
+ * dst-TYPE = edge|interface
+ * src-TYPE = edge|interface|any
+ * dst-ID = src-ID = IP|MAC
+ * MAC=xx:xx:xx:xx:xx:xx
+ * IP = xxx.xxx.xxx.xxx
+ *
+ *
+ * del route-idx
+ *
+ */
static ssize_t
route_write(struct file * file,
const char * buf,
}
if (strnicmp("ADD", token, strlen("ADD")) == 0) {
- struct palacios_vnet_route * new_route = NULL;
- new_route = kmalloc(sizeof(struct palacios_vnet_route), GFP_KERNEL);
+ struct vnet_route_iter * new_route = NULL;
+ new_route = kmalloc(sizeof(struct vnet_route_iter), GFP_KERNEL);
if (!new_route) {
return -ENOMEM;
}
- memset(new_route, 0, sizeof(struct palacios_vnet_route));
+ memset(new_route, 0, sizeof(struct vnet_route_iter));
if (parse_route_str(buf_iter, &(new_route->route)) == -1) {
kfree(new_route);
}
if (inject_route(new_route) != 0) {
+ kfree(new_route);
return -EFAULT;
}
} else if (strnicmp("DEL", token, strlen("DEL")) == 0) {
- printk("I should delete the route here\n");
+ char * idx_str = NULL;
+ uint32_t d_idx;
+
+ idx_str = strsep(&buf_iter, " ");
+
+ if (!idx_str) {
+ printk("Missing route idx in DEL Route command\n");
+ return -EFAULT;
+ }
+
+ d_idx = simple_strtoul(idx_str, &idx_str, 10);
+
+ v3_vnet_del_route(d_idx);
+
+ printk("VNET Control: One route deleted\n");
+
} else {
printk("Invalid Route command string\n");
}
return size;
}
-static int create_link(struct vnet_link * link) {
- int err;
+
+static void delete_link(struct vnet_link_iter * link){
unsigned long flags;
- int protocol;
- switch(link->sock_proto){
- case UDP:
- protocol = IPPROTO_UDP;
- break;
- case TCP:
- protocol = IPPROTO_TCP;
- break;
+ vnet_brg_delete_link(link->idx);
- default:
- printk("Unsupported VNET Server Protocol\n");
- return -1;
- }
-
- if ((err = sock_create(AF_INET, SOCK_DGRAM, protocol, &link->sock)) < 0) {
- printk("Could not create socket for VNET Link, error %d\n", err);
- return -1;
- }
+ spin_lock_irqsave(&(vnet_ctrl_s.lock), flags);
+ list_del(&(link->node));
+ vnet_ctrl_s.num_links --;
+ spin_unlock_irqrestore(&(vnet_ctrl_s.lock), flags);
- memset(&link->sock_addr, 0, sizeof(struct sockaddr));
+ kfree(link);
+ link = NULL;
+}
- link->sock_addr.sin_family = AF_INET;
- link->sock_addr.sin_addr.s_addr = link->dst_ip;
- link->sock_addr.sin_port = htons(link->dst_port);
- if ((err = link->sock->ops->connect(link->sock, (struct sockaddr *)&(link->sock_addr), sizeof(struct sockaddr), 0) < 0)) {
- printk("Could not connect to remote VNET Server, error %d\n", err);
- return -1;
- }
+static void deinit_links_list(void){
+ struct vnet_link_iter * link;
- // We use the file pointer because we are in the kernel
- // This is only used to assigned File Descriptors for user space, so it is available here
- // link->sock->file = link;
-
- spin_lock_irqsave(&(vnet_state.lock), flags);
- list_add(&(link->node), &(vnet_state.link_list));
- link->link_idx = vnet_state.num_links++;
- vnet_htable_insert(vnet_state.ip2link, (addr_t)&(link->dst_ip), (addr_t)link);
- spin_unlock_irqrestore(&(vnet_state.lock), flags);
+ list_for_each_entry(link, &(vnet_ctrl_s.link_iter_list), node) {
+ delete_link(link);
+ }
+}
- printk("VNET Bridge: Link created, ip 0x%x, port: %d, idx: %d, link: %p, protocol: %s\n",
- link->dst_ip,
- link->dst_port,
- link->link_idx,
- link,
- ((link->sock_proto==UDP)?"UDP":"TCP"));
+static void deinit_routes_list(void){
+ struct vnet_route_iter * route;
- return 0;
+ list_for_each_entry(route, &(vnet_ctrl_s.route_list), node) {
+ delete_route(route);
+ }
}
-
/* ADD dst-ip 9000 [udp|tcp] */
+/* DEL link-idx */
static ssize_t
link_write(struct file * file, const char * buf, size_t size, loff_t * ppos) {
char link_buf[256];
}
if (strnicmp("ADD", token, strlen("ADD")) == 0) {
- struct vnet_link * new_link = NULL;
+ struct vnet_link_iter * link = NULL;
char * ip_str = NULL;
- uint32_t ip;
+ uint32_t d_ip;
+ uint16_t d_port;
+ vnet_brg_proto_t d_proto;
+ int link_idx;
+ unsigned long flags;
ip_str = strsep(&link_iter, " ");
return -EFAULT;
}
- if (in4_pton(ip_str, strlen(ip_str), (uint8_t *)&(ip), '\0', NULL) != 1) {
+ if (in4_pton(ip_str, strlen(ip_str), (uint8_t *)&(d_ip), '\0', NULL) != 1) {
printk("Invalid Dst IP address (%s)\n", ip_str);
return -EFAULT;
}
- new_link = kmalloc(sizeof(struct vnet_link), GFP_KERNEL);
- if (!new_link) {
- return -ENOMEM;
+ d_port = simple_strtol(link_iter, &link_iter, 10);
+ d_proto = UDP;
+
+ link_idx = vnet_brg_add_link(d_ip, d_port, d_proto);
+ if(link_idx < 0){
+ printk("VNET Control: Failed to create link\n");
+ return -EFAULT;
}
-
- memset(new_link, 0, sizeof(struct vnet_link));
- new_link->dst_ip = ip;
- new_link->dst_port = simple_strtol(link_iter, &link_iter, 10);
+ link = kmalloc(sizeof(struct vnet_link_iter), GFP_KERNEL);
+ memset(link, 0, sizeof(struct vnet_link_iter));
- //TODO: Parse UDP|TCP
- new_link->sock_proto = UDP;
+ link->dst_ip = d_ip;
+ link->dst_port = d_port;
+ link->proto = d_proto;
+ link->idx = link_idx;
+
+ spin_lock_irqsave(&(vnet_ctrl_s.lock), flags);
+ list_add(&(link->node), &(vnet_ctrl_s.link_iter_list));
+ vnet_ctrl_s.num_links ++;
+ spin_unlock_irqrestore(&(vnet_ctrl_s.lock), flags);
+ } else if (strnicmp("DEL", token, strlen("DEL")) == 0) {
+ char * idx_str = NULL;
+ uint32_t d_idx;
- if (create_link(new_link) != 0) {
- printk("Could not create link\n");
- kfree(new_link);
+ idx_str = strsep(&link_iter, " ");
+
+ if (!idx_str) {
+ printk("Missing link idx in DEL Link command\n");
return -EFAULT;
}
- } else if (strnicmp("DEL", token, strlen("DEL")) == 0) {
- printk("Link deletion not supported\n");
+ d_idx = simple_strtoul(idx_str, &idx_str, 10);
+
+ vnet_brg_delete_link(d_idx);
+
+ printk("VNET Control: One link deleted\n");
} else {
printk("Invalid Link command string\n");
}
static ssize_t
debug_write(struct file * file, const char * buf, size_t size, loff_t * ppos) {
- char link_buf[32];
- char * link_iter = NULL;
- char * line_str = link_buf;
+ char in_buf[32];
+ char * in_iter = NULL;
+ char * line_str = in_buf;
int level = -1;
if (size >= 32) {
return -EFAULT;
}
- if (copy_from_user(link_buf, buf, size)) {
+ if (copy_from_user(in_buf, buf, size)) {
return -EFAULT;
}
- link_iter = strsep(&line_str, "\r\n");
- level = simple_strtol(link_iter, &link_iter, 10);
+ in_iter = strsep(&line_str, "\r\n");
+ level = simple_strtol(in_iter, &in_iter, 10);
- printk("Set VNET Debug level to %d\n", level);
+ printk("VNET Control: Set VNET Debug level to %d\n", level);
if(level >= 0){
- vnet_debug = level;
+ net_debug = level;
}
return size;
static int debug_show(struct seq_file * file, void * v){
- seq_printf(file, "Current VNET Debug Level: %d\n", vnet_debug);
+ seq_printf(file, "Current NET Debug Level: %d\n", net_debug);
return 0;
}
static int stat_show(struct seq_file * file, void * v){
struct vnet_stat stats;
+ struct vnet_brg_stats brg_stats;
v3_vnet_stat(&stats);
seq_printf(file, "\tTransmitted Packets: %d\n", stats.tx_pkts);
seq_printf(file, "\tTransmitted Bytes: %lld\n", stats.tx_bytes);
-
+ vnet_brg_stats(&brg_stats);
+
seq_printf(file, "\nVNET Bridge Server\n");
- seq_printf(file, "\tReceived From VMM: %d\n", vnet_state.pkt_from_vmm);
- seq_printf(file, "\tSent To VMM: %d\n", vnet_state.pkt_to_vmm);
- seq_printf(file, "\tDropped From VMM: %d\n", vnet_state.pkt_drop_vmm);
- seq_printf(file, "\tReceived From Extern Network: %d\n", vnet_state.pkt_from_phy);
- seq_printf(file, "\tSent To Extern Network: %d\n", vnet_state.pkt_to_phy);
- seq_printf(file, "\tDropped From Extern Network: %d\n", vnet_state.pkt_drop_phy);
+ seq_printf(file, "\tReceived From VMM: %lld\n", brg_stats.pkt_from_vmm);
+ seq_printf(file, "\tSent To VMM: %lld\n", brg_stats.pkt_to_vmm);
+ seq_printf(file, "\tDropped From VMM: %lld\n", brg_stats.pkt_drop_vmm);
+ seq_printf(file, "\tReceived From Extern Network: %lld\n", brg_stats.pkt_from_phy);
+ seq_printf(file, "\tSent To Extern Network: %lld\n", brg_stats.pkt_to_phy);
+ seq_printf(file, "\tDropped From Extern Network: %lld\n", brg_stats.pkt_drop_phy);
return 0;
}
return -1;
}
debug_entry->proc_fops = &debug_fops;
-
-
- return 0;
-}
-
-
-
-static int
-udp_send(struct socket * sock,
- struct sockaddr_in * addr,
- unsigned char * buf, int len) {
- struct msghdr msg;
- struct iovec iov;
- mm_segment_t oldfs;
- int size = 0;
-
-
- if (sock->sk == NULL) {
- return 0;
- }
-
- iov.iov_base = buf;
- iov.iov_len = len;
-
- msg.msg_flags = 0;
- msg.msg_name = addr;
- msg.msg_namelen = sizeof(struct sockaddr_in);
- msg.msg_control = NULL;
- msg.msg_controllen = 0;
- msg.msg_iov = &iov;
- msg.msg_iovlen = 1;
- msg.msg_control = NULL;
- oldfs = get_fs();
- set_fs(KERNEL_DS);
- size = sock_sendmsg(sock, &msg, len);
- set_fs(oldfs);
-
- return size;
-}
-
-
-
-static int
-udp_recv(struct socket * sock,
- struct sockaddr_in * addr,
- unsigned char * buf, int len) {
- struct msghdr msg;
- struct iovec iov;
- mm_segment_t oldfs;
- int size = 0;
-
- if (sock->sk == NULL) {
- return 0;
- }
-
- iov.iov_base = buf;
- iov.iov_len = len;
-
- msg.msg_flags = 0;
- msg.msg_name = addr;
- msg.msg_namelen = sizeof(struct sockaddr_in);
- msg.msg_control = NULL;
- msg.msg_controllen = 0;
- msg.msg_iov = &iov;
- msg.msg_iovlen = 1;
- msg.msg_control = NULL;
-
- oldfs = get_fs();
- set_fs(KERNEL_DS);
- size = sock_recvmsg(sock, &msg, len, msg.msg_flags);
-
- set_fs(oldfs);
-
- return size;
-}
-
-/* send packets to VNET core */
-static int
-send_to_palacios(unsigned char * buf,
- int len,
- int link_id){
- struct v3_vnet_pkt pkt;
- pkt.size = len;
- pkt.src_type = LINK_EDGE;
- pkt.src_id = link_id;
- memcpy(pkt.header, buf, ETHERNET_HEADER_LEN);
- pkt.data = buf;
-
- if(vnet_debug >= 2){
- printk("VNET Lnx Bridge: send pkt to VNET core (size: %d, src_id: %d, src_type: %d)\n",
- pkt.size, pkt.src_id, pkt.src_type);
- if(vnet_debug >= 4){
- print_hex_dump(NULL, "pkt_data: ", 0, 20, 20, pkt.data, pkt.size, 0);
- }
- }
-
- vnet_state.pkt_to_vmm ++;
-
- return v3_vnet_send_pkt(&pkt, NULL, 1);
-}
-
-
-/* send packet to extern network */
-static int
-bridge_send_pkt(struct v3_vm_info * vm,
- struct v3_vnet_pkt * pkt,
- void * private_data) {
- struct vnet_link * link;
-
- if(vnet_debug >= 2){
- printk("VNET Lnx Host Bridge: packet received from VNET Core ... pkt size: %d, link: %d\n",
- pkt->size,
- pkt->dst_id);
- if(vnet_debug >= 4){
- print_hex_dump(NULL, "pkt_data: ", 0, 20, 20, pkt->data, pkt->size, 0);
- }
- }
-
- vnet_state.pkt_from_vmm ++;
-
- link = link_by_idx(pkt->dst_id);
- if (link != NULL) {
- switch(link->sock_proto){
- case UDP:
- udp_send(link->sock, &(link->sock_addr), pkt->data, pkt->size);
- vnet_state.pkt_to_phy ++;
- break;
- case TCP:
- vnet_state.pkt_to_phy ++;
- break;
-
- default:
- printk("VNET Server: Invalid Link Protocol\n");
- vnet_state.pkt_drop_vmm ++;
- }
- link->bytes_tx += pkt->size;
- link->pkt_tx ++;
- } else {
- printk("VNET Bridge Linux Host: wrong dst link, idx: %d, discards the packet\n", pkt->dst_id);
- vnet_state.pkt_drop_vmm ++;
- }
+ vnet_ctrl_s.vnet_proc_root = vnet_root;
return 0;
}
-static int init_vnet_serv(void) {
- int protocol;
- int err;
-
- switch(vnet_state.serv_proto){
- case UDP:
- protocol = IPPROTO_UDP;
- break;
- case TCP:
- protocol = IPPROTO_TCP;
- break;
+static void destroy_proc_files(void) {
+ struct proc_dir_entry * vnet_root = vnet_ctrl_s.vnet_proc_root;
- default:
- printk("Unsupported VNET Server Protocol\n");
- return -1;
- }
-
- if ((err = sock_create(AF_INET, SOCK_DGRAM, protocol, &vnet_state.serv_sock)) < 0) {
- printk("Could not create VNET server socket, error: %d\n", err);
- return -1;
- }
-
- memset(&vnet_state.serv_addr, 0, sizeof(struct sockaddr));
-
- vnet_state.serv_addr.sin_family = AF_INET;
- vnet_state.serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
- vnet_state.serv_addr.sin_port = htons(VNET_SERVER_PORT);
-
- if ((err = vnet_state.serv_sock->ops->bind(vnet_state.serv_sock, (struct sockaddr *)&(vnet_state.serv_addr), sizeof(struct sockaddr))) < 0) {
- printk("Could not bind VNET server socket to port %d, error: %d\n", VNET_SERVER_PORT, err);
- return -1;
- }
-
- printk("VNET server bind to port: %d\n", VNET_SERVER_PORT);
-
- if(vnet_state.serv_proto == TCP){
- if((err = vnet_state.serv_sock->ops->listen(vnet_state.serv_sock, 32)) < 0){
- printk("VNET Server error listening on port %d, error %d\n", VNET_SERVER_PORT, err);
- return -1;
- }
- }
-
- return 0;
+ remove_proc_entry("debug", vnet_root);
+ remove_proc_entry("links", vnet_root);
+ remove_proc_entry("routes", vnet_root);
+ remove_proc_entry("stats", vnet_root);
+ remove_proc_entry("vnet", NULL);
}
-static int vnet_udp_server(void * arg) {
- unsigned char * pkt;
- struct sockaddr_in pkt_addr;
- struct vnet_link * link = NULL;
- int len;
-
- printk("Palacios VNET Bridge: UDP receiving server ..... \n");
- pkt = kmalloc(MAX_PACKET_LEN, GFP_KERNEL);
- while (!kthread_should_stop()) {
-
- len = udp_recv(vnet_state.serv_sock, &pkt_addr, pkt, MAX_PACKET_LEN);
- if(len < 0) {
- printk("Receive error: Could not get packet, error %d\n", len);
- continue;
- }
-
- link = link_by_ip(pkt_addr.sin_addr.s_addr);
- if (link == NULL){
- printk("VNET Server: No VNET Link match the src IP\n");
- vnet_state.pkt_drop_phy ++;
- continue;
- }
-
- vnet_state.pkt_from_phy ++;
- link->bytes_rx += len;
- link->pkt_rx ++;
-
- send_to_palacios(pkt, len, link->link_idx);
- }
-
- kfree(pkt);
-
- return 0;
-}
-
-
-
-static int vnet_server(void * arg) {
-
- if(vnet_state.serv_proto == UDP){
- vnet_udp_server(NULL);
- }else if(vnet_state.serv_proto == TCP) {
- //accept new connection
- //use select to receive pkt from physical network
- //or create new kthread to handle each connection?
- }else {
- printk ("VNET Server: Unsupported Protocol\n");
- return -1;
- }
-
- return 0;
-}
-
-static inline unsigned int hash_fn(addr_t hdr_ptr) {
- return vnet_hash_buffer((uint8_t *)hdr_ptr, sizeof(uint32_t));
-}
-
-static inline int hash_eq(addr_t key1, addr_t key2) {
- return (memcmp((uint8_t *)key1, (uint8_t *)key2, sizeof(uint32_t)) == 0);
-}
-
-
-int palacios_init_vnet(void) {
- struct v3_vnet_bridge_ops bridge_ops;
-
-
- if(vnet_state.status != 0) {
+int vnet_ctrl_init(void) {
+ if(vnet_ctrl_s.status != 0) {
return -1;
}
- vnet_state.status = 1;
+ vnet_ctrl_s.status = 1;
- memset(&vnet_state, 0, sizeof(struct palacios_vnet_state));
+ memset(&vnet_ctrl_s, 0, sizeof(struct vnet_ctrl_state));
- INIT_LIST_HEAD(&(vnet_state.link_list));
- INIT_LIST_HEAD(&(vnet_state.route_list));
- spin_lock_init(&(vnet_state.lock));
+ INIT_LIST_HEAD(&(vnet_ctrl_s.link_iter_list));
+ INIT_LIST_HEAD(&(vnet_ctrl_s.route_list));
+ spin_lock_init(&(vnet_ctrl_s.lock));
init_proc_files();
-
- vnet_state.serv_proto = UDP;
-
- vnet_state.ip2link = vnet_create_htable(10, hash_fn, hash_eq);
- if(vnet_state.ip2link == NULL){
- printk("Failure to initiate VNET link hashtable\n");
- return -1;
- }
- if(init_vnet_serv() < 0){
- printk("Failure to initiate VNET server\n");
- return -1;
- }
+ printk("VNET Linux control module initiated\n");
- vnet_state.serv_thread = kthread_run(vnet_server, NULL, "vnet-server");
+ return 0;
+}
- bridge_ops.input = bridge_send_pkt;
- bridge_ops.poll = NULL;
-
- v3_vnet_add_bridge(NULL, &bridge_ops, HOST_LNX_BRIDGE, NULL);
- printk("Palacios VNET Linux Bridge initiated\n");
+void vnet_ctrl_deinit(void){
+ destroy_proc_files();
- return 0;
+ deinit_links_list();
+ deinit_routes_list();
+
+ vnet_ctrl_s.status = 0;
}
+
#include <vnet/vnet.h>
#include "palacios-mm.h"
+#include "palacios-vnet.h"
static void host_print(const char * fmt, ...) {
-int vnet_init( void ) {
- printk("Host init VNET\n");
-
+int palacios_vnet_init( void ) {
init_vnet(&vnet_host_hooks);
+
+ vnet_bridge_init();
+ vnet_ctrl_init();
+
+ printk("V3 VNET Inited\n");
return 0;
}
+
+
+void palacios_vnet_deinit( void ) {
+ deinit_vnet();
+
+ vnet_bridge_deinit();
+ vnet_ctrl_deinit();
+
+ printk("V3 VNET Deinited\n");
+}
+
/*
- * Palacios VNET Host Bridge
+ * Palacios VNET Host Header
* (c) Lei Xia, 2010
*/
-#ifndef __PALACIOS_VNET_BRIDGE_H__
-#define __PALACIOS_VNET_BRIDGE_H__
+#ifndef __PALACIOS_VNET_H__
+#define __PALACIOS_VNET_H__
+
+#include <vnet/vnet.h>
+
+int palacios_vnet_init(void);
+void palacios_vnet_deinit(void);
+
+typedef enum {UDP, TCP, RAW, NONE} vnet_brg_proto_t;
+
+struct vnet_brg_stats{
+ uint64_t pkt_from_vmm;
+ uint64_t pkt_to_vmm;
+ uint64_t pkt_drop_vmm;
+ uint64_t pkt_from_phy;
+ uint64_t pkt_to_phy;
+ uint64_t pkt_drop_phy;
+};
+
+void vnet_brg_delete_link(uint32_t idx);
+uint32_t vnet_brg_add_link(uint32_t ip, uint16_t port, vnet_brg_proto_t proto);
+int vnet_brg_link_stats(uint32_t link_idx, struct nic_statistics * stats);
+int vnet_brg_stats(struct vnet_brg_stats * stats);
+int vnet_bridge_init(void);
+void vnet_bridge_deinit(void);
+
+
+int vnet_ctrl_init(void);
+void vnet_ctrl_deinit(void);
-int palacios_init_vnet(void);
#endif
#define V3_VM_STREAM_CONNECT 21
#define V3_VM_STOP 22
-#define V3_VM_FB_INPUT 256+1
-#define V3_VM_FB_QUERY 256+2
+#define V3_VM_FB_INPUT (256+1)
+#define V3_VM_FB_QUERY (256+2)
-#define V3_VM_HOST_DEV_CONNECT 512+1
+#define V3_VM_HOST_DEV_CONNECT (10244+1)
struct v3_guest_img {
struct palacios_console console;
#endif
-#ifdef V3_CONFIG_CONSOLE
+#ifdef V3_CONFIG_GRAPHICS_CONSOLE
struct palacios_graphics_console graphics_console;
#endif
-all: v3_ctrl v3_stop v3_cons v3_mem v3_monitor v3_serial v3_net v3_user_host_dev_example
+all: v3_ctrl v3_stop v3_cons v3_mem v3_monitor v3_serial v3_net v3_user_host_dev_example v3_os_debug
v3_user_host_dev_example: v3_user_host_dev_example.c v3_user_host_dev.h v3_user_host_dev.c
gcc -static -I../linux_module v3_user_host_dev_example.c v3_user_host_dev.c -o v3_user_host_dev_example
+v3_os_debug: v3_os_debug.c v3_user_host_dev.h v3_user_host_dev.c
+ gcc -static -I../linux_module v3_os_debug.c v3_user_host_dev.c -o v3_os_debug
+
+
clean:
- rm -f v3_ctrl v3_cons v3_mem v3_monitor v3_serial v3_net
+ rm -f v3_ctrl v3_cons v3_mem v3_monitor v3_serial v3_net v3_user_host_dev_example v3_os_debug
--- /dev/null
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <sys/select.h>
+#include <malloc.h>
+
+#include "v3_user_host_dev.h"
+
+void usage()
+{
+ fprintf(stderr,"v3_user_host_dev_example /dev/v3-vm0 user:mydev busywait|select\n");
+}
+
+
+int do_work(struct palacios_host_dev_host_request_response *req,
+ struct palacios_host_dev_host_request_response **resp)
+{
+ uint64_t datasize;
+
+ switch (req->type) {
+ case PALACIOS_HOST_DEV_HOST_REQUEST_WRITE_IO: {
+ if (req->port==0xc0c0) {
+ uint64_t i;
+ uint64_t numchars;
+ numchars = req->data_len - sizeof(struct palacios_host_dev_host_request_response);
+ for (i=0;i<numchars;i++) {
+ putchar(req->data[i]);
+ }
+ *resp = malloc(sizeof(struct palacios_host_dev_host_request_response));
+ **resp=*req;
+ (*resp)->len = (*resp)->data_len = sizeof(struct palacios_host_dev_host_request_response);
+ (*resp)->op_len = numchars;
+ } else {
+ printf("Huh? Unknown port %d\n",req->port);
+ }
+ }
+ break;
+
+ default:
+ printf("Huh? Unknown request %d\n", req->type);
+ }
+
+
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ int devfd;
+ int mode=0;
+ char *vm, *url;
+
+ if (argc!=4) {
+ usage();
+ exit(-1);
+ }
+
+ vm=argv[1];
+ url=argv[2];
+ mode = argv[3][0]=='s';
+
+ fprintf(stderr,"Attempting to rendezvous with host device %s on vm %s\n", url, vm);
+
+ if ((devfd = v3_user_host_dev_rendezvous(vm,url))<0) {
+ perror("failed to rendezvous");
+ exit(-1);
+ }
+
+ fprintf(stderr,"Rendezvous succeeded, I will now operate in %s mode\n", mode==0 ? "busywait" : "select");
+
+ if (mode==0) {
+ //busywait
+
+ struct palacios_host_dev_host_request_response *req;
+ struct palacios_host_dev_host_request_response *resp;
+ uint64_t datasize;
+
+ while (1) {
+ while (!(v3_user_host_dev_have_request(devfd))) {
+ }
+ v3_user_host_dev_pull_request(devfd, &req);
+
+ do_work(req, &resp);
+
+ v3_user_host_dev_push_response(devfd, resp);
+
+ free(resp);
+ free(req);
+ }
+ } else {
+
+ struct palacios_host_dev_host_request_response *req;
+ struct palacios_host_dev_host_request_response *resp;
+ uint64_t datasize;
+ fd_set readset;
+ int rc;
+
+ // select-based operation so that you can wait for multiple things
+
+ while (1) {
+ FD_ZERO(&readset);
+ FD_SET(devfd,&readset);
+
+ rc = select(devfd+1, &readset, 0, 0, 0); // pick whatever you want to select on, just include devfd
+
+ if (rc>0) {
+ if (FD_ISSET(devfd,&readset)) {
+ // a request is read for us!
+ v3_user_host_dev_pull_request(devfd, &req);
+
+ do_work(req, &resp);
+
+ v3_user_host_dev_push_response(devfd, resp);
+
+ free(resp);
+ free(req);
+ }
+ }
+ }
+ }
+
+ v3_user_host_dev_depart(devfd);
+
+ return 0;
+
+}
#include <sys/stat.h>
#include <fcntl.h>
#include <malloc.h>
+#include <string.h>
+#include <stdio.h>
#include "v3_user_host_dev.h"
{
int vmfd;
int devfd;
+ char buf[256];
+
+
+ strcpy(buf,url);
+ buf[255]=0;
if ((vmfd=open(vmdev,O_RDWR))<0) {
return -1;
}
- devfd = ioctl(vmfd,V3_VM_HOST_DEV_CONNECT,url);
+ devfd = ioctl(vmfd,V3_VM_HOST_DEV_CONNECT,buf);
close(vmfd);
{
uint64_t len;
- return ioctl(devfd,V3_HOST_DEV_HOST_REQUEST_SIZE_IOCTL,&len)==1;
+ int rc=ioctl(devfd,V3_HOST_DEV_HOST_REQUEST_SIZE_IOCTL,&len);
+
+ return rc==1;
}
int v3_user_host_dev_pull_request(int devfd, struct palacios_host_dev_host_request_response **req)
#ifndef __ETHERNET_H__
#define __ETHERNET_H__
+#include <palacios/vmm.h>
+
#define ETHERNET_HEADER_LEN 14
#define ETHERNET_MTU 1500
#define ETHERNET_PACKET_LEN (ETHERNET_HEADER_LEN + ETHERNET_MTU)
#define MAX_PACKET_LEN (ETHERNET_HEADER_LEN + MAX_MTU)
+#ifdef V3_CONFIG_VNET
+extern int net_debug;
+#endif
-extern int vnet_debug;
+struct nic_statistics {
+ uint64_t tx_pkts;
+ uint64_t tx_bytes;
+ uint64_t tx_dropped;
+
+ uint64_t rx_pkts;
+ uint64_t rx_bytes;
+ uint64_t rx_dropped;
+
+ uint32_t tx_interrupts;
+ uint32_t rx_interrupts;
+};
#ifdef __V3VEE__
#define V3_Net_Print(level, fmt, args...) \
do { \
- if(level <= vnet_debug) { \
+ if(level <= net_debug) { \
extern struct v3_os_hooks * os_hooks; \
if ((os_hooks) && (os_hooks)->print) { \
(os_hooks)->print((fmt), ##args); \
} \
} while (0)
-struct nic_statistics {
- uint64_t tx_pkts;
- uint64_t tx_bytes;
- uint64_t tx_dropped;
-
- uint64_t rx_pkts;
- uint64_t rx_bytes;
- uint64_t rx_dropped;
- uint32_t tx_interrupts;
- uint32_t rx_interrupts;
-};
-
static inline int is_multicast_ethaddr(const uint8_t * addr)
{
V3_ASSERT(ETH_ALEN == 6);
struct v3_vnet_bridge_ops * ops,
uint8_t type,
void * priv_data);
+
+void v3_vnet_del_bridge(uint8_t type);
+
int v3_vnet_add_route(struct v3_vnet_route route);
+void v3_vnet_del_route(uint32_t route_idx);
+
int v3_vnet_send_pkt(struct v3_vnet_pkt * pkt, void * private_data, int synchronize);
int v3_vnet_find_dev(uint8_t * mac);
int v3_vnet_stat(struct vnet_stat * stats);
#define Vnet_Print(level, fmt, args...) \
do { \
- extern int vnet_debug; \
- if(level <= vnet_debug) { \
+ extern int net_debug; \
+ if(level <= net_debug) { \
extern struct vnet_host_hooks * host_hooks; \
if ((host_hooks) && (host_hooks)->print) { \
(host_hooks)->print((fmt), ##args); \
void init_vnet(struct vnet_host_hooks * hooks);
+void deinit_vnet(void);
#endif
*/
typedef enum {NOT_RUNNING, PENDING, RUNNING} channel_run_state_t;
typedef enum {NOT_WAITING, WAITING_LOBYTE, WAITING_HIBYTE} channel_access_state_t;
-typedef enum {LATCH_COUNT, LOBYTE_ONLY, HIBYTE_ONLY, LOBYTE_HIBYTE} channel_access_mode_t;
-typedef enum {IRQ_ON_TERM_CNT, ONE_SHOT, RATE_GEN, SQR_WAVE, SW_STROBE, HW_STROBE} channel_op_mode_t;
+typedef enum {LATCH_COUNT = 0, LOBYTE_ONLY = 1, HIBYTE_ONLY = 2, LOBYTE_HIBYTE = 3} channel_access_mode_t;
+typedef enum {IRQ_ON_TERM_CNT = 0, ONE_SHOT = 1, RATE_GEN = 2, SQR_WAVE = 3, SW_STROBE = 4, HW_STROBE = 5} channel_op_mode_t;
struct channel {
} else {
ushort_t reload_val = ch->reload_value;
- if (ch->op_mode == SW_STROBE) {
+ if ((ch->op_mode == SW_STROBE) || (ch->op_mode == IRQ_ON_TERM_CNT)) {
reload_val = 0xffff;
}
config CHAR_STREAM
bool "Stream based character frontend"
+ depends on STREAM
default n
help
Include Stream based character device frontend
* 1. Queue locks. Actual irq insertions are done via queueing irq ops at the dest apic.
* The destination apic's core is responsible for draining the queue, and actually
* setting the vector table.
- * 2. State locks. This is a standard lock taken when internal apic state is read/written.
+ * 2. State lock. This is a standard lock taken when internal apic state is read/written.
* When an irq's destination is determined this lock is taken to examine the apic's
* addressability.
* 3. VM barrier lock. This is taken when actual VM core state is changed (via SIPI).
+
typedef enum {INIT_ST,
SIPI,
STARTED} ipi_state_t;
struct v3_timer * timer;
- v3_lock_t state_lock;
+
struct v3_queue irq_queue;
uint32_t eoi;
struct apic_dev_state {
int num_apics;
+ v3_lock_t state_lock;
+
struct apic_state apics[0];
} __attribute__((packed));
}
+
+
+
// irq_num is the bit offset into a 256 bit buffer...
static int activate_apic_irq(struct apic_state * apic, uint32_t irq_num) {
int major_offset = (irq_num & ~0x00000007) >> 3;
uint8_t flag = 0x1 << minor_offset;
- if (irq_num <= 15 || irq_num > 255) {
- PrintError("apic %u: core %d: Attempting to raise an invalid interrupt: %d\n",
- apic->lapic_id.val, apic->core->vcpu_id, irq_num);
- return -1;
- }
-
-
PrintDebug("apic %u: core %d: Raising APIC IRQ %d\n", apic->lapic_id.val, apic->core->vcpu_id, irq_num);
if (*req_location & flag) {
}
+static int add_apic_irq_entry(struct apic_state * apic, uint8_t irq_num) {
+
+ if (irq_num <= 15) {
+ PrintError("core %d: Attempting to raise an invalid interrupt: %d\n",
+ apic->core->vcpu_id, irq_num);
+ return -1;
+ }
+
+ v3_enqueue(&(apic->irq_queue), (addr_t)irq_num);
+
+ return 0;
+}
+
+static void drain_irq_entries(struct apic_state * apic) {
+ uint32_t irq = 0;
+
+ while ((irq = (uint32_t)v3_dequeue(&(apic->irq_queue))) != 0) {
+ activate_apic_irq(apic, irq);
+ }
+
+}
+
+
+
static int get_highest_isr(struct apic_state * apic) {
int i = 0, j = 0;
if (del_mode == APIC_FIXED_DELIVERY) {
//PrintDebug("Activating internal APIC IRQ %d\n", vec_num);
- return activate_apic_irq(apic, vec_num);
+ return add_apic_irq_entry(apic, vec_num);
} else {
PrintError("apic %u: core ?: Unhandled Delivery Mode\n", apic->lapic_id.val);
return -1;
-static inline int should_deliver_cluster_ipi(struct guest_info * dst_core,
+static inline int should_deliver_cluster_ipi(struct apic_dev_state * apic_dev,
+ struct guest_info * dst_core,
struct apic_state * dst_apic, uint8_t mda) {
+ int ret = 0;
+
+
if ( ((mda & 0xf0) == (dst_apic->log_dst.dst_log_id & 0xf0)) && /* (I am in the cluster and */
((mda & 0x0f) & (dst_apic->log_dst.dst_log_id & 0x0f)) ) { /* I am in the set) */
+ ret = 1;
+ } else {
+ ret = 0;
+ }
+
+ if (ret == 1) {
PrintDebug("apic %u core %u: accepting clustered IRQ (mda 0x%x == log_dst 0x%x)\n",
dst_apic->lapic_id.val, dst_core->vcpu_id, mda,
dst_apic->log_dst.dst_log_id);
-
- return 1;
} else {
PrintDebug("apic %u core %u: rejecting clustered IRQ (mda 0x%x != log_dst 0x%x)\n",
dst_apic->lapic_id.val, dst_core->vcpu_id, mda,
dst_apic->log_dst.dst_log_id);
- return 0;
}
+
+ return ret;
+
}
-static inline int should_deliver_flat_ipi(struct guest_info * dst_core,
+static inline int should_deliver_flat_ipi(struct apic_dev_state * apic_dev,
+ struct guest_info * dst_core,
struct apic_state * dst_apic, uint8_t mda) {
- if (dst_apic->log_dst.dst_log_id & mda) { // I am in the set
+ int ret = 0;
- PrintDebug("apic %u core %u: accepting flat IRQ (mda 0x%x == log_dst 0x%x)\n",
- dst_apic->lapic_id.val, dst_core->vcpu_id, mda,
- dst_apic->log_dst.dst_log_id);
- return 1;
+ if ((dst_apic->log_dst.dst_log_id & mda) != 0) { // I am in the set
+ ret = 1;
+ } else {
+ ret = 0;
+ }
- } else {
+ if (ret == 1) {
+ PrintDebug("apic %u core %u: accepting flat IRQ (mda 0x%x == log_dst 0x%x)\n",
+ dst_apic->lapic_id.val, dst_core->vcpu_id, mda,
+ dst_apic->log_dst.dst_log_id);
+ } else {
PrintDebug("apic %u core %u: rejecting flat IRQ (mda 0x%x != log_dst 0x%x)\n",
dst_apic->lapic_id.val, dst_core->vcpu_id, mda,
dst_apic->log_dst.dst_log_id);
- return 0;
- }
+ }
+
+
+ return ret;
}
-static int should_deliver_ipi(struct guest_info * dst_core,
+static int should_deliver_ipi(struct apic_dev_state * apic_dev,
+ struct guest_info * dst_core,
struct apic_state * dst_apic, uint8_t mda) {
+ addr_t flags = 0;
+ int ret = 0;
+ flags = v3_lock_irqsave(apic_dev->state_lock);
if (dst_apic->dst_fmt.model == 0xf) {
if (mda == 0xff) {
/* always deliver broadcast */
- return 1;
+ ret = 1;
+ } else {
+ ret = should_deliver_flat_ipi(apic_dev, dst_core, dst_apic, mda);
}
-
- return should_deliver_flat_ipi(dst_core, dst_apic, mda);
-
} else if (dst_apic->dst_fmt.model == 0x0) {
if (mda == 0xff) {
/* always deliver broadcast */
- return 1;
+ ret = 1;
+ } else {
+ ret = should_deliver_cluster_ipi(apic_dev, dst_core, dst_apic, mda);
}
- return should_deliver_cluster_ipi(dst_core, dst_apic, mda);
-
} else {
+ ret = -1;
+ }
+
+ v3_unlock_irqrestore(apic_dev->state_lock, flags);
+
+
+ if (ret == -1) {
PrintError("apic %u core %u: invalid destination format register value 0x%x for logical mode delivery.\n",
dst_apic->lapic_id.val, dst_core->vcpu_id, dst_apic->dst_fmt.model);
- return -1;
}
+
+ return ret;
}
+
+
// Only the src_apic pointer is used
static int deliver_ipi(struct apic_state * src_apic,
struct apic_state * dst_apic,
// lowest priority -
// caller needs to have decided which apic to deliver to!
- int do_xcall;
-
PrintDebug("delivering IRQ %d to core %u\n", vector, dst_core->vcpu_id);
- do_xcall = activate_apic_irq(dst_apic, vector);
+ add_apic_irq_entry(dst_apic, vector);
-
-
+#ifdef V3_CONFIG_MULTITHREAD_OS
if (dst_apic != src_apic) {
PrintDebug(" non-local core with new interrupt, forcing it to exit now\n");
-
-#ifdef V3_CONFIG_MULTITHREAD_OS
v3_interrupt_cpu(dst_core->vm_info, dst_core->pcpu_id, 0);
-#endif
}
+#endif
+
break;
}
}
-static struct apic_state * find_physical_apic(struct apic_dev_state *apic_dev, struct int_cmd_reg *icr)
-{
+static struct apic_state * find_physical_apic(struct apic_dev_state * apic_dev, uint32_t dst_idx) {
+ struct apic_state * dst_apic = NULL;
+ addr_t flags;
int i;
-
- if ( (icr->dst > 0) && (icr->dst < apic_dev->num_apics) ) {
+
+ flags = v3_lock_irqsave(apic_dev->state_lock);
+
+ if ( (dst_idx > 0) && (dst_idx < apic_dev->num_apics) ) {
// see if it simply is the core id
- if (apic_dev->apics[icr->dst].lapic_id.val == icr->dst) {
- return &(apic_dev->apics[icr->dst]);
+ if (apic_dev->apics[dst_idx].lapic_id.val == dst_idx) {
+ dst_apic = &(apic_dev->apics[dst_idx]);
}
}
for (i = 0; i < apic_dev->num_apics; i++) {
- if (apic_dev->apics[i].lapic_id.val == icr->dst) {
- return &(apic_dev->apics[i]);
+ if (apic_dev->apics[i].lapic_id.val == dst_idx) {
+ dst_apic = &(apic_dev->apics[i]);
}
}
-
- return NULL;
+
+ v3_unlock_irqrestore(apic_dev->state_lock, flags);
+
+ return dst_apic;
}
case APIC_SHORTHAND_NONE: // no shorthand
if (icr->dst_mode == APIC_DEST_PHYSICAL) {
- dest_apic = find_physical_apic(apic_dev, icr);
+ dest_apic = find_physical_apic(apic_dev, icr->dst);
if (dest_apic == NULL) {
PrintError("apic: Attempted send to unregistered apic id=%u\n", icr->dst);
dest_apic = &(apic_dev->apics[i]);
- del_flag = should_deliver_ipi(dest_apic->core, dest_apic, mda);
+ del_flag = should_deliver_ipi(apic_dev, dest_apic->core, dest_apic, mda);
if (del_flag == -1) {
}
}
}
- } else { //APIC_LOWEST_DELIVERY
- int i;
+ } else { // APIC_LOWEST_DELIVERY
struct apic_state * cur_best_apic = NULL;
uint8_t mda = icr->dst;
-
+ int i;
+
// logical, lowest priority
for (i = 0; i < apic_dev->num_apics; i++) {
dest_apic = &(apic_dev->apics[i]);
- del_flag = should_deliver_ipi(dest_apic->core, dest_apic, mda);
+ del_flag = should_deliver_ipi(apic_dev, dest_apic->core, dest_apic, mda);
if (del_flag == -1) {
PrintError("apic: Error checking delivery mode\n");
return -1;
} else if (del_flag == 1) {
// update priority for lowest priority scan
+ addr_t flags = 0;
+
+ flags = v3_lock_irqsave(apic_dev->state_lock);
+
if (cur_best_apic == 0) {
cur_best_apic = dest_apic;
} else if (dest_apic->task_prio.val < cur_best_apic->task_prio.val) {
cur_best_apic = dest_apic;
}
+
+ v3_unlock_irqrestore(apic_dev->state_lock, flags);
+
}
}
addr_t reg_addr = guest_addr - apic->base_addr;
struct apic_msr * msr = (struct apic_msr *)&(apic->base_addr_msr.value);
uint32_t op_val = *(uint32_t *)src;
+ addr_t flags = 0;
PrintDebug("apic %u: core %u: at %p and priv_data is at %p\n",
apic->lapic_id.val, core->vcpu_id, apic, priv_data);
case LDR_OFFSET:
PrintDebug("apic %u: core %u: setting log_dst.val to 0x%x\n",
apic->lapic_id.val, core->vcpu_id, op_val);
+ flags = v3_lock_irqsave(apic_dev->state_lock);
apic->log_dst.val = op_val;
+ v3_unlock_irqrestore(apic_dev->state_lock, flags);
break;
case DFR_OFFSET:
+ flags = v3_lock_irqsave(apic_dev->state_lock);
apic->dst_fmt.val = op_val;
+ v3_unlock_irqrestore(apic_dev->state_lock, flags);
break;
case SPURIOUS_INT_VEC_OFFSET:
apic->spurious_int.val = op_val;
static int apic_intr_pending(struct guest_info * core, void * private_data) {
struct apic_dev_state * apic_dev = (struct apic_dev_state *)(private_data);
struct apic_state * apic = &(apic_dev->apics[core->vcpu_id]);
+ int req_irq = 0;
+ int svc_irq = 0;
- // drain irq QUEUE
+ // Activate all queued IRQ entries
+ drain_irq_entries(apic);
- int req_irq = get_highest_irr(apic);
- int svc_irq = get_highest_isr(apic);
+ // Check for newly activated entries
+ req_irq = get_highest_irr(apic);
+ svc_irq = get_highest_isr(apic);
// PrintDebug("apic %u: core %u: req_irq=%d, svc_irq=%d\n",apic->lapic_id.val,info->vcpu_id,req_irq,svc_irq);
struct apic_dev_state * apic_dev = (struct apic_dev_state *)
(((struct vm_device*)dev_data)->private_data);
struct apic_state * apic = &(apic_dev->apics[dst]);
- int do_xcall;
PrintDebug("apic %u core ?: raising interrupt IRQ %u (dst = %u).\n", apic->lapic_id.val, irq, dst);
- do_xcall = activate_apic_irq(apic, irq);
+ add_apic_irq_entry(apic, irq);
- if (do_xcall < 0) {
- PrintError("Failed to activate apic irq\n");
- return -1;
- }
-
- if (do_xcall > 0 && (V3_Get_CPU() != dst)) {
-#ifdef V3_CONFIG_MULTITHREAD_OS
+#ifdef V3_CONFIG_MULTITHREAD_OS
+ if ((V3_Get_CPU() != dst)) {
v3_interrupt_cpu(vm, dst, 0);
-#else
- V3_ASSERT(0);
-#endif
-
}
+#endif
return 0;
}
sizeof(struct apic_state) * vm->num_cores);
apic_dev->num_apics = vm->num_cores;
+ v3_lock_init(&(apic_dev->state_lock));
struct vm_device * dev = v3_add_device(vm, dev_id, &dev_ops, apic_dev);
#define PrintDebug(fmt, args...)
#endif
+#ifndef V3_CONFIG_VNET
+static int net_debug = 0;
+#endif
+
#define TX_QUEUE_SIZE 4096
#define RX_QUEUE_SIZE 4096
#define CTRL_QUEUE_SIZE 64
}
V3_Net_Print(2, "Virtio-NIC: virtio_tx: size: %d\n", len);
- if(vnet_debug >= 4){
+ if(net_debug >= 4){
v3_hexdump(buf, len, NULL, 0);
}
}
static inline void enable_cb(struct virtio_queue *queue){
- queue->used->flags &= ~ VRING_NO_NOTIFY_FLAG;
+ if(queue->used){
+ queue->used->flags &= ~ VRING_NO_NOTIFY_FLAG;
+ }
}
static inline void disable_cb(struct virtio_queue *queue) {
- queue->used->flags |= VRING_NO_NOTIFY_FLAG;
+ if(queue->used){
+ queue->used->flags |= VRING_NO_NOTIFY_FLAG;
+ }
}
static int handle_pkt_tx(struct guest_info * core,
unsigned long flags;
V3_Net_Print(2, "Virtio-NIC: virtio_rx: size: %d\n", size);
- if(vnet_debug >= 4){
+ if(net_debug >= 4){
v3_hexdump(buf, size, NULL, 0);
}
return 0;
}
+
#define RATE_UPPER_THRESHOLD 10 /* 10000 pkts per second, around 100Mbits */
#define RATE_LOWER_THRESHOLD 1
#define PROFILE_PERIOD 10000 /*us*/
uint64_t period_us;
static int profile_ms = 0;
+ if(!net_state->status){ /* VNIC is not in working status */
+ return;
+ }
+
period_us = (1000*cpu_cycles)/cpu_freq;
net_state->past_us += period_us;
net_state->timer = v3_add_timer(&(info->cores[0]),&timer_ops,net_state);
+ PrintError("net_state 0x%p\n", (void *)net_state);
+
ops->recv = virtio_rx;
ops->frontend_data = net_state;
memcpy(ops->fnt_mac, virtio->mac, ETH_ALEN);
net_state->poll_thread = vnet_start_thread(virtio_tx_flush, (void *)net_state, "Virtio_Poll");
+ net_state->status = 1;
+
return 0;
}
V3_Net_Print(2, "VNET-NIC: send pkt (size: %d, src_id: %d, src_type: %d)\n",
pkt.size, pkt.src_id, pkt.src_type);
- if(vnet_debug >= 4){
+ if(net_debug >= 4){
v3_hexdump(buf, len, NULL, 0);
}
obj-$(V3_CONFIG_KEYED_STREAMS) += vmm_keyed_stream.o
obj-$(V3_CONFIG_HOST_DEVICE) += vmm_host_dev.o
+obj-y += null.o
--- /dev/null
+/** \file
+ * Do nothing module.
+ *
+ * This file only exists to appease the kbuild gods.
+ */
+
return -1;
}
- break;
+ break;
+ case VMEXIT_NMI:
+ // handled by interrupt dispatcher
+ break;
case VMEXIT_INTR:
// handled by interrupt dispatch earlier
break;
void v3_enqueue(struct v3_queue * queue, addr_t entry) {
struct v3_queue_entry * q_entry = V3_Malloc(sizeof(struct v3_queue_entry));
+ unsigned int flags = 0;
- v3_lock(queue->lock);
+ flags = v3_lock_irqsave(queue->lock);
q_entry->entry = entry;
list_add_tail(&(q_entry->entry_list), &(queue->entries));
queue->num_entries++;
- v3_unlock(queue->lock);
+ v3_unlock_irqrestore(queue->lock, flags);
}
addr_t v3_dequeue(struct v3_queue * queue) {
addr_t entry_val = 0;
+ unsigned int flags = 0;
- v3_lock(queue->lock);
+ flags = v3_lock_irqsave(queue->lock);
if (!list_empty(&(queue->entries))) {
struct list_head * q_entry = queue->entries.next;
struct v3_queue_entry * tmp_entry = list_entry(q_entry, struct v3_queue_entry, entry_list);
list_del(q_entry);
V3_Free(tmp_entry);
}
- v3_unlock(queue->lock);
+ v3_unlock_irqrestore(queue->lock, flags);
return entry_val;
}
#define Vnet_Debug(fmt, args...)
#endif
-int vnet_debug = 0;
+int net_debug = 0;
struct eth_hdr {
uint8_t dst_mac[ETH_ALEN];
struct vnet_dev * dst_dev;
struct vnet_dev * src_dev;
+ uint32_t idx;
+
struct list_head node;
struct list_head match_node; // used for route matching
};
struct list_head routes;
struct list_head devs;
- int num_routes;
- int num_devs;
+ uint32_t num_routes;
+ uint32_t route_idx;
+ uint32_t num_devs;
+ uint32_t dev_idx;
struct vnet_brg_dev * bridge;
#ifdef V3_CONFIG_DEBUG_VNET
-static inline void mac_to_string(uint8_t * mac, char * buf) {
+static inline void mac2str(uint8_t * mac, char * buf) {
snprintf(buf, 100, "%2x:%2x:%2x:%2x:%2x:%2x",
mac[0], mac[1], mac[2],
mac[3], mac[4], mac[5]);
static void print_route(struct v3_vnet_route * route){
char str[50];
- mac_to_string(route->src_mac, str);
+ mac2str(route->src_mac, str);
Vnet_Debug("Src Mac (%s), src_qual (%d)\n",
str, route->src_mac_qual);
- mac_to_string(route->dst_mac, str);
+ mac2str(route->dst_mac, str);
Vnet_Debug("Dst Mac (%s), dst_qual (%d)\n",
str, route->dst_mac_qual);
Vnet_Debug("Src dev id (%d), src type (%d)",
flags = vnet_lock_irqsave(vnet_state.lock);
list_add(&(new_route->node), &(vnet_state.routes));
- clear_hash_cache();
-
+ new_route->idx = ++ vnet_state.route_idx;
+ vnet_state.num_routes ++;
+
vnet_unlock_irqrestore(vnet_state.lock, flags);
-
+
+ clear_hash_cache();
#ifdef V3_CONFIG_DEBUG_VNET
dump_routes();
#endif
- return 0;
+ return new_route->idx;
+}
+
+
+void v3_vnet_del_route(uint32_t route_idx){
+ struct vnet_route_info * route = NULL;
+ unsigned long flags;
+
+ flags = vnet_lock_irqsave(vnet_state.lock);
+
+ list_for_each_entry(route, &(vnet_state.routes), node) {
+ if(route->idx == route_idx){
+ list_del(&(route->node));
+ list_del(&(route->match_node));
+ Vnet_Free(route);
+ }
+ }
+
+ vnet_unlock_irqrestore(vnet_state.lock, flags);
}
int max_rank = 0;
struct list_head match_list;
struct eth_hdr * hdr = (struct eth_hdr *)(pkt->data);
- // uint8_t src_type = pkt->src_type;
+ // uint8_t src_type = pkt->src_type;
// uint32_t src_link = pkt->src_id;
#ifdef V3_CONFIG_DEBUG_VNET
char dst_str[100];
char src_str[100];
- mac_to_string(hdr->src_mac, src_str);
- mac_to_string(hdr->dst_mac, dst_str);
+ mac2str(hdr->src_mac, src_str);
+ mac2str(hdr->dst_mac, dst_str);
Vnet_Debug("VNET/P Core: match_route. pkt: SRC(%s), DEST(%s)\n", src_str, dst_str);
}
#endif
Vnet_Print(2, "VNET/P Core: cpu %d: pkt (size %d, src_id:%d, src_type: %d, dst_id: %d, dst_type: %d)\n",
cpu, pkt->size, pkt->src_id,
pkt->src_type, pkt->dst_id, pkt->dst_type);
- if(vnet_debug >= 4){
+ if(net_debug >= 4){
v3_hexdump(pkt->data, pkt->size, NULL, 0);
}
if (dev_by_mac(mac) == NULL) {
list_add(&(new_dev->node), &(vnet_state.devs));
- new_dev->dev_id = ++vnet_state.num_devs;
+ new_dev->dev_id = ++ vnet_state.dev_idx;
+ vnet_state.num_devs ++;
}
vnet_unlock_irqrestore(vnet_state.lock, flags);
dev = dev_by_id(dev_id);
if (dev != NULL){
list_del(&(dev->node));
- del_routes_by_dev(dev_id);
+ //del_routes_by_dev(dev_id);
+ vnet_state.num_devs --;
}
vnet_unlock_irqrestore(vnet_state.lock, flags);
int v3_vnet_stat(struct vnet_stat * stats){
-
stats->rx_bytes = vnet_state.stats.rx_bytes;
stats->rx_pkts = vnet_state.stats.rx_pkts;
stats->tx_bytes = vnet_state.stats.tx_bytes;
return 0;
}
-static void free_devices(){
+static void deinit_devices_list(){
struct vnet_dev * dev = NULL;
list_for_each_entry(dev, &(vnet_state.devs), node) {
}
}
-static void free_routes(){
+static void deinit_routes_list(){
struct vnet_route_info * route = NULL;
list_for_each_entry(route, &(vnet_state.routes), node) {
return 0;
}
+
+void v3_vnet_del_bridge(uint8_t type) {
+ unsigned long flags;
+ struct vnet_brg_dev * tmp_bridge = NULL;
+
+ flags = vnet_lock_irqsave(vnet_state.lock);
+
+ if (vnet_state.bridge != NULL && vnet_state.bridge->type == type) {
+ tmp_bridge = vnet_state.bridge;
+ vnet_state.bridge = NULL;
+ }
+
+ vnet_unlock_irqrestore(vnet_state.lock, flags);
+
+ if (tmp_bridge) {
+ Vnet_Free(tmp_bridge);
+ }
+}
+
+
static int vnet_tx_flush(void *args){
unsigned long flags;
struct queue_entry * entry;
vnet_lock_deinit(&(vnet_state.lock));
- free_devices();
- free_routes();
+ deinit_devices_list();
+ deinit_routes_list();
vnet_free_htable(vnet_state.route_cache, 1, 1);
Vnet_Free(vnet_state.bridge);
struct vnet_host_hooks * host_hooks;
-
int vnet_lock_init(vnet_lock_t * lock) {
- *lock = (addr_t)(host_hooks->mutex_alloc());
-
- if (!(*lock)) {
- return -1;
+ if((host_hooks) && host_hooks->mutex_alloc){
+ *lock = (addr_t)(host_hooks->mutex_alloc());
+
+ if (*lock) {
+ return 0;
+ }
}
- return 0;
+ return -1;
}
struct vnet_thread * vnet_start_thread(int (*func)(void *), void *arg, char * name){
- struct vnet_thread * thread;
-
- thread = Vnet_Malloc(sizeof(struct vnet_thread));
-
- thread->host_thread = host_hooks->thread_start(func, arg, name);
+ if((host_hooks) && host_hooks->thread_start){
+ struct vnet_thread * thread = Vnet_Malloc(sizeof(struct vnet_thread));
+ thread->host_thread = host_hooks->thread_start(func, arg, name);
- if(thread->host_thread == NULL){
+ if(thread->host_thread){
+ return thread;
+ }
Vnet_Free(thread);
- return NULL;
}
- return thread;
+ return NULL;
}
struct vnet_timer * vnet_create_timer(unsigned long interval,
void (* timer_fun)(void * priv_data),
void * priv_data){
- struct vnet_timer * timer = NULL;
-
if((host_hooks) && host_hooks->timer_create){
- timer = Vnet_Malloc(sizeof(struct vnet_timer));
-
+ struct vnet_timer * timer = Vnet_Malloc(sizeof(struct vnet_timer));
timer->host_timer = host_hooks->timer_create(interval, timer_fun, priv_data);
+ return timer;
}
- return timer;
+ return NULL;
}
}
+void deinit_vnet(){
+ host_hooks = NULL;
+ v3_deinit_vnet();
+}
+