summaryrefslogtreecommitdiffstats
path: root/proto
diff options
context:
space:
mode:
authorOndrej Zajicek <santiago@crfreenet.org>2011-11-07 00:31:23 +0100
committerOndrej Zajicek <santiago@crfreenet.org>2011-11-07 00:31:23 +0100
commita7f23f581f5e3efe92ec97dfca7d01c66f31ab04 (patch)
tree3a8f7cffb7abce83b7bce8be87d21be8a2fbff72 /proto
parent74add5df17c386bd109ebea7b1dac04d1651ae51 (diff)
downloadbird-a7f23f581f5e3efe92ec97dfca7d01c66f31ab04.tar
bird-a7f23f581f5e3efe92ec97dfca7d01c66f31ab04.zip
Implements protocol templates.
Based on the patch from Alexander V. Chernikov. Extended to support almost all protocols. Uses 'protocol bgp NAME from TEMPLATE { ... }' syntax.
Diffstat (limited to 'proto')
-rw-r--r--proto/bgp/bgp.c122
-rw-r--r--proto/bgp/bgp.h2
-rw-r--r--proto/bgp/config.Y4
-rw-r--r--proto/ospf/config.Y2
-rw-r--r--proto/ospf/ospf.h4
-rw-r--r--proto/pipe/config.Y2
-rw-r--r--proto/pipe/pipe.c24
-rw-r--r--proto/radv/radv.c16
-rw-r--r--proto/radv/radv.h8
-rw-r--r--proto/rip/config.Y2
-rw-r--r--proto/rip/rip.c14
-rw-r--r--proto/static/config.Y2
-rw-r--r--proto/static/static.c53
13 files changed, 179 insertions, 76 deletions
diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c
index 4e4ca9f..675342d 100644
--- a/proto/bgp/bgp.c
+++ b/proto/bgp/bgp.c
@@ -919,6 +919,73 @@ bgp_init(struct proto_config *C)
return P;
}
+
+void
+bgp_check_config(struct bgp_config *c)
+{
+ int internal = (c->local_as == c->remote_as);
+
+ /* Do not check templates at all */
+ if (c->c.class == SYM_TEMPLATE)
+ return;
+
+ if (!c->local_as)
+ cf_error("Local AS number must be set");
+
+ if (!c->remote_as)
+ cf_error("Neighbor must be configured");
+
+ if (!(c->capabilities && c->enable_as4) && (c->remote_as > 0xFFFF))
+ cf_error("Neighbor AS number out of range (AS4 not available)");
+
+ if (!internal && c->rr_client)
+ cf_error("Only internal neighbor can be RR client");
+
+ if (internal && c->rs_client)
+ cf_error("Only external neighbor can be RS client");
+
+ if (c->multihop && (c->gw_mode == GW_DIRECT))
+ cf_error("Multihop BGP cannot use direct gateway mode");
+
+ /* Different default based on rs_client */
+ if (!c->missing_lladdr)
+ c->missing_lladdr = c->rs_client ? MLL_IGNORE : MLL_SELF;
+
+ /* Different default for gw_mode */
+ if (!c->gw_mode)
+ c->gw_mode = (c->multihop || internal) ? GW_RECURSIVE : GW_DIRECT;
+}
+
+static int
+bgp_reconfigure(struct proto *P, struct proto_config *C)
+{
+ struct bgp_config *new = (struct bgp_config *) C;
+ struct bgp_proto *p = (struct bgp_proto *) P;
+ struct bgp_config *old = p->cf;
+
+ int same = !memcmp(((byte *) old) + sizeof(struct proto_config),
+ ((byte *) new) + sizeof(struct proto_config),
+ // password item is last and must be checked separately
+ OFFSETOF(struct bgp_config, password) - sizeof(struct proto_config))
+ && ((!old->password && !new->password)
+ || (old->password && new->password && !strcmp(old->password, new->password)))
+ && (get_igp_table(old) == get_igp_table(new));
+
+ /* We should update our copy of configuration ptr as old configuration will be freed */
+ if (same)
+ p->cf = new;
+
+ return same;
+}
+
+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));
+}
+
+
/**
* bgp_error - report a protocol error
* @c: connection
@@ -983,38 +1050,6 @@ bgp_store_error(struct bgp_proto *p, struct bgp_conn *c, u8 class, u32 code)
p->last_error_code = code;
}
-void
-bgp_check(struct bgp_config *c)
-{
- int internal = (c->local_as == c->remote_as);
-
- if (!c->local_as)
- cf_error("Local AS number must be set");
-
- if (!c->remote_as)
- cf_error("Neighbor must be configured");
-
- if (!(c->capabilities && c->enable_as4) && (c->remote_as > 0xFFFF))
- cf_error("Neighbor AS number out of range (AS4 not available)");
-
- if (!internal && c->rr_client)
- cf_error("Only internal neighbor can be RR client");
-
- if (internal && c->rs_client)
- cf_error("Only external neighbor can be RS client");
-
- if (c->multihop && (c->gw_mode == GW_DIRECT))
- cf_error("Multihop BGP cannot use direct gateway mode");
-
- /* Different default based on rs_client */
- if (!c->missing_lladdr)
- c->missing_lladdr = c->rs_client ? MLL_IGNORE : MLL_SELF;
-
- /* Different default for gw_mode */
- if (!c->gw_mode)
- c->gw_mode = (c->multihop || internal) ? GW_RECURSIVE : GW_DIRECT;
-}
-
static char *bgp_state_names[] = { "Idle", "Connect", "Active", "OpenSent", "OpenConfirm", "Established", "Close" };
static char *bgp_err_classes[] = { "", "Error: ", "Socket: ", "Received: ", "BGP Error: ", "Automatic shutdown: ", ""};
static char *bgp_misc_errors[] = { "", "Neighbor lost", "Invalid next hop", "Kernel MD5 auth failed", "No listening socket" };
@@ -1124,28 +1159,6 @@ bgp_show_proto_info(struct proto *P)
}
}
-static int
-bgp_reconfigure(struct proto *P, struct proto_config *C)
-{
- struct bgp_config *new = (struct bgp_config *) C;
- struct bgp_proto *p = (struct bgp_proto *) P;
- struct bgp_config *old = p->cf;
-
- int same = !memcmp(((byte *) old) + sizeof(struct proto_config),
- ((byte *) new) + sizeof(struct proto_config),
- // password item is last and must be checked separately
- OFFSETOF(struct bgp_config, password) - sizeof(struct proto_config))
- && ((!old->password && !new->password)
- || (old->password && new->password && !strcmp(old->password, new->password)))
- && (get_igp_table(old) == get_igp_table(new));
-
- /* We should update our copy of configuration ptr as old configuration will be freed */
- if (same)
- p->cf = new;
-
- return same;
-}
-
struct protocol proto_bgp = {
name: "BGP",
template: "bgp%d",
@@ -1155,6 +1168,7 @@ struct protocol proto_bgp = {
shutdown: bgp_shutdown,
cleanup: bgp_cleanup,
reconfigure: bgp_reconfigure,
+ copy_config: bgp_copy_config,
get_status: bgp_get_status,
get_attr: bgp_get_attr,
get_route_info: bgp_get_route_info,
diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h
index 16e8ea8..437ba33 100644
--- a/proto/bgp/bgp.h
+++ b/proto/bgp/bgp.h
@@ -141,7 +141,7 @@ extern struct linpool *bgp_linpool;
void bgp_start_timer(struct timer *t, int value);
-void bgp_check(struct bgp_config *c);
+void bgp_check_config(struct bgp_config *c);
void bgp_error(struct bgp_conn *c, unsigned code, unsigned subcode, byte *data, int len);
void bgp_close_conn(struct bgp_conn *c);
void bgp_update_startup_delay(struct bgp_proto *p);
diff --git a/proto/bgp/config.Y b/proto/bgp/config.Y
index 19d757a..03c233d 100644
--- a/proto/bgp/config.Y
+++ b/proto/bgp/config.Y
@@ -29,10 +29,10 @@ CF_KEYWORDS(BGP, LOCAL, NEIGHBOR, AS, HOLD, TIME, CONNECT, RETRY,
CF_GRAMMAR
-CF_ADDTO(proto, bgp_proto '}' { bgp_check(BGP_CFG); } )
+CF_ADDTO(proto, bgp_proto '}' { bgp_check_config(BGP_CFG); } )
bgp_proto_start: proto_start BGP {
- this_proto = proto_config_new(&proto_bgp, sizeof(struct bgp_config));
+ this_proto = proto_config_new(&proto_bgp, sizeof(struct bgp_config), $1);
this_proto->preference = DEF_PREF_BGP;
BGP_CFG->hold_time = 240;
BGP_CFG->connect_retry_time = 120;
diff --git a/proto/ospf/config.Y b/proto/ospf/config.Y
index ec7da8e..4ada41e 100644
--- a/proto/ospf/config.Y
+++ b/proto/ospf/config.Y
@@ -128,7 +128,7 @@ CF_GRAMMAR
CF_ADDTO(proto, ospf_proto '}' { ospf_proto_finish(); } )
ospf_proto_start: proto_start OSPF {
- this_proto = proto_config_new(&proto_ospf, sizeof(struct ospf_config));
+ this_proto = proto_config_new(&proto_ospf, sizeof(struct ospf_config), $1);
this_proto->preference = DEF_PREF_OSPF;
init_list(&OSPF_CFG->area_list);
init_list(&OSPF_CFG->vlink_list);
diff --git a/proto/ospf/ospf.h b/proto/ospf/ospf.h
index 2e99b0f..60a34fb 100644
--- a/proto/ospf/ospf.h
+++ b/proto/ospf/ospf.h
@@ -85,8 +85,8 @@ struct ospf_config
byte rfc1583;
byte abr;
int ecmp;
- list area_list;
- list vlink_list;
+ list area_list; /* list of struct ospf_area_config */
+ list vlink_list; /* list of struct ospf_iface_patt */
};
struct nbma_node
diff --git a/proto/pipe/config.Y b/proto/pipe/config.Y
index e1c981b..4478afe 100644
--- a/proto/pipe/config.Y
+++ b/proto/pipe/config.Y
@@ -23,7 +23,7 @@ CF_GRAMMAR
CF_ADDTO(proto, pipe_proto '}')
pipe_proto_start: proto_start PIPE {
- this_proto = proto_config_new(&proto_pipe, sizeof(struct pipe_config));
+ this_proto = proto_config_new(&proto_pipe, sizeof(struct pipe_config), $1);
this_proto->preference = DEF_PREF_PIPE;
PIPE_CFG->mode = PIPE_TRANSPARENT;
}
diff --git a/proto/pipe/pipe.c b/proto/pipe/pipe.c
index e557097..420c5a9 100644
--- a/proto/pipe/pipe.c
+++ b/proto/pipe/pipe.c
@@ -165,14 +165,6 @@ pipe_postconfig(struct proto_config *C)
cf_error("Primary table and peer table must be different");
}
-static void
-pipe_get_status(struct proto *P, byte *buf)
-{
- struct pipe_proto *p = (struct pipe_proto *) P;
-
- bsprintf(buf, "%c> %s", (p->mode == PIPE_OPAQUE) ? '-' : '=', p->peer->name);
-}
-
static int
pipe_reconfigure(struct proto *P, struct proto_config *new)
{
@@ -186,6 +178,21 @@ pipe_reconfigure(struct proto *P, struct proto_config *new)
return 1;
}
+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;
+
+ bsprintf(buf, "%c> %s", (p->mode == PIPE_OPAQUE) ? '-' : '=', p->peer->name);
+}
+
struct protocol proto_pipe = {
name: "Pipe",
@@ -195,5 +202,6 @@ struct protocol proto_pipe = {
start: pipe_start,
cleanup: pipe_cleanup,
reconfigure: pipe_reconfigure,
+ copy_config: pipe_copy_config,
get_status: pipe_get_status,
};
diff --git a/proto/radv/radv.c b/proto/radv/radv.c
index 01cb689..42d4bff 100644
--- a/proto/radv/radv.c
+++ b/proto/radv/radv.c
@@ -318,6 +318,19 @@ radv_reconfigure(struct proto *p, struct proto_config *c)
return 1;
}
+static void
+radv_copy_config(struct proto_config *dest, struct proto_config *src)
+{
+ struct radv_config *d = (struct radv_config *) dest;
+ struct radv_config *s = (struct radv_config *) src;
+
+ /* We clean up patt_list, ifaces are non-sharable */
+ init_list(&d->patt_list);
+
+ /* We copy pref_list, shallow copy suffices */
+ cfg_copy_list(&d->iface_list, &s->iface_list, sizeof(struct iface_patt));
+}
+
struct protocol proto_radv = {
.name = "RAdv",
@@ -325,5 +338,6 @@ struct protocol proto_radv = {
.init = radv_init,
.start = radv_start,
.shutdown = radv_shutdown,
- .reconfigure = radv_reconfigure
+ .reconfigure = radv_reconfigure,
+ .copy_config = radv_copy_config
};
diff --git a/proto/radv/radv.h b/proto/radv/radv.h
index fe121f2..12bfe42 100644
--- a/proto/radv/radv.h
+++ b/proto/radv/radv.h
@@ -46,14 +46,14 @@
struct radv_config
{
struct proto_config c;
- list patt_list; /* List of iface configs */
- list pref_list; /* Global list of prefix configs */
+ list patt_list; /* List of iface configs (struct radv_iface_config) */
+ list pref_list; /* Global list of prefix configs (struct radv_prefix_config) */
};
struct radv_iface_config
{
struct iface_patt i;
- list pref_list; /* Local list of prefix configs */
+ list pref_list; /* Local list of prefix configs (struct radv_prefix_config) */
u32 min_ra_int; /* Standard options from RFC 4261 */
u32 max_ra_int;
@@ -64,7 +64,7 @@ struct radv_iface_config
u32 link_mtu;
u32 reachable_time;
u32 retrans_timer;
- u32 current_hop_limit;
+ u32 current_hop_limit;
u32 default_lifetime;
};
diff --git a/proto/rip/config.Y b/proto/rip/config.Y
index 2df0c5c..cd4f30e 100644
--- a/proto/rip/config.Y
+++ b/proto/rip/config.Y
@@ -37,7 +37,7 @@ CF_GRAMMAR
CF_ADDTO(proto, rip_cfg '}' { RIP_CFG->passwords = get_passwords(); } )
rip_cfg_start: proto_start RIP {
- this_proto = proto_config_new(&proto_rip, sizeof(struct rip_proto_config));
+ this_proto = proto_config_new(&proto_rip, sizeof(struct rip_proto_config), $1);
rip_init_config(RIP_CFG);
}
;
diff --git a/proto/rip/rip.c b/proto/rip/rip.c
index 1266380..543aa30 100644
--- a/proto/rip/rip.c
+++ b/proto/rip/rip.c
@@ -1015,6 +1015,19 @@ rip_reconfigure(struct proto *p, struct proto_config *c)
sizeof(struct rip_proto_config) - generic);
}
+static void
+rip_copy_config(struct proto_config *dest, struct proto_config *src)
+{
+ /* Shallow copy of everything */
+ proto_copy_rest(dest, src, sizeof(struct rip_proto_config));
+
+ /* We clean up iface_list, ifaces are non-sharable */
+ init_list(&((struct rip_proto_config *) dest)->iface_list);
+
+ /* Copy of passwords is OK, it just will be replaced in dest when used */
+}
+
+
struct protocol proto_rip = {
name: "RIP",
template: "rip%d",
@@ -1026,4 +1039,5 @@ struct protocol proto_rip = {
dump: rip_dump,
start: rip_start,
reconfigure: rip_reconfigure,
+ copy_config: rip_copy_config
};
diff --git a/proto/static/config.Y b/proto/static/config.Y
index 77d2419..621fdf9 100644
--- a/proto/static/config.Y
+++ b/proto/static/config.Y
@@ -26,7 +26,7 @@ CF_GRAMMAR
CF_ADDTO(proto, static_proto '}')
static_proto_start: proto_start STATIC {
- this_proto = proto_config_new(&proto_static, sizeof(struct static_config));
+ this_proto = proto_config_new(&proto_static, sizeof(struct static_config), $1);
static_init_config((struct static_config *) this_proto);
}
;
diff --git a/proto/static/static.c b/proto/static/static.c
index 2f33d81..e5b293c 100644
--- a/proto/static/static.c
+++ b/proto/static/static.c
@@ -470,6 +470,58 @@ static_reconfigure(struct proto *p, struct proto_config *new)
return 1;
}
+static void
+static_copy_routes(list *dlst, list *slst)
+{
+ struct static_route *dr, *sr;
+
+ init_list(dlst);
+ WALK_LIST(sr, *slst)
+ {
+ /* copy one route */
+ dr = cfg_alloc(sizeof(struct static_route));
+ memcpy(dr, sr, sizeof(struct static_route));
+
+ /* This fn is supposed to be called on fresh src routes, which have 'live'
+ fields (like .chain, .neigh or .installed) zero, so no need to zero them */
+
+ /* We need to copy multipath chain, because there are backptrs in 'if_name' */
+ if (dr->dest == RTD_MULTIPATH)
+ {
+ struct static_route *md, *ms, **mp_last;
+
+ mp_last = &(dr->mp_next);
+ for (ms = sr->mp_next; ms; ms = ms->mp_next)
+ {
+ md = cfg_alloc(sizeof(struct static_route));
+ memcpy(md, ms, sizeof(struct static_route));
+ md->if_name = (void *) dr; /* really */
+
+ *mp_last = md;
+ mp_last = &(md->mp_next);
+ }
+ *mp_last = NULL;
+ }
+
+ add_tail(dlst, (node *) dr);
+ }
+}
+
+static void
+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",
@@ -479,6 +531,7 @@ struct protocol proto_static = {
shutdown: static_shutdown,
cleanup: static_cleanup,
reconfigure: static_reconfigure,
+ copy_config: static_copy_config
};
static void