Library provides two APIs to create and destroy interfaces.

rtnl used to create or destroy interfaces.

Signed-off-by: Ferruh Yigit <ferruh.yi...@intel.com>
---
 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 <fcntl.h>
+#include <stdint.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+
+#include <rte_log.h>
 #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 <exec-env/rte_unci_common.h>
 
+/**
+ * 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: *;
 };
-- 
2.13.0

Reply via email to