From: Lei Xia Date: Sun, 6 Feb 2011 06:51:39 +0000 (-0600) Subject: Add MAC address configure support on Virtio NIC X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?p=palacios.git;a=commitdiff_plain;h=e49df33562b190c348b3a117044136c704442c6b Add MAC address configure support on Virtio NIC add MAC based packet demultiplexing in direct network bridge --- diff --git a/palacios/include/palacios/vmm_dev_mgr.h b/palacios/include/palacios/vmm_dev_mgr.h index f09c110..2e732cd 100644 --- a/palacios/include/palacios/vmm_dev_mgr.h +++ b/palacios/include/palacios/vmm_dev_mgr.h @@ -27,6 +27,7 @@ #include #include #include +#include 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 index 0000000..f7405fc --- /dev/null +++ b/palacios/include/palacios/vmm_ethernet.h @@ -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 + * Copyright (c) 2011, The V3VEE Project + * All rights reserved. + * + * Author: Lei Xia + * + * 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 + +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 + + diff --git a/palacios/include/palacios/vmm_packet.h b/palacios/include/palacios/vmm_packet.h index 8360adc..8fd7822 100644 --- a/palacios/include/palacios/vmm_packet.h +++ b/palacios/include/palacios/vmm_packet.h @@ -22,11 +22,12 @@ #define __VMM_PACKET_H__ #include +#include #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 diff --git a/palacios/include/palacios/vmm_vnet.h b/palacios/include/palacios/vmm_vnet.h index 040006d..86af1a2 100644 --- a/palacios/include/palacios/vmm_vnet.h +++ b/palacios/include/palacios/vmm_vnet.h @@ -13,7 +13,7 @@ * All rights reserved. * * Author: Lei Xia - * Yuan Tang + * Yuan Tang * * 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 +#include #define MAC_ANY 0 #define MAC_NOT 1 @@ -34,10 +35,6 @@ #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 diff --git a/palacios/src/devices/lnx_virtio_nic.c b/palacios/src/devices/lnx_virtio_nic.c index ca56633..56bf74e 100644 --- a/palacios/src/devices/lnx_virtio_nic.c +++ b/palacios/src/devices/lnx_virtio_nic.c @@ -29,6 +29,7 @@ #include #include #include +#include #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) { diff --git a/palacios/src/devices/nic_bridge.c b/palacios/src/devices/nic_bridge.c index e70d7a1..009633a 100644 --- a/palacios/src/devices/nic_bridge.c +++ b/palacios/src/devices/nic_bridge.c @@ -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; diff --git a/palacios/src/devices/vnet_nic.c b/palacios/src/devices/vnet_nic.c index 2a2ae6d..6a6406c 100644 --- a/palacios/src/devices/vnet_nic.c +++ b/palacios/src/devices/vnet_nic.c @@ -26,6 +26,7 @@ #include #include #include +#include #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; } diff --git a/palacios/src/palacios/vmm_packet.c b/palacios/src/palacios/vmm_packet.c index 2d0814b..643fd1b 100644 --- a/palacios/src/palacios/vmm_packet.c +++ b/palacios/src/palacios/vmm_packet.c @@ -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); }