n_left_from = frame->n_vectors;
next = node->cached_next_index;
- if (node->flags & VLIB_NODE_FLAG_TRACE)
- ip4_forward_next_trace (vm, node, frame, VLIB_TX);
-
while (n_left_from > 0)
{
vlib_get_next_frame (vm, node, next, to_next, n_left_to_next);
vlib_put_next_frame (vm, node, next, n_left_to_next);
}
+ if (node->flags & VLIB_NODE_FLAG_TRACE)
+ ip4_forward_next_trace (vm, node, frame, VLIB_TX);
+
return frame->n_vectors;
}
{
.arc_name = "ip4-unicast",
.node_name = "ip4-policer-classify",
- .runs_before = VNET_FEATURES ("ipsec-input-ip4"),
+ .runs_before = VNET_FEATURES ("ipsec4-input"),
};
VNET_FEATURE_INIT (ip4_ipsec, static) =
{
.arc_name = "ip4-unicast",
- .node_name = "ipsec-input-ip4",
+ .node_name = "ipsec4-input",
.runs_before = VNET_FEATURES ("vpath-input-ip4"),
};
{
.arc_name = "ip4-output",
.node_name = "ip4-outacl",
- .runs_before = VNET_FEATURES ("ipsec-output-ip4"),
+ .runs_before = VNET_FEATURES ("ipsec4-output"),
};
VNET_FEATURE_INIT (ip4_ipsec_output, static) =
{
.arc_name = "ip4-output",
- .node_name = "ipsec-output-ip4",
+ .node_name = "ipsec4-output",
.runs_before = VNET_FEATURES ("interface-output"),
};
{
ethernet_arp_header_t h;
- memset (&h, 0, sizeof (h));
+ clib_memset (&h, 0, sizeof (h));
/* Set target ethernet address to all zeros. */
- memset (h.ip4_over_ethernet[1].ethernet, 0,
- sizeof (h.ip4_over_ethernet[1].ethernet));
+ clib_memset (h.ip4_over_ethernet[1].ethernet, 0,
+ sizeof (h.ip4_over_ethernet[1].ethernet));
#define _16(f,v) h.f = clib_host_to_net_u16 (v);
#define _8(f,v) h.f = v;
}
}
+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},
while (n_left_from >= 6)
{
- u32 is_nat, not_batch = 0;
+ u8 not_batch = 0;
/* Prefetch next iteration. */
{
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))
}
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]);
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],
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]);
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);
[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* */
u32 *from, *to_next_drop;
uword n_left_from, n_left_to_next_drop, next_index;
u32 thread_index = vm->thread_index;
- u32 seed;
- f64 time_now;
+ u64 seed;
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;
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, bi0, adj_index0, sw_if_index0;
ip_adjacency_t *adj0;
- vlib_buffer_t *p0;
- ip4_header_t *ip0;
+ vlib_buffer_t *p0, *b0;
+ ip4_address_t resolve0;
+ ethernet_arp_header_t *h0;
+ vnet_hw_interface_t *hw_if0;
+ u64 r0;
pi0 = from[0];
-
p0 = vlib_get_buffer (vm, pi0);
+ from += 1;
+ n_left_from -= 1;
+ to_next_drop[0] = pi0;
+ to_next_drop += 1;
+ n_left_to_next_drop -= 1;
+
adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
adj0 = adj_get (adj_index0);
- ip0 = vlib_buffer_get_current (p0);
-
- sw_if_index0 = adj0->rewrite_header.sw_if_index;
- vnet_buffer (p0)->sw_if_index[VLIB_TX] = sw_if_index0;
- if (PREDICT_TRUE (is_glean))
+ if (is_glean)
{
- /*
- * this is the Glean case, so we are ARPing for the
- * packet's destination
- */
- r0 = ip0->dst_address.data_u32;
+ /* resolve the packet's destination */
+ ip4_header_t *ip0 = vlib_buffer_get_current (p0);
+ resolve0 = ip0->dst_address;
}
else
{
- r0 = adj0->sub_type.nbr.next_hop.ip4.data_u32;
+ /* resolve the incomplete adj */
+ resolve0 = adj0->sub_type.nbr.next_hop.ip4;
}
- 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;
-
- from += 1;
- n_left_from -= 1;
- to_next_drop[0] = pi0;
- to_next_drop += 1;
- n_left_to_next_drop -= 1;
+ /* combine the address and interface for the hash key */
+ sw_if_index0 = adj0->rewrite_header.sw_if_index;
+ r0 = (u64) resolve0.data_u32 << 32;
+ r0 |= sw_if_index0;
- p0->error =
- node->errors[drop0 ? IP4_ARP_ERROR_DROP :
- IP4_ARP_ERROR_REQUEST_SENT];
+ if (throttle_check (&im->arp_throttle, thread_index, r0, seed))
+ {
+ p0->error = node->errors[IP4_ARP_ERROR_THROTTLED];
+ continue;
+ }
/*
* the adj has been updated to a rewrite but the node the DPO that got
* us here hasn't - yet. no big deal. we'll drop while we wait.
*/
if (IP_LOOKUP_NEXT_REWRITE == adj0->lookup_next_index)
- continue;
-
- if (drop0)
- continue;
+ {
+ p0->error = node->errors[IP4_ARP_ERROR_RESOLVED];
+ continue;
+ }
/*
* Can happen if the control-plane is programming tables
|| (!is_glean && adj0->lookup_next_index != IP_LOOKUP_NEXT_ARP))
{
p0->error = node->errors[IP4_ARP_ERROR_NON_ARP_ADJ];
+ continue;
}
- else
- /* Send ARP request. */
+ /* Send ARP request. */
+ h0 =
+ vlib_packet_template_get_packet (vm,
+ &im->ip4_arp_request_packet_template,
+ &bi0);
+
+ /* Seems we're out of buffers */
+ if (PREDICT_FALSE (!h0))
{
- u32 bi0 = 0;
- vlib_buffer_t *b0;
- ethernet_arp_header_t *h0;
- vnet_hw_interface_t *hw_if0;
-
- h0 =
- vlib_packet_template_get_packet (vm,
- &im->ip4_arp_request_packet_template,
- &bi0);
-
- /* Seems we're out of buffers */
- if (PREDICT_FALSE (!h0))
- continue;
-
- /* Add rewrite/encap string for ARP packet. */
- vnet_rewrite_one_header (adj0[0], h0,
- sizeof (ethernet_header_t));
+ p0->error = node->errors[IP4_ARP_ERROR_NO_BUFFERS];
+ continue;
+ }
- hw_if0 = vnet_get_sup_hw_interface (vnm, sw_if_index0);
+ /* Add rewrite/encap string for ARP packet. */
+ vnet_rewrite_one_header (adj0[0], h0, sizeof (ethernet_header_t));
- /* Src ethernet address in ARP header. */
- clib_memcpy (h0->ip4_over_ethernet[0].ethernet,
- hw_if0->hw_address,
- sizeof (h0->ip4_over_ethernet[0].ethernet));
+ hw_if0 = vnet_get_sup_hw_interface (vnm, sw_if_index0);
- if (is_glean)
- {
- /* The interface's source address is stashed in the Glean Adj */
- h0->ip4_over_ethernet[0].ip4 =
- adj0->sub_type.glean.receive_addr.ip4;
-
- /* Copy in destination address we are requesting. This is the
- * glean case, so it's the packet's destination.*/
- h0->ip4_over_ethernet[1].ip4.data_u32 =
- ip0->dst_address.data_u32;
- }
- else
+ /* Src ethernet address in ARP header. */
+ clib_memcpy (h0->ip4_over_ethernet[0].ethernet,
+ hw_if0->hw_address,
+ sizeof (h0->ip4_over_ethernet[0].ethernet));
+ if (is_glean)
+ {
+ /* The interface's source address is stashed in the Glean Adj */
+ h0->ip4_over_ethernet[0].ip4 =
+ adj0->sub_type.glean.receive_addr.ip4;
+ }
+ else
+ {
+ /* Src IP address in ARP header. */
+ if (ip4_src_address_for_packet (lm, sw_if_index0,
+ &h0->ip4_over_ethernet[0].ip4))
{
- /* Src IP address in ARP header. */
- if (ip4_src_address_for_packet (lm, sw_if_index0,
- &h0->
- ip4_over_ethernet[0].ip4))
- {
- /* No source address available */
- p0->error =
- node->errors[IP4_ARP_ERROR_NO_SOURCE_ADDRESS];
- vlib_buffer_free (vm, &bi0, 1);
- continue;
- }
-
- /* Copy in destination address we are requesting from the
- incomplete adj */
- h0->ip4_over_ethernet[1].ip4.data_u32 =
- adj0->sub_type.nbr.next_hop.ip4.as_u32;
+ /* No source address available */
+ p0->error = node->errors[IP4_ARP_ERROR_NO_SOURCE_ADDRESS];
+ vlib_buffer_free (vm, &bi0, 1);
+ continue;
}
+ }
+ h0->ip4_over_ethernet[1].ip4 = resolve0;
- vlib_buffer_copy_trace_flag (vm, p0, bi0);
- b0 = vlib_get_buffer (vm, bi0);
- VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b0);
- vnet_buffer (b0)->sw_if_index[VLIB_TX] = sw_if_index0;
+ p0->error = node->errors[IP4_ARP_ERROR_REQUEST_SENT];
- vlib_buffer_advance (b0, -adj0->rewrite_header.data_bytes);
+ vlib_buffer_copy_trace_flag (vm, p0, bi0);
+ b0 = vlib_get_buffer (vm, bi0);
+ VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b0);
+ vnet_buffer (b0)->sw_if_index[VLIB_TX] = sw_if_index0;
- vlib_set_next_frame_buffer (vm, node,
- adj0->rewrite_header.next_index,
- bi0);
- }
+ vlib_buffer_advance (b0, -adj0->rewrite_header.data_bytes);
+
+ vlib_set_next_frame_buffer (vm, node,
+ adj0->rewrite_header.next_index, bi0);
}
vlib_put_next_frame (vm, node, IP4_ARP_NEXT_DROP, n_left_to_next_drop);
}
static char *ip4_arp_error_strings[] = {
- [IP4_ARP_ERROR_DROP] = "address overflow drops",
+ [IP4_ARP_ERROR_THROTTLED] = "ARP requests throttled",
+ [IP4_ARP_ERROR_RESOLVED] = "ARP requests resolved",
+ [IP4_ARP_ERROR_NO_BUFFERS] = "ARP requests out of buffer",
[IP4_ARP_ERROR_REQUEST_SENT] = "ARP requests sent",
[IP4_ARP_ERROR_NON_ARP_ADJ] = "ARPs to non-ARP adjacencies",
- [IP4_ARP_ERROR_REPLICATE_DROP] = "ARP replication completed",
- [IP4_ARP_ERROR_REPLICATE_FAIL] = "ARP replication failed",
[IP4_ARP_ERROR_NO_SOURCE_ADDRESS] = "no source address for ARP request",
};
/* *INDENT-ON* */
#define foreach_notrace_ip4_arp_error \
-_(DROP) \
+_(THROTTLED) \
+_(RESOLVED) \
+_(NO_BUFFERS) \
_(REQUEST_SENT) \
-_(REPLICATE_DROP) \
-_(REPLICATE_FAIL)
+_(NON_ARP_ADJ) \
+_(NO_SOURCE_ADDRESS)
static clib_error_t *
arp_notrace_init (vlib_main_t * vm)
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;
}