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.


VNET fixes and adaptation to new API
[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     kfree(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 = kmalloc(sizeof(struct vnet_link), GFP_KERNEL);
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         kfree(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 = kmalloc(MAX_PACKET_LEN, GFP_KERNEL);
417
418
419     while (!kthread_should_stop()) {
420
421         // This is a NONBLOCKING receive
422         // If we block here, we will never detect that this thread
423         // is being signaled to stop, plus we might go uninterrupted on this core
424         // blocking out access to other threads - leave this NONBLOCKING
425         // unless you know what you are doing
426         len = _udp_recv(vnet_brg_s.serv_sock, &pkt_addr, pkt, MAX_PACKET_LEN, 1); 
427
428
429         // If it would have blocked, we have no packet, and so
430         // we will give other threads on this core a chance
431         if (len==-EAGAIN || len==-EWOULDBLOCK || len==-EINTR) { 
432             palacios_yield_cpu_timed(VNET_YIELD_TIME_USEC);
433             continue;
434         }
435         
436         if(len < 0) {
437             WARNING("Receive error: Could not get packet, error %d\n", len);
438             continue;
439         }
440
441         link = _link_by_ip(pkt_addr.sin_addr.s_addr);
442
443         if (link == NULL){
444             WARNING("VNET Server: No VNET Link matches the src IP\n");
445             vnet_brg_s.stats.pkt_drop_phy ++;
446             continue;
447         }
448         
449         vnet_brg_s.stats.pkt_from_phy ++;
450         link->stats.rx_bytes += len;
451         link->stats.rx_pkts ++;
452
453         send_to_palacios(pkt, len, link->idx);
454     }
455
456     INFO("VNET Server: UDP thread exiting\n");
457
458     kfree(pkt);
459
460     return 0;
461 }
462
463
464 static int _rx_server(void * arg) {
465     
466     if(vnet_brg_s.serv_proto == UDP){
467         _udp_server(NULL);
468     }else if(vnet_brg_s.serv_proto == TCP) {
469         //accept new connection
470         //use select to receive pkt from physical network
471         //or create new kthread to handle each connection?
472         WARNING("VNET Server: TCP is not currently supported\n");
473         return -1;
474     }else {
475         WARNING ("VNET Server: Unsupported Protocol\n");
476         return -1;
477     }
478
479     return 0;
480 }
481
482 static inline unsigned int hash_fn(addr_t hdr_ptr) {    
483     return vnet_hash_buffer((uint8_t *)hdr_ptr, sizeof(uint32_t));
484 }
485
486 static inline int hash_eq(addr_t key1, addr_t key2) {   
487     return (memcmp((uint8_t *)key1, (uint8_t *)key2, sizeof(uint32_t)) == 0);
488 }
489
490
491 int vnet_bridge_init(void) {
492     struct v3_vnet_bridge_ops bridge_ops;
493
494     if(vnet_brg_s.status != 0) {
495         return -1;
496     }   
497     vnet_brg_s.status = 1;      
498         
499     memset(&vnet_brg_s, 0, sizeof(struct vnet_brg_state));
500
501     INIT_LIST_HEAD(&(vnet_brg_s.link_list));
502     spin_lock_init(&(vnet_brg_s.lock));
503
504     vnet_brg_s.serv_proto = UDP;
505
506     vnet_brg_s.ip2link = vnet_create_htable(10, hash_fn, hash_eq);
507     if(vnet_brg_s.ip2link == NULL){
508         WARNING("Failure to initiate VNET link hashtable\n");
509         return -1;
510     }
511         
512     if(init_vnet_serv() < 0){
513         WARNING("Failure to initiate VNET server\n");
514         return -1;
515     }
516
517     vnet_brg_s.serv_thread = kthread_run(_rx_server, NULL, "vnet_brgd");
518
519     bridge_ops.input = bridge_send_pkt;
520     bridge_ops.poll = NULL;
521         
522     if( v3_vnet_add_bridge(NULL, &bridge_ops, HOST_LNX_BRIDGE, NULL) < 0){
523         WARNING("VNET LNX Bridge: Fails to register bridge to VNET core");
524     }
525
526     INFO("VNET Linux Bridge initiated\n");
527
528     return 0;
529 }
530
531
532 void vnet_bridge_deinit(void){
533
534     INFO("VNET LNX Bridge Deinit Started\n");
535
536     v3_vnet_del_bridge(HOST_LNX_BRIDGE);
537
538     //DEBUG("Stopping bridge service thread\n");
539
540     kthread_stop(vnet_brg_s.serv_thread);
541
542     //DEBUG("Releasing bridee service socket\n");
543
544     vnet_brg_s.serv_sock->ops->release(vnet_brg_s.serv_sock);
545
546     //DEBUG("Deiniting bridge links\n");
547
548     deinit_links_list();
549
550     //DEBUG("Freeing bridge hash tables\n");
551
552     vnet_free_htable(vnet_brg_s.ip2link, 0, 0);
553
554     vnet_brg_s.status = 0;
555
556     INFO("VNET LNX Bridge Deinit Finished\n");
557 }
558
559