instances are spawned for incoming BGP connections (if source address
matches the network prefix). It is possible to mix regular BGP instances
with dynamic BGP instances and have multiple dynamic BGP instances with
- different ranges.
+ different ranges. These spawned dynamic BGP instances share the parent
+ configuration, therefore by reconfiguring the parent protocol forces
+ reconfiguration of the spawned protocols.
+
+ When the neighbor range is changed, all the spawned dynamic instances
+ shut down. Reconfiguration clears all dynamic instances which were
+ previously disabled by the <cf/disable/ CLI command. This may re-enable
+ connection of some clients otherwise blocked by the disabled instance.
<tag><label id="bgp-iface">interface "<m/text/"</tag>
Define interface we should use for link-local BGP IPv6 sessions.
<item><cf/require hostname/
<item><cf/require graceful restart/
<item><cf/require long lived graceful restart/
+ <item><cf/interface range/ if the already existing option is updated to another value.
</itemize>
<p>Channel options that cause a restart when changed:
<item><cf/max long lived stale time/
</itemize>
+<p>All these configuration changes apply also to the spawned dynamic BGP sessions
+and therefore reconfiguring the parent protocol may lead to shutdown of some or all
+of the dynamic BGP sessions.
+
<sect1>Attributes
<label id="bgp-attr">
cf->remote_ip = sk->daddr;
cf->local_ip = sk->saddr;
cf->iface = sk->iface;
- cf->ipatt = NULL;
struct bgp_proto *p = SKIP_BACK(struct bgp_proto, p, proto_spawn(sym->proto, 0));
p->postponed_sk = sk;
bgp_initiate(p);
}
-static void
-bgp_iface_update(struct bgp_proto *p, uint flags, struct iface *i)
+static bool
+bgp_iface_match(struct bgp_proto *p, struct iface *i)
{
int ps = p->p.proto_state;
ASSERT_DIE(p->cf->strict_bind);
if ((ps == PS_DOWN) || (ps == PS_STOP))
- return;
+ return false;
if (!iface_patt_match(p->cf->ipatt, i, NULL))
- return;
+ return false;
+
+ return true;
+}
+static void
+bgp_iface_update(struct bgp_proto *p, uint flags, struct iface *i)
+{
struct bgp_socket_params params = {
.iface = i,
.vrf = p->p.vrf,
{
struct bgp_proto *p = (struct bgp_proto *) P;
ASSERT_DIE(ipa_zero(p->cf->local_ip));
- bgp_iface_update(p, flags, i);
+ if (bgp_iface_match(p, i))
+ bgp_iface_update(p, flags, i);
}
static void
struct bgp_proto *p = (struct bgp_proto *) P;
ASSERT_DIE(!ipa_zero(p->cf->local_ip));
- if (ipa_equal(i->ip, p->cf->local_ip))
+ if (ipa_equal(i->ip, p->cf->local_ip) && bgp_iface_match(p, i->iface))
bgp_iface_update(p, flags, i->iface);
}
+static void
+bgp_if_reload(struct bgp_proto *p, struct iface_patt *patt)
+{
+ struct iface *iface;
+ struct ifa *a;
+
+ WALK_LIST(iface, iface_list)
+ {
+ bool old = iface_patt_match(p->cf->ipatt, iface, NULL);
+ bool new = iface_patt_match(patt, iface, NULL);
+
+ if (old == new)
+ continue;
+
+ if (ipa_zero(p->cf->local_ip))
+ bgp_iface_update(p, old ? IF_CHANGE_DOWN : IF_CHANGE_UP, iface);
+ else
+ WALK_LIST(a, iface->addrs)
+ if (ipa_equal(a->ip, p->cf->local_ip))
+ bgp_iface_update(p, old ? IF_CHANGE_DOWN : IF_CHANGE_UP, iface);
+ }
+}
+
static void
bgp_neigh_notify(neighbor *n)
{
/* Initialize listening socket list */
init_list(&p->listen);
+ /* Setup interface notification hooks */
+ P->if_notify = (cf->ipatt && ipa_zero(cf->local_ip)) ? bgp_if_notify : NULL;
+ P->ifa_notify = (cf->ipatt && !ipa_zero(cf->local_ip)) ? bgp_ifa_notify : NULL;
+
/* Initialize TCP-AO keys */
init_list(&p->ao.keys);
if (cf->auth_type == BGP_AUTH_AO)
p->remote_ip = cf->remote_ip;
p->remote_as = cf->remote_as;
- P->if_notify = (cf->ipatt && ipa_zero(cf->local_ip)) ? bgp_if_notify : NULL;
- P->ifa_notify = (cf->ipatt && !ipa_zero(cf->local_ip)) ? bgp_ifa_notify : NULL;
-
/* Hack: We use cf->remote_ip just to pass remote_ip from bgp_spawn() */
if (cf->c.parent)
cf->remote_ip = IPA_NONE;
bgp_reconfigure(struct proto *P, struct proto_config *CF)
{
struct bgp_proto *p = (void *) P;
- const struct bgp_config *new = (void *) CF;
+ struct bgp_config *new = (void *) CF;
const struct bgp_config *old = p->cf;
+ /* XXX: There is a section in documentation describing which configuration
+ * changes force BGP restart. When changing this function, you have to update
+ * also that part of documentation. */
+
if (proto_get_router_id(CF) != p->local_id)
return 0;
if (bstrcmp(proto_get_hostname(CF), p->hostname))
return 0;
+ /* Fix the virtual configuration so that memcpy does not fail */
+ if (old->c.parent)
+ {
+ new->remote_ip = old->remote_ip;
+ new->local_ip = old->local_ip;
+
+ /* Pre-check interfaces */
+ if (new->ipatt)
+ {
+ if (!old->iface || !iface_patt_match(new->ipatt, old->iface, NULL))
+ return 0;
+ }
+ else if (new->iface)
+ {
+ if (old->iface != new->iface)
+ return 0;
+ }
+
+ new->iface = old->iface;
+ }
+
int same = !memcmp(((byte *) old) + sizeof(struct proto_config),
((byte *) new) + sizeof(struct proto_config),
// password item is last and must be checked separately
&& !bstrcmp(old->dynamic_name, new->dynamic_name)
&& (old->dynamic_name_digits == new->dynamic_name_digits);
- /* Reconfigure TCP-AP */
+ /* Reconfigure interface notification hooks */
+ same = same && (!P->if_notify == !(new->ipatt && ipa_zero(new->local_ip)));
+ same = same && (!P->ifa_notify == !(new->ipatt && !ipa_zero(new->local_ip)));
+
+ /* Differing pattern lists cause an update of the listening sockets
+ * and also if the connection is up, then active sockets. */
+ bool need_if_reload = same && new->ipatt && old->ipatt && !iface_plists_equal(new->ipatt, old->ipatt);
+ if (need_if_reload && !bgp_is_dynamic(p) && (
+ p->incoming_conn.sk && !iface_patt_match(new->ipatt, p->incoming_conn.sk->iface, NULL) ||
+ p->outgoing_conn.sk && !iface_patt_match(new->ipatt, p->outgoing_conn.sk->iface, NULL)))
+ same = 0;
+
+ /* Reconfigure TCP-AO */
same = same && bgp_reconfigure_ao_keys(p, new);
/* FIXME: Move channel reconfiguration to generic protocol code ? */
if (p->start_state > BSS_PREPARE)
bgp_update_bfd(p, new->bfd);
+ if (need_if_reload)
+ bgp_if_reload(p, new->ipatt);
+
return 1;
}