/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
* Copyright 2012 Milan Jurik. All rights reserved.
*/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <strings.h>
#include <sys/sysmacros.h>
#include <fcntl.h>
#include <errno.h>
#include <assert.h>
#include <libgen.h>
#include <kstat.h>
#include <ofmt.h>
#include <libilb.h>
#include "ilbadm.h"
typedef struct {
} ilbst_stat_t;
{"num_servers", 0},
{"bytes_not_processed", 0},
{"pkt_not_processed", 0},
{"bytes_dropped", 0},
{"pkt_dropped", 0},
{"nomem_bytes_dropped", 0},
{"nomem_pkt_dropped", 0},
{"noport_bytes_dropped", 0},
{"noport_pkt_dropped", 0},
{"icmp_echo_processed", 0},
{"icmp_dropped", 0},
{"icmp_too_big_processed", 0},
{"icmp_too_big_dropped", 0}
};
/* indices into array above, to avoid searching */
#define RLSTA_NUM_SRV 0
{"bytes_processed", 0},
{"pkt_processed", 0}
};
/* indices into array above, to avoid searching */
#define SRVST_BYTES_P 0
/* values used for of_* commands as id */
#define ILBST_PKT_P 0
/* approx field widths */
};
};
"ICMP_P,ICMP_D,ICMP2BIG_P,ICMP2BIG_D,NOMEMP_D,NOPORTP_D";
typedef struct {
/*
* this data structure stores statistics for a rule - both an old set
* the pointers for every round. old_is_old in ilbst_arg_t indicates
* which pointer points to the "old" data struct (ie, if true, _o pointer
* points to old)
*/
typedef struct {
int ird_num_servers;
int ird_num_servers_o;
int ird_srv_ind;
/*
* overall "container" for information pertaining to statistics, and
* how to display them.
*/
typedef struct {
int ilbst_flags;
/* fields representing user input */
int ilbst_interval;
int ilbst_count;
/* "internal" fields for data and data presentation */
} ilbst_arg_t;
/* ARGSUSED */
static boolean_t
{
return (B_TRUE);
}
static boolean_t
int flags)
{
int i, num_servers;
/* if we do abs. numbers, we never look at the _o fields */
/* we only check for validity under certain conditions */
for (i = 0; i < num_servers; i++) {
if (old)
else
/*
* if creation times don't match, comparison is wrong; if
* if we already know something is invalid, we don't
* need to compare again.
*/
break;
}
}
/*
* save the result even though it may be imprecise - let the
* caller decide what to do
*/
return (valid);
}
static boolean_t
{
}
static boolean_t
{
}
static boolean_t
{
int i;
break;
break;
}
for (i = 0; i < sta->ilbst_rcount; i++) {
if (!valid)
return (valid);
}
goto out;
for (i = 0; i < sta->ilbst_rcount; i++) {
}
out:
/*
* normally, we print "change per second", which we calculate
* here. otherwise, we print "change over interval"
*/
return (B_TRUE);
}
/*
* this function is called when user wants itemized stats of every
* server for a named rule, or vice vera.
* i_do_print sets sta->rule_index and the proper ird_srv_ind so
* we don't have to differentiate between these two cases here.
*/
static boolean_t
{
int stat_ind;
break;
break;
case ILBST_ITEMIZE_RNAME:
return (B_TRUE);
case ILBST_ITEMIZE_SNAME:
return (B_TRUE);
}
goto out;
out:
/*
* normally, we print "change per second", which we calculate
* here. otherwise, we print "change over interval" or absolute
* values.
*/
return (ret);
}
static boolean_t
{
int i, ind;
break;
break;
break;
break;
break;
break;
break;
break;
break;
break;
break;
break;
}
for (i = 0; i < sta->ilbst_rcount; i++)
goto out;
/*
* the purist approach: if we can't say 100% that what we
* calculate is correct, don't.
*/
return (B_FALSE);
for (i = 0; i < sta->ilbst_rcount; i++) {
return (B_FALSE);
}
out:
/*
* normally, we print "change per second", which we calculate
* here. otherwise, we print "change over interval"
*/
return (B_TRUE);
}
/*
* Get the number of kstat instances. Note that when rules are being
* drained the number of kstats instances may be different than the
* kstat counter num_rules (ilb:0:global:num_rules").
*
* Also there can be multiple instances of a rule in the following
* scenario:
*
* A rule named rule A has been deleted but remains in kstats because
* its undergoing connection draining. During this time, the user adds
* a new rule with the same name(rule A). In this case, there would
* be two kstats instances for rule A. Currently ilbadm's aggregate
* results will include data from both instances of rule A. In,
* future we should have ilbadm stats only consider the latest instance
* of the rule (ie only consider the the instance that corresponds
* to the rule that was just added).
*
*/
static int
{
}
}
return (num_instances);
}
/*
* since server stat's classname is made up of <rulename>-sstat,
* we walk the rule list to construct the comparison
* Return: pointer to rule whose name matches the class
* NULL if no match
*/
static ilbst_rule_desc_t *
{
int i;
for (i = 0; i < rcount; i++) {
rlist[i].ird_rulename);
return (&rlist[i]);
}
return (NULL);
}
static int
{
int i;
for (i = 0; i < count; i++) {
return (i);
}
return (-1);
}
static void
{
int i, ind;
if (ind == -1)
continue;
}
}
static ilbadm_status_t
{
int i = -1;
/*
* find all "server" kstats, or the one specified in
* sta->server
*/
continue;
continue;
continue;
i = rp->ird_srv_ind++;
/*
* This means that a server is added after we check last
* time... Just make the array bigger.
*/
rc = ILBADM_ENOMEM;
break;
}
rp->ird_num_servers = i;
}
}
for (i = 0; i < rcount; i++)
rlist[i].ird_srv_ind = 0;
return (rc);
}
static void
{
int i, ind;
if (ind == -1)
continue;
}
}
static void
{
if (old_is_old) {
} else {
}
}
/*
* this function walks the array of rules and switches pointer to old
* and new stats as well as serverlists.
*/
static void
{
int i, tmp_num;
for (i = 0; i < rcount; i++) {
/* swap srvlist pointers */
/*
* swap server counts - we need the old one to
* save reallocation calls
*/
/* preserve creation time */
rlist[i].ird_srv_ind = 0;
}
}
static void
{
int i;
for (i = 0; i < rcount; i++) {
rlist[i].ird_srv_ind = 0;
}
}
/*
* this function searches for kstats describing individual rules and
* saves name, # of servers, and the kstat_t * describing them (this is
* for sta->rulename == NULL);
* if sta->rulename != NULL, it names the rule we're looking for
* and this function will fill in the other data (like the all_rules case)
* Returns: ILBADM_ENORULE named rule not found
* ILBADM_ENOMEM no mem. available
*/
static ilbadm_status_t
{
int i;
int num_servers;
/*
* find all "rule" kstats, or the one specified in
* sta->ilbst_rulename.
*/
continue;
rc = ILBADM_LIBERR;
break;
}
!= 0)
continue;
}
sizeof (rlist[i].ird_rulename));
/* only alloc the space we need, set counter here ... */
num_servers = 1;
else
/* ... furthermore, only reallocate if necessary */
sizeof (*srvlist));
else
sizeof (*srvlist) * num_servers);
rc = ILBADM_ENOMEM;
break;
}
}
rlist[i].ird_srv_ind = 0;
i++;
/* if we know we're done, return */
break;
}
}
rc = ILBADM_ENORULE;
return (rc);
}
static void
{
int i;
/* non-itemized display can go right ahead */
return;
}
/*
* rulename is given, list a line per server
* here's how we do it:
* the _ITEMIZE flag indicates to the print function (called
* from ofmt_print()) to look at server [ird_srv_ind] only.
*/
sta->ilbst_rule_index = 0;
}
return;
}
/* list one line for every rule for a given server */
for (i = 0; i < sta->ilbst_rcount; i++) {
/*
* if a rule doesn't contain a given server, there's no
* need to print it. Luckily, we can check that
* fairly easily
*/
'\0')
continue;
sta->ilbst_rule_index = i;
}
sta->ilbst_rule_index = 0;
}
static ilbadm_status_t
{
return (ILBADM_LIBERR);
}
rc = ILBADM_ENOMEM;
goto out;
}
/*
* in the first pass, we always print absolute numbers. We
* need to remember whether we wanted abs. numbers for
* other samples as well
*/
pseudo_abs = B_TRUE;
}
do {
goto out;
goto out;
else
break;
/*
* we only need to continue with most of the rest of this if
* the kstat chain id has changed
*/
if (nkid == 0)
goto swap_old_new;
if (nkid == -1) {
rc = ILBADM_LIBERR;
break;
}
/*
* find out whether the number of rules has changed.
* if so, adjust rcount and _o; if number has increased,
* expand array to hold all rules.
* we only shrink if rlist_sz is larger than both rcount and
* rcount_prev;
*/
rc = ILBADM_ENOMEM;
break;
}
/* realloc doesn't zero out memory */
for (i = sta->ilbst_rcount_prev;
i < rcount; i++) {
}
/*
* even if rlist_sz was > rcount, it's now
* shrunk to rcount
*/
}
}
/*
* we may need to shrink the allocated slots down to the
* actually required number - we need to make sure we
* don't delete old or new stats.
*/
sta->ilbst_rcount_prev)) {
rc = ILBADM_ENOMEM;
break;
}
}
/*
* move pointers around so what used to point to "old"
* stats now points to new, and vice versa
* if we're printing absolute numbers, this rigmarole is
* not necessary.
*/
if (pseudo_abs)
}
} while (B_TRUE);
out:
(void) kstat_close(kctl);
return (rc);
}
/*
* read ilb's kernel statistics and (periodically) display
* them.
*/
/* ARGSUSED */
{
int c;
int oflags = 0;
switch ((char)c) {
break;
break;
break;
break;
break;
break;
break;
break;
break;
" detected for %c"), (char)optopt);
exit(1);
/* not reached */
break;
case '?': /* fallthrough */
default:
/* not reached */
break;
}
}
exit(1);
}
if (i_opt) {
" either -r or -s"));
exit(1);
}
if (v_opt) {
" exclusive"));
exit(1);
}
/* only use "std" headers if none are specified */
if (!o_opt)
if (r_opt)
else /* must be s_opt */
}
if (p_opt) {
if (!o_opt) {
exit(1);
}
if (v_opt) {
" exclusive"));
exit(1);
}
" explicit field names"));
exit(1);
}
}
if (t_opt) {
if (v_opt) {
fieldnames = "all";
} else {
char *fnames;
rc = ILBADM_ENOMEM;
return (rc);
}
fieldnames = fnames;
}
}
exit(1);
}
/* find and parse interval and count arguments if present */
exit(1);
}
exit(1);
}
}
}
if (oerr != OFMT_SUCCESS) {
char e[80];
return (ILBADM_LIBERR);
}
ofmt_close(oh);
return (rc);
}