Memory for socket structure is allocated in the selected net framework but freed in the libsocket on the higher level. This patch moves memory free to the net framework implementation. Change-Id: Ia3d4e1553a858a38beb390986e9af105778c12c7 Signed-off-by: Tomasz Kulasek <tomaszx.kulasek@intel.com> Reviewed-on: https://review.gerrithub.io/421587 Tested-by: SPDK CI Jenkins <sys_sgci@intel.com> Chandler-Test-Pool: SPDK Automated Test System <sys_sgsw@intel.com> Reviewed-by: Jim Harris <james.r.harris@intel.com> Reviewed-by: Tomasz Zawadzki <tomasz.zawadzki@intel.com> Reviewed-by: Ben Walker <benjamin.walker@intel.com>
647 lines
14 KiB
C
647 lines
14 KiB
C
/*-
|
|
* 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/stdinc.h"
|
|
|
|
#include "spdk/log.h"
|
|
#include "spdk/sock.h"
|
|
#include "spdk/net.h"
|
|
#include "spdk/string.h"
|
|
#include "spdk_internal/sock.h"
|
|
#include <vcl/vppcom.h>
|
|
|
|
#define MAX_TMPBUF 1024
|
|
#define PORTNUMLEN 32
|
|
|
|
static bool g_vpp_initialized = false;
|
|
|
|
struct spdk_vpp_sock {
|
|
struct spdk_sock base;
|
|
int fd;
|
|
};
|
|
|
|
struct spdk_vpp_sock_group_impl {
|
|
struct spdk_sock_group_impl base;
|
|
int fd;
|
|
};
|
|
|
|
static int
|
|
get_addr_str(struct sockaddr *sa, char *host, size_t hlen)
|
|
{
|
|
const char *result = NULL;
|
|
|
|
if (sa == NULL || host == NULL) {
|
|
return -1;
|
|
}
|
|
|
|
if (sa->sa_family == AF_INET) {
|
|
result = inet_ntop(AF_INET, &(((struct sockaddr_in *)sa)->sin_addr),
|
|
host, hlen);
|
|
} else {
|
|
result = inet_ntop(AF_INET6, &(((struct sockaddr_in6 *)sa)->sin6_addr),
|
|
host, hlen);
|
|
}
|
|
|
|
if (result == NULL) {
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
#define __vpp_sock(sock) (struct spdk_vpp_sock *)sock
|
|
#define __vpp_group_impl(group) (struct spdk_vpp_sock_group_impl *)group
|
|
|
|
static inline void
|
|
vcom_socket_copy_ep_to_sockaddr(struct sockaddr *addr, socklen_t *len, vppcom_endpt_t *ep)
|
|
{
|
|
int sa_len, copy_len;
|
|
|
|
assert(ep->vrf == VPPCOM_VRF_DEFAULT);
|
|
|
|
if (ep->is_ip4 == VPPCOM_IS_IP4) {
|
|
addr->sa_family = AF_INET;
|
|
((struct sockaddr_in *) addr)->sin_port = ep->port;
|
|
if (*len > sizeof(struct sockaddr_in)) {
|
|
*len = sizeof(struct sockaddr_in);
|
|
}
|
|
sa_len = sizeof(struct sockaddr_in) - sizeof(struct in_addr);
|
|
copy_len = *len - sa_len;
|
|
if (copy_len > 0) {
|
|
memcpy(&((struct sockaddr_in *) addr)->sin_addr, ep->ip, copy_len);
|
|
}
|
|
} else {
|
|
addr->sa_family = AF_INET6;
|
|
((struct sockaddr_in6 *) addr)->sin6_port = ep->port;
|
|
if (*len > sizeof(struct sockaddr_in6)) {
|
|
*len = sizeof(struct sockaddr_in6);
|
|
}
|
|
sa_len = sizeof(struct sockaddr_in6) - sizeof(struct in6_addr);
|
|
copy_len = *len - sa_len;
|
|
if (copy_len > 0) {
|
|
memcpy(&((struct sockaddr_in6 *) addr)->sin6_addr, ep->ip, copy_len);
|
|
}
|
|
}
|
|
}
|
|
|
|
static int
|
|
getsockname_vpp(int fd, struct sockaddr *addr, socklen_t *len)
|
|
{
|
|
vppcom_endpt_t ep;
|
|
uint32_t size = sizeof(ep);
|
|
uint8_t addr_buf[sizeof(struct in6_addr)];
|
|
int rc;
|
|
|
|
if (!addr || !len) {
|
|
return -EFAULT;
|
|
}
|
|
|
|
ep.ip = addr_buf;
|
|
|
|
rc = vppcom_session_attr(fd, VPPCOM_ATTR_GET_LCL_ADDR, &ep, &size);
|
|
if (rc == VPPCOM_OK) {
|
|
vcom_socket_copy_ep_to_sockaddr(addr, len, &ep);
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
static int
|
|
getpeername_vpp(int sock, struct sockaddr *addr, socklen_t *len)
|
|
{
|
|
vppcom_endpt_t ep;
|
|
uint32_t size = sizeof(ep);
|
|
uint8_t addr_buf[sizeof(struct in6_addr)];
|
|
int rc;
|
|
|
|
if (!addr || !len) {
|
|
return -EFAULT;
|
|
}
|
|
|
|
ep.ip = addr_buf;
|
|
|
|
rc = vppcom_session_attr(sock, VPPCOM_ATTR_GET_PEER_ADDR, &ep, &size);
|
|
if (rc == VPPCOM_OK) {
|
|
vcom_socket_copy_ep_to_sockaddr(addr, len, &ep);
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
static int
|
|
spdk_vpp_sock_getaddr(struct spdk_sock *_sock, char *saddr, int slen, char *caddr, int clen)
|
|
{
|
|
struct spdk_vpp_sock *sock = __vpp_sock(_sock);
|
|
struct sockaddr sa;
|
|
socklen_t salen;
|
|
int rc;
|
|
|
|
assert(sock != NULL);
|
|
assert(g_vpp_initialized);
|
|
|
|
memset(&sa, 0, sizeof(sa));
|
|
salen = sizeof(sa);
|
|
rc = getsockname_vpp(sock->fd, &sa, &salen);
|
|
if (rc != 0) {
|
|
errno = -rc;
|
|
SPDK_ERRLOG("getsockname_vpp() failed (errno=%d)\n", errno);
|
|
return -1;
|
|
}
|
|
|
|
rc = get_addr_str(&sa, saddr, slen);
|
|
if (rc != 0) {
|
|
/* Errno already set by get_addr_str() */
|
|
SPDK_ERRLOG("get_addr_str() failed (errno=%d)\n", errno);
|
|
return -1;
|
|
}
|
|
|
|
memset(&sa, 0, sizeof(sa));
|
|
salen = sizeof(sa);
|
|
rc = getpeername_vpp(sock->fd, &sa, &salen);
|
|
if (rc != 0) {
|
|
errno = -rc;
|
|
SPDK_ERRLOG("getpeername_vpp() failed (errno=%d)\n", errno);
|
|
return -1;
|
|
}
|
|
|
|
rc = get_addr_str(&sa, caddr, clen);
|
|
if (rc != 0) {
|
|
/* Errno already set by get_addr_str() */
|
|
SPDK_ERRLOG("get_addr_str() failed (errno=%d)\n", errno);
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
enum spdk_vpp_create_type {
|
|
SPDK_SOCK_CREATE_LISTEN,
|
|
SPDK_SOCK_CREATE_CONNECT,
|
|
};
|
|
|
|
static struct spdk_sock *
|
|
spdk_vpp_sock_create(const char *ip, int port, enum spdk_vpp_create_type type)
|
|
{
|
|
struct spdk_vpp_sock *sock;
|
|
int fd, rc;
|
|
vppcom_endpt_t endpt;
|
|
uint8_t addr_buf[sizeof(struct in6_addr)];
|
|
|
|
if (ip == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
/* Check address family */
|
|
if (inet_pton(AF_INET, ip, &addr_buf)) {
|
|
endpt.is_ip4 = VPPCOM_IS_IP4;
|
|
} else if (inet_pton(AF_INET6, ip, &addr_buf)) {
|
|
endpt.is_ip4 = VPPCOM_IS_IP6;
|
|
} else {
|
|
SPDK_ERRLOG("IP address with invalid format\n");
|
|
return NULL;
|
|
}
|
|
endpt.vrf = VPPCOM_VRF_DEFAULT;
|
|
endpt.ip = (uint8_t *)&addr_buf;
|
|
endpt.port = htons(port);
|
|
|
|
fd = vppcom_session_create(VPPCOM_VRF_DEFAULT, VPPCOM_PROTO_TCP, 1 /* is_nonblocking */);
|
|
if (fd < 0) {
|
|
errno = -fd;
|
|
SPDK_ERRLOG("vppcom_session_create() failed, errno = %d\n", errno);
|
|
return NULL;
|
|
}
|
|
|
|
if (type == SPDK_SOCK_CREATE_LISTEN) {
|
|
rc = vppcom_session_bind(fd, &endpt);
|
|
if (rc != VPPCOM_OK) {
|
|
errno = -rc;
|
|
SPDK_ERRLOG("vppcom_session_bind() failed, errno = %d\n", errno);
|
|
vppcom_session_close(fd);
|
|
return NULL;
|
|
}
|
|
|
|
rc = vppcom_session_listen(fd, 512);
|
|
if (rc != VPPCOM_OK) {
|
|
errno = -rc;
|
|
SPDK_ERRLOG("vppcom_session_listen() failed, errno = %d\n", errno);
|
|
vppcom_session_close(fd);
|
|
return NULL;
|
|
}
|
|
} else if (type == SPDK_SOCK_CREATE_CONNECT) {
|
|
rc = vppcom_session_connect(fd, &endpt);
|
|
if (rc != VPPCOM_OK) {
|
|
errno = -rc;
|
|
SPDK_ERRLOG("vppcom_session_connect() failed, errno = %d\n", errno);
|
|
vppcom_session_close(fd);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
sock = calloc(1, sizeof(*sock));
|
|
if (sock == NULL) {
|
|
errno = -ENOMEM;
|
|
SPDK_ERRLOG("sock allocation failed\n");
|
|
vppcom_session_close(fd);
|
|
return NULL;
|
|
}
|
|
|
|
sock->fd = fd;
|
|
return &sock->base;
|
|
}
|
|
|
|
static struct spdk_sock *
|
|
spdk_vpp_sock_listen(const char *ip, int port)
|
|
{
|
|
if (!g_vpp_initialized) {
|
|
return NULL;
|
|
}
|
|
|
|
return spdk_vpp_sock_create(ip, port, SPDK_SOCK_CREATE_LISTEN);
|
|
}
|
|
|
|
static struct spdk_sock *
|
|
spdk_vpp_sock_connect(const char *ip, int port)
|
|
{
|
|
if (!g_vpp_initialized) {
|
|
return NULL;
|
|
}
|
|
|
|
return spdk_vpp_sock_create(ip, port, SPDK_SOCK_CREATE_CONNECT);
|
|
}
|
|
|
|
static struct spdk_sock *
|
|
spdk_vpp_sock_accept(struct spdk_sock *_sock)
|
|
{
|
|
struct spdk_vpp_sock *sock = __vpp_sock(_sock);
|
|
vppcom_endpt_t endpt;
|
|
uint8_t ip[16];
|
|
int rc;
|
|
struct spdk_vpp_sock *new_sock;
|
|
double wait_time = -1.0;
|
|
|
|
endpt.ip = ip;
|
|
|
|
assert(sock != NULL);
|
|
assert(g_vpp_initialized);
|
|
|
|
rc = vppcom_session_accept(sock->fd, &endpt, O_NONBLOCK, wait_time);
|
|
if (rc < 0) {
|
|
errno = -rc;
|
|
return NULL;
|
|
}
|
|
|
|
new_sock = calloc(1, sizeof(*sock));
|
|
if (new_sock == NULL) {
|
|
SPDK_ERRLOG("sock allocation failed\n");
|
|
vppcom_session_close(rc);
|
|
return NULL;
|
|
}
|
|
|
|
new_sock->fd = rc;
|
|
return &new_sock->base;
|
|
}
|
|
|
|
static int
|
|
spdk_vpp_sock_close(struct spdk_sock *_sock)
|
|
{
|
|
struct spdk_vpp_sock *sock = __vpp_sock(_sock);
|
|
int rc;
|
|
|
|
assert(sock != NULL);
|
|
assert(g_vpp_initialized);
|
|
|
|
rc = vppcom_session_close(sock->fd);
|
|
if (rc != VPPCOM_OK) {
|
|
errno = -rc;
|
|
return -1;
|
|
}
|
|
free(sock);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static ssize_t
|
|
spdk_vpp_sock_recv(struct spdk_sock *_sock, void *buf, size_t len)
|
|
{
|
|
struct spdk_vpp_sock *sock = __vpp_sock(_sock);
|
|
int rc;
|
|
|
|
assert(sock != NULL);
|
|
assert(g_vpp_initialized);
|
|
|
|
rc = vppcom_session_read(sock->fd, buf, len);
|
|
if (rc < 0) {
|
|
errno = -rc;
|
|
return -1;
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
static ssize_t
|
|
spdk_vpp_sock_writev(struct spdk_sock *_sock, struct iovec *iov, int iovcnt)
|
|
{
|
|
struct spdk_vpp_sock *sock = __vpp_sock(_sock);
|
|
ssize_t total = 0;
|
|
int i, rc;
|
|
|
|
assert(sock != NULL);
|
|
assert(g_vpp_initialized);
|
|
|
|
for (i = 0; i < iovcnt; ++i) {
|
|
rc = vppcom_session_write(sock->fd, iov[i].iov_base, iov[i].iov_len);
|
|
if (rc < 0) {
|
|
if (total > 0) {
|
|
break;
|
|
} else {
|
|
errno = -rc;
|
|
return -1;
|
|
}
|
|
} else {
|
|
total += rc;
|
|
}
|
|
}
|
|
return total;
|
|
}
|
|
|
|
|
|
/*
|
|
* TODO: Check if there are similar parameters to configure in VPP
|
|
* to three below.
|
|
*/
|
|
static int
|
|
spdk_vpp_sock_set_recvlowat(struct spdk_sock *_sock, int nbytes)
|
|
{
|
|
assert(g_vpp_initialized);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
spdk_vpp_sock_set_recvbuf(struct spdk_sock *_sock, int sz)
|
|
{
|
|
assert(g_vpp_initialized);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
spdk_vpp_sock_set_sendbuf(struct spdk_sock *_sock, int sz)
|
|
{
|
|
assert(g_vpp_initialized);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static bool
|
|
spdk_vpp_sock_is_ipv6(struct spdk_sock *_sock)
|
|
{
|
|
struct spdk_vpp_sock *sock = __vpp_sock(_sock);
|
|
vppcom_endpt_t ep;
|
|
uint32_t size = sizeof(ep);
|
|
uint8_t addr_buf[sizeof(struct in6_addr)];
|
|
int rc;
|
|
|
|
assert(sock != NULL);
|
|
assert(g_vpp_initialized);
|
|
|
|
ep.ip = addr_buf;
|
|
|
|
rc = vppcom_session_attr(sock->fd, VPPCOM_ATTR_GET_LCL_ADDR, &ep, &size);
|
|
if (rc != VPPCOM_OK) {
|
|
errno = -rc;
|
|
return false;
|
|
}
|
|
|
|
return (ep.is_ip4 == VPPCOM_IS_IP6);
|
|
}
|
|
|
|
static bool
|
|
spdk_vpp_sock_is_ipv4(struct spdk_sock *_sock)
|
|
{
|
|
struct spdk_vpp_sock *sock = __vpp_sock(_sock);
|
|
vppcom_endpt_t ep;
|
|
uint32_t size = sizeof(ep);
|
|
uint8_t addr_buf[sizeof(struct in6_addr)];
|
|
int rc;
|
|
|
|
assert(sock != NULL);
|
|
assert(g_vpp_initialized);
|
|
|
|
ep.ip = addr_buf;
|
|
|
|
rc = vppcom_session_attr(sock->fd, VPPCOM_ATTR_GET_LCL_ADDR, &ep, &size);
|
|
if (rc != VPPCOM_OK) {
|
|
errno = -rc;
|
|
return false;
|
|
}
|
|
|
|
return (ep.is_ip4 == VPPCOM_IS_IP4);
|
|
}
|
|
|
|
static struct spdk_sock_group_impl *
|
|
spdk_vpp_sock_group_impl_create(void)
|
|
{
|
|
struct spdk_vpp_sock_group_impl *group_impl;
|
|
int fd;
|
|
|
|
if (!g_vpp_initialized) {
|
|
return NULL;
|
|
}
|
|
|
|
group_impl = calloc(1, sizeof(*group_impl));
|
|
if (group_impl == NULL) {
|
|
SPDK_ERRLOG("sock_group allocation failed\n");
|
|
return NULL;
|
|
}
|
|
|
|
fd = vppcom_epoll_create();
|
|
if (fd < 0) {
|
|
free(group_impl);
|
|
return NULL;
|
|
}
|
|
|
|
group_impl->fd = fd;
|
|
|
|
return &group_impl->base;
|
|
}
|
|
|
|
static int
|
|
spdk_vpp_sock_group_impl_add_sock(struct spdk_sock_group_impl *_group, struct spdk_sock *_sock)
|
|
{
|
|
struct spdk_vpp_sock_group_impl *group = __vpp_group_impl(_group);
|
|
struct spdk_vpp_sock *sock = __vpp_sock(_sock);
|
|
int rc;
|
|
struct epoll_event event;
|
|
|
|
assert(sock != NULL);
|
|
assert(group != NULL);
|
|
assert(g_vpp_initialized);
|
|
|
|
event.events = EPOLLIN;
|
|
event.data.ptr = sock;
|
|
|
|
rc = vppcom_epoll_ctl(group->fd, EPOLL_CTL_ADD, sock->fd, &event);
|
|
if (rc != VPPCOM_OK) {
|
|
errno = -rc;
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
spdk_vpp_sock_group_impl_remove_sock(struct spdk_sock_group_impl *_group, struct spdk_sock *_sock)
|
|
{
|
|
struct spdk_vpp_sock_group_impl *group = __vpp_group_impl(_group);
|
|
struct spdk_vpp_sock *sock = __vpp_sock(_sock);
|
|
int rc;
|
|
struct epoll_event event;
|
|
|
|
assert(sock != NULL);
|
|
assert(group != NULL);
|
|
assert(g_vpp_initialized);
|
|
|
|
rc = vppcom_epoll_ctl(group->fd, EPOLL_CTL_DEL, sock->fd, &event);
|
|
if (rc != VPPCOM_OK) {
|
|
errno = -rc;
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
spdk_vpp_sock_group_impl_poll(struct spdk_sock_group_impl *_group, int max_events,
|
|
struct spdk_sock **socks)
|
|
{
|
|
struct spdk_vpp_sock_group_impl *group = __vpp_group_impl(_group);
|
|
int num_events, i;
|
|
struct epoll_event events[MAX_EVENTS_PER_POLL];
|
|
|
|
assert(group != NULL);
|
|
assert(socks != NULL);
|
|
assert(g_vpp_initialized);
|
|
|
|
num_events = vppcom_epoll_wait(group->fd, events, max_events, 0);
|
|
if (num_events < 0) {
|
|
errno = -num_events;
|
|
return -1;
|
|
}
|
|
|
|
for (i = 0; i < num_events; i++) {
|
|
socks[i] = events[i].data.ptr;
|
|
}
|
|
|
|
return num_events;
|
|
}
|
|
|
|
static int
|
|
spdk_vpp_sock_group_impl_close(struct spdk_sock_group_impl *_group)
|
|
{
|
|
struct spdk_vpp_sock_group_impl *group = __vpp_group_impl(_group);
|
|
int rc;
|
|
|
|
assert(group != NULL);
|
|
assert(g_vpp_initialized);
|
|
|
|
rc = vppcom_session_close(group->fd);
|
|
if (rc != VPPCOM_OK) {
|
|
errno = -rc;
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static struct spdk_net_impl g_vpp_net_impl = {
|
|
.name = "vpp",
|
|
.getaddr = spdk_vpp_sock_getaddr,
|
|
.connect = spdk_vpp_sock_connect,
|
|
.listen = spdk_vpp_sock_listen,
|
|
.accept = spdk_vpp_sock_accept,
|
|
.close = spdk_vpp_sock_close,
|
|
.recv = spdk_vpp_sock_recv,
|
|
.writev = spdk_vpp_sock_writev,
|
|
.set_recvlowat = spdk_vpp_sock_set_recvlowat,
|
|
.set_recvbuf = spdk_vpp_sock_set_recvbuf,
|
|
.set_sendbuf = spdk_vpp_sock_set_sendbuf,
|
|
.is_ipv6 = spdk_vpp_sock_is_ipv6,
|
|
.is_ipv4 = spdk_vpp_sock_is_ipv4,
|
|
.group_impl_create = spdk_vpp_sock_group_impl_create,
|
|
.group_impl_add_sock = spdk_vpp_sock_group_impl_add_sock,
|
|
.group_impl_remove_sock = spdk_vpp_sock_group_impl_remove_sock,
|
|
.group_impl_poll = spdk_vpp_sock_group_impl_poll,
|
|
.group_impl_close = spdk_vpp_sock_group_impl_close,
|
|
};
|
|
|
|
SPDK_NET_IMPL_REGISTER(vpp, &g_vpp_net_impl);
|
|
|
|
static int
|
|
spdk_vpp_net_framework_init(void)
|
|
{
|
|
int rc;
|
|
char *app_name;
|
|
|
|
app_name = spdk_sprintf_alloc("SPDK_%d", getpid());
|
|
if (app_name == NULL) {
|
|
SPDK_ERRLOG("Cannot alloc memory for SPDK app name\n");
|
|
return -ENOMEM;
|
|
}
|
|
|
|
rc = vppcom_app_create(app_name);
|
|
if (rc == 0) {
|
|
g_vpp_initialized = true;
|
|
}
|
|
|
|
free(app_name);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void
|
|
spdk_vpp_net_framework_fini(void)
|
|
{
|
|
if (g_vpp_initialized) {
|
|
vppcom_app_destroy();
|
|
}
|
|
}
|
|
|
|
static struct spdk_net_framework g_vpp_net_framework = {
|
|
.name = "vpp",
|
|
.init = spdk_vpp_net_framework_init,
|
|
.fini = spdk_vpp_net_framework_fini,
|
|
};
|
|
|
|
SPDK_NET_FRAMEWORK_REGISTER(vpp, &g_vpp_net_framework);
|