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.


Fix to vnet/virtio networking
[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) 2008, Lei Xia <lxia@northwestern.edu>
11  * Copyright (c) 2008, 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 guest_info * core;
39     struct v3_dev_net_ops net_ops;
40 };
41
42 //used when virtio_nic get a packet from guest and send it to the backend
43 static int vnet_send(uint8_t * buf, uint32_t len, void * private_data, struct vm_device *dest_dev){
44     struct v3_vnet_pkt * pkt = NULL;
45     struct guest_info *core  = (struct guest_info *)private_data; 
46
47     PrintDebug("Virtio VNET-NIC: send pkt size: %d\n", len);
48 #ifdef CONFIG_DEBUG_VNET_NIC
49     v3_hexdump(buf, len, NULL, 0);
50 #endif
51
52 #ifdef CONFIG_VNET_PROFILE
53     uint64_t start, end;
54     rdtscll(start);
55 #endif
56
57     pkt = (struct v3_vnet_pkt *)V3_Malloc(sizeof(struct v3_vnet_pkt));
58
59     if(pkt == NULL){
60         PrintError("Malloc() fails");
61         return -1;
62     }
63         
64 #ifdef CONFIG_VNET_PROFILE
65     {
66         rdtscll(end);
67         core->vnet_times.time_mallocfree = end - start;
68     }
69 #endif
70
71
72     pkt->size = len;
73     memcpy(pkt->data, buf, pkt->size);
74
75 #ifdef CONFIG_VNET_PROFILE
76     {
77         rdtscll(start);
78         core->vnet_times.time_copy_from_guest = start - end;
79     }
80 #endif
81
82     v3_vnet_send_pkt(pkt, (void *)core);
83
84 #ifdef CONFIG_VNET_PROFILE
85     {
86         rdtscll(end);
87         core->vnet_times.vnet_handle_time = end - start;
88     }
89 #endif
90
91     V3_Free(pkt);
92
93 #ifdef CONFIG_VNET_PROFILE
94     {
95         rdtscll(start);
96         core->vnet_times.time_mallocfree += start - end;
97     }
98 #endif
99
100     return 0;
101 }
102
103
104 static int virtio_input(struct v3_vm_info *info, struct v3_vnet_pkt * pkt, void * private_data){
105     struct vnet_nic_state *vnetnic = (struct vnet_nic_state *)private_data;
106         
107     PrintDebug("Vnet-nic: In input: vnet_nic state %p\n", vnetnic);     
108
109     return vnetnic->net_ops.recv(pkt->data, pkt->size, vnetnic->net_ops.frontend_data);
110 }
111
112 static int register_to_vnet(struct v3_vm_info * vm,
113                      struct vnet_nic_state *vnet_nic,
114                      char *dev_name,
115                      uchar_t mac[6]) { 
116    
117     PrintDebug("Vnet-nic: register Vnet-nic device %s, state %p to VNET\n", dev_name, vnet_nic);
118         
119     return v3_vnet_add_dev(vm, mac, virtio_input, (void *)vnet_nic);
120 }
121
122 static int vnet_nic_free(struct vm_device * dev) {
123     return 0;
124 }
125
126 static struct v3_device_ops dev_ops = {
127     .free = vnet_nic_free,
128     .reset = NULL,
129     .start = NULL,
130     .stop = NULL,
131 };
132
133
134 static int str2mac(char *macstr, char mac[6]){
135     char hex[2], *s = macstr;
136     int i = 0;
137
138     while(s){
139         memcpy(hex, s, 2);
140         mac[i++] = (char)atox(hex);
141         if (i == 6) return 0;
142         s=strchr(s, ':');
143         if(s) s++;
144     }
145
146     return -1;
147 }
148
149 static int vnet_nic_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
150     struct vnet_nic_state * vnetnic = NULL;
151     char * name = v3_cfg_val(cfg, "name");
152     char * macstr;
153     char mac[6];
154     int vnet_dev_id;
155
156     v3_cfg_tree_t * frontend_cfg = v3_cfg_subtree(cfg, "frontend");
157     macstr = v3_cfg_val(frontend_cfg, "mac");
158     str2mac(macstr, mac);
159
160     vnetnic = (struct vnet_nic_state *)V3_Malloc(sizeof(struct vnet_nic_state));
161     memset(vnetnic, 0, sizeof(struct vnet_nic_state));
162
163     struct vm_device * dev = v3_allocate_device(name, &dev_ops, vnetnic);
164
165     if (v3_attach_device(vm, dev) == -1) {
166         PrintError("Could not attach device %s\n", name);
167         return -1;
168     }
169
170     vnetnic->net_ops.send = vnet_send;
171     memcpy(vnetnic->mac, mac, 6);
172         
173     if (v3_dev_connect_net(vm, v3_cfg_val(frontend_cfg, "tag"), 
174                            &(vnetnic->net_ops), frontend_cfg, vnetnic) == -1) {
175         PrintError("Could not connect %s to frontend %s\n", 
176                    name, v3_cfg_val(frontend_cfg, "tag"));
177         return -1;
178     }
179
180     PrintDebug("Vnet-nic: Connect %s to frontend %s\n", 
181                    name, v3_cfg_val(frontend_cfg, "tag"));
182
183     if ((vnet_dev_id = register_to_vnet(vm, vnetnic, name, vnetnic->mac)) == -1) {
184         return -1;
185     }
186
187     PrintDebug("Vnet-nic device %s (mac: %s, %ld) initialized\n", name, macstr, *((ulong_t *)vnetnic->mac));
188
189
190 //for temporary hack
191 #if 1   
192     {
193          //uchar_t tapmac[6] = {0x00,0x02,0x55,0x67,0x42,0x39}; //for Intel-VT test HW
194         uchar_t tapmac[6] = {0x6e,0xa8,0x75,0xf4,0x82,0x95};
195         uchar_t dstmac[6] = {0xff,0xff,0xff,0xff,0xff,0xff};
196         uchar_t zeromac[6] = {0,0,0,0,0,0};
197
198         struct v3_vnet_route route;
199        route.dst_id = vnet_dev_id;
200         route.dst_type = LINK_INTERFACE;
201         route.src_id = -1;
202         route.src_type = LINK_ANY;
203
204         if(!strcmp(name, "vnet_nicdom0")){
205             memcpy(route.dst_mac, tapmac, 6);
206             route.dst_mac_qual = MAC_NONE;
207             memcpy(route.src_mac, zeromac, 6);
208             route.src_mac_qual = MAC_ANY;
209            
210             v3_vnet_add_route(route);
211
212             memcpy(route.dst_mac, dstmac, 6);
213             route.dst_mac_qual = MAC_NONE;
214             memcpy(route.src_mac, tapmac, 6);
215             route.src_mac_qual = MAC_NOT;
216
217             v3_vnet_add_route(route);
218         }
219
220         if (!strcmp(name, "vnet_nic0")){
221             memcpy(route.dst_mac, zeromac, 6);
222             route.dst_mac_qual = MAC_ANY;
223             memcpy(route.src_mac, tapmac, 6);
224             route.src_mac_qual = MAC_NONE;
225            
226             v3_vnet_add_route(route);
227         }
228     }
229
230 #endif
231
232     return 0;
233 }
234
235 device_register("VNET_NIC", vnet_nic_init)