Punt Infra

A punt/exception path that provides:
 1) clients that use the infra
 2) clients can create punt reasons
 3) clients can register to recieve packets that are punted
    for a given reason to be sent to the desired node.
 4) nodes which punt packets fill in the {reason,protocol} of the
    buffere (in the meta-data) and send to the new node "punt-dispatch"
 5) punt-dispatch sends packets to the registered nodes or drops

Change-Id: Ia4f144337f1387cbe585b4f375d0842aefffcde5
Signed-off-by: Neale Ranns <nranns@cisco.com>
diff --git a/src/vnet/vxlan-gbp/decap.c b/src/vnet/vxlan-gbp/decap.c
index 7dc8d25..c520e25 100644
--- a/src/vnet/vxlan-gbp/decap.c
+++ b/src/vnet/vxlan-gbp/decap.c
@@ -16,7 +16,7 @@
  */
 
 #include <vlib/vlib.h>
-#include <vnet/pg/pg.h>
+
 #include <vnet/vxlan-gbp/vxlan_gbp.h>
 
 typedef struct
@@ -309,7 +309,13 @@
 	      else
 		{
 		  error0 = VXLAN_GBP_ERROR_NO_SUCH_TUNNEL;
-		  next0 = VXLAN_GBP_INPUT_NEXT_NO_TUNNEL;
+		  next0 = VXLAN_GBP_INPUT_NEXT_PUNT;
+		  if (is_ip4)
+		    b0->punt_reason =
+		      vxm->punt_no_such_tunnel[FIB_PROTOCOL_IP4];
+		  else
+		    b0->punt_reason =
+		      vxm->punt_no_such_tunnel[FIB_PROTOCOL_IP6];
 		}
 	      b0->error = node->errors[error0];
 	    }
@@ -342,7 +348,13 @@
 	      else
 		{
 		  error1 = VXLAN_GBP_ERROR_NO_SUCH_TUNNEL;
-		  next1 = VXLAN_GBP_INPUT_NEXT_NO_TUNNEL;
+		  next1 = VXLAN_GBP_INPUT_NEXT_PUNT;
+		  if (is_ip4)
+		    b1->punt_reason =
+		      vxm->punt_no_such_tunnel[FIB_PROTOCOL_IP4];
+		  else
+		    b1->punt_reason =
+		      vxm->punt_no_such_tunnel[FIB_PROTOCOL_IP6];
 		}
 	      b1->error = node->errors[error1];
 	    }
@@ -444,7 +456,13 @@
 	      else
 		{
 		  error0 = VXLAN_GBP_ERROR_NO_SUCH_TUNNEL;
-		  next0 = VXLAN_GBP_INPUT_NEXT_NO_TUNNEL;
+		  next0 = VXLAN_GBP_INPUT_NEXT_PUNT;
+		  if (is_ip4)
+		    b0->punt_reason =
+		      vxm->punt_no_such_tunnel[FIB_PROTOCOL_IP4];
+		  else
+		    b0->punt_reason =
+		      vxm->punt_no_such_tunnel[FIB_PROTOCOL_IP6];
 		}
 	      b0->error = node->errors[error0];
 	    }
diff --git a/src/vnet/vxlan-gbp/vxlan_gbp.c b/src/vnet/vxlan-gbp/vxlan_gbp.c
index db10f54..e39c26f 100644
--- a/src/vnet/vxlan-gbp/vxlan_gbp.c
+++ b/src/vnet/vxlan-gbp/vxlan_gbp.c
@@ -28,7 +28,7 @@
  *
  * VXLAN GBP provides the features of vxlan and carry group policy id.
  */
-
+static vlib_punt_hdl_t punt_hdl;
 
 vxlan_gbp_main_t vxlan_gbp_main;
 
@@ -1144,10 +1144,14 @@
 vxlan_gbp_init (vlib_main_t * vm)
 {
   vxlan_gbp_main_t *vxm = &vxlan_gbp_main;
+  clib_error_t *error;
 
   vxm->vnet_main = vnet_get_main ();
   vxm->vlib_main = vm;
 
+  if ((error = vlib_call_init_function (vm, punt_init)))
+    return (error);
+
   /* initialize the ip6 hash */
   clib_bihash_init_16_8 (&vxm->vxlan4_gbp_tunnel_by_key, "vxlan4-gbp",
 			 VXLAN_GBP_HASH_NUM_BUCKETS,
@@ -1162,7 +1166,16 @@
 
   fib_node_register_type (FIB_NODE_TYPE_VXLAN_GBP_TUNNEL, &vxlan_gbp_vft);
 
-  return 0;
+  punt_hdl = vlib_punt_client_register ("vxlan-gbp");
+
+  vlib_punt_reason_alloc (punt_hdl,
+			  "VXLAN-GBP-no-such-v4-tunnel",
+			  &vxm->punt_no_such_tunnel[FIB_PROTOCOL_IP4]);
+  vlib_punt_reason_alloc (punt_hdl,
+			  "VXLAN-GBP-no-such-v6-tunnel",
+			  &vxm->punt_no_such_tunnel[FIB_PROTOCOL_IP6]);
+
+  return (error);
 }
 
 VLIB_INIT_FUNCTION (vxlan_gbp_init);
diff --git a/src/vnet/vxlan-gbp/vxlan_gbp.h b/src/vnet/vxlan-gbp/vxlan_gbp.h
index 6dc6225..6580f38 100644
--- a/src/vnet/vxlan-gbp/vxlan_gbp.h
+++ b/src/vnet/vxlan-gbp/vxlan_gbp.h
@@ -132,7 +132,7 @@
 
 #define foreach_vxlan_gbp_input_next         \
   _(DROP, "error-drop")                      \
-  _(NO_TUNNEL, "error-punt")                 \
+  _(PUNT, "punt-dispatch")                   \
   _(L2_INPUT, "l2-input")                    \
   _(IP4_INPUT, "ip4-input")                  \
   _(IP6_INPUT, "ip6-input")
@@ -189,6 +189,11 @@
 
   /* Record used instances */
   uword *instance_used;
+
+  /**
+   * Punt reasons for no such tunnel
+   */
+  vlib_punt_reason_t punt_no_such_tunnel[FIB_PROTOCOL_IP_MAX];
 } vxlan_gbp_main_t;
 
 extern vxlan_gbp_main_t vxlan_gbp_main;