From owner-p4-projects@FreeBSD.ORG Tue Aug 23 23:21:29 2005 Return-Path: X-Original-To: p4-projects@freebsd.org Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id 120B616A421; Tue, 23 Aug 2005 23:21:29 +0000 (GMT) X-Original-To: perforce@freebsd.org Delivered-To: perforce@freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id C596E16A41F for ; Tue, 23 Aug 2005 23:21:28 +0000 (GMT) (envelope-from soc-victor@freebsd.org) Received: from repoman.freebsd.org (repoman.freebsd.org [216.136.204.115]) by mx1.FreeBSD.org (Postfix) with ESMTP id 7242043D49 for ; Tue, 23 Aug 2005 23:21:28 +0000 (GMT) (envelope-from soc-victor@freebsd.org) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.13.1/8.13.1) with ESMTP id j7NNLSVo077614 for ; Tue, 23 Aug 2005 23:21:28 GMT (envelope-from soc-victor@freebsd.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.13.1/8.13.1/Submit) id j7NNLSXA077611 for perforce@freebsd.org; Tue, 23 Aug 2005 23:21:28 GMT (envelope-from soc-victor@freebsd.org) Date: Tue, 23 Aug 2005 23:21:28 GMT Message-Id: <200508232321.j7NNLSXA077611@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to soc-victor@freebsd.org using -f From: Victor Cruceru To: Perforce Change Reviews Cc: Subject: PERFORCE change 82477 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 23 Aug 2005 23:21:29 -0000 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 under the following copyright: + */ +/* + * Copyright (c) 2001-2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Author: Harti Brandt + * + * 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 #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + /*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