1 /* $OpenBSD: pfe.c,v 1.74 2013/03/10 23:32: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_hce: 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_hce: 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_hce: 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_RELAY_TABLE: 203 config_getrelaytable(env, imsg); 204 break; 205 case IMSG_CFG_DONE: 206 config_getcfg(env, imsg); 207 init_filter(env, imsg->fd); 208 init_tables(env); 209 break; 210 case IMSG_CTL_START: 211 pfe_setup_events(); 212 pfe_sync(); 213 break; 214 case IMSG_CTL_RESET: 215 config_getreset(env, imsg); 216 break; 217 default: 218 return (-1); 219 } 220 221 return (0); 222 } 223 224 int 225 pfe_dispatch_relay(int fd, struct privsep_proc *p, struct imsg *imsg) 226 { 227 struct ctl_natlook cnl; 228 struct ctl_stats crs; 229 struct relay *rlay; 230 struct ctl_conn *c; 231 struct rsession con; 232 int cid; 233 234 switch (imsg->hdr.type) { 235 case IMSG_NATLOOK: 236 IMSG_SIZE_CHECK(imsg, &cnl); 237 bcopy(imsg->data, &cnl, sizeof(cnl)); 238 if (cnl.proc > env->sc_prefork_relay) 239 fatalx("pfe_dispatch_relay: " 240 "invalid relay proc"); 241 if (natlook(env, &cnl) != 0) 242 cnl.in = -1; 243 proc_compose_imsg(env->sc_ps, PROC_RELAY, cnl.proc, 244 IMSG_NATLOOK, -1, &cnl, sizeof(cnl)); 245 break; 246 case IMSG_STATISTICS: 247 IMSG_SIZE_CHECK(imsg, &crs); 248 bcopy(imsg->data, &crs, sizeof(crs)); 249 if (crs.proc > env->sc_prefork_relay) 250 fatalx("pfe_dispatch_relay: " 251 "invalid relay proc"); 252 if ((rlay = relay_find(env, crs.id)) == NULL) 253 fatalx("pfe_dispatch_relay: invalid relay id"); 254 bcopy(&crs, &rlay->rl_stats[crs.proc], sizeof(crs)); 255 rlay->rl_stats[crs.proc].interval = 256 env->sc_statinterval.tv_sec; 257 break; 258 case IMSG_CTL_SESSION: 259 IMSG_SIZE_CHECK(imsg, &con); 260 memcpy(&con, imsg->data, sizeof(con)); 261 if ((c = control_connbyfd(con.se_cid)) == NULL) { 262 log_debug("%s: control connection %d not found", 263 __func__, con.se_cid); 264 return (0); 265 } 266 imsg_compose_event(&c->iev, 267 IMSG_CTL_SESSION, 0, 0, -1, 268 &con, sizeof(con)); 269 break; 270 case IMSG_CTL_END: 271 IMSG_SIZE_CHECK(imsg, &cid); 272 memcpy(&cid, imsg->data, sizeof(cid)); 273 if ((c = control_connbyfd(cid)) == NULL) { 274 log_debug("%s: control connection %d not found", 275 __func__, cid); 276 return (0); 277 } 278 if (c->waiting == 0) { 279 log_debug("%s: no pending control requests", __func__); 280 return (0); 281 } else if (--c->waiting == 0) { 282 /* Last ack for a previous request */ 283 imsg_compose_event(&c->iev, IMSG_CTL_END, 284 0, 0, -1, NULL, 0); 285 } 286 break; 287 default: 288 return (-1); 289 } 290 291 return (0); 292 } 293 294 void 295 show(struct ctl_conn *c) 296 { 297 struct rdr *rdr; 298 struct host *host; 299 struct relay *rlay; 300 struct router *rt; 301 struct netroute *nr; 302 struct relay_table *rlt; 303 304 if (env->sc_rdrs == NULL) 305 goto relays; 306 TAILQ_FOREACH(rdr, env->sc_rdrs, entry) { 307 imsg_compose_event(&c->iev, IMSG_CTL_RDR, 0, 0, -1, 308 rdr, sizeof(*rdr)); 309 if (rdr->conf.flags & F_DISABLE) 310 continue; 311 312 imsg_compose_event(&c->iev, IMSG_CTL_RDR_STATS, 0, 0, -1, 313 &rdr->stats, sizeof(rdr->stats)); 314 315 imsg_compose_event(&c->iev, IMSG_CTL_TABLE, 0, 0, -1, 316 rdr->table, sizeof(*rdr->table)); 317 if (!(rdr->table->conf.flags & F_DISABLE)) 318 TAILQ_FOREACH(host, &rdr->table->hosts, entry) 319 imsg_compose_event(&c->iev, IMSG_CTL_HOST, 320 0, 0, -1, host, sizeof(*host)); 321 322 if (rdr->backup->conf.id == EMPTY_TABLE) 323 continue; 324 imsg_compose_event(&c->iev, IMSG_CTL_TABLE, 0, 0, -1, 325 rdr->backup, sizeof(*rdr->backup)); 326 if (!(rdr->backup->conf.flags & F_DISABLE)) 327 TAILQ_FOREACH(host, &rdr->backup->hosts, entry) 328 imsg_compose_event(&c->iev, IMSG_CTL_HOST, 329 0, 0, -1, host, sizeof(*host)); 330 } 331 relays: 332 if (env->sc_relays == NULL) 333 goto routers; 334 TAILQ_FOREACH(rlay, env->sc_relays, rl_entry) { 335 rlay->rl_stats[env->sc_prefork_relay].id = EMPTY_ID; 336 imsg_compose_event(&c->iev, IMSG_CTL_RELAY, 0, 0, -1, 337 rlay, sizeof(*rlay)); 338 imsg_compose_event(&c->iev, IMSG_CTL_RELAY_STATS, 0, 0, -1, 339 &rlay->rl_stats, sizeof(rlay->rl_stats)); 340 341 TAILQ_FOREACH(rlt, &rlay->rl_tables, rlt_entry) { 342 imsg_compose_event(&c->iev, IMSG_CTL_TABLE, 0, 0, -1, 343 rlt->rlt_table, sizeof(*rlt->rlt_table)); 344 if (!(rlt->rlt_table->conf.flags & F_DISABLE)) 345 TAILQ_FOREACH(host, 346 &rlt->rlt_table->hosts, entry) 347 imsg_compose_event(&c->iev, 348 IMSG_CTL_HOST, 0, 0, -1, 349 host, sizeof(*host)); 350 } 351 } 352 353 routers: 354 if (env->sc_rts == NULL) 355 goto end; 356 TAILQ_FOREACH(rt, env->sc_rts, rt_entry) { 357 imsg_compose_event(&c->iev, IMSG_CTL_ROUTER, 0, 0, -1, 358 rt, sizeof(*rt)); 359 if (rt->rt_conf.flags & F_DISABLE) 360 continue; 361 362 TAILQ_FOREACH(nr, &rt->rt_netroutes, nr_entry) 363 imsg_compose_event(&c->iev, IMSG_CTL_NETROUTE, 364 0, 0, -1, nr, sizeof(*nr)); 365 imsg_compose_event(&c->iev, IMSG_CTL_TABLE, 0, 0, -1, 366 rt->rt_gwtable, sizeof(*rt->rt_gwtable)); 367 if (!(rt->rt_gwtable->conf.flags & F_DISABLE)) 368 TAILQ_FOREACH(host, &rt->rt_gwtable->hosts, entry) 369 imsg_compose_event(&c->iev, IMSG_CTL_HOST, 370 0, 0, -1, host, sizeof(*host)); 371 } 372 373 end: 374 imsg_compose_event(&c->iev, IMSG_CTL_END, 0, 0, -1, NULL, 0); 375 } 376 377 void 378 show_sessions(struct ctl_conn *c) 379 { 380 int proc, cid; 381 382 for (proc = 0; proc < env->sc_prefork_relay; proc++) { 383 cid = c->iev.ibuf.fd; 384 385 /* 386 * Request all the running sessions from the process 387 */ 388 proc_compose_imsg(env->sc_ps, PROC_RELAY, proc, 389 IMSG_CTL_SESSION, -1, &cid, sizeof(cid)); 390 c->waiting++; 391 } 392 } 393 394 int 395 disable_rdr(struct ctl_conn *c, struct ctl_id *id) 396 { 397 struct rdr *rdr; 398 399 if (id->id == EMPTY_ID) 400 rdr = rdr_findbyname(env, id->name); 401 else 402 rdr = rdr_find(env, id->id); 403 if (rdr == NULL) 404 return (-1); 405 id->id = rdr->conf.id; 406 407 if (rdr->conf.flags & F_DISABLE) 408 return (0); 409 410 rdr->conf.flags |= F_DISABLE; 411 rdr->conf.flags &= ~(F_ADD); 412 rdr->conf.flags |= F_DEL; 413 rdr->table->conf.flags |= F_DISABLE; 414 log_debug("%s: redirect %d", __func__, rdr->conf.id); 415 pfe_sync(); 416 return (0); 417 } 418 419 int 420 enable_rdr(struct ctl_conn *c, struct ctl_id *id) 421 { 422 struct rdr *rdr; 423 struct ctl_id eid; 424 425 if (id->id == EMPTY_ID) 426 rdr = rdr_findbyname(env, id->name); 427 else 428 rdr = rdr_find(env, id->id); 429 if (rdr == NULL) 430 return (-1); 431 id->id = rdr->conf.id; 432 433 if (!(rdr->conf.flags & F_DISABLE)) 434 return (0); 435 436 rdr->conf.flags &= ~(F_DISABLE); 437 rdr->conf.flags &= ~(F_DEL); 438 rdr->conf.flags |= F_ADD; 439 log_debug("%s: redirect %d", __func__, rdr->conf.id); 440 441 bzero(&eid, sizeof(eid)); 442 443 /* XXX: we're syncing twice */ 444 eid.id = rdr->table->conf.id; 445 if (enable_table(c, &eid) == -1) 446 return (-1); 447 if (rdr->backup->conf.id == EMPTY_ID) 448 return (0); 449 eid.id = rdr->backup->conf.id; 450 if (enable_table(c, &eid) == -1) 451 return (-1); 452 return (0); 453 } 454 455 int 456 disable_table(struct ctl_conn *c, struct ctl_id *id) 457 { 458 struct table *table; 459 struct host *host; 460 461 if (id->id == EMPTY_ID) 462 table = table_findbyname(env, id->name); 463 else 464 table = table_find(env, id->id); 465 if (table == NULL) 466 return (-1); 467 id->id = table->conf.id; 468 if (table->conf.rdrid > 0 && rdr_find(env, table->conf.rdrid) == NULL) 469 fatalx("disable_table: desynchronised"); 470 471 if (table->conf.flags & F_DISABLE) 472 return (0); 473 table->conf.flags |= (F_DISABLE|F_CHANGED); 474 table->up = 0; 475 TAILQ_FOREACH(host, &table->hosts, entry) 476 host->up = HOST_UNKNOWN; 477 proc_compose_imsg(env->sc_ps, PROC_HCE, -1, IMSG_TABLE_DISABLE, -1, 478 &table->conf.id, sizeof(table->conf.id)); 479 480 /* Forward to relay engine(s) */ 481 proc_compose_imsg(env->sc_ps, PROC_RELAY, -1, IMSG_TABLE_DISABLE, -1, 482 &table->conf.id, sizeof(table->conf.id)); 483 484 log_debug("%s: table %d", __func__, table->conf.id); 485 pfe_sync(); 486 return (0); 487 } 488 489 int 490 enable_table(struct ctl_conn *c, struct ctl_id *id) 491 { 492 struct table *table; 493 struct host *host; 494 495 if (id->id == EMPTY_ID) 496 table = table_findbyname(env, id->name); 497 else 498 table = table_find(env, id->id); 499 if (table == NULL) 500 return (-1); 501 id->id = table->conf.id; 502 503 if (table->conf.rdrid > 0 && rdr_find(env, table->conf.rdrid) == NULL) 504 fatalx("enable_table: desynchronised"); 505 506 if (!(table->conf.flags & F_DISABLE)) 507 return (0); 508 table->conf.flags &= ~(F_DISABLE); 509 table->conf.flags |= F_CHANGED; 510 table->up = 0; 511 TAILQ_FOREACH(host, &table->hosts, entry) 512 host->up = HOST_UNKNOWN; 513 proc_compose_imsg(env->sc_ps, PROC_HCE, -1, IMSG_TABLE_ENABLE, -1, 514 &table->conf.id, sizeof(table->conf.id)); 515 516 /* Forward to relay engine(s) */ 517 proc_compose_imsg(env->sc_ps, PROC_RELAY, -1, IMSG_TABLE_ENABLE, -1, 518 &table->conf.id, sizeof(table->conf.id)); 519 520 log_debug("%s: table %d", __func__, table->conf.id); 521 pfe_sync(); 522 return (0); 523 } 524 525 int 526 disable_host(struct ctl_conn *c, struct ctl_id *id, struct host *host) 527 { 528 struct host *h; 529 struct table *table; 530 531 if (host == NULL) { 532 if (id->id == EMPTY_ID) 533 host = host_findbyname(env, id->name); 534 else 535 host = host_find(env, id->id); 536 if (host == NULL || host->conf.parentid) 537 return (-1); 538 } 539 id->id = host->conf.id; 540 541 if (host->flags & F_DISABLE) 542 return (0); 543 544 if (host->up == HOST_UP) { 545 if ((table = table_find(env, host->conf.tableid)) == NULL) 546 fatalx("disable_host: invalid table id"); 547 table->up--; 548 table->conf.flags |= F_CHANGED; 549 } 550 551 host->up = HOST_UNKNOWN; 552 host->flags |= F_DISABLE; 553 host->flags |= F_DEL; 554 host->flags &= ~(F_ADD); 555 host->check_cnt = 0; 556 host->up_cnt = 0; 557 558 proc_compose_imsg(env->sc_ps, PROC_HCE, -1, IMSG_HOST_DISABLE, -1, 559 &host->conf.id, sizeof(host->conf.id)); 560 561 /* Forward to relay engine(s) */ 562 proc_compose_imsg(env->sc_ps, PROC_RELAY, -1, IMSG_HOST_DISABLE, -1, 563 &host->conf.id, sizeof(host->conf.id)); 564 log_debug("%s: host %d", __func__, host->conf.id); 565 566 if (!host->conf.parentid) { 567 /* Disable all children */ 568 SLIST_FOREACH(h, &host->children, child) 569 disable_host(c, id, h); 570 pfe_sync(); 571 } 572 return (0); 573 } 574 575 int 576 enable_host(struct ctl_conn *c, struct ctl_id *id, struct host *host) 577 { 578 struct host *h; 579 580 if (host == NULL) { 581 if (id->id == EMPTY_ID) 582 host = host_findbyname(env, id->name); 583 else 584 host = host_find(env, id->id); 585 if (host == NULL || host->conf.parentid) 586 return (-1); 587 } 588 id->id = host->conf.id; 589 590 if (!(host->flags & F_DISABLE)) 591 return (0); 592 593 host->up = HOST_UNKNOWN; 594 host->flags &= ~(F_DISABLE); 595 host->flags &= ~(F_DEL); 596 host->flags &= ~(F_ADD); 597 598 proc_compose_imsg(env->sc_ps, PROC_HCE, -1, IMSG_HOST_ENABLE, -1, 599 &host->conf.id, sizeof (host->conf.id)); 600 601 /* Forward to relay engine(s) */ 602 proc_compose_imsg(env->sc_ps, PROC_RELAY, -1, IMSG_HOST_ENABLE, -1, 603 &host->conf.id, sizeof(host->conf.id)); 604 605 log_debug("%s: host %d", __func__, host->conf.id); 606 607 if (!host->conf.parentid) { 608 /* Enable all children */ 609 SLIST_FOREACH(h, &host->children, child) 610 enable_host(c, id, h); 611 pfe_sync(); 612 } 613 return (0); 614 } 615 616 void 617 pfe_sync(void) 618 { 619 struct rdr *rdr; 620 struct table *active; 621 struct table *table; 622 struct ctl_id id; 623 struct imsg imsg; 624 struct ctl_demote demote; 625 struct router *rt; 626 627 bzero(&id, sizeof(id)); 628 bzero(&imsg, sizeof(imsg)); 629 TAILQ_FOREACH(rdr, env->sc_rdrs, entry) { 630 rdr->conf.flags &= ~(F_BACKUP); 631 rdr->conf.flags &= ~(F_DOWN); 632 633 if (rdr->conf.flags & F_DISABLE || 634 (rdr->table->up == 0 && rdr->backup->up == 0)) { 635 rdr->conf.flags |= F_DOWN; 636 active = NULL; 637 } else if (rdr->table->up == 0 && rdr->backup->up > 0) { 638 rdr->conf.flags |= F_BACKUP; 639 active = rdr->backup; 640 active->conf.flags |= 641 rdr->table->conf.flags & F_CHANGED; 642 active->conf.flags |= 643 rdr->backup->conf.flags & F_CHANGED; 644 } else 645 active = rdr->table; 646 647 if (active != NULL && active->conf.flags & F_CHANGED) { 648 id.id = active->conf.id; 649 imsg.hdr.type = IMSG_CTL_TABLE_CHANGED; 650 imsg.hdr.len = sizeof(id) + IMSG_HEADER_SIZE; 651 imsg.data = &id; 652 sync_table(env, rdr, active); 653 control_imsg_forward(&imsg); 654 } 655 656 if (rdr->conf.flags & F_DOWN) { 657 if (rdr->conf.flags & F_ACTIVE_RULESET) { 658 flush_table(env, rdr); 659 log_debug("%s: disabling ruleset", __func__); 660 rdr->conf.flags &= ~(F_ACTIVE_RULESET); 661 id.id = rdr->conf.id; 662 imsg.hdr.type = IMSG_CTL_PULL_RULESET; 663 imsg.hdr.len = sizeof(id) + IMSG_HEADER_SIZE; 664 imsg.data = &id; 665 sync_ruleset(env, rdr, 0); 666 control_imsg_forward(&imsg); 667 } 668 } else if (!(rdr->conf.flags & F_ACTIVE_RULESET)) { 669 log_debug("%s: enabling ruleset", __func__); 670 rdr->conf.flags |= F_ACTIVE_RULESET; 671 id.id = rdr->conf.id; 672 imsg.hdr.type = IMSG_CTL_PUSH_RULESET; 673 imsg.hdr.len = sizeof(id) + IMSG_HEADER_SIZE; 674 imsg.data = &id; 675 sync_ruleset(env, rdr, 1); 676 control_imsg_forward(&imsg); 677 } 678 } 679 680 TAILQ_FOREACH(rt, env->sc_rts, rt_entry) { 681 rt->rt_conf.flags &= ~(F_BACKUP); 682 rt->rt_conf.flags &= ~(F_DOWN); 683 684 if ((rt->rt_gwtable->conf.flags & F_CHANGED)) 685 sync_routes(env, rt); 686 } 687 688 TAILQ_FOREACH(table, env->sc_tables, entry) { 689 if (table->conf.check == CHECK_NOCHECK) 690 continue; 691 692 /* 693 * clean up change flag. 694 */ 695 table->conf.flags &= ~(F_CHANGED); 696 697 /* 698 * handle demotion. 699 */ 700 if ((table->conf.flags & F_DEMOTE) == 0) 701 continue; 702 demote.level = 0; 703 if (table->up && table->conf.flags & F_DEMOTED) { 704 demote.level = -1; 705 table->conf.flags &= ~F_DEMOTED; 706 } 707 else if (!table->up && !(table->conf.flags & F_DEMOTED)) { 708 demote.level = 1; 709 table->conf.flags |= F_DEMOTED; 710 } 711 if (demote.level == 0) 712 continue; 713 log_debug("%s: demote %d table '%s' group '%s'", __func__, 714 demote.level, table->conf.name, table->conf.demote_group); 715 (void)strlcpy(demote.group, table->conf.demote_group, 716 sizeof(demote.group)); 717 proc_compose_imsg(env->sc_ps, PROC_PARENT, -1, IMSG_DEMOTE, -1, 718 &demote, sizeof(demote)); 719 } 720 } 721 722 void 723 pfe_statistics(int fd, short events, void *arg) 724 { 725 struct rdr *rdr; 726 struct ctl_stats *cur; 727 struct timeval tv, tv_now; 728 int resethour, resetday; 729 u_long cnt; 730 731 timerclear(&tv); 732 getmonotime(&tv_now); 733 734 TAILQ_FOREACH(rdr, env->sc_rdrs, entry) { 735 cnt = check_table(env, rdr, rdr->table); 736 if (rdr->conf.backup_id != EMPTY_TABLE) 737 cnt += check_table(env, rdr, rdr->backup); 738 739 resethour = resetday = 0; 740 741 cur = &rdr->stats; 742 cur->last = cnt > cur->cnt ? cnt - cur->cnt : 0; 743 744 cur->cnt = cnt; 745 cur->tick++; 746 cur->avg = (cur->last + cur->avg) / 2; 747 cur->last_hour += cur->last; 748 if ((cur->tick % (3600 / env->sc_statinterval.tv_sec)) == 0) { 749 cur->avg_hour = (cur->last_hour + cur->avg_hour) / 2; 750 resethour++; 751 } 752 cur->last_day += cur->last; 753 if ((cur->tick % (86400 / env->sc_statinterval.tv_sec)) == 0) { 754 cur->avg_day = (cur->last_day + cur->avg_day) / 2; 755 resethour++; 756 } 757 if (resethour) 758 cur->last_hour = 0; 759 if (resetday) 760 cur->last_day = 0; 761 762 rdr->stats.interval = env->sc_statinterval.tv_sec; 763 } 764 765 /* Schedule statistics timer */ 766 evtimer_set(&env->sc_statev, pfe_statistics, NULL); 767 bcopy(&env->sc_statinterval, &tv, sizeof(tv)); 768 evtimer_add(&env->sc_statev, &tv); 769 } 770