Support reassembly for fragments coming to ip4-local node
[vpp.git] / src / vnet / ip / ip4_forward.c
index 614b6e2..69a8dba 100644 (file)
@@ -1481,20 +1481,51 @@ ip4_local_check_src_x2 (vlib_buffer_t ** b, ip4_header_t ** ip,
     }
 }
 
+enum ip_local_packet_type_e
+{
+  IP_LOCAL_PACKET_TYPE_L4,
+  IP_LOCAL_PACKET_TYPE_NAT,
+  IP_LOCAL_PACKET_TYPE_FRAG,
+};
+
+/**
+ * Determine packet type and next node.
+ *
+ * The expectation is that all packets that are not L4 will skip
+ * checksums and source checks.
+ */
+always_inline u8
+ip4_local_classify (vlib_buffer_t * b, ip4_header_t * ip, u16 * next)
+{
+  ip_lookup_main_t *lm = &ip4_main.lookup_main;
+
+  if (PREDICT_FALSE (ip4_is_fragment (ip)))
+    {
+      *next = IP_LOCAL_NEXT_REASSEMBLY;
+      return IP_LOCAL_PACKET_TYPE_FRAG;
+    }
+  if (PREDICT_FALSE (b->flags & VNET_BUFFER_F_IS_NATED))
+    {
+      *next = lm->local_next_by_ip_protocol[ip->protocol];
+      return IP_LOCAL_PACKET_TYPE_NAT;
+    }
+
+  *next = lm->local_next_by_ip_protocol[ip->protocol];
+  return IP_LOCAL_PACKET_TYPE_L4;
+}
+
 static inline uword
 ip4_local_inline (vlib_main_t * vm,
                  vlib_node_runtime_t * node,
                  vlib_frame_t * frame, int head_of_feature_arc)
 {
-  ip4_main_t *im = &ip4_main;
-  ip_lookup_main_t *lm = &im->lookup_main;
   u32 *from, n_left_from;
   vlib_node_runtime_t *error_node =
     vlib_node_get_runtime (vm, ip4_input_node.index);
   u16 nexts[VLIB_FRAME_SIZE], *next;
   vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
   ip4_header_t *ip[2];
-  u8 error[2];
+  u8 error[2], pt[2];
 
   ip4_local_last_check_t last_check = {
     .src = {.as_u32 = 0},
@@ -1514,7 +1545,7 @@ ip4_local_inline (vlib_main_t * vm,
 
   while (n_left_from >= 6)
     {
-      u32 is_nat, not_batch = 0;
+      u8 not_batch = 0;
 
       /* Prefetch next iteration. */
       {
@@ -1533,10 +1564,12 @@ ip4_local_inline (vlib_main_t * vm,
       vnet_buffer (b[0])->l3_hdr_offset = b[0]->current_data;
       vnet_buffer (b[1])->l3_hdr_offset = b[1]->current_data;
 
-      is_nat = b[0]->flags & VNET_BUFFER_F_IS_NATED;
-      not_batch |= is_nat ^ (b[1]->flags & VNET_BUFFER_F_IS_NATED);
+      pt[0] = ip4_local_classify (b[0], ip[0], &next[0]);
+      pt[1] = ip4_local_classify (b[1], ip[1], &next[1]);
 
-      if (head_of_feature_arc == 0 || (is_nat && not_batch == 0))
+      not_batch = pt[0] ^ pt[1];
+
+      if (head_of_feature_arc == 0 || (pt[0] && not_batch == 0))
        goto skip_checks;
 
       if (PREDICT_TRUE (not_batch == 0))
@@ -1546,12 +1579,12 @@ ip4_local_inline (vlib_main_t * vm,
        }
       else
        {
-         if (!(b[0]->flags & VNET_BUFFER_F_IS_NATED))
+         if (!pt[0])
            {
              ip4_local_check_l4_csum (vm, b[0], ip[0], &error[0]);
              ip4_local_check_src (b[0], ip[0], &last_check, &error[0]);
            }
-         if (!(b[1]->flags & VNET_BUFFER_F_IS_NATED))
+         if (!pt[1])
            {
              ip4_local_check_l4_csum (vm, b[1], ip[1], &error[1]);
              ip4_local_check_src (b[1], ip[1], &last_check, &error[1]);
@@ -1560,8 +1593,6 @@ ip4_local_inline (vlib_main_t * vm,
 
     skip_checks:
 
-      next[0] = lm->local_next_by_ip_protocol[ip[0]->protocol];
-      next[1] = lm->local_next_by_ip_protocol[ip[1]->protocol];
       ip4_local_set_next_and_error (error_node, b[0], &next[0], error[0],
                                    head_of_feature_arc);
       ip4_local_set_next_and_error (error_node, b[1], &next[1], error[1],
@@ -1578,8 +1609,9 @@ ip4_local_inline (vlib_main_t * vm,
 
       ip[0] = vlib_buffer_get_current (b[0]);
       vnet_buffer (b[0])->l3_hdr_offset = b[0]->current_data;
+      pt[0] = ip4_local_classify (b[0], ip[0], &next[0]);
 
-      if (head_of_feature_arc == 0 || (b[0]->flags & VNET_BUFFER_F_IS_NATED))
+      if (head_of_feature_arc == 0 || pt[0])
        goto skip_check;
 
       ip4_local_check_l4_csum (vm, b[0], ip[0], &error[0]);
@@ -1587,7 +1619,6 @@ ip4_local_inline (vlib_main_t * vm,
 
     skip_check:
 
-      next[0] = lm->local_next_by_ip_protocol[ip[0]->protocol];
       ip4_local_set_next_and_error (error_node, b[0], &next[0], error[0],
                                    head_of_feature_arc);
 
@@ -1619,6 +1650,7 @@ VLIB_REGISTER_NODE (ip4_local_node) =
     [IP_LOCAL_NEXT_PUNT] = "ip4-punt",
     [IP_LOCAL_NEXT_UDP_LOOKUP] = "ip4-udp-lookup",
     [IP_LOCAL_NEXT_ICMP] = "ip4-icmp-input",
+    [IP_LOCAL_NEXT_REASSEMBLY] = "ip4-reassembly",
   },
 };
 /* *INDENT-ON* */
@@ -1719,21 +1751,11 @@ ip4_arp_inline (vlib_main_t * vm,
   uword n_left_from, n_left_to_next_drop, next_index;
   u32 thread_index = vm->thread_index;
   u32 seed;
-  f64 time_now;
 
   if (node->flags & VLIB_NODE_FLAG_TRACE)
     ip4_forward_next_trace (vm, node, frame, VLIB_TX);
 
-  time_now = vlib_time_now (vm);
-  if (time_now - im->arp_throttle_last_seed_change_time[thread_index] > 1e-3)
-    {
-      (void) random_u32 (&im->arp_throttle_seeds[thread_index]);
-      memset (im->arp_throttle_bitmaps[thread_index], 0,
-             ARP_THROTTLE_BITS / BITS (u8));
-
-      im->arp_throttle_last_seed_change_time[thread_index] = time_now;
-    }
-  seed = im->arp_throttle_seeds[thread_index];
+  seed = throttle_seed (&im->arp_throttle, thread_index, vlib_time_now (vm));
 
   from = vlib_frame_vector_args (frame);
   n_left_from = frame->n_vectors;
@@ -1748,8 +1770,7 @@ ip4_arp_inline (vlib_main_t * vm,
 
       while (n_left_from > 0 && n_left_to_next_drop > 0)
        {
-         u32 pi0, adj_index0, r0, w0, sw_if_index0, drop0;
-         uword m0;
+         u32 pi0, adj_index0, r0, sw_if_index0, drop0;
          ip_adjacency_t *adj0;
          vlib_buffer_t *p0;
          ip4_header_t *ip0;
@@ -1778,14 +1799,7 @@ ip4_arp_inline (vlib_main_t * vm,
              r0 = adj0->sub_type.nbr.next_hop.ip4.data_u32;
            }
 
-         r0 ^= seed;
-         /* Select bit number */
-         r0 &= ARP_THROTTLE_BITS - 1;
-         w0 = r0 / BITS (uword);
-         m0 = (uword) 1 << (r0 % BITS (uword));
-
-         drop0 = (im->arp_throttle_bitmaps[thread_index][w0] & m0) != 0;
-         im->arp_throttle_bitmaps[thread_index][w0] |= m0;
+         drop0 = throttle_check (&im->arp_throttle, thread_index, r0, seed);
 
          from += 1;
          n_left_from -= 1;
@@ -2115,7 +2129,7 @@ ip4_mtu_check (vlib_buffer_t * b, u16 packet_len,
       else
        {
          /* IP fragmentation */
-         ip_frag_set_vnet_buffer (b, 0, adj_packet_bytes,
+         ip_frag_set_vnet_buffer (b, adj_packet_bytes,
                                   IP4_FRAG_NEXT_IP4_REWRITE, 0);
          *next = IP4_REWRITE_NEXT_FRAGMENT;
        }