2 * Palacios VNET Control Module
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>
13 #include <linux/netdevice.h>
16 #include <linux/net.h>
17 #include <linux/string.h>
18 #include <linux/preempt.h>
19 #include <linux/sched.h>
22 #include <vnet/vnet.h>
23 #include <vnet/vnet_hashtable.h>
24 #include "palacios-vnet.h"
27 #define VNET_SERVER_PORT 9000
29 struct vnet_route_iter {
30 struct v3_vnet_route route;
33 struct list_head node;
37 struct vnet_link_iter {
40 vnet_brg_proto_t proto;
43 struct list_head node;
47 struct vnet_ctrl_state {
53 struct list_head route_list;
54 struct list_head link_iter_list;
58 struct proc_dir_entry * vnet_proc_root;
62 static struct vnet_ctrl_state vnet_ctrl_s;
65 static int parse_mac_str(char * str, uint8_t * qual, uint8_t * mac) {
68 INFO("Parsing MAC (%s)\n", str);
71 if(strnicmp("any", str, strlen(str)) == 0){
74 }else if(strnicmp("none", str, strlen(str)) == 0){
78 if (strstr(str, "-")) {
79 token = strsep(&str, "-");
81 if (strnicmp("not", token, strlen("not")) == 0) {
84 WARNING("Invalid MAC String token (%s)\n", token);
89 if (strstr(str, ":")) {
92 if(*qual == MAC_NOSET){
96 for (i = 0; i < 6; i++) {
97 token = strsep(&str, ":");
99 WARNING("Invalid MAC String token (%s)\n", token);
102 mac[i] = simple_strtol(token, &token, 16);
104 DEBUG("MAC: %2x:%2x:%2x:%2x:%2x:%2x\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
107 WARNING("Invalid MAC String token (%s)\n", token);
117 static int str2mac(char * str, uint8_t * mac){
121 for (i = 0; i < ETH_ALEN; i++) {
122 hex = strsep(&str, ":");
124 WARNING("Invalid MAC String token (%s)\n", str);
127 mac[i] = simple_strtol(hex, &hex, 16);
134 static inline struct vnet_link_iter * link_by_ip(uint32_t ip) {
135 struct vnet_link_iter * link = NULL;
137 list_for_each_entry(link, &(vnet_ctrl_s.link_iter_list), node) {
139 if (link->dst_ip == ip) {
147 static inline struct vnet_link_iter * link_by_idx(int idx) {
148 struct vnet_link_iter * link = NULL;
150 list_for_each_entry(link, &(vnet_ctrl_s.link_iter_list), node) {
151 if (link->idx == idx) {
160 static int parse_route_str(char * str, struct v3_vnet_route * route) {
162 struct vnet_link_iter * link = NULL;
165 token = strsep(&str, " ");
169 parse_mac_str(token, &(route->src_mac_qual), route->src_mac);
172 token = strsep(&str, " ");
176 parse_mac_str(token, &(route->dst_mac_qual), route->dst_mac);
179 token = strsep(&str, " ");
183 INFO("dst type =(%s)\n", token);
185 if (strnicmp("interface", token, strlen("interface")) == 0) {
186 route->dst_type = LINK_INTERFACE;
187 } else if (strnicmp("edge", token, strlen("edge")) == 0) {
188 route->dst_type = LINK_EDGE;
190 WARNING("Invalid Destination Link Type (%s)\n", token);
195 token = strsep(&str, " ");
199 DEBUG("dst ID=(%s)\n", token);
201 // Figure out link here
202 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 WARNING("Invalid Dst IP address (%s)\n", token);
211 link = link_by_ip(link_ip);
213 route->dst_id = link->idx;
215 WARNING("can not find dst link %s\n", token);
219 INFO("link_ip = %d, link_id = %d\n", link_ip, link->idx);
220 } else if (route->dst_type == LINK_INTERFACE) {
221 uint8_t mac[ETH_ALEN];
223 if(str2mac(token, mac) == -1){
224 WARNING("wrong MAC format (%s)\n", token);
228 route->dst_id = v3_vnet_find_dev(mac);
229 if (route->dst_id == -1){
230 WARNING("can not find dst device %s\n", token);
234 WARNING("Unsupported dst link type\n");
239 route->src_type = -1;
242 token = strsep(&str, " ");
244 INFO("SRC type = %s\n", token);
250 if (strnicmp("interface", token, strlen("interface")) == 0) {
251 route->src_type = LINK_INTERFACE;
252 } else if (strnicmp("edge", token, strlen("edge")) == 0) {
253 route->src_type = LINK_EDGE;
254 } else if (strnicmp("any", token, strlen("any")) == 0) {
255 route->src_type = LINK_ANY;
257 WARNING("Invalid Src link type (%s)\n", token);
262 if (route->src_type == LINK_ANY) {
264 } else if (route->src_type == LINK_EDGE) {
266 token = strsep(&str, " ");
272 // Figure out Link Here
273 if (in4_pton(token, strlen(token), (uint8_t *)&(src_ip), '\0', NULL) != 1) {
274 WARNING("Invalid SRC IP address (%s)\n", token);
278 link = link_by_ip(src_ip);
280 route->src_id = link->idx;
282 WARNING("can not find src link %s\n", token);
285 } else if(route->src_type == LINK_INTERFACE){
286 uint8_t mac[ETH_ALEN];
288 if(str2mac(token, mac) == -1){
289 WARNING("wrong MAC format (%s)\n", token);
293 route->src_id = v3_vnet_find_dev(mac);
294 if (route->src_id == -1){
295 WARNING("can not find dst device %s\n", token);
299 WARNING("Invalid link type\n");
307 static void * route_seq_start(struct seq_file * s, loff_t * pos) {
308 struct vnet_route_iter * route_iter = NULL;
311 if (*pos >= vnet_ctrl_s.num_routes) {
315 list_for_each_entry(route_iter, &(vnet_ctrl_s.route_list), node) {
327 static void * route_seq_next(struct seq_file * s, void * v, loff_t * pos) {
328 struct vnet_route_iter * route_iter = NULL;
330 route_iter = list_entry(((struct vnet_route_iter *)v)->node.next, struct vnet_route_iter, node);
332 // Check if the list has looped
333 if (&(route_iter->node) == &(vnet_ctrl_s.route_list)) {
342 static void route_seq_stop(struct seq_file * s, void * v) {
347 static void * link_seq_start(struct seq_file * s, loff_t * pos) {
348 struct vnet_link_iter * link_iter = NULL;
351 if (*pos >= vnet_ctrl_s.num_links) {
355 list_for_each_entry(link_iter, &(vnet_ctrl_s.link_iter_list), node) {
366 static int route_seq_show(struct seq_file * s, void * v) {
367 struct vnet_route_iter * route_iter = v;
368 struct v3_vnet_route * route = &(route_iter->route);
370 seq_printf(s, "%d:\t", route_iter->idx);
372 seq_printf(s, "\nSrc:\t");
373 switch (route->src_mac_qual) {
375 seq_printf(s, "any ");
378 seq_printf(s, "none ");
381 seq_printf(s, "not-%2x:%2x:%2x:%2x:%2x:%2x ",
382 route->src_mac[0], route->src_mac[1], route->src_mac[2],
383 route->src_mac[3], route->src_mac[4], route->src_mac[5]);
386 seq_printf(s, "%x:%x:%x:%x:%x:%x ",
387 route->src_mac[0], route->src_mac[1], route->src_mac[2],
388 route->src_mac[3], route->src_mac[4], route->src_mac[5]);
392 seq_printf(s, "\nDst:\t");
393 switch (route->dst_mac_qual) {
395 seq_printf(s, "any ");
398 seq_printf(s, "none ");
401 seq_printf(s, "not-%x:%x:%x:%x:%x:%x ",
402 route->src_mac[0], route->src_mac[1], route->src_mac[2],
403 route->src_mac[3], route->src_mac[4], route->src_mac[5]);
406 seq_printf(s, "%x:%x:%x:%x:%x:%x ",
407 route->src_mac[0], route->src_mac[1], route->src_mac[2],
408 route->src_mac[3], route->src_mac[4], route->src_mac[5]);
412 seq_printf(s, "\nDst-Type:\t");
413 switch (route->dst_type) {
415 struct vnet_link_iter * link = (struct vnet_link_iter *)link_by_idx(route->dst_id);
416 seq_printf(s, "EDGE %pI4", &link->dst_ip);
419 case LINK_INTERFACE: {
420 seq_printf(s, "INTERFACE ");
421 seq_printf(s, "%d ", route->dst_id);
425 seq_printf(s, "Invalid Dst Link Type (%d) ", route->dst_type);
429 seq_printf(s, "\nSrc-Type:\t");
430 switch (route->src_type) {
432 struct vnet_link_iter * link = (struct vnet_link_iter *)link_by_idx(route->src_id);
433 seq_printf(s, "EDGE %pI4", &link->dst_ip);
436 case LINK_INTERFACE: {
437 seq_printf(s, "INTERFACE %d", route->src_id);
441 seq_printf(s, "ANY");
444 seq_printf(s, "Invalid Src Link Type (%d) ", route->src_type);
453 static void * link_seq_next(struct seq_file * s, void * v, loff_t * pos) {
454 struct vnet_link_iter * link_iter = NULL;
456 link_iter = list_entry(((struct vnet_link_iter *)v)->node.next, struct vnet_link_iter, node);
458 // Check if the list has looped
459 if (&(link_iter->node) == &(vnet_ctrl_s.link_iter_list)) {
468 static void link_seq_stop(struct seq_file * s, void * v) {
473 static int link_seq_show(struct seq_file * s, void * v) {
474 struct vnet_link_iter * link_iter = v;
475 struct nic_statistics stats;
477 vnet_brg_link_stats(link_iter->idx, &stats);
479 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",
492 static struct seq_operations route_seq_ops = {
493 .start = route_seq_start,
494 .next = route_seq_next,
495 .stop = route_seq_stop,
496 .show = route_seq_show
500 static struct seq_operations link_seq_ops = {
501 .start = link_seq_start,
502 .next = link_seq_next,
503 .stop = link_seq_stop,
504 .show = link_seq_show
508 static int route_open(struct inode * inode, struct file * file) {
509 return seq_open(file, &route_seq_ops);
513 static int link_open(struct inode * inode, struct file * file) {
514 return seq_open(file, &link_seq_ops);
519 static int inject_route(struct vnet_route_iter * route) {
522 route->idx = v3_vnet_add_route(route->route);
524 spin_lock_irqsave(&(vnet_ctrl_s.lock), flags);
525 list_add(&(route->node), &(vnet_ctrl_s.route_list));
526 vnet_ctrl_s.num_routes ++;
527 spin_unlock_irqrestore(&(vnet_ctrl_s.lock), flags);
529 INFO("VNET Control: One route added to VNET core\n");
535 static void delete_route(struct vnet_route_iter * route) {
538 v3_vnet_del_route(route->idx);
540 spin_lock_irqsave(&(vnet_ctrl_s.lock), flags);
541 list_del(&(route->node));
542 vnet_ctrl_s.num_routes --;
543 spin_unlock_irqrestore(&(vnet_ctrl_s.lock), flags);
545 INFO("VNET Control: Route %d deleted from VNET\n", route->idx);
547 palacios_free(route);
553 * add src-MAC dst-MAC dst-TYPE [dst-ID] src-TYPE [src-ID]
555 * src-MAC = dst-MAC = not-MAC|any|none|MAC
556 * dst-TYPE = edge|interface
557 * src-TYPE = edge|interface|any
558 * dst-ID = src-ID = IP|MAC
559 * MAC=xx:xx:xx:xx:xx:xx
560 * IP = xxx.xxx.xxx.xxx
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 route_buf[size] = '\0';
585 INFO("Route written: %s\n", route_buf);
587 while ((buf_iter = strsep(&line_str, "\r\n"))) {
589 token = strsep(&buf_iter, " ");
594 if (strnicmp("ADD", token, strlen("ADD")) == 0) {
595 struct vnet_route_iter * new_route = NULL;
596 new_route = palacios_alloc(sizeof(struct vnet_route_iter));
599 ERROR("Cannot allocate new route\n");
603 memset(new_route, 0, sizeof(struct vnet_route_iter));
605 if (parse_route_str(buf_iter, &(new_route->route)) == -1) {
606 ERROR("Cannot parse new route\n");
607 palacios_free(new_route);
611 if (inject_route(new_route) != 0) {
612 ERROR("Cannot inject new route\n");
613 palacios_free(new_route);
616 } else if (strnicmp("DEL", token, strlen("DEL")) == 0) {
617 char * idx_str = NULL;
619 struct vnet_route_iter * route = NULL;
621 idx_str = strsep(&buf_iter, " ");
624 WARNING("Missing route idx in DEL Route command\n");
628 d_idx = simple_strtoul(idx_str, &idx_str, 10);
630 INFO("VNET: deleting route %d\n", d_idx);
632 list_for_each_entry(route, &(vnet_ctrl_s.route_list), node) {
633 if (route->idx == d_idx) {
639 WARNING("Invalid Route command string\n");
647 static void delete_link(struct vnet_link_iter * link){
650 vnet_brg_delete_link(link->idx);
652 spin_lock_irqsave(&(vnet_ctrl_s.lock), flags);
653 list_del(&(link->node));
654 vnet_ctrl_s.num_links --;
655 spin_unlock_irqrestore(&(vnet_ctrl_s.lock), flags);
662 static void deinit_links_list(void){
663 struct vnet_link_iter * link, * tmp_link;
665 list_for_each_entry_safe(link, tmp_link, &(vnet_ctrl_s.link_iter_list), node) {
670 static void deinit_routes_list(void){
671 struct vnet_route_iter * route, * tmp_route;
673 list_for_each_entry_safe(route, tmp_route, &(vnet_ctrl_s.route_list), node) {
678 /* ADD dst-ip 9000 [udp|tcp] */
681 link_write(struct file * file, const char * buf, size_t size, loff_t * ppos) {
683 char * link_iter = NULL;
684 char * line_str = link_buf;
691 if (copy_from_user(link_buf, buf, size)) {
695 while ((link_iter = strsep(&line_str, "\r\n"))) {
696 DEBUG("Link written: %s\n", link_buf);
698 token = strsep(&link_iter, " ");
704 if (strnicmp("ADD", token, strlen("ADD")) == 0) {
705 struct vnet_link_iter * link = NULL;
706 char * ip_str = NULL;
709 vnet_brg_proto_t d_proto;
713 ip_str = strsep(&link_iter, " ");
715 if ((!ip_str) || (!link_iter)) {
716 WARNING("Missing fields in ADD Link command\n");
720 if (in4_pton(ip_str, strlen(ip_str), (uint8_t *)&(d_ip), '\0', NULL) != 1) {
721 WARNING("Invalid Dst IP address (%s)\n", ip_str);
725 d_port = simple_strtol(link_iter, &link_iter, 10);
728 link_idx = vnet_brg_add_link(d_ip, d_port, d_proto);
730 WARNING("VNET Control: Failed to create link\n");
734 link = palacios_alloc(sizeof(struct vnet_link_iter));
736 WARNING("VNET Control: Cannot allocate link\n");
740 memset(link, 0, sizeof(struct vnet_link_iter));
743 link->dst_port = d_port;
744 link->proto = d_proto;
745 link->idx = link_idx;
747 spin_lock_irqsave(&(vnet_ctrl_s.lock), flags);
748 list_add(&(link->node), &(vnet_ctrl_s.link_iter_list));
749 vnet_ctrl_s.num_links ++;
750 spin_unlock_irqrestore(&(vnet_ctrl_s.lock), flags);
751 } else if (strnicmp("DEL", token, strlen("DEL")) == 0) {
752 char * idx_str = NULL;
755 idx_str = strsep(&link_iter, " ");
758 WARNING("Missing link idx in DEL Link command\n");
762 d_idx = simple_strtoul(idx_str, &idx_str, 10);
764 vnet_brg_delete_link(d_idx);
766 DEBUG("VNET Control: One link deleted\n");
768 WARNING("Invalid Link command string\n");
776 static struct file_operations route_fops = {
777 .owner = THIS_MODULE,
780 .write = route_write,
782 .release = seq_release
786 static struct file_operations link_fops = {
787 .owner = THIS_MODULE,
792 .release = seq_release
797 debug_write(struct file * file, const char * buf, size_t size, loff_t * ppos) {
799 char * in_iter = NULL;
800 char * line_str = in_buf;
807 if (copy_from_user(in_buf, buf, size)) {
811 in_iter = strsep(&line_str, "\r\n");
812 level = simple_strtol(in_iter, &in_iter, 10);
814 DEBUG("VNET Control: Set VNET Debug level to %d\n", level);
824 static int debug_show(struct seq_file * file, void * v){
825 seq_printf(file, "Current NET Debug Level: %d\n", net_debug);
830 static int debug_open(struct inode * inode, struct file * file) {
831 return single_open(file, debug_show, NULL);
834 static struct file_operations debug_fops = {
835 .owner = THIS_MODULE,
838 .write = debug_write,
840 .release = seq_release
843 static int stat_show(struct seq_file * file, void * v){
844 struct vnet_stat stats;
845 struct vnet_brg_stats brg_stats;
847 v3_vnet_stat(&stats);
849 seq_printf(file, "VNET Core\n");
850 seq_printf(file, "\tReceived Packets: %d\n", stats.rx_pkts);
851 seq_printf(file, "\tReceived Bytes: %lld\n", stats.rx_bytes);
852 seq_printf(file, "\tTransmitted Packets: %d\n", stats.tx_pkts);
853 seq_printf(file, "\tTransmitted Bytes: %lld\n", stats.tx_bytes);
855 vnet_brg_stats(&brg_stats);
857 seq_printf(file, "\nVNET Bridge Server\n");
858 seq_printf(file, "\tReceived From VMM: %lld\n", brg_stats.pkt_from_vmm);
859 seq_printf(file, "\tSent To VMM: %lld\n", brg_stats.pkt_to_vmm);
860 seq_printf(file, "\tDropped From VMM: %lld\n", brg_stats.pkt_drop_vmm);
861 seq_printf(file, "\tReceived From Extern Network: %lld\n", brg_stats.pkt_from_phy);
862 seq_printf(file, "\tSent To Extern Network: %lld\n", brg_stats.pkt_to_phy);
863 seq_printf(file, "\tDropped From Extern Network: %lld\n", brg_stats.pkt_drop_phy);
868 static int stat_open(struct inode * inode, struct file * file) {
869 return single_open(file, stat_show, NULL);
872 static struct file_operations stat_fops = {
873 .owner = THIS_MODULE,
877 .release = seq_release
881 static int init_proc_files(void) {
882 struct proc_dir_entry * route_entry = NULL;
883 struct proc_dir_entry * link_entry = NULL;
884 struct proc_dir_entry * stat_entry = NULL;
885 struct proc_dir_entry * debug_entry = NULL;
886 struct proc_dir_entry * vnet_root = NULL;
889 vnet_root = proc_mkdir("vnet", palacios_get_procdir());
891 if (vnet_root == NULL) {
895 route_entry = create_proc_entry("routes", 0, vnet_root);
896 if (route_entry == NULL) {
897 remove_proc_entry("vnet", NULL);
900 route_entry->proc_fops = &route_fops;
903 link_entry = create_proc_entry("links", 0, vnet_root);
904 if (link_entry == NULL) {
905 remove_proc_entry("routes", vnet_root);
906 remove_proc_entry("vnet", NULL);
909 link_entry->proc_fops = &link_fops;
912 stat_entry = create_proc_entry("stats", 0, vnet_root);
913 if(stat_entry == NULL) {
914 remove_proc_entry("links", vnet_root);
915 remove_proc_entry("routes", vnet_root);
916 remove_proc_entry("vnet", NULL);
919 stat_entry->proc_fops = &stat_fops;
922 debug_entry = create_proc_entry("debug", 0, vnet_root);
923 if(debug_entry == NULL) {
924 remove_proc_entry("links", vnet_root);
925 remove_proc_entry("routes", vnet_root);
926 remove_proc_entry("stats", vnet_root);
927 remove_proc_entry("vnet", NULL);
930 debug_entry->proc_fops = &debug_fops;
932 vnet_ctrl_s.vnet_proc_root = vnet_root;
938 static void destroy_proc_files(void) {
939 struct proc_dir_entry * vnet_root = vnet_ctrl_s.vnet_proc_root;
941 remove_proc_entry("debug", vnet_root);
942 remove_proc_entry("links", vnet_root);
943 remove_proc_entry("routes", vnet_root);
944 remove_proc_entry("stats", vnet_root);
945 remove_proc_entry("vnet", NULL);
949 int vnet_ctrl_init(void) {
950 if(vnet_ctrl_s.status != 0) {
953 vnet_ctrl_s.status = 1;
955 memset(&vnet_ctrl_s, 0, sizeof(struct vnet_ctrl_state));
957 INIT_LIST_HEAD(&(vnet_ctrl_s.link_iter_list));
958 INIT_LIST_HEAD(&(vnet_ctrl_s.route_list));
959 spin_lock_init(&(vnet_ctrl_s.lock));
963 NOTICE("VNET Linux control module initiated\n");
969 void vnet_ctrl_deinit(void){
971 INFO("VNET Control Deinit Started\n");
973 destroy_proc_files();
976 deinit_routes_list();
978 vnet_ctrl_s.status = 0;
980 INFO("VNET Control Deinit Finished\n");