New version.
Changelog:
* Split nest API and bgp implementation
* Simplify new nest code a bit
* Fix crash on CLI lookups (forgot to fill in sym->def)
* Remove protocols on dynamic templates renaming
* Permit deleting dynamic instances via removal of disabled protos on
reconfigure
* Do not create new dynamic protocols on shutdown
* Permit using table names (%T) in templates
* Allow to inherit allow list from common templates (handy in link-local setups)
12.02.2015, 03:48, "Alexander V. Chernikov" <[email protected]>:
> I'm sorry, previous posting was in html, duplicating as plain-text
>
> I'd like to share some (beta-quality) patches permitting to create BGP
> protocol instances dynamically, based on templates.
> Main purpose is to get feedback and make them good enough to be integrated
> into main tree.
>
> Similar feature was implemented by major vendors yeas ago.
> Juniper:
> http://www.juniper.net/techpubs/en_US/junos11.4/topics/usage-guidelines/routing-configuring-bgp-groups-and-peers.html
> Cisco IOS:
> http://www.cisco.com/c/en/us/td/docs/ios/12_2sr/12_2srb/feature/guide/tbgp_c/brbpeer.html#wp1128937
>
> Typically it is used in peering setups.
>
> Patches still have some rough edges (see below) but should work^Wnot make
> bird crash every 5 minutes.
>
> Example setup:
>
> # Set up template with ALL info except and IP address
> # In this case we don't have any option to specify interface, so it is
> specified in
> # neighbor part
> template bgp bgg {
> debug all;
> local as 4444;
> neighbor fe80::1%em0 as 4443;
> import all;
> export all;
> };
>
> # Set up dynamic template with ranges and neighbor mask
> # Accepted format (%) values:
> # 1..4 - octets in IPv4 address
> # 1..8 - hex groups in IPv6 address
> # I - full address
> # format values can be specified more than once in format string
> # e.g. "b_x_%4_%I_%4"
> dynamic template bgp bgp_int from bgg {
> dynamic template name "b_s%4-%8-%8";
> dynamic allow fe80::f000/112, fe80::f00/116;
> };
>
> # You need to have at least one "normal" bgp peer to get listen socket opened
> # That's all
>
> # Example from working system:
> # using several { dynamic template name "b_Vrf1_s%8"; dynamic allow
> fe80::/64; }
> # templates
>
> bird> show protocols
> name proto table state since info
> direct1 Direct master up 22:06:05
> kernel1 Kernel master up 22:06:05
> device1 Device master up 22:06:05
> ospf3 OSPF master up 22:06:05 Running
> ..
> b_Vrf2_dc1_c1 BGP Vrf2 up 22:06:06 Established
> b_Vrf1_se48 BGP Vrf1 up 22:06:05 Established
> b_Vrf1_se10 BGP Vrf1 up 22:06:06 Established
> b_Vrf1_se45 BGP Vrf1 up 22:06:06 Established
> b_Vrf1_se60 BGP Vrf1 up 22:06:07 Established
> b_Vrf2_se91 BGP Vrf2 up 22:06:08 Established
> ..
>
> Comments on individual patches:
> 0001 is basic LPM for the f_trie and is part of aggregator patch
> 0002 decouples get-proto-from-address function from incoming connection
> handling. This makes hacking here much simpler (for example, implementing IP
> hash lookup)
> 0003 just moves SYM_MAX_LEN definition to header
> 0004 moves sizeof(XXX_proto) info inside protocol structure permitting anyone
> to call proto_config_init() without knowing details
> 0005 tries to isolate/limit global new_config/cfg_mem variables usage to
> absolute minimum. Despite the fact that actual BGP patch does not require
> much more than config_start_edit() / config_stop_edit() implementation, I
> (after hours of debugging cores) decided to make things more transparent here.
> 0006 is the actual patch.
> Basically, it
> * adds SYM_TEMPLATE class
> * adds dyn_parent proto_config field to specify parent template
> * adds condition-check and copy-dynamic protocol callbacks
> * adds runtime config/protocol creation functions to nest
> * adds bgp-specific structure to struct config allocated on demand
>
> Rough edges:
> * non-optimized case for IPv6 LL prefixes
> * non-optimized peer lookup for existing sessions
> * dynamic expire not implemented (next version)
> * no docs (next version)
> * some bugs, definitelyFrom ddbd97b2ea919ddfb49015fc6044daa960873138 Mon Sep 17 00:00:00 2001
From: "Alexander V. Chernikov" <[email protected]>
Date: Sat, 24 Jan 2015 21:10:01 +0300
Subject: [PATCH 1/8] Add LPM support for trie.
---
filter/config.Y | 2 +-
filter/filter.h | 7 +++-
filter/trie.c | 115 +++++++++++++++++++++++++++++++++++++++++++++++++++-----
nest/rt-table.c | 4 +-
4 files changed, 113 insertions(+), 15 deletions(-)
diff --git a/filter/config.Y b/filter/config.Y
index e50e75c..7eb2c0a 100644
--- a/filter/config.Y
+++ b/filter/config.Y
@@ -592,7 +592,7 @@ fprefix:
;
fprefix_set:
- fprefix { $$ = f_new_trie(cfg_mem); trie_add_fprefix($$, &($1.val.px)); }
+ fprefix { $$ = f_new_trie(cfg_mem, sizeof(struct f_trie_node)); trie_add_fprefix($$, &($1.val.px)); }
| fprefix_set ',' fprefix { $$ = $1; trie_add_fprefix($$, &($3.val.px)); }
;
diff --git a/filter/filter.h b/filter/filter.h
index 3a6b66d..522af9f 100644
--- a/filter/filter.h
+++ b/filter/filter.h
@@ -80,11 +80,13 @@ struct f_tree *find_tree(struct f_tree *t, struct f_val val);
int same_tree(struct f_tree *t1, struct f_tree *t2);
void tree_format(struct f_tree *t, buffer *buf);
-struct f_trie *f_new_trie(linpool *lp);
-void trie_add_prefix(struct f_trie *t, ip_addr px, int plen, int l, int h);
+struct f_trie *f_new_trie(linpool *lp, size_t node_size);
+void *trie_add_prefix(struct f_trie *t, ip_addr px, int plen, int l, int h);
int trie_match_prefix(struct f_trie *t, ip_addr px, int plen);
+void *trie_match_longest_prefix(struct f_trie *t, ip_addr px, int plen);
int trie_same(struct f_trie *t1, struct f_trie *t2);
void trie_format(struct f_trie *t, buffer *buf);
+void trie_walk(struct f_trie *t, void *func, void *data);
void fprefix_get_bounds(struct f_prefix *px, int *l, int *h);
@@ -204,6 +206,7 @@ struct f_trie
{
linpool *lp;
int zero;
+ int node_size;
struct f_trie_node root;
};
diff --git a/filter/trie.c b/filter/trie.c
index 217d72c..9851877 100644
--- a/filter/trie.c
+++ b/filter/trie.c
@@ -75,23 +75,24 @@
#include "filter/filter.h"
/**
- * f_new_trie
- *
- * Allocates and returns a new empty trie.
+ * f_new_trie - Allocates and returns a new empty trie.
+ * @lp: linear pool to allocate items from
+ * @node_size: element size to allocate
*/
struct f_trie *
-f_new_trie(linpool *lp)
+f_new_trie(linpool *lp, size_t node_size)
{
struct f_trie * ret;
- ret = lp_allocz(lp, sizeof(struct f_trie));
+ ret = lp_allocz(lp, sizeof(struct f_trie) + node_size - sizeof(struct f_trie_node));
ret->lp = lp;
+ ret->node_size = node_size;
return ret;
}
static inline struct f_trie_node *
new_node(struct f_trie *t, int plen, ip_addr paddr, ip_addr pmask, ip_addr amask)
{
- struct f_trie_node *n = lp_allocz(t->lp, sizeof(struct f_trie_node));
+ struct f_trie_node *n = lp_allocz(t->lp, t->node_size);
n->plen = plen;
n->addr = paddr;
n->mask = pmask;
@@ -116,9 +117,13 @@ attach_node(struct f_trie_node *parent, struct f_trie_node *child)
* Adds prefix (prefix pattern) @px/@plen to trie @t. @l and @h are lower
* and upper bounds on accepted prefix lengths, both inclusive.
* 0 <= l, h <= 32 (128 for IPv6).
+ *
+ * Returns pointer to allocated node. Function can return pointer to
+ * existing node if @px and @plen are the same. If px/plen == 0/0 (or ::/0)
+ * pointer to root node is returned
*/
-void
+void *
trie_add_prefix(struct f_trie *t, ip_addr px, int plen, int l, int h)
{
if (l == 0)
@@ -156,7 +161,7 @@ trie_add_prefix(struct f_trie *t, ip_addr px, int plen, int l, int h)
attach_node(o, b);
attach_node(b, n);
attach_node(b, a);
- return;
+ return a;
}
if (plen < n->plen)
@@ -166,14 +171,14 @@ trie_add_prefix(struct f_trie *t, ip_addr px, int plen, int l, int h)
struct f_trie_node *a = new_node(t, plen, paddr, pmask, amask);
attach_node(o, a);
attach_node(a, n);
- return;
+ return a;
}
if (plen == n->plen)
{
/* We already found added node in trie. Just update accept mask */
n->accept = ipa_or(n->accept, amask);
- return;
+ return n;
}
/* Update accept mask part M2 and go deeper */
@@ -187,6 +192,8 @@ trie_add_prefix(struct f_trie *t, ip_addr px, int plen, int l, int h)
/* We add new tail node 'a' after node 'o' */
struct f_trie_node *a = new_node(t, plen, paddr, pmask, amask);
attach_node(o, a);
+
+ return a;
}
/**
@@ -234,6 +241,94 @@ trie_match_prefix(struct f_trie *t, ip_addr px, int plen)
return 0;
}
+#define NODE_IS_BRANCHING(x) (*((u32 *)(((struct f_trie_node *)(x)) + 1)) == 0)
+/**
+ * trie_match_longest_prefix - find longest prefix match
+ * @t: trie
+ * @px: prefix address
+ * @plen: prefix length
+ *
+ * Tries to find a matching prefix pattern in the trie such that
+ * prefix @px/@plen matches that prefix pattern. Returns prefix pointer
+ * or NULL.
+ */
+void *
+trie_match_longest_prefix(struct f_trie *t, ip_addr px, int plen)
+{
+ ip_addr pmask = ipa_mkmask(plen);
+ ip_addr paddr = ipa_and(px, pmask);
+ ip_addr cmask;
+ struct f_trie_node *n = &t->root, *parent = NULL;
+
+ /* Return root node for 0/0 or :: */
+ if ((plen == 0) && (t->zero))
+ return n;
+
+ /* Skip root node since it is cath-all node */
+ n = n->c[(ipa_getbit(paddr, 0)) ? 1 : 0];
+
+ while (n)
+ {
+ cmask = ipa_and(n->mask, pmask);
+
+ /* We are out of path */
+ if (ipa_compare(ipa_and(paddr, cmask), ipa_and(n->addr, cmask)))
+ break;
+
+ /* Mask is too specific */
+ if (n->plen > plen)
+ break;
+
+ /* Do not save pointer to branching nodes */
+ if (!NODE_IS_BRANCHING(n))
+ parent = n;
+
+ /* Choose children */
+ n = n->c[(ipa_getbit(paddr, n->plen)) ? 1 : 0];
+ }
+
+ /*
+ * parent is either
+ * 1) NULL (if the first non-null node does not exist oris out of path)
+ * or
+ * 2) points to the last entry that match
+ *
+ * In former case we check if catch-all prefix really exists and return
+ * either pointer to root node or NULL. In latter case we simply return parent.
+ */
+
+ return parent ? parent : (t->zero ? &t->root : NULL);
+}
+
+static void
+trie_walk_call(struct f_trie_node *n, void *func, void *data)
+{
+ void (*f)(struct f_trie_node *, void *) = func;
+
+ if (n)
+ f(n, data);
+
+ if (n->c[0])
+ trie_walk_call(n->c[0], func, data);
+
+ if (n->c[1])
+ trie_walk_call(n->c[1], func, data);
+}
+
+void
+trie_walk(struct f_trie *t, void *func, void *data)
+{
+ void (*f)(struct f_trie_node *, void *) = func;
+
+ if (t->zero)
+ f(&t->root, data);
+
+ if (t->root.c[0])
+ trie_walk_call(t->root.c[0], func, data);
+ if (t->root.c[1])
+ trie_walk_call(t->root.c[1], func, data);
+}
+
static int
trie_node_same(struct f_trie_node *t1, struct f_trie_node *t2)
{
diff --git a/nest/rt-table.c b/nest/rt-table.c
index 125f1d1..dbe0c50 100644
--- a/nest/rt-table.c
+++ b/nest/rt-table.c
@@ -1988,7 +1988,7 @@ rt_init_hostcache(rtable *tab)
hc->slab = sl_new(rt_table_pool, sizeof(struct hostentry));
hc->lp = lp_new(rt_table_pool, 1008);
- hc->trie = f_new_trie(hc->lp);
+ hc->trie = f_new_trie(hc->lp, sizeof(struct f_trie_node));
tab->hostcache = hc;
}
@@ -2136,7 +2136,7 @@ rt_update_hostcache(rtable *tab)
/* Reset the trie */
lp_flush(hc->lp);
- hc->trie = f_new_trie(hc->lp);
+ hc->trie = f_new_trie(hc->lp, sizeof(struct f_trie_node));
WALK_LIST_DELSAFE(n, x, hc->hostentries)
{
--
2.1.2
From 716d97caa91e90bf079ce55356193d854c63dfdd Mon Sep 17 00:00:00 2001
From: "Alexander V. Chernikov" <[email protected]>
Date: Sat, 31 Jan 2015 20:34:38 +0300
Subject: [PATCH 2/8] Make BGP protocol instance search separate function.
---
proto/bgp/bgp.c | 122 +++++++++++++++++++++++++++++++++-----------------------
1 file changed, 71 insertions(+), 51 deletions(-)
diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c
index e233911..99ec1ce 100644
--- a/proto/bgp/bgp.c
+++ b/proto/bgp/bgp.c
@@ -713,6 +713,28 @@ bgp_connect(struct bgp_proto *p) /* Enter Connect state and start establishing c
}
/**
+ * bgp_find_proto - find existing proto by socket
+ * @sk: TCP socket
+ *
+ */
+static struct bgp_proto *
+bgp_find_proto(sock *sk)
+{
+ struct proto_config *pc;
+
+ WALK_LIST(pc, config->protos)
+ if (pc->protocol == &proto_bgp && pc->proto)
+ {
+ struct bgp_proto *p = (struct bgp_proto *) pc->proto;
+ if (ipa_equal(p->cf->remote_ip, sk->daddr) &&
+ (!ipa_has_link_scope(sk->daddr) || (p->cf->iface == sk->iface)))
+ return p;
+ }
+
+ return NULL;
+}
+
+/**
* bgp_incoming_connection - handle an incoming connection
* @sk: TCP socket
* @dummy: unused
@@ -727,60 +749,58 @@ bgp_connect(struct bgp_proto *p) /* Enter Connect state and start establishing c
static int
bgp_incoming_connection(sock *sk, int dummy UNUSED)
{
- struct proto_config *pc;
+ struct bgp_proto *p;
+ int acc, hops;
DBG("BGP: Incoming connection from %I port %d\n", sk->daddr, sk->dport);
- WALK_LIST(pc, config->protos)
- if (pc->protocol == &proto_bgp && pc->proto)
- {
- struct bgp_proto *p = (struct bgp_proto *) pc->proto;
- if (ipa_equal(p->cf->remote_ip, sk->daddr) &&
- (!ipa_has_link_scope(sk->daddr) || (p->cf->iface == sk->iface)))
- {
- /* We are in proper state and there is no other incoming connection */
- int acc = (p->p.proto_state == PS_START || p->p.proto_state == PS_UP) &&
- (p->start_state >= BSS_CONNECT) && (!p->incoming_conn.sk);
-
- if (p->conn && (p->conn->state == BS_ESTABLISHED) && p->gr_ready)
- {
- bgp_store_error(p, NULL, BE_MISC, BEM_GRACEFUL_RESTART);
- bgp_handle_graceful_restart(p);
- bgp_conn_enter_idle_state(p->conn);
- acc = 1;
- }
-
- BGP_TRACE(D_EVENTS, "Incoming connection from %I%J (port %d) %s",
- sk->daddr, ipa_has_link_scope(sk->daddr) ? sk->iface : NULL,
- sk->dport, acc ? "accepted" : "rejected");
-
- if (!acc)
- goto reject;
-
- int hops = p->cf->multihop ? : 1;
-
- if (sk_set_ttl(sk, p->cf->ttl_security ? 255 : hops) < 0)
- goto err;
-
- if (p->cf->ttl_security)
- if (sk_set_min_ttl(sk, 256 - hops) < 0)
- goto err;
-
- bgp_setup_conn(p, &p->incoming_conn);
- bgp_setup_sk(&p->incoming_conn, sk);
- bgp_send_open(&p->incoming_conn);
- return 0;
-
- err:
- sk_log_error(sk, p->p.name);
- log(L_ERR "%s: Incoming connection aborted", p->p.name);
- rfree(sk);
- return 0;
- }
- }
- log(L_WARN "BGP: Unexpected connect from unknown address %I%J (port %d)",
- sk->daddr, ipa_has_link_scope(sk->daddr) ? sk->iface : NULL, sk->dport);
- reject:
+ p = bgp_find_proto(sk);
+ if (!p)
+ {
+ log(L_WARN "BGP: Unexpected connect from unknown address %I%J (port %d)",
+ sk->daddr, ipa_has_link_scope(sk->daddr) ? sk->iface : NULL, sk->dport);
+ rfree(sk);
+ return 0;
+ }
+
+ /* We are in proper state and there is no other incoming connection */
+ acc = (p->p.proto_state == PS_START || p->p.proto_state == PS_UP) &&
+ (p->start_state >= BSS_CONNECT) && (!p->incoming_conn.sk);
+
+ if (p->conn && (p->conn->state == BS_ESTABLISHED) && p->gr_ready)
+ {
+ bgp_store_error(p, NULL, BE_MISC, BEM_GRACEFUL_RESTART);
+ bgp_handle_graceful_restart(p);
+ bgp_conn_enter_idle_state(p->conn);
+ acc = 1;
+ }
+
+ BGP_TRACE(D_EVENTS, "Incoming connection from %I%J (port %d) %s",
+ sk->daddr, ipa_has_link_scope(sk->daddr) ? sk->iface : NULL,
+ sk->dport, acc ? "accepted" : "rejected");
+
+ if (!acc)
+ {
+ rfree(sk);
+ return 0;
+ }
+
+ hops = p->cf->multihop ? : 1;
+
+ if (sk_set_ttl(sk, p->cf->ttl_security ? 255 : hops) < 0)
+ goto err;
+
+ if (p->cf->ttl_security && ((sk_set_min_ttl(sk, 256 - hops) < 0)))
+ goto err;
+
+ bgp_setup_conn(p, &p->incoming_conn);
+ bgp_setup_sk(&p->incoming_conn, sk);
+ bgp_send_open(&p->incoming_conn);
+ return 0;
+
+err:
+ sk_log_error(sk, p->p.name);
+ log(L_ERR "%s: Incoming connection aborted", p->p.name);
rfree(sk);
return 0;
}
--
2.1.2
From 070a4735e626c9a92edf64139c9acd022cd915ea Mon Sep 17 00:00:00 2001
From: "Alexander V. Chernikov" <[email protected]>
Date: Sun, 8 Feb 2015 17:39:24 +0300
Subject: [PATCH 3/8] Move SYM_MAX_LEN definition to conf.h
---
conf/cf-lex.l | 1 -
conf/conf.h | 2 ++
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/conf/cf-lex.l b/conf/cf-lex.l
index 35b590b..57e0bfa 100644
--- a/conf/cf-lex.l
+++ b/conf/cf-lex.l
@@ -61,7 +61,6 @@ static struct keyword *kw_hash[KW_HASH_SIZE];
static int kw_hash_inited;
#define SYM_HASH_SIZE 128
-#define SYM_MAX_LEN 32
struct sym_scope {
struct sym_scope *next; /* Next on scope stack */
diff --git a/conf/conf.h b/conf/conf.h
index 799873d..3e641ce 100644
--- a/conf/conf.h
+++ b/conf/conf.h
@@ -108,6 +108,8 @@ struct symbol {
char name[1];
};
+#define SYM_MAX_LEN 32
+
/* Remember to update cf_symbol_class_name() */
#define SYM_VOID 0
#define SYM_PROTO 1
--
2.1.2
From f9d08002d1c5969d7f48be92185660fd17511a05 Mon Sep 17 00:00:00 2001
From: "Alexander V. Chernikov" <[email protected]>
Date: Mon, 9 Feb 2015 00:17:32 +0300
Subject: [PATCH 4/8] Store protocol instance size inside protocol structure.
Make proto_config_new() use this info instead of supplied size.
---
nest/config.Y | 2 +-
nest/proto.c | 5 ++---
nest/protocol.h | 3 ++-
nest/rt-dev.c | 1 +
proto/bfd/bfd.c | 1 +
proto/bfd/config.Y | 2 +-
proto/bgp/bgp.c | 1 +
proto/bgp/config.Y | 2 +-
proto/ospf/config.Y | 2 +-
proto/ospf/ospf.c | 1 +
proto/pipe/config.Y | 2 +-
proto/pipe/pipe.c | 1 +
proto/radv/config.Y | 2 +-
proto/radv/radv.c | 1 +
proto/rip/config.Y | 2 +-
proto/rip/rip.c | 1 +
proto/static/config.Y | 2 +-
proto/static/static.c | 1 +
sysdep/unix/krt.c | 6 ++++--
19 files changed, 24 insertions(+), 14 deletions(-)
diff --git a/nest/config.Y b/nest/config.Y
index 59a776b..8b69729 100644
--- a/nest/config.Y
+++ b/nest/config.Y
@@ -307,7 +307,7 @@ tos:
CF_ADDTO(proto, dev_proto '}')
dev_proto_start: proto_start DIRECT {
- this_proto = proto_config_new(&proto_device, sizeof(struct rt_dev_config), $1);
+ this_proto = proto_config_new(&proto_device, $1);
init_list(&DIRECT_CFG->iface_list);
}
;
diff --git a/nest/proto.c b/nest/proto.c
index 7a1e9bf..1166573 100644
--- a/nest/proto.c
+++ b/nest/proto.c
@@ -245,7 +245,6 @@ proto_free_ahooks(struct proto *p)
/**
* proto_config_new - create a new protocol configuration
* @pr: protocol the configuration will belong to
- * @size: size of the structure including generic data
* @class: SYM_PROTO or SYM_TEMPLATE
*
* Whenever the configuration file says that a new instance
@@ -262,9 +261,9 @@ proto_free_ahooks(struct proto *p)
* initialized during protos_commit()).
*/
void *
-proto_config_new(struct protocol *pr, unsigned size, int class)
+proto_config_new(struct protocol *pr, int class)
{
- struct proto_config *c = cfg_allocz(size);
+ struct proto_config *c = cfg_allocz(pr->proto_size);
if (class == SYM_PROTO)
add_tail(&new_config->protos, &c->n);
diff --git a/nest/protocol.h b/nest/protocol.h
index eb43418..233ffa6 100644
--- a/nest/protocol.h
+++ b/nest/protocol.h
@@ -41,6 +41,7 @@ struct protocol {
int attr_class; /* Attribute class known to this protocol */
int multitable; /* Protocol handles all announce hooks itself */
unsigned preference; /* Default protocol preference */
+ size_t proto_size; /* size of protocol instance */
void (*preconfig)(struct protocol *, struct config *); /* Just before configuring */
void (*postconfig)(struct proto_config *); /* After configuring each instance */
@@ -239,7 +240,7 @@ struct proto_spec {
void *proto_new(struct proto_config *, unsigned size);
-void *proto_config_new(struct protocol *, unsigned size, int class);
+void *proto_config_new(struct protocol *, int class);
void proto_copy_config(struct proto_config *dest, struct proto_config *src);
void proto_request_feeding(struct proto *p);
diff --git a/nest/rt-dev.c b/nest/rt-dev.c
index 1a859da..5d22396 100644
--- a/nest/rt-dev.c
+++ b/nest/rt-dev.c
@@ -115,6 +115,7 @@ struct protocol proto_device = {
name: "Direct",
template: "direct%d",
preference: DEF_PREF_DIRECT,
+ proto_size: sizeof(struct rt_dev_config),
init: dev_init,
reconfigure: dev_reconfigure,
copy_config: dev_copy_config
diff --git a/proto/bfd/bfd.c b/proto/bfd/bfd.c
index 23e04e4..bdd27b4 100644
--- a/proto/bfd/bfd.c
+++ b/proto/bfd/bfd.c
@@ -1112,6 +1112,7 @@ bfd_show_sessions(struct proto *P)
struct protocol proto_bfd = {
.name = "BFD",
.template = "bfd%d",
+ .proto_size= sizeof(struct bfd_config),
.init = bfd_init,
.start = bfd_start,
.shutdown = bfd_shutdown,
diff --git a/proto/bfd/config.Y b/proto/bfd/config.Y
index 1b07495..4affb92 100644
--- a/proto/bfd/config.Y
+++ b/proto/bfd/config.Y
@@ -34,7 +34,7 @@ CF_ADDTO(proto, bfd_proto)
bfd_proto_start: proto_start BFD
{
- this_proto = proto_config_new(&proto_bfd, sizeof(struct bfd_config), $1);
+ this_proto = proto_config_new(&proto_bfd, $1);
init_list(&BFD_CFG->patt_list);
init_list(&BFD_CFG->neigh_list);
diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c
index 99ec1ce..0fd2b68 100644
--- a/proto/bgp/bgp.c
+++ b/proto/bgp/bgp.c
@@ -1430,6 +1430,7 @@ struct protocol proto_bgp = {
template: "bgp%d",
attr_class: EAP_BGP,
preference: DEF_PREF_BGP,
+ proto_size: sizeof(struct bgp_config),
init: bgp_init,
start: bgp_start,
shutdown: bgp_shutdown,
diff --git a/proto/bgp/config.Y b/proto/bgp/config.Y
index 8e0b241..d0ae064 100644
--- a/proto/bgp/config.Y
+++ b/proto/bgp/config.Y
@@ -33,7 +33,7 @@ CF_GRAMMAR
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), $1);
+ this_proto = proto_config_new(&proto_bgp, $1);
BGP_CFG->multihop = -1; /* undefined */
BGP_CFG->hold_time = 240;
BGP_CFG->connect_retry_time = 120;
diff --git a/proto/ospf/config.Y b/proto/ospf/config.Y
index 478529b..58cc52d 100644
--- a/proto/ospf/config.Y
+++ b/proto/ospf/config.Y
@@ -143,7 +143,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), $1);
+ this_proto = proto_config_new(&proto_ospf, $1);
init_list(&OSPF_CFG->area_list);
init_list(&OSPF_CFG->vlink_list);
OSPF_CFG->rfc1583 = DEFAULT_RFC1583;
diff --git a/proto/ospf/ospf.c b/proto/ospf/ospf.c
index 6756ff4..3f5a6a4 100644
--- a/proto/ospf/ospf.c
+++ b/proto/ospf/ospf.c
@@ -1590,6 +1590,7 @@ struct protocol proto_ospf = {
template: "ospf%d",
attr_class: EAP_OSPF,
preference: DEF_PREF_OSPF,
+ proto_size: sizeof(struct ospf_config),
init: ospf_init,
dump: ospf_dump,
start: ospf_start,
diff --git a/proto/pipe/config.Y b/proto/pipe/config.Y
index 4063755..8daf2e7 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), $1);
+ this_proto = proto_config_new(&proto_pipe, $1);
PIPE_CFG->mode = PIPE_TRANSPARENT;
}
;
diff --git a/proto/pipe/pipe.c b/proto/pipe/pipe.c
index 22381c3..fc9f948 100644
--- a/proto/pipe/pipe.c
+++ b/proto/pipe/pipe.c
@@ -340,6 +340,7 @@ struct protocol proto_pipe = {
template: "pipe%d",
multitable: 1,
preference: DEF_PREF_PIPE,
+ proto_size: sizeof(struct pipe_config),
postconfig: pipe_postconfig,
init: pipe_init,
start: pipe_start,
diff --git a/proto/radv/config.Y b/proto/radv/config.Y
index a26ea88..da30066 100644
--- a/proto/radv/config.Y
+++ b/proto/radv/config.Y
@@ -40,7 +40,7 @@ CF_ADDTO(proto, radv_proto)
radv_proto_start: proto_start RADV
{
- this_proto = proto_config_new(&proto_radv, sizeof(struct radv_config), $1);
+ 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);
diff --git a/proto/radv/radv.c b/proto/radv/radv.c
index 6be7cd8..eb2a693 100644
--- a/proto/radv/radv.c
+++ b/proto/radv/radv.c
@@ -426,6 +426,7 @@ radv_get_status(struct proto *p, byte *buf)
struct protocol proto_radv = {
.name = "RAdv",
.template = "radv%d",
+ .proto_size= sizeof(struct radv_config),
.init = radv_init,
.start = radv_start,
.shutdown = radv_shutdown,
diff --git a/proto/rip/config.Y b/proto/rip/config.Y
index 7639752..b2b9909 100644
--- a/proto/rip/config.Y
+++ b/proto/rip/config.Y
@@ -43,7 +43,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), $1);
+ this_proto = proto_config_new(&proto_rip, $1);
rip_init_config(RIP_CFG);
}
;
diff --git a/proto/rip/rip.c b/proto/rip/rip.c
index bc9ffc5..85f1d93 100644
--- a/proto/rip/rip.c
+++ b/proto/rip/rip.c
@@ -1050,6 +1050,7 @@ struct protocol proto_rip = {
template: "rip%d",
attr_class: EAP_RIP,
preference: DEF_PREF_RIP,
+ proto_size: sizeof(struct rip_proto_config),
get_route_info: rip_get_route_info,
get_attr: rip_get_attr,
diff --git a/proto/static/config.Y b/proto/static/config.Y
index 2d9d4b4..a8bfa36 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), $1);
+ this_proto = proto_config_new(&proto_static, $1);
static_init_config((struct static_config *) this_proto);
}
;
diff --git a/proto/static/static.c b/proto/static/static.c
index d3a595d..7d571b3 100644
--- a/proto/static/static.c
+++ b/proto/static/static.c
@@ -531,6 +531,7 @@ struct protocol proto_static = {
name: "Static",
template: "static%d",
preference: DEF_PREF_STATIC,
+ proto_size: sizeof(struct static_config),
init: static_init,
dump: static_dump,
start: static_start,
diff --git a/sysdep/unix/krt.c b/sysdep/unix/krt.c
index a2fb83d..6aa264f 100644
--- a/sysdep/unix/krt.c
+++ b/sysdep/unix/krt.c
@@ -251,7 +251,7 @@ kif_init_config(int class)
if (kif_cf)
cf_error("Kernel device protocol already defined");
- kif_cf = (struct kif_config *) proto_config_new(&proto_unix_iface, sizeof(struct kif_config), class);
+ kif_cf = (struct kif_config *) proto_config_new(&proto_unix_iface, class);
kif_cf->scan_time = 60;
init_list(&kif_cf->primary);
@@ -280,6 +280,7 @@ struct protocol proto_unix_iface = {
name: "Device",
template: "device%d",
preference: DEF_PREF_DIRECT,
+ proto_size: sizeof(struct kif_config),
preconfig: kif_preconfig,
init: kif_init,
start: kif_start,
@@ -1150,7 +1151,7 @@ krt_init_config(int class)
cf_error("Kernel protocol already defined");
#endif
- krt_cf = (struct krt_config *) proto_config_new(&proto_unix_kernel, sizeof(struct krt_config), class);
+ krt_cf = (struct krt_config *) proto_config_new(&proto_unix_kernel, class);
krt_cf->scan_time = 60;
krt_sys_init_config(krt_cf);
@@ -1202,6 +1203,7 @@ struct protocol proto_unix_kernel = {
template: "kernel%d",
attr_class: EAP_KRT,
preference: DEF_PREF_INHERITED,
+ proto_size: sizeof(struct krt_config),
preconfig: krt_preconfig,
postconfig: krt_postconfig,
init: krt_init,
--
2.1.2
From d0f8857438476b456690bc7608b472a2569b697d Mon Sep 17 00:00:00 2001
From: "Alexander V. Chernikov" <[email protected]>
Date: Thu, 12 Feb 2015 02:13:54 +0300
Subject: [PATCH 5/8] * Limit scope of new_config and cfg_mem variables:
new_config is not exported anymore, direct cfg_mem usage signifficantly
reduced. * Be more accurate in global variables assignment: use
config_start_edit() along with config_stop_edit() to set/clear new_config and
cfg_mem.
---
conf/cf-lex.l | 71 ++++++++++++++++++++++++++++---------------------------
conf/conf.c | 65 +++++++++++++++++++++++++++++++++-----------------
conf/conf.h | 18 +++++++++-----
conf/confbase.Y | 4 ++--
filter/config.Y | 24 +++++++++----------
filter/filter.c | 4 ++--
filter/filter.h | 6 +++--
filter/tree.c | 4 ++--
nest/config.Y | 15 +++++++-----
nest/proto.c | 17 ++++++-------
nest/protocol.h | 2 +-
nest/route.h | 6 ++---
nest/rt-roa.c | 14 +++++------
nest/rt-table.c | 16 ++++++-------
sysdep/unix/krt.Y | 4 ++--
sysdep/unix/krt.c | 8 +++----
sysdep/unix/krt.h | 4 ++--
17 files changed, 158 insertions(+), 124 deletions(-)
diff --git a/conf/cf-lex.l b/conf/cf-lex.l
index 57e0bfa..b995e10 100644
--- a/conf/cf-lex.l
+++ b/conf/cf-lex.l
@@ -70,9 +70,7 @@ struct sym_scope {
static struct sym_scope *conf_this_scope;
static int cf_hash(byte *c);
-static struct symbol *cf_find_sym(byte *c, unsigned int h0);
-
-linpool *cfg_mem;
+static struct symbol *cf_find_sym(struct config *c, byte *str, unsigned int h0);
int (*cf_read_hook)(byte *buf, unsigned int max, int fd);
struct include_file_stack *ifs;
@@ -192,7 +190,7 @@ else: {
}
k=k->next;
}
- cf_lval.s = cf_find_sym(yytext, h);
+ cf_lval.s = cf_find_sym(config_get_ptr_new(), yytext, h);
return SYM;
}
@@ -211,7 +209,7 @@ else: {
["][^"\n]*["] {
yytext[yyleng-1] = 0;
- cf_lval.t = cfg_strdup(yytext+1);
+ cf_lval.t = cfg_strdup(config_get_ptr_new(), yytext+1);
return TEXT;
}
@@ -277,10 +275,10 @@ cf_hash(byte *c)
*/
static struct include_file_stack *
-push_ifs(struct include_file_stack *old)
+push_ifs(struct config *c, struct include_file_stack *old)
{
struct include_file_stack *ret;
- ret = cfg_allocz(sizeof(struct include_file_stack));
+ ret = cfl_allocz(c, sizeof(struct include_file_stack));
ret->lino = 1;
ret->prev = old;
return ret;
@@ -341,8 +339,11 @@ cf_include(char *arg, int alen)
struct include_file_stack *base_ifs = ifs;
int new_depth, rv, i;
char *patt;
+ struct config *new;
glob_t g = {};
+ new = config_get_ptr_new();
+
new_depth = ifs->depth + 1;
if (new_depth > MAX_INCLUDE_DEPTH)
cf_error("Max include depth reached");
@@ -363,8 +364,8 @@ cf_include(char *arg, int alen)
response when the included config file is missing */
if (!strpbrk(arg, "?*["))
{
- ifs = push_ifs(ifs);
- ifs->file_name = cfg_strdup(patt);
+ ifs = push_ifs(new, ifs);
+ ifs->file_name = cfg_strdup(new, patt);
ifs->depth = new_depth;
ifs->up = base_ifs;
enter_ifs(ifs);
@@ -398,8 +399,8 @@ cf_include(char *arg, int alen)
continue;
/* Prepare new stack item */
- ifs = push_ifs(ifs);
- ifs->file_name = cfg_strdup(fname);
+ ifs = push_ifs(new, ifs);
+ ifs->file_name = cfg_strdup(new, fname);
ifs->depth = new_depth;
ifs->up = base_ifs;
}
@@ -424,48 +425,48 @@ check_eof(void)
}
static struct symbol *
-cf_new_sym(byte *c, unsigned int h)
+cf_new_sym(struct config *c, byte *str, unsigned int h)
{
struct symbol *s, **ht;
int l;
- if (!new_config->sym_hash)
- new_config->sym_hash = cfg_allocz(SYM_HASH_SIZE * sizeof(struct keyword *));
- ht = new_config->sym_hash;
- l = strlen(c);
+ if (!c->sym_hash)
+ c->sym_hash = cfl_allocz(c, SYM_HASH_SIZE * sizeof(struct keyword *));
+ ht = c->sym_hash;
+ l = strlen(str);
if (l > SYM_MAX_LEN)
cf_error("Symbol too long");
- s = cfg_alloc(sizeof(struct symbol) + l);
+ s = cfl_alloc(c, sizeof(struct symbol) + l);
s->next = ht[h];
ht[h] = s;
s->scope = conf_this_scope;
s->class = SYM_VOID;
s->def = NULL;
s->aux = 0;
- strcpy(s->name, c);
+ strcpy(s->name, str);
return s;
}
static struct symbol *
-cf_find_sym(byte *c, unsigned int h0)
+cf_find_sym(struct config *c, byte *str, unsigned int h0)
{
unsigned int h = h0 & (SYM_HASH_SIZE-1);
struct symbol *s, **ht;
- if (ht = new_config->sym_hash)
+ if (ht = c->sym_hash)
{
for(s = ht[h]; s; s=s->next)
- if (!strcmp(s->name, c) && s->scope->active)
+ if (!strcmp(s->name, str) && s->scope->active)
return s;
}
- if (new_config->sym_fallback)
+ if (c->sym_fallback)
{
/* We know only top-level scope is active */
- for(s = new_config->sym_fallback[h]; s; s=s->next)
- if (!strcmp(s->name, c) && s->scope->active)
+ for(s = c->sym_fallback[h]; s; s=s->next)
+ if (!strcmp(s->name, str) && s->scope->active)
return s;
}
- return cf_new_sym(c, h);
+ return cf_new_sym(c, str, h);
}
/**
@@ -479,13 +480,13 @@ cf_find_sym(byte *c, unsigned int h0)
* and returns %NULL to signify no match.
*/
struct symbol *
-cf_find_symbol(byte *c)
+cf_find_symbol(struct config *c, byte *str)
{
- return cf_find_sym(c, cf_hash(c));
+ return cf_find_sym(c, str, cf_hash(str));
}
struct symbol *
-cf_default_name(char *template, int *counter)
+cf_default_name(struct config *c, char *template, int *counter)
{
char buf[32];
struct symbol *s;
@@ -494,7 +495,7 @@ cf_default_name(char *template, int *counter)
for(;;)
{
bsprintf(buf, template, ++(*counter));
- s = cf_find_sym(buf, cf_hash(buf));
+ s = cf_find_sym(c, buf, cf_hash(buf));
if (!s)
break;
if (s->class == SYM_VOID)
@@ -521,13 +522,13 @@ cf_default_name(char *template, int *counter)
* scope, it's the same @sym as passed to the function.
*/
struct symbol *
-cf_define_symbol(struct symbol *sym, int type, void *def)
+cf_define_symbol(struct config *c, struct symbol *sym, int type, void *def)
{
if (sym->class)
{
if (sym->scope == conf_this_scope)
cf_error("Symbol already defined");
- sym = cf_new_sym(sym->name, cf_hash(sym->name) & (SYM_HASH_SIZE-1));
+ sym = cf_new_sym(c, sym->name, cf_hash(sym->name) & (SYM_HASH_SIZE-1));
}
sym->class = type;
sym->def = def;
@@ -561,7 +562,7 @@ cf_lex_init(int is_cli, struct config *c)
if (!kw_hash_inited)
cf_lex_init_kh();
- ifs_head = ifs = push_ifs(NULL);
+ ifs_head = ifs = push_ifs(c, NULL);
if (!is_cli)
{
ifs->file_name = c->file_name;
@@ -577,7 +578,7 @@ cf_lex_init(int is_cli, struct config *c)
else
BEGIN(INITIAL);
- conf_this_scope = cfg_allocz(sizeof(struct sym_scope));
+ conf_this_scope = cfl_allocz(c, sizeof(struct sym_scope));
conf_this_scope->active = 1;
}
@@ -592,9 +593,9 @@ cf_lex_init(int is_cli, struct config *c)
* in all scopes stored on the stack.
*/
void
-cf_push_scope(struct symbol *sym)
+cf_push_scope(struct config *c, struct symbol *sym)
{
- struct sym_scope *s = cfg_alloc(sizeof(struct sym_scope));
+ struct sym_scope *s = cfl_alloc(c, sizeof(struct sym_scope));
s->next = conf_this_scope;
conf_this_scope = s;
diff --git a/conf/conf.c b/conf/conf.c
index a907402..9f93813 100644
--- a/conf/conf.c
+++ b/conf/conf.c
@@ -59,6 +59,7 @@
static jmp_buf conf_jmpbuf;
struct config *config, *new_config;
+linpool *cfg_mem;
static struct config *old_config; /* Old configuration */
static struct config *future_config; /* New config held here if recon requested during recon */
@@ -93,8 +94,8 @@ config_alloc(byte *name)
c->mrtdump_file = -1; /* Hack, this should be sysdep-specific */
c->pool = p;
- cfg_mem = c->mem = l;
- c->file_name = cfg_strdup(name);
+ c->mem = l;
+ c->file_name = cfg_strdup(c, name);
c->load_time = now;
c->tf_route = c->tf_proto = (struct timeformat){"%T", "%F", 20*3600};
c->tf_base = c->tf_log = (struct timeformat){"%F %T", NULL, 0};
@@ -120,10 +121,12 @@ int
config_parse(struct config *c)
{
DBG("Parsing configuration file `%s'\n", c->file_name);
- new_config = c;
- cfg_mem = c->mem;
+ config_start_edit(c);
if (setjmp(conf_jmpbuf))
- return 0;
+ {
+ config_stop_edit();
+ return 0;
+ }
cf_lex_init(0, c);
sysdep_preconfig(c);
protos_preconfig(c);
@@ -137,6 +140,7 @@ config_parse(struct config *c)
if (!c->router_id)
cf_error("Router ID must be configured manually on IPv6 routers");
#endif
+ config_stop_edit();
return 1;
}
@@ -150,13 +154,16 @@ config_parse(struct config *c)
int
cli_parse(struct config *c)
{
- new_config = c;
+ config_start_edit(c);
c->sym_fallback = config->sym_hash;
- cfg_mem = c->mem;
if (setjmp(conf_jmpbuf))
- return 0;
+ {
+ config_stop_edit();
+ return 0;
+ }
cf_lex_init(1, c);
cf_parse();
+ config_stop_edit();
return 1;
}
@@ -237,10 +244,6 @@ config_do_commit(struct config *c, int type)
if (old_config && !config->shutdown)
log(L_INFO "Reconfiguring");
- /* This should not be necessary, but it seems there are some
- functions that access new_config instead of config */
- new_config = config;
-
if (old_config)
old_config->obstacle_count++;
@@ -254,9 +257,6 @@ config_do_commit(struct config *c, int type)
DBG("protos_commit\n");
protos_commit(c, old_config, force_restart, type);
- /* Just to be sure nobody uses that now */
- new_config = NULL;
-
int obs = 0;
if (old_config)
obs = --old_config->obstacle_count;
@@ -288,6 +288,26 @@ config_done(void *unused UNUSED)
}
}
+void
+config_start_edit(struct config *c)
+{
+ new_config = c;
+ cfg_mem = c->mem;
+}
+
+void
+config_stop_edit()
+{
+ new_config = NULL;
+ cfg_mem = NULL;
+}
+
+struct config *
+config_get_ptr_new(void)
+{
+ return new_config;
+}
+
/**
* config_commit - commit a configuration
* @c: new configuration
@@ -499,7 +519,7 @@ cf_error(char *msg, ...)
va_start(args, msg);
if (bvsnprintf(buf, sizeof(buf), msg, args) < 0)
strcpy(buf, "<bug: error message too long>");
- new_config->err_msg = cfg_strdup(buf);
+ new_config->err_msg = cfg_strdup(new_config, buf);
new_config->err_lino = ifs->lino;
new_config->err_file_name = ifs->file_name;
cf_lex_unwind();
@@ -508,19 +528,20 @@ cf_error(char *msg, ...)
/**
* cfg_strdup - copy a string to config memory
- * @c: string to copy
+ * @c: pointer to config
+ * @str: string to copy
*
* cfg_strdup() creates a new copy of the string in the memory
- * pool associated with the configuration being currently parsed.
+ * pool @c.
* It's often used when a string literal occurs in the configuration
* and we want to preserve it for further use.
*/
char *
-cfg_strdup(char *c)
+cfg_strdup(struct config *c, char *str)
{
- int l = strlen(c) + 1;
- char *z = cfg_allocu(l);
- memcpy(z, c, l);
+ int l = strlen(str) + 1;
+ char *z = cfl_allocu(c, l);
+ memcpy(z, str, l);
return z;
}
diff --git a/conf/conf.h b/conf/conf.h
index 3e641ce..eb8acb5 100644
--- a/conf/conf.h
+++ b/conf/conf.h
@@ -55,7 +55,6 @@ struct config {
/* Please don't use these variables in protocols. Use proto_config->global instead. */
extern struct config *config; /* Currently active configuration */
-extern struct config *new_config; /* Configuration being parsed */
struct config *config_alloc(byte *name);
int config_parse(struct config *);
@@ -64,6 +63,8 @@ void config_free(struct config *);
int config_commit(struct config *, int type, int timeout);
int config_confirm(void);
int config_undo(void);
+void config_start_edit(struct config *);
+void config_stop_edit(void);
void config_init(void);
void cf_error(char *msg, ...) NORET;
void config_add_obstacle(struct config *);
@@ -91,8 +92,13 @@ extern linpool *cfg_mem;
#define cfg_alloc(size) lp_alloc(cfg_mem, size)
#define cfg_allocu(size) lp_allocu(cfg_mem, size)
#define cfg_allocz(size) lp_allocz(cfg_mem, size)
-char *cfg_strdup(char *c);
+char *cfg_strdup(struct config *c, char *str);
void cfg_copy_list(list *dest, list *src, unsigned node_size);
+struct config * config_get_ptr_new(void);
+
+#define cfl_alloc(c, size) lp_alloc((c)->mem, size)
+#define cfl_allocz(c, size) lp_allocz((c)->mem, size)
+#define cfl_allocu(c, size) lp_allocu((c)->mem, size)
/* Lexer */
@@ -143,10 +149,10 @@ int cf_lex(void);
void cf_lex_init(int is_cli, struct config *c);
void cf_lex_unwind(void);
-struct symbol *cf_find_symbol(byte *c);
-struct symbol *cf_default_name(char *template, int *counter);
-struct symbol *cf_define_symbol(struct symbol *symbol, int type, void *def);
-void cf_push_scope(struct symbol *);
+struct symbol *cf_find_symbol(struct config *c, byte *str);
+struct symbol *cf_default_name(struct config *c, char *template, int *counter);
+struct symbol *cf_define_symbol(struct config *c, struct symbol *symbol, int type, void *def);
+void cf_push_scope(struct config *c, struct symbol *);
void cf_pop_scope(void);
struct symbol *cf_walk_symbols(struct config *cf, struct symbol *sym, int *pos);
char *cf_symbol_class_name(struct symbol *sym);
diff --git a/conf/confbase.Y b/conf/confbase.Y
index 49831b1..5f209a0 100644
--- a/conf/confbase.Y
+++ b/conf/confbase.Y
@@ -114,13 +114,13 @@ definition:
struct f_val *val = cfg_alloc(sizeof(struct f_val));
*val = f_eval($4, cfg_mem);
if (val->type == T_RETURN) cf_error("Runtime error");
- cf_define_symbol($2, SYM_CONSTANT | val->type, val);
+ cf_define_symbol(new_config, $2, SYM_CONSTANT | val->type, val);
}
;
expr:
NUM
- | '(' term ')' { $$ = f_eval_int($2); }
+ | '(' term ')' { $$ = f_eval_int($2, cfg_mem); }
| SYM {
if ($1->class != (SYM_CONSTANT | T_INT)) cf_error("Number expected");
$$ = SYM_VAL($1).i; }
diff --git a/filter/config.Y b/filter/config.Y
index 7eb2c0a..0a338e5 100644
--- a/filter/config.Y
+++ b/filter/config.Y
@@ -46,7 +46,7 @@ f_valid_set_type(int type)
static inline struct f_tree *
f_new_item(struct f_val from, struct f_val to)
{
- struct f_tree *t = f_new_tree();
+ struct f_tree *t = f_new_tree(new_config);
t->right = t;
t->from = from;
t->to = to;
@@ -66,7 +66,7 @@ f_merge_items(struct f_tree *a, struct f_tree *b)
static inline struct f_tree *
f_new_pair_item(int fa, int ta, int fb, int tb)
{
- struct f_tree *t = f_new_tree();
+ struct f_tree *t = f_new_tree(new_config);
t->right = t;
t->from.type = t->to.type = T_PAIR;
t->from.val.i = pair(fa, fb);
@@ -124,7 +124,7 @@ f_new_ec_item(u32 kind, u32 ipv4_used, u32 key, u32 vf, u32 vt)
to = ec_as4(kind, key, vt);
}
- struct f_tree *t = f_new_tree();
+ struct f_tree *t = f_new_tree(new_config);
t->right = t;
t->from.type = t->to.type = T_EC;
t->from.val.ec = fm;
@@ -305,7 +305,7 @@ CF_GRAMMAR
CF_ADDTO(conf, filter_def)
filter_def:
- FILTER SYM { $2 = cf_define_symbol($2, SYM_FILTER, NULL); cf_push_scope( $2 ); }
+ FILTER SYM { $2 = cf_define_symbol(new_config, $2, SYM_FILTER, NULL); cf_push_scope( new_config, $2 ); }
filter_body {
$2->def = $4;
$4->name = $2->name;
@@ -316,7 +316,7 @@ filter_def:
CF_ADDTO(conf, filter_eval)
filter_eval:
- EVAL term { f_eval_int($2); }
+ EVAL term { f_eval_int($2, cfg_mem); }
;
type:
@@ -356,7 +356,7 @@ one_decl:
type SYM {
struct f_val * val = cfg_alloc(sizeof(struct f_val));
val->type = T_VOID;
- $2 = cf_define_symbol($2, SYM_VARIABLE | $1, val);
+ $2 = cf_define_symbol(new_config, $2, SYM_VARIABLE | $1, val);
DBG( "New variable %s type %x\n", $2->name, $1 );
$2->aux2 = NULL;
$$=$2;
@@ -441,8 +441,8 @@ function_body:
CF_ADDTO(conf, function_def)
function_def:
FUNCTION SYM { DBG( "Beginning of function %s\n", $2->name );
- $2 = cf_define_symbol($2, SYM_FUNCTION, NULL);
- cf_push_scope($2);
+ $2 = cf_define_symbol(new_config, $2, SYM_FUNCTION, NULL);
+ cf_push_scope(new_config, $2);
} function_params function_body {
$2->def = $5;
$2->aux2 = $4;
@@ -507,14 +507,14 @@ set_atom:
switch_atom:
NUM { $$.type = T_INT; $$.val.i = $1; }
- | '(' term ')' { $$.type = T_INT; $$.val.i = f_eval_int($2); }
+ | '(' term ')' { $$.type = T_INT; $$.val.i = f_eval_int($2, cfg_mem); }
| RTRID { $$.type = T_QUAD; $$.val.i = $1; }
| fipa { $$ = $1; }
| ENUM { $$.type = pair_a($1); $$.val.i = pair_b($1); }
;
pair_expr:
- term { $$ = f_eval_int($1); check_u16($$); }
+ term { $$ = f_eval_int($1, cfg_mem); check_u16($$); }
pair_atom:
pair_expr { $$ = pair($1, $1); }
@@ -535,7 +535,7 @@ pair_item:
;
ec_expr:
- term { $$ = f_eval_int($1); }
+ term { $$ = f_eval_int($1, cfg_mem); }
ec_kind:
RT { $$ = EC_RT; }
@@ -605,7 +605,7 @@ switch_body: /* EMPTY */ { $$ = NULL; }
$$ = f_merge_items($1, $2);
}
| switch_body ELSECOL cmds {
- struct f_tree *t = f_new_tree();
+ struct f_tree *t = f_new_tree(new_config);
t->from.type = t->to.type = T_VOID;
t->right = t;
t->data = $3;
diff --git a/filter/filter.c b/filter/filter.c
index 63c2cd8..ac256f3 100644
--- a/filter/filter.c
+++ b/filter/filter.c
@@ -1513,10 +1513,10 @@ f_eval(struct f_inst *expr, struct linpool *tmp_pool)
}
uint
-f_eval_int(struct f_inst *expr)
+f_eval_int(struct f_inst *expr, struct linpool *tmp_pool)
{
/* Called independently in parse-time to eval expressions */
- struct f_val res = f_eval(expr, cfg_mem);
+ struct f_val res = f_eval(expr, tmp_pool);
if (res.type != T_INT)
cf_error("Integer expression expected");
diff --git a/filter/filter.h b/filter/filter.h
index 522af9f..23385cf 100644
--- a/filter/filter.h
+++ b/filter/filter.h
@@ -68,9 +68,11 @@ struct filter {
struct f_inst *root;
};
+struct config;
+
struct f_inst *f_new_inst(void);
struct f_inst *f_new_dynamic_attr(int type, int f_type, int code); /* Type as core knows it, type as filters know it, and code of dynamic attribute */
-struct f_tree *f_new_tree(void);
+struct f_tree *f_new_tree(struct config *);
struct f_inst *f_generate_complex(int operation, int operation_aux, struct f_inst *dyn, struct f_inst *argument);
struct f_inst *f_generate_roa_check(struct symbol *sym, struct f_inst *prefix, struct f_inst *asn);
@@ -110,7 +112,7 @@ struct rte;
int f_run(struct filter *filter, struct rte **rte, struct ea_list **tmp_attrs, struct linpool *tmp_pool, int flags);
struct f_val f_eval(struct f_inst *expr, struct linpool *tmp_pool);
-uint f_eval_int(struct f_inst *expr);
+uint f_eval_int(struct f_inst *expr, struct linpool *tmp_pool);
u32 f_eval_asn(struct f_inst *expr);
char *filter_name(struct filter *filter);
diff --git a/filter/tree.c b/filter/tree.c
index ee9f448..5910398 100644
--- a/filter/tree.c
+++ b/filter/tree.c
@@ -100,10 +100,10 @@ build_tree(struct f_tree *from)
}
struct f_tree *
-f_new_tree(void)
+f_new_tree(struct config *c)
{
struct f_tree * ret;
- ret = cfg_alloc(sizeof(struct f_tree));
+ ret = cfl_alloc(c, sizeof(struct f_tree));
ret->left = ret->right = NULL;
ret->from.type = ret->to.type = T_VOID;
ret->from.val.i = ret->to.val.i = 0;
diff --git a/nest/config.Y b/nest/config.Y
index 8b69729..481d9f5 100644
--- a/nest/config.Y
+++ b/nest/config.Y
@@ -16,6 +16,9 @@ CF_HDR
CF_DEFINES
+extern struct config *new_config; /* Configuration being parsed */
+#define proto_config_new(pr, cl) proto_create_config(new_config, pr, cl)
+
static struct proto_config *this_proto;
static struct iface_patt *this_ipatt;
static struct iface_patt_node *this_ipn;
@@ -138,7 +141,7 @@ CF_ADDTO(conf, newtab)
newtab: TABLE SYM tab_sorted {
struct rtable_config *cf;
- cf = rt_new_table($2);
+ cf = rt_new_table(new_config, $2);
cf->sorted = $3;
}
;
@@ -146,13 +149,13 @@ newtab: TABLE SYM tab_sorted {
CF_ADDTO(conf, roa_table)
roa_table_start: ROA TABLE SYM {
- this_roa_table = roa_new_table_config($3);
+ this_roa_table = roa_new_table_config(new_config, $3);
};
roa_table_opts:
/* empty */
| roa_table_opts ROA prefix MAX NUM AS NUM ';' {
- roa_add_item_config(this_roa_table, $3.addr, $3.len, $5, $7);
+ roa_add_item_config(new_config, this_roa_table, $3.addr, $3.len, $5, $7);
}
;
@@ -172,19 +175,19 @@ proto_start:
proto_name:
/* EMPTY */ {
- struct symbol *s = cf_default_name(this_proto->protocol->template, &this_proto->protocol->name_counter);
+ struct symbol *s = cf_default_name(new_config, this_proto->protocol->template, &this_proto->protocol->name_counter);
s->class = this_proto->class;
s->def = this_proto;
this_proto->name = s->name;
}
| SYM {
- cf_define_symbol($1, this_proto->class, this_proto);
+ cf_define_symbol(new_config, $1, this_proto->class, this_proto);
this_proto->name = $1->name;
}
| SYM FROM SYM {
if (($3->class != SYM_TEMPLATE) && ($3->class != SYM_PROTO)) cf_error("Template or protocol name expected");
- cf_define_symbol($1, this_proto->class, this_proto);
+ cf_define_symbol(new_config, $1, this_proto->class, this_proto);
this_proto->name = $1->name;
proto_copy_config(this_proto, $3->def);
diff --git a/nest/proto.c b/nest/proto.c
index 1166573..846d172 100644
--- a/nest/proto.c
+++ b/nest/proto.c
@@ -243,7 +243,8 @@ proto_free_ahooks(struct proto *p)
/**
- * proto_config_new - create a new protocol configuration
+ * proto_create_config - create a new protocol configuration
+ * @new: new config instance
* @pr: protocol the configuration will belong to
* @class: SYM_PROTO or SYM_TEMPLATE
*
@@ -261,21 +262,21 @@ proto_free_ahooks(struct proto *p)
* initialized during protos_commit()).
*/
void *
-proto_config_new(struct protocol *pr, int class)
+proto_create_config(struct config *new, struct protocol *pr, int class)
{
- struct proto_config *c = cfg_allocz(pr->proto_size);
+ struct proto_config *c = cfl_allocz(new, pr->proto_size);
if (class == SYM_PROTO)
- add_tail(&new_config->protos, &c->n);
- c->global = new_config;
+ add_tail(&new->protos, &c->n);
+ c->global = new;
c->protocol = pr;
c->name = pr->name;
c->preference = pr->preference;
c->class = class;
c->out_filter = FILTER_REJECT;
c->table = c->global->master_rtc;
- c->debug = new_config->proto_default_debug;
- c->mrtdump = new_config->proto_default_mrtdump;
+ c->debug = new->proto_default_debug;
+ c->mrtdump = new->proto_default_mrtdump;
return c;
}
@@ -521,7 +522,7 @@ protos_commit(struct config *new, struct config *old, int force_reconfig, int ty
WALK_LIST(oc, old->protos)
{
p = oc->proto;
- sym = cf_find_symbol(oc->name);
+ sym = cf_find_symbol(new, oc->name);
if (sym && sym->class == SYM_PROTO && !new->shutdown)
{
/* Found match, let's check if we can smoothly switch to new configuration */
diff --git a/nest/protocol.h b/nest/protocol.h
index 233ffa6..a20b053 100644
--- a/nest/protocol.h
+++ b/nest/protocol.h
@@ -240,7 +240,7 @@ struct proto_spec {
void *proto_new(struct proto_config *, unsigned size);
-void *proto_config_new(struct protocol *, int class);
+void *proto_create_config(struct config *, struct protocol *, int class);
void proto_copy_config(struct proto_config *dest, struct proto_config *src);
void proto_request_feeding(struct proto *p);
diff --git a/nest/route.h b/nest/route.h
index 5ee04a3..c38df41 100644
--- a/nest/route.h
+++ b/nest/route.h
@@ -274,7 +274,7 @@ void rt_dump_all(void);
int rt_feed_baby(struct proto *p);
void rt_feed_baby_abort(struct proto *p);
int rt_prune_loop(void);
-struct rtable_config *rt_new_table(struct symbol *s);
+struct rtable_config *rt_new_table(struct config *c, struct symbol *s);
static inline void
rt_mark_for_prune(rtable *tab)
@@ -591,8 +591,8 @@ void roa_add_item(struct roa_table *t, ip_addr prefix, byte pxlen, byte maxlen,
void roa_delete_item(struct roa_table *t, ip_addr prefix, byte pxlen, byte maxlen, u32 asn, byte src);
void roa_flush(struct roa_table *t, byte src);
byte roa_check(struct roa_table *t, ip_addr prefix, byte pxlen, u32 asn);
-struct roa_table_config * roa_new_table_config(struct symbol *s);
-void roa_add_item_config(struct roa_table_config *rtc, ip_addr prefix, byte pxlen, byte maxlen, u32 asn);
+struct roa_table_config * roa_new_table_config(struct config *c, struct symbol *s);
+void roa_add_item_config(struct config *c, struct roa_table_config *rtc, ip_addr prefix, byte pxlen, byte maxlen, u32 asn);
void roa_init(void);
void roa_preconfig(struct config *c);
void roa_commit(struct config *new, struct config *old);
diff --git a/nest/rt-roa.c b/nest/rt-roa.c
index aa453f1..1c28bdd 100644
--- a/nest/rt-roa.c
+++ b/nest/rt-roa.c
@@ -240,13 +240,13 @@ roa_new_table(struct roa_table_config *cf)
}
struct roa_table_config *
-roa_new_table_config(struct symbol *s)
+roa_new_table_config(struct config *c, struct symbol *s)
{
- struct roa_table_config *rtc = cfg_allocz(sizeof(struct roa_table_config));
+ struct roa_table_config *rtc = cfl_allocz(c, sizeof(struct roa_table_config));
- cf_define_symbol(s, SYM_ROA, rtc);
+ cf_define_symbol(c, s, SYM_ROA, rtc);
rtc->name = s->name;
- add_tail(&new_config->roa_tables, &rtc->n);
+ add_tail(&c->roa_tables, &rtc->n);
return rtc;
}
@@ -257,9 +257,9 @@ roa_new_table_config(struct symbol *s)
* are specifying the ROA entry.
*/
void
-roa_add_item_config(struct roa_table_config *rtc, ip_addr prefix, byte pxlen, byte maxlen, u32 asn)
+roa_add_item_config(struct config *c, struct roa_table_config *rtc, ip_addr prefix, byte pxlen, byte maxlen, u32 asn)
{
- struct roa_item_config *ric = cfg_allocz(sizeof(struct roa_item_config));
+ struct roa_item_config *ric = cfl_allocz(c, sizeof(struct roa_item_config));
ric->prefix = prefix;
ric->pxlen = pxlen;
@@ -311,7 +311,7 @@ roa_commit(struct config *new, struct config *old)
if (old)
WALK_LIST(t, roa_table_list)
{
- struct symbol *sym = cf_find_symbol(t->name);
+ struct symbol *sym = cf_find_symbol(new, t->name);
if (sym && sym->class == SYM_ROA)
{
/* Found old table in new config */
diff --git a/nest/rt-table.c b/nest/rt-table.c
index dbe0c50..17ca98e 100644
--- a/nest/rt-table.c
+++ b/nest/rt-table.c
@@ -1491,10 +1491,10 @@ rt_prune_loop(void)
void
rt_preconfig(struct config *c)
{
- struct symbol *s = cf_find_symbol("master");
+ struct symbol *s = cf_find_symbol(c, "master");
init_list(&c->tables);
- c->master_rtc = rt_new_table(s);
+ c->master_rtc = rt_new_table(c, s);
}
@@ -1648,17 +1648,17 @@ rt_next_hop_update(rtable *tab)
struct rtable_config *
-rt_new_table(struct symbol *s)
+rt_new_table(struct config *new, struct symbol *s)
{
/* Hack that allows to 'redefine' the master table */
- if ((s->class == SYM_TABLE) && (s->def == new_config->master_rtc))
+ if ((s->class == SYM_TABLE) && (s->def == new->master_rtc))
return s->def;
- struct rtable_config *c = cfg_allocz(sizeof(struct rtable_config));
+ struct rtable_config *c = cfl_allocz(new, sizeof(struct rtable_config));
- cf_define_symbol(s, SYM_TABLE, c);
+ cf_define_symbol(new, s, SYM_TABLE, c);
c->name = s->name;
- add_tail(&new_config->tables, &c->n);
+ add_tail(&new->tables, &c->n);
c->gc_max_ops = 1000;
c->gc_min_time = 5;
return c;
@@ -1728,7 +1728,7 @@ rt_commit(struct config *new, struct config *old)
rtable *ot = o->table;
if (!ot->deleted)
{
- struct symbol *sym = cf_find_symbol(o->name);
+ struct symbol *sym = cf_find_symbol(new, o->name);
if (sym && sym->class == SYM_TABLE && !new->shutdown)
{
DBG("\t%s: same\n", o->name);
diff --git a/sysdep/unix/krt.Y b/sysdep/unix/krt.Y
index 630cda3..d1bacb6 100644
--- a/sysdep/unix/krt.Y
+++ b/sysdep/unix/krt.Y
@@ -25,7 +25,7 @@ CF_GRAMMAR
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(new_config, $1); }
;
CF_ADDTO(kern_proto, kern_proto_start proto_name '{')
@@ -53,7 +53,7 @@ kern_item:
CF_ADDTO(proto, kif_proto '}')
-kif_proto_start: proto_start DEVICE { this_proto = kif_init_config($1); }
+kif_proto_start: proto_start DEVICE { this_proto = kif_init_config(new_config, $1); }
;
CF_ADDTO(kif_proto, kif_proto_start proto_name '{')
diff --git a/sysdep/unix/krt.c b/sysdep/unix/krt.c
index 6aa264f..d342f7b 100644
--- a/sysdep/unix/krt.c
+++ b/sysdep/unix/krt.c
@@ -246,12 +246,12 @@ kif_preconfig(struct protocol *P UNUSED, struct config *c)
}
struct proto_config *
-kif_init_config(int class)
+kif_init_config(struct config *c, int class)
{
if (kif_cf)
cf_error("Kernel device protocol already defined");
- kif_cf = (struct kif_config *) proto_config_new(&proto_unix_iface, class);
+ kif_cf = (struct kif_config *) proto_create_config(c, &proto_unix_iface, class);
kif_cf->scan_time = 60;
init_list(&kif_cf->primary);
@@ -1144,14 +1144,14 @@ krt_postconfig(struct proto_config *C)
}
struct proto_config *
-krt_init_config(int class)
+krt_init_config(struct config *c, int class)
{
#ifndef CONFIG_MULTIPLE_TABLES
if (krt_cf)
cf_error("Kernel protocol already defined");
#endif
- krt_cf = (struct krt_config *) proto_config_new(&proto_unix_kernel, class);
+ krt_cf = (struct krt_config *) proto_create_config(c, &proto_unix_kernel, class);
krt_cf->scan_time = 60;
krt_sys_init_config(krt_cf);
diff --git a/sysdep/unix/krt.h b/sysdep/unix/krt.h
index 2cd2316..fa4d25a 100644
--- a/sysdep/unix/krt.h
+++ b/sysdep/unix/krt.h
@@ -77,7 +77,7 @@ extern pool *krt_pool;
if (pr->p.debug & fl) \
{ log(L_TRACE "%s: " msg, pr->p.name , ## args); } } while(0)
-struct proto_config * kif_init_config(int class);
+struct proto_config * kif_init_config(struct config *, int class);
void kif_request_scan(void);
void krt_got_route(struct krt_proto *p, struct rte *e);
void krt_got_route_async(struct krt_proto *p, struct rte *e, int new);
@@ -112,7 +112,7 @@ struct kif_proto {
#define KIF_CF ((struct kif_config *)p->p.cf)
-struct proto_config * krt_init_config(int class);
+struct proto_config * krt_init_config(struct config *, int class);
/* krt sysdep */
--
2.1.2
From 071677ee93e42c3097f1c3acb5ad7fc73eaf2509 Mon Sep 17 00:00:00 2001
From: "Alexander V. Chernikov" <[email protected]>
Date: Fri, 13 Feb 2015 13:11:07 +0300
Subject: [PATCH 6/8] * Pass struct config to cfg_copy_list to specify where to
alloc memory * from
---
conf/conf.c | 4 ++--
conf/conf.h | 2 +-
nest/rt-dev.c | 2 +-
proto/radv/radv.c | 2 +-
sysdep/unix/krt.c | 2 +-
5 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/conf/conf.c b/conf/conf.c
index 9f93813..fd619f9 100644
--- a/conf/conf.c
+++ b/conf/conf.c
@@ -547,14 +547,14 @@ cfg_strdup(struct config *c, char *str)
void
-cfg_copy_list(list *dest, list *src, unsigned node_size)
+cfg_copy_list(struct config *c, list *dest, list *src, unsigned node_size)
{
node *dn, *sn;
init_list(dest);
WALK_LIST(sn, *src)
{
- dn = cfg_alloc(node_size);
+ dn = cfl_alloc(c, node_size);
memcpy(dn, sn, node_size);
add_tail(dest, dn);
}
diff --git a/conf/conf.h b/conf/conf.h
index eb8acb5..71da2a1 100644
--- a/conf/conf.h
+++ b/conf/conf.h
@@ -93,7 +93,7 @@ extern linpool *cfg_mem;
#define cfg_allocu(size) lp_allocu(cfg_mem, size)
#define cfg_allocz(size) lp_allocz(cfg_mem, size)
char *cfg_strdup(struct config *c, char *str);
-void cfg_copy_list(list *dest, list *src, unsigned node_size);
+void cfg_copy_list(struct config *c, list *dest, list *src, unsigned node_size);
struct config * config_get_ptr_new(void);
#define cfl_alloc(c, size) lp_alloc((c)->mem, size)
diff --git a/nest/rt-dev.c b/nest/rt-dev.c
index 5d22396..c153c3f 100644
--- a/nest/rt-dev.c
+++ b/nest/rt-dev.c
@@ -108,7 +108,7 @@ dev_copy_config(struct proto_config *dest, struct proto_config *src)
* Copy suffices to be is shallow, because new nodes can be added, but
* old nodes cannot be modified (although they contain internal lists).
*/
- cfg_copy_list(&d->iface_list, &s->iface_list, sizeof(struct iface_patt));
+ cfg_copy_list(dest->global, &d->iface_list, &s->iface_list, sizeof(struct iface_patt));
}
struct protocol proto_device = {
diff --git a/proto/radv/radv.c b/proto/radv/radv.c
index eb2a693..d1bed6e 100644
--- a/proto/radv/radv.c
+++ b/proto/radv/radv.c
@@ -411,7 +411,7 @@ radv_copy_config(struct proto_config *dest, struct proto_config *src)
init_list(&d->patt_list);
/* We copy pref_list, shallow copy suffices */
- cfg_copy_list(&d->pref_list, &s->pref_list, sizeof(struct radv_prefix_config));
+ cfg_copy_list(dest->global, &d->pref_list, &s->pref_list, sizeof(struct radv_prefix_config));
}
static void
diff --git a/sysdep/unix/krt.c b/sysdep/unix/krt.c
index d342f7b..ded42c7 100644
--- a/sysdep/unix/krt.c
+++ b/sysdep/unix/krt.c
@@ -269,7 +269,7 @@ kif_copy_config(struct proto_config *dest, struct proto_config *src)
proto_copy_rest(dest, src, sizeof(struct kif_config));
/* Copy primary addr list */
- cfg_copy_list(&d->primary, &s->primary, sizeof(struct kif_primary_item));
+ cfg_copy_list(dest->global, &d->primary, &s->primary, sizeof(struct kif_primary_item));
/* Fix sysdep parts */
kif_sys_copy_config(d, s);
--
2.1.2
From 9e0ef5395bbe6d17e4836495ff66103892e4a8fe Mon Sep 17 00:00:00 2001
From: "Alexander V. Chernikov" <[email protected]>
Date: Sun, 15 Feb 2015 14:13:55 +0300
Subject: [PATCH 7/8] Add api for dynamic protocol creation based on dynamic
templates.
---
conf/cf-lex.l | 2 +
conf/conf.h | 1 +
nest/config.Y | 4 +-
nest/proto.c | 146 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-
nest/protocol.h | 6 ++-
5 files changed, 156 insertions(+), 3 deletions(-)
diff --git a/conf/cf-lex.l b/conf/cf-lex.l
index b995e10..dfcee5f 100644
--- a/conf/cf-lex.l
+++ b/conf/cf-lex.l
@@ -657,6 +657,8 @@ cf_symbol_class_name(struct symbol *sym)
return "protocol";
case SYM_TEMPLATE:
return "protocol template";
+ case SYM_DYNTEMPLATE:
+ return "dynamic template";
case SYM_FUNCTION:
return "function";
case SYM_FILTER:
diff --git a/conf/conf.h b/conf/conf.h
index 71da2a1..9490377 100644
--- a/conf/conf.h
+++ b/conf/conf.h
@@ -124,6 +124,7 @@ struct symbol {
#define SYM_FILTER 4
#define SYM_TABLE 5
#define SYM_ROA 6
+#define SYM_DYNTEMPLATE 7
#define SYM_VARIABLE 0x100 /* 0x100-0x1ff are variable types */
#define SYM_CONSTANT 0x200 /* 0x200-0x2ff are variable types */
diff --git a/nest/config.Y b/nest/config.Y
index 481d9f5..095a8fe 100644
--- a/nest/config.Y
+++ b/nest/config.Y
@@ -63,7 +63,7 @@ CF_KEYWORDS(PASSWORD, FROM, PASSIVE, TO, ID, EVENTS, PACKETS, PROTOCOLS, INTERFA
CF_KEYWORDS(PRIMARY, STATS, COUNT, FOR, COMMANDS, PREEXPORT, NOEXPORT, GENERATE, ROA)
CF_KEYWORDS(LISTEN, BGP, V6ONLY, DUAL, ADDRESS, PORT, PASSWORDS, DESCRIPTION, SORTED)
CF_KEYWORDS(RELOAD, IN, OUT, MRTDUMP, MESSAGES, RESTRICT, MEMORY, IGP_METRIC, CLASS, DSCP)
-CF_KEYWORDS(GRACEFUL, RESTART, WAIT, MAX, FLUSH, AS)
+CF_KEYWORDS(GRACEFUL, RESTART, WAIT, MAX, FLUSH, AS, DYNAMIC)
CF_ENUM(T_ENUM_RTS, RTS_, DUMMY, STATIC, INHERIT, DEVICE, STATIC_DEVICE, REDIRECT,
RIP, OSPF, OSPF_IA, OSPF_EXT1, OSPF_EXT2, BGP, PIPE)
@@ -171,6 +171,7 @@ CF_ADDTO(conf, proto)
proto_start:
PROTOCOL { $$ = SYM_PROTO; }
| TEMPLATE { $$ = SYM_TEMPLATE; }
+ | DYNAMIC TEMPLATE { $$ = SYM_DYNTEMPLATE; }
;
proto_name:
@@ -191,6 +192,7 @@ proto_name:
this_proto->name = $1->name;
proto_copy_config(this_proto, $3->def);
+ this_proto->class = $1->class;
}
;
diff --git a/nest/proto.c b/nest/proto.c
index 846d172..dda438c 100644
--- a/nest/proto.c
+++ b/nest/proto.c
@@ -398,6 +398,146 @@ proto_init(struct proto_config *c)
return q;
}
+/**
+ * config_create_dynamic - Creates dynamic protocol configuration
+ * @tc = config template to use
+ * @pname - instance name
+ * @p - existing protocol instance, if reconfiguring
+ * @pi - pointer to protocol-specific data
+ *
+ * Function creates all attributes for protocol - symbol of
+ * appropriate type, protocol config and performs necessary bindings.
+ *
+ * Returns pointer to protocol config or NULL.
+ */
+static struct proto_config *
+config_create_dynamic(struct proto_config *tc, char *pname, struct proto *p, void *pi)
+{
+ struct proto_config *c;
+ struct protocol *q;
+ struct symbol *sym;
+
+ q = tc->protocol;
+
+ if (!q->copy_dynconfig)
+ return NULL;
+
+ config_start_edit(tc->global);
+
+ sym = cf_find_symbol(tc->global, pname);
+ if (!sym || sym->class != SYM_VOID)
+ {
+ config_stop_edit();
+ log(L_ERR "Unable to create symbol %s for dynamic %s protocol", pname, q->name);
+ return NULL;
+ }
+ sym->class = SYM_PROTO;
+
+ c = proto_create_config(tc->global, q, SYM_PROTO);
+ proto_copy_config(c, tc);
+ sym->def = c;
+ c->name = sym->name;
+ c->dyn_parent = tc;
+ q->copy_dynconfig(c, p, pi);
+
+ config_stop_edit();
+
+ return c;
+}
+
+/**
+ * proto_create_dynamic - Creates dynamic protocol instance
+ * @tc = config template to use
+ * @pname - instance name
+ * @pi - pointer to protocol-specific data
+ *
+ * Function creates all atrributes for protocol - symbol of
+ * appropriate type, protocol config and protocol itself.
+ * Protocol is started after this.
+ *
+ * Returns pointer to protocol instance or NULL.
+ */
+struct proto *
+proto_create_dynamic(struct proto_config *tc, char *pname, void *pi)
+{
+ struct proto_config *c;
+ struct proto *p = NULL;
+ struct protocol *q;
+
+ q = tc->protocol;
+
+ if (!q->copy_dynconfig)
+ return NULL;
+
+ c = config_create_dynamic(tc, pname, NULL, pi);
+ if (!c)
+ {
+ log(L_ERR "Creating dynamic %s config for %s failed", q->name, pname);
+ return NULL;
+ }
+
+ p = proto_init(c);
+
+ if (!p)
+ {
+ log(L_ERR "Creating dynamic %s protocol instance %s failed", q->name, pname);
+ return NULL;
+ }
+
+ /* Start protocol */
+ proto_rethink_goal(p);
+
+ return p;
+}
+
+/**
+ * proto_reconfigure_dynamic - creates dynamic protocol configuration on request
+ * @p - protocol instance
+ *
+ * Function checks is the protocol is really dynamic and it dynamic
+ * template still exists in new config. If true, it checks if the original
+ * creation conditions still holds by running @retest_dynconfig callback.
+ * At the end, new configuration is created based on new template and running
+ * protocol data.
+ *
+ * Returns pointer to proto_config or NULL,
+ */
+static struct proto_config *
+proto_reconfigure_dynamic(struct config *new, struct proto *p)
+{
+ struct proto_config *oc, *nc;
+ struct symbol *sym;
+
+ DBG("Dynamic protocol %s reconfiguration check\n", p->name);
+ /* Try to find parent dynamic template in new config */
+ oc = p->cf->dyn_parent;
+ sym = cf_find_symbol(new, oc->name);
+ if (!sym || sym->class != SYM_DYNTEMPLATE)
+ {
+ DBG("Wrong dyntemplate symbol %s class: %d\n", oc->name, sym ? sym->class : 0);
+ return NULL;
+ }
+ /* Found parent configuration */
+ nc = sym->def;
+
+ /* Check if dynamic template protocol is the same */
+ if (oc->protocol != nc->protocol)
+ {
+ DBG("Wrong dyntemplate protocol: %s vs %s\n", oc->protocol->name, nc->protocol->name);
+ return NULL;
+ }
+
+ /* Check if condition still holds */
+ if (!nc->protocol->retest_dynconfig(p, nc))
+ {
+ DBG("retest dynconfig failed\n");
+ return NULL;
+ }
+
+ DBG("Start of dynamic protocol %s reconfiguration\n", p->name);
+ return config_create_dynamic(nc, p->name, p, NULL);
+}
+
int proto_reconfig_type; /* Hack to propagate type info to pipe reconfigure hook */
static int
@@ -521,13 +661,17 @@ protos_commit(struct config *new, struct config *old, int force_reconfig, int ty
{
WALK_LIST(oc, old->protos)
{
+ nc = NULL;
p = oc->proto;
sym = cf_find_symbol(new, oc->name);
if (sym && sym->class == SYM_PROTO && !new->shutdown)
+ nc = sym->def;
+ if (!nc && oc->dyn_parent)
+ nc = proto_reconfigure_dynamic(new, p);
+ if (nc)
{
/* Found match, let's check if we can smoothly switch to new configuration */
/* No need to check description */
- nc = sym->def;
nc->proto = p;
/* We will try to reconfigure protocol p */
diff --git a/nest/protocol.h b/nest/protocol.h
index a20b053..0af8757 100644
--- a/nest/protocol.h
+++ b/nest/protocol.h
@@ -57,6 +57,8 @@ struct protocol {
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) */
void (*copy_config)(struct proto_config *, struct proto_config *); /* Copy config from given protocol instance */
+ void (*copy_dynconfig)(struct proto_config *, struct proto *, void *); /* Clone config from given dynamic template */
+ int (*retest_dynconfig)(struct proto *, struct proto_config *);
};
void protos_build(void);
@@ -65,6 +67,7 @@ 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_dump_all(void);
+struct proto *proto_create_dynamic(struct proto_config *tc, char *pname, void *pi);
#define GA_UNKNOWN 0 /* Attribute not recognized */
#define GA_NAME 1 /* Result = name */
@@ -89,7 +92,7 @@ struct proto_config {
struct proto *proto; /* Instance we've created */
char *name;
char *dsc;
- int class; /* SYM_PROTO or SYM_TEMPLATE */
+ int class; /* SYM_PROTO or SYM_TEMPLATE or SYM_DYNTEMPLATE */
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 */
@@ -100,6 +103,7 @@ struct proto_config {
(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 */
+ struct proto_config *dyn_parent; /* Parent dynamic template */
/* Check proto_reconfigure() and proto_copy_config() after changing struct proto_config */
--
2.1.2
From 7d8303ea3210156ed797f23423ed1e53ad365398 Mon Sep 17 00:00:00 2001
From: "Alexander V. Chernikov" <[email protected]>
Date: Sun, 15 Feb 2015 14:24:02 +0300
Subject: [PATCH 8/8] Implement dynamic BGP protocols creation based on
incoming connections.
---
conf/conf.h | 3 +
proto/bgp/bgp.c | 374 +++++++++++++++++++++++++++++++++++++++++++++++++++++
proto/bgp/bgp.h | 9 ++
proto/bgp/config.Y | 15 ++-
4 files changed, 400 insertions(+), 1 deletion(-)
diff --git a/conf/conf.h b/conf/conf.h
index 9490377..334d31c 100644
--- a/conf/conf.h
+++ b/conf/conf.h
@@ -14,6 +14,7 @@
/* Configuration structure */
+struct bgp_protocol_cfg;
struct config {
pool *pool; /* Pool the configuration is stored in */
@@ -51,6 +52,8 @@ struct config {
int obstacle_count; /* Number of items blocking freeing of this config */
int shutdown; /* This is a pseudo-config for daemon shutdown */
bird_clock_t load_time; /* When we've got this configuration */
+
+ struct bgp_protocol_cfg *bgp_cfg; /* generic storage for protocol specific data */
};
/* Please don't use these variables in protocols. Use proto_config->global instead. */
diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c
index 0fd2b68..a6bf7f4 100644
--- a/proto/bgp/bgp.c
+++ b/proto/bgp/bgp.c
@@ -71,6 +71,7 @@
#include "nest/route.h"
#include "nest/cli.h"
#include "nest/locks.h"
+#include "filter/filter.h"
#include "conf/conf.h"
#include "lib/socket.h"
#include "lib/resource.h"
@@ -89,6 +90,40 @@ static void bgp_active(struct bgp_proto *p);
static sock *bgp_setup_listen_sk(ip_addr addr, unsigned port, u32 flags);
static void bgp_update_bfd(struct bgp_proto *p, int use_bfd);
+struct bgp_addr_node {
+ struct f_trie_node tn; /* Information about network */
+ struct bgp_config *c; /* Pointer to protocol config */
+ node addr_node; /* Member of global lladdr_list */
+ node allow_node; /* Member of proto allow_list */
+};
+
+/* Used to pass data to dynamic reconfigure callback */
+struct bgp_dtemplate_pinfo {
+ ip_addr addr;
+};
+
+/**
+ * bgp_get_protocol_config - sets up BGP-specific parameters storage in config
+ *
+ */
+static struct bgp_protocol_cfg *
+bgp_get_protocol_config(struct config *new)
+{
+ struct bgp_protocol_cfg *bgp_cfg;
+
+ bgp_cfg = (struct bgp_protocol_cfg *)new->bgp_cfg;
+ if (!bgp_cfg)
+ {
+ bgp_cfg = cfl_allocz(new, sizeof(struct bgp_protocol_cfg));
+ bgp_cfg->addr_trie = f_new_trie(new->mem, sizeof(struct bgp_addr_node));
+ init_list(&bgp_cfg->lladdr_list);
+ new->bgp_cfg = bgp_cfg;
+ DBG("Set up new bgp-specific config\n");
+ }
+
+ return bgp_cfg;
+}
+
/**
* bgp_open - open a BGP instance
@@ -713,6 +748,271 @@ bgp_connect(struct bgp_proto *p) /* Enter Connect state and start establishing c
}
/**
+ * bgp_print_template - creates proto named based on template
+ * @buf - pointer to buffer storage
+ * @size - size of supplied buffer
+ * @fmt - format string
+ * @tname - protocol table name
+ * @pi - additional data used to create new proto
+ *
+ * Returns new protocol name length or -1
+ */
+static int
+bgp_print_template(char *buf, int size, const char *fmt, const char *tname, struct bgp_dtemplate_pinfo *pi)
+{
+ int len, off;
+ u32 a;
+ char *str;
+ char ipbuf[STD_ADDRESS_P_LENGTH+1];
+
+ for (str=buf ; *fmt ; ++fmt)
+ {
+ if (*fmt != '%')
+ {
+ if (!size)
+ return -1;
+ *str++ = *fmt;
+ size--;
+ continue;
+ }
+ ++fmt;
+ len = 0;
+
+ switch (*fmt)
+ {
+ /* Part of IPv4/IPv6 address */
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+#ifdef IPV6
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ off = (*fmt - '1');
+ a = pi->addr.addr[off / 2];
+ a = ((off % 2) ? a : (a >> 16)) & 0xffff;
+ len = bsnprintf(ipbuf, sizeof(ipbuf), "%x", a);
+ buf += len;
+ size -= len;
+#else
+ off = 32 - (*fmt - '0') * 8;
+ a = ipa_to_u32(pi->addr);
+ a = (a >> off) & 0xFF;
+ len = bsnprintf(ipbuf, sizeof(ipbuf), "%u", a);
+ buf += len;
+ size -= len;
+#endif
+ break;
+
+ /* IP address */
+ case 'I':
+ ip_ntop(pi->addr, ipbuf);
+ len = strlen(ipbuf);
+ break;
+
+ /* Table name */
+ case 'T':
+ len = bsnprintf(ipbuf, sizeof(ipbuf), "%s", tname);
+ len = strlen(ipbuf);
+ break;
+ }
+
+ if (len > size)
+ return -1;
+ if (len)
+ {
+ strcpy(str, ipbuf);
+ str += len;
+ }
+ }
+
+ if (!size)
+ return -1;
+ *str = '\0';
+ return str-buf;
+}
+
+/**
+ * bgp_create_proto - creates new dynamic instance
+ * @tc - pointer to template config
+ * @sk - socket
+ *
+ * Functions compiles protocol name based ot template and address
+ * and tries to create protocol instance itself.
+ *
+ * Returns pointer to instance or NULL.
+ */
+static struct bgp_proto *
+bgp_create_proto(struct bgp_config *tc, sock *sk)
+{
+ struct bgp_dtemplate_pinfo pi;
+ struct bgp_proto *p;
+ struct rtable_config *t;
+ char pname[SYM_MAX_LEN];
+
+ /* Use master table in the template by defaul. */
+ t = tc->c.table;
+ pi.addr = sk->daddr;
+
+ if (bgp_print_template(pname, sizeof(pname), tc->dyn_nameformat, t->name, &pi) == -1)
+ {
+ log(L_ERR "Unable to name connection from %I based on template %s", sk->daddr, tc->c.name);
+ return NULL;
+ }
+ log(L_ERR "Creating new BGP protocol %s from template %s and incoming connection %I",
+ pname, tc->c.name, sk->daddr);
+
+
+ p = (struct bgp_proto *)proto_create_dynamic(&tc->c, pname, &pi);
+ if (!p)
+ return NULL;
+
+ p->start_state = p->cf->capabilities ? BSS_CONNECT : BSS_CONNECT_NOCAP;
+
+ return p;
+}
+
+/**
+ * bgp_add_allow_mask - link new matching CIDR to the dynamic template
+ * @new - global config
+ * @c - bgp config
+ * @addr - prefix address
+ * @plen - mask length
+ *
+ * For addresses with link scope, add record to global linked list.
+ * For global scope, add record to global trie.
+ * In any case, link record to template allow_list.
+ */
+void
+bgp_add_allow_mask(struct config *new, struct bgp_config *c, ip_addr addr, int plen)
+{
+ struct bgp_protocol_cfg *bgp_cfg;
+ struct bgp_addr_node *an = NULL;
+
+ bgp_cfg = bgp_get_protocol_config(new);
+
+ /* Handle link-local addresses differently */
+ if (ipa_has_link_scope(addr) || c->c.class != SYM_DYNTEMPLATE)
+ {
+ /* LL or non-dynamic template. Do not attach to global trie */
+ an = (struct bgp_addr_node *)cfl_allocz(new, sizeof(struct bgp_addr_node));
+ an->tn.addr = addr;
+ an->tn.plen = plen;
+ }
+ else
+ {
+ /*
+ * Global address AND dynamic template.
+ * We should get here only in case of real reconfiguration
+ */
+ an = (struct bgp_addr_node *)trie_add_prefix(bgp_cfg->addr_trie,
+ addr, plen, plen, MAX_PREFIX_LENGTH);
+ if (an->c)
+ cf_error("Prefix %I/%d already exists from %s", addr, plen, an->c->c.name);
+ }
+
+ if (ipa_has_link_scope(addr) && c->c.class == SYM_DYNTEMPLATE)
+ add_tail(&bgp_cfg->lladdr_list, &an->addr_node);
+
+ an->c = c;
+ add_tail(&c->dyn_allow_list, &an->allow_node);
+
+}
+
+static void
+bgp_copy_dynconfig(struct proto_config *c, struct proto *p, void *data)
+{
+ struct bgp_config *new, *oc;
+ struct bgp_dtemplate_pinfo *pi;
+
+ new = (struct bgp_config *)c;
+
+ /* The only thing we have to copy is source address */
+ if (p)
+ {
+ oc = (struct bgp_config *)p->cf;
+ new->remote_ip = oc->remote_ip;
+ }
+ else
+ {
+ pi = (struct bgp_dtemplate_pinfo *)data;
+ new->remote_ip = pi->addr;
+ }
+}
+
+/**
+ * bgp_retest_dynconfig - checks if dynamic instance is still relevant
+ * @p - protocol instance in question
+ * @c - new template to check with
+ *
+ * Checks if @p remote address still matches prefix lists and
+ * interface in @c. Checks also if protocol was used recently.
+ *
+ * Returns non-zero if condition still holds/
+ */
+static int
+bgp_retest_dynconfig(struct proto *p, struct proto_config *c)
+{
+ struct bgp_config *oc, *nc;
+ struct bgp_addr_node *an;
+ node *n;
+ int found;
+
+ nc = (struct bgp_config *)c;
+ oc = (struct bgp_config *)p->cf;
+
+ if (oc->iface != nc->iface)
+ {
+ log(L_ERR "Interface changed for dynamic proto %s: %s vs %s",
+ p->name, oc->iface ? oc->iface->name : "NULL",
+ nc->iface ? nc->iface->name : "NULL");
+ return 0;
+ }
+
+ if (strcmp(oc->dyn_nameformat, nc->dyn_nameformat))
+ {
+ log(L_ERR "Name format changed for dynamic proto %s: %s vs %s",
+ p->name, oc->dyn_nameformat, nc->dyn_nameformat);
+ return 0;
+ }
+
+ if (strcmp(oc->dyn_nameformat, nc->dyn_nameformat))
+ {
+ log(L_ERR "Name format changed for dynamic proto %s: %s vs %s",
+ p->name, oc->dyn_nameformat, nc->dyn_nameformat);
+ return 0;
+ }
+
+ if (p->disabled)
+ {
+ log(L_ERR "Removing disabled dynamic proto %s", p->name);
+ return 0;
+ }
+
+ /* Check all dynamic prefix masks */
+ found = 0;
+ WALK_LIST(n, nc->dyn_allow_list)
+ {
+ an = SKIP_BACK(struct bgp_addr_node, allow_node, n);
+ if (ipa_in_net(oc->remote_ip, an->tn.addr, an->tn.plen))
+ {
+ found = 1;
+ break;
+ }
+ }
+ if (!found)
+ {
+ log(L_ERR "No more matching masks for dynamic proto %s in template %s",
+ p->name, nc->c.name);
+ return 0;
+ }
+
+ return 1;
+}
+
+/**
* bgp_find_proto - find existing proto by socket
* @sk: TCP socket
*
@@ -721,6 +1021,12 @@ static struct bgp_proto *
bgp_find_proto(sock *sk)
{
struct proto_config *pc;
+ struct bgp_addr_node *an;
+ struct bgp_protocol_cfg *bgp_cfg;
+ node *n;
+
+ if (config->shutdown)
+ return NULL;
WALK_LIST(pc, config->protos)
if (pc->protocol == &proto_bgp && pc->proto)
@@ -730,6 +1036,34 @@ bgp_find_proto(sock *sk)
(!ipa_has_link_scope(sk->daddr) || (p->cf->iface == sk->iface)))
return p;
}
+ bgp_cfg = config->bgp_cfg;
+ if (!bgp_cfg)
+ {
+ DBG("No dynamic templates\n");
+ return NULL;
+ }
+ DBG("Searching for %I in dynamic templates masks\n", sk->daddr);
+ /* Next stage: check dynamic masks */
+ if (ipa_has_link_scope(sk->daddr))
+ {
+ WALK_LIST(n, bgp_cfg->lladdr_list)
+ {
+ an = SKIP_BACK(struct bgp_addr_node, addr_node, n);
+ if (!ipa_in_net(sk->daddr, an->tn.addr, an->tn.plen))
+ continue;
+ if (an->c->iface != sk->iface)
+ continue;
+ return bgp_create_proto(an->c, sk);
+ }
+ }
+ else
+ {
+ an = (struct bgp_addr_node *)trie_match_longest_prefix(bgp_cfg->addr_trie,
+ sk->daddr, MAX_PREFIX_LENGTH);
+ DBG("Searching for %I in address trie\n", sk->daddr);
+ if (an)
+ return bgp_create_proto(an->c, sk);
+ }
return NULL;
}
@@ -1204,6 +1538,14 @@ bgp_check_config(struct bgp_config *c)
if (c->secondary && !c->c.table->sorted)
cf_error("BGP with secondary option requires sorted table");
+
+ if (c->c.class == SYM_DYNTEMPLATE)
+ {
+ if (!c->dyn_nameformat)
+ cf_error("Name template has to be specified");
+ if (EMPTY_LIST(c->dyn_allow_list))
+ cf_error("At least one prefix mask has to be specified");
+ }
}
static int
@@ -1237,8 +1579,38 @@ bgp_reconfigure(struct proto *P, struct proto_config *C)
static void
bgp_copy_config(struct proto_config *dest, struct proto_config *src)
{
+ struct bgp_config *nc, *oc;
+ struct bgp_addr_node *an, *xn;
+ node *n;
+
/* Just a shallow copy */
proto_copy_rest(dest, src, sizeof(struct bgp_config));
+
+ nc = (struct bgp_config *)dest;
+ oc = (struct bgp_config *)src;
+ /* Do not blindly copy dynamic allow lists */
+ init_list(&nc->dyn_allow_list);
+ if (dest->class == SYM_TEMPLATE)
+ {
+ /* copy prefix info only to permit dynamic template inheritance */
+ WALK_LIST(n, oc->dyn_allow_list)
+ {
+ an = SKIP_BACK(struct bgp_addr_node, allow_node, n);
+ xn = cfl_allocz(dest->global, sizeof(*xn));
+ xn->tn.addr = an->tn.addr;
+ xn->tn.plen = an->tn.plen;
+ add_tail(&nc->dyn_allow_list, &xn->allow_node);
+ }
+ }
+ else if (dest->class == SYM_DYNTEMPLATE)
+ {
+ /* copy with saving to global trie */
+ WALK_LIST(n, oc->dyn_allow_list)
+ {
+ an = SKIP_BACK(struct bgp_addr_node, allow_node, n);
+ bgp_add_allow_mask(dest->global, nc, an->tn.addr, an->tn.plen);
+ }
+ }
}
@@ -1437,6 +1809,8 @@ struct protocol proto_bgp = {
cleanup: bgp_cleanup,
reconfigure: bgp_reconfigure,
copy_config: bgp_copy_config,
+ copy_dynconfig: bgp_copy_dynconfig,
+ retest_dynconfig: bgp_retest_dynconfig,
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 0fd3a73..c8487b2 100644
--- a/proto/bgp/bgp.h
+++ b/proto/bgp/bgp.h
@@ -63,6 +63,14 @@ struct bgp_config {
char *password; /* Password used for MD5 authentication */
struct rtable_config *igp_table; /* Table used for recursive next hop lookups */
int bfd; /* Use BFD for liveness detection */
+ int dyn_expire; /* Min time to expire inactive dynamic protocols */
+ char *dyn_nameformat; /* Format string to name devived protocols */
+ list dyn_allow_list; /* list of prefixes allowed to connect */
+};
+
+struct bgp_protocol_cfg {
+ struct f_trie *addr_trie; /* trie for global prefixes */
+ list lladdr_list; /* list to store link-local addresses */
};
#define MLL_SELF 1
@@ -197,6 +205,7 @@ void bgp_handle_graceful_restart(struct bgp_proto *p);
void bgp_graceful_restart_done(struct bgp_proto *p);
void bgp_store_error(struct bgp_proto *p, struct bgp_conn *c, u8 class, u32 code);
void bgp_stop(struct bgp_proto *p, unsigned subcode);
+void bgp_add_allow_mask(struct config *new, struct bgp_config *c, ip_addr addr, int plen);
struct rte_source *bgp_find_source(struct bgp_proto *p, u32 path_id);
struct rte_source *bgp_get_source(struct bgp_proto *p, u32 path_id);
diff --git a/proto/bgp/config.Y b/proto/bgp/config.Y
index d0ae064..4c83ba1 100644
--- a/proto/bgp/config.Y
+++ b/proto/bgp/config.Y
@@ -26,7 +26,8 @@ CF_KEYWORDS(BGP, LOCAL, NEIGHBOR, AS, HOLD, TIME, CONNECT, RETRY,
PREFER, OLDER, MISSING, LLADDR, DROP, IGNORE, ROUTE, REFRESH,
INTERPRET, COMMUNITIES, BGP_ORIGINATOR_ID, BGP_CLUSTER_LIST, IGP,
TABLE, GATEWAY, DIRECT, RECURSIVE, MED, TTL, SECURITY, DETERMINISTIC,
- SECONDARY, ALLOW, BFD, ADD, PATHS, RX, TX, GRACEFUL, RESTART, AWARE)
+ SECONDARY, ALLOW, BFD, ADD, PATHS, RX, TX, GRACEFUL, RESTART, AWARE,
+ EXPIRE, INACTIVE)
CF_GRAMMAR
@@ -52,6 +53,7 @@ bgp_proto_start: proto_start BGP {
BGP_CFG->default_local_pref = 100;
BGP_CFG->gr_mode = BGP_GR_AWARE;
BGP_CFG->gr_time = 120;
+ init_list(&BGP_CFG->dyn_allow_list);
}
;
@@ -124,6 +126,17 @@ bgp_proto:
| bgp_proto IGP TABLE rtable ';' { BGP_CFG->igp_table = $4; }
| bgp_proto TTL SECURITY bool ';' { BGP_CFG->ttl_security = $4; }
| bgp_proto BFD bool ';' { BGP_CFG->bfd = $3; cf_check_bfd($3); }
+ | bgp_proto DYNAMIC ALLOW bgp_allow_dynamic ';'
+ | bgp_proto DYNAMIC TEMPLATE NAME text ';' { BGP_CFG->dyn_nameformat = $5; }
+ | bgp_proto DYNAMIC EXPIRE INACTIVE expr ';' { BGP_CFG->dyn_expire = $5; }
+ ;
+
+bgp_allow_dynamic:
+ bgp_allow_dynamic_entry
+ | bgp_allow_dynamic ',' bgp_allow_dynamic_entry
+ ;
+
+bgp_allow_dynamic_entry: prefix_or_ipa { bgp_add_allow_mask(new_config, BGP_CFG, $1.addr, $1.len); }
;
CF_ADDTO(dynamic_attr, BGP_ORIGIN
--
2.1.2