/* default VRF ID value used when VRF backend is not NETNS */
#define VRF_DEFAULT_INTERNAL 0
+#define VRF_DEFAULT_NAME_INTERNAL "default"
DEFINE_MTYPE_STATIC(LIB, VRF, "VRF")
DEFINE_MTYPE_STATIC(LIB, VRF_BITMAP, "VRF bit-map")
static int vrf_backend;
static struct zebra_privs_t *vrf_daemon_privs;
+static char vrf_default_name[VRF_NAMSIZ] = VRF_DEFAULT_NAME_INTERNAL;
/*
* Turn on/off debug code
int (*vrf_delete_hook)(struct vrf *);
int (*vrf_enable_hook)(struct vrf *);
int (*vrf_disable_hook)(struct vrf *);
+ int (*vrf_update_name_hook)(struct vrf *vrf);
} vrf_master = {
0,
};
*/
if (name)
vrf = vrf_lookup_by_name(name);
+ if (vrf && vrf_id != VRF_UNKNOWN
+ && vrf->vrf_id != VRF_UNKNOWN
+ && vrf->vrf_id != vrf_id) {
+ zlog_debug("VRF_GET: avoid %s creation(%u), same name exists (%u)",
+ name, vrf_id, vrf->vrf_id);
+ return NULL;
+ }
/* Try to find VRF both by ID and name */
if (!vrf && vrf_id != VRF_UNKNOWN)
vrf = vrf_lookup_by_id(vrf_id);
}
/*
- * VRF bit-map
+ * VRF hash for storing set or not.
*/
+struct vrf_bit_set {
+ vrf_id_t vrf_id;
+ bool set;
+};
+
+static unsigned int vrf_hash_bitmap_key(void *data)
+{
+ struct vrf_bit_set *bit = data;
-#define VRF_BITMAP_NUM_OF_GROUPS 1024
-#define VRF_BITMAP_NUM_OF_BITS_IN_GROUP (UINT32_MAX / VRF_BITMAP_NUM_OF_GROUPS)
-#define VRF_BITMAP_NUM_OF_BYTES_IN_GROUP \
- (VRF_BITMAP_NUM_OF_BITS_IN_GROUP / CHAR_BIT + 1) /* +1 for ensure */
+ return bit->vrf_id;
+}
-#define VRF_BITMAP_GROUP(_id) ((_id) / VRF_BITMAP_NUM_OF_BITS_IN_GROUP)
-#define VRF_BITMAP_BIT_OFFSET(_id) ((_id) % VRF_BITMAP_NUM_OF_BITS_IN_GROUP)
+static bool vrf_hash_bitmap_cmp(const void *a, const void *b)
+{
+ const struct vrf_bit_set *bit1 = a;
+ const struct vrf_bit_set *bit2 = b;
-#define VRF_BITMAP_INDEX_IN_GROUP(_bit_offset) ((_bit_offset) / CHAR_BIT)
-#define VRF_BITMAP_FLAG(_bit_offset) \
- (((uint8_t)1) << ((_bit_offset) % CHAR_BIT))
+ return bit1->vrf_id == bit2->vrf_id;
+}
-struct vrf_bitmap {
- uint8_t *groups[VRF_BITMAP_NUM_OF_GROUPS];
-};
+static void *vrf_hash_bitmap_alloc(void *data)
+{
+ struct vrf_bit_set *copy = data;
+ struct vrf_bit_set *bit;
+
+ bit = XMALLOC(MTYPE_VRF_BITMAP, sizeof(*bit));
+ bit->vrf_id = copy->vrf_id;
+
+ return bit;
+}
+
+static void vrf_hash_bitmap_free(void *data)
+{
+ struct vrf_bit_set *bit = data;
+
+ XFREE(MTYPE_VRF_BITMAP, bit);
+}
vrf_bitmap_t vrf_bitmap_init(void)
{
- return (vrf_bitmap_t)XCALLOC(MTYPE_VRF_BITMAP,
- sizeof(struct vrf_bitmap));
+ return hash_create_size(32, vrf_hash_bitmap_key, vrf_hash_bitmap_cmp,
+ "VRF BIT HASH");
}
void vrf_bitmap_free(vrf_bitmap_t bmap)
{
- struct vrf_bitmap *bm = (struct vrf_bitmap *)bmap;
- int i;
+ struct hash *vrf_hash = bmap;
- if (bmap == VRF_BITMAP_NULL)
+ if (vrf_hash == NULL)
return;
- for (i = 0; i < VRF_BITMAP_NUM_OF_GROUPS; i++)
- if (bm->groups[i])
- XFREE(MTYPE_VRF_BITMAP, bm->groups[i]);
-
- XFREE(MTYPE_VRF_BITMAP, bm);
+ hash_clean(vrf_hash, vrf_hash_bitmap_free);
+ hash_free(vrf_hash);
}
void vrf_bitmap_set(vrf_bitmap_t bmap, vrf_id_t vrf_id)
{
- struct vrf_bitmap *bm = (struct vrf_bitmap *)bmap;
- uint8_t group = VRF_BITMAP_GROUP(vrf_id);
- uint8_t offset = VRF_BITMAP_BIT_OFFSET(vrf_id);
+ struct vrf_bit_set lookup = { .vrf_id = vrf_id };
+ struct hash *vrf_hash = bmap;
+ struct vrf_bit_set *bit;
- if (bmap == VRF_BITMAP_NULL || vrf_id == VRF_UNKNOWN)
+ if (vrf_hash == NULL || vrf_id == VRF_UNKNOWN)
return;
- if (bm->groups[group] == NULL)
- bm->groups[group] = XCALLOC(MTYPE_VRF_BITMAP,
- VRF_BITMAP_NUM_OF_BYTES_IN_GROUP);
-
- SET_FLAG(bm->groups[group][VRF_BITMAP_INDEX_IN_GROUP(offset)],
- VRF_BITMAP_FLAG(offset));
+ bit = hash_get(vrf_hash, &lookup, vrf_hash_bitmap_alloc);
+ bit->set = true;
}
void vrf_bitmap_unset(vrf_bitmap_t bmap, vrf_id_t vrf_id)
{
- struct vrf_bitmap *bm = (struct vrf_bitmap *)bmap;
- uint8_t group = VRF_BITMAP_GROUP(vrf_id);
- uint8_t offset = VRF_BITMAP_BIT_OFFSET(vrf_id);
+ struct vrf_bit_set lookup = { .vrf_id = vrf_id };
+ struct hash *vrf_hash = bmap;
+ struct vrf_bit_set *bit;
- if (bmap == VRF_BITMAP_NULL || vrf_id == VRF_UNKNOWN
- || bm->groups[group] == NULL)
+ if (vrf_hash == NULL || vrf_id == VRF_UNKNOWN)
return;
- UNSET_FLAG(bm->groups[group][VRF_BITMAP_INDEX_IN_GROUP(offset)],
- VRF_BITMAP_FLAG(offset));
+ bit = hash_get(vrf_hash, &lookup, vrf_hash_bitmap_alloc);
+ bit->set = false;
}
int vrf_bitmap_check(vrf_bitmap_t bmap, vrf_id_t vrf_id)
{
- struct vrf_bitmap *bm = (struct vrf_bitmap *)bmap;
- uint8_t group = VRF_BITMAP_GROUP(vrf_id);
- uint8_t offset = VRF_BITMAP_BIT_OFFSET(vrf_id);
+ struct vrf_bit_set lookup = { .vrf_id = vrf_id };
+ struct hash *vrf_hash = bmap;
+ struct vrf_bit_set *bit;
- if (bmap == VRF_BITMAP_NULL || vrf_id == VRF_UNKNOWN
- || bm->groups[group] == NULL)
+ if (vrf_hash == NULL || vrf_id == VRF_UNKNOWN)
return 0;
- return CHECK_FLAG(bm->groups[group][VRF_BITMAP_INDEX_IN_GROUP(offset)],
- VRF_BITMAP_FLAG(offset))
- ? 1
- : 0;
+ bit = hash_lookup(vrf_hash, &lookup);
+ if (bit)
+ return bit->set;
+
+ return 0;
}
static void vrf_autocomplete(vector comps, struct cmd_token *token)
{
struct vrf *vrf = NULL;
- RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
- if (vrf->vrf_id != VRF_DEFAULT)
- vector_set(comps, XSTRDUP(MTYPE_COMPLETION, vrf->name));
- }
+ RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name)
+ vector_set(comps, XSTRDUP(MTYPE_COMPLETION, vrf->name));
}
static const struct cmd_variable_handler vrf_var_handlers[] = {
/* Initialize VRF module. */
void vrf_init(int (*create)(struct vrf *), int (*enable)(struct vrf *),
- int (*disable)(struct vrf *), int (*delete)(struct vrf *))
+ int (*disable)(struct vrf *), int (*delete)(struct vrf *),
+ int ((*update)(struct vrf *)))
{
struct vrf *default_vrf;
vrf_master.vrf_enable_hook = enable;
vrf_master.vrf_disable_hook = disable;
vrf_master.vrf_delete_hook = delete;
+ vrf_master.vrf_update_name_hook = update;
/* The default VRF always exists. */
default_vrf = vrf_get(VRF_DEFAULT, VRF_DEFAULT_NAME);
if (!default_vrf) {
- flog_err(LIB_ERR_VRF_START,
- "vrf_init: failed to create the default VRF!");
+ flog_err(EC_LIB_VRF_START,
+ "vrf_init: failed to create the default VRF!");
exit(1);
}
+ if (vrf_is_backend_netns()) {
+ struct ns *ns;
+
+ strlcpy(default_vrf->data.l.netns_name,
+ VRF_DEFAULT_NAME, NS_NAMSIZ);
+ ns = ns_lookup(ns_get_default_id());
+ ns->vrf_ctxt = default_vrf;
+ default_vrf->ns_ctxt = ns;
+ }
/* Enable the default VRF. */
if (!vrf_enable(default_vrf)) {
- flog_err(LIB_ERR_VRF_START,
- "vrf_init: failed to enable the default VRF!");
+ flog_err(EC_LIB_VRF_START,
+ "vrf_init: failed to enable the default VRF!");
exit(1);
}
ret = vrf_switch_to_netns(vrf_id);
if (ret < 0)
- flog_err_sys(LIB_ERR_SOCKET, "%s: Can't switch to VRF %u (%s)",
+ flog_err_sys(EC_LIB_SOCKET, "%s: Can't switch to VRF %u (%s)",
__func__, vrf_id, safe_strerror(errno));
if (ret > 0 && interfacename && vrf_default_accepts_vrf(type)) {
save_errno = errno;
ret2 = vrf_switchback_to_initial();
if (ret2 < 0)
- flog_err_sys(LIB_ERR_SOCKET,
+ flog_err_sys(EC_LIB_SOCKET,
"%s: Can't switchback from VRF %u (%s)", __func__,
vrf_id, safe_strerror(errno));
errno = save_errno;
"%% VRF name %s invalid: length exceeds %d bytes\n",
vrfname, VRF_NAMSIZ);
else
- zlog_warn(
+ flog_warn(
+ EC_LIB_VRF_LENGTH,
"%% VRF name %s invalid: length exceeds %d bytes\n",
vrfname, VRF_NAMSIZ);
return CMD_WARNING_CONFIG_FAILED;
"VRF %u is already configured with VRF %s\n",
vrf->vrf_id, vrf->name);
else
- zlog_warn("VRF %u is already configured with VRF %s\n",
+ zlog_info("VRF %u is already configured with VRF %s\n",
vrf->vrf_id, vrf->name);
return CMD_WARNING_CONFIG_FAILED;
}
"VRF %u already configured with NETNS %s\n",
vrf->vrf_id, ns->name);
else
- zlog_warn(
+ zlog_info(
"VRF %u already configured with NETNS %s",
vrf->vrf_id, ns->name);
return CMD_WARNING_CONFIG_FAILED;
" with VRF %u(%s)\n",
ns->name, vrf2->vrf_id, vrf2->name);
else
- zlog_warn("NS %s is already configured with VRF %u(%s)",
+ zlog_info("NS %s is already configured with VRF %u(%s)",
ns->name, vrf2->vrf_id, vrf2->name);
return CMD_WARNING_CONFIG_FAILED;
}
vty_out(vty, "Can not associate NS %u with NETNS %s\n",
ns->ns_id, ns->name);
else
- zlog_warn("Can not associate NS %u with NETNS %s",
+ zlog_info("Can not associate NS %u with NETNS %s",
ns->ns_id, ns->name);
return CMD_WARNING_CONFIG_FAILED;
}
{
if (!vrf || vrf->data.l.netns_name[0] == '\0')
return 0;
- if (vrf->vrf_id == VRF_DEFAULT)
- return 0;
return 1;
}
}
}
-vrf_id_t vrf_get_default_id(void)
+void vrf_set_default_name(const char *default_name, bool force)
+{
+ struct vrf *def_vrf;
+ struct vrf *vrf_with_default_name = NULL;
+ static bool def_vrf_forced;
+
+ def_vrf = vrf_lookup_by_id(VRF_DEFAULT);
+ assert(default_name);
+ if (def_vrf && !force && def_vrf_forced) {
+ zlog_debug("VRF: %s, avoid changing name to %s, previously forced (%u)",
+ def_vrf->name, default_name,
+ def_vrf->vrf_id);
+ return;
+ }
+ if (vrf_with_default_name && vrf_with_default_name != def_vrf) {
+ /* vrf name already used by an other VRF */
+ zlog_debug("VRF: %s, avoid changing name to %s, same name exists (%u)",
+ vrf_with_default_name->name, default_name,
+ vrf_with_default_name->vrf_id);
+ return;
+ }
+ snprintf(vrf_default_name, VRF_NAMSIZ, "%s", default_name);
+ if (def_vrf) {
+ if (force)
+ def_vrf_forced = true;
+ RB_REMOVE(vrf_name_head, &vrfs_by_name, def_vrf);
+ strlcpy(def_vrf->data.l.netns_name,
+ vrf_default_name, NS_NAMSIZ);
+ strlcpy(def_vrf->name, vrf_default_name, sizeof(def_vrf->name));
+ RB_INSERT(vrf_name_head, &vrfs_by_name, def_vrf);
+ if (vrf_master.vrf_update_name_hook)
+ (*vrf_master.vrf_update_name_hook)(def_vrf);
+ }
+}
+
+const char *vrf_get_default_name(void)
{
- struct vrf *vrf = vrf_lookup_by_name(VRF_DEFAULT_NAME);
+ return vrf_default_name;
+}
- if (vrf)
- return vrf->vrf_id;
+vrf_id_t vrf_get_default_id(void)
+{
/* backend netns is only known by zebra
* for other daemons, we return VRF_DEFAULT_INTERNAL
*/
ret = vrf_switch_to_netns(vrf_id);
if (ret < 0)
- flog_err_sys(LIB_ERR_SOCKET, "%s: Can't switch to VRF %u (%s)",
+ flog_err_sys(EC_LIB_SOCKET, "%s: Can't switch to VRF %u (%s)",
__func__, vrf_id, safe_strerror(errno));
ret = getaddrinfo(node, service, hints, res);
save_errno = errno;
ret2 = vrf_switchback_to_initial();
if (ret2 < 0)
- flog_err_sys(LIB_ERR_SOCKET,
+ flog_err_sys(EC_LIB_SOCKET,
"%s: Can't switchback from VRF %u (%s)", __func__,
vrf_id, safe_strerror(errno));
errno = save_errno;
ret = vrf_switch_to_netns(vrf_id);
if (ret < 0) {
- flog_err_sys(LIB_ERR_SOCKET, "%s: Can't switch to VRF %u (%s)",
+ flog_err_sys(EC_LIB_SOCKET, "%s: Can't switch to VRF %u (%s)",
__func__, vrf_id, safe_strerror(errno));
return 0;
}
saved_errno = errno;
ret = vrf_switchback_to_initial();
if (ret < 0)
- flog_err_sys(LIB_ERR_SOCKET,
+ flog_err_sys(EC_LIB_SOCKET,
"%s: Can't switchback from VRF %u (%s)", __func__,
vrf_id, safe_strerror(errno));
errno = saved_errno;
ret = vrf_switch_to_netns(vrf_id);
if (ret < 0)
- flog_err_sys(LIB_ERR_SOCKET, "%s: Can't switch to VRF %u (%s)",
+ flog_err_sys(EC_LIB_SOCKET, "%s: Can't switch to VRF %u (%s)",
__func__, vrf_id, safe_strerror(errno));
ret = sockunion_socket(su);
save_errno = errno;
ret2 = vrf_switchback_to_initial();
if (ret2 < 0)
- flog_err_sys(LIB_ERR_SOCKET,
+ flog_err_sys(EC_LIB_SOCKET,
"%s: Can't switchback from VRF %u (%s)", __func__,
vrf_id, safe_strerror(errno));
errno = save_errno;
}
return ret;
}
+
+vrf_id_t vrf_generate_id(void)
+{
+ static int vrf_id_local;
+
+ return ++vrf_id_local;
+}