#include <vnet/vnet.h>
#include <vnet/ip/ip.h>
#include <vnet/ip/ip_frag.h>
-#include <vnet/ip/ip6_neighbor.h>
+#include <vnet/ip/ip6_link.h>
#include <vnet/ethernet/ethernet.h> /* for ethernet_header_t */
#include <vnet/srp/srp.h> /* for srp_hw_interface_class */
#include <vppinfra/cache.h>
ip_lookup_main_t *lm = &im->lookup_main;
ip_interface_prefix_t *if_prefix;
+ /* *INDENT-OFF* */
ip_interface_prefix_key_t key = {
.prefix = {
- .fp_len = address_length,
- .fp_proto = FIB_PROTOCOL_IP6,
- .fp_addr.ip6 = {
- .as_u64 = {
- address->as_u64[0] &
- im->fib_masks[address_length].
- as_u64[0],
- address->
- as_u64[1] &
- im->fib_masks[address_length].
- as_u64[1],
- },
- },
- },
+ .fp_len = address_length,
+ .fp_proto = FIB_PROTOCOL_IP6,
+ .fp_addr.ip6 = {
+ .as_u64 = {
+ address->as_u64[0] & im->fib_masks[address_length].as_u64[0],
+ address->as_u64[1] & im->fib_masks[address_length].as_u64[1],
+ },
+ },
+ },
.sw_if_index = sw_if_index,
};
+ /* *INDENT-ON* */
/* If prefix already set on interface, just increment ref count & return */
if_prefix = ip_get_interface_prefix (lm, &key);
ip_lookup_main_t *lm = &im->lookup_main;
ip_interface_prefix_t *if_prefix;
+ /* *INDENT-OFF* */
ip_interface_prefix_key_t key = {
.prefix = {
- .fp_len = address_length,
- .fp_proto = FIB_PROTOCOL_IP6,
- .fp_addr.ip6 = {
- .as_u64 = {
- address->as_u64[0] &
- im->fib_masks[address_length].
- as_u64[0],
- address->
- as_u64[1] &
- im->fib_masks[address_length].
- as_u64[1],
- },
- },
- },
+ .fp_len = address_length,
+ .fp_proto = FIB_PROTOCOL_IP6,
+ .fp_addr.ip6 = {
+ .as_u64 = {
+ address->as_u64[0] & im->fib_masks[address_length].as_u64[0],
+ address->as_u64[1] & im->fib_masks[address_length].as_u64[1],
+ },
+ },
+ },
.sw_if_index = sw_if_index,
};
+ /* *INDENT-ON* */
if_prefix = ip_get_interface_prefix (lm, &key);
if (!if_prefix)
if (if_prefix->ref_count > 0)
return;
- /* length <= 30, delete glean route */
+ /* length <= 128, delete glean route */
if (address_length <= 128)
{
/* remove glean route for prefix */
fib_table_entry_delete (fib_index, &key.prefix, FIB_SOURCE_INTERFACE);
-
}
mhash_unset (&lm->prefix_to_if_prefix_index, &key, 0 /* old_value */ );
clib_error_t *error;
u32 if_address_index;
ip6_address_fib_t ip6_af, *addr_fib = 0;
- ip6_address_t ll_addr;
+ const ip6_address_t *ll_addr;
/* local0 interface doesn't support IP addressing */
if (sw_if_index == 0)
}
if (!is_del)
{
- return ip6_neighbor_set_link_local_address (vm, sw_if_index,
- address);
+ int rv;
+
+ rv = ip6_set_link_local_address (sw_if_index, address);
+
+ if (rv)
+ {
+ vnm->api_errno = rv;
+ return clib_error_create ("address not assignable");
+ }
}
else
{
- ll_addr = ip6_neighbor_get_link_local_address (sw_if_index);
- if (ip6_address_is_equal (&ll_addr, address))
+ ll_addr = ip6_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");
}
ip6_sw_interface_enable_disable (sw_if_index, !is_del);
+ if (!is_del)
+ ip6_link_enable (sw_if_index);
- if (is_del)
- ip6_del_interface_routes (sw_if_index,
- im, ip6_af.fib_index, address, address_length);
- else
- ip6_add_interface_routes (vnm, sw_if_index,
- im, ip6_af.fib_index,
- pool_elt_at_index (lm->if_address_pool,
- if_address_index));
-
+ /* intf addr routes are added/deleted on admin up/down */
+ if (vnet_sw_interface_is_admin_up (vnm, sw_if_index))
+ {
+ if (is_del)
+ ip6_del_interface_routes (sw_if_index,
+ im, ip6_af.fib_index, address,
+ address_length);
+ else
+ ip6_add_interface_routes (vnm, sw_if_index,
+ im, ip6_af.fib_index,
+ pool_elt_at_index (lm->if_address_pool,
+ if_address_index));
+ }
{
ip6_add_del_interface_address_callback_t *cb;
vec_foreach (cb, im->add_del_interface_address_callbacks)
cb->function (im, cb->function_opaque, sw_if_index,
address, address_length, if_address_index, is_del);
}
+ if (is_del)
+ ip6_link_disable (sw_if_index);
done:
vec_free (addr_fib);
ip6_address_t *address;
vlib_main_t *vm = vlib_get_main ();
- ip6_neighbor_sw_interface_add_del (vnm, sw_if_index, 0 /* is_add */ );
vnet_sw_interface_update_unnumbered (sw_if_index, ~0, 0);
/* *INDENT-OFF* */
foreach_ip_interface_address (lm6, ia, sw_if_index, 0,
s = format (s, "\n%U%U",
format_white_space, indent,
format_ip_adjacency_packet_data,
- t->adj_index, t->packet_data, sizeof (t->packet_data));
+ t->packet_data, sizeof (t->packet_data));
return s;
}
ip6_header_t * ip0, int *bogus_lengthp)
{
ip_csum_t sum0;
- u16 sum16, payload_length_host_byte_order;
- u32 i, n_this_buffer, n_bytes_left;
+ u16 payload_length_host_byte_order;
+ u32 i;
u32 headers_size = sizeof (ip0[0]);
u8 *data_this_buffer;
- u8 length_odd;
ASSERT (bogus_lengthp);
*bogus_lengthp = 0;
for (i = 0; i < ARRAY_LEN (ip0->src_address.as_uword); i++)
{
- sum0 = ip_csum_with_carry (sum0,
- clib_mem_unaligned (&ip0->
- src_address.as_uword[i],
- uword));
- sum0 =
- ip_csum_with_carry (sum0,
- clib_mem_unaligned (&ip0->dst_address.as_uword[i],
- uword));
+ sum0 = ip_csum_with_carry
+ (sum0, clib_mem_unaligned (&ip0->src_address.as_uword[i], uword));
+ sum0 = ip_csum_with_carry
+ (sum0, clib_mem_unaligned (&ip0->dst_address.as_uword[i], uword));
}
/* some icmp packets may come with a "router alert" hop-by-hop extension header (e.g., mldv2 packets)
headers_size += skip_bytes;
}
- n_bytes_left = n_this_buffer = payload_length_host_byte_order;
-
if (p0)
- {
- u32 n_ip_bytes_this_buffer =
- p0->current_length - (((u8 *) ip0 - p0->data) - p0->current_data);
- if (n_this_buffer + headers_size > n_ip_bytes_this_buffer)
- {
- n_this_buffer = p0->current_length > headers_size ?
- n_ip_bytes_this_buffer - headers_size : 0;
- }
- }
-
- while (1)
- {
- sum0 = ip_incremental_checksum (sum0, data_this_buffer, n_this_buffer);
- n_bytes_left -= n_this_buffer;
- if (n_bytes_left == 0)
- break;
-
- ASSERT (p0->flags & VLIB_BUFFER_NEXT_PRESENT);
- if (!(p0->flags & VLIB_BUFFER_NEXT_PRESENT))
- {
- *bogus_lengthp = 1;
- return 0xfefe;
- }
-
- length_odd = (n_this_buffer & 1);
-
- p0 = vlib_get_buffer (vm, p0->next_buffer);
- data_this_buffer = vlib_buffer_get_current (p0);
- n_this_buffer = clib_min (p0->current_length, n_bytes_left);
-
- if (PREDICT_FALSE (length_odd))
- {
- /* Prepend a 0 or the resulting checksum will be incorrect. */
- data_this_buffer--;
- n_this_buffer++;
- n_bytes_left++;
- data_this_buffer[0] = 0;
- }
- }
-
- sum16 = ~ip_csum_fold (sum0);
-
- return sum16;
+ return ip_calculate_l4_checksum (vm, p0, sum0,
+ payload_length_host_byte_order,
+ (u8 *) ip0, headers_size, NULL);
+ else
+ return ip_calculate_l4_checksum (vm, 0, sum0,
+ payload_length_host_byte_order, NULL, 0,
+ data_this_buffer);
}
u32
};
/* *INDENT-ON* */
+static_always_inline u8
+ip6_tcp_udp_icmp_bad_length (vlib_main_t * vm, vlib_buffer_t * p0)
+{
+
+ u16 payload_length_host_byte_order;
+ u32 n_this_buffer, n_bytes_left;
+ ip6_header_t *ip0 = vlib_buffer_get_current (p0);
+ u32 headers_size = sizeof (ip0[0]);
+ u8 *data_this_buffer;
+
+
+ data_this_buffer = (u8 *) (ip0 + 1);
+
+ ip6_hop_by_hop_ext_t *ext_hdr = (ip6_hop_by_hop_ext_t *) data_this_buffer;
+
+ /* validate really icmp6 next */
+
+ if (!(ext_hdr->next_hdr == IP_PROTOCOL_ICMP6)
+ || (ext_hdr->next_hdr == IP_PROTOCOL_UDP))
+ return 0;
+
+
+ payload_length_host_byte_order = clib_net_to_host_u16 (ip0->payload_length);
+ n_bytes_left = n_this_buffer = payload_length_host_byte_order;
+
+
+ u32 n_ip_bytes_this_buffer =
+ p0->current_length - (((u8 *) ip0 - p0->data) - p0->current_data);
+ if (n_this_buffer + headers_size > n_ip_bytes_this_buffer)
+ {
+ n_this_buffer = p0->current_length > headers_size ?
+ n_ip_bytes_this_buffer - headers_size : 0;
+ }
+
+ n_bytes_left -= n_this_buffer;
+ n_bytes_left -= p0->total_length_not_including_first_buffer;
+
+ if (n_bytes_left == 0)
+ return 0;
+ else
+ return 1;
+}
+
+
always_inline uword
ip6_local_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
vlib_frame_t * frame, int head_of_feature_arc)
{
flags[0] = ip6_tcp_udp_icmp_validate_checksum (vm, b[0]);
good_l4_csum[0] = flags[0] & VNET_BUFFER_F_L4_CHECKSUM_CORRECT;
+ error[0] = IP6_ERROR_UNKNOWN_PROTOCOL;
+ }
+ else
+ {
+ if (ip6_tcp_udp_icmp_bad_length (vm, b[0]))
+ error[0] = IP6_ERROR_BAD_LENGTH;
}
if (PREDICT_FALSE (need_csum[1]))
{
flags[1] = ip6_tcp_udp_icmp_validate_checksum (vm, b[1]);
good_l4_csum[1] = flags[1] & VNET_BUFFER_F_L4_CHECKSUM_CORRECT;
+ error[1] = IP6_ERROR_UNKNOWN_PROTOCOL;
}
+ else
+ {
+ if (ip6_tcp_udp_icmp_bad_length (vm, b[1]))
+ error[1] = IP6_ERROR_BAD_LENGTH;
+ }
+
- error[0] = IP6_ERROR_UNKNOWN_PROTOCOL;
error[0] = len_diff[0] < 0 ? IP6_ERROR_UDP_LENGTH : error[0];
- error[1] = IP6_ERROR_UNKNOWN_PROTOCOL;
+
error[1] = len_diff[1] < 0 ? IP6_ERROR_UDP_LENGTH : error[1];
STATIC_ASSERT (IP6_ERROR_UDP_CHECKSUM + IP_BUILTIN_PROTOCOL_UDP ==
{
flags = ip6_tcp_udp_icmp_validate_checksum (vm, b[0]);
good_l4_csum = flags & VNET_BUFFER_F_L4_CHECKSUM_CORRECT;
+ error = IP6_ERROR_UNKNOWN_PROTOCOL;
}
+ else
+ {
+ if (ip6_tcp_udp_icmp_bad_length (vm, b[0]))
+ error = IP6_ERROR_BAD_LENGTH;
+ }
+
+
- error = IP6_ERROR_UNKNOWN_PROTOCOL;
error = len_diff < 0 ? IP6_ERROR_UDP_LENGTH : error;
STATIC_ASSERT (IP6_ERROR_UDP_CHECKSUM + IP_BUILTIN_PROTOCOL_UDP ==
#ifdef CLIB_MARCH_VARIANT
extern vlib_node_registration_t ip6_local_node;
-
#else
-
void
ip6_register_protocol (u32 protocol, u32 node_index)
{
ASSERT (protocol < ARRAY_LEN (lm->local_next_by_ip_protocol));
lm->local_next_by_ip_protocol[protocol] = IP_LOCAL_NEXT_PUNT;
}
-
-clib_error_t *
-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;
- icmp6_neighbor_solicitation_header_t *h;
- ip6_address_t *src;
- ip_interface_address_t *ia;
- ip_adjacency_t *adj;
- vnet_hw_interface_t *hi;
- vnet_sw_interface_t *si;
- vlib_buffer_t *b;
- adj_index_t ai;
- u32 bi = 0;
- int bogus_length;
-
- si = vnet_get_sw_interface (vnm, sw_if_index);
-
- if (!(si->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP))
- {
- return clib_error_return (0, "%U: interface %U down",
- format_ip6_address, dst,
- format_vnet_sw_if_index_name, vnm,
- sw_if_index);
- }
-
- src =
- ip6_interface_address_matching_destination (im, dst, sw_if_index, &ia);
- if (!src)
- {
- vnm->api_errno = VNET_API_ERROR_NO_MATCHING_INTERFACE;
- return clib_error_return
- (0, "no matching interface address for destination %U (interface %U)",
- format_ip6_address, dst,
- format_vnet_sw_if_index_name, vnm, sw_if_index);
- }
-
- h =
- 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);
-
- /* 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. */
- h->ip.dst_address.as_u8[13] = dst->as_u8[13];
- h->ip.dst_address.as_u8[14] = dst->as_u8[14];
- h->ip.dst_address.as_u8[15] = dst->as_u8[15];
-
- h->ip.src_address = src[0];
- h->neighbor.target_address = dst[0];
-
- if (PREDICT_FALSE (!hi->hw_address))
- {
- return clib_error_return (0, "%U: interface %U do not support ip probe",
- format_ip6_address, dst,
- format_vnet_sw_if_index_name, vnm,
- sw_if_index);
- }
-
- 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);
- ASSERT (bogus_length == 0);
-
- b = vlib_get_buffer (vm, bi);
- vnet_buffer (b)->sw_if_index[VLIB_RX] =
- vnet_buffer (b)->sw_if_index[VLIB_TX] = sw_if_index;
-
- /* Add encapsulation string for software interface (e.g. ethernet header). */
- ip46_address_t nh = {
- .ip6 = *dst,
- };
-
- ai = adj_nbr_add_or_lock (FIB_PROTOCOL_IP6,
- VNET_LINK_IP6, &nh, sw_if_index);
- adj = adj_get (ai);
-
- /* Peer has been previously resolved, retrieve glean adj instead */
- if (adj->lookup_next_index == IP_LOOKUP_NEXT_REWRITE && refresh == 0)
- {
- adj_unlock (ai);
- ai = adj_glean_add_or_lock (FIB_PROTOCOL_IP6,
- VNET_LINK_IP6, sw_if_index, &nh);
- adj = adj_get (ai);
- }
-
- vnet_rewrite_one_header (adj[0], h, sizeof (ethernet_header_t));
- vlib_buffer_advance (b, -adj->rewrite_header.data_bytes);
-
- {
- vlib_frame_t *f = vlib_get_frame_to_node (vm, hi->output_node_index);
- u32 *to_next = vlib_frame_vector_args (f);
- to_next[0] = bi;
- f->n_vectors = 1;
- vlib_put_frame_to_node (vm, hi->output_node_index, f);
- }
-
- adj_unlock (ai);
- return /* no error */ 0;
-}
#endif
typedef enum
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)
+ u32 * next, u8 is_midchain, u32 * error)
{
if (adj_packet_bytes >= 1280 && packet_bytes > adj_packet_bytes)
{
{
/* IP fragmentation */
ip_frag_set_vnet_buffer (b, adj_packet_bytes,
- IP6_FRAG_NEXT_IP6_REWRITE, 0);
+ (is_midchain ?
+ IP_FRAG_NEXT_IP_REWRITE_MIDCHAIN :
+ IP_FRAG_NEXT_IP_REWRITE), 0);
*next = IP6_REWRITE_NEXT_FRAGMENT;
*error = IP6_ERROR_MTU_EXCEEDED;
}
ip6_rewrite_inline_with_gso (vlib_main_t * vm,
vlib_node_runtime_t * node,
vlib_frame_t * frame,
- int do_counters, int is_midchain, int is_mcast,
- int do_gso)
+ int do_counters, int is_midchain, int is_mcast)
{
ip_lookup_main_t *lm = &ip6_main.lookup_main;
u32 *from = vlib_frame_vector_args (frame);
while (n_left_from >= 4 && n_left_to_next >= 2)
{
- ip_adjacency_t *adj0, *adj1;
+ const ip_adjacency_t *adj0, *adj1;
vlib_buffer_t *p0, *p1;
ip6_header_t *ip0, *ip1;
u32 pi0, rw_len0, next0, error0, adj_index0;
u16 ip1_len =
clib_net_to_host_u16 (ip1->payload_length) +
sizeof (ip6_header_t);
- if (do_gso && (p0->flags & VNET_BUFFER_F_GSO))
+ if (p0->flags & VNET_BUFFER_F_GSO)
ip0_len = gso_mtu_sz (p0);
- if (do_gso && (p1->flags & VNET_BUFFER_F_GSO))
+ if (p1->flags & VNET_BUFFER_F_GSO)
ip1_len = gso_mtu_sz (p1);
ip6_mtu_check (p0, ip0_len,
adj0[0].rewrite_header.max_l3_packet_bytes,
- is_locally_originated0, &next0, &error0);
+ is_locally_originated0, &next0, is_midchain,
+ &error0);
ip6_mtu_check (p1, ip1_len,
adj1[0].rewrite_header.max_l3_packet_bytes,
- is_locally_originated1, &next1, &error1);
+ is_locally_originated1, &next1, is_midchain,
+ &error1);
/* Don't adjust the buffer for hop count issue; icmp-error node
* wants to see the IP header */
u16 ip0_len =
clib_net_to_host_u16 (ip0->payload_length) +
sizeof (ip6_header_t);
- if (do_gso && (p0->flags & VNET_BUFFER_F_GSO))
+ if (p0->flags & VNET_BUFFER_F_GSO)
ip0_len = gso_mtu_sz (p0);
ip6_mtu_check (p0, ip0_len,
adj0[0].rewrite_header.max_l3_packet_bytes,
- is_locally_originated0, &next0, &error0);
+ is_locally_originated0, &next0, is_midchain,
+ &error0);
/* Don't adjust the buffer for hop count issue; icmp-error node
* wants to see the IP header */
vlib_frame_t * frame,
int do_counters, int is_midchain, int is_mcast)
{
- vnet_main_t *vnm = vnet_get_main ();
- if (PREDICT_FALSE (vnm->interface_main.gso_interface_count > 0))
- return ip6_rewrite_inline_with_gso (vm, node, frame, do_counters,
- is_midchain, is_mcast,
- 1 /* do_gso */ );
- else
- return ip6_rewrite_inline_with_gso (vm, node, frame, do_counters,
- is_midchain, is_mcast,
- 0 /* no do_gso */ );
+ return ip6_rewrite_inline_with_gso (vm, node, frame, do_counters,
+ is_midchain, is_mcast);
}
VLIB_NODE_FN (ip6_rewrite_node) (vlib_main_t * vm,
/* Unless explicitly configured, don't process HBH options */
im->hbh_enabled = 0;
- {
- icmp6_neighbor_solicitation_header_t p;
-
- clib_memset (&p, 0, sizeof (p));
-
- p.ip.ip_version_traffic_class_and_flow_label =
- clib_host_to_net_u32 (0x6 << 28);
- p.ip.payload_length =
- clib_host_to_net_u16 (sizeof (p) -
- STRUCT_OFFSET_OF
- (icmp6_neighbor_solicitation_header_t, neighbor));
- p.ip.protocol = IP_PROTOCOL_ICMP6;
- p.ip.hop_limit = 255;
- ip6_set_solicited_node_multicast_address (&p.ip.dst_address, 0);
-
- p.neighbor.icmp.type = ICMP6_neighbor_solicitation;
-
- p.link_layer_option.header.type =
- ICMP6_NEIGHBOR_DISCOVERY_OPTION_source_link_layer_address;
- p.link_layer_option.header.n_data_u64s =
- sizeof (p.link_layer_option) / sizeof (u64);
-
- vlib_packet_template_init (vm,
- &im->discover_neighbor_packet_template,
- &p, sizeof (p),
- /* alloc chunk size */ 8,
- "ip6 neighbor discovery");
- }
-
return error;
}
VLIB_INIT_FUNCTION (ip6_lookup_init);
-static clib_error_t *
-test_ip6_link_command_fn (vlib_main_t * vm,
- unformat_input_t * input, vlib_cli_command_t * cmd)
-{
- u8 mac[6];
- ip6_address_t _a, *a = &_a;
-
- if (unformat (input, "%U", unformat_ethernet_address, mac))
- {
- ip6_link_local_address_from_ethernet_mac_address (a, mac);
- vlib_cli_output (vm, "Link local address: %U", format_ip6_address, a);
- ip6_ethernet_mac_address_from_link_local_address (mac, a);
- vlib_cli_output (vm, "Original MAC address: %U",
- format_ethernet_address, mac);
- }
-
- return 0;
-}
-
-/*?
- * This command converts the given MAC Address into an IPv6 link-local
- * address.
- *
- * @cliexpar
- * Example of how to create an IPv6 link-local address:
- * @cliexstart{test ip6 link 16:d9:e0:91:79:86}
- * Link local address: fe80::14d9:e0ff:fe91:7986
- * Original MAC address: 16:d9:e0:91:79:86
- * @cliexend
-?*/
-/* *INDENT-OFF* */
-VLIB_CLI_COMMAND (test_link_command, static) =
-{
- .path = "test ip6 link",
- .function = test_ip6_link_command_fn,
- .short_help = "test ip6 link <mac-address>",
-};
-/* *INDENT-ON* */
-
#ifndef CLIB_MARCH_VARIANT
int
vnet_set_ip6_flow_hash (u32 table_id, u32 flow_hash_config)