vcl: ldp support for ip_pktinfo 67/38167/15
authorFlorin Coras <fcoras@cisco.com>
Wed, 8 Feb 2023 01:36:17 +0000 (17:36 -0800)
committerDave Barach <vpp@barachs.net>
Mon, 20 Feb 2023 18:50:52 +0000 (18:50 +0000)
Type: improvement

Signed-off-by: Florin Coras <fcoras@cisco.com>
Change-Id: I3c15f38a4a3f5e92506059277948e7fca9cd8b55

src/vcl/ldp.c
src/vcl/vcl_private.h
src/vcl/vppcom.c
src/vcl/vppcom.h

index 71ce94b..9e8858f 100644 (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;
        }
index 3df8b4b..93e7656 100644 (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)
index 3b265d2..a800b44 100644 (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));
 }
 
index 81a6634..71a49ab 100644 (file)
 #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 */