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.


abdd227a38f55e4cfbe1c22dcc5640c6f288ceaf
[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
46     PrintDebug("Virtio VNET-NIC: send pkt size: %d\n", len);
47 #ifdef CONFIG_DEBUG_VNET_NIC
48     v3_hexdump(buf, len, NULL, 0);
49 #endif
50
51     pkt = (struct v3_vnet_pkt *)V3_Malloc(sizeof(struct v3_vnet_pkt));
52
53     if(pkt == NULL){
54         PrintError("Malloc() fails");
55         return -1;
56     }
57
58     pkt->size = len;
59     memcpy(pkt->data, buf, pkt->size);
60
61     v3_vnet_send_pkt(pkt);
62
63     V3_Free(pkt);
64     return 0;
65 }
66
67
68 // We need to make this dynamically allocated
69 //static struct v3_dev_net_ops net_ops = {
70 //    .send = vnet_send, 
71 //};
72
73 static int virtio_input(struct v3_vm_info *info, struct v3_vnet_pkt * pkt, void * private_data){
74     struct vnet_nic_state *vnetnic = (struct vnet_nic_state *)private_data;
75         
76     PrintDebug("Vnet-nic: In input: vnet_nic state %p\n", vnetnic);     
77
78     return vnetnic->net_ops.recv(pkt->data, pkt->size, vnetnic->net_ops.frontend_data);
79 }
80
81 #if 0
82 static int sendto_buf(struct vnet_nic_dev_state *vnetnic_dev, uchar_t * buf, uint_t size) {
83     struct eth_pkt *pkt;
84
85     pkt = (struct eth_pkt *)V3_Malloc(sizeof(struct eth_pkt));
86     if(pkt == NULL){
87         PrintError("Vnet NIC: Memory allocate fails\n");
88         return -1;
89     }
90   
91     pkt->size = size;
92     memcpy(pkt->data, buf, size);
93     v3_enqueue(vnetnic_dev->inpkt_q, (addr_t)pkt);
94         
95     PrintDebug("Vnet NIC: sendto_buf: packet: (size:%d)\n", (int)pkt->size);
96
97     return pkt->size;
98 }
99
100 /*
101   *called in svm/vmx handler
102   *iteative handled the unsent packet in incoming packet queues for
103   *all virtio nic devices in this guest
104   */
105 int v3_virtionic_pktprocess(struct guest_info * info)
106 {
107     struct eth_pkt *pkt = NULL;
108     struct virtio_net_state *net_state;
109     int i;
110
111     //PrintDebug("Virtio NIC: processing guest %p\n", info);
112     for (i = 0; i < net_idx; i++) {
113         while (1) {
114             net_state = temp_net_states[i];
115             if(net_state->dev->vm != info)
116                 break;
117
118             pkt = (struct eth_pkt *)v3_dequeue(net_state->inpkt_q);
119             if(pkt == NULL) 
120                 break;
121                         
122             if (send_pkt_to_guest(net_state, pkt->data, pkt->size, 1, NULL)) {
123                 PrintDebug("Virtio NIC: %p In pkt_handle: send one packet! pt length %d\n", 
124                                 net_state, (int)pkt->size);  
125             } else {
126                 PrintDebug("Virtio NIC: %p In pkt_handle: Fail to send one packet, pt length %d, discard it!\n", 
127                                 net_state, (int)pkt->size); 
128             }
129         
130             V3_Free(pkt);
131         }
132     }
133     
134     return 0;
135 }
136
137
138 /*
139   *called in svm/vmx handler
140   *iteative handled the unsent packet in incoming packet queues for
141   *all virtio nic devices in this guest
142   */
143 int v3_vnetnic_pktprocess(struct guest_info * info)
144 {
145  
146     return 0;
147 }
148
149 #endif
150
151 //register a virtio device to the vnet as backend
152 int register_to_vnet(struct v3_vm_info * vm,
153                      struct vnet_nic_state *vnet_nic,
154                      char *dev_name,
155                      uchar_t mac[6]) { 
156    
157     PrintDebug("Vnet-nic: register Vnet-nic device %s, state %p to VNET\n", dev_name, vnet_nic);
158         
159     v3_vnet_add_dev(vm, mac, virtio_input, (void *)vnet_nic);
160
161     return 0;
162 }
163
164 static int vnet_nic_free(struct vm_device * dev) {
165     return 0;
166 }
167
168 static struct v3_device_ops dev_ops = {
169     .free = vnet_nic_free,
170     .reset = NULL,
171     .start = NULL,
172     .stop = NULL,
173 };
174
175 static int vnet_nic_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
176     struct vnet_nic_state * vnetnic = NULL;
177     char * name = v3_cfg_val(cfg, "name");
178
179     v3_cfg_tree_t * frontend_cfg = v3_cfg_subtree(cfg, "frontend");
180
181     vnetnic = (struct vnet_nic_state *)V3_Malloc(sizeof(struct vnet_nic_state));
182     memset(vnetnic, 0, sizeof(struct vnet_nic_state));
183
184     struct vm_device * dev = v3_allocate_device(name, &dev_ops, vnetnic);
185
186     if (v3_attach_device(vm, dev) == -1) {
187         PrintError("Could not attach device %s\n", name);
188         return -1;
189     }
190
191     vnetnic->net_ops.send = vnet_send;
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                    name, v3_cfg_val(frontend_cfg, "tag"));
196         return -1;
197     }
198
199     if (register_to_vnet(vm, vnetnic, name, vnetnic->mac) == -1) {
200         return -1;
201     }
202
203     PrintDebug("Vnet-nic device %s initialized\n", name);
204
205     return 0;
206 }
207
208 device_register("VNET_NIC", vnet_nic_init)