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>