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