diff options
Diffstat (limited to 'nest/route.h')
-rw-r--r-- | nest/route.h | 334 |
1 files changed, 164 insertions, 170 deletions
diff --git a/nest/route.h b/nest/route.h index 383f4def..c1a60ccc 100644 --- a/nest/route.h +++ b/nest/route.h @@ -11,11 +11,13 @@ #include "lib/lists.h" #include "lib/resource.h" -#include "lib/timer.h" -#include "nest/protocol.h" +#include "sysdep/unix/timer.h" +#include "lib/net.h" +struct ea_list; struct protocol; struct proto; +struct rte_src; struct symbol; struct filter; struct cli; @@ -35,11 +37,8 @@ struct cli; struct fib_node { struct fib_node *next; /* Next in hash chain */ struct fib_iterator *readers; /* List of readers of this node */ - byte pxlen; - byte flags; /* User-defined */ - byte x0, x1; /* User-defined */ - u32 uid; /* Unique ID based on hash */ - ip_addr prefix; /* In host order */ + byte flags; /* User-defined, will be removed */ + net_addr addr[0]; }; struct fib_iterator { /* See lib/slists.h for an explanation */ @@ -50,7 +49,7 @@ struct fib_iterator { /* See lib/slists.h for an explanation */ uint hash; }; -typedef void (*fib_init_func)(struct fib_node *); +typedef void (*fib_init_fn)(void *); struct fib { pool *fib_pool; /* Pool holding all our data */ @@ -58,16 +57,26 @@ struct fib { struct fib_node **hash_table; /* Node hash table */ uint hash_size; /* Number of hash table entries (a power of two) */ uint hash_order; /* Binary logarithm of hash_size */ - uint hash_shift; /* 16 - hash_log */ + uint hash_shift; /* 32 - hash_order */ + uint addr_type; /* Type of address data stored in fib (NET_*) */ + uint node_size; /* FIB node size, 0 for nonuniform */ + uint node_offset; /* Offset of fib_node struct inside of user data */ uint entries; /* Number of entries */ uint entries_min, entries_max; /* Entry count limits (else start rehashing) */ - fib_init_func init; /* Constructor */ + fib_init_fn init; /* Constructor */ }; -void fib_init(struct fib *, pool *, unsigned node_size, unsigned hash_order, fib_init_func init); -void *fib_find(struct fib *, ip_addr *, int); /* Find or return NULL if doesn't exist */ -void *fib_get(struct fib *, ip_addr *, int); /* Find or create new if nonexistent */ -void *fib_route(struct fib *, ip_addr, int); /* Longest-match routing lookup */ +static inline void * fib_node_to_user(struct fib *f, struct fib_node *e) +{ return e ? (void *) ((char *) e - f->node_offset) : NULL; } + +static inline struct fib_node * fib_user_to_node(struct fib *f, void *e) +{ return e ? (void *) ((char *) e + f->node_offset) : NULL; } + +void fib_init(struct fib *f, pool *p, uint addr_type, uint node_size, uint node_offset, uint hash_order, fib_init_fn init); +void *fib_find(struct fib *, const net_addr *); /* Find or return NULL if doesn't exist */ +void *fib_get_chain(struct fib *f, const net_addr *a); /* Find first node in linked list from hash table */ +void *fib_get(struct fib *, const net_addr *); /* Find or create new if nonexistent */ +void *fib_route(struct fib *, const net_addr *); /* Longest-match routing lookup */ void fib_delete(struct fib *, void *); /* Remove fib entry */ void fib_free(struct fib *); /* Destroy the fib */ void fib_check(struct fib *); /* Consistency check for debugging */ @@ -78,34 +87,37 @@ void fit_put(struct fib_iterator *, struct fib_node *); void fit_put_next(struct fib *f, struct fib_iterator *i, struct fib_node *n, uint hpos); -#define FIB_WALK(fib, z) do { \ - struct fib_node *z, **ff = (fib)->hash_table; \ - uint count = (fib)->hash_size; \ - while (count--) \ - for(z = *ff++; z; z=z->next) +#define FIB_WALK(fib, type, z) do { \ + struct fib_node *fn_, **ff_ = (fib)->hash_table; \ + uint count_ = (fib)->hash_size; \ + type *z; \ + while (count_--) \ + for (fn_ = *ff_++; z = fib_node_to_user(fib, fn_); fn_=fn_->next) #define FIB_WALK_END } while (0) #define FIB_ITERATE_INIT(it, fib) fit_init(it, fib) -#define FIB_ITERATE_START(fib, it, z) do { \ - struct fib_node *z = fit_get(fib, it); \ - uint count = (fib)->hash_size; \ - uint hpos = (it)->hash; \ +#define FIB_ITERATE_START(fib, it, type, z) do { \ + struct fib_node *fn_ = fit_get(fib, it); \ + uint count_ = (fib)->hash_size; \ + uint hpos_ = (it)->hash; \ + type *z; \ for(;;) { \ - if (!z) \ + if (!fn_) \ { \ - if (++hpos >= count) \ + if (++hpos_ >= count_) \ break; \ - z = (fib)->hash_table[hpos]; \ + fn_ = (fib)->hash_table[hpos_]; \ continue; \ - } + } \ + z = fib_node_to_user(fib, fn_); -#define FIB_ITERATE_END(z) z = z->next; } } while(0) +#define FIB_ITERATE_END fn_ = fn_->next; } } while(0) -#define FIB_ITERATE_PUT(it, z) fit_put(it, z) +#define FIB_ITERATE_PUT(it) fit_put(it, fn_) -#define FIB_ITERATE_PUT_NEXT(it, fib, z) fit_put_next(fib, it, z, hpos) +#define FIB_ITERATE_PUT_NEXT(it, fib) fit_put_next(fib, it, fn_, hpos_) #define FIB_ITERATE_UNLINK(it, fib) fit_get(fib, it) @@ -126,6 +138,7 @@ struct rtable_config { char *name; struct rtable *table; struct proto_config *krt_attached; /* Kernel syncer attached to this table */ + uint addr_type; /* Type of address data stored in table (NET_*) */ int gc_max_ops; /* Maximum number of operations before GC is run */ int gc_min_time; /* Minimum time between two consecutive GC runs */ byte sorted; /* Routes of network are sorted according to rte_better() */ @@ -135,7 +148,8 @@ typedef struct rtable { node n; /* Node in list of all tables */ struct fib fib; char *name; /* Name of this table */ - list hooks; /* List of announcement hooks */ + list channels; /* List of attached channels (struct channel) */ + uint addr_type; /* Type of address data stored in table (NET_*) */ int pipe_busy; /* Pipe loop detection */ int use_count; /* Number of protocols using this table */ struct hostcache *hostcache; @@ -147,7 +161,6 @@ typedef struct rtable { struct event *rt_event; /* Routing table event */ int gc_counter; /* Number of operations since last GC */ bird_clock_t gc_time; /* Time of last GC */ - byte gc_scheduled; /* GC is scheduled */ byte prune_state; /* Table prune state, 1 -> scheduled, 2-> running */ byte hcu_scheduled; /* Hostcache update is scheduled */ byte nhu_state; /* Next Hop Update state */ @@ -155,13 +168,14 @@ typedef struct rtable { struct fib_iterator nhu_fit; /* Next Hop Update FIB iterator */ } rtable; -#define RPS_NONE 0 -#define RPS_SCHEDULED 1 -#define RPS_RUNNING 2 +#define NHU_CLEAN 0 +#define NHU_SCHEDULED 1 +#define NHU_RUNNING 2 +#define NHU_DIRTY 3 typedef struct network { - struct fib_node n; /* FIB flags reserved for kernel syncer */ struct rte *routes; /* Available routes for this network */ + struct fib_node n; /* FIB flags reserved for kernel syncer */ } net; struct hostcache { @@ -186,15 +200,15 @@ struct hostentry { unsigned hash_key; /* Hash key */ unsigned uc; /* Use count */ struct rta *src; /* Source rta entry */ - ip_addr gw; /* Chosen next hop */ byte dest; /* Chosen route destination type (RTD_...) */ + byte nexthop_linkable; /* Nexthop list is completely non-device */ u32 igp_metric; /* Chosen route IGP metric */ }; typedef struct rte { struct rte *next; net *net; /* Network this RTE belongs to */ - struct announce_hook *sender; /* Announce hook used to send the route to the routing table */ + struct channel *sender; /* Channel used to send the route to the routing table */ struct rta *attrs; /* Attributes of this route */ byte flags; /* Flags (REF_...) */ byte pflags; /* Protocol-specific flags */ @@ -249,6 +263,7 @@ static inline int rte_is_filtered(rte *r) { return !!(r->flags & REF_FILTERED); /* Types of route announcement, also used as flags */ +#define RA_UNDEF 0 /* Undefined RA type */ #define RA_OPTIMAL 1 /* Announcement of optimal route change */ #define RA_ACCEPTED 2 /* Announcement of first accepted route */ #define RA_ANY 3 /* Announcement of any route change */ @@ -268,16 +283,21 @@ void rt_commit(struct config *new, struct config *old); void rt_lock_table(rtable *); void rt_unlock_table(rtable *); void rt_setup(pool *, rtable *, char *, struct rtable_config *); -static inline net *net_find(rtable *tab, ip_addr addr, unsigned len) { return (net *) fib_find(&tab->fib, &addr, len); } -static inline net *net_get(rtable *tab, ip_addr addr, unsigned len) { return (net *) fib_get(&tab->fib, &addr, len); } +static inline net *net_find(rtable *tab, const net_addr *addr) { return (net *) fib_find(&tab->fib, addr); } +static inline net *net_find_valid(rtable *tab, const net_addr *addr) +{ net *n = net_find(tab, addr); return (n && rte_is_valid(n->routes)) ? n : NULL; } +static inline net *net_get(rtable *tab, const net_addr *addr) { return (net *) fib_get(&tab->fib, addr); } +void *net_route(rtable *tab, const net_addr *n); +int net_roa_check(rtable *tab, const net_addr *n, u32 asn); rte *rte_find(net *net, struct rte_src *src); rte *rte_get_temp(struct rta *); -void rte_update2(struct announce_hook *ah, net *net, rte *new, struct rte_src *src); -static inline void rte_update(struct proto *p, net *net, rte *new) { rte_update2(p->main_ahook, net, new, p->main_source); } -int rt_examine(rtable *t, ip_addr prefix, int pxlen, struct proto *p, struct filter *filter); -rte *rt_export_merged(struct announce_hook *ah, net *net, rte **rt_free, struct ea_list **tmpa, linpool *pool, int silent); -void rt_refresh_begin(rtable *t, struct announce_hook *ah); -void rt_refresh_end(rtable *t, struct announce_hook *ah); +void rte_update2(struct channel *c, const net_addr *n, rte *new, struct rte_src *src); +/* rte_update() moved to protocol.h to avoid dependency conflicts */ +int rt_examine(rtable *t, net_addr *a, struct proto *p, struct filter *filter); +rte *rt_export_merged(struct channel *c, net *net, rte **rt_free, struct ea_list **tmpa, linpool *pool, int silent); +void rt_refresh_begin(rtable *t, struct channel *c); +void rt_refresh_end(rtable *t, struct channel *c); +void rt_schedule_prune(rtable *t); void rte_dump(rte *); void rte_free(rte *); rte *rte_do_cow(rte *); @@ -285,35 +305,47 @@ static inline rte * rte_cow(rte *r) { return (r->flags & REF_COW) ? rte_do_cow(r rte *rte_cow_rta(rte *r, linpool *lp); void rt_dump(rtable *); void rt_dump_all(void); -int rt_feed_baby(struct proto *p); -void rt_feed_baby_abort(struct proto *p); -int rt_prune_loop(void); -struct rtable_config *rt_new_table(struct symbol *s); +int rt_feed_channel(struct channel *c); +void rt_feed_channel_abort(struct channel *c); +struct rtable_config *rt_new_table(struct symbol *s, uint addr_type); -static inline void -rt_mark_for_prune(rtable *tab) -{ - if (tab->prune_state == RPS_RUNNING) - fit_get(&tab->fib, &tab->prune_fit); - tab->prune_state = RPS_SCHEDULED; -} +struct rt_show_data_rtable { + node n; + rtable *table; + struct channel *export_channel; +}; struct rt_show_data { - ip_addr prefix; - unsigned pxlen; - rtable *table; + net_addr *addr; + list tables; + struct rt_show_data_rtable *tab; /* Iterator over table list */ + struct rt_show_data_rtable *last_table; /* Last table in output */ + struct fib_iterator fit; /* Iterator over networks in table */ + int verbose, tables_defined_by; struct filter *filter; - int verbose; - struct fib_iterator fit; struct proto *show_protocol; struct proto *export_protocol; - int export_mode, primary_only, filtered; + struct channel *export_channel; struct config *running_on_config; - int net_counter, rt_counter, show_counter; - int stats, show_for; + int export_mode, primary_only, filtered, stats, show_for; + + int table_open; /* Iteration (fit) is open */ + int net_counter, rt_counter, show_counter, table_counter; + int net_counter_last, rt_counter_last, show_counter_last; }; + void rt_show(struct rt_show_data *); +struct rt_show_data_rtable * rt_show_add_table(struct rt_show_data *d, rtable *t); + +/* Value of table definition mode in struct rt_show_data */ +#define RSD_TDB_DEFAULT 0 /* no table specified */ +#define RSD_TDB_INDIRECT 0 /* show route ... protocol P ... */ +#define RSD_TDB_ALL RSD_TDB_SET /* show route ... table all ... */ +#define RSD_TDB_DIRECT RSD_TDB_SET | RSD_TDB_NMN /* show route ... table X table Y ... */ + +#define RSD_TDB_SET 0x1 /* internal: show empty tables */ +#define RSD_TDB_NMN 0x2 /* internal: need matching net */ /* Value of export_mode in struct rt_show_data */ #define RSEM_NONE 0 /* Export mode not used */ @@ -329,14 +361,21 @@ void rt_show(struct rt_show_data *); * construction of BGP route attribute lists. */ -/* Multipath next-hop */ -struct mpnh { +/* Nexthop structure */ +struct nexthop { ip_addr gw; /* Next hop */ struct iface *iface; /* Outgoing interface */ - struct mpnh *next; + struct nexthop *next; + byte flags; byte weight; + byte labels_orig; /* Number of labels before hostentry was applied */ + byte labels; /* Number of all labels */ + u32 label[0]; }; +#define RNF_ONLINK 0x1 /* Gateway is onlink regardless of IP ranges */ + + struct rte_src { struct rte_src *next; /* Hash chain */ struct proto *proto; /* Protocol the source is based on */ @@ -348,22 +387,18 @@ struct rte_src { typedef struct rta { struct rta *next, **pprev; /* Hash chain */ + u32 uc; /* Use count */ + u32 hash_key; /* Hash over important fields */ + struct ea_list *eattrs; /* Extended Attribute chain */ struct rte_src *src; /* Route source that created the route */ - unsigned uc; /* Use count */ - byte source; /* Route source (RTS_...) */ - byte scope; /* Route scope (SCOPE_... -- see ip.h) */ - byte cast; /* Casting type (RTC_...) */ - byte dest; /* Route destination type (RTD_...) */ - byte flags; /* Route flags (RTF_...), now unused */ - byte aflags; /* Attribute cache flags (RTAF_...) */ - u16 hash_key; /* Hash over important fields */ - u32 igp_metric; /* IGP metric to next hop (for iBGP routes) */ - ip_addr gw; /* Next hop */ - ip_addr from; /* Advertising router */ struct hostentry *hostentry; /* Hostentry for recursive next-hops */ - struct iface *iface; /* Outgoing interface */ - struct mpnh *nexthops; /* Next-hops for multipath routes */ - struct ea_list *eattrs; /* Extended Attribute chain */ + ip_addr from; /* Advertising router */ + u32 igp_metric; /* IGP metric to next hop (for iBGP routes) */ + u8 source; /* Route source (RTS_...) */ + u8 scope; /* Route scope (SCOPE_... -- see ip.h) */ + u8 dest; /* Route destination type (RTD_...) */ + u8 aflags; + struct nexthop nh; /* Next hop */ } rta; #define RTS_DUMMY 0 /* Dummy route to be removed soon */ @@ -380,19 +415,20 @@ typedef struct rta { #define RTS_BGP 11 /* BGP route */ #define RTS_PIPE 12 /* Inter-table wormhole */ #define RTS_BABEL 13 /* Babel route */ +#define RTS_RPKI 14 /* Route Origin Authorization */ + #define RTC_UNICAST 0 #define RTC_BROADCAST 1 #define RTC_MULTICAST 2 #define RTC_ANYCAST 3 /* IPv6 Anycast */ -#define RTD_ROUTER 0 /* Next hop is neighbor router */ -#define RTD_DEVICE 1 /* Points to device */ +#define RTD_NONE 0 /* Undefined next hop */ +#define RTD_UNICAST 1 /* Next hop is neighbor router */ #define RTD_BLACKHOLE 2 /* Silently drop packets */ #define RTD_UNREACHABLE 3 /* Reject as unreachable */ #define RTD_PROHIBIT 4 /* Administratively prohibited */ -#define RTD_MULTIPATH 5 /* Multipath route (nexthops != NULL) */ -#define RTD_NONE 6 /* Invalid RTD */ +#define RTD_MAX 5 /* Flags for net->n.flags, used by kernel syncer */ #define KRF_INSTALLED 0x80 /* This route should be installed in the kernel */ @@ -404,9 +440,14 @@ typedef struct rta { protocol-specific metric is availabe */ +const char * rta_dest_names[RTD_MAX]; + +static inline const char *rta_dest_name(uint n) +{ return (n < RTD_MAX) ? rta_dest_names[n] : "???"; } + /* Route has regular, reachable nexthop (i.e. not RTD_UNREACHABLE and like) */ static inline int rte_is_reachable(rte *r) -{ uint d = r->attrs->dest; return (d == RTD_ROUTER) || (d == RTD_DEVICE) || (d == RTD_MULTIPATH); } +{ return r->attrs->dest == RTD_UNICAST; } /* @@ -454,13 +495,22 @@ typedef struct eattr { #define EAF_TYPE_UNDEF 0x1f /* `force undefined' entry */ #define EAF_EMBEDDED 0x01 /* Data stored in eattr.u.data (part of type spec) */ #define EAF_VAR_LENGTH 0x02 /* Attribute length is variable (part of type spec) */ -#define EAF_ORIGINATED 0x40 /* The attribute has originated locally */ +#define EAF_ORIGINATED 0x20 /* The attribute has originated locally */ +#define EAF_FRESH 0x40 /* An uncached attribute (e.g. modified in export filter) */ #define EAF_TEMP 0x80 /* A temporary attribute (the one stored in the tmp attr list) */ -struct adata { +typedef struct adata { uint length; /* Length of data */ byte data[0]; -}; +} adata; + +static inline struct adata * +lp_alloc_adata(struct linpool *pool, uint len) +{ + struct adata *ad = lp_alloc(pool, sizeof(struct adata) + len); + ad->length = len; + return ad; +} static inline int adata_same(struct adata *a, struct adata *b) { return (a->length == b->length && !memcmp(a->data, b->data, a->length)); } @@ -502,14 +552,22 @@ uint ea_hash(ea_list *e); /* Calculate 16-bit hash value */ ea_list *ea_append(ea_list *to, ea_list *what); void ea_format_bitfield(struct eattr *a, byte *buf, int bufsize, const char **names, int min, int max); -int mpnh__same(struct mpnh *x, struct mpnh *y); /* Compare multipath nexthops */ -static inline int mpnh_same(struct mpnh *x, struct mpnh *y) -{ return (x == y) || mpnh__same(x, y); } -struct mpnh *mpnh_merge(struct mpnh *x, struct mpnh *y, int rx, int ry, int max, linpool *lp); -void mpnh_insert(struct mpnh **n, struct mpnh *y); -int mpnh_is_sorted(struct mpnh *x); +#define NEXTHOP_MAX_SIZE (sizeof(struct nexthop) + sizeof(u32)*MPLS_MAX_LABEL_STACK) + +static inline size_t nexthop_size(const struct nexthop *nh) +{ return sizeof(struct nexthop) + sizeof(u32)*nh->labels; } +int nexthop__same(struct nexthop *x, struct nexthop *y); /* Compare multipath nexthops */ +static inline int nexthop_same(struct nexthop *x, struct nexthop *y) +{ return (x == y) || nexthop__same(x, y); } +struct nexthop *nexthop_merge(struct nexthop *x, struct nexthop *y, int rx, int ry, int max, linpool *lp); +static inline void nexthop_link(struct rta *a, struct nexthop *from) +{ memcpy(&a->nh, from, nexthop_size(from)); } +void nexthop_insert(struct nexthop **n, struct nexthop *y); +int nexthop_is_sorted(struct nexthop *x); void rta_init(void); +static inline size_t rta_size(const rta *a) { return sizeof(rta) + sizeof(u32)*a->nh.labels; } +#define RTA_MAX_SIZE (sizeof(rta) + sizeof(u32)*MPLS_MAX_LABEL_STACK) rta *rta_lookup(rta *); /* Get rta equivalent to this one, uc++ */ static inline int rta_is_cached(rta *r) { return r->aflags & RTAF_CACHED; } static inline rta *rta_clone(rta *r) { r->uc++; return r; } @@ -520,7 +578,15 @@ static inline rta * rta_cow(rta *r, linpool *lp) { return rta_is_cached(r) ? rta void rta_dump(rta *); void rta_dump_all(void); void rta_show(struct cli *, rta *, ea_list *); -void rta_set_recursive_next_hop(rtable *dep, rta *a, rtable *tab, ip_addr *gw, ip_addr *ll); + +struct hostentry * rt_get_hostentry(rtable *tab, ip_addr a, ip_addr ll, rtable *dep); +void rta_apply_hostentry(rta *a, struct hostentry *he, mpls_label_stack *mls); + +static inline void +rta_set_recursive_next_hop(rtable *dep, rta *a, rtable *tab, ip_addr gw, ip_addr ll, mpls_label_stack *mls) +{ + rta_apply_hostentry(a, rt_get_hostentry(tab, gw, ll, dep), mls); +} /* * rta_set_recursive_next_hop() acquires hostentry from hostcache and fills @@ -560,87 +626,15 @@ extern struct protocol *attr_class_to_protocol[EAP_MAX]; #define DEF_PREF_BABEL 130 /* Babel */ #define DEF_PREF_RIP 120 /* RIP */ #define DEF_PREF_BGP 100 /* BGP */ -#define DEF_PREF_PIPE 70 /* Routes piped from other tables */ +#define DEF_PREF_RPKI 100 /* RPKI */ #define DEF_PREF_INHERITED 10 /* Routes inherited from other routing daemons */ - /* * Route Origin Authorization */ -struct roa_item { - u32 asn; - byte maxlen; - byte src; - struct roa_item *next; -}; - -struct roa_node { - struct fib_node n; - struct roa_item *items; - // u32 cached_asn; -}; - -struct roa_table { - node n; /* Node in roa_table_list */ - struct fib fib; - char *name; /* Name of this ROA table */ - struct roa_table_config *cf; /* Configuration of this ROA table */ -}; - -struct roa_item_config { - ip_addr prefix; - byte pxlen, maxlen; - u32 asn; - struct roa_item_config *next; -}; - -struct roa_table_config { - node n; /* Node in config->rpa_tables */ - char *name; /* Name of this ROA table */ - struct roa_table *table; - - struct roa_item_config *roa_items; /* Preconfigured ROA items */ - - // char *filename; - // int gc_max_ops; /* Maximum number of operations before GC is run */ - // int gc_min_time; /* Minimum time between two consecutive GC runs */ -}; - -struct roa_show_data { - struct fib_iterator fit; - struct roa_table *table; - ip_addr prefix; - byte pxlen; - byte mode; /* ROA_SHOW_* values */ - u32 asn; /* Filter ASN, 0 -> all */ -}; - #define ROA_UNKNOWN 0 #define ROA_VALID 1 #define ROA_INVALID 2 -#define ROA_SRC_ANY 0 -#define ROA_SRC_CONFIG 1 -#define ROA_SRC_DYNAMIC 2 - -#define ROA_SHOW_ALL 0 -#define ROA_SHOW_PX 1 -#define ROA_SHOW_IN 2 -#define ROA_SHOW_FOR 3 - -extern struct roa_table *roa_table_default; - -void roa_add_item(struct roa_table *t, ip_addr prefix, byte pxlen, byte maxlen, u32 asn, byte src); -void roa_delete_item(struct roa_table *t, ip_addr prefix, byte pxlen, byte maxlen, u32 asn, byte src); -void roa_flush(struct roa_table *t, byte src); -byte roa_check(struct roa_table *t, ip_addr prefix, byte pxlen, u32 asn); -struct roa_table_config * roa_new_table_config(struct symbol *s); -void roa_add_item_config(struct roa_table_config *rtc, ip_addr prefix, byte pxlen, byte maxlen, u32 asn); -void roa_init(void); -void roa_preconfig(struct config *c); -void roa_commit(struct config *new, struct config *old); -void roa_show(struct roa_show_data *d); - - #endif |