#include <palacios/vmm_hashtable.h>
#include <palacios/vmm_msr.h>
#include <palacios/vmm_config.h>
+#include <palacios/vmm_ethernet.h>
struct v3_vm_info;
/* This is ugly... */
void * frontend_data;
+ char fnt_mac[ETH_ALEN];
};
struct v3_dev_console_ops {
--- /dev/null
+/*
+ * This file is part of the Palacios Virtual Machine Monitor developed
+ * by the V3VEE Project with funding from the United States National
+ * Science Foundation and the Department of Energy.
+ *
+ * The V3VEE Project is a joint project between Northwestern University
+ * and the University of New Mexico. You can find out more at
+ * http://www.v3vee.org
+ *
+ * Copyright (c) 2011, Lei Xia <lxia@northwestern.edu>
+ * Copyright (c) 2011, The V3VEE Project <http://www.v3vee.org>
+ * All rights reserved.
+ *
+ * Author: Lei Xia <lxia@northwestern.edu>
+ *
+ * This is free software. You are permitted to use,
+ * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
+ */
+
+#ifndef __ETHERNET_H__
+#define __ETHERNET_H__
+
+#define ETHERNET_HEADER_LEN 14
+#define ETHERNET_MTU 1500
+#define ETHERNET_PACKET_LEN (ETHERNET_HEADER_LEN + ETHERNET_MTU)
+#define ETH_ALEN 6
+
+
+#ifdef __V3VEE__
+
+#include <palacios/vmm.h>
+
+static inline int is_multicast_ethaddr(const uint8_t * addr)
+{
+ V3_ASSERT(ETH_ALEN == 6);
+
+ return (0x01 & addr[0]);
+}
+
+static inline int is_broadcast_ethaddr(const uint8_t * addr)
+{
+ V3_ASSERT(ETH_ALEN == 6);
+
+ return (addr[0] & addr[1] & addr[2] & addr[3] & addr[4] & addr[5]) == 0xff;
+}
+
+
+static inline int compare_ethaddr(const uint8_t * addr1, const uint8_t * addr2)
+{
+ const uint16_t *a = (const uint16_t *) addr1;
+ const uint16_t *b = (const uint16_t *) addr2;
+
+ V3_ASSERT(ETH_ALEN == 6);
+ return ((a[0] ^ b[0]) | (a[1] ^ b[1]) | (a[2] ^ b[2])) != 0;
+}
+
+
+static inline int compare_ether_hdr(const uint8_t * hdr1, const uint8_t * hdr2)
+{
+ uint32_t *a32 = (uint32_t *)(hdr1 + 2);
+ uint32_t *b32 = (uint32_t *)(hdr2 + 2);
+
+ V3_ASSERT(ETHERNET_HEADER_LEN == 14);
+
+ return (*(uint16_t *)hdr1 ^ *(uint16_t *)hdr2) | (a32[0] ^ b32[0]) |
+ (a32[1] ^ b32[1]) | (a32[2] ^ b32[2]);
+}
+
+#endif
+
+#endif
+
+
#define __VMM_PACKET_H__
#include <palacios/vmm.h>
+#include <palacios/vmm_ethernet.h>
#ifdef __V3VEE__
int V3_send_raw(const char * pkt, uint32_t len);
+int V3_packet_register_mac(const char * mac, struct v3_vm_info * vm);
#endif
struct v3_packet_hooks {
int (*send)(const char * pkt, unsigned int size, void * private_data);
-
+ int (*register_mac)(const char * mac, struct v3_vm_info * vm);
};
extern void V3_Init_Packet(struct v3_packet_hooks * hooks);
* All rights reserved.
*
* Author: Lei Xia <lxia@northwestern.edu>
- * Yuan Tang <ytang@northwestern.edu>
+ * Yuan Tang <ytang@northwestern.edu>
*
* This is free software. You are permitted to use,
* redistribute, and modify it as specified in the file "V3VEE_LICENSE".
#define __VNET_H__
#include <palacios/vmm.h>
+#include <palacios/vmm_ethernet.h>
#define MAC_ANY 0
#define MAC_NOT 1
#define LINK_ANY 2
#define VNET_HASH_SIZE 17
-#define ETHERNET_HEADER_LEN 14
-#define ETHERNET_MTU 1500
-#define ETHERNET_PACKET_LEN (ETHERNET_HEADER_LEN + ETHERNET_MTU)
-
#define VMM_DRIVERN 1
#define GUEST_DRIVERN 0
#include <palacios/vmm_lock.h>
#include <palacios/vmm_util.h>
#include <devices/pci.h>
+#include <palacios/vmm_ethernet.h>
#ifndef CONFIG_DEBUG_VIRTIO_NET
#define VIRTIO_NET_S_LINK_UP 1 /* Link is up */
#define VIRTIO_NET_MAX_BUFSIZE (sizeof(struct virtio_net_hdr) + (64 << 10))
+
struct virtio_net_hdr {
uint8_t flags;
#define TX_QUEUE_SIZE 64
#define RX_QUEUE_SIZE 1024
#define CTRL_QUEUE_SIZE 64
-#define ETH_ALEN 6
#define VIRTIO_NET_F_MRG_RXBUF 15 /* Host can merge receive buffers. */
#define VIRTIO_NET_F_MAC 5 /* Host has given MAC address. */
#define VIRTIO_NET_F_GSO 6 /* Host handles pkts w/ any GSO type */
#define VIRTIO_NET_F_HOST_TSO4 11 /* Host can handle TSOv4 in. */
+/* this is not how virtio supposed to be,
+ * we may need a separately implemented virtio_pci
+ * In order to make guest to get virtio MAC from host
+ * I added it here -- Lei
+ */
+ #define VIRTIO_NET_CONFIG 20
+
+
struct virtio_net_config
{
uint8_t mac[ETH_ALEN]; /* VIRTIO_NET_F_MAC */
struct vm_device * pci_bus;
struct list_head dev_list;
struct v3_vm_info *vm;
+
+ char mac[ETH_ALEN];
};
struct virtio_net_state {
virtio->virtio_cfg.pci_isr = 0;
- virtio->virtio_cfg.host_features = 0; // (1 << VIRTIO_NET_F_MAC);
+ virtio->virtio_cfg.host_features = 0 | (1 << VIRTIO_NET_F_MAC);
if ((v3_lock_init(&(virtio->rx_lock)) == -1) ||
(v3_lock_init(&(virtio->tx_lock)) == -1)){
int port_idx = port % virtio->io_range_size;
uint16_t queue_idx = virtio->virtio_cfg.vring_queue_selector;
- PrintDebug("Virtio NIC %p: Read for port %d (index =%d), length=%d\n", private_data,
+ PrintDebug("Virtio NIC %p: Read for port 0x%x (index =%d), length=%d\n", private_data,
port, port_idx, length);
switch (port_idx) {
v3_pci_lower_irq(virtio->virtio_dev->pci_bus, 0, virtio->pci_dev);
break;
+ case VIRTIO_NET_CONFIG ... VIRTIO_NET_CONFIG + ETH_ALEN:
+ *(uint8_t *)dst = virtio->net_cfg.mac[port_idx-VIRTIO_NET_CONFIG];
+ break;
+
default:
PrintError("Virtio NIC: Read of Unhandled Virtio Read:%d\n", port_idx);
return -1;
net_state->pci_dev = pci_dev;
net_state->virtio_dev = virtio;
- uchar_t mac[6] = {0x11,0x11,0x11,0x11,0x11,0x11};
- memcpy(net_state->net_cfg.mac, mac, 6);
-
- memcpy(pci_dev->config_data, net_state->net_cfg.mac, ETH_ALEN);
-
+ memcpy(net_state->net_cfg.mac, virtio->mac, 6);
+
virtio_init_state(net_state);
-
/* Add backend to list of devices */
list_add(&(net_state->dev_link), &(virtio->dev_list));
ops->start_tx = virtio_start_tx;
ops->stop_tx = virtio_stop_tx;
ops->frontend_data = net_state;
+ memcpy(ops->fnt_mac, virtio->mac, ETH_ALEN);
return 0;
}
+
+static int str2mac(char * macstr, char * mac){
+ char hex[2], *s = macstr;
+ int i = 0;
+
+ while(s){
+ memcpy(hex, s, 2);
+ mac[i++] = (char)atox(hex);
+ if (i == ETH_ALEN) return 0;
+ s=strchr(s, ':');
+ if(s) s++;
+ }
+
+ return -1;
+}
+
+static inline void random_ethaddr(uchar_t * addr)
+{
+ uint64_t val;
+
+ /* using current rdtsc as random number */
+ rdtscll(val);
+ *(uint64_t *)addr = val;
+
+ addr [0] &= 0xfe; /* clear multicast bit */
+ addr [0] |= 0x02; /* set local assignment bit (IEEE802) */
+}
+
+
static int virtio_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_dev_state * virtio_state = NULL;
char * dev_id = v3_cfg_val(cfg, "ID");
-
- PrintDebug("Virtio NIC: Initializing VIRTIO Network device: %s\n", dev_id);
+ char * macstr = v3_cfg_val(cfg, "mac");
if (pci_bus == NULL) {
PrintError("Virtio NIC: VirtIO devices require a PCI Bus");
virtio_state->pci_bus = pci_bus;
virtio_state->vm = vm;
+ if (macstr != NULL && !str2mac(macstr, virtio_state->mac)) {
+ PrintDebug("Virtio NIC: Mac specified %s\n", macstr);
+ }else {
+ PrintDebug("Virtio NIC: MAC not specified\n");
+ random_ethaddr(virtio_state->mac);
+ }
+
struct vm_device * dev = v3_add_device(vm, dev_id, &dev_ops, virtio_state);
if (dev == NULL) {
PrintDebug("NIC-Bridge: Connect %s to frontend %s\n",
dev_id, v3_cfg_val(frontend_cfg, "tag"));
+
+ V3_packet_register_mac(bridge->net_ops.fnt_mac, vm);
v3_hook_host_event(vm, HOST_PACKET_EVT, V3_HOST_EVENT_HANDLER(packet_input), bridge);
return 0;
#include <palacios/vm_guest_mem.h>
#include <devices/pci.h>
#include <palacios/vmm_sprintf.h>
+#include <palacios/vmm_ethernet.h>
#ifndef CONFIG_DEBUG_VNET_NIC
#undef PrintDebug
struct vnet_nic_state {
- char mac[6];
struct v3_vm_info * vm;
struct v3_dev_net_ops net_ops;
int vnet_dev_id;
}
-/* tell the frontend to start sending pkt to VNET*/
+/* notify the frontend to start sending pkt to VNET*/
static void start_tx(void * private_data){
struct vnet_nic_state *vnetnic = (struct vnet_nic_state *)private_data;
vnetnic->net_ops.start_tx(vnetnic->net_ops.frontend_data);
}
-/* tell the frontend device to stop sending pkt to VNET*/
+/* notify the frontend device to stop sending pkt to VNET*/
static void stop_tx(void * private_data){
struct vnet_nic_state *vnetnic = (struct vnet_nic_state *)private_data;
.stop_tx = stop_tx,
};
-static int str2mac(char * macstr, char mac[6]){
- char hex[2], *s = macstr;
- int i = 0;
-
- while(s){
- memcpy(hex, s, 2);
- mac[i++] = (char)atox(hex);
- if (i == 6) return 0;
- s=strchr(s, ':');
- if(s) s++;
- }
-
- return -1;
-}
static int vnet_nic_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
struct vnet_nic_state * vnetnic = NULL;
char * dev_id = v3_cfg_val(cfg, "ID");
- char * macstr = NULL;
- char mac[6];
int vnet_dev_id;
v3_cfg_tree_t * frontend_cfg = v3_cfg_subtree(cfg, "frontend");
- macstr = v3_cfg_val(frontend_cfg, "mac");
-
- if (macstr != NULL) {
- PrintDebug("Vnet-nic: Mac specified %s\n", macstr);
- str2mac(macstr, mac);
- }
vnetnic = (struct vnet_nic_state *)V3_Malloc(sizeof(struct vnet_nic_state));
memset(vnetnic, 0, sizeof(struct vnet_nic_state));
vnetnic->net_ops.send = vnet_nic_send;
vnetnic->net_ops.start_rx = start_rx;
vnetnic->net_ops.stop_rx = stop_rx;
- memcpy(vnetnic->mac, mac, 6);
vnetnic->vm = vm;
if (v3_dev_connect_net(vm, v3_cfg_val(frontend_cfg, "tag"),
PrintDebug("Vnet-nic: Connect %s to frontend %s\n",
dev_id, v3_cfg_val(frontend_cfg, "tag"));
- if ((vnet_dev_id = v3_vnet_add_dev(vm, vnetnic->mac, &vnet_dev_ops, (void *)vnetnic)) == -1) {
- PrintError("Vnet-nic device %s (mac: %s) fails to registered to VNET\n", dev_id, macstr);
+ if ((vnet_dev_id = v3_vnet_add_dev(vm, vnetnic->net_ops.fnt_mac, &vnet_dev_ops, (void *)vnetnic)) == -1) {
+ PrintError("Vnet-nic device %s fails to registered to VNET\n", dev_id);
v3_remove_device(dev);
return 0;
}
vnetnic->vnet_dev_id = vnet_dev_id;
- PrintDebug("Vnet-nic device %s (mac: %s, %ld) registered to VNET\n",
- dev_id, macstr, *((ulong_t *)vnetnic->mac));
-
-
-//for temporary hack for vnet bridge test
-#if 0
- {
- uchar_t zeromac[6] = {0,0,0,0,0,0};
-
- if(!strcmp(dev_id, "vnet_nic")){
- struct v3_vnet_route route;
-
- route.dst_id = vnet_dev_id;
- route.dst_type = LINK_INTERFACE;
- route.src_id = 0;
- route.src_type = LINK_EDGE;
- memcpy(route.dst_mac, zeromac, 6);
- route.dst_mac_qual = MAC_ANY;
- memcpy(route.src_mac, zeromac, 6);
- route.src_mac_qual = MAC_ANY;
- v3_vnet_add_route(route);
-
-
- route.dst_id = 0;
- route.dst_type = LINK_EDGE;
- route.src_id = vnet_dev_id;
- route.src_type = LINK_INTERFACE;
- memcpy(route.dst_mac, zeromac, 6);
- route.dst_mac_qual = MAC_ANY;
- memcpy(route.src_mac, zeromac, 6);
- route.src_mac_qual = MAC_ANY;
-
- v3_vnet_add_route(route);
- }
- }
-#endif
-
-//for temporary hack for Linux bridge (w/o encapuslation) test
-#if 0
- {
- static int vnet_nic_guestid = -1;
- static int vnet_nic_dom0 = -1;
- uchar_t zeromac[6] = {0,0,0,0,0,0};
-
- if(!strcmp(dev_id, "vnet_nic")){ //domu
- vnet_nic_guestid = vnet_dev_id;
- }
- if (!strcmp(dev_id, "vnet_nic_dom0")){
- vnet_nic_dom0 = vnet_dev_id;
- }
-
- if(vnet_nic_guestid != -1 && vnet_nic_dom0 !=-1){
- struct v3_vnet_route route;
-
- route.src_id = vnet_nic_guestid;
- route.src_type = LINK_INTERFACE;
- route.dst_id = vnet_nic_dom0;
- route.dst_type = LINK_INTERFACE;
- memcpy(route.dst_mac, zeromac, 6);
- route.dst_mac_qual = MAC_ANY;
- memcpy(route.src_mac, zeromac, 6);
- route.src_mac_qual = MAC_ANY;
- v3_vnet_add_route(route);
-
-
- route.src_id = vnet_nic_dom0;
- route.src_type = LINK_INTERFACE;
- route.dst_id = vnet_nic_guestid;
- route.dst_type = LINK_INTERFACE;
- memcpy(route.dst_mac, zeromac, 6);
- route.dst_mac_qual = MAC_ANY;
- memcpy(route.src_mac, zeromac, 6);
- route.src_mac_qual = MAC_ANY;
-
- v3_vnet_add_route(route);
- }
- }
-#endif
+ PrintDebug("Vnet-nic device %s registered to VNET\n", dev_id);
return 0;
}
}
+int V3_register_mac(const char * mac, struct v3_vm_info * vm){
+
+ return packet_hooks->register_mac(mac, vm);
+}
+
void V3_Init_Packet(struct v3_packet_hooks * hooks) {
packet_hooks = hooks;
PrintDebug("V3 raw packet interface inited\n");