ip: Use .api declared error counters
[vpp.git] / src / vnet / mpls / mpls_output.c
index 247f531..3ea6ce5 100644 (file)
  */
 
 #include <vlib/vlib.h>
-#include <vnet/pg/pg.h>
 #include <vnet/ip/ip.h>
 #include <vnet/mpls/mpls.h>
 #include <vnet/ip/ip_frag.h>
+#include <vnet/adj/adj_dp.h>
 
 typedef struct {
   /* Adjacency taken. */
@@ -200,36 +200,32 @@ mpls_output_inline (vlib_main_t * vm,
             }
           if (mode == MPLS_OUTPUT_MIDCHAIN_MODE)
           {
-             adj0->sub_type.midchain.fixup_func
-                (vm, adj0, p0,
-                 adj0->sub_type.midchain.fixup_data);
-             adj1->sub_type.midchain.fixup_func
-                (vm, adj1, p1,
-                 adj1->sub_type.midchain.fixup_data);
-          }
+           adj_midchain_fixup (vm, adj0, p0, VNET_LINK_MPLS);
+           adj_midchain_fixup (vm, adj1, p1, VNET_LINK_MPLS);
+         }
 
-          p0->error = error_node->errors[error0];
-          p1->error = error_node->errors[error1];
+         p0->error = error_node->errors[error0];
+         p1->error = error_node->errors[error1];
 
-          if (PREDICT_FALSE(p0->flags & VLIB_BUFFER_IS_TRACED))
-            {
-              mpls_output_trace_t *tr = vlib_add_trace (vm, node,
-                                                        p0, sizeof (*tr));
-              tr->adj_index = vnet_buffer(p0)->ip.adj_index[VLIB_TX];
-              tr->flow_hash = vnet_buffer(p0)->ip.flow_hash;
-            }
-          if (PREDICT_FALSE(p1->flags & VLIB_BUFFER_IS_TRACED))
-            {
-              mpls_output_trace_t *tr = vlib_add_trace (vm, node,
-                                                        p1, sizeof (*tr));
-              tr->adj_index = vnet_buffer(p1)->ip.adj_index[VLIB_TX];
-              tr->flow_hash = vnet_buffer(p1)->ip.flow_hash;
-            }
+         if (PREDICT_FALSE (p0->flags & VLIB_BUFFER_IS_TRACED))
+           {
+             mpls_output_trace_t *tr =
+               vlib_add_trace (vm, node, p0, sizeof (*tr));
+             tr->adj_index = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
+             tr->flow_hash = vnet_buffer (p0)->ip.flow_hash;
+           }
+         if (PREDICT_FALSE (p1->flags & VLIB_BUFFER_IS_TRACED))
+           {
+             mpls_output_trace_t *tr =
+               vlib_add_trace (vm, node, p1, sizeof (*tr));
+             tr->adj_index = vnet_buffer (p1)->ip.adj_index[VLIB_TX];
+             tr->flow_hash = vnet_buffer (p1)->ip.flow_hash;
+           }
 
-          vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
-                                           to_next, n_left_to_next,
-                                           pi0, pi1, next0, next1);
-        }
+         vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next,
+                                          n_left_to_next, pi0, pi1, next0,
+                                          next1);
+       }
 
       while (n_left_from > 0 && n_left_to_next > 0)
         {
@@ -249,9 +245,9 @@ mpls_output_inline (vlib_main_t * vm,
          hdr0 = vlib_buffer_get_current (p0);
 
          /* Guess we are only writing on simple Ethernet header. */
-          vnet_rewrite_one_header (adj0[0], hdr0, 
+          vnet_rewrite_one_header (adj0[0], hdr0,
                                    sizeof (ethernet_header_t));
-          
+
           /* Update packet buffer attributes/set output interface. */
           rw_len0 = adj0[0].rewrite_header.data_bytes;
           vnet_buffer (p0)->mpls.save_rewrite_length = rw_len0;
@@ -289,21 +285,19 @@ mpls_output_inline (vlib_main_t * vm,
             }
           if (mode == MPLS_OUTPUT_MIDCHAIN_MODE)
           {
-             adj0->sub_type.midchain.fixup_func
-                (vm, adj0, p0,
-                 adj0->sub_type.midchain.fixup_data);
-          }
+           adj_midchain_fixup (vm, adj0, p0, VNET_LINK_MPLS);
+         }
 
-          p0->error = error_node->errors[error0];
+         p0->error = error_node->errors[error0];
 
          from += 1;
          n_left_from -= 1;
          to_next += 1;
          n_left_to_next -= 1;
-      
-          if (PREDICT_FALSE(p0->flags & VLIB_BUFFER_IS_TRACED)) 
+
+          if (PREDICT_FALSE(p0->flags & VLIB_BUFFER_IS_TRACED))
             {
-              mpls_output_trace_t *tr = vlib_add_trace (vm, node, 
+              mpls_output_trace_t *tr = vlib_add_trace (vm, node,
                                                         p0, sizeof (*tr));
               tr->adj_index = vnet_buffer(p0)->ip.adj_index[VLIB_TX];
               tr->flow_hash = vnet_buffer(p0)->ip.flow_hash;
@@ -369,12 +363,6 @@ VLIB_REGISTER_NODE (mpls_midchain_node) = {
   .format_trace = format_mpls_output_trace,
 };
 
-static char *mpls_frag_error_strings[] = {
-#define _(sym,string) string,
-  foreach_ip_frag_error
-#undef _
-};
-
 typedef struct mpls_frag_trace_t_
 {
     u16 pkt_size;
@@ -383,11 +371,12 @@ typedef struct mpls_frag_trace_t_
 
 typedef enum
 {
-    MPLS_FRAG_NEXT_REWRITE,
-    MPLS_FRAG_NEXT_REWRITE_MIDCHAIN,
-    MPLS_FRAG_NEXT_ICMP_ERROR,
-    MPLS_FRAG_NEXT_DROP,
-    MPLS_FRAG_N_NEXT,
+  MPLS_FRAG_NEXT_REWRITE,
+  MPLS_FRAG_NEXT_REWRITE_MIDCHAIN,
+  MPLS_FRAG_NEXT_ICMP4_ERROR,
+  MPLS_FRAG_NEXT_ICMP6_ERROR,
+  MPLS_FRAG_NEXT_DROP,
+  MPLS_FRAG_N_NEXT,
 } mpls_frag_next_t;
 
 static uword
@@ -396,9 +385,7 @@ mpls_frag (vlib_main_t * vm,
            vlib_frame_t * frame)
 {
     u32 n_left_from, next_index, * from, * to_next, n_left_to_next, *frags;
-    vlib_node_runtime_t * error_node;
 
-    error_node = vlib_node_get_runtime (vm, mpls_output_node.index);
     from = vlib_frame_vector_args (frame);
     n_left_from = frame->n_vectors;
     next_index = node->cached_next_index;
@@ -416,91 +403,111 @@ mpls_frag (vlib_main_t * vm,
             mpls_frag_next_t next0;
             u32 pi0, adj_index0;
             ip_frag_error_t error0 = IP_FRAG_ERROR_NONE;
-            i16 encap_size;
-            u8 is_ip4;
-
-            pi0 = to_next[0] = from[0];
-            p0 = vlib_get_buffer (vm, pi0);
-            from += 1;
-            n_left_from -= 1;
-            is_ip4 = vnet_buffer (p0)->mpls.pyld_proto == DPO_PROTO_IP4;
-
-            adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
-            adj0 = adj_get(adj_index0);
-
-            /* the size of the MPLS stack */
-            encap_size = vnet_buffer(p0)->l3_hdr_offset - p0->current_data;
-            
-            /* IP fragmentation */
-            if (is_ip4)
-                error0 = ip4_frag_do_fragment (vm, pi0,
-                                               adj0->rewrite_header.max_l3_packet_bytes,
-                                               encap_size, &frags);
-            else
-                error0 = ip6_frag_do_fragment (vm, pi0,
-                                               adj0->rewrite_header.max_l3_packet_bytes,
-                                               encap_size, &frags);
-
-            if (PREDICT_FALSE (p0->flags & VLIB_BUFFER_IS_TRACED))
-           {
-                mpls_frag_trace_t *tr =
-                    vlib_add_trace (vm, node, p0, sizeof (*tr));
-                 tr->mtu = adj0->rewrite_header.max_l3_packet_bytes;
-                 tr->pkt_size = vlib_buffer_length_in_chain(vm, p0);
-           }
-
-            if (PREDICT_TRUE(error0 == IP_FRAG_ERROR_NONE))
-           {
-                /* Free original buffer chain */
-                vlib_buffer_free_one (vm, pi0);        /* Free original packet */
-                next0 = (IP_LOOKUP_NEXT_MIDCHAIN == adj0->lookup_next_index ?
-                         MPLS_FRAG_NEXT_REWRITE_MIDCHAIN :
-                         MPLS_FRAG_NEXT_REWRITE);
-           }
-            else if (is_ip4 && error0 == IP_FRAG_ERROR_DONT_FRAGMENT_SET)
-           {
-                icmp4_error_set_vnet_buffer (
-                    p0, ICMP4_destination_unreachable,
-                    ICMP4_destination_unreachable_fragmentation_needed_and_dont_fragment_set,
-                    vnet_buffer (p0)->ip_frag.mtu);
-                next0 = MPLS_FRAG_NEXT_ICMP_ERROR;
-           }
-            else
-           {
-                vlib_error_count (vm, next_index, error0, 1);
-                vec_add1 (frags, pi0); /* Get rid of the original buffer */
-                next0 = MPLS_FRAG_NEXT_DROP;
-           }
-
-            /* Send fragments that were added in the frame */
-            u32 *frag_from, frag_left;
-
-            frag_from = frags;
-            frag_left = vec_len (frags);
-
-            while (frag_left > 0)
-            {
-                while (frag_left > 0 && n_left_to_next > 0)
-                {
-                    u32 i;
-                    i = to_next[0] = frag_from[0];
-                    frag_from += 1;
-                    frag_left -= 1;
-                    to_next += 1;
-                    n_left_to_next -= 1;
-
-                    p0 = vlib_get_buffer (vm, i);
-                    p0->error = error_node->errors[error0];
-
-                    vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
-                                                     to_next, n_left_to_next, i,
-                                                     next0);
-                }
-                vlib_put_next_frame (vm, node, next_index, n_left_to_next);
-                vlib_get_next_frame (vm, node, next_index, to_next,
-                                     n_left_to_next);
-            }
-            vec_reset_length (frags);
+           i16 encap_size, mtu;
+           u8 is_ip4;
+
+           pi0 = to_next[0] = from[0];
+           p0 = vlib_get_buffer (vm, pi0);
+           from += 1;
+           n_left_from -= 1;
+           is_ip4 = vnet_buffer (p0)->mpls.pyld_proto == DPO_PROTO_IP4;
+
+           adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
+           adj0 = adj_get (adj_index0);
+
+           /* the size of the MPLS stack */
+           encap_size = vnet_buffer (p0)->l3_hdr_offset - p0->current_data;
+           mtu = adj0->rewrite_header.max_l3_packet_bytes - encap_size;
+
+           /* IP fragmentation */
+           if (is_ip4)
+             error0 = ip4_frag_do_fragment (vm, pi0, mtu, encap_size, &frags);
+           else
+             {
+               if (!(p0->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED))
+                 {
+                   /* only fragment locally generated IPv6 */
+                   error0 = IP_FRAG_ERROR_DONT_FRAGMENT_SET;
+                 }
+               else
+                 {
+                   error0 =
+                     ip6_frag_do_fragment (vm, pi0, mtu, encap_size, &frags);
+                 }
+             }
+
+           if (PREDICT_FALSE (p0->flags & VLIB_BUFFER_IS_TRACED))
+             {
+               mpls_frag_trace_t *tr =
+                 vlib_add_trace (vm, node, p0, sizeof (*tr));
+               tr->mtu = mtu;
+               tr->pkt_size = vlib_buffer_length_in_chain (vm, p0);
+             }
+
+           if (PREDICT_TRUE (error0 == IP_FRAG_ERROR_NONE))
+             {
+               /* Free original buffer chain */
+               vlib_buffer_free_one (vm, pi0);
+               next0 = (IP_LOOKUP_NEXT_MIDCHAIN == adj0->lookup_next_index ?
+                          MPLS_FRAG_NEXT_REWRITE_MIDCHAIN :
+                          MPLS_FRAG_NEXT_REWRITE);
+             }
+           else
+             {
+               vlib_error_count (vm, node->node_index, error0, 1);
+
+               if (error0 == IP_FRAG_ERROR_DONT_FRAGMENT_SET)
+                 {
+                   vlib_buffer_advance (p0, encap_size);
+                   if (is_ip4)
+                     {
+                       icmp4_error_set_vnet_buffer (
+                         p0, ICMP4_destination_unreachable,
+                         ICMP4_destination_unreachable_fragmentation_needed_and_dont_fragment_set,
+                         mtu);
+                       next0 = MPLS_FRAG_NEXT_ICMP4_ERROR;
+                     }
+                   else
+                     {
+                       icmp6_error_set_vnet_buffer (p0, ICMP6_packet_too_big,
+                                                    0, mtu);
+                       next0 = MPLS_FRAG_NEXT_ICMP6_ERROR;
+                     }
+                 }
+               else
+                 {
+                   next0 = MPLS_FRAG_NEXT_DROP;
+                 }
+
+               /* Get rid of the original buffer */
+               vec_add1 (frags, pi0);
+             }
+
+           /* Send fragments that were added in the frame */
+           u32 *frag_from, frag_left;
+
+           frag_from = frags;
+           frag_left = vec_len (frags);
+
+           while (frag_left > 0)
+             {
+               while (frag_left > 0 && n_left_to_next > 0)
+                 {
+                   u32 i;
+                   i = to_next[0] = frag_from[0];
+                   frag_from += 1;
+                   frag_left -= 1;
+                   to_next += 1;
+                   n_left_to_next -= 1;
+
+                   vlib_validate_buffer_enqueue_x1 (
+                     vm, node, next_index, to_next, n_left_to_next, i, next0);
+                 }
+               vlib_put_next_frame (vm, node, next_index, n_left_to_next);
+               vlib_get_next_frame (vm, node, next_index, to_next,
+                                    n_left_to_next);
+             }
+           vec_reset_length (frags);
        }
         vlib_put_next_frame (vm, node, next_index, n_left_to_next);
     }
@@ -521,22 +528,21 @@ format_mpls_frag_trace (u8 * s, va_list * args)
 }
 
 VLIB_REGISTER_NODE (mpls_frag_node) = {
-    .function = mpls_frag,
-    .name = "mpls-frag",
-    .vector_size = sizeof (u32),
-    .format_trace = format_mpls_frag_trace,
-    .type = VLIB_NODE_TYPE_INTERNAL,
-
-    .n_errors = IP_FRAG_N_ERROR,
-    .error_strings = mpls_frag_error_strings,
-
-    .n_next_nodes = MPLS_FRAG_N_NEXT,
-    .next_nodes = {
-        [MPLS_FRAG_NEXT_REWRITE] = "mpls-output",
-        [MPLS_FRAG_NEXT_REWRITE_MIDCHAIN] = "mpls-midchain",
-        [MPLS_FRAG_NEXT_ICMP_ERROR] = "ip4-icmp-error",
-        [MPLS_FRAG_NEXT_DROP] = "mpls-drop"
-    },
+  .function = mpls_frag,
+  .name = "mpls-frag",
+  .vector_size = sizeof (u32),
+  .format_trace = format_mpls_frag_trace,
+  .type = VLIB_NODE_TYPE_INTERNAL,
+
+  .n_errors = IP_FRAG_N_ERROR,
+  .error_counters = ip_frag_error_counters,
+
+  .n_next_nodes = MPLS_FRAG_N_NEXT,
+  .next_nodes = { [MPLS_FRAG_NEXT_REWRITE] = "mpls-output",
+                 [MPLS_FRAG_NEXT_REWRITE_MIDCHAIN] = "mpls-midchain",
+                 [MPLS_FRAG_NEXT_ICMP4_ERROR] = "ip4-icmp-error",
+                 [MPLS_FRAG_NEXT_ICMP6_ERROR] = "ip6-icmp-error",
+                 [MPLS_FRAG_NEXT_DROP] = "mpls-drop" },
 };
 
 /*
@@ -612,9 +618,9 @@ VLIB_NODE_FN (mpls_adj_incomplete_node) (vlib_main_t * vm,
           else
           {
               next0 = MPLS_ADJ_INCOMPLETE_NEXT_IP6;
-          }              
+          }
 
-         if (PREDICT_FALSE(p0->flags & VLIB_BUFFER_IS_TRACED)) 
+         if (PREDICT_FALSE(p0->flags & VLIB_BUFFER_IS_TRACED))
          {
              mpls_adj_incomplete_trace_t *tr =
                  vlib_add_trace (vm, node, p0, sizeof (*tr));
@@ -664,4 +670,3 @@ VLIB_REGISTER_NODE (mpls_adj_incomplete_node) = {
 #undef _
   },
 };
-