Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 23 Aug 2005 23:21:28 GMT
From:      Victor Cruceru <soc-victor@FreeBSD.org>
To:        Perforce Change Reviews <perforce@freebsd.org>
Subject:   PERFORCE change 82477 for review
Message-ID:  <200508232321.j7NNLSXA077611@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=82477

Change 82477 by soc-victor@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@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@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	



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200508232321.j7NNLSXA077611>