3 * TCP MIB group implementation - tcp.c
7 #include <net-snmp/net-snmp-config.h>
20 #include <sys/param.h>
22 #if HAVE_SYS_PROTOSW_H
23 #include <sys/protosw.h>
27 #include <sys/sysmp.h>
29 #if defined(IFNET_NEEDS_KERNEL) && !defined(_KERNEL)
31 #define _I_DEFINED_KERNEL
34 #include <sys/socket.h>
40 #include <netinet/in.h>
46 #include <net/if_var.h>
48 #ifdef _I_DEFINED_KERNEL
52 #include <sys/stream.h>
55 #include <net/route.h>
57 #if HAVE_NETINET_IN_SYSTM_H
58 #include <netinet/in_systm.h>
61 #include <netinet/ip.h>
64 #include <sys/queue.h>
66 #if HAVE_NETINET_IP_VAR_H
67 #include <netinet/ip_var.h>
70 #if HAVE_NETINET6_IP6_VAR_H
71 #include <netinet6/ip6_var.h>
74 #if HAVE_SYS_SOCKETVAR_H
75 #include <sys/socketvar.h>
77 #if HAVE_NETINET_IN_PCB_H
78 #include <netinet/in_pcb.h>
81 #include <inet/mib2.h>
85 #include <sys/sysctl.h>
88 #include <arpa/inet.h>
91 #if defined(osf4) || defined(aix4) || defined(hpux10)
93 * these are undefed to remove a stupid warning on osf compilers
94 * because they get redefined with a slightly different notation of the
100 #if HAVE_NETINET_TCP_H
101 #include <netinet/tcp.h>
103 #if HAVE_NETINET_TCPIP_H
104 #include <netinet/tcpip.h>
106 #if HAVE_NETINET_TCP_TIMER_H
107 #include <netinet/tcp_timer.h>
109 #if HAVE_NETINET_TCP_VAR_H
110 #include <netinet/tcp_var.h>
112 #if HAVE_NETINET_TCP_FSM_H
113 #include <netinet/tcp_fsm.h>
115 #if HAVE_SYS_TCPIPSTATS_H
116 #include <sys/tcpipstats.h>
123 #include <net-snmp/net-snmp-includes.h>
124 #include <net-snmp/agent/net-snmp-agent-includes.h>
125 #include <net-snmp/agent/auto_nlist.h>
128 #include "kernel_sunos5.h"
133 #include "kernel_linux.h"
135 #include "util_funcs.h"
139 #include <netinet/mib_kern.h>
148 #include "tcpTable.h"
149 #ifdef SNMP_SYSOR_MIB
150 #include "sysORTable.h"
151 #endif /* SNMP_SYSOR_MIB */
153 #ifndef MIB_STATS_CACHE_TIMEOUT
154 #define MIB_STATS_CACHE_TIMEOUT 5
156 #ifndef TCP_STATS_CACHE_TIMEOUT
157 #define TCP_STATS_CACHE_TIMEOUT MIB_STATS_CACHE_TIMEOUT
159 marker_t tcp_stats_cache_marker = NULL;
161 /*********************
163 * Kernel & interface information,
164 * and internal forward declarations
166 *********************/
169 static unsigned int hz;
172 /*********************
174 * Initialisation & common implementation functions
176 *********************/
178 struct variable3 tcp_variables[] = {
179 {TCPRTOALGORITHM, ASN_INTEGER, RONLY, var_tcp, 1, {1}},
180 {TCPRTOMIN, ASN_INTEGER, RONLY, var_tcp, 1, {2}},
182 {TCPRTOMAX, ASN_INTEGER, RONLY, var_tcp, 1, {3}},
184 {TCPMAXCONN, ASN_INTEGER, RONLY, var_tcp, 1, {4}},
186 {TCPACTIVEOPENS, ASN_COUNTER, RONLY, var_tcp, 1, {5}},
187 {TCPPASSIVEOPENS, ASN_COUNTER, RONLY, var_tcp, 1, {6}},
188 {TCPATTEMPTFAILS, ASN_COUNTER, RONLY, var_tcp, 1, {7}},
189 {TCPESTABRESETS, ASN_COUNTER, RONLY, var_tcp, 1, {8}},
191 {TCPCURRESTAB, ASN_GAUGE, RONLY, var_tcp, 1, {9}},
193 {TCPINSEGS, ASN_COUNTER, RONLY, var_tcp, 1, {10}},
194 {TCPOUTSEGS, ASN_COUNTER, RONLY, var_tcp, 1, {11}},
195 {TCPRETRANSSEGS, ASN_COUNTER, RONLY, var_tcp, 1, {12}},
198 {TCPCONNSTATE, ASN_INTEGER, RWRITE, var_tcpEntry, 3, {13, 1, 1}},
200 {TCPCONNSTATE, ASN_INTEGER, RONLY, var_tcpEntry, 3, {13, 1, 1}},
202 {TCPCONNLOCALADDRESS, ASN_IPADDRESS, RONLY, var_tcpEntry, 3,
204 {TCPCONNLOCALPORT, ASN_INTEGER, RONLY, var_tcpEntry, 3, {13, 1, 3}},
205 {TCPCONNREMADDRESS, ASN_IPADDRESS, RONLY, var_tcpEntry, 3, {13, 1, 4}},
206 {TCPCONNREMPORT, ASN_INTEGER, RONLY, var_tcpEntry, 3, {13, 1, 5}},
207 {TCPINERRS, ASN_COUNTER, RONLY, var_tcp, 1, {14}},
208 {TCPOUTRSTS, ASN_COUNTER, RONLY, var_tcp, 1, {15}}
212 * Define the OID pointer to the top of the mib tree that we're
213 * registering underneath, and the OID for the MIB module
215 oid tcp_variables_oid[] = { SNMP_OID_MIB2, 6 };
216 oid tcp_module_oid[] = { SNMP_OID_MIB2, 49 };
222 * register ourselves with the agent to handle our mib tree
224 REGISTER_MIB("mibII/tcp", tcp_variables, variable3,
226 #ifdef SNMP_SYSOR_MIB
227 REGISTER_SYSOR_ENTRY(tcp_module_oid,
228 "The MIB module for managing TCP implementations");
229 #endif /* SNMP_SYSOR_MIB */
230 #ifdef TCPSTAT_SYMBOL
231 auto_nlist(TCPSTAT_SYMBOL, 0, 0);
234 auto_nlist(TCP_SYMBOL, 0, 0);
237 hz = sysconf(_SC_CLK_TCK); /* get ticks/s from system */
240 init_kernel_sunos5();
245 /*********************
247 * System specific implementation functions
249 *********************/
252 #define TCP_STAT_STRUCTURE struct tcp_mib
253 #define USES_SNMP_DESIGNED_TCPSTAT
254 #undef TCPSTAT_SYMBOL
258 #define TCP_STAT_STRUCTURE mib2_tcp_t
259 #define USES_SNMP_DESIGNED_TCPSTAT
263 #define TCP_STAT_STRUCTURE int
267 #include <iphlpapi.h>
268 #define TCP_STAT_STRUCTURE MIB_TCPSTATS
271 #ifdef HAVE_SYS_TCPIPSTATS_H
272 #define TCP_STAT_STRUCTURE struct kna
273 #define USES_TRADITIONAL_TCPSTAT
276 #if !defined(TCP_STAT_STRUCTURE)
277 #define TCP_STAT_STRUCTURE struct tcpstat
278 #define USES_TRADITIONAL_TCPSTAT
281 long read_tcp_stat(TCP_STAT_STRUCTURE *, int);
285 var_tcp(struct variable *vp,
288 int exact, size_t * var_len, WriteMethod ** write_method)
290 static TCP_STAT_STRUCTURE tcpstat;
291 static long ret_value;
292 #ifdef TCPTV_NEEDS_HZ
294 * I don't know of any such system now, but maybe they'll figure
300 if (header_generic(vp, name, length, exact, var_len, write_method) ==
304 ret_value = read_tcp_stat(&tcpstat, vp->magic);
308 #ifdef HAVE_SYS_TCPIPSTATS_H
310 * This actually reads statistics for *all* the groups together,
311 * so we need to isolate the TCP-specific bits.
313 #define tcpstat tcpstat.tcpstat
317 #ifdef USES_SNMP_DESIGNED_TCPSTAT
318 case TCPRTOALGORITHM:
319 return (u_char *) & tcpstat.tcpRtoAlgorithm;
321 return (u_char *) & tcpstat.tcpRtoMin;
323 return (u_char *) & tcpstat.tcpRtoMax;
325 return (u_char *) & tcpstat.tcpMaxConn;
327 return (u_char *) & tcpstat.tcpActiveOpens;
328 case TCPPASSIVEOPENS:
329 return (u_char *) & tcpstat.tcpPassiveOpens;
330 case TCPATTEMPTFAILS:
331 return (u_char *) & tcpstat.tcpAttemptFails;
333 return (u_char *) & tcpstat.tcpEstabResets;
335 return (u_char *) & tcpstat.tcpCurrEstab;
337 return (u_char *) & tcpstat.tcpInSegs;
339 return (u_char *) & tcpstat.tcpOutSegs;
341 return (u_char *) & tcpstat.tcpRetransSegs;
344 return (u_char *) & ret_value;
346 if (tcpstat.tcpInErrsValid)
347 return (u_char *) & tcpstat.tcpInErrs;
354 if (tcpstat.tcpOutRstsValid)
355 return (u_char *) & tcpstat.tcpOutRsts;
362 #ifdef USES_TRADITIONAL_TCPSTAT
363 case TCPRTOALGORITHM: /* Assume Van Jacobsen's algorithm */
365 return (u_char *) & long_return;
367 #ifdef TCPTV_NEEDS_HZ
368 long_return = TCPTV_MIN;
370 long_return = TCPTV_MIN / PR_SLOWHZ * 1000;
372 return (u_char *) & long_return;
374 #ifdef TCPTV_NEEDS_HZ
375 long_return = TCPTV_REXMTMAX;
377 long_return = TCPTV_REXMTMAX / PR_SLOWHZ * 1000;
379 return (u_char *) & long_return;
383 return (u_char *) & tcpstat.tcps_connattempt;
384 case TCPPASSIVEOPENS:
385 return (u_char *) & tcpstat.tcps_accepts;
387 * NB: tcps_drops is actually the sum of the two MIB
388 * counters tcpAttemptFails and tcpEstabResets.
390 case TCPATTEMPTFAILS:
391 return (u_char *) & tcpstat.tcps_conndrops;
393 return (u_char *) & tcpstat.tcps_drops;
395 long_return = TCP_Count_Connections();
396 return (u_char *) & long_return;
398 return (u_char *) & tcpstat.tcps_rcvtotal;
401 * RFC 1213 defines this as the number of segments sent
402 * "excluding those containing only retransmitted octets"
404 long_return = tcpstat.tcps_sndtotal - tcpstat.tcps_sndrexmitpack;
405 return (u_char *) & long_return;
407 return (u_char *) & tcpstat.tcps_sndrexmitpack;
409 long_return = tcpstat.tcps_rcvbadsum + tcpstat.tcps_rcvbadoff
410 #ifdef STRUCT_TCPSTAT_HAS_TCPS_RCVMEMDROP
411 + tcpstat.tcps_rcvmemdrop
413 + tcpstat.tcps_rcvshort;
414 return (u_char *) & long_return;
416 long_return = tcpstat.tcps_sndctrl - tcpstat.tcps_closed;
417 return (u_char *) & long_return;
420 case TCPRTOALGORITHM:
421 return (u_char *) & tcpstat.dwRtoAlgorithm;
423 return (u_char *) & tcpstat.dwRtoMin;
425 return (u_char *) & tcpstat.dwRtoMax;
427 return (u_char *) & tcpstat.dwMaxConn;
429 return (u_char *) & tcpstat.dwActiveOpens;
430 case TCPPASSIVEOPENS:
431 return (u_char *) & tcpstat.dwPassiveOpens;
432 case TCPATTEMPTFAILS:
433 return (u_char *) & tcpstat.dwAttemptFails;
435 return (u_char *) & tcpstat.dwEstabResets;
437 return (u_char *) & tcpstat.dwCurrEstab;
439 return (u_char *) & tcpstat.dwInSegs;
441 return (u_char *) & tcpstat.dwOutSegs;
443 return (u_char *) & tcpstat.dwRetransSegs;
445 return (u_char *) & tcpstat.dwInErrs;
447 return (u_char *) & tcpstat.dwOutRsts;
450 DEBUGMSGTL(("snmpd", "unknown sub-id %d in var_tcp\n", vp->magic));
454 #ifdef HAVE_SYS_TCPIPSTATS_H
460 /*********************
462 * Internal implementation functions
464 *********************/
467 read_tcp_stat(TCP_STAT_STRUCTURE * tcpstat, int magic)
470 #if (defined(CAN_USE_SYSCTL) && defined(TCPCTL_STATS))
471 static int sname[4] =
472 { CTL_NET, PF_INET, IPPROTO_TCP, TCPCTL_STATS };
473 size_t len = sizeof(*tcpstat);
476 static mib2_ip_t ipstat;
484 if ((fd = open_mib("/dev/ip", O_RDONLY, 0, NM_ASYNC_OFF)) < 0)
485 return (-1); /* error */
488 case TCPRTOALGORITHM:
489 p.objid = ID_tcpRtoAlgorithm;
492 p.objid = ID_tcpRtoMin;
495 p.objid = ID_tcpRtoMax;
498 p.objid = ID_tcpMaxConn;
501 p.objid = ID_tcpActiveOpens;
503 case TCPPASSIVEOPENS:
504 p.objid = ID_tcpPassiveOpens;
506 case TCPATTEMPTFAILS:
507 p.objid = ID_tcpAttemptFails;
510 p.objid = ID_tcpEstabResets;
513 p.objid = ID_tcpCurrEstab;
516 p.objid = ID_tcpInSegs;
519 p.objid = ID_tcpOutSegs;
522 p.objid = ID_tcpRetransSegs;
525 p.objid = ID_tcpInErrs;
528 p.objid = ID_tcpOutRsts;
536 p.buffer = (void *) tcpstat;
537 ulen = sizeof(TCP_STAT_STRUCTURE);
539 ret_value = get_mib_info(fd, &p);
542 return (ret_value); /* 0: ok, < 0: error */
545 if (tcp_stats_cache_marker &&
547 (tcp_stats_cache_marker, TCP_STATS_CACHE_TIMEOUT * 1000)))
549 return (magic == TCPINERRS ? ipstat.tcpInErrs : 0);
554 if (tcp_stats_cache_marker)
555 atime_setMarker(tcp_stats_cache_marker);
557 tcp_stats_cache_marker = atime_newMarker();
560 ret_value = linux_read_tcp_stat(tcpstat);
564 if (magic == TCPINERRS) {
566 (MIB_IP, &ipstat, sizeof(mib2_ip_t), GET_FIRST,
567 &Get_everything, NULL) < 0)
570 ret_value = ipstat.tcpInErrs;
572 ret_value = getMibstat(MIB_TCP, tcpstat, sizeof(mib2_tcp_t),
573 GET_FIRST, &Get_everything, NULL);
577 ret_value = GetTcpStatistics(tcpstat);
580 #ifdef HAVE_SYS_TCPIPSTATS_H
581 ret_value = sysmp(MP_SAGET, MPSA_TCPIPSTATS, tcpstat, sizeof *tcpstat);
584 #if defined(CAN_USE_SYSCTL) && defined(TCPCTL_STATS)
585 ret_value = sysctl(sname, 4, tcpstat, &len, 0, 0);
588 #ifdef TCPSTAT_SYMBOL
589 if (auto_nlist(TCPSTAT_SYMBOL, (char *) tcpstat, sizeof(*tcpstat)))
593 if (ret_value == -1) {
594 free(tcp_stats_cache_marker);
595 tcp_stats_cache_marker = NULL;
607 #endif /* SNMP_TCP_MIB */