ip: allow addrs from the same prefix on intf
[vpp.git] / src / vnet / ip / icmp4.c
index a598ca9..1cf6a93 100644 (file)
@@ -188,15 +188,10 @@ ip4_icmp_input (vlib_main_t * vm,
          next0 = im->ip4_input_next_index_by_type[type0];
 
          p0->error = node->errors[ICMP4_ERROR_UNKNOWN_TYPE];
-         if (PREDICT_FALSE (next0 != next))
-           {
-             vlib_put_next_frame (vm, node, next, n_left_to_next + 1);
-             next = next0;
-             vlib_get_next_frame (vm, node, next, to_next, n_left_to_next);
-             to_next[0] = bi0;
-             to_next += 1;
-             n_left_to_next -= 1;
-           }
+
+         /* Verify speculative enqueue, maybe switch current next frame */
+         vlib_validate_buffer_enqueue_x1 (vm, node, next, to_next,
+                                          n_left_to_next, bi0, next0);
        }
 
       vlib_put_next_frame (vm, node, next, n_left_to_next);
@@ -476,15 +471,28 @@ ip4_icmp_error (vlib_main_t * vm,
 
       while (n_left_from > 0 && n_left_to_next > 0)
        {
-         u32 pi0 = from[0];
+         /*
+          * Duplicate first buffer and free the original chain.  Keep
+          * as much of the original packet as possible, within the
+          * minimum MTU. We chat "a little" here by keeping whatever
+          * is available in the first buffer.
+          */
+
+         u32 pi0 = ~0;
+         u32 org_pi0 = from[0];
          u32 next0 = IP4_ICMP_ERROR_NEXT_LOOKUP;
          u8 error0 = ICMP4_ERROR_NONE;
-         vlib_buffer_t *p0;
+         vlib_buffer_t *p0, *org_p0;
          ip4_header_t *ip0, *out_ip0;
          icmp46_header_t *icmp0;
          u32 sw_if_index0, if_add_index0;
          ip_csum_t sum;
 
+         org_p0 = vlib_get_buffer (vm, org_pi0);
+         p0 = vlib_buffer_copy_no_chain (vm, org_p0, &pi0);
+         if (!p0 || pi0 == ~0) /* Out of buffers */
+           continue;
+
          /* Speculatively enqueue p0 to the current next frame */
          to_next[0] = pi0;
          from += 1;
@@ -492,28 +500,9 @@ ip4_icmp_error (vlib_main_t * vm,
          n_left_from -= 1;
          n_left_to_next -= 1;
 
-         p0 = vlib_get_buffer (vm, pi0);
          ip0 = vlib_buffer_get_current (p0);
          sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
 
-         /*
-          * RFC1812 says to keep as much of the original packet as
-          * possible within the minimum MTU (576). We cheat "a little"
-          * here by keeping whatever fits in the first buffer, to be more
-          * efficient
-          */
-         if (PREDICT_FALSE (p0->total_length_not_including_first_buffer))
-           {
-             /* clear current_length of all other buffers in chain */
-             vlib_buffer_t *b = p0;
-             p0->total_length_not_including_first_buffer = 0;
-             while (b->flags & VLIB_BUFFER_NEXT_PRESENT)
-               {
-                 b = vlib_get_buffer (vm, b->next_buffer);
-                 b->current_length = 0;
-               }
-           }
-
          /* Add IP header and ICMPv4 header including a 4 byte data field */
          vlib_buffer_advance (p0,
                               -sizeof (ip4_header_t) -
@@ -521,7 +510,6 @@ ip4_icmp_error (vlib_main_t * vm,
 
          p0->current_length =
            p0->current_length > 576 ? 576 : p0->current_length;
-
          out_ip0 = vlib_buffer_get_current (p0);
          icmp0 = (icmp46_header_t *) & out_ip0[1];
 
@@ -570,6 +558,7 @@ ip4_icmp_error (vlib_main_t * vm,
          /* Update error status */
          if (error0 == ICMP4_ERROR_NONE)
            error0 = icmp4_icmp_type_to_error (icmp0->type);
+
          vlib_error_count (vm, node->node_index, error0, 1);
 
          /* Verify speculative enqueue, maybe switch current next frame */
@@ -580,6 +569,15 @@ ip4_icmp_error (vlib_main_t * vm,
       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
     }
 
+  /*
+   * push the original buffers to error-drop, so that
+   * they can get the error counters handled, then freed
+   */
+  vlib_buffer_enqueue_to_single_next (vm, node,
+                                     vlib_frame_vector_args (frame),
+                                     IP4_ICMP_ERROR_NEXT_DROP,
+                                     frame->n_vectors);
+
   return frame->n_vectors;
 }
 
@@ -739,10 +737,17 @@ void
 ip4_icmp_register_type (vlib_main_t * vm, icmp4_type_t type, u32 node_index)
 {
   icmp4_main_t *im = &icmp4_main;
+  u32 old_next_index;
 
   ASSERT ((int) type < ARRAY_LEN (im->ip4_input_next_index_by_type));
+  old_next_index = im->ip4_input_next_index_by_type[type];
+
   im->ip4_input_next_index_by_type[type]
     = vlib_node_add_next (vm, ip4_icmp_input_node.index, node_index);
+
+  if (old_next_index &&
+      (old_next_index != im->ip4_input_next_index_by_type[type]))
+    clib_warning ("WARNING: changed next_by_type[%d]", (int) type);
 }
 
 static clib_error_t *