xref: /openbsd/usr.bin/systat/cache.c (revision 0009a002)
1*0009a002Stedu /* $OpenBSD: cache.c,v 1.8 2019/01/17 05:56:29 tedu Exp $ */
273baed14Scanacar /*
373baed14Scanacar  * Copyright (c) 2001, 2007 Can Erkin Acar <canacar@openbsd.org>
473baed14Scanacar  *
573baed14Scanacar  * Permission to use, copy, modify, and distribute this software for any
673baed14Scanacar  * purpose with or without fee is hereby granted, provided that the above
773baed14Scanacar  * copyright notice and this permission notice appear in all copies.
873baed14Scanacar  *
973baed14Scanacar  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1073baed14Scanacar  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1173baed14Scanacar  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1273baed14Scanacar  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1373baed14Scanacar  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1473baed14Scanacar  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1573baed14Scanacar  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1673baed14Scanacar  */
1773baed14Scanacar 
1873baed14Scanacar #include <sys/types.h>
1973baed14Scanacar #include <sys/ioctl.h>
2073baed14Scanacar #include <sys/socket.h>
2173baed14Scanacar 
2273baed14Scanacar #include <net/if.h>
2373baed14Scanacar #include <netinet/in.h>
2473baed14Scanacar 
2573baed14Scanacar #include <netinet/tcp_fsm.h>
2673baed14Scanacar #ifdef TEST_COMPAT
2773baed14Scanacar #include "pfvarmux.h"
2873baed14Scanacar #else
2973baed14Scanacar #include <net/pfvar.h>
3073baed14Scanacar #endif
3173baed14Scanacar #include <arpa/inet.h>
3273baed14Scanacar 
3373baed14Scanacar #include <stdio.h>
3473baed14Scanacar #include <stdlib.h>
35efffed83Sguenther #include <time.h>
3673baed14Scanacar 
3773baed14Scanacar #include <assert.h>
3873baed14Scanacar 
3973baed14Scanacar #include "cache.h"
4073baed14Scanacar 
4173baed14Scanacar /* prototypes */
42d93808b7Scanacar void update_state(struct sc_ent *, struct pfsync_state *, double);
43d93808b7Scanacar struct sc_ent *cache_state(struct pfsync_state *);
4473baed14Scanacar static __inline int sc_cmp(struct sc_ent *s1, struct sc_ent *s2);
4573baed14Scanacar 
4673baed14Scanacar /* initialize the tree and queue */
4773baed14Scanacar RB_HEAD(sc_tree, sc_ent) sctree;
4873baed14Scanacar TAILQ_HEAD(sc_queue, sc_ent) scq1, scq2, scq_free;
4907fe0f2dScanacar RB_GENERATE(sc_tree, sc_ent, tlink, sc_cmp)
5073baed14Scanacar 
5173baed14Scanacar struct sc_queue *scq_act = NULL;
5273baed14Scanacar struct sc_queue *scq_exp = NULL;
5373baed14Scanacar 
5473baed14Scanacar int cache_max = 0;
5573baed14Scanacar int cache_size = 0;
5673baed14Scanacar 
5773baed14Scanacar struct sc_ent *sc_store = NULL;
5873baed14Scanacar 
5973baed14Scanacar /* preallocate the cache and insert into the 'free' queue */
6073baed14Scanacar int
cache_init(int max)6173baed14Scanacar cache_init(int max)
6273baed14Scanacar {
6373baed14Scanacar 	int n;
6473baed14Scanacar 	static int initialized = 0;
6573baed14Scanacar 
6673baed14Scanacar 	if (max < 0 || initialized)
6773baed14Scanacar 		return (1);
6873baed14Scanacar 
6973baed14Scanacar 	if (max == 0) {
7073baed14Scanacar 		sc_store = NULL;
7173baed14Scanacar 	} else {
727e81aea1Sdoug 		sc_store = reallocarray(NULL, max, sizeof(struct sc_ent));
7373baed14Scanacar 		if (sc_store == NULL)
7473baed14Scanacar 			return (1);
7573baed14Scanacar 	}
7673baed14Scanacar 
7773baed14Scanacar 	RB_INIT(&sctree);
7873baed14Scanacar 	TAILQ_INIT(&scq1);
7973baed14Scanacar 	TAILQ_INIT(&scq2);
8073baed14Scanacar 	TAILQ_INIT(&scq_free);
8173baed14Scanacar 
8273baed14Scanacar 	scq_act = &scq1;
8373baed14Scanacar 	scq_exp = &scq2;
8473baed14Scanacar 
8573baed14Scanacar 	for (n = 0; n < max; n++)
8673baed14Scanacar 		TAILQ_INSERT_HEAD(&scq_free, sc_store + n, qlink);
8773baed14Scanacar 
8873baed14Scanacar 	cache_size = cache_max = max;
8973baed14Scanacar 	initialized++;
9073baed14Scanacar 
9173baed14Scanacar 	return (0);
9273baed14Scanacar }
9373baed14Scanacar 
9473baed14Scanacar void
update_state(struct sc_ent * prev,struct pfsync_state * new,double rate)95d93808b7Scanacar update_state(struct sc_ent *prev, struct pfsync_state *new, double rate)
9673baed14Scanacar {
9773baed14Scanacar 	assert (prev != NULL && new != NULL);
9873baed14Scanacar 	prev->t = time(NULL);
9973baed14Scanacar 	prev->rate = rate;
10073baed14Scanacar 	prev->bytes = COUNTER(new->bytes[0]) + COUNTER(new->bytes[1]);
10173baed14Scanacar 	if (prev->peak < rate)
10273baed14Scanacar 		prev->peak = rate;
10373baed14Scanacar }
10473baed14Scanacar 
10573baed14Scanacar void
add_state(struct pfsync_state * st)106d93808b7Scanacar add_state(struct pfsync_state *st)
10773baed14Scanacar {
10873baed14Scanacar 	struct sc_ent *ent;
10973baed14Scanacar 	assert(st != NULL);
11073baed14Scanacar 
11173baed14Scanacar 	if (cache_max == 0)
11273baed14Scanacar 		return;
11373baed14Scanacar 
11473baed14Scanacar 	if (TAILQ_EMPTY(&scq_free))
11573baed14Scanacar 		return;
11673baed14Scanacar 
11773baed14Scanacar 	ent = TAILQ_FIRST(&scq_free);
11873baed14Scanacar 	TAILQ_REMOVE(&scq_free, ent, qlink);
11973baed14Scanacar 
12073baed14Scanacar 	cache_size--;
12173baed14Scanacar 
1223230bc44Sdlg 	ent->id = st->id;
1233230bc44Sdlg 	ent->creatorid = st->creatorid;
12473baed14Scanacar 	ent->bytes = COUNTER(st->bytes[0]) + COUNTER(st->bytes[1]);
12573baed14Scanacar 	ent->peak = 0;
12673baed14Scanacar 	ent->rate = 0;
1275ddc7cc1Scanacar 	ent->t = 0;
12873baed14Scanacar 
12973baed14Scanacar 	RB_INSERT(sc_tree, &sctree, ent);
13073baed14Scanacar 	TAILQ_INSERT_HEAD(scq_act, ent, qlink);
13173baed14Scanacar }
13273baed14Scanacar 
13373baed14Scanacar /* must be called only once for each state before cache_endupdate */
13473baed14Scanacar struct sc_ent *
cache_state(struct pfsync_state * st)135d93808b7Scanacar cache_state(struct pfsync_state *st)
13673baed14Scanacar {
13773baed14Scanacar 	struct sc_ent ent, *old;
13873baed14Scanacar 	double sd, td, r;
13973baed14Scanacar 
14073baed14Scanacar 	if (cache_max == 0)
14173baed14Scanacar 		return (NULL);
14273baed14Scanacar 
1433230bc44Sdlg 	ent.id = st->id;
1443230bc44Sdlg 	ent.creatorid = st->creatorid;
14573baed14Scanacar 	old = RB_FIND(sc_tree, &sctree, &ent);
14673baed14Scanacar 
14773baed14Scanacar 	if (old == NULL) {
14873baed14Scanacar 		add_state(st);
14973baed14Scanacar 		return (NULL);
15073baed14Scanacar 	}
15173baed14Scanacar 
15273baed14Scanacar 	if (COUNTER(st->bytes[0]) + COUNTER(st->bytes[1]) < old->bytes)
15373baed14Scanacar 		return (NULL);
15473baed14Scanacar 
15573baed14Scanacar 	sd = COUNTER(st->bytes[0]) + COUNTER(st->bytes[1]) - old->bytes;
15673baed14Scanacar 	td = time(NULL) - old->t;
15773baed14Scanacar 
15873baed14Scanacar 	if (td > 0) {
15973baed14Scanacar 		r = sd/td;
16073baed14Scanacar 		update_state(old, st, r);
16173baed14Scanacar 	}
16273baed14Scanacar 
16373baed14Scanacar 	/* move to active queue */
16473baed14Scanacar 	TAILQ_REMOVE(scq_exp, old, qlink);
16573baed14Scanacar 	TAILQ_INSERT_HEAD(scq_act, old, qlink);
16673baed14Scanacar 
16773baed14Scanacar 	return (old);
16873baed14Scanacar }
16973baed14Scanacar 
17073baed14Scanacar /* remove the states that are not updated in this cycle */
17173baed14Scanacar void
cache_endupdate(void)17273baed14Scanacar cache_endupdate(void)
17373baed14Scanacar {
17473baed14Scanacar 	struct sc_queue *tmp;
17573baed14Scanacar 	struct sc_ent *ent;
17673baed14Scanacar 
17773baed14Scanacar 	while (! TAILQ_EMPTY(scq_exp)) {
17873baed14Scanacar 		ent = TAILQ_FIRST(scq_exp);
17973baed14Scanacar 		TAILQ_REMOVE(scq_exp, ent, qlink);
18073baed14Scanacar 		RB_REMOVE(sc_tree, &sctree, ent);
18173baed14Scanacar 		TAILQ_INSERT_HEAD(&scq_free, ent, qlink);
18273baed14Scanacar 		cache_size++;
18373baed14Scanacar 	}
18473baed14Scanacar 
18573baed14Scanacar 	tmp = scq_act;
18673baed14Scanacar 	scq_act = scq_exp;
18773baed14Scanacar 	scq_exp = tmp;
18873baed14Scanacar }
18973baed14Scanacar 
19073baed14Scanacar static __inline int
sc_cmp(struct sc_ent * a,struct sc_ent * b)19173baed14Scanacar sc_cmp(struct sc_ent *a, struct sc_ent *b)
19273baed14Scanacar {
1933230bc44Sdlg 	if (a->id > b->id)
19473baed14Scanacar 		return (1);
1953230bc44Sdlg 	if (a->id < b->id)
19673baed14Scanacar 		return (-1);
1973230bc44Sdlg 	if (a->creatorid > b->creatorid)
19873baed14Scanacar 		return (1);
1993230bc44Sdlg 	if (a->creatorid < b->creatorid)
20073baed14Scanacar 		return (-1);
20173baed14Scanacar 	return (0);
20273baed14Scanacar }
203