X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=src%2Fvnet%2Finterface.c;h=28c46110851aeaea9e5ba361cf016bbe6883f2b5;hb=70083ee;hp=dad1f315620affc12e6fe97a5ecdbe592a1f56aa;hpb=c418e4ac7cf36bd64f3130c258d5f1897c245f2b;p=vpp.git diff --git a/src/vnet/interface.c b/src/vnet/interface.c index dad1f315620..28c46110851 100644 --- a/src/vnet/interface.c +++ b/src/vnet/interface.c @@ -41,6 +41,7 @@ #include #include #include +#include #define VNET_INTERFACE_SET_FLAGS_HELPER_IS_CREATE (1 << 0) #define VNET_INTERFACE_SET_FLAGS_HELPER_WANT_REDISTRIBUTE (1 << 1) @@ -121,6 +122,57 @@ unserialize_vnet_sw_interface_set_flags (serialize_main_t * m, va_list * va) /* helper_flags no redistribution */ 0); } +static void +vnet_sw_interface_set_mtu_cb (vnet_main_t * vnm, u32 sw_if_index, void *ctx) +{ + u32 *mtu = ctx; + vnet_sw_interface_t *si = vnet_get_sw_interface (vnm, sw_if_index); + ASSERT (si); + + si->max_l3_packet_bytes[VLIB_TX] = si->max_l3_packet_bytes[VLIB_RX] = *mtu; + adj_mtu_update (sw_if_index); +} + +/* + * MTU is set per software interface. Setting MTU on a parent + * interface will override the MTU setting on sub-interfaces. + * TODO: If sub-interface MTU is ~0 inherit from parent? + */ +int +vnet_sw_interface_set_mtu (vnet_main_t * vnm, u32 sw_if_index, u32 mtu) +{ + vnet_sw_interface_t *si = vnet_get_sw_interface (vnm, sw_if_index); + vnet_hw_interface_t *hi = vnet_get_sw_hw_interface (vnm, sw_if_index); + + if (mtu < hi->min_packet_bytes) + return VNET_API_ERROR_INVALID_VALUE; + if (mtu > hi->max_packet_bytes) + return VNET_API_ERROR_INVALID_VALUE; + + /* If done on a parent interface */ + if (si->sw_if_index == si->sup_sw_if_index) + { + if (hi->hw_class_index == ethernet_hw_interface_class.index) + { + ethernet_set_flags (vnm, hi->hw_if_index, + ETHERNET_INTERFACE_FLAG_MTU); + } + + /* Override MTU on any sub-interface */ + vnet_hw_interface_walk_sw (vnm, + hi->hw_if_index, + vnet_sw_interface_set_mtu_cb, &mtu); + } + else + { + si->max_l3_packet_bytes[VLIB_TX] = si->max_l3_packet_bytes[VLIB_RX] = + mtu; + adj_mtu_update (sw_if_index); + } + + return 0; +} + static void unserialize_vnet_hw_interface_set_flags (serialize_main_t * m, va_list * va) { @@ -567,6 +619,9 @@ vnet_create_sw_interface_no_callbacks (vnet_main_t * vnm, if (sw->type == VNET_SW_INTERFACE_TYPE_HARDWARE) sw->sup_sw_if_index = sw->sw_if_index; + sw->max_l3_packet_bytes[VLIB_RX] = ~0; + sw->max_l3_packet_bytes[VLIB_TX] = ~0; + /* Allocate counters for this interface. */ { u32 i; @@ -703,6 +758,7 @@ vnet_register_interface (vnet_main_t * vnm, char *tx_node_name, *output_node_name; pool_get (im->hw_interfaces, hw); + memset (hw, 0, sizeof (*hw)); hw_index = hw - im->hw_interfaces; hw->hw_if_index = hw_index; @@ -740,9 +796,10 @@ vnet_register_interface (vnet_main_t * vnm, hw->max_rate_bits_per_sec = 0; hw->min_packet_bytes = 0; - hw->per_packet_overhead_bytes = 0; - hw->max_l3_packet_bytes[VLIB_RX] = ~0; - hw->max_l3_packet_bytes[VLIB_TX] = ~0; + hw->max_packet_bytes = 9000; /* default */ + + if (dev_class->tx_function == 0) + goto no_output_nodes; /* No output/tx nodes to create */ tx_node_name = (char *) format (0, "%v-tx", hw->name); output_node_name = (char *) format (0, "%v-output", hw->name); @@ -880,6 +937,7 @@ vnet_register_interface (vnet_main_t * vnm, setup_output_node (vm, hw->output_node_index, hw_class); setup_tx_node (vm, hw->tx_node_index, dev_class); +no_output_nodes: /* Call all up/down callbacks with zero flags when interface is created. */ vnet_sw_interface_set_flags_helper (vnm, hw->sw_if_index, /* flags */ 0, VNET_INTERFACE_SET_FLAGS_HELPER_IS_CREATE); @@ -895,7 +953,8 @@ vnet_delete_hw_interface (vnet_main_t * vnm, u32 hw_if_index) vnet_interface_main_t *im = &vnm->interface_main; vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, hw_if_index); vlib_main_t *vm = vnm->vlib_main; - + vnet_device_class_t *dev_class = vnet_get_device_class (vnm, + hw->dev_class_index); /* If it is up, mark it down. */ if (hw->flags != 0) vnet_hw_interface_set_flags (vnm, hw_if_index, /* flags */ 0); @@ -903,41 +962,50 @@ vnet_delete_hw_interface (vnet_main_t * vnm, u32 hw_if_index) /* Call delete callbacks. */ call_hw_interface_add_del_callbacks (vnm, hw_if_index, /* is_create */ 0); - /* Delete software interface corresponding to hardware interface. */ - vnet_delete_sw_interface (vnm, hw->sw_if_index); - /* Delete any sub-interfaces. */ { u32 id, sw_if_index; /* *INDENT-OFF* */ - hash_foreach (id, sw_if_index, hw->sub_interface_sw_if_index_by_id, ({ + hash_foreach (id, sw_if_index, hw->sub_interface_sw_if_index_by_id, + ({ + vnet_sw_interface_t *si = vnet_get_sw_interface (vnm, sw_if_index); + u64 sup_and_sub_key = + ((u64) (si->sup_sw_if_index) << 32) | (u64) si->sub.id; + hash_unset_mem_free (&im->sw_if_index_by_sup_and_sub, &sup_and_sub_key); vnet_delete_sw_interface (vnm, sw_if_index); })); + hash_free (hw->sub_interface_sw_if_index_by_id); /* *INDENT-ON* */ } - { - vnet_hw_interface_nodes_t *dn; + /* Delete software interface corresponding to hardware interface. */ + vnet_delete_sw_interface (vnm, hw->sw_if_index); - /* *INDENT-OFF* */ - foreach_vlib_main ({ - vnet_interface_output_runtime_t *rt = - vlib_node_get_runtime_data (this_vlib_main, hw->output_node_index); - - /* Mark node runtime as deleted so output node (if called) - * will drop packets. */ - rt->is_deleted = 1; - }); - /* *INDENT-ON* */ + if (dev_class->tx_function) + { + /* Put output/tx nodes into recycle pool */ + vnet_hw_interface_nodes_t *dn; - vlib_node_rename (vm, hw->output_node_index, - "interface-%d-output-deleted", hw_if_index); - vlib_node_rename (vm, hw->tx_node_index, "interface-%d-tx-deleted", - hw_if_index); - vec_add2 (im->deleted_hw_interface_nodes, dn, 1); - dn->tx_node_index = hw->tx_node_index; - dn->output_node_index = hw->output_node_index; - } + /* *INDENT-OFF* */ + foreach_vlib_main + ({ + vnet_interface_output_runtime_t *rt = + vlib_node_get_runtime_data (this_vlib_main, hw->output_node_index); + + /* Mark node runtime as deleted so output node (if called) + * will drop packets. */ + rt->is_deleted = 1; + }); + /* *INDENT-ON* */ + + vlib_node_rename (vm, hw->output_node_index, + "interface-%d-output-deleted", hw_if_index); + vlib_node_rename (vm, hw->tx_node_index, "interface-%d-tx-deleted", + hw_if_index); + vec_add2 (im->deleted_hw_interface_nodes, dn, 1); + dn->tx_node_index = hw->tx_node_index; + dn->output_node_index = hw->output_node_index; + } hash_unset_mem (im->hw_interface_by_name, hw->name); vec_free (hw->name); @@ -1151,6 +1219,10 @@ vnet_hw_interface_compare (vnet_main_t * vnm, int vnet_sw_interface_is_p2p (vnet_main_t * vnm, u32 sw_if_index) { + vnet_sw_interface_t *si = vnet_get_sw_interface (vnm, sw_if_index); + if (si->type == VNET_SW_INTERFACE_TYPE_P2P) + return 1; + vnet_hw_interface_t *hw = vnet_get_sup_hw_interface (vnm, sw_if_index); vnet_hw_interface_class_t *hc = vnet_get_hw_interface_class (vnm, hw->hw_class_index); @@ -1165,6 +1237,7 @@ vnet_interface_init (vlib_main_t * vm) vnet_interface_main_t *im = &vnm->interface_main; vlib_buffer_t *b = 0; vnet_buffer_opaque_t *o = 0; + clib_error_t *error; /* * Keep people from shooting themselves in the foot. @@ -1200,7 +1273,19 @@ vnet_interface_init (vlib_main_t * vm) vec_validate (im->combined_sw_if_counters, VNET_N_COMBINED_INTERFACE_COUNTER - 1); im->combined_sw_if_counters[VNET_INTERFACE_COUNTER_RX].name = "rx"; + im->combined_sw_if_counters[VNET_INTERFACE_COUNTER_RX_UNICAST].name = + "rx-unicast"; + im->combined_sw_if_counters[VNET_INTERFACE_COUNTER_RX_MULTICAST].name = + "rx-multicast"; + im->combined_sw_if_counters[VNET_INTERFACE_COUNTER_RX_BROADCAST].name = + "rx-broadcast"; im->combined_sw_if_counters[VNET_INTERFACE_COUNTER_TX].name = "tx"; + im->combined_sw_if_counters[VNET_INTERFACE_COUNTER_TX_UNICAST].name = + "tx-unicast"; + im->combined_sw_if_counters[VNET_INTERFACE_COUNTER_TX_MULTICAST].name = + "tx-multicast"; + im->combined_sw_if_counters[VNET_INTERFACE_COUNTER_TX_BROADCAST].name = + "tx-broadcast"; im->sw_if_counter_lock[0] = 0; @@ -1245,15 +1330,17 @@ vnet_interface_init (vlib_main_t * vm) } } - { - clib_error_t *error; + if ((error = vlib_call_init_function (vm, vnet_interface_cli_init))) + return error; - if ((error = vlib_call_init_function (vm, vnet_interface_cli_init))) - return error; + vnm->interface_tag_by_sw_if_index = hash_create (0, sizeof (uword)); +#if VLIB_BUFFER_TRACE_TRAJECTORY > 0 + if ((error = vlib_call_init_function (vm, trajectory_trace_init))) return error; - } - vnm->interface_tag_by_sw_if_index = hash_create (0, sizeof (uword)); +#endif + + return 0; } VLIB_INIT_FUNCTION (vnet_interface_init); @@ -1326,7 +1413,8 @@ vnet_rename_interface (vnet_main_t * vnm, u32 hw_if_index, char *new_name) static clib_error_t * vnet_hw_interface_change_mac_address_helper (vnet_main_t * vnm, - u32 hw_if_index, u64 mac_address) + u32 hw_if_index, + u8 * mac_address) { clib_error_t *error = 0; vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, hw_if_index); @@ -1338,7 +1426,7 @@ vnet_hw_interface_change_mac_address_helper (vnet_main_t * vnm, if (dev_class->mac_addr_change_function) { error = - dev_class->mac_addr_change_function (hi, (char *) &mac_address); + dev_class->mac_addr_change_function (hi, (char *) mac_address); } if (!error) { @@ -1347,7 +1435,7 @@ vnet_hw_interface_change_mac_address_helper (vnet_main_t * vnm, hw_class = vnet_get_hw_interface_class (vnm, hi->hw_class_index); if (NULL != hw_class->mac_addr_change_function) - hw_class->mac_addr_change_function (hi, (char *) &mac_address); + hw_class->mac_addr_change_function (hi, (char *) mac_address); } else { @@ -1368,12 +1456,57 @@ vnet_hw_interface_change_mac_address_helper (vnet_main_t * vnm, clib_error_t * vnet_hw_interface_change_mac_address (vnet_main_t * vnm, u32 hw_if_index, - u64 mac_address) + u8 * mac_address) { return vnet_hw_interface_change_mac_address_helper (vnm, hw_if_index, mac_address); } +/* update the unnumbered state of an interface*/ +void +vnet_sw_interface_update_unnumbered (u32 unnumbered_sw_if_index, + u32 ip_sw_if_index, u8 enable) +{ + vnet_main_t *vnm = vnet_get_main (); + vnet_sw_interface_t *si; + u32 was_unnum; + + si = vnet_get_sw_interface (vnm, unnumbered_sw_if_index); + was_unnum = (si->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED); + + if (enable) + { + si->flags |= VNET_SW_INTERFACE_FLAG_UNNUMBERED; + si->unnumbered_sw_if_index = ip_sw_if_index; + + ip4_main.lookup_main.if_address_pool_index_by_sw_if_index + [unnumbered_sw_if_index] = + ip4_main. + lookup_main.if_address_pool_index_by_sw_if_index[ip_sw_if_index]; + ip6_main. + lookup_main.if_address_pool_index_by_sw_if_index + [unnumbered_sw_if_index] = + ip6_main. + lookup_main.if_address_pool_index_by_sw_if_index[ip_sw_if_index]; + } + else + { + si->flags &= ~(VNET_SW_INTERFACE_FLAG_UNNUMBERED); + si->unnumbered_sw_if_index = (u32) ~ 0; + + ip4_main.lookup_main.if_address_pool_index_by_sw_if_index + [unnumbered_sw_if_index] = ~0; + ip6_main.lookup_main.if_address_pool_index_by_sw_if_index + [unnumbered_sw_if_index] = ~0; + } + + if (was_unnum != (si->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED)) + { + ip4_sw_interface_enable_disable (unnumbered_sw_if_index, enable); + ip6_sw_interface_enable_disable (unnumbered_sw_if_index, enable); + } +} + vnet_l3_packet_type_t vnet_link_to_l3_proto (vnet_link_t link) { @@ -1407,15 +1540,104 @@ default_build_rewrite (vnet_main_t * vnm, void default_update_adjacency (vnet_main_t * vnm, u32 sw_if_index, u32 ai) { - u8 *rewrite; + ip_adjacency_t *adj; - rewrite = vnet_build_rewrite_for_sw_interface (vnm, sw_if_index, - adj_get_link_type (ai), - NULL); + adj = adj_get (ai); - adj_nbr_update_rewrite (ai, ADJ_NBR_REWRITE_FLAG_COMPLETE, rewrite); + switch (adj->lookup_next_index) + { + case IP_LOOKUP_NEXT_GLEAN: + adj_glean_update_rewrite (ai); + break; + case IP_LOOKUP_NEXT_ARP: + /* + * default rewirte in neighbour adj + */ + adj_nbr_update_rewrite + (ai, + ADJ_NBR_REWRITE_FLAG_COMPLETE, + vnet_build_rewrite_for_sw_interface (vnm, + sw_if_index, + adj_get_link_type (ai), NULL)); + break; + case IP_LOOKUP_NEXT_MCAST: + /* + * mcast traffic also uses default rewrite string with no mcast + * switch time updates. + */ + adj_mcast_update_rewrite + (ai, + vnet_build_rewrite_for_sw_interface (vnm, + sw_if_index, + adj_get_link_type (ai), + NULL), 0, 0); + break; + case IP_LOOKUP_NEXT_DROP: + case IP_LOOKUP_NEXT_PUNT: + case IP_LOOKUP_NEXT_LOCAL: + case IP_LOOKUP_NEXT_REWRITE: + case IP_LOOKUP_NEXT_MCAST_MIDCHAIN: + case IP_LOOKUP_NEXT_MIDCHAIN: + case IP_LOOKUP_NEXT_ICMP_ERROR: + case IP_LOOKUP_N_NEXT: + ASSERT (0); + break; + } +} + +int collect_detailed_interface_stats_flag = 0; + +void +collect_detailed_interface_stats_flag_set (void) +{ + collect_detailed_interface_stats_flag = 1; +} + +void +collect_detailed_interface_stats_flag_clear (void) +{ + collect_detailed_interface_stats_flag = 0; +} + +static clib_error_t * +collect_detailed_interface_stats_cli (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + unformat_input_t _line_input, *line_input = &_line_input; + clib_error_t *error = NULL; + + /* Get a line of input. */ + if (!unformat_user (input, unformat_line_input, line_input)) + return clib_error_return (0, "expected enable | disable"); + + while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (line_input, "enable") || unformat (line_input, "on")) + collect_detailed_interface_stats_flag_set (); + else if (unformat (line_input, "disable") + || unformat (line_input, "off")) + collect_detailed_interface_stats_flag_clear (); + else + { + error = clib_error_return (0, "unknown input `%U'", + format_unformat_error, line_input); + goto done; + } + } + +done: + unformat_free (line_input); + return error; } +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (collect_detailed_interface_stats_command, static) = { + .path = "interface collect detailed-stats", + .short_help = "interface collect detailed-stats ", + .function = collect_detailed_interface_stats_cli, +}; +/* *INDENT-ON* */ /* * fd.io coding-style-patch-verification: ON