X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=lib%2Flibrte_eal%2Flinuxapp%2Fkni%2Fkni_misc.c;h=59d15ca6eb94a22ac8c24bb0aeacb61bd9e60e5e;hb=73983b2bdae8a285c3cca3bbd18a7e965c3f1cca;hp=79ab1f9b9233b2f5b21796f98c9dc52f1f4ce66b;hpb=9c61145ff6f977dd55ccf6c293f842eb768f45c2;p=dpdk.git diff --git a/lib/librte_eal/linuxapp/kni/kni_misc.c b/lib/librte_eal/linuxapp/kni/kni_misc.c index 79ab1f9b92..59d15ca6eb 100644 --- a/lib/librte_eal/linuxapp/kni/kni_misc.c +++ b/lib/librte_eal/linuxapp/kni/kni_misc.c @@ -1,37 +1,43 @@ /*- * GPL LICENSE SUMMARY - * - * Copyright(c) 2010-2013 Intel Corporation. All rights reserved. - * + * + * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. + * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. - * + * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. * The full GNU General Public License is included in this distribution * in the file called LICENSE.GPL. - * + * * Contact Information: * Intel Corporation */ +#include #include #include #include +#include #include #include #include +#include +#include +#include #include + +#include "compat.h" #include "kni_dev.h" -#include MODULE_LICENSE("Dual BSD/GPL"); MODULE_AUTHOR("Intel Corporation"); @@ -90,18 +96,70 @@ static unsigned multiple_kthread_on = 0; #define KNI_DEV_IN_USE_BIT_NUM 0 /* Bit number for device in use */ -static volatile unsigned long device_in_use; /* device in use flag */ -static struct task_struct *kni_kthread; +static int kni_net_id; + +struct kni_net { + unsigned long device_in_use; /* device in use flag */ + struct task_struct *kni_kthread; + struct rw_semaphore kni_list_lock; + struct list_head kni_list_head; +}; + +static int __net_init kni_init_net(struct net *net) +{ +#ifdef HAVE_SIMPLIFIED_PERNET_OPERATIONS + struct kni_net *knet = net_generic(net, kni_net_id); +#else + struct kni_net *knet; + int ret; + + knet = kmalloc(sizeof(struct kni_net), GFP_KERNEL); + if (!knet) { + ret = -ENOMEM; + return ret; + } +#endif + + /* Clear the bit of device in use */ + clear_bit(KNI_DEV_IN_USE_BIT_NUM, &knet->device_in_use); -/* kni list lock */ -static DECLARE_RWSEM(kni_list_lock); + init_rwsem(&knet->kni_list_lock); + INIT_LIST_HEAD(&knet->kni_list_head); -/* kni list */ -static struct list_head kni_list_head = LIST_HEAD_INIT(kni_list_head); +#ifdef HAVE_SIMPLIFIED_PERNET_OPERATIONS + return 0; +#else + ret = net_assign_generic(net, kni_net_id, knet); + if (ret < 0) + kfree(knet); + + return ret; +#endif +} + +static void __net_exit kni_exit_net(struct net *net) +{ +#ifndef HAVE_SIMPLIFIED_PERNET_OPERATIONS + struct kni_net *knet = net_generic(net, kni_net_id); + + kfree(knet); +#endif +} + +static struct pernet_operations kni_net_ops = { + .init = kni_init_net, + .exit = kni_exit_net, +#ifdef HAVE_SIMPLIFIED_PERNET_OPERATIONS + .id = &kni_net_id, + .size = sizeof(struct kni_net), +#endif +}; static int __init kni_init(void) { + int rc; + KNI_PRINT("######## DPDK kni module loading ########\n"); if (kni_parse_kthread_mode() < 0) { @@ -109,13 +167,19 @@ kni_init(void) return -EINVAL; } - if (misc_register(&kni_misc) != 0) { - KNI_ERR("Misc registration failed\n"); +#ifdef HAVE_SIMPLIFIED_PERNET_OPERATIONS + rc = register_pernet_subsys(&kni_net_ops); +#else + rc = register_pernet_gen_subsys(&kni_net_id, &kni_net_ops); +#endif + if (rc) return -EPERM; - } - /* Clear the bit of device in use */ - clear_bit(KNI_DEV_IN_USE_BIT_NUM, &device_in_use); + rc = misc_register(&kni_misc); + if (rc != 0) { + KNI_ERR("Misc registration failed\n"); + goto out; + } /* Configure the lo mode according to the input parameter */ kni_net_config_lo_mode(lo_mode); @@ -123,12 +187,25 @@ kni_init(void) KNI_PRINT("######## DPDK kni module loaded ########\n"); return 0; + +out: +#ifdef HAVE_SIMPLIFIED_PERNET_OPERATIONS + unregister_pernet_subsys(&kni_net_ops); +#else + register_pernet_gen_subsys(&kni_net_id, &kni_net_ops); +#endif + return rc; } static void __exit kni_exit(void) { misc_deregister(&kni_misc); +#ifdef HAVE_SIMPLIFIED_PERNET_OPERATIONS + unregister_pernet_subsys(&kni_net_ops); +#else + register_pernet_gen_subsys(&kni_net_id, &kni_net_ops); +#endif KNI_PRINT("####### DPDK kni module unloaded #######\n"); } @@ -151,23 +228,27 @@ kni_parse_kthread_mode(void) static int kni_open(struct inode *inode, struct file *file) { - /* kni device can be opened by one user only, test and set bit */ - if (test_and_set_bit(KNI_DEV_IN_USE_BIT_NUM, &device_in_use)) + struct net *net = current->nsproxy->net_ns; + struct kni_net *knet = net_generic(net, kni_net_id); + + /* kni device can be opened by one user only per netns */ + if (test_and_set_bit(KNI_DEV_IN_USE_BIT_NUM, &knet->device_in_use)) return -EBUSY; /* Create kernel thread for single mode */ if (multiple_kthread_on == 0) { KNI_PRINT("Single kernel thread for all KNI devices\n"); /* Create kernel thread for RX */ - kni_kthread = kthread_run(kni_thread_single, NULL, + knet->kni_kthread = kthread_run(kni_thread_single, (void *)knet, "kni_single"); - if (IS_ERR(kni_kthread)) { + if (IS_ERR(knet->kni_kthread)) { KNI_ERR("Unable to create kernel threaed\n"); - return PTR_ERR(kni_kthread); + return PTR_ERR(knet->kni_kthread); } } else KNI_PRINT("Multiple kernel thread mode enabled\n"); + file->private_data = get_net(net); KNI_PRINT("/dev/kni opened\n"); return 0; @@ -176,55 +257,67 @@ kni_open(struct inode *inode, struct file *file) static int kni_release(struct inode *inode, struct file *file) { + struct net *net = file->private_data; + struct kni_net *knet = net_generic(net, kni_net_id); struct kni_dev *dev, *n; /* Stop kernel thread for single mode */ if (multiple_kthread_on == 0) { /* Stop kernel thread */ - kthread_stop(kni_kthread); - kni_kthread = NULL; + kthread_stop(knet->kni_kthread); + knet->kni_kthread = NULL; } - down_write(&kni_list_lock); - list_for_each_entry_safe(dev, n, &kni_list_head, list) { + down_write(&knet->kni_list_lock); + list_for_each_entry_safe(dev, n, &knet->kni_list_head, list) { /* Stop kernel thread for multiple mode */ if (multiple_kthread_on && dev->pthread != NULL) { kthread_stop(dev->pthread); dev->pthread = NULL; } +#ifdef RTE_KNI_VHOST + kni_vhost_backend_release(dev); +#endif kni_dev_remove(dev); list_del(&dev->list); } - up_write(&kni_list_lock); + up_write(&knet->kni_list_lock); /* Clear the bit of device in use */ - clear_bit(KNI_DEV_IN_USE_BIT_NUM, &device_in_use); + clear_bit(KNI_DEV_IN_USE_BIT_NUM, &knet->device_in_use); + put_net(net); KNI_PRINT("/dev/kni closed\n"); return 0; } static int -kni_thread_single(void *unused) +kni_thread_single(void *data) { + struct kni_net *knet = data; int j; - struct kni_dev *dev, *n; + struct kni_dev *dev; while (!kthread_should_stop()) { - down_read(&kni_list_lock); + down_read(&knet->kni_list_lock); for (j = 0; j < KNI_RX_LOOP_NUM; j++) { - list_for_each_entry_safe(dev, n, - &kni_list_head, list) { + list_for_each_entry(dev, &knet->kni_list_head, list) { +#ifdef RTE_KNI_VHOST + kni_chk_vhost_rx(dev); +#else kni_net_rx(dev); +#endif kni_net_poll_resp(dev); } } - up_read(&kni_list_lock); + up_read(&knet->kni_list_lock); +#ifdef RTE_KNI_PREEMPT_DEFAULT /* reschedule out for a while */ schedule_timeout_interruptible(usecs_to_jiffies( \ KNI_KTHREAD_RESCHEDULE_INTERVAL)); +#endif } return 0; @@ -238,11 +331,17 @@ kni_thread_multiple(void *param) while (!kthread_should_stop()) { for (j = 0; j < KNI_RX_LOOP_NUM; j++) { +#ifdef RTE_KNI_VHOST + kni_chk_vhost_rx(dev); +#else kni_net_rx(dev); +#endif kni_net_poll_resp(dev); } +#ifdef RTE_KNI_PREEMPT_DEFAULT schedule_timeout_interruptible(usecs_to_jiffies( \ KNI_KTHREAD_RESCHEDULE_INTERVAL)); +#endif } return 0; @@ -291,8 +390,10 @@ kni_check_param(struct kni_dev *kni, struct rte_kni_device_info *dev) } static int -kni_ioctl_create(unsigned int ioctl_num, unsigned long ioctl_param) +kni_ioctl_create(struct net *net, + unsigned int ioctl_num, unsigned long ioctl_param) { + struct kni_net *knet = net_generic(net, kni_net_id); int ret; struct rte_kni_device_info dev_info; struct pci_dev *pci = NULL; @@ -324,22 +425,27 @@ kni_ioctl_create(unsigned int ioctl_num, unsigned long ioctl_param) } /* Check if it has been created */ - down_read(&kni_list_lock); - list_for_each_entry_safe(dev, n, &kni_list_head, list) { + down_read(&knet->kni_list_lock); + list_for_each_entry_safe(dev, n, &knet->kni_list_head, list) { if (kni_check_param(dev, &dev_info) < 0) { - up_read(&kni_list_lock); + up_read(&knet->kni_list_lock); return -EINVAL; } } - up_read(&kni_list_lock); + up_read(&knet->kni_list_lock); net_dev = alloc_netdev(sizeof(struct kni_dev), dev_info.name, +#ifdef NET_NAME_UNKNOWN + NET_NAME_UNKNOWN, +#endif kni_net_init); if (net_dev == NULL) { KNI_ERR("error allocating device \"%s\"\n", dev_info.name); return -EBUSY; } + dev_net_set(net_dev, net); + kni = netdev_priv(net_dev); kni->net_dev = net_dev; @@ -361,6 +467,10 @@ kni_ioctl_create(unsigned int ioctl_num, unsigned long ioctl_param) kni->mbuf_kva = phys_to_virt(dev_info.mbuf_phys); kni->mbuf_va = dev_info.mbuf_va; +#ifdef RTE_KNI_VHOST + kni->vhost_queue = NULL; + kni->vq_status = BE_STOP; +#endif kni->mbuf_size = dev_info.mbuf_size; KNI_PRINT("tx_phys: 0x%016llx, tx_q addr: 0x%p\n", @@ -435,6 +545,15 @@ kni_ioctl_create(unsigned int ioctl_num, unsigned long ioctl_param) if (pci) pci_dev_put(pci); + if (kni->lad_dev) + memcpy(net_dev->dev_addr, kni->lad_dev->dev_addr, ETH_ALEN); + else + /* + * Generate random mac address. eth_random_addr() is the newer + * version of generating mac address in linux kernel. + */ + random_ether_addr(net_dev->dev_addr); + ret = register_netdev(net_dev); if (ret) { KNI_ERR("error %i registering device \"%s\"\n", @@ -443,6 +562,10 @@ kni_ioctl_create(unsigned int ioctl_num, unsigned long ioctl_param) return -ENODEV; } +#ifdef RTE_KNI_VHOST + kni_vhost_init(kni); +#endif + /** * Create a new kernel thread for multiple mode, set its core affinity, * and finally wake it up. @@ -460,16 +583,18 @@ kni_ioctl_create(unsigned int ioctl_num, unsigned long ioctl_param) wake_up_process(kni->pthread); } - down_write(&kni_list_lock); - list_add(&kni->list, &kni_list_head); - up_write(&kni_list_lock); + down_write(&knet->kni_list_lock); + list_add(&kni->list, &knet->kni_list_head); + up_write(&knet->kni_list_lock); return 0; } static int -kni_ioctl_release(unsigned int ioctl_num, unsigned long ioctl_param) +kni_ioctl_release(struct net *net, + unsigned int ioctl_num, unsigned long ioctl_param) { + struct kni_net *knet = net_generic(net, kni_net_id); int ret = -EINVAL; struct kni_dev *dev, *n; struct rte_kni_device_info dev_info; @@ -487,8 +612,8 @@ kni_ioctl_release(unsigned int ioctl_num, unsigned long ioctl_param) if (strlen(dev_info.name) == 0) return ret; - down_write(&kni_list_lock); - list_for_each_entry_safe(dev, n, &kni_list_head, list) { + down_write(&knet->kni_list_lock); + list_for_each_entry_safe(dev, n, &knet->kni_list_head, list) { if (strncmp(dev->name, dev_info.name, RTE_KNI_NAMESIZE) != 0) continue; @@ -497,12 +622,15 @@ kni_ioctl_release(unsigned int ioctl_num, unsigned long ioctl_param) dev->pthread = NULL; } +#ifdef RTE_KNI_VHOST + kni_vhost_backend_release(dev); +#endif kni_dev_remove(dev); list_del(&dev->list); ret = 0; break; } - up_write(&kni_list_lock); + up_write(&knet->kni_list_lock); printk(KERN_INFO "KNI: %s release kni named %s\n", (ret == 0 ? "Successfully" : "Unsuccessfully"), dev_info.name); @@ -515,8 +643,9 @@ kni_ioctl(struct inode *inode, unsigned long ioctl_param) { int ret = -EINVAL; + struct net *net = current->nsproxy->net_ns; - KNI_DBG("IOCTL num=0x%0x param=0x%0lx \n", ioctl_num, ioctl_param); + KNI_DBG("IOCTL num=0x%0x param=0x%0lx\n", ioctl_num, ioctl_param); /* * Switch according to the ioctl called @@ -526,13 +655,13 @@ kni_ioctl(struct inode *inode, /* For test only, not used */ break; case _IOC_NR(RTE_KNI_IOCTL_CREATE): - ret = kni_ioctl_create(ioctl_num, ioctl_param); + ret = kni_ioctl_create(net, ioctl_num, ioctl_param); break; case _IOC_NR(RTE_KNI_IOCTL_RELEASE): - ret = kni_ioctl_release(ioctl_num, ioctl_param); + ret = kni_ioctl_release(net, ioctl_num, ioctl_param); break; default: - KNI_DBG("IOCTL default \n"); + KNI_DBG("IOCTL default\n"); break; } @@ -569,4 +698,3 @@ MODULE_PARM_DESC(kthread_mode, " multiple Multiple kernel thread mode enabled.\n" "\n" ); -