BGP: Dynamic BGP
Support for dynamically spawning BGP protocols for incoming connections. Use 'neighbor range' to specify range of valid neighbor addresses, then incoming connections from these addresses spawn new BGP instances.
This commit is contained in:
parent
df092aa1de
commit
e0835db4f1
8 changed files with 193 additions and 20 deletions
|
@ -87,7 +87,7 @@ HASH_DEFINE_REHASH_FN(SYM, struct symbol)
|
||||||
HASH(struct keyword) kw_hash;
|
HASH(struct keyword) kw_hash;
|
||||||
|
|
||||||
|
|
||||||
static struct sym_scope *conf_this_scope;
|
struct sym_scope *conf_this_scope;
|
||||||
|
|
||||||
linpool *cfg_mem;
|
linpool *cfg_mem;
|
||||||
|
|
||||||
|
@ -673,7 +673,8 @@ cf_lex_init(int is_cli, struct config *c)
|
||||||
else
|
else
|
||||||
BEGIN(INITIAL);
|
BEGIN(INITIAL);
|
||||||
|
|
||||||
conf_this_scope = cfg_allocz(sizeof(struct sym_scope));
|
c->root_scope = cfg_allocz(sizeof(struct sym_scope));
|
||||||
|
conf_this_scope = c->root_scope;
|
||||||
conf_this_scope->active = 1;
|
conf_this_scope->active = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -52,6 +52,7 @@ struct config {
|
||||||
int file_fd; /* File descriptor of main configuration file */
|
int file_fd; /* File descriptor of main configuration file */
|
||||||
HASH(struct symbol) sym_hash; /* Lexer: symbol hash table */
|
HASH(struct symbol) sym_hash; /* Lexer: symbol hash table */
|
||||||
struct config *fallback; /* Link to regular config for CLI parsing */
|
struct config *fallback; /* Link to regular config for CLI parsing */
|
||||||
|
struct sym_scope *root_scope; /* Scope for root symbols */
|
||||||
int obstacle_count; /* Number of items blocking freeing of this config */
|
int obstacle_count; /* Number of items blocking freeing of this config */
|
||||||
int shutdown; /* This is a pseudo-config for daemon shutdown */
|
int shutdown; /* This is a pseudo-config for daemon shutdown */
|
||||||
btime load_time; /* When we've got this configuration */
|
btime load_time; /* When we've got this configuration */
|
||||||
|
@ -152,6 +153,8 @@ struct include_file_stack {
|
||||||
|
|
||||||
extern struct include_file_stack *ifs;
|
extern struct include_file_stack *ifs;
|
||||||
|
|
||||||
|
extern struct sym_scope *conf_this_scope;
|
||||||
|
|
||||||
int cf_lex(void);
|
int cf_lex(void);
|
||||||
void cf_lex_init(int is_cli, struct config *c);
|
void cf_lex_init(int is_cli, struct config *c);
|
||||||
void cf_lex_unwind(void);
|
void cf_lex_unwind(void);
|
||||||
|
|
56
nest/proto.c
56
nest/proto.c
|
@ -874,6 +874,28 @@ proto_copy_config(struct proto_config *dest, struct proto_config *src)
|
||||||
dest->protocol->copy_config(dest, src);
|
dest->protocol->copy_config(dest, src);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
proto_clone_config(struct symbol *sym, struct proto_config *parent)
|
||||||
|
{
|
||||||
|
struct proto_config *cf = proto_config_new(parent->protocol, SYM_PROTO);
|
||||||
|
proto_copy_config(cf, parent);
|
||||||
|
cf->name = sym->name;
|
||||||
|
cf->proto = NULL;
|
||||||
|
cf->parent = parent;
|
||||||
|
|
||||||
|
sym->class = cf->class;
|
||||||
|
sym->def = cf;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
proto_undef_clone(struct symbol *sym, struct proto_config *cf)
|
||||||
|
{
|
||||||
|
rem_node(&cf->n);
|
||||||
|
|
||||||
|
sym->class = SYM_VOID;
|
||||||
|
sym->def = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* protos_preconfig - pre-configuration processing
|
* protos_preconfig - pre-configuration processing
|
||||||
* @c: new configuration
|
* @c: new configuration
|
||||||
|
@ -973,6 +995,24 @@ protos_commit(struct config *new, struct config *old, int force_reconfig, int ty
|
||||||
{
|
{
|
||||||
p = oc->proto;
|
p = oc->proto;
|
||||||
sym = cf_find_symbol(new, oc->name);
|
sym = cf_find_symbol(new, oc->name);
|
||||||
|
|
||||||
|
/* Handle dynamic protocols */
|
||||||
|
if (!sym && oc->parent && !new->shutdown)
|
||||||
|
{
|
||||||
|
struct symbol *parsym = cf_find_symbol(new, oc->parent->name);
|
||||||
|
if (parsym && parsym->class == SYM_PROTO)
|
||||||
|
{
|
||||||
|
/* This is hack, we would like to share config, but we need to copy it now */
|
||||||
|
new_config = new;
|
||||||
|
cfg_mem = new->mem;
|
||||||
|
conf_this_scope = new->root_scope;
|
||||||
|
sym = cf_get_symbol(oc->name);
|
||||||
|
proto_clone_config(sym, parsym->def);
|
||||||
|
new_config = NULL;
|
||||||
|
cfg_mem = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (sym && sym->class == SYM_PROTO && !new->shutdown)
|
if (sym && sym->class == SYM_PROTO && !new->shutdown)
|
||||||
{
|
{
|
||||||
/* Found match, let's check if we can smoothly switch to new configuration */
|
/* Found match, let's check if we can smoothly switch to new configuration */
|
||||||
|
@ -984,6 +1024,12 @@ protos_commit(struct config *new, struct config *old, int force_reconfig, int ty
|
||||||
if (! force_reconfig && proto_reconfigure(p, oc, nc, type))
|
if (! force_reconfig && proto_reconfigure(p, oc, nc, type))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
if (nc->parent)
|
||||||
|
{
|
||||||
|
proto_undef_clone(sym, nc);
|
||||||
|
goto remove;
|
||||||
|
}
|
||||||
|
|
||||||
/* Unsuccessful, we will restart it */
|
/* Unsuccessful, we will restart it */
|
||||||
if (!p->disabled && !nc->disabled)
|
if (!p->disabled && !nc->disabled)
|
||||||
log(L_INFO "Restarting protocol %s", p->name);
|
log(L_INFO "Restarting protocol %s", p->name);
|
||||||
|
@ -997,6 +1043,7 @@ protos_commit(struct config *new, struct config *old, int force_reconfig, int ty
|
||||||
}
|
}
|
||||||
else if (!new->shutdown)
|
else if (!new->shutdown)
|
||||||
{
|
{
|
||||||
|
remove:
|
||||||
log(L_INFO "Removing protocol %s", p->name);
|
log(L_INFO "Removing protocol %s", p->name);
|
||||||
p->down_code = PDC_CF_REMOVE;
|
p->down_code = PDC_CF_REMOVE;
|
||||||
p->cf_new = NULL;
|
p->cf_new = NULL;
|
||||||
|
@ -1105,6 +1152,15 @@ proto_rethink_goal(struct proto *p)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct proto *
|
||||||
|
proto_spawn(struct proto_config *cf, uint disabled)
|
||||||
|
{
|
||||||
|
struct proto *p = proto_init(cf, TAIL(proto_list));
|
||||||
|
p->disabled = disabled;
|
||||||
|
proto_rethink_goal(p);
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DOC: Graceful restart recovery
|
* DOC: Graceful restart recovery
|
||||||
|
|
|
@ -89,6 +89,7 @@ void protos_build(void);
|
||||||
void proto_build(struct protocol *);
|
void proto_build(struct protocol *);
|
||||||
void protos_preconfig(struct config *);
|
void protos_preconfig(struct config *);
|
||||||
void protos_commit(struct config *new, struct config *old, int force_restart, int type);
|
void protos_commit(struct config *new, struct config *old, int force_restart, int type);
|
||||||
|
struct proto * proto_spawn(struct proto_config *cf, uint disabled);
|
||||||
void protos_dump_all(void);
|
void protos_dump_all(void);
|
||||||
|
|
||||||
#define GA_UNKNOWN 0 /* Attribute not recognized */
|
#define GA_UNKNOWN 0 /* Attribute not recognized */
|
||||||
|
@ -113,6 +114,7 @@ struct proto_config {
|
||||||
struct config *global; /* Global configuration data */
|
struct config *global; /* Global configuration data */
|
||||||
struct protocol *protocol; /* Protocol */
|
struct protocol *protocol; /* Protocol */
|
||||||
struct proto *proto; /* Instance we've created */
|
struct proto *proto; /* Instance we've created */
|
||||||
|
struct proto_config *parent; /* Parent proto_config for dynamic protocols */
|
||||||
char *name;
|
char *name;
|
||||||
char *dsc;
|
char *dsc;
|
||||||
int class; /* SYM_PROTO or SYM_TEMPLATE */
|
int class; /* SYM_PROTO or SYM_TEMPLATE */
|
||||||
|
@ -263,6 +265,7 @@ struct proto_spec {
|
||||||
void *proto_new(struct proto_config *);
|
void *proto_new(struct proto_config *);
|
||||||
void *proto_config_new(struct protocol *, int class);
|
void *proto_config_new(struct protocol *, int class);
|
||||||
void proto_copy_config(struct proto_config *dest, struct proto_config *src);
|
void proto_copy_config(struct proto_config *dest, struct proto_config *src);
|
||||||
|
void proto_clone_config(struct symbol *sym, struct proto_config *parent);
|
||||||
void proto_set_message(struct proto *p, char *msg, int len);
|
void proto_set_message(struct proto *p, char *msg, int len);
|
||||||
|
|
||||||
void graceful_restart_recovery(void);
|
void graceful_restart_recovery(void);
|
||||||
|
|
117
proto/bgp/bgp.c
117
proto/bgp/bgp.c
|
@ -129,6 +129,9 @@ static list bgp_sockets; /* Global list of listening sockets */
|
||||||
|
|
||||||
static void bgp_connect(struct bgp_proto *p);
|
static void bgp_connect(struct bgp_proto *p);
|
||||||
static void bgp_active(struct bgp_proto *p);
|
static void bgp_active(struct bgp_proto *p);
|
||||||
|
static void bgp_setup_conn(struct bgp_proto *p, struct bgp_conn *conn);
|
||||||
|
static void bgp_setup_sk(struct bgp_conn *conn, sock *s);
|
||||||
|
static void bgp_send_open(struct bgp_conn *conn);
|
||||||
static void bgp_update_bfd(struct bgp_proto *p, int use_bfd);
|
static void bgp_update_bfd(struct bgp_proto *p, int use_bfd);
|
||||||
|
|
||||||
static int bgp_incoming_connection(sock *sk, uint dummy UNUSED);
|
static int bgp_incoming_connection(sock *sk, uint dummy UNUSED);
|
||||||
|
@ -149,7 +152,7 @@ bgp_open(struct bgp_proto *p)
|
||||||
struct bgp_socket *bs = NULL;
|
struct bgp_socket *bs = NULL;
|
||||||
struct iface *ifa = p->cf->strict_bind ? p->cf->iface : NULL;
|
struct iface *ifa = p->cf->strict_bind ? p->cf->iface : NULL;
|
||||||
ip_addr addr = p->cf->strict_bind ? p->cf->local_ip :
|
ip_addr addr = p->cf->strict_bind ? p->cf->local_ip :
|
||||||
(ipa_is_ip4(p->cf->remote_ip) ? IPA_NONE4 : IPA_NONE6);
|
(p->ipv4 ? IPA_NONE4 : IPA_NONE6);
|
||||||
uint port = p->cf->local_port;
|
uint port = p->cf->local_port;
|
||||||
|
|
||||||
/* FIXME: Add some global init? */
|
/* FIXME: Add some global init? */
|
||||||
|
@ -272,8 +275,17 @@ bgp_startup(struct bgp_proto *p)
|
||||||
BGP_TRACE(D_EVENTS, "Started");
|
BGP_TRACE(D_EVENTS, "Started");
|
||||||
p->start_state = BSS_CONNECT;
|
p->start_state = BSS_CONNECT;
|
||||||
|
|
||||||
if (!p->cf->passive)
|
if (!p->passive)
|
||||||
bgp_active(p);
|
bgp_active(p);
|
||||||
|
|
||||||
|
if (p->postponed_sk)
|
||||||
|
{
|
||||||
|
/* Apply postponed incoming connection */
|
||||||
|
bgp_setup_conn(p, &p->incoming_conn);
|
||||||
|
bgp_setup_sk(&p->incoming_conn, p->postponed_sk);
|
||||||
|
bgp_send_open(&p->incoming_conn);
|
||||||
|
p->postponed_sk = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -456,7 +468,7 @@ bgp_decision(void *vp)
|
||||||
if ((p->p.proto_state == PS_START) &&
|
if ((p->p.proto_state == PS_START) &&
|
||||||
(p->outgoing_conn.state == BS_IDLE) &&
|
(p->outgoing_conn.state == BS_IDLE) &&
|
||||||
(p->incoming_conn.state != BS_OPENCONFIRM) &&
|
(p->incoming_conn.state != BS_OPENCONFIRM) &&
|
||||||
!p->cf->passive)
|
!p->passive)
|
||||||
bgp_active(p);
|
bgp_active(p);
|
||||||
|
|
||||||
if ((p->p.proto_state == PS_STOP) &&
|
if ((p->p.proto_state == PS_STOP) &&
|
||||||
|
@ -465,6 +477,29 @@ bgp_decision(void *vp)
|
||||||
bgp_down(p);
|
bgp_down(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct bgp_proto *
|
||||||
|
bgp_spawn(struct bgp_proto *pp, ip_addr remote_ip)
|
||||||
|
{
|
||||||
|
struct symbol *sym;
|
||||||
|
char fmt[SYM_MAX_LEN];
|
||||||
|
|
||||||
|
bsprintf(fmt, "%s%%0%dd", pp->cf->dynamic_name, pp->cf->dynamic_name_digits);
|
||||||
|
|
||||||
|
/* This is hack, we would like to share config, but we need to copy it now */
|
||||||
|
new_config = config;
|
||||||
|
cfg_mem = config->mem;
|
||||||
|
conf_this_scope = config->root_scope;
|
||||||
|
sym = cf_default_name(fmt, &(pp->dynamic_name_counter));
|
||||||
|
proto_clone_config(sym, pp->p.cf);
|
||||||
|
new_config = NULL;
|
||||||
|
cfg_mem = NULL;
|
||||||
|
|
||||||
|
/* Just pass remote_ip to bgp_init() */
|
||||||
|
((struct bgp_config *) sym->def)->remote_ip = remote_ip;
|
||||||
|
|
||||||
|
return (void *) proto_spawn(sym->def, 0);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
bgp_stop(struct bgp_proto *p, uint subcode, byte *data, uint len)
|
bgp_stop(struct bgp_proto *p, uint subcode, byte *data, uint len)
|
||||||
{
|
{
|
||||||
|
@ -1088,6 +1123,9 @@ err:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int bgp_is_dynamic(struct bgp_proto *p)
|
||||||
|
{ return ipa_zero(p->remote_ip); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* bgp_find_proto - find existing proto for incoming connection
|
* bgp_find_proto - find existing proto for incoming connection
|
||||||
* @sk: TCP socket
|
* @sk: TCP socket
|
||||||
|
@ -1096,6 +1134,7 @@ err:
|
||||||
static struct bgp_proto *
|
static struct bgp_proto *
|
||||||
bgp_find_proto(sock *sk)
|
bgp_find_proto(sock *sk)
|
||||||
{
|
{
|
||||||
|
struct bgp_proto *best = NULL;
|
||||||
struct bgp_proto *p;
|
struct bgp_proto *p;
|
||||||
|
|
||||||
/* sk->iface is valid only if src or dst address is link-local */
|
/* sk->iface is valid only if src or dst address is link-local */
|
||||||
|
@ -1103,13 +1142,20 @@ bgp_find_proto(sock *sk)
|
||||||
|
|
||||||
WALK_LIST(p, proto_list)
|
WALK_LIST(p, proto_list)
|
||||||
if ((p->p.proto == &proto_bgp) &&
|
if ((p->p.proto == &proto_bgp) &&
|
||||||
(p->sock == sk->data) &&
|
(ipa_equal(p->remote_ip, sk->daddr) || bgp_is_dynamic(p)) &&
|
||||||
ipa_equal(p->cf->remote_ip, sk->daddr) &&
|
(!p->cf->remote_range || ipa_in_netX(sk->daddr, p->cf->remote_range)) &&
|
||||||
|
(p->p.vrf == sk->vrf) &&
|
||||||
|
(p->cf->local_port == sk->sport) &&
|
||||||
(!link || (p->cf->iface == sk->iface)) &&
|
(!link || (p->cf->iface == sk->iface)) &&
|
||||||
(ipa_zero(p->cf->local_ip) || ipa_equal(p->cf->local_ip, sk->saddr)))
|
(ipa_zero(p->cf->local_ip) || ipa_equal(p->cf->local_ip, sk->saddr)))
|
||||||
return p;
|
{
|
||||||
|
best = p;
|
||||||
|
|
||||||
return NULL;
|
if (!bgp_is_dynamic(p))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return best;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1188,6 +1234,16 @@ bgp_incoming_connection(sock *sk, uint dummy UNUSED)
|
||||||
sk_reallocate(sk);
|
sk_reallocate(sk);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* For dynamic BGP, spawn new instance and postpone the socket */
|
||||||
|
if (bgp_is_dynamic(p))
|
||||||
|
{
|
||||||
|
p = bgp_spawn(p, sk->daddr);
|
||||||
|
p->postponed_sk = sk;
|
||||||
|
rmove(sk, p->p.pool);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
rmove(sk, p->p.pool);
|
||||||
bgp_setup_conn(p, &p->incoming_conn);
|
bgp_setup_conn(p, &p->incoming_conn);
|
||||||
bgp_setup_sk(&p->incoming_conn, sk);
|
bgp_setup_sk(&p->incoming_conn, sk);
|
||||||
bgp_send_open(&p->incoming_conn);
|
bgp_send_open(&p->incoming_conn);
|
||||||
|
@ -1306,7 +1362,7 @@ bgp_bfd_notify(struct bfd_request *req)
|
||||||
static void
|
static void
|
||||||
bgp_update_bfd(struct bgp_proto *p, int use_bfd)
|
bgp_update_bfd(struct bgp_proto *p, int use_bfd)
|
||||||
{
|
{
|
||||||
if (use_bfd && !p->bfd_req)
|
if (use_bfd && !p->bfd_req && !bgp_is_dynamic(p))
|
||||||
p->bfd_req = bfd_request_session(p->p.pool, p->remote_ip, p->local_ip,
|
p->bfd_req = bfd_request_session(p->p.pool, p->remote_ip, p->local_ip,
|
||||||
p->cf->multihop ? NULL : p->neigh->iface,
|
p->cf->multihop ? NULL : p->neigh->iface,
|
||||||
bgp_bfd_notify, p);
|
bgp_bfd_notify, p);
|
||||||
|
@ -1398,7 +1454,7 @@ bgp_start_locked(struct object_lock *lock)
|
||||||
|
|
||||||
DBG("BGP: Got lock\n");
|
DBG("BGP: Got lock\n");
|
||||||
|
|
||||||
if (cf->multihop)
|
if (cf->multihop || bgp_is_dynamic(p))
|
||||||
{
|
{
|
||||||
/* Multi-hop sessions do not use neighbor entries */
|
/* Multi-hop sessions do not use neighbor entries */
|
||||||
bgp_initiate(p);
|
bgp_initiate(p);
|
||||||
|
@ -1433,20 +1489,26 @@ bgp_start(struct proto *P)
|
||||||
const struct bgp_config *cf = p->cf;
|
const struct bgp_config *cf = p->cf;
|
||||||
|
|
||||||
p->local_ip = cf->local_ip;
|
p->local_ip = cf->local_ip;
|
||||||
p->remote_ip = cf->remote_ip;
|
|
||||||
p->local_as = cf->local_as;
|
p->local_as = cf->local_as;
|
||||||
p->remote_as = cf->remote_as;
|
p->remote_as = cf->remote_as;
|
||||||
p->public_as = cf->local_as;
|
p->public_as = cf->local_as;
|
||||||
|
|
||||||
|
/* For dynamic BGP childs, remote_ip is already set */
|
||||||
|
if (ipa_nonzero(cf->remote_ip))
|
||||||
|
p->remote_ip = cf->remote_ip;
|
||||||
|
|
||||||
/* Confederation ID is used for truly external peers */
|
/* Confederation ID is used for truly external peers */
|
||||||
if (p->cf->confederation && !p->is_interior)
|
if (p->cf->confederation && !p->is_interior)
|
||||||
p->public_as = cf->confederation;
|
p->public_as = cf->confederation;
|
||||||
|
|
||||||
|
p->passive = cf->passive || bgp_is_dynamic(p);
|
||||||
|
|
||||||
p->start_state = BSS_PREPARE;
|
p->start_state = BSS_PREPARE;
|
||||||
p->outgoing_conn.state = BS_IDLE;
|
p->outgoing_conn.state = BS_IDLE;
|
||||||
p->incoming_conn.state = BS_IDLE;
|
p->incoming_conn.state = BS_IDLE;
|
||||||
p->neigh = NULL;
|
p->neigh = NULL;
|
||||||
p->bfd_req = NULL;
|
p->bfd_req = NULL;
|
||||||
|
p->postponed_sk = NULL;
|
||||||
p->gr_ready = 0;
|
p->gr_ready = 0;
|
||||||
p->gr_active_num = 0;
|
p->gr_active_num = 0;
|
||||||
|
|
||||||
|
@ -1588,6 +1650,17 @@ bgp_init(struct proto_config *CF)
|
||||||
p->rs_client = cf->rs_client;
|
p->rs_client = cf->rs_client;
|
||||||
p->rr_client = cf->rr_client;
|
p->rr_client = cf->rr_client;
|
||||||
|
|
||||||
|
p->ipv4 = ipa_nonzero(cf->remote_ip) ?
|
||||||
|
ipa_is_ip4(cf->remote_ip) :
|
||||||
|
(cf->remote_range && (cf->remote_range->type == NET_IP4));
|
||||||
|
|
||||||
|
p->remote_ip = cf->remote_ip;
|
||||||
|
p->remote_as = cf->remote_as;
|
||||||
|
|
||||||
|
/* Hack: We use cf->remote_ip just to pass remote_ip from bgp_spawn() */
|
||||||
|
if (cf->c.parent)
|
||||||
|
cf->remote_ip = IPA_NONE;
|
||||||
|
|
||||||
/* Add all channels */
|
/* Add all channels */
|
||||||
struct bgp_channel_config *cc;
|
struct bgp_channel_config *cc;
|
||||||
WALK_LIST(cc, CF->channels)
|
WALK_LIST(cc, CF->channels)
|
||||||
|
@ -1788,9 +1861,12 @@ bgp_postconfig(struct proto_config *CF)
|
||||||
if (!cf->local_as)
|
if (!cf->local_as)
|
||||||
cf_error("Local AS number must be set");
|
cf_error("Local AS number must be set");
|
||||||
|
|
||||||
if (ipa_zero(cf->remote_ip))
|
if (ipa_zero(cf->remote_ip) && !cf->remote_range)
|
||||||
cf_error("Neighbor must be configured");
|
cf_error("Neighbor must be configured");
|
||||||
|
|
||||||
|
if (ipa_zero(cf->local_ip) && cf->strict_bind)
|
||||||
|
cf_error("Local address must be configured for strict bind");
|
||||||
|
|
||||||
if (!cf->remote_as && !cf->peer_type)
|
if (!cf->remote_as && !cf->peer_type)
|
||||||
cf_error("Remote AS number (or peer type) must be set");
|
cf_error("Remote AS number (or peer type) must be set");
|
||||||
|
|
||||||
|
@ -1921,7 +1997,10 @@ bgp_reconfigure(struct proto *P, struct proto_config *CF)
|
||||||
// password item is last and must be checked separately
|
// password item is last and must be checked separately
|
||||||
OFFSETOF(struct bgp_config, password) - sizeof(struct proto_config))
|
OFFSETOF(struct bgp_config, password) - sizeof(struct proto_config))
|
||||||
&& ((!old->password && !new->password)
|
&& ((!old->password && !new->password)
|
||||||
|| (old->password && new->password && !strcmp(old->password, new->password)));
|
|| (old->password && new->password && !strcmp(old->password, new->password)))
|
||||||
|
&& net_equal(old->remote_range, new->remote_range)
|
||||||
|
&& !strcmp(old->dynamic_name, new->dynamic_name)
|
||||||
|
&& (old->dynamic_name_digits == new->dynamic_name_digits);
|
||||||
|
|
||||||
/* FIXME: Move channel reconfiguration to generic protocol code ? */
|
/* FIXME: Move channel reconfiguration to generic protocol code ? */
|
||||||
struct channel *C, *C2;
|
struct channel *C, *C2;
|
||||||
|
@ -1951,6 +2030,9 @@ bgp_reconfigure(struct proto *P, struct proto_config *CF)
|
||||||
if (same)
|
if (same)
|
||||||
p->cf = new;
|
p->cf = new;
|
||||||
|
|
||||||
|
/* Reset name counter */
|
||||||
|
p->dynamic_name_counter = 0;
|
||||||
|
|
||||||
return same;
|
return same;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2081,7 +2163,7 @@ bgp_state_dsc(struct bgp_proto *p)
|
||||||
return "Down";
|
return "Down";
|
||||||
|
|
||||||
int state = MAX(p->incoming_conn.state, p->outgoing_conn.state);
|
int state = MAX(p->incoming_conn.state, p->outgoing_conn.state);
|
||||||
if ((state == BS_IDLE) && (p->start_state >= BSS_CONNECT) && p->cf->passive)
|
if ((state == BS_IDLE) && (p->start_state >= BSS_CONNECT) && p->passive)
|
||||||
return "Passive";
|
return "Passive";
|
||||||
|
|
||||||
return bgp_state_names[state];
|
return bgp_state_names[state];
|
||||||
|
@ -2257,8 +2339,13 @@ bgp_show_proto_info(struct proto *P)
|
||||||
struct bgp_proto *p = (struct bgp_proto *) P;
|
struct bgp_proto *p = (struct bgp_proto *) P;
|
||||||
|
|
||||||
cli_msg(-1006, " BGP state: %s", bgp_state_dsc(p));
|
cli_msg(-1006, " BGP state: %s", bgp_state_dsc(p));
|
||||||
cli_msg(-1006, " Neighbor address: %I%J", p->cf->remote_ip, p->cf->iface);
|
|
||||||
cli_msg(-1006, " Neighbor AS: %u", p->cf->remote_as ?: p->remote_as);
|
if (bgp_is_dynamic(p) && p->cf->remote_range)
|
||||||
|
cli_msg(-1006, " Neighbor range: %N", p->cf->remote_range);
|
||||||
|
else
|
||||||
|
cli_msg(-1006, " Neighbor address: %I%J", p->remote_ip, p->cf->iface);
|
||||||
|
|
||||||
|
cli_msg(-1006, " Neighbor AS: %u", p->remote_as);
|
||||||
|
|
||||||
if (p->gr_active_num)
|
if (p->gr_active_num)
|
||||||
cli_msg(-1006, " Neighbor graceful restart active");
|
cli_msg(-1006, " Neighbor graceful restart active");
|
||||||
|
|
|
@ -124,6 +124,9 @@ struct bgp_config {
|
||||||
u32 disable_after_cease; /* Disable it when cease is received, bitfield */
|
u32 disable_after_cease; /* Disable it when cease is received, bitfield */
|
||||||
|
|
||||||
char *password; /* Password used for MD5 authentication */
|
char *password; /* Password used for MD5 authentication */
|
||||||
|
net_addr *remote_range; /* Allowed neighbor range for dynamic BGP */
|
||||||
|
char *dynamic_name; /* Name pattern for dynamic BGP */
|
||||||
|
int dynamic_name_digits; /* Minimum number of digits for dynamic names */
|
||||||
int check_link; /* Use iface link state for liveness detection */
|
int check_link; /* Use iface link state for liveness detection */
|
||||||
int bfd; /* Use BFD for liveness detection */
|
int bfd; /* Use BFD for liveness detection */
|
||||||
};
|
};
|
||||||
|
@ -270,12 +273,14 @@ struct bgp_proto {
|
||||||
u32 local_id; /* BGP identifier of this router */
|
u32 local_id; /* BGP identifier of this router */
|
||||||
u32 remote_id; /* BGP identifier of the neighbor */
|
u32 remote_id; /* BGP identifier of the neighbor */
|
||||||
u32 rr_cluster_id; /* Route reflector cluster ID */
|
u32 rr_cluster_id; /* Route reflector cluster ID */
|
||||||
int start_state; /* Substates that partitions BS_START */
|
u8 start_state; /* Substates that partitions BS_START */
|
||||||
u8 is_internal; /* Internal BGP session (local_as == remote_as) */
|
u8 is_internal; /* Internal BGP session (local_as == remote_as) */
|
||||||
u8 is_interior; /* Internal or intra-confederation BGP session */
|
u8 is_interior; /* Internal or intra-confederation BGP session */
|
||||||
u8 as4_session; /* Session uses 4B AS numbers in AS_PATH (both sides support it) */
|
u8 as4_session; /* Session uses 4B AS numbers in AS_PATH (both sides support it) */
|
||||||
u8 rr_client; /* Whether neighbor is RR client of me */
|
u8 rr_client; /* Whether neighbor is RR client of me */
|
||||||
u8 rs_client; /* Whether neighbor is RS client of me */
|
u8 rs_client; /* Whether neighbor is RS client of me */
|
||||||
|
u8 ipv4; /* Use IPv4 connection, i.e. remote_ip is IPv4 */
|
||||||
|
u8 passive; /* Do not initiate outgoing connection */
|
||||||
u8 route_refresh; /* Route refresh allowed to send [RFC 2918] */
|
u8 route_refresh; /* Route refresh allowed to send [RFC 2918] */
|
||||||
u8 enhanced_refresh; /* Enhanced refresh is negotiated [RFC 7313] */
|
u8 enhanced_refresh; /* Enhanced refresh is negotiated [RFC 7313] */
|
||||||
u8 gr_ready; /* Neighbor could do graceful restart */
|
u8 gr_ready; /* Neighbor could do graceful restart */
|
||||||
|
@ -292,10 +297,12 @@ struct bgp_proto {
|
||||||
struct neighbor *neigh; /* Neighbor entry corresponding to remote ip, NULL if multihop */
|
struct neighbor *neigh; /* Neighbor entry corresponding to remote ip, NULL if multihop */
|
||||||
struct bgp_socket *sock; /* Shared listening socket */
|
struct bgp_socket *sock; /* Shared listening socket */
|
||||||
struct bfd_request *bfd_req; /* BFD request, if BFD is used */
|
struct bfd_request *bfd_req; /* BFD request, if BFD is used */
|
||||||
|
struct birdsock *postponed_sk; /* Postponed incoming socket for dynamic BGP */
|
||||||
ip_addr link_addr; /* Link-local version of local_ip */
|
ip_addr link_addr; /* Link-local version of local_ip */
|
||||||
event *event; /* Event for respawning and shutting process */
|
event *event; /* Event for respawning and shutting process */
|
||||||
timer *startup_timer; /* Timer used to delay protocol startup due to previous errors (startup_delay) */
|
timer *startup_timer; /* Timer used to delay protocol startup due to previous errors (startup_delay) */
|
||||||
timer *gr_timer; /* Timer waiting for reestablishment after graceful restart */
|
timer *gr_timer; /* Timer waiting for reestablishment after graceful restart */
|
||||||
|
int dynamic_name_counter; /* Counter for dynamic BGP names */
|
||||||
uint startup_delay; /* Delay (in seconds) of protocol startup due to previous errors */
|
uint startup_delay; /* Delay (in seconds) of protocol startup due to previous errors */
|
||||||
btime last_proto_error; /* Time of last error that leads to protocol stop */
|
btime last_proto_error; /* Time of last error that leads to protocol stop */
|
||||||
u8 last_error_class; /* Error class of last error */
|
u8 last_error_class; /* Error class of last error */
|
||||||
|
|
|
@ -29,7 +29,8 @@ CF_KEYWORDS(BGP, LOCAL, NEIGHBOR, AS, HOLD, TIME, CONNECT, RETRY, KEEPALIVE,
|
||||||
SECURITY, DETERMINISTIC, SECONDARY, ALLOW, BFD, ADD, PATHS, RX, TX,
|
SECURITY, DETERMINISTIC, SECONDARY, ALLOW, BFD, ADD, PATHS, RX, TX,
|
||||||
GRACEFUL, RESTART, AWARE, CHECK, LINK, PORT, EXTENDED, MESSAGES, SETKEY,
|
GRACEFUL, RESTART, AWARE, CHECK, LINK, PORT, EXTENDED, MESSAGES, SETKEY,
|
||||||
STRICT, BIND, CONFEDERATION, MEMBER, MULTICAST, FLOW4, FLOW6, LONG,
|
STRICT, BIND, CONFEDERATION, MEMBER, MULTICAST, FLOW4, FLOW6, LONG,
|
||||||
LIVED, STALE, IMPORT, IBGP, EBGP, MANDATORY, INTERNAL, EXTERNAL)
|
LIVED, STALE, IMPORT, IBGP, EBGP, MANDATORY, INTERNAL, EXTERNAL,
|
||||||
|
DYNAMIC, RANGE, NAME, DIGITS)
|
||||||
|
|
||||||
%type <i> bgp_nh
|
%type <i> bgp_nh
|
||||||
%type <i32> bgp_afi
|
%type <i32> bgp_afi
|
||||||
|
@ -68,6 +69,7 @@ bgp_proto_start: proto_start BGP {
|
||||||
BGP_CFG->llgr_mode = -1;
|
BGP_CFG->llgr_mode = -1;
|
||||||
BGP_CFG->llgr_time = 3600;
|
BGP_CFG->llgr_time = 3600;
|
||||||
BGP_CFG->setkey = 1;
|
BGP_CFG->setkey = 1;
|
||||||
|
BGP_CFG->dynamic_name = "dynbgp";
|
||||||
BGP_CFG->check_link = -1;
|
BGP_CFG->check_link = -1;
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
@ -120,11 +122,18 @@ bgp_proto:
|
||||||
}
|
}
|
||||||
| bgp_proto NEIGHBOR bgp_nbr_opts ';'
|
| bgp_proto NEIGHBOR bgp_nbr_opts ';'
|
||||||
| bgp_proto NEIGHBOR ipa ipa_scope bgp_nbr_opts ';' {
|
| bgp_proto NEIGHBOR ipa ipa_scope bgp_nbr_opts ';' {
|
||||||
if (ipa_nonzero(BGP_CFG->remote_ip))
|
if (ipa_nonzero(BGP_CFG->remote_ip) || BGP_CFG->remote_range)
|
||||||
cf_error("Only one neighbor per BGP instance is allowed");
|
cf_error("Only one neighbor per BGP instance is allowed");
|
||||||
BGP_CFG->remote_ip = $3;
|
BGP_CFG->remote_ip = $3;
|
||||||
if ($4) BGP_CFG->iface = $4;
|
if ($4) BGP_CFG->iface = $4;
|
||||||
}
|
}
|
||||||
|
| bgp_proto NEIGHBOR RANGE net_ip bgp_nbr_opts ';' {
|
||||||
|
if (ipa_nonzero(BGP_CFG->remote_ip) || BGP_CFG->remote_range)
|
||||||
|
cf_error("Only one neighbor per BGP instance is allowed");
|
||||||
|
net_addr *n = cfg_alloc($4.length);
|
||||||
|
net_copy(n, &($4));
|
||||||
|
BGP_CFG->remote_range = n;
|
||||||
|
}
|
||||||
| bgp_proto INTERFACE TEXT ';' { BGP_CFG->iface = if_get_by_name($3); }
|
| bgp_proto INTERFACE TEXT ';' { BGP_CFG->iface = if_get_by_name($3); }
|
||||||
| bgp_proto RR CLUSTER ID idval ';' { BGP_CFG->rr_cluster_id = $5; }
|
| bgp_proto RR CLUSTER ID idval ';' { BGP_CFG->rr_cluster_id = $5; }
|
||||||
| bgp_proto RR CLIENT bool ';' { BGP_CFG->rr_client = $4; }
|
| bgp_proto RR CLIENT bool ';' { BGP_CFG->rr_client = $4; }
|
||||||
|
@ -136,6 +145,12 @@ bgp_proto:
|
||||||
| bgp_proto DIRECT ';' { BGP_CFG->multihop = 0; }
|
| bgp_proto DIRECT ';' { BGP_CFG->multihop = 0; }
|
||||||
| bgp_proto MULTIHOP ';' { BGP_CFG->multihop = 64; }
|
| bgp_proto MULTIHOP ';' { BGP_CFG->multihop = 64; }
|
||||||
| bgp_proto MULTIHOP expr ';' { BGP_CFG->multihop = $3; if (($3<1) || ($3>255)) cf_error("Multihop must be in range 1-255"); }
|
| bgp_proto MULTIHOP expr ';' { BGP_CFG->multihop = $3; if (($3<1) || ($3>255)) cf_error("Multihop must be in range 1-255"); }
|
||||||
|
| bgp_proto DYNAMIC NAME text ';' {
|
||||||
|
if (strchr($4, '%')) cf_error("Forbidden character '%%' in dynamic name");
|
||||||
|
if (strlen($4) > (SYM_MAX_LEN - 16)) cf_error("Dynamic name too long");
|
||||||
|
BGP_CFG->dynamic_name = $4;
|
||||||
|
}
|
||||||
|
| bgp_proto DYNAMIC NAME DIGITS expr ';' { BGP_CFG->dynamic_name_digits = $5; if ($5>10) cf_error("Dynamic name digits must be at most 10"); }
|
||||||
| bgp_proto STRICT BIND bool ';' { BGP_CFG->strict_bind = $4; }
|
| bgp_proto STRICT BIND bool ';' { BGP_CFG->strict_bind = $4; }
|
||||||
| bgp_proto PATH METRIC bool ';' { BGP_CFG->compare_path_lengths = $4; }
|
| bgp_proto PATH METRIC bool ';' { BGP_CFG->compare_path_lengths = $4; }
|
||||||
| bgp_proto MED METRIC bool ';' { BGP_CFG->med_metric = $4; }
|
| bgp_proto MED METRIC bool ';' { BGP_CFG->med_metric = $4; }
|
||||||
|
|
|
@ -1082,6 +1082,7 @@ sk_passive_connected(sock *s, int type)
|
||||||
t->fd = fd;
|
t->fd = fd;
|
||||||
t->ttl = s->ttl;
|
t->ttl = s->ttl;
|
||||||
t->tos = s->tos;
|
t->tos = s->tos;
|
||||||
|
t->vrf = s->vrf;
|
||||||
t->rbsize = s->rbsize;
|
t->rbsize = s->rbsize;
|
||||||
t->tbsize = s->tbsize;
|
t->tbsize = s->tbsize;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue