X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=src%2Fvnet%2Fip%2Fip6_forward.c;h=06c473b1495cc67997b9d0fbcc011fa0f3a6078d;hb=2f4586d9b3507243918c11ce99b9d151d5bde7a0;hp=252bdf975be695facf1602de442493ad165bc651;hpb=e7eba48937c52478d3844745ebb63a4b9ce8d681;p=vpp.git diff --git a/src/vnet/ip/ip6_forward.c b/src/vnet/ip/ip6_forward.c index 252bdf975be..06c473b1495 100644 --- a/src/vnet/ip/ip6_forward.c +++ b/src/vnet/ip/ip6_forward.c @@ -40,7 +40,7 @@ #include #include #include -#include +#include #include /* for ethernet_header_t */ #include /* for srp_hw_interface_class */ #include @@ -48,7 +48,10 @@ #include #include #include +#include #include +#include +#include #ifndef CLIB_MARCH_VARIANT #include @@ -70,20 +73,15 @@ ip6_add_interface_prefix_routes (ip6_main_t * im, 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, }; @@ -180,20 +178,15 @@ ip6_del_interface_prefix_routes (ip6_main_t * im, 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, }; @@ -201,7 +194,7 @@ ip6_del_interface_prefix_routes (ip6_main_t * im, if (!if_prefix) { clib_warning ("Prefix not found while deleting %U", - format_ip4_address_and_length, address, address_length); + format_ip6_address_and_length, address, address_length); return; } @@ -210,12 +203,11 @@ ip6_del_interface_prefix_routes (ip6_main_t * im, 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 */ ); @@ -245,6 +237,8 @@ void ip6_sw_interface_enable_disable (u32 sw_if_index, u32 is_enable) { ip6_main_t *im = &ip6_main; + vnet_main_t *vnm = vnet_get_main (); + vnet_hw_interface_t *hi = vnet_get_sup_hw_interface (vnm, sw_if_index); vec_validate_init_empty (im->ip_enabled_by_sw_if_index, sw_if_index, 0); @@ -270,6 +264,11 @@ ip6_sw_interface_enable_disable (u32 sw_if_index, u32 is_enable) vnet_feature_enable_disable ("ip6-multicast", "ip6-not-enabled", sw_if_index, !is_enable, 0, 0); + + if (is_enable) + hi->l3_if_count++; + else if (hi->l3_if_count) + hi->l3_if_count--; } /* get first interface address */ @@ -280,7 +279,6 @@ ip6_interface_first_address (ip6_main_t * im, u32 sw_if_index) ip_interface_address_t *ia = 0; ip6_address_t *result = 0; - /* *INDENT-OFF* */ foreach_ip_interface_address (lm, ia, sw_if_index, 1 /* honor unnumbered */, ({ @@ -288,7 +286,6 @@ ip6_interface_first_address (ip6_main_t * im, u32 sw_if_index) result = a; break; })); - /* *INDENT-ON* */ return result; } @@ -301,16 +298,16 @@ ip6_add_del_interface_address (vlib_main_t * vm, vnet_main_t *vnm = vnet_get_main (); ip6_main_t *im = &ip6_main; ip_lookup_main_t *lm = &im->lookup_main; - clib_error_t *error; + clib_error_t *error = NULL; 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) + error = vnet_sw_interface_supports_addressing (vnm, sw_if_index); + if (error) { - return - clib_error_create ("local0 interface doesn't support IP addressing"); + vnm->api_errno = VNET_API_ERROR_UNSUPPORTED; + return error; } if (ip6_address_is_link_local_unicast (address)) @@ -324,13 +321,20 @@ ip6_add_del_interface_address (vlib_main_t * vm, } if (!is_del) { - return ip6_neighbor_set_link_local_address (vm, sw_if_index, - address); + int rv; + + rv = ip6_link_set_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"); @@ -341,16 +345,14 @@ ip6_add_del_interface_address (vlib_main_t * vm, 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); + return (NULL); + } ip6_addr_fib_init (&ip6_af, address, 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 @@ -358,8 +360,8 @@ ip6_add_del_interface_address (vlib_main_t * vm, ip_interface_address_t *ia; vnet_sw_interface_t *sif; - pool_foreach(sif, vnm->interface_main.sw_interfaces, - ({ + 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]) { @@ -370,6 +372,7 @@ ip6_add_del_interface_address (vlib_main_t * vm, 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, @@ -383,10 +386,17 @@ ip6_add_del_interface_address (vlib_main_t * vm, !ip6_address_is_equal (x, address)) continue; + if (ia->flags & IP_INTERFACE_ADDRESS_FLAG_STALE) + /* if the address we're comparing against is stale + * then the CP has not added this one back yet, maybe + * it never will, so we have to assume it won't and + * ignore it. if it does add it back, then it will fail + * because this one is now present */ + continue; + /* error if the length or intf was different */ vnm->api_errno = VNET_API_ERROR_DUPLICATE_IF_ADDRESS; - return - clib_error_create + error = clib_error_create ("failed to add %U which conflicts with %U for interface %U", format_ip6_address_and_length, address, address_length, @@ -394,43 +404,107 @@ ip6_add_del_interface_address (vlib_main_t * vm, ia->address_length, format_vnet_sw_if_index_name, vnm, sif->sw_if_index); + goto done; } })); } - })); + } } - /* *INDENT-ON* */ - { - uword elts_before = pool_elts (lm->if_address_pool); + if_address_index = ip_interface_address_find (lm, addr_fib, address_length); - error = ip_interface_address_add_del - (lm, sw_if_index, addr_fib, address_length, is_del, &if_address_index); - if (error) - goto done; + if (is_del) + { + if (~0 == if_address_index) + { + vnm->api_errno = VNET_API_ERROR_ADDRESS_NOT_FOUND_FOR_INTERFACE; + error = clib_error_create ("%U not found for interface %U", + lm->format_address_and_length, + addr_fib, address_length, + format_vnet_sw_if_index_name, vnm, + sw_if_index); + goto done; + } - /* Pool did not grow: add duplicate address. */ - if (elts_before == pool_elts (lm->if_address_pool)) - goto done; - } + error = ip_interface_address_del (lm, vnm, if_address_index, addr_fib, + address_length, sw_if_index); + if (error) + goto done; + } + else + { + if (~0 != if_address_index) + { + ip_interface_address_t *ia; + + ia = pool_elt_at_index (lm->if_address_pool, if_address_index); + + if (ia->flags & IP_INTERFACE_ADDRESS_FLAG_STALE) + { + if (ia->sw_if_index == sw_if_index) + { + /* re-adding an address during the replace action. + * consdier this the update. clear the flag and + * we're done */ + ia->flags &= ~IP_INTERFACE_ADDRESS_FLAG_STALE; + goto done; + } + else + { + /* The prefix is moving from one interface to another. + * delete the stale and add the new */ + ip6_add_del_interface_address (vm, + ia->sw_if_index, + address, address_length, 1); + ia = NULL; + error = ip_interface_address_add (lm, sw_if_index, + addr_fib, address_length, + &if_address_index); + } + } + else + { + vnm->api_errno = VNET_API_ERROR_DUPLICATE_IF_ADDRESS; + error = clib_error_create + ("Prefix %U already found on interface %U", + lm->format_address_and_length, addr_fib, address_length, + format_vnet_sw_if_index_name, vnm, ia->sw_if_index); + } + } + else + error = ip_interface_address_add (lm, sw_if_index, + addr_fib, address_length, + &if_address_index); + } + + if (error) + goto done; ip6_sw_interface_enable_disable (sw_if_index, !is_del); + if (!is_del) + ip6_link_enable (sw_if_index, NULL); - 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); - } + 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); @@ -447,9 +521,6 @@ ip6_sw_interface_admin_up_down (vnet_main_t * vnm, u32 sw_if_index, u32 flags) ip6_address_t *a; u32 is_admin_up, fib_index; - /* Fill in lookup tables with default table (0). */ - vec_validate (im->fib_index_by_sw_if_index, sw_if_index); - vec_validate_init_empty (im-> lookup_main.if_address_pool_index_by_sw_if_index, sw_if_index, ~0); @@ -458,7 +529,6 @@ ip6_sw_interface_admin_up_down (vnet_main_t * vnm, u32 sw_if_index, u32 flags) fib_index = vec_elt (im->fib_index_by_sw_if_index, sw_if_index); - /* *INDENT-OFF* */ foreach_ip_interface_address (&im->lookup_main, ia, sw_if_index, 0 /* honor unnumbered */, ({ @@ -471,7 +541,6 @@ ip6_sw_interface_admin_up_down (vnet_main_t * vnm, u32 sw_if_index, u32 flags) ip6_del_interface_routes (sw_if_index, im, fib_index, a, ia->address_length); })); - /* *INDENT-ON* */ return 0; } @@ -479,7 +548,6 @@ ip6_sw_interface_admin_up_down (vnet_main_t * vnm, u32 sw_if_index, u32 flags) VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (ip6_sw_interface_admin_up_down); /* Built-in ip6 unicast rx feature path definition */ -/* *INDENT-OFF* */ VNET_FEATURE_ARC_INIT (ip6_unicast, static) = { .arc_name = "ip6-unicast", @@ -604,17 +672,22 @@ VNET_FEATURE_INIT (ip6_interface_output, static) = { .node_name = "interface-output", .runs_before = 0, /* not before any other features */ }; -/* *INDENT-ON* */ 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; - 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_validate_init_empty (im->fib_index_by_sw_if_index, sw_if_index, ~0); + vec_validate_init_empty (im->mfib_index_by_sw_if_index, sw_if_index, ~0); - if (!is_add) + if (is_add) + { + /* Fill in lookup tables with default table (0). */ + im->fib_index_by_sw_if_index[sw_if_index] = 0; + im->mfib_index_by_sw_if_index[sw_if_index] = 0; + } + else { /* Ensure that IPv6 is disabled */ ip6_main_t *im6 = &ip6_main; @@ -623,16 +696,22 @@ ip6_sw_interface_add_del (vnet_main_t * vnm, u32 sw_if_index, u32 is_add) 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, ({ address = ip_interface_address_get_address (lm6, ia); ip6_add_del_interface_address(vm, sw_if_index, address, ia->address_length, 1); })); - /* *INDENT-ON* */ ip6_mfib_interface_enable_disable (sw_if_index, 0); + + if (0 != im6->fib_index_by_sw_if_index[sw_if_index]) + fib_table_bind (FIB_PROTOCOL_IP6, sw_if_index, 0); + if (0 != im6->mfib_index_by_sw_if_index[sw_if_index]) + mfib_table_bind (FIB_PROTOCOL_IP6, sw_if_index, 0); + + /* Erase the lookup tables just in case */ + im6->fib_index_by_sw_if_index[sw_if_index] = ~0; + im6->mfib_index_by_sw_if_index[sw_if_index] = ~0; } vnet_feature_enable_disable ("ip6-unicast", "ip6-not-enabled", sw_if_index, @@ -655,7 +734,6 @@ VLIB_NODE_FN (ip6_lookup_node) (vlib_main_t * vm, static u8 *format_ip6_lookup_trace (u8 * s, va_list * args); -/* *INDENT-OFF* */ VLIB_REGISTER_NODE (ip6_lookup_node) = { .name = "ip6-lookup", @@ -664,7 +742,6 @@ VLIB_REGISTER_NODE (ip6_lookup_node) = .n_next_nodes = IP6_LOOKUP_N_NEXT, .next_nodes = IP6_LOOKUP_NEXT_NODES, }; -/* *INDENT-ON* */ VLIB_NODE_FN (ip6_load_balance_node) (vlib_main_t * vm, vlib_node_runtime_t * node, @@ -842,7 +919,6 @@ VLIB_NODE_FN (ip6_load_balance_node) (vlib_main_t * vm, return frame->n_vectors; } -/* *INDENT-OFF* */ VLIB_REGISTER_NODE (ip6_load_balance_node) = { .name = "ip6-load-balance", @@ -850,7 +926,6 @@ VLIB_REGISTER_NODE (ip6_load_balance_node) = .sibling_of = "ip6-lookup", .format_trace = format_ip6_lookup_trace, }; -/* *INDENT-ON* */ typedef struct { @@ -873,7 +948,10 @@ format_ip6_forward_next_trace (u8 * s, va_list * args) ip6_forward_next_trace_t *t = va_arg (*args, ip6_forward_next_trace_t *); u32 indent = format_get_indent (s); - s = format (s, "%U%U", + s = format (s, "%Ufib:%d adj:%d flow:%d", + format_white_space, indent, + t->fib_index, t->adj_index, t->flow_hash); + s = format (s, "\n%U%U", format_white_space, indent, format_ip6_header, t->packet_data, sizeof (t->packet_data)); return s; @@ -911,7 +989,7 @@ format_ip6_rewrite_trace (u8 * s, va_list * args) 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; } @@ -1013,35 +1091,23 @@ u16 ip6_tcp_udp_icmp_compute_checksum (vlib_main_t * vm, vlib_buffer_t * p0, 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; + ip_csum_t sum0 = 0; + u16 payload_length, payload_length_host_byte_order; + u32 i; u32 headers_size = sizeof (ip0[0]); - void *data_this_buffer; + u8 *data_this_buffer; + u8 next_hdr = ip0->protocol; ASSERT (bogus_lengthp); *bogus_lengthp = 0; - /* Initialize checksum with ip header. */ - sum0 = ip0->payload_length + clib_host_to_net_u16 (ip0->protocol); payload_length_host_byte_order = clib_net_to_host_u16 (ip0->payload_length); - data_this_buffer = (void *) (ip0 + 1); - - 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)); - } + data_this_buffer = (u8 *) (ip0 + 1); + payload_length = ip0->payload_length; /* some icmp packets may come with a "router alert" hop-by-hop extension header (e.g., mldv2 packets) * or UDP-Ping packets */ - if (PREDICT_FALSE (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)) + if (PREDICT_FALSE (next_hdr == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)) { u32 skip_bytes; ip6_hop_by_hop_ext_t *ext_hdr = @@ -1056,41 +1122,34 @@ ip6_tcp_udp_icmp_compute_checksum (vlib_main_t * vm, vlib_buffer_t * p0, payload_length_host_byte_order -= skip_bytes; 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; - } + /* pseudo-header adjustments: + * exclude ext header bytes from payload length + * use payload IP proto rather than ext header IP proto + */ + payload_length = clib_host_to_net_u16 (payload_length_host_byte_order); + next_hdr = ext_hdr->next_hdr; } - 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; + /* Initialize checksum with ip pseudo-header. */ + sum0 = payload_length + clib_host_to_net_u16 (next_hdr); - if (!(p0->flags & VLIB_BUFFER_NEXT_PRESENT)) - { - *bogus_lengthp = 1; - return 0xfefe; - } - 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); + 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)); } - sum16 = ~ip_csum_fold (sum0); - - return sum16; + if (p0) + 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 @@ -1150,27 +1209,65 @@ always_inline u8 ip6_next_proto_is_tcp_udp (vlib_buffer_t * p0, ip6_header_t * ip0, u32 * udp_offset0) { - u32 proto0; - proto0 = ip6_locate_header (p0, ip0, IP_PROTOCOL_UDP, udp_offset0); - if (proto0 != IP_PROTOCOL_UDP) - { - proto0 = ip6_locate_header (p0, ip0, IP_PROTOCOL_TCP, udp_offset0); - proto0 = (proto0 == IP_PROTOCOL_TCP) ? proto0 : 0; - } - return proto0; + int nh = ip6_locate_header (p0, ip0, -1, udp_offset0); + if (nh > 0) + if (nh == IP_PROTOCOL_UDP || nh == IP_PROTOCOL_TCP) + return nh; + return 0; } -/* *INDENT-OFF* */ -VNET_FEATURE_ARC_INIT (ip6_local) = -{ - .arc_name = "ip6-local", - .start_nodes = VNET_FEATURES ("ip6-local"), +VNET_FEATURE_ARC_INIT (ip6_local) = { + .arc_name = "ip6-local", + .start_nodes = VNET_FEATURES ("ip6-local", "ip6-receive"), }; -/* *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 -= vlib_buffer_length_in_chain (vm, p0) - p0->current_length; + + 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) +ip6_local_inline (vlib_main_t *vm, vlib_node_runtime_t *node, + vlib_frame_t *frame, int head_of_feature_arc, + int is_receive_dpo) { ip6_main_t *im = &ip6_main; ip_lookup_main_t *lm = &im->lookup_main; @@ -1202,7 +1299,7 @@ ip6_local_inline (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_prefetch_buffer_data (b[3], LOAD); } - u8 error[2]; + vl_counter_ip6_enum_t error[2]; error[0] = IP6_ERROR_UNKNOWN_PROTOCOL; error[1] = IP6_ERROR_UNKNOWN_PROTOCOL; @@ -1223,15 +1320,23 @@ ip6_local_inline (vlib_main_t * vm, vlib_node_runtime_t * node, flags[0] = b[0]->flags; flags[1] = b[1]->flags; + vnet_buffer_oflags_t oflags[2]; + oflags[0] = vnet_buffer (b[0])->oflags; + oflags[1] = vnet_buffer (b[1])->oflags; + + u32 l4_offload[2]; + l4_offload[0] = (flags[0] & VNET_BUFFER_F_OFFLOAD) && + (oflags[0] & (VNET_BUFFER_OFFLOAD_F_TCP_CKSUM | + VNET_BUFFER_OFFLOAD_F_UDP_CKSUM)); + l4_offload[1] = (flags[1] & VNET_BUFFER_F_OFFLOAD) && + (oflags[1] & (VNET_BUFFER_OFFLOAD_F_TCP_CKSUM | + VNET_BUFFER_OFFLOAD_F_UDP_CKSUM)); + u32 good_l4_csum[2]; good_l4_csum[0] = - flags[0] & (VNET_BUFFER_F_L4_CHECKSUM_CORRECT | - VNET_BUFFER_F_OFFLOAD_TCP_CKSUM | - VNET_BUFFER_F_OFFLOAD_UDP_CKSUM); + (flags[0] & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) | l4_offload[0]; good_l4_csum[1] = - flags[1] & (VNET_BUFFER_F_L4_CHECKSUM_CORRECT | - VNET_BUFFER_F_OFFLOAD_TCP_CKSUM | - VNET_BUFFER_F_OFFLOAD_UDP_CKSUM); + (flags[1] & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) | l4_offload[1]; u32 udp_offset[2] = { }; u8 is_tcp_udp[2]; @@ -1282,16 +1387,28 @@ ip6_local_inline (vlib_main_t * vm, vlib_node_runtime_t * node, { 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 == @@ -1338,6 +1455,23 @@ ip6_local_inline (vlib_main_t * vm, vlib_node_runtime_t * node, vnet_buffer (b[1])->sw_if_index[VLIB_TX] != ~0 ? vnet_buffer (b[1])->sw_if_index[VLIB_TX] : vnet_buffer (b[1])->ip.fib_index; + + vnet_buffer (b[0])->ip.rx_sw_if_index = + vnet_buffer (b[0])->sw_if_index[VLIB_RX]; + vnet_buffer (b[1])->ip.rx_sw_if_index = + vnet_buffer (b[1])->sw_if_index[VLIB_RX]; + if (is_receive_dpo) + { + const receive_dpo_t *rd0, *rd1; + rd0 = + receive_dpo_get (vnet_buffer (b[0])->ip.adj_index[VLIB_TX]); + rd1 = + receive_dpo_get (vnet_buffer (b[1])->ip.adj_index[VLIB_TX]); + if (rd0->rd_sw_if_index != ~0) + vnet_buffer (b[0])->ip.rx_sw_if_index = rd0->rd_sw_if_index; + if (rd1->rd_sw_if_index != ~0) + vnet_buffer (b[1])->ip.rx_sw_if_index = rd1->rd_sw_if_index; + } } /* head_of_feature_arc */ next[0] = lm->local_next_by_ip_protocol[ip[0]->protocol]; @@ -1347,8 +1481,8 @@ ip6_local_inline (vlib_main_t * vm, vlib_node_runtime_t * node, next[1] = error[1] != IP6_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next[1]; - b[0]->error = error_node->errors[0]; - b[1]->error = error_node->errors[1]; + b[0]->error = error_node->errors[error[0]]; + b[1]->error = error_node->errors[error[1]]; if (head_of_feature_arc) { @@ -1359,16 +1493,16 @@ ip6_local_inline (vlib_main_t * vm, vlib_node_runtime_t * node, { u32 next32 = next[0]; vnet_feature_arc_start (arc_index, - vnet_buffer (b[0])->sw_if_index - [VLIB_RX], &next32, b[0]); + vnet_buffer (b[0])->ip.rx_sw_if_index, + &next32, b[0]); next[0] = next32; } if (PREDICT_TRUE (ip6_unknown[1])) { u32 next32 = next[1]; vnet_feature_arc_start (arc_index, - vnet_buffer (b[1])->sw_if_index - [VLIB_RX], &next32, b[1]); + vnet_buffer (b[1])->ip.rx_sw_if_index, + &next32, b[1]); next[1] = next32; } } @@ -1393,11 +1527,15 @@ ip6_local_inline (vlib_main_t * vm, vlib_node_runtime_t * node, 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); + vnet_buffer_oflags_t oflags = vnet_buffer (b[0])->oflags; + + u32 l4_offload = (flags & VNET_BUFFER_F_OFFLOAD) && + (oflags & (VNET_BUFFER_OFFLOAD_F_TCP_CKSUM | + VNET_BUFFER_OFFLOAD_F_UDP_CKSUM)); + + u32 good_l4_csum = + (flags & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) | l4_offload; u32 udp_offset; i16 len_diff = 0; u8 is_tcp_udp = ip6_next_proto_is_tcp_udp (b[0], ip, &udp_offset); @@ -1417,17 +1555,24 @@ ip6_local_inline (vlib_main_t * vm, vlib_node_runtime_t * node, good_l4_csum |= type == IP_BUILTIN_PROTOCOL_UNKNOWN; len_diff = type == IP_BUILTIN_PROTOCOL_UDP ? len_diff : 0; - u8 need_csum = type != IP_BUILTIN_PROTOCOL_UNKNOWN && !good_l4_csum - && !(flags & 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)) { 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; + + 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"); @@ -1454,13 +1599,23 @@ ip6_local_inline (vlib_main_t * vm, vlib_node_runtime_t * node, 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; + + vnet_buffer (b[0])->ip.rx_sw_if_index = + vnet_buffer (b[0])->sw_if_index[VLIB_RX]; + if (is_receive_dpo) + { + receive_dpo_t *rd; + rd = receive_dpo_get (vnet_buffer (b[0])->ip.adj_index[VLIB_TX]); + if (rd->rd_sw_if_index != ~0) + vnet_buffer (b[0])->ip.rx_sw_if_index = rd->rd_sw_if_index; + } } /* head_of_feature_arc */ next[0] = lm->local_next_by_ip_protocol[ip->protocol]; next[0] = error != IP6_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next[0]; - b[0]->error = error_node->errors[0]; + b[0]->error = error_node->errors[error]; if (head_of_feature_arc) { @@ -1468,8 +1623,8 @@ ip6_local_inline (vlib_main_t * vm, vlib_node_runtime_t * node, { u32 next32 = next[0]; vnet_feature_arc_start (arc_index, - vnet_buffer (b[0])->sw_if_index - [VLIB_RX], &next32, b[0]); + vnet_buffer (b[0])->ip.rx_sw_if_index, + &next32, b[0]); next[0] = next32; } } @@ -1487,15 +1642,17 @@ ip6_local_inline (vlib_main_t * vm, vlib_node_runtime_t * node, 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 */ ); + return ip6_local_inline (vm, node, frame, 1 /* head of feature arc */, + 0 /* ip6_local_inline */); } -/* *INDENT-OFF* */ VLIB_REGISTER_NODE (ip6_local_node) = { .name = "ip6-local", .vector_size = sizeof (u32), .format_trace = format_ip6_forward_next_trace, + .n_errors = IP6_N_ERROR, + .error_counters = ip6_error_counters, .n_next_nodes = IP_LOCAL_N_NEXT, .next_nodes = { @@ -1503,19 +1660,32 @@ VLIB_REGISTER_NODE (ip6_local_node) = [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", + [IP_LOCAL_NEXT_REASSEMBLY] = "ip6-local-full-reassembly", }, }; -/* *INDENT-ON* */ + +VLIB_NODE_FN (ip6_receive_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 */, + 1 /* is_receive_dpo */); +} + +VLIB_REGISTER_NODE (ip6_receive_local_node) = { + .name = "ip6-receive", + .vector_size = sizeof (u32), + .format_trace = format_ip6_forward_next_trace, + .sibling_of = "ip6-local" +}; 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 */ ); + return ip6_local_inline (vm, node, frame, 0 /* head of feature arc */, + 0 /* ip6_local_inline */); } -/* *INDENT-OFF* */ VLIB_REGISTER_NODE (ip6_local_end_of_arc_node) = { .name = "ip6-local-end-of-arc", .vector_size = sizeof (u32), @@ -1529,13 +1699,10 @@ VNET_FEATURE_INIT (ip6_local_end_of_arc, static) = { .node_name = "ip6-local-end-of-arc", .runs_before = 0, /* not before any other features */ }; -/* *INDENT-ON* */ #ifdef CLIB_MARCH_VARIANT extern vlib_node_registration_t ip6_local_node; - #else - void ip6_register_protocol (u32 protocol, u32 node_index) { @@ -1557,114 +1724,6 @@ ip6_unregister_protocol (u32 protocol) 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 @@ -1684,7 +1743,7 @@ 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) { @@ -1692,7 +1751,9 @@ ip6_mtu_check (vlib_buffer_t * b, u16 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; } @@ -1710,8 +1771,7 @@ always_inline uword 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); @@ -1729,7 +1789,7 @@ ip6_rewrite_inline_with_gso (vlib_main_t * vm, 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; @@ -1747,8 +1807,8 @@ ip6_rewrite_inline_with_gso (vlib_main_t * vm, vlib_prefetch_buffer_header (p2, LOAD); vlib_prefetch_buffer_header (p3, LOAD); - CLIB_PREFETCH (p2->pre_data, 32, STORE); - CLIB_PREFETCH (p3->pre_data, 32, STORE); + clib_prefetch_store (p2->pre_data); + clib_prefetch_store (p3->pre_data); CLIB_PREFETCH (p2->data, sizeof (ip0[0]), STORE); CLIB_PREFETCH (p3->data, sizeof (ip0[0]), STORE); @@ -1801,10 +1861,7 @@ ip6_rewrite_inline_with_gso (vlib_main_t * vm, 0); } } - else - { - p0->flags &= ~VNET_BUFFER_F_LOCALLY_ORIGINATED; - } + is_locally_originated1 = p1->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED; if (PREDICT_TRUE (!is_locally_originated1)) @@ -1832,10 +1889,7 @@ ip6_rewrite_inline_with_gso (vlib_main_t * vm, 0); } } - else - { - p1->flags &= ~VNET_BUFFER_F_LOCALLY_ORIGINATED; - } + adj0 = adj_get (adj_index0); adj1 = adj_get (adj_index1); @@ -1863,35 +1917,33 @@ ip6_rewrite_inline_with_gso (vlib_main_t * vm, 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 */ if (PREDICT_TRUE (error0 == IP6_ERROR_NONE)) { p0->current_data -= rw_len0; p0->current_length += rw_len0; - tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index; vnet_buffer (p0)->sw_if_index[VLIB_TX] = tx_sw_if_index0; next0 = adj0[0].rewrite_header.next_index; - if (PREDICT_FALSE (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES)) - vnet_feature_arc_start (lm->output_feature_arc_index, - tx_sw_if_index0, &next0, p0); + vnet_feature_arc_start_w_cfg_index + (lm->output_feature_arc_index, tx_sw_if_index0, &next0, p0, + adj0->ia_cfg_index); } else { @@ -1908,8 +1960,9 @@ ip6_rewrite_inline_with_gso (vlib_main_t * vm, if (PREDICT_FALSE (adj1[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES)) - vnet_feature_arc_start (lm->output_feature_arc_index, - tx_sw_if_index1, &next1, p1); + vnet_feature_arc_start_w_cfg_index + (lm->output_feature_arc_index, tx_sw_if_index1, &next1, p1, + adj1->ia_cfg_index); } else { @@ -1918,15 +1971,14 @@ ip6_rewrite_inline_with_gso (vlib_main_t * vm, if (is_midchain) { - /* before we paint on the next header, update the L4 - * checksums if required, since there's no offload on a tunnel */ - calc_checksums (vm, p0); - calc_checksums (vm, p1); + /* Guess we are only writing on ipv6 header. */ + vnet_rewrite_two_headers (adj0[0], adj1[0], + ip0, ip1, sizeof (ip6_header_t)); } - - /* Guess we are only writing on simple Ethernet header. */ - vnet_rewrite_two_headers (adj0[0], adj1[0], - ip0, ip1, sizeof (ethernet_header_t)); + else + /* Guess we are only writing on simple Ethernet header. */ + vnet_rewrite_two_headers (adj0[0], adj1[0], + ip0, ip1, sizeof (ethernet_header_t)); if (is_midchain) { @@ -2009,18 +2061,16 @@ ip6_rewrite_inline_with_gso (vlib_main_t * vm, 0); } } - else - { - p0->flags &= ~VNET_BUFFER_F_LOCALLY_ORIGINATED; - } if (is_midchain) { - calc_checksums (vm, p0); + /* Guess we are only writing on ip6 header. */ + vnet_rewrite_one_header (adj0[0], ip0, sizeof (ip6_header_t)); } - - /* Guess we are only writing on simple Ethernet header. */ - vnet_rewrite_one_header (adj0[0], ip0, sizeof (ethernet_header_t)); + else + /* Guess we are only writing on simple Ethernet header. */ + vnet_rewrite_one_header (adj0[0], ip0, + sizeof (ethernet_header_t)); /* Update packet buffer attributes/set output interface. */ rw_len0 = adj0[0].rewrite_header.data_bytes; @@ -2038,13 +2088,13 @@ ip6_rewrite_inline_with_gso (vlib_main_t * vm, 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 */ if (PREDICT_TRUE (error0 == IP6_ERROR_NONE)) @@ -2059,8 +2109,9 @@ ip6_rewrite_inline_with_gso (vlib_main_t * vm, if (PREDICT_FALSE (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES)) - vnet_feature_arc_start (lm->output_feature_arc_index, - tx_sw_if_index0, &next0, p0); + vnet_feature_arc_start_w_cfg_index + (lm->output_feature_arc_index, tx_sw_if_index0, &next0, p0, + adj0->ia_cfg_index); } else { @@ -2108,15 +2159,8 @@ ip6_rewrite_inline (vlib_main_t * vm, 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, @@ -2169,14 +2213,12 @@ VLIB_NODE_FN (ip6_mcast_midchain_node) (vlib_main_t * vm, return ip6_rewrite_inline (vm, node, frame, 0, 1, 1); } -/* *INDENT-OFF* */ -VLIB_REGISTER_NODE (ip6_midchain_node) = -{ +VLIB_REGISTER_NODE (ip6_midchain_node) = { .name = "ip6-midchain", .vector_size = sizeof (u32), .format_trace = format_ip6_forward_next_trace, .sibling_of = "ip6-rewrite", - }; +}; VLIB_REGISTER_NODE (ip6_rewrite_node) = { @@ -2217,7 +2259,6 @@ VLIB_REGISTER_NODE (ip6_mcast_midchain_node) = .sibling_of = "ip6-rewrite", }; -/* *INDENT-ON* */ /* * Hop-by-Hop handling @@ -2231,7 +2272,6 @@ _(PROCESSED, "pkts with ip6 hop-by-hop options") \ _(FORMAT, "incorrectly formatted hop-by-hop options") \ _(UNKNOWN_OPTION, "unknown ip6 hop-by-hop options") -/* *INDENT-OFF* */ typedef enum { #define _(sym,str) IP6_HOP_BY_HOP_ERROR_##sym, @@ -2239,7 +2279,6 @@ typedef enum #undef _ IP6_HOP_BY_HOP_N_ERROR, } ip6_hop_by_hop_error_t; -/* *INDENT-ON* */ /* * Primary h-b-h handler trace support @@ -2269,7 +2308,6 @@ format_ip6_hop_by_hop_ext_hdr (u8 * s, va_list * args) ip6_hop_by_hop_option_t *opt0, *limit0; ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main; u8 type0; - s = format (s, "IP6_HOP_BY_HOP: next protocol %d len %d total %d", hbh0->protocol, (hbh0->length + 1) << 3, total_len); @@ -2292,9 +2330,8 @@ format_ip6_hop_by_hop_ext_hdr (u8 * s, va_list * args) } else { - s = - format (s, "\n unrecognized option %d length %d", type0, - opt0->length); + s = format (s, "\n unrecognized option %d length %d", type0, + opt0->length); } opt0 = (ip6_hop_by_hop_option_t *) (((u8 *) opt0) + opt0->length + @@ -2342,9 +2379,8 @@ format_ip6_hop_by_hop_trace (u8 * s, va_list * args) } else { - s = - format (s, "\n unrecognized option %d length %d", type0, - opt0->length); + s = format (s, "\n unrecognized option %d length %d", type0, + opt0->length); } opt0 = (ip6_hop_by_hop_option_t *) (((u8 *) opt0) + opt0->length + @@ -2669,7 +2705,6 @@ VLIB_NODE_FN (ip6_hop_by_hop_node) (vlib_main_t * vm, return frame->n_vectors; } -/* *INDENT-OFF* */ VLIB_REGISTER_NODE (ip6_hop_by_hop_node) = { .name = "ip6-hop-by-hop", @@ -2681,7 +2716,6 @@ VLIB_REGISTER_NODE (ip6_hop_by_hop_node) = .error_strings = ip6_hop_by_hop_error_strings, .n_next_nodes = 0, }; -/* *INDENT-ON* */ static clib_error_t * ip6_hop_by_hop_init (vlib_main_t * vm) @@ -2791,24 +2825,6 @@ ip6_lookup_init (vlib_main_t * vm) ip_lookup_init (&im->lookup_main, /* is_ip6 */ 1); - if (im->lookup_table_nbuckets == 0) - im->lookup_table_nbuckets = IP6_FIB_DEFAULT_HASH_NUM_BUCKETS; - - im->lookup_table_nbuckets = 1 << max_log2 (im->lookup_table_nbuckets); - - if (im->lookup_table_size == 0) - im->lookup_table_size = IP6_FIB_DEFAULT_HASH_MEMORY_SIZE; - - 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); - 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, FIB_SOURCE_DEFAULT_ROUTE); @@ -2824,97 +2840,11 @@ ip6_lookup_init (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 ", -}; -/* *INDENT-ON* */ - -#ifndef CLIB_MARCH_VARIANT -int -vnet_set_ip6_flow_hash (u32 table_id, u32 flow_hash_config) -{ - u32 fib_index; - - fib_index = fib_table_find (FIB_PROTOCOL_IP6, table_id); - - if (~0 == fib_index) - return VNET_API_ERROR_NO_SUCH_FIB; - - fib_table_set_flow_hash_config (fib_index, FIB_PROTOCOL_IP6, - flow_hash_config); - - return 0; -} -#endif - static clib_error_t * set_ip6_flow_hash_command_fn (vlib_main_t * vm, unformat_input_t * input, @@ -2929,8 +2859,12 @@ set_ip6_flow_hash_command_fn (vlib_main_t * vm, { if (unformat (input, "table %d", &table_id)) matched = 1; -#define _(a,v) \ - else if (unformat (input, #a)) { flow_hash_config |= v; matched=1;} +#define _(a, b, v) \ + else if (unformat (input, #a)) \ + { \ + flow_hash_config |= v; \ + matched = 1; \ + } foreach_flow_hash_bit #undef _ else @@ -2941,7 +2875,7 @@ set_ip6_flow_hash_command_fn (vlib_main_t * vm, return clib_error_return (0, "unknown input `%U'", format_unformat_error, input); - rv = vnet_set_ip6_flow_hash (table_id, flow_hash_config); + rv = ip_flow_hash_set (AF_IP6, table_id, flow_hash_config); switch (rv) { case 0: @@ -3033,15 +2967,12 @@ set_ip6_flow_hash_command_fn (vlib_main_t * vm, * @cliexend * @endparblock ?*/ -/* *INDENT-OFF* */ -VLIB_CLI_COMMAND (set_ip6_flow_hash_command, static) = -{ +VLIB_CLI_COMMAND (set_ip6_flow_hash_command, static) = { .path = "set ip6 flow-hash", - .short_help = - "set ip6 flow-hash table [src] [dst] [sport] [dport] [proto] [reverse]", + .short_help = "set ip6 flow-hash table [src] [dst] [sport] " + "[dport] [proto] [reverse] [flowlabel]", .function = set_ip6_flow_hash_command_fn, }; -/* *INDENT-ON* */ static clib_error_t * show_ip6_local_command_fn (vlib_main_t * vm, @@ -3082,19 +3013,16 @@ show_ip6_local_command_fn (vlib_main_t * vm, * 115 * @cliexend ?*/ -/* *INDENT-OFF* */ VLIB_CLI_COMMAND (show_ip6_local, static) = { .path = "show ip6 local", .function = show_ip6_local_command_fn, .short_help = "show ip6 local", }; -/* *INDENT-ON* */ #ifndef CLIB_MARCH_VARIANT int -vnet_set_ip6_classify_intfc (vlib_main_t * vm, u32 sw_if_index, - u32 table_index) +vnet_set_ip6_classify_intfc (vlib_main_t *vm, u32 sw_if_index, u32 table_index) { vnet_main_t *vnm = vnet_get_main (); vnet_interface_main_t *im = &vnm->interface_main; @@ -3125,17 +3053,13 @@ vnet_set_ip6_classify_intfc (vlib_main_t * vm, u32 sw_if_index, fib_index = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4, sw_if_index); - - if (table_index != (u32) ~ 0) { dpo_id_t dpo = DPO_INVALID; - dpo_set (&dpo, DPO_CLASSIFY, DPO_PROTO_IP6, classify_dpo_create (DPO_PROTO_IP6, table_index)); - fib_table_entry_special_dpo_add (fib_index, &pfx, FIB_SOURCE_CLASSIFY, @@ -3206,7 +3130,6 @@ set_ip6_classify_command_fn (vlib_main_t * vm, * Example of how to assign a classification table to an interface: * @cliexcmd{set ip6 classify intfc GigabitEthernet2/0/0 table-index 1} ?*/ -/* *INDENT-OFF* */ VLIB_CLI_COMMAND (set_ip6_classify_command, static) = { .path = "set ip6 classify", @@ -3214,35 +3137,6 @@ VLIB_CLI_COMMAND (set_ip6_classify_command, static) = "set ip6 classify intfc table-index ", .function = set_ip6_classify_command_fn, }; -/* *INDENT-ON* */ - -static clib_error_t * -ip6_config (vlib_main_t * vm, unformat_input_t * input) -{ - ip6_main_t *im = &ip6_main; - uword heapsize = 0; - u32 tmp; - u32 nbuckets = 0; - - while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) - { - if (unformat (input, "hash-buckets %d", &tmp)) - nbuckets = tmp; - else if (unformat (input, "heap-size %U", - unformat_memory_size, &heapsize)) - ; - else - return clib_error_return (0, "unknown input '%U'", - format_unformat_error, input); - } - - im->lookup_table_nbuckets = nbuckets; - im->lookup_table_size = heapsize; - - return 0; -} - -VLIB_EARLY_CONFIG_FUNCTION (ip6_config, "ip6"); /* * fd.io coding-style-patch-verification: ON