vcl: ldp support for ip_pktinfo

Type: improvement

Signed-off-by: Florin Coras <fcoras@cisco.com>
Change-Id: I3c15f38a4a3f5e92506059277948e7fca9cd8b55
This commit is contained in:
Florin Coras
2023-02-07 17:36:17 -08:00
committed by Dave Barach
parent 7c7231fc30
commit eff5f7aea8
4 changed files with 243 additions and 85 deletions

View File

@ -26,7 +26,7 @@
#include <stdarg.h>
#include <sys/resource.h>
#include <netinet/tcp.h>
#include <linux/udp.h>
#include <netinet/udp.h>
#include <vcl/ldp_socket_wrapper.h>
#include <vcl/ldp.h>
@ -1556,17 +1556,14 @@ __recv_chk (int fd, void *buf, size_t n, size_t buflen, int flags)
static inline int
ldp_vls_sendo (vls_handle_t vlsh, const void *buf, size_t n,
vppcom_endpt_tlv_t *ep_tlv, int flags,
vppcom_endpt_tlv_t *app_tlvs, int flags,
__CONST_SOCKADDR_ARG _addr, socklen_t addr_len)
{
const struct sockaddr *addr = SOCKADDR_GET_SA (_addr);
vppcom_endpt_t *ep = 0;
vppcom_endpt_t _ep;
if (ep_tlv)
{
_ep.app_data = *ep_tlv;
}
_ep.app_tlvs = app_tlvs;
if (addr)
{
@ -1679,6 +1676,97 @@ recvfrom (int fd, void *__restrict buf, size_t n, int flags,
return size;
}
static int
ldp_parse_cmsg (vls_handle_t vlsh, const struct msghdr *msg,
vppcom_endpt_tlv_t **app_tlvs)
{
uint8_t *ad, *at = (uint8_t *) *app_tlvs;
vppcom_endpt_tlv_t *adh;
struct in_pktinfo *pi;
struct cmsghdr *cmsg;
cmsg = CMSG_FIRSTHDR (msg);
while (cmsg != NULL)
{
switch (cmsg->cmsg_level)
{
case SOL_UDP:
switch (cmsg->cmsg_type)
{
case UDP_SEGMENT:
vec_add2 (at, adh, sizeof (*adh));
adh->data_type = VCL_UDP_SEGMENT;
adh->data_len = sizeof (uint16_t);
vec_add2 (at, ad, sizeof (uint16_t));
*(uint16_t *) ad = *(uint16_t *) CMSG_DATA (cmsg);
break;
default:
LDBG (1, "SOL_UDP cmsg_type %u not supported", cmsg->cmsg_type);
break;
}
break;
case SOL_IP:
switch (cmsg->cmsg_type)
{
case IP_PKTINFO:
vec_add2 (at, adh, sizeof (*adh));
adh->data_type = VCL_IP_PKTINFO;
adh->data_len = sizeof (struct in_addr);
vec_add2 (at, ad, sizeof (struct in_addr));
pi = (void *) CMSG_DATA (cmsg);
clib_memcpy_fast (ad, &pi->ipi_spec_dst,
sizeof (struct in_addr));
break;
default:
LDBG (1, "SOL_IP cmsg_type %u not supported", cmsg->cmsg_type);
break;
}
break;
default:
LDBG (1, "cmsg_level %u not supported", cmsg->cmsg_level);
break;
}
cmsg = CMSG_NXTHDR ((struct msghdr *) msg, cmsg);
}
*app_tlvs = (vppcom_endpt_tlv_t *) at;
return 0;
}
static int
ldp_make_cmsg (vls_handle_t vlsh, struct msghdr *msg)
{
u32 optval, optlen = sizeof (optval);
struct cmsghdr *cmsg;
cmsg = CMSG_FIRSTHDR (msg);
if (!vls_attr (vlsh, VPPCOM_ATTR_GET_IP_PKTINFO, (void *) &optval, &optlen))
return 0;
if (optval)
{
vppcom_endpt_t ep;
u8 addr_buf[sizeof (struct in_addr)];
u32 size = sizeof (ep);
ep.ip = addr_buf;
if (!vls_attr (vlsh, VPPCOM_ATTR_GET_LCL_ADDR, &ep, &size))
{
struct in_pktinfo pi = {};
clib_memcpy (&pi.ipi_addr, ep.ip, sizeof (struct in_addr));
cmsg->cmsg_level = SOL_IP;
cmsg->cmsg_type = IP_PKTINFO;
cmsg->cmsg_len = CMSG_LEN (sizeof (pi));
clib_memcpy (CMSG_DATA (cmsg), &pi, sizeof (pi));
}
}
return 0;
}
ssize_t
sendmsg (int fd, const struct msghdr * msg, int flags)
{
@ -1690,29 +1778,17 @@ sendmsg (int fd, const struct msghdr * msg, int flags)
vlsh = ldp_fd_to_vlsh (fd);
if (vlsh != VLS_INVALID_HANDLE)
{
vppcom_endpt_tlv_t *app_tlvs = 0;
struct iovec *iov = msg->msg_iov;
ssize_t total = 0;
int i, rv = 0;
struct cmsghdr *cmsg;
uint16_t *valp;
vppcom_endpt_tlv_t _app_data;
vppcom_endpt_tlv_t *p_app_data = NULL;
cmsg = CMSG_FIRSTHDR (msg);
if (cmsg && cmsg->cmsg_type == UDP_SEGMENT)
{
p_app_data = &_app_data;
valp = (void *) CMSG_DATA (cmsg);
p_app_data->data_type = VCL_UDP_SEGMENT;
p_app_data->data_len = sizeof (*valp);
p_app_data->value = *valp;
}
ldp_parse_cmsg (vlsh, msg, &app_tlvs);
for (i = 0; i < msg->msg_iovlen; ++i)
{
rv =
ldp_vls_sendo (vlsh, iov[i].iov_base, iov[i].iov_len, p_app_data,
flags, msg->msg_name, msg->msg_namelen);
rv = ldp_vls_sendo (vlsh, iov[i].iov_base, iov[i].iov_len, app_tlvs,
flags, msg->msg_name, msg->msg_namelen);
if (rv < 0)
break;
else
@ -1723,6 +1799,8 @@ sendmsg (int fd, const struct msghdr * msg, int flags)
}
}
vec_free (app_tlvs);
if (rv < 0 && total == 0)
{
errno = -rv;
@ -1828,7 +1906,11 @@ recvmsg (int fd, struct msghdr * msg, int flags)
size = -1;
}
else
size = total;
{
if (msg->msg_controllen)
ldp_make_cmsg (vlsh, msg);
size = total;
}
}
else
{
@ -2114,6 +2196,21 @@ setsockopt (int fd, int level, int optname,
break;
}
break;
case SOL_IP:
switch (optname)
{
case IP_PKTINFO:
rv = vls_attr (vlsh, VPPCOM_ATTR_SET_IP_PKTINFO, (void *) optval,
&optlen);
break;
default:
LDBG (0,
"ERROR: fd %d: setsockopt SOL_IP: vlsh %u optname %d"
"unsupported!",
fd, vlsh, optname);
break;
}
break;
default:
break;
}

View File

@ -118,16 +118,17 @@ typedef enum
VCL_SESS_ATTR_CUT_THRU,
VCL_SESS_ATTR_VEP,
VCL_SESS_ATTR_VEP_SESSION,
VCL_SESS_ATTR_LISTEN, // SOL_SOCKET,SO_ACCEPTCONN
VCL_SESS_ATTR_NONBLOCK, // fcntl,O_NONBLOCK
VCL_SESS_ATTR_REUSEADDR, // SOL_SOCKET,SO_REUSEADDR
VCL_SESS_ATTR_REUSEPORT, // SOL_SOCKET,SO_REUSEPORT
VCL_SESS_ATTR_BROADCAST, // SOL_SOCKET,SO_BROADCAST
VCL_SESS_ATTR_V6ONLY, // SOL_TCP,IPV6_V6ONLY
VCL_SESS_ATTR_KEEPALIVE, // SOL_SOCKET,SO_KEEPALIVE
VCL_SESS_ATTR_TCP_NODELAY, // SOL_TCP,TCP_NODELAY
VCL_SESS_ATTR_TCP_KEEPIDLE, // SOL_TCP,TCP_KEEPIDLE
VCL_SESS_ATTR_TCP_KEEPINTVL, // SOL_TCP,TCP_KEEPINTVL
VCL_SESS_ATTR_LISTEN, // SOL_SOCKET,SO_ACCEPTCONN
VCL_SESS_ATTR_NONBLOCK, // fcntl,O_NONBLOCK
VCL_SESS_ATTR_REUSEADDR, // SOL_SOCKET,SO_REUSEADDR
VCL_SESS_ATTR_REUSEPORT, // SOL_SOCKET,SO_REUSEPORT
VCL_SESS_ATTR_BROADCAST, // SOL_SOCKET,SO_BROADCAST
VCL_SESS_ATTR_V6ONLY, // SOL_TCP,IPV6_V6ONLY
VCL_SESS_ATTR_KEEPALIVE, // SOL_SOCKET,SO_KEEPALIVE
VCL_SESS_ATTR_TCP_NODELAY, // SOL_TCP,TCP_NODELAY
VCL_SESS_ATTR_TCP_KEEPIDLE, // SOL_TCP,TCP_KEEPIDLE
VCL_SESS_ATTR_TCP_KEEPINTVL, // SOL_TCP,TCP_KEEPINTVL
VCL_SESS_ATTR_IP_PKTINFO, /* IPPROTO_IP, IP_PKTINFO */
VCL_SESS_ATTR_MAX
} vppcom_session_attr_t;
@ -165,6 +166,7 @@ typedef struct vcl_session_
u32 attributes; /**< see @ref vppcom_session_attr_t */
int libc_epfd;
u32 vrf;
u16 gso_size;
u32 sndbuf_size; // VPP-TBD: Hack until support setsockopt(SO_SNDBUF)
u32 rcvbuf_size; // VPP-TBD: Hack until support setsockopt(SO_RCVBUF)

View File

@ -2228,7 +2228,7 @@ vcl_fifo_is_writeable (svm_fifo_t * f, u32 len, u8 is_dgram)
always_inline int
vppcom_session_write_inline (vcl_worker_t *wrk, vcl_session_t *s, void *buf,
size_t n, u16 gso_size, u8 is_flush, u8 is_dgram)
size_t n, u8 is_flush, u8 is_dgram)
{
int n_write, is_nonblocking;
session_evt_type_t et;
@ -2295,7 +2295,7 @@ vppcom_session_write_inline (vcl_worker_t *wrk, vcl_session_t *s, void *buf,
if (is_dgram)
n_write =
app_send_dgram_raw_gso (tx_fifo, &s->transport, s->vpp_evt_q, buf, n,
gso_size, et, 0 /* do_evt */, SVM_Q_WAIT);
s->gso_size, et, 0 /* do_evt */, SVM_Q_WAIT);
else
n_write = app_send_stream_raw (tx_fifo, s->vpp_evt_q, buf, n, et,
0 /* do_evt */ , SVM_Q_WAIT);
@ -2324,7 +2324,7 @@ vppcom_session_write (uint32_t session_handle, void *buf, size_t n)
if (PREDICT_FALSE (!s))
return VPPCOM_EBADFD;
return vppcom_session_write_inline (wrk, s, buf, n, 0, 0 /* is_flush */,
return vppcom_session_write_inline (wrk, s, buf, n, 0 /* is_flush */,
s->is_dgram ? 1 : 0);
}
@ -2338,7 +2338,7 @@ vppcom_session_write_msg (uint32_t session_handle, void *buf, size_t n)
if (PREDICT_FALSE (!s))
return VPPCOM_EBADFD;
return vppcom_session_write_inline (wrk, s, buf, n, 0, 1 /* is_flush */,
return vppcom_session_write_inline (wrk, s, buf, n, 1 /* is_flush */,
s->is_dgram ? 1 : 0);
}
@ -4105,6 +4105,36 @@ vppcom_session_attr (uint32_t session_handle, uint32_t op,
clib_memcpy (session->ext_config->data, buffer, *buflen);
session->ext_config->len = *buflen;
break;
case VPPCOM_ATTR_SET_IP_PKTINFO:
if (buffer && buflen && (*buflen == sizeof (int)) &&
!vcl_session_has_attr (session, VCL_SESS_ATTR_IP_PKTINFO))
{
if (*(int *) buffer)
vcl_session_set_attr (session, VCL_SESS_ATTR_IP_PKTINFO);
else
vcl_session_clear_attr (session, VCL_SESS_ATTR_IP_PKTINFO);
VDBG (2, "VCL_SESS_ATTR_IP_PKTINFO: %d, buflen %d",
vcl_session_has_attr (session, VCL_SESS_ATTR_IP_PKTINFO),
*buflen);
}
else
rv = VPPCOM_EINVAL;
break;
case VPPCOM_ATTR_GET_IP_PKTINFO:
if (buffer && buflen && (*buflen >= sizeof (int)))
{
*(int *) buffer =
vcl_session_has_attr (session, VCL_SESS_ATTR_IP_PKTINFO);
*buflen = sizeof (int);
VDBG (2, "VCL_SESS_ATTR_IP_PKTINFO: %d, buflen %d", *(int *) buffer,
*buflen);
}
else
rv = VPPCOM_EINVAL;
break;
default:
rv = VPPCOM_EINVAL;
@ -4148,13 +4178,37 @@ vppcom_session_recvfrom (uint32_t session_handle, void *buffer,
return rv;
}
static void
vcl_handle_ep_app_tlvs (vcl_session_t *s, vppcom_endpt_t *ep)
{
vppcom_endpt_tlv_t *tlv = ep->app_tlvs;
do
{
switch (tlv->data_type)
{
case VCL_UDP_SEGMENT:
s->gso_size = *(u16 *) tlv->data;
break;
case VCL_IP_PKTINFO:
clib_memcpy_fast (&s->transport.lcl_ip, (ip4_address_t *) tlv->data,
sizeof (ip4_address_t));
break;
default:
VDBG (0, "Ignorning unsupported app tlv %u", tlv->data_type);
break;
}
tlv = VCL_EP_NEXT_APP_TLV (ep, tlv);
}
while (tlv);
}
int
vppcom_session_sendto (uint32_t session_handle, void *buffer,
uint32_t buflen, int flags, vppcom_endpt_t * ep)
{
vcl_worker_t *wrk = vcl_worker_get_current ();
vcl_session_t *s;
u16 gso_size = 0;
s = vcl_session_get_w_handle (wrk, session_handle);
if (PREDICT_FALSE (!s))
@ -4169,12 +4223,9 @@ vppcom_session_sendto (uint32_t session_handle, void *buffer,
s->transport.rmt_port = ep->port;
vcl_ip_copy_from_ep (&s->transport.rmt_ip, ep);
vppcom_endpt_tlv_t *p_app_data = &ep->app_data;
if (ep->app_tlvs)
vcl_handle_ep_app_tlvs (s, ep);
if (p_app_data && (p_app_data->data_type == VCL_UDP_SEGMENT))
{
gso_size = p_app_data->value;
}
/* Session not connected/bound in vpp. Create it by 'connecting' it */
if (PREDICT_FALSE (s->session_state == VCL_STATE_CLOSED))
{
@ -4198,7 +4249,7 @@ vppcom_session_sendto (uint32_t session_handle, void *buffer,
VDBG (2, "handling flags 0x%u (%d) not implemented yet.", flags, flags);
}
return (vppcom_session_write_inline (wrk, s, buffer, buflen, gso_size, 1,
return (vppcom_session_write_inline (wrk, s, buffer, buflen, 1,
s->is_dgram ? 1 : 0));
}

View File

@ -22,12 +22,12 @@
#include <poll.h>
#include <sys/epoll.h>
/* *INDENT-OFF* */
/* clang-format off */
#ifdef __cplusplus
extern "C"
{
#endif
/* *INDENT-ON* */
/*
* VPPCOM Public API Definitions, Enums, and Data Structures
@ -46,49 +46,56 @@ extern "C"
#define VPPCOM_ENV_VPP_API_SOCKET "VCL_VPP_API_SOCKET"
#define VPPCOM_ENV_VPP_SAPI_SOCKET "VCL_VPP_SAPI_SOCKET"
typedef enum
{
VPPCOM_PROTO_TCP = 0,
VPPCOM_PROTO_UDP,
VPPCOM_PROTO_NONE,
VPPCOM_PROTO_TLS,
VPPCOM_PROTO_QUIC,
VPPCOM_PROTO_DTLS,
VPPCOM_PROTO_SRTP,
} vppcom_proto_t;
typedef enum vppcom_proto_
{
VPPCOM_PROTO_TCP = 0,
VPPCOM_PROTO_UDP,
VPPCOM_PROTO_NONE,
VPPCOM_PROTO_TLS,
VPPCOM_PROTO_QUIC,
VPPCOM_PROTO_DTLS,
VPPCOM_PROTO_SRTP,
} vppcom_proto_t;
typedef enum
{
VPPCOM_IS_IP6 = 0,
VPPCOM_IS_IP4,
} vppcom_is_ip4_t;
typedef enum
{
VPPCOM_IS_IP6 = 0,
VPPCOM_IS_IP4,
} vppcom_is_ip4_t;
typedef struct vppcom_endpt_tlv_t_
{
uint32_t data_type;
uint32_t data_len;
uint8_t data[0];
} vppcom_endpt_tlv_t;
typedef struct vppcom_endpt_t_
{
uint8_t unused; /**< unused */
uint8_t is_ip4; /**< flag set if if ip is ipv4 */
uint8_t *ip; /**< pointer to ip address */
uint16_t port; /**< transport port */
uint64_t unused2; /**< unused */
uint32_t app_tlv_len; /**< length of app provided tlvs */
vppcom_endpt_tlv_t *app_tlvs; /**< array of app provided tlvs */
} vppcom_endpt_t;
#define VCL_UDP_OPTS_BASE (VPPCOM_PROTO_UDP << 16)
#define VCL_UDP_SEGMENT (VCL_UDP_OPTS_BASE + 0)
typedef struct vppcom_endpt_tlv_t_
{
uint32_t data_type;
uint32_t data_len;
union
{
/* data */
uint64_t value;
uint32_t as_u32[2];
uint16_t as_u16[4];
uint8_t as_u8[8];
};
} vppcom_endpt_tlv_t;
/* By convention we'll use 127 for IP since we don't support IP as protocol */
#define VCL_IP_OPTS_BASE (127 << 16)
#define VCL_IP_PKTINFO (VCL_IP_OPTS_BASE + 1)
typedef struct vppcom_endpt_t_
{
uint8_t is_cut_thru;
uint8_t is_ip4;
uint8_t *ip;
uint16_t port;
uint64_t parent_handle;
vppcom_endpt_tlv_t app_data;
} vppcom_endpt_t;
#define VCL_EP_APP_TLV_LEN(tlv_) (sizeof (vppcom_endpt_tlv_t) + tlv->data_len)
#define VCL_EP_APP_TLV_POS(ep_, tlv_) ((void *)ep_->app_tlvs - (void *)tlv_)
#define VCL_EP_APP_TLV_LEN_LEFT(ep_, tlv_) \
(ep_->app_tlv_len - VCL_EP_APP_TLV_POS (ep_, tlv_))
#define VCL_EP_NEXT_APP_TLV(ep_, tlv_) \
(VCL_EP_APP_TLV_LEN (tlv_) < VCL_EP_APP_TLV_POS (ep_, tlv_) ? ( \
(vppcom_endpt_tlv_t *)((uint8_t *)tlv_ + VCL_EP_APP_TLV_LEN (tlv_))) \
: 0)
typedef uint32_t vcl_session_handle_t;
@ -167,6 +174,8 @@ typedef enum
VPPCOM_ATTR_GET_DOMAIN,
VPPCOM_ATTR_SET_ENDPT_EXT_CFG,
VPPCOM_ATTR_SET_DSCP,
VPPCOM_ATTR_SET_IP_PKTINFO,
VPPCOM_ATTR_GET_IP_PKTINFO,
} vppcom_attr_op_t;
typedef struct _vcl_poll
@ -299,11 +308,10 @@ extern int vppcom_session_get_error (uint32_t session_handle);
*/
extern int vppcom_worker_is_detached (void);
/* *INDENT-OFF* */
#ifdef __cplusplus
}
#endif
/* *INDENT-ON* */
/* clang-format on */
#endif /* included_vppcom_h */