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