X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=src%2Fvnet%2Fip%2Fip6_forward.c;h=0325627a1effeaea4082f973131715292f2c94fd;hb=59f71132e;hp=4cb7608d0b4039a2229b56909402dac49a974320;hpb=cbe25aab3be72154f2c706c39eeba6a77f34450f;p=vpp.git diff --git a/src/vnet/ip/ip6_forward.c b/src/vnet/ip/ip6_forward.c index 4cb7608d0b4..0325627a1ef 100644 --- a/src/vnet/ip/ip6_forward.c +++ b/src/vnet/ip/ip6_forward.c @@ -49,6 +49,7 @@ #include #include #include +#include #ifndef CLIB_MARCH_VARIANT #include @@ -294,7 +295,7 @@ 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; const ip6_address_t *ll_addr; @@ -370,6 +371,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 +385,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,6 +403,7 @@ 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; } })); } @@ -401,18 +411,71 @@ ip6_add_del_interface_address (vlib_main_t * vm, } /* *INDENT-ON* */ - { - uword elts_before = pool_elts (lm->if_address_pool); + if_address_index = ip_interface_address_find (lm, addr_fib, address_length); + + 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; + } + + ip_interface_address_del (lm, if_address_index, addr_fib); + } + else + { + if (~0 != if_address_index) + { + ip_interface_address_t *ia; - error = ip_interface_address_add_del - (lm, sw_if_index, addr_fib, address_length, is_del, &if_address_index); - if (error) - goto done; + ia = pool_elt_at_index (lm->if_address_pool, if_address_index); - /* Pool did not grow: add duplicate address. */ - if (elts_before == pool_elts (lm->if_address_pool)) - goto done; - } + 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) @@ -431,12 +494,12 @@ ip6_add_del_interface_address (vlib_main_t * vm, 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); @@ -1020,31 +1083,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 payload_length_host_byte_order; + ip_csum_t sum0 = 0; + u16 payload_length, payload_length_host_byte_order; u32 i; u32 headers_size = sizeof (ip0[0]); 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 = (u8 *) (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)); - } + 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 = @@ -1059,6 +1114,24 @@ 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; + + /* 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; + } + + /* Initialize checksum with ip pseudo-header. */ + sum0 = payload_length + clib_host_to_net_u16 (next_hdr); + + 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)); } if (p0) @@ -1733,10 +1806,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)) @@ -1764,10 +1834,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); @@ -1854,8 +1921,12 @@ ip6_rewrite_inline_with_gso (vlib_main_t * vm, { /* 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); + vnet_calc_checksums_inline (vm, p0, 0 /* is_ip4 */ , + 1 /* is_ip6 */ , + 0 /* with gso */ ); + vnet_calc_checksums_inline (vm, p1, 0 /* is_ip4 */ , + 1 /* is_ip6 */ , + 0 /* with gso */ ); } /* Guess we are only writing on simple Ethernet header. */ @@ -1943,14 +2014,12 @@ 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); + vnet_calc_checksums_inline (vm, p0, 0 /* is_ip4 */ , + 1 /* is_ip6 */ , + 0 /* with gso */ ); } /* Guess we are only writing on simple Ethernet header. */