From eff5f7aea8c7ca8a63c88624bf962c43b3f8bdd3 Mon Sep 17 00:00:00 2001 From: Florin Coras Date: Tue, 7 Feb 2023 17:36:17 -0800 Subject: vcl: ldp support for ip_pktinfo Type: improvement Signed-off-by: Florin Coras Change-Id: I3c15f38a4a3f5e92506059277948e7fca9cd8b55 --- src/vcl/ldp.c | 143 ++++++++++++++++++++++++++++++++++++++++++-------- src/vcl/vcl_private.h | 22 ++++---- src/vcl/vppcom.c | 73 ++++++++++++++++++++++---- src/vcl/vppcom.h | 94 ++++++++++++++++++--------------- 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 #include #include -#include +#include #include #include @@ -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 #include -/* *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 */ -- cgit 1.2.3-korg