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