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 the socket interface
[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     .reset = NULL,
220     .start = NULL,
221     .stop = NULL,
222 };
223
224
225 static int socket_init(struct disk_state * disk) {
226     char header[64];
227     
228     PrintDebug("Intializing Net Disk\n");
229
230     disk->socket = v3_create_tcp_socket(disk->vm);
231
232     PrintDebug("DISK socket: %d\n", disk->socket);
233     PrintDebug("Connecting to: %s:%d\n", v3_inet_ntoa(disk->ip_addr), disk->port);
234
235     v3_connect_to_ip(disk->socket, v3_ntohl(disk->ip_addr), disk->port);
236
237     PrintDebug("Connected to NBD server\n");
238
239     //snprintf(header, 64, "V3_NBD_1 %s\n", cd->disk_name);
240     strcpy(header, "V3_NBD_1 ");
241     strncat(header, disk->disk_name, 32);
242     strncat(header, "\n", 1);
243
244
245     if (send_all(disk->socket, header, strlen(header)) == -1) {
246         PrintError("Error connecting to Network Block Device: %s\n", disk->disk_name);
247         return -1;
248     }
249
250     // store local copy of capacity
251     {
252         char nbd_cmd[4] = {0,0,0,0};
253
254         nbd_cmd[0] = NBD_CAPACITY_CMD;
255         
256         if (send_all(disk->socket, nbd_cmd, 4) == -1) {
257             PrintError("Error sending capacity command\n");
258             return -1;
259         }
260
261         if (recv_all(disk->socket, (char *)&(disk->capacity), 8) == -1) {
262             PrintError("Error Receiving Capacity\n");
263             return -1;
264         }       
265
266         PrintDebug("Capacity: %p\n", (void *)(addr_t)disk->capacity);
267     }
268
269
270
271     return 0;
272 }
273
274
275 static int disk_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
276     struct disk_state * disk = (struct disk_state *)V3_Malloc(sizeof(struct disk_state));
277
278     char * ip_str = v3_cfg_val(cfg, "IP");
279     char * port_str = v3_cfg_val(cfg, "port");
280     char * disk_tag = v3_cfg_val(cfg, "tag");
281     char * dev_id = v3_cfg_val(cfg, "ID");
282
283     v3_cfg_tree_t * frontend_cfg = v3_cfg_subtree(cfg, "frontend");
284
285     PrintDebug("Registering Net disk at %s:%s disk=%s\n", ip_str, port_str, disk_tag);
286
287     strncpy(disk->disk_name, disk_tag, sizeof(disk->disk_name));
288     disk->ip_addr = v3_inet_addr(ip_str);
289     disk->port = atoi(port_str);
290     disk->vm = vm;
291
292     struct vm_device * dev = v3_allocate_device(dev_id, &dev_ops, disk);
293
294     if (v3_attach_device(vm, dev) == -1) {
295         PrintError("Could not attach device %s\n", dev_id);
296         return -1;
297     }
298
299     if (socket_init(disk) == -1) {
300         PrintError("could not initialize network connection\n");
301         return -1;
302     }
303
304     PrintDebug("Registering Disk\n");
305
306     if (v3_dev_connect_blk(vm, v3_cfg_val(frontend_cfg, "tag"), 
307                            &blk_ops, frontend_cfg, disk) == -1) {
308         PrintError("Could not connect %s to frontend\n", dev_id);
309         return -1;
310     }
311
312     PrintDebug("intialization done\n");
313
314     return 0;
315 }
316
317
318 device_register("NETDISK", disk_init)