api: missing support for dumping of neighbours (VPP-333) 90/4090/3
authorPavel Kotucek <pkotucek@cisco.com>
Mon, 5 Dec 2016 07:27:37 +0000 (08:27 +0100)
committerDamjan Marion <dmarion.lists@gmail.com>
Tue, 6 Dec 2016 12:08:46 +0000 (12:08 +0000)
added API to dump ipv4/ipv6 neighboors (added by ip_neighbor_add_del).

Change-Id: I33209a3d06beba64d68465c0892a9f4c65657334
Signed-off-by: Pavel Kotucek <pkotucek@cisco.com>
vnet/Makefile.am
vnet/vnet/ethernet/arp.c
vnet/vnet/ethernet/arp_packet.h
vnet/vnet/ip/ip6_neighbor.c
vnet/vnet/ip/ip6_neighbor.h [new file with mode: 0644]
vpp-api-test/vat/api_format.c
vpp/vpp-api/api.c
vpp/vpp-api/vpe.api

index fc91bcd..7cf19eb 100644 (file)
@@ -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      \
index 4968d7b..ec13858 100644 (file)
 
 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 = &ethernet_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);
index 8befb6c..e762ffa 100644 (file)
@@ -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 */
 
 /*
index 5380950..92417a4 100644 (file)
@@ -16,6 +16,7 @@
  */
 
 #include <vnet/ip/ip.h>
+#include <vnet/ip/ip6_neighbor.h>
 #include <vnet/ethernet/ethernet.h>
 #include <vppinfra/mhash.h>
 #include <vppinfra/md5.h>
  * 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 (file)
index 0000000..2d57208
--- /dev/null
@@ -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 <vnet/fib/fib_types.h>
+
+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 */
index 003fd72..94495de 100644 (file)
@@ -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 <arc_name> "                        \
 _(sw_interface_tag_add_del, "<intfc> | sw_if_index <nn> tag <text>"    \
 "[disable]")                                                           \
 _(l2_xconnect_dump, "")                                                \
-_(sw_interface_set_mtu, "<intfc> | sw_if_index <nn> mtu <nn>")
+_(sw_interface_set_mtu, "<intfc> | sw_if_index <nn> mtu <nn>")        \
+_(ip_neighbor_dump, "[ip6] <intfc> | sw_if_index <nn>")
 
 /* List of command functions, CLI names map directly to functions */
 #define foreach_cli_function                                    \
index 004dcb7..c0facc0 100644 (file)
@@ -52,6 +52,7 @@
 #include <vnet/l2tp/l2tp.h>
 #include <vnet/ip/ip.h>
 #include <vnet/ip/ip6.h>
+#include <vnet/ip/ip6_neighbor.h>
 #include <vnet/unix/tuntap.h>
 #include <vnet/unix/tapcli.h>
 #include <vnet/mpls/mpls.h>
@@ -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)                                                \
index 66108ac..cc444ba 100644 (file)
@@ -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