Home | History | Annotate | Line # | Download | only in netstat
vtw.c revision 1.1
      1 /*	$NetBSD: vtw.c,v 1.1 2011/05/03 18:28:46 dyoung Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 2011 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Coyote Point Systems, Inc.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29  * POSSIBILITY OF SUCH DAMAGE.
     30  */
     31 /*
     32  * Copyright (c) 1983, 1988, 1993
     33  *	The Regents of the University of California.  All rights reserved.
     34  *
     35  * Redistribution and use in source and binary forms, with or without
     36  * modification, are permitted provided that the following conditions
     37  * are met:
     38  * 1. Redistributions of source code must retain the above copyright
     39  *    notice, this list of conditions and the following disclaimer.
     40  * 2. Redistributions in binary form must reproduce the above copyright
     41  *    notice, this list of conditions and the following disclaimer in the
     42  *    documentation and/or other materials provided with the distribution.
     43  * 3. Neither the name of the University nor the names of its contributors
     44  *    may be used to endorse or promote products derived from this software
     45  *    without specific prior written permission.
     46  *
     47  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     48  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     49  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     50  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     51  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     52  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     53  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     54  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     55  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     56  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     57  * SUCH DAMAGE.
     58  */
     59 
     60 #include <sys/cdefs.h>
     61 #ifndef lint
     62 #if 0
     63 static char sccsid[] = "from: @(#)inet.c	8.4 (Berkeley) 4/20/94";
     64 #else
     65 __RCSID("$NetBSD: vtw.c,v 1.1 2011/05/03 18:28:46 dyoung Exp $");
     66 #endif
     67 #endif /* not lint */
     68 
     69 #define	_CALLOUT_PRIVATE	/* for defs in sys/callout.h */
     70 
     71 #include <sys/param.h>
     72 #include <sys/queue.h>
     73 #include <sys/socket.h>
     74 #include <sys/socketvar.h>
     75 #include <sys/mbuf.h>
     76 #include <sys/protosw.h>
     77 #include <sys/sysctl.h>
     78 
     79 #include <net/if_arp.h>
     80 #include <net/route.h>
     81 #include <netinet/in.h>
     82 #include <netinet/in_systm.h>
     83 #include <netinet/ip.h>
     84 #include <netinet/in_pcb.h>
     85 #include <netinet/ip_icmp.h>
     86 
     87 #ifdef INET6
     88 #include <netinet/ip6.h>
     89 #endif
     90 
     91 #include <netinet/icmp_var.h>
     92 #include <netinet/igmp_var.h>
     93 #include <netinet/ip_var.h>
     94 #include <netinet/pim_var.h>
     95 #include <netinet/tcp.h>
     96 #include <netinet/tcpip.h>
     97 #include <netinet/tcp_seq.h>
     98 #include <netinet/tcp_fsm.h>
     99 #include <netinet/tcp_timer.h>
    100 #include <netinet/tcp_var.h>
    101 #include <netinet/tcp_debug.h>
    102 #include <netinet/udp.h>
    103 #include <netinet/ip_carp.h>
    104 #include <netinet/udp_var.h>
    105 #include <netinet/tcp_vtw.h>
    106 
    107 #include <arpa/inet.h>
    108 #include <kvm.h>
    109 #include <netdb.h>
    110 #include <stdio.h>
    111 #include <string.h>
    112 #include <unistd.h>
    113 #include <stdlib.h>
    114 #include <err.h>
    115 #include "netstat.h"
    116 #include "vtw.h"
    117 #include "prog_ops.h"
    118 
    119 static void	snarf(const void *, void *, size_t);
    120 static void	*lookup(const char *);
    121 static void	process_vtw(const vtw_ctl_t *, void (*)(const vtw_t *));
    122 
    123 static void
    124 snarf(const void *addr, void *buf, size_t len)
    125 {
    126 	size_t cc;
    127 
    128 	memset(buf, 0, len);
    129 
    130 	cc = kvm_read(get_kvmd(), (unsigned long) addr, buf, len);
    131 
    132 	if (cc != len) {
    133 		warnx("%s: short read at %p, len %x cc %x\n", __func__, addr,
    134 		    len, cc);
    135 	}
    136 }
    137 
    138 static void *
    139 lookup(const char *name)
    140 {
    141 	kvm_t *k;
    142 	struct nlist nl[2];
    143 
    144 	nl[0].n_name = name;
    145 	nl[0].n_value = 0;
    146 	nl[1].n_name = NULL;
    147 
    148 	if ((k = get_kvmd()) == NULL) {
    149 		if (Vflag)
    150 			errx(EXIT_FAILURE, "kvm not available");
    151 		return NULL;
    152 	}
    153 	switch (kvm_nlist(k, &nl[0])) {
    154 	case -1:
    155 		err(EXIT_FAILURE, "kvm_nlist");
    156 		break;
    157 
    158 	case 0:
    159 		return (void *)nl[0].n_value;
    160 
    161 	default:
    162 		if (Vflag)
    163 			errx(EXIT_FAILURE, "%s missing in symbol table", name);
    164 		break;
    165 	}
    166 
    167 	return NULL;
    168 }
    169 
    170 static void
    171 process_vtw(const vtw_ctl_t * ctl, void (*print)(const vtw_t *))
    172 {
    173 	vtw_t *vp;
    174 
    175 	for (vp = ctl->base.v; vp && vp <= ctl->lim.v;) {
    176 
    177 		(*print)(vp);
    178 
    179 		if (ctl->is_v4) {
    180 			vtw_v4_t *v4 = (vtw_v4_t *)vp;
    181 
    182 			vp = &(++v4)->common;
    183 		} else if (ctl->is_v6) {
    184 			vtw_v6_t *v6 = (vtw_v6_t *)vp;
    185 
    186 			vp = &(++v6)->common;
    187 		}
    188 	}
    189 }
    190 
    191 void
    192 show_vtw_stats(void)
    193 {
    194 	vtw_stats_t stats;
    195 	void *p;
    196 
    197 	if (!Vflag)
    198 		return;
    199 
    200 	if ((p = lookup("vtw_stats")) == NULL)
    201 		return;
    202 	snarf(p, &stats, sizeof(stats));
    203 
    204 	printf("\t\t%" PRIu64 " inserts\n", stats.ins);
    205 	printf("\t\t%" PRIu64 " deletes\n", stats.del);
    206 	printf("\t\t%" PRIu64 " assassinations\n", stats.kill);
    207 	printf("\tvestigial time-wait lookup_connect\n");
    208 	printf("\t\t%" PRIu64 " look\n", stats.look[0]);
    209 	printf("\t\t%" PRIu64 " hit\n", stats.hit[0]);
    210 	printf("\t\t%" PRIu64 " miss\n", stats.miss[0]);
    211 	printf("\t\t%" PRIu64 " probe\n", stats.probe[0]);
    212 	printf("\t\t%" PRIu64 " losing\n", stats.losing[0]);
    213 	printf("\t\t%" PRIu64 " max_chain\n", stats.max_chain[0]);
    214 	printf("\t\t%" PRIu64 " max_probe\n", stats.max_probe[0]);
    215 	printf("\t\t%" PRIu64 " max_loss\n", stats.max_loss[0]);
    216 	printf("\tvestigial time-wait lookup_port\n");
    217 	printf("\t\t%" PRIu64 " look\n", stats.look[1]);
    218 	printf("\t\t%" PRIu64 " hit\n", stats.hit[1]);
    219 	printf("\t\t%" PRIu64 " miss\n", stats.miss[1]);
    220 	printf("\t\t%" PRIu64 " probe\n", stats.probe[1]);
    221 	printf("\t\t%" PRIu64 " losing\n", stats.losing[1]);
    222 	printf("\t\t%" PRIu64 " max_chain\n", stats.max_chain[1]);
    223 	printf("\t\t%" PRIu64 " max_probe\n", stats.max_probe[1]);
    224 	printf("\t\t%" PRIu64 " max_loss\n", stats.max_loss[1]);
    225 }
    226 
    227 void
    228 show_vtw_v4(void (*print)(const vtw_t *))
    229 {
    230 	fatp_t *base, *lim;
    231 	fatp_t **hash, **port;
    232 	size_t n;
    233 	fatp_ctl_t fat_tcpv4;
    234 	vtw_ctl_t  vtw_tcpv4[VTW_NCLASS];
    235 	int i;
    236 	int mem = 0;
    237 	void *p;
    238 
    239 	if ((p = lookup("fat_tcpv4")) == NULL)
    240 		return;
    241 	snarf(p, &fat_tcpv4, sizeof(fat_tcpv4));
    242 
    243 	if ((p = lookup("vtw_tcpv4")) == NULL)
    244 		return;
    245 	snarf(p, &vtw_tcpv4[0], sizeof(vtw_tcpv4));
    246 
    247 	mem += sizeof(fat_tcpv4);
    248 	mem += sizeof(vtw_tcpv4);
    249 
    250 	/* snarf/adjust vtw_ctl */
    251 	for (i = 0; i < VTW_NCLASS; ++i) {
    252 		vtw_v4_t *kbase, *klim;
    253 		vtw_v4_t *ubase, *ulim;
    254 		int delta;
    255 
    256 		kbase = vtw_tcpv4[i].base.v4;
    257 		klim = vtw_tcpv4[i].lim.v4;
    258 
    259 		if (!kbase | !klim)
    260 			continue;
    261 
    262 		n = (klim - kbase + 1);
    263 
    264 		if (!i) {
    265 			if ((ubase = malloc(n * sizeof(*kbase))) == NULL)
    266 				err(EXIT_FAILURE, NULL);
    267 			ulim = ubase + n - 1;
    268 
    269 			snarf(kbase, ubase, n * sizeof(*ubase));
    270 
    271 			mem += n * sizeof(*ubase);
    272 		} else {
    273 			ubase = vtw_tcpv4[0].base.v4;
    274 			ulim = vtw_tcpv4[0].lim.v4;
    275 		}
    276 
    277 		delta = ubase - kbase;
    278 
    279 		vtw_tcpv4[i].base.v4 += delta;
    280 		vtw_tcpv4[i].lim.v4 += delta;
    281 		vtw_tcpv4[i].alloc.v4 += delta;
    282 		vtw_tcpv4[i].fat = &fat_tcpv4;
    283 
    284 		if (vtw_tcpv4[i].oldest.v4)
    285 			vtw_tcpv4[i].oldest.v4 += delta;
    286 	}
    287 
    288 	/* snarf/adjust fat_ctl */
    289 
    290 	base = fat_tcpv4.base;
    291 	lim = fat_tcpv4.lim;
    292 
    293 	if (!base | !lim)
    294 		goto end;
    295 
    296 	mem += (lim - base + 1) * sizeof(*base);
    297 
    298 	fat_tcpv4.base = malloc((lim - base + 1) * sizeof(*base));
    299 	if (fat_tcpv4.base == NULL)
    300 		err(EXIT_FAILURE, NULL);
    301 	fat_tcpv4.lim = fat_tcpv4.base + (lim - base);
    302 
    303 	snarf(base, fat_tcpv4.base, sizeof(*base) * (lim - base + 1));
    304 
    305 	fat_tcpv4.vtw = &vtw_tcpv4[0];
    306 	fat_tcpv4.free = fat_tcpv4.base + (fat_tcpv4.free - base);
    307 
    308 	n = fat_tcpv4.mask + 1;
    309 	hash = fat_tcpv4.hash;
    310 	port = fat_tcpv4.port;
    311 
    312 	fat_tcpv4.hash = malloc(n * sizeof(*hash));
    313 	fat_tcpv4.port = malloc(n * sizeof(*port));
    314 	if (fat_tcpv4.hash == NULL || fat_tcpv4.port == NULL)
    315 		err(EXIT_FAILURE, NULL);
    316 
    317 	snarf(hash, fat_tcpv4.hash, n * sizeof(*hash));
    318 	snarf(port, fat_tcpv4.port, n * sizeof(*port));
    319 
    320 end:
    321 	process_vtw(&vtw_tcpv4[0], print);
    322 
    323 #if 0
    324 	if (Vflag && vflag) {
    325 		printf("total memory for VTW in current config: %d bytes %f MB\n"
    326 		    ,mem
    327 		    ,mem / (1024.0 * 1024));
    328 	}
    329 #endif
    330 }
    331 
    332 void
    333 show_vtw_v6(void (*print)(const vtw_t *))
    334 {
    335 	fatp_t *base, *lim;
    336 	fatp_t **hash, **port;
    337 	size_t n;
    338 	fatp_ctl_t fat_tcpv6;
    339 	vtw_ctl_t  vtw_tcpv6[VTW_NCLASS];
    340 	int i;
    341 	int mem = 0;
    342 	void *p;
    343 
    344 	if ((p = lookup("fat_tcpv6")) == NULL)
    345 		return;
    346 	snarf(p, &fat_tcpv6, sizeof(fat_tcpv6));
    347 	if ((p = lookup("vtw_tcpv6")) == NULL)
    348 		return;
    349 	snarf(p, &vtw_tcpv6[0], sizeof(vtw_tcpv6));
    350 
    351 	mem += sizeof(fat_tcpv6);
    352 	mem += sizeof(vtw_tcpv6);
    353 
    354 	for (i = 0; i < VTW_NCLASS; ++i) {
    355 		vtw_v6_t *kbase, *klim;
    356 		vtw_v6_t *ubase, *ulim;
    357 		int delta;
    358 
    359 		kbase = vtw_tcpv6[i].base.v6;
    360 		klim = vtw_tcpv6[i].lim.v6;
    361 
    362 		if (!kbase | !klim)
    363 			continue;
    364 
    365 		n = (klim - kbase + 1);
    366 
    367 		if (!i) {
    368 			if ((ubase = malloc(n * sizeof(*kbase))) == NULL)
    369 				err(EXIT_FAILURE, NULL);
    370 			ulim = ubase + n - 1;
    371 
    372 			snarf(kbase, ubase, n * sizeof(*ubase));
    373 
    374 			mem += n * sizeof(*ubase);
    375 		} else {
    376 			ubase = vtw_tcpv6[0].base.v6;
    377 			ulim = vtw_tcpv6[0].lim.v6;
    378 		}
    379 
    380 		delta = ubase - kbase;
    381 
    382 		vtw_tcpv6[i].base.v6 += delta;
    383 		vtw_tcpv6[i].lim.v6 += delta;
    384 		vtw_tcpv6[i].alloc.v6 += delta;
    385 		vtw_tcpv6[i].fat = &fat_tcpv6;
    386 
    387 		if (vtw_tcpv6[i].oldest.v6)
    388 			vtw_tcpv6[i].oldest.v6 += delta;
    389 	}
    390 
    391 	base = fat_tcpv6.base;
    392 	lim = fat_tcpv6.lim;
    393 
    394 	if (!base | !lim)
    395 		goto end;
    396 
    397 	mem += (lim - base + 1) * sizeof(*base);
    398 
    399 	fat_tcpv6.base = malloc((lim - base + 1) * sizeof(*base));
    400 	if (fat_tcpv6.base == NULL)
    401 		err(EXIT_FAILURE, NULL);
    402 	fat_tcpv6.lim = fat_tcpv6.base + (lim - base);
    403 
    404 	snarf(base, fat_tcpv6.base, sizeof(*base) * (lim - base + 1));
    405 
    406 	fat_tcpv6.vtw = &vtw_tcpv6[0];
    407 	fat_tcpv6.free = fat_tcpv6.base + (fat_tcpv6.free - base);
    408 
    409 	n = fat_tcpv6.mask + 1;
    410 	hash = fat_tcpv6.hash;
    411 	port = fat_tcpv6.port;
    412 
    413 	fat_tcpv6.hash = malloc(n * sizeof(*hash));
    414 	fat_tcpv6.port = malloc(n * sizeof(*port));
    415 	if (fat_tcpv6.hash == NULL || fat_tcpv6.port == NULL)
    416 		err(EXIT_FAILURE, NULL);
    417 
    418 	snarf(hash, fat_tcpv6.hash, n * sizeof(*hash));
    419 	snarf(port, fat_tcpv6.port, n * sizeof(*port));
    420 
    421 end:
    422 
    423 	process_vtw(&vtw_tcpv6[0], print);
    424 #if 0
    425 	if (Vflag && vflag) {
    426 		printf("total memory for VTW in current config: %d bytes %f MB\n"
    427 		    ,mem
    428 		    ,mem / (1024.0 * 1024));
    429 	}
    430 #endif
    431 }
    432