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.


Extensive, Pedantic Error Checking in Linux module, especially for memory
[palacios.git] / linux_module / palacios-vnet-brg.c
1 /* 
2  * Palacios VNET Host Bridge
3  * (c) Lei Xia  2010
4  */ 
5
6 #include <linux/spinlock.h>
7 #include <linux/seq_file.h>
8 #include <linux/proc_fs.h>
9 #include <asm/uaccess.h>
10 #include <linux/inet.h>
11 #include <linux/kthread.h>
12
13 #include <linux/netdevice.h>
14 #include <linux/ip.h>
15 #include <linux/in.h>
16 #include <linux/net.h>
17 #include <linux/string.h>
18 #include <linux/preempt.h>
19 #include <linux/sched.h>
20 #include <asm/msr.h>
21
22 #include <vnet/vnet.h>
23 #include <vnet/vnet_hashtable.h>
24 #include "palacios-vnet.h"
25 #include "palacios.h"
26
27
28 #define VNET_SERVER_PORT 9000
29
30 #define VNET_YIELD_TIME_USEC 1000
31
32 struct vnet_link {
33     uint32_t dst_ip;
34     uint16_t dst_port;
35     
36     struct socket * sock;
37     struct sockaddr_in sock_addr;
38     vnet_brg_proto_t sock_proto;
39
40     struct nic_statistics stats;
41
42     uint32_t idx;
43
44     struct list_head node;
45 };
46
47
48 struct vnet_brg_state {
49     uint8_t status;
50
51     uint32_t num_links;
52     uint32_t link_idx;
53     struct list_head link_list;
54     struct hashtable *ip2link;
55
56     spinlock_t lock;
57
58     struct socket * serv_sock;
59     struct sockaddr_in serv_addr;
60     vnet_brg_proto_t serv_proto;
61         
62     struct task_struct * serv_thread;
63
64     void * brg_data; /* private data from vnet_core */
65
66     struct vnet_brg_stats stats;
67 };
68
69
70 static struct vnet_brg_state vnet_brg_s;
71
72
73 int vnet_brg_stats(struct vnet_brg_stats * stats){
74     memcpy(stats, &(vnet_brg_s.stats), sizeof(*stats));
75
76     return 0;
77 }
78
79 static inline struct vnet_link * _link_by_ip(uint32_t ip) {
80     return (struct vnet_link *)vnet_htable_search(vnet_brg_s.ip2link, (addr_t)&ip);
81 }
82
83 static inline struct vnet_link * _link_by_idx(int idx) {
84     struct vnet_link * link = NULL;
85
86     list_for_each_entry(link, &(vnet_brg_s.link_list), node) {
87                 
88         if (link->idx == idx) {
89             return link;
90         }
91     }
92     return NULL;
93 }
94
95
96 static void _delete_link(struct vnet_link * link){
97     unsigned long flags;
98
99     link->sock->ops->release(link->sock);
100
101     spin_lock_irqsave(&(vnet_brg_s.lock), flags);
102     list_del(&(link->node));
103     vnet_htable_remove(vnet_brg_s.ip2link, (addr_t)&(link->dst_ip), 0);
104     vnet_brg_s.num_links --;
105     spin_unlock_irqrestore(&(vnet_brg_s.lock), flags);
106
107     INFO("VNET Bridge: Link deleted, ip 0x%x, port: %d, idx: %d\n", 
108            link->dst_ip, 
109            link->dst_port, 
110            link->idx);
111
112     palacios_free(link);
113     link = NULL;
114 }
115
116 void vnet_brg_delete_link(uint32_t idx){
117     struct vnet_link * link = _link_by_idx(idx);
118
119     if(link){
120         _delete_link(link);
121     }
122 }
123
124 static void deinit_links_list(void){
125     struct vnet_link * link, * tmp_link;
126
127     list_for_each_entry_safe(link, tmp_link, &(vnet_brg_s.link_list), node) {
128         _delete_link(link);
129     }
130 }
131
132 static uint32_t _create_link(struct vnet_link * link) {
133     int err;
134     unsigned long flags;
135     int protocol;
136
137     switch(link->sock_proto){
138         case UDP:
139             protocol = IPPROTO_UDP;
140             break;
141         case TCP:
142             protocol = IPPROTO_TCP;
143             break;
144
145         default:
146            WARNING("Unsupported VNET Server Protocol\n");
147             return -1;
148     }
149    
150     if ((err = sock_create(AF_INET, SOCK_DGRAM, protocol, &link->sock)) < 0) {
151         WARNING("Could not create socket for VNET Link, error %d\n", err);
152         return -1;
153     }
154
155     memset(&link->sock_addr, 0, sizeof(struct sockaddr));
156
157     link->sock_addr.sin_family = AF_INET;
158     link->sock_addr.sin_addr.s_addr = link->dst_ip;
159     link->sock_addr.sin_port = htons(link->dst_port);
160
161     if ((err = link->sock->ops->connect(link->sock, (struct sockaddr *)&(link->sock_addr), sizeof(struct sockaddr), 0) < 0)) {
162         WARNING("Could not connect to remote VNET Server, error %d\n", err);
163         return -1;
164     }
165
166     spin_lock_irqsave(&(vnet_brg_s.lock), flags);
167     list_add(&(link->node), &(vnet_brg_s.link_list));
168     vnet_brg_s.num_links ++;
169     link->idx = ++ vnet_brg_s.link_idx;
170     vnet_htable_insert(vnet_brg_s.ip2link, (addr_t)&(link->dst_ip), (addr_t)link);
171     spin_unlock_irqrestore(&(vnet_brg_s.lock), flags);
172
173     INFO("VNET Bridge: Link created, ip 0x%x, port: %d, idx: %d, link: %p, protocol: %s\n", 
174            link->dst_ip, 
175            link->dst_port, 
176            link->idx, 
177            link,
178            ((link->sock_proto==UDP)?"UDP":"TCP"));
179
180     return link->idx;
181 }
182
183
184 uint32_t vnet_brg_add_link(uint32_t ip, uint16_t port, vnet_brg_proto_t proto){
185      struct vnet_link * new_link = NULL;
186      uint32_t idx;
187
188      new_link = palacios_alloc(sizeof(struct vnet_link));
189      if (!new_link) {
190         return -1;
191      }
192      memset(new_link, 0, sizeof(struct vnet_link));
193
194      new_link->dst_ip = ip;
195      new_link->dst_port = port;
196      new_link->sock_proto = proto;
197
198      idx = _create_link(new_link);
199      if (idx < 0) {
200         WARNING("Could not create link\n");
201         palacios_free(new_link);
202         return -1;
203      }
204
205      return idx;
206 }
207
208
209 int vnet_brg_link_stats(uint32_t link_idx, struct nic_statistics * stats){
210      struct vnet_link * link;
211
212      link = _link_by_idx(link_idx);
213      if(!link){
214          return -1;
215      }
216
217      memcpy(stats, &(link->stats), sizeof(*stats));
218
219      return 0;
220 }
221      
222
223 static int 
224 _udp_send(struct socket * sock, 
225          struct sockaddr_in * addr,
226          unsigned char * buf,  int len) {
227     struct msghdr msg;
228     struct iovec iov;
229     mm_segment_t oldfs;
230     int size = 0;
231
232           
233     if (sock->sk == NULL) {
234         return 0;
235     }
236
237     iov.iov_base = buf;
238     iov.iov_len = len;
239
240     msg.msg_flags = 0;
241     msg.msg_name = addr;
242     msg.msg_namelen = sizeof(struct sockaddr_in);
243     msg.msg_control = NULL;
244     msg.msg_controllen = 0;
245     msg.msg_iov = &iov;
246     msg.msg_iovlen = 1;
247     msg.msg_control = NULL;
248
249     oldfs = get_fs();
250     set_fs(KERNEL_DS);
251     size = sock_sendmsg(sock, &msg, len);
252     set_fs(oldfs);
253
254     return size;
255 }
256
257
258
259 static int 
260 _udp_recv(struct socket * sock, 
261           struct sockaddr_in * addr,
262           unsigned char * buf, int len, int nonblocking) {
263     struct msghdr msg;
264     struct iovec iov;
265     mm_segment_t oldfs;
266     int size = 0;
267     
268     if (sock->sk == NULL) {
269         return 0;
270     }
271
272     iov.iov_base = buf;
273     iov.iov_len = len;
274     
275     msg.msg_flags = MSG_NOSIGNAL | (nonblocking ? MSG_DONTWAIT : 0);
276     msg.msg_name = addr;
277     msg.msg_namelen = sizeof(struct sockaddr_in);
278     msg.msg_control = NULL;
279     msg.msg_controllen = 0;
280     msg.msg_iov = &iov;
281     msg.msg_iovlen = 1;
282     msg.msg_control = NULL;
283     
284     oldfs = get_fs();
285     set_fs(KERNEL_DS);
286     size = sock_recvmsg(sock, &msg, len, msg.msg_flags);
287         
288     set_fs(oldfs);
289     
290     return size;
291 }
292
293 /* send packets to VNET core */
294 static int 
295 send_to_palacios(unsigned char * buf, 
296                  int len,
297                  int link_id){
298     struct v3_vnet_pkt pkt;
299     pkt.size = len;
300     pkt.src_type = LINK_EDGE;
301     pkt.src_id = link_id;
302     memcpy(pkt.header, buf, ETHERNET_HEADER_LEN);
303     pkt.data = buf;
304
305     if(net_debug >= 2){
306         DEBUG("VNET Lnx Bridge: send pkt to VNET core (size: %d, src_id: %d, src_type: %d)\n", 
307                         pkt.size,  pkt.src_id, pkt.src_type);
308         if(net_debug >= 4){
309             print_hex_dump(NULL, "pkt_data: ", 0, 20, 20, pkt.data, pkt.size, 0);
310         }
311     }
312
313     vnet_brg_s.stats.pkt_to_vmm ++;
314
315     return v3_vnet_send_pkt(&pkt, NULL);
316 }
317
318
319 /* send packet to extern network */
320 static int 
321 bridge_send_pkt(struct v3_vm_info * vm, 
322                 struct v3_vnet_pkt * pkt, 
323                 void * private_data) {
324     struct vnet_link * link;
325
326     if(net_debug >= 2){
327         DEBUG("VNET Lnx Host Bridge: packet received from VNET Core ... pkt size: %d, link: %d\n",
328                         pkt->size,
329                         pkt->dst_id);
330         if(net_debug >= 4){
331             print_hex_dump(NULL, "pkt_data: ", 0, 20, 20, pkt->data, pkt->size, 0);
332         }
333     }
334
335     vnet_brg_s.stats.pkt_from_vmm ++;
336
337     link = _link_by_idx(pkt->dst_id);
338     if (link != NULL) {
339         switch(link->sock_proto){
340             case UDP:
341                 _udp_send(link->sock, &(link->sock_addr), pkt->data, pkt->size);
342                 vnet_brg_s.stats.pkt_to_phy ++;
343                 break;
344             case TCP:
345                 vnet_brg_s.stats.pkt_to_phy ++;
346                 break;  
347
348             default:
349                 WARNING("VNET Server: Invalid Link Protocol\n");
350                 vnet_brg_s.stats.pkt_drop_vmm ++;
351         }
352         link->stats.tx_bytes += pkt->size;
353         link->stats.tx_pkts ++;
354     } else {
355         INFO("VNET Bridge Linux Host: wrong dst link, idx: %d, discarding the packet\n", pkt->dst_id);
356         vnet_brg_s.stats.pkt_drop_vmm ++;
357     }
358
359     return 0;
360 }
361
362
363 static int init_vnet_serv(void) {
364     int protocol;
365     int err;
366
367     switch(vnet_brg_s.serv_proto){
368         case UDP:
369             protocol = IPPROTO_UDP;
370             break;
371         case TCP:
372             protocol = IPPROTO_TCP;
373             break;
374
375         default:
376            WARNING("Unsupported VNET Server Protocol\n");
377             return -1;
378     }
379          
380     if ((err = sock_create(AF_INET, SOCK_DGRAM, protocol, &vnet_brg_s.serv_sock)) < 0) {
381         WARNING("Could not create VNET server socket, error: %d\n", err);
382         return -1;
383     }
384
385     memset(&vnet_brg_s.serv_addr, 0, sizeof(struct sockaddr));
386
387     vnet_brg_s.serv_addr.sin_family = AF_INET;
388     vnet_brg_s.serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
389     vnet_brg_s.serv_addr.sin_port = htons(VNET_SERVER_PORT);
390
391     if ((err = vnet_brg_s.serv_sock->ops->bind(vnet_brg_s.serv_sock, (struct sockaddr *)&(vnet_brg_s.serv_addr), sizeof(struct sockaddr))) < 0) {
392         WARNING("Could not bind VNET server socket to port %d, error: %d\n", VNET_SERVER_PORT, err);
393         return -1;
394     }
395
396     INFO("VNET server bind to port: %d\n", VNET_SERVER_PORT);
397
398     if(vnet_brg_s.serv_proto == TCP){
399         if((err = vnet_brg_s.serv_sock->ops->listen(vnet_brg_s.serv_sock, 32)) < 0){
400             WARNING("VNET Server error listening on port %d, error %d\n", VNET_SERVER_PORT, err);
401             return -1;
402         }
403     }
404
405     return 0;
406 }
407
408 static int _udp_server(void * arg) {
409     unsigned char * pkt;
410     struct sockaddr_in pkt_addr;
411     struct vnet_link * link = NULL;
412     int len;
413
414     INFO("Palacios VNET Bridge: UDP receiving server ..... \n");
415
416     pkt = palacios_alloc(MAX_PACKET_LEN);
417
418     if (!pkt) { 
419         ERROR("Unable to allocate packet in VNET UDP Server\n");
420         return -1;
421     }
422
423
424     while (!kthread_should_stop()) {
425
426         // This is a NONBLOCKING receive
427         // If we block here, we will never detect that this thread
428         // is being signaled to stop, plus we might go uninterrupted on this core
429         // blocking out access to other threads - leave this NONBLOCKING
430         // unless you know what you are doing
431         len = _udp_recv(vnet_brg_s.serv_sock, &pkt_addr, pkt, MAX_PACKET_LEN, 1); 
432
433
434         // If it would have blocked, we have no packet, and so
435         // we will give other threads on this core a chance
436         if (len==-EAGAIN || len==-EWOULDBLOCK || len==-EINTR) { 
437             palacios_yield_cpu_timed(VNET_YIELD_TIME_USEC);
438             continue;
439         }
440         
441         if(len < 0) {
442             WARNING("Receive error: Could not get packet, error %d\n", len);
443             continue;
444         }
445
446         link = _link_by_ip(pkt_addr.sin_addr.s_addr);
447
448         if (link == NULL){
449             WARNING("VNET Server: No VNET Link matches the src IP\n");
450             vnet_brg_s.stats.pkt_drop_phy ++;
451             continue;
452         }
453         
454         vnet_brg_s.stats.pkt_from_phy ++;
455         link->stats.rx_bytes += len;
456         link->stats.rx_pkts ++;
457
458         send_to_palacios(pkt, len, link->idx);
459     }
460
461     INFO("VNET Server: UDP thread exiting\n");
462
463     palacios_free(pkt);
464
465     return 0;
466 }
467
468
469 static int _rx_server(void * arg) {
470     
471     if(vnet_brg_s.serv_proto == UDP){
472         _udp_server(NULL);
473     }else if(vnet_brg_s.serv_proto == TCP) {
474         //accept new connection
475         //use select to receive pkt from physical network
476         //or create new kthread to handle each connection?
477         WARNING("VNET Server: TCP is not currently supported\n");
478         return -1;
479     }else {
480         WARNING ("VNET Server: Unsupported Protocol\n");
481         return -1;
482     }
483
484     return 0;
485 }
486
487 static inline unsigned int hash_fn(addr_t hdr_ptr) {    
488     return vnet_hash_buffer((uint8_t *)hdr_ptr, sizeof(uint32_t));
489 }
490
491 static inline int hash_eq(addr_t key1, addr_t key2) {   
492     return (memcmp((uint8_t *)key1, (uint8_t *)key2, sizeof(uint32_t)) == 0);
493 }
494
495
496 int vnet_bridge_init(void) {
497     struct v3_vnet_bridge_ops bridge_ops;
498
499     if(vnet_brg_s.status != 0) {
500         return -1;
501     }   
502     vnet_brg_s.status = 1;      
503         
504     memset(&vnet_brg_s, 0, sizeof(struct vnet_brg_state));
505
506     INIT_LIST_HEAD(&(vnet_brg_s.link_list));
507     spin_lock_init(&(vnet_brg_s.lock));
508
509     vnet_brg_s.serv_proto = UDP;
510
511     vnet_brg_s.ip2link = vnet_create_htable(10, hash_fn, hash_eq);
512     if(vnet_brg_s.ip2link == NULL){
513         WARNING("Failure to initiate VNET link hashtable\n");
514         return -1;
515     }
516         
517     if(init_vnet_serv() < 0){
518         WARNING("Failure to initiate VNET server\n");
519         return -1;
520     }
521
522     vnet_brg_s.serv_thread = kthread_run(_rx_server, NULL, "vnet_brgd");
523
524     bridge_ops.input = bridge_send_pkt;
525     bridge_ops.poll = NULL;
526         
527     if( v3_vnet_add_bridge(NULL, &bridge_ops, HOST_LNX_BRIDGE, NULL) < 0){
528         WARNING("VNET LNX Bridge: Fails to register bridge to VNET core");
529     }
530
531     INFO("VNET Linux Bridge initiated\n");
532
533     return 0;
534 }
535
536
537 void vnet_bridge_deinit(void){
538
539     INFO("VNET LNX Bridge Deinit Started\n");
540
541     v3_vnet_del_bridge(HOST_LNX_BRIDGE);
542
543     //DEBUG("Stopping bridge service thread\n");
544
545     kthread_stop(vnet_brg_s.serv_thread);
546
547     //DEBUG("Releasing bridee service socket\n");
548
549     vnet_brg_s.serv_sock->ops->release(vnet_brg_s.serv_sock);
550
551     //DEBUG("Deiniting bridge links\n");
552
553     deinit_links_list();
554
555     //DEBUG("Freeing bridge hash tables\n");
556
557     vnet_free_htable(vnet_brg_s.ip2link, 0, 0);
558
559     vnet_brg_s.status = 0;
560
561     INFO("VNET LNX Bridge Deinit Finished\n");
562 }
563
564