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