summaryrefslogtreecommitdiff
path: root/proto
diff options
context:
space:
mode:
authorOndrej Zajicek (work) <santiago@crfreenet.org>2016-01-26 11:48:58 +0100
committerJan Moskyto Matejka <mq@ucw.cz>2016-02-01 10:28:50 +0100
commitf4a60a9bc429c28cb397402331dc01a789197450 (patch)
treee8cead76aa1c2aedfb76d7e3ceade2fc4a7214cf /proto
parent9f5782d9691f23296c4b1a68ef66630d9cc3a6cd (diff)
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.
Diffstat (limited to 'proto')
-rw-r--r--proto/bfd/bfd.c3
-rw-r--r--proto/bgp/bgp.c1
-rw-r--r--proto/bgp/config.Y6
-rw-r--r--proto/ospf/config.Y25
-rw-r--r--proto/ospf/ospf.c37
-rw-r--r--proto/ospf/rt.c5
-rw-r--r--proto/pipe/config.Y25
-rw-r--r--proto/pipe/pipe.c238
-rw-r--r--proto/pipe/pipe.h16
-rw-r--r--proto/radv/config.Y7
-rw-r--r--proto/radv/radv.c48
-rw-r--r--proto/radv/radv.h3
-rw-r--r--proto/rip/config.Y5
-rw-r--r--proto/rip/rip.c43
-rw-r--r--proto/static/config.Y11
-rw-r--r--proto/static/static.c69
16 files changed, 271 insertions, 271 deletions
diff --git a/proto/bfd/bfd.c b/proto/bfd/bfd.c
index 110bf931..62752e21 100644
--- a/proto/bfd/bfd.c
+++ b/proto/bfd/bfd.c
@@ -952,7 +952,7 @@ bfd_init_all(void)
static struct proto *
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;
@@ -1118,6 +1118,7 @@ bfd_show_sessions(struct proto *P)
struct protocol proto_bfd = {
.name = "BFD",
.template = "bfd%d",
+ .proto_size = sizeof(struct bfd_proto),
.config_size = sizeof(struct bfd_config),
.init = bfd_init,
.start = bfd_start,
diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c
index f549b0ed..cb5b108c 100644
--- a/proto/bgp/bgp.c
+++ b/proto/bgp/bgp.c
@@ -1372,7 +1372,6 @@ static void
bgp_copy_config(struct proto_config *dest, struct proto_config *src)
{
/* Just a shallow copy */
- proto_copy_rest(dest, src, sizeof(struct bgp_config));
}
diff --git a/proto/bgp/config.Y b/proto/bgp/config.Y
index 85b93a6b..614ef08c 100644
--- a/proto/bgp/config.Y
+++ b/proto/bgp/config.Y
@@ -112,12 +112,6 @@ bgp_proto:
| bgp_proto CAPABILITIES bool ';' { BGP_CFG->capabilities = $3; }
| bgp_proto ADVERTISE IPV4 bool ';' { BGP_CFG->advertise_ipv4 = $4; }
| 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 INTERPRET COMMUNITIES bool ';' { BGP_CFG->interpret_communities = $4; }
| bgp_proto SECONDARY bool ';' { BGP_CFG->secondary = $3; }
diff --git a/proto/ospf/config.Y b/proto/ospf/config.Y
index 881ec781..297774b5 100644
--- a/proto/ospf/config.Y
+++ b/proto/ospf/config.Y
@@ -68,6 +68,10 @@ ospf_proto_finish(void)
if (EMPTY_LIST(cf->area_list))
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 backbone = 0;
int nssa = 0;
@@ -84,7 +88,7 @@ ospf_proto_finish(void)
cf->abr = areano > 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)
{
@@ -145,14 +149,16 @@ ospf_variant:
| OSPF3 { $$ = 0; }
;
-ospf_proto_start: proto_start ospf_variant {
- this_proto = proto_config_new(&proto_ospf, $1);
- init_list(&OSPF_CFG->area_list);
- init_list(&OSPF_CFG->vlink_list);
- OSPF_CFG->tick = OSPF_DEFAULT_TICK;
- OSPF_CFG->ospf2 = $2;
- }
- ;
+ospf_proto_start: proto_start ospf_variant
+{
+ this_proto = proto_config_new(&proto_ospf, $1);
+ this_proto->net_type = $2 ? NET_IP4 : NET_IP6;
+
+ 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_start proto_name '{'
@@ -161,6 +167,7 @@ ospf_proto:
ospf_proto_item:
proto_item
+ | proto_channel
| RFC1583COMPAT bool { OSPF_CFG->rfc1583 = $2; }
| STUB ROUTER bool { OSPF_CFG->stub_router = $3; }
| ECMP bool { OSPF_CFG->ecmp = $2 ? OSPF_DEFAULT_ECMP_LIMIT : 0; }
diff --git a/proto/ospf/ospf.c b/proto/ospf/ospf.c
index 1c128794..d074600a 100644
--- a/proto/ospf/ospf.c
+++ b/proto/ospf/ospf.c
@@ -102,7 +102,7 @@
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 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_same(struct rte *new, struct rte *old);
static void ospf_disp(timer *timer);
@@ -297,15 +297,16 @@ ospf_dump(struct proto *P)
}
static struct proto *
-ospf_init(struct proto_config *c)
+ospf_init(struct proto_config *CF)
{
- struct ospf_config *oc = (struct ospf_config *) c;
- struct proto *P = proto_new(c, sizeof(struct ospf_proto));
+ struct ospf_config *cf = (struct ospf_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->rt_notify = ospf_rt_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->reload_routes = ospf_reload_routes;
P->make_tmp_attrs = ospf_make_tmp_attrs;
@@ -389,17 +390,16 @@ ospf_schedule_rtcalc(struct ospf_proto *p)
p->calcrt = 1;
}
-static int
-ospf_reload_routes(struct proto *P)
+static void
+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)
- OSPF_TRACE(D_EVENTS, "Scheduling routing table calculation with route reload");
+ if (p->calcrt == 2)
+ return;
+ OSPF_TRACE(D_EVENTS, "Scheduling routing table calculation with route reload");
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.
*/
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_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 *oa, *oax;
struct ospf_iface *ifa, *ifx;
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;
if (p->ospf2 != new->ospf2)
@@ -659,6 +659,9 @@ ospf_reconfigure(struct proto *P, struct proto_config *c)
if (old->abr != new->abr)
return 0;
+ if (!proto_configure_channel(P, &P->main_channel, proto_cf_main_channel(CF)))
+ return 0;
+
p->stub_router = new->stub_router;
p->merge_external = new->merge_external;
p->asbr = new->asbr;
@@ -1465,6 +1468,8 @@ struct protocol proto_ospf = {
.template = "ospf%d",
.attr_class = EAP_OSPF,
.preference = DEF_PREF_OSPF,
+ .channel_mask = NB_IP,
+ .proto_size = sizeof(struct ospf_proto),
.config_size = sizeof(struct ospf_config),
.init = ospf_init,
.dump = ospf_dump,
diff --git a/proto/ospf/rt.c b/proto/ospf/rt.c
index 21a3e300..0855f21f 100644
--- a/proto/ospf/rt.c
+++ b/proto/ospf/rt.c
@@ -1973,7 +1973,7 @@ again1:
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);
rte *e = rte_get_temp(a);
@@ -1985,7 +1985,6 @@ again1:
e->u.ospf.router_id = nf->old_rid = nf->n.rid;
e->pflags = 0;
e->net = ne;
- e->pref = p->p.preference;
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);
@@ -1998,7 +1997,7 @@ again1:
rta_free(nf->old_rta);
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);
}
diff --git a/proto/pipe/config.Y b/proto/pipe/config.Y
index 8daf2e7c..f51ee575 100644
--- a/proto/pipe/config.Y
+++ b/proto/pipe/config.Y
@@ -16,28 +16,25 @@ CF_DEFINES
CF_DECLS
-CF_KEYWORDS(PIPE, PEER, TABLE, MODE, OPAQUE, TRANSPARENT)
+CF_KEYWORDS(PIPE, PEER, TABLE)
CF_GRAMMAR
-CF_ADDTO(proto, pipe_proto '}')
+CF_ADDTO(proto, pipe_proto '}' { this_channel = NULL; } )
-pipe_proto_start: proto_start PIPE {
- this_proto = proto_config_new(&proto_pipe, $1);
- PIPE_CFG->mode = PIPE_TRANSPARENT;
- }
- ;
+pipe_proto_start: proto_start PIPE
+{
+ 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_start proto_name '{'
| pipe_proto proto_item ';'
- | pipe_proto PEER TABLE SYM ';' {
- if ($4->class != SYM_TABLE)
- 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; }
+ | pipe_proto channel_item ';'
+ | pipe_proto PEER TABLE rtable ';' { PIPE_CFG->peer = $4; }
;
CF_CODE
diff --git a/proto/pipe/pipe.c b/proto/pipe/pipe.c
index 42285880..57db3e8b 100644
--- a/proto/pipe/pipe.c
+++ b/proto/pipe/pipe.c
@@ -46,9 +46,8 @@
static void
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 announce_hook *ah = (src_table == P->table) ? p->peer_ahook : P->main_ahook;
- rtable *dst_table = ah->table;
+ struct pipe_proto *p = (void *) P;
+ struct channel *dst = (src_table == p->pri->table) ? p->sec : p->pri;
struct rte_src *src;
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)
return;
- if (dst_table->pipe_busy)
+ if (dst->table->pipe_busy)
{
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;
}
- nn = net_get(dst_table, n->n.addr);
+ nn = net_get(dst->table, n->n.addr);
if (new)
{
memcpy(&a, new->attrs, sizeof(rta));
- if (p->mode == PIPE_OPAQUE)
- {
- a.src = P->main_source;
- a.source = RTS_PIPE;
- }
-
a.aflags = 0;
a.eattrs = attrs;
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->pflags = 0;
- if (p->mode == PIPE_TRANSPARENT)
- {
- /* Copy protocol specific embedded attributes. */
- memcpy(&(e->u), &(new->u), sizeof(e->u));
- e->pref = new->pref;
- e->pflags = new->pflags;
- }
+ /* Copy protocol specific embedded attributes. */
+ memcpy(&(e->u), &(new->u), sizeof(e->u));
+ e->pref = new->pref;
+ e->pflags = new->pflags;
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;
- rte_update2(ah, nn, e, src);
+ rte_update2(dst, nn, e, src);
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)
return -1; /* Avoid local loops automatically */
+
return 0;
}
-static int
-pipe_reload_routes(struct proto *P)
+static void
+pipe_reload_routes(struct channel *C)
{
- struct pipe_proto *p = (struct pipe_proto *) P;
-
- /*
- * Because the pipe protocol feeds routes from both routing tables
- * 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);
+ struct pipe_proto *p = (void *) C->proto;
- proto_reset_limit(P->main_ahook->in_limit);
- proto_reset_limit(p->peer_ahook->in_limit);
-
- return 1;
+ /* Route reload on one channel is just refeed on the other */
+ channel_request_feeding((C == p->pri) ? p->sec : p->pri);
}
-static struct proto *
-pipe_init(struct proto_config *C)
-{
- struct pipe_config *c = (struct pipe_config *) C;
- struct proto *P = proto_new(C, sizeof(struct pipe_proto));
- struct pipe_proto *p = (struct pipe_proto *) P;
- 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->import_control = pipe_import_control;
- P->reload_routes = pipe_reload_routes;
-
- return P;
-}
-
-static int
-pipe_start(struct proto *P)
+static void
+pipe_postconfig(struct proto_config *CF)
{
- struct pipe_config *cf = (struct pipe_config *) P->cf;
- struct pipe_proto *p = (struct pipe_proto *) P;
+ struct pipe_config *cf = (void *) CF;
+ struct channel_config *cc = proto_cf_main_channel(CF);
- /* Lock both tables, unlock is handled in pipe_cleanup() */
- rt_lock_table(P->table);
- rt_lock_table(p->peer_table);
+ if (!cc->table)
+ cf_error("Primary routing table not specified");
- /* Going directly to PS_UP - prepare for feeding,
- connect the protocol to both routing tables */
+ if (!cf->peer)
+ cf_error("Secondary routing table not specified");
- 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);
+ if (cc->table == cf->peer)
+ cf_error("Primary table and peer table must be different");
- 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 (cc->table->addr_type != cf->peer->addr_type)
+ cf_error("Primary table and peer table must have the same type");
- if (p->mode == PIPE_OPAQUE)
- {
- P->main_source = rt_get_source(P, 0);
- rt_lock_source(P->main_source);
- }
+ if (cc->rx_limit.action)
+ cf_error("Pipe protocol does not support receive limits");
- return PS_UP;
+ if (cc->in_keep_filtered)
+ cf_error("Pipe protocol prohibits keeping filtered routes");
}
-static void
-pipe_cleanup(struct proto *P)
+static int
+pipe_configure_channels(struct pipe_proto *p, struct pipe_config *cf)
{
- 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);
+ 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 void
-pipe_postconfig(struct proto_config *C)
+static struct proto *
+pipe_init(struct proto_config *CF)
{
- struct pipe_config *c = (struct pipe_config *) C;
+ struct proto *P = proto_new(CF);
+ struct pipe_proto *p = (void *) P;
+ struct pipe_config *cf = (void *) CF;
- 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");
+ P->rt_notify = pipe_rt_notify;
+ P->import_control = pipe_import_control;
+ P->reload_routes = pipe_reload_routes;
- 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");
-}
+ pipe_configure_channels(p, cf);
-extern int proto_reconfig_type;
+ return P;
+}
static int
-pipe_reconfigure(struct proto *P, struct proto_config *new)
+pipe_reconfigure(struct proto *P, struct proto_config *CF)
{
- 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);
+ struct pipe_proto *p = (void *) P;
+ struct pipe_config *cf = (void *) CF;
- return 1;
+ return pipe_configure_channels(p, cf);
}
static void
pipe_copy_config(struct proto_config *dest, struct proto_config *src)
{
/* Just a shallow copy, not many items here */
- proto_copy_rest(dest, src, sizeof(struct pipe_config));
}
static void
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
pipe_show_stats(struct pipe_proto *p)
{
- struct proto_stats *s1 = &p->p.stats;
- struct proto_stats *s2 = &p->peer_stats;
+ struct proto_stats *s1 = &p->pri->stats;
+ struct proto_stats *s2 = &p->sec->stats;
/*
* 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
pipe_show_proto_info(struct proto *P)
{
- struct pipe_proto *p = (struct pipe_proto *) P;
- struct pipe_config *cf = (struct pipe_config *) P->cf;
+ struct pipe_proto *p = (void *) P;
- // cli_msg(-1006, " Table: %s", P->table->name);
- // cli_msg(-1006, " Peer table: %s", p->peer_table->name);
- cli_msg(-1006, " Preference: %d", P->preference);
- cli_msg(-1006, " Input filter: %s", filter_name(cf->c.in_filter));
- cli_msg(-1006, " Output filter: %s", filter_name(cf->c.out_filter));
+ cli_msg(-1006, " Channel %s", "main");
+ cli_msg(-1006, " Table: %s", p->pri->table->name);
+ cli_msg(-1006, " Peer table: %s", p->sec->table->name);
+ cli_msg(-1006, " Import filter: %s", filter_name(p->sec->out_filter));
+ cli_msg(-1006, " Export filter: %s", filter_name(p->pri->out_filter));
- proto_show_limit(cf->c.in_limit, "Import limit:");
- proto_show_limit(cf->c.out_limit, "Export limit:");
+ channel_show_limit(&p->pri->in_limit, "Import limit:");
+ channel_show_limit(&p->sec->in_limit, "Export limit:");
if (P->proto_state != PS_DOWN)
pipe_show_stats(p);
@@ -338,13 +273,10 @@ pipe_show_proto_info(struct proto *P)
struct protocol proto_pipe = {
.name = "Pipe",
.template = "pipe%d",
- .multitable = 1,
- .preference = DEF_PREF_PIPE,
+ .proto_size = sizeof(struct pipe_proto),
.config_size = sizeof(struct pipe_config),
.postconfig = pipe_postconfig,
.init = pipe_init,
- .start = pipe_start,
- .cleanup = pipe_cleanup,
.reconfigure = pipe_reconfigure,
.copy_config = pipe_copy_config,
.get_status = pipe_get_status,
diff --git a/proto/pipe/pipe.h b/proto/pipe/pipe.h
index 50b31698..038c6666 100644
--- a/proto/pipe/pipe.h
+++ b/proto/pipe/pipe.h
@@ -9,27 +9,15 @@
#ifndef _BIRD_PIPE_H_
#define _BIRD_PIPE_H_
-#define PIPE_OPAQUE 0
-#define PIPE_TRANSPARENT 1
-
struct pipe_config {
struct proto_config c;
struct rtable_config *peer; /* Table we're connected to */
- int mode; /* PIPE_OPAQUE or PIPE_TRANSPARENT */
};
struct pipe_proto {
struct proto p;
- struct rtable *peer_table;
- struct announce_hook *peer_ahook; /* Announce hook for direction peer->primary */
- struct proto_stats peer_stats; /* Statistics for the direction peer->primary */
- int mode; /* PIPE_OPAQUE or PIPE_TRANSPARENT */
+ struct channel *pri;
+ struct channel *sec;
};
-
-extern struct protocol proto_pipe;
-
-static inline int proto_is_pipe(struct proto *p)
-{ return p->proto == &proto_pipe; }
-
#endif
diff --git a/proto/radv/config.Y b/proto/radv/config.Y
index 5e655de4..7ba23205 100644
--- a/proto/radv/config.Y
+++ b/proto/radv/config.Y
@@ -41,6 +41,7 @@ CF_ADDTO(proto, radv_proto)
radv_proto_start: proto_start RADV
{
this_proto = proto_config_new(&proto_radv, $1);
+
init_list(&RADV_CFG->patt_list);
init_list(&RADV_CFG->pref_list);
init_list(&RADV_CFG->rdnss_list);
@@ -49,14 +50,12 @@ radv_proto_start: proto_start RADV
radv_proto_item:
proto_item
+ | proto_channel
| INTERFACE radv_iface
| 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); }
| DNSSL { init_list(&radv_dns_list); } radv_dnssl { add_tail_list(&RADV_CFG->dnssl_list, &radv_dns_list); }
- | TRIGGER net_any {
- RADV_CFG->trigger = $2;
- RADV_CFG->trigger_valid = 1;
- }
+ | TRIGGER net_ip6 { RADV_CFG->trigger = $2; }
;
radv_proto_opts:
diff --git a/proto/radv/radv.c b/proto/radv/radv.c
index 97713b95..f9c0940f 100644
--- a/proto/radv/radv.c
+++ b/proto/radv/radv.c
@@ -256,9 +256,16 @@ radv_ifa_notify(struct proto *p, unsigned flags, struct ifa *a)
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
@@ -301,22 +308,35 @@ radv_check_active(struct proto_radv *ra)
{
struct radv_config *cf = (struct radv_config *) (ra->p.cf);
- if (! cf->trigger_valid)
+ if (!radv_trigger_valid(cf))
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 *
-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->rt_notify = radv_rt_notify;
p->if_notify = radv_if_notify;
p->ifa_notify = radv_ifa_notify;
+
return p;
}
@@ -327,7 +347,7 @@ radv_start(struct proto *p)
struct radv_config *cf = (struct radv_config *) (p->cf);
init_list(&(ra->iface_list));
- ra->active = !cf->trigger_valid;
+ ra->active = !radv_trigger_valid(cf);
return PS_UP;
}
@@ -352,11 +372,11 @@ radv_shutdown(struct proto *p)
}
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 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
@@ -366,7 +386,10 @@ radv_reconfigure(struct proto *p, struct proto_config *c)
* 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);
struct iface *iface;
@@ -423,7 +446,10 @@ radv_get_status(struct proto *p, byte *buf)
struct protocol proto_radv = {
.name = "RAdv",
.template = "radv%d",
+ .channel_mask = NB_IP6,
+ .proto_size = sizeof(struct proto_radv),
.config_size = sizeof(struct radv_config),
+ .postconfig = radv_postconfig,
.init = radv_init,
.start = radv_start,
.shutdown = radv_shutdown,
diff --git a/proto/radv/radv.h b/proto/radv/radv.h
index 755009d4..f8aa421d 100644
--- a/proto/radv/radv.h
+++ b/proto/radv/radv.h
@@ -50,8 +50,7 @@ struct radv_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) */
- net_addr *trigger; /* Prefix of a trigger route, if defined */
- u8 trigger_valid; /* Whether a trigger route is defined */
+ net_addr trigger; /* Prefix of a trigger route, if defined */
};
struct radv_iface_config
diff --git a/proto/rip/config.Y b/proto/rip/config.Y
index d81c42d7..79e57741 100644
--- a/proto/rip/config.Y
+++ b/proto/rip/config.Y
@@ -52,17 +52,18 @@ rip_variant:
rip_proto_start: proto_start rip_variant
{
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->infinity = RIP_DEFAULT_INFINITY;
-
RIP_CFG->min_timeout_time = 60;
RIP_CFG->max_garbage_time = 60;
};
rip_proto_item:
proto_item
+ | proto_channel
| 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"); }
| INFINITY expr { RIP_CFG->infinity = $2; }
diff --git a/proto/rip/rip.c b/proto/rip/rip.c
index 7e5d6802..f020bc5b 100644
--- a/proto/rip/rip.c
+++ b/proto/rip/rip.c
@@ -143,7 +143,7 @@ rip_announce_rte(struct rip_proto *p, struct rip_entry *en)
if (rt)
{
/* 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 = {
.src = p->p.main_source,
@@ -212,7 +212,7 @@ rip_announce_rte(struct rip_proto *p, struct rip_entry *en)
else
{
/* 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);
}
}
@@ -1027,19 +1027,17 @@ rip_import_control(struct proto *P, struct rte **rt, struct ea_list **attrs, str
return 0;
}
-static int
-rip_reload_routes(struct proto *P)
+static void
+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)
- return 1;
+ return;
TRACE(D_EVENTS, "Scheduling route reload");
p->rt_reload = 1;
rip_kick_timer(p);
-
- return 1;
}
static struct ea_list *
@@ -1070,12 +1068,23 @@ rip_rte_same(struct rte *new, struct rte *old)
}
+static void
+rip_postconfig(struct proto_config *CF)
+{
+ // 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 *cfg)
+rip_init(struct proto_config *CF)
{
- struct proto *P = proto_new(cfg, sizeof(struct rip_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->if_notify = rip_if_notify;
P->rt_notify = rip_rt_notify;
P->neigh_notify = rip_neigh_notify;
@@ -1115,10 +1124,10 @@ rip_start(struct proto *P)
}
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_config *new = (void *) c;
+ struct rip_config *new = (void *) CF;
// struct rip_config *old = (void *) (P->cf);
if (new->rip2 != p->rip2)
@@ -1127,9 +1136,12 @@ rip_reconfigure(struct proto *P, struct proto_config *c)
if (new->infinity != p->infinity)
return 0;
+ if (!proto_configure_channel(P, &P->main_channel, proto_cf_main_channel(CF)))
+ return 0;
+
TRACE(D_EVENTS, "Reconfiguring");
- p->p.cf = c;
+ p->p.cf = CF;
p->ecmp = new->ecmp;
rip_reconfigure_ifaces(p, new);
@@ -1270,7 +1282,10 @@ struct protocol proto_rip = {
.template = "rip%d",
.attr_class = EAP_RIP,
.preference = DEF_PREF_RIP,
+ .channel_mask = NB_IP,
+ .proto_size = sizeof(struct rip_proto),
.config_size = sizeof(struct rip_config),
+ .postconfig = rip_postconfig,
.init = rip_init,
.dump = rip_dump,
.start = rip_start,
diff --git a/proto/static/config.Y b/proto/static/config.Y
index 9e634803..86359f0b 100644
--- a/proto/static/config.Y
+++ b/proto/static/config.Y
@@ -38,15 +38,16 @@ CF_GRAMMAR
CF_ADDTO(proto, static_proto '}')
-static_proto_start: proto_start STATIC {
- this_proto = proto_config_new(&proto_static, $1);
- static_init_config((struct static_config *) this_proto);
- }
- ;
+static_proto_start: proto_start STATIC
+{
+ this_proto = proto_config_new(&proto_static, $1);
+ static_init_config(STATIC_CFG);
+};
static_proto:
static_proto_start proto_name '{'
| 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 IGP TABLE rtable ';' { STATIC_CFG->igp_table = $4; }
| static_proto stat_route stat_route_opt_list ';' { static_route_finish(); }
diff --git a/proto/static/static.c b/proto/static/static.c
index 809c29fb..6239fccb 100644
--- a/proto/static/static.c
+++ b/proto/static/static.c
@@ -54,7 +54,7 @@ static inline rtable *
p_igp_table(struct proto *p)
{
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
@@ -108,11 +108,11 @@ static_install(struct proto *p, struct static_route *r, struct iface *ifa)
}
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 */
- n = net_get(p->table, r->net);
+ n = net_get(p->main_channel->table, r->net);
e = rte_get_temp(&a);
e->net = n;
e->pflags = 0;
@@ -136,7 +136,7 @@ static_remove(struct proto *p, struct static_route *r)
return;
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);
r->installed = 0;
}
@@ -309,6 +309,17 @@ static_shutdown(struct proto *p)
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;
}
@@ -450,16 +461,40 @@ static_init_config(struct static_config *c)
init_list(&c->other_routes);
}
+static void
+static_postconfig(struct proto_config *CF)
+{
+ struct static_config *cf = (void *) CF;
+ struct static_route *r;
+
+ if (EMPTY_LIST(CF->channels))
+ cf_error("Channel not specified");
+
+
+ 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 *c)
+static_init(struct proto_config *CF)
{
- struct proto *p = proto_new(c, sizeof(struct proto));
+ struct proto *P = proto_new(CF);
+ // struct static_proto *p = (void *) P;
+ // struct static_config *cf = (void *) CF;
- p->neigh_notify = static_neigh_notify;
- p->if_notify = static_if_notify;
- p->rte_mergable = static_rte_mergable;
+ P->main_channel = proto_add_channel(P, proto_cf_main_channel(CF));
- return p;
+ P->neigh_notify = static_neigh_notify;
+ P->if_notify = static_if_notify;
+ P->rte_mergable = static_rte_mergable;
+
+ return P;
}
static inline int
@@ -543,15 +578,18 @@ cf_igp_table(struct static_config *cf)
}
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 *n = (void *) new;
+ struct static_config *n = (void *) CF;
struct static_route *r;
if (cf_igp_table(o) != cf_igp_table(n))
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 */
WALK_LIST(r, o->iface_routes)
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 *s = (struct static_config *) src;
- /* Shallow copy of everything */
- proto_copy_rest(dest, src, sizeof(struct static_config));
-
/* Copy route lists */
static_copy_routes(&d->iface_routes, &s->iface_routes);
static_copy_routes(&d->other_routes, &s->other_routes);
}
-
struct protocol proto_static = {
.name = "Static",
.template = "static%d",
.preference = DEF_PREF_STATIC,
+ .channel_mask = NB_ANY,
+ .proto_size = sizeof(struct proto),
.config_size = sizeof(struct static_config),
+ .postconfig = static_postconfig,
.init = static_init,
.dump = static_dump,
.start = static_start,