Commit 3ad8bd6964 for frr
commit 3ad8bd6964cb40edfa29e738058f88c22471126b
Author: Abdul Wasey <w453y.me@gmail.com>
Date: Mon Sep 14 07:21:41 2026 +0000
lib: tell keychain users when a lifetime changes
The `keychain_updated` hook fires when a key is created or removed, when
its string changes and when its algorithm changes. It does not fire when
a send or accept lifetime changes, so a user holding the chain is never
told that the period a key may be used in has moved.
That went unnoticed because the users in tree read the chain on the path
that needs it: `key_lookup_for_send` and `key_lookup_for_accept` are
consulted per packet, so a changed period takes effect on the next one
without anyone being notified. A user that was handed the periods ahead
of time instead has nothing to re-read, and there is no expiry hook in
the key chain to fire on its behalf either. bfdd offloading a session to
a data plane is such a user.
Fire the hook from the five lifetime callbacks the way the other leaves
under a key already do. The two dnode helpers hand the keychain back so
each callback has the name to notify with.
Signed-off-by: Abdul Wasey <w453y.me@gmail.com>
diff --git a/lib/keychain_nb.c b/lib/keychain_nb.c
index 8a36948e38..8d7c900d7c 100644
--- a/lib/keychain_nb.c
+++ b/lib/keychain_nb.c
@@ -87,7 +87,7 @@ static int __destroy_nop(struct nb_cb_destroy_args *args)
return NB_OK;
}
-static struct key *__dnode_get_key2(const struct lyd_node *dnode, bool touch)
+static struct key *__dnode_get_key2(const struct lyd_node *dnode, bool touch, struct keychain **kcp)
{
struct keychain *keychain;
const char *name;
@@ -100,10 +100,12 @@ static struct key *__dnode_get_key2(const struct lyd_node *dnode, bool touch)
key = key_lookup(keychain, index);
if (touch)
keychain_touch(keychain);
+ if (kcp)
+ *kcp = keychain;
return key;
}
-static struct key *__dnode_get_key3(const struct lyd_node *dnode, bool touch)
+static struct key *__dnode_get_key3(const struct lyd_node *dnode, bool touch, struct keychain **kcp)
{
struct keychain *keychain;
const char *name;
@@ -116,6 +118,8 @@ static struct key *__dnode_get_key3(const struct lyd_node *dnode, bool touch)
key = key_lookup(keychain, index);
if (touch)
keychain_touch(keychain);
+ if (kcp)
+ *kcp = keychain;
return key;
}
@@ -268,15 +272,16 @@ static const void *key_chains_key_chain_key_lookup_entry(struct nb_cb_lookup_ent
static int __lifetime_create(struct nb_cb_create_args *args, bool send,
bool accept, bool always)
{
+ struct keychain *keychain;
struct key *key;
if (args->event != NB_EV_APPLY)
return NB_OK;
if (always)
- key = __dnode_get_key3(args->dnode, true);
+ key = __dnode_get_key3(args->dnode, true, &keychain);
else
- key = __dnode_get_key2(args->dnode, true);
+ key = __dnode_get_key2(args->dnode, true, &keychain);
if (send) {
key->send.start = 0;
key->send.end = -1;
@@ -287,19 +292,30 @@ static int __lifetime_create(struct nb_cb_create_args *args, bool send,
key->accept.end = -1;
key->accept.duration = 0;
}
+
+ /*
+ * A lifetime is as much a property of the key as its string or its
+ * algorithm. A user that reads the chain on every packet follows a
+ * changed period without being told, but one that was handed the
+ * periods ahead of time - a data plane holding an offloaded session -
+ * has nothing to re-read and would keep the old window.
+ */
+ if (keychain)
+ hook_call(keychain_updated, keychain->name);
return NB_OK;
}
static int __lifetime_start_date_time_modify(struct nb_cb_modify_args *args,
bool send, bool accept)
{
+ struct keychain *keychain;
struct key *key;
time_t time;
if (args->event != NB_EV_APPLY)
return NB_OK;
- key = __dnode_get_key3(args->dnode, true);
+ key = __dnode_get_key3(args->dnode, true, &keychain);
time = yang_dnode_get_date_and_time(args->dnode, NULL);
if (send)
@@ -307,28 +323,50 @@ static int __lifetime_start_date_time_modify(struct nb_cb_modify_args *args,
if (accept)
key->accept.start = time;
+ /*
+ * A lifetime is as much a property of the key as its string or its
+ * algorithm. A user that reads the chain on every packet follows a
+ * changed period without being told, but one that was handed the
+ * periods ahead of time - a data plane holding an offloaded session -
+ * has nothing to re-read and would keep the old window.
+ */
+ if (keychain)
+ hook_call(keychain_updated, keychain->name);
+
return NB_OK;
}
static int __lifetime_no_end_time_create(struct nb_cb_create_args *args,
bool send, bool accept)
{
+ struct keychain *keychain;
struct key *key;
if (args->event != NB_EV_APPLY)
return NB_OK;
- key = __dnode_get_key3(args->dnode, true);
+ key = __dnode_get_key3(args->dnode, true, &keychain);
if (send)
key->send.end = -1;
if (accept)
key->accept.end = -1;
+
+ /*
+ * A lifetime is as much a property of the key as its string or its
+ * algorithm. A user that reads the chain on every packet follows a
+ * changed period without being told, but one that was handed the
+ * periods ahead of time - a data plane holding an offloaded session -
+ * has nothing to re-read and would keep the old window.
+ */
+ if (keychain)
+ hook_call(keychain_updated, keychain->name);
return NB_OK;
}
static int __lifetime_duration_modify(struct nb_cb_modify_args *args, bool send,
bool accept)
{
+ struct keychain *keychain;
struct key *key;
uint32_t duration;
time_t time;
@@ -336,7 +374,7 @@ static int __lifetime_duration_modify(struct nb_cb_modify_args *args, bool send,
if (args->event != NB_EV_APPLY)
return NB_OK;
- key = __dnode_get_key3(args->dnode, true);
+ key = __dnode_get_key3(args->dnode, true, &keychain);
time = yang_dnode_get_date_and_time(args->dnode, "../start-date-time");
duration = yang_dnode_get_uint32(args->dnode, NULL);
@@ -344,25 +382,46 @@ static int __lifetime_duration_modify(struct nb_cb_modify_args *args, bool send,
key->send.end = time + duration;
if (accept)
key->accept.end = time + duration;
+
+ /*
+ * A lifetime is as much a property of the key as its string or its
+ * algorithm. A user that reads the chain on every packet follows a
+ * changed period without being told, but one that was handed the
+ * periods ahead of time - a data plane holding an offloaded session -
+ * has nothing to re-read and would keep the old window.
+ */
+ if (keychain)
+ hook_call(keychain_updated, keychain->name);
return NB_OK;
}
static int __lifetime_end_date_time_modify(struct nb_cb_modify_args *args,
bool send, bool accept)
{
+ struct keychain *keychain;
struct key *key;
time_t time;
if (args->event != NB_EV_APPLY)
return NB_OK;
- key = __dnode_get_key3(args->dnode, true);
+ key = __dnode_get_key3(args->dnode, true, &keychain);
time = yang_dnode_get_date_and_time(args->dnode, NULL);
if (send)
key->send.end = time;
if (accept)
key->accept.end = time;
+
+ /*
+ * A lifetime is as much a property of the key as its string or its
+ * algorithm. A user that reads the chain on every packet follows a
+ * changed period without being told, but one that was handed the
+ * periods ahead of time - a data plane holding an offloaded session -
+ * has nothing to re-read and would keep the old window.
+ */
+ if (keychain)
+ hook_call(keychain_updated, keychain->name);
return NB_OK;
}