Merge pull request #15469 from LabNConsulting/chopps/keychain-yang

add ietf-key-chain YANG module support
This commit is contained in:
Donald Sharp 2024-03-08 08:15:02 -05:00 committed by GitHub
commit 7e058c201a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
25 changed files with 2723 additions and 1028 deletions

View file

@ -132,6 +132,8 @@ static const struct frr_yang_module_info *const eigrpd_yang_modules[] = {
&frr_interface_info,
&frr_route_map_info,
&frr_vrf_info,
&ietf_key_chain_info,
&ietf_key_chain_deviation_info,
};
/* clang-format off */

View file

@ -678,6 +678,21 @@ vector cmd_describe_command(vector vline, struct vty *vty, int *status)
static struct list *varhandlers = NULL;
static int __add_key_comp(const struct lyd_node *dnode, void *arg)
{
const char *key_value = yang_dnode_get_string(dnode, NULL);
vector_set((vector)arg, XSTRDUP(MTYPE_COMPLETION, key_value));
return YANG_ITER_CONTINUE;
}
static void __get_list_keys(vector comps, const char *xpath)
{
yang_dnode_iterate(__add_key_comp, comps,
vty_shared_candidate_config->dnode, "%s", xpath);
}
void cmd_variable_complete(struct cmd_token *token, const char *arg,
vector comps)
{
@ -694,7 +709,10 @@ void cmd_variable_complete(struct cmd_token *token, const char *arg,
if (cvh->varname && (!token->varname
|| strcmp(cvh->varname, token->varname)))
continue;
cvh->completions(tmpcomps, token);
if (cvh->xpath)
__get_list_keys(tmpcomps, cvh->xpath);
if (cvh->completions)
cvh->completions(tmpcomps, token);
break;
}
@ -753,7 +771,7 @@ void cmd_variable_handler_register(const struct cmd_variable_handler *cvh)
if (!varhandlers)
return;
for (; cvh->completions; cvh++)
for (; cvh->completions || cvh->xpath; cvh++)
listnode_add(varhandlers, (void *)cvh);
}

View file

@ -636,6 +636,7 @@ extern void cmd_banner_motd_line(const char *line);
struct cmd_variable_handler {
const char *tokenname, *varname;
const char *xpath; /* fill comps from set of values at xpath */
void (*completions)(vector out, struct cmd_token *token);
};

File diff suppressed because it is too large Load diff

View file

@ -6,6 +6,8 @@
#ifndef _ZEBRA_KEYCHAIN_H
#define _ZEBRA_KEYCHAIN_H
#include "memory.h"
#include "northbound.h"
#include "qobj.h"
#ifdef __cplusplus
@ -44,6 +46,10 @@ struct keychain_algo_info {
const char *desc;
};
extern const struct frr_yang_module_info ietf_key_chain_info;
extern const struct frr_yang_module_info ietf_key_chain_cli_info;
extern const struct frr_yang_module_info ietf_key_chain_deviation_info;
extern const struct keychain_algo_info algo_info[];
uint16_t keychain_get_block_size(enum keychain_hash_algo key);
uint16_t keychain_get_hash_len(enum keychain_hash_algo key);
@ -55,6 +61,8 @@ const char *keychain_get_algo_name_by_id(enum keychain_hash_algo key);
struct keychain {
char *name;
char *desc;
time_t last_touch;
struct list *key;
@ -81,13 +89,43 @@ struct key {
};
DECLARE_QOBJ_TYPE(key);
DECLARE_MTYPE(KEY);
DECLARE_MTYPE(KEYCHAIN);
DECLARE_MTYPE(KEYCHAIN_DESC);
/* keychain implementation */
extern struct list *keychain_list;
struct keychain *keychain_lookup(const char *name);
struct keychain *keychain_get(const char *name);
void keychain_delete(struct keychain *keychain);
struct key *key_lookup(const struct keychain *keychain, uint32_t index);
struct key *key_get(const struct keychain *keychain, uint32_t index);
void key_delete(struct keychain *keychain, struct key *key);
void keychain_cli_init(void);
extern void key_chains_key_chain_cli_write(struct vty *vty, const struct lyd_node *dnode, bool show_defaults);
extern void key_chains_key_chain_cli_write_end(struct vty *vty, const struct lyd_node *dnode);
extern void key_chains_key_chain_description_cli_write(struct vty *vty, const struct lyd_node *dnode, bool show_defaults);
void key_chains_key_chain_key_cli_write(struct vty *vty, const struct lyd_node *dnode, bool show_defaults);
extern void key_chains_key_chain_key_cli_write_end(struct vty *vty, const struct lyd_node *dnode);
extern void key_chains_key_chain_key_lifetime_send_accept_lifetime_start_date_time_cli_write(struct vty *vty, const struct lyd_node *dnode, bool show_defaults);
extern void key_chains_key_chain_key_lifetime_send_lifetime_start_date_time_cli_write(struct vty *vty, const struct lyd_node *dnode, bool show_defaults);
extern void key_chains_key_chain_key_lifetime_accept_lifetime_start_date_time_cli_write(struct vty *vty, const struct lyd_node *dnode, bool show_defaults);
extern void key_chains_key_chain_key_crypto_algorithm_cli_write(struct vty *vty, const struct lyd_node *dnode, bool show_defaults);
extern void key_chains_key_chain_key_key_string_keystring_cli_write(struct vty *vty, const struct lyd_node *dnode, bool show_defaults);
/* keychain users */
extern void keychain_init(void);
extern void keychain_init_new(bool in_backend);
extern void keychain_terminate(void);
extern struct keychain *keychain_lookup(const char *);
extern struct key *key_lookup_for_accept(const struct keychain *, uint32_t);
extern struct key *key_match_for_accept(const struct keychain *, const char *);
extern struct key *key_lookup_for_send(const struct keychain *);
const char *keychain_algo_str(enum keychain_hash_algo hash_algo);
#ifdef __cplusplus
}
#endif

1033
lib/keychain_cli.c Normal file

File diff suppressed because it is too large Load diff

898
lib/keychain_nb.c Normal file
View file

@ -0,0 +1,898 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* February 22 2024, Christian Hopps <chopps@labn.net>
*
* Copyright (C) 2024 LabN Consulting, L.L.C.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; see the file COPYING; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <zebra.h>
#include "lib_errors.h"
#include "northbound.h"
#include "keychain.h"
static void keychain_touch(struct keychain *keychain)
{
keychain->last_touch = time(NULL);
}
/*
* XPath: /ietf-key-chain:key-chains/key-chain
*/
static int key_chains_key_chain_create(struct nb_cb_create_args *args)
{
const char *name;
struct keychain *keychain;
if (args->event != NB_EV_APPLY)
return NB_OK;
name = yang_dnode_get_string(args->dnode, "name");
keychain = keychain_get(name);
keychain_touch(keychain);
return NB_OK;
}
static int key_chains_key_chain_destroy(struct nb_cb_destroy_args *args)
{
const char *name;
if (args->event != NB_EV_APPLY)
return NB_OK;
name = yang_dnode_get_string(args->dnode, "name");
keychain_delete(keychain_lookup(name));
return NB_OK;
}
static const void *key_chains_key_chain_get_next(struct nb_cb_get_next_args *args)
{
const struct listnode *prev = args->list_entry;
return prev ? prev->next : keychain_list->head;
}
static int key_chains_key_chain_get_keys(struct nb_cb_get_keys_args *args)
{
const struct listnode *node = args->list_entry;
const struct keychain *keychain = node->data;
args->keys->num = 1;
strlcpy(args->keys->key[0], keychain->name, sizeof(args->keys->key[0]));
return NB_OK;
}
static const void *key_chains_key_chain_lookup_entry(struct nb_cb_lookup_entry_args *args)
{
const char *name = args->keys->key[0];
struct keychain *keychain;
struct listnode *node;
for (ALL_LIST_ELEMENTS_RO(keychain_list, node, keychain)) {
if (strcmp(keychain->name, name) == 0)
return node;
}
return NULL;
}
static int __destroy_nop(struct nb_cb_destroy_args *args)
{
/* modified by sibling or cleaned up by container destroy */
return NB_OK;
}
static struct key *__dnode_get_key2(const struct lyd_node *dnode, bool touch)
{
struct keychain *keychain;
const char *name;
struct key *key;
uint32_t index;
name = yang_dnode_get_string(dnode, "../../../name");
keychain = keychain_lookup(name);
index = (uint32_t)yang_dnode_get_uint64(dnode, "../../key-id");
key = key_lookup(keychain, index);
if (touch)
keychain_touch(keychain);
return key;
}
static struct key *__dnode_get_key3(const struct lyd_node *dnode, bool touch)
{
struct keychain *keychain;
const char *name;
struct key *key;
uint32_t index;
name = yang_dnode_get_string(dnode, "../../../../name");
keychain = keychain_lookup(name);
index = (uint32_t)yang_dnode_get_uint64(dnode, "../../../key-id");
key = key_lookup(keychain, index);
if (touch)
keychain_touch(keychain);
return key;
}
/*
* XPath: /ietf-key-chain:key-chains/key-chain/description
*/
static int key_chains_key_chain_description_modify(struct nb_cb_modify_args *args)
{
struct keychain *keychain;
const char *name;
if (args->event != NB_EV_APPLY)
return NB_OK;
name = yang_dnode_get_string(args->dnode, "../name");
keychain = keychain_lookup(name);
XFREE(MTYPE_KEYCHAIN_DESC, keychain->desc);
keychain->desc = XSTRDUP(MTYPE_KEYCHAIN_DESC,
yang_dnode_get_string(args->dnode, NULL));
keychain_touch(keychain);
return NB_OK;
}
static int key_chains_key_chain_description_destroy(struct nb_cb_destroy_args *args)
{
struct keychain *keychain;
const char *name;
if (args->event != NB_EV_APPLY)
return NB_OK;
name = yang_dnode_get_string(args->dnode, "../name");
keychain = keychain_lookup(name);
XFREE(MTYPE_KEYCHAIN_DESC, keychain->desc);
keychain_touch(keychain);
return NB_OK;
}
/*
* XPath: /ietf-key-chain:key-chains/key-chain/last-modified-timestamp
*/
static struct yang_data *key_chains_key_chain_last_modified_timestamp_get_elem(struct nb_cb_get_elem_args *args)
{
const struct listnode *kcnode = args->list_entry;
const struct keychain *keychain = kcnode->data;
return yang_data_new_date_and_time(args->xpath, keychain->last_touch,
false);
}
/*
* XPath: /ietf-key-chain:key-chains/key-chain/key
*/
static int key_chains_key_chain_key_create(struct nb_cb_create_args *args)
{
struct keychain *keychain;
struct key *key;
const char *name;
uint64_t keyid;
if (args->event != NB_EV_VALIDATE && args->event != NB_EV_APPLY)
return NB_OK;
keyid = yang_dnode_get_uint64(args->dnode, "key-id");
if (args->event == NB_EV_VALIDATE) {
if (keyid > UINT32_MAX) {
/* Warn most protocols can't use this value */
flog_err(EC_LIB_NB_CB_CONFIG_VALIDATE,
"Protocols do not accept > 32-bit key-id values");
return NB_EV_VALIDATE;
}
return NB_OK;
}
if (args->event != NB_EV_APPLY)
return NB_OK;
name = yang_dnode_get_string(args->dnode, "../name");
keychain = keychain_lookup(name);
assert(keyid <= UINT32_MAX);
key = key_get(keychain, (uint32_t)keyid);
assert(key);
keychain_touch(keychain);
return NB_OK;
}
static int key_chains_key_chain_key_destroy(struct nb_cb_destroy_args *args)
{
struct keychain *keychain;
struct key *key;
const char *name;
uint64_t keyid;
if (args->event != NB_EV_APPLY)
return NB_OK;
keyid = yang_dnode_get_uint64(args->dnode, "key-id");
if (keyid > UINT32_MAX)
return NB_ERR_NOT_FOUND;
name = yang_dnode_get_string(args->dnode, "../name");
keychain = keychain_lookup(name);
key = key_lookup(keychain, (uint32_t)keyid);
key_delete(keychain, key);
keychain_touch(keychain);
return NB_OK;
}
static const void *key_chains_key_chain_key_get_next(struct nb_cb_get_next_args *args)
{
const struct listnode *kcnode = args->parent_list_entry;
const struct keychain *keychain = kcnode->data;
const struct listnode *prev = args->list_entry;
return prev ? prev->next : keychain->key->head;
}
static int key_chains_key_chain_key_get_keys(struct nb_cb_get_keys_args *args)
{
const struct listnode *node = args->list_entry;
const struct key *key = node->data;
args->keys->num = 1;
snprintf(args->keys->key[0], sizeof(args->keys->key[0]), "%" PRIu32,
key->index);
return NB_OK;
}
static const void *key_chains_key_chain_key_lookup_entry(struct nb_cb_lookup_entry_args *args)
{
const struct listnode *kcnode = args->parent_list_entry;
const struct keychain *keychain = kcnode->data;
struct listnode *node;
struct key *key;
uint32_t index;
index = strtoul(args->keys->key[0], NULL, 0);
for (ALL_LIST_ELEMENTS_RO(keychain->key, node, key))
if (key->index == index)
return node;
return NULL;
}
static int __lifetime_create(struct nb_cb_create_args *args, bool send,
bool accept, bool always)
{
struct key *key;
if (args->event != NB_EV_APPLY)
return NB_OK;
if (always)
key = __dnode_get_key3(args->dnode, true);
else
key = __dnode_get_key2(args->dnode, true);
if (send) {
key->send.start = 0;
key->send.end = -1;
key->send.duration = 0;
}
if (accept) {
key->accept.start = 0;
key->accept.end = -1;
key->accept.duration = 0;
}
return NB_OK;
}
static int __lifetime_start_date_time_modify(struct nb_cb_modify_args *args,
bool send, bool accept)
{
struct key *key;
time_t time;
if (args->event != NB_EV_APPLY)
return NB_OK;
key = __dnode_get_key3(args->dnode, true);
time = yang_dnode_get_date_and_time(args->dnode, NULL);
if (send)
key->send.start = time;
if (accept)
key->accept.start = time;
return NB_OK;
}
static int __lifetime_no_end_time_create(struct nb_cb_create_args *args,
bool send, bool accept)
{
struct key *key;
if (args->event != NB_EV_APPLY)
return NB_OK;
key = __dnode_get_key3(args->dnode, true);
if (send)
key->send.end = -1;
if (accept)
key->accept.end = -1;
return NB_OK;
}
static int __lifetime_duration_modify(struct nb_cb_modify_args *args, bool send,
bool accept)
{
struct key *key;
uint32_t duration;
time_t time;
if (args->event != NB_EV_APPLY)
return NB_OK;
key = __dnode_get_key3(args->dnode, true);
time = yang_dnode_get_date_and_time(args->dnode, "../start-date-time");
duration = yang_dnode_get_uint32(args->dnode, NULL);
if (send)
key->send.end = time + duration;
if (accept)
key->accept.end = time + duration;
return NB_OK;
}
static int __lifetime_end_date_time_modify(struct nb_cb_modify_args *args,
bool send, bool accept)
{
struct key *key;
time_t time;
if (args->event != NB_EV_APPLY)
return NB_OK;
key = __dnode_get_key3(args->dnode, true);
time = yang_dnode_get_date_and_time(args->dnode, NULL);
if (send)
key->send.end = time;
if (accept)
key->accept.end = time;
return NB_OK;
}
/*
* XPath: /ietf-key-chain:key-chains/key-chain/key/lifetime/send-accept-lifetime
*/
static int key_chains_key_chain_key_lifetime_send_accept_lifetime_create(
struct nb_cb_create_args *args)
{
return __lifetime_create(args, true, true, false);
}
/*
* XPath: /ietf-key-chain:key-chains/key-chain/key/lifetime/send-accept-lifetime/always
*/
static int key_chains_key_chain_key_lifetime_send_accept_lifetime_always_create(
struct nb_cb_create_args *args)
{
return __lifetime_create(args, true, true, true);
}
/*
* XPath: /ietf-key-chain:key-chains/key-chain/key/lifetime/send-accept-lifetime/start-date-time
*/
static int
key_chains_key_chain_key_lifetime_send_accept_lifetime_start_date_time_modify(
struct nb_cb_modify_args *args)
{
return __lifetime_start_date_time_modify(args, true, true);
}
/*
* XPath: /ietf-key-chain:key-chains/key-chain/key/lifetime/send-accept-lifetime/no-end-time
*/
static int
key_chains_key_chain_key_lifetime_send_accept_lifetime_no_end_time_create(
struct nb_cb_create_args *args)
{
return __lifetime_no_end_time_create(args, true, true);
}
/*
* XPath: /ietf-key-chain:key-chains/key-chain/key/lifetime/send-accept-lifetime/duration
*/
static int key_chains_key_chain_key_lifetime_send_accept_lifetime_duration_modify(
struct nb_cb_modify_args *args)
{
return __lifetime_duration_modify(args, true, true);
}
/*
* XPath: /ietf-key-chain:key-chains/key-chain/key/lifetime/send-accept-lifetime/end-date-time
*/
static int
key_chains_key_chain_key_lifetime_send_accept_lifetime_end_date_time_modify(
struct nb_cb_modify_args *args)
{
return __lifetime_end_date_time_modify(args, true, true);
}
/*
* XPath: /ietf-key-chain:key-chains/key-chain/key/lifetime/send-lifetime
*/
static int key_chains_key_chain_key_lifetime_send_lifetime_create(
struct nb_cb_create_args *args)
{
return __lifetime_create(args, true, false, false);
}
/*
* XPath: /ietf-key-chain:key-chains/key-chain/key/lifetime/send-lifetime/always
*/
static int key_chains_key_chain_key_lifetime_send_lifetime_always_create(
struct nb_cb_create_args *args)
{
return __lifetime_create(args, true, false, true);
}
/*
* XPath: /ietf-key-chain:key-chains/key-chain/key/lifetime/send-lifetime/start-date-time
*/
static int key_chains_key_chain_key_lifetime_send_lifetime_start_date_time_modify(struct nb_cb_modify_args *args)
{
return __lifetime_start_date_time_modify(args, true, false);
}
/*
* XPath: /ietf-key-chain:key-chains/key-chain/key/lifetime/send-lifetime/no-end-time
*/
static int key_chains_key_chain_key_lifetime_send_lifetime_no_end_time_create(struct nb_cb_create_args *args)
{
return __lifetime_no_end_time_create(args, true, false);
}
/*
* XPath: /ietf-key-chain:key-chains/key-chain/key/lifetime/send-lifetime/duration
*/
static int key_chains_key_chain_key_lifetime_send_lifetime_duration_modify(struct nb_cb_modify_args *args)
{
return __lifetime_duration_modify(args, true, false);
}
/*
* XPath: /ietf-key-chain:key-chains/key-chain/key/lifetime/send-lifetime/end-date-time
*/
static int key_chains_key_chain_key_lifetime_send_lifetime_end_date_time_modify(struct nb_cb_modify_args *args)
{
return __lifetime_end_date_time_modify(args, true, false);
}
/*
* XPath: /ietf-key-chain:key-chains/key-chain/key/lifetime/accept-lifetime
*/
static int key_chains_key_chain_key_lifetime_accept_lifetime_create(
struct nb_cb_create_args *args)
{
return __lifetime_create(args, false, true, false);
}
/*
* XPath: /ietf-key-chain:key-chains/key-chain/key/lifetime/accept-lifetime/always
*/
static int key_chains_key_chain_key_lifetime_accept_lifetime_always_create(struct nb_cb_create_args *args)
{
return __lifetime_create(args, false, true, true);
}
/*
* XPath: /ietf-key-chain:key-chains/key-chain/key/lifetime/accept-lifetime/start-date-time
*/
static int key_chains_key_chain_key_lifetime_accept_lifetime_start_date_time_modify(struct nb_cb_modify_args *args)
{
return __lifetime_start_date_time_modify(args, false, true);
}
/*
* XPath: /ietf-key-chain:key-chains/key-chain/key/lifetime/accept-lifetime/no-end-time
*/
static int key_chains_key_chain_key_lifetime_accept_lifetime_no_end_time_create(struct nb_cb_create_args *args)
{
return __lifetime_no_end_time_create(args, false, true);
}
/*
* XPath: /ietf-key-chain:key-chains/key-chain/key/lifetime/accept-lifetime/duration
*/
static int key_chains_key_chain_key_lifetime_accept_lifetime_duration_modify(struct nb_cb_modify_args *args)
{
return __lifetime_duration_modify(args, false, true);
}
/*
* XPath: /ietf-key-chain:key-chains/key-chain/key/lifetime/accept-lifetime/end-date-time
*/
static int key_chains_key_chain_key_lifetime_accept_lifetime_end_date_time_modify(struct nb_cb_modify_args *args)
{
return __lifetime_end_date_time_modify(args, false, true);
}
/*
* XPath: /ietf-key-chain:key-chains/key-chain/key/crypto-algorithm
*/
static int key_chains_key_chain_key_crypto_algorithm_modify(struct nb_cb_modify_args *args)
{
static const char prefix[] = "ietf-key-chain:";
static const int prefix_len = sizeof(prefix) - 1;
struct keychain *keychain;
const char *name;
struct key *key;
uint32_t index;
uint8_t hash_algo;
if (args->event != NB_EV_VALIDATE && args->event != NB_EV_APPLY)
return NB_OK;
name = yang_dnode_get_string(args->dnode, "../../name");
keychain = keychain_lookup(name);
index = (uint32_t)yang_dnode_get_uint64(args->dnode, "../key-id");
key = key_lookup(keychain, index);
name = yang_dnode_get_string(args->dnode, NULL);
if (!strncmp(name, prefix, prefix_len))
name += prefix_len;
hash_algo = keychain_get_algo_id_by_name(name);
if (args->event == NB_EV_VALIDATE) {
if (!hash_algo) {
zlog_err("\"%s\" hash algo not supported", name);
return NB_ERR_VALIDATION;
}
#ifndef CRYPTO_OPENSSL
if (hash_algo == KEYCHAIN_ALGO_NULL) {
zlog_err("\"%s\" algo not supported, compile with --with-crypto=openssl",
name);
return NB_ERR_VALIDATION;
}
#endif /* CRYPTO_OPENSSL */
return NB_OK;
}
assert(args->event == NB_EV_APPLY);
key->hash_algo = hash_algo;
keychain_touch(keychain);
return NB_OK;
}
static int key_chains_key_chain_key_crypto_algorithm_destroy(
struct nb_cb_destroy_args *args)
{
struct keychain *keychain;
const char *name;
struct key *key;
uint32_t index;
if (args->event != NB_EV_APPLY)
return NB_OK;
name = yang_dnode_get_string(args->dnode, "../../../name");
keychain = keychain_lookup(name);
index = (uint32_t)yang_dnode_get_uint64(args->dnode, "../../key-id");
key = key_lookup(keychain, index);
key->hash_algo = KEYCHAIN_ALGO_NULL;
keychain_touch(keychain);
return NB_OK;
}
/*
* XPath: /ietf-key-chain:key-chains/key-chain/key/key-string/keystring
*/
static int key_chains_key_chain_key_key_string_keystring_modify(struct nb_cb_modify_args *args)
{
struct keychain *keychain;
const char *name;
struct key *key;
uint32_t index;
if (args->event != NB_EV_APPLY)
return NB_OK;
name = yang_dnode_get_string(args->dnode, "../../../name");
keychain = keychain_lookup(name);
index = (uint32_t)yang_dnode_get_uint64(args->dnode, "../../key-id");
key = key_lookup(keychain, index);
assert(key);
if (key->string)
XFREE(MTYPE_KEY, key->string);
key->string = XSTRDUP(MTYPE_KEY,
yang_dnode_get_string(args->dnode, NULL));
keychain_touch(keychain);
return NB_OK;
}
static int key_chains_key_chain_key_key_string_keystring_destroy(struct nb_cb_destroy_args *args)
{
struct keychain *keychain;
const char *name;
struct key *key;
uint32_t index;
if (args->event != NB_EV_APPLY)
return NB_OK;
name = yang_dnode_get_string(args->dnode, "../../../name");
keychain = keychain_lookup(name);
index = (uint32_t)yang_dnode_get_uint64(args->dnode, "../../key-id");
key = key_lookup(keychain, index);
assert(key);
XFREE(MTYPE_KEY, key->string);
keychain_touch(keychain);
return NB_OK;
}
/*
* XPath: /ietf-key-chain:key-chains/key-chain/key/send-lifetime-active
*/
static struct yang_data *key_chains_key_chain_key_send_lifetime_active_get_elem(struct nb_cb_get_elem_args *args)
{
const struct listnode *node = args->list_entry;
const struct key *key = node->data;
time_t now = time(NULL);
bool active = false;
if (key->send.start == 0)
active = true;
else if (key->send.start <= now)
if (key->send.end >= now || key->send.end == -1)
active = true;
return yang_data_new_bool(args->xpath, active);
}
/*
* XPath: /ietf-key-chain:key-chains/key-chain/key/accept-lifetime-active
*/
static struct yang_data *key_chains_key_chain_key_accept_lifetime_active_get_elem(struct nb_cb_get_elem_args *args)
{
const struct listnode *node = args->list_entry;
const struct key *key = node->data;
time_t now = time(NULL);
bool active = false;
if (key->accept.start == 0)
active = true;
else if (key->accept.start <= now)
if (key->accept.end >= now || key->accept.end == -1)
active = true;
return yang_data_new_bool(args->xpath, active);
}
static const char * const keychain_features[] = {
"independent-send-accept-lifetime",
NULL,
};
/* clang-format off */
const struct frr_yang_module_info ietf_key_chain_info = {
.name = "ietf-key-chain",
.features = (const char **)keychain_features,
.nodes = {
{
.xpath = "/ietf-key-chain:key-chains/key-chain",
.cbs = {
.create = key_chains_key_chain_create,
.destroy = key_chains_key_chain_destroy,
.get_next = key_chains_key_chain_get_next,
.get_keys = key_chains_key_chain_get_keys,
.lookup_entry = key_chains_key_chain_lookup_entry,
.cli_show = key_chains_key_chain_cli_write,
.cli_show_end = key_chains_key_chain_cli_write_end,
}
},
{
.xpath = "/ietf-key-chain:key-chains/key-chain/description",
.cbs = {
.modify = key_chains_key_chain_description_modify,
.destroy = key_chains_key_chain_description_destroy,
.cli_show = key_chains_key_chain_description_cli_write,
}
},
{
.xpath = "/ietf-key-chain:key-chains/key-chain/last-modified-timestamp",
.cbs = {
.get_elem = key_chains_key_chain_last_modified_timestamp_get_elem,
}
},
{
.xpath = "/ietf-key-chain:key-chains/key-chain/key",
.cbs = {
.create = key_chains_key_chain_key_create,
.destroy = key_chains_key_chain_key_destroy,
.get_next = key_chains_key_chain_key_get_next,
.get_keys = key_chains_key_chain_key_get_keys,
.lookup_entry = key_chains_key_chain_key_lookup_entry,
.cli_show = key_chains_key_chain_key_cli_write,
.cli_show_end = key_chains_key_chain_key_cli_write_end,
}
},
{
.xpath = "/ietf-key-chain:key-chains/key-chain/key/lifetime/send-accept-lifetime",
.cbs = {
.create = key_chains_key_chain_key_lifetime_send_accept_lifetime_create,
.destroy = __destroy_nop,
}
},
{
.xpath = "/ietf-key-chain:key-chains/key-chain/key/lifetime/send-accept-lifetime/always",
.cbs = {
.create = key_chains_key_chain_key_lifetime_send_accept_lifetime_always_create,
.destroy = __destroy_nop,
}
},
{
.xpath = "/ietf-key-chain:key-chains/key-chain/key/lifetime/send-accept-lifetime/start-date-time",
.cbs = {
.modify = key_chains_key_chain_key_lifetime_send_accept_lifetime_start_date_time_modify,
.destroy = __destroy_nop,
.cli_show = key_chains_key_chain_key_lifetime_send_accept_lifetime_start_date_time_cli_write,
}
},
{
.xpath = "/ietf-key-chain:key-chains/key-chain/key/lifetime/send-accept-lifetime/no-end-time",
.cbs = {
.create = key_chains_key_chain_key_lifetime_send_accept_lifetime_no_end_time_create,
.destroy = __destroy_nop,
}
},
{
.xpath = "/ietf-key-chain:key-chains/key-chain/key/lifetime/send-accept-lifetime/duration",
.cbs = {
.modify = key_chains_key_chain_key_lifetime_send_accept_lifetime_duration_modify,
.destroy = __destroy_nop,
}
},
{
.xpath = "/ietf-key-chain:key-chains/key-chain/key/lifetime/send-accept-lifetime/end-date-time",
.cbs = {
.modify = key_chains_key_chain_key_lifetime_send_accept_lifetime_end_date_time_modify,
.destroy = __destroy_nop,
}
},
{
.xpath = "/ietf-key-chain:key-chains/key-chain/key/lifetime/send-lifetime",
.cbs = {
.create = key_chains_key_chain_key_lifetime_send_lifetime_create,
.destroy = __destroy_nop,
}
},
{
.xpath = "/ietf-key-chain:key-chains/key-chain/key/lifetime/send-lifetime/always",
.cbs = {
.create = key_chains_key_chain_key_lifetime_send_lifetime_always_create,
.destroy = __destroy_nop,
}
},
{
.xpath = "/ietf-key-chain:key-chains/key-chain/key/lifetime/send-lifetime/start-date-time",
.cbs = {
.modify = key_chains_key_chain_key_lifetime_send_lifetime_start_date_time_modify,
.destroy = __destroy_nop,
.cli_show = key_chains_key_chain_key_lifetime_send_lifetime_start_date_time_cli_write,
}
},
{
.xpath = "/ietf-key-chain:key-chains/key-chain/key/lifetime/send-lifetime/no-end-time",
.cbs = {
.create = key_chains_key_chain_key_lifetime_send_lifetime_no_end_time_create,
.destroy = __destroy_nop,
}
},
{
.xpath = "/ietf-key-chain:key-chains/key-chain/key/lifetime/send-lifetime/duration",
.cbs = {
.modify = key_chains_key_chain_key_lifetime_send_lifetime_duration_modify,
.destroy = __destroy_nop,
}
},
{
.xpath = "/ietf-key-chain:key-chains/key-chain/key/lifetime/send-lifetime/end-date-time",
.cbs = {
.modify = key_chains_key_chain_key_lifetime_send_lifetime_end_date_time_modify,
.destroy = __destroy_nop,
}
},
{
.xpath = "/ietf-key-chain:key-chains/key-chain/key/lifetime/accept-lifetime",
.cbs = {
.create = key_chains_key_chain_key_lifetime_accept_lifetime_create,
.destroy = __destroy_nop,
}
},
{
.xpath = "/ietf-key-chain:key-chains/key-chain/key/lifetime/accept-lifetime/always",
.cbs = {
.create = key_chains_key_chain_key_lifetime_accept_lifetime_always_create,
.destroy = __destroy_nop,
}
},
{
.xpath = "/ietf-key-chain:key-chains/key-chain/key/lifetime/accept-lifetime/start-date-time",
.cbs = {
.modify = key_chains_key_chain_key_lifetime_accept_lifetime_start_date_time_modify,
.destroy = __destroy_nop,
.cli_show = key_chains_key_chain_key_lifetime_accept_lifetime_start_date_time_cli_write,
}
},
{
.xpath = "/ietf-key-chain:key-chains/key-chain/key/lifetime/accept-lifetime/no-end-time",
.cbs = {
.create = key_chains_key_chain_key_lifetime_accept_lifetime_no_end_time_create,
.destroy = __destroy_nop,
}
},
{
.xpath = "/ietf-key-chain:key-chains/key-chain/key/lifetime/accept-lifetime/duration",
.cbs = {
.modify = key_chains_key_chain_key_lifetime_accept_lifetime_duration_modify,
.destroy = __destroy_nop,
}
},
{
.xpath = "/ietf-key-chain:key-chains/key-chain/key/lifetime/accept-lifetime/end-date-time",
.cbs = {
.modify = key_chains_key_chain_key_lifetime_accept_lifetime_end_date_time_modify,
.destroy = __destroy_nop,
}
},
{
.xpath = "/ietf-key-chain:key-chains/key-chain/key/crypto-algorithm",
.cbs = {
.modify = key_chains_key_chain_key_crypto_algorithm_modify,
.destroy = key_chains_key_chain_key_crypto_algorithm_destroy,
.cli_show = key_chains_key_chain_key_crypto_algorithm_cli_write,
}
},
{
.xpath = "/ietf-key-chain:key-chains/key-chain/key/key-string/keystring",
.cbs = {
.modify = key_chains_key_chain_key_key_string_keystring_modify,
.destroy = key_chains_key_chain_key_key_string_keystring_destroy,
.cli_show = key_chains_key_chain_key_key_string_keystring_cli_write,
}
},
{
.xpath = "/ietf-key-chain:key-chains/key-chain/key/send-lifetime-active",
.cbs = {
.get_elem = key_chains_key_chain_key_send_lifetime_active_get_elem,
}
},
{
.xpath = "/ietf-key-chain:key-chains/key-chain/key/accept-lifetime-active",
.cbs = {
.get_elem = key_chains_key_chain_key_accept_lifetime_active_get_elem,
}
},
{
.xpath = NULL,
},
},
};

View file

@ -53,6 +53,8 @@ lib_libfrr_la_SOURCES = \
lib/jhash.c \
lib/json.c \
lib/keychain.c \
lib/keychain_cli.c \
lib/keychain_nb.c \
lib/ldp_sync.c \
lib/lib_errors.c \
lib/lib_vty.c \
@ -148,7 +150,9 @@ nodist_lib_libfrr_la_SOURCES = \
yang/frr-vrf.yang.c \
yang/frr-routing.yang.c \
yang/frr-nexthop.yang.c \
yang/ietf/frr-deviations-ietf-key-chain.yang.c \
yang/ietf/ietf-routing-types.yang.c \
yang/ietf/ietf-key-chain.yang.c \
yang/ietf/ietf-interfaces.yang.c \
yang/ietf/ietf-bgp-types.yang.c \
yang/frr-module-translator.yang.c \
@ -181,6 +185,7 @@ clippy_scan += \
lib/if.c \
lib/filter_cli.c \
lib/if_rmap.c \
lib/keychain_cli.c \
lib/log_vty.c \
lib/mgmt_be_client.c \
lib/mgmt_fe_client.c \

View file

@ -1026,30 +1026,50 @@ void yang_dnode_get_mac(struct ethaddr *mac, const struct lyd_node *dnode,
(void)prefix_str2mac(canon, mac);
}
struct yang_data *yang_data_new_date_and_time(const char *xpath, time_t time)
struct yang_data *yang_data_new_date_and_time(const char *xpath, time_t time, bool is_monotime)
{
struct tm tm;
char timebuf[MONOTIME_STRLEN];
struct timeval _time, time_real;
char *ts_dot;
uint16_t buflen;
struct yang_data *yd;
char *times = NULL;
_time.tv_sec = time;
_time.tv_usec = 0;
monotime_to_realtime(&_time, &time_real);
if (is_monotime) {
struct timeval _time = { time, 0 };
struct timeval time_real;
gmtime_r(&time_real.tv_sec, &tm);
monotime_to_realtime(&_time, &time_real);
time = time_real.tv_sec;
}
/* rfc-3339 format */
strftime(timebuf, sizeof(timebuf), "%Y-%m-%dT%H:%M:%S", &tm);
buflen = strlen(timebuf);
ts_dot = timebuf + buflen;
(void)ly_time_time2str(time, NULL, &times);
yd = yang_data_new(xpath, times);
free(times);
/* microseconds and appends Z */
snprintfrr(ts_dot, sizeof(timebuf) - buflen, ".%06luZ",
(unsigned long)time_real.tv_usec);
return yd;
}
return yang_data_new(xpath, timebuf);
struct timespec yang_dnode_get_date_and_timespec(const struct lyd_node *dnode,
const char *xpath_fmt, ...)
{
const char *canon = YANG_DNODE_XPATH_GET_CANON(dnode, xpath_fmt);
struct timespec ts;
LY_ERR err;
err = ly_time_str2ts(canon, &ts);
assert(!err);
return ts;
}
time_t yang_dnode_get_date_and_time(const struct lyd_node *dnode,
const char *xpath_fmt, ...)
{
const char *canon = YANG_DNODE_XPATH_GET_CANON(dnode, xpath_fmt);
time_t time;
LY_ERR err;
err = ly_time_str2time(canon, &time, NULL);
assert(!err);
return time;
}
float yang_dnode_get_bandwidth_ieee_float32(const struct lyd_node *dnode,

View file

@ -7,6 +7,7 @@
#ifndef _FRR_NORTHBOUND_WRAPPERS_H_
#define _FRR_NORTHBOUND_WRAPPERS_H_
#include <libyang/libyang.h>
#include "prefix.h"
#ifdef __cplusplus
@ -200,7 +201,14 @@ extern void yang_dnode_get_mac(struct ethaddr *mac, const struct lyd_node *dnode
/*data-and-time */
extern struct yang_data *yang_data_new_date_and_time(const char *xpath,
time_t time);
time_t time,
bool is_monotime);
struct timespec yang_dnode_get_date_and_timespec(const struct lyd_node *dnode,
const char *xpath_fmt, ...)
PRINTFRR(2, 3);
time_t yang_dnode_get_date_and_time(const struct lyd_node *dnode,
const char *xpath_fmt, ...)
PRINTFRR(2, 3);
/* rt-types:bandwidth-ieee-float32 */
extern float yang_dnode_get_bandwidth_ieee_float32(const struct lyd_node *dnode,

View file

@ -90,10 +90,12 @@ static const char *const ripd_config_xpaths[] = {
"/frr-ripd:ripd",
"/frr-route-map:lib",
"/frr-vrf:lib",
"/ietf-key-chain:key-chains",
NULL,
};
static const char *const ripd_oper_xpaths[] = {
"/frr-ripd:ripd",
"/ietf-key-chain:key-chains",
NULL,
};
#endif

View file

@ -10,6 +10,7 @@
#include "lib/version.h"
#include "routemap.h"
#include "filter.h"
#include "keychain.h"
#include "libfrr.h"
#include "frr_pthread.h"
#include "mgmtd/mgmt.h"
@ -185,6 +186,8 @@ static const struct frr_yang_module_info *const mgmt_yang_modules[] = {
&frr_zebra_cli_info,
&zebra_route_map_info,
&ietf_key_chain_cli_info,
&ietf_key_chain_deviation_info,
#ifdef HAVE_RIPD
&frr_ripd_cli_info,
@ -199,20 +202,20 @@ static const struct frr_yang_module_info *const mgmt_yang_modules[] = {
/* clang-format off */
FRR_DAEMON_INFO(mgmtd, MGMTD,
.vty_port = MGMTD_VTY_PORT,
.proghelp = "FRR Management Daemon.",
.vty_port = MGMTD_VTY_PORT,
.proghelp = "FRR Management Daemon.",
.signals = mgmt_signals,
.n_signals = array_size(mgmt_signals),
.signals = mgmt_signals,
.n_signals = array_size(mgmt_signals),
.privs = &mgmt_privs,
.privs = &mgmt_privs,
.yang_modules = mgmt_yang_modules,
.n_yang_modules = array_size(mgmt_yang_modules),
.yang_modules = mgmt_yang_modules,
.n_yang_modules = array_size(mgmt_yang_modules),
/* avoid libfrr trying to read our config file for us */
.flags = FRR_MANUAL_VTY_START | FRR_NO_SPLIT_CONFIG,
);
/* avoid libfrr trying to read our config file for us */
.flags = FRR_MANUAL_VTY_START | FRR_NO_SPLIT_CONFIG,
);
/* clang-format on */
#define DEPRECATED_OPTIONS ""

View file

@ -12,6 +12,7 @@
#include "command.h"
#include "filter.h"
#include "json.h"
#include "keychain.h"
#include "network.h"
#include "northbound_cli.h"
#include "routemap.h"
@ -600,6 +601,7 @@ void mgmt_vty_init(void)
filter_cli_init();
route_map_cli_init();
affinity_map_init();
keychain_cli_init();
/*
* Initialize command handling from VTYSH connection.

View file

@ -169,6 +169,8 @@ static const struct frr_yang_module_info *const ospf6d_yang_modules[] = {
&frr_vrf_info,
&frr_ospf_route_map_info,
&frr_ospf6_route_map_info,
&ietf_key_chain_info,
&ietf_key_chain_deviation_info,
};
/* actual paths filled in main() */
@ -182,19 +184,19 @@ static char *state_paths[] = {
/* clang-format off */
FRR_DAEMON_INFO(ospf6d, OSPF6,
.vty_port = OSPF6_VTY_PORT,
.proghelp = "Implementation of the OSPFv3 routing protocol.",
.vty_port = OSPF6_VTY_PORT,
.proghelp = "Implementation of the OSPFv3 routing protocol.",
.signals = ospf6_signals,
.n_signals = array_size(ospf6_signals),
.signals = ospf6_signals,
.n_signals = array_size(ospf6_signals),
.privs = &ospf6d_privs,
.privs = &ospf6d_privs,
.yang_modules = ospf6d_yang_modules,
.n_yang_modules = array_size(ospf6d_yang_modules),
.yang_modules = ospf6d_yang_modules,
.n_yang_modules = array_size(ospf6d_yang_modules),
.state_paths = state_paths,
);
.state_paths = state_paths,
);
/* clang-format on */
/* Max wait time for config to load before accepting hellos */

View file

@ -134,6 +134,8 @@ static const struct frr_yang_module_info *const ospfd_yang_modules[] = {
&frr_route_map_info,
&frr_vrf_info,
&frr_ospf_route_map_info,
&ietf_key_chain_info,
&ietf_key_chain_deviation_info,
};
/* actual paths filled in main() */

View file

@ -36,7 +36,7 @@ daemon_flags = {
"lib/filter.c": "VTYSH_ACL_SHOW",
"lib/filter_cli.c": "VTYSH_ACL_CONFIG",
"lib/if.c": "VTYSH_INTERFACE",
"lib/keychain.c": "VTYSH_KEYS",
"lib/keychain_cli.c": "VTYSH_KEYS",
"lib/mgmt_be_client.c": "VTYSH_MGMT_BACKEND",
"lib/mgmt_fe_client.c": "VTYSH_MGMT_FRONTEND",
"lib/lib_vty.c": "VTYSH_ALL",

View file

@ -131,6 +131,8 @@ static const struct frr_yang_module_info *const ripd_yang_modules[] = {
&frr_ripd_info,
&frr_route_map_info,
&frr_vrf_info,
&ietf_key_chain_info,
&ietf_key_chain_deviation_info,
};
/* clang-format off */
@ -189,7 +191,7 @@ int main(int argc, char **argv)
/* Library initialization. */
rip_error_init();
keychain_init();
keychain_init_new(true);
rip_vrf_init();
/* RIP related initialization. */

View file

@ -0,0 +1,31 @@
log timestamp precision 6
log file frr.log debug
! debug northbound libyang
debug northbound notifications
debug northbound events
debug northbound callbacks
debug mgmt backend datastore frontend transaction
debug mgmt client frontend
debug mgmt client backend
interface r1-eth0
ip address 1.1.1.1/24
ip ospf hello-interval 2
ip ospf dead-interval 10
exit
router ospf
ospf router-id 1.1.1.1
network 1.1.1.0/24 area 0
exit
router rip
network 1.1.1.0/24
network r1-eth0
exit
!ip route 250.0.0.1/32 Null0

View file

@ -0,0 +1,20 @@
log timestamp precision 6
log file frr.log debug
interface r2-eth0
ip address 1.1.1.2/24
ip ospf hello-interval 2
ip ospf dead-interval 10
exit
router ospf
ospf router-id 2.2.2.2
network 1.1.1.0/24 area 0
exit
router rip
network 1.1.1.0/24
exit
ip route 250.0.0.2/32 Null0

View file

@ -0,0 +1,150 @@
#!/usr/bin/env python
# -*- coding: utf-8 eval: (blacken-mode 1) -*-
# SPDX-License-Identifier: ISC
#
# March 4 2024, Christian Hopps <chopps@labn.net>
#
# Copyright (c) 2024, LabN Consulting, L.L.C.
#
"""
Test static route functionality
"""
import json
import pytest
from lib.topogen import Topogen
pytestmark = [pytest.mark.ripd, pytest.mark.mgmtd]
@pytest.fixture(scope="module")
def tgen(request):
"Setup/Teardown the environment and provide tgen argument to tests"
topodef = {"s1": ("r1", "r2")}
tgen = Topogen(topodef, request.module.__name__)
tgen.start_topology()
router_list = tgen.routers()
for rname, router in router_list.items():
router.load_frr_config("frr.conf")
tgen.start_router()
yield tgen
tgen.stop_topology()
DIR_SEND = 0
DIR_ACCEPT = 1
def is_key_active(router, keychain, keyid, direction):
dstr = "send" if direction == DIR_SEND else "accept"
node = f"{dstr}-lifetime-active"
output = router.net.cmd_raises(
"vtysh -c 'show mgmt get-data "
f'/ietf-key-chain:key-chains/key-chain[name="{keychain}"]'
f'/key[key-id="{keyid}"]/{node} json'
"'"
)
jd = json.loads(output)
return jd["ietf-key-chain:key-chains"]["key-chain"][0]["key"][0][node]
def test_send_accept(tgen):
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
r1 = tgen.gears["r1"]
conf = """conf t
key chain kc
key 1
key-string theSecret
crypto-algorithm md5
exit
exit
"""
r1.vtysh_multicmd(conf.split("\n"), pretty_output=True)
assert is_key_active(r1, "kc", 1, DIR_SEND)
assert is_key_active(r1, "kc", 1, DIR_ACCEPT)
conf = """conf t
key chain kc
key 1
key-string theSecret
crypto-algorithm md5
send-lifetime 00:00:00 Jan 1 2024 infinite
accept-lifetime 00:00:00 Jan 1 2024 infinite
exit
exit
"""
r1.vtysh_multicmd(conf.split("\n"), pretty_output=True)
assert is_key_active(r1, "kc", 1, DIR_SEND)
assert is_key_active(r1, "kc", 1, DIR_ACCEPT)
conf = """conf t
key chain kc
key 1
send-lifetime 00:00:00 Jan 1 2035 infinite
accept-lifetime 00:00:00 Jan 1 2035 infinite
exit
exit
"""
r1.vtysh_multicmd(conf.split("\n"), pretty_output=True)
assert not is_key_active(r1, "kc", 1, DIR_SEND)
assert not is_key_active(r1, "kc", 1, DIR_ACCEPT)
secs_in_10_years = 60 * 60 * 24 * 365 * 10
conf = f"""conf t
key chain kc
key 2
key-string theSecret
crypto-algorithm md5
send-lifetime 00:00:00 Jan 1 2024 duration {secs_in_10_years}
accept-lifetime 00:00:00 Jan 1 2024 duration {secs_in_10_years}
exit
exit
"""
r1.vtysh_multicmd(conf.split("\n"), pretty_output=True)
assert is_key_active(r1, "kc", 2, DIR_SEND)
assert is_key_active(r1, "kc", 2, DIR_ACCEPT)
conf = f"""conf t
key chain kc
key 2
send-lifetime 00:00:00 Jan 1 2000 duration 10
accept-lifetime 00:00:00 Jan 1 2000 duration 10
exit
exit
"""
r1.vtysh_multicmd(conf.split("\n"), pretty_output=True)
assert not is_key_active(r1, "kc", 2, DIR_SEND)
assert not is_key_active(r1, "kc", 2, DIR_ACCEPT)
conf = """conf t
key chain kc
key 3
key-string theSecret
crypto-algorithm md5
send-lifetime 00:00:00 Jan 1 2024 23:59:59 Dec 31 2034
accept-lifetime 00:00:00 Jan 1 2024 23:59:59 Dec 31 2034
exit
exit
"""
r1.vtysh_multicmd(conf.split("\n"), pretty_output=True)
assert is_key_active(r1, "kc", 3, DIR_SEND)
assert is_key_active(r1, "kc", 3, DIR_ACCEPT)
conf = """conf t
key chain kc
key 3
send-lifetime 00:00:00 Dec 1 2035 23:59:59 Dec 31 2034
accept-lifetime 00:00:00 Dec 1 2035 23:59:59 Dec 31 2034
exit
exit
"""
r1.vtysh_multicmd(conf.split("\n"), pretty_output=True)
assert not is_key_active(r1, "kc", 3, DIR_SEND)
assert not is_key_active(r1, "kc", 3, DIR_ACCEPT)

View file

@ -75,7 +75,7 @@ extern struct event_loop *master;
VTYSH_VRRPD | VTYSH_MGMTD
#define VTYSH_INTERFACE VTYSH_INTERFACE_SUBSET | VTYSH_BGPD
#define VTYSH_VRF VTYSH_INTERFACE_SUBSET | VTYSH_BGPD
#define VTYSH_KEYS VTYSH_RIPD | VTYSH_EIGRPD | VTYSH_OSPF6D | VTYSH_OSPFD
#define VTYSH_KEYS VTYSH_MGMTD | VTYSH_EIGRPD | VTYSH_OSPF6D | VTYSH_OSPFD
/* Daemons who can process nexthop-group configs */
#define VTYSH_NH_GROUP VTYSH_PBRD|VTYSH_SHARPD
#define VTYSH_SR VTYSH_ZEBRA|VTYSH_PATHD

View file

@ -0,0 +1,29 @@
module frr-deviations-ietf-key-chain {
yang-version 1.1;
namespace "http://frrouting.org/yang/frr-deviations-ietf-key-chain";
prefix frr-deviations-ietf-key-chain;
import ietf-key-chain {
prefix kc;
}
organization
"FRRouting";
contact
"FRR Users List: <mailto:frog@lists.frrouting.org>
FRR Development List: <mailto:dev@lists.frrouting.org>";
description
"This module defines deviation statements for the ietf-key-chain
module.";
revision 2024-03-03 {
description "Initial revision.";
reference "RFC 8177: YANG Data Model for Key Chains";
}
deviation /kc:key-chains/kc:key-chain/kc:key/kc:crypto-algorithm {
deviate replace {
mandatory false;
}
}
}

View file

@ -0,0 +1,382 @@
module ietf-key-chain {
yang-version 1.1;
namespace "urn:ietf:params:xml:ns:yang:ietf-key-chain";
prefix key-chain;
import ietf-yang-types {
prefix yang;
}
import ietf-netconf-acm {
prefix nacm;
}
organization
"IETF RTGWG - Routing Area Working Group";
contact
"WG Web: <https://datatracker.ietf.org/group/rtgwg>
WG List: <mailto:rtgwg@ietf.org>
Editor: Acee Lindem
<mailto:acee@cisco.com>
Yingzhen Qu
<mailto:yingzhen.qu@huawei.com>
Derek Yeung
<mailto:derek@arrcus.com>
Ing-Wher Chen
<mailto:Ing-Wher_Chen@jabail.com>
Jeffrey Zhang
<mailto:zzhang@juniper.net>";
description
"This YANG module defines the generic configuration
data for key chains. It is intended that the module
will be extended by vendors to define vendor-specific
key chain configuration parameters.
Copyright (c) 2017 IETF Trust and the persons identified as
authors of the code. All rights reserved.
Redistribution and use in source and binary forms, with or
without modification, is permitted pursuant to, and subject
to the license terms contained in, the Simplified BSD License
set forth in Section 4.c of the IETF Trust's Legal Provisions
Relating to IETF Documents
(http://trustee.ietf.org/license-info).
This version of this YANG module is part of RFC 8177;
see the RFC itself for full legal notices.";
reference "RFC 8177";
revision 2017-06-15 {
description
"Initial RFC Revision";
reference "RFC 8177: YANG Data Model for Key Chains";
}
feature hex-key-string {
description
"Support hexadecimal key string.";
}
feature accept-tolerance {
description
"Support the tolerance or acceptance limit.";
}
feature independent-send-accept-lifetime {
description
"Support for independent send and accept key lifetimes.";
}
feature crypto-hmac-sha-1-12 {
description
"Support for TCP HMAC-SHA-1 12-byte digest hack.";
}
feature cleartext {
description
"Support for cleartext algorithm. Usage is
NOT RECOMMENDED.";
}
feature aes-cmac-prf-128 {
description
"Support for AES Cipher-based Message Authentication
Code Pseudorandom Function.";
}
feature aes-key-wrap {
description
"Support for Advanced Encryption Standard (AES) Key Wrap.";
}
feature replay-protection-only {
description
"Provide replay protection without any authentication
as required by protocols such as Bidirectional
Forwarding Detection (BFD).";
}
identity crypto-algorithm {
description
"Base identity of cryptographic algorithm options.";
}
identity hmac-sha-1-12 {
base crypto-algorithm;
if-feature "crypto-hmac-sha-1-12";
description
"The HMAC-SHA1-12 algorithm.";
}
identity aes-cmac-prf-128 {
base crypto-algorithm;
if-feature "aes-cmac-prf-128";
description
"The AES-CMAC-PRF-128 algorithm - required by
RFC 5926 for TCP-AO key derivation functions.";
}
identity md5 {
base crypto-algorithm;
description
"The MD5 algorithm.";
}
identity sha-1 {
base crypto-algorithm;
description
"The SHA-1 algorithm.";
}
identity hmac-sha-1 {
base crypto-algorithm;
description
"HMAC-SHA-1 authentication algorithm.";
}
identity hmac-sha-256 {
base crypto-algorithm;
description
"HMAC-SHA-256 authentication algorithm.";
}
identity hmac-sha-384 {
base crypto-algorithm;
description
"HMAC-SHA-384 authentication algorithm.";
}
identity hmac-sha-512 {
base crypto-algorithm;
description
"HMAC-SHA-512 authentication algorithm.";
}
identity cleartext {
base crypto-algorithm;
if-feature "cleartext";
description
"cleartext.";
}
identity replay-protection-only {
base crypto-algorithm;
if-feature "replay-protection-only";
description
"Provide replay protection without any authentication as
required by protocols such as Bidirectional Forwarding
Detection (BFD).";
}
typedef key-chain-ref {
type leafref {
path
"/key-chain:key-chains/key-chain:key-chain/key-chain:name";
}
description
"This type is used by data models that need to reference
configured key chains.";
}
grouping lifetime {
description
"Key lifetime specification.";
choice lifetime {
default "always";
description
"Options for specifying key accept or send lifetimes";
case always {
leaf always {
type empty;
description
"Indicates key lifetime is always valid.";
}
}
case start-end-time {
leaf start-date-time {
type yang:date-and-time;
description
"Start time.";
}
choice end-time {
default "infinite";
description
"End-time setting.";
case infinite {
leaf no-end-time {
type empty;
description
"Indicates key lifetime end-time is infinite.";
}
}
case duration {
leaf duration {
type uint32 {
range "1..2147483646";
}
units "seconds";
description
"Key lifetime duration, in seconds";
}
}
case end-date-time {
leaf end-date-time {
type yang:date-and-time;
description
"End time.";
}
}
}
}
}
}
container key-chains {
description
"All configured key-chains on the device.";
list key-chain {
key "name";
description
"List of key-chains.";
leaf name {
type string;
description
"Name of the key-chain.";
}
leaf description {
type string;
description
"A description of the key-chain";
}
container accept-tolerance {
if-feature "accept-tolerance";
description
"Tolerance for key lifetime acceptance (seconds).";
leaf duration {
type uint32;
units "seconds";
default "0";
description
"Tolerance range, in seconds.";
}
}
leaf last-modified-timestamp {
type yang:date-and-time;
config false;
description
"Timestamp of the most recent update to the key-chain";
}
list key {
key "key-id";
description
"Single key in key chain.";
leaf key-id {
type uint64;
description
"Numeric value uniquely identifying the key";
}
container lifetime {
description
"Specify a key's lifetime.";
choice lifetime {
description
"Options for specification of send and accept
lifetimes.";
case send-and-accept-lifetime {
description
"Send and accept key have the same lifetime.";
container send-accept-lifetime {
description
"Single lifetime specification for both
send and accept lifetimes.";
uses lifetime;
}
}
case independent-send-accept-lifetime {
if-feature "independent-send-accept-lifetime";
description
"Independent send and accept key lifetimes.";
container send-lifetime {
description
"Separate lifetime specification for send
lifetime.";
uses lifetime;
}
container accept-lifetime {
description
"Separate lifetime specification for accept
lifetime.";
uses lifetime;
}
}
}
}
leaf crypto-algorithm {
type identityref {
base crypto-algorithm;
}
mandatory true;
description
"Cryptographic algorithm associated with key.";
}
container key-string {
description
"The key string.";
nacm:default-deny-all;
choice key-string-style {
description
"Key string styles";
case keystring {
leaf keystring {
type string;
description
"Key string in ASCII format.";
}
}
case hexadecimal {
if-feature "hex-key-string";
leaf hexadecimal-string {
type yang:hex-string;
description
"Key in hexadecimal string format. When compared
to ASCII, specification in hexadecimal affords
greater key entropy with the same number of
internal key-string octets. Additionally, it
discourages usage of well-known words or
numbers.";
}
}
}
}
leaf send-lifetime-active {
type boolean;
config false;
description
"Indicates if the send lifetime of the
key-chain key is currently active.";
}
leaf accept-lifetime-active {
type boolean;
config false;
description
"Indicates if the accept lifetime of the
key-chain key is currently active.";
}
}
}
container aes-key-wrap {
if-feature "aes-key-wrap";
description
"AES Key Wrap encryption for key-chain key-strings. The
encrypted key-strings are encoded as hexadecimal key
strings using the hex-key-string leaf.";
leaf enable {
type boolean;
default "false";
description
"Enable AES Key Wrap encryption.";
}
}
}
}

View file

@ -35,9 +35,11 @@ dist_yangmodels_DATA += yang/frr-bgp-route-map.yang
dist_yangmodels_DATA += yang/frr-vrf.yang
dist_yangmodels_DATA += yang/frr-route-types.yang
dist_yangmodels_DATA += yang/frr-routing.yang
dist_yangmodels_DATA += yang/ietf/frr-deviations-ietf-key-chain.yang
dist_yangmodels_DATA += yang/ietf/ietf-routing-types.yang
dist_yangmodels_DATA += yang/ietf/ietf-interfaces.yang
dist_yangmodels_DATA += yang/ietf/ietf-bgp-types.yang
dist_yangmodels_DATA += yang/ietf/ietf-key-chain.yang
dist_yangmodels_DATA += yang/ietf/ietf-netconf-acm.yang
dist_yangmodels_DATA += yang/ietf/ietf-netconf.yang
dist_yangmodels_DATA += yang/ietf/ietf-netconf-with-defaults.yang

View file

@ -608,7 +608,7 @@ struct yang_data *lib_vrf_zebra_ribs_rib_route_route_entry_uptime_get_elem(
{
struct route_entry *re = (struct route_entry *)args->list_entry;
return yang_data_new_date_and_time(args->xpath, re->uptime);
return yang_data_new_date_and_time(args->xpath, re->uptime, true);
}
/*