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.


deallocation of devices
[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) 2010, Lei Xia <lxia@northwestern.edu>
11  * Copyright (c) 2010, 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 /* called by frontend device, 
44   * tell the VNET can start sending pkt to it */
45 static void start_rx(void * private_data){
46     //struct vnet_nic_state *vnetnic = (struct vnet_nic_state *)private_data;
47
48     //v3_vnet_enable_device(vnetnic->vnet_dev_id);
49 }
50
51 /* called by frontend device, 
52   * tell the VNET stop sending pkt to it */
53 static void stop_rx(void * private_data){
54     //struct vnet_nic_state *vnetnic = (struct vnet_nic_state *)private_data;
55
56     //v3_vnet_disable_device(vnetnic->vnet_dev_id);
57 }
58
59 /* called by frontend, send pkt to VNET */
60 static int vnet_nic_send(uint8_t * buf, uint32_t len, 
61                          void * private_data) {
62     struct vnet_nic_state * vnetnic = (struct vnet_nic_state *)private_data;
63
64     struct v3_vnet_pkt pkt;
65     pkt.size = len;
66     pkt.src_type = LINK_INTERFACE;
67     pkt.src_id = vnetnic->vnet_dev_id;
68     memcpy(pkt.header, buf, ETHERNET_HEADER_LEN);
69     pkt.data = buf;
70
71 #ifdef CONFIG_DEBUG_VNET_NIC
72     {
73         PrintDebug("VNET-NIC: send pkt (size: %d, src_id: %d, src_type: %d)\n", 
74                    pkt.size, pkt.src_id, pkt.src_type);
75         //v3_hexdump(buf, len, NULL, 0);
76     }
77 #endif
78
79     return v3_vnet_send_pkt(&pkt, NULL);;
80 }
81
82
83 /* send pkt to frontend device */
84 static int virtio_input(struct v3_vm_info * info, 
85                         struct v3_vnet_pkt * pkt, 
86                         void * private_data){
87     struct vnet_nic_state *vnetnic = (struct vnet_nic_state *)private_data;
88
89     PrintDebug("VNET-NIC: receive pkt (size %d, src_id:%d, src_type: %d, dst_id: %d, dst_type: %d)\n", 
90                 pkt->size, pkt->src_id, pkt->src_type, pkt->dst_id, pkt->dst_type);
91         
92     return vnetnic->net_ops.recv(pkt->data, pkt->size,
93                                  vnetnic->net_ops.frontend_data);
94 }
95
96 /* tell frontend device to poll data from guest */
97 static void virtio_poll(struct v3_vm_info * info, 
98                         void * private_data){
99     struct vnet_nic_state *vnetnic = (struct vnet_nic_state *)private_data;
100
101     vnetnic->net_ops.poll(info, vnetnic->net_ops.frontend_data);
102 }
103
104
105 /* tell the frontend to start sending pkt to VNET*/
106 static void start_tx(void * private_data){
107     struct vnet_nic_state *vnetnic = (struct vnet_nic_state *)private_data;
108
109     vnetnic->net_ops.start_tx(vnetnic->net_ops.frontend_data);
110 }
111
112 /* tell the frontend device to stop sending pkt to VNET*/
113 static void stop_tx(void * private_data){
114     struct vnet_nic_state *vnetnic = (struct vnet_nic_state *)private_data;
115
116     vnetnic->net_ops.stop_tx(vnetnic->net_ops.frontend_data);
117 }
118
119
120 static int vnet_nic_free(struct vnet_nic_state * vnetnic) {
121     
122
123     V3_Free(vnetnic);
124     return 0;
125 }
126
127 static struct v3_device_ops dev_ops = {
128     .free = (int (*)(void *))vnet_nic_free,
129
130 };
131
132 static struct v3_vnet_dev_ops vnet_dev_ops = {
133     .input = virtio_input,
134     .poll = virtio_poll,
135     .start_tx = start_tx,
136     .stop_tx = stop_tx,
137 };
138
139
140 static int register_to_vnet(struct v3_vm_info * vm,
141                             struct vnet_nic_state * vnet_nic,
142                             char * dev_name, uchar_t mac[6]) { 
143    
144     PrintDebug("Vnet-nic: register Vnet-nic device %s, state %p to VNET\n", dev_name, vnet_nic);
145         
146     return v3_vnet_add_dev(vm, mac, &vnet_dev_ops, (void *)vnet_nic);
147 }
148
149
150 static int str2mac(char * macstr, char mac[6]){
151     char hex[2], *s = macstr;
152     int i = 0;
153
154     while(s){
155         memcpy(hex, s, 2);
156         mac[i++] = (char)atox(hex);
157         if (i == 6) return 0;
158         s=strchr(s, ':');
159         if(s) s++;
160     }
161
162     return -1;
163 }
164
165 static int vnet_nic_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
166     struct vnet_nic_state * vnetnic = NULL;
167     char * dev_id = v3_cfg_val(cfg, "ID");
168     char * macstr = NULL;
169     char mac[6];
170     int vnet_dev_id;
171
172     v3_cfg_tree_t * frontend_cfg = v3_cfg_subtree(cfg, "frontend");
173     macstr = v3_cfg_val(frontend_cfg, "mac");
174
175     if (macstr == NULL) {
176         PrintDebug("Vnet-nic: No Mac specified\n");
177     } else {
178         str2mac(macstr, mac);
179     }
180
181     vnetnic = (struct vnet_nic_state *)V3_Malloc(sizeof(struct vnet_nic_state));
182     memset(vnetnic, 0, sizeof(struct vnet_nic_state));
183
184     struct vm_device * dev = v3_add_device(vm, dev_id, &dev_ops, vnetnic);
185
186     if (dev == NULL) {
187         PrintError("Could not attach device %s\n", dev_id);
188         V3_Free(vnetnic);
189         return -1;
190     }
191
192     vnetnic->net_ops.send = vnet_nic_send;
193     vnetnic->net_ops.start_rx = start_rx;
194     vnetnic->net_ops.stop_rx = stop_rx;
195     memcpy(vnetnic->mac, mac, 6);
196     vnetnic->vm = vm;
197         
198     if (v3_dev_connect_net(vm, v3_cfg_val(frontend_cfg, "tag"), 
199                            &(vnetnic->net_ops), frontend_cfg, vnetnic) == -1) {
200         PrintError("Could not connect %s to frontend %s\n", 
201                    dev_id, v3_cfg_val(frontend_cfg, "tag"));
202         v3_remove_device(dev);
203         return -1;
204     }
205
206     PrintDebug("Vnet-nic: Connect %s to frontend %s\n", 
207               dev_id, v3_cfg_val(frontend_cfg, "tag"));
208
209     if ((vnet_dev_id = register_to_vnet(vm, vnetnic, dev_id, vnetnic->mac)) == -1) {
210         PrintError("Vnet-nic device %s (mac: %s) fails to registered to VNET\n", dev_id, macstr);
211         v3_remove_device(dev);
212         return 0;
213     }
214
215     vnetnic->vnet_dev_id = vnet_dev_id;
216
217     PrintDebug("Vnet-nic device %s (mac: %s, %ld) registered to VNET\n", 
218                 dev_id, macstr, *((ulong_t *)vnetnic->mac));
219
220
221 //for temporary hack for vnet bridge test
222 #if 1
223     {
224         uchar_t zeromac[6] = {0,0,0,0,0,0};
225                 
226         if(!strcmp(dev_id, "vnet_nic")){
227             struct v3_vnet_route route;
228                 
229             route.dst_id = vnet_dev_id;
230             route.dst_type = LINK_INTERFACE;
231             route.src_id = 0;
232             route.src_type = LINK_EDGE;
233             memcpy(route.dst_mac, zeromac, 6);
234             route.dst_mac_qual = MAC_ANY;
235             memcpy(route.src_mac, zeromac, 6);
236             route.src_mac_qual = MAC_ANY;  
237             v3_vnet_add_route(route);
238
239
240             route.dst_id = 0;
241             route.dst_type = LINK_EDGE;
242             route.src_id = vnet_dev_id;
243             route.src_type = LINK_INTERFACE;
244             memcpy(route.dst_mac, zeromac, 6);
245             route.dst_mac_qual = MAC_ANY;
246             memcpy(route.src_mac, zeromac, 6);
247             route.src_mac_qual = MAC_ANY;
248
249             v3_vnet_add_route(route);
250         }
251     }
252 #endif
253
254 //for temporary hack for Linux bridge (w/o encapuslation) test
255 #if 0
256     {
257         static int vnet_nic_guestid = -1;
258         static int vnet_nic_dom0 = -1;
259         uchar_t zeromac[6] = {0,0,0,0,0,0};
260                 
261         if(!strcmp(dev_id, "vnet_nic")){ //domu
262             vnet_nic_guestid = vnet_dev_id;
263         }
264         if (!strcmp(dev_id, "vnet_nic_dom0")){
265             vnet_nic_dom0 = vnet_dev_id;
266         }
267
268         if(vnet_nic_guestid != -1 && vnet_nic_dom0 !=-1){
269             struct v3_vnet_route route;
270                 
271             route.src_id = vnet_nic_guestid;
272             route.src_type = LINK_INTERFACE;
273             route.dst_id = vnet_nic_dom0;
274             route.dst_type = LINK_INTERFACE;
275             memcpy(route.dst_mac, zeromac, 6);
276             route.dst_mac_qual = MAC_ANY;
277             memcpy(route.src_mac, zeromac, 6);
278             route.src_mac_qual = MAC_ANY;  
279             v3_vnet_add_route(route);
280
281
282             route.src_id = vnet_nic_dom0;
283             route.src_type = LINK_INTERFACE;
284             route.dst_id = vnet_nic_guestid;
285             route.dst_type = LINK_INTERFACE;
286             memcpy(route.dst_mac, zeromac, 6);
287             route.dst_mac_qual = MAC_ANY;
288             memcpy(route.src_mac, zeromac, 6);
289             route.src_mac_qual = MAC_ANY;
290
291             v3_vnet_add_route(route);
292         }
293     }
294 #endif
295
296     return 0;
297 }
298
299 device_register("VNET_NIC", vnet_nic_init)