PERFORCE change 82477 for review
Victor Cruceru
soc-victor at FreeBSD.org
Tue Aug 23 23:21:29 GMT 2005
http://perforce.freebsd.org/chv.cgi?CH=82477
Change 82477 by soc-victor at soc-victor_82.76.158.176 on 2005/08/23 23:20:55
Finished the SNMP instrumentation for the scalars from the TCP-MIB / RFC 4022
Affected files ...
.. //depot/projects/soc2005/bsnmp/usr.sbin/bsnmpd/modules/snmp_tcp46/tcp46_snmp.c#2 edit
Differences ...
==== //depot/projects/soc2005/bsnmp/usr.sbin/bsnmpd/modules/snmp_tcp46/tcp46_snmp.c#2 (text+ko) ====
@@ -29,6 +29,42 @@
* TCP-MIB implementation for SNMPd: instrumentation for RFC 4022 covering
* both IPv4 and IPv6 objects
*/
+ /*
+ * The code for this module is based on and inspired by code developed
+ * by Harti Brandt <harti at freebsd.org> under the following copyright:
+ */
+/*
+ * Copyright (c) 2001-2003
+ * Fraunhofer Institute for Open Communication Systems (FhG Fokus).
+ * All rights reserved.
+ *
+ * Author: Harti Brandt <harti at freebsd.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Begemot: bsnmp/snmp_mibII/mibII_tcp.c,v 1.7 2005/05/23 09:03:42 brandt_h Exp $
+ *
+ * tcp
+ */
#include "asn1.h"
#include "snmp.h"
@@ -37,18 +73,31 @@
#include "tcp46_tree.h"
#include <stdio.h>
#include <syslog.h>
+#include <sys/socketvar.h>
+#include <netinet/in_pcb.h>
+#include <netinet/tcp.h>
+#include <netinet/tcp_var.h>
+#include <netinet/tcp_timer.h>
+#include <netinet/tcp_fsm.h>
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <sys/types.h>
+#include <sys/sysctl.h>
+
/*a debug macro*/
#ifndef NDEBUG
-#define TCP46_DPRINTF(ARGS) do { \
- fprintf(stderr, "TCP46_DEBUG: "); \
- fprintf ARGS; \
+#define TCP46_DPRINTF(ARGS) do { \
+ fprintf(stderr, "TCP46_DEBUG: "); \
+ fprintf ARGS; \
} while (0)
#else
#define TCP46_DPRINTF(ARGS)
#endif /*NDEBUG*/
+
/*internal id got after we'll register this module with the agent */
static
u_int tcp46_registration_id = 0;
@@ -62,6 +111,49 @@
+struct tcp_index {
+ struct asn_oid index;
+ struct xtcpcb *tp;
+};
+
+static int
+tcp_compare(const void *p1, const void *p2)
+{
+ int result = 0;
+ const struct tcp_index *t1 = p1;
+ const struct tcp_index *t2 = p2;
+ assert(t1 != NULL);
+ assert(t2 != NULL);
+ if (t1 == NULL || t2 == NULL) {
+ return 0;
+ }
+ result = asn_compare_oid(&t1->index, &t2->index);
+ if ( result == 0 ) {
+ syslog(LOG_ERR, "tcp46 malfunction: two equal oids.");
+ assert(0);
+ }
+ return result;
+}
+
+
+struct tcp46_state {
+ struct clockinfo clock_info;
+ uint64_t tcp_tick; /*agent tick when this struct was last updated*/
+ struct tcpstat tcpstat; /*holder for tcp stats*/
+ struct xinpgen *xinpgen; /*holder for data get via sysctl; malloc'd*/
+ size_t xinpgen_len; /*the allocated len of the above vector */
+ u_int tcp_estab_count; /*value for the scalar named tcpCurrEstab*/
+ u_int tcp4_total; /*the number of tcp4 entries*/
+
+ struct tcp_index *tcp4oids; /*snmp vector for the tcp4 table; malloc'd*/
+ size_t tcp4oids_len; /*the allocated len of the above vector */
+};
+
+static
+struct tcp46_state tcp46_state_g;
+
+
+
/*
* TCP mib module initialization hook.
* Returns 0 on success, < 0 on error
@@ -69,7 +161,18 @@
static
int tcp46_init(struct lmodule * mod, int argc __unused, char *argv[] __unused) {
tcp46_module = mod;
+ int len = 0;
+ memset(&tcp46_state_g, 0, sizeof(struct tcp46_state));
+ len = sizeof(tcp46_state_g.clock_info);
+ if (sysctlbyname("kern.clockrate", &tcp46_state_g.clock_info, &len, NULL, 0) == -1) {
+ syslog(LOG_ERR, "kern.clockrate: %m");
+ return (-1);
+ }
+ if (len != sizeof(tcp46_state_g.clock_info)) {
+ syslog(LOG_ERR, "kern.clockrate: wrong size");
+ return (-1);
+ }
TCP46_DPRINTF((stderr, "[%s] done.\n", __func__));
return (0);
}
@@ -80,8 +183,20 @@
*/
static
int tcp46_fini(void) {
-
- if( tcp46_registration_id > 0){
+ if (tcp46_state_g.tcp4oids != NULL && tcp46_state_g.tcp4oids_len > 0) {
+ free(tcp46_state_g.tcp4oids);
+ tcp46_state_g.tcp4oids = NULL;
+ tcp46_state_g.tcp4oids_len = 0;
+ }
+
+ if (tcp46_state_g.xinpgen != NULL && tcp46_state_g.xinpgen_len > 0) {
+ free(tcp46_state_g.xinpgen);
+ tcp46_state_g.xinpgen = NULL;
+ tcp46_state_g.xinpgen_len = 0;
+ }
+
+
+ if (tcp46_registration_id > 0) {
or_unregister(tcp46_registration_id);
}
@@ -159,14 +274,245 @@
};
-int
-op_tcp( struct snmp_context *ctx __unused,
- struct snmp_value *value __unused,
- u_int sub __unused,
- u_int iidx __unused,
- enum snmp_op curr_op __unused) {
+static int
+fetch_tcp(void)
+{
+ size_t len;
+ struct xinpgen *ptr = NULL;
+ struct xtcpcb *tp = NULL;
+ struct tcp_index *oid = NULL;
+ in_addr_t inaddr;
+
+ len = sizeof(tcp46_state_g.tcpstat);
+ if (sysctlbyname("net.inet.tcp.stats", &tcp46_state_g.tcpstat, &len, NULL, 0) == -1) {
+ syslog(LOG_ERR, "sysctlbyname(net.inet.tcp.stats) failed: %m");
+ return (-1);
+ }
+ if (len != sizeof(tcp46_state_g.tcpstat)) {
+ syslog(LOG_ERR, "sysctlbyname(net.inet.tcp.stats) error: wrong size");
+ return (-1);
+ }
+
+ len = 0;
+ if (sysctlbyname("net.inet.tcp.pcblist", NULL, &len, NULL, 0) == -1) {
+ syslog(LOG_ERR, "sysctlbyname(net.inet.tcp.pcblist) failed: %m");
+ return (-1);
+ }
+ if (len > tcp46_state_g.xinpgen_len) {
+ if ((ptr = realloc(tcp46_state_g.xinpgen, len)) == NULL) {
+ syslog(LOG_ERR, "%zu: %m", len);
+ return (-1);
+ }
+ tcp46_state_g.xinpgen = ptr;
+ tcp46_state_g.xinpgen_len = len;
+ }
+ if (sysctlbyname("net.inet.tcp.pcblist", tcp46_state_g.xinpgen, &len, NULL, 0) == -1) {
+ syslog(LOG_ERR, "sysctlbyname(net.inet.tcp.pcblist) failed: %m");
+ return (-1);
+ }
+
+ tcp46_state_g.tcp_tick = get_ticks();
+
+ tcp46_state_g.tcp_estab_count = 0;
- return (SNMP_ERR_NOSUCHNAME);
+ /*First count the endpoints*/
+ for (ptr = (struct xinpgen *)(void *)((char *)tcp46_state_g.xinpgen + tcp46_state_g.xinpgen->xig_len);
+ ptr->xig_len > sizeof(struct xinpgen);
+ ptr = (struct xinpgen *)(void *)((char *)ptr + ptr->xig_len)) {
+ tp = (struct xtcpcb *)ptr;
+ assert(ptr != NULL);
+
+ /* Ignore sockets for protocols other than the desired one. */
+ if (((struct xinpcb *)ptr)->xi_socket.xso_protocol != IPPROTO_TCP) {
+ continue;
+ }
+
+ /* Ignore PCBs which were freed during copyout. */
+ if (tp->xt_inp.inp_gencnt > tcp46_state_g.xinpgen->xig_gen ) {
+ continue;
+ }
+
+
+ if ( (tp->xt_inp.inp_vflag & INP_IPV4) == INP_IPV4) {
+ tcp46_state_g.tcp4_total++;
+ }
+
+ if (tp->xt_tp.t_state == TCPS_ESTABLISHED ||
+ tp->xt_tp.t_state == TCPS_CLOSE_WAIT) {
+ tcp46_state_g.tcp_estab_count++;
+ }
+ }
+
+ /*Then reallocate the SNMP holder if needed*/
+ if (tcp46_state_g.tcp4oids_len < tcp46_state_g.tcp4_total) {
+ oid = realloc(tcp46_state_g.tcp4oids,
+ tcp46_state_g.tcp4_total * sizeof(tcp46_state_g.tcp4oids[0]));
+ if (oid == NULL) {
+ free(tcp46_state_g.tcp4oids);
+ tcp46_state_g.tcp4oids_len = 0;
+ return (0);
+ }
+ tcp46_state_g.tcp4oids = oid;
+ tcp46_state_g.tcp4oids_len = tcp46_state_g.tcp4_total;
+ }
+
+ /*Fimally fill in the SNMP index*/
+ memset(tcp46_state_g.tcp4oids, 0,
+ tcp46_state_g.tcp4_total * sizeof(tcp46_state_g.tcp4oids[0]) );
+
+ oid = tcp46_state_g.tcp4oids;
+ for (ptr = (struct xinpgen *)(void *)((char *)tcp46_state_g.xinpgen + tcp46_state_g.xinpgen->xig_len);
+ ptr->xig_len > sizeof(struct xinpgen);
+ ptr = (struct xinpgen *)(void *)((char *)ptr + ptr->xig_len)) {
+ tp = (struct xtcpcb *)ptr;
+ assert(ptr != NULL);
+ /* Ignore sockets for protocols other than the desired one. */
+ if (((struct xinpcb *)ptr)->xi_socket.xso_protocol != IPPROTO_TCP) {
+ continue;
+ }
+
+ /* Ignore PCBs which were freed during copyout. */
+ if (tp->xt_inp.inp_gencnt > tcp46_state_g.xinpgen->xig_gen ) {
+ continue;
+ }
+ if ( (tp->xt_inp.inp_vflag & INP_IPV4) == INP_IPV4) {
+ oid->tp = tp;
+ oid->index.len = 10;
+ inaddr = ntohl(tp->xt_inp.inp_laddr.s_addr);
+ oid->index.subs[0] = (inaddr >> 24) & 0xff;
+ oid->index.subs[1] = (inaddr >> 16) & 0xff;
+ oid->index.subs[2] = (inaddr >> 8) & 0xff;
+ oid->index.subs[3] = (inaddr >> 0) & 0xff;
+ oid->index.subs[4] = ntohs(tp->xt_inp.inp_lport);
+ inaddr = ntohl(tp->xt_inp.inp_faddr.s_addr);
+ oid->index.subs[5] = (inaddr >> 24) & 0xff;
+ oid->index.subs[6] = (inaddr >> 16) & 0xff;
+ oid->index.subs[7] = (inaddr >> 8) & 0xff;
+ oid->index.subs[8] = (inaddr >> 0) & 0xff;
+ oid->index.subs[9] = ntohs(tp->xt_inp.inp_fport);
+ oid++;
+ }
+ }
+
+ /*Keep the list sorted ins SNMP index ordering*/
+ qsort( tcp46_state_g.tcp4oids,
+ tcp46_state_g.tcp4_total,
+ sizeof(tcp46_state_g.tcp4oids),
+ tcp_compare);
+
+ return (0);
+}
+
+
+/*
+ * Scalars
+ */
+int
+op_tcp(struct snmp_context *ctx __unused, struct snmp_value *value,
+ u_int sub, u_int iidx __unused, enum snmp_op op)
+{
+ switch (op) {
+
+ case SNMP_OP_GETNEXT:{
+ assert(0);
+ return (SNMP_ERR_GENERR);
+ }
+
+ case SNMP_OP_GET:
+ break;
+
+ case SNMP_OP_SET:
+ return (SNMP_ERR_NOT_WRITEABLE);
+
+ case SNMP_OP_ROLLBACK:
+ case SNMP_OP_COMMIT: {
+ assert(0);
+ return (SNMP_ERR_NOERROR);
+
+ }
+ }
+
+ if (tcp46_state_g.tcp_tick < this_tick)
+ if (fetch_tcp() == -1)
+ return (SNMP_ERR_GENERR);
+
+ switch (value->var.subs[sub - 1]) {
+
+ case LEAF_tcpRtoAlgorithm:
+ value->v.integer = 4; /* Van Jacobson */
+ break;
+
+#define hz (tcp46_state_g.clock_info.hz)
+
+ case LEAF_tcpRtoMin:
+ value->v.integer = 1000 * TCPTV_MIN / hz;
+ break;
+
+ case LEAF_tcpRtoMax:
+ value->v.integer = 1000 * TCPTV_REXMTMAX / hz;
+ break;
+#undef hz
+ case LEAF_tcpMaxConn:
+ value->v.integer = -1;
+ break;
+
+ case LEAF_tcpActiveOpens:
+ value->v.uint32 = tcp46_state_g.tcpstat.tcps_connattempt;
+ break;
+
+ case LEAF_tcpPassiveOpens:
+ value->v.uint32 = tcp46_state_g.tcpstat.tcps_accepts;
+ break;
+
+ case LEAF_tcpAttemptFails:
+ value->v.uint32 = tcp46_state_g.tcpstat.tcps_conndrops;
+ break;
+
+ case LEAF_tcpEstabResets:
+ value->v.uint32 = tcp46_state_g.tcpstat.tcps_drops;
+ break;
+
+ case LEAF_tcpCurrEstab:
+ value->v.uint32 = tcp46_state_g.tcp_estab_count;
+ break;
+
+ case LEAF_tcpInSegs:
+ value->v.uint32 = tcp46_state_g.tcpstat.tcps_rcvtotal;
+ break;
+
+ case LEAF_tcpOutSegs:
+ value->v.uint32 = tcp46_state_g.tcpstat.tcps_sndtotal -
+ tcp46_state_g.tcpstat.tcps_sndrexmitpack;
+ break;
+
+ case LEAF_tcpRetransSegs:
+ value->v.uint32 = tcp46_state_g.tcpstat.tcps_sndrexmitpack;
+ break;
+
+ case LEAF_tcpInErrs:
+ value->v.uint32 = tcp46_state_g.tcpstat.tcps_rcvbadsum +
+ tcp46_state_g.tcpstat.tcps_rcvbadoff +
+ tcp46_state_g.tcpstat.tcps_rcvshort;
+ break;
+
+ case LEAF_tcpOutRsts:
+ value->v.uint32 = 0;
+ break;
+
+ case LEAF_tcpHCInSegs:
+ value->v.counter64 = tcp46_state_g.tcpstat.tcps_rcvtotal;
+ break;
+
+ case LEAF_tcpHCOutSegs:
+ value->v.counter64 = tcp46_state_g.tcpstat.tcps_sndtotal -
+ tcp46_state_g.tcpstat.tcps_sndrexmitpack;
+ break;
+
+ default :
+ assert(0);
+ return (SNMP_ERR_NOSUCHNAME);
+ }
+ return (SNMP_ERR_NOERROR);
}
int
More information about the p4-projects
mailing list