diff options
Diffstat (limited to 'src/spdk/lib/net')
-rw-r--r-- | src/spdk/lib/net/Makefile | 46 | ||||
-rw-r--r-- | src/spdk/lib/net/interface.c | 551 | ||||
-rw-r--r-- | src/spdk/lib/net/net_internal.h | 79 | ||||
-rw-r--r-- | src/spdk/lib/net/net_rpc.c | 198 | ||||
-rw-r--r-- | src/spdk/lib/net/spdk_net.map | 9 |
5 files changed, 883 insertions, 0 deletions
diff --git a/src/spdk/lib/net/Makefile b/src/spdk/lib/net/Makefile new file mode 100644 index 000000000..918df6cfb --- /dev/null +++ b/src/spdk/lib/net/Makefile @@ -0,0 +1,46 @@ +# +# BSD LICENSE +# +# Copyright (c) Intel Corporation. +# 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. +# + +SPDK_ROOT_DIR := $(abspath $(CURDIR)/../..) +include $(SPDK_ROOT_DIR)/mk/spdk.common.mk + +SO_VER := 2 +SO_MINOR := 0 + +C_SRCS = interface.c net_rpc.c + +LIBNAME = net + +SPDK_MAP_FILE = $(abspath $(CURDIR)/spdk_net.map) + +include $(SPDK_ROOT_DIR)/mk/spdk.lib.mk diff --git a/src/spdk/lib/net/interface.c b/src/spdk/lib/net/interface.c new file mode 100644 index 000000000..358cbc308 --- /dev/null +++ b/src/spdk/lib/net/interface.c @@ -0,0 +1,551 @@ +/*- + * BSD LICENSE + * + * Copyright (c) Intel Corporation. + * 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 "net_internal.h" + +#include "spdk/stdinc.h" +#include "spdk/string.h" + +#include "spdk/log.h" +#include "spdk/net.h" + +#ifdef __linux__ /* Interface management is Linux-specific */ + +#include <linux/netlink.h> +#include <linux/rtnetlink.h> + +static TAILQ_HEAD(, spdk_interface) g_interface_head; + +static pthread_mutex_t interface_lock = PTHREAD_MUTEX_INITIALIZER; + +static int get_ifc_ipv4(void) +{ + int ret; + int rtattrlen; + int netlink_fd; + uint32_t ipv4_addr; + + struct { + struct nlmsghdr n; + struct ifaddrmsg r; + struct rtattr rta; + } req; + char buf[16384]; + struct nlmsghdr *nlmp; + struct ifaddrmsg *rtmp; + struct rtattr *rtatp; + struct spdk_interface *ifc; + + netlink_fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE); + if (netlink_fd < 0) { + SPDK_ERRLOG("socket failed!\n"); + return 1; + } + + /* + * Prepare a message structure + */ + memset(&req, 0, sizeof(req)); + req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg)); + req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT; + req.n.nlmsg_type = RTM_GETADDR; + + /* IPv4 only */ + req.r.ifa_family = AF_INET; + + /* + * Fill up all the attributes for the rtnetlink header. + */ + assert(&req.rta == (struct rtattr *)(((char *)&req) + NLMSG_ALIGN(req.n.nlmsg_len))); + req.rta.rta_len = RTA_LENGTH(16); + + /* Send and recv the message from kernel */ + ret = send(netlink_fd, &req, req.n.nlmsg_len, 0); + if (ret < 0) { + SPDK_ERRLOG("netlink send failed: %s\n", spdk_strerror(errno)); + ret = 1; + goto exit; + } + + ret = recv(netlink_fd, buf, sizeof(buf), 0); + if (ret <= 0) { + SPDK_ERRLOG("netlink recv failed: %s\n", spdk_strerror(errno)); + ret = 1; + goto exit; + } + + for (nlmp = (struct nlmsghdr *)buf; ret > (int)sizeof(*nlmp);) { + int len = nlmp->nlmsg_len; + int req_len = len - sizeof(*nlmp); + + if (req_len < 0 || len > ret) { + SPDK_ERRLOG("error\n"); + ret = 1; + goto exit; + } + + if (!NLMSG_OK(nlmp, (uint32_t)ret)) { + SPDK_ERRLOG("NLMSG not OK\n"); + ret = 1; + goto exit; + } + + rtmp = (struct ifaddrmsg *)NLMSG_DATA(nlmp); + rtatp = (struct rtattr *)IFA_RTA(rtmp); + + rtattrlen = IFA_PAYLOAD(nlmp); + + for (; RTA_OK(rtatp, rtattrlen); rtatp = RTA_NEXT(rtatp, rtattrlen)) { + if (rtatp->rta_type == IFA_LOCAL) { + memcpy(&ipv4_addr, (struct in_addr *)RTA_DATA(rtatp), + sizeof(struct in_addr)); + TAILQ_FOREACH(ifc, &g_interface_head, tailq) { + if (ifc->index == rtmp->ifa_index) { + /* add a new IP address to interface */ + if (ifc->num_ip_addresses >= SPDK_MAX_IP_PER_IFC) { + SPDK_ERRLOG("SPDK: number of IP addresses supported for %s excceded. limit=%d\n", + ifc->name, + SPDK_MAX_IP_PER_IFC); + break; + } + ifc->ip_address[ifc->num_ip_addresses] = ipv4_addr; + ifc->num_ip_addresses++; + break; + } + } + } + } + ret -= NLMSG_ALIGN(len); + nlmp = (struct nlmsghdr *)((char *)nlmp + NLMSG_ALIGN(len)); + } + ret = 0; + +exit: + close(netlink_fd); + return ret; +} + + +static int process_new_interface_msg(struct nlmsghdr *h) +{ + int len; + struct spdk_interface *ifc; + struct ifinfomsg *iface; + struct rtattr *attribute; + + iface = (struct ifinfomsg *)NLMSG_DATA(h); + + ifc = (struct spdk_interface *) malloc(sizeof(*ifc)); + if (ifc == NULL) { + SPDK_ERRLOG("Malloc failed\n"); + return 1; + } + + memset(ifc, 0, sizeof(*ifc)); + + /* Set interface index */ + ifc->index = iface->ifi_index; + + len = h->nlmsg_len - NLMSG_LENGTH(sizeof(*iface)); + + /* Loop over all attributes for the NEWLINK message */ + for (attribute = IFLA_RTA(iface); RTA_OK(attribute, len); attribute = RTA_NEXT(attribute, len)) { + switch (attribute->rta_type) { + case IFLA_IFNAME: + if (if_indextoname(iface->ifi_index, ifc->name) == NULL) { + SPDK_ERRLOG("Indextoname failed!\n"); + free(ifc); + return 2; + } + break; + default: + break; + } + } + TAILQ_INSERT_TAIL(&g_interface_head, ifc, tailq); + return 0; +} + +static int prepare_ifc_list(void) +{ + int ret = 0; + struct nl_req_s { + struct nlmsghdr hdr; + struct rtgenmsg gen; + struct ifinfomsg ifi; + }; + int netlink_fd; + struct sockaddr_nl local; /* Our local (user space) side of the communication */ + struct sockaddr_nl kernel; /* The remote (kernel space) side of the communication */ + + struct msghdr rtnl_msg; /* Generic msghdr struct for use with sendmsg */ + struct iovec io; /* IO vector for sendmsg */ + + struct nl_req_s req; /* Structure that describes the rtnetlink packet itself */ + char reply[16384]; /* a large buffer to receive lots of link information */ + + pid_t pid = getpid(); /* Our process ID to build the correct netlink address */ + int end = 0; /* some flag to end loop parsing */ + + /* + * Prepare netlink socket for kernel/user space communication + */ + netlink_fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); + if (netlink_fd < 0) { + SPDK_ERRLOG("socket failed!\n"); + return 1; + } + + memset(&local, 0, sizeof(local)); /* Fill-in local address information */ + local.nl_family = AF_NETLINK; + local.nl_pid = pid; + local.nl_groups = 0; + + /* RTNL socket is ready to use, prepare and send L2 request. */ + memset(&rtnl_msg, 0, sizeof(rtnl_msg)); + memset(&kernel, 0, sizeof(kernel)); + memset(&req, 0, sizeof(req)); + + kernel.nl_family = AF_NETLINK; /* Fill-in kernel address (destination of our message) */ + + req.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg)); + req.hdr.nlmsg_type = RTM_GETLINK; + req.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; + req.hdr.nlmsg_seq = 1; + req.hdr.nlmsg_pid = pid; + + req.ifi.ifi_family = AF_UNSPEC; + req.ifi.ifi_type = 1; + + io.iov_base = &req; + io.iov_len = req.hdr.nlmsg_len; + rtnl_msg.msg_iov = &io; + rtnl_msg.msg_iovlen = 1; + rtnl_msg.msg_name = &kernel; + rtnl_msg.msg_namelen = sizeof(kernel); + + if (sendmsg(netlink_fd, &rtnl_msg, 0) == -1) { + SPDK_ERRLOG("Sendmsg failed!\n"); + ret = 1; + goto exit; + } + + /* Parse reply */ + while (!end) { + int len; + struct nlmsghdr *msg_ptr; /* Pointer to current message part */ + + struct msghdr rtnl_reply; /* Generic msghdr structure for use with recvmsg */ + struct iovec io_reply; + + memset(&io_reply, 0, sizeof(io_reply)); + memset(&rtnl_reply, 0, sizeof(rtnl_reply)); + + io.iov_base = reply; + io.iov_len = 8192; + rtnl_reply.msg_iov = &io; + rtnl_reply.msg_iovlen = 1; + rtnl_reply.msg_name = &kernel; + rtnl_reply.msg_namelen = sizeof(kernel); + + /* Read as much data as fits in the receive buffer */ + len = recvmsg(netlink_fd, &rtnl_reply, 0); + if (len) { + for (msg_ptr = (struct nlmsghdr *) reply; NLMSG_OK(msg_ptr, (uint32_t)len); + msg_ptr = NLMSG_NEXT(msg_ptr, len)) { + switch (msg_ptr->nlmsg_type) { + case NLMSG_DONE: /* This is the special meaning NLMSG_DONE message we asked for by using NLM_F_DUMP flag */ + end++; + break; + case RTM_NEWLINK: /* This is a RTM_NEWLINK message, which contains lots of information about a link */ + ret = process_new_interface_msg(msg_ptr); + if (ret != 0) { + goto exit; + } + break; + default: + break; + } + } + } + } +exit: + close(netlink_fd); + return ret; +} + +static struct spdk_interface * +interface_find_by_index(uint32_t ifc_index) +{ + struct spdk_interface *ifc_entry; + + /* Mutex must has benn held by the caller */ + TAILQ_FOREACH(ifc_entry, &g_interface_head, tailq) { + if (ifc_entry->index == ifc_index) { + return ifc_entry; + } + } + + return NULL; +} + +static int netlink_addr_msg(uint32_t ifc_idx, uint32_t ip_address, uint32_t create) +{ + int fd; + struct sockaddr_nl la; + struct sockaddr_nl pa; + struct msghdr msg; + struct iovec iov; + int ifal; + struct { + struct nlmsghdr n; + struct ifaddrmsg r; + char buf[16384]; + } req; + struct rtattr *rta; + + fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); + if (fd < 0) { + SPDK_ERRLOG("socket failed!\n"); + return errno; + } + + /* setup local address & bind using this address. */ + bzero(&la, sizeof(la)); + la.nl_family = AF_NETLINK; + la.nl_pid = getpid(); + bind(fd, (struct sockaddr *) &la, sizeof(la)); + + /* initialize RTNETLINK request buffer. */ + bzero(&req, sizeof(req)); + + /* compute the initial length of the service request. */ + ifal = sizeof(struct ifaddrmsg); + + /* add first attrib: set IP addr and RTNETLINK buffer size. */ + rta = (struct rtattr *) req.buf; + rta->rta_type = IFA_ADDRESS; + rta->rta_len = sizeof(struct rtattr) + 4; + memcpy(((char *)rta) + sizeof(struct rtattr), &ip_address, sizeof(ip_address)); + ifal += rta->rta_len; + + /* add second attrib. */ + rta = (struct rtattr *)(((char *)rta) + rta->rta_len); + rta->rta_type = IFA_LOCAL; + rta->rta_len = sizeof(struct rtattr) + 4; + memcpy(((char *)rta) + sizeof(struct rtattr), &ip_address, sizeof(ip_address)); + ifal += rta->rta_len; + + /* setup the NETLINK header. */ + req.n.nlmsg_len = NLMSG_LENGTH(ifal); + if (create) { + req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_APPEND; + req.n.nlmsg_type = RTM_NEWADDR; + } else { + req.n.nlmsg_flags = NLM_F_REQUEST; + req.n.nlmsg_type = RTM_DELADDR; + } + + /* setup the service header (struct rtmsg). */ + req.r.ifa_family = AF_INET; + req.r.ifa_prefixlen = 32; /* hardcoded */ + req.r.ifa_flags = IFA_F_PERMANENT | IFA_F_SECONDARY; + req.r.ifa_index = ifc_idx; + req.r.ifa_scope = 0; + + /* create the remote address to communicate. */ + bzero(&pa, sizeof(pa)); + pa.nl_family = AF_NETLINK; + + /* initialize & create the struct msghdr supplied to the sendmsg() function. */ + bzero(&msg, sizeof(msg)); + msg.msg_name = (void *) &pa; + msg.msg_namelen = sizeof(pa); + + /* place the pointer & size of the RTNETLINK message in the struct msghdr. */ + iov.iov_base = (void *) &req.n; + iov.iov_len = req.n.nlmsg_len; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + /* send the RTNETLINK message to kernel. */ + sendmsg(fd, &msg, 0); + close(fd); + return 0; +} + +static void interface_ip_update(void) +{ + struct spdk_interface *ifc_entry; + + pthread_mutex_lock(&interface_lock); + TAILQ_FOREACH(ifc_entry, &g_interface_head, tailq) { + ifc_entry->num_ip_addresses = 0; + memset(ifc_entry->ip_address, 0, sizeof(ifc_entry->ip_address)); + } + get_ifc_ipv4(); + pthread_mutex_unlock(&interface_lock); +} + +static int +interface_is_ip_address_in_use(int ifc_index, uint32_t addr, bool add) +{ + struct spdk_interface *ifc_entry; + bool in_use = false; + uint32_t idx = 0; + + interface_ip_update(); + + pthread_mutex_lock(&interface_lock); + ifc_entry = interface_find_by_index(ifc_index); + if (ifc_entry == NULL) { + pthread_mutex_unlock(&interface_lock); + return -ENODEV; + } + + for (idx = 0; idx < ifc_entry->num_ip_addresses; idx++) { + if (ifc_entry->ip_address[idx] == addr) { + in_use = true; + break; + } + } + pthread_mutex_unlock(&interface_lock); + + /* The IP address to add is alerady in use */ + if (add == true && in_use == true) { + return -EADDRINUSE; + } + + /* The IP address to delete is not in use */ + if (add == false && in_use == false) { + return -ENXIO; + } + + return 0; +} + +int +spdk_interface_init(void) +{ + int rc = 0; + + TAILQ_INIT(&g_interface_head); + rc = prepare_ifc_list(); + if (!rc) { + rc = get_ifc_ipv4(); + } + + return rc; +} + +void +spdk_interface_destroy(void) +{ + struct spdk_interface *ifc_entry; + + while (!TAILQ_EMPTY(&g_interface_head)) { + ifc_entry = TAILQ_FIRST(&g_interface_head); + TAILQ_REMOVE(&g_interface_head, ifc_entry, tailq); + free(ifc_entry); + } +} + +int +interface_net_interface_add_ip_address(int ifc_index, char *ip_addr) +{ + uint32_t addr; + int ret; + + addr = inet_addr(ip_addr); + + ret = interface_is_ip_address_in_use(ifc_index, addr, true); + if (ret < 0) { + return ret; + } + + return netlink_addr_msg(ifc_index, addr, 1); +} + +int +interface_net_interface_delete_ip_address(int ifc_index, char *ip_addr) +{ + uint32_t addr; + int ret; + + addr = inet_addr(ip_addr); + + ret = interface_is_ip_address_in_use(ifc_index, addr, false); + if (ret < 0) { + return ret; + } + + return netlink_addr_msg(ifc_index, addr, 0); +} + +void *interface_get_list(void) +{ + interface_ip_update(); + return &g_interface_head; +} + +#else /* Not Linux */ + +int +spdk_interface_init(void) +{ + return 0; +} + +void +spdk_interface_destroy(void) +{ +} + +int +interface_net_interface_add_ip_address(int ifc_index, char *ip_addr) +{ + return -1; +} + +int +interface_net_interface_delete_ip_address(int ifc_index, char *ip_addr) +{ + return -1; +} + +void * +interface_get_list(void) +{ + return NULL; +} + +#endif diff --git a/src/spdk/lib/net/net_internal.h b/src/spdk/lib/net/net_internal.h new file mode 100644 index 000000000..4a1422939 --- /dev/null +++ b/src/spdk/lib/net/net_internal.h @@ -0,0 +1,79 @@ +/*- + * BSD LICENSE + * + * Copyright (c) Intel Corporation. + * 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 SPDK_NET_INTERNAL_H +#define SPDK_NET_INTERNAL_H + +#include "spdk/stdinc.h" + +#include "spdk/queue.h" + +#define SPDK_IFNAMSIZE 32 +#define SPDK_MAX_IP_PER_IFC 32 + +struct spdk_interface { + char name[SPDK_IFNAMSIZE]; + uint32_t index; + uint32_t num_ip_addresses; /* number of IP addresses defined */ + uint32_t ip_address[SPDK_MAX_IP_PER_IFC]; + TAILQ_ENTRY(spdk_interface) tailq; +}; + +/** + * Add an ip address to the network interface. + * + * \param ifc_index Index of the network interface. + * \param ip_addr Ip address to add. + * + * \return 0 on success, -1 on failure. + */ +int interface_net_interface_add_ip_address(int ifc_index, char *ip_addr); + +/** + * Delete an ip address from the network interface. + * + * \param ifc_index Index of the network interface. + * \param ip_addr Ip address to delete. + * + * \return 0 on success, -1 on failure. + */ +int interface_net_interface_delete_ip_address(int ifc_index, char *ip_addr); + +/** + * Get the list of all the network interfaces. + * + * \return a pointer to the head of the linked list of all the network interfaces. + */ +void *interface_get_list(void); + +#endif /* SPDK_NET_INTERNAL_H */ diff --git a/src/spdk/lib/net/net_rpc.c b/src/spdk/lib/net/net_rpc.c new file mode 100644 index 000000000..47a302a6b --- /dev/null +++ b/src/spdk/lib/net/net_rpc.c @@ -0,0 +1,198 @@ +/*- + * BSD LICENSE + * + * Copyright (c) Intel Corporation. + * 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 "net_internal.h" + +#include "spdk/stdinc.h" + +#include "spdk/rpc.h" +#include "spdk/net.h" +#include "spdk/util.h" + +#include "spdk_internal/log.h" + +struct rpc_ip_address { + int32_t ifc_index; + char *ip_address; +}; + +static void +free_rpc_ip_address(struct rpc_ip_address *req) +{ + free(req->ip_address); +} + +static const struct spdk_json_object_decoder rpc_ip_address_decoders[] = { + {"ifc_index", offsetof(struct rpc_ip_address, ifc_index), spdk_json_decode_int32}, + {"ip_address", offsetof(struct rpc_ip_address, ip_address), spdk_json_decode_string}, +}; + +static void +rpc_net_interface_add_ip_address(struct spdk_jsonrpc_request *request, + const struct spdk_json_val *params) +{ + struct rpc_ip_address req = {}; + struct spdk_json_write_ctx *w; + int ret_val = 0; + + if (spdk_json_decode_object(params, rpc_ip_address_decoders, + SPDK_COUNTOF(rpc_ip_address_decoders), + &req)) { + SPDK_DEBUGLOG(SPDK_LOG_NET, "spdk_json_decode_object failed\n"); + spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, + "spdk_json_decode_object failed"); + goto invalid; + } + + ret_val = interface_net_interface_add_ip_address(req.ifc_index, req.ip_address); + if (ret_val) { + if (ret_val == -ENODEV) { + spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_STATE, + "Interface %d not available", req.ifc_index); + } else if (ret_val == -EADDRINUSE) { + spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, + "IP address %s is already added to interface %d", + req.ip_address, req.ifc_index); + } else { + spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, + strerror(ret_val)); + } + goto invalid; + } + + free_rpc_ip_address(&req); + + w = spdk_jsonrpc_begin_result(request); + spdk_json_write_bool(w, true); + spdk_jsonrpc_end_result(request, w); + return; + +invalid: + free_rpc_ip_address(&req); +} +SPDK_RPC_REGISTER("net_interface_add_ip_address", rpc_net_interface_add_ip_address, + SPDK_RPC_RUNTIME) +SPDK_RPC_REGISTER_ALIAS_DEPRECATED(net_interface_add_ip_address, add_ip_address) + +static void +rpc_net_interface_delete_ip_address(struct spdk_jsonrpc_request *request, + const struct spdk_json_val *params) +{ + struct rpc_ip_address req = {}; + struct spdk_json_write_ctx *w; + int ret_val = 0; + + if (spdk_json_decode_object(params, rpc_ip_address_decoders, + SPDK_COUNTOF(rpc_ip_address_decoders), + &req)) { + SPDK_DEBUGLOG(SPDK_LOG_NET, "spdk_json_decode_object failed\n"); + spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, + "spdk_json_decode_object failed"); + goto invalid; + } + + ret_val = interface_net_interface_delete_ip_address(req.ifc_index, req.ip_address); + if (ret_val) { + if (ret_val == -ENODEV) { + spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_STATE, + "Interface %d not available", req.ifc_index); + } else if (ret_val == -ENXIO) { + spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, + "IP address %s is not found in interface %d", + req.ip_address, req.ifc_index); + } else { + spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, + strerror(ret_val)); + } + goto invalid; + } + + free_rpc_ip_address(&req); + + w = spdk_jsonrpc_begin_result(request); + spdk_json_write_bool(w, true); + spdk_jsonrpc_end_result(request, w); + return; + +invalid: + free_rpc_ip_address(&req); +} +SPDK_RPC_REGISTER("net_interface_delete_ip_address", rpc_net_interface_delete_ip_address, + SPDK_RPC_RUNTIME) +SPDK_RPC_REGISTER_ALIAS_DEPRECATED(net_interface_delete_ip_address, delete_ip_address) + +static void +rpc_net_get_interfaces(struct spdk_jsonrpc_request *request, + const struct spdk_json_val *params) +{ + struct spdk_json_write_ctx *w; + TAILQ_HEAD(, spdk_interface) *interface_head = interface_get_list(); + struct spdk_interface *ifc; + char *ip_address; + struct in_addr inaddr; + uint32_t i; + + if (params != NULL) { + spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, + "net_get_interfaces requires no parameters"); + return; + } + + w = spdk_jsonrpc_begin_result(request); + spdk_json_write_array_begin(w); + + TAILQ_FOREACH(ifc, interface_head, tailq) { + spdk_json_write_object_begin(w); + + spdk_json_write_named_string(w, "name", ifc->name); + + spdk_json_write_named_int32(w, "ifc_index", ifc->index); + + spdk_json_write_named_array_begin(w, "ip_addr"); + for (i = 0; i < ifc->num_ip_addresses; i++) { + memcpy(&inaddr, &ifc->ip_address[i], sizeof(uint32_t)); + ip_address = inet_ntoa(inaddr); + spdk_json_write_string(w, ip_address); + } + spdk_json_write_array_end(w); + + spdk_json_write_object_end(w); + } + spdk_json_write_array_end(w); + + spdk_jsonrpc_end_result(request, w); +} +SPDK_RPC_REGISTER("net_get_interfaces", rpc_net_get_interfaces, SPDK_RPC_RUNTIME) +SPDK_RPC_REGISTER_ALIAS_DEPRECATED(net_get_interfaces, get_interfaces) + +SPDK_LOG_REGISTER_COMPONENT("net", SPDK_LOG_NET) diff --git a/src/spdk/lib/net/spdk_net.map b/src/spdk/lib/net/spdk_net.map new file mode 100644 index 000000000..944bc4c6e --- /dev/null +++ b/src/spdk/lib/net/spdk_net.map @@ -0,0 +1,9 @@ +{ + global: + + # public functions + spdk_interface_init; + spdk_interface_destroy; + + local: *; +}; |