summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/plugins/ping/CMakeLists.txt5
-rw-r--r--src/plugins/ping/ping.api46
-rw-r--r--src/plugins/ping/ping.c76
-rw-r--r--src/plugins/ping/ping.h73
-rw-r--r--src/plugins/ping/ping_api.c155
-rw-r--r--test/test_ping.py34
6 files changed, 319 insertions, 70 deletions
diff --git a/src/plugins/ping/CMakeLists.txt b/src/plugins/ping/CMakeLists.txt
index 2828f769fcc..d0040ff373a 100644
--- a/src/plugins/ping/CMakeLists.txt
+++ b/src/plugins/ping/CMakeLists.txt
@@ -14,4 +14,9 @@
add_vpp_plugin(ping
SOURCES
ping.c
+ ping.h
+ ping_api.c
+
+ API_FILES
+ ping.api
)
diff --git a/src/plugins/ping/ping.api b/src/plugins/ping/ping.api
new file mode 100644
index 00000000000..4cf043f5c31
--- /dev/null
+++ b/src/plugins/ping/ping.api
@@ -0,0 +1,46 @@
+/* Hey Emacs use -*- mode: C -*- */
+/*
+ * Copyright (c) 2023 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.
+ */
+
+option version = "0.1.0";
+import "vnet/interface_types.api";
+import "vnet/ip/ip_types.api";
+
+autoreply define want_ping_finished_events
+{
+ u32 client_index;
+ u32 context;
+ vl_api_address_t address;
+ u32 repeat [default=1];
+ f64 interval [default=1.0];
+};
+
+define ping_finished_event
+{
+ u32 client_index;
+ u32 request_count;
+ u32 reply_count;
+};
+
+service {
+ rpc want_ping_finished_events returns want_ping_finished_events_reply
+ events ping_finished_event;
+};
+
+/*
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/src/plugins/ping/ping.c b/src/plugins/ping/ping.c
index 050048211e6..ca2fc1fa055 100644
--- a/src/plugins/ping/ping.c
+++ b/src/plugins/ping/ping.c
@@ -99,70 +99,6 @@ format_ip46_ping_result (u8 * s, va_list * args)
*
*/
-
-static_always_inline uword
-get_cli_process_id_by_icmp_id_mt (vlib_main_t * vm, u16 icmp_id)
-{
- ping_main_t *pm = &ping_main;
- uword cli_process_id = PING_CLI_UNKNOWN_NODE;
- ping_run_t *pr;
-
- clib_spinlock_lock_if_init (&pm->ping_run_check_lock);
- vec_foreach (pr, pm->active_ping_runs)
- {
- if (pr->icmp_id == icmp_id)
- {
- cli_process_id = pr->cli_process_id;
- break;
- }
- }
- clib_spinlock_unlock_if_init (&pm->ping_run_check_lock);
- return cli_process_id;
-}
-
-
-static_always_inline void
-set_cli_process_id_by_icmp_id_mt (vlib_main_t * vm, u16 icmp_id,
- uword cli_process_id)
-{
- ping_main_t *pm = &ping_main;
- ping_run_t *pr;
-
- clib_spinlock_lock_if_init (&pm->ping_run_check_lock);
- vec_foreach (pr, pm->active_ping_runs)
- {
- if (pr->icmp_id == icmp_id)
- {
- pr->cli_process_id = cli_process_id;
- goto have_found_and_set;
- }
- }
- /* no such key yet - add a new one */
- ping_run_t new_pr = {.icmp_id = icmp_id,.cli_process_id = cli_process_id };
- vec_add1 (pm->active_ping_runs, new_pr);
-have_found_and_set:
- clib_spinlock_unlock_if_init (&pm->ping_run_check_lock);
-}
-
-
-static_always_inline void
-clear_cli_process_id_by_icmp_id_mt (vlib_main_t * vm, u16 icmp_id)
-{
- ping_main_t *pm = &ping_main;
- ping_run_t *pr;
-
- clib_spinlock_lock_if_init (&pm->ping_run_check_lock);
- vec_foreach (pr, pm->active_ping_runs)
- {
- if (pr->icmp_id == icmp_id)
- {
- vec_del1 (pm->active_ping_runs, pr - pm->active_ping_runs);
- break;
- }
- }
- clib_spinlock_unlock_if_init (&pm->ping_run_check_lock);
-}
-
static_always_inline int
ip46_get_icmp_id_and_seq (vlib_main_t * vm, vlib_buffer_t * b0,
u16 * out_icmp_id, u16 * out_icmp_seq, int is_ip6)
@@ -1229,9 +1165,8 @@ done:
return err;
}
-static send_ip46_ping_result_t
-send_ip6_ping (vlib_main_t * vm,
- u32 table_id, ip6_address_t * pa6,
+send_ip46_ping_result_t
+send_ip6_ping (vlib_main_t *vm, u32 table_id, ip6_address_t *pa6,
u32 sw_if_index, u16 seq_host, u16 id_host, u16 data_len,
u32 burst, u8 verbose)
{
@@ -1241,9 +1176,8 @@ send_ip6_ping (vlib_main_t * vm,
id_host, data_len, burst, verbose, 1 /* is_ip6 */ );
}
-static send_ip46_ping_result_t
-send_ip4_ping (vlib_main_t * vm,
- u32 table_id, ip4_address_t * pa4,
+send_ip46_ping_result_t
+send_ip4_ping (vlib_main_t *vm, u32 table_id, ip4_address_t *pa4,
u32 sw_if_index, u16 seq_host, u16 id_host, u16 data_len,
u32 burst, u8 verbose)
{
@@ -1678,6 +1612,8 @@ ping_cli_init (vlib_main_t * vm)
icmp6_register_type (vm, ICMP6_echo_request,
ip6_icmp_echo_request_node.index);
+ ping_plugin_api_hookup (vm);
+
return 0;
}
diff --git a/src/plugins/ping/ping.h b/src/plugins/ping/ping.h
index 7826945ea8b..e789300acd6 100644
--- a/src/plugins/ping/ping.h
+++ b/src/plugins/ping/ping.h
@@ -52,6 +52,9 @@ typedef struct ping_run_t
typedef struct ping_main_t
{
+ /* API message ID base */
+ u16 msg_id_base;
+
ip6_main_t *ip6_main;
ip4_main_t *ip4_main;
/* a vector of current ping runs. */
@@ -88,4 +91,74 @@ typedef enum
ICMP46_ECHO_REPLY_N_NEXT,
} icmp46_echo_reply_next_t;
+static_always_inline uword
+get_cli_process_id_by_icmp_id_mt (vlib_main_t *vm, u16 icmp_id)
+{
+ ping_main_t *pm = &ping_main;
+ uword cli_process_id = PING_CLI_UNKNOWN_NODE;
+ ping_run_t *pr;
+
+ clib_spinlock_lock_if_init (&pm->ping_run_check_lock);
+ vec_foreach (pr, pm->active_ping_runs)
+ {
+ if (pr->icmp_id == icmp_id)
+ {
+ cli_process_id = pr->cli_process_id;
+ break;
+ }
+ }
+ clib_spinlock_unlock_if_init (&pm->ping_run_check_lock);
+ return cli_process_id;
+}
+
+static_always_inline void
+set_cli_process_id_by_icmp_id_mt (vlib_main_t *vm, u16 icmp_id,
+ uword cli_process_id)
+{
+ ping_main_t *pm = &ping_main;
+ ping_run_t *pr;
+
+ clib_spinlock_lock_if_init (&pm->ping_run_check_lock);
+ vec_foreach (pr, pm->active_ping_runs)
+ {
+ if (pr->icmp_id == icmp_id)
+ {
+ pr->cli_process_id = cli_process_id;
+ goto have_found_and_set;
+ }
+ }
+ /* no such key yet - add a new one */
+ ping_run_t new_pr = { .icmp_id = icmp_id, .cli_process_id = cli_process_id };
+ vec_add1 (pm->active_ping_runs, new_pr);
+have_found_and_set:
+ clib_spinlock_unlock_if_init (&pm->ping_run_check_lock);
+}
+
+static_always_inline void
+clear_cli_process_id_by_icmp_id_mt (vlib_main_t *vm, u16 icmp_id)
+{
+ ping_main_t *pm = &ping_main;
+ ping_run_t *pr;
+
+ clib_spinlock_lock_if_init (&pm->ping_run_check_lock);
+ vec_foreach (pr, pm->active_ping_runs)
+ {
+ if (pr->icmp_id == icmp_id)
+ {
+ vec_del1 (pm->active_ping_runs, pr - pm->active_ping_runs);
+ break;
+ }
+ }
+ clib_spinlock_unlock_if_init (&pm->ping_run_check_lock);
+}
+clib_error_t *ping_plugin_api_hookup (vlib_main_t *vm);
+send_ip46_ping_result_t send_ip4_ping (vlib_main_t *vm, u32 table_id,
+ ip4_address_t *pa4, u32 sw_if_index,
+ u16 seq_host, u16 id_host, u16 data_len,
+ u32 burst, u8 verbose);
+send_ip46_ping_result_t send_ip6_ping (vlib_main_t *vm, u32 table_id,
+ ip6_address_t *pa6, u32 sw_if_index,
+ u16 seq_host, u16 id_host, u16 data_len,
+ u32 burst, u8 verbose);
+
#endif /* included_ping_ping_h */
diff --git a/src/plugins/ping/ping_api.c b/src/plugins/ping/ping_api.c
new file mode 100644
index 00000000000..5578fa560f2
--- /dev/null
+++ b/src/plugins/ping/ping_api.c
@@ -0,0 +1,155 @@
+/*
+ *------------------------------------------------------------------
+ * Copyright (c) 2023 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 <vlib/unix/unix.h>
+#include <vlib/pci/pci.h>
+#include <vnet/ethernet/ethernet.h>
+#include <vnet/format_fns.h>
+#include <vnet/ip/ip_types_api.h>
+
+#include <vlibapi/api.h>
+#include <vlibmemory/api.h>
+
+#include <ping/ping.h>
+
+/* define message IDs */
+#include <ping/ping.api_enum.h>
+#include <ping/ping.api_types.h>
+
+#define REPLY_MSG_ID_BASE pm->msg_id_base
+#include <vlibapi/api_helper_macros.h>
+
+static void
+ping_api_send_ping_event (vl_api_want_ping_finished_events_t *mp,
+ u32 request_count, u32 reply_count)
+{
+ ping_main_t *pm = &ping_main;
+
+ vl_api_registration_t *rp;
+ rp = vl_api_client_index_to_registration (mp->client_index);
+
+ vl_api_ping_finished_event_t *e = vl_msg_api_alloc (sizeof (*e));
+ clib_memset (e, 0, sizeof (*e));
+
+ e->_vl_msg_id = htons (VL_API_PING_FINISHED_EVENT + pm->msg_id_base);
+ e->request_count = htonl (request_count);
+ e->reply_count = htonl (reply_count);
+
+ vl_api_send_msg (rp, (u8 *) e);
+}
+
+void
+vl_api_want_ping_finished_events_t_handler (
+ vl_api_want_ping_finished_events_t *mp)
+{
+ vlib_main_t *vm = vlib_get_main ();
+ ping_main_t *pm = &ping_main;
+ vl_api_want_ping_finished_events_reply_t *rmp;
+
+ uword curr_proc = vlib_current_process (vm);
+
+ u16 icmp_id;
+ static u32 rand_seed = 0;
+
+ if (PREDICT_FALSE (!rand_seed))
+ rand_seed = random_default_seed ();
+
+ icmp_id = random_u32 (&rand_seed) & 0xffff;
+
+ while (~0 != get_cli_process_id_by_icmp_id_mt (vm, icmp_id))
+ icmp_id++;
+
+ set_cli_process_id_by_icmp_id_mt (vm, icmp_id, curr_proc);
+
+ int rv = 0;
+ u32 request_count = 0;
+ u32 reply_count = 0;
+
+ u32 table_id = 0;
+ ip_address_t dst_addr = { 0 };
+ u32 sw_if_index = ~0;
+ f64 ping_interval = clib_net_to_host_f64 (mp->interval);
+ u32 ping_repeat = ntohl (mp->repeat);
+ u32 data_len = PING_DEFAULT_DATA_LEN;
+ u32 ping_burst = 1;
+ u32 verbose = 0;
+ ip_address_decode2 (&mp->address, &dst_addr);
+
+ vl_api_registration_t *rp;
+ rp = vl_api_client_index_to_registration (mp->client_index);
+
+ rmp = vl_msg_api_alloc (sizeof (*rmp));
+ rmp->_vl_msg_id =
+ htons ((VL_API_WANT_PING_FINISHED_EVENTS_REPLY) + (REPLY_MSG_ID_BASE));
+ rmp->context = mp->context;
+ rmp->retval = ntohl (rv);
+ vl_api_send_msg (rp, (u8 *) rmp);
+
+ int i;
+ send_ip46_ping_result_t res = SEND_PING_OK;
+ for (i = 1; i <= ping_repeat; i++)
+ {
+ f64 sleep_interval;
+ f64 time_ping_sent = vlib_time_now (vm);
+
+ if (dst_addr.version == AF_IP4)
+ res = send_ip4_ping (vm, table_id, &dst_addr.ip.ip4, sw_if_index, i,
+ icmp_id, data_len, ping_burst, verbose);
+ else
+ res = send_ip6_ping (vm, table_id, &dst_addr.ip.ip6, sw_if_index, i,
+ icmp_id, data_len, ping_burst, verbose);
+
+ if (SEND_PING_OK == res)
+ request_count += 1;
+ else
+ continue;
+
+ while ((sleep_interval =
+ time_ping_sent + ping_interval - vlib_time_now (vm)) > 0.0)
+ {
+ uword event_type;
+ vlib_process_wait_for_event_or_clock (vm, sleep_interval);
+ event_type = vlib_process_get_events (vm, 0);
+
+ if (event_type == ~0)
+ break;
+
+ if (event_type == PING_RESPONSE_IP4 ||
+ event_type == PING_RESPONSE_IP6)
+ reply_count += 1;
+ }
+ }
+
+ ping_api_send_ping_event (mp, request_count, reply_count);
+
+ clear_cli_process_id_by_icmp_id_mt (vm, icmp_id);
+}
+
+/* set tup the API message handling tables */
+#include <ping/ping.api.c>
+
+clib_error_t *
+ping_plugin_api_hookup (vlib_main_t *vm)
+{
+ ping_main_t *pm = &ping_main;
+
+ /* ask for a correctly-sized block of API message decode slots */
+ pm->msg_id_base = setup_message_id_table ();
+
+ return 0;
+} \ No newline at end of file
diff --git a/test/test_ping.py b/test/test_ping.py
index c2eb8b75299..2fb36e5d7b6 100644
--- a/test/test_ping.py
+++ b/test/test_ping.py
@@ -179,3 +179,37 @@ class TestPing(VppTestCase):
icmp_seq = icmp_seq + 1
finally:
self.vapi.cli("show error")
+
+ def test_ping_api(self):
+ """ping api"""
+
+ try:
+ self.pg_enable_capture(self.pg_interfaces)
+ self.pg_start()
+
+ ret = self.vapi.want_ping_finished_events(
+ address=self.pg1.remote_ip4,
+ repeat=4,
+ interval=0.2,
+ )
+ self.logger.info(ret)
+ timeout = 1
+
+ ev = self.vapi.wait_for_event(timeout, "ping_finished_event")
+ self.logger.info(ev)
+ self.assertEqual(ev.request_count, 4)
+
+ out = self.pg1.get_capture(4)
+ icmp_id = None
+ icmp_seq = 1
+ for p in out:
+ icmp = self.verify_ping_request(
+ p, self.pg1.local_ip4, self.pg1.remote_ip4, icmp_seq
+ )
+ icmp_seq = icmp_seq + 1
+ if icmp_id is None:
+ icmp_id = icmp.id
+ else:
+ self.assertEqual(icmp.id, icmp_id)
+ finally:
+ self.vapi.cli("show error")