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);
+void ip4_unregister_protocol (u32 protocolx);
 
 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);
 }
+
+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 *
@@ -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]];
-         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;
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);
+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;
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);
 }
 
+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)
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,
+  IP_API_PROTO_EIGRP = 88,
+  IP_API_PROTO_OSPF = 89,
 };
 
 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)
 {
-  vl_api_ip_proto_t ipp = clib_host_to_net_u32 (_ipp);
+  ip_protocol_t ipp = clib_host_to_net_u32 (_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);
 }
@@ -84,12 +84,11 @@ ip_proto_encode (ip_protocol_t 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);
index cedddc5..6cb2731 100644 (file)
@@ -22,6 +22,8 @@ enum punt_type
 {
     /* 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,
 };
@@ -38,6 +40,16 @@ typedef punt_l4
     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
 */
@@ -52,6 +64,7 @@ union punt_union
 {
     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
index d4d5028..296df59 100644 (file)
@@ -74,6 +74,36 @@ punt_client_l4_db_remove (ip_address_family_t af, u16 port)
   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)
 {
@@ -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 (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)
@@ -159,6 +183,36 @@ punt_socket_register_l4 (vlib_main_t * vm,
   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,
@@ -202,6 +256,24 @@ punt_socket_unregister_l4 (ip_address_family_t af,
   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)
 {
@@ -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 (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)
     {
@@ -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));
+    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,
@@ -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));
+    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));
     }
@@ -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)
 {
@@ -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_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));
@@ -560,11 +640,22 @@ punt_client_walk (punt_type_t pt, punt_client_walk_cb_t cb, void *ctx)
     {
     case PUNT_TYPE_L4:
       {
-       u32 pci;
-       u16 port;
+       u32 pci, key;
 
         /* *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);
         }));
@@ -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;
+    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);
@@ -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;
+      else if (unformat (input, "ip"))
+       pt = PUNT_TYPE_IP_PROTO;
       else
        {
          error = clib_error_return (0, "parse error: '%U'",
index a77e633..8835f3e 100644 (file)
 #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_
 {
@@ -42,6 +43,12 @@ typedef struct 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;
@@ -51,6 +58,7 @@ typedef struct punt_union_t_
 {
   punt_exception_t exception;
   punt_l4_t l4;
+  punt_ip_proto_t ip_proto;
 } 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_ip_proto;
 } punt_client_db_t;
 
 typedef struct
@@ -146,6 +155,28 @@ punt_client_l4_get (ip_address_family_t af, u16 port)
   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)
 {
@@ -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 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
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);
 }
 
+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)
@@ -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_IP_PROTO:
+      return (vl_api_punt_ip_proto_decode (&in->punt.ip_proto,
+                                          &out->punt.ip_proto));
     }
 
   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);
 }
 
+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)
@@ -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_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);
index 53c8199..67f9743 100644 (file)
@@ -286,13 +286,29 @@ punt_socket_inline (vlib_main_t * vm,
              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
           */
-         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)
        {
@@ -390,6 +406,22 @@ udp6_punt_socket (vlib_main_t * vm,
   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)
@@ -419,6 +451,25 @@ VLIB_REGISTER_NODE (udp6_punt_socket_node) = {
   .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",
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.contrib.ospf import OSPF_Hdr, OSPFv3_Hello
 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'])
 
+    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:
@@ -182,7 +190,7 @@ def mk_vpp_cfg6():
 
 
 class TestIP4PuntSocket(TestPuntSocket):
-    """ Punt Socket for IPv4 """
+    """ Punt Socket for IPv4 UDP """
 
     @classmethod
     def setUpClass(cls):
@@ -409,7 +417,7 @@ class TestIP4PuntSocket(TestPuntSocket):
 
 
 class TestIP6PuntSocket(TestPuntSocket):
-    """ Punt Socket for IPv6"""
+    """ Punt Socket for IPv6 UDP """
 
     @classmethod
     def setUpClass(cls):
@@ -850,8 +858,157 @@ class TestExceptionPuntSocket(TestPuntSocket):
             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):
-    """ Punt Test Case """
+    """ Exception Punt Test Case """
 
     @classmethod
     def setUpClass(cls):