summaryrefslogtreecommitdiff
path: root/zebra/zebra_vrf.c
diff options
context:
space:
mode:
Diffstat (limited to 'zebra/zebra_vrf.c')
-rw-r--r--zebra/zebra_vrf.c191
1 files changed, 184 insertions, 7 deletions
diff --git a/zebra/zebra_vrf.c b/zebra/zebra_vrf.c
index 2430b51989..d051ed67a0 100644
--- a/zebra/zebra_vrf.c
+++ b/zebra/zebra_vrf.c
@@ -20,6 +20,9 @@
*/
#include <zebra.h>
+/* for basename */
+#include <libgen.h>
+
#include "log.h"
#include "linklist.h"
#include "command.h"
@@ -41,6 +44,10 @@
#include "zebra/zebra_vxlan.h"
#include "zebra/zebra_netns_notify.h"
#include "zebra/zebra_routemap.h"
+#ifndef VTYSH_EXTRACT_PL
+#include "zebra/zebra_vrf_clippy.c"
+#endif
+#include "zebra/table_manager.h"
static void zebra_vrf_table_create(struct zebra_vrf *zvrf, afi_t afi,
safi_t safi);
@@ -110,6 +117,10 @@ static int zebra_vrf_new(struct vrf *vrf)
otable_init(&zvrf->other_tables);
router_id_init(zvrf);
+
+ /* Initiate Table Manager per ZNS */
+ table_manager_enable(zvrf);
+
return 0;
}
@@ -150,7 +161,7 @@ static int zebra_vrf_enable(struct vrf *vrf)
table = route_table_init();
table->cleanup = zebra_rnhtable_node_cleanup;
- zvrf->import_check_table[afi] = table;
+ zvrf->rnh_table_multicast[afi] = table;
}
/* Kick off any VxLAN-EVPN processing. */
@@ -173,6 +184,8 @@ static int zebra_vrf_disable(struct vrf *vrf)
zlog_debug("VRF %s id %u is now inactive", zvrf_name(zvrf),
zvrf_id(zvrf));
+ table_manager_disable(zvrf);
+
/* Stop any VxLAN-EVPN processing. */
zebra_vxlan_vrf_disable(zvrf);
@@ -193,8 +206,8 @@ static int zebra_vrf_disable(struct vrf *vrf)
for (afi = AFI_IP; afi <= AFI_IP6; afi++) {
route_table_finish(zvrf->rnh_table[afi]);
zvrf->rnh_table[afi] = NULL;
- route_table_finish(zvrf->import_check_table[afi]);
- zvrf->import_check_table[afi] = NULL;
+ route_table_finish(zvrf->rnh_table_multicast[afi]);
+ zvrf->rnh_table_multicast[afi] = NULL;
for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST; safi++)
rib_close_table(zvrf->table[afi][safi]);
@@ -295,8 +308,8 @@ static int zebra_vrf_delete(struct vrf *vrf)
if (zvrf->rnh_table[afi])
route_table_finish(zvrf->rnh_table[afi]);
- if (zvrf->import_check_table[afi])
- route_table_finish(zvrf->import_check_table[afi]);
+ if (zvrf->rnh_table_multicast[afi])
+ route_table_finish(zvrf->rnh_table[afi]);
}
otable = otable_pop(&zvrf->other_tables);
@@ -500,6 +513,12 @@ static int vrf_config_write(struct vty *vty)
if (zvrf->zebra_rnh_ipv6_default_route)
vty_out(vty, "ipv6 nht resolve-via-default\n");
+
+ if (zvrf->tbl_mgr
+ && (zvrf->tbl_mgr->start || zvrf->tbl_mgr->end))
+ vty_out(vty, "ip table range %u %u\n",
+ zvrf->tbl_mgr->start,
+ zvrf->tbl_mgr->end);
} else {
vty_frame(vty, "vrf %s\n", zvrf_name(zvrf));
if (zvrf->l3vni)
@@ -514,6 +533,12 @@ static int vrf_config_write(struct vty *vty)
if (zvrf->zebra_rnh_ipv6_default_route)
vty_out(vty, " ipv6 nht resolve-via-default\n");
+
+ if (zvrf->tbl_mgr && vrf_is_backend_netns()
+ && (zvrf->tbl_mgr->start || zvrf->tbl_mgr->end))
+ vty_out(vty, " ip table range %u %u\n",
+ zvrf->tbl_mgr->start,
+ zvrf->tbl_mgr->end);
}
@@ -521,18 +546,170 @@ static int vrf_config_write(struct vty *vty)
router_id_write(vty, zvrf);
if (zvrf_id(zvrf) != VRF_DEFAULT)
- vty_endframe(vty, " exit-vrf\n!\n");
+ vty_endframe(vty, "exit-vrf\n!\n");
else
vty_out(vty, "!\n");
}
return 0;
}
+DEFPY (vrf_netns,
+ vrf_netns_cmd,
+ "netns NAME$netns_name",
+ "Attach VRF to a Namespace\n"
+ "The file name in " NS_RUN_DIR ", or a full pathname\n")
+{
+ char *pathname = ns_netns_pathname(vty, netns_name);
+ int ret;
+
+ VTY_DECLVAR_CONTEXT(vrf, vrf);
+
+ if (!pathname)
+ return CMD_WARNING_CONFIG_FAILED;
+
+ frr_with_privs(&zserv_privs) {
+ ret = zebra_vrf_netns_handler_create(
+ vty, vrf, pathname, NS_UNKNOWN, NS_UNKNOWN, NS_UNKNOWN);
+ }
+
+ return ret;
+}
+
+DEFUN (no_vrf_netns,
+ no_vrf_netns_cmd,
+ "no netns [NAME]",
+ NO_STR
+ "Detach VRF from a Namespace\n"
+ "The file name in " NS_RUN_DIR ", or a full pathname\n")
+{
+ struct ns *ns = NULL;
+
+ VTY_DECLVAR_CONTEXT(vrf, vrf);
+
+ if (!vrf_is_backend_netns()) {
+ vty_out(vty, "VRF backend is not Netns. Aborting\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+ if (!vrf->ns_ctxt) {
+ vty_out(vty, "VRF %s(%u) is not configured with NetNS\n",
+ vrf->name, vrf->vrf_id);
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ ns = (struct ns *)vrf->ns_ctxt;
+
+ ns->vrf_ctxt = NULL;
+ vrf_disable(vrf);
+ /* vrf ID from VRF is necessary for Zebra
+ * so that propagate to other clients is done
+ */
+ ns_delete(ns);
+ vrf->ns_ctxt = NULL;
+ return CMD_SUCCESS;
+}
+
+/* if ns_id is different and not VRF_UNKNOWN,
+ * then update vrf identifier, and enable VRF
+ */
+static void vrf_update_vrf_id(ns_id_t ns_id, void *opaqueptr)
+{
+ ns_id_t vrf_id = (vrf_id_t)ns_id;
+ vrf_id_t old_vrf_id;
+ struct vrf *vrf = (struct vrf *)opaqueptr;
+
+ if (!vrf)
+ return;
+ old_vrf_id = vrf->vrf_id;
+ if (vrf_id == vrf->vrf_id)
+ return;
+ if (vrf->vrf_id != VRF_UNKNOWN)
+ RB_REMOVE(vrf_id_head, &vrfs_by_id, vrf);
+ vrf->vrf_id = vrf_id;
+ RB_INSERT(vrf_id_head, &vrfs_by_id, vrf);
+ if (old_vrf_id == VRF_UNKNOWN)
+ vrf_enable(vrf);
+}
+
+int zebra_vrf_netns_handler_create(struct vty *vty, struct vrf *vrf,
+ char *pathname, ns_id_t ns_id,
+ ns_id_t internal_ns_id,
+ ns_id_t rel_def_ns_id)
+{
+ struct ns *ns = NULL;
+
+ if (!vrf)
+ return CMD_WARNING_CONFIG_FAILED;
+ if (vrf->vrf_id != VRF_UNKNOWN && vrf->ns_ctxt == NULL) {
+ if (vty)
+ vty_out(vty,
+ "VRF %u is already configured with VRF %s\n",
+ vrf->vrf_id, vrf->name);
+ else
+ zlog_info("VRF %u is already configured with VRF %s",
+ vrf->vrf_id, vrf->name);
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+ if (vrf->ns_ctxt != NULL) {
+ ns = (struct ns *)vrf->ns_ctxt;
+ if (!strcmp(ns->name, pathname)) {
+ if (vty)
+ vty_out(vty,
+ "VRF %u already configured with NETNS %s\n",
+ vrf->vrf_id, ns->name);
+ else
+ zlog_info(
+ "VRF %u already configured with NETNS %s",
+ vrf->vrf_id, ns->name);
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+ }
+ ns = ns_lookup_name(pathname);
+ if (ns && ns->vrf_ctxt) {
+ struct vrf *vrf2 = (struct vrf *)ns->vrf_ctxt;
+
+ if (vrf2 == vrf)
+ return CMD_SUCCESS;
+ if (vty)
+ vty_out(vty,
+ "NS %s is already configured with VRF %u(%s)\n",
+ ns->name, vrf2->vrf_id, vrf2->name);
+ else
+ zlog_info("NS %s is already configured with VRF %u(%s)",
+ ns->name, vrf2->vrf_id, vrf2->name);
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+ ns = ns_get_created(ns, pathname, ns_id);
+ ns->internal_ns_id = internal_ns_id;
+ ns->relative_default_ns = rel_def_ns_id;
+ ns->vrf_ctxt = (void *)vrf;
+ vrf->ns_ctxt = (void *)ns;
+ /* update VRF netns NAME */
+ strlcpy(vrf->data.l.netns_name, basename(pathname), NS_NAMSIZ);
+
+ if (!ns_enable(ns, vrf_update_vrf_id)) {
+ if (vty)
+ vty_out(vty, "Can not associate NS %u with NETNS %s\n",
+ ns->ns_id, ns->name);
+ else
+ zlog_info("Can not associate NS %u with NETNS %s",
+ ns->ns_id, ns->name);
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ return CMD_SUCCESS;
+}
+
/* Zebra VRF initialization. */
void zebra_vrf_init(void)
{
vrf_init(zebra_vrf_new, zebra_vrf_enable, zebra_vrf_disable,
zebra_vrf_delete, zebra_vrf_update);
- vrf_cmd_init(vrf_config_write, &zserv_privs);
+ vrf_cmd_init(vrf_config_write);
+
+ if (vrf_is_backend_netns() && ns_have_netns()) {
+ /* Install NS commands. */
+ install_element(VRF_NODE, &vrf_netns_cmd);
+ install_element(VRF_NODE, &no_vrf_netns_cmd);
+ }
}