2 Palacios VNET Control Module
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/net.h>
16 #include <linux/string.h>
17 #include <linux/preempt.h>
18 #include <linux/sched.h>
21 #include <vnet/vnet.h>
22 #include <vnet/vnet_hashtable.h>
23 #include "palacios-vnet.h"
25 #define VNET_SERVER_PORT 9000
27 struct vnet_route_iter {
28 struct v3_vnet_route route;
31 struct list_head node;
35 struct vnet_link_iter {
38 vnet_brg_proto_t proto;
41 struct list_head node;
45 struct vnet_ctrl_state {
51 struct list_head route_list;
52 struct list_head link_iter_list;
56 struct proc_dir_entry * vnet_proc_root;
60 static struct vnet_ctrl_state vnet_ctrl_s;
63 static int parse_mac_str(char * str, uint8_t * qual, uint8_t * mac) {
66 printk("Parsing MAC (%s)\n", str);
69 if(strnicmp("any", str, strlen(str)) == 0){
72 }else if(strnicmp("none", str, strlen(str)) == 0){
76 if (strstr(str, "-")) {
77 token = strsep(&str, "-");
79 if (strnicmp("not", token, strlen("not")) == 0) {
82 printk("Invalid MAC String token (%s)\n", token);
87 if (strstr(str, ":")) {
90 if(*qual == MAC_NOSET){
94 for (i = 0; i < 6; i++) {
95 token = strsep(&str, ":");
97 printk("Invalid MAC String token (%s)\n", token);
100 mac[i] = simple_strtol(token, &token, 16);
102 printk("MAC: %2x:%2x:%2x:%2x:%2x:%2x\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
105 printk("Invalid MAC String token (%s)\n", token);
115 static int str2mac(char * str, uint8_t * mac){
119 for (i = 0; i < ETH_ALEN; i++) {
120 hex = strsep(&str, ":");
122 printk("Invalid MAC String token (%s)\n", str);
125 mac[i] = simple_strtol(hex, &hex, 16);
132 static inline struct vnet_link_iter * link_by_ip(uint32_t ip) {
133 struct vnet_link_iter * link = NULL;
135 list_for_each_entry(link, &(vnet_ctrl_s.link_iter_list), node) {
137 if (link->dst_ip == ip) {
145 static inline struct vnet_link_iter * link_by_idx(int idx) {
146 struct vnet_link_iter * link = NULL;
148 list_for_each_entry(link, &(vnet_ctrl_s.link_iter_list), node) {
149 if (link->idx == idx) {
158 static int parse_route_str(char * str, struct v3_vnet_route * route) {
160 struct vnet_link_iter * link = NULL;
163 token = strsep(&str, " ");
167 parse_mac_str(token, &(route->src_mac_qual), route->src_mac);
170 token = strsep(&str, " ");
174 parse_mac_str(token, &(route->dst_mac_qual), route->dst_mac);
177 token = strsep(&str, " ");
181 printk("dst type =(%s)\n", token);
183 if (strnicmp("interface", token, strlen("interface")) == 0) {
184 route->dst_type = LINK_INTERFACE;
185 } else if (strnicmp("edge", token, strlen("edge")) == 0) {
186 route->dst_type = LINK_EDGE;
188 printk("Invalid Destination Link Type (%s)\n", token);
193 token = strsep(&str, " ");
197 printk("dst ID=(%s)\n", token);
199 // Figure out link here
200 if (route->dst_type == LINK_EDGE) {
203 // Figure out Link Here
204 if (in4_pton(token, strlen(token), (uint8_t *)&(link_ip), '\0', NULL) != 1) {
205 printk("Invalid Dst IP address (%s)\n", token);
209 link = link_by_ip(link_ip);
211 route->dst_id = link->idx;
213 printk("can not find dst link %s\n", token);
217 printk("link_ip = %d, link_id = %d\n", link_ip, link->idx);
218 } else if (route->dst_type == LINK_INTERFACE) {
219 uint8_t mac[ETH_ALEN];
221 if(str2mac(token, mac) == -1){
222 printk("wrong MAC format (%s)\n", token);
226 route->dst_id = v3_vnet_find_dev(mac);
227 if (route->dst_id == -1){
228 printk("can not find dst device %s\n", token);
232 printk("Unsupported dst link type\n");
237 route->src_type = -1;
240 token = strsep(&str, " ");
242 printk("SRC type = %s\n", token);
248 if (strnicmp("interface", token, strlen("interface")) == 0) {
249 route->src_type = LINK_INTERFACE;
250 } else if (strnicmp("edge", token, strlen("edge")) == 0) {
251 route->src_type = LINK_EDGE;
252 } else if (strnicmp("any", token, strlen("any")) == 0) {
253 route->src_type = LINK_ANY;
255 printk("Invalid Src link type (%s)\n", token);
260 if (route->src_type == LINK_ANY) {
262 } else if (route->src_type == LINK_EDGE) {
264 token = strsep(&str, " ");
270 // Figure out Link Here
271 if (in4_pton(token, strlen(token), (uint8_t *)&(src_ip), '\0', NULL) != 1) {
272 printk("Invalid SRC IP address (%s)\n", token);
276 link = link_by_ip(src_ip);
278 route->src_id = link->idx;
280 printk("can not find src link %s\n", token);
283 } else if(route->src_type == LINK_INTERFACE){
284 uint8_t mac[ETH_ALEN];
286 if(str2mac(token, mac) == -1){
287 printk("wrong MAC format (%s)\n", token);
291 route->src_id = v3_vnet_find_dev(mac);
292 if (route->src_id == -1){
293 printk("can not find dst device %s\n", token);
297 printk("Invalid link type\n");
305 static void * route_seq_start(struct seq_file * s, loff_t * pos) {
306 struct vnet_route_iter * route_iter = NULL;
309 if (*pos >= vnet_ctrl_s.num_routes) {
313 list_for_each_entry(route_iter, &(vnet_ctrl_s.route_list), node) {
325 static void * route_seq_next(struct seq_file * s, void * v, loff_t * pos) {
326 struct vnet_route_iter * route_iter = NULL;
328 route_iter = list_entry(((struct vnet_route_iter *)v)->node.next, struct vnet_route_iter, node);
330 // Check if the list has looped
331 if (&(route_iter->node) == &(vnet_ctrl_s.route_list)) {
340 static void route_seq_stop(struct seq_file * s, void * v) {
345 static void * link_seq_start(struct seq_file * s, loff_t * pos) {
346 struct vnet_link_iter * link_iter = NULL;
349 if (*pos >= vnet_ctrl_s.num_links) {
353 list_for_each_entry(link_iter, &(vnet_ctrl_s.link_iter_list), node) {
364 static int route_seq_show(struct seq_file * s, void * v) {
365 struct vnet_route_iter * route_iter = v;
366 struct v3_vnet_route * route = &(route_iter->route);
368 seq_printf(s, "%d:\t", route_iter->idx);
370 seq_printf(s, "\nSrc:\t");
371 switch (route->src_mac_qual) {
373 seq_printf(s, "any ");
376 seq_printf(s, "none ");
379 seq_printf(s, "not-%2x:%2x:%2x:%2x:%2x:%2x ",
380 route->src_mac[0], route->src_mac[1], route->src_mac[2],
381 route->src_mac[3], route->src_mac[4], route->src_mac[5]);
384 seq_printf(s, "%x:%x:%x:%x:%x:%x ",
385 route->src_mac[0], route->src_mac[1], route->src_mac[2],
386 route->src_mac[3], route->src_mac[4], route->src_mac[5]);
390 seq_printf(s, "\nDst:\t");
391 switch (route->dst_mac_qual) {
393 seq_printf(s, "any ");
396 seq_printf(s, "none ");
399 seq_printf(s, "not-%x:%x:%x:%x:%x:%x ",
400 route->src_mac[0], route->src_mac[1], route->src_mac[2],
401 route->src_mac[3], route->src_mac[4], route->src_mac[5]);
404 seq_printf(s, "%x:%x:%x:%x:%x:%x ",
405 route->src_mac[0], route->src_mac[1], route->src_mac[2],
406 route->src_mac[3], route->src_mac[4], route->src_mac[5]);
410 seq_printf(s, "\nDst-Type:\t");
411 switch (route->dst_type) {
413 struct vnet_link_iter * link = (struct vnet_link_iter *)link_by_idx(route->dst_id);
414 seq_printf(s, "EDGE %pI4", &link->dst_ip);
417 case LINK_INTERFACE: {
418 seq_printf(s, "INTERFACE ");
419 seq_printf(s, "%d ", route->dst_id);
423 seq_printf(s, "Invalid Dst Link Type (%d) ", route->dst_type);
427 seq_printf(s, "\nSrc-Type:\t");
428 switch (route->src_type) {
430 struct vnet_link_iter * link = (struct vnet_link_iter *)link_by_idx(route->src_id);
431 seq_printf(s, "EDGE %pI4", &link->dst_ip);
434 case LINK_INTERFACE: {
435 seq_printf(s, "INTERFACE %d", route->src_id);
439 seq_printf(s, "ANY");
442 seq_printf(s, "Invalid Src Link Type (%d) ", route->src_type);
451 static void * link_seq_next(struct seq_file * s, void * v, loff_t * pos) {
452 struct vnet_link_iter * link_iter = NULL;
454 link_iter = list_entry(((struct vnet_link_iter *)v)->node.next, struct vnet_link_iter, node);
456 // Check if the list has looped
457 if (&(link_iter->node) == &(vnet_ctrl_s.link_iter_list)) {
466 static void link_seq_stop(struct seq_file * s, void * v) {
471 static int link_seq_show(struct seq_file * s, void * v) {
472 struct vnet_link_iter * link_iter = v;
473 struct nic_statistics stats;
475 vnet_brg_link_stats(link_iter->idx, &stats);
477 seq_printf(s, "%d:\t%pI4\t%d\n\t\tReceived Pkts: %lld, Received Bytes %lld\n\t\tSent Pkts: %lld, Sent Bytes: %lld\n\n",
490 static struct seq_operations route_seq_ops = {
491 .start = route_seq_start,
492 .next = route_seq_next,
493 .stop = route_seq_stop,
494 .show = route_seq_show
498 static struct seq_operations link_seq_ops = {
499 .start = link_seq_start,
500 .next = link_seq_next,
501 .stop = link_seq_stop,
502 .show = link_seq_show
506 static int route_open(struct inode * inode, struct file * file) {
507 return seq_open(file, &route_seq_ops);
511 static int link_open(struct inode * inode, struct file * file) {
512 return seq_open(file, &link_seq_ops);
517 static int inject_route(struct vnet_route_iter * route) {
520 route->idx = v3_vnet_add_route(route->route);
522 spin_lock_irqsave(&(vnet_ctrl_s.lock), flags);
523 list_add(&(route->node), &(vnet_ctrl_s.route_list));
524 vnet_ctrl_s.num_routes ++;
525 spin_unlock_irqrestore(&(vnet_ctrl_s.lock), flags);
527 printk("VNET Control: One route added to VNET core\n");
533 static void delete_route(struct vnet_route_iter * route) {
536 v3_vnet_del_route(route->idx);
538 spin_lock_irqsave(&(vnet_ctrl_s.lock), flags);
539 list_del(&(route->node));
540 vnet_ctrl_s.num_routes --;
541 spin_unlock_irqrestore(&(vnet_ctrl_s.lock), flags);
543 printk("VNET Control: Route %d deleted from VNET\n", route->idx);
551 * add src-MAC dst-MAC dst-TYPE [dst-ID] src-TYPE [src-ID]
553 * src-MAC = dst-MAC = not-MAC|any|none|MAC
554 * dst-TYPE = edge|interface
555 * src-TYPE = edge|interface|any
556 * dst-ID = src-ID = IP|MAC
557 * MAC=xx:xx:xx:xx:xx:xx
558 * IP = xxx.xxx.xxx.xxx
565 route_write(struct file * file,
570 char * buf_iter = NULL;
571 char * line_str = route_buf;
578 if (copy_from_user(route_buf, buf, size)) {
582 route_buf[size] = '\0';
583 printk("Route written: %s\n", route_buf);
585 while ((buf_iter = strsep(&line_str, "\r\n"))) {
587 token = strsep(&buf_iter, " ");
592 if (strnicmp("ADD", token, strlen("ADD")) == 0) {
593 struct vnet_route_iter * new_route = NULL;
594 new_route = kmalloc(sizeof(struct vnet_route_iter), GFP_KERNEL);
600 memset(new_route, 0, sizeof(struct vnet_route_iter));
602 if (parse_route_str(buf_iter, &(new_route->route)) == -1) {
607 if (inject_route(new_route) != 0) {
611 } else if (strnicmp("DEL", token, strlen("DEL")) == 0) {
612 char * idx_str = NULL;
615 idx_str = strsep(&buf_iter, " ");
618 printk("Missing route idx in DEL Route command\n");
622 d_idx = simple_strtoul(idx_str, &idx_str, 10);
624 v3_vnet_del_route(d_idx);
626 printk("VNET Control: One route deleted\n");
629 printk("Invalid Route command string\n");
637 static void delete_link(struct vnet_link_iter * link){
640 vnet_brg_delete_link(link->idx);
642 spin_lock_irqsave(&(vnet_ctrl_s.lock), flags);
643 list_del(&(link->node));
644 vnet_ctrl_s.num_links --;
645 spin_unlock_irqrestore(&(vnet_ctrl_s.lock), flags);
652 static void deinit_links_list(void){
653 struct vnet_link_iter * link;
655 list_for_each_entry(link, &(vnet_ctrl_s.link_iter_list), node) {
660 static void deinit_routes_list(void){
661 struct vnet_route_iter * route;
663 list_for_each_entry(route, &(vnet_ctrl_s.route_list), node) {
668 /* ADD dst-ip 9000 [udp|tcp] */
671 link_write(struct file * file, const char * buf, size_t size, loff_t * ppos) {
673 char * link_iter = NULL;
674 char * line_str = link_buf;
681 if (copy_from_user(link_buf, buf, size)) {
685 while ((link_iter = strsep(&line_str, "\r\n"))) {
686 printk("Link written: %s\n", link_buf);
688 token = strsep(&link_iter, " ");
694 if (strnicmp("ADD", token, strlen("ADD")) == 0) {
695 struct vnet_link_iter * link = NULL;
696 char * ip_str = NULL;
699 vnet_brg_proto_t d_proto;
703 ip_str = strsep(&link_iter, " ");
705 if ((!ip_str) || (!link_iter)) {
706 printk("Missing fields in ADD Link command\n");
710 if (in4_pton(ip_str, strlen(ip_str), (uint8_t *)&(d_ip), '\0', NULL) != 1) {
711 printk("Invalid Dst IP address (%s)\n", ip_str);
715 d_port = simple_strtol(link_iter, &link_iter, 10);
718 link_idx = vnet_brg_add_link(d_ip, d_port, d_proto);
720 printk("VNET Control: Failed to create link\n");
724 link = kmalloc(sizeof(struct vnet_link_iter), GFP_KERNEL);
725 memset(link, 0, sizeof(struct vnet_link_iter));
728 link->dst_port = d_port;
729 link->proto = d_proto;
730 link->idx = link_idx;
732 spin_lock_irqsave(&(vnet_ctrl_s.lock), flags);
733 list_add(&(link->node), &(vnet_ctrl_s.link_iter_list));
734 vnet_ctrl_s.num_links ++;
735 spin_unlock_irqrestore(&(vnet_ctrl_s.lock), flags);
736 } else if (strnicmp("DEL", token, strlen("DEL")) == 0) {
737 char * idx_str = NULL;
740 idx_str = strsep(&link_iter, " ");
743 printk("Missing link idx in DEL Link command\n");
747 d_idx = simple_strtoul(idx_str, &idx_str, 10);
749 vnet_brg_delete_link(d_idx);
751 printk("VNET Control: One link deleted\n");
753 printk("Invalid Link command string\n");
761 static struct file_operations route_fops = {
762 .owner = THIS_MODULE,
765 .write = route_write,
767 .release = seq_release
771 static struct file_operations link_fops = {
772 .owner = THIS_MODULE,
777 .release = seq_release
782 debug_write(struct file * file, const char * buf, size_t size, loff_t * ppos) {
784 char * in_iter = NULL;
785 char * line_str = in_buf;
792 if (copy_from_user(in_buf, buf, size)) {
796 in_iter = strsep(&line_str, "\r\n");
797 level = simple_strtol(in_iter, &in_iter, 10);
799 printk("VNET Control: Set VNET Debug level to %d\n", level);
809 static int debug_show(struct seq_file * file, void * v){
810 seq_printf(file, "Current NET Debug Level: %d\n", net_debug);
815 static int debug_open(struct inode * inode, struct file * file) {
816 return single_open(file, debug_show, NULL);
819 static struct file_operations debug_fops = {
820 .owner = THIS_MODULE,
823 .write = debug_write,
825 .release = seq_release
828 static int stat_show(struct seq_file * file, void * v){
829 struct vnet_stat stats;
830 struct vnet_brg_stats brg_stats;
832 v3_vnet_stat(&stats);
834 seq_printf(file, "VNET Core\n");
835 seq_printf(file, "\tReceived Packets: %d\n", stats.rx_pkts);
836 seq_printf(file, "\tReceived Bytes: %lld\n", stats.rx_bytes);
837 seq_printf(file, "\tTransmitted Packets: %d\n", stats.tx_pkts);
838 seq_printf(file, "\tTransmitted Bytes: %lld\n", stats.tx_bytes);
840 vnet_brg_stats(&brg_stats);
842 seq_printf(file, "\nVNET Bridge Server\n");
843 seq_printf(file, "\tReceived From VMM: %lld\n", brg_stats.pkt_from_vmm);
844 seq_printf(file, "\tSent To VMM: %lld\n", brg_stats.pkt_to_vmm);
845 seq_printf(file, "\tDropped From VMM: %lld\n", brg_stats.pkt_drop_vmm);
846 seq_printf(file, "\tReceived From Extern Network: %lld\n", brg_stats.pkt_from_phy);
847 seq_printf(file, "\tSent To Extern Network: %lld\n", brg_stats.pkt_to_phy);
848 seq_printf(file, "\tDropped From Extern Network: %lld\n", brg_stats.pkt_drop_phy);
853 static int stat_open(struct inode * inode, struct file * file) {
854 return single_open(file, stat_show, NULL);
857 static struct file_operations stat_fops = {
858 .owner = THIS_MODULE,
862 .release = seq_release
866 static int init_proc_files(void) {
867 struct proc_dir_entry * route_entry = NULL;
868 struct proc_dir_entry * link_entry = NULL;
869 struct proc_dir_entry * stat_entry = NULL;
870 struct proc_dir_entry * debug_entry = NULL;
871 struct proc_dir_entry * vnet_root = NULL;
873 vnet_root = proc_mkdir("vnet", NULL);
874 if (vnet_root == NULL) {
878 route_entry = create_proc_entry("routes", 0, vnet_root);
879 if (route_entry == NULL) {
880 remove_proc_entry("vnet", NULL);
883 route_entry->proc_fops = &route_fops;
886 link_entry = create_proc_entry("links", 0, vnet_root);
887 if (link_entry == NULL) {
888 remove_proc_entry("routes", vnet_root);
889 remove_proc_entry("vnet", NULL);
892 link_entry->proc_fops = &link_fops;
895 stat_entry = create_proc_entry("stats", 0, vnet_root);
896 if(stat_entry == NULL) {
897 remove_proc_entry("links", vnet_root);
898 remove_proc_entry("routes", vnet_root);
899 remove_proc_entry("vnet", NULL);
902 stat_entry->proc_fops = &stat_fops;
905 debug_entry = create_proc_entry("debug", 0, vnet_root);
906 if(debug_entry == NULL) {
907 remove_proc_entry("links", vnet_root);
908 remove_proc_entry("routes", vnet_root);
909 remove_proc_entry("stats", vnet_root);
910 remove_proc_entry("vnet", NULL);
913 debug_entry->proc_fops = &debug_fops;
915 vnet_ctrl_s.vnet_proc_root = vnet_root;
921 static void destroy_proc_files(void) {
922 struct proc_dir_entry * vnet_root = vnet_ctrl_s.vnet_proc_root;
924 remove_proc_entry("debug", vnet_root);
925 remove_proc_entry("links", vnet_root);
926 remove_proc_entry("routes", vnet_root);
927 remove_proc_entry("stats", vnet_root);
928 remove_proc_entry("vnet", NULL);
932 int vnet_ctrl_init(void) {
933 if(vnet_ctrl_s.status != 0) {
936 vnet_ctrl_s.status = 1;
938 memset(&vnet_ctrl_s, 0, sizeof(struct vnet_ctrl_state));
940 INIT_LIST_HEAD(&(vnet_ctrl_s.link_iter_list));
941 INIT_LIST_HEAD(&(vnet_ctrl_s.route_list));
942 spin_lock_init(&(vnet_ctrl_s.lock));
946 printk("VNET Linux control module initiated\n");
952 void vnet_ctrl_deinit(void){
953 destroy_proc_files();
956 deinit_routes_list();
958 vnet_ctrl_s.status = 0;