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.


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