Channels - explicit links between protocols and tables

The patch adds support for channels, structures connecting protocols and
tables and handling most interactions between them. The documentation is
missing yet.
This commit is contained in:
Ondrej Zajicek (work) 2016-01-26 11:48:58 +01:00 committed by Jan Moskyto Matejka
parent 9f5782d969
commit f4a60a9bc4
37 changed files with 2050 additions and 1778 deletions

View file

@ -136,12 +136,14 @@ config_parse(struct config *c)
protos_preconfig(c); protos_preconfig(c);
rt_preconfig(c); rt_preconfig(c);
cf_parse(); cf_parse();
protos_postconfig(c);
if (EMPTY_LIST(c->protos)) if (EMPTY_LIST(c->protos))
cf_error("No protocol is specified in the config file"); cf_error("No protocol is specified in the config file");
/* XXXX */
/*
if (!c->router_id) if (!c->router_id)
cf_error("Router ID must be configured manually"); cf_error("Router ID must be configured manually");
*/
done = 1; done = 1;

View file

@ -24,7 +24,7 @@ struct config {
int mrtdump_file; /* Configured MRTDump file (sysdep, fd in unix) */ int mrtdump_file; /* Configured MRTDump file (sysdep, fd in unix) */
char *syslog_name; /* Name used for syslog (NULL -> no syslog) */ char *syslog_name; /* Name used for syslog (NULL -> no syslog) */
struct rtable_config *master_rtc; /* Configuration of master routing table */ struct rtable_config *def_tables[NET_MAX]; /* Default routing tables for each network */
struct iface_patt *router_id_from; /* Configured list of router ID iface patterns */ struct iface_patt *router_id_from; /* Configured list of router ID iface patterns */
u32 router_id; /* Our Router ID */ u32 router_id; /* Our Router ID */

View file

@ -46,6 +46,7 @@ CF_DECLS
struct symbol *s; struct symbol *s;
char *t; char *t;
struct rtable_config *r; struct rtable_config *r;
struct channel_config *cc;
struct f_inst *x; struct f_inst *x;
struct filter *f; struct filter *f;
struct f_tree *e; struct f_tree *e;
@ -61,6 +62,7 @@ CF_DECLS
bird_clock_t time; bird_clock_t time;
struct f_prefix px; struct f_prefix px;
struct proto_spec ps; struct proto_spec ps;
struct channel_limit cl;
struct timeformat *tf; struct timeformat *tf;
} }

View file

@ -34,6 +34,7 @@
#define ABS(a) ((a)>=0 ? (a) : -(a)) #define ABS(a) ((a)>=0 ? (a) : -(a))
#define DELTA(a,b) (((a)>=(b))?(a)-(b):(b)-(a)) #define DELTA(a,b) (((a)>=(b))?(a)-(b):(b)-(a))
#define ARRAY_SIZE(a) (sizeof(a)/sizeof(*(a))) #define ARRAY_SIZE(a) (sizeof(a)/sizeof(*(a)))
#define CALL(fn, args...) ({ if (fn) fn(args); })
static inline int uint_cmp(uint i1, uint i2) static inline int uint_cmp(uint i1, uint i2)
{ return (int)(i1 > i2) - (int)(i1 < i2); } { return (int)(i1 > i2) - (int)(i1 < i2); }

View file

@ -39,7 +39,10 @@ typedef struct list { /* In fact two overlayed nodes */
#define WALK_LIST2(n,nn,list,pos) \ #define WALK_LIST2(n,nn,list,pos) \
for(nn=(list).head; NODE_VALID(nn) && (n=SKIP_BACK(typeof(*n),pos,nn)); nn=nn->next) for(nn=(list).head; NODE_VALID(nn) && (n=SKIP_BACK(typeof(*n),pos,nn)); nn=nn->next)
#define WALK_LIST_DELSAFE(n,nxt,list) \ #define WALK_LIST_DELSAFE(n,nxt,list) \
for(n=HEAD(list); nxt=NODE_NEXT(n); n=(void *) nxt) for(n=HEAD(list); nxt=NODE_NEXT(n); n=(void *) nxt)
#define WALK_LIST2_DELSAFE(n,nn,nxt,list,pos) \
for(nn=HEAD(list); (nxt=nn->next) && (n=SKIP_BACK(typeof(*n),pos,nn)); nn=nxt)
/* WALK_LIST_FIRST supposes that called code removes each processed node */ /* WALK_LIST_FIRST supposes that called code removes each processed node */
#define WALK_LIST_FIRST(n,list) \ #define WALK_LIST_FIRST(n,list) \
while(n=HEAD(list), (NODE (n))->next) while(n=HEAD(list), (NODE (n))->next)

View file

@ -4,6 +4,13 @@
#include "lib/net.h" #include "lib/net.h"
const char * const net_label[] = {
[NET_IP4] = "ipv4",
[NET_IP6] = "ipv6",
[NET_VPN4] = "vpn4",
[NET_VPN6] = "vpn6"
};
const u16 net_addr_length[] = { const u16 net_addr_length[] = {
[NET_IP4] = sizeof(net_addr_ip4), [NET_IP4] = sizeof(net_addr_ip4),
[NET_IP6] = sizeof(net_addr_ip6), [NET_IP6] = sizeof(net_addr_ip6),

View file

@ -21,6 +21,15 @@
#define NET_ROA6 6 #define NET_ROA6 6
#define NET_MAX 7 #define NET_MAX 7
#define NB_IP4 (1 << NET_IP4)
#define NB_IP6 (1 << NET_IP6)
#define NB_VPN4 (1 << NET_VPN4)
#define NB_VPN6 (1 << NET_VPN6)
#define NB_IP (NB_IP4 | NB_IP6)
#define NB_ANY 0xffffffff
typedef struct net_addr { typedef struct net_addr {
u8 type; u8 type;
u8 pxlen; u8 pxlen;
@ -88,6 +97,7 @@ typedef union net_addr_union {
} net_addr_union; } net_addr_union;
extern const char * const net_label[];
extern const u16 net_addr_length[]; extern const u16 net_addr_length[];
extern const u8 net_max_prefix_length[]; extern const u8 net_max_prefix_length[];
extern const u16 net_max_text_length[]; extern const u16 net_max_text_length[];
@ -149,6 +159,13 @@ static inline void net_fill_ip_host(net_addr *a, ip_addr prefix)
net_fill_ip6(a, ipa_to_ip6(prefix), IP6_MAX_PREFIX_LENGTH); net_fill_ip6(a, ipa_to_ip6(prefix), IP6_MAX_PREFIX_LENGTH);
} }
static inline int net_val_match(u8 type, u32 mask)
{ return !!((1 << type) & mask); }
static inline int net_type_match(const net_addr *a, u32 mask)
{ return net_val_match(a->type, mask); }
static inline int net_is_ip(const net_addr *a) static inline int net_is_ip(const net_addr *a)
{ return (a->type == NET_IP4) || (a->type == NET_IP6); } { return (a->type == NET_IP4) || (a->type == NET_IP6); }

View file

@ -17,6 +17,7 @@ CF_HDR
CF_DEFINES CF_DEFINES
static struct proto_config *this_proto; static struct proto_config *this_proto;
static struct channel_config *this_channel;
static struct iface_patt *this_ipatt; static struct iface_patt *this_ipatt;
static struct iface_patt_node *this_ipn; static struct iface_patt_node *this_ipn;
/* static struct roa_table_config *this_roa_table; */ /* static struct roa_table_config *this_roa_table; */
@ -49,6 +50,15 @@ get_passwords(void)
return rv; return rv;
} }
static void
proto_postconfig(void)
{
CALL(this_proto->protocol->postconfig, this_proto);
this_channel = NULL;
this_proto = NULL;
}
#define DIRECT_CFG ((struct rt_dev_config *) this_proto) #define DIRECT_CFG ((struct rt_dev_config *) this_proto)
CF_DECLS CF_DECLS
@ -76,9 +86,10 @@ CF_ENUM(T_ENUM_ROA, ROA_, UNKNOWN, VALID, INVALID)
%type <s> optsym %type <s> optsym
%type <ra> r_args %type <ra> r_args
%type <sd> sym_args %type <sd> sym_args
%type <i> proto_start echo_mask echo_size debug_mask debug_list debug_flag mrtdump_mask mrtdump_list mrtdump_flag export_mode limit_action table_type table_sorted tos %type <i> proto_start echo_mask echo_size debug_mask debug_list debug_flag mrtdump_mask mrtdump_list mrtdump_flag export_mode limit_action net_type table_sorted tos
%type <ps> proto_patt proto_patt2 %type <ps> proto_patt proto_patt2
%type <g> limit_spec %type <cc> channel_start proto_channel
%type <cl> limit_spec
CF_GRAMMAR CF_GRAMMAR
@ -115,7 +126,7 @@ listen_opts:
| listen_opts listen_opt | listen_opts listen_opt
; ;
listen_opt: listen_opt:
ADDRESS ipa { new_config->listen_bgp_addr = $2; } ADDRESS ipa { new_config->listen_bgp_addr = $2; }
| PORT expr { new_config->listen_bgp_port = $2; } | PORT expr { new_config->listen_bgp_port = $2; }
| V6ONLY { new_config->listen_bgp_flags = 0; } | V6ONLY { new_config->listen_bgp_flags = 0; }
@ -128,13 +139,10 @@ CF_ADDTO(conf, gr_opts)
gr_opts: GRACEFUL RESTART WAIT expr ';' { new_config->gr_wait = $4; } ; gr_opts: GRACEFUL RESTART WAIT expr ';' { new_config->gr_wait = $4; } ;
/* Creation of routing tables */ /* Network types (for tables, channels) */
CF_ADDTO(conf, table) net_type:
IPV4 { $$ = NET_IP4; }
table_type:
/* empty */ { $$ = NET_IP4; }
| IPV4 { $$ = NET_IP4; }
| IPV6 { $$ = NET_IP6; } | IPV6 { $$ = NET_IP6; }
| VPN4 { $$ = NET_VPN4; } | VPN4 { $$ = NET_VPN4; }
| VPN6 { $$ = NET_VPN6; } | VPN6 { $$ = NET_VPN6; }
@ -142,21 +150,27 @@ table_type:
| ROA6 { $$ = NET_ROA6; } | ROA6 { $$ = NET_ROA6; }
; ;
/* Creation of routing tables */
CF_ADDTO(conf, table)
table_sorted: table_sorted:
{ $$ = 0; } { $$ = 0; }
| SORTED { $$ = 1; } | SORTED { $$ = 1; }
; ;
table: table_type TABLE SYM table_sorted { table: net_type TABLE SYM table_sorted {
struct rtable_config *cf; struct rtable_config *cf;
cf = rt_new_table($3, $1); cf = rt_new_table($3, $1);
cf->sorted = $4; cf->sorted = $4;
} }
; ;
/* Definition of protocols */ /* Definition of protocols */
CF_ADDTO(conf, proto) CF_ADDTO(conf, proto { proto_postconfig(); })
proto_start: proto_start:
PROTOCOL { $$ = SYM_PROTO; } PROTOCOL { $$ = SYM_PROTO; }
@ -194,24 +208,62 @@ proto_name:
proto_item: proto_item:
/* EMPTY */ /* EMPTY */
| PREFERENCE expr {
if ($2 < 0 || $2 > 0xFFFF) cf_error("Invalid preference");
this_proto->preference = $2;
}
| DISABLED bool { this_proto->disabled = $2; } | DISABLED bool { this_proto->disabled = $2; }
| DEBUG debug_mask { this_proto->debug = $2; } | DEBUG debug_mask { this_proto->debug = $2; }
| MRTDUMP mrtdump_mask { this_proto->mrtdump = $2; } | MRTDUMP mrtdump_mask { this_proto->mrtdump = $2; }
| IMPORT imexport { this_proto->in_filter = $2; }
| EXPORT imexport { this_proto->out_filter = $2; }
| RECEIVE LIMIT limit_spec { this_proto->rx_limit = $3; }
| IMPORT LIMIT limit_spec { this_proto->in_limit = $3; }
| EXPORT LIMIT limit_spec { this_proto->out_limit = $3; }
| IMPORT KEEP FILTERED bool { this_proto->in_keep_filtered = $4; }
| TABLE rtable { this_proto->table = $2; }
| ROUTER ID idval { this_proto->router_id = $3; } | ROUTER ID idval { this_proto->router_id = $3; }
| DESCRIPTION text { this_proto->dsc = $2; } | DESCRIPTION text { this_proto->dsc = $2; }
; ;
channel_start: net_type
{
$$ = this_channel = channel_config_new(NULL, $1, this_proto);
};
channel_item:
TABLE rtable {
if (this_channel->net_type && ($2->addr_type != this_channel->net_type))
cf_error("Incompatible table type");
this_channel->table = $2;
}
| IMPORT imexport { this_channel->in_filter = $2; }
| EXPORT imexport { this_channel->out_filter = $2; }
| RECEIVE LIMIT limit_spec { this_channel->rx_limit = $3; }
| IMPORT LIMIT limit_spec { this_channel->in_limit = $3; }
| EXPORT LIMIT limit_spec { this_channel->out_limit = $3; }
| PREFERENCE expr { this_channel->preference = $2; check_u16($2); }
| IMPORT KEEP FILTERED bool { this_channel->in_keep_filtered = $4; }
;
channel_opts:
/* empty */
| channel_opts channel_item ';'
;
channel_opt_list:
/* empty */
| '{' channel_opts '}'
;
channel_end:
{
if (!this_channel->table)
cf_error("Routing table not specified");
this_channel = NULL;
};
proto_channel: channel_start channel_opt_list channel_end;
rtable:
SYM {
if ($1->class != SYM_TABLE) cf_error("Table expected");
$$ = $1->def;
}
;
imexport: imexport:
FILTER filter { $$ = $2; } FILTER filter { $$ = $2; }
| where_filter | where_filter
@ -228,20 +280,8 @@ limit_action:
; ;
limit_spec: limit_spec:
expr limit_action { expr limit_action { $$ = (struct channel_limit){ .limit = $1, $$.action = $2 }; }
struct proto_limit *l = cfg_allocz(sizeof(struct proto_limit)); | OFF { $$ = (struct channel_limit){}; }
l->limit = $1;
l->action = $2;
$$ = l;
}
| OFF { $$ = NULL; }
;
rtable:
SYM {
if ($1->class != SYM_TABLE) cf_error("Table name expected");
$$ = $1->def;
}
; ;
CF_ADDTO(conf, debug_default) CF_ADDTO(conf, debug_default)
@ -315,6 +355,7 @@ dev_proto_start: proto_start DIRECT {
dev_proto: dev_proto:
dev_proto_start proto_name '{' dev_proto_start proto_name '{'
| dev_proto proto_item ';' | dev_proto proto_item ';'
| dev_proto proto_channel ';'
| dev_proto dev_iface_patt ';' | dev_proto dev_iface_patt ';'
; ;

View file

@ -138,7 +138,7 @@ if_copy(struct iface *to, struct iface *from)
static inline void static inline void
ifa_send_notify(struct proto *p, unsigned c, struct ifa *a) ifa_send_notify(struct proto *p, unsigned c, struct ifa *a)
{ {
if (p->ifa_notify) if (p->ifa_notify && (p->proto_state != PS_DOWN))
{ {
if (p->debug & D_IFACES) if (p->debug & D_IFACES)
log(L_TRACE "%s < %s address %N on interface %s %s", log(L_TRACE "%s < %s address %N on interface %s %s",
@ -155,7 +155,7 @@ ifa_notify_change_(unsigned c, struct ifa *a)
DBG("IFA change notification (%x) for %s:%I\n", c, a->iface->name, a->ip); DBG("IFA change notification (%x) for %s:%I\n", c, a->iface->name, a->ip);
WALK_LIST(p, active_proto_list) WALK_LIST(p, proto_list)
ifa_send_notify(p, c, a); ifa_send_notify(p, c, a);
} }
@ -174,7 +174,7 @@ ifa_notify_change(unsigned c, struct ifa *a)
static inline void static inline void
if_send_notify(struct proto *p, unsigned c, struct iface *i) if_send_notify(struct proto *p, unsigned c, struct iface *i)
{ {
if (p->if_notify) if (p->if_notify && (p->proto_state != PS_DOWN))
{ {
if (p->debug & D_IFACES) if (p->debug & D_IFACES)
log(L_TRACE "%s < interface %s %s", p->name, i->name, log(L_TRACE "%s < interface %s %s", p->name, i->name,
@ -215,7 +215,7 @@ if_notify_change(unsigned c, struct iface *i)
ifa_notify_change_(IF_CHANGE_DOWN, a); ifa_notify_change_(IF_CHANGE_DOWN, a);
} }
WALK_LIST(p, active_proto_list) WALK_LIST(p, proto_list)
if_send_notify(p, c, i); if_send_notify(p, c, i);
if (c & IF_CHANGE_UP) if (c & IF_CHANGE_UP)

View file

@ -239,7 +239,7 @@ neigh_up(neighbor *n, struct iface *i, int scope, struct ifa *a)
rem_node(&n->n); rem_node(&n->n);
add_tail(&neigh_hash_table[neigh_hash(n->proto, &n->addr)], &n->n); add_tail(&neigh_hash_table[neigh_hash(n->proto, &n->addr)], &n->n);
DBG("Waking up sticky neighbor %I\n", n->addr); DBG("Waking up sticky neighbor %I\n", n->addr);
if (n->proto->neigh_notify && n->proto->core_state != FS_FLUSHING) if (n->proto->neigh_notify && (n->proto->proto_state != PS_STOP))
n->proto->neigh_notify(n); n->proto->neigh_notify(n);
} }
@ -252,7 +252,7 @@ neigh_down(neighbor *n)
n->iface = NULL; n->iface = NULL;
n->ifa = NULL; n->ifa = NULL;
n->scope = -1; n->scope = -1;
if (n->proto->neigh_notify && n->proto->core_state != FS_FLUSHING) if (n->proto->neigh_notify && (n->proto->proto_state != PS_STOP))
n->proto->neigh_notify(n); n->proto->neigh_notify(n);
rem_node(&n->n); rem_node(&n->n);
if (n->flags & NEF_STICKY) if (n->flags & NEF_STICKY)
@ -333,7 +333,7 @@ neigh_if_link(struct iface *i)
WALK_LIST_DELSAFE(x, y, i->neighbors) WALK_LIST_DELSAFE(x, y, i->neighbors)
{ {
neighbor *n = SKIP_BACK(neighbor, if_n, x); neighbor *n = SKIP_BACK(neighbor, if_n, x);
if (n->proto->neigh_notify && n->proto->core_state != FS_FLUSHING) if (n->proto->neigh_notify && (n->proto->proto_state != PS_STOP))
n->proto->neigh_notify(n); n->proto->neigh_notify(n);
} }
} }

File diff suppressed because it is too large Load diff

View file

@ -69,23 +69,6 @@ its state by calling the <func/proto_notify_state/ function.
<p>At any time, the core code can ask the protocol to shut itself down by calling its stop() hook. <p>At any time, the core code can ask the protocol to shut itself down by calling its stop() hook.
<p>The <em/core state machine/ takes care of the core view of protocol state.
The states are traversed according to changes of the protocol state machine, but
sometimes the transitions are delayed if the core needs to finish some actions
(for example sending of new routes to the protocol) before proceeding to the
new state. There are the following core states:
<descrip>
<tag/FS_HUNGRY/ The protocol is down, it doesn't have any routes and
doesn't want them.
<tag/FS_FEEDING/ The protocol has reached the <tt/PS_UP/ state, but
we are still busy sending the initial set of routes to it.
<tag/FS_HAPPY/ The protocol is up and has complete routing information.
<tag/FS_FLUSHING/ The protocol is shutting down (it's in either <tt/PS_STOP/
or <tt/PS_DOWN/ state) and we're flushing all of its routes from the
routing tables.
</descrip>
<sect1>Functions of the protocol module <sect1>Functions of the protocol module
<p>The protocol module provides the following functions: <p>The protocol module provides the following functions:

View file

@ -11,7 +11,9 @@
#include "lib/lists.h" #include "lib/lists.h"
#include "lib/resource.h" #include "lib/resource.h"
#include "lib/event.h"
#include "lib/timer.h" #include "lib/timer.h"
#include "nest/route.h"
#include "conf/conf.h" #include "conf/conf.h"
struct iface; struct iface;
@ -22,13 +24,16 @@ struct neighbor;
struct rta; struct rta;
struct network; struct network;
struct proto_config; struct proto_config;
struct channel_limit;
struct channel_config;
struct config; struct config;
struct proto; struct proto;
struct event; struct channel;
struct ea_list; struct ea_list;
struct eattr; struct eattr;
struct symbol; struct symbol;
/* /*
* Routing Protocol * Routing Protocol
*/ */
@ -39,9 +44,10 @@ struct protocol {
char *template; /* Template for automatic generation of names */ char *template; /* Template for automatic generation of names */
int name_counter; /* Counter for automatic name generation */ int name_counter; /* Counter for automatic name generation */
int attr_class; /* Attribute class known to this protocol */ int attr_class; /* Attribute class known to this protocol */
int multitable; /* Protocol handles all announce hooks itself */
uint preference; /* Default protocol preference */ uint preference; /* Default protocol preference */
uint config_size; /* Size of protocol config */ uint channel_mask; /* Mask of accepted channel types (NB_*) */
uint proto_size; /* Size of protocol data structure */
uint config_size; /* Size of protocol config data structure */
void (*preconfig)(struct protocol *, struct config *); /* Just before configuring */ void (*preconfig)(struct protocol *, struct config *); /* Just before configuring */
void (*postconfig)(struct proto_config *); /* After configuring each instance */ void (*postconfig)(struct proto_config *); /* After configuring each instance */
@ -62,7 +68,6 @@ struct protocol {
void protos_build(void); void protos_build(void);
void proto_build(struct protocol *); void proto_build(struct protocol *);
void protos_preconfig(struct config *); void protos_preconfig(struct config *);
void protos_postconfig(struct config *);
void protos_commit(struct config *new, struct config *old, int force_restart, int type); void protos_commit(struct config *new, struct config *old, int force_restart, int type);
void protos_dump_all(void); void protos_dump_all(void);
@ -90,16 +95,12 @@ struct proto_config {
char *name; char *name;
char *dsc; char *dsc;
int class; /* SYM_PROTO or SYM_TEMPLATE */ int class; /* SYM_PROTO or SYM_TEMPLATE */
u8 net_type; /* Protocol network type (NET_*), 0 for undefined */
u8 disabled; /* Protocol enabled/disabled by default */
u32 debug, mrtdump; /* Debugging bitfields, both use D_* constants */ u32 debug, mrtdump; /* Debugging bitfields, both use D_* constants */
unsigned preference, disabled; /* Generic parameters */
int in_keep_filtered; /* Routes rejected in import filter are kept */
u32 router_id; /* Protocol specific router ID */ u32 router_id; /* Protocol specific router ID */
struct rtable_config *table; /* Table we're attached to */
struct filter *in_filter, *out_filter; /* Attached filters */ list channels; /* List of channel configs (struct channel_config) */
struct proto_limit *rx_limit; /* Limit for receiving routes from protocol
(relevant when in_keep_filtered is active) */
struct proto_limit *in_limit; /* Limit for importing routes from protocol */
struct proto_limit *out_limit; /* Limit for exporting routes to protocol */
/* Check proto_reconfigure() and proto_copy_config() after changing struct proto_config */ /* Check proto_reconfigure() and proto_copy_config() after changing struct proto_config */
@ -111,7 +112,6 @@ struct proto_stats {
/* Import - from protocol to core */ /* Import - from protocol to core */
u32 imp_routes; /* Number of routes successfully imported to the (adjacent) routing table */ u32 imp_routes; /* Number of routes successfully imported to the (adjacent) routing table */
u32 filt_routes; /* Number of routes rejected in import filter but kept in the routing table */ u32 filt_routes; /* Number of routes rejected in import filter but kept in the routing table */
u32 pref_routes; /* Number of routes that are preferred, sum over all routing tables */
u32 imp_updates_received; /* Number of route updates received */ u32 imp_updates_received; /* Number of route updates received */
u32 imp_updates_invalid; /* Number of route updates rejected as invalid */ u32 imp_updates_invalid; /* Number of route updates rejected as invalid */
u32 imp_updates_filtered; /* Number of route updates rejected by filters */ u32 imp_updates_filtered; /* Number of route updates rejected by filters */
@ -133,36 +133,34 @@ struct proto_stats {
}; };
struct proto { struct proto {
node n; /* Node in *_proto_list */ node n; /* Node in global proto_list */
node glob_node; /* Node in global proto_list */
struct protocol *proto; /* Protocol */ struct protocol *proto; /* Protocol */
struct proto_config *cf; /* Configuration data */ struct proto_config *cf; /* Configuration data */
struct proto_config *cf_new; /* Configuration we want to switch to after shutdown (NULL=delete) */ struct proto_config *cf_new; /* Configuration we want to switch to after shutdown (NULL=delete) */
pool *pool; /* Pool containing local objects */ pool *pool; /* Pool containing local objects */
struct event *attn; /* "Pay attention" event */ event *event; /* Protocol event */
list channels; /* List of channels to rtables (struct channel) */
struct channel *main_channel; /* Primary channel */
struct rte_src *main_source; /* Primary route source */
char *name; /* Name of this instance (== cf->name) */ char *name; /* Name of this instance (== cf->name) */
u32 debug; /* Debugging flags */ u32 debug; /* Debugging flags */
u32 mrtdump; /* MRTDump flags */ u32 mrtdump; /* MRTDump flags */
unsigned preference; /* Default route preference */ uint active_channels; /* Number of active channels */
byte accept_ra_types; /* Which types of route announcements are accepted (RA_OPTIMAL or RA_ANY) */ byte net_type; /* Protocol network type (NET_*), 0 for undefined */
byte disabled; /* Manually disabled */ byte disabled; /* Manually disabled */
byte proto_state; /* Protocol state machine (PS_*, see below) */ byte proto_state; /* Protocol state machine (PS_*, see below) */
byte core_state; /* Core state machine (FS_*, see below) */ byte active; /* From PS_START to cleanup after PS_STOP */
byte export_state; /* Route export state (ES_*, see below) */ byte do_start; /* Start actions are scheduled */
byte do_stop; /* Stop actions are scheduled */
byte reconfiguring; /* We're shutting down due to reconfiguration */ byte reconfiguring; /* We're shutting down due to reconfiguration */
byte refeeding; /* We are refeeding (valid only if export_state == ES_FEEDING) */
byte flushing; /* Protocol is flushed in current flush loop round */
byte gr_recovery; /* Protocol should participate in graceful restart recovery */ byte gr_recovery; /* Protocol should participate in graceful restart recovery */
byte gr_lock; /* Graceful restart mechanism should wait for this proto */
byte gr_wait; /* Route export to protocol is postponed until graceful restart */
byte down_sched; /* Shutdown is scheduled for later (PDS_*) */ byte down_sched; /* Shutdown is scheduled for later (PDS_*) */
byte down_code; /* Reason for shutdown (PDC_* codes) */ byte down_code; /* Reason for shutdown (PDC_* codes) */
byte merge_limit; /* Maximal number of nexthops for RA_MERGED */
u32 hash_key; /* Random key used for hashing of neighbors */ u32 hash_key; /* Random key used for hashing of neighbors */
bird_clock_t last_state_change; /* Time of last state transition */ bird_clock_t last_state_change; /* Time of last state transition */
char *last_state_name_announced; /* Last state name we've announced to the user */ char *last_state_name_announced; /* Last state name we've announced to the user */
struct proto_stats stats; /* Current protocol statistics */
/* /*
* General protocol hooks: * General protocol hooks:
@ -177,11 +175,11 @@ struct proto {
* It can construct a new rte, add private attributes and * It can construct a new rte, add private attributes and
* decide whether the route shall be imported: 1=yes, -1=no, * decide whether the route shall be imported: 1=yes, -1=no,
* 0=process it through the import filter set by the user. * 0=process it through the import filter set by the user.
* reload_routes Request protocol to reload all its routes to the core * reload_routes Request channel to reload all its routes to the core
* (using rte_update()). Returns: 0=reload cannot be done, * (using rte_update()). Returns: 0=reload cannot be done,
* 1= reload is scheduled and will happen (asynchronously). * 1= reload is scheduled and will happen (asynchronously).
* feed_begin Notify protocol about beginning of route feeding. * feed_begin Notify channel about beginning of route feeding.
* feed_end Notify protocol about finish of route feeding. * feed_end Notify channel about finish of route feeding.
*/ */
void (*if_notify)(struct proto *, unsigned flags, struct iface *i); void (*if_notify)(struct proto *, unsigned flags, struct iface *i);
@ -191,9 +189,9 @@ struct proto {
struct ea_list *(*make_tmp_attrs)(struct rte *rt, struct linpool *pool); struct ea_list *(*make_tmp_attrs)(struct rte *rt, struct linpool *pool);
void (*store_tmp_attrs)(struct rte *rt, struct ea_list *attrs); void (*store_tmp_attrs)(struct rte *rt, struct ea_list *attrs);
int (*import_control)(struct proto *, struct rte **rt, struct ea_list **attrs, struct linpool *pool); int (*import_control)(struct proto *, struct rte **rt, struct ea_list **attrs, struct linpool *pool);
int (*reload_routes)(struct proto *); void (*reload_routes)(struct channel *);
void (*feed_begin)(struct proto *, int initial); void (*feed_begin)(struct channel *, int initial);
void (*feed_end)(struct proto *); void (*feed_end)(struct channel *);
/* /*
* Routing entry hooks (called only for routes belonging to this protocol): * Routing entry hooks (called only for routes belonging to this protocol):
@ -213,14 +211,6 @@ struct proto {
void (*rte_insert)(struct network *, struct rte *); void (*rte_insert)(struct network *, struct rte *);
void (*rte_remove)(struct network *, struct rte *); void (*rte_remove)(struct network *, struct rte *);
struct rtable *table; /* Our primary routing table */
struct rte_src *main_source; /* Primary route source */
struct announce_hook *main_ahook; /* Primary announcement hook */
struct announce_hook *ahooks; /* Announcement hooks for this protocol */
struct fib_iterator *feed_iterator; /* Routing table iterator used during protocol feeding */
struct announce_hook *feed_ahook; /* Announce hook we currently feed */
/* Hic sunt protocol-specific data */ /* Hic sunt protocol-specific data */
}; };
@ -244,25 +234,20 @@ struct proto_spec {
#define PDC_OUT_LIMIT_HIT 0x23 /* Route export limit reached */ #define PDC_OUT_LIMIT_HIT 0x23 /* Route export limit reached */
void *proto_new(struct proto_config *, unsigned size); void *proto_new(struct proto_config *);
void *proto_config_new(struct protocol *, int class); void *proto_config_new(struct protocol *, int class);
void proto_copy_config(struct proto_config *dest, struct proto_config *src); void proto_copy_config(struct proto_config *dest, struct proto_config *src);
void proto_request_feeding(struct proto *p);
static inline void
proto_copy_rest(struct proto_config *dest, struct proto_config *src, unsigned size)
{ memcpy(dest + 1, src + 1, size - sizeof(struct proto_config)); }
void graceful_restart_recovery(void); void graceful_restart_recovery(void);
void graceful_restart_init(void); void graceful_restart_init(void);
void graceful_restart_show_status(void); void graceful_restart_show_status(void);
void proto_graceful_restart_lock(struct proto *p); void channel_graceful_restart_lock(struct channel *c);
void proto_graceful_restart_unlock(struct proto *p); void channel_graceful_restart_unlock(struct channel *c);
#define DEFAULT_GR_WAIT 240 #define DEFAULT_GR_WAIT 240
void proto_show_limit(struct proto_limit *l, const char *dsc); void channel_show_limit(struct channel_limit *l, const char *dsc);
void proto_show_basic_info(struct proto *p); void channel_show_info(struct channel *c);
void proto_cmd_show(struct proto *, uint, int); void proto_cmd_show(struct proto *, uint, int);
void proto_cmd_disable(struct proto *, uint, int); void proto_cmd_disable(struct proto *, uint, int);
@ -285,7 +270,10 @@ proto_get_router_id(struct proto_config *pc)
return pc->router_id ? pc->router_id : pc->global->router_id; return pc->router_id ? pc->router_id : pc->global->router_id;
} }
extern list active_proto_list; /* Moved from route.h to avoid dependency conflicts */
static inline void rte_update(struct proto *p, net *net, rte *new) { rte_update2(p->main_channel, net, new, p->main_source); }
extern list proto_list;
/* /*
* Each protocol instance runs two different state machines: * Each protocol instance runs two different state machines:
@ -361,16 +349,6 @@ void proto_notify_state(struct proto *p, unsigned state);
* as a result of received ROUTE-REFRESH request). * as a result of received ROUTE-REFRESH request).
*/ */
#define FS_HUNGRY 0
#define FS_FEEDING 1 /* obsolete */
#define FS_HAPPY 2
#define FS_FLUSHING 3
#define ES_DOWN 0
#define ES_FEEDING 1
#define ES_READY 2
/* /*
@ -413,6 +391,7 @@ extern struct proto_config *cf_dev_proto;
#define PLD_OUT 2 /* Export limit */ #define PLD_OUT 2 /* Export limit */
#define PLD_MAX 3 #define PLD_MAX 3
#define PLA_NONE 0 /* No limit */
#define PLA_WARN 1 /* Issue log warning */ #define PLA_WARN 1 /* Issue log warning */
#define PLA_BLOCK 2 /* Block new routes */ #define PLA_BLOCK 2 /* Block new routes */
#define PLA_RESTART 4 /* Force protocol restart */ #define PLA_RESTART 4 /* Force protocol restart */
@ -422,42 +401,176 @@ extern struct proto_config *cf_dev_proto;
#define PLS_ACTIVE 1 /* Limit was hit */ #define PLS_ACTIVE 1 /* Limit was hit */
#define PLS_BLOCKED 2 /* Limit is active and blocking new routes */ #define PLS_BLOCKED 2 /* Limit is active and blocking new routes */
struct proto_limit { struct channel_limit {
u32 limit; /* Maximum number of prefixes */ u32 limit; /* Maximum number of prefixes */
byte action; /* Action to take (PLA_*) */ u8 action; /* Action to take (PLA_*) */
byte state; /* State of limit (PLS_*) */ u8 state; /* State of limit (PLS_*) */
}; };
void proto_notify_limit(struct announce_hook *ah, struct proto_limit *l, int dir, u32 rt_count); void channel_notify_limit(struct channel *c, struct channel_limit *l, int dir, u32 rt_count);
void proto_verify_limits(struct announce_hook *ah);
static inline void
proto_reset_limit(struct proto_limit *l)
{
if (l)
l->state = PLS_INITIAL;
}
/* /*
* Route Announcement Hook * Channels
*/ */
struct announce_hook { struct channel_class {
node n; uint channel_size; /* Size of channel data structure */
struct rtable *table; uint config_size; /* Size of channel config data structure */
struct proto *proto;
struct filter *in_filter; /* Input filter */ struct channel * (*init)(struct channel *, struct channel_config *); /* Create new instance */
struct filter *out_filter; /* Output filter */ int (*reconfigure)(struct channel *, struct channel_config *); /* Try to reconfigure instance, returns success */
struct proto_limit *rx_limit; /* Receive limit (for in_keep_filtered) */ int (*start)(struct channel *); /* Start the instance */
struct proto_limit *in_limit; /* Input limit */ int (*shutdown)(struct channel *); /* Stop the instance */
struct proto_limit *out_limit; /* Output limit */
struct proto_stats *stats; /* Per-table protocol statistics */ void (*copy_config)(struct channel_config *, struct channel_config *); /* Copy config from given channel instance */
struct announce_hook *next; /* Next hook for the same protocol */ #if 0
int in_keep_filtered; /* Routes rejected in import filter are kept */ void (*preconfig)(struct protocol *, struct config *); /* Just before configuring */
}; void (*postconfig)(struct proto_config *); /* After configuring each instance */
void (*dump)(struct proto *); /* Debugging dump */
void (*dump_attrs)(struct rte *); /* Dump protocol-dependent attributes */
void (*cleanup)(struct proto *); /* Called after shutdown when protocol became hungry/down */
void (*get_status)(struct proto *, byte *buf); /* Get instance status (for `show protocols' command) */
void (*get_route_info)(struct rte *, byte *buf, struct ea_list *attrs); /* Get route information (for `show route' command) */
int (*get_attr)(struct eattr *, byte *buf, int buflen); /* ASCIIfy dynamic attribute (returns GA_*) */
void (*show_proto_info)(struct proto *); /* Show protocol info (for `show protocols all' command) */
#endif
};
struct channel_config {
node n;
const char *name;
const struct channel_class *channel;
struct rtable_config *table; /* Table we're attached to */
struct filter *in_filter, *out_filter; /* Attached filters */
struct channel_limit rx_limit; /* Limit for receiving routes from protocol
(relevant when in_keep_filtered is active) */
struct channel_limit in_limit; /* Limit for importing routes from protocol */
struct channel_limit out_limit; /* Limit for exporting routes to protocol */
u8 net_type; /* Routing table network type (NET_*), 0 for undefined */
u8 ra_mode; /* Mode of received route advertisements (RA_*) */
u16 preference; /* Default route preference */
u8 merge_limit; /* Maximal number of nexthops for RA_MERGED */
u8 in_keep_filtered; /* Routes rejected in import filter are kept */
};
struct channel {
node n; /* Node in proto->channels */
node table_node; /* Node in table->channels */
const char *name; /* Channel name (may be NULL) */
const struct channel_class *channel;
struct proto *proto;
struct rtable *table;
struct filter *in_filter; /* Input filter */
struct filter *out_filter; /* Output filter */
struct channel_limit rx_limit; /* Receive limit (for in_keep_filtered) */
struct channel_limit in_limit; /* Input limit */
struct channel_limit out_limit; /* Output limit */
struct event *feed_event; /* Event responsible for feeding */
struct fib_iterator feed_fit; /* Routing table iterator used during feeding */
struct proto_stats stats; /* Per-channel protocol statistics */
u8 net_type; /* Routing table network type (NET_*), 0 for undefined */
u8 ra_mode; /* Mode of received route advertisements (RA_*) */
u16 preference; /* Default route preference */
u8 merge_limit; /* Maximal number of nexthops for RA_MERGED */
u8 in_keep_filtered; /* Routes rejected in import filter are kept */
u8 disabled;
u8 channel_state;
u8 export_state; /* Route export state (ES_*, see below) */
u8 feed_active;
u8 flush_active;
u8 refeeding; /* We are refeeding (valid only if export_state == ES_FEEDING) */
u8 reloadable; /* Hook reload_routes() is allowed on the channel */
u8 gr_lock; /* Graceful restart mechanism should wait for this channel */
u8 gr_wait; /* Route export to channel is postponed until graceful restart */
bird_clock_t last_state_change; /* Time of last state transition */
};
/*
* Channel states
*
* CS_DOWN - The initial and the final state of a channel. There is no route
* exchange between the protocol and the table. Channel is not counted as
* active. Channel keeps a ptr to the table, but do not lock the table and is
* not linked in the table. Generally, new closed channels are created in
* protocols' init() hooks. The protocol is expected to explicitly activate its
* channels (by calling channel_init() or channel_open()).
*
* CS_START - The channel as a connection between the protocol and the table is
* initialized (counted as active by the protocol, linked in the table and keeps
* the table locked), but there is no current route exchange. There still may be
* routes associated with the channel in the routing table if the channel falls
* to CS_START from CS_UP. Generally, channels are initialized in protocols'
* start() hooks when going to PS_START.
*
* CS_UP - The channel is initialized and the route exchange is allowed. Note
* that even in CS_UP state, route export may still be down (ES_DOWN) by the
* core decision (e.g. waiting for table convergence after graceful restart).
* I.e., the protocol decides to open the channel but the core decides to start
* route export. Route import (caused by rte_update() from the protocol) is not
* restricted by that and is on volition of the protocol. Generally, channels
* are opened in protocols' start() hooks when going to PS_UP.
*
* CS_FLUSHING - The transitional state between initialized channel and closed
* channel. The channel is still initialized, but no route exchange is allowed.
* Instead, the associated table is running flush loop to remove routes imported
* through the channel. After that, the channel changes state to CS_DOWN and
* is detached from the table (the table is unlocked and the channel is unlinked
* from it). Unlike other states, the CS_FLUSHING state is not explicitly
* entered or left by the protocol. A protocol may request to close a channel
* (by calling channel_close()), which causes the channel to change state to
* CS_FLUSHING and later to CS_DOWN. Also note that channels are closed
* automatically by the core when the protocol is going down.
*
* Allowed transitions:
*
* CS_DOWN -> CS_START / CS_UP
* CS_START -> CS_UP / CS_FLUSHING
* CS_UP -> CS_START / CS_FLUSHING
* CS_FLUSHING -> CS_DOWN (automatic)
*/
#define CS_DOWN 0
#define CS_START 1
#define CS_UP 2
#define CS_FLUSHING 3
#define ES_DOWN 0
#define ES_FEEDING 1
#define ES_READY 2
struct channel_config *proto_cf_find_channel(struct proto_config *p, uint net_type);
static inline struct channel_config *proto_cf_main_channel(struct proto_config *pc)
{ struct channel_config *cc = HEAD(pc->channels); return NODE_VALID(cc) ? cc : NULL; }
struct channel *proto_find_channel_by_table(struct proto *p, struct rtable *t);
struct channel *proto_add_channel(struct proto *p, struct channel_config *cf);
int proto_configure_channel(struct proto *p, struct channel **c, struct channel_config *cf);
void channel_set_state(struct channel *c, uint state);
/*
static inline void channel_init(struct channel *c) { channel_set_state(c, CS_START); }
static inline void channel_open(struct channel *c) { channel_set_state(c, CS_UP); }
static inline void channel_close(struct channel *c) { channel_set_state(c, CS_FLUSHING); }
*/
void channel_request_feeding(struct channel *c);
void *channel_config_new(const struct channel_class *cc, uint net_type, struct proto_config *proto);
int channel_reconfigure(struct channel *c, struct channel_config *cf);
struct announce_hook *proto_add_announce_hook(struct proto *p, struct rtable *t, struct proto_stats *stats);
struct announce_hook *proto_find_announce_hook(struct proto *p, struct rtable *t);
#endif #endif

View file

@ -12,10 +12,12 @@
#include "lib/lists.h" #include "lib/lists.h"
#include "lib/resource.h" #include "lib/resource.h"
#include "lib/timer.h" #include "lib/timer.h"
#include "nest/protocol.h" //#include "nest/protocol.h"
struct ea_list;
struct protocol; struct protocol;
struct proto; struct proto;
struct rte_src;
struct symbol; struct symbol;
struct filter; struct filter;
struct cli; struct cli;
@ -57,8 +59,8 @@ struct fib {
uint hash_order; /* Binary logarithm of hash_size */ uint hash_order; /* Binary logarithm of hash_size */
uint hash_shift; /* 32 - hash_order */ uint hash_shift; /* 32 - hash_order */
uint addr_type; /* Type of address data stored in fib (NET_*) */ uint addr_type; /* Type of address data stored in fib (NET_*) */
uint node_size; /* XXXX */ uint node_size; /* FIB node size, 0 for nonuniform */
uint node_offset; /* XXXX */ uint node_offset; /* Offset of fib_node struct inside of user data */
uint entries; /* Number of entries */ uint entries; /* Number of entries */
uint entries_min, entries_max; /* Entry count limits (else start rehashing) */ uint entries_min, entries_max; /* Entry count limits (else start rehashing) */
fib_init_fn init; /* Constructor */ fib_init_fn init; /* Constructor */
@ -146,7 +148,7 @@ typedef struct rtable {
node n; /* Node in list of all tables */ node n; /* Node in list of all tables */
struct fib fib; struct fib fib;
char *name; /* Name of this table */ 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_*) */ uint addr_type; /* Type of address data stored in table (NET_*) */
int pipe_busy; /* Pipe loop detection */ int pipe_busy; /* Pipe loop detection */
int use_count; /* Number of protocols using this table */ int use_count; /* Number of protocols using this table */
@ -159,7 +161,6 @@ typedef struct rtable {
struct event *rt_event; /* Routing table event */ struct event *rt_event; /* Routing table event */
int gc_counter; /* Number of operations since last GC */ int gc_counter; /* Number of operations since last GC */
bird_clock_t gc_time; /* Time of 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 prune_state; /* Table prune state, 1 -> scheduled, 2-> running */
byte hcu_scheduled; /* Hostcache update is scheduled */ byte hcu_scheduled; /* Hostcache update is scheduled */
byte nhu_state; /* Next Hop Update state */ byte nhu_state; /* Next Hop Update state */
@ -167,10 +168,6 @@ typedef struct rtable {
struct fib_iterator nhu_fit; /* Next Hop Update FIB iterator */ struct fib_iterator nhu_fit; /* Next Hop Update FIB iterator */
} rtable; } rtable;
#define RPS_NONE 0
#define RPS_SCHEDULED 1
#define RPS_RUNNING 2
typedef struct network { typedef struct network {
struct rte *routes; /* Available routes for this network */ struct rte *routes; /* Available routes for this network */
struct fib_node n; /* FIB flags reserved for kernel syncer */ struct fib_node n; /* FIB flags reserved for kernel syncer */
@ -206,7 +203,7 @@ struct hostentry {
typedef struct rte { typedef struct rte {
struct rte *next; struct rte *next;
net *net; /* Network this RTE belongs to */ 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 */ struct rta *attrs; /* Attributes of this route */
byte flags; /* Flags (REF_...) */ byte flags; /* Flags (REF_...) */
byte pflags; /* Protocol-specific flags */ byte pflags; /* Protocol-specific flags */
@ -279,13 +276,14 @@ static inline net *net_get(rtable *tab, const net_addr *addr) { return (net *) f
rte *rte_find(net *net, struct rte_src *src); rte *rte_find(net *net, struct rte_src *src);
rte *rte_get_temp(struct rta *); rte *rte_get_temp(struct rta *);
void rte_update2(struct announce_hook *ah, net *net, rte *new, struct rte_src *src); void rte_update2(struct channel *c, 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); } /* rte_update() moved to protocol.h to avoid dependency conflicts */
void rte_discard(rtable *tab, rte *old); void rte_discard(rtable *tab, rte *old);
int rt_examine(rtable *t, net_addr *a, struct proto *p, struct filter *filter); int rt_examine(rtable *t, net_addr *a, struct proto *p, struct filter *filter);
rte *rt_export_merged(struct announce_hook *ah, net *net, rte **rt_free, struct ea_list **tmpa, int silent); rte *rt_export_merged(struct channel *c, net *net, rte **rt_free, struct ea_list **tmpa, int silent);
void rt_refresh_begin(rtable *t, struct announce_hook *ah); void rt_refresh_begin(rtable *t, struct channel *c);
void rt_refresh_end(rtable *t, struct announce_hook *ah); void rt_refresh_end(rtable *t, struct channel *c);
void rt_schedule_prune(rtable *t);
void rte_dump(rte *); void rte_dump(rte *);
void rte_free(rte *); void rte_free(rte *);
rte *rte_do_cow(rte *); rte *rte_do_cow(rte *);
@ -293,19 +291,10 @@ static inline rte * rte_cow(rte *r) { return (r->flags & REF_COW) ? rte_do_cow(r
rte *rte_cow_rta(rte *r, linpool *lp); rte *rte_cow_rta(rte *r, linpool *lp);
void rt_dump(rtable *); void rt_dump(rtable *);
void rt_dump_all(void); void rt_dump_all(void);
int rt_feed_baby(struct proto *p); int rt_feed_channel(struct channel *c);
void rt_feed_baby_abort(struct proto *p); void rt_feed_channel_abort(struct channel *c);
int rt_prune_loop(void);
struct rtable_config *rt_new_table(struct symbol *s, uint addr_type); 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 { struct rt_show_data {
net_addr *addr; net_addr *addr;
@ -315,6 +304,7 @@ struct rt_show_data {
struct fib_iterator fit; struct fib_iterator fit;
struct proto *show_protocol; struct proto *show_protocol;
struct proto *export_protocol; struct proto *export_protocol;
struct channel *export_channel;
int export_mode, primary_only, filtered; int export_mode, primary_only, filtered;
struct config *running_on_config; struct config *running_on_config;
int net_counter, rt_counter, show_counter; int net_counter, rt_counter, show_counter;
@ -561,7 +551,6 @@ extern struct protocol *attr_class_to_protocol[EAP_MAX];
#define DEF_PREF_OSPF 150 /* OSPF intra-area, inter-area and type 1 external routes */ #define DEF_PREF_OSPF 150 /* OSPF intra-area, inter-area and type 1 external routes */
#define DEF_PREF_RIP 120 /* RIP */ #define DEF_PREF_RIP 120 /* RIP */
#define DEF_PREF_BGP 100 /* BGP */ #define DEF_PREF_BGP 100 /* BGP */
#define DEF_PREF_PIPE 70 /* Routes piped from other tables */
#define DEF_PREF_INHERITED 10 /* Routes inherited from other routing daemons */ #define DEF_PREF_INHERITED 10 /* Routes inherited from other routing daemons */
/* /*

View file

@ -24,13 +24,16 @@
#include "lib/resource.h" #include "lib/resource.h"
#include "lib/string.h" #include "lib/string.h"
static void
dev_ifa_notify(struct proto *p, unsigned c, struct ifa *ad)
{
struct rt_dev_config *P = (void *) p->cf;
if (!EMPTY_LIST(P->iface_list) && static void
!iface_patt_find(&P->iface_list, ad->iface, ad->iface->addr)) dev_ifa_notify(struct proto *P, uint flags, struct ifa *ad)
{
struct rt_dev_proto *p = (void *) P;
struct rt_dev_config *cf = (void *) P->cf;
struct channel *c;
if (!EMPTY_LIST(cf->iface_list) &&
!iface_patt_find(&cf->iface_list, ad->iface, ad->iface->addr))
/* Empty list is automagically treated as "*" */ /* Empty list is automagically treated as "*" */
return; return;
@ -40,12 +43,22 @@ dev_ifa_notify(struct proto *p, unsigned c, struct ifa *ad)
if (ad->scope <= SCOPE_LINK) if (ad->scope <= SCOPE_LINK)
return; return;
if (c & IF_CHANGE_DOWN) if (ad->prefix.type == NET_IP4)
c = p->ip4_channel;
else if (ad->prefix.type == NET_IP6)
c = p->ip6_channel;
else
return;
if (!c)
return;
if (flags & IF_CHANGE_DOWN)
{ {
net *n; net *n;
DBG("dev_if_notify: %s:%I going down\n", ad->iface->name, ad->ip); DBG("dev_if_notify: %s:%I going down\n", ad->iface->name, ad->ip);
n = net_find(p->table, &ad->prefix); n = net_find(c->table, &ad->prefix);
if (!n) if (!n)
{ {
DBG("dev_if_notify: device shutdown: prefix not found\n"); DBG("dev_if_notify: device shutdown: prefix not found\n");
@ -53,10 +66,10 @@ dev_ifa_notify(struct proto *p, unsigned c, struct ifa *ad)
} }
/* Use iface ID as local source ID */ /* Use iface ID as local source ID */
struct rte_src *src = rt_get_source(p, ad->iface->index); struct rte_src *src = rt_get_source(P, ad->iface->index);
rte_update2(p->main_ahook, n, NULL, src); rte_update2(c, n, NULL, src);
} }
else if (c & IF_CHANGE_UP) else if (flags & IF_CHANGE_UP)
{ {
rta *a; rta *a;
net *n; net *n;
@ -65,7 +78,7 @@ dev_ifa_notify(struct proto *p, unsigned c, struct ifa *ad)
DBG("dev_if_notify: %s:%I going up\n", ad->iface->name, ad->ip); DBG("dev_if_notify: %s:%I going up\n", ad->iface->name, ad->ip);
/* Use iface ID as local source ID */ /* Use iface ID as local source ID */
struct rte_src *src = rt_get_source(p, ad->iface->index); struct rte_src *src = rt_get_source(P, ad->iface->index);
rta a0 = { rta a0 = {
.src = src, .src = src,
@ -77,37 +90,51 @@ dev_ifa_notify(struct proto *p, unsigned c, struct ifa *ad)
}; };
a = rta_lookup(&a0); a = rta_lookup(&a0);
n = net_get(p->table, &ad->prefix); n = net_get(c->table, &ad->prefix);
e = rte_get_temp(a); e = rte_get_temp(a);
e->net = n; e->net = n;
e->pflags = 0; e->pflags = 0;
rte_update2(p->main_ahook, n, e, src); rte_update2(c, n, e, src);
} }
} }
static struct proto * static struct proto *
dev_init(struct proto_config *c) dev_init(struct proto_config *CF)
{ {
struct proto *p = proto_new(c, sizeof(struct proto)); struct proto *P = proto_new(CF);
struct rt_dev_proto *p = (void *) P;
// struct rt_dev_config *cf = (void *) CF;
p->ifa_notify = dev_ifa_notify; proto_configure_channel(P, &p->ip4_channel, proto_cf_find_channel(CF, NET_IP4));
return p; proto_configure_channel(P, &p->ip6_channel, proto_cf_find_channel(CF, NET_IP6));
P->ifa_notify = dev_ifa_notify;
return P;
} }
static int static int
dev_reconfigure(struct proto *p, struct proto_config *new) dev_reconfigure(struct proto *P, struct proto_config *CF)
{ {
struct rt_dev_config *o = (struct rt_dev_config *) p->cf; struct rt_dev_proto *p = (void *) P;
struct rt_dev_config *n = (struct rt_dev_config *) new; struct rt_dev_config *o = (void *) P->cf;
struct rt_dev_config *n = (void *) CF;
return iface_patts_equal(&o->iface_list, &n->iface_list, NULL); if (!iface_patts_equal(&o->iface_list, &n->iface_list, NULL))
return 0;
return
proto_configure_channel(P, &p->ip4_channel, proto_cf_find_channel(CF, NET_IP4)) &&
proto_configure_channel(P, &p->ip6_channel, proto_cf_find_channel(CF, NET_IP6));
return 1;
} }
static void static void
dev_copy_config(struct proto_config *dest, struct proto_config *src) dev_copy_config(struct proto_config *dest, struct proto_config *src)
{ {
struct rt_dev_config *d = (struct rt_dev_config *) dest; struct rt_dev_config *d = (void *) dest;
struct rt_dev_config *s = (struct rt_dev_config *) src; struct rt_dev_config *s = (void *) src;
/* /*
* We copy iface_list as ifaces can be shared by more direct protocols. * We copy iface_list as ifaces can be shared by more direct protocols.
@ -120,7 +147,9 @@ dev_copy_config(struct proto_config *dest, struct proto_config *src)
struct protocol proto_device = { struct protocol proto_device = {
.name = "Direct", .name = "Direct",
.template = "direct%d", .template = "direct%d",
.preference = DEF_PREF_DIRECT, .preference = DEF_PREF_DIRECT,
.channel_mask = NB_IP,
.proto_size = sizeof(struct rt_dev_proto),
.config_size = sizeof(struct rt_dev_config), .config_size = sizeof(struct rt_dev_config),
.init = dev_init, .init = dev_init,
.reconfigure = dev_reconfigure, .reconfigure = dev_reconfigure,

View file

@ -14,4 +14,10 @@ struct rt_dev_config {
list iface_list; /* list of struct iface_patt */ list iface_list; /* list of struct iface_patt */
}; };
struct rt_dev_proto {
struct proto p;
struct channel *ip4_channel;
struct channel *ip6_channel;
};
#endif #endif

File diff suppressed because it is too large Load diff

View file

@ -952,7 +952,7 @@ bfd_init_all(void)
static struct proto * static struct proto *
bfd_init(struct proto_config *c) bfd_init(struct proto_config *c)
{ {
struct proto *p = proto_new(c, sizeof(struct bfd_proto)); struct proto *p = proto_new(c);
p->neigh_notify = bfd_neigh_notify; p->neigh_notify = bfd_neigh_notify;
@ -1118,6 +1118,7 @@ bfd_show_sessions(struct proto *P)
struct protocol proto_bfd = { struct protocol proto_bfd = {
.name = "BFD", .name = "BFD",
.template = "bfd%d", .template = "bfd%d",
.proto_size = sizeof(struct bfd_proto),
.config_size = sizeof(struct bfd_config), .config_size = sizeof(struct bfd_config),
.init = bfd_init, .init = bfd_init,
.start = bfd_start, .start = bfd_start,

View file

@ -1372,7 +1372,6 @@ static void
bgp_copy_config(struct proto_config *dest, struct proto_config *src) bgp_copy_config(struct proto_config *dest, struct proto_config *src)
{ {
/* Just a shallow copy */ /* Just a shallow copy */
proto_copy_rest(dest, src, sizeof(struct bgp_config));
} }

View file

@ -112,12 +112,6 @@ bgp_proto:
| bgp_proto CAPABILITIES bool ';' { BGP_CFG->capabilities = $3; } | bgp_proto CAPABILITIES bool ';' { BGP_CFG->capabilities = $3; }
| bgp_proto ADVERTISE IPV4 bool ';' { BGP_CFG->advertise_ipv4 = $4; } | bgp_proto ADVERTISE IPV4 bool ';' { BGP_CFG->advertise_ipv4 = $4; }
| bgp_proto PASSWORD text ';' { BGP_CFG->password = $3; } | bgp_proto PASSWORD text ';' { BGP_CFG->password = $3; }
| bgp_proto ROUTE LIMIT expr ';' {
this_proto->in_limit = cfg_allocz(sizeof(struct proto_limit));
this_proto->in_limit->limit = $4;
this_proto->in_limit->action = PLA_RESTART;
log(L_WARN "%s: Route limit option is deprecated, use import limit", this_proto->name);
}
| bgp_proto PASSIVE bool ';' { BGP_CFG->passive = $3; } | bgp_proto PASSIVE bool ';' { BGP_CFG->passive = $3; }
| bgp_proto INTERPRET COMMUNITIES bool ';' { BGP_CFG->interpret_communities = $4; } | bgp_proto INTERPRET COMMUNITIES bool ';' { BGP_CFG->interpret_communities = $4; }
| bgp_proto SECONDARY bool ';' { BGP_CFG->secondary = $3; } | bgp_proto SECONDARY bool ';' { BGP_CFG->secondary = $3; }

View file

@ -68,6 +68,10 @@ ospf_proto_finish(void)
if (EMPTY_LIST(cf->area_list)) if (EMPTY_LIST(cf->area_list))
cf_error( "No configured areas in OSPF"); cf_error( "No configured areas in OSPF");
/* Define default channel */
if (EMPTY_LIST(this_proto->channels))
channel_config_new(NULL, this_proto->net_type, this_proto);
int areano = 0; int areano = 0;
int backbone = 0; int backbone = 0;
int nssa = 0; int nssa = 0;
@ -84,7 +88,7 @@ ospf_proto_finish(void)
cf->abr = areano > 1; cf->abr = areano > 1;
/* Route export or NSSA translation (RFC 3101 3.1) */ /* Route export or NSSA translation (RFC 3101 3.1) */
cf->asbr = (this_proto->out_filter != FILTER_REJECT) || (nssa && cf->abr); cf->asbr = (proto_cf_main_channel(this_proto)->out_filter != FILTER_REJECT) || (nssa && cf->abr);
if (cf->abr && !backbone) if (cf->abr && !backbone)
{ {
@ -145,14 +149,16 @@ ospf_variant:
| OSPF3 { $$ = 0; } | OSPF3 { $$ = 0; }
; ;
ospf_proto_start: proto_start ospf_variant { ospf_proto_start: proto_start ospf_variant
this_proto = proto_config_new(&proto_ospf, $1); {
init_list(&OSPF_CFG->area_list); this_proto = proto_config_new(&proto_ospf, $1);
init_list(&OSPF_CFG->vlink_list); this_proto->net_type = $2 ? NET_IP4 : NET_IP6;
OSPF_CFG->tick = OSPF_DEFAULT_TICK;
OSPF_CFG->ospf2 = $2; init_list(&OSPF_CFG->area_list);
} init_list(&OSPF_CFG->vlink_list);
; OSPF_CFG->tick = OSPF_DEFAULT_TICK;
OSPF_CFG->ospf2 = $2;
};
ospf_proto: ospf_proto:
ospf_proto_start proto_name '{' ospf_proto_start proto_name '{'
@ -161,6 +167,7 @@ ospf_proto:
ospf_proto_item: ospf_proto_item:
proto_item proto_item
| proto_channel
| RFC1583COMPAT bool { OSPF_CFG->rfc1583 = $2; } | RFC1583COMPAT bool { OSPF_CFG->rfc1583 = $2; }
| STUB ROUTER bool { OSPF_CFG->stub_router = $3; } | STUB ROUTER bool { OSPF_CFG->stub_router = $3; }
| ECMP bool { OSPF_CFG->ecmp = $2 ? OSPF_DEFAULT_ECMP_LIMIT : 0; } | ECMP bool { OSPF_CFG->ecmp = $2 ? OSPF_DEFAULT_ECMP_LIMIT : 0; }

View file

@ -102,7 +102,7 @@
static int ospf_import_control(struct proto *P, rte **new, ea_list **attrs, struct linpool *pool); static int ospf_import_control(struct proto *P, rte **new, ea_list **attrs, struct linpool *pool);
static struct ea_list *ospf_make_tmp_attrs(struct rte *rt, struct linpool *pool); static struct ea_list *ospf_make_tmp_attrs(struct rte *rt, struct linpool *pool);
static void ospf_store_tmp_attrs(struct rte *rt, struct ea_list *attrs); static void ospf_store_tmp_attrs(struct rte *rt, struct ea_list *attrs);
static int ospf_reload_routes(struct proto *P); static void ospf_reload_routes(struct channel *C);
static int ospf_rte_better(struct rte *new, struct rte *old); static int ospf_rte_better(struct rte *new, struct rte *old);
static int ospf_rte_same(struct rte *new, struct rte *old); static int ospf_rte_same(struct rte *new, struct rte *old);
static void ospf_disp(timer *timer); static void ospf_disp(timer *timer);
@ -297,15 +297,16 @@ ospf_dump(struct proto *P)
} }
static struct proto * static struct proto *
ospf_init(struct proto_config *c) ospf_init(struct proto_config *CF)
{ {
struct ospf_config *oc = (struct ospf_config *) c; struct ospf_config *cf = (struct ospf_config *) CF;
struct proto *P = proto_new(c, sizeof(struct ospf_proto)); struct proto *P = proto_new(CF);
P->main_channel = proto_add_channel(P, proto_cf_main_channel(CF));
P->accept_ra_types = RA_OPTIMAL;
P->rt_notify = ospf_rt_notify; P->rt_notify = ospf_rt_notify;
P->if_notify = ospf_if_notify; P->if_notify = ospf_if_notify;
P->ifa_notify = oc->ospf2 ? ospf_ifa_notify2 : ospf_ifa_notify3; P->ifa_notify = cf->ospf2 ? ospf_ifa_notify2 : ospf_ifa_notify3;
P->import_control = ospf_import_control; P->import_control = ospf_import_control;
P->reload_routes = ospf_reload_routes; P->reload_routes = ospf_reload_routes;
P->make_tmp_attrs = ospf_make_tmp_attrs; P->make_tmp_attrs = ospf_make_tmp_attrs;
@ -389,17 +390,16 @@ ospf_schedule_rtcalc(struct ospf_proto *p)
p->calcrt = 1; p->calcrt = 1;
} }
static int static void
ospf_reload_routes(struct proto *P) ospf_reload_routes(struct channel *C)
{ {
struct ospf_proto *p = (struct ospf_proto *) P; struct ospf_proto *p = (struct ospf_proto *) C->proto;
if (p->calcrt != 2) if (p->calcrt == 2)
OSPF_TRACE(D_EVENTS, "Scheduling routing table calculation with route reload"); return;
OSPF_TRACE(D_EVENTS, "Scheduling routing table calculation with route reload");
p->calcrt = 2; p->calcrt = 2;
return 1;
} }
@ -637,17 +637,17 @@ ospf_area_reconfigure(struct ospf_area *oa, struct ospf_area_config *nac)
* nonbroadcast network, cost of interface, etc. * nonbroadcast network, cost of interface, etc.
*/ */
static int static int
ospf_reconfigure(struct proto *P, struct proto_config *c) ospf_reconfigure(struct proto *P, struct proto_config *CF)
{ {
struct ospf_proto *p = (struct ospf_proto *) P; struct ospf_proto *p = (struct ospf_proto *) P;
struct ospf_config *old = (struct ospf_config *) (P->cf); struct ospf_config *old = (struct ospf_config *) (P->cf);
struct ospf_config *new = (struct ospf_config *) c; struct ospf_config *new = (struct ospf_config *) CF;
struct ospf_area_config *nac; struct ospf_area_config *nac;
struct ospf_area *oa, *oax; struct ospf_area *oa, *oax;
struct ospf_iface *ifa, *ifx; struct ospf_iface *ifa, *ifx;
struct ospf_iface_patt *ip; struct ospf_iface_patt *ip;
if (proto_get_router_id(c) != p->router_id) if (proto_get_router_id(CF) != p->router_id)
return 0; return 0;
if (p->ospf2 != new->ospf2) if (p->ospf2 != new->ospf2)
@ -659,6 +659,9 @@ ospf_reconfigure(struct proto *P, struct proto_config *c)
if (old->abr != new->abr) if (old->abr != new->abr)
return 0; return 0;
if (!proto_configure_channel(P, &P->main_channel, proto_cf_main_channel(CF)))
return 0;
p->stub_router = new->stub_router; p->stub_router = new->stub_router;
p->merge_external = new->merge_external; p->merge_external = new->merge_external;
p->asbr = new->asbr; p->asbr = new->asbr;
@ -1465,6 +1468,8 @@ struct protocol proto_ospf = {
.template = "ospf%d", .template = "ospf%d",
.attr_class = EAP_OSPF, .attr_class = EAP_OSPF,
.preference = DEF_PREF_OSPF, .preference = DEF_PREF_OSPF,
.channel_mask = NB_IP,
.proto_size = sizeof(struct ospf_proto),
.config_size = sizeof(struct ospf_config), .config_size = sizeof(struct ospf_config),
.init = ospf_init, .init = ospf_init,
.dump = ospf_dump, .dump = ospf_dump,

View file

@ -1973,7 +1973,7 @@ again1:
if (reload || ort_changed(nf, &a0)) if (reload || ort_changed(nf, &a0))
{ {
net *ne = net_get(p->p.table, nf->fn.addr); net *ne = net_get(p->p.main_channel->table, nf->fn.addr);
rta *a = rta_lookup(&a0); rta *a = rta_lookup(&a0);
rte *e = rte_get_temp(a); rte *e = rte_get_temp(a);
@ -1985,7 +1985,6 @@ again1:
e->u.ospf.router_id = nf->old_rid = nf->n.rid; e->u.ospf.router_id = nf->old_rid = nf->n.rid;
e->pflags = 0; e->pflags = 0;
e->net = ne; e->net = ne;
e->pref = p->p.preference;
DBG("Mod rte type %d - %N via %I on iface %s, met %d\n", DBG("Mod rte type %d - %N via %I on iface %s, met %d\n",
a0.source, nf->fn.addr, a0.gw, a0.iface ? a0.iface->name : "(none)", nf->n.metric1); a0.source, nf->fn.addr, a0.gw, a0.iface ? a0.iface->name : "(none)", nf->n.metric1);
@ -1998,7 +1997,7 @@ again1:
rta_free(nf->old_rta); rta_free(nf->old_rta);
nf->old_rta = NULL; nf->old_rta = NULL;
net *ne = net_get(p->p.table, nf->fn.addr); net *ne = net_get(p->p.main_channel->table, nf->fn.addr);
rte_update(&p->p, ne, NULL); rte_update(&p->p, ne, NULL);
} }

View file

@ -16,28 +16,25 @@ CF_DEFINES
CF_DECLS CF_DECLS
CF_KEYWORDS(PIPE, PEER, TABLE, MODE, OPAQUE, TRANSPARENT) CF_KEYWORDS(PIPE, PEER, TABLE)
CF_GRAMMAR CF_GRAMMAR
CF_ADDTO(proto, pipe_proto '}') CF_ADDTO(proto, pipe_proto '}' { this_channel = NULL; } )
pipe_proto_start: proto_start PIPE { pipe_proto_start: proto_start PIPE
this_proto = proto_config_new(&proto_pipe, $1); {
PIPE_CFG->mode = PIPE_TRANSPARENT; this_proto = proto_config_new(&proto_pipe, $1);
} this_channel = channel_config_new(NULL, 0, this_proto);
; this_channel->in_filter = FILTER_ACCEPT;
this_channel->out_filter = FILTER_ACCEPT;
};
pipe_proto: pipe_proto:
pipe_proto_start proto_name '{' pipe_proto_start proto_name '{'
| pipe_proto proto_item ';' | pipe_proto proto_item ';'
| pipe_proto PEER TABLE SYM ';' { | pipe_proto channel_item ';'
if ($4->class != SYM_TABLE) | pipe_proto PEER TABLE rtable ';' { PIPE_CFG->peer = $4; }
cf_error("Routing table name expected");
PIPE_CFG->peer = $4->def;
}
| pipe_proto MODE OPAQUE ';' { PIPE_CFG->mode = PIPE_OPAQUE; }
| pipe_proto MODE TRANSPARENT ';' { PIPE_CFG->mode = PIPE_TRANSPARENT; }
; ;
CF_CODE CF_CODE

View file

@ -46,9 +46,8 @@
static void static void
pipe_rt_notify(struct proto *P, rtable *src_table, net *n, rte *new, rte *old, ea_list *attrs) pipe_rt_notify(struct proto *P, rtable *src_table, net *n, rte *new, rte *old, ea_list *attrs)
{ {
struct pipe_proto *p = (struct pipe_proto *) P; struct pipe_proto *p = (void *) P;
struct announce_hook *ah = (src_table == P->table) ? p->peer_ahook : P->main_ahook; struct channel *dst = (src_table == p->pri->table) ? p->sec : p->pri;
rtable *dst_table = ah->table;
struct rte_src *src; struct rte_src *src;
net *nn; net *nn;
@ -58,24 +57,18 @@ pipe_rt_notify(struct proto *P, rtable *src_table, net *n, rte *new, rte *old, e
if (!new && !old) if (!new && !old)
return; return;
if (dst_table->pipe_busy) if (dst->table->pipe_busy)
{ {
log(L_ERR "Pipe loop detected when sending %N to table %s", log(L_ERR "Pipe loop detected when sending %N to table %s",
n->n.addr, dst_table->name); n->n.addr, dst->table->name);
return; return;
} }
nn = net_get(dst_table, n->n.addr); nn = net_get(dst->table, n->n.addr);
if (new) if (new)
{ {
memcpy(&a, new->attrs, sizeof(rta)); memcpy(&a, new->attrs, sizeof(rta));
if (p->mode == PIPE_OPAQUE)
{
a.src = P->main_source;
a.source = RTS_PIPE;
}
a.aflags = 0; a.aflags = 0;
a.eattrs = attrs; a.eattrs = attrs;
a.hostentry = NULL; a.hostentry = NULL;
@ -83,13 +76,10 @@ pipe_rt_notify(struct proto *P, rtable *src_table, net *n, rte *new, rte *old, e
e->net = nn; e->net = nn;
e->pflags = 0; e->pflags = 0;
if (p->mode == PIPE_TRANSPARENT) /* Copy protocol specific embedded attributes. */
{ memcpy(&(e->u), &(new->u), sizeof(e->u));
/* Copy protocol specific embedded attributes. */ e->pref = new->pref;
memcpy(&(e->u), &(new->u), sizeof(e->u)); e->pflags = new->pflags;
e->pref = new->pref;
e->pflags = new->pflags;
}
src = a.src; src = a.src;
} }
@ -100,7 +90,7 @@ pipe_rt_notify(struct proto *P, rtable *src_table, net *n, rte *new, rte *old, e
} }
src_table->pipe_busy = 1; src_table->pipe_busy = 1;
rte_update2(ah, nn, e, src); rte_update2(dst, nn, e, src);
src_table->pipe_busy = 0; src_table->pipe_busy = 0;
} }
@ -111,171 +101,117 @@ pipe_import_control(struct proto *P, rte **ee, ea_list **ea UNUSED, struct linpo
if (pp == P) if (pp == P)
return -1; /* Avoid local loops automatically */ return -1; /* Avoid local loops automatically */
return 0; return 0;
} }
static int static void
pipe_reload_routes(struct proto *P) pipe_reload_routes(struct channel *C)
{ {
struct pipe_proto *p = (struct pipe_proto *) P; struct pipe_proto *p = (void *) C->proto;
/* /* Route reload on one channel is just refeed on the other */
* Because the pipe protocol feeds routes from both routing tables channel_request_feeding((C == p->pri) ? p->sec : p->pri);
* together, both directions are reloaded during refeed and 'reload }
* out' command works like 'reload' command. For symmetry, we also
* request refeed when 'reload in' command is used.
*/
proto_request_feeding(P);
proto_reset_limit(P->main_ahook->in_limit);
proto_reset_limit(p->peer_ahook->in_limit);
return 1; static void
pipe_postconfig(struct proto_config *CF)
{
struct pipe_config *cf = (void *) CF;
struct channel_config *cc = proto_cf_main_channel(CF);
if (!cc->table)
cf_error("Primary routing table not specified");
if (!cf->peer)
cf_error("Secondary routing table not specified");
if (cc->table == cf->peer)
cf_error("Primary table and peer table must be different");
if (cc->table->addr_type != cf->peer->addr_type)
cf_error("Primary table and peer table must have the same type");
if (cc->rx_limit.action)
cf_error("Pipe protocol does not support receive limits");
if (cc->in_keep_filtered)
cf_error("Pipe protocol prohibits keeping filtered routes");
}
static int
pipe_configure_channels(struct pipe_proto *p, struct pipe_config *cf)
{
struct channel_config *cc = proto_cf_main_channel(&cf->c);
struct channel_config pri_cf = {
.name = "pri",
.channel = cc->channel,
.table = cc->table,
.out_filter = cc->out_filter,
.in_limit = cc->in_limit,
.ra_mode = RA_ANY
};
struct channel_config sec_cf = {
.name = "sec",
.channel = cc->channel,
.table = cf->peer,
.out_filter = cc->in_filter,
.in_limit = cc->out_limit,
.ra_mode = RA_ANY
};
return
proto_configure_channel(&p->p, &p->pri, &pri_cf) &&
proto_configure_channel(&p->p, &p->sec, &sec_cf);
} }
static struct proto * static struct proto *
pipe_init(struct proto_config *C) pipe_init(struct proto_config *CF)
{ {
struct pipe_config *c = (struct pipe_config *) C; struct proto *P = proto_new(CF);
struct proto *P = proto_new(C, sizeof(struct pipe_proto)); struct pipe_proto *p = (void *) P;
struct pipe_proto *p = (struct pipe_proto *) P; struct pipe_config *cf = (void *) CF;
p->mode = c->mode;
p->peer_table = c->peer->table;
P->accept_ra_types = (p->mode == PIPE_OPAQUE) ? RA_OPTIMAL : RA_ANY;
P->rt_notify = pipe_rt_notify; P->rt_notify = pipe_rt_notify;
P->import_control = pipe_import_control; P->import_control = pipe_import_control;
P->reload_routes = pipe_reload_routes; P->reload_routes = pipe_reload_routes;
pipe_configure_channels(p, cf);
return P; return P;
} }
static int static int
pipe_start(struct proto *P) pipe_reconfigure(struct proto *P, struct proto_config *CF)
{ {
struct pipe_config *cf = (struct pipe_config *) P->cf; struct pipe_proto *p = (void *) P;
struct pipe_proto *p = (struct pipe_proto *) P; struct pipe_config *cf = (void *) CF;
/* Lock both tables, unlock is handled in pipe_cleanup() */ return pipe_configure_channels(p, cf);
rt_lock_table(P->table);
rt_lock_table(p->peer_table);
/* Going directly to PS_UP - prepare for feeding,
connect the protocol to both routing tables */
P->main_ahook = proto_add_announce_hook(P, P->table, &P->stats);
P->main_ahook->out_filter = cf->c.out_filter;
P->main_ahook->in_limit = cf->c.in_limit;
proto_reset_limit(P->main_ahook->in_limit);
p->peer_ahook = proto_add_announce_hook(P, p->peer_table, &p->peer_stats);
p->peer_ahook->out_filter = cf->c.in_filter;
p->peer_ahook->in_limit = cf->c.out_limit;
proto_reset_limit(p->peer_ahook->in_limit);
if (p->mode == PIPE_OPAQUE)
{
P->main_source = rt_get_source(P, 0);
rt_lock_source(P->main_source);
}
return PS_UP;
}
static void
pipe_cleanup(struct proto *P)
{
struct pipe_proto *p = (struct pipe_proto *) P;
bzero(&P->stats, sizeof(struct proto_stats));
bzero(&p->peer_stats, sizeof(struct proto_stats));
P->main_ahook = NULL;
p->peer_ahook = NULL;
if (p->mode == PIPE_OPAQUE)
rt_unlock_source(P->main_source);
P->main_source = NULL;
rt_unlock_table(P->table);
rt_unlock_table(p->peer_table);
}
static void
pipe_postconfig(struct proto_config *C)
{
struct pipe_config *c = (struct pipe_config *) C;
if (!c->peer)
cf_error("Name of peer routing table not specified");
if (c->peer == C->table)
cf_error("Primary table and peer table must be different");
if (C->in_keep_filtered)
cf_error("Pipe protocol prohibits keeping filtered routes");
if (C->rx_limit)
cf_error("Pipe protocol does not support receive limits");
}
extern int proto_reconfig_type;
static int
pipe_reconfigure(struct proto *P, struct proto_config *new)
{
struct pipe_proto *p = (struct pipe_proto *)P;
struct proto_config *old = P->cf;
struct pipe_config *oc = (struct pipe_config *) old;
struct pipe_config *nc = (struct pipe_config *) new;
if ((oc->peer->table != nc->peer->table) || (oc->mode != nc->mode))
return 0;
/* Update output filters in ahooks */
if (P->main_ahook)
{
P->main_ahook->out_filter = new->out_filter;
P->main_ahook->in_limit = new->in_limit;
proto_verify_limits(P->main_ahook);
}
if (p->peer_ahook)
{
p->peer_ahook->out_filter = new->in_filter;
p->peer_ahook->in_limit = new->out_limit;
proto_verify_limits(p->peer_ahook);
}
if ((P->proto_state != PS_UP) || (proto_reconfig_type == RECONFIG_SOFT))
return 1;
if ((new->preference != old->preference)
|| ! filter_same(new->in_filter, old->in_filter)
|| ! filter_same(new->out_filter, old->out_filter))
proto_request_feeding(P);
return 1;
} }
static void static void
pipe_copy_config(struct proto_config *dest, struct proto_config *src) pipe_copy_config(struct proto_config *dest, struct proto_config *src)
{ {
/* Just a shallow copy, not many items here */ /* Just a shallow copy, not many items here */
proto_copy_rest(dest, src, sizeof(struct pipe_config));
} }
static void static void
pipe_get_status(struct proto *P, byte *buf) pipe_get_status(struct proto *P, byte *buf)
{ {
struct pipe_proto *p = (struct pipe_proto *) P; struct pipe_proto *p = (void *) P;
bsprintf(buf, "%c> %s", (p->mode == PIPE_OPAQUE) ? '-' : '=', p->peer_table->name); bsprintf(buf, "%s <=> %s", p->pri->table->name, p->sec->table->name);
} }
static void static void
pipe_show_stats(struct pipe_proto *p) pipe_show_stats(struct pipe_proto *p)
{ {
struct proto_stats *s1 = &p->p.stats; struct proto_stats *s1 = &p->pri->stats;
struct proto_stats *s2 = &p->peer_stats; struct proto_stats *s2 = &p->sec->stats;
/* /*
* Pipe stats (as anything related to pipes) are a bit tricky. There * Pipe stats (as anything related to pipes) are a bit tricky. There
@ -318,17 +254,16 @@ pipe_show_stats(struct pipe_proto *p)
static void static void
pipe_show_proto_info(struct proto *P) pipe_show_proto_info(struct proto *P)
{ {
struct pipe_proto *p = (struct pipe_proto *) P; struct pipe_proto *p = (void *) P;
struct pipe_config *cf = (struct pipe_config *) P->cf;
// cli_msg(-1006, " Table: %s", P->table->name); cli_msg(-1006, " Channel %s", "main");
// cli_msg(-1006, " Peer table: %s", p->peer_table->name); cli_msg(-1006, " Table: %s", p->pri->table->name);
cli_msg(-1006, " Preference: %d", P->preference); cli_msg(-1006, " Peer table: %s", p->sec->table->name);
cli_msg(-1006, " Input filter: %s", filter_name(cf->c.in_filter)); cli_msg(-1006, " Import filter: %s", filter_name(p->sec->out_filter));
cli_msg(-1006, " Output filter: %s", filter_name(cf->c.out_filter)); cli_msg(-1006, " Export filter: %s", filter_name(p->pri->out_filter));
proto_show_limit(cf->c.in_limit, "Import limit:"); channel_show_limit(&p->pri->in_limit, "Import limit:");
proto_show_limit(cf->c.out_limit, "Export limit:"); channel_show_limit(&p->sec->in_limit, "Export limit:");
if (P->proto_state != PS_DOWN) if (P->proto_state != PS_DOWN)
pipe_show_stats(p); pipe_show_stats(p);
@ -338,13 +273,10 @@ pipe_show_proto_info(struct proto *P)
struct protocol proto_pipe = { struct protocol proto_pipe = {
.name = "Pipe", .name = "Pipe",
.template = "pipe%d", .template = "pipe%d",
.multitable = 1, .proto_size = sizeof(struct pipe_proto),
.preference = DEF_PREF_PIPE,
.config_size = sizeof(struct pipe_config), .config_size = sizeof(struct pipe_config),
.postconfig = pipe_postconfig, .postconfig = pipe_postconfig,
.init = pipe_init, .init = pipe_init,
.start = pipe_start,
.cleanup = pipe_cleanup,
.reconfigure = pipe_reconfigure, .reconfigure = pipe_reconfigure,
.copy_config = pipe_copy_config, .copy_config = pipe_copy_config,
.get_status = pipe_get_status, .get_status = pipe_get_status,

View file

@ -9,27 +9,15 @@
#ifndef _BIRD_PIPE_H_ #ifndef _BIRD_PIPE_H_
#define _BIRD_PIPE_H_ #define _BIRD_PIPE_H_
#define PIPE_OPAQUE 0
#define PIPE_TRANSPARENT 1
struct pipe_config { struct pipe_config {
struct proto_config c; struct proto_config c;
struct rtable_config *peer; /* Table we're connected to */ struct rtable_config *peer; /* Table we're connected to */
int mode; /* PIPE_OPAQUE or PIPE_TRANSPARENT */
}; };
struct pipe_proto { struct pipe_proto {
struct proto p; struct proto p;
struct rtable *peer_table; struct channel *pri;
struct announce_hook *peer_ahook; /* Announce hook for direction peer->primary */ struct channel *sec;
struct proto_stats peer_stats; /* Statistics for the direction peer->primary */
int mode; /* PIPE_OPAQUE or PIPE_TRANSPARENT */
}; };
extern struct protocol proto_pipe;
static inline int proto_is_pipe(struct proto *p)
{ return p->proto == &proto_pipe; }
#endif #endif

View file

@ -41,6 +41,7 @@ CF_ADDTO(proto, radv_proto)
radv_proto_start: proto_start RADV radv_proto_start: proto_start RADV
{ {
this_proto = proto_config_new(&proto_radv, $1); this_proto = proto_config_new(&proto_radv, $1);
init_list(&RADV_CFG->patt_list); init_list(&RADV_CFG->patt_list);
init_list(&RADV_CFG->pref_list); init_list(&RADV_CFG->pref_list);
init_list(&RADV_CFG->rdnss_list); init_list(&RADV_CFG->rdnss_list);
@ -49,14 +50,12 @@ radv_proto_start: proto_start RADV
radv_proto_item: radv_proto_item:
proto_item proto_item
| proto_channel
| INTERFACE radv_iface | INTERFACE radv_iface
| PREFIX radv_prefix { add_tail(&RADV_CFG->pref_list, NODE this_radv_prefix); } | PREFIX radv_prefix { add_tail(&RADV_CFG->pref_list, NODE this_radv_prefix); }
| RDNSS { init_list(&radv_dns_list); } radv_rdnss { add_tail_list(&RADV_CFG->rdnss_list, &radv_dns_list); } | RDNSS { init_list(&radv_dns_list); } radv_rdnss { add_tail_list(&RADV_CFG->rdnss_list, &radv_dns_list); }
| DNSSL { init_list(&radv_dns_list); } radv_dnssl { add_tail_list(&RADV_CFG->dnssl_list, &radv_dns_list); } | DNSSL { init_list(&radv_dns_list); } radv_dnssl { add_tail_list(&RADV_CFG->dnssl_list, &radv_dns_list); }
| TRIGGER net_any { | TRIGGER net_ip6 { RADV_CFG->trigger = $2; }
RADV_CFG->trigger = $2;
RADV_CFG->trigger_valid = 1;
}
; ;
radv_proto_opts: radv_proto_opts:

View file

@ -256,9 +256,16 @@ radv_ifa_notify(struct proto *p, unsigned flags, struct ifa *a)
radv_iface_notify(ifa, RA_EV_CHANGE); radv_iface_notify(ifa, RA_EV_CHANGE);
} }
static inline int radv_net_match_trigger(struct radv_config *cf, net *n) static inline int
radv_trigger_valid(struct radv_config *cf)
{ {
return cf->trigger_valid && net_equal(n->n.addr, cf->trigger); return cf->trigger.type != 0;
}
static inline int
radv_net_match_trigger(struct radv_config *cf, net *n)
{
return radv_trigger_valid(cf) && net_equal(n->n.addr, &cf->trigger);
} }
int int
@ -301,22 +308,35 @@ radv_check_active(struct proto_radv *ra)
{ {
struct radv_config *cf = (struct radv_config *) (ra->p.cf); struct radv_config *cf = (struct radv_config *) (ra->p.cf);
if (! cf->trigger_valid) if (!radv_trigger_valid(cf))
return 1; return 1;
return rt_examine(ra->p.table, cf->trigger, &ra->p, ra->p.cf->out_filter); struct channel *c =ra->p.main_channel;
return rt_examine(c->table, &cf->trigger, &ra->p, c->out_filter);
}
static void
radv_postconfig(struct proto_config *CF)
{
// struct radv_config *cf = (void *) CF;
/* Define default channel */
if (EMPTY_LIST(CF->channels))
channel_config_new(NULL, NET_IP6, CF);
} }
static struct proto * static struct proto *
radv_init(struct proto_config *c) radv_init(struct proto_config *CF)
{ {
struct proto *p = proto_new(c, sizeof(struct proto_radv)); struct proto *p = proto_new(CF);
p->main_channel = proto_add_channel(p, proto_cf_main_channel(CF));
p->accept_ra_types = RA_OPTIMAL;
p->import_control = radv_import_control; p->import_control = radv_import_control;
p->rt_notify = radv_rt_notify; p->rt_notify = radv_rt_notify;
p->if_notify = radv_if_notify; p->if_notify = radv_if_notify;
p->ifa_notify = radv_ifa_notify; p->ifa_notify = radv_ifa_notify;
return p; return p;
} }
@ -327,7 +347,7 @@ radv_start(struct proto *p)
struct radv_config *cf = (struct radv_config *) (p->cf); struct radv_config *cf = (struct radv_config *) (p->cf);
init_list(&(ra->iface_list)); init_list(&(ra->iface_list));
ra->active = !cf->trigger_valid; ra->active = !radv_trigger_valid(cf);
return PS_UP; return PS_UP;
} }
@ -352,11 +372,11 @@ radv_shutdown(struct proto *p)
} }
static int static int
radv_reconfigure(struct proto *p, struct proto_config *c) radv_reconfigure(struct proto *p, struct proto_config *CF)
{ {
struct proto_radv *ra = (struct proto_radv *) p; struct proto_radv *ra = (struct proto_radv *) p;
// struct radv_config *old = (struct radv_config *) (p->cf); // struct radv_config *old = (struct radv_config *) (p->cf);
struct radv_config *new = (struct radv_config *) c; struct radv_config *new = (struct radv_config *) CF;
/* /*
* The question is why there is a reconfigure function for RAdv if * The question is why there is a reconfigure function for RAdv if
@ -366,7 +386,10 @@ radv_reconfigure(struct proto *p, struct proto_config *c)
* causing nodes to temporary remove their default routes. * causing nodes to temporary remove their default routes.
*/ */
p->cf = c; /* radv_check_active() requires proper p->cf */ if (!proto_configure_channel(p, &p->main_channel, proto_cf_main_channel(CF)))
return 0;
p->cf = CF; /* radv_check_active() requires proper p->cf */
ra->active = radv_check_active(ra); ra->active = radv_check_active(ra);
struct iface *iface; struct iface *iface;
@ -423,7 +446,10 @@ radv_get_status(struct proto *p, byte *buf)
struct protocol proto_radv = { struct protocol proto_radv = {
.name = "RAdv", .name = "RAdv",
.template = "radv%d", .template = "radv%d",
.channel_mask = NB_IP6,
.proto_size = sizeof(struct proto_radv),
.config_size = sizeof(struct radv_config), .config_size = sizeof(struct radv_config),
.postconfig = radv_postconfig,
.init = radv_init, .init = radv_init,
.start = radv_start, .start = radv_start,
.shutdown = radv_shutdown, .shutdown = radv_shutdown,

View file

@ -50,8 +50,7 @@ struct radv_config
list rdnss_list; /* Global list of RDNSS configs (struct radv_rdnss_config) */ list rdnss_list; /* Global list of RDNSS configs (struct radv_rdnss_config) */
list dnssl_list; /* Global list of DNSSL configs (struct radv_dnssl_config) */ list dnssl_list; /* Global list of DNSSL configs (struct radv_dnssl_config) */
net_addr *trigger; /* Prefix of a trigger route, if defined */ net_addr trigger; /* Prefix of a trigger route, if defined */
u8 trigger_valid; /* Whether a trigger route is defined */
}; };
struct radv_iface_config struct radv_iface_config

View file

@ -52,17 +52,18 @@ rip_variant:
rip_proto_start: proto_start rip_variant rip_proto_start: proto_start rip_variant
{ {
this_proto = proto_config_new(&proto_rip, $1); this_proto = proto_config_new(&proto_rip, $1);
init_list(&RIP_CFG->patt_list); this_proto->net_type = $2 ? NET_IP4 : NET_IP6;
init_list(&RIP_CFG->patt_list);
RIP_CFG->rip2 = $2; RIP_CFG->rip2 = $2;
RIP_CFG->infinity = RIP_DEFAULT_INFINITY; RIP_CFG->infinity = RIP_DEFAULT_INFINITY;
RIP_CFG->min_timeout_time = 60; RIP_CFG->min_timeout_time = 60;
RIP_CFG->max_garbage_time = 60; RIP_CFG->max_garbage_time = 60;
}; };
rip_proto_item: rip_proto_item:
proto_item proto_item
| proto_channel
| ECMP bool { RIP_CFG->ecmp = $2 ? RIP_DEFAULT_ECMP_LIMIT : 0; } | ECMP bool { RIP_CFG->ecmp = $2 ? RIP_DEFAULT_ECMP_LIMIT : 0; }
| ECMP bool LIMIT expr { RIP_CFG->ecmp = $2 ? $4 : 0; if ($4 < 0) cf_error("ECMP limit cannot be negative"); } | ECMP bool LIMIT expr { RIP_CFG->ecmp = $2 ? $4 : 0; if ($4 < 0) cf_error("ECMP limit cannot be negative"); }
| INFINITY expr { RIP_CFG->infinity = $2; } | INFINITY expr { RIP_CFG->infinity = $2; }

View file

@ -143,7 +143,7 @@ rip_announce_rte(struct rip_proto *p, struct rip_entry *en)
if (rt) if (rt)
{ {
/* Update */ /* Update */
net *n = net_get(p->p.table, en->n.addr); net *n = net_get(p->p.main_channel->table, en->n.addr);
rta a0 = { rta a0 = {
.src = p->p.main_source, .src = p->p.main_source,
@ -212,7 +212,7 @@ rip_announce_rte(struct rip_proto *p, struct rip_entry *en)
else else
{ {
/* Withdraw */ /* Withdraw */
net *n = net_find(p->p.table, en->n.addr); net *n = net_find(p->p.main_channel->table, en->n.addr);
rte_update(&p->p, n, NULL); rte_update(&p->p, n, NULL);
} }
} }
@ -1027,19 +1027,17 @@ rip_import_control(struct proto *P, struct rte **rt, struct ea_list **attrs, str
return 0; return 0;
} }
static int static void
rip_reload_routes(struct proto *P) rip_reload_routes(struct channel *C)
{ {
struct rip_proto *p = (struct rip_proto *) P; struct rip_proto *p = (struct rip_proto *) C->proto;
if (p->rt_reload) if (p->rt_reload)
return 1; return;
TRACE(D_EVENTS, "Scheduling route reload"); TRACE(D_EVENTS, "Scheduling route reload");
p->rt_reload = 1; p->rt_reload = 1;
rip_kick_timer(p); rip_kick_timer(p);
return 1;
} }
static struct ea_list * static struct ea_list *
@ -1070,12 +1068,23 @@ rip_rte_same(struct rte *new, struct rte *old)
} }
static struct proto * static void
rip_init(struct proto_config *cfg) rip_postconfig(struct proto_config *CF)
{ {
struct proto *P = proto_new(cfg, sizeof(struct rip_proto)); // struct rip_config *cf = (void *) CF;
/* Define default channel */
if (EMPTY_LIST(CF->channels))
channel_config_new(NULL, CF->net_type, CF);
}
static struct proto *
rip_init(struct proto_config *CF)
{
struct proto *P = proto_new(CF);
P->main_channel = proto_add_channel(P, proto_cf_main_channel(CF));
P->accept_ra_types = RA_OPTIMAL;
P->if_notify = rip_if_notify; P->if_notify = rip_if_notify;
P->rt_notify = rip_rt_notify; P->rt_notify = rip_rt_notify;
P->neigh_notify = rip_neigh_notify; P->neigh_notify = rip_neigh_notify;
@ -1115,10 +1124,10 @@ rip_start(struct proto *P)
} }
static int static int
rip_reconfigure(struct proto *P, struct proto_config *c) rip_reconfigure(struct proto *P, struct proto_config *CF)
{ {
struct rip_proto *p = (void *) P; struct rip_proto *p = (void *) P;
struct rip_config *new = (void *) c; struct rip_config *new = (void *) CF;
// struct rip_config *old = (void *) (P->cf); // struct rip_config *old = (void *) (P->cf);
if (new->rip2 != p->rip2) if (new->rip2 != p->rip2)
@ -1127,9 +1136,12 @@ rip_reconfigure(struct proto *P, struct proto_config *c)
if (new->infinity != p->infinity) if (new->infinity != p->infinity)
return 0; return 0;
if (!proto_configure_channel(P, &P->main_channel, proto_cf_main_channel(CF)))
return 0;
TRACE(D_EVENTS, "Reconfiguring"); TRACE(D_EVENTS, "Reconfiguring");
p->p.cf = c; p->p.cf = CF;
p->ecmp = new->ecmp; p->ecmp = new->ecmp;
rip_reconfigure_ifaces(p, new); rip_reconfigure_ifaces(p, new);
@ -1270,7 +1282,10 @@ struct protocol proto_rip = {
.template = "rip%d", .template = "rip%d",
.attr_class = EAP_RIP, .attr_class = EAP_RIP,
.preference = DEF_PREF_RIP, .preference = DEF_PREF_RIP,
.channel_mask = NB_IP,
.proto_size = sizeof(struct rip_proto),
.config_size = sizeof(struct rip_config), .config_size = sizeof(struct rip_config),
.postconfig = rip_postconfig,
.init = rip_init, .init = rip_init,
.dump = rip_dump, .dump = rip_dump,
.start = rip_start, .start = rip_start,

View file

@ -38,15 +38,16 @@ CF_GRAMMAR
CF_ADDTO(proto, static_proto '}') CF_ADDTO(proto, static_proto '}')
static_proto_start: proto_start STATIC { static_proto_start: proto_start STATIC
this_proto = proto_config_new(&proto_static, $1); {
static_init_config((struct static_config *) this_proto); this_proto = proto_config_new(&proto_static, $1);
} static_init_config(STATIC_CFG);
; };
static_proto: static_proto:
static_proto_start proto_name '{' static_proto_start proto_name '{'
| static_proto proto_item ';' | static_proto proto_item ';'
| static_proto proto_channel ';' { this_proto->net_type = $2->net_type; }
| static_proto CHECK LINK bool ';' { STATIC_CFG->check_link = $4; } | static_proto CHECK LINK bool ';' { STATIC_CFG->check_link = $4; }
| static_proto IGP TABLE rtable ';' { STATIC_CFG->igp_table = $4; } | static_proto IGP TABLE rtable ';' { STATIC_CFG->igp_table = $4; }
| static_proto stat_route stat_route_opt_list ';' { static_route_finish(); } | static_proto stat_route stat_route_opt_list ';' { static_route_finish(); }

View file

@ -54,7 +54,7 @@ static inline rtable *
p_igp_table(struct proto *p) p_igp_table(struct proto *p)
{ {
struct static_config *cf = (void *) p->cf; struct static_config *cf = (void *) p->cf;
return cf->igp_table ? cf->igp_table->table : p->table; return cf->igp_table ? cf->igp_table->table : p->main_channel->table;
} }
static void static void
@ -108,11 +108,11 @@ static_install(struct proto *p, struct static_route *r, struct iface *ifa)
} }
if (r->dest == RTDX_RECURSIVE) if (r->dest == RTDX_RECURSIVE)
rta_set_recursive_next_hop(p->table, &a, p_igp_table(p), &r->via, &r->via); rta_set_recursive_next_hop(p->main_channel->table, &a, p_igp_table(p), &r->via, &r->via);
/* We skip rta_lookup() here */ /* We skip rta_lookup() here */
n = net_get(p->table, r->net); n = net_get(p->main_channel->table, r->net);
e = rte_get_temp(&a); e = rte_get_temp(&a);
e->net = n; e->net = n;
e->pflags = 0; e->pflags = 0;
@ -136,7 +136,7 @@ static_remove(struct proto *p, struct static_route *r)
return; return;
DBG("Removing static route %N via %I\n", r->net, r->via); DBG("Removing static route %N via %I\n", r->net, r->via);
n = net_find(p->table, r->net); n = net_find(p->main_channel->table, r->net);
rte_update(p, n, NULL); rte_update(p, n, NULL);
r->installed = 0; r->installed = 0;
} }
@ -309,6 +309,17 @@ static_shutdown(struct proto *p)
r->installed = 0; r->installed = 0;
} }
/* Handle failure during channel reconfigure */
/* FIXME: This should be handled in a better way */
cf = (void *) p->cf_new;
if (cf)
{
WALK_LIST(r, cf->iface_routes)
r->installed = 0;
WALK_LIST(r, cf->other_routes)
r->installed = 0;
}
return PS_DOWN; return PS_DOWN;
} }
@ -450,16 +461,40 @@ static_init_config(struct static_config *c)
init_list(&c->other_routes); init_list(&c->other_routes);
} }
static struct proto * static void
static_init(struct proto_config *c) static_postconfig(struct proto_config *CF)
{ {
struct proto *p = proto_new(c, sizeof(struct proto)); struct static_config *cf = (void *) CF;
struct static_route *r;
p->neigh_notify = static_neigh_notify; if (EMPTY_LIST(CF->channels))
p->if_notify = static_if_notify; cf_error("Channel not specified");
p->rte_mergable = static_rte_mergable;
return p;
WALK_LIST(r, cf->iface_routes)
if (r->net->type != CF->net_type)
cf_error("Route %N incompatible with channel type", r->net);
WALK_LIST(r, cf->other_routes)
if (r->net->type != CF->net_type)
cf_error("Route %N incompatible with channel type", r->net);
}
static struct proto *
static_init(struct proto_config *CF)
{
struct proto *P = proto_new(CF);
// struct static_proto *p = (void *) P;
// struct static_config *cf = (void *) CF;
P->main_channel = proto_add_channel(P, proto_cf_main_channel(CF));
P->neigh_notify = static_neigh_notify;
P->if_notify = static_if_notify;
P->rte_mergable = static_rte_mergable;
return P;
} }
static inline int static inline int
@ -543,15 +578,18 @@ cf_igp_table(struct static_config *cf)
} }
static int static int
static_reconfigure(struct proto *p, struct proto_config *new) static_reconfigure(struct proto *p, struct proto_config *CF)
{ {
struct static_config *o = (void *) p->cf; struct static_config *o = (void *) p->cf;
struct static_config *n = (void *) new; struct static_config *n = (void *) CF;
struct static_route *r; struct static_route *r;
if (cf_igp_table(o) != cf_igp_table(n)) if (cf_igp_table(o) != cf_igp_table(n))
return 0; return 0;
if (!proto_configure_channel(p, &p->main_channel, proto_cf_main_channel(CF)))
return 0;
/* Delete all obsolete routes and reset neighbor entries */ /* Delete all obsolete routes and reset neighbor entries */
WALK_LIST(r, o->iface_routes) WALK_LIST(r, o->iface_routes)
static_match(p, r, n); static_match(p, r, n);
@ -617,20 +655,19 @@ static_copy_config(struct proto_config *dest, struct proto_config *src)
struct static_config *d = (struct static_config *) dest; struct static_config *d = (struct static_config *) dest;
struct static_config *s = (struct static_config *) src; struct static_config *s = (struct static_config *) src;
/* Shallow copy of everything */
proto_copy_rest(dest, src, sizeof(struct static_config));
/* Copy route lists */ /* Copy route lists */
static_copy_routes(&d->iface_routes, &s->iface_routes); static_copy_routes(&d->iface_routes, &s->iface_routes);
static_copy_routes(&d->other_routes, &s->other_routes); static_copy_routes(&d->other_routes, &s->other_routes);
} }
struct protocol proto_static = { struct protocol proto_static = {
.name = "Static", .name = "Static",
.template = "static%d", .template = "static%d",
.preference = DEF_PREF_STATIC, .preference = DEF_PREF_STATIC,
.channel_mask = NB_ANY,
.proto_size = sizeof(struct proto),
.config_size = sizeof(struct static_config), .config_size = sizeof(struct static_config),
.postconfig = static_postconfig,
.init = static_init, .init = static_init,
.dump = static_dump, .dump = static_dump,
.start = static_start, .start = static_start,

View file

@ -1127,7 +1127,7 @@ nl_parse_route(struct nlmsghdr *h, int scan)
src = KRT_SRC_ALIEN; src = KRT_SRC_ALIEN;
} }
net *net = net_get(p->p.table, &dst); net *net = net_get(p->p.main_channel->table, &dst);
rta ra = { rta ra = {
.src= p->p.main_source, .src= p->p.main_source,

View file

@ -15,6 +15,16 @@ CF_DEFINES
#define THIS_KRT ((struct krt_config *) this_proto) #define THIS_KRT ((struct krt_config *) this_proto)
#define THIS_KIF ((struct kif_config *) this_proto) #define THIS_KIF ((struct kif_config *) this_proto)
static void
krt_set_merge_paths(struct channel_config *cc, uint merge, uint limit)
{
if ((limit <= 0) || (limit > 255))
cf_error("Merge paths limit must be in range 1-255");
cc->ra_mode = merge ? RA_MERGED : RA_OPTIMAL;
cc->merge_limit = limit;
}
CF_DECLS CF_DECLS
CF_KEYWORDS(KERNEL, PERSIST, SCAN, TIME, LEARN, DEVICE, ROUTES, GRACEFUL, RESTART, KRT_SOURCE, KRT_METRIC, MERGE, PATHS) CF_KEYWORDS(KERNEL, PERSIST, SCAN, TIME, LEARN, DEVICE, ROUTES, GRACEFUL, RESTART, KRT_SOURCE, KRT_METRIC, MERGE, PATHS)
@ -25,15 +35,18 @@ CF_GRAMMAR
CF_ADDTO(proto, kern_proto '}') CF_ADDTO(proto, kern_proto '}')
kern_proto_start: proto_start KERNEL { this_proto = krt_init_config($1); } kern_proto_start: proto_start KERNEL {
this_proto = krt_init_config($1);
}
; ;
CF_ADDTO(kern_proto, kern_proto_start proto_name '{') CF_ADDTO(kern_proto, kern_proto_start proto_name '{')
CF_ADDTO(kern_proto, kern_proto proto_item ';')
CF_ADDTO(kern_proto, kern_proto kern_item ';') CF_ADDTO(kern_proto, kern_proto kern_item ';')
kern_item: kern_item:
PERSIST bool { THIS_KRT->persist = $2; } proto_item
| proto_channel { this_proto->net_type = $1->net_type; }
| PERSIST bool { THIS_KRT->persist = $2; }
| SCAN TIME expr { | SCAN TIME expr {
/* Scan time of 0 means scan on startup only */ /* Scan time of 0 means scan on startup only */
THIS_KRT->scan_time = $3; THIS_KRT->scan_time = $3;
@ -47,8 +60,8 @@ kern_item:
} }
| DEVICE ROUTES bool { THIS_KRT->devroutes = $3; } | DEVICE ROUTES bool { THIS_KRT->devroutes = $3; }
| GRACEFUL RESTART bool { THIS_KRT->graceful_restart = $3; } | GRACEFUL RESTART bool { THIS_KRT->graceful_restart = $3; }
| MERGE PATHS bool { THIS_KRT->merge_paths = $3 ? KRT_DEFAULT_ECMP_LIMIT : 0; } | MERGE PATHS bool { krt_set_merge_paths(this_channel, $3, KRT_DEFAULT_ECMP_LIMIT); }
| MERGE PATHS bool LIMIT expr { THIS_KRT->merge_paths = $3 ? $5 : 0; if (($5 <= 0) || ($5 > 255)) cf_error("Merge paths limit must be in range 1-255"); } | MERGE PATHS bool LIMIT expr { krt_set_merge_paths(this_channel, $3, $5); }
; ;
/* Kernel interface protocol */ /* Kernel interface protocol */
@ -59,11 +72,11 @@ kif_proto_start: proto_start DEVICE { this_proto = kif_init_config($1); }
; ;
CF_ADDTO(kif_proto, kif_proto_start proto_name '{') CF_ADDTO(kif_proto, kif_proto_start proto_name '{')
CF_ADDTO(kif_proto, kif_proto proto_item ';')
CF_ADDTO(kif_proto, kif_proto kif_item ';') CF_ADDTO(kif_proto, kif_proto kif_item ';')
kif_item: kif_item:
SCAN TIME expr { proto_item
| SCAN TIME expr {
/* Scan time of 0 means scan on startup only */ /* Scan time of 0 means scan on startup only */
THIS_KIF->scan_time = $3; THIS_KIF->scan_time = $3;
} }

View file

@ -170,7 +170,7 @@ kif_choose_primary(struct iface *i)
static struct proto * static struct proto *
kif_init(struct proto_config *c) kif_init(struct proto_config *c)
{ {
struct kif_proto *p = proto_new(c, sizeof(struct kif_proto)); struct kif_proto *p = proto_new(c);
kif_sys_init(p); kif_sys_init(p);
return &p->p; return &p->p;
@ -266,9 +266,6 @@ kif_copy_config(struct proto_config *dest, struct proto_config *src)
struct kif_config *d = (struct kif_config *) dest; struct kif_config *d = (struct kif_config *) dest;
struct kif_config *s = (struct kif_config *) src; struct kif_config *s = (struct kif_config *) src;
/* Shallow copy of everything (just scan_time currently) */
proto_copy_rest(dest, src, sizeof(struct kif_config));
/* Copy primary addr list */ /* Copy primary addr list */
cfg_copy_list(&d->primary, &s->primary, sizeof(struct kif_primary_item)); cfg_copy_list(&d->primary, &s->primary, sizeof(struct kif_primary_item));
@ -280,7 +277,7 @@ kif_copy_config(struct proto_config *dest, struct proto_config *src)
struct protocol proto_unix_iface = { struct protocol proto_unix_iface = {
.name = "Device", .name = "Device",
.template = "device%d", .template = "device%d",
.preference = DEF_PREF_DIRECT, .proto_size = sizeof(struct kif_proto),
.config_size = sizeof(struct kif_config), .config_size = sizeof(struct kif_config),
.preconfig = kif_preconfig, .preconfig = kif_preconfig,
.init = kif_init, .init = kif_init,
@ -348,10 +345,9 @@ krt_learn_announce_update(struct krt_proto *p, rte *e)
net *n = e->net; net *n = e->net;
rta *aa = rta_clone(e->attrs); rta *aa = rta_clone(e->attrs);
rte *ee = rte_get_temp(aa); rte *ee = rte_get_temp(aa);
net *nn = net_get(p->p.table, n->n.addr); net *nn = net_get(p->p.main_channel->table, n->n.addr);
ee->net = nn; ee->net = nn;
ee->pflags = 0; ee->pflags = 0;
ee->pref = p->p.preference;
ee->u.krt = e->u.krt; ee->u.krt = e->u.krt;
rte_update(&p->p, nn, ee); rte_update(&p->p, nn, ee);
} }
@ -359,7 +355,7 @@ krt_learn_announce_update(struct krt_proto *p, rte *e)
static void static void
krt_learn_announce_delete(struct krt_proto *p, net *n) krt_learn_announce_delete(struct krt_proto *p, net *n)
{ {
n = net_find(p->p.table, n->n.addr); n = net_find(p->p.main_channel->table, n->n.addr);
rte_update(&p->p, n, NULL); rte_update(&p->p, n, NULL);
} }
@ -575,7 +571,7 @@ krt_dump_attrs(rte *e)
static void static void
krt_flush_routes(struct krt_proto *p) krt_flush_routes(struct krt_proto *p)
{ {
struct rtable *t = p->p.table; struct rtable *t = p->p.main_channel->table;
KRT_TRACE(p, D_EVENTS, "Flushing kernel routes"); KRT_TRACE(p, D_EVENTS, "Flushing kernel routes");
FIB_WALK(&t->fib, net, n) FIB_WALK(&t->fib, net, n)
@ -594,12 +590,12 @@ krt_flush_routes(struct krt_proto *p)
static struct rte * static struct rte *
krt_export_net(struct krt_proto *p, net *net, rte **rt_free, ea_list **tmpa) krt_export_net(struct krt_proto *p, net *net, rte **rt_free, ea_list **tmpa)
{ {
struct announce_hook *ah = p->p.main_ahook; struct channel *c = p->p.main_channel;
struct filter *filter = ah->out_filter; struct filter *filter = c->out_filter;
rte *rt; rte *rt;
if (p->p.accept_ra_types == RA_MERGED) if (c->ra_mode == RA_MERGED)
return rt_export_merged(ah, net, rt_free, tmpa, 1); return rt_export_merged(c, net, rt_free, tmpa, 1);
rt = net->routes; rt = net->routes;
*rt_free = NULL; *rt_free = NULL;
@ -746,7 +742,7 @@ krt_got_route(struct krt_proto *p, rte *e)
static void static void
krt_prune(struct krt_proto *p) krt_prune(struct krt_proto *p)
{ {
struct rtable *t = p->p.table; struct rtable *t = p->p.main_channel->table;
KRT_TRACE(p, D_EVENTS, "Pruning table %s", t->name); KRT_TRACE(p, D_EVENTS, "Pruning table %s", t->name);
FIB_WALK(&t->fib, net, n) FIB_WALK(&t->fib, net, n)
@ -1052,10 +1048,10 @@ krt_if_notify(struct proto *P, uint flags, struct iface *iface UNUSED)
krt_scan_timer_kick(p); krt_scan_timer_kick(p);
} }
static int static void
krt_reload_routes(struct proto *P) krt_reload_routes(struct channel *C)
{ {
struct krt_proto *p = (struct krt_proto *) P; struct krt_proto *p = (void *) C->proto;
/* Although we keep learned routes in krt_table, we rather schedule a scan */ /* Although we keep learned routes in krt_table, we rather schedule a scan */
@ -1064,14 +1060,12 @@ krt_reload_routes(struct proto *P)
p->reload = 1; p->reload = 1;
krt_scan_timer_kick(p); krt_scan_timer_kick(p);
} }
return 1;
} }
static void static void
krt_feed_end(struct proto *P) krt_feed_end(struct channel *C)
{ {
struct krt_proto *p = (struct krt_proto *) P; struct krt_proto *p = (void *) C->proto;
p->ready = 1; p->ready = 1;
krt_scan_timer_kick(p); krt_scan_timer_kick(p);
@ -1092,14 +1086,42 @@ krt_rte_same(rte *a, rte *b)
struct krt_config *krt_cf; struct krt_config *krt_cf;
static struct proto * static void
krt_init(struct proto_config *C) krt_preconfig(struct protocol *P UNUSED, struct config *c)
{ {
struct krt_proto *p = proto_new(C, sizeof(struct krt_proto)); krt_cf = NULL;
struct krt_config *c = (struct krt_config *) C; krt_sys_preconfig(c);
}
static void
krt_postconfig(struct proto_config *CF)
{
struct krt_config *cf = (void *) CF;
if (EMPTY_LIST(CF->channels))
cf_error("Channel not specified");
#ifdef CONFIG_ALL_TABLES_AT_ONCE
if (krt_cf->scan_time != cf->scan_time)
cf_error("All kernel syncers must use the same table scan interval");
#endif
struct rtable_config *tab = proto_cf_main_channel(CF)->table;
if (tab->krt_attached)
cf_error("Kernel syncer (%s) already attached to table %s", tab->krt_attached->name, tab->name);
tab->krt_attached = CF;
krt_sys_postconfig(cf);
}
static struct proto *
krt_init(struct proto_config *CF)
{
struct krt_proto *p = proto_new(CF);
// struct krt_config *cf = (void *) CF;
p->p.main_channel = proto_add_channel(&p->p, proto_cf_main_channel(CF));
p->p.accept_ra_types = c->merge_paths ? RA_MERGED : RA_OPTIMAL;
p->p.merge_limit = c->merge_paths;
p->p.import_control = krt_import_control; p->p.import_control = krt_import_control;
p->p.rt_notify = krt_rt_notify; p->p.rt_notify = krt_rt_notify;
p->p.if_notify = krt_if_notify; p->p.if_notify = krt_if_notify;
@ -1118,7 +1140,7 @@ krt_start(struct proto *P)
{ {
struct krt_proto *p = (struct krt_proto *) P; struct krt_proto *p = (struct krt_proto *) P;
switch (p->p.table->addr_type) switch (p->p.net_type)
{ {
case NET_IP4: p->af = AF_INET; break; case NET_IP4: p->af = AF_INET; break;
case NET_IP6: p->af = AF_INET6; break; case NET_IP6: p->af = AF_INET6; break;
@ -1139,8 +1161,8 @@ krt_start(struct proto *P)
krt_scan_timer_start(p); krt_scan_timer_start(p);
if (P->gr_recovery && KRT_CF->graceful_restart) if (p->p.gr_recovery && KRT_CF->graceful_restart)
P->gr_wait = 1; p->p.main_channel->gr_wait = 1;
return PS_UP; return PS_UP;
} }
@ -1169,40 +1191,19 @@ krt_shutdown(struct proto *P)
} }
static int static int
krt_reconfigure(struct proto *p, struct proto_config *new) krt_reconfigure(struct proto *p, struct proto_config *CF)
{ {
struct krt_config *o = (struct krt_config *) p->cf; struct krt_config *o = (void *) p->cf;
struct krt_config *n = (struct krt_config *) new; struct krt_config *n = (void *) CF;
if (!proto_configure_channel(p, &p->main_channel, proto_cf_main_channel(CF)))
return 0;
if (!krt_sys_reconfigure((struct krt_proto *) p, n, o)) if (!krt_sys_reconfigure((struct krt_proto *) p, n, o))
return 0; return 0;
/* persist, graceful restart need not be the same */ /* persist, graceful restart need not be the same */
return o->scan_time == n->scan_time && o->learn == n->learn && return o->scan_time == n->scan_time && o->learn == n->learn && o->devroutes == n->devroutes;
o->devroutes == n->devroutes && o->merge_paths == n->merge_paths;
}
static void
krt_preconfig(struct protocol *P UNUSED, struct config *c)
{
krt_cf = NULL;
krt_sys_preconfig(c);
}
static void
krt_postconfig(struct proto_config *C)
{
struct krt_config *c = (struct krt_config *) C;
#ifdef CONFIG_ALL_TABLES_AT_ONCE
if (krt_cf->scan_time != c->scan_time)
cf_error("All kernel syncers must use the same table scan interval");
#endif
if (C->table->krt_attached)
cf_error("Kernel syncer (%s) already attached to table %s", C->table->krt_attached->name, C->table->name);
C->table->krt_attached = C;
krt_sys_postconfig(c);
} }
struct proto_config * struct proto_config *
@ -1226,9 +1227,6 @@ krt_copy_config(struct proto_config *dest, struct proto_config *src)
struct krt_config *d = (struct krt_config *) dest; struct krt_config *d = (struct krt_config *) dest;
struct krt_config *s = (struct krt_config *) src; struct krt_config *s = (struct krt_config *) src;
/* Shallow copy of everything */
proto_copy_rest(dest, src, sizeof(struct krt_config));
/* Fix sysdep parts */ /* Fix sysdep parts */
krt_sys_copy_config(d, s); krt_sys_copy_config(d, s);
} }
@ -1257,6 +1255,8 @@ struct protocol proto_unix_kernel = {
.template = "kernel%d", .template = "kernel%d",
.attr_class = EAP_KRT, .attr_class = EAP_KRT,
.preference = DEF_PREF_INHERITED, .preference = DEF_PREF_INHERITED,
.channel_mask = NB_IP,
.proto_size = sizeof(struct krt_proto),
.config_size = sizeof(struct krt_config), .config_size = sizeof(struct krt_config),
.preconfig = krt_preconfig, .preconfig = krt_preconfig,
.postconfig = krt_postconfig, .postconfig = krt_postconfig,

View file

@ -49,7 +49,6 @@ struct krt_config {
int learn; /* Learn routes from other sources */ int learn; /* Learn routes from other sources */
int devroutes; /* Allow export of device routes */ int devroutes; /* Allow export of device routes */
int graceful_restart; /* Regard graceful restart recovery */ int graceful_restart; /* Regard graceful restart recovery */
int merge_paths; /* Exported routes are merged for ECMP */
}; };
struct krt_proto { struct krt_proto {