ip: punt add punt socket support for icmp6 84/39484/6
authorOle Troan <otroan@employees.org>
Tue, 5 Sep 2023 06:27:53 +0000 (08:27 +0200)
committerDamjan Marion <dmarion@0xa5.net>
Wed, 6 Sep 2023 10:48:18 +0000 (10:48 +0000)
Punt support for ICMP6 messages allows for an external IPv6 RA advertisement agent.

Type: feature
Change-Id: I0cc928b747ac1f8335ee9f7c42a3231424825dbc
Signed-off-by: Ole Troan <otroan@employees.org>
src/vnet/ip/punt.c
src/vnet/ip/punt.h
src/vnet/ip/punt_node.c

index 10deb2e..aedfcad 100644 (file)
@@ -148,14 +148,31 @@ punt_socket_register_l4 (vlib_main_t * vm,
   punt_main_t *pm = &punt_main;
   punt_client_t *c;
 
-  /* For now we only support UDP punt */
-  if (protocol != IP_PROTOCOL_UDP)
-    return clib_error_return (0,
-                             "only UDP protocol (%d) is supported, got %d",
-                             IP_PROTOCOL_UDP, protocol);
-
   if (port == (u16) ~ 0)
-    return clib_error_return (0, "UDP port number required");
+    return clib_error_return (0, "Port number required");
+
+  u32 node_index;
+  switch (protocol)
+    {
+    case IP_PROTOCOL_UDP:
+      node_index = (af == AF_IP4 ? udp4_punt_socket_node.index :
+                                        udp6_punt_socket_node.index);
+      udp_register_dst_port (vm, port, node_index, af == AF_IP4);
+      break;
+    case IP_PROTOCOL_ICMP6:
+      if (af != AF_IP6)
+       return clib_error_return (
+         0, "only UDP or ICMP6 protocol (%d, %d) is supported, got %d",
+         IP_PROTOCOL_UDP, IP_PROTOCOL_ICMP6, protocol);
+
+      node_index = icmp6_punt_socket_node.index;
+      icmp6_register_type (vm, port, node_index);
+      break;
+    default:
+      return clib_error_return (
+       0, "only UDP or ICMP6 protocol (%d) is supported, got %d",
+       IP_PROTOCOL_UDP, protocol);
+    }
 
   c = punt_client_l4_get (af, port);
 
@@ -173,12 +190,6 @@ punt_socket_register_l4 (vlib_main_t * vm,
   c->reg.punt.l4.protocol = protocol;
   c->reg.punt.l4.af = af;
 
-  u32 node_index = (af == AF_IP4 ?
-                   udp4_punt_socket_node.index :
-                   udp6_punt_socket_node.index);
-
-  udp_register_dst_port (vm, port, node_index, af == AF_IP4);
-
   return (NULL);
 }
 
index a2612d6..09e6e73 100644 (file)
@@ -239,6 +239,7 @@ extern vlib_node_registration_t udp4_punt_node;
 extern vlib_node_registration_t udp6_punt_node;
 extern vlib_node_registration_t udp4_punt_socket_node;
 extern vlib_node_registration_t udp6_punt_socket_node;
+extern vlib_node_registration_t icmp6_punt_socket_node;
 extern vlib_node_registration_t ip4_proto_punt_socket_node;
 extern vlib_node_registration_t ip6_proto_punt_socket_node;
 extern vlib_node_registration_t punt_socket_rx_node;
index 5d822c7..8a2057b 100644 (file)
@@ -244,10 +244,9 @@ format_udp_punt_trace (u8 * s, va_list * args)
 }
 
 always_inline uword
-punt_socket_inline (vlib_main_t * vm,
-                   vlib_node_runtime_t * node,
-                   vlib_frame_t * frame,
-                   punt_type_t pt, ip_address_family_t af)
+punt_socket_inline2 (vlib_main_t *vm, vlib_node_runtime_t *node,
+                    vlib_frame_t *frame, punt_type_t pt,
+                    ip_address_family_t af, ip_protocol_t protocol)
 {
   u32 *buffers = vlib_frame_vector_args (frame);
   u32 thread_index = vm->thread_index;
@@ -267,33 +266,42 @@ punt_socket_inline (vlib_main_t * vm,
       uword l;
       punt_packetdesc_t packetdesc;
       punt_client_t *c;
-
+      u16 port = 0;
       b = vlib_get_buffer (vm, buffers[i]);
 
       if (PUNT_TYPE_L4 == pt)
        {
-         /* Reverse UDP Punt advance */
-         udp_header_t *udp;
-         if (AF_IP4 == af)
+         if (protocol == IP_PROTOCOL_UDP)
            {
-             vlib_buffer_advance (b, -(sizeof (ip4_header_t) +
-                                       sizeof (udp_header_t)));
-             ip4_header_t *ip = vlib_buffer_get_current (b);
-             udp = (udp_header_t *) (ip + 1);
+             /* Reverse UDP Punt advance */
+             udp_header_t *udp;
+             if (AF_IP4 == af)
+               {
+                 vlib_buffer_advance (
+                   b, -(sizeof (ip4_header_t) + sizeof (udp_header_t)));
+                 ip4_header_t *ip = vlib_buffer_get_current (b);
+                 udp = (udp_header_t *) (ip + 1);
+               }
+             else
+               {
+                 vlib_buffer_advance (
+                   b, -(sizeof (ip6_header_t) + sizeof (udp_header_t)));
+                 ip6_header_t *ip = vlib_buffer_get_current (b);
+                 udp = (udp_header_t *) (ip + 1);
+               }
+             port = clib_net_to_host_u16 (udp->dst_port);
            }
-         else
+         else if (protocol == IP_PROTOCOL_ICMP6)
            {
-             vlib_buffer_advance (b, -(sizeof (ip6_header_t) +
-                                       sizeof (udp_header_t)));
              ip6_header_t *ip = vlib_buffer_get_current (b);
-             udp = (udp_header_t *) (ip + 1);
+             icmp46_header_t *icmp = ip6_next_header (ip);
+             port = icmp->type;
            }
-
          /*
           * Find registerered client
           * If no registered client, drop packet and count
           */
-         c = punt_client_l4_get (af, clib_net_to_host_u16 (udp->dst_port));
+         c = punt_client_l4_get (af, port);
        }
       else if (PUNT_TYPE_IP_PROTO == pt)
        {
@@ -397,6 +405,14 @@ error:
   return n_packets;
 }
 
+always_inline uword
+punt_socket_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
+                   vlib_frame_t *frame, punt_type_t pt,
+                   ip_address_family_t af)
+{
+  return punt_socket_inline2 (vm, node, frame, pt, af, IP_PROTOCOL_UDP);
+}
+
 static uword
 udp4_punt_socket (vlib_main_t * vm,
                  vlib_node_runtime_t * node, vlib_frame_t * from_frame)
@@ -427,6 +443,14 @@ ip6_proto_punt_socket (vlib_main_t * vm,
                             PUNT_TYPE_IP_PROTO, AF_IP6);
 }
 
+static uword
+icmp6_punt_socket (vlib_main_t *vm, vlib_node_runtime_t *node,
+                  vlib_frame_t *from_frame)
+{
+  return punt_socket_inline2 (vm, node, from_frame, PUNT_TYPE_L4, AF_IP6,
+                             IP_PROTOCOL_ICMP6);
+}
+
 static uword
 exception_punt_socket (vlib_main_t * vm,
                       vlib_node_runtime_t * node, vlib_frame_t * from_frame)
@@ -484,6 +508,16 @@ VLIB_REGISTER_NODE (exception_punt_socket_node) = {
   .n_errors = PUNT_N_ERROR,
   .error_strings = punt_error_strings,
 };
+VLIB_REGISTER_NODE (icmp6_punt_socket_node) = {
+  .function = icmp6_punt_socket,
+  .name = "ip6-icmp-punt-socket",
+  .format_trace = format_udp_punt_trace,
+  .flags = VLIB_NODE_FLAG_IS_DROP,
+  .vector_size = sizeof (u32),
+  .n_errors = PUNT_N_ERROR,
+  .error_strings = punt_error_strings,
+};
+
 /* *INDENT-ON* */
 
 typedef struct