/*
* 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
* or http://www.opensolaris.org/os/licensing.
* 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 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* MAC Services Module
*/
#include <sys/types.h>
#include <sys/sysmacros.h>
#include <sys/stream.h>
#include <sys/kstat.h>
#include <sys/mac.h>
#include <sys/mac_impl.h>
#include <sys/mac_client_impl.h>
#include <sys/mac_stat.h>
#include <sys/mac_soft_ring.h>
#include <sys/vlan.h>
#define MAC_KSTAT_NAME "mac"
#define MAC_KSTAT_CLASS "net"
enum mac_stat {
MAC_STAT_LCL,
MAC_STAT_LCLBYTES,
MAC_STAT_INTRS,
MAC_STAT_INTRBYTES,
MAC_STAT_POLLS,
MAC_STAT_POLLBYTES,
MAC_STAT_RXSDROPS,
MAC_STAT_CHU10,
MAC_STAT_CH10T50,
MAC_STAT_CHO50,
MAC_STAT_BLOCK,
MAC_STAT_UNBLOCK,
MAC_STAT_TXSDROPS,
MAC_STAT_TX_ERRORS,
MAC_STAT_MACSPOOFED,
MAC_STAT_IPSPOOFED,
MAC_STAT_DHCPSPOOFED,
MAC_STAT_RESTRICTED,
MAC_STAT_DHCPDROPPED,
MAC_STAT_MULTIRCVBYTES,
MAC_STAT_BRDCSTRCVBYTES,
MAC_STAT_MULTIXMTBYTES,
MAC_STAT_BRDCSTXMTBYTES
};
static mac_stat_info_t i_mac_si[] = {
{ MAC_STAT_IFSPEED, "ifspeed", KSTAT_DATA_UINT64, 0 },
{ MAC_STAT_MULTIRCV, "multircv", KSTAT_DATA_UINT32, 0 },
{ MAC_STAT_BRDCSTRCV, "brdcstrcv", KSTAT_DATA_UINT32, 0 },
{ MAC_STAT_MULTIXMT, "multixmt", KSTAT_DATA_UINT32, 0 },
{ MAC_STAT_BRDCSTXMT, "brdcstxmt", KSTAT_DATA_UINT32, 0 },
{ MAC_STAT_NORCVBUF, "norcvbuf", KSTAT_DATA_UINT32, 0 },
{ MAC_STAT_IERRORS, "ierrors", KSTAT_DATA_UINT32, 0 },
{ MAC_STAT_UNKNOWNS, "unknowns", KSTAT_DATA_UINT32, 0 },
{ MAC_STAT_NOXMTBUF, "noxmtbuf", KSTAT_DATA_UINT32, 0 },
{ MAC_STAT_OERRORS, "oerrors", KSTAT_DATA_UINT32, 0 },
{ MAC_STAT_COLLISIONS, "collisions", KSTAT_DATA_UINT32, 0 },
{ MAC_STAT_UNDERFLOWS, "uflo", KSTAT_DATA_UINT32, 0 },
{ MAC_STAT_OVERFLOWS, "oflo", KSTAT_DATA_UINT32, 0 },
{ MAC_STAT_RBYTES, "rbytes", KSTAT_DATA_UINT32, 0 },
{ MAC_STAT_IPACKETS, "ipackets", KSTAT_DATA_UINT32, 0 },
{ MAC_STAT_OBYTES, "obytes", KSTAT_DATA_UINT32, 0 },
{ MAC_STAT_OPACKETS, "opackets", KSTAT_DATA_UINT32, 0 },
{ MAC_STAT_RBYTES, "rbytes64", KSTAT_DATA_UINT64, 0 },
{ MAC_STAT_IPACKETS, "ipackets64", KSTAT_DATA_UINT64, 0 },
{ MAC_STAT_OBYTES, "obytes64", KSTAT_DATA_UINT64, 0 },
{ MAC_STAT_OPACKETS, "opackets64", KSTAT_DATA_UINT64, 0 }
};
#define MAC_NKSTAT \
(sizeof (i_mac_si) / sizeof (mac_stat_info_t))
static mac_stat_info_t i_mac_mod_si[] = {
{ MAC_STAT_LINK_STATE, "link_state", KSTAT_DATA_UINT32,
(uint64_t)LINK_STATE_UNKNOWN },
{ MAC_STAT_LINK_UP, "link_up", KSTAT_DATA_UINT32, 0 },
{ MAC_STAT_PROMISC, "promisc", KSTAT_DATA_UINT32, 0 }
};
#define MAC_MOD_NKSTAT \
(sizeof (i_mac_mod_si) / sizeof (mac_stat_info_t))
#define MAC_MOD_KSTAT_OFFSET 0
#define MAC_KSTAT_OFFSET MAC_MOD_KSTAT_OFFSET + MAC_MOD_NKSTAT
#define MAC_TYPE_KSTAT_OFFSET MAC_KSTAT_OFFSET + MAC_NKSTAT
/*
* Definitions for per rx ring statistics
*/
static mac_stat_info_t i_mac_rx_ring_si[] = {
{ MAC_STAT_RBYTES, "rbytes", KSTAT_DATA_UINT64, 0},
{ MAC_STAT_IPACKETS, "ipackets", KSTAT_DATA_UINT64, 0},
{ MAC_STAT_HDROPS, "hdrops", KSTAT_DATA_UINT64, 0}
};
#define MAC_RX_RING_NKSTAT \
(sizeof (i_mac_rx_ring_si) / sizeof (mac_stat_info_t))
/*
* Definitions for per tx ring statistics
*/
static mac_stat_info_t i_mac_tx_ring_si[] = {
{ MAC_STAT_OBYTES, "obytes", KSTAT_DATA_UINT64, 0},
{ MAC_STAT_OPACKETS, "opackets", KSTAT_DATA_UINT64, 0}
};
#define MAC_TX_RING_NKSTAT \
(sizeof (i_mac_tx_ring_si) / sizeof (mac_stat_info_t))
/*
* Definitions for per software lane tx statistics
*/
static mac_stat_info_t i_mac_tx_swlane_si[] = {
{ MAC_STAT_OBYTES, "obytes", KSTAT_DATA_UINT64, 0},
{ MAC_STAT_OPACKETS, "opackets", KSTAT_DATA_UINT64, 0},
{ MAC_STAT_OERRORS, "oerrors", KSTAT_DATA_UINT64, 0},
{ MAC_STAT_BLOCK, "blockcnt", KSTAT_DATA_UINT64, 0},
{ MAC_STAT_UNBLOCK, "unblockcnt", KSTAT_DATA_UINT64, 0},
{ MAC_STAT_TXSDROPS, "txsdrops", KSTAT_DATA_UINT64, 0}
};
#define MAC_TX_SWLANE_NKSTAT \
(sizeof (i_mac_tx_swlane_si) / sizeof (mac_stat_info_t))
/*
* Definitions for per software lane rx statistics
*/
static mac_stat_info_t i_mac_rx_swlane_si[] = {
{ MAC_STAT_IPACKETS, "ipackets", KSTAT_DATA_UINT64, 0},
{ MAC_STAT_RBYTES, "rbytes", KSTAT_DATA_UINT64, 0},
{ MAC_STAT_LCL, "local", KSTAT_DATA_UINT64, 0},
{ MAC_STAT_LCLBYTES, "localbytes", KSTAT_DATA_UINT64, 0},
{ MAC_STAT_INTRS, "intrs", KSTAT_DATA_UINT64, 0},
{ MAC_STAT_INTRBYTES, "intrbytes", KSTAT_DATA_UINT64, 0},
{ MAC_STAT_RXSDROPS, "rxsdrops", KSTAT_DATA_UINT64, 0}
};
#define MAC_RX_SWLANE_NKSTAT \
(sizeof (i_mac_rx_swlane_si) / sizeof (mac_stat_info_t))
/*
* Definitions for per hardware lane rx statistics
*/
static mac_stat_info_t i_mac_rx_hwlane_si[] = {
{ MAC_STAT_IPACKETS, "ipackets", KSTAT_DATA_UINT64, 0},
{ MAC_STAT_RBYTES, "rbytes", KSTAT_DATA_UINT64, 0},
{ MAC_STAT_INTRS, "intrs", KSTAT_DATA_UINT64, 0},
{ MAC_STAT_INTRBYTES, "intrbytes", KSTAT_DATA_UINT64, 0},
{ MAC_STAT_POLLS, "polls", KSTAT_DATA_UINT64, 0},
{ MAC_STAT_POLLBYTES, "pollbytes", KSTAT_DATA_UINT64, 0},
{ MAC_STAT_RXSDROPS, "rxsdrops", KSTAT_DATA_UINT64, 0},
{ MAC_STAT_CHU10, "chainunder10", KSTAT_DATA_UINT64, 0},
{ MAC_STAT_CH10T50, "chain10to50", KSTAT_DATA_UINT64, 0},
{ MAC_STAT_CHO50, "chainover50", KSTAT_DATA_UINT64, 0}
};
#define MAC_RX_HWLANE_NKSTAT \
(sizeof (i_mac_rx_hwlane_si) / sizeof (mac_stat_info_t))
/*
* Definitions for misc statistics
*/
static mac_stat_info_t i_mac_misc_si[] = {
{ MAC_STAT_MULTIRCV, "multircv", KSTAT_DATA_UINT64, 0},
{ MAC_STAT_BRDCSTRCV, "brdcstrcv", KSTAT_DATA_UINT64, 0},
{ MAC_STAT_MULTIXMT, "multixmt", KSTAT_DATA_UINT64, 0},
{ MAC_STAT_BRDCSTXMT, "brdcstxmt", KSTAT_DATA_UINT64, 0},
{ MAC_STAT_MULTIRCVBYTES, "multircvbytes", KSTAT_DATA_UINT64, 0},
{ MAC_STAT_BRDCSTRCVBYTES, "brdcstrcvbytes", KSTAT_DATA_UINT64, 0},
{ MAC_STAT_MULTIXMTBYTES, "multixmtbytes", KSTAT_DATA_UINT64, 0},
{ MAC_STAT_BRDCSTXMTBYTES, "brdcstxmtbytes", KSTAT_DATA_UINT64, 0},
{ MAC_STAT_TX_ERRORS, "txerrors", KSTAT_DATA_UINT64, 0},
{ MAC_STAT_MACSPOOFED, "macspoofed", KSTAT_DATA_UINT64, 0},
{ MAC_STAT_IPSPOOFED, "ipspoofed", KSTAT_DATA_UINT64, 0},
{ MAC_STAT_DHCPSPOOFED, "dhcpspoofed", KSTAT_DATA_UINT64, 0},
{ MAC_STAT_RESTRICTED, "restricted", KSTAT_DATA_UINT64, 0},
{ MAC_STAT_DHCPDROPPED, "dhcpdropped", KSTAT_DATA_UINT64, 0},
{ MAC_STAT_IPACKETS, "ipackets", KSTAT_DATA_UINT64, 0},
{ MAC_STAT_RBYTES, "rbytes", KSTAT_DATA_UINT64, 0},
{ MAC_STAT_LCL, "local", KSTAT_DATA_UINT64, 0},
{ MAC_STAT_LCLBYTES, "localbytes", KSTAT_DATA_UINT64, 0},
{ MAC_STAT_INTRS, "intrs", KSTAT_DATA_UINT64, 0},
{ MAC_STAT_INTRBYTES, "intrbytes", KSTAT_DATA_UINT64, 0},
{ MAC_STAT_POLLS, "polls", KSTAT_DATA_UINT64, 0},
{ MAC_STAT_POLLBYTES, "pollbytes", KSTAT_DATA_UINT64, 0},
{ MAC_STAT_RXSDROPS, "rxsdrops", KSTAT_DATA_UINT64, 0},
{ MAC_STAT_CHU10, "chainunder10", KSTAT_DATA_UINT64, 0},
{ MAC_STAT_CH10T50, "chain10to50", KSTAT_DATA_UINT64, 0},
{ MAC_STAT_CHO50, "chainover50", KSTAT_DATA_UINT64, 0},
{ MAC_STAT_OBYTES, "obytes", KSTAT_DATA_UINT64, 0},
{ MAC_STAT_OPACKETS, "opackets", KSTAT_DATA_UINT64, 0},
{ MAC_STAT_OERRORS, "oerrors", KSTAT_DATA_UINT64, 0},
{ MAC_STAT_BLOCK, "blockcnt", KSTAT_DATA_UINT64, 0},
{ MAC_STAT_UNBLOCK, "unblockcnt", KSTAT_DATA_UINT64, 0},
{ MAC_STAT_TXSDROPS, "txsdrops", KSTAT_DATA_UINT64, 0}
};
#define MAC_SUMMARY_NKSTAT \
(sizeof (i_mac_misc_si) / sizeof (mac_stat_info_t))
/*
* Definitions for per hardware lane tx statistics
*/
static mac_stat_info_t i_mac_tx_hwlane_si[] = {
{ MAC_STAT_OBYTES, "obytes", KSTAT_DATA_UINT64, 0},
{ MAC_STAT_OPACKETS, "opackets", KSTAT_DATA_UINT64, 0},
{ MAC_STAT_OERRORS, "oerrors", KSTAT_DATA_UINT64, 0},
{ MAC_STAT_BLOCK, "blockcnt", KSTAT_DATA_UINT64, 0},
{ MAC_STAT_UNBLOCK, "unblockcnt", KSTAT_DATA_UINT64, 0},
{ MAC_STAT_TXSDROPS, "txsdrops", KSTAT_DATA_UINT64, 0}
};
#define MAC_TX_HWLANE_NKSTAT \
(sizeof (i_mac_tx_hwlane_si) / sizeof (mac_stat_info_t))
/*
* Definitions for per fanout rx statistics
*/
static mac_stat_info_t i_mac_rx_fanout_si[] = {
{ MAC_STAT_RBYTES, "rbytes", KSTAT_DATA_UINT64, 0},
{ MAC_STAT_IPACKETS, "ipackets", KSTAT_DATA_UINT64, 0},
};
#define MAC_RX_FANOUT_NKSTAT \
(sizeof (i_mac_rx_fanout_si) / sizeof (mac_stat_info_t))
/*
* Private functions.
*/
typedef struct {
uint_t si_offset;
} stat_info_t;
#define RX_SRS_STAT_OFF(f) (offsetof(mac_rx_stats_t, f))
static stat_info_t rx_srs_stats_list[] = {
{RX_SRS_STAT_OFF(mrs_lclbytes)},
{RX_SRS_STAT_OFF(mrs_lclcnt)},
{RX_SRS_STAT_OFF(mrs_pollcnt)},
{RX_SRS_STAT_OFF(mrs_pollbytes)},
{RX_SRS_STAT_OFF(mrs_intrcnt)},
{RX_SRS_STAT_OFF(mrs_intrbytes)},
{RX_SRS_STAT_OFF(mrs_sdrops)},
{RX_SRS_STAT_OFF(mrs_chaincntundr10)},
{RX_SRS_STAT_OFF(mrs_chaincnt10to50)},
{RX_SRS_STAT_OFF(mrs_chaincntover50)},
{RX_SRS_STAT_OFF(mrs_ierrors)}
};
#define RX_SRS_STAT_SIZE \
(sizeof (rx_srs_stats_list) / sizeof (stat_info_t))
#define TX_SOFTRING_STAT_OFF(f) (offsetof(mac_tx_stats_t, f))
static stat_info_t tx_softring_stats_list[] = {
{TX_SOFTRING_STAT_OFF(mts_obytes)},
{TX_SOFTRING_STAT_OFF(mts_opackets)},
{TX_SOFTRING_STAT_OFF(mts_oerrors)},
{TX_SOFTRING_STAT_OFF(mts_blockcnt)},
{TX_SOFTRING_STAT_OFF(mts_unblockcnt)},
{TX_SOFTRING_STAT_OFF(mts_sdrops)},
};
#define TX_SOFTRING_STAT_SIZE \
(sizeof (tx_softring_stats_list) / sizeof (stat_info_t))
static void
i_mac_add_stats(void *sum, void *op1, void *op2,
stat_info_t stats_list[], uint_t size)
{
int i;
for (i = 0; i < size; i++) {
uint64_t *op1_val = (uint64_t *)
((uchar_t *)op1 + stats_list[i].si_offset);
uint64_t *op2_val = (uint64_t *)
((uchar_t *)op2 + stats_list[i].si_offset);
uint64_t *sum_val = (uint64_t *)
((uchar_t *)sum + stats_list[i].si_offset);
*sum_val = *op1_val + *op2_val;
}
}
static int
i_mac_driver_stat_update(kstat_t *ksp, int rw)
{
mac_impl_t *mip = ksp->ks_private;
kstat_named_t *knp = ksp->ks_data;
uint_t i;
uint64_t val;
mac_stat_info_t *msi;
uint_t msi_index;
if (rw != KSTAT_READ)
return (EACCES);
for (i = 0; i < mip->mi_kstat_count; i++, msi_index++) {
if (i == MAC_MOD_KSTAT_OFFSET) {
msi_index = 0;
msi = i_mac_mod_si;
} else if (i == MAC_KSTAT_OFFSET) {
msi_index = 0;
msi = i_mac_si;
} else if (i == MAC_TYPE_KSTAT_OFFSET) {
msi_index = 0;
msi = mip->mi_type->mt_stats;
}
val = mac_stat_get((mac_handle_t)mip, msi[msi_index].msi_stat);
switch (msi[msi_index].msi_type) {
case KSTAT_DATA_UINT64:
knp->value.ui64 = val;
break;
case KSTAT_DATA_UINT32:
knp->value.ui32 = (uint32_t)val;
break;
default:
ASSERT(B_FALSE);
break;
}
knp++;
}
return (0);
}
static void
i_mac_kstat_init(kstat_named_t *knp, mac_stat_info_t *si, uint_t count)
{
int i;
for (i = 0; i < count; i++) {
kstat_named_init(knp, si[i].msi_name, si[i].msi_type);
knp++;
}
}
static int
i_mac_stat_update(kstat_t *ksp, int rw, uint64_t (*fn)(void *, uint_t),
mac_stat_info_t *msi, uint_t count)
{
kstat_named_t *knp = ksp->ks_data;
uint_t i;
uint64_t val;
if (rw != KSTAT_READ)
return (EACCES);
for (i = 0; i < count; i++) {
val = fn(ksp->ks_private, msi[i].msi_stat);
switch (msi[i].msi_type) {
case KSTAT_DATA_UINT64:
knp->value.ui64 = val;
break;
case KSTAT_DATA_UINT32:
knp->value.ui32 = (uint32_t)val;
break;
default:
ASSERT(B_FALSE);
break;
}
knp++;
}
return (0);
}
/*
* Create kstat with given name - statname, update function - fn
* and initialize it with given names - init_stat_info
*/
static kstat_t *
i_mac_stat_create(void *handle, const char *modname, const char *statname,
int (*fn) (kstat_t *, int),
mac_stat_info_t *init_stat_info, uint_t count)
{
kstat_t *ksp;
kstat_named_t *knp;
ksp = kstat_create(modname, 0, statname, "net",
KSTAT_TYPE_NAMED, count, 0);
if (ksp == NULL)
return (NULL);
ksp->ks_update = fn;
ksp->ks_private = handle;
knp = (kstat_named_t *)ksp->ks_data;
i_mac_kstat_init(knp, init_stat_info, count);
kstat_install(ksp);
return (ksp);
}
/*
* Per rx ring statistics
*/
uint64_t
mac_rx_ring_stat_get(void *handle, uint_t stat)
{
mac_ring_t *ring = (mac_ring_t *)handle;
uint64_t val = 0;
/*
* XXX Every ring-capable driver must implement an entry point to
* query per ring statistics. CR 6893122 tracks this work item.
* Once this bug is fixed, the framework should fail registration
* for a driver that does not implement this entry point and
* assert ring->mr_stat != NULL here.
*/
if (ring->mr_stat != NULL)
ring->mr_stat(ring->mr_driver, stat, &val);
return (val);
}
static int
i_mac_rx_ring_stat_update(kstat_t *ksp, int rw)
{
return (i_mac_stat_update(ksp, rw, mac_rx_ring_stat_get,
i_mac_rx_ring_si, MAC_RX_RING_NKSTAT));
}
static void
i_mac_rx_ring_stat_create(mac_ring_t *ring, const char *modname,
const char *statname)
{
kstat_t *ksp;
ksp = i_mac_stat_create(ring, modname, statname,
i_mac_rx_ring_stat_update, i_mac_rx_ring_si, MAC_RX_RING_NKSTAT);
ring->mr_ksp = ksp;
}
/*
* Per tx ring statistics
*/
uint64_t
mac_tx_ring_stat_get(void *handle, uint_t stat)
{
mac_ring_t *ring = (mac_ring_t *)handle;
uint64_t val = 0;
/*
* XXX Every ring-capable driver must implement an entry point to
* query per ring statistics. CR 6893122 tracks this work item.
* Once this bug is fixed, the framework should fail registration
* for a driver that does not implement this entry point and
* assert ring->mr_stat != NULL here.
*/
if (ring->mr_stat != NULL)
ring->mr_stat(ring->mr_driver, stat, &val);
return (val);
}
static int
i_mac_tx_ring_stat_update(kstat_t *ksp, int rw)
{
return (i_mac_stat_update(ksp, rw, mac_tx_ring_stat_get,
i_mac_tx_ring_si, MAC_TX_RING_NKSTAT));
}
static void
i_mac_tx_ring_stat_create(mac_ring_t *ring, const char *modname,
const char *statname)
{
kstat_t *ksp;
ksp = i_mac_stat_create(ring, modname, statname,
i_mac_tx_ring_stat_update, i_mac_tx_ring_si, MAC_TX_RING_NKSTAT);
ring->mr_ksp = ksp;
}
/*
* Per software lane tx statistics
*/
static uint64_t
i_mac_tx_swlane_stat_get(void *handle, uint_t stat)
{
mac_soft_ring_set_t *mac_srs = (mac_soft_ring_set_t *)handle;
mac_tx_stats_t *mac_tx_stat = &mac_srs->srs_tx.st_stat;
switch (stat) {
case MAC_STAT_OBYTES:
return (mac_tx_stat->mts_obytes);
case MAC_STAT_OPACKETS:
return (mac_tx_stat->mts_opackets);
case MAC_STAT_OERRORS:
return (mac_tx_stat->mts_oerrors);
case MAC_STAT_BLOCK:
return (mac_tx_stat->mts_blockcnt);
case MAC_STAT_UNBLOCK:
return (mac_tx_stat->mts_unblockcnt);
case MAC_STAT_TXSDROPS:
return (mac_tx_stat->mts_sdrops);
default:
return (0);
}
}
static int
i_mac_tx_swlane_stat_update(kstat_t *ksp, int rw)
{
return (i_mac_stat_update(ksp, rw, i_mac_tx_swlane_stat_get,
i_mac_tx_swlane_si, MAC_TX_SWLANE_NKSTAT));
}
static void
i_mac_tx_swlane_stat_create(mac_soft_ring_set_t *mac_srs, const char *modname,
const char *statname)
{
kstat_t *ksp;
ksp = i_mac_stat_create(mac_srs, modname, statname,
i_mac_tx_swlane_stat_update, i_mac_tx_swlane_si,
MAC_TX_SWLANE_NKSTAT);
mac_srs->srs_ksp = ksp;
}
/*
* Per software lane rx statistics
*/
static uint64_t
i_mac_rx_swlane_stat_get(void *handle, uint_t stat)
{
mac_soft_ring_set_t *mac_srs = (mac_soft_ring_set_t *)handle;
mac_rx_stats_t *mac_rx_stat = &mac_srs->srs_rx.sr_stat;
switch (stat) {
case MAC_STAT_IPACKETS:
return (mac_rx_stat->mrs_intrcnt +
mac_rx_stat->mrs_lclcnt);
case MAC_STAT_RBYTES:
return (mac_rx_stat->mrs_intrbytes +
mac_rx_stat->mrs_lclbytes);
case MAC_STAT_LCL:
return (mac_rx_stat->mrs_lclcnt);
case MAC_STAT_LCLBYTES:
return (mac_rx_stat->mrs_lclbytes);
case MAC_STAT_INTRS:
return (mac_rx_stat->mrs_intrcnt);
case MAC_STAT_INTRBYTES:
return (mac_rx_stat->mrs_intrbytes);
case MAC_STAT_RXSDROPS:
return (mac_rx_stat->mrs_sdrops);
default:
return (0);
}
}
static int
i_mac_rx_swlane_stat_update(kstat_t *ksp, int rw)
{
return (i_mac_stat_update(ksp, rw, i_mac_rx_swlane_stat_get,
i_mac_rx_swlane_si, MAC_RX_SWLANE_NKSTAT));
}
static void
i_mac_rx_swlane_stat_create(mac_soft_ring_set_t *mac_srs, const char *modname,
const char *statname)
{
kstat_t *ksp;
ksp = i_mac_stat_create(mac_srs, modname, statname,
i_mac_rx_swlane_stat_update, i_mac_rx_swlane_si,
MAC_RX_SWLANE_NKSTAT);
mac_srs->srs_ksp = ksp;
}
/*
* Per hardware lane rx statistics
*/
static uint64_t
i_mac_rx_hwlane_stat_get(void *handle, uint_t stat)
{
mac_soft_ring_set_t *mac_srs = (mac_soft_ring_set_t *)handle;
mac_rx_stats_t *mac_rx_stat = &mac_srs->srs_rx.sr_stat;
switch (stat) {
case MAC_STAT_IPACKETS:
return (mac_rx_stat->mrs_intrcnt +
mac_rx_stat->mrs_pollcnt);
case MAC_STAT_RBYTES:
return (mac_rx_stat->mrs_intrbytes +
mac_rx_stat->mrs_pollbytes);
case MAC_STAT_INTRS:
return (mac_rx_stat->mrs_intrcnt);
case MAC_STAT_INTRBYTES:
return (mac_rx_stat->mrs_intrbytes);
case MAC_STAT_POLLS:
return (mac_rx_stat->mrs_pollcnt);
case MAC_STAT_POLLBYTES:
return (mac_rx_stat->mrs_pollbytes);
case MAC_STAT_RXSDROPS:
return (mac_rx_stat->mrs_sdrops);
case MAC_STAT_CHU10:
return (mac_rx_stat->mrs_chaincntundr10);
case MAC_STAT_CH10T50:
return (mac_rx_stat->mrs_chaincnt10to50);
case MAC_STAT_CHO50:
return (mac_rx_stat->mrs_chaincntover50);
default:
return (0);
}
}
static int
i_mac_rx_hwlane_stat_update(kstat_t *ksp, int rw)
{
return (i_mac_stat_update(ksp, rw, i_mac_rx_hwlane_stat_get,
i_mac_rx_hwlane_si, MAC_RX_HWLANE_NKSTAT));
}
static void
i_mac_rx_hwlane_stat_create(mac_soft_ring_set_t *mac_srs, const char *modname,
const char *statname)
{
kstat_t *ksp;
ksp = i_mac_stat_create(mac_srs, modname, statname,
i_mac_rx_hwlane_stat_update, i_mac_rx_hwlane_si,
MAC_RX_HWLANE_NKSTAT);
mac_srs->srs_ksp = ksp;
}
/*
* Misc statistics
*
* Counts for
* - Multicast/broadcast Rx/Tx counts
* - Tx errors
*/
static uint64_t
i_mac_misc_stat_get(void *handle, uint_t stat)
{
flow_entry_t *flent = handle;
mac_client_impl_t *mcip = flent->fe_mcip;
mac_misc_stats_t *mac_misc_stat = &mcip->mci_misc_stat;
mac_rx_stats_t *mac_rx_stat;
mac_tx_stats_t *mac_tx_stat;
mac_rx_stat = &mac_misc_stat->mms_defunctrxlanestats;
mac_tx_stat = &mac_misc_stat->mms_defuncttxlanestats;
switch (stat) {
case MAC_STAT_MULTIRCV:
return (mac_misc_stat->mms_multircv);
case MAC_STAT_BRDCSTRCV:
return (mac_misc_stat->mms_brdcstrcv);
case MAC_STAT_MULTIXMT:
return (mac_misc_stat->mms_multixmt);
case MAC_STAT_BRDCSTXMT:
return (mac_misc_stat->mms_brdcstxmt);
case MAC_STAT_MULTIRCVBYTES:
return (mac_misc_stat->mms_multircvbytes);
case MAC_STAT_BRDCSTRCVBYTES:
return (mac_misc_stat->mms_brdcstrcvbytes);
case MAC_STAT_MULTIXMTBYTES:
return (mac_misc_stat->mms_multixmtbytes);
case MAC_STAT_BRDCSTXMTBYTES:
return (mac_misc_stat->mms_brdcstxmtbytes);
case MAC_STAT_TX_ERRORS:
return (mac_misc_stat->mms_txerrors);
case MAC_STAT_MACSPOOFED:
return (mac_misc_stat->mms_macspoofed);
case MAC_STAT_IPSPOOFED:
return (mac_misc_stat->mms_ipspoofed);
case MAC_STAT_DHCPSPOOFED:
return (mac_misc_stat->mms_dhcpspoofed);
case MAC_STAT_RESTRICTED:
return (mac_misc_stat->mms_restricted);
case MAC_STAT_DHCPDROPPED:
return (mac_misc_stat->mms_dhcpdropped);
case MAC_STAT_IPACKETS:
return (mac_rx_stat->mrs_intrcnt +
mac_rx_stat->mrs_pollcnt);
case MAC_STAT_RBYTES:
return (mac_rx_stat->mrs_intrbytes +
mac_rx_stat->mrs_pollbytes);
case MAC_STAT_LCL:
return (mac_rx_stat->mrs_lclcnt);
case MAC_STAT_LCLBYTES:
return (mac_rx_stat->mrs_lclbytes);
case MAC_STAT_INTRS:
return (mac_rx_stat->mrs_intrcnt);
case MAC_STAT_INTRBYTES:
return (mac_rx_stat->mrs_intrbytes);
case MAC_STAT_POLLS:
return (mac_rx_stat->mrs_pollcnt);
case MAC_STAT_POLLBYTES:
return (mac_rx_stat->mrs_pollbytes);
case MAC_STAT_RXSDROPS:
return (mac_rx_stat->mrs_sdrops);
case MAC_STAT_CHU10:
return (mac_rx_stat->mrs_chaincntundr10);
case MAC_STAT_CH10T50:
return (mac_rx_stat->mrs_chaincnt10to50);
case MAC_STAT_CHO50:
return (mac_rx_stat->mrs_chaincntover50);
case MAC_STAT_OBYTES:
return (mac_tx_stat->mts_obytes);
case MAC_STAT_OPACKETS:
return (mac_tx_stat->mts_opackets);
case MAC_STAT_OERRORS:
return (mac_tx_stat->mts_oerrors);
case MAC_STAT_BLOCK:
return (mac_tx_stat->mts_blockcnt);
case MAC_STAT_UNBLOCK:
return (mac_tx_stat->mts_unblockcnt);
case MAC_STAT_TXSDROPS:
return (mac_tx_stat->mts_sdrops);
default:
return (0);
}
}
static int
i_mac_misc_stat_update(kstat_t *ksp, int rw)
{
return (i_mac_stat_update(ksp, rw, i_mac_misc_stat_get,
i_mac_misc_si, MAC_SUMMARY_NKSTAT));
}
static void
i_mac_misc_stat_create(flow_entry_t *flent, const char *modname,
const char *statname)
{
kstat_t *ksp;
ksp = i_mac_stat_create(flent, modname, statname,
i_mac_misc_stat_update, i_mac_misc_si,
MAC_SUMMARY_NKSTAT);
flent->fe_misc_stat_ksp = ksp;
}
/*
* Per hardware lane tx statistics
*/
static uint64_t
i_mac_tx_hwlane_stat_get(void *handle, uint_t stat)
{
mac_soft_ring_t *ringp = (mac_soft_ring_t *)handle;
mac_tx_stats_t *mac_tx_stat = &ringp->s_st_stat;
switch (stat) {
case MAC_STAT_OBYTES:
return (mac_tx_stat->mts_obytes);
case MAC_STAT_OPACKETS:
return (mac_tx_stat->mts_opackets);
case MAC_STAT_OERRORS:
return (mac_tx_stat->mts_oerrors);
case MAC_STAT_BLOCK:
return (mac_tx_stat->mts_blockcnt);
case MAC_STAT_UNBLOCK:
return (mac_tx_stat->mts_unblockcnt);
case MAC_STAT_TXSDROPS:
return (mac_tx_stat->mts_sdrops);
default:
return (0);
}
}
static int
i_mac_tx_hwlane_stat_update(kstat_t *ksp, int rw)
{
return (i_mac_stat_update(ksp, rw, i_mac_tx_hwlane_stat_get,
i_mac_tx_hwlane_si, MAC_TX_HWLANE_NKSTAT));
}
static void
i_mac_tx_hwlane_stat_create(mac_soft_ring_t *ringp, const char *modname,
const char *statname)
{
kstat_t *ksp;
ksp = i_mac_stat_create(ringp, modname, statname,
i_mac_tx_hwlane_stat_update, i_mac_tx_hwlane_si,
MAC_TX_HWLANE_NKSTAT);
ringp->s_ring_ksp = ksp;
}
/*
* Per fanout rx statistics
*/
static uint64_t
i_mac_rx_fanout_stat_get(void *handle, uint_t stat)
{
mac_soft_ring_t *tcp_ringp = (mac_soft_ring_t *)handle;
mac_soft_ring_t *udp_ringp = NULL, *oth_ringp = NULL;
mac_soft_ring_set_t *mac_srs = tcp_ringp->s_ring_set;
int index;
uint64_t val;
mutex_enter(&mac_srs->srs_lock);
/* Extract corresponding udp and oth ring pointers */
for (index = 0; mac_srs->srs_tcp_soft_rings[index] != NULL; index++) {
if (mac_srs->srs_tcp_soft_rings[index] == tcp_ringp) {
udp_ringp = mac_srs->srs_udp_soft_rings[index];
oth_ringp = mac_srs->srs_oth_soft_rings[index];
break;
}
}
ASSERT((udp_ringp != NULL) && (oth_ringp != NULL));
switch (stat) {
case MAC_STAT_RBYTES:
val = (tcp_ringp->s_ring_total_rbytes) +
(udp_ringp->s_ring_total_rbytes) +
(oth_ringp->s_ring_total_rbytes);
break;
case MAC_STAT_IPACKETS:
val = (tcp_ringp->s_ring_total_inpkt) +
(udp_ringp->s_ring_total_inpkt) +
(oth_ringp->s_ring_total_inpkt);
break;
default:
val = 0;
break;
}
mutex_exit(&mac_srs->srs_lock);
return (val);
}
static int
i_mac_rx_fanout_stat_update(kstat_t *ksp, int rw)
{
return (i_mac_stat_update(ksp, rw, i_mac_rx_fanout_stat_get,
i_mac_rx_fanout_si, MAC_RX_FANOUT_NKSTAT));
}
static void
i_mac_rx_fanout_stat_create(mac_soft_ring_t *ringp, const char *modname,
const char *statname)
{
kstat_t *ksp;
ksp = i_mac_stat_create(ringp, modname, statname,
i_mac_rx_fanout_stat_update, i_mac_rx_fanout_si,
MAC_RX_FANOUT_NKSTAT);
ringp->s_ring_ksp = ksp;
}
/*
* Exported functions.
*/
/*
* Create the "mac" kstat. The "mac" kstat is comprised of three kinds of
* statistics: statistics maintained by the mac module itself, generic mac
* statistics maintained by the driver, and MAC-type specific statistics
* also maintained by the driver.
*/
void
mac_driver_stat_create(mac_impl_t *mip)
{
kstat_t *ksp;
kstat_named_t *knp;
uint_t count;
major_t major = getmajor(mip->mi_phy_dev);
count = MAC_MOD_NKSTAT + MAC_NKSTAT + mip->mi_type->mt_statcount;
ksp = kstat_create((const char *)ddi_major_to_name(major),
getminor(mip->mi_phy_dev) - 1, MAC_KSTAT_NAME,
MAC_KSTAT_CLASS, KSTAT_TYPE_NAMED, count, 0);
if (ksp == NULL)
return;
ksp->ks_update = i_mac_driver_stat_update;
ksp->ks_private = mip;
mip->mi_ksp = ksp;
mip->mi_kstat_count = count;
knp = (kstat_named_t *)ksp->ks_data;
i_mac_kstat_init(knp, i_mac_mod_si, MAC_MOD_NKSTAT);
knp += MAC_MOD_NKSTAT;
i_mac_kstat_init(knp, i_mac_si, MAC_NKSTAT);
if (mip->mi_type->mt_statcount > 0) {
knp += MAC_NKSTAT;
i_mac_kstat_init(knp, mip->mi_type->mt_stats,
mip->mi_type->mt_statcount);
}
kstat_install(ksp);
}
/*ARGSUSED*/
void
mac_driver_stat_delete(mac_impl_t *mip)
{
if (mip->mi_ksp != NULL) {
kstat_delete(mip->mi_ksp);
mip->mi_ksp = NULL;
mip->mi_kstat_count = 0;
}
}
uint64_t
mac_driver_stat_default(mac_impl_t *mip, uint_t stat)
{
uint_t stat_index;
if (IS_MAC_STAT(stat)) {
stat_index = stat - MAC_STAT_MIN;
ASSERT(stat_index < MAC_NKSTAT);
return (i_mac_si[stat_index].msi_default);
}
ASSERT(IS_MACTYPE_STAT(stat));
stat_index = stat - MACTYPE_STAT_MIN;
ASSERT(stat_index < mip->mi_type->mt_statcount);
return (mip->mi_type->mt_stats[stat_index].msi_default);
}
void
mac_ring_stat_create(mac_ring_t *ring)
{
mac_impl_t *mip = ring->mr_mip;
char statname[MAXNAMELEN];
char modname[MAXNAMELEN];
if (mip->mi_state_flags & MIS_IS_AGGR) {
(void) strlcpy(modname, mip->mi_clients_list->mci_name,
MAXNAMELEN);
} else
(void) strlcpy(modname, mip->mi_name, MAXNAMELEN);
switch (ring->mr_type) {
case MAC_RING_TYPE_RX:
(void) snprintf(statname, sizeof (statname), "mac_rx_ring%d",
ring->mr_index);
i_mac_rx_ring_stat_create(ring, modname, statname);
break;
case MAC_RING_TYPE_TX:
(void) snprintf(statname, sizeof (statname), "mac_tx_ring%d",
ring->mr_index);
i_mac_tx_ring_stat_create(ring, modname, statname);
break;
default:
ASSERT(B_FALSE);
break;
}
}
void
mac_srs_stat_create(mac_soft_ring_set_t *mac_srs)
{
flow_entry_t *flent = mac_srs->srs_flent;
char statname[MAXNAMELEN];
boolean_t is_tx_srs;
/* No hardware/software lanes for user defined flows */
if ((flent->fe_type & FLOW_USER) != 0)
return;
is_tx_srs = ((mac_srs->srs_type & SRST_TX) != 0);
if (is_tx_srs) {
mac_srs_tx_t *srs_tx = &mac_srs->srs_tx;
mac_ring_t *ring = srs_tx->st_arg2;
if (ring != NULL) {
(void) snprintf(statname, sizeof (statname),
"mac_tx_hwlane%d", ring->mr_index);
} else {
(void) snprintf(statname, sizeof (statname),
"mac_tx_swlane0");
}
i_mac_tx_swlane_stat_create(mac_srs, flent->fe_flow_name,
statname);
} else {
mac_ring_t *ring = mac_srs->srs_ring;
if (ring == NULL) {
(void) snprintf(statname, sizeof (statname),
"mac_rx_swlane0");
i_mac_rx_swlane_stat_create(mac_srs,
flent->fe_flow_name, statname);
} else {
(void) snprintf(statname, sizeof (statname),
"mac_rx_hwlane%d", ring->mr_index);
i_mac_rx_hwlane_stat_create(mac_srs,
flent->fe_flow_name, statname);
}
}
}
void
mac_misc_stat_create(flow_entry_t *flent)
{
char statname[MAXNAMELEN];
/* No misc stats for user defined or mcast/bcast flows */
if (((flent->fe_type & FLOW_USER) != 0) ||
((flent->fe_type & FLOW_MCAST) != 0))
return;
(void) snprintf(statname, sizeof (statname), "mac_misc_stat");
i_mac_misc_stat_create(flent, flent->fe_flow_name, statname);
}
void
mac_soft_ring_stat_create(mac_soft_ring_t *ringp)
{
mac_soft_ring_set_t *mac_srs = ringp->s_ring_set;
flow_entry_t *flent = ringp->s_ring_mcip->mci_flent;
mac_ring_t *ring = (mac_ring_t *)ringp->s_ring_tx_arg2;
boolean_t is_tx_srs;
char statname[MAXNAMELEN];
/* No hardware/software lanes for user defined flows */
if ((flent->fe_type & FLOW_USER) != 0)
return;
is_tx_srs = ((mac_srs->srs_type & SRST_TX) != 0);
if (is_tx_srs) { /* tx side hardware lane */
ASSERT(ring != NULL);
(void) snprintf(statname, sizeof (statname), "mac_tx_hwlane%d",
ring->mr_index);
i_mac_tx_hwlane_stat_create(ringp, flent->fe_flow_name,
statname);
} else { /* rx side fanout */
/* Maintain single stat for (tcp, udp, oth) */
if (ringp->s_ring_type & ST_RING_TCP) {
int index;
mac_soft_ring_t *softring;
for (index = 0, softring = mac_srs->srs_soft_ring_head;
softring != NULL;
index++, softring = softring->s_ring_next) {
if (softring == ringp)
break;
}
if (mac_srs->srs_ring == NULL) {
(void) snprintf(statname, sizeof (statname),
"mac_rx_swlane0_fanout%d", index/3);
} else {
(void) snprintf(statname, sizeof (statname),
"mac_rx_hwlane%d_fanout%d",
mac_srs->srs_ring->mr_index, index/3);
}
i_mac_rx_fanout_stat_create(ringp, flent->fe_flow_name,
statname);
}
}
}
void
mac_ring_stat_delete(mac_ring_t *ring)
{
if (ring->mr_ksp != NULL) {
kstat_delete(ring->mr_ksp);
ring->mr_ksp = NULL;
}
}
void
mac_srs_stat_delete(mac_soft_ring_set_t *mac_srs)
{
boolean_t is_tx_srs;
is_tx_srs = ((mac_srs->srs_type & SRST_TX) != 0);
if (!is_tx_srs) {
/*
* Rx ring has been taken away. Before destroying corresponding
* SRS, save the stats recorded by that SRS.
*/
mac_client_impl_t *mcip = mac_srs->srs_mcip;
mac_misc_stats_t *mac_misc_stat = &mcip->mci_misc_stat;
mac_rx_stats_t *mac_rx_stat = &mac_srs->srs_rx.sr_stat;
i_mac_add_stats(&mac_misc_stat->mms_defunctrxlanestats,
mac_rx_stat, &mac_misc_stat->mms_defunctrxlanestats,
rx_srs_stats_list, RX_SRS_STAT_SIZE);
}
if (mac_srs->srs_ksp != NULL) {
kstat_delete(mac_srs->srs_ksp);
mac_srs->srs_ksp = NULL;
}
}
void
mac_misc_stat_delete(flow_entry_t *flent)
{
if (flent->fe_misc_stat_ksp != NULL) {
kstat_delete(flent->fe_misc_stat_ksp);
flent->fe_misc_stat_ksp = NULL;
}
}
void
mac_soft_ring_stat_delete(mac_soft_ring_t *ringp)
{
mac_soft_ring_set_t *mac_srs = ringp->s_ring_set;
boolean_t is_tx_srs;
is_tx_srs = ((mac_srs->srs_type & SRST_TX) != 0);
if (is_tx_srs) {
/*
* Tx ring has been taken away. Before destroying corresponding
* soft ring, save the stats recorded by that soft ring.
*/
mac_client_impl_t *mcip = mac_srs->srs_mcip;
mac_misc_stats_t *mac_misc_stat = &mcip->mci_misc_stat;
mac_tx_stats_t *mac_tx_stat = &ringp->s_st_stat;
i_mac_add_stats(&mac_misc_stat->mms_defuncttxlanestats,
mac_tx_stat, &mac_misc_stat->mms_defuncttxlanestats,
tx_softring_stats_list, TX_SOFTRING_STAT_SIZE);
}
if (ringp->s_ring_ksp) {
kstat_delete(ringp->s_ring_ksp);
ringp->s_ring_ksp = NULL;
}
}
void
mac_pseudo_ring_stat_rename(mac_impl_t *mip)
{
mac_group_t *group;
mac_ring_t *ring;
/* Recreate pseudo rx ring kstats */
for (group = mip->mi_rx_groups; group != NULL;
group = group->mrg_next) {
for (ring = group->mrg_rings; ring != NULL;
ring = ring->mr_next) {
mac_ring_stat_delete(ring);
mac_ring_stat_create(ring);
}
}
/* Recreate pseudo tx ring kstats */
for (group = mip->mi_tx_groups; group != NULL;
group = group->mrg_next) {
for (ring = group->mrg_rings; ring != NULL;
ring = ring->mr_next) {
mac_ring_stat_delete(ring);
mac_ring_stat_create(ring);
}
}
}
void
mac_stat_rename(mac_client_impl_t *mcip)
{
flow_entry_t *flent = mcip->mci_flent;
mac_soft_ring_set_t *mac_srs;
mac_soft_ring_t *ringp;
int i, j;
ASSERT(flent != NULL);
/* Recreate rx SRSes kstats */
for (i = 0; i < flent->fe_rx_srs_cnt; i++) {
mac_srs = (mac_soft_ring_set_t *)flent->fe_rx_srs[i];
mac_srs_stat_delete(mac_srs);
mac_srs_stat_create(mac_srs);
/* Recreate rx fanout kstats */
for (j = 0; j < mac_srs->srs_tcp_ring_count; j++) {
ringp = mac_srs->srs_tcp_soft_rings[j];
mac_soft_ring_stat_delete(ringp);
mac_soft_ring_stat_create(ringp);
}
}
/* Recreate tx SRS kstats */
mac_srs = (mac_soft_ring_set_t *)flent->fe_tx_srs;
mac_srs_stat_delete(mac_srs);
mac_srs_stat_create(mac_srs);
/* Recreate tx sofring kstats */
for (ringp = mac_srs->srs_soft_ring_head; ringp;
ringp = ringp->s_ring_next) {
mac_soft_ring_stat_delete(ringp);
mac_soft_ring_stat_create(ringp);
}
/* Recreate misc kstats */
mac_misc_stat_delete(flent);
mac_misc_stat_create(flent);
}
void
mac_tx_srs_stat_recreate(mac_soft_ring_set_t *tx_srs, boolean_t add_stats)
{
mac_client_impl_t *mcip = tx_srs->srs_mcip;
mac_misc_stats_t *mac_misc_stat = &mcip->mci_misc_stat;
mac_tx_stats_t *mac_tx_stat = &tx_srs->srs_tx.st_stat;
if (add_stats) {
/* Add the stats to cumulative stats */
i_mac_add_stats(&mac_misc_stat->mms_defuncttxlanestats,
mac_tx_stat, &mac_misc_stat->mms_defuncttxlanestats,
tx_softring_stats_list, TX_SOFTRING_STAT_SIZE);
}
bzero(mac_tx_stat, sizeof (mac_tx_stats_t));
mac_srs_stat_delete(tx_srs);
mac_srs_stat_create(tx_srs);
}