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-vnet.h"
22 //#define DEBUG_VNET_BRIGE
24 #define VNET_UDP_PORT 9000
26 struct palacios_vnet_route {
27 struct v3_vnet_route route;
31 struct list_head node;
40 struct sockaddr_in sock_addr;
44 struct list_head node;
47 struct palacios_vnet_state {
51 struct list_head route_list;
52 struct list_head link_list;
54 struct socket * serv_sock;
55 struct sockaddr_in serv_addr;
57 /* The thread recving pkts from sockets. */
58 struct task_struct * serv_thread;
61 unsigned long pkt_sent, pkt_recv, pkt_drop, pkt_udp_recv, pkt_udp_send;
65 static struct palacios_vnet_state vnet_state;
68 struct vnet_link * link_by_ip(uint32_t ip) {
69 struct vnet_link * link = NULL;
71 list_for_each_entry(link, &(vnet_state.link_list), node) {
73 if (link->dst_ip == ip) {
81 struct vnet_link * link_by_idx(int idx) {
82 struct vnet_link * link = NULL;
84 list_for_each_entry(link, &(vnet_state.link_list), node) {
86 if (link->link_idx == idx) {
93 struct palacios_vnet_route * route_by_idx(int idx) {
94 struct palacios_vnet_route * route = NULL;
96 list_for_each_entry(route, &(vnet_state.route_list), node) {
98 if (route->route_idx == idx) {
107 static int parse_mac_str(char * str, uint8_t * qual, uint8_t * mac) {
110 printk("Parsing MAC (%s)\n", str);
113 if(strnicmp("any", str, strlen(str)) == 0){
116 }else if(strnicmp("none", str, strlen(str)) == 0){
120 if (strstr(str, "-")) {
121 token = strsep(&str, "-");
123 if (strnicmp("not", token, strlen("not")) == 0) {
126 printk("Invalid MAC String token (%s)\n", token);
131 if (strstr(str, ":")) {
134 if(*qual == MAC_NOSET){
138 for (i = 0; i < 6; i++) {
139 token = strsep(&str, ":");
141 printk("Invalid MAC String token (%s)\n", token);
144 mac[i] = simple_strtol(token, &token, 16);
146 printk("MAC: %2x:%2x:%2x:%2x:%2x:%2x\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
149 printk("Invalid MAC String token (%s)\n", token);
159 static int str2mac(char * str, uint8_t * mac){
163 for (i = 0; i < ETH_ALEN; i++) {
164 hex = strsep(&str, ":");
166 printk("Invalid MAC String token (%s)\n", str);
169 mac[i] = simple_strtol(hex, &hex, 16);
177 * add src-MAC dst-MAC dst-TYPE [dst-ID] src-TYPE [src-ID]
179 * src-MAC = dst-MAC = not-MAC|any|none|MAC
180 * dst-TYPE = edge|interface
181 * src-TYPE = edge|interface|any
182 * dst-ID = src-ID = IP|MAC
183 * MAC=xx:xx:xx:xx:xx:xx
184 * IP = xxx.xxx.xxx.xxx
186 static int parse_route_str(char * str, struct v3_vnet_route * route) {
188 struct vnet_link *link = NULL;
191 token = strsep(&str, " ");
195 parse_mac_str(token, &(route->src_mac_qual), route->src_mac);
198 token = strsep(&str, " ");
202 parse_mac_str(token, &(route->dst_mac_qual), route->dst_mac);
205 token = strsep(&str, " ");
209 printk("dst type =(%s)\n", token);
211 if (strnicmp("interface", token, strlen("interface")) == 0) {
212 route->dst_type = LINK_INTERFACE;
213 } else if (strnicmp("edge", token, strlen("edge")) == 0) {
214 route->dst_type = LINK_EDGE;
216 printk("Invalid Destination Link Type (%s)\n", token);
221 token = strsep(&str, " ");
225 printk("dst link ID=(%s)\n", token);
227 // Figure out link here
228 if (route->dst_type == LINK_EDGE) {
231 // Figure out Link Here
232 if (in4_pton(token, strlen(token), (uint8_t *)&(link_ip), '\0', NULL) != 1) {
233 printk("Invalid Dst IP address (%s)\n", token);
237 link = link_by_ip(link_ip);
239 route->dst_id = link->link_idx;
241 printk("can not find dst link %s\n", token);
245 printk("link_ip = %d, link_id = %d\n", link_ip, link->link_idx);
246 } else if (route->dst_type == LINK_INTERFACE) {
247 uint8_t mac[ETH_ALEN];
249 if(str2mac(token, mac) == -1){
250 printk("wrong MAC format (%s)\n", token);
254 route->dst_id = v3_vnet_find_dev(mac);
255 if (route->dst_id == -1){
256 printk("can not find dst device %s\n", token);
260 printk("Unsupported dst link type\n");
265 route->src_type = -1;
268 token = strsep(&str, " ");
270 printk("SRC type = %s\n", token);
276 if (strnicmp("interface", token, strlen("interface")) == 0) {
277 route->src_type = LINK_INTERFACE;
278 } else if (strnicmp("edge", token, strlen("edge")) == 0) {
279 route->src_type = LINK_EDGE;
280 } else if (strnicmp("any", token, strlen("any")) == 0) {
281 route->src_type = LINK_ANY;
283 printk("Invalid Src link type (%s)\n", token);
288 if (route->src_type == LINK_ANY) {
290 } else if (route->src_type == LINK_EDGE) {
292 token = strsep(&str, " ");
298 // Figure out Link Here
299 if (in4_pton(token, strlen(token), (uint8_t *)&(src_ip), '\0', NULL) != 1) {
300 printk("Invalid SRC IP address (%s)\n", token);
304 link = link_by_ip(src_ip);
306 route->src_id = link->link_idx;
308 printk("can not find src link %s\n", token);
311 } else if(route->src_type == LINK_INTERFACE){
312 uint8_t mac[ETH_ALEN];
314 if(str2mac(token, mac) == -1){
315 printk("wrong MAC format (%s)\n", token);
319 route->src_id = v3_vnet_find_dev(mac);
320 if (route->src_id == -1){
321 printk("can not find dst device %s\n", token);
325 printk("Invalid link type\n");
335 static void * route_seq_start(struct seq_file * s, loff_t * pos) {
336 struct palacios_vnet_route * route_iter = NULL;
340 if (*pos >= vnet_state.num_routes) {
344 list_for_each_entry(route_iter, &(vnet_state.route_list), node) {
357 static void * link_seq_start(struct seq_file * s, loff_t * pos) {
358 struct vnet_link * link_iter = NULL;
361 if (*pos >= vnet_state.num_links) {
365 list_for_each_entry(link_iter, &(vnet_state.link_list), node) {
379 static void * route_seq_next(struct seq_file * s, void * v, loff_t * pos) {
380 struct palacios_vnet_route * route_iter = NULL;
382 route_iter = list_entry(((struct palacios_vnet_route *)v)->node.next, struct palacios_vnet_route, node);
384 // Check if the list has looped
385 if (&(route_iter->node) == &(vnet_state.route_list)) {
395 static void * link_seq_next(struct seq_file * s, void * v, loff_t * pos) {
396 struct vnet_link * link_iter = NULL;
399 link_iter = list_entry(((struct vnet_link *)v)->node.next, struct vnet_link, node);
401 // Check if the list has looped
402 if (&(link_iter->node) == &(vnet_state.link_list)) {
412 static void route_seq_stop(struct seq_file * s, void * v) {
413 printk("route_seq_stop\n");
419 static void link_seq_stop(struct seq_file * s, void * v) {
420 printk("link_seq_stop\n");
425 static int route_seq_show(struct seq_file * s, void * v) {
426 struct palacios_vnet_route * route_iter = v;
427 struct v3_vnet_route * route = &(route_iter->route);
429 seq_printf(s, "%d:\t", route_iter->route_idx);
431 seq_printf(s, "\nSrc:\t");
432 switch (route->src_mac_qual) {
434 seq_printf(s, "any ");
437 seq_printf(s, "none ");
440 seq_printf(s, "not-%2x:%2x:%2x:%2x:%2x:%2x ",
441 route->src_mac[0], route->src_mac[1], route->src_mac[2],
442 route->src_mac[3], route->src_mac[4], route->src_mac[5]);
445 seq_printf(s, "%x:%x:%x:%x:%x:%x ",
446 route->src_mac[0], route->src_mac[1], route->src_mac[2],
447 route->src_mac[3], route->src_mac[4], route->src_mac[5]);
451 seq_printf(s, "\nDst:\t");
452 switch (route->dst_mac_qual) {
454 seq_printf(s, "any ");
457 seq_printf(s, "none ");
460 seq_printf(s, "not-%x:%x:%x:%x:%x:%x ",
461 route->src_mac[0], route->src_mac[1], route->src_mac[2],
462 route->src_mac[3], route->src_mac[4], route->src_mac[5]);
465 seq_printf(s, "%x:%x:%x:%x:%x:%x ",
466 route->src_mac[0], route->src_mac[1], route->src_mac[2],
467 route->src_mac[3], route->src_mac[4], route->src_mac[5]);
471 seq_printf(s, "\nDst-Type:\t");
472 switch (route->dst_type) {
474 struct vnet_link * link = (struct vnet_link *)link_by_idx(route->dst_id);
475 seq_printf(s, "EDGE %pI4", &link->dst_ip);
478 case LINK_INTERFACE: {
479 seq_printf(s, "INTERFACE ");
480 seq_printf(s, "%d ", route->dst_id);
484 seq_printf(s, "Invalid Dst Link Type (%d) ", route->dst_type);
488 seq_printf(s, "\nSrc-Type:\t");
489 switch (route->src_type) {
491 struct vnet_link * link = (struct vnet_link *)link_by_idx(route->src_id);
492 seq_printf(s, "EDGE %pI4", &link->dst_ip);
495 case LINK_INTERFACE: {
496 seq_printf(s, "INTERFACE %d", route->src_id);
500 seq_printf(s, "ANY");
503 seq_printf(s, "Invalid Src Link Type (%d) ", route->src_type);
514 static int link_seq_show(struct seq_file * s, void * v) {
515 struct vnet_link * link_iter = v;
517 seq_printf(s, "%d:\t%pI4\t%d\n",
520 link_iter->dst_port);
526 static struct seq_operations route_seq_ops = {
527 .start = route_seq_start,
528 .next = route_seq_next,
529 .stop = route_seq_stop,
530 .show = route_seq_show
534 static struct seq_operations link_seq_ops = {
535 .start = link_seq_start,
536 .next = link_seq_next,
537 .stop = link_seq_stop,
538 .show = link_seq_show
542 static int route_open(struct inode * inode, struct file * file) {
543 return seq_open(file, &route_seq_ops);
547 static int link_open(struct inode * inode, struct file * file) {
548 return seq_open(file, &link_seq_ops);
551 static int inject_route(struct palacios_vnet_route * route) {
554 v3_vnet_add_route(route->route);
556 spin_lock_irqsave(&(vnet_state.lock), flags);
557 list_add(&(route->node), &(vnet_state.route_list));
558 route->route_idx = vnet_state.num_routes++;
559 spin_unlock_irqrestore(&(vnet_state.lock), flags);
561 printk("Palacios-vnet: One route added to VNET core\n");
567 route_write(struct file * file,
572 char * buf_iter = NULL;
573 char * line_str = route_buf;
580 if (copy_from_user(route_buf, buf, size)) {
584 printk("Route written: %s\n", route_buf);
586 while ((buf_iter = strsep(&line_str, "\r\n"))) {
588 token = strsep(&buf_iter, " ");
593 if (strnicmp("ADD", token, strlen("ADD")) == 0) {
594 struct palacios_vnet_route * new_route = NULL;
595 new_route = kmalloc(sizeof(struct palacios_vnet_route), GFP_KERNEL);
601 memset(new_route, 0, sizeof(struct palacios_vnet_route));
603 if (parse_route_str(buf_iter, &(new_route->route)) == -1) {
608 if (inject_route(new_route) != 0) {
611 } else if (strnicmp("DEL", token, strlen("DEL")) == 0) {
612 printk("I should delete the route here\n");
614 printk("Invalid Route command string\n");
622 static int create_link(struct vnet_link * link) {
626 if ( (err = sock_create(AF_INET, SOCK_DGRAM, IPPROTO_UDP, &link->sock)) < 0) {
627 printk("Could not create socket\n");
631 memset(&link->sock_addr, 0, sizeof(struct sockaddr));
633 link->sock_addr.sin_family = AF_INET;
634 link->sock_addr.sin_addr.s_addr = link->dst_ip;
635 link->sock_addr.sin_port = htons(link->dst_port);
637 if ((err = link->sock->ops->connect(link->sock, (struct sockaddr *)&(link->sock_addr), sizeof(struct sockaddr), 0) < 0)) {
638 printk("Could not connect to remote host\n");
642 // We use the file pointer because we are in the kernel
643 // This is only used to assigned File Descriptors for user space, so it is available here
644 // link->sock->file = link;
646 spin_lock_irqsave(&(vnet_state.lock), flags);
647 list_add(&(link->node), &(vnet_state.link_list));
648 link->link_idx = vnet_state.num_links++;
649 spin_unlock_irqrestore(&(vnet_state.lock), flags);
651 printk("VNET Bridge: Link created, ip %d, port: %d, idx: %d, link: %p\n",
661 /* ADD dst-ip 9000 */
663 link_write(struct file * file, const char * buf, size_t size, loff_t * ppos) {
665 char * link_iter = NULL;
666 char * line_str = link_buf;
673 if (copy_from_user(link_buf, buf, size)) {
677 while ((link_iter = strsep(&line_str, "\r\n"))) {
678 printk("Link written: %s\n", link_buf);
680 token = strsep(&link_iter, " ");
686 if (strnicmp("ADD", token, strlen("ADD")) == 0) {
687 struct vnet_link * new_link = NULL;
688 char * ip_str = NULL;
691 ip_str = strsep(&link_iter, " ");
693 if ((!ip_str) || (!link_iter)) {
694 printk("Missing fields in ADD Link command\n");
698 if (in4_pton(ip_str, strlen(ip_str), (uint8_t *)&(ip), '\0', NULL) != 1) {
699 printk("Invalid Dst IP address (%s)\n", ip_str);
703 new_link = kmalloc(sizeof(struct vnet_link), GFP_KERNEL);
709 memset(new_link, 0, sizeof(struct vnet_link));
711 new_link->dst_ip = ip;
712 new_link->dst_port = simple_strtol(link_iter, &link_iter, 10);
714 if (create_link(new_link) != 0) {
715 printk("Could not create link\n");
720 } else if (strnicmp("DEL", token, strlen("DEL")) == 0) {
721 printk("Link deletion not supported\n");
723 printk("Invalid Link command string\n");
731 static struct file_operations route_fops = {
732 .owner = THIS_MODULE,
735 .write = route_write,
737 .release = seq_release
741 static struct file_operations link_fops = {
742 .owner = THIS_MODULE,
747 .release = seq_release
751 static int init_proc_files(void) {
752 struct proc_dir_entry * route_entry = NULL;
753 struct proc_dir_entry * link_entry = NULL;
754 struct proc_dir_entry * vnet_root = NULL;
757 vnet_root = proc_mkdir("vnet", NULL);
758 if (vnet_root == NULL) {
762 route_entry = create_proc_entry("routes", 0, vnet_root);
764 if (route_entry == NULL) {
765 remove_proc_entry("vnet", NULL);
769 route_entry->proc_fops = &route_fops;
772 link_entry = create_proc_entry("links", 0, vnet_root);
774 if (link_entry == NULL) {
775 remove_proc_entry("routes", vnet_root);
776 remove_proc_entry("vnet", NULL);
780 link_entry->proc_fops = &link_fops;
789 udp_send(struct socket * sock,
790 struct sockaddr_in * addr,
791 unsigned char * buf, int len) {
798 if (sock->sk == NULL) {
807 msg.msg_namelen = sizeof(struct sockaddr_in);
808 msg.msg_control = NULL;
809 msg.msg_controllen = 0;
812 msg.msg_control = NULL;
816 size = sock_sendmsg(sock, &msg, len);
825 udp_recv(struct socket * sock,
826 struct sockaddr_in * addr,
827 unsigned char * buf, int len) {
833 if (sock->sk == NULL) {
842 msg.msg_namelen = sizeof(struct sockaddr_in);
843 msg.msg_control = NULL;
844 msg.msg_controllen = 0;
847 msg.msg_control = NULL;
851 size = sock_recvmsg(sock, &msg, len, msg.msg_flags);
858 //send packets from Network to VNET core
860 send_to_palacios(unsigned char * buf,
863 struct v3_vnet_pkt pkt;
865 pkt.src_type = LINK_EDGE;
866 pkt.src_id = link_id;
867 memcpy(pkt.header, buf, ETHERNET_HEADER_LEN);
870 #ifdef CONFIG_PALACIOS_VNET_DEBUG
872 printk("VNET Lnx Bridge: send pkt to VNET core (size: %d, src_id: %d, src_type: %d)\n",
873 pkt.size, pkt.src_id, pkt.src_type);
875 print_hex_dump(NULL, "pkt_data: ", 0, 20, 20, pkt.data, pkt.size, 0);
879 return v3_vnet_send_pkt(&pkt, NULL, 1);
883 //send packet from VNET core to Network
885 bridge_send_pkt(struct v3_vm_info * vm,
886 struct v3_vnet_pkt * pkt,
887 void * private_data) {
888 struct vnet_link * link;
890 #ifdef CONFIG_PALACIOS_VNET_DEBUG
892 printk("VNET Lnx Host Bridge: packet received from VNET Core ... len: %d, pkt size: %d, link: %d\n",
897 print_hex_dump(NULL, "pkt_data: ", 0, 20, 20, pkt->data, pkt->size, 0);
901 vnet_state.pkt_recv ++;
903 link = link_by_idx(pkt->dst_id);
905 udp_send(link->sock, &(link->sock_addr), pkt->data, pkt->size);
906 vnet_state.pkt_udp_send ++;
908 printk("VNET Bridge Linux Host: wrong dst link, idx: %d, discards the packet\n", pkt->dst_id);
909 vnet_state.pkt_drop ++;
917 poll_pkt(struct v3_vm_info * vm,
918 void * private_data) {
925 static int init_vnet_serv(void) {
927 if (sock_create(AF_INET, SOCK_DGRAM, IPPROTO_UDP, &vnet_state.serv_sock) < 0) {
928 printk("Could not create socket\n");
932 memset(&vnet_state.serv_addr, 0, sizeof(struct sockaddr));
934 vnet_state.serv_addr.sin_family = AF_INET;
935 vnet_state.serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
936 vnet_state.serv_addr.sin_port = htons(VNET_UDP_PORT);
938 if (vnet_state.serv_sock->ops->bind(vnet_state.serv_sock, (struct sockaddr *)&(vnet_state.serv_addr), sizeof(struct sockaddr)) < 0) {
939 printk("Could not bind VNET server socket to port %d\n", VNET_UDP_PORT);
943 printk("VNET server bind to port: %d\n", VNET_UDP_PORT);
948 static int vnet_server(void * arg) {
949 unsigned char pkt[ETHERNET_PACKET_LEN];
950 struct sockaddr_in pkt_addr;
951 struct vnet_link *link = NULL;
955 printk("Palacios VNET Bridge: UDP receiving server ..... \n");
957 while (!kthread_should_stop()) {
959 len = udp_recv(vnet_state.serv_sock, &pkt_addr, pkt, ETHERNET_PACKET_LEN);
961 printk("Receive error: Could not get packet, error %d\n", len);
965 link = link_by_ip(ntohl(pkt_addr.sin_addr.s_addr));
967 link_id= link->link_idx;
973 vnet_state.pkt_udp_recv ++;
975 send_to_palacios(pkt, len, link_id);
982 int palacios_init_vnet(void) {
983 struct v3_vnet_bridge_ops bridge_ops;
985 memset(&vnet_state, 0, sizeof(struct palacios_vnet_state));
987 INIT_LIST_HEAD(&(vnet_state.link_list));
988 INIT_LIST_HEAD(&(vnet_state.route_list));
989 spin_lock_init(&(vnet_state.lock));
992 if(init_vnet_serv() < 0){
993 printk("Failure to initiate VNET server\n");
997 vnet_state.serv_thread = kthread_run(vnet_server, NULL, "vnet-server");
999 //kthread_run(profiling, NULL, "Profiling");
1001 bridge_ops.input = bridge_send_pkt;
1002 bridge_ops.poll = poll_pkt;
1004 v3_vnet_add_bridge(NULL, &bridge_ops, HOST_LNX_BRIDGE, NULL);
1006 printk("Palacios VNET Linux Bridge initiated\n");