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.


Merge branch 'devel' of ssh://palacios@newskysaw.cs.northwestern.edu/home/palacios...
[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 #if 0
44 //Malloc/Free version of send
45 static int vnet_send(uint8_t * buf, uint32_t len, void * private_data, struct vm_device *dest_dev){
46     struct v3_vnet_pkt * pkt = NULL;
47     struct guest_info *core  = (struct guest_info *)private_data; 
48
49 #ifdef WCONFIG_DEBUG_VNET_NIC
50     {
51         PrintDebug("Virtio VNET-NIC: send pkt size: %d\n", len);
52         v3_hexdump(buf, len, NULL, 0);
53     }
54 #endif
55
56 #ifdef CONFIG_VNET_PROFILE
57     uint64_t start, end;
58     rdtscll(start);
59 #endif
60
61     pkt = (struct v3_vnet_pkt *)V3_Malloc(sizeof(struct v3_vnet_pkt));
62
63     if(pkt == NULL){
64         PrintError("Malloc() fails");
65         return -1;
66     }
67         
68 #ifdef CONFIG_VNET_PROFILE
69     {
70         rdtscll(end);
71         core->vnet_times.time_mallocfree = end - start;
72     }
73 #endif
74
75
76     pkt->size = len;
77     pkt->src_type = LINK_INTERFACE;
78     pkt->src_id = 0;
79     memcpy(pkt->data, buf, pkt->size);
80
81 #ifdef CONFIG_VNET_PROFILE
82     {
83         rdtscll(start);
84         core->vnet_times.memcpy_time = start - end;
85         core->vnet_times.time_copy_from_guest = start - core->vnet_times.virtio_handle_start - core->vnet_times.time_mallocfree;
86     }
87 #endif
88
89     v3_vnet_send_pkt(pkt, (void *)core);
90
91 #ifdef CONFIG_VNET_PROFILE
92     rdtscll(start);
93 #endif
94
95     V3_Free(pkt);
96
97 #ifdef CONFIG_VNET_PROFILE
98     {
99         rdtscll(end);
100         core->vnet_times.time_mallocfree += end - start;
101     }
102 #endif
103
104     return 0;
105 }
106
107 #endif
108
109 #if 1
110 //alternative way, no malloc/free
111 static int vnet_send(uint8_t * buf, uint32_t len, void * private_data, struct vm_device *dest_dev){
112     struct v3_vnet_pkt pkt;
113     struct vnet_nic_state *vnetnic = (struct vnet_nic_state *)private_data;
114     struct guest_info *core  = &(vnetnic->vm->cores[0]); 
115
116 #ifdef CONFIG_VNET_PROFILE
117     uint64_t start, end;
118     rdtscll(start);
119 #endif
120
121     pkt.size = len;
122     pkt.src_type = LINK_INTERFACE;
123     pkt.src_id = vnetnic->vnet_dev_id;
124     memcpy(pkt.data, buf, pkt.size);
125
126 #ifdef CONFIG_DEBUG_VNET_NIC
127     {
128         PrintDebug("Virtio VNET-NIC: send pkt size: %d, pkt src_id: %d, src_type: %d\n", 
129                         len, pkt.src_id, pkt.src_type);
130         v3_hexdump(buf, len, NULL, 0);
131     }
132 #endif
133
134
135 #ifdef CONFIG_VNET_PROFILE
136     rdtscll(end);
137     core->vnet_times.time_copy_from_guest = end - core->vnet_times.virtio_handle_start;
138     core->vnet_times.memcpy_time = end - start;
139 #endif
140
141     v3_vnet_send_pkt(&pkt, (void *)core);
142
143     return 0;
144 }
145 #endif
146
147 #if 0
148 //alternative way, no malloc/free, no copy
149 //need to change pkt format
150 static int vnet_send(uint8_t * buf, uint32_t len, void * private_data, struct vm_device *dest_dev){
151     struct v3_vnet_pkt pkt;
152     struct guest_info *core  = (struct guest_info *)private_data; 
153
154     
155 #ifdef CONFIG_DEBUG_VNET_NIC
156     {
157         PrintDebug("Virtio VNET-NIC: send pkt size: %d\n", len);
158         v3_hexdump(buf, len, NULL, 0);
159     }
160 #endif
161
162     pkt.size = len;
163     pkt.data = buf;
164
165 #ifdef CONFIG_VNET_PROFILE
166     uint64_t start, end;
167     rdtscll(start);
168 #endif
169
170     v3_vnet_send_pkt(&pkt, (void *)core);
171
172 #ifdef CONFIG_VNET_PROFILE
173     {
174         rdtscll(end);
175         core->vnet_times.vnet_handle_time = end - start;
176     }
177 #endif
178
179     return 0;
180 }
181
182 #endif
183
184 static int virtio_input(struct v3_vm_info *info, struct v3_vnet_pkt * pkt, void * private_data){
185     struct vnet_nic_state *vnetnic = (struct vnet_nic_state *)private_data;
186         
187     PrintDebug("Vnet-nic: In input: vnet_nic state %p\n", vnetnic);     
188
189     return vnetnic->net_ops.recv(pkt->data, pkt->size, vnetnic->net_ops.frontend_data);
190 }
191
192 static int register_to_vnet(struct v3_vm_info * vm,
193                      struct vnet_nic_state *vnet_nic,
194                      char *dev_name,
195                      uchar_t mac[6]) { 
196    
197     PrintDebug("Vnet-nic: register Vnet-nic device %s, state %p to VNET\n", dev_name, vnet_nic);
198         
199     return v3_vnet_add_dev(vm, mac, virtio_input, (void *)vnet_nic);
200 }
201
202 static int vnet_nic_free(struct vm_device * dev) {
203     return 0;
204 }
205
206 static struct v3_device_ops dev_ops = {
207     .free = vnet_nic_free,
208     .reset = NULL,
209     .start = NULL,
210     .stop = NULL,
211 };
212
213
214 static int str2mac(char *macstr, char mac[6]){
215     char hex[2], *s = macstr;
216     int i = 0;
217
218     while(s){
219         memcpy(hex, s, 2);
220         mac[i++] = (char)atox(hex);
221         if (i == 6) return 0;
222         s=strchr(s, ':');
223         if(s) s++;
224     }
225
226     return -1;
227 }
228
229 static int vnet_nic_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
230     struct vnet_nic_state * vnetnic = NULL;
231     char * name = v3_cfg_val(cfg, "name");
232     char * macstr = NULL;
233     char mac[6];
234     int vnet_dev_id;
235
236     v3_cfg_tree_t * frontend_cfg = v3_cfg_subtree(cfg, "frontend");
237     macstr = v3_cfg_val(frontend_cfg, "mac");
238
239     if (macstr == NULL) {
240         PrintDebug("Vnet-nic: No Mac specified\n");
241     } else {
242         str2mac(macstr, mac);
243     }
244
245     vnetnic = (struct vnet_nic_state *)V3_Malloc(sizeof(struct vnet_nic_state));
246     memset(vnetnic, 0, sizeof(struct vnet_nic_state));
247
248     struct vm_device * dev = v3_allocate_device(name, &dev_ops, vnetnic);
249
250     if (v3_attach_device(vm, dev) == -1) {
251         PrintError("Could not attach device %s\n", name);
252         return -1;
253     }
254
255     vnetnic->net_ops.send = vnet_send;
256     memcpy(vnetnic->mac, mac, 6);
257     vnetnic->vm = vm;
258         
259     if (v3_dev_connect_net(vm, v3_cfg_val(frontend_cfg, "tag"), 
260                            &(vnetnic->net_ops), frontend_cfg, vnetnic) == -1) {
261         PrintError("Could not connect %s to frontend %s\n", 
262                    name, v3_cfg_val(frontend_cfg, "tag"));
263         return -1;
264     }
265
266     PrintDebug("Vnet-nic: Connect %s to frontend %s\n", 
267                    name, v3_cfg_val(frontend_cfg, "tag"));
268
269     if ((vnet_dev_id = register_to_vnet(vm, vnetnic, name, vnetnic->mac)) == -1) {
270         PrintError("Vnet-nic device %s (mac: %s) fails to registered to VNET\n", name, macstr);
271     }
272     vnetnic->vnet_dev_id = vnet_dev_id;
273
274     PrintDebug("Vnet-nic device %s (mac: %s, %ld) registered to VNET\n", name, macstr, *((ulong_t *)vnetnic->mac));
275
276
277 //for temporary hack for vnet bridge test
278 #if 1
279     {
280         uchar_t zeromac[6] = {0,0,0,0,0,0};
281                 
282         if(!strcmp(name, "vnet_nic")){
283             struct v3_vnet_route route;
284                 
285             route.dst_id = vnet_dev_id;
286             route.dst_type = LINK_INTERFACE;
287             route.src_id = 0;
288             route.src_type = LINK_EDGE;
289             memcpy(route.dst_mac, zeromac, 6);
290             route.dst_mac_qual = MAC_ANY;
291             memcpy(route.src_mac, zeromac, 6);
292             route.src_mac_qual = MAC_ANY;  
293             v3_vnet_add_route(route);
294
295
296             route.dst_id = 0;
297             route.dst_type = LINK_EDGE;
298             route.src_id = vnet_dev_id;
299             route.src_type = LINK_INTERFACE;
300             memcpy(route.dst_mac, zeromac, 6);
301             route.dst_mac_qual = MAC_ANY;
302             memcpy(route.src_mac, zeromac, 6);
303             route.src_mac_qual = MAC_ANY;
304
305             v3_vnet_add_route(route);
306         }
307     }
308 #endif
309 #if 0 //temporay hacking for vnet virtio bridge
310     {
311         uchar_t tapmac[6] = {0x00,0x02,0x55,0x67,0x42,0x39}; //for Intel-VT test HW
312         //uchar_t tapmac[6] = {0x6e,0xa8,0x75,0xf4,0x82,0x95};
313         uchar_t dstmac[6] = {0xff,0xff,0xff,0xff,0xff,0xff};
314         uchar_t zeromac[6] = {0,0,0,0,0,0};
315
316         struct v3_vnet_route route;
317         route.dst_id = vnet_dev_id;
318         route.dst_type = LINK_INTERFACE;
319         route.src_id = -1;
320         route.src_type = LINK_ANY;
321
322         if(!strcmp(name, "vnet_nicdom0")){
323             memcpy(route.dst_mac, tapmac, 6);
324             route.dst_mac_qual = MAC_NONE;
325             memcpy(route.src_mac, zeromac, 6);
326             route.src_mac_qual = MAC_ANY;
327            
328             v3_vnet_add_route(route);
329
330             memcpy(route.dst_mac, dstmac, 6);
331             route.dst_mac_qual = MAC_NONE;
332             memcpy(route.src_mac, tapmac, 6);
333             route.src_mac_qual = MAC_NOT;
334
335             v3_vnet_add_route(route);
336         }
337
338         if (!strcmp(name, "vnet_nic0")){
339             memcpy(route.dst_mac, zeromac, 6);
340             route.dst_mac_qual = MAC_ANY;
341             memcpy(route.src_mac, tapmac, 6);
342             route.src_mac_qual = MAC_NONE;
343            
344             v3_vnet_add_route(route);
345         }
346     }
347 #endif
348
349     return 0;
350 }
351
352 device_register("VNET_NIC", vnet_nic_init)