From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mga09.intel.com (mga09.intel.com [134.134.136.24]) by dpdk.org (Postfix) with ESMTP id 80FF67CAA for ; Tue, 4 Jul 2017 18:14:10 +0200 (CEST) Received: from fmsmga006.fm.intel.com ([10.253.24.20]) by orsmga102.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 04 Jul 2017 09:14:10 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.40,309,1496127600"; d="scan'208";a="122666427" Received: from silpixa00372839.ir.intel.com (HELO silpixa00372839.ger.corp.intel.com) ([10.237.222.154]) by fmsmga006.fm.intel.com with ESMTP; 04 Jul 2017 09:14:08 -0700 From: Ferruh Yigit To: dev@dpdk.org Cc: Ferruh Yigit , Stephen Hemminger , Bruce Richardson , Anatoly Burakov Date: Tue, 4 Jul 2017 17:13:28 +0100 Message-Id: <20170704161337.45926-12-ferruh.yigit@intel.com> X-Mailer: git-send-email 2.13.0 In-Reply-To: <20170704161337.45926-1-ferruh.yigit@intel.com> References: <20170630165140.59594-1-ferruh.yigit@intel.com> <20170704161337.45926-1-ferruh.yigit@intel.com> Subject: [dpdk-dev] [PATCH v10 11/20] unci: add netlink exec X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 04 Jul 2017 16:14:11 -0000 Add netlink exec function, which sends a message to userspace and waits and receives the response from userspace. Signed-off-by: Ferruh Yigit --- .../linuxapp/eal/include/exec-env/unci.h | 6 + lib/librte_eal/linuxapp/unci/unci_dev.h | 4 + lib/librte_eal/linuxapp/unci/unci_net.c | 5 + lib/librte_eal/linuxapp/unci/unci_nl.c | 180 +++++++++++++++++++++ 4 files changed, 195 insertions(+) diff --git a/lib/librte_eal/linuxapp/eal/include/exec-env/unci.h b/lib/librte_eal/linuxapp/eal/include/exec-env/unci.h index 6d3490aee..3d88b7ef3 100644 --- a/lib/librte_eal/linuxapp/eal/include/exec-env/unci.h +++ b/lib/librte_eal/linuxapp/eal/include/exec-env/unci.h @@ -74,6 +74,12 @@ struct unci_nl_msg { int err; }; +enum unci_ethtool_msg_flag { + UNCI_MSG_FLAG_NONE, + UNCI_MSG_FLAG_REQUEST, + UNCI_MSG_FLAG_RESPONSE, +}; + /* can go into include/uapi/linux/if_link.h */ enum { IFLA_UNCI_UNSPEC, diff --git a/lib/librte_eal/linuxapp/unci/unci_dev.h b/lib/librte_eal/linuxapp/unci/unci_dev.h index a748abf98..8d9ca6970 100644 --- a/lib/librte_eal/linuxapp/unci/unci_dev.h +++ b/lib/librte_eal/linuxapp/unci/unci_dev.h @@ -37,9 +37,13 @@ struct unci_dev { __u32 port_id; __u32 pid; + struct completion msg_received; + u32 nb_timedout_msg; }; int unci_nl_init(void); void unci_nl_release(void); +int unci_nl_exec(u32 cmd, struct net_device *dev, void *in_data, + size_t in_len, void *out_data, size_t out_len); #endif /* _UNCI_DEV_H_ */ diff --git a/lib/librte_eal/linuxapp/unci/unci_net.c b/lib/librte_eal/linuxapp/unci/unci_net.c index 1989b6d23..27b9f9f70 100644 --- a/lib/librte_eal/linuxapp/unci/unci_net.c +++ b/lib/librte_eal/linuxapp/unci/unci_net.c @@ -31,8 +31,13 @@ static const struct net_device_ops unci_net_netdev_ops = { 0 }; static void unci_net_setup(struct net_device *dev) { + struct unci_dev *unci; + ether_setup(dev); dev->netdev_ops = &unci_net_netdev_ops; + + unci = netdev_priv(dev); + init_completion(&unci->msg_received); } static int unci_net_newlink(struct net *net, struct net_device *dev, diff --git a/lib/librte_eal/linuxapp/unci/unci_nl.c b/lib/librte_eal/linuxapp/unci/unci_nl.c index 1461a3309..fd79ec8f9 100644 --- a/lib/librte_eal/linuxapp/unci/unci_nl.c +++ b/lib/librte_eal/linuxapp/unci/unci_nl.c @@ -26,6 +26,180 @@ #include "unci_dev.h" +#define UNCI_GENL_MSG_LEN 1536 + +#define UNCI_CMD_TIMEOUT 500 /* ms */ + +static struct response_buffer { + int magic; /* for sanity check */ + void *buffer; + size_t length; + struct completion *msg_received; + int *err; + u32 in_use; +} response_buffer; + +static DEFINE_MUTEX(sync_lock); + +static int unci_response_buffer_register(int magic, void *buffer, size_t length, + struct completion *msg_received, int *err) +{ + if (!response_buffer.in_use) { + response_buffer.magic = magic; + response_buffer.buffer = buffer; + response_buffer.length = length; + response_buffer.msg_received = msg_received; + response_buffer.err = err; + response_buffer.in_use = 1; + return 0; + } + + return 1; +} + +static void unci_response_buffer_unregister(int magic) +{ + if (response_buffer.in_use) { + if (magic == response_buffer.magic) { + response_buffer.magic = -1; + response_buffer.buffer = NULL; + response_buffer.length = 0; + response_buffer.msg_received = NULL; + response_buffer.err = NULL; + response_buffer.in_use = 0; + } else { + pr_err("Unregister magic mismatch\n"); + } + } +} + +static void nl_recv_user_request(struct unci_nl_msg *nl_msg) +{ + /* Userspace requests not supported yet */ + pr_debug("Request from userspace received\n"); +} + +static void nl_recv_user_response(struct unci_nl_msg *nl_msg) +{ + struct completion *msg_received; + size_t recv_len; + size_t expected_len; + + if (response_buffer.in_use) { + if (response_buffer.buffer != NULL) { + recv_len = nl_msg->output_buffer_len; + expected_len = response_buffer.length; + + memcpy(response_buffer.buffer, + nl_msg->output_buffer, + response_buffer.length); + + if (nl_msg->err == 0 && recv_len != expected_len) + pr_info("Expected and received len not match " + "%zu - %zu\n", recv_len, expected_len); + } + + *response_buffer.err = nl_msg->err; + msg_received = response_buffer.msg_received; + unci_response_buffer_unregister(response_buffer.magic); + complete(msg_received); + } +} + +static struct genl_family unci_genl_family; + +static int unci_nl_send(u32 cmd_id, u32 port_id, u32 pid, void *in_data, + size_t in_data_len) +{ + struct unci_nl_msg nl_msg; + struct sk_buff *skb; + void *payload; + u32 size = 0; + + if (pid == 0) + return -1; + + memset(&nl_msg, 0, sizeof(struct unci_nl_msg)); + nl_msg.cmd_id = cmd_id; + nl_msg.port_id = port_id; + + if (in_data) { + if (in_data_len == 0 || in_data_len > UNCI_NL_MSG_LEN) + return -EINVAL; + nl_msg.input_buffer_len = in_data_len; + memcpy(nl_msg.input_buffer, in_data, in_data_len); + } + + skb = genlmsg_new(UNCI_GENL_MSG_LEN, GFP_ATOMIC); + if (!skb) + return -ENOMEM; + + size = sizeof(struct unci_nl_msg) + GENL_HDRLEN + + unci_genl_family.hdrsize; + + payload = genlmsg_put(skb, 0, 0, &unci_genl_family, 0, UNCI_CMD_MSG); + if (payload == NULL) { + nlmsg_free(skb); + return -EMSGSIZE; + } + + nla_put(skb, UNCI_ATTR_MSG, sizeof(struct unci_nl_msg), &nl_msg); + + genlmsg_end(skb, payload); + + genlmsg_unicast(&init_net, skb, pid); + pr_debug("Sent cmd:%u port:%u pid:%u\n", cmd_id, port_id, pid); + + return 0; +} + +int unci_nl_exec(u32 cmd, struct net_device *dev, void *in_data, + size_t in_data_len, void *out_data, size_t out_data_len) +{ + struct unci_dev *unci = netdev_priv(dev); + int err = -EINVAL; + int ret; + + if (out_data_len > UNCI_NL_MSG_LEN) { + pr_err("Message is too big to receive:%zu\n", out_data_len); + return err; + } + + mutex_lock(&sync_lock); + ret = unci_response_buffer_register(cmd, out_data, out_data_len, + &unci->msg_received, &err); + if (ret) { + mutex_unlock(&sync_lock); + return -EINVAL; + } + + ret = unci_nl_send(cmd, unci->port_id, unci->pid, in_data, in_data_len); + if (ret) { + unci_response_buffer_unregister(response_buffer.magic); + mutex_unlock(&sync_lock); + return ret; + } + + ret = wait_for_completion_interruptible_timeout(&unci->msg_received, + msecs_to_jiffies(UNCI_CMD_TIMEOUT)); + if (ret == 0 || err < 0) { + unci_response_buffer_unregister(response_buffer.magic); + mutex_unlock(&sync_lock); + if (ret == 0) { /* timeout */ + unci->nb_timedout_msg++; + pr_info("Command timed-out for port:%u cmd:%u (%u)\n", + unci->port_id, cmd, unci->nb_timedout_msg); + return -EINVAL; + } + pr_debug("Command return error for port:%d cmd:%d err:%d\n", + unci->port_id, cmd, err); + return err; + } + mutex_unlock(&sync_lock); + + return 0; +} + static int unci_genl_process(struct sk_buff *skb, struct genl_info *info) { struct nlattr **attrs = info->attrs; @@ -37,6 +211,12 @@ static int unci_genl_process(struct sk_buff *skb, struct genl_info *info) nla_memcpy(&nl_msg, attrs[UNCI_ATTR_MSG], sizeof(struct unci_nl_msg)); pr_debug("cmd: %u\n", nl_msg.cmd_id); + if (nl_msg.flag & UNCI_MSG_FLAG_REQUEST) { + nl_recv_user_request(&nl_msg); + return 0; + } + + nl_recv_user_response(&nl_msg); return 0; } -- 2.13.0