-static uword
-ip6_local (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
-{
- 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;
- vlib_node_runtime_t *error_node =
- vlib_node_get_runtime (vm, ip6_input_node.index);
-
- 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_checksum0;
- u8 error1, type1, good_l4_checksum1;
- 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;
-
- p0 = vlib_get_buffer (vm, pi0);
- p1 = vlib_get_buffer (vm, pi1);
-
- ip0 = vlib_buffer_get_current (p0);
- ip1 = vlib_buffer_get_current (p1);
-
- vnet_buffer (p0)->ip.start_of_ip_header = p0->current_data;
- vnet_buffer (p1)->ip.start_of_ip_header = p1->current_data;
-
- type0 = lm->builtin_protocol_by_ip_protocol[ip0->protocol];
- type1 = lm->builtin_protocol_by_ip_protocol[ip1->protocol];
-
- next0 = lm->local_next_by_ip_protocol[ip0->protocol];
- next1 = lm->local_next_by_ip_protocol[ip1->protocol];
-
- flags0 = p0->flags;
- flags1 = p1->flags;
-
- good_l4_checksum0 = (flags0 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
- good_l4_checksum1 = (flags1 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
- len_diff0 = 0;
- len_diff1 = 0;
-
- if (PREDICT_TRUE (IP_PROTOCOL_UDP == ip6_locate_header (p0, ip0,
- IP_PROTOCOL_UDP,
- &udp_offset0)))
- {
- udp0 = (udp_header_t *) ((u8 *) ip0 + udp_offset0);
- /* Don't verify UDP checksum for packets with explicit zero checksum. */
- good_l4_checksum0 |= type0 == IP_BUILTIN_PROTOCOL_UDP
- && udp0->checksum == 0;
- /* Verify UDP length. */
- 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 (IP_PROTOCOL_UDP == ip6_locate_header (p1, ip1,
- IP_PROTOCOL_UDP,
- &udp_offset1)))
- {
- udp1 = (udp_header_t *) ((u8 *) ip1 + udp_offset1);
- /* Don't verify UDP checksum for packets with explicit zero checksum. */
- good_l4_checksum1 |= type1 == IP_BUILTIN_PROTOCOL_UDP
- && udp1->checksum == 0;
- /* Verify UDP length. */
- 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;
- }
-
- good_l4_checksum0 |= type0 == IP_BUILTIN_PROTOCOL_UNKNOWN;
- good_l4_checksum1 |= type1 == IP_BUILTIN_PROTOCOL_UNKNOWN;
-
- 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_checksum0
- && !(flags0 & IP_BUFFER_L4_CHECKSUM_COMPUTED)))
- {
- flags0 = ip6_tcp_udp_icmp_validate_checksum (vm, p0);
- good_l4_checksum0 =
- (flags0 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
- }
- if (PREDICT_FALSE (type1 != IP_BUILTIN_PROTOCOL_UNKNOWN
- && !good_l4_checksum1
- && !(flags1 & IP_BUFFER_L4_CHECKSUM_COMPUTED)))
- {
- flags1 = ip6_tcp_udp_icmp_validate_checksum (vm, p1);
- good_l4_checksum1 =
- (flags1 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
- }
-
- error0 = error1 = IP6_ERROR_UNKNOWN_PROTOCOL;
-
- error0 = len_diff0 < 0 ? IP6_ERROR_UDP_LENGTH : error0;
- error1 = len_diff1 < 0 ? IP6_ERROR_UDP_LENGTH : error1;
-
- 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_checksum0 ? IP6_ERROR_UDP_CHECKSUM + type0 : error0);
- error1 =
- (!good_l4_checksum1 ? IP6_ERROR_UDP_CHECKSUM + type1 : error1);
-
- /* 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))
- {
- error0 = (!ip6_urpf_loose_check (im, p0, ip0)
- ? IP6_ERROR_SRC_LOOKUP_MISS : error0);
- }
- 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);
- }
-
- next0 =
- error0 != IP6_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next0;
- next1 =
- error1 != IP6_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next1;
-
- p0->error = error_node->errors[error0];
- p1->error = error_node->errors[error1];
-
- 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_checksum0;
- u32 udp_offset0;
-
- pi0 = to_next[0] = from[0];
- from += 1;
- n_left_from -= 1;
- to_next += 1;
- n_left_to_next -= 1;
-
- p0 = vlib_get_buffer (vm, pi0);
-
- ip0 = vlib_buffer_get_current (p0);
-
- vnet_buffer (p0)->ip.start_of_ip_header = p0->current_data;
-
- type0 = lm->builtin_protocol_by_ip_protocol[ip0->protocol];
- next0 = lm->local_next_by_ip_protocol[ip0->protocol];
-
- flags0 = p0->flags;
-
- good_l4_checksum0 = (flags0 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
- len_diff0 = 0;
-
- if (PREDICT_TRUE (IP_PROTOCOL_UDP == ip6_locate_header (p0, ip0,
- IP_PROTOCOL_UDP,
- &udp_offset0)))
- {
- udp0 = (udp_header_t *) ((u8 *) ip0 + udp_offset0);
- /* Don't verify UDP checksum for packets with explicit zero checksum. */
- good_l4_checksum0 |= type0 == IP_BUILTIN_PROTOCOL_UDP
- && udp0->checksum == 0;
- /* Verify UDP length. */
- 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;
- }
-
- good_l4_checksum0 |= type0 == IP_BUILTIN_PROTOCOL_UNKNOWN;
- len_diff0 = type0 == IP_BUILTIN_PROTOCOL_UDP ? len_diff0 : 0;
-
- if (PREDICT_FALSE (type0 != IP_BUILTIN_PROTOCOL_UNKNOWN
- && !good_l4_checksum0
- && !(flags0 & IP_BUFFER_L4_CHECKSUM_COMPUTED)))
- {
- flags0 = ip6_tcp_udp_icmp_validate_checksum (vm, p0);
- good_l4_checksum0 =
- (flags0 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
- }
-
- error0 = IP6_ERROR_UNKNOWN_PROTOCOL;
-
- error0 = len_diff0 < 0 ? IP6_ERROR_UDP_LENGTH : error0;
-
- 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_checksum0 ? IP6_ERROR_UDP_CHECKSUM + type0 : error0);
-
- /* 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))
- {
- error0 = (!ip6_urpf_loose_check (im, p0, ip0)
- ? IP6_ERROR_SRC_LOOKUP_MISS : error0);
- }
-
- next0 =
- error0 != IP6_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next0;
-
- p0->error = error_node->errors[error0];
-
- 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);
- }
-
- return frame->n_vectors;
-}
-
-/* *INDENT-OFF* */
-VLIB_REGISTER_NODE (ip6_local_node, static) =
-{
- .function = ip6_local,
- .name = "ip6-local",
- .vector_size = sizeof (u32),
- .format_trace = format_ip6_forward_next_trace,
- .n_next_nodes = IP_LOCAL_N_NEXT,
- .next_nodes =
- {
- [IP_LOCAL_NEXT_DROP] = "error-drop",
- [IP_LOCAL_NEXT_PUNT] = "error-punt",
- [IP_LOCAL_NEXT_UDP_LOOKUP] = "ip6-udp-lookup",
- [IP_LOCAL_NEXT_ICMP] = "ip6-icmp-input",
- },
-};
-/* *INDENT-ON* */
-
-VLIB_NODE_FUNCTION_MULTIARCH (ip6_local_node, ip6_local);
-
-void
-ip6_register_protocol (u32 protocol, u32 node_index)
-{
- vlib_main_t *vm = vlib_get_main ();
- ip6_main_t *im = &ip6_main;
- ip_lookup_main_t *lm = &im->lookup_main;
-
- ASSERT (protocol < ARRAY_LEN (lm->local_next_by_ip_protocol));
- lm->local_next_by_ip_protocol[protocol] =
- vlib_node_add_next (vm, ip6_local_node.index, node_index);
-}
-
-typedef enum