1/* $NetBSD: vtw.c,v 1.5 2011/05/10 04:40:16 enami 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 63static char sccsid[] = "from: @(#)inet.c 8.4 (Berkeley) 4/20/94"; 64#else 65__RCSID("$NetBSD: vtw.c,v 1.5 2011/05/10 04:40:16 enami 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 119static void snarf(const void *, void *, size_t); 120static void *lookup(const char *); 121static void process_vtw(const vtw_ctl_t *, void (*)(const vtw_t *)); 122 123static void 124snarf(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 138static void * 139lookup(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 170void 171timebase(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 183static void 184process_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 204void 205show_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 240void 241show_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, *ulim; 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 ulim = ubase + n - 1; 281 282 snarf(kbase, ubase, n * sizeof(*ubase)); 283 284 mem += n * sizeof(*ubase); 285 } else { 286 ubase = vtw_tcpv4[0].base.v4; 287 ulim = vtw_tcpv4[0].lim.v4; 288 } 289 290 delta = ubase - kbase; 291 292 vtw_tcpv4[i].base.v4 += delta; 293 vtw_tcpv4[i].lim.v4 += delta; 294 vtw_tcpv4[i].alloc.v4 += delta; 295 vtw_tcpv4[i].fat = &fat_tcpv4; 296 297 if (vtw_tcpv4[i].oldest.v4) 298 vtw_tcpv4[i].oldest.v4 += delta; 299 } 300 301 /* snarf/adjust fat_ctl */ 302 303 base = fat_tcpv4.base; 304 lim = fat_tcpv4.lim; 305 306 if (!base | !lim) 307 goto end; 308 309 mem += (lim - base + 1) * sizeof(*base); 310 311 fat_tcpv4.base = malloc((lim - base + 1) * sizeof(*base)); 312 if (fat_tcpv4.base == NULL) 313 err(EXIT_FAILURE, NULL); 314 fat_tcpv4.lim = fat_tcpv4.base + (lim - base); 315 316 snarf(base, fat_tcpv4.base, sizeof(*base) * (lim - base + 1)); 317 318 fat_tcpv4.vtw = &vtw_tcpv4[0]; 319 fat_tcpv4.free = fat_tcpv4.base + (fat_tcpv4.free - base); 320 321 n = fat_tcpv4.mask + 1; 322 hash = fat_tcpv4.hash; 323 port = fat_tcpv4.port; 324 325 fat_tcpv4.hash = malloc(n * sizeof(*hash)); 326 fat_tcpv4.port = malloc(n * sizeof(*port)); 327 if (fat_tcpv4.hash == NULL || fat_tcpv4.port == NULL) 328 err(EXIT_FAILURE, NULL); 329 330 snarf(hash, fat_tcpv4.hash, n * sizeof(*hash)); 331 snarf(port, fat_tcpv4.port, n * sizeof(*port)); 332 333end: 334 process_vtw(&vtw_tcpv4[0], print); 335 336#if 0 337 if (Vflag && vflag) { 338 printf("total memory for VTW in current config: %d bytes %f MB\n" 339 ,mem 340 ,mem / (1024.0 * 1024)); 341 } 342#endif 343} 344 345void 346show_vtw_v6(void (*print)(const vtw_t *)) 347{ 348 fatp_t *base, *lim; 349 fatp_t **hash, **port; 350 size_t n; 351 fatp_ctl_t fat_tcpv6; 352 vtw_ctl_t vtw_tcpv6[VTW_NCLASS]; 353 int i; 354 int mem = 0; 355 void *p; 356 357 if ((p = lookup("fat_tcpv6")) == NULL) 358 return; 359 snarf(p, &fat_tcpv6, sizeof(fat_tcpv6)); 360 if ((p = lookup("vtw_tcpv6")) == NULL) 361 return; 362 snarf(p, &vtw_tcpv6[0], sizeof(vtw_tcpv6)); 363 364 mem += sizeof(fat_tcpv6); 365 mem += sizeof(vtw_tcpv6); 366 367 for (i = 0; i < VTW_NCLASS; ++i) { 368 vtw_v6_t *kbase, *klim; 369 vtw_v6_t *ubase, *ulim; 370 ptrdiff_t delta; 371 372 kbase = vtw_tcpv6[i].base.v6; 373 klim = vtw_tcpv6[i].lim.v6; 374 375 if (!kbase | !klim) 376 continue; 377 378 n = (klim - kbase + 1); 379 380 if (!i) { 381 if ((ubase = malloc(n * sizeof(*kbase))) == NULL) 382 err(EXIT_FAILURE, NULL); 383 ulim = ubase + n - 1; 384 385 snarf(kbase, ubase, n * sizeof(*ubase)); 386 387 mem += n * sizeof(*ubase); 388 } else { 389 ubase = vtw_tcpv6[0].base.v6; 390 ulim = vtw_tcpv6[0].lim.v6; 391 } 392 393 delta = ubase - kbase; 394 395 vtw_tcpv6[i].base.v6 += delta; 396 vtw_tcpv6[i].lim.v6 += delta; 397 vtw_tcpv6[i].alloc.v6 += delta; 398 vtw_tcpv6[i].fat = &fat_tcpv6; 399 400 if (vtw_tcpv6[i].oldest.v6) 401 vtw_tcpv6[i].oldest.v6 += delta; 402 } 403 404 base = fat_tcpv6.base; 405 lim = fat_tcpv6.lim; 406 407 if (!base | !lim) 408 goto end; 409 410 mem += (lim - base + 1) * sizeof(*base); 411 412 fat_tcpv6.base = malloc((lim - base + 1) * sizeof(*base)); 413 if (fat_tcpv6.base == NULL) 414 err(EXIT_FAILURE, NULL); 415 fat_tcpv6.lim = fat_tcpv6.base + (lim - base); 416 417 snarf(base, fat_tcpv6.base, sizeof(*base) * (lim - base + 1)); 418 419 fat_tcpv6.vtw = &vtw_tcpv6[0]; 420 fat_tcpv6.free = fat_tcpv6.base + (fat_tcpv6.free - base); 421 422 n = fat_tcpv6.mask + 1; 423 hash = fat_tcpv6.hash; 424 port = fat_tcpv6.port; 425 426 fat_tcpv6.hash = malloc(n * sizeof(*hash)); 427 fat_tcpv6.port = malloc(n * sizeof(*port)); 428 if (fat_tcpv6.hash == NULL || fat_tcpv6.port == NULL) 429 err(EXIT_FAILURE, NULL); 430 431 snarf(hash, fat_tcpv6.hash, n * sizeof(*hash)); 432 snarf(port, fat_tcpv6.port, n * sizeof(*port)); 433 434end: 435 436 process_vtw(&vtw_tcpv6[0], print); 437#if 0 438 if (Vflag && vflag) { 439 printf("total memory for VTW in current config: %d bytes %f MB\n" 440 ,mem 441 ,mem / (1024.0 * 1024)); 442 } 443#endif 444} 445