flow-hash: Add symmetric flag for flow hashing
[vpp.git] / src / vnet / ip / punt.c
index 651542f..d8c7d81 100644 (file)
@@ -27,6 +27,7 @@
 #include <vnet/pg/pg.h>
 #include <vnet/udp/udp.h>
 #include <vnet/tcp/tcp.h>
+#include <vnet/sctp/sctp.h>
 #include <vnet/ip/punt.h>
 #include <vppinfra/sparse_vec.h>
 #include <vlib/unix/unix.h>
@@ -40,7 +41,8 @@
 #include <stdbool.h>
 
 #define foreach_punt_next                      \
-  _ (PUNT, "error-punt")
+  _ (PUNT4, "ip4-punt")                         \
+  _ (PUNT6, "ip6-punt")
 
 typedef enum
 {
@@ -58,6 +60,8 @@ enum punt_socket_rx_next_e
   PUNT_SOCKET_RX_N_NEXT
 };
 
+#define punt_next_punt(is_ip4) (is_ip4 ? PUNT_NEXT_PUNT4 : PUNT_NEXT_PUNT6)
+
 vlib_node_registration_t udp4_punt_node;
 vlib_node_registration_t udp6_punt_node;
 vlib_node_registration_t udp4_punt_socket_node;
@@ -104,7 +108,8 @@ udp46_punt_inline (vlib_main_t * vm,
     {
       u32 n_left_to_next;
 
-      vlib_get_next_frame (vm, node, PUNT_NEXT_PUNT, to_next, n_left_to_next);
+      vlib_get_next_frame (vm, node, punt_next_punt (is_ip4), to_next,
+                          n_left_to_next);
 
       while (n_left_from > 0 && n_left_to_next > 0)
        {
@@ -123,7 +128,7 @@ udp46_punt_inline (vlib_main_t * vm,
          b0->error = node->errors[PUNT_ERROR_UDP_PORT];
        }
 
-      vlib_put_next_frame (vm, node, PUNT_NEXT_PUNT, n_left_to_next);
+      vlib_put_next_frame (vm, node, punt_next_punt (is_ip4), n_left_to_next);
     }
 
   return from_frame->n_vectors;
@@ -232,18 +237,28 @@ VLIB_NODE_FUNCTION_MULTIARCH (udp6_punt_node, udp6_punt);;
 
 /* *INDENT-ON* */
 
-static struct sockaddr_un *
-punt_socket_get (bool is_ip4, u16 port)
+static punt_client_t *
+punt_client_get (bool is_ip4, u16 port)
 {
   punt_main_t *pm = &punt_main;
-  punt_client_t *v = is_ip4 ? pm->clients_by_dst_port4 :
-    pm->clients_by_dst_port6;
+  punt_client_t *v =
+    is_ip4 ? pm->clients_by_dst_port4 : pm->clients_by_dst_port6;
 
   u16 i = sparse_vec_index (v, port);
   if (i == SPARSE_VEC_INVALID_INDEX)
     return 0;
 
-  return &vec_elt (v, i).caddr;
+  return &vec_elt (v, i);
+}
+
+static struct sockaddr_un *
+punt_socket_get (bool is_ip4, u16 port)
+{
+  punt_client_t *v = punt_client_get (is_ip4, port);
+  if (v)
+    return &v->caddr;
+
+  return NULL;
 }
 
 static void
@@ -255,7 +270,7 @@ punt_socket_register (bool is_ip4, u8 protocol, u16 port,
   punt_client_t *v = is_ip4 ? pm->clients_by_dst_port4 :
     pm->clients_by_dst_port6;
 
-  memset (&c, 0, sizeof (c));
+  clib_memset (&c, 0, sizeof (c));
   memcpy (c.caddr.sun_path, client_pathname, sizeof (c.caddr.sun_path));
   c.caddr.sun_family = AF_UNIX;
   c.port = port;
@@ -270,12 +285,34 @@ punt_socket_unregister (bool is_ip4, u8 protocol, u16 port)
   return;
 }
 
+typedef struct
+{
+  punt_client_t client;
+  u8 is_midchain;
+} udp_punt_trace_t;
+
+u8 *
+format_udp_punt_trace (u8 * s, va_list * args)
+{
+  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
+  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
+  udp_punt_trace_t *t = va_arg (*args, udp_punt_trace_t *);
+  u32 indent = format_get_indent (s);
+  s = format (s, "to: %s", t->client.caddr.sun_path);
+  if (t->is_midchain)
+    {
+      s = format (s, "\n%U(buffer is part of chain)", format_white_space,
+                 indent);
+    }
+  return s;
+}
+
 always_inline uword
 udp46_punt_socket_inline (vlib_main_t * vm,
                          vlib_node_runtime_t * node,
                          vlib_frame_t * frame, bool is_ip4)
 {
-  u32 *buffers = vlib_frame_args (frame);
+  u32 *buffers = vlib_frame_vector_args (frame);
   uword n_packets = frame->n_vectors;
   struct iovec *iovecs = 0;
   punt_main_t *pm = &punt_main;
@@ -325,6 +362,15 @@ udp46_punt_socket_inline (vlib_main_t * vm,
          goto error;
        }
 
+      punt_client_t *c = NULL;
+      if (PREDICT_FALSE (b->flags & VLIB_BUFFER_IS_TRACED))
+       {
+         c = punt_client_get (is_ip4, port);
+         udp_punt_trace_t *t;
+         t = vlib_add_trace (vm, node, b, sizeof (t[0]));
+         clib_memcpy_fast (&t->client, c, sizeof (t->client));
+       }
+
       /* Re-set iovecs if present. */
       if (iovecs)
        _vec_len (iovecs) = 0;
@@ -347,6 +393,17 @@ udp46_punt_socket_inline (vlib_main_t * vm,
          do
            {
              b = vlib_get_buffer (vm, b->next_buffer);
+             if (PREDICT_FALSE (b->flags & VLIB_BUFFER_IS_TRACED))
+               {
+                 if (PREDICT_FALSE (!c))
+                   {
+                     c = punt_client_get (is_ip4, port);
+                   }
+                 udp_punt_trace_t *t;
+                 t = vlib_add_trace (vm, node, b, sizeof (t[0]));
+                 clib_memcpy_fast (&t->client, c, sizeof (t->client));
+                 t->is_midchain = 1;
+               }
 
              vec_add2 (iovecs, iov, 1);
 
@@ -364,7 +421,7 @@ udp46_punt_socket_inline (vlib_main_t * vm,
        .msg_iovlen = vec_len (iovecs),
       };
 
-      if (sendmsg (pm->socket_fd, &msg, 0) < l)
+      if (sendmsg (pm->socket_fd, &msg, 0) < (ssize_t) l)
        vlib_node_increment_counter (vm, node_index,
                                     PUNT_ERROR_SOCKET_TX_ERROR, 1);
     }
@@ -394,6 +451,7 @@ udp6_punt_socket (vlib_main_t * vm,
 VLIB_REGISTER_NODE (udp4_punt_socket_node) = {
   .function = udp4_punt_socket,
   .name = "ip4-udp-punt-socket",
+  .format_trace = format_udp_punt_trace,
   .flags = VLIB_NODE_FLAG_IS_DROP,
   /* Takes a vector of packets. */
   .vector_size = sizeof (u32),
@@ -403,6 +461,7 @@ VLIB_REGISTER_NODE (udp4_punt_socket_node) = {
 VLIB_REGISTER_NODE (udp6_punt_socket_node) = {
   .function = udp6_punt_socket,
   .name = "ip6-udp-punt-socket",
+  .format_trace = format_udp_punt_trace,
   .flags = VLIB_NODE_FLAG_IS_DROP,
   .vector_size = sizeof (u32),
   .n_errors = PUNT_N_ERROR,
@@ -631,11 +690,13 @@ vnet_punt_add_del (vlib_main_t * vm, u8 ipv, u8 protocol, u16 port,
                   bool is_add)
 {
 
-  /* For now we only support UDP punt */
-  if (protocol != IP_PROTOCOL_UDP && protocol != IP_PROTOCOL_TCP)
+  /* For now we only support TCP, UDP and SCTP punt */
+  if (protocol != IP_PROTOCOL_UDP &&
+      protocol != IP_PROTOCOL_TCP && protocol != IP_PROTOCOL_SCTP)
     return clib_error_return (0,
-                             "only UDP (%d) and TCP (%d) protocols are supported, got %d",
-                             IP_PROTOCOL_UDP, IP_PROTOCOL_TCP, protocol);
+                             "only UDP (%d), TCP (%d) and SCTP (%d) protocols are supported, got %d",
+                             IP_PROTOCOL_UDP, IP_PROTOCOL_TCP,
+                             IP_PROTOCOL_SCTP, protocol);
 
   if (ipv != (u8) ~ 0 && ipv != 4 && ipv != 6)
     return clib_error_return (0, "IP version must be 4 or 6, got %d", ipv);
@@ -648,6 +709,8 @@ vnet_punt_add_del (vlib_main_t * vm, u8 ipv, u8 protocol, u16 port,
            udp_punt_unknown (vm, 1, is_add);
          else if (protocol == IP_PROTOCOL_TCP)
            tcp_punt_unknown (vm, 1, is_add);
+         else if (protocol == IP_PROTOCOL_SCTP)
+           sctp_punt_unknown (vm, 1, is_add);
        }
 
       if ((ipv == 6) || (ipv == (u8) ~ 0))
@@ -656,6 +719,8 @@ vnet_punt_add_del (vlib_main_t * vm, u8 ipv, u8 protocol, u16 port,
            udp_punt_unknown (vm, 0, is_add);
          else if (protocol == IP_PROTOCOL_TCP)
            tcp_punt_unknown (vm, 0, is_add);
+         else if (protocol == IP_PROTOCOL_SCTP)
+           sctp_punt_unknown (vm, 0, is_add);
        }
 
       return 0;
@@ -663,8 +728,9 @@ vnet_punt_add_del (vlib_main_t * vm, u8 ipv, u8 protocol, u16 port,
 
   else if (is_add)
     {
-      if (protocol == IP_PROTOCOL_TCP)
-       return clib_error_return (0, "punt TCP ports is not supported yet");
+      if (protocol == IP_PROTOCOL_TCP || protocol == IP_PROTOCOL_SCTP)
+       return clib_error_return (0,
+                                 "punt TCP/SCTP ports is not supported yet");
 
       if (ipv == 4 || ipv == (u8) ~ 0)
        udp_register_dst_port (vm, port, udp4_punt_node.index, 1);
@@ -685,7 +751,7 @@ punt_cli (vlib_main_t * vm,
   u32 port;
   bool is_add = true;
   u32 protocol = ~0;
-  clib_error_t *error;
+  clib_error_t *error = NULL;
 
   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
     {
@@ -696,22 +762,34 @@ punt_cli (vlib_main_t * vm,
          /* punt both IPv6 and IPv4 when used in CLI */
          error = vnet_punt_add_del (vm, ~0, protocol, ~0, is_add);
          if (error)
-           clib_error_report (error);
+           {
+             clib_error_report (error);
+             goto done;
+           }
        }
       else if (unformat (input, "%d", &port))
        {
          /* punt both IPv6 and IPv4 when used in CLI */
          error = vnet_punt_add_del (vm, ~0, protocol, port, is_add);
          if (error)
-           clib_error_report (error);
+           {
+             clib_error_report (error);
+             goto done;
+           }
        }
       else if (unformat (input, "udp"))
        protocol = IP_PROTOCOL_UDP;
       else if (unformat (input, "tcp"))
        protocol = IP_PROTOCOL_TCP;
+      else
+       {
+         error = clib_error_return (0, "parse error: '%U'",
+                                    format_unformat_error, input);
+         goto done;
+       }
     }
-
-  return 0;
+done:
+  return error;
 }
 
 /*?
@@ -788,7 +866,7 @@ punt_config (vlib_main_t * vm, unformat_input_t * input)
       return clib_error_return (0, "socket error");
     }
 
-  memset (&addr, 0, sizeof (addr));
+  clib_memset (&addr, 0, sizeof (addr));
   addr.sun_family = AF_UNIX;
   if (*socket_path == '\0')
     {
@@ -812,6 +890,7 @@ punt_config (vlib_main_t * vm, unformat_input_t * input)
   clib_file_t template = { 0 };
   template.read_function = punt_socket_read_ready;
   template.file_descriptor = pm->socket_fd;
+  template.description = format (0, "%s", socket_path);
   pm->clib_file_index = clib_file_add (fm, &template);
 
   pm->is_configured = true;