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.


more device free updates
[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, uchar_t mac[6]) { 
141    
142     PrintDebug("Vnet-nic: register Vnet-nic device %s, state %p to VNET\n", dev_name, vnet_nic);
143         
144     return v3_vnet_add_dev(vm, mac, &vnet_dev_ops, (void *)vnet_nic);
145 }
146
147
148 static int str2mac(char * macstr, char mac[6]){
149     char hex[2], *s = macstr;
150     int i = 0;
151
152     while(s){
153         memcpy(hex, s, 2);
154         mac[i++] = (char)atox(hex);
155         if (i == 6) return 0;
156         s=strchr(s, ':');
157         if(s) s++;
158     }
159
160     return -1;
161 }
162
163 static int vnet_nic_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
164     struct vnet_nic_state * vnetnic = NULL;
165     char * name = v3_cfg_val(cfg, "name");
166     char * macstr = NULL;
167     char mac[6];
168     int vnet_dev_id;
169
170     v3_cfg_tree_t * frontend_cfg = v3_cfg_subtree(cfg, "frontend");
171     macstr = v3_cfg_val(frontend_cfg, "mac");
172
173     if (macstr == NULL) {
174         PrintDebug("Vnet-nic: No Mac specified\n");
175     } else {
176         str2mac(macstr, mac);
177     }
178
179     vnetnic = (struct vnet_nic_state *)V3_Malloc(sizeof(struct vnet_nic_state));
180     memset(vnetnic, 0, sizeof(struct vnet_nic_state));
181
182     struct vm_device * dev = v3_allocate_device(name, &dev_ops, vnetnic);
183
184     if (v3_attach_device(vm, dev) == -1) {
185         PrintError("Could not attach device %s\n", name);
186         return -1;
187     }
188
189     vnetnic->net_ops.send = vnet_nic_send;
190     vnetnic->net_ops.start_rx = start_rx;
191     vnetnic->net_ops.stop_rx = stop_rx;
192     memcpy(vnetnic->mac, mac, 6);
193     vnetnic->vm = vm;
194         
195     if (v3_dev_connect_net(vm, v3_cfg_val(frontend_cfg, "tag"), 
196                            &(vnetnic->net_ops), frontend_cfg, vnetnic) == -1) {
197         PrintError("Could not connect %s to frontend %s\n", 
198                    name, v3_cfg_val(frontend_cfg, "tag"));
199         return -1;
200     }
201
202     PrintDebug("Vnet-nic: Connect %s to frontend %s\n", 
203               name, v3_cfg_val(frontend_cfg, "tag"));
204
205     if ((vnet_dev_id = register_to_vnet(vm, vnetnic, name, vnetnic->mac)) == -1) {
206         PrintError("Vnet-nic device %s (mac: %s) fails to registered to VNET\n", name, macstr);
207     }
208     vnetnic->vnet_dev_id = vnet_dev_id;
209
210     PrintDebug("Vnet-nic device %s (mac: %s, %ld) registered to VNET\n", 
211                 name, macstr, *((ulong_t *)vnetnic->mac));
212
213
214 //for temporary hack for vnet bridge test
215 #if 0
216     {
217         uchar_t zeromac[6] = {0,0,0,0,0,0};
218                 
219         if(!strcmp(name, "vnet_nic")){
220             struct v3_vnet_route route;
221                 
222             route.dst_id = vnet_dev_id;
223             route.dst_type = LINK_INTERFACE;
224             route.src_id = 0;
225             route.src_type = LINK_EDGE;
226             memcpy(route.dst_mac, zeromac, 6);
227             route.dst_mac_qual = MAC_ANY;
228             memcpy(route.src_mac, zeromac, 6);
229             route.src_mac_qual = MAC_ANY;  
230             v3_vnet_add_route(route);
231
232
233             route.dst_id = 0;
234             route.dst_type = LINK_EDGE;
235             route.src_id = vnet_dev_id;
236             route.src_type = LINK_INTERFACE;
237             memcpy(route.dst_mac, zeromac, 6);
238             route.dst_mac_qual = MAC_ANY;
239             memcpy(route.src_mac, zeromac, 6);
240             route.src_mac_qual = MAC_ANY;
241
242             v3_vnet_add_route(route);
243         }
244     }
245 #endif
246
247 //for temporary hack for Linux bridge (w/o encapuslation) test
248 #if 1
249     {
250         static int vnet_nic_guestid = -1;
251         static int vnet_nic_dom0 = -1;
252         uchar_t zeromac[6] = {0,0,0,0,0,0};
253                 
254         if(!strcmp(name, "vnet_nic")){ //domu
255             vnet_nic_guestid = vnet_dev_id;
256         }
257         if (!strcmp(name, "vnet_nic_dom0")){
258             vnet_nic_dom0 = vnet_dev_id;
259         }
260
261         if(vnet_nic_guestid != -1 && vnet_nic_dom0 !=-1){
262             struct v3_vnet_route route;
263                 
264             route.src_id = vnet_nic_guestid;
265             route.src_type = LINK_INTERFACE;
266             route.dst_id = vnet_nic_dom0;
267             route.dst_type = LINK_INTERFACE;
268             memcpy(route.dst_mac, zeromac, 6);
269             route.dst_mac_qual = MAC_ANY;
270             memcpy(route.src_mac, zeromac, 6);
271             route.src_mac_qual = MAC_ANY;  
272             v3_vnet_add_route(route);
273
274
275             route.src_id = vnet_nic_dom0;
276             route.src_type = LINK_INTERFACE;
277             route.dst_id = vnet_nic_guestid;
278             route.dst_type = LINK_INTERFACE;
279             memcpy(route.dst_mac, zeromac, 6);
280             route.dst_mac_qual = MAC_ANY;
281             memcpy(route.src_mac, zeromac, 6);
282             route.src_mac_qual = MAC_ANY;
283
284             v3_vnet_add_route(route);
285         }
286     }
287 #endif
288
289     return 0;
290 }
291
292 device_register("VNET_NIC", vnet_nic_init)