Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


Add MAC address configure support on Virtio NIC
Lei Xia [Sun, 6 Feb 2011 06:51:39 +0000 (00:51 -0600)]
add MAC based packet demultiplexing in direct network bridge

palacios/include/palacios/vmm_dev_mgr.h
palacios/include/palacios/vmm_ethernet.h [new file with mode: 0644]
palacios/include/palacios/vmm_packet.h
palacios/include/palacios/vmm_vnet.h
palacios/src/devices/lnx_virtio_nic.c
palacios/src/devices/nic_bridge.c
palacios/src/devices/vnet_nic.c
palacios/src/palacios/vmm_packet.c

index f09c110..2e732cd 100644 (file)
@@ -27,6 +27,7 @@
 #include <palacios/vmm_string.h>
 #include <palacios/vmm_hashtable.h>
 #include <palacios/vmm_config.h>
+#include <palacios/vmm_ethernet.h>
 
 
 struct v3_vm_info;
@@ -175,6 +176,7 @@ struct v3_dev_net_ops {
 
     /* This is ugly... */
     void * frontend_data; 
+    char fnt_mac[ETH_ALEN];
 };
 
 struct v3_dev_console_ops {
diff --git a/palacios/include/palacios/vmm_ethernet.h b/palacios/include/palacios/vmm_ethernet.h
new file mode 100644 (file)
index 0000000..f7405fc
--- /dev/null
@@ -0,0 +1,73 @@
+/* 
+ * 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
+
+
index 8360adc..8fd7822 100644 (file)
 #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_register_mac(const char mac[6], struct v3_vm_info * vm);
+int V3_packet_register_mac(const char * mac, struct v3_vm_info * vm);
 
 #endif
 
index 040006d..86af1a2 100644 (file)
@@ -13,7 +13,7 @@
  * 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".
@@ -23,6 +23,7 @@
 #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
 
index ca56633..56bf74e 100644 (file)
@@ -29,6 +29,7 @@
 #include <palacios/vmm_lock.h>
 #include <palacios/vmm_util.h>
 #include <devices/pci.h>
+#include <palacios/vmm_ethernet.h>
 
 
 #ifndef CONFIG_DEBUG_VIRTIO_NET
@@ -39,6 +40,7 @@
 #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;
 
@@ -62,13 +64,20 @@ struct virtio_net_hdr_mrg_rxbuf {
 #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 */
@@ -79,6 +88,8 @@ struct virtio_dev_state {
     struct vm_device * pci_bus;
     struct list_head dev_list;
     struct v3_vm_info *vm;
+
+    char mac[ETH_ALEN];
 };
 
 struct virtio_net_state {
@@ -143,7 +154,7 @@ static int virtio_init_state(struct virtio_net_state * virtio)
 
     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)){
@@ -468,7 +479,7 @@ static int virtio_io_read(struct guest_info *core,
     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) {
@@ -534,6 +545,10 @@ static int virtio_io_read(struct guest_info *core,
            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;
@@ -772,14 +787,10 @@ static int register_dev(struct virtio_dev_state * virtio,
     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));
 
@@ -807,16 +818,45 @@ static int connect_fn(struct v3_vm_info * info,
     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");
@@ -830,6 +870,13 @@ static int virtio_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
     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) {
index e70d7a1..009633a 100644 (file)
@@ -111,6 +111,8 @@ static int nic_bridge_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
     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;
index 2a2ae6d..6a6406c 100644 (file)
@@ -26,6 +26,7 @@
 #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
@@ -34,7 +35,6 @@
 
 
 struct vnet_nic_state {
-    char mac[6];
     struct v3_vm_info * vm;
     struct v3_dev_net_ops net_ops;
     int vnet_dev_id;
@@ -102,14 +102,14 @@ static void virtio_poll(struct v3_vm_info * info,
 }
 
 
-/* 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;
 
@@ -137,35 +137,13 @@ static struct v3_vnet_dev_ops vnet_dev_ops = {
     .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));
@@ -180,7 +158,6 @@ static int vnet_nic_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
     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"), 
@@ -194,91 +171,14 @@ static int vnet_nic_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
     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;
 }
index 2d0814b..643fd1b 100644 (file)
@@ -32,7 +32,7 @@ int V3_send_raw(const char * pkt, uint32_t len) {
 }
 
 
-int V3_register_mac(const char mac[6], struct v3_vm_info * vm){
+int V3_register_mac(const char * mac, struct v3_vm_info * vm){
 
     return packet_hooks->register_mac(mac, vm);
 }