Annotation of embedaddon/bird2/nest/rt-show.c, revision 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>