Print this page
10052 "dladm show-ether" should pick one kstat snapshot and stick with it
Reviewed by: Rob Johnston <rob.johnston@joyent.com>
Reviewed by: Robert Mustacchi <rm@joyent.com>
Reviewed by: Gergo Doma <domag02@gmail.com>
Reviewed by: Andy Fiddaman <andy@omniosce.org>
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/flowstat/flowstat.c
+++ new/usr/src/cmd/flowstat/flowstat.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
↓ open down ↓ |
19 lines elided |
↑ open up ↑ |
20 20 */
21 21 /*
22 22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
23 23 * Use is subject to license terms.
24 24 */
25 25
26 26 /*
27 27 * Copyright 2017 Joyent, Inc.
28 28 */
29 29
30 +/*
31 + * Copyright 2019 OmniOS Community Edition (OmniOSce) Association.
32 + */
33 +
30 34 #include <stdio.h>
31 35 #include <locale.h>
32 36 #include <stdarg.h>
33 37 #include <stdlib.h>
34 38 #include <fcntl.h>
35 39 #include <string.h>
36 40 #include <stropts.h>
37 41 #include <errno.h>
38 42 #include <strings.h>
39 43 #include <getopt.h>
40 44 #include <unistd.h>
41 45 #include <priv.h>
42 46 #include <netdb.h>
43 47 #include <libintl.h>
44 48 #include <libdlflow.h>
45 49 #include <libdllink.h>
46 50 #include <libdlstat.h>
47 51 #include <sys/types.h>
48 52 #include <sys/socket.h>
49 53 #include <netinet/in.h>
50 54 #include <arpa/inet.h>
51 55 #include <sys/ethernet.h>
52 56 #include <inet/ip.h>
53 57 #include <inet/ip6.h>
54 58 #include <stddef.h>
55 59 #include <ofmt.h>
56 60
57 61 typedef struct flow_chain_s {
58 62 char fc_flowname[MAXFLOWNAMELEN];
59 63 boolean_t fc_visited;
60 64 flow_stat_t *fc_stat;
61 65 struct flow_chain_s *fc_next;
62 66 } flow_chain_t;
63 67
64 68 typedef struct show_flow_state {
65 69 flow_chain_t *fs_flowchain;
66 70 ofmt_handle_t fs_ofmt;
67 71 char fs_unit;
68 72 boolean_t fs_parsable;
69 73 } show_flow_state_t;
70 74
71 75 typedef struct show_history_state_s {
72 76 boolean_t us_plot;
73 77 boolean_t us_parsable;
74 78 boolean_t us_printheader;
75 79 boolean_t us_first;
76 80 boolean_t us_showall;
77 81 ofmt_handle_t us_ofmt;
78 82 } show_history_state_t;
79 83
80 84 static void do_show_history(int, char **);
81 85
82 86 static int query_flow_stats(dladm_handle_t, dladm_flow_attr_t *, void *);
83 87 static int query_link_flow_stats(dladm_handle_t, datalink_id_t, void *);
84 88
85 89 static void die(const char *, ...);
86 90 static void die_optdup(int);
87 91 static void die_opterr(int, int, const char *);
88 92 static void die_dlerr(dladm_status_t, const char *, ...);
89 93 static void warn(const char *, ...);
90 94
91 95 /* callback functions for printing output */
92 96 static ofmt_cb_t print_default_cb, print_flow_stats_cb;
93 97
94 98 #define NULL_OFMT {NULL, 0, 0, NULL}
95 99
96 100 /*
97 101 * structures for flowstat (printing live statistics)
98 102 */
99 103 typedef enum {
100 104 FLOW_S_FLOW,
101 105 FLOW_S_IPKTS,
102 106 FLOW_S_RBYTES,
103 107 FLOW_S_IERRORS,
104 108 FLOW_S_OPKTS,
105 109 FLOW_S_OBYTES,
106 110 FLOW_S_OERRORS
107 111 } flow_s_field_index_t;
108 112
109 113 static ofmt_field_t flow_s_fields[] = {
110 114 /* name, field width, index, callback */
111 115 { "FLOW", 15, FLOW_S_FLOW, print_flow_stats_cb},
112 116 { "IPKTS", 8, FLOW_S_IPKTS, print_flow_stats_cb},
113 117 { "RBYTES", 8, FLOW_S_RBYTES, print_flow_stats_cb},
114 118 { "IERRS", 8, FLOW_S_IERRORS, print_flow_stats_cb},
115 119 { "OPKTS", 8, FLOW_S_OPKTS, print_flow_stats_cb},
116 120 { "OBYTES", 8, FLOW_S_OBYTES, print_flow_stats_cb},
117 121 { "OERRS", 8, FLOW_S_OERRORS, print_flow_stats_cb},
118 122 NULL_OFMT}
119 123 ;
120 124
121 125 typedef struct flow_args_s {
122 126 char *flow_s_flow;
123 127 flow_stat_t *flow_s_stat;
124 128 char flow_s_unit;
125 129 boolean_t flow_s_parsable;
126 130 } flow_args_t;
127 131
128 132 /*
129 133 * structures for 'flowstat -h'
130 134 */
131 135 typedef struct history_fields_buf_s {
132 136 char history_flow[12];
133 137 char history_duration[10];
134 138 char history_ipackets[9];
135 139 char history_rbytes[10];
136 140 char history_opackets[9];
137 141 char history_obytes[10];
138 142 char history_bandwidth[14];
139 143 } history_fields_buf_t;
140 144
141 145 static ofmt_field_t history_fields[] = {
142 146 /* name, field width, offset */
143 147 { "FLOW", 13,
144 148 offsetof(history_fields_buf_t, history_flow), print_default_cb},
145 149 { "DURATION", 11,
146 150 offsetof(history_fields_buf_t, history_duration), print_default_cb},
147 151 { "IPACKETS", 10,
148 152 offsetof(history_fields_buf_t, history_ipackets), print_default_cb},
149 153 { "RBYTES", 11,
150 154 offsetof(history_fields_buf_t, history_rbytes), print_default_cb},
151 155 { "OPACKETS", 10,
152 156 offsetof(history_fields_buf_t, history_opackets), print_default_cb},
153 157 { "OBYTES", 11,
154 158 offsetof(history_fields_buf_t, history_obytes), print_default_cb},
155 159 { "BANDWIDTH", 15,
156 160 offsetof(history_fields_buf_t, history_bandwidth), print_default_cb},
157 161 NULL_OFMT}
158 162 ;
159 163
160 164 typedef struct history_l_fields_buf_s {
161 165 char history_l_flow[12];
162 166 char history_l_stime[13];
163 167 char history_l_etime[13];
164 168 char history_l_rbytes[8];
165 169 char history_l_obytes[8];
166 170 char history_l_bandwidth[14];
167 171 } history_l_fields_buf_t;
168 172
169 173 static ofmt_field_t history_l_fields[] = {
170 174 /* name, field width, offset */
171 175 { "FLOW", 13,
172 176 offsetof(history_l_fields_buf_t, history_l_flow), print_default_cb},
173 177 { "START", 14,
174 178 offsetof(history_l_fields_buf_t, history_l_stime), print_default_cb},
175 179 { "END", 14,
176 180 offsetof(history_l_fields_buf_t, history_l_etime), print_default_cb},
177 181 { "RBYTES", 9,
178 182 offsetof(history_l_fields_buf_t, history_l_rbytes), print_default_cb},
179 183 { "OBYTES", 9,
180 184 offsetof(history_l_fields_buf_t, history_l_obytes), print_default_cb},
181 185 { "BANDWIDTH", 15,
182 186 offsetof(history_l_fields_buf_t, history_l_bandwidth),
183 187 print_default_cb},
184 188 NULL_OFMT}
185 189 ;
186 190
187 191 static char *progname;
188 192
189 193 /*
190 194 * Handle to libdladm. Opened in main() before the sub-command
191 195 * specific function is called.
192 196 */
193 197 static dladm_handle_t handle = NULL;
194 198
195 199 const char *usage_ermsg = "flowstat [-r | -t] [-i interval] "
196 200 "[-l link] [flow]\n"
197 201 " flowstat [-A] [-i interval] [-p] [ -o field[,...]]\n"
198 202 " [-u R|K|M|G|T|P] [-l link] [flow]\n"
199 203 " flowstat -h [-a] [-d] [-F format]"
200 204 " [-s <DD/MM/YYYY,HH:MM:SS>]\n"
201 205 " [-e <DD/MM/YYYY,HH:MM:SS>] -f <logfile> "
202 206 "[<flow>]";
203 207
204 208 static void
205 209 usage(void)
206 210 {
207 211 (void) fprintf(stderr, "%s\n", gettext(usage_ermsg));
208 212
209 213 /* close dladm handle if it was opened */
210 214 if (handle != NULL)
211 215 dladm_close(handle);
212 216
213 217 exit(1);
214 218 }
215 219
216 220 boolean_t
217 221 flowstat_unit(char *oarg, char *unit)
218 222 {
219 223 if ((strcmp(oarg, "R") == 0) || (strcmp(oarg, "K") == 0) ||
220 224 (strcmp(oarg, "M") == 0) || (strcmp(oarg, "G") == 0) ||
221 225 (strcmp(oarg, "T") == 0) || (strcmp(oarg, "P") == 0)) {
222 226 *unit = oarg[0];
223 227 return (B_TRUE);
224 228 }
225 229
226 230 return (B_FALSE);
227 231 }
228 232
229 233 void
230 234 map_to_units(char *buf, uint_t bufsize, double num, char unit,
231 235 boolean_t parsable)
232 236 {
233 237 if (parsable) {
234 238 (void) snprintf(buf, bufsize, "%.0lf", num);
235 239 return;
236 240 }
237 241
238 242 if (unit == '\0') {
239 243 int index;
240 244
241 245 for (index = 0; (int)(num/1000) != 0; index++, num /= 1000)
242 246 ;
243 247
244 248 switch (index) {
245 249 case 0:
246 250 unit = '\0';
247 251 break;
248 252 case 1:
249 253 unit = 'K';
250 254 break;
251 255 case 2:
252 256 unit = 'M';
253 257 break;
254 258 case 3:
255 259 unit = 'G';
256 260 break;
257 261 case 4:
258 262 unit = 'T';
259 263 break;
260 264 case 5:
261 265 /* Largest unit supported */
262 266 default:
263 267 unit = 'P';
264 268 break;
265 269 }
266 270 } else {
267 271 switch (unit) {
268 272 case 'R':
269 273 /* Already raw numbers */
270 274 unit = '\0';
271 275 break;
272 276 case 'K':
273 277 num /= 1000;
274 278 break;
275 279 case 'M':
276 280 num /= (1000*1000);
277 281 break;
278 282 case 'G':
279 283 num /= (1000*1000*1000);
280 284 break;
281 285 case 'T':
282 286 num /= (1000.0*1000.0*1000.0*1000.0);
283 287 break;
284 288 case 'P':
285 289 /* Largest unit supported */
286 290 default:
287 291 num /= (1000.0*1000.0*1000.0*1000.0*1000.0);
288 292 break;
289 293 }
290 294 }
291 295
292 296 if (unit == '\0')
293 297 (void) snprintf(buf, bufsize, " %7.0lf%c", num, unit);
294 298 else
295 299 (void) snprintf(buf, bufsize, " %6.2lf%c", num, unit);
296 300 }
297 301
298 302 flow_chain_t *
299 303 get_flow_prev_stat(const char *flowname, void *arg)
300 304 {
301 305 show_flow_state_t *state = arg;
302 306 flow_chain_t *flow_curr = NULL;
303 307
304 308 /* Scan prev flowname list and look for entry matching this entry */
305 309 for (flow_curr = state->fs_flowchain; flow_curr;
306 310 flow_curr = flow_curr->fc_next) {
307 311 if (strcmp(flow_curr->fc_flowname, flowname) == 0)
308 312 break;
309 313 }
310 314
311 315 /* New flow, add it */
312 316 if (flow_curr == NULL) {
313 317 flow_curr = (flow_chain_t *)malloc(sizeof (flow_chain_t));
314 318 if (flow_curr == NULL)
315 319 goto done;
316 320 (void) strncpy(flow_curr->fc_flowname, flowname,
317 321 MAXFLOWNAMELEN);
318 322 flow_curr->fc_stat = NULL;
319 323 flow_curr->fc_next = state->fs_flowchain;
320 324 state->fs_flowchain = flow_curr;
321 325 }
322 326 done:
323 327 return (flow_curr);
324 328 }
325 329
326 330 /*
327 331 * Number of flows may change while flowstat -i is executing.
328 332 * Free memory allocated for flows that are no longer there.
329 333 * Prepare for next iteration by marking visited = false for
330 334 * existing stat entries.
331 335 */
332 336 static void
333 337 cleanup_removed_flows(show_flow_state_t *state)
334 338 {
335 339 flow_chain_t *fcurr;
336 340 flow_chain_t *fprev;
337 341 flow_chain_t *tofree;
338 342
339 343 /* Delete all nodes from the list that have fc_visited marked false */
340 344 fcurr = state->fs_flowchain;
341 345 while (fcurr != NULL) {
342 346 if (fcurr->fc_visited) {
343 347 fcurr->fc_visited = B_FALSE;
344 348 fprev = fcurr;
345 349 fcurr = fcurr->fc_next;
346 350 continue;
347 351 }
348 352
349 353 /* Is it head of the list? */
350 354 if (fcurr == state->fs_flowchain)
351 355 state->fs_flowchain = fcurr->fc_next;
352 356 else
353 357 fprev->fc_next = fcurr->fc_next;
354 358
355 359 /* fprev remains the same */
356 360 tofree = fcurr;
357 361 fcurr = fcurr->fc_next;
358 362
359 363 /* Free stats memory for the removed flow */
360 364 dladm_flow_stat_free(tofree->fc_stat);
361 365 free(tofree);
362 366 }
363 367 }
364 368
365 369 static boolean_t
366 370 print_flow_stats_cb(ofmt_arg_t *of_arg, char *buf, uint_t bufsize)
367 371 {
368 372 flow_args_t *fargs = of_arg->ofmt_cbarg;
369 373 flow_stat_t *diff_stats = fargs->flow_s_stat;
370 374 char unit = fargs->flow_s_unit;
371 375 boolean_t parsable = fargs->flow_s_parsable;
372 376
373 377 switch (of_arg->ofmt_id) {
374 378 case FLOW_S_FLOW:
375 379 (void) snprintf(buf, bufsize, "%s", fargs->flow_s_flow);
376 380 break;
377 381 case FLOW_S_IPKTS:
378 382 map_to_units(buf, bufsize, diff_stats->fl_ipackets, unit,
379 383 parsable);
380 384 break;
381 385 case FLOW_S_RBYTES:
382 386 map_to_units(buf, bufsize, diff_stats->fl_rbytes, unit,
383 387 parsable);
384 388 break;
385 389 case FLOW_S_IERRORS:
386 390 map_to_units(buf, bufsize, diff_stats->fl_ierrors, unit,
387 391 parsable);
388 392 break;
389 393 case FLOW_S_OPKTS:
390 394 map_to_units(buf, bufsize, diff_stats->fl_opackets, unit,
391 395 parsable);
392 396 break;
393 397 case FLOW_S_OBYTES:
394 398 map_to_units(buf, bufsize, diff_stats->fl_obytes, unit,
395 399 parsable);
396 400 break;
397 401 case FLOW_S_OERRORS:
398 402 map_to_units(buf, bufsize, diff_stats->fl_oerrors, unit,
399 403 parsable);
400 404 break;
401 405 default:
402 406 die("invalid input");
403 407 break;
404 408 }
405 409 return (B_TRUE);
406 410 }
407 411
408 412 /* ARGSUSED */
409 413 static int
410 414 query_flow_stats(dladm_handle_t handle, dladm_flow_attr_t *attr, void *arg)
411 415 {
412 416 show_flow_state_t *state = arg;
413 417 flow_chain_t *flow_node;
414 418 flow_stat_t *curr_stat;
415 419 flow_stat_t *prev_stat;
416 420 flow_stat_t *diff_stat;
417 421 char *flowname = attr->fa_flowname;
418 422 flow_args_t fargs;
↓ open down ↓ |
379 lines elided |
↑ open up ↑ |
419 423
420 424 /* Get previous stats for the flow */
421 425 flow_node = get_flow_prev_stat(flowname, arg);
422 426 if (flow_node == NULL)
423 427 goto done;
424 428
425 429 flow_node->fc_visited = B_TRUE;
426 430 prev_stat = flow_node->fc_stat;
427 431
428 432 /* Query library for current stats */
429 - curr_stat = dladm_flow_stat_query(flowname);
433 + curr_stat = dladm_flow_stat_query(handle, flowname);
430 434 if (curr_stat == NULL)
431 435 goto done;
432 436
433 437 /* current stats - prev iteration stats */
434 438 diff_stat = dladm_flow_stat_diff(curr_stat, prev_stat);
435 439
436 440 /* Free prev stats */
437 441 dladm_flow_stat_free(prev_stat);
438 442
439 443 /* Prev <- curr stats */
440 444 flow_node->fc_stat = curr_stat;
441 445
442 446 if (diff_stat == NULL)
443 447 goto done;
444 448
445 449 /* Print stats */
446 450 fargs.flow_s_flow = flowname;
447 451 fargs.flow_s_stat = diff_stat;
448 452 fargs.flow_s_unit = state->fs_unit;
449 453 fargs.flow_s_parsable = state->fs_parsable;
450 454 ofmt_print(state->fs_ofmt, &fargs);
451 455
452 456 /* Free diff stats */
453 457 dladm_flow_stat_free(diff_stat);
454 458 done:
455 459 return (DLADM_WALK_CONTINUE);
456 460 }
457 461
458 462 /*
459 463 * Wrapper of dladm_walk_flow(query_flow_stats,...) to make it usable for
460 464 * dladm_walk_datalink_id(). Used for showing flow stats for
461 465 * all flows on all links.
462 466 */
463 467 static int
464 468 query_link_flow_stats(dladm_handle_t dh, datalink_id_t linkid, void * arg)
465 469 {
466 470 if (dladm_walk_flow(query_flow_stats, dh, linkid, arg, B_FALSE)
467 471 == DLADM_STATUS_OK)
468 472 return (DLADM_WALK_CONTINUE);
469 473 else
470 474 return (DLADM_WALK_TERMINATE);
471 475 }
472 476
473 477 void
474 478 print_all_stats(name_value_stat_entry_t *stat_entry)
475 479 {
476 480 name_value_stat_t *curr_stat;
477 481
478 482 printf("%s\n", stat_entry->nve_header);
479 483
480 484 for (curr_stat = stat_entry->nve_stats; curr_stat != NULL;
481 485 curr_stat = curr_stat->nv_nextstat) {
482 486 printf("\t%15s", curr_stat->nv_statname);
483 487 printf("\t%15llu\n", curr_stat->nv_statval);
↓ open down ↓ |
44 lines elided |
↑ open up ↑ |
484 488 }
485 489 }
486 490
487 491 /* ARGSUSED */
488 492 static int
489 493 dump_one_flow_stats(dladm_handle_t handle, dladm_flow_attr_t *attr, void *arg)
490 494 {
491 495 char *flowname = attr->fa_flowname;
492 496 void *stat;
493 497
494 - stat = dladm_flow_stat_query_all(flowname);
498 + stat = dladm_flow_stat_query_all(handle, flowname);
495 499 if (stat == NULL)
496 500 goto done;
497 501 print_all_stats(stat);
498 502 dladm_flow_stat_query_all_free(stat);
499 503
500 504 done:
501 505 return (DLADM_WALK_CONTINUE);
502 506 }
503 507
504 508 /*
505 509 * Wrapper of dladm_walk_flow(query_flow_stats,...) to make it usable for
506 510 * dladm_walk_datalink_id(). Used for showing flow stats for
507 511 * all flows on all links.
508 512 */
509 513 static int
510 514 dump_link_flow_stats(dladm_handle_t dh, datalink_id_t linkid, void * arg)
511 515 {
512 516 if (dladm_walk_flow(dump_one_flow_stats, dh, linkid, arg, B_FALSE)
513 517 == DLADM_STATUS_OK)
514 518 return (DLADM_WALK_CONTINUE);
515 519 else
516 520 return (DLADM_WALK_TERMINATE);
517 521 }
518 522
519 523 static void
520 524 dump_all_flow_stats(dladm_flow_attr_t *attrp, void *arg, datalink_id_t linkid,
521 525 boolean_t flow_arg)
522 526 {
523 527 /* Show stats for named flow */
524 528 if (flow_arg) {
525 529 (void) dump_one_flow_stats(handle, attrp, arg);
526 530
527 531 /* Show stats for flows on one link */
528 532 } else if (linkid != DATALINK_INVALID_LINKID) {
529 533 (void) dladm_walk_flow(dump_one_flow_stats, handle, linkid,
530 534 arg, B_FALSE);
531 535
532 536 /* Show stats for all flows on all links */
533 537 } else {
534 538 (void) dladm_walk_datalink_id(dump_link_flow_stats,
535 539 handle, arg, DATALINK_CLASS_ALL,
536 540 DATALINK_ANY_MEDIATYPE, DLADM_OPT_ACTIVE);
537 541 }
538 542 }
539 543
540 544 int
541 545 main(int argc, char *argv[])
542 546 {
543 547 dladm_status_t status;
544 548 int option;
545 549 boolean_t r_arg = B_FALSE;
546 550 boolean_t t_arg = B_FALSE;
547 551 boolean_t p_arg = B_FALSE;
548 552 boolean_t i_arg = B_FALSE;
549 553 boolean_t o_arg = B_FALSE;
550 554 boolean_t u_arg = B_FALSE;
551 555 boolean_t A_arg = B_FALSE;
552 556 boolean_t flow_arg = B_FALSE;
553 557 datalink_id_t linkid = DATALINK_ALL_LINKID;
554 558 char linkname[MAXLINKNAMELEN];
555 559 char flowname[MAXFLOWNAMELEN];
556 560 uint32_t interval = 0;
557 561 char unit = '\0';
558 562 show_flow_state_t state;
559 563 char *fields_str = NULL;
560 564 char *o_fields_str = NULL;
561 565
562 566 char *total_stat_fields =
563 567 "flow,ipkts,rbytes,ierrs,opkts,obytes,oerrs";
564 568 char *rx_stat_fields =
565 569 "flow,ipkts,rbytes,ierrs";
566 570 char *tx_stat_fields =
567 571 "flow,opkts,obytes,oerrs";
568 572
569 573 ofmt_handle_t ofmt;
570 574 ofmt_status_t oferr;
571 575 uint_t ofmtflags = OFMT_RIGHTJUST;
572 576
573 577 dladm_flow_attr_t attr;
574 578
575 579 (void) setlocale(LC_ALL, "");
576 580 #if !defined(TEXT_DOMAIN)
577 581 #define TEXT_DOMAIN "SYS_TEST"
578 582 #endif
579 583 (void) textdomain(TEXT_DOMAIN);
580 584
581 585 progname = argv[0];
582 586
583 587 /* Open the libdladm handle */
584 588 if ((status = dladm_open(&handle)) != DLADM_STATUS_OK)
585 589 die_dlerr(status, "could not open /dev/dld");
586 590
587 591 bzero(&state, sizeof (state));
588 592
589 593 opterr = 0;
590 594 while ((option = getopt_long(argc, argv, ":rtApi:o:u:l:h",
591 595 NULL, NULL)) != -1) {
592 596 switch (option) {
593 597 case 'r':
594 598 if (r_arg)
595 599 die_optdup(option);
596 600
597 601 r_arg = B_TRUE;
598 602 break;
599 603 case 't':
600 604 if (t_arg)
601 605 die_optdup(option);
602 606
603 607 t_arg = B_TRUE;
604 608 break;
605 609 case 'A':
606 610 if (A_arg)
607 611 die_optdup(option);
608 612
609 613 A_arg = B_TRUE;
610 614 break;
611 615 case 'p':
612 616 if (p_arg)
613 617 die_optdup(option);
614 618
615 619 p_arg = B_TRUE;
616 620 break;
617 621 case 'i':
618 622 if (i_arg)
619 623 die_optdup(option);
620 624
621 625 i_arg = B_TRUE;
622 626 if (!dladm_str2interval(optarg, &interval))
623 627 die("invalid interval value '%s'", optarg);
624 628 break;
625 629 case 'o':
626 630 o_arg = B_TRUE;
627 631 o_fields_str = optarg;
628 632 break;
629 633 case 'u':
630 634 if (u_arg)
631 635 die_optdup(option);
632 636
633 637 u_arg = B_TRUE;
634 638 if (!flowstat_unit(optarg, &unit))
635 639 die("invalid unit value '%s',"
636 640 "unit must be R|K|M|G|T|P", optarg);
637 641 break;
638 642 case 'l':
639 643 if (strlcpy(linkname, optarg, MAXLINKNAMELEN)
640 644 >= MAXLINKNAMELEN)
641 645 die("link name too long\n");
642 646 if (dladm_name2info(handle, linkname, &linkid, NULL,
643 647 NULL, NULL) != DLADM_STATUS_OK)
644 648 die("invalid link '%s'", linkname);
645 649 break;
646 650 case 'h':
647 651 if (r_arg || t_arg || p_arg || o_arg || u_arg ||
648 652 i_arg || A_arg) {
649 653 die("the option -h is not compatible with "
650 654 "-r, -t, -p, -o, -u, -i, -A");
651 655 }
652 656 do_show_history(argc, argv);
653 657 return (0);
654 658 break;
655 659 default:
656 660 die_opterr(optopt, option, usage_ermsg);
657 661 break;
658 662 }
659 663 }
660 664
661 665 if (r_arg && t_arg)
662 666 die("the option -t and -r are not compatible");
663 667
664 668 if (u_arg && p_arg)
665 669 die("the option -u and -p are not compatible");
666 670
667 671 if (p_arg && !o_arg)
668 672 die("-p requires -o");
669 673
670 674 if (p_arg && strcasecmp(o_fields_str, "all") == 0)
671 675 die("\"-o all\" is invalid with -p");
672 676
673 677 if (A_arg &&
674 678 (r_arg || t_arg || p_arg || o_arg || u_arg || i_arg))
675 679 die("the option -A is not compatible with "
676 680 "-r, -t, -p, -o, -u, -i");
677 681
678 682 /* get flow name (optional last argument) */
679 683 if (optind == (argc-1)) {
680 684 if (strlcpy(flowname, argv[optind], MAXFLOWNAMELEN)
681 685 >= MAXFLOWNAMELEN)
682 686 die("flow name too long");
683 687 flow_arg = B_TRUE;
684 688 } else if (optind != argc) {
685 689 usage();
686 690 }
687 691
688 692 if (flow_arg &&
689 693 dladm_flow_info(handle, flowname, &attr) != DLADM_STATUS_OK)
690 694 die("invalid flow %s", flowname);
691 695
692 696 if (A_arg) {
693 697 dump_all_flow_stats(&attr, &state, linkid, flow_arg);
694 698 return (0);
695 699 }
696 700
697 701 state.fs_unit = unit;
698 702 state.fs_parsable = p_arg;
699 703
700 704 if (state.fs_parsable)
701 705 ofmtflags |= OFMT_PARSABLE;
702 706
703 707 if (r_arg)
704 708 fields_str = rx_stat_fields;
705 709 else if (t_arg)
706 710 fields_str = tx_stat_fields;
707 711 else
708 712 fields_str = total_stat_fields;
709 713
710 714 if (o_arg) {
711 715 fields_str = (strcasecmp(o_fields_str, "all") == 0) ?
712 716 fields_str : o_fields_str;
713 717 }
714 718
715 719 oferr = ofmt_open(fields_str, flow_s_fields, ofmtflags, 0, &ofmt);
716 720 ofmt_check(oferr, state.fs_parsable, ofmt, die, warn);
717 721 state.fs_ofmt = ofmt;
718 722
719 723 for (;;) {
720 724 /* Show stats for named flow */
721 725 if (flow_arg) {
722 726 (void) query_flow_stats(handle, &attr, &state);
723 727
724 728 /* Show stats for flows on one link */
725 729 } else if (linkid != DATALINK_INVALID_LINKID) {
726 730 (void) dladm_walk_flow(query_flow_stats, handle, linkid,
727 731 &state, B_FALSE);
728 732
729 733 /* Show stats for all flows on all links */
730 734 } else {
731 735 (void) dladm_walk_datalink_id(query_link_flow_stats,
732 736 handle, &state, DATALINK_CLASS_ALL,
733 737 DATALINK_ANY_MEDIATYPE, DLADM_OPT_ACTIVE);
734 738 }
735 739
736 740 if (interval == 0)
737 741 break;
738 742
739 743 (void) fflush(stdout);
740 744 cleanup_removed_flows(&state);
741 745 (void) sleep(interval);
742 746 }
743 747 ofmt_close(ofmt);
744 748
745 749 dladm_close(handle);
746 750 return (0);
747 751 }
748 752
749 753 /* ARGSUSED */
750 754 static int
751 755 show_history_date(dladm_usage_t *history, void *arg)
752 756 {
753 757 show_history_state_t *state = (show_history_state_t *)arg;
754 758 time_t stime;
755 759 char timebuf[20];
756 760 dladm_flow_attr_t attr;
757 761 dladm_status_t status;
758 762
759 763 /*
760 764 * Only show historical information for existing flows unless '-a'
761 765 * is specified.
762 766 */
763 767 if (!state->us_showall && ((status = dladm_flow_info(handle,
764 768 history->du_name, &attr)) != DLADM_STATUS_OK)) {
765 769 return (status);
766 770 }
767 771
768 772 stime = history->du_stime;
769 773 (void) strftime(timebuf, sizeof (timebuf), "%m/%d/%Y",
770 774 localtime(&stime));
771 775 (void) printf("%s\n", timebuf);
772 776
773 777 return (DLADM_STATUS_OK);
774 778 }
775 779
776 780 static int
777 781 show_history_time(dladm_usage_t *history, void *arg)
778 782 {
779 783 show_history_state_t *state = (show_history_state_t *)arg;
780 784 char buf[DLADM_STRSIZE];
781 785 history_l_fields_buf_t ubuf;
782 786 time_t time;
783 787 double bw;
784 788 dladm_flow_attr_t attr;
785 789 dladm_status_t status;
786 790
787 791 /*
788 792 * Only show historical information for existing flows unless '-a'
789 793 * is specified.
790 794 */
791 795 if (!state->us_showall && ((status = dladm_flow_info(handle,
792 796 history->du_name, &attr)) != DLADM_STATUS_OK)) {
793 797 return (status);
794 798 }
795 799
796 800 if (state->us_plot) {
797 801 if (!state->us_printheader) {
798 802 if (state->us_first) {
799 803 (void) printf("# Time");
800 804 state->us_first = B_FALSE;
801 805 }
802 806 (void) printf(" %s", history->du_name);
803 807 if (history->du_last) {
804 808 (void) printf("\n");
805 809 state->us_first = B_TRUE;
806 810 state->us_printheader = B_TRUE;
807 811 }
808 812 } else {
809 813 if (state->us_first) {
810 814 time = history->du_etime;
811 815 (void) strftime(buf, sizeof (buf), "%T",
812 816 localtime(&time));
813 817 state->us_first = B_FALSE;
814 818 (void) printf("%s", buf);
815 819 }
816 820 bw = (double)history->du_bandwidth/1000;
817 821 (void) printf(" %.2f", bw);
818 822 if (history->du_last) {
819 823 (void) printf("\n");
820 824 state->us_first = B_TRUE;
821 825 }
822 826 }
823 827 return (DLADM_STATUS_OK);
824 828 }
825 829
826 830 bzero(&ubuf, sizeof (ubuf));
827 831
828 832 (void) snprintf(ubuf.history_l_flow, sizeof (ubuf.history_l_flow), "%s",
829 833 history->du_name);
830 834 time = history->du_stime;
831 835 (void) strftime(buf, sizeof (buf), "%T", localtime(&time));
832 836 (void) snprintf(ubuf.history_l_stime, sizeof (ubuf.history_l_stime),
833 837 "%s", buf);
834 838 time = history->du_etime;
835 839 (void) strftime(buf, sizeof (buf), "%T", localtime(&time));
836 840 (void) snprintf(ubuf.history_l_etime, sizeof (ubuf.history_l_etime),
837 841 "%s", buf);
838 842 (void) snprintf(ubuf.history_l_rbytes, sizeof (ubuf.history_l_rbytes),
839 843 "%llu", history->du_rbytes);
840 844 (void) snprintf(ubuf.history_l_obytes, sizeof (ubuf.history_l_obytes),
841 845 "%llu", history->du_obytes);
842 846 (void) snprintf(ubuf.history_l_bandwidth,
843 847 sizeof (ubuf.history_l_bandwidth), "%s Mbps",
844 848 dladm_bw2str(history->du_bandwidth, buf));
845 849
846 850 ofmt_print(state->us_ofmt, (void *)&ubuf);
847 851 return (DLADM_STATUS_OK);
848 852 }
849 853
850 854 static int
851 855 show_history_res(dladm_usage_t *history, void *arg)
852 856 {
853 857 show_history_state_t *state = (show_history_state_t *)arg;
854 858 char buf[DLADM_STRSIZE];
855 859 history_fields_buf_t ubuf;
856 860 dladm_flow_attr_t attr;
857 861 dladm_status_t status;
858 862
859 863 /*
860 864 * Only show historical information for existing flows unless '-a'
861 865 * is specified.
862 866 */
863 867 if (!state->us_showall && ((status = dladm_flow_info(handle,
864 868 history->du_name, &attr)) != DLADM_STATUS_OK)) {
865 869 return (status);
866 870 }
867 871
868 872 bzero(&ubuf, sizeof (ubuf));
869 873
870 874 (void) snprintf(ubuf.history_flow, sizeof (ubuf.history_flow), "%s",
871 875 history->du_name);
872 876 (void) snprintf(ubuf.history_duration, sizeof (ubuf.history_duration),
873 877 "%llu", history->du_duration);
874 878 (void) snprintf(ubuf.history_ipackets, sizeof (ubuf.history_ipackets),
875 879 "%llu", history->du_ipackets);
876 880 (void) snprintf(ubuf.history_rbytes, sizeof (ubuf.history_rbytes),
877 881 "%llu", history->du_rbytes);
878 882 (void) snprintf(ubuf.history_opackets, sizeof (ubuf.history_opackets),
879 883 "%llu", history->du_opackets);
880 884 (void) snprintf(ubuf.history_obytes, sizeof (ubuf.history_obytes),
881 885 "%llu", history->du_obytes);
882 886 (void) snprintf(ubuf.history_bandwidth, sizeof (ubuf.history_bandwidth),
883 887 "%s Mbps", dladm_bw2str(history->du_bandwidth, buf));
884 888
885 889 ofmt_print(state->us_ofmt, (void *)&ubuf);
886 890
887 891 return (DLADM_STATUS_OK);
888 892 }
889 893
890 894 static boolean_t
891 895 valid_formatspec(char *formatspec_str)
892 896 {
893 897 return (strcmp(formatspec_str, "gnuplot") == 0);
894 898 }
895 899
896 900 /* ARGSUSED */
897 901 static void
898 902 do_show_history(int argc, char *argv[])
899 903 {
900 904 char *file = NULL;
901 905 int opt;
902 906 dladm_status_t status;
903 907 boolean_t d_arg = B_FALSE;
904 908 char *stime = NULL;
905 909 char *etime = NULL;
906 910 char *resource = NULL;
907 911 show_history_state_t state;
908 912 boolean_t o_arg = B_FALSE;
909 913 boolean_t F_arg = B_FALSE;
910 914 char *fields_str = NULL;
911 915 char *formatspec_str = NULL;
912 916 char *all_fields =
913 917 "flow,duration,ipackets,rbytes,opackets,obytes,bandwidth";
914 918 char *all_l_fields =
915 919 "flow,start,end,rbytes,obytes,bandwidth";
916 920 ofmt_handle_t ofmt;
917 921 ofmt_status_t oferr;
918 922 uint_t ofmtflags = 0;
919 923
920 924 bzero(&state, sizeof (show_history_state_t));
921 925 state.us_parsable = B_FALSE;
922 926 state.us_printheader = B_FALSE;
923 927 state.us_plot = B_FALSE;
924 928 state.us_first = B_TRUE;
925 929
926 930 while ((opt = getopt(argc, argv, "das:e:o:f:F:")) != -1) {
927 931 switch (opt) {
928 932 case 'd':
929 933 d_arg = B_TRUE;
930 934 break;
931 935 case 'a':
932 936 state.us_showall = B_TRUE;
933 937 break;
934 938 case 'f':
935 939 file = optarg;
936 940 break;
937 941 case 's':
938 942 stime = optarg;
939 943 break;
940 944 case 'e':
941 945 etime = optarg;
942 946 break;
943 947 case 'o':
944 948 o_arg = B_TRUE;
945 949 fields_str = optarg;
946 950 break;
947 951 case 'F':
948 952 state.us_plot = F_arg = B_TRUE;
949 953 formatspec_str = optarg;
950 954 break;
951 955 default:
952 956 die_opterr(optopt, opt, usage_ermsg);
953 957 }
954 958 }
955 959
956 960 if (file == NULL)
957 961 die("-h requires a file");
958 962
959 963 if (optind == (argc-1)) {
960 964 dladm_flow_attr_t attr;
961 965
962 966 resource = argv[optind];
963 967 if (!state.us_showall &&
964 968 dladm_flow_info(handle, resource, &attr) !=
965 969 DLADM_STATUS_OK) {
966 970 die("invalid flow: '%s'", resource);
967 971 }
968 972 }
969 973
970 974 if (state.us_parsable)
971 975 ofmtflags |= OFMT_PARSABLE;
972 976 if (resource == NULL && stime == NULL && etime == NULL) {
973 977 if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0))
974 978 fields_str = all_fields;
975 979 oferr = ofmt_open(fields_str, history_fields, ofmtflags,
976 980 0, &ofmt);
977 981 } else {
978 982 if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0))
979 983 fields_str = all_l_fields;
980 984 oferr = ofmt_open(fields_str, history_l_fields, ofmtflags,
981 985 0, &ofmt);
982 986 }
983 987
984 988 ofmt_check(oferr, state.us_parsable, ofmt, die, warn);
985 989 state.us_ofmt = ofmt;
986 990
987 991 if (F_arg && d_arg)
988 992 die("incompatible -d and -F options");
989 993
990 994 if (F_arg && !valid_formatspec(formatspec_str))
991 995 die("Format specifier %s not supported", formatspec_str);
992 996
993 997 if (d_arg) {
994 998 /* Print log dates */
995 999 status = dladm_usage_dates(show_history_date,
996 1000 DLADM_LOGTYPE_FLOW, file, resource, &state);
997 1001 } else if (resource == NULL && stime == NULL && etime == NULL &&
998 1002 !F_arg) {
999 1003 /* Print summary */
1000 1004 status = dladm_usage_summary(show_history_res,
1001 1005 DLADM_LOGTYPE_FLOW, file, &state);
1002 1006 } else if (resource != NULL) {
1003 1007 /* Print log entries for named resource */
1004 1008 status = dladm_walk_usage_res(show_history_time,
1005 1009 DLADM_LOGTYPE_FLOW, file, resource, stime, etime, &state);
1006 1010 } else {
1007 1011 /* Print time and information for each flow */
1008 1012 status = dladm_walk_usage_time(show_history_time,
1009 1013 DLADM_LOGTYPE_FLOW, file, stime, etime, &state);
1010 1014 }
1011 1015
1012 1016 ofmt_close(ofmt);
1013 1017 if (status != DLADM_STATUS_OK)
1014 1018 die_dlerr(status, "-h");
1015 1019 dladm_close(handle);
1016 1020 }
1017 1021
1018 1022 static void
1019 1023 warn(const char *format, ...)
1020 1024 {
1021 1025 va_list alist;
1022 1026
1023 1027 format = gettext(format);
1024 1028 (void) fprintf(stderr, "%s: warning: ", progname);
1025 1029
1026 1030 va_start(alist, format);
1027 1031 (void) vfprintf(stderr, format, alist);
1028 1032 va_end(alist);
1029 1033
1030 1034 (void) putc('\n', stderr);
1031 1035 }
1032 1036
1033 1037 /* PRINTFLIKE1 */
1034 1038 static void
1035 1039 die(const char *format, ...)
1036 1040 {
1037 1041 va_list alist;
1038 1042
1039 1043 format = gettext(format);
1040 1044 (void) fprintf(stderr, "%s: ", progname);
1041 1045
1042 1046 va_start(alist, format);
1043 1047 (void) vfprintf(stderr, format, alist);
1044 1048 va_end(alist);
1045 1049
1046 1050 (void) putc('\n', stderr);
1047 1051
1048 1052 /* close dladm handle if it was opened */
1049 1053 if (handle != NULL)
1050 1054 dladm_close(handle);
1051 1055
1052 1056 exit(EXIT_FAILURE);
1053 1057 }
1054 1058
1055 1059 static void
1056 1060 die_optdup(int opt)
1057 1061 {
1058 1062 die("the option -%c cannot be specified more than once", opt);
1059 1063 }
1060 1064
1061 1065 static void
1062 1066 die_opterr(int opt, int opterr, const char *usage)
1063 1067 {
1064 1068 switch (opterr) {
1065 1069 case ':':
1066 1070 die("option '-%c' requires a value\nusage: %s", opt,
1067 1071 gettext(usage));
1068 1072 break;
1069 1073 case '?':
1070 1074 default:
1071 1075 die("unrecognized option '-%c'\nusage: %s", opt,
1072 1076 gettext(usage));
1073 1077 break;
1074 1078 }
1075 1079 }
1076 1080
1077 1081 /* PRINTFLIKE2 */
1078 1082 static void
1079 1083 die_dlerr(dladm_status_t err, const char *format, ...)
1080 1084 {
1081 1085 va_list alist;
1082 1086 char errmsg[DLADM_STRSIZE];
1083 1087
1084 1088 format = gettext(format);
1085 1089 (void) fprintf(stderr, "%s: ", progname);
1086 1090
1087 1091 va_start(alist, format);
1088 1092 (void) vfprintf(stderr, format, alist);
1089 1093 va_end(alist);
1090 1094 (void) fprintf(stderr, ": %s\n", dladm_status2str(err, errmsg));
1091 1095
1092 1096 /* close dladm handle if it was opened */
1093 1097 if (handle != NULL)
1094 1098 dladm_close(handle);
1095 1099
1096 1100 exit(EXIT_FAILURE);
1097 1101 }
1098 1102
1099 1103
1100 1104 /*
1101 1105 * default output callback function that, when invoked from dladm_print_output,
1102 1106 * prints string which is offset by of_arg->ofmt_id within buf.
1103 1107 */
1104 1108 static boolean_t
1105 1109 print_default_cb(ofmt_arg_t *of_arg, char *buf, uint_t bufsize)
1106 1110 {
1107 1111 char *value;
1108 1112
1109 1113 value = (char *)of_arg->ofmt_cbarg + of_arg->ofmt_id;
1110 1114 (void) strlcpy(buf, value, bufsize);
1111 1115 return (B_TRUE);
1112 1116 }
↓ open down ↓ |
608 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX