ip: add support for buffer offload metadata in ip midchain
[vpp.git] / src / vnet / ip / ip_punt_drop.h
index ccf88e5..11b7ad6 100644 (file)
 typedef struct ip_punt_policer_t_
 {
   u32 policer_index;
+  u32 fq_index;
 } ip_punt_policer_t;
 
 typedef enum ip_punt_policer_next_t_
 {
   IP_PUNT_POLICER_NEXT_DROP,
+  IP_PUNT_POLICER_NEXT_HANDOFF,
   IP_PUNT_POLICER_N_NEXT,
 } ip_punt_policer_next_t;
 
@@ -53,6 +55,10 @@ typedef enum
 } ip_punt_policer_error_t;
 
 extern u8 *format_ip_punt_policer_trace (u8 * s, va_list * args);
+extern vlib_node_registration_t ip4_punt_policer_node;
+extern ip_punt_policer_t ip4_punt_policer_cfg;
+extern vlib_node_registration_t ip6_punt_policer_node;
+extern ip_punt_policer_t ip6_punt_policer_cfg;
 
 /**
  * IP punt policing node function
@@ -97,45 +103,52 @@ ip_punt_policer (vlib_main_t * vm,
          b0 = vlib_get_buffer (vm, bi0);
          b1 = vlib_get_buffer (vm, bi1);
 
-         vnet_get_config_data (&cm->config_main,
-                               &b0->current_config_index, &next0, 0);
-         vnet_get_config_data (&cm->config_main,
-                               &b1->current_config_index, &next1, 0);
-
-         act0 = vnet_policer_police (vm, b0,
-                                     policer_index,
-                                     time_in_policer_periods,
-                                     POLICE_CONFORM);
-         act1 = vnet_policer_police (vm, b1,
-                                     policer_index,
-                                     time_in_policer_periods,
-                                     POLICE_CONFORM);
-
-         if (PREDICT_FALSE (act0 == SSE2_QOS_ACTION_DROP))
-           {
-             next0 = IP_PUNT_POLICER_NEXT_DROP;
-             b0->error = node->errors[IP_PUNT_POLICER_ERROR_DROP];
-           }
-         if (PREDICT_FALSE (act1 == SSE2_QOS_ACTION_DROP))
-           {
-             next1 = IP_PUNT_POLICER_NEXT_DROP;
-             b1->error = node->errors[IP_PUNT_POLICER_ERROR_DROP];
-           }
+         act0 = vnet_policer_police (vm, b0, policer_index,
+                                     time_in_policer_periods, POLICE_CONFORM,
+                                     true);
+         act1 = vnet_policer_police (vm, b1, policer_index,
+                                     time_in_policer_periods, POLICE_CONFORM,
+                                     true);
 
-         if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
+         if (PREDICT_FALSE (act0 == QOS_ACTION_HANDOFF))
            {
-             ip_punt_policer_trace_t *t =
-               vlib_add_trace (vm, node, b0, sizeof (*t));
-             t->next = next0;
-             t->policer_index = policer_index;
+             next0 = next1 = IP_PUNT_POLICER_NEXT_HANDOFF;
            }
-         if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
+         else
            {
-             ip_punt_policer_trace_t *t =
-               vlib_add_trace (vm, node, b1, sizeof (*t));
-             t->next = next1;
-             t->policer_index = policer_index;
+
+             vnet_get_config_data (&cm->config_main,
+                                   &b0->current_config_index, &next0, 0);
+             vnet_get_config_data (&cm->config_main,
+                                   &b1->current_config_index, &next1, 0);
+
+             if (PREDICT_FALSE (act0 == QOS_ACTION_DROP))
+               {
+                 next0 = IP_PUNT_POLICER_NEXT_DROP;
+                 b0->error = node->errors[IP_PUNT_POLICER_ERROR_DROP];
+               }
+             if (PREDICT_FALSE (act1 == QOS_ACTION_DROP))
+               {
+                 next1 = IP_PUNT_POLICER_NEXT_DROP;
+                 b1->error = node->errors[IP_PUNT_POLICER_ERROR_DROP];
+               }
+
+             if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
+               {
+                 ip_punt_policer_trace_t *t =
+                   vlib_add_trace (vm, node, b0, sizeof (*t));
+                 t->next = next0;
+                 t->policer_index = policer_index;
+               }
+             if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
+               {
+                 ip_punt_policer_trace_t *t =
+                   vlib_add_trace (vm, node, b1, sizeof (*t));
+                 t->next = next1;
+                 t->policer_index = policer_index;
+               }
            }
+
          vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next,
                                           n_left_to_next,
                                           bi0, bi1, next0, next1);
@@ -157,27 +170,32 @@ ip_punt_policer (vlib_main_t * vm,
 
          b0 = vlib_get_buffer (vm, bi0);
 
-         vnet_get_config_data (&cm->config_main,
-                               &b0->current_config_index, &next0, 0);
-
-         act0 = vnet_policer_police (vm, b0,
-                                     policer_index,
-                                     time_in_policer_periods,
-                                     POLICE_CONFORM);
-         if (PREDICT_FALSE (act0 == SSE2_QOS_ACTION_DROP))
+         act0 = vnet_policer_police (vm, b0, policer_index,
+                                     time_in_policer_periods, POLICE_CONFORM,
+                                     true);
+         if (PREDICT_FALSE (act0 == QOS_ACTION_HANDOFF))
            {
-             next0 = IP_PUNT_POLICER_NEXT_DROP;
-             b0->error = node->errors[IP_PUNT_POLICER_ERROR_DROP];
+             next0 = IP_PUNT_POLICER_NEXT_HANDOFF;
            }
-
-         if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
+         else
            {
-             ip_punt_policer_trace_t *t =
-               vlib_add_trace (vm, node, b0, sizeof (*t));
-             t->next = next0;
-             t->policer_index = policer_index;
-           }
+             vnet_get_config_data (&cm->config_main,
+                                   &b0->current_config_index, &next0, 0);
+
+             if (PREDICT_FALSE (act0 == QOS_ACTION_DROP))
+               {
+                 next0 = IP_PUNT_POLICER_NEXT_DROP;
+                 b0->error = node->errors[IP_PUNT_POLICER_ERROR_DROP];
+               }
 
+             if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
+               {
+                 ip_punt_policer_trace_t *t =
+                   vlib_add_trace (vm, node, b0, sizeof (*t));
+                 t->next = next0;
+                 t->policer_index = policer_index;
+               }
+           }
          vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
                                           n_left_to_next, bi0, next0);
        }
@@ -194,19 +212,19 @@ ip_punt_policer (vlib_main_t * vm,
 typedef struct ip_punt_redirect_rx_t_
 {
   /**
-   * The next-hop to send redirected packets to
+   * Node linkage into the FIB graph
    */
-  ip46_address_t nh;
+  fib_node_t node;
 
-  /**
-   * the TX interface to send redirected packets
-   */
-  u32 tx_sw_if_index;
+  fib_protocol_t fproto;
+  fib_forward_chain_type_t payload_type;
+  fib_node_index_t pl;
+  u32 sibling;
 
   /**
-   * redirect forwarding adjacency
+   * redirect forwarding
    */
-  adj_index_t adj_index;
+  dpo_id_t dpo;
 } ip_punt_redirect_rx_t;
 
 /**
@@ -214,16 +232,17 @@ typedef struct ip_punt_redirect_rx_t_
  */
 typedef struct ip_punt_redirect_t_
 {
-    /**
-     * any RX interface redirect
-     */
-  ip_punt_redirect_rx_t any_rx_sw_if_index;
+  ip_punt_redirect_rx_t *pool;
+
+  /**
+   * per-RX interface configuration.
+   *  sw_if_index = 0 (from which packets are never received) is used to
+   *  indicate 'from-any'
+   */
+  index_t *redirect_by_rx_sw_if_index[FIB_PROTOCOL_IP_MAX];
+} ip_punt_redirect_cfg_t;
 
-    /**
-    * per-RX interface configuration
-    */
-  ip_punt_redirect_rx_t *redirect_by_rx_sw_if_index;
-} ip_punt_redirect_t;
+extern ip_punt_redirect_cfg_t ip_punt_redirect_cfg;
 
 /**
  * IP punt redirect next nodes
@@ -241,75 +260,50 @@ typedef enum ip_punt_redirect_next_t_
  */
 typedef struct ip4_punt_redirect_trace_t_
 {
-  ip_punt_redirect_rx_t redirect;
+  index_t rrxi;
   u32 next;
 } ip_punt_redirect_trace_t;
 
-typedef struct ip_punt_redirect_detail_t_
-{
-  /**
-   * the RX interface
-   */
-  u32 rx_sw_if_index;
-  /**
-   * IP punt redirect configuration
-   */
-  ip_punt_redirect_rx_t punt_redirect;
-} ip_punt_redirect_detail_t;
-
 /**
  * Add a punt redirect entry
  */
-extern void ip_punt_redirect_add (ip_punt_redirect_t * cfg,
-                                 u32 rx_sw_if_index,
-                                 ip_punt_redirect_rx_t * redirect,
-                                 fib_protocol_t fproto, vnet_link_t linkt);
-extern void ip_punt_redirect_del (ip_punt_redirect_t * cfg,
-                                 u32 rx_sw_if_index);
+extern void ip_punt_redirect_add (fib_protocol_t fproto, u32 rx_sw_if_index,
+                                 fib_forward_chain_type_t ct,
+                                 const fib_route_path_t *rpaths);
+
+extern void ip_punt_redirect_del (fib_protocol_t fproto, u32 rx_sw_if_index);
+extern index_t ip_punt_redirect_find (fib_protocol_t fproto,
+                                     u32 rx_sw_if_index);
 extern u8 *format_ip_punt_redirect (u8 * s, va_list * args);
 
 extern u8 *format_ip_punt_redirect_trace (u8 * s, va_list * args);
 
-extern ip_punt_redirect_detail_t *ip4_punt_redirect_entries (u32 sw_if_index);
-extern ip_punt_redirect_detail_t *ip6_punt_redirect_entries (u32 sw_if_index);
+typedef walk_rc_t (*ip_punt_redirect_walk_cb_t) (u32 rx_sw_if_index,
+                                                const ip_punt_redirect_rx_t *
+                                                redirect, void *arg);
+extern void ip_punt_redirect_walk (fib_protocol_t fproto,
+                                  ip_punt_redirect_walk_cb_t cb, void *ctx);
 
-always_inline u32
-ip_punt_redirect_tx_via_adj (vlib_buffer_t * b0, adj_index_t ai)
+static_always_inline ip_punt_redirect_rx_t *
+ip_punt_redirect_get (index_t rrxi)
 {
-  ip_adjacency_t *adj = adj_get (ai);
-  u32 next0;
-
-  vnet_buffer (b0)->ip.adj_index[VLIB_TX] = ai;
-
-  switch (adj->lookup_next_index)
-    {
-    case IP_LOOKUP_NEXT_ARP:
-      next0 = IP_PUNT_REDIRECT_NEXT_ARP;
-      break;
-    case IP_LOOKUP_NEXT_REWRITE:
-      next0 = IP_PUNT_REDIRECT_NEXT_TX;
-      break;
-    default:
-      next0 = IP_PUNT_REDIRECT_NEXT_DROP;
-      break;
-    }
-
-  return (next0);
+  return (pool_elt_at_index (ip_punt_redirect_cfg.pool, rrxi));
 }
 
 always_inline uword
 ip_punt_redirect (vlib_main_t * vm,
                  vlib_node_runtime_t * node,
-                 vlib_frame_t * frame,
-                 u8 arc_index, ip_punt_redirect_t * redirect)
+                 vlib_frame_t * frame, u8 arc_index, fib_protocol_t fproto)
 {
   u32 *from, *to_next, n_left_from, n_left_to_next, next_index;
   vnet_feature_main_t *fm = &feature_main;
   vnet_feature_config_main_t *cm = &fm->feature_config_mains[arc_index];
+  index_t *redirects;
 
   from = vlib_frame_vector_args (frame);
   n_left_from = frame->n_vectors;
   next_index = node->cached_next_index;
+  redirects = ip_punt_redirect_cfg.redirect_by_rx_sw_if_index[fproto];
 
   while (n_left_from > 0)
     {
@@ -317,13 +311,13 @@ ip_punt_redirect (vlib_main_t * vm,
 
       while (n_left_from > 0 && n_left_to_next > 0)
        {
-         u32 rx_sw_if_index0;
+         u32 rx_sw_if_index0, rrxi0;
          ip_punt_redirect_rx_t *rrx0;
          vlib_buffer_t *b0;
          u32 next0;
          u32 bi0;
 
-         rrx0 = NULL;
+         rrxi0 = INDEX_INVALID;
          next0 = 0;
          bi0 = to_next[0] = from[0];
 
@@ -339,24 +333,26 @@ ip_punt_redirect (vlib_main_t * vm,
 
          rx_sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
 
-         if (vec_len (redirect->redirect_by_rx_sw_if_index) >
-             rx_sw_if_index0)
+         /*
+          * If config exists for this particular RX interface use it,
+          * else use the default (at RX = 0)
+          */
+         if (vec_len (redirects) > rx_sw_if_index0)
            {
-             rrx0 = &redirect->redirect_by_rx_sw_if_index[rx_sw_if_index0];
-             if (~0 != rrx0->tx_sw_if_index)
-               {
-                 next0 = ip_punt_redirect_tx_via_adj (b0, rrx0->adj_index);
-               }
-             else if (~0 != redirect->any_rx_sw_if_index.tx_sw_if_index)
-               {
-                 rrx0 = &redirect->any_rx_sw_if_index;
-                 next0 = ip_punt_redirect_tx_via_adj (b0, rrx0->adj_index);
-               }
+             rrxi0 = redirects[rx_sw_if_index0];
+             if (INDEX_INVALID == rrxi0)
+               rrxi0 = redirects[0];
            }
-         else if (~0 != redirect->any_rx_sw_if_index.tx_sw_if_index)
+         else if (vec_len (redirects) >= 1)
+           rrxi0 = redirects[0];
+
+         if (PREDICT_TRUE (INDEX_INVALID != rrxi0))
            {
-             rrx0 = &redirect->any_rx_sw_if_index;
-             next0 = ip_punt_redirect_tx_via_adj (b0, rrx0->adj_index);
+             /* prevent ttl decrement on forward */
+             b0->flags |= VNET_BUFFER_F_LOCALLY_ORIGINATED;
+             rrx0 = ip_punt_redirect_get (rrxi0);
+             vnet_buffer (b0)->ip.adj_index[VLIB_TX] = rrx0->dpo.dpoi_index;
+             next0 = rrx0->dpo.dpoi_next_node;
            }
 
          if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
@@ -364,8 +360,7 @@ ip_punt_redirect (vlib_main_t * vm,
              ip_punt_redirect_trace_t *t =
                vlib_add_trace (vm, node, b0, sizeof (*t));
              t->next = next0;
-             if (rrx0)
-               t->redirect = *rrx0;
+             t->rrxi = rrxi0;
            }
 
          vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,