2 Palacios VNET interface
5 #include <linux/spinlock.h>
6 #include <linux/seq_file.h>
7 #include <linux/proc_fs.h>
8 #include <asm/uaccess.h>
9 #include <linux/inet.h>
10 #include <linux/kthread.h>
12 #include <linux/netdevice.h>
15 #include <linux/string.h>
16 #include <linux/preempt.h>
17 #include <linux/sched.h>
20 #include <palacios/vmm_vnet.h>
21 #include "palacios-vnet.h"
23 //#define DEBUG_VNET_BRIGE
25 #define VNET_UDP_PORT 9000
28 struct v3_vnet_route route;
32 struct list_head node;
41 struct sockaddr_in sock_addr;
45 struct list_head node;
48 struct palacios_vnet_state {
52 struct list_head route_list;
53 struct list_head link_list;
55 struct socket * serv_sock;
56 struct sockaddr_in serv_addr;
58 /* The thread recving pkts from sockets. */
59 struct task_struct * serv_thread;
62 unsigned long pkt_sent, pkt_recv, pkt_drop, pkt_udp_recv, pkt_udp_send;
66 static struct palacios_vnet_state vnet_state;
69 struct vnet_link * find_link_by_ip(uint32_t ip) {
70 struct vnet_link * link = NULL;
72 list_for_each_entry(link, &(vnet_state.link_list), node) {
74 if (link->dst_ip == ip) {
82 struct vnet_link * find_link_by_idx(int idx) {
83 struct vnet_link * link = NULL;
85 list_for_each_entry(link, &(vnet_state.link_list), node) {
87 if (link->link_idx == idx) {
94 struct vnet_route * find_route_by_idx(int idx) {
95 struct vnet_route * route = NULL;
97 list_for_each_entry(route, &(vnet_state.route_list), node) {
99 if (route->route_idx == idx) {
108 static int parse_mac_str(char * str, uint8_t * qual, uint8_t * mac) {
111 printk("Parsing MAC (%s)\n", str);
113 if (strstr(str, "-")) {
114 token = strsep(&str, "-");
116 if (strnicmp("not", token, strlen("not")) == 0) {
119 printk("Invalid MAC String token (%s)\n", token);
124 if (!strstr(str, ":")) {
125 if (strnicmp("any", str, strlen("any")) == 0) {
126 printk("qual = any\n");
128 } else if (strnicmp("none", str, strlen("none")) == 0) {
129 printk("qual = None\n");
132 printk("Invalid MAC Qual token (%s)\n", str);
141 for (i = 0; i < 6; i++) {
142 token = strsep(&str, ":");
143 mac[i] = simple_strtol(token, &token, 16);
150 static int parse_route_str(char * str, struct v3_vnet_route * route) {
152 struct vnet_link *link = NULL;
155 token = strsep(&str, " ");
161 parse_mac_str(token, &(route->src_mac_qual), route->src_mac);
164 token = strsep(&str, " ");
170 parse_mac_str(token, &(route->dst_mac_qual), route->dst_mac);
173 token = strsep(&str, " ");
179 if (strnicmp("interface", token, strlen("interface")) == 0) {
180 route->dst_type = LINK_INTERFACE;
181 printk("DST type = INTERFACE\n");
182 } else if (strnicmp("edge", token, strlen("edge")) == 0) {
183 route->dst_type = LINK_EDGE;
184 printk("DST type = EDGE\n");
186 printk("Invalid Destination Link Type (%s)\n", token);
192 token = strsep(&str, " ");
198 printk("dst link ID=%s\n", token);
200 // Figure out link ID here
201 if (route->dst_type == LINK_EDGE) {
205 // Figure out Link Here
206 if (in4_pton(token, strlen(token), (uint8_t *)&(link_ip), '\0', NULL) != 1) {
207 printk("Invalid Dst IP address (%s)\n", token);
212 printk("link_ip = %d\n", link_ip);
213 link = find_link_by_ip(link_ip);
215 route->dst_id = link->link_idx;
217 printk("can not find dst link %s\n", token);
221 printk("Unsupported dst link type\n");
226 token = strsep(&str, " ");
228 printk("SRC type = %s\n", token);
234 if (strnicmp("interface", token, strlen("interface")) == 0) {
235 route->src_type = LINK_INTERFACE;
236 printk("SRC type = INTERFACE\n");
237 } else if (strnicmp("edge", token, strlen("edge")) == 0) {
238 route->src_type = LINK_EDGE;
239 printk("SRC type = EDGE\n");
240 } else if (strnicmp("any", token, strlen("any")) == 0) {
241 route->src_type = LINK_ANY;
242 printk("SRC type = ANY\n");
244 printk("Invalid Src link type (%s)\n", token);
249 if (route->src_type == LINK_ANY) {
250 route->src_id = (uint32_t)-1;
251 } else if (route->src_type == LINK_EDGE) {
253 token = strsep(&str, " ");
259 // Figure out Link Here
260 if (in4_pton(token, strlen(token), (uint8_t *)&(src_ip), '\0', NULL) != 1) {
261 printk("Invalid SRC IP address (%s)\n", token);
265 link = find_link_by_ip(src_ip);
267 route->src_id = link->link_idx;
269 printk("can not find src link %s\n", token);
273 printk("Invalid link type\n");
284 static void * route_seq_start(struct seq_file * s, loff_t * pos) {
285 struct vnet_route * route_iter = NULL;
289 if (*pos >= vnet_state.num_routes) {
293 list_for_each_entry(route_iter, &(vnet_state.route_list), node) {
306 static void * link_seq_start(struct seq_file * s, loff_t * pos) {
307 struct vnet_link * link_iter = NULL;
311 if (*pos >= vnet_state.num_links) {
315 list_for_each_entry(link_iter, &(vnet_state.link_list), node) {
329 static void * route_seq_next(struct seq_file * s, void * v, loff_t * pos) {
330 struct vnet_route * route_iter = NULL;
332 route_iter = list_entry(((struct vnet_route *)v)->node.next, struct vnet_route, node);
334 // Check if the list has looped
335 if (&(route_iter->node) == &(vnet_state.route_list)) {
345 static void * link_seq_next(struct seq_file * s, void * v, loff_t * pos) {
346 struct vnet_link * link_iter = NULL;
349 link_iter = list_entry(((struct vnet_link *)v)->node.next, struct vnet_link, node);
351 // Check if the list has looped
352 if (&(link_iter->node) == &(vnet_state.link_list)) {
362 static void route_seq_stop(struct seq_file * s, void * v) {
363 printk("route_seq_stop\n");
369 static void link_seq_stop(struct seq_file * s, void * v) {
370 printk("link_seq_stop\n");
375 static int route_seq_show(struct seq_file * s, void * v) {
376 struct vnet_route * route_iter = v;
377 struct v3_vnet_route * route = &(route_iter->route);
380 seq_printf(s, "%d:\t", route_iter->route_idx);
382 switch (route->src_mac_qual) {
384 seq_printf(s, "any ");
387 seq_printf(s, "none ");
390 seq_printf(s, "not-%x:%x:%x:%x:%x:%x ",
391 route->src_mac[0], route->src_mac[1], route->src_mac[2],
392 route->src_mac[3], route->src_mac[4], route->src_mac[5]);
395 seq_printf(s, "%x:%x:%x:%x:%x:%x ",
396 route->src_mac[0], route->src_mac[1], route->src_mac[2],
397 route->src_mac[3], route->src_mac[4], route->src_mac[5]);
401 switch (route->dst_mac_qual) {
403 seq_printf(s, "any ");
406 seq_printf(s, "none ");
409 seq_printf(s, "not-%x:%x:%x:%x:%x:%x ",
410 route->src_mac[0], route->src_mac[1], route->src_mac[2],
411 route->src_mac[3], route->src_mac[4], route->src_mac[5]);
414 seq_printf(s, "%x:%x:%x:%x:%x:%x ",
415 route->src_mac[0], route->src_mac[1], route->src_mac[2],
416 route->src_mac[3], route->src_mac[4], route->src_mac[5]);
421 switch (route->dst_type) {
423 struct vnet_link * link = (struct vnet_link *)find_link_by_idx(route->dst_id);
424 seq_printf(s, "EDGE %pI4", &link->dst_ip);
427 case LINK_INTERFACE: {
428 seq_printf(s, "INTERFACE ");
429 seq_printf(s, "%d ", route->dst_id);
433 seq_printf(s, "Invalid Dst Link Type (%d) ", route->dst_type);
441 switch (route->src_type) {
443 struct vnet_link * link = (struct vnet_link *)find_link_by_idx(route->src_id);
444 seq_printf(s, "EDGE %pI4", &link->dst_ip);
447 case LINK_INTERFACE: {
448 seq_printf(s, "INTERFACE %d", route->src_id);
452 seq_printf(s, "ANY");
455 seq_printf(s, "Invalid Src Link Type (%d) ", route->src_type);
466 static int link_seq_show(struct seq_file * s, void * v) {
467 struct vnet_link * link_iter = v;
469 seq_printf(s, "%d:\t%pI4\t%d\n",
472 link_iter->dst_port);
478 static struct seq_operations route_seq_ops = {
479 .start = route_seq_start,
480 .next = route_seq_next,
481 .stop = route_seq_stop,
482 .show = route_seq_show
486 static struct seq_operations link_seq_ops = {
487 .start = link_seq_start,
488 .next = link_seq_next,
489 .stop = link_seq_stop,
490 .show = link_seq_show
494 static int route_open(struct inode * inode, struct file * file) {
495 return seq_open(file, &route_seq_ops);
499 static int link_open(struct inode * inode, struct file * file) {
500 return seq_open(file, &link_seq_ops);
503 static int inject_route(struct vnet_route * route) {
504 v3_vnet_add_route(route->route);
506 printk("Palacios-vnet: One route added to VNET core\n");
512 route_write(struct file * file,
517 char * buf_iter = NULL;
518 char * line_str = route_buf;
525 if (copy_from_user(route_buf, buf, size)) {
529 printk("Route written: %s\n", route_buf);
531 while ((buf_iter = strsep(&line_str, "\r\n"))) {
533 token = strsep(&buf_iter, " ");
538 if (strnicmp("ADD", token, strlen("ADD")) == 0) {
539 struct vnet_route * new_route = NULL;
540 new_route = kmalloc(sizeof(struct vnet_route), GFP_KERNEL);
546 memset(new_route, 0, sizeof(struct vnet_route));
548 if (parse_route_str(buf_iter, &(new_route->route)) == -1) {
553 if (inject_route(new_route) != 0) {
556 } else if (strnicmp("DEL", token, strlen("DEL")) == 0) {
557 printk("I should delete the route here\n");
559 printk("Invalid Route command string\n");
567 static int create_link(struct vnet_link * link) {
571 if ( (err = sock_create(AF_INET, SOCK_DGRAM, IPPROTO_UDP, &link->sock)) < 0) {
572 printk("Could not create socket\n");
576 memset(&link->sock_addr, 0, sizeof(struct sockaddr));
578 link->sock_addr.sin_family = AF_INET;
579 link->sock_addr.sin_addr.s_addr = link->dst_ip;
580 link->sock_addr.sin_port = htons(link->dst_port);
582 if ((err = link->sock->ops->connect(link->sock, (struct sockaddr *)&(link->sock_addr), sizeof(struct sockaddr), 0) < 0)) {
583 printk("Could not connect to remote host\n");
587 // We use the file pointer because we are in the kernel
588 // This is only used to assigned File Descriptors for user space, so it is available here
589 // link->sock->file = link;
591 spin_lock_irqsave(&(vnet_state.lock), flags);
592 list_add(&(link->node), &(vnet_state.link_list));
593 link->link_idx = vnet_state.num_links++;
594 spin_unlock_irqrestore(&(vnet_state.lock), flags);
596 printk("VNET Bridge: Link created, ip %d, port: %d, idx: %d, link: %p\n",
606 link_write(struct file * file, const char * buf, size_t size, loff_t * ppos) {
608 char * link_iter = NULL;
609 char * line_str = link_buf;
616 if (copy_from_user(link_buf, buf, size)) {
620 while ((link_iter = strsep(&line_str, "\r\n"))) {
621 printk("Link written: %s\n", link_buf);
623 token = strsep(&link_iter, " ");
629 if (strnicmp("ADD", token, strlen("ADD")) == 0) {
630 struct vnet_link * new_link = NULL;
631 char * ip_str = NULL;
634 ip_str = strsep(&link_iter, " ");
636 if ((!ip_str) || (!link_iter)) {
637 printk("Missing fields in ADD Link command\n");
641 if (in4_pton(ip_str, strlen(ip_str), (uint8_t *)&(ip), '\0', NULL) != 1) {
642 printk("Invalid Dst IP address (%s)\n", ip_str);
646 new_link = kmalloc(sizeof(struct vnet_link), GFP_KERNEL);
652 memset(new_link, 0, sizeof(struct vnet_link));
654 new_link->dst_ip = ip;
655 new_link->dst_port = simple_strtol(link_iter, &link_iter, 10);
657 if (create_link(new_link) != 0) {
658 printk("Could not create link\n");
663 } else if (strnicmp("DEL", token, strlen("DEL")) == 0) {
664 printk("Link deletion not supported\n");
666 printk("Invalid Link command string\n");
674 static struct file_operations route_fops = {
675 .owner = THIS_MODULE,
678 .write = route_write,
680 .release = seq_release
684 static struct file_operations link_fops = {
685 .owner = THIS_MODULE,
690 .release = seq_release
694 static int init_proc_files(void) {
695 struct proc_dir_entry * route_entry = NULL;
696 struct proc_dir_entry * link_entry = NULL;
697 struct proc_dir_entry * vnet_root = NULL;
700 vnet_root = proc_mkdir("vnet", NULL);
701 if (vnet_root == NULL) {
705 route_entry = create_proc_entry("routes", 0, vnet_root);
707 if (route_entry == NULL) {
708 remove_proc_entry("vnet", NULL);
712 route_entry->proc_fops = &route_fops;
715 link_entry = create_proc_entry("links", 0, vnet_root);
717 if (link_entry == NULL) {
718 remove_proc_entry("routes", vnet_root);
719 remove_proc_entry("vnet", NULL);
723 link_entry->proc_fops = &link_fops;
732 udp_send(struct socket * sock,
733 struct sockaddr_in * addr,
734 unsigned char * buf, int len) {
741 if (sock->sk == NULL) {
750 msg.msg_namelen = sizeof(struct sockaddr_in);
751 msg.msg_control = NULL;
752 msg.msg_controllen = 0;
755 msg.msg_control = NULL;
759 size = sock_sendmsg(sock, &msg, len);
768 udp_recv(struct socket * sock,
769 struct sockaddr_in * addr,
770 unsigned char * buf, int len) {
776 if (sock->sk == NULL) {
785 msg.msg_namelen = sizeof(struct sockaddr_in);
786 msg.msg_control = NULL;
787 msg.msg_controllen = 0;
790 msg.msg_control = NULL;
794 size = sock_recvmsg(sock, &msg, len, msg.msg_flags);
801 //send packets from Network to VNET core
803 send_to_palacios(unsigned char * buf,
806 struct v3_vnet_pkt pkt;
808 pkt.src_type = LINK_EDGE;
809 pkt.src_id = link_id;
810 memcpy(pkt.header, buf, ETHERNET_HEADER_LEN);
813 #ifdef DEBUG_VNET_BRIGE
815 printk("VNET Lnx Bridge: send pkt to VNET core (size: %d, src_id: %d, src_type: %d)\n",
816 pkt.size, pkt.src_id, pkt.src_type);
818 print_hex_dump(NULL, "pkt_data: ", 0, 20, 20, pkt.data, pkt.size, 0);
822 return v3_vnet_send_pkt(&pkt, NULL);;
826 //send packet from VNET core to Network
828 bridge_send_pkt(struct v3_vm_info * vm,
829 struct v3_vnet_pkt * pkt,
830 void * private_data) {
831 struct vnet_link * link;
833 #ifdef DEBUG_VNET_BRIGE
835 printk("VNET Lnx Host Bridge: packet received from VNET Core ... len: %d, pkt size: %d, link: %d\n",
840 print_hex_dump(NULL, "pkt_data: ", 0, 20, 20, pkt->data, pkt->size, 0);
844 vnet_state.pkt_recv ++;
846 link = find_link_by_idx(pkt->dst_id);
848 udp_send(link->sock, &(link->sock_addr), pkt->data, pkt->size);
849 vnet_state.pkt_udp_send ++;
851 printk("VNET Bridge Linux Host: wrong dst link, idx: %d, discards the packet\n", pkt->dst_id);
852 vnet_state.pkt_drop ++;
860 poll_pkt(struct v3_vm_info * vm,
861 void * private_data) {
868 static int init_vnet_serv(void) {
870 if (sock_create(AF_INET, SOCK_DGRAM, IPPROTO_UDP, &vnet_state.serv_sock) < 0) {
871 printk("Could not create socket\n");
875 memset(&vnet_state.serv_addr, 0, sizeof(struct sockaddr));
877 vnet_state.serv_addr.sin_family = AF_INET;
878 vnet_state.serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
879 vnet_state.serv_addr.sin_port = htons(VNET_UDP_PORT);
881 if (vnet_state.serv_sock->ops->bind(vnet_state.serv_sock, (struct sockaddr *)&(vnet_state.serv_addr), sizeof(struct sockaddr)) < 0) {
882 printk("Could not bind VNET server socket to port %d\n", VNET_UDP_PORT);
886 printk("VNET server bind to port: %d\n", VNET_UDP_PORT);
891 static int vnet_server(void * arg) {
892 unsigned char pkt[ETHERNET_PACKET_LEN];
893 struct sockaddr_in pkt_addr;
894 struct vnet_link *link = NULL;
898 printk("Palacios VNET Bridge: UDP receiving server ..... \n");
900 while (!kthread_should_stop()) {
902 len = udp_recv(vnet_state.serv_sock, &pkt_addr, pkt, ETHERNET_PACKET_LEN);
904 printk("Receive error: Could not get packet, error %d\n", len);
908 link = find_link_by_ip(ntohl(pkt_addr.sin_addr.s_addr));
910 link_id= link->link_idx;
916 vnet_state.pkt_udp_recv ++;
918 send_to_palacios(pkt, len, link_id);
925 static int profiling(void *args) {
926 static unsigned long long last_time=0;
927 unsigned long long cur_time=0;
928 set_user_nice(current, MAX_PRIO-1);
930 while (!kthread_should_stop()) {
932 if((cur_time - last_time) > 50000000000) {
933 last_time = cur_time;
934 printk("Palacios Linux VNET Bridge - profiling: sent: %ld, rxed: %ld, dropped: %ld, upd send: %ld, udp recv: %ld\n",
938 vnet_state.pkt_udp_send,
939 vnet_state.pkt_udp_recv);
948 int palacios_init_vnet(void) {
949 struct v3_vnet_bridge_ops bridge_ops;
951 memset(&vnet_state, 0, sizeof(struct palacios_vnet_state));
953 INIT_LIST_HEAD(&(vnet_state.link_list));
954 INIT_LIST_HEAD(&(vnet_state.route_list));
955 spin_lock_init(&(vnet_state.lock));
958 if(init_vnet_serv() < 0){
959 printk("Failure to initiate VNET server\n");
963 vnet_state.serv_thread = kthread_run(vnet_server, NULL, "vnet-server");
965 //kthread_run(profiling, NULL, "Profiling");
967 bridge_ops.input = bridge_send_pkt;
968 bridge_ops.poll = poll_pkt;
970 v3_vnet_add_bridge(NULL, &bridge_ops, HOST_LNX_BRIDGE, NULL);
972 printk("Palacios VNET Linux Bridge initiated\n");