From a7f23f581f5e3efe92ec97dfca7d01c66f31ab04 Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Mon, 7 Nov 2011 00:31:23 +0100 Subject: Implements protocol templates. Based on the patch from Alexander V. Chernikov. Extended to support almost all protocols. Uses 'protocol bgp NAME from TEMPLATE { ... }' syntax. --- proto/bgp/bgp.c | 122 ++++++++++++++++++++++++++++---------------------- proto/bgp/bgp.h | 2 +- proto/bgp/config.Y | 4 +- proto/ospf/config.Y | 2 +- proto/ospf/ospf.h | 4 +- proto/pipe/config.Y | 2 +- proto/pipe/pipe.c | 24 ++++++---- proto/radv/radv.c | 16 ++++++- proto/radv/radv.h | 8 ++-- proto/rip/config.Y | 2 +- proto/rip/rip.c | 14 ++++++ proto/static/config.Y | 2 +- proto/static/static.c | 53 ++++++++++++++++++++++ 13 files changed, 179 insertions(+), 76 deletions(-) (limited to 'proto') 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 -- cgit v1.2.3