@@ -257,6 +257,10 @@ F: app/test/test_kni.c
F: examples/kni/
F: doc/guides/sample_app_ug/kernel_nic_interface.rst
+Linux KCP
+M: Ferruh Yigit <ferruh.yigit@intel.com>
+F: lib/librte_eal/linuxapp/kcp/
+
Linux AF_PACKET
M: John W. Linville <linville@tuxdriver.com>
F: drivers/net/af_packet/
@@ -502,6 +502,12 @@ CONFIG_RTE_KNI_VHOST_DEBUG_TX=n
CONFIG_RTE_LIBRTE_ETHTOOL=y
#
+# Compile librte_ctrl_if
+#
+CONFIG_RTE_KCP_KMOD=y
+CONFIG_RTE_KCP_KO_DEBUG=n
+
+#
# Compile vhost library
# fuse-devel is needed to run vhost-cuse.
# fuse-devel enables user space char driver development
@@ -1,6 +1,6 @@
# BSD LICENSE
#
-# Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+# Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@@ -38,6 +38,9 @@ DIRS-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP) += eal
ifeq ($(CONFIG_RTE_KNI_KMOD),y)
DIRS-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP) += kni
endif
+ifeq ($(CONFIG_RTE_KCP_KMOD),y)
+DIRS-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP) += kcp
+endif
ifeq ($(CONFIG_RTE_LIBRTE_XEN_DOM0),y)
DIRS-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP) += xen_dom0
endif
@@ -1,6 +1,6 @@
# BSD LICENSE
#
-# Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+# Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@@ -121,6 +121,7 @@ CFLAGS_eal_thread.o += -Wno-return-type
endif
INC := rte_interrupts.h rte_kni_common.h rte_dom0_common.h
+INC += rte_kcp_common.h
SYMLINK-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP)-include/exec-env := \
$(addprefix include/exec-env/,$(INC))
new file mode 100644
@@ -0,0 +1,109 @@
+/*-
+ * This file is provided under a dual BSD/LGPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GNU LESSER GENERAL PUBLIC LICENSE
+ *
+ * Copyright(c) 2016 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2.1 of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program;
+ *
+ * Contact Information:
+ * Intel Corporation
+ *
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2016 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef _RTE_KCP_COMMON_H_
+#define _RTE_KCP_COMMON_H_
+
+#define KCP_DEVICE "kcp"
+
+#define KCP_NL_GRP 31
+
+#define KCP_ETHTOOL_MSG_LEN 500
+struct kcp_ethtool_msg {
+ int cmd_id;
+ int port_id;
+ unsigned int flag;
+ char input_buffer[KCP_ETHTOOL_MSG_LEN];
+ char output_buffer[KCP_ETHTOOL_MSG_LEN];
+ int input_buffer_len;
+ int output_buffer_len;
+ int err;
+};
+
+enum kcp_ethtool_msg_flag {
+ KCP_MSG_FLAG_NONE,
+ KCP_MSG_FLAG_REQUEST,
+ KCP_MSG_FLAG_RESPONSE,
+};
+
+enum {
+ IFLA_KCP_UNSPEC,
+ IFLA_KCP_PORTID,
+ IFLA_KCP_PID,
+ __IFLA_KCP_MAX,
+};
+
+#define IFLA_KCP_MAX (__IFLA_KCP_MAX - 1)
+
+/*
+ * Request id.
+ */
+enum rte_kcp_req_id {
+ RTE_KCP_REQ_UNKNOWN = (1 << 16),
+ RTE_KCP_REQ_CHANGE_MTU,
+ RTE_KCP_REQ_CFG_NETWORK_IF,
+ RTE_KCP_REQ_GET_STATS,
+ RTE_KCP_REQ_GET_MAC,
+ RTE_KCP_REQ_SET_MAC,
+ RTE_KCP_REQ_START_PORT,
+ RTE_KCP_REQ_STOP_PORT,
+ RTE_KCP_REQ_SET_PROMISC,
+ RTE_KCP_REQ_SET_ALLMULTI,
+ RTE_KCP_REQ_MAX,
+};
+
+#endif /* _RTE_KCP_COMMON_H_ */
new file mode 100644
@@ -0,0 +1,57 @@
+# BSD LICENSE
+#
+# Copyright(c) 2016 Intel Corporation. All rights reserved.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Intel Corporation nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+#
+# module name and path
+#
+MODULE = rte_kcp
+
+#
+# CFLAGS
+#
+MODULE_CFLAGS += -I$(SRCDIR)
+MODULE_CFLAGS += -I$(RTE_OUTPUT)/include
+MODULE_CFLAGS += -include $(RTE_OUTPUT)/include/rte_config.h
+MODULE_CFLAGS += -Wall -Werror
+
+# this lib needs main eal
+DEPDIRS-y += lib/librte_eal/linuxapp/eal
+
+#
+# all source are stored in SRCS-y
+#
+SRCS-y += kcp_net.c
+SRCS-y += kcp_ethtool.c
+SRCS-y += kcp_nl.c
+
+include $(RTE_SDK)/mk/rte.module.mk
new file mode 100644
@@ -0,0 +1,54 @@
+/*-
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2016 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;
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ * Intel Corporation
+ */
+
+#ifndef _KCP_DEV_H_
+#define _KCP_DEV_H_
+
+#include <linux/netdevice.h>
+#include <exec-env/rte_kcp_common.h>
+
+struct kcp_dev {
+ int port_id;
+ unsigned int pid;
+ struct completion msg_received;
+ unsigned int nb_timedout_msg;
+};
+
+void kcp_nl_init(void);
+void kcp_nl_release(void);
+int kcp_nl_exec(int cmd, struct net_device *dev, void *in_data, int in_len,
+ void *out_data, int out_len);
+
+void kcp_set_ethtool_ops(struct net_device *netdev);
+
+#define KCP_ERR(args...) printk(KERN_ERR "KCP: " args)
+#define KCP_INFO(args...) printk(KERN_INFO "KCP: " args)
+
+#ifdef RTE_KCP_KO_DEBUG
+#define KCP_DBG(args...) printk(KERN_DEBUG "KCP: " args)
+#else
+#define KCP_DBG(args...)
+#endif
+
+#endif /* _KCP_DEV_H_ */
new file mode 100644
@@ -0,0 +1,300 @@
+/*-
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2016 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;
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ * Intel Corporation
+ */
+
+#include "kcp_dev.h"
+
+#define ETHTOOL_GEEPROM_LEN 99
+#define ETHTOOL_GREGS_LEN 98
+#define ETHTOOL_GSSET_COUNT 97
+
+static int kcp_check_if_running(struct net_device *dev)
+{
+ return 0;
+}
+
+static void kcp_get_drvinfo(struct net_device *dev,
+ struct ethtool_drvinfo *info)
+{
+ int ret;
+
+ ret = kcp_nl_exec(info->cmd, dev, NULL, 0,
+ info, sizeof(struct ethtool_drvinfo));
+ if (ret < 0)
+ memset(info, 0, sizeof(struct ethtool_drvinfo));
+}
+
+static int kcp_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
+{
+ return kcp_nl_exec(ecmd->cmd, dev, NULL, 0,
+ ecmd, sizeof(struct ethtool_cmd));
+}
+
+static int kcp_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
+{
+ return kcp_nl_exec(ecmd->cmd, dev, ecmd, sizeof(struct ethtool_cmd),
+ NULL, 0);
+}
+
+static void kcp_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+ int ret;
+
+ ret = kcp_nl_exec(wol->cmd, dev, NULL, 0,
+ wol, sizeof(struct ethtool_wolinfo));
+ if (ret < 0)
+ memset(wol, 0, sizeof(struct ethtool_wolinfo));
+}
+
+static int kcp_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+ return kcp_nl_exec(wol->cmd, dev, wol, sizeof(struct ethtool_wolinfo),
+ NULL, 0);
+}
+
+static int kcp_nway_reset(struct net_device *dev)
+{
+ return kcp_nl_exec(ETHTOOL_NWAY_RST, dev, NULL, 0, NULL, 0);
+}
+
+static unsigned int kcp_get_link(struct net_device *dev)
+{
+ unsigned int data;
+ int ret;
+
+ ret = kcp_nl_exec(ETHTOOL_GLINK, dev, NULL, 0, &data, sizeof(int));
+ if (ret < 0)
+ return 0;
+
+ return data;
+}
+
+static int kcp_get_eeprom_len(struct net_device *dev)
+{
+ int data;
+ int ret;
+
+ ret = kcp_nl_exec(ETHTOOL_GEEPROM_LEN, dev, NULL, 0,
+ &data, sizeof(int));
+ if (ret < 0)
+ return 0;
+
+ return data;
+}
+
+static int kcp_get_eeprom(struct net_device *dev,
+ struct ethtool_eeprom *eeprom, u8 *data)
+{
+ struct ethtool_eeprom eeprom_tmp;
+ int ret = 0;
+ int remaining;
+ int offset = 0;
+
+ eeprom_tmp = *eeprom;
+
+ remaining = eeprom_tmp.len;
+ while (remaining > 0 && ret == 0) {
+ eeprom_tmp.len = min(remaining, KCP_ETHTOOL_MSG_LEN);
+
+ ret = kcp_nl_exec(eeprom_tmp.cmd, dev,
+ &eeprom_tmp, sizeof(struct ethtool_eeprom),
+ data + offset, eeprom_tmp.len);
+ eeprom_tmp.offset += eeprom_tmp.len;
+ offset += eeprom_tmp.len;
+ remaining -= eeprom_tmp.len;
+ }
+
+ return ret;
+}
+
+static int kcp_set_eeprom(struct net_device *dev,
+ struct ethtool_eeprom *eeprom, u8 *data)
+{
+ struct ethtool_eeprom *eeprom_tmp;
+ int ret = 0;
+ int remaining;
+ int offset = 0;
+ int payload;
+
+ if (sizeof(struct ethtool_eeprom) > KCP_ETHTOOL_MSG_LEN)
+ return -1;
+
+ eeprom_tmp = kmalloc(KCP_ETHTOOL_MSG_LEN, GFP_KERNEL);
+ payload = KCP_ETHTOOL_MSG_LEN - sizeof(struct ethtool_eeprom);
+
+ *eeprom_tmp = *eeprom;
+ remaining = eeprom->len;
+
+ while (remaining > 0 && ret == 0) {
+ eeprom_tmp->len = min(remaining, payload);
+
+ memcpy(eeprom_tmp->data, data + offset, payload);
+
+ ret = kcp_nl_exec(eeprom->cmd, dev, eeprom,
+ KCP_ETHTOOL_MSG_LEN, NULL, 0);
+
+ eeprom_tmp->offset += eeprom_tmp->len;
+ offset += eeprom_tmp->len;
+ remaining -= eeprom_tmp->len;
+ }
+
+ kfree(eeprom_tmp);
+
+ return ret;
+}
+
+static void kcp_get_ringparam(struct net_device *dev,
+ struct ethtool_ringparam *ring)
+{
+
+ kcp_nl_exec(ring->cmd, dev, NULL, 0,
+ ring, sizeof(struct ethtool_ringparam));
+}
+
+static int kcp_set_ringparam(struct net_device *dev,
+ struct ethtool_ringparam *ring)
+{
+ return kcp_nl_exec(ring->cmd, dev,
+ ring, sizeof(struct ethtool_ringparam),
+ NULL, 0);
+}
+
+static void kcp_get_pauseparam(struct net_device *dev,
+ struct ethtool_pauseparam *pause)
+{
+
+ kcp_nl_exec(pause->cmd, dev, NULL, 0,
+ pause, sizeof(struct ethtool_pauseparam));
+}
+
+static int kcp_set_pauseparam(struct net_device *dev,
+ struct ethtool_pauseparam *pause)
+{
+ return kcp_nl_exec(pause->cmd, dev,
+ pause, sizeof(struct ethtool_pauseparam),
+ NULL, 0);
+}
+
+static u32 kcp_get_msglevel(struct net_device *dev)
+{
+ int data;
+ int ret;
+
+ ret = kcp_nl_exec(ETHTOOL_GMSGLVL, dev, NULL, 0, &data, sizeof(int));
+ if (ret < 0)
+ return 0;
+
+ return data;
+}
+
+static void kcp_set_msglevel(struct net_device *dev, u32 data)
+{
+
+ kcp_nl_exec(ETHTOOL_SMSGLVL, dev, &data, sizeof(int), NULL, 0);
+}
+
+static int kcp_get_regs_len(struct net_device *dev)
+{
+ int data;
+ int ret;
+
+ ret = kcp_nl_exec(ETHTOOL_GREGS_LEN, dev, NULL, 0, &data, sizeof(int));
+ if (ret < 0)
+ return 0;
+
+ return data;
+}
+
+static void kcp_get_regs(struct net_device *dev, struct ethtool_regs *regs,
+ void *p)
+{
+ struct ethtool_regs regs_tmp;
+ int len = regs->len;
+
+ regs_tmp = *regs;
+
+ if (len > KCP_ETHTOOL_MSG_LEN) {
+ len = KCP_ETHTOOL_MSG_LEN;
+ regs_tmp.len = len;
+ }
+
+ kcp_nl_exec(regs->cmd, dev, ®s_tmp, sizeof(struct ethtool_regs),
+ p, len);
+}
+
+static void kcp_get_strings(struct net_device *dev, u32 stringset, u8 *data)
+{
+
+ kcp_nl_exec(ETHTOOL_GSTRINGS, dev, &stringset, sizeof(u32), data, 0);
+}
+
+static int kcp_get_sset_count(struct net_device *dev, int sset)
+{
+ int data;
+ int ret;
+
+ ret = kcp_nl_exec(ETHTOOL_GSSET_COUNT, dev, &sset, sizeof(int),
+ &data, sizeof(int));
+ if (ret < 0)
+ return 0;
+
+ return data;
+}
+
+static void kcp_get_ethtool_stats(struct net_device *dev,
+ struct ethtool_stats *stats, u64 *data)
+{
+
+ kcp_nl_exec(stats->cmd, dev, stats, sizeof(struct ethtool_stats),
+ data, stats->n_stats);
+}
+
+static const struct ethtool_ops kcp_ethtool_ops = {
+ .begin = kcp_check_if_running,
+ .get_drvinfo = kcp_get_drvinfo,
+ .get_settings = kcp_get_settings,
+ .set_settings = kcp_set_settings,
+ .get_regs_len = kcp_get_regs_len,
+ .get_regs = kcp_get_regs,
+ .get_wol = kcp_get_wol,
+ .set_wol = kcp_set_wol,
+ .nway_reset = kcp_nway_reset,
+ .get_link = kcp_get_link,
+ .get_eeprom_len = kcp_get_eeprom_len,
+ .get_eeprom = kcp_get_eeprom,
+ .set_eeprom = kcp_set_eeprom,
+ .get_ringparam = kcp_get_ringparam,
+ .set_ringparam = kcp_set_ringparam,
+ .get_pauseparam = kcp_get_pauseparam,
+ .set_pauseparam = kcp_set_pauseparam,
+ .get_msglevel = kcp_get_msglevel,
+ .set_msglevel = kcp_set_msglevel,
+ .get_strings = kcp_get_strings,
+ .get_sset_count = kcp_get_sset_count,
+ .get_ethtool_stats = kcp_get_ethtool_stats,
+};
+
+void kcp_set_ethtool_ops(struct net_device *netdev)
+{
+ netdev->ethtool_ops = &kcp_ethtool_ops;
+}
new file mode 100644
@@ -0,0 +1,225 @@
+/*-
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2016 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;
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ * Intel Corporation
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/etherdevice.h>
+#include <net/rtnetlink.h>
+
+#include "kcp_dev.h"
+
+static int kcp_net_init(struct net_device *dev)
+{
+ char mac[ETH_ALEN] = {0};
+
+ kcp_nl_exec(RTE_KCP_REQ_GET_MAC, dev, NULL, 0, mac, ETH_ALEN);
+ memcpy(dev->dev_addr, mac, dev->addr_len);
+
+ return 0;
+}
+
+static int kcp_net_open(struct net_device *dev)
+{
+ /* DPDK port already started, stop it first */
+ kcp_nl_exec(RTE_KCP_REQ_STOP_PORT, dev, NULL, 0, NULL, 0);
+ kcp_nl_exec(RTE_KCP_REQ_START_PORT, dev, NULL, 0, NULL, 0);
+ netif_start_queue(dev);
+ return 0;
+}
+
+static int kcp_net_close(struct net_device *dev)
+{
+ kcp_nl_exec(RTE_KCP_REQ_STOP_PORT, dev, NULL, 0, NULL, 0);
+ netif_stop_queue(dev);
+ return 0;
+}
+
+static int kcp_net_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ dev_kfree_skb(skb);
+ return NETDEV_TX_OK;
+}
+
+static void kcp_net_change_rx_flags(struct net_device *dev, int flags)
+{
+ int on = 1;
+ int off = 0;
+
+ if (flags & IFF_PROMISC)
+ kcp_nl_exec(RTE_KCP_REQ_SET_PROMISC, dev,
+ dev->flags & IFF_PROMISC ? &on : &off,
+ sizeof(int), NULL, 0);
+
+ if (flags & IFF_ALLMULTI)
+ kcp_nl_exec(RTE_KCP_REQ_SET_ALLMULTI, dev,
+ dev->flags & IFF_ALLMULTI ? &on : &off,
+ sizeof(int), NULL, 0);
+}
+
+static int kcp_net_set_mac(struct net_device *dev, void *p)
+{
+ struct sockaddr *addr = p;
+ int err = 0;
+
+ if (!is_valid_ether_addr((unsigned char *)(addr->sa_data)))
+ return -EADDRNOTAVAIL;
+
+ err = kcp_nl_exec(RTE_KCP_REQ_SET_MAC, dev, addr->sa_data,
+ dev->addr_len, NULL, 0);
+ if (err < 0)
+ return -EADDRNOTAVAIL;
+
+ memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+
+ return 0;
+}
+
+static int kcp_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+ return -EOPNOTSUPP;
+}
+
+/*
+ * Configuration changes (passed on by ifconfig)
+ */
+static int kcp_net_config(struct net_device *dev, struct ifmap *map)
+{
+ if (dev->flags & IFF_UP)
+ return -EBUSY;
+
+ return -EOPNOTSUPP;
+}
+
+static int kcp_net_change_mtu(struct net_device *dev, int new_mtu)
+{
+ int err = 0;
+
+ err = kcp_nl_exec(RTE_KCP_REQ_CHANGE_MTU, dev, &new_mtu, sizeof(int),
+ NULL, 0);
+
+ if (err == 0)
+ dev->mtu = new_mtu;
+
+ return err;
+}
+
+static struct rtnl_link_stats64 *kcp_net_stats64(struct net_device *dev,
+ struct rtnl_link_stats64 *stats)
+{
+ int err;
+
+ err = kcp_nl_exec(RTE_KCP_REQ_GET_STATS, dev, NULL, 0,
+ stats, sizeof(struct rtnl_link_stats64));
+
+ return stats;
+}
+
+#if (KERNEL_VERSION(3, 9, 0) <= LINUX_VERSION_CODE)
+static int kcp_net_change_carrier(struct net_device *dev, bool new_carrier)
+{
+ if (new_carrier)
+ netif_carrier_on(dev);
+ else
+ netif_carrier_off(dev);
+ return 0;
+}
+#endif
+
+static const struct net_device_ops kcp_net_netdev_ops = {
+ .ndo_init = kcp_net_init,
+ .ndo_open = kcp_net_open,
+ .ndo_stop = kcp_net_close,
+ .ndo_start_xmit = kcp_net_xmit,
+ .ndo_change_rx_flags = kcp_net_change_rx_flags,
+ .ndo_set_mac_address = kcp_net_set_mac,
+ .ndo_do_ioctl = kcp_net_ioctl,
+ .ndo_set_config = kcp_net_config,
+ .ndo_change_mtu = kcp_net_change_mtu,
+ .ndo_get_stats64 = kcp_net_stats64,
+#if (KERNEL_VERSION(3, 9, 0) <= LINUX_VERSION_CODE)
+ .ndo_change_carrier = kcp_net_change_carrier,
+#endif
+};
+
+static void kcp_net_setup(struct net_device *dev)
+{
+ struct kcp_dev *kcp;
+
+ ether_setup(dev);
+ dev->netdev_ops = &kcp_net_netdev_ops;
+
+ kcp = netdev_priv(dev);
+ init_completion(&kcp->msg_received);
+
+ kcp_set_ethtool_ops(dev);
+}
+
+static int kcp_net_newlink(struct net *net, struct net_device *dev,
+ struct nlattr *tb[], struct nlattr *data[])
+{
+ int ret;
+ struct kcp_dev *kcp;
+
+ kcp = netdev_priv(dev);
+
+ if (data && data[IFLA_KCP_PORTID])
+ kcp->port_id = nla_get_u8(data[IFLA_KCP_PORTID]);
+ else
+ kcp->port_id = 0;
+
+ if (data && data[IFLA_KCP_PID])
+ kcp->pid = nla_get_u32(data[IFLA_KCP_PID]);
+ else
+ kcp->pid = 0;
+
+ ret = register_netdevice(dev);
+
+ return ret;
+}
+
+static struct rtnl_link_ops kcp_link_ops __read_mostly = {
+ .kind = KCP_DEVICE,
+ .priv_size = sizeof(struct kcp_dev),
+ .setup = kcp_net_setup,
+ .maxtype = IFLA_KCP_MAX,
+ .newlink = kcp_net_newlink,
+};
+
+static int __init kcp_init(void)
+{
+ kcp_nl_init();
+ return rtnl_link_register(&kcp_link_ops);
+}
+module_init(kcp_init);
+
+static void __exit kcp_exit(void)
+{
+ rtnl_link_unregister(&kcp_link_ops);
+ kcp_nl_release();
+}
+module_exit(kcp_exit);
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_AUTHOR("Intel Corporation");
+MODULE_DESCRIPTION("Kernel Module for managing kcp devices");
new file mode 100644
@@ -0,0 +1,215 @@
+/*-
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2016 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;
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ * Intel Corporation
+ */
+
+#include <net/sock.h>
+
+#include "kcp_dev.h"
+
+#define KCP_CMD_TIMEOUT 500 /* ms */
+
+static struct ethtool_input_buffer {
+ int magic;
+ void *buffer;
+ int length;
+ struct completion *msg_received;
+ int *err;
+ int in_use;
+} ethtool_input_buffer;
+
+static struct sock *nl_sock;
+static struct mutex sync_lock;
+
+static int kcp_input_buffer_register(int magic, void *buffer, int length,
+ struct completion *msg_received, int *err)
+{
+ if (ethtool_input_buffer.in_use == 0) {
+ ethtool_input_buffer.magic = magic;
+ ethtool_input_buffer.buffer = buffer;
+ ethtool_input_buffer.length = length;
+ ethtool_input_buffer.msg_received = msg_received;
+ ethtool_input_buffer.err = err;
+ ethtool_input_buffer.in_use = 1;
+ return 0;
+ }
+
+ return 1;
+}
+
+static void kcp_input_buffer_unregister(int magic)
+{
+ if (ethtool_input_buffer.in_use == 1) {
+ if (magic == ethtool_input_buffer.magic) {
+ ethtool_input_buffer.magic = -1;
+ ethtool_input_buffer.buffer = NULL;
+ ethtool_input_buffer.length = 0;
+ ethtool_input_buffer.msg_received = NULL;
+ ethtool_input_buffer.err = NULL;
+ ethtool_input_buffer.in_use = 0;
+ } else {
+ KCP_ERR("Unregister magic mismatch\n");
+ }
+ }
+}
+
+static void nl_recv_user_request(struct kcp_ethtool_msg *ethtool_msg)
+{
+ KCP_DBG("Request from userspace received\n");
+}
+
+static void nl_recv_user_response(struct kcp_ethtool_msg *ethtool_msg)
+{
+ struct completion *msg_received;
+ int recv_len;
+ int expected_len;
+
+ if (ethtool_input_buffer.in_use == 1) {
+ if (ethtool_input_buffer.buffer != NULL) {
+ recv_len = ethtool_msg->output_buffer_len;
+ expected_len = ethtool_input_buffer.length;
+
+ memcpy(ethtool_input_buffer.buffer,
+ ethtool_msg->output_buffer,
+ ethtool_input_buffer.length);
+
+ if (ethtool_msg->err == 0 && recv_len != expected_len)
+ KCP_INFO("Expected and received len not match "
+ "%d - %d\n", recv_len, expected_len);
+ }
+
+ *ethtool_input_buffer.err = ethtool_msg->err;
+ msg_received = ethtool_input_buffer.msg_received;
+ kcp_input_buffer_unregister(ethtool_input_buffer.magic);
+ complete(msg_received);
+ }
+}
+
+static void nl_recv(struct sk_buff *skb)
+{
+ struct nlmsghdr *nlh;
+ struct kcp_ethtool_msg ethtool_msg;
+
+ nlh = (struct nlmsghdr *)skb->data;
+
+ memcpy(ðtool_msg, NLMSG_DATA(nlh), sizeof(struct kcp_ethtool_msg));
+ KCP_DBG("CMD: %d\n", ethtool_msg.cmd_id);
+
+ if (ethtool_msg.flag & KCP_MSG_FLAG_REQUEST) {
+ nl_recv_user_request(ðtool_msg);
+ return;
+ }
+
+ nl_recv_user_response(ðtool_msg);
+}
+
+static int kcp_nl_send(int cmd_id, int port_id, unsigned int pid,
+ void *in_data, int in_data_len)
+{
+ struct sk_buff *skb;
+ struct nlmsghdr *nlh;
+ struct kcp_ethtool_msg ethtool_msg;
+
+ if (pid == 0)
+ return -1;
+
+ memset(ðtool_msg, 0, sizeof(struct kcp_ethtool_msg));
+ ethtool_msg.cmd_id = cmd_id;
+ ethtool_msg.port_id = port_id;
+
+ if (in_data) {
+ if (in_data_len == 0 || in_data_len > KCP_ETHTOOL_MSG_LEN)
+ return -EINVAL;
+ ethtool_msg.input_buffer_len = in_data_len;
+ memcpy(ethtool_msg.input_buffer, in_data, in_data_len);
+ }
+
+ skb = nlmsg_new(NLMSG_ALIGN(sizeof(struct kcp_ethtool_msg)),
+ GFP_ATOMIC);
+ nlh = nlmsg_put(skb, 0, 0, NLMSG_DONE, sizeof(struct kcp_ethtool_msg),
+ 0);
+
+ NETLINK_CB(skb).dst_group = 0;
+
+ memcpy(nlmsg_data(nlh), ðtool_msg, sizeof(struct kcp_ethtool_msg));
+
+ nlmsg_unicast(nl_sock, skb, pid);
+ KCP_DBG("Sent cmd:%d port:%d pid:%u\n", cmd_id, port_id, pid);
+
+ return 0;
+}
+
+int kcp_nl_exec(int cmd, struct net_device *dev, void *in_data,
+ int in_data_len, void *out_data, int out_data_len)
+{
+ struct kcp_dev *priv = netdev_priv(dev);
+ int err = -EINVAL;
+ int ret;
+
+ if (out_data_len > KCP_ETHTOOL_MSG_LEN) {
+ KCP_ERR("Message is too big to receive:%u\n", out_data_len);
+ return err;
+ }
+
+ mutex_lock(&sync_lock);
+ ret = kcp_input_buffer_register(cmd, out_data, out_data_len,
+ &priv->msg_received, &err);
+ if (ret) {
+ mutex_unlock(&sync_lock);
+ return -EINVAL;
+ }
+
+ ret = kcp_nl_send(cmd, priv->port_id, priv->pid, in_data, in_data_len);
+ if (ret) {
+ kcp_input_buffer_unregister(ethtool_input_buffer.magic);
+ mutex_unlock(&sync_lock);
+ return ret;
+ }
+
+ ret = wait_for_completion_interruptible_timeout(&priv->msg_received,
+ msecs_to_jiffies(KCP_CMD_TIMEOUT));
+ if (ret == 0 || err < 0) {
+ kcp_input_buffer_unregister(ethtool_input_buffer.magic);
+ mutex_unlock(&sync_lock);
+ priv->nb_timedout_msg++;
+ KCP_INFO("Command timed-out for port:%d cmd:%d (%u)\n",
+ priv->port_id, cmd, priv->nb_timedout_msg);
+ return ret == 0 ? -EINVAL : err;
+ }
+ mutex_unlock(&sync_lock);
+
+ return 0;
+}
+
+static struct netlink_kernel_cfg cfg = {
+ .input = nl_recv,
+};
+
+void kcp_nl_init(void)
+{
+ nl_sock = netlink_kernel_create(&init_net, KCP_NL_GRP, &cfg);
+ mutex_init(&sync_lock);
+}
+
+void kcp_nl_release(void)
+{
+ netlink_kernel_release(nl_sock);
+}