X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=src%2Fvnet%2Fip%2Fip6_forward.c;h=be0037e5edda40a841d757adb47fe4955c85b474;hb=5bb1ecae8;hp=b53cdc473463b655e69e9b4bf2bfcbe55c94912a;hpb=c7b8f203c0740ddd36bced39439aef63ea092d59;p=vpp.git diff --git a/src/vnet/ip/ip6_forward.c b/src/vnet/ip/ip6_forward.c index b53cdc47346..be0037e5edd 100644 --- a/src/vnet/ip/ip6_forward.c +++ b/src/vnet/ip/ip6_forward.c @@ -39,6 +39,7 @@ #include #include +#include #include #include /* for ethernet_header_t */ #include /* for srp_hw_interface_class */ @@ -200,6 +201,7 @@ ip6_add_del_interface_address (vlib_main_t * vm, 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) @@ -208,6 +210,36 @@ ip6_add_del_interface_address (vlib_main_t * vm, 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); @@ -215,6 +247,50 @@ ip6_add_del_interface_address (vlib_main_t * vm, 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); @@ -316,13 +392,13 @@ VNET_FEATURE_INIT (ip6_policer_classify, static) = { .arc_name = "ip6-unicast", .node_name = "ip6-policer-classify", - .runs_before = VNET_FEATURES ("ipsec-input-ip6"), + .runs_before = VNET_FEATURES ("ipsec6-input"), }; VNET_FEATURE_INIT (ip6_ipsec, static) = { .arc_name = "ip6-unicast", - .node_name = "ipsec-input-ip6", + .node_name = "ipsec6-input", .runs_before = VNET_FEATURES ("l2tp-decap"), }; @@ -398,12 +474,12 @@ VNET_FEATURE_ARC_INIT (ip6_output, static) = 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"), }; VNET_FEATURE_INIT (ip6_ipsec_output, static) = { .arc_name = "ip6-output", - .node_name = "ipsec-output-ip6", + .node_name = "ipsec6-output", .runs_before = VNET_FEATURES ("interface-output"), }; @@ -477,23 +553,20 @@ VLIB_REGISTER_NODE (ip6_lookup_node) = VLIB_NODE_FUNCTION_MULTIARCH (ip6_lookup_node, ip6_lookup); -always_inline uword +static uword ip6_load_balance (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); @@ -691,6 +764,9 @@ ip6_load_balance (vlib_main_t * vm, 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; } @@ -1169,23 +1245,15 @@ ip6_local_inline (vlib_main_t * vm, vlib_node_runtime_t * node, ? 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 (p0)->sw_if_index[VLIB_TX] != ~0 ? + vnet_buffer (p0)->sw_if_index[VLIB_TX] : + vnet_buffer (p0)->ip.fib_index; 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]; - + vnet_buffer (p1)->sw_if_index[VLIB_TX] != ~0 ? + vnet_buffer (p1)->sw_if_index[VLIB_TX] : + vnet_buffer (p1)->ip.fib_index; skip_checks: @@ -1301,12 +1369,9 @@ ip6_local_inline (vlib_main_t * vm, vlib_node_runtime_t * node, } 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 (p0)->sw_if_index[VLIB_TX] != ~0 ? + vnet_buffer (p0)->sw_if_index[VLIB_TX] : + vnet_buffer (p0)->ip.fib_index; skip_check: @@ -1355,6 +1420,7 @@ VLIB_REGISTER_NODE (ip6_local_node, static) = [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* */ @@ -1401,7 +1467,8 @@ ip6_register_protocol (u32 protocol, u32 node_index) } 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; @@ -1441,6 +1508,8 @@ ip6_probe_neighbor (vlib_main_t * vm, ip6_address_t * dst, u32 sw_if_index) 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); @@ -1482,7 +1551,7 @@ ip6_probe_neighbor (vlib_main_t * vm, ip6_address_t * dst, u32 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) + if (adj->lookup_next_index == IP_LOOKUP_NEXT_REWRITE && refresh == 0) { adj_unlock (ai); ai = adj_glean_add_or_lock (FIB_PROTOCOL_IP6, @@ -1509,6 +1578,8 @@ typedef enum { IP6_REWRITE_NEXT_DROP, IP6_REWRITE_NEXT_ICMP_ERROR, + IP6_REWRITE_NEXT_FRAGMENT, + IP6_REWRITE_N_NEXT /* Last */ } ip6_rewrite_next_t; /** @@ -1517,6 +1588,31 @@ typedef enum */ #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, @@ -1531,7 +1627,7 @@ ip6_rewrite_inline (vlib_main_t * vm, 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) { @@ -1545,6 +1641,7 @@ ip6_rewrite_inline (vlib_main_t * vm, 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. */ { @@ -1583,7 +1680,9 @@ ip6_rewrite_inline (vlib_main_t * vm, 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; @@ -1612,7 +1711,9 @@ ip6_rewrite_inline (vlib_main_t * vm, { 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; @@ -1662,16 +1763,14 @@ ip6_rewrite_inline (vlib_main_t * vm, } /* 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 */ @@ -1745,6 +1844,7 @@ ip6_rewrite_inline (vlib_main_t * vm, u32 pi0, rw_len0; u32 adj_index0, next0, error0; u32 tx_sw_if_index0; + bool is_locally_originated0; pi0 = to_next[0] = from[0]; @@ -1760,7 +1860,9 @@ ip6_rewrite_inline (vlib_main_t * vm, 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; @@ -1805,14 +1907,13 @@ ip6_rewrite_inline (vlib_main_t * vm, } /* 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; @@ -1875,6 +1976,16 @@ ip6_rewrite (vlib_main_t * vm, return ip6_rewrite_inline (vm, node, frame, 0, 0, 0); } +static uword +ip6_rewrite_bcast (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); +} + static uword ip6_rewrite_mcast (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) @@ -1914,29 +2025,36 @@ VLIB_REGISTER_NODE (ip6_midchain_node) = .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); -/* *INDENT-OFF* */ +VLIB_REGISTER_NODE (ip6_rewrite_bcast_node) = { + .function = ip6_rewrite_bcast, + .name = "ip6-rewrite-bcast", + .vector_size = sizeof (u32), + + .format_trace = format_ip6_rewrite_trace, + .sibling_of = "ip6-rewrite", +}; +VLIB_NODE_FUNCTION_MULTIARCH (ip6_rewrite_bcast_node, ip6_rewrite_bcast) + VLIB_REGISTER_NODE (ip6_rewrite_mcast_node) = { .function = ip6_rewrite_mcast, @@ -1945,11 +2063,9 @@ VLIB_REGISTER_NODE (ip6_rewrite_mcast_node) = .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) = { .function = ip6_mcast_midchain, @@ -1958,9 +2074,9 @@ VLIB_REGISTER_NODE (ip6_mcast_midchain_node, static) = .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 @@ -2429,8 +2545,8 @@ 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); } @@ -2564,7 +2680,7 @@ ip6_lookup_init (vlib_main_t * vm) { 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);