1*8663a10cSsashan /* $OpenBSD: pfe.c,v 1.91 2024/06/17 08:36:56 sashan Exp $ */
2feb9ff76Sreyk
3feb9ff76Sreyk /*
436f5dc5eSpyr * Copyright (c) 2006 Pierre-Yves Ritschard <pyr@openbsd.org>
5feb9ff76Sreyk *
6feb9ff76Sreyk * Permission to use, copy, modify, and distribute this software for any
7feb9ff76Sreyk * purpose with or without fee is hereby granted, provided that the above
8feb9ff76Sreyk * copyright notice and this permission notice appear in all copies.
9feb9ff76Sreyk *
10feb9ff76Sreyk * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11feb9ff76Sreyk * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12feb9ff76Sreyk * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13feb9ff76Sreyk * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14feb9ff76Sreyk * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15feb9ff76Sreyk * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16feb9ff76Sreyk * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17feb9ff76Sreyk */
18feb9ff76Sreyk
19f04ff968Sreyk #include <sys/types.h>
20f04ff968Sreyk #include <sys/queue.h>
2105b29ae0Sbenno #include <sys/socket.h>
22f04ff968Sreyk #include <sys/time.h>
23f04ff968Sreyk #include <sys/uio.h>
2405b29ae0Sbenno #include <sys/ioctl.h>
2505b29ae0Sbenno #include <net/if.h>
2605b29ae0Sbenno #include <net/pfvar.h>
270ca734d7Sreyk
28feb9ff76Sreyk #include <event.h>
2905b29ae0Sbenno #include <fcntl.h>
30feb9ff76Sreyk #include <stdlib.h>
31feb9ff76Sreyk #include <string.h>
32005c709bSbenno #include <unistd.h>
33f04ff968Sreyk #include <imsg.h>
34e8fb3979Spyr
35748ceb64Sreyk #include "relayd.h"
36feb9ff76Sreyk
370325c666Sreyk void pfe_init(struct privsep *, struct privsep_proc *p, void *);
38feb9ff76Sreyk void pfe_shutdown(void);
39dd80bec5Spyr void pfe_setup_events(void);
40dd80bec5Spyr void pfe_disable_events(void);
41feb9ff76Sreyk void pfe_sync(void);
42dec6607bSreyk void pfe_statistics(int, short, void *);
43feb9ff76Sreyk
440325c666Sreyk int pfe_dispatch_parent(int, struct privsep_proc *, struct imsg *);
450325c666Sreyk int pfe_dispatch_hce(int, struct privsep_proc *, struct imsg *);
460325c666Sreyk int pfe_dispatch_relay(int, struct privsep_proc *, struct imsg *);
470325c666Sreyk
48748ceb64Sreyk static struct relayd *env = NULL;
49feb9ff76Sreyk
500325c666Sreyk static struct privsep_proc procs[] = {
510325c666Sreyk { "parent", PROC_PARENT, pfe_dispatch_parent },
520325c666Sreyk { "relay", PROC_RELAY, pfe_dispatch_relay },
530325c666Sreyk { "hce", PROC_HCE, pfe_dispatch_hce }
540325c666Sreyk };
55feb9ff76Sreyk
56f910ac11Sreyk void
pfe(struct privsep * ps,struct privsep_proc * p)570325c666Sreyk pfe(struct privsep *ps, struct privsep_proc *p)
58feb9ff76Sreyk {
5905b29ae0Sbenno int s;
6005b29ae0Sbenno struct pf_status status;
6105b29ae0Sbenno
620325c666Sreyk env = ps->ps_env;
63feb9ff76Sreyk
6405b29ae0Sbenno if ((s = open(PF_SOCKET, O_RDWR)) == -1) {
6505b29ae0Sbenno fatal("%s: cannot open pf socket", __func__);
6605b29ae0Sbenno }
6705b29ae0Sbenno if (env->sc_pf == NULL) {
6805b29ae0Sbenno if ((env->sc_pf = calloc(1, sizeof(*(env->sc_pf)))) == NULL)
6905b29ae0Sbenno fatal("calloc");
7005b29ae0Sbenno env->sc_pf->dev = s;
7105b29ae0Sbenno }
7205b29ae0Sbenno if (ioctl(env->sc_pf->dev, DIOCGETSTATUS, &status) == -1)
73efc39811Sbenno fatal("%s: DIOCGETSTATUS", __func__);
7405b29ae0Sbenno if (!status.running)
75efc39811Sbenno fatalx("%s: pf is disabled", __func__);
7605b29ae0Sbenno log_debug("%s: filter init done", __func__);
7705b29ae0Sbenno
78f910ac11Sreyk proc_run(ps, p, procs, nitems(procs), pfe_init, NULL);
79053249cdSpyr }
80feb9ff76Sreyk
810325c666Sreyk void
pfe_init(struct privsep * ps,struct privsep_proc * p,void * arg)820325c666Sreyk pfe_init(struct privsep *ps, struct privsep_proc *p, void *arg)
830325c666Sreyk {
84a2195becSreyk if (config_init(ps->ps_env) == -1)
85a2195becSreyk fatal("failed to initialize configuration");
86a2195becSreyk
87005c709bSbenno if (pledge("stdio recvfd unix pf", NULL) == -1)
88005c709bSbenno fatal("pledge");
89005c709bSbenno
900325c666Sreyk p->p_shutdown = pfe_shutdown;
91feb9ff76Sreyk }
92feb9ff76Sreyk
93feb9ff76Sreyk void
pfe_shutdown(void)94feb9ff76Sreyk pfe_shutdown(void)
95feb9ff76Sreyk {
96feb9ff76Sreyk flush_rulesets(env);
97a2195becSreyk config_purge(env, CONFIG_ALL);
98feb9ff76Sreyk }
99feb9ff76Sreyk
100feb9ff76Sreyk void
pfe_setup_events(void)101dd80bec5Spyr pfe_setup_events(void)
102dd80bec5Spyr {
103dec6607bSreyk struct timeval tv;
104dd80bec5Spyr
105dec6607bSreyk /* Schedule statistics timer */
106a2195becSreyk if (!event_initialized(&env->sc_statev)) {
10735d10c30Sreyk evtimer_set(&env->sc_statev, pfe_statistics, NULL);
108586b5f8aSreyk bcopy(&env->sc_conf.statinterval, &tv, sizeof(tv));
10935d10c30Sreyk evtimer_add(&env->sc_statev, &tv);
110dd80bec5Spyr }
111a2195becSreyk }
112dd80bec5Spyr
113dd80bec5Spyr void
pfe_disable_events(void)114dd80bec5Spyr pfe_disable_events(void)
115dd80bec5Spyr {
11635d10c30Sreyk event_del(&env->sc_statev);
117dd80bec5Spyr }
118dd80bec5Spyr
1190325c666Sreyk int
pfe_dispatch_hce(int fd,struct privsep_proc * p,struct imsg * imsg)1200325c666Sreyk pfe_dispatch_hce(int fd, struct privsep_proc *p, struct imsg *imsg)
121feb9ff76Sreyk {
122feb9ff76Sreyk struct host *host;
123feb9ff76Sreyk struct table *table;
124feb9ff76Sreyk struct ctl_status st;
125feb9ff76Sreyk
126c28c61ccSreyk control_imsg_forward(p->p_ps, imsg);
1272668107aSreyk
1280325c666Sreyk switch (imsg->hdr.type) {
129feb9ff76Sreyk case IMSG_HOST_STATUS:
1300325c666Sreyk IMSG_SIZE_CHECK(imsg, &st);
1310325c666Sreyk memcpy(&st, imsg->data, sizeof(st));
132feb9ff76Sreyk if ((host = host_find(env, st.id)) == NULL)
133efc39811Sbenno fatalx("%s: invalid host id", __func__);
134c0dc99f6Sreyk host->he = st.he;
135253ca2ceSreyk if (host->flags & F_DISABLE)
136253ca2ceSreyk break;
1372edd718bSreyk host->retry_cnt = st.retry_cnt;
1382edd718bSreyk if (st.up != HOST_UNKNOWN) {
1392edd718bSreyk host->check_cnt++;
1402edd718bSreyk if (st.up == HOST_UP)
1412edd718bSreyk host->up_cnt++;
1422edd718bSreyk }
1432edd718bSreyk if (host->check_cnt != st.check_cnt) {
14485a8c65fSreyk log_debug("%s: host %d => %d", __func__,
14568b79041Spyr host->conf.id, host->up);
146efc39811Sbenno fatalx("%s: desynchronized", __func__);
147feb9ff76Sreyk }
148feb9ff76Sreyk
1492edd718bSreyk if (host->up == st.up)
1502edd718bSreyk break;
1512edd718bSreyk
1522edd718bSreyk /* Forward to relay engine(s) */
153c2c37c5dSreyk proc_compose(env->sc_ps, PROC_RELAY,
154c2c37c5dSreyk IMSG_HOST_STATUS, &st, sizeof(st));
1552edd718bSreyk
15668b79041Spyr if ((table = table_find(env, host->conf.tableid))
15768b79041Spyr == NULL)
158efc39811Sbenno fatalx("%s: invalid table id", __func__);
159feb9ff76Sreyk
16085a8c65fSreyk log_debug("%s: state %d for host %u %s", __func__,
16168b79041Spyr st.up, host->conf.id, host->conf.name);
162feb9ff76Sreyk
163c26b8e61Smartijn /* XXX Readd hosttrap code later */
164c26b8e61Smartijn #if 0
1656e07057bSblambert snmp_hosttrap(env, table, host);
166c26b8e61Smartijn #endif
1676e07057bSblambert
168f123d28fSreyk /*
169f123d28fSreyk * Do not change the table state when the host
170f123d28fSreyk * state switches between UNKNOWN and DOWN.
171f123d28fSreyk */
172f123d28fSreyk if (HOST_ISUP(st.up)) {
17368b79041Spyr table->conf.flags |= F_CHANGED;
174feb9ff76Sreyk table->up++;
175feb9ff76Sreyk host->flags |= F_ADD;
176feb9ff76Sreyk host->flags &= ~(F_DEL);
177f123d28fSreyk } else if (HOST_ISUP(host->up)) {
178feb9ff76Sreyk table->up--;
17968b79041Spyr table->conf.flags |= F_CHANGED;
180feb9ff76Sreyk host->flags |= F_DEL;
181feb9ff76Sreyk host->flags &= ~(F_ADD);
1822381fb0aSbenno host->up = st.up;
1832381fb0aSbenno pfe_sync();
184feb9ff76Sreyk }
185f123d28fSreyk
186feb9ff76Sreyk host->up = st.up;
187feb9ff76Sreyk break;
188feb9ff76Sreyk case IMSG_SYNC:
189feb9ff76Sreyk pfe_sync();
190feb9ff76Sreyk break;
191feb9ff76Sreyk default:
1920325c666Sreyk return (-1);
193feb9ff76Sreyk }
194feb9ff76Sreyk
1950325c666Sreyk return (0);
1960325c666Sreyk }
1970325c666Sreyk
1980325c666Sreyk int
pfe_dispatch_parent(int fd,struct privsep_proc * p,struct imsg * imsg)1990325c666Sreyk pfe_dispatch_parent(int fd, struct privsep_proc *p, struct imsg *imsg)
200feb9ff76Sreyk {
2010325c666Sreyk switch (imsg->hdr.type) {
202a2195becSreyk case IMSG_CFG_TABLE:
203a2195becSreyk config_gettable(env, imsg);
204adf98c11Spyr break;
205a2195becSreyk case IMSG_CFG_HOST:
206a2195becSreyk config_gethost(env, imsg);
207adf98c11Spyr break;
208a2195becSreyk case IMSG_CFG_RDR:
209a2195becSreyk config_getrdr(env, imsg);
210adf98c11Spyr break;
211a2195becSreyk case IMSG_CFG_VIRT:
212a2195becSreyk config_getvirt(env, imsg);
213adf98c11Spyr break;
214a2195becSreyk case IMSG_CFG_ROUTER:
215a2195becSreyk config_getrt(env, imsg);
216adf98c11Spyr break;
217a2195becSreyk case IMSG_CFG_ROUTE:
218a2195becSreyk config_getroute(env, imsg);
219a2195becSreyk break;
220a2195becSreyk case IMSG_CFG_PROTO:
221a2195becSreyk config_getproto(env, imsg);
222a2195becSreyk break;
223a2195becSreyk case IMSG_CFG_RELAY:
224a2195becSreyk config_getrelay(env, imsg);
225a2195becSreyk break;
226416fa9c0Sreyk case IMSG_CFG_RELAY_TABLE:
227416fa9c0Sreyk config_getrelaytable(env, imsg);
228416fa9c0Sreyk break;
229a2195becSreyk case IMSG_CFG_DONE:
230a2195becSreyk config_getcfg(env, imsg);
23164b0bc0cSreyk init_tables(env);
232c26b8e61Smartijn agentx_init(env);
2330dcba380Scamield break;
2340dcba380Scamield case IMSG_CTL_START:
235adf98c11Spyr pfe_setup_events();
236adf98c11Spyr pfe_sync();
237adf98c11Spyr break;
238a2195becSreyk case IMSG_CTL_RESET:
239a2195becSreyk config_getreset(env, imsg);
240a2195becSreyk break;
241c26b8e61Smartijn case IMSG_AGENTXSOCK:
242c26b8e61Smartijn agentx_getsock(imsg);
2436e07057bSblambert break;
244feb9ff76Sreyk default:
2450325c666Sreyk return (-1);
246feb9ff76Sreyk }
247feb9ff76Sreyk
2480325c666Sreyk return (0);
2490325c666Sreyk }
2500325c666Sreyk
2510325c666Sreyk int
pfe_dispatch_relay(int fd,struct privsep_proc * p,struct imsg * imsg)2520325c666Sreyk pfe_dispatch_relay(int fd, struct privsep_proc *p, struct imsg *imsg)
2532edd718bSreyk {
2542edd718bSreyk struct ctl_natlook cnl;
2552edd718bSreyk struct ctl_stats crs;
2562edd718bSreyk struct relay *rlay;
25786b74329Sreyk struct ctl_conn *c;
2586e07057bSblambert struct rsession con, *s, *t;
25986b74329Sreyk int cid;
2606e07057bSblambert objid_t sid;
2612edd718bSreyk
2620325c666Sreyk switch (imsg->hdr.type) {
2632edd718bSreyk case IMSG_NATLOOK:
2640325c666Sreyk IMSG_SIZE_CHECK(imsg, &cnl);
2650325c666Sreyk bcopy(imsg->data, &cnl, sizeof(cnl));
266586b5f8aSreyk if (cnl.proc > env->sc_conf.prefork_relay)
267efc39811Sbenno fatalx("%s: invalid relay proc", __func__);
2682edd718bSreyk if (natlook(env, &cnl) != 0)
2692edd718bSreyk cnl.in = -1;
2700325c666Sreyk proc_compose_imsg(env->sc_ps, PROC_RELAY, cnl.proc,
271c2c37c5dSreyk IMSG_NATLOOK, -1, -1, &cnl, sizeof(cnl));
2722edd718bSreyk break;
2732edd718bSreyk case IMSG_STATISTICS:
2740325c666Sreyk IMSG_SIZE_CHECK(imsg, &crs);
2750325c666Sreyk bcopy(imsg->data, &crs, sizeof(crs));
276586b5f8aSreyk if (crs.proc > env->sc_conf.prefork_relay)
277efc39811Sbenno fatalx("%s: invalid relay proc", __func__);
2782edd718bSreyk if ((rlay = relay_find(env, crs.id)) == NULL)
279efc39811Sbenno fatalx("%s: invalid relay id", __func__);
2804a5b9b3eSreyk bcopy(&crs, &rlay->rl_stats[crs.proc], sizeof(crs));
2814a5b9b3eSreyk rlay->rl_stats[crs.proc].interval =
282586b5f8aSreyk env->sc_conf.statinterval.tv_sec;
2832edd718bSreyk break;
28486b74329Sreyk case IMSG_CTL_SESSION:
28586b74329Sreyk IMSG_SIZE_CHECK(imsg, &con);
28686b74329Sreyk memcpy(&con, imsg->data, sizeof(con));
28786b74329Sreyk if ((c = control_connbyfd(con.se_cid)) == NULL) {
28886b74329Sreyk log_debug("%s: control connection %d not found",
28986b74329Sreyk __func__, con.se_cid);
29086b74329Sreyk return (0);
29186b74329Sreyk }
29286b74329Sreyk imsg_compose_event(&c->iev,
29386b74329Sreyk IMSG_CTL_SESSION, 0, 0, -1,
29486b74329Sreyk &con, sizeof(con));
29586b74329Sreyk break;
29686b74329Sreyk case IMSG_CTL_END:
29786b74329Sreyk IMSG_SIZE_CHECK(imsg, &cid);
29886b74329Sreyk memcpy(&cid, imsg->data, sizeof(cid));
29986b74329Sreyk if ((c = control_connbyfd(cid)) == NULL) {
30086b74329Sreyk log_debug("%s: control connection %d not found",
30186b74329Sreyk __func__, cid);
30286b74329Sreyk return (0);
30386b74329Sreyk }
30486b74329Sreyk if (c->waiting == 0) {
30586b74329Sreyk log_debug("%s: no pending control requests", __func__);
30686b74329Sreyk return (0);
30786b74329Sreyk } else if (--c->waiting == 0) {
30886b74329Sreyk /* Last ack for a previous request */
30986b74329Sreyk imsg_compose_event(&c->iev, IMSG_CTL_END,
31086b74329Sreyk 0, 0, -1, NULL, 0);
31186b74329Sreyk }
31286b74329Sreyk break;
3136e07057bSblambert case IMSG_SESS_PUBLISH:
3146e07057bSblambert IMSG_SIZE_CHECK(imsg, s);
3156e07057bSblambert if ((s = calloc(1, sizeof(*s))) == NULL)
3166e07057bSblambert return (0); /* XXX */
3176e07057bSblambert memcpy(s, imsg->data, sizeof(*s));
3186e07057bSblambert TAILQ_FOREACH(t, &env->sc_sessions, se_entry) {
319080b67b5Sjsg /* duplicate registration */
320080b67b5Sjsg if (t->se_id == s->se_id) {
321080b67b5Sjsg free(s);
3226e07057bSblambert return (0);
323080b67b5Sjsg }
3246e07057bSblambert if (t->se_id > s->se_id)
3256e07057bSblambert break;
3266e07057bSblambert }
3276e07057bSblambert if (t)
3286e07057bSblambert TAILQ_INSERT_BEFORE(t, s, se_entry);
3296e07057bSblambert else
3306e07057bSblambert TAILQ_INSERT_TAIL(&env->sc_sessions, s, se_entry);
3316e07057bSblambert break;
3326e07057bSblambert case IMSG_SESS_UNPUBLISH:
3336e07057bSblambert IMSG_SIZE_CHECK(imsg, &sid);
3346e07057bSblambert memcpy(&sid, imsg->data, sizeof(sid));
3356e07057bSblambert TAILQ_FOREACH(s, &env->sc_sessions, se_entry)
3366e07057bSblambert if (s->se_id == sid)
3376e07057bSblambert break;
3386e07057bSblambert if (s) {
3396e07057bSblambert TAILQ_REMOVE(&env->sc_sessions, s, se_entry);
3406e07057bSblambert free(s);
3418c50f9c1Sblambert } else {
3428c50f9c1Sblambert DPRINTF("removal of unpublished session %i", sid);
3438c50f9c1Sblambert }
3446e07057bSblambert break;
3452edd718bSreyk default:
3460325c666Sreyk return (-1);
3472edd718bSreyk }
3480325c666Sreyk
3490325c666Sreyk return (0);
3502edd718bSreyk }
3512edd718bSreyk
3522edd718bSreyk void
show(struct ctl_conn * c)353feb9ff76Sreyk show(struct ctl_conn *c)
354feb9ff76Sreyk {
3559591a9f7Spyr struct rdr *rdr;
356feb9ff76Sreyk struct host *host;
3572edd718bSreyk struct relay *rlay;
358417c432fSreyk struct router *rt;
359417c432fSreyk struct netroute *nr;
360416fa9c0Sreyk struct relay_table *rlt;
361feb9ff76Sreyk
36235d10c30Sreyk if (env->sc_rdrs == NULL)
363f00ce691Spyr goto relays;
36435d10c30Sreyk TAILQ_FOREACH(rdr, env->sc_rdrs, entry) {
365f07d0e3bSpyr imsg_compose_event(&c->iev, IMSG_CTL_RDR, 0, 0, -1,
3669591a9f7Spyr rdr, sizeof(*rdr));
3679591a9f7Spyr if (rdr->conf.flags & F_DISABLE)
368feb9ff76Sreyk continue;
369feb9ff76Sreyk
370f07d0e3bSpyr imsg_compose_event(&c->iev, IMSG_CTL_RDR_STATS, 0, 0, -1,
371dec6607bSreyk &rdr->stats, sizeof(rdr->stats));
372dec6607bSreyk
373f07d0e3bSpyr imsg_compose_event(&c->iev, IMSG_CTL_TABLE, 0, 0, -1,
3749591a9f7Spyr rdr->table, sizeof(*rdr->table));
3759591a9f7Spyr if (!(rdr->table->conf.flags & F_DISABLE))
3769591a9f7Spyr TAILQ_FOREACH(host, &rdr->table->hosts, entry)
377f07d0e3bSpyr imsg_compose_event(&c->iev, IMSG_CTL_HOST,
378069bf5e4Spyr 0, 0, -1, host, sizeof(*host));
379feb9ff76Sreyk
3809591a9f7Spyr if (rdr->backup->conf.id == EMPTY_TABLE)
381feb9ff76Sreyk continue;
382f07d0e3bSpyr imsg_compose_event(&c->iev, IMSG_CTL_TABLE, 0, 0, -1,
3839591a9f7Spyr rdr->backup, sizeof(*rdr->backup));
3849591a9f7Spyr if (!(rdr->backup->conf.flags & F_DISABLE))
3859591a9f7Spyr TAILQ_FOREACH(host, &rdr->backup->hosts, entry)
386f07d0e3bSpyr imsg_compose_event(&c->iev, IMSG_CTL_HOST,
387069bf5e4Spyr 0, 0, -1, host, sizeof(*host));
388feb9ff76Sreyk }
389f00ce691Spyr relays:
39035d10c30Sreyk if (env->sc_relays == NULL)
391417c432fSreyk goto routers;
3924a5b9b3eSreyk TAILQ_FOREACH(rlay, env->sc_relays, rl_entry) {
393586b5f8aSreyk rlay->rl_stats[env->sc_conf.prefork_relay].id = EMPTY_ID;
394f07d0e3bSpyr imsg_compose_event(&c->iev, IMSG_CTL_RELAY, 0, 0, -1,
3952edd718bSreyk rlay, sizeof(*rlay));
396f07d0e3bSpyr imsg_compose_event(&c->iev, IMSG_CTL_RELAY_STATS, 0, 0, -1,
3974a5b9b3eSreyk &rlay->rl_stats, sizeof(rlay->rl_stats));
398253ca2ceSreyk
399416fa9c0Sreyk TAILQ_FOREACH(rlt, &rlay->rl_tables, rlt_entry) {
400f07d0e3bSpyr imsg_compose_event(&c->iev, IMSG_CTL_TABLE, 0, 0, -1,
401416fa9c0Sreyk rlt->rlt_table, sizeof(*rlt->rlt_table));
402416fa9c0Sreyk if (!(rlt->rlt_table->conf.flags & F_DISABLE))
403416fa9c0Sreyk TAILQ_FOREACH(host,
404416fa9c0Sreyk &rlt->rlt_table->hosts, entry)
405416fa9c0Sreyk imsg_compose_event(&c->iev,
406416fa9c0Sreyk IMSG_CTL_HOST, 0, 0, -1,
407416fa9c0Sreyk host, sizeof(*host));
408416fa9c0Sreyk }
4092edd718bSreyk }
410417c432fSreyk
411417c432fSreyk routers:
412417c432fSreyk if (env->sc_rts == NULL)
413417c432fSreyk goto end;
414417c432fSreyk TAILQ_FOREACH(rt, env->sc_rts, rt_entry) {
415417c432fSreyk imsg_compose_event(&c->iev, IMSG_CTL_ROUTER, 0, 0, -1,
416417c432fSreyk rt, sizeof(*rt));
417417c432fSreyk if (rt->rt_conf.flags & F_DISABLE)
418417c432fSreyk continue;
419417c432fSreyk
420417c432fSreyk TAILQ_FOREACH(nr, &rt->rt_netroutes, nr_entry)
421417c432fSreyk imsg_compose_event(&c->iev, IMSG_CTL_NETROUTE,
422417c432fSreyk 0, 0, -1, nr, sizeof(*nr));
423417c432fSreyk imsg_compose_event(&c->iev, IMSG_CTL_TABLE, 0, 0, -1,
424417c432fSreyk rt->rt_gwtable, sizeof(*rt->rt_gwtable));
425417c432fSreyk if (!(rt->rt_gwtable->conf.flags & F_DISABLE))
426417c432fSreyk TAILQ_FOREACH(host, &rt->rt_gwtable->hosts, entry)
427417c432fSreyk imsg_compose_event(&c->iev, IMSG_CTL_HOST,
428417c432fSreyk 0, 0, -1, host, sizeof(*host));
429417c432fSreyk }
430417c432fSreyk
431f00ce691Spyr end:
432f07d0e3bSpyr imsg_compose_event(&c->iev, IMSG_CTL_END, 0, 0, -1, NULL, 0);
433feb9ff76Sreyk }
434feb9ff76Sreyk
4359d421a7aSreyk void
show_sessions(struct ctl_conn * c)4369d421a7aSreyk show_sessions(struct ctl_conn *c)
4379d421a7aSreyk {
43886b74329Sreyk int proc, cid;
4399d421a7aSreyk
440586b5f8aSreyk for (proc = 0; proc < env->sc_conf.prefork_relay; proc++) {
44186b74329Sreyk cid = c->iev.ibuf.fd;
4420325c666Sreyk
4439d421a7aSreyk /*
4449d421a7aSreyk * Request all the running sessions from the process
4459d421a7aSreyk */
4460325c666Sreyk proc_compose_imsg(env->sc_ps, PROC_RELAY, proc,
447c2c37c5dSreyk IMSG_CTL_SESSION, -1, -1, &cid, sizeof(cid));
44886b74329Sreyk c->waiting++;
4499d421a7aSreyk }
4509d421a7aSreyk }
451feb9ff76Sreyk
452feb9ff76Sreyk int
disable_rdr(struct ctl_conn * c,struct ctl_id * id)4539591a9f7Spyr disable_rdr(struct ctl_conn *c, struct ctl_id *id)
454feb9ff76Sreyk {
4559591a9f7Spyr struct rdr *rdr;
456feb9ff76Sreyk
457ef1f2334Sreyk if (id->id == EMPTY_ID)
4589591a9f7Spyr rdr = rdr_findbyname(env, id->name);
459ef1f2334Sreyk else
4609591a9f7Spyr rdr = rdr_find(env, id->id);
4619591a9f7Spyr if (rdr == NULL)
462feb9ff76Sreyk return (-1);
4639591a9f7Spyr id->id = rdr->conf.id;
464feb9ff76Sreyk
4659591a9f7Spyr if (rdr->conf.flags & F_DISABLE)
466feb9ff76Sreyk return (0);
467feb9ff76Sreyk
4689591a9f7Spyr rdr->conf.flags |= F_DISABLE;
4699591a9f7Spyr rdr->conf.flags &= ~(F_ADD);
4709591a9f7Spyr rdr->conf.flags |= F_DEL;
4719591a9f7Spyr rdr->table->conf.flags |= F_DISABLE;
47285a8c65fSreyk log_debug("%s: redirect %d", __func__, rdr->conf.id);
473feb9ff76Sreyk pfe_sync();
474feb9ff76Sreyk return (0);
475feb9ff76Sreyk }
476feb9ff76Sreyk
477feb9ff76Sreyk int
enable_rdr(struct ctl_conn * c,struct ctl_id * id)4789591a9f7Spyr enable_rdr(struct ctl_conn *c, struct ctl_id *id)
479feb9ff76Sreyk {
4809591a9f7Spyr struct rdr *rdr;
481ef1f2334Sreyk struct ctl_id eid;
482feb9ff76Sreyk
483ef1f2334Sreyk if (id->id == EMPTY_ID)
4849591a9f7Spyr rdr = rdr_findbyname(env, id->name);
485ef1f2334Sreyk else
4869591a9f7Spyr rdr = rdr_find(env, id->id);
4879591a9f7Spyr if (rdr == NULL)
488feb9ff76Sreyk return (-1);
4899591a9f7Spyr id->id = rdr->conf.id;
490feb9ff76Sreyk
4919591a9f7Spyr if (!(rdr->conf.flags & F_DISABLE))
492feb9ff76Sreyk return (0);
493feb9ff76Sreyk
4949591a9f7Spyr rdr->conf.flags &= ~(F_DISABLE);
4959591a9f7Spyr rdr->conf.flags &= ~(F_DEL);
4969591a9f7Spyr rdr->conf.flags |= F_ADD;
49785a8c65fSreyk log_debug("%s: redirect %d", __func__, rdr->conf.id);
498feb9ff76Sreyk
499ef1f2334Sreyk bzero(&eid, sizeof(eid));
500ef1f2334Sreyk
501feb9ff76Sreyk /* XXX: we're syncing twice */
5029591a9f7Spyr eid.id = rdr->table->conf.id;
503ef1f2334Sreyk if (enable_table(c, &eid) == -1)
504feb9ff76Sreyk return (-1);
5059591a9f7Spyr if (rdr->backup->conf.id == EMPTY_ID)
506eac15771Spyr return (0);
5079591a9f7Spyr eid.id = rdr->backup->conf.id;
508ef1f2334Sreyk if (enable_table(c, &eid) == -1)
509feb9ff76Sreyk return (-1);
510feb9ff76Sreyk return (0);
511feb9ff76Sreyk }
512feb9ff76Sreyk
513feb9ff76Sreyk int
disable_table(struct ctl_conn * c,struct ctl_id * id)514ef1f2334Sreyk disable_table(struct ctl_conn *c, struct ctl_id *id)
515feb9ff76Sreyk {
516feb9ff76Sreyk struct table *table;
517feb9ff76Sreyk struct host *host;
518feb9ff76Sreyk
519ef1f2334Sreyk if (id->id == EMPTY_ID)
520ef1f2334Sreyk table = table_findbyname(env, id->name);
521ef1f2334Sreyk else
522ef1f2334Sreyk table = table_find(env, id->id);
523ef1f2334Sreyk if (table == NULL)
524feb9ff76Sreyk return (-1);
52568b79041Spyr id->id = table->conf.id;
526b850e197Sjsg if (table->conf.rdrid > 0 && rdr_find(env, table->conf.rdrid) == NULL)
527efc39811Sbenno fatalx("%s: desynchronised", __func__);
528feb9ff76Sreyk
52968b79041Spyr if (table->conf.flags & F_DISABLE)
530feb9ff76Sreyk return (0);
53168b79041Spyr table->conf.flags |= (F_DISABLE|F_CHANGED);
532feb9ff76Sreyk table->up = 0;
533feb9ff76Sreyk TAILQ_FOREACH(host, &table->hosts, entry)
534feb9ff76Sreyk host->up = HOST_UNKNOWN;
535c2c37c5dSreyk proc_compose(env->sc_ps, PROC_HCE, IMSG_TABLE_DISABLE,
53668b79041Spyr &table->conf.id, sizeof(table->conf.id));
5370325c666Sreyk
538b850e197Sjsg /* Forward to relay engine(s) */
539c2c37c5dSreyk proc_compose(env->sc_ps, PROC_RELAY, IMSG_TABLE_DISABLE,
540b850e197Sjsg &table->conf.id, sizeof(table->conf.id));
5410325c666Sreyk
54285a8c65fSreyk log_debug("%s: table %d", __func__, table->conf.id);
543feb9ff76Sreyk pfe_sync();
544feb9ff76Sreyk return (0);
545feb9ff76Sreyk }
546feb9ff76Sreyk
547feb9ff76Sreyk int
enable_table(struct ctl_conn * c,struct ctl_id * id)548ef1f2334Sreyk enable_table(struct ctl_conn *c, struct ctl_id *id)
549feb9ff76Sreyk {
550feb9ff76Sreyk struct table *table;
551feb9ff76Sreyk struct host *host;
552feb9ff76Sreyk
553ef1f2334Sreyk if (id->id == EMPTY_ID)
554ef1f2334Sreyk table = table_findbyname(env, id->name);
555ef1f2334Sreyk else
556ef1f2334Sreyk table = table_find(env, id->id);
557ef1f2334Sreyk if (table == NULL)
558feb9ff76Sreyk return (-1);
55968b79041Spyr id->id = table->conf.id;
560ef1f2334Sreyk
561b850e197Sjsg if (table->conf.rdrid > 0 && rdr_find(env, table->conf.rdrid) == NULL)
562efc39811Sbenno fatalx("%s: desynchronised", __func__);
563feb9ff76Sreyk
56468b79041Spyr if (!(table->conf.flags & F_DISABLE))
565feb9ff76Sreyk return (0);
56668b79041Spyr table->conf.flags &= ~(F_DISABLE);
56768b79041Spyr table->conf.flags |= F_CHANGED;
568feb9ff76Sreyk table->up = 0;
569feb9ff76Sreyk TAILQ_FOREACH(host, &table->hosts, entry)
570feb9ff76Sreyk host->up = HOST_UNKNOWN;
571c2c37c5dSreyk proc_compose(env->sc_ps, PROC_HCE, IMSG_TABLE_ENABLE,
57268b79041Spyr &table->conf.id, sizeof(table->conf.id));
5730325c666Sreyk
574b850e197Sjsg /* Forward to relay engine(s) */
575c2c37c5dSreyk proc_compose(env->sc_ps, PROC_RELAY, IMSG_TABLE_ENABLE,
576b850e197Sjsg &table->conf.id, sizeof(table->conf.id));
5770325c666Sreyk
57885a8c65fSreyk log_debug("%s: table %d", __func__, table->conf.id);
579feb9ff76Sreyk pfe_sync();
580feb9ff76Sreyk return (0);
581feb9ff76Sreyk }
582feb9ff76Sreyk
583feb9ff76Sreyk int
disable_host(struct ctl_conn * c,struct ctl_id * id,struct host * host)584c723f8edSreyk disable_host(struct ctl_conn *c, struct ctl_id *id, struct host *host)
585feb9ff76Sreyk {
586c723f8edSreyk struct host *h;
587*8663a10cSsashan struct table *table, *t;
588*8663a10cSsashan int host_byname = 0;
589feb9ff76Sreyk
590c723f8edSreyk if (host == NULL) {
591*8663a10cSsashan if (id->id == EMPTY_ID) {
592ef1f2334Sreyk host = host_findbyname(env, id->name);
593*8663a10cSsashan host_byname = 1;
594*8663a10cSsashan }
595ef1f2334Sreyk else
596ef1f2334Sreyk host = host_find(env, id->id);
597c723f8edSreyk if (host == NULL || host->conf.parentid)
598feb9ff76Sreyk return (-1);
599c723f8edSreyk }
60068b79041Spyr id->id = host->conf.id;
601feb9ff76Sreyk
602feb9ff76Sreyk if (host->flags & F_DISABLE)
603feb9ff76Sreyk return (0);
604feb9ff76Sreyk
605feb9ff76Sreyk if (host->up == HOST_UP) {
60668b79041Spyr if ((table = table_find(env, host->conf.tableid)) == NULL)
607efc39811Sbenno fatalx("%s: invalid table id", __func__);
608feb9ff76Sreyk table->up--;
60968b79041Spyr table->conf.flags |= F_CHANGED;
610feb9ff76Sreyk }
611feb9ff76Sreyk
612feb9ff76Sreyk host->up = HOST_UNKNOWN;
613feb9ff76Sreyk host->flags |= F_DISABLE;
614feb9ff76Sreyk host->flags |= F_DEL;
615feb9ff76Sreyk host->flags &= ~(F_ADD);
6162edd718bSreyk host->check_cnt = 0;
6172edd718bSreyk host->up_cnt = 0;
618feb9ff76Sreyk
619c2c37c5dSreyk proc_compose(env->sc_ps, PROC_HCE, IMSG_HOST_DISABLE,
62068b79041Spyr &host->conf.id, sizeof(host->conf.id));
6210325c666Sreyk
622253ca2ceSreyk /* Forward to relay engine(s) */
623c2c37c5dSreyk proc_compose(env->sc_ps, PROC_RELAY, IMSG_HOST_DISABLE,
62468b79041Spyr &host->conf.id, sizeof(host->conf.id));
62585a8c65fSreyk log_debug("%s: host %d", __func__, host->conf.id);
626c723f8edSreyk
6271584e35dSreyk if (!host->conf.parentid) {
628c723f8edSreyk /* Disable all children */
6291584e35dSreyk SLIST_FOREACH(h, &host->children, child)
630c723f8edSreyk disable_host(c, id, h);
631*8663a10cSsashan
632*8663a10cSsashan /* Disable hosts with same name on all tables */
633*8663a10cSsashan if (host_byname)
634*8663a10cSsashan TAILQ_FOREACH(t, env->sc_tables, entry)
635*8663a10cSsashan TAILQ_FOREACH(h, &t->hosts, entry)
636*8663a10cSsashan if (strcmp(h->conf.name,
637*8663a10cSsashan host->conf.name) == 0 &&
638*8663a10cSsashan h->conf.id != host->conf.id &&
639*8663a10cSsashan !h->conf.parentid)
640*8663a10cSsashan disable_host(c, id, h);
641feb9ff76Sreyk pfe_sync();
6421584e35dSreyk }
643feb9ff76Sreyk return (0);
644feb9ff76Sreyk }
645feb9ff76Sreyk
646feb9ff76Sreyk int
enable_host(struct ctl_conn * c,struct ctl_id * id,struct host * host)647c723f8edSreyk enable_host(struct ctl_conn *c, struct ctl_id *id, struct host *host)
648feb9ff76Sreyk {
649c723f8edSreyk struct host *h;
650*8663a10cSsashan struct table *t;
651*8663a10cSsashan int host_byname = 0;
652*8663a10cSsashan
653feb9ff76Sreyk
654c723f8edSreyk if (host == NULL) {
655*8663a10cSsashan if (id->id == EMPTY_ID) {
656ef1f2334Sreyk host = host_findbyname(env, id->name);
657*8663a10cSsashan host_byname = 1;
658*8663a10cSsashan }
659ef1f2334Sreyk else
660ef1f2334Sreyk host = host_find(env, id->id);
661c723f8edSreyk if (host == NULL || host->conf.parentid)
662feb9ff76Sreyk return (-1);
663c723f8edSreyk }
66468b79041Spyr id->id = host->conf.id;
665feb9ff76Sreyk
666feb9ff76Sreyk if (!(host->flags & F_DISABLE))
667feb9ff76Sreyk return (0);
668feb9ff76Sreyk
669feb9ff76Sreyk host->up = HOST_UNKNOWN;
670feb9ff76Sreyk host->flags &= ~(F_DISABLE);
671feb9ff76Sreyk host->flags &= ~(F_DEL);
672feb9ff76Sreyk host->flags &= ~(F_ADD);
673feb9ff76Sreyk
674c2c37c5dSreyk proc_compose(env->sc_ps, PROC_HCE, IMSG_HOST_ENABLE,
67568b79041Spyr &host->conf.id, sizeof (host->conf.id));
6760325c666Sreyk
677253ca2ceSreyk /* Forward to relay engine(s) */
678c2c37c5dSreyk proc_compose(env->sc_ps, PROC_RELAY, IMSG_HOST_ENABLE,
67968b79041Spyr &host->conf.id, sizeof(host->conf.id));
6800325c666Sreyk
68185a8c65fSreyk log_debug("%s: host %d", __func__, host->conf.id);
682c723f8edSreyk
6831584e35dSreyk if (!host->conf.parentid) {
684c723f8edSreyk /* Enable all children */
6851584e35dSreyk SLIST_FOREACH(h, &host->children, child)
686c723f8edSreyk enable_host(c, id, h);
687*8663a10cSsashan
688*8663a10cSsashan /* Enable hosts with same name on all tables */
689*8663a10cSsashan if (host_byname)
690*8663a10cSsashan TAILQ_FOREACH(t, env->sc_tables, entry)
691*8663a10cSsashan TAILQ_FOREACH(h, &t->hosts, entry)
692*8663a10cSsashan if (strcmp(h->conf.name,
693*8663a10cSsashan host->conf.name) == 0 &&
694*8663a10cSsashan h->conf.id != host->conf.id &&
695*8663a10cSsashan !h->conf.parentid)
696*8663a10cSsashan enable_host(c, id, h);
697feb9ff76Sreyk pfe_sync();
6981584e35dSreyk }
699feb9ff76Sreyk return (0);
700feb9ff76Sreyk }
701feb9ff76Sreyk
702feb9ff76Sreyk void
pfe_sync(void)703feb9ff76Sreyk pfe_sync(void)
704feb9ff76Sreyk {
7059591a9f7Spyr struct rdr *rdr;
706feb9ff76Sreyk struct table *active;
7072edd718bSreyk struct table *table;
7089ea8c990Spyr struct ctl_id id;
7099ea8c990Spyr struct imsg imsg;
7102edd718bSreyk struct ctl_demote demote;
71134438db4Sreyk struct router *rt;
712feb9ff76Sreyk
7139ea8c990Spyr bzero(&id, sizeof(id));
7149ea8c990Spyr bzero(&imsg, sizeof(imsg));
71535d10c30Sreyk TAILQ_FOREACH(rdr, env->sc_rdrs, entry) {
7169591a9f7Spyr rdr->conf.flags &= ~(F_BACKUP);
7179591a9f7Spyr rdr->conf.flags &= ~(F_DOWN);
718feb9ff76Sreyk
7199591a9f7Spyr if (rdr->conf.flags & F_DISABLE ||
7209591a9f7Spyr (rdr->table->up == 0 && rdr->backup->up == 0)) {
7219591a9f7Spyr rdr->conf.flags |= F_DOWN;
722feb9ff76Sreyk active = NULL;
7239591a9f7Spyr } else if (rdr->table->up == 0 && rdr->backup->up > 0) {
7249591a9f7Spyr rdr->conf.flags |= F_BACKUP;
7259591a9f7Spyr active = rdr->backup;
72668b79041Spyr active->conf.flags |=
7279591a9f7Spyr rdr->table->conf.flags & F_CHANGED;
72868b79041Spyr active->conf.flags |=
7299591a9f7Spyr rdr->backup->conf.flags & F_CHANGED;
730feb9ff76Sreyk } else
7319591a9f7Spyr active = rdr->table;
732feb9ff76Sreyk
73368b79041Spyr if (active != NULL && active->conf.flags & F_CHANGED) {
73468b79041Spyr id.id = active->conf.id;
7359ea8c990Spyr imsg.hdr.type = IMSG_CTL_TABLE_CHANGED;
7369ea8c990Spyr imsg.hdr.len = sizeof(id) + IMSG_HEADER_SIZE;
7379ea8c990Spyr imsg.data = &id;
7389591a9f7Spyr sync_table(env, rdr, active);
739c28c61ccSreyk control_imsg_forward(env->sc_ps, &imsg);
7409ea8c990Spyr }
741feb9ff76Sreyk
7429591a9f7Spyr if (rdr->conf.flags & F_DOWN) {
7439591a9f7Spyr if (rdr->conf.flags & F_ACTIVE_RULESET) {
7449591a9f7Spyr flush_table(env, rdr);
74585a8c65fSreyk log_debug("%s: disabling ruleset", __func__);
7469591a9f7Spyr rdr->conf.flags &= ~(F_ACTIVE_RULESET);
7479591a9f7Spyr id.id = rdr->conf.id;
7489ea8c990Spyr imsg.hdr.type = IMSG_CTL_PULL_RULESET;
7499ea8c990Spyr imsg.hdr.len = sizeof(id) + IMSG_HEADER_SIZE;
7509ea8c990Spyr imsg.data = &id;
7519591a9f7Spyr sync_ruleset(env, rdr, 0);
752c28c61ccSreyk control_imsg_forward(env->sc_ps, &imsg);
753feb9ff76Sreyk }
7549591a9f7Spyr } else if (!(rdr->conf.flags & F_ACTIVE_RULESET)) {
75585a8c65fSreyk log_debug("%s: enabling ruleset", __func__);
7569591a9f7Spyr rdr->conf.flags |= F_ACTIVE_RULESET;
7579591a9f7Spyr id.id = rdr->conf.id;
7589ea8c990Spyr imsg.hdr.type = IMSG_CTL_PUSH_RULESET;
7599ea8c990Spyr imsg.hdr.len = sizeof(id) + IMSG_HEADER_SIZE;
7609ea8c990Spyr imsg.data = &id;
7619591a9f7Spyr sync_ruleset(env, rdr, 1);
762c28c61ccSreyk control_imsg_forward(env->sc_ps, &imsg);
763feb9ff76Sreyk }
764feb9ff76Sreyk }
7652edd718bSreyk
76634438db4Sreyk TAILQ_FOREACH(rt, env->sc_rts, rt_entry) {
76734438db4Sreyk rt->rt_conf.flags &= ~(F_BACKUP);
76834438db4Sreyk rt->rt_conf.flags &= ~(F_DOWN);
76934438db4Sreyk
77034438db4Sreyk if ((rt->rt_gwtable->conf.flags & F_CHANGED))
77134438db4Sreyk sync_routes(env, rt);
77234438db4Sreyk }
77334438db4Sreyk
77435d10c30Sreyk TAILQ_FOREACH(table, env->sc_tables, entry) {
775a2195becSreyk if (table->conf.check == CHECK_NOCHECK)
776a2195becSreyk continue;
777a2195becSreyk
778228f7fe4Spyr /*
779228f7fe4Spyr * clean up change flag.
780228f7fe4Spyr */
781228f7fe4Spyr table->conf.flags &= ~(F_CHANGED);
782228f7fe4Spyr
783228f7fe4Spyr /*
784228f7fe4Spyr * handle demotion.
785228f7fe4Spyr */
78668b79041Spyr if ((table->conf.flags & F_DEMOTE) == 0)
7872edd718bSreyk continue;
7882edd718bSreyk demote.level = 0;
78968b79041Spyr if (table->up && table->conf.flags & F_DEMOTED) {
7902edd718bSreyk demote.level = -1;
79168b79041Spyr table->conf.flags &= ~F_DEMOTED;
7922edd718bSreyk }
79368b79041Spyr else if (!table->up && !(table->conf.flags & F_DEMOTED)) {
7942edd718bSreyk demote.level = 1;
79568b79041Spyr table->conf.flags |= F_DEMOTED;
7962edd718bSreyk }
7972edd718bSreyk if (demote.level == 0)
7982edd718bSreyk continue;
79985a8c65fSreyk log_debug("%s: demote %d table '%s' group '%s'", __func__,
80068b79041Spyr demote.level, table->conf.name, table->conf.demote_group);
80168b79041Spyr (void)strlcpy(demote.group, table->conf.demote_group,
8022edd718bSreyk sizeof(demote.group));
803c2c37c5dSreyk proc_compose(env->sc_ps, PROC_PARENT, IMSG_DEMOTE,
8042edd718bSreyk &demote, sizeof(demote));
8052edd718bSreyk }
806feb9ff76Sreyk }
807dec6607bSreyk
808dec6607bSreyk void
pfe_statistics(int fd,short events,void * arg)809dec6607bSreyk pfe_statistics(int fd, short events, void *arg)
810dec6607bSreyk {
811dec6607bSreyk struct rdr *rdr;
812dec6607bSreyk struct ctl_stats *cur;
813dec6607bSreyk struct timeval tv, tv_now;
814dec6607bSreyk int resethour, resetday;
815dec6607bSreyk u_long cnt;
816dec6607bSreyk
817dec6607bSreyk timerclear(&tv);
818fd1841a3Sreyk getmonotime(&tv_now);
819dec6607bSreyk
82035d10c30Sreyk TAILQ_FOREACH(rdr, env->sc_rdrs, entry) {
821dec6607bSreyk cnt = check_table(env, rdr, rdr->table);
822dec6607bSreyk if (rdr->conf.backup_id != EMPTY_TABLE)
823dec6607bSreyk cnt += check_table(env, rdr, rdr->backup);
824dec6607bSreyk
825dec6607bSreyk resethour = resetday = 0;
826dec6607bSreyk
827dec6607bSreyk cur = &rdr->stats;
828dec6607bSreyk cur->last = cnt > cur->cnt ? cnt - cur->cnt : 0;
829dec6607bSreyk
830dec6607bSreyk cur->cnt = cnt;
831dec6607bSreyk cur->tick++;
832dec6607bSreyk cur->avg = (cur->last + cur->avg) / 2;
833dec6607bSreyk cur->last_hour += cur->last;
834586b5f8aSreyk if ((cur->tick %
835586b5f8aSreyk (3600 / env->sc_conf.statinterval.tv_sec)) == 0) {
836dec6607bSreyk cur->avg_hour = (cur->last_hour + cur->avg_hour) / 2;
837dec6607bSreyk resethour++;
838dec6607bSreyk }
839dec6607bSreyk cur->last_day += cur->last;
840586b5f8aSreyk if ((cur->tick %
841586b5f8aSreyk (86400 / env->sc_conf.statinterval.tv_sec)) == 0) {
842dec6607bSreyk cur->avg_day = (cur->last_day + cur->avg_day) / 2;
843dec6607bSreyk resethour++;
844dec6607bSreyk }
845dec6607bSreyk if (resethour)
846dec6607bSreyk cur->last_hour = 0;
847dec6607bSreyk if (resetday)
848dec6607bSreyk cur->last_day = 0;
849dec6607bSreyk
850586b5f8aSreyk rdr->stats.interval = env->sc_conf.statinterval.tv_sec;
851dec6607bSreyk }
852dec6607bSreyk
853dec6607bSreyk /* Schedule statistics timer */
85435d10c30Sreyk evtimer_set(&env->sc_statev, pfe_statistics, NULL);
855586b5f8aSreyk bcopy(&env->sc_conf.statinterval, &tv, sizeof(tv));
85635d10c30Sreyk evtimer_add(&env->sc_statev, &tv);
857dec6607bSreyk }
858