From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mga02.intel.com (mga02.intel.com [134.134.136.20]) by dpdk.org (Postfix) with ESMTP id 9ED6B4CC5 for ; Fri, 30 Jun 2017 18:52:04 +0200 (CEST) Received: from orsmga004.jf.intel.com ([10.7.209.38]) by orsmga101.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 30 Jun 2017 09:52:00 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.40,287,1496127600"; d="scan'208";a="103233232" Received: from silpixa00372839.ir.intel.com (HELO silpixa00372839.ger.corp.intel.com) ([10.237.222.154]) by orsmga004.jf.intel.com with ESMTP; 30 Jun 2017 09:51:59 -0700 From: Ferruh Yigit To: dev@dpdk.org Cc: Ferruh Yigit , Stephen Hemminger , Bruce Richardson , Anatoly Burakov Date: Fri, 30 Jun 2017 17:51:31 +0100 Message-Id: <20170630165140.59594-12-ferruh.yigit@intel.com> X-Mailer: git-send-email 2.13.0 In-Reply-To: <20170630165140.59594-1-ferruh.yigit@intel.com> References: <20170621110651.75299-1-ferruh.yigit@intel.com> <20170630165140.59594-1-ferruh.yigit@intel.com> Subject: [dpdk-dev] [PATCH v9 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: Fri, 30 Jun 2017 16:52:06 -0000 Add netlink exec function, which sends a message to userspace and waits and receives the response from userspace. Signed-off-by: Ferruh Yigit --- .../eal/include/exec-env/rte_unci_common.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 | 164 +++++++++++++++++++++ 4 files changed, 179 insertions(+) diff --git a/lib/librte_eal/linuxapp/eal/include/exec-env/rte_unci_common.h b/lib/librte_eal/linuxapp/eal/include/exec-env/rte_unci_common.h index a14c463a0..474f62606 100644 --- a/lib/librte_eal/linuxapp/eal/include/exec-env/rte_unci_common.h +++ b/lib/librte_eal/linuxapp/eal/include/exec-env/rte_unci_common.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, +}; + enum { IFLA_UNCI_UNSPEC, IFLA_UNCI_PORTID, diff --git a/lib/librte_eal/linuxapp/unci/unci_dev.h b/lib/librte_eal/linuxapp/unci/unci_dev.h index 668574167..75a4098bd 100644 --- a/lib/librte_eal/linuxapp/unci/unci_dev.h +++ b/lib/librte_eal/linuxapp/unci/unci_dev.h @@ -36,9 +36,13 @@ struct unci_dev { u8 port_id; u32 pid; + struct completion msg_received; + u32 nb_timedout_msg; }; void 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 131769c37..72099e596 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 9d07e9822..a0a317cca 100644 --- a/lib/librte_eal/linuxapp/unci/unci_nl.c +++ b/lib/librte_eal/linuxapp/unci/unci_nl.c @@ -25,9 +25,85 @@ #include "unci_dev.h" +#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 struct sock *nl_sock; static struct 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 void nl_recv(struct sk_buff *skb) { struct nlmsghdr *nlh; @@ -37,6 +113,94 @@ static void nl_recv(struct sk_buff *skb) memcpy(&nl_msg, NLMSG_DATA(nlh), 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; + } + + nl_recv_user_response(&nl_msg); +} + +static int unci_nl_send(u32 cmd_id, u8 port_id, u32 pid, void *in_data, + size_t in_data_len) +{ + struct sk_buff *skb; + struct nlmsghdr *nlh; + struct unci_nl_msg nl_msg; + + 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 = nlmsg_new(NLMSG_ALIGN(sizeof(struct unci_nl_msg)), GFP_ATOMIC); + nlh = nlmsg_put(skb, 0, 0, NLMSG_DONE, sizeof(struct unci_nl_msg), 0); + + NETLINK_CB(skb).dst_group = 0; + + memcpy(nlmsg_data(nlh), &nl_msg, sizeof(struct unci_nl_msg)); + + nlmsg_unicast(nl_sock, 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 struct netlink_kernel_cfg cfg = { -- 2.13.0