2 * This file is part of the Palacios Virtual Machine Monitor developed
3 * by the V3VEE Project with funding from the United States National
4 * Science Foundation and the Department of Energy.
6 * The V3VEE Project is a joint project between Northwestern University
7 * and the University of New Mexico. You can find out more at
10 * Copyright (c) 2011, Lei Xia <lxia@northwestern.edu>
11 * Copyright (c) 2011, The V3VEE Project <http://www.v3vee.org>
12 * All rights reserved.
14 * This is free software. You are permitted to use, redistribute,
15 * and modify it under the terms of the GNU General Public License
16 * Version 2 (GPLv2). The accompanying COPYING file contains the
17 * full text of the license.
19 /* Palacios VNET Control Module */
21 #include <linux/spinlock.h>
22 #include <linux/seq_file.h>
23 #include <linux/proc_fs.h>
24 #include <asm/uaccess.h>
25 #include <linux/inet.h>
26 #include <linux/kthread.h>
28 #include <linux/netdevice.h>
31 #include <linux/net.h>
32 #include <linux/string.h>
33 #include <linux/preempt.h>
34 #include <linux/sched.h>
37 #include <vnet/vnet.h>
38 #include <vnet/vnet_hashtable.h>
39 #include "palacios-vnet.h"
41 #define VNET_SERVER_PORT 9000
43 struct vnet_route_iter {
44 struct v3_vnet_route route;
47 struct list_head node;
51 struct vnet_link_iter {
54 vnet_brg_proto_t proto;
57 struct list_head node;
61 struct vnet_ctrl_state {
67 struct list_head route_list;
68 struct list_head link_iter_list;
72 struct proc_dir_entry * vnet_proc_root;
76 static struct vnet_ctrl_state vnet_ctrl_s;
79 static int parse_mac_str(char * str, uint8_t * qual, uint8_t * mac) {
82 printk("Parsing MAC (%s)\n", str);
85 if(strnicmp("any", str, strlen(str)) == 0){
88 }else if(strnicmp("none", str, strlen(str)) == 0){
92 if (strstr(str, "-")) {
93 token = strsep(&str, "-");
95 if (strnicmp("not", token, strlen("not")) == 0) {
98 printk("Invalid MAC String token (%s)\n", token);
103 if (strstr(str, ":")) {
106 if(*qual == MAC_NOSET){
110 for (i = 0; i < 6; i++) {
111 token = strsep(&str, ":");
113 printk("Invalid MAC String token (%s)\n", token);
116 mac[i] = simple_strtol(token, &token, 16);
118 printk("MAC: %2x:%2x:%2x:%2x:%2x:%2x\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
121 printk("Invalid MAC String token (%s)\n", token);
131 static int str2mac(char * str, uint8_t * mac){
135 for (i = 0; i < ETH_ALEN; i++) {
136 hex = strsep(&str, ":");
138 printk("Invalid MAC String token (%s)\n", str);
141 mac[i] = simple_strtol(hex, &hex, 16);
148 static inline struct vnet_link_iter * link_by_ip(uint32_t ip) {
149 struct vnet_link_iter * link = NULL;
151 list_for_each_entry(link, &(vnet_ctrl_s.link_iter_list), node) {
153 if (link->dst_ip == ip) {
161 static inline struct vnet_link_iter * link_by_idx(int idx) {
162 struct vnet_link_iter * link = NULL;
164 list_for_each_entry(link, &(vnet_ctrl_s.link_iter_list), node) {
165 if (link->idx == idx) {
174 static int parse_route_str(char * str, struct v3_vnet_route * route) {
176 struct vnet_link_iter * link = NULL;
179 token = strsep(&str, " ");
183 parse_mac_str(token, &(route->src_mac_qual), route->src_mac);
186 token = strsep(&str, " ");
190 parse_mac_str(token, &(route->dst_mac_qual), route->dst_mac);
193 token = strsep(&str, " ");
197 printk("dst type =(%s)\n", token);
199 if (strnicmp("interface", token, strlen("interface")) == 0) {
200 route->dst_type = LINK_INTERFACE;
201 } else if (strnicmp("edge", token, strlen("edge")) == 0) {
202 route->dst_type = LINK_EDGE;
204 printk("Invalid Destination Link Type (%s)\n", token);
209 token = strsep(&str, " ");
213 printk("dst ID=(%s)\n", token);
215 // Figure out link here
216 if (route->dst_type == LINK_EDGE) {
219 // Figure out Link Here
220 if (in4_pton(token, strlen(token), (uint8_t *)&(link_ip), '\0', NULL) != 1) {
221 printk("Invalid Dst IP address (%s)\n", token);
225 link = link_by_ip(link_ip);
227 route->dst_id = link->idx;
229 printk("can not find dst link %s\n", token);
233 printk("link_ip = %d, link_id = %d\n", link_ip, link->idx);
234 } else if (route->dst_type == LINK_INTERFACE) {
235 uint8_t mac[ETH_ALEN];
237 if(str2mac(token, mac) == -1){
238 printk("wrong MAC format (%s)\n", token);
242 route->dst_id = v3_vnet_find_dev(mac);
243 if (route->dst_id == -1){
244 printk("can not find dst device %s\n", token);
248 printk("Unsupported dst link type\n");
253 route->src_type = -1;
256 token = strsep(&str, " ");
258 printk("SRC type = %s\n", token);
264 if (strnicmp("interface", token, strlen("interface")) == 0) {
265 route->src_type = LINK_INTERFACE;
266 } else if (strnicmp("edge", token, strlen("edge")) == 0) {
267 route->src_type = LINK_EDGE;
268 } else if (strnicmp("any", token, strlen("any")) == 0) {
269 route->src_type = LINK_ANY;
271 printk("Invalid Src link type (%s)\n", token);
276 if (route->src_type == LINK_ANY) {
278 } else if (route->src_type == LINK_EDGE) {
280 token = strsep(&str, " ");
286 // Figure out Link Here
287 if (in4_pton(token, strlen(token), (uint8_t *)&(src_ip), '\0', NULL) != 1) {
288 printk("Invalid SRC IP address (%s)\n", token);
292 link = link_by_ip(src_ip);
294 route->src_id = link->idx;
296 printk("can not find src link %s\n", token);
299 } else if(route->src_type == LINK_INTERFACE){
300 uint8_t mac[ETH_ALEN];
302 if(str2mac(token, mac) == -1){
303 printk("wrong MAC format (%s)\n", token);
307 route->src_id = v3_vnet_find_dev(mac);
308 if (route->src_id == -1){
309 printk("can not find dst device %s\n", token);
313 printk("Invalid link type\n");
321 static void * route_seq_start(struct seq_file * s, loff_t * pos) {
322 struct vnet_route_iter * route_iter = NULL;
325 if (*pos >= vnet_ctrl_s.num_routes) {
329 list_for_each_entry(route_iter, &(vnet_ctrl_s.route_list), node) {
341 static void * route_seq_next(struct seq_file * s, void * v, loff_t * pos) {
342 struct vnet_route_iter * route_iter = NULL;
344 route_iter = list_entry(((struct vnet_route_iter *)v)->node.next, struct vnet_route_iter, node);
346 // Check if the list has looped
347 if (&(route_iter->node) == &(vnet_ctrl_s.route_list)) {
356 static void route_seq_stop(struct seq_file * s, void * v) {
361 static void * link_seq_start(struct seq_file * s, loff_t * pos) {
362 struct vnet_link_iter * link_iter = NULL;
365 if (*pos >= vnet_ctrl_s.num_links) {
369 list_for_each_entry(link_iter, &(vnet_ctrl_s.link_iter_list), node) {
380 static int route_seq_show(struct seq_file * s, void * v) {
381 struct vnet_route_iter * route_iter = v;
382 struct v3_vnet_route * route = &(route_iter->route);
384 seq_printf(s, "%d:\t", route_iter->idx);
386 seq_printf(s, "\nSrc:\t");
387 switch (route->src_mac_qual) {
389 seq_printf(s, "any ");
392 seq_printf(s, "none ");
395 seq_printf(s, "not-%2x:%2x:%2x:%2x:%2x:%2x ",
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]);
400 seq_printf(s, "%x:%x:%x:%x:%x:%x ",
401 route->src_mac[0], route->src_mac[1], route->src_mac[2],
402 route->src_mac[3], route->src_mac[4], route->src_mac[5]);
406 seq_printf(s, "\nDst:\t");
407 switch (route->dst_mac_qual) {
409 seq_printf(s, "any ");
412 seq_printf(s, "none ");
415 seq_printf(s, "not-%x:%x:%x:%x:%x:%x ",
416 route->src_mac[0], route->src_mac[1], route->src_mac[2],
417 route->src_mac[3], route->src_mac[4], route->src_mac[5]);
420 seq_printf(s, "%x:%x:%x:%x:%x:%x ",
421 route->src_mac[0], route->src_mac[1], route->src_mac[2],
422 route->src_mac[3], route->src_mac[4], route->src_mac[5]);
426 seq_printf(s, "\nDst-Type:\t");
427 switch (route->dst_type) {
429 struct vnet_link_iter * link = (struct vnet_link_iter *)link_by_idx(route->dst_id);
430 seq_printf(s, "EDGE %pI4", &link->dst_ip);
433 case LINK_INTERFACE: {
434 seq_printf(s, "INTERFACE ");
435 seq_printf(s, "%d ", route->dst_id);
439 seq_printf(s, "Invalid Dst Link Type (%d) ", route->dst_type);
443 seq_printf(s, "\nSrc-Type:\t");
444 switch (route->src_type) {
446 struct vnet_link_iter * link = (struct vnet_link_iter *)link_by_idx(route->src_id);
447 seq_printf(s, "EDGE %pI4", &link->dst_ip);
450 case LINK_INTERFACE: {
451 seq_printf(s, "INTERFACE %d", route->src_id);
455 seq_printf(s, "ANY");
458 seq_printf(s, "Invalid Src Link Type (%d) ", route->src_type);
467 static void * link_seq_next(struct seq_file * s, void * v, loff_t * pos) {
468 struct vnet_link_iter * link_iter = NULL;
470 link_iter = list_entry(((struct vnet_link_iter *)v)->node.next, struct vnet_link_iter, node);
472 // Check if the list has looped
473 if (&(link_iter->node) == &(vnet_ctrl_s.link_iter_list)) {
482 static void link_seq_stop(struct seq_file * s, void * v) {
487 static int link_seq_show(struct seq_file * s, void * v) {
488 struct vnet_link_iter * link_iter = v;
489 struct nic_statistics stats;
491 vnet_brg_link_stats(link_iter->idx, &stats);
493 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",
506 static struct seq_operations route_seq_ops = {
507 .start = route_seq_start,
508 .next = route_seq_next,
509 .stop = route_seq_stop,
510 .show = route_seq_show
514 static struct seq_operations link_seq_ops = {
515 .start = link_seq_start,
516 .next = link_seq_next,
517 .stop = link_seq_stop,
518 .show = link_seq_show
522 static int route_open(struct inode * inode, struct file * file) {
523 return seq_open(file, &route_seq_ops);
527 static int link_open(struct inode * inode, struct file * file) {
528 return seq_open(file, &link_seq_ops);
533 static int inject_route(struct vnet_route_iter * route) {
536 route->idx = v3_vnet_add_route(route->route);
538 spin_lock_irqsave(&(vnet_ctrl_s.lock), flags);
539 list_add(&(route->node), &(vnet_ctrl_s.route_list));
540 vnet_ctrl_s.num_routes ++;
541 spin_unlock_irqrestore(&(vnet_ctrl_s.lock), flags);
543 printk("VNET Control: One route added to VNET core\n");
549 static void delete_route(struct vnet_route_iter * route) {
552 v3_vnet_del_route(route->idx);
554 spin_lock_irqsave(&(vnet_ctrl_s.lock), flags);
555 list_del(&(route->node));
556 vnet_ctrl_s.num_routes --;
557 spin_unlock_irqrestore(&(vnet_ctrl_s.lock), flags);
559 printk("VNET Control: Route %d deleted from VNET\n", route->idx);
567 * add src-MAC dst-MAC dst-TYPE [dst-ID] src-TYPE [src-ID]
569 * src-MAC = dst-MAC = not-MAC|any|none|MAC
570 * dst-TYPE = edge|interface
571 * src-TYPE = edge|interface|any
572 * dst-ID = src-ID = IP|MAC
573 * MAC=xx:xx:xx:xx:xx:xx
574 * IP = xxx.xxx.xxx.xxx
581 route_write(struct file * file,
586 char * buf_iter = NULL;
587 char * line_str = route_buf;
594 if (copy_from_user(route_buf, buf, size)) {
598 route_buf[size] = '\0';
599 printk("Route written: %s\n", route_buf);
601 while ((buf_iter = strsep(&line_str, "\r\n"))) {
603 token = strsep(&buf_iter, " ");
608 if (strnicmp("ADD", token, strlen("ADD")) == 0) {
609 struct vnet_route_iter * new_route = NULL;
610 new_route = kmalloc(sizeof(struct vnet_route_iter), GFP_KERNEL);
616 memset(new_route, 0, sizeof(struct vnet_route_iter));
618 if (parse_route_str(buf_iter, &(new_route->route)) == -1) {
623 if (inject_route(new_route) != 0) {
627 } else if (strnicmp("DEL", token, strlen("DEL")) == 0) {
628 char * idx_str = NULL;
630 struct vnet_route_iter * route = NULL;
632 idx_str = strsep(&buf_iter, " ");
635 printk("Missing route idx in DEL Route command\n");
639 d_idx = simple_strtoul(idx_str, &idx_str, 10);
641 printk("VNET: deleting route %d\n", d_idx);
643 list_for_each_entry(route, &(vnet_ctrl_s.route_list), node) {
644 if (route->idx == d_idx) {
650 printk("Invalid Route command string\n");
658 static void delete_link(struct vnet_link_iter * link){
661 vnet_brg_delete_link(link->idx);
663 spin_lock_irqsave(&(vnet_ctrl_s.lock), flags);
664 list_del(&(link->node));
665 vnet_ctrl_s.num_links --;
666 spin_unlock_irqrestore(&(vnet_ctrl_s.lock), flags);
673 static void deinit_links_list(void){
674 struct vnet_link_iter * link;
676 list_for_each_entry(link, &(vnet_ctrl_s.link_iter_list), node) {
681 static void deinit_routes_list(void){
682 struct vnet_route_iter * route;
684 list_for_each_entry(route, &(vnet_ctrl_s.route_list), node) {
689 /* ADD dst-ip 9000 [udp|tcp] */
692 link_write(struct file * file, const char * buf, size_t size, loff_t * ppos) {
694 char * link_iter = NULL;
695 char * line_str = link_buf;
702 if (copy_from_user(link_buf, buf, size)) {
706 while ((link_iter = strsep(&line_str, "\r\n"))) {
707 printk("Link written: %s\n", link_buf);
709 token = strsep(&link_iter, " ");
715 if (strnicmp("ADD", token, strlen("ADD")) == 0) {
716 struct vnet_link_iter * link = NULL;
717 char * ip_str = NULL;
720 vnet_brg_proto_t d_proto;
724 ip_str = strsep(&link_iter, " ");
726 if ((!ip_str) || (!link_iter)) {
727 printk("Missing fields in ADD Link command\n");
731 if (in4_pton(ip_str, strlen(ip_str), (uint8_t *)&(d_ip), '\0', NULL) != 1) {
732 printk("Invalid Dst IP address (%s)\n", ip_str);
736 d_port = simple_strtol(link_iter, &link_iter, 10);
739 link_idx = vnet_brg_add_link(d_ip, d_port, d_proto);
741 printk("VNET Control: Failed to create link\n");
745 link = kmalloc(sizeof(struct vnet_link_iter), GFP_KERNEL);
746 memset(link, 0, sizeof(struct vnet_link_iter));
749 link->dst_port = d_port;
750 link->proto = d_proto;
751 link->idx = link_idx;
753 spin_lock_irqsave(&(vnet_ctrl_s.lock), flags);
754 list_add(&(link->node), &(vnet_ctrl_s.link_iter_list));
755 vnet_ctrl_s.num_links ++;
756 spin_unlock_irqrestore(&(vnet_ctrl_s.lock), flags);
757 } else if (strnicmp("DEL", token, strlen("DEL")) == 0) {
758 char * idx_str = NULL;
761 idx_str = strsep(&link_iter, " ");
764 printk("Missing link idx in DEL Link command\n");
768 d_idx = simple_strtoul(idx_str, &idx_str, 10);
770 vnet_brg_delete_link(d_idx);
772 printk("VNET Control: One link deleted\n");
774 printk("Invalid Link command string\n");
782 static struct file_operations route_fops = {
783 .owner = THIS_MODULE,
786 .write = route_write,
788 .release = seq_release
792 static struct file_operations link_fops = {
793 .owner = THIS_MODULE,
798 .release = seq_release
803 debug_write(struct file * file, const char * buf, size_t size, loff_t * ppos) {
805 char * in_iter = NULL;
806 char * line_str = in_buf;
813 if (copy_from_user(in_buf, buf, size)) {
817 in_iter = strsep(&line_str, "\r\n");
818 level = simple_strtol(in_iter, &in_iter, 10);
820 printk("VNET Control: Set VNET Debug level to %d\n", level);
830 static int debug_show(struct seq_file * file, void * v){
831 seq_printf(file, "Current NET Debug Level: %d\n", net_debug);
836 static int debug_open(struct inode * inode, struct file * file) {
837 return single_open(file, debug_show, NULL);
840 static struct file_operations debug_fops = {
841 .owner = THIS_MODULE,
844 .write = debug_write,
846 .release = seq_release
849 static int stat_show(struct seq_file * file, void * v){
850 struct vnet_stat stats;
851 struct vnet_brg_stats brg_stats;
853 v3_vnet_stat(&stats);
855 seq_printf(file, "VNET Core\n");
856 seq_printf(file, "\tReceived Packets: %d\n", stats.rx_pkts);
857 seq_printf(file, "\tReceived Bytes: %lld\n", stats.rx_bytes);
858 seq_printf(file, "\tTransmitted Packets: %d\n", stats.tx_pkts);
859 seq_printf(file, "\tTransmitted Bytes: %lld\n", stats.tx_bytes);
861 vnet_brg_stats(&brg_stats);
863 seq_printf(file, "\nVNET Bridge Server\n");
864 seq_printf(file, "\tReceived From VMM: %lld\n", brg_stats.pkt_from_vmm);
865 seq_printf(file, "\tSent To VMM: %lld\n", brg_stats.pkt_to_vmm);
866 seq_printf(file, "\tDropped From VMM: %lld\n", brg_stats.pkt_drop_vmm);
867 seq_printf(file, "\tReceived From Extern Network: %lld\n", brg_stats.pkt_from_phy);
868 seq_printf(file, "\tSent To Extern Network: %lld\n", brg_stats.pkt_to_phy);
869 seq_printf(file, "\tDropped From Extern Network: %lld\n", brg_stats.pkt_drop_phy);
874 static int stat_open(struct inode * inode, struct file * file) {
875 return single_open(file, stat_show, NULL);
878 static struct file_operations stat_fops = {
879 .owner = THIS_MODULE,
883 .release = seq_release
887 static int init_proc_files(void) {
888 struct proc_dir_entry * route_entry = NULL;
889 struct proc_dir_entry * link_entry = NULL;
890 struct proc_dir_entry * stat_entry = NULL;
891 struct proc_dir_entry * debug_entry = NULL;
892 struct proc_dir_entry * vnet_root = NULL;
894 vnet_root = proc_mkdir("vnet", NULL);
895 if (vnet_root == NULL) {
899 route_entry = create_proc_entry("routes", 0, vnet_root);
900 if (route_entry == NULL) {
901 remove_proc_entry("vnet", NULL);
904 route_entry->proc_fops = &route_fops;
907 link_entry = create_proc_entry("links", 0, vnet_root);
908 if (link_entry == NULL) {
909 remove_proc_entry("routes", vnet_root);
910 remove_proc_entry("vnet", NULL);
913 link_entry->proc_fops = &link_fops;
916 stat_entry = create_proc_entry("stats", 0, vnet_root);
917 if(stat_entry == NULL) {
918 remove_proc_entry("links", vnet_root);
919 remove_proc_entry("routes", vnet_root);
920 remove_proc_entry("vnet", NULL);
923 stat_entry->proc_fops = &stat_fops;
926 debug_entry = create_proc_entry("debug", 0, vnet_root);
927 if(debug_entry == NULL) {
928 remove_proc_entry("links", vnet_root);
929 remove_proc_entry("routes", vnet_root);
930 remove_proc_entry("stats", vnet_root);
931 remove_proc_entry("vnet", NULL);
934 debug_entry->proc_fops = &debug_fops;
936 vnet_ctrl_s.vnet_proc_root = vnet_root;
942 static void destroy_proc_files(void) {
943 struct proc_dir_entry * vnet_root = vnet_ctrl_s.vnet_proc_root;
945 remove_proc_entry("debug", vnet_root);
946 remove_proc_entry("links", vnet_root);
947 remove_proc_entry("routes", vnet_root);
948 remove_proc_entry("stats", vnet_root);
949 remove_proc_entry("vnet", NULL);
953 int vnet_ctrl_init(void) {
954 if(vnet_ctrl_s.status != 0) {
957 vnet_ctrl_s.status = 1;
959 memset(&vnet_ctrl_s, 0, sizeof(struct vnet_ctrl_state));
961 INIT_LIST_HEAD(&(vnet_ctrl_s.link_iter_list));
962 INIT_LIST_HEAD(&(vnet_ctrl_s.route_list));
963 spin_lock_init(&(vnet_ctrl_s.lock));
967 printk("VNET Linux control module initiated\n");
973 void vnet_ctrl_deinit(void){
974 destroy_proc_files();
977 deinit_routes_list();
979 vnet_ctrl_s.status = 0;