#include <vnet/vnet.h>
#include <vnet/ip/ip.h>
+#include <vnet/ip/ip_frag.h>
#include <vnet/ip/ip6_neighbor.h>
#include <vnet/ethernet/ethernet.h> /* for ethernet_header_t */
#include <vnet/srp/srp.h> /* for srp_hw_interface_class */
#include <vnet/dpo/load_balance_map.h>
#include <vnet/dpo/classify_dpo.h>
+#ifndef CLIB_MARCH_VARIANT
#include <vppinfra/bihash_template.c>
+#endif
#include <vnet/ip/ip6_forward.h>
/* Flag used by IOAM code. Classifier sets it pop-hop-by-hop checks it */
fib_table_entry_delete (fib_index, &pfx, FIB_SOURCE_INTERFACE);
}
+#ifndef CLIB_MARCH_VARIANT
void
ip6_sw_interface_enable_disable (u32 sw_if_index, u32 is_enable)
{
clib_error_t *error;
u32 if_address_index;
ip6_address_fib_t ip6_af, *addr_fib = 0;
+ ip6_address_t ll_addr;
/* local0 interface doesn't support IP addressing */
if (sw_if_index == 0)
clib_error_create ("local0 interface doesn't support IP addressing");
}
+ if (ip6_address_is_link_local_unicast (address))
+ {
+ if (address_length != 128)
+ {
+ vnm->api_errno = VNET_API_ERROR_ADDRESS_LENGTH_MISMATCH;
+ return
+ clib_error_create
+ ("prefix length of link-local address must be 128");
+ }
+ if (!is_del)
+ {
+ return ip6_neighbor_set_link_local_address (vm, sw_if_index,
+ address);
+ }
+ else
+ {
+ ll_addr = ip6_neighbor_get_link_local_address (sw_if_index);
+ if (ip6_address_is_equal (&ll_addr, address))
+ {
+ vnm->api_errno = VNET_API_ERROR_ADDRESS_NOT_DELETABLE;
+ return clib_error_create ("address not deletable");
+ }
+ else
+ {
+ vnm->api_errno = VNET_API_ERROR_ADDRESS_NOT_FOUND_FOR_INTERFACE;
+ return clib_error_create ("address not found");
+ }
+ }
+ }
+
vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
vec_validate (im->mfib_index_by_sw_if_index, sw_if_index);
vec_elt (im->fib_index_by_sw_if_index, sw_if_index));
vec_add1 (addr_fib, ip6_af);
+ /* *INDENT-OFF* */
+ if (!is_del)
+ {
+ /* When adding an address check that it does not conflict
+ with an existing address on any interface in this table. */
+ ip_interface_address_t *ia;
+ vnet_sw_interface_t *sif;
+
+ pool_foreach(sif, vnm->interface_main.sw_interfaces,
+ ({
+ if (im->fib_index_by_sw_if_index[sw_if_index] ==
+ im->fib_index_by_sw_if_index[sif->sw_if_index])
+ {
+ foreach_ip_interface_address
+ (&im->lookup_main, ia, sif->sw_if_index,
+ 0 /* honor unnumbered */ ,
+ ({
+ ip6_address_t * x =
+ ip_interface_address_get_address
+ (&im->lookup_main, ia);
+ if (ip6_destination_matches_route
+ (im, address, x, ia->address_length) ||
+ ip6_destination_matches_route (im,
+ x,
+ address,
+ address_length))
+ {
+ vnm->api_errno = VNET_API_ERROR_DUPLICATE_IF_ADDRESS;
+ return
+ clib_error_create
+ ("failed to add %U which conflicts with %U for interface %U",
+ format_ip6_address_and_length, address,
+ address_length,
+ format_ip6_address_and_length, x,
+ ia->address_length,
+ format_vnet_sw_if_index_name, vnm,
+ sif->sw_if_index);
+ }
+ }));
+ }
+ }));
+ }
+ /* *INDENT-ON* */
+
{
uword elts_before = pool_elts (lm->if_address_pool);
return error;
}
-clib_error_t *
+#endif
+
+static clib_error_t *
ip6_sw_interface_admin_up_down (vnet_main_t * vnm, u32 sw_if_index, u32 flags)
{
ip6_main_t *im = &ip6_main;
{
.arc_name = "ip6-unicast",
.start_nodes = VNET_FEATURES ("ip6-input"),
+ .last_in_arc = "ip6-lookup",
.arc_index_ptr = &ip6_main.lookup_main.ucast_feature_arc_index,
};
{
.arc_name = "ip6-unicast",
.node_name = "ip6-policer-classify",
- .runs_before = VNET_FEATURES ("ipsec-input-ip6"),
+ .runs_before = VNET_FEATURES ("ipsec6-input-feature"),
};
VNET_FEATURE_INIT (ip6_ipsec, static) =
{
.arc_name = "ip6-unicast",
- .node_name = "ipsec-input-ip6",
+ .node_name = "ipsec6-input-feature",
.runs_before = VNET_FEATURES ("l2tp-decap"),
};
{
.arc_name = "ip6-multicast",
.start_nodes = VNET_FEATURES ("ip6-input"),
+ .last_in_arc = "ip6-mfib-forward-lookup",
.arc_index_ptr = &ip6_main.lookup_main.mcast_feature_arc_index,
};
{
.arc_name = "ip6-output",
.start_nodes = VNET_FEATURES ("ip6-rewrite", "ip6-midchain", "ip6-dvr-dpo"),
+ .last_in_arc = "interface-output",
.arc_index_ptr = &ip6_main.lookup_main.output_feature_arc_index,
};
VNET_FEATURE_INIT (ip6_outacl, static) = {
.arc_name = "ip6-output",
.node_name = "ip6-outacl",
- .runs_before = VNET_FEATURES ("ipsec-output-ip6"),
+ .runs_before = VNET_FEATURES ("ipsec6-output-feature"),
};
VNET_FEATURE_INIT (ip6_ipsec_output, static) = {
.arc_name = "ip6-output",
- .node_name = "ipsec-output-ip6",
+ .node_name = "ipsec6-output-feature",
.runs_before = VNET_FEATURES ("interface-output"),
};
};
/* *INDENT-ON* */
-clib_error_t *
+static clib_error_t *
ip6_sw_interface_add_del (vnet_main_t * vnm, u32 sw_if_index, u32 is_add)
{
ip6_main_t *im = &ip6_main;
VNET_SW_INTERFACE_ADD_DEL_FUNCTION (ip6_sw_interface_add_del);
-static uword
-ip6_lookup (vlib_main_t * vm,
- vlib_node_runtime_t * node, vlib_frame_t * frame)
+VLIB_NODE_FN (ip6_lookup_node) (vlib_main_t * vm,
+ vlib_node_runtime_t * node,
+ vlib_frame_t * frame)
{
return ip6_lookup_inline (vm, node, frame);
}
/* *INDENT-OFF* */
VLIB_REGISTER_NODE (ip6_lookup_node) =
{
- .function = ip6_lookup,
.name = "ip6-lookup",
.vector_size = sizeof (u32),
.format_trace = format_ip6_lookup_trace,
};
/* *INDENT-ON* */
-VLIB_NODE_FUNCTION_MULTIARCH (ip6_lookup_node, ip6_lookup);
-
-always_inline uword
-ip6_load_balance (vlib_main_t * vm,
- vlib_node_runtime_t * node, vlib_frame_t * frame)
+VLIB_NODE_FN (ip6_load_balance_node) (vlib_main_t * vm,
+ vlib_node_runtime_t * node,
+ vlib_frame_t * frame)
{
vlib_combined_counter_main_t *cm = &load_balance_main.lbm_via_counters;
u32 n_left_from, n_left_to_next, *from, *to_next;
ip_lookup_next_t next;
- u32 thread_index = vlib_get_thread_index ();
+ u32 thread_index = vm->thread_index;
ip6_main_t *im = &ip6_main;
from = vlib_frame_vector_args (frame);
n_left_from = frame->n_vectors;
next = node->cached_next_index;
- if (node->flags & VLIB_NODE_FLAG_TRACE)
- ip6_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)
+ ip6_forward_next_trace (vm, node, frame, VLIB_TX);
+
return frame->n_vectors;
}
/* *INDENT-OFF* */
VLIB_REGISTER_NODE (ip6_load_balance_node) =
{
- .function = ip6_load_balance,
.name = "ip6-load-balance",
.vector_size = sizeof (u32),
.sibling_of = "ip6-lookup",
};
/* *INDENT-ON* */
-VLIB_NODE_FUNCTION_MULTIARCH (ip6_load_balance_node, ip6_load_balance);
-
typedef struct
{
/* Adjacency taken. */
}
ip6_forward_next_trace_t;
+#ifndef CLIB_MARCH_VARIANT
u8 *
format_ip6_forward_next_trace (u8 * s, va_list * args)
{
format_ip6_header, t->packet_data, sizeof (t->packet_data));
return s;
}
+#endif
static u8 *
format_ip6_lookup_trace (u8 * s, va_list * args)
}
/* Common trace function for all ip6-forward next nodes. */
+#ifndef CLIB_MARCH_VARIANT
void
ip6_forward_next_trace (vlib_main_t * vm,
vlib_node_runtime_t * node,
vec_elt (im->fib_index_by_sw_if_index,
vnet_buffer (b0)->sw_if_index[VLIB_RX]);
- clib_memcpy (t0->packet_data,
- vlib_buffer_get_current (b0),
- sizeof (t0->packet_data));
+ clib_memcpy_fast (t0->packet_data,
+ vlib_buffer_get_current (b0),
+ sizeof (t0->packet_data));
}
if (b1->flags & VLIB_BUFFER_IS_TRACED)
{
vec_elt (im->fib_index_by_sw_if_index,
vnet_buffer (b1)->sw_if_index[VLIB_RX]);
- clib_memcpy (t1->packet_data,
- vlib_buffer_get_current (b1),
- sizeof (t1->packet_data));
+ clib_memcpy_fast (t1->packet_data,
+ vlib_buffer_get_current (b1),
+ sizeof (t1->packet_data));
}
from += 2;
n_left -= 2;
vec_elt (im->fib_index_by_sw_if_index,
vnet_buffer (b0)->sw_if_index[VLIB_RX]);
- clib_memcpy (t0->packet_data,
- vlib_buffer_get_current (b0),
- sizeof (t0->packet_data));
+ clib_memcpy_fast (t0->packet_data,
+ vlib_buffer_get_current (b0),
+ sizeof (t0->packet_data));
}
from += 1;
n_left -= 1;
return p0->flags;
}
+#endif
/**
* @brief returns number of links on which src is reachable.
};
/* *INDENT-ON* */
-static uword
+always_inline uword
ip6_local_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
vlib_frame_t * frame, int head_of_feature_arc)
{
ip6_main_t *im = &ip6_main;
ip_lookup_main_t *lm = &im->lookup_main;
- ip_local_next_t next_index;
- u32 *from, *to_next, n_left_from, n_left_to_next;
+ u32 *from, n_left_from;
vlib_node_runtime_t *error_node =
vlib_node_get_runtime (vm, ip6_input_node.index);
u8 arc_index = vnet_feat_arc_ip6_local.feature_arc_index;
+ vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
+ u16 nexts[VLIB_FRAME_SIZE], *next;
from = vlib_frame_vector_args (frame);
n_left_from = frame->n_vectors;
- next_index = node->cached_next_index;
if (node->flags & VLIB_NODE_FLAG_TRACE)
ip6_forward_next_trace (vm, node, frame, VLIB_TX);
- while (n_left_from > 0)
- {
- vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
-
- while (n_left_from >= 4 && n_left_to_next >= 2)
- {
- vlib_buffer_t *p0, *p1;
- ip6_header_t *ip0, *ip1;
- udp_header_t *udp0, *udp1;
- u32 pi0, ip_len0, udp_len0, flags0, next0;
- u32 pi1, ip_len1, udp_len1, flags1, next1;
- i32 len_diff0, len_diff1;
- u8 error0, type0, good_l4_csum0, is_tcp_udp0;
- u8 error1, type1, good_l4_csum1, is_tcp_udp1;
- u32 udp_offset0, udp_offset1;
-
- pi0 = to_next[0] = from[0];
- pi1 = to_next[1] = from[1];
- from += 2;
- n_left_from -= 2;
- to_next += 2;
- n_left_to_next -= 2;
-
- error0 = error1 = IP6_ERROR_UNKNOWN_PROTOCOL;
-
- p0 = vlib_get_buffer (vm, pi0);
- p1 = vlib_get_buffer (vm, pi1);
-
- ip0 = vlib_buffer_get_current (p0);
- ip1 = vlib_buffer_get_current (p1);
+ vlib_get_buffers (vm, from, bufs, n_left_from);
+ b = bufs;
+ next = nexts;
- if (head_of_feature_arc == 0)
- goto skip_checks;
+#define N 2
+#define xN for (int n=0; n<N; n++)
- vnet_buffer (p0)->l3_hdr_offset = p0->current_data;
- vnet_buffer (p1)->l3_hdr_offset = p1->current_data;
-
- type0 = lm->builtin_protocol_by_ip_protocol[ip0->protocol];
- type1 = lm->builtin_protocol_by_ip_protocol[ip1->protocol];
-
- flags0 = p0->flags;
- flags1 = p1->flags;
+ while (n_left_from > N)
+ {
+ /* Prefetch next iteration. */
+ if (n_left_from >= 3 * N)
+ {
+ xN vlib_prefetch_buffer_header (b[2 * N + n], STORE);
+ xN vlib_prefetch_buffer_data (b[1 * N + n], LOAD);
+ }
- is_tcp_udp0 = ip6_next_proto_is_tcp_udp (p0, ip0, &udp_offset0);
- is_tcp_udp1 = ip6_next_proto_is_tcp_udp (p1, ip1, &udp_offset1);
+ u8 error[N];
+ xN error[n] = IP6_ERROR_UNKNOWN_PROTOCOL;
- good_l4_csum0 = (flags0 & VNET_BUFFER_F_L4_CHECKSUM_CORRECT
- || (flags0 & VNET_BUFFER_F_OFFLOAD_TCP_CKSUM
- || flags0 & VNET_BUFFER_F_OFFLOAD_UDP_CKSUM))
- != 0;
- good_l4_csum1 = (flags1 & VNET_BUFFER_F_L4_CHECKSUM_CORRECT
- || (flags1 & VNET_BUFFER_F_OFFLOAD_TCP_CKSUM
- || flags1 & VNET_BUFFER_F_OFFLOAD_UDP_CKSUM))
- != 0;
- len_diff0 = 0;
- len_diff1 = 0;
+ ip6_header_t *ip[N];
+ xN ip[n] = vlib_buffer_get_current (b[n]);
- if (PREDICT_TRUE (is_tcp_udp0))
- {
- udp0 = (udp_header_t *) ((u8 *) ip0 + udp_offset0);
- /* Don't verify UDP checksum for packets with explicit zero checksum. */
- good_l4_csum0 |= type0 == IP_BUILTIN_PROTOCOL_UDP
- && udp0->checksum == 0;
- /* Verify UDP length. */
- if (is_tcp_udp0 == IP_PROTOCOL_UDP)
- {
- ip_len0 = clib_net_to_host_u16 (ip0->payload_length);
- udp_len0 = clib_net_to_host_u16 (udp0->length);
- len_diff0 = ip_len0 - udp_len0;
- }
- }
- if (PREDICT_TRUE (is_tcp_udp1))
+ if (head_of_feature_arc)
+ {
+ xN vnet_buffer (b[n])->l3_hdr_offset = b[n]->current_data;
+
+ u8 type[N];
+ xN type[n] = lm->builtin_protocol_by_ip_protocol[ip[n]->protocol];
+
+ u32 flags[N];
+ xN flags[n] = b[n]->flags;
+
+ u32 good_l4_csum[N];
+ xN good_l4_csum[n] =
+ flags[n] & (VNET_BUFFER_F_L4_CHECKSUM_CORRECT |
+ VNET_BUFFER_F_OFFLOAD_TCP_CKSUM |
+ VNET_BUFFER_F_OFFLOAD_UDP_CKSUM);
+
+ u32 udp_offset[N];
+ u8 is_tcp_udp[N];
+ xN is_tcp_udp[n] =
+ ip6_next_proto_is_tcp_udp (b[n], ip[n], &udp_offset[n]);
+ i16 len_diff[N] = { 0 };
+ xN if (PREDICT_TRUE (is_tcp_udp[n]))
{
- udp1 = (udp_header_t *) ((u8 *) ip1 + udp_offset1);
- /* Don't verify UDP checksum for packets with explicit zero checksum. */
- good_l4_csum1 |= type1 == IP_BUILTIN_PROTOCOL_UDP
- && udp1->checksum == 0;
- /* Verify UDP length. */
- if (is_tcp_udp1 == IP_PROTOCOL_UDP)
- {
- ip_len1 = clib_net_to_host_u16 (ip1->payload_length);
- udp_len1 = clib_net_to_host_u16 (udp1->length);
- len_diff1 = ip_len1 - udp_len1;
- }
+ udp_header_t *udp =
+ (udp_header_t *) ((u8 *) ip[n] + udp_offset[n]);
+ good_l4_csum[n] |= type[n] == IP_BUILTIN_PROTOCOL_UDP
+ && udp->checksum == 0;
+ /* optimistically verify UDP length. */
+ u16 ip_len, udp_len;
+ ip_len = clib_net_to_host_u16 (ip[n]->payload_length);
+ udp_len = clib_net_to_host_u16 (udp->length);
+ len_diff[n] = ip_len - udp_len;
}
- good_l4_csum0 |= type0 == IP_BUILTIN_PROTOCOL_UNKNOWN;
- good_l4_csum1 |= type1 == IP_BUILTIN_PROTOCOL_UNKNOWN;
+ xN good_l4_csum[n] |= type[n] == IP_BUILTIN_PROTOCOL_UNKNOWN;
+ xN len_diff[n] =
+ type[n] == IP_BUILTIN_PROTOCOL_UDP ? len_diff[n] : 0;
- len_diff0 = type0 == IP_BUILTIN_PROTOCOL_UDP ? len_diff0 : 0;
- len_diff1 = type1 == IP_BUILTIN_PROTOCOL_UDP ? len_diff1 : 0;
-
- if (PREDICT_FALSE (type0 != IP_BUILTIN_PROTOCOL_UNKNOWN
- && !good_l4_csum0
- && !(flags0 &
- VNET_BUFFER_F_L4_CHECKSUM_COMPUTED)))
- {
- flags0 = ip6_tcp_udp_icmp_validate_checksum (vm, p0);
- good_l4_csum0 =
- (flags0 & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) != 0;
- }
- if (PREDICT_FALSE (type1 != IP_BUILTIN_PROTOCOL_UNKNOWN
- && !good_l4_csum1
- && !(flags1 &
- VNET_BUFFER_F_L4_CHECKSUM_COMPUTED)))
+ u8 need_csum[N];
+ xN need_csum[n] = type[n] != IP_BUILTIN_PROTOCOL_UNKNOWN
+ && !good_l4_csum[n]
+ && !(flags[n] & VNET_BUFFER_F_L4_CHECKSUM_COMPUTED);
+ xN if (PREDICT_FALSE (need_csum[n]))
{
- flags1 = ip6_tcp_udp_icmp_validate_checksum (vm, p1);
- good_l4_csum1 =
- (flags1 & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) != 0;
+ flags[n] = ip6_tcp_udp_icmp_validate_checksum (vm, b[n]);
+ good_l4_csum[n] = flags[n] & VNET_BUFFER_F_L4_CHECKSUM_CORRECT;
}
- error0 = error1 = IP6_ERROR_UNKNOWN_PROTOCOL;
- error0 = len_diff0 < 0 ? IP6_ERROR_UDP_LENGTH : error0;
- error1 = len_diff1 < 0 ? IP6_ERROR_UDP_LENGTH : error1;
+ xN error[n] = IP6_ERROR_UNKNOWN_PROTOCOL;
+ xN error[n] = len_diff[n] < 0 ? IP6_ERROR_UDP_LENGTH : error[n];
+
+ STATIC_ASSERT (IP6_ERROR_UDP_CHECKSUM + IP_BUILTIN_PROTOCOL_UDP ==
+ IP6_ERROR_UDP_CHECKSUM,
+ "Wrong IP6 errors constants");
+ STATIC_ASSERT (IP6_ERROR_UDP_CHECKSUM + IP_BUILTIN_PROTOCOL_ICMP ==
+ IP6_ERROR_ICMP_CHECKSUM,
+ "Wrong IP6 errors constants");
- ASSERT (IP6_ERROR_UDP_CHECKSUM + IP_BUILTIN_PROTOCOL_UDP ==
- IP6_ERROR_UDP_CHECKSUM);
- ASSERT (IP6_ERROR_UDP_CHECKSUM + IP_BUILTIN_PROTOCOL_ICMP ==
- IP6_ERROR_ICMP_CHECKSUM);
- error0 = (!good_l4_csum0 ? IP6_ERROR_UDP_CHECKSUM + type0 : error0);
- error1 = (!good_l4_csum1 ? IP6_ERROR_UDP_CHECKSUM + type1 : error1);
+ xN error[n] =
+ !good_l4_csum[n] ? IP6_ERROR_UDP_CHECKSUM + type[n] : error[n];
/* Drop packets from unroutable hosts. */
/* If this is a neighbor solicitation (ICMP), skip source RPF check */
- if (error0 == IP6_ERROR_UNKNOWN_PROTOCOL &&
- type0 != IP_BUILTIN_PROTOCOL_ICMP &&
- !ip6_address_is_link_local_unicast (&ip0->src_address))
+ u8 unroutable[N];
+ xN unroutable[n] = error[n] == IP6_ERROR_UNKNOWN_PROTOCOL
+ && type[n] != IP_BUILTIN_PROTOCOL_ICMP
+ && !ip6_address_is_link_local_unicast (&ip[n]->src_address);
+ xN if (PREDICT_FALSE (unroutable[n]))
{
- error0 = (!ip6_urpf_loose_check (im, p0, ip0)
- ? IP6_ERROR_SRC_LOOKUP_MISS : error0);
+ error[n] =
+ !ip6_urpf_loose_check (im, b[n],
+ ip[n]) ? IP6_ERROR_SRC_LOOKUP_MISS
+ : error[n];
}
- if (error1 == IP6_ERROR_UNKNOWN_PROTOCOL &&
- type1 != IP_BUILTIN_PROTOCOL_ICMP &&
- !ip6_address_is_link_local_unicast (&ip1->src_address))
- {
- error1 = (!ip6_urpf_loose_check (im, p1, ip1)
- ? IP6_ERROR_SRC_LOOKUP_MISS : error1);
- }
-
- /* TODO maybe move to lookup? */
- vnet_buffer (p0)->ip.fib_index =
- vec_elt (im->fib_index_by_sw_if_index,
- vnet_buffer (p0)->sw_if_index[VLIB_RX]);
- vnet_buffer (p0)->ip.fib_index =
- (vnet_buffer (p0)->sw_if_index[VLIB_TX] ==
- (u32) ~ 0) ? vnet_buffer (p0)->ip.
- fib_index : vnet_buffer (p0)->sw_if_index[VLIB_TX];
-
- vnet_buffer (p1)->ip.fib_index =
- vec_elt (im->fib_index_by_sw_if_index,
- vnet_buffer (p1)->sw_if_index[VLIB_RX]);
- vnet_buffer (p1)->ip.fib_index =
- (vnet_buffer (p1)->sw_if_index[VLIB_TX] ==
- (u32) ~ 0) ? vnet_buffer (p1)->ip.
- fib_index : vnet_buffer (p1)->sw_if_index[VLIB_TX];
-
- skip_checks:
+ xN vnet_buffer (b[n])->ip.fib_index =
+ vnet_buffer (b[n])->sw_if_index[VLIB_TX] != ~0 ?
+ vnet_buffer (b[n])->sw_if_index[VLIB_TX] :
+ vnet_buffer (b[n])->ip.fib_index;
+ } /* head_of_feature_arc */
- next0 = lm->local_next_by_ip_protocol[ip0->protocol];
- next1 = lm->local_next_by_ip_protocol[ip1->protocol];
+ xN next[n] = lm->local_next_by_ip_protocol[ip[n]->protocol];
+ xN next[n] =
+ error[n] != IP6_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next[n];
- next0 =
- error0 != IP6_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next0;
- next1 =
- error1 != IP6_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next1;
+ xN b[n]->error = error_node->errors[n];
- p0->error = error_node->errors[error0];
- p1->error = error_node->errors[error1];
-
- if (head_of_feature_arc)
+ if (head_of_feature_arc)
+ {
+ u8 ip6_unknown[N];
+ xN ip6_unknown[n] = error[n] == (u8) IP6_ERROR_UNKNOWN_PROTOCOL;
+ xN if (PREDICT_TRUE (ip6_unknown[n]))
{
- if (PREDICT_TRUE (error0 == (u8) IP6_ERROR_UNKNOWN_PROTOCOL))
- vnet_feature_arc_start (arc_index,
- vnet_buffer (p0)->sw_if_index
- [VLIB_RX], &next0, p0);
- if (PREDICT_TRUE (error1 == (u8) IP6_ERROR_UNKNOWN_PROTOCOL))
- vnet_feature_arc_start (arc_index,
- vnet_buffer (p1)->sw_if_index
- [VLIB_RX], &next1, p1);
+ u32 next32 = next[n];
+ vnet_feature_arc_start (arc_index,
+ vnet_buffer (b[n])->sw_if_index
+ [VLIB_RX], &next32, b[n]);
+ next[n] = next32;
}
-
- 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)
- {
- vlib_buffer_t *p0;
- ip6_header_t *ip0;
- udp_header_t *udp0;
- u32 pi0, ip_len0, udp_len0, flags0, next0;
- i32 len_diff0;
- u8 error0, type0, good_l4_csum0;
- u32 udp_offset0;
- u8 is_tcp_udp0;
-
- pi0 = to_next[0] = from[0];
- from += 1;
- n_left_from -= 1;
- to_next += 1;
- n_left_to_next -= 1;
-
- error0 = IP6_ERROR_UNKNOWN_PROTOCOL;
-
- p0 = vlib_get_buffer (vm, pi0);
- ip0 = vlib_buffer_get_current (p0);
-
- if (head_of_feature_arc == 0)
- goto skip_check;
-
- vnet_buffer (p0)->l3_hdr_offset = p0->current_data;
+ /* next */
+ b += N;
+ next += N;
+ n_left_from -= N;
+ }
+#undef xN
+#undef N
+ while (n_left_from)
+ {
+ u8 error;
+ error = IP6_ERROR_UNKNOWN_PROTOCOL;
- type0 = lm->builtin_protocol_by_ip_protocol[ip0->protocol];
- flags0 = p0->flags;
- is_tcp_udp0 = ip6_next_proto_is_tcp_udp (p0, ip0, &udp_offset0);
- good_l4_csum0 = (flags0 & VNET_BUFFER_F_L4_CHECKSUM_CORRECT
- || (flags0 & VNET_BUFFER_F_OFFLOAD_TCP_CKSUM
- || flags0 & VNET_BUFFER_F_OFFLOAD_UDP_CKSUM))
- != 0;
+ ip6_header_t *ip;
+ ip = vlib_buffer_get_current (b[0]);
- len_diff0 = 0;
- if (PREDICT_TRUE (is_tcp_udp0))
+ if (head_of_feature_arc)
+ {
+ vnet_buffer (b[0])->l3_hdr_offset = b[0]->current_data;
+ u8 type = lm->builtin_protocol_by_ip_protocol[ip->protocol];
+
+ u32 flags = b[0]->flags;
+ u32 good_l4_csum =
+ flags & (VNET_BUFFER_F_L4_CHECKSUM_CORRECT |
+ VNET_BUFFER_F_OFFLOAD_TCP_CKSUM |
+ VNET_BUFFER_F_OFFLOAD_UDP_CKSUM);
+
+ u32 udp_offset;
+ i16 len_diff = 0;
+ u8 is_tcp_udp = ip6_next_proto_is_tcp_udp (b[0], ip, &udp_offset);
+ if (PREDICT_TRUE (is_tcp_udp))
{
- udp0 = (udp_header_t *) ((u8 *) ip0 + udp_offset0);
- /* Don't verify UDP checksum for packets with explicit zero
- * checksum. */
- good_l4_csum0 |= type0 == IP_BUILTIN_PROTOCOL_UDP
- && udp0->checksum == 0;
- /* Verify UDP length. */
- if (is_tcp_udp0 == IP_PROTOCOL_UDP)
- {
- ip_len0 = clib_net_to_host_u16 (ip0->payload_length);
- udp_len0 = clib_net_to_host_u16 (udp0->length);
- len_diff0 = ip_len0 - udp_len0;
- }
+ udp_header_t *udp = (udp_header_t *) ((u8 *) ip + udp_offset);
+ /* Don't verify UDP checksum for packets with explicit zero checksum. */
+ good_l4_csum |= type == IP_BUILTIN_PROTOCOL_UDP
+ && udp->checksum == 0;
+ /* optimistically verify UDP length. */
+ u16 ip_len, udp_len;
+ ip_len = clib_net_to_host_u16 (ip->payload_length);
+ udp_len = clib_net_to_host_u16 (udp->length);
+ len_diff = ip_len - udp_len;
}
- good_l4_csum0 |= type0 == IP_BUILTIN_PROTOCOL_UNKNOWN;
- len_diff0 = type0 == IP_BUILTIN_PROTOCOL_UDP ? len_diff0 : 0;
+ good_l4_csum |= type == IP_BUILTIN_PROTOCOL_UNKNOWN;
+ len_diff = type == IP_BUILTIN_PROTOCOL_UDP ? len_diff : 0;
- if (PREDICT_FALSE (type0 != IP_BUILTIN_PROTOCOL_UNKNOWN
- && !good_l4_csum0
- && !(flags0 &
- VNET_BUFFER_F_L4_CHECKSUM_COMPUTED)))
+ u8 need_csum = type != IP_BUILTIN_PROTOCOL_UNKNOWN && !good_l4_csum
+ && !(flags & VNET_BUFFER_F_L4_CHECKSUM_COMPUTED);
+ if (PREDICT_FALSE (need_csum))
{
- flags0 = ip6_tcp_udp_icmp_validate_checksum (vm, p0);
- good_l4_csum0 =
- (flags0 & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) != 0;
+ flags = ip6_tcp_udp_icmp_validate_checksum (vm, b[0]);
+ good_l4_csum = flags & VNET_BUFFER_F_L4_CHECKSUM_CORRECT;
}
- error0 = IP6_ERROR_UNKNOWN_PROTOCOL;
- error0 = len_diff0 < 0 ? IP6_ERROR_UDP_LENGTH : error0;
+ error = IP6_ERROR_UNKNOWN_PROTOCOL;
+ error = len_diff < 0 ? IP6_ERROR_UDP_LENGTH : error;
+
+ STATIC_ASSERT (IP6_ERROR_UDP_CHECKSUM + IP_BUILTIN_PROTOCOL_UDP ==
+ IP6_ERROR_UDP_CHECKSUM,
+ "Wrong IP6 errors constants");
+ STATIC_ASSERT (IP6_ERROR_UDP_CHECKSUM + IP_BUILTIN_PROTOCOL_ICMP ==
+ IP6_ERROR_ICMP_CHECKSUM,
+ "Wrong IP6 errors constants");
- ASSERT (IP6_ERROR_UDP_CHECKSUM + IP_BUILTIN_PROTOCOL_UDP ==
- IP6_ERROR_UDP_CHECKSUM);
- ASSERT (IP6_ERROR_UDP_CHECKSUM + IP_BUILTIN_PROTOCOL_ICMP ==
- IP6_ERROR_ICMP_CHECKSUM);
- error0 = (!good_l4_csum0 ? IP6_ERROR_UDP_CHECKSUM + type0 : error0);
+ error = !good_l4_csum ? IP6_ERROR_UDP_CHECKSUM + type : error;
- /* If this is a neighbor solicitation (ICMP), skip src RPF check */
- if (error0 == IP6_ERROR_UNKNOWN_PROTOCOL &&
- type0 != IP_BUILTIN_PROTOCOL_ICMP &&
- !ip6_address_is_link_local_unicast (&ip0->src_address))
+ /* Drop packets from unroutable hosts. */
+ /* If this is a neighbor solicitation (ICMP), skip source RPF check */
+ u8 unroutable = error == IP6_ERROR_UNKNOWN_PROTOCOL
+ && type != IP_BUILTIN_PROTOCOL_ICMP
+ && !ip6_address_is_link_local_unicast (&ip->src_address);
+ if (PREDICT_FALSE (unroutable))
{
- error0 = (!ip6_urpf_loose_check (im, p0, ip0)
- ? IP6_ERROR_SRC_LOOKUP_MISS : error0);
+ error =
+ !ip6_urpf_loose_check (im, b[0],
+ ip) ? IP6_ERROR_SRC_LOOKUP_MISS :
+ error;
}
- vnet_buffer (p0)->ip.fib_index =
- vec_elt (im->fib_index_by_sw_if_index,
- vnet_buffer (p0)->sw_if_index[VLIB_RX]);
- vnet_buffer (p0)->ip.fib_index =
- (vnet_buffer (p0)->sw_if_index[VLIB_TX] ==
- (u32) ~ 0) ? vnet_buffer (p0)->ip.
- fib_index : vnet_buffer (p0)->sw_if_index[VLIB_TX];
-
- skip_check:
+ vnet_buffer (b[0])->ip.fib_index =
+ vnet_buffer (b[0])->sw_if_index[VLIB_TX] != ~0 ?
+ vnet_buffer (b[0])->sw_if_index[VLIB_TX] :
+ vnet_buffer (b[0])->ip.fib_index;
+ } /* head_of_feature_arc */
- next0 = lm->local_next_by_ip_protocol[ip0->protocol];
- next0 =
- error0 != IP6_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next0;
+ next[0] = lm->local_next_by_ip_protocol[ip->protocol];
+ next[0] =
+ error != IP6_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next[0];
- p0->error = error_node->errors[error0];
+ b[0]->error = error_node->errors[0];
- if (head_of_feature_arc)
+ if (head_of_feature_arc)
+ {
+ if (PREDICT_TRUE (error == (u8) IP6_ERROR_UNKNOWN_PROTOCOL))
{
- if (PREDICT_TRUE (error0 == (u8) IP6_ERROR_UNKNOWN_PROTOCOL))
- vnet_feature_arc_start (arc_index,
- vnet_buffer (p0)->sw_if_index
- [VLIB_RX], &next0, p0);
+ u32 next32 = next[0];
+ vnet_feature_arc_start (arc_index,
+ vnet_buffer (b[0])->sw_if_index
+ [VLIB_RX], &next32, b[0]);
+ next[0] = next32;
}
-
- vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
- to_next, n_left_to_next,
- pi0, next0);
}
- vlib_put_next_frame (vm, node, next_index, n_left_to_next);
+ /* next */
+ b += 1;
+ next += 1;
+ n_left_from -= 1;
}
+ vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
return frame->n_vectors;
}
-static uword
-ip6_local (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
+VLIB_NODE_FN (ip6_local_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
+ vlib_frame_t * frame)
{
return ip6_local_inline (vm, node, frame, 1 /* head of feature arc */ );
}
/* *INDENT-OFF* */
-VLIB_REGISTER_NODE (ip6_local_node, static) =
+VLIB_REGISTER_NODE (ip6_local_node) =
{
- .function = ip6_local,
.name = "ip6-local",
.vector_size = sizeof (u32),
.format_trace = format_ip6_forward_next_trace,
[IP_LOCAL_NEXT_PUNT] = "ip6-punt",
[IP_LOCAL_NEXT_UDP_LOOKUP] = "ip6-udp-lookup",
[IP_LOCAL_NEXT_ICMP] = "ip6-icmp-input",
+ [IP_LOCAL_NEXT_REASSEMBLY] = "ip6-reassembly",
},
};
/* *INDENT-ON* */
-VLIB_NODE_FUNCTION_MULTIARCH (ip6_local_node, ip6_local);
-
-
-static uword
-ip6_local_end_of_arc (vlib_main_t * vm,
- vlib_node_runtime_t * node, vlib_frame_t * frame)
+VLIB_NODE_FN (ip6_local_end_of_arc_node) (vlib_main_t * vm,
+ vlib_node_runtime_t * node,
+ vlib_frame_t * frame)
{
return ip6_local_inline (vm, node, frame, 0 /* head of feature arc */ );
}
/* *INDENT-OFF* */
-VLIB_REGISTER_NODE (ip6_local_end_of_arc_node,static) = {
- .function = ip6_local_end_of_arc,
+VLIB_REGISTER_NODE (ip6_local_end_of_arc_node) = {
.name = "ip6-local-end-of-arc",
.vector_size = sizeof (u32),
.sibling_of = "ip6-local",
};
-VLIB_NODE_FUNCTION_MULTIARCH (ip6_local_end_of_arc_node, ip6_local_end_of_arc)
-
VNET_FEATURE_INIT (ip6_local_end_of_arc, static) = {
.arc_name = "ip6-local",
.node_name = "ip6-local-end-of-arc",
};
/* *INDENT-ON* */
+#ifdef CLIB_MARCH_VARIANT
+extern vlib_node_registration_t ip6_local_node;
+
+#else
+
void
ip6_register_protocol (u32 protocol, u32 node_index)
{
vlib_node_add_next (vm, ip6_local_node.index, node_index);
}
-typedef enum
-{
- IP6_DISCOVER_NEIGHBOR_NEXT_DROP,
- IP6_DISCOVER_NEIGHBOR_NEXT_REPLY_TX,
- IP6_DISCOVER_NEIGHBOR_N_NEXT,
-} ip6_discover_neighbor_next_t;
-
-typedef enum
-{
- IP6_DISCOVER_NEIGHBOR_ERROR_DROP,
- IP6_DISCOVER_NEIGHBOR_ERROR_REQUEST_SENT,
- IP6_DISCOVER_NEIGHBOR_ERROR_NO_SOURCE_ADDRESS,
-} ip6_discover_neighbor_error_t;
-
-static uword
-ip6_discover_neighbor_inline (vlib_main_t * vm,
- vlib_node_runtime_t * node,
- vlib_frame_t * frame, int is_glean)
-{
- vnet_main_t *vnm = vnet_get_main ();
- ip6_main_t *im = &ip6_main;
- ip_lookup_main_t *lm = &im->lookup_main;
- u32 *from, *to_next_drop;
- uword n_left_from, n_left_to_next_drop;
- static f64 time_last_seed_change = -1e100;
- static u32 hash_seeds[3];
- static uword hash_bitmap[256 / BITS (uword)];
- f64 time_now;
- int bogus_length;
-
- if (node->flags & VLIB_NODE_FLAG_TRACE)
- ip6_forward_next_trace (vm, node, frame, VLIB_TX);
-
- time_now = vlib_time_now (vm);
- if (time_now - time_last_seed_change > 1e-3)
- {
- uword i;
- u32 *r = clib_random_buffer_get_data (&vm->random_buffer,
- sizeof (hash_seeds));
- for (i = 0; i < ARRAY_LEN (hash_seeds); i++)
- hash_seeds[i] = r[i];
-
- /* Mark all hash keys as been not-seen before. */
- for (i = 0; i < ARRAY_LEN (hash_bitmap); i++)
- hash_bitmap[i] = 0;
-
- time_last_seed_change = time_now;
- }
-
- from = vlib_frame_vector_args (frame);
- n_left_from = frame->n_vectors;
-
- while (n_left_from > 0)
- {
- vlib_get_next_frame (vm, node, IP6_DISCOVER_NEIGHBOR_NEXT_DROP,
- to_next_drop, n_left_to_next_drop);
-
- while (n_left_from > 0 && n_left_to_next_drop > 0)
- {
- vlib_buffer_t *p0;
- ip6_header_t *ip0;
- u32 pi0, adj_index0, a0, b0, c0, m0, sw_if_index0, drop0;
- uword bm0;
- ip_adjacency_t *adj0;
- vnet_hw_interface_t *hw_if0;
- u32 next0;
-
- pi0 = from[0];
-
- p0 = vlib_get_buffer (vm, pi0);
-
- adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
-
- ip0 = vlib_buffer_get_current (p0);
-
- adj0 = adj_get (adj_index0);
-
- if (!is_glean)
- {
- ip0->dst_address.as_u64[0] =
- adj0->sub_type.nbr.next_hop.ip6.as_u64[0];
- ip0->dst_address.as_u64[1] =
- adj0->sub_type.nbr.next_hop.ip6.as_u64[1];
- }
-
- a0 = hash_seeds[0];
- b0 = hash_seeds[1];
- c0 = hash_seeds[2];
-
- sw_if_index0 = adj0->rewrite_header.sw_if_index;
- vnet_buffer (p0)->sw_if_index[VLIB_TX] = sw_if_index0;
-
- a0 ^= sw_if_index0;
- b0 ^= ip0->dst_address.as_u32[0];
- c0 ^= ip0->dst_address.as_u32[1];
-
- hash_v3_mix32 (a0, b0, c0);
-
- b0 ^= ip0->dst_address.as_u32[2];
- c0 ^= ip0->dst_address.as_u32[3];
-
- hash_v3_finalize32 (a0, b0, c0);
-
- c0 &= BITS (hash_bitmap) - 1;
- c0 = c0 / BITS (uword);
- m0 = (uword) 1 << (c0 % BITS (uword));
-
- bm0 = hash_bitmap[c0];
- drop0 = (bm0 & m0) != 0;
-
- /* Mark it as seen. */
- hash_bitmap[c0] = bm0 | m0;
-
- from += 1;
- n_left_from -= 1;
- to_next_drop[0] = pi0;
- to_next_drop += 1;
- n_left_to_next_drop -= 1;
-
- hw_if0 = vnet_get_sup_hw_interface (vnm, sw_if_index0);
-
- /* If the interface is link-down, drop the pkt */
- if (!(hw_if0->flags & VNET_HW_INTERFACE_FLAG_LINK_UP))
- drop0 = 1;
-
- p0->error =
- node->errors[drop0 ? IP6_DISCOVER_NEIGHBOR_ERROR_DROP
- : IP6_DISCOVER_NEIGHBOR_ERROR_REQUEST_SENT];
- if (drop0)
- 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;
-
- {
- u32 bi0 = 0;
- icmp6_neighbor_solicitation_header_t *h0;
- vlib_buffer_t *b0;
-
- h0 = vlib_packet_template_get_packet
- (vm, &im->discover_neighbor_packet_template, &bi0);
-
- /*
- * Build ethernet header.
- * Choose source address based on destination lookup
- * adjacency.
- */
- if (!ip6_src_address_for_packet (lm,
- sw_if_index0,
- &ip0->dst_address,
- &h0->ip.src_address))
- {
- /* There is no address on the interface */
- p0->error =
- node->errors[IP6_DISCOVER_NEIGHBOR_ERROR_NO_SOURCE_ADDRESS];
- vlib_buffer_free (vm, &bi0, 1);
- continue;
- }
-
- /*
- * Destination address is a solicited node multicast address.
- * We need to fill in
- * the low 24 bits with low 24 bits of target's address.
- */
- h0->ip.dst_address.as_u8[13] = ip0->dst_address.as_u8[13];
- h0->ip.dst_address.as_u8[14] = ip0->dst_address.as_u8[14];
- h0->ip.dst_address.as_u8[15] = ip0->dst_address.as_u8[15];
-
- h0->neighbor.target_address = ip0->dst_address;
-
- clib_memcpy (h0->link_layer_option.ethernet_address,
- hw_if0->hw_address, vec_len (hw_if0->hw_address));
-
- /* $$$$ appears we need this; why is the checksum non-zero? */
- h0->neighbor.icmp.checksum = 0;
- h0->neighbor.icmp.checksum =
- ip6_tcp_udp_icmp_compute_checksum (vm, 0, &h0->ip,
- &bogus_length);
-
- ASSERT (bogus_length == 0);
-
- vlib_buffer_copy_trace_flag (vm, p0, bi0);
- b0 = vlib_get_buffer (vm, bi0);
- vnet_buffer (b0)->sw_if_index[VLIB_TX]
- = vnet_buffer (p0)->sw_if_index[VLIB_TX];
-
- /* Add rewrite/encap string. */
- vnet_rewrite_one_header (adj0[0], h0, sizeof (ethernet_header_t));
- vlib_buffer_advance (b0, -adj0->rewrite_header.data_bytes);
-
- next0 = IP6_DISCOVER_NEIGHBOR_NEXT_REPLY_TX;
-
- vlib_set_next_frame_buffer (vm, node, next0, bi0);
- }
- }
-
- vlib_put_next_frame (vm, node, IP6_DISCOVER_NEIGHBOR_NEXT_DROP,
- n_left_to_next_drop);
- }
-
- return frame->n_vectors;
-}
-
-static uword
-ip6_discover_neighbor (vlib_main_t * vm,
- vlib_node_runtime_t * node, vlib_frame_t * frame)
-{
- return (ip6_discover_neighbor_inline (vm, node, frame, 0));
-}
-
-static uword
-ip6_glean (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
-{
- return (ip6_discover_neighbor_inline (vm, node, frame, 1));
-}
-
-static char *ip6_discover_neighbor_error_strings[] = {
- [IP6_DISCOVER_NEIGHBOR_ERROR_DROP] = "address overflow drops",
- [IP6_DISCOVER_NEIGHBOR_ERROR_REQUEST_SENT] = "neighbor solicitations sent",
- [IP6_DISCOVER_NEIGHBOR_ERROR_NO_SOURCE_ADDRESS]
- = "no source address for ND solicitation",
-};
-
-/* *INDENT-OFF* */
-VLIB_REGISTER_NODE (ip6_discover_neighbor_node) =
-{
- .function = ip6_discover_neighbor,
- .name = "ip6-discover-neighbor",
- .vector_size = sizeof (u32),
- .format_trace = format_ip6_forward_next_trace,
- .n_errors = ARRAY_LEN (ip6_discover_neighbor_error_strings),
- .error_strings = ip6_discover_neighbor_error_strings,
- .n_next_nodes = IP6_DISCOVER_NEIGHBOR_N_NEXT,
- .next_nodes =
- {
- [IP6_DISCOVER_NEIGHBOR_NEXT_DROP] = "ip6-drop",
- [IP6_DISCOVER_NEIGHBOR_NEXT_REPLY_TX] = "interface-output",
- },
-};
-/* *INDENT-ON* */
-
-/* *INDENT-OFF* */
-VLIB_REGISTER_NODE (ip6_glean_node) =
-{
- .function = ip6_glean,
- .name = "ip6-glean",
- .vector_size = sizeof (u32),
- .format_trace = format_ip6_forward_next_trace,
- .n_errors = ARRAY_LEN (ip6_discover_neighbor_error_strings),
- .error_strings = ip6_discover_neighbor_error_strings,
- .n_next_nodes = IP6_DISCOVER_NEIGHBOR_N_NEXT,
- .next_nodes =
- {
- [IP6_DISCOVER_NEIGHBOR_NEXT_DROP] = "ip6-drop",
- [IP6_DISCOVER_NEIGHBOR_NEXT_REPLY_TX] = "interface-output",
- },
-};
-/* *INDENT-ON* */
-
clib_error_t *
-ip6_probe_neighbor (vlib_main_t * vm, ip6_address_t * dst, u32 sw_if_index)
+ip6_probe_neighbor (vlib_main_t * vm, ip6_address_t * dst, u32 sw_if_index,
+ u8 refresh)
{
vnet_main_t *vnm = vnet_get_main ();
ip6_main_t *im = &ip6_main;
vlib_packet_template_get_packet (vm,
&im->discover_neighbor_packet_template,
&bi);
+ if (!h)
+ return clib_error_return (0, "ICMP6 NS packet allocation failed");
hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
sw_if_index);
}
- clib_memcpy (h->link_layer_option.ethernet_address, hi->hw_address,
- vec_len (hi->hw_address));
+ clib_memcpy_fast (h->link_layer_option.ethernet_address, hi->hw_address,
+ vec_len (hi->hw_address));
h->neighbor.icmp.checksum =
ip6_tcp_udp_icmp_compute_checksum (vm, 0, &h->ip, &bogus_length);
adj = adj_get (ai);
/* Peer has been previously resolved, retrieve glean adj instead */
- if (adj->lookup_next_index == IP_LOOKUP_NEXT_REWRITE)
+ if (adj->lookup_next_index == IP_LOOKUP_NEXT_REWRITE && refresh == 0)
{
adj_unlock (ai);
ai = adj_glean_add_or_lock (FIB_PROTOCOL_IP6,
adj_unlock (ai);
return /* no error */ 0;
}
+#endif
typedef enum
{
IP6_REWRITE_NEXT_DROP,
IP6_REWRITE_NEXT_ICMP_ERROR,
+ IP6_REWRITE_NEXT_FRAGMENT,
+ IP6_REWRITE_N_NEXT /* Last */
} ip6_rewrite_next_t;
+/**
+ * This bits of an IPv6 address to mask to construct a multicast
+ * MAC address
+ */
+#define IP6_MCAST_ADDR_MASK 0xffffffff
+
+always_inline void
+ip6_mtu_check (vlib_buffer_t * b, u16 packet_bytes,
+ u16 adj_packet_bytes, bool is_locally_generated,
+ u32 * next, u32 * error)
+{
+ if (adj_packet_bytes >= 1280 && packet_bytes > adj_packet_bytes)
+ {
+ if (is_locally_generated)
+ {
+ /* IP fragmentation */
+ ip_frag_set_vnet_buffer (b, adj_packet_bytes,
+ IP6_FRAG_NEXT_IP6_REWRITE, 0);
+ *next = IP6_REWRITE_NEXT_FRAGMENT;
+ *error = IP6_ERROR_MTU_EXCEEDED;
+ }
+ else
+ {
+ *error = IP6_ERROR_MTU_EXCEEDED;
+ icmp6_error_set_vnet_buffer (b, ICMP6_packet_too_big, 0,
+ adj_packet_bytes);
+ *next = IP6_REWRITE_NEXT_ICMP_ERROR;
+ }
+ }
+}
+
always_inline uword
ip6_rewrite_inline (vlib_main_t * vm,
vlib_node_runtime_t * node,
n_left_from = frame->n_vectors;
next_index = node->cached_next_index;
- u32 thread_index = vlib_get_thread_index ();
+ u32 thread_index = vm->thread_index;
while (n_left_from > 0)
{
u32 pi0, rw_len0, next0, error0, adj_index0;
u32 pi1, rw_len1, next1, error1, adj_index1;
u32 tx_sw_if_index0, tx_sw_if_index1;
+ bool is_locally_originated0, is_locally_originated1;
/* Prefetch next iteration. */
{
error0 = error1 = IP6_ERROR_NONE;
next0 = next1 = IP6_REWRITE_NEXT_DROP;
- if (PREDICT_TRUE (!(p0->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED)))
+ is_locally_originated0 =
+ p0->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED;
+ if (PREDICT_TRUE (!is_locally_originated0))
{
i32 hop_limit0 = ip0->hop_limit;
{
p0->flags &= ~VNET_BUFFER_F_LOCALLY_ORIGINATED;
}
- if (PREDICT_TRUE (!(p1->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED)))
+ is_locally_originated1 =
+ p1->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED;
+ if (PREDICT_TRUE (!is_locally_originated1))
{
i32 hop_limit1 = ip1->hop_limit;
}
/* Check MTU of outgoing interface. */
- error0 =
- (vlib_buffer_length_in_chain (vm, p0) >
- adj0[0].
- rewrite_header.max_l3_packet_bytes ? IP6_ERROR_MTU_EXCEEDED :
- error0);
- error1 =
- (vlib_buffer_length_in_chain (vm, p1) >
- adj1[0].
- rewrite_header.max_l3_packet_bytes ? IP6_ERROR_MTU_EXCEEDED :
- error1);
+ ip6_mtu_check (p0, clib_net_to_host_u16 (ip0->payload_length) +
+ sizeof (ip6_header_t),
+ adj0[0].rewrite_header.max_l3_packet_bytes,
+ is_locally_originated0, &next0, &error0);
+ ip6_mtu_check (p1, clib_net_to_host_u16 (ip1->payload_length) +
+ sizeof (ip6_header_t),
+ adj1[0].rewrite_header.max_l3_packet_bytes,
+ is_locally_originated1, &next1, &error1);
/* Don't adjust the buffer for hop count issue; icmp-error node
* wants to see the IP headerr */
/*
* copy bytes from the IP address into the MAC rewrite
*/
- vnet_fixup_one_header (adj0[0], &ip0->dst_address, ip0);
- vnet_fixup_one_header (adj1[0], &ip1->dst_address, ip1);
+ vnet_ip_mcast_fixup_header (IP6_MCAST_ADDR_MASK,
+ adj0->
+ rewrite_header.dst_mcast_offset,
+ &ip0->dst_address.as_u32[3],
+ (u8 *) ip0);
+ vnet_ip_mcast_fixup_header (IP6_MCAST_ADDR_MASK,
+ adj1->
+ rewrite_header.dst_mcast_offset,
+ &ip1->dst_address.as_u32[3],
+ (u8 *) ip1);
}
vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
u32 pi0, rw_len0;
u32 adj_index0, next0, error0;
u32 tx_sw_if_index0;
+ bool is_locally_originated0;
pi0 = to_next[0] = from[0];
next0 = IP6_REWRITE_NEXT_DROP;
/* Check hop limit */
- if (PREDICT_TRUE (!(p0->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED)))
+ is_locally_originated0 =
+ p0->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED;
+ if (PREDICT_TRUE (!is_locally_originated0))
{
i32 hop_limit0 = ip0->hop_limit;
}
/* Check MTU of outgoing interface. */
- error0 =
- (vlib_buffer_length_in_chain (vm, p0) >
- adj0[0].
- rewrite_header.max_l3_packet_bytes ? IP6_ERROR_MTU_EXCEEDED :
- error0);
+ ip6_mtu_check (p0, clib_net_to_host_u16 (ip0->payload_length) +
+ sizeof (ip6_header_t),
+ adj0[0].rewrite_header.max_l3_packet_bytes,
+ is_locally_originated0, &next0, &error0);
/* Don't adjust the buffer for hop count issue; icmp-error node
- * wants to see the IP headerr */
+ * wants to see the IP header */
if (PREDICT_TRUE (error0 == IP6_ERROR_NONE))
{
p0->current_data -= rw_len0;
}
if (is_mcast)
{
- vnet_fixup_one_header (adj0[0], &ip0->dst_address, ip0);
+ vnet_ip_mcast_fixup_header (IP6_MCAST_ADDR_MASK,
+ adj0->
+ rewrite_header.dst_mcast_offset,
+ &ip0->dst_address.as_u32[3],
+ (u8 *) ip0);
}
p0->error = error_node->errors[error0];
return frame->n_vectors;
}
-static uword
-ip6_rewrite (vlib_main_t * vm,
- vlib_node_runtime_t * node, vlib_frame_t * frame)
+VLIB_NODE_FN (ip6_rewrite_node) (vlib_main_t * vm,
+ vlib_node_runtime_t * node,
+ vlib_frame_t * frame)
{
if (adj_are_counters_enabled ())
return ip6_rewrite_inline (vm, node, frame, 1, 0, 0);
return ip6_rewrite_inline (vm, node, frame, 0, 0, 0);
}
-static uword
-ip6_rewrite_mcast (vlib_main_t * vm,
- vlib_node_runtime_t * node, vlib_frame_t * frame)
+VLIB_NODE_FN (ip6_rewrite_bcast_node) (vlib_main_t * vm,
+ vlib_node_runtime_t * node,
+ vlib_frame_t * frame)
+{
+ if (adj_are_counters_enabled ())
+ return ip6_rewrite_inline (vm, node, frame, 1, 0, 0);
+ else
+ return ip6_rewrite_inline (vm, node, frame, 0, 0, 0);
+}
+
+VLIB_NODE_FN (ip6_rewrite_mcast_node) (vlib_main_t * vm,
+ vlib_node_runtime_t * node,
+ vlib_frame_t * frame)
{
if (adj_are_counters_enabled ())
return ip6_rewrite_inline (vm, node, frame, 1, 0, 1);
return ip6_rewrite_inline (vm, node, frame, 0, 0, 1);
}
-static uword
-ip6_midchain (vlib_main_t * vm,
- vlib_node_runtime_t * node, vlib_frame_t * frame)
+VLIB_NODE_FN (ip6_midchain_node) (vlib_main_t * vm,
+ vlib_node_runtime_t * node,
+ vlib_frame_t * frame)
{
if (adj_are_counters_enabled ())
return ip6_rewrite_inline (vm, node, frame, 1, 1, 0);
return ip6_rewrite_inline (vm, node, frame, 0, 1, 0);
}
-static uword
-ip6_mcast_midchain (vlib_main_t * vm,
- vlib_node_runtime_t * node, vlib_frame_t * frame)
+VLIB_NODE_FN (ip6_mcast_midchain_node) (vlib_main_t * vm,
+ vlib_node_runtime_t * node,
+ vlib_frame_t * frame)
{
if (adj_are_counters_enabled ())
return ip6_rewrite_inline (vm, node, frame, 1, 1, 1);
/* *INDENT-OFF* */
VLIB_REGISTER_NODE (ip6_midchain_node) =
{
- .function = ip6_midchain,
.name = "ip6-midchain",
.vector_size = sizeof (u32),
.format_trace = format_ip6_forward_next_trace,
.sibling_of = "ip6-rewrite",
};
-/* *INDENT-ON* */
-VLIB_NODE_FUNCTION_MULTIARCH (ip6_midchain_node, ip6_midchain);
-
-/* *INDENT-OFF* */
VLIB_REGISTER_NODE (ip6_rewrite_node) =
{
- .function = ip6_rewrite,
.name = "ip6-rewrite",
.vector_size = sizeof (u32),
.format_trace = format_ip6_rewrite_trace,
- .n_next_nodes = 2,
+ .n_next_nodes = IP6_REWRITE_N_NEXT,
.next_nodes =
{
[IP6_REWRITE_NEXT_DROP] = "ip6-drop",
[IP6_REWRITE_NEXT_ICMP_ERROR] = "ip6-icmp-error",
+ [IP6_REWRITE_NEXT_FRAGMENT] = "ip6-frag",
},
};
-/* *INDENT-ON* */
-VLIB_NODE_FUNCTION_MULTIARCH (ip6_rewrite_node, ip6_rewrite);
+VLIB_REGISTER_NODE (ip6_rewrite_bcast_node) = {
+ .name = "ip6-rewrite-bcast",
+ .vector_size = sizeof (u32),
+
+ .format_trace = format_ip6_rewrite_trace,
+ .sibling_of = "ip6-rewrite",
+};
-/* *INDENT-OFF* */
VLIB_REGISTER_NODE (ip6_rewrite_mcast_node) =
{
- .function = ip6_rewrite_mcast,
.name = "ip6-rewrite-mcast",
.vector_size = sizeof (u32),
.format_trace = format_ip6_rewrite_trace,
.sibling_of = "ip6-rewrite",
};
-/* *INDENT-ON* */
-VLIB_NODE_FUNCTION_MULTIARCH (ip6_rewrite_mcast_node, ip6_rewrite_mcast);
-/* *INDENT-OFF* */
-VLIB_REGISTER_NODE (ip6_mcast_midchain_node, static) =
+VLIB_REGISTER_NODE (ip6_mcast_midchain_node) =
{
- .function = ip6_mcast_midchain,
.name = "ip6-mcast-midchain",
.vector_size = sizeof (u32),
.format_trace = format_ip6_rewrite_trace,
.sibling_of = "ip6-rewrite",
};
-/* *INDENT-ON* */
-VLIB_NODE_FUNCTION_MULTIARCH (ip6_mcast_midchain_node, ip6_mcast_midchain);
+/* *INDENT-ON* */
/*
* Hop-by-Hop handling
*/
+#ifndef CLIB_MARCH_VARIANT
ip6_hop_by_hop_main_t ip6_hop_by_hop_main;
+#endif /* CLIB_MARCH_VARIANT */
#define foreach_ip6_hop_by_hop_error \
_(PROCESSED, "pkts with ip6 hop-by-hop options") \
u8 option_data[256];
} ip6_hop_by_hop_trace_t;
-vlib_node_registration_t ip6_hop_by_hop_node;
+extern vlib_node_registration_t ip6_hop_by_hop_node;
static char *ip6_hop_by_hop_error_strings[] = {
#define _(sym,string) string,
#undef _
};
+#ifndef CLIB_MARCH_VARIANT
u8 *
format_ip6_hop_by_hop_ext_hdr (u8 * s, va_list * args)
{
}
return s;
}
+#endif
static u8 *
format_ip6_hop_by_hop_trace (u8 * s, va_list * args)
/*
* Process the Hop-by-Hop Options header
*/
-static uword
-ip6_hop_by_hop (vlib_main_t * vm,
- vlib_node_runtime_t * node, vlib_frame_t * frame)
+VLIB_NODE_FN (ip6_hop_by_hop_node) (vlib_main_t * vm,
+ vlib_node_runtime_t * node,
+ vlib_frame_t * frame)
{
vlib_node_runtime_t *error_node =
vlib_node_get_runtime (vm, ip6_hop_by_hop_node.index);
ARRAY_LEN (t->option_data) ? trace_len :
ARRAY_LEN (t->option_data);
t->trace_len = trace_len;
- clib_memcpy (t->option_data, hbh0, trace_len);
+ clib_memcpy_fast (t->option_data, hbh0, trace_len);
}
if (b1->flags & VLIB_BUFFER_IS_TRACED)
{
ARRAY_LEN (t->option_data) ? trace_len :
ARRAY_LEN (t->option_data);
t->trace_len = trace_len;
- clib_memcpy (t->option_data, hbh1, trace_len);
+ clib_memcpy_fast (t->option_data, hbh1, trace_len);
}
}
ARRAY_LEN (t->option_data) ? trace_len :
ARRAY_LEN (t->option_data);
t->trace_len = trace_len;
- clib_memcpy (t->option_data, hbh0, trace_len);
+ clib_memcpy_fast (t->option_data, hbh0, trace_len);
}
b0->error = error_node->errors[error0];
/* *INDENT-OFF* */
VLIB_REGISTER_NODE (ip6_hop_by_hop_node) =
{
- .function = ip6_hop_by_hop,
.name = "ip6-hop-by-hop",
.sibling_of = "ip6-lookup",
.vector_size = sizeof (u32),
};
/* *INDENT-ON* */
-VLIB_NODE_FUNCTION_MULTIARCH (ip6_hop_by_hop_node, ip6_hop_by_hop);
-
static clib_error_t *
ip6_hop_by_hop_init (vlib_main_t * vm)
{
ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
- memset (hm->options, 0, sizeof (hm->options));
- memset (hm->trace, 0, sizeof (hm->trace));
+ clib_memset (hm->options, 0, sizeof (hm->options));
+ clib_memset (hm->trace, 0, sizeof (hm->trace));
hm->next_override = IP6_LOOKUP_NEXT_POP_HOP_BY_HOP;
return (0);
}
VLIB_INIT_FUNCTION (ip6_hop_by_hop_init);
+#ifndef CLIB_MARCH_VARIANT
void
ip6_hbh_set_next_override (uword next)
{
/* Global IP6 main. */
ip6_main_t ip6_main;
+#endif
static clib_error_t *
ip6_lookup_init (vlib_main_t * vm)
if (im->lookup_table_size == 0)
im->lookup_table_size = IP6_FIB_DEFAULT_HASH_MEMORY_SIZE;
- BV (clib_bihash_init) (&(im->ip6_table[IP6_FIB_TABLE_FWDING].ip6_hash),
+ clib_bihash_init_24_8 (&(im->ip6_table[IP6_FIB_TABLE_FWDING].ip6_hash),
"ip6 FIB fwding table",
im->lookup_table_nbuckets, im->lookup_table_size);
- BV (clib_bihash_init) (&im->ip6_table[IP6_FIB_TABLE_NON_FWDING].ip6_hash,
+ clib_bihash_init_24_8 (&im->ip6_table[IP6_FIB_TABLE_NON_FWDING].ip6_hash,
"ip6 FIB non-fwding table",
im->lookup_table_nbuckets, im->lookup_table_size);
+ clib_bihash_init_40_8 (&im->ip6_mtable.ip6_mhash,
+ "ip6 mFIB table",
+ im->lookup_table_nbuckets, im->lookup_table_size);
/* Create FIB with index 0 and table id of 0. */
fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6, 0,
{
icmp6_neighbor_solicitation_header_t p;
- memset (&p, 0, sizeof (p));
+ clib_memset (&p, 0, sizeof (p));
p.ip.ip_version_traffic_class_and_flow_label =
clib_host_to_net_u32 (0x6 << 28);
VLIB_INIT_FUNCTION (ip6_lookup_init);
-void
-ip6_link_local_address_from_ethernet_mac_address (ip6_address_t * ip,
- u8 * mac)
-{
- ip->as_u64[0] = clib_host_to_net_u64 (0xFE80000000000000ULL);
- /* Invert the "u" bit */
- ip->as_u8[8] = mac[0] ^ (1 << 1);
- ip->as_u8[9] = mac[1];
- ip->as_u8[10] = mac[2];
- ip->as_u8[11] = 0xFF;
- ip->as_u8[12] = 0xFE;
- ip->as_u8[13] = mac[3];
- ip->as_u8[14] = mac[4];
- ip->as_u8[15] = mac[5];
-}
-
-void
-ip6_ethernet_mac_address_from_link_local_address (u8 * mac,
- ip6_address_t * ip)
-{
- /* Invert the previously inverted "u" bit */
- mac[0] = ip->as_u8[8] ^ (1 << 1);
- mac[1] = ip->as_u8[9];
- mac[2] = ip->as_u8[10];
- mac[3] = ip->as_u8[13];
- mac[4] = ip->as_u8[14];
- mac[5] = ip->as_u8[15];
-}
-
static clib_error_t *
test_ip6_link_command_fn (vlib_main_t * vm,
unformat_input_t * input, vlib_cli_command_t * cmd)
};
/* *INDENT-ON* */
+#ifndef CLIB_MARCH_VARIANT
int
vnet_set_ip6_flow_hash (u32 table_id, u32 flow_hash_config)
{
return 0;
}
+#endif
static clib_error_t *
set_ip6_flow_hash_command_fn (vlib_main_t * vm,
};
/* *INDENT-ON* */
+#ifndef CLIB_MARCH_VARIANT
int
vnet_set_ip6_classify_intfc (vlib_main_t * vm, u32 sw_if_index,
u32 table_index)
return 0;
}
+#endif
static clib_error_t *
set_ip6_classify_command_fn (vlib_main_t * vm,