+static int
+kni_ioctl_release(unsigned int ioctl_num, unsigned long ioctl_param)
+{
+ int ret = -EINVAL;
+ uint8_t port_id;
+ struct kni_dev *dev, *n;
+
+ if (_IOC_SIZE(ioctl_num) > sizeof(port_id))
+ return -EINVAL;
+
+ ret = copy_from_user(&port_id, (void *)ioctl_param, sizeof(port_id));
+ if (ret) {
+ KNI_ERR("copy_from_user in kni_ioctl_release");
+ return -EIO;
+ }
+
+ down_write(&kni_list_lock);
+ list_for_each_entry_safe(dev, n, &kni_list_head, list) {
+ if (dev->port_id != port_id)
+ continue;
+
+ switch (dev->device_id) {
+ #define RTE_PCI_DEV_ID_DECL_IGB(vend, dev) case (dev):
+ #include <rte_pci_dev_ids.h>
+ igb_kni_remove(dev->pci_dev);
+ break;
+ #define RTE_PCI_DEV_ID_DECL_IXGBE(vend, dev) case (dev):
+ #include <rte_pci_dev_ids.h>
+ ixgbe_kni_remove(dev->pci_dev);
+ break;
+ default:
+ break;
+ }
+ unregister_netdev(dev->net_dev);
+ free_netdev(dev->net_dev);
+ list_del(&dev->list);
+ ret = 0;
+ break;
+ }
+ up_write(&kni_list_lock);
+ printk(KERN_INFO "KNI: %s release kni for port %d\n",
+ (ret == 0 ? "Successfully" : "Unsuccessfully"), port_id);
+
+ return ret;
+}
+