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.


Linux kernel compatability enhancements (through 3.19)
[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 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,16,0)
166         link->sock->sk->sk_no_check = 1;
167 #else
168         link->sock->sk->sk_no_check_tx = 1;
169         link->sock->sk->sk_no_check_rx = 1;
170 #endif
171         release_sock(link->sock->sk);
172     }
173
174     memset(&link->sock_addr, 0, sizeof(struct sockaddr));
175
176     link->sock_addr.sin_family = AF_INET;
177     link->sock_addr.sin_addr.s_addr = link->dst_ip;
178     link->sock_addr.sin_port = htons(link->dst_port);
179
180
181     if ((err = link->sock->ops->connect(link->sock, (struct sockaddr *)&(link->sock_addr), sizeof(struct sockaddr), 0)) < 0) {
182         WARNING("Could not connect to remote VNET Server, error %d\n", err);
183         return -1;
184     }
185
186
187     palacios_spinlock_lock_irqsave(&(vnet_brg_s.lock), flags);
188     list_add(&(link->node), &(vnet_brg_s.link_list));
189     vnet_brg_s.num_links ++;
190     link->idx = ++ vnet_brg_s.link_idx;
191     vnet_htable_insert(vnet_brg_s.ip2link, (addr_t)&(link->dst_ip), (addr_t)link);
192     palacios_spinlock_unlock_irqrestore(&(vnet_brg_s.lock), flags);
193
194     INFO("VNET Bridge: Link created, ip 0x%x, port: %d, idx: %d, link: %p, protocol: %s\n", 
195            link->dst_ip, 
196            link->dst_port, 
197            link->idx, 
198            link,
199            ((link->sock_proto==UDP)?"UDP":"TCP"));
200
201     return link->idx;
202 }
203
204
205 uint32_t vnet_brg_add_link(uint32_t ip, uint16_t port, vnet_brg_proto_t proto){
206      struct vnet_link * new_link = NULL;
207      uint32_t idx;
208
209      new_link = palacios_alloc(sizeof(struct vnet_link));
210      if (!new_link) {
211         return -1;
212      }
213      memset(new_link, 0, sizeof(struct vnet_link));
214
215      new_link->dst_ip = ip;
216      new_link->dst_port = port;
217      new_link->sock_proto = proto;
218
219      idx = _create_link(new_link);
220      if (idx < 0) {
221         WARNING("Could not create link\n");
222         palacios_free(new_link);
223         return -1;
224      }
225
226      return idx;
227 }
228
229
230 int vnet_brg_link_stats(uint32_t link_idx, struct nic_statistics * stats){
231      struct vnet_link * link;
232
233      link = _link_by_idx(link_idx);
234      if(!link){
235          return -1;
236      }
237
238      memcpy(stats, &(link->stats), sizeof(*stats));
239
240      return 0;
241 }
242      
243
244 static int 
245 _udp_send(struct socket * sock, 
246          struct sockaddr_in * addr,
247          unsigned char * buf,  int len) {
248     struct msghdr msg;
249     struct iovec iov;
250     mm_segment_t oldfs;
251     int size = 0;
252
253           
254     if (sock->sk == NULL) {
255         return 0;
256     }
257
258     iov.iov_base = buf;
259     iov.iov_len = len;
260
261     msg.msg_flags = MSG_NOSIGNAL;
262     msg.msg_name = addr;
263     msg.msg_namelen = sizeof(struct sockaddr_in);
264     msg.msg_control = NULL;
265     msg.msg_controllen = 0;
266 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,19,0)
267     msg.msg_iov = &iov;
268     msg.msg_iovlen = 1;
269 #else
270     iov_iter_init(&(msg.msg_iter),WRITE,&iov,1,0);
271 #endif
272     msg.msg_control = NULL;
273
274     oldfs = get_fs();
275     set_fs(KERNEL_DS);
276     size = sock_sendmsg(sock, &msg, len);
277     set_fs(oldfs);
278
279     return size;
280 }
281
282
283
284 static int 
285 _udp_recv(struct socket * sock, 
286           struct sockaddr_in * addr,
287           unsigned char * buf, int len, int nonblocking) {
288     struct msghdr msg;
289     struct iovec iov;
290     mm_segment_t oldfs;
291     int size = 0;
292     
293     if (sock->sk == NULL) {
294         return 0;
295     }
296
297     iov.iov_base = buf;
298     iov.iov_len = len;
299     
300     msg.msg_flags = MSG_NOSIGNAL | (nonblocking ? MSG_DONTWAIT : 0);
301     msg.msg_name = addr;
302     msg.msg_namelen = sizeof(struct sockaddr_in);
303     msg.msg_control = NULL;
304     msg.msg_controllen = 0;
305 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,19,0)
306     msg.msg_iov = &iov;
307     msg.msg_iovlen = 1;
308 #else
309     iov_iter_init(&(msg.msg_iter),READ,&iov,1,0);
310 #endif
311     msg.msg_control = NULL;
312     
313     oldfs = get_fs();
314     set_fs(KERNEL_DS);
315     size = sock_recvmsg(sock, &msg, len, msg.msg_flags);
316         
317     set_fs(oldfs);
318     
319     return size;
320 }
321
322 /* send packets to VNET core */
323 static int 
324 send_to_palacios(unsigned char * buf, 
325                  int len,
326                  int link_id){
327     struct v3_vnet_pkt pkt;
328     memset(&pkt,0,sizeof(struct v3_vnet_pkt));
329     pkt.size = len;
330     pkt.dst_type = LINK_NOSET;
331     pkt.src_type = LINK_EDGE;
332     pkt.src_id = link_id;
333     memcpy(pkt.header, buf, ETHERNET_HEADER_LEN);
334     pkt.data = buf;
335
336     if(net_debug >= 2){
337         DEBUG("VNET Lnx Bridge: send pkt to VNET core (size: %d, src_id: %d, src_type: %d)\n", 
338                         pkt.size,  pkt.src_id, pkt.src_type);
339         if(net_debug >= 4){
340             print_hex_dump(NULL, "pkt_data: ", 0, 20, 20, pkt.data, pkt.size, 0);
341         }
342     }
343
344     vnet_brg_s.stats.pkt_to_vmm ++;
345
346     return v3_vnet_send_pkt(&pkt, NULL);
347 }
348
349
350 /* send packet to extern network */
351 static int 
352 bridge_send_pkt(struct v3_vm_info * vm, 
353                 struct v3_vnet_pkt * pkt, 
354                 void * private_data) {
355     struct vnet_link * link = NULL;
356
357     if(net_debug >= 2){
358         DEBUG("VNET Lnx Host Bridge: packet received from VNET Core ... pkt size: %d, link: %d\n",
359                         pkt->size,
360                         pkt->dst_id);
361         if(net_debug >= 4){
362             print_hex_dump(NULL, "pkt_data: ", 0, 20, 20, pkt->data, pkt->size, 0);
363         }
364     }
365
366     vnet_brg_s.stats.pkt_from_vmm ++;
367
368     link = _link_by_idx(pkt->dst_id);
369     if (link != NULL) {
370         switch(link->sock_proto){
371             case UDP:
372                 _udp_send(link->sock, &(link->sock_addr), pkt->data, pkt->size);
373                 vnet_brg_s.stats.pkt_to_phy ++;
374                 break;
375             case TCP:
376                 vnet_brg_s.stats.pkt_to_phy ++;
377                 break;  
378
379             default:
380                 WARNING("VNET Server: Invalid Link Protocol\n");
381                 vnet_brg_s.stats.pkt_drop_vmm ++;
382         }
383         link->stats.tx_bytes += pkt->size;
384         link->stats.tx_pkts ++;
385     } else {
386         INFO("VNET Bridge Linux Host: wrong dst link, idx: %d, discarding the packet\n", pkt->dst_id);
387         vnet_brg_s.stats.pkt_drop_vmm ++;
388     }
389
390     return 0;
391 }
392
393
394 static int init_vnet_serv(void) {
395     int protocol;
396     int err;
397
398     switch(vnet_brg_s.serv_proto){
399         case UDP:
400             protocol = IPPROTO_UDP;
401             break;
402         case TCP:
403             protocol = IPPROTO_TCP;
404             break;
405
406         default:
407            WARNING("Unsupported VNET Server Protocol\n");
408             return -1;
409     }
410          
411     if ((err = sock_create(AF_INET, SOCK_DGRAM, protocol, &vnet_brg_s.serv_sock)) < 0) {
412         WARNING("Could not create VNET server socket, error: %d\n", err);
413         return -1;
414     }
415
416     if (vnet_brg_s.serv_proto == UDP) { 
417         // No UDP checksumming is done
418         lock_sock(vnet_brg_s.serv_sock->sk);
419 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,16,0)
420         vnet_brg_s.serv_sock->sk->sk_no_check = 1;
421 #else
422         vnet_brg_s.serv_sock->sk->sk_no_check_tx = 1;
423         vnet_brg_s.serv_sock->sk->sk_no_check_rx = 1;
424 #endif
425         release_sock(vnet_brg_s.serv_sock->sk);
426     }
427
428     memset(&vnet_brg_s.serv_addr, 0, sizeof(struct sockaddr));
429
430     vnet_brg_s.serv_addr.sin_family = AF_INET;
431     vnet_brg_s.serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
432     vnet_brg_s.serv_addr.sin_port = htons(VNET_SERVER_PORT);
433
434     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) {
435         WARNING("Could not bind VNET server socket to port %d, error: %d\n", VNET_SERVER_PORT, err);
436         return -1;
437     }
438
439     INFO("VNET server bind to port: %d\n", VNET_SERVER_PORT);
440
441     if(vnet_brg_s.serv_proto == TCP){
442         if((err = vnet_brg_s.serv_sock->ops->listen(vnet_brg_s.serv_sock, 32)) < 0){
443             WARNING("VNET Server error listening on port %d, error %d\n", VNET_SERVER_PORT, err);
444             return -1;
445         }
446     }
447
448
449
450     return 0;
451 }
452
453 static int _udp_server(void * arg) {
454     unsigned char * pkt;
455     struct sockaddr_in pkt_addr;
456     struct vnet_link * link = NULL;
457     int len;
458     uint64_t noprogress_count;
459
460     INFO("Palacios VNET Bridge: UDP receiving server ..... \n");
461
462     pkt = palacios_alloc(MAX_PACKET_LEN);
463
464     if (!pkt) { 
465         ERROR("Unable to allocate packet in VNET UDP Server\n");
466         return -1;
467     }
468
469     
470     noprogress_count=0;
471
472     while (!kthread_should_stop()) {
473
474         // This is a NONBLOCKING receive
475         // If we block here, we will never detect that this thread
476         // is being signaled to stop, plus we might go uninterrupted on this core
477         // blocking out access to other threads - leave this NONBLOCKING
478         // unless you know what you are doing
479         len = _udp_recv(vnet_brg_s.serv_sock, &pkt_addr, pkt, MAX_PACKET_LEN, 1); 
480
481
482         // If it would have blocked, we have no packet, and so
483         // we will give other threads on this core a chance
484         if (len==-EAGAIN || len==-EWOULDBLOCK || len==-EINTR) { 
485
486             // avoid rollover in the counter out of paranoia
487             if (! ((noprogress_count + 1) < noprogress_count)) { 
488                 noprogress_count++;
489             }
490             
491             // adaptively select yielding strategy depending on
492             // whether we are making progress
493             if ((!VNET_ADAPTIVE_BRIDGE) || (noprogress_count < VNET_NOPROGRESS_LIMIT)) { 
494                 // Likely making progress, do fast yield so we 
495                 // come back immediately if there is no other action
496                 palacios_yield_cpu();
497             } else {
498                 // Likely not making progress, do potentially slow
499                 // yield - we won't come back for until VNET_YIELD_TIME_USEC has passed
500                 palacios_sleep_cpu(VNET_YIELD_TIME_USEC);
501             }
502
503             continue;
504         }
505         
506
507         // Something interesting has happened, therefore progress!
508         noprogress_count=0;
509             
510
511         if(len < 0) {
512             WARNING("Receive error: Could not get packet, error %d\n", len);
513             continue;
514         }
515
516         link = _link_by_ip(pkt_addr.sin_addr.s_addr);
517
518         if (link == NULL){
519             WARNING("VNET Server: No VNET Link matches the src IP\n");
520             vnet_brg_s.stats.pkt_drop_phy ++;
521             continue;
522         }
523         
524         vnet_brg_s.stats.pkt_from_phy ++;
525         link->stats.rx_bytes += len;
526         link->stats.rx_pkts ++;
527
528         send_to_palacios(pkt, len, link->idx);
529     }
530
531     INFO("VNET Server: UDP thread exiting\n");
532
533     palacios_free(pkt);
534
535     return 0;
536 }
537
538
539 static int _rx_server(void * arg) {
540     
541     if(vnet_brg_s.serv_proto == UDP){
542         _udp_server(NULL);
543     }else if(vnet_brg_s.serv_proto == TCP) {
544         //accept new connection
545         //use select to receive pkt from physical network
546         //or create new kthread to handle each connection?
547         WARNING("VNET Server: TCP is not currently supported\n");
548         return -1;
549     }else {
550         WARNING ("VNET Server: Unsupported Protocol\n");
551         return -1;
552     }
553
554     return 0;
555 }
556
557 static inline unsigned int hash_fn(addr_t hdr_ptr) {    
558     return vnet_hash_buffer((uint8_t *)hdr_ptr, sizeof(uint32_t));
559 }
560
561 static inline int hash_eq(addr_t key1, addr_t key2) {   
562     return (memcmp((uint8_t *)key1, (uint8_t *)key2, sizeof(uint32_t)) == 0);
563 }
564
565
566 int vnet_bridge_init(void) {
567     struct v3_vnet_bridge_ops bridge_ops;
568
569     if(vnet_brg_s.status != 0) {
570         return -1;
571     }   
572     vnet_brg_s.status = 1;      
573         
574     memset(&vnet_brg_s, 0, sizeof(struct vnet_brg_state));
575
576     INIT_LIST_HEAD(&(vnet_brg_s.link_list));
577     palacios_spinlock_init(&(vnet_brg_s.lock));
578
579     vnet_brg_s.serv_proto = UDP;
580
581     vnet_brg_s.ip2link = vnet_create_htable(10, hash_fn, hash_eq);
582     if(vnet_brg_s.ip2link == NULL){
583         WARNING("Failure to initiate VNET link hashtable\n");
584         return -1;
585     }
586         
587     if(init_vnet_serv() < 0){
588         WARNING("Failure to initiate VNET server\n");
589         return -1;
590     }
591
592     vnet_brg_s.serv_thread = kthread_run(_rx_server, NULL, "vnet_brgd");
593
594     bridge_ops.input = bridge_send_pkt;
595     bridge_ops.poll = NULL;
596         
597     if( v3_vnet_add_bridge(NULL, &bridge_ops, HOST_LNX_BRIDGE, NULL) < 0){
598         WARNING("VNET LNX Bridge: Fails to register bridge to VNET core");
599     }
600
601     INFO("VNET Linux Bridge initiated\n");
602
603     return 0;
604 }
605
606
607 void vnet_bridge_deinit(void){
608
609     INFO("VNET LNX Bridge Deinit Started\n");
610
611     v3_vnet_del_bridge(HOST_LNX_BRIDGE);
612
613     //DEBUG("Stopping bridge service thread\n");
614
615     kthread_stop(vnet_brg_s.serv_thread);
616
617     //DEBUG("Releasing bridee service socket\n");
618
619     vnet_brg_s.serv_sock->ops->release(vnet_brg_s.serv_sock);
620
621     //DEBUG("Deiniting bridge links\n");
622
623     deinit_links_list();
624
625     //DEBUG("Freeing bridge hash tables\n");
626
627     vnet_free_htable(vnet_brg_s.ip2link, 0, 0);
628
629     vnet_brg_s.status = 0;
630
631     palacios_spinlock_deinit(&(vnet_brg_s.lock));
632
633     INFO("VNET LNX Bridge Deinit Finished\n");
634 }
635
636