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.


3052a9b7edf7b4fd460afa4a76446adb4f3f4618
[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     int socket;
42
43     uint32_t ip_addr;
44     uint16_t port;
45
46     char disk_name[32];
47
48 };
49
50
51 static int send_all(int socket, char * buf, int length) {
52     int bytes_sent = 0;
53     
54     PrintDebug("Sending %d bytes\n", length - bytes_sent);
55     while (bytes_sent < length) {
56         int tmp_bytes = V3_Send(socket, buf + bytes_sent, length - bytes_sent);
57         PrintDebug("Sent %d bytes\n", tmp_bytes);
58         
59         if (tmp_bytes == 0) {
60             PrintError("Connection Closed unexpectedly\n");
61             return -1;
62         }
63         
64         bytes_sent += tmp_bytes;
65     }
66     
67     return 0;
68 }
69
70
71 static int recv_all(int socket, char * buf, int length) {
72     int bytes_read = 0;
73     
74     PrintDebug("Reading %d bytes\n", length - bytes_read);
75     while (bytes_read < length) {
76         int tmp_bytes = V3_Recv(socket, buf + bytes_read, length - bytes_read);
77         PrintDebug("Received %d bytes\n", tmp_bytes);
78         
79         if (tmp_bytes == 0) {
80             PrintError("Connection Closed unexpectedly\n");
81             return -1;
82         }
83         
84         bytes_read += tmp_bytes;
85     }
86     
87     return 0;
88 }
89
90
91 // HDs always read 512 byte blocks... ?
92 static int read(uint8_t * buf, uint64_t lba, uint64_t num_bytes, void * private_data) {
93     struct disk_state * disk = (struct disk_state *)private_data ;
94     uint8_t status;
95     uint32_t ret_len = 0;
96     char nbd_cmd[4] = {0,0,0,0};
97     uint64_t offset = lba;
98     uint64_t length = num_bytes;
99
100     nbd_cmd[0] = NBD_READ_CMD;
101     
102     if (send_all(disk->socket, nbd_cmd, 4) == -1) {
103         PrintError("Error sending read command\n");
104         return -1;
105     }
106     
107     if (send_all(disk->socket, (char *)&offset, 8) == -1) {
108         PrintError("Error sending read offset\n");
109         return -1;
110     }
111
112     if (send_all(disk->socket, (char *)&length, 4) == -1) {
113         PrintError("Error sending read length\n");
114         return -1;
115     }
116
117     if (recv_all(disk->socket, (char *)&status, 1) == -1) {
118         PrintError("Error receiving status\n");
119         return -1;
120     }
121
122     if (status != NBD_STATUS_OK) {
123         PrintError("NBD Error....\n");
124         return -1;
125     }
126
127     PrintDebug("Reading Data Ret Length\n");
128
129     if (recv_all(disk->socket, (char *)&ret_len, 4) == -1) {
130         PrintError("Error receiving Return read length\n");
131         return -1;
132     }
133
134     if (ret_len != length) {
135         PrintError("Read length mismatch (req=%llu) (result=%u)\n", length, ret_len);
136         return -1;
137     }
138
139     PrintDebug("Reading Data (%d bytes)\n", ret_len);
140
141     if (recv_all(disk->socket, (char *)buf, ret_len) == -1) {
142         PrintError("Read Data Error\n");
143         return -1;
144     }
145
146     return 0;
147 }
148
149
150 static int write(uint8_t * buf, uint64_t lba, uint64_t num_bytes, void * private_data) {
151     struct disk_state * disk = (struct disk_state *)private_data ;
152     uint64_t offset = lba;
153     int length = num_bytes;
154     uint8_t status;
155     char nbd_cmd[4] = {0,0,0,0};
156
157     nbd_cmd[0] = NBD_WRITE_CMD;
158
159     if (send_all(disk->socket, nbd_cmd, 4) == -1) {
160         PrintError("Error sending write command\n");
161         return -1;
162     }
163
164     if (send_all(disk->socket, (char *)&offset, 8) == -1) {
165         PrintError("Error sending write offset\n");
166         return -1;
167     }
168
169     if (send_all(disk->socket, (char *)&length, 4) == -1) {
170         PrintError("Error sending write length\n");
171         return -1;
172     }
173
174     PrintDebug("Writing Data (%d bytes)\n", length);
175
176     if (send_all(disk->socket, (char *)buf, length) == -1) {
177         PrintError("Write Data Error\n");
178         return -1;
179     }
180
181     if (recv_all(disk->socket, (char *)&status, 1) == -1) {
182         PrintError("Error receiving status\n");
183         return -1;
184     }
185
186     if (status != NBD_STATUS_OK) {
187         PrintError("NBD Error....\n");
188         return -1;
189     }
190
191     return 0;
192 }
193
194
195 static uint64_t get_capacity(void * private_data) {
196     struct disk_state * disk = (struct disk_state *)private_data;
197
198     return disk->capacity;
199 }
200
201 static struct v3_dev_blk_ops blk_ops = {
202     .read = read, 
203     .write = write,
204     .get_capacity = get_capacity,
205 };
206
207
208
209
210
211 static int disk_free(struct vm_device * dev) {
212     return 0;
213 }
214
215 static struct v3_device_ops dev_ops = {
216     .free = disk_free,
217     .reset = NULL,
218     .start = NULL,
219     .stop = NULL,
220 };
221
222
223 static int socket_init(struct disk_state * disk) {
224     char header[64];
225     
226     PrintDebug("Intializing Net Disk\n");
227
228     disk->socket = V3_Create_TCP_Socket();
229
230     PrintDebug("DISK socket: %d\n", disk->socket);
231     PrintDebug("Connecting to: %s:%d\n", v3_inet_ntoa(disk->ip_addr), disk->port);
232
233     V3_Connect_To_IP(disk->socket, v3_ntohl(disk->ip_addr), disk->port);
234
235     PrintDebug("Connected to NBD server\n");
236
237     //snprintf(header, 64, "V3_NBD_1 %s\n", cd->disk_name);
238     strcpy(header, "V3_NBD_1 ");
239     strncat(header, disk->disk_name, 32);
240     strncat(header, "\n", 1);
241
242
243     if (send_all(disk->socket, header, strlen(header)) == -1) {
244         PrintError("Error connecting to Network Block Device: %s\n", disk->disk_name);
245         return -1;
246     }
247
248     // store local copy of capacity
249     {
250         char nbd_cmd[4] = {0,0,0,0};
251
252         nbd_cmd[0] = NBD_CAPACITY_CMD;
253         
254         if (send_all(disk->socket, nbd_cmd, 4) == -1) {
255             PrintError("Error sending capacity command\n");
256             return -1;
257         }
258
259         if (recv_all(disk->socket, (char *)&(disk->capacity), 8) == -1) {
260             PrintError("Error Receiving Capacity\n");
261             return -1;
262         }       
263
264         PrintDebug("Capacity: %p\n", (void *)(disk->capacity));
265     }
266
267
268
269     return 0;
270 }
271
272
273 static int disk_init(struct guest_info * vm, v3_cfg_tree_t * cfg) {
274     struct disk_state * disk = (struct disk_state *)V3_Malloc(sizeof(struct disk_state));
275
276     char * ip_str = v3_cfg_val(cfg, "IP");
277     char * port_str = v3_cfg_val(cfg, "port");
278     char * disk_tag = v3_cfg_val(cfg, "tag");
279     char * name = v3_cfg_val(cfg, "name");
280
281     v3_cfg_tree_t * frontend_cfg = v3_cfg_subtree(cfg, "frontend");
282
283     PrintDebug("Registering Net disk at %s:%s disk=%s\n", ip_str, port_str, disk_tag);
284
285     strncpy(disk->disk_name, disk_tag, sizeof(disk->disk_name));
286     disk->ip_addr = v3_inet_addr(ip_str);
287     disk->port = atoi(port_str);
288         
289     struct vm_device * dev = v3_allocate_device(name, &dev_ops, disk);
290
291     if (v3_attach_device(vm, dev) == -1) {
292         PrintError("Could not attach device %s\n", name);
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", name);
306         return -1;
307     }
308
309     PrintDebug("intialization done\n");
310
311     return 0;
312 }
313
314
315 device_register("NETDISK", disk_init)