TRIP Routing Daemon
TRIP (RFC 3219) Location Server Implementation
Loading...
Searching...
No Matches
trib.c
Go to the documentation of this file.
1/*
2
3 trip: Modern TRIP LS implementation
4 Copyright (C) 2025 arf20 (Ángel Ruiz Fernandez)
5
6 This program is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <https://www.gnu.org/licenses/>.
18
19 trib.c: Telephony Routing Information Bases
20
21*/
22
27
28#include "trib.h"
29#include "db/pib.h"
30#include "protocol/protocol.h"
31#include <time.h>
32
33#define _COMPONENT_ "db"
34
35#include <logging/logging.h>
36
37#include <stdlib.h>
38#include <string.h>
39
40#define INIT_TABLE_CAPACITY 256
41#define INIT_ADJ_TRIBS_CAPACITY 32
42
43static trib_t g_trib = { 0 };
44
45const char *entry_type_strs[] = {
46 "TRIP",
47 "CONNECTED",
48 "STATIC"
49};
50
51entry_t *
52entry_clone(const entry_t *entry)
53{
54 entry_t *ne = malloc(sizeof(entry_t));
55 /* shallow copy */
56 *ne = *entry;
57 /* deep copy */
58 ne->attrs = entry->attrs;
59 ne->prefix = strdup(entry->prefix);
60 ne->attrs.nexthop = strdup(entry->attrs.nexthop);
61 if (ATTR_IS_USED_ADVERTPATH(entry->attrs.use)) {
62 ne->attrs.advertpath = malloc(sizeof(uint32_t)
63 * entry->attrs.advertpath_size);
64 memcpy(ne->attrs.advertpath, entry->attrs.advertpath, sizeof(uint32_t)
65 * entry->attrs.advertpath_size);
66 } else ne->attrs.advertpath = NULL;
67 if (ATTR_IS_USED_ROUTEDPATH(entry->attrs.use)) {
68 ne->attrs.routedpath = malloc(sizeof(uint32_t)
69 * entry->attrs.routedpath_size);
70 memcpy(ne->attrs.routedpath, entry->attrs.routedpath, sizeof(uint32_t)
71 * entry->attrs.routedpath_size);
72 } else ne->attrs.routedpath = NULL;
73 if (ATTR_IS_USED_COMMUNITIES(entry->attrs.use)) {
74 ne->attrs.communities = malloc(sizeof(uint32_t)
75 * entry->attrs.communities_size);
76 memcpy(ne->attrs.communities, entry->attrs.communities,
77 sizeof(community_t) * entry->attrs.communities_size);
78 } else ne->attrs.communities = NULL;
79 return ne;
80}
81
82void
84{
85 free(entry->prefix);
86 free(entry->attrs.nexthop);
87 if (ATTR_IS_USED_ADVERTPATH(entry->attrs.use))
88 free(entry->attrs.advertpath);
89 if (ATTR_IS_USED_ROUTEDPATH(entry->attrs.use))
90 free(entry->attrs.routedpath);
91 if (ATTR_IS_USED_COMMUNITIES(entry->attrs.use))
92 free(entry->attrs.communities);
93 free(entry);
94}
95
96static void
97table_init(table_t *t)
98{
99 t->capacity = INIT_TABLE_CAPACITY;
100 t->size = 0;
101 t->table = malloc(t->capacity * sizeof(entry_t*));
102 t->routemap = NULL;
103}
104
105static void
106table_copy(table_t *dst, table_t *src)
107{
108 for (size_t i = 0; i < src->size; i++)
109 trib_table_insert(dst, entry_clone(src->table[i]));
110}
111
112void
114{
115 for (size_t i = 0; i < t->size; i++)
116 entry_destroy(t->table[i]);
117 free(t->table);
118}
119
120trib_t *
121trib_new(uint32_t local_itad)
122{
123 if (g_trib.local_routes.table)
124 return NULL;
125
126 trib_t *t = &g_trib;
127
128 t->local_itad = local_itad;
129
130 table_init(&t->local_routes);
131 table_init(&t->ext_trib);
132 table_init(&t->loc_trib);
133 table_init(&t->optimized_loc_trib);
134
135 t->adj_tribs_capacity = INIT_ADJ_TRIBS_CAPACITY;
136 t->adj_tribs_size = 0;
137 t->adj_tribs_in = malloc(t->adj_tribs_capacity * sizeof(table_t));
138 t->adj_tribs_out = malloc(t->adj_tribs_capacity * sizeof(table_t));
139
140 return t;
141}
142
143void
145{
146 if (trib->adj_tribs_capacity < trib->adj_tribs_size + 1) {
147 trib->adj_tribs_capacity *= 2;
148 trib->adj_tribs_in = realloc(trib->adj_tribs_in,
149 trib->adj_tribs_capacity * sizeof(table_t));
150 trib->adj_tribs_out = realloc(trib->adj_tribs_out,
151 trib->adj_tribs_capacity * sizeof(table_t));
152 }
153
154 trib->adj_tribs_in[trib->adj_tribs_size] = in;
155 trib->adj_tribs_out[trib->adj_tribs_size] = out;
156 trib->adj_tribs_size++;
157
158 table_init(in);
159 table_init(out);
160}
161
162void
163trib_adj_pair_remove(trib_t *trib, table_t *in, table_t *out)
164{
165 for (size_t i = 0; i < trib->adj_tribs_size; i++) {
166 if (trib->adj_tribs_in[i] == in && trib->adj_tribs_out[i] == out) {
169 memmove(&trib->adj_tribs_in[i], &trib->adj_tribs_in[i+1],
170 sizeof(table_t*) * (trib->adj_tribs_size - i));
171 memmove(&trib->adj_tribs_out[i], &trib->adj_tribs_out[i+1],
172 sizeof(table_t*) * (trib->adj_tribs_size - i));
173 trib->adj_tribs_size--;
174 return;
175 }
176 }
177}
178
179void
181{
182 trib_table_deinit(&trib->local_routes);
183 trib_table_deinit(&trib->ext_trib);
184 trib_table_deinit(&trib->loc_trib);
185 trib_table_deinit(&trib->optimized_loc_trib);
186 free(trib->adj_tribs_in);
187 free(trib->adj_tribs_out);
188}
189
190
191entry_t **
192trib_table_find(table_t *t, uint16_t af, const char *prefix)
193{
194 for (size_t i = 0; i < t->size; i++)
195 if (t->table[i]->af == af && strcmp(t->table[i]->prefix, prefix) == 0)
196 return &t->table[i];
197 return NULL;
198}
199
200const entry_t *
201trib_table_lookup(const table_t *table, uint16_t af, uint16_t app_proto,
202 const char *address)
203{
204 int specificity = 0;
205 const entry_t *e = NULL;
206 for (size_t i = 0; i < table->size; i++) {
207 if (af && table->table[i]->af != af)
208 continue;
209 if (app_proto && table->table[i]->app_proto != app_proto)
210 continue;
211 int len = strlen(table->table[i]->prefix);
212 if (strncmp(table->table[i]->prefix, address, len) == 0)
213 {
214 if (len <= specificity)
215 continue;
216 specificity = len;
217 e = table->table[i];
218 }
219 }
220 return e;
221}
222
223void
225{
226 if (table->capacity < table->size + 1) {
227 table->capacity *= 2;
228 table->table = realloc(table->table,
229 table->capacity * sizeof(entry_t*));
230 }
231
232 table->table[table->size++] = entry;
233}
234
235void
236trib_table_insert_or_replace(table_t *table, entry_t *route)
237{
238 entry_t **match = trib_table_find(table, route->af, route->prefix);
239
240 if (!match) {
241 /* insert new route */
242 trib_table_insert(table, route);
243 return;
244 }
245
246 /* replace (update) existing route */
247 entry_destroy(*match);
248 *match = route;
249}
250
251void
252trib_table_insert_or_replace_if_new(table_t *table, entry_t *route)
253{
254 entry_t **match = trib_table_find(table, route->af, route->prefix);
255
256 if (!match) {
257 /* insert new route */
258 trib_table_insert(table, route);
259 return;
260 }
261
262 /* check if different */
263 if (
264 ((*match)->app_proto == route->app_proto) &&
265 ((*match)->attrs.convertedroute == route->attrs.convertedroute) &&
266 ((*match)->attrs.routedpath_size == route->attrs.routedpath_size) &&
267 ((*match)->attrs.advertpath_size == route->attrs.advertpath_size) &&
268 ((*match)->attrs.communities_size == route->attrs.communities_size) &&
269 ((*match)->attrs.atomicaggregate == route->attrs.atomicaggregate) &&
270 ((*match)->attrs.local_pref == route->attrs.local_pref) &&
271 ((*match)->attrs.metric == route->attrs.metric) &&
272 ((*match)->attrs.nextitad == route->attrs.nextitad) &&
273 (strcmp((*match)->attrs.nexthop, route->attrs.nexthop) == 0) &&
274 (memcmp((*match)->attrs.advertpath, route->attrs.advertpath,
275 sizeof(uint32_t) * route->attrs.advertpath_size) == 0) &&
276 (memcmp((*match)->attrs.routedpath, route->attrs.routedpath,
277 sizeof(uint32_t) * route->attrs.routedpath_size) == 0) &&
278 (memcmp((*match)->attrs.communities, route->attrs.communities,
279 sizeof(uint32_t) * route->attrs.communities_size) == 0) &&
280 ((*match)->attrs.withdrawn == route->attrs.withdrawn) &&
281 ((*match)->attrs.use == route->attrs.use)
282 ) {
283 return;
284 }
285
286 /* update seq */
287 if ((*match)->seq < route->seq)
288 (*match)->seq = route->seq;
289
290 /* replace (update) existing route (marked unsent) */
291 entry_destroy(*match);
292 *match = route;
293}
294
295void
297{
298 for (size_t i = 0; i < table->size; i++)
299 entry_destroy(table->table[i]);
300 table->size = 0;
301}
302
303
316static int
317entry_compare(const entry_t *e1, const entry_t *e2, uint32_t itad)
318{
319 if (e1->attrs.local_pref != e2->attrs.local_pref)
320 return e1->attrs.local_pref < e2->attrs.local_pref;
321 if (e1->type != e2->type)
322 return e1->type < e2->type;
323 if (e1->attrs.routedpath_size != e2->attrs.routedpath_size)
324 return e1->attrs.routedpath_size < e2->attrs.routedpath_size;
325 if (e1->attrs.metric != e2->attrs.metric)
326 return e1->attrs.metric < e2->attrs.metric;
327 if ((e1->learn_itad == itad) != (e2->learn_itad == itad))
328 return e2->learn_itad == itad;
329 if (e1->time != e2->time)
330 return e1->time > e2->time;
331 if (e1->learn_lsid != e2->learn_lsid)
332 return e1->learn_lsid < e2->learn_lsid;
333 INFO("identical route preference for %s", e1->prefix);
334 return 0;
335}
336
346static void
347table_select_into(table_t *t1, table_t *t2, uint32_t itad)
348{
349 for (size_t i = 0; i < t2->size; i++) {
350 entry_t **match = trib_table_find(t1, t2->table[i]->af,
351 t2->table[i]->prefix);
352 if (!match) {
353 trib_table_insert(t1, entry_clone(t2->table[i]));
354 continue;
355 }
356
357 /* replace entry */
358 if (entry_compare(*match, t2->table[i], itad)) {
359 entry_destroy(*match);
360 *match = entry_clone(t2->table[i]);
361 continue;
362 }
363
364 DEBUG("route %s left out of selection algo", t2->table[i]->prefix);
365 }
366}
367
369static void
370optimize_table(table_t *dst, table_t *src)
371{
372 for (size_t i = 0; i < src->size; i++) {
373 /* TODO: */
374 trib_table_insert(dst, entry_clone(src->table[i]));
375 }
376}
377
379static void
380apply_policy(table_t *dst, const table_t *src, uint32_t local_itad,
381 const routemap_t *policy)
382{
383 for (size_t i = 0; i < src->size; i++) {
384 const routemap_statement_t *s =
385 routemap_match(policy, src->table[i]->prefix);
386 if (!s || s->deny) {
387 DEBUG("route %s denied", src->table[i]->prefix);
388 continue; /* default deny */
389 }
390
391 entry_t *e = entry_clone(src->table[i]);
392
393 for (size_t j = 0; j < s->actions_size; j++) {
394 switch (s->actions[j].attribute) {
397 e->attrs.local_pref = s->actions[j].value;
398 break;
400 free(e->attrs.nexthop);
401 e->attrs.nexthop = strdup(s->actions[j].valstr2);
402 break;
404 e->attrs.routedpath_size = s->actions[j].value
405 + e->attrs.routedpath_size;
406 e->attrs.routedpath = realloc(e->attrs.routedpath,
407 e->attrs.routedpath_size * sizeof(uint32_t));
408 for (size_t k = 0; k < s->actions[j].value; k++)
409 e->attrs.routedpath[k] = local_itad;
410 break;
411 }
412 }
413
414 trib_table_insert(dst, e);
415 }
416}
417
418
419void
421{
422 for (size_t i = 0; i < trib->local_routes.size; i++) {
423 entry_attrs_t *a = &trib->local_routes.table[i]->attrs;
424 a->nextitad = trib->local_itad;
425 }
426
427 trib_update_full(trib);
428}
429
431static table_t *
432select_eligible_routes_out(table_t *loc, uint32_t itad, uint32_t id)
433{
434 table_t *t = malloc(sizeof(table_t));
435 table_init(t);
436
437 for (size_t i = 0; i < loc->size; i++) {
438 if ((loc->table[i]->learn_itad == itad &&
439 loc->table[i]->learn_lsid == id))
440 {
441 continue;
442 }
443 for (int j = 0; j < loc->table[i]->attrs.advertpath_size; j++)
444 if (loc->table[i]->attrs.advertpath[j] == itad)
445 continue;
446 for (int j = 0; j < loc->table[i]->attrs.routedpath_size; j++)
447 if (loc->table[i]->attrs.routedpath[j] == itad)
448 continue;
449 if (loc->table[i]->attrs.nextitad == itad)
450 continue;
451 trib_table_insert(t, entry_clone(loc->table[i]));
452 }
453
454 return t;
455}
456
457void
458trib_update_adj_out(trib_t *trib, table_t *adj_trib_out)
459{
460 /* get eligible routes for peer */
461 table_t *eligible = select_eligible_routes_out(&trib->optimized_loc_trib,
462 adj_trib_out->peer_itad, adj_trib_out->peer_id);
463
464 table_t policied = { };
465 table_init(&policied);
466
467 /* apply output policy if applicable */
468 if (adj_trib_out->routemap)
469 apply_policy(&policied, eligible, trib->local_itad,
470 adj_trib_out->routemap);
471 else
472 table_copy(&policied, eligible); /* stupid copy */
473
474 for (size_t i = 0; i < policied.size; i++)
475 trib_table_insert_or_replace_if_new(adj_trib_out,
476 entry_clone(policied.table[i]));
477
478 trib_table_deinit(&policied);
479 trib_table_deinit(eligible);
480 free(eligible);
481}
482
483void
485{
486 trib_table_clear(&trib->ext_trib);
487 trib_table_clear(&trib->loc_trib);
488 trib_table_clear(&trib->optimized_loc_trib);
489
490 /* Phase 2a: local routes and external Ext-TRIBs-in to Ext-TRIB */
491 table_t scratch; /* temporary working table */
492 table_init(&scratch);
493
494 struct timespec start, end;
495 clock_gettime(CLOCK_THREAD_CPUTIME_ID, &start);
496
497 table_select_into(&trib->ext_trib, &trib->local_routes, trib->local_itad);
498 for (size_t i = 0; i < trib->adj_tribs_size; i++) {
499 if (trib->adj_tribs_in[i]->peer_itad != trib->local_itad) {
500 /* apply input policy if applicable */
501 if (trib->adj_tribs_in[i]->routemap) {
502 trib_table_clear(&scratch);
503 apply_policy(&scratch, trib->adj_tribs_in[i], trib->local_itad,
504 trib->adj_tribs_in[i]->routemap);
505 table_select_into(&trib->ext_trib, &scratch, trib->local_itad);
506 } else
507 table_select_into(&trib->ext_trib, trib->adj_tribs_in[i],
508 trib->local_itad);
509 }
510 }
511
512 /* Phase 2b: Ext-TRIB and internal Ext-TRIBs-in to Loc-TRIB */
513 table_select_into(&trib->loc_trib, &trib->ext_trib, trib->local_itad);
514 for (size_t i = 0; i < trib->adj_tribs_size; i++)
515 if (trib->adj_tribs_in[i]->peer_itad == trib->local_itad)
516 table_select_into(&trib->loc_trib, trib->adj_tribs_in[i],
517 trib->local_itad);
518
519 /* Phase 3: Loc-TRIB to Ext-TRIBs-Out */
520 /* optimize table */
521 optimize_table(&trib->optimized_loc_trib, &trib->loc_trib);
522
523 for (size_t i = 0; i < trib->adj_tribs_size; i++) {
524 trib_update_adj_out(trib, trib->adj_tribs_out[i]);
525 }
526
527 clock_gettime(CLOCK_THREAD_CPUTIME_ID, &end);
528
529 DEBUG("TRIB updated in %fus", (1000000.0 * (double)(end.tv_sec - start.tv_sec))
530 + (0.001 * (double)(end.tv_nsec - start.tv_nsec)));
531
532 trib_table_deinit(&scratch);
533}
534
535
536size_t
537get_new_entries(const table_t *table, entry_t ***new_ents_out)
538{
539 size_t new_ents_size = 0, new_ents_capacity = INIT_TABLE_CAPACITY;
540 entry_t **new_ents = malloc(sizeof(entry_t*) * new_ents_capacity);
541
542 for (size_t i = 0; i < table->size; i++) {
543 if (table->table[i]->sent)
544 continue;
545
546 if (new_ents_size + 1 > new_ents_capacity) {
547 new_ents_capacity *= 2;
548 new_ents = realloc(new_ents, sizeof(entry_t*) * new_ents_capacity);
549 }
550
551 new_ents[new_ents_size++] = table->table[i];
552 }
553
554 *new_ents_out = new_ents;
555 return new_ents_size;
556}
557
559static int
560attrs_equals(const entry_attrs_t *a1, const entry_attrs_t *a2)
561{
562 /* group all withdrawn together */
563 if (a1->withdrawn && a2->withdrawn)
564 return 1;
565 if (a1->withdrawn || a2->withdrawn)
566 return 0;
567
568 if (!ATTR_IS_USED_NEXTHOP(a1->use) || !ATTR_IS_USED_NEXTHOP(a2->use)) {
569 ERROR("reachable route compared without nexthop");
570 return 0;
571 }
572
573 return
574 (strcmp(a1->nexthop, a2->nexthop) == 0) &&
575 ((!ATTR_IS_USED_ADVERTPATH(a1->use) || !ATTR_IS_USED_ADVERTPATH(a2->use)) ||
576 (a1->advertpath_size == a2->advertpath_size &&
577 memcmp(a1->advertpath, a2->advertpath,
578 sizeof(uint32_t) * a1->advertpath_size))) &&
579 ((!ATTR_IS_USED_ROUTEDPATH(a1->use) || !ATTR_IS_USED_ROUTEDPATH(a2->use)) ||
580 (a1->routedpath_size == a2->routedpath_size &&
581 memcmp(a1->routedpath, a2->routedpath,
582 sizeof(uint32_t) * a1->routedpath_size))) &&
583 ((!ATTR_IS_USED_LOCALPREF(a1->use) || !ATTR_IS_USED_LOCALPREF(a2->use)) ||
584 (a1->local_pref == a2->local_pref)) &&
585 ((!ATTR_IS_USED_METRIC(a1->use) || !ATTR_IS_USED_METRIC(a2->use)) ||
586 (a1->metric == a2->metric)) &&
587 ((!ATTR_IS_USED_COMMUNITIES(a1->use) || !ATTR_IS_USED_COMMUNITIES(a2->use)) ||
588 (a1->communities_size == a2->communities_size &&
589 memcmp(a1->communities, a2->communities,
590 sizeof(uint32_t) * a1->communities_size)));
591}
592
593static entry_group_t *
594is_entry_in_group(const entry_t *e, entry_group_t *groups,
595 size_t groups_size)
596{
597 for (size_t i = 0; i < groups_size; i++)
598 if (attrs_equals(&e->attrs, &groups[i].attrs))
599 return &groups[i];
600 return NULL;
601}
602
603static void
604group_init(entry_group_t *g, const entry_attrs_t *attrs)
605{
606 g->capacity = INIT_TABLE_CAPACITY;
607 g->size = 0;
608 g->entries = malloc(sizeof(entry_t*) * g->capacity);
609 g->attrs = *attrs;
610}
611
612static void
613group_insert(entry_group_t *g, entry_t *e)
614{
615 if (g->size + 1 > g->capacity) {
616 g->capacity *= 2;
617 g->entries = realloc(g->entries,
618 sizeof(entry_t*) * g->capacity);
619 }
620
621 g->entries[g->size++] = e;
622}
623
624size_t
625group_entries_by_attrs(entry_t **entries, size_t entry_size,
626 entry_group_t **groups_out)
627{
628
629 size_t groups_size = 0, groups_capacity = entry_size;
630 entry_group_t *groups = malloc(sizeof(entry_group_t) * groups_capacity);
631
632 for (size_t i = 0; i < entry_size; i++) {
633 entry_group_t *ingroup = is_entry_in_group(entries[i], groups,
634 groups_size);
635
636 if (!ingroup) {
637 if (groups_size + 1 > groups_capacity) {
638 groups_capacity *= 2;
639 groups = realloc(groups, sizeof(entry_group_t) * groups_capacity);
640 }
641
642 ingroup = &groups[groups_size++];
643 group_init(ingroup, &entries[i]->attrs);
644 }
645
646 group_insert(ingroup, entries[i]);
647 }
648
649
650 *groups_out = groups;
651 return groups_size;
652}
653
logging utilities
#define DEBUG(format,...)
log for debugging purposes
Definition logging.h:65
#define ERROR(format,...)
log an error
Definition logging.h:56
#define INFO(format,...)
log informational event
Definition logging.h:62
const routemap_statement_t * routemap_match(const routemap_t *routemap, const char *route)
Match route against route map matchers.
Definition pib.c:367
Policy Information Base.
@ ROUTEMAP_SET_METRIC
Definition pib.h:49
@ ROUTEMAP_SET_ITADPATH_PREPEND
Definition pib.h:51
@ ROUTEMAP_SET_NEXTHOP
Definition pib.h:50
@ ROUTEMAP_SET_LOCALPREF
Definition pib.h:48
Protocol definition header.
af
Address families.
Definition protocol.h:211
app_proto
Application protocols.
Definition protocol.h:225
Groupable attributes that are related to a route.
Definition trib.h:52
char * nexthop
Definition trib.h:56
uint32_t local_pref
Definition trib.h:62
int atomicaggregate
Definition trib.h:61
uint32_t nextitad
Definition trib.h:55
community_t * communities
Definition trib.h:64
uint32_t use
Definition trib.h:53
int convertedroute
Definition trib.h:66
uint32_t * advertpath
Definition trib.h:57
int withdrawn
Definition trib.h:54
uint32_t metric
Definition trib.h:63
uint32_t * routedpath
Definition trib.h:59
Definition trib.h:111
entry_t ** entries
Definition trib.h:113
entry_attrs_t attrs
Definition trib.h:112
Route Entry.
Definition trib.h:78
int sent
Definition trib.h:99
uint16_t af
Definition trib.h:80
entry_type_t type
Definition trib.h:84
uint32_t learn_lsid
Definition trib.h:91
int32_t seq
Definition trib.h:94
uint32_t learn_itad
Definition trib.h:89
entry_attrs_t attrs
Definition trib.h:97
time_t time
Definition trib.h:95
uint16_t app_proto
Definition trib.h:81
char * prefix
Definition trib.h:82
Route map statement.
Definition pib.h:69
Route map.
Definition pib.h:79
Route Table.
Definition trib.h:103
uint32_t peer_id
Definition trib.h:104
routemap_t * routemap
Definition trib.h:107
Telephony Routing Information Base.
Definition trib.h:140
uint32_t local_itad
Definition trib.h:141
table_t ** adj_tribs_out
Definition trib.h:145
void trib_update_local(trib_t *trib)
Update local routes when ITAD is defined.
Definition trib.c:420
size_t get_new_entries(const table_t *table, entry_t ***new_ents_out)
Return array of new entry references to new.
Definition trib.c:537
size_t group_entries_by_attrs(entry_t **entries, size_t entry_size, entry_group_t **groups_out)
Group array of entry references by attributes.
Definition trib.c:625
entry_t ** trib_table_find(table_t *t, uint16_t af, const char *prefix)
Find exact route in table.
Definition trib.c:192
void trib_destroy(trib_t *trib)
Deinit TRIB structure.
Definition trib.c:180
void trib_adj_pair_add(trib_t *trib, table_t *in, table_t *out)
Add and init pair of tables owned by caller.
Definition trib.c:144
void trib_table_insert(table_t *table, entry_t *entry)
Add route to table.
Definition trib.c:224
void trib_table_deinit(table_t *t)
Deinitialize table.
Definition trib.c:113
void entry_destroy(entry_t *entry)
Destroy entry.
Definition trib.c:83
void trib_update_adj_out(trib_t *trib, table_t *adj_trib_out)
Update an Adj-TRIB-Out.
Definition trib.c:458
trib_t * trib_new(uint32_t local_itad)
Initialize TRIB structure.
Definition trib.c:121
void trib_update_full(trib_t *trib)
Execute route selection.
Definition trib.c:484
entry_t * entry_clone(const entry_t *entry)
Clone entry.
Definition trib.c:52
const entry_t * trib_table_lookup(const table_t *table, uint16_t af, uint16_t app_proto, const char *address)
Lookup address in table.
Definition trib.c:201
void trib_table_clear(table_t *table)
Destroy all entries and clear table.
Definition trib.c:296
Telephony Routing Information Base.