From 7cd468a3d7dee7d6c92f69a0bb7061ae208ec727 Mon Sep 17 00:00:00 2001 From: Damjan Marion Date: Mon, 19 Dec 2016 23:05:39 +0100 Subject: Reorganize source tree to use single autotools instance Change-Id: I7b51f88292e057c6443b12224486f2d0c9f8ae23 Signed-off-by: Damjan Marion --- src/vnet/interface_cli.c | 1165 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1165 insertions(+) create mode 100644 src/vnet/interface_cli.c (limited to 'src/vnet/interface_cli.c') diff --git a/src/vnet/interface_cli.c b/src/vnet/interface_cli.c new file mode 100644 index 00000000..7dbee867 --- /dev/null +++ b/src/vnet/interface_cli.c @@ -0,0 +1,1165 @@ +/* + * Copyright (c) 2015 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * interface_cli.c: interface CLI + * + * Copyright (c) 2008 Eliot Dresselhaus + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * @file + * Interface CLI. + */ + +#include +#include +#include +#include +#include + +static int +compare_interface_names (void *a1, void *a2) +{ + u32 *hi1 = a1; + u32 *hi2 = a2; + + return vnet_hw_interface_compare (vnet_get_main (), *hi1, *hi2); +} + +static clib_error_t * +show_or_clear_hw_interfaces (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + clib_error_t *error = 0; + vnet_main_t *vnm = vnet_get_main (); + vnet_interface_main_t *im = &vnm->interface_main; + vnet_hw_interface_t *hi; + u32 hw_if_index, *hw_if_indices = 0; + int i, verbose = -1, is_show, show_bond = 0; + + is_show = strstr (cmd->path, "show") != 0; + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + /* See if user wants to show a specific interface. */ + if (unformat + (input, "%U", unformat_vnet_hw_interface, vnm, &hw_if_index)) + vec_add1 (hw_if_indices, hw_if_index); + + /* See if user wants to show an interface with a specific hw_if_index. */ + else if (unformat (input, "%u", &hw_if_index)) + vec_add1 (hw_if_indices, hw_if_index); + + else if (unformat (input, "verbose")) + verbose = 1; /* this is also the default */ + + else if (unformat (input, "detail")) + verbose = 2; + + else if (unformat (input, "brief")) + verbose = 0; + + else if (unformat (input, "bond")) + { + show_bond = 1; + if (verbose < 0) + verbose = 0; /* default to brief for link bonding */ + } + + else + { + error = clib_error_return (0, "unknown input `%U'", + format_unformat_error, input); + goto done; + } + } + + /* Gather interfaces. */ + if (vec_len (hw_if_indices) == 0) + pool_foreach (hi, im->hw_interfaces, + vec_add1 (hw_if_indices, hi - im->hw_interfaces)); + + if (verbose < 0) + verbose = 1; /* default to verbose (except bond) */ + + if (is_show) + { + /* Sort by name. */ + vec_sort_with_function (hw_if_indices, compare_interface_names); + + vlib_cli_output (vm, "%U\n", format_vnet_hw_interface, vnm, 0, verbose); + for (i = 0; i < vec_len (hw_if_indices); i++) + { + hi = vnet_get_hw_interface (vnm, hw_if_indices[i]); + if (show_bond == 0) /* show all interfaces */ + vlib_cli_output (vm, "%U\n", format_vnet_hw_interface, vnm, + hi, verbose); + else if ((hi->bond_info) && + (hi->bond_info != VNET_HW_INTERFACE_BOND_INFO_SLAVE)) + { /* show only bonded interface and all its slave interfaces */ + int hw_idx; + vnet_hw_interface_t *shi; + vlib_cli_output (vm, "%U\n", format_vnet_hw_interface, vnm, + hi, verbose); + + /* *INDENT-OFF* */ + clib_bitmap_foreach (hw_idx, hi->bond_info, + ({ + shi = vnet_get_hw_interface(vnm, hw_idx); + vlib_cli_output (vm, "%U\n", + format_vnet_hw_interface, vnm, shi, verbose); + })); + /* *INDENT-ON* */ + } + } + } + else + { + for (i = 0; i < vec_len (hw_if_indices); i++) + { + vnet_device_class_t *dc; + + hi = vnet_get_hw_interface (vnm, hw_if_indices[i]); + dc = vec_elt_at_index (im->device_classes, hi->dev_class_index); + + if (dc->clear_counters) + dc->clear_counters (hi->dev_instance); + } + } + +done: + vec_free (hw_if_indices); + return error; +} + +/* *INDENT-OFF* */ +/*? + * Displays various information about the state of the current terminal + * session. + * + * @cliexpar + * @cliexstart{show hardware} + * Name Link Hardware + * GigabitEthernet2/0/0 up GigabitEthernet2/0/0 + * Ethernet address 00:50:56:b7:7c:83 + * Intel 82545em_copper + * link up, media 1000T full-duplex, master, + * 0 unprocessed, 384 total buffers on rx queue 0 ring + * 237 buffers in driver rx cache + * rx total packets 1816 + * rx total bytes 181084 + * rx good packets 1816 + * rx good bytes 181084 + * rx 65 127 byte packets 1586 + * rx 256 511 byte packets 230 + * tx total packets 346 + * tx total bytes 90224 + * tx good packets 346 + * tx good bytes 88840 + * tx 64 byte packets 1 + * tx 65 127 byte packets 115 + * tx 256 511 byte packets 230 + * @cliexend + ?*/ +VLIB_CLI_COMMAND (show_hw_interfaces_command, static) = { + .path = "show hardware-interfaces", + .short_help = "show hardware-interfaces [brief|verbose|detail] [bond] [ ...]", + .function = show_or_clear_hw_interfaces, +}; +/* *INDENT-ON* */ + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (clear_hw_interface_counters_command, static) = { + .path = "clear hardware-interfaces", + .short_help = "Clear hardware interfaces statistics", + .function = show_or_clear_hw_interfaces, +}; +/* *INDENT-ON* */ + +static int +sw_interface_name_compare (void *a1, void *a2) +{ + vnet_sw_interface_t *si1 = a1; + vnet_sw_interface_t *si2 = a2; + + return vnet_sw_interface_compare (vnet_get_main (), + si1->sw_if_index, si2->sw_if_index); +} + +static clib_error_t * +show_sw_interfaces (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + clib_error_t *error = 0; + vnet_main_t *vnm = vnet_get_main (); + vnet_interface_main_t *im = &vnm->interface_main; + vnet_sw_interface_t *si, *sorted_sis = 0; + u32 sw_if_index = ~(u32) 0; + u8 show_addresses = 0; + u8 show_features = 0; + u8 show_tag = 0; + + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + /* See if user wants to show specific interface */ + if (unformat + (input, "%U", unformat_vnet_sw_interface, vnm, &sw_if_index)) + { + si = pool_elt_at_index (im->sw_interfaces, sw_if_index); + vec_add1 (sorted_sis, si[0]); + } + else if (unformat (input, "address") || unformat (input, "addr")) + show_addresses = 1; + else if (unformat (input, "features") || unformat (input, "feat")) + show_features = 1; + else if (unformat (input, "tag")) + show_tag = 1; + else + { + error = clib_error_return (0, "unknown input `%U'", + format_unformat_error, input); + goto done; + } + } + + if (show_features || show_tag) + { + if (sw_if_index == ~(u32) 0) + return clib_error_return (0, "Interface not specified..."); + } + + if (show_features) + { + vnet_interface_features_show (vm, sw_if_index); + return 0; + } + if (show_tag) + { + u8 *tag; + tag = vnet_get_sw_interface_tag (vnm, sw_if_index); + vlib_cli_output (vm, "%U: %s", + format_vnet_sw_if_index_name, vnm, sw_if_index, + tag ? (char *) tag : "(none)"); + return 0; + } + + if (!show_addresses) + vlib_cli_output (vm, "%U\n", format_vnet_sw_interface, vnm, 0); + + if (vec_len (sorted_sis) == 0) /* Get all interfaces */ + { + /* Gather interfaces. */ + sorted_sis = + vec_new (vnet_sw_interface_t, pool_elts (im->sw_interfaces)); + _vec_len (sorted_sis) = 0; + pool_foreach (si, im->sw_interfaces, ( + { + vec_add1 (sorted_sis, si[0]); + } + )); + + /* Sort by name. */ + vec_sort_with_function (sorted_sis, sw_interface_name_compare); + } + + if (show_addresses) + { + vec_foreach (si, sorted_sis) + { + l2input_main_t *l2m = &l2input_main; + ip4_main_t *im4 = &ip4_main; + ip6_main_t *im6 = &ip6_main; + ip_lookup_main_t *lm4 = &im4->lookup_main; + ip_lookup_main_t *lm6 = &im6->lookup_main; + ip_interface_address_t *ia = 0; + ip4_address_t *r4; + ip6_address_t *r6; + u32 fib_index4 = 0, fib_index6 = 0; + ip4_fib_t *fib4; + ip6_fib_t *fib6; + l2_input_config_t *config; + + if (vec_len (im4->fib_index_by_sw_if_index) > si->sw_if_index) + fib_index4 = vec_elt (im4->fib_index_by_sw_if_index, + si->sw_if_index); + + if (vec_len (im6->fib_index_by_sw_if_index) > si->sw_if_index) + fib_index6 = vec_elt (im6->fib_index_by_sw_if_index, + si->sw_if_index); + + fib4 = ip4_fib_get (fib_index4); + fib6 = ip6_fib_get (fib_index6); + + if (si->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED) + vlib_cli_output + (vm, "%U (%s): \n unnumbered, use %U", + format_vnet_sw_if_index_name, + vnm, si->sw_if_index, + (si->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) ? "up" : "dn", + format_vnet_sw_if_index_name, vnm, si->unnumbered_sw_if_index); + + else + { + vlib_cli_output (vm, "%U (%s):", + format_vnet_sw_if_index_name, + vnm, si->sw_if_index, + (si->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) + ? "up" : "dn"); + } + + /* Display any L2 addressing info */ + vec_validate (l2m->configs, si->sw_if_index); + config = vec_elt_at_index (l2m->configs, si->sw_if_index); + if (config->bridge) + { + u32 bd_id = l2input_main.bd_configs[config->bd_index].bd_id; + vlib_cli_output (vm, " l2 bridge bd_id %d%s%d", bd_id, + config->bvi ? " bvi shg " : " shg ", + config->shg); + } + else if (config->xconnect) + { + vlib_cli_output (vm, " l2 xconnect %U", + format_vnet_sw_if_index_name, + vnm, config->output_sw_if_index); + } + + /* Display any IP4 addressing info */ + /* *INDENT-OFF* */ + foreach_ip_interface_address (lm4, ia, si->sw_if_index, + 1 /* honor unnumbered */, + ({ + r4 = ip_interface_address_get_address (lm4, ia); + if (fib4->table_id) + { + vlib_cli_output (vm, " %U/%d table %d", + format_ip4_address, r4, + ia->address_length, + fib4->table_id); + } + else + { + vlib_cli_output (vm, " %U/%d", + format_ip4_address, r4, + ia->address_length); + } + })); + /* *INDENT-ON* */ + + /* Display any IP6 addressing info */ + /* *INDENT-OFF* */ + foreach_ip_interface_address (lm6, ia, si->sw_if_index, + 1 /* honor unnumbered */, + ({ + r6 = ip_interface_address_get_address (lm6, ia); + if (fib6->table_id) + { + vlib_cli_output (vm, " %U/%d table %d", + format_ip6_address, r6, + ia->address_length, + fib6->table_id); + } + else + { + vlib_cli_output (vm, " %U/%d", + format_ip6_address, r6, + ia->address_length); + } + })); + /* *INDENT-ON* */ + } + } + else + { + vec_foreach (si, sorted_sis) + { + vlib_cli_output (vm, "%U\n", format_vnet_sw_interface, vnm, si); + } + } + +done: + vec_free (sorted_sis); + return error; +} + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (show_sw_interfaces_command, static) = { + .path = "show interfaces", + .short_help = "show interfaces [address|addr|features|feat] [ ...]", + .function = show_sw_interfaces, +}; +/* *INDENT-ON* */ + +/* Root of all interface commands. */ +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (vnet_cli_interface_command, static) = { + .path = "interface", + .short_help = "Interface commands", +}; +/* *INDENT-ON* */ + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (vnet_cli_set_interface_command, static) = { + .path = "set interface", + .short_help = "Interface commands", +}; +/* *INDENT-ON* */ + +static clib_error_t * +clear_interface_counters (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + vnet_main_t *vnm = vnet_get_main (); + vnet_interface_main_t *im = &vnm->interface_main; + vlib_simple_counter_main_t *sm; + vlib_combined_counter_main_t *cm; + static vnet_main_t **my_vnet_mains; + int i, j, n_counters; + + vec_reset_length (my_vnet_mains); + + for (i = 0; i < vec_len (vnet_mains); i++) + { + if (vnet_mains[i]) + vec_add1 (my_vnet_mains, vnet_mains[i]); + } + + if (vec_len (vnet_mains) == 0) + vec_add1 (my_vnet_mains, vnm); + + n_counters = vec_len (im->combined_sw_if_counters); + + for (j = 0; j < n_counters; j++) + { + for (i = 0; i < vec_len (my_vnet_mains); i++) + { + im = &my_vnet_mains[i]->interface_main; + cm = im->combined_sw_if_counters + j; + vlib_clear_combined_counters (cm); + } + } + + n_counters = vec_len (im->sw_if_counters); + + for (j = 0; j < n_counters; j++) + { + for (i = 0; i < vec_len (my_vnet_mains); i++) + { + im = &my_vnet_mains[i]->interface_main; + sm = im->sw_if_counters + j; + vlib_clear_simple_counters (sm); + } + } + + return 0; +} + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (clear_interface_counters_command, static) = { + .path = "clear interfaces", + .short_help = "Clear interfaces statistics", + .function = clear_interface_counters, +}; +/* *INDENT-ON* */ + +/** + * Parse subinterface names. + * + * The following subinterface syntax is supported. The first two are for + * backwards compatability: + * + * + * - a subinterface with the name .. The subinterface + * is a single dot1q vlan with vlan id and exact-match semantics. + * + * - + * - a set of the above subinterfaces, repeating for each id + * in the range to + * + * In the following, exact-match semantics (i.e. the number of vlan tags on the + * packet must match the number of tags in the configuration) are used only if + * the keyword exact-match is present. Non-exact match is the default. + * + * dot1q [exact-match] + * - a subinterface with the name .. The subinterface + * is a single dot1q vlan with vlan id . + * + * dot1q any [exact-match] + * - a subinterface with the name .. The subinterface + * is a single dot1q vlan with any vlan id. + * + * dot1q inner-dot1q [exact-match] + * - a subinterface with the name .. The subinterface + * is a double dot1q vlan with outer vlan id and inner vlan id + * . + * + * dot1q inner-dot1q any [exact-match] + * - a subinterface with the name .. The subinterface + * is a double dot1q vlan with outer vlan id and any inner vlan id. + * + * dot1q any inner-dot1q any [exact-match] + * + * - a subinterface with the name .. The subinterface + * is a double dot1q vlan with any outer vlan id and any inner vlan id. + * + * For each of the above CLI, there is a duplicate that uses the keyword + * "dot1ad" in place of the first "dot1q". These interfaces use ethertype + * 0x88ad in place of 0x8100 for the outer ethertype. Note that for double- + * tagged packets the inner ethertype is always 0x8100. Also note that + * the dot1q and dot1ad naming spaces are independent, so it is legal to + * have both "Gig3/0/0.1 dot1q 100" and "Gig3/0/0.2 dot1ad 100". For example: + * + * dot1ad inner-dot1q [exact-match] + * - a subinterface with the name .. The subinterface + * is a double dot1ad vlan with outer vlan id and inner vlan + * id . + * + * untagged + * - a subinterface with the name .. The subinterface + * has no vlan tags. Only one can be specified per interface. + * + * default + * - a subinterface with the name .. This is associated + * with a packet that did not match any other configured subinterface + * on this interface. Only one can be specified per interface. + */ + +static clib_error_t * +parse_vlan_sub_interfaces (unformat_input_t * input, + vnet_sw_interface_t * template) +{ + clib_error_t *error = 0; + u32 inner_vlan, outer_vlan; + + if (unformat (input, "any inner-dot1q any")) + { + template->sub.eth.flags.two_tags = 1; + template->sub.eth.flags.outer_vlan_id_any = 1; + template->sub.eth.flags.inner_vlan_id_any = 1; + } + else if (unformat (input, "any")) + { + template->sub.eth.flags.one_tag = 1; + template->sub.eth.flags.outer_vlan_id_any = 1; + } + else if (unformat (input, "%d inner-dot1q any", &outer_vlan)) + { + template->sub.eth.flags.two_tags = 1; + template->sub.eth.flags.inner_vlan_id_any = 1; + template->sub.eth.outer_vlan_id = outer_vlan; + } + else if (unformat (input, "%d inner-dot1q %d", &outer_vlan, &inner_vlan)) + { + template->sub.eth.flags.two_tags = 1; + template->sub.eth.outer_vlan_id = outer_vlan; + template->sub.eth.inner_vlan_id = inner_vlan; + } + else if (unformat (input, "%d", &outer_vlan)) + { + template->sub.eth.flags.one_tag = 1; + template->sub.eth.outer_vlan_id = outer_vlan; + } + else + { + error = clib_error_return (0, "expected dot1q config, got `%U'", + format_unformat_error, input); + goto done; + } + + if (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "exact-match")) + { + template->sub.eth.flags.exact_match = 1; + } + } + +done: + return error; +} + +static clib_error_t * +create_sub_interfaces (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + vnet_main_t *vnm = vnet_get_main (); + clib_error_t *error = 0; + u32 hw_if_index, sw_if_index; + vnet_hw_interface_t *hi; + u32 id, id_min, id_max; + vnet_sw_interface_t template; + + hw_if_index = ~0; + if (!unformat_user (input, unformat_vnet_hw_interface, vnm, &hw_if_index)) + { + error = clib_error_return (0, "unknown interface `%U'", + format_unformat_error, input); + goto done; + } + + memset (&template, 0, sizeof (template)); + template.sub.eth.raw_flags = 0; + + if (unformat (input, "%d default", &id_min)) + { + id_max = id_min; + template.sub.eth.flags.default_sub = 1; + } + else if (unformat (input, "%d untagged", &id_min)) + { + id_max = id_min; + template.sub.eth.flags.no_tags = 1; + template.sub.eth.flags.exact_match = 1; + } + else if (unformat (input, "%d dot1q", &id_min)) + { + /* parse dot1q config */ + id_max = id_min; + error = parse_vlan_sub_interfaces (input, &template); + if (error) + goto done; + } + else if (unformat (input, "%d dot1ad", &id_min)) + { + /* parse dot1ad config */ + id_max = id_min; + template.sub.eth.flags.dot1ad = 1; + error = parse_vlan_sub_interfaces (input, &template); + if (error) + goto done; + } + else if (unformat (input, "%d-%d", &id_min, &id_max)) + { + template.sub.eth.flags.one_tag = 1; + template.sub.eth.flags.exact_match = 1; + if (id_min > id_max) + goto id_error; + } + else if (unformat (input, "%d", &id_min)) + { + id_max = id_min; + template.sub.eth.flags.one_tag = 1; + template.sub.eth.outer_vlan_id = id_min; + template.sub.eth.flags.exact_match = 1; + } + else + { + id_error: + error = clib_error_return (0, "expected ID or ID MIN-MAX, got `%U'", + format_unformat_error, input); + goto done; + } + + hi = vnet_get_hw_interface (vnm, hw_if_index); + + if (hi->bond_info == VNET_HW_INTERFACE_BOND_INFO_SLAVE) + { + error = + clib_error_return (0, + "not allowed as %v belong to a BondEthernet interface", + hi->name); + goto done; + } + + for (id = id_min; id <= id_max; id++) + { + uword *p; + vnet_interface_main_t *im = &vnm->interface_main; + u64 sup_and_sub_key = ((u64) (hi->sw_if_index) << 32) | (u64) id; + u64 *kp; + + p = hash_get_mem (im->sw_if_index_by_sup_and_sub, &sup_and_sub_key); + if (p) + { + if (CLIB_DEBUG > 0) + clib_warning ("sup sw_if_index %d, sub id %d already exists\n", + hi->sw_if_index, id); + continue; + } + + kp = clib_mem_alloc (sizeof (*kp)); + *kp = sup_and_sub_key; + + template.type = VNET_SW_INTERFACE_TYPE_SUB; + template.flood_class = VNET_FLOOD_CLASS_NORMAL; + template.sup_sw_if_index = hi->sw_if_index; + template.sub.id = id; + if (id_min < id_max) + template.sub.eth.outer_vlan_id = id; + + error = vnet_create_sw_interface (vnm, &template, &sw_if_index); + if (error) + goto done; + + hash_set (hi->sub_interface_sw_if_index_by_id, id, sw_if_index); + hash_set_mem (im->sw_if_index_by_sup_and_sub, kp, sw_if_index); + vlib_cli_output (vm, "%U\n", format_vnet_sw_if_index_name, + vnet_get_main (), sw_if_index); + } + +done: + return error; +} + +/* *INDENT-OFF* */ +/*? + * Create vlan subinterfaces + * + * @cliexpar + * @cliexstart{create sub-interfaces} + * + * To create a vlan subinterface 11 to process packets on 802.1q VLAN id 11, use: + * + * vpp# create sub GigabitEthernet2/0/0 11 + * + * This shorthand is equivalent to: + * vpp# create sub GigabitEthernet2/0/0 11 dot1q 11 exact-match + * + * You can specify a subinterface number that is different from the vlan id: + * vpp# create sub GigabitEthernet2/0/0 11 dot1q 100 + * + * You can create qinq and q-in-any interfaces: + * vpp# create sub GigabitEthernet2/0/0 11 dot1q 100 inner-dot1q 200 + * vpp# create sub GigabitEthernet2/0/0 12 dot1q 100 inner-dot1q any + * + * You can also create dot1ad interfaces: + * vpp# create sub GigabitEthernet2/0/0 11 dot1ad 11 + * vpp# create sub GigabitEthernet2/0/0 12 dot1q 100 inner-dot1q 200 + * + * Subinterfaces can be configured as either exact-match or non-exact match. + * Non-exact match is the CLI default. If exact-match is specified, + * packets must have the same number of vlan tags as the configuration. + * For non-exact-match, packets must at least that number of tags. + * L3 (routed) interfaces must be configured as exact-match. + * L2 interfaces are typically configured as non-exact-match. + * + * For example, a packet with outer vlan 100 and inner 200 would match this interface: + * vpp# create sub GigabitEthernet2/0/0 5 dot1q 100 + * + * but would not match this interface: + * vpp# create sub GigabitEthernet2/0/0 5 dot1q 100 exact-match + * + * There are two special subinterfaces that can be configured. Subinterface untagged has no vlan tags: + * vpp# create sub GigabitEthernet2/0/0 5 untagged + * + * The subinterface default matches any packet that does not match any other subinterface: + * vpp# create sub GigabitEthernet2/0/0 7 default + * @cliexend + ?*/ +VLIB_CLI_COMMAND (create_sub_interfaces_command, static) = { + .path = "create sub-interfaces", + .short_help = "create sub-interfaces [-] [dot1q|dot1ad|default|untagged]", + .function = create_sub_interfaces, +}; +/* *INDENT-ON* */ + +static clib_error_t * +set_state (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + vnet_main_t *vnm = vnet_get_main (); + clib_error_t *error; + u32 sw_if_index, flags; + + sw_if_index = ~0; + if (!unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index)) + { + error = clib_error_return (0, "unknown interface `%U'", + format_unformat_error, input); + goto done; + } + + if (!unformat (input, "%U", unformat_vnet_sw_interface_flags, &flags)) + { + error = clib_error_return (0, "unknown flags `%U'", + format_unformat_error, input); + goto done; + } + + error = vnet_sw_interface_set_flags (vnm, sw_if_index, flags); + if (error) + goto done; + +done: + return error; +} + + +/* *INDENT-OFF* */ +/*? + * Interface admin up/down + * + * @cliexpar + * @cliexstart{set interface state} + * vpp# set interface state GigabitEthernet2/0/0 up + * vpp# set interface state GigabitEthernet2/0/0 down + * @cliexend + ?*/ +VLIB_CLI_COMMAND (set_state_command, static) = { + .path = "set interface state", + .short_help = "Set interface state", + .function = set_state, +}; +/* *INDENT-ON* */ + +static clib_error_t * +set_unnumbered (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + vnet_main_t *vnm = vnet_get_main (); + u32 unnumbered_sw_if_index; + u32 inherit_from_sw_if_index; + vnet_sw_interface_t *si; + int is_set = 0; + int is_del = 0; + + if (unformat (input, "%U use %U", + unformat_vnet_sw_interface, vnm, &unnumbered_sw_if_index, + unformat_vnet_sw_interface, vnm, &inherit_from_sw_if_index)) + is_set = 1; + else if (unformat (input, "del %U", + unformat_vnet_sw_interface, vnm, + &unnumbered_sw_if_index)) + is_del = 1; + else + return clib_error_return (0, "parse error '%U'", + format_unformat_error, input); + + si = vnet_get_sw_interface (vnm, unnumbered_sw_if_index); + if (is_del) + { + si->flags &= ~(VNET_SW_INTERFACE_FLAG_UNNUMBERED); + si->unnumbered_sw_if_index = (u32) ~ 0; + ip4_sw_interface_enable_disable (unnumbered_sw_if_index, 0); + ip6_sw_interface_enable_disable (unnumbered_sw_if_index, 0); + } + else if (is_set) + { + si->flags |= VNET_SW_INTERFACE_FLAG_UNNUMBERED; + si->unnumbered_sw_if_index = inherit_from_sw_if_index; + ip4_sw_interface_enable_disable (unnumbered_sw_if_index, 1); + ip6_sw_interface_enable_disable (unnumbered_sw_if_index, 1); + } + + return 0; +} + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (set_unnumbered_command, static) = { + .path = "set interface unnumbered", + .short_help = "set interface unnumbered [ use | del ]", + .function = set_unnumbered, +}; +/* *INDENT-ON* */ + + + +static clib_error_t * +set_hw_class (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + vnet_main_t *vnm = vnet_get_main (); + vnet_interface_main_t *im = &vnm->interface_main; + clib_error_t *error; + u32 hw_if_index, hw_class_index; + + hw_if_index = ~0; + if (!unformat_user (input, unformat_vnet_hw_interface, vnm, &hw_if_index)) + { + error = clib_error_return (0, "unknown hardware interface `%U'", + format_unformat_error, input); + goto done; + } + + if (!unformat_user (input, unformat_hash_string, + im->hw_interface_class_by_name, &hw_class_index)) + { + error = clib_error_return (0, "unknown hardware class `%U'", + format_unformat_error, input); + goto done; + } + + error = vnet_hw_interface_set_class (vnm, hw_if_index, hw_class_index); + if (error) + goto done; + +done: + return error; +} + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (set_hw_class_command, static) = { + .path = "set interface hw-class", + .short_help = "Set interface hardware class", + .function = set_hw_class, +}; +/* *INDENT-ON* */ + +static clib_error_t * +vnet_interface_cli_init (vlib_main_t * vm) +{ + return 0; +} + +VLIB_INIT_FUNCTION (vnet_interface_cli_init); + +static clib_error_t * +renumber_interface_command_fn (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + u32 hw_if_index; + u32 new_dev_instance; + vnet_main_t *vnm = vnet_get_main (); + int rv; + + if (!unformat_user (input, unformat_vnet_hw_interface, vnm, &hw_if_index)) + return clib_error_return (0, "unknown hardware interface `%U'", + format_unformat_error, input); + + if (!unformat (input, "%d", &new_dev_instance)) + return clib_error_return (0, "new dev instance missing"); + + rv = vnet_interface_name_renumber (hw_if_index, new_dev_instance); + + switch (rv) + { + case 0: + break; + + default: + return clib_error_return (0, "vnet_interface_name_renumber returned %d", + rv); + + } + + return 0; +} + + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (renumber_interface_command, static) = { + .path = "renumber interface", + .short_help = "renumber interface ", + .function = renumber_interface_command_fn, +}; +/* *INDENT-ON* */ + +static clib_error_t * +promiscuous_cmd (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + vnet_main_t *vnm = vnet_get_main (); + u32 hw_if_index; + u32 flags = ETHERNET_INTERFACE_FLAG_ACCEPT_ALL; + ethernet_main_t *em = ðernet_main; + ethernet_interface_t *eif; + + if (unformat (input, "on %U", + unformat_vnet_hw_interface, vnm, &hw_if_index)) + ; + else if (unformat (input, "off %U", + unformat_ethernet_interface, vnm, &hw_if_index)) + flags = 0; + else + return clib_error_return (0, "unknown input `%U'", + format_unformat_error, input); + + eif = ethernet_get_interface (em, hw_if_index); + if (!eif) + return clib_error_return (0, "not supported"); + + ethernet_set_flags (vnm, hw_if_index, flags); + return 0; +} + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (set_interface_promiscuous_cmd, static) = { + .path = "set interface promiscuous", + .short_help = "set interface promiscuous [on | off] ", + .function = promiscuous_cmd, +}; +/* *INDENT-ON* */ + +static clib_error_t * +mtu_cmd (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) +{ + vnet_main_t *vnm = vnet_get_main (); + u32 hw_if_index, mtu; + u32 flags = ETHERNET_INTERFACE_FLAG_MTU; + ethernet_main_t *em = ðernet_main; + + if (unformat (input, "%d %U", &mtu, + unformat_vnet_hw_interface, vnm, &hw_if_index)) + { + vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, hw_if_index); + ethernet_interface_t *eif = ethernet_get_interface (em, hw_if_index); + + if (!eif) + return clib_error_return (0, "not supported"); + + if (mtu < hi->min_supported_packet_bytes) + return clib_error_return (0, "Invalid mtu (%d): " + "must be >= min pkt bytes (%d)", mtu, + hi->min_supported_packet_bytes); + + if (mtu > hi->max_supported_packet_bytes) + return clib_error_return (0, "Invalid mtu (%d): must be <= (%d)", mtu, + hi->max_supported_packet_bytes); + + if (hi->max_packet_bytes != mtu) + { + hi->max_packet_bytes = mtu; + ethernet_set_flags (vnm, hw_if_index, flags); + } + } + else + return clib_error_return (0, "unknown input `%U'", + format_unformat_error, input); + return 0; +} + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (set_interface_mtu_cmd, static) = { + .path = "set interface mtu", + .short_help = "set interface mtu ", + .function = mtu_cmd, +}; +/* *INDENT-ON* */ + +static clib_error_t * +set_interface_mac_address (vlib_main_t * vm, unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + vnet_main_t *vnm = vnet_get_main (); + clib_error_t *error = 0; + u32 sw_if_index = ~0; + u64 mac = 0; + + if (!unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index)) + { + error = clib_error_return (0, "unknown interface `%U'", + format_unformat_error, input); + goto done; + } + if (!unformat_user (input, unformat_ethernet_address, &mac)) + { + error = clib_error_return (0, "expected mac address `%U'", + format_unformat_error, input); + goto done; + } + error = vnet_hw_interface_change_mac_address (vnm, sw_if_index, mac); +done: + return error; +} + +/*? + * The 'set interface mac address ' command allows to set MAC address of given interface. + * In case of NIC interfaces the one has to support MAC address change. A side effect of MAC address + * change are changes of MAC addresses in FIB tables (ipv4 and ipv6). + * + * @cliexpar + * @parblock + * Example of how to change MAC Address of interface: + * @cliexcmd{set interface mac address GigabitEthernet0/8/0 aa:bb:cc:dd:ee:01} + * @cliexcmd{set interface mac address host-vpp0 aa:bb:cc:dd:ee:02} + * @cliexcmd{set interface mac address tap-0 aa:bb:cc:dd:ee:03} + * @cliexcmd{set interface mac address pg0 aa:bb:cc:dd:ee:04} + * @endparblock +?*/ +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (set_interface_mac_address_cmd, static) = { + .path = "set interface mac address", + .short_help = "set interface mac address ", + .function = set_interface_mac_address, +}; +/* *INDENT-ON* */ + +static clib_error_t * +set_tag (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) +{ + vnet_main_t *vnm = vnet_get_main (); + u32 sw_if_index = ~0; + u8 *tag = 0; + + if (!unformat (input, "%U %s", unformat_vnet_sw_interface, + vnm, &sw_if_index, &tag)) + return clib_error_return (0, "unknown input `%U'", + format_unformat_error, input); + + vnet_set_sw_interface_tag (vnm, tag, sw_if_index); + + return 0; +} + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (set_tag_command, static) = { + .path = "set interface tag", + .short_help = "set interface tag ", + .function = set_tag, +}; +/* *INDENT-ON* */ + +static clib_error_t * +clear_tag (vlib_main_t * vm, unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + vnet_main_t *vnm = vnet_get_main (); + u32 sw_if_index = ~0; + + if (!unformat (input, "%U", unformat_vnet_sw_interface, vnm, &sw_if_index)) + return clib_error_return (0, "unknown input `%U'", + format_unformat_error, input); + + vnet_clear_sw_interface_tag (vnm, sw_if_index); + + return 0; +} + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (clear_tag_command, static) = { + .path = "clear interface tag", + .short_help = "clear interface tag ", + .function = clear_tag, +}; +/* *INDENT-ON* */ + + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ -- cgit 1.2.3-korg From 3212c57087069c5137abe4919ac1336e79fa93e9 Mon Sep 17 00:00:00 2001 From: Eyal Bari Date: Mon, 6 Mar 2017 11:47:50 +0200 Subject: CLI: hide deleted interfaces Added a new interface flag - HIDDEN Indicates that the interface does not appear in CLI/API. Added three new interface functions: vnet_sw_interface_is_api_visible - indicates if the sw_if_index should be displayed vnet_swif_is_api_visible - variant for sw_interface vnet_sw_interface_is_api_valid - tests if the given if_index exists and is visible for future use by api functions Changed the unformat function to only accept visible interfaces Changed vxlan to add the HIDDEN flag to deleted interfaces This is the first part in a series to hide deleted interfaces from the API Change-Id: Ib43cc5cf1c450856560faf4e84126eb3671038e2 Signed-off-by: Eyal Bari --- src/vnet/interface.h | 3 +++ src/vnet/interface_cli.c | 5 +++-- src/vnet/interface_format.c | 10 +++++++--- src/vnet/interface_funcs.h | 20 ++++++++++++++++++++ src/vnet/vxlan/vxlan.c | 7 +++++++ 5 files changed, 40 insertions(+), 5 deletions(-) (limited to 'src/vnet/interface_cli.c') diff --git a/src/vnet/interface.h b/src/vnet/interface.h index 7b791751..ef8f9118 100644 --- a/src/vnet/interface.h +++ b/src/vnet/interface.h @@ -538,6 +538,9 @@ typedef struct #define VNET_SW_INTERFACE_FLAG_BOND_SLAVE (1 << 4) +/* Interface does not appear in CLI/API */ +#define VNET_SW_INTERFACE_FLAG_HIDDEN (1 << 5) + /* Index for this interface. */ u32 sw_if_index; diff --git a/src/vnet/interface_cli.c b/src/vnet/interface_cli.c index 7dbee867..bd715e4e 100644 --- a/src/vnet/interface_cli.c +++ b/src/vnet/interface_cli.c @@ -285,8 +285,9 @@ show_sw_interfaces (vlib_main_t * vm, _vec_len (sorted_sis) = 0; pool_foreach (si, im->sw_interfaces, ( { - vec_add1 (sorted_sis, si[0]); - } + if (vnet_swif_is_api_visible + (si)) vec_add1 (sorted_sis, + si[0]);} )); /* Sort by name. */ diff --git a/src/vnet/interface_format.c b/src/vnet/interface_format.c index b3a30622..b961c778 100644 --- a/src/vnet/interface_format.c +++ b/src/vnet/interface_format.c @@ -321,6 +321,7 @@ unformat_vnet_sw_interface (unformat_input_t * input, va_list * args) u32 *result = va_arg (*args, u32 *); vnet_hw_interface_t *hi; u32 hw_if_index, id, id_specified; + u32 sw_if_index; u8 *if_name = 0; uword *p, error = 0; @@ -340,14 +341,17 @@ unformat_vnet_sw_interface (unformat_input_t * input, va_list * args) hi = vnet_get_hw_interface (vnm, hw_if_index); if (!id_specified) { - *result = hi->sw_if_index; + sw_if_index = hi->sw_if_index; } else { if (!(p = hash_get (hi->sub_interface_sw_if_index_by_id, id))) - return 0; - *result = p[0]; + goto done; + sw_if_index = p[0]; } + if (!vnet_sw_interface_is_api_visible (vnm, sw_if_index)) + goto done; + *result = sw_if_index; error = 1; done: vec_free (if_name); diff --git a/src/vnet/interface_funcs.h b/src/vnet/interface_funcs.h index ab808dfa..b3aca2fd 100644 --- a/src/vnet/interface_funcs.h +++ b/src/vnet/interface_funcs.h @@ -182,6 +182,26 @@ vnet_sw_interface_is_admin_up (vnet_main_t * vnm, u32 sw_if_index) VNET_SW_INTERFACE_FLAG_ADMIN_UP) != 0; } +always_inline uword +vnet_swif_is_api_visible (vnet_sw_interface_t * si) +{ + return !(si->flags & VNET_SW_INTERFACE_FLAG_HIDDEN); +} + +always_inline uword +vnet_sw_interface_is_api_visible (vnet_main_t * vnm, u32 sw_if_index) +{ + vnet_sw_interface_t *si = vnet_get_sw_interface (vnm, sw_if_index); + return vnet_swif_is_api_visible (si); +} + +always_inline uword +vnet_sw_interface_is_api_valid (vnet_main_t * vnm, u32 sw_if_index) +{ + return !pool_is_free_index (vnm->interface_main.sw_interfaces, sw_if_index) + && vnet_sw_interface_is_api_visible (vnm, sw_if_index); +} + always_inline uword vnet_hw_interface_get_flags (vnet_main_t * vnm, u32 hw_if_index) { diff --git a/src/vnet/vxlan/vxlan.c b/src/vnet/vxlan/vxlan.c index f373a283..58c7becb 100644 --- a/src/vnet/vxlan/vxlan.c +++ b/src/vnet/vxlan/vxlan.c @@ -18,6 +18,7 @@ #include #include #include +#include #include /** @@ -462,8 +463,11 @@ int vnet_vxlan_add_del_tunnel l2im->configs[sw_if_index].feature_bitmap = L2INPUT_FEAT_DROP; l2im->configs[sw_if_index].bd_index = 0; + vnet_sw_interface_t * si = vnet_get_sw_interface (vnm, sw_if_index); + si->flags &= ~VNET_SW_INTERFACE_FLAG_HIDDEN; vnet_sw_interface_set_flags (vnm, sw_if_index, VNET_SW_INTERFACE_FLAG_ADMIN_UP); + fib_node_init(&t->node, FIB_NODE_TYPE_VXLAN_TUNNEL); fib_prefix_t tun_dst_pfx; u32 encap_index = !is_ip6 ? @@ -573,6 +577,9 @@ int vnet_vxlan_add_del_tunnel t = pool_elt_at_index (vxm->tunnels, p[0]); vnet_sw_interface_set_flags (vnm, t->sw_if_index, 0 /* down */); + vnet_sw_interface_t * si = vnet_get_sw_interface (vnm, t->sw_if_index); + si->flags |= VNET_SW_INTERFACE_FLAG_HIDDEN; + /* make sure tunnel is removed from l2 bd or xconnect */ set_int_l2_mode(vxm->vlib_main, vnm, MODE_L3, t->sw_if_index, 0, 0, 0, 0); vec_add1 (vxm->free_vxlan_tunnel_hw_if_indices, t->hw_if_index); -- cgit 1.2.3-korg From 4b919a56642ccd0a44920feace872aeb5b7a62cf Mon Sep 17 00:00:00 2001 From: Neale Ranns Date: Sat, 11 Mar 2017 05:55:21 -0800 Subject: Attached hosts allow this config to function: set int ip address loop0 169.254.1.1/32 (the default GW address for attached hosts) set int unnumbered af_packet0 use loop0 ('enable' IP on the host interface) ip route add 192.168.1.1/32 via af_packet0 (where to find the host) repeat for each host and host interface. Inter-host communication is throught the /32 routes. To allow this: 1 - attached host routes have the ATTACHED flag set, so the ARP code accepts then as legitimate sources 2 - unnumbered interfaces inherit the source address from the IP interface Change-Id: Ib66c5f0e848c528f79372813adc3a0c11b50717f Signed-off-by: Neale Ranns --- src/vnet/ethernet/arp.c | 72 +++++++++++++----- src/vnet/fib/fib_entry_src.c | 4 + src/vnet/fib/fib_path.c | 7 ++ src/vnet/fib/fib_path.h | 6 ++ src/vnet/fib/fib_table.c | 1 + src/vnet/fib/fib_types.h | 4 + src/vnet/interface_api.c | 15 ++++ src/vnet/interface_cli.c | 12 +++ test/test_neighbor.py | 176 ++++++++++++++++++++++++++++++++++++++++--- test/vpp_interface.py | 2 +- 10 files changed, 269 insertions(+), 30 deletions(-) (limited to 'src/vnet/interface_cli.c') diff --git a/src/vnet/ethernet/arp.c b/src/vnet/ethernet/arp.c index d8ae8443..75c7e203 100644 --- a/src/vnet/ethernet/arp.c +++ b/src/vnet/ethernet/arp.c @@ -1016,7 +1016,6 @@ arp_input (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) vnet_hw_interface_t *hw_if0; ethernet_arp_header_t *arp0; ethernet_header_t *eth0; - ip_adjacency_t *adj0; ip4_address_t *if_addr0, proxy_src; u32 pi0, error0, next0, sw_if_index0, conn_sw_if_index0, fib_index0; u8 is_request0, dst_is_local0, is_unnum0; @@ -1073,6 +1072,11 @@ arp_input (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) 32); dst_flags = fib_entry_get_flags (dst_fei); + src_fei = ip4_fib_table_lookup (ip4_fib_get (fib_index0), + &arp0->ip4_over_ethernet[0].ip4, + 32); + src_flags = fib_entry_get_flags (src_fei); + conn_sw_if_index0 = fib_entry_get_resolving_interface (dst_fei); if (!(FIB_ENTRY_FLAG_CONNECTED & dst_flags)) @@ -1085,11 +1089,6 @@ arp_input (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) is_unnum0 = sw_if_index0 != conn_sw_if_index0; /* Source must also be local to subnet of matching interface address. */ - src_fei = ip4_fib_table_lookup (ip4_fib_get (fib_index0), - &arp0->ip4_over_ethernet[0].ip4, - 32); - src_flags = fib_entry_get_flags (src_fei); - if (!((FIB_ENTRY_FLAG_ATTACHED & src_flags) || (FIB_ENTRY_FLAG_CONNECTED & src_flags))) { @@ -1187,25 +1186,62 @@ arp_input (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) /* get the adj from the destination's covering connected */ if (NULL == pa) { - adj0 = - adj_get (fib_entry_get_adj_for_source - (ip4_fib_table_lookup - (ip4_fib_get (fib_index0), - &arp0->ip4_over_ethernet[1].ip4, 31), - FIB_SOURCE_INTERFACE)); - if (adj0->lookup_next_index != IP_LOOKUP_NEXT_GLEAN) - { - error0 = ETHERNET_ARP_ERROR_missing_interface_address; - goto drop2; - } if (is_unnum0) { if (!arp_unnumbered (p0, pi0, eth0, conn_sw_if_index0)) goto drop2; } else - vlib_buffer_advance (p0, -adj0->rewrite_header.data_bytes); + { + ip_adjacency_t *adj0 = NULL; + adj_index_t ai; + + if (FIB_ENTRY_FLAG_ATTACHED & src_flags) + { + /* + * If the source is attached use the adj from that source. + */ + ai = fib_entry_get_adj (src_fei); + if (ADJ_INDEX_INVALID != ai) + { + adj0 = adj_get (ai); + } + } + else + { + /* + * Get the glean adj from the cover. This is presumably interface + * sourced, and therefre needs to be a glean adj. + */ + ai = fib_entry_get_adj_for_source + (ip4_fib_table_lookup + (ip4_fib_get (fib_index0), + &arp0->ip4_over_ethernet[1].ip4, 31), + FIB_SOURCE_INTERFACE); + + if (ADJ_INDEX_INVALID != ai) + { + adj0 = adj_get (ai); + + if (adj0->lookup_next_index == IP_LOOKUP_NEXT_GLEAN) + { + adj0 = NULL; + } + } + } + if (NULL != adj0) + { + vlib_buffer_advance (p0, + -adj0->rewrite_header.data_bytes); + } + else + { + error0 = ETHERNET_ARP_ERROR_missing_interface_address; + goto drop2; + } + } } + vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next, n_left_to_next, pi0, next0); diff --git a/src/vnet/fib/fib_entry_src.c b/src/vnet/fib/fib_entry_src.c index feb232df..aa1d5a24 100644 --- a/src/vnet/fib/fib_entry_src.c +++ b/src/vnet/fib/fib_entry_src.c @@ -946,6 +946,10 @@ fib_path_is_attached (const fib_route_path_t *rpath) { return (!0); } + else if (rpath->frp_flags & FIB_ROUTE_PATH_ATTACHED) + { + return (!0); + } return (0); } diff --git a/src/vnet/fib/fib_path.c b/src/vnet/fib/fib_path.c index aa545b5e..3ed309f3 100644 --- a/src/vnet/fib/fib_path.c +++ b/src/vnet/fib/fib_path.c @@ -109,6 +109,10 @@ typedef enum fib_path_oper_attribute_t_ { * The path is resolved */ FIB_PATH_OPER_ATTRIBUTE_RESOLVED, + /** + * The path is attached, despite what the next-hop may say. + */ + FIB_PATH_OPER_ATTRIBUTE_ATTACHED, /** * The path has become a permanent drop. */ @@ -143,6 +147,7 @@ typedef enum fib_path_oper_flags_t_ { FIB_PATH_OPER_FLAG_RECURSIVE_LOOP = (1 << FIB_PATH_OPER_ATTRIBUTE_RECURSIVE_LOOP), FIB_PATH_OPER_FLAG_DROP = (1 << FIB_PATH_OPER_ATTRIBUTE_DROP), FIB_PATH_OPER_FLAG_RESOLVED = (1 << FIB_PATH_OPER_ATTRIBUTE_RESOLVED), + FIB_PATH_OPER_FLAG_ATTACHED = (1 << FIB_PATH_OPER_ATTRIBUTE_ATTACHED), } __attribute__ ((packed)) fib_path_oper_flags_t; /** @@ -963,6 +968,8 @@ fib_path_route_flags_to_cfg_flags (const fib_route_path_t *rpath) cfg_flags |= FIB_PATH_CFG_FLAG_RESOLVE_ATTACHED; if (rpath->frp_flags & FIB_ROUTE_PATH_LOCAL) cfg_flags |= FIB_PATH_CFG_FLAG_LOCAL; + if (rpath->frp_flags & FIB_ROUTE_PATH_ATTACHED) + cfg_flags |= FIB_PATH_CFG_FLAG_ATTACHED; return (cfg_flags); } diff --git a/src/vnet/fib/fib_path.h b/src/vnet/fib/fib_path.h index 91f49d09..14efc1ab 100644 --- a/src/vnet/fib/fib_path.h +++ b/src/vnet/fib/fib_path.h @@ -62,6 +62,10 @@ typedef enum fib_path_cfg_attribute_t_ { * Recursion constraint via attached */ FIB_PATH_CFG_ATTRIBUTE_RESOLVE_ATTACHED, + /** + * The path is attached + */ + FIB_PATH_CFG_ATTRIBUTE_ATTACHED, /** * The path is a for-us path */ @@ -83,6 +87,7 @@ typedef enum fib_path_cfg_attribute_t_ { [FIB_PATH_CFG_ATTRIBUTE_RESOLVE_HOST] = "resolve-host", \ [FIB_PATH_CFG_ATTRIBUTE_RESOLVE_ATTACHED] = "resolve-attached", \ [FIB_PATH_CFG_ATTRIBUTE_LOCAL] = "local", \ + [FIB_PATH_CFG_ATTRIBUTE_ATTACHED] = "attached", \ } #define FOR_EACH_FIB_PATH_CFG_ATTRIBUTE(_item) \ @@ -100,6 +105,7 @@ typedef enum fib_path_cfg_flags_t_ { FIB_PATH_CFG_FLAG_RESOLVE_HOST = (1 << FIB_PATH_CFG_ATTRIBUTE_RESOLVE_HOST), FIB_PATH_CFG_FLAG_RESOLVE_ATTACHED = (1 << FIB_PATH_CFG_ATTRIBUTE_RESOLVE_ATTACHED), FIB_PATH_CFG_FLAG_LOCAL = (1 << FIB_PATH_CFG_ATTRIBUTE_LOCAL), + FIB_PATH_CFG_FLAG_ATTACHED = (1 << FIB_PATH_CFG_ATTRIBUTE_ATTACHED), } __attribute__ ((packed)) fib_path_cfg_flags_t; diff --git a/src/vnet/fib/fib_table.c b/src/vnet/fib/fib_table.c index a0ce0bbb..7818d02e 100644 --- a/src/vnet/fib/fib_table.c +++ b/src/vnet/fib/fib_table.c @@ -480,6 +480,7 @@ fib_table_route_path_fixup (const fib_prefix_t *prefix, path->frp_sw_if_index != ~0) { path->frp_addr = prefix->fp_addr; + path->frp_flags |= FIB_ROUTE_PATH_ATTACHED; } } diff --git a/src/vnet/fib/fib_types.h b/src/vnet/fib/fib_types.h index 05e0e0af..1c5299a9 100644 --- a/src/vnet/fib/fib_types.h +++ b/src/vnet/fib/fib_types.h @@ -282,6 +282,10 @@ typedef enum fib_route_path_flags_t_ * A for-us/local path */ FIB_ROUTE_PATH_LOCAL = (1 << 2), + /** + * Attached path + */ + FIB_ROUTE_PATH_ATTACHED = (1 << 3), } fib_route_path_flags_t; /** diff --git a/src/vnet/interface_api.c b/src/vnet/interface_api.c index 28b09b55..44798c8b 100644 --- a/src/vnet/interface_api.c +++ b/src/vnet/interface_api.c @@ -459,11 +459,26 @@ static void vl_api_sw_interface_set_unnumbered_t_handler { si->flags |= VNET_SW_INTERFACE_FLAG_UNNUMBERED; si->unnumbered_sw_if_index = 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[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[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; } ip4_sw_interface_enable_disable (unnumbered_sw_if_index, mp->is_add); ip6_sw_interface_enable_disable (unnumbered_sw_if_index, mp->is_add); diff --git a/src/vnet/interface_cli.c b/src/vnet/interface_cli.c index bd715e4e..ec8530da 100644 --- a/src/vnet/interface_cli.c +++ b/src/vnet/interface_cli.c @@ -864,6 +864,10 @@ set_unnumbered (vlib_main_t * vm, si->unnumbered_sw_if_index = (u32) ~ 0; ip4_sw_interface_enable_disable (unnumbered_sw_if_index, 0); ip6_sw_interface_enable_disable (unnumbered_sw_if_index, 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; } else if (is_set) { @@ -871,6 +875,14 @@ set_unnumbered (vlib_main_t * vm, si->unnumbered_sw_if_index = inherit_from_sw_if_index; ip4_sw_interface_enable_disable (unnumbered_sw_if_index, 1); ip6_sw_interface_enable_disable (unnumbered_sw_if_index, 1); + 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 + [inherit_from_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 + [inherit_from_sw_if_index]; } return 0; diff --git a/test/test_neighbor.py b/test/test_neighbor.py index a97a63fc..f2b1cfa4 100644 --- a/test/test_neighbor.py +++ b/test/test_neighbor.py @@ -44,9 +44,15 @@ class ARPTestCase(VppTestCase): def tearDown(self): super(ARPTestCase, self).tearDown() + self.pg0.unconfig_ip4() + self.pg0.unconfig_ip6() + + self.pg1.unconfig_ip4() + self.pg1.unconfig_ip6() + + self.pg3.unconfig_ip4() + for i in self.pg_interfaces: - i.unconfig_ip4() - i.unconfig_ip6() i.admin_down() def verify_arp_req(self, rx, smac, sip, dip): @@ -115,7 +121,7 @@ class ARPTestCase(VppTestCase): # # Generate some hosts on the LAN # - self.pg1.generate_remote_hosts(6) + self.pg1.generate_remote_hosts(9) # # Send IP traffic to one of these unresolved hosts. @@ -249,6 +255,47 @@ class ARPTestCase(VppTestCase): self.assertTrue(find_nbr(self, self.pg1.sw_if_index, self.pg1._remote_hosts[3].ip4)) + # + # Fire in an ARP request before the interface becomes IP enabled + # + self.pg2.generate_remote_hosts(4) + + p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) / + ARP(op="who-has", + hwsrc=self.pg2.remote_mac, + pdst=self.pg1.local_ip4, + psrc=self.pg2.remote_hosts[3].ip4)) + self.send_and_assert_no_replies(self.pg2, p, + "interface not IP enabled") + + # + # Make pg2 un-numbered to pg1 + # + self.pg2.set_unnumbered(self.pg1.sw_if_index) + + # + # We should respond to ARP requests for the unnumbered to address + # once an attached route to the source is known + # + self.send_and_assert_no_replies( + self.pg2, p, + "ARP req for unnumbered address - no source") + + attached_host = VppIpRoute(self, self.pg2.remote_hosts[3].ip4, 32, + [VppRoutePath("0.0.0.0", + self.pg2.sw_if_index)]) + attached_host.add_vpp_config() + + self.pg2.add_stream(p) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + + rx = self.pg2.get_capture(1) + self.verify_arp_resp(rx[0], + self.pg2.local_mac, + self.pg2.remote_mac, + self.pg1.local_ip4, + self.pg2.remote_hosts[3].ip4) # # A neighbor entry that has no associated FIB-entry @@ -270,12 +317,8 @@ class ARPTestCase(VppTestCase): self.pg1._remote_hosts[4].ip4, 32)) # - # Unnumbered pg2 to pg1 - # - self.pg2.set_unnumbered(self.pg1.sw_if_index) - - # - # now we can form adjacencies out of pg2 from within pg1's subnet + # pg2 is unnumbered to pg1, so we can form adjacencies out of pg2 + # from within pg1's subnet # arp_unnum = VppNeighbor(self, self.pg2.sw_if_index, @@ -301,11 +344,101 @@ class ARPTestCase(VppTestCase): self.pg0.remote_ip4, self.pg1._remote_hosts[5].ip4) + # + # ARP requests from hosts in pg1's subnet sent on pg2 are replied to + # with the unnumbered interface's address as the source + # + p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) / + ARP(op="who-has", + hwsrc=self.pg2.remote_mac, + pdst=self.pg1.local_ip4, + psrc=self.pg1.remote_hosts[6].ip4)) + + self.pg2.add_stream(p) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + + rx = self.pg2.get_capture(1) + self.verify_arp_resp(rx[0], + self.pg2.local_mac, + self.pg2.remote_mac, + self.pg1.local_ip4, + self.pg1.remote_hosts[6].ip4) + + # + # An attached host route out of pg2 for an undiscovered hosts generates + # an ARP request with the unnumbered address as the source + # + att_unnum = VppIpRoute(self, self.pg1.remote_hosts[7].ip4, 32, + [VppRoutePath("0.0.0.0", + self.pg2.sw_if_index)]) + att_unnum.add_vpp_config() + + p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / + IP(src=self.pg0.remote_ip4, + dst=self.pg1._remote_hosts[7].ip4) / + UDP(sport=1234, dport=1234) / + Raw()) + + self.pg0.add_stream(p) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + + rx = self.pg2.get_capture(1) + + self.verify_arp_req(rx[0], + self.pg2.local_mac, + self.pg1.local_ip4, + self.pg1._remote_hosts[7].ip4) + + p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) / + ARP(op="who-has", + hwsrc=self.pg2.remote_mac, + pdst=self.pg1.local_ip4, + psrc=self.pg1.remote_hosts[7].ip4)) + + self.pg2.add_stream(p) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + + rx = self.pg2.get_capture(1) + self.verify_arp_resp(rx[0], + self.pg2.local_mac, + self.pg2.remote_mac, + self.pg1.local_ip4, + self.pg1.remote_hosts[7].ip4) + + # + # An attached host route as yet unresolved out of pg2 for an + # undiscovered host, an ARP requests begets a response. + # + att_unnum1 = VppIpRoute(self, self.pg1.remote_hosts[8].ip4, 32, + [VppRoutePath("0.0.0.0", + self.pg2.sw_if_index)]) + att_unnum1.add_vpp_config() + + p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) / + ARP(op="who-has", + hwsrc=self.pg2.remote_mac, + pdst=self.pg1.local_ip4, + psrc=self.pg1.remote_hosts[8].ip4)) + + self.pg2.add_stream(p) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + + rx = self.pg2.get_capture(1) + self.verify_arp_resp(rx[0], + self.pg2.local_mac, + self.pg2.remote_mac, + self.pg1.local_ip4, + self.pg1.remote_hosts[8].ip4) + # # ERROR Cases # 1 - don't respond to ARP request for address not within the # interface's sub-net - # + # 1a - nor within the unnumbered subnet p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) / ARP(op="who-has", hwsrc=self.pg0.remote_mac, @@ -313,6 +446,14 @@ class ARPTestCase(VppTestCase): psrc=self.pg0.remote_ip4)) self.send_and_assert_no_replies(self.pg0, p, "ARP req for non-local destination") + p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) / + ARP(op="who-has", + hwsrc=self.pg2.remote_mac, + pdst="10.10.10.3", + psrc=self.pg1.remote_hosts[7].ip4)) + self.send_and_assert_no_replies( + self.pg0, p, + "ARP req for non-local destination - unnum") # # 2 - don't respond to ARP request from an address not within the @@ -325,6 +466,14 @@ class ARPTestCase(VppTestCase): pdst=self.pg0.local_ip4)) self.send_and_assert_no_replies(self.pg0, p, "ARP req for non-local source") + p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) / + ARP(op="who-has", + hwsrc=self.pg2.remote_mac, + psrc="10.10.10.3", + pdst=self.pg0.local_ip4)) + self.send_and_assert_no_replies( + self.pg0, p, + "ARP req for non-local source - unnum") # # 3 - don't respond to ARP request from an address that belongs to @@ -358,6 +507,10 @@ class ARPTestCase(VppTestCase): static_arp.remove_vpp_config() self.pg2.unset_unnumbered(self.pg1.sw_if_index) + # need this to flush the adj-fibs + self.pg2.unset_unnumbered(self.pg1.sw_if_index) + self.pg2.admin_down() + def test_proxy_arp(self): """ Proxy ARP """ @@ -500,7 +653,7 @@ class ARPTestCase(VppTestCase): # # clean up on interface 2 # - self.pg2.set_unnumbered(self.pg1.sw_if_index) + self.pg2.unset_unnumbered(self.pg1.sw_if_index) def test_mpls(self): """ MPLS """ @@ -560,6 +713,7 @@ class ARPTestCase(VppTestCase): 55, self.pg0.remote_ip4, "10.0.0.1") + self.pg2.unconfig_ip4() if __name__ == '__main__': unittest.main(testRunner=VppTestRunner) diff --git a/test/vpp_interface.py b/test/vpp_interface.py index 8135bc84..aeaf27a8 100644 --- a/test/vpp_interface.py +++ b/test/vpp_interface.py @@ -336,7 +336,7 @@ class VppInterface(object): ip_sw_if_index) def unset_unnumbered(self, ip_sw_if_index): - """ Unaet the interface to unnumbered via ip_sw_if_index """ + """ Unset the interface to unnumbered via ip_sw_if_index """ self.test.vapi.sw_interface_set_unnumbered( self.sw_if_index, ip_sw_if_index, -- cgit 1.2.3-korg From 898273fbb588811824bb27ad0ef203d358a7121a Mon Sep 17 00:00:00 2001 From: Neale Ranns Date: Sat, 18 Mar 2017 02:57:38 -0700 Subject: Check change in unnumbered setting before updating IP enabled state Change-Id: I6424a083ec889961ba4d0cd1df8348f20436be14 Signed-off-by: Neale Ranns --- src/vnet/interface_api.c | 10 ++++++++-- src/vnet/interface_cli.c | 19 +++++++++++++++---- 2 files changed, 23 insertions(+), 6 deletions(-) (limited to 'src/vnet/interface_cli.c') diff --git a/src/vnet/interface_api.c b/src/vnet/interface_api.c index 44798c8b..39c06271 100644 --- a/src/vnet/interface_api.c +++ b/src/vnet/interface_api.c @@ -433,6 +433,7 @@ static void vl_api_sw_interface_set_unnumbered_t_handler vnet_main_t *vnm = vnet_get_main (); u32 sw_if_index = ntohl (mp->sw_if_index); u32 unnumbered_sw_if_index = ntohl (mp->unnumbered_sw_if_index); + u32 was_unnum; /* * The API message field names are backwards from @@ -454,6 +455,7 @@ static void vl_api_sw_interface_set_unnumbered_t_handler vnet_sw_interface_t *si = vnet_get_sw_interface (vnm, unnumbered_sw_if_index); + was_unnum = (si->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED); if (mp->is_add) { @@ -480,8 +482,12 @@ static void vl_api_sw_interface_set_unnumbered_t_handler ip6_main.lookup_main.if_address_pool_index_by_sw_if_index [unnumbered_sw_if_index] = ~0; } - ip4_sw_interface_enable_disable (unnumbered_sw_if_index, mp->is_add); - ip6_sw_interface_enable_disable (unnumbered_sw_if_index, mp->is_add); + + if (was_unnum != (si->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED)) + { + ip4_sw_interface_enable_disable (unnumbered_sw_if_index, mp->is_add); + ip6_sw_interface_enable_disable (unnumbered_sw_if_index, mp->is_add); + } done: REPLY_MACRO (VL_API_SW_INTERFACE_SET_UNNUMBERED_REPLY); diff --git a/src/vnet/interface_cli.c b/src/vnet/interface_cli.c index ec8530da..c1566551 100644 --- a/src/vnet/interface_cli.c +++ b/src/vnet/interface_cli.c @@ -844,6 +844,7 @@ set_unnumbered (vlib_main_t * vm, vnet_sw_interface_t *si; int is_set = 0; int is_del = 0; + u32 was_unnum; if (unformat (input, "%U use %U", unformat_vnet_sw_interface, vnm, &unnumbered_sw_if_index, @@ -858,12 +859,13 @@ set_unnumbered (vlib_main_t * vm, format_unformat_error, input); si = vnet_get_sw_interface (vnm, unnumbered_sw_if_index); + was_unnum = (si->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED); + if (is_del) { si->flags &= ~(VNET_SW_INTERFACE_FLAG_UNNUMBERED); si->unnumbered_sw_if_index = (u32) ~ 0; - ip4_sw_interface_enable_disable (unnumbered_sw_if_index, 0); - ip6_sw_interface_enable_disable (unnumbered_sw_if_index, 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 @@ -873,8 +875,7 @@ set_unnumbered (vlib_main_t * vm, { si->flags |= VNET_SW_INTERFACE_FLAG_UNNUMBERED; si->unnumbered_sw_if_index = inherit_from_sw_if_index; - ip4_sw_interface_enable_disable (unnumbered_sw_if_index, 1); - ip6_sw_interface_enable_disable (unnumbered_sw_if_index, 1); + 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 @@ -884,6 +885,16 @@ set_unnumbered (vlib_main_t * vm, ip6_main.lookup_main.if_address_pool_index_by_sw_if_index [inherit_from_sw_if_index]; } + else + { + return (0); + } + + if (was_unnum != (si->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED)) + { + ip4_sw_interface_enable_disable (unnumbered_sw_if_index, !is_del); + ip6_sw_interface_enable_disable (unnumbered_sw_if_index, !is_del); + } return 0; } -- cgit 1.2.3-korg From 13ad1f02922858177915b1cb1450041d2e4d85de Mon Sep 17 00:00:00 2001 From: Dave Barach Date: Sun, 26 Mar 2017 19:36:18 -0400 Subject: Rename "show interfaces" -> "show interface" To line up with "show interface placement," recently added. Otherwise, "show int" refers only to "show interface placement," which tends to annoy the cash customers... Change-Id: Iea9e3681aeb051e2b0e1ecbf06706d98af9a3abf Signed-off-by: Dave Barach --- src/vnet/devices/af_packet/cli.c | 2 +- src/vnet/devices/virtio/vhost-user.c | 2 +- src/vnet/interface_cli.c | 4 ++-- src/vnet/span/span.c | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) (limited to 'src/vnet/interface_cli.c') diff --git a/src/vnet/devices/af_packet/cli.c b/src/vnet/devices/af_packet/cli.c index d4aa7016..44dc5179 100644 --- a/src/vnet/devices/af_packet/cli.c +++ b/src/vnet/devices/af_packet/cli.c @@ -113,7 +113,7 @@ done: * exist. Once created, a new host interface will exist in VPP * with the name 'host-', where '' * is the name of the specified veth pair. Use the - * 'show interfaces' command to display host interface details. + * 'show interface' command to display host interface details. * * This command has the following optional parameters: * diff --git a/src/vnet/devices/virtio/vhost-user.c b/src/vnet/devices/virtio/vhost-user.c index 5a5beb15..5ad4cb62 100644 --- a/src/vnet/devices/virtio/vhost-user.c +++ b/src/vnet/devices/virtio/vhost-user.c @@ -3408,7 +3408,7 @@ VLIB_CLI_COMMAND (vhost_user_connect_command, static) = { /*? * Delete a vHost User interface using the interface name or the - * software interface index. Use the 'show interfaces' + * software interface index. Use the 'show interface' * command to determine the software interface index. On deletion, * the linux socket will not be deleted. * diff --git a/src/vnet/interface_cli.c b/src/vnet/interface_cli.c index c1566551..5640966c 100644 --- a/src/vnet/interface_cli.c +++ b/src/vnet/interface_cli.c @@ -416,8 +416,8 @@ done: /* *INDENT-OFF* */ VLIB_CLI_COMMAND (show_sw_interfaces_command, static) = { - .path = "show interfaces", - .short_help = "show interfaces [address|addr|features|feat] [ ...]", + .path = "show interface", + .short_help = "show interface [address|addr|features|feat] [ ...]", .function = show_sw_interfaces, }; /* *INDENT-ON* */ diff --git a/src/vnet/span/span.c b/src/vnet/span/span.c index bc244eff..c5b43e34 100644 --- a/src/vnet/span/span.c +++ b/src/vnet/span/span.c @@ -169,7 +169,7 @@ show_interfaces_span_command_fn (vlib_main_t * vm, /* *INDENT-OFF* */ VLIB_CLI_COMMAND (show_interfaces_span_command, static) = { - .path = "show interfaces span", + .path = "show interface span", .short_help = "Shows SPAN mirror table", .function = show_interfaces_span_command_fn, }; -- cgit 1.2.3-korg From 2c0d0fed47ada96346aa97c30de6fddf462d9a59 Mon Sep 17 00:00:00 2001 From: Neale Ranns Date: Wed, 29 Mar 2017 09:34:10 -0700 Subject: Coverity Error: logically dead code in IP unnumbered CLI Change-Id: Id3398bd4b7a56c168aaab37942b92715e19d4025 Signed-off-by: Neale Ranns --- src/vnet/interface_cli.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'src/vnet/interface_cli.c') diff --git a/src/vnet/interface_cli.c b/src/vnet/interface_cli.c index 5640966c..b17072af 100644 --- a/src/vnet/interface_cli.c +++ b/src/vnet/interface_cli.c @@ -885,10 +885,6 @@ set_unnumbered (vlib_main_t * vm, ip6_main.lookup_main.if_address_pool_index_by_sw_if_index [inherit_from_sw_if_index]; } - else - { - return (0); - } if (was_unnum != (si->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED)) { -- cgit 1.2.3-korg From 3ef16710dc33b5b27730ced10008e2a69f81e147 Mon Sep 17 00:00:00 2001 From: Ray Kinsella Date: Thu, 27 Apr 2017 09:57:00 +0100 Subject: vnet: update help message for intfc state Add useful help information on set interface state. Change-Id: Ibcdcea2849ccaee4cc72bf38d79102beb0d4be11 Signed-off-by: Ray Kinsella --- src/vnet/interface_cli.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/vnet/interface_cli.c') diff --git a/src/vnet/interface_cli.c b/src/vnet/interface_cli.c index b17072af..94eb7ea9 100644 --- a/src/vnet/interface_cli.c +++ b/src/vnet/interface_cli.c @@ -829,7 +829,7 @@ done: ?*/ VLIB_CLI_COMMAND (set_state_command, static) = { .path = "set interface state", - .short_help = "Set interface state", + .short_help = "set interface state [up|down|punt|enable]", .function = set_state, }; /* *INDENT-ON* */ -- cgit 1.2.3-korg From 4403690cda44134af3b9ea78d33a5cbf78a5acc9 Mon Sep 17 00:00:00 2001 From: Damjan Marion Date: Fri, 28 Apr 2017 12:29:15 +0200 Subject: Add interface rx mode commands, unify rx mode and placement CLI Change-Id: Ib506c3e9d66170f29e3266ad6dc4d32b829befba Signed-off-by: Damjan Marion --- src/plugins/dpdk/device/init.c | 10 +- src/vnet/api_errno.h | 3 +- src/vnet/devices/af_packet/af_packet.c | 18 ++- src/vnet/devices/devices.c | 172 +++--------------------- src/vnet/devices/devices.h | 34 ++--- src/vnet/interface.h | 15 +++ src/vnet/interface_cli.c | 238 +++++++++++++++++++++++++++++++++ src/vnet/interface_format.c | 17 +++ src/vnet/interface_funcs.h | 1 + 9 files changed, 326 insertions(+), 182 deletions(-) (limited to 'src/vnet/interface_cli.c') diff --git a/src/plugins/dpdk/device/init.c b/src/plugins/dpdk/device/init.c index 6f51ff64..2d21bfd9 100755 --- a/src/plugins/dpdk/device/init.c +++ b/src/plugins/dpdk/device/init.c @@ -704,8 +704,8 @@ dpdk_lib_init (dpdk_main_t * dm) sw = vnet_get_hw_sw_interface (dm->vnet_main, xd->hw_if_index); xd->vlib_sw_if_index = sw->sw_if_index; - vnet_set_device_input_node (dm->vnet_main, xd->hw_if_index, - dpdk_input_node.index); + vnet_hw_interface_set_input_node (dm->vnet_main, xd->hw_if_index, + dpdk_input_node.index); if (devconf->workers) { @@ -713,7 +713,7 @@ dpdk_lib_init (dpdk_main_t * dm) q = 0; /* *INDENT-OFF* */ clib_bitmap_foreach (i, devconf->workers, ({ - vnet_device_input_assign_thread (dm->vnet_main, xd->hw_if_index, q++, + vnet_hw_interface_assign_rx_thread (dm->vnet_main, xd->hw_if_index, q++, vdm->first_worker_thread_index + i); })); /* *INDENT-ON* */ @@ -721,8 +721,8 @@ dpdk_lib_init (dpdk_main_t * dm) else for (q = 0; q < xd->rx_q_used; q++) { - vnet_device_input_assign_thread (dm->vnet_main, xd->hw_if_index, q, /* any */ - ~1); + vnet_hw_interface_assign_rx_thread (dm->vnet_main, xd->hw_if_index, q, /* any */ + ~1); } hi = vnet_get_hw_interface (dm->vnet_main, xd->hw_if_index); diff --git a/src/vnet/api_errno.h b/src/vnet/api_errno.h index 0d5b2227..b87c197f 100644 --- a/src/vnet/api_errno.h +++ b/src/vnet/api_errno.h @@ -109,7 +109,8 @@ _(ENTRY_ALREADY_EXISTS, -116, "Entry already exists") \ _(SVM_SEGMENT_CREATE_FAIL, -117, "svm segment create fail") \ _(APPLICATION_NOT_ATTACHED, -118, "application not attached") \ _(BD_ALREADY_EXISTS, -119, "Bridge domain already exists") \ -_(BD_IN_USE, -120, "Bridge domain has member interfaces") +_(BD_IN_USE, -120, "Bridge domain has member interfaces") \ +_(UNSUPPORTED, -121, "Unsupported") typedef enum { diff --git a/src/vnet/devices/af_packet/af_packet.c b/src/vnet/devices/af_packet/af_packet.c index 92bd1092..cb52e6da 100644 --- a/src/vnet/devices/af_packet/af_packet.c +++ b/src/vnet/devices/af_packet/af_packet.c @@ -195,6 +195,7 @@ af_packet_create_if (vlib_main_t * vm, u8 * host_if_name, u8 * hw_addr_set, u8 hw_addr[6]; clib_error_t *error; vnet_sw_interface_t *sw; + vnet_hw_interface_t *hw; vlib_thread_main_t *tm = vlib_get_thread_main (); vnet_main_t *vnm = vnet_get_main (); uword *p; @@ -294,17 +295,21 @@ af_packet_create_if (vlib_main_t * vm, u8 * host_if_name, u8 * hw_addr_set, } sw = vnet_get_hw_sw_interface (vnm, apif->hw_if_index); + hw = vnet_get_hw_interface (vnm, apif->hw_if_index); apif->sw_if_index = sw->sw_if_index; - vnet_set_device_input_node (vnm, apif->hw_if_index, - af_packet_input_node.index); - vnet_device_input_assign_thread (vnm, apif->hw_if_index, 0, /* queue */ - ~0 /* any cpu */ ); - vnet_device_input_set_mode (vnm, apif->hw_if_index, 0, - VNET_DEVICE_INPUT_MODE_INTERRUPT); + vnet_hw_interface_set_input_node (vnm, apif->hw_if_index, + af_packet_input_node.index); + vnet_hw_interface_assign_rx_thread (vnm, apif->hw_if_index, 0, /* queue */ + ~0 /* any cpu */ ); + + hw->flags |= VNET_HW_INTERFACE_FLAG_SUPPORTS_INT_MODE; vnet_hw_interface_set_flags (vnm, apif->hw_if_index, VNET_HW_INTERFACE_FLAG_LINK_UP); + vnet_hw_interface_set_rx_mode (vnm, apif->hw_if_index, 0, + VNET_HW_INTERFACE_RX_MODE_INTERRUPT); + mhash_set_mem (&apm->if_index_by_host_if_name, host_if_name_dup, &if_index, 0); if (sw_if_index) @@ -340,6 +345,7 @@ af_packet_delete_if (vlib_main_t * vm, u8 * host_if_name) /* bring down the interface */ vnet_hw_interface_set_flags (vnm, apif->hw_if_index, 0); + vnet_hw_interface_unassign_rx_thread (vnm, apif->hw_if_index, 0); /* clean up */ if (apif->unix_file_index != ~0) diff --git a/src/vnet/devices/devices.c b/src/vnet/devices/devices.c index 2f55adcb..d75d905a 100644 --- a/src/vnet/devices/devices.c +++ b/src/vnet/devices/devices.c @@ -119,8 +119,8 @@ vnet_device_queue_update (vnet_main_t * vnm, vnet_device_input_runtime_t * rt) } void -vnet_device_input_assign_thread (vnet_main_t * vnm, u32 hw_if_index, - u16 queue_id, uword thread_index) +vnet_hw_interface_assign_rx_thread (vnet_main_t * vnm, u32 hw_if_index, + u16 queue_id, uword thread_index) { vnet_device_main_t *vdm = &vnet_device_main; vlib_main_t *vm; @@ -149,16 +149,19 @@ vnet_device_input_assign_thread (vnet_main_t * vnm, u32 hw_if_index, dq->hw_if_index = hw_if_index; dq->dev_instance = hw->dev_instance; dq->queue_id = queue_id; + dq->mode = VNET_HW_INTERFACE_RX_MODE_POLLING; vnet_device_queue_update (vnm, rt); vec_validate (hw->input_node_thread_index_by_queue, queue_id); + vec_validate (hw->rx_mode_by_queue, queue_id); hw->input_node_thread_index_by_queue[queue_id] = thread_index; + hw->rx_mode_by_queue[queue_id] = VNET_HW_INTERFACE_RX_MODE_POLLING; vlib_node_set_state (vm, hw->input_node_index, rt->enabled_node_state); } int -vnet_device_input_unassign_thread (vnet_main_t * vnm, u32 hw_if_index, - u16 queue_id, uword thread_index) +vnet_hw_interface_unassign_rx_thread (vnet_main_t * vnm, u32 hw_if_index, + u16 queue_id) { vlib_main_t *vm; vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, hw_if_index); @@ -190,6 +193,7 @@ vnet_device_input_unassign_thread (vnet_main_t * vnm, u32 hw_if_index, deleted: vnet_device_queue_update (vnm, rt); + hw->rx_mode_by_queue[queue_id] = VNET_HW_INTERFACE_RX_MODE_UNKNOWN; if (vec_len (rt->devices_and_queues) == 0) vlib_node_set_state (vm, hw->input_node_index, VLIB_NODE_STATE_DISABLED); @@ -199,21 +203,28 @@ deleted: int -vnet_device_input_set_mode (vnet_main_t * vnm, u32 hw_if_index, u16 queue_id, - vnet_device_input_mode_t mode) +vnet_hw_interface_set_rx_mode (vnet_main_t * vnm, u32 hw_if_index, + u16 queue_id, vnet_hw_interface_rx_mode mode) { vlib_main_t *vm; uword thread_index; vnet_device_and_queue_t *dq; vlib_node_state_t enabled_node_state; - ASSERT (mode < VNET_DEVICE_INPUT_N_MODES); + ASSERT (mode < VNET_HW_INTERFACE_NUM_RX_MODES); vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, hw_if_index); vnet_device_input_runtime_t *rt; int is_polling = 0; - if (hw->input_node_thread_index_by_queue == 0) + if (hw->input_node_thread_index_by_queue == 0 || hw->rx_mode_by_queue == 0) return VNET_API_ERROR_INVALID_INTERFACE; + if (hw->rx_mode_by_queue[queue_id] == mode) + return 0; + + if (mode != VNET_HW_INTERFACE_RX_MODE_POLLING && + (hw->flags & VNET_HW_INTERFACE_FLAG_SUPPORTS_INT_MODE) == 0) + return VNET_API_ERROR_UNSUPPORTED; + thread_index = hw->input_node_thread_index_by_queue[queue_id]; vm = vlib_mains[thread_index]; @@ -223,7 +234,7 @@ vnet_device_input_set_mode (vnet_main_t * vnm, u32 hw_if_index, u16 queue_id, { if (dq->hw_if_index == hw_if_index && dq->queue_id == queue_id) dq->mode = mode; - if (dq->mode == VNET_DEVICE_INPUT_MODE_POLLING) + if (dq->mode == VNET_HW_INTERFACE_RX_MODE_POLLING) is_polling = 1; } @@ -244,8 +255,8 @@ vnet_device_input_set_mode (vnet_main_t * vnm, u32 hw_if_index, u16 queue_id, } int -vnet_device_input_get_mode (vnet_main_t * vnm, u32 hw_if_index, u16 queue_id, - vnet_device_input_mode_t * mode) +vnet_hw_interface_get_rx_mode (vnet_main_t * vnm, u32 hw_if_index, + u16 queue_id, vnet_hw_interface_rx_mode * mode) { vlib_main_t *vm; uword thread_index; @@ -271,146 +282,7 @@ vnet_device_input_get_mode (vnet_main_t * vnm, u32 hw_if_index, u16 queue_id, return VNET_API_ERROR_INVALID_INTERFACE; } -static clib_error_t * -show_device_placement_fn (vlib_main_t * vm, unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - u8 *s = 0; - vnet_main_t *vnm = vnet_get_main (); - vnet_device_input_runtime_t *rt; - vnet_device_and_queue_t *dq; - vlib_node_t *pn = vlib_get_node_by_name (vm, (u8 *) "device-input"); - uword si; - int index = 0; - - /* *INDENT-OFF* */ - foreach_vlib_main (({ - clib_bitmap_foreach (si, pn->sibling_bitmap, - ({ - rt = vlib_node_get_runtime_data (this_vlib_main, si); - - if (vec_len (rt->devices_and_queues)) - s = format (s, " node %U:\n", format_vlib_node_name, vm, si); - - vec_foreach (dq, rt->devices_and_queues) - { - s = format (s, " %U queue %u (%s)\n", - format_vnet_sw_if_index_name, vnm, dq->hw_if_index, - dq->queue_id, - dq->mode == VNET_DEVICE_INPUT_MODE_POLLING ? - "polling" : "interrupt"); - } - })); - if (vec_len (s) > 0) - { - vlib_cli_output(vm, "Thread %u (%v):\n%v", index, - vlib_worker_threads[index].name, s); - vec_reset_length (s); - } - index++; - })); - /* *INDENT-ON* */ - - vec_free (s); - return 0; -} - -/* *INDENT-OFF* */ -VLIB_CLI_COMMAND (memif_delete_command, static) = { - .path = "show interface placement", - .short_help = "show interface placement", - .function = show_device_placement_fn, -}; -/* *INDENT-ON* */ - -static clib_error_t * -set_device_placement (vlib_main_t * vm, unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - clib_error_t *error = 0; - unformat_input_t _line_input, *line_input = &_line_input; - vnet_main_t *vnm = vnet_get_main (); - vnet_device_main_t *vdm = &vnet_device_main; - vnet_device_input_mode_t mode; - u32 hw_if_index = (u32) ~ 0; - u32 queue_id = (u32) 0; - u32 thread_index = (u32) ~ 0; - int rv; - - if (!unformat_user (input, unformat_line_input, line_input)) - return 0; - - while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) - { - if (unformat - (line_input, "%U", unformat_vnet_hw_interface, vnm, &hw_if_index)) - ; - else if (unformat (line_input, "queue %d", &queue_id)) - ; - else if (unformat (line_input, "main", &thread_index)) - thread_index = 0; - else if (unformat (line_input, "worker %d", &thread_index)) - thread_index += vdm->first_worker_thread_index; - else - { - error = clib_error_return (0, "parse error: '%U'", - format_unformat_error, line_input); - unformat_free (line_input); - return error; - } - } - - unformat_free (line_input); - - if (hw_if_index == (u32) ~ 0) - return clib_error_return (0, "please specify valid interface name"); - - if (thread_index > vdm->last_worker_thread_index) - return clib_error_return (0, - "please specify valid worker thread or main"); - - rv = vnet_device_input_get_mode (vnm, hw_if_index, queue_id, &mode); - - if (rv) - return clib_error_return (0, "not found"); - - rv = vnet_device_input_unassign_thread (vnm, hw_if_index, queue_id, - thread_index); - if (rv) - return clib_error_return (0, "not found"); - - vnet_device_input_assign_thread (vnm, hw_if_index, queue_id, thread_index); - vnet_device_input_set_mode (vnm, hw_if_index, queue_id, mode); - - return 0; -} - -/*? - * This command is used to assign a given interface, and optionally a - * given queue, to a different thread. If the 'queue' is not provided, - * it defaults to 0. - * - * @cliexpar - * Example of how to display the interface placement: - * @cliexstart{show interface placement} - * Thread 1 (vpp_wk_0): - * GigabitEthernet0/8/0 queue 0 - * GigabitEthernet0/9/0 queue 0 - * Thread 2 (vpp_wk_1): - * GigabitEthernet0/8/0 queue 1 - * GigabitEthernet0/9/0 queue 1 - * @cliexend - * Example of how to assign a interface and queue to a thread: - * @cliexcmd{set interface placement GigabitEthernet0/8/0 queue 1 thread 1} -?*/ -/* *INDENT-OFF* */ -VLIB_CLI_COMMAND (cmd_set_dpdk_if_placement,static) = { - .path = "set interface placement", - .short_help = "set interface placement [queue ] [thread | main]", - .function = set_device_placement, -}; -/* *INDENT-ON* */ static clib_error_t * vnet_device_init (vlib_main_t * vm) diff --git a/src/vnet/devices/devices.h b/src/vnet/devices/devices.h index baf03b7c..f1f7e778 100644 --- a/src/vnet/devices/devices.h +++ b/src/vnet/devices/devices.h @@ -55,19 +55,12 @@ typedef struct uword next_worker_thread_index; } vnet_device_main_t; -typedef enum -{ - VNET_DEVICE_INPUT_MODE_POLLING = 0, - VNET_DEVICE_INPUT_MODE_INTERRUPT, - VNET_DEVICE_INPUT_N_MODES, -} vnet_device_input_mode_t; - typedef struct { u32 hw_if_index; u32 dev_instance; u16 queue_id; - vnet_device_input_mode_t mode; + vnet_hw_interface_rx_mode mode; uword interrupt_pending; } vnet_device_and_queue_t; @@ -82,22 +75,23 @@ extern vlib_node_registration_t device_input_node; extern const u32 device_input_next_node_advance[]; static inline void -vnet_set_device_input_node (vnet_main_t * vnm, u32 hw_if_index, - u32 node_index) +vnet_hw_interface_set_input_node (vnet_main_t * vnm, u32 hw_if_index, + u32 node_index) { vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, hw_if_index); hw->input_node_index = node_index; } -void vnet_device_input_assign_thread (vnet_main_t * vnm, u32 hw_if_index, - u16 queue_id, uword thread_index); -int vnet_device_input_unassign_thread (vnet_main_t * vnm, u32 hw_if_index, - u16 queue_id, uword thread_index); -int vnet_device_input_set_mode (vnet_main_t * vnm, u32 hw_if_index, - u16 queue_id, vnet_device_input_mode_t mode); -int vnet_device_input_get_mode (vnet_main_t * vnm, u32 hw_if_index, - u16 queue_id, - vnet_device_input_mode_t * mode); +void vnet_hw_interface_assign_rx_thread (vnet_main_t * vnm, u32 hw_if_index, + u16 queue_id, uword thread_index); +int vnet_hw_interface_unassign_rx_thread (vnet_main_t * vnm, u32 hw_if_index, + u16 queue_id); +int vnet_hw_interface_set_rx_mode (vnet_main_t * vnm, u32 hw_if_index, + u16 queue_id, + vnet_hw_interface_rx_mode mode); +int vnet_hw_interface_get_rx_mode (vnet_main_t * vnm, u32 hw_if_index, + u16 queue_id, + vnet_hw_interface_rx_mode * mode); static inline u64 vnet_get_aggregate_rx_packets (void) @@ -161,7 +155,7 @@ vnet_device_input_set_interrupt_pending (vnet_main_t * vnm, u32 hw_if_index, #define foreach_device_and_queue(var,vec) \ for (var = (vec); var < vec_end (vec); var++) \ if (clib_smp_swap (&((var)->interrupt_pending), 0) || \ - var->mode == VNET_DEVICE_INPUT_MODE_POLLING) + var->mode == VNET_HW_INTERFACE_RX_MODE_POLLING) #endif /* included_vnet_vnet_device_h */ diff --git a/src/vnet/interface.h b/src/vnet/interface.h index 9c223040..2344348b 100644 --- a/src/vnet/interface.h +++ b/src/vnet/interface.h @@ -405,6 +405,9 @@ typedef struct vnet_hw_interface_t #define VNET_HW_INTERFACE_FLAG_L2OUTPUT_SHIFT 9 #define VNET_HW_INTERFACE_FLAG_L2OUTPUT_MAPPED (1 << 9) + /* rx mode flags */ +#define VNET_HW_INTERFACE_FLAG_SUPPORTS_INT_MODE (1 << 10) + /* Hardware address as vector. Zero (e.g. zero-length vector) if no address for this class (e.g. PPP). */ u8 *hw_address; @@ -470,6 +473,9 @@ typedef struct vnet_hw_interface_t /* input node cpu index by queue */ u32 *input_node_thread_index_by_queue; + /* vnet_hw_interface_rx_mode by queue */ + u8 *rx_mode_by_queue; + /* device input device_and_queue runtime index */ uword *dq_runtime_index_by_queue; @@ -486,6 +492,15 @@ typedef enum VNET_SW_INTERFACE_TYPE_SUB, } vnet_sw_interface_type_t; +typedef enum +{ + VNET_HW_INTERFACE_RX_MODE_UNKNOWN, + VNET_HW_INTERFACE_RX_MODE_POLLING, + VNET_HW_INTERFACE_RX_MODE_INTERRUPT, + VNET_HW_INTERFACE_RX_MODE_ADAPTIVE, + VNET_HW_INTERFACE_NUM_RX_MODES, +} vnet_hw_interface_rx_mode; + typedef struct { /* diff --git a/src/vnet/interface_cli.c b/src/vnet/interface_cli.c index 94eb7ea9..bfce03e1 100644 --- a/src/vnet/interface_cli.c +++ b/src/vnet/interface_cli.c @@ -1175,7 +1175,245 @@ VLIB_CLI_COMMAND (clear_tag_command, static) = { }; /* *INDENT-ON* */ +static clib_error_t * +set_interface_rx_mode (vlib_main_t * vm, unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + clib_error_t *error = 0; + unformat_input_t _line_input, *line_input = &_line_input; + vnet_main_t *vnm = vnet_get_main (); + vnet_hw_interface_t *hw; + u32 hw_if_index = (u32) ~ 0; + u32 queue_id = (u32) ~ 0; + vnet_hw_interface_rx_mode mode = VNET_HW_INTERFACE_RX_MODE_UNKNOWN; + int i, rv = 0; + + if (!unformat_user (input, unformat_line_input, line_input)) + return 0; + + while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) + { + if (unformat + (line_input, "%U", unformat_vnet_hw_interface, vnm, &hw_if_index)) + ; + else if (unformat (line_input, "queue %d", &queue_id)) + ; + else if (unformat (line_input, "polling")) + mode = VNET_HW_INTERFACE_RX_MODE_POLLING; + else if (unformat (line_input, "interrupt")) + mode = VNET_HW_INTERFACE_RX_MODE_INTERRUPT; + else if (unformat (line_input, "adaptive")) + mode = VNET_HW_INTERFACE_RX_MODE_ADAPTIVE; + else + { + error = clib_error_return (0, "parse error: '%U'", + format_unformat_error, line_input); + unformat_free (line_input); + return error; + } + } + + unformat_free (line_input); + + if (hw_if_index == (u32) ~ 0) + return clib_error_return (0, "please specify valid interface name"); + if (mode == VNET_HW_INTERFACE_RX_MODE_UNKNOWN) + return clib_error_return (0, "please specify valid rx-mode"); + + hw = vnet_get_hw_interface (vnm, hw_if_index); + + if (queue_id == ~0) + for (i = 0; i < vec_len (hw->dq_runtime_index_by_queue); i++) + { + rv = vnet_hw_interface_set_rx_mode (vnm, hw_if_index, i, mode); + if (rv) + goto error; + } + else + rv = vnet_hw_interface_set_rx_mode (vnm, hw_if_index, queue_id, mode); + + if (rv) + goto error; + + return 0; + +error: + if (rv == VNET_API_ERROR_UNSUPPORTED) + return clib_error_return (0, "unsupported"); + + if (rv == VNET_API_ERROR_INVALID_INTERFACE) + return clib_error_return (0, "invalid interfaace"); + + return clib_error_return (0, "unknown error"); +} + +/*? + * This command is used to assign a given interface, and optionally a + * given queue, to a different thread. If the 'queue' is not provided, + * it defaults to 0. + * + * @cliexpar + * Example of how to display the interface placement: + * @cliexstart{show interface rx-placement} + * Thread 1 (vpp_wk_0): + * GigabitEthernet0/8/0 queue 0 + * GigabitEthernet0/9/0 queue 0 + * Thread 2 (vpp_wk_1): + * GigabitEthernet0/8/0 queue 1 + * GigabitEthernet0/9/0 queue 1 + * @cliexend + * Example of how to assign a interface and queue to a thread: + * @cliexcmd{set interface placement GigabitEthernet0/8/0 queue 1 thread 1} +?*/ +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (cmd_set_if_rx_mode,static) = { + .path = "set interface rx-mode", + .short_help = "set interface rx-mode [queue ] [polling | interrupt | adaptive]", + .function = set_interface_rx_mode, +}; +/* *INDENT-ON* */ + +static clib_error_t * +show_interface_rx_placement_fn (vlib_main_t * vm, unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + u8 *s = 0; + vnet_main_t *vnm = vnet_get_main (); + vnet_device_input_runtime_t *rt; + vnet_device_and_queue_t *dq; + vlib_node_t *pn = vlib_get_node_by_name (vm, (u8 *) "device-input"); + uword si; + int index = 0; + + /* *INDENT-OFF* */ + foreach_vlib_main (({ + clib_bitmap_foreach (si, pn->sibling_bitmap, + ({ + rt = vlib_node_get_runtime_data (this_vlib_main, si); + + if (vec_len (rt->devices_and_queues)) + s = format (s, " node %U:\n", format_vlib_node_name, vm, si); + + vec_foreach (dq, rt->devices_and_queues) + { + s = format (s, " %U queue %u (%U)\n", + format_vnet_sw_if_index_name, vnm, dq->hw_if_index, + dq->queue_id, + format_vnet_hw_interface_rx_mode, dq->mode); + } + })); + if (vec_len (s) > 0) + { + vlib_cli_output(vm, "Thread %u (%v):\n%v", index, + vlib_worker_threads[index].name, s); + vec_reset_length (s); + } + index++; + })); + /* *INDENT-ON* */ + + vec_free (s); + return 0; +} + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (show_interface_rx_placement, static) = { + .path = "show interface rx-placement", + .short_help = "show interface rx-placement", + .function = show_interface_rx_placement_fn, +}; +/* *INDENT-ON* */ + +static clib_error_t * +set_interface_rx_placement (vlib_main_t * vm, unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + clib_error_t *error = 0; + unformat_input_t _line_input, *line_input = &_line_input; + vnet_main_t *vnm = vnet_get_main (); + vnet_device_main_t *vdm = &vnet_device_main; + vnet_hw_interface_rx_mode mode; + u32 hw_if_index = (u32) ~ 0; + u32 queue_id = (u32) 0; + u32 thread_index = (u32) ~ 0; + int rv; + + if (!unformat_user (input, unformat_line_input, line_input)) + return 0; + + while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) + { + if (unformat + (line_input, "%U", unformat_vnet_hw_interface, vnm, &hw_if_index)) + ; + else if (unformat (line_input, "queue %d", &queue_id)) + ; + else if (unformat (line_input, "main", &thread_index)) + thread_index = 0; + else if (unformat (line_input, "worker %d", &thread_index)) + thread_index += vdm->first_worker_thread_index; + else + { + error = clib_error_return (0, "parse error: '%U'", + format_unformat_error, line_input); + unformat_free (line_input); + return error; + } + } + + unformat_free (line_input); + + if (hw_if_index == (u32) ~ 0) + return clib_error_return (0, "please specify valid interface name"); + + if (thread_index > vdm->last_worker_thread_index) + return clib_error_return (0, + "please specify valid worker thread or main"); + + rv = vnet_hw_interface_get_rx_mode (vnm, hw_if_index, queue_id, &mode); + + if (rv) + return clib_error_return (0, "not found"); + + rv = vnet_hw_interface_unassign_rx_thread (vnm, hw_if_index, queue_id); + + if (rv) + return clib_error_return (0, "not found"); + + vnet_hw_interface_assign_rx_thread (vnm, hw_if_index, queue_id, + thread_index); + vnet_hw_interface_set_rx_mode (vnm, hw_if_index, queue_id, mode); + + return 0; +} + +/*? + * This command is used to assign a given interface, and optionally a + * given queue, to a different thread. If the 'queue' is not provided, + * it defaults to 0. + * + * @cliexpar + * Example of how to display the interface placement: + * @cliexstart{show interface placement} + * Thread 1 (vpp_wk_0): + * GigabitEthernet0/8/0 queue 0 + * GigabitEthernet0/9/0 queue 0 + * Thread 2 (vpp_wk_1): + * GigabitEthernet0/8/0 queue 1 + * GigabitEthernet0/9/0 queue 1 + * @cliexend + * Example of how to assign a interface and queue to a thread: + * @cliexcmd{set interface placement GigabitEthernet0/8/0 queue 1 thread 1} +?*/ +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (cmd_set_if_rx_placement,static) = { + .path = "set interface rx-placement", + .short_help = "set interface rx-placement [queue ] [thread | main]", + .function = set_interface_rx_placement, +}; + +/* *INDENT-ON* */ /* * fd.io coding-style-patch-verification: ON * diff --git a/src/vnet/interface_format.c b/src/vnet/interface_format.c index b961c778..03caf5c6 100644 --- a/src/vnet/interface_format.c +++ b/src/vnet/interface_format.c @@ -58,6 +58,23 @@ format_vnet_sw_interface_flags (u8 * s, va_list * args) return s; } +u8 * +format_vnet_hw_interface_rx_mode (u8 * s, va_list * args) +{ + vnet_hw_interface_rx_mode mode = va_arg (*args, vnet_hw_interface_rx_mode); + + if (mode == VNET_HW_INTERFACE_RX_MODE_POLLING) + return format (s, "polling"); + + if (mode == VNET_HW_INTERFACE_RX_MODE_INTERRUPT) + return format (s, "interrupt"); + + if (mode == VNET_HW_INTERFACE_RX_MODE_ADAPTIVE) + return format (s, "adaptive"); + + return format (s, "unknown"); +} + u8 * format_vnet_hw_interface (u8 * s, va_list * args) { diff --git a/src/vnet/interface_funcs.h b/src/vnet/interface_funcs.h index b3aca2fd..999b72e5 100644 --- a/src/vnet/interface_funcs.h +++ b/src/vnet/interface_funcs.h @@ -277,6 +277,7 @@ clib_error_t *vnet_hw_interface_change_mac_address (vnet_main_t * vnm, /* Formats sw/hw interface. */ format_function_t format_vnet_hw_interface; +format_function_t format_vnet_hw_interface_rx_mode; format_function_t format_vnet_sw_interface; format_function_t format_vnet_sw_interface_name; format_function_t format_vnet_sw_interface_name_override; -- cgit 1.2.3-korg From e3a395c8406a292becb719495052374449fcd152 Mon Sep 17 00:00:00 2001 From: Steven Date: Tue, 9 May 2017 16:19:50 -0700 Subject: device: Add callback for set interface rx-mode - When the interface rx-mode is changed via CLI, the corresponding device may want to know about it and to reset the driver. This patch is to add the callback. - In the function vnet_hw_interface_set_rx_mode, it appears it is missing a line hw->rx_mode_by_queue[queue_id] = mode because the function is checking if the new mode is the same as hw->rx_mode_by_queue which is initialized to POLLING. So if the function is called to change the mode to interrupt, it just returns without doing anything. This is the check that I am talking about in the same function. if (hw->rx_mode_by_queue[queue_id] == mode) return 0; Change-Id: Iaca2651c43e0ae3fda6fd8dc128e247b0851cc65 Signed-off-by: Steven --- src/vnet/devices/devices.c | 1 + src/vnet/interface.h | 26 +++++++++++------ src/vnet/interface_cli.c | 72 ++++++++++++++++++++++++++++++++++------------ 3 files changed, 72 insertions(+), 27 deletions(-) (limited to 'src/vnet/interface_cli.c') diff --git a/src/vnet/devices/devices.c b/src/vnet/devices/devices.c index d75d905a..e71be602 100644 --- a/src/vnet/devices/devices.c +++ b/src/vnet/devices/devices.c @@ -225,6 +225,7 @@ vnet_hw_interface_set_rx_mode (vnet_main_t * vnm, u32 hw_if_index, (hw->flags & VNET_HW_INTERFACE_FLAG_SUPPORTS_INT_MODE) == 0) return VNET_API_ERROR_UNSUPPORTED; + hw->rx_mode_by_queue[queue_id] = mode; thread_index = hw->input_node_thread_index_by_queue[queue_id]; vm = vlib_mains[thread_index]; diff --git a/src/vnet/interface.h b/src/vnet/interface.h index 2344348b..1c985558 100644 --- a/src/vnet/interface.h +++ b/src/vnet/interface.h @@ -48,6 +48,15 @@ struct vnet_hw_interface_t; struct vnet_sw_interface_t; struct ip46_address_t; +typedef enum +{ + VNET_HW_INTERFACE_RX_MODE_UNKNOWN, + VNET_HW_INTERFACE_RX_MODE_POLLING, + VNET_HW_INTERFACE_RX_MODE_INTERRUPT, + VNET_HW_INTERFACE_RX_MODE_ADAPTIVE, + VNET_HW_INTERFACE_NUM_RX_MODES, +} vnet_hw_interface_rx_mode; + /* Interface up/down callback. */ typedef clib_error_t *(vnet_interface_function_t) (struct vnet_main_t * vnm, u32 if_index, u32 flags); @@ -61,6 +70,11 @@ typedef clib_error_t *(vnet_subif_add_del_function_t) typedef clib_error_t *(vnet_interface_set_mac_address_function_t) (struct vnet_hw_interface_t * hi, char *address); +/* Interface set rx mode callback. */ +typedef clib_error_t *(vnet_interface_set_rx_mode_function_t) + (struct vnet_main_t * vnm, u32 if_index, u32 queue_id, + vnet_hw_interface_rx_mode mode); + typedef enum vnet_interface_function_priority_t_ { VNET_ITF_FUNC_PRIORITY_LOW, @@ -134,6 +148,9 @@ typedef struct _vnet_device_class /* Function to call when sub-interface is added/deleted */ vnet_subif_add_del_function_t *subif_add_del_function; + /* Function to call interface rx mode is changed */ + vnet_interface_set_rx_mode_function_t *rx_mode_change_function; + /* Redistribute flag changes/existence of this interface class. */ u32 redistribute; @@ -492,15 +509,6 @@ typedef enum VNET_SW_INTERFACE_TYPE_SUB, } vnet_sw_interface_type_t; -typedef enum -{ - VNET_HW_INTERFACE_RX_MODE_UNKNOWN, - VNET_HW_INTERFACE_RX_MODE_POLLING, - VNET_HW_INTERFACE_RX_MODE_INTERRUPT, - VNET_HW_INTERFACE_RX_MODE_ADAPTIVE, - VNET_HW_INTERFACE_NUM_RX_MODES, -} vnet_hw_interface_rx_mode; - typedef struct { /* diff --git a/src/vnet/interface_cli.c b/src/vnet/interface_cli.c index bfce03e1..e18a80fc 100644 --- a/src/vnet/interface_cli.c +++ b/src/vnet/interface_cli.c @@ -1175,6 +1175,54 @@ VLIB_CLI_COMMAND (clear_tag_command, static) = { }; /* *INDENT-ON* */ +static clib_error_t * +set_hw_interface_rx_mode (vnet_main_t * vnm, u32 hw_if_index, + u32 queue_id, vnet_hw_interface_rx_mode mode) +{ + vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, hw_if_index); + vnet_device_class_t *dev_class = + vnet_get_device_class (vnm, hw->dev_class_index); + clib_error_t *error; + vnet_hw_interface_rx_mode old_mode; + int rv; + + rv = vnet_hw_interface_get_rx_mode (vnm, hw_if_index, queue_id, &old_mode); + switch (rv) + { + case 0: + if (old_mode == mode) + return 0; /* same rx-mode, no change */ + break; + case VNET_API_ERROR_INVALID_INTERFACE: + return clib_error_return (0, "invalid interface"); + default: + return clib_error_return (0, "unknown error"); + } + + if (dev_class->rx_mode_change_function) + { + error = dev_class->rx_mode_change_function (vnm, hw_if_index, queue_id, + mode); + if (error) + return (error); + } + + rv = vnet_hw_interface_set_rx_mode (vnm, hw_if_index, queue_id, mode); + switch (rv) + { + case 0: + break; + case VNET_API_ERROR_UNSUPPORTED: + return clib_error_return (0, "unsupported"); + case VNET_API_ERROR_INVALID_INTERFACE: + return clib_error_return (0, "invalid interface"); + default: + return clib_error_return (0, "unknown error"); + } + + return 0; +} + static clib_error_t * set_interface_rx_mode (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) @@ -1186,7 +1234,7 @@ set_interface_rx_mode (vlib_main_t * vm, unformat_input_t * input, u32 hw_if_index = (u32) ~ 0; u32 queue_id = (u32) ~ 0; vnet_hw_interface_rx_mode mode = VNET_HW_INTERFACE_RX_MODE_UNKNOWN; - int i, rv = 0; + int i; if (!unformat_user (input, unformat_line_input, line_input)) return 0; @@ -1226,26 +1274,14 @@ set_interface_rx_mode (vlib_main_t * vm, unformat_input_t * input, if (queue_id == ~0) for (i = 0; i < vec_len (hw->dq_runtime_index_by_queue); i++) { - rv = vnet_hw_interface_set_rx_mode (vnm, hw_if_index, i, mode); - if (rv) - goto error; + error = set_hw_interface_rx_mode (vnm, hw_if_index, i, mode); + if (error) + break; } else - rv = vnet_hw_interface_set_rx_mode (vnm, hw_if_index, queue_id, mode); - - if (rv) - goto error; - - return 0; - -error: - if (rv == VNET_API_ERROR_UNSUPPORTED) - return clib_error_return (0, "unsupported"); - - if (rv == VNET_API_ERROR_INVALID_INTERFACE) - return clib_error_return (0, "invalid interfaace"); + error = set_hw_interface_rx_mode (vnm, hw_if_index, queue_id, mode); - return clib_error_return (0, "unknown error"); + return (error); } /*? -- cgit 1.2.3-korg From 6f9ac6559ba155cc15dbc1153900f7bd3c4c9e13 Mon Sep 17 00:00:00 2001 From: Damjan Marion Date: Thu, 15 Jun 2017 19:01:31 +0200 Subject: Add missing barrier sync to rx placement infra code Change-Id: I25ccf8260dbe7e1550aee3904a688fc135ce1f03 Signed-off-by: Damjan Marion --- src/vnet/devices/devices.c | 20 +++++++++++++++----- src/vnet/interface_cli.c | 4 +++- 2 files changed, 18 insertions(+), 6 deletions(-) (limited to 'src/vnet/interface_cli.c') diff --git a/src/vnet/devices/devices.c b/src/vnet/devices/devices.c index 58c72077..e3311c43 100644 --- a/src/vnet/devices/devices.c +++ b/src/vnet/devices/devices.c @@ -123,7 +123,7 @@ vnet_hw_interface_assign_rx_thread (vnet_main_t * vnm, u32 hw_if_index, u16 queue_id, uword thread_index) { vnet_device_main_t *vdm = &vnet_device_main; - vlib_main_t *vm; + vlib_main_t *vm, *vm0; vnet_device_input_runtime_t *rt; vnet_device_and_queue_t *dq; vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, hw_if_index); @@ -143,6 +143,10 @@ vnet_hw_interface_assign_rx_thread (vnet_main_t * vnm, u32 hw_if_index, } vm = vlib_mains[thread_index]; + vm0 = vlib_get_main (); + + vlib_worker_thread_barrier_sync (vm0); + rt = vlib_node_get_runtime_data (vm, hw->input_node_index); vec_add2 (rt->devices_and_queues, dq, 1); @@ -157,6 +161,9 @@ vnet_hw_interface_assign_rx_thread (vnet_main_t * vnm, u32 hw_if_index, vec_validate (hw->rx_mode_by_queue, queue_id); hw->input_node_thread_index_by_queue[queue_id] = thread_index; hw->rx_mode_by_queue[queue_id] = VNET_HW_INTERFACE_RX_MODE_POLLING; + + vlib_worker_thread_barrier_release (vm0); + vlib_node_set_state (vm, hw->input_node_index, rt->enabled_node_state); } @@ -164,7 +171,7 @@ int vnet_hw_interface_unassign_rx_thread (vnet_main_t * vnm, u32 hw_if_index, u16 queue_id) { - vlib_main_t *vm; + vlib_main_t *vm, *vm0; vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, hw_if_index); vnet_device_input_runtime_t *rt; vnet_device_and_queue_t *dq; @@ -187,16 +194,19 @@ vnet_hw_interface_unassign_rx_thread (vnet_main_t * vnm, u32 hw_if_index, if (dq->hw_if_index == hw_if_index && dq->queue_id == queue_id) { mode = dq->mode; - vec_del1 (rt->devices_and_queues, dq - rt->devices_and_queues); - goto deleted; + goto delete; } return VNET_API_ERROR_INVALID_INTERFACE; -deleted: +delete: + vm0 = vlib_get_main (); + vlib_worker_thread_barrier_sync (vm0); + vec_del1 (rt->devices_and_queues, dq - rt->devices_and_queues); vnet_device_queue_update (vnm, rt); hw->rx_mode_by_queue[queue_id] = VNET_HW_INTERFACE_RX_MODE_UNKNOWN; + vlib_worker_thread_barrier_release (vm0); if (vec_len (rt->devices_and_queues) == 0) vlib_node_set_state (vm, hw->input_node_index, VLIB_NODE_STATE_DISABLED); diff --git a/src/vnet/interface_cli.c b/src/vnet/interface_cli.c index e18a80fc..d37c7894 100644 --- a/src/vnet/interface_cli.c +++ b/src/vnet/interface_cli.c @@ -1445,8 +1445,10 @@ set_interface_rx_placement (vlib_main_t * vm, unformat_input_t * input, /* *INDENT-OFF* */ VLIB_CLI_COMMAND (cmd_set_if_rx_placement,static) = { .path = "set interface rx-placement", - .short_help = "set interface rx-placement [queue ] [thread | main]", + .short_help = "set interface rx-placement [queue ] " + "[worker | main]", .function = set_interface_rx_placement, + .is_mp_safe = 1, }; /* *INDENT-ON* */ -- cgit 1.2.3-korg From 4e53a0d0f01c8c81842d1f50fb5cf0d26e0c1713 Mon Sep 17 00:00:00 2001 From: Damjan Marion Date: Wed, 21 Jun 2017 14:29:44 +0200 Subject: Introduce default rx mode for device drivers If interface is down and queues are not configured then we are not able to change rx-mode. This change introducess default mode which is stored per interface and applied if driver wants. Change-Id: I70149c21c1530eafc148d5e4aa03fbee53dec62f Signed-off-by: Damjan Marion --- src/plugins/memif/memif.c | 2 +- src/vnet/devices/devices.c | 3 +++ src/vnet/interface.c | 1 + src/vnet/interface.h | 2 ++ src/vnet/interface_cli.c | 18 ++++++++++++------ 5 files changed, 19 insertions(+), 7 deletions(-) (limited to 'src/vnet/interface_cli.c') diff --git a/src/plugins/memif/memif.c b/src/plugins/memif/memif.c index ec67023b..fffb94c9 100644 --- a/src/plugins/memif/memif.c +++ b/src/plugins/memif/memif.c @@ -222,7 +222,7 @@ memif_connect (memif_if_t * mif) } vnet_hw_interface_assign_rx_thread (vnm, mif->hw_if_index, i, ~0); rv = vnet_hw_interface_set_rx_mode (vnm, mif->hw_if_index, i, - VNET_HW_INTERFACE_RX_MODE_INTERRUPT); + VNET_HW_INTERFACE_RX_MODE_DEFAULT); if (rv) clib_warning ("Warning: unable to set rx mode for interface %d queue %d: " diff --git a/src/vnet/devices/devices.c b/src/vnet/devices/devices.c index e3311c43..f64c6e0d 100644 --- a/src/vnet/devices/devices.c +++ b/src/vnet/devices/devices.c @@ -245,6 +245,9 @@ vnet_hw_interface_set_rx_mode (vnet_main_t * vnm, u32 hw_if_index, vnet_device_input_runtime_t *rt; int is_polling = 0; + if (mode == VNET_HW_INTERFACE_RX_MODE_DEFAULT) + mode = hw->default_rx_mode; + if (hw->input_node_thread_index_by_queue == 0 || hw->rx_mode_by_queue == 0) return VNET_API_ERROR_INVALID_INTERFACE; diff --git a/src/vnet/interface.c b/src/vnet/interface.c index e9042ae8..1370d048 100644 --- a/src/vnet/interface.c +++ b/src/vnet/interface.c @@ -706,6 +706,7 @@ vnet_register_interface (vnet_main_t * vnm, hw_index = hw - im->hw_interfaces; hw->hw_if_index = hw_index; + hw->default_rx_mode = VNET_HW_INTERFACE_RX_MODE_POLLING; if (dev_class->format_device_name) hw->name = format (0, "%U", dev_class->format_device_name, dev_instance); diff --git a/src/vnet/interface.h b/src/vnet/interface.h index 095fe961..d684e356 100644 --- a/src/vnet/interface.h +++ b/src/vnet/interface.h @@ -54,6 +54,7 @@ typedef enum VNET_HW_INTERFACE_RX_MODE_POLLING, VNET_HW_INTERFACE_RX_MODE_INTERRUPT, VNET_HW_INTERFACE_RX_MODE_ADAPTIVE, + VNET_HW_INTERFACE_RX_MODE_DEFAULT, VNET_HW_INTERFACE_NUM_RX_MODES, } vnet_hw_interface_rx_mode; @@ -492,6 +493,7 @@ typedef struct vnet_hw_interface_t /* vnet_hw_interface_rx_mode by queue */ u8 *rx_mode_by_queue; + vnet_hw_interface_rx_mode default_rx_mode; /* device input device_and_queue runtime index */ uword *dq_runtime_index_by_queue; diff --git a/src/vnet/interface_cli.c b/src/vnet/interface_cli.c index d37c7894..bf2873ac 100644 --- a/src/vnet/interface_cli.c +++ b/src/vnet/interface_cli.c @@ -1186,6 +1186,9 @@ set_hw_interface_rx_mode (vnet_main_t * vnm, u32 hw_if_index, vnet_hw_interface_rx_mode old_mode; int rv; + if (mode == VNET_HW_INTERFACE_RX_MODE_DEFAULT) + mode = hw->default_rx_mode; + rv = vnet_hw_interface_get_rx_mode (vnm, hw_if_index, queue_id, &old_mode); switch (rv) { @@ -1272,12 +1275,15 @@ set_interface_rx_mode (vlib_main_t * vm, unformat_input_t * input, hw = vnet_get_hw_interface (vnm, hw_if_index); if (queue_id == ~0) - for (i = 0; i < vec_len (hw->dq_runtime_index_by_queue); i++) - { - error = set_hw_interface_rx_mode (vnm, hw_if_index, i, mode); - if (error) - break; - } + { + for (i = 0; i < vec_len (hw->dq_runtime_index_by_queue); i++) + { + error = set_hw_interface_rx_mode (vnm, hw_if_index, i, mode); + if (error) + break; + } + hw->default_rx_mode = mode; + } else error = set_hw_interface_rx_mode (vnm, hw_if_index, queue_id, mode); -- cgit 1.2.3-korg From 9d6d9894b1035eda6163d96c72b9ddbaea096f0e Mon Sep 17 00:00:00 2001 From: Steven Date: Fri, 30 Jun 2017 07:15:02 -0700 Subject: devices: show interface rx-placement displays the wrong information (VPP-894) show interface rx-placement somtimes displays the wrong interface names. This happens when there exists subinterfaces in VPP. The problem is due to the function show_interface_rx_placement_fn is calling format_vnet_sw_if_index_name with hw_if_index instead of sw_if_index. VPP has the concept of sw_if_index and hw_if_index. Each serves a different purpose. When there is no subinterfaces, both hw_if_index and sw_if_index may happen to have the same value. But don't count on it. When the API calls for sw_if_index, we must pass the sw_if_index although the hw_if_index has the same type which the compiler does not catch. Passing hw_if_index for an API which requires sw_if_index may have an unpredictable result such as described in the VPP-894 and sometimes it may even crash if the particular index does not exist. Change-Id: I76c4834f79b88a1c20684fcba64f14b2da142d77 Signed-off-by: Steven (cherry picked from commit bafa4d048439fdbcc0bd577e43a2784d1b89bfc5) --- src/vnet/interface_cli.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/vnet/interface_cli.c') diff --git a/src/vnet/interface_cli.c b/src/vnet/interface_cli.c index bf2873ac..fe7ae38f 100644 --- a/src/vnet/interface_cli.c +++ b/src/vnet/interface_cli.c @@ -1339,8 +1339,10 @@ show_interface_rx_placement_fn (vlib_main_t * vm, unformat_input_t * input, vec_foreach (dq, rt->devices_and_queues) { + vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, + dq->hw_if_index); s = format (s, " %U queue %u (%U)\n", - format_vnet_sw_if_index_name, vnm, dq->hw_if_index, + format_vnet_sw_if_index_name, vnm, hi->sw_if_index, dq->queue_id, format_vnet_hw_interface_rx_mode, dq->mode); } -- cgit 1.2.3-korg From 942402b02096af1c966f10e3e2a3d235787b962e Mon Sep 17 00:00:00 2001 From: Eyal Bari Date: Wed, 26 Jul 2017 11:57:04 +0300 Subject: CLI:add l2 input/outut to "sh int features" Change-Id: If608bbc7f4c8b0d5c3a237098a20279e407c82d3 Signed-off-by: Eyal Bari --- src/vnet/interface_cli.c | 42 ++++++++++++++++++++++++++++-------------- src/vnet/l2/l2_bd.h | 2 +- src/vnet/l2/l2_input.c | 23 +++++++++++++++++++++++ src/vnet/l2/l2_input.h | 2 ++ src/vnet/l2/l2_output.c | 23 +++++++++++++++++++++++ src/vnet/l2/l2_output.h | 2 ++ 6 files changed, 79 insertions(+), 15 deletions(-) (limited to 'src/vnet/interface_cli.c') diff --git a/src/vnet/interface_cli.c b/src/vnet/interface_cli.c index fe7ae38f..a8aa3056 100644 --- a/src/vnet/interface_cli.c +++ b/src/vnet/interface_cli.c @@ -47,6 +47,8 @@ #include #include #include +#include +#include static int compare_interface_names (void *a1, void *a2) @@ -262,6 +264,20 @@ show_sw_interfaces (vlib_main_t * vm, if (show_features) { vnet_interface_features_show (vm, sw_if_index); + + l2_input_config_t *l2_input = l2input_intf_config (sw_if_index); + u32 fb = l2_input->feature_bitmap; + /* intf input features are masked by bridge domain */ + if (l2_input->bridge) + fb &= l2input_bd_config (l2_input->bd_index)->feature_bitmap; + vlib_cli_output (vm, "\nl2-input:\n%U", format_l2_input_features, fb); + + l2_output_config_t *l2_output = l2output_intf_config (sw_if_index); + vlib_cli_output (vm, "\nl2-output:"); + if (l2_output->out_vtr_flag) + vlib_cli_output (vm, "%10s (%s)", "VTR", "--internal--"); + vlib_cli_output (vm, "%U", format_l2_output_features, + l2_output->feature_bitmap); return 0; } if (show_tag) @@ -285,9 +301,10 @@ show_sw_interfaces (vlib_main_t * vm, _vec_len (sorted_sis) = 0; pool_foreach (si, im->sw_interfaces, ( { - if (vnet_swif_is_api_visible - (si)) vec_add1 (sorted_sis, - si[0]);} + int visible = + vnet_swif_is_api_visible (si); + if (visible) + vec_add1 (sorted_sis, si[0]);} )); /* Sort by name. */ @@ -298,7 +315,6 @@ show_sw_interfaces (vlib_main_t * vm, { vec_foreach (si, sorted_sis) { - l2input_main_t *l2m = &l2input_main; ip4_main_t *im4 = &ip4_main; ip6_main_t *im6 = &ip6_main; ip_lookup_main_t *lm4 = &im4->lookup_main; @@ -309,7 +325,6 @@ show_sw_interfaces (vlib_main_t * vm, u32 fib_index4 = 0, fib_index6 = 0; ip4_fib_t *fib4; ip6_fib_t *fib6; - l2_input_config_t *config; if (vec_len (im4->fib_index_by_sw_if_index) > si->sw_if_index) fib_index4 = vec_elt (im4->fib_index_by_sw_if_index, @@ -339,21 +354,20 @@ show_sw_interfaces (vlib_main_t * vm, ? "up" : "dn"); } - /* Display any L2 addressing info */ - vec_validate (l2m->configs, si->sw_if_index); - config = vec_elt_at_index (l2m->configs, si->sw_if_index); - if (config->bridge) + /* Display any L2 info */ + l2_input_config_t *l2_input = l2input_intf_config (si->sw_if_index); + if (l2_input->bridge) { - u32 bd_id = l2input_main.bd_configs[config->bd_index].bd_id; + u32 bd_id = l2input_main.bd_configs[l2_input->bd_index].bd_id; vlib_cli_output (vm, " l2 bridge bd_id %d%s%d", bd_id, - config->bvi ? " bvi shg " : " shg ", - config->shg); + l2_input->bvi ? " bvi shg " : " shg ", + l2_input->shg); } - else if (config->xconnect) + else if (l2_input->xconnect) { vlib_cli_output (vm, " l2 xconnect %U", format_vnet_sw_if_index_name, - vnm, config->output_sw_if_index); + vnm, l2_input->output_sw_if_index); } /* Display any IP4 addressing info */ diff --git a/src/vnet/l2/l2_bd.h b/src/vnet/l2/l2_bd.h index 93ed1a85..0e070651 100644 --- a/src/vnet/l2/l2_bd.h +++ b/src/vnet/l2/l2_bd.h @@ -34,7 +34,7 @@ typedef struct vnet_main_t *vnet_main; } bd_main_t; -bd_main_t bd_main; +extern bd_main_t bd_main; /* Bridge domain member */ diff --git a/src/vnet/l2/l2_input.c b/src/vnet/l2/l2_input.c index 26c832ad..faed7c7f 100644 --- a/src/vnet/l2/l2_input.c +++ b/src/vnet/l2/l2_input.c @@ -60,6 +60,29 @@ l2input_get_feat_names (void) return l2input_feat_names; } +u8 * +format_l2_input_features (u8 * s, va_list * args) +{ + static char *display_names[] = { +#define _(sym,name) #sym, + foreach_l2input_feat +#undef _ + }; + u32 feature_bitmap = va_arg (*args, u32); + + if (feature_bitmap == 0) + { + s = format (s, " none configured"); + return s; + } + + feature_bitmap &= ~L2INPUT_FEAT_DROP; /* Not a feature */ + int i; + for (i = L2INPUT_N_FEAT; i >= 0; i--) + if (feature_bitmap & (1 << i)) + s = format (s, "%10s (%s)\n", display_names[i], l2input_feat_names[i]); + return s; +} typedef struct { diff --git a/src/vnet/l2/l2_input.h b/src/vnet/l2/l2_input.h index e6b3bc7f..e8a6c776 100644 --- a/src/vnet/l2/l2_input.h +++ b/src/vnet/l2/l2_input.h @@ -148,6 +148,8 @@ STATIC_ASSERT ((u64) L2INPUT_VALID_MASK == (1ull << L2INPUT_N_FEAT) - 1, ""); /** Return an array of strings containing graph node names of each feature */ char **l2input_get_feat_names (void); +/* arg0 - u32 feature_bitmap */ +u8 *format_l2_input_features (u8 * s, va_list * args); static_always_inline u8 bd_feature_flood (l2_bridge_domain_t * bd_config) diff --git a/src/vnet/l2/l2_output.c b/src/vnet/l2/l2_output.c index fbee590c..500fc5d0 100644 --- a/src/vnet/l2/l2_output.c +++ b/src/vnet/l2/l2_output.c @@ -40,6 +40,29 @@ l2output_get_feat_names (void) return l2output_feat_names; } +u8 * +format_l2_output_features (u8 * s, va_list * args) +{ + static char *display_names[] = { +#define _(sym,name) #sym, + foreach_l2output_feat +#undef _ + }; + u32 feature_bitmap = va_arg (*args, u32); + + if (feature_bitmap == 0) + { + s = format (s, " none configured"); + return s; + } + + int i; + for (i = L2OUTPUT_N_FEAT - 1; i >= 0; i--) + if (feature_bitmap & (1 << i)) + s = format (s, "%10s (%s)\n", display_names[i], l2output_feat_names[i]); + return s; +} + l2output_main_t l2output_main; typedef struct diff --git a/src/vnet/l2/l2_output.h b/src/vnet/l2/l2_output.h index a54b8d67..1a73fdf9 100644 --- a/src/vnet/l2/l2_output.h +++ b/src/vnet/l2/l2_output.h @@ -141,6 +141,8 @@ typedef enum /* Return an array of strings containing graph node names of each feature */ char **l2output_get_feat_names (void); +/* arg0 - u32 feature_bitmap */ +u8 *format_l2_output_features (u8 * s, va_list * args); /** * The next set of functions is for use by output feature graph nodes. -- cgit 1.2.3-korg From e9bac6953d03440f2f7437f4e3f0a4e3bf7f8a60 Mon Sep 17 00:00:00 2001 From: Billy McFall Date: Fri, 11 Aug 2017 14:05:11 -0400 Subject: VPP-939: Update CLI Helptext for rx-placement commands The CLI commands were change from 'set/show interface placement' to 'set/show interface rx-placement', but the associated help text was not updated. On the 'set interface rx-placement', some of the parameters were renamed, which was confusing when looking at the documentation for help. While in the file interface_cli.c, cleaned up several other CLI commands. There are still other commands in the file that need addressing. Change-Id: Ifdc357c73ad9f3362133c495217b5a6b3a411eab Signed-off-by: Billy McFall --- src/vnet/dir.dox | 29 ++++ src/vnet/interface_cli.c | 358 ++++++++++++++++++++++++++++++++++------------- 2 files changed, 293 insertions(+), 94 deletions(-) create mode 100644 src/vnet/dir.dox (limited to 'src/vnet/interface_cli.c') diff --git a/src/vnet/dir.dox b/src/vnet/dir.dox new file mode 100644 index 00000000..8bc2c4cf --- /dev/null +++ b/src/vnet/dir.dox @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2017 Red Hat and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* Doxygen directory documentation */ + +/** +@dir +@brief Interface. + +This is a high level directory which contains sub-directories for all the +networking protocols. Also contained within this directory are more generic +CLI command files such as interface management. + +*/ +/*? %%clicmd:group_label Interface %% ?*/ +/*? %%syscfg:group_label Interface %% ?*/ diff --git a/src/vnet/interface_cli.c b/src/vnet/interface_cli.c index a8aa3056..f37f139b 100644 --- a/src/vnet/interface_cli.c +++ b/src/vnet/interface_cli.c @@ -39,7 +39,10 @@ /** * @file - * Interface CLI. + * @brief Interface CLI. + * + * Source code for several CLI interface commands. + * */ #include @@ -165,46 +168,88 @@ done: return error; } -/* *INDENT-OFF* */ /*? - * Displays various information about the state of the current terminal - * session. + * Display more detailed information about all or a list of given interfaces. + * The verboseness of the output can be controlled by the following optional + * parameters: + * - brief: Only show name, index and state (default for bonded interfaces). + * - verbose: Also display additional attributes (default for all other interfaces). + * - detail: Also display all remaining attributes and extended statistics. + * + * To limit the output of the command to bonded interfaces and their slave + * interfaces, use the 'bond' optional parameter. * * @cliexpar - * @cliexstart{show hardware} - * Name Link Hardware - * GigabitEthernet2/0/0 up GigabitEthernet2/0/0 - * Ethernet address 00:50:56:b7:7c:83 - * Intel 82545em_copper - * link up, media 1000T full-duplex, master, - * 0 unprocessed, 384 total buffers on rx queue 0 ring - * 237 buffers in driver rx cache - * rx total packets 1816 - * rx total bytes 181084 - * rx good packets 1816 - * rx good bytes 181084 - * rx 65 127 byte packets 1586 - * rx 256 511 byte packets 230 - * tx total packets 346 - * tx total bytes 90224 - * tx good packets 346 - * tx good bytes 88840 - * tx 64 byte packets 1 - * tx 65 127 byte packets 115 - * tx 256 511 byte packets 230 + * Example of how to display default data for all interfaces: + * @cliexstart{show hardware-interfaces} + * Name Idx Link Hardware + * GigabitEthernet7/0/0 1 up GigabitEthernet7/0/0 + * Ethernet address ec:f4:bb:c0:bc:fc + * Intel e1000 + * carrier up full duplex speed 1000 mtu 9216 + * rx queues 1, rx desc 1024, tx queues 3, tx desc 1024 + * cpu socket 0 + * GigabitEthernet7/0/1 2 up GigabitEthernet7/0/1 + * Ethernet address ec:f4:bb:c0:bc:fd + * Intel e1000 + * carrier up full duplex speed 1000 mtu 9216 + * rx queues 1, rx desc 1024, tx queues 3, tx desc 1024 + * cpu socket 0 + * VirtualEthernet0/0/0 3 up VirtualEthernet0/0/0 + * Ethernet address 02:fe:a5:a9:8b:8e + * VirtualEthernet0/0/1 4 up VirtualEthernet0/0/1 + * Ethernet address 02:fe:c0:4e:3b:b0 + * VirtualEthernet0/0/2 5 up VirtualEthernet0/0/2 + * Ethernet address 02:fe:1f:73:92:81 + * VirtualEthernet0/0/3 6 up VirtualEthernet0/0/3 + * Ethernet address 02:fe:f2:25:c4:68 + * local0 0 down local0 + * local + * @cliexend + * Example of how to display 'verbose' data for an interface by name and + * software index (where 2 is the software index): + * @cliexstart{show hardware-interfaces GigabitEthernet7/0/0 2 verbose} + * Name Idx Link Hardware + * GigabitEthernet7/0/0 1 up GigabitEthernet7/0/0 + * Ethernet address ec:f4:bb:c0:bc:fc + * Intel e1000 + * carrier up full duplex speed 1000 mtu 9216 + * rx queues 1, rx desc 1024, tx queues 3, tx desc 1024 + * cpu socket 0 + * GigabitEthernet7/0/1 2 down GigabitEthernet7/0/1 + * Ethernet address ec:f4:bb:c0:bc:fd + * Intel e1000 + * carrier up full duplex speed 1000 mtu 9216 + * rx queues 1, rx desc 1024, tx queues 3, tx desc 1024 + * cpu socket 0 * @cliexend ?*/ +/* *INDENT-OFF* */ VLIB_CLI_COMMAND (show_hw_interfaces_command, static) = { .path = "show hardware-interfaces", - .short_help = "show hardware-interfaces [brief|verbose|detail] [bond] [ ...]", + .short_help = "show hardware-interfaces [brief|verbose|detail] [bond] " + "[ [ [..]]] [ [ [..]]]", .function = show_or_clear_hw_interfaces, }; /* *INDENT-ON* */ + +/*? + * Clear the extended statistics for all or a list of given interfaces + * (statistics associated with the 'show hardware-interfaces' command). + * + * @cliexpar + * Example of how to clear the extended statistics for all interfaces: + * @cliexcmd{clear hardware-interfaces} + * Example of how to clear the extended statistics for an interface by + * name and software index (where 2 is the software index): + * @cliexcmd{clear hardware-interfaces GigabitEthernet7/0/0 2} + ?*/ /* *INDENT-OFF* */ VLIB_CLI_COMMAND (clear_hw_interface_counters_command, static) = { .path = "clear hardware-interfaces", - .short_help = "Clear hardware interfaces statistics", + .short_help = "clear hardware-interfaces " + "[ [ [..]]] [ [ [..]]]", .function = show_or_clear_hw_interfaces, }; /* *INDENT-ON* */ @@ -431,7 +476,7 @@ done: /* *INDENT-OFF* */ VLIB_CLI_COMMAND (show_sw_interfaces_command, static) = { .path = "show interface", - .short_help = "show interface [address|addr|features|feat] [ ...]", + .short_help = "show interface [address|addr|features|feat] [ [ [..]]]", .function = show_sw_interfaces, }; /* *INDENT-ON* */ @@ -500,10 +545,18 @@ clear_interface_counters (vlib_main_t * vm, return 0; } +/*? + * Clear the statistics for all interfaces (statistics associated with the + * 'show interface' command). + * + * @cliexpar + * Example of how to clear the statistics for all interfaces: + * @cliexcmd{clear interfaces} + ?*/ /* *INDENT-OFF* */ VLIB_CLI_COMMAND (clear_interface_counters_command, static) = { .path = "clear interfaces", - .short_help = "Clear interfaces statistics", + .short_help = "clear interfaces", .function = clear_interface_counters, }; /* *INDENT-ON* */ @@ -747,54 +800,97 @@ done: return error; } -/* *INDENT-OFF* */ /*? - * Create vlan subinterfaces + * This command is used to add VLAN IDs to interfaces, also known as subinterfaces. + * The primary input to this command is the 'interface' and 'subId' + * (subinterface Id) parameters. If no additional VLAN ID is provide, the VLAN ID is + * assumed to be the 'subId'. The VLAN ID and 'subId' can be different, + * but this is not recommended. + * + * This command has several variations: + * - create sub-interfaces - Create a subinterface to + * process packets with a given 802.1q VLAN ID (same value as the 'subId'). + * + * - create sub-interfaces default - Adding the + * 'default' parameter indicates that packets with VLAN IDs that do not + * match any other subinterfaces should be sent to this subinterface. + * + * - create sub-interfaces untagged - Adding the + * 'untagged' parameter indicates that packets no VLAN IDs should be sent + * to this subinterface. + * + * - create sub-interfaces - - Create a range of + * subinterfaces to handle a range of VLAN IDs. + * + * - create sub-interfaces dot1q|dot1ad |any [exact-match] - + * Use this command to specify the outer VLAN ID, to either be explicited or to make the + * VLAN ID different from the 'subId'. + * + * - create sub-interfaces dot1q|dot1ad |any inner-dot1q + * |any [exact-match] - Use this command to specify the outer VLAN ID and + * the innner VLAN ID. + * + * When 'dot1q' or 'dot1ad' is explictly entered, subinterfaces + * can be configured as either exact-match or non-exact match. Non-exact match is the CLI + * default. If 'exact-match' is specified, packets must have the same number of + * VLAN tags as the configuration. For non-exact-match, packets must at least that number + * of tags. L3 (routed) interfaces must be configured as exact-match. L2 interfaces are + * typically configured as non-exact-match. If 'dot1q' or 'dot1ad' is NOT + * entered, then the default behavior is exact-match. + * + * Use the 'show interface' command to display all subinterfaces. * * @cliexpar - * @cliexstart{create sub-interfaces} + * @parblock + * Example of how to create a VLAN subinterface 11 to process packets on 802.1q VLAN ID 11: + * @cliexcmd{create sub-interfaces GigabitEthernet2/0/0 11} * - * To create a vlan subinterface 11 to process packets on 802.1q VLAN id 11, use: + * The previous example is shorthand and is equivalent to: + * @cliexcmd{create sub-interfaces GigabitEthernet2/0/0 11 dot1q 11 exact-match} * - * vpp# create sub GigabitEthernet2/0/0 11 * - * This shorthand is equivalent to: - * vpp# create sub GigabitEthernet2/0/0 11 dot1q 11 exact-match + * Example of how to create a subinterface number that is different from the VLAN ID: + * @cliexcmd{create sub-interfaces GigabitEthernet2/0/0 11 dot1q 100} * - * You can specify a subinterface number that is different from the vlan id: - * vpp# create sub GigabitEthernet2/0/0 11 dot1q 100 * - * You can create qinq and q-in-any interfaces: - * vpp# create sub GigabitEthernet2/0/0 11 dot1q 100 inner-dot1q 200 - * vpp# create sub GigabitEthernet2/0/0 12 dot1q 100 inner-dot1q any + * Examples of how to create q-in-q and q-in-any subinterfaces: + * @cliexcmd{create sub-interfaces GigabitEthernet2/0/0 11 dot1q 100 inner-dot1q 200} + * @cliexcmd{create sub-interfaces GigabitEthernet2/0/0 12 dot1q 100 inner-dot1q any} * - * You can also create dot1ad interfaces: - * vpp# create sub GigabitEthernet2/0/0 11 dot1ad 11 - * vpp# create sub GigabitEthernet2/0/0 12 dot1q 100 inner-dot1q 200 + * Examples of how to create dot1ad interfaces: + * @cliexcmd{create sub-interfaces GigabitEthernet2/0/0 11 dot1ad 11} + * @cliexcmd{create sub-interfaces GigabitEthernet2/0/0 12 dot1ad 100 inner-dot1q 200} * - * Subinterfaces can be configured as either exact-match or non-exact match. - * Non-exact match is the CLI default. If exact-match is specified, - * packets must have the same number of vlan tags as the configuration. - * For non-exact-match, packets must at least that number of tags. - * L3 (routed) interfaces must be configured as exact-match. - * L2 interfaces are typically configured as non-exact-match. * - * For example, a packet with outer vlan 100 and inner 200 would match this interface: - * vpp# create sub GigabitEthernet2/0/0 5 dot1q 100 + * Examples of 'exact-match' versus non-exact match. A packet with + * outer VLAN 100 and inner VLAN 200 would match this interface, because the default + * is non-exact match: + * @cliexcmd{create sub-interfaces GigabitEthernet2/0/0 5 dot1q 100} * - * but would not match this interface: - * vpp# create sub GigabitEthernet2/0/0 5 dot1q 100 exact-match + * However, the same packet would NOT match this interface because 'exact-match' + * is specified and only one VLAN is configured, but packet contains two VLANs: + * @cliexcmd{create sub-interfaces GigabitEthernet2/0/0 5 dot1q 100 exact-match} * - * There are two special subinterfaces that can be configured. Subinterface untagged has no vlan tags: - * vpp# create sub GigabitEthernet2/0/0 5 untagged * - * The subinterface default matches any packet that does not match any other subinterface: - * vpp# create sub GigabitEthernet2/0/0 7 default - * @cliexend + * Example of how to created a subinterface to process untagged packets: + * @cliexcmd{create sub-interfaces GigabitEthernet2/0/0 5 untagged} + * + * Example of how to created a subinterface to process any packet with a VLAN ID that + * does not match any other subinterface: + * @cliexcmd{create sub-interfaces GigabitEthernet2/0/0 7 default} + * + * When subinterfaces are created, they are in the down state. Example of how to + * enable a newly created subinterface: + * @cliexcmd{set interface GigabitEthernet2/0/0.7 up} + * @endparblock ?*/ +/* *INDENT-OFF* */ VLIB_CLI_COMMAND (create_sub_interfaces_command, static) = { .path = "create sub-interfaces", - .short_help = "create sub-interfaces [-] [dot1q|dot1ad|default|untagged]", + .short_help = "create sub-interfaces " + "{ [default|untagged]} | " + "{-} | " + "{ dot1q|dot1ad |any [inner-dot1q |any] [exact-match]}", .function = create_sub_interfaces, }; /* *INDENT-ON* */ @@ -831,19 +927,24 @@ done: } -/* *INDENT-OFF* */ /*? - * Interface admin up/down + * This command is used to change the admin state (up/down) of an interface. + * + * If an interface is down, the optional 'punt' flag can also be set. + * The 'punt' flag implies the interface is disabled for forwarding + * but punt all traffic to slow-path. Use the 'enable' flag to clear + * 'punt' flag (interface is still down). * * @cliexpar - * @cliexstart{set interface state} - * vpp# set interface state GigabitEthernet2/0/0 up - * vpp# set interface state GigabitEthernet2/0/0 down - * @cliexend + * Example of how to configure the admin state of an interface to 'updownqueue' is not provided, - * it defaults to 0. + * This command is used to assign the RX packet processing mode (polling, + * interrupt, adaptive) of the a given interface, and optionally a + * given queue. If the 'queue' is not provided, the 'mode' + * is applied to all queues of the interface. Not all interfaces support + * all modes. To display the current rx-mode use the command + * 'show interface rx-placement'. * * @cliexpar - * Example of how to display the interface placement: + * Example of how to assign rx-mode to all queues on an interface: + * @cliexcmd{set interface rx-mode VirtualEthernet0/0/12 polling} + * Example of how to assign rx-mode to one queue of an interface: + * @cliexcmd{set interface rx-mode VirtualEthernet0/0/12 queue 0 interrupt} + * Example of how to display the rx-mode of all interfaces: * @cliexstart{show interface rx-placement} * Thread 1 (vpp_wk_0): - * GigabitEthernet0/8/0 queue 0 - * GigabitEthernet0/9/0 queue 0 + * node dpdk-input: + * GigabitEthernet7/0/0 queue 0 (polling) + * node vhost-user-input: + * VirtualEthernet0/0/12 queue 0 (interrupt) + * VirtualEthernet0/0/12 queue 2 (polling) + * VirtualEthernet0/0/13 queue 0 (polling) + * VirtualEthernet0/0/13 queue 2 (polling) * Thread 2 (vpp_wk_1): - * GigabitEthernet0/8/0 queue 1 - * GigabitEthernet0/9/0 queue 1 + * node dpdk-input: + * GigabitEthernet7/0/1 queue 0 (polling) + * node vhost-user-input: + * VirtualEthernet0/0/12 queue 1 (polling) + * VirtualEthernet0/0/12 queue 3 (polling) + * VirtualEthernet0/0/13 queue 1 (polling) + * VirtualEthernet0/0/13 queue 3 (polling) * @cliexend - * Example of how to assign a interface and queue to a thread: - * @cliexcmd{set interface placement GigabitEthernet0/8/0 queue 1 thread 1} ?*/ /* *INDENT-OFF* */ VLIB_CLI_COMMAND (cmd_set_if_rx_mode,static) = { @@ -1375,6 +1491,31 @@ show_interface_rx_placement_fn (vlib_main_t * vm, unformat_input_t * input, return 0; } +/*? + * This command is used to display the interface and queue worker + * thread placement. + * + * @cliexpar + * Example of how to display the interface placement: + * @cliexstart{show interface rx-placement} + * Thread 1 (vpp_wk_0): + * node dpdk-input: + * GigabitEthernet7/0/0 queue 0 (polling) + * node vhost-user-input: + * VirtualEthernet0/0/12 queue 0 (polling) + * VirtualEthernet0/0/12 queue 2 (polling) + * VirtualEthernet0/0/13 queue 0 (polling) + * VirtualEthernet0/0/13 queue 2 (polling) + * Thread 2 (vpp_wk_1): + * node dpdk-input: + * GigabitEthernet7/0/1 queue 0 (polling) + * node vhost-user-input: + * VirtualEthernet0/0/12 queue 1 (polling) + * VirtualEthernet0/0/12 queue 3 (polling) + * VirtualEthernet0/0/13 queue 1 (polling) + * VirtualEthernet0/0/13 queue 3 (polling) + * @cliexend +?*/ /* *INDENT-OFF* */ VLIB_CLI_COMMAND (show_interface_rx_placement, static) = { .path = "show interface rx-placement", @@ -1449,30 +1590,59 @@ set_interface_rx_placement (vlib_main_t * vm, unformat_input_t * input, /*? * This command is used to assign a given interface, and optionally a * given queue, to a different thread. If the 'queue' is not provided, - * it defaults to 0. + * it defaults to 0. The 'worker' parameter is zero based and the index + * in the thread name, for example, 0 in the thread name 'vpp_wk_0'. * * @cliexpar * Example of how to display the interface placement: - * @cliexstart{show interface placement} + * @cliexstart{show interface rx-placement} * Thread 1 (vpp_wk_0): - * GigabitEthernet0/8/0 queue 0 - * GigabitEthernet0/9/0 queue 0 + * node dpdk-input: + * GigabitEthernet7/0/0 queue 0 (polling) + * node vhost-user-input: + * VirtualEthernet0/0/12 queue 0 (polling) + * VirtualEthernet0/0/12 queue 2 (polling) + * VirtualEthernet0/0/13 queue 0 (polling) + * VirtualEthernet0/0/13 queue 2 (polling) * Thread 2 (vpp_wk_1): - * GigabitEthernet0/8/0 queue 1 - * GigabitEthernet0/9/0 queue 1 + * node dpdk-input: + * GigabitEthernet7/0/1 queue 0 (polling) + * node vhost-user-input: + * VirtualEthernet0/0/12 queue 1 (polling) + * VirtualEthernet0/0/12 queue 3 (polling) + * VirtualEthernet0/0/13 queue 1 (polling) + * VirtualEthernet0/0/13 queue 3 (polling) + * @cliexend + * Example of how to assign a interface and queue to a worker thread: + * @cliexcmd{set interface rx-placement VirtualEthernet0/0/12 queue 1 worker 0} + * Example of how to display the interface placement: + * @cliexstart{show interface rx-placement} + * Thread 1 (vpp_wk_0): + * node dpdk-input: + * GigabitEthernet7/0/0 queue 0 (polling) + * node vhost-user-input: + * VirtualEthernet0/0/12 queue 0 (polling) + * VirtualEthernet0/0/12 queue 1 (polling) + * VirtualEthernet0/0/12 queue 2 (polling) + * VirtualEthernet0/0/13 queue 0 (polling) + * VirtualEthernet0/0/13 queue 2 (polling) + * Thread 2 (vpp_wk_1): + * node dpdk-input: + * GigabitEthernet7/0/1 queue 0 (polling) + * node vhost-user-input: + * VirtualEthernet0/0/12 queue 3 (polling) + * VirtualEthernet0/0/13 queue 1 (polling) + * VirtualEthernet0/0/13 queue 3 (polling) * @cliexend - * Example of how to assign a interface and queue to a thread: - * @cliexcmd{set interface placement GigabitEthernet0/8/0 queue 1 thread 1} ?*/ /* *INDENT-OFF* */ VLIB_CLI_COMMAND (cmd_set_if_rx_placement,static) = { .path = "set interface rx-placement", - .short_help = "set interface rx-placement [queue ] " + .short_help = "set interface rx-placement [queue ] " "[worker | main]", .function = set_interface_rx_placement, .is_mp_safe = 1, }; - /* *INDENT-ON* */ /* * fd.io coding-style-patch-verification: ON -- cgit 1.2.3-korg From bd8a611c7e4558f18e3280ace9e48ecae5673800 Mon Sep 17 00:00:00 2001 From: Steven Date: Sun, 30 Jul 2017 10:29:26 -0700 Subject: Devices: Set interface rx-mode may cause SIGSEGV with nonexistent queue When I type in set interface rx-mode with a nonexistent queue, I got a crash with the following traceback. It looks like the vm is NULL when vlib_node_get_runtime is called. DBGvpp# sh int rx Thread 0 (vpp_main): node dpdk-input: TenGigabitEthernet5/0/0 queue 0 (polling) TenGigabitEthernet5/0/1 queue 0 (polling) TenGigabitEthernet7/0/0 queue 0 (polling) TenGigabitEthernet7/0/1 queue 0 (polling) node vhost-user-input: VirtualEthernet0/0/2 queue 0 (adaptive) DBGvpp# set interface rx-mode VirtualEthernet0/0/2 queue 1 polling Thread 1 "vpp_main" received signal SIGSEGV, Segmentation fault. 0x00007ffff6d4e0bc in vlib_node_get_runtime (vm=0x0, node_index=125) at /home/sluong/vpp/build-data/../src/vlib/node_funcs.h:92 92 vlib_node_t *n = vec_elt (nm->nodes, node_index); (gdb) where at /home/sluong/vpp/build-data/../src/vlib/node_funcs.h:92 at /home/sluong/vpp/build-data/../src/vlib/node_funcs.h:112 vnm=0x6f0fa0 , hw_if_index=7, queue_id=1, mode=0x7fffb62099e8) at /home/sluong/vpp/build-data/../src/vnet/devices/devices.c:307 hw_if_index=7, queue_id=1, mode=VNET_HW_INTERFACE_RX_MODE_POLLING) at /home/sluong/vpp/build-data/../src/vnet/interface_cli.c:1192 vm=0x7ffff7b9d440 , input=0x7fffb6209ef0, cmd=0x7fffb61d5d14) at /home/sluong/vpp/build-data/../src/vnet/interface_cli.c:1288 vm=0x7ffff7b9d440 , cm=0x7ffff7b9d630 , input=0x7fffb6209ef0, parent_command_index=18) at /home/sluong/vpp/build-data/../src/vlib/cli.c:588 vm=0x7ffff7b9d440 , cm=0x7ffff7b9d630 , input=0x7fffb6209ef0, parent_command_index=12) The fix is to add a check for vec_len(hw->input_node_thread_index_by_queue) and vec_len (hw->rx_mode_by_queue) to reject the command if the queue_id is out of bound. While at it, I notice inputting queue_id=-1 is being interpreted as all queues. An easy fix is to not overload the queue_id variable with -1 to mean something else. Change-Id: Id70ec3e7d06ccc67635e6d28ef53420bdac4a988 Signed-off-by: Steven --- src/vnet/api_errno.h | 3 ++- src/vnet/devices/devices.c | 8 ++++++++ src/vnet/interface_cli.c | 9 +++++++-- 3 files changed, 17 insertions(+), 3 deletions(-) (limited to 'src/vnet/interface_cli.c') diff --git a/src/vnet/api_errno.h b/src/vnet/api_errno.h index 22522f34..c0deb1d0 100644 --- a/src/vnet/api_errno.h +++ b/src/vnet/api_errno.h @@ -114,7 +114,8 @@ _(BD_NOT_MODIFIABLE, -121, "Bridge domain 0 can't be deleted/modified") \ _(BD_ID_EXCEED_MAX, -122, "Bridge domain ID exceed 16M limit") \ _(SUBIF_DOESNT_EXIST, -123, "Subinterface doesn't exist") \ _(L2_MACS_EVENT_CLINET_PRESENT, -124, "Client already exist for L2 MACs events") \ -_(UNSUPPORTED, -125, "Unsupported") +_(INVALID_QUEUE, -125, "Invalid queue") \ +_(UNSUPPORTED, -126, "Unsupported") typedef enum { diff --git a/src/vnet/devices/devices.c b/src/vnet/devices/devices.c index 2eb8e30e..a38ecd2d 100644 --- a/src/vnet/devices/devices.c +++ b/src/vnet/devices/devices.c @@ -264,6 +264,10 @@ vnet_hw_interface_set_rx_mode (vnet_main_t * vnm, u32 hw_if_index, (hw->flags & VNET_HW_INTERFACE_FLAG_SUPPORTS_INT_MODE) == 0) return VNET_API_ERROR_UNSUPPORTED; + if ((vec_len (hw->input_node_thread_index_by_queue) < queue_id + 1) || + (vec_len (hw->rx_mode_by_queue) < queue_id + 1)) + return VNET_API_ERROR_INVALID_QUEUE; + hw->rx_mode_by_queue[queue_id] = mode; thread_index = hw->input_node_thread_index_by_queue[queue_id]; vm = vlib_mains[thread_index]; @@ -307,6 +311,10 @@ vnet_hw_interface_get_rx_mode (vnet_main_t * vnm, u32 hw_if_index, if (hw->input_node_thread_index_by_queue == 0) return VNET_API_ERROR_INVALID_INTERFACE; + if ((vec_len (hw->input_node_thread_index_by_queue) < queue_id + 1) || + (vec_len (hw->rx_mode_by_queue) < queue_id + 1)) + return VNET_API_ERROR_INVALID_QUEUE; + thread_index = hw->input_node_thread_index_by_queue[queue_id]; vm = vlib_mains[thread_index]; diff --git a/src/vnet/interface_cli.c b/src/vnet/interface_cli.c index f37f139b..a6680c5b 100644 --- a/src/vnet/interface_cli.c +++ b/src/vnet/interface_cli.c @@ -1313,6 +1313,8 @@ set_hw_interface_rx_mode (vnet_main_t * vnm, u32 hw_if_index, break; case VNET_API_ERROR_INVALID_INTERFACE: return clib_error_return (0, "invalid interface"); + case VNET_API_ERROR_INVALID_QUEUE: + return clib_error_return (0, "invalid queue"); default: return clib_error_return (0, "unknown error"); } @@ -1334,6 +1336,8 @@ set_hw_interface_rx_mode (vnet_main_t * vnm, u32 hw_if_index, return clib_error_return (0, "unsupported"); case VNET_API_ERROR_INVALID_INTERFACE: return clib_error_return (0, "invalid interface"); + case VNET_API_ERROR_INVALID_QUEUE: + return clib_error_return (0, "invalid queue"); default: return clib_error_return (0, "unknown error"); } @@ -1353,6 +1357,7 @@ set_interface_rx_mode (vlib_main_t * vm, unformat_input_t * input, u32 queue_id = (u32) ~ 0; vnet_hw_interface_rx_mode mode = VNET_HW_INTERFACE_RX_MODE_UNKNOWN; int i; + u8 input_queue_id = 0; if (!unformat_user (input, unformat_line_input, line_input)) return 0; @@ -1363,7 +1368,7 @@ set_interface_rx_mode (vlib_main_t * vm, unformat_input_t * input, (line_input, "%U", unformat_vnet_hw_interface, vnm, &hw_if_index)) ; else if (unformat (line_input, "queue %d", &queue_id)) - ; + input_queue_id = 1; else if (unformat (line_input, "polling")) mode = VNET_HW_INTERFACE_RX_MODE_POLLING; else if (unformat (line_input, "interrupt")) @@ -1389,7 +1394,7 @@ set_interface_rx_mode (vlib_main_t * vm, unformat_input_t * input, hw = vnet_get_hw_interface (vnm, hw_if_index); - if (queue_id == ~0) + if (input_queue_id == 0) { for (i = 0; i < vec_len (hw->dq_runtime_index_by_queue); i++) { -- cgit 1.2.3-korg From 77d7dcba32516b3353dc075ca2753f5532178137 Mon Sep 17 00:00:00 2001 From: Neale Ranns Date: Wed, 4 Oct 2017 02:29:07 -0700 Subject: Set MAC address needs the HW interface index Change-Id: I7b175d57b85e626aab00221b6dac0498aebcbeae Signed-off-by: Neale Ranns (cherry picked from commit d867a7cf6baffcebbf1b6e408272ec22dc55dd68) --- src/vnet/interface_api.c | 4 +++- src/vnet/interface_cli.c | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'src/vnet/interface_cli.c') diff --git a/src/vnet/interface_api.c b/src/vnet/interface_api.c index 0731ab35..05d9f211 100644 --- a/src/vnet/interface_api.c +++ b/src/vnet/interface_api.c @@ -864,6 +864,7 @@ static void vl_api_sw_interface_set_mac_address_t_handler vl_api_sw_interface_set_mac_address_reply_t *rmp; vnet_main_t *vnm = vnet_get_main (); u32 sw_if_index = ntohl (mp->sw_if_index); + vnet_sw_interface_t *si; u64 mac; clib_error_t *error; int rv = 0; @@ -877,7 +878,8 @@ static void vl_api_sw_interface_set_mac_address_t_handler | (u64) mp->mac_address[4] << (8 * 4) | (u64) mp->mac_address[5] << (8 * 5)); - error = vnet_hw_interface_change_mac_address (vnm, sw_if_index, mac); + si = vnet_get_sw_interface (vnm, sw_if_index); + error = vnet_hw_interface_change_mac_address (vnm, si->hw_if_index, mac); if (error) { rv = VNET_API_ERROR_UNIMPLEMENTED; diff --git a/src/vnet/interface_cli.c b/src/vnet/interface_cli.c index a6680c5b..15dc7f8d 100644 --- a/src/vnet/interface_cli.c +++ b/src/vnet/interface_cli.c @@ -1198,6 +1198,7 @@ set_interface_mac_address (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) { vnet_main_t *vnm = vnet_get_main (); + vnet_sw_interface_t *si = NULL; clib_error_t *error = 0; u32 sw_if_index = ~0; u64 mac = 0; @@ -1214,7 +1215,8 @@ set_interface_mac_address (vlib_main_t * vm, unformat_input_t * input, format_unformat_error, input); goto done; } - error = vnet_hw_interface_change_mac_address (vnm, sw_if_index, mac); + si = vnet_get_sw_interface (vnm, sw_if_index); + error = vnet_hw_interface_change_mac_address (vnm, si->hw_if_index, mac); done: return error; } -- cgit 1.2.3-korg