X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=src%2Fvnet%2Fip%2Fip4_forward.c;h=bbba4b70e01c82c250f36ef8782e2faf054cb2af;hb=9a69a6095f67b8979a02f128f44e449889454273;hp=66d91ab697d17822540988e6d55ce1e410d437b3;hpb=68b0fb0c620c7451ef1a6380c43c39de6614db51;p=vpp.git diff --git a/src/vnet/ip/ip4_forward.c b/src/vnet/ip/ip4_forward.c index 66d91ab697d..bbba4b70e01 100644 --- a/src/vnet/ip/ip4_forward.c +++ b/src/vnet/ip/ip4_forward.c @@ -586,8 +586,7 @@ ip4_load_balance (vlib_main_t * vm, * We don't want to use the same hash value at each level in the recursion * graph as that would lead to polarisation */ - hc0 = vnet_buffer (p0)->ip.flow_hash = 0; - hc1 = vnet_buffer (p1)->ip.flow_hash = 0; + hc0 = hc1 = 0; if (PREDICT_FALSE (lb0->lb_n_buckets > 1)) { @@ -599,7 +598,7 @@ ip4_load_balance (vlib_main_t * vm, else { hc0 = vnet_buffer (p0)->ip.flow_hash = - ip4_compute_flow_hash (ip0, hc0); + ip4_compute_flow_hash (ip0, lb0->lb_hash_config); } } if (PREDICT_FALSE (lb1->lb_n_buckets > 1)) @@ -612,7 +611,7 @@ ip4_load_balance (vlib_main_t * vm, else { hc1 = vnet_buffer (p1)->ip.flow_hash = - ip4_compute_flow_hash (ip1, hc1); + ip4_compute_flow_hash (ip1, lb1->lb_hash_config); } } @@ -662,7 +661,7 @@ ip4_load_balance (vlib_main_t * vm, lb0 = load_balance_get (lbi0); - hc0 = vnet_buffer (p0)->ip.flow_hash = 0; + hc0 = 0; if (PREDICT_FALSE (lb0->lb_n_buckets > 1)) { if (PREDICT_TRUE (vnet_buffer (p0)->ip.flow_hash)) @@ -673,7 +672,7 @@ ip4_load_balance (vlib_main_t * vm, else { hc0 = vnet_buffer (p0)->ip.flow_hash = - ip4_compute_flow_hash (ip0, hc0); + ip4_compute_flow_hash (ip0, lb0->lb_hash_config); } } @@ -746,8 +745,9 @@ ip4_add_interface_routes (u32 sw_if_index, a->neighbor_probe_adj_index = ~0; - if (pfx.fp_len < 32) + if (pfx.fp_len <= 30) { + /* a /30 or shorter - add a glean for the network address */ fib_node_index_t fei; fei = fib_table_entry_update_one_path (fib_index, &pfx, @@ -765,8 +765,50 @@ ip4_add_interface_routes (u32 sw_if_index, NULL, FIB_ROUTE_PATH_FLAG_NONE); a->neighbor_probe_adj_index = fib_entry_get_adj (fei); - } + /* Add the two broadcast addresses as drop */ + fib_prefix_t net_pfx = { + .fp_len = 32, + .fp_proto = FIB_PROTOCOL_IP4, + .fp_addr.ip4.as_u32 = address->as_u32 & im->fib_masks[pfx.fp_len], + }; + if (net_pfx.fp_addr.ip4.as_u32 != pfx.fp_addr.ip4.as_u32) + fib_table_entry_special_add(fib_index, + &net_pfx, + FIB_SOURCE_INTERFACE, + (FIB_ENTRY_FLAG_DROP | + FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT), + ADJ_INDEX_INVALID); + net_pfx.fp_addr.ip4.as_u32 |= ~im->fib_masks[pfx.fp_len]; + if (net_pfx.fp_addr.ip4.as_u32 != pfx.fp_addr.ip4.as_u32) + fib_table_entry_special_add(fib_index, + &net_pfx, + FIB_SOURCE_INTERFACE, + (FIB_ENTRY_FLAG_DROP | + FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT), + ADJ_INDEX_INVALID); + } + else if (pfx.fp_len == 31) + { + u32 mask = clib_host_to_net_u32(1); + fib_prefix_t net_pfx = pfx; + + net_pfx.fp_len = 32; + net_pfx.fp_addr.ip4.as_u32 ^= mask; + + /* a /31 - add the other end as an attached host */ + fib_table_entry_update_one_path (fib_index, &net_pfx, + FIB_SOURCE_INTERFACE, + (FIB_ENTRY_FLAG_ATTACHED), + FIB_PROTOCOL_IP4, + &net_pfx.fp_addr, + sw_if_index, + // invalid FIB index + ~0, + 1, + NULL, + FIB_ROUTE_PATH_FLAG_NONE); + } pfx.fp_len = 32; if (sw_if_index < vec_len (lm->classify_table_index_by_sw_if_index)) @@ -814,10 +856,34 @@ ip4_del_interface_routes (ip4_main_t * im, .fp_addr.ip4 = *address, }; - if (pfx.fp_len < 32) + if (pfx.fp_len <= 30) { + fib_prefix_t net_pfx = { + .fp_len = 32, + .fp_proto = FIB_PROTOCOL_IP4, + .fp_addr.ip4.as_u32 = address->as_u32 & im->fib_masks[pfx.fp_len], + }; + if (net_pfx.fp_addr.ip4.as_u32 != pfx.fp_addr.ip4.as_u32) + fib_table_entry_special_remove(fib_index, + &net_pfx, + FIB_SOURCE_INTERFACE); + net_pfx.fp_addr.ip4.as_u32 |= ~im->fib_masks[pfx.fp_len]; + if (net_pfx.fp_addr.ip4.as_u32 != pfx.fp_addr.ip4.as_u32) + fib_table_entry_special_remove(fib_index, + &net_pfx, + FIB_SOURCE_INTERFACE); fib_table_entry_delete (fib_index, &pfx, FIB_SOURCE_INTERFACE); } + else if (pfx.fp_len == 31) + { + u32 mask = clib_host_to_net_u32(1); + fib_prefix_t net_pfx = pfx; + + net_pfx.fp_len = 32; + net_pfx.fp_addr.ip4.as_u32 ^= mask; + + fib_table_entry_delete (fib_index, &net_pfx, FIB_SOURCE_INTERFACE); + } pfx.fp_len = 32; fib_table_entry_delete (fib_index, &pfx, FIB_SOURCE_INTERFACE); @@ -848,9 +914,8 @@ ip4_sw_interface_enable_disable (u32 sw_if_index, u32 is_enable) !is_enable, 0, 0); - vnet_feature_enable_disable ("ip4-multicast", - "ip4-mfib-forward-lookup", - sw_if_index, is_enable, 0, 0); + vnet_feature_enable_disable ("ip4-multicast", "ip4-drop", + sw_if_index, !is_enable, 0, 0); } static clib_error_t * @@ -955,7 +1020,6 @@ VNET_FEATURE_ARC_INIT (ip4_unicast, static) = { .arc_name = "ip4-unicast", .start_nodes = VNET_FEATURES ("ip4-input", "ip4-input-no-checksum"), - .end_node = "ip4-lookup", .arc_index_ptr = &ip4_main.lookup_main.ucast_feature_arc_index, }; @@ -1022,27 +1086,25 @@ VNET_FEATURE_INIT (ip4_vxlan_bypass, static) = .runs_before = VNET_FEATURES ("ip4-lookup"), }; -VNET_FEATURE_INIT (ip4_lookup, static) = +VNET_FEATURE_INIT (ip4_drop, static) = { .arc_name = "ip4-unicast", - .node_name = "ip4-lookup", - .runs_before = VNET_FEATURES ("ip4-drop"), + .node_name = "ip4-drop", + .runs_before = VNET_FEATURES ("ip4-lookup"), }; -VNET_FEATURE_INIT (ip4_drop, static) = +VNET_FEATURE_INIT (ip4_lookup, static) = { .arc_name = "ip4-unicast", - .node_name = "ip4-drop", + .node_name = "ip4-lookup", .runs_before = 0, /* not before any other features */ }; - /* Built-in ip4 multicast rx feature path definition */ VNET_FEATURE_ARC_INIT (ip4_multicast, static) = { .arc_name = "ip4-multicast", .start_nodes = VNET_FEATURES ("ip4-input", "ip4-input-no-checksum"), - .end_node = "ip4-lookup-multicast", .arc_index_ptr = &ip4_main.lookup_main.mcast_feature_arc_index, }; @@ -1053,17 +1115,17 @@ VNET_FEATURE_INIT (ip4_vpath_mc, static) = .runs_before = VNET_FEATURES ("ip4-mfib-forward-lookup"), }; -VNET_FEATURE_INIT (ip4_lookup_mc, static) = +VNET_FEATURE_INIT (ip4_mc_drop, static) = { .arc_name = "ip4-multicast", - .node_name = "ip4-mfib-forward-lookup", - .runs_before = VNET_FEATURES ("ip4-drop"), + .node_name = "ip4-drop", + .runs_before = VNET_FEATURES ("ip4-mfib-forward-lookup"), }; -VNET_FEATURE_INIT (ip4_mc_drop, static) = +VNET_FEATURE_INIT (ip4_lookup_mc, static) = { .arc_name = "ip4-multicast", - .node_name = "ip4-drop", + .node_name = "ip4-mfib-forward-lookup", .runs_before = 0, /* last feature */ }; @@ -1072,7 +1134,6 @@ VNET_FEATURE_ARC_INIT (ip4_output, static) = { .arc_name = "ip4-output", .start_nodes = VNET_FEATURES ("ip4-rewrite", "ip4-midchain"), - .end_node = "interface-output", .arc_index_ptr = &ip4_main.lookup_main.output_feature_arc_index, }; @@ -1233,7 +1294,6 @@ format_ip4_rewrite_trace (u8 * s, va_list * args) CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); ip4_forward_next_trace_t *t = va_arg (*args, ip4_forward_next_trace_t *); - vnet_main_t *vnm = vnet_get_main (); uword indent = format_get_indent (s); s = format (s, "tx_sw_if_index %d dpo-idx %d : %U flow hash: 0x%08x", @@ -1242,7 +1302,7 @@ format_ip4_rewrite_trace (u8 * s, va_list * args) s = format (s, "\n%U%U", format_white_space, indent, format_ip_adjacency_packet_data, - vnm, t->dpo_index, t->packet_data, sizeof (t->packet_data)); + t->dpo_index, t->packet_data, sizeof (t->packet_data)); return s; } @@ -1707,10 +1767,11 @@ ip4_local_inline (vlib_main_t * vm, ip1->dst_address.as_u32 != 0xFFFFFFFF) ? IP4_ERROR_SRC_LOOKUP_MISS : error1); + skip_checks: + next0 = lm->local_next_by_ip_protocol[proto0]; next1 = lm->local_next_by_ip_protocol[proto1]; - skip_checks: next0 = error0 != IP4_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next0; next1 = @@ -2327,7 +2388,8 @@ typedef enum always_inline uword ip4_rewrite_inline (vlib_main_t * vm, vlib_node_runtime_t * node, - vlib_frame_t * frame, int is_midchain, int is_mcast) + vlib_frame_t * frame, + int do_counters, int is_midchain, int is_mcast) { ip_lookup_main_t *lm = &ip4_main.lookup_main; u32 *from = vlib_frame_vector_args (frame); @@ -2380,6 +2442,17 @@ ip4_rewrite_inline (vlib_main_t * vm, adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX]; adj_index1 = vnet_buffer (p1)->ip.adj_index[VLIB_TX]; + /* + * pre-fetch the per-adjacency counters + */ + if (do_counters) + { + vlib_prefetch_combined_counter (&adjacency_counters, + cpu_index, adj_index0); + vlib_prefetch_combined_counter (&adjacency_counters, + cpu_index, adj_index1); + } + /* We should never rewrite a pkt using the MISS adjacency */ ASSERT (adj_index0 && adj_index1); @@ -2485,14 +2558,6 @@ ip4_rewrite_inline (vlib_main_t * vm, rewrite_header.max_l3_packet_bytes ? IP4_ERROR_MTU_EXCEEDED : error1); - /* - * pre-fetch the per-adjacency counters - */ - vlib_prefetch_combined_counter (&adjacency_counters, - cpu_index, adj_index0); - vlib_prefetch_combined_counter (&adjacency_counters, - cpu_index, adj_index1); - /* Don't adjust the buffer for ttl issue; icmp-error node wants * to see the IP headerr */ if (PREDICT_TRUE (error0 == IP4_ERROR_NONE)) @@ -2503,8 +2568,10 @@ ip4_rewrite_inline (vlib_main_t * vm, tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index; vnet_buffer (p0)->sw_if_index[VLIB_TX] = tx_sw_if_index0; - vnet_feature_arc_start (lm->output_feature_arc_index, - tx_sw_if_index0, &next0, p0); + 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); } if (PREDICT_TRUE (error1 == IP4_ERROR_NONE)) { @@ -2515,8 +2582,10 @@ ip4_rewrite_inline (vlib_main_t * vm, tx_sw_if_index1 = adj1[0].rewrite_header.sw_if_index; vnet_buffer (p1)->sw_if_index[VLIB_TX] = tx_sw_if_index1; - vnet_feature_arc_start (lm->output_feature_arc_index, - tx_sw_if_index1, &next1, p1); + 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); } /* Guess we are only writing on simple Ethernet header. */ @@ -2526,15 +2595,20 @@ ip4_rewrite_inline (vlib_main_t * vm, /* * Bump the per-adjacency counters */ - vlib_increment_combined_counter - (&adjacency_counters, - cpu_index, - adj_index0, 1, vlib_buffer_length_in_chain (vm, p0) + rw_len0); - - vlib_increment_combined_counter - (&adjacency_counters, - cpu_index, - adj_index1, 1, vlib_buffer_length_in_chain (vm, p1) + rw_len1); + if (do_counters) + { + vlib_increment_combined_counter + (&adjacency_counters, + cpu_index, + adj_index0, 1, + vlib_buffer_length_in_chain (vm, p0) + rw_len0); + + vlib_increment_combined_counter + (&adjacency_counters, + cpu_index, + adj_index1, 1, + vlib_buffer_length_in_chain (vm, p1) + rw_len1); + } if (is_midchain) { @@ -2546,8 +2620,8 @@ ip4_rewrite_inline (vlib_main_t * vm, /* * copy bytes from the IP address into the MAC rewrite */ - vnet_fixup_one_header (adj0[0], &ip0->dst_address, ip0, 1); - vnet_fixup_one_header (adj1[0], &ip1->dst_address, ip1, 1); + vnet_fixup_one_header (adj0[0], &ip0->dst_address, ip0); + vnet_fixup_one_header (adj1[0], &ip1->dst_address, ip1); } vlib_validate_buffer_enqueue_x2 (vm, node, next_index, @@ -2617,8 +2691,9 @@ ip4_rewrite_inline (vlib_main_t * vm, p0->flags &= ~VNET_BUFFER_LOCALLY_ORIGINATED; } - vlib_prefetch_combined_counter (&adjacency_counters, - cpu_index, adj_index0); + if (do_counters) + vlib_prefetch_combined_counter (&adjacency_counters, + cpu_index, adj_index0); /* Guess we are only writing on simple Ethernet header. */ vnet_rewrite_one_header (adj0[0], ip0, sizeof (ethernet_header_t)); @@ -2627,17 +2702,18 @@ ip4_rewrite_inline (vlib_main_t * vm, /* * copy bytes from the IP address into the MAC rewrite */ - vnet_fixup_one_header (adj0[0], &ip0->dst_address, ip0, 1); + vnet_fixup_one_header (adj0[0], &ip0->dst_address, ip0); } /* Update packet buffer attributes/set output interface. */ rw_len0 = adj0[0].rewrite_header.data_bytes; vnet_buffer (p0)->ip.save_rewrite_length = rw_len0; - vlib_increment_combined_counter - (&adjacency_counters, - cpu_index, - adj_index0, 1, vlib_buffer_length_in_chain (vm, p0) + rw_len0); + if (do_counters) + vlib_increment_combined_counter + (&adjacency_counters, + cpu_index, adj_index0, 1, + vlib_buffer_length_in_chain (vm, p0) + rw_len0); /* Check MTU of outgoing interface. */ error0 = (vlib_buffer_length_in_chain (vm, p0) @@ -2662,8 +2738,10 @@ ip4_rewrite_inline (vlib_main_t * vm, adj0->sub_type.midchain.fixup_func (vm, adj0, p0); } - vnet_feature_arc_start (lm->output_feature_arc_index, - tx_sw_if_index0, &next0, p0); + 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); } @@ -2723,21 +2801,30 @@ static uword ip4_rewrite (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) { - return ip4_rewrite_inline (vm, node, frame, 0, 0); + if (adj_are_counters_enabled ()) + return ip4_rewrite_inline (vm, node, frame, 1, 0, 0); + else + return ip4_rewrite_inline (vm, node, frame, 0, 0, 0); } static uword ip4_midchain (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) { - return ip4_rewrite_inline (vm, node, frame, 1, 0); + if (adj_are_counters_enabled ()) + return ip4_rewrite_inline (vm, node, frame, 1, 1, 0); + else + return ip4_rewrite_inline (vm, node, frame, 0, 1, 0); } static uword ip4_rewrite_mcast (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) { - return ip4_rewrite_inline (vm, node, frame, 0, 1); + if (adj_are_counters_enabled ()) + return ip4_rewrite_inline (vm, node, frame, 1, 0, 1); + else + return ip4_rewrite_inline (vm, node, frame, 0, 0, 1); } /* *INDENT-OFF* */ @@ -2781,6 +2868,7 @@ add_del_interface_table (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) { vnet_main_t *vnm = vnet_get_main (); + ip_interface_address_t *ia; clib_error_t *error = 0; u32 sw_if_index, table_id; @@ -2802,29 +2890,44 @@ add_del_interface_table (vlib_main_t * vm, goto done; } - { - ip4_main_t *im = &ip4_main; - u32 fib_index; - - fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, - table_id); - - // - // FIXME-LATER - // changing an interface's table has consequences for any connecteds - // and adj-fibs already installed. - // - vec_validate (im->fib_index_by_sw_if_index, sw_if_index); - im->fib_index_by_sw_if_index[sw_if_index] = fib_index; - - fib_index = mfib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, - table_id); - vec_validate (im->mfib_index_by_sw_if_index, sw_if_index); - im->mfib_index_by_sw_if_index[sw_if_index] = fib_index; - } + /* + * If the interface already has in IP address, then a change int + * VRF is not allowed. The IP address applied must first be removed. + * We do not do that automatically here, since VPP has no knowledge + * of whether thoses subnets are valid in the destination VRF. + */ + /* *INDENT-OFF* */ + foreach_ip_interface_address (&ip4_main.lookup_main, + ia, sw_if_index, + 1 /* honor unnumbered */, + ({ + ip4_address_t * a; + + a = ip_interface_address_get_address (&ip4_main.lookup_main, ia); + error = clib_error_return (0, "interface %U has address %U", + format_vnet_sw_if_index_name, vnm, + sw_if_index, + format_ip4_address, a); + goto done; + })); + /* *INDENT-ON* */ + +{ + ip4_main_t *im = &ip4_main; + u32 fib_index; + + fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, table_id); + + vec_validate (im->fib_index_by_sw_if_index, sw_if_index); + im->fib_index_by_sw_if_index[sw_if_index] = fib_index; + + fib_index = mfib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, table_id); + vec_validate (im->mfib_index_by_sw_if_index, sw_if_index); + im->mfib_index_by_sw_if_index[sw_if_index] = fib_index; +} done: - return error; +return error; } /*? @@ -2835,13 +2938,12 @@ done: * an IP Address is assigned to an interface in the table (which adds a route * automatically). * - * @note IP addresses added after setting the interface IP table end up in - * the indicated FIB table. If the IP address is added prior to adding the - * interface to the FIB table, it will NOT be part of the FIB table. Predictable - * but potentially counter-intuitive results occur if you provision interface - * addresses in multiple FIBs. Upon RX, packets will be processed in the last - * IP table ID provisioned. It might be marginally useful to evade source RPF - * drops to put an interface address into multiple FIBs. + * @note IP addresses added after setting the interface IP table are added to + * the indicated FIB table. If an IP address is added prior to changing the + * table then this is an error. The control plane must remove these addresses + * first and then change the table. VPP will not automatically move the + * addresses from the old to the new table as it does not know the validity + * of such a change. * * @cliexpar * Example of how to add an interface to an IPv4 FIB table (where 2 is the table-id):