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.
6 * The V3VEE Project is a joint project between Northwestern University
7 * and the University of New Mexico. You can find out more at
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.
14 * Author: Jack Lange <jarusl@cs.northwestern.edu>
16 * This is free software. You are permitted to use,
17 * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
28 #include <sys/types.h>
30 #elif defined(WIN32) && !defined(__CYGWIN__)
37 #define NBD_KEY "V3_NBD_1"
40 #define DEFAULT_LOG_FILE "./status.log"
41 #define DEFAULT_CONF_FILE "v3_nbd.ini"
44 #define DEFAULT_PORT 9500
45 #define MAX_STRING_SIZE 1024
48 #define LOGFILE_TAG "logfile"
49 #define PORT_TAG "port"
50 #define DISKS_TAG "disks"
52 // Turn on 64 bit file offset support (see 'man fseeko')
53 #define _FILE_OFFSET_BITS 64
57 //using namespace __gnu_cxx;
61 bool operator()(const SOCK sock1, const SOCK sock2) const {
62 return sock1 == sock2;
67 // Server Port that we'll listen on
70 // List of disks being served
71 // eqstr from vtl (config.h)
72 map<const string, struct disk_info *, eqstr> disks;
74 // List of open connections
75 map<SOCK, struct disk_info *, eqsock> conns;
79 static const int enable_debug = 1;
83 int config_nbd(string conf_file_name);
84 int serv_loop(int serv_sock);
85 void setup_disk(string disk_tag, config_t &config_map);
87 int handle_new_connection(SOCK new_conn);
90 int __main (int argc, char ** argv);
96 int main(int argc, char ** argv) {
97 return __main(argc, argv);
108 int __main (int argc, char ** argv) {
117 config_file = string(argv[1]);
119 config_file = DEFAULT_CONF_FILE;
123 if (config_nbd(config_file) == -1) {
124 cerr << "Configuration Error" << endl;
128 // setup network sockets
129 serv_sock = CreateAndSetupTcpSocket();
131 if (serv_sock == -1) {
132 cerr << "Could not create server socket, exiting..." << endl;
136 if (BindSocket(serv_sock, server_port) == -1) {
137 cerr << "Could not bind socket to port: " << server_port << endl;
141 if (ListenSocket(serv_sock) == -1) {
142 cerr << "Could not listen on server socket (port=" << server_port << ")" << endl;
147 vtl_debug("Starting Server Loop\n");
148 serv_loop(serv_sock);
155 int serv_loop(int serv_sock) {
156 fd_set all_set, read_set;
158 RawEthernetPacket pkt;
161 list<SOCK> pending_cons;
164 FD_SET(serv_sock, &all_set);
172 nready = select(max_fd + 1, &read_set, &write_set, NULL, NULL);
175 if (errno == EINTR) {
178 vtl_debug("Select returned error\n");
184 if (FD_ISSET(serv_sock, &read_set)) {
186 struct sockaddr_in rem_addr;
187 socklen_t addr_len = sizeof(struct sockaddr_in);
189 conn_socket = accept(serv_sock, (struct sockaddr *)&rem_addr, &addr_len);
191 if (conn_socket < 0) {
192 if (errno == EINTR) {
195 vtl_debug("Accept returned error\n");
200 pending_cons.push_front(conn_socket);
202 FD_SET(conn_socket, &all_set);
204 if (conn_socket > max_fd) {
205 max_fd = conn_socket;
208 if (--nready <= 0) continue;
211 // handle open connections
214 // check pending connections
216 for (list<SOCK>::iterator pending_iter = pending_cons.begin();
217 pending_iter != pending_cons.end();
220 if (handle_new_connection(pending_iter.value()) == -1) {
224 pending_cons.remove(pending_iter);
226 if (--nready <= 0) break;
229 if (nready <= 0) continue;
239 int serv_loop(iface_t * iface, SOCK vnet_sock, struct vnet_config * vnet_info) {
241 RawEthernetPacket pkt;
242 WSANETWORKEVENTS net_events;
246 events[VNET_EVENT] = WSACreateEvent();
248 WSAEventSelect(vnet_sock, events[VNET_EVENT], FD_READ | FD_CLOSE);
249 events[IF_EVENT] = if_get_event(iface);
252 event_i = WSAWaitForMultipleEvents(2, events, false, WSA_INFINITE, false);
253 cout << "Wait returned" << endl;
255 if (event_i == WAIT_FAILED) {
256 cout << "ERROR: " << GetLastError() << endl;
259 event_i -= WAIT_OBJECT_0;
261 if (event_i == VNET_EVENT) {
263 if (WSAEnumNetworkEvents(vnet_sock, events[event_i], &net_events) == SOCKET_ERROR) {
264 cout << "EnumEventsError: " << WSAGetLastError() << endl;
267 if (net_events.lNetworkEvents & FD_READ) {
271 if (vnet_info->link_type == TCP_LINK) {
272 pkt.Unserialize(vnet_sock);
273 } else if (vnet_info->link_type == UDP_LINK) {
274 pkt.UdpUnserialize(vnet_sock);
277 process_outbound_pkt(&pkt);
279 if_write_pkt(iface, &pkt);
281 } else if (net_events.lNetworkEvents & FD_CLOSE) {
297 * <NBD_KEY> <Disk Tag>\n
300 int handle_new_connection(SOCK new_conn) {
304 struct disk_info * disk = NULL;
306 GetLine(new_conn, input);
309 istringstream is(input, istringstream::in);
310 is >> key_str >> tag_str;
313 if (key_str != NBD_KEY) {
314 vtl_debug("Error: Invalid NBD key string (%s)\n", key_str.c_str());
318 if (disks[tag_str].count() == 0) {
319 vtl_debug("Error: Requesting disk that does not exist (%s)\n", tag_str.c_str());
323 // Check if already assigned...
324 disk = disks[tag_str];
330 conns[new_conn] = disk;
336 int config_nbd(string conf_file_name) {
339 if (read_config(conf_file_name, &config_map) != 0) {
340 cerr << "Could not read config file..." << endl;
344 if (config_map.count(PORT_TAG) > 0) {
345 server_port = atoi(config_map[PORT_TAG].c_str());
347 server_port = DEFAULT_PORT;
350 if (config_map.count(DISKS_TAG) > 0) {
351 istringstream disk_stream(config_map[DISKS_TAG], istringstream::in);
355 while (disk_stream >> disk_tag) {
357 if (i >= MAX_DISKS) {
358 cerr << "You specified too many disks, truncating..." << endl;
362 setup_disk(disk_tag, config_map);
366 cerr << "Must specify a set of disks" << endl;
370 if (config_map.count(LOGFILE_TAG) == 0) {
371 config_map[LOGFILE_TAG] = DEFAULT_LOG_FILE;
374 vtl_debug_init(config_map[LOGFILE_TAG], enable_debug);
379 void setup_disk(string disk_tag, config_t &config_map) {
380 string file_tag = disk_tag + ".file";
381 string type_tag = disk_tag + ".type";
386 cout << "Setting up " << disk_tag.c_str() << endl;
388 if ((config_map.count(file_tag) == 0) &&
389 (config_map.count(type_tag) == 0)) {
390 cerr << "Missing Disk configuration directive for " << disk_tag << endl;
393 type = config_map[type_tag];
396 disks[disk->tag] = new raw_disk(config_map[file_tag]);;
397 } else if (type == "ISO") {
413 cout << "Usage: v3_nbd [config_file]" << endl;