Motr  M0
main.c
Go to the documentation of this file.
1 /* -*- C -*- */
2 /*
3  * Copyright (c) 2012-2020 Seagate Technology LLC and/or its Affiliates
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  * For any questions about this software or licensing,
18  * please email opensource@seagate.com or cortx-questions@seagate.com.
19  *
20  */
21 
22 
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <string.h>
26 
27 #include <sys/socket.h>
28 #ifdef HAVE_NETINET_IN_H
29 # include <netinet/in.h>
30 #endif
31 #include <arpa/inet.h>
32 #include <netdb.h>
33 
34 #include "motr/init.h"
35 #include "lib/assert.h"
36 #include "lib/errno.h"
37 #include "lib/getopts.h"
38 #include "lib/memory.h"
39 #include "lib/misc.h" /* M0_SET0 */
40 #include "lib/thread.h"
41 #include "net/net.h"
42 #include "net/bulk_mem.h"
43 #include "ping.h"
44 
45 enum {
46  DEF_BUFS = 20,
49  DEF_LOOPS = 1,
50 
53 
56 
58 
59  ONE_MILLION = 1000000ULL,
60  SEC_PER_HR = 60 * 60,
62 };
63 
64 struct ping_xprt {
65  const struct m0_net_xprt *px_xprt;
69 };
70 
71 struct ping_xprt xprts[1] = {
72  {
74  .px_dual_only = true,
75  .px_3part_addr = false,
76  .px_client_port = MEM_CLIENT_BASE_PORT,
77  },
78 };
79 
80 struct ping_ctx sctx = {
81  .pc_tm = {
83  }
84 };
85 
86 int canon_host(const char *hostname, char *buf, size_t bufsiz)
87 {
88  int i;
89  int rc = 0;
90  struct in_addr ipaddr;
91 
92  /* m0_net_end_point_create requires string IPv4 address, not name */
93  if (inet_aton(hostname, &ipaddr) == 0) {
94  struct hostent he;
95  char he_buf[4096];
96  struct hostent *hp;
97  int herrno;
98 
99  rc = gethostbyname_r(hostname, &he, he_buf, sizeof he_buf,
100  &hp, &herrno);
101  if (rc != 0) {
102  fprintf(stderr, "Can't get address for %s\n",
103  hostname);
104  return -ENOENT;
105  }
106  for (i = 0; hp->h_addr_list[i] != NULL; ++i)
107  /* take 1st IPv4 address found */
108  if (hp->h_addrtype == AF_INET &&
109  hp->h_length == sizeof(ipaddr))
110  break;
111  if (hp->h_addr_list[i] == NULL) {
112  fprintf(stderr, "No IPv4 address for %s\n",
113  hostname);
114  return -EPFNOSUPPORT;
115  }
116  if (inet_ntop(hp->h_addrtype, hp->h_addr, buf, bufsiz) ==
117  NULL) {
118  fprintf(stderr, "Cannot parse network address for %s\n",
119  hostname);
120  rc = -errno;
121  }
122  } else {
123  if (strlen(hostname) >= bufsiz) {
124  fprintf(stderr, "Buffer size too small for %s\n",
125  hostname);
126  return -ENOSPC;
127  }
128  strcpy(buf, hostname);
129  }
130  return rc;
131 }
132 
133 int lookup_xprt(const char *xprt_name, struct ping_xprt **xprt)
134 {
135  int i;
136 
137  for (i = 0; i < ARRAY_SIZE(xprts); ++i)
138  if (strcmp(xprt_name, xprts[i].px_xprt->nx_name) == 0) {
139  *xprt = &xprts[i];
140  return 0;
141  }
142  return -ENOENT;
143 }
144 
145 void list_xprt_names(FILE *s, struct ping_xprt *def)
146 {
147  int i;
148 
149  fprintf(s, "Supported transports:\n");
150  for (i = 0; ARRAY_SIZE(xprts); ++i)
151  fprintf(s, " %s%s\n", xprts[i].px_xprt->nx_name,
152  (&xprts[i] == def) ? " [default]" : "");
153 }
154 
156 
157 void print_qstats(struct ping_ctx *ctx, bool reset)
158 {
159  int i;
160  int rc;
161  uint64_t hr;
162  uint64_t min;
163  uint64_t sec;
164  uint64_t msec;
165  struct m0_net_qstats qs[M0_NET_QT_NR];
166  struct m0_net_qstats *qp;
167  static const char *qnames[M0_NET_QT_NR] = {
168  "mRECV", "mSEND",
169  "pRECV", "pSEND",
170  "aRECV", "aSEND",
171  };
172  char tbuf[256];
173  const char *lfmt =
174 "%5s %6lu %6lu %6lu %6lu %13s %14lu %13lu\n";
175  const char *hfmt =
176 "Queue #Add #Del #Succ #Fail Time in Queue Total Bytes Max Buffer Sz\n"
177 "----- ------ ------ ------ ------ ------------- --------------- -------------\n";
178 
179  if (ctx->pc_tm.ntm_state < M0_NET_TM_INITIALIZED)
180  return;
181  rc = m0_net_tm_stats_get(&ctx->pc_tm, M0_NET_QT_NR, qs, reset);
182  M0_ASSERT(rc == 0);
184  ctx->pc_ops->pf("%s statistics:\n", ctx->pc_ident);
185  ctx->pc_ops->pf("%s", hfmt);
186  for (i = 0; i < ARRAY_SIZE(qs); ++i) {
187  qp = &qs[i];
189  hr = sec / SEC_PER_HR;
190  min = sec % SEC_PER_HR / SEC_PER_MIN;
191  sec %= SEC_PER_MIN;
193  ONE_MILLION / 2) / ONE_MILLION;
194  sprintf(tbuf, "%02lu:%02lu:%02lu.%03lu",
195  hr, min, sec, msec);
196  ctx->pc_ops->pf(lfmt,
197  qnames[i],
198  qp->nqs_num_adds, qp->nqs_num_dels,
200  tbuf, qp->nqs_total_bytes, qp->nqs_max_bytes);
201  }
203 }
204 
205 int quiet_printf(const char *fmt, ...)
206 {
207  return 0;
208 }
209 
211  .pf = printf,
212  .pqs = print_qstats
213 };
214 
215 struct ping_ops quiet_ops = {
216  .pf = quiet_printf,
217  .pqs = print_qstats
218 };
219 
221  struct ping_xprt *xprt;
222  bool verbose;
224  int loops;
225  int nr_bufs;
228  const char *local_host;
229  const char *remote_host;
231 };
232 
234 {
235  int i;
236  int rc;
237  struct m0_net_end_point *server_ep;
238  char ident[24];
239  char *bp = NULL;
240  struct ping_ctx cctx = {
241  .pc_xprt = params->xprt->px_xprt,
242  .pc_hostname = params->local_host,
243  .pc_rhostname = params->remote_host,
244  .pc_rport = PING_PORT1,
245  .pc_nr_bufs = params->nr_bufs,
246  .pc_segments = PING_CLIENT_SEGMENTS,
247  .pc_seg_size = PING_CLIENT_SEGMENT_SIZE,
248  .pc_passive_size = params->passive_size,
249  .pc_ident = ident,
250  .pc_tm = {
251  .ntm_state = M0_NET_TM_UNDEFINED
252  },
253  .pc_passive_bulk_timeout = params->passive_bulk_timeout,
254  };
255 
256  if (params->xprt->px_3part_addr) {
257  cctx.pc_port = params->base_port;
258  cctx.pc_id = params->client_id;
259  sprintf(ident, "Client %d:%d", cctx.pc_port, cctx.pc_id);
260  cctx.pc_rid = PART3_SERVER_ID;
261  } else {
262  cctx.pc_port = params->base_port + params->client_id;
263  cctx.pc_id = 0;
264  cctx.pc_rid = 0;
265  sprintf(ident, "Client %d", cctx.pc_port);
266  }
267  if (params->verbose)
268  cctx.pc_ops = &verbose_ops;
269  else
270  cctx.pc_ops = &quiet_ops;
271  m0_mutex_init(&cctx.pc_mutex);
272  m0_cond_init(&cctx.pc_cond, &cctx.pc_mutex);
273  rc = ping_client_init(&cctx, &server_ep);
274  if (rc != 0)
275  goto fail;
276 
277  if (params->passive_size != 0) {
278  bp = m0_alloc(params->passive_size);
279  M0_ASSERT(bp != NULL);
280  for (i = 0; i < params->passive_size - 1; ++i)
281  bp[i] = "abcdefghi"[i % 9];
282  }
283 
284  for (i = 1; i <= params->loops; ++i) {
285  cctx.pc_ops->pf("%s: Loop %d\n", ident, i);
286  rc = ping_client_msg_send_recv(&cctx, server_ep, bp);
287  M0_ASSERT(rc == 0);
288  rc = ping_client_passive_recv(&cctx, server_ep);
289  M0_ASSERT(rc == 0);
290  rc = ping_client_passive_send(&cctx, server_ep, bp);
291  M0_ASSERT(rc == 0);
292  }
293 
294  if (params->verbose)
295  print_qstats(&cctx, false);
296  rc = ping_client_fini(&cctx, server_ep);
297  m0_free(bp);
298  M0_ASSERT(rc == 0);
299 fail:
300  m0_cond_fini(&cctx.pc_cond);
301  m0_mutex_fini(&cctx.pc_mutex);
302 }
303 
304 int main(int argc, char *argv[])
305 {
306  int rc;
307  bool client_only = false;
308  bool server_only = false;
309  bool verbose = false;
310  const char *local_name = "localhost";
311  const char *remote_name = "localhost";
312  const char *xprt_name = m0_net_bulk_mem_xprt.nx_name;
313  int loops = DEF_LOOPS;
314  int base_port = 0;
316  int nr_bufs = DEF_BUFS;
317  int passive_size = 0;
318  int passive_bulk_timeout = 0;
319  int active_bulk_delay = 0;
320 
321  struct ping_xprt *xprt;
322  struct m0_thread server_thread;
323  /* hostname buffers big enough for 255.255.255.255 */
324  char local_hostbuf[16];
325  char remote_hostbuf[16];
326 
327  rc = m0_init(NULL);
328  M0_ASSERT(rc == 0);
329 
330  rc = M0_GETOPTS("m0bulkping", argc, argv,
331  M0_FLAGARG('s', "run server only", &server_only),
332  M0_FLAGARG('c', "run client only", &client_only),
333  M0_STRINGARG('h', "hostname to listen on",
334  LAMBDA(void, (const char *str) {
335  local_name = str; })),
336  M0_STRINGARG('r', "name of remote server host",
337  LAMBDA(void, (const char *str) {
338  remote_name = str; })),
339  M0_FORMATARG('p', "base client port", "%i", &base_port),
340  M0_FORMATARG('b', "number of buffers", "%i", &nr_bufs),
341  M0_FORMATARG('l', "loops to run", "%i", &loops),
342  M0_FORMATARG('d', "passive data size", "%i",
343  &passive_size),
344  M0_FORMATARG('n', "number of client threads", "%i",
345  &nr_clients),
346  M0_STRINGARG('t', "transport-name or \"list\" to "
347  "list supported transports.",
348  LAMBDA(void, (const char *str) {
349  xprt_name = str; })),
350  M0_FORMATARG('D', "server active bulk delay",
351  "%i", &active_bulk_delay),
352  M0_FLAGARG('v', "verbose", &verbose));
353  if (rc != 0)
354  return rc;
355 
356  if (strcmp(xprt_name, "list") == 0) {
357  list_xprt_names(stdout, &xprts[0]);
358  return 0;
359  }
360  rc = lookup_xprt(xprt_name, &xprt);
361  if (rc != 0) {
362  fprintf(stderr, "Unknown transport-name.\n");
363  list_xprt_names(stderr, &xprts[0]);
364  return rc;
365  }
366  if (xprt->px_dual_only && (client_only || server_only)) {
367  fprintf(stderr,
368  "Transport %s does not support client or server only\n",
369  xprt_name);
370  return 1;
371  }
373  fprintf(stderr, "Max of %d client threads supported\n",
375  return 1;
376  }
377  if (nr_bufs < DEF_BUFS) {
378  fprintf(stderr, "Minimum of %d buffers required\n", DEF_BUFS);
379  return 1;
380  }
381  if (passive_size < 0 || passive_size >
383  /* need to leave room for encoding overhead */
384  fprintf(stderr, "Max supported passive data size: %d\n",
386  return 1;
387  }
388  if (client_only && server_only)
389  client_only = server_only = false;
390  if (base_port == 0) {
391  /* be nice and pick the non-server port by default */
392  base_port = xprt->px_client_port;
393  if (client_only && base_port == PING_PORT1)
394  base_port = PING_PORT2;
395  }
396  if (canon_host(local_name, local_hostbuf, sizeof local_hostbuf) != 0)
397  return 1;
398  if (canon_host(remote_name, remote_hostbuf, sizeof remote_hostbuf) != 0)
399  return 1;
400 
402 
403  if (!client_only) {
404  /* start server in background thread */
407  if (verbose)
409  else
410  sctx.pc_ops = &quiet_ops;
411  sctx.pc_hostname = local_hostbuf;
412  sctx.pc_xprt = xprt->px_xprt;
414  if (xprt->px_3part_addr)
416  else
417  sctx.pc_id = 0;
421  sctx.pc_passive_size = passive_size;
425  &ping_server, &sctx, "ping_server");
426  M0_ASSERT(rc == 0);
427  }
428 
429  if (server_only) {
430  char readbuf[BUFSIZ];
431 
432  printf("Type \"quit\" or ^D to cause server to terminate\n");
433  while (fgets(readbuf, BUFSIZ, stdin)) {
434  if (strcmp(readbuf, "quit\n") == 0)
435  break;
436  if (strcmp(readbuf, "\n") == 0)
437  print_qstats(&sctx, false);
438  if (strcmp(readbuf, "reset_stats\n") == 0)
439  print_qstats(&sctx, true);
440  }
441  } else {
442  int i;
443  struct m0_thread *client_thread;
444  struct client_params *params;
447 
448  /* start all the client threads */
449  for (i = 0; i < nr_clients; ++i) {
450  params[i].xprt = xprt;
451  params[i].verbose = verbose;
452  params[i].base_port = base_port;
453  params[i].loops = loops;
454  params[i].nr_bufs = nr_bufs;
455  params[i].client_id = i + 1;
456  params[i].passive_size = passive_size;
457  params[i].local_host = local_hostbuf;
458  params[i].remote_host = remote_hostbuf;
459  params[i].passive_bulk_timeout = passive_bulk_timeout;
460 
462  struct client_params *,
463  NULL, &client, &params[i],
464  "client_%d", params[i].client_id);
465  M0_ASSERT(rc == 0);
466  }
467 
468  /* ...and wait for them */
469  for (i = 0; i < nr_clients; ++i) {
471  if (verbose) {
472  if (xprt->px_3part_addr)
473  printf("Client %d:%d: joined\n",
475  else
476  printf("Client %d: joined\n",
478  }
479  }
481  m0_free(params);
482  }
483 
484  if (!client_only) {
485  if (verbose)
486  print_qstats(&sctx, false);
491  }
492 
494  m0_fini();
495  return 0;
496 }
497 
498 /*
499  * Local variables:
500  * c-indentation-style: "K&R"
501  * c-basic-offset: 8
502  * tab-width: 8
503  * fill-column: 80
504  * scroll-step: 1
505  * End:
506  */
#define M0_GETOPTS(progname, argc, argv,...)
Definition: getopts.h:169
void ping_server(struct ping_ctx *ctx)
Definition: ping.c:907
int(* pf)(const char *format,...) __attribute__((format(printf
Definition: ping.h:33
uint64_t nqs_num_f_events
Definition: net.h:784
Definition: main.c:46
uint64_t nqs_num_adds
Definition: net.h:764
#define M0_ALLOC_ARR(arr, nr)
Definition: memory.h:84
M0_INTERNAL void m0_mutex_unlock(struct m0_mutex *mutex)
Definition: mutex.c:66
m0_time_t nqs_time_in_queue
Definition: net.h:791
static struct m0_thread server_thread
uint64_t nqs_num_s_events
Definition: net.h:774
#define M0_FLAGARG(ch, desc, ptr)
Definition: getopts.h:232
struct ping_ops quiet_ops
Definition: main.c:215
#define NULL
Definition: misc.h:38
const char * local_host
Definition: main.c:228
const struct ping_ops * pc_ops
Definition: ping.h:42
void m0_fini(void)
Definition: init.c:318
int m0_thread_join(struct m0_thread *q)
Definition: kthread.c:169
short px_client_port
Definition: main.c:68
uint64_t nqs_num_dels
Definition: net.h:769
uint32_t pc_nr_bufs
Definition: ping.h:52
const char * remote_host
Definition: main.c:229
M0_INTERNAL int m0_net_tm_stats_get(struct m0_net_transfer_mc *tm, enum m0_net_queue_type qtype, struct m0_net_qstats *qs, bool reset)
Definition: tm.c:343
uint64_t m0_time_nanoseconds(const m0_time_t time)
Definition: time.c:89
enum m0_net_tm_state ntm_state
Definition: net.h:819
struct ping_ctx sctx
Definition: main.c:80
int passive_size
Definition: main.c:227
static bool verbose
Definition: fdmi_echo.c:80
static struct m0_rpc_client_ctx cctx
Definition: rconfc.c:69
const char * pc_hostname
Definition: ping.h:45
#define M0_THREAD_INIT(thread, TYPE, init, func, arg, namefmt,...)
Definition: thread.h:139
int ping_client_fini(struct ping_ctx *ctx, struct m0_net_end_point *server_ep)
Definition: ping.c:1292
uint64_t nqs_total_bytes
Definition: net.h:797
int m0_init(struct m0 *instance)
Definition: init.c:310
#define M0_SET0(obj)
Definition: misc.h:64
M0_INTERNAL void m0_mutex_lock(struct m0_mutex *mutex)
Definition: mutex.c:49
bool verbose
Definition: main.c:222
uint32_t pc_id
Definition: ping.h:47
M0_INTERNAL void m0_cond_init(struct m0_cond *cond, struct m0_mutex *mutex)
Definition: cond.c:40
Definition: sock.c:887
int32_t pc_passive_size
Definition: ping.h:55
int ping_client_init(struct ping_ctx *ctx, struct m0_net_end_point **server_ep)
Definition: ping.c:1261
short pc_port
Definition: ping.h:46
static int active_bulk_delay
int ping_client_passive_recv(struct ping_ctx *ctx, struct m0_net_end_point *server_ep)
Definition: ping.c:1088
#define M0_STRINGARG(ch, desc, func)
Definition: getopts.h:207
int i
Definition: dir.c:1033
static struct nlx_ping_client_params * params
#define LAMBDA(T,...)
Definition: thread.h:153
uint32_t pc_seg_size
Definition: ping.h:54
int quiet_printf(const char *fmt,...)
Definition: main.c:205
int passive_bulk_timeout
Definition: main.c:230
int client_id
Definition: main.c:226
#define M0_FORMATARG(ch, desc, fmt, ptr)
Definition: getopts.h:218
void client(struct client_params *params)
Definition: main.c:233
#define M0_ASSERT(cond)
int base_port
Definition: main.c:223
M0_INTERNAL void m0_cond_fini(struct m0_cond *cond)
Definition: cond.c:46
const struct m0_net_xprt * px_xprt
Definition: main.c:65
Definition: client.h:37
void print_qstats(struct ping_ctx *ctx, bool reset)
Definition: main.c:157
struct m0_net_transfer_mc pc_tm
Definition: ping.h:59
bool px_dual_only
Definition: main.c:66
char * fmt(const char *format,...) __attribute__((format(printf
void * m0_alloc(size_t size)
Definition: memory.c:126
M0_INTERNAL void m0_mutex_init(struct m0_mutex *mutex)
Definition: mutex.c:35
Definition: main.c:64
struct ping_xprt xprts[1]
Definition: main.c:71
struct m0_mutex qstats_mutex
Definition: main.c:155
uint64_t m0_time_seconds(const m0_time_t time)
Definition: time.c:83
int loops
Definition: main.c:224
int canon_host(const char *hostname, char *buf, size_t bufsiz)
Definition: main.c:86
int ping_client_passive_send(struct ping_ctx *ctx, struct m0_net_end_point *server_ep, const char *data)
Definition: ping.c:1172
int pc_server_bulk_delay
Definition: ping.h:66
void list_xprt_names(FILE *s, struct ping_xprt *def)
Definition: main.c:145
static uint8_t fail[DATA_UNIT_COUNT_MAX+PARITY_UNIT_COUNT_MAX]
static long long min(long long a, long long b)
Definition: crate.c:191
Definition: ping.h:41
static int nr_clients
Definition: common.h:34
int lookup_xprt(const char *xprt_name, struct ping_xprt **xprt)
Definition: main.c:133
struct ping_xprt * xprt
Definition: main.c:221
M0_INTERNAL void m0_mutex_fini(struct m0_mutex *mutex)
Definition: mutex.c:42
static struct m0_thread * client_thread
const char * nx_name
Definition: net.h:125
struct m0_cond pc_cond
Definition: ping.h:61
struct m0_mutex pc_mutex
Definition: ping.h:60
bool px_3part_addr
Definition: main.c:67
void ping_server_should_stop(struct ping_ctx *ctx)
Definition: ping.c:990
int main(int argc, char *argv[])
Definition: main.c:245
Definition: main.c:49
static struct bulkio_params * bp
Definition: bulkio_ut.c:44
Definition: nucleus.c:42
static bool server_only
const struct m0_net_xprt * pc_xprt
Definition: ping.h:43
struct m0_net_xprt * xprt
Definition: module.c:61
int ping_client_msg_send_recv(struct ping_ctx *ctx, struct m0_net_end_point *server_ep, const char *data)
Definition: ping.c:1007
void m0_free(void *data)
Definition: memory.c:146
Definition: mutex.h:47
static struct m0_addb2_source * s
Definition: consumer.c:39
uint32_t pc_segments
Definition: ping.h:53
struct ping_ops verbose_ops
Definition: main.c:210
int32_t rc
Definition: trigger_fop.h:47
static int loops
#define ARRAY_SIZE(a)
Definition: misc.h:45
uint64_t nqs_max_bytes
Definition: net.h:804
int nr_bufs
Definition: main.c:225
const struct m0_net_xprt m0_net_bulk_mem_xprt
Definition: mem_xprt_xo.c:761
Definition: ping.h:32
static uint nr_bufs
static bool client_only