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 / netdisk.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, Jack Lange <jarusl@cs.northwestern.edu> 
11  * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org> 
12  * All rights reserved.
13  *
14  * Author: Jack Lange <jarusl@cs.northwestern.edu>
15  *
16  * This is free software.  You are permitted to use,
17  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
18  */
19
20 #include <palacios/vmm.h>
21 #include <palacios/vmm_dev_mgr.h>
22 #include <palacios/vmm_socket.h>
23
24 #ifndef CONFIG_DEBUG_IDE
25 #undef PrintDebug
26 #define PrintDebug(fmt, args...)
27 #endif
28
29
30 #define NBD_READ_CMD 0x1
31 #define NBD_WRITE_CMD 0x2
32 #define NBD_CAPACITY_CMD 0x3
33
34 #define NBD_STATUS_OK 0x00
35 #define NBD_STATUS_ERR 0xff
36
37
38 struct disk_state {
39     uint64_t capacity; // in bytes
40
41     v3_sock_t socket;
42
43     uint32_t ip_addr;
44     uint16_t port;
45
46     struct v3_vm_info * vm;
47
48     char disk_name[32];
49
50 };
51
52
53 static int send_all(v3_sock_t socket, char * buf, int length) {
54     int bytes_sent = 0;
55     
56     PrintDebug("Sending %d bytes\n", length - bytes_sent);
57     while (bytes_sent < length) {
58         int tmp_bytes = v3_socket_send(socket, buf + bytes_sent, length - bytes_sent);
59         PrintDebug("Sent %d bytes\n", tmp_bytes);
60         
61         if (tmp_bytes == 0) {
62             PrintError("Connection Closed unexpectedly\n");
63             return -1;
64         }
65         
66         bytes_sent += tmp_bytes;
67     }
68     
69     return 0;
70 }
71
72
73 static int recv_all(v3_sock_t socket, char * buf, int length) {
74     int bytes_read = 0;
75     
76     PrintDebug("Reading %d bytes\n", length - bytes_read);
77     while (bytes_read < length) {
78         int tmp_bytes = v3_socket_recv(socket, buf + bytes_read, length - bytes_read);
79         PrintDebug("Received %d bytes\n", tmp_bytes);
80         
81         if (tmp_bytes == 0) {
82             PrintError("Connection Closed unexpectedly\n");
83             return -1;
84         }
85         
86         bytes_read += tmp_bytes;
87     }
88     
89     return 0;
90 }
91
92
93 // HDs always read 512 byte blocks... ?
94 static int read(uint8_t * buf, uint64_t lba, uint64_t num_bytes, void * private_data) {
95     struct disk_state * disk = (struct disk_state *)private_data ;
96     uint8_t status;
97     uint32_t ret_len = 0;
98     char nbd_cmd[4] = {0,0,0,0};
99     uint64_t offset = lba;
100     uint64_t length = num_bytes;
101
102     nbd_cmd[0] = NBD_READ_CMD;
103     
104     if (send_all(disk->socket, nbd_cmd, 4) == -1) {
105         PrintError("Error sending read command\n");
106         return -1;
107     }
108     
109     if (send_all(disk->socket, (char *)&offset, 8) == -1) {
110         PrintError("Error sending read offset\n");
111         return -1;
112     }
113
114     if (send_all(disk->socket, (char *)&length, 4) == -1) {
115         PrintError("Error sending read length\n");
116         return -1;
117     }
118
119     if (recv_all(disk->socket, (char *)&status, 1) == -1) {
120         PrintError("Error receiving status\n");
121         return -1;
122     }
123
124     if (status != NBD_STATUS_OK) {
125         PrintError("NBD Error....\n");
126         return -1;
127     }
128
129     PrintDebug("Reading Data Ret Length\n");
130
131     if (recv_all(disk->socket, (char *)&ret_len, 4) == -1) {
132         PrintError("Error receiving Return read length\n");
133         return -1;
134     }
135
136     if (ret_len != length) {
137         PrintError("Read length mismatch (req=%llu) (result=%u)\n", length, ret_len);
138         return -1;
139     }
140
141     PrintDebug("Reading Data (%d bytes)\n", ret_len);
142
143     if (recv_all(disk->socket, (char *)buf, ret_len) == -1) {
144         PrintError("Read Data Error\n");
145         return -1;
146     }
147
148     return 0;
149 }
150
151
152 static int write(uint8_t * buf, uint64_t lba, uint64_t num_bytes, void * private_data) {
153     struct disk_state * disk = (struct disk_state *)private_data ;
154     uint64_t offset = lba;
155     int length = num_bytes;
156     uint8_t status;
157     char nbd_cmd[4] = {0,0,0,0};
158
159     nbd_cmd[0] = NBD_WRITE_CMD;
160
161     if (send_all(disk->socket, nbd_cmd, 4) == -1) {
162         PrintError("Error sending write command\n");
163         return -1;
164     }
165
166     if (send_all(disk->socket, (char *)&offset, 8) == -1) {
167         PrintError("Error sending write offset\n");
168         return -1;
169     }
170
171     if (send_all(disk->socket, (char *)&length, 4) == -1) {
172         PrintError("Error sending write length\n");
173         return -1;
174     }
175
176     PrintDebug("Writing Data (%d bytes)\n", length);
177
178     if (send_all(disk->socket, (char *)buf, length) == -1) {
179         PrintError("Write Data Error\n");
180         return -1;
181     }
182
183     if (recv_all(disk->socket, (char *)&status, 1) == -1) {
184         PrintError("Error receiving status\n");
185         return -1;
186     }
187
188     if (status != NBD_STATUS_OK) {
189         PrintError("NBD Error....\n");
190         return -1;
191     }
192
193     return 0;
194 }
195
196
197 static uint64_t get_capacity(void * private_data) {
198     struct disk_state * disk = (struct disk_state *)private_data;
199
200     return disk->capacity;
201 }
202
203 static struct v3_dev_blk_ops blk_ops = {
204     .read = read, 
205     .write = write,
206     .get_capacity = get_capacity,
207 };
208
209
210
211
212
213 static int disk_free(struct vm_device * dev) {
214     return 0;
215 }
216
217 static struct v3_device_ops dev_ops = {
218     .free = disk_free,
219 };
220
221
222 static int socket_init(struct disk_state * disk) {
223     char header[64];
224     
225     PrintDebug("Intializing Net Disk\n");
226
227     disk->socket = v3_create_tcp_socket(disk->vm);
228
229     PrintDebug("DISK socket: %d\n", disk->socket);
230     PrintDebug("Connecting to: %s:%d\n", v3_inet_ntoa(disk->ip_addr), disk->port);
231
232     v3_connect_to_ip(disk->socket, v3_ntohl(disk->ip_addr), disk->port);
233
234     PrintDebug("Connected to NBD server\n");
235
236     //snprintf(header, 64, "V3_NBD_1 %s\n", cd->disk_name);
237     strcpy(header, "V3_NBD_1 ");
238     strncat(header, disk->disk_name, 32);
239     strncat(header, "\n", 1);
240
241
242     if (send_all(disk->socket, header, strlen(header)) == -1) {
243         PrintError("Error connecting to Network Block Device: %s\n", disk->disk_name);
244         return -1;
245     }
246
247     // store local copy of capacity
248     {
249         char nbd_cmd[4] = {0,0,0,0};
250
251         nbd_cmd[0] = NBD_CAPACITY_CMD;
252         
253         if (send_all(disk->socket, nbd_cmd, 4) == -1) {
254             PrintError("Error sending capacity command\n");
255             return -1;
256         }
257
258         if (recv_all(disk->socket, (char *)&(disk->capacity), 8) == -1) {
259             PrintError("Error Receiving Capacity\n");
260             return -1;
261         }       
262
263         PrintDebug("Capacity: %p\n", (void *)(addr_t)disk->capacity);
264     }
265
266
267
268     return 0;
269 }
270
271
272 static int disk_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
273     struct disk_state * disk = (struct disk_state *)V3_Malloc(sizeof(struct disk_state));
274
275     char * ip_str = v3_cfg_val(cfg, "IP");
276     char * port_str = v3_cfg_val(cfg, "port");
277     char * disk_tag = v3_cfg_val(cfg, "tag");
278     char * dev_id = v3_cfg_val(cfg, "ID");
279
280     v3_cfg_tree_t * frontend_cfg = v3_cfg_subtree(cfg, "frontend");
281
282     PrintDebug("Registering Net disk at %s:%s disk=%s\n", ip_str, port_str, disk_tag);
283
284     strncpy(disk->disk_name, disk_tag, sizeof(disk->disk_name));
285     disk->ip_addr = v3_inet_addr(ip_str);
286     disk->port = atoi(port_str);
287     disk->vm = vm;
288
289     struct vm_device * dev = v3_allocate_device(dev_id, &dev_ops, disk);
290
291     if (v3_attach_device(vm, dev) == -1) {
292         PrintError("Could not attach device %s\n", dev_id);
293         return -1;
294     }
295
296     if (socket_init(disk) == -1) {
297         PrintError("could not initialize network connection\n");
298         return -1;
299     }
300
301     PrintDebug("Registering Disk\n");
302
303     if (v3_dev_connect_blk(vm, v3_cfg_val(frontend_cfg, "tag"), 
304                            &blk_ops, frontend_cfg, disk) == -1) {
305         PrintError("Could not connect %s to frontend\n", dev_id);
306         return -1;
307     }
308
309     PrintDebug("intialization done\n");
310
311     return 0;
312 }
313
314
315 device_register("NETDISK", disk_init)