1 /* $OpenBSD: pfe.c,v 1.70 2011/05/20 09:43:53 reyk Exp $ */ 2 3 /* 4 * Copyright (c) 2006 Pierre-Yves Ritschard <pyr@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/param.h> 20 #include <sys/stat.h> 21 #include <sys/socket.h> 22 #include <sys/un.h> 23 24 #include <net/if.h> 25 26 #include <errno.h> 27 #include <event.h> 28 #include <fcntl.h> 29 #include <stdlib.h> 30 #include <string.h> 31 #include <unistd.h> 32 #include <pwd.h> 33 34 #include <openssl/ssl.h> 35 36 #include "relayd.h" 37 38 void pfe_init(struct privsep *, struct privsep_proc *p, void *); 39 void pfe_shutdown(void); 40 void pfe_setup_events(void); 41 void pfe_disable_events(void); 42 void pfe_sync(void); 43 void pfe_statistics(int, short, void *); 44 45 int pfe_dispatch_parent(int, struct privsep_proc *, struct imsg *); 46 int pfe_dispatch_hce(int, struct privsep_proc *, struct imsg *); 47 int pfe_dispatch_relay(int, struct privsep_proc *, struct imsg *); 48 49 static struct relayd *env = NULL; 50 51 static struct privsep_proc procs[] = { 52 { "parent", PROC_PARENT, pfe_dispatch_parent }, 53 { "relay", PROC_RELAY, pfe_dispatch_relay }, 54 { "hce", PROC_HCE, pfe_dispatch_hce } 55 }; 56 57 pid_t 58 pfe(struct privsep *ps, struct privsep_proc *p) 59 { 60 env = ps->ps_env; 61 62 return (proc_run(ps, p, procs, nitems(procs), pfe_init, NULL)); 63 } 64 65 void 66 pfe_init(struct privsep *ps, struct privsep_proc *p, void *arg) 67 { 68 if (config_init(ps->ps_env) == -1) 69 fatal("failed to initialize configuration"); 70 71 p->p_shutdown = pfe_shutdown; 72 } 73 74 void 75 pfe_shutdown(void) 76 { 77 flush_rulesets(env); 78 config_purge(env, CONFIG_ALL); 79 } 80 81 void 82 pfe_setup_events(void) 83 { 84 struct timeval tv; 85 86 /* Schedule statistics timer */ 87 if (!event_initialized(&env->sc_statev)) { 88 evtimer_set(&env->sc_statev, pfe_statistics, NULL); 89 bcopy(&env->sc_statinterval, &tv, sizeof(tv)); 90 evtimer_add(&env->sc_statev, &tv); 91 } 92 } 93 94 void 95 pfe_disable_events(void) 96 { 97 event_del(&env->sc_statev); 98 } 99 100 int 101 pfe_dispatch_hce(int fd, struct privsep_proc *p, struct imsg *imsg) 102 { 103 struct host *host; 104 struct table *table; 105 struct ctl_status st; 106 107 control_imsg_forward(imsg); 108 109 switch (imsg->hdr.type) { 110 case IMSG_HOST_STATUS: 111 IMSG_SIZE_CHECK(imsg, &st); 112 memcpy(&st, imsg->data, sizeof(st)); 113 if ((host = host_find(env, st.id)) == NULL) 114 fatalx("pfe_dispatch_imsg: invalid host id"); 115 host->he = st.he; 116 if (host->flags & F_DISABLE) 117 break; 118 host->retry_cnt = st.retry_cnt; 119 if (st.up != HOST_UNKNOWN) { 120 host->check_cnt++; 121 if (st.up == HOST_UP) 122 host->up_cnt++; 123 } 124 if (host->check_cnt != st.check_cnt) { 125 log_debug("%s: host %d => %d", __func__, 126 host->conf.id, host->up); 127 fatalx("pfe_dispatch_imsg: desynchronized"); 128 } 129 130 if (host->up == st.up) 131 break; 132 133 /* Forward to relay engine(s) */ 134 proc_compose_imsg(env->sc_ps, PROC_RELAY, -1, 135 IMSG_HOST_STATUS, -1, &st, sizeof(st)); 136 137 if ((table = table_find(env, host->conf.tableid)) 138 == NULL) 139 fatalx("pfe_dispatch_imsg: invalid table id"); 140 141 log_debug("%s: state %d for host %u %s", __func__, 142 st.up, host->conf.id, host->conf.name); 143 144 /* 145 * Do not change the table state when the host 146 * state switches between UNKNOWN and DOWN. 147 */ 148 if (HOST_ISUP(st.up)) { 149 table->conf.flags |= F_CHANGED; 150 table->up++; 151 host->flags |= F_ADD; 152 host->flags &= ~(F_DEL); 153 } else if (HOST_ISUP(host->up)) { 154 table->up--; 155 table->conf.flags |= F_CHANGED; 156 host->flags |= F_DEL; 157 host->flags &= ~(F_ADD); 158 } 159 160 host->up = st.up; 161 break; 162 case IMSG_SYNC: 163 pfe_sync(); 164 break; 165 default: 166 return (-1); 167 } 168 169 return (0); 170 } 171 172 int 173 pfe_dispatch_parent(int fd, struct privsep_proc *p, struct imsg *imsg) 174 { 175 switch (imsg->hdr.type) { 176 case IMSG_CFG_TABLE: 177 config_gettable(env, imsg); 178 break; 179 case IMSG_CFG_HOST: 180 config_gethost(env, imsg); 181 break; 182 case IMSG_CFG_RDR: 183 config_getrdr(env, imsg); 184 break; 185 case IMSG_CFG_VIRT: 186 config_getvirt(env, imsg); 187 break; 188 case IMSG_CFG_ROUTER: 189 config_getrt(env, imsg); 190 break; 191 case IMSG_CFG_ROUTE: 192 config_getroute(env, imsg); 193 break; 194 case IMSG_CFG_PROTO: 195 config_getproto(env, imsg); 196 break; 197 case IMSG_CFG_PROTONODE: 198 break; 199 case IMSG_CFG_RELAY: 200 config_getrelay(env, imsg); 201 break; 202 case IMSG_CFG_DONE: 203 config_getcfg(env, imsg); 204 init_filter(env, imsg->fd); 205 init_tables(env); 206 pfe_setup_events(); 207 pfe_sync(); 208 break; 209 case IMSG_CTL_RESET: 210 config_getreset(env, imsg); 211 break; 212 default: 213 return (-1); 214 } 215 216 return (0); 217 } 218 219 int 220 pfe_dispatch_relay(int fd, struct privsep_proc *p, struct imsg *imsg) 221 { 222 struct ctl_natlook cnl; 223 struct ctl_stats crs; 224 struct relay *rlay; 225 struct ctl_conn *c; 226 struct rsession con; 227 int cid; 228 229 switch (imsg->hdr.type) { 230 case IMSG_NATLOOK: 231 IMSG_SIZE_CHECK(imsg, &cnl); 232 bcopy(imsg->data, &cnl, sizeof(cnl)); 233 if (cnl.proc > env->sc_prefork_relay) 234 fatalx("pfe_dispatch_relay: " 235 "invalid relay proc"); 236 if (natlook(env, &cnl) != 0) 237 cnl.in = -1; 238 proc_compose_imsg(env->sc_ps, PROC_RELAY, cnl.proc, 239 IMSG_NATLOOK, -1, &cnl, sizeof(cnl)); 240 break; 241 case IMSG_STATISTICS: 242 IMSG_SIZE_CHECK(imsg, &crs); 243 bcopy(imsg->data, &crs, sizeof(crs)); 244 if (crs.proc > env->sc_prefork_relay) 245 fatalx("pfe_dispatch_relay: " 246 "invalid relay proc"); 247 if ((rlay = relay_find(env, crs.id)) == NULL) 248 fatalx("pfe_dispatch_relay: invalid relay id"); 249 bcopy(&crs, &rlay->rl_stats[crs.proc], sizeof(crs)); 250 rlay->rl_stats[crs.proc].interval = 251 env->sc_statinterval.tv_sec; 252 break; 253 case IMSG_CTL_SESSION: 254 IMSG_SIZE_CHECK(imsg, &con); 255 memcpy(&con, imsg->data, sizeof(con)); 256 if ((c = control_connbyfd(con.se_cid)) == NULL) { 257 log_debug("%s: control connection %d not found", 258 __func__, con.se_cid); 259 return (0); 260 } 261 imsg_compose_event(&c->iev, 262 IMSG_CTL_SESSION, 0, 0, -1, 263 &con, sizeof(con)); 264 break; 265 case IMSG_CTL_END: 266 IMSG_SIZE_CHECK(imsg, &cid); 267 memcpy(&cid, imsg->data, sizeof(cid)); 268 if ((c = control_connbyfd(cid)) == NULL) { 269 log_debug("%s: control connection %d not found", 270 __func__, cid); 271 return (0); 272 } 273 if (c->waiting == 0) { 274 log_debug("%s: no pending control requests", __func__); 275 return (0); 276 } else if (--c->waiting == 0) { 277 /* Last ack for a previous request */ 278 imsg_compose_event(&c->iev, IMSG_CTL_END, 279 0, 0, -1, NULL, 0); 280 } 281 break; 282 default: 283 return (-1); 284 } 285 286 return (0); 287 } 288 289 void 290 show(struct ctl_conn *c) 291 { 292 struct rdr *rdr; 293 struct host *host; 294 struct relay *rlay; 295 struct router *rt; 296 struct netroute *nr; 297 298 if (env->sc_rdrs == NULL) 299 goto relays; 300 TAILQ_FOREACH(rdr, env->sc_rdrs, entry) { 301 imsg_compose_event(&c->iev, IMSG_CTL_RDR, 0, 0, -1, 302 rdr, sizeof(*rdr)); 303 if (rdr->conf.flags & F_DISABLE) 304 continue; 305 306 imsg_compose_event(&c->iev, IMSG_CTL_RDR_STATS, 0, 0, -1, 307 &rdr->stats, sizeof(rdr->stats)); 308 309 imsg_compose_event(&c->iev, IMSG_CTL_TABLE, 0, 0, -1, 310 rdr->table, sizeof(*rdr->table)); 311 if (!(rdr->table->conf.flags & F_DISABLE)) 312 TAILQ_FOREACH(host, &rdr->table->hosts, entry) 313 imsg_compose_event(&c->iev, IMSG_CTL_HOST, 314 0, 0, -1, host, sizeof(*host)); 315 316 if (rdr->backup->conf.id == EMPTY_TABLE) 317 continue; 318 imsg_compose_event(&c->iev, IMSG_CTL_TABLE, 0, 0, -1, 319 rdr->backup, sizeof(*rdr->backup)); 320 if (!(rdr->backup->conf.flags & F_DISABLE)) 321 TAILQ_FOREACH(host, &rdr->backup->hosts, entry) 322 imsg_compose_event(&c->iev, IMSG_CTL_HOST, 323 0, 0, -1, host, sizeof(*host)); 324 } 325 relays: 326 if (env->sc_relays == NULL) 327 goto routers; 328 TAILQ_FOREACH(rlay, env->sc_relays, rl_entry) { 329 rlay->rl_stats[env->sc_prefork_relay].id = EMPTY_ID; 330 imsg_compose_event(&c->iev, IMSG_CTL_RELAY, 0, 0, -1, 331 rlay, sizeof(*rlay)); 332 imsg_compose_event(&c->iev, IMSG_CTL_RELAY_STATS, 0, 0, -1, 333 &rlay->rl_stats, sizeof(rlay->rl_stats)); 334 335 if (rlay->rl_dsttable == NULL) 336 continue; 337 imsg_compose_event(&c->iev, IMSG_CTL_TABLE, 0, 0, -1, 338 rlay->rl_dsttable, sizeof(*rlay->rl_dsttable)); 339 if (!(rlay->rl_dsttable->conf.flags & F_DISABLE)) 340 TAILQ_FOREACH(host, &rlay->rl_dsttable->hosts, entry) 341 imsg_compose_event(&c->iev, IMSG_CTL_HOST, 342 0, 0, -1, host, sizeof(*host)); 343 344 if (rlay->rl_conf.backuptable == EMPTY_TABLE) 345 continue; 346 imsg_compose_event(&c->iev, IMSG_CTL_TABLE, 0, 0, -1, 347 rlay->rl_backuptable, sizeof(*rlay->rl_backuptable)); 348 if (!(rlay->rl_backuptable->conf.flags & F_DISABLE)) 349 TAILQ_FOREACH(host, &rlay->rl_backuptable->hosts, entry) 350 imsg_compose_event(&c->iev, IMSG_CTL_HOST, 351 0, 0, -1, host, sizeof(*host)); 352 } 353 354 routers: 355 if (env->sc_rts == NULL) 356 goto end; 357 TAILQ_FOREACH(rt, env->sc_rts, rt_entry) { 358 imsg_compose_event(&c->iev, IMSG_CTL_ROUTER, 0, 0, -1, 359 rt, sizeof(*rt)); 360 if (rt->rt_conf.flags & F_DISABLE) 361 continue; 362 363 TAILQ_FOREACH(nr, &rt->rt_netroutes, nr_entry) 364 imsg_compose_event(&c->iev, IMSG_CTL_NETROUTE, 365 0, 0, -1, nr, sizeof(*nr)); 366 imsg_compose_event(&c->iev, IMSG_CTL_TABLE, 0, 0, -1, 367 rt->rt_gwtable, sizeof(*rt->rt_gwtable)); 368 if (!(rt->rt_gwtable->conf.flags & F_DISABLE)) 369 TAILQ_FOREACH(host, &rt->rt_gwtable->hosts, entry) 370 imsg_compose_event(&c->iev, IMSG_CTL_HOST, 371 0, 0, -1, host, sizeof(*host)); 372 } 373 374 end: 375 imsg_compose_event(&c->iev, IMSG_CTL_END, 0, 0, -1, NULL, 0); 376 } 377 378 void 379 show_sessions(struct ctl_conn *c) 380 { 381 int proc, cid; 382 383 for (proc = 0; proc < env->sc_prefork_relay; proc++) { 384 cid = c->iev.ibuf.fd; 385 386 /* 387 * Request all the running sessions from the process 388 */ 389 proc_compose_imsg(env->sc_ps, PROC_RELAY, proc, 390 IMSG_CTL_SESSION, -1, &cid, sizeof(cid)); 391 c->waiting++; 392 } 393 } 394 395 int 396 disable_rdr(struct ctl_conn *c, struct ctl_id *id) 397 { 398 struct rdr *rdr; 399 400 if (id->id == EMPTY_ID) 401 rdr = rdr_findbyname(env, id->name); 402 else 403 rdr = rdr_find(env, id->id); 404 if (rdr == NULL) 405 return (-1); 406 id->id = rdr->conf.id; 407 408 if (rdr->conf.flags & F_DISABLE) 409 return (0); 410 411 rdr->conf.flags |= F_DISABLE; 412 rdr->conf.flags &= ~(F_ADD); 413 rdr->conf.flags |= F_DEL; 414 rdr->table->conf.flags |= F_DISABLE; 415 log_debug("%s: redirect %d", __func__, rdr->conf.id); 416 pfe_sync(); 417 return (0); 418 } 419 420 int 421 enable_rdr(struct ctl_conn *c, struct ctl_id *id) 422 { 423 struct rdr *rdr; 424 struct ctl_id eid; 425 426 if (id->id == EMPTY_ID) 427 rdr = rdr_findbyname(env, id->name); 428 else 429 rdr = rdr_find(env, id->id); 430 if (rdr == NULL) 431 return (-1); 432 id->id = rdr->conf.id; 433 434 if (!(rdr->conf.flags & F_DISABLE)) 435 return (0); 436 437 rdr->conf.flags &= ~(F_DISABLE); 438 rdr->conf.flags &= ~(F_DEL); 439 rdr->conf.flags |= F_ADD; 440 log_debug("%s: redirect %d", __func__, rdr->conf.id); 441 442 bzero(&eid, sizeof(eid)); 443 444 /* XXX: we're syncing twice */ 445 eid.id = rdr->table->conf.id; 446 if (enable_table(c, &eid) == -1) 447 return (-1); 448 if (rdr->backup->conf.id == EMPTY_ID) 449 return (0); 450 eid.id = rdr->backup->conf.id; 451 if (enable_table(c, &eid) == -1) 452 return (-1); 453 return (0); 454 } 455 456 int 457 disable_table(struct ctl_conn *c, struct ctl_id *id) 458 { 459 struct table *table; 460 struct host *host; 461 462 if (id->id == EMPTY_ID) 463 table = table_findbyname(env, id->name); 464 else 465 table = table_find(env, id->id); 466 if (table == NULL) 467 return (-1); 468 id->id = table->conf.id; 469 if (table->conf.rdrid > 0 && rdr_find(env, table->conf.rdrid) == NULL) 470 fatalx("disable_table: desynchronised"); 471 472 if (table->conf.flags & F_DISABLE) 473 return (0); 474 table->conf.flags |= (F_DISABLE|F_CHANGED); 475 table->up = 0; 476 TAILQ_FOREACH(host, &table->hosts, entry) 477 host->up = HOST_UNKNOWN; 478 proc_compose_imsg(env->sc_ps, PROC_HCE, -1, IMSG_TABLE_DISABLE, -1, 479 &table->conf.id, sizeof(table->conf.id)); 480 481 /* Forward to relay engine(s) */ 482 proc_compose_imsg(env->sc_ps, PROC_RELAY, -1, IMSG_TABLE_DISABLE, -1, 483 &table->conf.id, sizeof(table->conf.id)); 484 485 log_debug("%s: table %d", __func__, table->conf.id); 486 pfe_sync(); 487 return (0); 488 } 489 490 int 491 enable_table(struct ctl_conn *c, struct ctl_id *id) 492 { 493 struct table *table; 494 struct host *host; 495 496 if (id->id == EMPTY_ID) 497 table = table_findbyname(env, id->name); 498 else 499 table = table_find(env, id->id); 500 if (table == NULL) 501 return (-1); 502 id->id = table->conf.id; 503 504 if (table->conf.rdrid > 0 && rdr_find(env, table->conf.rdrid) == NULL) 505 fatalx("enable_table: desynchronised"); 506 507 if (!(table->conf.flags & F_DISABLE)) 508 return (0); 509 table->conf.flags &= ~(F_DISABLE); 510 table->conf.flags |= F_CHANGED; 511 table->up = 0; 512 TAILQ_FOREACH(host, &table->hosts, entry) 513 host->up = HOST_UNKNOWN; 514 proc_compose_imsg(env->sc_ps, PROC_HCE, -1, IMSG_TABLE_ENABLE, -1, 515 &table->conf.id, sizeof(table->conf.id)); 516 517 /* Forward to relay engine(s) */ 518 proc_compose_imsg(env->sc_ps, PROC_RELAY, -1, IMSG_TABLE_ENABLE, -1, 519 &table->conf.id, sizeof(table->conf.id)); 520 521 log_debug("%s: table %d", __func__, table->conf.id); 522 pfe_sync(); 523 return (0); 524 } 525 526 int 527 disable_host(struct ctl_conn *c, struct ctl_id *id, struct host *host) 528 { 529 struct host *h; 530 struct table *table; 531 532 if (host == NULL) { 533 if (id->id == EMPTY_ID) 534 host = host_findbyname(env, id->name); 535 else 536 host = host_find(env, id->id); 537 if (host == NULL || host->conf.parentid) 538 return (-1); 539 } 540 id->id = host->conf.id; 541 542 if (host->flags & F_DISABLE) 543 return (0); 544 545 if (host->up == HOST_UP) { 546 if ((table = table_find(env, host->conf.tableid)) == NULL) 547 fatalx("disable_host: invalid table id"); 548 table->up--; 549 table->conf.flags |= F_CHANGED; 550 } 551 552 host->up = HOST_UNKNOWN; 553 host->flags |= F_DISABLE; 554 host->flags |= F_DEL; 555 host->flags &= ~(F_ADD); 556 host->check_cnt = 0; 557 host->up_cnt = 0; 558 559 proc_compose_imsg(env->sc_ps, PROC_HCE, -1, IMSG_HOST_DISABLE, -1, 560 &host->conf.id, sizeof(host->conf.id)); 561 562 /* Forward to relay engine(s) */ 563 proc_compose_imsg(env->sc_ps, PROC_RELAY, -1, IMSG_HOST_DISABLE, -1, 564 &host->conf.id, sizeof(host->conf.id)); 565 log_debug("%s: host %d", __func__, host->conf.id); 566 567 if (!host->conf.parentid) { 568 /* Disable all children */ 569 SLIST_FOREACH(h, &host->children, child) 570 disable_host(c, id, h); 571 pfe_sync(); 572 } 573 return (0); 574 } 575 576 int 577 enable_host(struct ctl_conn *c, struct ctl_id *id, struct host *host) 578 { 579 struct host *h; 580 581 if (host == NULL) { 582 if (id->id == EMPTY_ID) 583 host = host_findbyname(env, id->name); 584 else 585 host = host_find(env, id->id); 586 if (host == NULL || host->conf.parentid) 587 return (-1); 588 } 589 id->id = host->conf.id; 590 591 if (!(host->flags & F_DISABLE)) 592 return (0); 593 594 host->up = HOST_UNKNOWN; 595 host->flags &= ~(F_DISABLE); 596 host->flags &= ~(F_DEL); 597 host->flags &= ~(F_ADD); 598 599 proc_compose_imsg(env->sc_ps, PROC_HCE, -1, IMSG_HOST_ENABLE, -1, 600 &host->conf.id, sizeof (host->conf.id)); 601 602 /* Forward to relay engine(s) */ 603 proc_compose_imsg(env->sc_ps, PROC_RELAY, -1, IMSG_HOST_ENABLE, -1, 604 &host->conf.id, sizeof(host->conf.id)); 605 606 log_debug("%s: host %d", __func__, host->conf.id); 607 608 if (!host->conf.parentid) { 609 /* Enable all children */ 610 SLIST_FOREACH(h, &host->children, child) 611 enable_host(c, id, h); 612 pfe_sync(); 613 } 614 return (0); 615 } 616 617 void 618 pfe_sync(void) 619 { 620 struct rdr *rdr; 621 struct table *active; 622 struct table *table; 623 struct ctl_id id; 624 struct imsg imsg; 625 struct ctl_demote demote; 626 struct router *rt; 627 628 bzero(&id, sizeof(id)); 629 bzero(&imsg, sizeof(imsg)); 630 TAILQ_FOREACH(rdr, env->sc_rdrs, entry) { 631 rdr->conf.flags &= ~(F_BACKUP); 632 rdr->conf.flags &= ~(F_DOWN); 633 634 if (rdr->conf.flags & F_DISABLE || 635 (rdr->table->up == 0 && rdr->backup->up == 0)) { 636 rdr->conf.flags |= F_DOWN; 637 active = NULL; 638 } else if (rdr->table->up == 0 && rdr->backup->up > 0) { 639 rdr->conf.flags |= F_BACKUP; 640 active = rdr->backup; 641 active->conf.flags |= 642 rdr->table->conf.flags & F_CHANGED; 643 active->conf.flags |= 644 rdr->backup->conf.flags & F_CHANGED; 645 } else 646 active = rdr->table; 647 648 if (active != NULL && active->conf.flags & F_CHANGED) { 649 id.id = active->conf.id; 650 imsg.hdr.type = IMSG_CTL_TABLE_CHANGED; 651 imsg.hdr.len = sizeof(id) + IMSG_HEADER_SIZE; 652 imsg.data = &id; 653 sync_table(env, rdr, active); 654 control_imsg_forward(&imsg); 655 } 656 657 if (rdr->conf.flags & F_DOWN) { 658 if (rdr->conf.flags & F_ACTIVE_RULESET) { 659 flush_table(env, rdr); 660 log_debug("%s: disabling ruleset", __func__); 661 rdr->conf.flags &= ~(F_ACTIVE_RULESET); 662 id.id = rdr->conf.id; 663 imsg.hdr.type = IMSG_CTL_PULL_RULESET; 664 imsg.hdr.len = sizeof(id) + IMSG_HEADER_SIZE; 665 imsg.data = &id; 666 sync_ruleset(env, rdr, 0); 667 control_imsg_forward(&imsg); 668 } 669 } else if (!(rdr->conf.flags & F_ACTIVE_RULESET)) { 670 log_debug("%s: enabling ruleset", __func__); 671 rdr->conf.flags |= F_ACTIVE_RULESET; 672 id.id = rdr->conf.id; 673 imsg.hdr.type = IMSG_CTL_PUSH_RULESET; 674 imsg.hdr.len = sizeof(id) + IMSG_HEADER_SIZE; 675 imsg.data = &id; 676 sync_ruleset(env, rdr, 1); 677 control_imsg_forward(&imsg); 678 } 679 } 680 681 TAILQ_FOREACH(rt, env->sc_rts, rt_entry) { 682 rt->rt_conf.flags &= ~(F_BACKUP); 683 rt->rt_conf.flags &= ~(F_DOWN); 684 685 if ((rt->rt_gwtable->conf.flags & F_CHANGED)) 686 sync_routes(env, rt); 687 } 688 689 TAILQ_FOREACH(table, env->sc_tables, entry) { 690 if (table->conf.check == CHECK_NOCHECK) 691 continue; 692 693 /* 694 * clean up change flag. 695 */ 696 table->conf.flags &= ~(F_CHANGED); 697 698 /* 699 * handle demotion. 700 */ 701 if ((table->conf.flags & F_DEMOTE) == 0) 702 continue; 703 demote.level = 0; 704 if (table->up && table->conf.flags & F_DEMOTED) { 705 demote.level = -1; 706 table->conf.flags &= ~F_DEMOTED; 707 } 708 else if (!table->up && !(table->conf.flags & F_DEMOTED)) { 709 demote.level = 1; 710 table->conf.flags |= F_DEMOTED; 711 } 712 if (demote.level == 0) 713 continue; 714 log_debug("%s: demote %d table '%s' group '%s'", __func__, 715 demote.level, table->conf.name, table->conf.demote_group); 716 (void)strlcpy(demote.group, table->conf.demote_group, 717 sizeof(demote.group)); 718 proc_compose_imsg(env->sc_ps, PROC_PARENT, -1, IMSG_DEMOTE, -1, 719 &demote, sizeof(demote)); 720 } 721 } 722 723 void 724 pfe_statistics(int fd, short events, void *arg) 725 { 726 struct rdr *rdr; 727 struct ctl_stats *cur; 728 struct timeval tv, tv_now; 729 int resethour, resetday; 730 u_long cnt; 731 732 timerclear(&tv); 733 if (gettimeofday(&tv_now, NULL) == -1) 734 fatal("pfe_statistics: gettimeofday"); 735 736 TAILQ_FOREACH(rdr, env->sc_rdrs, entry) { 737 cnt = check_table(env, rdr, rdr->table); 738 if (rdr->conf.backup_id != EMPTY_TABLE) 739 cnt += check_table(env, rdr, rdr->backup); 740 741 resethour = resetday = 0; 742 743 cur = &rdr->stats; 744 cur->last = cnt > cur->cnt ? cnt - cur->cnt : 0; 745 746 cur->cnt = cnt; 747 cur->tick++; 748 cur->avg = (cur->last + cur->avg) / 2; 749 cur->last_hour += cur->last; 750 if ((cur->tick % (3600 / env->sc_statinterval.tv_sec)) == 0) { 751 cur->avg_hour = (cur->last_hour + cur->avg_hour) / 2; 752 resethour++; 753 } 754 cur->last_day += cur->last; 755 if ((cur->tick % (86400 / env->sc_statinterval.tv_sec)) == 0) { 756 cur->avg_day = (cur->last_day + cur->avg_day) / 2; 757 resethour++; 758 } 759 if (resethour) 760 cur->last_hour = 0; 761 if (resetday) 762 cur->last_day = 0; 763 764 rdr->stats.interval = env->sc_statinterval.tv_sec; 765 } 766 767 /* Schedule statistics timer */ 768 evtimer_set(&env->sc_statev, pfe_statistics, NULL); 769 bcopy(&env->sc_statinterval, &tv, sizeof(tv)); 770 evtimer_add(&env->sc_statev, &tv); 771 } 772