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