Annotation of embedaddon/bird2/sysdep/unix/krt.c, revision 1.1
1.1 ! misho 1: /*
! 2: * BIRD -- UNIX Kernel Synchronization
! 3: *
! 4: * (c) 1998--2000 Martin Mares <mj@ucw.cz>
! 5: *
! 6: * Can be freely distributed and used under the terms of the GNU GPL.
! 7: */
! 8:
! 9: /**
! 10: * DOC: Kernel synchronization
! 11: *
! 12: * This system dependent module implements the Kernel and Device protocol,
! 13: * that is synchronization of interface lists and routing tables with the
! 14: * OS kernel.
! 15: *
! 16: * The whole kernel synchronization is a bit messy and touches some internals
! 17: * of the routing table engine, because routing table maintenance is a typical
! 18: * example of the proverbial compatibility between different Unices and we want
! 19: * to keep the overhead of our KRT business as low as possible and avoid maintaining
! 20: * a local routing table copy.
! 21: *
! 22: * The kernel syncer can work in three different modes (according to system config header):
! 23: * Either with a single routing table and single KRT protocol [traditional UNIX]
! 24: * or with many routing tables and separate KRT protocols for all of them
! 25: * or with many routing tables, but every scan including all tables, so we start
! 26: * separate KRT protocols which cooperate with each other [Linux].
! 27: * In this case, we keep only a single scan timer.
! 28: *
! 29: * We use FIB node flags in the routing table to keep track of route
! 30: * synchronization status. We also attach temporary &rte's to the routing table,
! 31: * but it cannot do any harm to the rest of BIRD since table synchronization is
! 32: * an atomic process.
! 33: *
! 34: * When starting up, we cheat by looking if there is another
! 35: * KRT instance to be initialized later and performing table scan
! 36: * only once for all the instances.
! 37: *
! 38: * The code uses OS-dependent parts for kernel updates and scans. These parts are
! 39: * in more specific sysdep directories (e.g. sysdep/linux) in functions krt_sys_*
! 40: * and kif_sys_* (and some others like krt_replace_rte()) and krt-sys.h header file.
! 41: * This is also used for platform specific protocol options and route attributes.
! 42: *
! 43: * There was also an old code that used traditional UNIX ioctls for these tasks.
! 44: * It was unmaintained and later removed. For reference, see sysdep/krt-* files
! 45: * in commit 396dfa9042305f62da1f56589c4b98fac57fc2f6
! 46: */
! 47:
! 48: /*
! 49: * If you are brave enough, continue now. You cannot say you haven't been warned.
! 50: */
! 51:
! 52: #undef LOCAL_DEBUG
! 53:
! 54: #include "nest/bird.h"
! 55: #include "nest/iface.h"
! 56: #include "nest/route.h"
! 57: #include "nest/protocol.h"
! 58: #include "filter/filter.h"
! 59: #include "conf/conf.h"
! 60: #include "lib/string.h"
! 61: #include "lib/timer.h"
! 62:
! 63: #include "unix.h"
! 64: #include "krt.h"
! 65:
! 66: /*
! 67: * Global resources
! 68: */
! 69:
! 70: pool *krt_pool;
! 71: static linpool *krt_filter_lp;
! 72: static list krt_proto_list;
! 73:
! 74: void
! 75: krt_io_init(void)
! 76: {
! 77: krt_pool = rp_new(&root_pool, "Kernel Syncer");
! 78: krt_filter_lp = lp_new_default(krt_pool);
! 79: init_list(&krt_proto_list);
! 80: krt_sys_io_init();
! 81: }
! 82:
! 83: /*
! 84: * Interfaces
! 85: */
! 86:
! 87: struct kif_proto *kif_proto;
! 88: static struct kif_config *kif_cf;
! 89: static timer *kif_scan_timer;
! 90: static btime kif_last_shot;
! 91:
! 92: static struct kif_iface_config kif_default_iface = {};
! 93:
! 94: struct kif_iface_config *
! 95: kif_get_iface_config(struct iface *iface)
! 96: {
! 97: struct kif_config *cf = (void *) (kif_proto->p.cf);
! 98: struct kif_iface_config *ic = (void *) iface_patt_find(&cf->iface_list, iface, NULL);
! 99: return ic ?: &kif_default_iface;
! 100: }
! 101:
! 102: static void
! 103: kif_scan(timer *t)
! 104: {
! 105: struct kif_proto *p = t->data;
! 106:
! 107: KRT_TRACE(p, D_EVENTS, "Scanning interfaces");
! 108: kif_last_shot = current_time();
! 109: kif_do_scan(p);
! 110: }
! 111:
! 112: static void
! 113: kif_force_scan(void)
! 114: {
! 115: if (kif_proto && ((kif_last_shot + 2 S) < current_time()))
! 116: {
! 117: kif_scan(kif_scan_timer);
! 118: tm_start(kif_scan_timer, ((struct kif_config *) kif_proto->p.cf)->scan_time);
! 119: }
! 120: }
! 121:
! 122: void
! 123: kif_request_scan(void)
! 124: {
! 125: if (kif_proto && (kif_scan_timer->expires > (current_time() + 1 S)))
! 126: tm_start(kif_scan_timer, 1 S);
! 127: }
! 128:
! 129: static struct proto *
! 130: kif_init(struct proto_config *c)
! 131: {
! 132: struct kif_proto *p = proto_new(c);
! 133:
! 134: kif_sys_init(p);
! 135: return &p->p;
! 136: }
! 137:
! 138: static int
! 139: kif_start(struct proto *P)
! 140: {
! 141: struct kif_proto *p = (struct kif_proto *) P;
! 142:
! 143: kif_proto = p;
! 144: kif_sys_start(p);
! 145:
! 146: /* Start periodic interface scanning */
! 147: kif_scan_timer = tm_new_init(P->pool, kif_scan, p, KIF_CF->scan_time, 0);
! 148: kif_scan(kif_scan_timer);
! 149: tm_start(kif_scan_timer, KIF_CF->scan_time);
! 150:
! 151: return PS_UP;
! 152: }
! 153:
! 154: static int
! 155: kif_shutdown(struct proto *P)
! 156: {
! 157: struct kif_proto *p = (struct kif_proto *) P;
! 158:
! 159: tm_stop(kif_scan_timer);
! 160: kif_sys_shutdown(p);
! 161: kif_proto = NULL;
! 162:
! 163: return PS_DOWN;
! 164: }
! 165:
! 166: static int
! 167: kif_reconfigure(struct proto *p, struct proto_config *new)
! 168: {
! 169: struct kif_config *o = (struct kif_config *) p->cf;
! 170: struct kif_config *n = (struct kif_config *) new;
! 171:
! 172: if (!kif_sys_reconfigure((struct kif_proto *) p, n, o))
! 173: return 0;
! 174:
! 175: if (o->scan_time != n->scan_time)
! 176: {
! 177: tm_stop(kif_scan_timer);
! 178: kif_scan_timer->recurrent = n->scan_time;
! 179: kif_scan(kif_scan_timer);
! 180: tm_start(kif_scan_timer, n->scan_time);
! 181: }
! 182:
! 183: if (!EMPTY_LIST(o->iface_list) || !EMPTY_LIST(n->iface_list))
! 184: {
! 185: /* This is hack, we have to update a configuration
! 186: * to the new value just now, because it is used
! 187: * for recalculation of preferred addresses.
! 188: */
! 189: p->cf = new;
! 190:
! 191: if_recalc_all_preferred_addresses();
! 192: }
! 193:
! 194: return 1;
! 195: }
! 196:
! 197:
! 198: static void
! 199: kif_preconfig(struct protocol *P UNUSED, struct config *c)
! 200: {
! 201: kif_cf = NULL;
! 202: kif_sys_preconfig(c);
! 203: }
! 204:
! 205: struct proto_config *
! 206: kif_init_config(int class)
! 207: {
! 208: if (kif_cf)
! 209: cf_error("Kernel device protocol already defined");
! 210:
! 211: kif_cf = (struct kif_config *) proto_config_new(&proto_unix_iface, class);
! 212: kif_cf->scan_time = 60 S;
! 213: init_list(&kif_cf->iface_list);
! 214:
! 215: kif_sys_init_config(kif_cf);
! 216: return (struct proto_config *) kif_cf;
! 217: }
! 218:
! 219: static void
! 220: kif_copy_config(struct proto_config *dest, struct proto_config *src)
! 221: {
! 222: struct kif_config *d = (struct kif_config *) dest;
! 223: struct kif_config *s = (struct kif_config *) src;
! 224:
! 225: /* Copy interface config list */
! 226: cfg_copy_list(&d->iface_list, &s->iface_list, sizeof(struct kif_iface_config));
! 227:
! 228: /* Fix sysdep parts */
! 229: kif_sys_copy_config(d, s);
! 230: }
! 231:
! 232: struct protocol proto_unix_iface = {
! 233: .name = "Device",
! 234: .template = "device%d",
! 235: .class = PROTOCOL_DEVICE,
! 236: .proto_size = sizeof(struct kif_proto),
! 237: .config_size = sizeof(struct kif_config),
! 238: .preconfig = kif_preconfig,
! 239: .init = kif_init,
! 240: .start = kif_start,
! 241: .shutdown = kif_shutdown,
! 242: .reconfigure = kif_reconfigure,
! 243: .copy_config = kif_copy_config
! 244: };
! 245:
! 246: /*
! 247: * Tracing of routes
! 248: */
! 249:
! 250: static inline void
! 251: krt_trace_in(struct krt_proto *p, rte *e, char *msg)
! 252: {
! 253: if (p->p.debug & D_PACKETS)
! 254: log(L_TRACE "%s: %N: %s", p->p.name, e->net->n.addr, msg);
! 255: }
! 256:
! 257: static inline void
! 258: krt_trace_in_rl(struct tbf *f, struct krt_proto *p, rte *e, char *msg)
! 259: {
! 260: if (p->p.debug & D_PACKETS)
! 261: log_rl(f, L_TRACE "%s: %N: %s", p->p.name, e->net->n.addr, msg);
! 262: }
! 263:
! 264: /*
! 265: * Inherited Routes
! 266: */
! 267:
! 268: #ifdef KRT_ALLOW_LEARN
! 269:
! 270: static struct tbf rl_alien = TBF_DEFAULT_LOG_LIMITS;
! 271:
! 272: /*
! 273: * krt_same_key() specifies what (aside from the net) is the key in
! 274: * kernel routing tables. It should be OS-dependent, this is for
! 275: * Linux. It is important for asynchronous alien updates, because a
! 276: * positive update is implicitly a negative one for any old route with
! 277: * the same key.
! 278: */
! 279:
! 280: static inline int
! 281: krt_same_key(rte *a, rte *b)
! 282: {
! 283: return a->u.krt.metric == b->u.krt.metric;
! 284: }
! 285:
! 286: static inline int
! 287: krt_uptodate(rte *a, rte *b)
! 288: {
! 289: if (a->attrs != b->attrs)
! 290: return 0;
! 291:
! 292: if (a->u.krt.proto != b->u.krt.proto)
! 293: return 0;
! 294:
! 295: return 1;
! 296: }
! 297:
! 298: static void
! 299: krt_learn_announce_update(struct krt_proto *p, rte *e)
! 300: {
! 301: net *n = e->net;
! 302: rta *aa = rta_clone(e->attrs);
! 303: rte *ee = rte_get_temp(aa);
! 304: ee->pflags = EA_ID_FLAG(EA_KRT_SOURCE) | EA_ID_FLAG(EA_KRT_METRIC);
! 305: ee->u.krt = e->u.krt;
! 306: rte_update(&p->p, n->n.addr, ee);
! 307: }
! 308:
! 309: static void
! 310: krt_learn_announce_delete(struct krt_proto *p, net *n)
! 311: {
! 312: rte_update(&p->p, n->n.addr, NULL);
! 313: }
! 314:
! 315: /* Called when alien route is discovered during scan */
! 316: static void
! 317: krt_learn_scan(struct krt_proto *p, rte *e)
! 318: {
! 319: net *n0 = e->net;
! 320: net *n = net_get(&p->krt_table, n0->n.addr);
! 321: rte *m, **mm;
! 322:
! 323: e->attrs = rta_lookup(e->attrs);
! 324:
! 325: for(mm=&n->routes; m = *mm; mm=&m->next)
! 326: if (krt_same_key(m, e))
! 327: break;
! 328: if (m)
! 329: {
! 330: if (krt_uptodate(m, e))
! 331: {
! 332: krt_trace_in_rl(&rl_alien, p, e, "[alien] seen");
! 333: rte_free(e);
! 334: m->u.krt.seen = 1;
! 335: }
! 336: else
! 337: {
! 338: krt_trace_in(p, e, "[alien] updated");
! 339: *mm = m->next;
! 340: rte_free(m);
! 341: m = NULL;
! 342: }
! 343: }
! 344: else
! 345: krt_trace_in(p, e, "[alien] created");
! 346: if (!m)
! 347: {
! 348: e->next = n->routes;
! 349: n->routes = e;
! 350: e->u.krt.seen = 1;
! 351: }
! 352: }
! 353:
! 354: static void
! 355: krt_learn_prune(struct krt_proto *p)
! 356: {
! 357: struct fib *fib = &p->krt_table.fib;
! 358: struct fib_iterator fit;
! 359:
! 360: KRT_TRACE(p, D_EVENTS, "Pruning inherited routes");
! 361:
! 362: FIB_ITERATE_INIT(&fit, fib);
! 363: again:
! 364: FIB_ITERATE_START(fib, &fit, net, n)
! 365: {
! 366: rte *e, **ee, *best, **pbest, *old_best;
! 367:
! 368: /*
! 369: * Note that old_best may be NULL even if there was an old best route in
! 370: * the previous step, because it might be replaced in krt_learn_scan().
! 371: * But in that case there is a new valid best route.
! 372: */
! 373:
! 374: old_best = NULL;
! 375: best = NULL;
! 376: pbest = NULL;
! 377: ee = &n->routes;
! 378: while (e = *ee)
! 379: {
! 380: if (e->u.krt.best)
! 381: old_best = e;
! 382:
! 383: if (!e->u.krt.seen)
! 384: {
! 385: *ee = e->next;
! 386: rte_free(e);
! 387: continue;
! 388: }
! 389:
! 390: if (!best || best->u.krt.metric > e->u.krt.metric)
! 391: {
! 392: best = e;
! 393: pbest = ee;
! 394: }
! 395:
! 396: e->u.krt.seen = 0;
! 397: e->u.krt.best = 0;
! 398: ee = &e->next;
! 399: }
! 400: if (!n->routes)
! 401: {
! 402: DBG("%I/%d: deleting\n", n->n.prefix, n->n.pxlen);
! 403: if (old_best)
! 404: krt_learn_announce_delete(p, n);
! 405:
! 406: FIB_ITERATE_PUT(&fit);
! 407: fib_delete(fib, n);
! 408: goto again;
! 409: }
! 410:
! 411: best->u.krt.best = 1;
! 412: *pbest = best->next;
! 413: best->next = n->routes;
! 414: n->routes = best;
! 415:
! 416: if ((best != old_best) || p->reload)
! 417: {
! 418: DBG("%I/%d: announcing (metric=%d)\n", n->n.prefix, n->n.pxlen, best->u.krt.metric);
! 419: krt_learn_announce_update(p, best);
! 420: }
! 421: else
! 422: DBG("%I/%d: uptodate (metric=%d)\n", n->n.prefix, n->n.pxlen, best->u.krt.metric);
! 423: }
! 424: FIB_ITERATE_END;
! 425:
! 426: p->reload = 0;
! 427: }
! 428:
! 429: static void
! 430: krt_learn_async(struct krt_proto *p, rte *e, int new)
! 431: {
! 432: net *n0 = e->net;
! 433: net *n = net_get(&p->krt_table, n0->n.addr);
! 434: rte *g, **gg, *best, **bestp, *old_best;
! 435:
! 436: e->attrs = rta_lookup(e->attrs);
! 437:
! 438: old_best = n->routes;
! 439: for(gg=&n->routes; g = *gg; gg = &g->next)
! 440: if (krt_same_key(g, e))
! 441: break;
! 442: if (new)
! 443: {
! 444: if (g)
! 445: {
! 446: if (krt_uptodate(g, e))
! 447: {
! 448: krt_trace_in(p, e, "[alien async] same");
! 449: rte_free(e);
! 450: return;
! 451: }
! 452: krt_trace_in(p, e, "[alien async] updated");
! 453: *gg = g->next;
! 454: rte_free(g);
! 455: }
! 456: else
! 457: krt_trace_in(p, e, "[alien async] created");
! 458:
! 459: e->next = n->routes;
! 460: n->routes = e;
! 461: }
! 462: else if (!g)
! 463: {
! 464: krt_trace_in(p, e, "[alien async] delete failed");
! 465: rte_free(e);
! 466: return;
! 467: }
! 468: else
! 469: {
! 470: krt_trace_in(p, e, "[alien async] removed");
! 471: *gg = g->next;
! 472: rte_free(e);
! 473: rte_free(g);
! 474: }
! 475: best = n->routes;
! 476: bestp = &n->routes;
! 477: for(gg=&n->routes; g=*gg; gg=&g->next)
! 478: {
! 479: if (best->u.krt.metric > g->u.krt.metric)
! 480: {
! 481: best = g;
! 482: bestp = gg;
! 483: }
! 484:
! 485: g->u.krt.best = 0;
! 486: }
! 487:
! 488: if (best)
! 489: {
! 490: best->u.krt.best = 1;
! 491: *bestp = best->next;
! 492: best->next = n->routes;
! 493: n->routes = best;
! 494: }
! 495:
! 496: if (best != old_best)
! 497: {
! 498: DBG("krt_learn_async: distributing change\n");
! 499: if (best)
! 500: krt_learn_announce_update(p, best);
! 501: else
! 502: krt_learn_announce_delete(p, n);
! 503: }
! 504: }
! 505:
! 506: static void
! 507: krt_learn_init(struct krt_proto *p)
! 508: {
! 509: if (KRT_CF->learn)
! 510: {
! 511: struct rtable_config *cf = mb_allocz(p->p.pool, sizeof(struct rtable_config));
! 512: cf->name = "Inherited";
! 513: cf->addr_type = p->p.net_type;
! 514:
! 515: rt_setup(p->p.pool, &p->krt_table, cf);
! 516: }
! 517: }
! 518:
! 519: static void
! 520: krt_dump(struct proto *P)
! 521: {
! 522: struct krt_proto *p = (struct krt_proto *) P;
! 523:
! 524: if (!KRT_CF->learn)
! 525: return;
! 526: debug("KRT: Table of inheritable routes\n");
! 527: rt_dump(&p->krt_table);
! 528: }
! 529:
! 530: static void
! 531: krt_dump_attrs(rte *e)
! 532: {
! 533: debug(" [m=%d,p=%d]", e->u.krt.metric, e->u.krt.proto);
! 534: }
! 535:
! 536: #endif
! 537:
! 538: /*
! 539: * Routes
! 540: */
! 541:
! 542: static void
! 543: krt_flush_routes(struct krt_proto *p)
! 544: {
! 545: struct rtable *t = p->p.main_channel->table;
! 546:
! 547: KRT_TRACE(p, D_EVENTS, "Flushing kernel routes");
! 548: FIB_WALK(&t->fib, net, n)
! 549: {
! 550: rte *e = n->routes;
! 551: if (rte_is_valid(e) && (n->n.flags & KRF_INSTALLED))
! 552: {
! 553: /* FIXME: this does not work if gw is changed in export filter */
! 554: krt_replace_rte(p, e->net, NULL, e);
! 555: n->n.flags &= ~KRF_INSTALLED;
! 556: }
! 557: }
! 558: FIB_WALK_END;
! 559: }
! 560:
! 561: static struct rte *
! 562: krt_export_net(struct krt_proto *p, net *net, rte **rt_free)
! 563: {
! 564: struct channel *c = p->p.main_channel;
! 565: const struct filter *filter = c->out_filter;
! 566: rte *rt;
! 567:
! 568: if (c->ra_mode == RA_MERGED)
! 569: return rt_export_merged(c, net, rt_free, krt_filter_lp, 1);
! 570:
! 571: rt = net->routes;
! 572: *rt_free = NULL;
! 573:
! 574: if (!rte_is_valid(rt))
! 575: return NULL;
! 576:
! 577: if (filter == FILTER_REJECT)
! 578: return NULL;
! 579:
! 580: rte_make_tmp_attrs(&rt, krt_filter_lp, NULL);
! 581:
! 582: /* We could run krt_preexport() here, but it is already handled by KRF_INSTALLED */
! 583:
! 584: if (filter == FILTER_ACCEPT)
! 585: goto accept;
! 586:
! 587: if (f_run(filter, &rt, krt_filter_lp, FF_SILENT) > F_ACCEPT)
! 588: goto reject;
! 589:
! 590:
! 591: accept:
! 592: if (rt != net->routes)
! 593: *rt_free = rt;
! 594: return rt;
! 595:
! 596: reject:
! 597: if (rt != net->routes)
! 598: rte_free(rt);
! 599: return NULL;
! 600: }
! 601:
! 602: static int
! 603: krt_same_dest(rte *k, rte *e)
! 604: {
! 605: rta *ka = k->attrs, *ea = e->attrs;
! 606:
! 607: if (ka->dest != ea->dest)
! 608: return 0;
! 609:
! 610: if (ka->dest == RTD_UNICAST)
! 611: return nexthop_same(&(ka->nh), &(ea->nh));
! 612:
! 613: return 1;
! 614: }
! 615:
! 616: /*
! 617: * This gets called back when the low-level scanning code discovers a route.
! 618: * We expect that the route is a temporary rte and its attributes are uncached.
! 619: */
! 620:
! 621: void
! 622: krt_got_route(struct krt_proto *p, rte *e)
! 623: {
! 624: net *net = e->net;
! 625: int verdict;
! 626:
! 627: #ifdef KRT_ALLOW_LEARN
! 628: switch (e->u.krt.src)
! 629: {
! 630: case KRT_SRC_KERNEL:
! 631: verdict = KRF_IGNORE;
! 632: goto sentenced;
! 633:
! 634: case KRT_SRC_REDIRECT:
! 635: verdict = KRF_DELETE;
! 636: goto sentenced;
! 637:
! 638: case KRT_SRC_ALIEN:
! 639: if (KRT_CF->learn)
! 640: krt_learn_scan(p, e);
! 641: else
! 642: {
! 643: krt_trace_in_rl(&rl_alien, p, e, "[alien] ignored");
! 644: rte_free(e);
! 645: }
! 646: return;
! 647: }
! 648: #endif
! 649: /* The rest is for KRT_SRC_BIRD (or KRT_SRC_UNKNOWN) */
! 650:
! 651: if (net->n.flags & KRF_VERDICT_MASK)
! 652: {
! 653: /* Route to this destination was already seen. Strange, but it happens... */
! 654: krt_trace_in(p, e, "already seen");
! 655: rte_free(e);
! 656: return;
! 657: }
! 658:
! 659: if (!p->ready)
! 660: {
! 661: /* We wait for the initial feed to have correct KRF_INSTALLED flag */
! 662: verdict = KRF_IGNORE;
! 663: goto sentenced;
! 664: }
! 665:
! 666: if (net->n.flags & KRF_INSTALLED)
! 667: {
! 668: rte *new, *rt_free;
! 669:
! 670: new = krt_export_net(p, net, &rt_free);
! 671:
! 672: /* TODO: There also may be changes in route eattrs, we ignore that for now. */
! 673:
! 674: if (!new)
! 675: verdict = KRF_DELETE;
! 676: else if ((net->n.flags & KRF_SYNC_ERROR) || !krt_same_dest(e, new))
! 677: verdict = KRF_UPDATE;
! 678: else
! 679: verdict = KRF_SEEN;
! 680:
! 681: if (rt_free)
! 682: rte_free(rt_free);
! 683:
! 684: lp_flush(krt_filter_lp);
! 685: }
! 686: else
! 687: verdict = KRF_DELETE;
! 688:
! 689: sentenced:
! 690: krt_trace_in(p, e, ((char *[]) { "?", "seen", "will be updated", "will be removed", "ignored" }) [verdict]);
! 691: net->n.flags = (net->n.flags & ~KRF_VERDICT_MASK) | verdict;
! 692: if (verdict == KRF_UPDATE || verdict == KRF_DELETE)
! 693: {
! 694: /* Get a cached copy of attributes and temporarily link the route */
! 695: rta *a = e->attrs;
! 696: a->source = RTS_DUMMY;
! 697: e->attrs = rta_lookup(a);
! 698: e->next = net->routes;
! 699: net->routes = e;
! 700: }
! 701: else
! 702: rte_free(e);
! 703: }
! 704:
! 705: static void
! 706: krt_prune(struct krt_proto *p)
! 707: {
! 708: struct rtable *t = p->p.main_channel->table;
! 709:
! 710: KRT_TRACE(p, D_EVENTS, "Pruning table %s", t->name);
! 711: FIB_WALK(&t->fib, net, n)
! 712: {
! 713: int verdict = n->n.flags & KRF_VERDICT_MASK;
! 714: rte *new, *old, *rt_free = NULL;
! 715:
! 716: if (verdict == KRF_UPDATE || verdict == KRF_DELETE)
! 717: {
! 718: /* Get a dummy route from krt_got_route() */
! 719: old = n->routes;
! 720: n->routes = old->next;
! 721: }
! 722: else
! 723: old = NULL;
! 724:
! 725: if (verdict == KRF_CREATE || verdict == KRF_UPDATE)
! 726: {
! 727: /* We have to run export filter to get proper 'new' route */
! 728: new = krt_export_net(p, n, &rt_free);
! 729:
! 730: if (!new)
! 731: verdict = (verdict == KRF_CREATE) ? KRF_IGNORE : KRF_DELETE;
! 732: }
! 733: else
! 734: new = NULL;
! 735:
! 736: switch (verdict)
! 737: {
! 738: case KRF_CREATE:
! 739: if (new && (n->n.flags & KRF_INSTALLED))
! 740: {
! 741: krt_trace_in(p, new, "reinstalling");
! 742: krt_replace_rte(p, n, new, NULL);
! 743: }
! 744: break;
! 745: case KRF_SEEN:
! 746: case KRF_IGNORE:
! 747: /* Nothing happens */
! 748: break;
! 749: case KRF_UPDATE:
! 750: krt_trace_in(p, new, "updating");
! 751: krt_replace_rte(p, n, new, old);
! 752: break;
! 753: case KRF_DELETE:
! 754: krt_trace_in(p, old, "deleting");
! 755: krt_replace_rte(p, n, NULL, old);
! 756: break;
! 757: default:
! 758: bug("krt_prune: invalid route status");
! 759: }
! 760:
! 761: if (old)
! 762: rte_free(old);
! 763: if (rt_free)
! 764: rte_free(rt_free);
! 765: lp_flush(krt_filter_lp);
! 766: n->n.flags &= ~KRF_VERDICT_MASK;
! 767: }
! 768: FIB_WALK_END;
! 769:
! 770: #ifdef KRT_ALLOW_LEARN
! 771: if (KRT_CF->learn)
! 772: krt_learn_prune(p);
! 773: #endif
! 774:
! 775: if (p->ready)
! 776: p->initialized = 1;
! 777: }
! 778:
! 779: void
! 780: krt_got_route_async(struct krt_proto *p, rte *e, int new)
! 781: {
! 782: net *net = e->net;
! 783:
! 784: switch (e->u.krt.src)
! 785: {
! 786: case KRT_SRC_BIRD:
! 787: /* Should be filtered by the back end */
! 788: bug("BIRD originated routes should not get here.");
! 789:
! 790: case KRT_SRC_REDIRECT:
! 791: if (new)
! 792: {
! 793: krt_trace_in(p, e, "[redirect] deleting");
! 794: krt_replace_rte(p, net, NULL, e);
! 795: }
! 796: /* If !new, it is probably echo of our deletion */
! 797: break;
! 798:
! 799: #ifdef KRT_ALLOW_LEARN
! 800: case KRT_SRC_ALIEN:
! 801: if (KRT_CF->learn)
! 802: {
! 803: krt_learn_async(p, e, new);
! 804: return;
! 805: }
! 806: #endif
! 807: }
! 808: rte_free(e);
! 809: }
! 810:
! 811: /*
! 812: * Periodic scanning
! 813: */
! 814:
! 815:
! 816: #ifdef CONFIG_ALL_TABLES_AT_ONCE
! 817:
! 818: static timer *krt_scan_timer;
! 819: static int krt_scan_count;
! 820:
! 821: static void
! 822: krt_scan(timer *t UNUSED)
! 823: {
! 824: struct krt_proto *p;
! 825:
! 826: kif_force_scan();
! 827:
! 828: /* We need some node to decide whether to print the debug messages or not */
! 829: p = SKIP_BACK(struct krt_proto, krt_node, HEAD(krt_proto_list));
! 830: KRT_TRACE(p, D_EVENTS, "Scanning routing table");
! 831:
! 832: krt_do_scan(NULL);
! 833:
! 834: void *q;
! 835: WALK_LIST(q, krt_proto_list)
! 836: {
! 837: p = SKIP_BACK(struct krt_proto, krt_node, q);
! 838: krt_prune(p);
! 839: }
! 840: }
! 841:
! 842: static void
! 843: krt_scan_timer_start(struct krt_proto *p)
! 844: {
! 845: if (!krt_scan_count)
! 846: krt_scan_timer = tm_new_init(krt_pool, krt_scan, NULL, KRT_CF->scan_time, 0);
! 847:
! 848: krt_scan_count++;
! 849:
! 850: tm_start(krt_scan_timer, 1 S);
! 851: }
! 852:
! 853: static void
! 854: krt_scan_timer_stop(struct krt_proto *p UNUSED)
! 855: {
! 856: krt_scan_count--;
! 857:
! 858: if (!krt_scan_count)
! 859: {
! 860: rfree(krt_scan_timer);
! 861: krt_scan_timer = NULL;
! 862: }
! 863: }
! 864:
! 865: static void
! 866: krt_scan_timer_kick(struct krt_proto *p UNUSED)
! 867: {
! 868: tm_start(krt_scan_timer, 0);
! 869: }
! 870:
! 871: #else
! 872:
! 873: static void
! 874: krt_scan(timer *t)
! 875: {
! 876: struct krt_proto *p = t->data;
! 877:
! 878: kif_force_scan();
! 879:
! 880: KRT_TRACE(p, D_EVENTS, "Scanning routing table");
! 881: krt_do_scan(p);
! 882: krt_prune(p);
! 883: }
! 884:
! 885: static void
! 886: krt_scan_timer_start(struct krt_proto *p)
! 887: {
! 888: p->scan_timer = tm_new_init(p->p.pool, krt_scan, p, KRT_CF->scan_time, 0);
! 889: tm_start(p->scan_timer, 1 S);
! 890: }
! 891:
! 892: static void
! 893: krt_scan_timer_stop(struct krt_proto *p)
! 894: {
! 895: tm_stop(p->scan_timer);
! 896: }
! 897:
! 898: static void
! 899: krt_scan_timer_kick(struct krt_proto *p)
! 900: {
! 901: tm_start(p->scan_timer, 0);
! 902: }
! 903:
! 904: #endif
! 905:
! 906:
! 907:
! 908:
! 909: /*
! 910: * Updates
! 911: */
! 912:
! 913: static void
! 914: krt_make_tmp_attrs(struct rte *rt, struct linpool *pool)
! 915: {
! 916: rte_init_tmp_attrs(rt, pool, 2);
! 917: rte_make_tmp_attr(rt, EA_KRT_SOURCE, EAF_TYPE_INT, rt->u.krt.proto);
! 918: rte_make_tmp_attr(rt, EA_KRT_METRIC, EAF_TYPE_INT, rt->u.krt.metric);
! 919: }
! 920:
! 921: static void
! 922: krt_store_tmp_attrs(struct rte *rt, struct linpool *pool)
! 923: {
! 924: rte_init_tmp_attrs(rt, pool, 2);
! 925: rt->u.krt.proto = rte_store_tmp_attr(rt, EA_KRT_SOURCE);
! 926: rt->u.krt.metric = rte_store_tmp_attr(rt, EA_KRT_METRIC);
! 927: }
! 928:
! 929: static int
! 930: krt_preexport(struct proto *P, rte **new, struct linpool *pool UNUSED)
! 931: {
! 932: // struct krt_proto *p = (struct krt_proto *) P;
! 933: rte *e = *new;
! 934:
! 935: if (e->attrs->src->proto == P)
! 936: {
! 937: #ifdef CONFIG_SINGLE_ROUTE
! 938: /*
! 939: * Implicit withdraw - when the imported kernel route becomes the best one,
! 940: * we know that the previous one exported to the kernel was already removed,
! 941: * but if we processed the update as usual, we would send withdraw to the
! 942: * kernel, which would remove the new imported route instead.
! 943: *
! 944: * We will remove KRT_INSTALLED flag, which stops such withdraw to be
! 945: * processed in krt_rt_notify() and krt_replace_rte().
! 946: */
! 947: if (e == e->net->routes)
! 948: e->net->n.flags &= ~KRF_INSTALLED;
! 949: #endif
! 950: return -1;
! 951: }
! 952:
! 953: if (!krt_capable(e))
! 954: return -1;
! 955:
! 956: return 0;
! 957: }
! 958:
! 959: static void
! 960: krt_rt_notify(struct proto *P, struct channel *ch UNUSED, net *net,
! 961: rte *new, rte *old)
! 962: {
! 963: struct krt_proto *p = (struct krt_proto *) P;
! 964:
! 965: if (config->shutdown)
! 966: return;
! 967: if (!(net->n.flags & KRF_INSTALLED))
! 968: old = NULL;
! 969: if (new)
! 970: net->n.flags |= KRF_INSTALLED;
! 971: else
! 972: net->n.flags &= ~KRF_INSTALLED;
! 973: if (p->initialized) /* Before first scan we don't touch the routes */
! 974: krt_replace_rte(p, net, new, old);
! 975: }
! 976:
! 977: static void
! 978: krt_if_notify(struct proto *P, uint flags, struct iface *iface UNUSED)
! 979: {
! 980: struct krt_proto *p = (struct krt_proto *) P;
! 981:
! 982: /*
! 983: * When interface went down, we should remove routes to it. In the ideal world,
! 984: * OS kernel would send us route removal notifications in such cases, but we
! 985: * cannot rely on it as it is often not true. E.g. Linux kernel removes related
! 986: * routes when an interface went down, but it does not notify userspace about
! 987: * that. To be sure, we just schedule a scan to ensure synchronization.
! 988: */
! 989:
! 990: if ((flags & IF_CHANGE_DOWN) && KRT_CF->learn)
! 991: krt_scan_timer_kick(p);
! 992: }
! 993:
! 994: static void
! 995: krt_reload_routes(struct channel *C)
! 996: {
! 997: struct krt_proto *p = (void *) C->proto;
! 998:
! 999: /* Although we keep learned routes in krt_table, we rather schedule a scan */
! 1000:
! 1001: if (KRT_CF->learn)
! 1002: {
! 1003: p->reload = 1;
! 1004: krt_scan_timer_kick(p);
! 1005: }
! 1006: }
! 1007:
! 1008: static void
! 1009: krt_feed_end(struct channel *C)
! 1010: {
! 1011: struct krt_proto *p = (void *) C->proto;
! 1012:
! 1013: p->ready = 1;
! 1014: krt_scan_timer_kick(p);
! 1015: }
! 1016:
! 1017:
! 1018: static int
! 1019: krt_rte_same(rte *a, rte *b)
! 1020: {
! 1021: /* src is always KRT_SRC_ALIEN and type is irrelevant */
! 1022: return (a->u.krt.proto == b->u.krt.proto) && (a->u.krt.metric == b->u.krt.metric);
! 1023: }
! 1024:
! 1025:
! 1026: /*
! 1027: * Protocol glue
! 1028: */
! 1029:
! 1030: struct krt_config *krt_cf;
! 1031:
! 1032: static void
! 1033: krt_preconfig(struct protocol *P UNUSED, struct config *c)
! 1034: {
! 1035: krt_cf = NULL;
! 1036: krt_sys_preconfig(c);
! 1037: }
! 1038:
! 1039: static void
! 1040: krt_postconfig(struct proto_config *CF)
! 1041: {
! 1042: struct krt_config *cf = (void *) CF;
! 1043:
! 1044: if (EMPTY_LIST(CF->channels))
! 1045: cf_error("Channel not specified");
! 1046:
! 1047: #ifdef CONFIG_ALL_TABLES_AT_ONCE
! 1048: if (krt_cf->scan_time != cf->scan_time)
! 1049: cf_error("All kernel syncers must use the same table scan interval");
! 1050: #endif
! 1051:
! 1052: struct channel_config *cc = proto_cf_main_channel(CF);
! 1053: struct rtable_config *tab = cc->table;
! 1054: if (tab->krt_attached)
! 1055: cf_error("Kernel syncer (%s) already attached to table %s", tab->krt_attached->name, tab->name);
! 1056: tab->krt_attached = CF;
! 1057:
! 1058: if (cf->merge_paths)
! 1059: {
! 1060: cc->ra_mode = RA_MERGED;
! 1061: cc->merge_limit = cf->merge_paths;
! 1062: }
! 1063:
! 1064: krt_sys_postconfig(cf);
! 1065: }
! 1066:
! 1067: static struct proto *
! 1068: krt_init(struct proto_config *CF)
! 1069: {
! 1070: struct krt_proto *p = proto_new(CF);
! 1071: // struct krt_config *cf = (void *) CF;
! 1072:
! 1073: p->p.main_channel = proto_add_channel(&p->p, proto_cf_main_channel(CF));
! 1074:
! 1075: p->p.preexport = krt_preexport;
! 1076: p->p.rt_notify = krt_rt_notify;
! 1077: p->p.if_notify = krt_if_notify;
! 1078: p->p.reload_routes = krt_reload_routes;
! 1079: p->p.feed_end = krt_feed_end;
! 1080: p->p.make_tmp_attrs = krt_make_tmp_attrs;
! 1081: p->p.store_tmp_attrs = krt_store_tmp_attrs;
! 1082: p->p.rte_same = krt_rte_same;
! 1083:
! 1084: krt_sys_init(p);
! 1085: return &p->p;
! 1086: }
! 1087:
! 1088: static int
! 1089: krt_start(struct proto *P)
! 1090: {
! 1091: struct krt_proto *p = (struct krt_proto *) P;
! 1092:
! 1093: switch (p->p.net_type)
! 1094: {
! 1095: case NET_IP4: p->af = AF_INET; break;
! 1096: case NET_IP6: p->af = AF_INET6; break;
! 1097: case NET_IP6_SADR: p->af = AF_INET6; break;
! 1098: #ifdef AF_MPLS
! 1099: case NET_MPLS: p->af = AF_MPLS; break;
! 1100: #endif
! 1101: default: log(L_ERR "KRT: Tried to start with strange net type: %d", p->p.net_type); return PS_START; break;
! 1102: }
! 1103:
! 1104: add_tail(&krt_proto_list, &p->krt_node);
! 1105:
! 1106: #ifdef KRT_ALLOW_LEARN
! 1107: krt_learn_init(p);
! 1108: #endif
! 1109:
! 1110: if (!krt_sys_start(p))
! 1111: {
! 1112: rem_node(&p->krt_node);
! 1113: return PS_START;
! 1114: }
! 1115:
! 1116: krt_scan_timer_start(p);
! 1117:
! 1118: if (p->p.gr_recovery && KRT_CF->graceful_restart)
! 1119: p->p.main_channel->gr_wait = 1;
! 1120:
! 1121: return PS_UP;
! 1122: }
! 1123:
! 1124: static int
! 1125: krt_shutdown(struct proto *P)
! 1126: {
! 1127: struct krt_proto *p = (struct krt_proto *) P;
! 1128:
! 1129: krt_scan_timer_stop(p);
! 1130:
! 1131: /* FIXME we should flush routes even when persist during reconfiguration */
! 1132: if (p->initialized && !KRT_CF->persist && (P->down_code != PDC_CMD_GR_DOWN))
! 1133: krt_flush_routes(p);
! 1134:
! 1135: p->ready = 0;
! 1136: p->initialized = 0;
! 1137:
! 1138: if (p->p.proto_state == PS_START)
! 1139: return PS_DOWN;
! 1140:
! 1141: krt_sys_shutdown(p);
! 1142: rem_node(&p->krt_node);
! 1143:
! 1144: return PS_DOWN;
! 1145: }
! 1146:
! 1147: static int
! 1148: krt_reconfigure(struct proto *p, struct proto_config *CF)
! 1149: {
! 1150: struct krt_config *o = (void *) p->cf;
! 1151: struct krt_config *n = (void *) CF;
! 1152:
! 1153: if (!proto_configure_channel(p, &p->main_channel, proto_cf_main_channel(CF)))
! 1154: return 0;
! 1155:
! 1156: if (!krt_sys_reconfigure((struct krt_proto *) p, n, o))
! 1157: return 0;
! 1158:
! 1159: /* persist, graceful restart need not be the same */
! 1160: return o->scan_time == n->scan_time && o->learn == n->learn;
! 1161: }
! 1162:
! 1163: struct proto_config *
! 1164: krt_init_config(int class)
! 1165: {
! 1166: #ifndef CONFIG_MULTIPLE_TABLES
! 1167: if (krt_cf)
! 1168: cf_error("Kernel protocol already defined");
! 1169: #endif
! 1170:
! 1171: krt_cf = (struct krt_config *) proto_config_new(&proto_unix_kernel, class);
! 1172: krt_cf->scan_time = 60 S;
! 1173:
! 1174: krt_sys_init_config(krt_cf);
! 1175: return (struct proto_config *) krt_cf;
! 1176: }
! 1177:
! 1178: static void
! 1179: krt_copy_config(struct proto_config *dest, struct proto_config *src)
! 1180: {
! 1181: struct krt_config *d = (struct krt_config *) dest;
! 1182: struct krt_config *s = (struct krt_config *) src;
! 1183:
! 1184: /* Fix sysdep parts */
! 1185: krt_sys_copy_config(d, s);
! 1186: }
! 1187:
! 1188: static int
! 1189: krt_get_attr(eattr *a, byte *buf, int buflen)
! 1190: {
! 1191: switch (a->id)
! 1192: {
! 1193: case EA_KRT_SOURCE:
! 1194: bsprintf(buf, "source");
! 1195: return GA_NAME;
! 1196:
! 1197: case EA_KRT_METRIC:
! 1198: bsprintf(buf, "metric");
! 1199: return GA_NAME;
! 1200:
! 1201: default:
! 1202: return krt_sys_get_attr(a, buf, buflen);
! 1203: }
! 1204: }
! 1205:
! 1206:
! 1207: #ifdef CONFIG_IP6_SADR_KERNEL
! 1208: #define MAYBE_IP6_SADR NB_IP6_SADR
! 1209: #else
! 1210: #define MAYBE_IP6_SADR 0
! 1211: #endif
! 1212:
! 1213: #ifdef HAVE_MPLS_KERNEL
! 1214: #define MAYBE_MPLS NB_MPLS
! 1215: #else
! 1216: #define MAYBE_MPLS 0
! 1217: #endif
! 1218:
! 1219: struct protocol proto_unix_kernel = {
! 1220: .name = "Kernel",
! 1221: .template = "kernel%d",
! 1222: .class = PROTOCOL_KERNEL,
! 1223: .preference = DEF_PREF_INHERITED,
! 1224: .channel_mask = NB_IP | MAYBE_IP6_SADR | MAYBE_MPLS,
! 1225: .proto_size = sizeof(struct krt_proto),
! 1226: .config_size = sizeof(struct krt_config),
! 1227: .preconfig = krt_preconfig,
! 1228: .postconfig = krt_postconfig,
! 1229: .init = krt_init,
! 1230: .start = krt_start,
! 1231: .shutdown = krt_shutdown,
! 1232: .reconfigure = krt_reconfigure,
! 1233: .copy_config = krt_copy_config,
! 1234: .get_attr = krt_get_attr,
! 1235: #ifdef KRT_ALLOW_LEARN
! 1236: .dump = krt_dump,
! 1237: .dump_attrs = krt_dump_attrs,
! 1238: #endif
! 1239: };
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>