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.


Update on VNET-NIC device, and fix vnet & virtio net
[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
29
30 #ifndef CONFIG_DEBUG_VNET_NIC
31 #undef PrintDebug
32 #define PrintDebug(fmt, args...)
33 #endif
34
35 #define ETHERNET_PACKET_LEN 1514
36 struct eth_pkt {
37     uint32_t size; //size of data
38     char data[ETHERNET_PACKET_LEN];
39 }__attribute__((packed));
40
41 struct vnet_nic_state {
42     char mac[6];
43     struct guest_info *core;
44     struct gen_queue * inpkt_q;
45         
46     void *frontend_data;
47     int (*frontend_input)(struct v3_vm_info *info, 
48                                     uchar_t * buf,
49                                  uint32_t size,
50                                  void *private_data);
51 };
52
53 //used when virtio_nic get a packet from guest and send it to the backend
54 static int vnet_send(uint8_t * buf, uint32_t len, void * private_data, struct vm_device *dest_dev){
55     PrintDebug("Virito NIC: In vnet_send: guest net state %p\n", private_data);
56
57     v3_vnet_send_rawpkt(buf, len, private_data);
58     return 0;
59 }
60
61 static int register_frontend_input(void *backend_data, 
62                                                                           int (*frontend_input)(struct v3_vm_info *info, 
63                                                                                               uchar_t * buf,
64                                                                                            uint32_t size,
65                                                                                            void *private_data), 
66                                                             void *front_data){
67     struct vnet_nic_state *dev = (struct vnet_nic_state *)backend_data;
68
69     dev->frontend_data = front_data;
70     dev->frontend_input = frontend_input;
71
72     return 0;
73 }
74
75
76 static struct v3_dev_net_ops net_ops = {
77     .send = vnet_send, 
78     .register_input = register_frontend_input,
79 };
80
81 static int virtio_input(struct v3_vm_info *info, uchar_t * buf, uint32_t len, void * private_data){
82     struct vnet_nic_state *vnetnic = (struct vnet_nic_state *)private_data;
83         
84     PrintDebug("Vnet-nic: In input: vnet_nic state %p\n", vnetnic);     
85
86     return vnetnic->frontend_input(info, buf, len, vnetnic->frontend_data);
87 }
88
89 #if 0
90 static int sendto_buf(struct vnet_nic_dev_state *vnetnic_dev, uchar_t * buf, uint_t size) {
91     struct eth_pkt *pkt;
92
93     pkt = (struct eth_pkt *)V3_Malloc(sizeof(struct eth_pkt));
94     if(pkt == NULL){
95         PrintError("Vnet NIC: Memory allocate fails\n");
96         return -1;
97     }
98   
99     pkt->size = size;
100     memcpy(pkt->data, buf, size);
101     v3_enqueue(vnetnic_dev->inpkt_q, (addr_t)pkt);
102         
103     PrintDebug("Vnet NIC: sendto_buf: packet: (size:%d)\n", (int)pkt->size);
104
105     return pkt->size;
106 }
107
108 /*
109   *called in svm/vmx handler
110   *iteative handled the unsent packet in incoming packet queues for
111   *all virtio nic devices in this guest
112   */
113 int v3_virtionic_pktprocess(struct guest_info * info)
114 {
115     struct eth_pkt *pkt = NULL;
116     struct virtio_net_state *net_state;
117     int i;
118
119     //PrintDebug("Virtio NIC: processing guest %p\n", info);
120     for (i = 0; i < net_idx; i++) {
121         while (1) {
122             net_state = temp_net_states[i];
123             if(net_state->dev->vm != info)
124                 break;
125
126             pkt = (struct eth_pkt *)v3_dequeue(net_state->inpkt_q);
127             if(pkt == NULL) 
128                 break;
129                         
130             if (send_pkt_to_guest(net_state, pkt->data, pkt->size, 1, NULL)) {
131                 PrintDebug("Virtio NIC: %p In pkt_handle: send one packet! pt length %d\n", 
132                                 net_state, (int)pkt->size);  
133             } else {
134                 PrintDebug("Virtio NIC: %p In pkt_handle: Fail to send one packet, pt length %d, discard it!\n", 
135                                 net_state, (int)pkt->size); 
136             }
137         
138             V3_Free(pkt);
139         }
140     }
141     
142     return 0;
143 }
144
145
146 /*
147   *called in svm/vmx handler
148   *iteative handled the unsent packet in incoming packet queues for
149   *all virtio nic devices in this guest
150   */
151 int v3_vnetnic_pktprocess(struct guest_info * info)
152 {
153  
154     return 0;
155 }
156
157 #endif
158
159 //register a virtio device to the vnet as backend
160 int register_to_vnet(struct v3_vm_info *info,
161                                                 struct vnet_nic_state *vnet_nic,
162                                                 char *dev_name,
163                                                 uchar_t mac[6]){
164     uchar_t brdmac[6] = {0xff,0xff,0xff,0xff,0xff,0xff};
165     uchar_t zeromac[6] = {0,0,0,0,0,0};
166     struct v3_vnet_route route;
167
168     PrintDebug("Vnet-nic: register Vnet-nic device %s, state %p to VNET\n", dev_name, vnet_nic);
169         
170     int idx = v3_vnet_add_node(info, dev_name, mac, virtio_input, (void *)vnet_nic);
171
172     if (idx < 0) return -1;
173
174  //add default routes for each link edge device
175     memcpy(&route.src_mac, zeromac, 6);
176     memcpy(&route.dest_mac, mac, 6);
177     route.src_mac_qual = MAC_ANY;
178     route.dest_mac_qual = MAC_NONE;
179     route.link_idx = idx;
180     route.link_type = LINK_EDGE;
181     route.src_link_idx = -1;
182     route.src_type = LINK_ANY;
183     v3_vnet_add_route(&route);
184
185     memcpy(&route.dest_mac, brdmac, 6);
186     memcpy(&route.src_mac, mac, 6);
187     route.src_mac_qual = MAC_NOT;
188     route.dest_mac_qual = MAC_NONE;
189     route.link_idx = idx;
190     route.link_type = LINK_EDGE;
191     route.src_link_idx = -1;
192     route.src_type = LINK_ANY;
193     v3_vnet_add_route(&route);
194
195     return 0;
196 }
197
198 static int vnet_nic_free(struct vm_device * dev) {
199     return 0;
200 }
201
202 static struct v3_device_ops dev_ops = {
203     .free = vnet_nic_free,
204     .reset = NULL,
205     .start = NULL,
206     .stop = NULL,
207 };
208
209 static int vnet_nic_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
210     struct vnet_nic_state * vnetnic = NULL;
211     char * name = v3_cfg_val(cfg, "name");
212
213     v3_cfg_tree_t * frontend_cfg = v3_cfg_subtree(cfg, "frontend");
214
215     vnetnic = (struct vnet_nic_state *)V3_Malloc(sizeof(struct vnet_nic_state));
216     memset(vnetnic, 0, sizeof(struct vnet_nic_state));
217
218     struct vm_device * dev = v3_allocate_device(name, &dev_ops, vnetnic);
219
220     if (v3_attach_device(vm, dev) == -1) {
221         PrintError("Could not attach device %s\n", name);
222         return -1;
223     }
224
225     if (v3_dev_connect_net(vm, v3_cfg_val(frontend_cfg, "tag"), 
226                            &net_ops, frontend_cfg, vnetnic) == -1) {
227         PrintError("Could not connect %s to frontend %s\n", 
228                    name, v3_cfg_val(frontend_cfg, "tag"));
229         return -1;
230     }
231
232     vnetnic->inpkt_q = v3_create_queue();
233
234     if(register_to_vnet(vm, vnetnic, name, vnetnic->mac) == -1)
235       return -1;
236
237     PrintDebug("Vnet-nic device %s initialized\n", name);
238
239     return 0;
240 }
241
242 device_register("VNET_NIC", vnet_nic_init)