aboutsummaryrefslogtreecommitdiffstats
path: root/src/vpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/vpp')
-rw-r--r--src/vpp/api/api.c2468
l---------src/vpp/api/api_format.c1
-rw-r--r--src/vpp/api/api_main.c250
-rw-r--r--src/vpp/api/custom_dump.c3231
-rw-r--r--src/vpp/api/gmon.c306
-rw-r--r--src/vpp/api/json_format.c304
-rw-r--r--src/vpp/api/json_format.h254
-rw-r--r--src/vpp/api/plugin.c201
-rw-r--r--src/vpp/api/plugin.h61
-rw-r--r--src/vpp/api/summary_stats_client.c302
-rw-r--r--src/vpp/api/test_client.c1526
-rw-r--r--src/vpp/api/test_ha.c249
l---------src/vpp/api/vat.h1
-rw-r--r--src/vpp/api/vpe.api936
-rw-r--r--src/vpp/api/vpe_all_api_h.h40
-rw-r--r--src/vpp/api/vpe_msg_enum.h37
-rw-r--r--src/vpp/api/vpp_get_metrics.c253
-rw-r--r--src/vpp/app/sticky_hash.c581
-rw-r--r--src/vpp/app/version.c92
-rw-r--r--src/vpp/app/vpe_cli.c136
-rw-r--r--src/vpp/app/vppctl.c384
-rw-r--r--src/vpp/conf/80-vpp.conf15
-rw-r--r--src/vpp/conf/startup.conf133
-rw-r--r--src/vpp/oam/oam.c644
-rw-r--r--src/vpp/oam/oam.h96
-rw-r--r--src/vpp/stats/stats.api265
-rw-r--r--src/vpp/stats/stats.c2410
-rw-r--r--src/vpp/stats/stats.h200
-rw-r--r--src/vpp/stats/stats.reg42
-rw-r--r--src/vpp/vnet/main.c367
30 files changed, 15785 insertions, 0 deletions
diff --git a/src/vpp/api/api.c b/src/vpp/api/api.c
new file mode 100644
index 00000000..d020314b
--- /dev/null
+++ b/src/vpp/api/api.c
@@ -0,0 +1,2468 @@
+/*
+ *------------------------------------------------------------------
+ * api.c - message handler registration
+ *
+ * Copyright (c) 2010-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.
+ *------------------------------------------------------------------
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <signal.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <time.h>
+#include <fcntl.h>
+#include <string.h>
+#include <pwd.h>
+#include <grp.h>
+
+#include <vppinfra/clib.h>
+#include <vppinfra/vec.h>
+#include <vppinfra/hash.h>
+#include <vppinfra/bitmap.h>
+#include <vppinfra/fifo.h>
+#include <vppinfra/time.h>
+#include <vppinfra/mheap.h>
+#include <vppinfra/heap.h>
+#include <vppinfra/pool.h>
+#include <vppinfra/format.h>
+#include <vppinfra/error.h>
+
+#include <vnet/api_errno.h>
+#include <vnet/vnet.h>
+#include <vnet/l2/l2_input.h>
+#include <vnet/l2/l2_bd.h>
+#include <vnet/ip/ip.h>
+#include <vnet/ip/ip6.h>
+#include <vnet/ip/ip6_neighbor.h>
+#if WITH_LIBSSL > 0
+#include <vnet/srv6/sr.h>
+#endif
+#include <vlib/vlib.h>
+#include <vlib/unix/unix.h>
+#include <vlibapi/api.h>
+#include <vlibmemory/api.h>
+#include <vnet/classify/input_acl.h>
+#include <vnet/l2/l2_classify.h>
+#include <vnet/map/map.h>
+#include <vnet/ip/ip6_hop_by_hop.h>
+#include <vnet/ip/ip_source_and_port_range_check.h>
+#include <vnet/ip/punt.h>
+#include <vnet/feature/feature.h>
+
+#undef BIHASH_TYPE
+#undef __included_bihash_template_h__
+#include <vnet/l2/l2_fib.h>
+
+#include <vpp/stats/stats.h>
+#include <vpp/oam/oam.h>
+
+#include <vnet/ethernet/ethernet.h>
+#include <vnet/ethernet/arp_packet.h>
+#include <vnet/interface.h>
+#include <vnet/l2/l2_fib.h>
+#include <vnet/l2/l2_bd.h>
+#include <vpp/api/vpe_msg_enum.h>
+#include <vnet/span/span.h>
+#include <vnet/fib/fib_api.h>
+#include <vnet/dpo/drop_dpo.h>
+#include <vnet/dpo/receive_dpo.h>
+#include <vnet/dpo/lookup_dpo.h>
+#include <vnet/dpo/classify_dpo.h>
+#include <vnet/dpo/ip_null_dpo.h>
+#define vl_typedefs /* define message structures */
+#include <vpp/api/vpe_all_api_h.h>
+#undef vl_typedefs
+#define vl_endianfun /* define message structures */
+#include <vpp/api/vpe_all_api_h.h>
+#undef vl_endianfun
+/* instantiate all the print functions we know about */
+#define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
+#define vl_printfun
+#include <vpp/api/vpe_all_api_h.h>
+#undef vl_printfun
+#include <vlibapi/api_helper_macros.h>
+#define foreach_vpe_api_msg \
+_(WANT_OAM_EVENTS, want_oam_events) \
+_(OAM_ADD_DEL, oam_add_del) \
+_(SW_INTERFACE_SET_MPLS_ENABLE, sw_interface_set_mpls_enable) \
+_(SW_INTERFACE_SET_VPATH, sw_interface_set_vpath) \
+_(SW_INTERFACE_SET_L2_XCONNECT, sw_interface_set_l2_xconnect) \
+_(SW_INTERFACE_SET_L2_BRIDGE, sw_interface_set_l2_bridge) \
+_(CREATE_VLAN_SUBIF, create_vlan_subif) \
+_(CREATE_SUBIF, create_subif) \
+_(PROXY_ARP_ADD_DEL, proxy_arp_add_del) \
+_(PROXY_ARP_INTFC_ENABLE_DISABLE, proxy_arp_intfc_enable_disable) \
+_(RESET_FIB, reset_fib) \
+_(CREATE_LOOPBACK, create_loopback) \
+_(CREATE_LOOPBACK_INSTANCE, create_loopback_instance) \
+_(CONTROL_PING, control_ping) \
+_(CLI, cli) \
+_(CLI_INBAND, cli_inband) \
+_(SET_ARP_NEIGHBOR_LIMIT, set_arp_neighbor_limit) \
+_(L2_PATCH_ADD_DEL, l2_patch_add_del) \
+_(CLASSIFY_SET_INTERFACE_IP_TABLE, classify_set_interface_ip_table) \
+_(CLASSIFY_SET_INTERFACE_L2_TABLES, classify_set_interface_l2_tables) \
+_(GET_NODE_INDEX, get_node_index) \
+_(ADD_NODE_NEXT, add_node_next) \
+_(L2_INTERFACE_EFP_FILTER, l2_interface_efp_filter) \
+_(SHOW_VERSION, show_version) \
+_(INTERFACE_NAME_RENUMBER, interface_name_renumber) \
+_(WANT_IP4_ARP_EVENTS, want_ip4_arp_events) \
+_(WANT_IP6_ND_EVENTS, want_ip6_nd_events) \
+_(INPUT_ACL_SET_INTERFACE, input_acl_set_interface) \
+_(DELETE_LOOPBACK, delete_loopback) \
+_(BD_IP_MAC_ADD_DEL, bd_ip_mac_add_del) \
+_(GET_NODE_GRAPH, get_node_graph) \
+_(IOAM_ENABLE, ioam_enable) \
+_(IOAM_DISABLE, ioam_disable) \
+_(GET_NEXT_INDEX, get_next_index) \
+_(PG_CREATE_INTERFACE, pg_create_interface) \
+_(PG_CAPTURE, pg_capture) \
+_(PG_ENABLE_DISABLE, pg_enable_disable) \
+_(IP_SOURCE_AND_PORT_RANGE_CHECK_ADD_DEL, \
+ ip_source_and_port_range_check_add_del) \
+_(IP_SOURCE_AND_PORT_RANGE_CHECK_INTERFACE_ADD_DEL, \
+ ip_source_and_port_range_check_interface_add_del) \
+_(DELETE_SUBIF, delete_subif) \
+_(PUNT, punt) \
+_(PUNT_SOCKET_REGISTER, punt_socket_register) \
+_(PUNT_SOCKET_DEREGISTER, punt_socket_deregister) \
+_(FEATURE_ENABLE_DISABLE, feature_enable_disable)
+
+#define QUOTE_(x) #x
+#define QUOTE(x) QUOTE_(x)
+typedef enum
+{
+ RESOLVE_IP4_ADD_DEL_ROUTE = 1,
+ RESOLVE_IP6_ADD_DEL_ROUTE,
+} resolve_t;
+
+static vlib_node_registration_t vpe_resolver_process_node;
+extern vpe_api_main_t vpe_api_main;
+
+static int arp_change_delete_callback (u32 pool_index, u8 * notused);
+static int nd_change_delete_callback (u32 pool_index, u8 * notused);
+
+/* Clean up all registrations belonging to the indicated client */
+static clib_error_t *
+memclnt_delete_callback (u32 client_index)
+{
+ vpe_api_main_t *vam = &vpe_api_main;
+ vpe_client_registration_t *rp;
+ uword *p;
+ int stats_memclnt_delete_callback (u32 client_index);
+
+ stats_memclnt_delete_callback (client_index);
+
+#define _(a) \
+ p = hash_get (vam->a##_registration_hash, client_index); \
+ if (p) { \
+ rp = pool_elt_at_index (vam->a##_registrations, p[0]); \
+ pool_put (vam->a##_registrations, rp); \
+ hash_unset (vam->a##_registration_hash, client_index); \
+ }
+ foreach_registration_hash;
+#undef _
+ return 0;
+}
+
+VL_MSG_API_REAPER_FUNCTION (memclnt_delete_callback);
+
+pub_sub_handler (oam_events, OAM_EVENTS);
+
+#define RESOLUTION_EVENT 1
+#define RESOLUTION_PENDING_EVENT 2
+#define IP4_ARP_EVENT 3
+#define IP6_ND_EVENT 4
+
+int ip4_add_del_route_t_handler (vl_api_ip_add_del_route_t * mp);
+
+int ip6_add_del_route_t_handler (vl_api_ip_add_del_route_t * mp);
+
+static void
+handle_ip4_arp_event (u32 pool_index)
+{
+ vpe_api_main_t *vam = &vpe_api_main;
+ vnet_main_t *vnm = vam->vnet_main;
+ vlib_main_t *vm = vam->vlib_main;
+ vl_api_ip4_arp_event_t *event;
+ vl_api_ip4_arp_event_t *mp;
+ unix_shared_memory_queue_t *q;
+
+ /* Client can cancel, die, etc. */
+ if (pool_is_free_index (vam->arp_events, pool_index))
+ return;
+
+ event = pool_elt_at_index (vam->arp_events, pool_index);
+
+ q = vl_api_client_index_to_input_queue (event->client_index);
+ if (!q)
+ {
+ (void) vnet_add_del_ip4_arp_change_event
+ (vnm, arp_change_delete_callback,
+ event->pid, &event->address,
+ vpe_resolver_process_node.index, IP4_ARP_EVENT,
+ ~0 /* pool index, notused */ , 0 /* is_add */ );
+ return;
+ }
+
+ if (q->cursize < q->maxsize)
+ {
+ mp = vl_msg_api_alloc (sizeof (*mp));
+ clib_memcpy (mp, event, sizeof (*mp));
+ vl_msg_api_send_shmem (q, (u8 *) & mp);
+ }
+ else
+ {
+ static f64 last_time;
+ /*
+ * Throttle syslog msgs.
+ * It's pretty tempting to just revoke the registration...
+ */
+ if (vlib_time_now (vm) > last_time + 10.0)
+ {
+ clib_warning ("arp event for %U to pid %d: queue stuffed!",
+ format_ip4_address, &event->address, event->pid);
+ last_time = vlib_time_now (vm);
+ }
+ }
+}
+
+void
+handle_ip6_nd_event (u32 pool_index)
+{
+ vpe_api_main_t *vam = &vpe_api_main;
+ vnet_main_t *vnm = vam->vnet_main;
+ vlib_main_t *vm = vam->vlib_main;
+ vl_api_ip6_nd_event_t *event;
+ vl_api_ip6_nd_event_t *mp;
+ unix_shared_memory_queue_t *q;
+
+ /* Client can cancel, die, etc. */
+ if (pool_is_free_index (vam->nd_events, pool_index))
+ return;
+
+ event = pool_elt_at_index (vam->nd_events, pool_index);
+
+ q = vl_api_client_index_to_input_queue (event->client_index);
+ if (!q)
+ {
+ (void) vnet_add_del_ip6_nd_change_event
+ (vnm, nd_change_delete_callback,
+ event->pid, &event->address,
+ vpe_resolver_process_node.index, IP6_ND_EVENT,
+ ~0 /* pool index, notused */ , 0 /* is_add */ );
+ return;
+ }
+
+ if (q->cursize < q->maxsize)
+ {
+ mp = vl_msg_api_alloc (sizeof (*mp));
+ clib_memcpy (mp, event, sizeof (*mp));
+ vl_msg_api_send_shmem (q, (u8 *) & mp);
+ }
+ else
+ {
+ static f64 last_time;
+ /*
+ * Throttle syslog msgs.
+ * It's pretty tempting to just revoke the registration...
+ */
+ if (vlib_time_now (vm) > last_time + 10.0)
+ {
+ clib_warning ("ip6 nd event for %U to pid %d: queue stuffed!",
+ format_ip6_address, &event->address, event->pid);
+ last_time = vlib_time_now (vm);
+ }
+ }
+}
+
+static uword
+resolver_process (vlib_main_t * vm,
+ vlib_node_runtime_t * rt, vlib_frame_t * f)
+{
+ volatile f64 timeout = 100.0;
+ volatile uword *event_data = 0;
+
+ while (1)
+ {
+ vlib_process_wait_for_event_or_clock (vm, timeout);
+
+ uword event_type =
+ vlib_process_get_events (vm, (uword **) & event_data);
+
+ int i;
+ switch (event_type)
+ {
+ case RESOLUTION_PENDING_EVENT:
+ timeout = 1.0;
+ break;
+
+ case RESOLUTION_EVENT:
+ clib_warning ("resolver: BOGUS TYPE");
+ break;
+
+ case IP4_ARP_EVENT:
+ for (i = 0; i < vec_len (event_data); i++)
+ handle_ip4_arp_event (event_data[i]);
+ break;
+
+ case IP6_ND_EVENT:
+ for (i = 0; i < vec_len (event_data); i++)
+ handle_ip6_nd_event (event_data[i]);
+ break;
+
+ case ~0: /* timeout */
+ break;
+ }
+
+ vec_reset_length (event_data);
+ }
+ return 0; /* or not */
+}
+
+/* *INDENT-OFF* */
+VLIB_REGISTER_NODE (vpe_resolver_process_node,static) = {
+ .function = resolver_process,
+ .type = VLIB_NODE_TYPE_PROCESS,
+ .name = "vpe-route-resolver-process",
+};
+/* *INDENT-ON* */
+
+static void
+vl_api_sw_interface_set_vpath_t_handler (vl_api_sw_interface_set_vpath_t * mp)
+{
+ vl_api_sw_interface_set_vpath_reply_t *rmp;
+ int rv = 0;
+ u32 sw_if_index = ntohl (mp->sw_if_index);
+
+ VALIDATE_SW_IF_INDEX (mp);
+
+ l2input_intf_bitmap_enable (sw_if_index, L2INPUT_FEAT_VPATH, mp->enable);
+ vnet_feature_enable_disable ("ip4-unicast", "vpath-input-ip4",
+ sw_if_index, mp->enable, 0, 0);
+ vnet_feature_enable_disable ("ip4-multicast", "vpath-input-ip4",
+ sw_if_index, mp->enable, 0, 0);
+ vnet_feature_enable_disable ("ip6-unicast", "vpath-input-ip6",
+ sw_if_index, mp->enable, 0, 0);
+ vnet_feature_enable_disable ("ip6-multicast", "vpath-input-ip6",
+ sw_if_index, mp->enable, 0, 0);
+
+ BAD_SW_IF_INDEX_LABEL;
+
+ REPLY_MACRO (VL_API_SW_INTERFACE_SET_VPATH_REPLY);
+}
+
+static void
+ vl_api_sw_interface_set_l2_xconnect_t_handler
+ (vl_api_sw_interface_set_l2_xconnect_t * mp)
+{
+ vl_api_sw_interface_set_l2_xconnect_reply_t *rmp;
+ int rv = 0;
+ u32 rx_sw_if_index = ntohl (mp->rx_sw_if_index);
+ u32 tx_sw_if_index = ntohl (mp->tx_sw_if_index);
+ vlib_main_t *vm = vlib_get_main ();
+ vnet_main_t *vnm = vnet_get_main ();
+
+ VALIDATE_RX_SW_IF_INDEX (mp);
+
+ if (mp->enable)
+ {
+ VALIDATE_TX_SW_IF_INDEX (mp);
+ rv = set_int_l2_mode (vm, vnm, MODE_L2_XC,
+ rx_sw_if_index, 0, 0, 0, tx_sw_if_index);
+ }
+ else
+ {
+ rv = set_int_l2_mode (vm, vnm, MODE_L3, rx_sw_if_index, 0, 0, 0, 0);
+ }
+
+ BAD_RX_SW_IF_INDEX_LABEL;
+ BAD_TX_SW_IF_INDEX_LABEL;
+
+ REPLY_MACRO (VL_API_SW_INTERFACE_SET_L2_XCONNECT_REPLY);
+}
+
+static void
+ vl_api_sw_interface_set_l2_bridge_t_handler
+ (vl_api_sw_interface_set_l2_bridge_t * mp)
+{
+ bd_main_t *bdm = &bd_main;
+ vl_api_sw_interface_set_l2_bridge_reply_t *rmp;
+ int rv = 0;
+ vlib_main_t *vm = vlib_get_main ();
+ vnet_main_t *vnm = vnet_get_main ();
+
+ VALIDATE_RX_SW_IF_INDEX (mp);
+ u32 rx_sw_if_index = ntohl (mp->rx_sw_if_index);
+
+
+ if (mp->enable)
+ {
+ VALIDATE_BD_ID (mp);
+ u32 bd_id = ntohl (mp->bd_id);
+ u32 bd_index = bd_find_or_add_bd_index (bdm, bd_id);
+ u32 bvi = mp->bvi;
+ u8 shg = mp->shg;
+ rv = set_int_l2_mode (vm, vnm, MODE_L2_BRIDGE,
+ rx_sw_if_index, bd_index, bvi, shg, 0);
+ }
+ else
+ {
+ rv = set_int_l2_mode (vm, vnm, MODE_L3, rx_sw_if_index, 0, 0, 0, 0);
+ }
+
+ BAD_RX_SW_IF_INDEX_LABEL;
+ BAD_BD_ID_LABEL;
+
+ REPLY_MACRO (VL_API_SW_INTERFACE_SET_L2_BRIDGE_REPLY);
+}
+
+static void
+vl_api_bd_ip_mac_add_del_t_handler (vl_api_bd_ip_mac_add_del_t * mp)
+{
+ bd_main_t *bdm = &bd_main;
+ vl_api_bd_ip_mac_add_del_reply_t *rmp;
+ int rv = 0;
+ u32 bd_id = ntohl (mp->bd_id);
+ u32 bd_index;
+ uword *p;
+
+ if (bd_id == 0)
+ {
+ rv = VNET_API_ERROR_BD_NOT_MODIFIABLE;
+ goto out;
+ }
+
+ p = hash_get (bdm->bd_index_by_bd_id, bd_id);
+ if (p == 0)
+ {
+ rv = VNET_API_ERROR_NO_SUCH_ENTRY;
+ goto out;
+ }
+
+ bd_index = p[0];
+ if (bd_add_del_ip_mac (bd_index, mp->ip_address,
+ mp->mac_address, mp->is_ipv6, mp->is_add))
+ rv = VNET_API_ERROR_UNSPECIFIED;
+
+out:
+ REPLY_MACRO (VL_API_BD_IP_MAC_ADD_DEL_REPLY);
+}
+
+static void
+vl_api_create_vlan_subif_t_handler (vl_api_create_vlan_subif_t * mp)
+{
+ vl_api_create_vlan_subif_reply_t *rmp;
+ vnet_main_t *vnm = vnet_get_main ();
+ u32 sw_if_index = (u32) ~ 0;
+ vnet_hw_interface_t *hi;
+ int rv = 0;
+ u32 id;
+ vnet_sw_interface_t template;
+ uword *p;
+ vnet_interface_main_t *im = &vnm->interface_main;
+ u64 sup_and_sub_key;
+ unix_shared_memory_queue_t *q;
+ clib_error_t *error;
+
+ VALIDATE_SW_IF_INDEX (mp);
+
+ hi = vnet_get_sup_hw_interface (vnm, ntohl (mp->sw_if_index));
+
+ if (hi->bond_info == VNET_HW_INTERFACE_BOND_INFO_SLAVE)
+ {
+ rv = VNET_API_ERROR_BOND_SLAVE_NOT_ALLOWED;
+ goto out;
+ }
+
+ id = ntohl (mp->vlan_id);
+ if (id == 0 || id > 4095)
+ {
+ rv = VNET_API_ERROR_INVALID_VLAN;
+ goto out;
+ }
+
+ sup_and_sub_key = ((u64) (hi->sw_if_index) << 32) | (u64) id;
+
+ p = hash_get_mem (im->sw_if_index_by_sup_and_sub, &sup_and_sub_key);
+ if (p)
+ {
+ rv = VNET_API_ERROR_VLAN_ALREADY_EXISTS;
+ goto out;
+ }
+
+ memset (&template, 0, sizeof (template));
+ template.type = VNET_SW_INTERFACE_TYPE_SUB;
+ template.sup_sw_if_index = hi->sw_if_index;
+ template.sub.id = id;
+ template.sub.eth.raw_flags = 0;
+ template.sub.eth.flags.one_tag = 1;
+ template.sub.eth.outer_vlan_id = id;
+ template.sub.eth.flags.exact_match = 1;
+
+ error = vnet_create_sw_interface (vnm, &template, &sw_if_index);
+ if (error)
+ {
+ clib_error_report (error);
+ rv = VNET_API_ERROR_INVALID_REGISTRATION;
+ goto out;
+ }
+
+ u64 *kp = clib_mem_alloc (sizeof (*kp));
+ *kp = sup_and_sub_key;
+
+ 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);
+
+ BAD_SW_IF_INDEX_LABEL;
+
+out:
+ q = vl_api_client_index_to_input_queue (mp->client_index);
+ if (!q)
+ return;
+
+ rmp = vl_msg_api_alloc (sizeof (*rmp));
+ rmp->_vl_msg_id = htons (VL_API_CREATE_VLAN_SUBIF_REPLY);
+ rmp->context = mp->context;
+ rmp->retval = htonl (rv);
+ rmp->sw_if_index = htonl (sw_if_index);
+ vl_msg_api_send_shmem (q, (u8 *) & rmp);
+}
+
+static void
+vl_api_create_subif_t_handler (vl_api_create_subif_t * mp)
+{
+ vl_api_create_subif_reply_t *rmp;
+ vnet_main_t *vnm = vnet_get_main ();
+ u32 sw_if_index = ~0;
+ int rv = 0;
+ u32 sub_id;
+ vnet_sw_interface_t *si;
+ vnet_hw_interface_t *hi;
+ vnet_sw_interface_t template;
+ uword *p;
+ vnet_interface_main_t *im = &vnm->interface_main;
+ u64 sup_and_sub_key;
+ clib_error_t *error;
+
+ VALIDATE_SW_IF_INDEX (mp);
+
+ si = vnet_get_sup_sw_interface (vnm, ntohl (mp->sw_if_index));
+ hi = vnet_get_sup_hw_interface (vnm, ntohl (mp->sw_if_index));
+
+ if (hi->bond_info == VNET_HW_INTERFACE_BOND_INFO_SLAVE)
+ {
+ rv = VNET_API_ERROR_BOND_SLAVE_NOT_ALLOWED;
+ goto out;
+ }
+
+ sw_if_index = si->sw_if_index;
+ sub_id = ntohl (mp->sub_id);
+
+ sup_and_sub_key = ((u64) (sw_if_index) << 32) | (u64) sub_id;
+
+ 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",
+ sw_if_index, sub_id);
+ rv = VNET_API_ERROR_SUBIF_ALREADY_EXISTS;
+ goto out;
+ }
+
+ memset (&template, 0, sizeof (template));
+ template.type = VNET_SW_INTERFACE_TYPE_SUB;
+ template.sup_sw_if_index = sw_if_index;
+ template.sub.id = sub_id;
+ template.sub.eth.flags.no_tags = mp->no_tags;
+ template.sub.eth.flags.one_tag = mp->one_tag;
+ template.sub.eth.flags.two_tags = mp->two_tags;
+ template.sub.eth.flags.dot1ad = mp->dot1ad;
+ template.sub.eth.flags.exact_match = mp->exact_match;
+ template.sub.eth.flags.default_sub = mp->default_sub;
+ template.sub.eth.flags.outer_vlan_id_any = mp->outer_vlan_id_any;
+ template.sub.eth.flags.inner_vlan_id_any = mp->inner_vlan_id_any;
+ template.sub.eth.outer_vlan_id = ntohs (mp->outer_vlan_id);
+ template.sub.eth.inner_vlan_id = ntohs (mp->inner_vlan_id);
+
+ error = vnet_create_sw_interface (vnm, &template, &sw_if_index);
+ if (error)
+ {
+ clib_error_report (error);
+ rv = VNET_API_ERROR_SUBIF_CREATE_FAILED;
+ goto out;
+ }
+
+ u64 *kp = clib_mem_alloc (sizeof (*kp));
+ *kp = sup_and_sub_key;
+
+ hash_set (hi->sub_interface_sw_if_index_by_id, sub_id, sw_if_index);
+ hash_set_mem (im->sw_if_index_by_sup_and_sub, kp, sw_if_index);
+
+ BAD_SW_IF_INDEX_LABEL;
+
+out:
+
+ /* *INDENT-OFF* */
+ REPLY_MACRO2(VL_API_CREATE_SUBIF_REPLY,
+ ({
+ rmp->sw_if_index = ntohl(sw_if_index);
+ }));
+ /* *INDENT-ON* */
+}
+
+static void
+vl_api_proxy_arp_add_del_t_handler (vl_api_proxy_arp_add_del_t * mp)
+{
+ vl_api_proxy_arp_add_del_reply_t *rmp;
+ u32 fib_index;
+ int rv;
+ ip4_main_t *im = &ip4_main;
+ stats_main_t *sm = &stats_main;
+ int vnet_proxy_arp_add_del (ip4_address_t * lo_addr,
+ ip4_address_t * hi_addr,
+ u32 fib_index, int is_del);
+ uword *p;
+
+ dslock (sm, 1 /* release hint */ , 6 /* tag */ );
+
+ p = hash_get (im->fib_index_by_table_id, ntohl (mp->vrf_id));
+
+ if (!p)
+ {
+ rv = VNET_API_ERROR_NO_SUCH_FIB;
+ goto out;
+ }
+
+ fib_index = p[0];
+
+ rv = vnet_proxy_arp_add_del ((ip4_address_t *) mp->low_address,
+ (ip4_address_t *) mp->hi_address,
+ fib_index, mp->is_add == 0);
+
+out:
+ dsunlock (sm);
+ REPLY_MACRO (VL_API_PROXY_ARP_ADD_DEL_REPLY);
+}
+
+static void
+ vl_api_proxy_arp_intfc_enable_disable_t_handler
+ (vl_api_proxy_arp_intfc_enable_disable_t * mp)
+{
+ int rv = 0;
+ vnet_main_t *vnm = vnet_get_main ();
+ vl_api_proxy_arp_intfc_enable_disable_reply_t *rmp;
+
+ VALIDATE_SW_IF_INDEX (mp);
+
+ vnet_sw_interface_t *si =
+ vnet_get_sw_interface (vnm, ntohl (mp->sw_if_index));
+
+ ASSERT (si);
+
+ if (mp->enable_disable)
+ si->flags |= VNET_SW_INTERFACE_FLAG_PROXY_ARP;
+ else
+ si->flags &= ~VNET_SW_INTERFACE_FLAG_PROXY_ARP;
+
+ BAD_SW_IF_INDEX_LABEL;
+
+ REPLY_MACRO (VL_API_PROXY_ARP_INTFC_ENABLE_DISABLE_REPLY);
+}
+
+static void
+ vl_api_sw_interface_set_mpls_enable_t_handler
+ (vl_api_sw_interface_set_mpls_enable_t * mp)
+{
+ vl_api_sw_interface_set_mpls_enable_reply_t *rmp;
+ int rv = 0;
+
+ VALIDATE_SW_IF_INDEX (mp);
+
+ rv = mpls_sw_interface_enable_disable (&mpls_main,
+ ntohl (mp->sw_if_index),
+ mp->enable, 1);
+
+ BAD_SW_IF_INDEX_LABEL;
+ REPLY_MACRO (VL_API_SW_INTERFACE_SET_MPLS_ENABLE_REPLY);
+}
+
+void
+send_oam_event (oam_target_t * t)
+{
+ vpe_api_main_t *vam = &vpe_api_main;
+ unix_shared_memory_queue_t *q;
+ vpe_client_registration_t *reg;
+ vl_api_oam_event_t *mp;
+
+ /* *INDENT-OFF* */
+ pool_foreach(reg, vam->oam_events_registrations,
+ ({
+ q = vl_api_client_index_to_input_queue (reg->client_index);
+ if (q)
+ {
+ mp = vl_msg_api_alloc (sizeof (*mp));
+ mp->_vl_msg_id = ntohs (VL_API_OAM_EVENT);
+ clib_memcpy (mp->dst_address, &t->dst_address,
+ sizeof (mp->dst_address));
+ mp->state = t->state;
+ vl_msg_api_send_shmem (q, (u8 *)&mp);
+ }
+ }));
+ /* *INDENT-ON* */
+}
+
+static void
+vl_api_oam_add_del_t_handler (vl_api_oam_add_del_t * mp)
+{
+ vl_api_oam_add_del_reply_t *rmp;
+ int rv;
+
+ rv = vpe_oam_add_del_target ((ip4_address_t *) mp->src_address,
+ (ip4_address_t *) mp->dst_address,
+ ntohl (mp->vrf_id), (int) (mp->is_add));
+
+ REPLY_MACRO (VL_API_OAM_ADD_DEL_REPLY);
+}
+
+
+static int
+ip4_reset_fib_t_handler (vl_api_reset_fib_t * mp)
+{
+ vnet_main_t *vnm = vnet_get_main ();
+ vnet_interface_main_t *im = &vnm->interface_main;
+ ip4_main_t *im4 = &ip4_main;
+ static u32 *sw_if_indices_to_shut;
+ stats_main_t *sm = &stats_main;
+ fib_table_t *fib_table;
+ ip4_fib_t *fib;
+ u32 sw_if_index;
+ int i;
+ int rv = VNET_API_ERROR_NO_SUCH_FIB;
+ u32 target_fib_id = ntohl (mp->vrf_id);
+
+ dslock (sm, 1 /* release hint */ , 8 /* tag */ );
+
+ /* *INDENT-OFF* */
+ pool_foreach (fib_table, im4->fibs,
+ ({
+ vnet_sw_interface_t * si;
+
+ fib = pool_elt_at_index (im4->v4_fibs, fib_table->ft_index);
+
+ if (fib->table_id != target_fib_id)
+ continue;
+
+ /* remove any mpls encap/decap labels */
+ mpls_fib_reset_labels (fib->table_id);
+
+ /* remove any proxy arps in this fib */
+ vnet_proxy_arp_fib_reset (fib->table_id);
+
+ /* Set the flow hash for this fib to the default */
+ vnet_set_ip4_flow_hash (fib->table_id, IP_FLOW_HASH_DEFAULT);
+
+ vec_reset_length (sw_if_indices_to_shut);
+
+ /* Shut down interfaces in this FIB / clean out intfc routes */
+ pool_foreach (si, im->sw_interfaces,
+ ({
+ u32 sw_if_index = si->sw_if_index;
+
+ if (sw_if_index < vec_len (im4->fib_index_by_sw_if_index)
+ && (im4->fib_index_by_sw_if_index[si->sw_if_index] ==
+ fib->index))
+ vec_add1 (sw_if_indices_to_shut, si->sw_if_index);
+ }));
+
+ for (i = 0; i < vec_len (sw_if_indices_to_shut); i++) {
+ sw_if_index = sw_if_indices_to_shut[i];
+
+ u32 flags = vnet_sw_interface_get_flags (vnm, sw_if_index);
+ flags &= ~(VNET_SW_INTERFACE_FLAG_ADMIN_UP);
+ vnet_sw_interface_set_flags (vnm, sw_if_index, flags);
+ }
+
+ fib_table_flush(fib->index, FIB_PROTOCOL_IP4, FIB_SOURCE_API);
+
+ rv = 0;
+ break;
+ })); /* pool_foreach (fib) */
+ /* *INDENT-ON* */
+
+ dsunlock (sm);
+ return rv;
+}
+
+static int
+ip6_reset_fib_t_handler (vl_api_reset_fib_t * mp)
+{
+ vnet_main_t *vnm = vnet_get_main ();
+ vnet_interface_main_t *im = &vnm->interface_main;
+ ip6_main_t *im6 = &ip6_main;
+ stats_main_t *sm = &stats_main;
+ static u32 *sw_if_indices_to_shut;
+ fib_table_t *fib_table;
+ ip6_fib_t *fib;
+ u32 sw_if_index;
+ int i;
+ int rv = VNET_API_ERROR_NO_SUCH_FIB;
+ u32 target_fib_id = ntohl (mp->vrf_id);
+
+ dslock (sm, 1 /* release hint */ , 9 /* tag */ );
+
+ /* *INDENT-OFF* */
+ pool_foreach (fib_table, im6->fibs,
+ ({
+ vnet_sw_interface_t * si;
+
+ fib = pool_elt_at_index (im6->v6_fibs, fib_table->ft_index);
+
+ if (fib->table_id != target_fib_id)
+ continue;
+
+ vec_reset_length (sw_if_indices_to_shut);
+
+ /* Set the flow hash for this fib to the default */
+ vnet_set_ip6_flow_hash (fib->table_id, IP_FLOW_HASH_DEFAULT);
+
+ /* Shut down interfaces in this FIB / clean out intfc routes */
+ pool_foreach (si, im->sw_interfaces,
+ ({
+ if (im6->fib_index_by_sw_if_index[si->sw_if_index] ==
+ fib->index)
+ vec_add1 (sw_if_indices_to_shut, si->sw_if_index);
+ }));
+
+ for (i = 0; i < vec_len (sw_if_indices_to_shut); i++) {
+ sw_if_index = sw_if_indices_to_shut[i];
+
+ u32 flags = vnet_sw_interface_get_flags (vnm, sw_if_index);
+ flags &= ~(VNET_SW_INTERFACE_FLAG_ADMIN_UP);
+ vnet_sw_interface_set_flags (vnm, sw_if_index, flags);
+ }
+
+ fib_table_flush(fib->index, FIB_PROTOCOL_IP6, FIB_SOURCE_API);
+
+ rv = 0;
+ break;
+ })); /* pool_foreach (fib) */
+ /* *INDENT-ON* */
+
+ dsunlock (sm);
+ return rv;
+}
+
+static void
+vl_api_reset_fib_t_handler (vl_api_reset_fib_t * mp)
+{
+ int rv;
+ vl_api_reset_fib_reply_t *rmp;
+
+ if (mp->is_ipv6)
+ rv = ip6_reset_fib_t_handler (mp);
+ else
+ rv = ip4_reset_fib_t_handler (mp);
+
+ REPLY_MACRO (VL_API_RESET_FIB_REPLY);
+}
+
+static void
+vl_api_create_loopback_t_handler (vl_api_create_loopback_t * mp)
+{
+ vl_api_create_loopback_reply_t *rmp;
+ u32 sw_if_index;
+ int rv;
+
+ rv = vnet_create_loopback_interface (&sw_if_index, mp->mac_address, 0, 0);
+
+ /* *INDENT-OFF* */
+ REPLY_MACRO2(VL_API_CREATE_LOOPBACK_REPLY,
+ ({
+ rmp->sw_if_index = ntohl (sw_if_index);
+ }));
+ /* *INDENT-ON* */
+}
+
+static void vl_api_create_loopback_instance_t_handler
+ (vl_api_create_loopback_instance_t * mp)
+{
+ vl_api_create_loopback_instance_reply_t *rmp;
+ u32 sw_if_index;
+ u8 is_specified = mp->is_specified;
+ u32 user_instance = ntohl (mp->user_instance);
+ int rv;
+
+ rv = vnet_create_loopback_interface (&sw_if_index, mp->mac_address,
+ is_specified, user_instance);
+
+ /* *INDENT-OFF* */
+ REPLY_MACRO2(VL_API_CREATE_LOOPBACK_INSTANCE_REPLY,
+ ({
+ rmp->sw_if_index = ntohl (sw_if_index);
+ }));
+ /* *INDENT-ON* */
+}
+
+static void
+vl_api_delete_loopback_t_handler (vl_api_delete_loopback_t * mp)
+{
+ vl_api_delete_loopback_reply_t *rmp;
+ u32 sw_if_index;
+ int rv;
+
+ sw_if_index = ntohl (mp->sw_if_index);
+ rv = vnet_delete_loopback_interface (sw_if_index);
+
+ REPLY_MACRO (VL_API_DELETE_LOOPBACK_REPLY);
+}
+
+static void
+vl_api_control_ping_t_handler (vl_api_control_ping_t * mp)
+{
+ vl_api_control_ping_reply_t *rmp;
+ int rv = 0;
+
+ /* *INDENT-OFF* */
+ REPLY_MACRO2(VL_API_CONTROL_PING_REPLY,
+ ({
+ rmp->vpe_pid = ntohl (getpid());
+ }));
+ /* *INDENT-ON* */
+}
+
+static void
+shmem_cli_output (uword arg, u8 * buffer, uword buffer_bytes)
+{
+ u8 **shmem_vecp = (u8 **) arg;
+ u8 *shmem_vec;
+ void *oldheap;
+ api_main_t *am = &api_main;
+ u32 offset;
+
+ shmem_vec = *shmem_vecp;
+
+ offset = vec_len (shmem_vec);
+
+ pthread_mutex_lock (&am->vlib_rp->mutex);
+ oldheap = svm_push_data_heap (am->vlib_rp);
+
+ vec_validate (shmem_vec, offset + buffer_bytes - 1);
+
+ clib_memcpy (shmem_vec + offset, buffer, buffer_bytes);
+
+ svm_pop_heap (oldheap);
+ pthread_mutex_unlock (&am->vlib_rp->mutex);
+
+ *shmem_vecp = shmem_vec;
+}
+
+
+static void
+vl_api_cli_t_handler (vl_api_cli_t * mp)
+{
+ vl_api_cli_reply_t *rp;
+ unix_shared_memory_queue_t *q;
+ vlib_main_t *vm = vlib_get_main ();
+ api_main_t *am = &api_main;
+ unformat_input_t input;
+ u8 *shmem_vec = 0;
+ void *oldheap;
+
+ q = vl_api_client_index_to_input_queue (mp->client_index);
+ if (!q)
+ return;
+
+ rp = vl_msg_api_alloc (sizeof (*rp));
+ rp->_vl_msg_id = ntohs (VL_API_CLI_REPLY);
+ rp->context = mp->context;
+
+ unformat_init_vector (&input, (u8 *) (uword) mp->cmd_in_shmem);
+
+ vlib_cli_input (vm, &input, shmem_cli_output, (uword) & shmem_vec);
+
+ pthread_mutex_lock (&am->vlib_rp->mutex);
+ oldheap = svm_push_data_heap (am->vlib_rp);
+
+ vec_add1 (shmem_vec, 0);
+
+ svm_pop_heap (oldheap);
+ pthread_mutex_unlock (&am->vlib_rp->mutex);
+
+ rp->reply_in_shmem = (uword) shmem_vec;
+
+ vl_msg_api_send_shmem (q, (u8 *) & rp);
+}
+
+static void
+inband_cli_output (uword arg, u8 * buffer, uword buffer_bytes)
+{
+ u8 **mem_vecp = (u8 **) arg;
+ u8 *mem_vec = *mem_vecp;
+ u32 offset = vec_len (mem_vec);
+
+ vec_validate (mem_vec, offset + buffer_bytes - 1);
+ clib_memcpy (mem_vec + offset, buffer, buffer_bytes);
+ *mem_vecp = mem_vec;
+}
+
+static void
+vl_api_cli_inband_t_handler (vl_api_cli_inband_t * mp)
+{
+ vl_api_cli_inband_reply_t *rmp;
+ int rv = 0;
+ unix_shared_memory_queue_t *q;
+ vlib_main_t *vm = vlib_get_main ();
+ unformat_input_t input;
+ u8 *out_vec = 0;
+
+ q = vl_api_client_index_to_input_queue (mp->client_index);
+ if (!q)
+ return;
+
+ unformat_init_string (&input, (char *) mp->cmd, ntohl (mp->length));
+ vlib_cli_input (vm, &input, inband_cli_output, (uword) & out_vec);
+
+ u32 len = vec_len (out_vec);
+ /* *INDENT-OFF* */
+ REPLY_MACRO3(VL_API_CLI_INBAND_REPLY, len,
+ ({
+ rmp->length = htonl (len);
+ clib_memcpy (rmp->reply, out_vec, len);
+ }));
+ /* *INDENT-ON* */
+ vec_free (out_vec);
+}
+
+static void
+vl_api_set_arp_neighbor_limit_t_handler (vl_api_set_arp_neighbor_limit_t * mp)
+{
+ int rv;
+ vl_api_set_arp_neighbor_limit_reply_t *rmp;
+ vnet_main_t *vnm = vnet_get_main ();
+ clib_error_t *error;
+
+ vnm->api_errno = 0;
+
+ if (mp->is_ipv6)
+ error = ip6_set_neighbor_limit (ntohl (mp->arp_neighbor_limit));
+ else
+ error = ip4_set_arp_limit (ntohl (mp->arp_neighbor_limit));
+
+ if (error)
+ {
+ clib_error_report (error);
+ rv = VNET_API_ERROR_UNSPECIFIED;
+ }
+ else
+ {
+ rv = vnm->api_errno;
+ }
+
+ REPLY_MACRO (VL_API_SET_ARP_NEIGHBOR_LIMIT_REPLY);
+}
+
+static void vl_api_classify_set_interface_ip_table_t_handler
+ (vl_api_classify_set_interface_ip_table_t * mp)
+{
+ vlib_main_t *vm = vlib_get_main ();
+ vl_api_classify_set_interface_ip_table_reply_t *rmp;
+ int rv;
+
+ VALIDATE_SW_IF_INDEX (mp);
+
+ u32 table_index = ntohl (mp->table_index);
+ u32 sw_if_index = ntohl (mp->sw_if_index);
+
+ if (mp->is_ipv6)
+ rv = vnet_set_ip6_classify_intfc (vm, sw_if_index, table_index);
+ else
+ rv = vnet_set_ip4_classify_intfc (vm, sw_if_index, table_index);
+
+ BAD_SW_IF_INDEX_LABEL;
+
+ REPLY_MACRO (VL_API_CLASSIFY_SET_INTERFACE_IP_TABLE_REPLY);
+}
+
+static void vl_api_classify_set_interface_l2_tables_t_handler
+ (vl_api_classify_set_interface_l2_tables_t * mp)
+{
+ vl_api_classify_set_interface_l2_tables_reply_t *rmp;
+ int rv;
+ u32 sw_if_index, ip4_table_index, ip6_table_index, other_table_index;
+ int enable;
+
+ ip4_table_index = ntohl (mp->ip4_table_index);
+ ip6_table_index = ntohl (mp->ip6_table_index);
+ other_table_index = ntohl (mp->other_table_index);
+ sw_if_index = ntohl (mp->sw_if_index);
+
+ VALIDATE_SW_IF_INDEX (mp);
+
+ if (mp->is_input)
+ rv = vnet_l2_input_classify_set_tables (sw_if_index, ip4_table_index,
+ ip6_table_index,
+ other_table_index);
+ else
+ rv = vnet_l2_output_classify_set_tables (sw_if_index, ip4_table_index,
+ ip6_table_index,
+ other_table_index);
+
+ if (rv == 0)
+ {
+ if (ip4_table_index != ~0 || ip6_table_index != ~0
+ || other_table_index != ~0)
+ enable = 1;
+ else
+ enable = 0;
+
+ if (mp->is_input)
+ vnet_l2_input_classify_enable_disable (sw_if_index, enable);
+ else
+ vnet_l2_output_classify_enable_disable (sw_if_index, enable);
+ }
+
+ BAD_SW_IF_INDEX_LABEL;
+
+ REPLY_MACRO (VL_API_CLASSIFY_SET_INTERFACE_L2_TABLES_REPLY);
+}
+
+extern void l2_efp_filter_configure (vnet_main_t * vnet_main,
+ u32 sw_if_index, u32 enable);
+
+static void
+vl_api_l2_interface_efp_filter_t_handler (vl_api_l2_interface_efp_filter_t *
+ mp)
+{
+ int rv;
+ vl_api_l2_interface_efp_filter_reply_t *rmp;
+ vnet_main_t *vnm = vnet_get_main ();
+
+ // enable/disable the feature
+ l2_efp_filter_configure (vnm, mp->sw_if_index, mp->enable_disable);
+ rv = vnm->api_errno;
+
+ REPLY_MACRO (VL_API_L2_INTERFACE_EFP_FILTER_REPLY);
+}
+
+static void
+vl_api_show_version_t_handler (vl_api_show_version_t * mp)
+{
+ vl_api_show_version_reply_t *rmp;
+ int rv = 0;
+ char *vpe_api_get_build_directory (void);
+ char *vpe_api_get_version (void);
+ char *vpe_api_get_build_date (void);
+
+ unix_shared_memory_queue_t *q =
+ vl_api_client_index_to_input_queue (mp->client_index);
+
+ if (!q)
+ return;
+
+ /* *INDENT-OFF* */
+ REPLY_MACRO2(VL_API_SHOW_VERSION_REPLY,
+ ({
+ strncpy ((char *) rmp->program, "vpe", ARRAY_LEN(rmp->program)-1);
+ strncpy ((char *) rmp->build_directory, vpe_api_get_build_directory(),
+ ARRAY_LEN(rmp->build_directory)-1);
+ strncpy ((char *) rmp->version, vpe_api_get_version(),
+ ARRAY_LEN(rmp->version)-1);
+ strncpy ((char *) rmp->build_date, vpe_api_get_build_date(),
+ ARRAY_LEN(rmp->build_date)-1);
+ }));
+ /* *INDENT-ON* */
+}
+
+static void
+vl_api_get_node_index_t_handler (vl_api_get_node_index_t * mp)
+{
+ vlib_main_t *vm = vlib_get_main ();
+ vl_api_get_node_index_reply_t *rmp;
+ vlib_node_t *n;
+ int rv = 0;
+ u32 node_index = ~0;
+
+ n = vlib_get_node_by_name (vm, mp->node_name);
+
+ if (n == 0)
+ rv = VNET_API_ERROR_NO_SUCH_NODE;
+ else
+ node_index = n->index;
+
+ /* *INDENT-OFF* */
+ REPLY_MACRO2(VL_API_GET_NODE_INDEX_REPLY,
+ ({
+ rmp->node_index = ntohl(node_index);
+ }));
+ /* *INDENT-ON* */
+}
+
+static void
+vl_api_get_next_index_t_handler (vl_api_get_next_index_t * mp)
+{
+ vlib_main_t *vm = vlib_get_main ();
+ vl_api_get_next_index_reply_t *rmp;
+ vlib_node_t *node, *next_node;
+ int rv = 0;
+ u32 next_node_index = ~0, next_index = ~0;
+ uword *p;
+
+ node = vlib_get_node_by_name (vm, mp->node_name);
+
+ if (node == 0)
+ {
+ rv = VNET_API_ERROR_NO_SUCH_NODE;
+ goto out;
+ }
+
+ next_node = vlib_get_node_by_name (vm, mp->next_name);
+
+ if (next_node == 0)
+ {
+ rv = VNET_API_ERROR_NO_SUCH_NODE2;
+ goto out;
+ }
+ else
+ next_node_index = next_node->index;
+
+ p = hash_get (node->next_slot_by_node, next_node_index);
+
+ if (p == 0)
+ {
+ rv = VNET_API_ERROR_NO_SUCH_ENTRY;
+ goto out;
+ }
+ else
+ next_index = p[0];
+
+out:
+ /* *INDENT-OFF* */
+ REPLY_MACRO2(VL_API_GET_NEXT_INDEX_REPLY,
+ ({
+ rmp->next_index = ntohl(next_index);
+ }));
+ /* *INDENT-ON* */
+}
+
+static void
+vl_api_add_node_next_t_handler (vl_api_add_node_next_t * mp)
+{
+ vlib_main_t *vm = vlib_get_main ();
+ vl_api_add_node_next_reply_t *rmp;
+ vlib_node_t *n, *next;
+ int rv = 0;
+ u32 next_index = ~0;
+
+ n = vlib_get_node_by_name (vm, mp->node_name);
+
+ if (n == 0)
+ {
+ rv = VNET_API_ERROR_NO_SUCH_NODE;
+ goto out;
+ }
+
+ next = vlib_get_node_by_name (vm, mp->next_name);
+
+ if (next == 0)
+ rv = VNET_API_ERROR_NO_SUCH_NODE2;
+ else
+ next_index = vlib_node_add_next (vm, n->index, next->index);
+
+out:
+ /* *INDENT-OFF* */
+ REPLY_MACRO2(VL_API_GET_NODE_INDEX_REPLY,
+ ({
+ rmp->next_index = ntohl(next_index);
+ }));
+ /* *INDENT-ON* */
+}
+
+static void
+vl_api_l2_patch_add_del_t_handler (vl_api_l2_patch_add_del_t * mp)
+{
+ extern int vnet_l2_patch_add_del (u32 rx_sw_if_index, u32 tx_sw_if_index,
+ int is_add);
+ vl_api_l2_patch_add_del_reply_t *rmp;
+ int vnet_l2_patch_add_del (u32 rx_sw_if_index, u32 tx_sw_if_index,
+ int is_add);
+ int rv = 0;
+
+ VALIDATE_RX_SW_IF_INDEX (mp);
+ VALIDATE_TX_SW_IF_INDEX (mp);
+
+ rv = vnet_l2_patch_add_del (ntohl (mp->rx_sw_if_index),
+ ntohl (mp->tx_sw_if_index),
+ (int) (mp->is_add != 0));
+
+ BAD_RX_SW_IF_INDEX_LABEL;
+ BAD_TX_SW_IF_INDEX_LABEL;
+
+ REPLY_MACRO (VL_API_L2_PATCH_ADD_DEL_REPLY);
+}
+
+static void
+vl_api_interface_name_renumber_t_handler (vl_api_interface_name_renumber_t *
+ mp)
+{
+ vl_api_interface_name_renumber_reply_t *rmp;
+ int rv = 0;
+
+ VALIDATE_SW_IF_INDEX (mp);
+
+ rv = vnet_interface_name_renumber
+ (ntohl (mp->sw_if_index), ntohl (mp->new_show_dev_instance));
+
+ BAD_SW_IF_INDEX_LABEL;
+
+ REPLY_MACRO (VL_API_INTERFACE_NAME_RENUMBER_REPLY);
+}
+
+static int
+arp_change_data_callback (u32 pool_index, u8 * new_mac,
+ u32 sw_if_index, u32 address)
+{
+ vpe_api_main_t *am = &vpe_api_main;
+ vlib_main_t *vm = am->vlib_main;
+ vl_api_ip4_arp_event_t *event;
+
+ if (pool_is_free_index (am->arp_events, pool_index))
+ return 1;
+
+ event = pool_elt_at_index (am->arp_events, pool_index);
+ if (eth_mac_equal (event->new_mac, new_mac) &&
+ sw_if_index == ntohl (event->sw_if_index))
+ {
+ return 1;
+ }
+
+ clib_memcpy (event->new_mac, new_mac, sizeof (event->new_mac));
+ event->sw_if_index = htonl (sw_if_index);
+ return 0;
+}
+
+static int
+nd_change_data_callback (u32 pool_index, u8 * new_mac,
+ u32 sw_if_index, ip6_address_t * address)
+{
+ vpe_api_main_t *am = &vpe_api_main;
+ vlib_main_t *vm = am->vlib_main;
+ vl_api_ip6_nd_event_t *event;
+
+ if (pool_is_free_index (am->nd_events, pool_index))
+ return 1;
+
+ event = pool_elt_at_index (am->nd_events, pool_index);
+ if (eth_mac_equal (event->new_mac, new_mac) &&
+ sw_if_index == ntohl (event->sw_if_index))
+ {
+ return 1;
+ }
+
+ clib_memcpy (event->new_mac, new_mac, sizeof (event->new_mac));
+ event->sw_if_index = htonl (sw_if_index);
+ return 0;
+}
+
+static int
+arp_change_delete_callback (u32 pool_index, u8 * notused)
+{
+ vpe_api_main_t *am = &vpe_api_main;
+
+ if (pool_is_free_index (am->arp_events, pool_index))
+ return 1;
+
+ pool_put_index (am->arp_events, pool_index);
+ return 0;
+}
+
+static int
+nd_change_delete_callback (u32 pool_index, u8 * notused)
+{
+ vpe_api_main_t *am = &vpe_api_main;
+
+ if (pool_is_free_index (am->nd_events, pool_index))
+ return 1;
+
+ pool_put_index (am->nd_events, pool_index);
+ return 0;
+}
+
+static vlib_node_registration_t wc_arp_process_node;
+
+enum
+{ WC_ARP_REPORT, WC_ND_REPORT };
+
+static uword
+wc_arp_process (vlib_main_t * vm, vlib_node_runtime_t * rt, vlib_frame_t * f)
+{
+ /* These cross the longjmp boundry (vlib_process_wait_for_event)
+ * and need to be volatile - to prevent them from being optimized into
+ * a register - which could change during suspension */
+
+ volatile wc_arp_report_t arp_prev = { 0 };
+ volatile wc_nd_report_t nd_prev = { 0 };
+ volatile f64 last_arp = vlib_time_now (vm);
+ volatile f64 last_nd = vlib_time_now (vm);
+
+ while (1)
+ {
+ vlib_process_wait_for_event (vm);
+ uword event_type;
+ void *event_data = vlib_process_get_event_data (vm, &event_type);
+
+ f64 now = vlib_time_now (vm);
+ int i;
+ if (event_type == WC_ARP_REPORT)
+ {
+ wc_arp_report_t *arp_events = event_data;
+ for (i = 0; i < vec_len (arp_events); i++)
+ {
+ /* discard dup event */
+ if (arp_prev.ip4 == arp_events[i].ip4 &&
+ eth_mac_equal ((u8 *) arp_prev.mac, arp_events[i].mac) &&
+ arp_prev.sw_if_index == arp_events[i].sw_if_index &&
+ (now - last_arp) < 10.0)
+ {
+ continue;
+ }
+ arp_prev = arp_events[i];
+ last_arp = now;
+ vpe_client_registration_t *reg;
+ /* *INDENT-OFF* */
+ pool_foreach(reg, vpe_api_main.wc_ip4_arp_events_registrations,
+ ({
+ unix_shared_memory_queue_t *q;
+ q = vl_api_client_index_to_input_queue (reg->client_index);
+ if (q && q->cursize < q->maxsize)
+ {
+ vl_api_ip4_arp_event_t * event = vl_msg_api_alloc (sizeof *event);
+ memset (event, 0, sizeof *event);
+ event->_vl_msg_id = htons (VL_API_IP4_ARP_EVENT);
+ event->client_index = reg->client_index;
+ event->pid = reg->client_pid;
+ event->mac_ip = 1;
+ event->address = arp_events[i].ip4;
+ event->sw_if_index = htonl(arp_events[i].sw_if_index);
+ memcpy(event->new_mac, arp_events[i].mac, sizeof event->new_mac);
+ vl_msg_api_send_shmem (q, (u8 *) &event);
+ }
+ }));
+ /* *INDENT-ON* */
+ }
+ }
+ else if (event_type == WC_ND_REPORT)
+ {
+ wc_nd_report_t *nd_events = event_data;
+ for (i = 0; i < vec_len (nd_events); i++)
+ {
+ /* discard dup event */
+ if (ip6_address_is_equal
+ ((ip6_address_t *) & nd_prev.ip6, &nd_events[i].ip6)
+ && eth_mac_equal ((u8 *) nd_prev.mac, nd_events[i].mac)
+ && nd_prev.sw_if_index == nd_events[i].sw_if_index
+ && (now - last_nd) < 10.0)
+ {
+ continue;
+ }
+ nd_prev = nd_events[i];
+ last_nd = now;
+ vpe_client_registration_t *reg;
+ /* *INDENT-OFF* */
+ pool_foreach(reg, vpe_api_main.wc_ip6_nd_events_registrations,
+ ({
+ unix_shared_memory_queue_t *q;
+ q = vl_api_client_index_to_input_queue (reg->client_index);
+ if (q && q->cursize < q->maxsize)
+ {
+ vl_api_ip6_nd_event_t * event = vl_msg_api_alloc (sizeof *event);
+ memset (event, 0, sizeof *event);
+ event->_vl_msg_id = htons (VL_API_IP6_ND_EVENT);
+ event->client_index = reg->client_index;
+ event->pid = reg->client_pid;
+ event->mac_ip = 1;
+ memcpy(event->address, nd_events[i].ip6.as_u8, sizeof event->address);
+ event->sw_if_index = htonl(nd_events[i].sw_if_index);
+ memcpy(event->new_mac, nd_events[i].mac, sizeof event->new_mac);
+ vl_msg_api_send_shmem (q, (u8 *) &event);
+ }
+ }));
+ /* *INDENT-ON* */
+ }
+ }
+ vlib_process_put_event_data (vm, event_data);
+ }
+
+ return 0;
+}
+
+/* *INDENT-OFF* */
+VLIB_REGISTER_NODE (wc_arp_process_node,static) = {
+ .function = wc_arp_process,
+ .type = VLIB_NODE_TYPE_PROCESS,
+ .name = "wildcard-ip4-arp-publisher-process",
+};
+/* *INDENT-ON* */
+
+static void
+vl_api_want_ip4_arp_events_t_handler (vl_api_want_ip4_arp_events_t * mp)
+{
+ vpe_api_main_t *am = &vpe_api_main;
+ vnet_main_t *vnm = vnet_get_main ();
+ vl_api_want_ip4_arp_events_reply_t *rmp;
+ int rv = 0;
+
+ if (mp->address == 0)
+ {
+ uword *p =
+ hash_get (am->wc_ip4_arp_events_registration_hash, mp->client_index);
+ vpe_client_registration_t *rp;
+ if (p)
+ {
+ if (mp->enable_disable)
+ {
+ clib_warning ("pid %d: already enabled...", mp->pid);
+ rv = VNET_API_ERROR_INVALID_REGISTRATION;
+ goto reply;
+ }
+ else
+ {
+ rp =
+ pool_elt_at_index (am->wc_ip4_arp_events_registrations, p[0]);
+ pool_put (am->wc_ip4_arp_events_registrations, rp);
+ hash_unset (am->wc_ip4_arp_events_registration_hash,
+ mp->client_index);
+ if (pool_elts (am->wc_ip4_arp_events_registrations) == 0)
+ wc_arp_set_publisher_node (~0, WC_ARP_REPORT);
+ goto reply;
+ }
+ }
+ if (mp->enable_disable == 0)
+ {
+ clib_warning ("pid %d: already disabled...", mp->pid);
+ rv = VNET_API_ERROR_INVALID_REGISTRATION;
+ goto reply;
+ }
+ pool_get (am->wc_ip4_arp_events_registrations, rp);
+ rp->client_index = mp->client_index;
+ rp->client_pid = mp->pid;
+ hash_set (am->wc_ip4_arp_events_registration_hash, rp->client_index,
+ rp - am->wc_ip4_arp_events_registrations);
+ wc_arp_set_publisher_node (wc_arp_process_node.index, WC_ARP_REPORT);
+ goto reply;
+ }
+
+ if (mp->enable_disable)
+ {
+ vl_api_ip4_arp_event_t *event;
+ pool_get (am->arp_events, event);
+ rv = vnet_add_del_ip4_arp_change_event
+ (vnm, arp_change_data_callback,
+ mp->pid, &mp->address /* addr, in net byte order */ ,
+ vpe_resolver_process_node.index,
+ IP4_ARP_EVENT, event - am->arp_events, 1 /* is_add */ );
+
+ if (rv)
+ {
+ pool_put (am->arp_events, event);
+ goto reply;
+ }
+ memset (event, 0, sizeof (*event));
+
+ /* Python API expects events to have no context */
+ event->_vl_msg_id = htons (VL_API_IP4_ARP_EVENT);
+ event->client_index = mp->client_index;
+ event->address = mp->address;
+ event->pid = mp->pid;
+ if (mp->address == 0)
+ event->mac_ip = 1;
+ }
+ else
+ {
+ rv = vnet_add_del_ip4_arp_change_event
+ (vnm, arp_change_delete_callback,
+ mp->pid, &mp->address /* addr, in net byte order */ ,
+ vpe_resolver_process_node.index,
+ IP4_ARP_EVENT, ~0 /* pool index */ , 0 /* is_add */ );
+ }
+reply:
+ REPLY_MACRO (VL_API_WANT_IP4_ARP_EVENTS_REPLY);
+}
+
+static void
+vl_api_want_ip6_nd_events_t_handler (vl_api_want_ip6_nd_events_t * mp)
+{
+ vpe_api_main_t *am = &vpe_api_main;
+ vnet_main_t *vnm = vnet_get_main ();
+ vl_api_want_ip6_nd_events_reply_t *rmp;
+ int rv = 0;
+
+ if (ip6_address_is_zero ((ip6_address_t *) mp->address))
+ {
+ uword *p =
+ hash_get (am->wc_ip6_nd_events_registration_hash, mp->client_index);
+ vpe_client_registration_t *rp;
+ if (p)
+ {
+ if (mp->enable_disable)
+ {
+ clib_warning ("pid %d: already enabled...", mp->pid);
+ rv = VNET_API_ERROR_INVALID_REGISTRATION;
+ goto reply;
+ }
+ else
+ {
+ rp =
+ pool_elt_at_index (am->wc_ip6_nd_events_registrations, p[0]);
+ pool_put (am->wc_ip6_nd_events_registrations, rp);
+ hash_unset (am->wc_ip6_nd_events_registration_hash,
+ mp->client_index);
+ if (pool_elts (am->wc_ip6_nd_events_registrations) == 0)
+ wc_nd_set_publisher_node (~0, 2);
+ goto reply;
+ }
+ }
+ if (mp->enable_disable == 0)
+ {
+ clib_warning ("pid %d: already disabled...", mp->pid);
+ rv = VNET_API_ERROR_INVALID_REGISTRATION;
+ goto reply;
+ }
+ pool_get (am->wc_ip6_nd_events_registrations, rp);
+ rp->client_index = mp->client_index;
+ rp->client_pid = mp->pid;
+ hash_set (am->wc_ip6_nd_events_registration_hash, rp->client_index,
+ rp - am->wc_ip6_nd_events_registrations);
+ wc_nd_set_publisher_node (wc_arp_process_node.index, WC_ND_REPORT);
+ goto reply;
+ }
+
+ if (mp->enable_disable)
+ {
+ vl_api_ip6_nd_event_t *event;
+ pool_get (am->nd_events, event);
+
+ rv = vnet_add_del_ip6_nd_change_event
+ (vnm, nd_change_data_callback,
+ mp->pid, mp->address /* addr, in net byte order */ ,
+ vpe_resolver_process_node.index,
+ IP6_ND_EVENT, event - am->nd_events, 1 /* is_add */ );
+
+ if (rv)
+ {
+ pool_put (am->nd_events, event);
+ goto reply;
+ }
+ memset (event, 0, sizeof (*event));
+
+ event->_vl_msg_id = ntohs (VL_API_IP6_ND_EVENT);
+ event->client_index = mp->client_index;
+ clib_memcpy (event->address, mp->address, sizeof event->address);
+ event->pid = mp->pid;
+ }
+ else
+ {
+ rv = vnet_add_del_ip6_nd_change_event
+ (vnm, nd_change_delete_callback,
+ mp->pid, mp->address /* addr, in net byte order */ ,
+ vpe_resolver_process_node.index,
+ IP6_ND_EVENT, ~0 /* pool index */ , 0 /* is_add */ );
+ }
+reply:
+ REPLY_MACRO (VL_API_WANT_IP6_ND_EVENTS_REPLY);
+}
+
+static void vl_api_input_acl_set_interface_t_handler
+ (vl_api_input_acl_set_interface_t * mp)
+{
+ vlib_main_t *vm = vlib_get_main ();
+ vl_api_input_acl_set_interface_reply_t *rmp;
+ int rv;
+
+ VALIDATE_SW_IF_INDEX (mp);
+
+ u32 ip4_table_index = ntohl (mp->ip4_table_index);
+ u32 ip6_table_index = ntohl (mp->ip6_table_index);
+ u32 l2_table_index = ntohl (mp->l2_table_index);
+ u32 sw_if_index = ntohl (mp->sw_if_index);
+
+ rv = vnet_set_input_acl_intfc (vm, sw_if_index, ip4_table_index,
+ ip6_table_index, l2_table_index, mp->is_add);
+
+ BAD_SW_IF_INDEX_LABEL;
+
+ REPLY_MACRO (VL_API_INPUT_ACL_SET_INTERFACE_REPLY);
+}
+
+static void
+vl_api_get_node_graph_t_handler (vl_api_get_node_graph_t * mp)
+{
+ int rv = 0;
+ u8 *vector = 0;
+ api_main_t *am = &api_main;
+ vlib_main_t *vm = vlib_get_main ();
+ void *oldheap;
+ vl_api_get_node_graph_reply_t *rmp;
+
+ pthread_mutex_lock (&am->vlib_rp->mutex);
+ oldheap = svm_push_data_heap (am->vlib_rp);
+
+ /*
+ * Keep the number of memcpy ops to a minimum (e.g. 1).
+ */
+ vec_validate (vector, 16384);
+ vec_reset_length (vector);
+
+ /* $$$$ FIXME */
+ vector = vlib_node_serialize (&vm->node_main, vector,
+ (u32) ~ 0 /* all threads */ ,
+ 1 /* include nexts */ ,
+ 1 /* include stats */ );
+
+ svm_pop_heap (oldheap);
+ pthread_mutex_unlock (&am->vlib_rp->mutex);
+
+ /* *INDENT-OFF* */
+ REPLY_MACRO2(VL_API_GET_NODE_GRAPH_REPLY,
+ ({
+ rmp->reply_in_shmem = (uword) vector;
+ }));
+ /* *INDENT-ON* */
+}
+
+static void
+vl_api_ioam_enable_t_handler (vl_api_ioam_enable_t * mp)
+{
+ int rv = 0;
+ vl_api_ioam_enable_reply_t *rmp;
+ clib_error_t *error;
+
+ /* Ignoring the profile id as currently a single profile
+ * is supported */
+ error = ip6_ioam_enable (mp->trace_enable, mp->pot_enable,
+ mp->seqno, mp->analyse);
+ if (error)
+ {
+ clib_error_report (error);
+ rv = clib_error_get_code (error);
+ }
+
+ REPLY_MACRO (VL_API_IOAM_ENABLE_REPLY);
+}
+
+static void
+vl_api_ioam_disable_t_handler (vl_api_ioam_disable_t * mp)
+{
+ int rv = 0;
+ vl_api_ioam_disable_reply_t *rmp;
+ clib_error_t *error;
+
+ error = clear_ioam_rewrite_fn ();
+ if (error)
+ {
+ clib_error_report (error);
+ rv = clib_error_get_code (error);
+ }
+
+ REPLY_MACRO (VL_API_IOAM_DISABLE_REPLY);
+}
+
+static void
+vl_api_pg_create_interface_t_handler (vl_api_pg_create_interface_t * mp)
+{
+ vl_api_pg_create_interface_reply_t *rmp;
+ int rv = 0;
+
+ pg_main_t *pg = &pg_main;
+ u32 pg_if_id = pg_interface_add_or_get (pg, ntohl (mp->interface_id));
+ pg_interface_t *pi = pool_elt_at_index (pg->interfaces, pg_if_id);
+
+ /* *INDENT-OFF* */
+ REPLY_MACRO2(VL_API_PG_CREATE_INTERFACE_REPLY,
+ ({
+ rmp->sw_if_index = ntohl(pi->sw_if_index);
+ }));
+ /* *INDENT-ON* */
+}
+
+static void
+vl_api_pg_capture_t_handler (vl_api_pg_capture_t * mp)
+{
+ vl_api_pg_capture_reply_t *rmp;
+ int rv = 0;
+
+ vnet_main_t *vnm = vnet_get_main ();
+ vnet_interface_main_t *im = &vnm->interface_main;
+ vnet_hw_interface_t *hi = 0;
+
+ u8 *intf_name = format (0, "pg%d", ntohl (mp->interface_id), 0);
+ u32 hw_if_index = ~0;
+ uword *p = hash_get_mem (im->hw_interface_by_name, intf_name);
+ if (p)
+ hw_if_index = *p;
+ vec_free (intf_name);
+
+ if (hw_if_index != ~0)
+ {
+ pg_capture_args_t _a, *a = &_a;
+
+ u32 len = ntohl (mp->pcap_name_length);
+ u8 *pcap_file_name = vec_new (u8, len);
+ clib_memcpy (pcap_file_name, mp->pcap_file_name, len);
+
+ hi = vnet_get_sup_hw_interface (vnm, hw_if_index);
+ a->hw_if_index = hw_if_index;
+ a->dev_instance = hi->dev_instance;
+ a->is_enabled = mp->is_enabled;
+ a->pcap_file_name = pcap_file_name;
+ a->count = ntohl (mp->count);
+
+ clib_error_t *e = pg_capture (a);
+ if (e)
+ {
+ clib_error_report (e);
+ rv = VNET_API_ERROR_CANNOT_CREATE_PCAP_FILE;
+ }
+
+ vec_free (pcap_file_name);
+ }
+ REPLY_MACRO (VL_API_PG_CAPTURE_REPLY);
+}
+
+static void
+vl_api_pg_enable_disable_t_handler (vl_api_pg_enable_disable_t * mp)
+{
+ vl_api_pg_enable_disable_reply_t *rmp;
+ int rv = 0;
+
+ pg_main_t *pg = &pg_main;
+ u32 stream_index = ~0;
+
+ int is_enable = mp->is_enabled != 0;
+ u32 len = ntohl (mp->stream_name_length) - 1;
+
+ if (len > 0)
+ {
+ u8 *stream_name = vec_new (u8, len);
+ clib_memcpy (stream_name, mp->stream_name, len);
+ uword *p = hash_get_mem (pg->stream_index_by_name, stream_name);
+ if (p)
+ stream_index = *p;
+ vec_free (stream_name);
+ }
+
+ pg_enable_disable (stream_index, is_enable);
+
+ REPLY_MACRO (VL_API_PG_ENABLE_DISABLE_REPLY);
+}
+
+static void
+ vl_api_ip_source_and_port_range_check_add_del_t_handler
+ (vl_api_ip_source_and_port_range_check_add_del_t * mp)
+{
+ vl_api_ip_source_and_port_range_check_add_del_reply_t *rmp;
+ int rv = 0;
+
+ u8 is_ipv6 = mp->is_ipv6;
+ u8 is_add = mp->is_add;
+ u8 mask_length = mp->mask_length;
+ ip4_address_t ip4_addr;
+ ip6_address_t ip6_addr;
+ u16 *low_ports = 0;
+ u16 *high_ports = 0;
+ u32 vrf_id;
+ u16 tmp_low, tmp_high;
+ u8 num_ranges;
+ int i;
+
+ // Validate port range
+ num_ranges = mp->number_of_ranges;
+ if (num_ranges > 32)
+ { // This is size of array in VPE.API
+ rv = VNET_API_ERROR_EXCEEDED_NUMBER_OF_RANGES_CAPACITY;
+ goto reply;
+ }
+
+ vec_reset_length (low_ports);
+ vec_reset_length (high_ports);
+
+ for (i = 0; i < num_ranges; i++)
+ {
+ tmp_low = mp->low_ports[i];
+ tmp_high = mp->high_ports[i];
+ // If tmp_low <= tmp_high then only need to check tmp_low = 0
+ // If tmp_low <= tmp_high then only need to check tmp_high > 65535
+ if (tmp_low > tmp_high || tmp_low == 0 || tmp_high > 65535)
+ {
+ rv = VNET_API_ERROR_INVALID_VALUE;
+ goto reply;
+ }
+ vec_add1 (low_ports, tmp_low);
+ vec_add1 (high_ports, tmp_high + 1);
+ }
+
+ // Validate mask_length
+ if ((is_ipv6 && mask_length > 128) || (!is_ipv6 && mask_length > 32))
+ {
+ rv = VNET_API_ERROR_ADDRESS_LENGTH_MISMATCH;
+ goto reply;
+ }
+
+ vrf_id = ntohl (mp->vrf_id);
+
+ if (vrf_id < 1)
+ {
+ rv = VNET_API_ERROR_INVALID_VALUE;
+ goto reply;
+ }
+
+
+ if (is_ipv6)
+ {
+ clib_memcpy (ip6_addr.as_u8, mp->address, sizeof (ip6_addr.as_u8));
+ rv = ip6_source_and_port_range_check_add_del (&ip6_addr,
+ mask_length,
+ vrf_id,
+ low_ports,
+ high_ports, is_add);
+ }
+ else
+ {
+ clib_memcpy (ip4_addr.data, mp->address, sizeof (ip4_addr));
+ rv = ip4_source_and_port_range_check_add_del (&ip4_addr,
+ mask_length,
+ vrf_id,
+ low_ports,
+ high_ports, is_add);
+ }
+
+reply:
+ vec_free (low_ports);
+ vec_free (high_ports);
+ REPLY_MACRO (VL_API_IP_SOURCE_AND_PORT_RANGE_CHECK_ADD_DEL_REPLY);
+}
+
+static void
+ vl_api_ip_source_and_port_range_check_interface_add_del_t_handler
+ (vl_api_ip_source_and_port_range_check_interface_add_del_t * mp)
+{
+ vlib_main_t *vm = vlib_get_main ();
+ vl_api_ip_source_and_port_range_check_interface_add_del_reply_t *rmp;
+ ip4_main_t *im = &ip4_main;
+ int rv;
+ u32 sw_if_index;
+ u32 fib_index[IP_SOURCE_AND_PORT_RANGE_CHECK_N_PROTOCOLS];
+ u32 vrf_id[IP_SOURCE_AND_PORT_RANGE_CHECK_N_PROTOCOLS];
+ uword *p = 0;
+ int i;
+
+ vrf_id[IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_TCP_OUT] =
+ ntohl (mp->tcp_out_vrf_id);
+ vrf_id[IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_UDP_OUT] =
+ ntohl (mp->udp_out_vrf_id);
+ vrf_id[IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_TCP_IN] =
+ ntohl (mp->tcp_in_vrf_id);
+ vrf_id[IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_UDP_IN] =
+ ntohl (mp->udp_in_vrf_id);
+
+
+ for (i = 0; i < IP_SOURCE_AND_PORT_RANGE_CHECK_N_PROTOCOLS; i++)
+ {
+ if (vrf_id[i] != 0 && vrf_id[i] != ~0)
+ {
+ p = hash_get (im->fib_index_by_table_id, vrf_id[i]);
+
+ if (p == 0)
+ {
+ rv = VNET_API_ERROR_INVALID_VALUE;
+ goto reply;
+ }
+
+ fib_index[i] = p[0];
+ }
+ else
+ fib_index[i] = ~0;
+ }
+ sw_if_index = ntohl (mp->sw_if_index);
+
+ VALIDATE_SW_IF_INDEX (mp);
+
+ rv =
+ set_ip_source_and_port_range_check (vm, fib_index, sw_if_index,
+ mp->is_add);
+
+ BAD_SW_IF_INDEX_LABEL;
+reply:
+
+ REPLY_MACRO (VL_API_IP_SOURCE_AND_PORT_RANGE_CHECK_INTERFACE_ADD_DEL_REPLY);
+}
+
+static void
+vl_api_delete_subif_t_handler (vl_api_delete_subif_t * mp)
+{
+ vl_api_delete_subif_reply_t *rmp;
+ int rv;
+
+ rv = vnet_delete_sub_interface (ntohl (mp->sw_if_index));
+
+ REPLY_MACRO (VL_API_DELETE_SUBIF_REPLY);
+}
+
+static void
+vl_api_punt_t_handler (vl_api_punt_t * mp)
+{
+ vl_api_punt_reply_t *rmp;
+ vlib_main_t *vm = vlib_get_main ();
+ int rv = 0;
+ clib_error_t *error;
+
+ error = vnet_punt_add_del (vm, mp->ipv, mp->l4_protocol,
+ ntohs (mp->l4_port), mp->is_add);
+ if (error)
+ {
+ rv = -1;
+ clib_error_report (error);
+ }
+
+ REPLY_MACRO (VL_API_PUNT_REPLY);
+}
+
+static void
+vl_api_punt_socket_register_t_handler (vl_api_punt_socket_register_t * mp)
+{
+ vl_api_punt_socket_register_reply_t *rmp;
+ vlib_main_t *vm = vlib_get_main ();
+ int rv = 0;
+ clib_error_t *error;
+ unix_shared_memory_queue_t *q;
+ u32 handle;
+
+ error = vnet_punt_socket_add (vm, ntohl (mp->header_version),
+ mp->is_ip4, mp->l4_protocol,
+ ntohs (mp->l4_port), (char *) mp->pathname);
+ if (error)
+ {
+ rv = -1;
+ clib_error_report (error);
+ }
+
+ q = vl_api_client_index_to_input_queue (mp->client_index);
+ if (!q)
+ return;
+
+ rmp = vl_msg_api_alloc (sizeof (*rmp));
+ rmp->_vl_msg_id = htons (VL_API_PUNT_SOCKET_REGISTER_REPLY);
+ rmp->context = mp->context;
+ rmp->retval = htonl (rv);
+ char *p = vnet_punt_get_server_pathname ();
+ /* Abstract pathnames start with \0 */
+ memcpy ((char *) rmp->pathname, p, sizeof (rmp->pathname));
+ vl_msg_api_send_shmem (q, (u8 *) & rmp);
+}
+
+static void
+vl_api_punt_socket_deregister_t_handler (vl_api_punt_socket_deregister_t * mp)
+{
+ vl_api_punt_socket_deregister_reply_t *rmp;
+ vlib_main_t *vm = vlib_get_main ();
+ int rv = 0;
+ clib_error_t *error;
+ unix_shared_memory_queue_t *q;
+ u32 handle;
+
+ error = vnet_punt_socket_del (vm, mp->is_ip4, mp->l4_protocol,
+ ntohs (mp->l4_port));
+ if (error)
+ {
+ rv = -1;
+ clib_error_report (error);
+ }
+
+ q = vl_api_client_index_to_input_queue (mp->client_index);
+ if (!q)
+ return;
+
+ rmp = vl_msg_api_alloc (sizeof (*rmp));
+ rmp->_vl_msg_id = htons (VL_API_PUNT_SOCKET_DEREGISTER_REPLY);
+ rmp->context = mp->context;
+ rmp->retval = htonl (rv);
+ vl_msg_api_send_shmem (q, (u8 *) & rmp);
+}
+
+static void
+vl_api_feature_enable_disable_t_handler (vl_api_feature_enable_disable_t * mp)
+{
+ vl_api_feature_enable_disable_reply_t *rmp;
+ int rv = 0;
+
+ VALIDATE_SW_IF_INDEX (mp);
+
+ u8 *arc_name = format (0, "%s%c", mp->arc_name, 0);
+ u8 *feature_name = format (0, "%s%c", mp->feature_name, 0);
+
+ vnet_feature_registration_t *reg =
+ vnet_get_feature_reg ((const char *) arc_name,
+ (const char *) feature_name);
+ if (reg == 0)
+ rv = VNET_API_ERROR_INVALID_VALUE;
+ else
+ {
+ u32 sw_if_index = ntohl (mp->sw_if_index);
+ clib_error_t *error = 0;
+
+ if (reg->enable_disable_cb)
+ error = reg->enable_disable_cb (sw_if_index, mp->enable);
+ if (!error)
+ vnet_feature_enable_disable ((const char *) arc_name,
+ (const char *) feature_name,
+ sw_if_index, mp->enable, 0, 0);
+ else
+ {
+ clib_error_report (error);
+ rv = VNET_API_ERROR_CANNOT_ENABLE_DISABLE_FEATURE;
+ }
+ }
+
+ vec_free (feature_name);
+ vec_free (arc_name);
+
+ BAD_SW_IF_INDEX_LABEL;
+
+ REPLY_MACRO (VL_API_FEATURE_ENABLE_DISABLE_REPLY);
+}
+
+#define BOUNCE_HANDLER(nn) \
+static void vl_api_##nn##_t_handler ( \
+ vl_api_##nn##_t *mp) \
+{ \
+ vpe_client_registration_t *reg; \
+ vpe_api_main_t * vam = &vpe_api_main; \
+ unix_shared_memory_queue_t * q; \
+ \
+ /* One registration only... */ \
+ pool_foreach(reg, vam->nn##_registrations, \
+ ({ \
+ q = vl_api_client_index_to_input_queue (reg->client_index); \
+ if (q) { \
+ /* \
+ * If the queue is stuffed, turf the msg and complain \
+ * It's unlikely that the intended recipient is \
+ * alive; avoid deadlock at all costs. \
+ */ \
+ if (q->cursize == q->maxsize) { \
+ clib_warning ("ERROR: receiver queue full, drop msg"); \
+ vl_msg_api_free (mp); \
+ return; \
+ } \
+ vl_msg_api_send_shmem (q, (u8 *)&mp); \
+ return; \
+ } \
+ })); \
+ vl_msg_api_free (mp); \
+}
+
+static void setup_message_id_table (api_main_t * am);
+
+/*
+ * vpe_api_hookup
+ * Add vpe's API message handlers to the table.
+ * vlib has alread mapped shared memory and
+ * added the client registration handlers.
+ * See .../open-repo/vlib/memclnt_vlib.c:memclnt_process()
+ */
+static clib_error_t *
+vpe_api_hookup (vlib_main_t * vm)
+{
+ api_main_t *am = &api_main;
+
+#define _(N,n) \
+ vl_msg_api_set_handlers(VL_API_##N, #n, \
+ vl_api_##n##_t_handler, \
+ vl_noop_handler, \
+ vl_api_##n##_t_endian, \
+ vl_api_##n##_t_print, \
+ sizeof(vl_api_##n##_t), 1);
+ foreach_vpe_api_msg;
+#undef _
+
+ /*
+ * Trace space for classifier mask+match
+ */
+ am->api_trace_cfg[VL_API_CLASSIFY_ADD_DEL_TABLE].size += 5 * sizeof (u32x4);
+ am->api_trace_cfg[VL_API_CLASSIFY_ADD_DEL_SESSION].size
+ += 5 * sizeof (u32x4);
+
+ /*
+ * Thread-safe API messages
+ */
+ am->is_mp_safe[VL_API_IP_ADD_DEL_ROUTE] = 1;
+ am->is_mp_safe[VL_API_GET_NODE_GRAPH] = 1;
+
+ /*
+ * Set up the (msg_name, crc, message-id) table
+ */
+ setup_message_id_table (am);
+
+ return 0;
+}
+
+VLIB_API_INIT_FUNCTION (vpe_api_hookup);
+
+static clib_error_t *
+vpe_api_init (vlib_main_t * vm)
+{
+ vpe_api_main_t *am = &vpe_api_main;
+
+ am->vlib_main = vm;
+ am->vnet_main = vnet_get_main ();
+#define _(a) \
+ am->a##_registration_hash = hash_create (0, sizeof (uword));
+ foreach_registration_hash;
+#undef _
+
+ vl_set_memory_region_name ("/vpe-api");
+ vl_enable_disable_memory_api (vm, 1 /* enable it */ );
+
+ return 0;
+}
+
+VLIB_INIT_FUNCTION (vpe_api_init);
+
+
+static clib_error_t *
+api_segment_config (vlib_main_t * vm, unformat_input_t * input)
+{
+ u8 *chroot_path;
+ u64 baseva, size, pvt_heap_size;
+ int uid, gid, rv;
+ const int max_buf_size = 4096;
+ char *s, *buf;
+ struct passwd _pw, *pw;
+ struct group _grp, *grp;
+ clib_error_t *e;
+ buf = vec_new (char, 128);
+ while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (input, "prefix %s", &chroot_path))
+ {
+ vec_add1 (chroot_path, 0);
+ vl_set_memory_root_path ((char *) chroot_path);
+ }
+ else if (unformat (input, "uid %d", &uid))
+ vl_set_memory_uid (uid);
+ else if (unformat (input, "gid %d", &gid))
+ vl_set_memory_gid (gid);
+ else if (unformat (input, "baseva %llx", &baseva))
+ vl_set_global_memory_baseva (baseva);
+ else if (unformat (input, "global-size %lldM", &size))
+ vl_set_global_memory_size (size * (1ULL << 20));
+ else if (unformat (input, "global-size %lldG", &size))
+ vl_set_global_memory_size (size * (1ULL << 30));
+ else if (unformat (input, "global-size %lld", &size))
+ vl_set_global_memory_size (size);
+ else if (unformat (input, "global-pvt-heap-size %lldM", &pvt_heap_size))
+ vl_set_global_pvt_heap_size (pvt_heap_size * (1ULL << 20));
+ else if (unformat (input, "global-pvt-heap-size size %lld",
+ &pvt_heap_size))
+ vl_set_global_pvt_heap_size (pvt_heap_size);
+ else if (unformat (input, "api-pvt-heap-size %lldM", &pvt_heap_size))
+ vl_set_api_pvt_heap_size (pvt_heap_size * (1ULL << 20));
+ else if (unformat (input, "api-pvt-heap-size size %lld",
+ &pvt_heap_size))
+ vl_set_api_pvt_heap_size (pvt_heap_size);
+ else if (unformat (input, "api-size %lldM", &size))
+ vl_set_api_memory_size (size * (1ULL << 20));
+ else if (unformat (input, "api-size %lldG", &size))
+ vl_set_api_memory_size (size * (1ULL << 30));
+ else if (unformat (input, "api-size %lld", &size))
+ vl_set_api_memory_size (size);
+ else if (unformat (input, "uid %s", &s))
+ {
+ /* lookup the username */
+ pw = NULL;
+ while (((rv =
+ getpwnam_r (s, &_pw, buf, vec_len (buf), &pw)) == ERANGE)
+ && (vec_len (buf) <= max_buf_size))
+ {
+ vec_resize (buf, vec_len (buf) * 2);
+ }
+ if (rv < 0)
+ {
+ e = clib_error_return_code (0, rv,
+ CLIB_ERROR_ERRNO_VALID |
+ CLIB_ERROR_FATAL,
+ "cannot fetch username %s", s);
+ vec_free (s);
+ vec_free (buf);
+ return e;
+ }
+ if (pw == NULL)
+ {
+ e =
+ clib_error_return_fatal (0, "username %s does not exist", s);
+ vec_free (s);
+ vec_free (buf);
+ return e;
+ }
+ vec_free (s);
+ vl_set_memory_uid (pw->pw_uid);
+ }
+ else if (unformat (input, "gid %s", &s))
+ {
+ /* lookup the group name */
+ grp = NULL;
+ while (((rv =
+ getgrnam_r (s, &_grp, buf, vec_len (buf), &grp)) == ERANGE)
+ && (vec_len (buf) <= max_buf_size))
+ {
+ vec_resize (buf, vec_len (buf) * 2);
+ }
+ if (rv != 0)
+ {
+ e = clib_error_return_code (0, rv,
+ CLIB_ERROR_ERRNO_VALID |
+ CLIB_ERROR_FATAL,
+ "cannot fetch group %s", s);
+ vec_free (s);
+ vec_free (buf);
+ return e;
+ }
+ if (grp == NULL)
+ {
+ e = clib_error_return_fatal (0, "group %s does not exist", s);
+ vec_free (s);
+ vec_free (buf);
+ return e;
+ }
+ vec_free (s);
+ vec_free (buf);
+ vl_set_memory_gid (grp->gr_gid);
+ }
+ else
+ return clib_error_return (0, "unknown input `%U'",
+ format_unformat_error, input);
+ }
+ return 0;
+}
+
+VLIB_EARLY_CONFIG_FUNCTION (api_segment_config, "api-segment");
+
+void *
+get_unformat_vnet_sw_interface (void)
+{
+ return (void *) &unformat_vnet_sw_interface;
+}
+
+static u8 *
+format_arp_event (u8 * s, va_list * args)
+{
+ vl_api_ip4_arp_event_t *event = va_arg (*args, vl_api_ip4_arp_event_t *);
+
+ s = format (s, "pid %d: ", ntohl (event->pid));
+ s = format (s, "resolution for %U", format_ip4_address, &event->address);
+ return s;
+}
+
+static u8 *
+format_nd_event (u8 * s, va_list * args)
+{
+ vl_api_ip6_nd_event_t *event = va_arg (*args, vl_api_ip6_nd_event_t *);
+
+ s = format (s, "pid %d: ", ntohl (event->pid));
+ s = format (s, "resolution for %U", format_ip6_address, event->address);
+ return s;
+}
+
+static clib_error_t *
+show_ip_arp_nd_events_fn (vlib_main_t * vm,
+ unformat_input_t * input, vlib_cli_command_t * cmd)
+{
+ vpe_api_main_t *am = &vpe_api_main;
+ vl_api_ip4_arp_event_t *arp_event;
+ vl_api_ip6_nd_event_t *nd_event;
+
+ if (pool_elts (am->arp_events) == 0 && pool_elts (am->nd_events) == 0 &&
+ pool_elts (am->wc_ip4_arp_events_registrations) == 0 &&
+ pool_elts (am->wc_ip6_nd_events_registrations) == 0)
+ {
+ vlib_cli_output (vm, "No active arp or nd event registrations");
+ return 0;
+ }
+
+ /* *INDENT-OFF* */
+ pool_foreach (arp_event, am->arp_events,
+ ({
+ vlib_cli_output (vm, "%U", format_arp_event, arp_event);
+ }));
+
+ vpe_client_registration_t *reg;
+ pool_foreach(reg, am->wc_ip4_arp_events_registrations,
+ ({
+ vlib_cli_output (vm, "pid %d: bd mac/ip4 binding events",
+ ntohl (reg->client_pid));
+ }));
+
+ pool_foreach (nd_event, am->nd_events,
+ ({
+ vlib_cli_output (vm, "%U", format_nd_event, nd_event);
+ }));
+
+ pool_foreach(reg, am->wc_ip6_nd_events_registrations,
+ ({
+ vlib_cli_output (vm, "pid %d: bd mac/ip6 binding events",
+ ntohl (reg->client_pid));
+ }));
+ /* *INDENT-ON* */
+
+ return 0;
+}
+
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND (show_ip_arp_nd_events, static) = {
+ .path = "show arp-nd-event registrations",
+ .function = show_ip_arp_nd_events_fn,
+ .short_help = "Show ip4 arp and ip6 nd event registrations",
+};
+/* *INDENT-ON* */
+
+#define vl_msg_name_crc_list
+#include <vpp/api/vpe_all_api_h.h>
+#undef vl_msg_name_crc_list
+
+static void
+setup_message_id_table (api_main_t * am)
+{
+#define _(id,n,crc) vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id);
+ foreach_vl_msg_name_crc_memclnt;
+ foreach_vl_msg_name_crc_vpe;
+#undef _
+}
+
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/src/vpp/api/api_format.c b/src/vpp/api/api_format.c
new file mode 120000
index 00000000..cec72cc0
--- /dev/null
+++ b/src/vpp/api/api_format.c
@@ -0,0 +1 @@
+../../vat/api_format.c \ No newline at end of file
diff --git a/src/vpp/api/api_main.c b/src/vpp/api/api_main.c
new file mode 100644
index 00000000..c355a5fd
--- /dev/null
+++ b/src/vpp/api/api_main.c
@@ -0,0 +1,250 @@
+#include "vat.h"
+
+vat_main_t vat_main;
+
+void
+vat_suspend (vlib_main_t * vm, f64 interval)
+{
+ vlib_process_suspend (vm, interval);
+}
+
+static u8 *
+format_api_error (u8 * s, va_list * args)
+{
+ vat_main_t *vam = va_arg (*args, vat_main_t *);
+ i32 error = va_arg (*args, u32);
+ uword *p;
+
+ p = hash_get (vam->error_string_by_error_number, -error);
+
+ if (p)
+ s = format (s, "%s", p[0]);
+ else
+ s = format (s, "%d", error);
+ return s;
+}
+
+
+static void
+init_error_string_table (vat_main_t * vam)
+{
+
+ vam->error_string_by_error_number = hash_create (0, sizeof (uword));
+
+#define _(n,v,s) hash_set (vam->error_string_by_error_number, -v, s);
+ foreach_vnet_api_error;
+#undef _
+
+ hash_set (vam->error_string_by_error_number, 99, "Misc");
+}
+
+static clib_error_t *
+api_main_init (vlib_main_t * vm)
+{
+ vat_main_t *vam = &vat_main;
+ int rv;
+ int vat_plugin_init (vat_main_t * vam);
+
+ vam->vlib_main = vm;
+ vam->my_client_index = (u32) ~ 0;
+ /* Ensure that vam->inbuf is never NULL */
+ vec_validate (vam->inbuf, 0);
+ init_error_string_table (vam);
+ rv = vat_plugin_init (vam);
+ if (rv)
+ clib_warning ("vat_plugin_init returned %d", rv);
+ return 0;
+}
+
+VLIB_INIT_FUNCTION (api_main_init);
+
+void
+vat_plugin_hash_create (void)
+{
+ vat_main_t *vam = &vat_main;
+
+ vam->sw_if_index_by_interface_name = hash_create_string (0, sizeof (uword));
+ vam->function_by_name = hash_create_string (0, sizeof (uword));
+ vam->help_by_name = hash_create_string (0, sizeof (uword));
+}
+
+static clib_error_t *
+api_command_fn (vlib_main_t * vm,
+ unformat_input_t * input, vlib_cli_command_t * cmd)
+{
+ vat_main_t *vam = &vat_main;
+ unformat_input_t _input;
+ uword c;
+ u8 *cmdp, *argsp, *this_cmd;
+ uword *p;
+ u32 arg_len;
+ int rv;
+ int (*fp) (vat_main_t *);
+ api_main_t *am = &api_main;
+
+ vam->vl_input_queue = am->shmem_hdr->vl_input_queue;
+
+ /* vec_validated in the init routine */
+ _vec_len (vam->inbuf) = 0;
+
+ vam->input = &_input;
+
+ while (((c = unformat_get_input (input)) != '\n') &&
+ (c != UNFORMAT_END_OF_INPUT))
+ vec_add1 (vam->inbuf, c);
+
+ /* Null-terminate the command */
+ vec_add1 (vam->inbuf, 0);
+
+ /* In case no args given */
+ vec_add1 (vam->inbuf, 0);
+
+ /* Split input into cmd + args */
+ this_cmd = cmdp = vam->inbuf;
+
+ /* Skip leading whitespace */
+ while (cmdp < (this_cmd + vec_len (this_cmd)))
+ {
+ if (*cmdp == ' ' || *cmdp == '\t' || *cmdp == '\n')
+ {
+ cmdp++;
+ }
+ else
+ break;
+ }
+
+ argsp = cmdp;
+
+ /* Advance past the command */
+ while (argsp < (this_cmd + vec_len (this_cmd)))
+ {
+ if (*argsp != ' ' && *argsp != '\t' && *argsp != '\n' && *argsp != 0)
+ {
+ argsp++;
+ }
+ else
+ break;
+ }
+ /* NULL terminate the command */
+ *argsp++ = 0;
+
+ /* No arguments? Ensure that argsp points to a proper (empty) string */
+ if (argsp == (this_cmd + vec_len (this_cmd) - 1))
+ argsp[0] = 0;
+ else
+ while (argsp < (this_cmd + vec_len (this_cmd)))
+ {
+ if (*argsp == ' ' || *argsp == '\t' || *argsp == '\n')
+ {
+ argsp++;
+ }
+ else
+ break;
+ }
+
+ /* Blank input line? */
+ if (*cmdp == 0)
+ return 0;
+
+ p = hash_get_mem (vam->function_by_name, cmdp);
+ if (p == 0)
+ {
+ return clib_error_return (0, "'%s': function not found\n", cmdp);
+ }
+
+ arg_len = strlen ((char *) argsp);
+
+ unformat_init_string (vam->input, (char *) argsp, arg_len);
+ fp = (void *) p[0];
+
+ rv = (*fp) (vam);
+
+ if (rv < 0)
+ {
+ unformat_free (vam->input);
+ return clib_error_return (0,
+ "%s error: %U\n", cmdp,
+ format_api_error, vam, rv);
+
+ }
+ if (vam->regenerate_interface_table)
+ {
+ vam->regenerate_interface_table = 0;
+ api_sw_interface_dump (vam);
+ }
+ unformat_free (vam->input);
+ return 0;
+}
+
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND (api_command, static) =
+{
+ .path = "binary-api",
+ .short_help = "binary-api [help] <name> [<args>]",
+ .function = api_command_fn,
+};
+/* *INDENT-ON* */
+
+void
+api_cli_output (void *notused, const char *fmt, ...)
+{
+ va_list va;
+ vat_main_t *vam = &vat_main;
+ vlib_main_t *vm = vam->vlib_main;
+ vlib_process_t *cp = vlib_get_current_process (vm);
+ u8 *s;
+
+ va_start (va, fmt);
+ s = va_format (0, fmt, &va);
+ va_end (va);
+
+ /* Terminate with \n if not present. */
+ if (vec_len (s) > 0 && s[vec_len (s) - 1] != '\n')
+ vec_add1 (s, '\n');
+
+ if ((!cp) || (!cp->output_function))
+ fformat (stdout, "%v", s);
+ else
+ cp->output_function (cp->output_function_arg, s, vec_len (s));
+
+ vec_free (s);
+}
+
+u16
+vl_client_get_first_plugin_msg_id (const char *plugin_name)
+{
+ api_main_t *am = &api_main;
+ vl_api_msg_range_t *rp;
+ uword *p;
+
+ p = hash_get_mem (am->msg_range_by_name, plugin_name);
+ if (p == 0)
+ return ~0;
+
+ rp = vec_elt_at_index (am->msg_ranges, p[0]);
+
+ return (rp->first_msg_id);
+}
+
+uword
+unformat_sw_if_index (unformat_input_t * input, va_list * args)
+{
+ u32 *result = va_arg (*args, u32 *);
+ vnet_main_t *vnm = vnet_get_main ();
+ u32 sw_if_index = ~0;
+
+ if (unformat (input, "%U", unformat_vnet_sw_interface, vnm, &sw_if_index))
+ {
+ *result = sw_if_index;
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/src/vpp/api/custom_dump.c b/src/vpp/api/custom_dump.c
new file mode 100644
index 00000000..2e1f980e
--- /dev/null
+++ b/src/vpp/api/custom_dump.c
@@ -0,0 +1,3231 @@
+/*
+ *------------------------------------------------------------------
+ * custom_dump.c - pretty-print API messages for replay
+ *
+ * Copyright (c) 2014-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.
+ *------------------------------------------------------------------
+ */
+
+#include <vnet/vnet.h>
+#include <vnet/ip/ip.h>
+#include <vnet/unix/tuntap.h>
+#include <vnet/mpls/mpls.h>
+#include <vnet/dhcp/dhcp_proxy.h>
+#include <vnet/l2tp/l2tp.h>
+#include <vnet/l2/l2_input.h>
+#include <vnet/srv6/sr.h>
+#include <vnet/vxlan-gpe/vxlan_gpe.h>
+#include <vnet/classify/policer_classify.h>
+#include <vnet/policer/xlate.h>
+#include <vnet/policer/policer.h>
+#include <vnet/classify/flow_classify.h>
+#include <vlib/vlib.h>
+#include <vlib/unix/unix.h>
+#include <vlibapi/api.h>
+#include <vlibmemory/api.h>
+#include <vnet/lisp-cp/lisp_types.h>
+
+#include <vpp/stats/stats.h>
+#include <vpp/oam/oam.h>
+
+#include <vnet/ethernet/ethernet.h>
+#include <vnet/l2/l2_vtr.h>
+
+#include <vpp/api/vpe_msg_enum.h>
+
+#define vl_typedefs /* define message structures */
+#include <vpp/api/vpe_all_api_h.h>
+#undef vl_typedefs
+
+#define vl_endianfun /* define message structures */
+#include <vpp/api/vpe_all_api_h.h>
+#undef vl_endianfun
+
+#define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
+
+#define FINISH \
+ vec_add1 (s, 0); \
+ vl_print (handle, (char *)s); \
+ vec_free (s); \
+ return handle;
+
+
+static void *vl_api_create_loopback_t_print
+ (vl_api_create_loopback_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: create_loopback ");
+ s = format (s, "mac %U ", format_ethernet_address, &mp->mac_address);
+
+ FINISH;
+}
+
+static void *vl_api_create_loopback_instance_t_print
+ (vl_api_create_loopback_instance_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: create_loopback ");
+ s = format (s, "mac %U ", format_ethernet_address, &mp->mac_address);
+ s = format (s, "instance %d ", ntohl (mp->user_instance));
+
+ FINISH;
+}
+
+static void *vl_api_delete_loopback_t_print
+ (vl_api_delete_loopback_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: delete_loopback ");
+ s = format (s, "sw_if_index %d ", ntohl (mp->sw_if_index));
+
+ FINISH;
+}
+
+static void *vl_api_sw_interface_set_flags_t_print
+ (vl_api_sw_interface_set_flags_t * mp, void *handle)
+{
+ u8 *s;
+ s = format (0, "SCRIPT: sw_interface_set_flags ");
+
+ s = format (s, "sw_if_index %d ", ntohl (mp->sw_if_index));
+
+ if (mp->admin_up_down)
+ s = format (s, "admin-up ");
+ else
+ s = format (s, "admin-down ");
+
+ FINISH;
+}
+
+static void *vl_api_sw_interface_event_t_print
+ (vl_api_sw_interface_event_t * mp, void *handle)
+{
+ u8 *s;
+ s = format (0, "SCRIPT: sw_interface_event ");
+
+ s = format (s, "sw_if_index %d ", ntohl (mp->sw_if_index));
+
+ if (mp->admin_up_down)
+ s = format (s, "admin-up ");
+ else
+ s = format (s, "admin-down ");
+
+ if (mp->link_up_down)
+ s = format (s, "link-up");
+ else
+ s = format (s, "link-down");
+
+ if (mp->deleted)
+ s = format (s, " deleted");
+
+ FINISH;
+}
+
+static void *vl_api_sw_interface_add_del_address_t_print
+ (vl_api_sw_interface_add_del_address_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: sw_interface_add_del_address ");
+
+ s = format (s, "sw_if_index %d ", ntohl (mp->sw_if_index));
+
+ if (mp->is_ipv6)
+ s = format (s, "%U/%d ", format_ip6_address,
+ (ip6_address_t *) mp->address, mp->address_length);
+ else
+ s = format (s, "%U/%d ", format_ip4_address,
+ (ip4_address_t *) mp->address, mp->address_length);
+
+ if (mp->is_add == 0)
+ s = format (s, "del ");
+ if (mp->del_all)
+ s = format (s, "del-all ");
+
+ FINISH;
+}
+
+static void *vl_api_sw_interface_set_table_t_print
+ (vl_api_sw_interface_set_table_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: sw_interface_set_table ");
+
+ s = format (s, "sw_if_index %d ", ntohl (mp->sw_if_index));
+
+ if (mp->vrf_id)
+ s = format (s, "vrf %d ", ntohl (mp->vrf_id));
+
+ if (mp->is_ipv6)
+ s = format (s, "ipv6 ");
+
+ FINISH;
+}
+
+static void *vl_api_sw_interface_set_mpls_enable_t_print
+ (vl_api_sw_interface_set_mpls_enable_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: sw_interface_set_mpls_enable ");
+
+ s = format (s, "sw_if_index %d ", ntohl (mp->sw_if_index));
+
+ if (mp->enable == 0)
+ s = format (s, "disable");
+
+ FINISH;
+}
+
+static void *vl_api_sw_interface_set_vpath_t_print
+ (vl_api_sw_interface_set_vpath_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: sw_interface_set_vpath ");
+
+ s = format (s, "sw_if_index %d ", ntohl (mp->sw_if_index));
+
+ if (mp->enable)
+ s = format (s, "enable ");
+ else
+ s = format (s, "disable ");
+
+ FINISH;
+}
+
+static void *vl_api_sw_interface_set_vxlan_bypass_t_print
+ (vl_api_sw_interface_set_vxlan_bypass_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: sw_interface_set_vxlan_bypass ");
+
+ s = format (s, "sw_if_index %d ", ntohl (mp->sw_if_index));
+
+ if (mp->is_ipv6)
+ s = format (s, "ip6 ");
+
+ if (mp->enable)
+ s = format (s, "enable ");
+ else
+ s = format (s, "disable ");
+
+ FINISH;
+}
+
+static void *vl_api_sw_interface_set_l2_xconnect_t_print
+ (vl_api_sw_interface_set_l2_xconnect_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: sw_interface_set_l2_xconnect ");
+
+ s = format (s, "sw_if_index %d ", ntohl (mp->rx_sw_if_index));
+
+ if (mp->enable)
+ {
+ s = format (s, "tx_sw_if_index %d ", ntohl (mp->tx_sw_if_index));
+ }
+ else
+ s = format (s, "delete ");
+
+ FINISH;
+}
+
+static void *vl_api_sw_interface_set_l2_bridge_t_print
+ (vl_api_sw_interface_set_l2_bridge_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: sw_interface_set_l2_bridge ");
+
+ s = format (s, "sw_if_index %d ", ntohl (mp->rx_sw_if_index));
+
+ if (mp->enable)
+ {
+ s = format (s, "bd_id %d shg %d %senable ", ntohl (mp->bd_id),
+ mp->shg, ((mp->bvi) ? "bvi " : " "));
+ }
+ else
+ s = format (s, "disable ");
+
+ FINISH;
+}
+
+static void *vl_api_bridge_domain_add_del_t_print
+ (vl_api_bridge_domain_add_del_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: bridge_domain_add_del ");
+
+ s = format (s, "bd_id %d ", ntohl (mp->bd_id));
+
+ if (mp->is_add)
+ {
+ if (mp->bd_tag[0])
+ s = format (s, "bd_tag %s ", mp->bd_tag);
+ s = format (s, "flood %d uu-flood %d ", mp->flood, mp->uu_flood);
+ s = format (s, "forward %d learn %d ", mp->forward, mp->learn);
+ s = format (s, "arp-term %d mac-age %d", mp->arp_term, mp->mac_age);
+ }
+ else
+ s = format (s, "del ");
+
+ FINISH;
+}
+
+static void *vl_api_bridge_domain_set_mac_age_t_print
+ (vl_api_bridge_domain_set_mac_age_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: bridge_domain_set_mac_age ");
+
+ s = format (s, "bd_id %d ", ntohl (mp->bd_id));
+
+ s = format (s, "mac-age %d", mp->mac_age);
+
+ FINISH;
+}
+
+static void *vl_api_bridge_domain_dump_t_print
+ (vl_api_bridge_domain_dump_t * mp, void *handle)
+{
+ u8 *s;
+ u32 bd_id = ntohl (mp->bd_id);
+
+ s = format (0, "SCRIPT: bridge_domain_dump ");
+
+ if (bd_id != ~0)
+ s = format (s, "bd_id %d ", bd_id);
+
+ FINISH;
+}
+
+static void *vl_api_l2fib_flush_all_t_print
+ (vl_api_l2fib_flush_all_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: l2fib_flush_all ");
+
+ FINISH;
+}
+
+
+static void *vl_api_l2fib_flush_bd_t_print
+ (vl_api_l2fib_flush_bd_t * mp, void *handle)
+{
+ u8 *s;
+ u32 bd_id = ntohl (mp->bd_id);
+
+ s = format (0, "SCRIPT: l2fib_flush_bd ");
+ s = format (s, "bd_id %d ", bd_id);
+
+ FINISH;
+}
+
+static void *vl_api_l2fib_flush_int_t_print
+ (vl_api_l2fib_flush_int_t * mp, void *handle)
+{
+ u8 *s;
+ u32 sw_if_index = ntohl (mp->sw_if_index);
+
+ s = format (0, "SCRIPT: l2fib_flush_int ");
+ s = format (s, "sw_if_index %d ", sw_if_index);
+
+ FINISH;
+}
+
+static void *vl_api_l2fib_add_del_t_print
+ (vl_api_l2fib_add_del_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: l2fib_add_del ");
+
+ s = format (s, "mac %U ", format_ethernet_address, &mp->mac);
+
+ s = format (s, "bd_id %d ", ntohl (mp->bd_id));
+
+
+ if (mp->is_add)
+ {
+ s = format (s, "sw_if_index %d ", ntohl (mp->sw_if_index));
+ if (mp->static_mac)
+ s = format (s, "%s", "static ");
+ if (mp->filter_mac)
+ s = format (s, "%s", "filter ");
+ if (mp->bvi_mac)
+ s = format (s, "%s", "bvi ");
+ }
+ else
+ {
+ s = format (s, "del ");
+ }
+
+ FINISH;
+}
+
+static void *
+vl_api_l2_flags_t_print (vl_api_l2_flags_t * mp, void *handle)
+{
+ u8 *s;
+ u32 flags = ntohl (mp->feature_bitmap);
+
+ s = format (0, "SCRIPT: l2_flags ");
+
+ s = format (s, "sw_if_index %d ", ntohl (mp->sw_if_index));
+
+ if (flags & L2_LEARN)
+ s = format (s, "learn ");
+ if (flags & L2_FWD)
+ s = format (s, "forward ");
+ if (flags & L2_FLOOD)
+ s = format (s, "flood ");
+ if (flags & L2_UU_FLOOD)
+ s = format (s, "uu-flood ");
+ if (flags & L2_ARP_TERM)
+ s = format (s, "arp-term ");
+
+ if (mp->is_set == 0)
+ s = format (s, "clear ");
+
+ FINISH;
+}
+
+static void *vl_api_bridge_flags_t_print
+ (vl_api_bridge_flags_t * mp, void *handle)
+{
+ u8 *s;
+ u32 flags = ntohl (mp->feature_bitmap);
+
+ s = format (0, "SCRIPT: bridge_flags ");
+
+ s = format (s, "bd_id %d ", ntohl (mp->bd_id));
+
+ if (flags & L2_LEARN)
+ s = format (s, "learn ");
+ if (flags & L2_FWD)
+ s = format (s, "forward ");
+ if (flags & L2_FLOOD)
+ s = format (s, "flood ");
+ if (flags & L2_UU_FLOOD)
+ s = format (s, "uu-flood ");
+ if (flags & L2_ARP_TERM)
+ s = format (s, "arp-term ");
+
+ if (mp->is_set == 0)
+ s = format (s, "clear ");
+
+ FINISH;
+}
+
+static void *vl_api_bd_ip_mac_add_del_t_print
+ (vl_api_bd_ip_mac_add_del_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: bd_ip_mac_add_del ");
+ s = format (s, "bd_id %d ", ntohl (mp->bd_id));
+
+ if (mp->is_ipv6)
+ s = format (s, "%U ", format_ip6_address,
+ (ip6_address_t *) mp->ip_address);
+ else
+ s = format (s, "%U ", format_ip4_address,
+ (ip4_address_t *) mp->ip_address);
+
+ s = format (s, "%U ", format_ethernet_address, mp->mac_address);
+ if (mp->is_add == 0)
+ s = format (s, "del ");
+
+ FINISH;
+}
+
+static void *vl_api_tap_connect_t_print
+ (vl_api_tap_connect_t * mp, void *handle)
+{
+ u8 *s;
+ u8 null_mac[6];
+
+ memset (null_mac, 0, sizeof (null_mac));
+
+ s = format (0, "SCRIPT: tap_connect ");
+ s = format (s, "tapname %s ", mp->tap_name);
+ if (mp->use_random_mac)
+ s = format (s, "random-mac ");
+ if (mp->tag[0])
+ s = format (s, "tag %s ", mp->tag);
+ if (memcmp (mp->mac_address, null_mac, 6))
+ s = format (s, "mac %U ", format_ethernet_address, mp->mac_address);
+ if (mp->ip4_address_set)
+ s = format (s, "address %U/%d ", format_ip4_address, mp->ip4_address,
+ mp->ip4_mask_width);
+ if (mp->ip6_address_set)
+ s = format (s, "address %U/%d ", format_ip6_address, mp->ip6_address,
+ mp->ip6_mask_width);
+ FINISH;
+}
+
+static void *vl_api_tap_modify_t_print
+ (vl_api_tap_modify_t * mp, void *handle)
+{
+ u8 *s;
+ u8 null_mac[6];
+
+ memset (null_mac, 0, sizeof (null_mac));
+
+ s = format (0, "SCRIPT: tap_modify ");
+ s = format (s, "sw_if_index %d ", ntohl (mp->sw_if_index));
+ s = format (s, "tapname %s ", mp->tap_name);
+ if (mp->use_random_mac)
+ s = format (s, "random-mac ");
+
+ if (memcmp (mp->mac_address, null_mac, 6))
+ s = format (s, "mac %U ", format_ethernet_address, mp->mac_address);
+
+ FINISH;
+}
+
+static void *vl_api_tap_delete_t_print
+ (vl_api_tap_delete_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: tap_delete ");
+ s = format (s, "sw_if_index %d ", ntohl (mp->sw_if_index));
+
+ FINISH;
+}
+
+static void *vl_api_sw_interface_tap_dump_t_print
+ (vl_api_sw_interface_tap_dump_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: sw_interface_tap_dump ");
+
+ FINISH;
+}
+
+
+static void *vl_api_ip_add_del_route_t_print
+ (vl_api_ip_add_del_route_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: ip_add_del_route ");
+ if (mp->is_add == 0)
+ s = format (s, "del ");
+
+ if (mp->next_hop_sw_if_index)
+ s = format (s, "sw_if_index %d ", ntohl (mp->next_hop_sw_if_index));
+
+ if (mp->is_ipv6)
+ s = format (s, "%U/%d ", format_ip6_address, mp->dst_address,
+ mp->dst_address_length);
+ else
+ s = format (s, "%U/%d ", format_ip4_address, mp->dst_address,
+ mp->dst_address_length);
+ if (mp->is_local)
+ s = format (s, "local ");
+ else if (mp->is_drop)
+ s = format (s, "drop ");
+ else if (mp->is_classify)
+ s = format (s, "classify %d", ntohl (mp->classify_table_index));
+ else
+ {
+ if (mp->is_ipv6)
+ s = format (s, "via %U ", format_ip6_address, mp->next_hop_address);
+ else
+ s = format (s, "via %U ", format_ip4_address, mp->next_hop_address);
+ }
+
+ if (mp->table_id != 0)
+ s = format (s, "vrf %d ", ntohl (mp->table_id));
+
+ if (mp->next_hop_weight != 1)
+ s = format (s, "weight %d ", mp->next_hop_weight);
+
+ if (mp->not_last)
+ s = format (s, "not-last ");
+
+ if (mp->is_multipath)
+ s = format (s, "multipath ");
+
+ if (mp->is_multipath)
+ s = format (s, "multipath ");
+
+ if (mp->next_hop_table_id)
+ s = format (s, "lookup-in-vrf %d ", ntohl (mp->next_hop_table_id));
+
+ FINISH;
+}
+
+static void *vl_api_proxy_arp_add_del_t_print
+ (vl_api_proxy_arp_add_del_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: proxy_arp_add_del ");
+
+ s = format (s, "%U - %U ", format_ip4_address, mp->low_address,
+ format_ip4_address, mp->hi_address);
+
+ if (mp->vrf_id)
+ s = format (s, "vrf %d ", ntohl (mp->vrf_id));
+
+ if (mp->is_add == 0)
+ s = format (s, "del ");
+
+ FINISH;
+}
+
+static void *vl_api_proxy_arp_intfc_enable_disable_t_print
+ (vl_api_proxy_arp_intfc_enable_disable_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: proxy_arp_intfc_enable_disable ");
+
+ s = format (s, "sw_if_index %d ", ntohl (mp->sw_if_index));
+
+ s = format (s, "enable %d ", mp->enable_disable);
+
+ FINISH;
+}
+
+static void *vl_api_mpls_tunnel_add_del_t_print
+ (vl_api_mpls_tunnel_add_del_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: mpls_tunnel_add_del ");
+
+ if (mp->mt_next_hop_sw_if_index)
+ s = format (s, "sw_if_index %d ", ntohl (mp->mt_next_hop_sw_if_index));
+
+ if (mp->mt_next_hop_proto_is_ip4)
+ s = format (s, "%U ", format_ip4_address, mp->mt_next_hop);
+ else
+ s = format (s, "%U ", format_ip6_address, mp->mt_next_hop);
+
+ if (mp->mt_l2_only)
+ s = format (s, "l2-only ");
+
+ if (mp->mt_is_add == 0)
+ s = format (s, "del ");
+
+ FINISH;
+}
+
+static void *vl_api_sw_interface_set_unnumbered_t_print
+ (vl_api_sw_interface_set_unnumbered_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: sw_interface_set_unnumbered ");
+
+ s = format (s, "sw_if_index %d ", ntohl (mp->sw_if_index));
+
+ s = format (s, "unnum_if_index %d ", ntohl (mp->unnumbered_sw_if_index));
+
+ if (mp->is_add == 0)
+ s = format (s, "del ");
+
+ FINISH;
+}
+
+static void *vl_api_ip_neighbor_add_del_t_print
+ (vl_api_ip_neighbor_add_del_t * mp, void *handle)
+{
+ u8 *s;
+ u8 null_mac[6];
+
+ memset (null_mac, 0, sizeof (null_mac));
+
+ s = format (0, "SCRIPT: ip_neighbor_add_del ");
+
+ s = format (s, "sw_if_index %d ", ntohl (mp->sw_if_index));
+
+ if (mp->is_static)
+ s = format (s, "is_static ");
+
+ if (mp->is_no_adj_fib)
+ s = format (s, "is_no_fib_entry ");
+
+ if (memcmp (mp->mac_address, null_mac, 6))
+ s = format (s, "mac %U ", format_ethernet_address, mp->mac_address);
+
+ if (mp->is_ipv6)
+ s =
+ format (s, "dst %U ", format_ip6_address,
+ (ip6_address_t *) mp->dst_address);
+ else
+ s =
+ format (s, "dst %U ", format_ip4_address,
+ (ip4_address_t *) mp->dst_address);
+
+ if (mp->is_add == 0)
+ s = format (s, "del ");
+
+ FINISH;
+}
+
+static void *
+vl_api_reset_vrf_t_print (vl_api_reset_vrf_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: reset_vrf ");
+
+ if (mp->vrf_id)
+ s = format (s, "vrf %d ", ntohl (mp->vrf_id));
+
+ if (mp->is_ipv6 != 0)
+ s = format (s, "ipv6 ");
+
+ FINISH;
+}
+
+static void *vl_api_create_vlan_subif_t_print
+ (vl_api_create_vlan_subif_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: create_vlan_subif ");
+
+ if (mp->sw_if_index)
+ s = format (s, "sw_if_index %d ", ntohl (mp->sw_if_index));
+
+ if (mp->vlan_id)
+ s = format (s, "vlan_id %d ", ntohl (mp->vlan_id));
+
+ FINISH;
+}
+
+#define foreach_create_subif_bit \
+_(no_tags) \
+_(one_tag) \
+_(two_tags) \
+_(dot1ad) \
+_(exact_match) \
+_(default_sub) \
+_(outer_vlan_id_any) \
+_(inner_vlan_id_any)
+
+static void *vl_api_create_subif_t_print
+ (vl_api_create_subif_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: create_subif ");
+
+ s = format (s, "sw_if_index %d ", ntohl (mp->sw_if_index));
+
+ s = format (s, "sub_id %d ", ntohl (mp->sub_id));
+
+ if (mp->outer_vlan_id)
+ s = format (s, "outer_vlan_id %d ", ntohs (mp->outer_vlan_id));
+
+ if (mp->inner_vlan_id)
+ s = format (s, "inner_vlan_id %d ", ntohs (mp->inner_vlan_id));
+
+#define _(a) if (mp->a) s = format (s, "%s ", #a);
+ foreach_create_subif_bit;
+#undef _
+
+ FINISH;
+}
+
+static void *vl_api_delete_subif_t_print
+ (vl_api_delete_subif_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: delete_subif ");
+ s = format (s, "sw_if_index %d ", ntohl (mp->sw_if_index));
+
+ FINISH;
+}
+
+static void *vl_api_oam_add_del_t_print
+ (vl_api_oam_add_del_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: oam_add_del ");
+
+ if (mp->vrf_id)
+ s = format (s, "vrf %d ", ntohl (mp->vrf_id));
+
+ s = format (s, "src %U ", format_ip4_address, mp->src_address);
+
+ s = format (s, "dst %U ", format_ip4_address, mp->dst_address);
+
+ if (mp->is_add == 0)
+ s = format (s, "del ");
+
+ FINISH;
+}
+
+static void *
+vl_api_reset_fib_t_print (vl_api_reset_fib_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: reset_fib ");
+
+ if (mp->vrf_id)
+ s = format (s, "vrf %d ", ntohl (mp->vrf_id));
+
+ if (mp->is_ipv6 != 0)
+ s = format (s, "ipv6 ");
+
+ FINISH;
+}
+
+static void *vl_api_dhcp_proxy_config_t_print
+ (vl_api_dhcp_proxy_config_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: dhcp_proxy_config_2 ");
+
+ s = format (s, "rx_vrf_id %d ", ntohl (mp->rx_vrf_id));
+ s = format (s, "server_vrf_id %d ", ntohl (mp->server_vrf_id));
+
+ if (mp->is_ipv6)
+ {
+ s = format (s, "svr %U ", format_ip6_address,
+ (ip6_address_t *) mp->dhcp_server);
+ s = format (s, "src %U ", format_ip6_address,
+ (ip6_address_t *) mp->dhcp_src_address);
+ }
+ else
+ {
+ s = format (s, "svr %U ", format_ip4_address,
+ (ip4_address_t *) mp->dhcp_server);
+ s = format (s, "src %U ", format_ip4_address,
+ (ip4_address_t *) mp->dhcp_src_address);
+ }
+ if (mp->is_add == 0)
+ s = format (s, "del ");
+
+ FINISH;
+}
+
+static void *vl_api_dhcp_proxy_set_vss_t_print
+ (vl_api_dhcp_proxy_set_vss_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: dhcp_proxy_set_vss ");
+
+ s = format (s, "tbl_id %d ", ntohl (mp->tbl_id));
+
+ s = format (s, "fib_id %d ", ntohl (mp->fib_id));
+
+ s = format (s, "oui %d ", ntohl (mp->oui));
+
+ if (mp->is_ipv6 != 0)
+ s = format (s, "ipv6 ");
+
+ if (mp->is_add == 0)
+ s = format (s, "del ");
+
+ FINISH;
+}
+
+static void *vl_api_dhcp_client_config_t_print
+ (vl_api_dhcp_client_config_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: dhcp_client_config ");
+
+ s = format (s, "sw_if_index %d ", ntohl (mp->sw_if_index));
+
+ s = format (s, "hostname %s ", mp->hostname);
+
+ s = format (s, "want_dhcp_event %d ", mp->want_dhcp_event);
+
+ s = format (s, "pid %d ", ntohl (mp->pid));
+
+ if (mp->is_add == 0)
+ s = format (s, "del ");
+
+ FINISH;
+}
+
+
+static void *vl_api_set_ip_flow_hash_t_print
+ (vl_api_set_ip_flow_hash_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: set_ip_flow_hash ");
+
+ s = format (s, "vrf_id %d ", ntohl (mp->vrf_id));
+
+ if (mp->src)
+ s = format (s, "src ");
+
+ if (mp->dst)
+ s = format (s, "dst ");
+
+ if (mp->sport)
+ s = format (s, "sport ");
+
+ if (mp->dport)
+ s = format (s, "dport ");
+
+ if (mp->proto)
+ s = format (s, "proto ");
+
+ if (mp->reverse)
+ s = format (s, "reverse ");
+
+ if (mp->is_ipv6 != 0)
+ s = format (s, "ipv6 ");
+
+ FINISH;
+}
+
+static void *vl_api_sw_interface_ip6_set_link_local_address_t_print
+ (vl_api_sw_interface_ip6_set_link_local_address_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: sw_interface_ip6_set_link_local_address ");
+
+ s = format (s, "sw_if_index %d ", ntohl (mp->sw_if_index));
+
+ s = format (s, "%U ", format_ip6_address, mp->address);
+
+ FINISH;
+}
+
+static void *vl_api_sw_interface_ip6nd_ra_prefix_t_print
+ (vl_api_sw_interface_ip6nd_ra_prefix_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: sw_interface_ip6nd_ra_prefix ");
+
+ s = format (s, "sw_if_index %d ", ntohl (mp->sw_if_index));
+
+ s = format (s, "%U/%d ", format_ip6_address, mp->address,
+ mp->address_length);
+
+ s = format (s, "val_life %d ", ntohl (mp->val_lifetime));
+
+ s = format (s, "pref_life %d ", ntohl (mp->pref_lifetime));
+
+ if (mp->use_default)
+ s = format (s, "def ");
+
+ if (mp->no_advertise)
+ s = format (s, "noadv ");
+
+ if (mp->off_link)
+ s = format (s, "offl ");
+
+ if (mp->no_autoconfig)
+ s = format (s, "noauto ");
+
+ if (mp->no_onlink)
+ s = format (s, "nolink ");
+
+ if (mp->is_no)
+ s = format (s, "isno ");
+
+ FINISH;
+}
+
+static void *vl_api_sw_interface_ip6nd_ra_config_t_print
+ (vl_api_sw_interface_ip6nd_ra_config_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: sw_interface_ip6nd_ra_config ");
+
+ s = format (s, "sw_if_index %d ", ntohl (mp->sw_if_index));
+
+ s = format (s, "maxint %d ", ntohl (mp->max_interval));
+
+ s = format (s, "minint %d ", ntohl (mp->min_interval));
+
+ s = format (s, "life %d ", ntohl (mp->lifetime));
+
+ s = format (s, "count %d ", ntohl (mp->initial_count));
+
+ s = format (s, "interval %d ", ntohl (mp->initial_interval));
+
+ if (mp->suppress)
+ s = format (s, "suppress ");
+
+ if (mp->managed)
+ s = format (s, "managed ");
+
+ if (mp->other)
+ s = format (s, "other ");
+
+ if (mp->ll_option)
+ s = format (s, "ll ");
+
+ if (mp->send_unicast)
+ s = format (s, "send ");
+
+ if (mp->cease)
+ s = format (s, "cease ");
+
+ if (mp->is_no)
+ s = format (s, "isno ");
+
+ if (mp->default_router)
+ s = format (s, "def ");
+
+ FINISH;
+}
+
+static void *vl_api_set_arp_neighbor_limit_t_print
+ (vl_api_set_arp_neighbor_limit_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: set_arp_neighbor_limit ");
+
+ s = format (s, "arp_nbr_limit %d ", ntohl (mp->arp_neighbor_limit));
+
+ if (mp->is_ipv6 != 0)
+ s = format (s, "ipv6 ");
+
+ FINISH;
+}
+
+static void *vl_api_l2_patch_add_del_t_print
+ (vl_api_l2_patch_add_del_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: l2_patch_add_del ");
+
+ s = format (s, "rx_sw_if_index %d ", ntohl (mp->rx_sw_if_index));
+
+ s = format (s, "tx_sw_if_index %d ", ntohl (mp->tx_sw_if_index));
+
+ if (mp->is_add == 0)
+ s = format (s, "del ");
+
+ FINISH;
+}
+
+static void *vl_api_sr_localsid_add_del_t_print
+ (vl_api_sr_localsid_add_del_t * mp, void *handle)
+{
+ vnet_main_t *vnm = vnet_get_main ();
+ u8 *s;
+
+ s = format (0, "SCRIPT: sr_localsid_add_del ");
+
+ switch (mp->behavior)
+ {
+ case SR_BEHAVIOR_END:
+ s = format (s, "Address: %U\nBehavior: End",
+ format_ip6_address, (ip6_address_t *) mp->localsid_addr);
+ s = format (s, (mp->end_psp ? "End.PSP: True" : "End.PSP: False"));
+ break;
+ case SR_BEHAVIOR_X:
+ s =
+ format (s,
+ "Address: %U\nBehavior: X (Endpoint with Layer-3 cross-connect)"
+ "\nIface: %U\nNext hop: %U", format_ip6_address,
+ (ip6_address_t *) mp->localsid_addr,
+ format_vnet_sw_if_index_name, vnm, ntohl (mp->sw_if_index),
+ format_ip6_address, (ip6_address_t *) mp->nh_addr);
+ s = format (s, (mp->end_psp ? "End.PSP: True" : "End.PSP: False"));
+ break;
+ case SR_BEHAVIOR_DX4:
+ s =
+ format (s,
+ "Address: %U\nBehavior: DX4 (Endpoint with decapsulation with IPv4 cross-connect)"
+ "\nIface: %U\nNext hop: %U", format_ip6_address,
+ (ip6_address_t *) mp->localsid_addr,
+ format_vnet_sw_if_index_name, vnm, ntohl (mp->sw_if_index),
+ format_ip4_address, (ip4_address_t *) mp->nh_addr);
+ break;
+ case SR_BEHAVIOR_DX6:
+ s =
+ format (s,
+ "Address: %U\nBehavior: DX6 (Endpoint with decapsulation with IPv6 cross-connect)"
+ "\nIface: %UNext hop: %U", format_ip6_address,
+ (ip6_address_t *) mp->localsid_addr,
+ format_vnet_sw_if_index_name, vnm, ntohl (mp->sw_if_index),
+ format_ip6_address, (ip6_address_t *) mp->nh_addr);
+ break;
+ case SR_BEHAVIOR_DX2:
+ s =
+ format (s,
+ "Address: %U\nBehavior: DX2 (Endpoint with decapulation and Layer-2 cross-connect)"
+ "\nIface: %U", format_ip6_address,
+ (ip6_address_t *) mp->localsid_addr,
+ format_vnet_sw_if_index_name, vnm, ntohl (mp->sw_if_index));
+ break;
+ case SR_BEHAVIOR_DT6:
+ s =
+ format (s,
+ "Address: %U\nBehavior: DT6 (Endpoint with decapsulation and specific IPv6 table lookup)"
+ "\nTable: %u", format_ip6_address,
+ (ip6_address_t *) mp->localsid_addr, ntohl (mp->fib_table));
+ break;
+ case SR_BEHAVIOR_DT4:
+ s =
+ format (s,
+ "Address: %U\nBehavior: DT4 (Endpoint with decapsulation and specific IPv4 table lookup)"
+ "\nTable: %u", format_ip6_address,
+ (ip6_address_t *) mp->localsid_addr, ntohl (mp->fib_table));
+ break;
+ default:
+ if (mp->behavior >= SR_BEHAVIOR_LAST)
+ {
+ s = format (s, "Address: %U\n Behavior: %u",
+ format_ip6_address, (ip6_address_t *) mp->localsid_addr,
+ mp->behavior);
+ }
+ else
+ //Should never get here...
+ s = format (s, "Internal error");
+ break;
+ }
+ FINISH;
+}
+
+static void *vl_api_sr_steering_add_del_t_print
+ (vl_api_sr_steering_add_del_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: sr_steering_add_del ");
+
+ s = format (s, (mp->is_del ? "Del: True" : "Del: False"));
+
+ switch (mp->traffic_type)
+ {
+ case SR_STEER_L2:
+ s = format (s, "Traffic type: L2 iface: %u", ntohl (mp->sw_if_index));
+ break;
+ case SR_STEER_IPV4:
+ s = format (s, "Traffic type: IPv4 %U/%u", format_ip4_address,
+ (ip4_address_t *) mp->prefix_addr, ntohl (mp->mask_width));
+ break;
+ case SR_STEER_IPV6:
+ s = format (s, "Traffic type: IPv6 %U/%u", format_ip6_address,
+ (ip6_address_t *) mp->prefix_addr, ntohl (mp->mask_width));
+ break;
+ default:
+ s = format (s, "Traffic type: Unknown(%u)", mp->traffic_type);
+ break;
+ }
+ s = format (s, "BindingSID: %U", format_ip6_address,
+ (ip6_address_t *) mp->bsid_addr);
+
+ s = format (s, "SR Policy Index: %u", ntohl (mp->sr_policy_index));
+
+ s = format (s, "FIB_table: %u", ntohl (mp->table_id));
+
+ FINISH;
+}
+
+static void *vl_api_sr_policy_add_t_print
+ (vl_api_sr_policy_add_t * mp, void *handle)
+{
+ u8 *s;
+
+ ip6_address_t *segments = 0, *seg;
+ ip6_address_t *this_address = (ip6_address_t *) mp->segments;
+
+ int i;
+ for (i = 0; i < mp->n_segments; i++)
+ {
+ vec_add2 (segments, seg, 1);
+ clib_memcpy (seg->as_u8, this_address->as_u8, sizeof (*this_address));
+ this_address++;
+ }
+
+ s = format (0, "SCRIPT: sr_policy_add ");
+
+ s = format (s, "BSID: %U", format_ip6_address,
+ (ip6_address_t *) mp->bsid_addr);
+
+ s =
+ format (s,
+ (mp->is_encap ? "Behavior: Encapsulation" :
+ "Behavior: SRH insertion"));
+
+ s = format (s, "FIB_table: %u", ntohl (mp->fib_table));
+
+ s = format (s, (mp->type ? "Type: Default" : "Type: Spray"));
+
+ s = format (s, "SID list weight: %u", ntohl (mp->weight));
+
+ s = format (s, "{");
+ vec_foreach (seg, segments)
+ {
+ s = format (s, "%U, ", format_ip6_address, seg);
+ }
+ s = format (s, "\b\b } ");
+
+ FINISH;
+}
+
+static void *vl_api_sr_policy_mod_t_print
+ (vl_api_sr_policy_mod_t * mp, void *handle)
+{
+ u8 *s;
+
+ ip6_address_t *segments = 0, *seg;
+ ip6_address_t *this_address = (ip6_address_t *) mp->segments;
+
+ int i;
+ for (i = 0; i < mp->n_segments; i++)
+ {
+ vec_add2 (segments, seg, 1);
+ clib_memcpy (seg->as_u8, this_address->as_u8, sizeof (*this_address));
+ this_address++;
+ }
+
+ s = format (0, "SCRIPT: sr_policy_mod ");
+
+ s = format (s, "BSID: %U", format_ip6_address,
+ (ip6_address_t *) mp->bsid_addr);
+
+ s = format (s, "SR Policy index: %u", ntohl (mp->sr_policy_index));
+
+ s = format (s, "Operation: %u", mp->operation);
+
+ s = format (s, "SID list index: %u", ntohl (mp->sl_index));
+
+ s = format (s, "SID list weight: %u", ntohl (mp->weight));
+
+ s = format (s, "{");
+ vec_foreach (seg, segments)
+ {
+ s = format (s, "%U, ", format_ip6_address, seg);
+ }
+ s = format (s, "\b\b } ");
+
+ FINISH;
+}
+
+static void *vl_api_sr_policy_del_t_print
+ (vl_api_sr_policy_del_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: sr_policy_del ");
+ s = format (s, "To be delivered. Good luck.");
+ FINISH;
+}
+
+static void *vl_api_classify_add_del_table_t_print
+ (vl_api_classify_add_del_table_t * mp, void *handle)
+{
+ u8 *s;
+ int i;
+
+ s = format (0, "SCRIPT: classify_add_del_table ");
+
+ if (mp->is_add == 0)
+ {
+ s = format (s, "table %d ", ntohl (mp->table_index));
+ s = format (s, "%s ", mp->del_chain ? "del-chain" : "del");
+ }
+ else
+ {
+ s = format (s, "nbuckets %d ", ntohl (mp->nbuckets));
+ s = format (s, "memory_size %d ", ntohl (mp->memory_size));
+ s = format (s, "skip %d ", ntohl (mp->skip_n_vectors));
+ s = format (s, "match %d ", ntohl (mp->match_n_vectors));
+ s = format (s, "next-table %d ", ntohl (mp->next_table_index));
+ s = format (s, "miss-next %d ", ntohl (mp->miss_next_index));
+ s = format (s, "current-data-flag %d ", ntohl (mp->current_data_flag));
+ if (mp->current_data_flag)
+ s = format (s, "current-data-offset %d ",
+ ntohl (mp->current_data_offset));
+ s = format (s, "mask hex ");
+ for (i = 0; i < ntohl (mp->match_n_vectors) * sizeof (u32x4); i++)
+ s = format (s, "%02x", mp->mask[i]);
+ vec_add1 (s, ' ');
+ }
+
+ FINISH;
+}
+
+static void *vl_api_classify_add_del_session_t_print
+ (vl_api_classify_add_del_session_t * mp, void *handle)
+{
+ u8 *s;
+ int i, limit = 0;
+
+ s = format (0, "SCRIPT: classify_add_del_session ");
+
+ s = format (s, "table_index %d ", ntohl (mp->table_index));
+ s = format (s, "hit_next_index %d ", ntohl (mp->hit_next_index));
+ s = format (s, "opaque_index %d ", ntohl (mp->opaque_index));
+ s = format (s, "advance %d ", ntohl (mp->advance));
+ s = format (s, "action %d ", mp->action);
+ if (mp->action)
+ s = format (s, "metadata %d ", ntohl (mp->metadata));
+ if (mp->is_add == 0)
+ s = format (s, "del ");
+
+ s = format (s, "match hex ");
+ for (i = 5 * sizeof (u32x4) - 1; i > 0; i--)
+ {
+ if (mp->match[i] != 0)
+ {
+ limit = i + 1;
+ break;
+ }
+ }
+
+ for (i = 0; i < limit; i++)
+ s = format (s, "%02x", mp->match[i]);
+
+ FINISH;
+}
+
+static void *vl_api_classify_set_interface_ip_table_t_print
+ (vl_api_classify_set_interface_ip_table_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: classify_set_interface_ip_table ");
+
+ if (mp->is_ipv6)
+ s = format (s, "ipv6 ");
+
+ s = format (s, "sw_if_index %d ", ntohl (mp->sw_if_index));
+ s = format (s, "table %d ", ntohl (mp->table_index));
+
+ FINISH;
+}
+
+static void *vl_api_classify_set_interface_l2_tables_t_print
+ (vl_api_classify_set_interface_l2_tables_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: classify_set_interface_l2_tables ");
+
+ s = format (s, "sw_if_index %d ", ntohl (mp->sw_if_index));
+ s = format (s, "ip4-table %d ", ntohl (mp->ip4_table_index));
+ s = format (s, "ip6-table %d ", ntohl (mp->ip6_table_index));
+ s = format (s, "other-table %d ", ntohl (mp->other_table_index));
+ s = format (s, "is-input %d ", mp->is_input);
+
+ FINISH;
+}
+
+static void *vl_api_add_node_next_t_print
+ (vl_api_add_node_next_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: add_node_next ");
+
+ s = format (0, "node %s next %s ", mp->node_name, mp->next_name);
+
+ FINISH;
+}
+
+static void *vl_api_l2tpv3_create_tunnel_t_print
+ (vl_api_l2tpv3_create_tunnel_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: l2tpv3_create_tunnel ");
+
+ s = format (s, "client_address %U our_address %U ",
+ format_ip6_address, (ip6_address_t *) (mp->client_address),
+ format_ip6_address, (ip6_address_t *) (mp->our_address));
+ s = format (s, "local_session_id %d ", ntohl (mp->local_session_id));
+ s = format (s, "remote_session_id %d ", ntohl (mp->remote_session_id));
+ s = format (s, "local_cookie %lld ",
+ clib_net_to_host_u64 (mp->local_cookie));
+ s = format (s, "remote_cookie %lld ",
+ clib_net_to_host_u64 (mp->remote_cookie));
+ if (mp->l2_sublayer_present)
+ s = format (s, "l2-sublayer-present ");
+
+ FINISH;
+}
+
+static void *vl_api_l2tpv3_set_tunnel_cookies_t_print
+ (vl_api_l2tpv3_set_tunnel_cookies_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: l2tpv3_set_tunnel_cookies ");
+
+ s = format (s, "sw_if_index %d ", ntohl (mp->sw_if_index));
+
+ s = format (s, "new_local_cookie %llu ",
+ clib_net_to_host_u64 (mp->new_local_cookie));
+
+ s = format (s, "new_remote_cookie %llu ",
+ clib_net_to_host_u64 (mp->new_remote_cookie));
+
+ FINISH;
+}
+
+static void *vl_api_l2tpv3_interface_enable_disable_t_print
+ (vl_api_l2tpv3_interface_enable_disable_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: l2tpv3_interface_enable_disable ");
+
+ s = format (s, "sw_if_index %d ", ntohl (mp->sw_if_index));
+
+ if (mp->enable_disable == 0)
+ s = format (s, "del ");
+
+ FINISH;
+}
+
+static void *vl_api_l2tpv3_set_lookup_key_t_print
+ (vl_api_l2tpv3_set_lookup_key_t * mp, void *handle)
+{
+ u8 *s;
+ char *str = "unknown";
+
+ s = format (0, "SCRIPT: l2tpv3_set_lookup_key ");
+
+ switch (mp->key)
+ {
+ case L2T_LOOKUP_SRC_ADDRESS:
+ str = "lookup_v6_src";
+ break;
+ case L2T_LOOKUP_DST_ADDRESS:
+ str = "lookup_v6_dst";
+ break;
+ case L2T_LOOKUP_SESSION_ID:
+ str = "lookup_session_id";
+ break;
+ default:
+ break;
+ }
+
+ s = format (s, "%s ", str);
+
+ FINISH;
+}
+
+static void *vl_api_sw_if_l2tpv3_tunnel_dump_t_print
+ (vl_api_sw_if_l2tpv3_tunnel_dump_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: sw_if_l2tpv3_tunnel_dump ");
+
+ FINISH;
+}
+
+static void *vl_api_vxlan_add_del_tunnel_t_print
+ (vl_api_vxlan_add_del_tunnel_t * mp, void *handle)
+{
+ u8 *s;
+ s = format (0, "SCRIPT: vxlan_add_del_tunnel ");
+
+ ip46_address_t src = to_ip46 (mp->is_ipv6, mp->src_address);
+ ip46_address_t dst = to_ip46 (mp->is_ipv6, mp->dst_address);
+
+ u8 is_grp = ip46_address_is_multicast (&dst);
+ char *dst_name = is_grp ? "group" : "dst";
+
+ s = format (s, "src %U ", format_ip46_address, &src, IP46_TYPE_ANY);
+ s = format (s, "%s %U ", dst_name, format_ip46_address,
+ &dst, IP46_TYPE_ANY);
+
+ if (is_grp)
+ s = format (s, "mcast_sw_if_index %d ", ntohl (mp->mcast_sw_if_index));
+
+ if (mp->encap_vrf_id)
+ s = format (s, "encap-vrf-id %d ", ntohl (mp->encap_vrf_id));
+
+ s = format (s, "decap-next %d ", ntohl (mp->decap_next_index));
+
+ s = format (s, "vni %d ", ntohl (mp->vni));
+
+ if (mp->is_add == 0)
+ s = format (s, "del ");
+
+ FINISH;
+}
+
+static void *vl_api_vxlan_tunnel_dump_t_print
+ (vl_api_vxlan_tunnel_dump_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: vxlan_tunnel_dump ");
+
+ s = format (s, "sw_if_index %d ", ntohl (mp->sw_if_index));
+
+ FINISH;
+}
+
+static void *vl_api_gre_add_del_tunnel_t_print
+ (vl_api_gre_add_del_tunnel_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: gre_add_del_tunnel ");
+
+ s = format (s, "dst %U ", format_ip46_address,
+ (ip46_address_t *) & (mp->dst_address),
+ mp->is_ipv6 ? IP46_TYPE_IP6 : IP46_TYPE_IP4);
+
+ s = format (s, "src %U ", format_ip46_address,
+ (ip46_address_t *) & (mp->src_address),
+ mp->is_ipv6 ? IP46_TYPE_IP6 : IP46_TYPE_IP4);
+
+ if (mp->teb)
+ s = format (s, "teb ");
+
+ if (mp->outer_fib_id)
+ s = format (s, "outer-fib-id %d ", ntohl (mp->outer_fib_id));
+
+ if (mp->is_add == 0)
+ s = format (s, "del ");
+
+ FINISH;
+}
+
+static void *vl_api_gre_tunnel_dump_t_print
+ (vl_api_gre_tunnel_dump_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: gre_tunnel_dump ");
+
+ s = format (s, "sw_if_index %d ", ntohl (mp->sw_if_index));
+
+ FINISH;
+}
+
+static void *vl_api_l2_fib_clear_table_t_print
+ (vl_api_l2_fib_clear_table_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: l2_fib_clear_table ");
+
+ FINISH;
+}
+
+static void *vl_api_l2_interface_efp_filter_t_print
+ (vl_api_l2_interface_efp_filter_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: l2_interface_efp_filter ");
+
+ s = format (s, "sw_if_index %d ", ntohl (mp->sw_if_index));
+ if (mp->enable_disable)
+ s = format (s, "enable ");
+ else
+ s = format (s, "disable ");
+
+ FINISH;
+}
+
+static void *vl_api_l2_interface_vlan_tag_rewrite_t_print
+ (vl_api_l2_interface_vlan_tag_rewrite_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: l2_interface_vlan_tag_rewrite ");
+
+ s = format (s, "sw_if_index %d ", ntohl (mp->sw_if_index));
+ s = format (s, "vtr_op %d ", ntohl (mp->vtr_op));
+ s = format (s, "push_dot1q %d ", ntohl (mp->push_dot1q));
+ s = format (s, "tag1 %d ", ntohl (mp->tag1));
+ s = format (s, "tag2 %d ", ntohl (mp->tag2));
+
+ FINISH;
+}
+
+static void *vl_api_create_vhost_user_if_t_print
+ (vl_api_create_vhost_user_if_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: create_vhost_user_if ");
+
+ s = format (s, "socket %s ", mp->sock_filename);
+ if (mp->is_server)
+ s = format (s, "server ");
+ if (mp->renumber)
+ s = format (s, "renumber %d ", ntohl (mp->custom_dev_instance));
+ if (mp->tag[0])
+ s = format (s, "tag %s", mp->tag);
+
+ FINISH;
+}
+
+static void *vl_api_modify_vhost_user_if_t_print
+ (vl_api_modify_vhost_user_if_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: modify_vhost_user_if ");
+
+ s = format (s, "sw_if_index %d ", ntohl (mp->sw_if_index));
+ s = format (s, "socket %s ", mp->sock_filename);
+ if (mp->is_server)
+ s = format (s, "server ");
+ if (mp->renumber)
+ s = format (s, "renumber %d ", ntohl (mp->custom_dev_instance));
+
+ FINISH;
+}
+
+static void *vl_api_delete_vhost_user_if_t_print
+ (vl_api_delete_vhost_user_if_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: delete_vhost_user_if ");
+ s = format (s, "sw_if_index %d ", ntohl (mp->sw_if_index));
+
+ FINISH;
+}
+
+static void *vl_api_sw_interface_vhost_user_dump_t_print
+ (vl_api_sw_interface_vhost_user_dump_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: sw_interface_vhost_user_dump ");
+
+ FINISH;
+}
+
+static void *vl_api_sw_interface_dump_t_print
+ (vl_api_sw_interface_dump_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: sw_interface_dump ");
+
+ if (mp->name_filter_valid)
+ s = format (s, "name_filter %s ", mp->name_filter);
+ else
+ s = format (s, "all ");
+
+ FINISH;
+}
+
+static void *vl_api_l2_fib_table_dump_t_print
+ (vl_api_l2_fib_table_dump_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: l2_fib_table_dump ");
+
+ s = format (s, "bd_id %d ", ntohl (mp->bd_id));
+
+ FINISH;
+}
+
+static void *vl_api_control_ping_t_print
+ (vl_api_control_ping_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: control_ping ");
+
+ FINISH;
+}
+
+static void *vl_api_want_interface_events_t_print
+ (vl_api_want_interface_events_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: want_interface_events pid %d enable %d ",
+ ntohl (mp->pid), ntohl (mp->enable_disable));
+
+ FINISH;
+}
+
+static void *
+vl_api_cli_t_print (vl_api_cli_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: cli ");
+
+ FINISH;
+}
+
+static void *vl_api_cli_inband_t_print
+ (vl_api_cli_inband_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: cli_inband ");
+
+ FINISH;
+}
+
+static void *vl_api_memclnt_create_t_print
+ (vl_api_memclnt_create_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: memclnt_create name %s ", mp->name);
+
+ FINISH;
+}
+
+static void *vl_api_show_version_t_print
+ (vl_api_show_version_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: show_version ");
+
+ FINISH;
+}
+
+static void *vl_api_vxlan_gpe_add_del_tunnel_t_print
+ (vl_api_vxlan_gpe_add_del_tunnel_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: vxlan_gpe_add_del_tunnel ");
+
+ ip46_address_t local = to_ip46 (mp->is_ipv6, mp->local);
+ ip46_address_t remote = to_ip46 (mp->is_ipv6, mp->remote);
+
+ u8 is_grp = ip46_address_is_multicast (&remote);
+ char *remote_name = is_grp ? "group" : "remote";
+
+ s = format (s, "local %U ", format_ip46_address, &local, IP46_TYPE_ANY);
+ s = format (s, "%s %U ", remote_name, format_ip46_address,
+ &remote, IP46_TYPE_ANY);
+
+ if (is_grp)
+ s = format (s, "mcast_sw_if_index %d ", ntohl (mp->mcast_sw_if_index));
+ s = format (s, "protocol %d ", ntohl (mp->protocol));
+
+ s = format (s, "vni %d ", ntohl (mp->vni));
+
+ if (mp->is_add == 0)
+ s = format (s, "del ");
+
+ if (mp->encap_vrf_id)
+ s = format (s, "encap-vrf-id %d ", ntohl (mp->encap_vrf_id));
+
+ if (mp->decap_vrf_id)
+ s = format (s, "decap-vrf-id %d ", ntohl (mp->decap_vrf_id));
+
+ FINISH;
+}
+
+static void *vl_api_vxlan_gpe_tunnel_dump_t_print
+ (vl_api_vxlan_gpe_tunnel_dump_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: vxlan_gpe_tunnel_dump ");
+
+ s = format (s, "sw_if_index %d ", ntohl (mp->sw_if_index));
+
+ FINISH;
+}
+
+static void *vl_api_interface_name_renumber_t_print
+ (vl_api_interface_name_renumber_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: interface_renumber ");
+
+ s = format (s, "sw_if_index %d ", ntohl (mp->sw_if_index));
+
+ s = format (s, "new_show_dev_instance %d ",
+ ntohl (mp->new_show_dev_instance));
+
+ FINISH;
+}
+
+static void *vl_api_want_ip4_arp_events_t_print
+ (vl_api_want_ip4_arp_events_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: want_ip4_arp_events ");
+ s = format (s, "pid %d address %U ", ntohl (mp->pid),
+ format_ip4_address, &mp->address);
+ if (mp->enable_disable == 0)
+ s = format (s, "del ");
+
+ FINISH;
+}
+
+static void *vl_api_want_ip6_nd_events_t_print
+ (vl_api_want_ip6_nd_events_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: want_ip6_nd_events ");
+ s = format (s, "pid %d address %U ", ntohl (mp->pid),
+ format_ip6_address, mp->address);
+ if (mp->enable_disable == 0)
+ s = format (s, "del ");
+
+ FINISH;
+}
+
+static void *vl_api_want_l2_macs_events_t_print
+ (vl_api_want_l2_macs_events_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: want_l2_macs_events ");
+ s = format (s, "learn-limit %d ", ntohl (mp->learn_limit));
+ s = format (s, "scan-delay %d ", (u32) mp->scan_delay);
+ s = format (s, "max-entries %d ", (u32) mp->max_macs_in_event * 10);
+ if (mp->enable_disable == 0)
+ s = format (s, "disable");
+
+ FINISH;
+}
+
+static void *vl_api_input_acl_set_interface_t_print
+ (vl_api_input_acl_set_interface_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: input_acl_set_interface ");
+
+ s = format (s, "sw_if_index %d ", ntohl (mp->sw_if_index));
+ s = format (s, "ip4-table %d ", ntohl (mp->ip4_table_index));
+ s = format (s, "ip6-table %d ", ntohl (mp->ip6_table_index));
+ s = format (s, "l2-table %d ", ntohl (mp->l2_table_index));
+
+ if (mp->is_add == 0)
+ s = format (s, "del ");
+
+ FINISH;
+}
+
+static void *vl_api_ip_address_dump_t_print
+ (vl_api_ip_address_dump_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: ip6_address_dump ");
+ s = format (s, "sw_if_index %d ", ntohl (mp->sw_if_index));
+ s = format (s, "is_ipv6 %d ", mp->is_ipv6 != 0);
+
+ FINISH;
+}
+
+static void *
+vl_api_ip_dump_t_print (vl_api_ip_dump_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: ip_dump ");
+ s = format (s, "is_ipv6 %d ", mp->is_ipv6 != 0);
+
+ FINISH;
+}
+
+static void *vl_api_cop_interface_enable_disable_t_print
+ (vl_api_cop_interface_enable_disable_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: cop_interface_enable_disable ");
+ s = format (s, "sw_if_index %d ", ntohl (mp->sw_if_index));
+ if (mp->enable_disable)
+ s = format (s, "enable ");
+ else
+ s = format (s, "disable ");
+
+ FINISH;
+}
+
+static void *vl_api_cop_whitelist_enable_disable_t_print
+ (vl_api_cop_whitelist_enable_disable_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: cop_whitelist_enable_disable ");
+ s = format (s, "sw_if_index %d ", ntohl (mp->sw_if_index));
+ s = format (s, "fib-id %d ", ntohl (mp->fib_id));
+ if (mp->ip4)
+ s = format (s, "ip4 ");
+ if (mp->ip6)
+ s = format (s, "ip6 ");
+ if (mp->default_cop)
+ s = format (s, "default ");
+
+ FINISH;
+}
+
+static void *vl_api_af_packet_create_t_print
+ (vl_api_af_packet_create_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: af_packet_create ");
+ s = format (s, "host_if_name %s ", mp->host_if_name);
+ if (mp->use_random_hw_addr)
+ s = format (s, "hw_addr random ");
+ else
+ s = format (s, "hw_addr %U ", format_ethernet_address, mp->hw_addr);
+
+ FINISH;
+}
+
+static void *vl_api_af_packet_delete_t_print
+ (vl_api_af_packet_delete_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: af_packet_delete ");
+ s = format (s, "host_if_name %s ", mp->host_if_name);
+
+ FINISH;
+}
+
+static u8 *
+format_policer_action (u8 * s, va_list * va)
+{
+ u32 action = va_arg (*va, u32);
+ u32 dscp = va_arg (*va, u32);
+ char *t = 0;
+
+ if (action == SSE2_QOS_ACTION_DROP)
+ s = format (s, "drop");
+ else if (action == SSE2_QOS_ACTION_TRANSMIT)
+ s = format (s, "transmit");
+ else if (action == SSE2_QOS_ACTION_MARK_AND_TRANSMIT)
+ {
+ s = format (s, "mark-and-transmit ");
+ switch (dscp)
+ {
+#define _(v,f,str) case VNET_DSCP_##f: t = str; break;
+ foreach_vnet_dscp
+#undef _
+ default:
+ break;
+ }
+ s = format (s, "%s", t);
+ }
+
+ return s;
+}
+
+static void *vl_api_policer_add_del_t_print
+ (vl_api_policer_add_del_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: policer_add_del ");
+ s = format (s, "name %s ", mp->name);
+ s = format (s, "cir %d ", mp->cir);
+ s = format (s, "eir %d ", mp->eir);
+ s = format (s, "cb %d ", mp->cb);
+ s = format (s, "eb %d ", mp->eb);
+
+ switch (mp->rate_type)
+ {
+ case SSE2_QOS_RATE_KBPS:
+ s = format (s, "rate_type kbps ");
+ break;
+ case SSE2_QOS_RATE_PPS:
+ s = format (s, "rate_type pps ");
+ break;
+ default:
+ break;
+ }
+
+ switch (mp->round_type)
+ {
+ case SSE2_QOS_ROUND_TO_CLOSEST:
+ s = format (s, "round_type closest ");
+ break;
+ case SSE2_QOS_ROUND_TO_UP:
+ s = format (s, "round_type up ");
+ break;
+ case SSE2_QOS_ROUND_TO_DOWN:
+ s = format (s, "round_type down ");
+ break;
+ default:
+ break;
+ }
+
+ switch (mp->type)
+ {
+ case SSE2_QOS_POLICER_TYPE_1R2C:
+ s = format (s, "type 1r2c ");
+ break;
+ case SSE2_QOS_POLICER_TYPE_1R3C_RFC_2697:
+ s = format (s, "type 1r3c ");
+ break;
+ case SSE2_QOS_POLICER_TYPE_2R3C_RFC_2698:
+ s = format (s, "type 2r3c-2698 ");
+ break;
+ case SSE2_QOS_POLICER_TYPE_2R3C_RFC_4115:
+ s = format (s, "type 2r3c-4115 ");
+ break;
+ case SSE2_QOS_POLICER_TYPE_2R3C_RFC_MEF5CF1:
+ s = format (s, "type 2r3c-mef5cf1 ");
+ break;
+ default:
+ break;
+ }
+
+ s = format (s, "conform_action %U ", format_policer_action,
+ mp->conform_action_type, mp->conform_dscp);
+ s = format (s, "exceed_action %U ", format_policer_action,
+ mp->exceed_action_type, mp->exceed_dscp);
+ s = format (s, "violate_action %U ", format_policer_action,
+ mp->violate_action_type, mp->violate_dscp);
+
+ if (mp->color_aware)
+ s = format (s, "color-aware ");
+ if (mp->is_add == 0)
+ s = format (s, "del ");
+
+ FINISH;
+}
+
+static void *vl_api_policer_dump_t_print
+ (vl_api_policer_dump_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: policer_dump ");
+ if (mp->match_name_valid)
+ s = format (s, "name %s ", mp->match_name);
+
+ FINISH;
+}
+
+static void *vl_api_policer_classify_set_interface_t_print
+ (vl_api_policer_classify_set_interface_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: policer_classify_set_interface ");
+ s = format (s, "sw_if_index %d ", ntohl (mp->sw_if_index));
+ if (mp->ip4_table_index != ~0)
+ s = format (s, "ip4-table %d ", ntohl (mp->ip4_table_index));
+ if (mp->ip6_table_index != ~0)
+ s = format (s, "ip6-table %d ", ntohl (mp->ip6_table_index));
+ if (mp->l2_table_index != ~0)
+ s = format (s, "l2-table %d ", ntohl (mp->l2_table_index));
+ if (mp->is_add == 0)
+ s = format (s, "del ");
+
+ FINISH;
+}
+
+static void *vl_api_policer_classify_dump_t_print
+ (vl_api_policer_classify_dump_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: policer_classify_dump ");
+ switch (mp->type)
+ {
+ case POLICER_CLASSIFY_TABLE_IP4:
+ s = format (s, "type ip4 ");
+ break;
+ case POLICER_CLASSIFY_TABLE_IP6:
+ s = format (s, "type ip6 ");
+ break;
+ case POLICER_CLASSIFY_TABLE_L2:
+ s = format (s, "type l2 ");
+ break;
+ default:
+ break;
+ }
+
+ FINISH;
+}
+
+static void *vl_api_sw_interface_clear_stats_t_print
+ (vl_api_sw_interface_clear_stats_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: sw_interface_clear_stats ");
+ if (mp->sw_if_index != ~0)
+ s = format (s, "sw_if_index %d ", ntohl (mp->sw_if_index));
+
+ FINISH;
+}
+
+static void *vl_api_mpls_tunnel_dump_t_print
+ (vl_api_mpls_tunnel_dump_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: mpls_tunnel_dump ");
+
+ s = format (s, "tunnel_index %d ", ntohl (mp->tunnel_index));
+
+ FINISH;
+}
+
+static void *vl_api_mpls_fib_dump_t_print
+ (vl_api_mpls_fib_dump_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: mpls_fib_decap_dump ");
+
+ FINISH;
+}
+
+static void *vl_api_ip_fib_dump_t_print
+ (vl_api_ip_fib_dump_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: ip_fib_dump ");
+
+ FINISH;
+}
+
+static void *vl_api_ip6_fib_dump_t_print
+ (vl_api_ip6_fib_dump_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: ip6_fib_dump ");
+
+ FINISH;
+}
+
+static void *vl_api_classify_table_ids_t_print
+ (vl_api_classify_table_ids_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: classify_table_ids ");
+
+ FINISH;
+}
+
+static void *vl_api_classify_table_by_interface_t_print
+ (vl_api_classify_table_by_interface_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: classify_table_by_interface ");
+ if (mp->sw_if_index != ~0)
+ s = format (s, "sw_if_index %d ", ntohl (mp->sw_if_index));
+
+ FINISH;
+}
+
+static void *vl_api_classify_table_info_t_print
+ (vl_api_classify_table_info_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: classify_table_info ");
+ if (mp->table_id != ~0)
+ s = format (s, "table_id %d ", ntohl (mp->table_id));
+
+ FINISH;
+}
+
+static void *vl_api_classify_session_dump_t_print
+ (vl_api_classify_session_dump_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: classify_session_dump ");
+ if (mp->table_id != ~0)
+ s = format (s, "table_id %d ", ntohl (mp->table_id));
+
+ FINISH;
+}
+
+static void *vl_api_set_ipfix_exporter_t_print
+ (vl_api_set_ipfix_exporter_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: set_ipfix_exporter ");
+
+ s = format (s, "collector-address %U ", format_ip4_address,
+ (ip4_address_t *) mp->collector_address);
+ s = format (s, "collector-port %d ", ntohs (mp->collector_port));
+ s = format (s, "src-address %U ", format_ip4_address,
+ (ip4_address_t *) mp->src_address);
+ s = format (s, "vrf-id %d ", ntohl (mp->vrf_id));
+ s = format (s, "path-mtu %d ", ntohl (mp->path_mtu));
+ s = format (s, "template-interval %d ", ntohl (mp->template_interval));
+ s = format (s, "udp-checksum %d ", mp->udp_checksum);
+
+ FINISH;
+}
+
+static void *vl_api_ipfix_exporter_dump_t_print
+ (vl_api_ipfix_exporter_dump_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: ipfix_exporter_dump ");
+
+ FINISH;
+}
+
+static void *vl_api_set_ipfix_classify_stream_t_print
+ (vl_api_set_ipfix_classify_stream_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: set_ipfix_classify_stream ");
+
+ s = format (s, "domain-id %d ", ntohl (mp->domain_id));
+ s = format (s, "src-port %d ", ntohs (mp->src_port));
+
+ FINISH;
+}
+
+static void *vl_api_ipfix_classify_stream_dump_t_print
+ (vl_api_ipfix_classify_stream_dump_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: ipfix_classify_stream_dump ");
+
+ FINISH;
+}
+
+static void *vl_api_ipfix_classify_table_add_del_t_print
+ (vl_api_ipfix_classify_table_add_del_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: ipfix_classify_table_add_del ");
+
+ s = format (s, "table-id %d ", ntohl (mp->table_id));
+ s = format (s, "ip-version %d ", mp->ip_version);
+ s = format (s, "transport-protocol %d ", mp->transport_protocol);
+
+ FINISH;
+}
+
+static void *vl_api_ipfix_classify_table_dump_t_print
+ (vl_api_ipfix_classify_table_dump_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: ipfix_classify_table_dump ");
+
+ FINISH;
+}
+
+static void *vl_api_sw_interface_span_enable_disable_t_print
+ (vl_api_sw_interface_span_enable_disable_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: sw_interface_span_enable_disable ");
+ s = format (s, "src_sw_if_index %u ", ntohl (mp->sw_if_index_from));
+ s = format (s, "dst_sw_if_index %u ", ntohl (mp->sw_if_index_to));
+
+ if (mp->is_l2)
+ s = format (s, "l2 ");
+
+ switch (mp->state)
+ {
+ case 0:
+ s = format (s, "disable ");
+ break;
+ case 1:
+ s = format (s, "rx ");
+ break;
+ case 2:
+ s = format (s, "tx ");
+ break;
+ case 3:
+ default:
+ s = format (s, "both ");
+ break;
+ }
+
+ FINISH;
+}
+
+static void *
+vl_api_sw_interface_span_dump_t_print (vl_api_sw_interface_span_dump_t * mp,
+ void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: sw_interface_span_dump ");
+
+ if (mp->is_l2)
+ s = format (s, "l2 ");
+
+ FINISH;
+}
+
+static void *vl_api_get_next_index_t_print
+ (vl_api_get_next_index_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: get_next_index ");
+ s = format (s, "node-name %s ", mp->node_name);
+ s = format (s, "next-node-name %s ", mp->next_name);
+
+ FINISH;
+}
+
+static void *vl_api_pg_create_interface_t_print
+ (vl_api_pg_create_interface_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: pg_create_interface ");
+ s = format (0, "if_id %d", ntohl (mp->interface_id));
+
+ FINISH;
+}
+
+static void *vl_api_pg_capture_t_print
+ (vl_api_pg_capture_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: pg_capture ");
+ s = format (0, "if_id %d ", ntohl (mp->interface_id));
+ s = format (0, "pcap %s", mp->pcap_file_name);
+ if (mp->count != ~0)
+ s = format (s, "count %d ", ntohl (mp->count));
+ if (!mp->is_enabled)
+ s = format (s, "disable");
+
+ FINISH;
+}
+
+static void *vl_api_pg_enable_disable_t_print
+ (vl_api_pg_enable_disable_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: pg_enable_disable ");
+ if (ntohl (mp->stream_name_length) > 0)
+ s = format (s, "stream %s", mp->stream_name);
+ if (!mp->is_enabled)
+ s = format (s, "disable");
+
+ FINISH;
+}
+
+static void *vl_api_ip_source_and_port_range_check_add_del_t_print
+ (vl_api_ip_source_and_port_range_check_add_del_t * mp, void *handle)
+{
+ u8 *s;
+ int i;
+
+ s = format (0, "SCRIPT: ip_source_and_port_range_check_add_del ");
+ if (mp->is_ipv6)
+ s = format (s, "%U/%d ", format_ip6_address, mp->address,
+ mp->mask_length);
+ else
+ s = format (s, "%U/%d ", format_ip4_address, mp->address,
+ mp->mask_length);
+
+ for (i = 0; i < mp->number_of_ranges; i++)
+ {
+ s = format (s, "range %d - %d ", mp->low_ports[i], mp->high_ports[i]);
+ }
+
+ s = format (s, "vrf %d ", ntohl (mp->vrf_id));
+
+ if (mp->is_add == 0)
+ s = format (s, "del ");
+
+ FINISH;
+}
+
+static void *vl_api_ip_source_and_port_range_check_interface_add_del_t_print
+ (vl_api_ip_source_and_port_range_check_interface_add_del_t * mp,
+ void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: ip_source_and_port_range_check_interface_add_del ");
+
+ s = format (s, "sw_if_index %d ", ntohl (mp->sw_if_index));
+
+ if (mp->tcp_out_vrf_id != ~0)
+ s = format (s, "tcp-out-vrf %d ", ntohl (mp->tcp_out_vrf_id));
+
+ if (mp->udp_out_vrf_id != ~0)
+ s = format (s, "udp-out-vrf %d ", ntohl (mp->udp_out_vrf_id));
+
+ if (mp->tcp_in_vrf_id != ~0)
+ s = format (s, "tcp-in-vrf %d ", ntohl (mp->tcp_in_vrf_id));
+
+ if (mp->udp_in_vrf_id != ~0)
+ s = format (s, "udp-in-vrf %d ", ntohl (mp->udp_in_vrf_id));
+
+ if (mp->is_add == 0)
+ s = format (s, "del ");
+
+ FINISH;
+}
+
+static void *vl_api_lisp_enable_disable_t_print
+ (vl_api_lisp_enable_disable_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: lisp_enable_disable %s",
+ mp->is_en ? "enable" : "disable");
+
+ FINISH;
+}
+
+static void *vl_api_gpe_add_del_iface_t_print
+ (vl_api_gpe_add_del_iface_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: gpe_add_del_iface ");
+
+ s = format (s, "%s ", mp->is_add ? "up" : "down");
+ s = format (s, "vni %d ", mp->vni);
+ s = format (s, "%s %d ", mp->is_l2 ? "bd_id" : "table_id", mp->dp_table);
+
+ FINISH;
+}
+
+static void *vl_api_lisp_pitr_set_locator_set_t_print
+ (vl_api_lisp_pitr_set_locator_set_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: lisp_pitr_set_locator_set ");
+
+ if (mp->is_add)
+ s = format (s, "locator-set %s ", mp->ls_name);
+ else
+ s = format (s, "del");
+
+ FINISH;
+}
+
+static u8 *
+format_lisp_flat_eid (u8 * s, va_list * args)
+{
+ u32 type = va_arg (*args, u32);
+ u8 *eid = va_arg (*args, u8 *);
+ u32 eid_len = va_arg (*args, u32);
+
+ switch (type)
+ {
+ case 0:
+ return format (s, "%U/%d", format_ip4_address, eid, eid_len);
+ case 1:
+ return format (s, "%U/%d", format_ip6_address, eid, eid_len);
+ case 3:
+ return format (s, "%U", format_ethernet_address, eid);
+ }
+ return 0;
+}
+
+static void *vl_api_lisp_add_del_remote_mapping_t_print
+ (vl_api_lisp_add_del_remote_mapping_t * mp, void *handle)
+{
+ u8 *s;
+ u32 rloc_num = 0;
+
+ s = format (0, "SCRIPT: lisp_add_del_remote_mapping ");
+
+ if (mp->del_all)
+ s = format (s, "del-all ");
+
+ s = format (s, "%s ", mp->is_add ? "add" : "del");
+ s = format (s, "vni %d ", clib_net_to_host_u32 (mp->vni));
+
+ s = format (s, "eid %U ", format_lisp_flat_eid,
+ mp->eid_type, mp->eid, mp->eid_len);
+
+ if (mp->is_src_dst)
+ {
+ s = format (s, "seid %U ", format_lisp_flat_eid,
+ mp->eid_type, mp->seid, mp->seid_len);
+ }
+
+ rloc_num = clib_net_to_host_u32 (mp->rloc_num);
+
+ if (0 == rloc_num)
+ s = format (s, "action %d", mp->action);
+
+ FINISH;
+}
+
+static void *vl_api_lisp_add_del_adjacency_t_print
+ (vl_api_lisp_add_del_adjacency_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: lisp_add_del_adjacency ");
+
+ s = format (s, "%s ", mp->is_add ? "add" : "del");
+ s = format (s, "vni %d ", clib_net_to_host_u32 (mp->vni));
+ s = format (s, "reid %U leid %U ",
+ format_lisp_flat_eid, mp->eid_type, mp->reid, mp->reid_len,
+ format_lisp_flat_eid, mp->eid_type, mp->leid, mp->leid_len);
+
+ FINISH;
+}
+
+static void *vl_api_lisp_add_del_map_request_itr_rlocs_t_print
+ (vl_api_lisp_add_del_map_request_itr_rlocs_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: lisp_add_del_map_request_itr_rlocs ");
+
+ if (mp->is_add)
+ s = format (s, "%s", mp->locator_set_name);
+ else
+ s = format (s, "del");
+
+ FINISH;
+}
+
+static void *vl_api_lisp_eid_table_add_del_map_t_print
+ (vl_api_lisp_eid_table_add_del_map_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: lisp_eid_table_add_del_map ");
+
+ if (!mp->is_add)
+ s = format (s, "del ");
+
+ s = format (s, "vni %d ", clib_net_to_host_u32 (mp->vni));
+ s = format (s, "%s %d ",
+ mp->is_l2 ? "bd_index" : "vrf",
+ clib_net_to_host_u32 (mp->dp_table));
+ FINISH;
+}
+
+static void *vl_api_lisp_add_del_local_eid_t_print
+ (vl_api_lisp_add_del_local_eid_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: lisp_add_del_local_eid ");
+
+ if (!mp->is_add)
+ s = format (s, "del ");
+
+ s = format (s, "vni %d ", clib_net_to_host_u32 (mp->vni));
+ s = format (s, "eid %U ", format_lisp_flat_eid, mp->eid_type, mp->eid,
+ mp->prefix_len);
+ s = format (s, "locator-set %s ", mp->locator_set_name);
+ if (*mp->key)
+ {
+ u32 key_id = mp->key_id;
+ s = format (s, "key-id %U", format_hmac_key_id, key_id);
+ s = format (s, "secret-key %s", mp->key);
+ }
+ FINISH;
+}
+
+static void *vl_api_gpe_add_del_fwd_entry_t_print
+ (vl_api_gpe_add_del_fwd_entry_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: gpe_add_del_fwd_entry TODO");
+
+ FINISH;
+}
+
+static void *vl_api_lisp_add_del_map_resolver_t_print
+ (vl_api_lisp_add_del_map_resolver_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: lisp_add_del_map_resolver ");
+
+ if (!mp->is_add)
+ s = format (s, "del ");
+
+ if (mp->is_ipv6)
+ s = format (s, "%U ", format_ip6_address, mp->ip_address);
+ else
+ s = format (s, "%U ", format_ip4_address, mp->ip_address);
+
+ FINISH;
+}
+
+static void *vl_api_gpe_enable_disable_t_print
+ (vl_api_gpe_enable_disable_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: gpe_enable_disable ");
+
+ s = format (s, "%s ", mp->is_en ? "enable" : "disable");
+
+ FINISH;
+}
+
+static void *vl_api_lisp_add_del_locator_set_t_print
+ (vl_api_lisp_add_del_locator_set_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: lisp_add_del_locator_set ");
+
+ if (!mp->is_add)
+ s = format (s, "del ");
+
+ s = format (s, "locator-set %s ", mp->locator_set_name);
+
+ FINISH;
+}
+
+static void *vl_api_lisp_add_del_locator_t_print
+ (vl_api_lisp_add_del_locator_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: lisp_add_del_locator ");
+
+ if (!mp->is_add)
+ s = format (s, "del ");
+
+ s = format (s, "locator-set %s ", mp->locator_set_name);
+ s = format (s, "sw_if_index %d ", mp->sw_if_index);
+ s = format (s, "p %d w %d ", mp->priority, mp->weight);
+
+ FINISH;
+}
+
+static void *vl_api_lisp_locator_set_dump_t_print
+ (vl_api_lisp_locator_set_dump_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: lisp_locator_set_dump ");
+ if (mp->filter == 1)
+ s = format (s, "local");
+ else if (mp->filter == 2)
+ s = format (s, "remote");
+
+ FINISH;
+}
+
+static void *vl_api_lisp_locator_dump_t_print
+ (vl_api_lisp_locator_dump_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: lisp_locator_dump ");
+ if (mp->is_index_set)
+ s = format (s, "ls_index %d", clib_net_to_host_u32 (mp->ls_index));
+ else
+ s = format (s, "ls_name %s", mp->ls_name);
+
+ FINISH;
+}
+
+static void *vl_api_lisp_map_request_mode_t_print
+ (vl_api_lisp_map_request_mode_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: lisp_map_request_mode ");
+
+ switch (mp->mode)
+ {
+ case 0:
+ s = format (s, "dst-only");
+ break;
+ case 1:
+ s = format (s, "src-dst");
+ default:
+ break;
+ }
+
+ FINISH;
+}
+
+static void *vl_api_lisp_eid_table_dump_t_print
+ (vl_api_lisp_eid_table_dump_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: lisp_eid_table_dump ");
+
+ if (mp->eid_set)
+ {
+ s = format (s, "vni %d ", clib_net_to_host_u32 (mp->vni));
+ s = format (s, "eid %U ", format_lisp_flat_eid, mp->eid_type,
+ mp->eid, mp->prefix_length);
+ switch (mp->filter)
+ {
+ case 1:
+ s = format (s, "local ");
+ break;
+ case 2:
+ s = format (s, "remote ");
+ break;
+ }
+ }
+
+ FINISH;
+}
+
+static void *vl_api_lisp_rloc_probe_enable_disable_t_print
+ (vl_api_lisp_rloc_probe_enable_disable_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: lisp_rloc_probe_enable_disable ");
+ if (mp->is_enabled)
+ s = format (s, "enable");
+ else
+ s = format (s, "disable");
+
+ FINISH;
+}
+
+static void *vl_api_lisp_map_register_enable_disable_t_print
+ (vl_api_lisp_map_register_enable_disable_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: lisp_map_register_enable_disable ");
+ if (mp->is_enabled)
+ s = format (s, "enable");
+ else
+ s = format (s, "disable");
+
+ FINISH;
+}
+
+static void *vl_api_lisp_adjacencies_get_t_print
+ (vl_api_lisp_adjacencies_get_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: lisp_adjacencies_get ");
+ s = format (s, "vni %d", clib_net_to_host_u32 (mp->vni));
+
+ FINISH;
+}
+
+static void *vl_api_lisp_eid_table_map_dump_t_print
+ (vl_api_lisp_eid_table_map_dump_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: lisp_eid_table_map_dump ");
+
+ if (mp->is_l2)
+ s = format (s, "l2");
+ else
+ s = format (s, "l3");
+
+ FINISH;
+}
+
+static void *vl_api_ipsec_gre_add_del_tunnel_t_print
+ (vl_api_ipsec_gre_add_del_tunnel_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: ipsec_gre_add_del_tunnel ");
+
+ s = format (s, "dst %U ", format_ip4_address,
+ (ip4_address_t *) & (mp->dst_address));
+
+ s = format (s, "src %U ", format_ip4_address,
+ (ip4_address_t *) & (mp->src_address));
+
+ s = format (s, "local_sa %d ", ntohl (mp->local_sa_id));
+
+ s = format (s, "remote_sa %d ", ntohl (mp->remote_sa_id));
+
+ if (mp->is_add == 0)
+ s = format (s, "del ");
+
+ FINISH;
+}
+
+static void *vl_api_ipsec_gre_tunnel_dump_t_print
+ (vl_api_ipsec_gre_tunnel_dump_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: ipsec_gre_tunnel_dump ");
+
+ if (mp->sw_if_index != ~0)
+ s = format (s, "sw_if_index %d ", ntohl (mp->sw_if_index));
+
+ FINISH;
+}
+
+static void *vl_api_l2_interface_pbb_tag_rewrite_t_print
+ (vl_api_l2_interface_pbb_tag_rewrite_t * mp, void *handle)
+{
+ u8 *s;
+ u32 vtr_op = ntohl (mp->vtr_op);
+
+ s = format (0, "SCRIPT: l2_interface_pbb_tag_rewrite ");
+
+ s = format (s, "sw_if_index %d ", ntohl (mp->sw_if_index));
+ s = format (s, "vtr_op %d ", vtr_op);
+ if (vtr_op != L2_VTR_DISABLED && vtr_op != L2_VTR_POP_2)
+ {
+ if (vtr_op == L2_VTR_TRANSLATE_2_2)
+ s = format (s, "%d ", ntohs (mp->outer_tag));
+ s = format (s, "dmac %U ", format_ethernet_address, &mp->b_dmac);
+ s = format (s, "smac %U ", format_ethernet_address, &mp->b_smac);
+ s = format (s, "sid %d ", ntohl (mp->i_sid));
+ s = format (s, "vlanid %d ", ntohs (mp->b_vlanid));
+ }
+
+ FINISH;
+}
+
+static void *vl_api_flow_classify_set_interface_t_print
+ (vl_api_flow_classify_set_interface_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: flow_classify_set_interface ");
+ s = format (s, "sw_if_index %d ", ntohl (mp->sw_if_index));
+ if (mp->ip4_table_index != ~0)
+ s = format (s, "ip4-table %d ", ntohl (mp->ip4_table_index));
+ if (mp->ip6_table_index != ~0)
+ s = format (s, "ip6-table %d ", ntohl (mp->ip6_table_index));
+ if (mp->is_add == 0)
+ s = format (s, "del ");
+
+ FINISH;
+}
+
+static void *
+vl_api_punt_t_print (vl_api_punt_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: punt ");
+
+ if (mp->ipv != (u8) ~ 0)
+ s = format (s, "ip %d ", mp->ipv);
+
+ s = format (s, "protocol %d ", mp->l4_protocol);
+
+ if (mp->l4_port != (u16) ~ 0)
+ s = format (s, "port %d ", ntohs (mp->l4_port));
+
+ if (!mp->is_add)
+ s = format (s, "del ");
+
+ FINISH;
+}
+
+static void *vl_api_flow_classify_dump_t_print
+ (vl_api_flow_classify_dump_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: flow_classify_dump ");
+ switch (mp->type)
+ {
+ case FLOW_CLASSIFY_TABLE_IP4:
+ s = format (s, "type ip4 ");
+ break;
+ case FLOW_CLASSIFY_TABLE_IP6:
+ s = format (s, "type ip6 ");
+ break;
+ default:
+ break;
+ }
+
+ FINISH;
+}
+
+static void *vl_api_get_first_msg_id_t_print
+ (vl_api_get_first_msg_id_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: get_first_msg_id %s ", mp->name);
+
+ FINISH;
+}
+
+static void *vl_api_ioam_enable_t_print
+ (vl_api_ioam_enable_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: ioam_enable ");
+
+ if (mp->trace_enable)
+ s = format (s, "trace enabled");
+
+ if (mp->pot_enable)
+ s = format (s, "POT enabled");
+
+ if (mp->seqno)
+ s = format (s, "Seqno enabled");
+
+ if (mp->analyse)
+ s = format (s, "Analyse enabled");
+
+ FINISH;
+}
+
+static void *vl_api_ioam_disable_t_print
+ (vl_api_ioam_disable_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: ioam_disable ");
+ s = format (s, "trace disabled");
+ s = format (s, "POT disabled");
+ s = format (s, "Seqno disabled");
+ s = format (s, "Analyse disabled");
+
+ FINISH;
+}
+
+static void *vl_api_feature_enable_disable_t_print
+ (vl_api_feature_enable_disable_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: feature_enable_disable ");
+ s = format (s, "arc_name %s ", mp->arc_name);
+ s = format (s, "feature_name %s ", mp->feature_name);
+ s = format (s, "sw_if_index %d ", ntohl (mp->sw_if_index));
+ if (!mp->enable)
+ s = format (s, "disable");
+
+ FINISH;
+}
+
+static void *vl_api_sw_interface_tag_add_del_t_print
+ (vl_api_sw_interface_tag_add_del_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: sw_interface_tag_add_del ");
+ s = format (s, "sw_if_index %d ", ntohl (mp->sw_if_index));
+ if (mp->is_add)
+ s = format (s, "tag %s ", mp->tag);
+ else
+ s = format (s, "del ");
+
+ FINISH;
+}
+
+static void *vl_api_sw_interface_set_mtu_t_print
+ (vl_api_sw_interface_set_mtu_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: sw_interface_set_mtu ");
+ s = format (s, "sw_if_index %d ", ntohl (mp->sw_if_index));
+ s = format (s, "tag %d ", ntohs (mp->mtu));
+
+ FINISH;
+}
+
+static void *vl_api_p2p_ethernet_add_t_print
+ (vl_api_p2p_ethernet_add_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: p2p_ethernet_add ");
+ s = format (s, "sw_if_index %d ", ntohl (mp->parent_if_index));
+ s = format (s, "remote_mac %U ", format_ethernet_address, mp->remote_mac);
+
+ FINISH;
+}
+
+static void *vl_api_p2p_ethernet_del_t_print
+ (vl_api_p2p_ethernet_del_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: p2p_ethernet_del ");
+ s = format (s, "sw_if_index %d ", ntohl (mp->parent_if_index));
+ s = format (s, "remote_mac %U ", format_ethernet_address, mp->remote_mac);
+
+ FINISH;
+}
+
+static void *vl_api_tcp_configure_src_addresses_t_print
+ (vl_api_tcp_configure_src_addresses_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: tcp_configure_src_addresses ");
+ if (mp->is_ipv6)
+ s = format (s, "%U - %U ",
+ format_ip6_address, (ip6_address_t *) mp->first_address,
+ format_ip6_address, (ip6_address_t *) mp->last_address);
+ else
+ s = format (s, "%U - %U ",
+ format_ip4_address, (ip4_address_t *) mp->first_address,
+ format_ip4_address, (ip4_address_t *) mp->last_address);
+
+ if (mp->vrf_id)
+ s = format (s, "vrf %d ", ntohl (mp->vrf_id));
+
+ FINISH;
+}
+
+#define foreach_custom_print_no_arg_function \
+_(lisp_eid_table_vni_dump) \
+_(lisp_map_resolver_dump) \
+_(lisp_map_server_dump) \
+_(show_lisp_rloc_probe_state) \
+_(show_lisp_map_register_state) \
+_(show_lisp_map_request_mode)
+
+#define _(f) \
+static void * vl_api_ ## f ## _t_print \
+ (vl_api_ ## f ## _t * mp, void * handle) \
+{ \
+ u8 * s; \
+ s = format (0, "SCRIPT: " #f ); \
+ FINISH; \
+}
+foreach_custom_print_no_arg_function
+#undef _
+#define foreach_custom_print_function \
+_(CREATE_LOOPBACK, create_loopback) \
+_(CREATE_LOOPBACK_INSTANCE, create_loopback_instance) \
+_(SW_INTERFACE_SET_FLAGS, sw_interface_set_flags) \
+_(SW_INTERFACE_EVENT, sw_interface_event) \
+_(SW_INTERFACE_ADD_DEL_ADDRESS, sw_interface_add_del_address) \
+_(SW_INTERFACE_SET_TABLE, sw_interface_set_table) \
+_(SW_INTERFACE_SET_MPLS_ENABLE, sw_interface_set_mpls_enable) \
+_(SW_INTERFACE_SET_VPATH, sw_interface_set_vpath) \
+_(SW_INTERFACE_SET_VXLAN_BYPASS, sw_interface_set_vxlan_bypass) \
+_(TAP_CONNECT, tap_connect) \
+_(TAP_MODIFY, tap_modify) \
+_(TAP_DELETE, tap_delete) \
+_(SW_INTERFACE_TAP_DUMP, sw_interface_tap_dump) \
+_(IP_ADD_DEL_ROUTE, ip_add_del_route) \
+_(PROXY_ARP_ADD_DEL, proxy_arp_add_del) \
+_(PROXY_ARP_INTFC_ENABLE_DISABLE, proxy_arp_intfc_enable_disable) \
+_(MPLS_TUNNEL_ADD_DEL, mpls_tunnel_add_del) \
+_(SW_INTERFACE_SET_UNNUMBERED, sw_interface_set_unnumbered) \
+_(IP_NEIGHBOR_ADD_DEL, ip_neighbor_add_del) \
+_(RESET_VRF, reset_vrf) \
+_(CREATE_VLAN_SUBIF, create_vlan_subif) \
+_(CREATE_SUBIF, create_subif) \
+_(OAM_ADD_DEL, oam_add_del) \
+_(RESET_FIB, reset_fib) \
+_(DHCP_PROXY_CONFIG, dhcp_proxy_config) \
+_(DHCP_PROXY_SET_VSS, dhcp_proxy_set_vss) \
+_(SET_IP_FLOW_HASH, set_ip_flow_hash) \
+_(SW_INTERFACE_IP6_SET_LINK_LOCAL_ADDRESS, \
+ sw_interface_ip6_set_link_local_address) \
+_(SW_INTERFACE_IP6ND_RA_PREFIX, sw_interface_ip6nd_ra_prefix) \
+_(SW_INTERFACE_IP6ND_RA_CONFIG, sw_interface_ip6nd_ra_config) \
+_(SET_ARP_NEIGHBOR_LIMIT, set_arp_neighbor_limit) \
+_(L2_PATCH_ADD_DEL, l2_patch_add_del) \
+_(SR_LOCALSID_ADD_DEL, sr_localsid_add_del) \
+_(SR_STEERING_ADD_DEL, sr_steering_add_del) \
+_(SR_POLICY_ADD, sr_policy_add) \
+_(SR_POLICY_MOD, sr_policy_mod) \
+_(SR_POLICY_DEL, sr_policy_del) \
+_(SW_INTERFACE_SET_L2_XCONNECT, sw_interface_set_l2_xconnect) \
+_(L2FIB_ADD_DEL, l2fib_add_del) \
+_(L2FIB_FLUSH_ALL, l2fib_flush_all) \
+_(L2FIB_FLUSH_BD, l2fib_flush_bd) \
+_(L2FIB_FLUSH_INT, l2fib_flush_int) \
+_(L2_FLAGS, l2_flags) \
+_(BRIDGE_FLAGS, bridge_flags) \
+_(CLASSIFY_ADD_DEL_TABLE, classify_add_del_table) \
+_(CLASSIFY_ADD_DEL_SESSION, classify_add_del_session) \
+_(SW_INTERFACE_SET_L2_BRIDGE, sw_interface_set_l2_bridge) \
+_(BRIDGE_DOMAIN_ADD_DEL, bridge_domain_add_del) \
+_(BRIDGE_DOMAIN_DUMP, bridge_domain_dump) \
+_(BRIDGE_DOMAIN_SET_MAC_AGE, bridge_domain_set_mac_age) \
+_(CLASSIFY_SET_INTERFACE_IP_TABLE, classify_set_interface_ip_table) \
+_(CLASSIFY_SET_INTERFACE_L2_TABLES, classify_set_interface_l2_tables) \
+_(ADD_NODE_NEXT, add_node_next) \
+_(DHCP_CLIENT_CONFIG, dhcp_client_config) \
+_(L2TPV3_CREATE_TUNNEL, l2tpv3_create_tunnel) \
+_(L2TPV3_SET_TUNNEL_COOKIES, l2tpv3_set_tunnel_cookies) \
+_(L2TPV3_INTERFACE_ENABLE_DISABLE, l2tpv3_interface_enable_disable) \
+_(L2TPV3_SET_LOOKUP_KEY, l2tpv3_set_lookup_key) \
+_(SW_IF_L2TPV3_TUNNEL_DUMP, sw_if_l2tpv3_tunnel_dump) \
+_(VXLAN_ADD_DEL_TUNNEL, vxlan_add_del_tunnel) \
+_(VXLAN_TUNNEL_DUMP, vxlan_tunnel_dump) \
+_(GRE_ADD_DEL_TUNNEL, gre_add_del_tunnel) \
+_(GRE_TUNNEL_DUMP, gre_tunnel_dump) \
+_(L2_FIB_CLEAR_TABLE, l2_fib_clear_table) \
+_(L2_INTERFACE_EFP_FILTER, l2_interface_efp_filter) \
+_(L2_INTERFACE_VLAN_TAG_REWRITE, l2_interface_vlan_tag_rewrite) \
+_(CREATE_VHOST_USER_IF, create_vhost_user_if) \
+_(MODIFY_VHOST_USER_IF, modify_vhost_user_if) \
+_(DELETE_VHOST_USER_IF, delete_vhost_user_if) \
+_(SW_INTERFACE_DUMP, sw_interface_dump) \
+_(CONTROL_PING, control_ping) \
+_(WANT_INTERFACE_EVENTS, want_interface_events) \
+_(CLI, cli) \
+_(CLI_INBAND, cli_inband) \
+_(MEMCLNT_CREATE, memclnt_create) \
+_(SW_INTERFACE_VHOST_USER_DUMP, sw_interface_vhost_user_dump) \
+_(SHOW_VERSION, show_version) \
+_(L2_FIB_TABLE_DUMP, l2_fib_table_dump) \
+_(VXLAN_GPE_ADD_DEL_TUNNEL, vxlan_gpe_add_del_tunnel) \
+_(VXLAN_GPE_TUNNEL_DUMP, vxlan_gpe_tunnel_dump) \
+_(INTERFACE_NAME_RENUMBER, interface_name_renumber) \
+_(WANT_IP4_ARP_EVENTS, want_ip4_arp_events) \
+_(WANT_IP6_ND_EVENTS, want_ip6_nd_events) \
+_(WANT_L2_MACS_EVENTS, want_l2_macs_events) \
+_(INPUT_ACL_SET_INTERFACE, input_acl_set_interface) \
+_(IP_ADDRESS_DUMP, ip_address_dump) \
+_(IP_DUMP, ip_dump) \
+_(DELETE_LOOPBACK, delete_loopback) \
+_(BD_IP_MAC_ADD_DEL, bd_ip_mac_add_del) \
+_(COP_INTERFACE_ENABLE_DISABLE, cop_interface_enable_disable) \
+_(COP_WHITELIST_ENABLE_DISABLE, cop_whitelist_enable_disable) \
+_(AF_PACKET_CREATE, af_packet_create) \
+_(AF_PACKET_DELETE, af_packet_delete) \
+_(SW_INTERFACE_CLEAR_STATS, sw_interface_clear_stats) \
+_(MPLS_FIB_DUMP, mpls_fib_dump) \
+_(MPLS_TUNNEL_DUMP, mpls_tunnel_dump) \
+_(CLASSIFY_TABLE_IDS,classify_table_ids) \
+_(CLASSIFY_TABLE_BY_INTERFACE, classify_table_by_interface) \
+_(CLASSIFY_TABLE_INFO,classify_table_info) \
+_(CLASSIFY_SESSION_DUMP,classify_session_dump) \
+_(SET_IPFIX_EXPORTER, set_ipfix_exporter) \
+_(IPFIX_EXPORTER_DUMP, ipfix_exporter_dump) \
+_(SET_IPFIX_CLASSIFY_STREAM, set_ipfix_classify_stream) \
+_(IPFIX_CLASSIFY_STREAM_DUMP, ipfix_classify_stream_dump) \
+_(IPFIX_CLASSIFY_TABLE_ADD_DEL, ipfix_classify_table_add_del) \
+_(IPFIX_CLASSIFY_TABLE_DUMP, ipfix_classify_table_dump) \
+_(SW_INTERFACE_SPAN_ENABLE_DISABLE, sw_interface_span_enable_disable) \
+_(SW_INTERFACE_SPAN_DUMP, sw_interface_span_dump) \
+_(GET_NEXT_INDEX, get_next_index) \
+_(PG_CREATE_INTERFACE,pg_create_interface) \
+_(PG_CAPTURE, pg_capture) \
+_(PG_ENABLE_DISABLE, pg_enable_disable) \
+_(POLICER_ADD_DEL, policer_add_del) \
+_(POLICER_DUMP, policer_dump) \
+_(POLICER_CLASSIFY_SET_INTERFACE, policer_classify_set_interface) \
+_(POLICER_CLASSIFY_DUMP, policer_classify_dump) \
+_(IP_SOURCE_AND_PORT_RANGE_CHECK_ADD_DEL, \
+ ip_source_and_port_range_check_add_del) \
+_(IP_SOURCE_AND_PORT_RANGE_CHECK_INTERFACE_ADD_DEL, \
+ ip_source_and_port_range_check_interface_add_del) \
+_(LISP_ENABLE_DISABLE, lisp_enable_disable) \
+_(GPE_ENABLE_DISABLE, gpe_enable_disable) \
+_(GPE_ADD_DEL_IFACE, gpe_add_del_iface) \
+_(LISP_PITR_SET_LOCATOR_SET, lisp_pitr_set_locator_set) \
+_(LISP_MAP_REQUEST_MODE, lisp_map_request_mode) \
+_(SHOW_LISP_MAP_REQUEST_MODE, show_lisp_map_request_mode) \
+_(LISP_ADD_DEL_REMOTE_MAPPING, lisp_add_del_remote_mapping) \
+_(LISP_ADD_DEL_ADJACENCY, lisp_add_del_adjacency) \
+_(LISP_ADD_DEL_MAP_REQUEST_ITR_RLOCS, \
+ lisp_add_del_map_request_itr_rlocs) \
+_(LISP_EID_TABLE_ADD_DEL_MAP, lisp_eid_table_add_del_map) \
+_(LISP_ADD_DEL_LOCAL_EID, lisp_add_del_local_eid) \
+_(GPE_ADD_DEL_FWD_ENTRY, gpe_add_del_fwd_entry) \
+_(LISP_ADD_DEL_LOCATOR_SET, lisp_add_del_locator_set) \
+_(LISP_ADD_DEL_MAP_RESOLVER, lisp_add_del_map_resolver) \
+_(LISP_ADD_DEL_LOCATOR, lisp_add_del_locator) \
+_(LISP_EID_TABLE_DUMP, lisp_eid_table_dump) \
+_(LISP_EID_TABLE_MAP_DUMP, lisp_eid_table_map_dump) \
+_(LISP_EID_TABLE_VNI_DUMP, lisp_eid_table_vni_dump) \
+_(LISP_MAP_RESOLVER_DUMP, lisp_map_resolver_dump) \
+_(LISP_MAP_SERVER_DUMP, lisp_map_server_dump) \
+_(LISP_LOCATOR_SET_DUMP, lisp_locator_set_dump) \
+_(LISP_LOCATOR_DUMP, lisp_locator_dump) \
+_(LISP_ADJACENCIES_GET, lisp_adjacencies_get) \
+_(SHOW_LISP_RLOC_PROBE_STATE, show_lisp_rloc_probe_state) \
+_(SHOW_LISP_MAP_REGISTER_STATE, show_lisp_map_register_state) \
+_(LISP_RLOC_PROBE_ENABLE_DISABLE, lisp_rloc_probe_enable_disable) \
+_(LISP_MAP_REGISTER_ENABLE_DISABLE, lisp_map_register_enable_disable) \
+_(IPSEC_GRE_ADD_DEL_TUNNEL, ipsec_gre_add_del_tunnel) \
+_(IPSEC_GRE_TUNNEL_DUMP, ipsec_gre_tunnel_dump) \
+_(DELETE_SUBIF, delete_subif) \
+_(L2_INTERFACE_PBB_TAG_REWRITE, l2_interface_pbb_tag_rewrite) \
+_(PUNT, punt) \
+_(FLOW_CLASSIFY_SET_INTERFACE, flow_classify_set_interface) \
+_(FLOW_CLASSIFY_DUMP, flow_classify_dump) \
+_(GET_FIRST_MSG_ID, get_first_msg_id) \
+_(IOAM_ENABLE, ioam_enable) \
+_(IOAM_DISABLE, ioam_disable) \
+_(IP_FIB_DUMP, ip_fib_dump) \
+_(IP6_FIB_DUMP, ip6_fib_dump) \
+_(FEATURE_ENABLE_DISABLE, feature_enable_disable) \
+_(SW_INTERFACE_TAG_ADD_DEL, sw_interface_tag_add_del) \
+_(SW_INTERFACE_SET_MTU, sw_interface_set_mtu) \
+_(P2P_ETHERNET_ADD, p2p_ethernet_add) \
+_(P2P_ETHERNET_DEL, p2p_ethernet_del) \
+_(TCP_CONFIGURE_SRC_ADDRESSES, tcp_configure_src_addresses)
+ void
+vl_msg_api_custom_dump_configure (api_main_t * am)
+{
+#define _(n,f) am->msg_print_handlers[VL_API_##n] \
+ = (void *) vl_api_##f##_t_print;
+ foreach_custom_print_function;
+#undef _
+}
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/src/vpp/api/gmon.c b/src/vpp/api/gmon.c
new file mode 100644
index 00000000..6b333730
--- /dev/null
+++ b/src/vpp/api/gmon.c
@@ -0,0 +1,306 @@
+/*
+ * Copyright (c) 2012 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <signal.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <time.h>
+#include <fcntl.h>
+#include <string.h>
+#include <vppinfra/clib.h>
+#include <vppinfra/vec.h>
+#include <vppinfra/hash.h>
+#include <vppinfra/bitmap.h>
+#include <vppinfra/fifo.h>
+#include <vppinfra/time.h>
+#include <vppinfra/mheap.h>
+#include <vppinfra/heap.h>
+#include <vppinfra/pool.h>
+#include <vppinfra/format.h>
+#include <vlibapi/api.h>
+#include <vlibmemory/api.h>
+
+#include <vlib/vlib.h>
+#include <vlib/unix/unix.h>
+#include <vnet/api_errno.h>
+
+#include <svm/svmdb.h>
+
+typedef struct
+{
+ svmdb_client_t *svmdb_client;
+ f64 *vector_rate_ptr;
+ f64 *input_rate_ptr;
+ f64 *sig_error_rate_ptr;
+ pid_t *vpef_pid_ptr;
+ u64 last_sig_errors;
+ u64 current_sig_errors;
+ uword *sig_error_bitmap;
+ vlib_main_t *vlib_main;
+ vlib_main_t **my_vlib_mains;
+
+} gmon_main_t;
+
+#include <vlib/vlib.h>
+#include <vnet/vnet.h>
+#include <vnet/devices/devices.h>
+
+gmon_main_t gmon_main;
+
+static u64
+get_significant_errors (gmon_main_t * gm)
+{
+ vlib_main_t *this_vlib_main;
+ vlib_error_main_t *em;
+ uword code;
+ int vm_index;
+ u64 significant_errors = 0;
+
+ /* *INDENT-OFF* */
+ clib_bitmap_foreach (code, gm->sig_error_bitmap,
+ ({
+ for (vm_index = 0; vm_index < vec_len (gm->my_vlib_mains); vm_index++)
+ {
+ this_vlib_main = gm->my_vlib_mains[vm_index];
+ em = &this_vlib_main->error_main;
+ significant_errors += em->counters[code] -
+ ((vec_len(em->counters_last_clear) > code) ?
+ em->counters_last_clear[code] : 0);
+ }
+ }));
+ /* *INDENT-ON* */
+
+ return (significant_errors);
+}
+
+static clib_error_t *
+publish_pid (vlib_main_t * vm)
+{
+ gmon_main_t *gm = &gmon_main;
+
+ *gm->vpef_pid_ptr = getpid ();
+
+ return 0;
+}
+
+VLIB_API_INIT_FUNCTION (publish_pid);
+
+
+static uword
+gmon_process (vlib_main_t * vm, vlib_node_runtime_t * rt, vlib_frame_t * f)
+{
+ f64 vector_rate;
+ u64 input_packets, last_input_packets, new_sig_errors;
+ f64 last_runtime, dt, now;
+ gmon_main_t *gm = &gmon_main;
+ int i;
+
+ last_runtime = 0.0;
+ last_input_packets = 0;
+
+ last_runtime = 0.0;
+ last_input_packets = 0;
+
+ /* Initial wait for the world to settle down */
+ vlib_process_suspend (vm, 5.0);
+
+ for (i = 0; i < vec_len (vlib_mains); i++)
+ vec_add1 (gm->my_vlib_mains, vlib_mains[i]);
+
+ while (1)
+ {
+ vlib_process_suspend (vm, 5.0);
+ vector_rate = vlib_last_vector_length_per_node (vm);
+ *gm->vector_rate_ptr = vector_rate;
+ now = vlib_time_now (vm);
+ dt = now - last_runtime;
+ input_packets = vnet_get_aggregate_rx_packets ();
+ *gm->input_rate_ptr = (f64) (input_packets - last_input_packets) / dt;
+ last_runtime = now;
+ last_input_packets = input_packets;
+
+ new_sig_errors = get_significant_errors (gm);
+ *gm->sig_error_rate_ptr =
+ ((f64) (new_sig_errors - gm->last_sig_errors)) / dt;
+ gm->last_sig_errors = new_sig_errors;
+ }
+
+ return 0; /* not so much */
+}
+
+/* *INDENT-OFF* */
+VLIB_REGISTER_NODE (gmon_process_node,static) = {
+ .function = gmon_process,
+ .type = VLIB_NODE_TYPE_PROCESS,
+ .name = "gmon-process",
+};
+/* *INDENT-ON* */
+
+static clib_error_t *
+gmon_init (vlib_main_t * vm)
+{
+ gmon_main_t *gm = &gmon_main;
+ api_main_t *am = &api_main;
+ pid_t *swp = 0;
+ f64 *v = 0;
+ clib_error_t *error;
+ svmdb_map_args_t _ma, *ma = &_ma;
+
+ if ((error = vlib_call_init_function (vm, vpe_api_init)))
+ return (error);
+
+ if ((error = vlib_call_init_function (vm, vlibmemory_init)))
+ return (error);
+
+ gm->vlib_main = vm;
+
+ memset (ma, 0, sizeof (*ma));
+ ma->root_path = am->root_path;
+ ma->uid = am->api_uid;
+ ma->gid = am->api_gid;
+
+ gm->svmdb_client = svmdb_map (ma);
+
+ /* Find or create, set to zero */
+ vec_add1 (v, 0.0);
+ svmdb_local_set_vec_variable (gm->svmdb_client,
+ "vpp_vector_rate", (char *) v, sizeof (*v));
+ vec_free (v);
+ vec_add1 (v, 0.0);
+ svmdb_local_set_vec_variable (gm->svmdb_client,
+ "vpp_input_rate", (char *) v, sizeof (*v));
+ vec_free (v);
+ vec_add1 (v, 0.0);
+ svmdb_local_set_vec_variable (gm->svmdb_client,
+ "vpp_sig_error_rate",
+ (char *) v, sizeof (*v));
+ vec_free (v);
+
+ vec_add1 (swp, 0.0);
+ svmdb_local_set_vec_variable (gm->svmdb_client,
+ "vpp_pid", (char *) swp, sizeof (*swp));
+ vec_free (swp);
+
+ /* the value cells will never move, so acquire references to them */
+ gm->vector_rate_ptr =
+ svmdb_local_get_variable_reference (gm->svmdb_client,
+ SVMDB_NAMESPACE_VEC,
+ "vpp_vector_rate");
+ gm->input_rate_ptr =
+ svmdb_local_get_variable_reference (gm->svmdb_client,
+ SVMDB_NAMESPACE_VEC,
+ "vpp_input_rate");
+ gm->sig_error_rate_ptr =
+ svmdb_local_get_variable_reference (gm->svmdb_client,
+ SVMDB_NAMESPACE_VEC,
+ "vpp_sig_error_rate");
+ gm->vpef_pid_ptr =
+ svmdb_local_get_variable_reference (gm->svmdb_client,
+ SVMDB_NAMESPACE_VEC, "vpp_pid");
+ return 0;
+}
+
+VLIB_INIT_FUNCTION (gmon_init);
+
+static clib_error_t *
+gmon_exit (vlib_main_t * vm)
+{
+ gmon_main_t *gm = &gmon_main;
+
+ if (gm->vector_rate_ptr)
+ {
+ *gm->vector_rate_ptr = 0.0;
+ *gm->vpef_pid_ptr = 0;
+ *gm->input_rate_ptr = 0.0;
+ *gm->sig_error_rate_ptr = 0.0;
+ svm_region_unmap ((void *) gm->svmdb_client->db_rp);
+ vec_free (gm->svmdb_client);
+ }
+ return 0;
+}
+
+VLIB_MAIN_LOOP_EXIT_FUNCTION (gmon_exit);
+
+static int
+significant_error_enable_disable (gmon_main_t * gm, u32 index, int enable)
+{
+ vlib_main_t *vm = gm->vlib_main;
+ vlib_error_main_t *em = &vm->error_main;
+
+ if (index >= vec_len (em->counters))
+ return VNET_API_ERROR_NO_SUCH_ENTRY;
+
+ gm->sig_error_bitmap =
+ clib_bitmap_set (gm->sig_error_bitmap, index, enable);
+ return 0;
+}
+
+static clib_error_t *
+set_significant_error_command_fn (vlib_main_t * vm,
+ unformat_input_t * input,
+ vlib_cli_command_t * cmd)
+{
+ u32 index;
+ int enable = 1;
+ int rv;
+ gmon_main_t *gm = &gmon_main;
+
+ while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (input, "%d", &index))
+ ;
+ else if (unformat (input, "disable"))
+ enable = 0;
+ else
+ return clib_error_return (0, "unknown input `%U'",
+ format_unformat_error, input);
+ }
+
+ rv = significant_error_enable_disable (gm, index, enable);
+
+ switch (rv)
+ {
+ case 0:
+ break;
+
+ default:
+ return clib_error_return
+ (0, "significant_error_enable_disable returned %d", rv);
+ }
+
+ return 0;
+}
+
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND (set_significant_error_command, static) = {
+ .path = "set significant error",
+ .short_help = "set significant error <counter-index-nnn> [disable]",
+ .function = set_significant_error_command_fn,
+};
+/* *INDENT-ON* */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/src/vpp/api/json_format.c b/src/vpp/api/json_format.c
new file mode 100644
index 00000000..63454b87
--- /dev/null
+++ b/src/vpp/api/json_format.c
@@ -0,0 +1,304 @@
+/*
+ *------------------------------------------------------------------
+ * json_format.c
+ *
+ * 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.
+ *------------------------------------------------------------------
+
+*/
+#include <inttypes.h>
+#include "json_format.h"
+#include <vnet/ip/ip.h>
+#include <vppinfra/vec.h>
+
+#define VAT_TAB_WIDTH 2
+
+typedef struct vat_print_ctx_s
+{
+ FILE *ofp;
+ u32 indent;
+} vat_print_ctx_t;
+
+/* Format an IP4 address. */
+static u8 *
+vat_json_format_ip4_address (u8 * s, va_list * args)
+{
+ u8 *a = va_arg (*args, u8 *);
+ return format (s, "%d.%d.%d.%d", a[0], a[1], a[2], a[3]);
+}
+
+/* Format an IP6 address. */
+static u8 *
+vat_json_format_ip6_address (u8 * s, va_list * args)
+{
+ ip6_address_t *a = va_arg (*args, ip6_address_t *);
+ u32 i, i_max_n_zero, max_n_zeros, i_first_zero, n_zeros, last_double_colon;
+
+ i_max_n_zero = ARRAY_LEN (a->as_u16);
+ max_n_zeros = 0;
+ i_first_zero = i_max_n_zero;
+ n_zeros = 0;
+ for (i = 0; i < ARRAY_LEN (a->as_u16); i++)
+ {
+ u32 is_zero = a->as_u16[i] == 0;
+ if (is_zero && i_first_zero >= ARRAY_LEN (a->as_u16))
+ {
+ i_first_zero = i;
+ n_zeros = 0;
+ }
+ n_zeros += is_zero;
+ if ((!is_zero && n_zeros > max_n_zeros)
+ || (i + 1 >= ARRAY_LEN (a->as_u16) && n_zeros > max_n_zeros))
+ {
+ i_max_n_zero = i_first_zero;
+ max_n_zeros = n_zeros;
+ i_first_zero = ARRAY_LEN (a->as_u16);
+ n_zeros = 0;
+ }
+ }
+
+ last_double_colon = 0;
+ for (i = 0; i < ARRAY_LEN (a->as_u16); i++)
+ {
+ if (i == i_max_n_zero && max_n_zeros > 1)
+ {
+ s = format (s, "::");
+ i += max_n_zeros - 1;
+ last_double_colon = 1;
+ }
+ else
+ {
+ s = format (s, "%s%x",
+ (last_double_colon || i == 0) ? "" : ":",
+ clib_net_to_host_u16 (a->as_u16[i]));
+ last_double_colon = 0;
+ }
+ }
+
+ return s;
+}
+
+static void
+vat_json_indent_print (vat_print_ctx_t * ctx)
+{
+ int i;
+ for (i = 0; i < ctx->indent * VAT_TAB_WIDTH; i++)
+ {
+ fformat (ctx->ofp, " ");
+ }
+}
+
+static void
+vat_json_indent_line (vat_print_ctx_t * ctx, char *fmt, ...)
+{
+ va_list va;
+
+ vat_json_indent_print (ctx);
+ va_start (va, fmt);
+ va_fformat (ctx->ofp, fmt, &va);
+ va_end (va);
+}
+
+static u8
+is_num_only (vat_json_node_t * p)
+{
+ vat_json_node_t *elem;
+ vec_foreach (elem, p)
+ {
+ if (VAT_JSON_INT != elem->type && VAT_JSON_UINT != elem->type)
+ {
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static void
+vat_json_print_internal (vat_print_ctx_t * ctx, vat_json_node_t * node)
+{
+#define P(fmt,...) fformat(ctx->ofp, fmt, ##__VA_ARGS__)
+#define PL(fmt,...) fformat(ctx->ofp, fmt"\n", ##__VA_ARGS__)
+#define PPL(fmt,...) vat_json_indent_line(ctx, fmt"\n", ##__VA_ARGS__)
+#define PP(fmt,...) vat_json_indent_line(ctx, fmt, ##__VA_ARGS__)
+#define INCR (ctx->indent++)
+#define DECR (ctx->indent--)
+
+ vat_json_pair_t *pair;
+ u32 i, count;
+ vat_json_node_t *elem;
+ u8 num_only = 0;
+
+ if (!node)
+ {
+ return;
+ }
+
+ switch (node->type)
+ {
+ case VAT_JSON_OBJECT:
+ count = vec_len (node->pairs);
+ if (count >= 1)
+ {
+ PL ("{");
+ INCR;
+ for (i = 0; i < count; i++)
+ {
+ pair = &node->pairs[i];
+ PP ("\"%s\": ", pair->name);
+ vat_json_print_internal (ctx, &pair->value);
+ if (i < count - 1)
+ {
+ P (",");
+ }
+ PL ();
+ }
+ DECR;
+ PP ("}");
+ }
+ else
+ {
+ P ("{}");
+ }
+ break;
+ case VAT_JSON_ARRAY:
+ num_only = is_num_only (node->array);
+ count = vec_len (node->array);
+ if (count >= 1)
+ {
+ if (num_only)
+ P ("[");
+ else
+ PL ("[ ");
+ INCR;
+ for (i = 0; i < count; i++)
+ {
+ elem = &node->array[i];
+ if (!num_only)
+ {
+ vat_json_indent_print (ctx);
+ }
+ vat_json_print_internal (ctx, elem);
+ if (i < count - 1)
+ {
+ if (num_only)
+ {
+ P (", ");
+ }
+ else
+ {
+ P (",");
+ }
+ }
+ if (!num_only)
+ PL ();
+ }
+ DECR;
+ if (!num_only)
+ PP ("]");
+ else
+ P ("]");
+ }
+ else
+ {
+ P ("[]");
+ }
+ break;
+ case VAT_JSON_INT:
+ P ("%d", node->sint);
+ break;
+ case VAT_JSON_UINT:
+ P ("%" PRIu64, node->uint);
+ break;
+ case VAT_JSON_REAL:
+ P ("%f", node->real);
+ break;
+ case VAT_JSON_STRING:
+ P ("\"%s\"", node->string);
+ break;
+ case VAT_JSON_IPV4:
+ P ("\"%U\"", vat_json_format_ip4_address, &node->ip4);
+ break;
+ case VAT_JSON_IPV6:
+ P ("\"%U\"", vat_json_format_ip6_address, &node->ip6);
+ break;
+ default:
+ break;
+ }
+#undef PPL
+#undef PP
+#undef PL
+#undef P
+}
+
+void
+vat_json_print (FILE * ofp, vat_json_node_t * node)
+{
+ vat_print_ctx_t ctx;
+ memset (&ctx, 0, sizeof ctx);
+ ctx.indent = 0;
+ ctx.ofp = ofp;
+ fformat (ofp, "\n");
+ vat_json_print_internal (&ctx, node);
+ fformat (ofp, "\n");
+}
+
+void
+vat_json_free (vat_json_node_t * node)
+{
+ int i = 0;
+
+ if (NULL == node)
+ {
+ return;
+ }
+ switch (node->type)
+ {
+ case VAT_JSON_OBJECT:
+ for (i = 0; i < vec_len (node->pairs); i++)
+ {
+ vat_json_free (&node->pairs[i].value);
+ }
+ if (NULL != node->pairs)
+ {
+ vec_free (node->pairs);
+ }
+ break;
+ case VAT_JSON_ARRAY:
+ for (i = 0; i < vec_len (node->array); i++)
+ {
+ vat_json_free (&node->array[i]);
+ }
+ if (NULL != node->array)
+ {
+ vec_free (node->array);
+ }
+ break;
+ case VAT_JSON_STRING:
+ if (NULL != node->string)
+ {
+ vec_free (node->string);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/src/vpp/api/json_format.h b/src/vpp/api/json_format.h
new file mode 100644
index 00000000..154fb3df
--- /dev/null
+++ b/src/vpp/api/json_format.h
@@ -0,0 +1,254 @@
+/*
+ *------------------------------------------------------------------
+ * json_format.h
+ *
+ * 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.
+ *------------------------------------------------------------------
+ */
+
+#ifndef __JSON_FORMAT_H__
+#define __JSON_FORMAT_H__
+
+#include <vppinfra/clib.h>
+#include <vppinfra/format.h>
+#include <netinet/ip.h>
+
+/* JSON value type */
+typedef enum
+{
+ VAT_JSON_NONE,
+ VAT_JSON_OBJECT,
+ VAT_JSON_ARRAY,
+ VAT_JSON_STRING,
+ VAT_JSON_REAL,
+ VAT_JSON_UINT,
+ VAT_JSON_INT,
+ VAT_JSON_IPV4,
+ VAT_JSON_IPV6,
+ VAT_JSON_MAX
+} vat_json_val_type_t;
+
+typedef struct vat_json_node_s vat_json_node_t;
+typedef struct vat_json_pair_s vat_json_pair_t;
+
+/* JSON object structure */
+struct vat_json_node_s
+{
+ vat_json_val_type_t type;
+ union
+ {
+ vat_json_pair_t *pairs;
+ vat_json_node_t *array;
+ u8 *string;
+ struct in_addr ip4;
+ struct in6_addr ip6;
+ u64 uint;
+ i64 sint;
+ f64 real;
+ };
+};
+
+struct vat_json_pair_s
+{
+ const char *name;
+ vat_json_node_t value;
+};
+
+void vat_json_print (FILE * ofp, vat_json_node_t * node);
+void vat_json_free (vat_json_node_t * node);
+
+static_always_inline void
+vat_json_init_object (vat_json_node_t * json)
+{
+ json->type = VAT_JSON_OBJECT;
+ json->pairs = NULL;
+}
+
+static_always_inline void
+vat_json_init_array (vat_json_node_t * json)
+{
+ json->type = VAT_JSON_ARRAY;
+ json->array = NULL;
+}
+
+static_always_inline void
+vat_json_set_string (vat_json_node_t * json, u8 * str)
+{
+ json->type = VAT_JSON_STRING;
+ json->string = str;
+}
+
+static_always_inline void
+vat_json_set_string_copy (vat_json_node_t * json, const u8 * str)
+{
+ u8 *ns = NULL;
+ vec_validate (ns, strlen ((const char *) str));
+ strcpy ((char *) ns, (const char *) str);
+ vec_add1 (ns, '\0');
+ vat_json_set_string (json, ns);
+}
+
+static_always_inline void
+vat_json_set_int (vat_json_node_t * json, i64 num)
+{
+ json->type = VAT_JSON_INT;
+ json->sint = num;
+}
+
+static_always_inline void
+vat_json_set_uint (vat_json_node_t * json, u64 num)
+{
+ json->type = VAT_JSON_UINT;
+ json->uint = num;
+}
+
+static_always_inline void
+vat_json_set_real (vat_json_node_t * json, f64 real)
+{
+ json->type = VAT_JSON_REAL;
+ json->real = real;
+}
+
+static_always_inline void
+vat_json_set_ip4 (vat_json_node_t * json, struct in_addr ip4)
+{
+ json->type = VAT_JSON_IPV4;
+ json->ip4 = ip4;
+}
+
+static_always_inline void
+vat_json_set_ip6 (vat_json_node_t * json, struct in6_addr ip6)
+{
+ json->type = VAT_JSON_IPV6;
+ json->ip6 = ip6;
+}
+
+static_always_inline vat_json_node_t *
+vat_json_object_add (vat_json_node_t * json, const char *name)
+{
+ ASSERT (VAT_JSON_OBJECT == json->type);
+ uword pos = vec_len (json->pairs);
+ vec_validate (json->pairs, pos);
+ json->pairs[pos].name = name;
+ return &json->pairs[pos].value;
+}
+
+static_always_inline vat_json_node_t *
+vat_json_array_add (vat_json_node_t * json)
+{
+ ASSERT (VAT_JSON_ARRAY == json->type);
+ uword pos = vec_len (json->array);
+ vec_validate (json->array, pos);
+ return &json->array[pos];
+}
+
+static_always_inline vat_json_node_t *
+vat_json_object_add_list (vat_json_node_t * json, const char *name)
+{
+ vat_json_node_t *array_node = vat_json_object_add (json, name);
+ vat_json_init_array (array_node);
+ return array_node;
+}
+
+static_always_inline void
+vat_json_object_add_string_copy (vat_json_node_t * json,
+ const char *name, u8 * str)
+{
+ vat_json_set_string_copy (vat_json_object_add (json, name), str);
+}
+
+static_always_inline void
+vat_json_object_add_uint (vat_json_node_t * json,
+ const char *name, u64 number)
+{
+ vat_json_set_uint (vat_json_object_add (json, name), number);
+}
+
+static_always_inline void
+vat_json_object_add_int (vat_json_node_t * json, const char *name, i64 number)
+{
+ vat_json_set_int (vat_json_object_add (json, name), number);
+}
+
+static_always_inline void
+vat_json_object_add_real (vat_json_node_t * json, const char *name, f64 real)
+{
+ vat_json_set_real (vat_json_object_add (json, name), real);
+}
+
+static_always_inline void
+vat_json_object_add_ip4 (vat_json_node_t * json,
+ const char *name, struct in_addr ip4)
+{
+ vat_json_set_ip4 (vat_json_object_add (json, name), ip4);
+}
+
+static_always_inline void
+vat_json_object_add_ip6 (vat_json_node_t * json,
+ const char *name, struct in6_addr ip6)
+{
+ vat_json_set_ip6 (vat_json_object_add (json, name), ip6);
+}
+
+static_always_inline void
+vat_json_array_add_int (vat_json_node_t * json, i64 number)
+{
+ vat_json_set_int (vat_json_array_add (json), number);
+}
+
+static_always_inline void
+vat_json_array_add_uint (vat_json_node_t * json, u64 number)
+{
+ vat_json_set_uint (vat_json_array_add (json), number);
+}
+
+static_always_inline void
+vat_json_object_add_bytes (vat_json_node_t * json,
+ const char *name, u8 * array, uword size)
+{
+ ASSERT (VAT_JSON_OBJECT == json->type);
+ vat_json_node_t *json_array = vat_json_object_add (json, name);
+ vat_json_init_array (json_array);
+ int i;
+ for (i = 0; i < size; i++)
+ {
+ vat_json_array_add_uint (json_array, array[i]);
+ }
+}
+
+static_always_inline vat_json_node_t *
+vat_json_object_get_element (vat_json_node_t * json, const char *name)
+{
+ int i = 0;
+
+ ASSERT (VAT_JSON_OBJECT == json->type);
+ for (i = 0; i < vec_len (json->pairs); i++)
+ {
+ if (0 == strcmp (json->pairs[i].name, name))
+ {
+ return &json->pairs[i].value;
+ }
+ }
+ return NULL;
+}
+
+#endif /* __JSON_FORMAT_H__ */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/src/vpp/api/plugin.c b/src/vpp/api/plugin.c
new file mode 100644
index 00000000..c1cc928c
--- /dev/null
+++ b/src/vpp/api/plugin.c
@@ -0,0 +1,201 @@
+/*
+ * 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.
+ */
+/*
+ * plugin.c: plugin handling
+ */
+
+#include <vat/vat.h>
+#include <vat/plugin.h>
+#include <dlfcn.h>
+#include <dirent.h>
+
+plugin_main_t vat_plugin_main;
+
+static int
+load_one_plugin (plugin_main_t * pm, plugin_info_t * pi)
+{
+ void *handle, *register_handle;
+ clib_error_t *(*fp) (vat_main_t *);
+ clib_error_t *error;
+
+ handle = dlopen ((char *) pi->name, RTLD_LAZY);
+
+ /*
+ * Note: this can happen if the plugin has an undefined symbol reference,
+ * so print a warning. Otherwise, the poor slob won't know what happened.
+ * Ask me how I know that...
+ */
+ if (handle == 0)
+ {
+ clib_warning ("%s", dlerror ());
+ return -1;
+ }
+
+ pi->handle = handle;
+
+ register_handle = dlsym (pi->handle, "vat_plugin_register");
+ if (register_handle == 0)
+ return 0;
+
+ fp = register_handle;
+
+ error = (*fp) (pm->vat_main);
+
+ if (error)
+ {
+ clib_error_report (error);
+ dlclose (handle);
+ return 1;
+ }
+
+ clib_warning ("Loaded plugin: %s", pi->name);
+
+ return 0;
+}
+
+static u8 **
+split_plugin_path (plugin_main_t * pm)
+{
+ int i;
+ u8 **rv = 0;
+ u8 *path = pm->plugin_path;
+ u8 *this = 0;
+
+ for (i = 0; i < vec_len (pm->plugin_path); i++)
+ {
+ if (path[i] != ':')
+ {
+ vec_add1 (this, path[i]);
+ continue;
+ }
+ vec_add1 (this, 0);
+ vec_add1 (rv, this);
+ this = 0;
+ }
+ if (this)
+ {
+ vec_add1 (this, 0);
+ vec_add1 (rv, this);
+ }
+ return rv;
+}
+
+int
+vat_load_new_plugins (plugin_main_t * pm)
+{
+ DIR *dp;
+ struct dirent *entry;
+ struct stat statb;
+ uword *p;
+ plugin_info_t *pi;
+ u8 **plugin_path;
+ int i;
+
+ plugin_path = split_plugin_path (pm);
+
+ for (i = 0; i < vec_len (plugin_path); i++)
+ {
+ dp = opendir ((char *) plugin_path[i]);
+
+ if (dp == 0)
+ continue;
+
+ while ((entry = readdir (dp)))
+ {
+ u8 *plugin_name;
+
+ if (pm->plugin_name_filter)
+ {
+ int j;
+ for (j = 0; j < vec_len (pm->plugin_name_filter); j++)
+ if (entry->d_name[j] != pm->plugin_name_filter[j])
+ goto next;
+ }
+
+ plugin_name = format (0, "%s/%s%c", plugin_path[i],
+ entry->d_name, 0);
+
+ /* unreadable */
+ if (stat ((char *) plugin_name, &statb) < 0)
+ {
+ ignore:
+ vec_free (plugin_name);
+ continue;
+ }
+
+ /* a dir or other things which aren't plugins */
+ if (!S_ISREG (statb.st_mode))
+ goto ignore;
+
+ p = hash_get_mem (pm->plugin_by_name_hash, plugin_name);
+ if (p == 0)
+ {
+ vec_add2 (pm->plugin_info, pi, 1);
+ pi->name = plugin_name;
+ pi->file_info = statb;
+
+ if (load_one_plugin (pm, pi))
+ {
+ vec_free (plugin_name);
+ _vec_len (pm->plugin_info) = vec_len (pm->plugin_info) - 1;
+ continue;
+ }
+ memset (pi, 0, sizeof (*pi));
+ hash_set_mem (pm->plugin_by_name_hash, plugin_name,
+ pi - pm->plugin_info);
+ }
+ next:
+ ;
+ }
+ closedir (dp);
+ vec_free (plugin_path[i]);
+ }
+ vec_free (plugin_path);
+ return 0;
+}
+
+#define QUOTE_(x) #x
+#define QUOTE(x) QUOTE_(x)
+
+/*
+ * Load plugins from /usr/lib/vpp_api_test_plugins by default
+ */
+char *vat_plugin_path = "/usr/lib/vpp_api_test_plugins";
+
+char *vat_plugin_name_filter = 0;
+
+int
+vat_plugin_init (vat_main_t * vam)
+{
+ plugin_main_t *pm = &vat_plugin_main;
+
+
+ pm->plugin_path = format (0, "%s%c", vat_plugin_path, 0);
+ if (vat_plugin_name_filter)
+ pm->plugin_name_filter = format (0, "%s%c", vat_plugin_name_filter, 0);
+
+ pm->plugin_by_name_hash = hash_create_string (0, sizeof (uword));
+ pm->vat_main = vam;
+
+ return vat_load_new_plugins (pm);
+}
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/src/vpp/api/plugin.h b/src/vpp/api/plugin.h
new file mode 100644
index 00000000..559ec52f
--- /dev/null
+++ b/src/vpp/api/plugin.h
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ */
+/*
+ * plugin.h: plugin handling
+ */
+
+#ifndef __included_plugin_h__
+#define __included_plugin_h__
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+typedef struct
+{
+ u8 *name;
+ struct stat file_info;
+ void *handle;
+} plugin_info_t;
+
+typedef struct
+{
+ /* loaded plugin info */
+ plugin_info_t *plugin_info;
+ uword *plugin_by_name_hash;
+
+ /* path and name filter */
+ u8 *plugin_path;
+ u8 *plugin_name_filter;
+
+ /* convenience */
+ vat_main_t *vat_main;
+
+} plugin_main_t;
+
+plugin_main_t vat_plugin_main;
+
+int vat_plugin_init (vat_main_t * vam);
+int vat_load_new_plugins (plugin_main_t * pm);
+
+#endif
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/src/vpp/api/summary_stats_client.c b/src/vpp/api/summary_stats_client.c
new file mode 100644
index 00000000..2c81d667
--- /dev/null
+++ b/src/vpp/api/summary_stats_client.c
@@ -0,0 +1,302 @@
+/*
+ *------------------------------------------------------------------
+ * summary_stats_client -
+ *
+ * Copyright (c) 2010 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.
+ *------------------------------------------------------------------
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <signal.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <time.h>
+#include <fcntl.h>
+#include <string.h>
+#include <vppinfra/clib.h>
+#include <vppinfra/vec.h>
+#include <vppinfra/hash.h>
+#include <vppinfra/bitmap.h>
+#include <vppinfra/fifo.h>
+#include <vppinfra/time.h>
+#include <vppinfra/mheap.h>
+#include <vppinfra/heap.h>
+#include <vppinfra/pool.h>
+#include <vppinfra/format.h>
+#include <vppinfra/error.h>
+
+#include <vnet/vnet.h>
+#include <vlib/vlib.h>
+#include <vlib/unix/unix.h>
+#include <vlibapi/api.h>
+#include <vlibmemory/api.h>
+
+#include <vpp/api/vpe_msg_enum.h>
+
+#include <vnet/ip/ip.h>
+
+#define f64_endian(a)
+#define f64_print(a,b)
+
+#define vl_typedefs /* define message structures */
+#include <vpp/api/vpe_all_api_h.h>
+#undef vl_typedefs
+
+#define vl_endianfun /* define message structures */
+#include <vpp/api/vpe_all_api_h.h>
+#undef vl_endianfun
+
+/* instantiate all the print functions we know about */
+#define vl_print(handle, ...)
+#define vl_printfun
+#include <vpp/api/vpe_all_api_h.h>
+#undef vl_printfun
+
+vl_shmem_hdr_t *shmem_hdr;
+
+typedef struct
+{
+ volatile int sigterm_received;
+
+ struct sockaddr_in send_data_addr;
+ int send_data_socket;
+ u8 *display_name;
+
+ /* convenience */
+ unix_shared_memory_queue_t *vl_input_queue;
+ u32 my_client_index;
+} test_main_t;
+
+test_main_t test_main;
+
+/*
+ * Satisfy external references when -lvlib is not available.
+ */
+vlib_main_t vlib_global_main;
+vlib_main_t **vlib_mains;
+
+void
+vlib_cli_output (struct vlib_main_t *vm, char *fmt, ...)
+{
+ clib_warning ("vlib_cli_output callled...");
+}
+
+
+static void
+ vl_api_vnet_get_summary_stats_reply_t_handler
+ (vl_api_vnet_get_summary_stats_reply_t * mp)
+{
+ test_main_t *tm = &test_main;
+ static u8 *sb;
+ int n;
+
+ printf ("total rx pkts %llu, total rx bytes %llu\n",
+ (unsigned long long) mp->total_pkts[0],
+ (unsigned long long) mp->total_bytes[0]);
+ printf ("total tx pkts %llu, total tx bytes %llu\n",
+ (unsigned long long) mp->total_pkts[1],
+ (unsigned long long) mp->total_bytes[1]);
+ printf ("vector rate %.2f\n", mp->vector_rate);
+
+ vec_reset_length (sb);
+ sb = format (sb, "%v,%.0f,%llu,%llu,%llu,%llu\n%c",
+ tm->display_name, mp->vector_rate,
+ (unsigned long long) mp->total_pkts[0],
+ (unsigned long long) mp->total_bytes[0],
+ (unsigned long long) mp->total_pkts[1],
+ (unsigned long long) mp->total_bytes[1], 0);
+
+ n = sendto (tm->send_data_socket, sb, vec_len (sb),
+ 0, (struct sockaddr *) &tm->send_data_addr,
+ sizeof (tm->send_data_addr));
+
+ if (n != vec_len (sb))
+ clib_unix_warning ("sendto");
+
+}
+
+#define foreach_api_msg \
+_(VNET_GET_SUMMARY_STATS_REPLY, vnet_get_summary_stats_reply)
+
+int
+connect_to_vpe (char *name)
+{
+ int rv = 0;
+
+ rv = vl_client_connect_to_vlib ("/vpe-api", name, 32);
+
+#define _(N,n) \
+ vl_msg_api_set_handlers(VL_API_##N, #n, \
+ vl_api_##n##_t_handler, \
+ vl_noop_handler, \
+ vl_api_##n##_t_endian, \
+ vl_api_##n##_t_print, \
+ sizeof(vl_api_##n##_t), 1);
+ foreach_api_msg;
+#undef _
+
+ shmem_hdr = api_main.shmem_hdr;
+
+ return rv;
+}
+
+int
+disconnect_from_vpe (void)
+{
+ vl_client_disconnect_from_vlib ();
+ return 0;
+}
+
+static void
+sigterm_handler (int sig)
+{
+ test_main_t *tm = &test_main;
+ tm->sigterm_received = 1;
+}
+
+/* Parse an IP4 address %d.%d.%d.%d. */
+uword
+unformat_ip4_address (unformat_input_t * input, va_list * args)
+{
+ u8 *result = va_arg (*args, u8 *);
+ unsigned a[4];
+
+ if (!unformat (input, "%d.%d.%d.%d", &a[0], &a[1], &a[2], &a[3]))
+ return 0;
+
+ if (a[0] >= 256 || a[1] >= 256 || a[2] >= 256 || a[3] >= 256)
+ return 0;
+
+ result[0] = a[0];
+ result[1] = a[1];
+ result[2] = a[2];
+ result[3] = a[3];
+
+ return 1;
+}
+
+int
+main (int argc, char **argv)
+{
+ api_main_t *am = &api_main;
+ test_main_t *tm = &test_main;
+ vl_api_vnet_get_summary_stats_t *mp;
+ unformat_input_t _input, *input = &_input;
+ clib_error_t *error = 0;
+ ip4_address_t collector_ip;
+ u8 *display_name = 0;
+ u16 collector_port = 7654;
+
+ collector_ip.as_u32 = (u32) ~ 0;
+
+ unformat_init_command_line (input, argv);
+
+ while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (input, "collector-ip %U",
+ unformat_ip4_address, &collector_ip))
+ ;
+ else if (unformat (input, "display-name %v", &display_name))
+ ;
+ else if (unformat (input, "collector-port %d", &collector_port))
+ ;
+ else
+ {
+ error =
+ clib_error_return
+ (0, "Usage: %s collector-ip <ip>\n"
+ " [display-name <string>] [collector-port <num>]\n"
+ " port defaults to 7654", argv[0]);
+ break;
+ }
+ }
+
+ if (error == 0 && collector_ip.as_u32 == (u32) ~ 0)
+ error = clib_error_return (0, "collector-ip not set...\n");
+
+
+ if (error)
+ {
+ clib_error_report (error);
+ exit (1);
+ }
+
+ if (display_name == 0)
+ {
+ display_name = format (0, "vpe-to-%d.%d.%d.%d",
+ collector_ip.as_u8[0],
+ collector_ip.as_u8[1],
+ collector_ip.as_u8[2], collector_ip.as_u8[3]);
+ }
+
+
+ connect_to_vpe ("test_client");
+
+ tm->vl_input_queue = shmem_hdr->vl_input_queue;
+ tm->my_client_index = am->my_client_index;
+ tm->display_name = display_name;
+
+ signal (SIGTERM, sigterm_handler);
+ signal (SIGINT, sigterm_handler);
+ signal (SIGQUIT, sigterm_handler);
+
+ /* data (multicast) RX socket */
+ tm->send_data_socket = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ if (tm->send_data_socket < 0)
+ {
+ clib_unix_warning (0, "data_rx_socket");
+ exit (1);
+ }
+
+ memset (&tm->send_data_addr, 0, sizeof (tm->send_data_addr));
+ tm->send_data_addr.sin_family = AF_INET;
+ tm->send_data_addr.sin_addr.s_addr = collector_ip.as_u32;
+ tm->send_data_addr.sin_port = htons (collector_port);
+
+ fformat (stdout, "Send SIGINT or SIGTERM to quit...\n");
+
+ while (1)
+ {
+ sleep (5);
+
+ if (tm->sigterm_received)
+ break;
+ /* Poll for stats */
+ mp = vl_msg_api_alloc (sizeof (*mp));
+ memset (mp, 0, sizeof (*mp));
+ mp->_vl_msg_id = ntohs (VL_API_VNET_GET_SUMMARY_STATS);
+ mp->client_index = tm->my_client_index;
+ vl_msg_api_send_shmem (tm->vl_input_queue, (u8 *) & mp);
+ }
+
+ fformat (stdout, "Exiting...\n");
+
+ disconnect_from_vpe ();
+ exit (0);
+}
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/src/vpp/api/test_client.c b/src/vpp/api/test_client.c
new file mode 100644
index 00000000..844b9702
--- /dev/null
+++ b/src/vpp/api/test_client.c
@@ -0,0 +1,1526 @@
+/*
+ *------------------------------------------------------------------
+ * api.c - message handler registration
+ *
+ * Copyright (c) 2010 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.
+ *------------------------------------------------------------------
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <signal.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <time.h>
+#include <fcntl.h>
+#include <string.h>
+#include <vppinfra/clib.h>
+#include <vppinfra/vec.h>
+#include <vppinfra/hash.h>
+#include <vppinfra/bitmap.h>
+#include <vppinfra/fifo.h>
+#include <vppinfra/time.h>
+#include <vppinfra/mheap.h>
+#include <vppinfra/heap.h>
+#include <vppinfra/pool.h>
+#include <vppinfra/format.h>
+#include <vppinfra/error.h>
+
+#include <vnet/vnet.h>
+#include <vlib/vlib.h>
+#include <vlib/unix/unix.h>
+#include <vlibapi/api.h>
+#include <vlibmemory/api.h>
+
+#include <vpp/api/vpe_msg_enum.h>
+
+#include <vnet/ip/ip.h>
+#include <vnet/interface.h>
+
+#define f64_endian(a)
+#define f64_print(a,b)
+
+#define vl_typedefs /* define message structures */
+#include <vpp/api/vpe_all_api_h.h>
+#undef vl_typedefs
+
+#define vl_endianfun /* define message structures */
+#include <vpp/api/vpe_all_api_h.h>
+#undef vl_endianfun
+
+/* instantiate all the print functions we know about */
+#define vl_print(handle, ...)
+#define vl_printfun
+#include <vpp/api/vpe_all_api_h.h>
+#undef vl_printfun
+
+vl_shmem_hdr_t *shmem_hdr;
+
+typedef struct
+{
+ int link_events_on;
+ int stats_on;
+ int oam_events_on;
+
+ /* convenience */
+ unix_shared_memory_queue_t *vl_input_queue;
+ u32 my_client_index;
+} test_main_t;
+
+test_main_t test_main;
+
+/*
+ * Satisfy external references when -lvlib is not available.
+ */
+vlib_main_t vlib_global_main;
+vlib_main_t **vlib_mains;
+
+void
+vlib_cli_output (struct vlib_main_t *vm, char *fmt, ...)
+{
+ clib_warning ("vlib_cli_output callled...");
+}
+
+u8 *
+format_ethernet_address (u8 * s, va_list * args)
+{
+ u8 *a = va_arg (*args, u8 *);
+
+ return format (s, "%02x:%02x:%02x:%02x:%02x:%02x",
+ a[0], a[1], a[2], a[3], a[4], a[5]);
+}
+
+static void
+vl_api_sw_interface_details_t_handler (vl_api_sw_interface_details_t * mp)
+{
+ char *duplex, *speed;
+
+ switch (mp->link_duplex << VNET_HW_INTERFACE_FLAG_DUPLEX_SHIFT)
+ {
+ case VNET_HW_INTERFACE_FLAG_HALF_DUPLEX:
+ duplex = "half";
+ break;
+ case VNET_HW_INTERFACE_FLAG_FULL_DUPLEX:
+ duplex = "full";
+ break;
+ default:
+ duplex = "bogus";
+ break;
+ }
+ switch (mp->link_speed << VNET_HW_INTERFACE_FLAG_SPEED_SHIFT)
+ {
+ case VNET_HW_INTERFACE_FLAG_SPEED_10M:
+ speed = "10Mbps";
+ break;
+ case VNET_HW_INTERFACE_FLAG_SPEED_100M:
+ speed = "100Mbps";
+ break;
+ case VNET_HW_INTERFACE_FLAG_SPEED_1G:
+ speed = "1Gbps";
+ break;
+ case VNET_HW_INTERFACE_FLAG_SPEED_10G:
+ speed = "10Gbps";
+ break;
+ case VNET_HW_INTERFACE_FLAG_SPEED_40G:
+ speed = "40Gbps";
+ break;
+ case VNET_HW_INTERFACE_FLAG_SPEED_100G:
+ speed = "100Gbps";
+ break;
+ default:
+ speed = "bogus";
+ break;
+ }
+ fformat (stdout, "details: %s sw_if_index %d sup_sw_if_index %d "
+ "link_duplex %s link_speed %s",
+ mp->interface_name, ntohl (mp->sw_if_index),
+ ntohl (mp->sup_sw_if_index), duplex, speed);
+
+ if (mp->l2_address_length)
+ fformat (stdout, " l2 address: %U\n",
+ format_ethernet_address, mp->l2_address);
+ else
+ fformat (stdout, "\n");
+}
+
+static void
+vl_api_sw_interface_set_flags_t_handler (vl_api_sw_interface_set_flags_t * mp)
+{
+ fformat (stdout, "set flags: sw_if_index %d, admin %s link %s\n",
+ ntohl (mp->sw_if_index),
+ mp->admin_up_down ? "up" : "down",
+ mp->link_up_down ? "up" : "down");
+}
+
+static void
+ vl_api_sw_interface_set_flags_reply_t_handler
+ (vl_api_sw_interface_set_flags_reply_t * mp)
+{
+ fformat (stdout, "set flags reply: reply %d\n", ntohl (mp->retval));
+}
+
+static void
+ vl_api_want_interface_events_reply_t_handler
+ (vl_api_want_interface_events_reply_t * mp)
+{
+}
+
+static void
+vl_api_want_stats_reply_t_handler (vl_api_want_stats_reply_t * mp)
+{
+ fformat (stdout, "want stats reply %d\n", ntohl (mp->retval));
+}
+
+static void
+vl_api_want_oam_events_reply_t_handler (vl_api_want_oam_events_reply_t * mp)
+{
+ fformat (stdout, "want oam reply %d\n", ntohl (mp->retval));
+}
+
+static void
+vl_api_ip_add_del_route_reply_t_handler (vl_api_ip_add_del_route_reply_t * mp)
+{
+ fformat (stdout, "add_route reply %d\n", ntohl (mp->retval));
+}
+
+static void
+ vl_api_sw_interface_add_del_address_reply_t_handler
+ (vl_api_sw_interface_add_del_address_reply_t * mp)
+{
+ fformat (stdout, "add_del_address reply %d\n", ntohl (mp->retval));
+}
+
+static void
+ vl_api_sw_interface_set_table_reply_t_handler
+ (vl_api_sw_interface_set_table_reply_t * mp)
+{
+ fformat (stdout, "set_table reply %d\n", ntohl (mp->retval));
+}
+
+static void
+vl_api_tap_connect_reply_t_handler (vl_api_tap_connect_reply_t * mp)
+{
+ fformat (stdout, "tap connect reply %d, sw_if_index %d\n",
+ ntohl (mp->retval), ntohl (mp->sw_if_index));
+}
+
+static void
+vl_api_create_vlan_subif_reply_t_handler (vl_api_create_vlan_subif_reply_t *
+ mp)
+{
+ fformat (stdout, "create vlan subif reply %d, sw_if_index %d\n",
+ ntohl (mp->retval), ntohl (mp->sw_if_index));
+}
+
+static void vl_api_proxy_arp_add_del_reply_t_handler
+ (vl_api_proxy_arp_add_del_reply_t * mp)
+{
+ fformat (stdout, "add del proxy arp reply %d\n", ntohl (mp->retval));
+}
+
+static void vl_api_proxy_arp_intfc_enable_disable_reply_t_handler
+ (vl_api_proxy_arp_intfc_enable_disable_reply_t * mp)
+{
+ fformat (stdout, "proxy arp intfc ena/dis reply %d\n", ntohl (mp->retval));
+}
+
+static void vl_api_ip_neighbor_add_del_reply_t_handler
+ (vl_api_ip_neighbor_add_del_reply_t * mp)
+{
+ fformat (stdout, "ip neighbor add del reply %d\n", ntohl (mp->retval));
+}
+
+#if 0
+static void
+vl_api_vnet_interface_counters_t_handler (vl_api_vnet_interface_counters_t *
+ mp)
+{
+ char *counter_name;
+ u32 count, sw_if_index;
+ int i;
+
+ count = ntohl (mp->count);
+ sw_if_index = ntohl (mp->first_sw_if_index);
+ if (mp->is_combined == 0)
+ {
+ u64 *vp, v;
+ vp = (u64 *) mp->data;
+
+ switch (mp->vnet_counter_type)
+ {
+ case VNET_INTERFACE_COUNTER_DROP:
+ counter_name = "drop";
+ break;
+ case VNET_INTERFACE_COUNTER_PUNT:
+ counter_name = "punt";
+ break;
+ case VNET_INTERFACE_COUNTER_IP4:
+ counter_name = "ip4";
+ break;
+ case VNET_INTERFACE_COUNTER_IP6:
+ counter_name = "ip6";
+ break;
+ case VNET_INTERFACE_COUNTER_RX_NO_BUF:
+ counter_name = "rx-no-buf";
+ break;
+ case VNET_INTERFACE_COUNTER_RX_MISS:
+ counter_name = "rx-miss";
+ break;
+ case VNET_INTERFACE_COUNTER_RX_ERROR:
+ counter_name = "rx-error";
+ break;
+ case VNET_INTERFACE_COUNTER_TX_ERROR:
+ counter_name = "tx-error (fifo-full)";
+ break;
+ default:
+ counter_name = "bogus";
+ break;
+ }
+ for (i = 0; i < count; i++)
+ {
+ v = clib_mem_unaligned (vp, u64);
+ v = clib_net_to_host_u64 (v);
+ vp++;
+ fformat (stdout, "%d.%s %lld\n", sw_if_index, counter_name, v);
+ sw_if_index++;
+ }
+ }
+ else
+ {
+ vlib_counter_t *vp;
+ u64 packets, bytes;
+ vp = (vlib_counter_t *) mp->data;
+
+ switch (mp->vnet_counter_type)
+ {
+ case VNET_INTERFACE_COUNTER_RX:
+ counter_name = "rx";
+ break;
+ case VNET_INTERFACE_COUNTER_TX:
+ counter_name = "tx";
+ break;
+ default:
+ counter_name = "bogus";
+ break;
+ }
+ for (i = 0; i < count; i++)
+ {
+ packets = clib_mem_unaligned (&vp->packets, u64);
+ packets = clib_net_to_host_u64 (packets);
+ bytes = clib_mem_unaligned (&vp->bytes, u64);
+ bytes = clib_net_to_host_u64 (bytes);
+ vp++;
+ fformat (stdout, "%d.%s.packets %lld\n",
+ sw_if_index, counter_name, packets);
+ fformat (stdout, "%d.%s.bytes %lld\n",
+ sw_if_index, counter_name, bytes);
+ sw_if_index++;
+ }
+ }
+}
+#endif
+
+/* Format an IP4 address. */
+u8 *
+format_ip4_address (u8 * s, va_list * args)
+{
+ u8 *a = va_arg (*args, u8 *);
+ return format (s, "%d.%d.%d.%d", a[0], a[1], a[2], a[3]);
+}
+
+/* Format an IP4 route destination and length. */
+u8 *
+format_ip4_address_and_length (u8 * s, va_list * args)
+{
+ u8 *a = va_arg (*args, u8 *);
+ u8 l = va_arg (*args, u32);
+ return format (s, "%U/%d", format_ip4_address, a, l);
+}
+
+static void
+vl_api_vnet_ip4_fib_counters_t_handler (vl_api_vnet_ip4_fib_counters_t * mp)
+{
+ int i;
+ vl_api_ip4_fib_counter_t *ctrp;
+ u32 count;
+
+ count = ntohl (mp->count);
+
+ fformat (stdout, "fib id %d, count this msg %d\n",
+ ntohl (mp->vrf_id), count);
+
+ ctrp = mp->c;
+ for (i = 0; i < count; i++)
+ {
+ fformat (stdout, "%U: %lld packets, %lld bytes\n",
+ format_ip4_address_and_length, &ctrp->address,
+ (u32) ctrp->address_length,
+ clib_net_to_host_u64 (ctrp->packets),
+ clib_net_to_host_u64 (ctrp->bytes));
+ ctrp++;
+ }
+}
+
+/* Format an IP6 address. */
+u8 *
+format_ip6_address (u8 * s, va_list * args)
+{
+ ip6_address_t *a = va_arg (*args, ip6_address_t *);
+ u32 i, i_max_n_zero, max_n_zeros, i_first_zero, n_zeros, last_double_colon;
+
+ i_max_n_zero = ARRAY_LEN (a->as_u16);
+ max_n_zeros = 0;
+ i_first_zero = i_max_n_zero;
+ n_zeros = 0;
+ for (i = 0; i < ARRAY_LEN (a->as_u16); i++)
+ {
+ u32 is_zero = a->as_u16[i] == 0;
+ if (is_zero && i_first_zero >= ARRAY_LEN (a->as_u16))
+ {
+ i_first_zero = i;
+ n_zeros = 0;
+ }
+ n_zeros += is_zero;
+ if ((!is_zero && n_zeros > max_n_zeros)
+ || (i + 1 >= ARRAY_LEN (a->as_u16) && n_zeros > max_n_zeros))
+ {
+ i_max_n_zero = i_first_zero;
+ max_n_zeros = n_zeros;
+ i_first_zero = ARRAY_LEN (a->as_u16);
+ n_zeros = 0;
+ }
+ }
+
+ last_double_colon = 0;
+ for (i = 0; i < ARRAY_LEN (a->as_u16); i++)
+ {
+ if (i == i_max_n_zero && max_n_zeros > 1)
+ {
+ s = format (s, "::");
+ i += max_n_zeros - 1;
+ last_double_colon = 1;
+ }
+ else
+ {
+ s = format (s, "%s%x",
+ (last_double_colon || i == 0) ? "" : ":",
+ clib_net_to_host_u16 (a->as_u16[i]));
+ last_double_colon = 0;
+ }
+ }
+
+ return s;
+}
+
+/* Format an IP6 route destination and length. */
+u8 *
+format_ip6_address_and_length (u8 * s, va_list * args)
+{
+ ip6_address_t *a = va_arg (*args, ip6_address_t *);
+ u8 l = va_arg (*args, u32);
+ return format (s, "%U/%d", format_ip6_address, a, l);
+}
+
+static void
+vl_api_vnet_ip6_fib_counters_t_handler (vl_api_vnet_ip6_fib_counters_t * mp)
+{
+ int i;
+ vl_api_ip6_fib_counter_t *ctrp;
+ u32 count;
+
+ count = ntohl (mp->count);
+
+ fformat (stdout, "fib id %d, count this msg %d\n",
+ ntohl (mp->vrf_id), count);
+
+ ctrp = mp->c;
+ for (i = 0; i < count; i++)
+ {
+ fformat (stdout, "%U: %lld packets, %lld bytes\n",
+ format_ip6_address_and_length, &ctrp->address,
+ (u32) ctrp->address_length,
+ clib_net_to_host_u64 (ctrp->packets),
+ clib_net_to_host_u64 (ctrp->bytes));
+ ctrp++;
+ }
+}
+
+static void
+vl_api_oam_event_t_handler (vl_api_oam_event_t * mp)
+{
+ fformat (stdout, "OAM: %U now %s\n",
+ format_ip4_address, &mp->dst_address,
+ mp->state == 1 ? "alive" : "dead");
+}
+
+static void
+vl_api_oam_add_del_reply_t_handler (vl_api_oam_add_del_reply_t * mp)
+{
+ fformat (stdout, "oam add del reply %d\n", ntohl (mp->retval));
+}
+
+static void
+vl_api_reset_fib_reply_t_handler (vl_api_reset_fib_reply_t * mp)
+{
+ fformat (stdout, "fib reset reply %d\n", ntohl (mp->retval));
+}
+
+static void
+vl_api_dhcp_proxy_set_vss_reply_t_handler (vl_api_dhcp_proxy_set_vss_reply_t *
+ mp)
+{
+ fformat (stdout, "dhcp proxy set vss reply %d\n", ntohl (mp->retval));
+}
+
+static void
+vl_api_dhcp_proxy_config_reply_t_handler (vl_api_dhcp_proxy_config_reply_t *
+ mp)
+{
+ fformat (stdout, "dhcp proxy config reply %d\n", ntohl (mp->retval));
+}
+
+static void
+vl_api_set_ip_flow_hash_reply_t_handler (vl_api_set_ip_flow_hash_reply_t * mp)
+{
+ fformat (stdout, "set ip flow hash reply %d\n", ntohl (mp->retval));
+}
+
+static void
+ vl_api_sw_interface_ip6nd_ra_config_reply_t_handler
+ (vl_api_sw_interface_ip6nd_ra_config_reply_t * mp)
+{
+ fformat (stdout, "ip6 nd ra-config reply %d\n", ntohl (mp->retval));
+}
+
+static void
+ vl_api_sw_interface_ip6nd_ra_prefix_reply_t_handler
+ (vl_api_sw_interface_ip6nd_ra_prefix_reply_t * mp)
+{
+ fformat (stdout, "ip6 nd ra-prefix reply %d\n", ntohl (mp->retval));
+}
+
+static void
+ vl_api_sw_interface_ip6_enable_disable_reply_t_handler
+ (vl_api_sw_interface_ip6_enable_disable_reply_t * mp)
+{
+ fformat (stdout, "ip6 enable/disable reply %d\n", ntohl (mp->retval));
+}
+
+static void
+ vl_api_sw_interface_ip6_set_link_local_address_reply_t_handler
+ (vl_api_sw_interface_ip6_set_link_local_address_reply_t * mp)
+{
+ fformat (stdout, "ip6 set link-local address reply %d\n",
+ ntohl (mp->retval));
+}
+
+static void vl_api_create_loopback_reply_t_handler
+ (vl_api_create_loopback_reply_t * mp)
+{
+ fformat (stdout, "create loopback status %d, sw_if_index %d\n",
+ ntohl (mp->retval), ntohl (mp->sw_if_index));
+}
+
+static void vl_api_create_loopback_instance_reply_t_handler
+ (vl_api_create_loopback_instance_reply_t * mp)
+{
+ fformat (stdout, "create loopback status %d, sw_if_index %d\n",
+ ntohl (mp->retval), ntohl (mp->sw_if_index));
+}
+
+static void vl_api_l2_patch_add_del_reply_t_handler
+ (vl_api_l2_patch_add_del_reply_t * mp)
+{
+ fformat (stdout, "l2 patch reply %d\n", ntohl (mp->retval));
+}
+
+static void vl_api_sw_interface_set_l2_xconnect_reply_t_handler
+ (vl_api_sw_interface_set_l2_xconnect_reply_t * mp)
+{
+ fformat (stdout, "l2_xconnect reply %d\n", ntohl (mp->retval));
+}
+
+static void vl_api_sw_interface_set_l2_bridge_reply_t_handler
+ (vl_api_sw_interface_set_l2_bridge_reply_t * mp)
+{
+ fformat (stdout, "l2_bridge reply %d\n", ntohl (mp->retval));
+}
+
+static void
+noop_handler (void *notused)
+{
+}
+
+#define vl_api_vnet_ip4_fib_counters_t_endian noop_handler
+#define vl_api_vnet_ip4_fib_counters_t_print noop_handler
+#define vl_api_vnet_ip6_fib_counters_t_endian noop_handler
+#define vl_api_vnet_ip6_fib_counters_t_print noop_handler
+
+#define foreach_api_msg \
+_(SW_INTERFACE_DETAILS, sw_interface_details) \
+_(SW_INTERFACE_SET_FLAGS, sw_interface_set_flags) \
+_(SW_INTERFACE_SET_FLAGS_REPLY, sw_interface_set_flags_reply) \
+_(WANT_INTERFACE_EVENTS_REPLY, want_interface_events_reply) \
+_(WANT_STATS_REPLY, want_stats_reply) \
+_(WANT_OAM_EVENTS_REPLY, want_oam_events_reply) \
+_(OAM_EVENT, oam_event) \
+_(OAM_ADD_DEL_REPLY, oam_add_del_reply) \
+_(VNET_IP4_FIB_COUNTERS, vnet_ip4_fib_counters) \
+_(VNET_IP6_FIB_COUNTERS, vnet_ip6_fib_counters) \
+_(IP_ADD_DEL_ROUTE_REPLY, ip_add_del_route_reply) \
+_(SW_INTERFACE_ADD_DEL_ADDRESS_REPLY, sw_interface_add_del_address_reply) \
+_(SW_INTERFACE_SET_TABLE_REPLY, sw_interface_set_table_reply) \
+_(TAP_CONNECT_REPLY, tap_connect_reply) \
+_(CREATE_VLAN_SUBIF_REPLY, create_vlan_subif_reply) \
+_(PROXY_ARP_ADD_DEL_REPLY, proxy_arp_add_del_reply) \
+_(PROXY_ARP_INTFC_ENABLE_DISABLE_REPLY, proxy_arp_intfc_enable_disable_reply) \
+_(IP_NEIGHBOR_ADD_DEL_REPLY, ip_neighbor_add_del_reply) \
+_(RESET_FIB_REPLY, reset_fib_reply) \
+_(DHCP_PROXY_CONFIG_REPLY, dhcp_proxy_config_reply) \
+_(DHCP_PROXY_SET_VSS_REPLY, dhcp_proxy_set_vss_reply) \
+_(SET_IP_FLOW_HASH_REPLY, set_ip_flow_hash_reply) \
+_(SW_INTERFACE_IP6ND_RA_CONFIG_REPLY, sw_interface_ip6nd_ra_config_reply) \
+_(SW_INTERFACE_IP6ND_RA_PREFIX_REPLY, sw_interface_ip6nd_ra_prefix_reply) \
+_(SW_INTERFACE_IP6_ENABLE_DISABLE_REPLY, sw_interface_ip6_enable_disable_reply) \
+_(SW_INTERFACE_IP6_SET_LINK_LOCAL_ADDRESS_REPLY, sw_interface_ip6_set_link_local_address_reply) \
+ _(CREATE_LOOPBACK_REPLY, create_loopback_reply) \
+ _(CREATE_LOOPBACK_INSTANCE_REPLY, create_loopback_instance_reply) \
+_(L2_PATCH_ADD_DEL_REPLY, l2_patch_add_del_reply) \
+_(SW_INTERFACE_SET_L2_XCONNECT_REPLY, sw_interface_set_l2_xconnect_reply) \
+_(SW_INTERFACE_SET_L2_BRIDGE_REPLY, sw_interface_set_l2_bridge_reply)
+
+int
+connect_to_vpe (char *name)
+{
+ int rv = 0;
+
+ rv = vl_client_connect_to_vlib ("/vpe-api", name, 32);
+
+#define _(N,n) \
+ vl_msg_api_set_handlers(VL_API_##N, #n, \
+ vl_api_##n##_t_handler, \
+ noop_handler, \
+ vl_api_##n##_t_endian, \
+ vl_api_##n##_t_print, \
+ sizeof(vl_api_##n##_t), 1);
+ foreach_api_msg;
+#undef _
+
+ shmem_hdr = api_main.shmem_hdr;
+
+ return rv;
+}
+
+int
+disconnect_from_vpe (void)
+{
+ vl_client_disconnect_from_vlib ();
+ return 0;
+}
+
+void
+link_up_down_enable_disable (test_main_t * tm, int enable)
+{
+ vl_api_want_interface_events_t *mp;
+
+ /* Request admin / link up down messages */
+ mp = vl_msg_api_alloc (sizeof (*mp));
+ memset (mp, 0, sizeof (*mp));
+ mp->_vl_msg_id = ntohs (VL_API_WANT_INTERFACE_EVENTS);
+ mp->client_index = tm->my_client_index;
+ mp->context = 0xdeadbeef;
+ mp->enable_disable = enable;
+ mp->pid = getpid ();
+ vl_msg_api_send_shmem (tm->vl_input_queue, (u8 *) & mp);
+ tm->link_events_on = enable;
+}
+
+void
+stats_enable_disable (test_main_t * tm, int enable)
+{
+ vl_api_want_stats_t *mp;
+
+ mp = vl_msg_api_alloc (sizeof (*mp));
+ memset (mp, 0, sizeof (*mp));
+ mp->_vl_msg_id = ntohs (VL_API_WANT_STATS);
+ mp->client_index = tm->my_client_index;
+ mp->context = 0xdeadbeef;
+ mp->enable_disable = enable;
+ mp->pid = getpid ();
+ vl_msg_api_send_shmem (tm->vl_input_queue, (u8 *) & mp);
+ tm->stats_on = enable;
+}
+
+void
+oam_events_enable_disable (test_main_t * tm, int enable)
+{
+ vl_api_want_oam_events_t *mp;
+
+ mp = vl_msg_api_alloc (sizeof (*mp));
+ memset (mp, 0, sizeof (*mp));
+ mp->_vl_msg_id = ntohs (VL_API_WANT_OAM_EVENTS);
+ mp->client_index = tm->my_client_index;
+ mp->context = 0xdeadbeef;
+ mp->enable_disable = enable;
+ mp->pid = getpid ();
+ vl_msg_api_send_shmem (tm->vl_input_queue, (u8 *) & mp);
+ tm->oam_events_on = enable;
+}
+
+void
+oam_add_del (test_main_t * tm, int is_add)
+{
+ vl_api_oam_add_del_t *mp;
+ ip4_address_t tmp;
+
+ mp = vl_msg_api_alloc (sizeof (*mp));
+ memset (mp, 0, sizeof (*mp));
+ mp->_vl_msg_id = ntohs (VL_API_OAM_ADD_DEL);
+ mp->client_index = tm->my_client_index;
+ mp->context = 0xdeadbeef;
+ mp->is_add = is_add;
+
+ tmp.as_u32 = ntohl (0xc0a80101); /* 192.168.1.1 */
+ clib_memcpy (mp->src_address, tmp.as_u8, 4);
+
+ tmp.as_u32 = ntohl (0xc0a80103); /* 192.168.1.3 */
+ clib_memcpy (mp->dst_address, tmp.as_u8, 4);
+
+ mp->vrf_id = 0;
+ vl_msg_api_send_shmem (tm->vl_input_queue, (u8 *) & mp);
+}
+
+void
+dump (test_main_t * tm)
+{
+ vl_api_sw_interface_dump_t *mp;
+
+ mp = vl_msg_api_alloc (sizeof (*mp));
+ memset (mp, 0, sizeof (*mp));
+ mp->_vl_msg_id = ntohs (VL_API_SW_INTERFACE_DUMP);
+ mp->client_index = tm->my_client_index;
+ mp->name_filter_valid = 1;
+ strncpy ((char *) mp->name_filter, "eth", sizeof (mp->name_filter) - 1);
+
+ vl_msg_api_send_shmem (tm->vl_input_queue, (u8 *) & mp);
+}
+
+void
+add_del_ip4_route (test_main_t * tm, int enable_disable)
+{
+ vl_api_ip_add_del_route_t *mp;
+ u32 tmp;
+
+ mp = vl_msg_api_alloc (sizeof (*mp));
+ memset (mp, 0, sizeof (*mp));
+ mp->_vl_msg_id = ntohs (VL_API_IP_ADD_DEL_ROUTE);
+ mp->client_index = tm->my_client_index;
+ mp->context = 0xdeadbeef;
+ mp->table_id = ntohl (0);
+ mp->create_vrf_if_needed = 1;
+
+ mp->next_hop_sw_if_index = ntohl (5);
+ mp->is_add = enable_disable;
+ mp->next_hop_weight = 1;
+
+ /* Next hop: 6.0.0.1 */
+ tmp = ntohl (0x06000001);
+ clib_memcpy (mp->next_hop_address, &tmp, sizeof (tmp));
+
+ /* Destination: 10.0.0.1/32 */
+ tmp = ntohl (0x0);
+ clib_memcpy (mp->dst_address, &tmp, sizeof (tmp));
+ mp->dst_address_length = 0;
+
+ vl_msg_api_send_shmem (tm->vl_input_queue, (u8 *) & mp);
+}
+
+void
+add_del_ip6_route (test_main_t * tm, int enable_disable)
+{
+ vl_api_ip_add_del_route_t *mp;
+ u64 tmp[2];
+
+ mp = vl_msg_api_alloc (sizeof (*mp));
+ memset (mp, 0, sizeof (*mp));
+ mp->_vl_msg_id = ntohs (VL_API_IP_ADD_DEL_ROUTE);
+ mp->client_index = tm->my_client_index;
+ mp->context = 0xdeadbeef;
+ mp->next_hop_sw_if_index = ntohl (5);
+ mp->is_add = enable_disable;
+ mp->is_ipv6 = 1;
+ mp->next_hop_weight = 1;
+ mp->dst_address_length = 64;
+
+ /* add/del dabe::/64 via db01::11 */
+
+ tmp[0] = clib_host_to_net_u64 (0xdabe000000000000ULL);
+ tmp[1] = clib_host_to_net_u64 (0x0ULL);
+ clib_memcpy (mp->dst_address, &tmp[0], 8);
+ clib_memcpy (&mp->dst_address[8], &tmp[1], 8);
+
+ tmp[0] = clib_host_to_net_u64 (0xdb01000000000000ULL);
+ tmp[1] = clib_host_to_net_u64 (0x11ULL);
+ clib_memcpy (mp->next_hop_address, &tmp[0], 8);
+ clib_memcpy (&mp->next_hop_address[8], &tmp[1], 8);
+
+ vl_msg_api_send_shmem (tm->vl_input_queue, (u8 *) & mp);
+}
+
+void
+add_del_interface_address (test_main_t * tm, int enable_disable)
+{
+ vl_api_sw_interface_add_del_address_t *mp;
+ u32 tmp;
+
+ mp = vl_msg_api_alloc (sizeof (*mp));
+ memset (mp, 0, sizeof (*mp));
+ mp->_vl_msg_id = ntohs (VL_API_SW_INTERFACE_ADD_DEL_ADDRESS);
+ mp->client_index = tm->my_client_index;
+ mp->context = 0xdeadbeef;
+ mp->sw_if_index = ntohl (5);
+ mp->is_add = enable_disable;
+ mp->address_length = 8;
+
+ tmp = ntohl (0x01020304);
+ clib_memcpy (mp->address, &tmp, 4);
+
+ vl_msg_api_send_shmem (tm->vl_input_queue, (u8 *) & mp);
+}
+
+void
+add_del_v6_interface_address (test_main_t * tm, int enable_disable)
+{
+ vl_api_sw_interface_add_del_address_t *mp;
+ u64 tmp[2];
+
+ mp = vl_msg_api_alloc (sizeof (*mp));
+ memset (mp, 0, sizeof (*mp));
+ mp->_vl_msg_id = ntohs (VL_API_SW_INTERFACE_ADD_DEL_ADDRESS);
+ mp->client_index = tm->my_client_index;
+ mp->context = 0xdeadbeef;
+ mp->is_ipv6 = 1;
+ mp->sw_if_index = ntohl (5);
+ mp->is_add = enable_disable;
+ mp->address_length = 64;
+
+ tmp[0] = clib_host_to_net_u64 (0xdb01000000000000ULL);
+ tmp[1] = clib_host_to_net_u64 (0x11ULL);
+
+ clib_memcpy (mp->address, &tmp[0], 8);
+ clib_memcpy (&mp->address[8], &tmp[1], 8);
+
+ vl_msg_api_send_shmem (tm->vl_input_queue, (u8 *) & mp);
+}
+
+void
+del_all_interface_addresses (test_main_t * tm)
+{
+ vl_api_sw_interface_add_del_address_t *mp;
+
+ mp = vl_msg_api_alloc (sizeof (*mp));
+ memset (mp, 0, sizeof (*mp));
+ mp->_vl_msg_id = ntohs (VL_API_SW_INTERFACE_ADD_DEL_ADDRESS);
+ mp->client_index = tm->my_client_index;
+ mp->context = 0xdeadbeef;
+ mp->sw_if_index = ntohl (5);
+ mp->del_all = 1;
+
+ vl_msg_api_send_shmem (tm->vl_input_queue, (u8 *) & mp);
+}
+
+void
+set_interface_table (test_main_t * tm, int is_ipv6, u32 vrf_id)
+{
+ vl_api_sw_interface_set_table_t *mp;
+
+ mp = vl_msg_api_alloc (sizeof (*mp));
+ memset (mp, 0, sizeof (*mp));
+ mp->_vl_msg_id = ntohs (VL_API_SW_INTERFACE_SET_TABLE);
+ mp->client_index = tm->my_client_index;
+ mp->context = 0xdeadbeef;
+ mp->sw_if_index = ntohl (5);
+ mp->is_ipv6 = is_ipv6;
+ mp->vrf_id = ntohl (vrf_id);
+
+ vl_msg_api_send_shmem (tm->vl_input_queue, (u8 *) & mp);
+}
+
+void
+connect_unix_tap (test_main_t * tm, char *name)
+{
+ vl_api_tap_connect_t *mp;
+
+ mp = vl_msg_api_alloc (sizeof (*mp));
+ memset (mp, 0, sizeof (*mp));
+ mp->_vl_msg_id = ntohs (VL_API_TAP_CONNECT);
+ mp->client_index = tm->my_client_index;
+ mp->context = 0xdeadbeef;
+ strncpy ((char *) mp->tap_name, name, sizeof (mp->tap_name) - 1);
+ mp->use_random_mac = 1;
+ vl_msg_api_send_shmem (tm->vl_input_queue, (u8 *) & mp);
+}
+
+void
+create_vlan_subif (test_main_t * tm, u32 vlan_id)
+{
+ vl_api_create_vlan_subif_t *mp;
+
+ mp = vl_msg_api_alloc (sizeof (*mp));
+ memset (mp, 0, sizeof (*mp));
+ mp->_vl_msg_id = ntohs (VL_API_CREATE_VLAN_SUBIF);
+ mp->client_index = tm->my_client_index;
+ mp->context = 0xdeadbeef;
+ mp->sw_if_index = ntohl (5);
+ mp->vlan_id = ntohl (vlan_id);
+
+ vl_msg_api_send_shmem (tm->vl_input_queue, (u8 *) & mp);
+}
+
+void
+add_del_proxy_arp (test_main_t * tm, int is_add)
+{
+ vl_api_proxy_arp_add_del_t *mp;
+ u32 tmp;
+
+ mp = vl_msg_api_alloc (sizeof (*mp));
+ memset (mp, 0, sizeof (*mp));
+ mp->_vl_msg_id = ntohs (VL_API_PROXY_ARP_ADD_DEL);
+ mp->client_index = tm->my_client_index;
+ mp->context = 0xdeadbeef;
+ mp->vrf_id = ntohl (11);
+ mp->is_add = is_add;
+
+ /* proxy fib 11, 1.1.1.1 -> 1.1.1.10 */
+ tmp = ntohl (0x01010101);
+ clib_memcpy (mp->low_address, &tmp, 4);
+
+ tmp = ntohl (0x0101010a);
+ clib_memcpy (mp->hi_address, &tmp, 4);
+
+ vl_msg_api_send_shmem (tm->vl_input_queue, (u8 *) & mp);
+}
+
+void
+proxy_arp_intfc_enable_disable (test_main_t * tm, int enable_disable)
+{
+ vl_api_proxy_arp_intfc_enable_disable_t *mp;
+
+ mp = vl_msg_api_alloc (sizeof (*mp));
+ memset (mp, 0, sizeof (*mp));
+ mp->_vl_msg_id = ntohs (VL_API_PROXY_ARP_INTFC_ENABLE_DISABLE);
+ mp->client_index = tm->my_client_index;
+ mp->context = 0xdeadbeef;
+ mp->sw_if_index = ntohl (6);
+ mp->enable_disable = enable_disable;
+
+ vl_msg_api_send_shmem (tm->vl_input_queue, (u8 *) & mp);
+}
+
+void
+add_ip4_neighbor (test_main_t * tm, int add_del)
+{
+ vl_api_ip_neighbor_add_del_t *mp;
+ u32 tmp;
+
+ mp = vl_msg_api_alloc (sizeof (*mp));
+ memset (mp, 0, sizeof (*mp));
+ mp->_vl_msg_id = ntohs (VL_API_IP_NEIGHBOR_ADD_DEL);
+ mp->client_index = tm->my_client_index;
+ mp->context = 0xdeadbeef;
+ mp->sw_if_index = ntohl (6);
+ mp->is_add = add_del;
+
+ memset (mp->mac_address, 0xbe, sizeof (mp->mac_address));
+
+ tmp = ntohl (0x0101010a);
+ clib_memcpy (mp->dst_address, &tmp, 4);
+
+ vl_msg_api_send_shmem (tm->vl_input_queue, (u8 *) & mp);
+}
+
+void
+add_ip6_neighbor (test_main_t * tm, int add_del)
+{
+ vl_api_ip_neighbor_add_del_t *mp;
+ u64 tmp[2];
+
+ mp = vl_msg_api_alloc (sizeof (*mp));
+ memset (mp, 0, sizeof (*mp));
+ mp->_vl_msg_id = ntohs (VL_API_IP_NEIGHBOR_ADD_DEL);
+ mp->client_index = tm->my_client_index;
+ mp->context = 0xdeadbeef;
+ mp->sw_if_index = ntohl (6);
+ mp->is_add = add_del;
+ mp->is_ipv6 = 1;
+
+ memset (mp->mac_address, 0xbe, sizeof (mp->mac_address));
+
+ tmp[0] = clib_host_to_net_u64 (0xdb01000000000000ULL);
+ tmp[1] = clib_host_to_net_u64 (0x11ULL);
+
+ clib_memcpy (mp->dst_address, &tmp[0], 8);
+ clib_memcpy (&mp->dst_address[8], &tmp[1], 8);
+
+ vl_msg_api_send_shmem (tm->vl_input_queue, (u8 *) & mp);
+}
+
+void
+reset_fib (test_main_t * tm, u8 is_ip6)
+{
+ vl_api_reset_fib_t *mp;
+
+ mp = vl_msg_api_alloc (sizeof (*mp));
+ memset (mp, 0, sizeof (*mp));
+ mp->_vl_msg_id = ntohs (VL_API_RESET_FIB);
+ mp->client_index = tm->my_client_index;
+ mp->context = 0xdeadbeef;
+ mp->vrf_id = ntohl (11);
+ mp->is_ipv6 = is_ip6;
+
+ vl_msg_api_send_shmem (tm->vl_input_queue, (u8 *) & mp);
+}
+
+void
+dhcpv6_set_vss (test_main_t * tm)
+{
+ vl_api_dhcp_proxy_set_vss_t *mp;
+
+ mp = vl_msg_api_alloc (sizeof (*mp));
+ memset (mp, 0, sizeof (*mp));
+ mp->_vl_msg_id = ntohs (VL_API_DHCP_PROXY_SET_VSS);
+ mp->client_index = tm->my_client_index;
+ mp->context = 0xdeadbeef;
+ mp->oui = ntohl (6);
+ mp->fib_id = ntohl (60);
+ mp->is_add = 1;
+ mp->is_ipv6 = 1;
+ vl_msg_api_send_shmem (tm->vl_input_queue, (u8 *) & mp);
+}
+
+void
+dhcpv4_set_vss (test_main_t * tm)
+{
+ vl_api_dhcp_proxy_set_vss_t *mp;
+
+ mp = vl_msg_api_alloc (sizeof (*mp));
+ memset (mp, 0, sizeof (*mp));
+ mp->_vl_msg_id = ntohs (VL_API_DHCP_PROXY_SET_VSS);
+ mp->client_index = tm->my_client_index;
+ mp->context = 0xdeadbeef;
+ mp->oui = ntohl (4);
+ mp->fib_id = ntohl (40);
+ mp->is_add = 1;
+ mp->is_ipv6 = 0;
+ vl_msg_api_send_shmem (tm->vl_input_queue, (u8 *) & mp);
+}
+
+void
+dhcp_set_vss (test_main_t * tm)
+{
+ dhcpv4_set_vss (tm);
+ dhcpv6_set_vss (tm);
+}
+
+void
+dhcp_set_proxy (test_main_t * tm, int ipv6)
+{
+ vl_api_dhcp_proxy_config_t *mp;
+
+ mp = vl_msg_api_alloc (sizeof (*mp));
+ memset (mp, 0, sizeof (*mp));
+ mp->_vl_msg_id = ntohs (VL_API_DHCP_PROXY_CONFIG);
+ mp->client_index = tm->my_client_index;
+ mp->context = 0xdeadbeef;
+ mp->is_ipv6 = ipv6;
+ mp->is_add = 1;
+ mp->dhcp_server[0] = 0x20;
+ mp->dhcp_server[1] = 0x01;
+ mp->dhcp_server[2] = 0xab;
+ mp->dhcp_server[3] = 0xcd;
+ mp->dhcp_server[4] = 0x12;
+ mp->dhcp_server[5] = 0x34;
+ mp->dhcp_server[6] = 0xfe;
+ mp->dhcp_server[7] = 0xdc;
+ mp->dhcp_server[14] = 0;
+ mp->dhcp_server[15] = 0x2;
+
+ mp->dhcp_src_address[0] = 0x20;
+ mp->dhcp_src_address[1] = 0x01;
+ mp->dhcp_src_address[2] = 0xab;
+ mp->dhcp_src_address[3] = 0xcd;
+ mp->dhcp_src_address[4] = 0x12;
+ mp->dhcp_src_address[5] = 0x34;
+ mp->dhcp_src_address[6] = 0x56;
+ mp->dhcp_src_address[7] = 0x78;
+ mp->dhcp_src_address[14] = 0;
+ mp->dhcp_src_address[15] = 0x2;
+
+ vl_msg_api_send_shmem (tm->vl_input_queue, (u8 *) & mp);
+}
+
+void
+set_ip_flow_hash (test_main_t * tm, u8 is_ip6)
+{
+ vl_api_set_ip_flow_hash_t *mp;
+
+ mp = vl_msg_api_alloc (sizeof (*mp));
+ memset (mp, 0, sizeof (*mp));
+ mp->_vl_msg_id = ntohs (VL_API_SET_IP_FLOW_HASH);
+ mp->client_index = tm->my_client_index;
+ mp->context = 0xdeadbeef;
+ mp->vrf_id = 0;
+ mp->is_ipv6 = is_ip6;
+ mp->dst = 1;
+ mp->reverse = 1;
+
+ vl_msg_api_send_shmem (tm->vl_input_queue, (u8 *) & mp);
+}
+
+void
+ip6nd_ra_config (test_main_t * tm, int is_no)
+{
+ vl_api_sw_interface_ip6nd_ra_config_t *mp;
+
+ mp = vl_msg_api_alloc (sizeof (*mp));
+ memset (mp, 0, sizeof (*mp));
+
+ mp->client_index = tm->my_client_index;
+ mp->context = 0xdeadbeef;
+ mp->sw_if_index = ntohl (5);
+ mp->is_no = is_no;
+
+ mp->suppress = 1;
+
+
+ mp->_vl_msg_id = ntohs (VL_API_SW_INTERFACE_IP6ND_RA_CONFIG);
+ vl_msg_api_send_shmem (tm->vl_input_queue, (u8 *) & mp);
+}
+
+void
+ip6nd_ra_prefix (test_main_t * tm, int is_no)
+{
+ vl_api_sw_interface_ip6nd_ra_prefix_t *mp;
+ u64 tmp[2];
+
+ mp = vl_msg_api_alloc (sizeof (*mp));
+ memset (mp, 0, sizeof (*mp));
+
+ mp->client_index = tm->my_client_index;
+ mp->context = 0xdeadbeef;
+ mp->sw_if_index = ntohl (5);
+ mp->is_no = is_no;
+
+ mp->use_default = 1;
+
+
+ tmp[0] = clib_host_to_net_u64 (0xdb01000000000000ULL);
+ tmp[1] = clib_host_to_net_u64 (0x11ULL);
+
+
+ clib_memcpy (mp->address, &tmp[0], 8);
+ clib_memcpy (&mp->address[8], &tmp[1], 8);
+
+ mp->address_length = 64;
+
+
+ mp->_vl_msg_id = ntohs (VL_API_SW_INTERFACE_IP6ND_RA_PREFIX);
+ vl_msg_api_send_shmem (tm->vl_input_queue, (u8 *) & mp);
+}
+
+void
+ip6_enable_disable (test_main_t * tm, int enable)
+{
+ vl_api_sw_interface_ip6_enable_disable_t *mp;
+
+ mp = vl_msg_api_alloc (sizeof (*mp));
+ memset (mp, 0, sizeof (*mp));
+
+ mp->client_index = tm->my_client_index;
+ mp->context = 0xdeadbeef;
+ mp->sw_if_index = ntohl (5);
+ mp->enable = (enable == 1);;
+
+ mp->_vl_msg_id = ntohs (VL_API_SW_INTERFACE_IP6_ENABLE_DISABLE);
+ vl_msg_api_send_shmem (tm->vl_input_queue, (u8 *) & mp);
+}
+
+void
+loop_create (test_main_t * tm)
+{
+ vl_api_create_loopback_t *mp;
+
+ mp = vl_msg_api_alloc (sizeof (*mp));
+ memset (mp, 0, sizeof (*mp));
+
+ mp->_vl_msg_id = ntohs (VL_API_CREATE_LOOPBACK);
+ mp->client_index = tm->my_client_index;
+ mp->context = 0xdeadbeef;
+ vl_msg_api_send_shmem (tm->vl_input_queue, (u8 *) & mp);
+}
+
+void
+ip6_set_link_local_address (test_main_t * tm)
+{
+ vl_api_sw_interface_ip6_set_link_local_address_t *mp;
+ u64 tmp[2];
+
+ mp = vl_msg_api_alloc (sizeof (*mp));
+ memset (mp, 0, sizeof (*mp));
+
+ mp->client_index = tm->my_client_index;
+ mp->context = 0xdeadbeef;
+ mp->sw_if_index = ntohl (5);
+
+ tmp[0] = clib_host_to_net_u64 (0xfe80000000000000ULL);
+ tmp[1] = clib_host_to_net_u64 (0x11ULL);
+
+ clib_memcpy (mp->address, &tmp[0], 8);
+ clib_memcpy (&mp->address[8], &tmp[1], 8);
+
+ mp->_vl_msg_id = ntohs (VL_API_SW_INTERFACE_IP6_SET_LINK_LOCAL_ADDRESS);
+
+ vl_msg_api_send_shmem (tm->vl_input_queue, (u8 *) & mp);
+}
+
+
+void
+set_flags (test_main_t * tm, int up_down)
+{
+ vl_api_sw_interface_set_flags_t *mp;
+
+ mp = vl_msg_api_alloc (sizeof (*mp));
+ memset (mp, 0, sizeof (*mp));
+
+ mp->_vl_msg_id = ntohs (VL_API_SW_INTERFACE_SET_FLAGS);
+ mp->client_index = tm->my_client_index;
+ mp->context = 0xdeadbeef;
+ mp->sw_if_index = ntohl (5);
+ mp->admin_up_down = up_down;
+ vl_msg_api_send_shmem (tm->vl_input_queue, (u8 *) & mp);
+
+}
+
+void
+l2_patch_add_del (test_main_t * tm, int is_add)
+{
+ vl_api_l2_patch_add_del_t *mp;
+
+ mp = vl_msg_api_alloc (sizeof (*mp));
+ memset (mp, 0, sizeof (*mp));
+ mp->_vl_msg_id = ntohs (VL_API_L2_PATCH_ADD_DEL);
+ mp->client_index = tm->my_client_index;
+ mp->context = 0xdeadbeef;
+ mp->is_add = is_add;
+ mp->rx_sw_if_index = ntohl (1);
+ mp->tx_sw_if_index = ntohl (2);
+
+ vl_msg_api_send_shmem (tm->vl_input_queue, (u8 *) & mp);
+}
+
+void
+l2_xconnect (test_main_t * tm)
+{
+ vl_api_sw_interface_set_l2_xconnect_t *mp;
+
+ mp = vl_msg_api_alloc (sizeof (*mp));
+ memset (mp, 0, sizeof (*mp));
+ mp->_vl_msg_id = ntohs (VL_API_SW_INTERFACE_SET_L2_XCONNECT);
+ mp->client_index = tm->my_client_index;
+ mp->context = 0xdeadbeef;
+ mp->rx_sw_if_index = ntohl (5);
+ mp->tx_sw_if_index = ntohl (6);
+ mp->enable = 1;
+
+ vl_msg_api_send_shmem (tm->vl_input_queue, (u8 *) & mp);
+}
+
+void
+l2_bridge (test_main_t * tm)
+{
+ vl_api_sw_interface_set_l2_bridge_t *mp;
+
+ mp = vl_msg_api_alloc (sizeof (*mp));
+ memset (mp, 0, sizeof (*mp));
+ mp->_vl_msg_id = ntohs (VL_API_SW_INTERFACE_SET_L2_BRIDGE);
+ mp->client_index = tm->my_client_index;
+ mp->context = 0xdeadbeef;
+ mp->rx_sw_if_index = ntohl (5);
+ mp->bd_id = ntohl (6);
+ mp->bvi = ntohl (1);
+ mp->shg = ntohl (0);
+ mp->enable = 1;
+
+ vl_msg_api_send_shmem (tm->vl_input_queue, (u8 *) & mp);
+}
+
+int
+main (int argc, char **argv)
+{
+ api_main_t *am = &api_main;
+ test_main_t *tm = &test_main;
+ int ch;
+
+ connect_to_vpe ("test_client");
+
+ tm->vl_input_queue = shmem_hdr->vl_input_queue;
+ tm->my_client_index = am->my_client_index;
+
+ fformat (stdout, "Type 'h' for help, 'q' to quit...\n");
+
+ while (1)
+ {
+ ch = getchar ();
+ switch (ch)
+ {
+ case 'q':
+ goto done;
+ case 'd':
+ dump (tm);
+ break;
+ case 'L':
+ link_up_down_enable_disable (tm, 1 /* enable_disable */ );
+ break;
+ case 'l':
+ link_up_down_enable_disable (tm, 0 /* enable_disable */ );
+ break;
+ case 'S':
+ stats_enable_disable (tm, 1 /* enable_disable */ );
+ break;
+ case 's':
+ stats_enable_disable (tm, 0 /* enable_disable */ );
+ break;
+ case '3':
+ add_del_ip4_route (tm, 0 /* add */ );
+ break;
+ case '4':
+ add_del_ip4_route (tm, 1 /* add */ );
+ break;
+ case '5':
+ add_del_ip6_route (tm, 0 /* add */ );
+ break;
+ case '6':
+ add_del_ip6_route (tm, 1 /* add */ );
+ break;
+ case 'A':
+ add_del_interface_address (tm, 1 /* add */ );
+ break;
+ case 'a':
+ add_del_interface_address (tm, 0 /* add */ );
+ break;
+ case 'B':
+ add_del_v6_interface_address (tm, 1 /* add */ );
+ break;
+ case 'b':
+ add_del_v6_interface_address (tm, 0 /* add */ );
+ break;
+ case 'E':
+ l2_patch_add_del (tm, 1 /* is_add */ );
+ break;
+ case 'e':
+ l2_patch_add_del (tm, 0 /* is_add */ );
+ break;
+ case 'z':
+ del_all_interface_addresses (tm);
+ break;
+ case 't':
+ set_interface_table (tm, 0 /* is_ipv6 */ ,
+ 11 /* my amp goes to 11 */ );
+ break;
+ case 'T':
+ set_interface_table (tm, 1 /* is_ipv6 */ ,
+ 12 /* my amp goes to 12 */ );
+ break;
+
+ case 'u':
+ create_vlan_subif (tm, 123);
+ break;
+
+ case 'c':
+ connect_unix_tap (tm, "foo");
+ break;
+
+ case 'n':
+ add_ip4_neighbor (tm, 1 /* is_add */ );
+ add_ip6_neighbor (tm, 1 /* is_add */ );
+ break;
+
+ case 'N':
+ add_ip4_neighbor (tm, 0 /* is_add */ );
+ add_ip6_neighbor (tm, 0 /* is_add */ );
+ break;
+
+ case 'p':
+ add_del_proxy_arp (tm, 1 /* add */ );
+ break;
+
+ case 'i':
+ proxy_arp_intfc_enable_disable (tm, 1 /* enable */ );
+ break;
+
+ case 'O':
+ oam_events_enable_disable (tm, 0 /* enable */ );
+ break;
+
+ case 'o':
+ oam_events_enable_disable (tm, 1 /* enable */ );
+ break;
+
+ case '0':
+ oam_add_del (tm, 0 /* is_add */ );
+ break;
+
+ case '1':
+ oam_add_del (tm, 1 /* is_add */ );
+ break;
+
+ case 'r':
+ reset_fib (tm, 0 /* is_ip6 */ );
+ break;
+
+ case 'R':
+ reset_fib (tm, 1 /* is_ip6 */ );
+ break;
+
+ case 'j':
+ dhcp_set_vss (tm);
+ break;
+
+ case 'k':
+ dhcp_set_proxy (tm, 0);
+ break;
+
+ case 'K':
+ dhcp_set_proxy (tm, 1 /*ipv6 */ );
+ break;
+
+ case 'v':
+ set_ip_flow_hash (tm, 0 /* is_ip6 */ );
+ break;
+
+ case 'V':
+ ip6_set_link_local_address (tm);
+ break;
+
+ case 'w':
+ ip6_enable_disable (tm, 1 /* enable */ );
+ break;
+
+ case 'W':
+ ip6_enable_disable (tm, 0 /* disable */ );
+ break;
+
+ case 'x':
+ ip6nd_ra_config (tm, 0 /* is_no */ );
+ break;
+ case 'X':
+ ip6nd_ra_config (tm, 1 /* is_no */ );
+ break;
+ case 'y':
+ ip6nd_ra_prefix (tm, 0 /* is_no */ );
+ break;
+ case 'Y':
+ ip6nd_ra_prefix (tm, 1 /* is_no */ );
+ break;
+
+ case '7':
+ loop_create (tm);
+ break;
+
+ case 'F':
+ set_flags (tm, 1 /* up_down */ );
+ break;
+
+ case 'f':
+ set_flags (tm, 0 /* up_down */ );
+ break;
+
+ case '@':
+ l2_xconnect (tm);
+ break;
+
+ case '#':
+ l2_bridge (tm);
+ break;
+
+ case 'h':
+ fformat (stdout, "q=quit,d=dump,L=link evts on,l=link evts off\n");
+ fformat (stdout, "S=stats on,s=stats off\n");
+ fformat (stdout, "4=add v4 route, 3=del v4 route\n");
+ fformat (stdout, "6=add v6 route, 5=del v6 route\n");
+ fformat (stdout, "A=add v4 intfc route, a=del v4 intfc route\n");
+ fformat (stdout, "B=add v6 intfc route, b=del v6 intfc route\n");
+ fformat (stdout, "z=del all intfc routes\n");
+ fformat (stdout, "t=set v4 intfc table, T=set v6 intfc table\n");
+ fformat (stdout, "c=connect unix tap\n");
+ fformat (stdout,
+ "j=set dhcpv4 and v6 link-address/option-82 params\n");
+ fformat (stdout, "k=set dhcpv4 relay agent params\n");
+ fformat (stdout, "K=set dhcpv6 relay agent params\n");
+ fformat (stdout, "E=add l2 patch, e=del l2 patch\n");
+ fformat (stdout, "V=ip6 set link-local address \n");
+ fformat (stdout, "w=ip6 enable \n");
+ fformat (stdout, "W=ip6 disable \n");
+ fformat (stdout, "x=ip6 nd config \n");
+ fformat (stdout, "X=no ip6 nd config\n");
+ fformat (stdout, "y=ip6 nd prefix \n");
+ fformat (stdout, "Y=no ip6 nd prefix\n");
+ fformat (stdout, "@=l2 xconnect\n");
+ fformat (stdout, "#=l2 bridge\n");
+
+ default:
+ break;
+ }
+
+ }
+
+done:
+
+ if (tm->link_events_on)
+ link_up_down_enable_disable (tm, 0 /* enable */ );
+ if (tm->stats_on)
+ stats_enable_disable (tm, 0 /* enable */ );
+ if (tm->oam_events_on)
+ oam_events_enable_disable (tm, 0 /* enable */ );
+
+ disconnect_from_vpe ();
+ exit (0);
+}
+
+#undef vl_api_version
+#define vl_api_version(n,v) static u32 vpe_api_version = v;
+#include <vpp/api/vpe.api.h>
+#undef vl_api_version
+
+void
+vl_client_add_api_signatures (vl_api_memclnt_create_t * mp)
+{
+ /*
+ * Send the main API signature in slot 0. This bit of code must
+ * match the checks in ../vpe/api/api.c: vl_msg_api_version_check().
+ */
+ mp->api_versions[0] = clib_host_to_net_u32 (vpe_api_version);
+}
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/src/vpp/api/test_ha.c b/src/vpp/api/test_ha.c
new file mode 100644
index 00000000..3264d5f9
--- /dev/null
+++ b/src/vpp/api/test_ha.c
@@ -0,0 +1,249 @@
+/*
+ *------------------------------------------------------------------
+ * api.c - message handler registration
+ *
+ * Copyright (c) 2010 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.
+ *------------------------------------------------------------------
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <signal.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <time.h>
+#include <fcntl.h>
+#include <string.h>
+#include <vppinfra/clib.h>
+#include <vppinfra/vec.h>
+#include <vppinfra/hash.h>
+#include <vppinfra/bitmap.h>
+#include <vppinfra/fifo.h>
+#include <vppinfra/time.h>
+#include <vppinfra/mheap.h>
+#include <vppinfra/heap.h>
+#include <vppinfra/pool.h>
+#include <vppinfra/format.h>
+#include <vppinfra/error.h>
+
+#include <vnet/vnet.h>
+#include <vlib/vlib.h>
+#include <vlib/unix/unix.h>
+#include <vlibapi/api.h>
+#include <vlibmemory/api.h>
+#include <svm/svm.h>
+#include <svm/svmdb.h>
+
+#include <vpp/api/vpe_msg_enum.h>
+
+#include <vnet/ip/ip.h>
+
+#define f64_endian(a)
+#define f64_print(a,b)
+
+#define vl_typedefs /* define message structures */
+#include <vpp/api/vpe_all_api_h.h>
+#undef vl_typedefs
+
+#define vl_endianfun /* define message structures */
+#include <vpp/api/vpe_all_api_h.h>
+#undef vl_endianfun
+
+/* instantiate all the print functions we know about */
+#define vl_print(handle, ...)
+#define vl_printfun
+#include <vpp/api/vpe_all_api_h.h>
+#undef vl_printfun
+
+vl_shmem_hdr_t *shmem_hdr;
+
+typedef struct
+{
+ u32 pings_sent;
+ u32 pings_replied;
+ volatile u32 signal_received;
+
+ /* convenience */
+ unix_shared_memory_queue_t *vl_input_queue;
+ u32 my_client_index;
+ svmdb_client_t *svmdb_client;
+} test_main_t;
+
+test_main_t test_main;
+
+static void vl_api_control_ping_reply_t_handler
+ (vl_api_control_ping_reply_t * mp)
+{
+ test_main_t *tm = &test_main;
+
+ fformat (stdout, "control ping reply from pid %d\n", ntohl (mp->vpe_pid));
+ tm->pings_replied++;
+}
+
+vlib_main_t vlib_global_main;
+vlib_main_t **vlib_mains;
+
+void
+vlib_cli_output (struct vlib_main_t *vm, char *fmt, ...)
+{
+ clib_warning ("BUG: vlib_cli_output callled...");
+}
+
+#define foreach_api_msg \
+_(CONTROL_PING_REPLY,control_ping_reply)
+
+void
+ping (test_main_t * tm)
+{
+ vl_api_control_ping_t *mp;
+
+ mp = vl_msg_api_alloc (sizeof (*mp));
+ memset (mp, 0, sizeof (*mp));
+ mp->_vl_msg_id = ntohs (VL_API_CONTROL_PING);
+ mp->client_index = tm->my_client_index;
+ mp->context = 0xdeadbeef;
+
+ vl_msg_api_send_shmem (tm->vl_input_queue, (u8 *) & mp);
+}
+
+static void
+noop_handler (void *notused)
+{
+}
+
+int
+connect_to_vpe (char *name)
+{
+ int rv = 0;
+ test_main_t *tm = &test_main;
+ api_main_t *am = &api_main;
+
+ rv = vl_client_connect_to_vlib ("/vpe-api", name, 32);
+ if (rv < 0)
+ return rv;
+
+#define _(N,n) \
+ vl_msg_api_set_handlers(VL_API_##N, #n, \
+ vl_api_##n##_t_handler, \
+ noop_handler, \
+ vl_api_##n##_t_endian, \
+ vl_api_##n##_t_print, \
+ sizeof(vl_api_##n##_t), 1);
+ foreach_api_msg;
+#undef _
+
+ shmem_hdr = api_main.shmem_hdr;
+ tm->vl_input_queue = shmem_hdr->vl_input_queue;
+ tm->my_client_index = am->my_client_index;
+ return 0;
+}
+
+int
+disconnect_from_vpe (void)
+{
+ vl_client_disconnect_from_vlib ();
+
+ return 0;
+}
+
+void
+signal_handler (int signo)
+{
+ test_main_t *tm = &test_main;
+
+ tm->signal_received = 1;
+}
+
+
+int
+main (int argc, char **argv)
+{
+ test_main_t *tm = &test_main;
+ api_main_t *am = &api_main;
+ u32 swt_pid = 0;
+ int connected = 0;
+
+ signal (SIGINT, signal_handler);
+
+ while (1)
+ {
+ if (tm->signal_received)
+ break;
+
+ if (am->shmem_hdr)
+ swt_pid = am->shmem_hdr->vl_pid;
+
+ /* If kill returns 0, the vpe-f process is alive */
+ if (kill (swt_pid, 0) == 0)
+ {
+ /* Try to connect */
+ if (connected == 0)
+ {
+ fformat (stdout, "Connect to VPE-f\n");
+ if (connect_to_vpe ("test_ha_client") >= 0)
+ {
+ tm->pings_sent = 0;
+ tm->pings_replied = 0;
+ connected = 1;
+ }
+ else
+ {
+ fformat (stdout, "Connect failed, sleep and retry...\n");
+ sleep (1);
+ continue;
+ }
+ }
+ tm->pings_sent++;
+ ping (tm);
+
+ sleep (1);
+
+ /* havent heard back in 3 seconds, disco / reco */
+ if ((tm->pings_replied + 3) <= tm->pings_sent)
+ {
+ fformat (stdout, "VPE-f pid %d not responding\n", swt_pid);
+ swt_pid = 0;
+ disconnect_from_vpe ();
+ connected = 0;
+ }
+ }
+ else
+ {
+ if (connected)
+ {
+ fformat (stdout, "VPE-f pid %d died\n", swt_pid);
+ swt_pid = 0;
+ disconnect_from_vpe ();
+ connected = 0;
+ }
+ sleep (1);
+ }
+ }
+
+ fformat (stdout, "Signal received, graceful exit\n");
+ disconnect_from_vpe ();
+ exit (0);
+}
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/src/vpp/api/vat.h b/src/vpp/api/vat.h
new file mode 120000
index 00000000..3adbdbae
--- /dev/null
+++ b/src/vpp/api/vat.h
@@ -0,0 +1 @@
+../../vat/vat.h \ No newline at end of file
diff --git a/src/vpp/api/vpe.api b/src/vpp/api/vpe.api
new file mode 100644
index 00000000..d68beae1
--- /dev/null
+++ b/src/vpp/api/vpe.api
@@ -0,0 +1,936 @@
+/*
+ * Copyright (c) 2015-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.
+ */
+
+/** \file
+
+ This file defines vpe control-plane API messages which are generally
+ called through a shared memory interface.
+*/
+
+/*
+ * Note: API placement cleanup in progress
+ * If you're looking for interface APIs, please
+ * see .../src/vnet/{interface.api,interface_api.c}
+ * IP APIs: see .../src/vnet/ip/{ip.api, ip_api.c}
+ * TAP APIs: see .../src/vnet/unix/{tap.api, tap_api.c}
+ * VXLAN APIs: see .../src/vnet/vxlan/{vxlan.api, vxlan_api.c}
+ * LLDP APIs: see .../src/vnet/lldp/{lldp.api, lldp_api.c}
+ * AF-PACKET APIs: see ... /vnet/devices/af_packet/{af_packet.api, af_packet_api.c}
+ * NETMAP APIs: see ... /src/vnet/devices/netmap/{netmap.api, netmap_api.c}
+ * VHOST-USER APIs: see .../vnet/devices/virtio/{vhost_user.api, vhost_user_api.c}
+ * VXLAN GPE APIs: see .../src/vnet/vxlan-gpe/{vxlan_gpe.api, vxlan_gpe_api.c}
+ * GRE APIs: see .../src/vnet/gre/{gre.api, gre_api.c}
+ * L2 APIs: see .../src/vnet/l2/{l2.api, l2_api.c}
+ * L2TP APIs: see .../src/vnet/l2tp/{l2tp.api, l2tp_api.c}
+ * BFD APIs: see .../src/vnet/bfd/{bfd.api, bfd_api.c}
+ * IPSEC APIs: see .../src/vnet/ipsec/{ipsec.api, ipsec_api.c}
+ * IPSEC-GRE APIs: see .../src/vnet/ipsec-gre/{ipsec_gre.api, ipsec_gre_api.c}
+ * LISP APIs: see .../src/vnet/lisp/{lisp.api, lisp_api.c}
+ * LISP-GPE APIs: see .../src/vnet/lisp-gpe/{lisp_gpe.api, lisp_gpe_api.c}
+ * SESSION APIs: .../vnet/session/{session.api session_api.c}
+ * MPLS APIs: see .../src/vnet/mpls/{mpls.api, mpls_api.c}
+ * SR APIs: see .../src/vnet/srv6/{sr.api, sr_api.c}
+ * CLASSIFY APIs: see ... /src/vnet/classify/{classify.api, classify_api.c}
+ * FLOW APIs: see ... /src/vnet/flow/{flow.api, flow_api.c}
+ * DHCP APIs: see ... /src/vnet/dhcp/{dhcpk.api, dhcp_api.c}
+ * COP APIs: see ... /src/vnet/cop/{cop.api, cop_api.c}
+ * POLICER APIs: see ... /src/vnet/policer/{policer.api, policer_api.c}
+ * STATS APIs: see .../src/vpp/stats/{stats.api, stats.c}
+ */
+
+/** \brief Create a new subinterface with the given vlan id
+ @param client_index - opaque cookie to identify the sender
+ @param context - sender context, to match reply w/ request
+ @param sw_if_index - software index of the new vlan's parent interface
+ @param vlan_id - vlan tag of the new interface
+*/
+define create_vlan_subif
+{
+ u32 client_index;
+ u32 context;
+ u32 sw_if_index;
+ u32 vlan_id;
+};
+
+/** \brief Reply for the vlan subinterface create request
+ @param context - returned sender context, to match reply w/ request
+ @param retval - return code
+ @param sw_if_index - software index allocated for the new subinterface
+*/
+define create_vlan_subif_reply
+{
+ u32 context;
+ i32 retval;
+ u32 sw_if_index;
+};
+
+/** \brief Enable or Disable MPLS on and interface
+ @param client_index - opaque cookie to identify the sender
+ @param context - sender context, to match reply w/ request
+ @param sw_if_index - index of the interface
+ @param enable - if non-zero enable, else disable
+*/
+autoreply define sw_interface_set_mpls_enable
+{
+ u32 client_index;
+ u32 context;
+ u32 sw_if_index;
+ u8 enable;
+};
+
+/** \brief Proxy ARP add / del request
+ @param client_index - opaque cookie to identify the sender
+ @param context - sender context, to match reply w/ request
+ @param vrf_id - VRF / Fib table ID
+ @param is_add - 1 if adding the Proxy ARP range, 0 if deleting
+ @param low_address[4] - Low address of the Proxy ARP range
+ @param hi_address[4] - High address of the Proxy ARP range
+*/
+autoreply define proxy_arp_add_del
+{
+ u32 client_index;
+ u32 context;
+ u32 vrf_id;
+ u8 is_add;
+ u8 low_address[4];
+ u8 hi_address[4];
+};
+
+/** \brief Proxy ARP add / del request
+ @param client_index - opaque cookie to identify the sender
+ @param context - sender context, to match reply w/ request
+ @param sw_if_index - Which interface to enable / disable Proxy Arp on
+ @param enable_disable - 1 to enable Proxy ARP on interface, 0 to disable
+*/
+autoreply define proxy_arp_intfc_enable_disable
+{
+ u32 client_index;
+ u32 context;
+ u32 sw_if_index;
+ /* 1 = on, 0 = off */
+ u8 enable_disable;
+};
+
+/** \brief Reset VRF (remove all routes etc) request
+ @param client_index - opaque cookie to identify the sender
+ @param context - sender context, to match reply w/ request
+ @param is_ipv6 - 1 for IPv6 neighbor, 0 for IPv4
+ @param vrf_id - ID of th FIB table / VRF to reset
+*/
+autoreply define reset_vrf
+{
+ u32 client_index;
+ u32 context;
+ u8 is_ipv6;
+ u32 vrf_id;
+};
+
+/** \brief OAM event structure
+ @param dst_address[] -
+ @param state
+*/
+define oam_event
+{
+ u8 dst_address[4];
+ u8 state;
+};
+
+/** \brief Want OAM events request
+ @param client_index - opaque cookie to identify the sender
+ @param context - sender context, to match reply w/ request
+ @param enable_disable- enable if non-zero, else disable
+ @param pid - pid of the requesting process
+*/
+autoreply define want_oam_events
+{
+ u32 client_index;
+ u32 context;
+ u32 enable_disable;
+ u32 pid;
+};
+
+/** \brief OAM add / del target request
+ @param client_index - opaque cookie to identify the sender
+ @param context - sender context, to match reply w/ request
+ @param vrf_id - vrf_id of the target
+ @param src_address[] - source address to use for the updates
+ @param dst_address[] - destination address of the target
+ @param is_add - add target if non-zero, else delete
+*/
+autoreply define oam_add_del
+{
+ u32 client_index;
+ u32 context;
+ u32 vrf_id;
+ u8 src_address[4];
+ u8 dst_address[4];
+ u8 is_add;
+};
+
+/** \brief Reset fib table request
+ @param client_index - opaque cookie to identify the sender
+ @param context - sender context, to match reply w/ request
+ @param vrf_id - vrf/table id of the fib table to reset
+ @param is_ipv6 - an ipv6 fib to reset if non-zero, else ipv4
+*/
+autoreply define reset_fib
+{
+ u32 client_index;
+ u32 context;
+ u32 vrf_id;
+ u8 is_ipv6;
+};
+
+/** \brief Create loopback interface request
+ @param client_index - opaque cookie to identify the sender
+ @param context - sender context, to match reply w/ request
+ @param mac_address - mac addr to assign to the interface if none-zero
+*/
+define create_loopback
+{
+ u32 client_index;
+ u32 context;
+ u8 mac_address[6];
+};
+
+/** \brief Create loopback interface response
+ @param context - sender context, to match reply w/ request
+ @param sw_if_index - sw index of the interface that was created
+ @param retval - return code for the request
+*/
+define create_loopback_reply
+{
+ u32 context;
+ i32 retval;
+ u32 sw_if_index;
+};
+
+/** \brief Create loopback interface instance request
+ @param client_index - opaque cookie to identify the sender
+ @param context - sender context, to match reply w/ request
+ @param mac_address - mac addr to assign to the interface if none-zero
+ @param is_specified - if non-0, a specific user_instance is being requested
+ @param user_instance - requested instance, ~0 => dynamically allocate
+*/
+define create_loopback_instance
+{
+ u32 client_index;
+ u32 context;
+ u8 mac_address[6];
+ u8 is_specified;
+ u32 user_instance;
+};
+
+/** \brief Create loopback interface instance response
+ @param context - sender context, to match reply w/ request
+ @param sw_if_index - sw index of the interface that was created
+ @param retval - return code for the request
+*/
+define create_loopback_instance_reply
+{
+ u32 context;
+ i32 retval;
+ u32 sw_if_index;
+};
+
+/** \brief Delete loopback interface request
+ @param client_index - opaque cookie to identify the sender
+ @param context - sender context, to match reply w/ request
+ @param sw_if_index - sw index of the interface that was created
+*/
+autoreply define delete_loopback
+{
+ u32 client_index;
+ u32 context;
+ u32 sw_if_index;
+};
+
+/** \brief Control ping from client to api server request
+ @param client_index - opaque cookie to identify the sender
+ @param context - sender context, to match reply w/ request
+*/
+define control_ping
+{
+ u32 client_index;
+ u32 context;
+};
+
+/** \brief Control ping from the client to the server response
+ @param client_index - opaque cookie to identify the sender
+ @param context - sender context, to match reply w/ request
+ @param retval - return code for the request
+ @param vpe_pid - the pid of the vpe, returned by the server
+*/
+define control_ping_reply
+{
+ u32 context;
+ i32 retval;
+ u32 client_index;
+ u32 vpe_pid;
+};
+
+/** \brief Process a vpe parser cli string request
+ @param client_index - opaque cookie to identify the sender
+ @param context - sender context, to match reply w/ request
+ @param cmd_in_shmem - pointer to cli command string
+*/
+define cli
+{
+ u32 client_index;
+ u32 context;
+ u64 cmd_in_shmem;
+};
+define cli_inband
+{
+ u32 client_index;
+ u32 context;
+ u32 length;
+ u8 cmd[length];
+};
+
+/** \brief vpe parser cli string response
+ @param context - sender context, to match reply w/ request
+ @param retval - return code for request
+ @param reply_in_shmem - Reply string from cli processing if any
+*/
+define cli_reply
+{
+ u32 context;
+ i32 retval;
+ u64 reply_in_shmem;
+};
+define cli_inband_reply
+{
+ u32 context;
+ i32 retval;
+ u32 length;
+ u8 reply[length];
+};
+
+/** \brief Set max allowed ARP or ip6 neighbor entries request
+ @param client_index - opaque cookie to identify the sender
+ @param context - sender context, to match reply w/ request
+ @param is_ipv6 - neighbor limit if non-zero, else ARP limit
+ @param arp_neighbor_limit - the new limit, defaults are ~ 50k
+*/
+autoreply define set_arp_neighbor_limit
+{
+ u32 client_index;
+ u32 context;
+ u8 is_ipv6;
+ u32 arp_neighbor_limit;
+};
+
+/** \brief L2 interface patch add / del request
+ @param client_index - opaque cookie to identify the sender
+ @param context - sender context, to match reply w/ request
+ @param rx_sw_if_index - receive side interface
+ @param tx_sw_if_index - transmit side interface
+ @param is_add - if non-zero set up the interface patch, else remove it
+*/
+autoreply define l2_patch_add_del
+{
+ u32 client_index;
+ u32 context;
+ u32 rx_sw_if_index;
+ u32 tx_sw_if_index;
+ u8 is_add;
+};
+
+/** \brief Interface set vpath request
+ @param client_index - opaque cookie to identify the sender
+ @param context - sender context, to match reply w/ request
+ @param sw_if_index - interface used to reach neighbor
+ @param enable - if non-zero enable, else disable
+*/
+autoreply define sw_interface_set_vpath
+{
+ u32 client_index;
+ u32 context;
+ u32 sw_if_index;
+ u8 enable;
+};
+
+/** \brief Set L2 XConnect between two interfaces request
+ @param client_index - opaque cookie to identify the sender
+ @param context - sender context, to match reply w/ request
+ @param rx_sw_if_index - Receive interface index
+ @param tx_sw_if_index - Transmit interface index
+ @param enable - enable xconnect if not 0, else set to L3 mode
+*/
+autoreply define sw_interface_set_l2_xconnect
+{
+ u32 client_index;
+ u32 context;
+ u32 rx_sw_if_index;
+ u32 tx_sw_if_index;
+ u8 enable;
+};
+
+/** \brief Interface bridge mode request
+ @param client_index - opaque cookie to identify the sender
+ @param context - sender context, to match reply w/ request
+ @param rx_sw_if_index - the interface
+ @param bd_id - bridge domain id
+ @param bvi - Setup interface as a bvi, bridge mode only
+ @param shg - Shared horizon group, for bridge mode only
+ @param enable - Enable beige mode if not 0, else set to L3 mode
+*/
+autoreply define sw_interface_set_l2_bridge
+{
+ u32 client_index;
+ u32 context;
+ u32 rx_sw_if_index;
+ u32 bd_id;
+ u8 shg;
+ u8 bvi;
+ u8 enable;
+};
+
+/** \brief Set bridge domain ip to mac entry request
+ @param client_index - opaque cookie to identify the sender
+ @param context - sender context, to match reply w/ request
+ @param bd_id - the bridge domain to set the flags for
+ @param is_add - if non-zero, add the entry, else clear it
+ @param is_ipv6 - if non-zero, ipv6 address, else ipv4 address
+ @param mac_address - MAC address
+ @param
+*/
+autoreply define bd_ip_mac_add_del
+{
+ u32 client_index;
+ u32 context;
+ u32 bd_id;
+ u8 is_add;
+ u8 is_ipv6;
+ u8 ip_address[16];
+ u8 mac_address[6];
+};
+
+/** \brief Set/unset the classification table for an interface request
+ @param client_index - opaque cookie to identify the sender
+ @param context - sender context, to match reply w/ request
+ @param is_ipv6 - ipv6 if non-zero, else ipv4
+ @param sw_if_index - interface to associate with the table
+ @param table_index - index of the table, if ~0 unset the table
+*/
+autoreply define classify_set_interface_ip_table
+{
+ u32 client_index;
+ u32 context;
+ u8 is_ipv6;
+ u32 sw_if_index;
+ u32 table_index; /* ~0 => off */
+};
+
+/** \brief Set/unset l2 classification tables for an interface request
+ @param client_index - opaque cookie to identify the sender
+ @param context - sender context, to match reply w/ request
+ @param sw_if_index - interface to set/unset tables for
+ @param ip4_table_index - ip4 index, use ~0 for all 3 indexes to unset
+ @param ip6_table_index - ip6 index
+ @param other_table_index - other index
+*/
+autoreply define classify_set_interface_l2_tables
+{
+ u32 client_index;
+ u32 context;
+ u32 sw_if_index;
+ /* 3 x ~0 => off */
+ u32 ip4_table_index;
+ u32 ip6_table_index;
+ u32 other_table_index;
+ u8 is_input;
+};
+
+/** \brief Get node index using name request
+ @param client_index - opaque cookie to identify the sender
+ @param context - sender context, to match reply w/ request
+ @param node_name[] - name of the node
+*/
+define get_node_index
+{
+ u32 client_index;
+ u32 context;
+ u8 node_name[64];
+};
+
+/** \brief Get node index using name request
+ @param context - sender context, to match reply w/ request
+ @param retval - return code for the request
+ @param node_index - index of the desired node if found, else ~0
+*/
+define get_node_index_reply
+{
+ u32 context;
+ i32 retval;
+ u32 node_index;
+};
+
+/** \brief Set the next node for a given node request
+ @param client_index - opaque cookie to identify the sender
+ @param context - sender context, to match reply w/ request
+ @param node_name[] - node to add the next node to
+ @param next_name[] - node to add as the next node
+*/
+define add_node_next
+{
+ u32 client_index;
+ u32 context;
+ u8 node_name[64];
+ u8 next_name[64];
+};
+
+/** \brief IP Set the next node for a given node response
+ @param context - sender context, to match reply w/ request
+ @param retval - return code for the add next node request
+ @param next_index - the index of the next node if success, else ~0
+*/
+define add_node_next_reply
+{
+ u32 context;
+ i32 retval;
+ u32 next_index;
+};
+
+/** \brief L2 interface ethernet flow point filtering enable/disable request
+ @param client_index - opaque cookie to identify the sender
+ @param context - sender context, to match reply w/ request
+ @param sw_if_index - interface to enable/disable filtering on
+ @param enable_disable - if non-zero enable filtering, else disable
+*/
+autoreply define l2_interface_efp_filter
+{
+ u32 client_index;
+ u32 context;
+ u32 sw_if_index;
+ u32 enable_disable;
+};
+
+define create_subif
+{
+ u32 client_index;
+ u32 context;
+ u32 sw_if_index;
+ u32 sub_id;
+
+ /* These fields map directly onto the subif template */
+ u8 no_tags;
+ u8 one_tag;
+ u8 two_tags;
+ u8 dot1ad; // 0 = dot1q, 1=dot1ad
+ u8 exact_match;
+ u8 default_sub;
+ u8 outer_vlan_id_any;
+ u8 inner_vlan_id_any;
+ u16 outer_vlan_id;
+ u16 inner_vlan_id;
+};
+
+define create_subif_reply
+{
+ u32 context;
+ i32 retval;
+ u32 sw_if_index;
+};
+
+/** \brief show version
+ @param client_index - opaque cookie to identify the sender
+ @param context - sender context, to match reply w/ request
+*/
+define show_version
+{
+ u32 client_index;
+ u32 context;
+};
+
+/** \brief show version response
+ @param context - sender context, to match reply w/ request
+ @param retval - return code for the request
+ @param program - name of the program (vpe)
+ @param version - version of the program
+ @param build_directory - root of the workspace where the program was built
+*/
+define show_version_reply
+{
+ u32 context;
+ i32 retval;
+ u8 program[32];
+ u8 version[32];
+ u8 build_date[32];
+ u8 build_directory[256];
+};
+
+/* Gross kludge, DGMS */
+autoreply define interface_name_renumber
+{
+ u32 client_index;
+ u32 context;
+ u32 sw_if_index;
+ u32 new_show_dev_instance;
+};
+
+/** \brief Register for ip4 arp resolution events
+ @param client_index - opaque cookie to identify the sender
+ @param context - sender context, to match reply w/ request
+ @param enable_disable - 1 => register for events, 0 => cancel registration
+ @param pid - sender's pid
+ @param address - the exact ip4 address of interest
+*/
+autoreply define want_ip4_arp_events
+{
+ u32 client_index;
+ u32 context;
+ u8 enable_disable;
+ u32 pid;
+ u32 address;
+};
+
+/** \brief Tell client about an ip4 arp resolution event
+ @param client_index - opaque cookie to identify the sender
+ @param address - the exact ip4 address of interest
+ @param pid - client pid registered to receive notification
+ @param sw_if_index - interface which received ARP packet
+ @param new_mac - the new mac address
+ @param mac_ip - 0: resolution event, 1: mac/ip binding in bd
+*/
+define ip4_arp_event
+{
+ u32 client_index;
+ u32 address;
+ u32 pid;
+ u32 sw_if_index;
+ u8 new_mac[6];
+ u8 mac_ip;
+};
+
+/** \brief Register for ip6 nd resolution events
+ @param client_index - opaque cookie to identify the sender
+ @param context - sender context, to match reply w/ request
+ @param enable_disable - 1 => register for events, 0 => cancel registration
+ @param pid - sender's pid
+ @param address - the exact ip6 address of interest
+*/
+autoreply define want_ip6_nd_events
+{
+ u32 client_index;
+ u32 context;
+ u8 enable_disable;
+ u32 pid;
+ u8 address[16];
+};
+
+/** \brief Tell client about an ip6 nd resolution or mac/ip event
+ @param client_index - opaque cookie to identify the sender
+ @param pid - client pid registered to receive notification
+ @param sw_if_index - interface which received ARP packet
+ @param address - the exact ip6 address of interest
+ @param new_mac - the new mac address
+ @param mac_ip - 0: resolution event, 1: mac/ip binding in bd
+*/
+define ip6_nd_event
+{
+ u32 client_index;
+ u32 pid;
+ u32 sw_if_index;
+ u8 address[16];
+ u8 new_mac[6];
+ u8 mac_ip;
+};
+
+/** \brief Set/unset input ACL interface
+ @param client_index - opaque cookie to identify the sender
+ @param context - sender context, to match reply w/ request
+ @param sw_if_index - interface to set/unset input ACL
+ @param ip4_table_index - ip4 classify table index (~0 for skip)
+ @param ip6_table_index - ip6 classify table index (~0 for skip)
+ @param l2_table_index - l2 classify table index (~0 for skip)
+ @param is_add - Set input ACL if non-zero, else unset
+ Note: User is recommeneded to use just one valid table_index per call.
+ (ip4_table_index, ip6_table_index, or l2_table_index)
+*/
+autoreply define input_acl_set_interface
+{
+ u32 client_index;
+ u32 context;
+ u32 sw_if_index;
+ u32 ip4_table_index;
+ u32 ip6_table_index;
+ u32 l2_table_index;
+ u8 is_add;
+};
+
+define get_node_graph
+{
+ u32 client_index;
+ u32 context;
+};
+
+/** \brief get_node_graph_reply
+ @param context - returned sender context, to match reply w/ request
+ @param retval - return code
+ @param reply_in_shmem - result from vlib_node_serialize, in shared
+ memory. Process with vlib_node_unserialize, remember to switch
+ heaps and free the result.
+*/
+
+define get_node_graph_reply
+{
+ u32 context;
+ i32 retval;
+ u64 reply_in_shmem;
+};
+
+/** \brief IOAM enable : Enable in-band OAM
+ @param id - profile id
+ @param seqno - To enable Seqno Processing
+ @param analyse - Enabling analysis of iOAM at decap node
+ @param pow_enable - Proof of Work enabled or not flag
+ @param trace_enable - iOAM Trace enabled or not flag
+*/
+autoreply define ioam_enable
+{
+ u32 client_index;
+ u32 context;
+ u16 id;
+ u8 seqno;
+ u8 analyse;
+ u8 pot_enable;
+ u8 trace_enable;
+ u32 node_id;
+};
+
+/** \brief iOAM disable
+ @param client_index - opaque cookie to identify the sender
+ @param context - sender context, to match reply w/ request
+ @param index - MAP Domain index
+*/
+autoreply define ioam_disable
+{
+ u32 client_index;
+ u32 context;
+ u16 id;
+};
+
+/** \brief Query relative index via node names
+ @param client_index - opaque cookie to identify the sender
+ @param context - sender context, to match reply w/ request
+ @param node_name - name of node to find relative index from
+ @param next_name - next node from node_name to find relative index of
+*/
+define get_next_index
+{
+ u32 client_index;
+ u32 context;
+ u8 node_name[64];
+ u8 next_name[64];
+};
+
+/** \brief Reply for get next node index
+ @param context - sender context which was passed in the request
+ @param retval - return value
+ @param next_index - index of the next_node
+*/
+define get_next_index_reply
+{
+ u32 context;
+ i32 retval;
+ u32 next_index;
+};
+
+/** \brief PacketGenerator create interface request
+ @param client_index - opaque cookie to identify the sender
+ @param context - sender context, to match reply w/ request
+ @param interface_id - interface index
+*/
+define pg_create_interface
+{
+ u32 client_index;
+ u32 context;
+ u32 interface_id;
+};
+
+/** \brief PacketGenerator create interface response
+ @param context - sender context, to match reply w/ request
+ @param retval - return value for request
+*/
+define pg_create_interface_reply
+{
+ u32 context;
+ i32 retval;
+ u32 sw_if_index;
+};
+
+/** \brief PacketGenerator capture packets on given interface request
+ @param client_index - opaque cookie to identify the sender
+ @param context - sender context, to match reply w/ request
+ @param interface_id - pg interface index
+ @param is_enabled - 1 if enabling streams, 0 if disabling
+ @param count - number of packets to be captured
+ @param pcap_file - pacp file name to store captured packets
+*/
+autoreply define pg_capture
+{
+ u32 client_index;
+ u32 context;
+ u32 interface_id;
+ u8 is_enabled;
+ u32 count;
+ u32 pcap_name_length;
+ u8 pcap_file_name[pcap_name_length];
+};
+
+/** \brief Enable / disable packet generator request
+ @param client_index - opaque cookie to identify the sender
+ @param context - sender context, to match reply w/ request
+ @param is_enabled - 1 if enabling streams, 0 if disabling
+ @param stream - stream name to be enable/disabled, if not specified handle all streams
+*/
+autoreply define pg_enable_disable
+{
+ u32 client_index;
+ u32 context;
+ u8 is_enabled;
+ u32 stream_name_length;
+ u8 stream_name[stream_name_length];
+};
+
+/** \brief Configure IP source and L4 port-range check
+ @param client_index - opaque cookie to identify the sender
+ @param context - sender context, to match reply w/ request
+ @param is_ip6 - 1 if source address type is IPv6
+ @param is_add - 1 if add, 0 if delete
+ @param mask_length - mask length for address entry
+ @param address - array of address bytes
+ @param number_of_ranges - length of low_port and high_port arrays (must match)
+ @param low_ports[32] - up to 32 low end of port range entries (must have corresponding high_ports entry)
+ @param high_ports[32] - up to 32 high end of port range entries (must have corresponding low_ports entry)
+ @param vrf_id - fib table/vrf id to associate the source and port-range check with
+ @note To specify a single port set low_port and high_port entry the same
+*/
+autoreply define ip_source_and_port_range_check_add_del
+{
+ u32 client_index;
+ u32 context;
+ u8 is_ipv6;
+ u8 is_add;
+ u8 mask_length;
+ u8 address[16];
+ u8 number_of_ranges;
+ u16 low_ports[32];
+ u16 high_ports[32];
+ u32 vrf_id;
+};
+
+/** \brief Set interface source and L4 port-range request
+ @param client_index - opaque cookie to identify the sender
+ @param context - sender context, to match reply w/ request
+ @param interface_id - interface index
+ @param tcp_vrf_id - VRF associated with source and TCP port-range check
+ @param udp_vrf_id - VRF associated with source and TCP port-range check
+*/
+autoreply define ip_source_and_port_range_check_interface_add_del
+{
+ u32 client_index;
+ u32 context;
+ u8 is_add;
+ u32 sw_if_index;
+ u32 tcp_in_vrf_id;
+ u32 tcp_out_vrf_id;
+ u32 udp_in_vrf_id;
+ u32 udp_out_vrf_id;
+};
+
+/** \brief Delete sub interface request
+ @param client_index - opaque cookie to identify the sender
+ @param context - sender context, to match reply w/ request
+ @param sw_if_index - sw index of the interface that was created by create_subif
+*/
+autoreply define delete_subif {
+ u32 client_index;
+ u32 context;
+ u32 sw_if_index;
+};
+
+/** \brief Punt traffic to the host
+ @param client_index - opaque cookie to identify the sender
+ @param context - sender context, to match reply w/ request
+ @param is_add - add punt if non-zero, else delete
+ @param ipv - L3 protocol 4 - IPv4, 6 - IPv6, ~0 - All
+ @param l4_protocol - L4 protocol to be punted, only UDP (0x11) is supported
+ @param l4_port - TCP/UDP port to be punted
+*/
+autoreply define punt {
+ u32 client_index;
+ u32 context;
+ u8 is_add;
+ u8 ipv;
+ u8 l4_protocol;
+ u16 l4_port;
+};
+
+/** \brief Punt traffic to the host via socket
+ @param client_index - opaque cookie to identify the sender
+ @param context - sender context, to match reply w/ request
+ @param header_version - expected meta data header version (currently 1)
+ @param is_ip4 - L3 protocol 1 - IPv4, 0 - IPv6
+ @param l4_protocol - L4 protocol to be punted, only UDP (0x11) is supported
+ @param l4_port - TCP/UDP port to be punted
+*/
+define punt_socket_register {
+ u32 client_index;
+ u32 context;
+ u32 header_version;
+ u8 is_ip4;
+ u8 l4_protocol;
+ u16 l4_port;
+ u8 pathname[108]; /* Linux sun_path defined to be 108 bytes, see unix(7) */
+};
+
+define punt_socket_register_reply
+{
+ u32 context;
+ i32 retval;
+ u8 pathname[64];
+};
+
+autoreply define punt_socket_deregister {
+ u32 client_index;
+ u32 context;
+ u8 is_ip4;
+ u8 l4_protocol;
+ u16 l4_port;
+};
+
+/** \brief Feature path enable/disable request
+ @param client_index - opaque cookie to identify the sender
+ @param context - sender context, to match reply w/ request
+ @param sw_if_index - the interface
+ @param enable - 1 = on, 0 = off
+*/
+autoreply define feature_enable_disable {
+ u32 client_index;
+ u32 context;
+ u32 sw_if_index;
+ u8 enable;
+ u8 arc_name[64];
+ u8 feature_name[64];
+};
+
+/*
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/src/vpp/api/vpe_all_api_h.h b/src/vpp/api/vpe_all_api_h.h
new file mode 100644
index 00000000..d35a0535
--- /dev/null
+++ b/src/vpp/api/vpe_all_api_h.h
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+/*
+ * Add to the bottom of the #include list, or elves will steal your
+ * keyboard in the middle of the night!
+ */
+
+/* Include the (first) vlib-api API definition layer */
+#include <vlibmemory/vl_memory_api_h.h>
+
+/* Include the (second) vnet API definition layer */
+#define included_from_layer_3
+#include <vnet/vnet_all_api_h.h>
+#undef included_from_layer_3
+
+/* Include the current layer (third) vpp API definition layer */
+#include <vpp/api/vpe.api.h>
+
+/* Include stats APIs */
+#include <vpp/stats/stats.api.h>
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/src/vpp/api/vpe_msg_enum.h b/src/vpp/api/vpe_msg_enum.h
new file mode 100644
index 00000000..4fcc1c8c
--- /dev/null
+++ b/src/vpp/api/vpe_msg_enum.h
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ */
+#ifndef included_vpe_msg_enum_h
+#define included_vpe_msg_enum_h
+
+#include <vppinfra/byte_order.h>
+
+#define vl_msg_id(n,h) n,
+typedef enum
+{
+ VL_ILLEGAL_MESSAGE_ID = 0,
+#include <vpp/api/vpe_all_api_h.h>
+ VL_MSG_FIRST_AVAILABLE,
+} vl_msg_id_t;
+#undef vl_msg_id
+
+#endif /* included_vpe_msg_enum_h */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/src/vpp/api/vpp_get_metrics.c b/src/vpp/api/vpp_get_metrics.c
new file mode 100644
index 00000000..3474133d
--- /dev/null
+++ b/src/vpp/api/vpp_get_metrics.c
@@ -0,0 +1,253 @@
+/*
+ * 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <pwd.h>
+#include <grp.h>
+#include <netinet/in.h>
+#include <signal.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <time.h>
+#include <fcntl.h>
+#include <string.h>
+#include <vppinfra/clib.h>
+#include <vppinfra/vec.h>
+#include <vppinfra/hash.h>
+#include <vppinfra/bitmap.h>
+#include <vppinfra/fifo.h>
+#include <vppinfra/time.h>
+#include <vppinfra/mheap.h>
+#include <vppinfra/heap.h>
+#include <vppinfra/pool.h>
+#include <vppinfra/format.h>
+#include <vlibapi/api.h>
+#include <vlibmemory/api.h>
+
+#include <vlib/vlib.h>
+#include <vlib/unix/unix.h>
+#include <vnet/api_errno.h>
+
+#include <svm/svmdb.h>
+
+svmdb_client_t *c;
+volatile int signal_received;
+
+static void
+unix_signal_handler (int signum, siginfo_t * si, ucontext_t * uc)
+{
+ static int once;
+
+ if (once)
+ exit (1);
+
+ once = 1;
+ signal_received = 1;
+}
+
+static void
+setup_signal_handlers (void)
+{
+ uword i;
+ struct sigaction sa;
+
+ for (i = 1; i < 32; i++)
+ {
+ memset (&sa, 0, sizeof (sa));
+ sa.sa_sigaction = (void *) unix_signal_handler;
+ sa.sa_flags = SA_SIGINFO;
+
+ switch (i)
+ {
+ /* these signals take the default action */
+ case SIGABRT:
+ case SIGKILL:
+ case SIGSTOP:
+ case SIGUSR1:
+ case SIGUSR2:
+ continue;
+
+ /* ignore SIGPIPE, SIGCHLD */
+ case SIGPIPE:
+ case SIGCHLD:
+ sa.sa_sigaction = (void *) SIG_IGN;
+ break;
+
+ /* catch and handle all other signals */
+ default:
+ break;
+ }
+
+ if (sigaction (i, &sa, 0) < 0)
+ return clib_unix_warning (0, "sigaction %U", format_signal, i);
+ }
+}
+
+int
+main (int argc, char **argv)
+{
+ unformat_input_t input;
+ char *chroot_path = 0;
+ u8 *chroot_path_u8;
+ int interval = 0;
+ f64 *vector_ratep, *rx_ratep, *sig_error_ratep;
+ pid_t *vpp_pidp;
+ svmdb_map_args_t _ma, *ma = &_ma;
+ int uid, gid, rv;
+ struct passwd _pw, *pw;
+ struct group _grp, *grp;
+ char *s, buf[128];
+
+ unformat_init_command_line (&input, argv);
+
+ uid = geteuid ();
+ gid = getegid ();
+
+ while (unformat_check_input (&input) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (&input, "chroot %s", &chroot_path_u8))
+ {
+ chroot_path = (char *) chroot_path_u8;
+ }
+ else if (unformat (&input, "interval %d", &interval))
+ ;
+ else if (unformat (&input, "uid %d", &uid))
+ ;
+ else if (unformat (&input, "gid %d", &gid))
+ ;
+ else if (unformat (&input, "uid %s", &s))
+ {
+ /* lookup the username */
+ pw = NULL;
+ rv = getpwnam_r (s, &_pw, buf, sizeof (buf), &pw);
+ if (rv < 0)
+ {
+ fformat (stderr, "cannot fetch username %s", s);
+ exit (1);
+ }
+ if (pw == NULL)
+ {
+ fformat (stderr, "username %s does not exist", s);
+ exit (1);
+ }
+ vec_free (s);
+ uid = pw->pw_uid;
+ }
+ else if (unformat (&input, "gid %s", &s))
+ {
+ /* lookup the group name */
+ grp = NULL;
+ rv = getgrnam_r (s, &_grp, buf, sizeof (buf), &grp);
+ if (rv != 0)
+ {
+ fformat (stderr, "cannot fetch group %s", s);
+ exit (1);
+ }
+ if (grp == NULL)
+ {
+ fformat (stderr, "group %s does not exist", s);
+ exit (1);
+ }
+ vec_free (s);
+ gid = grp->gr_gid;
+ }
+ else
+ {
+ fformat (stderr,
+ "usage: vpp_get_metrics [chroot <path>] [interval <nn>]\n");
+ exit (1);
+ }
+ }
+
+ setup_signal_handlers ();
+
+ memset (ma, 0, sizeof (*ma));
+ ma->root_path = chroot_path;
+ ma->uid = uid;
+ ma->gid = gid;
+
+ c = svmdb_map (ma);
+
+ vpp_pidp =
+ svmdb_local_get_variable_reference (c, SVMDB_NAMESPACE_VEC, "vpp_pid");
+ vector_ratep =
+ svmdb_local_get_variable_reference (c, SVMDB_NAMESPACE_VEC,
+ "vpp_vector_rate");
+ rx_ratep =
+ svmdb_local_get_variable_reference (c, SVMDB_NAMESPACE_VEC,
+ "vpp_input_rate");
+ sig_error_ratep =
+ svmdb_local_get_variable_reference (c, SVMDB_NAMESPACE_VEC,
+ "vpp_sig_error_rate");
+
+ /*
+ * Make sure vpp is actually running. Otherwise, there's every
+ * chance that the database region will be wiped out by the
+ * process monitor script
+ */
+
+ if (vpp_pidp == 0 || vector_ratep == 0 || rx_ratep == 0
+ || sig_error_ratep == 0)
+ {
+ fformat (stdout, "vpp not running\n");
+ exit (1);
+ }
+
+ do
+ {
+ /*
+ * Once vpp exits, the svm db region will be recreated...
+ * Can't use kill (*vpp_pidp, 0) if running as non-root /
+ * accessing the shared-VM database via group perms.
+ */
+ if (*vpp_pidp == 0)
+ {
+ fformat (stdout, "vpp not running\n");
+ exit (1);
+ }
+ fformat (stdout,
+ "%d: vpp_vector_rate=%.2f, vpp_input_rate=%f, vpp_sig_error_rate=%f\n",
+ *vpp_pidp, *vector_ratep, *rx_ratep, *sig_error_ratep);
+
+ if (interval)
+ sleep (interval);
+ if (signal_received)
+ break;
+ }
+ while (interval);
+
+ svmdb_unmap (c);
+ exit (0);
+}
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/src/vpp/app/sticky_hash.c b/src/vpp/app/sticky_hash.c
new file mode 100644
index 00000000..5569c677
--- /dev/null
+++ b/src/vpp/app/sticky_hash.c
@@ -0,0 +1,581 @@
+/*
+ * 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.
+ */
+#include <vnet/l2/l2_classify.h>
+
+#include <vlib/vlib.h>
+#include <vnet/vnet.h>
+#include <vnet/pg/pg.h>
+#include <vnet/ip/ip.h>
+#include <vnet/ip/ip_packet.h>
+#include <vnet/ip/ip4_packet.h>
+#include <vnet/ip/ip6_packet.h>
+#include <vppinfra/error.h>
+
+typedef struct
+{
+ u32 fwd_entry_index;
+ u32 rev_entry_index;
+ /* Not strictly needed, for show command */
+ u32 fib_index;
+} sticky_hash_session_t;
+
+typedef struct
+{
+ u32 cached_next_index;
+
+ /* next index added to l2_classify */
+ u32 fwd_miss_next_index;
+
+ /* session pool */
+ sticky_hash_session_t *sessions;
+
+ /* Forward and reverse data session setup buffers */
+ u8 fdata[3 * sizeof (u32x4)];
+ u8 rdata[3 * sizeof (u32x4)];
+
+ /* convenience variables */
+ vlib_main_t *vlib_main;
+ vnet_main_t *vnet_main;
+ vnet_classify_main_t *vnet_classify_main;
+ l2_input_classify_main_t *l2_input_classify_main;
+}
+sticky_hash_main_t;
+
+typedef struct
+{
+ /* $$$$ fill in with per-pkt trace data */
+ u32 next_index;
+ u32 sw_if_index;
+} sticky_hash_miss_trace_t;
+
+/* packet trace format function */
+static u8 *
+format_sticky_hash_miss_trace (u8 * s, va_list * args)
+{
+ CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
+ CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
+ sticky_hash_miss_trace_t *t = va_arg (*args, sticky_hash_miss_trace_t *);
+
+ s = format (s, "STICKY_HASH_MISS: sw_if_index %d", t->sw_if_index);
+ return s;
+}
+
+typedef CLIB_PACKED (struct
+ {
+ ethernet_header_t eh; ip4_header_t ip;
+ }) classify_data_or_mask_t;
+
+sticky_hash_main_t sticky_hash_main;
+
+vlib_node_registration_t sticky_hash_miss_node;
+
+#define foreach_sticky_hash_miss_error \
+_(MISSES, "forward flow classify misses")
+
+typedef enum
+{
+#define _(sym,str) STICKY_HASH_MISS_ERROR_##sym,
+ foreach_sticky_hash_miss_error
+#undef _
+ STICKY_HASH_MISS_N_ERROR,
+} sticky_hash_miss_error_t;
+
+static char *sticky_hash_miss_error_strings[] = {
+#define _(sym,string) string,
+ foreach_sticky_hash_miss_error
+#undef _
+};
+
+/*
+ * To drop a pkt and increment one of the previous counters:
+ *
+ * set b0->error = error_node->errors[STICKY_HASH_MISS_ERROR_EXAMPLE];
+ * set next0 to a disposition index bound to "error-drop".
+ *
+ * To manually increment the specific counter STICKY_HASH_MISS_ERROR_EXAMPLE:
+ *
+ * vlib_node_t *n = vlib_get_node (vm, sticky_hash_miss.index);
+ * u32 node_counter_base_index = n->error_heap_index;
+ * vlib_error_main_t * em = &vm->error_main;
+ * em->counters[node_counter_base_index + STICKY_HASH_MISS_ERROR_EXAMPLE] += 1;
+ *
+ */
+
+typedef enum
+{
+ STICKY_HASH_MISS_NEXT_IP4_INPUT,
+ STICKY_HASH_MISS_N_NEXT,
+} sticky_hash_miss_next_t;
+
+static uword
+sticky_hash_miss_node_fn (vlib_main_t * vm,
+ vlib_node_runtime_t * node, vlib_frame_t * frame)
+{
+ u32 n_left_from, *from, *to_next;
+ sticky_hash_miss_next_t next_index;
+ sticky_hash_main_t *mp = &sticky_hash_main;
+ vlib_node_t *n = vlib_get_node (vm, sticky_hash_miss_node.index);
+ u32 node_counter_base_index = n->error_heap_index;
+ vlib_error_main_t *em = &vm->error_main;
+ vnet_classify_main_t *cm = mp->vnet_classify_main;
+ ip4_main_t *im = &ip4_main;
+
+ from = vlib_frame_vector_args (frame);
+ n_left_from = frame->n_vectors;
+ next_index = node->cached_next_index;
+
+ while (n_left_from > 0)
+ {
+ u32 n_left_to_next;
+
+ vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
+
+ while (n_left_from > 0 && n_left_to_next > 0)
+ {
+ u32 bi0;
+ vlib_buffer_t *b0;
+ u32 next0;
+ u32 sw_if_index0;
+ u32 fib_index0, ft_index0, rt_index0;
+ vnet_classify_table_3_t *ft0, *rt0;
+ vnet_classify_entry_3_t *fe0, *re0;
+ classify_data_or_mask_t *h0;
+ u8 was_found0;
+ ip4_fib_t *fib0;
+ sticky_hash_session_t *s;
+ u32 tmp;
+
+ /* speculatively enqueue b0 to the current next frame */
+ bi0 = from[0];
+ to_next[0] = bi0;
+ from += 1;
+ to_next += 1;
+ n_left_from -= 1;
+ n_left_to_next -= 1;
+
+ b0 = vlib_get_buffer (vm, bi0);
+
+ sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
+ next0 = mp->cached_next_index;
+
+ h0 = vlib_buffer_get_current (b0);
+
+ /* Add forward and reverse entries for this flow */
+ clib_memcpy (mp->fdata, h0, sizeof (mp->fdata));
+ clib_memcpy (mp->rdata, h0, sizeof (mp->rdata));
+
+ h0 = (classify_data_or_mask_t *) (mp->rdata);
+
+ /* swap src + dst addresses to form reverse data */
+ tmp = h0->ip.src_address.as_u32;
+ h0->ip.src_address.as_u32 = h0->ip.dst_address.as_u32;
+ h0->ip.dst_address.as_u32 = tmp;
+
+ /* dig up fwd + rev tables */
+ fib_index0 = vec_elt (im->fib_index_by_sw_if_index, sw_if_index0);
+ fib0 = vec_elt_at_index (im->fibs, fib_index0);
+
+ ft_index0 = fib0->fwd_classify_table_index;
+ rt_index0 = fib0->rev_classify_table_index;
+
+ ft0 = (vnet_classify_table_3_t *)
+ pool_elt_at_index (cm->tables, ft_index0);
+ rt0 = (vnet_classify_table_3_t *)
+ pool_elt_at_index (cm->tables, rt_index0);
+
+ fe0 =
+ vnet_classify_find_or_add_entry_3 (ft0, mp->fdata, &was_found0);
+ fe0->next_index = L2_INPUT_CLASSIFY_NEXT_IP4_INPUT;
+ fe0->advance = sizeof (ethernet_header_t);
+
+ re0 = vnet_classify_find_or_add_entry_3 (rt0, mp->rdata, 0);
+ re0->next_index = L2_INPUT_CLASSIFY_NEXT_IP4_INPUT; /* $$$ FIXME */
+ re0->advance = sizeof (ethernet_header_t);
+
+ /* Note: we could get a whole vector of misses for the same sess */
+ if (was_found0 == 0)
+ {
+ pool_get (mp->sessions, s);
+
+ fe0->opaque_index = s - mp->sessions;
+ re0->opaque_index = s - mp->sessions;
+
+ s->fwd_entry_index = fe0 - ft0->entries;
+ s->rev_entry_index = re0 - rt0->entries;
+ s->fib_index = fib_index0;
+ }
+
+ if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
+ && (b0->flags & VLIB_BUFFER_IS_TRACED)))
+ {
+ sticky_hash_miss_trace_t *t =
+ vlib_add_trace (vm, node, b0, sizeof (*t));
+ t->sw_if_index = sw_if_index0;
+ t->next_index = next0;
+ }
+
+ em->counters[node_counter_base_index +
+ STICKY_HASH_MISS_ERROR_MISSES] += 1;
+
+ vlib_buffer_advance (b0, sizeof (ethernet_header_t));
+
+ /* verify speculative enqueue, maybe switch current next frame */
+ vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
+ to_next, n_left_to_next,
+ bi0, next0);
+ }
+
+ vlib_put_next_frame (vm, node, next_index, n_left_to_next);
+ }
+
+ return frame->n_vectors;
+}
+
+/* *INDENT-OFF* */
+VLIB_REGISTER_NODE (sticky_hash_miss_node) = {
+ .function = sticky_hash_miss_node_fn,
+ .name = "sticky-hash-miss",
+ .vector_size = sizeof (u32),
+ .format_trace = format_sticky_hash_miss_trace,
+ .type = VLIB_NODE_TYPE_INTERNAL,
+
+ .n_errors = ARRAY_LEN(sticky_hash_miss_error_strings),
+ .error_strings = sticky_hash_miss_error_strings,
+
+ .n_next_nodes = STICKY_HASH_MISS_N_NEXT,
+
+ /* edit / add dispositions here */
+ .next_nodes = {
+ [STICKY_HASH_MISS_NEXT_IP4_INPUT] = "ip4-input",
+ },
+};
+/* *INDENT-ON* */
+
+clib_error_t *
+sticky_hash_miss_init (vlib_main_t * vm)
+{
+ sticky_hash_main_t *mp = &sticky_hash_main;
+
+ mp->vlib_main = vm;
+ mp->vnet_main = vnet_get_main ();
+ mp->vnet_classify_main = &vnet_classify_main;
+ mp->l2_input_classify_main = &l2_input_classify_main;
+
+ return 0;
+}
+
+VLIB_INIT_FUNCTION (sticky_hash_miss_init);
+
+static int ip4_sticky_hash_enable_disable
+ (sticky_hash_main_t * mp,
+ u32 fwd_sw_if_index, u8 * fwd_mask,
+ u32 rev_sw_if_index, u8 * rev_mask, u32 nbuckets, int enable_disable)
+{
+ ip4_main_t *im = &ip4_main;
+ u32 fib_index;
+ ip4_fib_t *fib;
+ vnet_classify_main_t *cm = mp->vnet_classify_main;
+ l2_input_classify_main_t *l2cm = mp->l2_input_classify_main;
+ vnet_classify_table_3_t *ft, *rt;
+
+ fib_index = vec_elt (im->fib_index_by_sw_if_index, fwd_sw_if_index);
+ fib = vec_elt_at_index (im->fibs, fib_index);
+
+ if (fib->fwd_classify_table_index == ~0)
+ {
+ /* Set up forward table */
+ ft = (vnet_classify_table_3_t *)
+ vnet_classify_new_table (cm, fwd_mask, nbuckets,
+ 0 /* skip */ , 3 /* match */ );
+ fib->fwd_classify_table_index
+ = ft - (vnet_classify_table_3_t *) cm->tables;
+ mp->fwd_miss_next_index =
+ vlib_node_add_next (mp->vlib_main, l2_input_classify_node.index,
+ sticky_hash_miss_node.index);
+ ft->miss_next_index = mp->fwd_miss_next_index;
+
+ /* Set up reverse table */
+ rt = (vnet_classify_table_3_t *)
+ vnet_classify_new_table (cm, rev_mask, nbuckets,
+ 0 /* skip */ , 3 /* match */ );
+ fib->rev_classify_table_index
+ = rt - (vnet_classify_table_3_t *) cm->tables;
+ }
+
+ vec_validate
+ (l2cm->classify_table_index_by_sw_if_index[L2_INPUT_CLASSIFY_TABLE_IP4],
+ fwd_sw_if_index);
+
+ vec_validate
+ (l2cm->classify_table_index_by_sw_if_index[L2_INPUT_CLASSIFY_TABLE_IP6],
+ fwd_sw_if_index);
+
+ vec_validate
+ (l2cm->classify_table_index_by_sw_if_index[L2_INPUT_CLASSIFY_TABLE_OTHER],
+ fwd_sw_if_index);
+
+ l2cm->classify_table_index_by_sw_if_index[L2_INPUT_CLASSIFY_TABLE_IP4]
+ [fwd_sw_if_index] = fib->fwd_classify_table_index;
+
+ l2cm->classify_table_index_by_sw_if_index[L2_INPUT_CLASSIFY_TABLE_IP6]
+ [fwd_sw_if_index] = ~0;
+
+ l2cm->classify_table_index_by_sw_if_index[L2_INPUT_CLASSIFY_TABLE_OTHER]
+ [fwd_sw_if_index] = ~0;
+
+
+ vec_validate
+ (l2cm->classify_table_index_by_sw_if_index[L2_INPUT_CLASSIFY_TABLE_IP4],
+ rev_sw_if_index);
+
+ vec_validate
+ (l2cm->classify_table_index_by_sw_if_index[L2_INPUT_CLASSIFY_TABLE_IP6],
+ rev_sw_if_index);
+
+ vec_validate
+ (l2cm->classify_table_index_by_sw_if_index[L2_INPUT_CLASSIFY_TABLE_OTHER],
+ rev_sw_if_index);
+
+
+ l2cm->classify_table_index_by_sw_if_index[L2_INPUT_CLASSIFY_TABLE_IP4]
+ [rev_sw_if_index] = fib->rev_classify_table_index;
+
+ l2cm->classify_table_index_by_sw_if_index[L2_INPUT_CLASSIFY_TABLE_IP6]
+ [rev_sw_if_index] = ~0;
+
+ l2cm->classify_table_index_by_sw_if_index[L2_INPUT_CLASSIFY_TABLE_OTHER]
+ [rev_sw_if_index] = ~0;
+
+ vnet_l2_input_classify_enable_disable (fwd_sw_if_index, enable_disable);
+ vnet_l2_input_classify_enable_disable (rev_sw_if_index, enable_disable);
+ return 0;
+}
+
+static clib_error_t *
+ip4_sticky_hash_init_command_fn (vlib_main_t * vm,
+ unformat_input_t * input,
+ vlib_cli_command_t * cmd)
+{
+ u32 fwd_sw_if_index = ~0, rev_sw_if_index = ~0;
+ int enable_disable = 1;
+ u32 nbuckets = 2;
+ int rv;
+ sticky_hash_main_t *mp = &sticky_hash_main;
+ classify_data_or_mask_t fwd_mask, rev_mask;
+ u8 *fm = 0, *rm = 0;
+
+ while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat
+ (input, "fwd %U", unformat_vnet_sw_interface, mp->vnet_main,
+ &fwd_sw_if_index))
+ ;
+ if (unformat
+ (input, "rev %U", unformat_vnet_sw_interface, mp->vnet_main,
+ &rev_sw_if_index))
+ ;
+ else if (unformat (input, "nbuckets %d", &nbuckets))
+ ;
+ else if (unformat (input, "disable"))
+ enable_disable = 0;
+
+ else
+ break;
+ }
+
+ nbuckets = 1 << max_log2 (nbuckets);
+
+ if (fwd_sw_if_index == ~0)
+ return clib_error_return (0, "fwd interface not set");
+
+ if (rev_sw_if_index == ~0)
+ return clib_error_return (0, "rev interface not set");
+
+ if (!is_pow2 (nbuckets))
+ return clib_error_return (0, "nbuckets %d not a power of 2", nbuckets);
+
+ ASSERT (sizeof (fwd_mask) <= 3 * sizeof (u32x4));
+
+ /* Mask on src/dst address, depending on direction */
+ memset (&fwd_mask, 0, sizeof (fwd_mask));
+ memset (&fwd_mask.ip.src_address, 0xff, 4);
+
+ memset (&rev_mask, 0, sizeof (rev_mask));
+ memset (&rev_mask.ip.dst_address, 0xff, 4);
+
+ vec_validate (fm, 3 * sizeof (u32x4) - 1);
+ vec_validate (rm, 3 * sizeof (u32x4) - 1);
+
+ clib_memcpy (fm, &fwd_mask, sizeof (fwd_mask));
+ clib_memcpy (rm, &rev_mask, sizeof (rev_mask));
+
+ rv = ip4_sticky_hash_enable_disable (mp, fwd_sw_if_index, fm,
+ rev_sw_if_index, rm,
+ nbuckets, enable_disable);
+
+ vec_free (fm);
+ vec_free (rm);
+ switch (rv)
+ {
+ case 0:
+ return 0;
+
+ default:
+ return clib_error_return (0,
+ "ip4_sticky_hash_enable_disable returned %d",
+ rv);
+ }
+
+ return 0;
+}
+
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND (sticky_hash_init_command, static) = {
+ .path = "ip sticky classify",
+ .short_help = "ip sticky classify fwd <intfc> rev <intfc> "
+ "[nbuckets <nn>][disable]",
+ .function = ip4_sticky_hash_init_command_fn,
+};
+/* *INDENT-ON* */
+
+
+u8 *
+format_sticky_hash_session (u8 * s, va_list * args)
+{
+ sticky_hash_main_t *mp = va_arg (*args, sticky_hash_main_t *);
+ sticky_hash_session_t *session = va_arg (*args, sticky_hash_session_t *);
+ vnet_classify_table_3_t *t;
+ vnet_classify_entry_3_t *e;
+ ip4_main_t *im = &ip4_main;
+ vnet_classify_main_t *cm = mp->vnet_classify_main;
+ ip4_fib_t *fib;
+ classify_data_or_mask_t *match;
+
+ fib = vec_elt_at_index (im->fibs, session->fib_index);
+
+ t = (vnet_classify_table_3_t *)
+ pool_elt_at_index (cm->tables, fib->fwd_classify_table_index);
+ e = pool_elt_at_index (t->entries, session->fwd_entry_index);
+ match = (classify_data_or_mask_t *) (e->key);
+
+ s = format
+ (s,
+ "[%6d] fwd src %U next index %d session %d fib %d\n"
+ " hits %lld last-heard %.6f\n",
+ e - t->entries,
+ format_ip4_address, &match->ip.src_address,
+ e->next_index, e->opaque_index, fib->table_id, e->hits, e->last_heard);
+
+ if (e->opaque_index != session - mp->sessions)
+ s = format (s, "WARNING: forward session index mismatch!\n");
+
+ t = (vnet_classify_table_3_t *)
+ pool_elt_at_index (cm->tables, fib->rev_classify_table_index);
+ e = pool_elt_at_index (t->entries, session->rev_entry_index);
+ match = (classify_data_or_mask_t *) (e->key);
+
+ s = format
+ (s,
+ "[%6d] rev dst %U next index %d session %d\n"
+ " hits %lld last-heard %.6f\n",
+ e - t->entries,
+ format_ip4_address, &match->ip.dst_address,
+ e->next_index, e->opaque_index, e->hits, e->last_heard);
+
+ if (e->opaque_index != session - mp->sessions)
+ s = format (s, "WARNING: reverse session index mismatch!\n");
+ s = format (s, "---------\n");
+
+ return s;
+}
+
+static clib_error_t *
+show_ip4_sticky_hash_command_fn (vlib_main_t * vm,
+ unformat_input_t * input,
+ vlib_cli_command_t * cmd)
+{
+ sticky_hash_main_t *mp = &sticky_hash_main;
+ sticky_hash_session_t *s;
+ int verbose = 0;
+ int dump_classifier_tables = 0;
+ ip4_fib_t *fib;
+ ip4_main_t *im4 = &ip4_main;
+ vnet_classify_main_t *cm = mp->vnet_classify_main;
+
+ while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (input, "verbose"))
+ verbose = 1;
+ else if (unformat (input, "dump-tables")
+ || unformat (input, "dump-classifier-tables"))
+ dump_classifier_tables = 1;
+ else
+ break;
+ }
+
+ if (pool_elts (mp->sessions) == 0)
+ vlib_cli_output (vm, "No ip sticky hash sessions");
+
+
+ vlib_cli_output (vm, "%d active sessions\n", pool_elts (mp->sessions));
+
+ vec_foreach (fib, im4->fibs)
+ {
+ if (fib->fwd_classify_table_index != ~0)
+ vlib_cli_output (vm, "fib %d fwd table: \n%U",
+ fib->table_id,
+ format_classify_table,
+ cm,
+ pool_elt_at_index
+ (cm->tables, fib->fwd_classify_table_index),
+ dump_classifier_tables);
+ if (fib->rev_classify_table_index != ~0)
+ vlib_cli_output (vm, "fib %d rev table: \n%U",
+ fib->table_id,
+ format_classify_table,
+ cm,
+ pool_elt_at_index
+ (cm->tables, fib->rev_classify_table_index),
+ dump_classifier_tables);
+ }
+
+ if (verbose)
+ {
+ /* *INDENT-OFF* */
+ pool_foreach (s, mp->sessions,
+ ({
+ vlib_cli_output (vm, "%U", format_sticky_hash_session, mp, s);
+ }));
+ /* *INDENT-ON* */
+ }
+ return 0;
+}
+
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND (show_sticky_hash_command, static) = {
+ .path = "show sticky classify",
+ .short_help = "Display sticky classifier tables",
+ .function = show_ip4_sticky_hash_command_fn,
+};
+/* *INDENT-ON* */
+
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/src/vpp/app/version.c b/src/vpp/app/version.c
new file mode 100644
index 00000000..0a2c7fd4
--- /dev/null
+++ b/src/vpp/app/version.c
@@ -0,0 +1,92 @@
+/*
+ * 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.
+ */
+#include <vlib/vlib.h>
+#include <vppinfra/cpu.h>
+#include <vpp/app/version.h>
+
+static char *vpe_version_string =
+ "vpp v" VPP_BUILD_VER
+ " built by " VPP_BUILD_USER " on " VPP_BUILD_HOST " at " VPP_BUILD_DATE;
+
+static char *vpe_compiler =
+#if defined(__INTEL_COMPILER)
+#define __(x) #x
+#define _(x) __(x)
+ "icc " _(__INTEL_COMPILER) " (" __VERSION__ ")";
+#undef _
+#undef __
+#elif defined(__clang__)
+ "Clang/LLVM " __clang_version__;
+#elif defined (__GNUC__)
+ "GCC " __VERSION__;
+#else
+ "unknown compiler";
+#endif
+
+static clib_error_t *
+show_vpe_version_command_fn (vlib_main_t * vm,
+ unformat_input_t * input,
+ vlib_cli_command_t * cmd)
+{
+ if (unformat (input, "verbose"))
+ {
+#define _(a,b,c) vlib_cli_output (vm, "%-25s " b, a ":", c);
+ _("Version", "%s", "v" VPP_BUILD_VER);
+ _("Compiled by", "%s", VPP_BUILD_USER);
+ _("Compile host", "%s", VPP_BUILD_HOST);
+ _("Compile date", "%s", VPP_BUILD_DATE);
+ _("Compile location", "%s", VPP_BUILD_TOPDIR);
+ _("Compiler", "%s", vpe_compiler);
+ _("Current PID", "%d", getpid ());
+#undef _
+ }
+ else
+ vlib_cli_output (vm, "%s", vpe_version_string);
+ return 0;
+}
+
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND (show_vpe_version_command, static) = {
+ .path = "show version",
+ .short_help = "show version information",
+ .function = show_vpe_version_command_fn,
+};
+/* *INDENT-ON* */
+
+char *
+vpe_api_get_build_directory (void)
+{
+ return VPP_BUILD_TOPDIR;
+}
+
+char *
+vpe_api_get_version (void)
+{
+ return VPP_BUILD_VER;
+}
+
+char *
+vpe_api_get_build_date (void)
+{
+ return VPP_BUILD_DATE;
+}
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/src/vpp/app/vpe_cli.c b/src/vpp/app/vpe_cli.c
new file mode 100644
index 00000000..e19c23de
--- /dev/null
+++ b/src/vpp/app/vpe_cli.c
@@ -0,0 +1,136 @@
+/*
+ * 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.
+ */
+#include <vnet/ip/ip.h>
+#include <vnet/ethernet/ethernet.h>
+#include <vnet/adj/adj.h>
+#include <vnet/fib/fib_table.h>
+
+typedef struct
+{
+ u8 mac_addr[6];
+} mac_addr_t;
+
+static clib_error_t *
+virtual_ip_cmd_fn_command_fn (vlib_main_t * vm,
+ unformat_input_t * input,
+ vlib_cli_command_t * cmd)
+{
+ unformat_input_t _line_input, *line_input = &_line_input;
+ vnet_main_t *vnm = vnet_get_main ();
+ ip46_address_t next_hop, *next_hops;
+ fib_route_path_t *rpaths;
+ fib_prefix_t prefix;
+ u8 mac_addr[6];
+ mac_addr_t *mac_addrs = 0;
+ u32 sw_if_index;
+ u32 i;
+ clib_error_t *error = NULL;
+
+ next_hops = NULL;
+ rpaths = NULL;
+ prefix.fp_len = 32;
+ prefix.fp_proto = FIB_PROTOCOL_IP4;
+
+ /* Get a line of input. */
+ if (!unformat_user (input, unformat_line_input, line_input))
+ return 0;
+
+ if (!unformat (line_input, "%U %U",
+ unformat_ip4_address, &prefix.fp_addr.ip4,
+ unformat_vnet_sw_interface, vnm, &sw_if_index))
+ {
+ error = clib_error_return (0, "unknown input `%U'",
+ format_unformat_error, line_input);
+ goto done;
+ }
+
+ while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (line_input, "mac %U",
+ unformat_ethernet_address, &mac_addr))
+ {
+ mac_addr_t *ma;
+ vec_add2 (mac_addrs, ma, 1);
+ clib_memcpy (ma, mac_addr, sizeof (mac_addr));
+ }
+ else if (unformat (line_input, "next-hop %U",
+ unformat_ip4_address, &next_hop.ip4))
+ {
+ vec_add1 (next_hops, next_hop);
+ }
+ else
+ {
+ error = clib_error_return (0, "unknown input `%U'",
+ format_unformat_error, line_input);
+ goto done;
+ }
+ }
+
+ if (vec_len (mac_addrs) == 0 || vec_len (mac_addrs) != vec_len (next_hops))
+ {
+ error = clib_error_return (0, "unknown input `%U'",
+ format_unformat_error, line_input);
+ goto done;
+ }
+
+ /* Create / delete special interface route /32's */
+
+ for (i = 0; i < vec_len (mac_addrs); i++)
+ {
+ fib_route_path_t *rpath;
+
+ adj_nbr_add_or_lock_w_rewrite (FIB_PROTOCOL_IP4,
+ VNET_LINK_IP4,
+ &next_hops[i],
+ sw_if_index, mac_addrs[i].mac_addr);
+
+ vec_add2 (rpaths, rpath, 1);
+
+ rpath->frp_proto = DPO_PROTO_IP4;
+ rpath->frp_addr = next_hops[i];
+ rpath->frp_sw_if_index = sw_if_index;
+ rpath->frp_fib_index = ~0;
+ rpath->frp_weight = 1;
+ rpath->frp_label_stack = NULL;
+ }
+
+ fib_table_entry_path_add2 (0, // default FIB table
+ &prefix,
+ FIB_SOURCE_CLI, FIB_ENTRY_FLAG_NONE, rpaths);
+
+done:
+ vec_free (mac_addrs);
+ vec_free (next_hops);
+ vec_free (rpaths);
+ unformat_free (line_input);
+
+ return error;
+}
+
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND (virtual_ip_cmd_fn_command, static) = {
+ .path = "ip virtual",
+ .short_help = "ip virtual <addr> <interface> [mac <Mi>]+",
+ .function = virtual_ip_cmd_fn_command_fn,
+};
+/* *INDENT-ON* */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/src/vpp/app/vppctl.c b/src/vpp/app/vppctl.c
new file mode 100644
index 00000000..66fe00ab
--- /dev/null
+++ b/src/vpp/app/vppctl.c
@@ -0,0 +1,384 @@
+/*
+ * Copyright (c) 2017 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.
+ */
+
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/epoll.h>
+#include <sys/ioctl.h>
+#include <signal.h>
+#include <termios.h>
+#include <unistd.h>
+#include <string.h>
+
+#define DEBUG 0
+
+#if DEBUG
+#define TELCMDS
+#define TELOPTS
+#endif
+
+#include <arpa/telnet.h>
+
+#include <vppinfra/mem.h>
+#include <vppinfra/format.h>
+#include <vppinfra/socket.h>
+
+#define SOCKET_FILE "/run/vpp/cli.sock"
+
+volatile int window_resized = 0;
+struct termios orig_tio;
+
+static void
+send_ttype (clib_socket_t * s, int is_interactive)
+{
+ char *term;
+
+ term = is_interactive ? getenv ("TERM") : "vppctl";
+ if (term == NULL)
+ term = "dumb";
+
+ clib_socket_tx_add_formatted (s, "%c%c%c" "%c%s" "%c%c",
+ IAC, SB, TELOPT_TTYPE, 0, term, IAC, SE);
+ clib_socket_tx (s);
+}
+
+static void
+send_naws (clib_socket_t * s)
+{
+ struct winsize ws;
+
+ if (ioctl (STDIN_FILENO, TIOCGWINSZ, &ws) < 0)
+ {
+ clib_unix_warning ("ioctl(TIOCGWINSZ)");
+ return;
+ }
+
+ clib_socket_tx_add_formatted (s, "%c%c%c" "%c%c%c%c" "%c%c",
+ IAC, SB, TELOPT_NAWS,
+ ws.ws_col >> 8, ws.ws_col & 0xff,
+ ws.ws_row >> 8, ws.ws_row & 0xff, IAC, SE);
+ clib_socket_tx (s);
+}
+
+static void
+signal_handler_winch (int signum)
+{
+ window_resized = 1;
+}
+
+static void
+signal_handler_term (int signum)
+{
+ tcsetattr (STDIN_FILENO, TCSAFLUSH, &orig_tio);
+}
+
+static u8 *
+process_input (u8 * str, clib_socket_t * s, int is_interactive,
+ int *sent_ttype)
+{
+ int i = 0;
+
+ while (i < vec_len (s->rx_buffer))
+ {
+ if (s->rx_buffer[i] == IAC)
+ {
+ if (s->rx_buffer[i + 1] == SB)
+ {
+ u8 *sb = 0;
+ char opt = s->rx_buffer[i + 2];
+ i += 3;
+ while (s->rx_buffer[i] != IAC)
+ vec_add1 (sb, s->rx_buffer[i++]);
+
+#if DEBUG
+ clib_warning ("SB %s\n %U", TELOPT (opt),
+ format_hexdump, sb, vec_len (sb));
+#endif
+ vec_free (sb);
+ i += 2;
+ if (opt == TELOPT_TTYPE)
+ {
+ send_ttype (s, is_interactive);
+ *sent_ttype = 1;
+ }
+ else if (is_interactive && opt == TELOPT_NAWS)
+ send_naws (s);
+ }
+ else
+ {
+#if DEBUG
+ clib_warning ("IAC at %d, IAC %s %s", i,
+ TELCMD (s->rx_buffer[i + 1]),
+ TELOPT (s->rx_buffer[i + 2]));
+#endif
+ i += 3;
+ }
+ }
+ else
+ vec_add1 (str, s->rx_buffer[i++]);
+ }
+ vec_reset_length (s->rx_buffer);
+ return str;
+}
+
+
+int
+main (int argc, char *argv[])
+{
+ clib_socket_t _s = { 0 }, *s = &_s;
+ clib_error_t *error = 0;
+ struct epoll_event event;
+ struct sigaction sa;
+ struct termios tio;
+ int efd = -1;
+ u8 *str = 0;
+ u8 *cmd = 0;
+ int do_quit = 0;
+ int is_interactive = 0;
+ int acked = 1; /* counts messages from VPP; starts at 1 */
+ int sent_ttype = 0;
+
+
+ clib_mem_init (0, 64ULL << 10);
+
+ /* process command line */
+ argc--;
+ argv++;
+
+ if (argc > 1 && strcmp (argv[0], "-s") == 0)
+ {
+ s->config = argv[1];
+ argc -= 2;
+ argv += 2;
+ }
+ else
+ s->config = SOCKET_FILE;
+
+ while (argc--)
+ cmd = format (cmd, "%s%c", (argv++)[0], argc ? ' ' : 0);
+
+ s->flags = CLIB_SOCKET_F_IS_CLIENT;
+
+ error = clib_socket_init (s);
+ if (error)
+ goto done;
+
+ is_interactive = isatty (STDIN_FILENO) && cmd == 0;
+
+ if (is_interactive)
+ {
+ /* Capture terminal resize events */
+ memset (&sa, 0, sizeof (struct sigaction));
+ sa.sa_handler = signal_handler_winch;
+ if (sigaction (SIGWINCH, &sa, 0) < 0)
+ {
+ error = clib_error_return_unix (0, "sigaction");
+ goto done;
+ }
+
+ /* Capture SIGTERM to reset tty settings */
+ sa.sa_handler = signal_handler_term;
+ if (sigaction (SIGTERM, &sa, 0) < 0)
+ {
+ error = clib_error_return_unix (0, "sigaction");
+ goto done;
+ }
+
+ /* Save the original tty state so we can restore it later */
+ if (tcgetattr (STDIN_FILENO, &orig_tio) < 0)
+ {
+ error = clib_error_return_unix (0, "tcgetattr");
+ goto done;
+ }
+
+ /* Tweak the tty settings */
+ tio = orig_tio;
+ /* echo off, canonical mode off, ext'd input processing off */
+ tio.c_lflag &= ~(ECHO | ICANON | IEXTEN);
+ tio.c_cc[VMIN] = 1; /* 1 byte at a time */
+ tio.c_cc[VTIME] = 0; /* no timer */
+
+ if (tcsetattr (STDIN_FILENO, TCSAFLUSH, &tio) < 0)
+ {
+ error = clib_error_return_unix (0, "tcsetattr");
+ goto done;
+ }
+ }
+
+ efd = epoll_create1 (0);
+
+ /* register STDIN */
+ event.events = EPOLLIN | EPOLLPRI | EPOLLERR;
+ event.data.fd = STDIN_FILENO;
+ if (epoll_ctl (efd, EPOLL_CTL_ADD, STDIN_FILENO, &event) != 0)
+ {
+ /* ignore EPERM; it means stdin is something like /dev/null */
+ if (errno != EPERM)
+ {
+ error = clib_error_return_unix (0, "epoll_ctl[%d]", STDIN_FILENO);
+ goto done;
+ }
+ }
+
+ /* register socket */
+ event.events = EPOLLIN | EPOLLPRI | EPOLLERR;
+ event.data.fd = s->fd;
+ if (epoll_ctl (efd, EPOLL_CTL_ADD, s->fd, &event) != 0)
+ {
+ error = clib_error_return_unix (0, "epoll_ctl[%d]", s->fd);
+ goto done;
+ }
+
+ while (1)
+ {
+ int n;
+
+ if (window_resized)
+ {
+ window_resized = 0;
+ send_naws (s);
+ }
+
+ if ((n = epoll_wait (efd, &event, 1, -1)) < 0)
+ {
+ /* maybe we received signal */
+ if (errno == EINTR)
+ continue;
+
+ error = clib_error_return_unix (0, "epoll_wait");
+ goto done;
+ }
+
+ if (n == 0)
+ continue;
+
+ if (event.data.fd == STDIN_FILENO)
+ {
+ int n;
+ char c[100];
+
+ if (!sent_ttype)
+ continue; /* not ready for this yet */
+
+ n = read (STDIN_FILENO, c, sizeof (c));
+ if (n > 0)
+ {
+ memcpy (clib_socket_tx_add (s, n), c, n);
+ error = clib_socket_tx (s);
+ if (error)
+ goto done;
+ }
+ else if (n < 0)
+ clib_warning ("read rv=%d", n);
+ else /* EOF */
+ do_quit = 1;
+ }
+ else if (event.data.fd == s->fd)
+ {
+ error = clib_socket_rx (s, 100);
+ if (error)
+ break;
+
+ if (clib_socket_rx_end_of_file (s))
+ break;
+
+ str = process_input (str, s, is_interactive, &sent_ttype);
+
+ if (vec_len (str) > 0)
+ {
+ int len = vec_len (str);
+ u8 *p = str, *q = str;
+
+ while (len)
+ {
+ /* Search for and skip NUL bytes */
+ while (q < (p + len) && *q)
+ q++;
+
+ n = write (STDOUT_FILENO, p, q - p);
+ if (n < 0)
+ {
+ error = clib_error_return_unix (0, "write");
+ goto done;
+ }
+
+ while (q < (p + len) && !*q)
+ {
+ q++;
+ acked++; /* every NUL is an acknowledgement */
+ }
+ len -= q - p;
+ p = q;
+ }
+
+ vec_reset_length (str);
+ }
+
+ if (do_quit && do_quit < acked)
+ {
+ /* Ask the other end to close the connection */
+ clib_socket_tx_add_formatted (s, "quit\n");
+ clib_socket_tx (s);
+ do_quit = 0;
+ }
+ if (cmd && sent_ttype)
+ {
+ /* We wait until after the TELNET TTYPE option has been sent.
+ * That is to make sure the session at the VPP end has switched
+ * to line-by-line mode, and thus avoid prompts and echoing.
+ * Note that it does also disable further TELNET option processing.
+ */
+ clib_socket_tx_add_formatted (s, "%s\n", cmd);
+ clib_socket_tx (s);
+ vec_free (cmd);
+ do_quit = acked; /* quit after the next response */
+ }
+ }
+ else
+ {
+ error = clib_error_return (0, "unknown fd");
+ goto done;
+ }
+ }
+
+ error = clib_socket_close (s);
+
+done:
+ vec_free (cmd);
+ vec_free (str);
+ if (efd > -1)
+ close (efd);
+
+ if (is_interactive)
+ tcsetattr (STDIN_FILENO, TCSAFLUSH, &orig_tio);
+
+ if (error)
+ {
+ clib_error_report (error);
+ return 1;
+ }
+
+ return 0;
+}
+
+/* *INDENT-ON* */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/src/vpp/conf/80-vpp.conf b/src/vpp/conf/80-vpp.conf
new file mode 100644
index 00000000..8fdf184c
--- /dev/null
+++ b/src/vpp/conf/80-vpp.conf
@@ -0,0 +1,15 @@
+# Number of 2MB hugepages desired
+vm.nr_hugepages=1024
+
+# Must be greater than or equal to (2 * vm.nr_hugepages).
+vm.max_map_count=3096
+
+# All groups allowed to access hugepages
+vm.hugetlb_shm_group=0
+
+# Shared Memory Max must be greator or equal to the total size of hugepages.
+# For 2MB pages, TotalHugepageSize = vm.nr_hugepages * 2 * 1024 * 1024
+# If the existing kernel.shmmax setting (cat /sys/proc/kernel/shmmax)
+# is greater than the calculated TotalHugepageSize then set this parameter
+# to current shmmax value.
+kernel.shmmax=2147483648
diff --git a/src/vpp/conf/startup.conf b/src/vpp/conf/startup.conf
new file mode 100644
index 00000000..c3b9872e
--- /dev/null
+++ b/src/vpp/conf/startup.conf
@@ -0,0 +1,133 @@
+
+unix {
+ nodaemon
+ log /tmp/vpp.log
+ full-coredump
+ cli-listen /run/vpp/cli.sock
+ gid vpp
+}
+
+api-trace {
+## This stanza controls binary API tracing. Unless there is a very strong reason,
+## please leave this feature enabled.
+ on
+## Additional parameters:
+##
+## To set the number of binary API trace records in the circular buffer, configure nitems
+##
+## nitems <nnn>
+##
+## To save the api message table decode tables, configure a filename. Results in /tmp/<filename>
+## Very handy for understanding api message changes between versions, identifying missing
+## plugins, and so forth.
+##
+## save-api-table <filename>
+}
+
+api-segment {
+ gid vpp
+}
+
+cpu {
+ ## In the VPP there is one main thread and optionally the user can create worker(s)
+ ## The main thread and worker thread(s) can be pinned to CPU core(s) manually or automatically
+
+ ## Manual pinning of thread(s) to CPU core(s)
+
+ ## Set logical CPU core where main thread runs
+ # main-core 1
+
+ ## Set logical CPU core(s) where worker threads are running
+ # corelist-workers 2-3,18-19
+
+ ## Automatic pinning of thread(s) to CPU core(s)
+
+ ## Sets number of CPU core(s) to be skipped (1 ... N-1)
+ ## Skipped CPU core(s) are not used for pinning main thread and working thread(s).
+ ## The main thread is automatically pinned to the first available CPU core and worker(s)
+ ## are pinned to next free CPU core(s) after core assigned to main thread
+ # skip-cores 4
+
+ ## Specify a number of workers to be created
+ ## Workers are pinned to N consecutive CPU cores while skipping "skip-cores" CPU core(s)
+ ## and main thread's CPU core
+ # workers 2
+
+ ## Set scheduling policy and priority of main and worker threads
+
+ ## Scheduling policy options are: other (SCHED_OTHER), batch (SCHED_BATCH)
+ ## idle (SCHED_IDLE), fifo (SCHED_FIFO), rr (SCHED_RR)
+ # scheduler-policy fifo
+
+ ## Scheduling priority is used only for "real-time policies (fifo and rr),
+ ## and has to be in the range of priorities supported for a particular policy
+ # scheduler-priority 50
+}
+
+# dpdk {
+ ## Change default settings for all intefaces
+ # dev default {
+ ## Number of receive queues, enables RSS
+ ## Default is 1
+ # num-rx-queues 3
+
+ ## Number of transmit queues, Default is equal
+ ## to number of worker threads or 1 if no workers treads
+ # num-tx-queues 3
+
+ ## Number of descriptors in transmit and receive rings
+ ## increasing or reducing number can impact performance
+ ## Default is 1024 for both rx and tx
+ # num-rx-desc 512
+ # num-tx-desc 512
+
+ ## VLAN strip offload mode for interface
+ ## Default is off
+ # vlan-strip-offload on
+ # }
+
+ ## Whitelist specific interface by specifying PCI address
+ # dev 0000:02:00.0
+
+ ## Whitelist specific interface by specifying PCI address and in
+ ## addition specify custom parameters for this interface
+ # dev 0000:02:00.1 {
+ # num-rx-queues 2
+ # }
+
+ ## Specify bonded interface and its slaves via PCI addresses
+ ##
+ ## Bonded interface in XOR load balance mode (mode 2) with L3 and L4 headers
+ # vdev eth_bond0,mode=2,slave=0000:02:00.0,slave=0000:03:00.0,xmit_policy=l34
+ # vdev eth_bond1,mode=2,slave=0000:02:00.1,slave=0000:03:00.1,xmit_policy=l34
+ ##
+ ## Bonded interface in Active-Back up mode (mode 1)
+ # vdev eth_bond0,mode=1,slave=0000:02:00.0,slave=0000:03:00.0
+ # vdev eth_bond1,mode=1,slave=0000:02:00.1,slave=0000:03:00.1
+
+ ## Change UIO driver used by VPP, Options are: igb_uio, vfio-pci
+ ## and uio_pci_generic (default)
+ # uio-driver vfio-pci
+
+ ## Disable mutli-segment buffers, improves performance but
+ ## disables Jumbo MTU support
+ # no-multi-seg
+
+ ## Increase number of buffers allocated, needed only in scenarios with
+ ## large number of interfaces and worker threads. Value is per CPU socket.
+ ## Default is 16384
+ # num-mbufs 128000
+
+ ## Change hugepages allocation per-socket, needed only if there is need for
+ ## larger number of mbufs. Default is 256M on each detected CPU socket
+ # socket-mem 2048,2048
+# }
+
+# Adjusting the plugin path depending on where the VPP plugins are:
+#plugins
+#{
+# path /home/bms/vpp/build-root/install-vpp-native/vpp/lib64/vpp_plugins
+#}
+
+# Alternate syntax to choose plugin path
+#plugin_path /home/bms/vpp/build-root/install-vpp-native/vpp/lib64/vpp_plugins
diff --git a/src/vpp/oam/oam.c b/src/vpp/oam/oam.c
new file mode 100644
index 00000000..ef061207
--- /dev/null
+++ b/src/vpp/oam/oam.c
@@ -0,0 +1,644 @@
+/*
+ * 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.
+ */
+#include <vpp/oam/oam.h>
+
+oam_main_t oam_main;
+
+static vlib_node_registration_t oam_node;
+
+static void
+init_oam_packet_template (oam_main_t * om, oam_target_t * t)
+{
+ oam_template_t *h;
+ int i;
+ ip_csum_t sum;
+ u16 csum;
+
+ vec_validate_aligned (t->template, 0, CLIB_CACHE_LINE_BYTES);
+
+ h = t->template;
+ memset (h, 0, sizeof (*h));
+
+ h->ip4.src_address.as_u32 = t->src_address.as_u32;
+ h->ip4.dst_address.as_u32 = t->dst_address.as_u32;
+ h->ip4.ip_version_and_header_length = 0x45;
+ h->ip4.length = clib_host_to_net_u16 (sizeof (*h));
+ h->ip4.ttl = 64; /* as in linux */
+ h->ip4.protocol = IP_PROTOCOL_ICMP;
+ h->ip4.checksum = ip4_header_checksum (&h->ip4);
+
+ /*
+ * Template has seq = 0. Each time we send one of these puppies,
+ * change the sequence number and fix the execrated checksum
+ */
+ h->icmp.type = ICMP4_echo_request;
+ h->id = clib_host_to_net_u16 (t->id);
+
+ for (i = 0; i < ARRAY_LEN (h->data); i++)
+ h->data[i] = 'A' + i;
+
+ sum = ip_incremental_checksum (0, &h->icmp,
+ sizeof (h->icmp) + sizeof (h->id) +
+ sizeof (h->seq) + sizeof (h->data));
+ csum = ~ip_csum_fold (sum);
+ h->icmp.checksum = csum;
+}
+
+int
+vpe_oam_add_del_target (ip4_address_t * src_address,
+ ip4_address_t * dst_address, u32 fib_id, int is_add)
+{
+ u64 key;
+ uword *p;
+ oam_main_t *om = &oam_main;
+ oam_target_t *t;
+ ip4_main_t *im = &ip4_main;
+ u32 fib_index;
+
+ /* Make sure the FIB actually exists */
+ p = hash_get (im->fib_index_by_table_id, fib_id);
+ if (!p)
+ return VNET_API_ERROR_NO_SUCH_FIB;
+
+ fib_index = p[0];
+
+ key = ((u64) fib_index << 32) | (dst_address->as_u32);
+ p = hash_get (om->target_by_address_and_fib_id, key);
+
+ if (is_add)
+ {
+ if (p)
+ return VNET_API_ERROR_INVALID_REGISTRATION; /* already there... */
+
+ pool_get (om->targets, t);
+ memset (t, 0, sizeof (*t));
+ t->src_address.as_u32 = src_address->as_u32;
+ t->dst_address.as_u32 = dst_address->as_u32;
+ t->fib_id = fib_id;
+ t->fib_index = fib_index;
+ t->state = OAM_STATE_DEAD;
+ t->last_heard_time = vlib_time_now (om->vlib_main);
+ t->last_heard_seq = (u16) ~ om->misses_allowed;
+ t->id = (u16) random_u32 (&om->random_seed);
+ t->seq = 1;
+ init_oam_packet_template (om, t);
+ hash_set (om->target_by_address_and_fib_id, key, t - om->targets);
+ }
+ else
+ {
+ if (!p)
+ return VNET_API_ERROR_NO_SUCH_ENTRY; /* no such oam target */
+ t = pool_elt_at_index (om->targets, p[0]);
+ vec_free (t->template);
+ hash_unset (om->target_by_address_and_fib_id, key);
+ pool_put (om->targets, t);
+ }
+ return 0;
+}
+
+static clib_error_t *
+oam_add_del_target_command_fn (vlib_main_t * vm,
+ unformat_input_t * input,
+ vlib_cli_command_t * cmd)
+{
+ int is_add = -1;
+ ip4_address_t src_address;
+ int src_set = 0;
+ ip4_address_t dst_address;
+ int dst_set = 0;
+ u32 fib_id = 0;
+
+ while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (input, "add"))
+ is_add = 1;
+ else if (unformat (input, "del"))
+ is_add = 0;
+ else if (unformat (input, "src %U", unformat_ip4_address, &src_address))
+ src_set = 1;
+ else if (unformat (input, "dst %U", unformat_ip4_address, &dst_address))
+ dst_set = 1;
+ else if (unformat (input, "fib %d", &fib_id))
+ ;
+ else
+ return clib_error_return (0, "unknown input `%U'",
+ format_unformat_error, input);
+ }
+
+ if (is_add == -1)
+ return clib_error_return (0, "missing add / del qualifier");
+ if (src_set == 0)
+ return clib_error_return (0, "src address not set");
+ if (dst_set == 0)
+ return clib_error_return (0, "dst address not set");
+
+ (void) vpe_oam_add_del_target (&src_address, &dst_address, fib_id, is_add);
+
+ return 0;
+}
+
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND (oam_add_del_target_command, static) = {
+ .path = "oam",
+ .short_help = "oam [add|del] target <ip4-address> fib <fib-id>",
+ .function = oam_add_del_target_command_fn,
+};
+/* *INDENT-ON* */
+
+static uword
+oam_process (vlib_main_t * vm, vlib_node_runtime_t * rt, vlib_frame_t * f_arg)
+{
+ oam_main_t *om = &oam_main;
+ uword *event_data = 0;
+ oam_target_t *t;
+ oam_template_t *h0;
+ u32 bi0;
+ u16 new_seq;
+ ip_csum_t sum0;
+ vlib_frame_t *f;
+ u32 *to_next, *from;
+ u32 ip4_lookup_node_index;
+ vlib_node_t *ip4_lookup_node;
+ vlib_buffer_t *b0;
+ static u32 *buffers;
+ oam_template_copy_t *copy_src, *copy_dst;
+ void send_oam_event (oam_target_t * t);
+ u32 nalloc;
+
+ /* Enqueue pkts to ip4-lookup */
+ ip4_lookup_node = vlib_get_node_by_name (vm, (u8 *) "ip4-lookup");
+ ip4_lookup_node_index = ip4_lookup_node->index;
+
+ while (1)
+ {
+ /* Only timeout events at the moment */
+ vlib_process_wait_for_event_or_clock (vm, om->interval);
+ vec_reset_length (event_data);
+
+ if (pool_elts (om->targets) == 0)
+ continue;
+
+ if (vec_len (buffers) < pool_elts (om->targets))
+ vec_validate (buffers, pool_elts (om->targets) - 1);
+
+ nalloc = vlib_buffer_alloc (vm, buffers, pool_elts (om->targets));
+ if (nalloc < pool_elts (om->targets))
+ {
+ vlib_buffer_free (vm, buffers, nalloc);
+ continue;
+ }
+
+ f = vlib_get_frame_to_node (vm, ip4_lookup_node_index);
+ f->n_vectors = 0;
+ to_next = vlib_frame_vector_args (f);
+ from = buffers;
+
+ /* *INDENT-OFF* */
+ pool_foreach (t, om->targets,
+ ({
+ /* State transition announcement... */
+ if ((t->seq - t->last_heard_seq) >= om->misses_allowed)
+ {
+ if (t->state == OAM_STATE_ALIVE)
+ {
+ if (CLIB_DEBUG > 0)
+ clib_warning ("oam target %U now DEAD",
+ format_ip4_address, &t->dst_address);
+ t->state = OAM_STATE_DEAD;
+ send_oam_event (t);
+ }
+ }
+ else
+ {
+ if (t->state == OAM_STATE_DEAD)
+ {
+ if (CLIB_DEBUG > 0)
+ clib_warning ("oam target %U now ALIVE",
+ format_ip4_address, &t->dst_address);
+ t->state = OAM_STATE_ALIVE;
+ send_oam_event (t);
+ }
+ }
+
+ /* Send a new icmp */
+ t->seq++;
+ new_seq = clib_host_to_net_u16 (t->seq);
+
+ bi0 = from[0];
+ from++;
+
+ b0 = vlib_get_buffer (vm, bi0);
+ vnet_buffer (b0)->sw_if_index[VLIB_RX] = 0;
+ vnet_buffer (b0)->sw_if_index [VLIB_TX] = t->fib_index;
+
+ /* Marginally faster than memcpy, probably */
+ copy_dst = (oam_template_copy_t *) b0->data;
+ copy_src = (oam_template_copy_t *) t->template;
+
+ copy_dst->v8[0] = copy_src->v8[0];
+ copy_dst->v8[1] = copy_src->v8[1];
+ copy_dst->v8[2] = copy_src->v8[2];
+ copy_dst->v8[3] = copy_src->v8[3];
+ copy_dst->v4 = copy_src->v4;
+
+ b0->current_data = 0;
+ b0->current_length = sizeof (*t->template);
+ h0 = vlib_buffer_get_current (b0);
+
+ sum0 = h0->icmp.checksum;
+ sum0 = ip_csum_update(sum0, 0 /* old seq */,
+ new_seq, oam_template_t, seq);
+ h0->seq = new_seq;
+ h0->icmp.checksum = ip_csum_fold (sum0);
+
+ to_next[0] = bi0;
+ to_next++;
+ f->n_vectors++;
+ if (f->n_vectors == VLIB_FRAME_SIZE)
+ {
+ clib_warning ("Too many OAM clients...");
+ goto out;
+ }
+ }));
+ /* *INDENT-ON* */
+
+ out:
+ vlib_put_frame_to_node (vm, ip4_lookup_node_index, f);
+ }
+ return 0; /* not so much */
+}
+
+/* *INDENT-OFF* */
+VLIB_REGISTER_NODE (oam_process_node,static) = {
+ .function = oam_process,
+ .type = VLIB_NODE_TYPE_PROCESS,
+ .name = "vpe-oam-process",
+};
+/* *INDENT-ON* */
+
+static clib_error_t *
+oam_config (vlib_main_t * vm, unformat_input_t * input)
+{
+ oam_main_t *om = &oam_main;
+ f64 interval;
+ u32 misses_allowed;
+
+ while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (input, "interval %f", &interval))
+ om->interval = interval;
+ else if (unformat (input, "misses-allowed %d", &misses_allowed))
+ om->interval = misses_allowed;
+ else
+ return clib_error_return (0, "unknown input `%U'",
+ format_unformat_error, input);
+ }
+ return 0;
+}
+
+VLIB_CONFIG_FUNCTION (oam_config, "oam");
+
+static clib_error_t *
+oam_init (vlib_main_t * vm)
+{
+ oam_main_t *om = &oam_main;
+
+ om->vlib_main = vm;
+ om->vnet_main = vnet_get_main ();
+ om->interval = 2.04;
+ om->misses_allowed = 3;
+ om->random_seed = (u32) (vlib_time_now (vm) * 1e6);
+ om->target_by_address_and_fib_id = hash_create (0, sizeof (uword));
+ om->icmp_id = random_u32 (&om->random_seed);
+
+ ip4_icmp_register_type (vm, ICMP4_echo_reply, oam_node.index);
+
+ return 0;
+}
+
+VLIB_INIT_FUNCTION (oam_init);
+
+static u8 *
+format_oam_target (u8 * s, va_list * args)
+{
+ oam_target_t *t = va_arg (*args, oam_target_t *);
+ int verbose = va_arg (*args, int);
+
+ if (t == 0)
+ return format (s, "%=6s%=14s%=14s%=12s%=10s",
+ "Fib", "Src", "Dst", "Last Heard", "State");
+
+ s = format (s, "%=6d%=14U%=14U%=12.2f%=10s",
+ t->fib_id,
+ format_ip4_address, &t->src_address,
+ format_ip4_address, &t->dst_address,
+ t->last_heard_time,
+ (t->state == OAM_STATE_ALIVE) ? "alive" : "dead");
+ if (verbose)
+ s = format (s, " seq %d last_heard_seq %d", t->seq, t->last_heard_seq);
+
+ return s;
+}
+
+static clib_error_t *
+show_oam_command_fn (vlib_main_t * vm,
+ unformat_input_t * input, vlib_cli_command_t * cmd)
+{
+ oam_main_t *om = &oam_main;
+ oam_target_t *t;
+ int verbose = 0;
+
+ if (unformat (input, "verbose") || unformat (input, "v"))
+ verbose = 1;
+
+ /* print header */
+ vlib_cli_output (vm, "%U", format_oam_target, 0, verbose);
+
+ /* *INDENT-OFF* */
+ pool_foreach (t, om->targets,
+ ({
+ vlib_cli_output (vm, "%U", format_oam_target, t, verbose);
+ }));
+ /* *INDENT-ON* */
+
+ return 0;
+}
+
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND (show_oam_command, static) = {
+ .path = "show oam",
+ .short_help = "show oam",
+ .function = show_oam_command_fn,
+};
+/* *INDENT-ON* */
+
+typedef struct
+{
+ u32 target_pool_index;
+ ip4_address_t address;
+} oam_trace_t;
+
+/* packet trace format function */
+static u8 *
+format_swap_trace (u8 * s, va_list * args)
+{
+ CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
+ CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
+ oam_trace_t *t = va_arg (*args, oam_trace_t *);
+
+ s = format (s, "OAM: rx from address %U, target index %d",
+ format_ip4_address, &t->address, t->target_pool_index);
+ return s;
+}
+
+
+#define foreach_oam_error \
+_(PROCESSED, "vpe icmp4 oam replies processed") \
+_(DROPPED, "icmp4 replies dropped (no registration)")
+
+typedef enum
+{
+#define _(sym,str) OAM_ERROR_##sym,
+ foreach_oam_error
+#undef _
+ OAM_N_ERROR,
+} oam_error_t;
+
+static char *oam_error_strings[] = {
+#define _(sym,string) string,
+ foreach_oam_error
+#undef _
+};
+
+/*
+ * To drop a pkt and increment one of the previous counters:
+ *
+ * set b0->error = error_node->errors[OAM_ERROR_EXAMPLE];
+ * set next0 to a disposition index bound to "error-drop".
+ *
+ * To manually increment the specific counter OAM_ERROR_EXAMPLE:
+ *
+ * vlib_node_t *n = vlib_get_node (vm, oam.index);
+ * u32 node_counter_base_index = n->error_heap_index;
+ * vlib_error_main_t * em = &vm->error_main;
+ * em->counters[node_counter_base_index + OAM_ERROR_EXAMPLE] += 1;
+ *
+ */
+
+typedef enum
+{
+ OAM_NEXT_DROP,
+ OAM_NEXT_PUNT,
+ OAM_N_NEXT,
+} oam_next_t;
+
+static uword
+oam_node_fn (vlib_main_t * vm,
+ vlib_node_runtime_t * node, vlib_frame_t * frame)
+{
+ u32 n_left_from, *from, *to_next;
+ oam_next_t next_index;
+ oam_main_t *om = &oam_main;
+ u32 next0 = OAM_NEXT_DROP; /* all pkts go to the hopper... */
+ u32 next1 = OAM_NEXT_DROP;
+ uword *u0, *u1;
+ oam_template_t *oam0, *oam1;
+ u32 fib_index0, fib_index1;
+ u64 key0, key1;
+ oam_target_t *t0, *t1;
+ ip4_main_t *im = &ip4_main;
+
+ from = vlib_frame_vector_args (frame);
+ n_left_from = frame->n_vectors;
+ next_index = node->cached_next_index;
+
+ while (n_left_from > 0)
+ {
+ u32 n_left_to_next;
+
+ vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
+
+ while (n_left_from >= 4 && n_left_to_next >= 2)
+ {
+ u32 bi0, bi1;
+ vlib_buffer_t *b0, *b1;
+ u32 sw_if_index0, sw_if_index1;
+
+ /* Prefetch next iteration. */
+ {
+ vlib_buffer_t *p2, *p3;
+
+ p2 = vlib_get_buffer (vm, from[2]);
+ p3 = vlib_get_buffer (vm, from[3]);
+
+ vlib_prefetch_buffer_header (p2, LOAD);
+ vlib_prefetch_buffer_header (p3, LOAD);
+
+ CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, STORE);
+ CLIB_PREFETCH (p3->data, CLIB_CACHE_LINE_BYTES, STORE);
+ }
+
+ /* speculatively enqueue b0 and b1 to the current next frame */
+ to_next[0] = bi0 = from[0];
+ to_next[1] = bi1 = from[1];
+ from += 2;
+ to_next += 2;
+ n_left_from -= 2;
+ n_left_to_next -= 2;
+
+ b0 = vlib_get_buffer (vm, bi0);
+ b1 = vlib_get_buffer (vm, bi1);
+
+ sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
+ sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];
+
+ oam0 = vlib_buffer_get_current (b0);
+ oam1 = vlib_buffer_get_current (b1);
+ fib_index0 = vec_elt (im->fib_index_by_sw_if_index, sw_if_index0);
+ fib_index1 = vec_elt (im->fib_index_by_sw_if_index, sw_if_index1);
+
+ key0 = ((u64) fib_index0 << 32) | oam0->ip4.src_address.as_u32;
+ u0 = hash_get (om->target_by_address_and_fib_id, key0);
+ if (u0)
+ {
+ t0 = pool_elt_at_index (om->targets, u0[0]);
+ t0->last_heard_time = vlib_time_now (vm);
+ t0->last_heard_seq = clib_net_to_host_u16 (oam0->seq);
+ b0->error = node->errors[OAM_ERROR_PROCESSED];
+ }
+ else
+ b0->error = node->errors[OAM_ERROR_DROPPED];
+
+ key1 = ((u64) fib_index1 << 32) | oam1->ip4.src_address.as_u32;
+ u1 = hash_get (om->target_by_address_and_fib_id, key1);
+ if (u1)
+ {
+ t1 = pool_elt_at_index (om->targets, u1[0]);
+ t1->last_heard_time = vlib_time_now (vm);
+ t1->last_heard_seq = clib_net_to_host_u16 (oam1->seq);
+ b1->error = node->errors[OAM_ERROR_PROCESSED];
+ }
+ else
+ b1->error = node->errors[OAM_ERROR_DROPPED];
+
+ if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
+ {
+ if (b0->flags & VLIB_BUFFER_IS_TRACED)
+ {
+ oam_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t));
+ t->target_pool_index = u0 ? u0[0] : (u32) ~ 0;
+ t->address.as_u32 = oam0->ip4.src_address.as_u32;
+ }
+ if (b1->flags & VLIB_BUFFER_IS_TRACED)
+ {
+ oam_trace_t *t = vlib_add_trace (vm, node, b1, sizeof (*t));
+ t->target_pool_index = u1 ? u1[0] : (u32) ~ 0;
+ t->address.as_u32 = oam1->ip4.src_address.as_u32;
+
+ }
+ }
+
+ if (vm->os_punt_frame)
+ next0 = next1 = OAM_NEXT_PUNT;
+
+ /* verify speculative enqueues, maybe switch current next frame */
+ vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
+ to_next, n_left_to_next,
+ bi0, bi1, next0, next1);
+ }
+
+ while (n_left_from > 0 && n_left_to_next > 0)
+ {
+ u32 bi0, sw_if_index0;
+ vlib_buffer_t *b0;
+
+ /* speculatively enqueue b0 to the current next frame */
+ bi0 = from[0];
+ to_next[0] = bi0;
+ from += 1;
+ to_next += 1;
+ n_left_from -= 1;
+ n_left_to_next -= 1;
+
+ b0 = vlib_get_buffer (vm, bi0);
+
+ sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
+
+ oam0 = vlib_buffer_get_current (b0);
+ fib_index0 = vec_elt (im->fib_index_by_sw_if_index, sw_if_index0);
+
+ key0 = ((u64) fib_index0 << 32) | oam0->ip4.src_address.as_u32;
+ u0 = hash_get (om->target_by_address_and_fib_id, key0);
+ if (u0)
+ {
+ t0 = pool_elt_at_index (om->targets, u0[0]);
+ t0->last_heard_time = vlib_time_now (vm);
+ t0->last_heard_seq = clib_net_to_host_u16 (oam0->seq);
+ b0->error = node->errors[OAM_ERROR_PROCESSED];
+ }
+ else
+ b0->error = node->errors[OAM_ERROR_DROPPED];
+
+ if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
+ && (b0->flags & VLIB_BUFFER_IS_TRACED)))
+ {
+ oam_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t));
+ t->target_pool_index = u0 ? u0[0] : (u32) ~ 0;
+ t->address.as_u32 = oam0->ip4.src_address.as_u32;
+ }
+
+ if (vm->os_punt_frame)
+ next0 = OAM_NEXT_PUNT;
+
+ /* verify speculative enqueue, maybe switch current next frame */
+ vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
+ to_next, n_left_to_next,
+ bi0, next0);
+ }
+
+ vlib_put_next_frame (vm, node, next_index, n_left_to_next);
+ }
+
+ return frame->n_vectors;
+}
+
+/* *INDENT-OFF* */
+VLIB_REGISTER_NODE (oam_node,static) = {
+ .function = oam_node_fn,
+ .name = "vpe-icmp4-oam",
+ .vector_size = sizeof (u32),
+ .format_trace = format_swap_trace,
+ .type = VLIB_NODE_TYPE_INTERNAL,
+
+ .n_errors = ARRAY_LEN(oam_error_strings),
+ .error_strings = oam_error_strings,
+
+ .n_next_nodes = OAM_N_NEXT,
+
+ /* edit / add dispositions here */
+ .next_nodes = {
+ [OAM_NEXT_DROP] = "error-drop",
+ [OAM_NEXT_PUNT] = "error-punt",
+ },
+};
+/* *INDENT-ON* */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/src/vpp/oam/oam.h b/src/vpp/oam/oam.h
new file mode 100644
index 00000000..f6af9788
--- /dev/null
+++ b/src/vpp/oam/oam.h
@@ -0,0 +1,96 @@
+/*
+ * 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.
+ */
+#ifndef __included_oam_h__
+#define __included_oam_h__
+
+#include <vlib/vlib.h>
+#include <vnet/vnet.h>
+#include <vnet/ip/ip.h>
+#include <vnet/interface.h>
+
+/* 36 octets, make a note of it... */
+/* *INDENT-OFF* */
+typedef CLIB_PACKED (struct {
+ ip4_header_t ip4;
+ icmp46_header_t icmp;
+ u16 id;
+ u16 seq;
+ u8 data[8];
+}) oam_template_t;
+/* *INDENT-ON* */
+
+/* *INDENT-OFF* */
+typedef CLIB_PACKED (struct {
+ u64 v8[4];
+ u32 v4;
+}) oam_template_copy_t;
+/* *INDENT-ON* */
+
+typedef enum
+{
+ OAM_STATE_UNKNOWN = 0,
+ OAM_STATE_ALIVE,
+ OAM_STATE_DEAD,
+} oam_state_t;
+
+typedef struct
+{
+ ip4_address_t src_address;
+ ip4_address_t dst_address;
+ u32 fib_id;
+ u32 fib_index;
+ f64 last_heard_time;
+ u16 seq;
+ u16 last_heard_seq;
+ u16 id;
+ u8 state;
+ oam_template_t *template;
+} oam_target_t;
+
+typedef struct
+{
+ /* OAM targets */
+ oam_target_t *targets;
+ uword *target_by_address_and_fib_id;
+
+ /* Config parameters */
+ f64 interval;
+ u32 misses_allowed;
+
+ /* random number seed */
+ u32 random_seed;
+ u16 icmp_id;
+
+ /* oam packet template */
+ vlib_packet_template_t packet_template;
+
+ /* convenience */
+ vlib_main_t *vlib_main;
+ vnet_main_t *vnet_main;
+} oam_main_t;
+
+int vpe_oam_add_del_target (ip4_address_t * src_address,
+ ip4_address_t * dst_address,
+ u32 fib_id, int is_add);
+
+#endif /* __included_oam_h__ */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/src/vpp/stats/stats.api b/src/vpp/stats/stats.api
new file mode 100644
index 00000000..caf8f515
--- /dev/null
+++ b/src/vpp/stats/stats.api
@@ -0,0 +1,265 @@
+/*
+ * Copyright (c) 2015-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.
+ */
+
+/** \file
+
+ This file defines the stats API
+*/
+
+
+/** \brief Want Stats, enable/disable ALL stats updates
+ @param client_index - opaque cookie to identify the sender
+ @param context - sender context, to match reply w/ request
+ @param enable_disable - 1 = enable stats, 0 = disable
+ @param pid - pid of process requesting stats updates
+*/
+autoreply define want_stats
+{
+ u32 client_index;
+ u32 context;
+ u32 enable_disable;
+ u32 pid;
+};
+
+/** \brief Want Interface Simple Stats, register for detailed interface stats
+ @param client_index - opaque cookie to identify the sender
+ @param context - sender context, to match reply w/ request
+ @param enable_disable - 1 = enable stats, 0 = disable
+ @param pid - pid of process requesting stats updates
+
+ Please consider using want_per_interface_simple_stats with sw_if_index=~0
+*/
+autoreply define want_interface_simple_stats
+{
+ u32 client_index;
+ u32 context;
+ u32 enable_disable;
+ u32 pid;
+};
+
+/** \brief Want Per Interface simple Stats, register for continuous stats
+ @param client_index - opaque cookie to identify the sender
+ @param context - sender context, to match reply w/ request
+ @param enable_disable - 1 = enable stats, 0 = disable
+ @param pid - pid of process requesting stats updates
+ @param num - number of sw_if_indexes
+ @param sw_ifs - array of sw_if_index
+*/
+autoreply define want_per_interface_simple_stats
+{
+ u32 client_index;
+ u32 context;
+ u32 enable_disable;
+ u32 pid;
+ u32 num;
+ u32 sw_ifs[num];
+
+};
+
+/** \brief Want Interface Combined Stats, register for continuous stats
+ @param client_index - opaque cookie to identify the sender
+ @param context - sender context, to match reply w/ request
+ @param enable_disable - 1 = enable stats, 0 = disable
+ @param pid - pid of process requesting stats updates
+
+ Please consider using want_per_interface_combined_stats with sw_if_index=~0
+
+*/
+autoreply define want_interface_combined_stats
+{
+ u32 client_index;
+ u32 context;
+ u32 enable_disable;
+ u32 pid;
+};
+
+/** \brief Want Per Interface Combined Stats, register for continuous stats
+ @param client_index - opaque cookie to identify the sender
+ @param context - sender context, to match reply w/ request
+ @param enable_disable - 1 = enable stats, 0 = disable
+ @param pid - pid of process requesting stats updates
+ @param num - number of sw_if_indexes
+ @param sw_ifs - array of sw_if_index
+*/
+autoreply define want_per_interface_combined_stats
+{
+ u32 client_index;
+ u32 context;
+ u32 enable_disable;
+ u32 pid;
+ u32 num;
+ u32 sw_ifs[num];
+
+};
+
+/** \brief Want IP4 FIB Stats, register for continuous stats
+ @param client_index - opaque cookie to identify the sender
+ @param context - sender context, to match reply w/ request
+ @param enable_disable - 1 = enable stats, 0 = disable
+ @param pid - pid of process requesting stats updates
+*/
+autoreply define want_ip4_fib_stats
+{
+ u32 client_index;
+ u32 context;
+ u32 enable_disable;
+ u32 pid;
+};
+
+/** \brief Want IP6 FIB Stats, register for continuous stats
+ @param client_index - opaque cookie to identify the sender
+ @param context - sender context, to match reply w/ request
+ @param enable_disable - 1 = enable stats, 0 = disable
+ @param pid - pid of process requesting stats updates
+*/
+autoreply define want_ip6_fib_stats
+{
+ u32 client_index;
+ u32 context;
+ u32 enable_disable;
+ u32 pid;
+};
+
+/** \brief Want IP4 NBR Stats, register for continuous stats
+ @param client_index - opaque cookie to identify the sender
+ @param context - sender context, to match reply w/ request
+ @param enable_disable - 1 = enable stats, 0 = disable
+ @param pid - pid of process requesting stats updates
+*/
+autoreply define want_ip4_nbr_stats
+{
+ u32 client_index;
+ u32 context;
+ u32 enable_disable;
+ u32 pid;
+};
+
+/** \brief Want IP6 NBR Stats, register for continuous stats
+ @param client_index - opaque cookie to identify the sender
+ @param context - sender context, to match reply w/ request
+ @param enable_disable - 1 = enable stats, 0 = disable
+ @param pid - pid of process requesting stats updates
+*/
+autoreply define want_ip6_nbr_stats
+{
+ u32 client_index;
+ u32 context;
+ u32 enable_disable;
+ u32 pid;
+};
+
+typeonly manual_print manual_endian define ip4_fib_counter
+{
+ u32 address;
+ u8 address_length;
+ u64 packets;
+ u64 bytes;
+};
+
+manual_print manual_endian define vnet_ip4_fib_counters
+{
+ u32 vrf_id;
+ u32 count;
+ vl_api_ip4_fib_counter_t c[count];
+};
+
+typeonly manual_print manual_endian define ip4_nbr_counter
+{
+ u32 address;
+ u8 link_type;
+ u64 packets;
+ u64 bytes;
+};
+
+/**
+ * @brief Per-neighbour (i.e. per-adjacency) coutners
+ * @param count The size of the array of counters
+ * @param sw_if_index The interface the adjacency is on
+ * @param begin Flag to indicate this is the first set of stats for this
+ * interface. If this flag is not set the it is a continuation of
+ * stats for this interface
+ * @param c counters
+ */
+manual_print manual_endian define vnet_ip4_nbr_counters
+{
+ u32 count;
+ u32 sw_if_index;
+ u8 begin;
+ vl_api_ip4_nbr_counter_t c[count];
+};
+
+typeonly manual_print manual_endian define ip6_fib_counter
+{
+ u64 address[2];
+ u8 address_length;
+ u64 packets;
+ u64 bytes;
+};
+
+manual_print manual_endian define vnet_ip6_fib_counters
+{
+ u32 vrf_id;
+ u32 count;
+ vl_api_ip6_fib_counter_t c[count];
+};
+
+typeonly manual_print manual_endian define ip6_nbr_counter
+{
+ u64 address[2];
+ u8 link_type;
+ u64 packets;
+ u64 bytes;
+};
+
+manual_print manual_endian define vnet_ip6_nbr_counters
+{
+ u32 count;
+ u32 sw_if_index;
+ u8 begin;
+ vl_api_ip6_nbr_counter_t c[count];
+};
+
+
+/** \brief Request for a single block of summary stats
+ @param client_index - opaque cookie to identify the sender
+ @param context - sender context, to match reply w/ request
+*/
+define vnet_get_summary_stats
+{
+ u32 client_index;
+ u32 context;
+};
+
+/** \brief Reply for vnet_get_summary_stats request
+ @param context - sender context, to match reply w/ request
+ @param retval - return code for request
+ @param total_pkts -
+ @param total_bytes -
+ @param vector_rate -
+*/
+define vnet_get_summary_stats_reply
+{
+ u32 context;
+ i32 retval;
+ u64 total_pkts[2];
+ u64 total_bytes[2];
+ f64 vector_rate;
+};
+
+/*
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/src/vpp/stats/stats.c b/src/vpp/stats/stats.c
new file mode 100644
index 00000000..ac364e88
--- /dev/null
+++ b/src/vpp/stats/stats.c
@@ -0,0 +1,2410 @@
+/*
+ * 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.
+ */
+#include <vpp/stats/stats.h>
+#include <signal.h>
+#include <vnet/fib/ip4_fib.h>
+#include <vnet/fib/fib_entry.h>
+#include <vnet/dpo/load_balance.h>
+
+#define STATS_DEBUG 0
+
+stats_main_t stats_main;
+
+#include <vnet/ip/ip.h>
+
+#include <vpp/api/vpe_msg_enum.h>
+
+#define f64_endian(a)
+#define f64_print(a,b)
+
+#define vl_typedefs /* define message structures */
+#include <vpp/api/vpe_all_api_h.h>
+#undef vl_typedefs
+
+#define vl_endianfun /* define message structures */
+#include <vpp/api/vpe_all_api_h.h>
+#undef vl_endianfun
+
+/* instantiate all the print functions we know about */
+#define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
+#define vl_printfun
+#include <vpp/api/vpe_all_api_h.h>
+#undef vl_printfun
+
+#define foreach_stats_msg \
+_(WANT_STATS, want_stats) \
+_(VNET_INTERFACE_SIMPLE_COUNTERS, vnet_interface_simple_counters) \
+_(WANT_INTERFACE_SIMPLE_STATS, want_interface_simple_stats) \
+_(VNET_INTERFACE_COMBINED_COUNTERS, vnet_interface_combined_counters) \
+_(WANT_INTERFACE_COMBINED_STATS, want_interface_combined_stats) \
+_(WANT_PER_INTERFACE_COMBINED_STATS, want_per_interface_combined_stats) \
+_(WANT_PER_INTERFACE_SIMPLE_STATS, want_per_interface_simple_stats) \
+_(VNET_IP4_FIB_COUNTERS, vnet_ip4_fib_counters) \
+_(WANT_IP4_FIB_STATS, want_ip4_fib_stats) \
+_(VNET_IP6_FIB_COUNTERS, vnet_ip6_fib_counters) \
+_(WANT_IP6_FIB_STATS, want_ip6_fib_stats) \
+_(VNET_IP4_NBR_COUNTERS, vnet_ip4_nbr_counters) \
+_(WANT_IP4_NBR_STATS, want_ip4_nbr_stats) \
+_(VNET_IP6_NBR_COUNTERS, vnet_ip6_nbr_counters) \
+_(WANT_IP6_NBR_STATS, want_ip6_nbr_stats) \
+_(VNET_GET_SUMMARY_STATS, vnet_get_summary_stats)
+
+
+#define vl_msg_name_crc_list
+#include <vpp/stats/stats.api.h>
+#undef vl_msg_name_crc_list
+
+static void
+setup_message_id_table (api_main_t * am)
+{
+#define _(id,n,crc) \
+ vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id);
+ foreach_vl_msg_name_crc_stats;
+#undef _
+}
+
+/* These constants ensure msg sizes <= 1024, aka ring allocation */
+#define SIMPLE_COUNTER_BATCH_SIZE 126
+#define COMBINED_COUNTER_BATCH_SIZE 63
+#define IP4_FIB_COUNTER_BATCH_SIZE 48
+#define IP6_FIB_COUNTER_BATCH_SIZE 30
+
+/* 5ms */
+#define STATS_RELEASE_DELAY_NS (1000 * 1000 * 5)
+/* ns/us us/ms */
+
+u8 *
+format_vnet_interface_combined_counters (u8 * s, va_list * args)
+{
+ stats_main_t *sm = &stats_main;
+ vl_api_vnet_interface_combined_counters_t *mp =
+ va_arg (*args, vl_api_vnet_interface_combined_counters_t *);
+
+ char *counter_name;
+ u32 count, sw_if_index;
+ int i;
+ count = ntohl (mp->count);
+ sw_if_index = ntohl (mp->first_sw_if_index);
+
+ vlib_counter_t *vp;
+ u64 packets, bytes;
+ vp = (vlib_counter_t *) mp->data;
+
+ switch (mp->vnet_counter_type)
+ {
+ case VNET_INTERFACE_COUNTER_RX:
+ counter_name = "rx";
+ break;
+ case VNET_INTERFACE_COUNTER_TX:
+ counter_name = "tx";
+ break;
+ default:
+ counter_name = "bogus";
+ break;
+ }
+ for (i = 0; i < count; i++)
+ {
+ packets = clib_mem_unaligned (&vp->packets, u64);
+ packets = clib_net_to_host_u64 (packets);
+ bytes = clib_mem_unaligned (&vp->bytes, u64);
+ bytes = clib_net_to_host_u64 (bytes);
+ vp++;
+ s = format (s, "%U.%s.packets %lld\n",
+ format_vnet_sw_if_index_name,
+ sm->vnet_main, sw_if_index, counter_name, packets);
+ s = format (s, "%U.%s.bytes %lld\n",
+ format_vnet_sw_if_index_name,
+ sm->vnet_main, sw_if_index, counter_name, bytes);
+ sw_if_index++;
+ }
+ return s;
+}
+
+u8 *
+format_vnet_interface_simple_counters (u8 * s, va_list * args)
+{
+ stats_main_t *sm = &stats_main;
+ vl_api_vnet_interface_simple_counters_t *mp =
+ va_arg (*args, vl_api_vnet_interface_simple_counters_t *);
+ char *counter_name;
+ u32 count, sw_if_index;
+ count = ntohl (mp->count);
+ sw_if_index = ntohl (mp->first_sw_if_index);
+ u64 *vp, v;
+ vp = (u64 *) mp->data;
+ int i;
+
+ switch (mp->vnet_counter_type)
+ {
+ case VNET_INTERFACE_COUNTER_DROP:
+ counter_name = "drop";
+ break;
+ case VNET_INTERFACE_COUNTER_PUNT:
+ counter_name = "punt";
+ break;
+ case VNET_INTERFACE_COUNTER_IP4:
+ counter_name = "ip4";
+ break;
+ case VNET_INTERFACE_COUNTER_IP6:
+ counter_name = "ip6";
+ break;
+ case VNET_INTERFACE_COUNTER_RX_NO_BUF:
+ counter_name = "rx-no-buff";
+ break;
+ case VNET_INTERFACE_COUNTER_RX_MISS:
+ counter_name = "rx-miss";
+ break;
+ case VNET_INTERFACE_COUNTER_RX_ERROR:
+ counter_name = "rx-error (fifo-full)";
+ break;
+ case VNET_INTERFACE_COUNTER_TX_ERROR:
+ counter_name = "tx-error (fifo-full)";
+ break;
+ default:
+ counter_name = "bogus";
+ break;
+ }
+ for (i = 0; i < count; i++)
+ {
+ v = clib_mem_unaligned (vp, u64);
+ v = clib_net_to_host_u64 (v);
+ vp++;
+ s = format (s, "%U.%s %lld\n", format_vnet_sw_if_index_name,
+ sm->vnet_main, sw_if_index, counter_name, v);
+ sw_if_index++;
+ }
+
+ return s;
+}
+
+void
+dslock (stats_main_t * sm, int release_hint, int tag)
+{
+ u32 thread_index;
+ data_structure_lock_t *l = sm->data_structure_lock;
+
+ if (PREDICT_FALSE (l == 0))
+ return;
+
+ thread_index = vlib_get_thread_index ();
+ if (l->lock && l->thread_index == thread_index)
+ {
+ l->count++;
+ return;
+ }
+
+ if (release_hint)
+ l->release_hint++;
+
+ while (__sync_lock_test_and_set (&l->lock, 1))
+ /* zzzz */ ;
+ l->tag = tag;
+ l->thread_index = thread_index;
+ l->count = 1;
+}
+
+void
+stats_dslock_with_hint (int hint, int tag)
+{
+ stats_main_t *sm = &stats_main;
+ dslock (sm, hint, tag);
+}
+
+void
+dsunlock (stats_main_t * sm)
+{
+ u32 thread_index;
+ data_structure_lock_t *l = sm->data_structure_lock;
+
+ if (PREDICT_FALSE (l == 0))
+ return;
+
+ thread_index = vlib_get_thread_index ();
+ ASSERT (l->lock && l->thread_index == thread_index);
+ l->count--;
+ if (l->count == 0)
+ {
+ l->tag = -l->tag;
+ l->release_hint = 0;
+ CLIB_MEMORY_BARRIER ();
+ l->lock = 0;
+ }
+}
+
+void
+stats_dsunlock (int hint, int tag)
+{
+ stats_main_t *sm = &stats_main;
+ dsunlock (sm);
+}
+
+static vpe_client_registration_t *
+get_client_for_stat (u32 reg, u32 item, u32 client_index)
+{
+ stats_main_t *sm = &stats_main;
+ vpe_client_stats_registration_t *registration;
+ uword *p;
+
+ /* Is there anything listening for item in that reg */
+ p = hash_get (sm->stats_registration_hash[reg], item);
+
+ if (!p)
+ return 0; // Fail
+
+ /* If there is, is our client_index one of them */
+ registration = pool_elt_at_index (sm->stats_registrations[reg], p[0]);
+ p = hash_get (registration->client_hash, client_index);
+
+ if (!p)
+ return 0; // Fail
+
+ return pool_elt_at_index (registration->clients, p[0]);
+
+}
+
+static int
+set_client_for_stat (u32 reg, u32 item, vpe_client_registration_t * client)
+{
+ stats_main_t *sm = &stats_main;
+ vpe_client_stats_registration_t *registration;
+ vpe_client_registration_t *cr;
+ uword *p;
+
+ /* Is there anything listening for item in that reg */
+ p = hash_get (sm->stats_registration_hash[reg], item);
+
+ if (!p)
+ {
+ pool_get (sm->stats_registrations[reg], registration);
+ registration->item = item;
+ hash_set (sm->stats_registration_hash[reg], item,
+ registration - sm->stats_registrations[reg]);
+ }
+ else
+ {
+ registration = pool_elt_at_index (sm->stats_registrations[reg], p[0]);
+ }
+
+ p = hash_get (registration->client_hash, client->client_index);
+
+ if (!p)
+ {
+ pool_get (registration->clients, cr);
+ cr->client_index = client->client_index;
+ cr->client_pid = client->client_pid;
+ hash_set (registration->client_hash, cr->client_index,
+ cr - registration->clients);
+ }
+
+ return 1; //At least one client is doing something ... poll
+}
+
+int
+clear_client_for_stat (u32 reg, u32 item, u32 client_index)
+{
+ stats_main_t *sm = &stats_main;
+ vpe_client_stats_registration_t *registration;
+ vpe_client_registration_t *client;
+ uword *p;
+ int i, elts;
+
+ /* Clear the client first */
+ /* Is there anything listening for item in that reg */
+ p = hash_get (sm->stats_registration_hash[reg], item);
+
+ if (!p)
+ goto exit;
+
+ /* If there is, is our client_index one of them */
+ registration = pool_elt_at_index (sm->stats_registrations[reg], p[0]);
+ p = hash_get (registration->client_hash, client_index);
+
+ if (!p)
+ goto exit;
+
+ client = pool_elt_at_index (registration->clients, p[0]);
+ hash_unset (registration->client_hash, client->client_index);
+ pool_put (registration->clients, client);
+
+ /* Now check if that was the last client for that item */
+ if (0 == pool_elts (registration->clients))
+ {
+ hash_unset (sm->stats_registration_hash[reg], item);
+ pool_put (sm->stats_registrations[reg], registration);
+ }
+
+exit:
+ elts = 0;
+ /* Now check if that was the last item in any of the listened to stats */
+ for (i = 0; i < STATS_REG_N_IDX; i++)
+ {
+ elts += pool_elts (sm->stats_registrations[i]);
+ }
+ return elts;
+}
+
+vpe_client_registration_t *
+get_clients_for_stat (u32 reg, u32 item)
+{
+ stats_main_t *sm = &stats_main;
+ vpe_client_registration_t *client, *clients = 0;
+ vpe_client_stats_registration_t *registration;
+ uword *p;
+
+ /* Is there anything listening for item in that reg */
+ p = hash_get (sm->stats_registration_hash[reg], item);
+
+ if (!p)
+ return 0; // Fail
+
+ /* If there is, is our client_index one of them */
+ registration = pool_elt_at_index (sm->stats_registrations[reg], p[0]);
+
+ vec_reset_length (clients);
+ pool_foreach (client, registration->clients, (
+ {
+ vec_add1 (clients, *client);}
+ ));
+ return clients;
+}
+
+
+static void
+clear_client_reg (u32 ** registrations)
+{
+ /* When registrations[x] is a vector of pool indices
+ here is a good place to clean up the pools
+ */
+#define stats_reg(n) vec_free(registrations[IDX_##n]);
+#include <vpp/stats/stats.reg>
+#undef stats_reg
+
+ vec_free (registrations);
+}
+
+u32 **
+init_client_reg (u32 ** registrations)
+{
+
+ /*
+ Initialise the stats registrations for each
+ type of stat a client can register for as well as
+ a vector of "interested" indexes.
+ Initially this is a u32 of either sw_if_index or fib_index
+ but eventually this should migrate to a pool_index (u32)
+ with a type specific pool that can include more complex things
+ such as timing and structured events.
+ */
+ vec_validate (registrations, STATS_REG_N_IDX);
+#define stats_reg(n) \
+ vec_reset_length(registrations[IDX_##n]);
+#include <vpp/stats/stats.reg>
+#undef stats_reg
+
+ /*
+ When registrations[x] is a vector of pool indices, here
+ is a good place to init the pools.
+ */
+ return registrations;
+}
+
+u32 **
+enable_all_client_reg (u32 ** registrations)
+{
+
+ /*
+ Enable all stats known by adding
+ ~0 to the index vector. Eventually this
+ should be deprecated.
+ */
+#define stats_reg(n) \
+ vec_add1(registrations[IDX_##n], ~0);
+#include <vpp/stats/stats.reg>
+#undef stats_reg
+ return registrations;
+}
+
+static void
+do_simple_interface_counters (stats_main_t * sm)
+{
+ vl_api_vnet_interface_simple_counters_t *mp = 0;
+ vnet_interface_main_t *im = sm->interface_main;
+ api_main_t *am = sm->api_main;
+ vl_shmem_hdr_t *shmem_hdr = am->shmem_hdr;
+ unix_shared_memory_queue_t *q = shmem_hdr->vl_input_queue;
+ vlib_simple_counter_main_t *cm;
+ u32 items_this_message = 0;
+ u64 v, *vp = 0;
+ int i, n_counts;
+
+ /*
+ * Prevent interface registration from expanding / moving the vectors...
+ * That tends never to happen, so we can hold this lock for a while.
+ */
+ vnet_interface_counter_lock (im);
+
+ vec_foreach (cm, im->sw_if_counters)
+ {
+ n_counts = vlib_simple_counter_n_counters (cm);
+ for (i = 0; i < n_counts; i++)
+ {
+ if (mp == 0)
+ {
+ items_this_message = clib_min (SIMPLE_COUNTER_BATCH_SIZE,
+ n_counts - i);
+
+ mp = vl_msg_api_alloc_as_if_client
+ (sizeof (*mp) + items_this_message * sizeof (v));
+ mp->_vl_msg_id = ntohs (VL_API_VNET_INTERFACE_SIMPLE_COUNTERS);
+ mp->vnet_counter_type = cm - im->sw_if_counters;
+ mp->first_sw_if_index = htonl (i);
+ mp->count = 0;
+ vp = (u64 *) mp->data;
+ }
+ v = vlib_get_simple_counter (cm, i);
+ clib_mem_unaligned (vp, u64) = clib_host_to_net_u64 (v);
+ vp++;
+ mp->count++;
+ if (mp->count == items_this_message)
+ {
+ mp->count = htonl (items_this_message);
+ /* Send to the main thread... */
+ vl_msg_api_send_shmem (q, (u8 *) & mp);
+ mp = 0;
+ }
+ }
+ ASSERT (mp == 0);
+ }
+ vnet_interface_counter_unlock (im);
+}
+
+void
+handle_client_registration (vpe_client_registration_t * client, u32 stat,
+ u32 item, int enable_disable)
+{
+ stats_main_t *sm = &stats_main;
+ vpe_client_registration_t *rp, _rp;
+
+ rp = get_client_for_stat (stat, item, client->client_index);
+
+ /* Disable case */
+ if (enable_disable == 0)
+ {
+ if (!rp) // No client to disable
+ {
+ clib_warning ("pid %d: already disabled for stats...",
+ client->client_pid);
+ return;
+ }
+ sm->enable_poller =
+ clear_client_for_stat (stat, item, client->client_index);
+ return;
+ }
+ /* Enable case */
+ if (!rp)
+ {
+ rp = &_rp;
+ rp->client_index = client->client_index;
+ rp->client_pid = client->client_pid;
+ sm->enable_poller = set_client_for_stat (stat, item, rp);
+ }
+}
+
+
+/**********************************
+ * ALL Interface Combined stats - to be deprecated
+ **********************************/
+
+/*
+ * This API should be deprecated as _per_interface_ works with ~0 as sw_if_index.
+ */
+static void
+ vl_api_want_interface_combined_stats_t_handler
+ (vl_api_want_interface_combined_stats_t * mp)
+{
+ stats_main_t *sm = &stats_main;
+ vpe_client_registration_t rp;
+ vl_api_want_interface_combined_stats_reply_t *rmp;
+ uword *p;
+ i32 retval = 0;
+ unix_shared_memory_queue_t *q;
+ u32 swif;
+
+ swif = ~0; //Using same mechanism as _per_interface_
+ rp.client_index = mp->client_index;
+ rp.client_pid = mp->pid;
+
+ handle_client_registration (&rp, IDX_PER_INTERFACE_COMBINED_COUNTERS, swif,
+ mp->enable_disable);
+
+reply:
+ q = vl_api_client_index_to_input_queue (mp->client_index);
+
+ if (!q)
+ {
+ sm->enable_poller =
+ clear_client_for_stat (IDX_PER_INTERFACE_COMBINED_COUNTERS, swif,
+ mp->client_index);
+ return;
+ }
+
+ rmp = vl_msg_api_alloc (sizeof (*rmp));
+ rmp->_vl_msg_id = ntohs (VL_API_WANT_INTERFACE_COMBINED_STATS_REPLY);
+ rmp->context = mp->context;
+ rmp->retval = retval;
+
+ vl_msg_api_send_shmem (q, (u8 *) & rmp);
+}
+
+static void
+ vl_api_vnet_interface_combined_counters_t_handler
+ (vl_api_vnet_interface_combined_counters_t * mp)
+{
+ vpe_client_registration_t *clients, client;
+ stats_main_t *sm = &stats_main;
+ unix_shared_memory_queue_t *q, *q_prev = NULL;
+ vl_api_vnet_interface_combined_counters_t *mp_copy = NULL;
+ u32 mp_size;
+ int i;
+
+ mp_size = sizeof (*mp) + (ntohl (mp->count) * sizeof (vlib_counter_t));
+
+ clients =
+ get_clients_for_stat (IDX_PER_INTERFACE_COMBINED_COUNTERS,
+ ~0 /*flag for all */ );
+
+ for (i = 0; i < vec_len (clients); i++)
+ {
+ client = clients[i];
+ q = vl_api_client_index_to_input_queue (client.client_index);
+ if (q)
+ {
+ if (q_prev && (q_prev->cursize < q_prev->maxsize))
+ {
+ mp_copy = vl_msg_api_alloc_as_if_client (mp_size);
+ clib_memcpy (mp_copy, mp, mp_size);
+ vl_msg_api_send_shmem (q_prev, (u8 *) & mp);
+ mp = mp_copy;
+ }
+ q_prev = q;
+ }
+ }
+#if STATS_DEBUG > 0
+ fformat (stdout, "%U\n", format_vnet_combined_counters, mp);
+#endif
+
+ if (q_prev && (q_prev->cursize < q_prev->maxsize))
+ {
+ vl_msg_api_send_shmem (q_prev, (u8 *) & mp);
+ }
+ else
+ {
+ vl_msg_api_free (mp);
+ }
+}
+
+static void
+do_combined_interface_counters (stats_main_t * sm)
+{
+ vl_api_vnet_interface_combined_counters_t *mp = 0;
+ vnet_interface_main_t *im = sm->interface_main;
+ api_main_t *am = sm->api_main;
+ vl_shmem_hdr_t *shmem_hdr = am->shmem_hdr;
+ unix_shared_memory_queue_t *q = shmem_hdr->vl_input_queue;
+ vlib_combined_counter_main_t *cm;
+ u32 items_this_message = 0;
+ vlib_counter_t v, *vp = 0;
+ int i, n_counts;
+
+ vnet_interface_counter_lock (im);
+
+ vec_foreach (cm, im->combined_sw_if_counters)
+ {
+ n_counts = vlib_combined_counter_n_counters (cm);
+ for (i = 0; i < n_counts; i++)
+ {
+ if (mp == 0)
+ {
+ items_this_message = clib_min (COMBINED_COUNTER_BATCH_SIZE,
+ n_counts - i);
+
+ mp = vl_msg_api_alloc_as_if_client
+ (sizeof (*mp) + items_this_message * sizeof (v));
+ mp->_vl_msg_id = ntohs (VL_API_VNET_INTERFACE_COMBINED_COUNTERS);
+ mp->vnet_counter_type = cm - im->combined_sw_if_counters;
+ mp->first_sw_if_index = htonl (i);
+ mp->count = 0;
+ vp = (vlib_counter_t *) mp->data;
+ }
+ vlib_get_combined_counter (cm, i, &v);
+ clib_mem_unaligned (&vp->packets, u64)
+ = clib_host_to_net_u64 (v.packets);
+ clib_mem_unaligned (&vp->bytes, u64) = clib_host_to_net_u64 (v.bytes);
+ vp++;
+ mp->count++;
+ if (mp->count == items_this_message)
+ {
+ mp->count = htonl (items_this_message);
+ /* Send to the main thread... */
+ vl_msg_api_send_shmem (q, (u8 *) & mp);
+ mp = 0;
+ }
+ }
+ ASSERT (mp == 0);
+ }
+ vnet_interface_counter_unlock (im);
+}
+
+/**********************************
+ * Per Interface Combined stats
+ **********************************/
+
+/* Request from client registering interfaces it wants */
+static void
+ vl_api_want_per_interface_combined_stats_t_handler
+ (vl_api_want_per_interface_combined_stats_t * mp)
+{
+ stats_main_t *sm = &stats_main;
+ vpe_client_registration_t rp;
+ vl_api_want_per_interface_combined_stats_reply_t *rmp;
+ vlib_combined_counter_main_t *cm;
+ uword *p;
+ i32 retval = 0;
+ unix_shared_memory_queue_t *q;
+ int i;
+ u32 swif;
+
+ // Validate we have good sw_if_indexes before registering
+ for (i = 0; i < mp->num; i++)
+ {
+ swif = mp->sw_ifs[i];
+
+ /* Check its a real sw_if_index that the client is allowed to see */
+ if (swif != ~0)
+ {
+ if (pool_is_free_index (sm->interface_main->sw_interfaces, swif))
+ {
+ retval = VNET_API_ERROR_INVALID_SW_IF_INDEX;
+ goto reply;
+ }
+ }
+ }
+
+ for (i = 0; i < mp->num; i++)
+ {
+ swif = mp->sw_ifs[i];
+
+ rp.client_index = mp->client_index;
+ rp.client_pid = mp->pid;
+ handle_client_registration (&rp, IDX_PER_INTERFACE_COMBINED_COUNTERS,
+ swif, mp->enable_disable);
+ }
+
+reply:
+ q = vl_api_client_index_to_input_queue (mp->client_index);
+
+ if (!q)
+ {
+ for (i = 0; i < mp->num; i++)
+ {
+ swif = mp->sw_ifs[i];
+ sm->enable_poller =
+ clear_client_for_stat (IDX_PER_INTERFACE_COMBINED_COUNTERS, swif,
+ mp->client_index);
+ }
+ return;
+ }
+
+ rmp = vl_msg_api_alloc (sizeof (*rmp));
+ rmp->_vl_msg_id = ntohs (VL_API_WANT_PER_INTERFACE_COMBINED_STATS_REPLY);
+ rmp->context = mp->context;
+ rmp->retval = retval;
+
+ vl_msg_api_send_shmem (q, (u8 *) & rmp);
+}
+
+/* Per Interface Combined distribution to client */
+static void
+do_combined_per_interface_counters (stats_main_t * sm)
+{
+ vl_api_vnet_per_interface_combined_counters_t *mp = 0;
+ vnet_interface_main_t *im = sm->interface_main;
+ api_main_t *am = sm->api_main;
+ vl_shmem_hdr_t *shmem_hdr = am->shmem_hdr;
+ unix_shared_memory_queue_t *q = NULL;
+ vlib_combined_counter_main_t *cm;
+ /*
+ * items_this_message will eventually be used to optimise the batching
+ * of per client messages for each stat. For now setting this to 1 then
+ * iterate. This will not affect API.
+ *
+ * FIXME instead of enqueueing here, this should be sent to a batch
+ * storer for per-client transmission. Each "mp" sent would be a single entry
+ * and if a client is listening to other sw_if_indexes for same, it would be
+ * appended to that *mp
+ */
+ u32 items_this_message = 1;
+ vnet_combined_counter_t *vp = 0;
+ vlib_counter_t v;
+ int i, j;
+ u32 timestamp;
+ vpe_client_stats_registration_t *reg;
+ vpe_client_registration_t *client;
+ u32 *sw_if_index = 0;
+
+ /*
+ FIXME(s):
+ - capturing the timestamp of the counters "when VPP knew them" is important.
+ Less so is that the timing of the delivery to the control plane be in the same
+ timescale.
+
+ i.e. As long as the control plane can delta messages from VPP and work out
+ velocity etc based on the timestamp, it can do so in a more "batch mode".
+
+ It would be beneficial to keep a "per-client" message queue, and then
+ batch all the stat messages for a client into one message, with
+ discrete timestamps.
+
+ Given this particular API is for "per interface" one assumes that the scale
+ is less than the ~0 case, which the prior API is suited for.
+ */
+ vnet_interface_counter_lock (im);
+
+ timestamp = vlib_time_now (sm->vlib_main);
+
+ vec_reset_length (sm->regs_tmp);
+ pool_foreach (reg,
+ sm->stats_registrations[IDX_PER_INTERFACE_COMBINED_COUNTERS],
+ (
+ {
+ vec_add1 (sm->regs_tmp, reg);}));
+
+ for (i = 0; i < vec_len (sm->regs_tmp); i++)
+ {
+ reg = sm->regs_tmp[i];
+ if (reg->item == ~0)
+ {
+ vnet_interface_counter_unlock (im);
+ do_combined_interface_counters (sm);
+ vnet_interface_counter_lock (im);
+ continue;
+ }
+ vec_reset_length (sm->clients_tmp);
+ pool_foreach (client, reg->clients, (
+ {
+ vec_add1 (sm->clients_tmp,
+ client);}
+ ));
+
+ //FIXME - should be doing non-variant part of mp here and managing
+ // any alloc per client in that vec_foreach
+ for (j = 0; j < vec_len (sm->clients_tmp); j++)
+ {
+ client = sm->clients_tmp[j];
+ q = vl_api_client_index_to_input_queue (client->client_index);
+
+ //Client may have disconnected abrubtly, clean up so we don't poll nothing.
+ if (!q)
+ {
+ sm->enable_poller =
+ clear_client_for_stat (IDX_PER_INTERFACE_COMBINED_COUNTERS,
+ reg->item, client->client_index);
+ continue;
+ }
+
+ mp = vl_msg_api_alloc (sizeof (*mp) +
+ (items_this_message *
+ (sizeof (*vp) /* rx */ )));
+
+ // FIXME when optimising for items_this_message > 1 need to include a
+ // SIMPLE_INTERFACE_BATCH_SIZE check.
+ mp->_vl_msg_id =
+ ntohs (VL_API_VNET_PER_INTERFACE_COMBINED_COUNTERS);
+
+ mp->count = items_this_message;
+ mp->timestamp = timestamp;
+ vp = (vnet_combined_counter_t *) mp->data;
+
+ vp->sw_if_index = htonl (reg->item);
+
+ cm = im->combined_sw_if_counters + VNET_INTERFACE_COUNTER_RX;
+ vlib_get_combined_counter (cm, reg->item, &v);
+ clib_mem_unaligned (&vp->rx_packets, u64)
+ = clib_host_to_net_u64 (v.packets);
+ clib_mem_unaligned (&vp->rx_bytes, u64) =
+ clib_host_to_net_u64 (v.bytes);
+
+
+ /* TX vlib_counter_t packets/bytes */
+ cm = im->combined_sw_if_counters + VNET_INTERFACE_COUNTER_TX;
+ vlib_get_combined_counter (cm, reg->item, &v);
+ clib_mem_unaligned (&vp->tx_packets, u64)
+ = clib_host_to_net_u64 (v.packets);
+ clib_mem_unaligned (&vp->tx_bytes, u64) =
+ clib_host_to_net_u64 (v.bytes);
+
+ vl_msg_api_send_shmem (q, (u8 *) & mp);
+ }
+ }
+
+ vnet_interface_counter_unlock (im);
+}
+
+/**********************************
+ * Per Interface simple stats
+ **********************************/
+
+/* Request from client registering interfaces it wants */
+static void
+ vl_api_want_per_interface_simple_stats_t_handler
+ (vl_api_want_per_interface_simple_stats_t * mp)
+{
+ stats_main_t *sm = &stats_main;
+ vpe_client_registration_t rp;
+ vl_api_want_per_interface_simple_stats_reply_t *rmp;
+ vlib_simple_counter_main_t *cm;
+ uword *p;
+ i32 retval = 0;
+ unix_shared_memory_queue_t *q;
+ int i;
+ u32 swif;
+
+ for (i = 0; i < mp->num; i++)
+ {
+ swif = mp->sw_ifs[i];
+
+ /* Check its a real sw_if_index that the client is allowed to see */
+ if (swif != ~0)
+ {
+ if (pool_is_free_index (sm->interface_main->sw_interfaces, swif))
+ {
+ retval = VNET_API_ERROR_INVALID_SW_IF_INDEX;
+ goto reply;
+ }
+ }
+ }
+
+ for (i = 0; i < mp->num; i++)
+ {
+ swif = mp->sw_ifs[i];
+
+ rp.client_index = mp->client_index;
+ rp.client_pid = mp->pid;
+ handle_client_registration (&rp, IDX_PER_INTERFACE_SIMPLE_COUNTERS,
+ swif, mp->enable_disable);
+ }
+
+reply:
+ q = vl_api_client_index_to_input_queue (mp->client_index);
+
+ //Client may have disconnected abrubtly, clean up so we don't poll nothing.
+ if (!q)
+ {
+ for (i = 0; i < mp->num; i++)
+ {
+ swif = mp->sw_ifs[i];
+ sm->enable_poller =
+ clear_client_for_stat (IDX_PER_INTERFACE_SIMPLE_COUNTERS, swif,
+ mp->client_index);
+ }
+
+ return;
+ }
+
+
+ rmp = vl_msg_api_alloc (sizeof (*rmp));
+ rmp->_vl_msg_id = ntohs (VL_API_WANT_PER_INTERFACE_SIMPLE_STATS_REPLY);
+ rmp->context = mp->context;
+ rmp->retval = retval;
+
+ vl_msg_api_send_shmem (q, (u8 *) & rmp);
+}
+
+/* Per Interface Simple distribution to client */
+static void
+do_simple_per_interface_counters (stats_main_t * sm)
+{
+ vl_api_vnet_per_interface_simple_counters_t *mp = 0;
+ vnet_interface_main_t *im = sm->interface_main;
+ api_main_t *am = sm->api_main;
+ vl_shmem_hdr_t *shmem_hdr = am->shmem_hdr;
+ unix_shared_memory_queue_t *q = NULL;
+ vlib_simple_counter_main_t *cm;
+ /*
+ * items_this_message will eventually be used to optimise the batching
+ * of per client messages for each stat. For now setting this to 1 then
+ * iterate. This will not affect API.
+ *
+ * FIXME instead of enqueueing here, this should be sent to a batch
+ * storer for per-client transmission. Each "mp" sent would be a single entry
+ * and if a client is listening to other sw_if_indexes for same, it would be
+ * appended to that *mp
+ */
+ u32 items_this_message = 1;
+ int i, j, size;
+ vpe_client_stats_registration_t *reg;
+ vpe_client_registration_t *client;
+ u32 timestamp;
+ u32 count;
+ vnet_simple_counter_t *vp = 0;
+ counter_t v;
+
+ /*
+ FIXME(s):
+ - capturing the timestamp of the counters "when VPP knew them" is important.
+ Less so is that the timing of the delivery to the control plane be in the same
+ timescale.
+
+ i.e. As long as the control plane can delta messages from VPP and work out
+ velocity etc based on the timestamp, it can do so in a more "batch mode".
+
+ It would be beneficial to keep a "per-client" message queue, and then
+ batch all the stat messages for a client into one message, with
+ discrete timestamps.
+
+ Given this particular API is for "per interface" one assumes that the scale
+ is less than the ~0 case, which the prior API is suited for.
+ */
+ vnet_interface_counter_lock (im);
+
+ timestamp = vlib_time_now (sm->vlib_main);
+
+ vec_reset_length (sm->regs_tmp);
+ pool_foreach (reg,
+ sm->stats_registrations[IDX_PER_INTERFACE_SIMPLE_COUNTERS], (
+ {
+ vec_add1
+ (sm->regs_tmp,
+ reg);}));
+
+ for (i = 0; i < vec_len (sm->regs_tmp); i++)
+ {
+ reg = sm->regs_tmp[i];
+ if (reg->item == ~0)
+ {
+ vnet_interface_counter_unlock (im);
+ do_simple_interface_counters (sm);
+ vnet_interface_counter_lock (im);
+ continue;
+ }
+ vec_reset_length (sm->clients_tmp);
+ pool_foreach (client, reg->clients, (
+ {
+ vec_add1 (sm->clients_tmp,
+ client);}
+ ));
+
+ //FIXME - should be doing non-variant part of mp here and managing
+ // any alloc per client in that vec_foreach
+ for (j = 0; j < vec_len (sm->clients_tmp); j++)
+ {
+ client = sm->clients_tmp[j];
+ q = vl_api_client_index_to_input_queue (client->client_index);
+
+ //Client may have disconnected abrubtly, clean up so we don't poll nothing.
+ if (!q)
+ {
+ sm->enable_poller =
+ clear_client_for_stat (IDX_PER_INTERFACE_SIMPLE_COUNTERS,
+ reg->item, client->client_index);
+ continue;
+ }
+
+ size = (sizeof (*mp) + (items_this_message * (sizeof (u64) * 10)));
+ mp = vl_msg_api_alloc (size);
+ // FIXME when optimising for items_this_message > 1 need to include a
+ // SIMPLE_INTERFACE_BATCH_SIZE check.
+ mp->_vl_msg_id = ntohs (VL_API_VNET_PER_INTERFACE_SIMPLE_COUNTERS);
+
+ mp->count = items_this_message;
+ mp->timestamp = timestamp;
+ vp = (vnet_simple_counter_t *) mp->data;
+
+ vp->sw_if_index = htonl (reg->item);
+
+ //FIXME will be simpler with a preprocessor macro
+ // VNET_INTERFACE_COUNTER_DROP
+ cm = im->sw_if_counters + VNET_INTERFACE_COUNTER_DROP;
+ v = vlib_get_simple_counter (cm, reg->item);
+ clib_mem_unaligned (&vp->drop, u64) = clib_host_to_net_u64 (v);
+
+ // VNET_INTERFACE_COUNTER_PUNT
+ cm = im->sw_if_counters + VNET_INTERFACE_COUNTER_PUNT;
+ v = vlib_get_simple_counter (cm, reg->item);
+ clib_mem_unaligned (&vp->punt, u64) = clib_host_to_net_u64 (v);
+
+ // VNET_INTERFACE_COUNTER_IP4
+ cm = im->sw_if_counters + VNET_INTERFACE_COUNTER_IP4;
+ v = vlib_get_simple_counter (cm, reg->item);
+ clib_mem_unaligned (&vp->rx_ip4, u64) = clib_host_to_net_u64 (v);
+
+ //VNET_INTERFACE_COUNTER_IP6
+ cm = im->sw_if_counters + VNET_INTERFACE_COUNTER_IP6;
+ v = vlib_get_simple_counter (cm, reg->item);
+ clib_mem_unaligned (&vp->rx_ip6, u64) = clib_host_to_net_u64 (v);
+
+ //VNET_INTERFACE_COUNTER_RX_NO_BUF
+ cm = im->sw_if_counters + VNET_INTERFACE_COUNTER_RX_NO_BUF;
+ v = vlib_get_simple_counter (cm, reg->item);
+ clib_mem_unaligned (&vp->rx_no_buffer, u64) =
+ clib_host_to_net_u64 (v);
+
+ //VNET_INTERFACE_COUNTER_RX_MISS
+ cm = im->sw_if_counters + VNET_INTERFACE_COUNTER_RX_MISS;
+ v = vlib_get_simple_counter (cm, reg->item);
+ clib_mem_unaligned (&vp->rx_miss, u64) = clib_host_to_net_u64 (v);
+
+ //VNET_INTERFACE_COUNTER_RX_ERROR
+ cm = im->sw_if_counters + VNET_INTERFACE_COUNTER_RX_ERROR;
+ v = vlib_get_simple_counter (cm, reg->item);
+ clib_mem_unaligned (&vp->rx_error, u64) = clib_host_to_net_u64 (v);
+
+ //VNET_INTERFACE_COUNTER_TX_ERROR
+ cm = im->sw_if_counters + VNET_INTERFACE_COUNTER_TX_ERROR;
+ v = vlib_get_simple_counter (cm, reg->item);
+ clib_mem_unaligned (&vp->tx_error, u64) = clib_host_to_net_u64 (v);
+
+ //VNET_INTERFACE_COUNTER_MPLS
+ cm = im->sw_if_counters + VNET_INTERFACE_COUNTER_MPLS;
+ v = vlib_get_simple_counter (cm, reg->item);
+ clib_mem_unaligned (&vp->rx_mpls, u64) = clib_host_to_net_u64 (v);
+
+ vl_msg_api_send_shmem (q, (u8 *) & mp);
+ }
+ }
+
+ vnet_interface_counter_unlock (im);
+}
+
+/**********************************
+ * Per FIB IP4 stats
+ **********************************/
+
+static void
+ip46_fib_stats_delay (stats_main_t * sm, u32 sec, u32 nsec)
+{
+ struct timespec _req, *req = &_req;
+ struct timespec _rem, *rem = &_rem;
+
+ req->tv_sec = sec;
+ req->tv_nsec = nsec;
+ while (1)
+ {
+ if (nanosleep (req, rem) == 0)
+ break;
+ *req = *rem;
+ if (errno == EINTR)
+ continue;
+ clib_unix_warning ("nanosleep");
+ break;
+ }
+}
+
+/**
+ * @brief The context passed when collecting adjacency counters
+ */
+typedef struct ip4_nbr_stats_ctx_t_
+{
+ /**
+ * The SW IF index all these adjs belong to
+ */
+ u32 sw_if_index;
+
+ /**
+ * A vector of ip4 nbr counters
+ */
+ vl_api_ip4_nbr_counter_t *counters;
+} ip4_nbr_stats_ctx_t;
+
+static adj_walk_rc_t
+ip4_nbr_stats_cb (adj_index_t ai, void *arg)
+{
+ vl_api_ip4_nbr_counter_t *vl_counter;
+ vlib_counter_t adj_counter;
+ ip4_nbr_stats_ctx_t *ctx;
+ ip_adjacency_t *adj;
+
+ ctx = arg;
+ vlib_get_combined_counter (&adjacency_counters, ai, &adj_counter);
+
+ if (0 != adj_counter.packets)
+ {
+ vec_add2 (ctx->counters, vl_counter, 1);
+ adj = adj_get (ai);
+
+ vl_counter->packets = clib_host_to_net_u64 (adj_counter.packets);
+ vl_counter->bytes = clib_host_to_net_u64 (adj_counter.bytes);
+ vl_counter->address = adj->sub_type.nbr.next_hop.ip4.as_u32;
+ vl_counter->link_type = adj->ia_link;
+ }
+ return (ADJ_WALK_RC_CONTINUE);
+}
+
+#define MIN(x,y) (((x)<(y))?(x):(y))
+
+static void
+ip4_nbr_ship (stats_main_t * sm, ip4_nbr_stats_ctx_t * ctx)
+{
+ api_main_t *am = sm->api_main;
+ vl_shmem_hdr_t *shmem_hdr = am->shmem_hdr;
+ unix_shared_memory_queue_t *q = shmem_hdr->vl_input_queue;
+ vl_api_vnet_ip4_nbr_counters_t *mp = 0;
+ int first = 0;
+
+ /*
+ * If the walk context has counters, which may be left over from the last
+ * suspend, then we continue from there.
+ */
+ while (0 != vec_len (ctx->counters))
+ {
+ u32 n_items = MIN (vec_len (ctx->counters),
+ IP4_FIB_COUNTER_BATCH_SIZE);
+ u8 pause = 0;
+
+ dslock (sm, 0 /* release hint */ , 1 /* tag */ );
+
+ mp = vl_msg_api_alloc_as_if_client (sizeof (*mp) +
+ (n_items *
+ sizeof
+ (vl_api_ip4_nbr_counter_t)));
+ mp->_vl_msg_id = ntohs (VL_API_VNET_IP4_NBR_COUNTERS);
+ mp->count = ntohl (n_items);
+ mp->sw_if_index = ntohl (ctx->sw_if_index);
+ mp->begin = first;
+ first = 0;
+
+ /*
+ * copy the counters from the back of the context, then we can easily
+ * 'erase' them by resetting the vector length.
+ * The order we push the stats to the caller is not important.
+ */
+ clib_memcpy (mp->c,
+ &ctx->counters[vec_len (ctx->counters) - n_items],
+ n_items * sizeof (*ctx->counters));
+
+ _vec_len (ctx->counters) = vec_len (ctx->counters) - n_items;
+
+ /*
+ * send to the shm q
+ */
+ unix_shared_memory_queue_lock (q);
+ pause = unix_shared_memory_queue_is_full (q);
+
+ vl_msg_api_send_shmem_nolock (q, (u8 *) & mp);
+ unix_shared_memory_queue_unlock (q);
+ dsunlock (sm);
+
+ if (pause)
+ ip46_fib_stats_delay (sm, 0 /* sec */ ,
+ STATS_RELEASE_DELAY_NS);
+ }
+}
+
+static void
+do_ip4_nbr_counters (stats_main_t * sm)
+{
+ vnet_main_t *vnm = vnet_get_main ();
+ vnet_interface_main_t *im = &vnm->interface_main;
+ vnet_sw_interface_t *si;
+
+ ip4_nbr_stats_ctx_t ctx = {
+ .sw_if_index = 0,
+ .counters = NULL,
+ };
+
+ /* *INDENT-OFF* */
+ pool_foreach (si, im->sw_interfaces,
+ ({
+ /*
+ * update the interface we are now concerned with
+ */
+ ctx.sw_if_index = si->sw_if_index;
+
+ /*
+ * we are about to walk another interface, so we shouldn't have any pending
+ * stats to export.
+ */
+ ASSERT(ctx.counters == NULL);
+
+ /*
+ * visit each neighbour adjacency on the interface and collect
+ * its current stats.
+ * Because we hold the lock the walk is synchronous, so safe to routing
+ * updates. It's limited in work by the number of adjacenies on an
+ * interface, which is typically not huge.
+ */
+ dslock (sm, 0 /* release hint */ , 1 /* tag */ );
+ adj_nbr_walk (si->sw_if_index,
+ FIB_PROTOCOL_IP4,
+ ip4_nbr_stats_cb,
+ &ctx);
+ dsunlock (sm);
+
+ /*
+ * if this interface has some adjacencies with counters then ship them,
+ * else continue to the next interface.
+ */
+ if (NULL != ctx.counters)
+ {
+ ip4_nbr_ship(sm, &ctx);
+ }
+ }));
+ /* *INDENT-OFF* */
+}
+
+/**
+ * @brief The context passed when collecting adjacency counters
+ */
+typedef struct ip6_nbr_stats_ctx_t_
+{
+ /**
+ * The SW IF index all these adjs belong to
+ */
+ u32 sw_if_index;
+
+ /**
+ * A vector of ip6 nbr counters
+ */
+ vl_api_ip6_nbr_counter_t *counters;
+} ip6_nbr_stats_ctx_t;
+
+static adj_walk_rc_t
+ip6_nbr_stats_cb (adj_index_t ai,
+ void *arg)
+{
+ vl_api_ip6_nbr_counter_t *vl_counter;
+ vlib_counter_t adj_counter;
+ ip6_nbr_stats_ctx_t *ctx;
+ ip_adjacency_t *adj;
+
+ ctx = arg;
+ vlib_get_combined_counter(&adjacency_counters, ai, &adj_counter);
+
+ if (0 != adj_counter.packets)
+ {
+ vec_add2(ctx->counters, vl_counter, 1);
+ adj = adj_get(ai);
+
+ vl_counter->packets = clib_host_to_net_u64(adj_counter.packets);
+ vl_counter->bytes = clib_host_to_net_u64(adj_counter.bytes);
+ vl_counter->address[0] = adj->sub_type.nbr.next_hop.ip6.as_u64[0];
+ vl_counter->address[1] = adj->sub_type.nbr.next_hop.ip6.as_u64[1];
+ vl_counter->link_type = adj->ia_link;
+ }
+ return (ADJ_WALK_RC_CONTINUE);
+}
+
+#define MIN(x,y) (((x)<(y))?(x):(y))
+
+static void
+ip6_nbr_ship (stats_main_t * sm,
+ ip6_nbr_stats_ctx_t *ctx)
+{
+ api_main_t *am = sm->api_main;
+ vl_shmem_hdr_t *shmem_hdr = am->shmem_hdr;
+ unix_shared_memory_queue_t *q = shmem_hdr->vl_input_queue;
+ vl_api_vnet_ip6_nbr_counters_t *mp = 0;
+ int first = 0;
+
+ /*
+ * If the walk context has counters, which may be left over from the last
+ * suspend, then we continue from there.
+ */
+ while (0 != vec_len(ctx->counters))
+ {
+ u32 n_items = MIN (vec_len (ctx->counters),
+ IP6_FIB_COUNTER_BATCH_SIZE);
+ u8 pause = 0;
+
+ dslock (sm, 0 /* release hint */ , 1 /* tag */ );
+
+ mp = vl_msg_api_alloc_as_if_client (sizeof (*mp) +
+ (n_items *
+ sizeof
+ (vl_api_ip6_nbr_counter_t)));
+ mp->_vl_msg_id = ntohs (VL_API_VNET_IP6_NBR_COUNTERS);
+ mp->count = ntohl (n_items);
+ mp->sw_if_index = ntohl (ctx->sw_if_index);
+ mp->begin = first;
+ first = 0;
+
+ /*
+ * copy the counters from the back of the context, then we can easily
+ * 'erase' them by resetting the vector length.
+ * The order we push the stats to the caller is not important.
+ */
+ clib_memcpy (mp->c,
+ &ctx->counters[vec_len (ctx->counters) - n_items],
+ n_items * sizeof (*ctx->counters));
+
+ _vec_len (ctx->counters) = vec_len (ctx->counters) - n_items;
+
+ /*
+ * send to the shm q
+ */
+ unix_shared_memory_queue_lock (q);
+ pause = unix_shared_memory_queue_is_full (q);
+
+ vl_msg_api_send_shmem_nolock (q, (u8 *) & mp);
+ unix_shared_memory_queue_unlock (q);
+ dsunlock (sm);
+
+ if (pause)
+ ip46_fib_stats_delay (sm, 0 /* sec */ ,
+ STATS_RELEASE_DELAY_NS);
+ }
+}
+
+static void
+do_ip6_nbr_counters (stats_main_t * sm)
+{
+ vnet_main_t *vnm = vnet_get_main ();
+ vnet_interface_main_t *im = &vnm->interface_main;
+ vnet_sw_interface_t *si;
+
+ ip6_nbr_stats_ctx_t ctx = {
+ .sw_if_index = 0,
+ .counters = NULL,
+ };
+
+ /* *INDENT-OFF* */
+ pool_foreach (si, im->sw_interfaces,
+ ({
+ /*
+ * update the interface we are now concerned with
+ */
+ ctx.sw_if_index = si->sw_if_index;
+
+ /*
+ * we are about to walk another interface, so we shouldn't have any pending
+ * stats to export.
+ */
+ ASSERT(ctx.counters == NULL);
+
+ /*
+ * visit each neighbour adjacency on the interface and collect
+ * its current stats.
+ * Because we hold the lock the walk is synchronous, so safe to routing
+ * updates. It's limited in work by the number of adjacenies on an
+ * interface, which is typically not huge.
+ */
+ dslock (sm, 0 /* release hint */ , 1 /* tag */ );
+ adj_nbr_walk (si->sw_if_index,
+ FIB_PROTOCOL_IP6,
+ ip6_nbr_stats_cb,
+ &ctx);
+ dsunlock (sm);
+
+ /*
+ * if this interface has some adjacencies with counters then ship them,
+ * else continue to the next interface.
+ */
+ if (NULL != ctx.counters)
+ {
+ ip6_nbr_ship(sm, &ctx);
+ }
+ }));
+ /* *INDENT-OFF* */
+}
+
+static void
+do_ip4_fib_counters (stats_main_t * sm)
+{
+ ip4_main_t *im4 = &ip4_main;
+ api_main_t *am = sm->api_main;
+ vl_shmem_hdr_t *shmem_hdr = am->shmem_hdr;
+ unix_shared_memory_queue_t *q = shmem_hdr->vl_input_queue;
+ ip4_route_t *r;
+ fib_table_t *fib;
+ ip4_fib_t *v4_fib;
+ do_ip46_fibs_t *do_fibs;
+ vl_api_vnet_ip4_fib_counters_t *mp = 0;
+ u32 items_this_message;
+ vl_api_ip4_fib_counter_t *ctrp = 0;
+ u32 start_at_fib_index = 0;
+ int i, j, k;
+
+ do_fibs = &sm->do_ip46_fibs;
+
+again:
+ vec_reset_length (do_fibs->fibs);
+ /* *INDENT-OFF* */
+ pool_foreach (fib, im4->fibs,
+ ({vec_add1(do_fibs->fibs,fib);}));
+
+ /* *INDENT-ON* */
+
+ for (j = 0; j < vec_len (do_fibs->fibs); j++)
+ {
+ fib = do_fibs->fibs[j];
+ /* We may have bailed out due to control-plane activity */
+ while ((fib - im4->fibs) < start_at_fib_index)
+ continue;
+
+ v4_fib = pool_elt_at_index (im4->v4_fibs, fib->ft_index);
+
+ if (mp == 0)
+ {
+ items_this_message = IP4_FIB_COUNTER_BATCH_SIZE;
+ mp = vl_msg_api_alloc_as_if_client
+ (sizeof (*mp) +
+ items_this_message * sizeof (vl_api_ip4_fib_counter_t));
+ mp->_vl_msg_id = ntohs (VL_API_VNET_IP4_FIB_COUNTERS);
+ mp->count = 0;
+ mp->vrf_id = ntohl (fib->ft_table_id);
+ ctrp = (vl_api_ip4_fib_counter_t *) mp->c;
+ }
+ else
+ {
+ /* happens if the last FIB was empty... */
+ ASSERT (mp->count == 0);
+ mp->vrf_id = ntohl (fib->ft_table_id);
+ }
+
+ dslock (sm, 0 /* release hint */ , 1 /* tag */ );
+
+ vec_reset_length (do_fibs->ip4routes);
+ vec_reset_length (do_fibs->results);
+
+ for (i = 0; i < ARRAY_LEN (v4_fib->fib_entry_by_dst_address); i++)
+ {
+ uword *hash = v4_fib->fib_entry_by_dst_address[i];
+ hash_pair_t *p;
+ ip4_route_t x;
+
+ vec_reset_length (do_fibs->pvec);
+
+ x.address_length = i;
+
+ hash_foreach_pair (p, hash, (
+ {
+ vec_add1 (do_fibs->pvec, p);}
+ ));
+ for (k = 0; k < vec_len (do_fibs->pvec); k++)
+ {
+ p = do_fibs->pvec[k];
+ x.address.data_u32 = p->key;
+ x.index = p->value[0];
+
+ vec_add1 (do_fibs->ip4routes, x);
+ if (sm->data_structure_lock->release_hint)
+ {
+ start_at_fib_index = fib - im4->fibs;
+ dsunlock (sm);
+ ip46_fib_stats_delay (sm, 0 /* sec */ ,
+ STATS_RELEASE_DELAY_NS);
+ mp->count = 0;
+ ctrp = (vl_api_ip4_fib_counter_t *) mp->c;
+ goto again;
+ }
+ }
+ }
+
+ vec_foreach (r, do_fibs->ip4routes)
+ {
+ vlib_counter_t c;
+ const dpo_id_t *dpo_id;
+ u32 index;
+
+ dpo_id = fib_entry_contribute_ip_forwarding (r->index);
+ index = (u32) dpo_id->dpoi_index;
+
+ vlib_get_combined_counter (&load_balance_main.lbm_to_counters,
+ index, &c);
+ /*
+ * If it has actually
+ * seen at least one packet, send it.
+ */
+ if (c.packets > 0)
+ {
+
+ /* already in net byte order */
+ ctrp->address = r->address.as_u32;
+ ctrp->address_length = r->address_length;
+ ctrp->packets = clib_host_to_net_u64 (c.packets);
+ ctrp->bytes = clib_host_to_net_u64 (c.bytes);
+ mp->count++;
+ ctrp++;
+
+ if (mp->count == items_this_message)
+ {
+ mp->count = htonl (items_this_message);
+ /*
+ * If the main thread's input queue is stuffed,
+ * drop the data structure lock (which the main thread
+ * may want), and take a pause.
+ */
+ unix_shared_memory_queue_lock (q);
+ if (unix_shared_memory_queue_is_full (q))
+ {
+ dsunlock (sm);
+ vl_msg_api_send_shmem_nolock (q, (u8 *) & mp);
+ unix_shared_memory_queue_unlock (q);
+ mp = 0;
+ ip46_fib_stats_delay (sm, 0 /* sec */ ,
+ STATS_RELEASE_DELAY_NS);
+ goto again;
+ }
+ vl_msg_api_send_shmem_nolock (q, (u8 *) & mp);
+ unix_shared_memory_queue_unlock (q);
+
+ items_this_message = IP4_FIB_COUNTER_BATCH_SIZE;
+ mp = vl_msg_api_alloc_as_if_client
+ (sizeof (*mp) +
+ items_this_message * sizeof (vl_api_ip4_fib_counter_t));
+ mp->_vl_msg_id = ntohs (VL_API_VNET_IP4_FIB_COUNTERS);
+ mp->count = 0;
+ mp->vrf_id = ntohl (fib->ft_table_id);
+ ctrp = (vl_api_ip4_fib_counter_t *) mp->c;
+ }
+ } /* for each (mp or single) adj */
+ if (sm->data_structure_lock->release_hint)
+ {
+ start_at_fib_index = fib - im4->fibs;
+ dsunlock (sm);
+ ip46_fib_stats_delay (sm, 0 /* sec */ , STATS_RELEASE_DELAY_NS);
+ mp->count = 0;
+ ctrp = (vl_api_ip4_fib_counter_t *) mp->c;
+ goto again;
+ }
+ } /* vec_foreach (routes) */
+
+ dsunlock (sm);
+
+ /* Flush any data from this fib */
+ if (mp->count)
+ {
+ mp->count = htonl (mp->count);
+ vl_msg_api_send_shmem (q, (u8 *) & mp);
+ mp = 0;
+ }
+ }
+
+ /* If e.g. the last FIB had no reportable routes, free the buffer */
+ if (mp)
+ vl_msg_api_free (mp);
+}
+
+typedef struct
+{
+ u32 fib_index;
+ ip6_route_t **routep;
+ stats_main_t *sm;
+} add_routes_in_fib_arg_t;
+
+static void
+add_routes_in_fib (BVT (clib_bihash_kv) * kvp, void *arg)
+{
+ add_routes_in_fib_arg_t *ap = arg;
+ stats_main_t *sm = ap->sm;
+
+ if (sm->data_structure_lock->release_hint)
+ clib_longjmp (&sm->jmp_buf, 1);
+
+ if (kvp->key[2] >> 32 == ap->fib_index)
+ {
+ ip6_address_t *addr;
+ ip6_route_t *r;
+ addr = (ip6_address_t *) kvp;
+ vec_add2 (*ap->routep, r, 1);
+ r->address = addr[0];
+ r->address_length = kvp->key[2] & 0xFF;
+ r->index = kvp->value;
+ }
+}
+
+static void
+do_ip6_fib_counters (stats_main_t * sm)
+{
+ ip6_main_t *im6 = &ip6_main;
+ api_main_t *am = sm->api_main;
+ vl_shmem_hdr_t *shmem_hdr = am->shmem_hdr;
+ unix_shared_memory_queue_t *q = shmem_hdr->vl_input_queue;
+ ip6_route_t *r;
+ fib_table_t *fib;
+ do_ip46_fibs_t *do_fibs;
+ vl_api_vnet_ip6_fib_counters_t *mp = 0;
+ u32 items_this_message;
+ vl_api_ip6_fib_counter_t *ctrp = 0;
+ u32 start_at_fib_index = 0;
+ BVT (clib_bihash) * h = &im6->ip6_table[IP6_FIB_TABLE_FWDING].ip6_hash;
+ add_routes_in_fib_arg_t _a, *a = &_a;
+ int i;
+
+ do_fibs = &sm->do_ip46_fibs;
+again:
+ vec_reset_length (do_fibs->fibs);
+ /* *INDENT-OFF* */
+ pool_foreach (fib, im6->fibs,
+ ({vec_add1(do_fibs->fibs,fib);}));
+ /* *INDENT-ON* */
+
+
+ for (i = 0; i < vec_len (do_fibs->fibs); i++)
+ {
+ fib = do_fibs->fibs[i];
+ /* We may have bailed out due to control-plane activity */
+ while ((fib - im6->fibs) < start_at_fib_index)
+ continue;
+
+ if (mp == 0)
+ {
+ items_this_message = IP6_FIB_COUNTER_BATCH_SIZE;
+ mp = vl_msg_api_alloc_as_if_client
+ (sizeof (*mp) +
+ items_this_message * sizeof (vl_api_ip6_fib_counter_t));
+ mp->_vl_msg_id = ntohs (VL_API_VNET_IP6_FIB_COUNTERS);
+ mp->count = 0;
+ mp->vrf_id = ntohl (fib->ft_table_id);
+ ctrp = (vl_api_ip6_fib_counter_t *) mp->c;
+ }
+
+ dslock (sm, 0 /* release hint */ , 1 /* tag */ );
+
+ vec_reset_length (do_fibs->ip6routes);
+ vec_reset_length (do_fibs->results);
+
+ a->fib_index = fib - im6->fibs;
+ a->routep = &do_fibs->ip6routes;
+ a->sm = sm;
+
+ if (clib_setjmp (&sm->jmp_buf, 0) == 0)
+ {
+ start_at_fib_index = fib - im6->fibs;
+ BV (clib_bihash_foreach_key_value_pair) (h, add_routes_in_fib, a);
+ }
+ else
+ {
+ dsunlock (sm);
+ ip46_fib_stats_delay (sm, 0 /* sec */ ,
+ STATS_RELEASE_DELAY_NS);
+ mp->count = 0;
+ ctrp = (vl_api_ip6_fib_counter_t *) mp->c;
+ goto again;
+ }
+
+ vec_foreach (r, do_fibs->ip6routes)
+ {
+ vlib_counter_t c;
+
+ vlib_get_combined_counter (&load_balance_main.lbm_to_counters,
+ r->index, &c);
+ /*
+ * If it has actually
+ * seen at least one packet, send it.
+ */
+ if (c.packets > 0)
+ {
+ /* already in net byte order */
+ ctrp->address[0] = r->address.as_u64[0];
+ ctrp->address[1] = r->address.as_u64[1];
+ ctrp->address_length = (u8) r->address_length;
+ ctrp->packets = clib_host_to_net_u64 (c.packets);
+ ctrp->bytes = clib_host_to_net_u64 (c.bytes);
+ mp->count++;
+ ctrp++;
+
+ if (mp->count == items_this_message)
+ {
+ mp->count = htonl (items_this_message);
+ /*
+ * If the main thread's input queue is stuffed,
+ * drop the data structure lock (which the main thread
+ * may want), and take a pause.
+ */
+ unix_shared_memory_queue_lock (q);
+ if (unix_shared_memory_queue_is_full (q))
+ {
+ dsunlock (sm);
+ vl_msg_api_send_shmem_nolock (q, (u8 *) & mp);
+ unix_shared_memory_queue_unlock (q);
+ mp = 0;
+ ip46_fib_stats_delay (sm, 0 /* sec */ ,
+ STATS_RELEASE_DELAY_NS);
+ goto again;
+ }
+ vl_msg_api_send_shmem_nolock (q, (u8 *) & mp);
+ unix_shared_memory_queue_unlock (q);
+
+ items_this_message = IP6_FIB_COUNTER_BATCH_SIZE;
+ mp = vl_msg_api_alloc_as_if_client
+ (sizeof (*mp) +
+ items_this_message * sizeof (vl_api_ip6_fib_counter_t));
+ mp->_vl_msg_id = ntohs (VL_API_VNET_IP6_FIB_COUNTERS);
+ mp->count = 0;
+ mp->vrf_id = ntohl (fib->ft_table_id);
+ ctrp = (vl_api_ip6_fib_counter_t *) mp->c;
+ }
+ }
+
+ if (sm->data_structure_lock->release_hint)
+ {
+ start_at_fib_index = fib - im6->fibs;
+ dsunlock (sm);
+ ip46_fib_stats_delay (sm, 0 /* sec */ , STATS_RELEASE_DELAY_NS);
+ mp->count = 0;
+ ctrp = (vl_api_ip6_fib_counter_t *) mp->c;
+ goto again;
+ }
+ } /* vec_foreach (routes) */
+
+ dsunlock (sm);
+
+ /* Flush any data from this fib */
+ if (mp->count)
+ {
+ mp->count = htonl (mp->count);
+ vl_msg_api_send_shmem (q, (u8 *) & mp);
+ mp = 0;
+ }
+ }
+
+ /* If e.g. the last FIB had no reportable routes, free the buffer */
+ if (mp)
+ vl_msg_api_free (mp);
+}
+
+static void
+stats_thread_fn (void *arg)
+{
+ stats_main_t *sm = &stats_main;
+ vlib_worker_thread_t *w = (vlib_worker_thread_t *) arg;
+ vlib_thread_main_t *tm = vlib_get_thread_main ();
+
+ /* stats thread wants no signals. */
+ {
+ sigset_t s;
+ sigfillset (&s);
+ pthread_sigmask (SIG_SETMASK, &s, 0);
+ }
+
+ if (vec_len (tm->thread_prefix))
+ vlib_set_thread_name ((char *)
+ format (0, "%v_stats%c", tm->thread_prefix, '\0'));
+
+ clib_mem_set_heap (w->thread_mheap);
+
+ while (1)
+ {
+ /* 10 second poll interval */
+ ip46_fib_stats_delay (sm, 10 /* secs */ , 0 /* nsec */ );
+
+ if (!(sm->enable_poller))
+ {
+ continue;
+ }
+ if (pool_elts
+ (sm->stats_registrations[IDX_PER_INTERFACE_COMBINED_COUNTERS]))
+ do_combined_per_interface_counters (sm);
+
+ if (pool_elts
+ (sm->stats_registrations[IDX_PER_INTERFACE_SIMPLE_COUNTERS]))
+ do_simple_per_interface_counters (sm);
+
+ if (pool_elts (sm->stats_registrations[IDX_IP4_FIB_COUNTERS]))
+ do_ip4_fib_counters (sm);
+
+ if (pool_elts (sm->stats_registrations[IDX_IP6_FIB_COUNTERS]))
+ do_ip6_fib_counters (sm);
+
+ if (pool_elts (sm->stats_registrations[IDX_IP4_NBR_COUNTERS]))
+ do_ip4_nbr_counters (sm);
+
+ if (pool_elts (sm->stats_registrations[IDX_IP6_NBR_COUNTERS]))
+ do_ip6_nbr_counters (sm);
+ }
+}
+
+static void
+ vl_api_vnet_interface_simple_counters_t_handler
+ (vl_api_vnet_interface_simple_counters_t * mp)
+{
+ vpe_client_registration_t *clients, client;
+ stats_main_t *sm = &stats_main;
+ unix_shared_memory_queue_t *q, *q_prev = NULL;
+ vl_api_vnet_interface_simple_counters_t *mp_copy = NULL;
+ u32 mp_size;
+ int i;
+
+ mp_size = sizeof (*mp) + (ntohl (mp->count) * sizeof (u64));
+
+ clients =
+ get_clients_for_stat (IDX_PER_INTERFACE_SIMPLE_COUNTERS,
+ ~0 /*flag for all */ );
+
+ for (i = 0; i < vec_len (clients); i++)
+ {
+ client = clients[i];
+ q = vl_api_client_index_to_input_queue (client.client_index);
+ if (q)
+ {
+ if (q_prev && (q_prev->cursize < q_prev->maxsize))
+ {
+ mp_copy = vl_msg_api_alloc_as_if_client (mp_size);
+ clib_memcpy (mp_copy, mp, mp_size);
+ vl_msg_api_send_shmem (q_prev, (u8 *) & mp);
+ mp = mp_copy;
+ }
+ q_prev = q;
+ }
+ else
+ {
+ sm->enable_poller =
+ clear_client_for_stat (IDX_PER_INTERFACE_SIMPLE_COUNTERS, ~0,
+ client.client_index);
+ continue;
+ }
+ }
+
+#if STATS_DEBUG > 0
+ fformat (stdout, "%U\n", format_vnet_simple_counters, mp);
+#endif
+
+ if (q_prev && (q_prev->cursize < q_prev->maxsize))
+ {
+ vl_msg_api_send_shmem (q_prev, (u8 *) & mp);
+ }
+ else
+ {
+ vl_msg_api_free (mp);
+ }
+}
+
+
+
+
+
+static void
+vl_api_vnet_ip4_fib_counters_t_handler (vl_api_vnet_ip4_fib_counters_t * mp)
+{
+ stats_main_t *sm = &stats_main;
+ unix_shared_memory_queue_t *q, *q_prev = NULL;
+ vl_api_vnet_ip4_fib_counters_t *mp_copy = NULL;
+ u32 mp_size;
+ vpe_client_registration_t *clients, client;
+ int i;
+
+ mp_size = sizeof (*mp_copy) +
+ ntohl (mp->count) * sizeof (vl_api_ip4_fib_counter_t);
+
+ clients =
+ get_clients_for_stat (IDX_IP4_FIB_COUNTERS, ~0 /*flag for all */ );
+
+ for (i = 0; i < vec_len (clients); i++)
+ {
+ client = clients[i];
+ q = vl_api_client_index_to_input_queue (client.client_index);
+ if (q)
+ {
+ if (q_prev && (q_prev->cursize < q_prev->maxsize))
+ {
+ mp_copy = vl_msg_api_alloc_as_if_client (mp_size);
+ clib_memcpy (mp_copy, mp, mp_size);
+ vl_msg_api_send_shmem (q_prev, (u8 *) & mp);
+ mp = mp_copy;
+ }
+ q_prev = q;
+ }
+ else
+ {
+ sm->enable_poller = clear_client_for_stat (IDX_IP4_FIB_COUNTERS,
+ ~0, client.client_index);
+ continue;
+ }
+ }
+
+ if (q_prev && (q_prev->cursize < q_prev->maxsize))
+ {
+ vl_msg_api_send_shmem (q_prev, (u8 *) & mp);
+ }
+ else
+ {
+ vl_msg_api_free (mp);
+ }
+}
+
+static void
+vl_api_vnet_ip4_nbr_counters_t_handler (vl_api_vnet_ip4_nbr_counters_t * mp)
+{
+ stats_main_t *sm = &stats_main;
+ unix_shared_memory_queue_t *q, *q_prev = NULL;
+ vl_api_vnet_ip4_nbr_counters_t *mp_copy = NULL;
+ u32 mp_size;
+ vpe_client_registration_t *clients, client;
+ int i;
+
+ mp_size = sizeof (*mp_copy) +
+ ntohl (mp->count) * sizeof (vl_api_ip4_nbr_counter_t);
+
+ clients =
+ get_clients_for_stat (IDX_IP4_NBR_COUNTERS, ~0 /*flag for all */ );
+
+ for (i = 0; i < vec_len (clients); i++)
+ {
+ client = clients[i];
+ q = vl_api_client_index_to_input_queue (client.client_index);
+ if (q)
+ {
+ if (q_prev && (q_prev->cursize < q_prev->maxsize))
+ {
+ mp_copy = vl_msg_api_alloc_as_if_client (mp_size);
+ clib_memcpy (mp_copy, mp, mp_size);
+ vl_msg_api_send_shmem (q_prev, (u8 *) & mp);
+ mp = mp_copy;
+ }
+ q_prev = q;
+ }
+ else
+ {
+ sm->enable_poller = clear_client_for_stat (IDX_IP4_NBR_COUNTERS,
+ ~0, client.client_index);
+ continue;
+ }
+ }
+
+ /* *INDENT-ON* */
+ if (q_prev && (q_prev->cursize < q_prev->maxsize))
+ {
+ vl_msg_api_send_shmem (q_prev, (u8 *) & mp);
+ }
+ else
+ {
+ vl_msg_api_free (mp);
+ }
+}
+
+static void
+vl_api_vnet_ip6_fib_counters_t_handler (vl_api_vnet_ip6_fib_counters_t * mp)
+{
+ stats_main_t *sm = &stats_main;
+ unix_shared_memory_queue_t *q, *q_prev = NULL;
+ vl_api_vnet_ip6_fib_counters_t *mp_copy = NULL;
+ u32 mp_size;
+ vpe_client_registration_t *clients, client;
+ int i;
+
+ mp_size = sizeof (*mp_copy) +
+ ntohl (mp->count) * sizeof (vl_api_ip6_fib_counter_t);
+
+ clients =
+ get_clients_for_stat (IDX_IP6_FIB_COUNTERS, ~0 /*flag for all */ );
+
+ for (i = 0; i < vec_len (clients); i++)
+ {
+ client = clients[i];
+ q = vl_api_client_index_to_input_queue (client.client_index);
+ if (q)
+ {
+ if (q_prev && (q_prev->cursize < q_prev->maxsize))
+ {
+ mp_copy = vl_msg_api_alloc_as_if_client (mp_size);
+ clib_memcpy (mp_copy, mp, mp_size);
+ vl_msg_api_send_shmem (q_prev, (u8 *) & mp);
+ mp = mp_copy;
+ }
+ q_prev = q;
+ }
+ else
+ {
+ sm->enable_poller = clear_client_for_stat (IDX_IP6_FIB_COUNTERS,
+ ~0, client.client_index);
+ continue;
+ }
+ }
+ /* *INDENT-ON* */
+ if (q_prev && (q_prev->cursize < q_prev->maxsize))
+ {
+ vl_msg_api_send_shmem (q_prev, (u8 *) & mp);
+ }
+ else
+ {
+ vl_msg_api_free (mp);
+ }
+}
+
+static void
+vl_api_vnet_ip6_nbr_counters_t_handler (vl_api_vnet_ip6_nbr_counters_t * mp)
+{
+ stats_main_t *sm = &stats_main;
+ unix_shared_memory_queue_t *q, *q_prev = NULL;
+ vl_api_vnet_ip6_nbr_counters_t *mp_copy = NULL;
+ u32 mp_size;
+ vpe_client_registration_t *clients, client;
+ int i;
+
+ mp_size = sizeof (*mp_copy) +
+ ntohl (mp->count) * sizeof (vl_api_ip6_nbr_counter_t);
+
+ clients =
+ get_clients_for_stat (IDX_IP6_NBR_COUNTERS, ~0 /*flag for all */ );
+
+ for (i = 0; i < vec_len (clients); i++)
+ {
+ client = clients[i];
+ q = vl_api_client_index_to_input_queue (client.client_index);
+ if (q)
+ {
+ if (q_prev && (q_prev->cursize < q_prev->maxsize))
+ {
+ mp_copy = vl_msg_api_alloc_as_if_client (mp_size);
+ clib_memcpy (mp_copy, mp, mp_size);
+ vl_msg_api_send_shmem (q_prev, (u8 *) & mp);
+ mp = mp_copy;
+ }
+ q_prev = q;
+ }
+ else
+ {
+ sm->enable_poller = clear_client_for_stat (IDX_IP6_NBR_COUNTERS,
+ ~0, client.client_index);
+ continue;
+ }
+ }
+ /* *INDENT-ON* */
+ if (q_prev && (q_prev->cursize < q_prev->maxsize))
+ {
+ vl_msg_api_send_shmem (q_prev, (u8 *) & mp);
+ }
+ else
+ {
+ vl_msg_api_free (mp);
+ }
+}
+
+static void
+vl_api_want_stats_t_handler (vl_api_want_stats_t * mp)
+{
+ stats_main_t *sm = &stats_main;
+ vpe_client_registration_t rp;
+ vl_api_want_stats_reply_t *rmp;
+ uword *p;
+ i32 retval = 0;
+ u32 item;
+ unix_shared_memory_queue_t *q;
+
+ item = ~0; //"ALL THE THINGS IN THE THINGS
+ rp.client_index = mp->client_index;
+ rp.client_pid = mp->pid;
+
+ handle_client_registration (&rp, IDX_PER_INTERFACE_SIMPLE_COUNTERS,
+ item, mp->enable_disable);
+
+ handle_client_registration (&rp, IDX_PER_INTERFACE_COMBINED_COUNTERS,
+ item, mp->enable_disable);
+
+ handle_client_registration (&rp, IDX_IP4_FIB_COUNTERS,
+ item, mp->enable_disable);
+
+ handle_client_registration (&rp, IDX_IP4_NBR_COUNTERS,
+ item, mp->enable_disable);
+
+ handle_client_registration (&rp, IDX_IP6_FIB_COUNTERS,
+ item, mp->enable_disable);
+
+ handle_client_registration (&rp, IDX_IP6_NBR_COUNTERS,
+ item, mp->enable_disable);
+
+reply:
+ q = vl_api_client_index_to_input_queue (mp->client_index);
+
+ if (!q)
+ return;
+
+ rmp = vl_msg_api_alloc (sizeof (*rmp));
+ rmp->_vl_msg_id = ntohs (VL_API_WANT_STATS_REPLY);
+ rmp->context = mp->context;
+ rmp->retval = retval;
+
+ vl_msg_api_send_shmem (q, (u8 *) & rmp);
+}
+
+static void
+ vl_api_want_interface_simple_stats_t_handler
+ (vl_api_want_interface_simple_stats_t * mp)
+{
+ stats_main_t *sm = &stats_main;
+ vpe_client_registration_t rp;
+ vl_api_want_interface_simple_stats_reply_t *rmp;
+ uword *p;
+ i32 retval = 0;
+ u32 swif;
+ unix_shared_memory_queue_t *q;
+
+ swif = ~0; //Using same mechanism as _per_interface_
+ rp.client_index = mp->client_index;
+ rp.client_pid = mp->pid;
+
+ handle_client_registration (&rp, IDX_PER_INTERFACE_SIMPLE_COUNTERS, swif,
+ mp->enable_disable);
+
+reply:
+ q = vl_api_client_index_to_input_queue (mp->client_index);
+
+ if (!q)
+ {
+ sm->enable_poller =
+ clear_client_for_stat (IDX_PER_INTERFACE_SIMPLE_COUNTERS, swif,
+ mp->client_index);
+ return;
+ }
+
+ rmp = vl_msg_api_alloc (sizeof (*rmp));
+ rmp->_vl_msg_id = ntohs (VL_API_WANT_INTERFACE_SIMPLE_STATS_REPLY);
+ rmp->context = mp->context;
+ rmp->retval = retval;
+
+ vl_msg_api_send_shmem (q, (u8 *) & rmp);
+}
+
+
+static void
+vl_api_want_ip4_fib_stats_t_handler (vl_api_want_ip4_fib_stats_t * mp)
+{
+ stats_main_t *sm = &stats_main;
+ vpe_client_registration_t rp;
+ vl_api_want_ip4_fib_stats_reply_t *rmp;
+ uword *p;
+ i32 retval = 0;
+ unix_shared_memory_queue_t *q;
+ u32 fib;
+
+ fib = ~0; //Using same mechanism as _per_interface_
+ rp.client_index = mp->client_index;
+ rp.client_pid = mp->pid;
+
+ handle_client_registration (&rp, IDX_IP4_FIB_COUNTERS, fib,
+ mp->enable_disable);
+
+reply:
+ q = vl_api_client_index_to_input_queue (mp->client_index);
+
+ if (!q)
+ {
+ sm->enable_poller = clear_client_for_stat (IDX_IP4_FIB_COUNTERS,
+ fib, mp->client_index);
+ return;
+ }
+
+ rmp = vl_msg_api_alloc (sizeof (*rmp));
+ rmp->_vl_msg_id = ntohs (VL_API_WANT_IP4_FIB_STATS_REPLY);
+ rmp->context = mp->context;
+ rmp->retval = retval;
+
+ vl_msg_api_send_shmem (q, (u8 *) & rmp);
+}
+
+static void
+vl_api_want_ip6_fib_stats_t_handler (vl_api_want_ip6_fib_stats_t * mp)
+{
+ stats_main_t *sm = &stats_main;
+ vpe_client_registration_t rp;
+ vl_api_want_ip4_fib_stats_reply_t *rmp;
+ uword *p;
+ i32 retval = 0;
+ unix_shared_memory_queue_t *q;
+ u32 fib;
+
+ fib = ~0; //Using same mechanism as _per_interface_
+ rp.client_index = mp->client_index;
+ rp.client_pid = mp->pid;
+
+ handle_client_registration (&rp, IDX_IP6_FIB_COUNTERS, fib,
+ mp->enable_disable);
+
+reply:
+ q = vl_api_client_index_to_input_queue (mp->client_index);
+
+ if (!q)
+ {
+ sm->enable_poller = clear_client_for_stat (IDX_IP6_FIB_COUNTERS,
+ fib, mp->client_index);
+ return;
+ }
+
+ rmp = vl_msg_api_alloc (sizeof (*rmp));
+ rmp->_vl_msg_id = ntohs (VL_API_WANT_IP6_FIB_STATS_REPLY);
+ rmp->context = mp->context;
+ rmp->retval = retval;
+
+ vl_msg_api_send_shmem (q, (u8 *) & rmp);
+}
+
+/* FIXME - NBR stats broken - this will be fixed in subsequent patch */
+static void
+vl_api_want_ip4_nbr_stats_t_handler (vl_api_want_ip4_nbr_stats_t * mp)
+{
+}
+
+static void
+vl_api_want_ip6_nbr_stats_t_handler (vl_api_want_ip6_nbr_stats_t * mp)
+{
+}
+
+static void
+vl_api_vnet_get_summary_stats_t_handler (vl_api_vnet_get_summary_stats_t * mp)
+{
+ stats_main_t *sm = &stats_main;
+ vnet_interface_main_t *im = sm->interface_main;
+ vl_api_vnet_get_summary_stats_reply_t *rmp;
+ vlib_combined_counter_main_t *cm;
+ vlib_counter_t v;
+ int i, which;
+ u64 total_pkts[VLIB_N_RX_TX];
+ u64 total_bytes[VLIB_N_RX_TX];
+
+ unix_shared_memory_queue_t *q =
+ vl_api_client_index_to_input_queue (mp->client_index);
+
+ if (!q)
+ {
+ return;
+ }
+
+ rmp = vl_msg_api_alloc (sizeof (*rmp));
+ rmp->_vl_msg_id = ntohs (VL_API_VNET_GET_SUMMARY_STATS_REPLY);
+ rmp->context = mp->context;
+ rmp->retval = 0;
+
+ memset (total_pkts, 0, sizeof (total_pkts));
+ memset (total_bytes, 0, sizeof (total_bytes));
+
+ vnet_interface_counter_lock (im);
+
+ vec_foreach (cm, im->combined_sw_if_counters)
+ {
+ which = cm - im->combined_sw_if_counters;
+
+ for (i = 0; i < vlib_combined_counter_n_counters (cm); i++)
+ {
+ vlib_get_combined_counter (cm, i, &v);
+ total_pkts[which] += v.packets;
+ total_bytes[which] += v.bytes;
+ }
+ }
+ vnet_interface_counter_unlock (im);
+
+ rmp->total_pkts[VLIB_RX] = clib_host_to_net_u64 (total_pkts[VLIB_RX]);
+ rmp->total_bytes[VLIB_RX] = clib_host_to_net_u64 (total_bytes[VLIB_RX]);
+ rmp->total_pkts[VLIB_TX] = clib_host_to_net_u64 (total_pkts[VLIB_TX]);
+ rmp->total_bytes[VLIB_TX] = clib_host_to_net_u64 (total_bytes[VLIB_TX]);
+ rmp->vector_rate =
+ clib_host_to_net_u64 (vlib_last_vector_length_per_node (sm->vlib_main));
+
+ vl_msg_api_send_shmem (q, (u8 *) & rmp);
+}
+
+int
+stats_memclnt_delete_callback (u32 client_index)
+{
+ vpe_client_stats_registration_t *rp;
+ stats_main_t *sm = &stats_main;
+ uword *p;
+
+ // FIXME
+ /* p = hash_get (sm->stats_registration_hash, client_index); */
+ /* if (p) */
+ /* { */
+ /* rp = pool_elt_at_index (sm->stats_registrations, p[0]); */
+ /* pool_put (sm->stats_registrations, rp); */
+ /* hash_unset (sm->stats_registration_hash, client_index); */
+ /* } */
+
+ return 0;
+}
+
+#define vl_api_vnet_interface_simple_counters_t_endian vl_noop_handler
+#define vl_api_vnet_interface_simple_counters_t_print vl_noop_handler
+#define vl_api_vnet_interface_combined_counters_t_endian vl_noop_handler
+#define vl_api_vnet_interface_combined_counters_t_print vl_noop_handler
+#define vl_api_vnet_ip4_fib_counters_t_endian vl_noop_handler
+#define vl_api_vnet_ip4_fib_counters_t_print vl_noop_handler
+#define vl_api_vnet_ip6_fib_counters_t_endian vl_noop_handler
+#define vl_api_vnet_ip6_fib_counters_t_print vl_noop_handler
+#define vl_api_vnet_ip4_nbr_counters_t_endian vl_noop_handler
+#define vl_api_vnet_ip4_nbr_counters_t_print vl_noop_handler
+#define vl_api_vnet_ip6_nbr_counters_t_endian vl_noop_handler
+#define vl_api_vnet_ip6_nbr_counters_t_print vl_noop_handler
+
+static clib_error_t *
+stats_init (vlib_main_t * vm)
+{
+ stats_main_t *sm = &stats_main;
+ api_main_t *am = &api_main;
+ void *vlib_worker_thread_bootstrap_fn (void *arg);
+
+ sm->vlib_main = vm;
+ sm->vnet_main = vnet_get_main ();
+ sm->interface_main = &vnet_get_main ()->interface_main;
+ sm->api_main = am;
+ sm->stats_poll_interval_in_seconds = 10;
+ sm->data_structure_lock =
+ clib_mem_alloc_aligned (sizeof (data_structure_lock_t),
+ CLIB_CACHE_LINE_BYTES);
+ memset (sm->data_structure_lock, 0, sizeof (*sm->data_structure_lock));
+
+#define _(N,n) \
+ vl_msg_api_set_handlers(VL_API_##N, #n, \
+ vl_api_##n##_t_handler, \
+ vl_noop_handler, \
+ vl_api_##n##_t_endian, \
+ vl_api_##n##_t_print, \
+ sizeof(vl_api_##n##_t), 0 /* do NOT trace! */);
+ foreach_stats_msg;
+#undef _
+
+ /* tell the msg infra not to free these messages... */
+ am->message_bounce[VL_API_VNET_INTERFACE_SIMPLE_COUNTERS] = 1;
+ am->message_bounce[VL_API_VNET_INTERFACE_COMBINED_COUNTERS] = 1;
+ am->message_bounce[VL_API_VNET_IP4_FIB_COUNTERS] = 1;
+ am->message_bounce[VL_API_VNET_IP6_FIB_COUNTERS] = 1;
+ am->message_bounce[VL_API_VNET_IP4_NBR_COUNTERS] = 1;
+ am->message_bounce[VL_API_VNET_IP6_NBR_COUNTERS] = 1;
+
+ /*
+ * Set up the (msg_name, crc, message-id) table
+ */
+ setup_message_id_table (am);
+
+ vec_validate (sm->stats_registrations, STATS_REG_N_IDX);
+ vec_validate (sm->stats_registration_hash, STATS_REG_N_IDX);
+#define stats_reg(n) \
+ sm->stats_registrations[IDX_##n] = 0; \
+ sm->stats_registration_hash[IDX_##n] = 0;
+#include <vpp/stats/stats.reg>
+#undef stats_reg
+
+ return 0;
+}
+
+VLIB_INIT_FUNCTION (stats_init);
+
+/* *INDENT-OFF* */
+VLIB_REGISTER_THREAD (stats_thread_reg, static) = {
+ .name = "stats",
+ .function = stats_thread_fn,
+ .fixed_count = 1,
+ .count = 1,
+ .no_data_structure_clone = 1,
+ .use_pthreads = 1,
+};
+/* *INDENT-ON* */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/src/vpp/stats/stats.h b/src/vpp/stats/stats.h
new file mode 100644
index 00000000..042bcb65
--- /dev/null
+++ b/src/vpp/stats/stats.h
@@ -0,0 +1,200 @@
+/*
+ * 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.
+ */
+#ifndef __included_stats_h__
+#define __included_stats_h__
+
+#include <time.h>
+#include <vlib/vlib.h>
+#include <vnet/vnet.h>
+#include <vnet/interface.h>
+#include <pthread.h>
+#include <vlib/threads.h>
+#include <vnet/fib/fib_table.h>
+#include <vlib/unix/unix.h>
+#include <vlibmemory/api.h>
+#include <vlibmemory/unix_shared_memory_queue.h>
+#include <vlibapi/api_helper_macros.h>
+
+typedef struct
+{
+ volatile u32 lock;
+ volatile u32 release_hint;
+ u32 thread_index;
+ u32 count;
+ int tag;
+} data_structure_lock_t;
+
+/**
+ * @brief stats request registration indexes
+ *
+ */
+/* from .../vnet/vnet/ip/lookup.c. Yuck */
+typedef CLIB_PACKED (struct
+ {
+ ip4_address_t address;
+u32 address_length: 6;
+u32 index: 26;
+ }) ip4_route_t;
+
+/* see interface.api */
+typedef struct
+{
+ u32 sw_if_index;
+ u64 drop;
+ u64 punt;
+ u64 rx_ip4;
+ u64 rx_ip6;
+ u64 rx_no_buffer;
+ u64 rx_miss;
+ u64 rx_error;
+ u64 tx_error;
+ u64 rx_mpls;
+} vnet_simple_counter_t;
+
+typedef struct
+{
+ u32 sw_if_index;
+ u64 rx_packets; /**< packet counter */
+ u64 rx_bytes; /**< byte counter */
+ u64 tx_packets; /**< packet counter */
+ u64 tx_bytes; /**< byte counter */
+} vnet_combined_counter_t;
+
+typedef struct
+{
+ ip6_address_t address;
+ u32 address_length;
+ u32 index;
+} ip6_route_t;
+
+
+typedef struct
+{
+ ip4_route_t *ip4routes;
+ ip6_route_t *ip6routes;
+ fib_table_t **fibs;
+ hash_pair_t **pvec;
+ uword *results;
+} do_ip46_fibs_t;
+
+typedef struct
+{
+ u16 msg_id;
+ u32 size;
+ u32 client_index;
+ u32 context;
+ i32 retval;
+} client_registration_reply_t;
+
+typedef enum
+{
+#define stats_reg(n) IDX_##n,
+#include <vpp/stats/stats.reg>
+#undef stats_reg
+ STATS_REG_N_IDX,
+} stats_reg_index_t;
+
+typedef struct
+{
+ //Standard client information
+ uword *client_hash;
+ vpe_client_registration_t *clients;
+ u32 item;
+
+} vpe_client_stats_registration_t;
+
+
+typedef struct
+{
+ void *mheap;
+ pthread_t thread_self;
+ pthread_t thread_handle;
+
+ u32 stats_poll_interval_in_seconds;
+ u32 enable_poller;
+
+ /*
+ * stats_registrations is a vector, indexed by
+ * IDX_xxxx_COUNTER generated for each streaming
+ * stat a client can register for. (see stats.reg)
+ *
+ * The values in the vector refer to pools.
+ *
+ * The pool is of type vpe_client_stats_registration_t
+ *
+ * This typedef consists of:
+ *
+ * u32 item: This is the instance of the IDX_xxxx_COUNTER a
+ * client is interested in.
+ * vpe_client_registration_t *clients: The list of clients interested.
+ *
+ * e.g.
+ * stats_registrations[IDX_INTERFACE_SIMPLE_COUNTERS] refers to a pool
+ * containing elements:
+ *
+ * u32 item = sw_if_index1
+ * clients = ["clienta","clientb"]
+ *
+ * When clients == NULL the pool element is freed. When the pool is empty
+ *
+ * ie
+ * 0 == pool_elts(stats_registrations[IDX_INTERFACE_SIMPLE_COUNTERS]
+ *
+ * then there is no need to process INTERFACE_SIMPLE_COUNTERS
+ *
+ * Note that u32 item = ~0 is the simple case for ALL interfaces or fibs.
+ *
+ */
+
+ uword **stats_registration_hash;
+ vpe_client_stats_registration_t **stats_registrations;
+
+ /* control-plane data structure lock */
+ data_structure_lock_t *data_structure_lock;
+
+ /* bail out of FIB walk if set */
+ clib_longjmp_t jmp_buf;
+
+ /* Vectors for Distribution funcs: do_ip4_fibs and do_ip6_fibs. */
+ do_ip46_fibs_t do_ip46_fibs;
+
+ /*
+ Working vector vars so as to not thrash memory allocator.
+ Has effect of making "static"
+ */
+ vpe_client_stats_registration_t **regs_tmp;
+ vpe_client_registration_t **clients_tmp;
+
+ /* convenience */
+ vlib_main_t *vlib_main;
+ vnet_main_t *vnet_main;
+ vnet_interface_main_t *interface_main;
+ api_main_t *api_main;
+} stats_main_t;
+
+stats_main_t stats_main;
+
+void dslock (stats_main_t * sm, int release_hint, int tag);
+void dsunlock (stats_main_t * sm);
+
+#endif /* __included_stats_h__ */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/src/vpp/stats/stats.reg b/src/vpp/stats/stats.reg
new file mode 100644
index 00000000..d76443c4
--- /dev/null
+++ b/src/vpp/stats/stats.reg
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2017 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.
+ */
+/**
+ * @file
+ * @brief Client stats registrations
+ *
+ * Each entry is a specific REGISTRATION as
+ * opposed to an API call.
+ *
+ * For instance:
+ * want_stats()
+ * enables/disables ALL stats entries below for all
+ * ITEM.
+ *
+ * An item is the an incident of the thing we want stats for
+ * such as a FIB or sw_if_index for interface. In each case the
+ * value ~0 is treated as ALL ITEMs.
+ *
+ * As such want_interface_simple_counters() is translated to
+ * want_per_interface_simple_counters(item=~0)
+ */
+
+
+stats_reg (IP4_FIB_COUNTERS)
+stats_reg (IP4_NBR_COUNTERS)
+stats_reg (IP6_FIB_COUNTERS)
+stats_reg (IP6_NBR_COUNTERS)
+stats_reg (PER_INTERFACE_COMBINED_COUNTERS)
+stats_reg (PER_INTERFACE_SIMPLE_COUNTERS)
+
diff --git a/src/vpp/vnet/main.c b/src/vpp/vnet/main.c
new file mode 100644
index 00000000..b330f60f
--- /dev/null
+++ b/src/vpp/vnet/main.c
@@ -0,0 +1,367 @@
+/*
+ * 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.
+ */
+
+#include <vppinfra/cpu.h>
+#include <vlib/vlib.h>
+#include <vlib/unix/unix.h>
+#include <vnet/plugin/plugin.h>
+#include <vnet/ethernet/ethernet.h>
+#include <vpp/app/version.h>
+#include <vpp/api/vpe_msg_enum.h>
+
+
+static void
+vpe_main_init (vlib_main_t * vm)
+{
+ void vat_plugin_hash_create (void);
+
+ if (CLIB_DEBUG > 0)
+ vlib_unix_cli_set_prompt ("DBGvpp# ");
+ else
+ vlib_unix_cli_set_prompt ("vpp# ");
+
+ /* Turn off network stack components which we don't want */
+ vlib_mark_init_function_complete (vm, srp_init);
+
+ /*
+ * Create the binary api plugin hashes before loading plugins
+ */
+ vat_plugin_hash_create ();
+}
+
+/*
+ * Default path for runtime data
+ */
+char *vlib_default_runtime_dir = "vpp";
+
+/*
+ * Load plugins from /usr/lib/vpp_plugins by default
+ */
+char *vlib_plugin_path = "/usr/lib/vpp_plugins";
+char *vlib_plugin_app_version = VPP_BUILD_VER;
+
+int
+main (int argc, char *argv[])
+{
+ int i;
+ vlib_main_t *vm = &vlib_global_main;
+ void vl_msg_api_set_first_available_msg_id (u16);
+ uword main_heap_size = (1ULL << 30);
+ u8 *sizep;
+ u32 size;
+
+#if __x86_64__
+ CLIB_UNUSED (const char *msg)
+ = "ERROR: This binary requires CPU with %s extensions.\n";
+#define _(a,b) \
+ if (!clib_cpu_supports_ ## a ()) \
+ { \
+ fprintf(stderr, msg, b); \
+ exit(1); \
+ }
+
+#if __AVX2__
+ _(avx2, "AVX2")
+#endif
+#if __AVX__
+ _(avx, "AVX")
+#endif
+#if __SSE4_2__
+ _(sse42, "SSE4.2")
+#endif
+#if __SSE4_1__
+ _(sse41, "SSE4.1")
+#endif
+#if __SSSE3__
+ _(ssse3, "SSSE3")
+#endif
+#if __SSE3__
+ _(sse3, "SSE3")
+#endif
+#undef _
+#endif
+ /*
+ * Load startup config from file.
+ * usage: vpp -c /etc/vpp/startup.conf
+ */
+ if ((argc == 3) && !strncmp (argv[1], "-c", 2))
+ {
+ FILE *fp;
+ char inbuf[4096];
+ int argc_ = 1;
+ char **argv_ = NULL;
+ char *arg = NULL;
+ char *p;
+
+ fp = fopen (argv[2], "r");
+ if (fp == NULL)
+ {
+ fprintf (stderr, "open configuration file '%s' failed\n", argv[2]);
+ return 1;
+ }
+ argv_ = calloc (1, sizeof (char *));
+ if (argv_ == NULL)
+ return 1;
+ arg = strndup (argv[0], 1024);
+ if (arg == NULL)
+ return 1;
+ argv_[0] = arg;
+
+ while (1)
+ {
+ if (fgets (inbuf, 4096, fp) == 0)
+ break;
+ p = strtok (inbuf, " \t\n");
+ while (p != NULL)
+ {
+ if (*p == '#')
+ break;
+ argc_++;
+ char **tmp = realloc (argv_, argc_ * sizeof (char *));
+ if (tmp == NULL)
+ return 1;
+ argv_ = tmp;
+ arg = strndup (p, 1024);
+ if (arg == NULL)
+ return 1;
+ argv_[argc_ - 1] = arg;
+ p = strtok (NULL, " \t\n");
+ }
+ }
+
+ fclose (fp);
+
+ char **tmp = realloc (argv_, (argc_ + 1) * sizeof (char *));
+ if (tmp == NULL)
+ return 1;
+ argv_ = tmp;
+ argv_[argc_] = NULL;
+
+ argc = argc_;
+ argv = argv_;
+ }
+
+ /*
+ * Look for and parse the "heapsize" config parameter.
+ * Manual since none of the clib infra has been bootstrapped yet.
+ *
+ * Format: heapsize <nn>[mM][gG]
+ */
+
+ for (i = 1; i < (argc - 1); i++)
+ {
+ if (!strncmp (argv[i], "plugin_path", 11))
+ {
+ if (i < (argc - 1))
+ vlib_plugin_path = argv[++i];
+ }
+ else if (!strncmp (argv[i], "heapsize", 8))
+ {
+ sizep = (u8 *) argv[i + 1];
+ size = 0;
+ while (*sizep >= '0' && *sizep <= '9')
+ {
+ size *= 10;
+ size += *sizep++ - '0';
+ }
+ if (size == 0)
+ {
+ fprintf
+ (stderr,
+ "warning: heapsize parse error '%s', use default %lld\n",
+ argv[i], (long long int) main_heap_size);
+ goto defaulted;
+ }
+
+ main_heap_size = size;
+
+ if (*sizep == 'g' || *sizep == 'G')
+ main_heap_size <<= 30;
+ else if (*sizep == 'm' || *sizep == 'M')
+ main_heap_size <<= 20;
+ }
+ }
+
+defaulted:
+
+ /* Set up the plugin message ID allocator right now... */
+ vl_msg_api_set_first_available_msg_id (VL_MSG_FIRST_AVAILABLE);
+
+ /* Allocate main heap */
+ if (clib_mem_init (0, main_heap_size))
+ {
+ vm->init_functions_called = hash_create (0, /* value bytes */ 0);
+ vpe_main_init (vm);
+ return vlib_unix_main (argc, argv);
+ }
+ else
+ {
+ {
+ int rv __attribute__ ((unused)) =
+ write (2, "Main heap allocation failure!\r\n", 31);
+ }
+ return 1;
+ }
+}
+
+static clib_error_t *
+heapsize_config (vlib_main_t * vm, unformat_input_t * input)
+{
+ u32 junk;
+
+ while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (input, "%dm", &junk)
+ || unformat (input, "%dM", &junk)
+ || unformat (input, "%dg", &junk) || unformat (input, "%dG", &junk))
+ return 0;
+ else
+ return clib_error_return (0, "unknown input '%U'",
+ format_unformat_error, input);
+ }
+ return 0;
+}
+
+VLIB_CONFIG_FUNCTION (heapsize_config, "heapsize");
+
+static clib_error_t *
+plugin_path_config (vlib_main_t * vm, unformat_input_t * input)
+{
+ u8 *junk;
+
+ while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (input, "%s", &junk))
+ {
+ vec_free (junk);
+ return 0;
+ }
+ else
+ return clib_error_return (0, "unknown input '%U'",
+ format_unformat_error, input);
+ }
+ return 0;
+}
+
+VLIB_CONFIG_FUNCTION (plugin_path_config, "plugin_path");
+
+void vl_msg_api_post_mortem_dump (void);
+void elog_post_mortem_dump (void);
+
+void
+os_panic (void)
+{
+ vl_msg_api_post_mortem_dump ();
+ elog_post_mortem_dump ();
+ abort ();
+}
+
+void vhost_user_unmap_all (void) __attribute__ ((weak));
+void
+vhost_user_unmap_all (void)
+{
+}
+
+void
+os_exit (int code)
+{
+ static int recursion_block;
+
+ if (code)
+ {
+ if (recursion_block)
+ abort ();
+
+ recursion_block = 1;
+
+ vl_msg_api_post_mortem_dump ();
+ elog_post_mortem_dump ();
+ vhost_user_unmap_all ();
+ abort ();
+ }
+ exit (code);
+}
+
+#ifdef BARRIER_TRACING
+void
+vl_msg_api_barrier_trace_context (const char *context)
+{
+ vlib_worker_threads[0].barrier_context = context;
+}
+#endif
+
+void
+vl_msg_api_barrier_sync (void)
+{
+ vlib_worker_thread_barrier_sync (vlib_get_main ());
+}
+
+void
+vl_msg_api_barrier_release (void)
+{
+ vlib_worker_thread_barrier_release (vlib_get_main ());
+}
+
+/* This application needs 1 thread stack for the stats pthread */
+u32
+vlib_app_num_thread_stacks_needed (void)
+{
+ return 1;
+}
+
+/*
+ * Depending on the configuration selected above,
+ * it may be necessary to generate stub graph nodes.
+ * It is never OK to ignore "node 'x' refers to unknown node 'y'
+ * messages!
+ */
+
+#if CLIB_DEBUG > 0
+
+static clib_error_t *
+test_crash_command_fn (vlib_main_t * vm,
+ unformat_input_t * input, vlib_cli_command_t * cmd)
+{
+ u64 *p = (u64 *) 0xdefec8ed;
+
+ ELOG_TYPE_DECLARE (e) =
+ {
+ .format = "deliberate crash: touching %x",.format_args = "i4",};
+
+ elog (&vm->elog_main, &e, 0xdefec8ed);
+
+ *p = 0xdeadbeef;
+
+ /* Not so much... */
+ return 0;
+}
+
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND (test_crash_command, static) = {
+ .path = "test crash",
+ .short_help = "crash the bus!",
+ .function = test_crash_command_fn,
+};
+/* *INDENT-ON* */
+
+#endif
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */