From 3e046ea96e7e9d98a8dd67eab84031e1d71b4422 Mon Sep 17 00:00:00 2001 From: Pavel Kotucek Date: Mon, 5 Dec 2016 08:27:37 +0100 Subject: [PATCH] api: missing support for dumping of neighbours (VPP-333) added API to dump ipv4/ipv6 neighboors (added by ip_neighbor_add_del). Change-Id: I33209a3d06beba64d68465c0892a9f4c65657334 Signed-off-by: Pavel Kotucek --- vnet/Makefile.am | 1 + vnet/vnet/ethernet/arp.c | 52 +++++++++------------ vnet/vnet/ethernet/arp_packet.h | 22 +++++++++ vnet/vnet/ip/ip6_neighbor.c | 47 +++++++++---------- vnet/vnet/ip/ip6_neighbor.h | 42 +++++++++++++++++ vpp-api-test/vat/api_format.c | 101 ++++++++++++++++++++++++++++++++++++++-- vpp/vpp-api/api.c | 79 ++++++++++++++++++++++++++++++- vpp/vpp-api/vpe.api | 30 +++++++++++- 8 files changed, 313 insertions(+), 61 deletions(-) create mode 100644 vnet/vnet/ip/ip6_neighbor.h diff --git a/vnet/Makefile.am b/vnet/Makefile.am index fc91bcd2a7a..7cf19eb8156 100644 --- a/vnet/Makefile.am +++ b/vnet/Makefile.am @@ -322,6 +322,7 @@ nobase_include_HEADERS += \ vnet/ip/ip6_hop_by_hop.h \ vnet/ip/ip6_hop_by_hop_packet.h \ vnet/ip/ip6_packet.h \ + vnet/ip/ip6_neighbor.h \ vnet/ip/ip.h \ vnet/ip/ip_packet.h \ vnet/ip/ip_source_and_port_range_check.h \ diff --git a/vnet/vnet/ethernet/arp.c b/vnet/vnet/ethernet/arp.c index 4968d7b780d..ec138586ff4 100644 --- a/vnet/vnet/ethernet/arp.c +++ b/vnet/vnet/ethernet/arp.c @@ -36,25 +36,6 @@ void vl_api_rpc_call_main_thread (void *fp, u8 * data, u32 data_length); -typedef struct -{ - u32 sw_if_index; - ip4_address_t ip4_address; - - u8 ethernet_address[6]; - - u16 flags; -#define ETHERNET_ARP_IP4_ENTRY_FLAG_STATIC (1 << 0) -#define ETHERNET_ARP_IP4_ENTRY_FLAG_DYNAMIC (1 << 1) - - u64 cpu_time_last_updated; - - /** - * The index of the adj-fib entry created - */ - fib_node_index_t fib_entry_index; -} ethernet_arp_ip4_entry_t; - /** * @brief Per-interface ARP configuration and state */ @@ -252,7 +233,7 @@ format_ethernet_arp_header (u8 * s, va_list * va) return s; } -static u8 * +u8 * format_ethernet_arp_ip4_entry (u8 * s, va_list * va) { vnet_main_t *vnm = va_arg (*va, vnet_main_t *); @@ -1284,6 +1265,25 @@ ip4_arp_entry_sort (void *a1, void *a2) return cmp; } +ethernet_arp_ip4_entry_t * +ip4_neighbor_entries (u32 sw_if_index) +{ + ethernet_arp_main_t *am = ðernet_arp_main; + ethernet_arp_ip4_entry_t *n, *ns = 0; + + /* *INDENT-OFF* */ + pool_foreach (n, am->ip4_entry_pool, ({ + if (sw_if_index != ~0 && n->sw_if_index != sw_if_index) + continue; + vec_add1 (ns, n[0]); + })); + /* *INDENT-ON* */ + + if (ns) + vec_sort_with_function (ns, ip4_arp_entry_sort); + return ns; +} + static clib_error_t * show_ip4_arp (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) @@ -1299,22 +1299,12 @@ show_ip4_arp (vlib_main_t * vm, sw_if_index = ~0; (void) unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index); - es = 0; - /* *INDENT-OFF* */ - pool_foreach (e, am->ip4_entry_pool, - ({ - vec_add1 (es, e[0]); - })); - /* *INDENT-ON* */ - + es = ip4_neighbor_entries (sw_if_index); if (es) { - vec_sort_with_function (es, ip4_arp_entry_sort); vlib_cli_output (vm, "%U", format_ethernet_arp_ip4_entry, vnm, 0); vec_foreach (e, es) { - if (sw_if_index != ~0 && e->sw_if_index != sw_if_index) - continue; vlib_cli_output (vm, "%U", format_ethernet_arp_ip4_entry, vnm, e); } vec_free (es); diff --git a/vnet/vnet/ethernet/arp_packet.h b/vnet/vnet/ethernet/arp_packet.h index 8befb6c5115..e762ffa4018 100644 --- a/vnet/vnet/ethernet/arp_packet.h +++ b/vnet/vnet/ethernet/arp_packet.h @@ -140,6 +140,28 @@ typedef struct }; } ethernet_arp_header_t; +typedef struct +{ + u32 sw_if_index; + ip4_address_t ip4_address; + + u8 ethernet_address[6]; + + u16 flags; +#define ETHERNET_ARP_IP4_ENTRY_FLAG_STATIC (1 << 0) +#define ETHERNET_ARP_IP4_ENTRY_FLAG_DYNAMIC (1 << 1) + + u64 cpu_time_last_updated; + + /** + * The index of the adj-fib entry created + */ + fib_node_index_t fib_entry_index; +} ethernet_arp_ip4_entry_t; + +ethernet_arp_ip4_entry_t *ip4_neighbor_entries (u32 sw_if_index); +u8 *format_ethernet_arp_ip4_entry (u8 * s, va_list * va); + #endif /* included_ethernet_arp_packet_h */ /* diff --git a/vnet/vnet/ip/ip6_neighbor.c b/vnet/vnet/ip/ip6_neighbor.c index 5380950ae6b..92417a44025 100644 --- a/vnet/vnet/ip/ip6_neighbor.c +++ b/vnet/vnet/ip/ip6_neighbor.c @@ -16,6 +16,7 @@ */ #include +#include #include #include #include @@ -31,26 +32,10 @@ * adjacency tables and neighbor discovery logic. */ -typedef struct { - ip6_address_t ip6_address; - u32 sw_if_index; - u32 pad; -} ip6_neighbor_key_t; - -/* can't use sizeof link_layer_address, that's 8 */ +/* can't use sizeof link_layer_address, that's 8 */ #define ETHER_MAC_ADDR_LEN 6 -typedef struct { - ip6_neighbor_key_t key; - u8 link_layer_address[8]; - u16 flags; -#define IP6_NEIGHBOR_FLAG_STATIC (1 << 0) -#define IP6_NEIGHBOR_FLAG_DYNAMIC (2 << 0) - u64 cpu_time_last_updated; - fib_node_index_t fib_entry_index; -} ip6_neighbor_t; - -/* advertised prefix option */ +/* advertised prefix option */ typedef struct { /* basic advertised information */ ip6_address_t prefix; @@ -737,13 +722,31 @@ ip6_neighbor_sort (void *a1, void *a2) return cmp; } +ip6_neighbor_t * +ip6_neighbors_entries (u32 sw_if_index) +{ + ip6_neighbor_main_t * nm = &ip6_neighbor_main; + ip6_neighbor_t *n, *ns = 0; + + /* *INDENT-OFF* */ + pool_foreach (n, nm->neighbor_pool, ({ + if (sw_if_index != ~0 && n->key.sw_if_index != sw_if_index) + continue; + vec_add1 (ns, n[0]); + })); + /* *INDENT-ON* */ + + if (ns) + vec_sort_with_function (ns, ip6_neighbor_sort); + return ns; +} + static clib_error_t * show_ip6_neighbors (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) { vnet_main_t * vnm = vnet_get_main(); - ip6_neighbor_main_t * nm = &ip6_neighbor_main; ip6_neighbor_t * n, * ns; clib_error_t * error = 0; u32 sw_if_index; @@ -752,15 +755,11 @@ show_ip6_neighbors (vlib_main_t * vm, sw_if_index = ~0; (void) unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index); - ns = 0; - pool_foreach (n, nm->neighbor_pool, ({ vec_add1 (ns, n[0]); })); + ns = ip6_neighbors_entries (sw_if_index); if (ns) { - vec_sort_with_function (ns, ip6_neighbor_sort); vlib_cli_output (vm, "%U", format_ip6_neighbor_ip6_entry, vm, 0); vec_foreach (n, ns) { - if (sw_if_index != ~0 && n->key.sw_if_index != sw_if_index) - continue; vlib_cli_output (vm, "%U", format_ip6_neighbor_ip6_entry, vm, n); } vec_free (ns); diff --git a/vnet/vnet/ip/ip6_neighbor.h b/vnet/vnet/ip/ip6_neighbor.h new file mode 100644 index 00000000000..2d572089dc2 --- /dev/null +++ b/vnet/vnet/ip/ip6_neighbor.h @@ -0,0 +1,42 @@ +/* + * + * ip6_neighboor.h: ip6 neighbor structures + * + * Copyright (c) 2016 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. + */ + +#ifndef included_ip6_neighbor_h +#define included_ip6_neighbor_h + +#include + +typedef struct { + ip6_address_t ip6_address; + u32 sw_if_index; + u32 pad; +} ip6_neighbor_key_t; + +typedef struct { + ip6_neighbor_key_t key; + u8 link_layer_address[8]; + u16 flags; +#define IP6_NEIGHBOR_FLAG_STATIC (1 << 0) +#define IP6_NEIGHBOR_FLAG_DYNAMIC (2 << 0) + u64 cpu_time_last_updated; + fib_node_index_t fib_entry_index; +} ip6_neighbor_t; + +ip6_neighbor_t * ip6_neighbors_entries (u32 sw_if_index); + +#endif /* included_ip6_neighbor_h */ diff --git a/vpp-api-test/vat/api_format.c b/vpp-api-test/vat/api_format.c index 003fd723714..94495ded191 100644 --- a/vpp-api-test/vat/api_format.c +++ b/vpp-api-test/vat/api_format.c @@ -3917,10 +3917,11 @@ _(L2_INTERFACE_PBB_TAG_REWRITE_REPLY, l2_interface_pbb_tag_rewrite_reply) \ _(PUNT_REPLY, punt_reply) \ _(IP_FIB_DETAILS, ip_fib_details) \ _(IP6_FIB_DETAILS, ip6_fib_details) \ -_(FEATURE_ENABLE_DISABLE_REPLY, feature_enable_disable_reply) \ +_(FEATURE_ENABLE_DISABLE_REPLY, feature_enable_disable_reply) \ _(SW_INTERFACE_TAG_ADD_DEL_REPLY, sw_interface_tag_add_del_reply) \ -_(L2_XCONNECT_DETAILS, l2_xconnect_details) \ -_(SW_INTERFACE_SET_MTU_REPLY, sw_interface_set_mtu_reply) +_(L2_XCONNECT_DETAILS, l2_xconnect_details) \ +_(SW_INTERFACE_SET_MTU_REPLY, sw_interface_set_mtu_reply) \ +_(IP_NEIGHBOR_DETAILS, ip_neighbor_details) /* M: construct, but don't yet send a message */ @@ -15395,6 +15396,97 @@ api_ip_fib_dump (vat_main_t * vam) W; } +static void vl_api_ip_neighbor_details_t_handler + (vl_api_ip_neighbor_details_t * mp) +{ + vat_main_t *vam = &vat_main; + + fformat (vam->ofp, "%c %U %U\n", + (mp->is_static) ? 'S' : 'D', + format_ethernet_address, &mp->mac_address, + (mp->is_ipv6) ? format_ip6_address : format_ip4_address, + &mp->ip_address); +} + +static void vl_api_ip_neighbor_details_t_handler_json + (vl_api_ip_neighbor_details_t * mp) +{ + + vat_main_t *vam = &vat_main; + vat_json_node_t *node; + struct in_addr ip4; + struct in6_addr ip6; + + if (VAT_JSON_ARRAY != vam->json_tree.type) + { + ASSERT (VAT_JSON_NONE == vam->json_tree.type); + vat_json_init_array (&vam->json_tree); + } + node = vat_json_array_add (&vam->json_tree); + + vat_json_init_object (node); + vat_json_object_add_string_copy (node, "flag", + (mp->is_static) ? (u8 *) "static" : (u8 *) + "dynamic"); + + vat_json_object_add_string_copy (node, "link_layer", + format (0, "%U", format_ethernet_address, + &mp->mac_address)); + + if (mp->is_ipv6) + { + clib_memcpy (&ip6, &mp->ip_address, sizeof (ip6)); + vat_json_object_add_ip6 (node, "ip_address", ip6); + } + else + { + clib_memcpy (&ip4, &mp->ip_address, sizeof (ip4)); + vat_json_object_add_ip4 (node, "ip_address", ip4); + } +} + +static int +api_ip_neighbor_dump (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_ip_neighbor_dump_t *mp; + f64 timeout; + u8 is_ipv6 = 0; + u32 sw_if_index = ~0; + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "%U", unformat_sw_if_index, vam, &sw_if_index)) + ; + else if (unformat (i, "sw_if_index %d", &sw_if_index)) + ; + else if (unformat (i, "ip6")) + is_ipv6 = 1; + else + break; + } + + if (sw_if_index == ~0) + { + errmsg ("missing interface name or sw_if_index\n"); + return -99; + } + + M (IP_NEIGHBOR_DUMP, ip_neighbor_dump); + mp->is_ipv6 = (u8) is_ipv6; + mp->sw_if_index = ntohl (sw_if_index); + S; + + /* Use a control ping for synchronization */ + { + vl_api_control_ping_t *mp; + M (CONTROL_PING, control_ping); + S; + } + W; +} + #define vl_api_ip6_fib_details_t_endian vl_noop_handler #define vl_api_ip6_fib_details_t_print vl_noop_handler @@ -17480,7 +17572,8 @@ _(feature_enable_disable, "arc_name " \ _(sw_interface_tag_add_del, " | sw_if_index tag " \ "[disable]") \ _(l2_xconnect_dump, "") \ -_(sw_interface_set_mtu, " | sw_if_index mtu ") +_(sw_interface_set_mtu, " | sw_if_index mtu ") \ +_(ip_neighbor_dump, "[ip6] | sw_if_index ") /* List of command functions, CLI names map directly to functions */ #define foreach_cli_function \ diff --git a/vpp/vpp-api/api.c b/vpp/vpp-api/api.c index 004dcb70053..c0facc0d657 100644 --- a/vpp/vpp-api/api.c +++ b/vpp/vpp-api/api.c @@ -52,6 +52,7 @@ #include #include #include +#include #include #include #include @@ -328,7 +329,9 @@ _(IP_FIB_DUMP, ip_fib_dump) \ _(IP_FIB_DETAILS, ip_fib_details) \ _(IP6_FIB_DUMP, ip6_fib_dump) \ _(IP6_FIB_DETAILS, ip6_fib_details) \ -_(FEATURE_ENABLE_DISABLE, feature_enable_disable) \ +_(FEATURE_ENABLE_DISABLE, feature_enable_disable) \ +_(IP_NEIGHBOR_DUMP, ip_neighbor_dump) \ +_(IP_NEIGHBOR_DETAILS, ip_neighbor_details) #define QUOTE_(x) #x #define QUOTE(x) QUOTE_(x) @@ -8393,6 +8396,80 @@ vl_api_feature_enable_disable_t_handler (vl_api_feature_enable_disable_t * mp) REPLY_MACRO (VL_API_FEATURE_ENABLE_DISABLE_REPLY); } +static void +send_ip_neighbor_details (u8 is_ipv6, + u8 is_static, + u8 * mac_address, + u8 * ip_address, + unix_shared_memory_queue_t * q, u32 context) +{ + vl_api_ip_neighbor_details_t *mp; + + mp = vl_msg_api_alloc (sizeof (*mp)); + memset (mp, 0, sizeof (*mp)); + mp->_vl_msg_id = ntohs (VL_API_IP_NEIGHBOR_DETAILS); + mp->context = context; + mp->is_ipv6 = is_ipv6; + mp->is_static = is_static; + memcpy (mp->mac_address, mac_address, 6); + memcpy (mp->ip_address, ip_address, (is_ipv6) ? 16 : 4); + + vl_msg_api_send_shmem (q, (u8 *) & mp); +} + +static void +vl_api_ip_neighbor_details_t_handler (vl_api_ip_neighbor_details_t * mp) +{ + clib_warning ("BUG"); +} + +static void +vl_api_ip_neighbor_dump_t_handler (vl_api_ip_neighbor_dump_t * mp) +{ + unix_shared_memory_queue_t *q; + + q = vl_api_client_index_to_input_queue (mp->client_index); + if (q == 0) + return; + + u32 sw_if_index = ntohl (mp->sw_if_index); + + if (mp->is_ipv6) + { + ip6_neighbor_t *n, *ns; + + ns = ip6_neighbors_entries (sw_if_index); + /* *INDENT-OFF* */ + vec_foreach (n, ns) + { + send_ip_neighbor_details (mp->is_ipv6, + ((n->flags & IP6_NEIGHBOR_FLAG_STATIC) ? 1 : 0), + (u8 *) n->link_layer_address, + (u8 *) & (n->key.ip6_address.as_u8), + q, mp->context); + } + /* *INDENT-ON* */ + vec_free (ns); + } + else + { + ethernet_arp_ip4_entry_t *n, *ns; + + ns = ip4_neighbor_entries (sw_if_index); + /* *INDENT-OFF* */ + vec_foreach (n, ns) + { + send_ip_neighbor_details (mp->is_ipv6, + ((n->flags & ETHERNET_ARP_IP4_ENTRY_FLAG_STATIC) ? 1 : 0), + (u8*) n->ethernet_address, + (u8*) & (n->ip4_address.as_u8), + q, mp->context); + } + /* *INDENT-ON* */ + vec_free (ns); + } +} + #define BOUNCE_HANDLER(nn) \ static void vl_api_##nn##_t_handler ( \ vl_api_##nn##_t *mp) \ diff --git a/vpp/vpp-api/vpe.api b/vpp/vpp-api/vpe.api index 66108acf70c..cc444ba79ea 100644 --- a/vpp/vpp-api/vpe.api +++ b/vpp/vpp-api/vpe.api @@ -5309,8 +5309,36 @@ define feature_enable_disable_reply u32 context; i32 retval; }; + +/** \brief Dump IP neighboors + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param sw_if_index - the interface to dump neighboors + @param is_ipv6 - [1|0] to indicate if address family is ipv[6|4] +*/ +define ip_neighbor_dump +{ + u32 client_index; + u32 context; + u32 sw_if_index; + u8 is_ipv6; +}; + +/** \brief IP neighboors dump response + @param context - sender context which was passed in the request + @param is_static - [1|0] to indicate if neighbor is statically configured + @param is_ipv6 - [1|0] to indicate if address family is ipv[6|4] +*/ +define ip_neighbor_details { + u32 context; + u32 is_static; + u8 is_ipv6; + u8 mac_address[6]; + u8 ip_address[16]; +}; + /* * Local Variables: * eval: (c-set-style "gnu") * End: - */ + */ \ No newline at end of file -- 2.16.6