Annotation of embedaddon/bird/sysdep/unix/krt.c, revision 1.1.1.2

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: 
1.1.1.2 ! misho     635:   if (f_run(filter, &rt, tmpa, krt_filter_lp, FF_FORCE_TMPATTR | FF_SILENT) > F_ACCEPT)
1.1       misho     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: };

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>