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.


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