summaryrefslogtreecommitdiffstats
path: root/nhrpd/nhrp_vty.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-09 13:16:35 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-09 13:16:35 +0000
commite2bbf175a2184bd76f6c54ccf8456babeb1a46fc (patch)
treef0b76550d6e6f500ada964a3a4ee933a45e5a6f1 /nhrpd/nhrp_vty.c
parentInitial commit. (diff)
downloadfrr-e2bbf175a2184bd76f6c54ccf8456babeb1a46fc.tar.xz
frr-e2bbf175a2184bd76f6c54ccf8456babeb1a46fc.zip
Adding upstream version 9.1.upstream/9.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'nhrpd/nhrp_vty.c')
-rw-r--r--nhrpd/nhrp_vty.c1271
1 files changed, 1271 insertions, 0 deletions
diff --git a/nhrpd/nhrp_vty.c b/nhrpd/nhrp_vty.c
new file mode 100644
index 0000000..40d38c4
--- /dev/null
+++ b/nhrpd/nhrp_vty.c
@@ -0,0 +1,1271 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/* NHRP vty handling
+ * Copyright (c) 2014-2015 Timo Teräs
+ */
+
+#include "zebra.h"
+#include "command.h"
+#include "zclient.h"
+#include "stream.h"
+#include "filter.h"
+#include "json.h"
+
+#include "nhrpd.h"
+#include "netlink.h"
+
+static int nhrp_config_write(struct vty *vty);
+static struct cmd_node zebra_node = {
+ .name = "zebra",
+ .node = ZEBRA_NODE,
+ .parent_node = CONFIG_NODE,
+ .prompt = "%s(config-router)# ",
+ .config_write = nhrp_config_write,
+};
+
+#define NHRP_DEBUG_FLAGS_CMD "<all|common|event|interface|kernel|route|vici>"
+
+#define NHRP_DEBUG_FLAGS_STR \
+ "All messages\n" \
+ "Common messages (default)\n" \
+ "Event manager messages\n" \
+ "Interface messages\n" \
+ "Kernel messages\n" \
+ "Route messages\n" \
+ "VICI messages\n"
+
+static const struct message debug_flags_desc[] = {
+ {NHRP_DEBUG_ALL, "all"}, {NHRP_DEBUG_COMMON, "common"},
+ {NHRP_DEBUG_IF, "interface"}, {NHRP_DEBUG_KERNEL, "kernel"},
+ {NHRP_DEBUG_ROUTE, "route"}, {NHRP_DEBUG_VICI, "vici"},
+ {NHRP_DEBUG_EVENT, "event"}, {0}};
+
+static const struct message interface_flags_desc[] = {
+ {NHRP_IFF_SHORTCUT, "shortcut"},
+ {NHRP_IFF_REDIRECT, "redirect"},
+ {NHRP_IFF_REG_NO_UNIQUE, "registration no-unique"},
+ {0}};
+
+static int nhrp_vty_return(struct vty *vty, int ret)
+{
+ static const char *const errmsgs[] = {
+ [NHRP_ERR_FAIL] = "Command failed",
+ [NHRP_ERR_NO_MEMORY] = "Out of memory",
+ [NHRP_ERR_UNSUPPORTED_INTERFACE] =
+ "NHRP not supported on this interface",
+ [NHRP_ERR_NHRP_NOT_ENABLED] =
+ "NHRP not enabled (set 'nhrp network-id' first)",
+ [NHRP_ERR_ENTRY_EXISTS] = "Entry exists already",
+ [NHRP_ERR_ENTRY_NOT_FOUND] = "Entry not found",
+ [NHRP_ERR_PROTOCOL_ADDRESS_MISMATCH] =
+ "Protocol address family does not match command (ip/ipv6 mismatch)",
+ };
+ const char *str = NULL;
+ char buf[256];
+
+ if (ret == NHRP_OK)
+ return CMD_SUCCESS;
+
+ if (ret > 0 && ret <= NHRP_ERR_MAX)
+ if (errmsgs[ret])
+ str = errmsgs[ret];
+
+ if (!str) {
+ str = buf;
+ snprintf(buf, sizeof(buf), "Unknown error %d", ret);
+ }
+
+ vty_out(vty, "%% %s\n", str);
+
+ return CMD_WARNING_CONFIG_FAILED;
+ ;
+}
+
+static int toggle_flag(struct vty *vty, const struct message *flag_desc,
+ const char *name, int on_off, unsigned *flags)
+{
+ int i;
+
+ for (i = 0; flag_desc[i].str != NULL; i++) {
+ if (strcmp(flag_desc[i].str, name) != 0)
+ continue;
+ if (on_off)
+ *flags |= flag_desc[i].key;
+ else
+ *flags &= ~flag_desc[i].key;
+ return CMD_SUCCESS;
+ }
+
+ vty_out(vty, "%% Invalid value %s\n", name);
+ return CMD_WARNING_CONFIG_FAILED;
+ ;
+}
+
+#ifndef NO_DEBUG
+
+DEFUN_NOSH(show_debugging_nhrp, show_debugging_nhrp_cmd,
+ "show debugging [nhrp]",
+ SHOW_STR
+ "Debugging information\n"
+ "NHRP configuration\n")
+{
+ int i;
+
+ vty_out(vty, "NHRP debugging status:\n");
+
+ for (i = 0; debug_flags_desc[i].str != NULL; i++) {
+ if (debug_flags_desc[i].key == NHRP_DEBUG_ALL)
+ continue;
+ if (!(debug_flags_desc[i].key & debug_flags))
+ continue;
+
+ vty_out(vty, " NHRP %s debugging is on\n",
+ debug_flags_desc[i].str);
+ }
+
+ cmd_show_lib_debugs(vty);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(debug_nhrp, debug_nhrp_cmd,
+ "debug nhrp " NHRP_DEBUG_FLAGS_CMD,
+ "Enable debug messages for specific or all parts.\n"
+ "NHRP information\n"
+ NHRP_DEBUG_FLAGS_STR)
+{
+ return toggle_flag(vty, debug_flags_desc, argv[2]->text, 1,
+ &debug_flags);
+}
+
+DEFUN(no_debug_nhrp, no_debug_nhrp_cmd,
+ "no debug nhrp " NHRP_DEBUG_FLAGS_CMD,
+ NO_STR
+ "Disable debug messages for specific or all parts.\n"
+ "NHRP information\n"
+ NHRP_DEBUG_FLAGS_STR)
+{
+ return toggle_flag(vty, debug_flags_desc, argv[3]->text, 0,
+ &debug_flags);
+}
+
+#endif /* NO_DEBUG */
+
+static int nhrp_config_write(struct vty *vty)
+{
+#ifndef NO_DEBUG
+ if (debug_flags == NHRP_DEBUG_ALL) {
+ vty_out(vty, "debug nhrp all\n");
+ } else {
+ int i;
+
+ for (i = 0; debug_flags_desc[i].str != NULL; i++) {
+ if (debug_flags_desc[i].key == NHRP_DEBUG_ALL)
+ continue;
+ if (!(debug_flags & debug_flags_desc[i].key))
+ continue;
+ vty_out(vty, "debug nhrp %s\n",
+ debug_flags_desc[i].str);
+ }
+ }
+ vty_out(vty, "!\n");
+#endif /* NO_DEBUG */
+
+ if (nhrp_event_socket_path) {
+ vty_out(vty, "nhrp event socket %s\n", nhrp_event_socket_path);
+ }
+ if (netlink_nflog_group) {
+ vty_out(vty, "nhrp nflog-group %d\n", netlink_nflog_group);
+ }
+ if (netlink_mcast_nflog_group)
+ vty_out(vty, "nhrp multicast-nflog-group %d\n",
+ netlink_mcast_nflog_group);
+
+ return 0;
+}
+
+#define IP_STR "IP information\n"
+#define IPV6_STR "IPv6 information\n"
+#define AFI_CMD "<ip|ipv6>"
+#define AFI_STR IP_STR IPV6_STR
+#define NHRP_STR "Next Hop Resolution Protocol functions\n"
+
+static afi_t cmd_to_afi(const struct cmd_token *tok)
+{
+ return strcmp(tok->text, "ipv6") == 0 ? AFI_IP6 : AFI_IP;
+}
+
+static const char *afi_to_cmd(afi_t afi)
+{
+ if (afi == AFI_IP6)
+ return "ipv6";
+ return "ip";
+}
+
+DEFUN(nhrp_event_socket, nhrp_event_socket_cmd,
+ "nhrp event socket SOCKET",
+ NHRP_STR
+ "Event Manager commands\n"
+ "Event Manager unix socket path\n"
+ "Unix path for the socket\n")
+{
+ evmgr_set_socket(argv[3]->arg);
+ return CMD_SUCCESS;
+}
+
+DEFUN(no_nhrp_event_socket, no_nhrp_event_socket_cmd,
+ "no nhrp event socket [SOCKET]",
+ NO_STR
+ NHRP_STR
+ "Event Manager commands\n"
+ "Event Manager unix socket path\n"
+ "Unix path for the socket\n")
+{
+ evmgr_set_socket(NULL);
+ return CMD_SUCCESS;
+}
+
+DEFUN(nhrp_nflog_group, nhrp_nflog_group_cmd,
+ "nhrp nflog-group (1-65535)",
+ NHRP_STR
+ "Specify NFLOG group number\n"
+ "NFLOG group number\n")
+{
+ uint32_t nfgroup;
+
+ nfgroup = strtoul(argv[2]->arg, NULL, 10);
+ netlink_set_nflog_group(nfgroup);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(no_nhrp_nflog_group, no_nhrp_nflog_group_cmd,
+ "no nhrp nflog-group [(1-65535)]",
+ NO_STR
+ NHRP_STR
+ "Specify NFLOG group number\n"
+ "NFLOG group number\n")
+{
+ netlink_set_nflog_group(0);
+ return CMD_SUCCESS;
+}
+
+DEFUN(nhrp_multicast_nflog_group, nhrp_multicast_nflog_group_cmd,
+ "nhrp multicast-nflog-group (1-65535)",
+ NHRP_STR
+ "Specify NFLOG group number for Multicast Packets\n"
+ "NFLOG group number\n")
+{
+ uint32_t nfgroup;
+
+ nfgroup = strtoul(argv[2]->arg, NULL, 10);
+ netlink_mcast_set_nflog_group(nfgroup);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(no_nhrp_multicast_nflog_group, no_nhrp_multicast_nflog_group_cmd,
+ "no nhrp multicast-nflog-group [(1-65535)]",
+ NO_STR
+ NHRP_STR
+ "Specify NFLOG group number\n"
+ "NFLOG group number\n")
+{
+ netlink_mcast_set_nflog_group(0);
+ return CMD_SUCCESS;
+}
+
+DEFUN(tunnel_protection, tunnel_protection_cmd,
+ "tunnel protection vici profile PROFILE [fallback-profile FALLBACK]",
+ "NHRP/GRE integration\n"
+ "IPsec protection\n"
+ "VICI (StrongSwan)\n"
+ "IPsec profile\n"
+ "IPsec profile name\n"
+ "Fallback IPsec profile\n"
+ "Fallback IPsec profile name\n")
+{
+ VTY_DECLVAR_CONTEXT(interface, ifp);
+
+ nhrp_interface_set_protection(ifp, argv[4]->arg,
+ argc > 6 ? argv[6]->arg : NULL);
+ return CMD_SUCCESS;
+}
+
+DEFUN(no_tunnel_protection, no_tunnel_protection_cmd,
+ "no tunnel protection",
+ NO_STR
+ "NHRP/GRE integration\n"
+ "IPsec protection\n")
+{
+ VTY_DECLVAR_CONTEXT(interface, ifp);
+
+ nhrp_interface_set_protection(ifp, NULL, NULL);
+ return CMD_SUCCESS;
+}
+
+DEFUN(tunnel_source, tunnel_source_cmd,
+ "tunnel source INTERFACE",
+ "NHRP/GRE integration\n"
+ "Tunnel device binding tracking\n"
+ "Interface name\n")
+{
+ VTY_DECLVAR_CONTEXT(interface, ifp);
+ nhrp_interface_set_source(ifp, argv[2]->arg);
+ return CMD_SUCCESS;
+}
+
+DEFUN(no_tunnel_source, no_tunnel_source_cmd,
+ "no tunnel source",
+ "NHRP/GRE integration\n"
+ "Tunnel device binding tracking\n"
+ "Interface name\n")
+{
+ VTY_DECLVAR_CONTEXT(interface, ifp);
+ nhrp_interface_set_source(ifp, NULL);
+ return CMD_SUCCESS;
+}
+
+DEFUN(if_nhrp_network_id, if_nhrp_network_id_cmd,
+ AFI_CMD " nhrp network-id (1-4294967295)",
+ AFI_STR
+ NHRP_STR
+ "Enable NHRP and specify network-id\n"
+ "System local ID to specify interface group\n")
+{
+ VTY_DECLVAR_CONTEXT(interface, ifp);
+ struct nhrp_interface *nifp = ifp->info;
+ afi_t afi = cmd_to_afi(argv[0]);
+
+ nifp->afi[afi].network_id = strtoul(argv[3]->arg, NULL, 10);
+ nhrp_interface_update(ifp);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(if_no_nhrp_network_id, if_no_nhrp_network_id_cmd,
+ "no " AFI_CMD " nhrp network-id [(1-4294967295)]",
+ NO_STR
+ AFI_STR
+ NHRP_STR
+ "Enable NHRP and specify network-id\n"
+ "System local ID to specify interface group\n")
+{
+ VTY_DECLVAR_CONTEXT(interface, ifp);
+ struct nhrp_interface *nifp = ifp->info;
+ afi_t afi = cmd_to_afi(argv[1]);
+
+ nifp->afi[afi].network_id = 0;
+ nhrp_interface_update(ifp);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(if_nhrp_flags, if_nhrp_flags_cmd,
+ AFI_CMD " nhrp <shortcut|redirect>",
+ AFI_STR
+ NHRP_STR
+ "Allow shortcut establishment\n"
+ "Send redirect notifications\n")
+{
+ VTY_DECLVAR_CONTEXT(interface, ifp);
+ struct nhrp_interface *nifp = ifp->info;
+ afi_t afi = cmd_to_afi(argv[0]);
+
+ return toggle_flag(vty, interface_flags_desc, argv[2]->text, 1,
+ &nifp->afi[afi].flags);
+}
+
+DEFUN(if_no_nhrp_flags, if_no_nhrp_flags_cmd,
+ "no " AFI_CMD " nhrp <shortcut|redirect>",
+ NO_STR
+ AFI_STR
+ NHRP_STR
+ "Allow shortcut establishment\n"
+ "Send redirect notifications\n")
+{
+ VTY_DECLVAR_CONTEXT(interface, ifp);
+ struct nhrp_interface *nifp = ifp->info;
+ afi_t afi = cmd_to_afi(argv[1]);
+
+ return toggle_flag(vty, interface_flags_desc, argv[3]->text, 0,
+ &nifp->afi[afi].flags);
+}
+
+DEFUN(if_nhrp_reg_flags, if_nhrp_reg_flags_cmd,
+ AFI_CMD " nhrp registration no-unique",
+ AFI_STR
+ NHRP_STR
+ "Registration configuration\n"
+ "Don't set unique flag\n")
+{
+ VTY_DECLVAR_CONTEXT(interface, ifp);
+ struct nhrp_interface *nifp = ifp->info;
+ afi_t afi = cmd_to_afi(argv[0]);
+ char name[256];
+ snprintf(name, sizeof(name), "registration %s", argv[3]->text);
+ return toggle_flag(vty, interface_flags_desc, name, 1,
+ &nifp->afi[afi].flags);
+}
+
+DEFUN(if_no_nhrp_reg_flags, if_no_nhrp_reg_flags_cmd,
+ "no " AFI_CMD " nhrp registration no-unique",
+ NO_STR
+ AFI_STR
+ NHRP_STR
+ "Registration configuration\n"
+ "Don't set unique flag\n")
+{
+ VTY_DECLVAR_CONTEXT(interface, ifp);
+ struct nhrp_interface *nifp = ifp->info;
+ afi_t afi = cmd_to_afi(argv[1]);
+ char name[256];
+ snprintf(name, sizeof(name), "registration %s", argv[4]->text);
+ return toggle_flag(vty, interface_flags_desc, name, 0,
+ &nifp->afi[afi].flags);
+}
+
+DEFUN(if_nhrp_holdtime, if_nhrp_holdtime_cmd,
+ AFI_CMD " nhrp holdtime (1-65000)",
+ AFI_STR
+ NHRP_STR
+ "Specify NBMA address validity time\n"
+ "Time in seconds that NBMA addresses are advertised valid\n")
+{
+ VTY_DECLVAR_CONTEXT(interface, ifp);
+ struct nhrp_interface *nifp = ifp->info;
+ afi_t afi = cmd_to_afi(argv[0]);
+
+ nifp->afi[afi].holdtime = strtoul(argv[3]->arg, NULL, 10);
+ nhrp_interface_update(ifp);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(if_no_nhrp_holdtime, if_no_nhrp_holdtime_cmd,
+ "no " AFI_CMD " nhrp holdtime [(1-65000)]",
+ NO_STR
+ AFI_STR
+ NHRP_STR
+ "Specify NBMA address validity time\n"
+ "Time in seconds that NBMA addresses are advertised valid\n")
+{
+ VTY_DECLVAR_CONTEXT(interface, ifp);
+ struct nhrp_interface *nifp = ifp->info;
+ afi_t afi = cmd_to_afi(argv[1]);
+
+ nifp->afi[afi].holdtime = NHRPD_DEFAULT_HOLDTIME;
+ nhrp_interface_update(ifp);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(if_nhrp_mtu, if_nhrp_mtu_cmd,
+ "ip nhrp mtu <(576-1500)|opennhrp>",
+ IP_STR
+ NHRP_STR
+ "Configure NHRP advertised MTU\n"
+ "MTU value\n"
+ "Advertise bound interface MTU similar to OpenNHRP\n")
+{
+ VTY_DECLVAR_CONTEXT(interface, ifp);
+ struct nhrp_interface *nifp = ifp->info;
+
+ if (argv[3]->arg[0] == 'o') {
+ nifp->afi[AFI_IP].configured_mtu = -1;
+ } else {
+ nifp->afi[AFI_IP].configured_mtu =
+ strtoul(argv[3]->arg, NULL, 10);
+ }
+ nhrp_interface_update_mtu(ifp, AFI_IP);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(if_no_nhrp_mtu, if_no_nhrp_mtu_cmd,
+ "no ip nhrp mtu [(576-1500)|opennhrp]",
+ NO_STR
+ IP_STR
+ NHRP_STR
+ "Configure NHRP advertised MTU\n"
+ "MTU value\n"
+ "Advertise bound interface MTU similar to OpenNHRP\n")
+{
+ VTY_DECLVAR_CONTEXT(interface, ifp);
+ struct nhrp_interface *nifp = ifp->info;
+
+ nifp->afi[AFI_IP].configured_mtu = 0;
+ nhrp_interface_update_mtu(ifp, AFI_IP);
+ return CMD_SUCCESS;
+}
+
+DEFUN(if_nhrp_map, if_nhrp_map_cmd,
+ AFI_CMD " nhrp map <A.B.C.D|X:X::X:X> <A.B.C.D|local>",
+ AFI_STR
+ NHRP_STR
+ "Nexthop Server configuration\n"
+ "IPv4 protocol address\n"
+ "IPv6 protocol address\n"
+ "IPv4 NBMA address\n"
+ "Handle protocol address locally\n")
+{
+ VTY_DECLVAR_CONTEXT(interface, ifp);
+ afi_t afi = cmd_to_afi(argv[0]);
+ union sockunion proto_addr, nbma_addr;
+ struct nhrp_cache_config *cc;
+ struct nhrp_cache *c;
+ enum nhrp_cache_type type;
+
+ if (str2sockunion(argv[3]->arg, &proto_addr) < 0
+ || afi2family(afi) != sockunion_family(&proto_addr))
+ return nhrp_vty_return(vty, NHRP_ERR_PROTOCOL_ADDRESS_MISMATCH);
+
+ if (strmatch(argv[4]->text, "local"))
+ type = NHRP_CACHE_LOCAL;
+ else {
+ if (str2sockunion(argv[4]->arg, &nbma_addr) < 0)
+ return nhrp_vty_return(vty, NHRP_ERR_FAIL);
+ type = NHRP_CACHE_STATIC;
+ }
+ cc = nhrp_cache_config_get(ifp, &proto_addr, 1);
+ if (!cc)
+ return nhrp_vty_return(vty, NHRP_ERR_FAIL);
+ cc->nbma = nbma_addr;
+ cc->type = type;
+ /* gre layer not ready */
+ if (ifp->ifindex == IFINDEX_INTERNAL)
+ return CMD_SUCCESS;
+
+ c = nhrp_cache_get(ifp, &proto_addr, 1);
+ if (!c)
+ return nhrp_vty_return(vty, NHRP_ERR_FAIL);
+
+ c->map = 1;
+ if (type == NHRP_CACHE_LOCAL)
+ nhrp_cache_update_binding(c, NHRP_CACHE_LOCAL, 0, NULL, 0,
+ NULL, NULL);
+ else
+ nhrp_cache_update_binding(c, NHRP_CACHE_STATIC, 0,
+ nhrp_peer_get(ifp, &nbma_addr), 0,
+ NULL, NULL);
+ return CMD_SUCCESS;
+}
+
+DEFUN(if_no_nhrp_map, if_no_nhrp_map_cmd,
+ "no " AFI_CMD " nhrp map <A.B.C.D|X:X::X:X> [<A.B.C.D|local>]",
+ NO_STR
+ AFI_STR
+ NHRP_STR
+ "Nexthop Server configuration\n"
+ "IPv4 protocol address\n"
+ "IPv6 protocol address\n"
+ "IPv4 NBMA address\n"
+ "Handle protocol address locally\n")
+{
+ VTY_DECLVAR_CONTEXT(interface, ifp);
+ afi_t afi = cmd_to_afi(argv[1]);
+ union sockunion proto_addr, nbma_addr;
+ struct nhrp_cache_config *cc;
+ struct nhrp_cache *c;
+
+ if (str2sockunion(argv[4]->arg, &proto_addr) < 0
+ || afi2family(afi) != sockunion_family(&proto_addr))
+ return nhrp_vty_return(vty, NHRP_ERR_PROTOCOL_ADDRESS_MISMATCH);
+
+ cc = nhrp_cache_config_get(ifp, &proto_addr, 0);
+ if (!cc)
+ return nhrp_vty_return(vty, NHRP_ERR_FAIL);
+ nhrp_cache_config_free(cc);
+
+ c = nhrp_cache_get(ifp, &proto_addr, 0);
+ /* silently return */
+ if (!c || !c->map)
+ return CMD_SUCCESS;
+
+ nhrp_cache_update_binding(c, c->cur.type, -1,
+ nhrp_peer_get(ifp, &nbma_addr), 0, NULL,
+ NULL);
+ return CMD_SUCCESS;
+}
+
+DEFUN(if_nhrp_map_multicast, if_nhrp_map_multicast_cmd,
+ AFI_CMD " nhrp map multicast <A.B.C.D|X:X::X:X|dynamic>",
+ AFI_STR
+ NHRP_STR
+ "Multicast NBMA Configuration\n"
+ "Use this NBMA mapping for multicasts\n"
+ "IPv4 NBMA address\n"
+ "IPv6 NBMA address\n"
+ "Dynamically learn destinations from client registrations on hub\n")
+{
+ VTY_DECLVAR_CONTEXT(interface, ifp);
+ afi_t afi = cmd_to_afi(argv[0]);
+ union sockunion nbma_addr;
+ int ret;
+
+ if (str2sockunion(argv[4]->arg, &nbma_addr) < 0)
+ sockunion_family(&nbma_addr) = AF_UNSPEC;
+
+ ret = nhrp_multicast_add(ifp, afi, &nbma_addr);
+
+ return nhrp_vty_return(vty, ret);
+}
+
+DEFUN(if_no_nhrp_map_multicast, if_no_nhrp_map_multicast_cmd,
+ "no " AFI_CMD " nhrp map multicast <A.B.C.D|X:X::X:X|dynamic>",
+ NO_STR
+ AFI_STR
+ NHRP_STR
+ "Multicast NBMA Configuration\n"
+ "Use this NBMA mapping for multicasts\n"
+ "IPv4 NBMA address\n"
+ "IPv6 NBMA address\n"
+ "Dynamically learn destinations from client registrations on hub\n")
+{
+ VTY_DECLVAR_CONTEXT(interface, ifp);
+ afi_t afi = cmd_to_afi(argv[1]);
+ union sockunion nbma_addr;
+ int ret;
+
+ if (str2sockunion(argv[5]->arg, &nbma_addr) < 0)
+ sockunion_family(&nbma_addr) = AF_UNSPEC;
+
+ ret = nhrp_multicast_del(ifp, afi, &nbma_addr);
+
+ return nhrp_vty_return(vty, ret);
+}
+
+DEFUN(if_nhrp_nhs, if_nhrp_nhs_cmd,
+ AFI_CMD " nhrp nhs <A.B.C.D|X:X::X:X|dynamic> nbma <A.B.C.D|FQDN>",
+ AFI_STR
+ NHRP_STR
+ "Nexthop Server configuration\n"
+ "IPv4 protocol address\n"
+ "IPv6 protocol address\n"
+ "Automatic detection of protocol address\n"
+ "NBMA address\n"
+ "IPv4 NBMA address\n"
+ "Fully qualified domain name for NBMA address(es)\n")
+{
+ VTY_DECLVAR_CONTEXT(interface, ifp);
+ afi_t afi = cmd_to_afi(argv[0]);
+ union sockunion proto_addr;
+ int ret;
+
+ if (str2sockunion(argv[3]->arg, &proto_addr) < 0)
+ sockunion_family(&proto_addr) = AF_UNSPEC;
+
+ ret = nhrp_nhs_add(ifp, afi, &proto_addr, argv[5]->arg);
+ return nhrp_vty_return(vty, ret);
+}
+
+DEFUN(if_no_nhrp_nhs, if_no_nhrp_nhs_cmd,
+ "no " AFI_CMD " nhrp nhs <A.B.C.D|X:X::X:X|dynamic> nbma <A.B.C.D|FQDN>",
+ NO_STR
+ AFI_STR
+ NHRP_STR
+ "Nexthop Server configuration\n"
+ "IPv4 protocol address\n"
+ "IPv6 protocol address\n"
+ "Automatic detection of protocol address\n"
+ "NBMA address\n"
+ "IPv4 NBMA address\n"
+ "Fully qualified domain name for NBMA address(es)\n")
+{
+ VTY_DECLVAR_CONTEXT(interface, ifp);
+ afi_t afi = cmd_to_afi(argv[1]);
+ union sockunion proto_addr;
+ int ret;
+
+ if (str2sockunion(argv[4]->arg, &proto_addr) < 0)
+ sockunion_family(&proto_addr) = AF_UNSPEC;
+
+ ret = nhrp_nhs_del(ifp, afi, &proto_addr, argv[6]->arg);
+ return nhrp_vty_return(vty, ret);
+}
+
+struct info_ctx {
+ struct vty *vty;
+ afi_t afi;
+ int count;
+ struct json_object *json;
+};
+
+static void show_ip_nhrp_cache(struct nhrp_cache *c, void *pctx)
+{
+ struct info_ctx *ctx = pctx;
+ struct vty *vty = ctx->vty;
+ char buf[3][SU_ADDRSTRLEN];
+ struct json_object *json = NULL;
+
+ if (ctx->afi != family2afi(sockunion_family(&c->remote_addr)))
+ return;
+
+
+ if (!ctx->count && !ctx->json) {
+ vty_out(vty, "%-8s %-8s %-24s %-24s %-24s %-6s %s\n", "Iface",
+ "Type", "Protocol", "NBMA", "Claimed NBMA", "Flags",
+ "Identity");
+ }
+ ctx->count++;
+
+ sockunion2str(&c->remote_addr, buf[0], sizeof(buf[0]));
+ if (c->cur.type == NHRP_CACHE_LOCAL) {
+ struct nhrp_interface *nifp = c->ifp->info;
+
+ if (sockunion_family(&nifp->nbma) != AF_UNSPEC) {
+ sockunion2str(&nifp->nbma, buf[1], sizeof(buf[1]));
+ sockunion2str(&nifp->nbma, buf[2], sizeof(buf[2]));
+ } else {
+ snprintf(buf[1], sizeof(buf[1]), "-");
+ snprintf(buf[2], sizeof(buf[2]), "-");
+ }
+
+ /* if we are behind NAT then update NBMA field */
+ if (sockunion_family(&nifp->nat_nbma) != AF_UNSPEC)
+ sockunion2str(&nifp->nat_nbma, buf[1], sizeof(buf[1]));
+ } else {
+ if (c->cur.peer)
+ sockunion2str(&c->cur.peer->vc->remote.nbma,
+ buf[1], sizeof(buf[1]));
+ else
+ snprintf(buf[1], sizeof(buf[1]), "-");
+
+ if (c->cur.peer
+ && sockunion_family(&c->cur.remote_nbma_claimed)
+ != AF_UNSPEC)
+ sockunion2str(&c->cur.remote_nbma_claimed,
+ buf[2], sizeof(buf[2]));
+ else
+ snprintf(buf[2], sizeof(buf[2]), "-");
+ }
+
+ if (ctx->json) {
+ json = json_object_new_object();
+ json_object_string_add(json, "interface", c->ifp->name);
+ json_object_string_add(json, "type",
+ nhrp_cache_type_str[c->cur.type]);
+ json_object_string_add(json, "protocol", buf[0]);
+ json_object_string_add(json, "nbma", buf[1]);
+ json_object_string_add(json, "claimed_nbma", buf[2]);
+
+ if (c->used)
+ json_object_boolean_true_add(json, "used");
+ else
+ json_object_boolean_false_add(json, "used");
+
+ if (c->t_timeout)
+ json_object_boolean_true_add(json, "timeout");
+ else
+ json_object_boolean_false_add(json, "timeout");
+
+ if (c->t_auth)
+ json_object_boolean_true_add(json, "auth");
+ else
+ json_object_boolean_false_add(json, "auth");
+
+ if (c->cur.peer)
+ json_object_string_add(json, "identity",
+ c->cur.peer->vc->remote.id);
+ else
+ json_object_string_add(json, "identity", "-");
+
+ json_object_array_add(ctx->json, json);
+ return;
+ }
+ vty_out(ctx->vty, "%-8s %-8s %-24s %-24s %-24s %c%c%c %s\n",
+ c->ifp->name,
+ nhrp_cache_type_str[c->cur.type],
+ buf[0], buf[1], buf[2],
+ c->used ? 'U' : ' ', c->t_timeout ? 'T' : ' ',
+ c->t_auth ? 'A' : ' ',
+ c->cur.peer ? c->cur.peer->vc->remote.id : "-");
+}
+
+static void show_ip_nhrp_nhs(struct nhrp_nhs *n, struct nhrp_registration *reg,
+ void *pctx)
+{
+ struct info_ctx *ctx = pctx;
+ struct vty *vty = ctx->vty;
+ char buf[2][SU_ADDRSTRLEN];
+ struct json_object *json = NULL;
+
+ if (!ctx->count && !ctx->json) {
+ vty_out(vty, "%-8s %-24s %-16s %-16s\n", "Iface", "FQDN",
+ "NBMA", "Protocol");
+ }
+ ctx->count++;
+
+ if (reg && reg->peer)
+ sockunion2str(&reg->peer->vc->remote.nbma, buf[0],
+ sizeof(buf[0]));
+ else
+ snprintf(buf[0], sizeof(buf[0]), "-");
+ sockunion2str(reg ? &reg->proto_addr : &n->proto_addr, buf[1],
+ sizeof(buf[1]));
+
+ if (ctx->json) {
+ json = json_object_new_object();
+ json_object_string_add(json, "interface", n->ifp->name);
+ json_object_string_add(json, "fqdn", n->nbma_fqdn);
+ json_object_string_add(json, "nbma", buf[0]);
+ json_object_string_add(json, "protocol", buf[1]);
+
+ json_object_array_add(ctx->json, json);
+ return;
+ }
+
+ vty_out(vty, "%-8s %-24s %-16s %-16s\n", n->ifp->name, n->nbma_fqdn,
+ buf[0], buf[1]);
+}
+
+static void show_ip_nhrp_shortcut(struct nhrp_shortcut *s, void *pctx)
+{
+ struct info_ctx *ctx = pctx;
+ struct nhrp_cache *c;
+ struct vty *vty = ctx->vty;
+ char buf1[PREFIX_STRLEN], buf2[SU_ADDRSTRLEN];
+ struct json_object *json = NULL;
+
+ if (!ctx->count) {
+ vty_out(vty, "%-8s %-24s %-24s %s\n", "Type", "Prefix", "Via",
+ "Identity");
+ }
+ ctx->count++;
+
+ c = s->cache;
+ buf2[0] = '\0';
+ if (c)
+ sockunion2str(&c->remote_addr, buf2, sizeof(buf2));
+ prefix2str(s->p, buf1, sizeof(buf1));
+
+ if (ctx->json) {
+ json = json_object_new_object();
+ json_object_string_add(json, "type",
+ nhrp_cache_type_str[s->type]);
+ json_object_string_add(json, "prefix", buf1);
+
+ if (c)
+ json_object_string_add(json, "via", buf2);
+
+ if (c && c->cur.peer)
+ json_object_string_add(json, "identity",
+ c->cur.peer->vc->remote.id);
+ else
+ json_object_string_add(json, "identity", "");
+
+ json_object_array_add(ctx->json, json);
+ return;
+ }
+
+ vty_out(ctx->vty, "%-8s %-24s %-24s %s\n",
+ nhrp_cache_type_str[s->type],
+ buf1, buf2,
+ (c && c->cur.peer) ? c->cur.peer->vc->remote.id : "");
+}
+
+static void show_ip_opennhrp_cache(struct nhrp_cache *c, void *pctx)
+{
+ struct info_ctx *ctx = pctx;
+ char buf[3][SU_ADDRSTRLEN];
+ struct json_object *json = NULL;
+
+
+ if (ctx->afi != family2afi(sockunion_family(&c->remote_addr)))
+ return;
+
+ sockunion2str(&c->remote_addr, buf[0], sizeof(buf[0]));
+ if (c->cur.peer)
+ sockunion2str(&c->cur.peer->vc->remote.nbma, buf[1],
+ sizeof(buf[1]));
+ if (sockunion_family(&c->cur.remote_nbma_natoa) != AF_UNSPEC)
+ sockunion2str(&c->cur.remote_nbma_natoa, buf[2],
+ sizeof(buf[2]));
+ if (ctx->json) {
+ json = json_object_new_object();
+ json_object_string_add(json, "type",
+ nhrp_cache_type_str[c->cur.type]);
+
+ if (c->cur.peer && c->cur.peer->online)
+ json_object_boolean_true_add(json, "up");
+ else
+ json_object_boolean_false_add(json, "up");
+
+ if (c->used)
+ json_object_boolean_true_add(json, "used");
+ else
+ json_object_boolean_false_add(json, "used");
+
+ json_object_string_add(json, "protocolAddress", buf[0]);
+ json_object_int_add(json, "protocolAddressSize",
+ 8 * family2addrsize(sockunion_family
+ (&c->remote_addr)));
+
+ if (c->cur.peer)
+ json_object_string_add(json, "nbmaAddress", buf[1]);
+
+ if (sockunion_family(&c->cur.remote_nbma_natoa) != AF_UNSPEC)
+ json_object_string_add(json, "nbmaNatOaAddress",
+ buf[2]);
+
+ json_object_array_add(ctx->json, json);
+ return;
+ }
+ vty_out(ctx->vty,
+ "Type: %s\n"
+ "Flags:%s%s\n"
+ "Protocol-Address: %s/%zu\n",
+ nhrp_cache_type_str[c->cur.type],
+ (c->cur.peer && c->cur.peer->online) ? " up" : "",
+ c->used ? " used" : "",
+ buf[0],
+ 8 * family2addrsize(sockunion_family(&c->remote_addr)));
+
+ if (c->cur.peer)
+ vty_out(ctx->vty, "NBMA-Address: %s\n", buf[1]);
+
+ if (sockunion_family(&c->cur.remote_nbma_natoa) != AF_UNSPEC)
+ vty_out(ctx->vty, "NBMA-NAT-OA-Address: %s\n", buf[2]);
+
+ vty_out(ctx->vty, "\n\n");
+}
+
+DEFUN(show_ip_nhrp, show_ip_nhrp_cmd,
+ "show " AFI_CMD " nhrp [cache|nhs|shortcut|opennhrp] [json]",
+ SHOW_STR
+ AFI_STR
+ "NHRP information\n"
+ "Forwarding cache information\n"
+ "Next hop server information\n"
+ "Shortcut information\n"
+ "opennhrpctl style cache dump\n"
+ JSON_STR)
+{
+ struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
+ struct interface *ifp;
+ struct info_ctx ctx = {
+ .vty = vty, .afi = cmd_to_afi(argv[1]), .json = NULL
+ };
+ bool uj = use_json(argc, argv);
+ struct json_object *json_path = NULL;
+ struct json_object *json_vrf = NULL, *json_vrf_path = NULL;
+ int ret = CMD_SUCCESS;
+
+ if (uj) {
+ json_vrf = json_object_new_object();
+ json_vrf_path = json_object_new_object();
+ json_path = json_object_new_array();
+ ctx.json = json_path;
+ }
+ if (argc <= 3 || argv[3]->text[0] == 'c') {
+ FOR_ALL_INTERFACES (vrf, ifp)
+ nhrp_cache_foreach(ifp, show_ip_nhrp_cache, &ctx);
+ } else if (argv[3]->text[0] == 'n') {
+ FOR_ALL_INTERFACES (vrf, ifp)
+ nhrp_nhs_foreach(ifp, ctx.afi, show_ip_nhrp_nhs, &ctx);
+ } else if (argv[3]->text[0] == 's') {
+ nhrp_shortcut_foreach(ctx.afi, show_ip_nhrp_shortcut, &ctx);
+ } else {
+ if (!ctx.json)
+ vty_out(vty, "Status: ok\n\n");
+ else
+ json_object_string_add(json_vrf, "status", "ok");
+
+ ctx.count++;
+ FOR_ALL_INTERFACES (vrf, ifp)
+ nhrp_cache_foreach(ifp, show_ip_opennhrp_cache, &ctx);
+ }
+
+ if (uj)
+ json_object_int_add(json_vrf, "entriesCount", ctx.count);
+ if (!ctx.count) {
+ if (!ctx.json)
+ vty_out(vty, "%% No entries\n");
+ ret = CMD_WARNING;
+ }
+ if (uj) {
+ json_object_object_add(json_vrf_path, "attr", json_vrf);
+ json_object_object_add(json_vrf_path, "table", ctx.json);
+ vty_json(vty, json_vrf_path);
+ }
+ return ret;
+}
+
+struct dmvpn_cfg {
+ struct vty *vty;
+ struct json_object *json;
+};
+
+static void show_dmvpn_entry(struct nhrp_vc *vc, void *ctx)
+{
+ struct dmvpn_cfg *ctxt = ctx;
+ struct vty *vty;
+ struct json_object *json = NULL;
+
+ if (!ctxt || !ctxt->vty)
+ return;
+ vty = ctxt->vty;
+ if (ctxt->json) {
+ json = json_object_new_object();
+ json_object_string_addf(json, "src", "%pSU", &vc->local.nbma);
+ json_object_string_addf(json, "dst", "%pSU", &vc->remote.nbma);
+
+ if (notifier_active(&vc->notifier_list))
+ json_object_boolean_true_add(json, "notifierActive");
+ else
+ json_object_boolean_false_add(json, "notifierActive");
+
+ json_object_int_add(json, "sas", vc->ipsec);
+ json_object_string_add(json, "identity", vc->remote.id);
+ json_object_array_add(ctxt->json, json);
+ } else {
+ vty_out(vty, "%-24pSU %-24pSU %c %-4d %-24s\n",
+ &vc->local.nbma, &vc->remote.nbma,
+ notifier_active(&vc->notifier_list) ? 'n' : ' ',
+ vc->ipsec, vc->remote.id);
+ }
+}
+
+DEFUN(show_dmvpn, show_dmvpn_cmd,
+ "show dmvpn [json]",
+ SHOW_STR
+ "DMVPN information\n"
+ JSON_STR)
+{
+ bool uj = use_json(argc, argv);
+ struct dmvpn_cfg ctxt;
+ struct json_object *json_path = NULL;
+
+ ctxt.vty = vty;
+ if (!uj) {
+ ctxt.json = NULL;
+ vty_out(vty, "%-24s %-24s %-6s %-4s %-24s\n",
+ "Src", "Dst", "Flags", "SAs", "Identity");
+ } else {
+ json_path = json_object_new_array();
+ ctxt.json = json_path;
+ }
+ nhrp_vc_foreach(show_dmvpn_entry, &ctxt);
+ if (uj)
+ vty_json(vty, json_path);
+ return CMD_SUCCESS;
+}
+
+static void clear_nhrp_cache(struct nhrp_cache *c, void *data)
+{
+ struct info_ctx *ctx = data;
+ if (c->cur.type <= NHRP_CACHE_DYNAMIC) {
+ nhrp_cache_update_binding(c, c->cur.type, -1, NULL, 0, NULL,
+ NULL);
+ if (ctx)
+ ctx->count++;
+ }
+}
+
+static void clear_nhrp_shortcut(struct nhrp_shortcut *s, void *data)
+{
+ struct info_ctx *ctx = data;
+ nhrp_shortcut_purge(s, 1);
+ ctx->count++;
+}
+
+DEFUN(clear_nhrp, clear_nhrp_cmd,
+ "clear " AFI_CMD " nhrp <cache|shortcut>",
+ CLEAR_STR
+ AFI_STR
+ NHRP_STR
+ "Dynamic cache entries\n"
+ "Shortcut entries\n")
+{
+ struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
+ struct interface *ifp;
+ struct info_ctx ctx = {
+ .vty = vty, .afi = cmd_to_afi(argv[1]), .count = 0,
+ };
+
+ if (argc <= 3 || argv[3]->text[0] == 'c') {
+ FOR_ALL_INTERFACES (vrf, ifp)
+ nhrp_cache_foreach(ifp, clear_nhrp_cache, &ctx);
+ } else {
+ nhrp_shortcut_foreach(ctx.afi, clear_nhrp_shortcut, &ctx);
+ /* Clear cache also because when a shortcut is cleared then its
+ * cache entry should be cleared as well (otherwise traffic
+ * continues via the shortcut path)
+ */
+ FOR_ALL_INTERFACES (vrf, ifp)
+ nhrp_cache_foreach(ifp, clear_nhrp_cache, NULL);
+ }
+
+ if (!ctx.count) {
+ vty_out(vty, "%% No entries\n");
+ return CMD_WARNING;
+ }
+
+ vty_out(vty, "%% %d entries cleared\n", ctx.count);
+ return CMD_SUCCESS;
+}
+
+struct write_map_ctx {
+ struct vty *vty;
+ int family;
+ const char *aficmd;
+};
+
+static void interface_config_write_nhrp_map(struct nhrp_cache_config *c,
+ void *data)
+{
+ struct write_map_ctx *ctx = data;
+ struct vty *vty = ctx->vty;
+
+ if (sockunion_family(&c->remote_addr) != ctx->family)
+ return;
+
+ vty_out(vty, " %s nhrp map %pSU ", ctx->aficmd, &c->remote_addr);
+ if (c->type == NHRP_CACHE_LOCAL)
+ vty_out(vty, "local\n");
+ else
+ vty_out(vty, "%pSU\n", &c->nbma);
+}
+
+static int interface_config_write(struct vty *vty)
+{
+ struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
+ struct write_map_ctx mapctx;
+ struct interface *ifp;
+ struct nhrp_interface *nifp;
+ struct nhrp_nhs *nhs;
+ struct nhrp_multicast *mcast;
+ const char *aficmd;
+ afi_t afi;
+ int i;
+
+ FOR_ALL_INTERFACES (vrf, ifp) {
+ if_vty_config_start(vty, ifp);
+ if (ifp->desc)
+ vty_out(vty, " description %s\n", ifp->desc);
+
+ nifp = ifp->info;
+ if (nifp->ipsec_profile) {
+ vty_out(vty, " tunnel protection vici profile %s",
+ nifp->ipsec_profile);
+ if (nifp->ipsec_fallback_profile)
+ vty_out(vty, " fallback-profile %s",
+ nifp->ipsec_fallback_profile);
+ vty_out(vty, "\n");
+ }
+ if (nifp->source)
+ vty_out(vty, " tunnel source %s\n", nifp->source);
+
+ for (afi = 0; afi < AFI_MAX; afi++) {
+ struct nhrp_afi_data *ad = &nifp->afi[afi];
+
+ aficmd = afi_to_cmd(afi);
+
+ if (ad->network_id)
+ vty_out(vty, " %s nhrp network-id %u\n", aficmd,
+ ad->network_id);
+
+ if (ad->holdtime != NHRPD_DEFAULT_HOLDTIME)
+ vty_out(vty, " %s nhrp holdtime %u\n", aficmd,
+ ad->holdtime);
+
+ if (ad->configured_mtu < 0)
+ vty_out(vty, " %s nhrp mtu opennhrp\n", aficmd);
+ else if (ad->configured_mtu)
+ vty_out(vty, " %s nhrp mtu %u\n", aficmd,
+ ad->configured_mtu);
+
+ for (i = 0; interface_flags_desc[i].str != NULL; i++) {
+ if (!(ad->flags & interface_flags_desc[i].key))
+ continue;
+ vty_out(vty, " %s nhrp %s\n", aficmd,
+ interface_flags_desc[i].str);
+ }
+
+ mapctx = (struct write_map_ctx){
+ .vty = vty,
+ .family = afi2family(afi),
+ .aficmd = aficmd,
+ };
+ nhrp_cache_config_foreach(
+ ifp, interface_config_write_nhrp_map, &mapctx);
+
+ frr_each (nhrp_nhslist, &ad->nhslist_head, nhs) {
+ vty_out(vty, " %s nhrp nhs ", aficmd);
+ if (sockunion_family(&nhs->proto_addr)
+ == AF_UNSPEC)
+ vty_out(vty, "dynamic");
+ else
+ vty_out(vty, "%pSU", &nhs->proto_addr);
+ vty_out(vty, " nbma %s\n", nhs->nbma_fqdn);
+ }
+
+ frr_each (nhrp_mcastlist, &ad->mcastlist_head, mcast) {
+ vty_out(vty, " %s nhrp map multicast ", aficmd);
+ if (sockunion_family(&mcast->nbma_addr)
+ == AF_UNSPEC)
+ vty_out(vty, "dynamic\n");
+ else
+ vty_out(vty, "%pSU\n",
+ &mcast->nbma_addr);
+ }
+ }
+
+ if_vty_config_end(vty);
+ }
+
+ return 0;
+}
+
+void nhrp_config_init(void)
+{
+ install_node(&zebra_node);
+ install_default(ZEBRA_NODE);
+
+ /* access-list commands */
+ access_list_init();
+
+ /* global commands */
+ install_element(VIEW_NODE, &show_ip_nhrp_cmd);
+ install_element(VIEW_NODE, &show_dmvpn_cmd);
+ install_element(ENABLE_NODE, &clear_nhrp_cmd);
+
+ install_element(ENABLE_NODE, &show_debugging_nhrp_cmd);
+
+ install_element(ENABLE_NODE, &debug_nhrp_cmd);
+ install_element(ENABLE_NODE, &no_debug_nhrp_cmd);
+
+ install_element(CONFIG_NODE, &debug_nhrp_cmd);
+ install_element(CONFIG_NODE, &no_debug_nhrp_cmd);
+
+ install_element(CONFIG_NODE, &nhrp_event_socket_cmd);
+ install_element(CONFIG_NODE, &no_nhrp_event_socket_cmd);
+ install_element(CONFIG_NODE, &nhrp_nflog_group_cmd);
+ install_element(CONFIG_NODE, &no_nhrp_nflog_group_cmd);
+ install_element(CONFIG_NODE, &nhrp_multicast_nflog_group_cmd);
+ install_element(CONFIG_NODE, &no_nhrp_multicast_nflog_group_cmd);
+
+ vrf_cmd_init(NULL);
+
+ /* interface specific commands */
+ if_cmd_init(interface_config_write);
+ install_element(INTERFACE_NODE, &tunnel_protection_cmd);
+ install_element(INTERFACE_NODE, &no_tunnel_protection_cmd);
+ install_element(INTERFACE_NODE, &tunnel_source_cmd);
+ install_element(INTERFACE_NODE, &no_tunnel_source_cmd);
+ install_element(INTERFACE_NODE, &if_nhrp_network_id_cmd);
+ install_element(INTERFACE_NODE, &if_no_nhrp_network_id_cmd);
+ install_element(INTERFACE_NODE, &if_nhrp_holdtime_cmd);
+ install_element(INTERFACE_NODE, &if_no_nhrp_holdtime_cmd);
+ install_element(INTERFACE_NODE, &if_nhrp_mtu_cmd);
+ install_element(INTERFACE_NODE, &if_no_nhrp_mtu_cmd);
+ install_element(INTERFACE_NODE, &if_nhrp_flags_cmd);
+ install_element(INTERFACE_NODE, &if_no_nhrp_flags_cmd);
+ install_element(INTERFACE_NODE, &if_nhrp_reg_flags_cmd);
+ install_element(INTERFACE_NODE, &if_no_nhrp_reg_flags_cmd);
+ install_element(INTERFACE_NODE, &if_nhrp_map_cmd);
+ install_element(INTERFACE_NODE, &if_no_nhrp_map_cmd);
+ install_element(INTERFACE_NODE, &if_nhrp_map_multicast_cmd);
+ install_element(INTERFACE_NODE, &if_no_nhrp_map_multicast_cmd);
+ install_element(INTERFACE_NODE, &if_nhrp_nhs_cmd);
+ install_element(INTERFACE_NODE, &if_no_nhrp_nhs_cmd);
+}