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