sockstat(1): use tree(3) rbtree instead of hash
o Use tree to lookup by socket kvaddr. The size of hash is too big for a small virtual machine and at the same time too little for a large production server. A tree would better fit here. o For those pcbs, that don't have a socket associated, use a list. o Provide a second tree to lookup by pcb kvaddr. These removes full hash traversal when printing every unix(4) socket. Reviewed by: tuexen Differential revision: https://reviews.freebsd.org/D35724
This commit is contained in:
parent
7d016011f4
commit
a83d596f43
@ -38,6 +38,8 @@ __FBSDID("$FreeBSD$");
|
|||||||
#include <sys/sysctl.h>
|
#include <sys/sysctl.h>
|
||||||
#include <sys/jail.h>
|
#include <sys/jail.h>
|
||||||
#include <sys/user.h>
|
#include <sys/user.h>
|
||||||
|
#include <sys/queue.h>
|
||||||
|
#include <sys/tree.h>
|
||||||
|
|
||||||
#include <sys/un.h>
|
#include <sys/un.h>
|
||||||
#include <sys/unpcb.h>
|
#include <sys/unpcb.h>
|
||||||
@ -119,6 +121,11 @@ struct addr {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct sock {
|
struct sock {
|
||||||
|
union {
|
||||||
|
RB_ENTRY(sock) socket_tree; /* tree of pcbs with socket */
|
||||||
|
SLIST_ENTRY(sock) socket_list; /* list of pcbs w/o socket */
|
||||||
|
};
|
||||||
|
RB_ENTRY(sock) pcb_tree;
|
||||||
kvaddr_t socket;
|
kvaddr_t socket;
|
||||||
kvaddr_t pcb;
|
kvaddr_t pcb;
|
||||||
uint64_t inp_gencnt;
|
uint64_t inp_gencnt;
|
||||||
@ -132,11 +139,25 @@ struct sock {
|
|||||||
char cc[TCP_CA_NAME_MAX];
|
char cc[TCP_CA_NAME_MAX];
|
||||||
struct addr *laddr;
|
struct addr *laddr;
|
||||||
struct addr *faddr;
|
struct addr *faddr;
|
||||||
struct sock *next;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#define HASHSIZE 1009
|
static RB_HEAD(socks_t, sock) socks = RB_INITIALIZER(&socks);
|
||||||
static struct sock *sockhash[HASHSIZE];
|
static int64_t
|
||||||
|
socket_compare(const struct sock *a, const struct sock *b)
|
||||||
|
{
|
||||||
|
return ((int64_t)(a->socket/2 - b->socket/2));
|
||||||
|
}
|
||||||
|
RB_GENERATE_STATIC(socks_t, sock, socket_tree, socket_compare);
|
||||||
|
|
||||||
|
static RB_HEAD(pcbs_t, sock) pcbs = RB_INITIALIZER(&pcbs);
|
||||||
|
static int64_t
|
||||||
|
pcb_compare(const struct sock *a, const struct sock *b)
|
||||||
|
{
|
||||||
|
return ((int64_t)(a->pcb/2 - b->pcb/2));
|
||||||
|
}
|
||||||
|
RB_GENERATE_STATIC(pcbs_t, sock, pcb_tree, pcb_compare);
|
||||||
|
|
||||||
|
static SLIST_HEAD(, sock) nosocks = SLIST_HEAD_INITIALIZER(&nosocks);
|
||||||
|
|
||||||
static struct xfile *xfiles;
|
static struct xfile *xfiles;
|
||||||
static int nxfiles;
|
static int nxfiles;
|
||||||
@ -350,7 +371,7 @@ gather_sctp(void)
|
|||||||
const char *varname;
|
const char *varname;
|
||||||
size_t len, offset;
|
size_t len, offset;
|
||||||
char *buf;
|
char *buf;
|
||||||
int hash, vflag;
|
int vflag;
|
||||||
int no_stcb, local_all_loopback, foreign_all_loopback;
|
int no_stcb, local_all_loopback, foreign_all_loopback;
|
||||||
|
|
||||||
vflag = 0;
|
vflag = 0;
|
||||||
@ -469,10 +490,7 @@ gather_sctp(void)
|
|||||||
(!opt_L || !local_all_loopback) &&
|
(!opt_L || !local_all_loopback) &&
|
||||||
((xinpcb->flags & SCTP_PCB_FLAGS_UDPTYPE) ||
|
((xinpcb->flags & SCTP_PCB_FLAGS_UDPTYPE) ||
|
||||||
(xstcb->last == 1))) {
|
(xstcb->last == 1))) {
|
||||||
hash = (int)((uintptr_t)sock->socket %
|
RB_INSERT(socks_t, &socks, sock);
|
||||||
HASHSIZE);
|
|
||||||
sock->next = sockhash[hash];
|
|
||||||
sockhash[hash] = sock;
|
|
||||||
} else {
|
} else {
|
||||||
free_socket(sock);
|
free_socket(sock);
|
||||||
}
|
}
|
||||||
@ -597,10 +615,7 @@ gather_sctp(void)
|
|||||||
(!opt_L ||
|
(!opt_L ||
|
||||||
!(local_all_loopback ||
|
!(local_all_loopback ||
|
||||||
foreign_all_loopback))) {
|
foreign_all_loopback))) {
|
||||||
hash = (int)((uintptr_t)sock->socket %
|
RB_INSERT(socks_t, &socks, sock);
|
||||||
HASHSIZE);
|
|
||||||
sock->next = sockhash[hash];
|
|
||||||
sockhash[hash] = sock;
|
|
||||||
} else {
|
} else {
|
||||||
free_socket(sock);
|
free_socket(sock);
|
||||||
}
|
}
|
||||||
@ -624,7 +639,7 @@ gather_inet(int proto)
|
|||||||
const char *varname, *protoname;
|
const char *varname, *protoname;
|
||||||
size_t len, bufsize;
|
size_t len, bufsize;
|
||||||
void *buf;
|
void *buf;
|
||||||
int hash, retry, vflag;
|
int retry, vflag;
|
||||||
|
|
||||||
vflag = 0;
|
vflag = 0;
|
||||||
if (opt_4)
|
if (opt_4)
|
||||||
@ -760,9 +775,10 @@ gather_inet(int proto)
|
|||||||
memcpy(sock->cc, xtp->xt_cc, TCP_CA_NAME_MAX);
|
memcpy(sock->cc, xtp->xt_cc, TCP_CA_NAME_MAX);
|
||||||
}
|
}
|
||||||
sock->protoname = protoname;
|
sock->protoname = protoname;
|
||||||
hash = (int)((uintptr_t)sock->socket % HASHSIZE);
|
if (sock->socket != 0)
|
||||||
sock->next = sockhash[hash];
|
RB_INSERT(socks_t, &socks, sock);
|
||||||
sockhash[hash] = sock;
|
else
|
||||||
|
SLIST_INSERT_HEAD(&nosocks, sock, socket_list);
|
||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
free(buf);
|
free(buf);
|
||||||
@ -778,7 +794,7 @@ gather_unix(int proto)
|
|||||||
const char *varname, *protoname;
|
const char *varname, *protoname;
|
||||||
size_t len, bufsize;
|
size_t len, bufsize;
|
||||||
void *buf;
|
void *buf;
|
||||||
int hash, retry;
|
int retry;
|
||||||
|
|
||||||
switch (proto) {
|
switch (proto) {
|
||||||
case SOCK_STREAM:
|
case SOCK_STREAM:
|
||||||
@ -852,9 +868,8 @@ gather_unix(int proto)
|
|||||||
faddr->next = NULL;
|
faddr->next = NULL;
|
||||||
sock->laddr = laddr;
|
sock->laddr = laddr;
|
||||||
sock->faddr = faddr;
|
sock->faddr = faddr;
|
||||||
hash = (int)((uintptr_t)sock->socket % HASHSIZE);
|
RB_INSERT(socks_t, &socks, sock);
|
||||||
sock->next = sockhash[hash];
|
RB_INSERT(pcbs_t, &pcbs, sock);
|
||||||
sockhash[hash] = sock;
|
|
||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
free(buf);
|
free(buf);
|
||||||
@ -1052,7 +1067,7 @@ static void
|
|||||||
displaysock(struct sock *s, int pos)
|
displaysock(struct sock *s, int pos)
|
||||||
{
|
{
|
||||||
kvaddr_t p;
|
kvaddr_t p;
|
||||||
int hash, first, offset;
|
int first, offset;
|
||||||
struct addr *laddr, *faddr;
|
struct addr *laddr, *faddr;
|
||||||
struct sock *s_tmp;
|
struct sock *s_tmp;
|
||||||
|
|
||||||
@ -1104,15 +1119,8 @@ displaysock(struct sock *s, int pos)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
pos += xprintf("-> ");
|
pos += xprintf("-> ");
|
||||||
for (hash = 0; hash < HASHSIZE; ++hash) {
|
s_tmp = RB_FIND(pcbs_t, &pcbs,
|
||||||
for (s_tmp = sockhash[hash];
|
&(struct sock){ .pcb = p });
|
||||||
s_tmp != NULL;
|
|
||||||
s_tmp = s_tmp->next)
|
|
||||||
if (s_tmp->pcb == p)
|
|
||||||
break;
|
|
||||||
if (s_tmp != NULL)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (s_tmp == NULL || s_tmp->laddr == NULL ||
|
if (s_tmp == NULL || s_tmp->laddr == NULL ||
|
||||||
s_tmp->laddr->address.ss_len == 0)
|
s_tmp->laddr->address.ss_len == 0)
|
||||||
pos += xprintf("??");
|
pos += xprintf("??");
|
||||||
@ -1222,7 +1230,7 @@ display(void)
|
|||||||
struct passwd *pwd;
|
struct passwd *pwd;
|
||||||
struct xfile *xf;
|
struct xfile *xf;
|
||||||
struct sock *s;
|
struct sock *s;
|
||||||
int hash, n, pos;
|
int n, pos;
|
||||||
|
|
||||||
if (opt_q != 1) {
|
if (opt_q != 1) {
|
||||||
printf("%-8s %-10s %-5s %-2s %-6s %-*s %-*s",
|
printf("%-8s %-10s %-5s %-2s %-6s %-*s %-*s",
|
||||||
@ -1250,12 +1258,9 @@ display(void)
|
|||||||
continue;
|
continue;
|
||||||
if (opt_j >= 0 && opt_j != getprocjid(xf->xf_pid))
|
if (opt_j >= 0 && opt_j != getprocjid(xf->xf_pid))
|
||||||
continue;
|
continue;
|
||||||
hash = (int)((uintptr_t)xf->xf_data % HASHSIZE);
|
s = RB_FIND(socks_t, &socks,
|
||||||
for (s = sockhash[hash]; s != NULL; s = s->next) {
|
&(struct sock){ .socket = xf->xf_data});
|
||||||
if (s->socket != xf->xf_data)
|
if (s != NULL && check_ports(s)) {
|
||||||
continue;
|
|
||||||
if (!check_ports(s))
|
|
||||||
continue;
|
|
||||||
s->shown = 1;
|
s->shown = 1;
|
||||||
pos = 0;
|
pos = 0;
|
||||||
if (opt_n ||
|
if (opt_n ||
|
||||||
@ -1277,17 +1282,21 @@ display(void)
|
|||||||
}
|
}
|
||||||
if (opt_j >= 0)
|
if (opt_j >= 0)
|
||||||
return;
|
return;
|
||||||
for (hash = 0; hash < HASHSIZE; hash++) {
|
SLIST_FOREACH(s, &nosocks, socket_list) {
|
||||||
for (s = sockhash[hash]; s != NULL; s = s->next) {
|
if (!check_ports(s))
|
||||||
if (s->shown)
|
continue;
|
||||||
continue;
|
pos = xprintf("%-8s %-10s %-5s %-2s ",
|
||||||
if (!check_ports(s))
|
"?", "?", "?", "?");
|
||||||
continue;
|
displaysock(s, pos);
|
||||||
pos = 0;
|
}
|
||||||
pos += xprintf("%-8s %-10s %-5s %-2s ",
|
RB_FOREACH(s, socks_t, &socks) {
|
||||||
"?", "?", "?", "?");
|
if (s->shown)
|
||||||
displaysock(s, pos);
|
continue;
|
||||||
}
|
if (!check_ports(s))
|
||||||
|
continue;
|
||||||
|
pos = xprintf("%-8s %-10s %-5s %-2s ",
|
||||||
|
"?", "?", "?", "?");
|
||||||
|
displaysock(s, pos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user