summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorQuentin Young <qlyoung@cumulusnetworks.com>2016-10-18 01:36:21 +0200
committerQuentin Young <qlyoung@cumulusnetworks.com>2016-10-18 01:36:21 +0200
commite52702f29d003585dcfbb4914b2a52d77a177739 (patch)
tree3e130ded38c48316796bfb602dc6fe6d119129d2 /lib
parentospf6d: fix a few vty help strings (diff)
parentvtysh: fix build failure in vtysh_writeconfig_integrated() (diff)
downloadfrr-e52702f29d003585dcfbb4914b2a52d77a177739.tar.xz
frr-e52702f29d003585dcfbb4914b2a52d77a177739.zip
Merge branch 'cmaster-next' into vtysh-grammar
Signed-off-by: Quentin Young <qlyoung@cumulusnetworks.com> Conflicts: bgpd/bgp_route.c bgpd/bgp_routemap.c bgpd/bgp_vty.c isisd/isis_redist.c isisd/isis_routemap.c isisd/isis_vty.c isisd/isisd.c lib/command.c lib/distribute.c lib/if.c lib/keychain.c lib/routemap.c lib/routemap.h ospf6d/ospf6_asbr.c ospf6d/ospf6_interface.c ospf6d/ospf6_neighbor.c ospf6d/ospf6_top.c ospf6d/ospf6_zebra.c ospf6d/ospf6d.c ospfd/ospf_routemap.c ospfd/ospf_vty.c ripd/rip_routemap.c ripngd/ripng_routemap.c vtysh/extract.pl.in vtysh/vtysh.c zebra/interface.c zebra/irdp_interface.c zebra/rt_netlink.c zebra/rtadv.c zebra/test_main.c zebra/zebra_routemap.c zebra/zebra_vty.c
Diffstat (limited to 'lib')
-rw-r--r--lib/Makefile.am10
-rw-r--r--lib/checksum.c2
-rw-r--r--lib/command.c84
-rw-r--r--lib/command.h15
-rw-r--r--lib/distribute.c338
-rw-r--r--lib/distribute.h6
-rw-r--r--lib/if.c18
-rw-r--r--lib/if.h4
-rw-r--r--lib/imsg-buffer.c301
-rw-r--r--lib/imsg.c334
-rw-r--r--lib/imsg.h112
-rw-r--r--lib/json.h6
-rw-r--r--lib/keychain.c100
-rw-r--r--lib/keychain.h8
-rw-r--r--lib/log.c62
-rw-r--r--lib/log.h14
-rw-r--r--lib/memory.c2
-rw-r--r--lib/memory_vty.c20
-rw-r--r--lib/mpls.h190
-rw-r--r--lib/nexthop.c36
-rw-r--r--lib/nexthop.h18
-rw-r--r--lib/openbsd-queue.h533
-rw-r--r--lib/openbsd-tree.h748
-rw-r--r--lib/plist.c56
-rw-r--r--lib/prefix.c2
-rw-r--r--lib/privs.c9
-rw-r--r--lib/qobj.c83
-rw-r--r--lib/qobj.h122
-rw-r--r--lib/route_types.txt14
-rw-r--r--lib/routemap.c192
-rw-r--r--lib/routemap.h11
-rw-r--r--lib/skiplist.c685
-rw-r--r--lib/skiplist.h159
-rw-r--r--lib/sockopt.c34
-rw-r--r--lib/sockunion.h6
-rw-r--r--lib/table.c6
-rw-r--r--lib/table.h3
-rw-r--r--lib/thread.c4
-rw-r--r--lib/vrf.c10
-rw-r--r--lib/vrf.h4
-rw-r--r--lib/vty.c100
-rw-r--r--lib/vty.h125
-rw-r--r--lib/zclient.c87
-rw-r--r--lib/zclient.h12
-rw-r--r--lib/zebra.h20
45 files changed, 4197 insertions, 508 deletions
diff --git a/lib/Makefile.am b/lib/Makefile.am
index acaf7e674..dbf1a82be 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -1,6 +1,7 @@
## Process this file with automake to produce Makefile.in.
-AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib
+AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib \
+ -DVTY_DEPRECATE_INDEX
AM_CFLAGS = $(WERROR)
DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\"
AM_YFLAGS = -d
@@ -17,7 +18,9 @@ libzebra_la_SOURCES = \
filter.c routemap.c distribute.c stream.c str.c log.c plist.c \
zclient.c sockopt.c smux.c agentx.c snmp.c md5.c if_rmap.c keychain.c privs.c \
sigevent.c pqueue.c jhash.c workqueue.c nexthop.c json.c \
- ptm_lib.c csv.c bfd.c vrf.c systemd.c ns.c memory.c memory_vty.c
+ ptm_lib.c csv.c bfd.c vrf.c systemd.c ns.c memory.c memory_vty.c \
+ imsg-buffer.c imsg.c skiplist.c \
+ qobj.c
BUILT_SOURCES = route_types.h gitversion.h command_parse.h
@@ -36,7 +39,8 @@ pkginclude_HEADERS = \
privs.h sigevent.h pqueue.h jhash.h zassert.h \
workqueue.h route_types.h libospf.h nexthop.h json.h \
ptm_lib.h csv.h bfd.h vrf.h ns.h systemd.h bitfield.h \
- fifo.h memory_vty.h
+ fifo.h memory_vty.h mpls.h imsg.h openbsd-queue.h openbsd-tree.h \
+ skiplist.h qobj.h
noinst_HEADERS = \
plist_int.h
diff --git a/lib/checksum.c b/lib/checksum.c
index 116aaafc9..3d6cd4579 100644
--- a/lib/checksum.c
+++ b/lib/checksum.c
@@ -47,7 +47,7 @@ in_cksum(void *parg, int nbytes)
}
/* Fletcher Checksum -- Refer to RFC1008. */
-#define MODX 4102 /* 5802 should be fine */
+#define MODX 4102U /* 5802 should be fine */
/* To be consistent, offset is 0-based index, rather than the 1-based
index required in the specification ISO 8473, Annex C.1 */
diff --git a/lib/command.c b/lib/command.c
index 2f83a7fa5..63cfc695d 100644
--- a/lib/command.c
+++ b/lib/command.c
@@ -40,6 +40,7 @@
#include "vrf.h"
#include "command_match.h"
#include "command_parse.h"
+#include "qobj.h"
DEFINE_MTYPE( LIB, HOST, "Host config")
DEFINE_MTYPE( LIB, STRVEC, "String vector")
@@ -65,12 +66,6 @@ static struct cmd_node view_node =
"%s> ",
};
-static struct cmd_node restricted_node =
-{
- RESTRICTED_NODE,
- "%s$ ",
-};
-
static struct cmd_node auth_enable_node =
{
AUTH_ENABLE_NODE,
@@ -342,6 +337,9 @@ install_element (enum node_type ntype, struct cmd_element *cmd)
command_parse_format (cnode->cmdgraph, cmd);
vector_set (cnode->cmd_vector, cmd);
+
+ if (ntype == VIEW_NODE)
+ install_element (ENABLE_NODE, cmd);
}
static const unsigned char itoa64[] =
@@ -480,7 +478,6 @@ cmd_try_do_shortcut (enum node_type node, char* first_word) {
node != VIEW_NODE &&
node != AUTH_ENABLE_NODE &&
node != ENABLE_NODE &&
- node != RESTRICTED_NODE &&
0 == strcmp( "do", first_word ) )
return 1;
return 0;
@@ -695,6 +692,9 @@ node_parent ( enum node_type node )
case BGP_VPNV6_NODE:
case BGP_ENCAP_NODE:
case BGP_ENCAPV6_NODE:
+ case BGP_VNC_DEFAULTS_NODE:
+ case BGP_VNC_NVE_GROUP_NODE:
+ case BGP_VNC_L2_GROUP_NODE:
case BGP_IPV4_NODE:
case BGP_IPV4M_NODE:
case BGP_IPV6_NODE:
@@ -707,6 +707,19 @@ node_parent ( enum node_type node )
case LINK_PARAMS_NODE:
ret = INTERFACE_NODE;
break;
+ case LDP_IPV4_NODE:
+ case LDP_IPV6_NODE:
+ ret = LDP_NODE;
+ break;
+ case LDP_IPV4_IFACE_NODE:
+ ret = LDP_IPV4_NODE;
+ break;
+ case LDP_IPV6_IFACE_NODE:
+ ret = LDP_IPV6_NODE;
+ break;
+ case LDP_PSEUDOWIRE_NODE:
+ ret = LDP_L2VPN_NODE;
+ break;
default:
ret = CONFIG_NODE;
break;
@@ -999,7 +1012,6 @@ DEFUN (config_exit,
{
case VIEW_NODE:
case ENABLE_NODE:
- case RESTRICTED_NODE:
if (vty_shell (vty))
exit (0);
else
@@ -1018,6 +1030,8 @@ DEFUN (config_exit,
case RIPNG_NODE:
case OSPF_NODE:
case OSPF6_NODE:
+ case LDP_NODE:
+ case LDP_L2VPN_NODE:
case ISIS_NODE:
case KEYCHAIN_NODE:
case MASC_NODE:
@@ -1032,10 +1046,26 @@ DEFUN (config_exit,
case BGP_VPNV6_NODE:
case BGP_ENCAP_NODE:
case BGP_ENCAPV6_NODE:
+ case BGP_VNC_DEFAULTS_NODE:
+ case BGP_VNC_NVE_GROUP_NODE:
+ case BGP_VNC_L2_GROUP_NODE:
case BGP_IPV6_NODE:
case BGP_IPV6M_NODE:
vty->node = BGP_NODE;
break;
+ case LDP_IPV4_NODE:
+ case LDP_IPV6_NODE:
+ vty->node = LDP_NODE;
+ break;
+ case LDP_IPV4_IFACE_NODE:
+ vty->node = LDP_IPV4_NODE;
+ break;
+ case LDP_IPV6_IFACE_NODE:
+ vty->node = LDP_IPV6_NODE;
+ break;
+ case LDP_PSEUDOWIRE_NODE:
+ vty->node = LDP_L2VPN_NODE;
+ break;
case KEYCHAIN_KEY_NODE:
vty->node = KEYCHAIN_NODE;
break;
@@ -1068,7 +1098,6 @@ DEFUN (config_end,
{
case VIEW_NODE:
case ENABLE_NODE:
- case RESTRICTED_NODE:
/* Nothing to do. */
break;
case CONFIG_NODE:
@@ -1081,6 +1110,9 @@ DEFUN (config_end,
case BGP_NODE:
case BGP_ENCAP_NODE:
case BGP_ENCAPV6_NODE:
+ case BGP_VNC_DEFAULTS_NODE:
+ case BGP_VNC_NVE_GROUP_NODE:
+ case BGP_VNC_L2_GROUP_NODE:
case BGP_VPNV4_NODE:
case BGP_VPNV6_NODE:
case BGP_IPV4_NODE:
@@ -1090,6 +1122,13 @@ DEFUN (config_end,
case RMAP_NODE:
case OSPF_NODE:
case OSPF6_NODE:
+ case LDP_NODE:
+ case LDP_IPV4_NODE:
+ case LDP_IPV6_NODE:
+ case LDP_IPV4_IFACE_NODE:
+ case LDP_IPV6_IFACE_NODE:
+ case LDP_L2VPN_NODE:
+ case LDP_PSEUDOWIRE_NODE:
case ISIS_NODE:
case KEYCHAIN_NODE:
case KEYCHAIN_KEY_NODE:
@@ -1725,6 +1764,7 @@ DEFUN (config_logmsg,
zlog(NULL, level, "%s", ((message = argv_concat(argv, argc, idx_message)) ? message : ""));
if (message)
XFREE(MTYPE_TMP, message);
+
return CMD_SUCCESS;
}
@@ -2195,6 +2235,8 @@ install_default (enum node_type node)
void
cmd_init (int terminal)
{
+ qobj_init ();
+
/* Allocate initial top vector of commands. */
cmdvec = vector_init (VECTOR_MIN_SIZE);
@@ -2213,7 +2255,6 @@ cmd_init (int terminal)
install_node (&enable_node, NULL);
install_node (&auth_node, NULL);
install_node (&auth_enable_node, NULL);
- install_node (&restricted_node, NULL);
install_node (&config_node, config_write_host);
/* Each node's basic commands. */
@@ -2230,36 +2271,22 @@ cmd_init (int terminal)
install_element (VIEW_NODE, &show_logging_cmd);
install_element (VIEW_NODE, &show_commandtree_cmd);
install_element (VIEW_NODE, &echo_cmd);
-
- install_element (RESTRICTED_NODE, &config_list_cmd);
- install_element (RESTRICTED_NODE, &config_exit_cmd);
- install_element (RESTRICTED_NODE, &config_quit_cmd);
- install_element (RESTRICTED_NODE, &config_help_cmd);
- install_element (RESTRICTED_NODE, &config_enable_cmd);
- install_element (RESTRICTED_NODE, &config_terminal_length_cmd);
- install_element (RESTRICTED_NODE, &config_terminal_no_length_cmd);
- install_element (RESTRICTED_NODE, &echo_cmd);
}
if (terminal)
{
- install_default (ENABLE_NODE);
+ install_element (ENABLE_NODE, &config_end_cmd);
install_element (ENABLE_NODE, &config_disable_cmd);
install_element (ENABLE_NODE, &config_terminal_cmd);
install_element (ENABLE_NODE, &copy_runningconf_startupconf_cmd);
+ install_element (ENABLE_NODE, &config_write_cmd);
+ install_element (ENABLE_NODE, &show_running_config_cmd);
}
install_element (ENABLE_NODE, &show_startup_config_cmd);
- install_element (ENABLE_NODE, &show_version_cmd);
- install_element (ENABLE_NODE, &show_commandtree_cmd);
if (terminal)
{
- install_element (ENABLE_NODE, &config_terminal_length_cmd);
- install_element (ENABLE_NODE, &config_terminal_no_length_cmd);
- install_element (ENABLE_NODE, &show_logging_cmd);
- install_element (ENABLE_NODE, &echo_cmd);
install_element (ENABLE_NODE, &config_logmsg_cmd);
-
install_default (CONFIG_NODE);
}
@@ -2297,12 +2324,9 @@ cmd_init (int terminal)
install_element (CONFIG_NODE, &no_service_terminal_length_cmd);
install_element (VIEW_NODE, &show_thread_cpu_cmd);
- install_element (ENABLE_NODE, &show_thread_cpu_cmd);
- install_element (RESTRICTED_NODE, &show_thread_cpu_cmd);
install_element (ENABLE_NODE, &clear_thread_cpu_cmd);
install_element (VIEW_NODE, &show_work_queues_cmd);
- install_element (ENABLE_NODE, &show_work_queues_cmd);
vrf_install_commands ();
}
diff --git a/lib/command.h b/lib/command.h
index e411e9c18..3c1008d4e 100644
--- a/lib/command.h
+++ b/lib/command.h
@@ -70,7 +70,6 @@ struct host
enum node_type
{
AUTH_NODE, /* Authentication mode of vty interface. */
- RESTRICTED_NODE, /* Restricted view mode */
VIEW_NODE, /* View node. Default mode of vty interface. */
AUTH_ENABLE_NODE, /* Authentication mode for change enable. */
ENABLE_NODE, /* Enable node. */
@@ -78,6 +77,7 @@ enum node_type
SERVICE_NODE, /* Service node. */
DEBUG_NODE, /* Debug node. */
VRF_DEBUG_NODE, /* Vrf Debug node. */
+ DEBUG_VNC_NODE, /* Debug VNC node. */
AAA_NODE, /* AAA node. */
KEYCHAIN_NODE, /* Key-chain node. */
KEYCHAIN_KEY_NODE, /* Key-chain key node. */
@@ -97,8 +97,19 @@ enum node_type
BGP_IPV6M_NODE, /* BGP IPv6 multicast address family. */
BGP_ENCAP_NODE, /* BGP ENCAP SAFI */
BGP_ENCAPV6_NODE, /* BGP ENCAP SAFI */
+ BGP_VNC_DEFAULTS_NODE, /* BGP VNC nve defaults */
+ BGP_VNC_NVE_GROUP_NODE, /* BGP VNC nve group */
+ BGP_VNC_L2_GROUP_NODE, /* BGP VNC L2 group */
+ RFP_DEFAULTS_NODE, /* RFP defaults node */
OSPF_NODE, /* OSPF protocol mode */
OSPF6_NODE, /* OSPF protocol for IPv6 mode */
+ LDP_NODE, /* LDP protocol mode */
+ LDP_IPV4_NODE, /* LDP IPv4 address family */
+ LDP_IPV6_NODE, /* LDP IPv6 address family */
+ LDP_IPV4_IFACE_NODE, /* LDP IPv4 Interface */
+ LDP_IPV6_IFACE_NODE, /* LDP IPv6 Interface */
+ LDP_L2VPN_NODE, /* LDP L2VPN node */
+ LDP_PSEUDOWIRE_NODE, /* LDP Pseudowire node */
ISIS_NODE, /* ISIS protocol mode */
PIM_NODE, /* PIM protocol mode */
MASC_NODE, /* MASC for multicast. */
@@ -115,6 +126,7 @@ enum node_type
DUMP_NODE, /* Packet dump node. */
FORWARDING_NODE, /* IP forwarding node. */
PROTOCOL_NODE, /* protocol filtering node */
+ MPLS_NODE, /* MPLS config node */
VTY_NODE, /* Vty node. */
LINK_PARAMS_NODE, /* Link-parameters node */
};
@@ -365,6 +377,7 @@ struct cmd_element
#define LINK_PARAMS_STR "Configure interface link parameters\n"
#define OSPF_RI_STR "OSPF Router Information specific commands\n"
#define PCE_STR "PCE Router Information specific commands\n"
+#define MPLS_STR "MPLS information\n"
#define CONF_BACKUP_EXT ".sav"
diff --git a/lib/distribute.c b/lib/distribute.c
index 8a0083391..8726e993c 100644
--- a/lib/distribute.c
+++ b/lib/distribute.c
@@ -49,22 +49,35 @@ distribute_new (void)
static void
distribute_free (struct distribute *dist)
{
+ int i = 0;
+
if (dist->ifname)
XFREE (MTYPE_DISTRIBUTE_IFNAME, dist->ifname);
- if (dist->list[DISTRIBUTE_IN])
- XFREE(MTYPE_DISTRIBUTE_NAME, dist->list[DISTRIBUTE_IN]);
- if (dist->list[DISTRIBUTE_OUT])
- XFREE(MTYPE_DISTRIBUTE_NAME, dist->list[DISTRIBUTE_OUT]);
+ for (i = 0; i < DISTRIBUTE_MAX; i++)
+ if (dist->list[i])
+ XFREE(MTYPE_DISTRIBUTE_NAME, dist->list[i]);
- if (dist->prefix[DISTRIBUTE_IN])
- XFREE(MTYPE_DISTRIBUTE_NAME, dist->prefix[DISTRIBUTE_IN]);
- if (dist->prefix[DISTRIBUTE_OUT])
- XFREE(MTYPE_DISTRIBUTE_NAME, dist->prefix[DISTRIBUTE_OUT]);
+ for (i = 0; i < DISTRIBUTE_MAX; i++)
+ if (dist->prefix[i])
+ XFREE(MTYPE_DISTRIBUTE_NAME, dist->prefix[i]);
XFREE (MTYPE_DISTRIBUTE, dist);
}
+static void
+distribute_free_if_empty(struct distribute *dist)
+{
+ int i;
+
+ for (i = 0; i < DISTRIBUTE_MAX; i++)
+ if (dist->list[i] != NULL || dist->prefix[i] != NULL)
+ return;
+
+ hash_release (disthash, dist);
+ distribute_free (dist);
+}
+
/* Lookup interface's distribute list. */
struct distribute *
distribute_lookup (const char *ifname)
@@ -156,18 +169,9 @@ distribute_list_set (const char *ifname, enum distribute_type type,
dist = distribute_get (ifname);
- if (type == DISTRIBUTE_IN)
- {
- if (dist->list[DISTRIBUTE_IN])
- XFREE(MTYPE_DISTRIBUTE_NAME, dist->list[DISTRIBUTE_IN]);
- dist->list[DISTRIBUTE_IN] = XSTRDUP(MTYPE_DISTRIBUTE_NAME, alist_name);
- }
- if (type == DISTRIBUTE_OUT)
- {
- if (dist->list[DISTRIBUTE_OUT])
- XFREE(MTYPE_DISTRIBUTE_NAME, dist->list[DISTRIBUTE_OUT]);
- dist->list[DISTRIBUTE_OUT] = XSTRDUP(MTYPE_DISTRIBUTE_NAME, alist_name);
- }
+ if (dist->list[type])
+ XFREE(MTYPE_DISTRIBUTE_NAME, dist->list[type]);
+ dist->list[type] = XSTRDUP(MTYPE_DISTRIBUTE_NAME, alist_name);
/* Apply this distribute-list to the interface. */
(*distribute_add_hook) (dist);
@@ -185,41 +189,19 @@ distribute_list_unset (const char *ifname, enum distribute_type type,
if (!dist)
return 0;
- if (type == DISTRIBUTE_IN)
- {
- if (!dist->list[DISTRIBUTE_IN])
+ if (!dist->list[type])
return 0;
- if (strcmp (dist->list[DISTRIBUTE_IN], alist_name) != 0)
+ if (strcmp (dist->list[type], alist_name) != 0)
return 0;
- XFREE(MTYPE_DISTRIBUTE_NAME, dist->list[DISTRIBUTE_IN]);
- dist->list[DISTRIBUTE_IN] = NULL;
- }
-
- if (type == DISTRIBUTE_OUT)
- {
- if (!dist->list[DISTRIBUTE_OUT])
- return 0;
- if (strcmp (dist->list[DISTRIBUTE_OUT], alist_name) != 0)
- return 0;
-
- XFREE(MTYPE_DISTRIBUTE_NAME, dist->list[DISTRIBUTE_OUT]);
- dist->list[DISTRIBUTE_OUT] = NULL;
- }
+ XFREE(MTYPE_DISTRIBUTE_NAME, dist->list[type]);
+ dist->list[type] = NULL;
/* Apply this distribute-list to the interface. */
(*distribute_delete_hook) (dist);
- /* If both out and in is NULL then free distribute list. */
- if (dist->list[DISTRIBUTE_IN] == NULL &&
- dist->list[DISTRIBUTE_OUT] == NULL &&
- dist->prefix[DISTRIBUTE_IN] == NULL &&
- dist->prefix[DISTRIBUTE_OUT] == NULL)
- {
- hash_release (disthash, dist);
- distribute_free (dist);
- }
-
+ /* If all dist are NULL, then free distribute list. */
+ distribute_free_if_empty(dist);
return 1;
}
@@ -232,18 +214,9 @@ distribute_list_prefix_set (const char *ifname, enum distribute_type type,
dist = distribute_get (ifname);
- if (type == DISTRIBUTE_IN)
- {
- if (dist->prefix[DISTRIBUTE_IN])
- XFREE(MTYPE_DISTRIBUTE_NAME, dist->prefix[DISTRIBUTE_IN]);
- dist->prefix[DISTRIBUTE_IN] = XSTRDUP(MTYPE_DISTRIBUTE_NAME, plist_name);
- }
- if (type == DISTRIBUTE_OUT)
- {
- if (dist->prefix[DISTRIBUTE_OUT])
- XFREE(MTYPE_DISTRIBUTE_NAME, dist->prefix[DISTRIBUTE_OUT]);
- dist->prefix[DISTRIBUTE_OUT] = XSTRDUP(MTYPE_DISTRIBUTE_NAME, plist_name);
- }
+ if (dist->prefix[type])
+ XFREE(MTYPE_DISTRIBUTE_NAME, dist->prefix[type]);
+ dist->prefix[type] = XSTRDUP(MTYPE_DISTRIBUTE_NAME, plist_name);
/* Apply this distribute-list to the interface. */
(*distribute_add_hook) (dist);
@@ -261,41 +234,19 @@ distribute_list_prefix_unset (const char *ifname, enum distribute_type type,
if (!dist)
return 0;
- if (type == DISTRIBUTE_IN)
- {
- if (!dist->prefix[DISTRIBUTE_IN])
- return 0;
- if (strcmp (dist->prefix[DISTRIBUTE_IN], plist_name) != 0)
- return 0;
-
- XFREE(MTYPE_DISTRIBUTE_NAME, dist->prefix[DISTRIBUTE_IN]);
- dist->prefix[DISTRIBUTE_IN] = NULL;
- }
-
- if (type == DISTRIBUTE_OUT)
- {
- if (!dist->prefix[DISTRIBUTE_OUT])
+ if (!dist->prefix[type])
return 0;
- if (strcmp (dist->prefix[DISTRIBUTE_OUT], plist_name) != 0)
+ if (strcmp (dist->prefix[type], plist_name) != 0)
return 0;
- XFREE(MTYPE_DISTRIBUTE_NAME, dist->prefix[DISTRIBUTE_OUT]);
- dist->prefix[DISTRIBUTE_OUT] = NULL;
- }
+ XFREE(MTYPE_DISTRIBUTE_NAME, dist->prefix[type]);
+ dist->prefix[type] = NULL;
/* Apply this distribute-list to the interface. */
(*distribute_delete_hook) (dist);
- /* If both out and in is NULL then free distribute list. */
- if (dist->list[DISTRIBUTE_IN] == NULL &&
- dist->list[DISTRIBUTE_OUT] == NULL &&
- dist->prefix[DISTRIBUTE_IN] == NULL &&
- dist->prefix[DISTRIBUTE_OUT] == NULL)
- {
- hash_release (disthash, dist);
- distribute_free (dist);
- }
-
+ /* If all dist are NULL, then free distribute list. */
+ distribute_free_if_empty(dist);
return 1;
}
@@ -312,7 +263,7 @@ DEFUN (distribute_list,
/* Check of distribute list type. */
enum distribute_type type = argv[2 + prefix]->arg[0] == 'i' ?
- DISTRIBUTE_IN : DISTRIBUTE_OUT;
+ DISTRIBUTE_V4_IN : DISTRIBUTE_V4_OUT;
/* Set appropriate function call */
void (*distfn)(const char *, enum distribute_type, const char *) = prefix ?
@@ -329,9 +280,40 @@ DEFUN (distribute_list,
return CMD_SUCCESS;
}
+DEFUN (ipv6_distribute_list,
+ ipv6_distribute_list_cmd,
+ "ipv6 distribute-list [prefix] WORD <in|out> [WORD]",
+ "IPv6\n"
+ "Filter networks in routing updates\n"
+ "Access-list name\n"
+ "Filter incoming routing updates\n"
+ "Filter outgoing routing updates\n"
+ "Interface name\n")
+{
+ int prefix = (argv[2]->type == WORD_TKN) ? 1 : 0;
+
+ /* Check of distribute list type. */
+ enum distribute_type type = argv[3 + prefix]->arg[0] == 'i' ?
+ DISTRIBUTE_V6_IN : DISTRIBUTE_V6_OUT;
+
+ /* Set appropriate function call */
+ void (*distfn)(const char *, enum distribute_type, const char *) = prefix ?
+ &distribute_list_prefix_set : &distribute_list_set;
+
+ /* if interface is present, get name */
+ const char *ifname = NULL;
+ if (argv[argc - 1]->type == VARIABLE_TKN)
+ ifname = argv[argc - 1]->arg;
+
+ /* Get interface name corresponding distribute list. */
+ distfn (ifname, type, argv[1 + prefix]->arg);
+
+ return CMD_SUCCESS;
+}
+
DEFUN (no_distribute_list,
no_distribute_list_cmd,
- "no distribute-list [prefix] WORD <in|out> [WORD]",
+ "no [ipv6] distribute-list [prefix] WORD <in|out> [WORD]",
NO_STR
"Filter networks in routing updates\n"
"Access-list name\n"
@@ -339,11 +321,17 @@ DEFUN (no_distribute_list,
"Filter outgoing routing updates\n"
"Interface name\n")
{
- int prefix = (argv[2]->type == WORD_TKN) ? 1 : 0;
+ int ipv6 = strmatch(argv[1]->text, "ipv6");
+ int prefix = (argv[2 + ipv6]->type == WORD_TKN) ? 1 : 0;
+
+ int idx_alname = 2 + ipv6 + prefix;
+ int idx_disttype = idx_alname + 1;
/* Check of distribute list type. */
- enum distribute_type type = argv[3 + prefix]->arg[0] == 'i' ?
- DISTRIBUTE_IN : DISTRIBUTE_OUT;
+ enum distribute_type distin = (ipv6) ? DISTRIBUTE_V6_IN : DISTRIBUTE_V4_IN;
+ enum distribute_type distout = (ipv6) ? DISTRIBUTE_V6_OUT : DISTRIBUTE_V4_OUT;
+
+ enum distribute_type type = argv[idx_disttype]->arg[0] == 'i' ? distin : distout;
/* Set appropriate function call */
int (*distfn)(const char *, enum distribute_type, const char *) = prefix ?
@@ -353,7 +341,6 @@ DEFUN (no_distribute_list,
const char *ifname = NULL;
if (argv[argc - 1]->type == VARIABLE_TKN)
ifname = argv[argc - 1]->arg;
-
/* Get interface name corresponding distribute list. */
int ret = distfn (ifname, type, argv[2 + prefix]->arg);
@@ -365,79 +352,112 @@ DEFUN (no_distribute_list,
return CMD_SUCCESS;
}
+static int
+distribute_print (struct vty *vty, char *tab[], int is_prefix,
+ enum distribute_type type, int has_print)
+{
+ if (tab[type]) {
+ vty_out (vty, "%s %s%s",
+ has_print ? "," : "",
+ is_prefix ? "(prefix-list) " : "",
+ tab[type]);
+ return 1;
+ }
+ return has_print;
+}
+
int
config_show_distribute (struct vty *vty)
{
unsigned int i;
+ int has_print = 0;
struct hash_backet *mp;
struct distribute *dist;
/* Output filter configuration. */
dist = distribute_lookup (NULL);
- if (dist && (dist->list[DISTRIBUTE_OUT] || dist->prefix[DISTRIBUTE_OUT]))
- {
vty_out (vty, " Outgoing update filter list for all interface is");
- if (dist->list[DISTRIBUTE_OUT])
- vty_out (vty, " %s", dist->list[DISTRIBUTE_OUT]);
- if (dist->prefix[DISTRIBUTE_OUT])
- vty_out (vty, "%s (prefix-list) %s",
- dist->list[DISTRIBUTE_OUT] ? "," : "",
- dist->prefix[DISTRIBUTE_OUT]);
- vty_out (vty, "%s", VTY_NEWLINE);
+ has_print = 0;
+ if (dist)
+ {
+ has_print = distribute_print(vty, dist->list, 0,
+ DISTRIBUTE_V4_OUT, has_print);
+ has_print = distribute_print(vty, dist->prefix, 1,
+ DISTRIBUTE_V4_OUT, has_print);
+ has_print = distribute_print(vty, dist->list, 0,
+ DISTRIBUTE_V6_OUT, has_print);
+ has_print = distribute_print(vty, dist->prefix, 1,
+ DISTRIBUTE_V6_OUT, has_print);
}
+ if (has_print)
+ vty_out (vty, "%s", VTY_NEWLINE);
else
- vty_out (vty, " Outgoing update filter list for all interface is not set%s", VTY_NEWLINE);
+ vty_out (vty, " not set%s", VTY_NEWLINE);
for (i = 0; i < disthash->size; i++)
for (mp = disthash->index[i]; mp; mp = mp->next)
{
dist = mp->data;
if (dist->ifname)
- if (dist->list[DISTRIBUTE_OUT] || dist->prefix[DISTRIBUTE_OUT])
{
vty_out (vty, " %s filtered by", dist->ifname);
- if (dist->list[DISTRIBUTE_OUT])
- vty_out (vty, " %s", dist->list[DISTRIBUTE_OUT]);
- if (dist->prefix[DISTRIBUTE_OUT])
- vty_out (vty, "%s (prefix-list) %s",
- dist->list[DISTRIBUTE_OUT] ? "," : "",
- dist->prefix[DISTRIBUTE_OUT]);
+ has_print = 0;
+ has_print = distribute_print(vty, dist->list, 0,
+ DISTRIBUTE_V4_OUT, has_print);
+ has_print = distribute_print(vty, dist->prefix, 1,
+ DISTRIBUTE_V4_OUT, has_print);
+ has_print = distribute_print(vty, dist->list, 0,
+ DISTRIBUTE_V6_OUT, has_print);
+ has_print = distribute_print(vty, dist->prefix, 1,
+ DISTRIBUTE_V6_OUT, has_print);
+ if (has_print)
vty_out (vty, "%s", VTY_NEWLINE);
+ else
+ vty_out(vty, " nothing%s", VTY_NEWLINE);
}
}
/* Input filter configuration. */
dist = distribute_lookup (NULL);
- if (dist && (dist->list[DISTRIBUTE_IN] || dist->prefix[DISTRIBUTE_IN]))
- {
vty_out (vty, " Incoming update filter list for all interface is");
- if (dist->list[DISTRIBUTE_IN])
- vty_out (vty, " %s", dist->list[DISTRIBUTE_IN]);
- if (dist->prefix[DISTRIBUTE_IN])
- vty_out (vty, "%s (prefix-list) %s",
- dist->list[DISTRIBUTE_IN] ? "," : "",
- dist->prefix[DISTRIBUTE_IN]);
- vty_out (vty, "%s", VTY_NEWLINE);
+ has_print = 0;
+ if (dist)
+ {
+ has_print = distribute_print(vty, dist->list, 0,
+ DISTRIBUTE_V4_IN, has_print);
+ has_print = distribute_print(vty, dist->prefix, 1,
+ DISTRIBUTE_V4_IN, has_print);
+ has_print = distribute_print(vty, dist->list, 0,
+ DISTRIBUTE_V6_IN, has_print);
+ has_print = distribute_print(vty, dist->prefix, 1,
+ DISTRIBUTE_V6_IN, has_print);
}
+ if (has_print)
+ vty_out (vty, "%s", VTY_NEWLINE);
else
- vty_out (vty, " Incoming update filter list for all interface is not set%s", VTY_NEWLINE);
+ vty_out (vty, " not set%s", VTY_NEWLINE);
for (i = 0; i < disthash->size; i++)
for (mp = disthash->index[i]; mp; mp = mp->next)
{
dist = mp->data;
if (dist->ifname)
- if (dist->list[DISTRIBUTE_IN] || dist->prefix[DISTRIBUTE_IN])
{
vty_out (vty, " %s filtered by", dist->ifname);
- if (dist->list[DISTRIBUTE_IN])
- vty_out (vty, " %s", dist->list[DISTRIBUTE_IN]);
- if (dist->prefix[DISTRIBUTE_IN])
- vty_out (vty, "%s (prefix-list) %s",
- dist->list[DISTRIBUTE_IN] ? "," : "",
- dist->prefix[DISTRIBUTE_IN]);
+ has_print = 0;
+ has_print = distribute_print(vty, dist->list, 0,
+ DISTRIBUTE_V4_IN, has_print);
+ has_print = distribute_print(vty, dist->prefix, 1,
+ DISTRIBUTE_V4_IN, has_print);
+ has_print = distribute_print(vty, dist->list, 0,
+ DISTRIBUTE_V6_IN, has_print);
+ has_print = distribute_print(vty, dist->prefix, 1,
+ DISTRIBUTE_V6_IN, has_print);
+ if (has_print)
vty_out (vty, "%s", VTY_NEWLINE);
+ else
+ vty_out(vty, " nothing%s", VTY_NEWLINE);
}
}
return 0;
@@ -448,6 +468,8 @@ int
config_write_distribute (struct vty *vty)
{
unsigned int i;
+ int j;
+ int output, v6;
struct hash_backet *mp;
int write = 0;
@@ -458,38 +480,27 @@ config_write_distribute (struct vty *vty)
dist = mp->data;
- if (dist->list[DISTRIBUTE_IN])
- {
- vty_out (vty, " distribute-list %s in %s%s",
- dist->list[DISTRIBUTE_IN],
- dist->ifname ? dist->ifname : "",
- VTY_NEWLINE);
- write++;
- }
-
- if (dist->list[DISTRIBUTE_OUT])
- {
- vty_out (vty, " distribute-list %s out %s%s",
-
- dist->list[DISTRIBUTE_OUT],
+ for (j = 0; j < DISTRIBUTE_MAX; j++)
+ if (dist->list[j]) {
+ output = j == DISTRIBUTE_V4_OUT || j == DISTRIBUTE_V6_OUT;
+ v6 = j == DISTRIBUTE_V6_IN || j == DISTRIBUTE_V6_OUT;
+ vty_out (vty, " %sdistribute-list %s %s %s%s",
+ v6 ? "ipv6 " : "",
+ dist->list[j],
+ output ? "out" : "in",
dist->ifname ? dist->ifname : "",
VTY_NEWLINE);
write++;
}
- if (dist->prefix[DISTRIBUTE_IN])
- {
- vty_out (vty, " distribute-list prefix %s in %s%s",
- dist->prefix[DISTRIBUTE_IN],
- dist->ifname ? dist->ifname : "",
- VTY_NEWLINE);
- write++;
- }
-
- if (dist->prefix[DISTRIBUTE_OUT])
- {
- vty_out (vty, " distribute-list prefix %s out %s%s",
- dist->prefix[DISTRIBUTE_OUT],
+ for (j = 0; j < DISTRIBUTE_MAX; j++)
+ if (dist->prefix[j]) {
+ output = j == DISTRIBUTE_V4_OUT || j == DISTRIBUTE_V6_OUT;
+ v6 = j == DISTRIBUTE_V6_IN || j == DISTRIBUTE_V6_OUT;
+ vty_out (vty, " %sdistribute-list prefix %s %s %s%s",
+ v6 ? "ipv6 " : "",
+ dist->prefix[j],
+ output ? "out" : "in",
dist->ifname ? dist->ifname : "",
VTY_NEWLINE);
write++;
@@ -514,4 +525,21 @@ distribute_list_init (int node)
install_element (node, &distribute_list_cmd);
install_element (node, &no_distribute_list_cmd);
+
+ /* install v6 */
+ if (node == RIPNG_NODE) {
+ install_element (node, &ipv6_distribute_list_cmd);
+ }
+
+ /* TODO: install v4 syntax command for v6 only protocols. */
+ /* if (node == RIPNG_NODE) {
+ * install_element (node, &ipv6_as_v4_distribute_list_all_cmd);
+ * install_element (node, &no_ipv6_as_v4_distribute_list_all_cmd);
+ * install_element (node, &ipv6_as_v4_distribute_list_cmd);
+ * install_element (node, &no_ipv6_as_v4_distribute_list_cmd);
+ * install_element (node, &ipv6_as_v4_distribute_list_prefix_all_cmd);
+ * install_element (node, &no_ipv6_as_v4_distribute_list_prefix_all_cmd);
+ * install_element (node, &ipv6_as_v4_distribute_list_prefix_cmd);
+ * install_element (node, &no_ipv6_as_v4_distribute_list_prefix_cmd);
+ }*/
}
diff --git a/lib/distribute.h b/lib/distribute.h
index a2ffffd5f..e9625a354 100644
--- a/lib/distribute.h
+++ b/lib/distribute.h
@@ -29,8 +29,10 @@
/* Disctirubte list types. */
enum distribute_type
{
- DISTRIBUTE_IN,
- DISTRIBUTE_OUT,
+ DISTRIBUTE_V4_IN,
+ DISTRIBUTE_V6_IN,
+ DISTRIBUTE_V4_OUT,
+ DISTRIBUTE_V6_OUT,
DISTRIBUTE_MAX
};
diff --git a/lib/if.c b/lib/if.c
index dd8922ee9..6235884e5 100644
--- a/lib/if.c
+++ b/lib/if.c
@@ -43,6 +43,8 @@ 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")
+DEFINE_QOBJ_TYPE(interface)
+
/* List of interfaces in only the default VRF */
int ptm_enable = 0;
@@ -149,6 +151,8 @@ if_create_vrf (const char *name, int namelen, vrf_id_t vrf_id)
/* Enable Link-detection by default */
SET_FLAG(ifp->status, ZEBRA_INTERFACE_LINKDETECTION);
+ QOBJ_REG (ifp, interface);
+
if (if_master.if_new_hook)
(*if_master.if_new_hook) (ifp);
@@ -193,6 +197,8 @@ if_delete_retain (struct interface *ifp)
if (if_master.if_delete_hook)
(*if_master.if_delete_hook) (ifp);
+ QOBJ_UNREG (ifp);
+
/* Free connected address list */
list_delete_all_node (ifp->connected);
@@ -678,9 +684,8 @@ DEFUN (interface_desc,
"Characters describing this interface\n")
{
int idx_line = 1;
- struct interface *ifp;
+ VTY_DECLVAR_CONTEXT (interface, ifp);
- ifp = vty->index;
if (ifp->desc)
XFREE (MTYPE_TMP, ifp->desc);
ifp->desc = argv_concat(argv, argc, idx_line);
@@ -694,9 +699,8 @@ DEFUN (no_interface_desc,
NO_STR
"Interface specific description\n")
{
- struct interface *ifp;
+ VTY_DECLVAR_CONTEXT (interface, ifp);
- ifp = vty->index;
if (ifp->desc)
XFREE (MTYPE_TMP, ifp->desc);
ifp->desc = NULL;
@@ -786,8 +790,7 @@ DEFUN (interface,
vty_out (vty, "%% interface %s not in %s%s", ifname, vrfname, VTY_NEWLINE);
return CMD_WARNING;
}
- vty->index = ifp;
- vty->node = INTERFACE_NODE;
+ VTY_PUSH_CONTEXT_COMPAT (INTERFACE_NODE, ifp);
return CMD_SUCCESS;
}
@@ -852,8 +855,7 @@ DEFUN (vrf,
vrfp = vrf_get (VRF_UNKNOWN, vrfname);
- vty->index = vrfp;
- vty->node = VRF_NODE;
+ VTY_PUSH_CONTEXT_COMPAT (VRF_NODE, vrfp);
return CMD_SUCCESS;
}
diff --git a/lib/if.h b/lib/if.h
index d1875e695..57062cd3f 100644
--- a/lib/if.h
+++ b/lib/if.h
@@ -24,6 +24,7 @@ Boston, MA 02111-1307, USA. */
#include "zebra.h"
#include "linklist.h"
#include "memory.h"
+#include "qobj.h"
DECLARE_MTYPE(IF)
DECLARE_MTYPE(CONNECTED_LABEL)
@@ -267,7 +268,10 @@ struct interface
struct route_node *node;
vrf_id_t vrf_id;
+
+ QOBJ_FIELDS
};
+DECLARE_QOBJ_TYPE(interface)
/* Connected address structure. */
struct connected
diff --git a/lib/imsg-buffer.c b/lib/imsg-buffer.c
new file mode 100644
index 000000000..a486fc17c
--- /dev/null
+++ b/lib/imsg-buffer.c
@@ -0,0 +1,301 @@
+/* $OpenBSD$ */
+
+/*
+ * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <zebra.h>
+
+#include "openbsd-queue.h"
+#include "imsg.h"
+
+int ibuf_realloc(struct ibuf *, size_t);
+void ibuf_enqueue(struct msgbuf *, struct ibuf *);
+void ibuf_dequeue(struct msgbuf *, struct ibuf *);
+
+struct ibuf *
+ibuf_open(size_t len)
+{
+ struct ibuf *buf;
+
+ if ((buf = calloc(1, sizeof(struct ibuf))) == NULL)
+ return (NULL);
+ if ((buf->buf = malloc(len)) == NULL) {
+ free(buf);
+ return (NULL);
+ }
+ buf->size = buf->max = len;
+ buf->fd = -1;
+
+ return (buf);
+}
+
+struct ibuf *
+ibuf_dynamic(size_t len, size_t max)
+{
+ struct ibuf *buf;
+
+ if (max < len)
+ return (NULL);
+
+ if ((buf = ibuf_open(len)) == NULL)
+ return (NULL);
+
+ if (max > 0)
+ buf->max = max;
+
+ return (buf);
+}
+
+int
+ibuf_realloc(struct ibuf *buf, size_t len)
+{
+ u_char *b;
+
+ /* on static buffers max is eq size and so the following fails */
+ if (buf->wpos + len > buf->max) {
+ errno = ERANGE;
+ return (-1);
+ }
+
+ b = realloc(buf->buf, buf->wpos + len);
+ if (b == NULL)
+ return (-1);
+ buf->buf = b;
+ buf->size = buf->wpos + len;
+
+ return (0);
+}
+
+int
+ibuf_add(struct ibuf *buf, const void *data, size_t len)
+{
+ if (buf->wpos + len > buf->size)
+ if (ibuf_realloc(buf, len) == -1)
+ return (-1);
+
+ memcpy(buf->buf + buf->wpos, data, len);
+ buf->wpos += len;
+ return (0);
+}
+
+void *
+ibuf_reserve(struct ibuf *buf, size_t len)
+{
+ void *b;
+
+ if (buf->wpos + len > buf->size)
+ if (ibuf_realloc(buf, len) == -1)
+ return (NULL);
+
+ b = buf->buf + buf->wpos;
+ buf->wpos += len;
+ return (b);
+}
+
+void *
+ibuf_seek(struct ibuf *buf, size_t pos, size_t len)
+{
+ /* only allowed to seek in already written parts */
+ if (pos + len > buf->wpos)
+ return (NULL);
+
+ return (buf->buf + pos);
+}
+
+size_t
+ibuf_size(struct ibuf *buf)
+{
+ return (buf->wpos);
+}
+
+size_t
+ibuf_left(struct ibuf *buf)
+{
+ return (buf->max - buf->wpos);
+}
+
+void
+ibuf_close(struct msgbuf *msgbuf, struct ibuf *buf)
+{
+ ibuf_enqueue(msgbuf, buf);
+}
+
+int
+ibuf_write(struct msgbuf *msgbuf)
+{
+ struct iovec iov[IOV_MAX];
+ struct ibuf *buf;
+ unsigned int i = 0;
+ ssize_t n;
+
+ memset(&iov, 0, sizeof(iov));
+ TAILQ_FOREACH(buf, &msgbuf->bufs, entry) {
+ if (i >= IOV_MAX)
+ break;
+ iov[i].iov_base = buf->buf + buf->rpos;
+ iov[i].iov_len = buf->wpos - buf->rpos;
+ i++;
+ }
+
+again:
+ if ((n = writev(msgbuf->fd, iov, i)) == -1) {
+ if (errno == EINTR)
+ goto again;
+ if (errno == ENOBUFS)
+ errno = EAGAIN;
+ return (-1);
+ }
+
+ if (n == 0) { /* connection closed */
+ errno = 0;
+ return (0);
+ }
+
+ msgbuf_drain(msgbuf, n);
+
+ return (1);
+}
+
+void
+ibuf_free(struct ibuf *buf)
+{
+ if (buf == NULL)
+ return;
+ free(buf->buf);
+ free(buf);
+}
+
+void
+msgbuf_init(struct msgbuf *msgbuf)
+{
+ msgbuf->queued = 0;
+ msgbuf->fd = -1;
+ TAILQ_INIT(&msgbuf->bufs);
+}
+
+void
+msgbuf_drain(struct msgbuf *msgbuf, size_t n)
+{
+ struct ibuf *buf, *next;
+
+ for (buf = TAILQ_FIRST(&msgbuf->bufs); buf != NULL && n > 0;
+ buf = next) {
+ next = TAILQ_NEXT(buf, entry);
+ if (buf->rpos + n >= buf->wpos) {
+ n -= buf->wpos - buf->rpos;
+ ibuf_dequeue(msgbuf, buf);
+ } else {
+ buf->rpos += n;
+ n = 0;
+ }
+ }
+}
+
+void
+msgbuf_clear(struct msgbuf *msgbuf)
+{
+ struct ibuf *buf;
+
+ while ((buf = TAILQ_FIRST(&msgbuf->bufs)) != NULL)
+ ibuf_dequeue(msgbuf, buf);
+}
+
+int
+msgbuf_write(struct msgbuf *msgbuf)
+{
+ struct iovec iov[IOV_MAX];
+ struct ibuf *buf;
+ unsigned int i = 0;
+ ssize_t n;
+ struct msghdr msg;
+ struct cmsghdr *cmsg;
+ union {
+ struct cmsghdr hdr;
+ char buf[CMSG_SPACE(sizeof(int))];
+ } cmsgbuf;
+
+ memset(&iov, 0, sizeof(iov));
+ memset(&msg, 0, sizeof(msg));
+ memset(&cmsgbuf, 0, sizeof(cmsgbuf));
+ TAILQ_FOREACH(buf, &msgbuf->bufs, entry) {
+ if (i >= IOV_MAX)
+ break;
+ iov[i].iov_base = buf->buf + buf->rpos;
+ iov[i].iov_len = buf->wpos - buf->rpos;
+ i++;
+ if (buf->fd != -1)
+ break;
+ }
+
+ msg.msg_iov = iov;
+ msg.msg_iovlen = i;
+
+ if (buf != NULL && buf->fd != -1) {
+ msg.msg_control = (caddr_t)&cmsgbuf.buf;
+ msg.msg_controllen = sizeof(cmsgbuf.buf);
+ cmsg = CMSG_FIRSTHDR(&msg);
+ cmsg->cmsg_len = CMSG_LEN(sizeof(int));
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+ memcpy(CMSG_DATA(cmsg), &buf->fd, sizeof(int));
+ }
+
+again:
+ if ((n = sendmsg(msgbuf->fd, &msg, 0)) == -1) {
+ if (errno == EINTR)
+ goto again;
+ if (errno == ENOBUFS)
+ errno = EAGAIN;
+ return (-1);
+ }
+
+ if (n == 0) { /* connection closed */
+ errno = 0;
+ return (0);
+ }
+
+ /*
+ * assumption: fd got sent if sendmsg sent anything
+ * this works because fds are passed one at a time
+ */
+ if (buf != NULL && buf->fd != -1) {
+ close(buf->fd);
+ buf->fd = -1;
+ }
+
+ msgbuf_drain(msgbuf, n);
+
+ return (1);
+}
+
+void
+ibuf_enqueue(struct msgbuf *msgbuf, struct ibuf *buf)
+{
+ TAILQ_INSERT_TAIL(&msgbuf->bufs, buf, entry);
+ msgbuf->queued++;
+}
+
+void
+ibuf_dequeue(struct msgbuf *msgbuf, struct ibuf *buf)
+{
+ TAILQ_REMOVE(&msgbuf->bufs, buf, entry);
+
+ if (buf->fd != -1)
+ close(buf->fd);
+
+ msgbuf->queued--;
+ ibuf_free(buf);
+}
diff --git a/lib/imsg.c b/lib/imsg.c
new file mode 100644
index 000000000..246430cdd
--- /dev/null
+++ b/lib/imsg.c
@@ -0,0 +1,334 @@
+/* $OpenBSD$ */
+
+/*
+ * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <zebra.h>
+
+#include "openbsd-queue.h"
+#include "imsg.h"
+
+int imsg_fd_overhead = 0;
+
+int imsg_get_fd(struct imsgbuf *);
+
+#ifndef __OpenBSD__
+/*
+ * The original code calls getdtablecount() which is OpenBSD specific. Use
+ * available_fds() from OpenSMTPD instead.
+ */
+static int
+available_fds(unsigned int n)
+{
+ unsigned int i;
+ int ret, fds[256];
+
+ if (n > (sizeof(fds)/sizeof(fds[0])))
+ return (1);
+
+ ret = 0;
+ for (i = 0; i < n; i++) {
+ fds[i] = -1;
+ if ((fds[i] = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ if (errno == EAFNOSUPPORT || errno == EPROTONOSUPPORT)
+ fds[i] = socket(AF_INET6, SOCK_DGRAM, 0);
+ if (fds[i] < 0) {
+ ret = 1;
+ break;
+ }
+ }
+ }
+
+ for (i = 0; i < n && fds[i] >= 0; i++)
+ close(fds[i]);
+
+ return (ret);
+}
+#endif
+
+void
+imsg_init(struct imsgbuf *ibuf, int fd)
+{
+ msgbuf_init(&ibuf->w);
+ memset(&ibuf->r, 0, sizeof(ibuf->r));
+ ibuf->fd = fd;
+ ibuf->w.fd = fd;
+ ibuf->pid = getpid();
+ TAILQ_INIT(&ibuf->fds);
+}
+
+ssize_t
+imsg_read(struct imsgbuf *ibuf)
+{
+ struct msghdr msg;
+ struct cmsghdr *cmsg;
+ union {
+ struct cmsghdr hdr;
+ char buf[CMSG_SPACE(sizeof(int) * 1)];
+ } cmsgbuf;
+ struct iovec iov;
+ ssize_t n = -1;
+ int fd;
+ struct imsg_fd *ifd;
+
+ memset(&msg, 0, sizeof(msg));
+ memset(&cmsgbuf, 0, sizeof(cmsgbuf));
+
+ iov.iov_base = ibuf->r.buf + ibuf->r.wpos;
+ iov.iov_len = sizeof(ibuf->r.buf) - ibuf->r.wpos;
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ msg.msg_control = &cmsgbuf.buf;
+ msg.msg_controllen = sizeof(cmsgbuf.buf);
+
+ if ((ifd = calloc(1, sizeof(struct imsg_fd))) == NULL)
+ return (-1);
+
+again:
+#ifdef __OpenBSD__
+ if (getdtablecount() + imsg_fd_overhead +
+ (int)((CMSG_SPACE(sizeof(int))-CMSG_SPACE(0))/sizeof(int))
+ >= getdtablesize()) {
+#else
+ if (available_fds(imsg_fd_overhead +
+ (CMSG_SPACE(sizeof(int))-CMSG_SPACE(0))/sizeof(int))) {
+#endif
+ errno = EAGAIN;
+ free(ifd);
+ return (-1);
+ }
+
+ if ((n = recvmsg(ibuf->fd, &msg, 0)) == -1) {
+ if (errno == EINTR)
+ goto again;
+ goto fail;
+ }
+
+ ibuf->r.wpos += n;
+
+ for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
+ cmsg = CMSG_NXTHDR(&msg, cmsg)) {
+ if (cmsg->cmsg_level == SOL_SOCKET &&
+ cmsg->cmsg_type == SCM_RIGHTS) {
+ int i;
+ int j;
+
+ /*
+ * We only accept one file descriptor. Due to C
+ * padding rules, our control buffer might contain
+ * more than one fd, and we must close them.
+ */
+ j = ((char *)cmsg + cmsg->cmsg_len -
+ (char *)CMSG_DATA(cmsg)) / sizeof(int);
+ for (i = 0; i < j; i++) {
+ fd = ((int *)CMSG_DATA(cmsg))[i];
+ if (ifd != NULL) {
+ ifd->fd = fd;
+ TAILQ_INSERT_TAIL(&ibuf->fds, ifd,
+ entry);
+ ifd = NULL;
+ } else
+ close(fd);
+ }
+ }
+ /* we do not handle other ctl data level */
+ }
+
+fail:
+ free(ifd);
+ return (n);
+}
+
+ssize_t
+imsg_get(struct imsgbuf *ibuf, struct imsg *imsg)
+{
+ size_t av, left, datalen;
+
+ av = ibuf->r.wpos;
+
+ if (IMSG_HEADER_SIZE > av)
+ return (0);
+
+ memcpy(&imsg->hdr, ibuf->r.buf, sizeof(imsg->hdr));
+ if (imsg->hdr.len < IMSG_HEADER_SIZE ||
+ imsg->hdr.len > MAX_IMSGSIZE) {
+ errno = ERANGE;
+ return (-1);
+ }
+ if (imsg->hdr.len > av)
+ return (0);
+ datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
+ ibuf->r.rptr = ibuf->r.buf + IMSG_HEADER_SIZE;
+ if (datalen == 0)
+ imsg->data = NULL;
+ else if ((imsg->data = malloc(datalen)) == NULL)
+ return (-1);
+
+ if (imsg->hdr.flags & IMSGF_HASFD)
+ imsg->fd = imsg_get_fd(ibuf);
+ else
+ imsg->fd = -1;
+
+ memcpy(imsg->data, ibuf->r.rptr, datalen);
+
+ if (imsg->hdr.len < av) {
+ left = av - imsg->hdr.len;
+ memmove(&ibuf->r.buf, ibuf->r.buf + imsg->hdr.len, left);
+ ibuf->r.wpos = left;
+ } else
+ ibuf->r.wpos = 0;
+
+ return (datalen + IMSG_HEADER_SIZE);
+}
+
+int
+imsg_compose(struct imsgbuf *ibuf, u_int32_t type, u_int32_t peerid,
+ pid_t pid, int fd, const void *data, u_int16_t datalen)
+{
+ struct ibuf *wbuf;
+
+ if ((wbuf = imsg_create(ibuf, type, peerid, pid, datalen)) == NULL)
+ return (-1);
+
+ if (imsg_add(wbuf, data, datalen) == -1)
+ return (-1);
+
+ wbuf->fd = fd;
+
+ imsg_close(ibuf, wbuf);
+
+ return (1);
+}
+
+int
+imsg_composev(struct imsgbuf *ibuf, u_int32_t type, u_int32_t peerid,
+ pid_t pid, int fd, const struct iovec *iov, int iovcnt)
+{
+ struct ibuf *wbuf;
+ int i, datalen = 0;
+
+ for (i = 0; i < iovcnt; i++)
+ datalen += iov[i].iov_len;
+
+ if ((wbuf = imsg_create(ibuf, type, peerid, pid, datalen)) == NULL)
+ return (-1);
+
+ for (i = 0; i < iovcnt; i++)
+ if (imsg_add(wbuf, iov[i].iov_base, iov[i].iov_len) == -1)
+ return (-1);
+
+ wbuf->fd = fd;
+
+ imsg_close(ibuf, wbuf);
+
+ return (1);
+}
+
+/* ARGSUSED */
+struct ibuf *
+imsg_create(struct imsgbuf *ibuf, u_int32_t type, u_int32_t peerid,
+ pid_t pid, u_int16_t datalen)
+{
+ struct ibuf *wbuf;
+ struct imsg_hdr hdr;
+
+ datalen += IMSG_HEADER_SIZE;
+ if (datalen > MAX_IMSGSIZE) {
+ errno = ERANGE;
+ return (NULL);
+ }
+
+ hdr.type = type;
+ hdr.flags = 0;
+ hdr.peerid = peerid;
+ if ((hdr.pid = pid) == 0)
+ hdr.pid = ibuf->pid;
+ if ((wbuf = ibuf_dynamic(datalen, MAX_IMSGSIZE)) == NULL) {
+ return (NULL);
+ }
+ if (imsg_add(wbuf, &hdr, sizeof(hdr)) == -1)
+ return (NULL);
+
+ return (wbuf);
+}
+
+int
+imsg_add(struct ibuf *msg, const void *data, u_int16_t datalen)
+{
+ if (datalen)
+ if (ibuf_add(msg, data, datalen) == -1) {
+ ibuf_free(msg);
+ return (-1);
+ }
+ return (datalen);
+}
+
+void
+imsg_close(struct imsgbuf *ibuf, struct ibuf *msg)
+{
+ struct imsg_hdr *hdr;
+
+ hdr = (struct imsg_hdr *)msg->buf;
+
+ hdr->flags &= ~IMSGF_HASFD;
+ if (msg->fd != -1)
+ hdr->flags |= IMSGF_HASFD;
+
+ hdr->len = (u_int16_t)msg->wpos;
+
+ ibuf_close(&ibuf->w, msg);
+}
+
+void
+imsg_free(struct imsg *imsg)
+{
+ free(imsg->data);
+}
+
+int
+imsg_get_fd(struct imsgbuf *ibuf)
+{
+ int fd;
+ struct imsg_fd *ifd;
+
+ if ((ifd = TAILQ_FIRST(&ibuf->fds)) == NULL)
+ return (-1);
+
+ fd = ifd->fd;
+ TAILQ_REMOVE(&ibuf->fds, ifd, entry);
+ free(ifd);
+
+ return (fd);
+}
+
+int
+imsg_flush(struct imsgbuf *ibuf)
+{
+ while (ibuf->w.queued)
+ if (msgbuf_write(&ibuf->w) <= 0)
+ return (-1);
+ return (0);
+}
+
+void
+imsg_clear(struct imsgbuf *ibuf)
+{
+ int fd;
+
+ msgbuf_clear(&ibuf->w);
+ while ((fd = imsg_get_fd(ibuf)) != -1)
+ close(fd);
+}
diff --git a/lib/imsg.h b/lib/imsg.h
new file mode 100644
index 000000000..d053d0195
--- /dev/null
+++ b/lib/imsg.h
@@ -0,0 +1,112 @@
+/* $OpenBSD$ */
+
+/*
+ * Copyright (c) 2006, 2007 Pierre-Yves Ritschard <pyr@openbsd.org>
+ * Copyright (c) 2006, 2007, 2008 Reyk Floeter <reyk@openbsd.org>
+ * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _IMSG_H_
+#define _IMSG_H_
+
+#define IBUF_READ_SIZE 65535
+#define IMSG_HEADER_SIZE sizeof(struct imsg_hdr)
+#define MAX_IMSGSIZE 16384
+
+struct ibuf {
+ TAILQ_ENTRY(ibuf) entry;
+ u_char *buf;
+ size_t size;
+ size_t max;
+ size_t wpos;
+ size_t rpos;
+ int fd;
+};
+
+struct msgbuf {
+ TAILQ_HEAD(, ibuf) bufs;
+ u_int32_t queued;
+ int fd;
+};
+
+struct ibuf_read {
+ u_char buf[IBUF_READ_SIZE];
+ u_char *rptr;
+ size_t wpos;
+};
+
+struct imsg_fd {
+ TAILQ_ENTRY(imsg_fd) entry;
+ int fd;
+};
+
+struct imsgbuf {
+ TAILQ_HEAD(, imsg_fd) fds;
+ struct ibuf_read r;
+ struct msgbuf w;
+ int fd;
+ pid_t pid;
+};
+
+#define IMSGF_HASFD 1
+
+struct imsg_hdr {
+ u_int32_t type;
+ u_int16_t len;
+ u_int16_t flags;
+ u_int32_t peerid;
+ u_int32_t pid;
+};
+
+struct imsg {
+ struct imsg_hdr hdr;
+ int fd;
+ void *data;
+};
+
+
+/* buffer.c */
+struct ibuf *ibuf_open(size_t);
+struct ibuf *ibuf_dynamic(size_t, size_t);
+int ibuf_add(struct ibuf *, const void *, size_t);
+void *ibuf_reserve(struct ibuf *, size_t);
+void *ibuf_seek(struct ibuf *, size_t, size_t);
+size_t ibuf_size(struct ibuf *);
+size_t ibuf_left(struct ibuf *);
+void ibuf_close(struct msgbuf *, struct ibuf *);
+int ibuf_write(struct msgbuf *);
+void ibuf_free(struct ibuf *);
+void msgbuf_init(struct msgbuf *);
+void msgbuf_clear(struct msgbuf *);
+int msgbuf_write(struct msgbuf *);
+void msgbuf_drain(struct msgbuf *, size_t);
+
+/* imsg.c */
+void imsg_init(struct imsgbuf *, int);
+ssize_t imsg_read(struct imsgbuf *);
+ssize_t imsg_get(struct imsgbuf *, struct imsg *);
+int imsg_compose(struct imsgbuf *, u_int32_t, u_int32_t, pid_t,
+ int, const void *, u_int16_t);
+int imsg_composev(struct imsgbuf *, u_int32_t, u_int32_t, pid_t,
+ int, const struct iovec *, int);
+struct ibuf *imsg_create(struct imsgbuf *, u_int32_t, u_int32_t, pid_t,
+ u_int16_t);
+int imsg_add(struct ibuf *, const void *, u_int16_t);
+void imsg_close(struct imsgbuf *, struct ibuf *);
+void imsg_free(struct imsg *);
+int imsg_flush(struct imsgbuf *);
+void imsg_clear(struct imsgbuf *);
+
+#endif
diff --git a/lib/json.h b/lib/json.h
index 3fcfe340e..e3d73d9d8 100644
--- a/lib/json.h
+++ b/lib/json.h
@@ -26,6 +26,12 @@
#include <json-c/json.h>
#else
#include <json/json.h>
+
+/*
+ * json_object_to_json_string_ext is only available for json-c
+ * so let's just turn it back to the original usage.
+ */
+#define json_object_to_json_string_ext(A, B) json_object_to_json_string (A)
#endif
extern int use_json(const int argc, struct cmd_token *argv[]);
diff --git a/lib/keychain.c b/lib/keychain.c
index c2d6e4571..f8a3ffc01 100644
--- a/lib/keychain.c
+++ b/lib/keychain.c
@@ -28,30 +28,40 @@ Boston, MA 02111-1307, USA. */
DEFINE_MTYPE_STATIC(LIB, KEY, "Key")
DEFINE_MTYPE_STATIC(LIB, KEYCHAIN, "Key chain")
+DEFINE_QOBJ_TYPE(keychain)
+DEFINE_QOBJ_TYPE(key)
+
/* Master list of key chain. */
struct list *keychain_list;
static struct keychain *
keychain_new (void)
{
- return XCALLOC (MTYPE_KEYCHAIN, sizeof (struct keychain));
+ struct keychain *keychain;
+ keychain = XCALLOC (MTYPE_KEYCHAIN, sizeof (struct keychain));
+ QOBJ_REG (keychain, keychain);
+ return keychain;
}
static void
keychain_free (struct keychain *keychain)
{
+ QOBJ_UNREG (keychain);
XFREE (MTYPE_KEYCHAIN, keychain);
}
static struct key *
key_new (void)
{
- return XCALLOC (MTYPE_KEY, sizeof (struct key));
+ struct key *key = XCALLOC (MTYPE_KEY, sizeof (struct key));
+ QOBJ_REG (key, key);
+ return key;
}
static void
key_free (struct key *key)
{
+ QOBJ_UNREG (key);
XFREE (MTYPE_KEY, key);
}
@@ -241,8 +251,7 @@ DEFUN (key_chain,
struct keychain *keychain;
keychain = keychain_get (argv[idx_word]->arg);
- vty->index = keychain;
- vty->node = KEYCHAIN_NODE;
+ VTY_PUSH_CONTEXT_COMPAT (KEYCHAIN_NODE, keychain);
return CMD_SUCCESS;
}
@@ -278,16 +287,13 @@ DEFUN (key,
"Key identifier number\n")
{
int idx_number = 1;
- struct keychain *keychain;
+ VTY_DECLVAR_CONTEXT (keychain, keychain);
struct key *key;
u_int32_t index;
- keychain = vty->index;
-
VTY_GET_INTEGER ("key identifier", index, argv[idx_number]->arg);
key = key_get (keychain, index);
- vty->index_sub = key;
- vty->node = KEYCHAIN_KEY_NODE;
+ VTY_PUSH_CONTEXT_SUB (KEYCHAIN_KEY_NODE, key);
return CMD_SUCCESS;
}
@@ -300,12 +306,10 @@ DEFUN (no_key,
"Key identifier number\n")
{
int idx_number = 2;
- struct keychain *keychain;
+ VTY_DECLVAR_CONTEXT (keychain, keychain);
struct key *key;
u_int32_t index;
- keychain = vty->index;
-
VTY_GET_INTEGER ("key identifier", index, argv[idx_number]->arg);
key = key_lookup (keychain, index);
if (! key)
@@ -328,9 +332,7 @@ DEFUN (key_string,
"The key\n")
{
int idx_line = 1;
- struct key *key;
-
- key = vty->index_sub;
+ VTY_DECLVAR_CONTEXT_SUB (key, key);
if (key->string)
XFREE(MTYPE_KEY, key->string);
@@ -346,9 +348,7 @@ DEFUN (no_key_string,
"Unset key string\n"
"The key\n")
{
- struct key *key;
-
- key = vty->index_sub;
+ VTY_DECLVAR_CONTEXT_SUB (key, key);
if (key->string)
{
@@ -565,9 +565,7 @@ DEFUN (accept_lifetime_day_month_day_month,
int idx_number_3 = 6;
int idx_month_2 = 7;
int idx_number_4 = 8;
- struct key *key;
-
- key = vty->index_sub;
+ VTY_DECLVAR_CONTEXT_SUB (key, key);
return key_lifetime_set (vty, &key->accept, argv[idx_hhmmss]->arg, argv[idx_number]->arg, argv[idx_month]->arg,
argv[idx_number_2]->arg, argv[idx_hhmmss_2]->arg, argv[idx_number_3]->arg, argv[idx_month_2]->arg, argv[idx_number_4]->arg);
@@ -594,9 +592,7 @@ DEFUN (accept_lifetime_day_month_month_day,
int idx_month_2 = 6;
int idx_number_3 = 7;
int idx_number_4 = 8;
- struct key *key;
-
- key = vty->index_sub;
+ VTY_DECLVAR_CONTEXT_SUB (key, key);
return key_lifetime_set (vty, &key->accept, argv[idx_hhmmss]->arg, argv[idx_number]->arg, argv[idx_month]->arg,
argv[idx_number_2]->arg, argv[idx_hhmmss_2]->arg, argv[idx_number_3]->arg, argv[idx_month_2]->arg, argv[idx_number_4]->arg);
@@ -623,9 +619,7 @@ DEFUN (accept_lifetime_month_day_day_month,
int idx_number_3 = 6;
int idx_month_2 = 7;
int idx_number_4 = 8;
- struct key *key;
-
- key = vty->index_sub;
+ VTY_DECLVAR_CONTEXT_SUB (key, key);
return key_lifetime_set (vty, &key->accept, argv[idx_hhmmss]->arg, argv[idx_number]->arg, argv[idx_month]->arg,
argv[idx_number_2]->arg, argv[idx_hhmmss_2]->arg, argv[idx_number_3]->arg, argv[idx_month_2]->arg, argv[idx_number_4]->arg);
@@ -652,9 +646,7 @@ DEFUN (accept_lifetime_month_day_month_day,
int idx_month_2 = 6;
int idx_number_3 = 7;
int idx_number_4 = 8;
- struct key *key;
-
- key = vty->index_sub;
+ VTY_DECLVAR_CONTEXT_SUB (key, key);
return key_lifetime_set (vty, &key->accept, argv[idx_hhmmss]->arg, argv[idx_number]->arg, argv[idx_month]->arg,
argv[idx_number_2]->arg, argv[idx_hhmmss_2]->arg, argv[idx_number_3]->arg, argv[idx_month_2]->arg, argv[idx_number_4]->arg);
@@ -674,9 +666,7 @@ DEFUN (accept_lifetime_infinite_day_month,
int idx_number = 2;
int idx_month = 3;
int idx_number_2 = 4;
- struct key *key;
-
- key = vty->index_sub;
+ VTY_DECLVAR_CONTEXT_SUB (key, key);
return key_lifetime_infinite_set (vty, &key->accept, argv[idx_hhmmss]->arg, argv[idx_number]->arg,
argv[idx_month]->arg, argv[idx_number_2]->arg);
@@ -696,9 +686,7 @@ DEFUN (accept_lifetime_infinite_month_day,
int idx_month = 2;
int idx_number = 3;
int idx_number_2 = 4;
- struct key *key;
-
- key = vty->index_sub;
+ VTY_DECLVAR_CONTEXT_SUB (key, key);
return key_lifetime_infinite_set (vty, &key->accept, argv[idx_hhmmss]->arg, argv[idx_number]->arg,
argv[idx_month]->arg, argv[idx_number_2]->arg);
@@ -720,9 +708,7 @@ DEFUN (accept_lifetime_duration_day_month,
int idx_month = 3;
int idx_number_2 = 4;
int idx_number_3 = 6;
- struct key *key;
-
- key = vty->index_sub;
+ VTY_DECLVAR_CONTEXT_SUB (key, key);
return key_lifetime_duration_set (vty, &key->accept, argv[idx_hhmmss]->arg, argv[idx_number]->arg,
argv[idx_month]->arg, argv[idx_number_2]->arg, argv[idx_number_3]->arg);
@@ -744,9 +730,7 @@ DEFUN (accept_lifetime_duration_month_day,
int idx_number = 3;
int idx_number_2 = 4;
int idx_number_3 = 6;
- struct key *key;
-
- key = vty->index_sub;
+ VTY_DECLVAR_CONTEXT_SUB (key, key);
return key_lifetime_duration_set (vty, &key->accept, argv[idx_hhmmss]->arg, argv[idx_number]->arg,
argv[idx_month]->arg, argv[idx_number_2]->arg, argv[idx_number_3]->arg);
@@ -773,9 +757,7 @@ DEFUN (send_lifetime_day_month_day_month,
int idx_number_3 = 6;
int idx_month_2 = 7;
int idx_number_4 = 8;
- struct key *key;
-
- key = vty->index_sub;
+ VTY_DECLVAR_CONTEXT_SUB (key, key);
return key_lifetime_set (vty, &key->send, argv[idx_hhmmss]->arg, argv[idx_number]->arg, argv[idx_month]->arg, argv[idx_number_2]->arg,
argv[idx_hhmmss_2]->arg, argv[idx_number_3]->arg, argv[idx_month_2]->arg, argv[idx_number_4]->arg);
@@ -802,9 +784,7 @@ DEFUN (send_lifetime_day_month_month_day,
int idx_month_2 = 6;
int idx_number_3 = 7;
int idx_number_4 = 8;
- struct key *key;
-
- key = vty->index_sub;
+ VTY_DECLVAR_CONTEXT_SUB (key, key);
return key_lifetime_set (vty, &key->send, argv[idx_hhmmss]->arg, argv[idx_number]->arg, argv[idx_month]->arg, argv[idx_number_2]->arg,
argv[idx_hhmmss_2]->arg, argv[idx_number_3]->arg, argv[idx_month_2]->arg, argv[idx_number_4]->arg);
@@ -831,9 +811,7 @@ DEFUN (send_lifetime_month_day_day_month,
int idx_number_3 = 6;
int idx_month_2 = 7;
int idx_number_4 = 8;
- struct key *key;
-
- key = vty->index_sub;
+ VTY_DECLVAR_CONTEXT_SUB (key, key);
return key_lifetime_set (vty, &key->send, argv[idx_hhmmss]->arg, argv[idx_number]->arg, argv[idx_month]->arg, argv[idx_number_2]->arg,
argv[idx_hhmmss_2]->arg, argv[idx_number_3]->arg, argv[idx_month_2]->arg, argv[idx_number_4]->arg);
@@ -860,9 +838,7 @@ DEFUN (send_lifetime_month_day_month_day,
int idx_month_2 = 6;
int idx_number_3 = 7;
int idx_number_4 = 8;
- struct key *key;
-
- key = vty->index_sub;
+ VTY_DECLVAR_CONTEXT_SUB (key, key);
return key_lifetime_set (vty, &key->send, argv[idx_hhmmss]->arg, argv[idx_number]->arg, argv[idx_month]->arg, argv[idx_number_2]->arg,
argv[idx_hhmmss_2]->arg, argv[idx_number_3]->arg, argv[idx_month_2]->arg, argv[idx_number_4]->arg);
@@ -882,9 +858,7 @@ DEFUN (send_lifetime_infinite_day_month,
int idx_number = 2;
int idx_month = 3;
int idx_number_2 = 4;
- struct key *key;
-
- key = vty->index_sub;
+ VTY_DECLVAR_CONTEXT_SUB (key, key);
return key_lifetime_infinite_set (vty, &key->send, argv[idx_hhmmss]->arg, argv[idx_number]->arg, argv[idx_month]->arg,
argv[idx_number_2]->arg);
@@ -904,9 +878,7 @@ DEFUN (send_lifetime_infinite_month_day,
int idx_month = 2;
int idx_number = 3;
int idx_number_2 = 4;
- struct key *key;
-
- key = vty->index_sub;
+ VTY_DECLVAR_CONTEXT_SUB (key, key);
return key_lifetime_infinite_set (vty, &key->send, argv[idx_hhmmss]->arg, argv[idx_number]->arg, argv[idx_month]->arg,
argv[idx_number_2]->arg);
@@ -928,9 +900,7 @@ DEFUN (send_lifetime_duration_day_month,
int idx_month = 3;
int idx_number_2 = 4;
int idx_number_3 = 6;
- struct key *key;
-
- key = vty->index_sub;
+ VTY_DECLVAR_CONTEXT_SUB (key, key);
return key_lifetime_duration_set (vty, &key->send, argv[idx_hhmmss]->arg, argv[idx_number]->arg, argv[idx_month]->arg,
argv[idx_number_2]->arg, argv[idx_number_3]->arg);
@@ -952,9 +922,7 @@ DEFUN (send_lifetime_duration_month_day,
int idx_number = 3;
int idx_number_2 = 4;
int idx_number_3 = 6;
- struct key *key;
-
- key = vty->index_sub;
+ VTY_DECLVAR_CONTEXT_SUB (key, key);
return key_lifetime_duration_set (vty, &key->send, argv[idx_hhmmss]->arg, argv[idx_number]->arg, argv[idx_month]->arg,
argv[idx_number_2]->arg, argv[idx_number_3]->arg);
diff --git a/lib/keychain.h b/lib/keychain.h
index f962864c5..d3f9168a0 100644
--- a/lib/keychain.h
+++ b/lib/keychain.h
@@ -22,12 +22,17 @@
#ifndef _ZEBRA_KEYCHAIN_H
#define _ZEBRA_KEYCHAIN_H
+#include "qobj.h"
+
struct keychain
{
char *name;
struct list *key;
+
+ QOBJ_FIELDS
};
+DECLARE_QOBJ_TYPE(keychain)
struct key_range
{
@@ -45,7 +50,10 @@ struct key
struct key_range send;
struct key_range accept;
+
+ QOBJ_FIELDS
};
+DECLARE_QOBJ_TYPE(key)
extern void keychain_init (void);
extern struct keychain *keychain_lookup (const char *);
diff --git a/lib/log.c b/lib/log.c
index b9edb12fb..cd1f0bb77 100644
--- a/lib/log.c
+++ b/lib/log.c
@@ -41,6 +41,10 @@ static int logfile_fd = -1; /* Used in signal handler. */
struct zlog *zlog_default = NULL;
+/*
+ * This must be kept in the same order as the
+ * zlog_proto_t enum
+ */
const char *zlog_proto_names[] =
{
"NONE",
@@ -51,9 +55,10 @@ const char *zlog_proto_names[] =
"OSPF",
"RIPNG",
"OSPF6",
+ "LDP",
"ISIS",
"PIM",
- "MASC",
+ "RFP",
NULL,
};
@@ -177,7 +182,7 @@ time_print(FILE *fp, struct timestamp_control *ctl)
/* va_list version of zlog. */
-static void
+void
vzlog (struct zlog *zl, int priority, const char *format, va_list args)
{
char proto_str[32];
@@ -257,6 +262,44 @@ vzlog (struct zlog *zl, int priority, const char *format, va_list args)
errno = original_errno;
}
+int
+vzlog_test (struct zlog *zl, int priority)
+{
+ /* If zlog is not specified, use default one. */
+ if (zl == NULL)
+ zl = zlog_default;
+
+ /* When zlog_default is also NULL, use stderr for logging. */
+ if (zl == NULL)
+ {
+ return 1;
+ }
+
+ /* Syslog output */
+ if (priority <= zl->maxlvl[ZLOG_DEST_SYSLOG])
+ {
+ return 1;
+ }
+
+ /* File output. */
+ if ((priority <= zl->maxlvl[ZLOG_DEST_FILE]) && zl->fp)
+ {
+ return 1;
+ }
+
+ /* stdout output. */
+ if (priority <= zl->maxlvl[ZLOG_DEST_STDOUT])
+ {
+ return 1;
+ }
+
+ /* Terminal monitor. */
+ if (priority <= zl->maxlvl[ZLOG_DEST_MONITOR])
+ return 1;
+
+ return 0;
+}
+
static char *
str_append(char *dst, int len, const char *src)
{
@@ -679,6 +722,7 @@ _zlog_assert_failed (const char *assertion, const char *file,
assertion,file,line,(function ? function : "?"));
zlog_backtrace(LOG_CRIT);
zlog_thread_info(LOG_CRIT);
+ log_memstats_stderr ("log");
abort();
}
@@ -938,6 +982,12 @@ static const struct zebra_desc_table command_types[] = {
DESC_ENTRY (ZEBRA_INTERFACE_ENABLE_RADV),
DESC_ENTRY (ZEBRA_INTERFACE_DISABLE_RADV),
DESC_ENTRY (ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB),
+ DESC_ENTRY (ZEBRA_MPLS_LABELS_ADD),
+ DESC_ENTRY (ZEBRA_MPLS_LABELS_DELETE),
+ DESC_ENTRY (ZEBRA_IPV4_NEXTHOP_ADD),
+ DESC_ENTRY (ZEBRA_IPV4_NEXTHOP_DELETE),
+ DESC_ENTRY (ZEBRA_IPV6_NEXTHOP_ADD),
+ DESC_ENTRY (ZEBRA_IPV6_NEXTHOP_DELETE),
};
#undef DESC_ENTRY
@@ -1026,6 +1076,10 @@ proto_redistnum(int afi, const char *s)
return ZEBRA_ROUTE_BGP;
else if (strncmp (s, "ta", 2) == 0)
return ZEBRA_ROUTE_TABLE;
+ else if (strncmp (s, "v", 1) == 0)
+ return ZEBRA_ROUTE_VNC;
+ else if (strncmp (s, "vd", 1) == 0)
+ return ZEBRA_ROUTE_VNC_DIRECT;
}
if (afi == AFI_IP6)
{
@@ -1045,6 +1099,10 @@ proto_redistnum(int afi, const char *s)
return ZEBRA_ROUTE_BGP;
else if (strncmp (s, "ta", 2) == 0)
return ZEBRA_ROUTE_TABLE;
+ else if (strncmp (s, "v", 1) == 0)
+ return ZEBRA_ROUTE_VNC;
+ else if (strncmp (s, "vd", 1) == 0)
+ return ZEBRA_ROUTE_VNC_DIRECT;
}
return -1;
}
diff --git a/lib/log.h b/lib/log.h
index b5edc75f1..cd4cd1495 100644
--- a/lib/log.h
+++ b/lib/log.h
@@ -41,6 +41,10 @@
* please use LOG_ERR instead.
*/
+/*
+ * This must be kept in the same order as
+ * zlog_proto_names[]
+ */
typedef enum
{
ZLOG_NONE,
@@ -51,9 +55,10 @@ typedef enum
ZLOG_OSPF,
ZLOG_RIPNG,
ZLOG_OSPF6,
+ ZLOG_LDP,
ZLOG_ISIS,
ZLOG_PIM,
- ZLOG_MASC
+ ZLOG_RFP,
} zlog_proto_t;
/* If maxlvl is set to ZLOG_DISABLED, then no messages will be sent
@@ -115,12 +120,15 @@ extern void zlog (struct zlog *zl, int priority, const char *format, ...)
PRINTF_ATTRIBUTE(3, 4);
/* Handy zlog functions. */
+extern void vzlog (struct zlog *zl, int priority, const char *format, va_list args);
extern void zlog_err (const char *format, ...) PRINTF_ATTRIBUTE(1, 2);
extern void zlog_warn (const char *format, ...) PRINTF_ATTRIBUTE(1, 2);
extern void zlog_info (const char *format, ...) PRINTF_ATTRIBUTE(1, 2);
extern void zlog_notice (const char *format, ...) PRINTF_ATTRIBUTE(1, 2);
extern void zlog_debug (const char *format, ...) PRINTF_ATTRIBUTE(1, 2);
+extern void vzlog (struct zlog *, int , const char *, va_list );
+
extern void zlog_thread_info (int log_level);
/* Set logging level for the given destination. If the log_level
@@ -180,6 +188,10 @@ extern size_t quagga_timestamp(int timestamp_precision /* # subsecond digits */,
extern void zlog_hexdump(const void *mem, unsigned int len);
+
+extern int
+vzlog_test (struct zlog *zl, int priority);
+
/* structure useful for avoiding repeated rendering of the same timestamp */
struct timestamp_control {
size_t len; /* length of rendered timestamp */
diff --git a/lib/memory.c b/lib/memory.c
index 38e424da7..99b191c2b 100644
--- a/lib/memory.c
+++ b/lib/memory.c
@@ -134,7 +134,7 @@ qmem_exit_walker (void *arg, struct memgroup *mg, struct memtype *mt)
char size[32];
eda->error++;
snprintf (size, sizeof (size), "%10zu", mt->size);
- fprintf (stderr, "%s: %-30s: %6zu * %s\n",
+ fprintf (stderr, "%s: memstats: %-30s: %6zu * %s\n",
eda->prefix, mt->name, mt->n_alloc,
mt->size == SIZE_VAR ? "(variably sized)" : size);
}
diff --git a/lib/memory_vty.c b/lib/memory_vty.c
index e4cb295cf..ff0363d45 100644
--- a/lib/memory_vty.c
+++ b/lib/memory_vty.c
@@ -82,13 +82,15 @@ static int qmem_walker(void *arg, struct memgroup *mg, struct memtype *mt)
if (!mt)
vty_out (vty, "--- qmem %s ---%s", mg->name, VTY_NEWLINE);
else {
- char size[32];
- snprintf(size, sizeof(size), "%6zu", mt->size);
- vty_out (vty, "%-30s: %10zu %s%s",
- mt->name, mt->n_alloc,
- mt->size == 0 ? "" :
- mt->size == SIZE_VAR ? "(variably sized)" :
- size, VTY_NEWLINE);
+ if (mt->n_alloc != 0) {
+ char size[32];
+ snprintf(size, sizeof(size), "%6zu", mt->size);
+ vty_out (vty, "%-30s: %10zu %s%s",
+ mt->name, mt->n_alloc,
+ mt->size == 0 ? "" :
+ mt->size == SIZE_VAR ? "(variably sized)" :
+ size, VTY_NEWLINE);
+ }
}
return 0;
}
@@ -111,11 +113,7 @@ DEFUN (show_memory,
void
memory_init (void)
{
- install_element (RESTRICTED_NODE, &show_memory_cmd);
-
install_element (VIEW_NODE, &show_memory_cmd);
-
- install_element (ENABLE_NODE, &show_memory_cmd);
}
/* Stats querying from users */
diff --git a/lib/mpls.h b/lib/mpls.h
new file mode 100644
index 000000000..1f77aaa53
--- /dev/null
+++ b/lib/mpls.h
@@ -0,0 +1,190 @@
+/*
+ * MPLS definitions
+ * Copyright 2015 Cumulus Networks, Inc.
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _QUAGGA_MPLS_H
+#define _QUAGGA_MPLS_H
+
+/* Well-known MPLS label values (RFC 3032 etc). */
+#define MPLS_V4_EXP_NULL_LABEL 0
+#define MPLS_RA_LABEL 1
+#define MPLS_V6_EXP_NULL_LABEL 2
+#define MPLS_IMP_NULL_LABEL 3
+#define MPLS_ENTROPY_LABEL_INDICATOR 7
+#define MPLS_GAL_LABEL 13
+#define MPLS_OAM_ALERT_LABEL 14
+#define MPLS_EXTENSION_LABEL 15
+
+/* Minimum and maximum label values */
+#define MPLS_MIN_RESERVED_LABEL 0
+#define MPLS_MAX_RESERVED_LABEL 15
+#define MPLS_MIN_UNRESERVED_LABEL 16
+#define MPLS_MAX_UNRESERVED_LABEL 1048575
+
+#define IS_MPLS_RESERVED_LABEL(label) \
+ (label >= MPLS_MIN_RESERVED_LABEL && label <= MPLS_MAX_RESERVED_LABEL)
+
+#define IS_MPLS_UNRESERVED_LABEL(label) \
+ (label >= MPLS_MIN_UNRESERVED_LABEL && label <= MPLS_MAX_UNRESERVED_LABEL)
+
+/* Definitions for a MPLS label stack entry (RFC 3032). This encodes the
+ * label, EXP, BOS and TTL fields.
+ */
+typedef unsigned int mpls_lse_t;
+
+#define MPLS_LS_LABEL_MASK 0xFFFFF000
+#define MPLS_LS_LABEL_SHIFT 12
+#define MPLS_LS_EXP_MASK 0x00000E00
+#define MPLS_LS_EXP_SHIFT 9
+#define MPLS_LS_S_MASK 0x00000100
+#define MPLS_LS_S_SHIFT 8
+#define MPLS_LS_TTL_MASK 0x000000FF
+#define MPLS_LS_TTL_SHIFT 0
+
+#define MPLS_LABEL_VALUE(lse) \
+ ((lse & MPLS_LS_LABEL_MASK) >> MPLS_LS_LABEL_SHIFT)
+#define MPLS_LABEL_EXP(lse) \
+ ((lse & MPLS_LS_EXP_MASK) >> MPLS_LS_EXP_SHIFT)
+#define MPLS_LABEL_BOS(lse) \
+ ((lse & MPLS_LS_S_MASK) >> MPLS_LS_S_SHIFT)
+#define MPLS_LABEL_TTL(lse) \
+ ((lse & MPLS_LS_TTL_MASK) >> MPLS_LS_TTL_SHIFT)
+
+#define IS_MPLS_LABEL_BOS(ls) (MPLS_LABEL_BOS(ls) == 1)
+
+#define MPLS_LABEL_LEN_BITS 20
+
+/* MPLS label value as a 32-bit (mostly we only care about the label value). */
+typedef unsigned int mpls_label_t;
+
+#define MPLS_NO_LABEL 0xFFFFFFFF
+#define MPLS_INVALID_LABEL 0xFFFFFFFF
+
+/* LSP types. */
+enum lsp_types_t
+{
+ ZEBRA_LSP_NONE = 0, /* No LSP. */
+ ZEBRA_LSP_STATIC = 1, /* Static LSP. */
+ ZEBRA_LSP_LDP = 2 /* LDP LSP. */
+};
+
+/* Functions for basic label operations. */
+
+/* Encode a label stack entry from fields; convert to network byte-order as
+ * the Netlink interface expects MPLS labels to be in this format.
+ */
+static inline mpls_lse_t
+mpls_lse_encode (mpls_label_t label, u_int32_t ttl,
+ u_int32_t exp, u_int32_t bos)
+{
+ mpls_lse_t lse;
+ lse = htonl ((label << MPLS_LS_LABEL_SHIFT) |
+ (exp << MPLS_LS_EXP_SHIFT) |
+ (bos ? (1 << MPLS_LS_S_SHIFT) : 0) |
+ (ttl << MPLS_LS_TTL_SHIFT));
+ return lse;
+}
+
+/* Extract the fields from a label stack entry after converting to host-byte
+ * order. This is expected to be called only for messages received over the
+ * Netlink interface.
+ */
+static inline void
+mpls_lse_decode (mpls_lse_t lse, mpls_label_t *label,
+ u_int32_t *ttl, u_int32_t *exp, u_int32_t *bos)
+{
+ mpls_lse_t local_lse;
+
+ local_lse = ntohl (lse);
+ *label = MPLS_LABEL_VALUE(local_lse);
+ *exp = MPLS_LABEL_EXP(local_lse);
+ *bos = MPLS_LABEL_BOS(local_lse);
+ *ttl = MPLS_LABEL_TTL(local_lse);
+}
+
+
+/* Printable string for labels (with consideration for reserved values). */
+static inline char *
+label2str (mpls_label_t label, char *buf, int len)
+{
+ switch(label) {
+ case MPLS_V4_EXP_NULL_LABEL:
+ strncpy(buf, "IPv4 Explicit Null", len);
+ return(buf);
+ break;
+ case MPLS_RA_LABEL:
+ strncpy(buf, "Router Alert", len);
+ return(buf);
+ break;
+ case MPLS_V6_EXP_NULL_LABEL:
+ strncpy(buf, "IPv6 Explict Null", len);
+ return(buf);
+ break;
+ case MPLS_IMP_NULL_LABEL:
+ strncpy(buf, "implicit-null", len);
+ return(buf);
+ break;
+ case MPLS_ENTROPY_LABEL_INDICATOR:
+ strncpy(buf, "Entropy Label Indicator", len);
+ return(buf);
+ break;
+ case MPLS_GAL_LABEL:
+ strncpy(buf, "Generic Associated Channel", len);
+ return(buf);
+ break;
+ case MPLS_OAM_ALERT_LABEL:
+ strncpy(buf, "OAM Alert", len);
+ return(buf);
+ break;
+ case MPLS_EXTENSION_LABEL:
+ strncpy(buf, "Extension", len);
+ return(buf);
+ break;
+ case 4:
+ case 5:
+ case 6:
+ case 8:
+ case 9:
+ case 10:
+ case 11:
+ case 12:
+ strncpy(buf, "Reserved", len);
+ return(buf);
+ break;
+ default:
+ sprintf(buf, "%u", label);
+ return(buf);
+ }
+
+ strncpy(buf, "Error", len);
+ return(buf);
+}
+
+/* constants used by ldpd */
+#define MPLS_LABEL_IPV4NULL 0 /* IPv4 Explicit NULL Label */
+#define MPLS_LABEL_RTALERT 1 /* Router Alert Label */
+#define MPLS_LABEL_IPV6NULL 2 /* IPv6 Explicit NULL Label */
+#define MPLS_LABEL_IMPLNULL 3 /* Implicit NULL Label */
+/* MPLS_LABEL_RESERVED 4-15 */ /* Values 4-15 are reserved */
+#define MPLS_LABEL_RESERVED_MAX 15
+#define MPLS_LABEL_MAX ((1 << 20) - 1)
+
+#endif
diff --git a/lib/nexthop.c b/lib/nexthop.c
index 427f77f87..23ee28b7d 100644
--- a/lib/nexthop.c
+++ b/lib/nexthop.c
@@ -32,8 +32,10 @@
#include "thread.h"
#include "prefix.h"
#include "nexthop.h"
+#include "mpls.h"
-DEFINE_MTYPE_STATIC(LIB, NEXTHOP, "Nexthop")
+DEFINE_MTYPE_STATIC(LIB, NEXTHOP, "Nexthop")
+DEFINE_MTYPE_STATIC(LIB, NH_LABEL, "Nexthop label")
/* check if nexthops are same, non-recursive */
int
@@ -127,6 +129,9 @@ copy_nexthops (struct nexthop **tnh, struct nexthop *nh)
nexthop->ifindex = nh->ifindex;
memcpy(&(nexthop->gate), &(nh->gate), sizeof(union g_addr));
memcpy(&(nexthop->src), &(nh->src), sizeof(union g_addr));
+ if (nh->nh_label)
+ nexthop_add_labels (nexthop, nh->nh_label_type,
+ nh->nh_label->num_labels, &nh->nh_label->label[0]);
nexthop_add(tnh, nexthop);
if (CHECK_FLAG(nh1->flags, NEXTHOP_FLAG_RECURSIVE))
@@ -138,6 +143,7 @@ copy_nexthops (struct nexthop **tnh, struct nexthop *nh)
void
nexthop_free (struct nexthop *nexthop)
{
+ nexthop_del_labels (nexthop);
if (nexthop->resolved)
nexthops_free(nexthop->resolved);
XFREE (MTYPE_NEXTHOP, nexthop);
@@ -156,6 +162,34 @@ nexthops_free (struct nexthop *nexthop)
}
}
+/* Update nexthop with label information. */
+void
+nexthop_add_labels (struct nexthop *nexthop, enum lsp_types_t type,
+ u_int8_t num_labels, mpls_label_t *label)
+{
+ struct nexthop_label *nh_label;
+ int i;
+
+ nexthop->nh_label_type = type;
+ nh_label = XCALLOC (MTYPE_NH_LABEL, sizeof (struct nexthop_label) +
+ num_labels * sizeof (mpls_label_t));
+ nh_label->num_labels = num_labels;
+ for (i = 0; i < num_labels; i++)
+ nh_label->label[i] = *(label + i);
+ nexthop->nh_label = nh_label;
+}
+
+/* Free label information of nexthop, if present. */
+void
+nexthop_del_labels (struct nexthop *nexthop)
+{
+ if (nexthop->nh_label)
+ {
+ XFREE (MTYPE_NH_LABEL, nexthop->nh_label);
+ nexthop->nh_label_type = ZEBRA_LSP_NONE;
+ }
+}
+
const char *
nexthop2str (struct nexthop *nexthop, char *str, int size)
{
diff --git a/lib/nexthop.h b/lib/nexthop.h
index 39e8b5425..e66e0eee2 100644
--- a/lib/nexthop.h
+++ b/lib/nexthop.h
@@ -25,6 +25,7 @@
#define _LIB_NEXTHOP_H
#include "prefix.h"
+#include "mpls.h"
/* Maximum next hop string length - gateway + ifindex */
#define NEXTHOP_STRLEN (INET6_ADDRSTRLEN + 30)
@@ -44,6 +45,14 @@ enum nexthop_types_t
NEXTHOP_TYPE_BLACKHOLE, /* Null0 nexthop. */
};
+/* Nexthop label structure. */
+struct nexthop_label
+{
+ u_int8_t num_labels;
+ u_int8_t reserved[3];
+ mpls_label_t label[0]; /* 1 or more labels. */
+};
+
/* Nexthop structure. */
struct nexthop
{
@@ -75,6 +84,12 @@ struct nexthop
* obtained by recursive resolution will be added to `resolved'.
* Only one level of recursive resolution is currently supported. */
struct nexthop *resolved;
+
+ /* Type of label(s), if any */
+ enum lsp_types_t nh_label_type;
+
+ /* Label(s) associated with this nexthop. */
+ struct nexthop_label *nh_label;
};
extern int zebra_rnh_ip_default_route;
@@ -97,6 +112,9 @@ void copy_nexthops (struct nexthop **tnh, struct nexthop *nh);
void nexthop_free (struct nexthop *nexthop);
void nexthops_free (struct nexthop *nexthop);
+void nexthop_add_labels (struct nexthop *, enum lsp_types_t, u_int8_t, mpls_label_t *);
+void nexthop_del_labels (struct nexthop *);
+
extern const char *nexthop_type_to_str (enum nexthop_types_t nh_type);
extern int nexthop_same_no_recurse (struct nexthop *next1, struct nexthop *next2);
diff --git a/lib/openbsd-queue.h b/lib/openbsd-queue.h
new file mode 100644
index 000000000..5e81fdd13
--- /dev/null
+++ b/lib/openbsd-queue.h
@@ -0,0 +1,533 @@
+/* $OpenBSD: queue.h,v 1.43 2015/12/28 19:38:40 millert Exp $ */
+/* $NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $ */
+
+/*
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)queue.h 8.5 (Berkeley) 8/20/94
+ */
+
+#ifndef _SYS_QUEUE_H_
+#define _SYS_QUEUE_H_
+
+/*
+ * This file defines five types of data structures: singly-linked lists,
+ * lists, simple queues, tail queues and XOR simple queues.
+ *
+ *
+ * A singly-linked list is headed by a single forward pointer. The elements
+ * are singly linked for minimum space and pointer manipulation overhead at
+ * the expense of O(n) removal for arbitrary elements. New elements can be
+ * added to the list after an existing element or at the head of the list.
+ * Elements being removed from the head of the list should use the explicit
+ * macro for this purpose for optimum efficiency. A singly-linked list may
+ * only be traversed in the forward direction. Singly-linked lists are ideal
+ * for applications with large datasets and few or no removals or for
+ * implementing a LIFO queue.
+ *
+ * A list is headed by a single forward pointer (or an array of forward
+ * pointers for a hash table header). The elements are doubly linked
+ * so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before
+ * or after an existing element or at the head of the list. A list
+ * may only be traversed in the forward direction.
+ *
+ * A simple queue is headed by a pair of pointers, one to the head of the
+ * list and the other to the tail of the list. The elements are singly
+ * linked to save space, so elements can only be removed from the
+ * head of the list. New elements can be added to the list before or after
+ * an existing element, at the head of the list, or at the end of the
+ * list. A simple queue may only be traversed in the forward direction.
+ *
+ * A tail queue is headed by a pair of pointers, one to the head of the
+ * list and the other to the tail of the list. The elements are doubly
+ * linked so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before or
+ * after an existing element, at the head of the list, or at the end of
+ * the list. A tail queue may be traversed in either direction.
+ *
+ * An XOR simple queue is used in the same way as a regular simple queue.
+ * The difference is that the head structure also includes a "cookie" that
+ * is XOR'd with the queue pointer (first, last or next) to generate the
+ * real pointer value.
+ *
+ * For details on the use of these macros, see the queue(3) manual page.
+ */
+
+#if defined(QUEUE_MACRO_DEBUG) || (defined(_KERNEL) && defined(DIAGNOSTIC))
+#define _Q_INVALIDATE(a) (a) = ((void *)-1)
+#else
+#define _Q_INVALIDATE(a)
+#endif
+
+/*
+ * Singly-linked List definitions.
+ */
+#define SLIST_HEAD(name, type) \
+struct name { \
+ struct type *slh_first; /* first element */ \
+}
+
+#define SLIST_HEAD_INITIALIZER(head) \
+ { NULL }
+
+#define SLIST_ENTRY(type) \
+struct { \
+ struct type *sle_next; /* next element */ \
+}
+
+/*
+ * Singly-linked List access methods.
+ */
+#define SLIST_FIRST(head) ((head)->slh_first)
+#define SLIST_END(head) NULL
+#define SLIST_EMPTY(head) (SLIST_FIRST(head) == SLIST_END(head))
+#define SLIST_NEXT(elm, field) ((elm)->field.sle_next)
+
+#define SLIST_FOREACH(var, head, field) \
+ for((var) = SLIST_FIRST(head); \
+ (var) != SLIST_END(head); \
+ (var) = SLIST_NEXT(var, field))
+
+#define SLIST_FOREACH_SAFE(var, head, field, tvar) \
+ for ((var) = SLIST_FIRST(head); \
+ (var) && ((tvar) = SLIST_NEXT(var, field), 1); \
+ (var) = (tvar))
+
+/*
+ * Singly-linked List functions.
+ */
+#define SLIST_INIT(head) { \
+ SLIST_FIRST(head) = SLIST_END(head); \
+}
+
+#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \
+ (elm)->field.sle_next = (slistelm)->field.sle_next; \
+ (slistelm)->field.sle_next = (elm); \
+} while (0)
+
+#define SLIST_INSERT_HEAD(head, elm, field) do { \
+ (elm)->field.sle_next = (head)->slh_first; \
+ (head)->slh_first = (elm); \
+} while (0)
+
+#define SLIST_REMOVE_AFTER(elm, field) do { \
+ (elm)->field.sle_next = (elm)->field.sle_next->field.sle_next; \
+} while (0)
+
+#define SLIST_REMOVE_HEAD(head, field) do { \
+ (head)->slh_first = (head)->slh_first->field.sle_next; \
+} while (0)
+
+#define SLIST_REMOVE(head, elm, type, field) do { \
+ if ((head)->slh_first == (elm)) { \
+ SLIST_REMOVE_HEAD((head), field); \
+ } else { \
+ struct type *curelm = (head)->slh_first; \
+ \
+ while (curelm->field.sle_next != (elm)) \
+ curelm = curelm->field.sle_next; \
+ curelm->field.sle_next = \
+ curelm->field.sle_next->field.sle_next; \
+ } \
+ _Q_INVALIDATE((elm)->field.sle_next); \
+} while (0)
+
+/*
+ * List definitions.
+ */
+#define LIST_HEAD(name, type) \
+struct name { \
+ struct type *lh_first; /* first element */ \
+}
+
+#define LIST_HEAD_INITIALIZER(head) \
+ { NULL }
+
+#define LIST_ENTRY(type) \
+struct { \
+ struct type *le_next; /* next element */ \
+ struct type **le_prev; /* address of previous next element */ \
+}
+
+/*
+ * List access methods.
+ */
+#define LIST_FIRST(head) ((head)->lh_first)
+#define LIST_END(head) NULL
+#define LIST_EMPTY(head) (LIST_FIRST(head) == LIST_END(head))
+#define LIST_NEXT(elm, field) ((elm)->field.le_next)
+
+#define LIST_FOREACH(var, head, field) \
+ for((var) = LIST_FIRST(head); \
+ (var)!= LIST_END(head); \
+ (var) = LIST_NEXT(var, field))
+
+#define LIST_FOREACH_SAFE(var, head, field, tvar) \
+ for ((var) = LIST_FIRST(head); \
+ (var) && ((tvar) = LIST_NEXT(var, field), 1); \
+ (var) = (tvar))
+
+/*
+ * List functions.
+ */
+#define LIST_INIT(head) do { \
+ LIST_FIRST(head) = LIST_END(head); \
+} while (0)
+
+#define LIST_INSERT_AFTER(listelm, elm, field) do { \
+ if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \
+ (listelm)->field.le_next->field.le_prev = \
+ &(elm)->field.le_next; \
+ (listelm)->field.le_next = (elm); \
+ (elm)->field.le_prev = &(listelm)->field.le_next; \
+} while (0)
+
+#define LIST_INSERT_BEFORE(listelm, elm, field) do { \
+ (elm)->field.le_prev = (listelm)->field.le_prev; \
+ (elm)->field.le_next = (listelm); \
+ *(listelm)->field.le_prev = (elm); \
+ (listelm)->field.le_prev = &(elm)->field.le_next; \
+} while (0)
+
+#define LIST_INSERT_HEAD(head, elm, field) do { \
+ if (((elm)->field.le_next = (head)->lh_first) != NULL) \
+ (head)->lh_first->field.le_prev = &(elm)->field.le_next;\
+ (head)->lh_first = (elm); \
+ (elm)->field.le_prev = &(head)->lh_first; \
+} while (0)
+
+#define LIST_REMOVE(elm, field) do { \
+ if ((elm)->field.le_next != NULL) \
+ (elm)->field.le_next->field.le_prev = \
+ (elm)->field.le_prev; \
+ *(elm)->field.le_prev = (elm)->field.le_next; \
+ _Q_INVALIDATE((elm)->field.le_prev); \
+ _Q_INVALIDATE((elm)->field.le_next); \
+} while (0)
+
+#define LIST_REPLACE(elm, elm2, field) do { \
+ if (((elm2)->field.le_next = (elm)->field.le_next) != NULL) \
+ (elm2)->field.le_next->field.le_prev = \
+ &(elm2)->field.le_next; \
+ (elm2)->field.le_prev = (elm)->field.le_prev; \
+ *(elm2)->field.le_prev = (elm2); \
+ _Q_INVALIDATE((elm)->field.le_prev); \
+ _Q_INVALIDATE((elm)->field.le_next); \
+} while (0)
+
+/*
+ * Simple queue definitions.
+ */
+#define SIMPLEQ_HEAD(name, type) \
+struct name { \
+ struct type *sqh_first; /* first element */ \
+ struct type **sqh_last; /* addr of last next element */ \
+}
+
+#define SIMPLEQ_HEAD_INITIALIZER(head) \
+ { NULL, &(head).sqh_first }
+
+#define SIMPLEQ_ENTRY(type) \
+struct { \
+ struct type *sqe_next; /* next element */ \
+}
+
+/*
+ * Simple queue access methods.
+ */
+#define SIMPLEQ_FIRST(head) ((head)->sqh_first)
+#define SIMPLEQ_END(head) NULL
+#define SIMPLEQ_EMPTY(head) (SIMPLEQ_FIRST(head) == SIMPLEQ_END(head))
+#define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next)
+
+#define SIMPLEQ_FOREACH(var, head, field) \
+ for((var) = SIMPLEQ_FIRST(head); \
+ (var) != SIMPLEQ_END(head); \
+ (var) = SIMPLEQ_NEXT(var, field))
+
+#define SIMPLEQ_FOREACH_SAFE(var, head, field, tvar) \
+ for ((var) = SIMPLEQ_FIRST(head); \
+ (var) && ((tvar) = SIMPLEQ_NEXT(var, field), 1); \
+ (var) = (tvar))
+
+/*
+ * Simple queue functions.
+ */
+#define SIMPLEQ_INIT(head) do { \
+ (head)->sqh_first = NULL; \
+ (head)->sqh_last = &(head)->sqh_first; \
+} while (0)
+
+#define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \
+ if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \
+ (head)->sqh_last = &(elm)->field.sqe_next; \
+ (head)->sqh_first = (elm); \
+} while (0)
+
+#define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \
+ (elm)->field.sqe_next = NULL; \
+ *(head)->sqh_last = (elm); \
+ (head)->sqh_last = &(elm)->field.sqe_next; \
+} while (0)
+
+#define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
+ if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\
+ (head)->sqh_last = &(elm)->field.sqe_next; \
+ (listelm)->field.sqe_next = (elm); \
+} while (0)
+
+#define SIMPLEQ_REMOVE_HEAD(head, field) do { \
+ if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \
+ (head)->sqh_last = &(head)->sqh_first; \
+} while (0)
+
+#define SIMPLEQ_REMOVE_AFTER(head, elm, field) do { \
+ if (((elm)->field.sqe_next = (elm)->field.sqe_next->field.sqe_next) \
+ == NULL) \
+ (head)->sqh_last = &(elm)->field.sqe_next; \
+} while (0)
+
+#define SIMPLEQ_CONCAT(head1, head2) do { \
+ if (!SIMPLEQ_EMPTY((head2))) { \
+ *(head1)->sqh_last = (head2)->sqh_first; \
+ (head1)->sqh_last = (head2)->sqh_last; \
+ SIMPLEQ_INIT((head2)); \
+ } \
+} while (0)
+
+/*
+ * XOR Simple queue definitions.
+ */
+#define XSIMPLEQ_HEAD(name, type) \
+struct name { \
+ struct type *sqx_first; /* first element */ \
+ struct type **sqx_last; /* addr of last next element */ \
+ unsigned long sqx_cookie; \
+}
+
+#define XSIMPLEQ_ENTRY(type) \
+struct { \
+ struct type *sqx_next; /* next element */ \
+}
+
+/*
+ * XOR Simple queue access methods.
+ */
+#define XSIMPLEQ_XOR(head, ptr) ((__typeof(ptr))((head)->sqx_cookie ^ \
+ (unsigned long)(ptr)))
+#define XSIMPLEQ_FIRST(head) XSIMPLEQ_XOR(head, ((head)->sqx_first))
+#define XSIMPLEQ_END(head) NULL
+#define XSIMPLEQ_EMPTY(head) (XSIMPLEQ_FIRST(head) == XSIMPLEQ_END(head))
+#define XSIMPLEQ_NEXT(head, elm, field) XSIMPLEQ_XOR(head, ((elm)->field.sqx_next))
+
+
+#define XSIMPLEQ_FOREACH(var, head, field) \
+ for ((var) = XSIMPLEQ_FIRST(head); \
+ (var) != XSIMPLEQ_END(head); \
+ (var) = XSIMPLEQ_NEXT(head, var, field))
+
+#define XSIMPLEQ_FOREACH_SAFE(var, head, field, tvar) \
+ for ((var) = XSIMPLEQ_FIRST(head); \
+ (var) && ((tvar) = XSIMPLEQ_NEXT(head, var, field), 1); \
+ (var) = (tvar))
+
+/*
+ * XOR Simple queue functions.
+ */
+#define XSIMPLEQ_INIT(head) do { \
+ arc4random_buf(&(head)->sqx_cookie, sizeof((head)->sqx_cookie)); \
+ (head)->sqx_first = XSIMPLEQ_XOR(head, NULL); \
+ (head)->sqx_last = XSIMPLEQ_XOR(head, &(head)->sqx_first); \
+} while (0)
+
+#define XSIMPLEQ_INSERT_HEAD(head, elm, field) do { \
+ if (((elm)->field.sqx_next = (head)->sqx_first) == \
+ XSIMPLEQ_XOR(head, NULL)) \
+ (head)->sqx_last = XSIMPLEQ_XOR(head, &(elm)->field.sqx_next); \
+ (head)->sqx_first = XSIMPLEQ_XOR(head, (elm)); \
+} while (0)
+
+#define XSIMPLEQ_INSERT_TAIL(head, elm, field) do { \
+ (elm)->field.sqx_next = XSIMPLEQ_XOR(head, NULL); \
+ *(XSIMPLEQ_XOR(head, (head)->sqx_last)) = XSIMPLEQ_XOR(head, (elm)); \
+ (head)->sqx_last = XSIMPLEQ_XOR(head, &(elm)->field.sqx_next); \
+} while (0)
+
+#define XSIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
+ if (((elm)->field.sqx_next = (listelm)->field.sqx_next) == \
+ XSIMPLEQ_XOR(head, NULL)) \
+ (head)->sqx_last = XSIMPLEQ_XOR(head, &(elm)->field.sqx_next); \
+ (listelm)->field.sqx_next = XSIMPLEQ_XOR(head, (elm)); \
+} while (0)
+
+#define XSIMPLEQ_REMOVE_HEAD(head, field) do { \
+ if (((head)->sqx_first = XSIMPLEQ_XOR(head, \
+ (head)->sqx_first)->field.sqx_next) == XSIMPLEQ_XOR(head, NULL)) \
+ (head)->sqx_last = XSIMPLEQ_XOR(head, &(head)->sqx_first); \
+} while (0)
+
+#define XSIMPLEQ_REMOVE_AFTER(head, elm, field) do { \
+ if (((elm)->field.sqx_next = XSIMPLEQ_XOR(head, \
+ (elm)->field.sqx_next)->field.sqx_next) \
+ == XSIMPLEQ_XOR(head, NULL)) \
+ (head)->sqx_last = \
+ XSIMPLEQ_XOR(head, &(elm)->field.sqx_next); \
+} while (0)
+
+
+/*
+ * Tail queue definitions.
+ */
+#define TAILQ_HEAD(name, type) \
+struct name { \
+ struct type *tqh_first; /* first element */ \
+ struct type **tqh_last; /* addr of last next element */ \
+}
+
+#define TAILQ_HEAD_INITIALIZER(head) \
+ { NULL, &(head).tqh_first }
+
+#define TAILQ_ENTRY(type) \
+struct { \
+ struct type *tqe_next; /* next element */ \
+ struct type **tqe_prev; /* address of previous next element */ \
+}
+
+/*
+ * Tail queue access methods.
+ */
+#define TAILQ_FIRST(head) ((head)->tqh_first)
+#define TAILQ_END(head) NULL
+#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
+#define TAILQ_LAST(head, headname) \
+ (*(((struct headname *)((head)->tqh_last))->tqh_last))
+/* XXX */
+#define TAILQ_PREV(elm, headname, field) \
+ (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
+#define TAILQ_EMPTY(head) \
+ (TAILQ_FIRST(head) == TAILQ_END(head))
+
+#define TAILQ_FOREACH(var, head, field) \
+ for((var) = TAILQ_FIRST(head); \
+ (var) != TAILQ_END(head); \
+ (var) = TAILQ_NEXT(var, field))
+
+#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \
+ for ((var) = TAILQ_FIRST(head); \
+ (var) != TAILQ_END(head) && \
+ ((tvar) = TAILQ_NEXT(var, field), 1); \
+ (var) = (tvar))
+
+
+#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \
+ for((var) = TAILQ_LAST(head, headname); \
+ (var) != TAILQ_END(head); \
+ (var) = TAILQ_PREV(var, headname, field))
+
+#define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \
+ for ((var) = TAILQ_LAST(head, headname); \
+ (var) != TAILQ_END(head) && \
+ ((tvar) = TAILQ_PREV(var, headname, field), 1); \
+ (var) = (tvar))
+
+/*
+ * Tail queue functions.
+ */
+#define TAILQ_INIT(head) do { \
+ (head)->tqh_first = NULL; \
+ (head)->tqh_last = &(head)->tqh_first; \
+} while (0)
+
+#define TAILQ_INSERT_HEAD(head, elm, field) do { \
+ if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \
+ (head)->tqh_first->field.tqe_prev = \
+ &(elm)->field.tqe_next; \
+ else \
+ (head)->tqh_last = &(elm)->field.tqe_next; \
+ (head)->tqh_first = (elm); \
+ (elm)->field.tqe_prev = &(head)->tqh_first; \
+} while (0)
+
+#define TAILQ_INSERT_TAIL(head, elm, field) do { \
+ (elm)->field.tqe_next = NULL; \
+ (elm)->field.tqe_prev = (head)->tqh_last; \
+ *(head)->tqh_last = (elm); \
+ (head)->tqh_last = &(elm)->field.tqe_next; \
+} while (0)
+
+#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
+ if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\
+ (elm)->field.tqe_next->field.tqe_prev = \
+ &(elm)->field.tqe_next; \
+ else \
+ (head)->tqh_last = &(elm)->field.tqe_next; \
+ (listelm)->field.tqe_next = (elm); \
+ (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \
+} while (0)
+
+#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \
+ (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
+ (elm)->field.tqe_next = (listelm); \
+ *(listelm)->field.tqe_prev = (elm); \
+ (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \
+} while (0)
+
+#define TAILQ_REMOVE(head, elm, field) do { \
+ if (((elm)->field.tqe_next) != NULL) \
+ (elm)->field.tqe_next->field.tqe_prev = \
+ (elm)->field.tqe_prev; \
+ else \
+ (head)->tqh_last = (elm)->field.tqe_prev; \
+ *(elm)->field.tqe_prev = (elm)->field.tqe_next; \
+ _Q_INVALIDATE((elm)->field.tqe_prev); \
+ _Q_INVALIDATE((elm)->field.tqe_next); \
+} while (0)
+
+#define TAILQ_REPLACE(head, elm, elm2, field) do { \
+ if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL) \
+ (elm2)->field.tqe_next->field.tqe_prev = \
+ &(elm2)->field.tqe_next; \
+ else \
+ (head)->tqh_last = &(elm2)->field.tqe_next; \
+ (elm2)->field.tqe_prev = (elm)->field.tqe_prev; \
+ *(elm2)->field.tqe_prev = (elm2); \
+ _Q_INVALIDATE((elm)->field.tqe_prev); \
+ _Q_INVALIDATE((elm)->field.tqe_next); \
+} while (0)
+
+#define TAILQ_CONCAT(head1, head2, field) do { \
+ if (!TAILQ_EMPTY(head2)) { \
+ *(head1)->tqh_last = (head2)->tqh_first; \
+ (head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \
+ (head1)->tqh_last = (head2)->tqh_last; \
+ TAILQ_INIT((head2)); \
+ } \
+} while (0)
+
+#endif /* !_SYS_QUEUE_H_ */
diff --git a/lib/openbsd-tree.h b/lib/openbsd-tree.h
new file mode 100644
index 000000000..e6502b1e7
--- /dev/null
+++ b/lib/openbsd-tree.h
@@ -0,0 +1,748 @@
+/* $OpenBSD: tree.h,v 1.14 2015/05/25 03:07:49 deraadt Exp $ */
+/*
+ * Copyright 2002 Niels Provos <provos@citi.umich.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _SYS_TREE_H_
+#define _SYS_TREE_H_
+
+/*
+ * This file defines data structures for different types of trees:
+ * splay trees and red-black trees.
+ *
+ * A splay tree is a self-organizing data structure. Every operation
+ * on the tree causes a splay to happen. The splay moves the requested
+ * node to the root of the tree and partly rebalances it.
+ *
+ * This has the benefit that request locality causes faster lookups as
+ * the requested nodes move to the top of the tree. On the other hand,
+ * every lookup causes memory writes.
+ *
+ * The Balance Theorem bounds the total access time for m operations
+ * and n inserts on an initially empty tree as O((m + n)lg n). The
+ * amortized cost for a sequence of m accesses to a splay tree is O(lg n);
+ *
+ * A red-black tree is a binary search tree with the node color as an
+ * extra attribute. It fulfills a set of conditions:
+ * - every search path from the root to a leaf consists of the
+ * same number of black nodes,
+ * - each red node (except for the root) has a black parent,
+ * - each leaf node is black.
+ *
+ * Every operation on a red-black tree is bounded as O(lg n).
+ * The maximum height of a red-black tree is 2lg (n+1).
+ */
+
+#define SPLAY_HEAD(name, type) \
+struct name { \
+ struct type *sph_root; /* root of the tree */ \
+}
+
+#define SPLAY_INITIALIZER(root) \
+ { NULL }
+
+#define SPLAY_INIT(root) do { \
+ (root)->sph_root = NULL; \
+} while (0)
+
+#define SPLAY_ENTRY(type) \
+struct { \
+ struct type *spe_left; /* left element */ \
+ struct type *spe_right; /* right element */ \
+}
+
+#define SPLAY_LEFT(elm, field) (elm)->field.spe_left
+#define SPLAY_RIGHT(elm, field) (elm)->field.spe_right
+#define SPLAY_ROOT(head) (head)->sph_root
+#define SPLAY_EMPTY(head) (SPLAY_ROOT(head) == NULL)
+
+/* SPLAY_ROTATE_{LEFT,RIGHT} expect that tmp hold SPLAY_{RIGHT,LEFT} */
+#define SPLAY_ROTATE_RIGHT(head, tmp, field) do { \
+ SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(tmp, field); \
+ SPLAY_RIGHT(tmp, field) = (head)->sph_root; \
+ (head)->sph_root = tmp; \
+} while (0)
+
+#define SPLAY_ROTATE_LEFT(head, tmp, field) do { \
+ SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(tmp, field); \
+ SPLAY_LEFT(tmp, field) = (head)->sph_root; \
+ (head)->sph_root = tmp; \
+} while (0)
+
+#define SPLAY_LINKLEFT(head, tmp, field) do { \
+ SPLAY_LEFT(tmp, field) = (head)->sph_root; \
+ tmp = (head)->sph_root; \
+ (head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \
+} while (0)
+
+#define SPLAY_LINKRIGHT(head, tmp, field) do { \
+ SPLAY_RIGHT(tmp, field) = (head)->sph_root; \
+ tmp = (head)->sph_root; \
+ (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \
+} while (0)
+
+#define SPLAY_ASSEMBLE(head, node, left, right, field) do { \
+ SPLAY_RIGHT(left, field) = SPLAY_LEFT((head)->sph_root, field); \
+ SPLAY_LEFT(right, field) = SPLAY_RIGHT((head)->sph_root, field);\
+ SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(node, field); \
+ SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(node, field); \
+} while (0)
+
+/* Generates prototypes and inline functions */
+
+#define SPLAY_PROTOTYPE(name, type, field, cmp) \
+void name##_SPLAY(struct name *, struct type *); \
+void name##_SPLAY_MINMAX(struct name *, int); \
+struct type *name##_SPLAY_INSERT(struct name *, struct type *); \
+struct type *name##_SPLAY_REMOVE(struct name *, struct type *); \
+ \
+/* Finds the node with the same key as elm */ \
+static __inline struct type * \
+name##_SPLAY_FIND(struct name *head, struct type *elm) \
+{ \
+ if (SPLAY_EMPTY(head)) \
+ return(NULL); \
+ name##_SPLAY(head, elm); \
+ if ((cmp)(elm, (head)->sph_root) == 0) \
+ return (head->sph_root); \
+ return (NULL); \
+} \
+ \
+static __inline struct type * \
+name##_SPLAY_NEXT(struct name *head, struct type *elm) \
+{ \
+ name##_SPLAY(head, elm); \
+ if (SPLAY_RIGHT(elm, field) != NULL) { \
+ elm = SPLAY_RIGHT(elm, field); \
+ while (SPLAY_LEFT(elm, field) != NULL) { \
+ elm = SPLAY_LEFT(elm, field); \
+ } \
+ } else \
+ elm = NULL; \
+ return (elm); \
+} \
+ \
+static __inline struct type * \
+name##_SPLAY_MIN_MAX(struct name *head, int val) \
+{ \
+ name##_SPLAY_MINMAX(head, val); \
+ return (SPLAY_ROOT(head)); \
+}
+
+/* Main splay operation.
+ * Moves node close to the key of elm to top
+ */
+#define SPLAY_GENERATE(name, type, field, cmp) \
+struct type * \
+name##_SPLAY_INSERT(struct name *head, struct type *elm) \
+{ \
+ if (SPLAY_EMPTY(head)) { \
+ SPLAY_LEFT(elm, field) = SPLAY_RIGHT(elm, field) = NULL; \
+ } else { \
+ int __comp; \
+ name##_SPLAY(head, elm); \
+ __comp = (cmp)(elm, (head)->sph_root); \
+ if(__comp < 0) { \
+ SPLAY_LEFT(elm, field) = SPLAY_LEFT((head)->sph_root, field);\
+ SPLAY_RIGHT(elm, field) = (head)->sph_root; \
+ SPLAY_LEFT((head)->sph_root, field) = NULL; \
+ } else if (__comp > 0) { \
+ SPLAY_RIGHT(elm, field) = SPLAY_RIGHT((head)->sph_root, field);\
+ SPLAY_LEFT(elm, field) = (head)->sph_root; \
+ SPLAY_RIGHT((head)->sph_root, field) = NULL; \
+ } else \
+ return ((head)->sph_root); \
+ } \
+ (head)->sph_root = (elm); \
+ return (NULL); \
+} \
+ \
+struct type * \
+name##_SPLAY_REMOVE(struct name *head, struct type *elm) \
+{ \
+ struct type *__tmp; \
+ if (SPLAY_EMPTY(head)) \
+ return (NULL); \
+ name##_SPLAY(head, elm); \
+ if ((cmp)(elm, (head)->sph_root) == 0) { \
+ if (SPLAY_LEFT((head)->sph_root, field) == NULL) { \
+ (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field);\
+ } else { \
+ __tmp = SPLAY_RIGHT((head)->sph_root, field); \
+ (head)->sph_root = SPLAY_LEFT((head)->sph_root, field);\
+ name##_SPLAY(head, elm); \
+ SPLAY_RIGHT((head)->sph_root, field) = __tmp; \
+ } \
+ return (elm); \
+ } \
+ return (NULL); \
+} \
+ \
+void \
+name##_SPLAY(struct name *head, struct type *elm) \
+{ \
+ struct type __node, *__left, *__right, *__tmp; \
+ int __comp; \
+\
+ SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\
+ __left = __right = &__node; \
+\
+ while ((__comp = (cmp)(elm, (head)->sph_root))) { \
+ if (__comp < 0) { \
+ __tmp = SPLAY_LEFT((head)->sph_root, field); \
+ if (__tmp == NULL) \
+ break; \
+ if ((cmp)(elm, __tmp) < 0){ \
+ SPLAY_ROTATE_RIGHT(head, __tmp, field); \
+ if (SPLAY_LEFT((head)->sph_root, field) == NULL)\
+ break; \
+ } \
+ SPLAY_LINKLEFT(head, __right, field); \
+ } else if (__comp > 0) { \
+ __tmp = SPLAY_RIGHT((head)->sph_root, field); \
+ if (__tmp == NULL) \
+ break; \
+ if ((cmp)(elm, __tmp) > 0){ \
+ SPLAY_ROTATE_LEFT(head, __tmp, field); \
+ if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\
+ break; \
+ } \
+ SPLAY_LINKRIGHT(head, __left, field); \
+ } \
+ } \
+ SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \
+} \
+ \
+/* Splay with either the minimum or the maximum element \
+ * Used to find minimum or maximum element in tree. \
+ */ \
+void name##_SPLAY_MINMAX(struct name *head, int __comp) \
+{ \
+ struct type __node, *__left, *__right, *__tmp; \
+\
+ SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\
+ __left = __right = &__node; \
+\
+ while (1) { \
+ if (__comp < 0) { \
+ __tmp = SPLAY_LEFT((head)->sph_root, field); \
+ if (__tmp == NULL) \
+ break; \
+ if (__comp < 0){ \
+ SPLAY_ROTATE_RIGHT(head, __tmp, field); \
+ if (SPLAY_LEFT((head)->sph_root, field) == NULL)\
+ break; \
+ } \
+ SPLAY_LINKLEFT(head, __right, field); \
+ } else if (__comp > 0) { \
+ __tmp = SPLAY_RIGHT((head)->sph_root, field); \
+ if (__tmp == NULL) \
+ break; \
+ if (__comp > 0) { \
+ SPLAY_ROTATE_LEFT(head, __tmp, field); \
+ if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\
+ break; \
+ } \
+ SPLAY_LINKRIGHT(head, __left, field); \
+ } \
+ } \
+ SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \
+}
+
+#define SPLAY_NEGINF -1
+#define SPLAY_INF 1
+
+#define SPLAY_INSERT(name, x, y) name##_SPLAY_INSERT(x, y)
+#define SPLAY_REMOVE(name, x, y) name##_SPLAY_REMOVE(x, y)
+#define SPLAY_FIND(name, x, y) name##_SPLAY_FIND(x, y)
+#define SPLAY_NEXT(name, x, y) name##_SPLAY_NEXT(x, y)
+#define SPLAY_MIN(name, x) (SPLAY_EMPTY(x) ? NULL \
+ : name##_SPLAY_MIN_MAX(x, SPLAY_NEGINF))
+#define SPLAY_MAX(name, x) (SPLAY_EMPTY(x) ? NULL \
+ : name##_SPLAY_MIN_MAX(x, SPLAY_INF))
+
+#define SPLAY_FOREACH(x, name, head) \
+ for ((x) = SPLAY_MIN(name, head); \
+ (x) != NULL; \
+ (x) = SPLAY_NEXT(name, head, x))
+
+/* Macros that define a red-black tree */
+#define RB_HEAD(name, type) \
+struct name { \
+ struct type *rbh_root; /* root of the tree */ \
+}
+
+#define RB_INITIALIZER(root) \
+ { NULL }
+
+#define RB_INIT(root) do { \
+ (root)->rbh_root = NULL; \
+} while (0)
+
+#define RB_BLACK 0
+#define RB_RED 1
+#define RB_ENTRY(type) \
+struct { \
+ struct type *rbe_left; /* left element */ \
+ struct type *rbe_right; /* right element */ \
+ struct type *rbe_parent; /* parent element */ \
+ int rbe_color; /* node color */ \
+}
+
+#define RB_LEFT(elm, field) (elm)->field.rbe_left
+#define RB_RIGHT(elm, field) (elm)->field.rbe_right
+#define RB_PARENT(elm, field) (elm)->field.rbe_parent
+#define RB_COLOR(elm, field) (elm)->field.rbe_color
+#define RB_ROOT(head) (head)->rbh_root
+#define RB_EMPTY(head) (RB_ROOT(head) == NULL)
+
+#define RB_SET(elm, parent, field) do { \
+ RB_PARENT(elm, field) = parent; \
+ RB_LEFT(elm, field) = RB_RIGHT(elm, field) = NULL; \
+ RB_COLOR(elm, field) = RB_RED; \
+} while (0)
+
+#define RB_SET_BLACKRED(black, red, field) do { \
+ RB_COLOR(black, field) = RB_BLACK; \
+ RB_COLOR(red, field) = RB_RED; \
+} while (0)
+
+#ifndef RB_AUGMENT
+#define RB_AUGMENT(x) do {} while (0)
+#endif
+
+#define RB_ROTATE_LEFT(head, elm, tmp, field) do { \
+ (tmp) = RB_RIGHT(elm, field); \
+ if ((RB_RIGHT(elm, field) = RB_LEFT(tmp, field))) { \
+ RB_PARENT(RB_LEFT(tmp, field), field) = (elm); \
+ } \
+ RB_AUGMENT(elm); \
+ if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field))) { \
+ if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \
+ RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \
+ else \
+ RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \
+ } else \
+ (head)->rbh_root = (tmp); \
+ RB_LEFT(tmp, field) = (elm); \
+ RB_PARENT(elm, field) = (tmp); \
+ RB_AUGMENT(tmp); \
+ if ((RB_PARENT(tmp, field))) \
+ RB_AUGMENT(RB_PARENT(tmp, field)); \
+} while (0)
+
+#define RB_ROTATE_RIGHT(head, elm, tmp, field) do { \
+ (tmp) = RB_LEFT(elm, field); \
+ if ((RB_LEFT(elm, field) = RB_RIGHT(tmp, field))) { \
+ RB_PARENT(RB_RIGHT(tmp, field), field) = (elm); \
+ } \
+ RB_AUGMENT(elm); \
+ if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field))) { \
+ if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \
+ RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \
+ else \
+ RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \
+ } else \
+ (head)->rbh_root = (tmp); \
+ RB_RIGHT(tmp, field) = (elm); \
+ RB_PARENT(elm, field) = (tmp); \
+ RB_AUGMENT(tmp); \
+ if ((RB_PARENT(tmp, field))) \
+ RB_AUGMENT(RB_PARENT(tmp, field)); \
+} while (0)
+
+/* Generates prototypes and inline functions */
+#define RB_PROTOTYPE(name, type, field, cmp) \
+ RB_PROTOTYPE_INTERNAL(name, type, field, cmp,)
+#define RB_PROTOTYPE_STATIC(name, type, field, cmp) \
+ RB_PROTOTYPE_INTERNAL(name, type, field, cmp, __attribute__((__unused__)) static)
+#define RB_PROTOTYPE_INTERNAL(name, type, field, cmp, attr) \
+attr void name##_RB_INSERT_COLOR(struct name *, struct type *); \
+attr void name##_RB_REMOVE_COLOR(struct name *, struct type *, struct type *);\
+attr struct type *name##_RB_REMOVE(struct name *, struct type *); \
+attr struct type *name##_RB_INSERT(struct name *, struct type *); \
+attr struct type *name##_RB_FIND(struct name *, struct type *); \
+attr struct type *name##_RB_NFIND(struct name *, struct type *); \
+attr struct type *name##_RB_NEXT(struct type *); \
+attr struct type *name##_RB_PREV(struct type *); \
+attr struct type *name##_RB_MINMAX(struct name *, int); \
+ \
+
+/* Main rb operation.
+ * Moves node close to the key of elm to top
+ */
+#define RB_GENERATE(name, type, field, cmp) \
+ RB_GENERATE_INTERNAL(name, type, field, cmp,)
+#define RB_GENERATE_STATIC(name, type, field, cmp) \
+ RB_GENERATE_INTERNAL(name, type, field, cmp, __attribute__((__unused__)) static)
+#define RB_GENERATE_INTERNAL(name, type, field, cmp, attr) \
+attr void \
+name##_RB_INSERT_COLOR(struct name *head, struct type *elm) \
+{ \
+ struct type *parent, *gparent, *tmp; \
+ while ((parent = RB_PARENT(elm, field)) && \
+ RB_COLOR(parent, field) == RB_RED) { \
+ gparent = RB_PARENT(parent, field); \
+ if (parent == RB_LEFT(gparent, field)) { \
+ tmp = RB_RIGHT(gparent, field); \
+ if (tmp && RB_COLOR(tmp, field) == RB_RED) { \
+ RB_COLOR(tmp, field) = RB_BLACK; \
+ RB_SET_BLACKRED(parent, gparent, field);\
+ elm = gparent; \
+ continue; \
+ } \
+ if (RB_RIGHT(parent, field) == elm) { \
+ RB_ROTATE_LEFT(head, parent, tmp, field);\
+ tmp = parent; \
+ parent = elm; \
+ elm = tmp; \
+ } \
+ RB_SET_BLACKRED(parent, gparent, field); \
+ RB_ROTATE_RIGHT(head, gparent, tmp, field); \
+ } else { \
+ tmp = RB_LEFT(gparent, field); \
+ if (tmp && RB_COLOR(tmp, field) == RB_RED) { \
+ RB_COLOR(tmp, field) = RB_BLACK; \
+ RB_SET_BLACKRED(parent, gparent, field);\
+ elm = gparent; \
+ continue; \
+ } \
+ if (RB_LEFT(parent, field) == elm) { \
+ RB_ROTATE_RIGHT(head, parent, tmp, field);\
+ tmp = parent; \
+ parent = elm; \
+ elm = tmp; \
+ } \
+ RB_SET_BLACKRED(parent, gparent, field); \
+ RB_ROTATE_LEFT(head, gparent, tmp, field); \
+ } \
+ } \
+ RB_COLOR(head->rbh_root, field) = RB_BLACK; \
+} \
+ \
+attr void \
+name##_RB_REMOVE_COLOR(struct name *head, struct type *parent, struct type *elm) \
+{ \
+ struct type *tmp; \
+ while ((elm == NULL || RB_COLOR(elm, field) == RB_BLACK) && \
+ elm != RB_ROOT(head)) { \
+ if (RB_LEFT(parent, field) == elm) { \
+ tmp = RB_RIGHT(parent, field); \
+ if (RB_COLOR(tmp, field) == RB_RED) { \
+ RB_SET_BLACKRED(tmp, parent, field); \
+ RB_ROTATE_LEFT(head, parent, tmp, field);\
+ tmp = RB_RIGHT(parent, field); \
+ } \
+ if ((RB_LEFT(tmp, field) == NULL || \
+ RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\
+ (RB_RIGHT(tmp, field) == NULL || \
+ RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\
+ RB_COLOR(tmp, field) = RB_RED; \
+ elm = parent; \
+ parent = RB_PARENT(elm, field); \
+ } else { \
+ if (RB_RIGHT(tmp, field) == NULL || \
+ RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK) {\
+ struct type *oleft; \
+ if ((oleft = RB_LEFT(tmp, field)))\
+ RB_COLOR(oleft, field) = RB_BLACK;\
+ RB_COLOR(tmp, field) = RB_RED; \
+ RB_ROTATE_RIGHT(head, tmp, oleft, field);\
+ tmp = RB_RIGHT(parent, field); \
+ } \
+ RB_COLOR(tmp, field) = RB_COLOR(parent, field);\
+ RB_COLOR(parent, field) = RB_BLACK; \
+ if (RB_RIGHT(tmp, field)) \
+ RB_COLOR(RB_RIGHT(tmp, field), field) = RB_BLACK;\
+ RB_ROTATE_LEFT(head, parent, tmp, field);\
+ elm = RB_ROOT(head); \
+ break; \
+ } \
+ } else { \
+ tmp = RB_LEFT(parent, field); \
+ if (RB_COLOR(tmp, field) == RB_RED) { \
+ RB_SET_BLACKRED(tmp, parent, field); \
+ RB_ROTATE_RIGHT(head, parent, tmp, field);\
+ tmp = RB_LEFT(parent, field); \
+ } \
+ if ((RB_LEFT(tmp, field) == NULL || \
+ RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\
+ (RB_RIGHT(tmp, field) == NULL || \
+ RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\
+ RB_COLOR(tmp, field) = RB_RED; \
+ elm = parent; \
+ parent = RB_PARENT(elm, field); \
+ } else { \
+ if (RB_LEFT(tmp, field) == NULL || \
+ RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) {\
+ struct type *oright; \
+ if ((oright = RB_RIGHT(tmp, field)))\
+ RB_COLOR(oright, field) = RB_BLACK;\
+ RB_COLOR(tmp, field) = RB_RED; \
+ RB_ROTATE_LEFT(head, tmp, oright, field);\
+ tmp = RB_LEFT(parent, field); \
+ } \
+ RB_COLOR(tmp, field) = RB_COLOR(parent, field);\
+ RB_COLOR(parent, field) = RB_BLACK; \
+ if (RB_LEFT(tmp, field)) \
+ RB_COLOR(RB_LEFT(tmp, field), field) = RB_BLACK;\
+ RB_ROTATE_RIGHT(head, parent, tmp, field);\
+ elm = RB_ROOT(head); \
+ break; \
+ } \
+ } \
+ } \
+ if (elm) \
+ RB_COLOR(elm, field) = RB_BLACK; \
+} \
+ \
+attr struct type * \
+name##_RB_REMOVE(struct name *head, struct type *elm) \
+{ \
+ struct type *child, *parent, *old = elm; \
+ int color; \
+ if (RB_LEFT(elm, field) == NULL) \
+ child = RB_RIGHT(elm, field); \
+ else if (RB_RIGHT(elm, field) == NULL) \
+ child = RB_LEFT(elm, field); \
+ else { \
+ struct type *left; \
+ elm = RB_RIGHT(elm, field); \
+ while ((left = RB_LEFT(elm, field))) \
+ elm = left; \
+ child = RB_RIGHT(elm, field); \
+ parent = RB_PARENT(elm, field); \
+ color = RB_COLOR(elm, field); \
+ if (child) \
+ RB_PARENT(child, field) = parent; \
+ if (parent) { \
+ if (RB_LEFT(parent, field) == elm) \
+ RB_LEFT(parent, field) = child; \
+ else \
+ RB_RIGHT(parent, field) = child; \
+ RB_AUGMENT(parent); \
+ } else \
+ RB_ROOT(head) = child; \
+ if (RB_PARENT(elm, field) == old) \
+ parent = elm; \
+ (elm)->field = (old)->field; \
+ if (RB_PARENT(old, field)) { \
+ if (RB_LEFT(RB_PARENT(old, field), field) == old)\
+ RB_LEFT(RB_PARENT(old, field), field) = elm;\
+ else \
+ RB_RIGHT(RB_PARENT(old, field), field) = elm;\
+ RB_AUGMENT(RB_PARENT(old, field)); \
+ } else \
+ RB_ROOT(head) = elm; \
+ RB_PARENT(RB_LEFT(old, field), field) = elm; \
+ if (RB_RIGHT(old, field)) \
+ RB_PARENT(RB_RIGHT(old, field), field) = elm; \
+ if (parent) { \
+ left = parent; \
+ do { \
+ RB_AUGMENT(left); \
+ } while ((left = RB_PARENT(left, field))); \
+ } \
+ goto color; \
+ } \
+ parent = RB_PARENT(elm, field); \
+ color = RB_COLOR(elm, field); \
+ if (child) \
+ RB_PARENT(child, field) = parent; \
+ if (parent) { \
+ if (RB_LEFT(parent, field) == elm) \
+ RB_LEFT(parent, field) = child; \
+ else \
+ RB_RIGHT(parent, field) = child; \
+ RB_AUGMENT(parent); \
+ } else \
+ RB_ROOT(head) = child; \
+color: \
+ if (color == RB_BLACK) \
+ name##_RB_REMOVE_COLOR(head, parent, child); \
+ return (old); \
+} \
+ \
+/* Inserts a node into the RB tree */ \
+attr struct type * \
+name##_RB_INSERT(struct name *head, struct type *elm) \
+{ \
+ struct type *tmp; \
+ struct type *parent = NULL; \
+ int comp = 0; \
+ tmp = RB_ROOT(head); \
+ while (tmp) { \
+ parent = tmp; \
+ comp = (cmp)(elm, parent); \
+ if (comp < 0) \
+ tmp = RB_LEFT(tmp, field); \
+ else if (comp > 0) \
+ tmp = RB_RIGHT(tmp, field); \
+ else \
+ return (tmp); \
+ } \
+ RB_SET(elm, parent, field); \
+ if (parent != NULL) { \
+ if (comp < 0) \
+ RB_LEFT(parent, field) = elm; \
+ else \
+ RB_RIGHT(parent, field) = elm; \
+ RB_AUGMENT(parent); \
+ } else \
+ RB_ROOT(head) = elm; \
+ name##_RB_INSERT_COLOR(head, elm); \
+ return (NULL); \
+} \
+ \
+/* Finds the node with the same key as elm */ \
+attr struct type * \
+name##_RB_FIND(struct name *head, struct type *elm) \
+{ \
+ struct type *tmp = RB_ROOT(head); \
+ int comp; \
+ while (tmp) { \
+ comp = cmp(elm, tmp); \
+ if (comp < 0) \
+ tmp = RB_LEFT(tmp, field); \
+ else if (comp > 0) \
+ tmp = RB_RIGHT(tmp, field); \
+ else \
+ return (tmp); \
+ } \
+ return (NULL); \
+} \
+ \
+/* Finds the first node greater than or equal to the search key */ \
+attr struct type * \
+name##_RB_NFIND(struct name *head, struct type *elm) \
+{ \
+ struct type *tmp = RB_ROOT(head); \
+ struct type *res = NULL; \
+ int comp; \
+ while (tmp) { \
+ comp = cmp(elm, tmp); \
+ if (comp < 0) { \
+ res = tmp; \
+ tmp = RB_LEFT(tmp, field); \
+ } \
+ else if (comp > 0) \
+ tmp = RB_RIGHT(tmp, field); \
+ else \
+ return (tmp); \
+ } \
+ return (res); \
+} \
+ \
+/* ARGSUSED */ \
+attr struct type * \
+name##_RB_NEXT(struct type *elm) \
+{ \
+ if (RB_RIGHT(elm, field)) { \
+ elm = RB_RIGHT(elm, field); \
+ while (RB_LEFT(elm, field)) \
+ elm = RB_LEFT(elm, field); \
+ } else { \
+ if (RB_PARENT(elm, field) && \
+ (elm == RB_LEFT(RB_PARENT(elm, field), field))) \
+ elm = RB_PARENT(elm, field); \
+ else { \
+ while (RB_PARENT(elm, field) && \
+ (elm == RB_RIGHT(RB_PARENT(elm, field), field)))\
+ elm = RB_PARENT(elm, field); \
+ elm = RB_PARENT(elm, field); \
+ } \
+ } \
+ return (elm); \
+} \
+ \
+/* ARGSUSED */ \
+attr struct type * \
+name##_RB_PREV(struct type *elm) \
+{ \
+ if (RB_LEFT(elm, field)) { \
+ elm = RB_LEFT(elm, field); \
+ while (RB_RIGHT(elm, field)) \
+ elm = RB_RIGHT(elm, field); \
+ } else { \
+ if (RB_PARENT(elm, field) && \
+ (elm == RB_RIGHT(RB_PARENT(elm, field), field))) \
+ elm = RB_PARENT(elm, field); \
+ else { \
+ while (RB_PARENT(elm, field) && \
+ (elm == RB_LEFT(RB_PARENT(elm, field), field)))\
+ elm = RB_PARENT(elm, field); \
+ elm = RB_PARENT(elm, field); \
+ } \
+ } \
+ return (elm); \
+} \
+ \
+attr struct type * \
+name##_RB_MINMAX(struct name *head, int val) \
+{ \
+ struct type *tmp = RB_ROOT(head); \
+ struct type *parent = NULL; \
+ while (tmp) { \
+ parent = tmp; \
+ if (val < 0) \
+ tmp = RB_LEFT(tmp, field); \
+ else \
+ tmp = RB_RIGHT(tmp, field); \
+ } \
+ return (parent); \
+}
+
+#define RB_NEGINF -1
+#define RB_INF 1
+
+#define RB_INSERT(name, x, y) name##_RB_INSERT(x, y)
+#define RB_REMOVE(name, x, y) name##_RB_REMOVE(x, y)
+#define RB_FIND(name, x, y) name##_RB_FIND(x, y)
+#define RB_NFIND(name, x, y) name##_RB_NFIND(x, y)
+#define RB_NEXT(name, x, y) name##_RB_NEXT(y)
+#define RB_PREV(name, x, y) name##_RB_PREV(y)
+#define RB_MIN(name, x) name##_RB_MINMAX(x, RB_NEGINF)
+#define RB_MAX(name, x) name##_RB_MINMAX(x, RB_INF)
+
+#define RB_FOREACH(x, name, head) \
+ for ((x) = RB_MIN(name, head); \
+ (x) != NULL; \
+ (x) = name##_RB_NEXT(x))
+
+#define RB_FOREACH_SAFE(x, name, head, y) \
+ for ((x) = RB_MIN(name, head); \
+ ((x) != NULL) && ((y) = name##_RB_NEXT(x), 1); \
+ (x) = (y))
+
+#define RB_FOREACH_REVERSE(x, name, head) \
+ for ((x) = RB_MAX(name, head); \
+ (x) != NULL; \
+ (x) = name##_RB_PREV(x))
+
+#define RB_FOREACH_REVERSE_SAFE(x, name, head, y) \
+ for ((x) = RB_MAX(name, head); \
+ ((x) != NULL) && ((y) = name##_RB_PREV(x), 1); \
+ (x) = (y))
+
+#endif /* _SYS_TREE_H_ */
diff --git a/lib/plist.c b/lib/plist.c
index 23d580bd6..a854ad52b 100644
--- a/lib/plist.c
+++ b/lib/plist.c
@@ -899,7 +899,7 @@ vty_prefix_list_install (struct vty *vty, afi_t afi, const char *name,
struct prefix_list *plist;
struct prefix_list_entry *pentry;
struct prefix_list_entry *dup;
- struct prefix p;
+ struct prefix p, p_tmp;
int any = 0;
int seqnum = -1;
int lenum = 0;
@@ -945,6 +945,11 @@ vty_prefix_list_install (struct vty *vty, afi_t afi, const char *name,
vty_out (vty, "%% Malformed IPv4 prefix%s", VTY_NEWLINE);
return CMD_WARNING;
}
+
+ /* make a copy to verify prefix matches mask length */
+ prefix_copy (&p_tmp, &p);
+ apply_mask_ipv4 ((struct prefix_ipv4 *) &p_tmp);
+
break;
case AFI_IP6:
if (strncmp ("any", prefix, strlen (prefix)) == 0)
@@ -962,6 +967,11 @@ vty_prefix_list_install (struct vty *vty, afi_t afi, const char *name,
vty_out (vty, "%% Malformed IPv6 prefix%s", VTY_NEWLINE);
return CMD_WARNING;
}
+
+ /* make a copy to verify prefix matches mask length */
+ prefix_copy (&p_tmp, &p);
+ apply_mask_ipv6 ((struct prefix_ipv6 *) &p_tmp);
+
break;
case AFI_ETHER:
default:
@@ -970,6 +980,18 @@ vty_prefix_list_install (struct vty *vty, afi_t afi, const char *name,
break;
}
+ /* If prefix has bits not under the mask, adjust it to fit */
+ if (!prefix_same (&p_tmp, &p))
+ {
+ char buf[PREFIX2STR_BUFFER];
+ char buf_tmp[PREFIX2STR_BUFFER];
+ prefix2str(&p, buf, sizeof(buf));
+ prefix2str(&p_tmp, buf_tmp, sizeof(buf_tmp));
+ zlog_warn ("Prefix-list %s prefix changed from %s to %s to match length",
+ name, buf, buf_tmp);
+ p = p_tmp;
+ }
+
/* ge and le check. */
if (genum && (genum <= p.prefixlen))
return vty_invalid_prefix_range (vty, prefix);
@@ -995,14 +1017,6 @@ vty_prefix_list_install (struct vty *vty, afi_t afi, const char *name,
if (dup)
{
prefix_list_entry_free (pentry);
- vty_out (vty, "%% Insertion failed - prefix-list entry exists:%s",
- VTY_NEWLINE);
- vty_out (vty, " seq %u %s %s", dup->seq, typestr, prefix);
- if (! any && genum)
- vty_out (vty, " ge %d", genum);
- if (! any && lenum)
- vty_out (vty, " le %d", lenum);
- vty_out (vty, "%s", VTY_NEWLINE);
return CMD_SUCCESS;
}
@@ -3072,7 +3086,7 @@ prefix_bgp_show_prefix_list (struct vty *vty, afi_t afi, char *name, u_char use_
else
json_object_object_add(json, "ipv6PrefixList", json_prefix);
- vty_out (vty, "%s%s", json_object_to_json_string(json), VTY_NEWLINE);
+ vty_out (vty, "%s%s", json_object_to_json_string_ext(json, JSON_C_TO_STRING_PRETTY), VTY_NEWLINE);
json_object_free(json);
}
else
@@ -3195,17 +3209,6 @@ prefix_list_init_ipv4 (void)
install_element (VIEW_NODE, &show_ip_prefix_list_detail_cmd);
install_element (VIEW_NODE, &show_ip_prefix_list_detail_name_cmd);
- install_element (ENABLE_NODE, &show_ip_prefix_list_cmd);
- install_element (ENABLE_NODE, &show_ip_prefix_list_name_cmd);
- install_element (ENABLE_NODE, &show_ip_prefix_list_name_seq_cmd);
- install_element (ENABLE_NODE, &show_ip_prefix_list_prefix_cmd);
- install_element (ENABLE_NODE, &show_ip_prefix_list_prefix_longer_cmd);
- install_element (ENABLE_NODE, &show_ip_prefix_list_prefix_first_match_cmd);
- install_element (ENABLE_NODE, &show_ip_prefix_list_summary_cmd);
- install_element (ENABLE_NODE, &show_ip_prefix_list_summary_name_cmd);
- install_element (ENABLE_NODE, &show_ip_prefix_list_detail_cmd);
- install_element (ENABLE_NODE, &show_ip_prefix_list_detail_name_cmd);
-
install_element (ENABLE_NODE, &clear_ip_prefix_list_cmd);
install_element (ENABLE_NODE, &clear_ip_prefix_list_name_cmd);
install_element (ENABLE_NODE, &clear_ip_prefix_list_name_prefix_cmd);
@@ -3272,17 +3275,6 @@ prefix_list_init_ipv6 (void)
install_element (VIEW_NODE, &show_ipv6_prefix_list_detail_cmd);
install_element (VIEW_NODE, &show_ipv6_prefix_list_detail_name_cmd);
- install_element (ENABLE_NODE, &show_ipv6_prefix_list_cmd);
- install_element (ENABLE_NODE, &show_ipv6_prefix_list_name_cmd);
- install_element (ENABLE_NODE, &show_ipv6_prefix_list_name_seq_cmd);
- install_element (ENABLE_NODE, &show_ipv6_prefix_list_prefix_cmd);
- install_element (ENABLE_NODE, &show_ipv6_prefix_list_prefix_longer_cmd);
- install_element (ENABLE_NODE, &show_ipv6_prefix_list_prefix_first_match_cmd);
- install_element (ENABLE_NODE, &show_ipv6_prefix_list_summary_cmd);
- install_element (ENABLE_NODE, &show_ipv6_prefix_list_summary_name_cmd);
- install_element (ENABLE_NODE, &show_ipv6_prefix_list_detail_cmd);
- install_element (ENABLE_NODE, &show_ipv6_prefix_list_detail_name_cmd);
-
install_element (ENABLE_NODE, &clear_ipv6_prefix_list_cmd);
install_element (ENABLE_NODE, &clear_ipv6_prefix_list_name_cmd);
install_element (ENABLE_NODE, &clear_ipv6_prefix_list_name_prefix_cmd);
diff --git a/lib/prefix.c b/lib/prefix.c
index 34bb1a493..112dae582 100644
--- a/lib/prefix.c
+++ b/lib/prefix.c
@@ -240,6 +240,8 @@ afi2str(afi_t afi)
return "IPv6";
case AFI_ETHER:
return "ethernet";
+ case AFI_MAX:
+ return "bad-value";
default:
break;
}
diff --git a/lib/privs.c b/lib/privs.c
index 9228a56d3..6cf87c18d 100644
--- a/lib/privs.c
+++ b/lib/privs.c
@@ -250,12 +250,6 @@ zprivs_caps_init (struct zebra_privs_t *zprivs)
exit(1);
}
- if ( !zprivs_state.syscaps_p )
- {
- fprintf (stderr, "privs_init: capabilities enabled, "
- "but no capabilities supplied\n");
- }
-
/* we have caps, we have no need to ever change back the original user */
if (zprivs_state.zuid)
{
@@ -266,6 +260,9 @@ zprivs_caps_init (struct zebra_privs_t *zprivs)
exit (1);
}
}
+
+ if ( !zprivs_state.syscaps_p )
+ return;
if ( !(zprivs_state.caps = cap_init()) )
{
diff --git a/lib/qobj.c b/lib/qobj.c
new file mode 100644
index 000000000..65b537f96
--- /dev/null
+++ b/lib/qobj.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2015-16 David Lamparter, for NetDEF, Inc.
+ *
+ * This file is part of Quagga
+ *
+ * Quagga is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * Quagga is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Quagga; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+#include "thread.h"
+#include "memory.h"
+#include "hash.h"
+#include "log.h"
+#include "qobj.h"
+
+static struct hash *nodes = NULL;
+
+static unsigned int qobj_key (void *data)
+{
+ struct qobj_node *node = data;
+ return (unsigned int)node->nid;
+}
+
+static int qobj_cmp (const void *a, const void *b)
+{
+ const struct qobj_node *na = a, *nb = b;
+ return na->nid == nb->nid;
+}
+
+void qobj_reg(struct qobj_node *node, struct qobj_nodetype *type)
+{
+ node->type = type;
+ do
+ {
+ node->nid = (uint64_t)random();
+ node->nid ^= (uint64_t)random() << 32;
+ }
+ while (hash_get (nodes, node, hash_alloc_intern) != node);
+}
+
+void qobj_unreg(struct qobj_node *node)
+{
+ hash_release (nodes, node);
+}
+
+struct qobj_node *qobj_get(uint64_t id)
+{
+ struct qobj_node dummy = { .nid = id };
+ return hash_lookup (nodes, &dummy);
+}
+
+void *qobj_get_typed(uint64_t id, struct qobj_nodetype *type)
+{
+ struct qobj_node *node = qobj_get(id);
+ if (!node || node->type != type)
+ return NULL;
+ return (char *)node - node->type->node_member_offset;
+}
+
+void qobj_init (void)
+{
+ nodes = hash_create (qobj_key, qobj_cmp);
+}
+
+void qobj_finish (void)
+{
+ hash_free (nodes);
+ nodes = NULL;
+}
diff --git a/lib/qobj.h b/lib/qobj.h
new file mode 100644
index 000000000..4a5c0c01e
--- /dev/null
+++ b/lib/qobj.h
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2015-16 David Lamparter, for NetDEF, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _QOBJ_H
+#define _QOBJ_H
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stddef.h>
+
+/* reserve a specific amount of bytes for a struct, which can grow up to
+ * that size (or be dummy'd out if not needed)
+ *
+ * note the padding's array size will be an error if it gets negative or zero;
+ * this is intentional to prevent the struct from growing beyond the allocated
+ * space.
+ */
+#define RESERVED_SPACE_STRUCT(name, fieldname, size) \
+ struct { \
+ struct name fieldname; \
+ char padding ## fieldname[size - sizeof(struct name)]; \
+ };
+
+/* don't need struct definitions for these here. code actually using
+ * these needs to define the struct *before* including this header.
+ * HAVE_QOBJ_xxx should be defined to +1 in that case, like this:
+ *
+ * #if defined(HAVE_QOBJ_NODETYPE_CLI) && HAVE_QOBJ_NODETYPE_CLI < 0
+ * #error include files are in wrong order
+ * #else
+ * #define HAVE_QOBJ_NODETYPE_CLI 1
+ * struct qobj_nodetype_cli { ... }
+ * #endif
+ */
+#ifndef HAVE_QOBJ_NODETYPE_CLI
+#define HAVE_QOBJ_NODETYPE_CLI -1
+struct qobj_nodetype_cli { int dummy; };
+#endif
+
+#ifndef HAVE_QOBJ_NODETYPE_CAPNP
+#define HAVE_QOBJ_NODETYPE_CAPNP -1
+struct qobj_nodetype_capnp { int dummy; };
+#endif
+
+/* each different kind of object will have a global variable of this type,
+ * which can be used by various other pieces to store type-related bits.
+ * type equality can be tested as pointer equality. (cf. QOBJ_GET_TYPESAFE)
+ */
+struct qobj_nodetype {
+ ptrdiff_t node_member_offset;
+ RESERVED_SPACE_STRUCT(qobj_nodetype_cli, cli, 256)
+ RESERVED_SPACE_STRUCT(qobj_nodetype_capnp, capnp, 256)
+};
+
+/* anchor to be embedded somewhere in the object's struct */
+struct qobj_node {
+ uint64_t nid;
+ struct qobj_nodetype *type;
+};
+
+#define QOBJ_FIELDS \
+ struct qobj_node qobj_node;
+
+/* call these at the end of any _create function (QOBJ_REG)
+ * and beginning of any _destroy function (QOBJ_UNREG) */
+#define QOBJ_REG(n, structname) \
+ qobj_reg(&n->qobj_node, &qobj_t_ ## structname)
+#define QOBJ_UNREG(n) \
+ qobj_unreg(&n->qobj_node)
+
+/* internals - should not be directly used without a good reason*/
+void qobj_reg(struct qobj_node *node, struct qobj_nodetype *type);
+void qobj_unreg(struct qobj_node *node);
+struct qobj_node *qobj_get(uint64_t id);
+void *qobj_get_typed(uint64_t id, struct qobj_nodetype *type);
+
+/* type declarations */
+#define DECLARE_QOBJ_TYPE(structname) \
+ extern struct qobj_nodetype qobj_t_ ## structname;
+#define DEFINE_QOBJ_TYPE(structname) \
+ struct qobj_nodetype qobj_t_ ## structname = { \
+ .node_member_offset = \
+ (ptrdiff_t)offsetof(struct structname, qobj_node) \
+ };
+#define DEFINE_QOBJ_TYPE_INIT(structname, ...) \
+ struct qobj_nodetype qobj_t_ ## structname = { \
+ .node_member_offset = \
+ (ptrdiff_t)offsetof(struct structname, qobj_node), \
+ __VA_ARGS__ \
+ };
+
+/* ID dereference with typecheck.
+ * will return NULL if id not found or wrong type. */
+#define QOBJ_GET_TYPESAFE(id, structname) \
+ ((struct structname *)qobj_get_typed((id), &qobj_t_ ## structname))
+
+#define QOBJ_ID(ptr) \
+ ((ptr)->qobj_node.nid)
+
+void qobj_init(void);
+void qobj_finish(void);
+
+#endif /* _QOBJ_H */
diff --git a/lib/route_types.txt b/lib/route_types.txt
index 42f3b8f32..eed4d8503 100644
--- a/lib/route_types.txt
+++ b/lib/route_types.txt
@@ -60,6 +60,17 @@ ZEBRA_ROUTE_PIM, pim, pimd, 'P', 1, 0, "PIM"
ZEBRA_ROUTE_HSLS, hsls, hslsd, 'H', 0, 0, "HSLS"
ZEBRA_ROUTE_OLSR, olsr, olsrd, 'o', 0, 0, "OLSR"
ZEBRA_ROUTE_TABLE, table, zebra, 'T', 1, 1, "Table"
+ZEBRA_ROUTE_LDP, ldp, ldpd, 'L', 0, 0, "LDP"
+#vnc when sent to zebra
+ZEBRA_ROUTE_VNC, vnc, NULL, 'v', 1, 1, "VNC"
+# vnc when sent to bgp
+ZEBRA_ROUTE_VNC_DIRECT, vpn, NULL, 'V', 1, 1, "VPN"
+# vnc when sent to bgp (remote next hop?)
+ZEBRA_ROUTE_VNC_DIRECT_RH, vpn-rh, NULL, 'V', 0, 0, "VPN"
+# bgp unicast -> vnc
+ZEBRA_ROUTE_BGP_DIRECT, bgp-direct, NULL, 'b', 0, 0, "BGP-Direct"
+# bgp unicast -> vnc
+ZEBRA_ROUTE_BGP_DIRECT_EXT, bgp-direct-to-nve-groups, NULL, 'e', 0, 0, "BGP2VNC"
## help strings
ZEBRA_ROUTE_SYSTEM, "Reserved route type, for internal use only"
@@ -74,5 +85,8 @@ ZEBRA_ROUTE_ISIS, "Intermediate System to Intermediate System (IS-IS)"
ZEBRA_ROUTE_BGP, "Border Gateway Protocol (BGP)"
ZEBRA_ROUTE_PIM, "Protocol Independent Multicast (PIM)"
ZEBRA_ROUTE_HSLS, "Hazy-Sighted Link State Protocol (HSLS)"
+ZEBRA_ROUTE_VNC, "Virtual Network Control (VNC)"
ZEBRA_ROUTE_OLSR, "Optimised Link State Routing (OLSR)"
ZEBRA_ROUTE_TABLE, "Non-main Kernel Routing Table"
+ZEBRA_ROUTE_LDP, "Label Distribution Protocol (LDP)"
+ZEBRA_ROUTE_VNC_DIRECT, "VPN routes(VPN)"
diff --git a/lib/routemap.c b/lib/routemap.c
index a68b6210b..fc2e6b7e5 100644
--- a/lib/routemap.c
+++ b/lib/routemap.c
@@ -38,6 +38,9 @@ DEFINE_MTYPE_STATIC(LIB, ROUTE_MAP_RULE_STR, "Route map rule str")
DEFINE_MTYPE( LIB, ROUTE_MAP_COMPILED, "Route map compiled")
DEFINE_MTYPE_STATIC(LIB, ROUTE_MAP_DEP, "Route map dependency")
+DEFINE_QOBJ_TYPE(route_map_index)
+DEFINE_QOBJ_TYPE(route_map)
+
/* Vector for route match rules. */
static vector route_match_vec;
@@ -743,6 +746,7 @@ route_map_new (const char *name)
new = XCALLOC (MTYPE_ROUTE_MAP, sizeof (struct route_map));
new->name = XSTRDUP (MTYPE_ROUTE_MAP_NAME, name);
+ QOBJ_REG (new, route_map);
return new;
}
@@ -803,6 +807,8 @@ route_map_free_map (struct route_map *map)
if (map != NULL)
{
+ QOBJ_UNREG (map);
+
if (map->next)
map->next->prev = map->prev;
else
@@ -1070,6 +1076,7 @@ route_map_index_new (void)
new = XCALLOC (MTYPE_ROUTE_MAP_INDEX, sizeof (struct route_map_index));
new->exitpolicy = RMAP_EXIT; /* Default to Cisco-style */
+ QOBJ_REG (new, route_map_index);
return new;
}
@@ -1079,6 +1086,8 @@ route_map_index_delete (struct route_map_index *index, int notify)
{
struct route_map_rule *rule;
+ QOBJ_UNREG (index);
+
/* Free route match. */
while ((rule = index->match_list.head) != NULL)
route_map_rule_delete (&index->match_list, rule);
@@ -1929,7 +1938,7 @@ static void
route_map_process_dependency (struct hash_backet *backet, void *data)
{
char *rmap_name;
- route_map_event_t type = (route_map_event_t )data;
+ route_map_event_t type = (route_map_event_t)(ptrdiff_t)data;
rmap_name = (char *)backet->data;
@@ -1994,9 +2003,10 @@ DEFUN (match_interface,
"Interface name\n")
{
int idx_word = 2;
+ VTY_DECLVAR_CONTEXT (route_map_index, index);
if (rmap_match_set_hook.match_interface)
- return rmap_match_set_hook.match_interface (vty, vty->index, "interface", argv[idx_word]->arg, RMAP_EVENT_MATCH_ADDED);
+ return rmap_match_set_hook.match_interface (vty, index, "interface", argv[idx_word]->arg, RMAP_EVENT_MATCH_ADDED);
return CMD_SUCCESS;
}
@@ -2009,9 +2019,10 @@ DEFUN (no_match_interface,
"Interface name\n")
{
char *iface = (argc == 4) ? argv[3]->arg : NULL;
+ VTY_DECLVAR_CONTEXT (route_map_index, index);
if (rmap_match_set_hook.no_match_interface)
- return rmap_match_set_hook.no_match_interface (vty, vty->index, "interface", iface, RMAP_EVENT_MATCH_DELETED);
+ return rmap_match_set_hook.no_match_interface (vty, index, "interface", iface, RMAP_EVENT_MATCH_DELETED);
return CMD_SUCCESS;
}
@@ -2027,9 +2038,10 @@ DEFUN (match_ip_address,
"IP Access-list name\n")
{
int idx_acl = 3;
+ VTY_DECLVAR_CONTEXT (route_map_index, index);
if (rmap_match_set_hook.match_ip_address)
- return rmap_match_set_hook.match_ip_address (vty, vty->index, "ip address", argv[idx_acl]->arg,
+ return rmap_match_set_hook.match_ip_address (vty, index, "ip address", argv[idx_acl]->arg,
RMAP_EVENT_FILTER_ADDED);
return CMD_SUCCESS;
}
@@ -2047,13 +2059,14 @@ DEFUN (no_match_ip_address,
"IP Access-list name\n")
{
int idx_word = 4;
+ VTY_DECLVAR_CONTEXT (route_map_index, index);
if (rmap_match_set_hook.no_match_ip_address)
{
if (argc <= idx_word)
- return rmap_match_set_hook.no_match_ip_address (vty, vty->index, "ip address", NULL,
+ return rmap_match_set_hook.no_match_ip_address (vty, index, "ip address", NULL,
RMAP_EVENT_FILTER_DELETED);
- return rmap_match_set_hook.no_match_ip_address (vty, vty->index, "ip address", argv[idx_word]->arg,
+ return rmap_match_set_hook.no_match_ip_address (vty, index, "ip address", argv[idx_word]->arg,
RMAP_EVENT_FILTER_DELETED);
}
return CMD_SUCCESS;
@@ -2070,8 +2083,10 @@ DEFUN (match_ip_address_prefix_list,
"IP prefix-list name\n")
{
int idx_word = 4;
+ VTY_DECLVAR_CONTEXT (route_map_index, index);
+
if (rmap_match_set_hook.match_ip_address_prefix_list)
- return rmap_match_set_hook.match_ip_address_prefix_list (vty, vty->index, "ip address prefix-list",
+ return rmap_match_set_hook.match_ip_address_prefix_list (vty, index, "ip address prefix-list",
argv[idx_word]->arg, RMAP_EVENT_PLIST_ADDED);
return CMD_SUCCESS;
}
@@ -2088,13 +2103,14 @@ DEFUN (no_match_ip_address_prefix_list,
"IP prefix-list name\n")
{
int idx_word = 5;
+ VTY_DECLVAR_CONTEXT (route_map_index, index);
if (rmap_match_set_hook.no_match_ip_address_prefix_list)
{
if (argc <= idx_word)
- return rmap_match_set_hook.no_match_ip_address_prefix_list (vty, vty->index, "ip address prefix-list",
+ return rmap_match_set_hook.no_match_ip_address_prefix_list (vty, index, "ip address prefix-list",
NULL, RMAP_EVENT_PLIST_DELETED);
- return rmap_match_set_hook.no_match_ip_address_prefix_list(vty, vty->index, "ip address prefix-list",
+ return rmap_match_set_hook.no_match_ip_address_prefix_list(vty, index, "ip address prefix-list",
argv[idx_word]->arg, RMAP_EVENT_PLIST_DELETED);
}
return CMD_SUCCESS;
@@ -2112,8 +2128,10 @@ DEFUN (match_ip_next_hop,
"IP Access-list name\n")
{
int idx_acl = 3;
+ VTY_DECLVAR_CONTEXT (route_map_index, index);
+
if (rmap_match_set_hook.match_ip_next_hop)
- return rmap_match_set_hook.match_ip_next_hop (vty, vty->index, "ip next-hop", argv[idx_acl]->arg,
+ return rmap_match_set_hook.match_ip_next_hop (vty, index, "ip next-hop", argv[idx_acl]->arg,
RMAP_EVENT_FILTER_ADDED);
return CMD_SUCCESS;
}
@@ -2130,14 +2148,15 @@ DEFUN (no_match_ip_next_hop,
"IP access-list number (expanded range)\n"
"IP Access-list name\n")
{
- int idx_word = 4;
+ int idx_word = 4;
+ VTY_DECLVAR_CONTEXT (route_map_index, index);
if (rmap_match_set_hook.no_match_ip_next_hop)
{
if (argc <= idx_word)
- return rmap_match_set_hook.no_match_ip_next_hop (vty, vty->index, "ip next-hop", NULL,
+ return rmap_match_set_hook.no_match_ip_next_hop (vty, index, "ip next-hop", NULL,
RMAP_EVENT_FILTER_DELETED);
- return rmap_match_set_hook.no_match_ip_next_hop (vty, vty->index, "ip next-hop", argv[idx_word]->arg,
+ return rmap_match_set_hook.no_match_ip_next_hop (vty, index, "ip next-hop", argv[idx_word]->arg,
RMAP_EVENT_FILTER_DELETED);
}
return CMD_SUCCESS;
@@ -2154,8 +2173,10 @@ DEFUN (match_ip_next_hop_prefix_list,
"IP prefix-list name\n")
{
int idx_word = 4;
+ VTY_DECLVAR_CONTEXT (route_map_index, index);
+
if (rmap_match_set_hook.match_ip_next_hop_prefix_list)
- return rmap_match_set_hook.match_ip_next_hop_prefix_list (vty, vty->index, "ip next-hop prefix-list",
+ return rmap_match_set_hook.match_ip_next_hop_prefix_list (vty, index, "ip next-hop prefix-list",
argv[idx_word]->arg, RMAP_EVENT_PLIST_ADDED);
return CMD_SUCCESS;
}
@@ -2171,13 +2192,14 @@ DEFUN (no_match_ip_next_hop_prefix_list,
"IP prefix-list name\n")
{
int idx_word = 5;
+ VTY_DECLVAR_CONTEXT (route_map_index, index);
if (rmap_match_set_hook.no_match_ip_next_hop)
{
if (argc <= idx_word)
- return rmap_match_set_hook.no_match_ip_next_hop (vty, vty->index, "ip next-hop prefix-list",
+ return rmap_match_set_hook.no_match_ip_next_hop (vty, index, "ip next-hop prefix-list",
NULL, RMAP_EVENT_PLIST_DELETED);
- return rmap_match_set_hook.no_match_ip_next_hop (vty, vty->index, "ip next-hop prefix-list",
+ return rmap_match_set_hook.no_match_ip_next_hop (vty, index, "ip next-hop prefix-list",
argv[idx_word]->arg, RMAP_EVENT_PLIST_DELETED);
}
return CMD_SUCCESS;
@@ -2193,8 +2215,10 @@ DEFUN (match_ipv6_address,
"IPv6 access-list name\n")
{
int idx_word = 3;
+ VTY_DECLVAR_CONTEXT (route_map_index, index);
+
if (rmap_match_set_hook.match_ipv6_address)
- return rmap_match_set_hook.match_ipv6_address (vty, vty->index, "ipv6 address", argv[idx_word]->arg,
+ return rmap_match_set_hook.match_ipv6_address (vty, index, "ipv6 address", argv[idx_word]->arg,
RMAP_EVENT_FILTER_ADDED);
return CMD_SUCCESS;
}
@@ -2209,8 +2233,10 @@ DEFUN (no_match_ipv6_address,
"IPv6 access-list name\n")
{
int idx_word = 4;
+ VTY_DECLVAR_CONTEXT (route_map_index, index);
+
if (rmap_match_set_hook.no_match_ipv6_address)
- return rmap_match_set_hook.no_match_ipv6_address (vty, vty->index, "ipv6 address", argv[idx_word]->arg,
+ return rmap_match_set_hook.no_match_ipv6_address (vty, index, "ipv6 address", argv[idx_word]->arg,
RMAP_EVENT_FILTER_DELETED);
return CMD_SUCCESS;
}
@@ -2226,8 +2252,10 @@ DEFUN (match_ipv6_address_prefix_list,
"IP prefix-list name\n")
{
int idx_word = 4;
+ VTY_DECLVAR_CONTEXT (route_map_index, index);
+
if (rmap_match_set_hook.match_ipv6_address_prefix_list)
- return rmap_match_set_hook.match_ipv6_address_prefix_list (vty, vty->index, "ipv6 address prefix-list",
+ return rmap_match_set_hook.match_ipv6_address_prefix_list (vty, index, "ipv6 address prefix-list",
argv[idx_word]->arg, RMAP_EVENT_PLIST_ADDED);
return CMD_SUCCESS;
}
@@ -2243,8 +2271,10 @@ DEFUN (no_match_ipv6_address_prefix_list,
"IP prefix-list name\n")
{
int idx_word = 5;
+ VTY_DECLVAR_CONTEXT (route_map_index, index);
+
if (rmap_match_set_hook.no_match_ipv6_address_prefix_list)
- return rmap_match_set_hook.no_match_ipv6_address_prefix_list(vty, vty->index, "ipv6 address prefix-list",
+ return rmap_match_set_hook.no_match_ipv6_address_prefix_list(vty, index, "ipv6 address prefix-list",
argv[idx_word]->arg, RMAP_EVENT_PLIST_DELETED);
return CMD_SUCCESS;
}
@@ -2258,8 +2288,10 @@ DEFUN (match_metric,
"Metric value\n")
{
int idx_number = 2;
+ VTY_DECLVAR_CONTEXT (route_map_index, index);
+
if (rmap_match_set_hook.match_metric)
- return rmap_match_set_hook.match_metric(vty, vty->index, "metric", argv[idx_number]->arg,
+ return rmap_match_set_hook.match_metric(vty, index, "metric", argv[idx_number]->arg,
RMAP_EVENT_MATCH_ADDED);
return CMD_SUCCESS;
}
@@ -2274,12 +2306,14 @@ DEFUN (no_match_metric,
"Metric value\n")
{
int idx_number = 3;
+ VTY_DECLVAR_CONTEXT (route_map_index, index);
+
if (rmap_match_set_hook.no_match_metric)
{
if (argc <= idx_number)
- return rmap_match_set_hook.no_match_metric (vty, vty->index, "metric",
+ return rmap_match_set_hook.no_match_metric (vty, index, "metric",
NULL, RMAP_EVENT_MATCH_DELETED);
- return rmap_match_set_hook.no_match_metric(vty, vty->index, "metric",
+ return rmap_match_set_hook.no_match_metric(vty, index, "metric",
argv[idx_number]->arg,
RMAP_EVENT_MATCH_DELETED);
}
@@ -2289,14 +2323,16 @@ DEFUN (no_match_metric,
DEFUN (match_tag,
match_tag_cmd,
- "match tag (1-65535)",
+ "match tag (1-4294967295)",
MATCH_STR
"Match tag of route\n"
"Tag value\n")
{
int idx_number = 2;
+ VTY_DECLVAR_CONTEXT (route_map_index, index);
+
if (rmap_match_set_hook.match_tag)
- return rmap_match_set_hook.match_tag(vty, vty->index, "tag", argv[idx_number]->arg,
+ return rmap_match_set_hook.match_tag(vty, index, "tag", argv[idx_number]->arg,
RMAP_EVENT_MATCH_ADDED);
return CMD_SUCCESS;
}
@@ -2304,14 +2340,16 @@ DEFUN (match_tag,
DEFUN (no_match_tag,
no_match_tag_cmd,
- "no match tag [(1-65535)]",
+ "no match tag [(1-4294967295)]",
NO_STR
MATCH_STR
"Match tag of route\n"
"Tag value\n")
{
+ VTY_DECLVAR_CONTEXT (route_map_index, index);
+
if (rmap_match_set_hook.no_match_tag)
- return rmap_match_set_hook.no_match_tag (vty, vty->index, "tag", argv[3]->arg,
+ return rmap_match_set_hook.no_match_tag (vty, index, "tag", argv[3]->arg,
RMAP_EVENT_MATCH_DELETED);
return CMD_SUCCESS;
}
@@ -2328,6 +2366,7 @@ DEFUN (set_ip_nexthop,
int idx_ipv4 = 3;
union sockunion su;
int ret;
+ VTY_DECLVAR_CONTEXT (route_map_index, index);
ret = str2sockunion (argv[idx_ipv4]->arg, &su);
if (ret < 0)
@@ -2344,7 +2383,7 @@ DEFUN (set_ip_nexthop,
}
if (rmap_match_set_hook.set_ip_nexthop)
- return rmap_match_set_hook.set_ip_nexthop(vty, vty->index, "ip next-hop", argv[idx_ipv4]->arg);
+ return rmap_match_set_hook.set_ip_nexthop(vty, index, "ip next-hop", argv[idx_ipv4]->arg);
return CMD_SUCCESS;
}
@@ -2359,12 +2398,13 @@ DEFUN (no_set_ip_nexthop,
"IP address of next hop\n")
{
int idx_peer = 4;
+ VTY_DECLVAR_CONTEXT (route_map_index, index);
if (rmap_match_set_hook.no_set_ip_nexthop)
{
if (argc <= idx_peer)
- return rmap_match_set_hook.no_set_ip_nexthop (vty, vty->index, "ip next-hop", NULL);
- return rmap_match_set_hook.no_set_ip_nexthop (vty, vty->index, "ip next-hop", argv[idx_peer]->arg);
+ return rmap_match_set_hook.no_set_ip_nexthop (vty, index, "ip next-hop", NULL);
+ return rmap_match_set_hook.no_set_ip_nexthop (vty, index, "ip next-hop", argv[idx_peer]->arg);
}
return CMD_SUCCESS;
}
@@ -2382,6 +2422,7 @@ DEFUN (set_ipv6_nexthop_local,
int idx_ipv6 = 4;
struct in6_addr addr;
int ret;
+ VTY_DECLVAR_CONTEXT (route_map_index, index);
ret = inet_pton (AF_INET6, argv[idx_ipv6]->arg, &addr);
if (!ret)
@@ -2396,7 +2437,7 @@ DEFUN (set_ipv6_nexthop_local,
}
if (rmap_match_set_hook.set_ipv6_nexthop_local)
- return rmap_match_set_hook.set_ipv6_nexthop_local (vty, vty->index, "ipv6 next-hop local", argv[idx_ipv6]->arg);
+ return rmap_match_set_hook.set_ipv6_nexthop_local (vty, index, "ipv6 next-hop local", argv[idx_ipv6]->arg);
return CMD_SUCCESS;
}
@@ -2412,11 +2453,13 @@ DEFUN (no_set_ipv6_nexthop_local,
"IPv6 address of next hop\n")
{
int idx_ipv6 = 5;
+ VTY_DECLVAR_CONTEXT (route_map_index, index);
+
if (rmap_match_set_hook.no_set_ipv6_nexthop_local)
{
if (argc <= idx_ipv6)
- return rmap_match_set_hook.no_set_ipv6_nexthop_local (vty, vty->index, "ipv6 next-hop local", NULL);
- return rmap_match_set_hook.no_set_ipv6_nexthop_local (vty, vty->index, "ipv6 next-hop local", argv[5]->arg);
+ return rmap_match_set_hook.no_set_ipv6_nexthop_local (vty, index, "ipv6 next-hop local", NULL);
+ return rmap_match_set_hook.no_set_ipv6_nexthop_local (vty, index, "ipv6 next-hop local", argv[5]->arg);
}
return CMD_SUCCESS;
}
@@ -2434,8 +2477,10 @@ DEFUN (set_metric,
"Subtract metric\n")
{
int idx_number = 2;
+ VTY_DECLVAR_CONTEXT (route_map_index, index);
+
if (rmap_match_set_hook.set_metric)
- return rmap_match_set_hook.set_metric (vty, vty->index, "metric", argv[idx_number]->arg);
+ return rmap_match_set_hook.set_metric (vty, index, "metric", argv[idx_number]->arg);
return CMD_SUCCESS;
}
@@ -2449,11 +2494,13 @@ DEFUN (no_set_metric,
"Metric value\n")
{
int idx_number = 3;
+ VTY_DECLVAR_CONTEXT (route_map_index, index);
+
if (rmap_match_set_hook.no_set_metric)
{
if (argc <= idx_number)
- return rmap_match_set_hook.no_set_metric (vty, vty->index, "metric", NULL);
- return rmap_match_set_hook.no_set_metric (vty, vty->index, "metric", argv[idx_number]->arg);
+ return rmap_match_set_hook.no_set_metric (vty, index, "metric", NULL);
+ return rmap_match_set_hook.no_set_metric (vty, index, "metric", argv[idx_number]->arg);
}
return CMD_SUCCESS;
}
@@ -2461,32 +2508,36 @@ DEFUN (no_set_metric,
DEFUN (set_tag,
set_tag_cmd,
- "set tag (1-65535)",
+ "set tag (1-4294967295)",
SET_STR
"Tag value for routing protocol\n"
"Tag value\n")
{
+ VTY_DECLVAR_CONTEXT (route_map_index, index);
+
int idx_number = 2;
if (rmap_match_set_hook.set_tag)
- return rmap_match_set_hook.set_tag (vty, vty->index, "tag", argv[idx_number]->arg);
+ return rmap_match_set_hook.set_tag (vty, index, "tag", argv[idx_number]->arg);
return CMD_SUCCESS;
}
DEFUN (no_set_tag,
no_set_tag_cmd,
- "no set tag [(1-65535)]",
+ "no set tag [(1-4294967295)]",
NO_STR
SET_STR
"Tag value for routing protocol\n"
"Tag value\n")
{
+ VTY_DECLVAR_CONTEXT (route_map_index, index);
+
int idx_number = 3;
if (rmap_match_set_hook.no_set_tag)
{
if (argc <= idx_number)
- return rmap_match_set_hook.no_set_tag (vty, vty->index, "tag", NULL);
- return rmap_match_set_hook.no_set_tag (vty, vty->index, "tag", argv[idx_number]->arg);
+ return rmap_match_set_hook.no_set_tag (vty, index, "tag", NULL);
+ return rmap_match_set_hook.no_set_tag (vty, index, "tag", argv[idx_number]->arg);
}
return CMD_SUCCESS;
}
@@ -2516,8 +2567,7 @@ DEFUN (route_map,
map = route_map_get (mapname);
index = route_map_index_get (map, permit, pref);
- vty->index = index;
- vty->node = RMAP_NODE;
+ VTY_PUSH_CONTEXT_COMPAT (RMAP_NODE, index);
return CMD_SUCCESS;
}
@@ -2598,9 +2648,7 @@ DEFUN (rmap_onmatch_next,
"Exit policy on matches\n"
"Next clause\n")
{
- struct route_map_index *index;
-
- index = vty->index;
+ struct route_map_index *index = VTY_GET_CONTEXT (route_map_index);
if (index)
{
@@ -2623,9 +2671,7 @@ DEFUN (no_rmap_onmatch_next,
"Exit policy on matches\n"
"Next clause\n")
{
- struct route_map_index *index;
-
- index = vty->index;
+ struct route_map_index *index = VTY_GET_CONTEXT (route_map_index);
if (index)
index->exitpolicy = RMAP_EXIT;
@@ -2643,8 +2689,9 @@ DEFUN (rmap_onmatch_goto,
int idx_number = 2;
char *num = NULL;
num = argv[idx_number]->arg;
-
- struct route_map_index *index = vty->index;
+
+
+ struct route_map_index *index = VTY_GET_CONTEXT (route_map_index);
int d = 0;
if (index)
@@ -2684,9 +2731,7 @@ DEFUN (no_rmap_onmatch_goto,
"Exit policy on matches\n"
"Goto Clause number\n")
{
- struct route_map_index *index;
-
- index = vty->index;
+ struct route_map_index *index = VTY_GET_CONTEXT (route_map_index);
if (index)
index->exitpolicy = RMAP_EXIT;
@@ -2736,10 +2781,9 @@ DEFUN (rmap_call,
"Target route-map name\n")
{
int idx_word = 1;
- struct route_map_index *index;
+ struct route_map_index *index = VTY_GET_CONTEXT (route_map_index);
const char *rmap = argv[idx_word]->arg;
- index = vty->index;
if (index)
{
if (index->nextrm)
@@ -2765,9 +2809,7 @@ DEFUN (no_rmap_call,
NO_STR
"Jump to another Route-Map after match+set\n")
{
- struct route_map_index *index;
-
- index = vty->index;
+ struct route_map_index *index = VTY_GET_CONTEXT (route_map_index);
if (index->nextrm)
{
@@ -2788,9 +2830,8 @@ DEFUN (rmap_description,
"Comment describing this route-map rule\n")
{
int idx_line = 1;
- struct route_map_index *index;
+ struct route_map_index *index = VTY_GET_CONTEXT (route_map_index);
- index = vty->index;
if (index)
{
if (index->description)
@@ -2806,9 +2847,8 @@ DEFUN (no_rmap_description,
NO_STR
"Route-map comment\n")
{
- struct route_map_index *index;
+ struct route_map_index *index = VTY_GET_CONTEXT (route_map_index);
- index = vty->index;
if (index)
{
if (index->description)
@@ -2883,6 +2923,32 @@ route_map_init_dep_hashes (void)
route_map_dep_hash_cmp);
}
+/* Common route map rules */
+
+void *
+route_map_rule_tag_compile (const char *arg)
+{
+ unsigned long int tmp;
+ char *endptr;
+ route_tag_t *tag;
+
+ errno = 0;
+ tmp = strtoul(arg, &endptr, 0);
+ if (arg[0] == '\0' || *endptr != '\0' || errno || tmp > ROUTE_TAG_MAX)
+ return NULL;
+
+ tag = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(*tag));
+ *tag = tmp;
+
+ return tag;
+}
+
+void
+route_map_rule_tag_free (void *rule)
+{
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
/* Initialization of route map vector. */
void
route_map_init_vty (void)
diff --git a/lib/routemap.h b/lib/routemap.h
index a6d312333..86d72ce47 100644
--- a/lib/routemap.h
+++ b/lib/routemap.h
@@ -24,6 +24,7 @@
#include "prefix.h"
#include "memory.h"
+#include "qobj.h"
DECLARE_MTYPE(ROUTE_MAP_NAME)
DECLARE_MTYPE(ROUTE_MAP_RULE)
DECLARE_MTYPE(ROUTE_MAP_COMPILED)
@@ -152,7 +153,10 @@ struct route_map_index
/* Make linked list. */
struct route_map_index *next;
struct route_map_index *prev;
+
+ QOBJ_FIELDS
};
+DECLARE_QOBJ_TYPE(route_map_index)
/* Route map list structure. */
struct route_map
@@ -171,7 +175,10 @@ struct route_map
/* Maintain update info */
int to_be_processed; /* True if modification isn't acted on yet */
int deleted; /* If 1, then this node will be deleted */
+
+ QOBJ_FIELDS
};
+DECLARE_QOBJ_TYPE(route_map)
/* Prototypes. */
extern void route_map_init (void);
@@ -393,4 +400,8 @@ extern void route_map_no_set_tag_hook (int (*func) (struct vty *vty,
struct route_map_index *index,
const char *command,
const char *arg));
+
+extern void *route_map_rule_tag_compile (const char *arg);
+extern void route_map_rule_tag_free (void *rule);
+
#endif /* _ZEBRA_ROUTEMAP_H */
diff --git a/lib/skiplist.c b/lib/skiplist.c
new file mode 100644
index 000000000..2a90b2c7c
--- /dev/null
+++ b/lib/skiplist.c
@@ -0,0 +1,685 @@
+/*
+ * Copyright 1990 William Pugh
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Permission to include in quagga provide on March 31, 2016
+ */
+
+/*
+ * Skip List impementation based on code from William Pugh.
+ * ftp://ftp.cs.umd.edu/pub/skipLists/
+ *
+ * Skip Lists are a probabilistic alternative to balanced trees, as
+ * described in the June 1990 issue of CACM and were invented by
+ * William Pugh in 1987.
+ *
+ * This file contains source code to implement a dictionary using
+ * skip lists and a test driver to test the routines.
+ *
+ * A couple of comments about this implementation:
+ * The routine randomLevel has been hard-coded to generate random
+ * levels using p=0.25. It can be easily changed.
+ *
+ * The insertion routine has been implemented so as to use the
+ * dirty hack described in the CACM paper: if a random level is
+ * generated that is more than the current maximum level, the
+ * current maximum level plus one is used instead.
+ *
+ * Levels start at zero and go up to MaxLevel (which is equal to
+ * (MaxNumberOfLevels-1).
+ *
+ * The run-time flag SKIPLIST_FLAG_ALLOW_DUPLICATES determines whether or
+ * not duplicates are allowed for a given list. If set, duplicates are
+ * allowed and act in a FIFO manner. If not set, an insertion of a value
+ * already in the list updates the previously existing binding.
+ *
+ * BitsInRandom is defined to be the number of bits returned by a call to
+ * random(). For most all machines with 32-bit integers, this is 31 bits
+ * as currently set.
+ */
+
+
+#include <zebra.h>
+
+#include "memory.h"
+#include "log.h"
+#include "vty.h"
+#include "skiplist.h"
+
+DEFINE_MTYPE_STATIC(LIB, SKIP_LIST, "Skip List")
+DEFINE_MTYPE_STATIC(LIB, SKIP_LIST_NODE, "Skip Node")
+
+#define BitsInRandom 31
+
+#define MaxNumberOfLevels 16
+#define MaxLevel (MaxNumberOfLevels-1)
+#define newNodeOfLevel(l) XCALLOC(MTYPE_SKIP_LIST_NODE, sizeof(struct skiplistnode)+(l)*sizeof(struct skiplistnode *))
+
+static int randomsLeft;
+static int randomBits;
+static struct skiplist *skiplist_last_created; /* debugging hack */
+
+#if 1
+#define CHECKLAST(sl) do {\
+ if ((sl)->header->forward[0] && !(sl)->last) assert(0); \
+ if (!(sl)->header->forward[0] && (sl)->last) assert(0); \
+} while (0)
+#else
+#define CHECKLAST(sl)
+#endif
+
+
+static int
+randomLevel()
+{
+ register int level = 0;
+ register int b;
+
+ do {
+ if (randomsLeft <= 0) {
+ randomBits = random();
+ randomsLeft = BitsInRandom/2;
+ }
+ b = randomBits&3;
+ randomBits>>=2;
+ --randomsLeft;
+
+ if (!b) {
+ level++;
+ if (level >= MaxLevel)
+ return MaxLevel;
+ }
+ } while (!b);
+
+ return level;
+}
+
+static int
+default_cmp(void *key1, void *key2)
+{
+ if (key1 < key2)
+ return -1;
+ if (key1 > key2)
+ return 1;
+ return 0;
+}
+
+unsigned int
+skiplist_count(struct skiplist *l)
+{
+ return l->count;
+}
+
+struct skiplist *
+skiplist_new(
+ int flags,
+ int (*cmp) (void *key1, void *key2),
+ void (*del) (void *val))
+{
+ struct skiplist *new;
+
+ new = XCALLOC (MTYPE_SKIP_LIST, sizeof (struct skiplist));
+ assert(new);
+
+ new->level = 0;
+ new->count = 0;
+ new->header = newNodeOfLevel(MaxNumberOfLevels);
+ new->stats = newNodeOfLevel(MaxNumberOfLevels);
+
+ new->flags = flags;
+ if (cmp)
+ new->cmp = cmp;
+ else
+ new->cmp = default_cmp;
+
+ if (del)
+ new->del = del;
+
+ skiplist_last_created = new; /* debug */
+
+ return new;
+}
+
+void
+skiplist_free(struct skiplist *l)
+{
+ register struct skiplistnode *p, *q;
+
+ p = l->header;
+
+ do {
+ q = p->forward[0];
+ if (l->del && p != l->header)
+ (*l->del)(p->value);
+ XFREE(MTYPE_SKIP_LIST_NODE, p);
+ p = q;
+ } while (p);
+
+ XFREE(MTYPE_SKIP_LIST_NODE, l->stats);
+ XFREE(MTYPE_SKIP_LIST, l);
+}
+
+
+int
+skiplist_insert(
+ register struct skiplist *l,
+ register void *key,
+ register void *value)
+{
+ register int k;
+ struct skiplistnode *update[MaxNumberOfLevels];
+ register struct skiplistnode *p, *q;
+
+ CHECKLAST(l);
+
+/* DEBUG */
+ if (!key) {
+ zlog_err("%s: key is 0, value is %p", __func__, value);
+ }
+
+ p = l->header;
+ k = l->level;
+ do {
+ while (q = p->forward[k], q && (*l->cmp)(q->key, key) < 0) p = q;
+ update[k] = p;
+ } while (--k >= 0);
+
+ if (!(l->flags & SKIPLIST_FLAG_ALLOW_DUPLICATES) &&
+ q && ((*l->cmp)(q->key, key) == 0)) {
+
+ return -1;
+ }
+
+ k = randomLevel();
+ if (k>l->level) {
+ k = ++l->level;
+ update[k] = l->header;
+ }
+
+ q = newNodeOfLevel(k);
+ q->key = key;
+ q->value = value;
+#if SKIPLIST_0TIMER_DEBUG
+ q->flags = SKIPLIST_NODE_FLAG_INSERTED; /* debug */
+#endif
+
+ ++(l->stats->forward[k]);
+#if SKIPLIST_DEBUG
+ zlog_debug("%s: incremented stats @%p:%d, now %ld", __func__, l, k,
+ l->stats->forward[k] - (struct skiplistnode *)NULL);
+#endif
+
+ do {
+ p = update[k];
+ q->forward[k] = p->forward[k];
+ p->forward[k] = q;
+ } while(--k>=0);
+
+ /*
+ * If this is the last item in the list, update the "last" pointer
+ */
+ if (!q->forward[0]) {
+ l->last = q;
+ }
+
+ ++(l->count);
+
+ CHECKLAST(l);
+
+ return 0;
+}
+
+int
+skiplist_delete(
+ register struct skiplist *l,
+ register void *key,
+ register void *value) /* used only if duplicates allowed */
+{
+ register int k,m;
+ struct skiplistnode *update[MaxNumberOfLevels];
+ register struct skiplistnode *p, *q;
+
+ CHECKLAST(l);
+
+ /* to make debugging easier */
+ for (k = 0; k < MaxNumberOfLevels; ++k)
+ update[k] = NULL;
+
+ p = l->header;
+ k = m = l->level;
+ do {
+ while (q = p->forward[k], q && (*l->cmp)(q->key, key) < 0) p = q;
+ update[k] = p;
+ } while(--k>=0);
+
+ if (l->flags & SKIPLIST_FLAG_ALLOW_DUPLICATES) {
+ while (q && ((*l->cmp)(q->key, key) == 0) && (q->value != value)) {
+ int i;
+ for (i = 0; i <= l->level; ++i) {
+ if (update[i]->forward[i] == q)
+ update[i] = q;
+ }
+ q = q->forward[0];
+ }
+ }
+
+ if (q && (*l->cmp)(q->key, key) == 0) {
+ if (!(l->flags & SKIPLIST_FLAG_ALLOW_DUPLICATES) ||
+ (q->value == value)) {
+
+ /*
+ * found node to delete
+ */
+#if SKIPLIST_0TIMER_DEBUG
+ q->flags &= ~SKIPLIST_NODE_FLAG_INSERTED;
+#endif
+ /*
+ * If we are deleting the last element of the list,
+ * update the list's "last" pointer.
+ */
+ if (l->last == q) {
+ if (update[0] == l->header)
+ l->last = NULL;
+ else
+ l->last = update[0];
+ }
+
+ for(k=0; k<=m && (p=update[k])->forward[k] == q; k++) {
+ p->forward[k] = q->forward[k];
+ }
+ --(l->stats->forward[k-1]);
+#if SKIPLIST_DEBUG
+ zlog_debug("%s: decremented stats @%p:%d, now %ld",
+ __func__, l, k-1,
+ l->stats->forward[k-1] - (struct skiplistnode *)NULL);
+#endif
+ if (l->del)
+ (*l->del)(q->value);
+ XFREE(MTYPE_SKIP_LIST_NODE, q);
+ while( l->header->forward[m] == NULL && m > 0 )
+ m--;
+ l->level = m;
+ CHECKLAST(l);
+ --(l->count);
+ return 0;
+ }
+ }
+
+ CHECKLAST(l);
+ return -1;
+}
+
+/*
+ * Obtain first value matching "key". Unless SKIPLIST_FLAG_ALLOW_DUPLICATES
+ * is set, this will also be the only value matching "key".
+ *
+ * Also set a cursor for use with skiplist_next_value.
+ */
+int
+skiplist_first_value(
+ register struct skiplist *l, /* in */
+ register void *key, /* in */
+ void **valuePointer, /* out */
+ void **cursor) /* out */
+{
+ register int k;
+ register struct skiplistnode *p, *q;
+
+ p = l->header;
+ k = l->level;
+
+ do {
+ while (q = p->forward[k], q && (*l->cmp)(q->key, key) < 0)
+ p = q;
+
+ } while (--k >= 0);
+
+ if (!q || (*l->cmp)(q->key, key))
+ return -1;
+
+ if (valuePointer)
+ *valuePointer = q->value;
+
+ if (cursor)
+ *cursor = q;
+
+ return 0;
+}
+
+int
+skiplist_search(
+ register struct skiplist *l,
+ register void *key,
+ void **valuePointer)
+{
+ return skiplist_first_value(l, key, valuePointer, NULL);
+}
+
+
+/*
+ * Caller supplies key and value of an existing item in the list.
+ * Function returns the value of the next list item that has the
+ * same key (useful when SKIPLIST_FLAG_ALLOW_DUPLICATES is set).
+ *
+ * Returns 0 on success. If the caller-supplied key and value
+ * do not correspond to a list element, or if they specify the
+ * last element with the given key, -1 is returned.
+ */
+int
+skiplist_next_value(
+ register struct skiplist *l, /* in */
+ register void *key, /* in */
+ void **valuePointer, /* in/out */
+ void **cursor) /* in/out */
+{
+ register int k,m;
+ register struct skiplistnode *p, *q;
+
+ CHECKLAST(l);
+
+ if (!(l->flags & SKIPLIST_FLAG_ALLOW_DUPLICATES)) {
+ return -1;
+ }
+
+ if (!cursor || !*cursor) {
+ p = l->header;
+ k = m = l->level;
+
+ /*
+ * Find matching key
+ */
+ do {
+ while (q = p->forward[k], q && (*l->cmp)(q->key, key) < 0)
+ p = q;
+ } while(--k>=0);
+
+ /*
+ * Find matching value
+ */
+ while (q && ((*l->cmp)(q->key, key) == 0) && (q->value != *valuePointer)) {
+ q = q->forward[0];
+ }
+
+ if (!q || ((*l->cmp)(q->key, key) != 0) || (q->value != *valuePointer)) {
+ /*
+ * No matching value
+ */
+ CHECKLAST(l);
+ return -1;
+ }
+ } else {
+ q = (struct skiplistnode *)*cursor;
+ }
+
+ /*
+ * Advance cursor
+ */
+ q = q->forward[0];
+
+ /*
+ * If we reached end-of-list or if the key is no longer the same,
+ * then return error
+ */
+ if (!q || ((*l->cmp)(q->key, key) != 0))
+ return -1;
+
+ *valuePointer = q->value;
+ *cursor = q;
+ CHECKLAST(l);
+ return 0;
+}
+
+int
+skiplist_first(
+ register struct skiplist *l,
+ void **keyPointer,
+ void **valuePointer)
+{
+ register struct skiplistnode *p;
+
+ CHECKLAST(l);
+ p = l->header->forward[0];
+ if (!p)
+ return -1;
+
+ if (keyPointer)
+ *keyPointer = p->key;
+
+ if (valuePointer)
+ *valuePointer = p->value;
+
+ CHECKLAST(l);
+
+ return 0;
+}
+
+int
+skiplist_last(
+ register struct skiplist *l,
+ void **keyPointer,
+ void **valuePointer)
+{
+ CHECKLAST(l);
+ if (l->last) {
+ if (keyPointer)
+ *keyPointer = l->last->key;
+ if (valuePointer)
+ *valuePointer = l->last->value;
+ return 0;
+ }
+ return -1;
+}
+
+/*
+ * true = empty
+ */
+int
+skiplist_empty(
+ register struct skiplist *l)
+{
+ CHECKLAST(l);
+ if (l->last)
+ return 0;
+ return 1;
+}
+
+/*
+ * Use this to walk the list. Caller sets *cursor to NULL to obtain
+ * first element. Return value of 0 indicates valid cursor/element
+ * returned, otherwise NULL cursor arg or EOL.
+ */
+int
+skiplist_next(
+ register struct skiplist *l, /* in */
+ void **keyPointer, /* out */
+ void **valuePointer, /* out */
+ void **cursor) /* in/out */
+{
+ struct skiplistnode *p;
+
+ if (!cursor)
+ return -1;
+
+ CHECKLAST(l);
+
+ if (!*cursor) {
+ p = l->header->forward[0];
+ } else {
+ p = *cursor;
+ p = p->forward[0];
+ }
+ *cursor = p;
+
+ if (!p)
+ return -1;
+
+ if (keyPointer)
+ *keyPointer = p->key;
+
+ if (valuePointer)
+ *valuePointer = p->value;
+
+ CHECKLAST(l);
+
+ return 0;
+}
+
+int
+skiplist_delete_first(
+ register struct skiplist *l)
+{
+ register int k;
+ register struct skiplistnode *p, *q;
+ int nodelevel = 0;
+
+ CHECKLAST(l);
+
+ p = l->header;
+ q = l->header->forward[0];
+
+ if (!q)
+ return -1;
+
+ for (k = l->level; k >= 0; --k) {
+ if (p->forward[k] == q) {
+ p->forward[k] = q->forward[k];
+ if ((k == l->level) && (p->forward[k] == NULL) && (l->level > 0))
+ --(l->level);
+ if (!nodelevel)
+ nodelevel = k;
+ }
+ }
+
+#if SKIPLIST_0TIMER_DEBUG
+ q->flags &= ~SKIPLIST_NODE_FLAG_INSERTED;
+#endif
+ /*
+ * If we are deleting the last element of the list,
+ * update the list's "last" pointer.
+ */
+ if (l->last == q) {
+ l->last = NULL;
+ }
+
+ --(l->stats->forward[nodelevel]);
+#if SKIPLIST_DEBUG
+ zlog_debug("%s: decremented stats @%p:%d, now %ld", __func__, l, nodelevel,
+ l->stats->forward[nodelevel] - (struct skiplistnode *)NULL);
+#endif
+
+ if (l->del)
+ (*l->del)(q->value);
+
+ XFREE(MTYPE_SKIP_LIST_NODE, q);
+
+ CHECKLAST(l);
+
+ --(l->count);
+
+ return 0;
+}
+
+void
+skiplist_debug(struct vty *vty, struct skiplist *l)
+{
+ int i;
+
+ if (!l)
+ l = skiplist_last_created;
+ vty_out(vty, "Skiplist %p has max level %d%s", l, l->level, VTY_NEWLINE);
+ for (i = l->level; i >= 0; --i)
+ vty_out(vty, " @%d: %ld%s",
+ i, (long)((l->stats->forward[i]) - (struct skiplistnode *)NULL),
+ VTY_NEWLINE);
+}
+
+static void *
+scramble(int i)
+{
+ uintptr_t result;
+
+ result = (i & 0xff) << 24;
+ result |= (i >> 8);
+
+ return (void *)result;
+}
+
+#define sampleSize 65536
+void
+skiplist_test(struct vty *vty) {
+ struct skiplist *l;
+ register int i,k;
+ void *keys[sampleSize];
+ void *v;
+
+ zlog_debug("%s: entry", __func__);
+
+ l= skiplist_new(SKIPLIST_FLAG_ALLOW_DUPLICATES, NULL, NULL);
+
+ zlog_debug("%s: skiplist_new returned %p", __func__, l);
+
+ for (i=0; i < 4; i++) {
+
+ for (k=0; k < sampleSize; k++) {
+ if (!(k%1000)) {
+ zlog_debug("%s: (%d:%d)", __func__, i, k);
+ }
+ //keys[k] = (void *)random();
+ keys[k] = (void *)scramble(k);
+ if (skiplist_insert(l, keys[k], keys[k]))
+ zlog_debug("error in insert #%d,#%d",i,k);
+ }
+
+ zlog_debug("%s: inserts done", __func__);
+
+ for (k=0; k < sampleSize; k++) {
+
+ if (!(k % 1000))
+ zlog_debug("[%d:%d]", i, k);
+ if (skiplist_search(l, keys[k], &v))
+ zlog_debug("error in search #%d,#%d",i,k);
+
+ if (v != keys[k])
+ zlog_debug("search returned wrong value");
+ }
+
+
+
+ for (k=0; k < sampleSize; k++) {
+
+ if (!(k % 1000))
+ zlog_debug("<%d:%d>", i, k);
+ if (skiplist_delete(l, keys[k], keys[k]))
+ zlog_debug("error in delete");
+ keys[k] = (void *)scramble(k ^ 0xf0f0f0f0);
+ if (skiplist_insert(l, keys[k], keys[k]))
+ zlog_debug("error in insert #%d,#%d",i,k);
+ }
+
+ for (k=0; k < sampleSize; k++) {
+
+ if (!(k % 1000))
+ zlog_debug("{%d:%d}", i, k);
+ if (skiplist_delete_first(l))
+ zlog_debug("error in delete_first");
+ }
+ }
+
+ skiplist_free(l);
+}
+
diff --git a/lib/skiplist.h b/lib/skiplist.h
new file mode 100644
index 000000000..25775f754
--- /dev/null
+++ b/lib/skiplist.h
@@ -0,0 +1,159 @@
+/*
+ * Copyright 1990 William Pugh
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Permission to include in quagga provide on March 31, 2016
+ */
+
+/*
+ * Skip List impementation based on code from William Pugh.
+ * ftp://ftp.cs.umd.edu/pub/skipLists/
+ */
+
+/* skiplist.h */
+
+
+#ifndef _ZEBRA_SKIPLIST_H
+#define _ZEBRA_SKIPLIST_H
+
+#define SKIPLIST_0TIMER_DEBUG 1
+
+/*
+ * skiplistnodes must always contain data to be valid. Adding an
+ * empty node to a list is invalid
+ */
+struct skiplistnode
+{
+ void *key;
+ void *value;
+#if SKIPLIST_0TIMER_DEBUG
+ int flags;
+#define SKIPLIST_NODE_FLAG_INSERTED 0x00000001
+#endif
+
+ struct skiplistnode *forward[1]; /* variable sized */
+};
+
+struct skiplist
+{
+ int flags;
+
+#define SKIPLIST_FLAG_ALLOW_DUPLICATES 0x00000001
+
+ int level; /* max lvl (1 + current # of levels in list) */
+ unsigned int count;
+ struct skiplistnode *header;
+ struct skiplistnode *stats;
+ struct skiplistnode *last; /* last real list item (NULL if empty list) */
+
+ /*
+ * Returns -1 if val1 < val2, 0 if equal?, 1 if val1 > val2.
+ * Used as definition of sorted for listnode_add_sort
+ */
+ int (*cmp) (void *val1, void *val2);
+
+ /* callback to free user-owned data when listnode is deleted. supplying
+ * this callback is very much encouraged!
+ */
+ void (*del) (void *val);
+};
+
+
+/* Prototypes. */
+extern struct skiplist *
+skiplist_new( /* encouraged: set list.del callback on new lists */
+ int flags,
+ int (*cmp) (void *key1, void *key2), /* NULL => default cmp */
+ void (*del) (void *val)); /* NULL => no auto val free */
+
+extern void
+skiplist_free (struct skiplist *);
+
+extern int
+skiplist_insert(
+ register struct skiplist *l,
+ register void *key,
+ register void *value);
+
+extern int
+skiplist_delete(
+ register struct skiplist *l,
+ register void *key,
+ register void *value);
+
+extern int
+skiplist_search(
+ register struct skiplist *l,
+ register void *key,
+ void **valuePointer);
+
+extern int
+skiplist_first_value(
+ register struct skiplist *l, /* in */
+ register void *key, /* in */
+ void **valuePointer, /* in/out */
+ void **cursor); /* out */
+
+extern int
+skiplist_next_value(
+ register struct skiplist *l, /* in */
+ register void *key, /* in */
+ void **valuePointer, /* in/out */
+ void **cursor); /* in/out */
+
+extern int
+skiplist_first(
+ register struct skiplist *l,
+ void **keyPointer,
+ void **valuePointer);
+
+extern int
+skiplist_last(
+ register struct skiplist *l,
+ void **keyPointer,
+ void **valuePointer);
+
+extern int
+skiplist_delete_first(
+ register struct skiplist *l);
+
+extern int
+skiplist_next(
+ register struct skiplist *l, /* in */
+ void **keyPointer, /* out */
+ void **valuePointer, /* out */
+ void **cursor); /* in/out */
+
+extern int
+skiplist_empty(
+ register struct skiplist *l); /* in */
+
+extern unsigned int
+skiplist_count(
+ register struct skiplist *l); /* in */
+
+extern void
+skiplist_debug(
+ struct vty *vty,
+ struct skiplist *l);
+
+extern void
+skiplist_test(
+ struct vty *vty);
+
+#endif /* _ZEBRA_SKIPLIST_H */
diff --git a/lib/sockopt.c b/lib/sockopt.c
index 31b2edbac..c480cee0d 100644
--- a/lib/sockopt.c
+++ b/lib/sockopt.c
@@ -20,6 +20,11 @@
*/
#include <zebra.h>
+
+#ifdef SUNOS_5
+#include <ifaddrs.h>
+#endif
+
#include "log.h"
#include "sockopt.h"
#include "sockunion.h"
@@ -346,6 +351,35 @@ setsockopt_ipv4_multicast_if(int sock, struct in_addr if_addr,
#endif
return setsockopt (sock, IPPROTO_IP, IP_MULTICAST_IF, (void *)&m, sizeof(m));
+#elif defined(SUNOS_5)
+ char ifname[IF_NAMESIZE];
+ struct ifaddrs *ifa, *ifap;
+ struct in_addr ifaddr;
+
+ if (if_indextoname(ifindex, ifname) == NULL)
+ return -1;
+
+ if (getifaddrs(&ifa) != 0)
+ return -1;
+
+ for (ifap = ifa; ifap != NULL; ifap = ifap->ifa_next)
+ {
+ struct sockaddr_in *sa;
+
+ if (strcmp(ifap->ifa_name, ifname) != 0)
+ continue;
+ if (ifap->ifa_addr->sa_family != AF_INET)
+ continue;
+ sa = (struct sockaddr_in*)ifap->ifa_addr;
+ memcpy(&ifaddr, &sa->sin_addr, sizeof(ifaddr));
+ break;
+ }
+
+ freeifaddrs(ifa);
+ if (!ifap) /* This means we did not find an IP */
+ return -1;
+
+ return setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF, (void *)&ifaddr, sizeof(ifaddr));
#else
#error "Unsupported multicast API"
#endif
diff --git a/lib/sockunion.h b/lib/sockunion.h
index 105b11a24..7dbd247dc 100644
--- a/lib/sockunion.h
+++ b/lib/sockunion.h
@@ -25,12 +25,18 @@
#include "privs.h"
#include "if.h"
+#ifdef __OpenBSD__
+#include <netmpls/mpls.h>
+#endif
union sockunion
{
struct sockaddr sa;
struct sockaddr_in sin;
struct sockaddr_in6 sin6;
+#ifdef __OpenBSD__
+ struct sockaddr_mpls smpls;
+#endif
};
enum connect_result
diff --git a/lib/table.c b/lib/table.c
index 8858aea0f..d0e084ead 100644
--- a/lib/table.c
+++ b/lib/table.c
@@ -523,6 +523,12 @@ static route_table_delegate_t default_delegate = {
.destroy_node = route_node_destroy
};
+route_table_delegate_t *
+route_table_get_default_delegate(void)
+{
+ return &default_delegate;
+}
+
/*
* route_table_init
*/
diff --git a/lib/table.h b/lib/table.h
index 34c196aa4..e6cdcfef1 100644
--- a/lib/table.h
+++ b/lib/table.h
@@ -144,6 +144,9 @@ extern struct route_table *route_table_init (void);
extern struct route_table *
route_table_init_with_delegate (route_table_delegate_t *);
+extern route_table_delegate_t *
+route_table_get_default_delegate(void);
+
extern void route_table_finish (struct route_table *);
extern void route_unlock_node (struct route_node *node);
extern struct route_node *route_top (struct route_table *);
diff --git a/lib/thread.c b/lib/thread.c
index 76acd0778..5dc296f2c 100644
--- a/lib/thread.c
+++ b/lib/thread.c
@@ -222,12 +222,12 @@ vty_out_cpu_thread_history(struct vty* vty,
struct cpu_thread_history *a)
{
#ifdef HAVE_RUSAGE
- vty_out(vty, "%7ld.%03ld %9d %8ld %9ld %8ld %9ld",
+ vty_out(vty, "%10ld.%03ld %9d %8ld %9ld %8ld %9ld",
a->cpu.total/1000, a->cpu.total%1000, a->total_calls,
a->cpu.total/a->total_calls, a->cpu.max,
a->real.total/a->total_calls, a->real.max);
#else
- vty_out(vty, "%7ld.%03ld %9d %8ld %9ld",
+ vty_out(vty, "%10ld.%03ld %9d %8ld %9ld",
a->real.total/1000, a->real.total%1000, a->total_calls,
a->real.total/a->total_calls, a->real.max);
#endif
diff --git a/lib/vrf.c b/lib/vrf.c
index 6de224f8c..63adea4ae 100644
--- a/lib/vrf.c
+++ b/lib/vrf.c
@@ -33,6 +33,8 @@
DEFINE_MTYPE_STATIC(LIB, VRF, "VRF")
DEFINE_MTYPE_STATIC(LIB, VRF_BITMAP, "VRF bit-map")
+DEFINE_QOBJ_TYPE(vrf)
+
/*
* Turn on/off debug code
* for vrf.
@@ -124,6 +126,7 @@ vrf_get (vrf_id_t vrf_id, const char *name)
strcpy (vrf->name, name);
listnode_add_sort (vrf_list, vrf);
if_init (&vrf->iflist);
+ QOBJ_REG (vrf, vrf);
if (vrf_master.vrf_new_hook)
{
(*vrf_master.vrf_new_hook) (vrf_id, name, &vrf->info);
@@ -212,6 +215,7 @@ vrf_get (vrf_id_t vrf_id, const char *name)
strcpy (vrf->name, name);
listnode_add_sort (vrf_list, vrf);
if_init (&vrf->iflist);
+ QOBJ_REG (vrf, vrf);
if (vrf_master.vrf_new_hook)
{
(*vrf_master.vrf_new_hook) (vrf_id, name, &vrf->info);
@@ -249,6 +253,7 @@ vrf_get (vrf_id_t vrf_id, const char *name)
vrf->node = rn;
vrf->vrf_id = vrf_id;
if_init (&vrf->iflist);
+ QOBJ_REG (vrf, vrf);
if (debug_vrf)
zlog_debug("Vrf Created: %p", vrf);
return vrf;
@@ -275,6 +280,7 @@ vrf_delete (struct vrf *vrf)
if (vrf_master.vrf_delete_hook)
(*vrf_master.vrf_delete_hook) (vrf->vrf_id, vrf->name, &vrf->info);
+ QOBJ_UNREG (vrf);
if_terminate (&vrf->iflist);
if (vrf->node)
@@ -738,7 +744,7 @@ vrf_socket (int domain, int type, int protocol, vrf_id_t vrf_id)
* Debug CLI for vrf's
*/
DEFUN (vrf_debug,
- vrf_debug_cmd,
+ vrf_debug_cmd,
"debug vrf",
DEBUG_STR
"VRF Debugging\n")
@@ -749,7 +755,7 @@ DEFUN (vrf_debug,
}
DEFUN (no_vrf_debug,
- no_vrf_debug_cmd,
+ no_vrf_debug_cmd,
"no debug vrf",
NO_STR
DEBUG_STR
diff --git a/lib/vrf.h b/lib/vrf.h
index e0fd25b9b..f1fbad9ff 100644
--- a/lib/vrf.h
+++ b/lib/vrf.h
@@ -24,6 +24,7 @@
#define _ZEBRA_VRF_H
#include "linklist.h"
+#include "qobj.h"
/* The default NS ID */
#define NS_DEFAULT 0
@@ -81,7 +82,10 @@ struct vrf
/* User data */
void *info;
+
+ QOBJ_FIELDS
};
+DECLARE_QOBJ_TYPE(vrf)
extern struct list *vrf_list;
diff --git a/lib/vty.c b/lib/vty.c
index ee7ea579a..78bf0e720 100644
--- a/lib/vty.c
+++ b/lib/vty.c
@@ -83,14 +83,11 @@ char *vty_cwd = NULL;
/* Configure lock. */
static int vty_config;
+static int vty_config_is_lockless = 0;
/* Login password check. */
static int no_password_check = 0;
-/* Restrict unauthenticated logins? */
-static const u_char restricted_mode_default = 0;
-static u_char restricted_mode = 0;
-
/* Integrated configuration file path */
char integrate_default[] = SYSCONFDIR INTEGRATE_DEFAULT_CONFIG;
@@ -394,7 +391,7 @@ vty_auth (struct vty *vty, char *buf)
/* AUTH_ENABLE_NODE */
vty->fail = 0;
vty_out (vty, "%% Bad enable passwords, too many failures!%s", VTY_NEWLINE);
- vty->node = restricted_mode ? RESTRICTED_NODE : VIEW_NODE;
+ vty->status = VTY_CLOSE;
}
}
}
@@ -734,7 +731,6 @@ vty_end_config (struct vty *vty)
{
case VIEW_NODE:
case ENABLE_NODE:
- case RESTRICTED_NODE:
/* Nothing to do. */
break;
case CONFIG_NODE:
@@ -747,6 +743,9 @@ vty_end_config (struct vty *vty)
case BGP_VPNV6_NODE:
case BGP_ENCAP_NODE:
case BGP_ENCAPV6_NODE:
+ case BGP_VNC_DEFAULTS_NODE:
+ case BGP_VNC_NVE_GROUP_NODE:
+ case BGP_VNC_L2_GROUP_NODE:
case BGP_IPV4_NODE:
case BGP_IPV4M_NODE:
case BGP_IPV6_NODE:
@@ -754,6 +753,13 @@ vty_end_config (struct vty *vty)
case RMAP_NODE:
case OSPF_NODE:
case OSPF6_NODE:
+ case LDP_NODE:
+ case LDP_IPV4_NODE:
+ case LDP_IPV6_NODE:
+ case LDP_IPV4_IFACE_NODE:
+ case LDP_IPV6_IFACE_NODE:
+ case LDP_L2VPN_NODE:
+ case LDP_PSEUDOWIRE_NODE:
case ISIS_NODE:
case KEYCHAIN_NODE:
case KEYCHAIN_KEY_NODE:
@@ -1144,7 +1150,6 @@ vty_stop_input (struct vty *vty)
{
case VIEW_NODE:
case ENABLE_NODE:
- case RESTRICTED_NODE:
/* Nothing to do. */
break;
case CONFIG_NODE:
@@ -1156,6 +1161,13 @@ vty_stop_input (struct vty *vty)
case RMAP_NODE:
case OSPF_NODE:
case OSPF6_NODE:
+ case LDP_NODE:
+ case LDP_IPV4_NODE:
+ case LDP_IPV6_NODE:
+ case LDP_IPV4_IFACE_NODE:
+ case LDP_IPV6_IFACE_NODE:
+ case LDP_L2VPN_NODE:
+ case LDP_PSEUDOWIRE_NODE:
case ISIS_NODE:
case KEYCHAIN_NODE:
case KEYCHAIN_KEY_NODE:
@@ -1697,9 +1709,7 @@ vty_create (int vty_sock, union sockunion *su)
strcpy (vty->address, buf);
if (no_password_check)
{
- if (restricted_mode)
- vty->node = RESTRICTED_NODE;
- else if (host.advanced)
+ if (host.advanced)
vty->node = ENABLE_NODE;
else
vty->node = VIEW_NODE;
@@ -2620,6 +2630,8 @@ vty_log_fixed (char *buf, size_t len)
int
vty_config_lock (struct vty *vty)
{
+ if (vty_config_is_lockless)
+ return 1;
if (vty_config == 0)
{
vty->config = 1;
@@ -2631,6 +2643,8 @@ vty_config_lock (struct vty *vty)
int
vty_config_unlock (struct vty *vty)
{
+ if (vty_config_is_lockless)
+ return 0;
if (vty_config == 1 && vty->config == 1)
{
vty->config = 0;
@@ -2639,6 +2653,12 @@ vty_config_unlock (struct vty *vty)
return vty->config;
}
+void
+vty_config_lockless (void)
+{
+ vty_config_is_lockless = 1;
+}
+
/* Master of the threads. */
static struct thread_master *vty_master;
@@ -2884,26 +2904,6 @@ DEFUN (no_vty_login,
return CMD_SUCCESS;
}
-/* initial mode. */
-DEFUN (vty_restricted_mode,
- vty_restricted_mode_cmd,
- "anonymous restricted",
- "Restrict view commands available in anonymous, unauthenticated vty\n")
-{
- restricted_mode = 1;
- return CMD_SUCCESS;
-}
-
-DEFUN (vty_no_restricted_mode,
- vty_no_restricted_mode_cmd,
- "no anonymous restricted",
- NO_STR
- "Enable password checking\n")
-{
- restricted_mode = 0;
- return CMD_SUCCESS;
-}
-
DEFUN (service_advanced_vty,
service_advanced_vty_cmd,
"service advanced-vty",
@@ -3017,14 +3017,6 @@ vty_config_write (struct vty *vty)
if (no_password_check)
vty_out (vty, " no login%s", VTY_NEWLINE);
- if (restricted_mode != restricted_mode_default)
- {
- if (restricted_mode_default)
- vty_out (vty, " no anonymous restricted%s", VTY_NEWLINE);
- else
- vty_out (vty, " anonymous restricted%s", VTY_NEWLINE);
- }
-
if (do_log_commands)
vty_out (vty, "log commands%s", VTY_NEWLINE);
@@ -3153,11 +3145,8 @@ vty_init (struct thread_master *master_thread)
/* Install bgp top node. */
install_node (&vty_node, vty_config_write);
- install_element (RESTRICTED_NODE, &config_who_cmd);
- install_element (RESTRICTED_NODE, &show_history_cmd);
install_element (VIEW_NODE, &config_who_cmd);
install_element (VIEW_NODE, &show_history_cmd);
- install_element (ENABLE_NODE, &config_who_cmd);
install_element (CONFIG_NODE, &line_vty_cmd);
install_element (CONFIG_NODE, &service_advanced_vty_cmd);
install_element (CONFIG_NODE, &no_service_advanced_vty_cmd);
@@ -3166,7 +3155,6 @@ vty_init (struct thread_master *master_thread)
install_element (ENABLE_NODE, &terminal_monitor_cmd);
install_element (ENABLE_NODE, &terminal_no_monitor_cmd);
install_element (ENABLE_NODE, &no_terminal_monitor_cmd);
- install_element (ENABLE_NODE, &show_history_cmd);
install_default (VTY_NODE);
install_element (VTY_NODE, &exec_timeout_min_cmd);
@@ -3176,8 +3164,6 @@ vty_init (struct thread_master *master_thread)
install_element (VTY_NODE, &no_vty_access_class_cmd);
install_element (VTY_NODE, &vty_login_cmd);
install_element (VTY_NODE, &no_vty_login_cmd);
- install_element (VTY_NODE, &vty_restricted_mode_cmd);
- install_element (VTY_NODE, &vty_no_restricted_mode_cmd);
#ifdef HAVE_IPV6
install_element (VTY_NODE, &vty_ipv6_access_class_cmd);
install_element (VTY_NODE, &no_vty_ipv6_access_class_cmd);
@@ -3197,3 +3183,29 @@ vty_terminate (void)
vector_free (Vvty_serv_thread);
}
}
+
+/* Utility functions to get arguments from commands generated
+ by the xml2cli.pl script. */
+const char *
+vty_get_arg_value (struct vty_arg *args[], const char *arg)
+{
+ while (*args)
+ {
+ if (strcmp ((*args)->name, arg) == 0)
+ return (*args)->value;
+ args++;
+ }
+ return NULL;
+}
+
+struct vty_arg *
+vty_get_arg (struct vty_arg *args[], const char *arg)
+{
+ while (*args)
+ {
+ if (strcmp ((*args)->name, arg) == 0)
+ return *args;
+ args++;
+ }
+ return NULL;
+}
diff --git a/lib/vty.h b/lib/vty.h
index fe051f053..3870e59b7 100644
--- a/lib/vty.h
+++ b/lib/vty.h
@@ -24,12 +24,20 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "thread.h"
#include "log.h"
#include "sockunion.h"
+#include "qobj.h"
#define VTY_BUFSIZ 512
#define VTY_MAXHIST 20
+#if defined(VTY_DEPRECATE_INDEX) && defined(__GNUC__) && \
+ (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
+#define INDEX_WARNING __attribute__((deprecated))
+#else
+#define INDEX_WARNING
+#endif
+
/* VTY struct. */
-struct vty
+struct vty
{
/* File descripter of this vty. */
int fd;
@@ -75,10 +83,13 @@ struct vty
/* For current referencing point of interface, route-map,
access-list etc... */
- void *index;
+ void *index INDEX_WARNING;
- /* For multiple level index treatment such as key chain and key. */
- void *index_sub;
+ /* qobj object ID (replacement for "index") */
+ uint64_t qobj_index;
+
+ /* qobj second-level object ID (replacement for "index_sub") */
+ uint64_t qobj_index_sub;
/* For escape character. */
unsigned char escape;
@@ -127,6 +138,64 @@ struct vty
char address[SU_ADDRSTRLEN];
};
+#undef INDEX_WARNING
+
+static inline void vty_push_context(struct vty *vty,
+ int node, uint64_t id, void *idx)
+{
+ vty->node = node;
+ vty->qobj_index = id;
+#if defined(VTY_DEPRECATE_INDEX) && defined(__GNUC__) && \
+ (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+ vty->index = idx;
+#pragma GCC diagnostic pop
+#else
+ vty->index = idx;
+#endif
+}
+
+#define VTY_PUSH_CONTEXT(nodeval, ptr) \
+ vty_push_context(vty, nodeval, QOBJ_ID(ptr), NULL)
+#define VTY_PUSH_CONTEXT_COMPAT(nodeval, ptr) \
+ vty_push_context(vty, nodeval, QOBJ_ID(ptr), ptr)
+#define VTY_PUSH_CONTEXT_SUB(nodeval, ptr) do { \
+ vty->node = nodeval; \
+ /* qobj_index stays untouched */ \
+ vty->qobj_index_sub = QOBJ_ID(ptr); \
+ } while (0)
+
+/* can return NULL if context is invalid! */
+#define VTY_GET_CONTEXT(structname) \
+ QOBJ_GET_TYPESAFE(vty->qobj_index, structname)
+#define VTY_GET_CONTEXT_SUB(structname) \
+ QOBJ_GET_TYPESAFE(vty->qobj_index_sub, structname)
+
+/* will return if ptr is NULL. */
+#define VTY_CHECK_CONTEXT(ptr) \
+ if (!ptr) { \
+ vty_out (vty, "Current configuration object was deleted " \
+ "by another process.%s", VTY_NEWLINE); \
+ return CMD_WARNING; \
+ }
+
+/* struct structname *ptr = <context>; ptr will never be NULL. */
+#define VTY_DECLVAR_CONTEXT(structname, ptr) \
+ struct structname *ptr = VTY_GET_CONTEXT(structname); \
+ VTY_CHECK_CONTEXT(ptr);
+#define VTY_DECLVAR_CONTEXT_SUB(structname, ptr) \
+ struct structname *ptr = VTY_GET_CONTEXT_SUB(structname); \
+ VTY_CHECK_CONTEXT(ptr);
+
+struct vty_arg
+{
+ const char *name;
+ const char *value;
+ const char **argv;
+ int argc;
+};
+
/* Integrated configuration file. */
#define INTEGRATE_DEFAULT_CONFIG "Quagga.conf"
@@ -231,33 +300,33 @@ do { \
VTY_GET_INTEGER_RANGE_HEART(NAME,tmpl,STR,MIN,MAX); \
} while (0)
-#define VTY_GET_INTEGER(NAME,V,STR) \
+#define VTY_GET_INTEGER(NAME,V,STR) \
VTY_GET_INTEGER_RANGE(NAME,V,STR,0U,UINT32_MAX)
-#define VTY_GET_IPV4_ADDRESS(NAME,V,STR) \
-do { \
- int retv; \
- retv = inet_aton ((STR), &(V)); \
- if (!retv) \
- { \
- vty_out (vty, "%% Invalid %s value%s", NAME, VTY_NEWLINE); \
- return CMD_WARNING; \
- } \
+#define VTY_GET_IPV4_ADDRESS(NAME,V,STR) \
+do { \
+ int retv; \
+ retv = inet_aton ((STR), &(V)); \
+ if (!retv) \
+ { \
+ vty_out (vty, "%% Invalid %s value%s", NAME, VTY_NEWLINE); \
+ return CMD_WARNING; \
+ } \
} while (0)
-#define VTY_GET_IPV4_PREFIX(NAME,V,STR) \
-do { \
- int retv; \
- retv = str2prefix_ipv4 ((STR), &(V)); \
- if (retv <= 0) \
- { \
- vty_out (vty, "%% Invalid %s value%s", NAME, VTY_NEWLINE); \
- return CMD_WARNING; \
- } \
+#define VTY_GET_IPV4_PREFIX(NAME,V,STR) \
+do { \
+ int retv; \
+ retv = str2prefix_ipv4 ((STR), &(V)); \
+ if (retv <= 0) \
+ { \
+ vty_out (vty, "%% Invalid %s value%s", NAME, VTY_NEWLINE); \
+ return CMD_WARNING; \
+ } \
} while (0)
-#define VTY_WARN_EXPERIMENTAL() \
-do { \
+#define VTY_WARN_EXPERIMENTAL() \
+do { \
vty_out (vty, "%% WARNING: this command is experimental. Both its name and" \
" parameters may%s%% change in a future version of Quagga," \
" possibly breaking your configuration!%s", \
@@ -280,10 +349,11 @@ extern void vty_time_print (struct vty *, int);
extern void vty_serv_sock (const char *, unsigned short, const char *);
extern void vty_close (struct vty *);
extern char *vty_get_cwd (void);
-extern void vty_log (const char *level, const char *proto,
+extern void vty_log (const char *level, const char *proto,
const char *fmt, struct timestamp_control *, va_list);
extern int vty_config_lock (struct vty *);
extern int vty_config_unlock (struct vty *);
+extern void vty_config_lockless (void);
extern int vty_shell (struct vty *);
extern int vty_shell_serv (struct vty *);
extern void vty_hello (struct vty *);
@@ -292,4 +362,7 @@ extern void vty_hello (struct vty *);
an async-signal-safe function. */
extern void vty_log_fixed (char *buf, size_t len);
+extern const char *vty_get_arg_value (struct vty_arg **, const char *);
+extern struct vty_arg *vty_get_arg (struct vty_arg **, const char *);
+
#endif /* _ZEBRA_VTY_H */
diff --git a/lib/zclient.c b/lib/zclient.c
index 057fa7758..fa8150c5a 100644
--- a/lib/zclient.c
+++ b/lib/zclient.c
@@ -140,6 +140,9 @@ redist_del_instance (struct redist_proto *red, u_short instance)
void
zclient_stop (struct zclient *zclient)
{
+ afi_t afi;
+ int i;
+
if (zclient_debug)
zlog_debug ("zclient stopped");
@@ -162,6 +165,15 @@ zclient_stop (struct zclient *zclient)
zclient->sock = -1;
}
zclient->fail = 0;
+
+ for (afi = AFI_IP; afi < AFI_MAX; afi++)
+ for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
+ {
+ vrf_bitmap_free(zclient->redist[afi][i]);
+ zclient->redist[afi][i] = VRF_BITMAP_NULL;
+ }
+ vrf_bitmap_free(zclient->default_information);
+ zclient->default_information = VRF_BITMAP_NULL;
}
void
@@ -710,7 +722,7 @@ zclient_connect (struct thread *t)
* If ZAPI_MESSAGE_METRIC is set, the metric value is written as an 8
* byte value.
*
- * If ZAPI_MESSAGE_TAG is set, the tag value is written as a 2 byte value
+ * If ZAPI_MESSAGE_TAG is set, the tag value is written as a 4 byte value
*
* If ZAPI_MESSAGE_MTU is set, the mtu value is written as a 4 byte value
*
@@ -733,7 +745,7 @@ zapi_ipv4_route (u_char cmd, struct zclient *zclient, struct prefix_ipv4 *p,
/* Put type and nexthop. */
stream_putc (s, api->type);
stream_putw (s, api->instance);
- stream_putc (s, api->flags);
+ stream_putl (s, api->flags);
stream_putc (s, api->message);
stream_putw (s, api->safi);
@@ -773,7 +785,7 @@ zapi_ipv4_route (u_char cmd, struct zclient *zclient, struct prefix_ipv4 *p,
if (CHECK_FLAG (api->message, ZAPI_MESSAGE_METRIC))
stream_putl (s, api->metric);
if (CHECK_FLAG (api->message, ZAPI_MESSAGE_TAG))
- stream_putw (s, api->tag);
+ stream_putl (s, api->tag);
if (CHECK_FLAG (api->message, ZAPI_MESSAGE_MTU))
stream_putl (s, api->mtu);
@@ -801,7 +813,7 @@ zapi_ipv4_route_ipv6_nexthop (u_char cmd, struct zclient *zclient,
/* Put type and nexthop. */
stream_putc (s, api->type);
stream_putw (s, api->instance);
- stream_putc (s, api->flags);
+ stream_putl (s, api->flags);
stream_putc (s, api->message);
stream_putw (s, api->safi);
@@ -840,7 +852,7 @@ zapi_ipv4_route_ipv6_nexthop (u_char cmd, struct zclient *zclient,
if (CHECK_FLAG (api->message, ZAPI_MESSAGE_METRIC))
stream_putl (s, api->metric);
if (CHECK_FLAG (api->message, ZAPI_MESSAGE_TAG))
- stream_putw (s, api->tag);
+ stream_putl (s, api->tag);
if (CHECK_FLAG (api->message, ZAPI_MESSAGE_MTU))
stream_putl (s, api->mtu);
@@ -867,7 +879,7 @@ zapi_ipv6_route (u_char cmd, struct zclient *zclient, struct prefix_ipv6 *p,
/* Put type and nexthop. */
stream_putc (s, api->type);
stream_putw (s, api->instance);
- stream_putc (s, api->flags);
+ stream_putl (s, api->flags);
stream_putc (s, api->message);
stream_putw (s, api->safi);
@@ -906,7 +918,7 @@ zapi_ipv6_route (u_char cmd, struct zclient *zclient, struct prefix_ipv6 *p,
if (CHECK_FLAG (api->message, ZAPI_MESSAGE_METRIC))
stream_putl (s, api->metric);
if (CHECK_FLAG (api->message, ZAPI_MESSAGE_TAG))
- stream_putw (s, api->tag);
+ stream_putl (s, api->tag);
if (CHECK_FLAG (api->message, ZAPI_MESSAGE_MTU))
stream_putl (s, api->mtu);
@@ -942,18 +954,30 @@ zebra_redistribute_send (int command, struct zclient *zclient, afi_t afi, int ty
return zclient_send_message(zclient);
}
+/* Get prefix in ZServ format; family should be filled in on prefix */
+static void
+zclient_stream_get_prefix (struct stream *s, struct prefix *p)
+{
+ size_t plen = prefix_blen (p);
+ u_char c;
+ p->prefixlen = 0;
+
+ if (plen == 0)
+ return;
+
+ stream_get (&p->u.prefix, s, plen);
+ c = stream_getc(s);
+ p->prefixlen = MIN(plen * 8, c);
+}
+
/* Router-id update from zebra daemon. */
void
zebra_router_id_update_read (struct stream *s, struct prefix *rid)
{
- int plen;
-
/* Fetch interface address. */
rid->family = stream_getc (s);
-
- plen = prefix_blen (rid);
- stream_get (&rid->u.prefix, s, plen);
- rid->prefixlen = stream_getc (s);
+
+ zclient_stream_get_prefix (s, rid);
}
/* Interface addition from zebra daemon. */
@@ -1263,8 +1287,7 @@ zebra_interface_address_read (int type, struct stream *s, vrf_id_t vrf_id)
ifindex_t ifindex;
struct interface *ifp;
struct connected *ifc;
- struct prefix p, d;
- int family;
+ struct prefix p, d, *dp;
int plen;
u_char ifc_flags;
@@ -1288,24 +1311,24 @@ zebra_interface_address_read (int type, struct stream *s, vrf_id_t vrf_id)
ifc_flags = stream_getc (s);
/* Fetch interface address. */
- family = p.family = stream_getc (s);
-
- plen = prefix_blen (&p);
- stream_get (&p.u.prefix, s, plen);
- p.prefixlen = stream_getc (s);
+ d.family = p.family = stream_getc (s);
+ plen = prefix_blen (&d);
+
+ zclient_stream_get_prefix (s, &p);
/* Fetch destination address. */
stream_get (&d.u.prefix, s, plen);
- d.family = family;
-
+
+ /* N.B. NULL destination pointers are encoded as all zeroes */
+ dp = memconstant(&d.u.prefix,0,plen) ? NULL : &d;
+
if (type == ZEBRA_INTERFACE_ADDRESS_ADD)
{
ifc = connected_lookup_prefix_exact (ifp, &p);
if (!ifc)
{
/* N.B. NULL destination pointers are encoded as all zeroes */
- ifc = connected_add_by_prefix(ifp, &p, (memconstant(&d.u.prefix,0,plen) ?
- NULL : &d));
+ ifc = connected_add_by_prefix(ifp, &p, dp);
}
if (ifc)
{
@@ -1583,22 +1606,6 @@ zclient_read (struct thread *thread)
if (zclient->interface_vrf_update)
(*zclient->interface_vrf_update) (command, zclient, length, vrf_id);
break;
- case ZEBRA_IPV4_ROUTE_ADD:
- if (zclient->ipv4_route_add)
- (*zclient->ipv4_route_add) (command, zclient, length, vrf_id);
- break;
- case ZEBRA_IPV4_ROUTE_DELETE:
- if (zclient->ipv4_route_delete)
- (*zclient->ipv4_route_delete) (command, zclient, length, vrf_id);
- break;
- case ZEBRA_IPV6_ROUTE_ADD:
- if (zclient->ipv6_route_add)
- (*zclient->ipv6_route_add) (command, zclient, length, vrf_id);
- break;
- case ZEBRA_IPV6_ROUTE_DELETE:
- if (zclient->ipv6_route_delete)
- (*zclient->ipv6_route_delete) (command, zclient, length, vrf_id);
- break;
case ZEBRA_NEXTHOP_UPDATE:
if (zclient_debug)
zlog_debug("zclient rcvd nexthop update\n");
diff --git a/lib/zclient.h b/lib/zclient.h
index b95d18ec1..f122b233b 100644
--- a/lib/zclient.h
+++ b/lib/zclient.h
@@ -98,10 +98,6 @@ struct zclient
int (*interface_nbr_address_add) (int, struct zclient *, uint16_t, vrf_id_t);
int (*interface_nbr_address_delete) (int, struct zclient *, uint16_t, vrf_id_t);
int (*interface_vrf_update) (int, struct zclient *, uint16_t, vrf_id_t);
- int (*ipv4_route_add) (int, struct zclient *, uint16_t, vrf_id_t);
- int (*ipv4_route_delete) (int, struct zclient *, uint16_t, vrf_id_t);
- int (*ipv6_route_add) (int, struct zclient *, uint16_t, vrf_id_t);
- int (*ipv6_route_delete) (int, struct zclient *, uint16_t, vrf_id_t);
int (*nexthop_update) (int, struct zclient *, uint16_t, vrf_id_t);
int (*import_check_update) (int, struct zclient *, uint16_t, vrf_id_t);
int (*bfd_dest_replay) (int, struct zclient *, uint16_t, vrf_id_t);
@@ -138,7 +134,7 @@ struct zapi_ipv4
u_char type;
u_short instance;
- u_char flags;
+ u_int32_t flags;
u_char message;
@@ -154,7 +150,7 @@ struct zapi_ipv4
u_int32_t metric;
- u_short tag;
+ route_tag_t tag;
u_int32_t mtu;
@@ -226,7 +222,7 @@ struct zapi_ipv6
u_char type;
u_short instance;
- u_char flags;
+ u_int32_t flags;
u_char message;
@@ -242,7 +238,7 @@ struct zapi_ipv6
u_int32_t metric;
- u_short tag;
+ route_tag_t tag;
u_int32_t mtu;
diff --git a/lib/zebra.h b/lib/zebra.h
index d7a441c2e..08c50c68b 100644
--- a/lib/zebra.h
+++ b/lib/zebra.h
@@ -352,18 +352,21 @@ struct in_pktinfo
#endif /* ndef BYTE_ORDER */
/* MAX / MIN are not commonly defined, but useful */
-#ifndef MAX
+/* note: glibc sys/param.h has #define MIN(a,b) (((a)<(b))?(a):(b)) */
+#ifdef MAX
+#undef MAX
+#endif
#define MAX(a, b) \
({ typeof (a) _a = (a); \
typeof (b) _b = (b); \
_a > _b ? _a : _b; })
+#ifdef MIN
+#undef MIN
#endif
-#ifndef MIN
#define MIN(a, b) \
({ typeof (a) _a = (a); \
typeof (b) _b = (b); \
_a < _b ? _a : _b; })
-#endif
#define ZEBRA_NUM_OF(x) (sizeof (x) / sizeof (x[0]))
@@ -422,6 +425,12 @@ typedef enum {
ZEBRA_INTERFACE_DISABLE_RADV,
ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB,
ZEBRA_INTERFACE_LINK_PARAMS,
+ ZEBRA_MPLS_LABELS_ADD,
+ ZEBRA_MPLS_LABELS_DELETE,
+ ZEBRA_IPV4_NEXTHOP_ADD,
+ ZEBRA_IPV4_NEXTHOP_DELETE,
+ ZEBRA_IPV6_NEXTHOP_ADD,
+ ZEBRA_IPV6_NEXTHOP_DELETE,
} zebra_message_types_t;
/* Marker value used in new Zserv, in the byte location corresponding
@@ -469,6 +478,7 @@ extern const char *zserv_command_string (unsigned int command);
#define ZEBRA_FLAG_STATIC 0x40
#define ZEBRA_FLAG_REJECT 0x80
#define ZEBRA_FLAG_SCOPE_LINK 0x100
+#define ZEBRA_FLAG_FIB_OVERRIDE 0x200
#ifndef INADDR_LOOPBACK
#define INADDR_LOOPBACK 0x7f000001 /* Internet address 127.0.0.1. */
@@ -518,4 +528,8 @@ typedef u_int16_t zebra_command_t;
/* VRF ID type. */
typedef u_int16_t vrf_id_t;
+typedef uint32_t route_tag_t;
+#define ROUTE_TAG_MAX UINT32_MAX
+#define ROUTE_TAG_PRI PRIu32
+
#endif /* _ZEBRA_H */