summaryrefslogtreecommitdiff
path: root/proto
diff options
context:
space:
mode:
authorOndrej Zajicek (work) <santiago@crfreenet.org>2020-11-08 15:33:22 +0100
committerOndrej Zajicek (work) <santiago@crfreenet.org>2020-11-08 15:33:22 +0100
commit9d3fc3062b236f51b2c72a4c2c7b068f1946261d (patch)
tree0a24e42caff1ba4eb004fc1831b1c0b00407216f /proto
parentfc1e3211b109400c0e96f889829c9f5145ac7226 (diff)
BFD: Allow per-request session options
BFD session options are configured per interface in BFD protocol. This patch allows to specify them also per-request in protocols requesting sessions (currently limited to BGP).
Diffstat (limited to 'proto')
-rw-r--r--proto/bfd/bfd.c67
-rw-r--r--proto/bfd/bfd.h12
-rw-r--r--proto/bgp/bgp.c28
-rw-r--r--proto/bgp/bgp.h2
-rw-r--r--proto/bgp/config.Y5
-rw-r--r--proto/ospf/neighbor.c2
-rw-r--r--proto/rip/rip.c2
-rw-r--r--proto/static/static.c2
8 files changed, 90 insertions, 30 deletions
diff --git a/proto/bfd/bfd.c b/proto/bfd/bfd.c
index e303d7a0..417263ef 100644
--- a/proto/bfd/bfd.c
+++ b/proto/bfd/bfd.c
@@ -128,6 +128,18 @@ static inline void bfd_notify_kick(struct bfd_proto *p);
* BFD sessions
*/
+static inline struct bfd_session_config
+bfd_merge_options(const struct bfd_iface_config *cf, const struct bfd_options *opts)
+{
+ return (struct bfd_session_config) {
+ .min_rx_int = opts->min_rx_int ?: cf->min_rx_int,
+ .min_tx_int = opts->min_tx_int ?: cf->min_tx_int,
+ .idle_tx_int = opts->idle_tx_int ?: cf->idle_tx_int,
+ .multiplier = opts->multiplier ?: cf->multiplier,
+ .passive = opts->passive_set ? opts->passive : cf->passive
+ };
+}
+
static void
bfd_session_update_state(struct bfd_session *s, uint state, uint diag)
{
@@ -152,10 +164,10 @@ bfd_session_update_state(struct bfd_session *s, uint state, uint diag)
bfd_unlock_sessions(p);
if (state == BFD_STATE_UP)
- bfd_session_set_min_tx(s, s->ifa->cf->min_tx_int);
+ bfd_session_set_min_tx(s, s->cf.min_tx_int);
if (old_state == BFD_STATE_UP)
- bfd_session_set_min_tx(s, s->ifa->cf->idle_tx_int);
+ bfd_session_set_min_tx(s, s->cf.idle_tx_int);
if (notify)
bfd_notify_kick(p);
@@ -405,7 +417,7 @@ bfd_get_free_id(struct bfd_proto *p)
}
static struct bfd_session *
-bfd_add_session(struct bfd_proto *p, ip_addr addr, ip_addr local, struct iface *iface)
+bfd_add_session(struct bfd_proto *p, ip_addr addr, ip_addr local, struct iface *iface, struct bfd_options *opts)
{
birdloop_enter(p->loop);
@@ -421,15 +433,16 @@ bfd_add_session(struct bfd_proto *p, ip_addr addr, ip_addr local, struct iface *
HASH_INSERT(p->session_hash_id, HASH_ID, s);
HASH_INSERT(p->session_hash_ip, HASH_IP, s);
+ s->cf = bfd_merge_options(ifa->cf, opts);
/* Initialization of state variables - see RFC 5880 6.8.1 */
s->loc_state = BFD_STATE_DOWN;
s->rem_state = BFD_STATE_DOWN;
- s->des_min_tx_int = s->des_min_tx_new = ifa->cf->idle_tx_int;
- s->req_min_rx_int = s->req_min_rx_new = ifa->cf->min_rx_int;
+ s->des_min_tx_int = s->des_min_tx_new = s->cf.idle_tx_int;
+ s->req_min_rx_int = s->req_min_rx_new = s->cf.min_rx_int;
s->rem_min_rx_int = 1;
- s->detect_mult = ifa->cf->multiplier;
- s->passive = ifa->cf->passive;
+ s->detect_mult = s->cf.multiplier;
+ s->passive = s->cf.passive;
s->tx_csn = random_u32();
s->tx_timer = tm_new_init(p->tpool, bfd_tx_timer_hook, s, 0, 0);
@@ -506,15 +519,19 @@ bfd_remove_session(struct bfd_proto *p, struct bfd_session *s)
static void
bfd_reconfigure_session(struct bfd_proto *p, struct bfd_session *s)
{
+ if (EMPTY_LIST(s->request_list))
+ return;
+
birdloop_enter(p->loop);
- struct bfd_iface_config *cf = s->ifa->cf;
+ struct bfd_request *req = SKIP_BACK(struct bfd_request, n, HEAD(s->request_list));
+ s->cf = bfd_merge_options(s->ifa->cf, &req->opts);
- u32 tx = (s->loc_state == BFD_STATE_UP) ? cf->min_tx_int : cf->idle_tx_int;
+ u32 tx = (s->loc_state == BFD_STATE_UP) ? s->cf.min_tx_int : s->cf.idle_tx_int;
bfd_session_set_min_tx(s, tx);
- bfd_session_set_min_rx(s, cf->min_rx_int);
- s->detect_mult = cf->multiplier;
- s->passive = cf->passive;
+ bfd_session_set_min_rx(s, s->cf.min_rx_int);
+ s->detect_mult = s->cf.multiplier;
+ s->passive = s->cf.passive;
bfd_session_control_tx_timer(s, 0);
@@ -639,7 +656,7 @@ bfd_add_request(struct bfd_proto *p, struct bfd_request *req)
u8 state, diag;
if (!s)
- s = bfd_add_session(p, req->addr, req->local, req->iface);
+ s = bfd_add_session(p, req->addr, req->local, req->iface, &req->opts);
rem_node(&req->n);
add_tail(&s->request_list, &req->n);
@@ -698,7 +715,8 @@ static struct resclass bfd_request_class;
struct bfd_request *
bfd_request_session(pool *p, ip_addr addr, ip_addr local,
struct iface *iface, struct iface *vrf,
- void (*hook)(struct bfd_request *), void *data)
+ void (*hook)(struct bfd_request *), void *data,
+ const struct bfd_options *opts)
{
struct bfd_request *req = ralloc(p, &bfd_request_class);
@@ -710,6 +728,9 @@ bfd_request_session(pool *p, ip_addr addr, ip_addr local,
req->iface = iface;
req->vrf = vrf;
+ if (opts)
+ req->opts = *opts;
+
bfd_submit_request(req);
req->hook = hook;
@@ -718,6 +739,20 @@ bfd_request_session(pool *p, ip_addr addr, ip_addr local,
return req;
}
+void
+bfd_update_request(struct bfd_request *req, const struct bfd_options *opts)
+{
+ struct bfd_session *s = req->session;
+
+ if (!memcmp(opts, &req->opts, sizeof(const struct bfd_options)))
+ return;
+
+ req->opts = *opts;
+
+ if (s)
+ bfd_reconfigure_session(s->ifa->bfd, s);
+}
+
static void
bfd_request_free(resource *r)
{
@@ -767,7 +802,7 @@ bfd_neigh_notify(struct neighbor *nb)
if ((nb->scope > 0) && !n->req)
{
ip_addr local = ipa_nonzero(n->local) ? n->local : nb->ifa->ip;
- n->req = bfd_request_session(p->p.pool, n->addr, local, nb->iface, p->p.vrf, NULL, NULL);
+ n->req = bfd_request_session(p->p.pool, n->addr, local, nb->iface, p->p.vrf, NULL, NULL, NULL);
}
if ((nb->scope <= 0) && n->req)
@@ -784,7 +819,7 @@ bfd_start_neighbor(struct bfd_proto *p, struct bfd_neighbor *n)
if (n->multihop)
{
- n->req = bfd_request_session(p->p.pool, n->addr, n->local, NULL, p->p.vrf, NULL, NULL);
+ n->req = bfd_request_session(p->p.pool, n->addr, n->local, NULL, p->p.vrf, NULL, NULL, NULL);
return;
}
diff --git a/proto/bfd/bfd.h b/proto/bfd/bfd.h
index 5c2054cc..83e2a991 100644
--- a/proto/bfd/bfd.h
+++ b/proto/bfd/bfd.h
@@ -61,6 +61,15 @@ struct bfd_iface_config
list *passwords; /* Passwords for authentication */
};
+struct bfd_session_config
+{
+ u32 min_rx_int;
+ u32 min_tx_int;
+ u32 idle_tx_int;
+ u8 multiplier;
+ u8 passive;
+};
+
struct bfd_neighbor
{
node n;
@@ -130,6 +139,9 @@ struct bfd_session
u8 rem_diag;
u32 loc_id; /* Local session ID (local discriminator) */
u32 rem_id; /* Remote session ID (remote discriminator) */
+
+ struct bfd_session_config cf; /* Static configuration parameters */
+
u32 des_min_tx_int; /* Desired min rx interval, local option */
u32 des_min_tx_new; /* Used for des_min_tx_int change */
u32 req_min_rx_int; /* Required min tx interval, local option */
diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c
index b9ed6c78..b34dc325 100644
--- a/proto/bgp/bgp.c
+++ b/proto/bgp/bgp.c
@@ -134,7 +134,7 @@ 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, const struct bfd_options *bfd);
static int bgp_incoming_connection(sock *sk, uint dummy UNUSED);
static void bgp_listen_sock_err(sock *sk UNUSED, int err);
@@ -1357,7 +1357,7 @@ bgp_bfd_notify(struct bfd_request *req)
BGP_TRACE(D_EVENTS, "BFD session down");
bgp_store_error(p, NULL, BE_MISC, BEM_BFD_DOWN);
- if (p->cf->bfd == BGP_BFD_GRACEFUL)
+ if (req->opts.mode == BGP_BFD_GRACEFUL)
{
/* Trigger graceful restart */
if (p->conn && (p->conn->state == BS_ESTABLISHED) && p->gr_ready)
@@ -1380,14 +1380,17 @@ bgp_bfd_notify(struct bfd_request *req)
}
static void
-bgp_update_bfd(struct bgp_proto *p, int use_bfd)
+bgp_update_bfd(struct bgp_proto *p, const struct bfd_options *bfd)
{
- if (use_bfd && !p->bfd_req && !bgp_is_dynamic(p))
+ if (bfd && p->bfd_req)
+ bfd_update_request(p->bfd_req, bfd);
+
+ if (bfd && !p->bfd_req && !bgp_is_dynamic(p))
p->bfd_req = bfd_request_session(p->p.pool, p->remote_ip, p->local_ip,
p->cf->multihop ? NULL : p->neigh->iface,
- p->p.vrf, bgp_bfd_notify, p);
+ p->p.vrf, bgp_bfd_notify, p, bfd);
- if (!use_bfd && p->bfd_req)
+ if (!bfd && p->bfd_req)
{
rfree(p->bfd_req);
p->bfd_req = NULL;
@@ -2138,9 +2141,18 @@ bgp_channel_reconfigure(struct channel *C, struct channel_config *CC, int *impor
}
static void
-bgp_copy_config(struct proto_config *dest UNUSED, struct proto_config *src UNUSED)
+bgp_copy_config(struct proto_config *dest, struct proto_config *src)
{
- /* Just a shallow copy */
+ struct bgp_config *d = (void *) dest;
+ struct bgp_config *s = (void *) src;
+
+ /* Copy BFD options */
+ if (s->bfd)
+ {
+ struct bfd_options *opts = cfg_alloc(sizeof(struct bfd_options));
+ memcpy(opts, s->bfd, sizeof(struct bfd_options));
+ d->bfd = opts;
+ }
}
diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h
index 455f04f9..5f365fcd 100644
--- a/proto/bgp/bgp.h
+++ b/proto/bgp/bgp.h
@@ -130,7 +130,7 @@ struct bgp_config {
const 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 bfd; /* Use BFD for liveness detection */
+ const struct bfd_options *bfd; /* Use BFD for liveness detection */
};
struct bgp_channel_config {
diff --git a/proto/bgp/config.Y b/proto/bgp/config.Y
index 7279560b..dc295645 100644
--- a/proto/bgp/config.Y
+++ b/proto/bgp/config.Y
@@ -190,8 +190,9 @@ bgp_proto:
| bgp_proto LONG LIVED STALE TIME expr ';' { BGP_CFG->llgr_time = $6; }
| bgp_proto TTL SECURITY bool ';' { BGP_CFG->ttl_security = $4; }
| bgp_proto CHECK LINK bool ';' { BGP_CFG->check_link = $4; }
- | bgp_proto BFD bool ';' { BGP_CFG->bfd = $3; cf_check_bfd($3); }
- | bgp_proto BFD GRACEFUL ';' { BGP_CFG->bfd = BGP_BFD_GRACEFUL; cf_check_bfd(1); }
+ | bgp_proto BFD bool ';' { cf_check_bfd($3); BGP_CFG->bfd = $3 ? bfd_new_options() : NULL; }
+ | bgp_proto BFD GRACEFUL ';' { cf_check_bfd(1); struct bfd_options *opts = bfd_new_options(); opts->mode = BGP_BFD_GRACEFUL; BGP_CFG->bfd = opts; }
+ | bgp_proto BFD bfd_opts ';' { BGP_CFG->bfd = $3; cf_check_bfd(1); }
| bgp_proto ENFORCE FIRST AS bool ';' { BGP_CFG->enforce_first_as = $5; }
;
diff --git a/proto/ospf/neighbor.c b/proto/ospf/neighbor.c
index 18692d6e..ca369819 100644
--- a/proto/ospf/neighbor.c
+++ b/proto/ospf/neighbor.c
@@ -777,7 +777,7 @@ ospf_neigh_update_bfd(struct ospf_neighbor *n, int use_bfd)
if (use_bfd && !n->bfd_req)
n->bfd_req = bfd_request_session(n->pool, n->ip, n->ifa->addr->ip,
n->ifa->iface, p->p.vrf,
- ospf_neigh_bfd_hook, n);
+ ospf_neigh_bfd_hook, n, NULL);
if (!use_bfd && n->bfd_req)
{
diff --git a/proto/rip/rip.c b/proto/rip/rip.c
index 5c53ab1e..8b4719f7 100644
--- a/proto/rip/rip.c
+++ b/proto/rip/rip.c
@@ -499,7 +499,7 @@ rip_update_bfd(struct rip_proto *p, struct rip_neighbor *n)
ip_addr saddr = rip_is_v2(p) ? n->ifa->sk->saddr : n->nbr->ifa->ip;
n->bfd_req = bfd_request_session(p->p.pool, n->nbr->addr, saddr,
n->nbr->iface, p->p.vrf,
- rip_bfd_notify, n);
+ rip_bfd_notify, n, NULL);
}
if (!use_bfd && n->bfd_req)
diff --git a/proto/static/static.c b/proto/static/static.c
index 72b14991..16a981ed 100644
--- a/proto/static/static.c
+++ b/proto/static/static.c
@@ -161,7 +161,7 @@ static_update_bfd(struct static_proto *p, struct static_route *r)
// ip_addr local = ipa_nonzero(r->local) ? r->local : nb->ifa->ip;
r->bfd_req = bfd_request_session(p->p.pool, r->via, nb->ifa->ip,
nb->iface, p->p.vrf,
- static_bfd_notify, r);
+ static_bfd_notify, r, NULL);
}
if (!bfd_up && r->bfd_req)