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.


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