From: Lei Xia Date: Sun, 22 May 2011 03:18:10 +0000 (-0500) Subject: add missed file X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?p=palacios.git;a=commitdiff_plain;h=465411cf0c2fd33177d032faf7a5bb59a6501104 add missed file --- diff --git a/linux_module/palacios-vnet-ctrl.c b/linux_module/palacios-vnet-ctrl.c new file mode 100644 index 0000000..f0bbac5 --- /dev/null +++ b/linux_module/palacios-vnet-ctrl.c @@ -0,0 +1,961 @@ +/* + Palacios VNET Control Module + (c) Lei Xia, 2010 + */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include "palacios-vnet.h" + +#define VNET_SERVER_PORT 9000 + +struct vnet_route_iter { + struct v3_vnet_route route; + uint32_t idx; + + struct list_head node; +}; + + +struct vnet_link_iter { + uint32_t dst_ip; + uint16_t dst_port; + vnet_brg_proto_t proto; + uint32_t idx; + + struct list_head node; +}; + + +struct vnet_ctrl_state { + uint8_t status; + + uint32_t num_links; + uint32_t num_routes; + + struct list_head route_list; + struct list_head link_iter_list; + + spinlock_t lock; + + struct proc_dir_entry * vnet_proc_root; +}; + + +static struct vnet_ctrl_state vnet_ctrl_s; + + +static int parse_mac_str(char * str, uint8_t * qual, uint8_t * mac) { + char * token; + + printk("Parsing MAC (%s)\n", str); + + *qual = MAC_NOSET; + if(strnicmp("any", str, strlen(str)) == 0){ + *qual = MAC_ANY; + return 0; + }else if(strnicmp("none", str, strlen(str)) == 0){ + *qual = MAC_NONE; + return 0; + }else{ + if (strstr(str, "-")) { + token = strsep(&str, "-"); + + if (strnicmp("not", token, strlen("not")) == 0) { + *qual = MAC_NOT; + } else { + printk("Invalid MAC String token (%s)\n", token); + return -1; + } + } + + if (strstr(str, ":")) { + int i = 0; + + if(*qual == MAC_NOSET){ + *qual = MAC_ADDR; + } + + for (i = 0; i < 6; i++) { + token = strsep(&str, ":"); + if (!token) { + printk("Invalid MAC String token (%s)\n", token); + return -1; + } + mac[i] = simple_strtol(token, &token, 16); + } + printk("MAC: %2x:%2x:%2x:%2x:%2x:%2x\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + + }else { + printk("Invalid MAC String token (%s)\n", token); + return -1; + } + + } + + return 0; +} + + +static int str2mac(char * str, uint8_t * mac){ + int i = 0; + char *hex = NULL; + + for (i = 0; i < ETH_ALEN; i++) { + hex = strsep(&str, ":"); + if (!hex) { + printk("Invalid MAC String token (%s)\n", str); + return -1; + } + mac[i] = simple_strtol(hex, &hex, 16); + } + + return 0; +} + + +static inline struct vnet_link_iter * link_by_ip(uint32_t ip) { + struct vnet_link_iter * link = NULL; + + list_for_each_entry(link, &(vnet_ctrl_s.link_iter_list), node) { + + if (link->dst_ip == ip) { + return link; + } + } + + return NULL; +} + +static inline struct vnet_link_iter * link_by_idx(int idx) { + struct vnet_link_iter * link = NULL; + + list_for_each_entry(link, &(vnet_ctrl_s.link_iter_list), node) { + if (link->idx == idx) { + return link; + } + } + + return NULL; +} + + +static int parse_route_str(char * str, struct v3_vnet_route * route) { + char * token = NULL; + struct vnet_link_iter * link = NULL; + + // src MAC + token = strsep(&str, " "); + if (!token) { + return -1; + } + parse_mac_str(token, &(route->src_mac_qual), route->src_mac); + + // dst MAC + token = strsep(&str, " "); + if (!token) { + return -1; + } + parse_mac_str(token, &(route->dst_mac_qual), route->dst_mac); + + // dst LINK type + token = strsep(&str, " "); + if (!token) { + return -1; + } + printk("dst type =(%s)\n", token); + + if (strnicmp("interface", token, strlen("interface")) == 0) { + route->dst_type = LINK_INTERFACE; + } else if (strnicmp("edge", token, strlen("edge")) == 0) { + route->dst_type = LINK_EDGE; + } else { + printk("Invalid Destination Link Type (%s)\n", token); + return -1; + } + + // dst link + token = strsep(&str, " "); + if (!token) { + return -1; + } + printk("dst ID=(%s)\n", token); + + // Figure out link here + if (route->dst_type == LINK_EDGE) { + uint32_t link_ip; + + // Figure out Link Here + if (in4_pton(token, strlen(token), (uint8_t *)&(link_ip), '\0', NULL) != 1) { + printk("Invalid Dst IP address (%s)\n", token); + return -EFAULT; + } + + link = link_by_ip(link_ip); + if (link != NULL){ + route->dst_id = link->idx; + }else{ + printk("can not find dst link %s\n", token); + return -1; + } + + printk("link_ip = %d, link_id = %d\n", link_ip, link->idx); + } else if (route->dst_type == LINK_INTERFACE) { + uint8_t mac[ETH_ALEN]; + + if(str2mac(token, mac) == -1){ + printk("wrong MAC format (%s)\n", token); + return -1; + } + + route->dst_id = v3_vnet_find_dev(mac); + if (route->dst_id == -1){ + printk("can not find dst device %s\n", token); + return -1; + } + } else { + printk("Unsupported dst link type\n"); + return -1; + } + + route->src_id = -1; + route->src_type = -1; + + // src LINK + token = strsep(&str, " "); + + printk("SRC type = %s\n", token); + + if (!token) { + return -1; + } + + if (strnicmp("interface", token, strlen("interface")) == 0) { + route->src_type = LINK_INTERFACE; + } else if (strnicmp("edge", token, strlen("edge")) == 0) { + route->src_type = LINK_EDGE; + } else if (strnicmp("any", token, strlen("any")) == 0) { + route->src_type = LINK_ANY; + } else { + printk("Invalid Src link type (%s)\n", token); + return -1; + } + + + if (route->src_type == LINK_ANY) { + route->src_id = -1; + } else if (route->src_type == LINK_EDGE) { + uint32_t src_ip; + token = strsep(&str, " "); + + if (!token) { + return -1; + } + + // Figure out Link Here + if (in4_pton(token, strlen(token), (uint8_t *)&(src_ip), '\0', NULL) != 1) { + printk("Invalid SRC IP address (%s)\n", token); + return -EFAULT; + } + + link = link_by_ip(src_ip); + if (link != NULL){ + route->src_id = link->idx; + }else{ + printk("can not find src link %s\n", token); + return -1; + } + } else if(route->src_type == LINK_INTERFACE){ + uint8_t mac[ETH_ALEN]; + + if(str2mac(token, mac) == -1){ + printk("wrong MAC format (%s)\n", token); + return -1; + } + + route->src_id = v3_vnet_find_dev(mac); + if (route->src_id == -1){ + printk("can not find dst device %s\n", token); + return -1; + } + } else { + printk("Invalid link type\n"); + return -1; + } + + return 0; +} + + +static void * route_seq_start(struct seq_file * s, loff_t * pos) { + struct vnet_route_iter * route_iter = NULL; + loff_t i = 0; + + if (*pos >= vnet_ctrl_s.num_routes) { + return NULL; + } + + list_for_each_entry(route_iter, &(vnet_ctrl_s.route_list), node) { + if (i == *pos) { + break; + } + + i++; + } + + return route_iter; +} + + +static void * route_seq_next(struct seq_file * s, void * v, loff_t * pos) { + struct vnet_route_iter * route_iter = NULL; + + route_iter = list_entry(((struct vnet_route_iter *)v)->node.next, struct vnet_route_iter, node); + + // Check if the list has looped + if (&(route_iter->node) == &(vnet_ctrl_s.route_list)) { + return NULL; + } + + *pos += 1; + + return route_iter; +} + +static void route_seq_stop(struct seq_file * s, void * v) { + + return; +} + +static void * link_seq_start(struct seq_file * s, loff_t * pos) { + struct vnet_link_iter * link_iter = NULL; + loff_t i = 0; + + if (*pos >= vnet_ctrl_s.num_links) { + return NULL; + } + + list_for_each_entry(link_iter, &(vnet_ctrl_s.link_iter_list), node) { + if (i == *pos) { + break; + } + + i++; + } + + return link_iter; +} + +static int route_seq_show(struct seq_file * s, void * v) { + struct vnet_route_iter * route_iter = v; + struct v3_vnet_route * route = &(route_iter->route); + + seq_printf(s, "%d:\t", route_iter->idx); + + seq_printf(s, "\nSrc:\t"); + switch (route->src_mac_qual) { + case MAC_ANY: + seq_printf(s, "any "); + break; + case MAC_NONE: + seq_printf(s, "none "); + break; + case MAC_NOT: + seq_printf(s, "not-%2x:%2x:%2x:%2x:%2x:%2x ", + route->src_mac[0], route->src_mac[1], route->src_mac[2], + route->src_mac[3], route->src_mac[4], route->src_mac[5]); + break; + default: + seq_printf(s, "%x:%x:%x:%x:%x:%x ", + route->src_mac[0], route->src_mac[1], route->src_mac[2], + route->src_mac[3], route->src_mac[4], route->src_mac[5]); + break; + } + + seq_printf(s, "\nDst:\t"); + switch (route->dst_mac_qual) { + case MAC_ANY: + seq_printf(s, "any "); + break; + case MAC_NONE: + seq_printf(s, "none "); + break; + case MAC_NOT: + seq_printf(s, "not-%x:%x:%x:%x:%x:%x ", + route->src_mac[0], route->src_mac[1], route->src_mac[2], + route->src_mac[3], route->src_mac[4], route->src_mac[5]); + break; + default: + seq_printf(s, "%x:%x:%x:%x:%x:%x ", + route->src_mac[0], route->src_mac[1], route->src_mac[2], + route->src_mac[3], route->src_mac[4], route->src_mac[5]); + break; + } + + seq_printf(s, "\nDst-Type:\t"); + switch (route->dst_type) { + case LINK_EDGE: { + struct vnet_link_iter * link = (struct vnet_link_iter *)link_by_idx(route->dst_id); + seq_printf(s, "EDGE %pI4", &link->dst_ip); + break; + } + case LINK_INTERFACE: { + seq_printf(s, "INTERFACE "); + seq_printf(s, "%d ", route->dst_id); + break; + } + default: + seq_printf(s, "Invalid Dst Link Type (%d) ", route->dst_type); + break; + } + + seq_printf(s, "\nSrc-Type:\t"); + switch (route->src_type) { + case LINK_EDGE: { + struct vnet_link_iter * link = (struct vnet_link_iter *)link_by_idx(route->src_id); + seq_printf(s, "EDGE %pI4", &link->dst_ip); + break; + } + case LINK_INTERFACE: { + seq_printf(s, "INTERFACE %d", route->src_id); + break; + } + case LINK_ANY: + seq_printf(s, "ANY"); + break; + default: + seq_printf(s, "Invalid Src Link Type (%d) ", route->src_type); + break; + } + + seq_printf(s, "\n"); + + return 0; +} + +static void * link_seq_next(struct seq_file * s, void * v, loff_t * pos) { + struct vnet_link_iter * link_iter = NULL; + + link_iter = list_entry(((struct vnet_link_iter *)v)->node.next, struct vnet_link_iter, node); + + // Check if the list has looped + if (&(link_iter->node) == &(vnet_ctrl_s.link_iter_list)) { + return NULL; + } + + *pos += 1; + + return link_iter; +} + +static void link_seq_stop(struct seq_file * s, void * v) { + + return; +} + +static int link_seq_show(struct seq_file * s, void * v) { + struct vnet_link_iter * link_iter = v; + struct nic_statistics stats; + + vnet_brg_link_stats(link_iter->idx, &stats); + + 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", + link_iter->idx, + &link_iter->dst_ip, + link_iter->dst_port, + stats.rx_pkts, + stats.rx_bytes, + stats.tx_pkts, + stats.tx_bytes); + + return 0; +} + + +static struct seq_operations route_seq_ops = { + .start = route_seq_start, + .next = route_seq_next, + .stop = route_seq_stop, + .show = route_seq_show +}; + + +static struct seq_operations link_seq_ops = { + .start = link_seq_start, + .next = link_seq_next, + .stop = link_seq_stop, + .show = link_seq_show +}; + + +static int route_open(struct inode * inode, struct file * file) { + return seq_open(file, &route_seq_ops); +} + + +static int link_open(struct inode * inode, struct file * file) { + return seq_open(file, &link_seq_ops); +} + + + +static int inject_route(struct vnet_route_iter * route) { + unsigned long flags; + + route->idx = v3_vnet_add_route(route->route); + + spin_lock_irqsave(&(vnet_ctrl_s.lock), flags); + list_add(&(route->node), &(vnet_ctrl_s.route_list)); + vnet_ctrl_s.num_routes ++; + spin_unlock_irqrestore(&(vnet_ctrl_s.lock), flags); + + printk("VNET Control: One route added to VNET core\n"); + + return 0; +} + + +static void delete_route(struct vnet_route_iter * route) { + unsigned long flags; + + v3_vnet_del_route(route->idx); + + spin_lock_irqsave(&(vnet_ctrl_s.lock), flags); + list_del(&(route->node)); + vnet_ctrl_s.num_routes --; + spin_unlock_irqrestore(&(vnet_ctrl_s.lock), flags); + + printk("VNET Control: Route %d deleted from VNET\n", route->idx); + + kfree(route); + route = NULL; +} + + +/* Format: + * add src-MAC dst-MAC dst-TYPE [dst-ID] src-TYPE [src-ID] + * + * src-MAC = dst-MAC = not-MAC|any|none|MAC + * dst-TYPE = edge|interface + * src-TYPE = edge|interface|any + * dst-ID = src-ID = IP|MAC + * MAC=xx:xx:xx:xx:xx:xx + * IP = xxx.xxx.xxx.xxx + * + * + * del route-idx + * + */ +static ssize_t +route_write(struct file * file, + const char * buf, + size_t size, + loff_t * ppos) { + char route_buf[256]; + char * buf_iter = NULL; + char * line_str = route_buf; + char * token = NULL; + + if (size >= 256) { + return -EFAULT; + } + + if (copy_from_user(route_buf, buf, size)) { + return -EFAULT; + } + + route_buf[size] = '\0'; + printk("Route written: %s\n", route_buf); + + while ((buf_iter = strsep(&line_str, "\r\n"))) { + + token = strsep(&buf_iter, " "); + if (!token) { + return -EFAULT; + } + + if (strnicmp("ADD", token, strlen("ADD")) == 0) { + struct vnet_route_iter * new_route = NULL; + new_route = kmalloc(sizeof(struct vnet_route_iter), GFP_KERNEL); + + if (!new_route) { + return -ENOMEM; + } + + memset(new_route, 0, sizeof(struct vnet_route_iter)); + + if (parse_route_str(buf_iter, &(new_route->route)) == -1) { + kfree(new_route); + return -EFAULT; + } + + if (inject_route(new_route) != 0) { + kfree(new_route); + return -EFAULT; + } + } else if (strnicmp("DEL", token, strlen("DEL")) == 0) { + char * idx_str = NULL; + uint32_t d_idx; + + idx_str = strsep(&buf_iter, " "); + + if (!idx_str) { + printk("Missing route idx in DEL Route command\n"); + return -EFAULT; + } + + d_idx = simple_strtoul(idx_str, &idx_str, 10); + + v3_vnet_del_route(d_idx); + + printk("VNET Control: One route deleted\n"); + + } else { + printk("Invalid Route command string\n"); + } + } + + return size; +} + + +static void delete_link(struct vnet_link_iter * link){ + unsigned long flags; + + vnet_brg_delete_link(link->idx); + + spin_lock_irqsave(&(vnet_ctrl_s.lock), flags); + list_del(&(link->node)); + vnet_ctrl_s.num_links --; + spin_unlock_irqrestore(&(vnet_ctrl_s.lock), flags); + + kfree(link); + link = NULL; +} + + +static void deinit_links_list(void){ + struct vnet_link_iter * link; + + list_for_each_entry(link, &(vnet_ctrl_s.link_iter_list), node) { + delete_link(link); + } +} + +static void deinit_routes_list(void){ + struct vnet_route_iter * route; + + list_for_each_entry(route, &(vnet_ctrl_s.route_list), node) { + delete_route(route); + } +} + +/* ADD dst-ip 9000 [udp|tcp] */ +/* DEL link-idx */ +static ssize_t +link_write(struct file * file, const char * buf, size_t size, loff_t * ppos) { + char link_buf[256]; + char * link_iter = NULL; + char * line_str = link_buf; + char * token = NULL; + + if (size >= 256) { + return -EFAULT; + } + + if (copy_from_user(link_buf, buf, size)) { + return -EFAULT; + } + + while ((link_iter = strsep(&line_str, "\r\n"))) { + printk("Link written: %s\n", link_buf); + + token = strsep(&link_iter, " "); + + if (!token) { + return -EFAULT; + } + + if (strnicmp("ADD", token, strlen("ADD")) == 0) { + struct vnet_link_iter * link = NULL; + char * ip_str = NULL; + uint32_t d_ip; + uint16_t d_port; + vnet_brg_proto_t d_proto; + int link_idx; + unsigned long flags; + + ip_str = strsep(&link_iter, " "); + + if ((!ip_str) || (!link_iter)) { + printk("Missing fields in ADD Link command\n"); + return -EFAULT; + } + + if (in4_pton(ip_str, strlen(ip_str), (uint8_t *)&(d_ip), '\0', NULL) != 1) { + printk("Invalid Dst IP address (%s)\n", ip_str); + return -EFAULT; + } + + d_port = simple_strtol(link_iter, &link_iter, 10); + d_proto = UDP; + + link_idx = vnet_brg_add_link(d_ip, d_port, d_proto); + if(link_idx < 0){ + printk("VNET Control: Failed to create link\n"); + return -EFAULT; + } + + link = kmalloc(sizeof(struct vnet_link_iter), GFP_KERNEL); + memset(link, 0, sizeof(struct vnet_link_iter)); + + link->dst_ip = d_ip; + link->dst_port = d_port; + link->proto = d_proto; + link->idx = link_idx; + + spin_lock_irqsave(&(vnet_ctrl_s.lock), flags); + list_add(&(link->node), &(vnet_ctrl_s.link_iter_list)); + vnet_ctrl_s.num_links ++; + spin_unlock_irqrestore(&(vnet_ctrl_s.lock), flags); + } else if (strnicmp("DEL", token, strlen("DEL")) == 0) { + char * idx_str = NULL; + uint32_t d_idx; + + idx_str = strsep(&link_iter, " "); + + if (!idx_str) { + printk("Missing link idx in DEL Link command\n"); + return -EFAULT; + } + + d_idx = simple_strtoul(idx_str, &idx_str, 10); + + vnet_brg_delete_link(d_idx); + + printk("VNET Control: One link deleted\n"); + } else { + printk("Invalid Link command string\n"); + } + } + + return size; +} + + +static struct file_operations route_fops = { + .owner = THIS_MODULE, + .open = route_open, + .read = seq_read, + .write = route_write, + .llseek = seq_lseek, + .release = seq_release +}; + + +static struct file_operations link_fops = { + .owner = THIS_MODULE, + .open = link_open, + .read = seq_read, + .write = link_write, + .llseek = seq_lseek, + .release = seq_release +}; + + +static ssize_t +debug_write(struct file * file, const char * buf, size_t size, loff_t * ppos) { + char in_buf[32]; + char * in_iter = NULL; + char * line_str = in_buf; + int level = -1; + + if (size >= 32) { + return -EFAULT; + } + + if (copy_from_user(in_buf, buf, size)) { + return -EFAULT; + } + + in_iter = strsep(&line_str, "\r\n"); + level = simple_strtol(in_iter, &in_iter, 10); + + printk("VNET Control: Set VNET Debug level to %d\n", level); + + if(level >= 0){ + net_debug = level; + } + + return size; +} + + +static int debug_show(struct seq_file * file, void * v){ + seq_printf(file, "Current NET Debug Level: %d\n", net_debug); + + return 0; +} + +static int debug_open(struct inode * inode, struct file * file) { + return single_open(file, debug_show, NULL); +} + +static struct file_operations debug_fops = { + .owner = THIS_MODULE, + .open = debug_open, + .read = seq_read, + .write = debug_write, + .llseek = seq_lseek, + .release = seq_release +}; + +static int stat_show(struct seq_file * file, void * v){ + struct vnet_stat stats; + struct vnet_brg_stats brg_stats; + + v3_vnet_stat(&stats); + + seq_printf(file, "VNET Core\n"); + seq_printf(file, "\tReceived Packets: %d\n", stats.rx_pkts); + seq_printf(file, "\tReceived Bytes: %lld\n", stats.rx_bytes); + seq_printf(file, "\tTransmitted Packets: %d\n", stats.tx_pkts); + seq_printf(file, "\tTransmitted Bytes: %lld\n", stats.tx_bytes); + + vnet_brg_stats(&brg_stats); + + seq_printf(file, "\nVNET Bridge Server\n"); + seq_printf(file, "\tReceived From VMM: %lld\n", brg_stats.pkt_from_vmm); + seq_printf(file, "\tSent To VMM: %lld\n", brg_stats.pkt_to_vmm); + seq_printf(file, "\tDropped From VMM: %lld\n", brg_stats.pkt_drop_vmm); + seq_printf(file, "\tReceived From Extern Network: %lld\n", brg_stats.pkt_from_phy); + seq_printf(file, "\tSent To Extern Network: %lld\n", brg_stats.pkt_to_phy); + seq_printf(file, "\tDropped From Extern Network: %lld\n", brg_stats.pkt_drop_phy); + + return 0; +} + +static int stat_open(struct inode * inode, struct file * file) { + return single_open(file, stat_show, NULL); +} + +static struct file_operations stat_fops = { + .owner = THIS_MODULE, + .open = stat_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release +}; + + +static int init_proc_files(void) { + struct proc_dir_entry * route_entry = NULL; + struct proc_dir_entry * link_entry = NULL; + struct proc_dir_entry * stat_entry = NULL; + struct proc_dir_entry * debug_entry = NULL; + struct proc_dir_entry * vnet_root = NULL; + + vnet_root = proc_mkdir("vnet", NULL); + if (vnet_root == NULL) { + return -1; + } + + route_entry = create_proc_entry("routes", 0, vnet_root); + if (route_entry == NULL) { + remove_proc_entry("vnet", NULL); + return -1; + } + route_entry->proc_fops = &route_fops; + + + link_entry = create_proc_entry("links", 0, vnet_root); + if (link_entry == NULL) { + remove_proc_entry("routes", vnet_root); + remove_proc_entry("vnet", NULL); + return -1; + } + link_entry->proc_fops = &link_fops; + + + stat_entry = create_proc_entry("stats", 0, vnet_root); + if(stat_entry == NULL) { + remove_proc_entry("links", vnet_root); + remove_proc_entry("routes", vnet_root); + remove_proc_entry("vnet", NULL); + return -1; + } + stat_entry->proc_fops = &stat_fops; + + + debug_entry = create_proc_entry("debug", 0, vnet_root); + if(debug_entry == NULL) { + remove_proc_entry("links", vnet_root); + remove_proc_entry("routes", vnet_root); + remove_proc_entry("stats", vnet_root); + remove_proc_entry("vnet", NULL); + return -1; + } + debug_entry->proc_fops = &debug_fops; + + vnet_ctrl_s.vnet_proc_root = vnet_root; + + return 0; +} + + +static void destroy_proc_files(void) { + struct proc_dir_entry * vnet_root = vnet_ctrl_s.vnet_proc_root; + + remove_proc_entry("debug", vnet_root); + remove_proc_entry("links", vnet_root); + remove_proc_entry("routes", vnet_root); + remove_proc_entry("stats", vnet_root); + remove_proc_entry("vnet", NULL); +} + + +int vnet_ctrl_init(void) { + if(vnet_ctrl_s.status != 0) { + return -1; + } + vnet_ctrl_s.status = 1; + + memset(&vnet_ctrl_s, 0, sizeof(struct vnet_ctrl_state)); + + INIT_LIST_HEAD(&(vnet_ctrl_s.link_iter_list)); + INIT_LIST_HEAD(&(vnet_ctrl_s.route_list)); + spin_lock_init(&(vnet_ctrl_s.lock)); + + init_proc_files(); + + printk("VNET Linux control module initiated\n"); + + return 0; +} + + +void vnet_ctrl_deinit(void){ + destroy_proc_files(); + + deinit_links_list(); + deinit_routes_list(); + + vnet_ctrl_s.status = 0; +} + +