Commit b40f4757 authored by Christoph Lameter's avatar Christoph Lameter Committed by Doug Ledford
Browse files

IB/core: Make device counter infrastructure dynamic



In practice, each RDMA device has a unique set of counters that the
hardware implements.  Having a central set of counters that they must
all adhere to is limiting and causes many useful counters to not be
available.

Therefore we create a dynamic counter registration infrastructure.

The driver must implement a stats structure allocation routine, in
which the driver must place the directory name it wants, a list of
names for all of the counters, an array of u64 counters themselves,
plus a few generic configuration options.

We then implement a core routine to create a sysfs file for each
of the named stats elements, and a core routine to retrieve the
stats when any of the sysfs attribute files are read.

To avoid excessive beating on the stats generation routine in the
drivers, the core code also caches the stats for a short period of
time so that someone attempting to read all of the stats in a
given device's directory will not result in a stats generation
call per file read.

Future work will attempt to standardize just the shared stats
elements, and possibly add a method to get the stats via netlink
in addition to sysfs.
Signed-off-by: default avatarChristoph Lameter <cl@linux.com>
Signed-off-by: default avatarMark Bloch <markb@mellanox.com>
Reviewed-by: default avatarSteve Wise <swise@opengridcomputing.com>
Signed-off-by: default avatarDoug Ledford <dledford@redhat.com>
[ Add caching, make structure names more informative, add i40iw support,
  other significant rewrites from the original patch ]
parent 8779e765
......@@ -56,6 +56,18 @@ SYSFS FILES
ports/1/pkeys/10 contains the value at index 10 in port 1's P_Key
table.
There is an optional "hw_counters" subdirectory that may be under either
the parent device or the port subdirectories or both. If present,
there are a list of counters provided by the hardware. They may match
some of the counters in the counters directory, but they often include
many other counters. In addition to the various counters, there will
be a file named "lifespan" that configures how frequently the core
should update the counters when they are being accessed (counters are
not updated if they are not being accessed). The lifespan is in milli-
seconds and defaults to 10 unless set to something else by the driver.
Users may echo a value between 0 - 10000 to the lifespan file to set
the length of time between updates in milliseconds.
MTHCA
The Mellanox HCA driver also creates the files:
......
......@@ -56,8 +56,10 @@ struct ib_port {
struct gid_attr_group *gid_attr_group;
struct attribute_group gid_group;
struct attribute_group pkey_group;
u8 port_num;
struct attribute_group *pma_table;
struct attribute_group *hw_stats_ag;
struct rdma_hw_stats *hw_stats;
u8 port_num;
};
struct port_attribute {
......@@ -80,6 +82,18 @@ struct port_table_attribute {
__be16 attr_id;
};
struct hw_stats_attribute {
struct attribute attr;
ssize_t (*show)(struct kobject *kobj,
struct attribute *attr, char *buf);
ssize_t (*store)(struct kobject *kobj,
struct attribute *attr,
const char *buf,
size_t count);
int index;
u8 port_num;
};
static ssize_t port_attr_show(struct kobject *kobj,
struct attribute *attr, char *buf)
{
......@@ -733,6 +747,212 @@ static struct attribute_group *get_counter_table(struct ib_device *dev,
return &pma_group;
}
static int update_hw_stats(struct ib_device *dev, struct rdma_hw_stats *stats,
u8 port_num, int index)
{
int ret;
if (time_is_after_eq_jiffies(stats->timestamp + stats->lifespan))
return 0;
ret = dev->get_hw_stats(dev, stats, port_num, index);
if (ret < 0)
return ret;
if (ret == stats->num_counters)
stats->timestamp = jiffies;
return 0;
}
static ssize_t print_hw_stat(struct rdma_hw_stats *stats, int index, char *buf)
{
return sprintf(buf, "%llu\n", stats->value[index]);
}
static ssize_t show_hw_stats(struct kobject *kobj, struct attribute *attr,
char *buf)
{
struct ib_device *dev;
struct ib_port *port;
struct hw_stats_attribute *hsa;
struct rdma_hw_stats *stats;
int ret;
hsa = container_of(attr, struct hw_stats_attribute, attr);
if (!hsa->port_num) {
dev = container_of((struct device *)kobj,
struct ib_device, dev);
stats = dev->hw_stats;
} else {
port = container_of(kobj, struct ib_port, kobj);
dev = port->ibdev;
stats = port->hw_stats;
}
ret = update_hw_stats(dev, stats, hsa->port_num, hsa->index);
if (ret)
return ret;
return print_hw_stat(stats, hsa->index, buf);
}
static ssize_t show_stats_lifespan(struct kobject *kobj,
struct attribute *attr,
char *buf)
{
struct hw_stats_attribute *hsa;
int msecs;
hsa = container_of(attr, struct hw_stats_attribute, attr);
if (!hsa->port_num) {
struct ib_device *dev = container_of((struct device *)kobj,
struct ib_device, dev);
msecs = jiffies_to_msecs(dev->hw_stats->lifespan);
} else {
struct ib_port *p = container_of(kobj, struct ib_port, kobj);
msecs = jiffies_to_msecs(p->hw_stats->lifespan);
}
return sprintf(buf, "%d\n", msecs);
}
static ssize_t set_stats_lifespan(struct kobject *kobj,
struct attribute *attr,
const char *buf, size_t count)
{
struct hw_stats_attribute *hsa;
int msecs;
int jiffies;
int ret;
ret = kstrtoint(buf, 10, &msecs);
if (ret)
return ret;
if (msecs < 0 || msecs > 10000)
return -EINVAL;
jiffies = msecs_to_jiffies(msecs);
hsa = container_of(attr, struct hw_stats_attribute, attr);
if (!hsa->port_num) {
struct ib_device *dev = container_of((struct device *)kobj,
struct ib_device, dev);
dev->hw_stats->lifespan = jiffies;
} else {
struct ib_port *p = container_of(kobj, struct ib_port, kobj);
p->hw_stats->lifespan = jiffies;
}
return count;
}
static void free_hsag(struct kobject *kobj, struct attribute_group *attr_group)
{
struct attribute **attr;
sysfs_remove_group(kobj, attr_group);
for (attr = attr_group->attrs; *attr; attr++)
kfree(*attr);
kfree(attr_group);
}
static struct attribute *alloc_hsa(int index, u8 port_num, const char *name)
{
struct hw_stats_attribute *hsa;
hsa = kmalloc(sizeof(*hsa), GFP_KERNEL);
if (!hsa)
return NULL;
hsa->attr.name = (char *)name;
hsa->attr.mode = S_IRUGO;
hsa->show = show_hw_stats;
hsa->store = NULL;
hsa->index = index;
hsa->port_num = port_num;
return &hsa->attr;
}
static struct attribute *alloc_hsa_lifespan(char *name, u8 port_num)
{
struct hw_stats_attribute *hsa;
hsa = kmalloc(sizeof(*hsa), GFP_KERNEL);
if (!hsa)
return NULL;
hsa->attr.name = name;
hsa->attr.mode = S_IWUSR | S_IRUGO;
hsa->show = show_stats_lifespan;
hsa->store = set_stats_lifespan;
hsa->index = 0;
hsa->port_num = port_num;
return &hsa->attr;
}
static void setup_hw_stats(struct ib_device *device, struct ib_port *port,
u8 port_num)
{
struct attribute_group *hsag = NULL;
struct rdma_hw_stats *stats;
int i = 0, ret;
stats = device->alloc_hw_stats(device, port_num);
if (!stats)
return;
if (!stats->names || stats->num_counters <= 0)
goto err;
hsag = kzalloc(sizeof(*hsag) +
// 1 extra for the lifespan config entry
sizeof(void *) * (stats->num_counters + 1),
GFP_KERNEL);
if (!hsag)
return;
ret = device->get_hw_stats(device, stats, port_num,
stats->num_counters);
if (ret != stats->num_counters)
goto err;
stats->timestamp = jiffies;
hsag->name = "hw_counters";
hsag->attrs = (void *)hsag + sizeof(*hsag);
for (i = 0; i < stats->num_counters; i++) {
hsag->attrs[i] = alloc_hsa(i, port_num, stats->names[i]);
if (!hsag->attrs[i])
goto err;
}
/* treat an error here as non-fatal */
hsag->attrs[i] = alloc_hsa_lifespan("lifespan", port_num);
if (port) {
struct kobject *kobj = &port->kobj;
ret = sysfs_create_group(kobj, hsag);
if (ret)
goto err;
port->hw_stats_ag = hsag;
port->hw_stats = stats;
} else {
struct kobject *kobj = &device->dev.kobj;
ret = sysfs_create_group(kobj, hsag);
if (ret)
goto err;
device->hw_stats_ag = hsag;
device->hw_stats = stats;
}
return;
err:
kfree(stats);
for (; i >= 0; i--)
kfree(hsag->attrs[i]);
kfree(hsag);
return;
}
static int add_port(struct ib_device *device, int port_num,
int (*port_callback)(struct ib_device *,
u8, struct kobject *))
......@@ -835,6 +1055,14 @@ static int add_port(struct ib_device *device, int port_num,
goto err_remove_pkey;
}
/*
* If port == 0, it means we have only one port and the parent
* device, not this port device, should be the holder of the
* hw_counters
*/
if (device->alloc_hw_stats && port_num)
setup_hw_stats(device, p, port_num);
list_add_tail(&p->kobj.entry, &device->port_list);
kobject_uevent(&p->kobj, KOBJ_ADD);
......@@ -972,120 +1200,6 @@ static struct device_attribute *ib_class_attributes[] = {
&dev_attr_node_desc
};
/* Show a given an attribute in the statistics group */
static ssize_t show_protocol_stat(const struct device *device,
struct device_attribute *attr, char *buf,
unsigned offset)
{
struct ib_device *dev = container_of(device, struct ib_device, dev);
union rdma_protocol_stats stats;
ssize_t ret;
ret = dev->get_protocol_stats(dev, &stats);
if (ret)
return ret;
return sprintf(buf, "%llu\n",
(unsigned long long) ((u64 *) &stats)[offset]);
}
/* generate a read-only iwarp statistics attribute */
#define IW_STATS_ENTRY(name) \
static ssize_t show_##name(struct device *device, \
struct device_attribute *attr, char *buf) \
{ \
return show_protocol_stat(device, attr, buf, \
offsetof(struct iw_protocol_stats, name) / \
sizeof (u64)); \
} \
static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL)
IW_STATS_ENTRY(ipInReceives);
IW_STATS_ENTRY(ipInHdrErrors);
IW_STATS_ENTRY(ipInTooBigErrors);
IW_STATS_ENTRY(ipInNoRoutes);
IW_STATS_ENTRY(ipInAddrErrors);
IW_STATS_ENTRY(ipInUnknownProtos);
IW_STATS_ENTRY(ipInTruncatedPkts);
IW_STATS_ENTRY(ipInDiscards);
IW_STATS_ENTRY(ipInDelivers);
IW_STATS_ENTRY(ipOutForwDatagrams);
IW_STATS_ENTRY(ipOutRequests);
IW_STATS_ENTRY(ipOutDiscards);
IW_STATS_ENTRY(ipOutNoRoutes);
IW_STATS_ENTRY(ipReasmTimeout);
IW_STATS_ENTRY(ipReasmReqds);
IW_STATS_ENTRY(ipReasmOKs);
IW_STATS_ENTRY(ipReasmFails);
IW_STATS_ENTRY(ipFragOKs);
IW_STATS_ENTRY(ipFragFails);
IW_STATS_ENTRY(ipFragCreates);
IW_STATS_ENTRY(ipInMcastPkts);
IW_STATS_ENTRY(ipOutMcastPkts);
IW_STATS_ENTRY(ipInBcastPkts);
IW_STATS_ENTRY(ipOutBcastPkts);
IW_STATS_ENTRY(tcpRtoAlgorithm);
IW_STATS_ENTRY(tcpRtoMin);
IW_STATS_ENTRY(tcpRtoMax);
IW_STATS_ENTRY(tcpMaxConn);
IW_STATS_ENTRY(tcpActiveOpens);
IW_STATS_ENTRY(tcpPassiveOpens);
IW_STATS_ENTRY(tcpAttemptFails);
IW_STATS_ENTRY(tcpEstabResets);
IW_STATS_ENTRY(tcpCurrEstab);
IW_STATS_ENTRY(tcpInSegs);
IW_STATS_ENTRY(tcpOutSegs);
IW_STATS_ENTRY(tcpRetransSegs);
IW_STATS_ENTRY(tcpInErrs);
IW_STATS_ENTRY(tcpOutRsts);
static struct attribute *iw_proto_stats_attrs[] = {
&dev_attr_ipInReceives.attr,
&dev_attr_ipInHdrErrors.attr,
&dev_attr_ipInTooBigErrors.attr,
&dev_attr_ipInNoRoutes.attr,
&dev_attr_ipInAddrErrors.attr,
&dev_attr_ipInUnknownProtos.attr,
&dev_attr_ipInTruncatedPkts.attr,
&dev_attr_ipInDiscards.attr,
&dev_attr_ipInDelivers.attr,
&dev_attr_ipOutForwDatagrams.attr,
&dev_attr_ipOutRequests.attr,
&dev_attr_ipOutDiscards.attr,
&dev_attr_ipOutNoRoutes.attr,
&dev_attr_ipReasmTimeout.attr,
&dev_attr_ipReasmReqds.attr,
&dev_attr_ipReasmOKs.attr,
&dev_attr_ipReasmFails.attr,
&dev_attr_ipFragOKs.attr,
&dev_attr_ipFragFails.attr,
&dev_attr_ipFragCreates.attr,
&dev_attr_ipInMcastPkts.attr,
&dev_attr_ipOutMcastPkts.attr,
&dev_attr_ipInBcastPkts.attr,
&dev_attr_ipOutBcastPkts.attr,
&dev_attr_tcpRtoAlgorithm.attr,
&dev_attr_tcpRtoMin.attr,
&dev_attr_tcpRtoMax.attr,
&dev_attr_tcpMaxConn.attr,
&dev_attr_tcpActiveOpens.attr,
&dev_attr_tcpPassiveOpens.attr,
&dev_attr_tcpAttemptFails.attr,
&dev_attr_tcpEstabResets.attr,
&dev_attr_tcpCurrEstab.attr,
&dev_attr_tcpInSegs.attr,
&dev_attr_tcpOutSegs.attr,
&dev_attr_tcpRetransSegs.attr,
&dev_attr_tcpInErrs.attr,
&dev_attr_tcpOutRsts.attr,
NULL
};
static struct attribute_group iw_stats_group = {
.name = "proto_stats",
.attrs = iw_proto_stats_attrs,
};
static void free_port_list_attributes(struct ib_device *device)
{
struct kobject *p, *t;
......@@ -1093,6 +1207,10 @@ static void free_port_list_attributes(struct ib_device *device)
list_for_each_entry_safe(p, t, &device->port_list, entry) {
struct ib_port *port = container_of(p, struct ib_port, kobj);
list_del(&p->entry);
if (port->hw_stats) {
kfree(port->hw_stats);
free_hsag(&port->kobj, port->hw_stats_ag);
}
sysfs_remove_group(p, port->pma_table);
sysfs_remove_group(p, &port->pkey_group);
sysfs_remove_group(p, &port->gid_group);
......@@ -1149,11 +1267,8 @@ int ib_device_register_sysfs(struct ib_device *device,
}
}
if (device->node_type == RDMA_NODE_RNIC && device->get_protocol_stats) {
ret = sysfs_create_group(&class_dev->kobj, &iw_stats_group);
if (ret)
goto err_put;
}
if (device->alloc_hw_stats)
setup_hw_stats(device, NULL, 0);
return 0;
......@@ -1169,15 +1284,18 @@ int ib_device_register_sysfs(struct ib_device *device,
void ib_device_unregister_sysfs(struct ib_device *device)
{
/* Hold kobject until ib_dealloc_device() */
struct kobject *kobj_dev = kobject_get(&device->dev.kobj);
int i;
if (device->node_type == RDMA_NODE_RNIC && device->get_protocol_stats)
sysfs_remove_group(kobj_dev, &iw_stats_group);
/* Hold kobject until ib_dealloc_device() */
kobject_get(&device->dev.kobj);
free_port_list_attributes(device);
if (device->hw_stats) {
kfree(device->hw_stats);
free_hsag(&device->dev.kobj, device->hw_stats_ag);
}
for (i = 0; i < ARRAY_SIZE(ib_class_attributes); ++i)
device_remove_file(&device->dev, ib_class_attributes[i]);
......
......@@ -1218,59 +1218,119 @@ static ssize_t show_board(struct device *dev, struct device_attribute *attr,
iwch_dev->rdev.rnic_info.pdev->device);
}
static int iwch_get_mib(struct ib_device *ibdev,
union rdma_protocol_stats *stats)
enum counters {
IPINRECEIVES,
IPINHDRERRORS,
IPINADDRERRORS,
IPINUNKNOWNPROTOS,
IPINDISCARDS,
IPINDELIVERS,
IPOUTREQUESTS,
IPOUTDISCARDS,
IPOUTNOROUTES,
IPREASMTIMEOUT,
IPREASMREQDS,
IPREASMOKS,
IPREASMFAILS,
TCPACTIVEOPENS,
TCPPASSIVEOPENS,
TCPATTEMPTFAILS,
TCPESTABRESETS,
TCPCURRESTAB,
TCPINSEGS,
TCPOUTSEGS,
TCPRETRANSSEGS,
TCPINERRS,
TCPOUTRSTS,
TCPRTOMIN,
TCPRTOMAX,
NR_COUNTERS
};
static const char * const names[] = {
[IPINRECEIVES] = "ipInReceives",
[IPINHDRERRORS] = "ipInHdrErrors",
[IPINADDRERRORS] = "ipInAddrErrors",
[IPINUNKNOWNPROTOS] = "ipInUnknownProtos",
[IPINDISCARDS] = "ipInDiscards",
[IPINDELIVERS] = "ipInDelivers",
[IPOUTREQUESTS] = "ipOutRequests",
[IPOUTDISCARDS] = "ipOutDiscards",
[IPOUTNOROUTES] = "ipOutNoRoutes",
[IPREASMTIMEOUT] = "ipReasmTimeout",
[IPREASMREQDS] = "ipReasmReqds",
[IPREASMOKS] = "ipReasmOKs",
[IPREASMFAILS] = "ipReasmFails",
[TCPACTIVEOPENS] = "tcpActiveOpens",
[TCPPASSIVEOPENS] = "tcpPassiveOpens",
[TCPATTEMPTFAILS] = "tcpAttemptFails",
[TCPESTABRESETS] = "tcpEstabResets",
[TCPCURRESTAB] = "tcpCurrEstab",
[TCPINSEGS] = "tcpInSegs",
[TCPOUTSEGS] = "tcpOutSegs",
[TCPRETRANSSEGS] = "tcpRetransSegs",
[TCPINERRS] = "tcpInErrs",
[TCPOUTRSTS] = "tcpOutRsts",
[TCPRTOMIN] = "tcpRtoMin",
[TCPRTOMAX] = "tcpRtoMax",
};
static struct rdma_hw_stats *iwch_alloc_stats(struct ib_device *ibdev,
u8 port_num)
{
BUILD_BUG_ON(ARRAY_SIZE(names) != NR_COUNTERS);
/* Our driver only supports device level stats */
if (port_num != 0)
return NULL;
return rdma_alloc_hw_stats_struct(names, NR_COUNTERS,
RDMA_HW_STATS_DEFAULT_LIFESPAN);
}
static int iwch_get_mib(struct ib_device *ibdev, struct rdma_hw_stats *stats,
u8 port, int index)
{
struct iwch_dev *dev;
struct tp_mib_stats m;
int ret;
if (port != 0 || !stats)
return -ENOSYS;
PDBG("%s ibdev %p\n", __func__, ibdev);
dev = to_iwch_dev(ibdev);
ret = dev->rdev.t3cdev_p->ctl(dev->rdev.t3cdev_p, RDMA_GET_MIB, &m);
if (ret)
return -ENOSYS;
memset(stats, 0, sizeof *stats);
stats->iw.ipInReceives = ((u64) m.ipInReceive_hi << 32) +
m.ipInReceive_lo;
stats->iw.ipInHdrErrors = ((u64) m.ipInHdrErrors_hi << 32) +
m.ipInHdrErrors_lo;
stats->iw.ipInAddrErrors = ((u64) m.ipInAddrErrors_hi << 32) +
m.ipInAddrErrors_lo;
stats->iw.ipInUnknownProtos = ((u64) m.ipInUnknownProtos_hi << 32) +
m.ipInUnknownProtos_lo;
stats->iw.ipInDiscards = ((u64) m.ipInDiscards_hi << 32) +
m.ipInDiscards_lo;
stats->iw.ipInDelivers = ((u64) m.ipInDelivers_hi << 32) +
m.ipInDelivers_lo;
stats->iw.ipOutRequests = ((u64) m.ipOutRequests_hi << 32) +
m.ipOutRequests_lo;
stats->iw.ipOutDiscards = ((u64) m.ipOutDiscards_hi << 32) +
m.ipOutDiscards_lo;
stats->iw.ipOutNoRoutes = ((u64) m.ipOutNoRoutes_hi << 32) +
m.ipOutNoRoutes_lo;
stats->iw.ipReasmTimeout = (u64) m.ipReasmTimeout;
stats->iw.ipReasmReqds = (u64) m.ipReasmReqds;
stats->iw.ipReasmOKs = (u64) m.ipReasmOKs;
stats->iw.ipReasmFails = (u64) m.ipReasmFails;
stats->iw.tcpActiveOpens = (u64) m.tcpActiveOpens;
stats->iw.tcpPassiveOpens = (u64) m.tcpPassiveOpens;
stats->iw.tcpAttemptFails = (u64) m.tcpAttemptFails;
stats->iw.tcpEstabResets = (u64) m.tcpEstabResets;
stats->iw.tcpOutRsts = (u64) m.tcpOutRsts;
stats->iw.tcpCurrEstab = (u64) m.tcpCurrEstab;
stats->iw.tcpInSegs = ((u64) m.tcpInSegs_hi << 32) +
m.tcpInSegs_lo;
stats->iw.tcpOutSegs = ((u64) m.tcpOutSegs_hi << 32) +
m.tcpOutSegs_lo;
stats->iw.tcpRetransSegs = ((u64) m.tcpRetransSeg_hi << 32) +
m.tcpRetransSeg_lo;
stats->iw.tcpInErrs = ((u64) m.tcpInErrs_hi << 32) +
m.tcpInErrs_lo;
stats->iw.tcpRtoMin = (u64) m.tcpRtoMin;
stats->iw.tcpRtoMax = (u64) m.tcpRtoMax;
return 0;
stats->value[IPINRECEIVES] = ((u64)m.ipInReceive_hi << 32) + m.ipInReceive_lo;
stats->value[IPINHDRERRORS] = ((u64)m.ipInHdrErrors_hi << 32) + m.ipInHdrErrors_lo;
stats->value[IPINADDRERRORS] = ((u64)m.ipInAddrErrors_hi << 32) + m.ipInAddrErrors_lo;
stats->value[IPINUNKNOWNPROTOS] = ((u64)m.ipInUnknownProtos_hi << 32) + m.ipInUnknownProtos_lo;
stats->value[IPINDISCARDS] = ((u64)m.ipInDiscards_hi << 32) + m.ipInDiscards_lo;
stats->value[IPINDELIVERS] = ((u64)m.ipInDelivers_hi << 32) + m.ipInDelivers_lo;
stats->value[IPOUTREQUESTS] = ((u64)m.ipOutRequests_hi << 32) + m.ipOutRequests_lo;
stats->value[IPOUTDISCARDS] = ((u64)m.ipOutDiscards_hi << 32) + m.ipOutDiscards_lo;
stats->value[IPOUTNOROUTES] = ((u64)m.ipOutNoRoutes_hi << 32) + m.ipOutNoRoutes_lo;
stats->value[IPREASMTIMEOUT] = m.ipReasmTimeout;
stats->value[IPREASMREQDS] = m.ipReasmReqds;
stats->value[IPREASMOKS] = m.ipReasmOKs;
stats->value[IPREASMFAILS] = m.ipReasmFails;
stats->value[TCPACTIVEOPENS] = m.tcpActiveOpens;
stats->value[TCPPASSIVEOPENS] = m.tcpPassiveOpens;
stats->value[TCPATTEMPTFAILS] = m.tcpAttemptFails;
stats->value[TCPESTABRESETS] = m.tcpEstabResets;
stats->value[TCPCURRESTAB] = m.tcpOutRsts;
stats->value[TCPINSEGS] = m.tcpCurrEstab;
stats->value[TCPOUTSEGS] = ((u64)m.tcpInSegs_hi << 32) + m.tcpInSegs_lo;
stats->value[TCPRETRANSSEGS] = ((u64)m.tcpOutSegs_hi << 32) + m.tcpOutSegs_lo;
stats->value[TCPINERRS] = ((u64)m.tcpRetransSeg_hi << 32) + m.tcpRetransSeg_lo,
stats->value[TCPOUTRSTS] = ((u64)m.tcpInErrs_hi << 32) + m.tcpInErrs_lo;