From patchwork Fri Jun 30 16:51:35 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ferruh Yigit X-Patchwork-Id: 26127 Return-Path: X-Original-To: patchwork@dpdk.org Delivered-To: patchwork@dpdk.org Received: from [92.243.14.124] (localhost [IPv6:::1]) by dpdk.org (Postfix) with ESMTP id 461397CDF; Fri, 30 Jun 2017 18:52:42 +0200 (CEST) Received: from mga02.intel.com (mga02.intel.com [134.134.136.20]) by dpdk.org (Postfix) with ESMTP id 16A8C235 for ; Fri, 30 Jun 2017 18:52:06 +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:06 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.40,287,1496127600"; d="scan'208";a="103233312" 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:52:05 -0700 From: Ferruh Yigit To: dev@dpdk.org Cc: Ferruh Yigit , Stephen Hemminger , Bruce Richardson , Anatoly Burakov Date: Fri, 30 Jun 2017 17:51:35 +0100 Message-Id: <20170630165140.59594-16-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 15/20] ctrl_if: add create destroy interface APIs 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: , Errors-To: dev-bounces@dpdk.org Sender: "dev" Library provides two APIs to create and destroy interfaces. rtnl used to create or destroy interfaces. Signed-off-by: Ferruh Yigit --- lib/librte_ctrl_if/rte_ctrl_if.c | 304 +++++++++++++++++++++++++++++ lib/librte_ctrl_if/rte_ctrl_if.h | 34 ++++ lib/librte_ctrl_if/rte_ctrl_if_version.map | 4 + 3 files changed, 342 insertions(+) diff --git a/lib/librte_ctrl_if/rte_ctrl_if.c b/lib/librte_ctrl_if/rte_ctrl_if.c index 45a3a07cf..8b0718969 100644 --- a/lib/librte_ctrl_if/rte_ctrl_if.c +++ b/lib/librte_ctrl_if/rte_ctrl_if.c @@ -31,4 +31,308 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include #include "rte_ctrl_if.h" + +#define NAMESZ 32 +#define IFNAME "dpdk" +#define BUFSZ 1024 + +static int unci_rtnl_fd = -1; +static uint32_t unci_fd_ref; + +struct unci_request { + struct nlmsghdr nlmsg; + uint8_t buf[BUFSZ]; +}; + +static int +control_interface_rtnl_init(void) +{ + struct sockaddr_nl src; + int ret; + + unci_rtnl_fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); + if (unci_rtnl_fd < 0) { + RTE_LOG(ERR, CTRL_IF, "Socket for create failed\n"); + return -1; + } + + memset(&src, 0, sizeof(struct sockaddr_nl)); + + src.nl_family = AF_NETLINK; + src.nl_pid = getpid(); + + ret = bind(unci_rtnl_fd, (struct sockaddr *)&src, + sizeof(struct sockaddr_nl)); + if (ret < 0) { + RTE_LOG(ERR, CTRL_IF, "Bind for create failed\n"); + return -1; + } + + return 0; +} + +static int +control_interface_init(void) +{ + int ret; + + ret = control_interface_rtnl_init(); + if (ret < 0) { + RTE_LOG(ERR, CTRL_IF, "Failed to initialize rtnetlink\n"); + return -1; + } + + return ret; +} + +static int +control_interface_ref_get(void) +{ + int ret = 0; + + if (unci_fd_ref == 0) + ret = control_interface_init(); + + if (ret == 0) + unci_fd_ref++; + else + RTE_LOG(ERR, CTRL_IF, + "Failed to initialize control interface\n"); + + return unci_fd_ref; +} + +static void +control_interface_release(void) +{ + close(unci_rtnl_fd); +} + +static int +control_interface_ref_put(void) +{ + if (unci_fd_ref == 0) + return 0; + + unci_fd_ref--; + + if (unci_fd_ref == 0) + control_interface_release(); + + return unci_fd_ref; +} + +static int +add_attr(struct unci_request *req, uint16_t type, void *buf, size_t len) +{ + struct rtattr *rta; + int nlmsg_len; + + nlmsg_len = NLMSG_ALIGN(req->nlmsg.nlmsg_len); + rta = (struct rtattr *)((char *)&req->nlmsg + nlmsg_len); + if (nlmsg_len + RTA_LENGTH(len) > sizeof(struct unci_request)) + return -1; + rta->rta_type = type; + rta->rta_len = RTA_LENGTH(len); + memcpy(RTA_DATA(rta), buf, len); + req->nlmsg.nlmsg_len = nlmsg_len + RTA_LENGTH(len); + + return 0; +} + +static struct +rtattr *add_attr_nested(struct unci_request *req, unsigned short type) +{ + struct rtattr *rta; + uint32_t nlmsg_len; + + nlmsg_len = NLMSG_ALIGN(req->nlmsg.nlmsg_len); + rta = (struct rtattr *)((uint8_t *)&req->nlmsg + nlmsg_len); + if (nlmsg_len + RTA_LENGTH(0) > sizeof(struct unci_request)) + return NULL; + rta->rta_type = type; + rta->rta_len = nlmsg_len; + req->nlmsg.nlmsg_len = nlmsg_len + RTA_LENGTH(0); + + return rta; +} + +static void +end_attr_nested(struct unci_request *req, struct rtattr *rta) +{ + rta->rta_len = req->nlmsg.nlmsg_len - rta->rta_len; +} + +static int +rte_eth_rtnl_create(uint8_t port_id) +{ + struct unci_request req; + struct ifinfomsg *info; + struct rtattr *rta1; + struct rtattr *rta2; + uint32_t pid = getpid(); + char name[NAMESZ]; + char type[NAMESZ]; + struct iovec iov; + struct msghdr msg; + struct sockaddr_nl nladdr; + int ret; + uint8_t buf[BUFSZ]; + + memset(&req, 0, sizeof(struct unci_request)); + + req.nlmsg.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); + req.nlmsg.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL; + req.nlmsg.nlmsg_flags |= NLM_F_ACK; + req.nlmsg.nlmsg_type = RTM_NEWLINK; + + info = NLMSG_DATA(&req.nlmsg); + + info->ifi_family = AF_UNSPEC; + info->ifi_index = 0; + + snprintf(name, NAMESZ, IFNAME"%u", port_id); + ret = add_attr(&req, IFLA_IFNAME, name, strlen(name) + 1); + if (ret < 0) + return -1; + + rta1 = add_attr_nested(&req, IFLA_LINKINFO); + if (rta1 == NULL) + return -1; + + snprintf(type, NAMESZ, UNCI_DEVICE); + ret = add_attr(&req, IFLA_INFO_KIND, type, strlen(type) + 1); + if (ret < 0) + return -1; + + rta2 = add_attr_nested(&req, IFLA_INFO_DATA); + if (rta2 == NULL) + return -1; + + ret = add_attr(&req, IFLA_UNCI_PORTID, &port_id, sizeof(uint8_t)); + if (ret < 0) + return -1; + + ret = add_attr(&req, IFLA_UNCI_PID, &pid, sizeof(uint32_t)); + if (ret < 0) + return -1; + + end_attr_nested(&req, rta2); + end_attr_nested(&req, rta1); + + memset(&nladdr, 0, sizeof(nladdr)); + nladdr.nl_family = AF_NETLINK; + + iov.iov_base = (void *)&req.nlmsg; + iov.iov_len = req.nlmsg.nlmsg_len; + + memset(&msg, 0, sizeof(struct msghdr)); + msg.msg_name = &nladdr; + msg.msg_namelen = sizeof(nladdr); + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + + ret = sendmsg(unci_rtnl_fd, &msg, 0); + if (ret < 0) { + RTE_LOG(ERR, CTRL_IF, "Send for create failed %d.\n", errno); + return -1; + } + + memset(buf, 0, sizeof(buf)); + iov.iov_base = buf; + iov.iov_len = sizeof(buf); + + ret = recvmsg(unci_rtnl_fd, &msg, 0); + if (ret < 0) { + RTE_LOG(ERR, CTRL_IF, "Recv for create failed\n"); + return -1; + } + + return 0; +} + +int +rte_eth_control_interface_create_one(uint8_t port_id) +{ + int ret; + + if (control_interface_ref_get() != 0) { + ret = rte_eth_rtnl_create(port_id); + RTE_LOG(DEBUG, CTRL_IF, + "Control interface %s for port:%u\n", + ret < 0 ? "failed" : "created", port_id); + } + + return 0; +} + +static int +rte_eth_rtnl_destroy(uint8_t port_id) +{ + struct unci_request req; + struct ifinfomsg *info; + char name[NAMESZ]; + struct iovec iov; + struct msghdr msg; + struct sockaddr_nl nladdr; + int ret; + + memset(&req, 0, sizeof(struct unci_request)); + + req.nlmsg.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); + req.nlmsg.nlmsg_flags = NLM_F_REQUEST; + req.nlmsg.nlmsg_type = RTM_DELLINK; + + info = NLMSG_DATA(&req.nlmsg); + + info->ifi_family = AF_UNSPEC; + info->ifi_index = 0; + + snprintf(name, NAMESZ, IFNAME"%u", port_id); + ret = add_attr(&req, IFLA_IFNAME, name, strlen(name) + 1); + if (ret < 0) + return -1; + + memset(&nladdr, 0, sizeof(nladdr)); + nladdr.nl_family = AF_NETLINK; + + iov.iov_base = (void *)&req.nlmsg; + iov.iov_len = req.nlmsg.nlmsg_len; + + memset(&msg, 0, sizeof(struct msghdr)); + msg.msg_name = &nladdr; + msg.msg_namelen = sizeof(nladdr); + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + + ret = sendmsg(unci_rtnl_fd, &msg, 0); + if (ret < 0) { + RTE_LOG(ERR, CTRL_IF, "Send for destroy failed\n"); + return -1; + } + return 0; +} + +int +rte_eth_control_interface_destroy_one(uint8_t port_id) +{ + rte_eth_rtnl_destroy(port_id); + control_interface_ref_put(); + RTE_LOG(DEBUG, CTRL_IF, "Control interface destroyed for port:%u\n", + port_id); + + return 0; +} diff --git a/lib/librte_ctrl_if/rte_ctrl_if.h b/lib/librte_ctrl_if/rte_ctrl_if.h index 04a6983bb..13ede38a8 100644 --- a/lib/librte_ctrl_if/rte_ctrl_if.h +++ b/lib/librte_ctrl_if/rte_ctrl_if.h @@ -49,6 +49,40 @@ extern "C" { #include +/** + * Creates control interfaces (Linux virtual network interface)for + * given ethdev port. + * + * This API opens device created by supportive kernel module and initializes + * kernel communication interface. + * + * With first interface created, a pthread created to receive the control + * messages. + * + * If supportive kernel module is not inserted this API will return + * an error. + * + * @param port_id + * port id to create virtual interface + * @return + * 0 on success. + * Negative value on error. + */ +int rte_eth_control_interface_create_one(uint8_t port_id); + +/** + * Destroys control interfaces. + * + * This API close device created by supportive kernel module and release + * underlying communication interface. + * + * @return + * @param port_id + * port id to destroy virtual interface + * 0 on success. + * Negative value on error. + */ +int rte_eth_control_interface_destroy_one(uint8_t port_id); #ifdef __cplusplus } diff --git a/lib/librte_ctrl_if/rte_ctrl_if_version.map b/lib/librte_ctrl_if/rte_ctrl_if_version.map index b6d2840be..b658a0ee0 100644 --- a/lib/librte_ctrl_if/rte_ctrl_if_version.map +++ b/lib/librte_ctrl_if/rte_ctrl_if_version.map @@ -1,4 +1,8 @@ DPDK_17.08 { + global: + + rte_eth_control_interface_create_one; + rte_eth_control_interface_destroy_one; local: *; };