summaryrefslogtreecommitdiffstats
path: root/src/vcl
diff options
context:
space:
mode:
authorFlorin Coras <fcoras@cisco.com>2023-02-07 17:36:17 -0800
committerDave Barach <vpp@barachs.net>2023-02-20 18:50:52 +0000
commiteff5f7aea8c7ca8a63c88624bf962c43b3f8bdd3 (patch)
tree5ea812f27cf5da59498cb5d2c69e6009852e7cca /src/vcl
parent7c7231fc30d9da81bc1311966fe8b9d8720c1623 (diff)
vcl: ldp support for ip_pktinfo
Type: improvement Signed-off-by: Florin Coras <fcoras@cisco.com> Change-Id: I3c15f38a4a3f5e92506059277948e7fca9cd8b55
Diffstat (limited to 'src/vcl')
-rw-r--r--src/vcl/ldp.c143
-rw-r--r--src/vcl/vcl_private.h22
-rw-r--r--src/vcl/vppcom.c73
-rw-r--r--src/vcl/vppcom.h94
4 files changed, 245 insertions, 87 deletions
diff --git a/src/vcl/ldp.c b/src/vcl/ldp.c
index 71ce94bdd18..9e8858fb230 100644
--- a/src/vcl/ldp.c
+++ b/src/vcl/ldp.c
@@ -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;
}
diff --git a/src/vcl/vcl_private.h b/src/vcl/vcl_private.h
index 3df8b4bb473..93e76565ee7 100644
--- a/src/vcl/vcl_private.h
+++ b/src/vcl/vcl_private.h
@@ -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)
diff --git a/src/vcl/vppcom.c b/src/vcl/vppcom.c
index 3b265d29ab8..a800b44aaa0 100644
--- a/src/vcl/vppcom.c
+++ b/src/vcl/vppcom.c
@@ -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));
}
diff --git a/src/vcl/vppcom.h b/src/vcl/vppcom.h
index 81a6634a8a3..71a49ab3480 100644
--- a/src/vcl/vppcom.h
+++ b/src/vcl/vppcom.h
@@ -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_IS_IP6 = 0,
- VPPCOM_IS_IP4,
- } vppcom_is_ip4_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 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;
-
- 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;
+/* 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)
+
+#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 */