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.


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