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.


Minimize the copies for vnet and Virtio bridge
[palacios.git] / palacios / src / devices / vnet_nic.c
1 /* 
2  * This file is part of the Palacios Virtual Machine Monitor developed
3  * by the V3VEE Project with funding from the United States National 
4  * Science Foundation and the Department of Energy.  
5  *
6  * The V3VEE Project is a joint project between Northwestern University
7  * and the University of New Mexico.  You can find out more at 
8  * http://www.v3vee.org
9  *
10  * Copyright (c) 2008, Lei Xia <lxia@northwestern.edu>
11  * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org> 
12  * All rights reserved.
13  *
14  * Author: Lei Xia <lxia@northwestern.edu>
15  *               
16  *
17  * This is free software.  You are permitted to use,
18  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
19  */
20 //backend device for Virtio NIC
21
22 #include <palacios/vmm_vnet.h>
23 #include <palacios/vmm.h>
24 #include <palacios/vmm_dev_mgr.h>
25 #include <devices/lnx_virtio_pci.h>
26 #include <palacios/vm_guest_mem.h>
27 #include <devices/pci.h>
28 #include <palacios/vmm_sprintf.h>
29
30 #ifndef CONFIG_DEBUG_VNET_NIC
31 #undef PrintDebug
32 #define PrintDebug(fmt, args...)
33 #endif
34
35
36 struct vnet_nic_state {
37     char mac[6];
38     struct v3_vm_info * vm;
39     struct v3_dev_net_ops net_ops;
40     int vnet_dev_id;
41 };
42
43
44 static int vnet_send(uint8_t * buf, uint32_t len, void * private_data, struct vm_device *dest_dev){
45     struct v3_vnet_pkt pkt;
46     struct vnet_nic_state *vnetnic = (struct vnet_nic_state *)private_data;
47
48
49     pkt.size = len;
50     pkt.src_type = LINK_INTERFACE;
51     pkt.src_id = vnetnic->vnet_dev_id;
52     memcpy(pkt.header, buf, ETHERNET_HEADER_LEN);
53     pkt.data = buf;
54
55 #ifdef CONFIG_DEBUG_VNET_NIC
56     {
57         PrintDebug("Virtio VNET-NIC: send pkt size: %d, pkt src_id: %d, src_type: %d\n", 
58                         len, pkt.src_id, pkt.src_type);
59         v3_hexdump(buf, len, NULL, 0);
60     }
61 #endif
62
63
64     v3_vnet_send_pkt(&pkt, NULL);
65
66     return 0;
67 }
68
69 static int virtio_input(struct v3_vm_info *info, struct v3_vnet_pkt * pkt, void * private_data){
70     struct vnet_nic_state *vnetnic = (struct vnet_nic_state *)private_data;
71         
72     PrintDebug("Vnet-nic: In input: vnet_nic state %p\n", vnetnic);     
73
74     return vnetnic->net_ops.recv(pkt->data, pkt->size, vnetnic->net_ops.frontend_data);
75 }
76
77 static int register_to_vnet(struct v3_vm_info * vm,
78                      struct vnet_nic_state *vnet_nic,
79                      char *dev_name,
80                      uchar_t mac[6]) { 
81    
82     PrintDebug("Vnet-nic: register Vnet-nic device %s, state %p to VNET\n", dev_name, vnet_nic);
83         
84     return v3_vnet_add_dev(vm, mac, virtio_input, (void *)vnet_nic);
85 }
86
87 static int vnet_nic_free(struct vm_device * dev) {
88     return 0;
89 }
90
91 static struct v3_device_ops dev_ops = {
92     .free = vnet_nic_free,
93     .reset = NULL,
94     .start = NULL,
95     .stop = NULL,
96 };
97
98
99 static int str2mac(char *macstr, char mac[6]){
100     char hex[2], *s = macstr;
101     int i = 0;
102
103     while(s){
104         memcpy(hex, s, 2);
105         mac[i++] = (char)atox(hex);
106         if (i == 6) return 0;
107         s=strchr(s, ':');
108         if(s) s++;
109     }
110
111     return -1;
112 }
113
114 static int vnet_nic_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
115     struct vnet_nic_state * vnetnic = NULL;
116     char * name = v3_cfg_val(cfg, "name");
117     char * macstr = NULL;
118     char mac[6];
119     int vnet_dev_id;
120
121     v3_cfg_tree_t * frontend_cfg = v3_cfg_subtree(cfg, "frontend");
122     macstr = v3_cfg_val(frontend_cfg, "mac");
123
124     if (macstr == NULL) {
125         PrintDebug("Vnet-nic: No Mac specified\n");
126     } else {
127         str2mac(macstr, mac);
128     }
129
130     vnetnic = (struct vnet_nic_state *)V3_Malloc(sizeof(struct vnet_nic_state));
131     memset(vnetnic, 0, sizeof(struct vnet_nic_state));
132
133     struct vm_device * dev = v3_allocate_device(name, &dev_ops, vnetnic);
134
135     if (v3_attach_device(vm, dev) == -1) {
136         PrintError("Could not attach device %s\n", name);
137         return -1;
138     }
139
140     vnetnic->net_ops.send = vnet_send;
141     memcpy(vnetnic->mac, mac, 6);
142     vnetnic->vm = vm;
143         
144     if (v3_dev_connect_net(vm, v3_cfg_val(frontend_cfg, "tag"), 
145                            &(vnetnic->net_ops), frontend_cfg, vnetnic) == -1) {
146         PrintError("Could not connect %s to frontend %s\n", 
147                    name, v3_cfg_val(frontend_cfg, "tag"));
148         return -1;
149     }
150
151     PrintDebug("Vnet-nic: Connect %s to frontend %s\n", 
152                    name, v3_cfg_val(frontend_cfg, "tag"));
153
154     if ((vnet_dev_id = register_to_vnet(vm, vnetnic, name, vnetnic->mac)) == -1) {
155         PrintError("Vnet-nic device %s (mac: %s) fails to registered to VNET\n", name, macstr);
156     }
157     vnetnic->vnet_dev_id = vnet_dev_id;
158
159     PrintDebug("Vnet-nic device %s (mac: %s, %ld) registered to VNET\n", name, macstr, *((ulong_t *)vnetnic->mac));
160
161
162 //for temporary hack for vnet bridge test
163 #if 1
164     {
165         uchar_t zeromac[6] = {0,0,0,0,0,0};
166                 
167         if(!strcmp(name, "vnet_nic")){
168             struct v3_vnet_route route;
169                 
170             route.dst_id = vnet_dev_id;
171             route.dst_type = LINK_INTERFACE;
172             route.src_id = 0;
173             route.src_type = LINK_EDGE;
174             memcpy(route.dst_mac, zeromac, 6);
175             route.dst_mac_qual = MAC_ANY;
176             memcpy(route.src_mac, zeromac, 6);
177             route.src_mac_qual = MAC_ANY;  
178             v3_vnet_add_route(route);
179
180
181             route.dst_id = 0;
182             route.dst_type = LINK_EDGE;
183             route.src_id = vnet_dev_id;
184             route.src_type = LINK_INTERFACE;
185             memcpy(route.dst_mac, zeromac, 6);
186             route.dst_mac_qual = MAC_ANY;
187             memcpy(route.src_mac, zeromac, 6);
188             route.src_mac_qual = MAC_ANY;
189
190             v3_vnet_add_route(route);
191         }
192     }
193 #endif
194
195     return 0;
196 }
197
198 device_register("VNET_NIC", vnet_nic_init)