]>
git.ipfire.org Git - thirdparty/bird.git/blob - nest/rt-show.c
2 * BIRD -- Route Display Routines
4 * (c) 1998--2000 Martin Mares <mj@ucw.cz>
5 * (c) 2017 Jan Moskyto Matejka <mq@jmq.cz>
7 * Can be freely distributed and used under the terms of the GNU GPL.
12 #include "nest/bird.h"
13 #include "nest/route.h"
14 #include "nest/protocol.h"
16 #include "nest/iface.h"
17 #include "filter/filter.h"
18 #include "filter/data.h"
19 #include "sysdep/unix/krt.h"
22 rt_show_table(struct cli
*c
, struct rt_show_data
*d
)
24 /* No table blocks in 'show route count' */
28 if (d
->last_table
) cli_printf(c
, -1007, "");
29 cli_printf(c
, -1007, "Table %s:", d
->tab
->table
->name
);
30 d
->last_table
= d
->tab
;
33 static inline struct krt_proto
*
34 rt_show_get_kernel(struct rt_show_data
*d
)
36 struct proto_config
*krt
= d
->tab
->table
->config
->krt_attached
;
37 return krt
? (struct krt_proto
*) krt
->proto
: NULL
;
41 rt_show_rte(struct cli
*c
, byte
*ia
, rte
*e
, struct rt_show_data
*d
, int primary
)
43 byte from
[IPA_MAX_TEXT_LENGTH
+8];
44 byte tm
[TM_DATETIME_BUFFER_SIZE
], info
[256];
46 int sync_error
= d
->kernel
? krt_get_sync_error(d
->kernel
, e
) : 0;
47 void (*get_route_info
)(struct rte
*, byte
*buf
);
50 tm_format_time(tm
, &config
->tf_route
, e
->lastmod
);
51 if (ipa_nonzero(a
->from
) && !ipa_equal(a
->from
, a
->nh
.gw
))
52 bsprintf(from
, " from %I", a
->from
);
56 /* Need to normalize the extended attributes */
57 if (d
->verbose
&& !rta_is_cached(a
) && a
->eattrs
)
58 ea_normalize(a
->eattrs
);
60 get_route_info
= e
->src
->proto
->proto
->get_route_info
;
62 get_route_info(e
, info
);
64 bsprintf(info
, " (%d)", a
->pref
);
66 if (d
->last_table
!= d
->tab
)
69 cli_printf(c
, -1007, "%-20s %s [%s %s%s]%s%s", ia
, rta_dest_name(a
->dest
),
70 e
->src
->proto
->name
, tm
, from
, primary
? (sync_error
? " !" : " *") : "", info
);
72 if (a
->dest
== RTD_UNICAST
)
73 for (nh
= &(a
->nh
); nh
; nh
= nh
->next
)
75 char mpls
[MPLS_MAX_LABEL_STRING
], *lsp
= mpls
;
76 char *onlink
= (nh
->flags
& RNF_ONLINK
) ? " onlink" : "";
81 lsp
+= bsprintf(lsp
, " mpls %d", nh
->label
[0]);
82 for (int i
=1;i
<nh
->labels
; i
++)
83 lsp
+= bsprintf(lsp
, "/%d", nh
->label
[i
]);
88 bsprintf(weight
, " weight %d", nh
->weight
+ 1);
90 if (ipa_nonzero(nh
->gw
))
91 cli_printf(c
, -1007, "\tvia %I on %s%s%s%s",
92 nh
->gw
, nh
->iface
->name
, mpls
, onlink
, weight
);
94 cli_printf(c
, -1007, "\tdev %s%s%s",
95 nh
->iface
->name
, mpls
, onlink
, weight
);
103 rt_show_net(struct cli
*c
, net
*n
, struct rt_show_data
*d
)
106 byte ia
[NET_MAX_TEXT_LENGTH
+16+1];
107 struct channel
*ec
= d
->tab
->export_channel
;
109 /* The Clang static analyzer complains that ec may be NULL.
110 * It should be ensured to be not NULL by rt_show_prepare_tables() */
111 ASSUME(!d
->export_mode
|| ec
);
118 for (e
= n
->routes
; e
; e
= e
->next
)
120 if (rte_is_filtered(e
) != d
->filtered
)
124 d
->net_counter
+= first
;
132 /* Export channel is down, do not try to export routes to it */
133 if (ec
&& (ec
->export_state
== ES_DOWN
))
136 if (d
->export_mode
== RSEM_EXPORTED
)
138 if (!bmap_test(&ec
->export_map
, ee
->id
))
141 // if (ec->ra_mode != RA_ANY)
144 else if ((d
->export_mode
== RSEM_EXPORT
) && (ec
->ra_mode
== RA_MERGED
))
146 /* Special case for merged export */
148 e
= rt_export_merged(ec
, n
, &rt_free
, c
->show_pool
, 1);
152 { e
= ee
; goto skip
; }
154 else if (d
->export_mode
)
156 struct proto
*ep
= ec
->proto
;
157 int ic
= ep
->preexport
? ep
->preexport(ec
, e
) : 0;
159 if (ec
->ra_mode
== RA_OPTIMAL
|| ec
->ra_mode
== RA_MERGED
)
165 if (d
->export_mode
> RSEM_PREEXPORT
)
168 * FIXME - This shows what should be exported according to current
169 * filters, but not what was really exported. 'configure soft'
170 * command may change the export filter and do not update routes.
172 int do_export
= (ic
> 0) ||
173 (f_run(ec
->out_filter
, &e
, c
->show_pool
, FF_SILENT
) <= F_ACCEPT
);
175 if (do_export
!= (d
->export_mode
== RSEM_EXPORT
))
178 if ((d
->export_mode
== RSEM_EXPORT
) && (ec
->ra_mode
== RA_ACCEPTED
))
183 if (d
->show_protocol
&& (d
->show_protocol
!= e
->src
->proto
))
186 if (f_run(d
->filter
, &e
, c
->show_pool
, 0) > F_ACCEPT
)
191 int label
= (int) ea_get_int(e
->attrs
->eattrs
, EA_MPLS_LABEL
, (uint
) -1);
193 if (first_show
|| (last_label
!= label
))
196 net_format(n
->n
.addr
, ia
, sizeof(ia
));
198 bsnprintf(ia
, sizeof(ia
), "%N mpls %d", n
->n
.addr
, label
);
203 rt_show_rte(c
, ia
, e
, d
, (e
->net
->routes
== ee
));
216 lp_flush(c
->show_pool
);
224 rt_show_cleanup(struct cli
*c
)
226 struct rt_show_data
*d
= c
->rover
;
227 struct rt_show_data_rtable
*tab
;
229 /* Unlink the iterator */
230 if (d
->table_open
&& !d
->trie_walk
)
231 fit_get(&d
->tab
->table
->fib
, &d
->fit
);
234 rt_unlock_trie(d
->tab
->table
, d
->walk_lock
);
236 /* Unlock referenced tables */
237 WALK_LIST(tab
, d
->tables
)
238 rt_unlock_table(tab
->table
);
242 rt_show_cont(struct cli
*c
)
244 struct rt_show_data
*d
= c
->rover
;
245 struct rtable
*tab
= d
->tab
->table
;
251 struct fib
*fib
= &tab
->fib
;
252 struct fib_iterator
*it
= &d
->fit
;
254 if (d
->running_on_config
&& (d
->running_on_config
!= config
))
256 cli_printf(c
, 8004, "Stopped due to reconfiguration");
262 /* We use either trie-based walk or fib-based walk */
263 d
->trie_walk
= tab
->trie
&&
264 (d
->addr_mode
== RSD_ADDR_IN
) &&
265 net_val_match(tab
->addr_type
, NB_IP
);
267 if (d
->trie_walk
&& !d
->walk_state
)
268 d
->walk_state
= lp_allocz(c
->parser_pool
, sizeof (struct f_trie_walk_state
));
272 d
->walk_lock
= rt_lock_trie(tab
);
273 trie_walk_init(d
->walk_state
, tab
->trie
, d
->addr
);
276 FIB_ITERATE_INIT(&d
->fit
, &tab
->fib
);
280 d
->kernel
= rt_show_get_kernel(d
);
282 d
->show_counter_last
= d
->show_counter
;
283 d
->rt_counter_last
= d
->rt_counter
;
284 d
->net_counter_last
= d
->net_counter
;
286 if (d
->tables_defined_by
& RSD_TDB_SET
)
292 /* Trie-based walk */
294 while (trie_walk_next(d
->walk_state
, &addr
))
296 net
*n
= net_find(tab
, &addr
);
300 rt_show_net(c
, n
, d
);
306 rt_unlock_trie(tab
, d
->walk_lock
);
312 FIB_ITERATE_START(fib
, it
, net
, n
)
314 if ((d
->addr_mode
== RSD_ADDR_IN
) && (!net_in_netX(n
->n
.addr
, d
->addr
)))
322 rt_show_net(c
, n
, d
);
331 if (d
->last_table
!= d
->tab
)
334 cli_printf(c
, -1007, "%d of %d routes for %d networks in table %s",
335 d
->show_counter
- d
->show_counter_last
, d
->rt_counter
- d
->rt_counter_last
,
336 d
->net_counter
- d
->net_counter_last
, tab
->name
);
341 d
->tab
= NODE_NEXT(d
->tab
);
343 if (NODE_VALID(d
->tab
))
346 if (d
->stats
&& (d
->table_counter
> 1))
348 if (d
->last_table
) cli_printf(c
, -1007, "");
349 cli_printf(c
, 14, "Total: %d of %d routes for %d networks in %d tables",
350 d
->show_counter
, d
->rt_counter
, d
->net_counter
, d
->table_counter
);
353 cli_printf(c
, 0, "");
357 c
->cont
= c
->cleanup
= NULL
;
360 struct rt_show_data_rtable
*
361 rt_show_add_table(struct rt_show_data
*d
, rtable
*t
)
363 struct rt_show_data_rtable
*tab
= cfg_allocz(sizeof(struct rt_show_data_rtable
));
365 add_tail(&(d
->tables
), &(tab
->n
));
370 rt_show_get_default_tables(struct rt_show_data
*d
)
373 struct rt_show_data_rtable
*tab
;
375 if (d
->export_channel
)
377 c
= d
->export_channel
;
378 tab
= rt_show_add_table(d
, c
->table
);
379 tab
->export_channel
= c
;
383 if (d
->export_protocol
)
385 WALK_LIST(c
, d
->export_protocol
->channels
)
387 if (c
->export_state
== ES_DOWN
)
390 tab
= rt_show_add_table(d
, c
->table
);
391 tab
->export_channel
= c
;
396 if (d
->show_protocol
)
398 WALK_LIST(c
, d
->show_protocol
->channels
)
399 rt_show_add_table(d
, c
->table
);
403 for (int i
=1; i
<NET_MAX
; i
++)
404 if (config
->def_tables
[i
] && config
->def_tables
[i
]->table
)
405 rt_show_add_table(d
, config
->def_tables
[i
]->table
);
409 rt_show_prepare_tables(struct rt_show_data
*d
)
411 struct rt_show_data_rtable
*tab
, *tabx
;
413 /* Add implicit tables if no table is specified */
414 if (EMPTY_LIST(d
->tables
))
415 rt_show_get_default_tables(d
);
417 WALK_LIST_DELSAFE(tab
, tabx
, d
->tables
)
419 /* Ensure there is defined export_channel for each table */
422 if (!tab
->export_channel
&& d
->export_channel
&&
423 (tab
->table
== d
->export_channel
->table
))
424 tab
->export_channel
= d
->export_channel
;
426 if (!tab
->export_channel
&& d
->export_protocol
)
427 tab
->export_channel
= proto_find_channel_by_table(d
->export_protocol
, tab
->table
);
429 if (!tab
->export_channel
)
431 if (d
->tables_defined_by
& RSD_TDB_NMN
)
432 cf_error("No export channel for table %s", tab
->table
->name
);
439 /* Ensure specified network is compatible with each table */
440 if (d
->addr
&& (tab
->table
->addr_type
!= d
->addr
->type
))
442 if (d
->tables_defined_by
& RSD_TDB_NMN
)
443 cf_error("Incompatible type of prefix/ip for table %s", tab
->table
->name
);
450 /* Ensure there is at least one table */
451 if (EMPTY_LIST(d
->tables
))
452 cf_error("No valid tables");
456 rt_show(struct rt_show_data
*d
)
458 struct rt_show_data_rtable
*tab
;
461 /* Filtered routes are neither exported nor have sensible ordering */
462 if (d
->filtered
&& (d
->export_mode
|| d
->primary_only
))
463 cf_error("Incompatible show route options");
465 rt_show_prepare_tables(d
);
467 if (!d
->addr
|| (d
->addr_mode
== RSD_ADDR_IN
))
469 WALK_LIST(tab
, d
->tables
)
470 rt_lock_table(tab
->table
);
472 /* There is at least one table */
473 d
->tab
= HEAD(d
->tables
);
474 this_cli
->cont
= rt_show_cont
;
475 this_cli
->cleanup
= rt_show_cleanup
;
480 WALK_LIST(tab
, d
->tables
)
483 d
->kernel
= rt_show_get_kernel(d
);
485 if (d
->addr_mode
== RSD_ADDR_FOR
)
486 n
= net_route(tab
->table
, d
->addr
);
488 n
= net_find(tab
->table
, d
->addr
);
491 rt_show_net(this_cli
, n
, d
);
497 cli_msg(8001, "Network not found");