Punt: specify packets by IP protocol Type 58/19858/2
authorNeale Ranns <nranns@cisco.com>
Tue, 21 May 2019 13:54:54 +0000 (06:54 -0700)
committerOle Trøan <otroan@employees.org>
Tue, 4 Jun 2019 10:32:46 +0000 (10:32 +0000)
Change-Id: I0c2d6fccd95146e52bb88ca4a6e84554d5d6b2ed
Signed-off-by: Neale Ranns <nranns@cisco.com>
12 files changed:
src/vnet/ip/ip4.h
src/vnet/ip/ip4_forward.c
src/vnet/ip/ip6.h
src/vnet/ip/ip6_forward.c
src/vnet/ip/ip_types.api
src/vnet/ip/ip_types_api.c
src/vnet/ip/punt.api
src/vnet/ip/punt.c
src/vnet/ip/punt.h
src/vnet/ip/punt_api.c
src/vnet/ip/punt_node.c
test/test_punt.py

index 5c9add4..9f25f43 100644 (file)
@@ -288,6 +288,7 @@ u16 ip4_tcp_udp_compute_checksum (vlib_main_t * vm, vlib_buffer_t * p0,
                                  ip4_header_t * ip0);
 
 void ip4_register_protocol (u32 protocol, u32 node_index);
                                  ip4_header_t * ip0);
 
 void ip4_register_protocol (u32 protocol, u32 node_index);
+void ip4_unregister_protocol (u32 protocolx);
 
 serialize_function_t serialize_vnet_ip4_main, unserialize_vnet_ip4_main;
 
 
 serialize_function_t serialize_vnet_ip4_main, unserialize_vnet_ip4_main;
 
index 9c5524f..43213fe 100644 (file)
@@ -1679,6 +1679,16 @@ ip4_register_protocol (u32 protocol, u32 node_index)
   lm->local_next_by_ip_protocol[protocol] =
     vlib_node_add_next (vm, ip4_local_node.index, node_index);
 }
   lm->local_next_by_ip_protocol[protocol] =
     vlib_node_add_next (vm, ip4_local_node.index, node_index);
 }
+
+void
+ip4_unregister_protocol (u32 protocol)
+{
+  ip4_main_t *im = &ip4_main;
+  ip_lookup_main_t *lm = &im->lookup_main;
+
+  ASSERT (protocol < ARRAY_LEN (lm->local_next_by_ip_protocol));
+  lm->local_next_by_ip_protocol[protocol] = IP_LOCAL_NEXT_PUNT;
+}
 #endif
 
 static clib_error_t *
 #endif
 
 static clib_error_t *
@@ -1697,8 +1707,8 @@ show_ip_local_command_fn (vlib_main_t * vm,
          u32 node_index = vlib_get_node (vm,
                                          ip4_local_node.index)->
            next_nodes[lm->local_next_by_ip_protocol[i]];
          u32 node_index = vlib_get_node (vm,
                                          ip4_local_node.index)->
            next_nodes[lm->local_next_by_ip_protocol[i]];
-         vlib_cli_output (vm, "%d: %U", i, format_vlib_node_name, vm,
-                          node_index);
+         vlib_cli_output (vm, "%U: %U", format_ip_protocol, i,
+                          format_vlib_node_name, vm, node_index);
        }
     }
   return 0;
        }
     }
   return 0;
index e66bbdd..b511ccc 100644 (file)
@@ -388,6 +388,7 @@ u16 ip6_tcp_udp_icmp_compute_checksum (vlib_main_t * vm, vlib_buffer_t * p0,
                                       int *bogus_lengthp);
 
 void ip6_register_protocol (u32 protocol, u32 node_index);
                                       int *bogus_lengthp);
 
 void ip6_register_protocol (u32 protocol, u32 node_index);
+void ip6_unregister_protocol (u32 protocol);
 void ip6_local_hop_by_hop_register_protocol (u32 protocol, u32 node_index);
 
 serialize_function_t serialize_vnet_ip6_main, unserialize_vnet_ip6_main;
 void ip6_local_hop_by_hop_register_protocol (u32 protocol, u32 node_index);
 
 serialize_function_t serialize_vnet_ip6_main, unserialize_vnet_ip6_main;
index 74f51fa..b6eae6e 100644 (file)
@@ -1433,6 +1433,16 @@ ip6_register_protocol (u32 protocol, u32 node_index)
     vlib_node_add_next (vm, ip6_local_node.index, node_index);
 }
 
     vlib_node_add_next (vm, ip6_local_node.index, node_index);
 }
 
+void
+ip6_unregister_protocol (u32 protocol)
+{
+  ip6_main_t *im = &ip6_main;
+  ip_lookup_main_t *lm = &im->lookup_main;
+
+  ASSERT (protocol < ARRAY_LEN (lm->local_next_by_ip_protocol));
+  lm->local_next_by_ip_protocol[protocol] = IP_LOCAL_NEXT_PUNT;
+}
+
 clib_error_t *
 ip6_probe_neighbor (vlib_main_t * vm, ip6_address_t * dst, u32 sw_if_index,
                    u8 refresh)
 clib_error_t *
 ip6_probe_neighbor (vlib_main_t * vm, ip6_address_t * dst, u32 sw_if_index,
                    u8 refresh)
index a9e6647..4c68567 100644 (file)
@@ -25,6 +25,8 @@ enum address_family {
 enum ip_proto {
   IP_API_PROTO_TCP = 6,
   IP_API_PROTO_UDP = 17,
 enum ip_proto {
   IP_API_PROTO_TCP = 6,
   IP_API_PROTO_UDP = 17,
+  IP_API_PROTO_EIGRP = 88,
+  IP_API_PROTO_OSPF = 89,
 };
 
 union address_union {
 };
 
 union address_union {
index d84c1ff..fd8d24f 100644 (file)
@@ -65,16 +65,16 @@ ip_address_family_encode (ip_address_family_t af)
 int
 ip_proto_decode (int _ipp, ip_protocol_t * out)
 {
 int
 ip_proto_decode (int _ipp, ip_protocol_t * out)
 {
-  vl_api_ip_proto_t ipp = clib_host_to_net_u32 (_ipp);
+  ip_protocol_t ipp = clib_host_to_net_u32 (_ipp);
 
   switch (ipp)
     {
 
   switch (ipp)
     {
-    case IP_API_PROTO_TCP:
-      *out = IP_PROTOCOL_TCP;
-      return (0);
-    case IP_API_PROTO_UDP:
-      *out = IP_PROTOCOL_UDP;
-      return (0);
+#define ip_protocol(n,s)                       \
+      case IP_PROTOCOL_##s:                    \
+        *out = IP_PROTOCOL_##s;                \
+        return (0);
+#include "protocols.def"
+#undef ip_protocol
     }
   return (-1);
 }
     }
   return (-1);
 }
@@ -84,12 +84,11 @@ ip_proto_encode (ip_protocol_t ipp)
 {
   switch (ipp)
     {
 {
   switch (ipp)
     {
-    case IP_PROTOCOL_UDP:
-      return (clib_host_to_net_u32 (IP_API_PROTO_UDP));
-    case IP_PROTOCOL_TCP:
-      return (clib_host_to_net_u32 (IP_API_PROTO_TCP));
-    default:
-      break;
+#define ip_protocol(n,s)                                \
+      case IP_PROTOCOL_##s:                             \
+        return (clib_host_to_net_u32 (IP_PROTOCOL_##s));
+#include "protocols.def"
+#undef ip_protocol
     }
 
   ASSERT (0);
     }
 
   ASSERT (0);
index cedddc5..6cb2731 100644 (file)
@@ -22,6 +22,8 @@ enum punt_type
 {
     /* L4 (UDP) packets */
     PUNT_API_TYPE_L4,
 {
     /* L4 (UDP) packets */
     PUNT_API_TYPE_L4,
+    /* IP proto (i.e. OSPF, RIP, etc) packets */
+    PUNT_API_TYPE_IP_PROTO,
     /* Exception packets handled by the VLIB punt infra */
     PUNT_API_TYPE_EXCEPTION,
 };
     /* Exception packets handled by the VLIB punt infra */
     PUNT_API_TYPE_EXCEPTION,
 };
@@ -38,6 +40,16 @@ typedef punt_l4
     u16 port;
 };
 
     u16 port;
 };
 
+/** \brief Punt IP protocol traffic definition
+    @param af - Address Family, IPv4 or IPV6
+    @param protocol - IP protocol to be punted
+*/
+typedef punt_ip_proto
+{
+    vl_api_address_family_t af;
+    vl_api_ip_proto_t protocol;
+};
+
 /** \brief The ID of the punt exception reason
            Dump all the reasons to obtain this
 */
 /** \brief The ID of the punt exception reason
            Dump all the reasons to obtain this
 */
@@ -52,6 +64,7 @@ union punt_union
 {
     vl_api_punt_exception_t exception;
     vl_api_punt_l4_t l4;
 {
     vl_api_punt_exception_t exception;
     vl_api_punt_l4_t l4;
+    vl_api_punt_ip_proto_t ip_proto;
 };
 
 /** \brief Full description of which packets are requested to be punted
 };
 
 /** \brief Full description of which packets are requested to be punted
index d4d5028..296df59 100644 (file)
@@ -74,6 +74,36 @@ punt_client_l4_db_remove (ip_address_family_t af, u16 port)
   return (index);
 }
 
   return (index);
 }
 
+static void
+punt_client_ip_proto_db_add (ip_address_family_t af,
+                            ip_protocol_t proto, u32 index)
+{
+  punt_main_t *pm = &punt_main;
+
+  pm->db.clients_by_ip_proto = hash_set (pm->db.clients_by_ip_proto,
+                                        punt_client_ip_proto_mk_key (af,
+                                                                     proto),
+                                        index);
+}
+
+static u32
+punt_client_ip_proto_db_remove (ip_address_family_t af, ip_protocol_t proto)
+{
+  punt_main_t *pm = &punt_main;
+  u32 key, index = ~0;
+  uword *p;
+
+  key = punt_client_ip_proto_mk_key (af, proto);
+  p = hash_get (pm->db.clients_by_ip_proto, key);
+
+  if (p)
+    index = p[0];
+
+  hash_unset (pm->db.clients_by_ip_proto, key);
+
+  return (index);
+}
+
 static void
 punt_client_exception_db_add (vlib_punt_reason_t reason, u32 pci)
 {
 static void
 punt_client_exception_db_add (vlib_punt_reason_t reason, u32 pci)
 {
@@ -129,12 +159,6 @@ punt_socket_register_l4 (vlib_main_t * vm,
   if (port == (u16) ~ 0)
     return clib_error_return (0, "UDP port number required");
 
   if (port == (u16) ~ 0)
     return clib_error_return (0, "UDP port number required");
 
-  if (strncmp (client_pathname, vnet_punt_get_server_pathname (),
-              UNIX_PATH_MAX) == 0)
-    return clib_error_return (0,
-                             "Punt socket: Invalid client path: %s",
-                             client_pathname);
-
   c = punt_client_l4_get (af, port);
 
   if (NULL == c)
   c = punt_client_l4_get (af, port);
 
   if (NULL == c)
@@ -159,6 +183,36 @@ punt_socket_register_l4 (vlib_main_t * vm,
   return (NULL);
 }
 
   return (NULL);
 }
 
+static clib_error_t *
+punt_socket_register_ip_proto (vlib_main_t * vm,
+                              ip_address_family_t af,
+                              ip_protocol_t proto, char *client_pathname)
+{
+  punt_main_t *pm = &punt_main;
+  punt_client_t *c;
+
+  c = punt_client_ip_proto_get (af, proto);
+
+  if (NULL == c)
+    {
+      pool_get_zero (pm->punt_client_pool, c);
+      punt_client_ip_proto_db_add (af, proto, c - pm->punt_client_pool);
+    }
+
+  memcpy (c->caddr.sun_path, client_pathname, sizeof (c->caddr.sun_path));
+  c->caddr.sun_family = AF_UNIX;
+  c->reg.type = PUNT_TYPE_IP_PROTO;
+  c->reg.punt.ip_proto.protocol = proto;
+  c->reg.punt.ip_proto.af = af;
+
+  if (af == AF_IP4)
+    ip4_register_protocol (proto, ip4_proto_punt_socket_node.index);
+  else
+    ip6_register_protocol (proto, ip6_proto_punt_socket_node.index);
+
+  return (NULL);
+}
+
 static clib_error_t *
 punt_socket_register_exception (vlib_main_t * vm,
                                vlib_punt_reason_t reason,
 static clib_error_t *
 punt_socket_register_exception (vlib_main_t * vm,
                                vlib_punt_reason_t reason,
@@ -202,6 +256,24 @@ punt_socket_unregister_l4 (ip_address_family_t af,
   return (NULL);
 }
 
   return (NULL);
 }
 
+static clib_error_t *
+punt_socket_unregister_ip_proto (ip_address_family_t af, ip_protocol_t proto)
+{
+  u32 pci;
+
+  if (af == AF_IP4)
+    ip4_unregister_protocol (proto);
+  else
+    ip6_unregister_protocol (proto);
+
+  pci = punt_client_ip_proto_db_remove (af, proto);
+
+  if (~0 != pci)
+    pool_put_index (punt_main.punt_client_pool, pci);
+
+  return (NULL);
+}
+
 static clib_error_t *
 punt_socket_unregister_exception (vlib_punt_reason_t reason)
 {
 static clib_error_t *
 punt_socket_unregister_exception (vlib_punt_reason_t reason)
 {
@@ -227,6 +299,12 @@ vnet_punt_socket_add (vlib_main_t * vm, u32 header_version,
   if (header_version != PUNT_PACKETDESC_VERSION)
     return clib_error_return (0, "Invalid packet descriptor version");
 
   if (header_version != PUNT_PACKETDESC_VERSION)
     return clib_error_return (0, "Invalid packet descriptor version");
 
+  if (strncmp (client_pathname, vnet_punt_get_server_pathname (),
+              UNIX_PATH_MAX) == 0)
+    return clib_error_return (0,
+                             "Punt socket: Invalid client path: %s",
+                             client_pathname);
+
   /* Register client */
   switch (pr->type)
     {
   /* Register client */
   switch (pr->type)
     {
@@ -235,6 +313,11 @@ vnet_punt_socket_add (vlib_main_t * vm, u32 header_version,
                                       pr->punt.l4.af,
                                       pr->punt.l4.protocol,
                                       pr->punt.l4.port, client_pathname));
                                       pr->punt.l4.af,
                                       pr->punt.l4.protocol,
                                       pr->punt.l4.port, client_pathname));
+    case PUNT_TYPE_IP_PROTO:
+      return (punt_socket_register_ip_proto (vm,
+                                            pr->punt.ip_proto.af,
+                                            pr->punt.ip_proto.protocol,
+                                            client_pathname));
     case PUNT_TYPE_EXCEPTION:
       return (punt_socket_register_exception (vm,
                                              pr->punt.exception.reason,
     case PUNT_TYPE_EXCEPTION:
       return (punt_socket_register_exception (vm,
                                              pr->punt.exception.reason,
@@ -258,6 +341,9 @@ vnet_punt_socket_del (vlib_main_t * vm, const punt_reg_t * pr)
       return (punt_socket_unregister_l4 (pr->punt.l4.af,
                                         pr->punt.l4.protocol,
                                         pr->punt.l4.port));
       return (punt_socket_unregister_l4 (pr->punt.l4.af,
                                         pr->punt.l4.protocol,
                                         pr->punt.l4.port));
+    case PUNT_TYPE_IP_PROTO:
+      return (punt_socket_unregister_ip_proto (pr->punt.ip_proto.af,
+                                              pr->punt.ip_proto.protocol));
     case PUNT_TYPE_EXCEPTION:
       return (punt_socket_unregister_exception (pr->punt.exception.reason));
     }
     case PUNT_TYPE_EXCEPTION:
       return (punt_socket_unregister_exception (pr->punt.exception.reason));
     }
@@ -330,13 +416,6 @@ punt_l4_add_del (vlib_main_t * vm,
     }
 }
 
     }
 }
 
-static clib_error_t *
-punt_exception_add_del (vlib_main_t * vm,
-                       vlib_punt_reason_t reason, bool is_add)
-{
-  return (NULL);
-}
-
 clib_error_t *
 vnet_punt_add_del (vlib_main_t * vm, const punt_reg_t * pr, bool is_add)
 {
 clib_error_t *
 vnet_punt_add_del (vlib_main_t * vm, const punt_reg_t * pr, bool is_add)
 {
@@ -346,7 +425,8 @@ vnet_punt_add_del (vlib_main_t * vm, const punt_reg_t * pr, bool is_add)
       return (punt_l4_add_del (vm, pr->punt.l4.af, pr->punt.l4.protocol,
                               pr->punt.l4.port, is_add));
     case PUNT_TYPE_EXCEPTION:
       return (punt_l4_add_del (vm, pr->punt.l4.af, pr->punt.l4.protocol,
                               pr->punt.l4.port, is_add));
     case PUNT_TYPE_EXCEPTION:
-      return (punt_exception_add_del (vm, pr->punt.exception.reason, is_add));
+    case PUNT_TYPE_IP_PROTO:
+      break;
     }
 
   return (clib_error_return (0, "Unsupported punt type: %d", pr->type));
     }
 
   return (clib_error_return (0, "Unsupported punt type: %d", pr->type));
@@ -560,11 +640,22 @@ punt_client_walk (punt_type_t pt, punt_client_walk_cb_t cb, void *ctx)
     {
     case PUNT_TYPE_L4:
       {
     {
     case PUNT_TYPE_L4:
       {
-       u32 pci;
-       u16 port;
+       u32 pci, key;
 
         /* *INDENT-OFF* */
 
         /* *INDENT-OFF* */
-        hash_foreach(port, pci, pm->db.clients_by_l4_port,
+        hash_foreach(key, pci, pm->db.clients_by_l4_port,
+        ({
+          cb (pool_elt_at_index(pm->punt_client_pool, pci), ctx);
+        }));
+        /* *INDENT-ON* */
+       break;
+      }
+    case PUNT_TYPE_IP_PROTO:
+      {
+       u32 pci, key;
+
+        /* *INDENT-OFF* */
+        hash_foreach(key, pci, pm->db.clients_by_ip_proto,
         ({
           cb (pool_elt_at_index(pm->punt_client_pool, pci), ctx);
         }));
         ({
           cb (pool_elt_at_index(pm->punt_client_pool, pci), ctx);
         }));
@@ -601,6 +692,11 @@ format_punt_client (u8 * s, va_list * args)
                  format_ip_protocol, pc->reg.punt.l4.protocol,
                  pc->reg.punt.l4.port);
       break;
                  format_ip_protocol, pc->reg.punt.l4.protocol,
                  pc->reg.punt.l4.port);
       break;
+    case PUNT_TYPE_IP_PROTO:
+      s = format (s, "%U %U",
+                 format_ip_address_family, pc->reg.punt.ip_proto.af,
+                 format_ip_protocol, pc->reg.punt.ip_proto.protocol);
+      break;
     case PUNT_TYPE_EXCEPTION:
       s = format (s, " %U", format_vlib_punt_reason,
                  pc->reg.punt.exception.reason);
     case PUNT_TYPE_EXCEPTION:
       s = format (s, " %U", format_vlib_punt_reason,
                  pc->reg.punt.exception.reason);
@@ -635,6 +731,8 @@ punt_socket_show_cmd (vlib_main_t * vm,
        pt = PUNT_TYPE_EXCEPTION;
       else if (unformat (input, "l4"))
        pt = PUNT_TYPE_L4;
        pt = PUNT_TYPE_EXCEPTION;
       else if (unformat (input, "l4"))
        pt = PUNT_TYPE_L4;
+      else if (unformat (input, "ip"))
+       pt = PUNT_TYPE_IP_PROTO;
       else
        {
          error = clib_error_return (0, "parse error: '%U'",
       else
        {
          error = clib_error_return (0, "parse error: '%U'",
index a77e633..8835f3e 100644 (file)
 #include <stdbool.h>
 #include <vnet/ip/ip.h>
 
 #include <stdbool.h>
 #include <vnet/ip/ip.h>
 
-#define foreach_punt_type \
-  _(L4, "l4")             \
-  _(EXCEPTION, "exception")
+#define foreach_punt_type                       \
+  _(L4, "l4")                                   \
+  _(EXCEPTION, "exception")                     \
+  _(IP_PROTO, "ip-proto")
 
 typedef enum punt_type_t_
 {
 
 typedef enum punt_type_t_
 {
@@ -42,6 +43,12 @@ typedef struct punt_l4_t_
   u16 port;
 } punt_l4_t;
 
   u16 port;
 } punt_l4_t;
 
+typedef struct punt_ip_proto_t_
+{
+  ip_address_family_t af;
+  ip_protocol_t protocol;
+} punt_ip_proto_t;
+
 typedef struct punt_exception_t_
 {
   vlib_punt_reason_t reason;
 typedef struct punt_exception_t_
 {
   vlib_punt_reason_t reason;
@@ -51,6 +58,7 @@ typedef struct punt_union_t_
 {
   punt_exception_t exception;
   punt_l4_t l4;
 {
   punt_exception_t exception;
   punt_l4_t l4;
+  punt_ip_proto_t ip_proto;
 } punt_union_t;
 
 typedef struct punt_reg_t_
 } punt_union_t;
 
 typedef struct punt_reg_t_
@@ -100,6 +108,7 @@ typedef struct punt_client_db_t_
 {
   void *clients_by_l4_port;
   u32 *clients_by_exception;
 {
   void *clients_by_l4_port;
   u32 *clients_by_exception;
+  void *clients_by_ip_proto;
 } punt_client_db_t;
 
 typedef struct
 } punt_client_db_t;
 
 typedef struct
@@ -146,6 +155,28 @@ punt_client_l4_get (ip_address_family_t af, u16 port)
   return (NULL);
 }
 
   return (NULL);
 }
 
+static_always_inline u32
+punt_client_ip_proto_mk_key (ip_address_family_t af, ip_protocol_t proto)
+{
+  return (af << 16 | proto);
+}
+
+static_always_inline punt_client_t *
+punt_client_ip_proto_get (ip_address_family_t af, ip_protocol_t proto)
+{
+  punt_main_t *pm = &punt_main;
+  uword *p;
+
+  p =
+    hash_get (pm->db.clients_by_ip_proto,
+             punt_client_ip_proto_mk_key (af, proto));
+
+  if (p)
+    return (pool_elt_at_index (pm->punt_client_pool, p[0]));
+
+  return (NULL);
+}
+
 static_always_inline punt_client_t *
 punt_client_exception_get (vlib_punt_reason_t reason)
 {
 static_always_inline punt_client_t *
 punt_client_exception_get (vlib_punt_reason_t reason)
 {
@@ -167,6 +198,8 @@ 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 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 ip4_proto_punt_socket_node;
+extern vlib_node_registration_t ip6_proto_punt_socket_node;
 extern vlib_node_registration_t punt_socket_rx_node;
 
 #endif
 extern vlib_node_registration_t punt_socket_rx_node;
 
 #endif
index 95fff71..b356886 100644 (file)
@@ -95,6 +95,18 @@ vl_api_punt_l4_decode (const vl_api_punt_l4_t * in, punt_l4_t * out)
   return (rv);
 }
 
   return (rv);
 }
 
+static int
+vl_api_punt_ip_proto_decode (const vl_api_punt_ip_proto_t * in,
+                            punt_ip_proto_t * out)
+{
+  int rv;
+
+  rv = ip_address_family_decode (in->af, &out->af);
+  rv += ip_proto_decode (in->protocol, &out->protocol);
+
+  return (rv);
+}
+
 static int
 vl_api_punt_exception_decode (const vl_api_punt_exception_t * in,
                              punt_exception_t * out)
 static int
 vl_api_punt_exception_decode (const vl_api_punt_exception_t * in,
                              punt_exception_t * out)
@@ -124,6 +136,9 @@ vl_api_punt_decode (const vl_api_punt_t * in, punt_reg_t * out)
     case PUNT_TYPE_EXCEPTION:
       return (vl_api_punt_exception_decode (&in->punt.exception,
                                            &out->punt.exception));
     case PUNT_TYPE_EXCEPTION:
       return (vl_api_punt_exception_decode (&in->punt.exception,
                                            &out->punt.exception));
+    case PUNT_TYPE_IP_PROTO:
+      return (vl_api_punt_ip_proto_decode (&in->punt.ip_proto,
+                                          &out->punt.ip_proto));
     }
 
   return (-1);
     }
 
   return (-1);
@@ -137,6 +152,14 @@ vl_api_punt_l4_encode (const punt_l4_t * in, vl_api_punt_l4_t * out)
   out->port = clib_net_to_host_u16 (in->port);
 }
 
   out->port = clib_net_to_host_u16 (in->port);
 }
 
+static void
+vl_api_punt_ip_proto_encode (const punt_ip_proto_t * in,
+                            vl_api_punt_ip_proto_t * out)
+{
+  out->af = ip_address_family_encode (in->af);
+  out->protocol = ip_proto_encode (in->protocol);
+}
+
 static void
 vl_api_punt_exception_encode (const punt_exception_t * in,
                              vl_api_punt_exception_t * out)
 static void
 vl_api_punt_exception_encode (const punt_exception_t * in,
                              vl_api_punt_exception_t * out)
@@ -154,6 +177,9 @@ vl_api_punt_encode (const punt_reg_t * in, vl_api_punt_t * out)
     case PUNT_TYPE_L4:
       vl_api_punt_l4_encode (&in->punt.l4, &out->punt.l4);
       break;
     case PUNT_TYPE_L4:
       vl_api_punt_l4_encode (&in->punt.l4, &out->punt.l4);
       break;
+    case PUNT_TYPE_IP_PROTO:
+      vl_api_punt_ip_proto_encode (&in->punt.ip_proto, &out->punt.ip_proto);
+      break;
     case PUNT_TYPE_EXCEPTION:
       vl_api_punt_exception_encode (&in->punt.exception,
                                    &out->punt.exception);
     case PUNT_TYPE_EXCEPTION:
       vl_api_punt_exception_encode (&in->punt.exception,
                                    &out->punt.exception);
index 53c8199..67f9743 100644 (file)
@@ -286,13 +286,29 @@ punt_socket_inline (vlib_main_t * vm,
              udp = (udp_header_t *) (ip + 1);
            }
 
              udp = (udp_header_t *) (ip + 1);
            }
 
-         u16 port = clib_net_to_host_u16 (udp->dst_port);
-
          /*
           * Find registerered client
           * If no registered client, drop packet and count
           */
          /*
           * Find registerered client
           * If no registered client, drop packet and count
           */
-         c = punt_client_l4_get (af, port);
+         c = punt_client_l4_get (af, clib_net_to_host_u16 (udp->dst_port));
+       }
+      else if (PUNT_TYPE_IP_PROTO == pt)
+       {
+         /* Reverse UDP Punt advance */
+         ip_protocol_t proto;
+
+         if (AF_IP4 == af)
+           {
+             ip4_header_t *ip = vlib_buffer_get_current (b);
+             proto = ip->protocol;
+           }
+         else
+           {
+             ip6_header_t *ip = vlib_buffer_get_current (b);
+             proto = ip->protocol;
+           }
+
+         c = punt_client_ip_proto_get (af, proto);
        }
       else if (PUNT_TYPE_EXCEPTION == pt)
        {
        }
       else if (PUNT_TYPE_EXCEPTION == pt)
        {
@@ -390,6 +406,22 @@ udp6_punt_socket (vlib_main_t * vm,
   return punt_socket_inline (vm, node, from_frame, PUNT_TYPE_L4, AF_IP6);
 }
 
   return punt_socket_inline (vm, node, from_frame, PUNT_TYPE_L4, AF_IP6);
 }
 
+static uword
+ip4_proto_punt_socket (vlib_main_t * vm,
+                      vlib_node_runtime_t * node, vlib_frame_t * from_frame)
+{
+  return punt_socket_inline (vm, node, from_frame,
+                            PUNT_TYPE_IP_PROTO, AF_IP4);
+}
+
+static uword
+ip6_proto_punt_socket (vlib_main_t * vm,
+                      vlib_node_runtime_t * node, vlib_frame_t * from_frame)
+{
+  return punt_socket_inline (vm, node, from_frame,
+                            PUNT_TYPE_IP_PROTO, AF_IP6);
+}
+
 static uword
 exception_punt_socket (vlib_main_t * vm,
                       vlib_node_runtime_t * node, vlib_frame_t * from_frame)
 static uword
 exception_punt_socket (vlib_main_t * vm,
                       vlib_node_runtime_t * node, vlib_frame_t * from_frame)
@@ -419,6 +451,25 @@ VLIB_REGISTER_NODE (udp6_punt_socket_node) = {
   .n_errors = PUNT_N_ERROR,
   .error_strings = punt_error_strings,
 };
   .n_errors = PUNT_N_ERROR,
   .error_strings = punt_error_strings,
 };
+VLIB_REGISTER_NODE (ip4_proto_punt_socket_node) = {
+  .function = ip4_proto_punt_socket,
+  .name = "ip4-proto-punt-socket",
+  .format_trace = format_udp_punt_trace,
+  .flags = VLIB_NODE_FLAG_IS_DROP,
+  /* Takes a vector of packets. */
+  .vector_size = sizeof (u32),
+  .n_errors = PUNT_N_ERROR,
+  .error_strings = punt_error_strings,
+};
+VLIB_REGISTER_NODE (ip6_proto_punt_socket_node) = {
+  .function = ip6_proto_punt_socket,
+  .name = "ip6-proto-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,
+};
 VLIB_REGISTER_NODE (exception_punt_socket_node) = {
   .function = exception_punt_socket,
   .name = "exception-punt-socket",
 VLIB_REGISTER_NODE (exception_punt_socket_node) = {
   .function = exception_punt_socket,
   .name = "exception-punt-socket",
index 28c17da..598f140 100644 (file)
@@ -22,6 +22,7 @@ from scapy.layers.inet import IP, UDP, ICMP
 from scapy.layers.ipsec import ESP
 import scapy.layers.inet6 as inet6
 from scapy.layers.inet6 import IPv6, ICMPv6DestUnreach
 from scapy.layers.ipsec import ESP
 import scapy.layers.inet6 as inet6
 from scapy.layers.inet6 import IPv6, ICMPv6DestUnreach
+from scapy.contrib.ospf import OSPF_Hdr, OSPFv3_Hello
 import six
 from framework import VppTestCase, VppTestRunner
 
 import six
 from framework import VppTestCase, VppTestRunner
 
@@ -130,6 +131,13 @@ class TestPuntSocket(VppTestCase):
         self.assertEqual(vpr.punt.punt.exception.id,
                          pr['punt']['exception']['id'])
 
         self.assertEqual(vpr.punt.punt.exception.id,
                          pr['punt']['exception']['id'])
 
+    def verify_ip_proto(self, pr, vpr):
+        self.assertEqual(vpr.punt.type, pr['type'])
+        self.assertEqual(vpr.punt.punt.ip_proto.af,
+                         pr['punt']['ip_proto']['af'])
+        self.assertEqual(vpr.punt.punt.ip_proto.protocol,
+                         pr['punt']['ip_proto']['protocol'])
+
     def verify_udp_pkts(self, rxs, n_rx, port):
         n_match = 0
         for rx in rxs:
     def verify_udp_pkts(self, rxs, n_rx, port):
         n_match = 0
         for rx in rxs:
@@ -182,7 +190,7 @@ def mk_vpp_cfg6():
 
 
 class TestIP4PuntSocket(TestPuntSocket):
 
 
 class TestIP4PuntSocket(TestPuntSocket):
-    """ Punt Socket for IPv4 """
+    """ Punt Socket for IPv4 UDP """
 
     @classmethod
     def setUpClass(cls):
 
     @classmethod
     def setUpClass(cls):
@@ -409,7 +417,7 @@ class TestIP4PuntSocket(TestPuntSocket):
 
 
 class TestIP6PuntSocket(TestPuntSocket):
 
 
 class TestIP6PuntSocket(TestPuntSocket):
-    """ Punt Socket for IPv6"""
+    """ Punt Socket for IPv6 UDP """
 
     @classmethod
     def setUpClass(cls):
 
     @classmethod
     def setUpClass(cls):
@@ -850,8 +858,157 @@ class TestExceptionPuntSocket(TestPuntSocket):
             self.vapi.punt_socket_deregister(cfg['vpp'])
 
 
             self.vapi.punt_socket_deregister(cfg['vpp'])
 
 
+class TestIpProtoPuntSocket(TestPuntSocket):
+    """ Punt Socket for IP packets """
+
+    @classmethod
+    def setUpClass(cls):
+        super(TestIpProtoPuntSocket, cls).setUpClass()
+
+    @classmethod
+    def tearDownClass(cls):
+        super(TestIpProtoPuntSocket, cls).tearDownClass()
+
+    def setUp(self):
+        super(TestIpProtoPuntSocket, self).setUp()
+
+        for i in self.pg_interfaces:
+            i.config_ip4()
+            i.resolve_arp()
+
+    def tearDown(self):
+        super(TestIpProtoPuntSocket, self).tearDown()
+        for i in self.pg_interfaces:
+            i.unconfig_ip4()
+            i.admin_down()
+
+    def test_registration(self):
+        """ Punt socket registration/deregistration"""
+
+        af_ip4 = VppEnum.vl_api_address_family_t.ADDRESS_IP4
+        pt_ip = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_IP_PROTO
+        proto_ospf = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_OSPF
+        proto_eigrp = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_EIGRP
+
+        punts = self.vapi.punt_socket_dump(type=pt_ip)
+        self.assertEqual(len(punts), 0)
+
+        #
+        # configure a punt socket
+        #
+        punt_ospf = {
+            'type': pt_ip,
+            'punt': {
+                'ip_proto': {
+                    'af': af_ip4,
+                    'protocol': proto_ospf
+                }
+            }
+        }
+        punt_eigrp = {
+            'type': pt_ip,
+            'punt': {
+                'ip_proto': {
+                    'af': af_ip4,
+                    'protocol': proto_eigrp
+                }
+            }
+        }
+
+        self.vapi.punt_socket_register(punt_ospf,
+                                       b"%s/socket_punt_1" %
+                                       six.ensure_binary(self.tempdir))
+        self.vapi.punt_socket_register(punt_eigrp,
+                                       b"%s/socket_punt_2" %
+                                       six.ensure_binary(self.tempdir))
+        self.logger.info(self.vapi.cli("sh punt sock reg ip"))
+        punts = self.vapi.punt_socket_dump(type=pt_ip)
+        self.assertEqual(len(punts), 2)
+        self.verify_ip_proto(punt_ospf, punts[0])
+        self.verify_ip_proto(punt_eigrp, punts[1])
+
+        #
+        # deregister a punt socket
+        #
+        self.vapi.punt_socket_deregister(punt_ospf)
+        punts = self.vapi.punt_socket_dump(type=pt_ip)
+        self.assertEqual(len(punts), 1)
+
+        #
+        # configure a punt socket again
+        #
+        self.vapi.punt_socket_register(punt_ospf,
+                                       b"%s/socket_punt_3" %
+                                       six.ensure_binary(self.tempdir))
+        punts = self.vapi.punt_socket_dump(type=pt_ip)
+        self.assertEqual(len(punts), 2)
+
+        self.logger.info(self.vapi.cli("sh punt sock reg exception"))
+
+        #
+        # deregister all punt socket
+        #
+        self.vapi.punt_socket_deregister(punt_eigrp)
+        self.vapi.punt_socket_deregister(punt_ospf)
+        punts = self.vapi.punt_socket_dump(type=pt_ip)
+        self.assertEqual(len(punts), 0)
+
+    def verify_ospf_pkts(self, rxs, n_sent):
+        self.assertEqual(len(rxs), n_sent)
+        for rx in rxs:
+            self.assertTrue(rx.haslayer(OSPF_Hdr))
+
+    def test_traffic(self):
+        """ Punt socket traffic """
+
+        af_ip4 = VppEnum.vl_api_address_family_t.ADDRESS_IP4
+        pt_ip = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_IP_PROTO
+        proto_ospf = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_OSPF
+
+        #
+        # configure a punt socket to capture OSPF packets
+        #
+        punt_ospf = {
+            'type': pt_ip,
+            'punt': {
+                'ip_proto': {
+                    'af': af_ip4,
+                    'protocol': proto_ospf
+                }
+            }
+        }
+
+        #
+        # create packet streams and configure a punt sockets
+        #
+        pkt = (Ether(src=self.pg0.remote_mac,
+                     dst=self.pg0.local_mac) /
+               IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) /
+               OSPF_Hdr() /
+               OSPFv3_Hello())
+        pkts = pkt * 7
+
+        sock = self.socket_client_create(b"%s/socket_1" % (
+            six.ensure_binary(self.tempdir)))
+        self.vapi.punt_socket_register(
+            punt_ospf,
+            b"%s/socket_1" % (six.ensure_binary(self.tempdir)))
+
+        #
+        # send packets for each SPI we expect to be punted
+        #
+        self.send_and_assert_no_replies(self.pg0, pkts)
+
+        #
+        # verify the punted packets arrived on the associated socket
+        #
+        rx = sock.close()
+        self.verify_ospf_pkts(rx, len(pkts))
+        self.vapi.punt_socket_deregister(punt_ospf)
+
+
 class TestPunt(VppTestCase):
 class TestPunt(VppTestCase):
-    """ Punt Test Case """
+    """ Exception Punt Test Case """
 
     @classmethod
     def setUpClass(cls):
 
     @classmethod
     def setUpClass(cls):