Home | History | Annotate | Line # | Download | only in netstat
vtw.c revision 1.7
      1 /*	$NetBSD: vtw.c,v 1.7 2013/10/18 20:26:45 christos 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.7 2013/10/18 20:26:45 christos 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 %zx cc %zx\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 void
    171 timebase(struct timeval *tv)
    172 {
    173 	void *p;
    174 	struct bintime timebasebin;
    175 
    176 	p = lookup("timebasebin");
    177 	if (!p)
    178 		return;
    179 	snarf(p, &timebasebin, sizeof(timebasebin));
    180 	bintime2timeval(&timebasebin, tv);
    181 }
    182 
    183 static void
    184 process_vtw(const vtw_ctl_t * ctl, void (*print)(const vtw_t *))
    185 {
    186 	vtw_t *vp;
    187 
    188 	for (vp = ctl->base.v; vp && vp <= ctl->lim.v;) {
    189 
    190 		(*print)(vp);
    191 
    192 		if (ctl->is_v4) {
    193 			vtw_v4_t *v4 = (vtw_v4_t *)vp;
    194 
    195 			vp = &(++v4)->common;
    196 		} else if (ctl->is_v6) {
    197 			vtw_v6_t *v6 = (vtw_v6_t *)vp;
    198 
    199 			vp = &(++v6)->common;
    200 		}
    201 	}
    202 }
    203 
    204 void
    205 show_vtw_stats(void)
    206 {
    207 	vtw_stats_t stats;
    208 	void *p;
    209 
    210 	if (!Vflag)
    211 		return;
    212 
    213 	if ((p = lookup("vtw_stats")) == NULL)
    214 		return;
    215 	snarf(p, &stats, sizeof(stats));
    216 
    217 	printf("\t\t%" PRIu64 " inserts\n", stats.ins);
    218 	printf("\t\t%" PRIu64 " deletes\n", stats.del);
    219 	printf("\t\t%" PRIu64 " assassinations\n", stats.kill);
    220 	printf("\tvestigial time-wait lookup_connect\n");
    221 	printf("\t\t%" PRIu64 " look\n", stats.look[0]);
    222 	printf("\t\t%" PRIu64 " hit\n", stats.hit[0]);
    223 	printf("\t\t%" PRIu64 " miss\n", stats.miss[0]);
    224 	printf("\t\t%" PRIu64 " probe\n", stats.probe[0]);
    225 	printf("\t\t%" PRIu64 " losing\n", stats.losing[0]);
    226 	printf("\t\t%" PRIu64 " max_chain\n", stats.max_chain[0]);
    227 	printf("\t\t%" PRIu64 " max_probe\n", stats.max_probe[0]);
    228 	printf("\t\t%" PRIu64 " max_loss\n", stats.max_loss[0]);
    229 	printf("\tvestigial time-wait lookup_port\n");
    230 	printf("\t\t%" PRIu64 " look\n", stats.look[1]);
    231 	printf("\t\t%" PRIu64 " hit\n", stats.hit[1]);
    232 	printf("\t\t%" PRIu64 " miss\n", stats.miss[1]);
    233 	printf("\t\t%" PRIu64 " probe\n", stats.probe[1]);
    234 	printf("\t\t%" PRIu64 " losing\n", stats.losing[1]);
    235 	printf("\t\t%" PRIu64 " max_chain\n", stats.max_chain[1]);
    236 	printf("\t\t%" PRIu64 " max_probe\n", stats.max_probe[1]);
    237 	printf("\t\t%" PRIu64 " max_loss\n", stats.max_loss[1]);
    238 }
    239 
    240 void
    241 show_vtw_v4(void (*print)(const vtw_t *))
    242 {
    243 	fatp_t *base, *lim;
    244 	fatp_t **hash, **port;
    245 	size_t n;
    246 	fatp_ctl_t fat_tcpv4;
    247 	vtw_ctl_t  vtw_tcpv4[VTW_NCLASS];
    248 	int i;
    249 	int mem = 0;
    250 	void *p;
    251 
    252 	if ((p = lookup("fat_tcpv4")) == NULL)
    253 		return;
    254 	snarf(p, &fat_tcpv4, sizeof(fat_tcpv4));
    255 
    256 	if ((p = lookup("vtw_tcpv4")) == NULL)
    257 		return;
    258 	snarf(p, &vtw_tcpv4[0], sizeof(vtw_tcpv4));
    259 
    260 	mem += sizeof(fat_tcpv4);
    261 	mem += sizeof(vtw_tcpv4);
    262 
    263 	/* snarf/adjust vtw_ctl */
    264 	for (i = 0; i < VTW_NCLASS; ++i) {
    265 		vtw_v4_t *kbase, *klim;
    266 		vtw_v4_t *ubase;
    267 		ptrdiff_t delta;
    268 
    269 		kbase = vtw_tcpv4[i].base.v4;
    270 		klim = vtw_tcpv4[i].lim.v4;
    271 
    272 		if (!kbase | !klim)
    273 			continue;
    274 
    275 		n = (klim - kbase + 1);
    276 
    277 		if (!i) {
    278 			if ((ubase = malloc(n * sizeof(*kbase))) == NULL)
    279 				err(EXIT_FAILURE, NULL);
    280 			snarf(kbase, ubase, n * sizeof(*ubase));
    281 
    282 			mem += n * sizeof(*ubase);
    283 		} else {
    284 			ubase = vtw_tcpv4[0].base.v4;
    285 		}
    286 
    287 		delta = ubase - kbase;
    288 
    289 		vtw_tcpv4[i].base.v4 += delta;
    290 		vtw_tcpv4[i].lim.v4 += delta;
    291 		vtw_tcpv4[i].alloc.v4 += delta;
    292 		vtw_tcpv4[i].fat = &fat_tcpv4;
    293 
    294 		if (vtw_tcpv4[i].oldest.v4)
    295 			vtw_tcpv4[i].oldest.v4 += delta;
    296 	}
    297 
    298 	/* snarf/adjust fat_ctl */
    299 
    300 	base = fat_tcpv4.base;
    301 	lim = fat_tcpv4.lim;
    302 
    303 	if (!base | !lim)
    304 		goto end;
    305 
    306 	mem += (lim - base + 1) * sizeof(*base);
    307 
    308 	fat_tcpv4.base = malloc((lim - base + 1) * sizeof(*base));
    309 	if (fat_tcpv4.base == NULL)
    310 		err(EXIT_FAILURE, NULL);
    311 	fat_tcpv4.lim = fat_tcpv4.base + (lim - base);
    312 
    313 	snarf(base, fat_tcpv4.base, sizeof(*base) * (lim - base + 1));
    314 
    315 	fat_tcpv4.vtw = &vtw_tcpv4[0];
    316 	fat_tcpv4.free = fat_tcpv4.base + (fat_tcpv4.free - base);
    317 
    318 	n = fat_tcpv4.mask + 1;
    319 	hash = fat_tcpv4.hash;
    320 	port = fat_tcpv4.port;
    321 
    322 	fat_tcpv4.hash = malloc(n * sizeof(*hash));
    323 	fat_tcpv4.port = malloc(n * sizeof(*port));
    324 	if (fat_tcpv4.hash == NULL || fat_tcpv4.port == NULL)
    325 		err(EXIT_FAILURE, NULL);
    326 
    327 	snarf(hash, fat_tcpv4.hash, n * sizeof(*hash));
    328 	snarf(port, fat_tcpv4.port, n * sizeof(*port));
    329 
    330 end:
    331 	process_vtw(&vtw_tcpv4[0], print);
    332 
    333 #if 0
    334 	if (Vflag && vflag) {
    335 		printf("total memory for VTW in current config: %d bytes %f MB\n"
    336 		    ,mem
    337 		    ,mem / (1024.0 * 1024));
    338 	}
    339 #endif
    340 }
    341 
    342 void
    343 show_vtw_v6(void (*print)(const vtw_t *))
    344 {
    345 	fatp_t *base, *lim;
    346 	fatp_t **hash, **port;
    347 	size_t n;
    348 	fatp_ctl_t fat_tcpv6;
    349 	vtw_ctl_t  vtw_tcpv6[VTW_NCLASS];
    350 	int i;
    351 	int mem = 0;
    352 	void *p;
    353 
    354 	if ((p = lookup("fat_tcpv6")) == NULL)
    355 		return;
    356 	snarf(p, &fat_tcpv6, sizeof(fat_tcpv6));
    357 	if ((p = lookup("vtw_tcpv6")) == NULL)
    358 		return;
    359 	snarf(p, &vtw_tcpv6[0], sizeof(vtw_tcpv6));
    360 
    361 	mem += sizeof(fat_tcpv6);
    362 	mem += sizeof(vtw_tcpv6);
    363 
    364 	for (i = 0; i < VTW_NCLASS; ++i) {
    365 		vtw_v6_t *kbase, *klim;
    366 		vtw_v6_t *ubase;
    367 		ptrdiff_t delta;
    368 
    369 		kbase = vtw_tcpv6[i].base.v6;
    370 		klim = vtw_tcpv6[i].lim.v6;
    371 
    372 		if (!kbase | !klim)
    373 			continue;
    374 
    375 		n = (klim - kbase + 1);
    376 
    377 		if (!i) {
    378 			if ((ubase = malloc(n * sizeof(*kbase))) == NULL)
    379 				err(EXIT_FAILURE, NULL);
    380 
    381 			snarf(kbase, ubase, n * sizeof(*ubase));
    382 
    383 			mem += n * sizeof(*ubase);
    384 		} else {
    385 			ubase = vtw_tcpv6[0].base.v6;
    386 		}
    387 
    388 		delta = ubase - kbase;
    389 
    390 		vtw_tcpv6[i].base.v6 += delta;
    391 		vtw_tcpv6[i].lim.v6 += delta;
    392 		vtw_tcpv6[i].alloc.v6 += delta;
    393 		vtw_tcpv6[i].fat = &fat_tcpv6;
    394 
    395 		if (vtw_tcpv6[i].oldest.v6)
    396 			vtw_tcpv6[i].oldest.v6 += delta;
    397 	}
    398 
    399 	base = fat_tcpv6.base;
    400 	lim = fat_tcpv6.lim;
    401 
    402 	if (!base | !lim)
    403 		goto end;
    404 
    405 	mem += (lim - base + 1) * sizeof(*base);
    406 
    407 	fat_tcpv6.base = malloc((lim - base + 1) * sizeof(*base));
    408 	if (fat_tcpv6.base == NULL)
    409 		err(EXIT_FAILURE, NULL);
    410 	fat_tcpv6.lim = fat_tcpv6.base + (lim - base);
    411 
    412 	snarf(base, fat_tcpv6.base, sizeof(*base) * (lim - base + 1));
    413 
    414 	fat_tcpv6.vtw = &vtw_tcpv6[0];
    415 	fat_tcpv6.free = fat_tcpv6.base + (fat_tcpv6.free - base);
    416 
    417 	n = fat_tcpv6.mask + 1;
    418 	hash = fat_tcpv6.hash;
    419 	port = fat_tcpv6.port;
    420 
    421 	fat_tcpv6.hash = malloc(n * sizeof(*hash));
    422 	fat_tcpv6.port = malloc(n * sizeof(*port));
    423 	if (fat_tcpv6.hash == NULL || fat_tcpv6.port == NULL)
    424 		err(EXIT_FAILURE, NULL);
    425 
    426 	snarf(hash, fat_tcpv6.hash, n * sizeof(*hash));
    427 	snarf(port, fat_tcpv6.port, n * sizeof(*port));
    428 
    429 end:
    430 
    431 	process_vtw(&vtw_tcpv6[0], print);
    432 #if 0
    433 	if (Vflag && vflag) {
    434 		printf("total memory for VTW in current config: %d bytes %f MB\n"
    435 		    ,mem
    436 		    ,mem / (1024.0 * 1024));
    437 	}
    438 #endif
    439 }
    440