From e3d2b22125ab97651fc34314fd05747f58c8fd42 Mon Sep 17 00:00:00 2001
From: Michele Baldessari <michele@acksyn.org>
Date: Sun, 27 Apr 2014 10:26:16 +0100
Subject: [PATCH 2/2] Add sctp counters

---
 src/pmdas/linux/GNUmakefile          |   5 +-
 src/pmdas/linux/clusters.h           |   1 +
 src/pmdas/linux/help                 |  34 ++++++++
 src/pmdas/linux/pmda.c               | 106 +++++++++++++++++++++++
 src/pmdas/linux/proc_net_sctp_snmp.c | 160 +++++++++++++++++++++++++++++++++++
 src/pmdas/linux/proc_net_sctp_snmp.h |  56 ++++++++++++
 src/pmdas/linux/root_linux           |  36 ++++++++
 7 files changed, 396 insertions(+), 2 deletions(-)
 create mode 100644 src/pmdas/linux/proc_net_sctp_snmp.c
 create mode 100644 src/pmdas/linux/proc_net_sctp_snmp.h

diff --git a/src/pmdas/linux/GNUmakefile b/src/pmdas/linux/GNUmakefile
index 4a0cc4f7b980..d406e58e87fc 100644
--- a/src/pmdas/linux/GNUmakefile
+++ b/src/pmdas/linux/GNUmakefile
@@ -35,7 +35,7 @@ CFILES		= pmda.c \
 		  proc_slabinfo.c sem_limits.c msg_limits.c shm_limits.c \
 		  proc_uptime.c proc_sys_fs.c proc_vmstat.c \
 		  sysfs_kernel.c linux_table.c numa_meminfo.c \
-		  proc_net_netstat.c
+		  proc_net_netstat.c proc_net_sctp_snmp.c
 
 HFILES		= clusters.h indom.h convert.h \
 		  proc_stat.h proc_meminfo.h proc_loadavg.h \
@@ -46,7 +46,7 @@ HFILES		= clusters.h indom.h convert.h \
 		  proc_slabinfo.h sem_limits.h msg_limits.h shm_limits.h \
 		  proc_uptime.h proc_sys_fs.h proc_vmstat.h \
 		  sysfs_kernel.h linux_table.h numa_meminfo.h \
-		  proc_net_netstat.h
+		  proc_net_netstat.h proc_net_sctp_snmp.h
 
 VERSION_SCRIPT	= exports
 HELPTARGETS	= help.dir help.pag
@@ -113,6 +113,7 @@ pmda.o proc_net_netstat.o:	proc_net_netstat.h
 pmda.o proc_net_rpc.o:	proc_net_rpc.h
 pmda.o proc_net_snmp.o:	proc_net_snmp.h
 pmda.o proc_net_sockstat.o:	proc_net_sockstat.h
+pmda.o proc_net_sctp_snmp.o:	proc_net_sctp_snmp.h
 pmda.o proc_net_tcp.o:	proc_net_tcp.h
 pmda.o proc_partitions.o:	proc_partitions.h
 pmda.o proc_scsi.o:	proc_scsi.h
diff --git a/src/pmdas/linux/clusters.h b/src/pmdas/linux/clusters.h
index 3343f3fe5f61..eb62f0ba58f4 100644
--- a/src/pmdas/linux/clusters.h
+++ b/src/pmdas/linux/clusters.h
@@ -74,6 +74,7 @@ enum {
 	PROC_PID_FD,		/* 51 /proc/<pid>/fd -> proc PMDA */
 	CLUSTER_LV,		/* 52 /dev/mapper */
 	CLUSTER_NET_NETSTAT,    /* 53 /proc/net/netstat */
+	CLUSTER_NET_SCTP,       /* 54 /proc/net/sctp/snmp */
 
 
 	NUM_CLUSTERS		/* one more than highest numbered cluster */
diff --git a/src/pmdas/linux/help b/src/pmdas/linux/help
index aa0095aa5b35..2d419cc7447f 100644
--- a/src/pmdas/linux/help
+++ b/src/pmdas/linux/help
@@ -998,6 +998,40 @@ Excluding retransmission but including data-in-SYN). This counter is different f
 TcpOutSegs because TcpOutSegs also tracks pure ACKs. TCPOrigDataSent is
 more useful to track the TCP retransmission rate.
 
+@ network.sctp.currestab Currently established associations
+@ network.sctp.activeestabs Active established associations
+@ network.sctp.passiveestabs Passive established associations
+@ network.sctp.aborteds Aborts
+@ network.sctp.shutdowns Shutdowns
+@ network.sctp.outofblues Out of the blue packets
+@ network.sctp.checksumerrors Checksum errors
+@ network.sctp.outctrlchunks Outgoing control chunks
+@ network.sctp.outorderchunks Outgoing ordered chunks
+@ network.sctp.outunorderchunks Outgoing unordered chunks
+@ network.sctp.inctrlchunks Incoming control chunks
+@ network.sctp.inorderchunks Incoming ordered chunks
+@ network.sctp.inunorderchunks Incoming unordered chunks
+@ network.sctp.fragusrmsgs Fragmented user messages
+@ network.sctp.reasmusrmsgs Reassembled user messages
+@ network.sctp.outsctppacks Outgoing packets
+@ network.sctp.insctppacks Incoming packets
+@ network.sctp.t1initexpireds T1 init expired
+@ network.sctp.t1cookieexpireds T1 cookie expired
+@ network.sctp.t2shutdownexpireds T2 shutdown expired
+@ network.sctp.t3rtxexpireds T3 RTX expired
+@ network.sctp.t4rtoexpireds T4 RTO expired
+@ network.sctp.t5shutdownguardexpireds T5 shutdown guard expires
+@ network.sctp.delaysackexpireds Delayed SACKs expired
+@ network.sctp.autocloseexpireds Autoclose expired
+@ network.sctp.t3retransmits T3 retransmits
+@ network.sctp.pmtudretransmits PMTUD retransmits
+@ network.sctp.fastretransmits Fast retransmits
+@ network.sctp.inpktsoftirq Incoming packet softirqs
+@ network.sctp.inpktbacklog Incoming packet backlog
+@ network.sctp.inpktdiscards Incoming packet discards
+@ network.sctp.indatachunkdiscards Incoming data chunk discards
+
+
 @ pmda.uname identity and type of current system
 Identity and type of current system.  The concatenation of the values
 returned from utsname(2), also similar to uname -a.
diff --git a/src/pmdas/linux/pmda.c b/src/pmdas/linux/pmda.c
index 73da7522fcdc..cf4cc05442a2 100644
--- a/src/pmdas/linux/pmda.c
+++ b/src/pmdas/linux/pmda.c
@@ -49,6 +49,7 @@
 #include "proc_net_tcp.h"
 #include "proc_partitions.h"
 #include "proc_net_netstat.h"
+#include "proc_net_sctp_snmp.h"
 #include "proc_net_snmp.h"
 #include "proc_scsi.h"
 #include "proc_slabinfo.h"
@@ -98,6 +99,7 @@ proc_vmstat_t _pm_proc_vmstat;
 proc_net_snmp_t _pm_proc_net_snmp;
 pmdaInstid _pm_proc_net_snmp_indom_id[NR_ICMPMSG_COUNTERS];
 proc_net_netstat_t _pm_proc_net_netstat;
+proc_net_sctp_snmp_t _pm_proc_net_sctp;
 
 /*
  * Metric Instance Domains (statically initialized ones only)
@@ -2924,6 +2926,107 @@ static pmdaMetric metrictab[] = {
     { PMDA_PMID(CLUSTER_NET_NETSTAT,118), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER,
     PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } },
 
+/*
+ * /proc/net/sctp/snmp
+ */
+/* network.sctp.currestab */
+  { &_pm_proc_net_sctp.snmp[_PM_SCTP_SNMP_SCTPCURRESTAB],
+    { PMDA_PMID(CLUSTER_NET_SCTP,0), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER,
+    PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } },
+  { &_pm_proc_net_sctp.snmp[_PM_SCTP_SNMP_SCTPACTIVEESTABS],
+    { PMDA_PMID(CLUSTER_NET_SCTP,1), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER,
+    PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } },
+  { &_pm_proc_net_sctp.snmp[_PM_SCTP_SNMP_SCTPPASSIVEESTABS],
+    { PMDA_PMID(CLUSTER_NET_SCTP,2), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER,
+    PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } },
+  { &_pm_proc_net_sctp.snmp[_PM_SCTP_SNMP_SCTPABORTEDS],
+    { PMDA_PMID(CLUSTER_NET_SCTP,3), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER,
+    PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } },
+  { &_pm_proc_net_sctp.snmp[_PM_SCTP_SNMP_SCTPSHUTDOWNS],
+    { PMDA_PMID(CLUSTER_NET_SCTP,4), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER,
+    PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } },
+  { &_pm_proc_net_sctp.snmp[_PM_SCTP_SNMP_SCTPOUTOFBLUES],
+    { PMDA_PMID(CLUSTER_NET_SCTP,5), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER,
+    PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } },
+  { &_pm_proc_net_sctp.snmp[_PM_SCTP_SNMP_SCTPCHECKSUMERRORS],
+    { PMDA_PMID(CLUSTER_NET_SCTP,6), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER,
+    PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } },
+  { &_pm_proc_net_sctp.snmp[_PM_SCTP_SNMP_SCTPOUTCTRLCHUNKS],
+    { PMDA_PMID(CLUSTER_NET_SCTP,7), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER,
+    PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } },
+  { &_pm_proc_net_sctp.snmp[_PM_SCTP_SNMP_SCTPOUTORDERCHUNKS],
+    { PMDA_PMID(CLUSTER_NET_SCTP,8), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER,
+    PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } },
+  { &_pm_proc_net_sctp.snmp[_PM_SCTP_SNMP_SCTPOUTUNORDERCHUNKS],
+    { PMDA_PMID(CLUSTER_NET_SCTP,9), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER,
+    PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } },
+  { &_pm_proc_net_sctp.snmp[_PM_SCTP_SNMP_SCTPINCTRLCHUNKS],
+    { PMDA_PMID(CLUSTER_NET_SCTP,10), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER,
+    PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } },
+  { &_pm_proc_net_sctp.snmp[_PM_SCTP_SNMP_SCTPINORDERCHUNKS],
+    { PMDA_PMID(CLUSTER_NET_SCTP,11), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER,
+    PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } },
+  { &_pm_proc_net_sctp.snmp[_PM_SCTP_SNMP_SCTPINUNORDERCHUNKS],
+    { PMDA_PMID(CLUSTER_NET_SCTP,12), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER,
+    PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } },
+  { &_pm_proc_net_sctp.snmp[_PM_SCTP_SNMP_SCTPFRAGUSRMSGS],
+    { PMDA_PMID(CLUSTER_NET_SCTP,13), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER,
+    PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } },
+  { &_pm_proc_net_sctp.snmp[_PM_SCTP_SNMP_SCTPREASMUSRMSGS],
+    { PMDA_PMID(CLUSTER_NET_SCTP,14), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER,
+    PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } },
+  { &_pm_proc_net_sctp.snmp[_PM_SCTP_SNMP_SCTPOUTSCTPPACKS],
+    { PMDA_PMID(CLUSTER_NET_SCTP,15), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER,
+    PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } },
+  { &_pm_proc_net_sctp.snmp[_PM_SCTP_SNMP_SCTPINSCTPPACKS],
+    { PMDA_PMID(CLUSTER_NET_SCTP,16), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER,
+    PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } },
+  { &_pm_proc_net_sctp.snmp[_PM_SCTP_SNMP_SCTPT1INITEXPIREDS],
+    { PMDA_PMID(CLUSTER_NET_SCTP,17), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER,
+    PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } },
+  { &_pm_proc_net_sctp.snmp[_PM_SCTP_SNMP_SCTPT1COOKIEEXPIREDS],
+    { PMDA_PMID(CLUSTER_NET_SCTP,18), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER,
+    PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } },
+  { &_pm_proc_net_sctp.snmp[_PM_SCTP_SNMP_SCTPT2SHUTDOWNEXPIREDS],
+    { PMDA_PMID(CLUSTER_NET_SCTP,19), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER,
+    PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } },
+  { &_pm_proc_net_sctp.snmp[_PM_SCTP_SNMP_SCTPT3RTXEXPIREDS],
+    { PMDA_PMID(CLUSTER_NET_SCTP,20), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER,
+    PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } },
+  { &_pm_proc_net_sctp.snmp[_PM_SCTP_SNMP_SCTPT4RTOEXPIREDS],
+    { PMDA_PMID(CLUSTER_NET_SCTP,21), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER,
+    PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } },
+  { &_pm_proc_net_sctp.snmp[_PM_SCTP_SNMP_SCTPT5SHUTDOWNGUARDEXPIREDS],
+    { PMDA_PMID(CLUSTER_NET_SCTP,22), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER,
+    PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } },
+  { &_pm_proc_net_sctp.snmp[_PM_SCTP_SNMP_SCTPDELAYSACKEXPIREDS],
+    { PMDA_PMID(CLUSTER_NET_SCTP,23), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER,
+    PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } },
+  { &_pm_proc_net_sctp.snmp[_PM_SCTP_SNMP_SCTPAUTOCLOSEEXPIREDS],
+    { PMDA_PMID(CLUSTER_NET_SCTP,24), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER,
+    PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } },
+  { &_pm_proc_net_sctp.snmp[_PM_SCTP_SNMP_SCTPT3RETRANSMITS],
+    { PMDA_PMID(CLUSTER_NET_SCTP,25), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER,
+    PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } },
+  { &_pm_proc_net_sctp.snmp[_PM_SCTP_SNMP_SCTPPMTUDRETRANSMITS],
+    { PMDA_PMID(CLUSTER_NET_SCTP,26), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER,
+    PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } },
+  { &_pm_proc_net_sctp.snmp[_PM_SCTP_SNMP_SCTPFASTRETRANSMITS],
+    { PMDA_PMID(CLUSTER_NET_SCTP,27), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER,
+    PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } },
+  { &_pm_proc_net_sctp.snmp[_PM_SCTP_SNMP_SCTPINPKTSOFTIRQ],
+    { PMDA_PMID(CLUSTER_NET_SCTP,28), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER,
+    PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } },
+  { &_pm_proc_net_sctp.snmp[_PM_SCTP_SNMP_SCTPINPKTBACKLOG],
+    { PMDA_PMID(CLUSTER_NET_SCTP,29), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER,
+    PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } },
+  { &_pm_proc_net_sctp.snmp[_PM_SCTP_SNMP_SCTPINPKTDISCARDS],
+    { PMDA_PMID(CLUSTER_NET_SCTP,30), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER,
+    PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } },
+  { &_pm_proc_net_sctp.snmp[_PM_SCTP_SNMP_SCTPINDATACHUNKDISCARDS],
+    { PMDA_PMID(CLUSTER_NET_SCTP,31), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER,
+    PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } },
+
 /* hinv.map.scsi */
     { NULL, 
       { PMDA_PMID(CLUSTER_SCSI,0), PM_TYPE_STRING, SCSI_INDOM, PM_SEM_DISCRETE, 
@@ -3768,6 +3871,9 @@ linux_refresh(pmdaExt *pmda, int *need_refresh)
     if (need_refresh[CLUSTER_NET_NETSTAT])
 	refresh_proc_net_netstat(&_pm_proc_net_netstat);
 
+    if (need_refresh[CLUSTER_NET_SCTP])
+	refresh_proc_net_sctp_snmp(&_pm_proc_net_sctp);
+
     if (need_refresh[CLUSTER_SLAB])
 	refresh_proc_slabinfo(&proc_slabinfo);
 
diff --git a/src/pmdas/linux/proc_net_sctp_snmp.c b/src/pmdas/linux/proc_net_sctp_snmp.c
new file mode 100644
index 000000000000..9cb397f6fa2a
--- /dev/null
+++ b/src/pmdas/linux/proc_net_sctp_snmp.c
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2014 Red Hat.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+#include "pmapi.h"
+#include "impl.h"
+#include "pmda.h"
+#include "proc_net_sctp_snmp.h"
+#include <ctype.h>
+
+extern proc_net_sctp_snmp_t	_pm_proc_net_sctp;
+
+typedef struct {
+    const char		*field;
+    __uint64_t		*offset;
+} sctp_snmp_fields_t;
+
+sctp_snmp_fields_t sctp_snmp_fields[] = {
+    { .field = "SctpCurrEstab",
+     .offset = &_pm_proc_net_sctp.snmp[_PM_SCTP_SNMP_SCTPCURRESTAB] },
+    { .field = "SctpActiveEstabs",
+     .offset = &_pm_proc_net_sctp.snmp[_PM_SCTP_SNMP_SCTPACTIVEESTABS] },
+    { .field = "SctpPassiveEstabs",
+     .offset = &_pm_proc_net_sctp.snmp[_PM_SCTP_SNMP_SCTPPASSIVEESTABS] },
+    { .field = "SctpAborteds",
+     .offset = &_pm_proc_net_sctp.snmp[_PM_SCTP_SNMP_SCTPABORTEDS] },
+    { .field = "SctpShutdowns",
+     .offset = &_pm_proc_net_sctp.snmp[_PM_SCTP_SNMP_SCTPSHUTDOWNS] },
+    { .field = "SctpOutOfBlues",
+     .offset = &_pm_proc_net_sctp.snmp[_PM_SCTP_SNMP_SCTPOUTOFBLUES] },
+    { .field = "SctpChecksumErrors",
+     .offset = &_pm_proc_net_sctp.snmp[_PM_SCTP_SNMP_SCTPCHECKSUMERRORS] },
+    { .field = "SctpOutCtrlChunks",
+     .offset = &_pm_proc_net_sctp.snmp[_PM_SCTP_SNMP_SCTPOUTCTRLCHUNKS] },
+    { .field = "SctpOutOrderChunks",
+     .offset = &_pm_proc_net_sctp.snmp[_PM_SCTP_SNMP_SCTPOUTORDERCHUNKS] },
+    { .field = "SctpOutUnorderChunks",
+     .offset = &_pm_proc_net_sctp.snmp[_PM_SCTP_SNMP_SCTPOUTUNORDERCHUNKS] },
+    { .field = "SctpInCtrlChunks",
+     .offset = &_pm_proc_net_sctp.snmp[_PM_SCTP_SNMP_SCTPINCTRLCHUNKS] },
+    { .field = "SctpInOrderChunks",
+     .offset = &_pm_proc_net_sctp.snmp[_PM_SCTP_SNMP_SCTPINORDERCHUNKS] },
+    { .field = "SctpInUnorderChunks",
+     .offset = &_pm_proc_net_sctp.snmp[_PM_SCTP_SNMP_SCTPINUNORDERCHUNKS] },
+    { .field = "SctpFragUsrMsgs",
+     .offset = &_pm_proc_net_sctp.snmp[_PM_SCTP_SNMP_SCTPFRAGUSRMSGS] },
+    { .field = "SctpReasmUsrMsgs",
+     .offset = &_pm_proc_net_sctp.snmp[_PM_SCTP_SNMP_SCTPREASMUSRMSGS] },
+    { .field = "SctpOutSCTPPacks",
+     .offset = &_pm_proc_net_sctp.snmp[_PM_SCTP_SNMP_SCTPOUTSCTPPACKS] },
+    { .field = "SctpInSCTPPacks",
+     .offset = &_pm_proc_net_sctp.snmp[_PM_SCTP_SNMP_SCTPINSCTPPACKS] },
+    { .field = "SctpT1InitExpireds",
+     .offset = &_pm_proc_net_sctp.snmp[_PM_SCTP_SNMP_SCTPT1INITEXPIREDS] },
+    { .field = "SctpT1CookieExpireds",
+     .offset = &_pm_proc_net_sctp.snmp[_PM_SCTP_SNMP_SCTPT1COOKIEEXPIREDS] },
+    { .field = "SctpT2ShutdownExpireds",
+     .offset = &_pm_proc_net_sctp.snmp[_PM_SCTP_SNMP_SCTPT2SHUTDOWNEXPIREDS] },
+    { .field = "SctpT3RtxExpireds",
+     .offset = &_pm_proc_net_sctp.snmp[_PM_SCTP_SNMP_SCTPT3RTXEXPIREDS] },
+    { .field = "SctpT4RtoExpireds",
+     .offset = &_pm_proc_net_sctp.snmp[_PM_SCTP_SNMP_SCTPT4RTOEXPIREDS] },
+    { .field = "SctpT5ShutdownGuardExpireds",
+     .offset = &_pm_proc_net_sctp.snmp[_PM_SCTP_SNMP_SCTPT5SHUTDOWNGUARDEXPIREDS] },
+    { .field = "SctpDelaySackExpireds",
+     .offset = &_pm_proc_net_sctp.snmp[_PM_SCTP_SNMP_SCTPDELAYSACKEXPIREDS] },
+    { .field = "SctpAutocloseExpireds",
+     .offset = &_pm_proc_net_sctp.snmp[_PM_SCTP_SNMP_SCTPAUTOCLOSEEXPIREDS] },
+    { .field = "SctpT3Retransmits",
+     .offset = &_pm_proc_net_sctp.snmp[_PM_SCTP_SNMP_SCTPT3RETRANSMITS] },
+    { .field = "SctpPmtudRetransmits",
+     .offset = &_pm_proc_net_sctp.snmp[_PM_SCTP_SNMP_SCTPPMTUDRETRANSMITS] },
+    { .field = "SctpFastRetransmits",
+     .offset = &_pm_proc_net_sctp.snmp[_PM_SCTP_SNMP_SCTPFASTRETRANSMITS] },
+    { .field = "SctpInPktSoftirq",
+     .offset = &_pm_proc_net_sctp.snmp[_PM_SCTP_SNMP_SCTPINPKTSOFTIRQ] },
+    { .field = "SctpInPktBacklog",
+     .offset = &_pm_proc_net_sctp.snmp[_PM_SCTP_SNMP_SCTPINPKTBACKLOG] },
+    { .field = "SctpInPktDiscards",
+     .offset = &_pm_proc_net_sctp.snmp[_PM_SCTP_SNMP_SCTPINPKTDISCARDS] },
+    { .field = "SctpInDataChunkDiscards",
+     .offset = &_pm_proc_net_sctp.snmp[_PM_SCTP_SNMP_SCTPINDATACHUNKDISCARDS] },
+};
+
+
+static void
+get_fields(sctp_snmp_fields_t *fields, int count, char *line)
+{
+    char *p, *label;
+    unsigned long value;
+    int i;
+
+    /* sctp/snmp lines are in the form: %-32s\t%ld\n */
+    p = line;
+    while (!isblank(*p) && *p != '\n')
+        p++;
+    --p;
+    *p = '\0';
+    label = line;
+    while (*p != '\t' && *p != '\n')
+        p++;
+
+    value = strtoull(p, NULL, 10);
+
+    /* optimize for the case where values exported by the kernel
+     * are complete and in the order as codified in this pmda
+     */
+    if (strcmp(fields[count].field, label) == 0)
+        *fields[count].offset = value;
+    else {
+        for (i = 0; fields[i].field; i++) {
+            if (strcmp(fields[i].field, label) != 0)
+               continue;
+            *fields[i].offset = value;
+            break;
+        }
+    }
+}
+
+#define SCTP_SNMP_OFFSET(ii, pp) (int64_t *)((char *)pp + \
+    (__psint_t)sctp_snmp_fields[ii].offset - (__psint_t)&_pm_proc_net_sctp.snmp)
+
+static void
+init_refresh_proc_net_sctp_snmp(proc_net_sctp_snmp_t *sctp_snmp)
+{
+    int		i;
+
+    /* initially, all marked as "no value available" */
+    for (i = 0; sctp_snmp_fields[i].field != NULL; i++)
+	*(SCTP_SNMP_OFFSET(i, sctp_snmp)) = -1;
+}
+
+int
+refresh_proc_net_sctp_snmp(proc_net_sctp_snmp_t *sctp_snmp)
+{
+    /* Need a sufficiently large value to hold a full line */
+    char	line[512];
+    int		count = 0;
+    FILE	*fp;
+
+    init_refresh_proc_net_sctp_snmp(sctp_snmp);
+    if ((fp = fopen("/proc/net/sctp/snmp", "r")) == NULL)
+	return -oserror();
+    while (fgets(line, sizeof(line), fp) != NULL) {
+	get_fields(sctp_snmp_fields, count, line);
+	count++;
+    }
+    fclose(fp);
+    return 0;
+}
diff --git a/src/pmdas/linux/proc_net_sctp_snmp.h b/src/pmdas/linux/proc_net_sctp_snmp.h
new file mode 100644
index 000000000000..38a4b43af27d
--- /dev/null
+++ b/src/pmdas/linux/proc_net_sctp_snmp.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2014 Red Hat.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+enum {
+    _PM_SCTP_SNMP_SCTPCURRESTAB = 0,
+    _PM_SCTP_SNMP_SCTPACTIVEESTABS,
+    _PM_SCTP_SNMP_SCTPPASSIVEESTABS,
+    _PM_SCTP_SNMP_SCTPABORTEDS,
+    _PM_SCTP_SNMP_SCTPSHUTDOWNS,
+    _PM_SCTP_SNMP_SCTPOUTOFBLUES,
+    _PM_SCTP_SNMP_SCTPCHECKSUMERRORS,
+    _PM_SCTP_SNMP_SCTPOUTCTRLCHUNKS,
+    _PM_SCTP_SNMP_SCTPOUTORDERCHUNKS,
+    _PM_SCTP_SNMP_SCTPOUTUNORDERCHUNKS,
+    _PM_SCTP_SNMP_SCTPINCTRLCHUNKS,
+    _PM_SCTP_SNMP_SCTPINORDERCHUNKS,
+    _PM_SCTP_SNMP_SCTPINUNORDERCHUNKS,
+    _PM_SCTP_SNMP_SCTPFRAGUSRMSGS,
+    _PM_SCTP_SNMP_SCTPREASMUSRMSGS,
+    _PM_SCTP_SNMP_SCTPOUTSCTPPACKS,
+    _PM_SCTP_SNMP_SCTPINSCTPPACKS,
+    _PM_SCTP_SNMP_SCTPT1INITEXPIREDS,
+    _PM_SCTP_SNMP_SCTPT1COOKIEEXPIREDS,
+    _PM_SCTP_SNMP_SCTPT2SHUTDOWNEXPIREDS,
+    _PM_SCTP_SNMP_SCTPT3RTXEXPIREDS,
+    _PM_SCTP_SNMP_SCTPT4RTOEXPIREDS,
+    _PM_SCTP_SNMP_SCTPT5SHUTDOWNGUARDEXPIREDS,
+    _PM_SCTP_SNMP_SCTPDELAYSACKEXPIREDS,
+    _PM_SCTP_SNMP_SCTPAUTOCLOSEEXPIREDS,
+    _PM_SCTP_SNMP_SCTPT3RETRANSMITS,
+    _PM_SCTP_SNMP_SCTPPMTUDRETRANSMITS,
+    _PM_SCTP_SNMP_SCTPFASTRETRANSMITS,
+    _PM_SCTP_SNMP_SCTPINPKTSOFTIRQ,
+    _PM_SCTP_SNMP_SCTPINPKTBACKLOG,
+    _PM_SCTP_SNMP_SCTPINPKTDISCARDS,
+    _PM_SCTP_SNMP_SCTPINDATACHUNKDISCARDS,
+    _PM_SCTP_SNMP_NFIELDS /* must be last */
+};
+
+
+typedef struct {
+    __uint64_t	snmp[_PM_SCTP_SNMP_NFIELDS];
+} proc_net_sctp_snmp_t;
+
+extern int refresh_proc_net_sctp_snmp(proc_net_sctp_snmp_t *);
diff --git a/src/pmdas/linux/root_linux b/src/pmdas/linux/root_linux
index 9f233471cd4b..53532e289ab1 100644
--- a/src/pmdas/linux/root_linux
+++ b/src/pmdas/linux/root_linux
@@ -409,6 +409,7 @@ network {
     udp
     udplite
     tcpconn
+    sctp
 }
 
 network.interface {
@@ -695,6 +696,41 @@ network.icmpmsg {
     outtype		60:14:89
 }
 
+network.sctp {
+    currestab           60:54:00
+    activeestabs        60:54:01
+    passiveestabs       60:54:02
+    aborteds            60:54:03
+    shutdowns           60:54:04
+    outofblues          60:54:05
+    checksumerrors      60:54:06
+    outctrlchunks       60:54:07
+    outorderchunks      60:54:08
+    outunorderchunks    60:54:09
+    inctrlchunks        60:54:10
+    inorderchunks       60:54:11
+    inunorderchunks     60:54:12
+    fragusrmsgs         60:54:13
+    reasmusrmsgs        60:54:14
+    outsctppacks        60:54:15
+    insctppacks         60:54:16
+    t1initexpireds      60:54:17
+    t1cookieexpireds    60:54:18
+    t2shutdownexpireds  60:54:19
+    t3rtxexpireds       60:54:20
+    t4rtoexpireds       60:54:21
+    t5shutdownguardexpireds 60:54:22
+    delaysackexpireds   60:54:23
+    autocloseexpireds   60:54:24
+    t3retransmits       60:54:25
+    pmtudretransmits    60:54:26
+    fastretransmits     60:54:27
+    inpktsoftirq        60:54:28
+    inpktbacklog        60:54:29
+    inpktdiscards       60:54:30
+    indatachunkdiscards 60:54:31
+}
+
 filesys {
     capacity		60:5:1
     used		60:5:2
-- 
1.9.0

