)
func init() {
- RegisterVethTests(EchoBuiltinTest, EchoBuiltinBandwidthTest, EchoBuiltinEchobytesTest)
+ RegisterVethTests(EchoBuiltinTest, EchoBuiltinBandwidthTest, EchoBuiltinEchobytesTest, EchoBuiltinRoundtripTest)
RegisterSoloVethTests(TcpWithLossTest)
RegisterVeth6Tests(TcpWithLoss6Test)
}
}
}
+func EchoBuiltinRoundtripTest(s *VethsSuite) {
+ regex := regexp.MustCompile(`(\.\d+)ms roundtrip`)
+ serverVpp := s.Containers.ServerVpp.VppInstance
+
+ serverVpp.Vppctl("test echo server " +
+ " uri tcp://" + s.Interfaces.Server.Ip4AddressString() + "/" + s.Ports.Port1)
+
+ clientVpp := s.Containers.ClientVpp.VppInstance
+
+ o := clientVpp.Vppctl("test echo client bytes 8m" +
+ " uri tcp://" + s.Interfaces.Server.Ip4AddressString() + "/" + s.Ports.Port1)
+ s.Log(o)
+ s.AssertContains(o, "Test started")
+ s.AssertContains(o, "Test finished")
+ if regex.MatchString(o) {
+ matches := regex.FindStringSubmatch(o)
+ if len(matches) != 0 {
+ seconds, _ := strconv.ParseFloat(matches[1], 32)
+ // Make sure that we are within ms range
+ s.AssertEqualWithinThreshold(seconds, 0.5, 0.5)
+ } else {
+ s.AssertEmpty("invalid echo test client output")
+ }
+ } else {
+ s.AssertEmpty("invalid echo test client output")
+ }
+}
+
func EchoBuiltinEchobytesTest(s *VethsSuite) {
serverVpp := s.Containers.ServerVpp.VppInstance
*/
#include <hs_apps/echo_client.h>
+#include <vnet/tcp/tcp_types.h>
static ec_main_t ec_main;
return pool_elt_at_index (wrk->sessions, ec_index);
}
+static void
+update_rtt_stats (f64 session_rtt)
+{
+ ec_main_t *ecm = &ec_main;
+ clib_spinlock_lock (&ecm->rtt_stats.w_lock);
+ ecm->rtt_stats.sum_rtt += session_rtt;
+ ecm->rtt_stats.n_sum++;
+ if (session_rtt < ecm->rtt_stats.min_rtt)
+ ecm->rtt_stats.min_rtt = session_rtt;
+ if (session_rtt > ecm->rtt_stats.max_rtt)
+ ecm->rtt_stats.max_rtt = session_rtt;
+ clib_spinlock_unlock (&ecm->rtt_stats.w_lock);
+}
+
static void
send_data_chunk (ec_main_t *ecm, ec_session_t *es)
{
if (n_read > 0)
{
+ if (ecm->transport_proto == TRANSPORT_PROTO_UDP && ecm->echo_bytes &&
+ (es->rtt_stat & EC_UDP_RTT_RX_FLAG) == 0)
+ {
+ es->rtt_stat |= EC_UDP_RTT_RX_FLAG;
+ update_rtt_stats (vlib_time_now (vlib_get_main ()) - es->send_rtt);
+ }
if (ecm->cfg.verbose)
{
ELOG_TYPE_DECLARE (e) =
if (es->bytes_to_send > 0)
{
+ if (ecm->transport_proto == TRANSPORT_PROTO_UDP && ecm->echo_bytes &&
+ (es->rtt_stat & EC_UDP_RTT_TX_FLAG) == 0)
+ {
+ es->send_rtt = time_now;
+ es->rtt_stat |= EC_UDP_RTT_TX_FLAG;
+ }
send_data_chunk (ecm, es);
if (ecm->throughput)
es->time_to_send += ecm->pacing_window_len;
if (s)
{
+ if (ecm->transport_proto == TRANSPORT_PROTO_TCP)
+ {
+ transport_connection_t *tc;
+ tcp_connection_t *tcpc;
+ tc = transport_get_connection (
+ TRANSPORT_PROTO_TCP, s->connection_index, s->thread_index);
+ if (PREDICT_TRUE (tc != NULL))
+ {
+ tcpc = tcp_get_connection_from_transport (tc);
+ update_rtt_stats (tcpc->srtt * TCP_TICK);
+ }
+ }
+
vnet_disconnect_args_t _a, *a = &_a;
a->handle = session_handle (s);
a->app_index = ecm->app_index;
ecm->throughput = 0;
ecm->pacing_window_len = 1;
ecm->max_chunk_bytes = 128 << 10;
+ clib_memset (&ecm->rtt_stats, 0, sizeof (ec_rttstat_t));
+ ecm->rtt_stats.min_rtt = CLIB_F64_MAX;
+ if (ecm->rtt_stats.w_lock == NULL)
+ clib_spinlock_init (&ecm->rtt_stats.w_lock);
vec_free (ecm->connect_uri);
}
ecm->pacing_window_len = 1;
if (ecm->barrier_acq_needed)
vlib_worker_thread_barrier_sync (ecm->vlib_main);
+ clib_spinlock_free (&ecm->rtt_stats.w_lock);
}
static int
/*
* Done. Compute stats
*/
+ if (ecm->transport_proto == TRANSPORT_PROTO_TCP ||
+ (ecm->transport_proto == TRANSPORT_PROTO_UDP && ecm->echo_bytes))
+ {
+ /* display rtt stats in milliseconds */
+ if (ecm->rtt_stats.n_sum == 1)
+ ec_cli ("%.05fms roundtrip", ecm->rtt_stats.min_rtt * 1000);
+ else if (ecm->rtt_stats.n_sum > 1)
+ ec_cli ("%.05fms/%.05fms/%.05fms min/avg/max roundtrip",
+ ecm->rtt_stats.min_rtt * 1000,
+ ecm->rtt_stats.sum_rtt / ecm->rtt_stats.n_sum * 1000,
+ ecm->rtt_stats.max_rtt * 1000);
+ else
+ ec_cli ("error measuring roundtrip time");
+ }
+
delta = ecm->test_end_time - ecm->test_start_time;
if (delta == 0.0)
{
#include <vnet/session/session.h>
#include <vnet/session/application_interface.h>
+typedef struct ec_rttstat_
+{
+ f64 min_rtt;
+ f64 max_rtt;
+ f64 sum_rtt;
+ u32 n_sum;
+ clib_spinlock_t w_lock;
+} ec_rttstat_t;
+
typedef struct ec_session_
{
CLIB_CACHE_LINE_ALIGN_MARK (cacheline0);
f64 time_to_send;
u64 bytes_paced_target;
u64 bytes_paced_current;
+ f64 send_rtt;
+ u8 rtt_stat;
} ec_session_t;
typedef struct ec_worker_
f64 test_end_time;
u32 prev_conns;
u32 repeats;
+ ec_rttstat_t rtt_stats;
f64
pacing_window_len; /**< Time between data chunk sends when limiting tput */
EC_CLI_TEST_DONE
} ec_cli_signal_t;
+typedef enum ec_rtt_stat_
+{
+ EC_UDP_RTT_TX_FLAG = 1,
+ EC_UDP_RTT_RX_FLAG = 2
+} ec_rtt_stat;
+
void ec_program_connects (void);
#endif /* __included_echo_client_h__ */