+#define V3_lapic_send_ipi(cpu, vector) \
+ do { \
+ extern struct v3_os_hooks * os_hooks; \
+ if ((os_hooks) && (os_hooks)->lapic_send_ipi) { \
+ (os_hooks)->lapic_send_ipi(cpu, vector); \
+ } \
+ } while (0)
+
typedef enum v3_vm_class {V3_INVALID_VM, V3_PC_VM, V3_CRAY_VM} v3_vm_class_t;
void (*interrupt_cpu)(struct v3_vm_info * vm, int logical_cpu);
void (*call_on_cpu)(int logical_cpu, void (*fn)(void * arg), void * arg);
void (*start_thread_on_cpu)(int logical_cpu, int (*fn)(void * arg), void * arg, char * thread_name);
-};
-
-
-
-
+ void (*lapic_send_ipi)(unsigned int cpu, unsigned int vector);
+};
//
#include <palacios/vmm.h>
+
+#define V3_VNET_POLLING_VECTOR 50
+
typedef enum {MAC_ANY=0, MAC_NOT, MAC_NONE, MAC_ADDR} mac_type_t; //for 'src_mac_qual' and 'dst_mac_qual'
typedef enum {LINK_INTERFACE=0, LINK_EDGE, LINK_ANY} link_type_t; //for 'type' and 'src_type' in struct routing
};
#endif
+struct v3_vnet_bridge_input_args{
+ struct v3_vm_info * vm;
+ struct v3_vnet_pkt *vnet_pkts;
+ uint16_t pkt_num;
+ void * private_data;
+};
int v3_vnet_send_pkt(struct v3_vnet_pkt * pkt, void *private_data);
-int v3_vnet_add_route(struct v3_vnet_route route);
-
-//int v3_vnet_del_route();
-
+void v3_vnet_send_pkt_xcall(void * data);
+int v3_vnet_add_route(struct v3_vnet_route route);
int V3_init_vnet();
int v3_vnet_add_bridge(struct v3_vm_info * vm,
- int (*input)(struct v3_vm_info * vm, struct v3_vnet_pkt * pkt, void * private_data),
- void * priv_data);
+ int (*input)(struct v3_vm_info * vm, struct v3_vnet_pkt pkt[], uint16_t pkt_num, void * private_data),
+ void (*xcall_input)(void *data),
+ uint16_t max_delayed_pkts,
+ long max_latency,
+ void * priv_data);
int v3_vnet_add_dev(struct v3_vm_info *info, uint8_t mac[6],
int (*dev_input)(struct v3_vm_info * vm, struct v3_vnet_pkt * pkt, void * private_data),
void * priv_data);
+void v3_vnet_heartbeat(struct guest_info *core);
+
+
+int v3_vnet_disable_bridge();
+int v3_vnet_enable_bridge();
+
+void v3_vnet_bridge_polling();
+
+int v3_vnet_bridge_rx(uchar_t *buf, uint16_t size, uint16_t src_link);
#endif
struct virtio_queue * q = &(virtio_state->tx_vq);
struct virtio_net_hdr * hdr = NULL;
+ PrintDebug("Virtio NIC: TX: running on cpu: %d\n", V3_Get_CPU());
while (q->cur_avail_idx != q->avail->index) {
struct vring_desc * hdr_desc = NULL;
hdr = (struct virtio_net_hdr*)hdr_addr;
desc_idx = hdr_desc->next;
-
+
for (i = 0; i < desc_cnt - 1; i++) {
struct vring_desc * buf_desc = &(q->desc[desc_idx]);
if (pkt_tx(core, virtio_state, buf_desc) == -1) {
virtio_state->virtio_cfg.pci_isr = 0x1;
}
+#ifdef CONFIG_VNET_PROFILE
+ if (virtio_state->pkt_sent % 10000 == 0)
+ PrintError("Virtio NIC: sent: %ld, rxed: %ld, dropped: %ld\n",
+ virtio_state->pkt_sent,
+ virtio_state->pkt_recv,
+ virtio_state->pkt_drop);
+
+#endif
+
return 0;
}
int raw = 1;
flags = v3_lock_irqsave(virtio->lock);
-
- PrintDebug("VIRTIO NIC: receiving packet to virtio nic %p, size:%d\n", virtio, size);
+
+ PrintDebug("VIRTIO NIC: RX on cpu %d to virtio nic %p, size:%d\n", V3_Get_CPU(), virtio, size);
virtio->pkt_recv ++;
q->cur_avail_idx++;
} else {
virtio->pkt_drop++;
+ goto exit;
}
if (!(q->avail->flags & VIRTIO_NO_IRQ_FLAG)) {
ret_val = offset;
exit:
+
+#ifdef CONFIG_VNET_PROFILE
+ if (virtio->pkt_recv % 10000 == 0)
+ PrintError("Virtio NIC: sent: %ld, rxed: %ld, dropped: %ld\n",
+ virtio->pkt_sent,
+ virtio->pkt_recv,
+ virtio->pkt_drop);
+
+#endif
v3_unlock_irqrestore(virtio->lock, flags);
PrintDebug("SYMMOD: VIRTIO SYMMOD Kick on loader queue\n");
- while (q->cur_avail_idx ! q->avail->index) {
+ while (q->cur_avail_idx != q->avail->index) {
struct vring_desc * hdr_desc = NULL;
struct vring_desc * buf_desc = NULL;
struct vring_desc * status_desc = NULL;
* http://www.v3vee.org
*
* Copyright (c) 2008, Jack Lange <jarusl@cs.northwestern.edu>
+ * Copyright (c) 2008, Lei Xia <lxia@cs.northwestern.edu>
* Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org>
* All rights reserved.
*
* Author: Jack Lange <jarusl@cs.northwestern.edu>
+ * Lei Xia <lxia@cs.northwestern.edu>
*
* This is free software. You are permitted to use,
* redistribute, and modify it as specified in the file "V3VEE_LICENSE".
#endif
-#define QUEUE_SIZE 128
+#define QUEUE_SIZE 8192
+#define CMD_QUEUE_SIZE 128
#define NUM_QUEUES 3
struct vnet_config {
int io_range_size;
v3_lock_t lock;
+
+ ulong_t pkt_sent, pkt_recv, pkt_drop;
+ int ready;
};
#define VNET_GET_ROUTES 10
uint32_t num_cmds;
} __attribute__((packed));
-struct vnet_virtio_pkt {
+
+struct vnet_bridge_pkt {
uint32_t link_id;
uint32_t pkt_size;
uint8_t pkt[ETHERNET_PACKET_LEN];
static int virtio_reset(struct virtio_vnet_state * vnet_state) {
- memset(vnet_state->queue, 0, sizeof(struct virtio_queue) * 2);
+ memset(vnet_state->queue, 0, sizeof(struct virtio_queue) * NUM_QUEUES);
vnet_state->cur_queue = &(vnet_state->queue[0]);
vnet_state->virtio_cfg.status = 0;
vnet_state->virtio_cfg.pci_isr = 0;
- vnet_state->queue[0].queue_size = QUEUE_SIZE;
+ vnet_state->queue[0].queue_size = CMD_QUEUE_SIZE;
vnet_state->queue[1].queue_size = QUEUE_SIZE;
vnet_state->queue[2].queue_size = QUEUE_SIZE;
}
-static int vnet_pkt_input_cb(struct v3_vm_info * vm, struct v3_vnet_pkt * pkt, void * private_data){
+static int vnet_pkt_input_cb(struct v3_vm_info * vm, struct v3_vnet_pkt vnet_pkts[], uint16_t pkt_num, void * private_data){
struct virtio_vnet_state * vnet_state = (struct virtio_vnet_state *)private_data;
struct virtio_queue * q = &(vnet_state->queue[RECV_QUEUE]);
int ret_val = -1;
unsigned long flags;
+ uint16_t sent;
+ struct v3_vnet_pkt *pkt;
+
+ if(pkt_num <= 0)
+ return 0;
flags = v3_lock_irqsave(vnet_state->lock);
goto exit;
}
+ PrintDebug("VNET Bridge: RX: running on cpu: %d, num of pkts: %d\n", V3_Get_CPU(), pkt_num);
- if (q->cur_avail_idx != q->avail->index) {
- uint16_t pkt_idx = q->avail->ring[q->cur_avail_idx % q->queue_size];
- struct vring_desc * pkt_desc = NULL;
- struct vnet_virtio_pkt * virtio_pkt = NULL;
+ for(sent = 0; sent < pkt_num; sent ++) {
+ pkt = &vnet_pkts[sent];
+ vnet_state->pkt_recv ++;
+ if (q->cur_avail_idx != q->avail->index) {
+ uint16_t pkt_idx = q->avail->ring[q->cur_avail_idx % q->queue_size];
+ struct vring_desc * pkt_desc = NULL;
+ struct vnet_bridge_pkt * virtio_pkt = NULL;
- pkt_desc = &(q->desc[pkt_idx]);
- PrintDebug("VNET Bridge RX: buffer desc len: %d\n", pkt_desc->length);
+ //if(q->cur_avail_idx % 100 == 0)
+ // PrintError("cur_avai_idx %d, idx: %d\n", q->cur_avail_idx, q->avail->index);
- if (guest_pa_to_host_va(&(vm->cores[0]), pkt_desc->addr_gpa, (addr_t *)&(virtio_pkt)) == -1) {
- PrintError("Could not translate buffer address\n");
- return -1;
- }
+ pkt_desc = &(q->desc[pkt_idx]);
+ PrintDebug("VNET Bridge RX: buffer desc len: %d\n", pkt_desc->length);
- PrintDebug("VNET Bridge: RX: pkt sent to guest pkt size: %d, dst link: %d\n", pkt->size, pkt->dst_id);
+ if (guest_pa_to_host_va(&(vm->cores[0]), pkt_desc->addr_gpa, (addr_t *)&(virtio_pkt)) == -1) {
+ PrintError("Could not translate buffer address\n");
+ goto exit;
+ }
+
+ PrintDebug("VNET Bridge: RX: pkt sent to guest pkt size: %d, dst link: %d\n", pkt->size, pkt->dst_id);
- // Fill in dst packet buffer
- virtio_pkt->link_id = pkt->dst_id;
- virtio_pkt->pkt_size = pkt->size;
- memcpy(virtio_pkt->pkt, pkt->data, pkt->size);
+ // Fill in dst packet buffer
+ virtio_pkt->link_id = pkt->dst_id;
+ virtio_pkt->pkt_size = pkt->size;
+ memcpy(virtio_pkt->pkt, pkt->data, pkt->size);
- q->used->ring[q->used->index % q->queue_size].id = q->avail->ring[q->cur_avail_idx % q->queue_size];
- q->used->ring[q->used->index % q->queue_size].length = sizeof(struct vnet_virtio_pkt); // This should be the total length of data sent to guest (header+pkt_data)
+ q->used->ring[q->used->index % q->queue_size].id = q->avail->ring[q->cur_avail_idx % q->queue_size];
+ q->used->ring[q->used->index % q->queue_size].length = sizeof(struct vnet_bridge_pkt); // This should be the total length of data sent to guest (header+pkt_data)
+
+ q->used->index++;
+ q->cur_avail_idx++;
+ } else {
+ //PrintError("VNET Bridge: guest RX buffer full: cur_avai_idx %d, idx: %d\nDisable Bridge\n", q->cur_avail_idx, q->avail->index);
+ vnet_state->pkt_drop ++;
+ v3_vnet_disable_bridge();
+ }
+ }
- q->used->index++;
- q->cur_avail_idx++;
- } else {
- PrintError("Packet buffer overflow in the guest: cur_avai_idx %d, idx: %d\n", q->cur_avail_idx, q->avail->index);
+ if(sent == 0){
+ goto exit;
}
if (!(q->avail->flags & VIRTIO_NO_IRQ_FLAG)) {
ret_val = 0;
exit:
+
+#ifdef CONFIG_VNET_PROFILE
+ if (vnet_state->pkt_recv % 10000 == 0)
+ PrintError("Vnet Bridge: sent: %ld, rxed: %ld, dropped: %ld\n",
+ vnet_state->pkt_sent,
+ vnet_state->pkt_recv,
+ vnet_state->pkt_drop);
+
+#endif
+
v3_unlock_irqrestore(vnet_state->lock, flags);
return ret_val;
}
+static void vnet_pkt_input_xcall(void *data){
+ struct v3_vnet_bridge_input_args *args = (struct v3_vnet_bridge_input_args *)data;
+
+ vnet_pkt_input_cb(args->vm, args->vnet_pkts, args->pkt_num, args->private_data);
+}
static int handle_pkt_kick(struct guest_info *core, struct virtio_vnet_state * vnet_state)
{
struct virtio_queue * q = &(vnet_state->queue[XMIT_QUEUE]);
- struct v3_vnet_pkt pkt;
while (q->cur_avail_idx != q->avail->index) {
uint16_t desc_idx = q->avail->ring[q->cur_avail_idx % q->queue_size];
struct vring_desc * pkt_desc = NULL;
- struct vnet_virtio_pkt * virtio_pkt = NULL;
+ struct vnet_bridge_pkt * virtio_pkt = NULL;
pkt_desc = &(q->desc[desc_idx]);
PrintDebug("VNET Bridge: Handle TX desc buf_len: %d\n", pkt_desc->length);
-
- //PrintDebug("q: %p, %p, %p, %d\n", q, vnet_state->queue, &vnet_state->queue[XMIT_QUEUE], XMIT_QUEUE);
- //PrintDebug("q->used: %p\n", q->used);
- //PrintDebug("q->used->ring %p\n", q->used->ring);
-
+
if (guest_pa_to_host_va(core, pkt_desc->addr_gpa, (addr_t *)&(virtio_pkt)) == -1) {
PrintError("Could not translate buffer address\n");
return -1;
}
- PrintDebug("VNET Bridge: TX: pkt size: %d, dst link: %d\n", virtio_pkt->pkt_size, virtio_pkt->link_id);
-
- pkt.size = virtio_pkt->pkt_size;
- pkt.src_id = virtio_pkt->link_id;
- pkt.src_type = LINK_EDGE;
- memcpy(pkt.header, virtio_pkt->pkt, ETHERNET_HEADER_LEN);
- pkt.data = virtio_pkt->pkt;
-
- v3_vnet_send_pkt(&pkt, NULL);
-
- q = (struct virtio_queue *)((addr_t)vnet_state->queue + XMIT_QUEUE*sizeof(struct virtio_queue));
-
- PrintDebug("After q: %p, , %p, %p, %d\n", q, vnet_state->queue, &(vnet_state->queue[XMIT_QUEUE]), XMIT_QUEUE);
- //PrintDebug("After q->used: %p\n", q->used);
- //PrintDebug("After q->used->ring %p\n", q->used->ring);
+ PrintDebug("VNET Bridge: TX: on cpu %d pkt size: %d, dst link: %d\n", cpu, virtio_pkt->pkt_size, virtio_pkt->link_id);
+ v3_vnet_bridge_rx(virtio_pkt->pkt, virtio_pkt->pkt_size, virtio_pkt->link_id);
+
q->used->ring[q->used->index % q->queue_size].id = q->avail->ring[q->cur_avail_idx % q->queue_size];
q->used->ring[q->used->index % q->queue_size].length = pkt_desc->length; // What do we set this to????
q->used->index++;
+ vnet_state->pkt_sent ++;
+
q->cur_avail_idx++;
}
- if (!(q->avail->flags & VIRTIO_NO_IRQ_FLAG)) {
- v3_pci_raise_irq(vnet_state->pci_bus, 0, vnet_state->pci_dev);
- vnet_state->virtio_cfg.pci_isr = 0x1;
+ //interrupt the vnet to poll pkts
+ int cpu = V3_Get_CPU();
+ cpu = (cpu == 0)?1:0;
+ V3_lapic_send_ipi(cpu, V3_VNET_POLLING_VECTOR);
+
+ if((vnet_state->pkt_sent % (QUEUE_SIZE/20)) == 0) { //optimized for guest's, batch the interrupts
+ if (!(q->avail->flags & VIRTIO_NO_IRQ_FLAG)) {
+ v3_pci_raise_irq(vnet_state->pci_bus, 0, vnet_state->pci_dev);
+ vnet_state->virtio_cfg.pci_isr = 0x1;
+ }
}
+#ifdef CONFIG_VNET_PROFILE
+ if (vnet_state->pkt_sent % 10000 == 0)
+ PrintError("Vnet Bridge: sent: %ld, rxed: %ld, dropped: %ld\n",
+ vnet_state->pkt_sent,
+ vnet_state->pkt_recv,
+ vnet_state->pkt_drop);
+
+#endif
+
return 0;
}
-static int virtio_io_write(struct guest_info * core, uint16_t port, void * src, uint_t length, void * private_data) {
+
+static int handle_rx_kick(struct guest_info *core, struct virtio_vnet_state * vnet_state)
+{
+ v3_vnet_enable_bridge();
+ //PrintError("Enable Bridge\n");
+
+ return 0;
+}
+
+static int vnet_virtio_io_write(struct guest_info * core, uint16_t port, void * src, uint_t length, void * private_data) {
struct virtio_vnet_state * vnet_state = (struct virtio_vnet_state *)private_data;
int port_idx = port % vnet_state->io_range_size;
PrintDebug("VNET Bridge: RingDesc=%p, Avail=%p, Used=%p\n",
vnet_state->cur_queue->desc, vnet_state->cur_queue->avail, vnet_state->cur_queue->used);
+ if(vnet_state->queue[RECV_QUEUE].avail != NULL){
+ vnet_state->ready = 1;
+ }
} else {
PrintError("Illegal write length for page frame number\n");
return -1;
if (handle_pkt_kick(core, vnet_state) == -1){
PrintError("Could not handle Virtio VNET TX\n");
return -1;
- }
+ }
} else if (queue_idx == 2) {
- PrintDebug("VNET Bridge: receive kick on RX Queue\n");
+ if (handle_rx_kick(core, vnet_state) == -1){
+ PrintError("Could not handle Virtio RX buffer refills Kick\n");
+ return -1;
+ }
} else {
PrintError("VNET Bridge: Kick on invalid queue (%d)\n", queue_idx);
return -1;
}
-static int virtio_io_read(struct guest_info * core, uint16_t port, void * dst, uint_t length, void * private_data) {
+static int vnet_virtio_io_read(struct guest_info * core, uint16_t port, void * dst, uint_t length, void * private_data) {
struct virtio_vnet_state * vnet_state = (struct virtio_vnet_state *)private_data;
int port_idx = port % vnet_state->io_range_size;
.stop = NULL,
};
-
static int dev_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
struct vm_device * pci_bus = v3_find_dev(vm, v3_cfg_val(cfg, "bus"));
struct virtio_vnet_state * vnet_state = NULL;
bars[0].type = PCI_BAR_IO;
bars[0].default_base_port = -1;
bars[0].num_ports = vnet_state->io_range_size;
- bars[0].io_read = virtio_io_read;
- bars[0].io_write = virtio_io_write;
+ bars[0].io_read = vnet_virtio_io_read;
+ bars[0].io_write = vnet_virtio_io_write;
bars[0].private_data = vnet_state;
pci_dev = v3_pci_register_device(pci_bus, PCI_STD_DEVICE,
virtio_reset(vnet_state);
V3_Print("Registering Virtio device as vnet bridge\n");
- v3_vnet_add_bridge(vm, vnet_pkt_input_cb, (void *)vnet_state);
+ v3_vnet_add_bridge(vm, vnet_pkt_input_cb, vnet_pkt_input_xcall, 5, 1000000, (void *)vnet_state);
+
return 0;
}
} __attribute__((packed));
+#define BRIDGE_BUF_SIZE 1024
+struct bridge_pkts_buf {
+ int start, end;
+ int num;
+ v3_lock_t lock;
+ struct v3_vnet_pkt pkts[BRIDGE_BUF_SIZE];
+ uint8_t datas[ETHERNET_PACKET_LEN*BRIDGE_BUF_SIZE];
+};
+
struct vnet_brg_dev {
struct v3_vm_info * vm;
- int (*input)(struct v3_vm_info * vm, struct v3_vnet_pkt * pkt, void * private_data);
+ int (*input)(struct v3_vm_info * vm, struct v3_vnet_pkt pkt[], uint16_t pkt_num, void * private_data);
+ void (*xcall_input)(void *data);
+
+ struct bridge_pkts_buf recv_buf; //packets from Vnet to vnet_bridge device
+
+ struct bridge_pkts_buf send_buf; //packets from vnet_bridge device to Vnet
+
+ int disabled;
+
+ uint16_t max_delayed_pkts;
+ long max_latency; //in cycles
void * private_data;
} __attribute__((packed));
};
-
-
struct route_list {
uint8_t hash_buf[VNET_HASH_SIZE];
#ifdef CONFIG_DEBUG_VNET
static inline void mac_to_string(char mac[6], char * buf) {
- snprintf(buf, 50, "%x:%x:%x:%x:%x:%x",
+ snprintf(buf, 100, "%d:%d:%d:%d:%d:%d",
mac[0], mac[1], mac[2],
mac[3], mac[4], mac[5]);
}
return (memcmp((uint8_t *)key1, (uint8_t *)key2, VNET_HASH_SIZE) == 0);
}
-
static int add_route_to_cache(const struct v3_vnet_pkt * pkt, struct route_list * routes) {
memcpy(routes->hash_buf, pkt->hash_buf, VNET_HASH_SIZE);
#ifdef CONFIG_DEBUG_VNET
{
- char dst_str[50];
- char src_str[50];
+ char dst_str[100];
+ char src_str[100];
mac_to_string(hdr->src_mac, src_str);
mac_to_string(hdr->dst_mac, dst_str);
return NULL;
}
- matches = V3_Malloc(sizeof(struct route_list) +
- (sizeof(struct vnet_route_info *) * num_matches));
+ matches = (struct route_list *)V3_Malloc(sizeof(struct route_list) +
+ (sizeof(struct vnet_route_info *) * num_matches));
matches->num_routes = num_matches;
}
+static int flush_bridge_pkts(struct vnet_brg_dev *bridge){
+ unsigned long flags;
+ int num, start, send;
+ struct v3_vnet_bridge_input_args args;
+ int cpu_id = bridge->vm->cores[0].cpu_id;
+ int current_core = V3_Get_CPU();
+
+ if (bridge == NULL) {
+ PrintDebug("VNET: No bridge to sent data to links\n");
+ return -1;
+ }
+
+ flags = v3_lock_irqsave(bridge->recv_buf.lock);
+
+ num = bridge->recv_buf.num;
+ start = bridge->recv_buf.start;
+
+ bridge->recv_buf.num -= num;
+ bridge->recv_buf.start += num;
+ bridge->recv_buf.start %= BRIDGE_BUF_SIZE;
+
+ v3_unlock_irqrestore(bridge->recv_buf.lock, flags);
+
+
+ if(bridge->disabled){
+ PrintDebug("VNET: In flush bridge pkts: Bridge is disabled\n");
+ return -1;
+ }
+
+ if(num <= 2 && num > 0){
+ PrintDebug("VNET: In flush bridge pkts: %d\n", num);
+ }
+
+ if(num > 0) {
+ PrintDebug("VNET: In flush bridge pkts to bridge, cur_cpu %d, brige_core: %d\n", current_core, cpu_id);
+ if (current_core == cpu_id){
+ if ((start + num) < BRIDGE_BUF_SIZE){
+ bridge->input(bridge->vm, &(bridge->recv_buf.pkts[start]), num, bridge->private_data);
+ }else {
+ bridge->input(bridge->vm, &(bridge->recv_buf.pkts[start]), (BRIDGE_BUF_SIZE - start), bridge->private_data);
+ send = num - (BRIDGE_BUF_SIZE - start);
+ bridge->input(bridge->vm, &(bridge->recv_buf.pkts[0]), send, bridge->private_data);
+ }
+ }else {
+ args.vm = bridge->vm;
+ args.private_data = bridge->private_data;
+
+ if ((start + num) < BRIDGE_BUF_SIZE){
+ args.pkt_num = num;
+ args.vnet_pkts = &(bridge->recv_buf.pkts[start]);
+ V3_Call_On_CPU(cpu_id, bridge->xcall_input, (void *)&args);
+ }else {
+ args.pkt_num = BRIDGE_BUF_SIZE - start;
+ args.vnet_pkts = &(bridge->recv_buf.pkts[start]);
+ V3_Call_On_CPU(cpu_id, bridge->xcall_input, (void *)&args);
+
+ send = num - (BRIDGE_BUF_SIZE - start);
+ args.pkt_num = send;
+ args.vnet_pkts = &(bridge->recv_buf.pkts[0]);
+ V3_Call_On_CPU(cpu_id, bridge->xcall_input, (void *)&args);
+ }
+ }
+
+ PrintDebug("VNET: flush bridge pkts %d\n", num);
+ }
+
+ return 0;
+}
+
+
+static int send_to_bridge(struct v3_vnet_pkt * pkt){
+ struct vnet_brg_dev *bridge = vnet_state.bridge;
+ int cpu_id = bridge->vm->cores[0].cpu_id;
+ struct v3_vnet_bridge_input_args args;
+
+ if (bridge == NULL) {
+ PrintDebug("VNET: No bridge to sent data to links\n");
+ return -1;
+ }
+
+ if(bridge->max_delayed_pkts <= 1){
+ if(bridge->disabled){
+ PrintDebug("VNET: Bridge diabled\n");
+ return -1;
+ }
+
+ args.pkt_num = 1;
+ args.vm = bridge->vm;
+ args.vnet_pkts = pkt;
+ args.private_data = bridge->private_data;
+
+ V3_Call_On_CPU(cpu_id, bridge->xcall_input, (void *)&args);
+ PrintDebug("VNET: sent one packet to the bridge\n");
+ return 0;
+ }
+
+ unsigned long flags;
+ int end, num=0;
+ struct v3_vnet_pkt *buf;
+
+ PrintDebug("VNET: send_to_bridge\n");
+
+ flags = v3_lock_irqsave(bridge->recv_buf.lock);
+
+ if(bridge->disabled && bridge->recv_buf.num >= BRIDGE_BUF_SIZE){
+ PrintDebug("Bridge diabled and bridge receive buffer full\n");
+ v3_unlock_irqrestore(bridge->recv_buf.lock, flags);//maybe should move this after copy
+ num = bridge->recv_buf.num;
+ goto exit;
+ }
+
+ end = bridge->recv_buf.end;
+ buf = &(bridge->recv_buf.pkts[end]);
+
+ bridge->recv_buf.num ++;
+ bridge->recv_buf.end ++;
+ bridge->recv_buf.end %= BRIDGE_BUF_SIZE;
+
+ num = bridge->recv_buf.num;
+
+ v3_unlock_irqrestore(bridge->recv_buf.lock, flags);//maybe should move this after copy
+
+
+ buf->size = pkt->size;
+ buf->dst_id = pkt->dst_id;
+ buf->src_id = pkt->src_id;
+ buf->src_type = pkt->src_type;
+ buf->dst_type = pkt->dst_type;
+ memcpy(buf->header, pkt->header, ETHERNET_HEADER_LEN);
+ memcpy(buf->data, pkt->data, pkt->size);
+
+exit:
+
+ if (num >= bridge->max_delayed_pkts){
+ flush_bridge_pkts(bridge);
+ }
+
+ return 0;
+}
+
int v3_vnet_send_pkt(struct v3_vnet_pkt * pkt, void * private_data) {
struct route_list * matched_routes = NULL;
unsigned long flags;
#ifdef CONFIG_DEBUG_VNET
{
struct eth_hdr * hdr = (struct eth_hdr *)(pkt->header);
- char dest_str[30];
- char src_str[30];
+ char dest_str[100];
+ char src_str[100];
mac_to_string(hdr->src_mac, src_str);
mac_to_string(hdr->dst_mac, dest_str);
- PrintDebug("Vnet: HandleDataOverLink. SRC(%s), DEST(%s)\n", src_str, dest_str);
+ int cpu = V3_Get_CPU();
+ PrintDebug("Vnet: on cpu %d, HandleDataOverLink. SRC(%s), DEST(%s), pkt size: %d\n", cpu, src_str, dest_str, pkt->size);
}
#endif
PrintDebug("Vnet: send pkt Looking into routing table\n");
matched_routes = match_route(pkt);
-
+
if (matched_routes) {
add_route_to_cache(pkt, matched_routes);
} else {
v3_unlock_irqrestore(vnet_state.lock, flags);
-
PrintDebug("Vnet: send pkt route matches %d\n", matched_routes->num_routes);
for (i = 0; i < matched_routes->num_routes; i++) {
pkt->dst_type = LINK_EDGE;
pkt->dst_id = route->route_def.dst_id;
- if (vnet_state.bridge == NULL) {
- PrintDebug("VNET: No bridge to sent data to links\n");
+ if (send_to_bridge(pkt) == -1) {
+ PrintDebug("VNET: Packet not sent properly to bridge\n");
continue;
- }
-
- if (vnet_state.bridge->input(vnet_state.bridge->vm, pkt, vnet_state.bridge->private_data) == -1) {
- PrintDebug("VNET: Packet not sent properly\n");
- continue;
- }
-
+ }
+
} else if (route->route_def.dst_type == LINK_INTERFACE) {
if (route->dst_dev->input(route->dst_dev->vm, pkt, route->dst_dev->private_data) == -1) {
PrintDebug("VNET: Packet not sent properly\n");
continue;
}
- PrintDebug("Vnet: HandleOnePacket: Forward packet according to Route\n");
+ PrintDebug("Vnet: v3_vnet_send_pkt: Forward packet according to Route %d\n", i);
}
return 0;
}
+void v3_vnet_send_pkt_xcall(void * data){
+ struct v3_vnet_pkt * pkt = (struct v3_vnet_pkt *)data;
+ v3_vnet_send_pkt(pkt, NULL);
+}
+
+
+void v3_vnet_bridge_polling()
+{
+ unsigned long flags;
+ int num, start;
+ struct v3_vnet_pkt *buf;
+ struct vnet_brg_dev *bridge = vnet_state.bridge;
+
+ PrintDebug("In vnet bridge pollling: cpu %d\n", V3_Get_CPU());
+
+ if(bridge == NULL){
+ PrintDebug("VNET: Bridge is not set\n");
+ return;
+ }
+
+ flags = v3_lock_irqsave(bridge->send_buf.lock);
+
+ num = bridge->send_buf.num;
+ start = bridge->send_buf.start;
+
+ PrintDebug("VNET: bridge polling pkts %d\n", num);
+
+ while(num > 0) {
+ buf = &(bridge->send_buf.pkts[bridge->send_buf.start]);
+
+ v3_vnet_send_pkt(buf, NULL);
+
+ bridge->send_buf.num --;
+ bridge->send_buf.start ++;
+ bridge->send_buf.start %= BRIDGE_BUF_SIZE;
+ num --;
+ }
+
+ v3_unlock_irqrestore(bridge->send_buf.lock, flags);
+
+ return;
+}
+
+
+int v3_vnet_bridge_rx(uchar_t *buf, uint16_t size, uint16_t src_link){
+ struct vnet_brg_dev *bridge = vnet_state.bridge;
+ unsigned long flags;
+ int end;
+ struct v3_vnet_pkt *pkt;
+
+ if (bridge == NULL) {
+ PrintDebug("VNET: No bridge is set\n");
+ return -1;
+ }
+
+ flags = v3_lock_irqsave(bridge->send_buf.lock);
+
+ end = bridge->send_buf.end;
+ pkt = &(bridge->send_buf.pkts[end]);
+
+ if(bridge->send_buf.num > BRIDGE_BUF_SIZE){
+ PrintDebug("VNET: bridge rx: buffer full\n");
+ goto exit;
+ }
+
+ bridge->send_buf.num ++;
+ bridge->send_buf.end ++;
+ bridge->send_buf.end %= BRIDGE_BUF_SIZE;
+
+ pkt->size = size;
+ pkt->src_id = src_link;
+ pkt->src_type = LINK_EDGE;
+ memcpy(pkt->header, buf, ETHERNET_HEADER_LEN);
+ memcpy(pkt->data, buf, size);
+
+exit:
+
+ v3_unlock_irqrestore(bridge->send_buf.lock, flags);
+
+ return 0;
+}
+
+
int v3_vnet_add_dev(struct v3_vm_info *vm, uint8_t mac[6],
int (*netif_input)(struct v3_vm_info * vm, struct v3_vnet_pkt * pkt, void * private_data),
void * priv_data){
}
+void v3_vnet_heartbeat(struct guest_info *core){
+ static long last_time, cur_time;
+
+ if(vnet_state.bridge == NULL)
+ return;
+
+ if(vnet_state.bridge->max_delayed_pkts <= 1)
+ return;
+
+ if(V3_Get_CPU() != vnet_state.bridge->vm->cores[0].cpu_id){
+ rdtscll(cur_time);
+ }
+
+ if ((cur_time - last_time) >= vnet_state.bridge->max_latency) {
+ last_time = cur_time;
+ flush_bridge_pkts(vnet_state.bridge);
+ }
+}
+
int v3_vnet_add_bridge(struct v3_vm_info * vm,
- int (*input)(struct v3_vm_info * vm, struct v3_vnet_pkt * pkt, void * private_data),
+ int (*input)(struct v3_vm_info * vm, struct v3_vnet_pkt pkt[], uint16_t pkt_num, void * private_data),
+ void (*xcall_input)(void *data),
+ uint16_t max_delayed_pkts,
+ long max_latency,
void * priv_data) {
unsigned long flags;
int bridge_free = 0;
struct vnet_brg_dev * tmp_bridge = NULL;
+ int i;
flags = v3_lock_irqsave(vnet_state.lock);
tmp_bridge->vm = vm;
tmp_bridge->input = input;
+ tmp_bridge->xcall_input = xcall_input;
tmp_bridge->private_data = priv_data;
+ tmp_bridge->disabled = 0;
+
+ //initial receving buffer
+ tmp_bridge->recv_buf.start = 0;
+ tmp_bridge->recv_buf.end = 0;
+ tmp_bridge->recv_buf.num = 0;
+ if(v3_lock_init(&(tmp_bridge->recv_buf.lock)) == -1){
+ PrintError("VNET: add bridge, error to initiate recv buf lock\n");
+ }
+ tmp_bridge->max_delayed_pkts = (max_delayed_pkts<BRIDGE_BUF_SIZE)?max_delayed_pkts : BRIDGE_BUF_SIZE;
+ tmp_bridge->max_latency = max_latency;
+ for(i = 0; i<BRIDGE_BUF_SIZE; i++){
+ tmp_bridge->recv_buf.pkts[i].data = &(tmp_bridge->recv_buf.datas[i*ETHERNET_PACKET_LEN]);
+ }
+ //initial sending buffer
+ tmp_bridge->send_buf.start = 0;
+ tmp_bridge->send_buf.end = 0;
+ tmp_bridge->send_buf.num = 0;
+ if(v3_lock_init(&(tmp_bridge->send_buf.lock)) == -1){
+ PrintError("VNET: add bridge, error to initiate send buf lock\n");
+ }
+ for(i = 0; i<BRIDGE_BUF_SIZE; i++){
+ tmp_bridge->send_buf.pkts[i].data = &(tmp_bridge->send_buf.datas[i*ETHERNET_PACKET_LEN]);
+ }
+
// make this atomic to avoid possible race conditions
flags = v3_lock_irqsave(vnet_state.lock);
vnet_state.bridge = tmp_bridge;
return 0;
}
+
+int v3_vnet_disable_bridge() {
+ unsigned long flags;
+
+ flags = v3_lock_irqsave(vnet_state.lock);
+
+ if (vnet_state.bridge != NULL) {
+ vnet_state.bridge->disabled = 1;
+ }
+
+ v3_unlock_irqrestore(vnet_state.lock, flags);
+
+ return 0;
+}
+
+
+int v3_vnet_enable_bridge() {
+ unsigned long flags;
+
+ flags = v3_lock_irqsave(vnet_state.lock);
+
+ if (vnet_state.bridge != NULL) {
+ vnet_state.bridge->disabled = 0;
+ }
+
+ v3_unlock_irqrestore(vnet_state.lock, flags);
+
+ return 0;
+}
+
+
+
int V3_init_vnet() {
INIT_LIST_HEAD(&(vnet_state.routes));
#endif
+#ifdef CONFIG_VNET
+#include <palacios/vmm_vnet.h>
+#endif
/* At this point the GPRs are already copied into the guest_info state */
int v3_handle_vmx_exit(struct guest_info * info, struct vmx_exit_info * exit_info) {
return -1;
}
+
+#ifdef CONFIG_VNET
+ v3_vnet_heartbeat(info);
+#endif
+
+
#ifdef CONFIG_TELEMETRY
if (info->vm_info->enable_telemetry) {
v3_telemetry_end_exit(info, exit_info->exit_reason);