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.


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