diff options
author | Quentin Young <qlyoung@cumulusnetworks.com> | 2016-10-18 01:36:21 +0200 |
---|---|---|
committer | Quentin Young <qlyoung@cumulusnetworks.com> | 2016-10-18 01:36:21 +0200 |
commit | e52702f29d003585dcfbb4914b2a52d77a177739 (patch) | |
tree | 3e130ded38c48316796bfb602dc6fe6d119129d2 /lib | |
parent | ospf6d: fix a few vty help strings (diff) | |
parent | vtysh: fix build failure in vtysh_writeconfig_integrated() (diff) | |
download | frr-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.am | 10 | ||||
-rw-r--r-- | lib/checksum.c | 2 | ||||
-rw-r--r-- | lib/command.c | 84 | ||||
-rw-r--r-- | lib/command.h | 15 | ||||
-rw-r--r-- | lib/distribute.c | 338 | ||||
-rw-r--r-- | lib/distribute.h | 6 | ||||
-rw-r--r-- | lib/if.c | 18 | ||||
-rw-r--r-- | lib/if.h | 4 | ||||
-rw-r--r-- | lib/imsg-buffer.c | 301 | ||||
-rw-r--r-- | lib/imsg.c | 334 | ||||
-rw-r--r-- | lib/imsg.h | 112 | ||||
-rw-r--r-- | lib/json.h | 6 | ||||
-rw-r--r-- | lib/keychain.c | 100 | ||||
-rw-r--r-- | lib/keychain.h | 8 | ||||
-rw-r--r-- | lib/log.c | 62 | ||||
-rw-r--r-- | lib/log.h | 14 | ||||
-rw-r--r-- | lib/memory.c | 2 | ||||
-rw-r--r-- | lib/memory_vty.c | 20 | ||||
-rw-r--r-- | lib/mpls.h | 190 | ||||
-rw-r--r-- | lib/nexthop.c | 36 | ||||
-rw-r--r-- | lib/nexthop.h | 18 | ||||
-rw-r--r-- | lib/openbsd-queue.h | 533 | ||||
-rw-r--r-- | lib/openbsd-tree.h | 748 | ||||
-rw-r--r-- | lib/plist.c | 56 | ||||
-rw-r--r-- | lib/prefix.c | 2 | ||||
-rw-r--r-- | lib/privs.c | 9 | ||||
-rw-r--r-- | lib/qobj.c | 83 | ||||
-rw-r--r-- | lib/qobj.h | 122 | ||||
-rw-r--r-- | lib/route_types.txt | 14 | ||||
-rw-r--r-- | lib/routemap.c | 192 | ||||
-rw-r--r-- | lib/routemap.h | 11 | ||||
-rw-r--r-- | lib/skiplist.c | 685 | ||||
-rw-r--r-- | lib/skiplist.h | 159 | ||||
-rw-r--r-- | lib/sockopt.c | 34 | ||||
-rw-r--r-- | lib/sockunion.h | 6 | ||||
-rw-r--r-- | lib/table.c | 6 | ||||
-rw-r--r-- | lib/table.h | 3 | ||||
-rw-r--r-- | lib/thread.c | 4 | ||||
-rw-r--r-- | lib/vrf.c | 10 | ||||
-rw-r--r-- | lib/vrf.h | 4 | ||||
-rw-r--r-- | lib/vty.c | 100 | ||||
-rw-r--r-- | lib/vty.h | 125 | ||||
-rw-r--r-- | lib/zclient.c | 87 | ||||
-rw-r--r-- | lib/zclient.h | 12 | ||||
-rw-r--r-- | lib/zebra.h | 20 |
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, ©_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 }; @@ -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; } @@ -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 *); @@ -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; } @@ -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 @@ -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 @@ -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; @@ -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; +} @@ -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 */ |