[dpdk-dev] Diff for persistent KNI interfaces

Gopakumar Choorakkot Edakkunni gopakumar.c.e at gmail.com
Sun Jul 12 20:39:03 CEST 2015


I guess theres not much interest from others for this support in
general, but putting it out here in case anyone wants to take a look.
If anyone finds any major issues with the diffset, please do let me
know, that will be of great help. I have tested this on my machine.

Rgds,
Gopa.
-------------- next part --------------
commit 58968f690056d5afa7517e724bc91f6436639d10
Author: Gopakumar C E <gopakumar.c.e at gmail.com>
Date:   Sun Jul 12 11:18:33 2015 -0700

    KNI persistent interfaces

diff --git a/lib/librte_eal/linuxapp/eal/include/exec-env/rte_kni_common.h b/lib/librte_eal/linuxapp/eal/include/exec-env/rte_kni_common.h
index 1e55c2d..369ab85 100644
--- a/lib/librte_eal/linuxapp/eal/include/exec-env/rte_kni_common.h
+++ b/lib/librte_eal/linuxapp/eal/include/exec-env/rte_kni_common.h
@@ -160,6 +160,7 @@ struct rte_kni_device_info {
 	uint32_t core_id;             /**< core ID to bind for kernel thread */
 
 	uint8_t force_bind : 1;       /**< Flag for kernel thread binding */
+	uint8_t persist_on_close : 1; /**< Dont delete interface on dev/kni close */
 
 	/* mbuf size */
 	unsigned mbuf_size;
diff --git a/lib/librte_eal/linuxapp/kni/kni_dev.h b/lib/librte_eal/linuxapp/kni/kni_dev.h
index e79e472..e50aad7 100644
--- a/lib/librte_eal/linuxapp/kni/kni_dev.h
+++ b/lib/librte_eal/linuxapp/kni/kni_dev.h
@@ -96,6 +96,12 @@ struct kni_dev {
 	/* synchro for request processing */
 	unsigned long synchro;
 
+	/* Persist netdev on /dev/kni close */
+	uint8_t netdev_persist : 1;
+
+	/* /dev/kni is closed or not */
+	uint8_t kni_released : 1;
+
 #ifdef RTE_KNI_VHOST
 	struct kni_vhost_queue* vhost_queue;
 	volatile enum {
diff --git a/lib/librte_eal/linuxapp/kni/kni_misc.c b/lib/librte_eal/linuxapp/kni/kni_misc.c
index 1935d32..f386a31 100644
--- a/lib/librte_eal/linuxapp/kni/kni_misc.c
+++ b/lib/librte_eal/linuxapp/kni/kni_misc.c
@@ -58,7 +58,7 @@ 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);
+static int kni_dev_remove(struct kni_dev *dev, int netdev_remove);
 
 static int __init kni_parse_kthread_mode(void);
 
@@ -128,6 +128,21 @@ kni_init(void)
 static void __exit
 kni_exit(void)
 {
+        struct kni_dev *dev, *n;
+
+	/*
+	 * Remove all the persistent KNI interfaces.
+	 */
+        down_write(&kni_list_lock);
+        list_for_each_entry_safe(dev, n, &kni_list_head, list) {
+		if (dev->net_dev) {			
+                	unregister_netdev(dev->net_dev);
+                	free_netdev(dev->net_dev);
+		}
+                list_del(&dev->list);
+	}
+        up_write(&kni_list_lock);
+
 	misc_deregister(&kni_misc);
 	KNI_PRINT("####### DPDK kni module unloaded  #######\n");
 }
@@ -196,8 +211,12 @@ kni_release(struct inode *inode, struct file *file)
 #ifdef RTE_KNI_VHOST
 		kni_vhost_backend_release(dev);
 #endif
-		kni_dev_remove(dev);
-		list_del(&dev->list);
+		kni_dev_remove(dev, !dev->netdev_persist);
+		if (!dev->netdev_persist) {	
+			list_del(&dev->list);
+		} else {
+			dev->kni_released = 1;
+		}
 	}
 	up_write(&kni_list_lock);
 
@@ -264,7 +283,7 @@ kni_thread_multiple(void *param)
 }
 
 static int
-kni_dev_remove(struct kni_dev *dev)
+kni_dev_remove(struct kni_dev *dev, int netdev_remove)
 {
 	if (!dev)
 		return -ENODEV;
@@ -282,7 +301,7 @@ kni_dev_remove(struct kni_dev *dev)
 		break;
 	}
 
-	if (dev->net_dev) {
+	if (dev->net_dev && netdev_remove) {
 		unregister_netdev(dev->net_dev);
 		free_netdev(dev->net_dev);
 	}
@@ -314,8 +333,9 @@ kni_ioctl_create(unsigned int ioctl_num, unsigned long ioctl_param)
 	struct pci_dev *found_pci = NULL;
 	struct net_device *net_dev = NULL;
 	struct net_device *lad_dev = NULL;
-	struct kni_dev *kni, *dev, *n;
+	struct kni_dev *kni = NULL, *dev, *n;
 	struct net *net;
+	int kni_exists = 0;
 
 	printk(KERN_INFO "KNI: Creating kni...\n");
 	/* Check the buffer size, to avoid warning */
@@ -343,32 +363,52 @@ kni_ioctl_create(unsigned int ioctl_num, unsigned long ioctl_param)
 	down_read(&kni_list_lock);
 	list_for_each_entry_safe(dev, n, &kni_list_head, list) {
 		if (kni_check_param(dev, &dev_info) < 0) {
-			up_read(&kni_list_lock);
-			return -EINVAL;
+			kni = dev;
+			kni_exists = 1;				
+			break;	
 		}
 	}
 	up_read(&kni_list_lock);
 
-	net_dev = alloc_netdev(sizeof(struct kni_dev), dev_info.name,
+	if (kni_exists && !dev_info.persist_on_close) {
+		return -EINVAL;
+	}
+
+	if (!kni_exists) {
+		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;
+		if (net_dev == NULL) {
+			KNI_ERR("error allocating device \"%s\"\n", dev_info.name);
+			return -EBUSY;
+		}
+	} else {
+		net_dev = kni->net_dev;
 	}
 
 	net = get_net_ns_by_pid(current->pid);
 	if (IS_ERR(net)) {
 		free_netdev(net_dev);
+		if (kni_exists) {
+			down_write(&kni_list_lock);
+			list_del(&kni->list);
+			up_write(&kni_list_lock);				
+		}
 		return PTR_ERR(net);
 	}
 	dev_net_set(net_dev, net);
 	put_net(net);
 
-	kni = netdev_priv(net_dev);
-
+	if (!kni_exists) {
+		kni = netdev_priv(net_dev);
+	}
+	if (dev_info.persist_on_close) {
+		kni->netdev_persist = 1;
+	} else {
+		kni->netdev_persist = 0;
+	}
 	kni->net_dev = net_dev;
 	kni->group_id = dev_info.group_id;
 	kni->core_id = dev_info.core_id;
@@ -466,12 +506,14 @@ kni_ioctl_create(unsigned int ioctl_num, unsigned long ioctl_param)
 	if (pci)
 		pci_dev_put(pci);
 
-	ret = register_netdev(net_dev);
-	if (ret) {
-		KNI_ERR("error %i registering device \"%s\"\n",
-					ret, dev_info.name);
-		kni_dev_remove(kni);
-		return -ENODEV;
+	if (!kni_exists) {
+		ret = register_netdev(net_dev);
+		if (ret) {
+			KNI_ERR("error %i registering device \"%s\"\n",
+						ret, dev_info.name);
+			kni_dev_remove(kni, 1);
+			return -ENODEV;
+		}
 	}
 
 #ifdef RTE_KNI_VHOST
@@ -487,7 +529,12 @@ kni_ioctl_create(unsigned int ioctl_num, unsigned long ioctl_param)
 					      (void *)kni,
 					      "kni_%s", kni->name);
 		if (IS_ERR(kni->pthread)) {
-			kni_dev_remove(kni);
+			kni_dev_remove(kni, 1);
+			if (kni_exists) {
+				down_write(&kni_list_lock);
+				list_del(&kni->list);
+				up_write(&kni_list_lock);				
+			}
 			return -ECANCELED;
 		}
 		if (dev_info.force_bind)
@@ -495,9 +542,13 @@ 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);
+	if (!kni_exists) {
+		down_write(&kni_list_lock);
+		list_add(&kni->list, &kni_list_head);
+		up_write(&kni_list_lock);
+	} else {
+		kni->kni_released = 0;
+	}
 
 	return 0;
 }
@@ -535,7 +586,7 @@ kni_ioctl_release(unsigned int ioctl_num, unsigned long ioctl_param)
 #ifdef RTE_KNI_VHOST
 		kni_vhost_backend_release(dev);
 #endif
-		kni_dev_remove(dev);
+		kni_dev_remove(dev, 1);
 		list_del(&dev->list);
 		ret = 0;
 		break;
diff --git a/lib/librte_eal/linuxapp/kni/kni_net.c b/lib/librte_eal/linuxapp/kni/kni_net.c
index dd95db5..3db521f 100644
--- a/lib/librte_eal/linuxapp/kni/kni_net.c
+++ b/lib/librte_eal/linuxapp/kni/kni_net.c
@@ -70,6 +70,10 @@ kni_net_open(struct net_device *dev)
 	struct rte_kni_request req;
 	struct kni_dev *kni = netdev_priv(dev);
 
+	if (kni->kni_released) {
+		return -EAGAIN;
+	}
+
 	if (kni->lad_dev)
 		memcpy(dev->dev_addr, kni->lad_dev->dev_addr, ETH_ALEN);
 	else
@@ -98,6 +102,10 @@ kni_net_release(struct net_device *dev)
 	struct rte_kni_request req;
 	struct kni_dev *kni = netdev_priv(dev);
 
+	if (kni->kni_released) {
+		return -EAGAIN;
+	}
+
 	netif_stop_queue(dev); /* can't transmit any more */
 
 	memset(&req, 0, sizeof(req));
@@ -370,6 +378,10 @@ kni_net_rx_lo_fifo_skb(struct kni_dev *kni)
 void
 kni_net_rx(struct kni_dev *kni)
 {
+	if (kni->kni_released) {
+		return;
+	}
+
 	/**
 	 * It doesn't need to check if it is NULL pointer,
 	 * as it has a default value
@@ -386,6 +398,10 @@ kni_net_tx(struct sk_buff *skb, struct net_device *dev)
 {
 	struct kni_dev *kni = netdev_priv(dev);
 
+	if (kni->kni_released) {
+		return NETDEV_TX_BUSY;
+	}
+
 	dev_kfree_skb(skb);
 	kni->stats.tx_dropped++;
 
@@ -401,6 +417,10 @@ kni_net_tx(struct sk_buff *skb, struct net_device *dev)
 	struct rte_kni_mbuf *pkt_kva = NULL;
 	struct rte_kni_mbuf *pkt_va = NULL;
 
+	if (kni->kni_released) {
+		return NETDEV_TX_BUSY;
+	}
+		
 	dev->trans_start = jiffies; /* save the timestamp */
 
 	/* Check if the length of skb is less than mbuf size */
@@ -478,6 +498,10 @@ kni_net_tx_timeout (struct net_device *dev)
 	KNI_DBG("Transmit timeout at %ld, latency %ld\n", jiffies,
 			jiffies - dev->trans_start);
 
+	if (kni->kni_released) {
+		return;
+	}
+
 	kni->stats.tx_errors++;
 	netif_wake_queue(dev);
 	return;
@@ -489,6 +513,12 @@ kni_net_tx_timeout (struct net_device *dev)
 static int
 kni_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
+	struct kni_dev *kni = netdev_priv(dev);
+
+	if (kni->kni_released) {
+		return -EAGAIN;
+	}
+
 	KNI_DBG("kni_net_ioctl %d\n",
 		((struct kni_dev *)netdev_priv(dev))->group_id);
 
@@ -504,6 +534,10 @@ kni_net_change_mtu(struct net_device *dev, int new_mtu)
 
 	KNI_DBG("kni_net_change_mtu new mtu %d to be set\n", new_mtu);
 
+	if (kni->kni_released) {
+		return -EAGAIN;
+	}
+
 	memset(&req, 0, sizeof(req));
 	req.req_id = RTE_KNI_REQ_CHANGE_MTU;
 	req.new_mtu = new_mtu;
@@ -520,6 +554,9 @@ kni_net_change_mtu(struct net_device *dev, int new_mtu)
 void
 kni_net_poll_resp(struct kni_dev *kni)
 {
+	if (kni->kni_released) {
+		return;
+	}
 	if (kni_fifo_count(kni->resp_q))
 		wake_up_interruptible(&kni->wq);
 }
diff --git a/lib/librte_kni/rte_kni.c b/lib/librte_kni/rte_kni.c
index 4e70fa0..1cf7c1f 100644
--- a/lib/librte_kni/rte_kni.c
+++ b/lib/librte_kni/rte_kni.c
@@ -381,6 +381,7 @@ rte_kni_alloc(struct rte_mempool *pktmbuf_pool,
 	dev_info.device_id = conf->id.device_id;
 	dev_info.core_id = conf->core_id;
 	dev_info.force_bind = conf->force_bind;
+	dev_info.persist_on_close = conf->persist_on_close;
 	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 815b8e2..c585bc7 100644
--- a/lib/librte_kni/rte_kni.h
+++ b/lib/librte_kni/rte_kni.h
@@ -87,6 +87,7 @@ struct rte_kni_conf {
 	struct rte_pci_id id;
 
 	uint8_t force_bind : 1; /* Flag to bind kernel thread */
+	uint8_t persist_on_close : 1; /* Flag to keep KNI around post /dev/kni close */
 };
 
 /**


More information about the dev mailing list