Annotation of embedaddon/bird2/nest/rt-show.c, revision 1.1.1.1

1.1       misho       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>