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

1.1     ! misho       1: /*
        !             2:  *     BIRD -- UNIX Kernel Synchronization
        !             3:  *
        !             4:  *     (c) 1998--2000 Martin Mares <mj@ucw.cz>
        !             5:  *
        !             6:  *     Can be freely distributed and used under the terms of the GNU GPL.
        !             7:  */
        !             8: 
        !             9: /**
        !            10:  * DOC: Kernel synchronization
        !            11:  *
        !            12:  * This system dependent module implements the Kernel and Device protocol,
        !            13:  * that is synchronization of interface lists and routing tables with the
        !            14:  * OS kernel.
        !            15:  *
        !            16:  * The whole kernel synchronization is a bit messy and touches some internals
        !            17:  * of the routing table engine, because routing table maintenance is a typical
        !            18:  * example of the proverbial compatibility between different Unices and we want
        !            19:  * to keep the overhead of our KRT business as low as possible and avoid maintaining
        !            20:  * a local routing table copy.
        !            21:  *
        !            22:  * The kernel syncer can work in three different modes (according to system config header):
        !            23:  * Either with a single routing table and single KRT protocol [traditional UNIX]
        !            24:  * or with many routing tables and separate KRT protocols for all of them
        !            25:  * or with many routing tables, but every scan including all tables, so we start
        !            26:  * separate KRT protocols which cooperate with each other [Linux].
        !            27:  * In this case, we keep only a single scan timer.
        !            28:  *
        !            29:  * We use FIB node flags in the routing table to keep track of route
        !            30:  * synchronization status. We also attach temporary &rte's to the routing table,
        !            31:  * but it cannot do any harm to the rest of BIRD since table synchronization is
        !            32:  * an atomic process.
        !            33:  *
        !            34:  * When starting up, we cheat by looking if there is another
        !            35:  * KRT instance to be initialized later and performing table scan
        !            36:  * only once for all the instances.
        !            37:  *
        !            38:  * The code uses OS-dependent parts for kernel updates and scans. These parts are
        !            39:  * in more specific sysdep directories (e.g. sysdep/linux) in functions krt_sys_*
        !            40:  * and kif_sys_* (and some others like krt_replace_rte()) and krt-sys.h header file.
        !            41:  * This is also used for platform specific protocol options and route attributes.
        !            42:  *
        !            43:  * There was also an old code that used traditional UNIX ioctls for these tasks.
        !            44:  * It was unmaintained and later removed. For reference, see sysdep/krt-* files
        !            45:  * in commit 396dfa9042305f62da1f56589c4b98fac57fc2f6
        !            46:  */
        !            47: 
        !            48: /*
        !            49:  *  If you are brave enough, continue now.  You cannot say you haven't been warned.
        !            50:  */
        !            51: 
        !            52: #undef LOCAL_DEBUG
        !            53: 
        !            54: #include "nest/bird.h"
        !            55: #include "nest/iface.h"
        !            56: #include "nest/route.h"
        !            57: #include "nest/protocol.h"
        !            58: #include "filter/filter.h"
        !            59: #include "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: };

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