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.


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