X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=src%2Fvnet%2Fip%2Flookup.c;h=f674fec48231b744c24940b9134cb83b86a9c800;hb=f2984bbb0;hp=4506ae140192df614ffff58cd6f3c6862b68c572;hpb=f73d0e2ea6bf4e0dc9c69ec4f1d0c7b9b41d2fa3;p=vpp.git diff --git a/src/vnet/ip/lookup.c b/src/vnet/ip/lookup.c old mode 100755 new mode 100644 index 4506ae14019..f674fec4823 --- a/src/vnet/ip/lookup.c +++ b/src/vnet/ip/lookup.c @@ -13,7 +13,7 @@ * limitations under the License. */ /* - * ip/ip_lookup.c: ip4/6 adjacency and lookup table managment + * ip/ip_lookup.c: ip4/6 adjacency and lookup table management * * Copyright (c) 2008 Eliot Dresselhaus * @@ -49,130 +49,13 @@ #include #include #include -#include /** * @file - * @brief IPv4 and IPv6 adjacency and lookup table managment. + * @brief IPv4 and IPv6 adjacency and lookup table management. * */ -clib_error_t * -ip_interface_address_add_del (ip_lookup_main_t * lm, - u32 sw_if_index, - void *addr_fib, - u32 address_length, - u32 is_del, u32 * result_if_address_index) -{ - vnet_main_t *vnm = vnet_get_main (); - ip_interface_address_t *a, *prev, *next; - uword *p = mhash_get (&lm->address_to_if_address_index, addr_fib); - - vec_validate_init_empty (lm->if_address_pool_index_by_sw_if_index, - sw_if_index, ~0); - a = p ? pool_elt_at_index (lm->if_address_pool, p[0]) : 0; - - /* Verify given length. */ - if ((a && (address_length != a->address_length)) || - (address_length == 0) || - (lm->is_ip6 && address_length > 128) || - (!lm->is_ip6 && address_length > 32)) - { - vnm->api_errno = VNET_API_ERROR_ADDRESS_LENGTH_MISMATCH; - return clib_error_create - ("%U wrong length (expected %d) for interface %U", - lm->format_address_and_length, addr_fib, - address_length, a ? a->address_length : -1, - format_vnet_sw_if_index_name, vnm, sw_if_index); - } - - if (is_del) - { - if (!a) - { - vnet_sw_interface_t *si = vnet_get_sw_interface (vnm, sw_if_index); - vnm->api_errno = VNET_API_ERROR_ADDRESS_NOT_FOUND_FOR_INTERFACE; - return clib_error_create ("%U not found for interface %U", - lm->format_address_and_length, - addr_fib, address_length, - format_vnet_sw_interface_name, vnm, si); - } - - if (a->prev_this_sw_interface != ~0) - { - prev = - pool_elt_at_index (lm->if_address_pool, - a->prev_this_sw_interface); - prev->next_this_sw_interface = a->next_this_sw_interface; - } - if (a->next_this_sw_interface != ~0) - { - next = - pool_elt_at_index (lm->if_address_pool, - a->next_this_sw_interface); - next->prev_this_sw_interface = a->prev_this_sw_interface; - - if (a->prev_this_sw_interface == ~0) - lm->if_address_pool_index_by_sw_if_index[sw_if_index] = - a->next_this_sw_interface; - } - - if ((a->next_this_sw_interface == ~0) - && (a->prev_this_sw_interface == ~0)) - lm->if_address_pool_index_by_sw_if_index[sw_if_index] = ~0; - - mhash_unset (&lm->address_to_if_address_index, addr_fib, - /* old_value */ 0); - pool_put (lm->if_address_pool, a); - - if (result_if_address_index) - *result_if_address_index = ~0; - } - - else if (!a) - { - u32 pi; /* previous index */ - u32 ai; - u32 hi; /* head index */ - - pool_get (lm->if_address_pool, a); - memset (a, ~0, sizeof (a[0])); - ai = a - lm->if_address_pool; - - hi = pi = lm->if_address_pool_index_by_sw_if_index[sw_if_index]; - prev = 0; - while (pi != (u32) ~ 0) - { - prev = pool_elt_at_index (lm->if_address_pool, pi); - pi = prev->next_this_sw_interface; - } - pi = prev ? prev - lm->if_address_pool : (u32) ~ 0; - - a->address_key = mhash_set (&lm->address_to_if_address_index, - addr_fib, ai, /* old_value */ 0); - a->address_length = address_length; - a->sw_if_index = sw_if_index; - a->flags = 0; - a->prev_this_sw_interface = pi; - a->next_this_sw_interface = ~0; - if (prev) - prev->next_this_sw_interface = ai; - - lm->if_address_pool_index_by_sw_if_index[sw_if_index] = - (hi != ~0) ? hi : ai; - if (result_if_address_index) - *result_if_address_index = ai; - } - else - { - if (result_if_address_index) - *result_if_address_index = a - lm->if_address_pool; - } - - - return /* no error */ 0; -} - static clib_error_t * ip_sw_interface_add_del (vnet_main_t * vnm, u32 sw_if_index, u32 is_add) { @@ -195,6 +78,8 @@ ip_lookup_init (ip_lookup_main_t * lm, u32 is_ip6) lm->fib_result_n_bytes = sizeof (uword); lm->is_ip6 = is_ip6; + mhash_init (&lm->prefix_to_if_prefix_index, sizeof (uword), + sizeof (ip_interface_prefix_key_t)); if (is_ip6) { lm->format_address_and_length = format_ip6_address_and_length; @@ -234,73 +119,22 @@ format_ip_flow_hash_config (u8 * s, va_list * args) { flow_hash_config_t flow_hash_config = va_arg (*args, u32); -#define _(n,v) if (flow_hash_config & v) s = format (s, "%s ", #n); +#define _(n, b, v) \ + if (flow_hash_config & v) \ + s = format (s, "%s ", #n); foreach_flow_hash_bit; #undef _ return s; } -u8 * -format_ip_lookup_next (u8 * s, va_list * args) -{ - /* int promotion of ip_lookup_next_t */ - ip_lookup_next_t n = va_arg (*args, int); - char *t = 0; - - switch (n) - { - default: - s = format (s, "unknown %d", n); - return s; - - case IP_LOOKUP_NEXT_DROP: - t = "drop"; - break; - case IP_LOOKUP_NEXT_PUNT: - t = "punt"; - break; - case IP_LOOKUP_NEXT_ARP: - t = "arp"; - break; - case IP_LOOKUP_NEXT_MIDCHAIN: - t = "midchain"; - break; - case IP_LOOKUP_NEXT_GLEAN: - t = "glean"; - break; - case IP_LOOKUP_NEXT_MCAST: - t = "mcast"; - break; - case IP_LOOKUP_NEXT_REWRITE: - break; - } - - if (t) - vec_add (s, t, strlen (t)); - - return s; -} - u8 * format_ip_adjacency_packet_data (u8 * s, va_list * args) { - u32 adj_index = va_arg (*args, u32); u8 *packet_data = va_arg (*args, u8 *); u32 n_packet_data_bytes = va_arg (*args, u32); - ip_adjacency_t *adj = adj_get (adj_index); - switch (adj->lookup_next_index) - { - case IP_LOOKUP_NEXT_REWRITE: - case IP_LOOKUP_NEXT_MCAST: - s = - format (s, "%U", format_hex_bytes, packet_data, n_packet_data_bytes); - break; - - default: - break; - } + s = format (s, "%U", format_hex_bytes, packet_data, n_packet_data_bytes); return s; } @@ -350,29 +184,23 @@ const ip46_address_t zero_addr = { 0, 0}, }; -clib_error_t * +static clib_error_t * vnet_ip_route_cmd (vlib_main_t * vm, unformat_input_t * main_input, vlib_cli_command_t * cmd) { unformat_input_t _line_input, *line_input = &_line_input; - fib_route_path_t *rpaths = NULL, rpath; + u32 table_id, is_del, fib_index, payload_proto; dpo_id_t dpo = DPO_INVALID, *dpos = NULL; + fib_route_path_t *rpaths = NULL, rpath; fib_prefix_t *prefixs = NULL, pfx; - mpls_label_t out_label, via_label; clib_error_t *error = NULL; - u32 weight, preference; - u32 table_id, is_del; - vnet_main_t *vnm; - u32 fib_index; f64 count; int i; - vnm = vnet_get_main (); is_del = 0; table_id = 0; count = 1; - memset (&pfx, 0, sizeof (pfx)); - out_label = via_label = MPLS_LABEL_INVALID; + clib_memset (&pfx, 0, sizeof (pfx)); /* Get a line of input. */ if (!unformat_user (main_input, unformat_line_input, line_input)) @@ -380,160 +208,28 @@ vnet_ip_route_cmd (vlib_main_t * vm, while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) { - memset (&rpath, 0, sizeof (rpath)); + clib_memset (&rpath, 0, sizeof (rpath)); if (unformat (line_input, "table %d", &table_id)) ; - else if (unformat (line_input, "del")) - is_del = 1; - else if (unformat (line_input, "add")) - is_del = 0; - else if (unformat (line_input, "resolve-via-host")) - { - if (vec_len (rpaths) == 0) - { - error = clib_error_return (0, "Paths then flags"); - goto done; - } - rpaths[vec_len (rpaths) - 1].frp_flags |= - FIB_ROUTE_PATH_RESOLVE_VIA_HOST; - } - else if (unformat (line_input, "resolve-via-attached")) - { - if (vec_len (rpaths) == 0) - { - error = clib_error_return (0, "Paths then flags"); - goto done; - } - rpaths[vec_len (rpaths) - 1].frp_flags |= - FIB_ROUTE_PATH_RESOLVE_VIA_ATTACHED; - } - else if (unformat (line_input, "out-labels")) - { - if (vec_len (rpaths) == 0) - { - error = clib_error_return (0, "Paths then labels"); - goto done; - } - else - { - while (unformat (line_input, "%U", - unformat_mpls_unicast_label, &out_label)) - { - vec_add1 (rpaths[vec_len (rpaths) - 1].frp_label_stack, - out_label); - } - } - } - else if (unformat (line_input, "via-label %U", - unformat_mpls_unicast_label, &rpath.frp_local_label)) - { - rpath.frp_weight = 1; - rpath.frp_eos = MPLS_NON_EOS; - rpath.frp_proto = DPO_PROTO_MPLS; - rpath.frp_sw_if_index = ~0; - vec_add1 (rpaths, rpath); - } else if (unformat (line_input, "count %f", &count)) ; else if (unformat (line_input, "%U/%d", unformat_ip4_address, &pfx.fp_addr.ip4, &pfx.fp_len)) { - pfx.fp_proto = FIB_PROTOCOL_IP4; + payload_proto = pfx.fp_proto = FIB_PROTOCOL_IP4; vec_add1 (prefixs, pfx); } else if (unformat (line_input, "%U/%d", unformat_ip6_address, &pfx.fp_addr.ip6, &pfx.fp_len)) { - pfx.fp_proto = FIB_PROTOCOL_IP6; + payload_proto = pfx.fp_proto = FIB_PROTOCOL_IP6; vec_add1 (prefixs, pfx); } - else if (unformat (line_input, "via %U %U", - unformat_ip4_address, - &rpath.frp_addr.ip4, - unformat_vnet_sw_interface, vnm, - &rpath.frp_sw_if_index)) - { - rpath.frp_weight = 1; - rpath.frp_proto = DPO_PROTO_IP4; - vec_add1 (rpaths, rpath); - } - - else if (unformat (line_input, "via %U %U", - unformat_ip6_address, - &rpath.frp_addr.ip6, - unformat_vnet_sw_interface, vnm, - &rpath.frp_sw_if_index)) - { - rpath.frp_weight = 1; - rpath.frp_proto = DPO_PROTO_IP6; - vec_add1 (rpaths, rpath); - } - else if (unformat (line_input, "weight %u", &weight)) - { - ASSERT (vec_len (rpaths)); - rpaths[vec_len (rpaths) - 1].frp_weight = weight; - } - else if (unformat (line_input, "preference %u", &preference)) - { - ASSERT (vec_len (rpaths)); - rpaths[vec_len (rpaths) - 1].frp_preference = preference; - } - else if (unformat (line_input, "via %U next-hop-table %d", - unformat_ip4_address, - &rpath.frp_addr.ip4, &rpath.frp_fib_index)) - { - rpath.frp_weight = 1; - rpath.frp_sw_if_index = ~0; - rpath.frp_proto = DPO_PROTO_IP4; - vec_add1 (rpaths, rpath); - } - else if (unformat (line_input, "via %U next-hop-table %d", - unformat_ip6_address, - &rpath.frp_addr.ip6, &rpath.frp_fib_index)) - { - rpath.frp_weight = 1; - rpath.frp_sw_if_index = ~0; - rpath.frp_proto = DPO_PROTO_IP6; - vec_add1 (rpaths, rpath); - } else if (unformat (line_input, "via %U", - unformat_ip4_address, &rpath.frp_addr.ip4)) + unformat_fib_route_path, &rpath, &payload_proto)) { - /* - * the recursive next-hops are by default in the same table - * as the prefix - */ - rpath.frp_fib_index = table_id; - rpath.frp_weight = 1; - rpath.frp_sw_if_index = ~0; - rpath.frp_proto = DPO_PROTO_IP4; - vec_add1 (rpaths, rpath); - } - else if (unformat (line_input, "via %U", - unformat_ip6_address, &rpath.frp_addr.ip6)) - { - rpath.frp_fib_index = table_id; - rpath.frp_weight = 1; - rpath.frp_sw_if_index = ~0; - rpath.frp_proto = DPO_PROTO_IP6; - vec_add1 (rpaths, rpath); - } - else if (unformat (line_input, - "lookup in table %d", &rpath.frp_fib_index)) - { - rpath.frp_proto = fib_proto_to_dpo (pfx.fp_proto); - rpath.frp_sw_if_index = ~0; - vec_add1 (rpaths, rpath); - } - else if (vec_len (prefixs) > 0 && - unformat (line_input, "via %U", - unformat_vnet_sw_interface, vnm, - &rpath.frp_sw_if_index)) - { - rpath.frp_weight = 1; - rpath.frp_proto = fib_proto_to_dpo (prefixs[0].fp_proto); vec_add1 (rpaths, rpath); } else if (vec_len (prefixs) > 0 && @@ -542,6 +238,10 @@ vnet_ip_route_cmd (vlib_main_t * vm, { vec_add1 (dpos, dpo); } + else if (unformat (line_input, "del")) + is_del = 1; + else if (unformat (line_input, "add")) + is_del = 0; else { error = unformat_parse_error (line_input); @@ -604,7 +304,7 @@ vnet_ip_route_cmd (vlib_main_t * vm, } else if (0 < vec_len (rpaths)) { - u32 k, j, n, incr; + u32 k, n, incr; ip46_address_t dst = prefixs[i].fp_addr; f64 t[2]; n = count; @@ -614,41 +314,20 @@ vnet_ip_route_cmd (vlib_main_t * vm, for (k = 0; k < n; k++) { - for (j = 0; j < vec_len (rpaths); j++) - { - u32 fi; - /* - * the CLI parsing stored table Ids, swap to FIB indicies - */ - fi = fib_table_find (prefixs[i].fp_proto, - rpaths[i].frp_fib_index); - - if (~0 == fi) - { - error = - clib_error_return (0, "Via table %d does not exist", - rpaths[i].frp_fib_index); - goto done; - } - rpaths[i].frp_fib_index = fi; - - fib_prefix_t rpfx = { - .fp_len = prefixs[i].fp_len, - .fp_proto = prefixs[i].fp_proto, - .fp_addr = dst, - }; - - if (is_del) - fib_table_entry_path_remove2 (fib_index, - &rpfx, - FIB_SOURCE_CLI, &rpaths[j]); - else - fib_table_entry_path_add2 (fib_index, - &rpfx, - FIB_SOURCE_CLI, - FIB_ENTRY_FLAG_NONE, - &rpaths[j]); - } + fib_prefix_t rpfx = { + .fp_len = prefixs[i].fp_len, + .fp_proto = prefixs[i].fp_proto, + .fp_addr = dst, + }; + + if (is_del) + fib_table_entry_path_remove2 (fib_index, + &rpfx, FIB_SOURCE_CLI, rpaths); + else + fib_table_entry_path_add2 (fib_index, + &rpfx, + FIB_SOURCE_CLI, + FIB_ENTRY_FLAG_NONE, rpaths); if (FIB_PROTOCOL_IP4 == prefixs[0].fp_proto) { @@ -664,9 +343,9 @@ vnet_ip_route_cmd (vlib_main_t * vm, clib_host_to_net_u64 (incr + clib_net_to_host_u64 (dst.ip6.as_u64 [bucket])); - } } + t[1] = vlib_time_now (vm); if (count > 1) vlib_cli_output (vm, "%.6e routes/sec", count / (t[1] - t[0])); @@ -678,7 +357,6 @@ vnet_ip_route_cmd (vlib_main_t * vm, } } - done: vec_free (dpos); vec_free (prefixs); @@ -687,6 +365,81 @@ done: return error; } +clib_error_t * +vnet_ip_table_cmd (vlib_main_t * vm, + unformat_input_t * main_input, + vlib_cli_command_t * cmd, fib_protocol_t fproto) +{ + unformat_input_t _line_input, *line_input = &_line_input; + clib_error_t *error = NULL; + u32 table_id, is_add; + u8 *name = NULL; + + is_add = 1; + table_id = ~0; + + /* Get a line of input. */ + if (!unformat_user (main_input, unformat_line_input, line_input)) + return 0; + + while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (line_input, "%d", &table_id)) + ; + else if (unformat (line_input, "del")) + is_add = 0; + else if (unformat (line_input, "add")) + is_add = 1; + else if (unformat (line_input, "name %s", &name)) + ; + else + { + error = unformat_parse_error (line_input); + goto done; + } + } + + if (~0 == table_id) + { + error = clib_error_return (0, "No table id"); + goto done; + } + else if (0 == table_id) + { + error = clib_error_return (0, "Can't change the default table"); + goto done; + } + else + { + if (is_add) + { + ip_table_create (fproto, table_id, 0, name); + } + else + { + ip_table_delete (fproto, table_id, 0); + } + } + +done: + unformat_free (line_input); + return error; +} + +clib_error_t * +vnet_ip4_table_cmd (vlib_main_t * vm, + unformat_input_t * main_input, vlib_cli_command_t * cmd) +{ + return (vnet_ip_table_cmd (vm, main_input, cmd, FIB_PROTOCOL_IP4)); +} + +clib_error_t * +vnet_ip6_table_cmd (vlib_main_t * vm, + unformat_input_t * main_input, vlib_cli_command_t * cmd) +{ + return (vnet_ip_table_cmd (vm, main_input, cmd, FIB_PROTOCOL_IP6)); +} + /* *INDENT-OFF* */ VLIB_CLI_COMMAND (vlib_cli_ip_command, static) = { .path = "ip", @@ -745,10 +498,161 @@ VLIB_CLI_COMMAND (vlib_cli_show_ip6_command, static) = { /* *INDENT-OFF* */ VLIB_CLI_COMMAND (ip_route_command, static) = { .path = "ip route", - .short_help = "ip route [add|del] [count ] / [table ] [via [] [weight ]] | [via arp ] | [via drop|punt|local|arp|classify ] [lookup in table ]", + .short_help = "ip route [add|del] [count ] / [table ] via [next-hop-address] [next-hop-interface] [next-hop-table ] [weight ] [preference ] [udp-encap-id ] [ip4-lookup-in-table ] [ip6-lookup-in-table ] [mpls-lookup-in-table ] [resolve-via-host] [resolve-via-connected] [rx-ip4 ] [out-labels ]", .function = vnet_ip_route_cmd, .is_mp_safe = 1, }; + +/* *INDENT-ON* */ +/*? + * This command is used to add or delete IPv4 Tables. All + * Tables must be explicitly added before that can be used. Creating a + * table will add both unicast and multicast FIBs + * + ?*/ +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (ip4_table_command, static) = { + .path = "ip table", + .short_help = "ip table [add|del] ", + .function = vnet_ip4_table_cmd, +}; +/* *INDENT-ON* */ + +/* *INDENT-ON* */ +/*? + * This command is used to add or delete IPv4 Tables. All + * Tables must be explicitly added before that can be used. Creating a + * table will add both unicast and multicast FIBs + * + ?*/ +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (ip6_table_command, static) = { + .path = "ip6 table", + .short_help = "ip6 table [add|del] ", + .function = vnet_ip6_table_cmd, +}; + +static clib_error_t * +ip_table_bind_cmd (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd, + fib_protocol_t fproto) +{ + vnet_main_t *vnm = vnet_get_main (); + clib_error_t *error = 0; + u32 sw_if_index, table_id; + int rv; + + 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, "%d", &table_id)) + ; + else + { + error = clib_error_return (0, "expected table id `%U'", + format_unformat_error, input); + goto done; + } + + rv = ip_table_bind (fproto, sw_if_index, table_id, 0); + + if (VNET_API_ERROR_ADDRESS_FOUND_FOR_INTERFACE == rv) + { + error = clib_error_return (0, "IP addresses are still present on %U", + format_vnet_sw_if_index_name, + vnet_get_main(), + sw_if_index); + } + else if (VNET_API_ERROR_NO_SUCH_FIB == rv) + { + error = clib_error_return (0, "no such table %d", table_id); + } + else if (0 != rv) + { + error = clib_error_return (0, "unknown error"); + } + + done: + return error; +} + +static clib_error_t * +ip4_table_bind_cmd (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + return (ip_table_bind_cmd (vm , input, cmd, FIB_PROTOCOL_IP4)); +} + +static clib_error_t * +ip6_table_bind_cmd (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + return (ip_table_bind_cmd (vm , input, cmd, FIB_PROTOCOL_IP6)); +} + +/*? + * Place the indicated interface into the supplied IPv4 FIB table (also known + * as a VRF). The FIB table must be created using "ip table add" already. To + * display the current IPv4 FIB table, use the command 'show ip fib'. + * FIB table will only be displayed if a route has been added to the table, or + * an IP Address is assigned to an interface in the table (which adds a route + * automatically). + * + * @note IP addresses added after setting the interface IP table are added to + * the indicated FIB table. If an IP address is added prior to changing the + * table then this is an error. The control plane must remove these addresses + * first and then change the table. VPP will not automatically move the + * addresses from the old to the new table as it does not know the validity + * of such a change. + * + * @cliexpar + * Example of how to add an interface to an IPv4 FIB table (where 2 is the table-id): + * @cliexcmd{set interface ip table GigabitEthernet2/0/0 2} + ?*/ +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (set_interface_ip_table_command, static) = +{ + .path = "set interface ip table", + .function = ip4_table_bind_cmd, + .short_help = "set interface ip table ", +}; +/* *INDENT-ON* */ + +/*? + * Place the indicated interface into the supplied IPv6 FIB table (also known + * as a VRF). The FIB table must be created using "ip6 table add" already. To + * display the current IPv6 FIB table, use the command 'show ip6 fib'. + * FIB table will only be displayed if a route has been added to the table, or + * an IP Address is assigned to an interface in the table (which adds a route + * automatically). + * + * @note IP addresses added after setting the interface IP table are added to + * the indicated FIB table. If an IP address is added prior to changing the + * table then this is an error. The control plane must remove these addresses + * first and then change the table. VPP will not automatically move the + * addresses from the old to the new table as it does not know the validity + * of such a change. + * + * @cliexpar + * Example of how to add an interface to an IPv6 FIB table (where 2 is the table-id): + * @cliexcmd{set interface ip6 table GigabitEthernet2/0/0 2} + ?*/ +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (set_interface_ip6_table_command, static) = +{ + .path = "set interface ip6 table", + .function = ip6_table_bind_cmd, + .short_help = "set interface ip6 table " +}; /* *INDENT-ON* */ clib_error_t * @@ -756,23 +660,21 @@ vnet_ip_mroute_cmd (vlib_main_t * vm, unformat_input_t * main_input, vlib_cli_command_t * cmd) { unformat_input_t _line_input, *line_input = &_line_input; + fib_route_path_t rpath, *rpaths = NULL; clib_error_t *error = NULL; - fib_route_path_t rpath; - u32 table_id, is_del; - vnet_main_t *vnm; + u32 table_id, is_del, payload_proto; mfib_prefix_t pfx; u32 fib_index; - mfib_itf_flags_t iflags = 0; mfib_entry_flags_t eflags = 0; u32 gcount, scount, ss, gg, incr; f64 timet[2]; + u32 rpf_id = MFIB_RPF_ID_NONE; gcount = scount = 1; - vnm = vnet_get_main (); is_del = 0; table_id = 0; - memset (&pfx, 0, sizeof (pfx)); - memset (&rpath, 0, sizeof (rpath)); + clib_memset (&pfx, 0, sizeof (pfx)); + clib_memset (&rpath, 0, sizeof (rpath)); rpath.frp_sw_if_index = ~0; /* Get a line of input. */ @@ -787,6 +689,8 @@ vnet_ip_mroute_cmd (vlib_main_t * vm, is_del = 1; else if (unformat (line_input, "add")) is_del = 0; + else if (unformat (line_input, "rpf-id %d", &rpf_id)) + ; else if (unformat (line_input, "scount %d", &scount)) ; else if (unformat (line_input, "gcount %d", &gcount)) @@ -796,7 +700,7 @@ vnet_ip_mroute_cmd (vlib_main_t * vm, &pfx.fp_src_addr.ip4, unformat_ip4_address, &pfx.fp_grp_addr.ip4)) { - pfx.fp_proto = FIB_PROTOCOL_IP4; + payload_proto = pfx.fp_proto = FIB_PROTOCOL_IP4; pfx.fp_len = 64; } else if (unformat (line_input, "%U %U", @@ -804,51 +708,56 @@ vnet_ip_mroute_cmd (vlib_main_t * vm, &pfx.fp_src_addr.ip6, unformat_ip6_address, &pfx.fp_grp_addr.ip6)) { - pfx.fp_proto = FIB_PROTOCOL_IP6; + payload_proto = pfx.fp_proto = FIB_PROTOCOL_IP6; pfx.fp_len = 256; } else if (unformat (line_input, "%U/%d", unformat_ip4_address, &pfx.fp_grp_addr.ip4, &pfx.fp_len)) { - memset (&pfx.fp_src_addr.ip4, 0, sizeof (pfx.fp_src_addr.ip4)); - pfx.fp_proto = FIB_PROTOCOL_IP4; + clib_memset (&pfx.fp_src_addr.ip4, 0, sizeof (pfx.fp_src_addr.ip4)); + payload_proto = pfx.fp_proto = FIB_PROTOCOL_IP4; } else if (unformat (line_input, "%U/%d", unformat_ip6_address, &pfx.fp_grp_addr.ip6, &pfx.fp_len)) { - memset (&pfx.fp_src_addr.ip6, 0, sizeof (pfx.fp_src_addr.ip6)); - pfx.fp_proto = FIB_PROTOCOL_IP6; + clib_memset (&pfx.fp_src_addr.ip6, 0, sizeof (pfx.fp_src_addr.ip6)); + payload_proto = pfx.fp_proto = FIB_PROTOCOL_IP6; } else if (unformat (line_input, "%U", unformat_ip4_address, &pfx.fp_grp_addr.ip4)) { - memset (&pfx.fp_src_addr.ip4, 0, sizeof (pfx.fp_src_addr.ip4)); - pfx.fp_proto = FIB_PROTOCOL_IP4; + clib_memset (&pfx.fp_src_addr.ip4, 0, sizeof (pfx.fp_src_addr.ip4)); + payload_proto = pfx.fp_proto = FIB_PROTOCOL_IP4; pfx.fp_len = 32; } else if (unformat (line_input, "%U", unformat_ip6_address, &pfx.fp_grp_addr.ip6)) { - memset (&pfx.fp_src_addr.ip6, 0, sizeof (pfx.fp_src_addr.ip6)); - pfx.fp_proto = FIB_PROTOCOL_IP6; + clib_memset (&pfx.fp_src_addr.ip6, 0, sizeof (pfx.fp_src_addr.ip6)); + payload_proto = pfx.fp_proto = FIB_PROTOCOL_IP6; pfx.fp_len = 128; } - else if (unformat (line_input, "via %U", - unformat_vnet_sw_interface, vnm, - &rpath.frp_sw_if_index)) - { - rpath.frp_weight = 1; - } - else if (unformat (line_input, "via local")) + else if (unformat (line_input, "via local Forward")) { + clib_memset (&rpath.frp_addr, 0, sizeof (rpath.frp_addr)); rpath.frp_sw_if_index = ~0; rpath.frp_weight = 1; rpath.frp_flags |= FIB_ROUTE_PATH_LOCAL; + /* + * set the path proto appropriately for the prefix + */ + rpath.frp_proto = fib_proto_to_dpo (pfx.fp_proto); + rpath.frp_mitf_flags = MFIB_ITF_FLAG_FORWARD; + + vec_add1 (rpaths, rpath); + } + else if (unformat (line_input, "via %U", + unformat_fib_route_path, &rpath, &payload_proto)) + { + vec_add1 (rpaths, rpath); } - else if (unformat (line_input, "%U", unformat_mfib_itf_flags, &iflags)) - ; else if (unformat (line_input, "%U", unformat_mfib_entry_flags, &eflags)) ; @@ -892,25 +801,24 @@ vnet_ip_mroute_cmd (vlib_main_t * vm, { for (gg = 0; gg < gcount; gg++) { - if (is_del && 0 == rpath.frp_weight) + if (is_del && 0 == vec_len (rpaths)) { /* no path provided => route delete */ mfib_table_entry_delete (fib_index, &pfx, MFIB_SOURCE_CLI); } - else if (eflags) + else if (eflags || (MFIB_RPF_ID_NONE != rpf_id)) { mfib_table_entry_update (fib_index, &pfx, MFIB_SOURCE_CLI, - MFIB_RPF_ID_NONE, eflags); + rpf_id, eflags); } else { if (is_del) mfib_table_entry_path_remove (fib_index, - &pfx, MFIB_SOURCE_CLI, &rpath); + &pfx, MFIB_SOURCE_CLI, rpaths); else mfib_table_entry_path_update (fib_index, - &pfx, MFIB_SOURCE_CLI, &rpath, - iflags); + &pfx, MFIB_SOURCE_CLI, rpaths); } if (FIB_PROTOCOL_IP4 == pfx.fp_proto) @@ -955,13 +863,14 @@ vnet_ip_mroute_cmd (vlib_main_t * vm, (scount * gcount) / (timet[1] - timet[0])); done: + vec_free (rpaths); unformat_free (line_input); return error; } /*? - * This command is used to add or delete IPv4 or IPv6 multicastroutes. All + * This command is used to add or delete IPv4 or IPv6 multicast routes. All * IP Addresses ('/', * '' and '') * can be IPv4 or IPv6, but all must be of the same form in a single @@ -985,216 +894,12 @@ done: VLIB_CLI_COMMAND (ip_mroute_command, static) = { .path = "ip mroute", - .short_help = "ip mroute [add|del] / [table ] [via [],", + .short_help = "ip mroute [add|del] / [table ] [rpf-id ] [via [],", .function = vnet_ip_mroute_cmd, .is_mp_safe = 1, }; /* *INDENT-ON* */ -/* - * The next two routines address a longstanding script hemorrhoid. - * Probing a v4 or v6 neighbor needs to appear to be synchronous, - * or dependent route-adds will simply fail. - */ -static clib_error_t * -ip6_probe_neighbor_wait (vlib_main_t * vm, ip6_address_t * a, u32 sw_if_index, - int retry_count) -{ - vnet_main_t *vnm = vnet_get_main (); - clib_error_t *e; - int i; - int resolved = 0; - uword event_type; - uword *event_data = 0; - - ASSERT (vlib_in_process_context (vm)); - - if (retry_count > 0) - vnet_register_ip6_neighbor_resolution_event - (vnm, a, vlib_get_current_process (vm)->node_runtime.node_index, - 1 /* event */ , 0 /* data */ ); - - for (i = 0; i < retry_count; i++) - { - /* The interface may be down, etc. */ - e = ip6_probe_neighbor (vm, a, sw_if_index); - - if (e) - return e; - - vlib_process_wait_for_event_or_clock (vm, 1.0); - event_type = vlib_process_get_events (vm, &event_data); - switch (event_type) - { - case 1: /* resolved... */ - vlib_cli_output (vm, "Resolved %U", format_ip6_address, a); - resolved = 1; - goto done; - - case ~0: /* timeout */ - break; - - default: - clib_warning ("unknown event_type %d", event_type); - } - vec_reset_length (event_data); - } - -done: - - if (!resolved) - return clib_error_return (0, "Resolution failed for %U", - format_ip6_address, a); - return 0; -} - -static clib_error_t * -ip4_probe_neighbor_wait (vlib_main_t * vm, ip4_address_t * a, u32 sw_if_index, - int retry_count) -{ - vnet_main_t *vnm = vnet_get_main (); - clib_error_t *e; - int i; - int resolved = 0; - uword event_type; - uword *event_data = 0; - - ASSERT (vlib_in_process_context (vm)); - - if (retry_count > 0) - vnet_register_ip4_arp_resolution_event - (vnm, a, vlib_get_current_process (vm)->node_runtime.node_index, - 1 /* event */ , 0 /* data */ ); - - for (i = 0; i < retry_count; i++) - { - /* The interface may be down, etc. */ - e = ip4_probe_neighbor (vm, a, sw_if_index); - - if (e) - return e; - - vlib_process_wait_for_event_or_clock (vm, 1.0); - event_type = vlib_process_get_events (vm, &event_data); - switch (event_type) - { - case 1: /* resolved... */ - vlib_cli_output (vm, "Resolved %U", format_ip4_address, a); - resolved = 1; - goto done; - - case ~0: /* timeout */ - break; - - default: - clib_warning ("unknown event_type %d", event_type); - } - vec_reset_length (event_data); - } - -done: - - vec_reset_length (event_data); - - if (!resolved) - return clib_error_return (0, "Resolution failed for %U", - format_ip4_address, a); - return 0; -} - -static clib_error_t * -probe_neighbor_address (vlib_main_t * vm, - unformat_input_t * input, vlib_cli_command_t * cmd) -{ - vnet_main_t *vnm = vnet_get_main (); - unformat_input_t _line_input, *line_input = &_line_input; - ip4_address_t a4; - ip6_address_t a6; - clib_error_t *error = 0; - u32 sw_if_index = ~0; - int retry_count = 3; - int is_ip4 = 1; - int address_set = 0; - - /* Get a line of input. */ - if (!unformat_user (input, unformat_line_input, line_input)) - return 0; - - while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) - { - if (unformat_user (line_input, unformat_vnet_sw_interface, vnm, - &sw_if_index)) - ; - else if (unformat (line_input, "retry %d", &retry_count)) - ; - - else if (unformat (line_input, "%U", unformat_ip4_address, &a4)) - address_set++; - else if (unformat (line_input, "%U", unformat_ip6_address, &a6)) - { - address_set++; - is_ip4 = 0; - } - else - { - error = clib_error_return (0, "unknown input '%U'", - format_unformat_error, line_input); - goto done; - } - } - - if (sw_if_index == ~0) - { - error = clib_error_return (0, "Interface required, not set."); - goto done; - } - if (address_set == 0) - { - error = clib_error_return (0, "ip address required, not set."); - goto done; - } - if (address_set > 1) - { - error = clib_error_return (0, "Multiple ip addresses not supported."); - goto done; - } - - if (is_ip4) - error = ip4_probe_neighbor_wait (vm, &a4, sw_if_index, retry_count); - else - error = ip6_probe_neighbor_wait (vm, &a6, sw_if_index, retry_count); - -done: - unformat_free (line_input); - - return error; -} - -/*? - * The 'ip probe-neighbor' command ARPs for IPv4 addresses or - * attempts IPv6 neighbor discovery depending on the supplied IP address - * format. - * - * @note This command will not immediately affect the indicated FIB; it - * is not suitable for use in establishing a FIB entry prior to adding - * recursive FIB entries. As in: don't use it in a script to probe a - * gateway prior to adding a default route. It won't work. Instead, - * configure a static ARP cache entry [see 'set ip arp'], or - * a static IPv6 neighbor [see 'set ip6 neighbor']. - * - * @cliexpar - * Example of probe for an IPv4 address: - * @cliexcmd{ip probe-neighbor GigabitEthernet2/0/0 172.16.1.2} -?*/ -/* *INDENT-OFF* */ -VLIB_CLI_COMMAND (ip_probe_neighbor_command, static) = { - .path = "ip probe-neighbor", - .function = probe_neighbor_address, - .short_help = "ip probe-neighbor | [retry nn]", - .is_mp_safe = 1, -}; -/* *INDENT-ON* */ - /* * fd.io coding-style-patch-verification: ON *