forked from Mirror/frr
Merge pull request #15469 from LabNConsulting/chopps/keychain-yang
add ietf-key-chain YANG module support
This commit is contained in:
commit
7e058c201a
|
@ -132,6 +132,8 @@ static const struct frr_yang_module_info *const eigrpd_yang_modules[] = {
|
||||||
&frr_interface_info,
|
&frr_interface_info,
|
||||||
&frr_route_map_info,
|
&frr_route_map_info,
|
||||||
&frr_vrf_info,
|
&frr_vrf_info,
|
||||||
|
&ietf_key_chain_info,
|
||||||
|
&ietf_key_chain_deviation_info,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* clang-format off */
|
/* clang-format off */
|
||||||
|
|
|
@ -678,6 +678,21 @@ vector cmd_describe_command(vector vline, struct vty *vty, int *status)
|
||||||
|
|
||||||
static struct list *varhandlers = NULL;
|
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,
|
void cmd_variable_complete(struct cmd_token *token, const char *arg,
|
||||||
vector comps)
|
vector comps)
|
||||||
{
|
{
|
||||||
|
@ -694,6 +709,9 @@ void cmd_variable_complete(struct cmd_token *token, const char *arg,
|
||||||
if (cvh->varname && (!token->varname
|
if (cvh->varname && (!token->varname
|
||||||
|| strcmp(cvh->varname, token->varname)))
|
|| strcmp(cvh->varname, token->varname)))
|
||||||
continue;
|
continue;
|
||||||
|
if (cvh->xpath)
|
||||||
|
__get_list_keys(tmpcomps, cvh->xpath);
|
||||||
|
if (cvh->completions)
|
||||||
cvh->completions(tmpcomps, token);
|
cvh->completions(tmpcomps, token);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -753,7 +771,7 @@ void cmd_variable_handler_register(const struct cmd_variable_handler *cvh)
|
||||||
if (!varhandlers)
|
if (!varhandlers)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (; cvh->completions; cvh++)
|
for (; cvh->completions || cvh->xpath; cvh++)
|
||||||
listnode_add(varhandlers, (void *)cvh);
|
listnode_add(varhandlers, (void *)cvh);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -636,6 +636,7 @@ extern void cmd_banner_motd_line(const char *line);
|
||||||
|
|
||||||
struct cmd_variable_handler {
|
struct cmd_variable_handler {
|
||||||
const char *tokenname, *varname;
|
const char *tokenname, *varname;
|
||||||
|
const char *xpath; /* fill comps from set of values at xpath */
|
||||||
void (*completions)(vector out, struct cmd_token *token);
|
void (*completions)(vector out, struct cmd_token *token);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
1013
lib/keychain.c
1013
lib/keychain.c
File diff suppressed because it is too large
Load diff
|
@ -6,6 +6,8 @@
|
||||||
#ifndef _ZEBRA_KEYCHAIN_H
|
#ifndef _ZEBRA_KEYCHAIN_H
|
||||||
#define _ZEBRA_KEYCHAIN_H
|
#define _ZEBRA_KEYCHAIN_H
|
||||||
|
|
||||||
|
#include "memory.h"
|
||||||
|
#include "northbound.h"
|
||||||
#include "qobj.h"
|
#include "qobj.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
@ -44,6 +46,10 @@ struct keychain_algo_info {
|
||||||
const char *desc;
|
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[];
|
extern const struct keychain_algo_info algo_info[];
|
||||||
uint16_t keychain_get_block_size(enum keychain_hash_algo key);
|
uint16_t keychain_get_block_size(enum keychain_hash_algo key);
|
||||||
uint16_t keychain_get_hash_len(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 {
|
struct keychain {
|
||||||
char *name;
|
char *name;
|
||||||
|
char *desc;
|
||||||
|
time_t last_touch;
|
||||||
|
|
||||||
struct list *key;
|
struct list *key;
|
||||||
|
|
||||||
|
@ -81,13 +89,43 @@ struct key {
|
||||||
};
|
};
|
||||||
DECLARE_QOBJ_TYPE(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(void);
|
||||||
|
extern void keychain_init_new(bool in_backend);
|
||||||
extern void keychain_terminate(void);
|
extern void keychain_terminate(void);
|
||||||
extern struct keychain *keychain_lookup(const char *);
|
extern struct keychain *keychain_lookup(const char *);
|
||||||
extern struct key *key_lookup_for_accept(const struct keychain *, uint32_t);
|
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_match_for_accept(const struct keychain *, const char *);
|
||||||
extern struct key *key_lookup_for_send(const struct keychain *);
|
extern struct key *key_lookup_for_send(const struct keychain *);
|
||||||
const char *keychain_algo_str(enum keychain_hash_algo hash_algo);
|
const char *keychain_algo_str(enum keychain_hash_algo hash_algo);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
1033
lib/keychain_cli.c
Normal file
1033
lib/keychain_cli.c
Normal file
File diff suppressed because it is too large
Load diff
898
lib/keychain_nb.c
Normal file
898
lib/keychain_nb.c
Normal 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,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
|
@ -53,6 +53,8 @@ lib_libfrr_la_SOURCES = \
|
||||||
lib/jhash.c \
|
lib/jhash.c \
|
||||||
lib/json.c \
|
lib/json.c \
|
||||||
lib/keychain.c \
|
lib/keychain.c \
|
||||||
|
lib/keychain_cli.c \
|
||||||
|
lib/keychain_nb.c \
|
||||||
lib/ldp_sync.c \
|
lib/ldp_sync.c \
|
||||||
lib/lib_errors.c \
|
lib/lib_errors.c \
|
||||||
lib/lib_vty.c \
|
lib/lib_vty.c \
|
||||||
|
@ -148,7 +150,9 @@ nodist_lib_libfrr_la_SOURCES = \
|
||||||
yang/frr-vrf.yang.c \
|
yang/frr-vrf.yang.c \
|
||||||
yang/frr-routing.yang.c \
|
yang/frr-routing.yang.c \
|
||||||
yang/frr-nexthop.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-routing-types.yang.c \
|
||||||
|
yang/ietf/ietf-key-chain.yang.c \
|
||||||
yang/ietf/ietf-interfaces.yang.c \
|
yang/ietf/ietf-interfaces.yang.c \
|
||||||
yang/ietf/ietf-bgp-types.yang.c \
|
yang/ietf/ietf-bgp-types.yang.c \
|
||||||
yang/frr-module-translator.yang.c \
|
yang/frr-module-translator.yang.c \
|
||||||
|
@ -181,6 +185,7 @@ clippy_scan += \
|
||||||
lib/if.c \
|
lib/if.c \
|
||||||
lib/filter_cli.c \
|
lib/filter_cli.c \
|
||||||
lib/if_rmap.c \
|
lib/if_rmap.c \
|
||||||
|
lib/keychain_cli.c \
|
||||||
lib/log_vty.c \
|
lib/log_vty.c \
|
||||||
lib/mgmt_be_client.c \
|
lib/mgmt_be_client.c \
|
||||||
lib/mgmt_fe_client.c \
|
lib/mgmt_fe_client.c \
|
||||||
|
|
|
@ -1026,30 +1026,50 @@ void yang_dnode_get_mac(struct ethaddr *mac, const struct lyd_node *dnode,
|
||||||
(void)prefix_str2mac(canon, mac);
|
(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;
|
struct yang_data *yd;
|
||||||
char timebuf[MONOTIME_STRLEN];
|
char *times = NULL;
|
||||||
struct timeval _time, time_real;
|
|
||||||
char *ts_dot;
|
if (is_monotime) {
|
||||||
uint16_t buflen;
|
struct timeval _time = { time, 0 };
|
||||||
|
struct timeval time_real;
|
||||||
|
|
||||||
_time.tv_sec = time;
|
|
||||||
_time.tv_usec = 0;
|
|
||||||
monotime_to_realtime(&_time, &time_real);
|
monotime_to_realtime(&_time, &time_real);
|
||||||
|
time = time_real.tv_sec;
|
||||||
|
}
|
||||||
|
|
||||||
gmtime_r(&time_real.tv_sec, &tm);
|
(void)ly_time_time2str(time, NULL, ×);
|
||||||
|
yd = yang_data_new(xpath, times);
|
||||||
|
free(times);
|
||||||
|
|
||||||
/* rfc-3339 format */
|
return yd;
|
||||||
strftime(timebuf, sizeof(timebuf), "%Y-%m-%dT%H:%M:%S", &tm);
|
}
|
||||||
buflen = strlen(timebuf);
|
|
||||||
ts_dot = timebuf + buflen;
|
|
||||||
|
|
||||||
/* microseconds and appends Z */
|
struct timespec yang_dnode_get_date_and_timespec(const struct lyd_node *dnode,
|
||||||
snprintfrr(ts_dot, sizeof(timebuf) - buflen, ".%06luZ",
|
const char *xpath_fmt, ...)
|
||||||
(unsigned long)time_real.tv_usec);
|
{
|
||||||
|
const char *canon = YANG_DNODE_XPATH_GET_CANON(dnode, xpath_fmt);
|
||||||
|
struct timespec ts;
|
||||||
|
LY_ERR err;
|
||||||
|
|
||||||
return yang_data_new(xpath, timebuf);
|
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,
|
float yang_dnode_get_bandwidth_ieee_float32(const struct lyd_node *dnode,
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#ifndef _FRR_NORTHBOUND_WRAPPERS_H_
|
#ifndef _FRR_NORTHBOUND_WRAPPERS_H_
|
||||||
#define _FRR_NORTHBOUND_WRAPPERS_H_
|
#define _FRR_NORTHBOUND_WRAPPERS_H_
|
||||||
|
|
||||||
|
#include <libyang/libyang.h>
|
||||||
#include "prefix.h"
|
#include "prefix.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
@ -200,7 +201,14 @@ extern void yang_dnode_get_mac(struct ethaddr *mac, const struct lyd_node *dnode
|
||||||
|
|
||||||
/*data-and-time */
|
/*data-and-time */
|
||||||
extern struct yang_data *yang_data_new_date_and_time(const char *xpath,
|
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 */
|
/* rt-types:bandwidth-ieee-float32 */
|
||||||
extern float yang_dnode_get_bandwidth_ieee_float32(const struct lyd_node *dnode,
|
extern float yang_dnode_get_bandwidth_ieee_float32(const struct lyd_node *dnode,
|
||||||
|
|
|
@ -90,10 +90,12 @@ static const char *const ripd_config_xpaths[] = {
|
||||||
"/frr-ripd:ripd",
|
"/frr-ripd:ripd",
|
||||||
"/frr-route-map:lib",
|
"/frr-route-map:lib",
|
||||||
"/frr-vrf:lib",
|
"/frr-vrf:lib",
|
||||||
|
"/ietf-key-chain:key-chains",
|
||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
static const char *const ripd_oper_xpaths[] = {
|
static const char *const ripd_oper_xpaths[] = {
|
||||||
"/frr-ripd:ripd",
|
"/frr-ripd:ripd",
|
||||||
|
"/ietf-key-chain:key-chains",
|
||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include "lib/version.h"
|
#include "lib/version.h"
|
||||||
#include "routemap.h"
|
#include "routemap.h"
|
||||||
#include "filter.h"
|
#include "filter.h"
|
||||||
|
#include "keychain.h"
|
||||||
#include "libfrr.h"
|
#include "libfrr.h"
|
||||||
#include "frr_pthread.h"
|
#include "frr_pthread.h"
|
||||||
#include "mgmtd/mgmt.h"
|
#include "mgmtd/mgmt.h"
|
||||||
|
@ -185,6 +186,8 @@ static const struct frr_yang_module_info *const mgmt_yang_modules[] = {
|
||||||
|
|
||||||
&frr_zebra_cli_info,
|
&frr_zebra_cli_info,
|
||||||
&zebra_route_map_info,
|
&zebra_route_map_info,
|
||||||
|
&ietf_key_chain_cli_info,
|
||||||
|
&ietf_key_chain_deviation_info,
|
||||||
|
|
||||||
#ifdef HAVE_RIPD
|
#ifdef HAVE_RIPD
|
||||||
&frr_ripd_cli_info,
|
&frr_ripd_cli_info,
|
||||||
|
@ -212,7 +215,7 @@ FRR_DAEMON_INFO(mgmtd, MGMTD,
|
||||||
|
|
||||||
/* avoid libfrr trying to read our config file for us */
|
/* avoid libfrr trying to read our config file for us */
|
||||||
.flags = FRR_MANUAL_VTY_START | FRR_NO_SPLIT_CONFIG,
|
.flags = FRR_MANUAL_VTY_START | FRR_NO_SPLIT_CONFIG,
|
||||||
);
|
);
|
||||||
/* clang-format on */
|
/* clang-format on */
|
||||||
|
|
||||||
#define DEPRECATED_OPTIONS ""
|
#define DEPRECATED_OPTIONS ""
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include "command.h"
|
#include "command.h"
|
||||||
#include "filter.h"
|
#include "filter.h"
|
||||||
#include "json.h"
|
#include "json.h"
|
||||||
|
#include "keychain.h"
|
||||||
#include "network.h"
|
#include "network.h"
|
||||||
#include "northbound_cli.h"
|
#include "northbound_cli.h"
|
||||||
#include "routemap.h"
|
#include "routemap.h"
|
||||||
|
@ -600,6 +601,7 @@ void mgmt_vty_init(void)
|
||||||
filter_cli_init();
|
filter_cli_init();
|
||||||
route_map_cli_init();
|
route_map_cli_init();
|
||||||
affinity_map_init();
|
affinity_map_init();
|
||||||
|
keychain_cli_init();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialize command handling from VTYSH connection.
|
* Initialize command handling from VTYSH connection.
|
||||||
|
|
|
@ -169,6 +169,8 @@ static const struct frr_yang_module_info *const ospf6d_yang_modules[] = {
|
||||||
&frr_vrf_info,
|
&frr_vrf_info,
|
||||||
&frr_ospf_route_map_info,
|
&frr_ospf_route_map_info,
|
||||||
&frr_ospf6_route_map_info,
|
&frr_ospf6_route_map_info,
|
||||||
|
&ietf_key_chain_info,
|
||||||
|
&ietf_key_chain_deviation_info,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* actual paths filled in main() */
|
/* actual paths filled in main() */
|
||||||
|
@ -194,7 +196,7 @@ FRR_DAEMON_INFO(ospf6d, OSPF6,
|
||||||
.n_yang_modules = array_size(ospf6d_yang_modules),
|
.n_yang_modules = array_size(ospf6d_yang_modules),
|
||||||
|
|
||||||
.state_paths = state_paths,
|
.state_paths = state_paths,
|
||||||
);
|
);
|
||||||
/* clang-format on */
|
/* clang-format on */
|
||||||
|
|
||||||
/* Max wait time for config to load before accepting hellos */
|
/* Max wait time for config to load before accepting hellos */
|
||||||
|
|
|
@ -134,6 +134,8 @@ static const struct frr_yang_module_info *const ospfd_yang_modules[] = {
|
||||||
&frr_route_map_info,
|
&frr_route_map_info,
|
||||||
&frr_vrf_info,
|
&frr_vrf_info,
|
||||||
&frr_ospf_route_map_info,
|
&frr_ospf_route_map_info,
|
||||||
|
&ietf_key_chain_info,
|
||||||
|
&ietf_key_chain_deviation_info,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* actual paths filled in main() */
|
/* actual paths filled in main() */
|
||||||
|
|
|
@ -36,7 +36,7 @@ daemon_flags = {
|
||||||
"lib/filter.c": "VTYSH_ACL_SHOW",
|
"lib/filter.c": "VTYSH_ACL_SHOW",
|
||||||
"lib/filter_cli.c": "VTYSH_ACL_CONFIG",
|
"lib/filter_cli.c": "VTYSH_ACL_CONFIG",
|
||||||
"lib/if.c": "VTYSH_INTERFACE",
|
"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_be_client.c": "VTYSH_MGMT_BACKEND",
|
||||||
"lib/mgmt_fe_client.c": "VTYSH_MGMT_FRONTEND",
|
"lib/mgmt_fe_client.c": "VTYSH_MGMT_FRONTEND",
|
||||||
"lib/lib_vty.c": "VTYSH_ALL",
|
"lib/lib_vty.c": "VTYSH_ALL",
|
||||||
|
|
|
@ -131,6 +131,8 @@ static const struct frr_yang_module_info *const ripd_yang_modules[] = {
|
||||||
&frr_ripd_info,
|
&frr_ripd_info,
|
||||||
&frr_route_map_info,
|
&frr_route_map_info,
|
||||||
&frr_vrf_info,
|
&frr_vrf_info,
|
||||||
|
&ietf_key_chain_info,
|
||||||
|
&ietf_key_chain_deviation_info,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* clang-format off */
|
/* clang-format off */
|
||||||
|
@ -189,7 +191,7 @@ int main(int argc, char **argv)
|
||||||
|
|
||||||
/* Library initialization. */
|
/* Library initialization. */
|
||||||
rip_error_init();
|
rip_error_init();
|
||||||
keychain_init();
|
keychain_init_new(true);
|
||||||
rip_vrf_init();
|
rip_vrf_init();
|
||||||
|
|
||||||
/* RIP related initialization. */
|
/* RIP related initialization. */
|
||||||
|
|
31
tests/topotests/key_sendaccept/r1/frr.conf
Normal file
31
tests/topotests/key_sendaccept/r1/frr.conf
Normal 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
|
20
tests/topotests/key_sendaccept/r2/frr.conf
Normal file
20
tests/topotests/key_sendaccept/r2/frr.conf
Normal 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
|
150
tests/topotests/key_sendaccept/test_keychain.py
Normal file
150
tests/topotests/key_sendaccept/test_keychain.py
Normal 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)
|
|
@ -75,7 +75,7 @@ extern struct event_loop *master;
|
||||||
VTYSH_VRRPD | VTYSH_MGMTD
|
VTYSH_VRRPD | VTYSH_MGMTD
|
||||||
#define VTYSH_INTERFACE VTYSH_INTERFACE_SUBSET | VTYSH_BGPD
|
#define VTYSH_INTERFACE VTYSH_INTERFACE_SUBSET | VTYSH_BGPD
|
||||||
#define VTYSH_VRF 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 */
|
/* Daemons who can process nexthop-group configs */
|
||||||
#define VTYSH_NH_GROUP VTYSH_PBRD|VTYSH_SHARPD
|
#define VTYSH_NH_GROUP VTYSH_PBRD|VTYSH_SHARPD
|
||||||
#define VTYSH_SR VTYSH_ZEBRA|VTYSH_PATHD
|
#define VTYSH_SR VTYSH_ZEBRA|VTYSH_PATHD
|
||||||
|
|
29
yang/ietf/frr-deviations-ietf-key-chain.yang
Normal file
29
yang/ietf/frr-deviations-ietf-key-chain.yang
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
382
yang/ietf/ietf-key-chain.yang
Normal file
382
yang/ietf/ietf-key-chain.yang
Normal 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.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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-vrf.yang
|
||||||
dist_yangmodels_DATA += yang/frr-route-types.yang
|
dist_yangmodels_DATA += yang/frr-route-types.yang
|
||||||
dist_yangmodels_DATA += yang/frr-routing.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-routing-types.yang
|
||||||
dist_yangmodels_DATA += yang/ietf/ietf-interfaces.yang
|
dist_yangmodels_DATA += yang/ietf/ietf-interfaces.yang
|
||||||
dist_yangmodels_DATA += yang/ietf/ietf-bgp-types.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-acm.yang
|
||||||
dist_yangmodels_DATA += yang/ietf/ietf-netconf.yang
|
dist_yangmodels_DATA += yang/ietf/ietf-netconf.yang
|
||||||
dist_yangmodels_DATA += yang/ietf/ietf-netconf-with-defaults.yang
|
dist_yangmodels_DATA += yang/ietf/ietf-netconf-with-defaults.yang
|
||||||
|
|
|
@ -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;
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
Loading…
Reference in a new issue