summaryrefslogtreecommitdiff
path: root/lib/if.c
diff options
context:
space:
mode:
authorIgor Ryzhov <iryzhov@nfware.com>2021-10-13 15:06:38 +0300
committerIgor Ryzhov <iryzhov@nfware.com>2021-10-19 15:29:51 +0300
commitf60a11883cb426f574dbe5abeff8254148e7c371 (patch)
tree2b489718f0d61ed4c5b043959bcbe3e18035d874 /lib/if.c
parente9f7b2b597ad8c6947ce3b7238e89391e4f9f863 (diff)
lib: allow to create interfaces in non-existing VRFs
It allows FRR to read the interface config even when the necessary VRFs are not yet created and interfaces are in "wrong" VRFs. Currently, such config is rejected. For VRF-lite backend, we don't care at all about the VRF of the inactive interface. When the interface is created in the OS and becomes active, we always use its actual VRF instead of the configured one. So there's no need to reject the config. For netns backend, we may have multiple interfaces with the same name in different VRFs. So we care about the VRF of inactive interfaces. And we must allow to preconfigure the interface in a VRF even before it is moved to the corresponding netns. From now on, we allow to create multiple configs for the same interface name in different VRFs and the necessary config is applied once the OS interface is moved to the corresponding netns. Signed-off-by: Igor Ryzhov <iryzhov@nfware.com>
Diffstat (limited to 'lib/if.c')
-rw-r--r--lib/if.c274
1 files changed, 109 insertions, 165 deletions
diff --git a/lib/if.c b/lib/if.c
index f316d1a9b7..cb6270f5ec 100644
--- a/lib/if.c
+++ b/lib/if.c
@@ -45,6 +45,7 @@ DEFINE_MTYPE_STATIC(LIB, NBR_CONNECTED, "Neighbor Connected");
DEFINE_MTYPE(LIB, CONNECTED_LABEL, "Connected interface label");
DEFINE_MTYPE_STATIC(LIB, IF_LINK_PARAMS, "Informational Link Parameters");
+static void if_set_name(struct interface *ifp, const char *name);
static struct interface *if_lookup_by_ifindex(ifindex_t ifindex,
vrf_id_t vrf_id);
static int if_cmp_func(const struct interface *, const struct interface *);
@@ -153,16 +154,19 @@ static void ifp_connected_free(void *arg)
}
/* Create new interface structure. */
-static struct interface *if_new(vrf_id_t vrf_id)
+static struct interface *if_new(struct vrf *vrf)
{
struct interface *ifp;
+ assert(vrf);
+
ifp = XCALLOC(MTYPE_IF, sizeof(struct interface));
ifp->ifindex = IFINDEX_INTERNAL;
ifp->name[0] = '\0';
- ifp->vrf_id = vrf_id;
+ ifp->vrf = vrf;
+ ifp->vrf_id = vrf->vrf_id;
ifp->connected = list_new();
ifp->connected->del = ifp_connected_free;
@@ -207,11 +211,11 @@ void if_down_via_zapi(struct interface *ifp)
(*ifp_master.down_hook)(ifp);
}
-struct interface *if_create_name(const char *name, vrf_id_t vrf_id)
+static struct interface *if_create_name(const char *name, struct vrf *vrf)
{
struct interface *ifp;
- ifp = if_new(vrf_id);
+ ifp = if_new(vrf);
if_set_name(ifp, name);
@@ -219,35 +223,23 @@ struct interface *if_create_name(const char *name, vrf_id_t vrf_id)
return ifp;
}
-struct interface *if_create_ifindex(ifindex_t ifindex, vrf_id_t vrf_id)
-{
- struct interface *ifp;
-
- ifp = if_new(vrf_id);
-
- if_set_index(ifp, ifindex);
-
- hook_call(if_add, ifp);
- return ifp;
-}
-
/* Create new interface structure. */
void if_update_to_new_vrf(struct interface *ifp, vrf_id_t vrf_id)
{
struct vrf *old_vrf, *vrf;
/* remove interface from old master vrf list */
- old_vrf = vrf_lookup_by_id(ifp->vrf_id);
- if (old_vrf) {
- if (ifp->name[0] != '\0')
- IFNAME_RB_REMOVE(old_vrf, ifp);
+ old_vrf = ifp->vrf;
- if (ifp->ifindex != IFINDEX_INTERNAL)
- IFINDEX_RB_REMOVE(old_vrf, ifp);
- }
+ if (ifp->name[0] != '\0')
+ IFNAME_RB_REMOVE(old_vrf, ifp);
+
+ if (ifp->ifindex != IFINDEX_INTERNAL)
+ IFINDEX_RB_REMOVE(old_vrf, ifp);
ifp->vrf_id = vrf_id;
vrf = vrf_get(ifp->vrf_id, NULL);
+ ifp->vrf = vrf;
if (ifp->name[0] != '\0')
IFNAME_RB_INSERT(vrf, ifp);
@@ -261,7 +253,7 @@ void if_update_to_new_vrf(struct interface *ifp, vrf_id_t vrf_id)
* the interface and readding it in the new VRF, which would have
* several implications.
*/
- if (yang_module_find("frr-interface")) {
+ if (!vrf_is_backend_netns() && yang_module_find("frr-interface")) {
struct lyd_node *if_dnode;
char oldpath[XPATH_MAXLEN];
char newpath[XPATH_MAXLEN];
@@ -304,15 +296,15 @@ void if_delete_retain(struct interface *ifp)
void if_delete(struct interface **ifp)
{
struct interface *ptr = *ifp;
- struct vrf *vrf;
-
- vrf = vrf_lookup_by_id(ptr->vrf_id);
- assert(vrf);
+ struct vrf *vrf = ptr->vrf;
IFNAME_RB_REMOVE(vrf, ptr);
if (ptr->ifindex != IFINDEX_INTERNAL)
IFINDEX_RB_REMOVE(vrf, ptr);
+ if (!vrf_is_enabled(vrf))
+ vrf_delete(vrf);
+
if_delete_retain(ptr);
list_delete(&ptr->connected);
@@ -439,7 +431,7 @@ struct interface *if_lookup_by_name_all_vrf(const char *name)
if (!name || strnlen(name, INTERFACE_NAMSIZ) == INTERFACE_NAMSIZ)
return NULL;
- RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) {
+ RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
ifp = if_lookup_by_name_vrf(name, vrf);
if (ifp)
return ifp;
@@ -582,72 +574,58 @@ size_t if_lookup_by_hwaddr(const uint8_t *hw_addr, size_t addrsz,
/* Get interface by name if given name interface doesn't exist create
one. */
-struct interface *if_get_by_name(const char *name, vrf_id_t vrf_id)
+struct interface *if_get_by_name(const char *name, vrf_id_t vrf_id,
+ const char *vrf_name)
{
- struct interface *ifp;
+ struct interface *ifp = NULL;
+ struct vrf *vrf;
switch (vrf_get_backend()) {
case VRF_BACKEND_UNKNOWN:
case VRF_BACKEND_NETNS:
- ifp = if_lookup_by_name(name, vrf_id);
- if (ifp)
- return ifp;
- return if_create_name(name, vrf_id);
- case VRF_BACKEND_VRF_LITE:
- ifp = if_lookup_by_name_all_vrf(name);
+ vrf = vrf_get(vrf_id, vrf_name);
+ assert(vrf);
+
+ ifp = if_lookup_by_name_vrf(name, vrf);
if (ifp) {
- if (ifp->vrf_id == vrf_id)
- return ifp;
/* 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 (ifp->vrf_id != vrf_id && vrf_id != VRF_UNKNOWN)
+ if_update_to_new_vrf(ifp, vrf_id);
+
return ifp;
}
- return if_create_name(name, vrf_id);
- }
- return NULL;
-}
-
-struct interface *if_get_by_ifindex(ifindex_t ifindex, vrf_id_t vrf_id)
-{
- struct interface *ifp;
-
- switch (vrf_get_backend()) {
- case VRF_BACKEND_UNKNOWN:
- case VRF_BACKEND_NETNS:
- ifp = if_lookup_by_ifindex(ifindex, vrf_id);
- if (ifp)
- return ifp;
- return if_create_ifindex(ifindex, vrf_id);
+ break;
case VRF_BACKEND_VRF_LITE:
- ifp = if_lookup_by_index_all_vrf(ifindex);
+ ifp = if_lookup_by_name_all_vrf(name);
if (ifp) {
- if (ifp->vrf_id == vrf_id)
- return ifp;
/* 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 (ifp->vrf_id != vrf_id && vrf_id != VRF_UNKNOWN)
+ if_update_to_new_vrf(ifp, vrf_id);
+
return ifp;
}
- return if_create_ifindex(ifindex, vrf_id);
+
+ vrf = vrf_get(vrf_id, vrf_name);
+ assert(vrf);
+
+ break;
+ default:
+ return NULL;
}
- return NULL;
+ return if_create_name(name, vrf);
}
int if_set_index(struct interface *ifp, ifindex_t ifindex)
{
- struct vrf *vrf;
-
if (ifp->ifindex == ifindex)
return 0;
- vrf = vrf_get(ifp->vrf_id, NULL);
- assert(vrf);
-
/*
* If there is already an interface with this ifindex, we will collide
* on insertion, so don't even try.
@@ -656,7 +634,7 @@ int if_set_index(struct interface *ifp, ifindex_t ifindex)
return -1;
if (ifp->ifindex != IFINDEX_INTERNAL)
- IFINDEX_RB_REMOVE(vrf, ifp);
+ IFINDEX_RB_REMOVE(ifp->vrf, ifp);
ifp->ifindex = ifindex;
@@ -666,30 +644,25 @@ int if_set_index(struct interface *ifp, ifindex_t ifindex)
* already an interface with the desired ifindex at the top of
* the function. Nevertheless.
*/
- if (IFINDEX_RB_INSERT(vrf, ifp))
+ if (IFINDEX_RB_INSERT(ifp->vrf, ifp))
return -1;
}
return 0;
}
-void if_set_name(struct interface *ifp, const char *name)
+static void if_set_name(struct interface *ifp, const char *name)
{
- struct vrf *vrf;
-
- vrf = vrf_get(ifp->vrf_id, NULL);
- assert(vrf);
-
if (if_cmp_name_func(ifp->name, name) == 0)
return;
if (ifp->name[0] != '\0')
- IFNAME_RB_REMOVE(vrf, ifp);
+ IFNAME_RB_REMOVE(ifp->vrf, ifp);
strlcpy(ifp->name, name, sizeof(ifp->name));
if (ifp->name[0] != '\0')
- IFNAME_RB_INSERT(vrf, ifp);
+ IFNAME_RB_INSERT(ifp->vrf, ifp);
}
/* Does interface up ? */
@@ -817,15 +790,12 @@ static void if_dump(const struct interface *ifp)
struct listnode *node;
struct connected *c __attribute__((unused));
- for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, c)) {
- struct vrf *vrf = vrf_lookup_by_id(ifp->vrf_id);
-
+ for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, c))
zlog_info(
"Interface %s vrf %s(%u) index %d metric %d mtu %d mtu6 %d %s",
- ifp->name, VRF_LOGNAME(vrf), ifp->vrf_id, ifp->ifindex,
+ ifp->name, ifp->vrf->name, ifp->vrf_id, ifp->ifindex,
ifp->metric, ifp->mtu, ifp->mtu6,
if_flag_dump(ifp->flags));
- }
}
/* Interface printing for all interface. */
@@ -894,16 +864,14 @@ connected_log(struct connected *connected, char *str)
{
struct prefix *p;
struct interface *ifp;
- struct vrf *vrf;
char logbuf[BUFSIZ];
char buf[BUFSIZ];
ifp = connected->ifp;
p = connected->address;
- vrf = vrf_lookup_by_id(ifp->vrf_id);
snprintf(logbuf, sizeof(logbuf), "%s interface %s vrf %s(%u) %s %pFX ",
- str, ifp->name, VRF_LOGNAME(vrf), ifp->vrf_id,
+ str, ifp->name, ifp->vrf->name, ifp->vrf_id,
prefix_family_str(p), p);
p = connected->destination;
@@ -1059,30 +1027,15 @@ struct connected *connected_get_linklocal(struct interface *ifp)
void if_terminate(struct vrf *vrf)
{
struct interface *ifp;
- bool delete;
-
- /*
- * If the default VRF is being terminated or has
- * already been terminated it means that
- * the program is shutting down and we need to
- * delete all the interfaces. Otherwise, we only
- * need to move VRF's interfaces to the default VRF.
- */
- delete = vrf_is_backend_netns() || vrf->vrf_id == VRF_DEFAULT
- || !vrf_lookup_by_id(VRF_DEFAULT);
while (!RB_EMPTY(if_name_head, &vrf->ifaces_by_name)) {
ifp = RB_ROOT(if_name_head, &vrf->ifaces_by_name);
- if (delete) {
- if (ifp->node) {
- ifp->node->info = NULL;
- route_unlock_node(ifp->node);
- }
- if_delete(&ifp);
- } else {
- if_update_to_new_vrf(ifp, VRF_DEFAULT);
+ if (ifp->node) {
+ ifp->node->info = NULL;
+ route_unlock_node(ifp->node);
}
+ if_delete(&ifp);
}
}
@@ -1186,6 +1139,25 @@ void if_link_params_free(struct interface *ifp)
/* ----------- CLI commands ----------- */
+/* Guess the VRF of an interface. */
+static int vrfname_by_ifname(const char *ifname, const char **vrfname)
+{
+ struct vrf *vrf;
+ struct interface *ifp;
+ int count = 0;
+
+ RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
+ FOR_ALL_INTERFACES (vrf, ifp) {
+ if (strmatch(ifp->name, ifname)) {
+ *vrfname = vrf->name;
+ count++;
+ }
+ }
+ }
+
+ return count;
+}
+
/*
* XPath: /frr-interface:lib/interface
*/
@@ -1197,12 +1169,9 @@ DEFPY_YANG_NOSH (interface,
VRF_CMD_HELP_STR)
{
char xpath_list[XPATH_MAXLEN];
- vrf_id_t vrf_id;
struct interface *ifp;
- int ret;
-
- if (!vrf_name)
- vrf_name = VRF_DEFAULT_NAME;
+ struct vrf *vrf;
+ int ret, count;
/*
* This command requires special handling to maintain backward
@@ -1211,30 +1180,30 @@ DEFPY_YANG_NOSH (interface,
* interface is found, then a new one should be created on the default
* VRF.
*/
- VRF_GET_ID(vrf_id, vrf_name, false);
- ifp = if_lookup_by_name_all_vrf(ifname);
- if (ifp && ifp->vrf_id != vrf_id) {
- struct vrf *vrf;
-
+ if (vrf_is_backend_netns()) {
/*
- * Special case 1: a VRF name was specified, but the found
- * interface is associated to different VRF. Reject the command.
+ * For backward compatibility, if the VRF name is not specified
+ * and there is exactly one interface with this name in the
+ * system, use its VRF. Otherwise fallback to the default VRF.
*/
- if (vrf_id != VRF_DEFAULT) {
- vty_out(vty, "%% interface %s not in %s vrf\n", ifname,
- vrf_name);
- return CMD_WARNING_CONFIG_FAILED;
+ if (!vrf_name) {
+ count = vrfname_by_ifname(ifname, &vrf_name);
+ if (count != 1)
+ vrf_name = VRF_DEFAULT_NAME;
}
-
+ } else {
/*
- * 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 vrf_name to account for that.
+ * If the interface already exists, use its VRF regardless of
+ * what user specified. We can't have same interface name in
+ * different VRFs with VRF-lite backend.
*/
- vrf = vrf_lookup_by_id(ifp->vrf_id);
- assert(vrf);
- vrf_id = ifp->vrf_id;
- vrf_name = vrf->name;
+ ifp = if_lookup_by_name_all_vrf(ifname);
+ if (ifp) {
+ vrf_name = ifp->vrf->name;
+ } else {
+ if (!vrf_name)
+ vrf_name = VRF_DEFAULT_NAME;
+ }
}
snprintf(xpath_list, sizeof(xpath_list),
@@ -1252,7 +1221,15 @@ DEFPY_YANG_NOSH (interface,
* all interface-level commands are converted to the new
* northbound model.
*/
- ifp = if_lookup_by_name(ifname, vrf_id);
+ if (vrf_is_backend_netns()) {
+ vrf = vrf_lookup_by_name(vrf_name);
+ if (vrf)
+ ifp = if_lookup_by_name_vrf(ifname, vrf);
+ else
+ ifp = NULL;
+ } else {
+ ifp = if_lookup_by_name_all_vrf(ifname);
+ }
if (ifp)
VTY_PUSH_CONTEXT(INTERFACE_NODE, ifp);
}
@@ -1397,7 +1374,6 @@ static int lib_interface_create(struct nb_cb_create_args *args)
{
const char *ifname;
const char *vrfname;
- struct vrf *vrf;
struct interface *ifp;
ifname = yang_dnode_get_string(args->dnode, "./name");
@@ -1405,39 +1381,11 @@ static int lib_interface_create(struct nb_cb_create_args *args)
switch (args->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 is netns or not yet known - init for instance
- * then assumption is that passed config is exact
- * then the user intent was not to use an other iface
- */
- 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);
- ifp = if_get_by_name(ifname, vrf->vrf_id);
+ ifp = if_get_by_name(ifname, VRF_UNKNOWN, vrfname);
ifp->configured = true;
nb_running_set_entry(args->dnode, ifp);
@@ -1488,7 +1436,7 @@ static const void *lib_interface_get_next(struct nb_cb_get_next_args *args)
assert(vrf);
pif = RB_MIN(if_name_head, &vrf->ifaces_by_name);
} else {
- vrf = vrf_lookup_by_id(pif->vrf_id);
+ vrf = pif->vrf;
pif = RB_NEXT(if_name_head, pif);
/* if no more interfaces, switch to next vrf */
while (pif == NULL) {
@@ -1506,13 +1454,9 @@ static int lib_interface_get_keys(struct nb_cb_get_keys_args *args)
{
const struct interface *ifp = args->list_entry;
- struct vrf *vrf = vrf_lookup_by_id(ifp->vrf_id);
-
- assert(vrf);
-
args->keys->num = 2;
strlcpy(args->keys->key[0], ifp->name, sizeof(args->keys->key[0]));
- strlcpy(args->keys->key[1], vrf->name, sizeof(args->keys->key[1]));
+ strlcpy(args->keys->key[1], ifp->vrf->name, sizeof(args->keys->key[1]));
return NB_OK;
}