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