File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / bird2 / nest / rt-show.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 (4 years, 8 months ago) by misho
Branches: bird2, MAIN
CVS tags: v2_0_7p0, HEAD
bird2 ver 2.0.7

    1: /*
    2:  *	BIRD -- Route Display Routines
    3:  *
    4:  *	(c) 1998--2000 Martin Mares <mj@ucw.cz>
    5:  *	(c) 2017       Jan Moskyto Matejka <mq@jmq.cz>
    6:  *
    7:  *	Can be freely distributed and used under the terms of the GNU GPL.
    8:  */
    9: 
   10: #undef LOCAL_DEBUG
   11: 
   12: #include "nest/bird.h"
   13: #include "nest/route.h"
   14: #include "nest/protocol.h"
   15: #include "nest/cli.h"
   16: #include "nest/iface.h"
   17: #include "filter/filter.h"
   18: 
   19: static void
   20: rt_show_table(struct cli *c, struct rt_show_data *d)
   21: {
   22:   /* No table blocks in 'show route count' */
   23:   if (d->stats == 2)
   24:     return;
   25: 
   26:   if (d->last_table) cli_printf(c, -1007, "");
   27:   cli_printf(c, -1007, "Table %s:", d->tab->table->name);
   28:   d->last_table = d->tab;
   29: }
   30: 
   31: static void
   32: rt_show_rte(struct cli *c, byte *ia, rte *e, struct rt_show_data *d)
   33: {
   34:   byte from[IPA_MAX_TEXT_LENGTH+8];
   35:   byte tm[TM_DATETIME_BUFFER_SIZE], info[256];
   36:   rta *a = e->attrs;
   37:   int primary = (e->net->routes == e);
   38:   int sync_error = (e->net->n.flags & KRF_SYNC_ERROR);
   39:   void (*get_route_info)(struct rte *, byte *buf);
   40:   struct nexthop *nh;
   41: 
   42:   tm_format_time(tm, &config->tf_route, e->lastmod);
   43:   if (ipa_nonzero(a->from) && !ipa_equal(a->from, a->nh.gw))
   44:     bsprintf(from, " from %I", a->from);
   45:   else
   46:     from[0] = 0;
   47: 
   48:   /* Need to normalize the extended attributes */
   49:   if (d->verbose && !rta_is_cached(a) && a->eattrs)
   50:     ea_normalize(a->eattrs);
   51: 
   52:   get_route_info = a->src->proto->proto->get_route_info;
   53:   if (get_route_info)
   54:     get_route_info(e, info);
   55:   else
   56:     bsprintf(info, " (%d)", e->pref);
   57: 
   58:   if (d->last_table != d->tab)
   59:     rt_show_table(c, d);
   60: 
   61:   cli_printf(c, -1007, "%-20s %s [%s %s%s]%s%s", ia, rta_dest_name(a->dest),
   62: 	     a->src->proto->name, tm, from, primary ? (sync_error ? " !" : " *") : "", info);
   63: 
   64:   if (a->dest == RTD_UNICAST)
   65:     for (nh = &(a->nh); nh; nh = nh->next)
   66:     {
   67:       char mpls[MPLS_MAX_LABEL_STACK*12 + 5], *lsp = mpls;
   68:       char *onlink = (nh->flags & RNF_ONLINK) ? " onlink" : "";
   69:       char weight[16] = "";
   70: 
   71:       if (nh->labels)
   72: 	{
   73: 	  lsp += bsprintf(lsp, " mpls %d", nh->label[0]);
   74: 	  for (int i=1;i<nh->labels; i++)
   75: 	    lsp += bsprintf(lsp, "/%d", nh->label[i]);
   76: 	}
   77:       *lsp = '\0';
   78: 
   79:       if (a->nh.next)
   80: 	bsprintf(weight, " weight %d", nh->weight + 1);
   81: 
   82:       if (ipa_nonzero(nh->gw))
   83: 	cli_printf(c, -1007, "\tvia %I on %s%s%s%s",
   84: 		   nh->gw, nh->iface->name, mpls, onlink, weight);
   85:       else
   86: 	cli_printf(c, -1007, "\tdev %s%s%s",
   87: 		   nh->iface->name, mpls,  onlink, weight);
   88:     }
   89: 
   90:   if (d->verbose)
   91:     rta_show(c, a);
   92: }
   93: 
   94: static void
   95: rt_show_net(struct cli *c, net *n, struct rt_show_data *d)
   96: {
   97:   rte *e, *ee;
   98:   byte ia[NET_MAX_TEXT_LENGTH+1];
   99:   struct channel *ec = d->tab->export_channel;
  100:   int first = 1;
  101:   int pass = 0;
  102: 
  103:   bsnprintf(ia, sizeof(ia), "%N", n->n.addr);
  104: 
  105:   for (e = n->routes; e; e = e->next)
  106:     {
  107:       if (rte_is_filtered(e) != d->filtered)
  108: 	continue;
  109: 
  110:       d->rt_counter++;
  111:       d->net_counter += first;
  112:       first = 0;
  113: 
  114:       if (pass)
  115: 	continue;
  116: 
  117:       ee = e;
  118:       rte_make_tmp_attrs(&e, c->show_pool, NULL);
  119: 
  120:       /* Export channel is down, do not try to export routes to it */
  121:       if (ec && (ec->export_state == ES_DOWN))
  122: 	goto skip;
  123: 
  124:       /* Special case for merged export */
  125:       if ((d->export_mode == RSEM_EXPORT) && (ec->ra_mode == RA_MERGED))
  126: 	{
  127: 	  rte *rt_free;
  128: 	  e = rt_export_merged(ec, n, &rt_free, c->show_pool, 1);
  129: 	  pass = 1;
  130: 
  131: 	  if (!e)
  132: 	  { e = ee; goto skip; }
  133: 	}
  134:       else if (d->export_mode)
  135: 	{
  136: 	  struct proto *ep = ec->proto;
  137: 	  int ic = ep->preexport ? ep->preexport(ep, &e, c->show_pool) : 0;
  138: 
  139: 	  if (ec->ra_mode == RA_OPTIMAL || ec->ra_mode == RA_MERGED)
  140: 	    pass = 1;
  141: 
  142: 	  if (ic < 0)
  143: 	    goto skip;
  144: 
  145: 	  if (d->export_mode > RSEM_PREEXPORT)
  146: 	    {
  147: 	      /*
  148: 	       * FIXME - This shows what should be exported according to current
  149: 	       * filters, but not what was really exported. 'configure soft'
  150: 	       * command may change the export filter and do not update routes.
  151: 	       */
  152: 	      int do_export = (ic > 0) ||
  153: 		(f_run(ec->out_filter, &e, c->show_pool, FF_SILENT) <= F_ACCEPT);
  154: 
  155: 	      if (do_export != (d->export_mode == RSEM_EXPORT))
  156: 		goto skip;
  157: 
  158: 	      if ((d->export_mode == RSEM_EXPORT) && (ec->ra_mode == RA_ACCEPTED))
  159: 		pass = 1;
  160: 	    }
  161: 	}
  162: 
  163:       if (d->show_protocol && (d->show_protocol != e->attrs->src->proto))
  164: 	goto skip;
  165: 
  166:       if (f_run(d->filter, &e, c->show_pool, 0) > F_ACCEPT)
  167: 	goto skip;
  168: 
  169:       if (d->stats < 2)
  170: 	rt_show_rte(c, ia, e, d);
  171: 
  172:       d->show_counter++;
  173:       ia[0] = 0;
  174: 
  175:     skip:
  176:       if (e != ee)
  177:       {
  178: 	rte_free(e);
  179: 	e = ee;
  180:       }
  181:       lp_flush(c->show_pool);
  182: 
  183:       if (d->primary_only)
  184: 	break;
  185:     }
  186: }
  187: 
  188: static void
  189: rt_show_cleanup(struct cli *c)
  190: {
  191:   struct rt_show_data *d = c->rover;
  192:   struct rt_show_data_rtable *tab;
  193: 
  194:   /* Unlink the iterator */
  195:   if (d->table_open)
  196:     fit_get(&d->tab->table->fib, &d->fit);
  197: 
  198:   /* Unlock referenced tables */
  199:   WALK_LIST(tab, d->tables)
  200:     rt_unlock_table(tab->table);
  201: }
  202: 
  203: static void
  204: rt_show_cont(struct cli *c)
  205: {
  206:   struct rt_show_data *d = c->rover;
  207: #ifdef DEBUGGING
  208:   unsigned max = 4;
  209: #else
  210:   unsigned max = 64;
  211: #endif
  212:   struct fib *fib = &d->tab->table->fib;
  213:   struct fib_iterator *it = &d->fit;
  214: 
  215:   if (d->running_on_config && (d->running_on_config != config))
  216:   {
  217:     cli_printf(c, 8004, "Stopped due to reconfiguration");
  218:     goto done;
  219:   }
  220: 
  221:   if (!d->table_open)
  222:   {
  223:     FIB_ITERATE_INIT(&d->fit, &d->tab->table->fib);
  224:     d->table_open = 1;
  225:     d->table_counter++;
  226: 
  227:     d->show_counter_last = d->show_counter;
  228:     d->rt_counter_last   = d->rt_counter;
  229:     d->net_counter_last  = d->net_counter;
  230: 
  231:     if (d->tables_defined_by & RSD_TDB_SET)
  232:       rt_show_table(c, d);
  233:   }
  234: 
  235:   FIB_ITERATE_START(fib, it, net, n)
  236:   {
  237:     if (!max--)
  238:     {
  239:       FIB_ITERATE_PUT(it);
  240:       return;
  241:     }
  242:     rt_show_net(c, n, d);
  243:   }
  244:   FIB_ITERATE_END;
  245: 
  246:   if (d->stats)
  247:   {
  248:     if (d->last_table != d->tab)
  249:       rt_show_table(c, d);
  250: 
  251:     cli_printf(c, -1007, "%d of %d routes for %d networks in table %s",
  252: 	       d->show_counter - d->show_counter_last, d->rt_counter - d->rt_counter_last,
  253: 	       d->net_counter - d->net_counter_last, d->tab->table->name);
  254:   }
  255: 
  256:   d->table_open = 0;
  257:   d->tab = NODE_NEXT(d->tab);
  258: 
  259:   if (NODE_VALID(d->tab))
  260:     return;
  261: 
  262:   if (d->stats && (d->table_counter > 1))
  263:   {
  264:     if (d->last_table) cli_printf(c, -1007, "");
  265:     cli_printf(c, 14, "Total: %d of %d routes for %d networks in %d tables",
  266: 	       d->show_counter, d->rt_counter, d->net_counter, d->table_counter);
  267:   }
  268:   else
  269:     cli_printf(c, 0, "");
  270: 
  271: done:
  272:   rt_show_cleanup(c);
  273:   c->cont = c->cleanup = NULL;
  274: }
  275: 
  276: struct rt_show_data_rtable *
  277: rt_show_add_table(struct rt_show_data *d, rtable *t)
  278: {
  279:   struct rt_show_data_rtable *tab = cfg_allocz(sizeof(struct rt_show_data_rtable));
  280:   tab->table = t;
  281:   add_tail(&(d->tables), &(tab->n));
  282:   return tab;
  283: }
  284: 
  285: static inline void
  286: rt_show_get_default_tables(struct rt_show_data *d)
  287: {
  288:   struct channel *c;
  289:   struct rt_show_data_rtable *tab;
  290: 
  291:   if (d->export_channel)
  292:   {
  293:     c = d->export_channel;
  294:     tab = rt_show_add_table(d, c->table);
  295:     tab->export_channel = c;
  296:     return;
  297:   }
  298: 
  299:   if (d->export_protocol)
  300:   {
  301:     WALK_LIST(c, d->export_protocol->channels)
  302:     {
  303:       if (c->export_state == ES_DOWN)
  304: 	continue;
  305: 
  306:       tab = rt_show_add_table(d, c->table);
  307:       tab->export_channel = c;
  308:     }
  309:     return;
  310:   }
  311: 
  312:   if (d->show_protocol)
  313:   {
  314:     WALK_LIST(c, d->show_protocol->channels)
  315:       rt_show_add_table(d, c->table);
  316:     return;
  317:   }
  318: 
  319:   for (int i=1; i<NET_MAX; i++)
  320:     if (config->def_tables[i])
  321:       rt_show_add_table(d, config->def_tables[i]->table);
  322: }
  323: 
  324: static inline void
  325: rt_show_prepare_tables(struct rt_show_data *d)
  326: {
  327:   struct rt_show_data_rtable *tab, *tabx;
  328: 
  329:   /* Add implicit tables if no table is specified */
  330:   if (EMPTY_LIST(d->tables))
  331:     rt_show_get_default_tables(d);
  332: 
  333:   WALK_LIST_DELSAFE(tab, tabx, d->tables)
  334:   {
  335:     /* Ensure there is defined export_channel for each table */
  336:     if (d->export_mode)
  337:     {
  338:       if (!tab->export_channel && d->export_channel &&
  339: 	  (tab->table == d->export_channel->table))
  340: 	tab->export_channel = d->export_channel;
  341: 
  342:       if (!tab->export_channel && d->export_protocol)
  343: 	tab->export_channel = proto_find_channel_by_table(d->export_protocol, tab->table);
  344: 
  345:       if (!tab->export_channel)
  346:       {
  347: 	if (d->tables_defined_by & RSD_TDB_NMN)
  348: 	  cf_error("No export channel for table %s", tab->table->name);
  349: 
  350: 	rem_node(&(tab->n));
  351: 	continue;
  352:       }
  353:     }
  354: 
  355:     /* Ensure specified network is compatible with each table */
  356:     if (d->addr && (tab->table->addr_type != d->addr->type))
  357:     {
  358:       if (d->tables_defined_by & RSD_TDB_NMN)
  359: 	cf_error("Incompatible type of prefix/ip for table %s", tab->table->name);
  360: 
  361:       rem_node(&(tab->n));
  362:       continue;
  363:     }
  364:   }
  365: 
  366:   /* Ensure there is at least one table */
  367:   if (EMPTY_LIST(d->tables))
  368:     cf_error("No valid tables");
  369: }
  370: 
  371: void
  372: rt_show(struct rt_show_data *d)
  373: {
  374:   struct rt_show_data_rtable *tab;
  375:   net *n;
  376: 
  377:   /* Filtered routes are neither exported nor have sensible ordering */
  378:   if (d->filtered && (d->export_mode || d->primary_only))
  379:     cf_error("Incompatible show route options");
  380: 
  381:   rt_show_prepare_tables(d);
  382: 
  383:   if (!d->addr)
  384:   {
  385:     WALK_LIST(tab, d->tables)
  386:       rt_lock_table(tab->table);
  387: 
  388:     /* There is at least one table */
  389:     d->tab = HEAD(d->tables);
  390:     this_cli->cont = rt_show_cont;
  391:     this_cli->cleanup = rt_show_cleanup;
  392:     this_cli->rover = d;
  393:   }
  394:   else
  395:   {
  396:     WALK_LIST(tab, d->tables)
  397:     {
  398:       d->tab = tab;
  399: 
  400:       if (d->show_for)
  401: 	n = net_route(tab->table, d->addr);
  402:       else
  403: 	n = net_find(tab->table, d->addr);
  404: 
  405:       if (n)
  406: 	rt_show_net(this_cli, n, d);
  407:     }
  408: 
  409:     if (d->rt_counter)
  410:       cli_msg(0, "");
  411:     else
  412:       cli_msg(8001, "Network not found");
  413:   }
  414: }

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