From 9c61145ff6f977dd55ccf6c293f842eb768f45c2 Mon Sep 17 00:00:00 2001 From: Intel Date: Wed, 18 Sep 2013 12:00:00 +0200 Subject: [PATCH] kni: allow multiple threads In this new mode, each KNI device has its own kernel thread for Rx. The core affinity is configurable. Signed-off-by: Intel --- lib/librte_eal/linuxapp/kni/kni_dev.h | 4 +- lib/librte_eal/linuxapp/kni/kni_misc.c | 186 +++++++++++++++++++------ lib/librte_kni/rte_kni.c | 2 + lib/librte_kni/rte_kni.h | 3 + 4 files changed, 153 insertions(+), 42 deletions(-) diff --git a/lib/librte_eal/linuxapp/kni/kni_dev.h b/lib/librte_eal/linuxapp/kni/kni_dev.h index cb13888c0d..1d7f066fec 100644 --- a/lib/librte_eal/linuxapp/kni/kni_dev.h +++ b/lib/librte_eal/linuxapp/kni/kni_dev.h @@ -33,7 +33,7 @@ #include #include -#define KNI_KTHREAD_RESCHEDULE_INTERVAL 10 /* us */ +#define KNI_KTHREAD_RESCHEDULE_INTERVAL 5 /* us */ /** * A structure describing the private information for a kni device. @@ -46,7 +46,9 @@ struct kni_dev { struct net_device_stats stats; int status; uint16_t group_id; /* Group ID of a group of KNI devices */ + unsigned core_id; /* Core ID to bind */ char name[RTE_KNI_NAMESIZE]; /* Network device name */ + struct task_struct *pthread; /* wait queue for req/resp */ wait_queue_head_t wq; diff --git a/lib/librte_eal/linuxapp/kni/kni_misc.c b/lib/librte_eal/linuxapp/kni/kni_misc.c index 9adf697144..79ab1f9b92 100644 --- a/lib/librte_eal/linuxapp/kni/kni_misc.c +++ b/lib/librte_eal/linuxapp/kni/kni_misc.c @@ -58,9 +58,14 @@ static int kni_ioctl(struct inode *inode, unsigned int ioctl_num, unsigned long ioctl_param); static int kni_compat_ioctl(struct inode *inode, unsigned int ioctl_num, unsigned long ioctl_param); +static int kni_dev_remove(struct kni_dev *dev); -/* kni kernel thread for rx */ -static int kni_thread(void *unused); +static int __init kni_parse_kthread_mode(void); + +/* KNI processing for single kernel thread mode */ +static int kni_thread_single(void *unused); +/* KNI processing for multiple kernel thread mode */ +static int kni_thread_multiple(void *param); static struct file_operations kni_fops = { .owner = THIS_MODULE, @@ -79,6 +84,10 @@ static struct miscdevice kni_misc = { /* loopback mode */ static char *lo_mode = NULL; +/* Kernel thread mode */ +static char *kthread_mode = NULL; +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 */ @@ -95,9 +104,14 @@ kni_init(void) { KNI_PRINT("######## DPDK kni module loading ########\n"); + if (kni_parse_kthread_mode() < 0) { + KNI_ERR("Invalid parameter for kthread_mode\n"); + return -EINVAL; + } + if (misc_register(&kni_misc) != 0) { KNI_ERR("Misc registration failed\n"); - return 1; + return -EPERM; } /* Clear the bit of device in use */ @@ -118,6 +132,22 @@ kni_exit(void) KNI_PRINT("####### DPDK kni module unloaded #######\n"); } +static int __init +kni_parse_kthread_mode(void) +{ + if (!kthread_mode) + return 0; + + if (strcmp(kthread_mode, "single") == 0) + return 0; + else if (strcmp(kthread_mode, "multiple") == 0) + multiple_kthread_on = 1; + else + return -1; + + return 0; +} + static int kni_open(struct inode *inode, struct file *file) { @@ -125,12 +155,18 @@ kni_open(struct inode *inode, struct file *file) if (test_and_set_bit(KNI_DEV_IN_USE_BIT_NUM, &device_in_use)) return -EBUSY; - /* Create kernel thread for RX */ - kni_kthread = kthread_run(kni_thread, NULL, "kni_thread"); - if (IS_ERR(kni_kthread)) { - KNI_ERR("Unable to create kernel threaed\n"); - return PTR_ERR(kni_kthread); - } + /* 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, + "kni_single"); + if (IS_ERR(kni_kthread)) { + KNI_ERR("Unable to create kernel threaed\n"); + return PTR_ERR(kni_kthread); + } + } else + KNI_PRINT("Multiple kernel thread mode enabled\n"); KNI_PRINT("/dev/kni opened\n"); @@ -142,27 +178,22 @@ kni_release(struct inode *inode, struct file *file) { struct kni_dev *dev, *n; - /* Stop kernel thread */ - kthread_stop(kni_kthread); - kni_kthread = NULL; + /* Stop kernel thread for single mode */ + if (multiple_kthread_on == 0) { + /* Stop kernel thread */ + kthread_stop(kni_kthread); + kni_kthread = NULL; + } down_write(&kni_list_lock); list_for_each_entry_safe(dev, n, &kni_list_head, list) { - /* Call the remove part to restore pci dev */ - switch (dev->device_id) { - #define RTE_PCI_DEV_ID_DECL_IGB(vend, dev) case (dev): - #include - igb_kni_remove(dev->pci_dev); - break; - #define RTE_PCI_DEV_ID_DECL_IXGBE(vend, dev) case (dev): - #include - ixgbe_kni_remove(dev->pci_dev); - break; - default: - break; + /* Stop kernel thread for multiple mode */ + if (multiple_kthread_on && dev->pthread != NULL) { + kthread_stop(dev->pthread); + dev->pthread = NULL; } - unregister_netdev(dev->net_dev); - free_netdev(dev->net_dev); + + kni_dev_remove(dev); list_del(&dev->list); } up_write(&kni_list_lock); @@ -176,7 +207,7 @@ kni_release(struct inode *inode, struct file *file) } static int -kni_thread(void *unused) +kni_thread_single(void *unused) { int j; struct kni_dev *dev, *n; @@ -199,6 +230,51 @@ kni_thread(void *unused) return 0; } +static int +kni_thread_multiple(void *param) +{ + int j; + struct kni_dev *dev = (struct kni_dev *)param; + + while (!kthread_should_stop()) { + for (j = 0; j < KNI_RX_LOOP_NUM; j++) { + kni_net_rx(dev); + kni_net_poll_resp(dev); + } + schedule_timeout_interruptible(usecs_to_jiffies( \ + KNI_KTHREAD_RESCHEDULE_INTERVAL)); + } + + return 0; +} + +static int +kni_dev_remove(struct kni_dev *dev) +{ + if (!dev) + return -ENODEV; + + switch (dev->device_id) { + #define RTE_PCI_DEV_ID_DECL_IGB(vend, dev) case (dev): + #include + igb_kni_remove(dev->pci_dev); + break; + #define RTE_PCI_DEV_ID_DECL_IXGBE(vend, dev) case (dev): + #include + ixgbe_kni_remove(dev->pci_dev); + break; + default: + break; + } + + if (dev->net_dev) { + unregister_netdev(dev->net_dev); + free_netdev(dev->net_dev); + } + + return 0; +} + static int kni_check_param(struct kni_dev *kni, struct rte_kni_device_info *dev) { @@ -237,6 +313,16 @@ kni_ioctl_create(unsigned int ioctl_num, unsigned long ioctl_param) return -EIO; } + /** + * Check if the cpu core id is valid for binding, + * for multiple kernel thread mode. + */ + if (multiple_kthread_on && dev_info.force_bind && + !cpu_online(dev_info.core_id)) { + KNI_ERR("cpu %u is not online\n", dev_info.core_id); + return -EINVAL; + } + /* Check if it has been created */ down_read(&kni_list_lock); list_for_each_entry_safe(dev, n, &kni_list_head, list) { @@ -258,6 +344,7 @@ kni_ioctl_create(unsigned int ioctl_num, unsigned long ioctl_param) kni->net_dev = net_dev; kni->group_id = dev_info.group_id; + kni->core_id = dev_info.core_id; strncpy(kni->name, dev_info.name, RTE_KNI_NAMESIZE); /* Translate user space info into kernel space info */ @@ -352,10 +439,27 @@ kni_ioctl_create(unsigned int ioctl_num, unsigned long ioctl_param) if (ret) { KNI_ERR("error %i registering device \"%s\"\n", ret, dev_info.name); - free_netdev(net_dev); + kni_dev_remove(kni); return -ENODEV; } + /** + * Create a new kernel thread for multiple mode, set its core affinity, + * and finally wake it up. + */ + if (multiple_kthread_on) { + kni->pthread = kthread_create(kni_thread_multiple, + (void *)kni, + "kni_%s", kni->name); + if (IS_ERR(kni->pthread)) { + kni_dev_remove(kni); + return -ECANCELED; + } + if (dev_info.force_bind) + kthread_bind(kni->pthread, kni->core_id); + wake_up_process(kni->pthread); + } + down_write(&kni_list_lock); list_add(&kni->list, &kni_list_head); up_write(&kni_list_lock); @@ -388,20 +492,12 @@ kni_ioctl_release(unsigned int ioctl_num, unsigned long ioctl_param) if (strncmp(dev->name, dev_info.name, RTE_KNI_NAMESIZE) != 0) continue; - switch (dev->device_id) { - #define RTE_PCI_DEV_ID_DECL_IGB(vend, dev) case (dev): - #include - igb_kni_remove(dev->pci_dev); - break; - #define RTE_PCI_DEV_ID_DECL_IXGBE(vend, dev) case (dev): - #include - ixgbe_kni_remove(dev->pci_dev); - break; - default: - break; + if (multiple_kthread_on && dev->pthread != NULL) { + kthread_stop(dev->pthread); + dev->pthread = NULL; } - unregister_netdev(dev->net_dev); - free_netdev(dev->net_dev); + + kni_dev_remove(dev); list_del(&dev->list); ret = 0; break; @@ -466,3 +562,11 @@ MODULE_PARM_DESC(lo_mode, "\n" ); +module_param(kthread_mode, charp, S_IRUGO); +MODULE_PARM_DESC(kthread_mode, +"Kernel thread mode (default=single):\n" +" single Single kernel thread mode enabled.\n" +" multiple Multiple kernel thread mode enabled.\n" +"\n" +); + diff --git a/lib/librte_kni/rte_kni.c b/lib/librte_kni/rte_kni.c index 8e8741fdd2..684af186f1 100644 --- a/lib/librte_kni/rte_kni.c +++ b/lib/librte_kni/rte_kni.c @@ -179,6 +179,8 @@ rte_kni_alloc(struct rte_mempool *pktmbuf_pool, dev_info.function = conf->addr.function; dev_info.vendor_id = conf->id.vendor_id; dev_info.device_id = conf->id.device_id; + dev_info.core_id = conf->core_id; + dev_info.force_bind = conf->force_bind; dev_info.group_id = conf->group_id; dev_info.mbuf_size = conf->mbuf_size; diff --git a/lib/librte_kni/rte_kni.h b/lib/librte_kni/rte_kni.h index 8be6281d8b..694a89996d 100644 --- a/lib/librte_kni/rte_kni.h +++ b/lib/librte_kni/rte_kni.h @@ -80,10 +80,13 @@ struct rte_kni_conf { * memzone name. */ char name[RTE_KNI_NAMESIZE]; + uint32_t core_id; /* Core ID to bind kernel thread on */ uint16_t group_id; /* Group ID */ unsigned mbuf_size; /* mbuf size */ struct rte_pci_addr addr; struct rte_pci_id id; + + uint8_t force_bind : 1; /* Flag to bind kernel thread */ }; /** -- 2.20.1