From: Peter Dinda Date: Wed, 18 Jul 2012 17:13:01 +0000 (-0500) Subject: VNET Hypercall interface, implemented as a new stub device X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?a=commitdiff_plain;h=5ed7ab7d688c249301404ced123d6d8ee1b0711a;p=palacios.releases.git VNET Hypercall interface, implemented as a new stub device --- diff --git a/palacios/include/palacios/vmm_hypercall.h b/palacios/include/palacios/vmm_hypercall.h index 575a9bb..e3c7c6f 100644 --- a/palacios/include/palacios/vmm_hypercall.h +++ b/palacios/include/palacios/vmm_hypercall.h @@ -53,6 +53,8 @@ typedef enum { OS_DEBUG_HCALL = 0xc0c0, // RBX: msg_gpa, RCX: msg_len, RDX: buf_is_va (flag) TIME_CPUFREQ_HCALL = 0xd000, //RBX: cpu freq (out) TIME_RDHTSC_HCALL = 0xd001, //RBX: cpu freq (out) + + VNET_HEADER_QUERY_HCALL = 0xe000, // Get the current header for a src/dest pair } hcall_id_t; diff --git a/palacios/include/vnet/vnet.h b/palacios/include/vnet/vnet.h index b123d59..ae12896 100644 --- a/palacios/include/vnet/vnet.h +++ b/palacios/include/vnet/vnet.h @@ -41,6 +41,37 @@ #define VNET_HASH_SIZE 17 +#define VNET_MAX_HEADER_LEN 128 + +/* + A VNET header is the data that needs to be + prefaced to an outgoing packet for a specific + MAC pair and qualifiers +*/ +struct v3_vnet_header { + // this header is for data that match + uint8_t src_mac[ETH_ALEN]; + uint8_t dst_mac[ETH_ALEN]; + + uint8_t src_mac_qual; + uint8_t dst_mac_qual; + +#define VNET_HEADER_NOMATCH 0 // Could not find a header +#define VNET_HEADER_NONE 1 // There is no header, send/receive without change +#define VNET_HEADER_RAW 2 // Prepend the following data on a send, remove this much data on a receive +#define VNET_HEADER_UDP 3 // Prepend this UDP header and then send this as a UDP packet / dual on receive +#define VNET_HEADER_TCP 4 // Prepend this TCP header and then send this as a TCP segment / dual on receive +#define VNET_HEADER_VXLAN 5 // Prepend this UDP header + VXLAN ID / dual on receive + + uint32_t header_type; + + uint32_t header_len; + uint8_t header_data[VNET_MAX_HEADER_LEN]; + + +} __attribute__((packed)); + + struct v3_vnet_route { uint8_t src_mac[ETH_ALEN]; uint8_t dst_mac[ETH_ALEN]; @@ -53,6 +84,7 @@ struct v3_vnet_route { int src_id; uint8_t src_type; + } __attribute__((packed)); @@ -132,6 +164,11 @@ int v3_vnet_add_dev(struct v3_vm_info * info, uint8_t * mac, void * priv_data); int v3_vnet_del_dev(int dev_id); +int v3_vnet_query_header(uint8_t src_mac[6], + uint8_t dest_mac[6], + int recv, + struct v3_vnet_header *header); + #endif diff --git a/palacios/src/devices/Kconfig b/palacios/src/devices/Kconfig index e9b2dc8..9748c1f 100644 --- a/palacios/src/devices/Kconfig +++ b/palacios/src/devices/Kconfig @@ -196,6 +196,7 @@ config DEBUG_LINUX_VIRTIO_VNET Enable debugging for the VNET Virtio interface + config VNET_NIC bool "Enable VNET Backend Device" default n @@ -210,6 +211,20 @@ config DEBUG_VNET_NIC help Enable debugging for the VNET NIC Device +config VNET_GUEST_IFACE + bool "Enable VNET guest hypercall interface" + default n + depends on VNET + help + Allows the guest to query for info, such as headers, from VNET + +config DEBUG_VNET_GUEST_IFACE + bool "VNET guest hypercall interface debugging" + default n + depends on VNET_GUEST_IFACE && DEBUG_ON + help + Enable debugging for the VNET guest hypercall interface + config NE2K bool "NE2K" diff --git a/palacios/src/devices/Makefile b/palacios/src/devices/Makefile index 1154059..61d00c5 100644 --- a/palacios/src/devices/Makefile +++ b/palacios/src/devices/Makefile @@ -47,3 +47,4 @@ obj-$(V3_CONFIG_VGA) += vga.o obj-$(V3_CONFIG_PCI_FRONT) += pci_front.o +obj-$(V3_CONFIG_VNET_GUEST_IFACE) += vnet_guest_iface.o diff --git a/palacios/src/vnet/vnet_core.c b/palacios/src/vnet/vnet_core.c index c2ebaf0..d9fe902 100644 --- a/palacios/src/vnet/vnet_core.c +++ b/palacios/src/vnet/vnet_core.c @@ -349,6 +349,9 @@ static void inline del_routes_by_dev(int dev_id){ vnet_unlock_irqrestore(vnet_state.lock, flags); } + + + /* At the end allocate a route_list * This list will be inserted into the cache so we don't need to free it */ @@ -483,6 +486,96 @@ static struct route_list * match_route(const struct v3_vnet_pkt * pkt) { return matches; } +int v3_vnet_query_header(uint8_t src_mac[6], + uint8_t dest_mac[6], + int recv, // 0 = send, 1=recv + struct v3_vnet_header *header) +{ + struct route_list *routes; + struct vnet_route_info *r; + struct v3_vnet_pkt p; + + p.size=14; + p.data=p.header; + memcpy(p.header,dest_mac,6); + memcpy(p.header+6,src_mac,6); + memset(p.header+12,0,2); + + p.src_type = LINK_EDGE; + p.src_id = 0; + + memcpy(header->src_mac,src_mac,6); + memcpy(header->dst_mac,dest_mac,6); + + + look_into_cache(&p,&routes); + + if (!routes) { + routes = match_route(&p); + if (!routes) { + PrintError("Cannot match route\n"); + header->header_type=VNET_HEADER_NOMATCH; + header->header_len=0; + return -1; + } else { + add_route_to_cache(&p,routes); + } + } + + if (routes->num_routes<1) { + PrintError("Less than one route\n"); + header->header_type=VNET_HEADER_NOMATCH; + header->header_len=0; + return -1; + } + + if (routes->num_routes>1) { + PrintError("More than one route, building header for the first one only\n"); + } + + r=routes->routes[0]; + + switch (r->route_def.dst_type) { + case LINK_EDGE: { + // switch based on the link type + // for mac-in-udp, we would want to generate a mac, ip, and udp header + // direct transmission + + // for now we will say we have no encapsulation + // + header->header_type=VNET_HEADER_NONE; + header->header_len=0; + header->src_mac_qual=r->route_def.src_mac_qual; + header->dst_mac_qual=r->route_def.dst_mac_qual; + + } + + return 0; + break; + + + case LINK_INTERFACE: + // direct transmission + // let's guess that it goes to the same interface... + header->header_type=VNET_HEADER_NONE; + header->header_len=0; + header->src_mac_qual=r->route_def.src_mac_qual; + header->dst_mac_qual=r->route_def.dst_mac_qual; + + return 0; + break; + + default: + PrintError("Unknown destination type\n"); + return -1; + break; + + } + +} + + + int v3_vnet_send_pkt(struct v3_vnet_pkt * pkt, void * private_data) { struct route_list * matched_routes = NULL;