File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / bird2 / sysdep / unix / krt.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Mon Oct 21 16:03:56 2019 UTC (5 years, 5 months ago) by misho
Branches: bird2, MAIN
CVS tags: v2_0_7p0, HEAD
bird2 ver 2.0.7

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

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