mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-05-31 03:08:23 +00:00
lib: retrofit interface commands to the new northbound model
The frr-interface YANG module models interfaces using a YANG list keyed by the interface name and the interface VRF. Interfaces can't be keyed only by their name since interface names might not be globally unique when the netns VRF backend is in use. When using the VRF-Lite backend, however, interface names *must* be globally unique. In this case, we need to validate the uniqueness of interface names inside the appropriate northbound callback since this constraint can't be expressed in the YANG language. We must also ensure that only inactive interfaces can be removed, among other things we need to validate in the northbound layer. Signed-off-by: Renato Westphal <renato@opensourcerouting.org>
This commit is contained in:
parent
a4bed468f9
commit
8f90d89ba9
512
lib/if.c
512
lib/if.c
@ -34,6 +34,10 @@
|
|||||||
#include "table.h"
|
#include "table.h"
|
||||||
#include "buffer.h"
|
#include "buffer.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
#include "northbound_cli.h"
|
||||||
|
#ifndef VTYSH_EXTRACT_PL
|
||||||
|
#include "lib/if_clippy.c"
|
||||||
|
#endif
|
||||||
|
|
||||||
DEFINE_MTYPE(LIB, IF, "Interface")
|
DEFINE_MTYPE(LIB, IF, "Interface")
|
||||||
DEFINE_MTYPE_STATIC(LIB, CONNECTED, "Connected")
|
DEFINE_MTYPE_STATIC(LIB, CONNECTED, "Connected")
|
||||||
@ -160,14 +164,14 @@ struct interface *if_create(const char *name, vrf_id_t vrf_id)
|
|||||||
/* Create new interface structure. */
|
/* Create new interface structure. */
|
||||||
void if_update_to_new_vrf(struct interface *ifp, vrf_id_t vrf_id)
|
void if_update_to_new_vrf(struct interface *ifp, vrf_id_t vrf_id)
|
||||||
{
|
{
|
||||||
struct vrf *vrf;
|
struct vrf *old_vrf, *vrf;
|
||||||
|
|
||||||
/* remove interface from old master vrf list */
|
/* remove interface from old master vrf list */
|
||||||
vrf = vrf_lookup_by_id(ifp->vrf_id);
|
old_vrf = vrf_lookup_by_id(ifp->vrf_id);
|
||||||
if (vrf) {
|
if (old_vrf) {
|
||||||
IFNAME_RB_REMOVE(vrf, ifp);
|
IFNAME_RB_REMOVE(old_vrf, ifp);
|
||||||
if (ifp->ifindex != IFINDEX_INTERNAL)
|
if (ifp->ifindex != IFINDEX_INTERNAL)
|
||||||
IFINDEX_RB_REMOVE(vrf, ifp);
|
IFINDEX_RB_REMOVE(old_vrf, ifp);
|
||||||
}
|
}
|
||||||
|
|
||||||
ifp->vrf_id = vrf_id;
|
ifp->vrf_id = vrf_id;
|
||||||
@ -176,6 +180,25 @@ void if_update_to_new_vrf(struct interface *ifp, vrf_id_t vrf_id)
|
|||||||
IFNAME_RB_INSERT(vrf, ifp);
|
IFNAME_RB_INSERT(vrf, ifp);
|
||||||
if (ifp->ifindex != IFINDEX_INTERNAL)
|
if (ifp->ifindex != IFINDEX_INTERNAL)
|
||||||
IFINDEX_RB_INSERT(vrf, ifp);
|
IFINDEX_RB_INSERT(vrf, ifp);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* HACK: Change the interface VRF in the running configuration directly,
|
||||||
|
* bypassing the northbound layer. This is necessary to avoid deleting
|
||||||
|
* the interface and readding it in the new VRF, which would have
|
||||||
|
* several implications.
|
||||||
|
*/
|
||||||
|
if (yang_module_find("frr-interface")) {
|
||||||
|
struct lyd_node *if_dnode;
|
||||||
|
|
||||||
|
if_dnode = yang_dnode_get(
|
||||||
|
running_config->dnode,
|
||||||
|
"/frr-interface:lib/interface[name='%s'][vrf='%s']/vrf",
|
||||||
|
ifp->name, old_vrf->name);
|
||||||
|
if (if_dnode) {
|
||||||
|
yang_dnode_change_leaf(if_dnode, vrf->name);
|
||||||
|
running_config->version++;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -369,44 +392,23 @@ struct interface *if_lookup_prefix(struct prefix *prefix, vrf_id_t vrf_id)
|
|||||||
|
|
||||||
/* Get interface by name if given name interface doesn't exist create
|
/* Get interface by name if given name interface doesn't exist create
|
||||||
one. */
|
one. */
|
||||||
struct interface *if_get_by_name(const char *name, vrf_id_t vrf_id, int vty)
|
struct interface *if_get_by_name(const char *name, vrf_id_t vrf_id)
|
||||||
{
|
{
|
||||||
struct interface *ifp = NULL;
|
struct interface *ifp;
|
||||||
|
|
||||||
if (vrf_is_mapped_on_netns(vrf_lookup_by_id(vrf_id))) {
|
switch (vrf_get_backend()) {
|
||||||
|
case VRF_BACKEND_NETNS:
|
||||||
ifp = if_lookup_by_name(name, vrf_id);
|
ifp = if_lookup_by_name(name, vrf_id);
|
||||||
if (ifp)
|
if (ifp)
|
||||||
return ifp;
|
return ifp;
|
||||||
if (vty) {
|
|
||||||
/* If the interface command was entered in vty without a
|
|
||||||
* VRF (passed as VRF_DEFAULT), search an interface with
|
|
||||||
* this name in all VRs
|
|
||||||
*/
|
|
||||||
if (vrf_id == VRF_DEFAULT)
|
|
||||||
return if_lookup_by_name_all_vrf(name);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
return if_create(name, vrf_id);
|
return if_create(name, vrf_id);
|
||||||
}
|
case VRF_BACKEND_VRF_LITE:
|
||||||
/* vrf is based on vrf-lite */
|
|
||||||
ifp = if_lookup_by_name_all_vrf(name);
|
ifp = if_lookup_by_name_all_vrf(name);
|
||||||
if (ifp) {
|
if (ifp) {
|
||||||
if (ifp->vrf_id == vrf_id)
|
if (ifp->vrf_id == vrf_id)
|
||||||
return ifp;
|
return ifp;
|
||||||
/* Found a match on a different VRF. If the interface command
|
/* If it came from the kernel or by way of zclient,
|
||||||
* was entered in vty without a VRF (passed as VRF_DEFAULT),
|
* believe it and update the ifp accordingly.
|
||||||
* accept the ifp we found. If a vrf was entered and there is a
|
|
||||||
* mismatch, reject it if from vty. If it came from the kernel
|
|
||||||
* or by way of zclient, believe it and update the ifp
|
|
||||||
* accordingly.
|
|
||||||
*/
|
|
||||||
if (vty) {
|
|
||||||
if (vrf_id == VRF_DEFAULT)
|
|
||||||
return ifp;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
/* If it came from the kernel or by way of zclient, believe it
|
|
||||||
* and update the ifp accordingly.
|
|
||||||
*/
|
*/
|
||||||
if_update_to_new_vrf(ifp, vrf_id);
|
if_update_to_new_vrf(ifp, vrf_id);
|
||||||
return ifp;
|
return ifp;
|
||||||
@ -414,6 +416,9 @@ struct interface *if_get_by_name(const char *name, vrf_id_t vrf_id, int vty)
|
|||||||
return if_create(name, vrf_id);
|
return if_create(name, vrf_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
void if_set_index(struct interface *ifp, ifindex_t ifindex)
|
void if_set_index(struct interface *ifp, ifindex_t ifindex)
|
||||||
{
|
{
|
||||||
struct vrf *vrf;
|
struct vrf *vrf;
|
||||||
@ -577,37 +582,6 @@ void if_dump_all(void)
|
|||||||
if_dump(ifp);
|
if_dump(ifp);
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFUN (interface_desc,
|
|
||||||
interface_desc_cmd,
|
|
||||||
"description LINE...",
|
|
||||||
"Interface specific description\n"
|
|
||||||
"Characters describing this interface\n")
|
|
||||||
{
|
|
||||||
int idx_line = 1;
|
|
||||||
VTY_DECLVAR_CONTEXT(interface, ifp);
|
|
||||||
|
|
||||||
if (ifp->desc)
|
|
||||||
XFREE(MTYPE_TMP, ifp->desc);
|
|
||||||
ifp->desc = argv_concat(argv, argc, idx_line);
|
|
||||||
|
|
||||||
return CMD_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
DEFUN (no_interface_desc,
|
|
||||||
no_interface_desc_cmd,
|
|
||||||
"no description",
|
|
||||||
NO_STR
|
|
||||||
"Interface specific description\n")
|
|
||||||
{
|
|
||||||
VTY_DECLVAR_CONTEXT(interface, ifp);
|
|
||||||
|
|
||||||
if (ifp->desc)
|
|
||||||
XFREE(MTYPE_TMP, ifp->desc);
|
|
||||||
ifp->desc = NULL;
|
|
||||||
|
|
||||||
return CMD_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef SUNOS_5
|
#ifdef SUNOS_5
|
||||||
/* Need to handle upgrade from SUNWzebra to Quagga. SUNWzebra created
|
/* Need to handle upgrade from SUNWzebra to Quagga. SUNWzebra created
|
||||||
* a seperate struct interface for each logical interface, so config
|
* a seperate struct interface for each logical interface, so config
|
||||||
@ -642,123 +616,10 @@ static struct interface *if_sunwzebra_get(const char *name, vrf_id_t vrf_id)
|
|||||||
if (cp)
|
if (cp)
|
||||||
*cp = '\0';
|
*cp = '\0';
|
||||||
|
|
||||||
return if_get_by_name(name, vrf_id, 1);
|
return if_get_by_name(name, vrf_id);
|
||||||
}
|
}
|
||||||
#endif /* SUNOS_5 */
|
#endif /* SUNOS_5 */
|
||||||
|
|
||||||
DEFUN_NOSH (interface,
|
|
||||||
interface_cmd,
|
|
||||||
"interface IFNAME [vrf NAME]",
|
|
||||||
"Select an interface to configure\n"
|
|
||||||
"Interface's name\n"
|
|
||||||
VRF_CMD_HELP_STR)
|
|
||||||
{
|
|
||||||
int idx_ifname = 1;
|
|
||||||
int idx_vrf = 3;
|
|
||||||
const char *ifname = argv[idx_ifname]->arg;
|
|
||||||
const char *vrfname =
|
|
||||||
(argc > 2) ? argv[idx_vrf]->arg : VRF_DEFAULT_NAME;
|
|
||||||
|
|
||||||
struct interface *ifp;
|
|
||||||
vrf_id_t vrf_id = VRF_DEFAULT;
|
|
||||||
|
|
||||||
if (strlen(ifname) > INTERFACE_NAMSIZ) {
|
|
||||||
vty_out(vty,
|
|
||||||
"%% Interface name %s is invalid: length exceeds "
|
|
||||||
"%d characters\n",
|
|
||||||
ifname, INTERFACE_NAMSIZ);
|
|
||||||
return CMD_WARNING_CONFIG_FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*Pending: need proper vrf name based lookup/(possible creation of VRF)
|
|
||||||
Imagine forward reference of a vrf by name in this interface config */
|
|
||||||
if (vrfname)
|
|
||||||
VRF_GET_ID(vrf_id, vrfname, false);
|
|
||||||
|
|
||||||
#ifdef SUNOS_5
|
|
||||||
ifp = if_sunwzebra_get(ifname, vrf_id);
|
|
||||||
#else
|
|
||||||
ifp = if_get_by_name(ifname, vrf_id, 1);
|
|
||||||
#endif /* SUNOS_5 */
|
|
||||||
|
|
||||||
if (!ifp) {
|
|
||||||
vty_out(vty, "%% interface %s not in %s vrf\n", ifname,
|
|
||||||
vrfname);
|
|
||||||
return CMD_WARNING_CONFIG_FAILED;
|
|
||||||
}
|
|
||||||
VTY_PUSH_CONTEXT(INTERFACE_NODE, ifp);
|
|
||||||
|
|
||||||
return CMD_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
DEFUN (no_interface,
|
|
||||||
no_interface_cmd,
|
|
||||||
"no interface IFNAME [vrf NAME]",
|
|
||||||
NO_STR
|
|
||||||
"Delete a pseudo interface's configuration\n"
|
|
||||||
"Interface's name\n"
|
|
||||||
VRF_CMD_HELP_STR)
|
|
||||||
{
|
|
||||||
int idx_vrf = 4;
|
|
||||||
const char *ifname = argv[2]->arg;
|
|
||||||
const char *vrfname = (argc > 3) ? argv[idx_vrf]->arg : NULL;
|
|
||||||
|
|
||||||
// deleting interface
|
|
||||||
struct interface *ifp;
|
|
||||||
vrf_id_t vrf_id = VRF_DEFAULT;
|
|
||||||
|
|
||||||
if (argc > 3)
|
|
||||||
VRF_GET_ID(vrf_id, vrfname, false);
|
|
||||||
|
|
||||||
ifp = if_lookup_by_name(ifname, vrf_id);
|
|
||||||
|
|
||||||
if (ifp == NULL) {
|
|
||||||
vty_out(vty, "%% Interface %s does not exist\n", ifname);
|
|
||||||
return CMD_WARNING_CONFIG_FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE)) {
|
|
||||||
vty_out(vty, "%% Only inactive interfaces can be deleted\n");
|
|
||||||
return CMD_WARNING_CONFIG_FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
if_delete(ifp);
|
|
||||||
|
|
||||||
return CMD_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void if_autocomplete(vector comps, struct cmd_token *token)
|
|
||||||
{
|
|
||||||
struct interface *ifp;
|
|
||||||
struct vrf *vrf = NULL;
|
|
||||||
|
|
||||||
RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
|
|
||||||
FOR_ALL_INTERFACES (vrf, ifp) {
|
|
||||||
vector_set(comps, XSTRDUP(MTYPE_COMPLETION, ifp->name));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct cmd_variable_handler if_var_handlers[] = {
|
|
||||||
{/* "interface NAME" */
|
|
||||||
.varname = "interface",
|
|
||||||
.completions = if_autocomplete},
|
|
||||||
{.tokenname = "IFNAME", .completions = if_autocomplete},
|
|
||||||
{.tokenname = "INTERFACE", .completions = if_autocomplete},
|
|
||||||
{.completions = NULL}};
|
|
||||||
|
|
||||||
void if_cmd_init(void)
|
|
||||||
{
|
|
||||||
cmd_variable_handler_register(if_var_handlers);
|
|
||||||
|
|
||||||
install_element(CONFIG_NODE, &interface_cmd);
|
|
||||||
install_element(CONFIG_NODE, &no_interface_cmd);
|
|
||||||
|
|
||||||
install_default(INTERFACE_NODE);
|
|
||||||
install_element(INTERFACE_NODE, &interface_desc_cmd);
|
|
||||||
install_element(INTERFACE_NODE, &no_interface_desc_cmd);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
/* For debug purpose. */
|
/* For debug purpose. */
|
||||||
DEFUN (show_address,
|
DEFUN (show_address,
|
||||||
@ -1212,6 +1073,208 @@ void if_link_params_free(struct interface *ifp)
|
|||||||
ifp->link_params = NULL;
|
ifp->link_params = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ----------- CLI commands ----------- */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* XPath: /frr-interface:lib/interface
|
||||||
|
*/
|
||||||
|
DEFPY_NOSH (interface,
|
||||||
|
interface_cmd,
|
||||||
|
"interface IFNAME [vrf NAME$vrfname]",
|
||||||
|
"Select an interface to configure\n"
|
||||||
|
"Interface's name\n"
|
||||||
|
VRF_CMD_HELP_STR)
|
||||||
|
{
|
||||||
|
char xpath_list[XPATH_MAXLEN];
|
||||||
|
struct cli_config_change changes[] = {
|
||||||
|
{
|
||||||
|
.xpath = ".",
|
||||||
|
.operation = NB_OP_CREATE,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
vrf_id_t vrf_id;
|
||||||
|
struct interface *ifp;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (!vrfname)
|
||||||
|
vrfname = VRF_DEFAULT_NAME;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This command requires special handling to maintain backward
|
||||||
|
* compatibility. If a VRF name is not specified, it means we're willing
|
||||||
|
* to accept any interface with the given name on any VRF. If no
|
||||||
|
* interface is found, then a new one should be created on the default
|
||||||
|
* VRF.
|
||||||
|
*/
|
||||||
|
VRF_GET_ID(vrf_id, vrfname, false);
|
||||||
|
ifp = if_lookup_by_name_all_vrf(ifname);
|
||||||
|
if (ifp && ifp->vrf_id != vrf_id) {
|
||||||
|
struct vrf *vrf;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Special case 1: a VRF name was specified, but the found
|
||||||
|
* interface is associated to different VRF. Reject the command.
|
||||||
|
*/
|
||||||
|
if (vrf_id != VRF_DEFAULT) {
|
||||||
|
vty_out(vty, "%% interface %s not in %s vrf\n", ifname,
|
||||||
|
vrfname);
|
||||||
|
return CMD_WARNING_CONFIG_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Special case 2: a VRF name was *not* specified, and the found
|
||||||
|
* interface is associated to a VRF other than the default one.
|
||||||
|
* Update vrf_id and vrfname to account for that.
|
||||||
|
*/
|
||||||
|
vrf = vrf_lookup_by_id(ifp->vrf_id);
|
||||||
|
assert(vrf);
|
||||||
|
vrf_id = ifp->vrf_id;
|
||||||
|
vrfname = vrf->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf(xpath_list, sizeof(xpath_list),
|
||||||
|
"/frr-interface:lib/interface[name='%s'][vrf='%s']", ifname,
|
||||||
|
vrfname);
|
||||||
|
|
||||||
|
ret = nb_cli_cfg_change(vty, xpath_list, changes, array_size(changes));
|
||||||
|
if (ret == CMD_SUCCESS) {
|
||||||
|
VTY_PUSH_XPATH(INTERFACE_NODE, xpath_list);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For backward compatibility with old commands we still need
|
||||||
|
* to use the qobj infrastructure. This can be removed once
|
||||||
|
* all interface-level commands are converted to the new
|
||||||
|
* northbound model.
|
||||||
|
*/
|
||||||
|
ifp = if_lookup_by_name(ifname, vrf_id);
|
||||||
|
if (ifp)
|
||||||
|
VTY_PUSH_CONTEXT(INTERFACE_NODE, ifp);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFPY (no_interface,
|
||||||
|
no_interface_cmd,
|
||||||
|
"no interface IFNAME [vrf NAME$vrfname]",
|
||||||
|
NO_STR
|
||||||
|
"Delete a pseudo interface's configuration\n"
|
||||||
|
"Interface's name\n"
|
||||||
|
VRF_CMD_HELP_STR)
|
||||||
|
{
|
||||||
|
char xpath_list[XPATH_MAXLEN];
|
||||||
|
struct cli_config_change changes[] = {
|
||||||
|
{
|
||||||
|
.xpath = ".",
|
||||||
|
.operation = NB_OP_DELETE,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!vrfname)
|
||||||
|
vrfname = VRF_DEFAULT_NAME;
|
||||||
|
|
||||||
|
snprintf(xpath_list, sizeof(xpath_list),
|
||||||
|
"/frr-interface:lib/interface[name='%s'][vrf='%s']", ifname,
|
||||||
|
vrfname);
|
||||||
|
|
||||||
|
return nb_cli_cfg_change(vty, xpath_list, changes, array_size(changes));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cli_show_interface(struct vty *vty, struct lyd_node *dnode,
|
||||||
|
bool show_defaults)
|
||||||
|
{
|
||||||
|
const char *vrf;
|
||||||
|
|
||||||
|
vrf = yang_dnode_get_string(dnode, "./vrf");
|
||||||
|
|
||||||
|
vty_out(vty, "!\n");
|
||||||
|
vty_out(vty, "interface %s", yang_dnode_get_string(dnode, "./name"));
|
||||||
|
if (!strmatch(vrf, VRF_DEFAULT_NAME))
|
||||||
|
vty_out(vty, " vrf %s", vrf);
|
||||||
|
vty_out(vty, "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* XPath: /frr-interface:lib/interface/description
|
||||||
|
*/
|
||||||
|
DEFPY (interface_desc,
|
||||||
|
interface_desc_cmd,
|
||||||
|
"description LINE...",
|
||||||
|
"Interface specific description\n"
|
||||||
|
"Characters describing this interface\n")
|
||||||
|
{
|
||||||
|
struct cli_config_change changes[] = {
|
||||||
|
{
|
||||||
|
.xpath = "./description",
|
||||||
|
.operation = NB_OP_MODIFY,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
char *desc;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
desc = argv_concat(argv, argc, 1);
|
||||||
|
changes[0].value = desc;
|
||||||
|
ret = nb_cli_cfg_change(vty, NULL, changes, array_size(changes));
|
||||||
|
XFREE(MTYPE_TMP, desc);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFPY (no_interface_desc,
|
||||||
|
no_interface_desc_cmd,
|
||||||
|
"no description",
|
||||||
|
NO_STR
|
||||||
|
"Interface specific description\n")
|
||||||
|
{
|
||||||
|
struct cli_config_change changes[] = {
|
||||||
|
{
|
||||||
|
.xpath = "./description",
|
||||||
|
.operation = NB_OP_DELETE,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return nb_cli_cfg_change(vty, NULL, changes, array_size(changes));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cli_show_interface_desc(struct vty *vty, struct lyd_node *dnode,
|
||||||
|
bool show_defaults)
|
||||||
|
{
|
||||||
|
vty_out(vty, " description %s\n", yang_dnode_get_string(dnode, NULL));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Interface autocomplete. */
|
||||||
|
static void if_autocomplete(vector comps, struct cmd_token *token)
|
||||||
|
{
|
||||||
|
struct interface *ifp;
|
||||||
|
struct vrf *vrf;
|
||||||
|
|
||||||
|
RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
|
||||||
|
FOR_ALL_INTERFACES (vrf, ifp) {
|
||||||
|
vector_set(comps, XSTRDUP(MTYPE_COMPLETION, ifp->name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct cmd_variable_handler if_var_handlers[] = {
|
||||||
|
{/* "interface NAME" */
|
||||||
|
.varname = "interface",
|
||||||
|
.completions = if_autocomplete},
|
||||||
|
{.tokenname = "IFNAME", .completions = if_autocomplete},
|
||||||
|
{.tokenname = "INTERFACE", .completions = if_autocomplete},
|
||||||
|
{.completions = NULL}};
|
||||||
|
|
||||||
|
void if_cmd_init(void)
|
||||||
|
{
|
||||||
|
cmd_variable_handler_register(if_var_handlers);
|
||||||
|
|
||||||
|
install_element(CONFIG_NODE, &interface_cmd);
|
||||||
|
install_element(CONFIG_NODE, &no_interface_cmd);
|
||||||
|
|
||||||
|
install_default(INTERFACE_NODE);
|
||||||
|
install_element(INTERFACE_NODE, &interface_desc_cmd);
|
||||||
|
install_element(INTERFACE_NODE, &no_interface_desc_cmd);
|
||||||
|
}
|
||||||
|
|
||||||
/* ------- Northbound callbacks ------- */
|
/* ------- Northbound callbacks ------- */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1221,14 +1284,78 @@ static int lib_interface_create(enum nb_event event,
|
|||||||
const struct lyd_node *dnode,
|
const struct lyd_node *dnode,
|
||||||
union nb_resource *resource)
|
union nb_resource *resource)
|
||||||
{
|
{
|
||||||
/* TODO: implement me. */
|
const char *ifname;
|
||||||
|
const char *vrfname;
|
||||||
|
struct vrf *vrf;
|
||||||
|
struct interface *ifp;
|
||||||
|
|
||||||
|
ifname = yang_dnode_get_string(dnode, "./name");
|
||||||
|
vrfname = yang_dnode_get_string(dnode, "./vrf");
|
||||||
|
|
||||||
|
switch (event) {
|
||||||
|
case NB_EV_VALIDATE:
|
||||||
|
vrf = vrf_lookup_by_name(vrfname);
|
||||||
|
if (!vrf) {
|
||||||
|
zlog_warn("%s: VRF %s doesn't exist", __func__,
|
||||||
|
vrfname);
|
||||||
|
return NB_ERR_VALIDATION;
|
||||||
|
}
|
||||||
|
if (vrf->vrf_id == VRF_UNKNOWN) {
|
||||||
|
zlog_warn("%s: VRF %s is not active", __func__,
|
||||||
|
vrf->name);
|
||||||
|
return NB_ERR_VALIDATION;
|
||||||
|
}
|
||||||
|
if (vrf_get_backend() == VRF_BACKEND_VRF_LITE) {
|
||||||
|
ifp = if_lookup_by_name_all_vrf(ifname);
|
||||||
|
if (ifp && ifp->vrf_id != vrf->vrf_id) {
|
||||||
|
zlog_warn(
|
||||||
|
"%s: interface %s already exists in another VRF",
|
||||||
|
__func__, ifp->name);
|
||||||
|
return NB_ERR_VALIDATION;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case NB_EV_PREPARE:
|
||||||
|
case NB_EV_ABORT:
|
||||||
|
break;
|
||||||
|
case NB_EV_APPLY:
|
||||||
|
vrf = vrf_lookup_by_name(vrfname);
|
||||||
|
assert(vrf);
|
||||||
|
#ifdef SUNOS_5
|
||||||
|
ifp = if_sunwzebra_get(ifname, vrf->vrf_id);
|
||||||
|
#else
|
||||||
|
ifp = if_get_by_name(ifname, vrf->vrf_id);
|
||||||
|
#endif /* SUNOS_5 */
|
||||||
|
yang_dnode_set_entry(dnode, ifp);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
return NB_OK;
|
return NB_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int lib_interface_delete(enum nb_event event,
|
static int lib_interface_delete(enum nb_event event,
|
||||||
const struct lyd_node *dnode)
|
const struct lyd_node *dnode)
|
||||||
{
|
{
|
||||||
/* TODO: implement me. */
|
struct interface *ifp;
|
||||||
|
|
||||||
|
ifp = yang_dnode_get_entry(dnode);
|
||||||
|
|
||||||
|
switch (event) {
|
||||||
|
case NB_EV_VALIDATE:
|
||||||
|
if (CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE)) {
|
||||||
|
zlog_warn("%s: only inactive interfaces can be deleted",
|
||||||
|
__func__);
|
||||||
|
return NB_ERR_VALIDATION;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case NB_EV_PREPARE:
|
||||||
|
case NB_EV_ABORT:
|
||||||
|
break;
|
||||||
|
case NB_EV_APPLY:
|
||||||
|
if_delete(ifp);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
return NB_OK;
|
return NB_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1239,14 +1366,33 @@ static int lib_interface_description_modify(enum nb_event event,
|
|||||||
const struct lyd_node *dnode,
|
const struct lyd_node *dnode,
|
||||||
union nb_resource *resource)
|
union nb_resource *resource)
|
||||||
{
|
{
|
||||||
/* TODO: implement me. */
|
struct interface *ifp;
|
||||||
|
const char *description;
|
||||||
|
|
||||||
|
if (event != NB_EV_APPLY)
|
||||||
|
return NB_OK;
|
||||||
|
|
||||||
|
ifp = yang_dnode_get_entry(dnode);
|
||||||
|
if (ifp->desc)
|
||||||
|
XFREE(MTYPE_TMP, ifp->desc);
|
||||||
|
description = yang_dnode_get_string(dnode, NULL);
|
||||||
|
ifp->desc = XSTRDUP(MTYPE_TMP, description);
|
||||||
|
|
||||||
return NB_OK;
|
return NB_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int lib_interface_description_delete(enum nb_event event,
|
static int lib_interface_description_delete(enum nb_event event,
|
||||||
const struct lyd_node *dnode)
|
const struct lyd_node *dnode)
|
||||||
{
|
{
|
||||||
/* TODO: implement me. */
|
struct interface *ifp;
|
||||||
|
|
||||||
|
if (event != NB_EV_APPLY)
|
||||||
|
return NB_OK;
|
||||||
|
|
||||||
|
ifp = yang_dnode_get_entry(dnode);
|
||||||
|
if (ifp->desc)
|
||||||
|
XFREE(MTYPE_TMP, ifp->desc);
|
||||||
|
|
||||||
return NB_OK;
|
return NB_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1258,11 +1404,13 @@ const struct frr_yang_module_info frr_interface_info = {
|
|||||||
.xpath = "/frr-interface:lib/interface",
|
.xpath = "/frr-interface:lib/interface",
|
||||||
.cbs.create = lib_interface_create,
|
.cbs.create = lib_interface_create,
|
||||||
.cbs.delete = lib_interface_delete,
|
.cbs.delete = lib_interface_delete,
|
||||||
|
.cbs.cli_show = cli_show_interface,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.xpath = "/frr-interface:lib/interface/description",
|
.xpath = "/frr-interface:lib/interface/description",
|
||||||
.cbs.modify = lib_interface_description_modify,
|
.cbs.modify = lib_interface_description_modify,
|
||||||
.cbs.delete = lib_interface_description_delete,
|
.cbs.delete = lib_interface_description_delete,
|
||||||
|
.cbs.cli_show = cli_show_interface_desc,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.xpath = NULL,
|
.xpath = NULL,
|
||||||
|
3
lib/if.h
3
lib/if.h
@ -474,8 +474,7 @@ extern struct interface *if_lookup_prefix(struct prefix *prefix,
|
|||||||
by a '\0' character: */
|
by a '\0' character: */
|
||||||
extern struct interface *if_lookup_by_name_all_vrf(const char *ifname);
|
extern struct interface *if_lookup_by_name_all_vrf(const char *ifname);
|
||||||
extern struct interface *if_lookup_by_name(const char *ifname, vrf_id_t vrf_id);
|
extern struct interface *if_lookup_by_name(const char *ifname, vrf_id_t vrf_id);
|
||||||
extern struct interface *if_get_by_name(const char *ifname, vrf_id_t vrf_id,
|
extern struct interface *if_get_by_name(const char *ifname, vrf_id_t vrf_id);
|
||||||
int vty);
|
|
||||||
extern void if_set_index(struct interface *ifp, ifindex_t ifindex);
|
extern void if_set_index(struct interface *ifp, ifindex_t ifindex);
|
||||||
|
|
||||||
/* Delete the interface, but do not free the structure, and leave it in the
|
/* Delete the interface, but do not free the structure, and leave it in the
|
||||||
|
@ -112,6 +112,8 @@ lib_libfrr_la_LIBADD += -lsqlite3
|
|||||||
lib_libfrr_la_SOURCES += lib/db.c
|
lib_libfrr_la_SOURCES += lib/db.c
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
lib/if_clippy.c: $(CLIPPY_DEPS)
|
||||||
|
lib/if.lo: lib/if_clippy.c
|
||||||
lib/plist_clippy.c: $(CLIPPY_DEPS)
|
lib/plist_clippy.c: $(CLIPPY_DEPS)
|
||||||
lib/plist.lo: lib/plist_clippy.c
|
lib/plist.lo: lib/plist_clippy.c
|
||||||
lib/nexthop_group_clippy.c: $(CLIPPY_DEPS)
|
lib/nexthop_group_clippy.c: $(CLIPPY_DEPS)
|
||||||
|
@ -1400,7 +1400,7 @@ struct interface *zebra_interface_add_read(struct stream *s, vrf_id_t vrf_id)
|
|||||||
stream_get(ifname_tmp, s, INTERFACE_NAMSIZ);
|
stream_get(ifname_tmp, s, INTERFACE_NAMSIZ);
|
||||||
|
|
||||||
/* Lookup/create interface by name. */
|
/* Lookup/create interface by name. */
|
||||||
ifp = if_get_by_name(ifname_tmp, vrf_id, 0);
|
ifp = if_get_by_name(ifname_tmp, vrf_id);
|
||||||
|
|
||||||
zebra_interface_if_set_value(s, ifp);
|
zebra_interface_if_set_value(s, ifp);
|
||||||
|
|
||||||
|
@ -656,7 +656,7 @@ DEFUN (ospf6_interface_area,
|
|||||||
uint32_t area_id;
|
uint32_t area_id;
|
||||||
|
|
||||||
/* find/create ospf6 interface */
|
/* find/create ospf6 interface */
|
||||||
ifp = if_get_by_name(argv[idx_ifname]->arg, VRF_DEFAULT, 0);
|
ifp = if_get_by_name(argv[idx_ifname]->arg, VRF_DEFAULT);
|
||||||
oi = (struct ospf6_interface *)ifp->info;
|
oi = (struct ospf6_interface *)ifp->info;
|
||||||
if (oi == NULL)
|
if (oi == NULL)
|
||||||
oi = ospf6_interface_create(ifp);
|
oi = ospf6_interface_create(ifp);
|
||||||
|
@ -460,7 +460,7 @@ DEFUN (ospf_passive_interface,
|
|||||||
return CMD_SUCCESS;
|
return CMD_SUCCESS;
|
||||||
}
|
}
|
||||||
if (ospf->vrf_id != VRF_UNKNOWN)
|
if (ospf->vrf_id != VRF_UNKNOWN)
|
||||||
ifp = if_get_by_name(argv[1]->arg, ospf->vrf_id, 0);
|
ifp = if_get_by_name(argv[1]->arg, ospf->vrf_id);
|
||||||
|
|
||||||
if (ifp == NULL) {
|
if (ifp == NULL) {
|
||||||
vty_out(vty, "interface %s not found.\n", (char *)argv[1]->arg);
|
vty_out(vty, "interface %s not found.\n", (char *)argv[1]->arg);
|
||||||
@ -533,7 +533,7 @@ DEFUN (no_ospf_passive_interface,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (ospf->vrf_id != VRF_UNKNOWN)
|
if (ospf->vrf_id != VRF_UNKNOWN)
|
||||||
ifp = if_get_by_name(argv[2]->arg, ospf->vrf_id, 0);
|
ifp = if_get_by_name(argv[2]->arg, ospf->vrf_id);
|
||||||
|
|
||||||
if (ifp == NULL) {
|
if (ifp == NULL) {
|
||||||
vty_out(vty, "interface %s not found.\n", (char *)argv[2]->arg);
|
vty_out(vty, "interface %s not found.\n", (char *)argv[2]->arg);
|
||||||
|
@ -110,7 +110,7 @@ static int interface_list_ioctl(void)
|
|||||||
unsigned int size;
|
unsigned int size;
|
||||||
|
|
||||||
ifreq = (struct ifreq *)((caddr_t)ifconf.ifc_req + n);
|
ifreq = (struct ifreq *)((caddr_t)ifconf.ifc_req + n);
|
||||||
ifp = if_get_by_name(ifreq->ifr_name, VRF_DEFAULT, 0);
|
ifp = if_get_by_name(ifreq->ifr_name, VRF_DEFAULT);
|
||||||
if_add_update(ifp);
|
if_add_update(ifp);
|
||||||
size = ifreq->ifr_addr.sa_len;
|
size = ifreq->ifr_addr.sa_len;
|
||||||
if (size < sizeof(ifreq->ifr_addr))
|
if (size < sizeof(ifreq->ifr_addr))
|
||||||
@ -120,7 +120,7 @@ static int interface_list_ioctl(void)
|
|||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
for (n = 0; n < ifconf.ifc_len; n += sizeof(struct ifreq)) {
|
for (n = 0; n < ifconf.ifc_len; n += sizeof(struct ifreq)) {
|
||||||
ifp = if_get_by_name(ifreq->ifr_name, VRF_DEFAULT, 0);
|
ifp = if_get_by_name(ifreq->ifr_name, VRF_DEFAULT);
|
||||||
if_add_update(ifp);
|
if_add_update(ifp);
|
||||||
ifreq++;
|
ifreq++;
|
||||||
}
|
}
|
||||||
|
@ -156,7 +156,7 @@ calculate_lifc_len:
|
|||||||
&& (*(lifreq->lifr_name + normallen) != ':'))
|
&& (*(lifreq->lifr_name + normallen) != ':'))
|
||||||
normallen++;
|
normallen++;
|
||||||
|
|
||||||
ifp = if_get_by_name(lifreq->lifr_name, VRF_DEFAULT, 0);
|
ifp = if_get_by_name(lifreq->lifr_name, VRF_DEFAULT);
|
||||||
|
|
||||||
if (lifreq->lifr_addr.ss_family == AF_INET)
|
if (lifreq->lifr_addr.ss_family == AF_INET)
|
||||||
ifp->flags |= IFF_IPV4;
|
ifp->flags |= IFF_IPV4;
|
||||||
|
@ -664,7 +664,7 @@ static int netlink_interface(struct nlmsghdr *h, ns_id_t ns_id, int startup)
|
|||||||
link_ifindex = *(ifindex_t *)RTA_DATA(tb[IFLA_LINK]);
|
link_ifindex = *(ifindex_t *)RTA_DATA(tb[IFLA_LINK]);
|
||||||
|
|
||||||
/* Add interface. */
|
/* Add interface. */
|
||||||
ifp = if_get_by_name(name, vrf_id, 0);
|
ifp = if_get_by_name(name, vrf_id);
|
||||||
set_ifindex(ifp, ifi->ifi_index, zns);
|
set_ifindex(ifp, ifi->ifi_index, zns);
|
||||||
ifp->flags = ifi->ifi_flags & 0x0000fffff;
|
ifp->flags = ifi->ifi_flags & 0x0000fffff;
|
||||||
ifp->mtu6 = ifp->mtu = *(uint32_t *)RTA_DATA(tb[IFLA_MTU]);
|
ifp->mtu6 = ifp->mtu = *(uint32_t *)RTA_DATA(tb[IFLA_MTU]);
|
||||||
@ -1198,7 +1198,7 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
|
|||||||
|
|
||||||
if (ifp == NULL) {
|
if (ifp == NULL) {
|
||||||
/* unknown interface */
|
/* unknown interface */
|
||||||
ifp = if_get_by_name(name, vrf_id, 0);
|
ifp = if_get_by_name(name, vrf_id);
|
||||||
} else {
|
} else {
|
||||||
/* pre-configured interface, learnt now */
|
/* pre-configured interface, learnt now */
|
||||||
if (ifp->vrf_id != vrf_id)
|
if (ifp->vrf_id != vrf_id)
|
||||||
|
@ -326,7 +326,7 @@ static int ifan_read(struct if_announcemsghdr *ifan)
|
|||||||
__func__, ifan->ifan_index, ifan->ifan_name);
|
__func__, ifan->ifan_index, ifan->ifan_name);
|
||||||
|
|
||||||
/* Create Interface */
|
/* Create Interface */
|
||||||
ifp = if_get_by_name(ifan->ifan_name, VRF_DEFAULT, 0);
|
ifp = if_get_by_name(ifan->ifan_name, VRF_DEFAULT);
|
||||||
if_set_index(ifp, ifan->ifan_index);
|
if_set_index(ifp, ifan->ifan_index);
|
||||||
|
|
||||||
if_get_metric(ifp);
|
if_get_metric(ifp);
|
||||||
|
Loading…
Reference in New Issue
Block a user