Add a network stack abstraction layer.
This is a useful abstraction when you want to plug in a userspace networking layer instead of using the kernel. Change-Id: I7039d2987e6abad9dcd1987fa105282b1598e2f5 Signed-off-by: Ben Walker <benjamin.walker@intel.com>
This commit is contained in:
parent
01d13145c9
commit
d3090c8455
87
include/spdk/net.h
Normal file
87
include/spdk/net.h
Normal file
@ -0,0 +1,87 @@
|
||||
/*-
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* Net framework abstraction layer
|
||||
*/
|
||||
|
||||
#ifndef SPDK_NET_H
|
||||
#define SPDK_NET_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/uio.h>
|
||||
|
||||
#include "spdk/queue.h"
|
||||
|
||||
#define IDLE_INTERVAL_TIME_IN_US 5000
|
||||
|
||||
const char *spdk_net_framework_get_name(void);
|
||||
int spdk_net_framework_start(void);
|
||||
void spdk_net_framework_clear_socket_association(int sock);
|
||||
int spdk_net_framework_fini(void);
|
||||
int spdk_net_framework_idle_time(void);
|
||||
|
||||
#define SPDK_IFNAMSIZE 32
|
||||
#define SPDK_MAX_IP_PER_IFC 32
|
||||
#define SPDK_MAX_NIC_NUM 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;
|
||||
};
|
||||
|
||||
int spdk_interface_add_ip_address(int ifc_index, char *ip_addr);
|
||||
int spdk_interface_delete_ip_address(int ifc_index, char *ip_addr);
|
||||
void *spdk_interface_get_list(void);
|
||||
|
||||
int spdk_sock_getaddr(int sock, char *saddr, int slen, char *caddr, int clen);
|
||||
int spdk_sock_connect(const char *ip, int port);
|
||||
int spdk_sock_listen(const char *ip, int port);
|
||||
int spdk_sock_accept(int sock);
|
||||
int spdk_sock_close(int sock);
|
||||
ssize_t spdk_sock_recv(int sock, void *buf, size_t len);
|
||||
ssize_t spdk_sock_writev(int sock, struct iovec *iov, int iovcnt);
|
||||
|
||||
int spdk_sock_set_recvlowat(int sock, int nbytes);
|
||||
int spdk_sock_set_recvbuf(int sock, int sz);
|
||||
int spdk_sock_set_sendbuf(int sock, int sz);
|
||||
|
||||
bool spdk_sock_is_ipv6(int sock);
|
||||
bool spdk_sock_is_ipv4(int sock);
|
||||
|
||||
#endif /* SPDK_NET_FRAMEWORK_H */
|
@ -34,7 +34,8 @@
|
||||
SPDK_ROOT_DIR := $(abspath $(CURDIR)/..)
|
||||
include $(SPDK_ROOT_DIR)/mk/spdk.common.mk
|
||||
|
||||
DIRS-y += bdev conf copy cunit event json jsonrpc log memory rpc trace util nvme nvmf scsi ioat
|
||||
DIRS-y += bdev conf copy cunit event json jsonrpc log memory \
|
||||
net rpc trace util nvme nvmf scsi ioat
|
||||
|
||||
.PHONY: all clean $(DIRS-y)
|
||||
|
||||
|
41
lib/net/Makefile
Normal file
41
lib/net/Makefile
Normal file
@ -0,0 +1,41 @@
|
||||
#
|
||||
# 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
|
||||
|
||||
C_SRCS = interface.c sock.c net_framework_default.c net_rpc.c
|
||||
|
||||
LIBNAME = net
|
||||
|
||||
include $(SPDK_ROOT_DIR)/mk/spdk.lib.mk
|
503
lib/net/interface.c
Normal file
503
lib/net/interface.c
Normal file
@ -0,0 +1,503 @@
|
||||
/*-
|
||||
* 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 <stdlib.h>
|
||||
|
||||
#include "spdk/log.h"
|
||||
#include "spdk/event.h"
|
||||
#include "spdk/net.h"
|
||||
|
||||
#ifdef __linux__ /* Interface management is Linux-specific */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <netinet/in.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <net/if.h>
|
||||
#include <unistd.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <pthread.h>
|
||||
|
||||
|
||||
|
||||
static TAILQ_HEAD(, spdk_interface) g_interface_head;
|
||||
|
||||
static pthread_mutex_t interface_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
static uint32_t spdk_get_ifc_ipv4(void)
|
||||
{
|
||||
int ret;
|
||||
int rtattrlen;
|
||||
int netlink_fd;
|
||||
uint32_t ipv4_addr;
|
||||
|
||||
struct {
|
||||
struct nlmsghdr n;
|
||||
struct ifaddrmsg r;
|
||||
} req;
|
||||
struct rtattr *rta;
|
||||
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.
|
||||
*/
|
||||
rta = (struct rtattr *)(((char *)&req) + NLMSG_ALIGN(req.n.nlmsg_len));
|
||||
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", strerror(errno));
|
||||
ret = 1;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ret = recv(netlink_fd, buf, sizeof(buf), 0);
|
||||
if (ret <= 0) {
|
||||
SPDK_ERRLOG("netlink recv failed: %s\n", 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 void spdk_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("%s: Malloc failed\n", __func__);
|
||||
exit(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");
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
TAILQ_INSERT_TAIL(&g_interface_head, ifc, tailq);
|
||||
}
|
||||
|
||||
static uint32_t spdk_prepare_ifc_list(void)
|
||||
{
|
||||
uint32_t 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 */
|
||||
spdk_process_new_interface_msg(msg_ptr);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
exit:
|
||||
close(netlink_fd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int spdk_interface_available(uint32_t ifc_index)
|
||||
{
|
||||
struct spdk_interface *ifc_entry;
|
||||
|
||||
pthread_mutex_lock(&interface_lock);
|
||||
TAILQ_FOREACH(ifc_entry, &g_interface_head, tailq) {
|
||||
if (ifc_entry->index == ifc_index) {
|
||||
pthread_mutex_unlock(&interface_lock);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&interface_lock);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if (spdk_interface_available(ifc_idx))
|
||||
return -1;
|
||||
|
||||
fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
|
||||
|
||||
/* 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));
|
||||
|
||||
/* initalize 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 spdk_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));
|
||||
}
|
||||
spdk_get_ifc_ipv4();
|
||||
pthread_mutex_unlock(&interface_lock);
|
||||
}
|
||||
|
||||
static int
|
||||
spdk_interface_init(void)
|
||||
{
|
||||
TAILQ_INIT(&g_interface_head);
|
||||
spdk_prepare_ifc_list();
|
||||
spdk_get_ifc_ipv4();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int 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);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
spdk_interface_add_ip_address(int ifc_index, char *ip_addr)
|
||||
{
|
||||
uint32_t addr;
|
||||
|
||||
addr = inet_addr(ip_addr);
|
||||
return netlink_addr_msg(ifc_index, addr, 1);
|
||||
}
|
||||
|
||||
int
|
||||
spdk_interface_delete_ip_address(int ifc_index, char *ip_addr)
|
||||
{
|
||||
uint32_t addr;
|
||||
|
||||
addr = inet_addr(ip_addr);
|
||||
return netlink_addr_msg(ifc_index, addr, 0);
|
||||
}
|
||||
|
||||
void *spdk_interface_get_list(void)
|
||||
{
|
||||
spdk_interface_ip_update();
|
||||
return &g_interface_head;
|
||||
}
|
||||
|
||||
#else /* Not Linux */
|
||||
|
||||
static int
|
||||
spdk_interface_init(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
spdk_interface_destroy(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
spdk_interface_add_ip_address(int ifc_index, char *ip_addr)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
spdk_interface_delete_ip_address(int ifc_index, char *ip_addr)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
void *
|
||||
spdk_interface_get_list(void)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
SPDK_SUBSYSTEM_REGISTER(interface, spdk_interface_init, spdk_interface_destroy, NULL)
|
67
lib/net/net_framework_default.c
Normal file
67
lib/net/net_framework_default.c
Normal file
@ -0,0 +1,67 @@
|
||||
/*-
|
||||
* 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 "spdk/event.h"
|
||||
#include "spdk/net.h"
|
||||
|
||||
__attribute__((weak))
|
||||
const char *spdk_net_framework_get_name(void)
|
||||
{
|
||||
return "default";
|
||||
}
|
||||
|
||||
__attribute__((weak))
|
||||
int spdk_net_framework_start(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
__attribute__((weak))
|
||||
int spdk_net_framework_fini(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
__attribute__((weak))
|
||||
void spdk_net_framework_clear_socket_association(int sock)
|
||||
{
|
||||
}
|
||||
|
||||
__attribute__((weak))
|
||||
int spdk_net_framework_idle_time(void)
|
||||
{
|
||||
return IDLE_INTERVAL_TIME_IN_US;
|
||||
}
|
||||
|
||||
SPDK_SUBSYSTEM_REGISTER(net_framework, spdk_net_framework_start, spdk_net_framework_fini, NULL)
|
||||
SPDK_SUBSYSTEM_DEPEND(net_framework, interface)
|
180
lib/net/net_rpc.c
Normal file
180
lib/net/net_rpc.c
Normal file
@ -0,0 +1,180 @@
|
||||
/*-
|
||||
* 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 <string.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "spdk/log.h"
|
||||
#include "spdk/rpc.h"
|
||||
#include "spdk/net.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
|
||||
spdk_rpc_add_ip_address(struct spdk_jsonrpc_server_conn *conn,
|
||||
const struct spdk_json_val *params,
|
||||
const struct spdk_json_val *id)
|
||||
{
|
||||
struct rpc_ip_address req = {};
|
||||
struct spdk_json_write_ctx *w;
|
||||
|
||||
if (spdk_json_decode_object(params, rpc_ip_address_decoders,
|
||||
sizeof(rpc_ip_address_decoders) / sizeof(*rpc_ip_address_decoders),
|
||||
&req)) {
|
||||
SPDK_TRACELOG(SPDK_TRACE_DEBUG, "spdk_json_decode_object failed\n");
|
||||
goto invalid;
|
||||
}
|
||||
|
||||
if (spdk_interface_add_ip_address(req.ifc_index, req.ip_address)) {
|
||||
goto invalid;
|
||||
}
|
||||
|
||||
free_rpc_ip_address(&req);
|
||||
|
||||
if (id == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
w = spdk_jsonrpc_begin_result(conn, id);
|
||||
spdk_json_write_bool(w, true);
|
||||
spdk_jsonrpc_end_result(conn, w);
|
||||
return;
|
||||
|
||||
invalid:
|
||||
spdk_jsonrpc_send_error_response(conn, id, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
|
||||
free_rpc_ip_address(&req);
|
||||
}
|
||||
SPDK_RPC_REGISTER("add_ip_address", spdk_rpc_add_ip_address)
|
||||
|
||||
static void
|
||||
spdk_rpc_delete_ip_address(struct spdk_jsonrpc_server_conn *conn,
|
||||
const struct spdk_json_val *params,
|
||||
const struct spdk_json_val *id)
|
||||
{
|
||||
struct rpc_ip_address req = {};
|
||||
struct spdk_json_write_ctx *w;
|
||||
|
||||
if (spdk_json_decode_object(params, rpc_ip_address_decoders,
|
||||
sizeof(rpc_ip_address_decoders) / sizeof(*rpc_ip_address_decoders),
|
||||
&req)) {
|
||||
SPDK_TRACELOG(SPDK_TRACE_DEBUG, "spdk_json_decode_object failed\n");
|
||||
goto invalid;
|
||||
}
|
||||
|
||||
if (spdk_interface_delete_ip_address(req.ifc_index, req.ip_address)) {
|
||||
goto invalid;
|
||||
}
|
||||
|
||||
free_rpc_ip_address(&req);
|
||||
|
||||
if (id == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
w = spdk_jsonrpc_begin_result(conn, id);
|
||||
spdk_json_write_bool(w, true);
|
||||
spdk_jsonrpc_end_result(conn, w);
|
||||
return;
|
||||
|
||||
invalid:
|
||||
spdk_jsonrpc_send_error_response(conn, id, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
|
||||
free_rpc_ip_address(&req);
|
||||
}
|
||||
SPDK_RPC_REGISTER("delete_ip_address", spdk_rpc_delete_ip_address)
|
||||
|
||||
static void
|
||||
spdk_rpc_get_interfaces(struct spdk_jsonrpc_server_conn *conn,
|
||||
const struct spdk_json_val *params,
|
||||
const struct spdk_json_val *id)
|
||||
{
|
||||
struct spdk_json_write_ctx *w;
|
||||
TAILQ_HEAD(, spdk_interface) *interface_head = spdk_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(conn, id, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
|
||||
"get_interfaces requires no parameters");
|
||||
return;
|
||||
}
|
||||
|
||||
if (id == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
w = spdk_jsonrpc_begin_result(conn, id);
|
||||
spdk_json_write_array_begin(w);
|
||||
|
||||
TAILQ_FOREACH(ifc, interface_head, tailq) {
|
||||
spdk_json_write_object_begin(w);
|
||||
|
||||
spdk_json_write_name(w, "name");
|
||||
spdk_json_write_string(w, ifc->name);
|
||||
|
||||
spdk_json_write_name(w, "ifc_index");
|
||||
spdk_json_write_int32(w, ifc->index);
|
||||
|
||||
spdk_json_write_name(w, "ip_addr");
|
||||
spdk_json_write_array_begin(w);
|
||||
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(conn, w);
|
||||
}
|
||||
SPDK_RPC_REGISTER("get_interfaces", spdk_rpc_get_interfaces)
|
350
lib/net/sock.c
Normal file
350
lib/net/sock.c
Normal file
@ -0,0 +1,350 @@
|
||||
/*-
|
||||
* 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 <errno.h>
|
||||
#include <netdb.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "spdk/event.h"
|
||||
#include "spdk/log.h"
|
||||
#include "spdk/net.h"
|
||||
|
||||
#define MAX_TMPBUF 1024
|
||||
#define TIMEOUT_RW 60
|
||||
#define POLLWAIT 1000
|
||||
#define PORTNUMLEN 32
|
||||
|
||||
static int get_addr_str(struct sockaddr_in *paddr, char *host, int hlen)
|
||||
{
|
||||
char buf[64];
|
||||
|
||||
if (paddr == NULL || host == NULL)
|
||||
return -1;
|
||||
|
||||
uint8_t *pa = (uint8_t *)&paddr->sin_addr.s_addr;
|
||||
sprintf(buf, "%u.%u.%u.%u", pa[0], pa[1], pa[2], pa[3]);
|
||||
strncpy(host, buf, hlen);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
spdk_sock_getaddr(int sock, char *saddr, int slen, char *caddr, int clen)
|
||||
{
|
||||
struct sockaddr_storage sa;
|
||||
socklen_t salen;
|
||||
int rc;
|
||||
|
||||
memset(&sa, 0, sizeof sa);
|
||||
salen = sizeof sa;
|
||||
rc = getsockname(sock, (struct sockaddr *) &sa, &salen);
|
||||
if (rc != 0) {
|
||||
SPDK_ERRLOG("getsockname() failed (errno=%d)\n", errno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (sa.ss_family) {
|
||||
case AF_UNIX:
|
||||
/* Acceptable connection types that don't have IPs */
|
||||
return 0;
|
||||
case AF_INET:
|
||||
case AF_INET6:
|
||||
/* Code below will get IP addresses */
|
||||
break;
|
||||
default:
|
||||
/* Unsupported socket family */
|
||||
return -1;
|
||||
}
|
||||
|
||||
rc = get_addr_str((struct sockaddr_in *)&sa, saddr, slen);
|
||||
if (rc != 0) {
|
||||
SPDK_ERRLOG("getnameinfo() failed (errno=%d)\n", errno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(&sa, 0, sizeof sa);
|
||||
salen = sizeof sa;
|
||||
rc = getpeername(sock, (struct sockaddr *) &sa, &salen);
|
||||
if (rc != 0) {
|
||||
SPDK_ERRLOG("getpeername() failed (errno=%d)\n", errno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
rc = get_addr_str((struct sockaddr_in *)&sa, caddr, clen);
|
||||
if (rc != 0) {
|
||||
SPDK_ERRLOG("getnameinfo() failed (errno=%d)\n", errno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
enum spdk_sock_create_type {
|
||||
SPDK_SOCK_CREATE_LISTEN,
|
||||
SPDK_SOCK_CREATE_CONNECT,
|
||||
};
|
||||
|
||||
static int
|
||||
spdk_sock_create(const char *ip, int port, enum spdk_sock_create_type type)
|
||||
{
|
||||
char buf[MAX_TMPBUF];
|
||||
char portnum[PORTNUMLEN];
|
||||
char *p;
|
||||
struct addrinfo hints, *res, *res0;
|
||||
int sock, nonblock;
|
||||
int val = 1;
|
||||
int rc;
|
||||
|
||||
if (ip == NULL)
|
||||
return -1;
|
||||
if (ip[0] == '[') {
|
||||
snprintf(buf, sizeof(buf), "%s", ip + 1);
|
||||
p = strchr(buf, ']');
|
||||
if (p != NULL)
|
||||
*p = '\0';
|
||||
ip = (const char *) &buf[0];
|
||||
if (strcasecmp(ip, "*") == 0) {
|
||||
snprintf(buf, sizeof(buf), "::");
|
||||
ip = (const char *) &buf[0];
|
||||
}
|
||||
} else if (strcasecmp(ip, "*") == 0) {
|
||||
snprintf(buf, sizeof(buf), "0.0.0.0");
|
||||
ip = (const char *) &buf[0];
|
||||
}
|
||||
|
||||
snprintf(portnum, sizeof portnum, "%d", port);
|
||||
memset(&hints, 0, sizeof hints);
|
||||
hints.ai_family = PF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_flags = AI_NUMERICSERV;
|
||||
hints.ai_flags |= AI_PASSIVE;
|
||||
hints.ai_flags |= AI_NUMERICHOST;
|
||||
rc = getaddrinfo(ip, portnum, &hints, &res0);
|
||||
if (rc != 0) {
|
||||
SPDK_ERRLOG("getaddrinfo() failed (errno=%d)\n", errno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* try listen */
|
||||
sock = -1;
|
||||
for (res = res0; res != NULL; res = res->ai_next) {
|
||||
retry:
|
||||
sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
|
||||
if (sock < 0) {
|
||||
/* error */
|
||||
continue;
|
||||
}
|
||||
rc = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &val, sizeof val);
|
||||
if (rc != 0) {
|
||||
close(sock);
|
||||
/* error */
|
||||
continue;
|
||||
}
|
||||
rc = setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &val, sizeof val);
|
||||
if (rc != 0) {
|
||||
close(sock);
|
||||
/* error */
|
||||
continue;
|
||||
}
|
||||
|
||||
if (type == SPDK_SOCK_CREATE_LISTEN) {
|
||||
rc = bind(sock, res->ai_addr, res->ai_addrlen);
|
||||
if (rc != 0) {
|
||||
SPDK_ERRLOG("bind() failed, errno = %d\n", errno);
|
||||
switch (errno) {
|
||||
case EINTR:
|
||||
/* interrupted? */
|
||||
close(sock);
|
||||
goto retry;
|
||||
case EADDRNOTAVAIL:
|
||||
SPDK_ERRLOG("IP address %s not available. "
|
||||
"Verify IP address in config file "
|
||||
"and make sure unbind script is "
|
||||
"run before starting spdk app.\n", ip);
|
||||
/* fallthrough */
|
||||
default:
|
||||
/* try next family */
|
||||
close(sock);
|
||||
sock = -1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
/* bind OK */
|
||||
rc = listen(sock, 512);
|
||||
if (rc != 0) {
|
||||
SPDK_ERRLOG("listen() failed, errno = %d\n", errno);
|
||||
close(sock);
|
||||
sock = -1;
|
||||
break;
|
||||
}
|
||||
} else if (type == SPDK_SOCK_CREATE_CONNECT) {
|
||||
rc = connect(sock, res->ai_addr, res->ai_addrlen);
|
||||
if (rc != 0) {
|
||||
SPDK_ERRLOG("connect() failed, errno = %d\n", errno);
|
||||
/* try next family */
|
||||
close(sock);
|
||||
sock = -1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
nonblock = 1;
|
||||
rc = ioctl(sock, FIONBIO, &nonblock);
|
||||
if (rc != 0) {
|
||||
SPDK_ERRLOG("ioctl(FIONBIO) failed\n");
|
||||
close(sock);
|
||||
sock = -1;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
freeaddrinfo(res0);
|
||||
|
||||
if (sock < 0) {
|
||||
return -1;
|
||||
}
|
||||
return sock;
|
||||
}
|
||||
|
||||
int
|
||||
spdk_sock_listen(const char *ip, int port)
|
||||
{
|
||||
return spdk_sock_create(ip, port, SPDK_SOCK_CREATE_LISTEN);
|
||||
}
|
||||
|
||||
int
|
||||
spdk_sock_connect(const char *ip, int port)
|
||||
{
|
||||
return spdk_sock_create(ip, port, SPDK_SOCK_CREATE_CONNECT);
|
||||
}
|
||||
|
||||
int
|
||||
spdk_sock_accept(int sock)
|
||||
{
|
||||
struct sockaddr_storage sa;
|
||||
socklen_t salen;
|
||||
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
salen = sizeof(sa);
|
||||
return accept(sock, (struct sockaddr *)&sa, &salen);
|
||||
}
|
||||
|
||||
int
|
||||
spdk_sock_close(int sock)
|
||||
{
|
||||
return close(sock);
|
||||
}
|
||||
|
||||
ssize_t
|
||||
spdk_sock_recv(int sock, void *buf, size_t len)
|
||||
{
|
||||
return recv(sock, buf, len, MSG_DONTWAIT);
|
||||
}
|
||||
|
||||
ssize_t
|
||||
spdk_sock_writev(int sock, struct iovec *iov, int iovcnt)
|
||||
{
|
||||
return writev(sock, iov, iovcnt);
|
||||
}
|
||||
|
||||
int
|
||||
spdk_sock_set_recvlowat(int s, int nbytes)
|
||||
{
|
||||
int val;
|
||||
int rc;
|
||||
|
||||
val = nbytes;
|
||||
rc = setsockopt(s, SOL_SOCKET, SO_RCVLOWAT, &val, sizeof val);
|
||||
if (rc != 0)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
spdk_sock_set_recvbuf(int sock, int sz)
|
||||
{
|
||||
return setsockopt(sock, SOL_SOCKET, SO_RCVBUF,
|
||||
&sz, sizeof(sz));
|
||||
}
|
||||
|
||||
int
|
||||
spdk_sock_set_sendbuf(int sock, int sz)
|
||||
{
|
||||
return setsockopt(sock, SOL_SOCKET, SO_SNDBUF,
|
||||
&sz, sizeof(sz));
|
||||
}
|
||||
|
||||
bool
|
||||
spdk_sock_is_ipv6(int sock)
|
||||
{
|
||||
struct sockaddr_storage sa;
|
||||
socklen_t salen;
|
||||
int rc;
|
||||
|
||||
memset(&sa, 0, sizeof sa);
|
||||
salen = sizeof sa;
|
||||
rc = getsockname(sock, (struct sockaddr *) &sa, &salen);
|
||||
if (rc != 0) {
|
||||
SPDK_ERRLOG("getsockname() failed (errno=%d)\n", errno);
|
||||
return false;
|
||||
}
|
||||
|
||||
return (sa.ss_family == AF_INET6);
|
||||
}
|
||||
|
||||
bool
|
||||
spdk_sock_is_ipv4(int sock)
|
||||
{
|
||||
struct sockaddr_storage sa;
|
||||
socklen_t salen;
|
||||
int rc;
|
||||
|
||||
memset(&sa, 0, sizeof sa);
|
||||
salen = sizeof sa;
|
||||
rc = getsockname(sock, (struct sockaddr *) &sa, &salen);
|
||||
if (rc != 0) {
|
||||
SPDK_ERRLOG("getsockname() failed (errno=%d)\n", errno);
|
||||
return false;
|
||||
}
|
||||
|
||||
return (sa.ss_family == AF_INET);
|
||||
}
|
Loading…
Reference in New Issue
Block a user