summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile.am2
-rw-r--r--bgpd/bgp_clist.c223
-rw-r--r--bgpd/bgp_clist.h50
-rw-r--r--bgpd/bgp_main.c8
-rw-r--r--bgpd/bgp_packet.c248
-rw-r--r--bgpd/bgp_route.c1067
-rw-r--r--bgpd/bgp_route.h44
-rw-r--r--bgpd/bgp_vty.c637
-rw-r--r--bgpd/bgpd.c433
-rw-r--r--bgpd/bgpd.h44
-rwxr-xr-xconfigure.ac1
-rw-r--r--lib/Makefile.am6
-rw-r--r--lib/command.c294
-rw-r--r--lib/filter.c2
-rw-r--r--lib/heap.c517
-rw-r--r--lib/heap.h160
-rw-r--r--lib/log.c651
-rw-r--r--lib/log.h30
-rw-r--r--lib/memory.c40
-rw-r--r--lib/memory.h10
-rw-r--r--lib/memtypes.c26
-rw-r--r--lib/mqueue.c575
-rw-r--r--lib/mqueue.h141
-rw-r--r--lib/plist.c2366
-rw-r--r--lib/plist.h45
-rw-r--r--lib/prefix.c92
-rw-r--r--lib/privs.c203
-rw-r--r--lib/privs.h4
-rw-r--r--lib/qpnexus.c120
-rw-r--r--lib/qpnexus.h86
-rw-r--r--lib/qpselect.c1321
-rw-r--r--lib/qpselect.h208
-rw-r--r--lib/qpthreads.c570
-rw-r--r--lib/qpthreads.h363
-rw-r--r--lib/qtime.c194
-rw-r--r--lib/qtime.h307
-rw-r--r--lib/qtimers.c336
-rw-r--r--lib/qtimers.h144
-rw-r--r--lib/routemap.c2
-rw-r--r--lib/symtab.c1181
-rw-r--r--lib/symtab.h318
-rw-r--r--lib/vector.c1206
-rw-r--r--lib/vector.h277
-rw-r--r--lib/vty.c996
-rw-r--r--lib/vty.h33
-rw-r--r--lib/zassert.h50
-rw-r--r--tests/Makefile.am8
-rw-r--r--tests/test-privs.c28
-rw-r--r--tests/test-symtab.c344
-rw-r--r--tests/test-vector.c1209
-rw-r--r--vtysh/vtysh.c2
-rw-r--r--vtysh/vtysh_config.c3
52 files changed, 13976 insertions, 3249 deletions
diff --git a/Makefile.am b/Makefile.am
index 007758f2..5362623d 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -2,7 +2,7 @@
SUBDIRS = lib @ZEBRA@ @BGPD@ @RIPD@ @RIPNGD@ @OSPFD@ @OSPF6D@ \
@ISISD@ @WATCHQUAGGA@ @VTYSH@ @OSPFCLIENT@ @DOC@ m4 @pkgsrcdir@ \
- redhat @SOLARIS@
+ redhat tests @SOLARIS@
DIST_SUBDIRS = lib zebra bgpd ripd ripngd ospfd ospf6d \
isisd watchquagga vtysh ospfclient doc m4 pkgsrc redhat tests \
diff --git a/bgpd/bgp_clist.c b/bgpd/bgp_clist.c
index d6601674..1d847ee4 100644
--- a/bgpd/bgp_clist.c
+++ b/bgpd/bgp_clist.c
@@ -30,10 +30,27 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "bgpd/bgp_aspath.h"
#include "bgpd/bgp_regex.h"
#include "bgpd/bgp_clist.h"
-
+
+
+/* Community-list handler.
+ *
+ * Contains a set of community and extcommunity filters.
+ *
+ * NB: have separate name-spaces for community-list and extcommunity-list.
+*/
+struct community_list_handler
+{
+ /* Community-list. */
+ struct symbol_table community_list ;
+
+ /* Exteded community-list. */
+ struct symbol_table extcommunity_list ;
+};
+
+
/* Lookup master structure for community-list or
extcommunity-list. */
-struct community_list_master *
+struct symbol_table*
community_list_master_lookup (struct community_list_handler *ch, int master)
{
if (ch)
@@ -95,127 +112,22 @@ community_list_new (void)
static void
community_list_free (struct community_list *list)
{
- if (list->name)
- XFREE (MTYPE_COMMUNITY_LIST_NAME, list->name);
XFREE (MTYPE_COMMUNITY_LIST, list);
}
-
-static struct community_list *
-community_list_insert (struct community_list_handler *ch,
- const char *name, int master)
-{
- size_t i;
- long number;
- struct community_list *new;
- struct community_list *point;
- struct community_list_list *list;
- struct community_list_master *cm;
-
- /* Lookup community-list master. */
- cm = community_list_master_lookup (ch, master);
- if (!cm)
- return NULL;
-
- /* Allocate new community_list and copy given name. */
- new = community_list_new ();
- new->name = XSTRDUP (MTYPE_COMMUNITY_LIST_NAME, name);
-
- /* If name is made by all digit character. We treat it as
- number. */
- for (number = 0, i = 0; i < strlen (name); i++)
- {
- if (isdigit ((int) name[i]))
- number = (number * 10) + (name[i] - '0');
- else
- break;
- }
-
- /* In case of name is all digit character */
- if (i == strlen (name))
- {
- new->sort = COMMUNITY_LIST_NUMBER;
-
- /* Set access_list to number list. */
- list = &cm->num;
-
- for (point = list->head; point; point = point->next)
- if (atol (point->name) >= number)
- break;
- }
- else
- {
- new->sort = COMMUNITY_LIST_STRING;
-
- /* Set access_list to string list. */
- list = &cm->str;
-
- /* Set point to insertion point. */
- for (point = list->head; point; point = point->next)
- if (strcmp (point->name, name) >= 0)
- break;
- }
-
- /* Link to upper list. */
- new->parent = list;
-
- /* In case of this is the first element of master. */
- if (list->head == NULL)
- {
- list->head = list->tail = new;
- return new;
- }
-
- /* In case of insertion is made at the tail of access_list. */
- if (point == NULL)
- {
- new->prev = list->tail;
- list->tail->next = new;
- list->tail = new;
- return new;
- }
-
- /* In case of insertion is made at the head of access_list. */
- if (point == list->head)
- {
- new->next = list->head;
- list->head->prev = new;
- list->head = new;
- return new;
- }
-
- /* Insertion is made at middle of the access_list. */
- new->next = point;
- new->prev = point->prev;
-
- if (point->prev)
- point->prev->next = new;
- point->prev = new;
-
- return new;
-}
-
struct community_list *
community_list_lookup (struct community_list_handler *ch,
const char *name, int master)
{
- struct community_list *list;
- struct community_list_master *cm;
+ struct symbol_table* table;
if (!name)
return NULL;
- cm = community_list_master_lookup (ch, master);
- if (!cm)
+ table = community_list_master_lookup (ch, master);
+ if (!table)
return NULL;
- for (list = cm->num.head; list; list = list->next)
- if (strcmp (list->name, name) == 0)
- return list;
- for (list = cm->str.head; list; list = list->next)
- if (strcmp (list->name, name) == 0)
- return list;
-
- return NULL;
+ return symbol_get_value(symbol_seek(table, name)) ;
}
static struct community_list *
@@ -223,37 +135,51 @@ community_list_get (struct community_list_handler *ch,
const char *name, int master)
{
struct community_list *list;
+ struct symbol_table* table;
+ struct symbol* sym ;
- list = community_list_lookup (ch, name, master);
+ if (!name)
+ return NULL;
+
+ table = community_list_master_lookup (ch, master);
+ if (!table)
+ return NULL;
+
+ sym = symbol_find(table, name) ;
+ list = symbol_get_value(sym) ;
if (!list)
- list = community_list_insert (ch, name, master);
+ {
+ /* Allocate new community_list and tie symbol and list together. */
+ list = community_list_new ();
+
+ symbol_set_value(sym, list) ;
+ list->sym = symbol_inc_ref(sym) ;
+ }
+
return list;
}
static void
community_list_delete (struct community_list *list)
{
- struct community_list_list *clist;
struct community_entry *entry, *next;
+ /* Easy if the list is not defined ! */
+ if (list == NULL)
+ return ;
+
+ /* Free body of list */
for (entry = list->head; entry; entry = next)
{
next = entry->next;
community_entry_free (entry);
}
- clist = list->parent;
-
- if (list->next)
- list->next->prev = list->prev;
- else
- clist->tail = list->prev;
-
- if (list->prev)
- list->prev->next = list->next;
- else
- clist->head = list->next;
+ /* Kill value in related symbol and drop reference. */
+ symbol_unset_value(list->sym) ;
+ list->sym = symbol_dec_ref(list->sym) ;
+ /* Free community list structure */
community_list_free (list);
}
@@ -262,7 +188,7 @@ community_list_empty_p (struct community_list *list)
{
return (list->head == NULL && list->tail == NULL) ? 1 : 0;
}
-
+
/* Add community-list entry to the list. */
static void
community_list_entry_add (struct community_list *list,
@@ -329,7 +255,7 @@ community_list_entry_lookup (struct community_list *list, const void *arg,
}
return NULL;
}
-
+
/* Internal function to perform regular expression match for community
attribute. */
static int
@@ -514,19 +440,19 @@ community_list_match_delete (struct community *com,
{
if (entry->any)
{
- if (entry->direct == COMMUNITY_PERMIT)
+ if (entry->direct == COMMUNITY_PERMIT)
{
/* This is a tricky part. Currently only
* route_set_community_delete() uses this function. In the
* function com->size is zero, it free the community
- * structure.
+ * structure.
*/
com->size = 0;
}
return com;
}
- if ((entry->style == COMMUNITY_LIST_STANDARD)
+ if ((entry->style == COMMUNITY_LIST_STANDARD)
&& (community_include (entry->u.com, COMMUNITY_INTERNET)
|| community_match (com, entry->u.com) ))
{
@@ -590,7 +516,7 @@ community_list_dup_check (struct community_list *list,
}
return 0;
}
-
+
/* Set community-list. */
int
community_list_set (struct community_list_handler *ch,
@@ -653,7 +579,7 @@ community_list_set (struct community_list_handler *ch,
community-list entry belongs to the specified name. */
int
community_list_unset (struct community_list_handler *ch,
- const char *name, const char *str,
+ const char *name, const char *str,
int direct, int style)
{
struct community_entry *entry = NULL;
@@ -702,7 +628,7 @@ community_list_unset (struct community_list_handler *ch,
/* Set extcommunity-list. */
int
extcommunity_list_set (struct community_list_handler *ch,
- const char *name, const char *str,
+ const char *name, const char *str,
int direct, int style)
{
struct community_entry *entry = NULL;
@@ -772,7 +698,7 @@ extcommunity_list_set (struct community_list_handler *ch,
extcommunity-list entry belongs to the specified name. */
int
extcommunity_list_unset (struct community_list_handler *ch,
- const char *name, const char *str,
+ const char *name, const char *str,
int direct, int style)
{
struct community_entry *entry = NULL;
@@ -819,33 +745,34 @@ extcommunity_list_unset (struct community_list_handler *ch,
}
/* Initializa community-list. Return community-list handler. */
-struct community_list_handler *
+struct community_list_handler*
community_list_init (void)
{
struct community_list_handler *ch;
ch = XCALLOC (MTYPE_COMMUNITY_LIST_HANDLER,
sizeof (struct community_list_handler));
+
+ symbol_table_init_new(&ch->community_list, &ch, 20, 200, NULL, NULL) ;
+ symbol_table_init_new(&ch->extcommunity_list, &ch, 20, 200, NULL, NULL) ;
+
return ch;
}
-/* Terminate community-list. */
+/* Terminate community-list.
+ *
+ * Any references to community lists must be released by the owners of those
+ * references.
+ */
void
community_list_terminate (struct community_list_handler *ch)
{
- struct community_list_master *cm;
- struct community_list *list;
+ struct community_list *list ;
- cm = &ch->community_list;
- while ((list = cm->num.head) != NULL)
- community_list_delete (list);
- while ((list = cm->str.head) != NULL)
- community_list_delete (list);
+ while ((list = symbol_table_ream_keep(&ch->community_list)))
+ community_list_delete(list) ;
- cm = &ch->extcommunity_list;
- while ((list = cm->num.head) != NULL)
- community_list_delete (list);
- while ((list = cm->str.head) != NULL)
- community_list_delete (list);
+ while ((list = symbol_table_ream_keep(&ch->extcommunity_list)))
+ community_list_delete(list) ;
XFREE (MTYPE_COMMUNITY_LIST_HANDLER, ch);
}
diff --git a/bgpd/bgp_clist.h b/bgpd/bgp_clist.h
index 5dcb3b4c..1d9b9189 100644
--- a/bgpd/bgp_clist.h
+++ b/bgpd/bgp_clist.h
@@ -21,6 +21,8 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#ifndef _QUAGGA_BGP_CLIST_H
#define _QUAGGA_BGP_CLIST_H
+#include "symtab.h"
+
/* Master Community-list. */
#define COMMUNITY_LIST_MASTER 0
#define EXTCOMMUNITY_LIST_MASTER 1
@@ -30,8 +32,8 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#define COMMUNITY_PERMIT 1
/* Number and string based community-list name. */
-#define COMMUNITY_LIST_STRING 0
-#define COMMUNITY_LIST_NUMBER 1
+//#define COMMUNITY_LIST_STRING 0
+//#define COMMUNITY_LIST_NUMBER 1
/* Community-list entry types. */
#define COMMUNITY_LIST_STANDARD 0 /* Standard community-list. */
@@ -42,18 +44,11 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
/* Community-list. */
struct community_list
{
- /* Name of the community-list. */
- char *name;
+ /* Pointer to symbol entry of the community-list. */
+ struct symbol* sym ;
/* String or number. */
- int sort;
-
- /* Link to upper list. */
- struct community_list_list *parent;
-
- /* Linked list for other community-list. */
- struct community_list *next;
- struct community_list *prev;
+//int sort;
/* Community-list entry in this community-list. */
struct community_entry *head;
@@ -89,30 +84,11 @@ struct community_entry
regex_t *reg;
};
-/* Linked list of community-list. */
-struct community_list_list
-{
- struct community_list *head;
- struct community_list *tail;
-};
-
-/* Master structure of community-list and extcommunity-list. */
-struct community_list_master
-{
- struct community_list_list num;
- struct community_list_list str;
-};
-
-/* Community-list handler. community_list_init() returns this
- structure as handler. */
-struct community_list_handler
-{
- /* Community-list. */
- struct community_list_master community_list;
-
- /* Exteded community-list. */
- struct community_list_master extcommunity_list;
-};
+/* Community-list handler.
+ * community_list_init() returns this structure as handler -- contains a
+ * distinct set of community-list and extcommunity-list filters.
+ */
+struct community_list_handler ;
/* Error code of community-list. */
#define COMMUNITY_LIST_ERR_CANT_FIND_LIST -1
@@ -140,7 +116,7 @@ extern int extcommunity_list_unset (struct community_list_handler *ch,
const char *name, const char *str,
int direct, int style);
-extern struct community_list_master *
+extern struct symbol_table*
community_list_master_lookup (struct community_list_handler *, int);
extern struct community_list *
diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c
index 9d14683c..7ab403bc 100644
--- a/bgpd/bgp_main.c
+++ b/bgpd/bgp_main.c
@@ -404,9 +404,10 @@ main (int argc, char **argv)
/* Initializations. */
srand (time (NULL));
signal_init (master, Q_SIGC(bgp_signals), bgp_signals);
- zprivs_init (&bgpd_privs);
+ zprivs_init_r (&bgpd_privs);
cmd_init (1);
- vty_init (master);
+ vty_init_r();
+/* vty_init (master); */
memory_init ();
/* BGP related initialization. */
@@ -442,6 +443,9 @@ main (int argc, char **argv)
(bm->address ? bm->address : "<all>"),
bm->port);
+ /* create CLI thread */
+ vty_exec_r();
+
/* Start finite state machine, here we go! */
while (thread_fetch (master, &thread))
thread_call (&thread);
diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c
index 1c9a3c91..e57112f2 100644
--- a/bgpd/bgp_packet.c
+++ b/bgpd/bgp_packet.c
@@ -49,7 +49,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "bgpd/bgp_vty.h"
int stream_put_prefix (struct stream *, struct prefix *);
-
+
/* Set up BGP packet marker and packet type. */
static int
bgp_packet_set_marker (struct stream *s, u_char type)
@@ -121,7 +121,7 @@ bgp_connect_check (struct peer *peer)
zlog (peer->log, LOG_INFO, "can't get sockopt for nonblocking connect");
BGP_EVENT_ADD (peer, TCP_fatal_error);
return;
- }
+ }
/* When status is 0 then TCP connection is established. */
if (status == 0)
@@ -174,7 +174,7 @@ bgp_update_packet (struct peer *peer, afi_t afi, safi_t safi)
struct prefix_rd *prd = NULL;
u_char *tag = NULL;
struct peer *from = NULL;
-
+
if (rn->prn)
prd = (struct prefix_rd *) &rn->prn->p;
if (binfo && binfo->extra)
@@ -182,21 +182,21 @@ bgp_update_packet (struct peer *peer, afi_t afi, safi_t safi)
tag = binfo->extra->tag;
from = binfo->peer;
}
-
+
bgp_packet_set_marker (s, BGP_MSG_UPDATE);
- stream_putw (s, 0);
+ stream_putw (s, 0);
pos = stream_get_endp (s);
stream_putw (s, 0);
- total_attr_len = bgp_packet_attribute (NULL, peer, s,
+ total_attr_len = bgp_packet_attribute (NULL, peer, s,
adv->baa->attr,
- &rn->p, afi, safi,
+ &rn->p, afi, safi,
from, prd, tag);
stream_putw_at (s, pos, total_attr_len);
}
if (afi == AFI_IP && safi == SAFI_UNICAST)
stream_put_prefix (s, &rn->p);
-
+
if (BGP_DEBUG (update, UPDATE_OUT))
zlog (peer->log, LOG_DEBUG, "%s send UPDATE %s/%d",
peer->host,
@@ -216,7 +216,7 @@ bgp_update_packet (struct peer *peer, afi_t afi, safi_t safi)
if (! (afi == AFI_IP && safi == SAFI_UNICAST))
break;
}
-
+
if (! stream_empty (s))
{
bgp_packet_set_size (s);
@@ -295,7 +295,7 @@ bgp_withdraw_packet (struct peer *peer, afi_t afi, safi_t safi)
adj = adv->adj;
rn = adv->rn;
- if (STREAM_REMAIN (s)
+ if (STREAM_REMAIN (s)
< (BGP_NLRI_LENGTH + BGP_TOTAL_ATTR_LEN + PSIZE (rn->p.prefixlen)))
break;
@@ -310,14 +310,14 @@ bgp_withdraw_packet (struct peer *peer, afi_t afi, safi_t safi)
else
{
struct prefix_rd *prd = NULL;
-
+
if (rn->prn)
prd = (struct prefix_rd *) &rn->prn->p;
pos = stream_get_endp (s);
stream_putw (s, 0);
total_attr_len
= bgp_packet_withdraw (peer, s, &rn->p, afi, safi, prd, NULL);
-
+
/* Set total path attribute length. */
stream_putw_at (s, pos, total_attr_len);
}
@@ -341,7 +341,7 @@ bgp_withdraw_packet (struct peer *peer, afi_t afi, safi_t safi)
{
if (afi == AFI_IP && safi == SAFI_UNICAST)
{
- unfeasible_len
+ unfeasible_len
= stream_get_endp (s) - BGP_HEADER_SIZE - BGP_UNFEASIBLE_LEN;
stream_putw_at (s, BGP_HEADER_SIZE, unfeasible_len);
stream_putw (s, 0);
@@ -374,7 +374,7 @@ bgp_default_update_send (struct peer *peer, struct attr *attr,
if (afi == AFI_IP)
str2prefix ("0.0.0.0/0", &p);
#ifdef HAVE_IPV6
- else
+ else
str2prefix ("::/0", &p);
#endif /* HAVE_IPV6 */
@@ -442,7 +442,7 @@ bgp_default_withdraw_send (struct peer *peer, afi_t afi, safi_t safi)
if (afi == AFI_IP)
str2prefix ("0.0.0.0/0", &p);
#ifdef HAVE_IPV6
- else
+ else
str2prefix ("::/0", &p);
#endif /* HAVE_IPV6 */
@@ -521,7 +521,7 @@ bgp_write_packet (struct peer *peer)
return s;
}
}
-
+
for (afi = AFI_IP; afi < AFI_MAX; afi++)
for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
{
@@ -594,7 +594,7 @@ bgp_write (struct thread *thread)
{
struct peer *peer;
u_char type;
- struct stream *s;
+ struct stream *s;
int num;
unsigned int count = 0;
int write_errno;
@@ -619,7 +619,7 @@ bgp_write (struct thread *thread)
s = bgp_write_packet (peer);
if (! s)
return 0;
-
+
/* XXX: FIXME, the socket should be NONBLOCK from the start
* status shouldnt need to be toggled on each write
*/
@@ -694,10 +694,10 @@ bgp_write (struct thread *thread)
if (++count >= BGP_WRITE_PACKET_MAX)
break;
}
-
+
if (bgp_write_proceed (peer))
BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd);
-
+
return 0;
}
@@ -707,7 +707,7 @@ bgp_write_notify (struct peer *peer)
{
int ret;
u_char type;
- struct stream *s;
+ struct stream *s;
/* There should be at least one packet. */
s = stream_fifo_head (peer->obuf);
@@ -761,9 +761,9 @@ bgp_keepalive_send (struct peer *peer)
/* Dump packet if debug option is set. */
/* bgp_packet_dump (s); */
-
- if (BGP_DEBUG (keepalive, KEEPALIVE))
- zlog_debug ("%s sending KEEPALIVE", peer->host);
+
+ if (BGP_DEBUG (keepalive, KEEPALIVE))
+ zlog_debug ("%s sending KEEPALIVE", peer->host);
if (BGP_DEBUG (normal, NORMAL))
zlog_debug ("%s send message type %d, length (incl. header) %d",
peer->host, BGP_MSG_KEEPALIVE, length);
@@ -790,9 +790,9 @@ bgp_open_send (struct peer *peer)
/* local-as Change */
if (peer->change_local_as)
- local_as = peer->change_local_as;
+ local_as = peer->change_local_as;
else
- local_as = peer->local_as;
+ local_as = peer->local_as;
s = stream_new (BGP_MAX_PACKET_SIZE);
@@ -801,7 +801,7 @@ bgp_open_send (struct peer *peer)
/* Set open packet values. */
stream_putc (s, BGP_VERSION_4); /* BGP version */
- stream_putw (s, (local_as <= BGP_AS_MAX) ? (u_int16_t) local_as
+ stream_putw (s, (local_as <= BGP_AS_MAX) ? (u_int16_t) local_as
: BGP_AS_TRANS);
stream_putw (s, send_holdtime); /* Hold Time */
stream_put_in_addr (s, &peer->local_id); /* BGP Identifier */
@@ -813,7 +813,7 @@ bgp_open_send (struct peer *peer)
length = bgp_packet_set_size (s);
if (BGP_DEBUG (normal, NORMAL))
- zlog_debug ("%s sending OPEN, version %d, my as %u, holdtime %d, id %s",
+ zlog_debug ("%s sending OPEN, version %d, my as %u, holdtime %d, id %s",
peer->host, BGP_VERSION_4, local_as,
send_holdtime, inet_ntoa (peer->local_id));
@@ -851,10 +851,10 @@ bgp_notify_send_with_data (struct peer *peer, u_char code, u_char sub_code,
/* If notify data is present. */
if (data)
stream_write (s, data, datalen);
-
+
/* Set BGP packet length. */
length = bgp_packet_set_size (s);
-
+
/* Add packet to the peer. */
stream_fifo_clean (peer->obuf);
bgp_packet_add (peer, s);
@@ -870,7 +870,7 @@ bgp_notify_send_with_data (struct peer *peer, u_char code, u_char sub_code,
bgp_notify.subcode = sub_code;
bgp_notify.data = NULL;
bgp_notify.length = length - BGP_MSG_NOTIFY_MIN_SIZE;
-
+
if (bgp_notify.length)
{
bgp_notify.data = XMALLOC (MTYPE_TMP, bgp_notify.length * 3);
@@ -963,7 +963,7 @@ bgp_route_refresh_send (struct peer *peer, afi_t afi, safi_t safi,
/* Adjust safi code. */
if (safi == SAFI_MPLS_VPN)
safi = BGP_SAFI_VPNV4;
-
+
s = stream_new (BGP_MAX_PACKET_SIZE);
/* Make BGP update packet. */
@@ -976,15 +976,15 @@ bgp_route_refresh_send (struct peer *peer, afi_t afi, safi_t safi,
stream_putw (s, afi);
stream_putc (s, 0);
stream_putc (s, safi);
-
+
if (orf_type == ORF_TYPE_PREFIX
|| orf_type == ORF_TYPE_PREFIX_OLD)
- if (remove || filter->plist[FILTER_IN].plist)
+ if (remove || filter->plist[FILTER_IN].ref)
{
u_int16_t orf_len;
unsigned long orfp;
- orf_refresh = 1;
+ orf_refresh = 1;
stream_putc (s, when_to_refresh);
stream_putc (s, orf_type);
orfp = stream_get_endp (s);
@@ -995,7 +995,7 @@ bgp_route_refresh_send (struct peer *peer, afi_t afi, safi_t safi,
UNSET_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_ORF_PREFIX_SEND);
stream_putc (s, ORF_COMMON_PART_REMOVE_ALL);
if (BGP_DEBUG (normal, NORMAL))
- zlog_debug ("%s sending REFRESH_REQ to remove ORF(%d) (%s) for afi/safi: %d/%d",
+ zlog_debug ("%s sending REFRESH_REQ to remove ORF(%d) (%s) for afi/safi: %d/%d",
peer->host, orf_type,
(when_to_refresh == REFRESH_DEFER ? "defer" : "immediate"),
afi, safi);
@@ -1003,11 +1003,11 @@ bgp_route_refresh_send (struct peer *peer, afi_t afi, safi_t safi,
else
{
SET_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_ORF_PREFIX_SEND);
- prefix_bgp_orf_entry (s, filter->plist[FILTER_IN].plist,
+ prefix_bgp_orf_entry (s, filter->plist[FILTER_IN].ref,
ORF_COMMON_PART_ADD, ORF_COMMON_PART_PERMIT,
ORF_COMMON_PART_DENY);
if (BGP_DEBUG (normal, NORMAL))
- zlog_debug ("%s sending REFRESH_REQ with pfxlist ORF(%d) (%s) for afi/safi: %d/%d",
+ zlog_debug ("%s sending REFRESH_REQ with pfxlist ORF(%d) (%s) for afi/safi: %d/%d",
peer->host, orf_type,
(when_to_refresh == REFRESH_DEFER ? "defer" : "immediate"),
afi, safi);
@@ -1024,7 +1024,7 @@ bgp_route_refresh_send (struct peer *peer, afi_t afi, safi_t safi,
if (BGP_DEBUG (normal, NORMAL))
{
if (! orf_refresh)
- zlog_debug ("%s sending REFRESH_REQ for afi/safi: %d/%d",
+ zlog_debug ("%s sending REFRESH_REQ for afi/safi: %d/%d",
peer->host, afi, safi);
zlog_debug ("%s send message type %d, length (incl. header) %d",
peer->host, CHECK_FLAG (peer->cap, PEER_CAP_REFRESH_NEW_RCV) ?
@@ -1091,7 +1091,7 @@ bgp_capability_send (struct peer *peer, afi_t afi, safi_t safi,
BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd);
}
-
+
/* RFC1771 6.8 Connection collision detection. */
static int
bgp_collision_detect (struct peer *new, struct in_addr remote_id)
@@ -1103,7 +1103,7 @@ bgp_collision_detect (struct peer *new, struct in_addr remote_id)
bgp = bgp_get_default ();
if (! bgp)
return 0;
-
+
/* Upon receipt of an OPEN message, the local system must examine
all of its connections that are in the OpenConfirm state. A BGP
speaker may also examine connections in an OpenSent state if it
@@ -1147,7 +1147,7 @@ bgp_collision_detect (struct peer *new, struct in_addr remote_id)
OpenConfirm state). */
if (new->fd >= 0)
- bgp_notify_send (new, BGP_NOTIFY_CEASE,
+ bgp_notify_send (new, BGP_NOTIFY_CEASE,
BGP_NOTIFY_CEASE_COLLISION_RESOLUTION);
return -1;
}
@@ -1173,7 +1173,7 @@ bgp_open_receive (struct peer *peer, bgp_size_t size)
u_int8_t notify_data_remote_id[4];
realpeer = NULL;
-
+
/* Parse open packet. */
version = stream_getc (peer->ibuf);
memcpy (notify_data_remote_as, stream_pnt (peer->ibuf), 2);
@@ -1188,20 +1188,20 @@ bgp_open_receive (struct peer *peer, bgp_size_t size)
" holdtime %d, id %s",
peer->host, version, remote_as, holdtime,
inet_ntoa (remote_id));
-
+
/* BEGIN to read the capability here, but dont do it yet */
capability = 0;
optlen = stream_getc (peer->ibuf);
-
+
if (optlen != 0)
{
/* We need the as4 capability value *right now* because
* if it is there, we have not got the remote_as yet, and without
* that we do not know which peer is connecting to us now.
- */
+ */
as4 = peek_for_as4_capability (peer, optlen);
}
-
+
/* Just in case we have a silly peer who sends AS4 capability set to 0 */
if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV) && !as4)
{
@@ -1211,7 +1211,7 @@ bgp_open_receive (struct peer *peer, bgp_size_t size)
BGP_NOTIFY_OPEN_BAD_PEER_AS);
return -1;
}
-
+
if (remote_as == BGP_AS_TRANS)
{
/* Take the AS4 from the capability. We must have received the
@@ -1226,7 +1226,7 @@ bgp_open_receive (struct peer *peer, bgp_size_t size)
BGP_NOTIFY_OPEN_BAD_PEER_AS);
return -1;
}
-
+
if (!as4 && BGP_DEBUG (as4, AS4))
zlog_debug ("%s [AS4] OPEN remote_as is AS_TRANS, but no AS4."
" Odd, but proceeding.", peer->host);
@@ -1235,8 +1235,8 @@ bgp_open_receive (struct peer *peer, bgp_size_t size)
"in 2-bytes, very odd peer.", peer->host, as4);
if (as4)
remote_as = as4;
- }
- else
+ }
+ else
{
/* We may have a partner with AS4 who has an asno < BGP_AS_MAX */
/* If we have got the capability, peer->as4cap must match remote_as */
@@ -1270,7 +1270,7 @@ bgp_open_receive (struct peer *peer, bgp_size_t size)
if (BGP_DEBUG (normal, NORMAL))
zlog_debug ("%s bad OPEN, wrong router identifier %s",
peer->host, inet_ntoa (remote_id));
- bgp_notify_send_with_data (peer, BGP_NOTIFY_OPEN_ERR,
+ bgp_notify_send_with_data (peer, BGP_NOTIFY_OPEN_ERR,
BGP_NOTIFY_OPEN_BAD_BGP_IDENT,
notify_data_remote_id, 4);
}
@@ -1307,7 +1307,7 @@ bgp_open_receive (struct peer *peer, bgp_size_t size)
&& realpeer->status != OpenConfirm
&& realpeer->status != Connect)
{
- /* XXX: This is an awful problem..
+ /* XXX: This is an awful problem..
*
* According to the RFC we should just let this connection (of the
* accepted 'peer') continue on to Established if the other
@@ -1325,7 +1325,7 @@ bgp_open_receive (struct peer *peer, bgp_size_t size)
* Active
* OpenSent OpenSent
* <arrive here,
- * Notify, delete>
+ * Notify, delete>
* Idle Active
* OpenSent OpenSent
* <arrive here,
@@ -1341,13 +1341,13 @@ bgp_open_receive (struct peer *peer, bgp_size_t size)
* exacerbated by high-latency (in bgpd and/or the network).
*
* The reason we do this is because our FSM is tied to our peer
- * structure, which carries our configuration information, etc.
+ * structure, which carries our configuration information, etc.
* I.e. we can't let the accepted-peer FSM continue on as it is,
* cause it's not associated with any actual peer configuration -
* it's just a dummy.
*
* It's possible we could hack-fix this by just bgp_stop'ing the
- * realpeer and continueing on with the 'transfer FSM' below.
+ * realpeer and continueing on with the 'transfer FSM' below.
* Ideally, we need to seperate FSMs from struct peer.
*
* Setting one side to passive avoids the race, as a workaround.
@@ -1364,11 +1364,11 @@ bgp_open_receive (struct peer *peer, bgp_size_t size)
if (BGP_DEBUG (events, EVENTS))
zlog_debug ("%s [Event] Transfer accept BGP peer to real (state %s)",
- peer->host,
+ peer->host,
LOOKUP (bgp_status_msg, realpeer->status));
bgp_stop (realpeer);
-
+
/* Transfer file descriptor. */
realpeer->fd = peer->fd;
peer->fd = -1;
@@ -1382,7 +1382,7 @@ bgp_open_receive (struct peer *peer, bgp_size_t size)
/* Transfer status. */
realpeer->status = peer->status;
bgp_stop (peer);
-
+
/* peer pointer change. Open packet send to neighbor. */
peer = realpeer;
bgp_open_send (peer);
@@ -1403,8 +1403,8 @@ bgp_open_receive (struct peer *peer, bgp_size_t size)
if (BGP_DEBUG (normal, NORMAL))
zlog_debug ("%s bad OPEN, wrong router identifier %s",
peer->host, inet_ntoa (remote_id));
- bgp_notify_send_with_data (peer,
- BGP_NOTIFY_OPEN_ERR,
+ bgp_notify_send_with_data (peer,
+ BGP_NOTIFY_OPEN_ERR,
BGP_NOTIFY_OPEN_BAD_BGP_IDENT,
notify_data_remote_id, 4);
return -1;
@@ -1420,8 +1420,8 @@ bgp_open_receive (struct peer *peer, bgp_size_t size)
if (BGP_DEBUG (normal, NORMAL))
zlog_debug ("%s bad protocol version, remote requested %d, local request %d",
peer->host, version, BGP_VERSION_4);
- bgp_notify_send_with_data (peer,
- BGP_NOTIFY_OPEN_ERR,
+ bgp_notify_send_with_data (peer,
+ BGP_NOTIFY_OPEN_ERR,
BGP_NOTIFY_OPEN_UNSUP_VERSION,
&maxver, 1);
return -1;
@@ -1433,8 +1433,8 @@ bgp_open_receive (struct peer *peer, bgp_size_t size)
if (BGP_DEBUG (normal, NORMAL))
zlog_debug ("%s bad OPEN, remote AS is %u, expected %u",
peer->host, remote_as, peer->as);
- bgp_notify_send_with_data (peer,
- BGP_NOTIFY_OPEN_ERR,
+ bgp_notify_send_with_data (peer,
+ BGP_NOTIFY_OPEN_ERR,
BGP_NOTIFY_OPEN_BAD_PEER_AS,
notify_data_remote_as, 2);
return -1;
@@ -1449,11 +1449,11 @@ bgp_open_receive (struct peer *peer, bgp_size_t size)
if (holdtime < 3 && holdtime != 0)
{
bgp_notify_send (peer,
- BGP_NOTIFY_OPEN_ERR,
+ BGP_NOTIFY_OPEN_ERR,
BGP_NOTIFY_OPEN_UNACEP_HOLDTIME);
return -1;
}
-
+
/* From the rfc: A reasonable maximum time between KEEPALIVE messages
would be one third of the Hold Time interval. KEEPALIVE messages
MUST NOT be sent more frequently than one per second. An
@@ -1473,7 +1473,7 @@ bgp_open_receive (struct peer *peer, bgp_size_t size)
peer->v_keepalive = peer->v_holdtime / 3;
/* Open option part parse. */
- if (optlen != 0)
+ if (optlen != 0)
{
ret = bgp_open_option_parse (peer, optlen, &capability);
if (ret < 0)
@@ -1525,7 +1525,7 @@ bgp_update_receive (struct peer *peer, bgp_size_t size)
char attrstr[BUFSIZ] = "";
/* Status must be Established. */
- if (peer->status != Established)
+ if (peer->status != Established)
{
zlog_err ("%s [FSM] Update packet received under status %s",
peer->host, LOOKUP (bgp_status_msg, peer->status));
@@ -1552,7 +1552,7 @@ bgp_update_receive (struct peer *peer, bgp_size_t size)
zlog_err ("%s [Error] Update packet error"
" (packet length is short for unfeasible length)",
peer->host);
- bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR,
+ bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR,
BGP_NOTIFY_UPDATE_MAL_ATTR);
return -1;
}
@@ -1566,7 +1566,7 @@ bgp_update_receive (struct peer *peer, bgp_size_t size)
zlog_err ("%s [Error] Update packet error"
" (packet unfeasible length overflow %d)",
peer->host, withdraw_len);
- bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR,
+ bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR,
BGP_NOTIFY_UPDATE_MAL_ATTR);
return -1;
}
@@ -1587,14 +1587,14 @@ bgp_update_receive (struct peer *peer, bgp_size_t size)
withdraw.length = withdraw_len;
stream_forward_getp (s, withdraw_len);
}
-
+
/* Attribute total length check. */
if (stream_pnt (s) + 2 > end)
{
zlog_warn ("%s [Error] Packet Error"
" (update packet is short for attribute length)",
peer->host);
- bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR,
+ bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR,
BGP_NOTIFY_UPDATE_MAL_ATTR);
return -1;
}
@@ -1608,7 +1608,7 @@ bgp_update_receive (struct peer *peer, bgp_size_t size)
zlog_warn ("%s [Error] Packet Error"
" (update packet attribute length overflow %d)",
peer->host, attribute_len);
- bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR,
+ bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR,
BGP_NOTIFY_UPDATE_MAL_ATTR);
return -1;
}
@@ -1616,7 +1616,7 @@ bgp_update_receive (struct peer *peer, bgp_size_t size)
/* Parse attribute when it exists. */
if (attribute_len)
{
- ret = bgp_attr_parse (peer, &attr, attribute_len,
+ ret = bgp_attr_parse (peer, &attr, attribute_len,
&mp_update, &mp_withdraw);
if (ret < 0)
return -1;
@@ -1669,12 +1669,12 @@ bgp_update_receive (struct peer *peer, bgp_size_t size)
}
if (mp_update.length
- && mp_update.afi == AFI_IP
+ && mp_update.afi == AFI_IP
&& mp_update.safi == SAFI_UNICAST)
bgp_nlri_parse (peer, &attr, &mp_update);
if (mp_withdraw.length
- && mp_withdraw.afi == AFI_IP
+ && mp_withdraw.afi == AFI_IP
&& mp_withdraw.safi == SAFI_UNICAST)
bgp_nlri_parse (peer, NULL, &mp_withdraw);
@@ -1696,12 +1696,12 @@ bgp_update_receive (struct peer *peer, bgp_size_t size)
if (peer->afc[AFI_IP][SAFI_MULTICAST])
{
if (mp_update.length
- && mp_update.afi == AFI_IP
+ && mp_update.afi == AFI_IP
&& mp_update.safi == SAFI_MULTICAST)
bgp_nlri_parse (peer, &attr, &mp_update);
if (mp_withdraw.length
- && mp_withdraw.afi == AFI_IP
+ && mp_withdraw.afi == AFI_IP
&& mp_withdraw.safi == SAFI_MULTICAST)
bgp_nlri_parse (peer, NULL, &mp_withdraw);
@@ -1725,13 +1725,13 @@ bgp_update_receive (struct peer *peer, bgp_size_t size)
}
if (peer->afc[AFI_IP6][SAFI_UNICAST])
{
- if (mp_update.length
- && mp_update.afi == AFI_IP6
+ if (mp_update.length
+ && mp_update.afi == AFI_IP6
&& mp_update.safi == SAFI_UNICAST)
bgp_nlri_parse (peer, &attr, &mp_update);
- if (mp_withdraw.length
- && mp_withdraw.afi == AFI_IP6
+ if (mp_withdraw.length
+ && mp_withdraw.afi == AFI_IP6
&& mp_withdraw.safi == SAFI_UNICAST)
bgp_nlri_parse (peer, NULL, &mp_withdraw);
@@ -1754,13 +1754,13 @@ bgp_update_receive (struct peer *peer, bgp_size_t size)
}
if (peer->afc[AFI_IP6][SAFI_MULTICAST])
{
- if (mp_update.length
- && mp_update.afi == AFI_IP6
+ if (mp_update.length
+ && mp_update.afi == AFI_IP6
&& mp_update.safi == SAFI_MULTICAST)
bgp_nlri_parse (peer, &attr, &mp_update);
- if (mp_withdraw.length
- && mp_withdraw.afi == AFI_IP6
+ if (mp_withdraw.length
+ && mp_withdraw.afi == AFI_IP6
&& mp_withdraw.safi == SAFI_MULTICAST)
bgp_nlri_parse (peer, NULL, &mp_withdraw);
@@ -1782,13 +1782,13 @@ bgp_update_receive (struct peer *peer, bgp_size_t size)
}
if (peer->afc[AFI_IP][SAFI_MPLS_VPN])
{
- if (mp_update.length
- && mp_update.afi == AFI_IP
+ if (mp_update.length
+ && mp_update.afi == AFI_IP
&& mp_update.safi == BGP_SAFI_VPNV4)
bgp_nlri_parse_vpnv4 (peer, &attr, &mp_update);
- if (mp_withdraw.length
- && mp_withdraw.afi == AFI_IP
+ if (mp_withdraw.length
+ && mp_withdraw.afi == AFI_IP
&& mp_withdraw.safi == BGP_SAFI_VPNV4)
bgp_nlri_parse_vpnv4 (peer, NULL, &mp_withdraw);
@@ -1921,9 +1921,9 @@ bgp_notify_receive (struct peer *peer, bgp_size_t size)
static void
bgp_keepalive_receive (struct peer *peer, bgp_size_t size)
{
- if (BGP_DEBUG (keepalive, KEEPALIVE))
- zlog_debug ("%s KEEPALIVE rcvd", peer->host);
-
+ if (BGP_DEBUG (keepalive, KEEPALIVE))
+ zlog_debug ("%s KEEPALIVE rcvd", peer->host);
+
BGP_EVENT_ADD (peer, Receive_KEEPALIVE_message);
}
@@ -1948,7 +1948,7 @@ bgp_route_refresh_receive (struct peer *peer, bgp_size_t size)
}
/* Status must be Established. */
- if (peer->status != Established)
+ if (peer->status != Established)
{
plog_err (peer->log,
"%s [Error] Route refresh packet received under status %s",
@@ -1958,7 +1958,7 @@ bgp_route_refresh_receive (struct peer *peer, bgp_size_t size)
}
s = peer->ibuf;
-
+
/* Parse packet. */
afi = stream_getw (s);
reserved = stream_getc (s);
@@ -2004,9 +2004,9 @@ bgp_route_refresh_receive (struct peer *peer, bgp_size_t size)
while ((stream_pnt (s) + 2) < end)
{
- orf_type = stream_getc (s);
+ orf_type = stream_getc (s);
orf_len = stream_getw (s);
-
+
/* orf_len in bounds? */
if ((stream_pnt (s) + orf_len) > end)
break; /* XXX: Notify instead?? */
@@ -2033,8 +2033,8 @@ bgp_route_refresh_receive (struct peer *peer, bgp_size_t size)
* and 7 bytes of ORF Address-filter entry from the stream
*/
if (orf_len < 7)
- break;
-
+ break;
+
/* ORF prefix-list name */
sprintf (name, "%s.%d.%d", peer->host, afi, safi);
@@ -2063,9 +2063,9 @@ bgp_route_refresh_receive (struct peer *peer, bgp_size_t size)
if (BGP_DEBUG (normal, NORMAL))
zlog_debug ("%s rcvd %s %s seq %u %s/%d ge %d le %d",
peer->host,
- (common & ORF_COMMON_PART_REMOVE ? "Remove" : "Add"),
+ (common & ORF_COMMON_PART_REMOVE ? "Remove" : "Add"),
(common & ORF_COMMON_PART_DENY ? "deny" : "permit"),
- orfp.seq,
+ orfp.seq,
inet_ntop (orfp.p.family, &orfp.p.u.prefix, buf, BUFSIZ),
orfp.p.prefixlen, orfp.ge, orfp.le);
@@ -2116,7 +2116,7 @@ bgp_capability_msg_parse (struct peer *peer, u_char *pnt, bgp_size_t length)
end = pnt + length;
while (pnt < end)
- {
+ {
/* We need at least action, capability code and capability length. */
if (pnt + 3 > end)
{
@@ -2126,7 +2126,7 @@ bgp_capability_msg_parse (struct peer *peer, u_char *pnt, bgp_size_t length)
}
action = *pnt;
hdr = (struct capability_header *)(pnt + 1);
-
+
/* Action value check. */
if (action != CAPABILITY_ACTION_SET
&& action != CAPABILITY_ACTION_UNSET)
@@ -2161,7 +2161,7 @@ bgp_capability_msg_parse (struct peer *peer, u_char *pnt, bgp_size_t length)
/* Ignore capability when override-capability is set. */
if (CHECK_FLAG (peer->flags, PEER_FLAG_OVERRIDE_CAPABILITY))
continue;
-
+
if (!bgp_afi_safi_valid_indices (afi, &safi))
{
if (BGP_DEBUG (normal, NORMAL))
@@ -2169,15 +2169,15 @@ bgp_capability_msg_parse (struct peer *peer, u_char *pnt, bgp_size_t length)
"(%u/%u)", peer->host, afi, safi);
continue;
}
-
+
/* Address family check. */
if (BGP_DEBUG (normal, NORMAL))
zlog_debug ("%s CAPABILITY has %s MP_EXT CAP for afi/safi: %u/%u",
peer->host,
- action == CAPABILITY_ACTION_SET
+ action == CAPABILITY_ACTION_SET
? "Advertising" : "Removing",
ntohs(mpc.afi) , mpc.safi);
-
+
if (action == CAPABILITY_ACTION_SET)
{
peer->afc_recv[afi][safi] = 1;
@@ -2208,10 +2208,10 @@ bgp_capability_msg_parse (struct peer *peer, u_char *pnt, bgp_size_t length)
return 0;
}
-/* Dynamic Capability is received.
+/* Dynamic Capability is received.
*
* This is exported for unit-test purposes
- */
+ */ extern int bgp_capability_receive(struct peer*, bgp_size_t) ;
int
bgp_capability_receive (struct peer *peer, bgp_size_t size)
{
@@ -2246,7 +2246,7 @@ bgp_capability_receive (struct peer *peer, bgp_size_t size)
/* Parse packet. */
return bgp_capability_msg_parse (peer, pnt, size);
}
-
+
/* BGP read utility function. */
static int
bgp_read_packet (struct peer *peer)
@@ -2264,7 +2264,7 @@ bgp_read_packet (struct peer *peer)
nbytes = stream_read_unblock (peer->ibuf, peer->fd, readsize);
/* If read byte is smaller than zero then error occured. */
- if (nbytes < 0)
+ if (nbytes < 0)
{
if (errno == EAGAIN)
return -1;
@@ -2272,7 +2272,7 @@ bgp_read_packet (struct peer *peer)
plog_err (peer->log, "%s [Error] bgp_read_packet error: %s",
peer->host, safe_strerror (errno));
- if (peer->status == Established)
+ if (peer->status == Established)
{
if (CHECK_FLAG (peer->sflags, PEER_STATUS_NSF_MODE))
{
@@ -2285,16 +2285,16 @@ bgp_read_packet (struct peer *peer)
BGP_EVENT_ADD (peer, TCP_fatal_error);
return -1;
- }
+ }
/* When read byte is zero : clear bgp peer and return */
- if (nbytes == 0)
+ if (nbytes == 0)
{
if (BGP_DEBUG (events, EVENTS))
plog_debug (peer->log, "%s [Event] BGP connection closed fd %d",
peer->host, peer->fd);
- if (peer->status == Established)
+ if (peer->status == Established)
{
if (CHECK_FLAG (peer->sflags, PEER_STATUS_NSF_MODE))
{
@@ -2368,7 +2368,7 @@ bgp_read (struct thread *thread)
ret = bgp_read_packet (peer);
/* Header read error or partial read packet. */
- if (ret < 0)
+ if (ret < 0)
goto done;
/* Get size and type. */
@@ -2386,14 +2386,14 @@ bgp_read (struct thread *thread)
&& ! bgp_marker_all_one (peer->ibuf, BGP_MARKER_SIZE))
{
bgp_notify_send (peer,
- BGP_NOTIFY_HEADER_ERR,
+ BGP_NOTIFY_HEADER_ERR,
BGP_NOTIFY_HEADER_NOT_SYNC);
goto done;
}
/* BGP type check. */
- if (type != BGP_MSG_OPEN && type != BGP_MSG_UPDATE
- && type != BGP_MSG_NOTIFY && type != BGP_MSG_KEEPALIVE
+ if (type != BGP_MSG_OPEN && type != BGP_MSG_UPDATE
+ && type != BGP_MSG_NOTIFY && type != BGP_MSG_KEEPALIVE
&& type != BGP_MSG_ROUTE_REFRESH_NEW
&& type != BGP_MSG_ROUTE_REFRESH_OLD
&& type != BGP_MSG_CAPABILITY)
@@ -2422,7 +2422,7 @@ bgp_read (struct thread *thread)
if (BGP_DEBUG (normal, NORMAL))
plog_debug (peer->log,
"%s bad message length - %d for %s",
- peer->host, size,
+ peer->host, size,
type == 128 ? "ROUTE-REFRESH" :
bgp_type_str[(int) type]);
bgp_notify_send_with_data (peer,
@@ -2437,7 +2437,7 @@ bgp_read (struct thread *thread)
}
ret = bgp_read_packet (peer);
- if (ret < 0)
+ if (ret < 0)
goto done;
/* Get size and type again. */
@@ -2446,11 +2446,11 @@ bgp_read (struct thread *thread)
/* BGP packet dump function. */
bgp_dump_packet (peer, type, peer->ibuf);
-
+
size = (peer->packet_size - BGP_HEADER_SIZE);
/* Read rest of the packet and call each sort of packet routine */
- switch (type)
+ switch (type)
{
case BGP_MSG_OPEN:
peer->open_in++;
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index 20880396..3488452a 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -58,18 +58,18 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
/* Extern from bgp_dump.c */
extern const char *bgp_origin_str[];
extern const char *bgp_origin_long_str[];
-
+
static struct bgp_node *
bgp_afi_node_get (struct bgp_table *table, afi_t afi, safi_t safi, struct prefix *p,
struct prefix_rd *prd)
{
struct bgp_node *rn;
struct bgp_node *prn = NULL;
-
+
assert (table);
if (!table)
return NULL;
-
+
if (safi == SAFI_MPLS_VPN)
{
prn = bgp_node_get (table, (struct prefix *) prd);
@@ -88,7 +88,7 @@ bgp_afi_node_get (struct bgp_table *table, afi_t afi, safi_t safi, struct prefix
return rn;
}
-
+
/* Allocate bgp_info_extra */
static struct bgp_info_extra *
bgp_info_extra_new (void)
@@ -105,11 +105,11 @@ bgp_info_extra_free (struct bgp_info_extra **extra)
{
if ((*extra)->damp_info)
bgp_damp_info_free ((*extra)->damp_info, 0);
-
+
(*extra)->damp_info = NULL;
-
+
XFREE (MTYPE_BGP_ROUTE_EXTRA, *extra);
-
+
*extra = NULL;
}
}
@@ -138,7 +138,7 @@ bgp_info_free (struct bgp_info *binfo)
{
if (binfo->attr)
bgp_attr_unintern (binfo->attr);
-
+
bgp_info_extra_free (&binfo->extra);
peer_unlock (binfo->peer); /* bgp_info peer reference */
@@ -158,7 +158,7 @@ bgp_info_unlock (struct bgp_info *binfo)
{
assert (binfo && binfo->lock > 0);
binfo->lock--;
-
+
if (binfo->lock == 0)
{
#if 0
@@ -176,7 +176,7 @@ bgp_info_unlock (struct bgp_info *binfo)
zlog_backtrace (LOG_DEBUG);
}
#endif
-
+
return binfo;
}
@@ -186,19 +186,19 @@ bgp_info_add (struct bgp_node *rn, struct bgp_info *ri)
struct bgp_info *top;
top = rn->info;
-
+
ri->next = rn->info;
ri->prev = NULL;
if (top)
top->prev = ri;
rn->info = ri;
-
+
bgp_info_lock (ri);
bgp_lock_node (rn);
peer_lock (ri->peer); /* bgp_info peer reference */
}
-/* Do the actual removal of info from RIB, for use by bgp_process
+/* Do the actual removal of info from RIB, for use by bgp_process
completion callback *only* */
static void
bgp_info_reap (struct bgp_node *rn, struct bgp_info *ri)
@@ -209,7 +209,7 @@ bgp_info_reap (struct bgp_node *rn, struct bgp_info *ri)
ri->prev->next = ri->next;
else
rn->info = ri->next;
-
+
bgp_info_unlock (ri);
bgp_unlock_node (rn);
}
@@ -233,7 +233,7 @@ bgp_info_restore (struct bgp_node *rn, struct bgp_info *ri)
SET_FLAG (ri->flags, BGP_INFO_VALID);
}
-/* Adjust pcount as required */
+/* Adjust pcount as required */
static void
bgp_pcount_adjust (struct bgp_node *rn, struct bgp_info *ri)
{
@@ -244,13 +244,13 @@ bgp_pcount_adjust (struct bgp_node *rn, struct bgp_info *ri)
if (rn->table->type != BGP_TABLE_MAIN
|| ri->peer == ri->peer->bgp->peer_self)
return;
-
+
if (BGP_INFO_HOLDDOWN (ri)
&& CHECK_FLAG (ri->flags, BGP_INFO_COUNTED))
{
-
+
UNSET_FLAG (ri->flags, BGP_INFO_COUNTED);
-
+
/* slight hack, but more robust against errors. */
if (ri->peer->pcount[rn->table->afi][rn->table->safi])
ri->peer->pcount[rn->table->afi][rn->table->safi]--;
@@ -260,9 +260,9 @@ bgp_pcount_adjust (struct bgp_node *rn, struct bgp_info *ri)
__func__, ri->peer->host);
zlog_backtrace (LOG_WARNING);
zlog_warn ("%s: Please report to Quagga bugzilla", __func__);
- }
+ }
}
- else if (!BGP_INFO_HOLDDOWN (ri)
+ else if (!BGP_INFO_HOLDDOWN (ri)
&& !CHECK_FLAG (ri->flags, BGP_INFO_COUNTED))
{
SET_FLAG (ri->flags, BGP_INFO_COUNTED);
@@ -278,11 +278,11 @@ void
bgp_info_set_flag (struct bgp_node *rn, struct bgp_info *ri, u_int32_t flag)
{
SET_FLAG (ri->flags, flag);
-
+
/* early bath if we know it's not a flag that changes useability state */
if (!CHECK_FLAG (flag, BGP_INFO_VALID|BGP_INFO_UNUSEABLE))
return;
-
+
bgp_pcount_adjust (rn, ri);
}
@@ -290,11 +290,11 @@ void
bgp_info_unset_flag (struct bgp_node *rn, struct bgp_info *ri, u_int32_t flag)
{
UNSET_FLAG (ri->flags, flag);
-
+
/* early bath if we know it's not a flag that changes useability state */
if (!CHECK_FLAG (flag, BGP_INFO_VALID|BGP_INFO_UNUSEABLE))
return;
-
+
bgp_pcount_adjust (rn, ri);
}
@@ -358,7 +358,7 @@ bgp_info_cmp (struct bgp *bgp, struct bgp_info *new, struct bgp_info *exist)
exist_pref = exist->attr->local_pref;
else
exist_pref = bgp->default_local_pref;
-
+
if (new_pref > exist_pref)
return 1;
if (new_pref < exist_pref)
@@ -385,14 +385,14 @@ bgp_info_cmp (struct bgp *bgp, struct bgp_info *new, struct bgp_info *exist)
{
int exist_hops = aspath_count_hops (exist->attr->aspath);
int exist_confeds = aspath_count_confeds (exist->attr->aspath);
-
+
if (bgp_flag_check (bgp, BGP_FLAG_ASPATH_CONFED))
{
int aspath_hops;
-
+
aspath_hops = aspath_count_hops (new->attr->aspath);
aspath_hops += aspath_count_confeds (new->attr->aspath);
-
+
if ( aspath_hops < (exist_hops + exist_confeds))
return 1;
if ( aspath_hops > (exist_hops + exist_confeds))
@@ -401,7 +401,7 @@ bgp_info_cmp (struct bgp *bgp, struct bgp_info *new, struct bgp_info *exist)
else
{
int newhops = aspath_count_hops (new->attr->aspath);
-
+
if (newhops < exist_hops)
return 1;
if (newhops > exist_hops)
@@ -422,7 +422,7 @@ bgp_info_cmp (struct bgp *bgp, struct bgp_info *new, struct bgp_info *exist)
&& aspath_count_confeds (exist->attr->aspath) > 0
&& aspath_count_hops (new->attr->aspath) == 0
&& aspath_count_hops (exist->attr->aspath) == 0);
-
+
if (bgp_flag_check (bgp, BGP_FLAG_ALWAYS_COMPARE_MED)
|| (bgp_flag_check (bgp, BGP_FLAG_MED_CONFED)
&& confed_as_route)
@@ -440,16 +440,16 @@ bgp_info_cmp (struct bgp *bgp, struct bgp_info *new, struct bgp_info *exist)
}
/* 7. Peer type check. */
- if (peer_sort (new->peer) == BGP_PEER_EBGP
+ if (peer_sort (new->peer) == BGP_PEER_EBGP
&& peer_sort (exist->peer) == BGP_PEER_IBGP)
return 1;
- if (peer_sort (new->peer) == BGP_PEER_EBGP
+ if (peer_sort (new->peer) == BGP_PEER_EBGP
&& peer_sort (exist->peer) == BGP_PEER_CONFED)
return 1;
- if (peer_sort (new->peer) == BGP_PEER_IBGP
+ if (peer_sort (new->peer) == BGP_PEER_IBGP
&& peer_sort (exist->peer) == BGP_PEER_EBGP)
return 0;
- if (peer_sort (new->peer) == BGP_PEER_CONFED
+ if (peer_sort (new->peer) == BGP_PEER_CONFED
&& peer_sort (exist->peer) == BGP_PEER_EBGP)
return 0;
@@ -458,7 +458,7 @@ bgp_info_cmp (struct bgp *bgp, struct bgp_info *new, struct bgp_info *exist)
{
uint32_t newm = (new->extra ? new->extra->igpmetric : 0);
uint32_t existm = (exist->extra ? exist->extra->igpmetric : 0);
-
+
if (newm < existm)
return 1;
if (newm > existm)
@@ -532,31 +532,31 @@ bgp_input_filter (struct peer *peer, struct prefix *p, struct attr *attr,
#define FILTER_EXIST_WARN(F,f,filter) \
if (BGP_DEBUG (update, UPDATE_IN) \
- && !(F ## _IN (filter))) \
+ && !(F ## _IN_LIST (filter))) \
plog_warn (peer->log, "%s: Could not find configured input %s-list %s!", \
peer->host, #f, F ## _IN_NAME(filter));
-
+
if (DISTRIBUTE_IN_NAME (filter)) {
FILTER_EXIST_WARN(DISTRIBUTE, distribute, filter);
-
- if (access_list_apply (DISTRIBUTE_IN (filter), p) == FILTER_DENY)
+
+ if (access_list_apply (DISTRIBUTE_IN_LIST (filter), p) == FILTER_DENY)
return FILTER_DENY;
}
if (PREFIX_LIST_IN_NAME (filter)) {
FILTER_EXIST_WARN(PREFIX_LIST, prefix, filter);
-
- if (prefix_list_apply (PREFIX_LIST_IN (filter), p) == PREFIX_DENY)
+
+ if (prefix_list_apply (PREFIX_LIST_IN_LIST(filter), p) == PREFIX_DENY)
return FILTER_DENY;
}
-
+
if (FILTER_LIST_IN_NAME (filter)) {
FILTER_EXIST_WARN(FILTER_LIST, as, filter);
-
- if (as_list_apply (FILTER_LIST_IN (filter), attr->aspath)== AS_FILTER_DENY)
+
+ if (as_list_apply (FILTER_LIST_IN_LIST (filter), attr->aspath)== AS_FILTER_DENY)
return FILTER_DENY;
}
-
+
return FILTER_PERMIT;
#undef FILTER_EXIST_WARN
}
@@ -571,28 +571,29 @@ bgp_output_filter (struct peer *peer, struct prefix *p, struct attr *attr,
#define FILTER_EXIST_WARN(F,f,filter) \
if (BGP_DEBUG (update, UPDATE_OUT) \
- && !(F ## _OUT (filter))) \
+ && !(F ## _OUT_LIST (filter))) \
plog_warn (peer->log, "%s: Could not find configured output %s-list %s!", \
peer->host, #f, F ## _OUT_NAME(filter));
if (DISTRIBUTE_OUT_NAME (filter)) {
FILTER_EXIST_WARN(DISTRIBUTE, distribute, filter);
-
- if (access_list_apply (DISTRIBUTE_OUT (filter), p) == FILTER_DENY)
+
+ if (access_list_apply (DISTRIBUTE_OUT_LIST (filter), p) == FILTER_DENY)
return FILTER_DENY;
}
- if (PREFIX_LIST_OUT_NAME (filter)) {
+ if (PREFIX_LIST_OUT_REF (filter)) {
FILTER_EXIST_WARN(PREFIX_LIST, prefix, filter);
-
- if (prefix_list_apply (PREFIX_LIST_OUT (filter), p) == PREFIX_DENY)
+
+ if (prefix_list_apply (PREFIX_LIST_OUT_LIST (filter), p) == PREFIX_DENY)
return FILTER_DENY;
}
if (FILTER_LIST_OUT_NAME (filter)) {
FILTER_EXIST_WARN(FILTER_LIST, as, filter);
-
- if (as_list_apply (FILTER_LIST_OUT (filter), attr->aspath) == AS_FILTER_DENY)
+
+ if (as_list_apply (FILTER_LIST_OUT_LIST (filter), attr->aspath)
+ == AS_FILTER_DENY)
return FILTER_DENY;
}
@@ -616,7 +617,7 @@ bgp_community_filter (struct peer *peer, struct attr *attr)
return 1;
/* NO_EXPORT_SUBCONFED check. */
- if (peer_sort (peer) == BGP_PEER_EBGP
+ if (peer_sort (peer) == BGP_PEER_EBGP
|| peer_sort (peer) == BGP_PEER_CONFED)
if (community_include (attr->community, COMMUNITY_NO_EXPORT_SUBCONFED))
return 1;
@@ -636,13 +637,13 @@ bgp_cluster_filter (struct peer *peer, struct attr *attr)
cluster_id = peer->bgp->cluster_id;
else
cluster_id = peer->bgp->router_id;
-
+
if (cluster_loop_check (attr->extra->cluster, cluster_id))
return 1;
}
return 0;
}
-
+
static int
bgp_input_modifier (struct peer *peer, struct prefix *p, struct attr *attr,
afi_t afi, safi_t safi)
@@ -664,7 +665,7 @@ bgp_input_modifier (struct peer *peer, struct prefix *p, struct attr *attr,
info.peer = peer;
info.attr = attr;
- SET_FLAG (peer->rmap_type, PEER_RMAP_TYPE_IN);
+ SET_FLAG (peer->rmap_type, PEER_RMAP_TYPE_IN);
/* Apply BGP route map to the attribute. */
ret = route_map_apply (ROUTE_MAP_IN (filter), p, RMAP_BGP, &info);
@@ -680,7 +681,7 @@ bgp_input_modifier (struct peer *peer, struct prefix *p, struct attr *attr,
}
return RMAP_PERMIT;
}
-
+
static int
bgp_export_modifier (struct peer *rsclient, struct peer *peer,
struct prefix *p, struct attr *attr, afi_t afi, safi_t safi)
@@ -752,7 +753,7 @@ bgp_import_modifier (struct peer *rsclient, struct peer *peer,
}
return RMAP_PERMIT;
}
-
+
static int
bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p,
struct attr *attr, afi_t afi, safi_t safi)
@@ -768,7 +769,7 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p,
from = ri->peer;
filter = &peer->filter[afi][safi];
bgp = peer->bgp;
-
+
if (DISABLE_BGP_ANNOUNCE)
return 0;
@@ -814,7 +815,7 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p,
transparent = 0;
/* If community is not disabled check the no-export and local. */
- if (! transparent && bgp_community_filter (peer, ri->attr))
+ if (! transparent && bgp_community_filter (peer, ri->attr))
return 0;
/* If the attribute has originator-id and it is same as remote
@@ -823,7 +824,7 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p,
{
if (IPV4_ADDR_SAME (&peer->remote_id, &ri->attr->extra->originator_id))
{
- if (BGP_DEBUG (filter, FILTER))
+ if (BGP_DEBUG (filter, FILTER))
zlog (peer->log, LOG_DEBUG,
"%s [Update:SEND] %s/%d originator-id is same as remote router-id",
peer->host,
@@ -832,7 +833,7 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p,
return 0;
}
}
-
+
/* ORF prefix-list filter check */
if (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_ADV)
&& (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_RCV)
@@ -859,8 +860,8 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p,
/* AS path loop check. */
if (aspath_loop_check (ri->attr->aspath, peer->as))
{
- if (BGP_DEBUG (filter, FILTER))
- zlog (peer->log, LOG_DEBUG,
+ if (BGP_DEBUG (filter, FILTER))
+ zlog (peer->log, LOG_DEBUG,
"%s [Update:SEND] suppress announcement to peer AS %u is AS path.",
peer->host, peer->as);
return 0;
@@ -872,13 +873,13 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p,
{
if (aspath_loop_check(ri->attr->aspath, bgp->confed_id))
{
- if (BGP_DEBUG (filter, FILTER))
- zlog (peer->log, LOG_DEBUG,
+ if (BGP_DEBUG (filter, FILTER))
+ zlog (peer->log, LOG_DEBUG,
"%s [Update:SEND] suppress announcement to peer AS %u is AS path.",
peer->host,
bgp->confed_id);
return 0;
- }
+ }
}
/* Route-Reflect check. */
@@ -909,7 +910,7 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p,
return 0;
}
}
-
+
/* AS-Pathlimit check */
if (ri->attr->pathlimit.ttl && peer_sort (peer) == BGP_PEER_EBGP)
/* Our ASN has not yet been pre-pended, that's done in packet_attribute
@@ -922,13 +923,13 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p,
peer->host, ri->attr->pathlimit.ttl);
return 0;
}
-
+
/* For modify attribute, copy it to temporary structure. */
bgp_attr_dup (attr, ri->attr);
-
+
/* If local-preference is not set. */
- if ((peer_sort (peer) == BGP_PEER_IBGP
- || peer_sort (peer) == BGP_PEER_CONFED)
+ if ((peer_sort (peer) == BGP_PEER_IBGP
+ || peer_sort (peer) == BGP_PEER_CONFED)
&& (! (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))))
{
attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF);
@@ -936,7 +937,7 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p,
}
/* Remove MED if its an EBGP peer - will get overwritten by route-maps */
- if (peer_sort (peer) == BGP_PEER_EBGP
+ if (peer_sort (peer) == BGP_PEER_EBGP
&& attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
{
if (ri->peer != bgp->peer_self && ! transparent
@@ -949,7 +950,7 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p,
|| (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_NEXTHOP_UNCHANGED)
&& ((p->family == AF_INET && attr->nexthop.s_addr)
#ifdef HAVE_IPV6
- || (p->family == AF_INET6 &&
+ || (p->family == AF_INET6 &&
! IN6_IS_ADDR_UNSPECIFIED(&attr->extra->mp_nexthop_global))
#endif /* HAVE_IPV6 */
)))
@@ -959,7 +960,7 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p,
else if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_NEXTHOP_SELF)
|| (p->family == AF_INET && attr->nexthop.s_addr == 0)
#ifdef HAVE_IPV6
- || (p->family == AF_INET6 &&
+ || (p->family == AF_INET6 &&
IN6_IS_ADDR_UNSPECIFIED(&attr->extra->mp_nexthop_global))
#endif /* HAVE_IPV6 */
|| (peer_sort (peer) == BGP_PEER_EBGP
@@ -979,7 +980,7 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p,
if (p->family == AF_INET6)
{
/* IPv6 global nexthop must be included. */
- memcpy (&attr->extra->mp_nexthop_global, &peer->nexthop.v6_global,
+ memcpy (&attr->extra->mp_nexthop_global, &peer->nexthop.v6_global,
IPV6_MAX_BYTELEN);
attr->extra->mp_nexthop_len = 16;
}
@@ -989,8 +990,8 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p,
#ifdef HAVE_IPV6
if (p->family == AF_INET6)
{
- /* Left nexthop_local unchanged if so configured. */
- if ( CHECK_FLAG (peer->af_flags[afi][safi],
+ /* Left nexthop_local unchanged if so configured. */
+ if ( CHECK_FLAG (peer->af_flags[afi][safi],
PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED) )
{
if ( IN6_IS_ADDR_LINKLOCAL (&attr->extra->mp_nexthop_local) )
@@ -1000,16 +1001,16 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p,
}
/* Default nexthop_local treatment for non-RS-Clients */
- else
+ else
{
/* Link-local address should not be transit to different peer. */
attr->extra->mp_nexthop_len = 16;
/* Set link-local address for shared network peer. */
- if (peer->shared_network
+ if (peer->shared_network
&& ! IN6_IS_ADDR_UNSPECIFIED (&peer->nexthop.v6_local))
{
- memcpy (&attr->extra->mp_nexthop_local, &peer->nexthop.v6_local,
+ memcpy (&attr->extra->mp_nexthop_local, &peer->nexthop.v6_local,
IPV6_MAX_BYTELEN);
attr->extra->mp_nexthop_len = 32;
}
@@ -1033,13 +1034,13 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p,
/* locally originated update */
if (!attr->pathlimit.as)
attr->pathlimit.as = peer->local_as;
-
+
/* if the AS_PATHLIMIT attribute is attached to a prefix by a
member of a confederation, then when the prefix is advertised outside
of the confederation boundary, then the AS number of the
confederation member inside of the AS_PATHLIMIT attribute should be
replaced by the confederation's AS number. */
- if (peer_sort (from) == BGP_PEER_CONFED
+ if (peer_sort (from) == BGP_PEER_CONFED
&& peer_sort (peer) != BGP_PEER_CONFED)
attr->pathlimit.as = peer->local_as;
@@ -1050,7 +1051,7 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p,
if (attr->pathlimit.as >= BGP_PRIVATE_AS_MIN
&& attr->pathlimit.as <= BGP_PRIVATE_AS_MAX)
{
- if (peer->local_as < BGP_PRIVATE_AS_MIN
+ if (peer->local_as < BGP_PRIVATE_AS_MIN
|| peer->local_as > BGP_PRIVATE_AS_MAX)
attr->pathlimit.as = peer->local_as;
/* Ours is private, try using theirs.. */
@@ -1059,7 +1060,7 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p,
attr->pathlimit.as = peer->as;
}
}
-
+
/* If this is EBGP peer and remove-private-AS is set. */
if (peer_sort (peer) == BGP_PEER_EBGP
&& peer_af_flag_check (peer, afi, safi, PEER_FLAG_REMOVE_PRIVATE_AS)
@@ -1072,20 +1073,20 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p,
{
struct bgp_info info;
struct attr dummy_attr = { 0 };
-
+
info.peer = peer;
info.attr = attr;
/* The route reflector is not allowed to modify the attributes
of the reflected IBGP routes. */
- if (peer_sort (from) == BGP_PEER_IBGP
+ if (peer_sort (from) == BGP_PEER_IBGP
&& peer_sort (peer) == BGP_PEER_IBGP)
{
bgp_attr_dup (&dummy_attr, attr);
info.attr = &dummy_attr;
}
- SET_FLAG (peer->rmap_type, PEER_RMAP_TYPE_OUT);
+ SET_FLAG (peer->rmap_type, PEER_RMAP_TYPE_OUT);
if (ri->extra && ri->extra->suppress)
ret = route_map_apply (UNSUPPRESS_MAP (filter), p, RMAP_BGP, &info);
@@ -1093,10 +1094,10 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p,
ret = route_map_apply (ROUTE_MAP_OUT (filter), p, RMAP_BGP, &info);
peer->rmap_type = 0;
-
+
if (dummy_attr.extra)
bgp_attr_extra_free (&dummy_attr);
-
+
if (ret == RMAP_DENYMATCH)
{
bgp_attr_flush (attr);
@@ -1149,7 +1150,7 @@ bgp_announce_check_rsclient (struct bgp_info *ri, struct peer *rsclient,
peer's id. */
if (ri->attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID))
{
- if (IPV4_ADDR_SAME (&rsclient->remote_id,
+ if (IPV4_ADDR_SAME (&rsclient->remote_id,
&ri->attr->extra->originator_id))
{
if (BGP_DEBUG (filter, FILTER))
@@ -1232,11 +1233,11 @@ bgp_announce_check_rsclient (struct bgp_info *ri, struct peer *rsclient,
if (p->family == AF_INET6)
{
struct attr_extra *attre = attr->extra;
-
+
assert (attr->extra);
-
+
/* Left nexthop_local unchanged if so configured. */
- if ( CHECK_FLAG (rsclient->af_flags[afi][safi],
+ if ( CHECK_FLAG (rsclient->af_flags[afi][safi],
PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED) )
{
if ( IN6_IS_ADDR_LINKLOCAL (&attre->mp_nexthop_local) )
@@ -1244,11 +1245,11 @@ bgp_announce_check_rsclient (struct bgp_info *ri, struct peer *rsclient,
else
attre->mp_nexthop_len=16;
}
-
+
/* Default nexthop_local treatment for RS-Clients */
- else
- {
- /* Announcer and RS-Client are both in the same network */
+ else
+ {
+ /* Announcer and RS-Client are both in the same network */
if (rsclient->shared_network && from->shared_network &&
(rsclient->ifindex == from->ifindex))
{
@@ -1321,7 +1322,7 @@ bgp_best_selection (struct bgp *bgp, struct bgp_node *rn, struct bgp_info_pair *
struct bgp_info *ri1;
struct bgp_info *ri2;
struct bgp_info *nextri = NULL;
-
+
/* bgp deterministic-med */
new_select = NULL;
if (bgp_flag_check (bgp, BGP_FLAG_DETERMINISTIC_MED))
@@ -1368,13 +1369,13 @@ bgp_best_selection (struct bgp *bgp, struct bgp_node *rn, struct bgp_info_pair *
if (BGP_INFO_HOLDDOWN (ri))
{
- /* reap REMOVED routes, if needs be
+ /* reap REMOVED routes, if needs be
* selected route must stay for a while longer though
*/
if (CHECK_FLAG (ri->flags, BGP_INFO_REMOVED)
&& (ri != old_select))
bgp_info_reap (rn, ri);
-
+
continue;
}
@@ -1390,7 +1391,7 @@ bgp_best_selection (struct bgp *bgp, struct bgp_node *rn, struct bgp_info_pair *
if (bgp_info_cmp (bgp, ri, new_select))
new_select = ri;
}
-
+
result->old = old_select;
result->new = new_select;
@@ -1430,22 +1431,22 @@ bgp_process_announce_selected (struct peer *peer, struct bgp_info *selected,
bgp_adj_out_unset (rn, peer, p, afi, safi);
break;
case BGP_TABLE_RSCLIENT:
- /* Announcement to peer->conf. If the route is filtered,
+ /* Announcement to peer->conf. If the route is filtered,
withdraw it. */
- if (selected &&
+ if (selected &&
bgp_announce_check_rsclient (selected, peer, p, &attr, afi, safi))
bgp_adj_out_set (rn, peer, p, &attr, afi, safi, selected);
else
bgp_adj_out_unset (rn, peer, p, afi, safi);
break;
}
-
+
bgp_attr_extra_free (&attr);
-
+
return 0;
}
-struct bgp_process_queue
+struct bgp_process_queue
{
struct bgp *bgp;
struct bgp_node *rn;
@@ -1466,7 +1467,7 @@ bgp_process_rsclient (struct work_queue *wq, void *data)
struct bgp_info_pair old_and_new;
struct listnode *node, *nnode;
struct peer *rsclient = rn->table->owner;
-
+
/* Best path selection. */
bgp_best_selection (bgp, rn, &old_and_new);
new_select = old_and_new.new;
@@ -1508,7 +1509,7 @@ bgp_process_rsclient (struct work_queue *wq, void *data)
if (old_select && CHECK_FLAG (old_select->flags, BGP_INFO_REMOVED))
bgp_info_reap (rn, old_select);
-
+
UNSET_FLAG (rn->flags, BGP_NODE_PROCESS_SCHEDULED);
return WQ_SUCCESS;
}
@@ -1527,7 +1528,7 @@ bgp_process_main (struct work_queue *wq, void *data)
struct bgp_info_pair old_and_new;
struct listnode *node, *nnode;
struct peer *peer;
-
+
/* Best path selection. */
bgp_best_selection (bgp, rn, &old_and_new);
old_select = old_and_new.old;
@@ -1540,7 +1541,7 @@ bgp_process_main (struct work_queue *wq, void *data)
{
if (CHECK_FLAG (old_select->flags, BGP_INFO_IGP_CHANGED))
bgp_zebra_announce (p, old_select, bgp);
-
+
UNSET_FLAG (rn->flags, BGP_NODE_PROCESS_SCHEDULED);
return WQ_SUCCESS;
}
@@ -1565,24 +1566,24 @@ bgp_process_main (struct work_queue *wq, void *data)
if (safi == SAFI_UNICAST && ! bgp->name &&
! bgp_option_check (BGP_OPT_NO_FIB))
{
- if (new_select
- && new_select->type == ZEBRA_ROUTE_BGP
+ if (new_select
+ && new_select->type == ZEBRA_ROUTE_BGP
&& new_select->sub_type == BGP_ROUTE_NORMAL)
bgp_zebra_announce (p, new_select, bgp);
else
{
/* Withdraw the route from the kernel. */
- if (old_select
+ if (old_select
&& old_select->type == ZEBRA_ROUTE_BGP
&& old_select->sub_type == BGP_ROUTE_NORMAL)
bgp_zebra_withdraw (p, old_select);
}
}
-
+
/* Reap old select bgp_info, it it has been removed */
if (old_select && CHECK_FLAG (old_select->flags, BGP_INFO_REMOVED))
bgp_info_reap (rn, old_select);
-
+
UNSET_FLAG (rn->flags, BGP_NODE_PROCESS_SCHEDULED);
return WQ_SUCCESS;
}
@@ -1592,7 +1593,7 @@ bgp_processq_del (struct work_queue *wq, void *data)
{
struct bgp_process_queue *pq = data;
struct bgp_table *table = pq->rn->table;
-
+
bgp_unlock (pq->bgp);
bgp_unlock_node (pq->rn);
bgp_table_unlock (table);
@@ -1606,13 +1607,13 @@ bgp_process_queue_init (void)
= work_queue_new (bm->master, "process_main_queue");
bm->process_rsclient_queue
= work_queue_new (bm->master, "process_rsclient_queue");
-
+
if ( !(bm->process_main_queue && bm->process_rsclient_queue) )
{
zlog_err ("%s: Failed to allocate work queue", __func__);
exit (1);
}
-
+
bm->process_main_queue->spec.workfunc = &bgp_process_main;
bm->process_rsclient_queue->spec.workfunc = &bgp_process_rsclient;
bm->process_main_queue->spec.del_item_data = &bgp_processq_del;
@@ -1628,16 +1629,16 @@ void
bgp_process (struct bgp *bgp, struct bgp_node *rn, afi_t afi, safi_t safi)
{
struct bgp_process_queue *pqnode;
-
+
/* already scheduled for processing? */
if (CHECK_FLAG (rn->flags, BGP_NODE_PROCESS_SCHEDULED))
return;
-
+
if ( (bm->process_main_queue == NULL) ||
(bm->process_rsclient_queue == NULL) )
bgp_process_queue_init ();
-
- pqnode = XCALLOC (MTYPE_BGP_PROCESS_QUEUE,
+
+ pqnode = XCALLOC (MTYPE_BGP_PROCESS_QUEUE,
sizeof (struct bgp_process_queue));
if (!pqnode)
return;
@@ -1649,7 +1650,7 @@ bgp_process (struct bgp *bgp, struct bgp_node *rn, afi_t afi, safi_t safi)
bgp_lock (bgp);
pqnode->afi = afi;
pqnode->safi = safi;
-
+
switch (rn->table->type)
{
case BGP_TABLE_MAIN:
@@ -1659,7 +1660,7 @@ bgp_process (struct bgp *bgp, struct bgp_node *rn, afi_t afi, safi_t safi)
work_queue_add (bm->process_rsclient_queue, pqnode);
break;
}
-
+
return;
}
@@ -1681,7 +1682,7 @@ bgp_maximum_prefix_restart_timer (struct thread *thread)
}
int
-bgp_maximum_prefix_overflow (struct peer *peer, afi_t afi,
+bgp_maximum_prefix_overflow (struct peer *peer, afi_t afi,
safi_t safi, int always)
{
if (!CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX))
@@ -1707,7 +1708,7 @@ bgp_maximum_prefix_overflow (struct peer *peer, afi_t afi,
if (safi == SAFI_MPLS_VPN)
safi = BGP_SAFI_VPNV4;
-
+
ndata[0] = (afi >> 8);
ndata[1] = afi;
ndata[2] = safi;
@@ -1764,10 +1765,10 @@ bgp_rib_remove (struct bgp_node *rn, struct bgp_info *ri, struct peer *peer,
afi_t afi, safi_t safi)
{
bgp_aggregate_decrement (peer->bgp, &rn->p, ri, afi, safi);
-
+
if (!CHECK_FLAG (ri->flags, BGP_INFO_HISTORY))
bgp_info_delete (rn, ri); /* keep historical info */
-
+
bgp_process (peer->bgp, rn, afi, safi);
}
@@ -1777,18 +1778,18 @@ bgp_rib_withdraw (struct bgp_node *rn, struct bgp_info *ri, struct peer *peer,
{
int status = BGP_DAMP_NONE;
- /* apply dampening, if result is suppressed, we'll be retaining
+ /* apply dampening, if result is suppressed, we'll be retaining
* the bgp_info in the RIB for historical reference.
*/
if (CHECK_FLAG (peer->bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING)
&& peer_sort (peer) == BGP_PEER_EBGP)
- if ( (status = bgp_damp_withdraw (ri, rn, afi, safi, 0))
+ if ( (status = bgp_damp_withdraw (ri, rn, afi, safi, 0))
== BGP_DAMP_SUPPRESSED)
{
bgp_aggregate_decrement (peer->bgp, &rn->p, ri, afi, safi);
return;
}
-
+
bgp_rib_remove (rn, ri, peer, afi, safi);
}
@@ -1833,7 +1834,7 @@ bgp_update_rsclient (struct peer *rsclient, afi_t afi, safi_t safi,
reason = "originator is us;";
goto filtered;
}
-
+
bgp_attr_dup (&new_attr, attr);
/* Apply export policy. */
@@ -1845,7 +1846,7 @@ bgp_update_rsclient (struct peer *rsclient, afi_t afi, safi_t safi,
}
attr_new2 = bgp_attr_intern (&new_attr);
-
+
/* Apply import policy. */
if (bgp_import_modifier (rsclient, peer, p, &new_attr, afi, safi) == RMAP_DENY)
{
@@ -1871,10 +1872,10 @@ bgp_update_rsclient (struct peer *rsclient, afi_t afi, safi_t safi,
goto filtered;
}
}
-
+
/* new_attr isn't passed to any functions after here */
bgp_attr_extra_free (&new_attr);
-
+
/* If the update is implicit withdraw. */
if (ri)
{
@@ -1903,7 +1904,7 @@ bgp_update_rsclient (struct peer *rsclient, afi_t afi, safi_t safi,
/* Withdraw/Announce before we fully processed the withdraw */
if (CHECK_FLAG(ri->flags, BGP_INFO_REMOVED))
bgp_info_restore (rn, ri);
-
+
/* Received Logging. */
if (BGP_DEBUG (update, UPDATE_IN))
zlog (peer->log, LOG_DEBUG, "%s rcvd %s/%d for RS-client %s",
@@ -1956,18 +1957,18 @@ bgp_update_rsclient (struct peer *rsclient, afi_t afi, safi_t safi,
/* Register new BGP information. */
bgp_info_add (rn, new);
-
+
/* route_node_get lock */
bgp_unlock_node (rn);
-
+
/* Process change. */
bgp_process (bgp, rn, afi, safi);
-
+
bgp_attr_extra_free (&new_attr);
-
+
return;
- filtered:
+ filtered:
/* This BGP update is filtered. Log the reason then update BGP entry. */
if (BGP_DEBUG (update, UPDATE_IN))
@@ -1981,10 +1982,10 @@ bgp_update_rsclient (struct peer *rsclient, afi_t afi, safi_t safi,
bgp_rib_remove (rn, ri, peer, afi, safi);
bgp_unlock_node (rn);
-
+
if (new_attr.extra)
bgp_attr_extra_free (&new_attr);
-
+
return;
}
@@ -2038,7 +2039,7 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr,
bgp = peer->bgp;
rn = bgp_afi_node_get (bgp->rib[afi][safi], afi, safi, p, prd);
-
+
/* When peer's soft reconfiguration enabled. Record input packet in
Adj-RIBs-In. */
if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SOFT_RECONFIG)
@@ -2056,7 +2057,7 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr,
if (! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND))
aspath_loop_count = 1;
- if (aspath_loop_check (attr->aspath, peer->change_local_as) > aspath_loop_count)
+ if (aspath_loop_check (attr->aspath, peer->change_local_as) > aspath_loop_count)
{
reason = "as-path contains our own AS;";
goto filtered;
@@ -2136,7 +2137,7 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr,
ri->uptime = time (NULL);
/* Same attribute comes in. */
- if (!CHECK_FLAG (ri->flags, BGP_INFO_REMOVED)
+ if (!CHECK_FLAG (ri->flags, BGP_INFO_REMOVED)
&& attrhash_cmp (ri->attr, attr_new))
{
bgp_info_unset_flag (rn, ri, BGP_INFO_ATTR_CHANGED);
@@ -2145,7 +2146,7 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr,
&& peer_sort (peer) == BGP_PEER_EBGP
&& CHECK_FLAG (ri->flags, BGP_INFO_HISTORY))
{
- if (BGP_DEBUG (update, UPDATE_IN))
+ if (BGP_DEBUG (update, UPDATE_IN))
zlog (peer->log, LOG_DEBUG, "%s rcvd %s/%d",
peer->host,
inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
@@ -2159,7 +2160,7 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr,
}
else /* Duplicate - odd */
{
- if (BGP_DEBUG (update, UPDATE_IN))
+ if (BGP_DEBUG (update, UPDATE_IN))
zlog (peer->log, LOG_DEBUG,
"%s rcvd %s/%d...duplicate ignored",
peer->host,
@@ -2177,7 +2178,7 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr,
bgp_unlock_node (rn);
bgp_attr_unintern (attr_new);
bgp_attr_extra_free (&new_attr);
-
+
return 0;
}
@@ -2193,7 +2194,7 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr,
}
/* Received Logging. */
- if (BGP_DEBUG (update, UPDATE_IN))
+ if (BGP_DEBUG (update, UPDATE_IN))
zlog (peer->log, LOG_DEBUG, "%s rcvd %s/%d",
peer->host,
inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
@@ -2205,12 +2206,12 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr,
/* The attribute is changed. */
bgp_info_set_flag (rn, ri, BGP_INFO_ATTR_CHANGED);
-
+
/* implicit withdraw, decrement aggregate and pcount here.
* only if update is accepted, they'll increment below.
*/
bgp_aggregate_decrement (bgp, p, ri, afi, safi);
-
+
/* Update bgp route dampening information. */
if (CHECK_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING)
&& peer_sort (peer) == BGP_PEER_EBGP)
@@ -2218,9 +2219,9 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr,
/* This is implicit withdraw so we should update dampening
information. */
if (! CHECK_FLAG (ri->flags, BGP_INFO_HISTORY))
- bgp_damp_withdraw (ri, rn, afi, safi, 1);
+ bgp_damp_withdraw (ri, rn, afi, safi, 1);
}
-
+
/* Update to new attribute. */
bgp_attr_unintern (ri->attr);
ri->attr = attr_new;
@@ -2245,7 +2246,7 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr,
/* Nexthop reachability check. */
if ((afi == AFI_IP || afi == AFI_IP6)
- && safi == SAFI_UNICAST
+ && safi == SAFI_UNICAST
&& (peer_sort (peer) == BGP_PEER_IBGP
|| peer_sort (peer) == BGP_PEER_CONFED
|| (peer_sort (peer) == BGP_PEER_EBGP && peer->ttl != 1)
@@ -2265,12 +2266,12 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr,
bgp_process (bgp, rn, afi, safi);
bgp_unlock_node (rn);
bgp_attr_extra_free (&new_attr);
-
+
return 0;
}
/* Received Logging. */
- if (BGP_DEBUG (update, UPDATE_IN))
+ if (BGP_DEBUG (update, UPDATE_IN))
{
zlog (peer->log, LOG_DEBUG, "%s rcvd %s/%d",
peer->host,
@@ -2308,15 +2309,15 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr,
/* Increment prefix */
bgp_aggregate_increment (bgp, p, new, afi, safi);
-
+
/* Register new BGP information. */
bgp_info_add (rn, new);
-
+
/* route_node_get lock */
bgp_unlock_node (rn);
-
+
bgp_attr_extra_free (&new_attr);
-
+
/* If maximum prefix count is configured and current prefix
count exeed it. */
if (bgp_maximum_prefix_overflow (peer, afi, safi, 0))
@@ -2341,9 +2342,9 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr,
bgp_rib_remove (rn, ri, peer, afi, safi);
bgp_unlock_node (rn);
-
+
bgp_attr_extra_free (&new_attr);
-
+
return 0;
}
@@ -2374,8 +2375,8 @@ bgp_update (struct peer *peer, struct prefix *p, struct attr *attr,
}
int
-bgp_withdraw (struct peer *peer, struct prefix *p, struct attr *attr,
- afi_t afi, safi_t safi, int type, int sub_type,
+bgp_withdraw (struct peer *peer, struct prefix *p, struct attr *attr,
+ afi_t afi, safi_t safi, int type, int sub_type,
struct prefix_rd *prd, u_char *tag)
{
struct bgp *bgp;
@@ -2395,7 +2396,7 @@ bgp_withdraw (struct peer *peer, struct prefix *p, struct attr *attr,
}
/* Logging. */
- if (BGP_DEBUG (update, UPDATE_IN))
+ if (BGP_DEBUG (update, UPDATE_IN))
zlog (peer->log, LOG_DEBUG, "%s rcvd UPDATE about %s/%d -- withdrawn",
peer->host,
inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
@@ -2419,7 +2420,7 @@ bgp_withdraw (struct peer *peer, struct prefix *p, struct attr *attr,
if (ri && ! CHECK_FLAG (ri->flags, BGP_INFO_HISTORY))
bgp_rib_withdraw (rn, ri, peer, afi, safi);
else if (BGP_DEBUG (update, UPDATE_IN))
- zlog (peer->log, LOG_DEBUG,
+ zlog (peer->log, LOG_DEBUG,
"%s Can't find the route %s/%d", peer->host,
inet_ntop (p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
p->prefixlen);
@@ -2429,7 +2430,7 @@ bgp_withdraw (struct peer *peer, struct prefix *p, struct attr *attr,
return 0;
}
-
+
void
bgp_default_originate (struct peer *peer, afi_t afi, safi_t safi, int withdraw)
{
@@ -2440,13 +2441,13 @@ bgp_default_originate (struct peer *peer, afi_t afi, safi_t safi, int withdraw)
struct bgp_info binfo;
struct peer *from;
int ret = RMAP_DENYMATCH;
-
+
if (!(afi == AFI_IP || afi == AFI_IP6))
return;
-
+
bgp = peer->bgp;
from = bgp->peer_self;
-
+
bgp_attr_default_set (&attr, BGP_ORIGIN_IGP);
aspath = attr.aspath;
attr.local_pref = bgp->default_local_pref;
@@ -2459,23 +2460,23 @@ bgp_default_originate (struct peer *peer, afi_t afi, safi_t safi, int withdraw)
{
struct attr_extra *ae;
attr.extra = NULL;
-
+
ae = bgp_attr_extra_get (&attr);
attr.extra = ae;
-
+
str2prefix ("::/0", &p);
/* IPv6 global nexthop must be included. */
- memcpy (&ae->mp_nexthop_global, &peer->nexthop.v6_global,
+ memcpy (&ae->mp_nexthop_global, &peer->nexthop.v6_global,
IPV6_MAX_BYTELEN);
ae->mp_nexthop_len = 16;
-
+
/* If the peer is on shared nextwork and we have link-local
nexthop set it. */
- if (peer->shared_network
+ if (peer->shared_network
&& !IN6_IS_ADDR_UNSPECIFIED (&peer->nexthop.v6_local))
{
- memcpy (&ae->mp_nexthop_local, &peer->nexthop.v6_local,
+ memcpy (&ae->mp_nexthop_local, &peer->nexthop.v6_local,
IPV6_MAX_BYTELEN);
ae->mp_nexthop_len = 32;
}
@@ -2512,11 +2513,11 @@ bgp_default_originate (struct peer *peer, afi_t afi, safi_t safi, int withdraw)
SET_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_DEFAULT_ORIGINATE);
bgp_default_update_send (peer, &attr, afi, safi, from);
}
-
+
bgp_attr_extra_free (&attr);
aspath_unintern (aspath);
}
-
+
static void
bgp_announce_table (struct peer *peer, afi_t afi, safi_t safi,
struct bgp_table *table, int rsclient)
@@ -2524,7 +2525,7 @@ bgp_announce_table (struct peer *peer, afi_t afi, safi_t safi,
struct bgp_node *rn;
struct bgp_info *ri;
struct attr attr = { 0 };
-
+
if (! table)
table = (rsclient) ? peer->rib[afi][safi] : peer->bgp->rib[afi][safi];
@@ -2542,7 +2543,7 @@ bgp_announce_table (struct peer *peer, afi_t afi, safi_t safi,
bgp_adj_out_set (rn, peer, &rn->p, &attr, afi, safi, ri);
else
bgp_adj_out_unset (rn, peer, &rn->p, afi, safi);
-
+
bgp_attr_extra_free (&attr);
}
}
@@ -2580,12 +2581,12 @@ bgp_announce_route_all (struct peer *peer)
{
afi_t afi;
safi_t safi;
-
+
for (afi = AFI_IP; afi < AFI_MAX; afi++)
for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
bgp_announce_route (peer, afi, safi);
}
-
+
static void
bgp_soft_reconfig_table_rsclient (struct peer *rsclient, afi_t afi,
safi_t safi, struct bgp_table *table)
@@ -2609,7 +2610,7 @@ bgp_soft_reconfig_rsclient (struct peer *rsclient, afi_t afi, safi_t safi)
{
struct bgp_table *table;
struct bgp_node *rn;
-
+
if (safi != SAFI_MPLS_VPN)
bgp_soft_reconfig_table_rsclient (rsclient, afi, safi, NULL);
@@ -2619,7 +2620,7 @@ bgp_soft_reconfig_rsclient (struct peer *rsclient, afi_t afi, safi_t safi)
if ((table = rn->info) != NULL)
bgp_soft_reconfig_table_rsclient (rsclient, afi, safi, table);
}
-
+
static void
bgp_soft_reconfig_table (struct peer *peer, afi_t afi, safi_t safi,
struct bgp_table *table)
@@ -2666,7 +2667,7 @@ bgp_soft_reconfig_in (struct peer *peer, afi_t afi, safi_t safi)
if ((table = rn->info) != NULL)
bgp_soft_reconfig_table (peer, afi, safi, table);
}
-
+
struct bgp_clear_node_queue
{
@@ -2683,9 +2684,9 @@ bgp_clear_route_node (struct work_queue *wq, void *data)
struct bgp_info *ri;
afi_t afi = rn->table->afi;
safi_t safi = rn->table->safi;
-
+
assert (rn && peer);
-
+
for (ri = rn->info; ri; ri = ri->next)
if (ri->peer == peer || cnq->purpose == BGP_CLEAR_ROUTE_MY_RSCLIENT)
{
@@ -2708,8 +2709,8 @@ bgp_clear_node_queue_del (struct work_queue *wq, void *data)
struct bgp_clear_node_queue *cnq = data;
struct bgp_node *rn = cnq->rn;
struct bgp_table *table = rn->table;
-
- bgp_unlock_node (rn);
+
+ bgp_unlock_node (rn);
bgp_table_unlock (table);
XFREE (MTYPE_BGP_CLEAR_NODE_QUEUE, cnq);
}
@@ -2718,7 +2719,7 @@ static void
bgp_clear_node_complete (struct work_queue *wq)
{
struct peer *peer = wq->spec.data;
-
+
/* Tickle FSM to start moving again */
BGP_EVENT_ADD (peer, Clearing_Completed);
@@ -2729,7 +2730,7 @@ static void
bgp_clear_node_queue_init (struct peer *peer)
{
char wname[sizeof("clear xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx")];
-
+
snprintf (wname, sizeof(wname), "clear %s", peer->host);
#undef CLEAR_QUEUE_NAME_LEN
@@ -2743,7 +2744,7 @@ bgp_clear_node_queue_init (struct peer *peer)
peer->clear_node_queue->spec.del_item_data = &bgp_clear_node_queue_del;
peer->clear_node_queue->spec.completion_func = &bgp_clear_node_complete;
peer->clear_node_queue->spec.max_retries = 0;
-
+
/* we only 'lock' this peer reference when the queue is actually active */
peer->clear_node_queue->spec.data = peer;
}
@@ -2754,21 +2755,21 @@ bgp_clear_route_table (struct peer *peer, afi_t afi, safi_t safi,
enum bgp_clear_route_type purpose)
{
struct bgp_node *rn;
-
-
+
+
if (! table)
table = (rsclient) ? rsclient->rib[afi][safi] : peer->bgp->rib[afi][safi];
-
+
/* If still no table => afi/safi isn't configured at all or smth. */
if (! table)
return;
-
+
for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn))
{
struct bgp_info *ri;
struct bgp_adj_in *ain;
struct bgp_adj_out *aout;
-
+
if (rn->info == NULL)
continue;
@@ -2848,7 +2849,7 @@ bgp_clear_route (struct peer *peer, afi_t afi, safi_t safi,
if (peer->clear_node_queue == NULL)
bgp_clear_node_queue_init (peer);
-
+
/* bgp_fsm.c keeps sessions in state Clearing, not transitioning to
* Idle until it receives a Clearing_Completed event. This protects
* against peers which flap faster than we can we clear, which could
@@ -2889,9 +2890,9 @@ bgp_clear_route (struct peer *peer, afi_t afi, safi_t safi,
assert (0);
break;
}
-
+
/* If no routes were cleared, nothing was added to workqueue, the
- * completion function won't be run by workqueue code - call it here.
+ * completion function won't be run by workqueue code - call it here.
* XXX: Actually, this assumption doesn't hold, see
* bgp_clear_route_table(), we queue all non-empty nodes.
*
@@ -2912,7 +2913,7 @@ bgp_clear_route (struct peer *peer, afi_t afi, safi_t safi,
if (!peer->clear_node_queue->thread)
bgp_clear_node_complete (peer->clear_node_queue);
}
-
+
void
bgp_clear_route_all (struct peer *peer)
{
@@ -2963,7 +2964,7 @@ bgp_clear_stale_route (struct peer *peer, afi_t afi, safi_t safi)
}
}
}
-
+
/* Delete all kernel routes. */
void
bgp_cleanup_routes (void)
@@ -2981,7 +2982,7 @@ bgp_cleanup_routes (void)
for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn))
for (ri = rn->info; ri; ri = ri->next)
if (CHECK_FLAG (ri->flags, BGP_INFO_SELECTED)
- && ri->type == ZEBRA_ROUTE_BGP
+ && ri->type == ZEBRA_ROUTE_BGP
&& ri->sub_type == BGP_ROUTE_NORMAL)
bgp_zebra_withdraw (&rn->p, ri);
@@ -2990,7 +2991,7 @@ bgp_cleanup_routes (void)
for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn))
for (ri = rn->info; ri; ri = ri->next)
if (CHECK_FLAG (ri->flags, BGP_INFO_SELECTED)
- && ri->type == ZEBRA_ROUTE_BGP
+ && ri->type == ZEBRA_ROUTE_BGP
&& ri->sub_type == BGP_ROUTE_NORMAL)
bgp_zebra_withdraw (&rn->p, ri);
}
@@ -3004,7 +3005,7 @@ bgp_reset (void)
access_list_reset ();
prefix_list_reset ();
}
-
+
/* Parse NLRI stream. Withdraw NLRI is recognized by NULL attr
value. */
int
@@ -3019,7 +3020,7 @@ bgp_nlri_parse (struct peer *peer, struct attr *attr, struct bgp_nlri *packet)
/* Check peer status. */
if (peer->status != Established)
return 0;
-
+
pnt = packet->nlri;
lim = pnt + packet->length;
@@ -3031,7 +3032,7 @@ bgp_nlri_parse (struct peer *peer, struct attr *attr, struct bgp_nlri *packet)
/* Fetch prefix length. */
p.prefixlen = *pnt++;
p.family = afi2family (packet->afi);
-
+
/* Already checked in nlri_sanity_check(). We do double check
here. */
if ((packet->afi == AFI_IP && p.prefixlen > 32)
@@ -3053,14 +3054,14 @@ bgp_nlri_parse (struct peer *peer, struct attr *attr, struct bgp_nlri *packet)
{
if (IN_CLASSD (ntohl (p.u.prefix4.s_addr)))
{
- /*
- * From draft-ietf-idr-bgp4-22, Section 6.3:
+ /*
+ * From draft-ietf-idr-bgp4-22, Section 6.3:
* If a BGP router receives an UPDATE message with a
* semantically incorrect NLRI field, in which a prefix is
* semantically incorrect (eg. an unexpected multicast IP
* address), it should ignore the prefix.
*/
- zlog (peer->log, LOG_ERR,
+ zlog (peer->log, LOG_ERR,
"IPv4 unicast NLRI is multicast address %s",
inet_ntoa (p.u.prefix4));
@@ -3076,7 +3077,7 @@ bgp_nlri_parse (struct peer *peer, struct attr *attr, struct bgp_nlri *packet)
{
char buf[BUFSIZ];
- zlog (peer->log, LOG_WARNING,
+ zlog (peer->log, LOG_WARNING,
"IPv6 link-local NLRI received %s ignore this NLRI",
inet_ntop (AF_INET6, &p.u.prefix6, buf, BUFSIZ));
@@ -3087,10 +3088,10 @@ bgp_nlri_parse (struct peer *peer, struct attr *attr, struct bgp_nlri *packet)
/* Normal process. */
if (attr)
- ret = bgp_update (peer, &p, attr, packet->afi, packet->safi,
+ ret = bgp_update (peer, &p, attr, packet->afi, packet->safi,
ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, NULL, NULL, 0);
else
- ret = bgp_withdraw (peer, &p, attr, packet->afi, packet->safi,
+ ret = bgp_withdraw (peer, &p, attr, packet->afi, packet->safi,
ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, NULL, NULL);
/* Address family configuration mismatch or maximum-prefix count
@@ -3124,15 +3125,15 @@ bgp_nlri_sanity_check (struct peer *peer, int afi, u_char *pnt,
while (pnt < end)
{
prefixlen = *pnt++;
-
+
/* Prefix length check. */
if ((afi == AFI_IP && prefixlen > 32)
|| (afi == AFI_IP6 && prefixlen > 128))
{
- plog_err (peer->log,
+ plog_err (peer->log,
"%s [Error] Update packet error (wrong prefix length %d)",
peer->host, prefixlen);
- bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR,
+ bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR,
BGP_NOTIFY_UPDATE_INVAL_NETWORK);
return -1;
}
@@ -3142,11 +3143,11 @@ bgp_nlri_sanity_check (struct peer *peer, int afi, u_char *pnt,
if (pnt + psize > end)
{
- plog_err (peer->log,
+ plog_err (peer->log,
"%s [Error] Update packet error"
" (prefix data overflow prefix size is %d)",
peer->host, psize);
- bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR,
+ bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR,
BGP_NOTIFY_UPDATE_INVAL_NETWORK);
return -1;
}
@@ -3161,13 +3162,13 @@ bgp_nlri_sanity_check (struct peer *peer, int afi, u_char *pnt,
"%s [Error] Update packet error"
" (prefix length mismatch with total length)",
peer->host);
- bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR,
+ bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR,
BGP_NOTIFY_UPDATE_INVAL_NETWORK);
return -1;
}
return 0;
}
-
+
static struct bgp_static *
bgp_static_new (void)
{
@@ -3238,7 +3239,7 @@ bgp_static_update_rsclient (struct peer *rsclient, struct prefix *p,
attr.nexthop = bgp_static->igpnexthop;
attr.med = bgp_static->igpmetric;
attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC);
-
+
if (bgp_static->ttl)
{
attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATHLIMIT);
@@ -3246,17 +3247,17 @@ bgp_static_update_rsclient (struct peer *rsclient, struct prefix *p,
attr.pathlimit.as = 0;
attr.pathlimit.ttl = bgp_static->ttl;
}
-
+
if (bgp_static->atomic)
attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
-
+
/* Apply network route-map for export to this rsclient. */
if (bgp_static->rmap.name)
{
struct attr attr_tmp = attr;
info.peer = rsclient;
info.attr = &attr_tmp;
-
+
SET_FLAG (rsclient->rmap_type, PEER_RMAP_TYPE_EXPORT);
SET_FLAG (rsclient->rmap_type, PEER_RMAP_TYPE_NETWORK);
@@ -3273,19 +3274,19 @@ bgp_static_update_rsclient (struct peer *rsclient, struct prefix *p,
aspath_unintern (attr.aspath);
bgp_static_withdraw_rsclient (bgp, rsclient, p, afi, safi);
bgp_attr_extra_free (&attr);
-
+
return;
}
attr_new = bgp_attr_intern (&attr_tmp);
}
else
attr_new = bgp_attr_intern (&attr);
-
+
new_attr = *attr_new;
-
+
SET_FLAG (bgp->peer_self->rmap_type, PEER_RMAP_TYPE_NETWORK);
- if (bgp_import_modifier (rsclient, bgp->peer_self, p, &new_attr, afi, safi)
+ if (bgp_import_modifier (rsclient, bgp->peer_self, p, &new_attr, afi, safi)
== RMAP_DENY)
{
/* This BGP update is filtered. Log the reason then update BGP entry. */
@@ -3302,7 +3303,7 @@ bgp_static_update_rsclient (struct peer *rsclient, struct prefix *p,
bgp_attr_extra_free (&attr);
bgp_static_withdraw_rsclient (bgp, rsclient, p, afi, safi);
-
+
return;
}
@@ -3347,7 +3348,7 @@ bgp_static_update_rsclient (struct peer *rsclient, struct prefix *p,
return;
}
}
-
+
/* Make new BGP info. */
new = bgp_info_new ();
new->type = ZEBRA_ROUTE_BGP;
@@ -3359,10 +3360,10 @@ bgp_static_update_rsclient (struct peer *rsclient, struct prefix *p,
/* Register new BGP information. */
bgp_info_add (rn, new);
-
+
/* route_node_get lock */
bgp_unlock_node (rn);
-
+
/* Process change. */
bgp_process (bgp, rn, afi, safi);
@@ -3390,7 +3391,7 @@ bgp_static_update_main (struct bgp *bgp, struct prefix *p,
rn = bgp_afi_node_get (bgp->rib[afi][safi], afi, safi, p, NULL);
bgp_attr_default_set (&attr, BGP_ORIGIN_IGP);
-
+
attr.nexthop = bgp_static->igpnexthop;
attr.med = bgp_static->igpmetric;
attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC);
@@ -3420,7 +3421,7 @@ bgp_static_update_main (struct bgp *bgp, struct prefix *p,
bgp->peer_self->rmap_type = 0;
if (ret == RMAP_DENYMATCH)
- {
+ {
/* Free uninterned attribute. */
bgp_attr_flush (&attr_tmp);
@@ -3486,13 +3487,13 @@ bgp_static_update_main (struct bgp *bgp, struct prefix *p,
/* Aggregate address increment. */
bgp_aggregate_increment (bgp, p, new, afi, safi);
-
+
/* Register new BGP information. */
bgp_info_add (rn, new);
-
+
/* route_node_get lock */
bgp_unlock_node (rn);
-
+
/* Process change. */
bgp_process (bgp, rn, afi, safi);
@@ -3523,7 +3524,7 @@ bgp_static_update_vpnv4 (struct bgp *bgp, struct prefix *p, u_int16_t afi,
{
struct bgp_node *rn;
struct bgp_info *new;
-
+
rn = bgp_afi_node_get (bgp->rib[afi][safi], afi, safi, p, prd);
/* Make new BGP info. */
@@ -3539,13 +3540,13 @@ bgp_static_update_vpnv4 (struct bgp *bgp, struct prefix *p, u_int16_t afi,
/* Aggregate address increment. */
bgp_aggregate_increment (bgp, p, new, afi, safi);
-
+
/* Register new BGP information. */
bgp_info_add (rn, new);
/* route_node_get lock */
bgp_unlock_node (rn);
-
+
/* Process change. */
bgp_process (bgp, rn, afi, safi);
}
@@ -3561,7 +3562,7 @@ bgp_static_withdraw (struct bgp *bgp, struct prefix *p, afi_t afi,
/* Check selected route and self inserted route. */
for (ri = rn->info; ri; ri = ri->next)
- if (ri->peer == bgp->peer_self
+ if (ri->peer == bgp->peer_self
&& ri->type == ZEBRA_ROUTE_BGP
&& ri->sub_type == BGP_ROUTE_STATIC)
break;
@@ -3609,7 +3610,7 @@ bgp_static_withdraw_vpnv4 (struct bgp *bgp, struct prefix *p, u_int16_t afi,
/* Check selected route and self inserted route. */
for (ri = rn->info; ri; ri = ri->next)
- if (ri->peer == bgp->peer_self
+ if (ri->peer == bgp->peer_self
&& ri->type == ZEBRA_ROUTE_BGP
&& ri->sub_type == BGP_ROUTE_STATIC)
break;
@@ -3632,14 +3633,14 @@ bgp_pathlimit_update_parents (struct bgp *bgp, struct bgp_node *rn,
{
struct bgp_node *parent = rn;
struct bgp_static *sp;
-
+
/* Existing static changed TTL, search parents and adjust their atomic */
while ((parent = parent->parent))
if ((sp = parent->info))
{
int sp_level = (sp->atomic ? 1 : 0);
ttl_edge ? sp->atomic++ : sp->atomic--;
-
+
/* did we change state of parent whether atomic is set or not? */
if (sp_level != (sp->atomic ? 1 : 0))
{
@@ -3652,7 +3653,7 @@ bgp_pathlimit_update_parents (struct bgp *bgp, struct bgp_node *rn,
/* Configure static BGP network. When user don't run zebra, static
route should be installed as valid. */
static int
-bgp_static_set (struct vty *vty, struct bgp *bgp, const char *ip_str,
+bgp_static_set (struct vty *vty, struct bgp *bgp, const char *ip_str,
u_int16_t afi, u_char safi, const char *rmap, int backdoor,
u_char ttl)
{
@@ -3698,16 +3699,16 @@ bgp_static_set (struct vty *vty, struct bgp *bgp, const char *ip_str,
|| bgp_static->ttl != ttl)
need_update = 1;
}
-
+
/* need to catch TTL set/unset transitions for handling of
- * ATOMIC_AGGREGATE
- */
+ * ATOMIC_AGGREGATE
+ */
if ((bgp_static->ttl ? 1 : 0) != ttl_edge)
ttl_change = 1;
-
+
bgp_static->backdoor = backdoor;
bgp_static->ttl = ttl;
-
+
if (rmap)
{
if (bgp_static->rmap.name)
@@ -3736,7 +3737,7 @@ bgp_static_set (struct vty *vty, struct bgp *bgp, const char *ip_str,
bgp_static->ttl = ttl;
ttl_change = ttl_edge;
new = 1;
-
+
if (rmap)
{
if (bgp_static->rmap.name)
@@ -3765,12 +3766,12 @@ bgp_static_set (struct vty *vty, struct bgp *bgp, const char *ip_str,
/* Existing static changed TTL, search parents and adjust their atomic */
bgp_pathlimit_update_parents (bgp, rn, ttl_edge);
}
-
+
if (new)
{
struct bgp_node *child;
struct bgp_static *sc;
-
+
/* New static, search children and bump this statics atomic.. */
child = bgp_lock_node (rn); /* route_next_until unlocks it.. */
while ((child = bgp_route_next_until (child, rn)))
@@ -3779,7 +3780,7 @@ bgp_static_set (struct vty *vty, struct bgp *bgp, const char *ip_str,
bgp_static->atomic++;
}
}
-
+
/* If BGP scan is not enabled, we should install this route here. */
if (! bgp_flag_check (bgp, BGP_FLAG_IMPORT_CHECK))
{
@@ -3832,10 +3833,10 @@ bgp_static_unset (struct vty *vty, struct bgp *bgp, const char *ip_str,
}
bgp_static = rn->info;
-
+
/* decrement atomic in parents, see bgp_static_set */
bgp_pathlimit_update_parents (bgp, rn, 0);
-
+
/* Update BGP RIB. */
if (! bgp_static->backdoor)
bgp_static_withdraw (bgp, &p, afi, safi);
@@ -3865,7 +3866,7 @@ bgp_static_delete (struct bgp *bgp)
for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
for (rn = bgp_table_top (bgp->route[afi][safi]); rn; rn = bgp_route_next (rn))
if (rn->info != NULL)
- {
+ {
if (safi == SAFI_MPLS_VPN)
{
table = rn->info;
@@ -3962,7 +3963,7 @@ bgp_static_set_vpnv4 (struct vty *vty, const char *ip_str, const char *rd_str,
/* Configure static BGP network. */
int
-bgp_static_unset_vpnv4 (struct vty *vty, const char *ip_str,
+bgp_static_unset_vpnv4 (struct vty *vty, const char *ip_str,
const char *rd_str, const char *tag_str)
{
int ret;
@@ -4025,7 +4026,7 @@ bgp_static_unset_vpnv4 (struct vty *vty, const char *ip_str,
return CMD_SUCCESS;
}
-
+
DEFUN (bgp_network,
bgp_network_cmd,
"network A.B.C.D/M",
@@ -4033,10 +4034,10 @@ DEFUN (bgp_network,
"IP prefix <network>/<length>, e.g., 35.0.0.0/8\n")
{
u_char ttl = 0;
-
+
if (argc == 2)
VTY_GET_INTEGER_RANGE ("Pathlimit TTL", ttl, argv[1], 1, 255);
-
+
return bgp_static_set (vty, vty->index, argv[0],
AFI_IP, bgp_node_safi (vty), NULL, 0, ttl);
}
@@ -4069,10 +4070,10 @@ DEFUN (bgp_network_backdoor,
"Specify a BGP backdoor route\n")
{
u_char ttl = 0;
-
+
if (argc == 2)
VTY_GET_INTEGER_RANGE ("Pathlimit TTL", ttl, argv[1], 1, 255);
-
+
return bgp_static_set (vty, vty->index, argv[0], AFI_IP, SAFI_UNICAST,
NULL, 1, ttl);
}
@@ -4097,10 +4098,10 @@ DEFUN (bgp_network_mask,
int ret;
char prefix_str[BUFSIZ];
u_char ttl = 0;
-
+
if (argc == 3)
VTY_GET_INTEGER_RANGE ("Pathlimit TTL", ttl, argv[2], 1, 255);
-
+
ret = netmask_str2prefix_str (argv[0], argv[1], prefix_str);
if (! ret)
{
@@ -4134,7 +4135,7 @@ DEFUN (bgp_network_mask_route_map,
{
int ret;
char prefix_str[BUFSIZ];
-
+
ret = netmask_str2prefix_str (argv[0], argv[1], prefix_str);
if (! ret)
{
@@ -4158,7 +4159,7 @@ DEFUN (bgp_network_mask_backdoor,
int ret;
char prefix_str[BUFSIZ];
u_char ttl = 0;
-
+
if (argc == 3)
VTY_GET_INTEGER_RANGE ("Pathlimit TTL", ttl, argv[2], 1, 255);
@@ -4193,7 +4194,7 @@ DEFUN (bgp_network_mask_natural,
int ret;
char prefix_str[BUFSIZ];
u_char ttl = 0;
-
+
if (argc == 2)
VTY_GET_INTEGER_RANGE ("Pathlimit TTL", ttl, argv[1], 1, 255);
@@ -4248,7 +4249,7 @@ DEFUN (bgp_network_mask_natural_backdoor,
int ret;
char prefix_str[BUFSIZ];
u_char ttl = 0;
-
+
if (argc == 2)
VTY_GET_INTEGER_RANGE ("Pathlimit TTL", ttl, argv[1], 1, 255);
@@ -4279,7 +4280,7 @@ DEFUN (no_bgp_network,
"Specify a network to announce via BGP\n"
"IP prefix <network>/<length>, e.g., 35.0.0.0/8\n")
{
- return bgp_static_unset (vty, vty->index, argv[0], AFI_IP,
+ return bgp_static_unset (vty, vty->index, argv[0], AFI_IP,
bgp_node_safi (vty));
}
@@ -4338,7 +4339,7 @@ DEFUN (no_bgp_network_mask,
return CMD_WARNING;
}
- return bgp_static_unset (vty, vty->index, prefix_str, AFI_IP,
+ return bgp_static_unset (vty, vty->index, prefix_str, AFI_IP,
bgp_node_safi (vty));
}
@@ -4403,7 +4404,7 @@ DEFUN (no_bgp_network_mask_natural,
return CMD_WARNING;
}
- return bgp_static_unset (vty, vty->index, prefix_str, AFI_IP,
+ return bgp_static_unset (vty, vty->index, prefix_str, AFI_IP,
bgp_node_safi (vty));
}
@@ -4451,7 +4452,7 @@ DEFUN (ipv6_bgp_network,
"IPv6 prefix <network>/<length>\n")
{
u_char ttl = 0;
-
+
if (argc == 2)
VTY_GET_INTEGER_RANGE ("Pathlimit TTL", ttl, argv[1], 1, 255);
@@ -4524,7 +4525,7 @@ ALIAS (no_ipv6_bgp_network,
"Specify a network to announce via BGP\n"
"IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n")
#endif /* HAVE_IPV6 */
-
+
/* Aggreagete address:
advertise-map Set condition to advertise attribute
@@ -4563,11 +4564,11 @@ static void
bgp_aggregate_free (struct bgp_aggregate *aggregate)
{
XFREE (MTYPE_BGP_AGGREGATE, aggregate);
-}
+}
static void
bgp_aggregate_route (struct bgp *bgp, struct prefix *p, struct bgp_info *rinew,
- afi_t afi, safi_t safi, struct bgp_info *del,
+ afi_t afi, safi_t safi, struct bgp_info *del,
struct bgp_aggregate *aggregate)
{
struct bgp_table *table;
@@ -4687,7 +4688,7 @@ bgp_aggregate_route (struct bgp *bgp, struct prefix *p, struct bgp_info *rinew,
if (rinew)
{
aggregate->count++;
-
+
if (aggregate->summary_only)
(bgp_info_extra_get (rinew))->suppress++;
@@ -4778,7 +4779,7 @@ bgp_aggregate_increment (struct bgp *bgp, struct prefix *p,
}
void
-bgp_aggregate_decrement (struct bgp *bgp, struct prefix *p,
+bgp_aggregate_decrement (struct bgp *bgp, struct prefix *p,
struct bgp_info *del, afi_t afi, safi_t safi)
{
struct bgp_node *child;
@@ -4827,7 +4828,7 @@ bgp_aggregate_add (struct bgp *bgp, struct prefix *p, afi_t afi, safi_t safi,
return;
if (afi == AFI_IP6 && p->prefixlen == IPV6_MAX_BITLEN)
return;
-
+
/* If routes exists below this node, generate aggregate routes. */
top = bgp_node_get (table, p);
for (rn = bgp_node_get (table, p); rn; rn = bgp_route_next_until (rn, top))
@@ -4882,7 +4883,7 @@ bgp_aggregate_add (struct bgp *bgp, struct prefix *p, afi_t afi, safi_t safi,
aggregate->count++;
}
}
-
+
/* If this node is suppressed, process the change. */
if (match)
bgp_process (bgp, rn, afi, safi);
@@ -4904,14 +4905,14 @@ bgp_aggregate_add (struct bgp *bgp, struct prefix *p, afi_t afi, safi_t safi,
bgp_info_add (rn, new);
bgp_unlock_node (rn);
-
+
/* Process change. */
bgp_process (bgp, rn, afi, safi);
}
}
void
-bgp_aggregate_delete (struct bgp *bgp, struct prefix *p, afi_t afi,
+bgp_aggregate_delete (struct bgp *bgp, struct prefix *p, afi_t afi,
safi_t safi, struct bgp_aggregate *aggregate)
{
struct bgp_table *table;
@@ -4965,7 +4966,7 @@ bgp_aggregate_delete (struct bgp *bgp, struct prefix *p, afi_t afi,
rn = bgp_node_get (table, p);
for (ri = rn->info; ri; ri = ri->next)
- if (ri->peer == bgp->peer_self
+ if (ri->peer == bgp->peer_self
&& ri->type == ZEBRA_ROUTE_BGP
&& ri->sub_type == BGP_ROUTE_AGGREGATE)
break;
@@ -4986,7 +4987,7 @@ bgp_aggregate_delete (struct bgp *bgp, struct prefix *p, afi_t afi,
#define AGGREGATE_AS_SET 1
static int
-bgp_aggregate_set (struct vty *vty, const char *prefix_str,
+bgp_aggregate_set (struct vty *vty, const char *prefix_str,
afi_t afi, safi_t safi,
u_char summary_only, u_char as_set)
{
@@ -5035,7 +5036,7 @@ bgp_aggregate_set (struct vty *vty, const char *prefix_str,
}
static int
-bgp_aggregate_unset (struct vty *vty, const char *prefix_str,
+bgp_aggregate_unset (struct vty *vty, const char *prefix_str,
afi_t afi, safi_t safi)
{
int ret;
@@ -5354,7 +5355,7 @@ DEFUN (ipv6_aggregate_address_summary_only,
"Aggregate prefix\n"
"Filter more specific routes from updates\n")
{
- return bgp_aggregate_set (vty, argv[0], AFI_IP6, SAFI_UNICAST,
+ return bgp_aggregate_set (vty, argv[0], AFI_IP6, SAFI_UNICAST,
AGGREGATE_SUMMARY_ONLY, 0);
}
@@ -5415,7 +5416,7 @@ ALIAS (no_ipv6_aggregate_address_summary_only,
"Aggregate prefix\n"
"Filter more specific routes from updates\n")
#endif /* HAVE_IPV6 */
-
+
/* Redistribute route treatment. */
void
bgp_redistribute_add (struct prefix *p, struct in_addr *nexthop,
@@ -5471,7 +5472,7 @@ bgp_redistribute_add (struct prefix *p, struct in_addr *nexthop,
/* Free uninterned attribute. */
bgp_attr_flush (&attr_new);
bgp_attr_extra_free (&attr_new);
-
+
/* Unintern original. */
aspath_unintern (attr.aspath);
bgp_attr_extra_free (&attr);
@@ -5480,17 +5481,17 @@ bgp_redistribute_add (struct prefix *p, struct in_addr *nexthop,
}
}
- bn = bgp_afi_node_get (bgp->rib[afi][SAFI_UNICAST],
+ bn = bgp_afi_node_get (bgp->rib[afi][SAFI_UNICAST],
afi, SAFI_UNICAST, p, NULL);
-
+
new_attr = bgp_attr_intern (&attr_new);
bgp_attr_extra_free (&attr_new);
-
+
for (bi = bn->info; bi; bi = bi->next)
if (bi->peer == bgp->peer_self
&& bi->sub_type == BGP_ROUTE_REDISTRIBUTE)
break;
-
+
if (bi)
{
if (attrhash_cmp (bi->attr, new_attr) &&
@@ -5506,7 +5507,7 @@ bgp_redistribute_add (struct prefix *p, struct in_addr *nexthop,
{
/* The attribute is changed. */
bgp_info_set_flag (bn, bi, BGP_INFO_ATTR_CHANGED);
-
+
/* Rewrite BGP route information. */
if (CHECK_FLAG(bi->flags, BGP_INFO_REMOVED))
bgp_info_restore(bn, bi);
@@ -5515,7 +5516,7 @@ bgp_redistribute_add (struct prefix *p, struct in_addr *nexthop,
bgp_attr_unintern (bi->attr);
bi->attr = new_attr;
bi->uptime = time (NULL);
-
+
/* Process change. */
bgp_aggregate_increment (bgp, p, bi, afi, SAFI_UNICAST);
bgp_process (bgp, bn, afi, SAFI_UNICAST);
@@ -5523,7 +5524,7 @@ bgp_redistribute_add (struct prefix *p, struct in_addr *nexthop,
aspath_unintern (attr.aspath);
bgp_attr_extra_free (&attr);
return;
- }
+ }
}
new = bgp_info_new ();
@@ -5604,13 +5605,13 @@ bgp_redistribute_withdraw (struct bgp *bgp, afi_t afi, int type)
}
}
}
-
+
/* Static function to display route. */
static void
route_vty_out_route (struct prefix *p, struct vty *vty)
{
int len;
- u_int32_t destination;
+ u_int32_t destination;
char buf[BUFSIZ];
if (p->family == AF_INET)
@@ -5674,7 +5675,7 @@ route_vty_short_status_out (struct vty *vty, struct bgp_info *binfo)
if ((binfo->peer->as) && (binfo->peer->as == binfo->peer->local_as))
vty_out (vty, "i");
else
- vty_out (vty, " ");
+ vty_out (vty, " ");
}
/* called from terminal list command */
@@ -5683,10 +5684,10 @@ route_vty_out (struct vty *vty, struct prefix *p,
struct bgp_info *binfo, int display, safi_t safi)
{
struct attr *attr;
-
- /* short status lead text */
+
+ /* short status lead text */
route_vty_short_status_out (vty, binfo);
-
+
/* print prefix and mask */
if (! display)
route_vty_out_route (p, vty);
@@ -5695,7 +5696,7 @@ route_vty_out (struct vty *vty, struct prefix *p,
/* Print attribute */
attr = binfo->attr;
- if (attr)
+ if (attr)
{
if (p->family == AF_INET)
{
@@ -5705,13 +5706,13 @@ route_vty_out (struct vty *vty, struct prefix *p,
else
vty_out (vty, "%-16s", inet_ntoa (attr->nexthop));
}
-#ifdef HAVE_IPV6
+#ifdef HAVE_IPV6
else if (p->family == AF_INET6)
{
int len;
char buf[BUFSIZ];
- len = vty_out (vty, "%s",
+ len = vty_out (vty, "%s",
inet_ntop (AF_INET6, &attr->extra->mp_nexthop_global,
buf, BUFSIZ));
len = 16 - len;
@@ -5733,7 +5734,7 @@ route_vty_out (struct vty *vty, struct prefix *p,
vty_out (vty, " ");
vty_out (vty, "%7u ", (attr->extra ? attr->extra->weight : 0));
-
+
/* Print aspath */
if (attr->aspath)
aspath_print_vty (vty, "%s", attr->aspath, " ");
@@ -5742,7 +5743,7 @@ route_vty_out (struct vty *vty, struct prefix *p,
vty_out (vty, "%s", bgp_origin_str[attr->origin]);
}
vty_out (vty, "%s", VTY_NEWLINE);
-}
+}
/* called from terminal list command */
void
@@ -5758,7 +5759,7 @@ route_vty_out_tmp (struct vty *vty, struct prefix *p,
route_vty_out_route (p, vty);
/* Print attribute */
- if (attr)
+ if (attr)
{
if (p->family == AF_INET)
{
@@ -5773,7 +5774,7 @@ route_vty_out_tmp (struct vty *vty, struct prefix *p,
{
int len;
char buf[BUFSIZ];
-
+
assert (attr->extra);
len = vty_out (vty, "%s",
@@ -5796,9 +5797,9 @@ route_vty_out_tmp (struct vty *vty, struct prefix *p,
vty_out (vty, "%7d", attr->local_pref);
else
vty_out (vty, " ");
-
+
vty_out (vty, "%7d ", (attr->extra ? attr->extra->weight : 0));
-
+
/* Print aspath */
if (attr->aspath)
aspath_print_vty (vty, "%s", attr->aspath, " ");
@@ -5808,7 +5809,7 @@ route_vty_out_tmp (struct vty *vty, struct prefix *p,
}
vty_out (vty, "%s", VTY_NEWLINE);
-}
+}
void
route_vty_out_tag (struct vty *vty, struct prefix *p,
@@ -5816,13 +5817,13 @@ route_vty_out_tag (struct vty *vty, struct prefix *p,
{
struct attr *attr;
u_int32_t label = 0;
-
+
if (!binfo->extra)
return;
-
- /* short status lead text */
+
+ /* short status lead text */
route_vty_short_status_out (vty, binfo);
-
+
/* print prefix and mask */
if (! display)
route_vty_out_route (p, vty);
@@ -5831,7 +5832,7 @@ route_vty_out_tag (struct vty *vty, struct prefix *p,
/* Print attribute */
attr = binfo->attr;
- if (attr)
+ if (attr)
{
if (p->family == AF_INET)
{
@@ -5841,14 +5842,14 @@ route_vty_out_tag (struct vty *vty, struct prefix *p,
else
vty_out (vty, "%-16s", inet_ntoa (attr->nexthop));
}
-#ifdef HAVE_IPV6
+#ifdef HAVE_IPV6
else if (p->family == AF_INET6)
{
assert (attr->extra);
char buf[BUFSIZ];
char buf1[BUFSIZ];
if (attr->extra->mp_nexthop_len == 16)
- vty_out (vty, "%s",
+ vty_out (vty, "%s",
inet_ntop (AF_INET6, &attr->extra->mp_nexthop_global,
buf, BUFSIZ));
else if (attr->extra->mp_nexthop_len == 32)
@@ -5857,7 +5858,7 @@ route_vty_out_tag (struct vty *vty, struct prefix *p,
buf, BUFSIZ),
inet_ntop (AF_INET6, &attr->extra->mp_nexthop_local,
buf1, BUFSIZ));
-
+
}
#endif /* HAVE_IPV6 */
}
@@ -5867,7 +5868,7 @@ route_vty_out_tag (struct vty *vty, struct prefix *p,
vty_out (vty, "notag/%d", label);
vty_out (vty, "%s", VTY_NEWLINE);
-}
+}
/* dampening route */
static void
@@ -5878,9 +5879,9 @@ damp_route_vty_out (struct vty *vty, struct prefix *p,
int len;
char timebuf[BGP_UPTIME_LEN];
- /* short status lead text */
+ /* short status lead text */
route_vty_short_status_out (vty, binfo);
-
+
/* print prefix and mask */
if (! display)
route_vty_out_route (p, vty);
@@ -5919,15 +5920,15 @@ flap_route_vty_out (struct vty *vty, struct prefix *p,
struct bgp_damp_info *bdi;
char timebuf[BGP_UPTIME_LEN];
int len;
-
+
if (!binfo->extra)
return;
-
+
bdi = binfo->extra->damp_info;
/* short status lead text */
route_vty_short_status_out (vty, binfo);
-
+
/* print prefix and mask */
if (! display)
route_vty_out_route (p, vty);
@@ -5947,7 +5948,7 @@ flap_route_vty_out (struct vty *vty, struct prefix *p,
vty_out (vty, " ");
else
vty_out (vty, "%*s ", len, " ");
-
+
vty_out (vty, "%s ", peer_uptime (bdi->start_time,
timebuf, BGP_UPTIME_LEN));
@@ -5972,14 +5973,14 @@ flap_route_vty_out (struct vty *vty, struct prefix *p,
}
static void
-route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p,
+route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p,
struct bgp_info *binfo, afi_t afi, safi_t safi)
{
char buf[INET6_ADDRSTRLEN];
char buf1[BUFSIZ];
struct attr *attr;
int sockunion_vty_out (struct vty *, union sockunion *);
-
+
attr = binfo->attr;
if (attr)
@@ -5999,7 +6000,7 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p,
if (CHECK_FLAG (binfo->flags, BGP_INFO_STALE))
vty_out (vty, ", (stale)");
if (CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR)))
- vty_out (vty, ", (aggregated by %u %s)",
+ vty_out (vty, ", (aggregated by %u %s)",
attr->extra->aggregator_as,
inet_ntoa (attr->extra->aggregator_addr));
if (CHECK_FLAG (binfo->peer->af_flags[afi][safi], PEER_FLAG_REFLECTOR_CLIENT))
@@ -6011,7 +6012,7 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p,
else if (CHECK_FLAG (binfo->flags, BGP_INFO_DAMPED))
vty_out (vty, ", (suppressed due to dampening)");
vty_out (vty, "%s", VTY_NEWLINE);
-
+
/* Line2 display Next-hop, Neighbor, Router-id */
if (p->family == AF_INET)
{
@@ -6031,14 +6032,14 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p,
if (binfo->peer == bgp->peer_self)
{
- vty_out (vty, " from %s ",
+ vty_out (vty, " from %s ",
p->family == AF_INET ? "0.0.0.0" : "::");
vty_out (vty, "(%s)", inet_ntoa(bgp->router_id));
}
else
{
if (! CHECK_FLAG (binfo->flags, BGP_INFO_VALID))
- vty_out (vty, " (inaccessible)");
+ vty_out (vty, " (inaccessible)");
else if (binfo->extra && binfo->extra->igpmetric)
vty_out (vty, " (metric %d)", binfo->extra->igpmetric);
vty_out (vty, " from %s", sockunion2str (&binfo->peer->su, buf, SU_ADDRSTRLEN));
@@ -6062,10 +6063,10 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p,
/* Line 3 display Origin, Med, Locpref, Weight, valid, Int/Ext/Local, Atomic, best */
vty_out (vty, " Origin %s", bgp_origin_long_str[attr->origin]);
-
+
if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC))
vty_out (vty, ", metric %d", attr->med);
-
+
if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF))
vty_out (vty, ", localpref %d", attr->local_pref);
else
@@ -6073,7 +6074,7 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p,
if (attr->extra && attr->extra->weight != 0)
vty_out (vty, ", weight %d", attr->extra->weight);
-
+
if (! CHECK_FLAG (binfo->flags, BGP_INFO_HISTORY))
vty_out (vty, ", valid");
@@ -6081,8 +6082,8 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p,
{
if (binfo->peer->as == binfo->peer->local_as)
vty_out (vty, ", internal");
- else
- vty_out (vty, ", %s",
+ else
+ vty_out (vty, ", %s",
(bgp_confederation_peers_check(bgp, binfo->peer->as) ? "confed-external" : "external"));
}
else if (binfo->sub_type == BGP_ROUTE_AGGREGATE)
@@ -6094,29 +6095,29 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p,
if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE))
vty_out (vty, ", atomic-aggregate");
-
+
if (CHECK_FLAG (binfo->flags, BGP_INFO_SELECTED))
vty_out (vty, ", best");
vty_out (vty, "%s", VTY_NEWLINE);
-
+
/* Line 4 display Community */
if (attr->community)
vty_out (vty, " Community: %s%s", attr->community->str,
VTY_NEWLINE);
-
+
/* Line 5 display Extended-community */
if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES))
- vty_out (vty, " Extended Community: %s%s",
+ vty_out (vty, " Extended Community: %s%s",
attr->extra->ecommunity->str, VTY_NEWLINE);
-
+
/* Line 6 display Originator, Cluster-id */
if ((attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID)) ||
(attr->flag & ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST)))
{
assert (attr->extra);
if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
- vty_out (vty, " Originator: %s",
+ vty_out (vty, " Originator: %s",
inet_ntoa (attr->extra->originator_id));
if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST))
@@ -6124,23 +6125,23 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p,
int i;
vty_out (vty, ", Cluster list: ");
for (i = 0; i < attr->extra->cluster->length / 4; i++)
- vty_out (vty, "%s ",
+ vty_out (vty, "%s ",
inet_ntoa (attr->extra->cluster->list[i]));
}
vty_out (vty, "%s", VTY_NEWLINE);
}
-
+
/* 7: AS Pathlimit */
if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_AS_PATHLIMIT))
{
-
+
vty_out (vty, " AS-Pathlimit: %u",
attr->pathlimit.ttl);
if (attr->pathlimit.as)
vty_out (vty, " (%u)", attr->pathlimit.as);
vty_out (vty, "%s", VTY_NEWLINE);
}
-
+
if (binfo->extra && binfo->extra->damp_info)
bgp_damp_info_vty (vty, binfo);
@@ -6148,8 +6149,8 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p,
vty_out (vty, " Last update: %s", ctime (&binfo->uptime));
}
vty_out (vty, "%s", VTY_NEWLINE);
-}
-
+}
+
#define BGP_SHOW_SCODE_HEADER "Status codes: s suppressed, d damped, h history, * valid, > best, i - internal,%s r RIB-failure, S Stale, R Removed%s"
#define BGP_SHOW_OCODE_HEADER "Origin codes: i - IGP, e - EGP, ? - incomplete%s%s"
#define BGP_SHOW_HEADER " Network Next Hop Metric LocPrf Weight Path%s"
@@ -6199,7 +6200,7 @@ bgp_show_table (struct vty *vty, struct bgp_table *table, struct in_addr *router
output_count = 0;
/* Start processing of routes. */
- for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn))
+ for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn))
if (rn->info != NULL)
{
display = 0;
@@ -6226,7 +6227,7 @@ bgp_show_table (struct vty *vty, struct bgp_table *table, struct in_addr *router
|| type == bgp_show_type_flap_regexp)
{
regex_t *regex = output_arg;
-
+
if (bgp_regexec (regex, ri->attr->aspath) == REG_NOMATCH)
continue;
}
@@ -6234,7 +6235,7 @@ bgp_show_table (struct vty *vty, struct bgp_table *table, struct in_addr *router
|| type == bgp_show_type_flap_prefix_list)
{
struct prefix_list *plist = output_arg;
-
+
if (prefix_list_apply (plist, &rn->p) != PREFIX_PERMIT)
continue;
}
@@ -6251,7 +6252,7 @@ bgp_show_table (struct vty *vty, struct bgp_table *table, struct in_addr *router
{
struct route_map *rmap = output_arg;
struct bgp_info binfo;
- struct attr dummy_attr = { 0 };
+ struct attr dummy_attr = { 0 };
int ret;
bgp_attr_dup (&dummy_attr, ri->attr);
@@ -6259,9 +6260,9 @@ bgp_show_table (struct vty *vty, struct bgp_table *table, struct in_addr *router
binfo.attr = &dummy_attr;
ret = route_map_apply (rmap, &rn->p, RMAP_BGP, &binfo);
-
+
bgp_attr_extra_free (&dummy_attr);
-
+
if (ret == RMAP_DENYMATCH)
continue;
}
@@ -6516,7 +6517,7 @@ route_vty_out_detail_header (struct vty *vty, struct bgp *bgp,
/* Display specified route of BGP table. */
static int
-bgp_show_route_in_table (struct vty *vty, struct bgp *bgp,
+bgp_show_route_in_table (struct vty *vty, struct bgp *bgp,
struct bgp_table *rib, const char *ip_str,
afi_t afi, safi_t safi, struct prefix_rd *prd,
int prefix_check)
@@ -6630,8 +6631,8 @@ bgp_show_route (struct vty *vty, const char *view_name, const char *ip_str,
return CMD_WARNING;
}
}
-
- return bgp_show_route_in_table (vty, bgp, bgp->rib[afi][safi], ip_str,
+
+ return bgp_show_route_in_table (vty, bgp, bgp->rib[afi][safi], ip_str,
afi, safi, prd, prefix_check);
}
@@ -6659,7 +6660,7 @@ DEFUN (show_ip_bgp_ipv4,
if (strncmp (argv[0], "m", 1) == 0)
return bgp_show (vty, NULL, AFI_IP, SAFI_MULTICAST, bgp_show_type_normal,
NULL);
-
+
return bgp_show (vty, NULL, AFI_IP, SAFI_UNICAST, bgp_show_type_normal, NULL);
}
@@ -6946,7 +6947,7 @@ DEFUN (show_bgp_view,
vty_out (vty, "Can't find BGP view %s%s", argv[0], VTY_NEWLINE);
return CMD_WARNING;
}
-
+
return bgp_show (vty, bgp, AFI_IP6, SAFI_UNICAST, bgp_show_type_normal, NULL);
}
@@ -6954,11 +6955,11 @@ ALIAS (show_bgp_view,
show_bgp_view_ipv6_cmd,
"show bgp view WORD ipv6",
SHOW_STR
- BGP_STR
+ BGP_STR
"BGP view\n"
"View name\n"
"Address family\n")
-
+
DEFUN (show_bgp_view_route,
show_bgp_view_route_cmd,
"show bgp view WORD X:X::X:X",
@@ -6987,10 +6988,10 @@ DEFUN (show_bgp_view_prefix,
SHOW_STR
BGP_STR
"BGP view\n"
- "View name\n"
+ "View name\n"
"IPv6 prefix <network>/<length>\n")
{
- return bgp_show_route (vty, argv[0], argv[1], AFI_IP6, SAFI_UNICAST, NULL, 1);
+ return bgp_show_route (vty, argv[0], argv[1], AFI_IP6, SAFI_UNICAST, NULL, 1);
}
ALIAS (show_bgp_view_prefix,
@@ -7001,7 +7002,7 @@ ALIAS (show_bgp_view_prefix,
"BGP view\n"
"View name\n"
"Address family\n"
- "IPv6 prefix <network>/<length>\n")
+ "IPv6 prefix <network>/<length>\n")
/* old command */
DEFUN (show_ipv6_mbgp,
@@ -7039,7 +7040,7 @@ DEFUN (show_ipv6_mbgp_prefix,
return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_MULTICAST, NULL, 1);
}
#endif
-
+
static int
bgp_show_regexp (struct vty *vty, int argc, const char **argv, afi_t afi,
@@ -7051,7 +7052,7 @@ bgp_show_regexp (struct vty *vty, int argc, const char **argv, afi_t afi,
int first;
regex_t *regex;
int rc;
-
+
first = 0;
b = buffer_new (1024);
for (i = 0; i < argc; i++)
@@ -7086,7 +7087,7 @@ bgp_show_regexp (struct vty *vty, int argc, const char **argv, afi_t afi,
return rc;
}
-DEFUN (show_ip_bgp_regexp,
+DEFUN (show_ip_bgp_regexp,
show_ip_bgp_regexp_cmd,
"show ip bgp regexp .LINE",
SHOW_STR
@@ -7099,7 +7100,7 @@ DEFUN (show_ip_bgp_regexp,
bgp_show_type_regexp);
}
-DEFUN (show_ip_bgp_flap_regexp,
+DEFUN (show_ip_bgp_flap_regexp,
show_ip_bgp_flap_regexp_cmd,
"show ip bgp flap-statistics regexp .LINE",
SHOW_STR
@@ -7113,7 +7114,7 @@ DEFUN (show_ip_bgp_flap_regexp,
bgp_show_type_flap_regexp);
}
-DEFUN (show_ip_bgp_ipv4_regexp,
+DEFUN (show_ip_bgp_ipv4_regexp,
show_ip_bgp_ipv4_regexp_cmd,
"show ip bgp ipv4 (unicast|multicast) regexp .LINE",
SHOW_STR
@@ -7134,7 +7135,7 @@ DEFUN (show_ip_bgp_ipv4_regexp,
}
#ifdef HAVE_IPV6
-DEFUN (show_bgp_regexp,
+DEFUN (show_bgp_regexp,
show_bgp_regexp_cmd,
"show bgp regexp .LINE",
SHOW_STR
@@ -7146,7 +7147,7 @@ DEFUN (show_bgp_regexp,
bgp_show_type_regexp);
}
-ALIAS (show_bgp_regexp,
+ALIAS (show_bgp_regexp,
show_bgp_ipv6_regexp_cmd,
"show bgp ipv6 regexp .LINE",
SHOW_STR
@@ -7156,7 +7157,7 @@ ALIAS (show_bgp_regexp,
"A regular-expression to match the BGP AS paths\n")
/* old command */
-DEFUN (show_ipv6_bgp_regexp,
+DEFUN (show_ipv6_bgp_regexp,
show_ipv6_bgp_regexp_cmd,
"show ipv6 bgp regexp .LINE",
SHOW_STR
@@ -7170,7 +7171,7 @@ DEFUN (show_ipv6_bgp_regexp,
}
/* old command */
-DEFUN (show_ipv6_mbgp_regexp,
+DEFUN (show_ipv6_mbgp_regexp,
show_ipv6_mbgp_regexp_cmd,
"show ipv6 mbgp regexp .LINE",
SHOW_STR
@@ -7183,7 +7184,7 @@ DEFUN (show_ipv6_mbgp_regexp,
bgp_show_type_regexp);
}
#endif /* HAVE_IPV6 */
-
+
static int
bgp_show_prefix_list (struct vty *vty, const char *prefix_list_str, afi_t afi,
safi_t safi, enum bgp_show_type type)
@@ -7194,14 +7195,14 @@ bgp_show_prefix_list (struct vty *vty, const char *prefix_list_str, afi_t afi,
if (plist == NULL)
{
vty_out (vty, "%% %s is not a valid prefix-list name%s",
- prefix_list_str, VTY_NEWLINE);
+ prefix_list_str, VTY_NEWLINE);
return CMD_WARNING;
}
return bgp_show (vty, NULL, afi, safi, type, plist);
}
-DEFUN (show_ip_bgp_prefix_list,
+DEFUN (show_ip_bgp_prefix_list,
show_ip_bgp_prefix_list_cmd,
"show ip bgp prefix-list WORD",
SHOW_STR
@@ -7214,7 +7215,7 @@ DEFUN (show_ip_bgp_prefix_list,
bgp_show_type_prefix_list);
}
-DEFUN (show_ip_bgp_flap_prefix_list,
+DEFUN (show_ip_bgp_flap_prefix_list,
show_ip_bgp_flap_prefix_list_cmd,
"show ip bgp flap-statistics prefix-list WORD",
SHOW_STR
@@ -7228,7 +7229,7 @@ DEFUN (show_ip_bgp_flap_prefix_list,
bgp_show_type_flap_prefix_list);
}
-DEFUN (show_ip_bgp_ipv4_prefix_list,
+DEFUN (show_ip_bgp_ipv4_prefix_list,
show_ip_bgp_ipv4_prefix_list_cmd,
"show ip bgp ipv4 (unicast|multicast) prefix-list WORD",
SHOW_STR
@@ -7249,7 +7250,7 @@ DEFUN (show_ip_bgp_ipv4_prefix_list,
}
#ifdef HAVE_IPV6
-DEFUN (show_bgp_prefix_list,
+DEFUN (show_bgp_prefix_list,
show_bgp_prefix_list_cmd,
"show bgp prefix-list WORD",
SHOW_STR
@@ -7261,7 +7262,7 @@ DEFUN (show_bgp_prefix_list,
bgp_show_type_prefix_list);
}
-ALIAS (show_bgp_prefix_list,
+ALIAS (show_bgp_prefix_list,
show_bgp_ipv6_prefix_list_cmd,
"show bgp ipv6 prefix-list WORD",
SHOW_STR
@@ -7271,7 +7272,7 @@ ALIAS (show_bgp_prefix_list,
"IPv6 prefix-list name\n")
/* old command */
-DEFUN (show_ipv6_bgp_prefix_list,
+DEFUN (show_ipv6_bgp_prefix_list,
show_ipv6_bgp_prefix_list_cmd,
"show ipv6 bgp prefix-list WORD",
SHOW_STR
@@ -7285,7 +7286,7 @@ DEFUN (show_ipv6_bgp_prefix_list,
}
/* old command */
-DEFUN (show_ipv6_mbgp_prefix_list,
+DEFUN (show_ipv6_mbgp_prefix_list,
show_ipv6_mbgp_prefix_list_cmd,
"show ipv6 mbgp prefix-list WORD",
SHOW_STR
@@ -7298,7 +7299,7 @@ DEFUN (show_ipv6_mbgp_prefix_list,
bgp_show_type_prefix_list);
}
#endif /* HAVE_IPV6 */
-
+
static int
bgp_show_filter_list (struct vty *vty, const char *filter, afi_t afi,
safi_t safi, enum bgp_show_type type)
@@ -7308,14 +7309,14 @@ bgp_show_filter_list (struct vty *vty, const char *filter, afi_t afi,
as_list = as_list_lookup (filter);
if (as_list == NULL)
{
- vty_out (vty, "%% %s is not a valid AS-path access-list name%s", filter, VTY_NEWLINE);
+ vty_out (vty, "%% %s is not a valid AS-path access-list name%s", filter, VTY_NEWLINE);
return CMD_WARNING;
}
return bgp_show (vty, NULL, afi, safi, type, as_list);
}
-DEFUN (show_ip_bgp_filter_list,
+DEFUN (show_ip_bgp_filter_list,
show_ip_bgp_filter_list_cmd,
"show ip bgp filter-list WORD",
SHOW_STR
@@ -7328,7 +7329,7 @@ DEFUN (show_ip_bgp_filter_list,
bgp_show_type_filter_list);
}
-DEFUN (show_ip_bgp_flap_filter_list,
+DEFUN (show_ip_bgp_flap_filter_list,
show_ip_bgp_flap_filter_list_cmd,
"show ip bgp flap-statistics filter-list WORD",
SHOW_STR
@@ -7342,7 +7343,7 @@ DEFUN (show_ip_bgp_flap_filter_list,
bgp_show_type_flap_filter_list);
}
-DEFUN (show_ip_bgp_ipv4_filter_list,
+DEFUN (show_ip_bgp_ipv4_filter_list,
show_ip_bgp_ipv4_filter_list_cmd,
"show ip bgp ipv4 (unicast|multicast) filter-list WORD",
SHOW_STR
@@ -7357,13 +7358,13 @@ DEFUN (show_ip_bgp_ipv4_filter_list,
if (strncmp (argv[0], "m", 1) == 0)
return bgp_show_filter_list (vty, argv[1], AFI_IP, SAFI_MULTICAST,
bgp_show_type_filter_list);
-
+
return bgp_show_filter_list (vty, argv[1], AFI_IP, SAFI_UNICAST,
bgp_show_type_filter_list);
}
#ifdef HAVE_IPV6
-DEFUN (show_bgp_filter_list,
+DEFUN (show_bgp_filter_list,
show_bgp_filter_list_cmd,
"show bgp filter-list WORD",
SHOW_STR
@@ -7375,7 +7376,7 @@ DEFUN (show_bgp_filter_list,
bgp_show_type_filter_list);
}
-ALIAS (show_bgp_filter_list,
+ALIAS (show_bgp_filter_list,
show_bgp_ipv6_filter_list_cmd,
"show bgp ipv6 filter-list WORD",
SHOW_STR
@@ -7385,7 +7386,7 @@ ALIAS (show_bgp_filter_list,
"Regular expression access list name\n")
/* old command */
-DEFUN (show_ipv6_bgp_filter_list,
+DEFUN (show_ipv6_bgp_filter_list,
show_ipv6_bgp_filter_list_cmd,
"show ipv6 bgp filter-list WORD",
SHOW_STR
@@ -7399,7 +7400,7 @@ DEFUN (show_ipv6_bgp_filter_list,
}
/* old command */
-DEFUN (show_ipv6_mbgp_filter_list,
+DEFUN (show_ipv6_mbgp_filter_list,
show_ipv6_mbgp_filter_list_cmd,
"show ipv6 mbgp filter-list WORD",
SHOW_STR
@@ -7412,7 +7413,7 @@ DEFUN (show_ipv6_mbgp_filter_list,
bgp_show_type_filter_list);
}
#endif /* HAVE_IPV6 */
-
+
static int
bgp_show_route_map (struct vty *vty, const char *rmap_str, afi_t afi,
safi_t safi, enum bgp_show_type type)
@@ -7423,14 +7424,14 @@ bgp_show_route_map (struct vty *vty, const char *rmap_str, afi_t afi,
if (! rmap)
{
vty_out (vty, "%% %s is not a valid route-map name%s",
- rmap_str, VTY_NEWLINE);
+ rmap_str, VTY_NEWLINE);
return CMD_WARNING;
}
return bgp_show (vty, NULL, afi, safi, type, rmap);
}
-DEFUN (show_ip_bgp_route_map,
+DEFUN (show_ip_bgp_route_map,
show_ip_bgp_route_map_cmd,
"show ip bgp route-map WORD",
SHOW_STR
@@ -7443,7 +7444,7 @@ DEFUN (show_ip_bgp_route_map,
bgp_show_type_route_map);
}
-DEFUN (show_ip_bgp_flap_route_map,
+DEFUN (show_ip_bgp_flap_route_map,
show_ip_bgp_flap_route_map_cmd,
"show ip bgp flap-statistics route-map WORD",
SHOW_STR
@@ -7457,7 +7458,7 @@ DEFUN (show_ip_bgp_flap_route_map,
bgp_show_type_flap_route_map);
}
-DEFUN (show_ip_bgp_ipv4_route_map,
+DEFUN (show_ip_bgp_ipv4_route_map,
show_ip_bgp_ipv4_route_map_cmd,
"show ip bgp ipv4 (unicast|multicast) route-map WORD",
SHOW_STR
@@ -7477,7 +7478,7 @@ DEFUN (show_ip_bgp_ipv4_route_map,
bgp_show_type_route_map);
}
-DEFUN (show_bgp_route_map,
+DEFUN (show_bgp_route_map,
show_bgp_route_map_cmd,
"show bgp route-map WORD",
SHOW_STR
@@ -7489,7 +7490,7 @@ DEFUN (show_bgp_route_map,
bgp_show_type_route_map);
}
-ALIAS (show_bgp_route_map,
+ALIAS (show_bgp_route_map,
show_bgp_ipv6_route_map_cmd,
"show bgp ipv6 route-map WORD",
SHOW_STR
@@ -7497,7 +7498,7 @@ ALIAS (show_bgp_route_map,
"Address family\n"
"Display routes matching the route-map\n"
"A route-map to match on\n")
-
+
DEFUN (show_ip_bgp_cidr_only,
show_ip_bgp_cidr_only_cmd,
"show ip bgp cidr-only",
@@ -7541,7 +7542,7 @@ DEFUN (show_ip_bgp_ipv4_cidr_only,
return bgp_show (vty, NULL, AFI_IP, SAFI_UNICAST,
bgp_show_type_cidr_only, NULL);
}
-
+
DEFUN (show_ip_bgp_community_all,
show_ip_bgp_community_all_cmd,
"show ip bgp community",
@@ -7568,7 +7569,7 @@ DEFUN (show_ip_bgp_ipv4_community_all,
if (strncmp (argv[0], "m", 1) == 0)
return bgp_show (vty, NULL, AFI_IP, SAFI_MULTICAST,
bgp_show_type_community_all, NULL);
-
+
return bgp_show (vty, NULL, AFI_IP, SAFI_UNICAST,
bgp_show_type_community_all, NULL);
}
@@ -7619,7 +7620,7 @@ DEFUN (show_ipv6_mbgp_community_all,
bgp_show_type_community_all, NULL);
}
#endif /* HAVE_IPV6 */
-
+
static int
bgp_show_community (struct vty *vty, int argc, const char **argv, int exact,
u_int16_t afi, u_char safi)
@@ -7641,7 +7642,7 @@ bgp_show_community (struct vty *vty, int argc, const char **argv, int exact,
continue;
first = 1;
}
-
+
buffer_putstr (b, argv[i]);
}
buffer_putc (b, '\0');
@@ -7692,7 +7693,7 @@ ALIAS (show_ip_bgp_community,
"Do not send outside local AS (well-known community)\n"
"Do not advertise to any peer (well-known community)\n"
"Do not export to next AS (well-known community)\n")
-
+
ALIAS (show_ip_bgp_community,
show_ip_bgp_community3_cmd,
"show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)",
@@ -7712,7 +7713,7 @@ ALIAS (show_ip_bgp_community,
"Do not send outside local AS (well-known community)\n"
"Do not advertise to any peer (well-known community)\n"
"Do not export to next AS (well-known community)\n")
-
+
ALIAS (show_ip_bgp_community,
show_ip_bgp_community4_cmd,
"show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)",
@@ -7754,7 +7755,7 @@ DEFUN (show_ip_bgp_ipv4_community,
{
if (strncmp (argv[0], "m", 1) == 0)
return bgp_show_community (vty, argc, argv, 0, AFI_IP, SAFI_MULTICAST);
-
+
return bgp_show_community (vty, argc, argv, 0, AFI_IP, SAFI_UNICAST);
}
@@ -7776,7 +7777,7 @@ ALIAS (show_ip_bgp_ipv4_community,
"Do not send outside local AS (well-known community)\n"
"Do not advertise to any peer (well-known community)\n"
"Do not export to next AS (well-known community)\n")
-
+
ALIAS (show_ip_bgp_ipv4_community,
show_ip_bgp_ipv4_community3_cmd,
"show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)",
@@ -7799,7 +7800,7 @@ ALIAS (show_ip_bgp_ipv4_community,
"Do not send outside local AS (well-known community)\n"
"Do not advertise to any peer (well-known community)\n"
"Do not export to next AS (well-known community)\n")
-
+
ALIAS (show_ip_bgp_ipv4_community,
show_ip_bgp_ipv4_community4_cmd,
"show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)",
@@ -7924,7 +7925,7 @@ DEFUN (show_ip_bgp_ipv4_community_exact,
{
if (strncmp (argv[0], "m", 1) == 0)
return bgp_show_community (vty, argc, argv, 1, AFI_IP, SAFI_MULTICAST);
-
+
return bgp_show_community (vty, argc, argv, 1, AFI_IP, SAFI_UNICAST);
}
@@ -7971,7 +7972,7 @@ ALIAS (show_ip_bgp_ipv4_community_exact,
"Do not advertise to any peer (well-known community)\n"
"Do not export to next AS (well-known community)\n"
"Exact match of the communities")
-
+
ALIAS (show_ip_bgp_ipv4_community_exact,
show_ip_bgp_ipv4_community4_exact_cmd,
"show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match",
@@ -8057,7 +8058,7 @@ ALIAS (show_bgp_community,
"Do not send outside local AS (well-known community)\n"
"Do not advertise to any peer (well-known community)\n"
"Do not export to next AS (well-known community)\n")
-
+
ALIAS (show_bgp_community,
show_bgp_community3_cmd,
"show bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)",
@@ -8348,7 +8349,7 @@ ALIAS (show_bgp_community_exact,
"Do not advertise to any peer (well-known community)\n"
"Do not export to next AS (well-known community)\n"
"Exact match of the communities")
-
+
ALIAS (show_bgp_community_exact,
show_bgp_ipv6_community4_exact_cmd,
"show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match",
@@ -8456,7 +8457,7 @@ ALIAS (show_ipv6_bgp_community_exact,
"Do not advertise to any peer (well-known community)\n"
"Do not export to next AS (well-known community)\n"
"Exact match of the communities")
-
+
/* old command */
DEFUN (show_ipv6_mbgp_community,
show_ipv6_mbgp_community_cmd,
@@ -8619,7 +8620,7 @@ ALIAS (show_ipv6_mbgp_community_exact,
"Do not export to next AS (well-known community)\n"
"Exact match of the communities")
#endif /* HAVE_IPV6 */
-
+
static int
bgp_show_community_list (struct vty *vty, const char *com, int exact,
u_int16_t afi, u_char safi)
@@ -8667,7 +8668,7 @@ DEFUN (show_ip_bgp_ipv4_community_list,
{
if (strncmp (argv[0], "m", 1) == 0)
return bgp_show_community_list (vty, argv[1], 0, AFI_IP, SAFI_MULTICAST);
-
+
return bgp_show_community_list (vty, argv[1], 0, AFI_IP, SAFI_UNICAST);
}
@@ -8701,7 +8702,7 @@ DEFUN (show_ip_bgp_ipv4_community_list_exact,
{
if (strncmp (argv[0], "m", 1) == 0)
return bgp_show_community_list (vty, argv[1], 1, AFI_IP, SAFI_MULTICAST);
-
+
return bgp_show_community_list (vty, argv[1], 1, AFI_IP, SAFI_UNICAST);
}
@@ -8806,7 +8807,7 @@ DEFUN (show_ipv6_mbgp_community_list_exact,
return bgp_show_community_list (vty, argv[0], 1, AFI_IP6, SAFI_MULTICAST);
}
#endif /* HAVE_IPV6 */
-
+
static int
bgp_show_prefix_longer (struct vty *vty, const char *prefix, afi_t afi,
safi_t safi, enum bgp_show_type type)
@@ -8952,7 +8953,7 @@ DEFUN (show_ipv6_mbgp_prefix_longer,
#endif /* HAVE_IPV6 */
static struct peer *
-peer_lookup_in_view (struct vty *vty, const char *view_name,
+peer_lookup_in_view (struct vty *vty, const char *view_name,
const char *ip_str)
{
int ret;
@@ -8968,7 +8969,7 @@ peer_lookup_in_view (struct vty *vty, const char *view_name,
{
vty_out (vty, "Can't find BGP view %s%s", view_name, VTY_NEWLINE);
return NULL;
- }
+ }
}
else
{
@@ -8980,7 +8981,7 @@ peer_lookup_in_view (struct vty *vty, const char *view_name,
}
}
- /* Get peer sockunion. */
+ /* Get peer sockunion. */
ret = str2sockunion (ip_str, &su);
if (ret < 0)
{
@@ -8995,10 +8996,10 @@ peer_lookup_in_view (struct vty *vty, const char *view_name,
vty_out (vty, "No such neighbor%s", VTY_NEWLINE);
return NULL;
}
-
+
return peer;
}
-
+
enum bgp_stats
{
BGP_STATS_MAXBITLEN = 0,
@@ -9050,7 +9051,7 @@ ravg_tally (unsigned long count, unsigned long oldavg, unsigned long newval)
unsigned long newtot = (count-1) * oldavg + (newval * TALLY_SIGFIG);
unsigned long res = (newtot * TALLY_SIGFIG) / count;
unsigned long ret = newtot / count;
-
+
if ((res % TALLY_SIGFIG) > (TALLY_SIGFIG/2))
return ret + 1;
else
@@ -9065,7 +9066,7 @@ bgp_table_stats_walker (struct thread *t)
struct bgp_node *top;
struct bgp_table_stats *ts = THREAD_ARG (t);
unsigned int space = 0;
-
+
if (!(top = bgp_table_top (ts->table)))
return 0;
@@ -9078,7 +9079,7 @@ bgp_table_stats_walker (struct thread *t)
space = IPV6_MAX_BITLEN;
break;
}
-
+
ts->counts[BGP_STATS_MAXBITLEN] = space;
for (rn = top; rn; rn = bgp_route_next (rn))
@@ -9086,13 +9087,13 @@ bgp_table_stats_walker (struct thread *t)
struct bgp_info *ri;
struct bgp_node *prn = rn->parent;
unsigned int rinum = 0;
-
+
if (rn == top)
continue;
-
+
if (!rn->info)
continue;
-
+
ts->counts[BGP_STATS_PREFIXES]++;
ts->counts[BGP_STATS_TOTPLEN] += rn->p.prefixlen;
@@ -9102,11 +9103,11 @@ bgp_table_stats_walker (struct thread *t)
ts->counts[BGP_STATS_AVGPLEN],
rn->p.prefixlen);
#endif
-
+
/* check if the prefix is included by any other announcements */
while (prn && !prn->info)
prn = prn->parent;
-
+
if (prn == NULL || prn == top)
{
ts->counts[BGP_STATS_UNAGGREGATEABLE]++;
@@ -9116,36 +9117,36 @@ bgp_table_stats_walker (struct thread *t)
}
else if (prn->info)
ts->counts[BGP_STATS_MAX_AGGREGATEABLE]++;
-
+
for (ri = rn->info; ri; ri = ri->next)
{
rinum++;
ts->counts[BGP_STATS_RIB]++;
-
+
if (ri->attr &&
(CHECK_FLAG (ri->attr->flag,
ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))))
ts->counts[BGP_STATS_AGGREGATES]++;
-
+
/* as-path stats */
if (ri->attr && ri->attr->aspath)
{
unsigned int hops = aspath_count_hops (ri->attr->aspath);
unsigned int size = aspath_size (ri->attr->aspath);
as_t highest = aspath_highest (ri->attr->aspath);
-
+
ts->counts[BGP_STATS_ASPATH_COUNT]++;
-
+
if (hops > ts->counts[BGP_STATS_ASPATH_MAXHOPS])
ts->counts[BGP_STATS_ASPATH_MAXHOPS] = hops;
-
+
if (size > ts->counts[BGP_STATS_ASPATH_MAXSIZE])
ts->counts[BGP_STATS_ASPATH_MAXSIZE] = size;
-
+
ts->counts[BGP_STATS_ASPATH_TOTHOPS] += hops;
ts->counts[BGP_STATS_ASPATH_TOTSIZE] += size;
#if 0
- ts->counts[BGP_STATS_ASPATH_AVGHOPS]
+ ts->counts[BGP_STATS_ASPATH_AVGHOPS]
= ravg_tally (ts->counts[BGP_STATS_ASPATH_COUNT],
ts->counts[BGP_STATS_ASPATH_AVGHOPS],
hops);
@@ -9167,25 +9168,25 @@ bgp_table_stats (struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi)
{
struct bgp_table_stats ts;
unsigned int i;
-
+
if (!bgp->rib[afi][safi])
{
vty_out (vty, "%% No RIB exist for the AFI/SAFI%s", VTY_NEWLINE);
return CMD_WARNING;
}
-
+
memset (&ts, 0, sizeof (ts));
ts.table = bgp->rib[afi][safi];
thread_execute (bm->master, bgp_table_stats_walker, &ts, 0);
vty_out (vty, "BGP %s RIB statistics%s%s",
afi_safi_print (afi, safi), VTY_NEWLINE, VTY_NEWLINE);
-
+
for (i = 0; i < BGP_STATS_MAX; i++)
{
if (!table_stats_strs[i])
continue;
-
+
switch (i)
{
#if 0
@@ -9202,7 +9203,7 @@ bgp_table_stats (struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi)
vty_out (vty, "%-30s: ", table_stats_strs[i]);
vty_out (vty, "%12.2f",
ts.counts[i] ?
- (float)ts.counts[i] /
+ (float)ts.counts[i] /
(float)ts.counts[BGP_STATS_ASPATH_COUNT]
: 0);
break;
@@ -9210,7 +9211,7 @@ bgp_table_stats (struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi)
vty_out (vty, "%-30s: ", table_stats_strs[i]);
vty_out (vty, "%12.2f",
ts.counts[i] ?
- (float)ts.counts[i] /
+ (float)ts.counts[i] /
(float)ts.counts[BGP_STATS_PREFIXES]
: 0);
break;
@@ -9220,27 +9221,27 @@ bgp_table_stats (struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi)
if (ts.counts[BGP_STATS_MAXBITLEN] < 9)
break;
vty_out (vty, "%30s: ", "%% announced ");
- vty_out (vty, "%12.2f%s",
- 100 * (float)ts.counts[BGP_STATS_SPACE] /
+ vty_out (vty, "%12.2f%s",
+ 100 * (float)ts.counts[BGP_STATS_SPACE] /
(float)((uint64_t)1UL << ts.counts[BGP_STATS_MAXBITLEN]),
VTY_NEWLINE);
vty_out (vty, "%30s: ", "/8 equivalent ");
- vty_out (vty, "%12.2f%s",
- (float)ts.counts[BGP_STATS_SPACE] /
+ vty_out (vty, "%12.2f%s",
+ (float)ts.counts[BGP_STATS_SPACE] /
(float)(1UL << (ts.counts[BGP_STATS_MAXBITLEN] - 8)),
VTY_NEWLINE);
if (ts.counts[BGP_STATS_MAXBITLEN] < 25)
break;
vty_out (vty, "%30s: ", "/24 equivalent ");
- vty_out (vty, "%12.2f",
- (float)ts.counts[BGP_STATS_SPACE] /
+ vty_out (vty, "%12.2f",
+ (float)ts.counts[BGP_STATS_SPACE] /
(float)(1UL << (ts.counts[BGP_STATS_MAXBITLEN] - 24)));
break;
default:
vty_out (vty, "%-30s: ", table_stats_strs[i]);
vty_out (vty, "%12llu", ts.counts[i]);
}
-
+
vty_out (vty, "%s", VTY_NEWLINE);
}
return CMD_SUCCESS;
@@ -9253,7 +9254,7 @@ bgp_table_stats_vty (struct vty *vty, const char *name,
struct bgp *bgp;
afi_t afi;
safi_t safi;
-
+
if (name)
bgp = bgp_lookup_by_name (name);
else
@@ -9355,7 +9356,7 @@ ALIAS (show_bgp_statistics_view,
"Address family\n"
"Address Family modifier\n"
"BGP RIB advertisement statistics\n")
-
+
enum bgp_pcounts
{
PCOUNT_ADJ_IN = 0,
@@ -9397,12 +9398,12 @@ bgp_peer_count_walker (struct thread *t)
struct bgp_node *rn;
struct peer_pcounts *pc = THREAD_ARG (t);
const struct peer *peer = pc->peer;
-
+
for (rn = bgp_table_top (pc->table); rn; rn = bgp_route_next (rn))
{
struct bgp_adj_in *ain;
struct bgp_info *ri;
-
+
for (ain = rn->adj_in; ain; ain = ain->next)
if (ain->peer == peer)
pc->count[PCOUNT_ADJ_IN]++;
@@ -9410,12 +9411,12 @@ bgp_peer_count_walker (struct thread *t)
for (ri = rn->info; ri; ri = ri->next)
{
char buf[SU_ADDRSTRLEN];
-
+
if (ri->peer != peer)
continue;
-
+
pc->count[PCOUNT_ALL]++;
-
+
if (CHECK_FLAG (ri->flags, BGP_INFO_DAMPED))
pc->count[PCOUNT_DAMPED]++;
if (CHECK_FLAG (ri->flags, BGP_INFO_HISTORY))
@@ -9428,7 +9429,7 @@ bgp_peer_count_walker (struct thread *t)
pc->count[PCOUNT_VALID]++;
if (!CHECK_FLAG (ri->flags, BGP_INFO_UNUSEABLE))
pc->count[PCOUNT_PFCNT]++;
-
+
if (CHECK_FLAG (ri->flags, BGP_INFO_COUNTED))
{
pc->count[PCOUNT_COUNTED]++;
@@ -9462,28 +9463,28 @@ bgp_peer_counts (struct vty *vty, struct peer *peer, afi_t afi, safi_t safi)
{
struct peer_pcounts pcounts = { .peer = peer };
unsigned int i;
-
+
if (!peer || !peer->bgp || !peer->afc[afi][safi]
|| !peer->bgp->rib[afi][safi])
{
vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE);
return CMD_WARNING;
}
-
+
memset (&pcounts, 0, sizeof(pcounts));
pcounts.peer = peer;
pcounts.table = peer->bgp->rib[afi][safi];
-
+
/* in-place call via thread subsystem so as to record execution time
* stats for the thread-walk (i.e. ensure this can't be blamed on
* on just vty_read()).
*/
thread_execute (bm->master, bgp_peer_count_walker, &pcounts, 0);
-
- vty_out (vty, "Prefix counts for %s, %s%s",
+
+ vty_out (vty, "Prefix counts for %s, %s%s",
peer->host, afi_safi_print (afi, safi), VTY_NEWLINE);
vty_out (vty, "PfxCt: %ld%s", peer->pcount[afi][safi], VTY_NEWLINE);
- vty_out (vty, "%sCounts from RIB table walk:%s%s",
+ vty_out (vty, "%sCounts from RIB table walk:%s%s",
VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
for (i = 0; i < PCOUNT_MAX; i++)
@@ -9497,7 +9498,7 @@ bgp_peer_counts (struct vty *vty, struct peer *peer, afi_t afi, safi_t safi)
vty_out (vty, "Please report this bug, with the above command output%s",
VTY_NEWLINE);
}
-
+
return CMD_SUCCESS;
}
@@ -9514,10 +9515,10 @@ DEFUN (show_ip_bgp_neighbor_prefix_counts,
{
struct peer *peer;
- peer = peer_lookup_in_view (vty, NULL, argv[0]);
- if (! peer)
+ peer = peer_lookup_in_view (vty, NULL, argv[0]);
+ if (! peer)
return CMD_WARNING;
-
+
return bgp_peer_counts (vty, peer, AFI_IP, SAFI_UNICAST);
}
@@ -9534,10 +9535,10 @@ DEFUN (show_bgp_ipv6_neighbor_prefix_counts,
{
struct peer *peer;
- peer = peer_lookup_in_view (vty, NULL, argv[0]);
- if (! peer)
+ peer = peer_lookup_in_view (vty, NULL, argv[0]);
+ if (! peer)
return CMD_WARNING;
-
+
return bgp_peer_counts (vty, peer, AFI_IP6, SAFI_UNICAST);
}
@@ -9586,7 +9587,7 @@ DEFUN (show_ip_bgp_vpnv4_neighbor_prefix_counts,
peer = peer_lookup_in_view (vty, NULL, argv[0]);
if (! peer)
return CMD_WARNING;
-
+
return bgp_peer_counts (vty, peer, AFI_IP, SAFI_MPLS_VPN);
}
@@ -9612,7 +9613,7 @@ show_adj_route (struct vty *vty, struct peer *peer, afi_t afi, safi_t safi,
table = bgp->rib[afi][safi];
output_count = 0;
-
+
if (! in && CHECK_FLAG (peer->af_sflags[afi][safi],
PEER_STATUS_DEFAULT_ORIGINATE))
{
@@ -9644,7 +9645,7 @@ show_adj_route (struct vty *vty, struct peer *peer, afi_t afi, safi_t safi,
header2 = 0;
}
if (ain->attr)
- {
+ {
route_vty_out_tmp (vty, &rn->p, ain->attr, safi);
output_count++;
}
@@ -9668,13 +9669,13 @@ show_adj_route (struct vty *vty, struct peer *peer, afi_t afi, safi_t safi,
header2 = 0;
}
if (adj->attr)
- {
+ {
route_vty_out_tmp (vty, &rn->p, adj->attr, safi);
output_count++;
}
}
}
-
+
if (output_count != 0)
vty_out (vty, "%sTotal number of prefixes %ld%s",
VTY_NEWLINE, output_count, VTY_NEWLINE);
@@ -9682,7 +9683,7 @@ show_adj_route (struct vty *vty, struct peer *peer, afi_t afi, safi_t safi,
static int
peer_adj_routes (struct vty *vty, struct peer *peer, afi_t afi, safi_t safi, int in)
-{
+{
if (! peer || ! peer->afc[afi][safi])
{
vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE);
@@ -9721,9 +9722,9 @@ DEFUN (show_ip_bgp_view_neighbor_advertised_route,
else
peer = peer_lookup_in_view (vty, NULL, argv[0]);
- if (! peer)
+ if (! peer)
return CMD_WARNING;
-
+
return peer_adj_routes (vty, peer, AFI_IP, SAFI_UNICAST, 0);
}
@@ -9785,7 +9786,7 @@ DEFUN (show_bgp_view_neighbor_advertised_route,
peer = peer_lookup_in_view (vty, NULL, argv[0]);
if (! peer)
- return CMD_WARNING;
+ return CMD_WARNING;
return peer_adj_routes (vty, peer, AFI_IP6, SAFI_UNICAST, 0);
}
@@ -9850,7 +9851,7 @@ ALIAS (show_bgp_view_neighbor_advertised_route,
"Neighbor to display information about\n"
"Neighbor to display information about\n"
"Display the routes advertised to a BGP neighbor\n")
-
+
ALIAS (show_bgp_view_neighbor_advertised_route,
show_bgp_ipv6_neighbor_advertised_route_cmd,
"show bgp ipv6 neighbors (A.B.C.D|X:X::X:X) advertised-routes",
@@ -9873,7 +9874,7 @@ ALIAS (show_bgp_view_neighbor_advertised_route,
"Neighbor to display information about\n"
"Neighbor to display information about\n"
"Display the routes advertised to a BGP neighbor\n")
-
+
/* old command */
DEFUN (ipv6_mbgp_neighbor_advertised_route,
ipv6_mbgp_neighbor_advertised_route_cmd,
@@ -9890,12 +9891,12 @@ DEFUN (ipv6_mbgp_neighbor_advertised_route,
peer = peer_lookup_in_view (vty, NULL, argv[0]);
if (! peer)
- return CMD_WARNING;
+ return CMD_WARNING;
return peer_adj_routes (vty, peer, AFI_IP6, SAFI_MULTICAST, 0);
}
#endif /* HAVE_IPV6 */
-
+
DEFUN (show_ip_bgp_view_neighbor_received_routes,
show_ip_bgp_view_neighbor_received_routes_cmd,
"show ip bgp view WORD neighbors (A.B.C.D|X:X::X:X) received-routes",
@@ -9952,7 +9953,7 @@ DEFUN (show_ip_bgp_ipv4_neighbor_received_routes,
peer = peer_lookup_in_view (vty, NULL, argv[1]);
if (! peer)
return CMD_WARNING;
-
+
if (strncmp (argv[0], "m", 1) == 0)
return peer_adj_routes (vty, peer, AFI_IP, SAFI_MULTICAST, 1);
@@ -10033,7 +10034,7 @@ DEFUN (show_ip_bgp_ipv4_neighbor_received_prefix_filter,
prefix_bgp_show_prefix_list (vty, AFI_IP, name);
}
}
- else
+ else
{
sprintf (name, "%s.%d.%d", peer->host, AFI_IP, SAFI_UNICAST);
count = prefix_bgp_show_prefix_list (NULL, AFI_IP, name);
@@ -10172,11 +10173,11 @@ DEFUN (show_bgp_view_neighbor_received_prefix_filter,
/* BGP structure lookup. */
bgp = bgp_lookup_by_name (argv[0]);
if (bgp == NULL)
- {
+ {
vty_out (vty, "Can't find BGP view %s%s", argv[0], VTY_NEWLINE);
return CMD_WARNING;
}
-
+
su = sockunion_str2su (argv[1]);
if (su == NULL)
return CMD_WARNING;
@@ -10210,7 +10211,7 @@ ALIAS (show_bgp_view_neighbor_received_prefix_filter,
"Display information received from a BGP neighbor\n"
"Display the prefixlist filter\n")
#endif /* HAVE_IPV6 */
-
+
static int
bgp_show_neighbor_route (struct vty *vty, struct peer *peer, afi_t afi,
safi_t safi, enum bgp_show_type type)
@@ -10220,7 +10221,7 @@ bgp_show_neighbor_route (struct vty *vty, struct peer *peer, afi_t afi,
vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE);
return CMD_WARNING;
}
-
+
return bgp_show (vty, peer->bgp, afi, safi, type, &peer->su);
}
@@ -10240,7 +10241,7 @@ DEFUN (show_ip_bgp_neighbor_routes,
peer = peer_lookup_in_view (vty, NULL, argv[0]);
if (! peer)
return CMD_WARNING;
-
+
return bgp_show_neighbor_route (vty, peer, AFI_IP, SAFI_UNICAST,
bgp_show_type_neighbor);
}
@@ -10261,7 +10262,7 @@ DEFUN (show_ip_bgp_neighbor_flap,
peer = peer_lookup_in_view (vty, NULL, argv[0]);
if (! peer)
return CMD_WARNING;
-
+
return bgp_show_neighbor_route (vty, peer, AFI_IP, SAFI_UNICAST,
bgp_show_type_flap_neighbor);
}
@@ -10282,7 +10283,7 @@ DEFUN (show_ip_bgp_neighbor_damp,
peer = peer_lookup_in_view (vty, NULL, argv[0]);
if (! peer)
return CMD_WARNING;
-
+
return bgp_show_neighbor_route (vty, peer, AFI_IP, SAFI_UNICAST,
bgp_show_type_damp_neighbor);
}
@@ -10306,7 +10307,7 @@ DEFUN (show_ip_bgp_ipv4_neighbor_routes,
peer = peer_lookup_in_view (vty, NULL, argv[1]);
if (! peer)
return CMD_WARNING;
-
+
if (strncmp (argv[0], "m", 1) == 0)
return bgp_show_neighbor_route (vty, peer, AFI_IP, SAFI_MULTICAST,
bgp_show_type_neighbor);
@@ -10423,8 +10424,8 @@ DEFUN (show_ip_bgp_view_rsclient_route,
VTY_NEWLINE);
return CMD_WARNING;
}
-
- return bgp_show_route_in_table (vty, bgp, peer->rib[AFI_IP][SAFI_UNICAST],
+
+ return bgp_show_route_in_table (vty, bgp, peer->rib[AFI_IP][SAFI_UNICAST],
(argc == 3) ? argv[2] : argv[1],
AFI_IP, SAFI_UNICAST, NULL, 0);
}
@@ -10481,7 +10482,7 @@ DEFUN (show_ip_bgp_view_rsclient_prefix,
if (! peer)
return CMD_WARNING;
-
+
if (! peer->afc[AFI_IP][SAFI_UNICAST])
{
vty_out (vty, "%% Activate the neighbor for the address family first%s",
@@ -10496,8 +10497,8 @@ DEFUN (show_ip_bgp_view_rsclient_prefix,
VTY_NEWLINE);
return CMD_WARNING;
}
-
- return bgp_show_route_in_table (vty, bgp, peer->rib[AFI_IP][SAFI_UNICAST],
+
+ return bgp_show_route_in_table (vty, bgp, peer->rib[AFI_IP][SAFI_UNICAST],
(argc == 3) ? argv[2] : argv[1],
AFI_IP, SAFI_UNICAST, NULL, 1);
}
@@ -10532,7 +10533,7 @@ DEFUN (show_bgp_view_neighbor_routes,
peer = peer_lookup_in_view (vty, argv[0], argv[1]);
else
peer = peer_lookup_in_view (vty, NULL, argv[0]);
-
+
if (! peer)
return CMD_WARNING;
@@ -10630,7 +10631,7 @@ ALIAS (show_bgp_view_neighbor_flap,
"Neighbor to display information about\n"
"Neighbor to display information about\n"
"Display flap statistics of the routes learned from neighbor\n")
-
+
ALIAS (show_bgp_view_neighbor_routes,
show_bgp_neighbor_routes_cmd,
"show bgp neighbors (A.B.C.D|X:X::X:X) routes",
@@ -10682,7 +10683,7 @@ DEFUN (ipv6_mbgp_neighbor_routes,
peer = peer_lookup_in_view (vty, NULL, argv[0]);
if (! peer)
return CMD_WARNING;
-
+
return bgp_show_neighbor_route (vty, peer, AFI_IP6, SAFI_MULTICAST,
bgp_show_type_neighbor);
}
@@ -10921,7 +10922,7 @@ ALIAS (show_bgp_view_rsclient_prefix,
"IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n")
#endif /* HAVE_IPV6 */
-
+
struct bgp_table *bgp_distance_table;
struct bgp_distance
@@ -10946,7 +10947,7 @@ bgp_distance_free (struct bgp_distance *bdistance)
}
static int
-bgp_distance_set (struct vty *vty, const char *distance_str,
+bgp_distance_set (struct vty *vty, const char *distance_str,
const char *ip_str, const char *access_list_str)
{
int ret;
@@ -10993,7 +10994,7 @@ bgp_distance_set (struct vty *vty, const char *distance_str,
}
static int
-bgp_distance_unset (struct vty *vty, const char *distance_str,
+bgp_distance_unset (struct vty *vty, const char *distance_str,
const char *ip_str, const char *access_list_str)
{
int ret;
@@ -11215,7 +11216,7 @@ DEFUN (no_bgp_distance_source_access_list,
bgp_distance_unset (vty, argv[0], argv[1], argv[2]);
return CMD_SUCCESS;
}
-
+
DEFUN (bgp_damp_set,
bgp_damp_set_cmd,
"bgp dampening <1-45> <1-20000> <1-20000> <1-255>",
@@ -11310,11 +11311,11 @@ DEFUN (show_ip_bgp_flap_statistics,
return bgp_show (vty, NULL, AFI_IP, SAFI_UNICAST,
bgp_show_type_flap_statistics, NULL);
}
-
+
/* Display specified route of BGP table. */
static int
-bgp_clear_damp_route (struct vty *vty, const char *view_name,
- const char *ip_str, afi_t afi, safi_t safi,
+bgp_clear_damp_route (struct vty *vty, const char *view_name,
+ const char *ip_str, afi_t afi, safi_t safi,
struct prefix_rd *prd, int prefix_check)
{
int ret;
@@ -11466,7 +11467,7 @@ DEFUN (clear_ip_bgp_dampening_address_mask,
return bgp_clear_damp_route (vty, NULL, prefix_str, AFI_IP,
SAFI_UNICAST, NULL, 0);
}
-
+
static int
bgp_config_write_network_vpnv4 (struct vty *vty, struct bgp *bgp,
afi_t afi, safi_t safi, int *write)
@@ -11480,11 +11481,11 @@ bgp_config_write_network_vpnv4 (struct vty *vty, struct bgp *bgp,
u_int32_t label;
char buf[SU_ADDRSTRLEN];
char rdbuf[RD_ADDRSTRLEN];
-
+
/* Network configuration. */
for (prn = bgp_table_top (bgp->route[afi][safi]); prn; prn = bgp_route_next (prn))
if ((table = prn->info) != NULL)
- for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn))
+ for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn))
if ((bgp_static = rn->info) != NULL)
{
p = &rn->p;
@@ -11498,7 +11499,7 @@ bgp_config_write_network_vpnv4 (struct vty *vty, struct bgp *bgp,
label = decode_label (bgp_static->tag);
vty_out (vty, " network %s/%d rd %s tag %d",
- inet_ntop (p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
+ inet_ntop (p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
p->prefixlen,
rdbuf, label);
vty_out (vty, "%s", VTY_NEWLINE);
@@ -11517,12 +11518,12 @@ bgp_config_write_network (struct vty *vty, struct bgp *bgp,
struct bgp_static *bgp_static;
struct bgp_aggregate *bgp_aggregate;
char buf[SU_ADDRSTRLEN];
-
+
if (afi == AFI_IP && safi == SAFI_MPLS_VPN)
return bgp_config_write_network_vpnv4 (vty, bgp, afi, safi, write);
/* Network configuration. */
- for (rn = bgp_table_top (bgp->route[afi][safi]); rn; rn = bgp_route_next (rn))
+ for (rn = bgp_table_top (bgp->route[afi][safi]); rn; rn = bgp_route_next (rn))
if ((bgp_static = rn->info) != NULL)
{
p = &rn->p;
@@ -11533,7 +11534,7 @@ bgp_config_write_network (struct vty *vty, struct bgp *bgp,
/* "network" configuration display. */
if (bgp_option_check (BGP_OPT_CONFIG_CISCO) && afi == AFI_IP)
{
- u_int32_t destination;
+ u_int32_t destination;
struct in_addr netmask;
destination = ntohl (p->u.prefix4.s_addr);
@@ -11554,13 +11555,13 @@ bgp_config_write_network (struct vty *vty, struct bgp *bgp,
else
{
vty_out (vty, " network %s/%d",
- inet_ntop (p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
+ inet_ntop (p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
p->prefixlen);
}
if (bgp_static->rmap.name)
vty_out (vty, " route-map %s", bgp_static->rmap.name);
- else
+ else
{
if (bgp_static->backdoor)
vty_out (vty, " backdoor");
@@ -11598,7 +11599,7 @@ bgp_config_write_network (struct vty *vty, struct bgp *bgp,
if (bgp_aggregate->as_set)
vty_out (vty, " as-set");
-
+
if (bgp_aggregate->summary_only)
vty_out (vty, " summary-only");
@@ -11624,7 +11625,7 @@ bgp_config_write_distance (struct vty *vty, struct bgp *bgp)
vty_out (vty, " distance bgp %d %d %d%s",
bgp->distance_ebgp, bgp->distance_ibgp, bgp->distance_local,
VTY_NEWLINE);
-
+
for (rn = bgp_table_top (bgp_distance_table); rn; rn = bgp_route_next (rn))
if ((bdistance = rn->info) != NULL)
{
@@ -11863,7 +11864,7 @@ bgp_route_init (void)
install_element (VIEW_NODE, &show_ip_bgp_view_rsclient_cmd);
install_element (VIEW_NODE, &show_ip_bgp_view_rsclient_route_cmd);
install_element (VIEW_NODE, &show_ip_bgp_view_rsclient_prefix_cmd);
-
+
/* Restricted node: VIEW_NODE - (set of dangerous commands) */
install_element (RESTRICTED_NODE, &show_ip_bgp_route_cmd);
install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_route_cmd);
@@ -12076,13 +12077,13 @@ bgp_route_init (void)
install_element (VIEW_NODE, &show_bgp_view_neighbor_flap_cmd);
install_element (VIEW_NODE, &show_bgp_view_ipv6_neighbor_flap_cmd);
install_element (VIEW_NODE, &show_bgp_view_neighbor_damp_cmd);
- install_element (VIEW_NODE, &show_bgp_view_ipv6_neighbor_damp_cmd);
+ install_element (VIEW_NODE, &show_bgp_view_ipv6_neighbor_damp_cmd);
install_element (VIEW_NODE, &show_bgp_view_rsclient_cmd);
install_element (VIEW_NODE, &show_bgp_view_rsclient_route_cmd);
install_element (VIEW_NODE, &show_bgp_view_rsclient_prefix_cmd);
-
+
/* Restricted:
- * VIEW_NODE - (set of dangerous commands) - (commands dependent on prev)
+ * VIEW_NODE - (set of dangerous commands) - (commands dependent on prev)
*/
install_element (RESTRICTED_NODE, &show_bgp_route_cmd);
install_element (RESTRICTED_NODE, &show_bgp_ipv6_route_cmd);
@@ -12189,13 +12190,13 @@ bgp_route_init (void)
install_element (ENABLE_NODE, &show_bgp_view_rsclient_cmd);
install_element (ENABLE_NODE, &show_bgp_view_rsclient_route_cmd);
install_element (ENABLE_NODE, &show_bgp_view_rsclient_prefix_cmd);
-
+
/* Statistics */
install_element (ENABLE_NODE, &show_bgp_statistics_cmd);
install_element (ENABLE_NODE, &show_bgp_statistics_vpnv4_cmd);
install_element (ENABLE_NODE, &show_bgp_statistics_view_cmd);
install_element (ENABLE_NODE, &show_bgp_statistics_view_vpnv4_cmd);
-
+
/* old command */
install_element (VIEW_NODE, &show_ipv6_bgp_cmd);
install_element (VIEW_NODE, &show_ipv6_bgp_route_cmd);
@@ -12233,7 +12234,7 @@ bgp_route_init (void)
install_element (VIEW_NODE, &show_ipv6_mbgp_community_list_cmd);
install_element (VIEW_NODE, &show_ipv6_mbgp_community_list_exact_cmd);
install_element (VIEW_NODE, &show_ipv6_mbgp_prefix_longer_cmd);
-
+
/* old command */
install_element (ENABLE_NODE, &show_ipv6_bgp_cmd);
install_element (ENABLE_NODE, &show_ipv6_bgp_route_cmd);
diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h
index 5eed3486..c206d673 100644
--- a/bgpd/bgp_route.h
+++ b/bgpd/bgp_route.h
@@ -23,7 +23,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "bgp_table.h"
-/* Ancillary information to struct bgp_info,
+/* Ancillary information to struct bgp_info,
* used for uncommonly used data (aggregation, MPLS, etc.)
* and lazily allocated to save memory.
*/
@@ -39,7 +39,7 @@ struct bgp_info_extra
u_int32_t igpmetric;
/* MPLS label. */
- u_char tag[3];
+ u_char tag[3];
};
struct bgp_info
@@ -47,22 +47,22 @@ struct bgp_info
/* For linked list. */
struct bgp_info *next;
struct bgp_info *prev;
-
+
/* Peer structure. */
struct peer *peer;
/* Attribute structure. */
struct attr *attr;
-
+
/* Extra information */
struct bgp_info_extra *extra;
-
+
/* Uptime. */
time_t uptime;
/* reference count */
int lock;
-
+
/* BGP information status. */
u_int16_t flags;
#define BGP_INFO_IGP_CHANGED (1 << 0)
@@ -86,7 +86,7 @@ struct bgp_info
#define BGP_ROUTE_NORMAL 0
#define BGP_ROUTE_STATIC 1
#define BGP_ROUTE_AGGREGATE 2
-#define BGP_ROUTE_REDISTRIBUTE 3
+#define BGP_ROUTE_REDISTRIBUTE 3
};
/* BGP static route configuration. */
@@ -106,7 +106,7 @@ struct bgp_static
/* Atomic set reference count (ie cause of pathlimit) */
u_int32_t atomic;
-
+
/* BGP redistribute route-map. */
struct
{
@@ -116,7 +116,7 @@ struct bgp_static
/* MPLS label. */
u_char tag[3];
-
+
/* AS-Pathlimit TTL */
u_char ttl;
};
@@ -133,19 +133,21 @@ struct bgp_static
|| CHECK_FLAG ((BI)->flags, BGP_INFO_UNUSEABLE))
#define DISTRIBUTE_IN_NAME(F) ((F)->dlist[FILTER_IN].name)
-#define DISTRIBUTE_IN(F) ((F)->dlist[FILTER_IN].alist)
+#define DISTRIBUTE_IN_LIST(F) ((F)->dlist[FILTER_IN].alist)
#define DISTRIBUTE_OUT_NAME(F) ((F)->dlist[FILTER_OUT].name)
-#define DISTRIBUTE_OUT(F) ((F)->dlist[FILTER_OUT].alist)
+#define DISTRIBUTE_OUT_LIST(F) ((F)->dlist[FILTER_OUT].alist)
-#define PREFIX_LIST_IN_NAME(F) ((F)->plist[FILTER_IN].name)
-#define PREFIX_LIST_IN(F) ((F)->plist[FILTER_IN].plist)
-#define PREFIX_LIST_OUT_NAME(F) ((F)->plist[FILTER_OUT].name)
-#define PREFIX_LIST_OUT(F) ((F)->plist[FILTER_OUT].plist)
+#define PREFIX_LIST_IN_REF(F) ((F)->plist[FILTER_IN].ref)
+#define PREFIX_LIST_IN_NAME(F) prefix_list_ref_name(PREFIX_LIST_IN_REF(F))
+#define PREFIX_LIST_IN_LIST(F) prefix_list_ref_plist(PREFIX_LIST_IN_REF(F))
+#define PREFIX_LIST_OUT_REF(F) ((F)->plist[FILTER_OUT].ref)
+#define PREFIX_LIST_OUT_NAME(F) prefix_list_ref_name(PREFIX_LIST_OUT_REF(F))
+#define PREFIX_LIST_OUT_LIST(F) prefix_list_ref_plist(PREFIX_LIST_OUT_REF(F))
#define FILTER_LIST_IN_NAME(F) ((F)->aslist[FILTER_IN].name)
-#define FILTER_LIST_IN(F) ((F)->aslist[FILTER_IN].aslist)
+#define FILTER_LIST_IN_LIST(F) ((F)->aslist[FILTER_IN].aslist)
#define FILTER_LIST_OUT_NAME(F) ((F)->aslist[FILTER_OUT].name)
-#define FILTER_LIST_OUT(F) ((F)->aslist[FILTER_OUT].aslist)
+#define FILTER_LIST_OUT_LIST(F) ((F)->aslist[FILTER_OUT].aslist)
#define ROUTE_MAP_IN_NAME(F) ((F)->map[RMAP_IN].name)
#define ROUTE_MAP_IN(F) ((F)->map[RMAP_IN].map)
@@ -203,16 +205,16 @@ extern void bgp_static_delete (struct bgp *);
extern void bgp_static_update (struct bgp *, struct prefix *, struct bgp_static *,
afi_t, safi_t);
extern void bgp_static_withdraw (struct bgp *, struct prefix *, afi_t, safi_t);
-
-extern int bgp_static_set_vpnv4 (struct vty *vty, const char *,
+
+extern int bgp_static_set_vpnv4 (struct vty *vty, const char *,
const char *, const char *);
-extern int bgp_static_unset_vpnv4 (struct vty *, const char *,
+extern int bgp_static_unset_vpnv4 (struct vty *, const char *,
const char *, const char *);
/* this is primarily for MPLS-VPN */
extern int bgp_update (struct peer *, struct prefix *, struct attr *,
- afi_t, safi_t, int, int, struct prefix_rd *,
+ afi_t, safi_t, int, int, struct prefix_rd *,
u_char *, int);
extern int bgp_withdraw (struct peer *, struct prefix *, struct attr *,
afi_t, safi_t, int, int, struct prefix_rd *, u_char *);
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index 88be52e2..bdf3190c 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -307,10 +307,10 @@ DEFUN_DEPRECATED (neighbor_version,
{
return CMD_SUCCESS;
}
-
+
/* "router bgp" commands. */
-DEFUN (router_bgp,
- router_bgp_cmd,
+DEFUN (router_bgp,
+ router_bgp_cmd,
"router bgp " CMD_AS_RANGE,
ROUTER_STR
BGP_STR
@@ -330,7 +330,7 @@ DEFUN (router_bgp,
switch (ret)
{
case BGP_ERR_MULTIPLE_INSTANCE_NOT_SET:
- vty_out (vty, "Please specify 'bgp multiple-instance' first%s",
+ vty_out (vty, "Please specify 'bgp multiple-instance' first%s",
VTY_NEWLINE);
return CMD_WARNING;
case BGP_ERR_AS_MISMATCH:
@@ -357,7 +357,7 @@ ALIAS (router_bgp,
AS_STR
"BGP view\n"
"view name\n")
-
+
/* "no router bgp" commands. */
DEFUN (no_router_bgp,
no_router_bgp_cmd,
@@ -398,7 +398,7 @@ ALIAS (no_router_bgp,
AS_STR
"BGP view\n"
"view name\n")
-
+
/* BGP router-id. */
DEFUN (bgp_router_id,
@@ -469,7 +469,7 @@ ALIAS (no_bgp_router_id,
BGP_STR
"Override configured router identifier\n"
"Manually configured router identifier\n")
-
+
/* BGP Cluster ID. */
DEFUN (bgp_cluster_id,
@@ -539,7 +539,7 @@ ALIAS (no_bgp_cluster_id,
BGP_STR
"Configure Route-Reflector Cluster-id\n"
"Route-Reflector Cluster-id in IP address format\n")
-
+
DEFUN (bgp_confederation_identifier,
bgp_confederation_identifier_cmd,
"bgp confederation identifier " CMD_AS_RANGE,
@@ -589,7 +589,7 @@ ALIAS (no_bgp_confederation_identifier,
"AS confederation parameters\n"
"AS number\n"
"Set routing domain confederation AS\n")
-
+
DEFUN (bgp_confederation_peers,
bgp_confederation_peers_cmd,
"bgp confederation peers ." CMD_AS_RANGE,
@@ -643,7 +643,7 @@ DEFUN (no_bgp_confederation_peers,
}
return CMD_SUCCESS;
}
-
+
/* BGP timers. */
DEFUN (bgp_timers,
@@ -699,7 +699,7 @@ ALIAS (no_bgp_timers,
"BGP timers\n"
"Keepalive interval\n"
"Holdtime\n")
-
+
DEFUN (bgp_client_to_client_reflection,
bgp_client_to_client_reflection_cmd,
"bgp client-to-client reflection",
@@ -756,7 +756,7 @@ DEFUN (no_bgp_always_compare_med,
bgp_flag_unset (bgp, BGP_FLAG_ALWAYS_COMPARE_MED);
return CMD_SUCCESS;
}
-
+
/* "bgp deterministic-med" configuration. */
DEFUN (bgp_deterministic_med,
bgp_deterministic_med_cmd,
@@ -887,7 +887,7 @@ DEFUN (no_bgp_fast_external_failover,
bgp_flag_set (bgp, BGP_FLAG_NO_FAST_EXT_FAILOVER);
return CMD_SUCCESS;
}
-
+
/* "bgp enforce-first-as" configuration. */
DEFUN (bgp_enforce_first_as,
bgp_enforce_first_as_cmd,
@@ -915,7 +915,7 @@ DEFUN (no_bgp_enforce_first_as,
bgp_flag_unset (bgp, BGP_FLAG_ENFORCE_FIRST_AS);
return CMD_SUCCESS;
}
-
+
/* "bgp bestpath compare-routerid" configuration. */
DEFUN (bgp_bestpath_compare_router_id,
bgp_bestpath_compare_router_id_cmd,
@@ -945,7 +945,7 @@ DEFUN (no_bgp_bestpath_compare_router_id,
bgp_flag_unset (bgp, BGP_FLAG_COMPARE_ROUTER_ID);
return CMD_SUCCESS;
}
-
+
/* "bgp bestpath as-path ignore" configuration. */
DEFUN (bgp_bestpath_aspath_ignore,
bgp_bestpath_aspath_ignore_cmd,
@@ -977,7 +977,7 @@ DEFUN (no_bgp_bestpath_aspath_ignore,
bgp_flag_unset (bgp, BGP_FLAG_ASPATH_IGNORE);
return CMD_SUCCESS;
}
-
+
/* "bgp bestpath as-path confed" configuration. */
DEFUN (bgp_bestpath_aspath_confed,
bgp_bestpath_aspath_confed_cmd,
@@ -1009,7 +1009,7 @@ DEFUN (no_bgp_bestpath_aspath_confed,
bgp_flag_unset (bgp, BGP_FLAG_ASPATH_CONFED);
return CMD_SUCCESS;
}
-
+
/* "bgp log-neighbor-changes" configuration. */
DEFUN (bgp_log_neighbor_changes,
bgp_log_neighbor_changes_cmd,
@@ -1037,7 +1037,7 @@ DEFUN (no_bgp_log_neighbor_changes,
bgp_flag_unset (bgp, BGP_FLAG_LOG_NEIGHBOR_CHANGES);
return CMD_SUCCESS;
}
-
+
/* "bgp bestpath med" configuration. */
DEFUN (bgp_bestpath_med,
bgp_bestpath_med_cmd,
@@ -1049,7 +1049,7 @@ DEFUN (bgp_bestpath_med,
"Treat missing MED as the least preferred one\n")
{
struct bgp *bgp;
-
+
bgp = vty->index;
if (strncmp (argv[0], "confed", 1) == 0)
@@ -1070,7 +1070,7 @@ DEFUN (bgp_bestpath_med2,
"Treat missing MED as the least preferred one\n")
{
struct bgp *bgp;
-
+
bgp = vty->index;
bgp_flag_set (bgp, BGP_FLAG_MED_CONFED);
bgp_flag_set (bgp, BGP_FLAG_MED_MISSING_AS_WORST);
@@ -1099,7 +1099,7 @@ DEFUN (no_bgp_bestpath_med,
struct bgp *bgp;
bgp = vty->index;
-
+
if (strncmp (argv[0], "confed", 1) == 0)
bgp_flag_unset (bgp, BGP_FLAG_MED_CONFED);
else
@@ -1119,7 +1119,7 @@ DEFUN (no_bgp_bestpath_med2,
"Treat missing MED as the least preferred one\n")
{
struct bgp *bgp;
-
+
bgp = vty->index;
bgp_flag_unset (bgp, BGP_FLAG_MED_CONFED);
bgp_flag_unset (bgp, BGP_FLAG_MED_MISSING_AS_WORST);
@@ -1135,7 +1135,7 @@ ALIAS (no_bgp_bestpath_med2,
"MED attribute\n"
"Treat missing MED as the least preferred one\n"
"Compare MED among confederation paths\n")
-
+
/* "no bgp default ipv4-unicast". */
DEFUN (no_bgp_default_ipv4_unicast,
no_bgp_default_ipv4_unicast_cmd,
@@ -1165,7 +1165,7 @@ DEFUN (bgp_default_ipv4_unicast,
bgp_flag_unset (bgp, BGP_FLAG_NO_DEFAULT_IPV4);
return CMD_SUCCESS;
}
-
+
/* "bgp import-check" configuration. */
DEFUN (bgp_network_import_check,
bgp_network_import_check_cmd,
@@ -1195,7 +1195,7 @@ DEFUN (no_bgp_network_import_check,
bgp_flag_unset (bgp, BGP_FLAG_IMPORT_CHECK);
return CMD_SUCCESS;
}
-
+
DEFUN (bgp_default_local_preference,
bgp_default_local_preference_cmd,
"bgp default local-preference <0-4294967295>",
@@ -1239,9 +1239,9 @@ ALIAS (no_bgp_default_local_preference,
"Configure BGP defaults\n"
"local preference (higher=more preferred)\n"
"Configure default local preference value\n")
-
+
static int
-peer_remote_as_vty (struct vty *vty, const char *peer_str,
+peer_remote_as_vty (struct vty *vty, const char *peer_str,
const char *as_str, afi_t afi, safi_t safi)
{
int ret;
@@ -1299,7 +1299,7 @@ DEFUN (neighbor_remote_as,
{
return peer_remote_as_vty (vty, argv[0], argv[1], AFI_IP, SAFI_UNICAST);
}
-
+
DEFUN (neighbor_peer_group,
neighbor_peer_group_cmd,
"neighbor WORD peer-group",
@@ -1404,7 +1404,7 @@ DEFUN (no_neighbor_peer_group_remote_as,
}
return CMD_SUCCESS;
}
-
+
DEFUN (neighbor_local_as,
neighbor_local_as_cmd,
NEIGHBOR_CMD2 "local-as " CMD_AS_RANGE,
@@ -1481,7 +1481,7 @@ ALIAS (no_neighbor_local_as,
"Specify a local-as number\n"
"AS number used as local AS\n"
"Do not prepend local-as to updates from ebgp peers\n")
-
+
DEFUN (neighbor_password,
neighbor_password_cmd,
NEIGHBOR_CMD2 "password LINE",
@@ -1519,7 +1519,7 @@ DEFUN (no_neighbor_password,
ret = peer_password_unset (peer);
return bgp_vty_return (vty, ret);
}
-
+
DEFUN (neighbor_activate,
neighbor_activate_cmd,
NEIGHBOR_CMD2 "activate",
@@ -1558,7 +1558,7 @@ DEFUN (no_neighbor_activate,
return bgp_vty_return (vty, ret);
}
-
+
DEFUN (neighbor_set_peer_group,
neighbor_set_peer_group_cmd,
NEIGHBOR_CMD "peer-group WORD",
@@ -1596,7 +1596,7 @@ DEFUN (neighbor_set_peer_group,
return CMD_WARNING;
}
- ret = peer_group_bind (bgp, &su, group, bgp_node_afi (vty),
+ ret = peer_group_bind (bgp, &su, group, bgp_node_afi (vty),
bgp_node_safi (vty), &as);
if (ret == BGP_ERR_PEER_GROUP_PEER_TYPE_DIFFERENT)
@@ -1640,9 +1640,9 @@ DEFUN (no_neighbor_set_peer_group,
return bgp_vty_return (vty, ret);
}
-
+
static int
-peer_flag_modify_vty (struct vty *vty, const char *ip_str,
+peer_flag_modify_vty (struct vty *vty, const char *ip_str,
u_int16_t flag, int set)
{
int ret;
@@ -1693,7 +1693,7 @@ DEFUN (no_neighbor_passive,
{
return peer_flag_unset_vty (vty, argv[0], PEER_FLAG_PASSIVE);
}
-
+
/* neighbor shutdown. */
DEFUN (neighbor_shutdown,
neighbor_shutdown_cmd,
@@ -1715,7 +1715,7 @@ DEFUN (no_neighbor_shutdown,
{
return peer_flag_unset_vty (vty, argv[0], PEER_FLAG_SHUTDOWN);
}
-
+
/* Deprecated neighbor capability route-refresh. */
DEFUN_DEPRECATED (neighbor_capability_route_refresh,
neighbor_capability_route_refresh_cmd,
@@ -1739,7 +1739,7 @@ DEFUN_DEPRECATED (no_neighbor_capability_route_refresh,
{
return CMD_SUCCESS;
}
-
+
/* neighbor capability dynamic. */
DEFUN (neighbor_capability_dynamic,
neighbor_capability_dynamic_cmd,
@@ -1763,7 +1763,7 @@ DEFUN (no_neighbor_capability_dynamic,
{
return peer_flag_unset_vty (vty, argv[0], PEER_FLAG_DYNAMIC_CAPABILITY);
}
-
+
/* neighbor dont-capability-negotiate */
DEFUN (neighbor_dont_capability_negotiate,
neighbor_dont_capability_negotiate_cmd,
@@ -1785,7 +1785,7 @@ DEFUN (no_neighbor_dont_capability_negotiate,
{
return peer_flag_unset_vty (vty, argv[0], PEER_FLAG_DONT_CAPABILITY);
}
-
+
static int
peer_af_flag_modify_vty (struct vty *vty, const char *peer_str, afi_t afi,
safi_t safi, u_int32_t flag, int set)
@@ -1818,7 +1818,7 @@ peer_af_flag_unset_vty (struct vty *vty, const char *peer_str, afi_t afi,
{
return peer_af_flag_modify_vty (vty, peer_str, afi, safi, flag, 0);
}
-
+
/* neighbor capability orf prefix-list. */
DEFUN (neighbor_capability_orf_prefix,
neighbor_capability_orf_prefix_cmd,
@@ -1874,7 +1874,7 @@ DEFUN (no_neighbor_capability_orf_prefix,
return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty),
bgp_node_safi (vty), flag);
}
-
+
/* neighbor next-hop-self. */
DEFUN (neighbor_nexthop_self,
neighbor_nexthop_self_cmd,
@@ -1898,7 +1898,7 @@ DEFUN (no_neighbor_nexthop_self,
return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty),
bgp_node_safi (vty), PEER_FLAG_NEXTHOP_SELF);
}
-
+
/* neighbor remove-private-AS. */
DEFUN (neighbor_remove_private_as,
neighbor_remove_private_as_cmd,
@@ -1924,7 +1924,7 @@ DEFUN (no_neighbor_remove_private_as,
bgp_node_safi (vty),
PEER_FLAG_REMOVE_PRIVATE_AS);
}
-
+
/* neighbor send-community. */
DEFUN (neighbor_send_community,
neighbor_send_community_cmd,
@@ -1950,7 +1950,7 @@ DEFUN (no_neighbor_send_community,
bgp_node_safi (vty),
PEER_FLAG_SEND_COMMUNITY);
}
-
+
/* neighbor send-community extended. */
DEFUN (neighbor_send_community_type,
neighbor_send_community_type_cmd,
@@ -2002,7 +2002,7 @@ DEFUN (no_neighbor_send_community_type,
(PEER_FLAG_SEND_COMMUNITY |
PEER_FLAG_SEND_EXT_COMMUNITY));
}
-
+
/* neighbor soft-reconfig. */
DEFUN (neighbor_soft_reconfiguration,
neighbor_soft_reconfiguration_cmd,
@@ -2030,7 +2030,7 @@ DEFUN (no_neighbor_soft_reconfiguration,
bgp_node_afi (vty), bgp_node_safi (vty),
PEER_FLAG_SOFT_RECONFIG);
}
-
+
DEFUN (neighbor_route_reflector_client,
neighbor_route_reflector_client_cmd,
NEIGHBOR_CMD2 "route-reflector-client",
@@ -2062,9 +2062,9 @@ DEFUN (no_neighbor_route_reflector_client,
bgp_node_safi (vty),
PEER_FLAG_REFLECTOR_CLIENT);
}
-
+
static int
-peer_rsclient_set_vty (struct vty *vty, const char *peer_str,
+peer_rsclient_set_vty (struct vty *vty, const char *peer_str,
int afi, int safi)
{
int ret;
@@ -2125,7 +2125,7 @@ peer_rsclient_set_vty (struct vty *vty, const char *peer_str,
{
pfilter = &peer->filter[afi][safi];
- /* Members of a non-RS-Client group should not be RS-Clients, as that
+ /* Members of a non-RS-Client group should not be RS-Clients, as that
is checked when the become part of the peer-group */
ret = peer_af_flag_set (peer, afi, safi, PEER_FLAG_RSERVER_CLIENT);
if (ret < 0)
@@ -2160,7 +2160,7 @@ peer_rsclient_set_vty (struct vty *vty, const char *peer_str,
}
static int
-peer_rsclient_unset_vty (struct vty *vty, const char *peer_str,
+peer_rsclient_unset_vty (struct vty *vty, const char *peer_str,
int afi, int safi)
{
int ret;
@@ -2210,7 +2210,7 @@ peer_rsclient_unset_vty (struct vty *vty, const char *peer_str,
return CMD_SUCCESS;
}
-
+
/* neighbor route-server-client. */
DEFUN (neighbor_route_server_client,
neighbor_route_server_client_cmd,
@@ -2234,7 +2234,7 @@ DEFUN (no_neighbor_route_server_client,
return peer_rsclient_unset_vty (vty, argv[0], bgp_node_afi(vty),
bgp_node_safi(vty));
}
-
+
DEFUN (neighbor_nexthop_local_unchanged,
neighbor_nexthop_local_unchanged_cmd,
NEIGHBOR_CMD2 "nexthop-local unchanged",
@@ -2247,7 +2247,7 @@ DEFUN (neighbor_nexthop_local_unchanged,
bgp_node_safi (vty),
PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED );
}
-
+
DEFUN (no_neighbor_nexthop_local_unchanged,
no_neighbor_nexthop_local_unchanged_cmd,
NO_NEIGHBOR_CMD2 "nexthop-local unchanged",
@@ -2261,7 +2261,7 @@ DEFUN (no_neighbor_nexthop_local_unchanged,
bgp_node_safi (vty),
PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED );
}
-
+
DEFUN (neighbor_attr_unchanged,
neighbor_attr_unchanged_cmd,
NEIGHBOR_CMD2 "attribute-unchanged",
@@ -2426,7 +2426,7 @@ ALIAS (neighbor_attr_unchanged,
DEFUN (no_neighbor_attr_unchanged,
no_neighbor_attr_unchanged_cmd,
NO_NEIGHBOR_CMD2 "attribute-unchanged",
- NO_STR
+ NO_STR
NEIGHBOR_STR
NEIGHBOR_ADDR_STR2
"BGP attribute is propagated unchanged to this neighbor\n")
@@ -2618,10 +2618,10 @@ DEFUN_DEPRECATED (neighbor_transparent_nexthop,
bgp_node_safi (vty),
PEER_FLAG_NEXTHOP_UNCHANGED);
}
-
+
/* EBGP multihop configuration. */
static int
-peer_ebgp_multihop_set_vty (struct vty *vty, const char *ip_str,
+peer_ebgp_multihop_set_vty (struct vty *vty, const char *ip_str,
const char *ttl_str)
{
struct peer *peer;
@@ -2642,7 +2642,7 @@ peer_ebgp_multihop_set_vty (struct vty *vty, const char *ip_str,
}
static int
-peer_ebgp_multihop_unset_vty (struct vty *vty, const char *ip_str)
+peer_ebgp_multihop_unset_vty (struct vty *vty, const char *ip_str)
{
struct peer *peer;
@@ -2696,7 +2696,7 @@ ALIAS (no_neighbor_ebgp_multihop,
NEIGHBOR_ADDR_STR2
"Allow EBGP neighbors not on directly connected networks\n"
"maximum hop count\n")
-
+
/* disable-connected-check */
DEFUN (neighbor_disable_connected_check,
neighbor_disable_connected_check_cmd,
@@ -2735,7 +2735,7 @@ ALIAS (no_neighbor_disable_connected_check,
NEIGHBOR_STR
NEIGHBOR_ADDR_STR2
"Enforce EBGP neighbors perform multihop\n")
-
+
DEFUN (neighbor_description,
neighbor_description_cmd,
NEIGHBOR_CMD2 "description .LINE",
@@ -2790,10 +2790,10 @@ ALIAS (no_neighbor_description,
NEIGHBOR_ADDR_STR2
"Neighbor specific description\n"
"Up to 80 characters describing this neighbor\n")
-
+
/* Neighbor update-source. */
static int
-peer_update_source_vty (struct vty *vty, const char *peer_str,
+peer_update_source_vty (struct vty *vty, const char *peer_str,
const char *source_str)
{
struct peer *peer;
@@ -2847,10 +2847,10 @@ DEFUN (no_neighbor_update_source,
{
return peer_update_source_vty (vty, argv[0], NULL);
}
-
+
static int
-peer_default_originate_set_vty (struct vty *vty, const char *peer_str,
- afi_t afi, safi_t safi,
+peer_default_originate_set_vty (struct vty *vty, const char *peer_str,
+ afi_t afi, safi_t safi,
const char *rmap, int set)
{
int ret;
@@ -2914,10 +2914,10 @@ ALIAS (no_neighbor_default_originate,
"Originate default route to this neighbor\n"
"Route-map to specify criteria to originate default\n"
"route-map name\n")
-
+
/* Set neighbor's BGP port. */
static int
-peer_port_vty (struct vty *vty, const char *ip_str, int afi,
+peer_port_vty (struct vty *vty, const char *ip_str, int afi,
const char *port_str)
{
struct peer *peer;
@@ -2929,7 +2929,7 @@ peer_port_vty (struct vty *vty, const char *ip_str, int afi,
return CMD_WARNING;
if (! port_str)
- {
+ {
sp = getservbyname ("bgp", "tcp");
port = (sp == NULL) ? BGP_PORT_DEFAULT : ntohs (sp->s_port);
}
@@ -2974,10 +2974,10 @@ ALIAS (no_neighbor_port,
NEIGHBOR_ADDR_STR
"Neighbor's BGP port\n"
"TCP port number\n")
-
+
/* neighbor weight. */
static int
-peer_weight_set_vty (struct vty *vty, const char *ip_str,
+peer_weight_set_vty (struct vty *vty, const char *ip_str,
const char *weight_str)
{
int ret;
@@ -3039,7 +3039,7 @@ ALIAS (no_neighbor_weight,
NEIGHBOR_ADDR_STR2
"Set default weight for routes from this neighbor\n"
"default weight\n")
-
+
/* Override capability negotiation. */
DEFUN (neighbor_override_capability,
neighbor_override_capability_cmd,
@@ -3061,7 +3061,7 @@ DEFUN (no_neighbor_override_capability,
{
return peer_flag_unset_vty (vty, argv[0], PEER_FLAG_OVERRIDE_CAPABILITY);
}
-
+
DEFUN (neighbor_strict_capability,
neighbor_strict_capability_cmd,
NEIGHBOR_CMD "strict-capability-match",
@@ -3082,9 +3082,9 @@ DEFUN (no_neighbor_strict_capability,
{
return peer_flag_unset_vty (vty, argv[0], PEER_FLAG_STRICT_CAP_MATCH);
}
-
+
static int
-peer_timers_set_vty (struct vty *vty, const char *ip_str,
+peer_timers_set_vty (struct vty *vty, const char *ip_str,
const char *keep_str, const char *hold_str)
{
int ret;
@@ -3103,7 +3103,7 @@ peer_timers_set_vty (struct vty *vty, const char *ip_str,
return bgp_vty_return (vty, ret);
}
-
+
static int
peer_timers_unset_vty (struct vty *vty, const char *ip_str)
{
@@ -3141,9 +3141,9 @@ DEFUN (no_neighbor_timers,
{
return peer_timers_unset_vty (vty, argv[0]);
}
-
+
static int
-peer_timers_connect_set_vty (struct vty *vty, const char *ip_str,
+peer_timers_connect_set_vty (struct vty *vty, const char *ip_str,
const char *time_str)
{
int ret;
@@ -3209,10 +3209,10 @@ ALIAS (no_neighbor_timers_connect,
"BGP per neighbor timers\n"
"BGP connect timer\n"
"Connect timer\n")
-
+
static int
-peer_advertise_interval_vty (struct vty *vty, const char *ip_str,
- const char *time_str, int set)
+peer_advertise_interval_vty (struct vty *vty, const char *ip_str,
+ const char *time_str, int set)
{
int ret;
struct peer *peer;
@@ -3263,7 +3263,7 @@ ALIAS (no_neighbor_advertise_interval,
NEIGHBOR_ADDR_STR
"Minimum interval between sending BGP routing updates\n"
"time in seconds\n")
-
+
/* neighbor interface */
static int
peer_interface_vty (struct vty *vty, const char *ip_str, const char *str)
@@ -3305,10 +3305,10 @@ DEFUN (no_neighbor_interface,
{
return peer_interface_vty (vty, argv[0], NULL);
}
-
+
/* Set distribute list to the peer. */
static int
-peer_distribute_set_vty (struct vty *vty, const char *ip_str,
+peer_distribute_set_vty (struct vty *vty, const char *ip_str,
afi_t afi, safi_t safi,
const char *name_str, const char *direct_str)
{
@@ -3386,11 +3386,11 @@ DEFUN (no_neighbor_distribute_list,
return peer_distribute_unset_vty (vty, argv[0], bgp_node_afi (vty),
bgp_node_safi (vty), argv[2]);
}
-
+
/* Set prefix list to the peer. */
static int
peer_prefix_list_set_vty (struct vty *vty, const char *ip_str, afi_t afi,
- safi_t safi, const char *name_str,
+ safi_t safi, const char *name_str,
const char *direct_str)
{
int ret;
@@ -3423,7 +3423,7 @@ peer_prefix_list_unset_vty (struct vty *vty, const char *ip_str, afi_t afi,
peer = peer_and_group_lookup_vty (vty, ip_str);
if (! peer)
return CMD_WARNING;
-
+
/* Check filter direction. */
if (strncmp (direct_str, "i", 1) == 0)
direct = FILTER_IN;
@@ -3463,9 +3463,9 @@ DEFUN (no_neighbor_prefix_list,
return peer_prefix_list_unset_vty (vty, argv[0], bgp_node_afi (vty),
bgp_node_safi (vty), argv[2]);
}
-
+
static int
-peer_aslist_set_vty (struct vty *vty, const char *ip_str,
+peer_aslist_set_vty (struct vty *vty, const char *ip_str,
afi_t afi, safi_t safi,
const char *name_str, const char *direct_str)
{
@@ -3489,7 +3489,7 @@ peer_aslist_set_vty (struct vty *vty, const char *ip_str,
}
static int
-peer_aslist_unset_vty (struct vty *vty, const char *ip_str,
+peer_aslist_unset_vty (struct vty *vty, const char *ip_str,
afi_t afi, safi_t safi,
const char *direct_str)
{
@@ -3540,10 +3540,10 @@ DEFUN (no_neighbor_filter_list,
return peer_aslist_unset_vty (vty, argv[0], bgp_node_afi (vty),
bgp_node_safi (vty), argv[2]);
}
-
+
/* Set route-map to the peer. */
static int
-peer_route_map_set_vty (struct vty *vty, const char *ip_str,
+peer_route_map_set_vty (struct vty *vty, const char *ip_str,
afi_t afi, safi_t safi,
const char *name_str, const char *direct_str)
{
@@ -3629,7 +3629,7 @@ DEFUN (no_neighbor_route_map,
return peer_route_map_unset_vty (vty, argv[0], bgp_node_afi (vty),
bgp_node_safi (vty), argv[2]);
}
-
+
/* Set unsuppress-map to the peer. */
static int
peer_unsuppress_map_set_vty (struct vty *vty, const char *ip_str, afi_t afi,
@@ -3688,10 +3688,10 @@ DEFUN (no_neighbor_unsuppress_map,
return peer_unsuppress_map_unset_vty (vty, argv[0], bgp_node_afi (vty),
bgp_node_safi (vty));
}
-
+
static int
peer_maximum_prefix_set_vty (struct vty *vty, const char *ip_str, afi_t afi,
- safi_t safi, const char *num_str,
+ safi_t safi, const char *num_str,
const char *threshold_str, int warning,
const char *restart_str)
{
@@ -3835,7 +3835,7 @@ DEFUN (no_neighbor_maximum_prefix,
return peer_maximum_prefix_unset_vty (vty, argv[0], bgp_node_afi (vty),
bgp_node_safi (vty));
}
-
+
ALIAS (no_neighbor_maximum_prefix,
no_neighbor_maximum_prefix_val_cmd,
NO_NEIGHBOR_CMD2 "maximum-prefix <1-4294967295>",
@@ -3898,7 +3898,7 @@ ALIAS (no_neighbor_maximum_prefix,
"Threshold value (%) at which to generate a warning msg\n"
"Restart bgp connection after limit is exceeded\n"
"Restart interval in minutes")
-
+
/* "neighbor allowas-in" */
DEFUN (neighbor_allowas_in,
neighbor_allowas_in_cmd,
@@ -3953,7 +3953,7 @@ DEFUN (no_neighbor_allowas_in,
return bgp_vty_return (vty, ret);
}
-
+
/* Address family configuration. */
DEFUN (address_family_ipv4,
address_family_ipv4_cmd,
@@ -4037,7 +4037,7 @@ DEFUN (exit_address_family,
vty->node = BGP_NODE;
return CMD_SUCCESS;
}
-
+
/* BGP clear sort. */
enum clear_sort
{
@@ -4134,7 +4134,7 @@ bgp_clear (struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi,
if (! group)
{
vty_out (vty, "%%BGP: No such peer-group %s%s", arg, VTY_NEWLINE);
- return CMD_WARNING;
+ return CMD_WARNING;
}
for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
@@ -4160,7 +4160,7 @@ bgp_clear (struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi,
{
for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
{
- if (peer_sort (peer) == BGP_PEER_IBGP)
+ if (peer_sort (peer) == BGP_PEER_IBGP)
continue;
if (stype == BGP_CLEAR_SOFT_NONE)
@@ -4181,17 +4181,17 @@ bgp_clear (struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi,
int find = 0;
VTY_GET_LONG ("AS", as_ul, arg);
-
+
if (!as_ul)
{
- vty_out (vty, "Invalid AS number%s", VTY_NEWLINE);
+ vty_out (vty, "Invalid AS number%s", VTY_NEWLINE);
return CMD_WARNING;
}
as = (as_t) as_ul;
for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
{
- if (peer->as != as)
+ if (peer->as != as)
continue;
find = 1;
@@ -4214,7 +4214,7 @@ bgp_clear (struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi,
static int
bgp_clear_vty (struct vty *vty, const char *name, afi_t afi, safi_t safi,
- enum clear_sort sort, enum bgp_clear_type stype,
+ enum clear_sort sort, enum bgp_clear_type stype,
const char *arg)
{
struct bgp *bgp;
@@ -4241,7 +4241,7 @@ bgp_clear_vty (struct vty *vty, const char *name, afi_t afi, safi_t safi,
return bgp_clear (vty, bgp, afi, safi, sort, stype, arg);
}
-
+
DEFUN (clear_ip_bgp_all,
clear_ip_bgp_all_cmd,
"clear ip bgp *",
@@ -4251,7 +4251,7 @@ DEFUN (clear_ip_bgp_all,
"Clear all peers\n")
{
if (argc == 1)
- return bgp_clear_vty (vty, argv[0], 0, 0, clear_all, BGP_CLEAR_SOFT_NONE, NULL);
+ return bgp_clear_vty (vty, argv[0], 0, 0, clear_all, BGP_CLEAR_SOFT_NONE, NULL);
return bgp_clear_vty (vty, NULL, 0, 0, clear_all, BGP_CLEAR_SOFT_NONE, NULL);
}
@@ -4291,7 +4291,7 @@ ALIAS (clear_ip_bgp_all,
"Clear all peers\n")
DEFUN (clear_ip_bgp_peer,
- clear_ip_bgp_peer_cmd,
+ clear_ip_bgp_peer_cmd,
"clear ip bgp (A.B.C.D|X:X::X:X)",
CLEAR_STR
IP_STR
@@ -4303,7 +4303,7 @@ DEFUN (clear_ip_bgp_peer,
}
ALIAS (clear_ip_bgp_peer,
- clear_bgp_peer_cmd,
+ clear_bgp_peer_cmd,
"clear bgp (A.B.C.D|X:X::X:X)",
CLEAR_STR
BGP_STR
@@ -4311,7 +4311,7 @@ ALIAS (clear_ip_bgp_peer,
"BGP IPv6 neighbor to clear\n")
ALIAS (clear_ip_bgp_peer,
- clear_bgp_ipv6_peer_cmd,
+ clear_bgp_ipv6_peer_cmd,
"clear bgp ipv6 (A.B.C.D|X:X::X:X)",
CLEAR_STR
BGP_STR
@@ -4320,7 +4320,7 @@ ALIAS (clear_ip_bgp_peer,
"BGP IPv6 neighbor to clear\n")
DEFUN (clear_ip_bgp_peer_group,
- clear_ip_bgp_peer_group_cmd,
+ clear_ip_bgp_peer_group_cmd,
"clear ip bgp peer-group WORD",
CLEAR_STR
IP_STR
@@ -4332,7 +4332,7 @@ DEFUN (clear_ip_bgp_peer_group,
}
ALIAS (clear_ip_bgp_peer_group,
- clear_bgp_peer_group_cmd,
+ clear_bgp_peer_group_cmd,
"clear bgp peer-group WORD",
CLEAR_STR
BGP_STR
@@ -4340,7 +4340,7 @@ ALIAS (clear_ip_bgp_peer_group,
"BGP peer-group name\n")
ALIAS (clear_ip_bgp_peer_group,
- clear_bgp_ipv6_peer_group_cmd,
+ clear_bgp_ipv6_peer_group_cmd,
"clear bgp ipv6 peer-group WORD",
CLEAR_STR
BGP_STR
@@ -4360,14 +4360,14 @@ DEFUN (clear_ip_bgp_external,
}
ALIAS (clear_ip_bgp_external,
- clear_bgp_external_cmd,
+ clear_bgp_external_cmd,
"clear bgp external",
CLEAR_STR
BGP_STR
"Clear all external peers\n")
ALIAS (clear_ip_bgp_external,
- clear_bgp_ipv6_external_cmd,
+ clear_bgp_ipv6_external_cmd,
"clear bgp ipv6 external",
CLEAR_STR
BGP_STR
@@ -4383,7 +4383,7 @@ DEFUN (clear_ip_bgp_as,
"Clear peers with the AS number\n")
{
return bgp_clear_vty (vty, NULL, 0, 0, clear_as, BGP_CLEAR_SOFT_NONE, argv[0]);
-}
+}
ALIAS (clear_ip_bgp_as,
clear_bgp_as_cmd,
@@ -4399,7 +4399,7 @@ ALIAS (clear_ip_bgp_as,
BGP_STR
"Address family\n"
"Clear peers with the AS number\n")
-
+
/* Outbound soft-reconfiguration */
DEFUN (clear_ip_bgp_all_soft_out,
clear_ip_bgp_all_soft_out_cmd,
@@ -4705,7 +4705,7 @@ ALIAS (clear_bgp_peer_soft_out,
"Soft reconfig outbound update\n")
DEFUN (clear_ip_bgp_peer_group_soft_out,
- clear_ip_bgp_peer_group_soft_out_cmd,
+ clear_ip_bgp_peer_group_soft_out_cmd,
"clear ip bgp peer-group WORD soft out",
CLEAR_STR
IP_STR
@@ -4720,7 +4720,7 @@ DEFUN (clear_ip_bgp_peer_group_soft_out,
}
ALIAS (clear_ip_bgp_peer_group_soft_out,
- clear_ip_bgp_peer_group_out_cmd,
+ clear_ip_bgp_peer_group_out_cmd,
"clear ip bgp peer-group WORD out",
CLEAR_STR
IP_STR
@@ -4809,7 +4809,7 @@ ALIAS (clear_bgp_peer_group_soft_out,
"Soft reconfig outbound update\n")
DEFUN (clear_ip_bgp_external_soft_out,
- clear_ip_bgp_external_soft_out_cmd,
+ clear_ip_bgp_external_soft_out_cmd,
"clear ip bgp external soft out",
CLEAR_STR
IP_STR
@@ -4823,7 +4823,7 @@ DEFUN (clear_ip_bgp_external_soft_out,
}
ALIAS (clear_ip_bgp_external_soft_out,
- clear_ip_bgp_external_out_cmd,
+ clear_ip_bgp_external_out_cmd,
"clear ip bgp external out",
CLEAR_STR
IP_STR
@@ -5026,7 +5026,7 @@ ALIAS (clear_bgp_as_soft_out,
"Address family\n"
"Clear peers with the AS number\n"
"Soft reconfig outbound update\n")
-
+
/* Inbound soft-reconfiguration */
DEFUN (clear_ip_bgp_all_soft_in,
clear_ip_bgp_all_soft_in_cmd,
@@ -5323,7 +5323,7 @@ ALIAS (clear_ip_bgp_peer_soft_in,
BGP_STR
"BGP neighbor address to clear\n"
"Soft reconfig inbound update\n")
-
+
DEFUN (clear_ip_bgp_peer_in_prefix_filter,
clear_ip_bgp_peer_in_prefix_filter_cmd,
"clear ip bgp A.B.C.D in prefix-filter",
@@ -5988,7 +5988,7 @@ ALIAS (clear_bgp_as_in_prefix_filter,
"Clear peers with the AS number\n"
"Soft reconfig inbound update\n"
"Push out prefix-list ORF and do inbound soft reconfig\n")
-
+
/* Both soft-reconfiguration */
DEFUN (clear_ip_bgp_all_soft,
clear_ip_bgp_all_soft_cmd,
@@ -6087,7 +6087,7 @@ DEFUN (clear_bgp_all_soft,
if (argc == 1)
return bgp_clear_vty (vty, argv[0], AFI_IP6, SAFI_UNICAST, clear_all,
BGP_CLEAR_SOFT_BOTH, argv[0]);
-
+
return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_all,
BGP_CLEAR_SOFT_BOTH, argv[0]);
}
@@ -6362,7 +6362,7 @@ ALIAS (clear_bgp_as_soft,
"Address family\n"
"Clear peers with the AS number\n"
"Soft reconfig\n")
-
+
/* RS-client soft reconfiguration. */
#ifdef HAVE_IPV6
DEFUN (clear_bgp_all_rsclient,
@@ -6538,17 +6538,17 @@ DEFUN (show_bgp_views,
vty_out (vty, "Multiple BGP views are not defined%s", VTY_NEWLINE);
return CMD_WARNING;
}
-
+
vty_out (vty, "Defined BGP views:%s", VTY_NEWLINE);
for (ALL_LIST_ELEMENTS_RO(inst, node, bgp))
- vty_out (vty, "\t%s (AS%u)%s",
+ vty_out (vty, "\t%s (AS%u)%s",
bgp->name ? bgp->name : "(null)",
bgp->as, VTY_NEWLINE);
-
+
return CMD_SUCCESS;
}
-DEFUN (show_bgp_memory,
+DEFUN (show_bgp_memory,
show_bgp_memory_cmd,
"show bgp memory",
SHOW_STR
@@ -6557,14 +6557,14 @@ DEFUN (show_bgp_memory,
{
char memstrbuf[MTYPE_MEMSTR_LEN];
unsigned long count;
-
+
/* RIB related usage stats */
count = mtype_stats_alloc (MTYPE_BGP_NODE);
vty_out (vty, "%ld RIB nodes, using %s of memory%s", count,
mtype_memstr (memstrbuf, sizeof (memstrbuf),
count * sizeof (struct bgp_node)),
VTY_NEWLINE);
-
+
count = mtype_stats_alloc (MTYPE_BGP_ROUTE);
vty_out (vty, "%ld BGP routes, using %s of memory%s", count,
mtype_memstr (memstrbuf, sizeof (memstrbuf),
@@ -6575,13 +6575,13 @@ DEFUN (show_bgp_memory,
mtype_memstr (memstrbuf, sizeof (memstrbuf),
count * sizeof (struct bgp_info_extra)),
VTY_NEWLINE);
-
+
if ((count = mtype_stats_alloc (MTYPE_BGP_STATIC)))
vty_out (vty, "%ld Static routes, using %s of memory%s", count,
mtype_memstr (memstrbuf, sizeof (memstrbuf),
count * sizeof (struct bgp_static)),
VTY_NEWLINE);
-
+
/* Adj-In/Out */
if ((count = mtype_stats_alloc (MTYPE_BGP_ADJ_IN)))
vty_out (vty, "%ld Adj-In entries, using %s of memory%s", count,
@@ -6593,7 +6593,7 @@ DEFUN (show_bgp_memory,
mtype_memstr (memstrbuf, sizeof (memstrbuf),
count * sizeof (struct bgp_adj_out)),
VTY_NEWLINE);
-
+
if ((count = mtype_stats_alloc (MTYPE_BGP_NEXTHOP_CACHE)))
vty_out (vty, "%ld Nexthop cache entries, using %s of memory%s", count,
mtype_memstr (memstrbuf, sizeof (memstrbuf),
@@ -6608,32 +6608,32 @@ DEFUN (show_bgp_memory,
/* Attributes */
count = attr_count();
- vty_out (vty, "%ld BGP attributes, using %s of memory%s", count,
- mtype_memstr (memstrbuf, sizeof (memstrbuf),
- count * sizeof(struct attr)),
+ vty_out (vty, "%ld BGP attributes, using %s of memory%s", count,
+ mtype_memstr (memstrbuf, sizeof (memstrbuf),
+ count * sizeof(struct attr)),
VTY_NEWLINE);
if ((count = mtype_stats_alloc (MTYPE_ATTR_EXTRA)))
- vty_out (vty, "%ld BGP extra attributes, using %s of memory%s", count,
- mtype_memstr (memstrbuf, sizeof (memstrbuf),
- count * sizeof(struct attr_extra)),
+ vty_out (vty, "%ld BGP extra attributes, using %s of memory%s", count,
+ mtype_memstr (memstrbuf, sizeof (memstrbuf),
+ count * sizeof(struct attr_extra)),
VTY_NEWLINE);
-
+
if ((count = attr_unknown_count()))
vty_out (vty, "%ld unknown attributes%s", count, VTY_NEWLINE);
-
+
/* AS_PATH attributes */
count = aspath_count ();
vty_out (vty, "%ld BGP AS-PATH entries, using %s of memory%s", count,
mtype_memstr (memstrbuf, sizeof (memstrbuf),
count * sizeof (struct aspath)),
VTY_NEWLINE);
-
+
count = mtype_stats_alloc (MTYPE_AS_SEG);
vty_out (vty, "%ld BGP AS-PATH segments, using %s of memory%s", count,
mtype_memstr (memstrbuf, sizeof (memstrbuf),
count * sizeof (struct assegment)),
VTY_NEWLINE);
-
+
/* Other attributes */
if ((count = community_count ()))
vty_out (vty, "%ld BGP community entries, using %s of memory%s", count,
@@ -6645,26 +6645,26 @@ DEFUN (show_bgp_memory,
mtype_memstr (memstrbuf, sizeof (memstrbuf),
count * sizeof (struct ecommunity)),
VTY_NEWLINE);
-
+
if ((count = mtype_stats_alloc (MTYPE_CLUSTER)))
vty_out (vty, "%ld Cluster lists, using %s of memory%s", count,
mtype_memstr (memstrbuf, sizeof (memstrbuf),
count * sizeof (struct cluster_list)),
VTY_NEWLINE);
-
+
/* Peer related usage */
count = mtype_stats_alloc (MTYPE_BGP_PEER);
vty_out (vty, "%ld peers, using %s of memory%s", count,
mtype_memstr (memstrbuf, sizeof (memstrbuf),
count * sizeof (struct peer)),
VTY_NEWLINE);
-
+
if ((count = mtype_stats_alloc (MTYPE_PEER_GROUP)))
vty_out (vty, "%ld peer groups, using %s of memory%s", count,
mtype_memstr (memstrbuf, sizeof (memstrbuf),
count * sizeof (struct peer_group)),
VTY_NEWLINE);
-
+
/* Other */
if ((count = mtype_stats_alloc (MTYPE_HASH)))
vty_out (vty, "%ld hash tables, using %s of memory%s", count,
@@ -6696,7 +6696,7 @@ bgp_show_summary (struct vty *vty, struct bgp *bgp, int afi, int safi)
/* Header string for each address family. */
static char header[] = "Neighbor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd";
-
+
for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
{
if (peer->afc[afi][safi])
@@ -6705,7 +6705,7 @@ bgp_show_summary (struct vty *vty, struct bgp *bgp, int afi, int safi)
{
unsigned long ents;
char memstrbuf[MTYPE_MEMSTR_LEN];
-
+
/* Usage summary and header */
vty_out (vty,
"BGP router identifier %s, local AS number %u%s",
@@ -6716,7 +6716,7 @@ bgp_show_summary (struct vty *vty, struct bgp *bgp, int afi, int safi)
mtype_memstr (memstrbuf, sizeof (memstrbuf),
ents * sizeof (struct bgp_node)),
VTY_NEWLINE);
-
+
/* Peer related usage */
ents = listcount (bgp->peer);
vty_out (vty, "Peers %ld, using %s of memory%s",
@@ -6724,14 +6724,14 @@ bgp_show_summary (struct vty *vty, struct bgp *bgp, int afi, int safi)
mtype_memstr (memstrbuf, sizeof (memstrbuf),
ents * sizeof (struct peer)),
VTY_NEWLINE);
-
+
if ((ents = listcount (bgp->rsclient)))
vty_out (vty, "RS-Client peers %ld, using %s of memory%s",
ents,
mtype_memstr (memstrbuf, sizeof (memstrbuf),
ents * sizeof (struct peer)),
VTY_NEWLINE);
-
+
if ((ents = listcount (bgp->group)))
vty_out (vty, "Peer groups %ld, using %s of memory%s", ents,
mtype_memstr (memstrbuf, sizeof (memstrbuf),
@@ -6743,7 +6743,7 @@ bgp_show_summary (struct vty *vty, struct bgp *bgp, int afi, int safi)
vty_out (vty, "%s", VTY_NEWLINE);
vty_out (vty, "%s%s", header, VTY_NEWLINE);
}
-
+
count++;
len = vty_out (vty, "%s", peer->host);
@@ -6764,7 +6764,7 @@ bgp_show_summary (struct vty *vty, struct bgp *bgp, int afi, int safi)
+ peer->dynamic_cap_out,
0, 0, (unsigned long) peer->obuf->count);
- vty_out (vty, "%8s",
+ vty_out (vty, "%8s",
peer_uptime (peer->uptime, timebuf, BGP_UPTIME_LEN));
if (peer->status == Established)
@@ -6794,8 +6794,8 @@ bgp_show_summary (struct vty *vty, struct bgp *bgp, int afi, int safi)
return CMD_SUCCESS;
}
-static int
-bgp_show_summary_vty (struct vty *vty, const char *name,
+static int
+bgp_show_summary_vty (struct vty *vty, const char *name,
afi_t afi, safi_t safi)
{
struct bgp *bgp;
@@ -6803,27 +6803,27 @@ bgp_show_summary_vty (struct vty *vty, const char *name,
if (name)
{
bgp = bgp_lookup_by_name (name);
-
+
if (! bgp)
{
- vty_out (vty, "%% No such BGP instance exist%s", VTY_NEWLINE);
+ vty_out (vty, "%% No such BGP instance exist%s", VTY_NEWLINE);
return CMD_WARNING;
}
bgp_show_summary (vty, bgp, afi, safi);
return CMD_SUCCESS;
}
-
+
bgp = bgp_get_default ();
if (bgp)
- bgp_show_summary (vty, bgp, afi, safi);
-
+ bgp_show_summary (vty, bgp, afi, safi);
+
return CMD_SUCCESS;
}
/* `show ip bgp summary' commands. */
-DEFUN (show_ip_bgp_summary,
+DEFUN (show_ip_bgp_summary,
show_ip_bgp_summary_cmd,
"show ip bgp summary",
SHOW_STR
@@ -6844,10 +6844,10 @@ DEFUN (show_ip_bgp_instance_summary,
"View name\n"
"Summary of BGP neighbor status\n")
{
- return bgp_show_summary_vty (vty, argv[0], AFI_IP, SAFI_UNICAST);
+ return bgp_show_summary_vty (vty, argv[0], AFI_IP, SAFI_UNICAST);
}
-DEFUN (show_ip_bgp_ipv4_summary,
+DEFUN (show_ip_bgp_ipv4_summary,
show_ip_bgp_ipv4_summary_cmd,
"show ip bgp ipv4 (unicast|multicast) summary",
SHOW_STR
@@ -6921,7 +6921,7 @@ DEFUN (show_ip_bgp_vpnv4_rd_summary,
}
#ifdef HAVE_IPV6
-DEFUN (show_bgp_summary,
+DEFUN (show_bgp_summary,
show_bgp_summary_cmd,
"show bgp summary",
SHOW_STR
@@ -6943,7 +6943,7 @@ DEFUN (show_bgp_instance_summary,
return bgp_show_summary_vty (vty, argv[0], AFI_IP6, SAFI_UNICAST);
}
-ALIAS (show_bgp_summary,
+ALIAS (show_bgp_summary,
show_bgp_ipv6_summary_cmd,
"show bgp ipv6 summary",
SHOW_STR
@@ -6962,7 +6962,7 @@ ALIAS (show_bgp_instance_summary,
"Summary of BGP neighbor status\n")
/* old command */
-DEFUN (show_ipv6_bgp_summary,
+DEFUN (show_ipv6_bgp_summary,
show_ipv6_bgp_summary_cmd,
"show ipv6 bgp summary",
SHOW_STR
@@ -6974,7 +6974,7 @@ DEFUN (show_ipv6_bgp_summary,
}
/* old command */
-DEFUN (show_ipv6_mbgp_summary,
+DEFUN (show_ipv6_mbgp_summary,
show_ipv6_mbgp_summary_cmd,
"show ipv6 mbgp summary",
SHOW_STR
@@ -6985,7 +6985,7 @@ DEFUN (show_ipv6_mbgp_summary,
return bgp_show_summary_vty (vty, NULL, AFI_IP6, SAFI_MULTICAST);
}
#endif /* HAVE_IPV6 */
-
+
const char *
afi_safi_print (afi_t afi, safi_t safi)
{
@@ -7136,7 +7136,7 @@ bgp_show_peer_afi (struct vty *vty, struct peer *p, afi_t afi, safi_t safi)
vty_out (vty, "(both)%s", VTY_NEWLINE);
else if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY))
vty_out (vty, "(extended)%s", VTY_NEWLINE);
- else
+ else
vty_out (vty, "(standard)%s", VTY_NEWLINE);
}
if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_DEFAULT_ORIGINATE))
@@ -7153,12 +7153,12 @@ bgp_show_peer_afi (struct vty *vty, struct peer *p, afi_t afi, safi_t safi)
vty_out (vty, " default not sent%s", VTY_NEWLINE);
}
- if (filter->plist[FILTER_IN].name
+ if (filter->plist[FILTER_IN].ref
|| filter->dlist[FILTER_IN].name
|| filter->aslist[FILTER_IN].name
|| filter->map[RMAP_IN].name)
vty_out (vty, " Inbound path policy configured%s", VTY_NEWLINE);
- if (filter->plist[FILTER_OUT].name
+ if (filter->plist[FILTER_OUT].ref
|| filter->dlist[FILTER_OUT].name
|| filter->aslist[FILTER_OUT].name
|| filter->map[RMAP_OUT].name
@@ -7170,15 +7170,15 @@ bgp_show_peer_afi (struct vty *vty, struct peer *p, afi_t afi, safi_t safi)
vty_out (vty, " Export policy for this RS-client configured%s", VTY_NEWLINE);
/* prefix-list */
- if (filter->plist[FILTER_IN].name)
+ if (filter->plist[FILTER_IN].ref)
vty_out (vty, " Incoming update prefix filter list is %s%s%s",
- filter->plist[FILTER_IN].plist ? "*" : "",
- filter->plist[FILTER_IN].name,
+ prefix_list_ref_plist(filter->plist[FILTER_IN].ref) ? "*" : "",
+ prefix_list_ref_name(filter->plist[FILTER_IN].ref),
VTY_NEWLINE);
- if (filter->plist[FILTER_OUT].name)
+ if (filter->plist[FILTER_OUT].ref)
vty_out (vty, " Outgoing update prefix filter list is %s%s%s",
- filter->plist[FILTER_OUT].plist ? "*" : "",
- filter->plist[FILTER_OUT].name,
+ prefix_list_ref_plist(filter->plist[FILTER_OUT].ref) ? "*" : "",
+ prefix_list_ref_name(filter->plist[FILTER_OUT].ref),
VTY_NEWLINE);
/* distribute-list */
@@ -7277,7 +7277,7 @@ bgp_show_peer (struct vty *vty, struct peer *p)
/* Description. */
if (p->desc)
vty_out (vty, " Description: %s%s", p->desc, VTY_NEWLINE);
-
+
/* Peer-group */
if (p->group)
vty_out (vty, " Member of peer-group %s for session parameters%s",
@@ -7289,7 +7289,7 @@ bgp_show_peer (struct vty *vty, struct peer *p)
/* BGP Version. */
vty_out (vty, " BGP version 4");
- vty_out (vty, ", remote router ID %s%s",
+ vty_out (vty, ", remote router ID %s%s",
inet_ntop (AF_INET, &p->remote_id, buf1, BUFSIZ),
VTY_NEWLINE);
@@ -7297,22 +7297,22 @@ bgp_show_peer (struct vty *vty, struct peer *p)
if (CHECK_FLAG (bgp->config, BGP_CONFIG_CONFEDERATION)
&& bgp_confederation_peers_check (bgp, p->as))
vty_out (vty, " Neighbor under common administration%s", VTY_NEWLINE);
-
+
/* Status. */
- vty_out (vty, " BGP state = %s",
+ vty_out (vty, " BGP state = %s",
LOOKUP (bgp_status_msg, p->status));
- if (p->status == Established)
- vty_out (vty, ", up for %8s",
+ if (p->status == Established)
+ vty_out (vty, ", up for %8s",
peer_uptime (p->uptime, timebuf, BGP_UPTIME_LEN));
else if (p->status == Active)
{
if (CHECK_FLAG (p->flags, PEER_FLAG_PASSIVE))
- vty_out (vty, " (passive)");
+ vty_out (vty, " (passive)");
else if (CHECK_FLAG (p->sflags, PEER_STATUS_NSF_WAIT))
- vty_out (vty, " (NSF passive)");
+ vty_out (vty, " (NSF passive)");
}
vty_out (vty, "%s", VTY_NEWLINE);
-
+
/* read timer */
vty_out (vty, " Last read %s", peer_uptime (p->readtime, timebuf, BGP_UPTIME_LEN));
@@ -7327,7 +7327,7 @@ bgp_show_peer (struct vty *vty, struct peer *p)
}
/* Capability. */
- if (p->status == Established)
+ if (p->status == Established)
{
if (p->cap
|| p->afc_adv[AFI_IP][SAFI_UNICAST]
@@ -7395,12 +7395,12 @@ bgp_show_peer (struct vty *vty, struct peer *p)
if (p->afc_adv[afi][safi] || p->afc_recv[afi][safi])
{
vty_out (vty, " Address family %s:", afi_safi_print (afi, safi));
- if (p->afc_adv[afi][safi])
+ if (p->afc_adv[afi][safi])
vty_out (vty, " advertised");
if (p->afc_recv[afi][safi])
vty_out (vty, " %sreceived", p->afc_adv[afi][safi] ? "and " : "");
vty_out (vty, "%s", VTY_NEWLINE);
- }
+ }
/* Gracefull Restart */
if (CHECK_FLAG (p->cap, PEER_CAP_RESTART_RCV)
@@ -7419,7 +7419,7 @@ bgp_show_peer (struct vty *vty, struct peer *p)
int restart_af_count = 0;
vty_out (vty, " Remote Restart timer is %d seconds%s",
- p->v_gr_restart, VTY_NEWLINE);
+ p->v_gr_restart, VTY_NEWLINE);
vty_out (vty, " Address families by peer:%s ", VTY_NEWLINE);
for (afi = AFI_IP ; afi < AFI_MAX ; afi++)
@@ -7449,7 +7449,7 @@ bgp_show_peer (struct vty *vty, struct peer *p)
int eor_receive_af_count = 0;
vty_out (vty, " Graceful restart informations:%s", VTY_NEWLINE);
- if (p->status == Established)
+ if (p->status == Established)
{
vty_out (vty, " End-of-RIB send: ");
for (afi = AFI_IP ; afi < AFI_MAX ; afi++)
@@ -7477,7 +7477,7 @@ bgp_show_peer (struct vty *vty, struct peer *p)
if (p->t_gr_restart)
vty_out (vty, " The remaining time of restart timer is %ld%s",
thread_timer_remain_second (p->t_gr_restart), VTY_NEWLINE);
-
+
if (p->t_gr_stale)
vty_out (vty, " The remaining time of stalepath timer is %ld%s",
thread_timer_remain_second (p->t_gr_stale), VTY_NEWLINE);
@@ -7565,7 +7565,7 @@ bgp_show_peer (struct vty *vty, struct peer *p)
ntohs (p->su_local->sin.sin_port),
VTY_NEWLINE);
}
-
+
/* Remote address. */
if (p->su_remote)
{
@@ -7578,11 +7578,11 @@ bgp_show_peer (struct vty *vty, struct peer *p)
/* Nexthop display. */
if (p->su_local)
{
- vty_out (vty, "Nexthop: %s%s",
+ vty_out (vty, "Nexthop: %s%s",
inet_ntop (AF_INET, &p->nexthop.v4, buf1, BUFSIZ),
VTY_NEWLINE);
#ifdef HAVE_IPV6
- vty_out (vty, "Nexthop global: %s%s",
+ vty_out (vty, "Nexthop global: %s%s",
inet_ntop (AF_INET6, &p->nexthop.v6_global, buf1, BUFSIZ),
VTY_NEWLINE);
vty_out (vty, "Nexthop local: %s%s",
@@ -7601,8 +7601,8 @@ bgp_show_peer (struct vty *vty, struct peer *p)
if (p->t_connect)
vty_out (vty, "Next connect timer due in %ld seconds%s",
thread_timer_remain_second (p->t_connect), VTY_NEWLINE);
-
- vty_out (vty, "Read thread: %s Write thread: %s%s",
+
+ vty_out (vty, "Read thread: %s Write thread: %s%s",
p->t_read ? "on" : "off",
p->t_write ? "on" : "off",
VTY_NEWLINE);
@@ -7610,7 +7610,7 @@ bgp_show_peer (struct vty *vty, struct peer *p)
if (p->notify.code == BGP_NOTIFY_OPEN_ERR
&& p->notify.subcode == BGP_NOTIFY_OPEN_UNSUP_CAPBL)
bgp_capability_vty_out (vty, p);
-
+
vty_out (vty, "%s", VTY_NEWLINE);
}
@@ -7641,12 +7641,12 @@ bgp_show_neighbor (struct vty *vty, struct bgp *bgp,
if (type == show_peer && ! find)
vty_out (vty, "%% No such neighbor%s", VTY_NEWLINE);
-
+
return CMD_SUCCESS;
}
-static int
-bgp_show_neighbor_vty (struct vty *vty, const char *name,
+static int
+bgp_show_neighbor_vty (struct vty *vty, const char *name,
enum show_type type, const char *ip_str)
{
int ret;
@@ -7666,10 +7666,10 @@ bgp_show_neighbor_vty (struct vty *vty, const char *name,
if (name)
{
bgp = bgp_lookup_by_name (name);
-
+
if (! bgp)
{
- vty_out (vty, "%% No such BGP instance exist%s", VTY_NEWLINE);
+ vty_out (vty, "%% No such BGP instance exist%s", VTY_NEWLINE);
return CMD_WARNING;
}
@@ -7881,11 +7881,11 @@ ALIAS (show_ip_bgp_instance_neighbors_peer,
"Detailed information on TCP and BGP neighbor connections\n"
"Neighbor to display information about\n"
"Neighbor to display information about\n")
-
+
/* Show BGP's AS paths internal data. There are both `show ip bgp
paths' and `show ip mbgp paths'. Those functions results are the
same.*/
-DEFUN (show_ip_bgp_paths,
+DEFUN (show_ip_bgp_paths,
show_ip_bgp_paths_cmd,
"show ip bgp paths",
SHOW_STR
@@ -7898,7 +7898,7 @@ DEFUN (show_ip_bgp_paths,
return CMD_SUCCESS;
}
-DEFUN (show_ip_bgp_ipv4_paths,
+DEFUN (show_ip_bgp_ipv4_paths,
show_ip_bgp_ipv4_paths_cmd,
"show ip bgp ipv4 (unicast|multicast) paths",
SHOW_STR
@@ -7914,7 +7914,7 @@ DEFUN (show_ip_bgp_ipv4_paths,
return CMD_SUCCESS;
}
-
+
#include "hash.h"
static void
@@ -7928,7 +7928,7 @@ community_show_all_iterator (struct hash_backet *backet, struct vty *vty)
}
/* Show BGP's community internal data. */
-DEFUN (show_ip_bgp_community_info,
+DEFUN (show_ip_bgp_community_info,
show_ip_bgp_community_info_cmd,
"show ip bgp community-info",
SHOW_STR
@@ -7938,7 +7938,7 @@ DEFUN (show_ip_bgp_community_info,
{
vty_out (vty, "Address Refcnt Community%s", VTY_NEWLINE);
- hash_iterate (community_hash (),
+ hash_iterate (community_hash (),
(void (*) (struct hash_backet *, void *))
community_show_all_iterator,
vty);
@@ -7946,7 +7946,7 @@ DEFUN (show_ip_bgp_community_info,
return CMD_SUCCESS;
}
-DEFUN (show_ip_bgp_attr_info,
+DEFUN (show_ip_bgp_attr_info,
show_ip_bgp_attr_info_cmd,
"show ip bgp attribute-info",
SHOW_STR
@@ -7957,7 +7957,7 @@ DEFUN (show_ip_bgp_attr_info,
attr_show_all (vty);
return CMD_SUCCESS;
}
-
+
static int
bgp_write_rsclient_summary (struct vty *vty, struct peer *rsclient,
afi_t afi, safi_t safi)
@@ -8027,7 +8027,7 @@ bgp_write_rsclient_summary (struct vty *vty, struct peer *rsclient,
}
static int
-bgp_show_rsclient_summary (struct vty *vty, struct bgp *bgp,
+bgp_show_rsclient_summary (struct vty *vty, struct bgp *bgp,
afi_t afi, safi_t safi)
{
struct peer *peer;
@@ -8070,7 +8070,7 @@ bgp_show_rsclient_summary (struct vty *vty, struct bgp *bgp,
}
static int
-bgp_show_rsclient_summary_vty (struct vty *vty, const char *name,
+bgp_show_rsclient_summary_vty (struct vty *vty, const char *name,
afi_t afi, safi_t safi)
{
struct bgp *bgp;
@@ -8207,7 +8207,7 @@ ALIAS (show_bgp_instance_rsclient_summary,
"Information about Route Server Clients\n"
"Summary of all Route Server Clients\n")
#endif /* HAVE IPV6 */
-
+
/* Redistribute VTY commands. */
/* Utility function to convert user input route type string to route
@@ -8498,7 +8498,7 @@ ALIAS (no_bgp_redistribute_ipv4_rmap_metric,
"Default metric\n"
"Route map reference\n"
"Pointer to route-map entries\n")
-
+
#ifdef HAVE_IPV6
DEFUN (bgp_redistribute_ipv6,
bgp_redistribute_ipv6_cmd,
@@ -8753,7 +8753,7 @@ ALIAS (no_bgp_redistribute_ipv6_rmap_metric,
"Route map reference\n"
"Pointer to route-map entries\n")
#endif /* HAVE_IPV6 */
-
+
int
bgp_config_write_redistribute (struct vty *vty, struct bgp *bgp, afi_t afi,
safi_t safi, int *write)
@@ -8786,7 +8786,7 @@ bgp_config_write_redistribute (struct vty *vty, struct bgp *bgp, afi_t afi,
}
return *write;
}
-
+
/* BGP node structure. */
static struct cmd_node bgp_node =
{
@@ -8829,7 +8829,7 @@ static struct cmd_node bgp_vpnv4_node =
"%s(config-router-af)# ",
1
};
-
+
static void community_list_vty (void);
void
@@ -8850,7 +8850,7 @@ bgp_vty_init (void)
install_default (BGP_IPV6_NODE);
install_default (BGP_IPV6M_NODE);
install_default (BGP_VPNV4_NODE);
-
+
/* "bgp multiple-instance" commands. */
install_element (CONFIG_NODE, &bgp_multiple_instance_cmd);
install_element (CONFIG_NODE, &no_bgp_multiple_instance_cmd);
@@ -8903,7 +8903,7 @@ bgp_vty_init (void)
/* "bgp always-compare-med" commands */
install_element (BGP_NODE, &bgp_always_compare_med_cmd);
install_element (BGP_NODE, &no_bgp_always_compare_med_cmd);
-
+
/* "bgp deterministic-med" commands */
install_element (BGP_NODE, &bgp_deterministic_med_cmd);
install_element (BGP_NODE, &no_bgp_deterministic_med_cmd);
@@ -8914,7 +8914,7 @@ bgp_vty_init (void)
install_element (BGP_NODE, &bgp_graceful_restart_stalepath_time_cmd);
install_element (BGP_NODE, &no_bgp_graceful_restart_stalepath_time_cmd);
install_element (BGP_NODE, &no_bgp_graceful_restart_stalepath_time_val_cmd);
-
+
/* "bgp fast-external-failover" commands */
install_element (BGP_NODE, &bgp_fast_external_failover_cmd);
install_element (BGP_NODE, &no_bgp_fast_external_failover_cmd);
@@ -8950,7 +8950,7 @@ bgp_vty_init (void)
/* "no bgp default ipv4-unicast" commands. */
install_element (BGP_NODE, &no_bgp_default_ipv4_unicast_cmd);
install_element (BGP_NODE, &bgp_default_ipv4_unicast_cmd);
-
+
/* "bgp network import-check" commands. */
install_element (BGP_NODE, &bgp_network_import_check_cmd);
install_element (BGP_NODE, &no_bgp_network_import_check_cmd);
@@ -9004,7 +9004,7 @@ bgp_vty_init (void)
install_element (BGP_IPV6_NODE, &neighbor_set_peer_group_cmd);
install_element (BGP_IPV6M_NODE, &neighbor_set_peer_group_cmd);
install_element (BGP_VPNV4_NODE, &neighbor_set_peer_group_cmd);
-
+
/* "no neighbor peer-group unset" commands. */
install_element (BGP_NODE, &no_neighbor_set_peer_group_cmd);
install_element (BGP_IPV4_NODE, &no_neighbor_set_peer_group_cmd);
@@ -9012,7 +9012,7 @@ bgp_vty_init (void)
install_element (BGP_IPV6_NODE, &no_neighbor_set_peer_group_cmd);
install_element (BGP_IPV6M_NODE, &no_neighbor_set_peer_group_cmd);
install_element (BGP_VPNV4_NODE, &no_neighbor_set_peer_group_cmd);
-
+
/* "neighbor softreconfiguration inbound" commands.*/
install_element (BGP_NODE, &neighbor_soft_reconfiguration_cmd);
install_element (BGP_NODE, &no_neighbor_soft_reconfiguration_cmd);
@@ -9434,7 +9434,7 @@ bgp_vty_init (void)
install_element (BGP_IPV6M_NODE, &neighbor_unsuppress_map_cmd);
install_element (BGP_IPV6M_NODE, &no_neighbor_unsuppress_map_cmd);
install_element (BGP_VPNV4_NODE, &neighbor_unsuppress_map_cmd);
- install_element (BGP_VPNV4_NODE, &no_neighbor_unsuppress_map_cmd);
+ install_element (BGP_VPNV4_NODE, &no_neighbor_unsuppress_map_cmd);
/* "neighbor maximum-prefix" commands. */
install_element (BGP_NODE, &neighbor_maximum_prefix_cmd);
@@ -9913,16 +9913,16 @@ bgp_vty_init (void)
install_element (VIEW_NODE, &show_bgp_memory_cmd);
install_element (RESTRICTED_NODE, &show_bgp_memory_cmd);
install_element (ENABLE_NODE, &show_bgp_memory_cmd);
-
+
/* "show bgp views" commands. */
install_element (VIEW_NODE, &show_bgp_views_cmd);
install_element (RESTRICTED_NODE, &show_bgp_views_cmd);
install_element (ENABLE_NODE, &show_bgp_views_cmd);
-
+
/* Community-list. */
community_list_vty ();
}
-
+
#include "memory.h"
#include "bgp_regex.h"
#include "bgp_clist.h"
@@ -9968,7 +9968,7 @@ community_list_perror (struct vty *vty, int ret)
/* VTY interface for community_set() function. */
static int
-community_list_set_vty (struct vty *vty, int argc, const char **argv,
+community_list_set_vty (struct vty *vty, int argc, const char **argv,
int style, int reject_all_digit_name)
{
int ret;
@@ -10249,20 +10249,21 @@ community_list_show (struct vty *vty, struct community_list *list)
{
struct community_entry *entry;
+ const char* list_name = symbol_get_name(list->sym) ;
for (entry = list->head; entry; entry = entry->next)
{
if (entry == list->head)
{
- if (all_digit (list->name))
+ if (all_digit (list_name))
vty_out (vty, "Community %s list %s%s",
entry->style == COMMUNITY_LIST_STANDARD ?
"standard" : "(expanded) access",
- list->name, VTY_NEWLINE);
+ list_name, VTY_NEWLINE);
else
vty_out (vty, "Named Community %s list %s%s",
entry->style == COMMUNITY_LIST_STANDARD ?
"standard" : "expanded",
- list->name, VTY_NEWLINE);
+ list_name, VTY_NEWLINE);
}
if (entry->any)
vty_out (vty, " %s%s",
@@ -10283,18 +10284,21 @@ DEFUN (show_ip_community_list,
IP_STR
"List community-list\n")
{
- struct community_list *list;
- struct community_list_master *cm;
+ struct symbol_table* table;
+ vector extract ;
+ vector_index i ;
+ struct symbol* sym ;
- cm = community_list_master_lookup (bgp_clist, COMMUNITY_LIST_MASTER);
- if (! cm)
+ table = community_list_master_lookup (bgp_clist, COMMUNITY_LIST_MASTER);
+ if (table == NULL)
return CMD_SUCCESS;
- for (list = cm->num.head; list; list = list->next)
- community_list_show (vty, list);
+ extract = symbol_table_extract(table, NULL, NULL, 0, symbol_mixed_name_cmp) ;
- for (list = cm->str.head; list; list = list->next)
- community_list_show (vty, list);
+ for (VECTOR_ITEMS(extract, sym, i))
+ community_list_show (vty, symbol_get_value(sym));
+
+ vector_free(extract) ; /* discard temporary vector */
return CMD_SUCCESS;
}
@@ -10313,7 +10317,7 @@ DEFUN (show_ip_community_list_arg,
list = community_list_lookup (bgp_clist, argv[0], COMMUNITY_LIST_MASTER);
if (! list)
{
- vty_out (vty, "%% Can't find communit-list%s", VTY_NEWLINE);
+ vty_out (vty, "%% Can't find community-list%s", VTY_NEWLINE);
return CMD_WARNING;
}
@@ -10321,9 +10325,9 @@ DEFUN (show_ip_community_list_arg,
return CMD_SUCCESS;
}
-
+
static int
-extcommunity_list_set_vty (struct vty *vty, int argc, const char **argv,
+extcommunity_list_set_vty (struct vty *vty, int argc, const char **argv,
int style, int reject_all_digit_name)
{
int ret;
@@ -10599,20 +10603,22 @@ extcommunity_list_show (struct vty *vty, struct community_list *list)
{
struct community_entry *entry;
+ const char* list_name = symbol_get_name(list->sym) ;
+
for (entry = list->head; entry; entry = entry->next)
{
if (entry == list->head)
{
- if (all_digit (list->name))
+ if (all_digit (list_name))
vty_out (vty, "Extended community %s list %s%s",
entry->style == EXTCOMMUNITY_LIST_STANDARD ?
"standard" : "(expanded) access",
- list->name, VTY_NEWLINE);
+ list_name, VTY_NEWLINE);
else
vty_out (vty, "Named extended community %s list %s%s",
entry->style == EXTCOMMUNITY_LIST_STANDARD ?
"standard" : "expanded",
- list->name, VTY_NEWLINE);
+ list_name, VTY_NEWLINE);
}
if (entry->any)
vty_out (vty, " %s%s",
@@ -10633,18 +10639,21 @@ DEFUN (show_ip_extcommunity_list,
IP_STR
"List extended-community list\n")
{
- struct community_list *list;
- struct community_list_master *cm;
+ struct symbol_table* table;
+ vector extract ;
+ vector_index i ;
+ struct symbol* sym ;
- cm = community_list_master_lookup (bgp_clist, EXTCOMMUNITY_LIST_MASTER);
- if (! cm)
+ table = community_list_master_lookup (bgp_clist, EXTCOMMUNITY_LIST_MASTER);
+ if (table == NULL)
return CMD_SUCCESS;
- for (list = cm->num.head; list; list = list->next)
- extcommunity_list_show (vty, list);
+ extract = symbol_table_extract(table, NULL, NULL, 0, symbol_mixed_name_cmp) ;
+
+ for (VECTOR_ITEMS(extract, sym, i))
+ extcommunity_list_show (vty, symbol_get_value(sym));
- for (list = cm->str.head; list; list = list->next)
- extcommunity_list_show (vty, list);
+ vector_free(extract) ; /* discard temporary vector */
return CMD_SUCCESS;
}
@@ -10663,7 +10672,7 @@ DEFUN (show_ip_extcommunity_list_arg,
list = community_list_lookup (bgp_clist, argv[0], EXTCOMMUNITY_LIST_MASTER);
if (! list)
{
- vty_out (vty, "%% Can't find extcommunit-list%s", VTY_NEWLINE);
+ vty_out (vty, "%% Can't find extcommunity-list%s", VTY_NEWLINE);
return CMD_WARNING;
}
@@ -10671,7 +10680,7 @@ DEFUN (show_ip_extcommunity_list_arg,
return CMD_SUCCESS;
}
-
+
/* Return configuration string of community-list entry. */
static const char *
community_list_config_str (struct community_entry *entry)
@@ -10690,60 +10699,76 @@ community_list_config_str (struct community_entry *entry)
return str;
}
-/* Display community-list and extcommunity-list configuration. */
+/* Put entire community-list or extcommunity-list. */
static int
-community_list_config_write (struct vty *vty)
+community_list_config_write_list(struct vty* vty, int what)
{
+ struct symbol_table* table;
struct community_list *list;
struct community_entry *entry;
- struct community_list_master *cm;
+ vector extract ;
+ vector_index i ;
+ struct symbol* sym ;
+
int write = 0;
- /* Community-list. */
- cm = community_list_master_lookup (bgp_clist, COMMUNITY_LIST_MASTER);
-
- for (list = cm->num.head; list; list = list->next)
- for (entry = list->head; entry; entry = entry->next)
- {
- vty_out (vty, "ip community-list %s %s %s%s",
- list->name, community_direct_str (entry->direct),
- community_list_config_str (entry),
- VTY_NEWLINE);
- write++;
- }
- for (list = cm->str.head; list; list = list->next)
- for (entry = list->head; entry; entry = entry->next)
- {
- vty_out (vty, "ip community-list %s %s %s %s%s",
- entry->style == COMMUNITY_LIST_STANDARD
- ? "standard" : "expanded",
- list->name, community_direct_str (entry->direct),
- community_list_config_str (entry),
- VTY_NEWLINE);
- write++;
- }
+ table = community_list_master_lookup (bgp_clist, what);
+
+ extract = symbol_table_extract(table, NULL, NULL, 0, symbol_mixed_name_cmp) ;
+ for (VECTOR_ITEMS(extract, sym, i))
+ {
+ list = symbol_get_value(sym) ;
+ for (entry = list->head; entry; entry = entry->next)
+ {
+ const char* list_type = "" ;
+ const char* list_style = "" ;
+ const char* list_name = symbol_get_name(list->sym) ;
+
+ switch (entry->style)
+ {
+ case COMMUNITY_LIST_STANDARD:
+ list_type = "community-list" ;
+ list_style = "standard " ;
+ break ;
+ case COMMUNITY_LIST_EXPANDED:
+ list_type = "community-list" ;
+ list_style = "expanded " ;
+ break ;
+ case EXTCOMMUNITY_LIST_STANDARD:
+ list_type = "extcommunity-list" ;
+ list_style = "standard " ;
+ break ;
+ case EXTCOMMUNITY_LIST_EXPANDED:
+ list_type = "extcommunity-list" ;
+ list_style = "expanded " ;
+ break ;
+ } ;
+ if (all_digit(list_name))
+ list_style = "" ; /* squash style for all digit names */
+
+ vty_out (vty, "ip %s %s%s %s %s%s",
+ list_type, list_style, list_name,
+ community_direct_str (entry->direct),
+ community_list_config_str (entry),
+ VTY_NEWLINE);
+ write++;
+ }
+ }
+
+ vector_free(extract) ; /* discard temporary vector */
+
+ return write;
+}
+
+/* Display community-list and extcommunity-list configuration. */
+static int
+community_list_config_write (struct vty *vty)
+{
+ int write = 0;
+
+ write += community_list_config_write_list(vty, COMMUNITY_LIST_MASTER) ;
+ write += community_list_config_write_list(vty, EXTCOMMUNITY_LIST_MASTER);
- /* Extcommunity-list. */
- cm = community_list_master_lookup (bgp_clist, EXTCOMMUNITY_LIST_MASTER);
-
- for (list = cm->num.head; list; list = list->next)
- for (entry = list->head; entry; entry = entry->next)
- {
- vty_out (vty, "ip extcommunity-list %s %s %s%s",
- list->name, community_direct_str (entry->direct),
- community_list_config_str (entry), VTY_NEWLINE);
- write++;
- }
- for (list = cm->str.head; list; list = list->next)
- for (entry = list->head; entry; entry = entry->next)
- {
- vty_out (vty, "ip extcommunity-list %s %s %s %s%s",
- entry->style == EXTCOMMUNITY_LIST_STANDARD
- ? "standard" : "expanded",
- list->name, community_direct_str (entry->direct),
- community_list_config_str (entry), VTY_NEWLINE);
- write++;
- }
return write;
}
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index b34f996b..600abf1c 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -60,7 +60,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#ifdef HAVE_SNMP
#include "bgpd/bgp_snmp.h"
#endif /* HAVE_SNMP */
-
+
/* BGP process wide configuration. */
static struct bgp_master bgp_master;
@@ -71,7 +71,7 @@ struct bgp_master *bm;
/* BGP community-list. */
struct community_list_handler *bgp_clist;
-
+
/* BGP global flag manipulation. */
int
bgp_option_set (int flag)
@@ -113,7 +113,7 @@ bgp_option_check (int flag)
{
return CHECK_FLAG (bm->options, flag);
}
-
+
/* BGP flag manipulation. */
int
bgp_flag_set (struct bgp *bgp, int flag)
@@ -134,7 +134,7 @@ bgp_flag_check (struct bgp *bgp, int flag)
{
return CHECK_FLAG (bgp->flags, flag);
}
-
+
/* Internal function to set BGP structure configureation flag. */
static void
bgp_config_set (struct bgp *bgp, int config)
@@ -153,7 +153,7 @@ bgp_config_check (struct bgp *bgp, int config)
{
return CHECK_FLAG (bgp->config, config);
}
-
+
/* Set BGP router identifier. */
int
bgp_router_id_set (struct bgp *bgp, struct in_addr *id)
@@ -240,12 +240,12 @@ bgp_cluster_id_unset (struct bgp *bgp)
}
return 0;
}
-
+
/* BGP timer configuration. */
int
bgp_timers_set (struct bgp *bgp, u_int32_t keepalive, u_int32_t holdtime)
{
- bgp->default_keepalive = (keepalive < holdtime / 3
+ bgp->default_keepalive = (keepalive < holdtime / 3
? keepalive : holdtime / 3);
bgp->default_holdtime = holdtime;
@@ -260,7 +260,7 @@ bgp_timers_unset (struct bgp *bgp)
return 0;
}
-
+
/* BGP confederation configuration. */
int
bgp_confederation_id_set (struct bgp *bgp, as_t as)
@@ -331,7 +331,7 @@ bgp_confederation_id_unset (struct bgp *bgp)
bgp->confed_id = 0;
bgp_config_unset (bgp, BGP_CONFIG_CONFEDERATION);
-
+
for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
{
/* We're looking for peers who's AS is not local */
@@ -364,7 +364,7 @@ bgp_confederation_peers_check (struct bgp *bgp, as_t as)
for (i = 0; i < bgp->confed_peers_cnt; i++)
if (bgp->confed_peers[i] == as)
return 1;
-
+
return 0;
}
@@ -385,11 +385,11 @@ bgp_confederation_peers_add (struct bgp *bgp, as_t as)
return -1;
if (bgp->confed_peers)
- bgp->confed_peers = XREALLOC (MTYPE_BGP_CONFED_LIST,
+ bgp->confed_peers = XREALLOC (MTYPE_BGP_CONFED_LIST,
bgp->confed_peers,
(bgp->confed_peers_cnt + 1) * sizeof (as_t));
else
- bgp->confed_peers = XMALLOC (MTYPE_BGP_CONFED_LIST,
+ bgp->confed_peers = XMALLOC (MTYPE_BGP_CONFED_LIST,
(bgp->confed_peers_cnt + 1) * sizeof (as_t));
bgp->confed_peers[bgp->confed_peers_cnt] = as;
@@ -472,7 +472,7 @@ bgp_confederation_peers_remove (struct bgp *bgp, as_t as)
return 0;
}
-
+
/* Local preference configuration. */
int
bgp_default_local_preference_set (struct bgp *bgp, u_int32_t local_pref)
@@ -495,7 +495,7 @@ bgp_default_local_preference_unset (struct bgp *bgp)
return 0;
}
-
+
/* If peer is RSERVER_CLIENT in at least one address family and is not member
of a peer_group for that family, return 1.
Used to check wether the peer is included in list bgp->rsclient. */
@@ -544,11 +544,7 @@ peer_af_flag_reset (struct peer *peer, afi_t afi, safi_t safi)
free (filter->dlist[i].name);
filter->dlist[i].name = NULL;
}
- if (filter->plist[i].name)
- {
- free (filter->plist[i].name);
- filter->plist[i].name = NULL;
- }
+ prefix_list_unset_ref(&filter->plist[i].ref) ;
if (filter->aslist[i].name)
{
free (filter->aslist[i].name);
@@ -651,9 +647,9 @@ peer_sort (struct peer *peer)
struct peer *peer1;
peer1 = listnode_head (peer->group->peer);
if (peer1)
- return (peer1->local_as == peer1->as
+ return (peer1->local_as == peer1->as
? BGP_PEER_IBGP : BGP_PEER_EBGP);
- }
+ }
return BGP_PEER_INTERNAL;
}
@@ -692,44 +688,44 @@ peer_free (struct peer *peer)
bgp_unlock(peer->bgp);
/* this /ought/ to have been done already through bgp_stop earlier,
- * but just to be sure..
+ * but just to be sure..
*/
bgp_timer_set (peer);
BGP_READ_OFF (peer->t_read);
BGP_WRITE_OFF (peer->t_write);
BGP_EVENT_FLUSH (peer);
-
+
if (peer->desc)
XFREE (MTYPE_PEER_DESC, peer->desc);
-
+
/* Free allocated host character. */
if (peer->host)
XFREE (MTYPE_BGP_PEER_HOST, peer->host);
-
+
/* Update source configuration. */
if (peer->update_source)
sockunion_free (peer->update_source);
-
+
if (peer->update_if)
XFREE (MTYPE_PEER_UPDATE_SOURCE, peer->update_if);
-
+
if (peer->clear_node_queue)
work_queue_free (peer->clear_node_queue);
-
+
bgp_sync_delete (peer);
memset (peer, 0, sizeof (struct peer));
-
+
XFREE (MTYPE_BGP_PEER, peer);
}
-
+
/* increase reference count on a struct peer */
struct peer *
peer_lock (struct peer *peer)
{
assert (peer && (peer->lock >= 0));
-
+
peer->lock++;
-
+
return peer;
}
@@ -740,9 +736,9 @@ struct peer *
peer_unlock (struct peer *peer)
{
assert (peer && (peer->lock > 0));
-
+
peer->lock--;
-
+
if (peer->lock == 0)
{
#if 0
@@ -763,7 +759,7 @@ peer_unlock (struct peer *peer)
return peer;
}
-
+
/* Allocate new peer object, implicitely locked. */
static struct peer *
peer_new (struct bgp *bgp)
@@ -772,12 +768,12 @@ peer_new (struct bgp *bgp)
safi_t safi;
struct peer *peer;
struct servent *sp;
-
+
/* bgp argument is absolutely required */
assert (bgp);
if (!bgp)
return NULL;
-
+
/* Allocate new peer. */
peer = XCALLOC (MTYPE_BGP_PEER, sizeof (struct peer));
@@ -841,7 +837,7 @@ peer_create (union sockunion *su, struct bgp *bgp, as_t local_as,
peer->v_routeadv = BGP_DEFAULT_IBGP_ROUTEADV;
else
peer->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV;
-
+
peer = peer_lock (peer); /* bgp peer list reference */
listnode_add_sort (bgp->peer, peer);
@@ -877,7 +873,7 @@ peer_create_accept (struct bgp *bgp)
struct peer *peer;
peer = peer_new (bgp);
-
+
peer = peer_lock (peer); /* bgp peer list reference */
listnode_add_sort (bgp->peer, peer);
@@ -997,20 +993,20 @@ peer_remote_as (struct bgp *bgp, union sockunion *su, as_t *as,
/* If the peer is not part of our confederation, and its not an
iBGP peer then spoof the source AS */
if (bgp_config_check (bgp, BGP_CONFIG_CONFEDERATION)
- && ! bgp_confederation_peers_check (bgp, *as)
+ && ! bgp_confederation_peers_check (bgp, *as)
&& bgp->as != *as)
local_as = bgp->confed_id;
else
local_as = bgp->as;
-
+
/* If this is IPv4 unicast configuration and "no bgp default
ipv4-unicast" is specified. */
if (bgp_flag_check (bgp, BGP_FLAG_NO_DEFAULT_IPV4)
&& afi == AFI_IP && safi == SAFI_UNICAST)
- peer = peer_create (su, bgp, local_as, *as, 0, 0);
+ peer = peer_create (su, bgp, local_as, *as, 0, 0);
else
- peer = peer_create (su, bgp, local_as, *as, afi, safi);
+ peer = peer_create (su, bgp, local_as, *as, afi, safi);
}
return 0;
@@ -1095,7 +1091,7 @@ peer_deactivate (struct peer *peer, afi_t afi, safi_t safi)
peer_af_flag_reset (peer, afi, safi);
if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
- {
+ {
if (peer->status == Established)
{
if (CHECK_FLAG (peer->cap, PEER_CAP_DYNAMIC_RCV))
@@ -1179,7 +1175,7 @@ peer_delete (struct peer *peer)
struct listnode *pn;
assert (peer->status != Deleted);
-
+
bgp = peer->bgp;
if (CHECK_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT))
@@ -1196,7 +1192,7 @@ peer_delete (struct peer *peer)
}
peer->group = NULL;
}
-
+
/* Withdraw all information from routing table. We can not use
* BGP_EVENT_ADD (peer, BGP_Stop) at here. Because the event is
* executed after peer structure is deleted.
@@ -1214,9 +1210,9 @@ peer_delete (struct peer *peer)
if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
bgp_md5_set (peer);
}
-
+
bgp_timer_set (peer); /* stops all timers for Deleted */
-
+
/* Delete from all peer list. */
if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)
&& (pn = listnode_lookup (bgp->peer, peer)))
@@ -1224,7 +1220,7 @@ peer_delete (struct peer *peer)
peer_unlock (peer); /* bgp peer list reference */
list_delete_node (bgp->peer, pn);
}
-
+
if (peer_rsclient_active (peer)
&& (pn = listnode_lookup (bgp->rsclient, peer)))
{
@@ -1262,7 +1258,7 @@ peer_delete (struct peer *peer)
if (peer->su_remote)
sockunion_free (peer->su_remote);
peer->su_local = peer->su_remote = NULL;
-
+
/* Free filter related memory. */
for (afi = AFI_IP; afi < AFI_MAX; afi++)
for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
@@ -1273,13 +1269,10 @@ peer_delete (struct peer *peer)
{
if (filter->dlist[i].name)
free (filter->dlist[i].name);
- if (filter->plist[i].name)
- free (filter->plist[i].name);
if (filter->aslist[i].name)
free (filter->aslist[i].name);
-
filter->dlist[i].name = NULL;
- filter->plist[i].name = NULL;
+ prefix_list_unset_ref(&filter->plist[i].ref) ;
filter->aslist[i].name = NULL;
}
for (i = RMAP_IN; i < RMAP_MAX; i++)
@@ -1294,16 +1287,16 @@ peer_delete (struct peer *peer)
if (peer->default_rmap[afi][safi].name)
free (peer->default_rmap[afi][safi].name);
-
+
filter->usmap.name = NULL;
peer->default_rmap[afi][safi].name = NULL;
}
-
+
peer_unlock (peer); /* initial reference */
return 0;
}
-
+
static int
peer_group_cmp (struct peer_group *g1, struct peer_group *g2)
{
@@ -1369,7 +1362,7 @@ peer_group_get (struct bgp *bgp, const char *name)
group->conf->afc[AFI_IP][SAFI_UNICAST] = 1;
group->conf->host = XSTRDUP (MTYPE_BGP_PEER_HOST, name);
group->conf->group = group;
- group->conf->as = 0;
+ group->conf->as = 0;
group->conf->ttl = 1;
group->conf->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV;
UNSET_FLAG (group->conf->config, PEER_CONFIG_TIMER);
@@ -1383,7 +1376,7 @@ peer_group_get (struct bgp *bgp, const char *name)
return 0;
}
-static void
+static void
peer_group2peer_config_copy (struct peer_group *group, struct peer *peer,
afi_t afi, safi_t safi)
{
@@ -1521,13 +1514,8 @@ peer_group2peer_config_copy (struct peer_group *group, struct peer *peer,
pfilter->dlist[in].name = strdup (gfilter->dlist[in].name);
pfilter->dlist[in].alist = gfilter->dlist[in].alist;
}
- if (gfilter->plist[in].name && ! pfilter->plist[in].name)
- {
- if (pfilter->plist[in].name)
- free (pfilter->plist[in].name);
- pfilter->plist[in].name = strdup (gfilter->plist[in].name);
- pfilter->plist[in].plist = gfilter->plist[in].plist;
- }
+ if (! pfilter->plist[in].ref)
+ prefix_list_copy_ref(&pfilter->plist[in].ref, gfilter->plist[in].ref) ;
if (gfilter->aslist[in].name && ! pfilter->aslist[in].name)
{
if (pfilter->aslist[in].name)
@@ -1558,20 +1546,9 @@ peer_group2peer_config_copy (struct peer_group *group, struct peer *peer,
pfilter->dlist[out].name = NULL;
pfilter->dlist[out].alist = NULL;
}
- if (gfilter->plist[out].name)
- {
- if (pfilter->plist[out].name)
- free (pfilter->plist[out].name);
- pfilter->plist[out].name = strdup (gfilter->plist[out].name);
- pfilter->plist[out].plist = gfilter->plist[out].plist;
- }
- else
- {
- if (pfilter->plist[out].name)
- free (pfilter->plist[out].name);
- pfilter->plist[out].name = NULL;
- pfilter->plist[out].plist = NULL;
- }
+
+ prefix_list_copy_ref(&pfilter->plist[out].ref, gfilter->plist[out].ref) ;
+
if (gfilter->aslist[out].name)
{
if (pfilter->aslist[out].name)
@@ -1638,7 +1615,7 @@ peer_group2peer_config_copy (struct peer_group *group, struct peer *peer,
pfilter->usmap.name = NULL;
pfilter->usmap.map = NULL;
}
-}
+}
/* Peer group's remote AS configuration. */
int
@@ -1784,7 +1761,7 @@ peer_group_bind (struct bgp *bgp, union sockunion *su,
if (! peer->group)
{
peer->group = group;
-
+
peer = peer_lock (peer); /* group->peer list reference */
listnode_add (group->peer, peer);
}
@@ -1814,7 +1791,7 @@ peer_group_bind (struct bgp *bgp, union sockunion *su,
if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT))
{
struct listnode *pn;
-
+
/* If it's not configured as RSERVER_CLIENT in any other address
family, without being member of a peer_group, remove it from
list bgp->rsclient.*/
@@ -1904,7 +1881,7 @@ peer_group_unbind (struct bgp *bgp, struct peer *peer,
return 0;
}
-
+
/* BGP instance creation by `router bgp' commands. */
static struct bgp *
bgp_create (as_t *as, const char *name)
@@ -1915,7 +1892,7 @@ bgp_create (as_t *as, const char *name)
if ( (bgp = XCALLOC (MTYPE_BGP, sizeof (struct bgp))) == NULL)
return NULL;
-
+
bgp_lock (bgp);
bgp->peer_self = peer_new (bgp);
bgp->peer_self->host = XSTRDUP (MTYPE_BGP_PEER_HOST, "Static announcement");
@@ -1969,7 +1946,7 @@ bgp_lookup (as_t as, const char *name)
for (ALL_LIST_ELEMENTS (bm->bgp, node, nnode, bgp))
if (bgp->as == as
- && ((bgp->name == NULL && name == NULL)
+ && ((bgp->name == NULL && name == NULL)
|| (bgp->name && name && strcmp (bgp->name, name) == 0)))
return bgp;
return NULL;
@@ -2067,7 +2044,7 @@ bgp_delete (struct bgp *bgp)
/* Unset redistribution. */
for (afi = AFI_IP; afi < AFI_MAX; afi++)
- for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
+ for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
if (i != ZEBRA_ROUTE_BGP)
bgp_redistribute_unset (bgp, afi, i);
@@ -2083,7 +2060,7 @@ bgp_delete (struct bgp *bgp)
peer_delete(bgp->peer_self);
bgp->peer_self = NULL;
}
-
+
/* Remove visibility via the master list - there may however still be
* routes to be processed still referencing the struct bgp.
*/
@@ -2092,7 +2069,7 @@ bgp_delete (struct bgp *bgp)
bgp_close ();
bgp_unlock(bgp); /* initial reference */
-
+
return 0;
}
@@ -2124,7 +2101,7 @@ bgp_free (struct bgp *bgp)
if (bgp->name)
free (bgp->name);
-
+
for (afi = AFI_IP; afi < AFI_MAX; afi++)
for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
{
@@ -2137,7 +2114,7 @@ bgp_free (struct bgp *bgp)
}
XFREE (MTYPE_BGP, bgp);
}
-
+
struct peer *
peer_lookup (struct bgp *bgp, union sockunion *su)
{
@@ -2154,7 +2131,7 @@ peer_lookup (struct bgp *bgp, union sockunion *su)
else if (bm->bgp != NULL)
{
struct listnode *bgpnode, *nbgpnode;
-
+
for (ALL_LIST_ELEMENTS (bm->bgp, bgpnode, nbgpnode, bgp))
for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
if (sockunion_same (&peer->su, su)
@@ -2206,7 +2183,7 @@ peer_lookup_with_open (union sockunion *su, as_t remote_as,
}
return NULL;
}
-
+
/* If peer is configured at least one address family return 1. */
int
peer_active (struct peer *peer)
@@ -2232,7 +2209,7 @@ peer_active_nego (struct peer *peer)
return 1;
return 0;
}
-
+
/* peer_flag_change_type. */
enum peer_change_type
{
@@ -2428,7 +2405,7 @@ peer_flag_modify (struct peer *peer, u_int32_t flag, int set)
/* No flag action is found. */
if (! found)
- return BGP_ERR_INVALID_FLAG;
+ return BGP_ERR_INVALID_FLAG;
/* Not for peer-group member. */
if (action.not_for_member && peer_group_active (peer))
@@ -2463,7 +2440,7 @@ peer_flag_modify (struct peer *peer, u_int32_t flag, int set)
SET_FLAG (peer->flags, flag);
else
UNSET_FLAG (peer->flags, flag);
-
+
if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
{
if (action.type == peer_change_reset)
@@ -2526,12 +2503,12 @@ peer_af_flag_modify (struct peer *peer, afi_t afi, safi_t safi, u_int32_t flag,
memset (&action, 0, sizeof (struct peer_flag_action));
size = sizeof peer_af_flag_action_list / sizeof (struct peer_flag_action);
-
+
found = peer_flag_action_set (peer_af_flag_action_list, size, &action, flag);
-
+
/* No flag action is found. */
if (! found)
- return BGP_ERR_INVALID_FLAG;
+ return BGP_ERR_INVALID_FLAG;
/* Adress family must be activated. */
if (! peer->afc[afi][safi])
@@ -2597,7 +2574,7 @@ peer_af_flag_modify (struct peer *peer, afi_t afi, safi_t safi, u_int32_t flag,
if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
{
group = peer->group;
-
+
for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
{
if (! peer->af_group[afi][safi])
@@ -2648,7 +2625,7 @@ peer_af_flag_unset (struct peer *peer, afi_t afi, safi_t safi, u_int32_t flag)
{
return peer_af_flag_modify (peer, afi, safi, flag, 0);
}
-
+
/* EBGP multihop configuration. */
int
peer_ebgp_multihop_set (struct peer *peer, int ttl)
@@ -2711,14 +2688,14 @@ peer_ebgp_multihop_unset (struct peer *peer)
continue;
peer->ttl = 1;
-
+
if (peer->fd >= 0)
sockopt_ttl (peer->su.sa.sa_family, peer->fd, peer->ttl);
}
}
return 0;
}
-
+
/* Neighbor description. */
int
peer_description_set (struct peer *peer, char *desc)
@@ -2741,7 +2718,7 @@ peer_description_unset (struct peer *peer)
return 0;
}
-
+
/* Neighbor update-source. */
int
peer_update_source_if_set (struct peer *peer, const char *ifname)
@@ -2914,7 +2891,7 @@ peer_update_source_unset (struct peer *peer)
peer->update_source = su;
}
else if (group->conf->update_if)
- peer->update_if =
+ peer->update_if =
XSTRDUP (MTYPE_PEER_UPDATE_SOURCE, group->conf->update_if);
}
@@ -2961,7 +2938,7 @@ peer_update_source_unset (struct peer *peer)
}
return 0;
}
-
+
int
peer_default_originate_set (struct peer *peer, afi_t afi, safi_t safi,
const char *rmap)
@@ -2980,7 +2957,7 @@ peer_default_originate_set (struct peer *peer, afi_t afi, safi_t safi,
if (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_DEFAULT_ORIGINATE)
|| (rmap && ! peer->default_rmap[afi][safi].name)
|| (rmap && strcmp (rmap, peer->default_rmap[afi][safi].name) != 0))
- {
+ {
SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_DEFAULT_ORIGINATE);
if (rmap)
@@ -3034,7 +3011,7 @@ peer_default_originate_unset (struct peer *peer, afi_t afi, safi_t safi)
return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER;
if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_DEFAULT_ORIGINATE))
- {
+ {
UNSET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_DEFAULT_ORIGINATE);
if (peer->default_rmap[afi][safi].name)
@@ -3066,7 +3043,7 @@ peer_default_originate_unset (struct peer *peer, afi_t afi, safi_t safi)
}
return 0;
}
-
+
int
peer_port_set (struct peer *peer, u_int16_t port)
{
@@ -3080,7 +3057,7 @@ peer_port_unset (struct peer *peer)
peer->port = BGP_PORT_DEFAULT;
return 0;
}
-
+
/* neighbor weight. */
int
peer_weight_set (struct peer *peer, u_int16_t weight)
@@ -3128,7 +3105,7 @@ peer_weight_unset (struct peer *peer)
}
return 0;
}
-
+
int
peer_timers_set (struct peer *peer, u_int32_t keepalive, u_int32_t holdtime)
{
@@ -3198,7 +3175,7 @@ peer_timers_unset (struct peer *peer)
return 0;
}
-
+
int
peer_timers_connect_set (struct peer *peer, u_int32_t connect)
{
@@ -3233,7 +3210,7 @@ peer_timers_connect_unset (struct peer *peer)
return 0;
}
-
+
int
peer_advertise_interval_set (struct peer *peer, u_int32_t routeadv)
{
@@ -3263,10 +3240,10 @@ peer_advertise_interval_unset (struct peer *peer)
peer->v_routeadv = BGP_DEFAULT_IBGP_ROUTEADV;
else
peer->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV;
-
+
return 0;
}
-
+
/* neighbor interface */
int
peer_interface_set (struct peer *peer, const char *str)
@@ -3287,7 +3264,7 @@ peer_interface_unset (struct peer *peer)
return 0;
}
-
+
/* Allow-as in. */
int
peer_allowas_in_set (struct peer *peer, afi_t afi, safi_t safi, int allow_num)
@@ -3317,7 +3294,7 @@ peer_allowas_in_set (struct peer *peer, afi_t afi, safi_t safi, int allow_num)
SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ALLOWAS_IN);
peer_change_action (peer, afi, safi, peer_change_reset_in);
}
-
+
}
return 0;
}
@@ -3348,7 +3325,7 @@ peer_allowas_in_unset (struct peer *peer, afi_t afi, safi_t safi)
}
return 0;
}
-
+
int
peer_local_as_set (struct peer *peer, as_t as, int no_prepend)
{
@@ -3459,7 +3436,7 @@ peer_local_as_unset (struct peer *peer)
}
return 0;
}
-
+
/* Set password for authenticating with the peer. */
int
peer_password_set (struct peer *peer, const char *password)
@@ -3477,7 +3454,7 @@ peer_password_set (struct peer *peer, const char *password)
if (peer->password)
XFREE (MTYPE_PEER_PASSWORD, peer->password);
-
+
peer->password = XSTRDUP (MTYPE_PEER_PASSWORD, password);
if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
@@ -3486,7 +3463,7 @@ peer_password_set (struct peer *peer, const char *password)
bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE);
else
BGP_EVENT_ADD (peer, BGP_Stop);
-
+
return (bgp_md5_set (peer) >= 0) ? BGP_SUCCESS : BGP_ERR_TCPSIG_FAILED;
}
@@ -3494,17 +3471,17 @@ peer_password_set (struct peer *peer, const char *password)
{
if (peer->password && strcmp (peer->password, password) == 0)
continue;
-
+
if (peer->password)
XFREE (MTYPE_PEER_PASSWORD, peer->password);
-
+
peer->password = XSTRDUP(MTYPE_PEER_PASSWORD, password);
if (peer->status == Established)
bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE);
else
BGP_EVENT_ADD (peer, BGP_Stop);
-
+
if (bgp_md5_set (peer) < 0)
ret = BGP_ERR_TCPSIG_FAILED;
}
@@ -3535,9 +3512,9 @@ peer_password_unset (struct peer *peer)
if (peer->password)
XFREE (MTYPE_PEER_PASSWORD, peer->password);
-
+
peer->password = NULL;
-
+
bgp_md5_set (peer);
return 0;
@@ -3555,7 +3532,7 @@ peer_password_unset (struct peer *peer)
bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE);
else
BGP_EVENT_ADD (peer, BGP_Stop);
-
+
XFREE (MTYPE_PEER_PASSWORD, peer->password);
peer->password = NULL;
@@ -3564,10 +3541,10 @@ peer_password_unset (struct peer *peer)
return 0;
}
-
+
/* Set distribute list to the peer. */
int
-peer_distribute_set (struct peer *peer, afi_t afi, safi_t safi, int direct,
+peer_distribute_set (struct peer *peer, afi_t afi, safi_t safi, int direct,
const char *name)
{
struct bgp_filter *filter;
@@ -3585,7 +3562,7 @@ peer_distribute_set (struct peer *peer, afi_t afi, safi_t safi, int direct,
filter = &peer->filter[afi][safi];
- if (filter->plist[direct].name)
+ if (filter->plist[direct].ref)
return BGP_ERR_PEER_FILTER_CONFLICT;
if (filter->dlist[direct].name)
@@ -3698,7 +3675,7 @@ peer_distribute_update (struct access_list *access)
for (direct = FILTER_IN; direct < FILTER_MAX; direct++)
{
if (filter->dlist[direct].name)
- filter->dlist[direct].alist =
+ filter->dlist[direct].alist =
access_list_lookup (afi, filter->dlist[direct].name);
else
filter->dlist[direct].alist = NULL;
@@ -3715,7 +3692,7 @@ peer_distribute_update (struct access_list *access)
for (direct = FILTER_IN; direct < FILTER_MAX; direct++)
{
if (filter->dlist[direct].name)
- filter->dlist[direct].alist =
+ filter->dlist[direct].alist =
access_list_lookup (afi, filter->dlist[direct].name);
else
filter->dlist[direct].alist = NULL;
@@ -3724,15 +3701,16 @@ peer_distribute_update (struct access_list *access)
}
}
}
-
+
/* Set prefix list to the peer. */
int
-peer_prefix_list_set (struct peer *peer, afi_t afi, safi_t safi, int direct,
+peer_prefix_list_set (struct peer *peer, afi_t afi, safi_t safi, int direct,
const char *name)
{
struct bgp_filter *filter;
struct peer_group *group;
struct listnode *node, *nnode;
+ prefix_list_ref ref ;
if (! peer->afc[afi][safi])
return BGP_ERR_PEER_INACTIVE;
@@ -3748,10 +3726,7 @@ peer_prefix_list_set (struct peer *peer, afi_t afi, safi_t safi, int direct,
if (filter->dlist[direct].name)
return BGP_ERR_PEER_FILTER_CONFLICT;
- if (filter->plist[direct].name)
- free (filter->plist[direct].name);
- filter->plist[direct].name = strdup (name);
- filter->plist[direct].plist = prefix_list_lookup (afi, name);
+ ref = prefix_list_set_ref(&filter->plist[direct].ref, afi, name) ;
if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
return 0;
@@ -3764,10 +3739,7 @@ peer_prefix_list_set (struct peer *peer, afi_t afi, safi_t safi, int direct,
if (! peer->af_group[afi][safi])
continue;
- if (filter->plist[direct].name)
- free (filter->plist[direct].name);
- filter->plist[direct].name = strdup (name);
- filter->plist[direct].plist = prefix_list_lookup (afi, name);
+ prefix_list_copy_ref(&filter->plist[direct].ref, ref) ;
}
return 0;
}
@@ -3796,20 +3768,15 @@ peer_prefix_list_unset (struct peer *peer, afi_t afi, safi_t safi, int direct)
{
gfilter = &peer->group->conf->filter[afi][safi];
- if (gfilter->plist[direct].name)
+ if (gfilter->plist[direct].ref)
{
- if (filter->plist[direct].name)
- free (filter->plist[direct].name);
- filter->plist[direct].name = strdup (gfilter->plist[direct].name);
- filter->plist[direct].plist = gfilter->plist[direct].plist;
+ prefix_list_copy_ref(&filter->plist[direct].ref,
+ gfilter->plist[direct].ref) ;
return 0;
}
}
- if (filter->plist[direct].name)
- free (filter->plist[direct].name);
- filter->plist[direct].name = NULL;
- filter->plist[direct].plist = NULL;
+ prefix_list_unset_ref(&filter->plist[direct].ref) ;
if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
return 0;
@@ -3822,10 +3789,7 @@ peer_prefix_list_unset (struct peer *peer, afi_t afi, safi_t safi, int direct)
if (! peer->af_group[afi][safi])
continue;
- if (filter->plist[direct].name)
- free (filter->plist[direct].name);
- filter->plist[direct].name = NULL;
- filter->plist[direct].plist = NULL;
+ prefix_list_unset_ref(&filter->plist[direct].ref) ;
}
return 0;
@@ -3835,55 +3799,15 @@ peer_prefix_list_unset (struct peer *peer, afi_t afi, safi_t safi, int direct)
static void
peer_prefix_list_update (struct prefix_list *plist)
{
- struct listnode *mnode, *mnnode;
- struct listnode *node, *nnode;
- struct bgp *bgp;
- struct peer *peer;
- struct peer_group *group;
- struct bgp_filter *filter;
- afi_t afi;
- safi_t safi;
- int direct;
-
- for (ALL_LIST_ELEMENTS (bm->bgp, mnode, mnnode, bgp))
- {
- for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
- {
- for (afi = AFI_IP; afi < AFI_MAX; afi++)
- for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
- {
- filter = &peer->filter[afi][safi];
-
- for (direct = FILTER_IN; direct < FILTER_MAX; direct++)
- {
- if (filter->plist[direct].name)
- filter->plist[direct].plist =
- prefix_list_lookup (afi, filter->plist[direct].name);
- else
- filter->plist[direct].plist = NULL;
- }
- }
- }
- for (ALL_LIST_ELEMENTS (bgp->group, node, nnode, group))
- {
- for (afi = AFI_IP; afi < AFI_MAX; afi++)
- for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
- {
- filter = &group->conf->filter[afi][safi];
-
- for (direct = FILTER_IN; direct < FILTER_MAX; direct++)
- {
- if (filter->plist[direct].name)
- filter->plist[direct].plist =
- prefix_list_lookup (afi, filter->plist[direct].name);
- else
- filter->plist[direct].plist = NULL;
- }
- }
- }
- }
+ /* This function used to fix up the addresses of prefix lists whenever
+ * a prefix list was changed. That is now done by the symbol reference
+ * mechanism.
+ *
+ * This function could have a use in updating a peer when a prefix list
+ * is changed ?
+ */
}
-
+
int
peer_aslist_set (struct peer *peer, afi_t afi, safi_t safi, int direct,
const char *name)
@@ -4011,7 +3935,7 @@ peer_aslist_update (void)
for (direct = FILTER_IN; direct < FILTER_MAX; direct++)
{
if (filter->aslist[direct].name)
- filter->aslist[direct].aslist =
+ filter->aslist[direct].aslist =
as_list_lookup (filter->aslist[direct].name);
else
filter->aslist[direct].aslist = NULL;
@@ -4028,7 +3952,7 @@ peer_aslist_update (void)
for (direct = FILTER_IN; direct < FILTER_MAX; direct++)
{
if (filter->aslist[direct].name)
- filter->aslist[direct].aslist =
+ filter->aslist[direct].aslist =
as_list_lookup (filter->aslist[direct].name);
else
filter->aslist[direct].aslist = NULL;
@@ -4037,10 +3961,10 @@ peer_aslist_update (void)
}
}
}
-
+
/* Set route-map to the peer. */
int
-peer_route_map_set (struct peer *peer, afi_t afi, safi_t safi, int direct,
+peer_route_map_set (struct peer *peer, afi_t afi, safi_t safi, int direct,
const char *name)
{
struct bgp_filter *filter;
@@ -4062,7 +3986,7 @@ peer_route_map_set (struct peer *peer, afi_t afi, safi_t safi, int direct,
if (filter->map[direct].name)
free (filter->map[direct].name);
-
+
filter->map[direct].name = strdup (name);
filter->map[direct].map = route_map_lookup_by_name (name);
@@ -4145,10 +4069,10 @@ peer_route_map_unset (struct peer *peer, afi_t afi, safi_t safi, int direct)
}
return 0;
}
-
+
/* Set unsuppress-map to the peer. */
int
-peer_unsuppress_map_set (struct peer *peer, afi_t afi, safi_t safi,
+peer_unsuppress_map_set (struct peer *peer, afi_t afi, safi_t safi,
const char *name)
{
struct bgp_filter *filter;
@@ -4160,12 +4084,12 @@ peer_unsuppress_map_set (struct peer *peer, afi_t afi, safi_t safi,
if (peer_is_group_member (peer, afi, safi))
return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER;
-
+
filter = &peer->filter[afi][safi];
if (filter->usmap.name)
free (filter->usmap.name);
-
+
filter->usmap.name = strdup (name);
filter->usmap.map = route_map_lookup_by_name (name);
@@ -4198,7 +4122,7 @@ peer_unsuppress_map_unset (struct peer *peer, afi_t afi, safi_t safi)
if (! peer->afc[afi][safi])
return BGP_ERR_PEER_INACTIVE;
-
+
if (peer_is_group_member (peer, afi, safi))
return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER;
@@ -4227,7 +4151,7 @@ peer_unsuppress_map_unset (struct peer *peer, afi_t afi, safi_t safi)
}
return 0;
}
-
+
int
peer_maximum_prefix_set (struct peer *peer, afi_t afi, safi_t safi,
u_int32_t max, u_char threshold,
@@ -4322,7 +4246,7 @@ peer_maximum_prefix_unset (struct peer *peer, afi_t afi, safi_t safi)
}
return 0;
}
-
+
int
peer_clear (struct peer *peer)
{
@@ -4387,7 +4311,7 @@ peer_clear_soft (struct peer *peer, afi_t afi, safi_t safi,
else
prefix_type = ORF_TYPE_PREFIX_OLD;
- if (filter->plist[FILTER_IN].plist)
+ if (filter->plist[FILTER_IN].ref)
{
if (CHECK_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_ORF_PREFIX_SEND))
bgp_route_refresh_send (peer, afi, safi,
@@ -4427,7 +4351,7 @@ peer_clear_soft (struct peer *peer, afi_t afi, safi_t safi,
}
return 0;
}
-
+
/* Display peer uptime.*/
/* XXX: why does this function return char * when it takes buffer? */
char *
@@ -4441,7 +4365,7 @@ peer_uptime (time_t uptime2, char *buf, size_t len)
{
zlog_warn ("peer_uptime (): buffer shortage %lu", (u_long)len);
/* XXX: should return status instead of buf... */
- snprintf (buf, len, "<error> ");
+ snprintf (buf, len, "<error> ");
return buf;
}
@@ -4462,17 +4386,17 @@ peer_uptime (time_t uptime2, char *buf, size_t len)
#define ONE_WEEK_SECOND 60*60*24*7
if (uptime1 < ONE_DAY_SECOND)
- snprintf (buf, len, "%02d:%02d:%02d",
+ snprintf (buf, len, "%02d:%02d:%02d",
tm->tm_hour, tm->tm_min, tm->tm_sec);
else if (uptime1 < ONE_WEEK_SECOND)
- snprintf (buf, len, "%dd%02dh%02dm",
+ snprintf (buf, len, "%dd%02dh%02dm",
tm->tm_yday, tm->tm_hour, tm->tm_min);
else
- snprintf (buf, len, "%02dw%dd%02dh",
+ snprintf (buf, len, "%02dw%dd%02dh",
tm->tm_yday/7, tm->tm_yday - ((tm->tm_yday/7) * 7), tm->tm_hour);
return buf;
}
-
+
static void
bgp_config_write_filter (struct vty *vty, struct peer *peer,
afi_t afi, safi_t safi)
@@ -4492,30 +4416,31 @@ bgp_config_write_filter (struct vty *vty, struct peer *peer,
if (filter->dlist[in].name)
if (! gfilter || ! gfilter->dlist[in].name
|| strcmp (filter->dlist[in].name, gfilter->dlist[in].name) != 0)
- vty_out (vty, " neighbor %s distribute-list %s in%s", addr,
+ vty_out (vty, " neighbor %s distribute-list %s in%s", addr,
filter->dlist[in].name, VTY_NEWLINE);
if (filter->dlist[out].name && ! gfilter)
- vty_out (vty, " neighbor %s distribute-list %s out%s", addr,
+ vty_out (vty, " neighbor %s distribute-list %s out%s", addr,
filter->dlist[out].name, VTY_NEWLINE);
/* prefix-list. */
- if (filter->plist[in].name)
- if (! gfilter || ! gfilter->plist[in].name
- || strcmp (filter->plist[in].name, gfilter->plist[in].name) != 0)
- vty_out (vty, " neighbor %s prefix-list %s in%s", addr,
- filter->plist[in].name, VTY_NEWLINE);
- if (filter->plist[out].name && ! gfilter)
- vty_out (vty, " neighbor %s prefix-list %s out%s", addr,
- filter->plist[out].name, VTY_NEWLINE);
+ if ( filter->plist[in].ref && (! gfilter
+ || (prefix_list_ref_ident(gfilter->plist[in].ref)
+ != prefix_list_ref_ident(filter->plist[in].ref))) )
+ vty_out (vty, " neighbor %s prefix-list %s in%s", addr,
+ prefix_list_ref_name(filter->plist[in].ref), VTY_NEWLINE);
+
+ if (filter->plist[out].ref && ! gfilter)
+ vty_out (vty, " neighbor %s prefix-list %s out%s", addr,
+ prefix_list_ref_name(filter->plist[out].ref), VTY_NEWLINE);
/* route-map. */
if (filter->map[RMAP_IN].name)
if (! gfilter || ! gfilter->map[RMAP_IN].name
|| strcmp (filter->map[RMAP_IN].name, gfilter->map[RMAP_IN].name) != 0)
- vty_out (vty, " neighbor %s route-map %s in%s", addr,
+ vty_out (vty, " neighbor %s route-map %s in%s", addr,
filter->map[RMAP_IN].name, VTY_NEWLINE);
if (filter->map[RMAP_OUT].name && ! gfilter)
- vty_out (vty, " neighbor %s route-map %s out%s", addr,
+ vty_out (vty, " neighbor %s route-map %s out%s", addr,
filter->map[RMAP_OUT].name, VTY_NEWLINE);
if (filter->map[RMAP_IMPORT].name && ! gfilter)
vty_out (vty, " neighbor %s route-map %s import%s", addr,
@@ -4536,10 +4461,10 @@ bgp_config_write_filter (struct vty *vty, struct peer *peer,
if (filter->aslist[in].name)
if (! gfilter || ! gfilter->aslist[in].name
|| strcmp (filter->aslist[in].name, gfilter->aslist[in].name) != 0)
- vty_out (vty, " neighbor %s filter-list %s in%s", addr,
+ vty_out (vty, " neighbor %s filter-list %s in%s", addr,
filter->aslist[in].name, VTY_NEWLINE);
if (filter->aslist[out].name && ! gfilter)
- vty_out (vty, " neighbor %s filter-list %s out%s", addr,
+ vty_out (vty, " neighbor %s filter-list %s out%s", addr,
filter->aslist[out].name, VTY_NEWLINE);
}
@@ -4619,7 +4544,7 @@ bgp_config_write_peer (struct vty *vty, struct bgp *bgp,
if (peer->ifname)
vty_out (vty, " neighbor %s interface %s%s", addr, peer->ifname,
VTY_NEWLINE);
-
+
/* Passive. */
if (CHECK_FLAG (peer->flags, PEER_FLAG_PASSIVE))
if (! peer_group_active (peer) ||
@@ -4656,16 +4581,16 @@ bgp_config_write_peer (struct vty *vty, struct bgp *bgp,
/* advertisement-interval */
if (CHECK_FLAG (peer->config, PEER_CONFIG_ROUTEADV))
vty_out (vty, " neighbor %s advertisement-interval %d%s",
- addr, peer->v_routeadv, VTY_NEWLINE);
+ addr, peer->v_routeadv, VTY_NEWLINE);
/* timers. */
if (CHECK_FLAG (peer->config, PEER_CONFIG_TIMER)
&& ! peer_group_active (peer))
- vty_out (vty, " neighbor %s timers %d %d%s", addr,
+ vty_out (vty, " neighbor %s timers %d %d%s", addr,
peer->keepalive, peer->holdtime, VTY_NEWLINE);
if (CHECK_FLAG (peer->config, PEER_CONFIG_CONNECT))
- vty_out (vty, " neighbor %s timers connect %d%s", addr,
+ vty_out (vty, " neighbor %s timers connect %d%s", addr,
peer->connect, VTY_NEWLINE);
/* Default weight. */
@@ -4752,7 +4677,7 @@ bgp_config_write_peer (struct vty *vty, struct bgp *bgp,
/* Route reflector client. */
if (peer_af_flag_check (peer, afi, safi, PEER_FLAG_REFLECTOR_CLIENT)
&& ! peer->af_group[afi][safi])
- vty_out (vty, " neighbor %s route-reflector-client%s", addr,
+ vty_out (vty, " neighbor %s route-reflector-client%s", addr,
VTY_NEWLINE);
/* Nexthop self. */
@@ -4774,7 +4699,7 @@ bgp_config_write_peer (struct vty *vty, struct bgp *bgp,
if (peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_COMMUNITY)
&& peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_EXT_COMMUNITY))
vty_out (vty, " neighbor %s send-community both%s", addr, VTY_NEWLINE);
- else if (peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_EXT_COMMUNITY))
+ else if (peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_EXT_COMMUNITY))
vty_out (vty, " neighbor %s send-community extended%s",
addr, VTY_NEWLINE);
else if (peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_COMMUNITY))
@@ -4862,7 +4787,7 @@ bgp_config_write_peer (struct vty *vty, struct bgp *bgp,
&& CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MED_UNCHANGED))
vty_out (vty, " neighbor %s attribute-unchanged%s", addr, VTY_NEWLINE);
else
- vty_out (vty, " neighbor %s attribute-unchanged%s%s%s%s", addr,
+ vty_out (vty, " neighbor %s attribute-unchanged%s%s%s%s", addr,
(CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED)) ?
" as-path" : "",
(CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_NEXTHOP_UNCHANGED)) ?
@@ -4895,7 +4820,7 @@ bgp_config_write_family_header (struct vty *vty, afi_t afi, safi_t safi,
else if (afi == AFI_IP6)
{
vty_out (vty, "ipv6");
-
+
if (safi == SAFI_MULTICAST)
vty_out (vty, " multicast");
}
@@ -4956,14 +4881,14 @@ bgp_config_write (struct vty *vty)
/* BGP Multiple instance. */
if (bgp_option_check (BGP_OPT_MULTIPLE_INSTANCE))
- {
+ {
vty_out (vty, "bgp multiple-instance%s", VTY_NEWLINE);
write++;
}
/* BGP Config type. */
if (bgp_option_check (BGP_OPT_CONFIG_CISCO))
- {
+ {
vty_out (vty, "bgp config-type cisco%s", VTY_NEWLINE);
write++;
}
@@ -4990,11 +4915,11 @@ bgp_config_write (struct vty *vty)
/* BGP fast-external-failover. */
if (CHECK_FLAG (bgp->flags, BGP_FLAG_NO_FAST_EXT_FAILOVER))
- vty_out (vty, " no bgp fast-external-failover%s", VTY_NEWLINE);
+ vty_out (vty, " no bgp fast-external-failover%s", VTY_NEWLINE);
/* BGP router ID. */
if (CHECK_FLAG (bgp->config, BGP_CONFIG_ROUTER_ID))
- vty_out (vty, " bgp router-id %s%s", inet_ntoa (bgp->router_id),
+ vty_out (vty, " bgp router-id %s%s", inet_ntoa (bgp->router_id),
VTY_NEWLINE);
/* BGP log-neighbor-changes. */
@@ -5017,7 +4942,7 @@ bgp_config_write (struct vty *vty)
/* BGP client-to-client reflection. */
if (bgp_flag_check (bgp, BGP_FLAG_NO_CLIENT_TO_CLIENT))
vty_out (vty, " no bgp client-to-client reflection%s", VTY_NEWLINE);
-
+
/* BGP cluster ID. */
if (CHECK_FLAG (bgp->config, BGP_CONFIG_CLUSTER_ID))
vty_out (vty, " bgp cluster-id %s%s", inet_ntoa (bgp->cluster_id),
@@ -5095,7 +5020,7 @@ bgp_config_write (struct vty *vty)
/* BGP timers configuration. */
if (bgp->default_keepalive != BGP_DEFAULT_KEEPALIVE
&& bgp->default_holdtime != BGP_DEFAULT_HOLDTIME)
- vty_out (vty, " timers bgp %d %d%s", bgp->default_keepalive,
+ vty_out (vty, " timers bgp %d %d%s", bgp->default_keepalive,
bgp->default_holdtime, VTY_NEWLINE);
/* peer-group */
@@ -5113,7 +5038,7 @@ bgp_config_write (struct vty *vty)
/* Distance configuration. */
bgp_config_write_distance (vty, bgp);
-
+
/* No auto-summary */
if (bgp_option_check (BGP_OPT_CONFIG_CISCO))
vty_out (vty, " no auto-summary%s", VTY_NEWLINE);
@@ -5148,7 +5073,7 @@ bgp_master_init (void)
bm->start_time = time (NULL);
}
-
+
void
bgp_init (void)
{
@@ -5203,9 +5128,9 @@ bgp_terminate (void)
if (peer->status == Established)
bgp_notify_send (peer, BGP_NOTIFY_CEASE,
BGP_NOTIFY_CEASE_PEER_UNCONFIG);
-
+
bgp_cleanup_routes ();
-
+
if (bm->process_main_queue)
{
work_queue_free (bm->process_main_queue);
diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h
index e8b8ef5a..696eabf4 100644
--- a/bgpd/bgpd.h
+++ b/bgpd/bgpd.h
@@ -21,6 +21,8 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#ifndef _QUAGGA_BGPD_H
#define _QUAGGA_BGPD_H
+#include "plist.h"
+
/* For union sockunion. */
#include "sockunion.h"
@@ -41,10 +43,10 @@ struct bgp_master
/* work queues */
struct work_queue *process_main_queue;
struct work_queue *process_rsclient_queue;
-
+
/* Listening sockets */
struct list *listen_sockets;
-
+
/* BGP port number. */
u_int16_t port;
@@ -62,14 +64,14 @@ struct bgp_master
};
/* BGP instance structure. */
-struct bgp
+struct bgp
{
/* AS number of this BGP instance. */
as_t as;
/* Name of this BGP instance. */
char *name;
-
+
/* Reference count to allow peer_delete to finish after bgp_delete */
int lock;
@@ -151,7 +153,7 @@ struct bgp
u_char distance_ebgp;
u_char distance_ibgp;
u_char distance_local;
-
+
/* BGP default local-preference. */
u_int32_t default_local_pref;
@@ -172,7 +174,7 @@ struct peer_group
/* Pointer to BGP. */
struct bgp *bgp;
-
+
/* Peer-group client list. */
struct list *peer;
@@ -181,7 +183,7 @@ struct peer_group
};
/* BGP Notify message format. */
-struct bgp_notify
+struct bgp_notify
{
u_char code;
u_char subcode;
@@ -197,7 +199,7 @@ struct bgp_nexthop
#ifdef HAVE_IPV6
struct in6_addr v6_global;
struct in6_addr v6_local;
-#endif /* HAVE_IPV6 */
+#endif /* HAVE_IPV6 */
};
/* BGP router distinguisher value. */
@@ -218,7 +220,7 @@ struct bgp_rd
struct bgp_filter
{
/* Distribute-list. */
- struct
+ struct
{
char *name;
struct access_list *alist;
@@ -227,8 +229,12 @@ struct bgp_filter
/* Prefix-list. */
struct
{
+#if 1
+ prefix_list_ref ref ;
+#else
char *name;
struct prefix_list *plist;
+#endif
} plist[FILTER_MAX];
/* Filter-list. */
@@ -271,7 +277,7 @@ struct peer
u_char af_group[AFI_MAX][SAFI_MAX];
/* Peer's remote AS number. */
- as_t as;
+ as_t as;
/* Peer's local AS number. */
as_t local_as;
@@ -310,7 +316,7 @@ struct peer
time_t uptime; /* Last Up/Down time */
time_t readtime; /* Last read time */
time_t resettime; /* Last reset time */
-
+
unsigned int ifindex; /* ifindex of the BGP connection. */
char *ifname; /* bind interface name. */
char *update_if;
@@ -449,10 +455,10 @@ struct peer
struct thread *t_pmax_restart;
struct thread *t_gr_restart;
struct thread *t_gr_stale;
-
+
/* workqueues */
struct work_queue *clear_node_queue;
-
+
/* Statistics field */
u_int32_t open_in; /* Open message input count */
u_int32_t open_out; /* Open message output count */
@@ -710,7 +716,7 @@ struct bgp_nlri
#define BGP_INIT_START_TIMER 5
#define BGP_ERROR_START_TIMER 30
#define BGP_DEFAULT_HOLDTIME 180
-#define BGP_DEFAULT_KEEPALIVE 60
+#define BGP_DEFAULT_KEEPALIVE 60
#define BGP_DEFAULT_ASORIGINATE 15
#define BGP_DEFAULT_EBGP_ROUTEADV 30
#define BGP_DEFAULT_IBGP_ROUTEADV 5
@@ -809,9 +815,11 @@ extern struct thread_master *master;
/* Prototypes. */
extern void bgp_terminate (void);
extern void bgp_reset (void);
-extern void bgp_zclient_reset (void);
-extern int bgp_nexthop_set (union sockunion *, union sockunion *,
- struct bgp_nexthop *, struct peer *);
+
+extern void bgp_zclient_reset (void); /* See bgp_zebra ! */
+extern int bgp_nexthop_set (union sockunion *, union sockunion *,
+ struct bgp_nexthop *, struct peer *); /* See bgp_zebra ! */
+
extern struct bgp *bgp_get_default (void);
extern struct bgp *bgp_lookup (as_t, const char *);
extern struct bgp *bgp_lookup_by_name (const char *);
@@ -829,7 +837,7 @@ extern struct peer *peer_create_accept (struct bgp *);
extern char *peer_uptime (time_t, char *, size_t);
extern int bgp_config_write (struct vty *);
extern void bgp_config_write_family_header (struct vty *, afi_t, safi_t, int *);
-
+
extern void bgp_master_init (void);
extern void bgp_init (void);
diff --git a/configure.ac b/configure.ac
index 9c47b5b4..17ab4387 100755
--- a/configure.ac
+++ b/configure.ac
@@ -128,6 +128,7 @@ if test "x${cflags_specified}" = "x" ; then
CFLAGS="${CFLAGS} -Wbad-function-cast -Wwrite-strings"
CFLAGS="${CFLAGS} -Wmissing-prototypes -Wmissing-declarations"
CFLAGS="${CFLAGS} -Wchar-subscripts -Wcast-qual"
+ CFLAGS="${CFLAGS} -pthread"
# TODO: conditionally addd -Wpacked if handled
AC_MSG_RESULT([gcc default])
;;
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 315e919b..3184a9b6 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -12,7 +12,8 @@ libzebra_la_SOURCES = \
sockunion.c prefix.c thread.c if.c memory.c buffer.c table.c hash.c \
filter.c routemap.c distribute.c stream.c str.c log.c plist.c \
zclient.c sockopt.c smux.c md5.c if_rmap.c keychain.c privs.c \
- sigevent.c pqueue.c jhash.c memtypes.c workqueue.c
+ sigevent.c pqueue.c jhash.c memtypes.c workqueue.c symtab.c heap.c \
+ qtime.c qpthreads.c mqueue.c qpselect.c qtimers.c qpnexus.c
BUILT_SOURCES = memtypes.h route_types.h
@@ -27,7 +28,8 @@ pkginclude_HEADERS = \
str.h stream.h table.h thread.h vector.h version.h vty.h zebra.h \
plist.h zclient.h sockopt.h smux.h md5.h if_rmap.h keychain.h \
privs.h sigevent.h pqueue.h jhash.h zassert.h memtypes.h \
- workqueue.h route_types.h
+ workqueue.h route_types.h symtab.h heap.h \
+ qtime.h qpthreads.h mqueue.h qpselect.h qtimers.h qpnexus.h
EXTRA_DIST = regex.c regex-gnu.h memtypes.awk route_types.awk route_types.txt
diff --git a/lib/command.c b/lib/command.c
index 31c067a3..80b113e8 100644
--- a/lib/command.c
+++ b/lib/command.c
@@ -1,11 +1,11 @@
/*
$Id$
-
+
Command interpreter routine for virtual terminal [aka TeletYpe]
Copyright (C) 1997, 98, 99 Kunihiro Ishiguro
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
@@ -93,7 +93,7 @@ static struct facility_map {
int facility;
const char *name;
size_t match;
-} syslog_facilities[] =
+} syslog_facilities[] =
{
{ LOG_KERN, "kern", 1 },
{ LOG_USER, "user", 2 },
@@ -145,7 +145,7 @@ static int
level_match(const char *s)
{
int level ;
-
+
for ( level = 0 ; zlog_priority [level] != NULL ; level ++ )
if (!strncmp (s, zlog_priority[level], 2))
return level;
@@ -160,7 +160,7 @@ print_version (const char *progname)
printf ("%s\n", QUAGGA_COPYRIGHT);
}
-
+
/* Utility function to concatenate argv argument into a single string
with inserting ' ' character between each argument. */
char *
@@ -190,30 +190,24 @@ argv_concat (const char **argv, int argc, int shift)
/* Install top node of command vector. */
void
-install_node (struct cmd_node *node,
+install_node (struct cmd_node *node,
int (*func) (struct vty *))
{
vector_set_index (cmdvec, node->node, node);
node->func = func;
- node->cmd_vector = vector_init (VECTOR_MIN_SIZE);
+ node->cmd_vector = vector_init (0);
}
/* Compare two command's string. Used in sort_node (). */
static int
-cmp_node (const void *p, const void *q)
+cmp_node (const struct cmd_element *a, const struct cmd_element *b)
{
- const struct cmd_element *a = *(struct cmd_element * const *)p;
- const struct cmd_element *b = *(struct cmd_element * const *)q;
-
return strcmp (a->string, b->string);
}
static int
-cmp_desc (const void *p, const void *q)
+cmp_desc (const struct desc *a, const struct desc *b)
{
- const struct desc *a = *(struct desc * const *)p;
- const struct desc *b = *(struct desc * const *)q;
-
return strcmp (a->cmd, b->cmd);
}
@@ -223,24 +217,21 @@ sort_node ()
{
unsigned int i, j;
struct cmd_node *cnode;
- vector descvec;
struct cmd_element *cmd_element;
for (i = 0; i < vector_active (cmdvec); i++)
if ((cnode = vector_slot (cmdvec, i)) != NULL)
- {
+ {
vector cmd_vector = cnode->cmd_vector;
- qsort (cmd_vector->index, vector_active (cmd_vector),
- sizeof (void *), cmp_node);
+ vector_sort(cmd_vector, (vector_sort_cmp*)cmp_node) ;
for (j = 0; j < vector_active (cmd_vector); j++)
if ((cmd_element = vector_slot (cmd_vector, j)) != NULL
&& vector_active (cmd_element->strvec))
{
- descvec = vector_slot (cmd_element->strvec,
+ vector descvec = vector_slot (cmd_element->strvec,
vector_active (cmd_element->strvec) - 1);
- qsort (descvec->index, vector_active (descvec),
- sizeof (void *), cmp_desc);
+ vector_sort(descvec, (vector_sort_cmp*)cmp_desc) ;
}
}
}
@@ -255,10 +246,10 @@ cmd_make_strvec (const char *string)
char *token;
int strlen;
vector strvec;
-
+
if (string == NULL)
return NULL;
-
+
cp = string;
/* Skip white spaces. */
@@ -273,10 +264,10 @@ cmd_make_strvec (const char *string)
return NULL;
/* Prepare return vector. */
- strvec = vector_init (VECTOR_MIN_SIZE);
+ strvec = vector_init (0);
/* Copy each command piece and set into vector. */
- while (1)
+ while (1)
{
start = cp;
while (!(isspace ((int) *cp) || *cp == '\r' || *cp == '\n') &&
@@ -321,7 +312,7 @@ cmd_desc_str (const char **string)
const char *cp, *start;
char *token;
int strlen;
-
+
cp = *string;
if (cp == NULL)
@@ -370,7 +361,7 @@ cmd_make_descvec (const char *string, const char *descstr)
if (cp == NULL)
return NULL;
- allvec = vector_init (VECTOR_MIN_SIZE);
+ allvec = vector_init (0);
while (1)
{
@@ -396,7 +387,7 @@ cmd_make_descvec (const char *string, const char *descstr)
}
cp++;
}
-
+
while (isspace ((int) *cp) && *cp != '\0')
cp++;
@@ -406,7 +397,7 @@ cmd_make_descvec (const char *string, const char *descstr)
cp++;
}
- if (*cp == '\0')
+ if (*cp == '\0')
return allvec;
sp = cp;
@@ -428,14 +419,14 @@ cmd_make_descvec (const char *string, const char *descstr)
{
if (multiple == 1)
{
- strvec = vector_init (VECTOR_MIN_SIZE);
+ strvec = vector_init (0);
vector_set (allvec, strvec);
}
multiple++;
}
else
{
- strvec = vector_init (VECTOR_MIN_SIZE);
+ strvec = vector_init (0);
vector_set (allvec, strvec);
}
vector_set (strvec, desc);
@@ -484,14 +475,14 @@ void
install_element (enum node_type ntype, struct cmd_element *cmd)
{
struct cmd_node *cnode;
-
+
/* cmd_init hasn't been called */
if (!cmdvec)
return;
-
+
cnode = vector_slot (cmdvec, ntype);
- if (cnode == NULL)
+ if (cnode == NULL)
{
fprintf (stderr, "Command node %d doesn't exist, please check it\n",
ntype);
@@ -506,13 +497,13 @@ install_element (enum node_type ntype, struct cmd_element *cmd)
cmd->cmdsize = cmd_cmdsize (cmd->strvec);
}
-static unsigned char itoa64[] =
+static unsigned char itoa64[] =
"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
static void
to64(char *s, long v, int n)
{
- while (--n >= 0)
+ while (--n >= 0)
{
*s++ = itoa64[v&0x3f];
v >>= 6;
@@ -527,7 +518,7 @@ zencrypt (const char *passwd)
char *crypt (const char *, const char *);
gettimeofday(&tv,0);
-
+
to64(&salt[0], random(), 3);
to64(&salt[3], tv.tv_usec, 3);
salt[5] = '\0';
@@ -545,9 +536,9 @@ config_write_host (struct vty *vty)
if (host.encrypt)
{
if (host.password_encrypt)
- vty_out (vty, "password 8 %s%s", host.password_encrypt, VTY_NEWLINE);
+ vty_out (vty, "password 8 %s%s", host.password_encrypt, VTY_NEWLINE);
if (host.enable_encrypt)
- vty_out (vty, "enable password 8 %s%s", host.enable_encrypt, VTY_NEWLINE);
+ vty_out (vty, "enable password 8 %s%s", host.enable_encrypt, VTY_NEWLINE);
}
else
{
@@ -557,57 +548,57 @@ config_write_host (struct vty *vty)
vty_out (vty, "enable password %s%s", host.enable, VTY_NEWLINE);
}
- if (zlog_default->default_lvl != LOG_DEBUG)
+ if (zlog_get_default_lvl(NULL) != LOG_DEBUG)
{
vty_out (vty, "! N.B. The 'log trap' command is deprecated.%s",
VTY_NEWLINE);
vty_out (vty, "log trap %s%s",
- zlog_priority[zlog_default->default_lvl], VTY_NEWLINE);
+ zlog_priority[zlog_get_default_lvl(NULL)], VTY_NEWLINE);
}
- if (host.logfile && (zlog_default->maxlvl[ZLOG_DEST_FILE] != ZLOG_DISABLED))
+ if (host.logfile && (zlog_get_maxlvl(NULL, ZLOG_DEST_FILE) != ZLOG_DISABLED))
{
vty_out (vty, "log file %s", host.logfile);
- if (zlog_default->maxlvl[ZLOG_DEST_FILE] != zlog_default->default_lvl)
+ if (zlog_get_maxlvl(NULL, ZLOG_DEST_FILE) != zlog_get_default_lvl(NULL))
vty_out (vty, " %s",
- zlog_priority[zlog_default->maxlvl[ZLOG_DEST_FILE]]);
+ zlog_priority[zlog_get_maxlvl(NULL, ZLOG_DEST_FILE)]);
vty_out (vty, "%s", VTY_NEWLINE);
}
- if (zlog_default->maxlvl[ZLOG_DEST_STDOUT] != ZLOG_DISABLED)
+ if (zlog_get_maxlvl(NULL, ZLOG_DEST_STDOUT) != ZLOG_DISABLED)
{
vty_out (vty, "log stdout");
- if (zlog_default->maxlvl[ZLOG_DEST_STDOUT] != zlog_default->default_lvl)
+ if (zlog_get_maxlvl(NULL, ZLOG_DEST_STDOUT) != zlog_get_default_lvl(NULL))
vty_out (vty, " %s",
- zlog_priority[zlog_default->maxlvl[ZLOG_DEST_STDOUT]]);
+ zlog_priority[zlog_get_maxlvl(NULL, ZLOG_DEST_STDOUT)]);
vty_out (vty, "%s", VTY_NEWLINE);
}
- if (zlog_default->maxlvl[ZLOG_DEST_MONITOR] == ZLOG_DISABLED)
+ if (zlog_get_maxlvl(NULL, ZLOG_DEST_MONITOR) == ZLOG_DISABLED)
vty_out(vty,"no log monitor%s",VTY_NEWLINE);
- else if (zlog_default->maxlvl[ZLOG_DEST_MONITOR] != zlog_default->default_lvl)
+ else if (zlog_get_maxlvl(NULL, ZLOG_DEST_MONITOR) != zlog_get_default_lvl(NULL))
vty_out(vty,"log monitor %s%s",
- zlog_priority[zlog_default->maxlvl[ZLOG_DEST_MONITOR]],VTY_NEWLINE);
+ zlog_priority[zlog_get_maxlvl(NULL, ZLOG_DEST_MONITOR)],VTY_NEWLINE);
- if (zlog_default->maxlvl[ZLOG_DEST_SYSLOG] != ZLOG_DISABLED)
+ if (zlog_get_maxlvl(NULL, ZLOG_DEST_SYSLOG) != ZLOG_DISABLED)
{
vty_out (vty, "log syslog");
- if (zlog_default->maxlvl[ZLOG_DEST_SYSLOG] != zlog_default->default_lvl)
+ if (zlog_get_maxlvl(NULL, ZLOG_DEST_SYSLOG) != zlog_get_default_lvl(NULL))
vty_out (vty, " %s",
- zlog_priority[zlog_default->maxlvl[ZLOG_DEST_SYSLOG]]);
+ zlog_priority[zlog_get_maxlvl(NULL, ZLOG_DEST_SYSLOG)]);
vty_out (vty, "%s", VTY_NEWLINE);
}
- if (zlog_default->facility != LOG_DAEMON)
+ if (zlog_get_facility(NULL) != LOG_DAEMON)
vty_out (vty, "log facility %s%s",
- facility_name(zlog_default->facility), VTY_NEWLINE);
+ facility_name(zlog_get_facility(NULL)), VTY_NEWLINE);
- if (zlog_default->record_priority == 1)
+ if (zlog_get_record_priority(NULL) == 1)
vty_out (vty, "log record-priority%s", VTY_NEWLINE);
- if (zlog_default->timestamp_precision > 0)
+ if (zlog_get_timestamp_precision(NULL) > 0)
vty_out (vty, "log timestamp precision %d%s",
- zlog_default->timestamp_precision, VTY_NEWLINE);
+ zlog_get_timestamp_precision(NULL), VTY_NEWLINE);
if (host.advanced)
vty_out (vty, "service advanced-vty%s", VTY_NEWLINE);
@@ -684,7 +675,7 @@ cmd_filter_by_symbol (char *command, char *symbol)
#endif
/* Completion match types. */
-enum match_type
+enum match_type
{
no_match,
extend_match,
@@ -695,7 +686,7 @@ enum match_type
range_match,
vararg_match,
partly_match,
- exact_match
+ exact_match
};
static enum match_type
@@ -866,7 +857,7 @@ cmd_ipv6_match (const char *str)
* ::1.2.3.4
*/
ret = inet_pton(AF_INET6, str, &sin6_dummy.sin6_addr);
-
+
if (ret == 1)
return exact_match;
@@ -1071,7 +1062,7 @@ cmd_ipv6_prefix_match (const char *str)
if (mask < 0 || mask > 128)
return no_match;
-
+
/* I don't know why mask < 13 makes command match partly.
Forgive me to make this comments. I Want to set static default route
because of lack of function to originate default in ospf6d; sorry
@@ -1162,7 +1153,7 @@ cmd_filter_by_completion (char *command, vector v, unsigned int index)
if ((desc = vector_slot (descvec, j)))
{
str = desc->cmd;
-
+
if (CMD_VARARG (str))
{
if (match_type < vararg_match)
@@ -1378,7 +1369,7 @@ is_cmd_ambiguous (char *command, vector v, int index, enum match_type type)
if ((desc = vector_slot (descvec, j)))
{
enum match_type ret;
-
+
str = desc->cmd;
switch (type)
@@ -1567,7 +1558,7 @@ desc_unique_string (vector v, const char *str)
return 0;
}
-static int
+static int
cmd_try_do_shortcut (enum node_type node, char* first_word) {
if ( first_word != NULL &&
node != AUTH_NODE &&
@@ -1602,7 +1593,7 @@ cmd_describe_command_real (vector vline, struct vty *vty, int *status)
}
else
index = vector_active (vline) - 1;
-
+
/* Make copy vector of current node's command vector. */
cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
@@ -1615,7 +1606,7 @@ cmd_describe_command_real (vector vline, struct vty *vty, int *status)
if ((command = vector_slot (vline, i)))
{
match = cmd_filter_by_completion (command, cmd_vector, i);
-
+
if (match == vararg_match)
{
struct cmd_element *cmd_element;
@@ -1634,7 +1625,7 @@ cmd_describe_command_real (vector vline, struct vty *vty, int *status)
vector_set (matchvec, desc);
}
}
-
+
vector_set (matchvec, &desc_cr);
vector_free (cmd_vector);
@@ -1734,7 +1725,7 @@ cmd_describe_command (vector vline, struct vty *vty, int *status)
shifted_vline = vector_init (vector_count(vline));
/* use memcpy? */
- for (index = 1; index < vector_active (vline); index++)
+ for (index = 1; index < vector_active (vline); index++)
{
vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
}
@@ -1836,7 +1827,7 @@ cmd_complete_command_real (vector vline, struct vty *vty, int *status)
}
*/
}
-
+
/* Prepare match vector. */
matchvec = vector_init (INIT_MATCHVEC_SIZE);
@@ -1858,7 +1849,7 @@ cmd_complete_command_real (vector vline, struct vty *vty, int *status)
for (j = 0; j < vector_active (descvec); j++)
if ((desc = vector_slot (descvec, j)))
{
- if ((string =
+ if ((string =
cmd_entry_function (vector_slot (vline, index),
desc->cmd)))
if (cmd_unique_string (matchvec, string))
@@ -1884,10 +1875,11 @@ cmd_complete_command_real (vector vline, struct vty *vty, int *status)
return NULL;
}
+/* XXX: TODO: stop poking around inside vector */
/* Only one matched */
if (vector_slot (matchvec, 1) == NULL)
{
- match_str = (char **) matchvec->index;
+ match_str = (char **) matchvec->VECTOR_INDEX;
vector_only_wrapper_free (matchvec);
*status = CMD_COMPLETE_FULL_MATCH;
return match_str;
@@ -1898,7 +1890,7 @@ cmd_complete_command_real (vector vline, struct vty *vty, int *status)
/* Check LCD of matched strings. */
if (vector_slot (vline, index) != NULL)
{
- lcd = cmd_lcd ((char **) matchvec->index);
+ lcd = cmd_lcd ((char **) matchvec->VECTOR_INDEX);
if (lcd)
{
@@ -1909,7 +1901,7 @@ cmd_complete_command_real (vector vline, struct vty *vty, int *status)
char *lcdstr;
lcdstr = XMALLOC (MTYPE_STRVEC, lcd + 1);
- memcpy (lcdstr, matchvec->index[0], lcd);
+ memcpy (lcdstr, matchvec->VECTOR_INDEX[0], lcd);
lcdstr[lcd] = '\0';
/* match_str = (char **) &lcdstr; */
@@ -1925,7 +1917,7 @@ cmd_complete_command_real (vector vline, struct vty *vty, int *status)
/* Make new matchvec. */
matchvec = vector_init (INIT_MATCHVEC_SIZE);
vector_set (matchvec, lcdstr);
- match_str = (char **) matchvec->index;
+ match_str = (char **) matchvec->VECTOR_INDEX;
vector_only_wrapper_free (matchvec);
*status = CMD_COMPLETE_MATCH;
@@ -1934,7 +1926,7 @@ cmd_complete_command_real (vector vline, struct vty *vty, int *status)
}
}
- match_str = (char **) matchvec->index;
+ match_str = (char **) matchvec->VECTOR_INDEX;
vector_only_wrapper_free (matchvec);
*status = CMD_COMPLETE_LIST_MATCH;
return match_str;
@@ -1957,7 +1949,7 @@ cmd_complete_command (vector vline, struct vty *vty, int *status)
shifted_vline = vector_init (vector_count(vline));
/* use memcpy? */
- for (index = 1; index < vector_active (vline); index++)
+ for (index = 1; index < vector_active (vline); index++)
{
vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
}
@@ -2030,7 +2022,7 @@ cmd_execute_command_real (vector vline, struct vty *vty,
if (match == vararg_match)
break;
-
+
ret = is_cmd_ambiguous (command, cmd_vector, index, match);
if (ret == 1)
@@ -2141,7 +2133,7 @@ cmd_execute_command (vector vline, struct vty *vty, struct cmd_element **cmd,
shifted_vline = vector_init (vector_count(vline));
/* use memcpy? */
- for (index = 1; index < vector_active (vline); index++)
+ for (index = 1; index < vector_active (vline); index++)
{
vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
}
@@ -2160,7 +2152,7 @@ cmd_execute_command (vector vline, struct vty *vty, struct cmd_element **cmd,
return saved_ret;
/* This assumes all nodes above CONFIG_NODE are childs of CONFIG_NODE */
- while ( ret != CMD_SUCCESS && ret != CMD_WARNING
+ while ( ret != CMD_SUCCESS && ret != CMD_WARNING
&& vty->node > CONFIG_NODE )
{
try_node = node_parent(try_node);
@@ -2204,14 +2196,14 @@ cmd_execute_command_strict (vector vline, struct vty *vty,
if ((command = vector_slot (vline, index)))
{
int ret;
-
+
match = cmd_filter_by_string (vector_slot (vline, index),
cmd_vector, index);
/* If command meets '.VARARG' then finish matching. */
if (match == vararg_match)
break;
-
+
ret = is_cmd_ambiguous (command, cmd_vector, index, match);
if (ret == 1)
{
@@ -2351,7 +2343,7 @@ DEFUN (config_terminal,
}
/* Enable command */
-DEFUN (enable,
+DEFUN (enable,
config_enable_cmd,
"enable",
"Turn on privileged mode command\n")
@@ -2367,7 +2359,7 @@ DEFUN (enable,
}
/* Disable command */
-DEFUN (disable,
+DEFUN (disable,
config_disable_cmd,
"disable",
"Turn off privileged mode command\n")
@@ -2432,7 +2424,7 @@ ALIAS (config_exit,
config_quit_cmd,
"quit",
"Exit current mode and down to previous mode\n")
-
+
/* End of configuration. */
DEFUN (config_end,
config_end_cmd,
@@ -2494,7 +2486,7 @@ DEFUN (config_help,
"help",
"Description of the interactive help system\n")
{
- vty_out (vty,
+ vty_out (vty,
"Quagga VTY provides advanced help feature. When you need help,%s\
anytime at the command line please press '?'.%s\
%s\
@@ -2532,9 +2524,9 @@ DEFUN (config_list,
}
/* Write current configuration into file. */
-DEFUN (config_write_file,
+DEFUN (config_write_file,
config_write_file_cmd,
- "write file",
+ "write file",
"Write running configuration to memory, network, or terminal\n"
"Write to configuration file\n")
{
@@ -2557,7 +2549,7 @@ DEFUN (config_write_file,
/* Get filename. */
config_file = host.config;
-
+
config_file_sav =
XMALLOC (MTYPE_TMP, strlen (config_file) + strlen (CONF_BACKUP_EXT) + 1);
strcpy (config_file_sav, config_file);
@@ -2566,7 +2558,7 @@ DEFUN (config_write_file,
config_file_tmp = XMALLOC (MTYPE_TMP, strlen (config_file) + 8);
sprintf (config_file_tmp, "%s.XXXXXX", config_file);
-
+
/* Open file to configuration write. */
fd = mkstemp (config_file_tmp);
if (fd < 0)
@@ -2575,10 +2567,9 @@ DEFUN (config_write_file,
VTY_NEWLINE);
goto finished;
}
-
+
/* Make vty for configuration file. */
- file_vty = vty_new ();
- file_vty->fd = fd;
+ file_vty = vty_new (fd);
file_vty->type = VTY_FILE;
/* Config file header print. */
@@ -2621,10 +2612,10 @@ DEFUN (config_write_file,
goto finished;
}
sync ();
-
+
if (chmod (config_file, CONFIGFILE_MASK) != 0)
{
- vty_out (vty, "Can't chmod configuration file %s: %s (%d).%s",
+ vty_out (vty, "Can't chmod configuration file %s: %s (%d).%s",
config_file, safe_strerror(errno), errno, VTY_NEWLINE);
goto finished;
}
@@ -2640,20 +2631,20 @@ finished:
return ret;
}
-ALIAS (config_write_file,
+ALIAS (config_write_file,
config_write_cmd,
- "write",
+ "write",
"Write running configuration to memory, network, or terminal\n")
-ALIAS (config_write_file,
+ALIAS (config_write_file,
config_write_memory_cmd,
- "write memory",
+ "write memory",
"Write running configuration to memory, network, or terminal\n"
"Write configuration to the file (same as write file)\n")
-ALIAS (config_write_file,
+ALIAS (config_write_file,
copy_runningconfig_startupconfig_cmd,
- "copy running-config startup-config",
+ "copy running-config startup-config",
"Copy configuration\n"
"Copy running config to... \n"
"Copy running config to startup config (same as write file)\n")
@@ -2736,7 +2727,7 @@ DEFUN (show_startup_config,
}
/* Hostname configuration */
-DEFUN (config_hostname,
+DEFUN (config_hostname,
hostname_cmd,
"hostname WORD",
"Set system's network name\n"
@@ -2750,12 +2741,12 @@ DEFUN (config_hostname,
if (host.name)
XFREE (MTYPE_HOST, host.name);
-
+
host.name = XSTRDUP (MTYPE_HOST, argv[0]);
return CMD_SUCCESS;
}
-DEFUN (config_no_hostname,
+DEFUN (config_no_hostname,
no_hostname_cmd,
"no hostname [HOSTNAME]",
NO_STR
@@ -2804,7 +2795,7 @@ DEFUN (config_password, password_cmd,
if (!isalnum ((int) *argv[0]))
{
- vty_out (vty,
+ vty_out (vty,
"Please specify string starting with alphanumeric%s", VTY_NEWLINE);
return CMD_WARNING;
}
@@ -2870,7 +2861,7 @@ DEFUN (config_enable_password, enable_password_cmd,
if (!isalnum ((int) *argv[0]))
{
- vty_out (vty,
+ vty_out (vty,
"Please specify string starting with alphanumeric%s", VTY_NEWLINE);
return CMD_WARNING;
}
@@ -2916,7 +2907,7 @@ DEFUN (no_config_enable_password, no_enable_password_cmd,
return CMD_SUCCESS;
}
-
+
DEFUN (service_password_encrypt,
service_password_encrypt_cmd,
"service password-encryption",
@@ -3068,49 +3059,51 @@ DEFUN (show_logging,
SHOW_STR
"Show current logging configuration\n")
{
- struct zlog *zl = zlog_default;
-
vty_out (vty, "Syslog logging: ");
- if (zl->maxlvl[ZLOG_DEST_SYSLOG] == ZLOG_DISABLED)
+ if (zlog_get_maxlvl(NULL, ZLOG_DEST_SYSLOG) == ZLOG_DISABLED)
vty_out (vty, "disabled");
else
vty_out (vty, "level %s, facility %s, ident %s",
- zlog_priority[zl->maxlvl[ZLOG_DEST_SYSLOG]],
- facility_name(zl->facility), zl->ident);
+ zlog_priority[zlog_get_maxlvl(NULL, ZLOG_DEST_SYSLOG)],
+ facility_name(zlog_get_facility(NULL)), zlog_get_ident(NULL));
vty_out (vty, "%s", VTY_NEWLINE);
vty_out (vty, "Stdout logging: ");
- if (zl->maxlvl[ZLOG_DEST_STDOUT] == ZLOG_DISABLED)
+ if (zlog_get_maxlvl(NULL, ZLOG_DEST_STDOUT) == ZLOG_DISABLED)
vty_out (vty, "disabled");
else
vty_out (vty, "level %s",
- zlog_priority[zl->maxlvl[ZLOG_DEST_STDOUT]]);
+ zlog_priority[zlog_get_maxlvl(NULL, ZLOG_DEST_STDOUT)]);
vty_out (vty, "%s", VTY_NEWLINE);
vty_out (vty, "Monitor logging: ");
- if (zl->maxlvl[ZLOG_DEST_MONITOR] == ZLOG_DISABLED)
+ if (zlog_get_maxlvl(NULL, ZLOG_DEST_MONITOR) == ZLOG_DISABLED)
vty_out (vty, "disabled");
else
vty_out (vty, "level %s",
- zlog_priority[zl->maxlvl[ZLOG_DEST_MONITOR]]);
+ zlog_priority[zlog_get_maxlvl(NULL, ZLOG_DEST_MONITOR)]);
vty_out (vty, "%s", VTY_NEWLINE);
vty_out (vty, "File logging: ");
- if ((zl->maxlvl[ZLOG_DEST_FILE] == ZLOG_DISABLED) ||
- !zl->fp)
+ if ((zlog_get_maxlvl(NULL, ZLOG_DEST_FILE) == ZLOG_DISABLED) ||
+ !zlog_is_file(NULL))
vty_out (vty, "disabled");
else
- vty_out (vty, "level %s, filename %s",
- zlog_priority[zl->maxlvl[ZLOG_DEST_FILE]],
- zl->filename);
+ {
+ char * filename = zlog_get_filename(NULL);
+ vty_out (vty, "level %s, filename %s",
+ zlog_priority[zlog_get_maxlvl(NULL, ZLOG_DEST_FILE)],
+ filename);
+ free(filename);
+ }
vty_out (vty, "%s", VTY_NEWLINE);
vty_out (vty, "Protocol name: %s%s",
- zlog_proto_names[zl->protocol], VTY_NEWLINE);
+ zlog_get_proto_name(NULL), VTY_NEWLINE);
vty_out (vty, "Record priority: %s%s",
- (zl->record_priority ? "enabled" : "disabled"), VTY_NEWLINE);
+ (zlog_get_record_priority(NULL) ? "enabled" : "disabled"), VTY_NEWLINE);
vty_out (vty, "Timestamp precision: %d%s",
- zl->timestamp_precision, VTY_NEWLINE);
+ zlog_get_timestamp_precision(NULL), VTY_NEWLINE);
return CMD_SUCCESS;
}
@@ -3121,7 +3114,7 @@ DEFUN (config_log_stdout,
"Logging control\n"
"Set stdout logging level\n")
{
- zlog_set_level (NULL, ZLOG_DEST_STDOUT, zlog_default->default_lvl);
+ zlog_set_level (NULL, ZLOG_DEST_STDOUT, zlog_get_default_lvl(NULL));
return CMD_SUCCESS;
}
@@ -3158,7 +3151,7 @@ DEFUN (config_log_monitor,
"Logging control\n"
"Set terminal line (monitor) logging level\n")
{
- zlog_set_level (NULL, ZLOG_DEST_MONITOR, zlog_default->default_lvl);
+ zlog_set_level (NULL, ZLOG_DEST_MONITOR, zlog_get_default_lvl(NULL));
return CMD_SUCCESS;
}
@@ -3195,19 +3188,19 @@ set_log_file(struct vty *vty, const char *fname, int loglevel)
int ret;
char *p = NULL;
const char *fullpath;
-
+
/* Path detection. */
if (! IS_DIRECTORY_SEP (*fname))
{
char cwd[MAXPATHLEN+1];
cwd[MAXPATHLEN] = '\0';
-
+
if (getcwd (cwd, MAXPATHLEN) == NULL)
{
zlog_err ("config_log_file: Unable to alloc mem!");
return CMD_WARNING;
}
-
+
if ( (p = XMALLOC (MTYPE_TMP, strlen (cwd) + strlen (fname) + 2))
== NULL)
{
@@ -3246,7 +3239,7 @@ DEFUN (config_log_file,
"Logging to file\n"
"Logging filename\n")
{
- return set_log_file(vty, argv[0], zlog_default->default_lvl);
+ return set_log_file(vty, argv[0], zlog_get_default_lvl(NULL));
}
DEFUN (config_log_file_level,
@@ -3297,7 +3290,7 @@ DEFUN (config_log_syslog,
"Logging control\n"
"Set syslog logging level\n")
{
- zlog_set_level (NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
+ zlog_set_level (NULL, ZLOG_DEST_SYSLOG, zlog_get_default_lvl(NULL));
return CMD_SUCCESS;
}
@@ -3329,8 +3322,8 @@ DEFUN_DEPRECATED (config_log_syslog_facility,
if ((facility = facility_match(argv[0])) < 0)
return CMD_ERR_NO_MATCH;
- zlog_set_level (NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
- zlog_default->facility = facility;
+ zlog_set_level (NULL, ZLOG_DEST_SYSLOG, zlog_get_default_lvl(NULL));
+ zlog_set_facility(NULL, facility);
return CMD_SUCCESS;
}
@@ -3366,7 +3359,7 @@ DEFUN (config_log_facility,
if ((facility = facility_match(argv[0])) < 0)
return CMD_ERR_NO_MATCH;
- zlog_default->facility = facility;
+ zlog_set_facility(NULL, facility);
return CMD_SUCCESS;
}
@@ -3378,7 +3371,7 @@ DEFUN (no_config_log_facility,
"Reset syslog facility to default (daemon)\n"
"Syslog facility\n")
{
- zlog_default->facility = LOG_DAEMON;
+ zlog_set_facility(NULL, LOG_DAEMON);
return CMD_SUCCESS;
}
@@ -3391,14 +3384,11 @@ DEFUN_DEPRECATED (config_log_trap,
{
int new_level ;
int i;
-
+
if ((new_level = level_match(argv[0])) == ZLOG_DISABLED)
return CMD_ERR_NO_MATCH;
- zlog_default->default_lvl = new_level;
- for (i = 0; i < ZLOG_NUM_DESTS; i++)
- if (zlog_default->maxlvl[i] != ZLOG_DISABLED)
- zlog_default->maxlvl[i] = new_level;
+ zlog_set_default_lvl_dest (NULL, new_level);
return CMD_SUCCESS;
}
@@ -3410,7 +3400,7 @@ DEFUN_DEPRECATED (no_config_log_trap,
"Permit all logging information\n"
"Logging level\n")
{
- zlog_default->default_lvl = LOG_DEBUG;
+ zlog_set_default_lvl(NULL, LOG_DEBUG);
return CMD_SUCCESS;
}
@@ -3420,7 +3410,7 @@ DEFUN (config_log_record_priority,
"Logging control\n"
"Log the priority of the message within the message\n")
{
- zlog_default->record_priority = 1 ;
+ zlog_set_record_priority(NULL, 1) ;
return CMD_SUCCESS;
}
@@ -3431,7 +3421,7 @@ DEFUN (no_config_log_record_priority,
"Logging control\n"
"Do not log the priority of the message within the message\n")
{
- zlog_default->record_priority = 0 ;
+ zlog_set_record_priority(NULL, 0) ;
return CMD_SUCCESS;
}
@@ -3443,6 +3433,8 @@ DEFUN (config_log_timestamp_precision,
"Set the timestamp precision\n"
"Number of subsecond digits\n")
{
+ int timestamp_precision;
+
if (argc != 1)
{
vty_out (vty, "Insufficient arguments%s", VTY_NEWLINE);
@@ -3450,7 +3442,9 @@ DEFUN (config_log_timestamp_precision,
}
VTY_GET_INTEGER_RANGE("Timestamp Precision",
- zlog_default->timestamp_precision, argv[0], 0, 6);
+ timestamp_precision, argv[0], 0, 6);
+ zlog_set_timestamp_precision(NULL, timestamp_precision);
+
return CMD_SUCCESS;
}
@@ -3462,7 +3456,7 @@ DEFUN (no_config_log_timestamp_precision,
"Timestamp configuration\n"
"Reset the timestamp precision to the default value of 0\n")
{
- zlog_default->timestamp_precision = 0 ;
+ zlog_set_timestamp_precision(NULL, 0);
return CMD_SUCCESS;
}
@@ -3500,7 +3494,7 @@ DEFUN (no_banner_motd,
"Strings for motd\n")
{
host.motd = NULL;
- if (host.motdfile)
+ if (host.motdfile)
XFREE (MTYPE_HOST, host.motdfile);
host.motdfile = NULL;
return CMD_SUCCESS;
@@ -3540,7 +3534,7 @@ cmd_init (int terminal)
desc_cr.str = XSTRDUP(MTYPE_STRVEC, "");
/* Allocate initial top vector of commands. */
- cmdvec = vector_init (VECTOR_MIN_SIZE);
+ cmdvec = vector_init (0);
/* Default host value settings. */
host.name = NULL;
@@ -3604,7 +3598,7 @@ cmd_init (int terminal)
install_default (CONFIG_NODE);
}
-
+
install_element (CONFIG_NODE, &hostname_cmd);
install_element (CONFIG_NODE, &no_hostname_cmd);
@@ -3667,7 +3661,7 @@ cmd_terminate ()
if (cmdvec)
{
- for (i = 0; i < vector_active (cmdvec); i++)
+ for (i = 0; i < vector_active (cmdvec); i++)
if ((cmd_node = vector_slot (cmdvec, i)) != NULL)
{
cmd_node_v = cmd_node->cmd_vector;
diff --git a/lib/filter.c b/lib/filter.c
index af8d587f..57109854 100644
--- a/lib/filter.c
+++ b/lib/filter.c
@@ -1584,7 +1584,7 @@ filter_show (struct vty *vty, const char *name, afi_t afi)
/* Print the name of the protocol */
if (zlog_default)
vty_out (vty, "%s:%s",
- zlog_proto_names[zlog_default->protocol], VTY_NEWLINE);
+ zlog_get_proto_name(NULL), VTY_NEWLINE);
for (access = master->num.head; access; access = access->next)
{
diff --git a/lib/heap.c b/lib/heap.c
new file mode 100644
index 00000000..35a1b51d
--- /dev/null
+++ b/lib/heap.c
@@ -0,0 +1,517 @@
+/* Generic heap data structure -- functions.
+ * Copyright (C) 2009 Chris Hall (GMCH), Highwayman
+ *
+ * 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.
+ */
+
+#include <zebra.h>
+
+#include "zassert.h"
+#include "heap.h"
+#include "memory.h"
+
+/* Heaps are implemented as a structure which includes a vector structure.
+ * So items in the heap are items in a vector, which are pointers to the item
+ * values.
+ *
+ * The heap structure may be statically allocated, embedded in another
+ * structure, or allocated dynamically. In any case the heap operations
+ * require the address of the heap structure -- see typedef for heap.
+ *
+ * An essential component of a heap is its comparison function. So, a heap
+ * CANNOT be used before it has been initialised and the comparison function
+ * set. (This is unlike a vector, which may be implicitly initialised empty by
+ * zeroising the vector structure.)
+ *
+ * Items may be pushed onto or popped off the heap, which is organised so that
+ * the top item has the smallest value -- according to the heap's comparison
+ * function. (For equal values, the order is undefined.)
+ *
+ * The top item in the heap may be examined, and its value may be updated.
+ * (Updating the top item is more efficient than popping and then pushing it.)
+ *
+ * Items may be deleted from the heap. Items may have their value updated
+ * while they are in the heap. Both of these operations cause the heap to be
+ * reorganised to maintain the heap's partial ordering. Note: these operations
+ * require knowledge of where in the heap the item is -- which, by default, is
+ * done by a linear scan of the heap. For large heaps, there is the option to
+ * keep a "backlink" from the item to it's heap position.
+ *
+ * Vectors may be pushed onto a heap -- copying or moving the contents.
+ *
+ * Heaps may popped to a vector -- copying or moving the contents. The
+ * resulting vector is fully sorted.
+ *
+ * ----------------------------
+ * Comparison function for heap.
+ *
+ * int heap_cmp(...** a, ...** b) ...
+ *
+ * Must return -1, 0, +1 : where -1 => a < b, 0 => a == b & +1 => a > b
+ *
+ * Heap will sort "smallest" to the top. If you want the biggest at the top,
+ * return -1 * usual comparison. Note that the effective heap ordering for
+ * equal values is, essentially, random.
+ *
+ * NB: like other comparison functions (cf qsort) the parameters are pointers
+ * to pointers to the value.
+ *
+ * NB: there should never be NULL items in the heap.
+ */
+
+/*==============================================================================
+ * Initialisation, allocation, reset etc.
+ */
+
+static heap
+heap_setup(heap h, int new_vector, vector_index size, heap_cmp* cmp,
+ int with_backlink, unsigned int backlink_offset) ;
+
+/* Initialize heap -- allocating heap structure if required.
+ *
+ * Does not allocate the underlying vector if the heap is initialised empty.
+ *
+ * eg:
+ *
+ * ... = heap_new_init_simple(NULL, 0, (heap_cmp*)my_cmp)
+ *
+ * See: #define heap_init_new_simple(h, size, cmp)
+ * #define heap_init_new_backlinked(h, size, cmp, offset)
+ *
+ * NB: when initialising an existing heap structure it is ESSENTIAL that
+ * any previous heap and its contents have been released, because this
+ * function simply discards whatever was there before. (This function may
+ * be called to initialise a heap structure which has never been
+ * initialised.)
+ *
+ * Backlink:
+ *
+ * The heap_delete_item and heap_update_item functions need the heap
+ * position of the item. The default way of finding that is to scan the
+ * underlying heap array, looking for the address of the item.
+ *
+ * If either of these functions is done often and on large heaps, it is
+ * possible to speed this up by implementing a 'backlink'. This requires
+ * a field of type heap_backlink_t in the item structure, and it is the
+ * offset of that which must be initialised here, eg:
+ *
+ * ... = heap_new_init_backlinked(NULL, 0, (heap_cmp*)my_cmp,
+ * offset_of(struct xxx_heap_item, backlink)) ;
+ *
+ * This adds a little extra work to every change in the heap -- keeping the
+ * backlink of any moved item up to date. But avoids a linear search for
+ * every heap_delete_item or heap_update_item.
+ *
+ * Returns the heap which has been initialised.
+ */
+heap
+heap_init_new(heap h, unsigned int size, heap_cmp* cmp,
+ int with_backlink, unsigned int backlink_offset)
+{
+ if (h == NULL)
+ h = XCALLOC(MTYPE_HEAP, sizeof(struct heap)) ;
+ else
+ memset(h, 0, sizeof(struct heap)) ;
+
+ return heap_setup(h, 1, size, cmp, with_backlink, backlink_offset) ;
+} ;
+
+/* Reinitialise heap (or create a new one, if h == NULL).
+ *
+ * Allocates heap structure if none given -- allocating vector if size != 0.
+ * Otherwise, re-initialise the heap and any vector (reusing its memory).
+ *
+ * See: #define heap_re_init_simple(h, size, cmp)
+ * #define heap_re_init_backlinked(h, size, cmp, offset)
+ *
+ * NB: when reinitialising an existing heap it is the caller's
+ * responsibility to release any item values *before* doing this.
+ *
+ * Returns the heap that has been reinitialised.
+ */
+heap
+heap_re_init(heap h, unsigned int size, heap_cmp* cmp,
+ int with_backlink, unsigned int backlink_offset)
+{
+ if (h == NULL)
+ return heap_init_new(h, size, cmp, with_backlink, backlink_offset) ;
+ else
+ return heap_setup(h, 0, size, cmp, with_backlink, backlink_offset) ;
+} ;
+
+/* Release heap contents (underlying vector), and (if required) release the
+ * heap structure.
+ *
+ * Returns NULL if releases heap, otherwise the reset heap.
+ *
+ * If does not release the heap, it retains the comparison function and any
+ * backlink setting -- so heap can be reused without reinitialising it.
+ *
+ * NB: it is the callers responsibility to release any heap item values
+ * *before* doing this.
+ */
+heap
+heap_reset(heap h, int free_structure)
+{
+ vector_reset_keep(&h->v) ; /* vector structure is embedded in the heap */
+
+ if (free_structure)
+ XFREE(MTYPE_VECTOR, h) ; /* sets h = NULL */
+
+ return h ;
+} ;
+
+/* Common set-up for heap_init_new() & heap_reset().
+ */
+static heap
+heap_setup(heap h, int new_vector, unsigned int size, heap_cmp* cmp,
+ int with_backlink, unsigned int backlink_offset)
+{
+ assert(cmp != NULL) ; /* or there will be tears */
+
+ h->cmp = cmp ;
+ h->state = with_backlink ? Heap_Has_Backlink : 0 ;
+ h->backlink_offset = backlink_offset ;
+
+ if (new_vector)
+ vector_init_new(&h->v, size) ;
+ else
+ vector_re_init(&h->v, size) ;
+
+ return h ;
+} ;
+
+/* Ream (another) item out of the given heap.
+ *
+ * If heap is empty, release the underlying vector, and (if required) release
+ * the heap structure.
+ *
+ * See: #define heap_ream_free(h) heap_ream(h, 1)
+ * #define heap_ream_keep(h) heap_ream(h, 0)
+ *
+ * Useful for emptying out and resetting/discarding a heap:
+ *
+ * while ((p_v = heap_ream_free(h)))
+ * ... do what's required to release the item p_v
+ *
+ * Returns NULL when heap is empty (and structure has been freed, if required).
+ *
+ * If does not release the heap, it retains the comparison function and any
+ * backlink setting -- so heap can be reused without reinitialising it.
+ *
+ * NB: once the process of reaming a heap has started: (a) MUST NOT attempt to
+ * use the heap until process completes, and (b) MUST complete the process.
+ *
+ * NB: items are reamed out in no defined order.
+ */
+p_vector_item
+heap_ream(heap h, int free_structure)
+{
+ p_vector_item p_v ;
+
+ if (h == NULL)
+ return NULL ;
+
+ if ((p_v = vector_ream_keep(&h->v)) == NULL)
+ heap_reset(h, free_structure) ;
+
+ return p_v ;
+} ;
+
+/*==============================================================================
+ * Simple Heap Operations -- see also the Inline functions.
+ */
+
+/* Pop item off the heap.
+ *
+ * Returns the popped value, which is NULL if the heap was (and still is) empty.
+ */
+p_vector_item
+heap_pop_item(heap h)
+{
+ p_vector_item p_v ;
+ p_vector_item p_x ;
+
+ p_v = vector_pop_item(&h->v) ; /* extract last item, if any */
+ if ((p_v == NULL) || (h->v.end == 0))
+ return p_v ; /* done if empty or last was also first */
+
+ p_x = h->v.p_items[0] ; /* this is what we are popping */
+
+ heap_bubble_down(h, 0, p_v) ; /* reposition what was the last item */
+ /* updating any backlink */
+ return p_x ;
+} ;
+
+/* Pop one item off the heap and promptly push another.
+ *
+ * In this combination, the pop is essentially free.
+ *
+ * Returns the popped value, which is NULL if the heap was (and still is) empty.
+ */
+p_vector_item
+heap_pop_push_item(heap h, p_vector_item p_v)
+{
+ p_vector_item p_x ;
+
+ dassert(p_v != NULL) ; /* no NULLs, thank you. */
+
+ p_x = heap_top_item(h) ; /* what we are popping */
+
+ if (p_x == NULL)
+ heap_push_item(h, p_v) ; /* for empty heap, this deals with */
+ /* extending heap etc. */
+ else
+ heap_bubble_down(h, 0, p_v) ; /* position the replacement */
+ /* setting any backlink */
+ return p_x ;
+} ;
+
+/*==============================================================================
+ * Heap Operations which use 'backlink', if implemented.
+ */
+
+/* Delete given item from the heap.
+ *
+ * See notes on backlink, above.
+ *
+ * NB: do NOT try this on items which are not in the given heap !
+ */
+void
+heap_delete_item(heap h, p_vector_item p_v)
+{
+ p_vector_item p_x ;
+ vector_index i ;
+
+ i = heap_find_item(h, p_v) ; /* index of item to be deleted */
+
+ p_x = vector_pop_item(&h->v) ; /* extract last item, if any */
+
+ if (i < h->v.end) /* if not deleting the last item... */
+ heap_bubble(h, i, p_x) ; /* ...reinsert what was last, at the delete */
+ /* position, updating any backlink */
+} ;
+
+/*==============================================================================
+ * Other Heap Operations.
+ */
+
+/* Push entire vector onto heap copying or moving items as required.
+ *
+ * Copy or move vector to end of heap's vector, then move each
+ * (non-NULL) item into heap order (discarding any NULL items).
+ *
+ * See: #define heap_push_vector_copy(h, v)
+ * #define heap_push_vector_move(h, v)
+ */
+void
+heap_push_vector(heap h, vector v, int move_vector)
+{
+ vector_index i = h->v.end ;
+ vector_index e ;
+ vector_index n = v->end ;
+ p_vector_item p_v ;
+
+ if (move_vector)
+ vector_move_append(&h->v, v) ;
+ else
+ vector_copy_append(&h->v, v) ;
+
+ e = i ; /* old end of the heap. */
+ while (n--) {
+ p_v = h->v.p_items[i++] ;
+ if (p_v != NULL)
+ heap_bubble_up(h, e++, p_v) ; /* move new item into position in heap */
+ /* setting any backlink */
+ } ;
+
+ h->v.end = e ; /* new end of heap */
+} ;
+
+/* Pop given heap to vector -- creating vector if required (v == NULL).
+ *
+ * Resulting vector is fully sorted.
+ *
+ * Moves or copies the contents of the heap.
+ *
+ * See: #define heap_pop_vector_copy(v, h)
+ * #define heap_pop_vector_move(v, h)
+ *
+ * NB: when creating new vector, will be exactly the required size.
+ *
+ * NB: if re-initialising existing vector, it is the caller's responsibility
+ * to release any existing items if that is required.
+ *
+ * NB: if re-initialising existing vector, it is the caller's responsibility
+ * to ensure the vector structure is currently valid.
+ */
+vector
+heap_pop_vector(vector v, heap h, int move_heap)
+{
+ vector_index n = h->v.end ;
+ vector_index i ;
+
+ v = vector_re_init(v, n) ; /* guarantees >= 'n' items in vector */
+ v->end = n ;
+
+ for (i = 0 ; i < n ; i++)
+ v->p_items[i] = heap_pop_item(h) ;
+
+ if (!move_heap)
+ vector_copy_here(&h->v, v) ; /* fully sorted is also heap ordered ! */
+
+ return v ;
+} ;
+
+/*==============================================================================
+ * The Heap internal mechanics.
+ */
+
+/* Returns pointer to backlink value in heap item: lvalue or rvalue */
+#define HEAP_BACKLINK(h, p_v) \
+ *(heap_backlink_t*)((char*)(p_v) + (h)->backlink_offset)
+/* Sets backlink, if required. */
+#define heap_set_backlink(h, p_v, i) \
+ if ((h)->state & Heap_Has_Backlink) HEAP_BACKLINK(h, p_v) = (i)
+
+/* Returns index of parent. */
+#define HEAP_UP(i) (((i) - 1) / 2)
+/* Returns index of left child. */
+#define HEAP_DOWN(i) (((i) * 2) + 1)
+
+/* Insert given item in the required place in heap, given that there is now
+ * a hole at the given position -- may move up or down the heap, or stay put.
+ *
+ * Bubbles up or down as required.
+ *
+ * Note that this sets the backlink on the given item.
+ */
+private void
+heap_bubble(heap h, vector_index i, p_vector_item p_v)
+{
+ /* If this is < parent, we bubble upwards. */
+ if ((i != 0) && (h->cmp(&p_v, &h->v.p_items[HEAP_UP(i)]) < 0))
+ heap_bubble_up(h, i, p_v) ;
+ /* Otherwise we try bubbling downwards. */
+ else
+ heap_bubble_down(h, i, p_v) ;
+} ;
+
+/* Insert given item in the required place in heap, given that there is now
+ * a hole at the given position -- where we know may *only* move up the heap.
+ *
+ * Note that this sets the backlink on the given item.
+ *
+ * NB: ignores anything in the heap beyond 'i' -- in particular does not use
+ * v.end at all. So this can be used to work along a vector and bring
+ * items into heap order.
+ */
+private void
+heap_bubble_up(heap h, vector_index i, p_vector_item p_v)
+{
+ p_vector_item* ha = h->v.p_items ; /* underlying array */
+ vector_index ip ; /* index of parent */
+ p_vector_item p_p ; /* pointer to parent item */
+
+ dassert(ha != NULL) ;
+
+ while (i != 0)
+ {
+ ip = HEAP_UP(i) ;
+ p_p = &ha[ip] ; /* get parent */
+
+ if (h->cmp(&p_v, &p_p) >= 0)
+ break ; /* stop when value >= parent */
+
+ ha[i] = p_p ; /* move parent down... */
+ heap_set_backlink(h, p_p, i) ; /* ...updating any backlink */
+
+ i = ip ; /* move up the heap */
+ } ;
+
+ ha[i] = p_v ; /* place in new position... */
+ heap_set_backlink(h, p_v, i) ; /* ...updating any backlink */
+} ;
+
+/* Insert given item in the required place in heap, given that there is now
+ * a hole at the given position -- where we know may *only* move down the heap.
+ *
+ * Note that this sets the backlink on the given item.
+ */
+private void
+heap_bubble_down(heap h, vector_index i, p_vector_item p_v)
+{
+ vector_index e = h->v.end ; /* end of heap */
+ vector_index ic ; /* index of child */
+ vector_index is ; /* index of sibling */
+ p_vector_item p_c ; /* pointer to child */
+ p_vector_item p_s ; /* pointer to sibling */
+
+ p_vector_item* ha = h->v.p_items ; /* underlying array */
+ dassert(ha != NULL) ;
+
+ while (1)
+ {
+ ic = HEAP_DOWN(i) ;
+ if (ic >= e)
+ break ; /* Quit if run out of heap ! */
+ p_c = &ha[ic] ; /* get left hand child */
+
+ is = ic + 1 ;
+ if (is < e) /* is there a right hand child ? */
+ {
+ p_s = &ha[is] ; /* get right hand child */
+ if (h->cmp(&p_s, &p_c) < 0)
+ {
+ ic = is ; /* select smaller sibling */
+ p_c = p_s ;
+ } ;
+ } ;
+
+ if (h->cmp(&p_v, &p_c) <= 0)
+ break ; /* stop when <= both children */
+
+ ha[i] = p_c ; /* move smaller child up */
+ heap_set_backlink(h, p_c, i) ; /* ...updating any backlink */
+
+ i = ic ; /* move down the heap */
+ } ;
+
+ ha[i] = p_v ; /* place in new position... */
+ heap_set_backlink(h, p_v, i) ; /* ...updating any backlink */
+} ;
+
+/* Find index of given item in the given heap. */
+private vector_index
+heap_find_item(heap h, p_vector_item p_v)
+{
+ vector_index i ;
+
+ if (h->state & Heap_Has_Backlink)
+ i = HEAP_BACKLINK(h, p_v) ;
+ else
+ {
+ for (i = 0 ; i < h->v.end ; ++i)
+ if (h->v.p_items[i] == p_v)
+ return i ;
+ } ;
+
+ assert((i < h->v.end) && (h->v.p_items[i] == p_v)) ;
+
+ return i ;
+} ;
diff --git a/lib/heap.h b/lib/heap.h
new file mode 100644
index 00000000..bd984398
--- /dev/null
+++ b/lib/heap.h
@@ -0,0 +1,160 @@
+/* Generic heap data structure -- header.
+ * Copyright (C) 2009 Chris Hall (GMCH), Highwayman
+ *.
+ * This file is part of GNU Zebra.
+ *
+ * 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 _ZEBRA_HEAP_H
+#define _ZEBRA_HEAP_H
+
+#include "vector.h"
+
+/* Macro in case there are particular compiler issues. */
+#ifndef Inline
+ #define Inline static inline
+#endif
+
+/*==============================================================================
+ * Data structures etc.
+ */
+
+typedef int heap_cmp(p_vector_item* a, p_vector_item*) ;
+
+enum heap_state {
+ Heap_Has_Backlink = 0x01, /* Set if backlink set */
+} ;
+
+typedef vector_index heap_backlink_t ;
+
+typedef struct heap* heap ;
+
+struct heap
+{
+ heap_cmp* cmp ;
+
+ enum heap_state state ;
+ unsigned int backlink_offset ;
+
+ struct vector v ;
+} ;
+
+/*==============================================================================
+ * Prototypes.
+ */
+
+extern heap heap_init_new(heap h, unsigned int size, heap_cmp* cmp,
+ int with_backlink, unsigned int backlink_offset) ;
+#define heap_init_new_simple(h, size, cmp) \
+ heap_init_new(h, size, cmp, 0, 0)
+#define heap_init_new_backlinked(h, size, cmp, offset) \
+ heap_init_new(h, size, cmp, 1, offset)
+
+extern heap heap_re_init(heap h, unsigned int size, heap_cmp* cmp,
+ int with_backlink, unsigned int backlink_offset) ;
+#define heap_re_init_simple(h, size, cmp) \
+ heap_re_init(h, size, cmp, 0, 0)
+#define heap_re_init_backlinked(h, size, cmp, offset) \
+ heap_re_init(h, size, cmp, 1, offset)
+
+extern heap heap_reset(heap h, int free_structure) ;
+extern p_vector_item heap_ream(heap h, int free_structure) ;
+
+/* Reset heap and free the heap structure. */
+#define heap_reset_free(h) heap_reset(h, 1)
+/* Reset heap but keep the heap structure. */
+#define heap_reset_keep(h) heap_reset(h, 0)
+/* Ream out heap and free the heap structure. */
+#define heap_ream_free(h) heap_ream(h, 1)
+/* Ream out heap but keep the heap structure. */
+#define heap_ream_keep(h) heap_ream(h, 0)
+
+Inline void heap_push_item(heap h, p_vector_item p_v) ;
+extern p_vector_item heap_pop_item(heap h) ;
+extern p_vector_item heap_pop_push_item(heap h, p_vector_item p_v) ;
+Inline p_vector_item heap_top_item(heap h) ;
+Inline void heap_update_top_item(heap h) ;
+
+extern void heap_delete_item(heap h, p_vector_item p_v) ;
+Inline void heap_update_item(heap h, p_vector_item p_v) ;
+
+extern void heap_push_vector(heap h, vector v, int move_vector) ;
+#define heap_push_vector_copy(h, v) \
+ heap_push_vector(h, v, 0)
+#define heap_push_vector_move(h, v) \
+ heap_push_vector(h, v, 1)
+extern vector heap_pop_vector(vector v, heap h, int move_heap) ;
+#define heap_pop_vector_copy(v, h) \
+ heap_pop_vector(v, h, 0)
+#define heap_pop_vector_move(v, h) \
+ heap_pop_vector(v, h, 1)
+
+/*==============================================================================
+ * This are extern only for use in Inline and other friends
+ */
+
+#ifndef private
+ #define private extern
+#endif
+
+private void
+heap_bubble(heap h, vector_index i, p_vector_item p_v) ;
+
+private void
+heap_bubble_up(heap h, vector_index i, p_vector_item p_v) ;
+
+private void
+heap_bubble_down(heap h, vector_index i, p_vector_item p_v) ;
+
+private vector_index
+heap_find_item(heap h, p_vector_item p_v) ;
+
+/*==============================================================================
+ * Inline Functions
+ */
+
+/* Push given item onto the heap
+ */
+Inline void
+heap_push_item(heap h, p_vector_item p_v)
+{
+ dassert(p_v != NULL) ; /* no NULLs, thank you. */
+ heap_bubble_up(h, vector_extend_by_1(&h->v), p_v) ;
+} ;
+
+/* Get copy of top heap item (does not pop).
+ *
+ * Returns NULL if heap is empty.
+ */
+Inline p_vector_item
+heap_top_item(heap h)
+{
+ return vector_get_first_item(&h->v) ; /* if any */
+} ;
+
+/* Update heap to reflect new value of top item.
+ */
+Inline void
+heap_update_top_item(heap h)
+{
+ heap_bubble_down(h, 0, heap_top_item(h)) ;
+} ;
+
+/* Update heap to reflect new value of given item.
+ */
+Inline void
+heap_update_item(heap h, p_vector_item p_v)
+{
+ heap_bubble(h, heap_find_item(h, p_v), p_v) ;
+} ;
+
+#endif /* _ZEBRA_HEAP_H */
diff --git a/lib/log.c b/lib/log.c
index 0c2f655b..81624f58 100644
--- a/lib/log.c
+++ b/lib/log.c
@@ -34,6 +34,24 @@
#ifdef HAVE_UCONTEXT_H
#include <ucontext.h>
#endif
+#include "qpthreads.h"
+
+#ifdef NDEBUG
+#define LOCK qpt_mutex_lock(vty_mutex);
+#define UNLOCK qpt_mutex_unlock(vty_mutex);
+#else
+#define LOCK qpt_mutex_lock(vty_mutex);++vty_lock_count;
+#define UNLOCK --vty_lock_count;qpt_mutex_unlock(vty_mutex);
+#endif
+
+/* log is protected by the same mutext as vty, see comments in vty.c */
+
+/* prototypes */
+static int uzlog_reset_file (struct zlog *zl);
+static void zlog_abort (const char *mess) __attribute__ ((noreturn));
+static void vzlog (struct zlog *zl, int priority, const char *format, va_list args);
+static void uzlog_backtrace(int priority);
+static void uvzlog (struct zlog *zl, int priority, const char *format, va_list args);
static int logfile_fd = -1; /* Used in signal handler. */
@@ -66,14 +84,23 @@ const char *zlog_priority[] =
"debugging",
NULL,
};
-
-
/* For time string format. */
size_t
quagga_timestamp(int timestamp_precision, char *buf, size_t buflen)
{
+ size_t result;
+ LOCK
+ result = uquagga_timestamp(timestamp_precision, buf, buflen);
+ UNLOCK
+ return result;
+}
+
+/* unprotected version for when mutex already held */
+size_t
+uquagga_timestamp(int timestamp_precision, char *buf, size_t buflen)
+{
static struct {
time_t last;
size_t len;
@@ -81,6 +108,8 @@ quagga_timestamp(int timestamp_precision, char *buf, size_t buflen)
} cache;
struct timeval clock;
+ size_t result = 0;
+
/* would it be sufficient to use global 'recent_time' here? I fear not... */
gettimeofday(&clock, NULL);
@@ -122,14 +151,19 @@ quagga_timestamp(int timestamp_precision, char *buf, size_t buflen)
}
while (--prec > 0);
*p = '.';
- return cache.len+1+timestamp_precision;
+ result = cache.len+1+timestamp_precision;
}
- buf[cache.len] = '\0';
- return cache.len;
+ else
+ {
+ buf[cache.len] = '\0';
+ result = cache.len;
+ }
+ } else {
+ if (buflen > 0)
+ buf[0] = '\0';
}
- if (buflen > 0)
- buf[0] = '\0';
- return 0;
+
+ return result;
}
/* Utility routine for current time printing. */
@@ -138,20 +172,30 @@ time_print(FILE *fp, struct timestamp_control *ctl)
{
if (!ctl->already_rendered)
{
- ctl->len = quagga_timestamp(ctl->precision, ctl->buf, sizeof(ctl->buf));
+ ctl->len = uquagga_timestamp(ctl->precision, ctl->buf, sizeof(ctl->buf));
ctl->already_rendered = 1;
}
fprintf(fp, "%s ", ctl->buf);
}
-
/* va_list version of zlog. */
static void
vzlog (struct zlog *zl, int priority, const char *format, va_list args)
{
+ LOCK
+ uvzlog(zl, priority, format, args);
+ UNLOCK
+}
+
+/* va_list version of zlog. Unprotected assumes mutex already held*/
+static void
+uvzlog (struct zlog *zl, int priority, const char *format, va_list args)
+{
struct timestamp_control tsctl;
tsctl.already_rendered = 0;
+ assert(vty_lock_count);
+
/* If zlog is not specified, use default one. */
if (zl == NULL)
zl = zlog_default;
@@ -165,55 +209,58 @@ vzlog (struct zlog *zl, int priority, const char *format, va_list args)
vfprintf (stderr, format, args);
fprintf (stderr, "\n");
fflush (stderr);
-
- /* In this case we return at here. */
- return;
}
- tsctl.precision = zl->timestamp_precision;
-
- /* Syslog output */
- if (priority <= zl->maxlvl[ZLOG_DEST_SYSLOG])
+ else
{
- va_list ac;
- va_copy(ac, args);
- vsyslog (priority|zlog_default->facility, format, ac);
- va_end(ac);
- }
+ tsctl.precision = zl->timestamp_precision;
- /* File output. */
- if ((priority <= zl->maxlvl[ZLOG_DEST_FILE]) && zl->fp)
- {
- va_list ac;
- time_print (zl->fp, &tsctl);
- if (zl->record_priority)
- fprintf (zl->fp, "%s: ", zlog_priority[priority]);
- fprintf (zl->fp, "%s: ", zlog_proto_names[zl->protocol]);
- va_copy(ac, args);
- vfprintf (zl->fp, format, ac);
- va_end(ac);
- fprintf (zl->fp, "\n");
- fflush (zl->fp);
- }
+ /* Syslog output */
+ if (priority <= zl->maxlvl[ZLOG_DEST_SYSLOG])
+ {
+ va_list ac;
+ va_copy(ac, args);
+ vsyslog (priority|zlog_default->facility, format, ac);
+ va_end(ac);
+ }
- /* stdout output. */
- if (priority <= zl->maxlvl[ZLOG_DEST_STDOUT])
- {
- va_list ac;
- time_print (stdout, &tsctl);
- if (zl->record_priority)
- fprintf (stdout, "%s: ", zlog_priority[priority]);
- fprintf (stdout, "%s: ", zlog_proto_names[zl->protocol]);
- va_copy(ac, args);
- vfprintf (stdout, format, ac);
- va_end(ac);
- fprintf (stdout, "\n");
- fflush (stdout);
- }
+ /* File output. */
+ if ((priority <= zl->maxlvl[ZLOG_DEST_FILE]) && zl->fp)
+ {
+ va_list ac;
+ time_print (zl->fp, &tsctl);
+ if (zl->record_priority)
+ fprintf (zl->fp, "%s: ", zlog_priority[priority]);
+ fprintf (zl->fp, "%s: ", zlog_proto_names[zl->protocol]);
+ va_copy(ac, args);
+ vfprintf (zl->fp, format, ac);
+ va_end(ac);
+ fprintf (zl->fp, "\n");
+ fflush (zl->fp);
+ }
- /* Terminal monitor. */
- if (priority <= zl->maxlvl[ZLOG_DEST_MONITOR])
- vty_log ((zl->record_priority ? zlog_priority[priority] : NULL),
- zlog_proto_names[zl->protocol], format, &tsctl, args);
+ /* stdout output. */
+ if (priority <= zl->maxlvl[ZLOG_DEST_STDOUT])
+ {
+ va_list ac;
+ time_print (stdout, &tsctl);
+ if (zl->record_priority)
+ fprintf (stdout, "%s: ", zlog_priority[priority]);
+ fprintf (stdout, "%s: ", zlog_proto_names[zl->protocol]);
+ va_copy(ac, args);
+ vfprintf (stdout, format, ac);
+ va_end(ac);
+ fprintf (stdout, "\n");
+ fflush (stdout);
+ }
+
+ /* Terminal monitor. */
+ if (priority <= zl->maxlvl[ZLOG_DEST_MONITOR])
+ {
+ const char *priority_name = (zl->record_priority ? zlog_priority[priority] : NULL);
+ const char *proto_name = zlog_proto_names[zl->protocol];
+ vty_log (priority_name, proto_name, format, &tsctl, args);
+ }
+ }
}
static char *
@@ -518,8 +565,16 @@ zlog_backtrace_sigsafe(int priority, void *program_counter)
void
zlog_backtrace(int priority)
{
+ LOCK
+ zlog_backtrace(priority);
+ UNLOCK
+}
+
+static void
+uzlog_backtrace(int priority)
+{
#ifndef HAVE_GLIBC_BACKTRACE
- zlog(NULL, priority, "No backtrace available on this platform.");
+ uzlog(NULL, priority, "No backtrace available on this platform.");
#else
void *array[20];
int size, i;
@@ -528,27 +583,38 @@ zlog_backtrace(int priority)
if (((size = backtrace(array,sizeof(array)/sizeof(array[0]))) <= 0) ||
((size_t)size > sizeof(array)/sizeof(array[0])))
{
- zlog_err("Cannot get backtrace, returned invalid # of frames %d "
+ uzlog(NULL, LOG_ERR, "Cannot get backtrace, returned invalid # of frames %d "
"(valid range is between 1 and %lu)",
size, (unsigned long)(sizeof(array)/sizeof(array[0])));
return;
}
- zlog(NULL, priority, "Backtrace for %d stack frames:", size);
+ uzlog(NULL, priority, "Backtrace for %d stack frames:", size);
if (!(strings = backtrace_symbols(array, size)))
{
- zlog_err("Cannot get backtrace symbols (out of memory?)");
+ uzlog(NULL, LOG_ERR, "Cannot get backtrace symbols (out of memory?)");
for (i = 0; i < size; i++)
- zlog(NULL, priority, "[bt %d] %p",i,array[i]);
+ uzlog(NULL, priority, "[bt %d] %p",i,array[i]);
}
else
{
for (i = 0; i < size; i++)
- zlog(NULL, priority, "[bt %d] %s",i,strings[i]);
+ uzlog(NULL, priority, "[bt %d] %s",i,strings[i]);
free(strings);
}
#endif /* HAVE_GLIBC_BACKTRACE */
}
+/* unlocked version */
+void
+uzlog (struct zlog *zl, int priority, const char *format, ...)
+{
+ va_list args;
+
+ va_start(args, format);
+ uvzlog (zl, priority, format, args);
+ va_end (args);
+}
+
void
zlog (struct zlog *zl, int priority, const char *format, ...)
{
@@ -605,16 +671,64 @@ PLOG_FUNC(plog_debug, LOG_DEBUG)
void
_zlog_assert_failed (const char *assertion, const char *file,
- unsigned int line, const char *function)
+ unsigned int line, const char *function)
+{
+ const static size_t buff_size = 1024;
+ char buff[buff_size];
+ snprintf(buff, buff_size,
+ "Assertion `%s' failed in file %s, line %u, function %s",
+ assertion, file, line, (function ? function : "?"));
+ zlog_abort(buff);
+}
+
+/* Abort with message */
+void
+_zlog_abort_mess (const char *mess, const char *file,
+ unsigned int line, const char *function)
+{
+ const static size_t buff_size = 1024;
+ char buff[buff_size];
+ snprintf(buff, buff_size, "%s, in file %s, line %u, function %s",
+ mess, file, line, (function ? function : "?"));
+ zlog_abort(buff);
+}
+
+/* Abort with message and errno and strerror() thereof */
+void
+_zlog_abort_errno (const char *mess, const char *file,
+ unsigned int line, const char *function)
+{
+ _zlog_abort_err(mess, errno, file, line, function);
+}
+
+/* Abort with message and given error and strerror() thereof */
+void
+_zlog_abort_err (const char *mess, int err, const char *file,
+ unsigned int line, const char *function)
+{
+ const static size_t buff_size = 1024;
+ char buff[buff_size];
+ char err_mess[buff_size];
+ strerror_r(err, err_mess, buff_size);
+ snprintf(buff, buff_size,
+ "%s, in file %s, line %u, function %s, error %d \"%s\"",
+ mess, file, line, (function ? function : "?"),
+ err, err_mess);
+ zlog_abort(buff);
+}
+
+
+static void
+zlog_abort (const char *mess)
{
/* Force fallback file logging? */
if (zlog_default && !zlog_default->fp &&
((logfile_fd = open_crashlog()) >= 0) &&
((zlog_default->fp = fdopen(logfile_fd, "w")) != NULL))
zlog_default->maxlvl[ZLOG_DEST_FILE] = LOG_ERR;
- zlog(NULL, LOG_CRIT, "Assertion `%s' failed in file %s, line %u, function %s",
- assertion,file,line,(function ? function : "?"));
- zlog_backtrace(LOG_CRIT);
+
+ uzlog(NULL, LOG_CRIT, "%s", mess);
+ uzlog_backtrace(LOG_CRIT);
abort();
}
@@ -648,22 +762,33 @@ openzlog (const char *progname, zlog_proto_t protocol,
void
closezlog (struct zlog *zl)
{
+ LOCK
+
closelog();
if (zl->fp != NULL)
fclose (zl->fp);
XFREE (MTYPE_ZLOG, zl);
+
+ UNLOCK
}
/* Called from command.c. */
void
zlog_set_level (struct zlog *zl, zlog_dest_t dest, int log_level)
{
+ LOCK
+
if (zl == NULL)
zl = zlog_default;
- zl->maxlvl[dest] = log_level;
+ if (zl != NULL)
+ {
+ zl->maxlvl[dest] = log_level;
+ }
+
+ UNLOCK
}
int
@@ -671,46 +796,68 @@ zlog_set_file (struct zlog *zl, const char *filename, int log_level)
{
FILE *fp;
mode_t oldumask;
+ int result = 1;
+
+ LOCK
/* There is opend file. */
- zlog_reset_file (zl);
+ uzlog_reset_file (zl);
/* Set default zl. */
if (zl == NULL)
zl = zlog_default;
- /* Open file. */
- oldumask = umask (0777 & ~LOGFILE_MASK);
- fp = fopen (filename, "a");
- umask(oldumask);
- if (fp == NULL)
- return 0;
-
- /* Set flags. */
- zl->filename = strdup (filename);
- zl->maxlvl[ZLOG_DEST_FILE] = log_level;
- zl->fp = fp;
- logfile_fd = fileno(fp);
+ if (zl != NULL)
+ {
+ /* Open file. */
+ oldumask = umask (0777 & ~LOGFILE_MASK);
+ fp = fopen (filename, "a");
+ umask(oldumask);
+ if (fp == NULL)
+ result = 0;
+ else
+ {
+ /* Set flags. */
+ zl->filename = strdup (filename);
+ zl->maxlvl[ZLOG_DEST_FILE] = log_level;
+ zl->fp = fp;
+ logfile_fd = fileno(fp);
+ }
+ }
- return 1;
+ UNLOCK
+ return result;
}
/* Reset opend file. */
int
zlog_reset_file (struct zlog *zl)
{
+ int result;
+ LOCK
+ result = uzlog_reset_file(zl);
+ UNLOCK
+ return result;
+}
+
+static int
+uzlog_reset_file (struct zlog *zl)
+ {
if (zl == NULL)
zl = zlog_default;
- if (zl->fp)
- fclose (zl->fp);
- zl->fp = NULL;
- logfile_fd = -1;
- zl->maxlvl[ZLOG_DEST_FILE] = ZLOG_DISABLED;
-
- if (zl->filename)
- free (zl->filename);
- zl->filename = NULL;
+ if (zl != NULL)
+ {
+ if (zl->fp)
+ fclose (zl->fp);
+ zl->fp = NULL;
+ logfile_fd = -1;
+ zl->maxlvl[ZLOG_DEST_FILE] = ZLOG_DISABLED;
+
+ if (zl->filename)
+ free (zl->filename);
+ zl->filename = NULL;
+ }
return 1;
}
@@ -720,39 +867,318 @@ int
zlog_rotate (struct zlog *zl)
{
int level;
+ int result = 1;
+
+ LOCK
if (zl == NULL)
zl = zlog_default;
- if (zl->fp)
- fclose (zl->fp);
- zl->fp = NULL;
- logfile_fd = -1;
- level = zl->maxlvl[ZLOG_DEST_FILE];
- zl->maxlvl[ZLOG_DEST_FILE] = ZLOG_DISABLED;
+ if (zl != NULL)
+ {
+ if (zl->fp)
+ fclose (zl->fp);
+ zl->fp = NULL;
+ logfile_fd = -1;
+ level = zl->maxlvl[ZLOG_DEST_FILE];
+ zl->maxlvl[ZLOG_DEST_FILE] = ZLOG_DISABLED;
+
+ if (zl->filename)
+ {
+ mode_t oldumask;
+ int save_errno;
+
+ oldumask = umask (0777 & ~LOGFILE_MASK);
+ zl->fp = fopen (zl->filename, "a");
+ save_errno = errno;
+ umask(oldumask);
+ if (zl->fp == NULL)
+ {
+ /* can't call logging while locked */
+ char *fname = strdup(zl->filename);
+ uzlog(NULL, LOG_ERR, "Log rotate failed: cannot open file %s for append: %s",
+ fname, safe_strerror(save_errno));
+ free(fname);
+ result = -1;
+ }
+ else
+ {
+ logfile_fd = fileno(zl->fp);
+ zl->maxlvl[ZLOG_DEST_FILE] = level;
+ }
+ }
+ }
+ UNLOCK
+ return result;
+}
- if (zl->filename)
+int
+zlog_get_default_lvl (struct zlog *zl)
+{
+ int result = LOG_DEBUG;
+
+ LOCK
+
+ if (zl == NULL)
+ zl = zlog_default;
+
+ if (zl != NULL)
{
- mode_t oldumask;
- int save_errno;
+ result = zl->default_lvl;
+ }
- oldumask = umask (0777 & ~LOGFILE_MASK);
- zl->fp = fopen (zl->filename, "a");
- save_errno = errno;
- umask(oldumask);
- if (zl->fp == NULL)
- {
- zlog_err("Log rotate failed: cannot open file %s for append: %s",
- zl->filename, safe_strerror(save_errno));
- return -1;
- }
- logfile_fd = fileno(zl->fp);
- zl->maxlvl[ZLOG_DEST_FILE] = level;
+ UNLOCK
+ return result;
+}
+
+void
+zlog_set_default_lvl (struct zlog *zl, int level)
+{
+ LOCK
+
+ if (zl == NULL)
+ zl = zlog_default;
+
+ if (zl != NULL)
+ {
+ zl->default_lvl = level;
}
- return 1;
+ UNLOCK
}
-
+
+/* Set logging level and default for all destinations */
+void
+zlog_set_default_lvl_dest (struct zlog *zl, int level)
+{
+ int i;
+
+ LOCK
+
+ if (zl == NULL)
+ zl = zlog_default;
+
+ if (zl != NULL)
+ {
+ zl->default_lvl = level;
+
+ for (i = 0; i < ZLOG_NUM_DESTS; i++)
+ if (zl->maxlvl[i] != ZLOG_DISABLED)
+ zl->maxlvl[i] = level;
+ }
+
+ UNLOCK
+}
+
+int
+zlog_get_maxlvl (struct zlog *zl, zlog_dest_t dest)
+{
+ int result = ZLOG_DISABLED;
+
+ LOCK
+
+ if (zl == NULL)
+ zl = zlog_default;
+
+ if (zl != NULL)
+ {
+ result = zl->maxlvl[dest];
+ }
+
+ UNLOCK
+ return result;
+}
+
+int
+zlog_get_facility (struct zlog *zl)
+{
+ int result = LOG_DAEMON;
+
+ LOCK
+
+ if (zl == NULL)
+ zl = zlog_default;
+
+ if (zl != NULL)
+ {
+ result = zl->facility;
+ }
+
+ UNLOCK
+ return result;
+}
+
+void
+zlog_set_facility (struct zlog *zl, int facility)
+{
+ LOCK
+
+ if (zl == NULL)
+ zl = zlog_default;
+
+ if (zl != NULL)
+ {
+ zl->facility = facility;
+ }
+
+ UNLOCK
+}
+
+int
+zlog_get_record_priority (struct zlog *zl)
+{
+ int result = 0;
+
+ LOCK
+
+ if (zl == NULL)
+ zl = zlog_default;
+
+ if (zl != NULL)
+ {
+ result = zl->record_priority;
+ }
+
+ UNLOCK
+ return result;
+}
+
+void
+zlog_set_record_priority (struct zlog *zl, int record_priority)
+{
+ LOCK
+
+ if (zl == NULL)
+ zl = zlog_default;
+
+ if (zl != NULL)
+ {
+ zl->record_priority = record_priority;
+ }
+ UNLOCK
+}
+
+int
+zlog_get_timestamp_precision (struct zlog *zl)
+{
+ int result = 0;
+
+ LOCK
+
+ if (zl == NULL)
+ zl = zlog_default;
+
+ if (zl != NULL)
+ {
+ result = zl->timestamp_precision;
+ }
+ UNLOCK
+ return result;
+}
+
+void
+zlog_set_timestamp_precision (struct zlog *zl, int timestamp_precision)
+{
+ LOCK
+
+ if (zl == NULL)
+ zl = zlog_default;
+
+ if (zl != NULL)
+ {
+ zl->timestamp_precision = timestamp_precision;
+ }
+
+ UNLOCK
+}
+
+/* returns name of ZLOG_NONE if no zlog given and no default set */
+const char *
+zlog_get_proto_name (struct zlog *zl)
+{
+ const char * result;
+ LOCK
+ result = uzlog_get_proto_name(zl);
+ UNLOCK
+ return result;
+}
+
+/* unprotected version, assumes mutex held */
+const char *
+uzlog_get_proto_name (struct zlog *zl)
+{
+ zlog_proto_t protocol = ZLOG_NONE;
+
+ if (zl == NULL)
+ zl = zlog_default;
+
+ if (zl != NULL)
+ {
+ protocol = zl->protocol;
+ }
+
+ return zlog_proto_names[protocol];
+}
+
+/* caller must free result */
+char *
+zlog_get_filename (struct zlog *zl)
+{
+ char * result = NULL;
+
+ LOCK
+
+ if (zl == NULL)
+ zl = zlog_default;
+
+ if (zl != NULL && zl->filename != NULL)
+ {
+ result = strdup(zl->filename);
+ }
+
+ UNLOCK
+ return result;
+}
+
+const char *
+zlog_get_ident (struct zlog *zl)
+{
+ const char * result = NULL;
+
+ LOCK
+
+ if (zl == NULL)
+ zl = zlog_default;
+
+ if (zl != NULL)
+ {
+ result = zl->ident;
+ }
+
+ UNLOCK
+ return result;
+}
+
+/* logging to a file? */
+int
+zlog_is_file (struct zlog *zl)
+{
+ int result = 0;
+
+ LOCK
+
+ if (zl == NULL)
+ zl = zlog_default;
+
+ if (zl != NULL)
+ {
+ result = (zl->fp != NULL);
+ }
+
+ UNLOCK;
+ return result;
+}
+
/* Message lookup function. */
const char *
lookup (const struct message *mes, int key)
@@ -928,3 +1354,6 @@ proto_name2num(const char *s)
return -1;
}
#undef RTSIZE
+
+#undef LOCK
+#undef UNLOCK
diff --git a/lib/log.h b/lib/log.h
index 2dd1d313..6ab1b37c 100644
--- a/lib/log.h
+++ b/lib/log.h
@@ -93,7 +93,11 @@ struct message
const char *str;
};
-/* Default logging strucutre. */
+/* module initialization */
+extern void zlog_init_r(void);
+extern void zlog_destroy_r(void);
+
+/* Default logging structure. */
extern struct zlog *zlog_default;
/* Open zlog function */
@@ -113,6 +117,9 @@ extern void closezlog (struct zlog *zl);
/* Generic function for zlog. */
extern void zlog (struct zlog *zl, int priority, const char *format, ...)
PRINTF_ATTRIBUTE(3, 4);
+/* assumed locked version for close friends */
+extern void uzlog (struct zlog *zl, int priority, const char *format, ...)
+ PRINTF_ATTRIBUTE(3, 4);
/* Handy zlog functions. */
extern void zlog_err (const char *format, ...) PRINTF_ATTRIBUTE(1, 2);
@@ -147,6 +154,23 @@ extern int zlog_reset_file (struct zlog *zl);
/* Rotate log. */
extern int zlog_rotate (struct zlog *);
+/* getters & setters */
+extern int zlog_get_default_lvl (struct zlog *zl);
+extern void zlog_set_default_lvl (struct zlog *zl, int level);
+extern void zlog_set_default_lvl_dest (struct zlog *zl, int level);
+extern int zlog_get_maxlvl (struct zlog *zl, zlog_dest_t dest);
+extern int zlog_get_facility (struct zlog *zl);
+extern void zlog_set_facility (struct zlog *zl, int facility);
+extern int zlog_get_record_priority (struct zlog *zl);
+extern void zlog_set_record_priority (struct zlog *zl, int record_priority);
+extern int zlog_get_timestamp_precision (struct zlog *zl);
+extern void zlog_set_timestamp_precision (struct zlog *zl, int timestamp_precision);
+extern const char * zlog_get_ident (struct zlog *zl);
+extern char * zlog_get_filename (struct zlog *zl);
+extern int zlog_is_file (struct zlog *zl);
+extern const char * zlog_get_proto_name (struct zlog *zl);
+extern const char * uzlog_get_proto_name (struct zlog *zl);
+
/* For hackey massage lookup and check */
#define LOOKUP(x, y) mes_lookup(x, x ## _max, y, "(no item found)")
@@ -185,7 +209,9 @@ extern void zlog_backtrace_sigsafe(int priority, void *program_counter);
*buf will be set to '\0', and 0 will be returned. */
extern size_t quagga_timestamp(int timestamp_precision /* # subsecond digits */,
char *buf, size_t buflen);
-
+/* unprotected version for when mutex already held */
+extern size_t uquagga_timestamp(int timestamp_precision /* # subsecond digits */,
+ char *buf, size_t buflen);
/* 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 dc09d8a6..333f59ad 100644
--- a/lib/memory.c
+++ b/lib/memory.c
@@ -17,7 +17,7 @@
* 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.
+ * 02111-1307, USA.
*/
#include <zebra.h>
@@ -32,22 +32,22 @@
static void alloc_inc (int);
static void alloc_dec (int);
static void log_memstats(int log_priority);
-
+
static const struct message mstr [] =
{
{ MTYPE_THREAD, "thread" },
{ MTYPE_THREAD_MASTER, "thread_master" },
{ MTYPE_VECTOR, "vector" },
- { MTYPE_VECTOR_INDEX, "vector_index" },
+ { MTYPE_VECTOR_BODY, "vector_index" },
{ MTYPE_IF, "interface" },
{ 0, NULL },
};
-
+
/* Fatal memory allocation error occured. */
static void __attribute__ ((noreturn))
zerror (const char *fname, int type, size_t size)
{
- zlog_err ("%s : can't allocate memory for `%s' size %d: %s\n",
+ zlog_err ("%s : can't allocate memory for `%s' size %d: %s\n",
fname, lookup (mstr, type), (int) size, safe_strerror(errno));
log_memstats(LOG_WARNING);
/* N.B. It might be preferable to call zlog_backtrace_sigsafe here, since
@@ -122,9 +122,9 @@ zstrdup (int type, const char *str)
alloc_inc (type);
return dup;
}
-
+
#ifdef MEMORY_LOG
-static struct
+static struct
{
const char *name;
long alloc;
@@ -187,7 +187,7 @@ mtype_zrealloc (const char *file, int line, int type, void *ptr, size_t size)
}
/* Important function. */
-void
+void
mtype_zfree (const char *file, int line, int type, void *ptr)
{
mstat[type].t_free++;
@@ -205,13 +205,13 @@ mtype_zstrdup (const char *file, int line, int type, const char *str)
mstat[type].c_strdup++;
memory = zstrdup (type, str);
-
+
mtype_log ("xstrdup", memory, file, line, type);
return memory;
}
#else
-static struct
+static struct
{
char *name;
long alloc;
@@ -231,7 +231,7 @@ alloc_dec (int type)
{
mstat[type].alloc--;
}
-
+
/* Looking up memory status from vty interface. */
#include "vector.h"
#include "vty.h"
@@ -329,7 +329,7 @@ show_memory_mallinfo (struct vty *vty)
{
struct mallinfo minfo = mallinfo();
char buf[MTYPE_MEMSTR_LEN];
-
+
vty_out (vty, "System allocator statistics:%s", VTY_NEWLINE);
vty_out (vty, " Total heap allocated: %s%s",
mtype_memstr (buf, MTYPE_MEMSTR_LEN, minfo.arena),
@@ -373,11 +373,11 @@ DEFUN (show_memory_all,
{
struct mlist *ml;
int needsep = 0;
-
+
#ifdef HAVE_MALLINFO
needsep = show_memory_mallinfo (vty);
#endif /* HAVE_MALLINFO */
-
+
for (ml = mlists; ml->list; ml++)
{
if (needsep)
@@ -516,7 +516,7 @@ memory_init (void)
install_element (ENABLE_NODE, &show_memory_ospf6_cmd);
install_element (ENABLE_NODE, &show_memory_isis_cmd);
}
-
+
/* Stats querying from users */
/* Return a pointer to a human friendly string describing
* the byte count passed in. E.g:
@@ -529,13 +529,13 @@ const char *
mtype_memstr (char *buf, size_t len, unsigned long bytes)
{
unsigned int t, g, m, k;
-
+
/* easy cases */
if (!bytes)
return "0 bytes";
if (bytes == 1)
return "1 byte";
-
+
if (sizeof (unsigned long) >= 8)
/* Hacked to make it not warn on ILP32 machines
* Shift will always be 40 at runtime. See below too */
@@ -545,11 +545,11 @@ mtype_memstr (char *buf, size_t len, unsigned long bytes)
g = bytes >> 30;
m = bytes >> 20;
k = bytes >> 10;
-
+
if (t > 10)
{
/* The shift will always be 39 at runtime.
- * Just hacked to make it not warn on 'smaller' machines.
+ * Just hacked to make it not warn on 'smaller' machines.
* Static compiler analysis should mean no extra code
*/
if (bytes & (1UL << (sizeof (unsigned long) >= 8 ? 39 : 0)))
@@ -576,7 +576,7 @@ mtype_memstr (char *buf, size_t len, unsigned long bytes)
}
else
snprintf (buf, len, "%ld bytes", bytes);
-
+
return buf;
}
diff --git a/lib/memory.h b/lib/memory.h
index 42eb5cae..fd9f1b97 100644
--- a/lib/memory.h
+++ b/lib/memory.h
@@ -21,6 +21,8 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#ifndef _ZEBRA_MEMORY_H
#define _ZEBRA_MEMORY_H
+#include <stddef.h>
+
/* For pretty printing of memory allocate information. */
struct memory_list
{
@@ -32,11 +34,11 @@ struct mlist {
struct memory_list *list;
const char *name;
};
-
-#include "lib/memtypes.h"
extern struct mlist mlists[];
+#include "lib/memtypes.h"
+
/* #define MEMORY_LOG */
#ifdef MEMORY_LOG
#define XMALLOC(mtype, size) \
@@ -60,6 +62,8 @@ extern struct mlist mlists[];
#define XSTRDUP(mtype, str) zstrdup ((mtype), (str))
#endif /* MEMORY_LOG */
+#define SIZE(t,n) (sizeof(t) * (n))
+
/* Prototypes of memory function. */
extern void *zmalloc (int type, size_t size);
extern void *zcalloc (int type, size_t size);
@@ -69,7 +73,7 @@ extern char *zstrdup (int type, const char *str);
extern void *mtype_zmalloc (const char *file, int line, int type, size_t size);
-extern void *mtype_zcalloc (const char *file, int line, int type,
+extern void *mtype_zcalloc (const char *file, int line, int type,
size_t num, size_t size);
extern void *mtype_zrealloc (const char *file, int line, int type, void *ptr,
diff --git a/lib/memtypes.c b/lib/memtypes.c
index 05d93225..8146f21f 100644
--- a/lib/memtypes.c
+++ b/lib/memtypes.c
@@ -1,6 +1,6 @@
/*
* Memory type definitions. This file is parsed by memtypes.awk to extract
- * MTYPE_ and memory_list_.. information in order to autogenerate
+ * MTYPE_ and memory_list_.. information in order to autogenerate
* memtypes.h.
*
* The script is sensitive to the format (though not whitespace), see
@@ -16,14 +16,30 @@ struct memory_list memory_list_lib[] =
{
{ MTYPE_TMP, "Temporary memory" },
{ MTYPE_STRVEC, "String vector" },
- { MTYPE_VECTOR, "Vector" },
- { MTYPE_VECTOR_INDEX, "Vector index" },
+ { MTYPE_VECTOR, "Vector structure" },
+ { MTYPE_VECTOR_BODY, "Vector body" },
+ { MTYPE_SYMBOL_TABLE, "Symbol Table structure" },
+ { MTYPE_SYMBOL_BASES, "Symbol Table chain bases" },
+ { MTYPE_SYMBOL, "Symbol" },
+ { MTYPE_SYMBOL_REF, "Symbol Reference" },
+ { MTYPE_HEAP, "Heap structure" },
{ MTYPE_LINK_LIST, "Link List" },
{ MTYPE_LINK_NODE, "Link Node" },
{ MTYPE_THREAD, "Thread" },
{ MTYPE_THREAD_MASTER, "Thread master" },
{ MTYPE_THREAD_STATS, "Thread stats" },
- { MTYPE_THREAD_FUNCNAME, "Thread function name" },
+ { MTYPE_THREAD_FUNCNAME, "Thread function name" },
+ { MTYPE_QPT_THREAD_ATTR, "qpt thread attributes" },
+ { MTYPE_QPT_MUTEX, "qpt mutex" },
+ { MTYPE_QPT_COND, "qpt condition variable" },
+ { MTYPE_MQUEUE_QUEUE, "Mqueue queue structure" },
+ { MTYPE_MQUEUE_BLOCKS, "Mqueue message blocks" },
+ { MTYPE_MQUEUE_THREAD_SIGNAL, "Mqueue thread signal" },
+ { MTYPE_QPS_SELECTION, "qpselect selection" },
+ { MTYPE_QPS_FILE, "qpselect file" },
+ { MTYPE_QTIMER_PILE, "qtimer pile structure" },
+ { MTYPE_QTIMER, "qtimer timer" },
+ { MTYPE_QPN_NEXUS, "qtn nexus" },
{ MTYPE_VTY, "VTY" },
{ MTYPE_VTY_OUT_BUF, "VTY output buffer" },
{ MTYPE_VTY_HIST, "VTY history" },
@@ -75,7 +91,7 @@ struct memory_list memory_list_lib[] =
{ -1, NULL },
};
-struct memory_list memory_list_zebra[] =
+struct memory_list memory_list_zebra[] =
{
{ MTYPE_RTADV_PREFIX, "Router Advertisement Prefix" },
{ MTYPE_VRF, "VRF" },
diff --git a/lib/mqueue.c b/lib/mqueue.c
new file mode 100644
index 00000000..5fe892c2
--- /dev/null
+++ b/lib/mqueue.c
@@ -0,0 +1,575 @@
+/* Message Queue data structure -- functions
+ * Copyright (C) 2009 Chris Hall (GMCH), Highwayman
+ *
+ * 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.
+ */
+
+#include <string.h>
+
+#include "memory.h"
+#include "mqueue.h"
+#include "zassert.h"
+
+/*==============================================================================
+ * These message queues are designed for inter-qpthread communication.
+ *
+ * A message queue carries messages from one or more qpthreads to one or more
+ * other qpthreads.
+ *
+ * A message queue has one ordinary priority queue and one high priority
+ * queue.
+ *
+ * There are four types of queue, depending on how qpthreads wait and how they
+ * are woken up:
+ *
+ * mqt_cond_unicast -- wait on condition variable, one waiter kicked
+ * mqt_cond_broadcast -- wait on condition variable, all waiters kicked
+ * mqt_signal_unicast -- wait for signal, one waiter kicked
+ * mqt_signal_broadcast -- wait for signal, all waiters kicked
+ *
+ * For condition variables there is a timeout mechanism so that waiters
+ * are woken up at least every now and then. The message queue maintains
+ * a timeout time and a timeout interval. The timeout time is a qtime_mono_t
+ * time -- so is monotonic.
+ *
+ * When waiting, an explicit timeout may be given, otherwise the stored timeout
+ * will be used:
+ *
+ * wait until explicit/stored timeout
+ * if times out and there is a stored interval:
+ * new stored timeout = stored timeout + stored interval
+ * if new stored timeout < time now
+ * new stored timeout = time now + stored interval
+ *
+ * Left to its own devices, this will produce a regular timeout every interval,
+ * assuming that the queue is waited on within the interval. Otherwise the
+ * "clock" will slip.
+ *
+ * There is a default timeout period. The period may be set "infinite".
+ *
+ * For waiters kicked by signal, the wait does not occur within the message
+ * queue code, but the need for a signal is recorded in the message queue.
+ *
+ * Messages take the form of a small block of information which contains:
+ *
+ * * flags -- used by the message handler
+ * * context -- identifies the context of the message (see revoke)
+ *
+ * * action -- void action(mqueue_block) message dispatch
+ * * arg_0 -- *void/uintptr_t/intptr_t ) standard arguments
+ * * arg_1 -- *void/uintptr_t/intptr_t )
+ *
+ * (see struct mqueue_block).
+ *
+ * To send a message, first allocate a message block (see mqueue_block_new),
+ * then fill in the arguments and enqueue it.
+ *
+ *
+ */
+
+/*==============================================================================
+ * Initialisation etc. for Message Queues.
+ *
+ * TODO: how to shut down a message queue... for reset/exit ?
+ */
+
+/* Initialise new Message Queue, if required (mq == NULL) allocating it.
+ *
+ * For mqt_cond_xxx type queues, sets the default timeout interval and the
+ * initial timeout time to now + that interval.
+ */
+
+mqueue_queue
+mqueue_init_new(mqueue_queue mq, enum mqueue_queue_type type)
+{
+ if (mq == NULL)
+ mq = XCALLOC(MTYPE_MQUEUE_QUEUE, sizeof(struct mqueue_queue)) ;
+ else
+ memset(mq, 0, sizeof(struct mqueue_queue)) ;
+
+ qpt_mutex_init(&mq->mutex, qpt_mutex_quagga) ;
+
+ /* head, tail and tail_priority set NULL already */
+ /* waiters set zero already */
+
+ mq->type = type ;
+ switch (type)
+ {
+ case mqt_cond_unicast:
+ case mqt_cond_broadcast:
+ qpt_cond_init(&mq->kick.cond.wait_here, qpt_cond_quagga) ;
+ if (MQUEUE_DEFAULT_INTERVAL != 0)
+ {
+ mq->kick.cond.interval = MQUEUE_DEFAULT_INTERVAL ;
+ mq->kick.cond.timeout = qt_get_monotonic()
+ + MQUEUE_DEFAULT_INTERVAL ;
+ } ;
+ break;
+
+ case mqt_signal_unicast:
+ case mqt_signal_broadcast:
+ /* head/tail pointers set NULL already */
+ break;
+
+ default:
+ zabort("Invalid mqueue queue type") ;
+ } ;
+
+ return mq ;
+} ;
+
+/* Set new timeout interval (or unset by setting <= 0)
+ *
+ * Sets the next timeout to be the time now + new interval (or never).
+ */
+void
+mqueue_set_timeout_interval(mqueue_queue mq, qtime_t interval)
+{
+ qpt_mutex_lock(&mq->mutex) ;
+
+ dassert( (mq->type == mqt_cond_unicast) ||
+ (mq->type == mqt_cond_broadcast) ) ;
+
+ mq->kick.cond.interval = interval ;
+ mq->kick.cond.timeout = (interval > 0) ? qt_get_monotonic() + interval
+ : 0 ;
+ qpt_mutex_unlock(&mq->mutex) ;
+} ;
+
+/*==============================================================================
+ * Message Block memory management.
+ *
+ * Allocates message_block structures in lots of 256. Uses first message_block
+ * in each lot to keep track of the lots.
+ *
+ * mqueue_initialise MUST be called before the first message block is allocated.
+ */
+
+static pthread_mutex_t* p_mb_mutex ; /* NULL => no mutex (yet) */
+static pthread_mutex_t mb_mutex ;
+
+#define MB_LOT_SIZE 256
+
+static mqueue_block mb_lot_list = NULL ;
+static mqueue_block mb_free_list = NULL ;
+
+static mqueue_block mqueue_block_new_lot(void) ;
+
+/* Get an empty message block
+ */
+mqueue_block
+mqueue_block_new(void)
+{
+ mqueue_block mb ;
+
+ qpt_mutex_lock(&mb_mutex) ;
+
+ mb = mb_free_list ;
+ if (mb == NULL)
+ mb = mqueue_block_new_lot() ;
+
+ mb_free_list = mb->next ;
+
+ qpt_mutex_unlock(&mb_mutex) ;
+
+ memset(mb, 0, sizeof(struct mqueue_block)) ;
+
+ return mb ;
+} ;
+
+/* Free message block when done with it.
+ */
+void
+mqueue_block_free(mqueue_block mb)
+{
+ qpt_mutex_lock(&mb_mutex) ;
+
+ mb->next = mb_free_list ;
+ mb_free_list = mb ;
+
+ qpt_mutex_unlock(&mb_mutex) ;
+} ;
+
+/* Make a new lot of empty message_block structures.
+ *
+ * NB: caller MUST hold the mb_mutex.
+ *
+ */
+static mqueue_block
+mqueue_block_new_lot(void)
+{
+ mqueue_block first, last, this ;
+
+ mqueue_block new = XCALLOC(MTYPE_MQUEUE_BLOCKS,
+ SIZE(struct mqueue_block, MB_LOT_SIZE)) ;
+ first = &new[1] ;
+ last = &new[MB_LOT_SIZE - 1] ;
+
+ new->next = mb_lot_list ; /* add to list of lots */
+ mb_lot_list = new ;
+
+ /* String all the new message_blocks together. */
+ this = last ;
+ while (this > first)
+ {
+ mqueue_block prev = this-- ;
+ this->next = prev ;
+ } ;
+ assert(this == first) ;
+
+ last->next = mb_free_list ; /* point last at old free list */
+ mb_free_list = first ; /* new blocks at head of free list */
+
+ return mb_free_list ;
+} ;
+
+/*==============================================================================
+ * Enqueue and dequeue messages.
+ */
+
+static void mqueue_kick_signal(mqueue_queue mq, int n) ;
+static void mqueue_dequeue_signal(mqueue_queue mq, mqueue_thread_signal mtsig) ;
+
+/* Enqueue message.
+ *
+ * If priority != 0, will enqueue after any previously enqueued priority
+ * messages.
+ *
+ * If there are any waiters, then we kick one or all of them.
+ *
+ * Note that we decrement or zero the waiters count here -- because if the
+ * waiter did it, they might not run before something else is enqueued.
+ * Similarly, if the kick uses a signal, the signal block is dequeued here.
+ *
+ * The waiter count is only incremented when a dequeue is attempted and the
+ * queue is empty, then:
+ *
+ * for a broadcast type message queue, the first message that arrives will
+ * kick all the waiters into action.
+ *
+ * for a signal type message queue, each message that arrives will kick one
+ * waiter.
+ */
+
+void
+mqueue_enqueue(mqueue_queue mq, mqueue_block mb, int priority)
+{
+ qpt_mutex_lock(&mq->mutex) ;
+
+ if (mq->head == NULL)
+ {
+ mb->next = NULL ;
+ mq->head = mb ;
+ mq->tail_priority = priority ? mb : NULL ;
+ mq->tail = mb ;
+ }
+ else if (priority)
+ {
+ mqueue_block after = mq->tail_priority ;
+ if (after == NULL)
+ {
+ mb->next = mq->head ;
+ mq->head = mb ;
+ }
+ else
+ {
+ mb->next = after->next ;
+ after->next = mb ;
+ }
+ mq->tail_priority = mb ;
+ }
+ else
+ {
+ dassert(mq->tail != NULL) ;
+ mb->next = NULL ;
+ mq->tail->next = mb ;
+ mq->tail = mb ;
+ } ;
+
+ if (mq->waiters != 0)
+ {
+ switch (mq->type)
+ {
+ case mqt_cond_unicast:
+ qpt_cond_signal(&mq->kick.cond.wait_here) ;
+ --mq->waiters ;
+ break ;
+
+ case mqt_cond_broadcast:
+ qpt_cond_broadcast(&mq->kick.cond.wait_here) ;
+ mq->waiters = 0 ;
+ break ;
+
+ case mqt_signal_unicast:
+ mqueue_kick_signal(mq, 1) ; /* pick off first and kick it (MUST be */
+ /* one) and decrement the waiters count */
+ break ;
+
+ case mqt_signal_broadcast:
+ mqueue_kick_signal(mq, mq->waiters) ;
+ dassert(mq->kick.signal.head == NULL) ;
+ break;
+
+ default:
+ zabort("Invalid mqueue queue type") ;
+ } ;
+ } ;
+
+ qpt_mutex_unlock(&mq->mutex) ;
+} ;
+
+/* Dequeue message.
+ *
+ * If the queue is empty and wait != 0, will wait for a message. In which
+ * case for:
+ *
+ * * mqt_cond_xxxx type message queues, will wait on the condition variable,
+ * and may timeout.
+ *
+ * If the argument is NULL, uses the already set up timeout, if there is
+ * one.
+ *
+ * If the argument is not NULL, it is a pointer to a qtime_mono_t time,
+ * to be used as the new timeout time.
+ *
+ * * mqt_signal_xxxx type message queues, will register the given signal
+ * (mtsig argument MUST be provided), and return immediately.
+ *
+ * Returns a message block if one is available. (And not otherwise.)
+ */
+
+mqueue_block
+mqueue_dequeue(mqueue_queue mq, int wait, void* arg)
+{
+ mqueue_block mb ;
+ mqueue_thread_signal last ;
+
+ mqueue_thread_signal mtsig ;
+ qtime_mono_t timeout_time ;
+
+ qpt_mutex_lock(&mq->mutex) ;
+
+ while (1)
+ {
+ mb = mq->head ;
+ if (mb != NULL)
+ break ; /* Easy if queue not empty */
+
+ if (!wait)
+ goto done ; /* Easy if not waiting ! mb == NULL */
+
+ ++mq->waiters ; /* Another waiter */
+
+ switch (mq->type)
+ {
+ case mqt_cond_unicast: /* Now wait here */
+ case mqt_cond_broadcast:
+ if ((arg == NULL) && (mq->kick.cond.interval <= 0))
+ qpt_cond_wait(&mq->kick.cond.wait_here, &mq->mutex) ;
+ else
+ {
+ timeout_time = (arg != NULL) ? *(qtime_mono_t*)arg
+ : mq->kick.cond.timeout ;
+
+ if (qpt_cond_timedwait(&mq->kick.cond.wait_here, &mq->mutex,
+ timeout_time) == 0)
+ {
+ /* Timed out -- update timeout time, if required */
+ if (mq->kick.cond.interval > 0)
+ {
+ qtime_mono_t now = qt_get_monotonic() ;
+ timeout_time = mq->kick.cond.timeout
+ + mq->kick.cond.interval ;
+ if (timeout_time < now)
+ timeout_time = now + mq->kick.cond.interval ;
+
+ mq->kick.cond.timeout = timeout_time ;
+ } ;
+
+ goto done ; /* immediate return. mb == NULL */
+ } ;
+ } ;
+ break ;
+
+ case mqt_signal_unicast: /* Register desire for signal */
+ case mqt_signal_broadcast:
+ mtsig = arg ;
+ dassert(mtsig != NULL) ;
+
+ last = mq->kick.signal.tail ;
+ if (last == NULL)
+ {
+ mq->kick.signal.head = mtsig ;
+ mtsig->prev = (void*)mq ;
+ }
+ else
+ {
+ last->next = mtsig ;
+ mtsig->prev = last ;
+ }
+ mtsig->next = NULL ;
+ mq->kick.signal.tail = mtsig ;
+
+ goto done ; /* BUT do not wait ! mb == NULL */
+
+ default:
+ zabort("Invalid mqueue queue type") ;
+ } ;
+ } ;
+
+ /* Have something to pull off the queue */
+
+ mq->head = mb->next ;
+ if (mb == mq->tail_priority)
+ mq->tail_priority = NULL ;
+
+done:
+ qpt_mutex_unlock(&mq->mutex) ;
+
+ return mb ;
+} ;
+
+/* No longer waiting for a signal.
+ *
+ * Returns true <=> signal has been kicked.
+ */
+int
+mqueue_done_waiting(mqueue_queue mq, mqueue_thread_signal mtsig)
+{
+ int kicked ;
+
+ qpt_mutex_lock(&mq->mutex) ;
+
+ dassert( (mq->type == mqt_signal_unicast) ||
+ (mq->type == mqt_signal_broadcast) ) ;
+ dassert(mtsig != NULL) ;
+
+ /* When the thread is signalled, the prev entry is set NULL and the */
+ /* waiters count is decremented. */
+ /* */
+ /* So, only need to do something here if the prev is not NULL (ie the */
+ /* mqueue_thread_signal is still on the list. */
+
+ kicked = (mtsig->prev == NULL) ;
+
+ if (!kicked)
+ mqueue_dequeue_signal(mq, mtsig) ;
+
+ qpt_mutex_unlock(&mq->mutex) ;
+
+ return kicked ;
+} ;
+
+/*==============================================================================
+ * Message queue signal handling
+ */
+
+/* Initialise a message queue signal structure (struct mqueue_thread_signal).
+ * Allocate one if required.
+ *
+ * Returns address of the structure.
+ */
+mqueue_thread_signal
+mqueue_thread_signal_init(mqueue_thread_signal mqt, qpt_thread_t thread,
+ int signum)
+{
+ if (mqt == NULL)
+ mqt = XCALLOC(MTYPE_MQUEUE_THREAD_SIGNAL,
+ sizeof(struct mqueue_thread_signal)) ;
+ else
+ memset(mqt, 0, sizeof(struct mqueue_thread_signal)) ;
+
+ /* next and prev fields set to NULL already. */
+
+ mqt->qpthread = thread ;
+ mqt->signum = signum ;
+
+ return mqt ;
+} ;
+
+/* Signal the first 'n' threads on the to be signalled list.
+ *
+ * Removes the threads from the list and reduces the waiters count.
+ *
+ * NB: sets the prev entry in the mqueue_thread_signal block to NULL, so that
+ * the thread can tell that its signal has been kicked.
+ *
+ * NB: *** MUST own the mqueue_queue mutex. ***
+ */
+static void
+mqueue_kick_signal(mqueue_queue mq, int n)
+{
+ mqueue_thread_signal mtsig ;
+
+ while (n--)
+ {
+ mqueue_dequeue_signal(mq, mtsig = mq->kick.signal.head) ;
+ qpt_thread_signal(mtsig->qpthread, mtsig->signum) ;
+ } ;
+} ;
+
+/* Remove given signal from given message queue.
+ *
+ * NB: *** MUST own the mqueue_queue mutex. ***
+ */
+static void
+mqueue_dequeue_signal(mqueue_queue mq, mqueue_thread_signal mtsig)
+{
+ mqueue_thread_signal next ;
+ mqueue_thread_signal prev ;
+
+ dassert((mq->kick.signal.head != NULL) && (mq->waiters != 0)) ;
+
+ next = mtsig->next ;
+ prev = mtsig->prev ;
+
+ if (prev == (void*)mq) /* marker for head of list */
+ {
+ dassert(mq->kick.signal.head == mtsig) ;
+ mq->kick.signal.head = next ;
+ }
+ else
+ {
+ dassert((prev != NULL) && (prev->next == mtsig)) ;
+ prev->next = next ;
+ } ;
+
+ if (next != NULL)
+ next->prev = prev ;
+
+ mtsig->next = NULL ;
+ mtsig->prev = NULL ; /* essential to show signal kicked */
+ --mq->waiters ; /* one fewer waiter */
+
+ dassert( ((mq->kick.signal.head == NULL) && (mq->waiters == 0)) ||
+ ((mq->kick.signal.head != NULL) && (mq->waiters != 0)) ) ;
+} ;
+
+/*==============================================================================
+ * Initialise Message Queue handling
+ *
+ * Must be called before any qpt_threads are started.
+ *
+ * TODO: how do we shut down message queue handling ?
+ */
+void
+mqueue_initialise(int qpthreads)
+{
+ if (qpthreads)
+ p_mb_mutex = qpt_mutex_init(&mb_mutex, qpt_mutex_quagga) ;
+} ;
diff --git a/lib/mqueue.h b/lib/mqueue.h
new file mode 100644
index 00000000..5c10911b
--- /dev/null
+++ b/lib/mqueue.h
@@ -0,0 +1,141 @@
+/* Message Queue data structure -- header
+ * Copyright (C) 2009 Chris Hall (GMCH), Highwayman
+ *
+ * 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 _ZEBRA_MQUEUE_H
+#define _ZEBRA_MQUEUE_H
+
+#include "qpthreads.h"
+#include "qtime.h"
+
+/*==============================================================================
+ */
+
+typedef struct mqueue_block* mqueue_block ;
+
+typedef uint32_t mqueue_flags_t ;
+typedef uint32_t mqueue_context_t ;
+typedef union
+{
+ void* p ;
+ uintptr_t u ;
+ intptr_t i ;
+} mqueue_arg_t ;
+
+typedef void mqueue_action(mqueue_block) ;
+
+struct mqueue_block
+{
+ mqueue_block next ; /* single linked list -- see ... */
+
+ mqueue_action* action ; /* for message dispatch */
+
+ mqueue_flags_t flags ; /* for message handler */
+
+ mqueue_context_t context ; /* for message revoke */
+
+ mqueue_arg_t arg0 ; /* may be pointer to more data or integer */
+ mqueue_arg_t arg1 ; /* may be pointer to more data or integer */
+} ;
+
+typedef struct mqueue_thread_signal* mqueue_thread_signal ;
+
+struct mqueue_thread_signal {
+ mqueue_thread_signal next ; /* NULL => last on list */
+ mqueue_thread_signal prev ; /* NULL => NOT on list -- vital ! */
+
+ qpt_thread_t qpthread ; /* qpthread to kick */
+ int signum ; /* signal to kick with */
+} ;
+
+enum mqueue_queue_type {
+ mqt_cond_unicast, /* use qpt_cond_signal to kick the queue */
+ mqt_cond_broadcast, /* use qpt_cond_broadcast to kick the queue */
+ mqt_signal_unicast, /* use single qpt_signal to kick the queue */
+ mqt_signal_broadcast, /* use multiple qpt_signal to kick the queue */
+};
+
+#ifndef MQUEUE_DEFAULT_INTERVAL
+# define MQUEUE_DEFAULT_INTERVAL QTIME(5)
+#endif
+
+struct mqueue_queue_cond {
+ qpt_cond_t wait_here ;
+ qtime_mono_t timeout ;
+ qtime_t interval ;
+} ;
+
+struct mqueue_queue_signal {
+ mqueue_thread_signal head ; /* NULL => list is empty */
+ mqueue_thread_signal tail ;
+};
+
+typedef struct mqueue_queue* mqueue_queue ;
+
+struct mqueue_queue
+{
+ qpt_mutex_t mutex ;
+
+ mqueue_block head ; /* NULL => list is empty */
+ mqueue_block tail_priority ; /* last priority message (if any & not empty) */
+ mqueue_block tail ; /* last message (if not empty) */
+
+ enum mqueue_queue_type type ;
+
+ unsigned waiters ;
+
+ union {
+ struct mqueue_queue_cond cond ;
+ struct mqueue_queue_signal signal ;
+ } kick ;
+} ;
+
+/*==============================================================================
+ * Functions
+ */
+
+void
+mqueue_initialise(int qpthreads) ;
+
+mqueue_queue
+mqueue_init_new(mqueue_queue mq, enum mqueue_queue_type type) ;
+
+void
+mqueue_set_timeout_interval(mqueue_queue mq, qtime_t interval) ;
+
+mqueue_thread_signal
+mqueue_thread_signal_init(mqueue_thread_signal mqt, qpt_thread_t thread,
+ int signum) ;
+mqueue_block
+mqueue_block_new(void) ;
+
+void
+mqueue_block_free(mqueue_block mb) ;
+
+void
+mqueue_enqueue(mqueue_queue mq, mqueue_block mb, int priority) ;
+
+mqueue_block
+mqueue_dequeue(mqueue_queue mq, int wait, void* arg) ;
+
+int
+mqueue_done_waiting(mqueue_queue mq, mqueue_thread_signal mtsig) ;
+
+#endif /* _ZEBRA_MQUEUE_H */
diff --git a/lib/plist.c b/lib/plist.c
index 0f802a83..b01c48f6 100644
--- a/lib/plist.c
+++ b/lib/plist.c
@@ -1,6 +1,10 @@
/* Prefix list functions.
* Copyright (C) 1999 Kunihiro Ishiguro
*
+ * 24-Nov-2009 -- substantially re-cast to speed up the handling of very
+ * large prefix-lists (10,000+ entries).
+ * Copyright (C) 2009 Chris Hall (GMCH), Highwayman
+ *
* This file is part of GNU Zebra.
*
* GNU Zebra is free software; you can redistribute it and/or modify
@@ -29,494 +33,949 @@
#include "buffer.h"
#include "stream.h"
#include "log.h"
+#include "symtab.h"
+#include "vector.h"
-/* Each prefix-list's entry. */
-struct prefix_list_entry
+/* This implements ip prefix-list functions.
+ *
+ * A prefix-list is referred to by name, where a name is an arbitrary string,
+ * case-sensitive. When showing prefix-lists the names are sorted
+ * "alphabetically", except for any digit sections, which sort numerically.
+ * Note that leading zeros are significant... "01" is not the same as "1",
+ * and sorts after it.
+*/
+
+enum prefix_flags {
+ PREFIX_ANY = 0x01, /* prefix declared as 'any' */
+ PREFIX_LE = 0x02, /* explicit 'le' */
+ PREFIX_GE = 0x04, /* explicit 'ge' */
+ PREFIX_SEQ = 0x10, /* explicit sequence number */
+} ;
+
+struct prefix_list ;
+struct prefix_list_entry ;
+
+/* Master structure of prefix_list.
+ *
+ * Each address family has it's own distinct set of prefix lists. (Including
+ * the fake AFI_ORF_PREFIX "family".)
+ *
+ * This means that a prefix_list name is local to an address family, but
+ * global wrt router instances.
+ * */
+struct prefix_master
{
- int seq;
+ struct symbol_table table ; /* table of prefix_list by name. */
- int le;
- int ge;
-
- enum prefix_list_type type;
+ int seqnum_flag ; /* ip prefix-list sequence-number state. */
- int any;
- struct prefix prefix;
+ struct prefix_list *recent ; /* the latest update. */
- unsigned long refcnt;
- unsigned long hitcnt;
+ struct prefix_list *cache_owner ;
+ /* prefix_list that owns the dup_cache */
+ struct vector dup_cache ; /* the dup_cache vector */
- struct prefix_list_entry *next;
- struct prefix_list_entry *prev;
+ void (*add_hook) (struct prefix_list *);
+ /* executed when new prefix_list is added. */
+ void (*delete_hook) (struct prefix_list *);
+ /* executed when a prefix_list is deleted. */
};
-/* List of struct prefix_list. */
-struct prefix_list_list
+/* Each prefix_list is described by one of these.*/
+struct prefix_list
{
- struct prefix_list *head;
- struct prefix_list *tail;
-};
+ struct prefix_master *master ; /* parent table: scope of this list. */
+ struct symbol* sym ; /* symbol in parent's symbol table */
-/* Master structure of prefix_list. */
-struct prefix_master
+ char *desc ; /* ip prefix-list description */
+
+ afi_t afi ; /* address family for all prefixes */
+ /* this is the *real* address family, so */
+ /* not "AFI_ORF_PREFIX" or similar. */
+
+ struct vector list ; /* the actual list of prefix matches */
+
+ int (*cmp)(struct prefix_list_entry** p_a, struct prefix_list_entry** p_b) ;
+ /* used when searching for duplicates */
+
+ int rangecount; /* XXX TODO: discover what this is for ?? */
+ /* Is not changed anywhere !! */
+} ;
+
+/* Each prefix-list's entry. */
+struct prefix_list_entry
{
- /* List of prefix_list which name is number. */
- struct prefix_list_list num;
+ int seq;
- /* List of prefix_list which name is string. */
- struct prefix_list_list str;
+ enum prefix_list_type type;
- /* Whether sequential number is used. */
- int seqnum;
+ int flags ; /* zero or more of PREFIX_ANY, PREFIX_LE and PREFIX_GE */
+ int le ; /* for exact match, set to prefix length */
+ int ge ; /* ditto */
- /* The latest update. */
- struct prefix_list *recent;
+ struct prefix prefix;
- /* Hook function which is executed when new prefix_list is added. */
- void (*add_hook) (struct prefix_list *);
+ u_int32_t mask ; /* for IPv4 -- host order. */
+ /* for last significant word of IPv6 -- network order */
+ int last ; /* for IPv4 -- not used. */
+ /* for IPv6 -- word to apply mask to. */
- /* Hook function which is executed when prefix_list is deleted. */
- void (*delete_hook) (struct prefix_list *);
+ unsigned long refcnt;
+ unsigned long hitcnt;
};
/* Static structure of IPv4 prefix_list's master. */
-static struct prefix_master prefix_master_ipv4 =
-{
- {NULL, NULL},
- {NULL, NULL},
- 1,
- NULL,
- NULL,
-};
+static struct prefix_master prefix_master_ipv4 ;
#ifdef HAVE_IPV6
/* Static structure of IPv6 prefix-list's master. */
-static struct prefix_master prefix_master_ipv6 =
-{
- {NULL, NULL},
- {NULL, NULL},
- 1,
- NULL,
- NULL,
-};
+static struct prefix_master prefix_master_ipv6 ;
#endif /* HAVE_IPV6*/
/* Static structure of BGP ORF prefix_list's master. */
-static struct prefix_master prefix_master_orf =
-{
- {NULL, NULL},
- {NULL, NULL},
- 1,
- NULL,
- NULL,
-};
-
-static struct prefix_master *
-prefix_master_get (afi_t afi)
+static struct prefix_master prefix_master_orf ;
+
+/* For real afi, the choice is strictly limited, and includes IPv6
+ * only if HAVE_IPV6 ! */
+#ifdef HAVE_IPV6
+#define assert_afi_real(a) assert(((a) == AFI_IP) || ((a) == AFI_IP6))
+#else
+#define assert_afi_real(a) assert((a) == AFI_IP)
+#endif
+
+/* Map afi to prefix_master.
+ *
+ * Note: there is no ipv6 master if not HAVE_IPV6.
+ *
+ * Returns address of prefix_master, or NULL if unknown afi.
+ */
+static inline struct prefix_master *
+prefix_master_get(afi_t afi)
{
- if (afi == AFI_IP)
- return &prefix_master_ipv4;
+ switch (afi)
+ {
+ case AFI_IP:
+ return &prefix_master_ipv4;
#ifdef HAVE_IPV6
- else if (afi == AFI_IP6)
- return &prefix_master_ipv6;
+ case AFI_IP6:
+ return &prefix_master_ipv6;
#endif /* HAVE_IPV6 */
- else if (afi == AFI_ORF_PREFIX)
- return &prefix_master_orf;
- return NULL;
-}
+ case AFI_ORF_PREFIX:
+ return &prefix_master_orf;
+ default:
+ return NULL;
+ } ;
+} ;
-/* Lookup prefix_list from list of prefix_list by name. */
-struct prefix_list *
-prefix_list_lookup (afi_t afi, const char *name)
+/* Map afi to maximum prefix length. Implied assert_afi_real(). */
+static int
+prefix_max_length(afi_t afi)
{
- struct prefix_list *plist;
- struct prefix_master *master;
+ switch (afi)
+ {
+ case AFI_IP:
+ return IPV4_MAX_BITLEN ;
+#ifdef HAVE_IPV6
+ case AFI_IP6:
+ return IPV6_MAX_BITLEN ;
+#endif
+ default:
+ assert(0) ; /* Should not get here ! */
+ return 0 ;
+ } ;
+} ;
- if (name == NULL)
- return NULL;
+/* Compare prefix list entries, taking into account:
+ *
+ * -- prefix value -- assumes is masked down correctly
+ * -- prefix length
+ * -- ge
+ * -- le
+ * -- type
+ *
+ * ... everything *except* the sequence number.
+ */
- master = prefix_master_get (afi);
- if (master == NULL)
- return NULL;
+#define PREFIX_LIST_CMP_RET(f) \
+ if ((*p_a)->f != (*p_b)->f) \
+ return ( (*p_a)->f < (*p_b)->f) ? -1 : +1
+#define PREFIX_LIST_CMP_RET_NL(f) \
+ if ((*p_a)->f != (*p_b)->f) \
+ return (ntohl((*p_a)->f) < ntohl((*p_b)->f)) ? -1 : +1
+#define PREFIX_LIST_CMP_REST \
+PREFIX_LIST_CMP_RET(prefix.prefixlen) ; \
+PREFIX_LIST_CMP_RET(ge) ; \
+PREFIX_LIST_CMP_RET(le) ; \
+PREFIX_LIST_CMP_RET(type)
- for (plist = master->num.head; plist; plist = plist->next)
- if (strcmp (plist->name, name) == 0)
- return plist;
+static int
+prefix_list_ipv4_cmp(struct prefix_list_entry** p_a,
+ struct prefix_list_entry** p_b)
+{
+ PREFIX_LIST_CMP_RET_NL(prefix.u.prefix4.s_addr) ;
+ PREFIX_LIST_CMP_REST ;
+ return 0 ;
+} ;
- for (plist = master->str.head; plist; plist = plist->next)
- if (strcmp (plist->name, name) == 0)
- return plist;
+#ifdef HAVE_IPV6 /*----------------------------------------------------*/
+static int
+prefix_list_ipv6_cmp(struct prefix_list_entry** p_a,
+ struct prefix_list_entry** p_b)
+{
+#ifdef s6_addr32
+ PREFIX_LIST_CMP_RET_NL(prefix.u.prefix6.s6_addr32[0]) ;
+ PREFIX_LIST_CMP_RET_NL(prefix.u.prefix6.s6_addr32[1]) ;
+ PREFIX_LIST_CMP_RET_NL(prefix.u.prefix6.s6_addr32[2]) ;
+ PREFIX_LIST_CMP_RET_NL(prefix.u.prefix6.s6_addr32[3]) ;
+#else
+ int c ;
+ if ((c = memcmp(&(*p_a)->prefix.u.prefix6.s6_addr,
+ &(*p_b)->prefix.u.prefix6.s6_addr, 16)) != 0)
+ return c ;
+#endif
+ PREFIX_LIST_CMP_REST ;
+ return 0 ;
+} ;
+#endif /*----------------------------------------------------*/
+
+/*==============================================================================
+ * Operations on prefix_master.
+ */
- return NULL;
-}
+static void prefix_list_delete (struct prefix_list* plist) ;
+static void prefix_dup_cache_free(struct prefix_master* pm) ;
-static struct prefix_list *
-prefix_list_new (void)
+/* Initialise given prefix_master. */
+static void
+prefix_master_init(struct prefix_master * pm)
{
- struct prefix_list *new;
+ memset(pm, 0, sizeof(struct prefix_master)) ;
- new = XCALLOC (MTYPE_PREFIX_LIST, sizeof (struct prefix_list));
- return new;
-}
+ symbol_table_init_new(&pm->table, pm, 20, 200, NULL, NULL) ;
+ pm->seqnum_flag = 1 ; /* Default is to generate sequence numbers. */
+} ;
+/* Reset given prefix_master.
+ *
+ * Frees all prefix lists and empties the symbol table. Any references to
+ * prefix lists are the responsibility of the reference owners.
+ *
+ * Resets to the default sequence numbering state.
+ *
+ * Retains current add_hook and delete_hook functions.
+ */
static void
-prefix_list_free (struct prefix_list *plist)
+prefix_master_reset(struct prefix_master * pm)
{
- XFREE (MTYPE_PREFIX_LIST, plist);
-}
+ struct prefix_list* plist ;
+ while ((plist = symbol_table_ream_keep(&(pm->table))))
+ prefix_list_delete(plist) ;
-static struct prefix_list_entry *
-prefix_list_entry_new (void)
-{
- struct prefix_list_entry *new;
+ pm->seqnum_flag = 1 ; /* Default is to generate sequence numbers. */
- new = XCALLOC (MTYPE_PREFIX_LIST_ENTRY, sizeof (struct prefix_list_entry));
- return new;
+ pm->recent = NULL ;
+ prefix_dup_cache_free(pm) ;
+} ;
+
+/* Add hook function. */
+void
+prefix_list_add_hook (void (*func)(struct prefix_list *plist))
+{
+ prefix_master_ipv4.add_hook = func;
+#ifdef HAVE_IPV6
+ prefix_master_ipv6.add_hook = func;
+#endif /* HAVE_IPV6 */
}
-static void
-prefix_list_entry_free (struct prefix_list_entry *pentry)
+/* Delete hook function. */
+void
+prefix_list_delete_hook (void (*func)(struct prefix_list *plist))
{
- XFREE (MTYPE_PREFIX_LIST_ENTRY, pentry);
+ prefix_master_ipv4.delete_hook = func;
+#ifdef HAVE_IPV6
+ prefix_master_ipv6.delete_hook = func;
+#endif /* HAVE_IPVt6 */
}
-/* Insert new prefix list to list of prefix_list. Each prefix_list
- is sorted by the name. */
-static struct prefix_list *
-prefix_list_insert (afi_t afi, const char *name)
+/*==============================================================================
+ * Prefix List Use.
+ *
+ * The prefix_list_ref type is a struct symbol_ref*, so we can operate on
+ * prefix_list_ref* arguments, keeping the stored reference values up to date.
+ */
+
+const char*
+prefix_list_get_name(struct prefix_list* plist)
{
- unsigned int i;
- long number;
- struct prefix_list *plist;
- struct prefix_list *point;
- struct prefix_list_list *list;
- struct prefix_master *master;
+ return symbol_get_name(plist->sym) ;
+} ;
- master = prefix_master_get (afi);
- if (master == NULL)
- return NULL;
+/* Set reference to prefix_list, by name.
+ * Replaces any existing reference.
+ *
+ * Returns the new value of the prefix_list_ref.
+ *
+ * NB: if reference existed, the parent and tag fields are preserved.
+ * Otherwise they are set to 0.
+ */
+prefix_list_ref
+prefix_list_set_ref(prefix_list_ref* p_ref, afi_t afi, const char* name)
+{
+ struct prefix_master* pm = prefix_master_get(afi) ;
- /* Allocate new prefix_list and copy given name. */
- plist = prefix_list_new ();
- plist->name = XSTRDUP (MTYPE_PREFIX_LIST_STR, name);
- plist->master = master;
+ if (pm == NULL)
+ return NULL ;
- /* If name is made by all digit character. We treat it as
- number. */
- for (number = 0, i = 0; i < strlen (name); i++)
- {
- if (isdigit ((int) name[i]))
- number = (number * 10) + (name[i] - '0');
- else
- break;
- }
+ return *p_ref = symbol_set_ref(*p_ref, symbol_find(&(pm->table), name)) ;
+} ;
- /* In case of name is all digit character */
- if (i == strlen (name))
- {
- plist->type = PREFIX_TYPE_NUMBER;
+/* Copy reference to prefix_list.
+ * Replaces any existing reference (by NULL if reference is NULL).
+ *
+ * Returns the new value of the prefix_list_ref.
+ *
+ * NB: if reference existed, the parent and tag fields are preserved.
+ * Otherwise they are set to 0.
+ */
+prefix_list_ref
+prefix_list_copy_ref(prefix_list_ref* p_dst, prefix_list_ref src)
+{
+ return *p_dst = symbol_set_ref(*p_dst, sym_ref_symbol(src)) ;
+} ;
- /* Set prefix_list to number list. */
- list = &master->num;
+/* Unset reference to prefix_list (does nothing if reference is NULL).
+ *
+ * Returns the new value of the prefix_list_ref -- ie NULL.
+ */
+prefix_list_ref
+prefix_list_unset_ref(prefix_list_ref* p_ref)
+{
+ return *p_ref = symbol_unset_ref(*p_ref, 1) ;
+} ;
- for (point = list->head; point; point = point->next)
- if (atol (point->name) >= number)
- break;
- }
- else
- {
- plist->type = PREFIX_TYPE_STRING;
-
- /* Set prefix_list to string list. */
- list = &master->str;
-
- /* Set point to insertion point. */
- for (point = list->head; point; point = point->next)
- if (strcmp (point->name, name) >= 0)
- break;
- }
+/* Get name of prefix_list to which given reference (if any) refers.
+ *
+ * Returns NULL if the reference is NULL.
+ */
+const char*
+prefix_list_ref_name(prefix_list_ref ref)
+{
+ return sym_ref_name(ref) ;
+} ;
- /* In case of this is the first element of master. */
- if (list->head == NULL)
- {
- list->head = list->tail = plist;
- return plist;
- }
+/* Return "identity" of prefix_list referred to by the given reference.
+ * Will be NULL if the reference is NULL.
+ *
+ * Two references to the same prefix_list will have the same "identity".
+ */
+void* prefix_list_ref_ident(prefix_list_ref ref)
+{
+ return (void*)sym_ref_symbol(ref) ;
+} ;
- /* In case of insertion is made at the tail of access_list. */
- if (point == NULL)
- {
- plist->prev = list->tail;
- list->tail->next = plist;
- list->tail = plist;
- return plist;
- }
+/* Return prefix_list referred to by the given reference.
+ * Will be NULL If the reference is NULL *OR* if the prefix_list is undefined.
+ */
+struct prefix_list* prefix_list_ref_plist(prefix_list_ref ref)
+{
+ return (struct prefix_list*)sym_ref_value(ref) ;
+} ;
- /* In case of insertion is made at the head of access_list. */
- if (point == list->head)
- {
- plist->next = list->head;
- list->head->prev = plist;
- list->head = plist;
- return plist;
- }
- /* Insertion is made at middle of the access_list. */
- plist->next = point;
- plist->prev = point->prev;
+/* Apply a prefix_list to the given prefix. */
+enum prefix_list_type
+prefix_list_apply (struct prefix_list *plist, void *object)
+{
+ struct prefix *p ;
+ int plen ;
+ struct prefix_list_entry* pe ;
+ vector_index i ;
+
+ in_addr_t ip ;
+#ifdef s6_addr32
+ u_int32_t* pp ;
+ u_int32_t* pep ;
+#else
+ unsigned char* pp ;
+ unsigned char* pep ;
+#endif
+ /* Deny if prefix_list is undefined or empty */
+ if ((plist == NULL) || (vector_end(&plist->list) == 0))
+ return PREFIX_DENY;
- if (point->prev)
- point->prev->next = plist;
- point->prev = plist;
+ p = object ;
+ plen = p->prefixlen ;
- return plist;
-}
+ /* For maximum performance we have separate loops for IPv4 and IPv6 */
+ assert_afi_real(plist->afi) ;
-static struct prefix_list *
-prefix_list_get (afi_t afi, const char *name)
-{
- struct prefix_list *plist;
+ switch (plist->afi)
+ {
+ case AFI_IP:
+ ip = p->u.prefix4.s_addr ;
+ for (VECTOR_ITEMS(&plist->list, pe, i))
+ {
+ ++pe->refcnt ;
+ if ((((pe->prefix.u.prefix4.s_addr ^ ip) & pe->mask) == 0)
+ && (plen >= pe->ge) && (plen <= pe->le))
+ {
+ ++pe->hitcnt;
+ return pe->type ;
+ } ;
+ }
+ break ;
+
+ case AFI_IP6:
+#ifdef s6_addr32
+ pp = p->u.prefix6.s6_addr32 ;
+#else
+ pp = p->u.prefix6.s6_addr ;
+#endif
+ for (VECTOR_ITEMS(&plist->list, pe, i))
+ {
+ int l = pe->last ;
+ int j ;
+ ++pe->refcnt ;
+#ifdef s6_addr32
+ pep = pe->prefix.u.prefix6.s6_addr32 ;
+#else
+ pep = pe->prefix.u.prefix6.s6_addr ;
+#endif
+ for (j = 0 ; j < l ; j++)
+ if (pep[j] != pp[j])
+ goto NEXT ;
+ if ((((pep[l] ^ pp[l]) & pe->mask) == 0)
+ && (plen >= pe->ge) && (plen <= pe->le))
+ {
+ ++pe->hitcnt;
+ return pe->type ;
+ } ;
+ NEXT: ;
+ }
+ break ;
- plist = prefix_list_lookup (afi, name);
+ default:
+ assert(0) ;
+ } ;
- if (plist == NULL)
- plist = prefix_list_insert (afi, name);
- return plist;
+ return PREFIX_DENY;
}
+/*==============================================================================
+ * Basic constructors and destructors.
+ */
-/* Delete prefix-list from prefix_list_master and free it. */
-static void
-prefix_list_delete (struct prefix_list *plist)
+/* Construct a new prefix_list and set the the associated symbol's value.
+ *
+ * Implied assert_afi_real().
+ */
+static struct prefix_list *
+prefix_list_new(struct prefix_master* pm, struct symbol* sym, afi_t afi)
{
- struct prefix_list_list *list;
- struct prefix_master *master;
- struct prefix_list_entry *pentry;
- struct prefix_list_entry *next;
+ struct prefix_list* new ;
- /* If prefix-list contain prefix_list_entry free all of it. */
- for (pentry = plist->head; pentry; pentry = next)
- {
- next = pentry->next;
- prefix_list_entry_free (pentry);
- plist->count--;
- }
-
- master = plist->master;
-
- if (plist->type == PREFIX_TYPE_NUMBER)
- list = &master->num;
- else
- list = &master->str;
+ new = XCALLOC (MTYPE_PREFIX_LIST, sizeof (struct prefix_list));
+ /* NB: implicitly sets the list empty. */
- if (plist->next)
- plist->next->prev = plist->prev;
- else
- list->tail = plist->prev;
+ new->sym = symbol_inc_ref(sym) ;
+ new->master = pm ;
- if (plist->prev)
- plist->prev->next = plist->next;
- else
- list->head = plist->next;
+ new->afi = afi ;
+ switch (afi)
+ {
+ case AFI_IP:
+ new->cmp = prefix_list_ipv4_cmp ;
+ break ;
+#ifdef HAVE_IPV6
+ case AFI_IP6:
+ new->cmp = prefix_list_ipv6_cmp ;
+ break ;
+#endif
+ default:
+ assert(0) ; /* Should not get here ! */
+ } ;
- if (plist->desc)
- XFREE (MTYPE_TMP, plist->desc);
+ symbol_set_value(sym, new) ;
- /* Make sure master's recent changed prefix-list information is
- cleared. */
- master->recent = NULL;
+ return new ;
+} ;
- if (plist->name)
- XFREE (MTYPE_PREFIX_LIST_STR, plist->name);
-
- prefix_list_free (plist);
-
- if (master->delete_hook)
- (*master->delete_hook) (NULL);
+/* Initialise prefix_list entry -- cleared to zeros. */
+static struct prefix_list_entry *
+prefix_list_entry_init(struct prefix_list_entry * pe)
+{
+ return memset(pe, 0, sizeof(struct prefix_list_entry));
}
+/* Allocate new prefix_list entry -- cleared to zeros. */
static struct prefix_list_entry *
-prefix_list_entry_make (struct prefix *prefix, enum prefix_list_type type,
- int seq, int le, int ge, int any)
+prefix_list_entry_new (void)
{
- struct prefix_list_entry *pentry;
-
- pentry = prefix_list_entry_new ();
-
- if (any)
- pentry->any = 1;
-
- prefix_copy (&pentry->prefix, prefix);
- pentry->type = type;
- pentry->seq = seq;
- pentry->le = le;
- pentry->ge = ge;
-
- return pentry;
+ return XCALLOC (MTYPE_PREFIX_LIST_ENTRY, sizeof (struct prefix_list_entry));
}
-/* Add hook function. */
-void
-prefix_list_add_hook (void (*func) (struct prefix_list *plist))
+/* Free given prefix list entry. */
+static void
+prefix_list_entry_free (struct prefix_list_entry* pe)
{
- prefix_master_ipv4.add_hook = func;
-#ifdef HAVE_IPV6
- prefix_master_ipv6.add_hook = func;
-#endif /* HAVE_IPV6 */
+ XFREE (MTYPE_PREFIX_LIST_ENTRY, pe);
}
-/* Delete hook function. */
-void
-prefix_list_delete_hook (void (*func) (struct prefix_list *plist))
+/* Set cache owned by nobody, and free the contents of the cache (if any). */
+static void
+prefix_dup_cache_free(struct prefix_master* pm)
{
- prefix_master_ipv4.delete_hook = func;
-#ifdef HAVE_IPV6
- prefix_master_ipv6.delete_hook = func;
-#endif /* HAVE_IPVt6 */
+ pm->cache_owner = NULL ;
+ vector_reset(&pm->dup_cache, 0) ;
}
-/* Calculate new sequential number. */
-static int
-prefix_new_seq_get (struct prefix_list *plist)
+/* Delete prefix_list from prefix_list_master and free it and its contents. */
+/* The prefix_list's symbol is set undefined. */
+static void
+prefix_list_delete (struct prefix_list* plist)
{
- int maxseq;
- int newseq;
- struct prefix_list_entry *pentry;
+ struct prefix_master* pm = plist->master ;
+ unsigned int i ;
+ struct prefix_list_entry* pe ;
- maxseq = newseq = 0;
+ /* Free all the prefix_list_entries, then free the vector they live in. */
+ for (VECTOR_ITEMS(&plist->list, pe, i))
+ prefix_list_entry_free(pe) ;
+ vector_reset(&plist->list, 0) ;
- for (pentry = plist->head; pentry; pentry = pentry->next)
- {
- if (maxseq < pentry->seq)
- maxseq = pentry->seq;
- }
+ /* If there is a description, release that now. */
+ if (plist->desc)
+ XFREE (MTYPE_TMP, plist->desc);
- newseq = ((maxseq / 5) * 5) + 5;
-
- return newseq;
-}
+ /* Can no longer own the dup_cache. */
+ if (pm->cache_owner == plist)
+ prefix_dup_cache_free(pm) ;
-/* Return prefix list entry which has same seq number. */
-static struct prefix_list_entry *
-prefix_seq_check (struct prefix_list *plist, int seq)
-{
- struct prefix_list_entry *pentry;
+ /* Symbol no longer has a value & drop reference. */
+ symbol_unset_value(plist->sym) ;
+ plist->sym = symbol_dec_ref(plist->sym) ;
- for (pentry = plist->head; pentry; pentry = pentry->next)
- if (pentry->seq == seq)
- return pentry;
- return NULL;
-}
+ /* Finally, release the prefix_list structure. */
+ XFREE (MTYPE_PREFIX_LIST, plist) ;
-static struct prefix_list_entry *
-prefix_list_entry_lookup (struct prefix_list *plist, struct prefix *prefix,
- enum prefix_list_type type, int seq, int le, int ge)
-{
- struct prefix_list_entry *pentry;
+ /* No longer have a recently changed prefix-list */
+ pm->recent = NULL ;
- for (pentry = plist->head; pentry; pentry = pentry->next)
- if (prefix_same (&pentry->prefix, prefix) && pentry->type == type)
- {
- if (seq >= 0 && pentry->seq != seq)
- continue;
+ /* Tell the world. */
+ if (pm->delete_hook)
+ (*pm->delete_hook) (NULL);
+} ;
- if (pentry->le != le)
- continue;
- if (pentry->ge != ge)
- continue;
+/*==============================================================================
+ * Operations on prefix_lists
+ */
- return pentry;
- }
+/* Seek prefix_list by name in give prefix master. Does NOT create. */
+static struct prefix_list *
+prefix_list_seek (struct prefix_master* pm, const char *name)
+{
+ return symbol_get_value(symbol_seek(&(pm->table), name)) ;
+} ;
- return NULL;
-}
+/* Lookup prefix_list by afi and name -- if afi is known, and name not NULL.
+ *
+ * Returns NULL if no prefix_list by that afi and name. Tolerates unknown afi
+ * and allows "fake" afi (eg. AFI_ORF_PREFIX).
+ */
+struct prefix_list *
+prefix_list_lookup (afi_t afi, const char *name)
+{
+ struct prefix_master* pm = prefix_master_get(afi) ;
-static void
-prefix_list_entry_delete (struct prefix_list *plist,
- struct prefix_list_entry *pentry,
- int update_list)
+ if ((name == NULL) || (pm == NULL))
+ return NULL;
+
+ return prefix_list_seek(pm, name) ;
+} ;
+
+/* Get prefix_list -- creating empty one if required. */
+static struct prefix_list *
+prefix_list_get (struct prefix_master* pm, const char *name, afi_t afi)
{
- if (plist == NULL || pentry == NULL)
- return;
- if (pentry->prev)
- pentry->prev->next = pentry->next;
- else
- plist->head = pentry->next;
- if (pentry->next)
- pentry->next->prev = pentry->prev;
- else
- plist->tail = pentry->prev;
+ struct symbol* sym ;
+ struct prefix_list* plist ;
- prefix_list_entry_free (pentry);
+ assert((pm != NULL) && (name != NULL)) ;
- plist->count--;
+ sym = symbol_find(&(pm->table), name) ; /* creates if required */
+ plist = symbol_get_value(sym) ;
- if (update_list)
- {
- if (plist->master->delete_hook)
- (*plist->master->delete_hook) (plist);
+ return plist ? plist : prefix_list_new(pm, sym, afi) ;
+} ;
- if (plist->head == NULL && plist->tail == NULL && plist->desc == NULL)
- prefix_list_delete (plist);
- else
- plist->master->recent = plist;
- }
-}
+/*==============================================================================
+ * Operations on prefix_list_entry
+ */
-static void
-prefix_list_entry_add (struct prefix_list *plist,
- struct prefix_list_entry *pentry)
+/* Sequence comparison function -- used in prefix_list_entry_lookup_seq */
+static int
+prefix_seq_cmp(const int** seq, const struct prefix_list_entry** pe)
{
- struct prefix_list_entry *replace;
- struct prefix_list_entry *point;
+ if (**seq != (*pe)->seq)
+ return (**seq < (*pe)->seq) ? -1 : + 1 ;
+ return 0 ;
+} ;
+
+/* Check any ge and le settings -- set defaults as required.
+ *
+ * -- sets the implied le for "any" or ge, if no explicit le set
+ *
+ * -- checks le & ge and updates as required the filter.
+ *
+ * Note that filter requires le = ge = prefix-length for an exact match.
+ *
+ * Returns: CMD_SUCCESS -- it's OK
+ * CMD_WARNING -- something amiss with the ge and/or le setting
+ *
+ * If ge: must be <= maximum prefix length and > actual prefix length
+ * else: set to prefix length
+ *
+ * If le: must be <= maximum prefix length and > actual prefix length
+ * else: if ge or any set to maximum prefix length
+ * else: set to prefix length
+ *
+ * If both ge and le: must have le > ge
+ *
+ * XXX TODO: see if we can allow explicit ge == prefix_length
+ * and explicit le == ge
+ */
+static int
+prefix_list_entry_ge_le_check(struct prefix_list_entry* pe, afi_t afi)
+{
+ int pl_max = prefix_max_length(afi) ;
+ int pl = pe->prefix.prefixlen ;
+
+ /* If we had ge, check in range, otherwise set to prefixlen. */
+ if (pe->flags & PREFIX_GE)
+ {
+ if (!(pe->ge <= pl_max) || !(pe->ge > pl))
+ return CMD_WARNING ;
+ }
+ else
+ pe->ge = pl ;
- /* Automatic asignment of seq no. */
- if (pentry->seq == -1)
- pentry->seq = prefix_new_seq_get (plist);
+ /* If we had le, check in range, otherwise set as required. */
+ if (pe->flags & PREFIX_LE)
+ {
+ if (!(pe->le <= pl_max) || !(pe->le > pl))
+ return CMD_WARNING ;
+ }
+ else
+ pe->le = (pe->flags & (PREFIX_ANY | PREFIX_GE)) ? pl_max : pl ;
- /* Is there any same seq prefix list entry? */
- replace = prefix_seq_check (plist, pentry->seq);
- if (replace)
- prefix_list_entry_delete (plist, replace, 0);
+ /* If had both ge and le, check that le > ge. */
+ if ((pe->flags & (PREFIX_GE | PREFIX_LE)) == (PREFIX_GE | PREFIX_LE))
+ if (pe->le <= pe->ge)
+ return CMD_WARNING ;
- /* Check insert point. */
- for (point = plist->head; point; point = point->next)
- if (point->seq >= pentry->seq)
- break;
+ return CMD_SUCCESS ;
+} ;
- /* In case of this is the first element of the list. */
- pentry->next = point;
+/* Lookup prefix_list_entry by its sequence number. Returns index of an entry
+ * in the prefix_list, and sets:
+ *
+ * result < 0 -- not found. index returned is of first entry in the
+ * prefix list, and this sequence number comes
+ * before it. (Or list is empty.)
+ * result == 0 -- found. index is of the entry found.
+ * result > 0 -- not found. index returned is of the entry with the largest
+ * sequence number smaller than the given one.
+ */
+static vector_index
+prefix_list_entry_lookup_seq(struct prefix_list *plist, int seq, int* result)
+{
+ return vector_bsearch(&plist->list, (vector_bsearch_cmp*)prefix_seq_cmp,
+ &seq, result) ;
+} ;
- if (point)
+/* Lookup prefix_list_entry by its contents.
+ *
+ * For large prefix_lists this uses the "dup_cache", which is an auxiliary
+ * vector, sorted by prefix value. Each prefix_master has a dup_cache,
+ * which is co-opted by the last prefix_list to use it.
+ *
+ * Returns index of an entry in the prefix_list or the dup_cache, and sets:
+ *
+ * cache -- NULL if not using dup_cache for this prefix_list.
+ * The index and result values refer to the main prefix_list.
+ *
+ * -- address of the cache (a vector).
+ * The index and result values refer to the cache. << NB
+ *
+ * result < 0 -- not found. index returned is of first entry in the
+ * prefix list, and this sequence number comes
+ * before it. (Or list is empty.)
+ * result == 0 -- found. index is of the entry found.
+ * result > 0 -- not found. index returned is of the entry with the largest
+ * sequence number smaller than the given one.
+ */
+static vector_index
+prefix_list_entry_lookup_val(struct prefix_list *plist,
+ struct prefix_list_entry* temp,
+ vector* cache,
+ int* result)
+{
+ /* See if we already have an entry like this one. */
+ if (vector_end(&plist->list) > 10)
{
- if (point->prev)
- point->prev->next = pentry;
- else
- plist->head = pentry;
-
- pentry->prev = point->prev;
- point->prev = pentry;
+ struct prefix_master* pm = plist->master ;
+
+ if (pm->cache_owner != plist)
+ {
+ /* Create new cache by copying vector. Releases any old cache. */
+ vector_copy_here(&pm->dup_cache, &plist->list) ;
+ /* Sort the result so can binary chop it. */
+ vector_sort(&pm->dup_cache, (vector_sort_cmp*)plist->cmp) ;
+ /* Now we own the cache. */
+ pm->cache_owner = plist ;
+ } ;
+
+ *cache = &pm->dup_cache ;
+ return vector_bsearch(*cache, (vector_bsearch_cmp*)plist->cmp, temp,
+ result) ;
}
else
{
- if (plist->tail)
- plist->tail->next = pentry;
- else
- plist->head = pentry;
+ struct prefix_list_entry* pe ;
+ vector_index i ;
+ *cache = NULL ; /* Not found in cache. */
+ *result = 0 ; /* Assume found ! */
+ for (VECTOR_ITEMS(&plist->list, pe, i))
+ {
+ if (plist->cmp(&pe, &temp) == 0)
+ return i ; /* Found ! */
+ } ;
+ *result = 1 ; /* Not found. */
+ return i ;
+ } ;
+} ;
+
+/* Look up prefix_list_entry looking for an exact match.
+ *
+ * If we have an explicit sequence number, then we look that up and then
+ * see if that prefix_list_entry is identical.
+ *
+ * Otherwise, look for entry whose value is identical, if any.
+ *
+ * Returns an index of a prefix_list entry and sets:
+ *
+ * -- result == 0 found -- index is of entry found
+ * -- result != 0 not found -- index is immaterial
+ *
+ * */
+static vector_index
+prefix_list_entry_lookup (struct prefix_list* plist,
+ struct prefix_list_entry* pe_seek, int* result)
+{
+ struct prefix_list_entry* pe_found ;
+ vector_index i ;
- pentry->prev = plist->tail;
- plist->tail = pentry;
+ if (pe_seek->flags & PREFIX_SEQ)
+ {
+ /* Lookup by sequence number. */
+ i = prefix_list_entry_lookup_seq(plist, pe_seek->seq, result) ;
+ if (*result == 0)
+ {
+ /* found by sequence number, now see if value matches. */
+ pe_found = vector_get_item(&plist->list, i) ;
+ *result = plist->cmp(&pe_seek, &pe_found) ;
+ } ;
+ }
+ else
+ {
+ /* Lookup by value. */
+ vector cache ;
+ i = prefix_list_entry_lookup_val(plist, pe_seek, &cache, result) ;
+ if ((*result == 0) && cache)
+ {
+ /* Found in the cache. We need it's position in prefix_list */
+ pe_found = vector_get_item(cache, i) ;
+ i = prefix_list_entry_lookup_seq(plist, pe_found->seq, result) ;
+ assert(*result == 0) ; /* MUST Find it !! */
+ } ;
}
- /* Increment count. */
- plist->count++;
+ return i ;
+} ;
+
+/* Insert prefix_list_entry or replace an existing one, if we can.
+ *
+ * May NOT insert or replace if an entry already exists with the same value,
+ * (where the value excludes the sequence number).
+ *
+ * Except that, if a sequence number is given, it is (trivially) possible to
+ * "replace" an entry with the same sequence number and the same value.
+ *
+ * Then, if no sequence number is given, one is allocated. The allocation
+ * rounds the last sequence number up to a multiple of 5 and adds 5.
+ *
+ * The prefix_list_entry is then put in the list by sequence number, replacing
+ * any existing entry.
+ *
+ * Returns: CMD_SUCCESS -- OK
+ * CMD_WARNING -- Nope, and NB: temp->seq set to sequence number
+ * of existing prefix_list_entry.
+ */
+static int
+prefix_list_entry_insert(struct prefix_list *plist,
+ struct prefix_list_entry *temp)
+{
+ struct prefix_list_entry* pe ;
+ vector cache ;
+ vector_index i, ic ;
+ int ret, retc ;
+ u_int32_t mask ;
+ int pl ;
+
+ /* See if we have an entry like this one, if we do:
+ *
+ * OK if sequence number is the same too -- nothing more to do !
+ * Fail if sequence number differs or was not set.
+ *
+ * If not found, and we own the cache, ic and retc tell us where in the
+ * cache the new entry belongs.
+ */
+ ic = prefix_list_entry_lookup_val(plist, temp, &cache, &retc) ;
+ if (retc == 0)
+ {
+ pe = vector_get_item(cache ? cache : &plist->list, ic) ;
+ if ((temp->flags & PREFIX_SEQ) && (pe->seq == temp->seq))
+ return CMD_SUCCESS ;
+ temp->seq = pe->seq ; /* capture clashing sequence number */
+ return CMD_WARNING ;
+ } ;
+
+ /* Now we need to find where to insert in the list. */
+ /* If required, we set implied sequence number, and insert at end. */
+ if (temp->flags & PREFIX_SEQ)
+ i = prefix_list_entry_lookup_seq(plist, temp->seq, &ret) ;
+ else
+ {
+ int last_seq = 0 ;
+ i = vector_end(&plist->list) ;
+ if (i != 0)
+ {
+ --i ; /* step back to last entry */
+ pe = vector_get_item(&plist->list, i) ;
+ last_seq = pe->seq ;
+ } ;
+ temp->seq = (((last_seq + 5 - 1) / 5) * 5) + 5 ;
+ ret = 1 ; /* insert after last entry (if any) */
+ } ;
+
+ /* If we found it with same sequence number, then replace entry,
+ * otherwise we need to create a new entry and insert it. i & ret show
+ * where we need to put the value in the list.
+ *
+ * If a dup cache exists, that must be kept up to date. ic & retc show
+ * where need to put the new value in the cache.
+ */
+ if (ret == 0)
+ {
+ /* We are going to replace an existing list entry. */
+ pe = vector_get_item(&plist->list, i) ; /* address of current entry */
+ /* If we have a cache, need to move the entry to it's new place */
+ if (cache)
+ {
+ /* We need to know where the old value was. */
+ vector_index io ;
+ int reto ;
+ io = vector_bsearch(cache, (vector_bsearch_cmp*)plist->cmp, pe,
+ &reto) ;
+ assert(reto == 0) ; /* MUST find it !! */
+ vector_move_item_here(cache, ic, retc, io) ;
+ } ;
+ }
+ else
+ {
+ /* We are going to insert a new list entry item. */
+ pe = prefix_list_entry_new() ;
+ vector_insert_item_here(&plist->list, i, ret, pe) ;
+ /* If we have a cache, need to insert the entry to it's place */
+ if (cache)
+ vector_insert_item_here(cache, ic, retc, pe) ;
+ } ;
+
+ /* Now we can set the value of the entry. */
+ *pe = *temp ;
+
+ /* Set mask and last ready to apply the filter. */
+ /* Note: if we don't have s6_addr32, we must handle IPv6 byte-wise ! */
+ pl = pe->prefix.prefixlen ;
+ mask = htonl((0xFFFFFFFF >> (pl & 0x1F)) ^ 0xFFFFFFFF) ;
+ switch (plist->afi)
+ {
+ case AFI_IP:
+ pe->mask = mask ;
+ break ;
+ case AFI_IP6:
+#ifdef s6_addr32
+ pe->mask = mask ;
+ pe->last = (pl == 0) ? 0 : (pl - 1) >> 5 ;
+#else
+ pe->mask = (0xFF >> (pl & 0x07)) ^ 0xFF ;
+ pe->last = (pl == 0) ? 0 : (pl - 1) >> 3 ;
+#endif
+ break ;
+ default:
+ assert(0) ;
+ } ;
/* Run hook function. */
if (plist->master->add_hook)
(*plist->master->add_hook) (plist);
plist->master->recent = plist;
+
+ return CMD_SUCCESS ;
}
+/* Delete prefix_list_entry, if we can.
+ *
+ * To delete an entry the caller must specify the exact value of an existing
+ * entry. If a sequence number is specified, that entry must exist, and its
+ * value must exactly match the given value. If no sequence number is
+ * specified, an entry must exist with exactly the given value.
+ *
+ * Returns: CMD_SUCCESS -- OK
+ * CMD_WARNING -- entry not found.
+ */
+static int
+prefix_list_entry_delete (struct prefix_list *plist,
+ struct prefix_list_entry *pe_seek)
+{
+ struct prefix_list_entry* pe ;
+ vector_index i ;
+ int ret ;
+
+ i = prefix_list_entry_lookup (plist, pe_seek, &ret) ;
+ if (ret)
+ return CMD_WARNING ;
+
+ pe = vector_delete_item(&plist->list, i) ;
+ assert(pe != NULL) ;
+
+ prefix_list_entry_free(pe) ; /* now release memory */
+
+ if (plist->master->delete_hook)
+ (*plist->master->delete_hook) (plist);
+
+ if ((vector_end(&plist->list) == 0) && (plist->desc == NULL))
+ prefix_list_delete (plist);
+ else
+ plist->master->recent = plist;
+
+ return CMD_SUCCESS ;
+} ;
+
+/*==============================================================================
+ * Common printing operations
+ */
+
/* Return string of prefix_list_type. */
static const char *
prefix_list_type_str (struct prefix_list_entry *pentry)
@@ -532,179 +991,192 @@ prefix_list_type_str (struct prefix_list_entry *pentry)
}
}
-static int
-prefix_list_entry_match (struct prefix_list_entry *pentry, struct prefix *p)
+/* Map afi to name of same: "ip" or "ipv6". Implied assert_afi_real(). */
+static const char*
+prefix_afi_name_str(afi_t afi)
{
- int ret;
+ switch (afi)
+ {
+ case AFI_IP:
+ return "ip" ;
+#ifdef HAVE_IPV6
+ case AFI_IP6:
+ return "ipv6" ;
+#endif
+ default:
+ assert(0) ; /* Should not get here ! */
+ return "?" ;
+ } ;
+} ;
- ret = prefix_match (&pentry->prefix, p);
- if (! ret)
- return 0;
-
- /* In case of le nor ge is specified, exact match is performed. */
- if (! pentry->le && ! pentry->ge)
- {
- if (pentry->prefix.prefixlen != p->prefixlen)
- return 0;
- }
- else
- {
- if (pentry->le)
- if (p->prefixlen > pentry->le)
- return 0;
-
- if (pentry->ge)
- if (p->prefixlen < pentry->ge)
- return 0;
- }
- return 1;
-}
+/* Print: "(ip|ipv6) prefix-list NAME" <post> */
+static void
+vty_prefix_list_name_print(struct vty* vty, struct prefix_list* plist,
+ const char* post)
+{
+ vty_out(vty, "%s prefix-list %s%s", prefix_afi_name_str(plist->afi),
+ (const char*)symbol_get_name(plist->sym), post) ;
+} ;
-enum prefix_list_type
-prefix_list_apply (struct prefix_list *plist, void *object)
+/* Print: "(ip|ipv6) prefix-list NAME: 99 entries" <post> */
+static void
+vty_prefix_list_name_count_print(struct vty* vty, struct prefix_list* plist,
+ const char* post)
{
- struct prefix_list_entry *pentry;
- struct prefix *p;
+ vty_prefix_list_name_print(vty, plist, "") ;
+ vty_out(vty, ": %d entries%s", vector_end(&plist->list), post);
+} ;
- p = (struct prefix *) object;
+/* Print: "(ip|ipv6) prefix-list NAME" UNDEFINED<post> */
+static void
+vty_prefix_list_undefined_print(struct vty* vty, afi_t afi, struct symbol* sym,
+ const char* post)
+{
+ vty_out(vty, "%s prefix-list %s UNDEFINED%s", prefix_afi_name_str(afi),
+ (const char*)symbol_get_name(sym), post) ;
+} ;
- if (plist == NULL)
- return PREFIX_DENY;
+/* Print: <indent>"Description: xxxx"<post>, if there is a description */
+static void
+vty_prefix_list_desc_print(struct vty* vty, struct prefix_list* plist,
+ int indent, const char* post)
+{
+ if (plist->desc)
+ vty_out (vty, "%sDescription: %s%s", VTY_SPACES(indent), plist->desc,
+ VTY_NEWLINE) ;
+}
+
+/* Size of buffer to hold either IPv4 or IPv6 string. */
+#ifndef INETX_ADDRSTRLEN
+# if INET_ADDRSTRLEN < INET6_ADDRSTRLEN
+# define INETX_ADDRSTRLEN INET6_ADDRSTRLEN
+# else
+# define INETX_ADDRSTRLEN INET_ADDRSTLEN
+# endif
+#endif
+
+/* Print value of given prefix_list_entry:
+ *
+ * "[seq 999 ](permit|deny) (any|XXXXX/999)[ ge 99][ le 99]"
+ * "[ '('hit count: 999, refcount: 999')']" <post>
+ *
+ * where: sequence number is included if "with_seq" specified
+ * ge and/or le are included if explicitly set
+ * the hit count and refcount are included if "with_stats" specified
+ */
+static void
+vty_prefix_list_value_print(struct vty* vty, struct prefix_list_entry* pe,
+ const char* post, int with_seq, int with_stats)
+{
+ if (with_seq)
+ vty_out(vty, "seq %d ", pe->seq) ;
- if (plist->count == 0)
- return PREFIX_PERMIT;
+ vty_out(vty, "%s ", prefix_list_type_str(pe)) ;
- for (pentry = plist->head; pentry; pentry = pentry->next)
+ if (pe->flags & PREFIX_ANY)
+ vty_puts(vty, "any");
+ else
{
- pentry->refcnt++;
- if (prefix_list_entry_match (pentry, p))
- {
- pentry->hitcnt++;
- return pentry->type;
- }
- }
+ struct prefix *p = &pe->prefix ;
+ char buf[INETX_ADDRSTRLEN];
+ vty_out(vty, "%s/%d",
+ inet_ntop (p->family, &p->u.prefix, buf, INETX_ADDRSTRLEN),
+ p->prefixlen);
+ } ;
- return PREFIX_DENY;
+ if (pe->flags & PREFIX_GE)
+ vty_out(vty, " ge %d", pe->ge);
+ if (pe->flags & PREFIX_LE)
+ vty_out(vty, " le %d", pe->le);
+
+ if (with_stats)
+ vty_out (vty, " (hit count: %lu, refcount: %lu)", pe->hitcnt, pe->refcnt);
+
+ vty_puts(vty, post) ;
}
static void __attribute__ ((unused))
prefix_list_print (struct prefix_list *plist)
{
- struct prefix_list_entry *pentry;
+ struct prefix_list_entry* pe ;
+ vector_index i ;
+ struct vty* vty = NULL ;
if (plist == NULL)
return;
- printf ("ip prefix-list %s: %d entries\n", plist->name, plist->count);
+ vty_prefix_list_name_count_print(vty, plist, VTY_NEWLINE) ;
- for (pentry = plist->head; pentry; pentry = pentry->next)
+ for (VECTOR_ITEMS(&plist->list, pe, i))
{
- if (pentry->any)
- printf ("any %s\n", prefix_list_type_str (pentry));
- else
- {
- struct prefix *p;
- char buf[BUFSIZ];
-
- p = &pentry->prefix;
-
- printf (" seq %d %s %s/%d",
- pentry->seq,
- prefix_list_type_str (pentry),
- inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ),
- p->prefixlen);
- if (pentry->ge)
- printf (" ge %d", pentry->ge);
- if (pentry->le)
- printf (" le %d", pentry->le);
- printf ("\n");
- }
+ vty_out_indent(vty, 2) ;
+ vty_prefix_list_value_print(vty, pe, VTY_NEWLINE, 1, 1) ;
}
}
-
-/* Retrun 1 when plist already include pentry policy. */
-static struct prefix_list_entry *
-prefix_entry_dup_check (struct prefix_list *plist,
- struct prefix_list_entry *new)
-{
- struct prefix_list_entry *pentry;
- int seq = 0;
-
- if (new->seq == -1)
- seq = prefix_new_seq_get (plist);
- else
- seq = new->seq;
-
- for (pentry = plist->head; pentry; pentry = pentry->next)
- {
- if (prefix_same (&pentry->prefix, &new->prefix)
- && pentry->type == new->type
- && pentry->le == new->le
- && pentry->ge == new->ge
- && pentry->seq != seq)
- return pentry;
- }
- return NULL;
-}
+/*==============================================================================
+ * vty prefix_list operations.
+ */
-static int
-vty_invalid_prefix_range (struct vty *vty, const char *prefix)
+/* Look up given prefix_list -- complain if not found. */
+static struct prefix_list*
+vty_prefix_list_lookup(struct vty *vty, afi_t afi, const char* name)
{
- vty_out (vty, "%% Invalid prefix range for %s, make sure: len < ge-value <= le-value%s",
- prefix, VTY_NEWLINE);
- return CMD_WARNING;
-}
+ struct prefix_list* plist = prefix_list_lookup(afi, name);
+ if (plist == NULL)
+ vty_out (vty, "%% Can't find specified prefix-list%s", VTY_NEWLINE);
+ return plist ;
+} ;
+/* Process parameters for (ip|ipv6) prefix-list and no (ip|ipv6) prefix-list
+ *
+ * Fills in the given prefix_list_entry structure, ready for looking up,
+ * inserting or deleting prefix_list_entry.
+ *
+ * Checks parameters for validity/legality.
+ *
+ * Returns a CMD_xxxx return code. CMD_SUCCESS => OK !
+ */
static int
-vty_prefix_list_install (struct vty *vty, afi_t afi, const char *name,
- const char *seq, const char *typestr,
- const char *prefix, const char *ge, const char *le)
+vty_prefix_list_process(struct vty *vty, struct prefix_list_entry* pe,
+ struct prefix_list* plist,
+ afi_t afi, const char *seq_str, const char *type_str,
+ const char *prefix_str,
+ const char *ge_str, const char *le_str)
{
- int ret;
- enum prefix_list_type type;
- struct prefix_list *plist;
- struct prefix_list_entry *pentry;
- struct prefix_list_entry *dup;
- struct prefix p;
- int any = 0;
- int seqnum = -1;
- int lenum = 0;
- int genum = 0;
+ int ret ;
- /* Sequential number. */
- if (seq)
- seqnum = atoi (seq);
+ assert_afi_real(afi) ; /* require real (and supported) afi */
- /* ge and le number */
- if (ge)
- genum = atoi (ge);
- if (le)
- lenum = atoi (le);
+ prefix_list_entry_init(pe) ; /* clears everything, including flags */
+
+ /* Sequence number. */
+ if (seq_str)
+ {
+ pe->flags |= PREFIX_SEQ ;
+ pe->seq = atoi(seq_str) ;
+ } ;
/* Check filter type. */
- if (strncmp ("permit", typestr, 1) == 0)
- type = PREFIX_PERMIT;
- else if (strncmp ("deny", typestr, 1) == 0)
- type = PREFIX_DENY;
+ if (strncmp ("permit", type_str, 1) == 0)
+ pe->type = PREFIX_PERMIT;
+ else if (strncmp ("deny", type_str, 1) == 0)
+ pe->type = PREFIX_DENY;
else
{
vty_out (vty, "%% prefix type must be permit or deny%s", VTY_NEWLINE);
return CMD_WARNING;
}
- /* "any" is special token for matching any IPv4 addresses. */
+ /* Watch out for "any" */
+ if (strncmp ("any", prefix_str, strlen (prefix_str)) == 0)
+ pe->flags |= PREFIX_ANY ;
+
+ /* Process the prefix. */
if (afi == AFI_IP)
{
- if (strncmp ("any", prefix, strlen (prefix)) == 0)
- {
- ret = str2prefix_ipv4 ("0.0.0.0/0", (struct prefix_ipv4 *) &p);
- genum = 0;
- lenum = IPV4_MAX_BITLEN;
- any = 1;
- }
- else
- ret = str2prefix_ipv4 (prefix, (struct prefix_ipv4 *) &p);
-
+ if (pe->flags & PREFIX_ANY)
+ prefix_str = "0.0.0.0/0" ;
+ ret = str2prefix_ipv4 (prefix_str, (struct prefix_ipv4 *)&pe->prefix);
if (ret <= 0)
{
vty_out (vty, "%% Malformed IPv4 prefix%s", VTY_NEWLINE);
@@ -714,16 +1186,9 @@ vty_prefix_list_install (struct vty *vty, afi_t afi, const char *name,
#ifdef HAVE_IPV6
else if (afi == AFI_IP6)
{
- if (strncmp ("any", prefix, strlen (prefix)) == 0)
- {
- ret = str2prefix_ipv6 ("::/0", (struct prefix_ipv6 *) &p);
- genum = 0;
- lenum = IPV6_MAX_BITLEN;
- any = 1;
- }
- else
- ret = str2prefix_ipv6 (prefix, (struct prefix_ipv6 *) &p);
-
+ if (pe->flags & PREFIX_ANY)
+ prefix_str = "::/0" ;
+ ret = str2prefix_ipv6 (prefix_str, (struct prefix_ipv6 *)&pe->prefix);
if (ret <= 0)
{
vty_out (vty, "%% Malformed IPv6 prefix%s", VTY_NEWLINE);
@@ -732,155 +1197,147 @@ vty_prefix_list_install (struct vty *vty, afi_t afi, const char *name,
}
#endif /* HAVE_IPV6 */
- /* ge and le check. */
- if (genum && genum <= p.prefixlen)
- return vty_invalid_prefix_range (vty, prefix);
+ /* ge and le number */
+ if (ge_str)
+ {
+ pe->ge = atoi (ge_str) ;
+ pe->flags |= PREFIX_GE ;
+ }
+
+ if (le_str)
+ {
+ pe->le = atoi (le_str);
+ pe->flags |= PREFIX_LE ;
+ } ;
+
+ /* Complete the entry we've constructed, and check ge and le. */
+ ret = prefix_list_entry_ge_le_check(pe, afi) ;
+
+ if (ret != CMD_SUCCESS)
+ vty_out (vty, "%% Invalid prefix range for %s, make sure: "
+ "len < ge-value <= le-value%s",
+ prefix_str, VTY_NEWLINE);
- if (lenum && lenum <= p.prefixlen)
- return vty_invalid_prefix_range (vty, prefix);
+ return ret ;
+} ;
+
+/* Install a prefix_list_entry.
+ *
+ * Deals with all of ip prefix-list and ipv6 prefix-list commands.
+ *
+ * Note:
+ *
+ */
+
+static int
+vty_prefix_list_install (struct vty *vty, afi_t afi, const char *name,
+ const char *seq_str, const char *type_str,
+ const char *prefix_str,
+ const char *ge_str, const char *le_str)
+{
+ struct prefix_master* pm ;
+ struct prefix_list *plist;
+ struct prefix_list_entry temp ;
+ int ret;
- if (lenum && genum > lenum)
- return vty_invalid_prefix_range (vty, prefix);
+ assert_afi_real(afi) ; /* UI stuff should ensure this */
+ pm = prefix_master_get(afi) ;
- if (genum && lenum == (afi == AFI_IP ? 32 : 128))
- lenum = 0;
+ /* Get prefix_list with name. Make new list if required. */
+ plist = prefix_list_get(pm, name, afi) ;
- /* Get prefix_list with name. */
- plist = prefix_list_get (afi, name);
+ /* Do the grunt work on the parameters.
+ * Completely fill in the temp prefix_list_entry structure.
+ */
+ ret = vty_prefix_list_process(vty, &temp, plist, afi, seq_str, type_str,
+ prefix_str, ge_str, le_str) ;
+ if (ret != CMD_SUCCESS)
+ return ret ;
- /* Make prefix entry. */
- pentry = prefix_list_entry_make (&p, type, seqnum, lenum, genum, any);
-
- /* Check same policy. */
- dup = prefix_entry_dup_check (plist, pentry);
+ /* Insert into the list, unless list contains an entry which is the same
+ * apart from the sequence number.
+ * If fails, sets the sequence no. in temp to the sequence number found.
+ */
+ ret = prefix_list_entry_insert(plist, &temp);
- if (dup)
+ if (ret != CMD_SUCCESS)
{
- prefix_list_entry_free (pentry);
vty_out (vty, "%% Insertion failed - prefix-list entry exists:%s",
VTY_NEWLINE);
- vty_out (vty, " seq %d %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_WARNING;
+ vty_out_indent(vty, 2) ;
+ vty_prefix_list_value_print(vty, &temp, VTY_NEWLINE, 1, 0) ;
}
- /* Install new filter to the access_list. */
- prefix_list_entry_add (plist, pentry);
-
return CMD_SUCCESS;
}
+/* Remove a prefix_list_entry. */
static int
-vty_prefix_list_uninstall (struct vty *vty, afi_t afi, const char *name,
- const char *seq, const char *typestr,
- const char *prefix, const char *ge, const char *le)
+vty_prefix_list_uninstall(struct vty *vty, afi_t afi, const char *name,
+ const char *seq_str, const char *type_str,
+ const char *prefix_str,
+ const char *ge_str, const char *le_str)
{
- int ret;
- enum prefix_list_type type;
struct prefix_list *plist;
- struct prefix_list_entry *pentry;
- struct prefix p;
- int seqnum = -1;
- int lenum = 0;
- int genum = 0;
+ struct prefix_list_entry temp ;
+ int ret;
- /* Check prefix list name. */
- plist = prefix_list_lookup (afi, name);
- if (! plist)
- {
- vty_out (vty, "%% Can't find specified prefix-list%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
+ assert_afi_real(afi) ; /* UI should guarantee this. */
+
+ /* Seek prefix_list with name -- error if not found. */
+ plist = vty_prefix_list_lookup(vty, afi, name);
+ if (plist == NULL)
+ return CMD_WARNING ;
/* Only prefix-list name specified, delete the entire prefix-list. */
- if (seq == NULL && typestr == NULL && prefix == NULL &&
- ge == NULL && le == NULL)
+ if (seq_str == NULL && type_str == NULL && prefix_str == NULL &&
+ ge_str == NULL && le_str == NULL)
{
prefix_list_delete (plist);
return CMD_SUCCESS;
}
/* We must have, at a minimum, both the type and prefix here */
- if ((typestr == NULL) || (prefix == NULL))
+ if ((type_str == NULL) || (prefix_str == NULL))
{
vty_out (vty, "%% Both prefix and type required%s", VTY_NEWLINE);
return CMD_WARNING;
}
- /* Check sequence number. */
- if (seq)
- seqnum = atoi (seq);
+ /* Do the grunt work on the parameters.
+ * Completely fill in the temp prefix_list_entry structure.
+ */
+ ret = vty_prefix_list_process(vty, &temp, plist, afi, seq_str, type_str,
+ prefix_str, ge_str, le_str) ;
+ if (ret != CMD_SUCCESS)
+ return ret ;
- /* ge and le number */
- if (ge)
- genum = atoi (ge);
- if (le)
- lenum = atoi (le);
-
- /* Check of filter type. */
- if (strncmp ("permit", typestr, 1) == 0)
- type = PREFIX_PERMIT;
- else if (strncmp ("deny", typestr, 1) == 0)
- type = PREFIX_DENY;
- else
- {
- vty_out (vty, "%% prefix type must be permit or deny%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
+ /* Remove prefix_list_entry if we can. */
+ ret = prefix_list_entry_delete (plist, &temp);
- /* "any" is special token for matching any IPv4 addresses. */
- if (afi == AFI_IP)
- {
- if (strncmp ("any", prefix, strlen (prefix)) == 0)
- {
- ret = str2prefix_ipv4 ("0.0.0.0/0", (struct prefix_ipv4 *) &p);
- genum = 0;
- lenum = IPV4_MAX_BITLEN;
- }
- else
- ret = str2prefix_ipv4 (prefix, (struct prefix_ipv4 *) &p);
+ if (ret != CMD_SUCCESS)
+ vty_out (vty, "%% Can't find specified prefix-list%s", VTY_NEWLINE);
- if (ret <= 0)
- {
- vty_out (vty, "%% Malformed IPv4 prefix%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
- }
-#ifdef HAVE_IPV6
- else if (afi == AFI_IP6)
- {
- if (strncmp ("any", prefix, strlen (prefix)) == 0)
- {
- ret = str2prefix_ipv6 ("::/0", (struct prefix_ipv6 *) &p);
- genum = 0;
- lenum = IPV6_MAX_BITLEN;
- }
- else
- ret = str2prefix_ipv6 (prefix, (struct prefix_ipv6 *) &p);
+ return ret;
+}
- if (ret <= 0)
- {
- vty_out (vty, "%% Malformed IPv6 prefix%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
- }
-#endif /* HAVE_IPV6 */
+static int
+vty_prefix_list_desc_set (struct vty *vty, afi_t afi, const char *name,
+ char* desc)
+{
+ struct prefix_master* pm ;
+ struct prefix_list *plist;
- /* Lookup prefix entry. */
- pentry = prefix_list_entry_lookup(plist, &p, type, seqnum, lenum, genum);
+ assert_afi_real(afi) ; /* UI stuff should ensure this */
+ pm = prefix_master_get(afi) ;
- if (pentry == NULL)
- {
- vty_out (vty, "%% Can't find specified prefix-list%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
+ /* Get prefix_list with name. Make new list if required. */
+ plist = prefix_list_get(pm, name, afi) ;
+
+ if (plist->desc)
+ XFREE (MTYPE_TMP, plist->desc) ; /* Discard any existing value */
- /* Install new filter to the access_list. */
- prefix_list_entry_delete (plist, pentry, 1);
+ plist->desc = desc ;
return CMD_SUCCESS;
}
@@ -890,21 +1347,15 @@ vty_prefix_list_desc_unset (struct vty *vty, afi_t afi, const char *name)
{
struct prefix_list *plist;
- plist = prefix_list_lookup (afi, name);
- if (! plist)
- {
- vty_out (vty, "%% Can't find specified prefix-list%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
+ plist = vty_prefix_list_lookup(vty, afi, name);
+ if (plist == NULL)
+ return CMD_WARNING ;
if (plist->desc)
- {
- XFREE (MTYPE_TMP, plist->desc);
- plist->desc = NULL;
- }
+ XFREE (MTYPE_TMP, plist->desc) ; /* sets plist->dec to NULL */
- if (plist->head == NULL && plist->tail == NULL && plist->desc == NULL)
- prefix_list_delete (plist);
+ if (vector_end(&plist->list) == 0)
+ prefix_list_delete(plist) ; /* delete list if all gone now */
return CMD_SUCCESS;
}
@@ -916,143 +1367,135 @@ enum display_type
detail_display,
sequential_display,
longer_display,
- first_match_display
+ first_match_display,
};
+/* Show given prefix_list */
static void
-vty_show_prefix_entry (struct vty *vty, afi_t afi, struct prefix_list *plist,
- struct prefix_master *master, enum display_type dtype,
+vty_show_prefix_entry (struct vty *vty, struct prefix_list *plist,
+ struct prefix_master* pm, enum display_type dtype,
int seqnum)
{
- struct prefix_list_entry *pentry;
-
/* Print the name of the protocol */
if (zlog_default)
- vty_out (vty, "%s: ", zlog_proto_names[zlog_default->protocol]);
-
+ vty_out (vty, "%s: ", zlog_get_proto_name(NULL));
+
if (dtype == normal_display)
{
- vty_out (vty, "ip%s prefix-list %s: %d entries%s",
- afi == AFI_IP ? "" : "v6",
- plist->name, plist->count, VTY_NEWLINE);
- if (plist->desc)
- vty_out (vty, " Description: %s%s", plist->desc, VTY_NEWLINE);
+ vty_prefix_list_name_count_print(vty, plist, VTY_NEWLINE) ;
+ vty_prefix_list_desc_print(vty, plist, 3, VTY_NEWLINE) ;
}
else if (dtype == summary_display || dtype == detail_display)
{
- vty_out (vty, "ip%s prefix-list %s:%s",
- afi == AFI_IP ? "" : "v6", plist->name, VTY_NEWLINE);
+ struct prefix_list_entry* p_f = vector_get_first_item(&plist->list) ;
+ struct prefix_list_entry* p_l = vector_get_last_item(&plist->list) ;
+
+ vty_prefix_list_name_print(vty, plist, ":") ;
+ vty_out_newline(vty) ;
- if (plist->desc)
- vty_out (vty, " Description: %s%s", plist->desc, VTY_NEWLINE);
+ vty_prefix_list_desc_print(vty, plist, 3, VTY_NEWLINE) ;
vty_out (vty, " count: %d, range entries: %d, sequences: %d - %d%s",
- plist->count, plist->rangecount,
- plist->head ? plist->head->seq : 0,
- plist->tail ? plist->tail->seq : 0,
+ vector_end(&plist->list), plist->rangecount,
+ p_f ? p_f->seq : 0,
+ p_l ? p_l->seq : 0,
VTY_NEWLINE);
- }
+ } ;
if (dtype != summary_display)
{
- for (pentry = plist->head; pentry; pentry = pentry->next)
+ struct prefix_list_entry* pe ;
+ vector_index i ;
+ int with_seq = pm->seqnum_flag ;
+ int with_stats = (dtype == detail_display)
+ ||(dtype == sequential_display) ;
+
+ for (VECTOR_ITEMS(&plist->list, pe, i))
{
- if (dtype == sequential_display && pentry->seq != seqnum)
+ if ((dtype == sequential_display) && (pe->seq != seqnum))
continue;
-
- vty_out (vty, " ");
-
- if (master->seqnum)
- vty_out (vty, "seq %d ", pentry->seq);
- vty_out (vty, "%s ", prefix_list_type_str (pentry));
-
- if (pentry->any)
- vty_out (vty, "any");
- else
- {
- struct prefix *p = &pentry->prefix;
- char buf[BUFSIZ];
-
- vty_out (vty, "%s/%d",
- inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ),
- p->prefixlen);
-
- if (pentry->ge)
- vty_out (vty, " ge %d", pentry->ge);
- if (pentry->le)
- vty_out (vty, " le %d", pentry->le);
- }
-
- if (dtype == detail_display || dtype == sequential_display)
- vty_out (vty, " (hit count: %ld, refcount: %ld)",
- pentry->hitcnt, pentry->refcnt);
-
- vty_out (vty, "%s", VTY_NEWLINE);
+ vty_out_indent(vty, 3);
+ vty_prefix_list_value_print(vty, pe, VTY_NEWLINE,
+ with_seq, with_stats) ;
}
}
}
+/* Show given prefix list in given afi, or all prefix lists in given afi. */
+
static int
vty_show_prefix_list (struct vty *vty, afi_t afi, const char *name,
- const char *seq, enum display_type dtype)
+ const char *seq_str, enum display_type dtype)
{
struct prefix_list *plist;
- struct prefix_master *master;
- int seqnum = 0;
+ struct prefix_master *pm;
+ int seq = 0;
- master = prefix_master_get (afi);
- if (master == NULL)
+ pm = prefix_master_get(afi) ;
+ if (pm == NULL)
return CMD_WARNING;
- if (seq)
- seqnum = atoi (seq);
+ if (seq_str)
+ seq = atoi (seq_str);
if (name)
{
- plist = prefix_list_lookup (afi, name);
- if (! plist)
- {
- vty_out (vty, "%% Can't find specified prefix-list%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
- vty_show_prefix_entry (vty, afi, plist, master, dtype, seqnum);
+ /* Note that asking after an undefined prefix_list is an error. */
+ /* Does not mention references to an undefined prefix_list. */
+ plist = vty_prefix_list_lookup(vty, afi, name);
+ if (plist == NULL)
+ return CMD_WARNING;
+ vty_show_prefix_entry (vty, plist, pm, dtype, seq);
}
else
{
+ vector extract ;
+ vector_index i ;
+ struct symbol* sym ;
+
if (dtype == detail_display || dtype == summary_display)
{
- if (master->recent)
+ if (pm->recent)
vty_out (vty, "Prefix-list with the last deletion/insertion: %s%s",
- master->recent->name, VTY_NEWLINE);
+ (const char*)symbol_get_name(pm->recent->sym), VTY_NEWLINE) ;
}
- for (plist = master->num.head; plist; plist = plist->next)
- vty_show_prefix_entry (vty, afi, plist, master, dtype, seqnum);
+ /* Extract a vector of all prefix_list symbols, in name order. */
+ extract = symbol_table_extract(&pm->table, NULL, NULL, 0,
+ symbol_mixed_name_cmp) ;
+
+ for (VECTOR_ITEMS(extract, sym, i))
+ {
+ plist = symbol_get_value(sym) ;
+ if (plist != NULL)
+ vty_show_prefix_entry(vty, plist, pm, dtype, seq);
+ else
+ vty_prefix_list_undefined_print(vty, afi, sym, VTY_NEWLINE) ;
+ }
- for (plist = master->str.head; plist; plist = plist->next)
- vty_show_prefix_entry (vty, afi, plist, master, dtype, seqnum);
+ vector_free(extract) ; /* throw away temporary vector */
}
return CMD_SUCCESS;
}
static int
-vty_show_prefix_list_prefix (struct vty *vty, afi_t afi, const char *name,
+vty_show_prefix_list_prefix (struct vty *vty, afi_t afi, const char *name,
const char *prefix, enum display_type type)
{
struct prefix_list *plist;
- struct prefix_list_entry *pentry;
+ struct prefix_list_entry* pe ;
+ vector_index i ;
struct prefix p;
int ret;
int match;
+ int with_stats ;
- plist = prefix_list_lookup (afi, name);
- if (! plist)
- {
- vty_out (vty, "%% Can't find specified prefix-list%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
+ /* Error if cannot find prefix list. */
+ plist = vty_prefix_list_lookup(vty, afi, name);
+ if (plist == NULL)
+ return CMD_WARNING;
ret = str2prefix (prefix, &p);
if (ret <= 0)
@@ -1061,88 +1504,66 @@ vty_show_prefix_list_prefix (struct vty *vty, afi_t afi, const char *name,
return CMD_WARNING;
}
- for (pentry = plist->head; pentry; pentry = pentry->next)
+ with_stats = (type == normal_display) || (type == first_match_display) ;
+
+ for (VECTOR_ITEMS(&plist->list, pe, i))
{
match = 0;
- if (type == normal_display || type == first_match_display)
- if (prefix_same (&p, &pentry->prefix))
- match = 1;
-
- if (type == longer_display)
- if (prefix_match (&p, &pentry->prefix))
- match = 1;
+ if ((type == normal_display || type == first_match_display))
+ match = prefix_same(&p, &pe->prefix) ;
+ else if (type == longer_display)
+ match = (prefix_match (&p, &pe->prefix)) ;
if (match)
{
- vty_out (vty, " seq %d %s ",
- pentry->seq,
- prefix_list_type_str (pentry));
-
- if (pentry->any)
- vty_out (vty, "any");
- else
- {
- struct prefix *p = &pentry->prefix;
- char buf[BUFSIZ];
-
- vty_out (vty, "%s/%d",
- inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ),
- p->prefixlen);
-
- if (pentry->ge)
- vty_out (vty, " ge %d", pentry->ge);
- if (pentry->le)
- vty_out (vty, " le %d", pentry->le);
- }
-
- if (type == normal_display || type == first_match_display)
- vty_out (vty, " (hit count: %ld, refcount: %ld)",
- pentry->hitcnt, pentry->refcnt);
-
- vty_out (vty, "%s", VTY_NEWLINE);
+ vty_out_indent(vty, 3);
+ vty_prefix_list_value_print(vty, pe, VTY_NEWLINE, 1, with_stats) ;
if (type == first_match_display)
- return CMD_SUCCESS;
+ break ;
}
}
return CMD_SUCCESS;
}
+/* Clear hit counters in all prefix_list_entries:
+ *
+ * a) in all prefix_lists -- name NULL
+ * b) in given prefix list -- prefix NULL
+ * c) that match given prefix, in given prefix_list
+ */
static int
-vty_clear_prefix_list (struct vty *vty, afi_t afi, const char *name,
+vty_clear_prefix_list (struct vty *vty, afi_t afi, const char *name,
const char *prefix)
{
- struct prefix_master *master;
+ struct prefix_master *pm;
struct prefix_list *plist;
- struct prefix_list_entry *pentry;
int ret;
struct prefix p;
+ struct prefix_list_entry* pe ;
+ vector_index i ;
- master = prefix_master_get (afi);
- if (master == NULL)
+ pm = prefix_master_get (afi);
+ if (pm == NULL)
return CMD_WARNING;
- if (name == NULL && prefix == NULL)
+ if (name == NULL)
{
- for (plist = master->num.head; plist; plist = plist->next)
- for (pentry = plist->head; pentry; pentry = pentry->next)
- pentry->hitcnt = 0;
-
- for (plist = master->str.head; plist; plist = plist->next)
- for (pentry = plist->head; pentry; pentry = pentry->next)
- pentry->hitcnt = 0;
+ struct symbol_walker walker ;
+ symbol_walk_start(&pm->table, &walker) ;
+ while ((plist = symbol_get_value(symbol_walk_next(&walker))))
+ for (VECTOR_ITEMS(&plist->list, pe, i))
+ pe->hitcnt = 0 ;
}
else
{
- plist = prefix_list_lookup (afi, name);
- if (! plist)
- {
- vty_out (vty, "%% Can't find specified prefix-list%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
+ /* Error if cannot find prefix list. */
+ plist = vty_prefix_list_lookup(vty, afi, name);
+ if (plist == NULL)
+ return CMD_WARNING;
- if (prefix)
+ if (prefix != NULL)
{
ret = str2prefix (prefix, &p);
if (ret <= 0)
@@ -1152,20 +1573,13 @@ vty_clear_prefix_list (struct vty *vty, afi_t afi, const char *name,
}
}
- for (pentry = plist->head; pentry; pentry = pentry->next)
- {
- if (prefix)
- {
- if (prefix_match (&pentry->prefix, &p))
- pentry->hitcnt = 0;
- }
- else
- pentry->hitcnt = 0;
- }
- }
- return CMD_SUCCESS;
+ for (VECTOR_ITEMS(&plist->list, pe, i))
+ if ((prefix == NULL) || prefix_match(&pe->prefix, &p))
+ pe->hitcnt = 0;
+ } ;
+return CMD_SUCCESS;
}
-
+
DEFUN (ip_prefix_list,
ip_prefix_list_cmd,
"ip prefix-list WORD (deny|permit) (A.B.C.D/M|any)",
@@ -1177,7 +1591,7 @@ DEFUN (ip_prefix_list,
"IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
"Any prefix match. Same as \"0.0.0.0/0 le 32\"\n")
{
- return vty_prefix_list_install (vty, AFI_IP, argv[0], NULL,
+ return vty_prefix_list_install (vty, AFI_IP, argv[0], NULL,
argv[1], argv[2], NULL, NULL);
}
@@ -1193,7 +1607,7 @@ DEFUN (ip_prefix_list_ge,
"Minimum prefix length to be matched\n"
"Minimum prefix length\n")
{
- return vty_prefix_list_install (vty, AFI_IP, argv[0], NULL, argv[1],
+ return vty_prefix_list_install (vty, AFI_IP, argv[0], NULL, argv[1],
argv[2], argv[3], NULL);
}
@@ -1211,7 +1625,7 @@ DEFUN (ip_prefix_list_ge_le,
"Maximum prefix length to be matched\n"
"Maximum prefix length\n")
{
- return vty_prefix_list_install (vty, AFI_IP, argv[0], NULL, argv[1],
+ return vty_prefix_list_install (vty, AFI_IP, argv[0], NULL, argv[1],
argv[2], argv[3], argv[4]);
}
@@ -1547,7 +1961,7 @@ DEFUN (ip_prefix_list_sequence_number,
PREFIX_LIST_STR
"Include/exclude sequence numbers in NVGEN\n")
{
- prefix_master_ipv4.seqnum = 1;
+ prefix_master_ipv4.seqnum_flag = 1;
return CMD_SUCCESS;
}
@@ -1559,7 +1973,7 @@ DEFUN (no_ip_prefix_list_sequence_number,
PREFIX_LIST_STR
"Include/exclude sequence numbers in NVGEN\n")
{
- prefix_master_ipv4.seqnum = 0;
+ prefix_master_ipv4.seqnum_flag = 0;
return CMD_SUCCESS;
}
@@ -1572,19 +1986,9 @@ DEFUN (ip_prefix_list_description,
"Prefix-list specific description\n"
"Up to 80 characters describing this prefix-list\n")
{
- struct prefix_list *plist;
-
- plist = prefix_list_get (AFI_IP, argv[0]);
-
- if (plist->desc)
- {
- XFREE (MTYPE_TMP, plist->desc);
- plist->desc = NULL;
- }
- plist->desc = argv_concat(argv, argc, 1);
-
- return CMD_SUCCESS;
-}
+ return vty_prefix_list_desc_set (vty, AFI_IP, argv[0],
+ argv_concat(argv, argc, 1));
+} ;
DEFUN (no_ip_prefix_list_description,
no_ip_prefix_list_description_cmd,
@@ -1759,7 +2163,7 @@ DEFUN (clear_ip_prefix_list_name_prefix,
{
return vty_clear_prefix_list (vty, AFI_IP, argv[0], argv[1]);
}
-
+
#ifdef HAVE_IPV6
DEFUN (ipv6_prefix_list,
ipv6_prefix_list_cmd,
@@ -1772,7 +2176,7 @@ DEFUN (ipv6_prefix_list,
"IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
"Any prefix match. Same as \"::0/0 le 128\"\n")
{
- return vty_prefix_list_install (vty, AFI_IP6, argv[0], NULL,
+ return vty_prefix_list_install (vty, AFI_IP6, argv[0], NULL,
argv[1], argv[2], NULL, NULL);
}
@@ -1788,7 +2192,7 @@ DEFUN (ipv6_prefix_list_ge,
"Minimum prefix length to be matched\n"
"Minimum prefix length\n")
{
- return vty_prefix_list_install (vty, AFI_IP6, argv[0], NULL, argv[1],
+ return vty_prefix_list_install (vty, AFI_IP6, argv[0], NULL, argv[1],
argv[2], argv[3], NULL);
}
@@ -1807,7 +2211,7 @@ DEFUN (ipv6_prefix_list_ge_le,
"Maximum prefix length\n")
{
- return vty_prefix_list_install (vty, AFI_IP6, argv[0], NULL, argv[1],
+ return vty_prefix_list_install (vty, AFI_IP6, argv[0], NULL, argv[1],
argv[2], argv[3], argv[4]);
}
@@ -2143,7 +2547,7 @@ DEFUN (ipv6_prefix_list_sequence_number,
PREFIX_LIST_STR
"Include/exclude sequence numbers in NVGEN\n")
{
- prefix_master_ipv6.seqnum = 1;
+ prefix_master_ipv6.seqnum_flag = 1;
return CMD_SUCCESS;
}
@@ -2155,7 +2559,7 @@ DEFUN (no_ipv6_prefix_list_sequence_number,
PREFIX_LIST_STR
"Include/exclude sequence numbers in NVGEN\n")
{
- prefix_master_ipv6.seqnum = 0;
+ prefix_master_ipv6.seqnum_flag = 0;
return CMD_SUCCESS;
}
@@ -2168,19 +2572,9 @@ DEFUN (ipv6_prefix_list_description,
"Prefix-list specific description\n"
"Up to 80 characters describing this prefix-list\n")
{
- struct prefix_list *plist;
-
- plist = prefix_list_get (AFI_IP6, argv[0]);
-
- if (plist->desc)
- {
- XFREE (MTYPE_TMP, plist->desc);
- plist->desc = NULL;
- }
- plist->desc = argv_concat(argv, argc, 1);
-
- return CMD_SUCCESS;
-}
+ return vty_prefix_list_desc_set (vty, AFI_IP6, argv[0],
+ argv_concat(argv, argc, 1));
+}
DEFUN (no_ipv6_prefix_list_description,
no_ipv6_prefix_list_description_cmd,
@@ -2355,190 +2749,138 @@ DEFUN (clear_ipv6_prefix_list_name_prefix,
return vty_clear_prefix_list (vty, AFI_IP6, argv[0], argv[1]);
}
#endif /* HAVE_IPV6 */
-
+
/* Configuration write function. */
static int
config_write_prefix_afi (afi_t afi, struct vty *vty)
{
struct prefix_list *plist;
- struct prefix_list_entry *pentry;
- struct prefix_master *master;
+ struct prefix_list_entry *pe;
+ struct prefix_master *pm;
int write = 0;
+ vector extract ;
+ vector_index i, ipe ;
+ struct symbol* sym ;
- master = prefix_master_get (afi);
- if (master == NULL)
+ pm = prefix_master_get (afi);
+ if (pm == NULL)
return 0;
- if (! master->seqnum)
+ if (! pm->seqnum_flag)
{
- vty_out (vty, "no ip%s prefix-list sequence-number%s",
+ vty_out (vty, "no ip%s prefix-list sequence-number%s",
afi == AFI_IP ? "" : "v6", VTY_NEWLINE);
vty_out (vty, "!%s", VTY_NEWLINE);
}
- for (plist = master->num.head; plist; plist = plist->next)
+ /* Extract a vector of all prefix_list symbols, in name order. */
+ extract = symbol_table_extract(&pm->table, NULL, NULL, 0,
+ symbol_mixed_name_cmp) ;
+ for (VECTOR_ITEMS(extract, sym, i))
{
- if (plist->desc)
- {
- vty_out (vty, "ip%s prefix-list %s description %s%s",
- afi == AFI_IP ? "" : "v6",
- plist->name, plist->desc, VTY_NEWLINE);
- write++;
- }
-
- for (pentry = plist->head; pentry; pentry = pentry->next)
+ plist = symbol_get_value(sym) ;
+ if (plist)
{
- vty_out (vty, "ip%s prefix-list %s ",
- afi == AFI_IP ? "" : "v6",
- plist->name);
-
- if (master->seqnum)
- vty_out (vty, "seq %d ", pentry->seq);
-
- vty_out (vty, "%s ", prefix_list_type_str (pentry));
-
- if (pentry->any)
- vty_out (vty, "any");
- else
+ if (plist->desc)
{
- struct prefix *p = &pentry->prefix;
- char buf[BUFSIZ];
-
- vty_out (vty, "%s/%d",
- inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ),
- p->prefixlen);
-
- if (pentry->ge)
- vty_out (vty, " ge %d", pentry->ge);
- if (pentry->le)
- vty_out (vty, " le %d", pentry->le);
+ vty_prefix_list_name_print(vty, plist, "") ;
+ vty_out (vty, " description %s%s", plist->desc, VTY_NEWLINE) ;
+ write++ ;
}
- vty_out (vty, "%s", VTY_NEWLINE);
- write++;
- }
- /* vty_out (vty, "!%s", VTY_NEWLINE); */
- }
- for (plist = master->str.head; plist; plist = plist->next)
- {
- if (plist->desc)
- {
- vty_out (vty, "ip%s prefix-list %s description %s%s",
- afi == AFI_IP ? "" : "v6",
- plist->name, plist->desc, VTY_NEWLINE);
- write++;
+ for (VECTOR_ITEMS(&plist->list, pe, ipe))
+ {
+ vty_prefix_list_name_print(vty, plist, " ") ;
+ vty_prefix_list_value_print(vty, pe, VTY_NEWLINE,
+ pm->seqnum_flag, 0) ;
+ write++ ;
+ }
}
-
- for (pentry = plist->head; pentry; pentry = pentry->next)
+ else
{
- vty_out (vty, "ip%s prefix-list %s ",
- afi == AFI_IP ? "" : "v6",
- plist->name);
-
- if (master->seqnum)
- vty_out (vty, "seq %d ", pentry->seq);
-
- vty_out (vty, "%s", prefix_list_type_str (pentry));
-
- if (pentry->any)
- vty_out (vty, " any");
- else
- {
- struct prefix *p = &pentry->prefix;
- char buf[BUFSIZ];
+ vty_puts(vty, "!! ") ;
+ vty_prefix_list_undefined_print(vty, afi, sym, VTY_NEWLINE) ;
+ write++ ;
+ } ;
+ } ;
- vty_out (vty, " %s/%d",
- inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ),
- p->prefixlen);
+ vector_free(extract) ; /* discard temporary vector */
- if (pentry->ge)
- vty_out (vty, " ge %d", pentry->ge);
- if (pentry->le)
- vty_out (vty, " le %d", pentry->le);
- }
- vty_out (vty, "%s", VTY_NEWLINE);
- write++;
- }
- }
-
return write;
}
struct stream *
-prefix_bgp_orf_entry (struct stream *s, struct prefix_list *plist,
+prefix_bgp_orf_entry (struct stream *s, prefix_list_ref ref,
u_char init_flag, u_char permit_flag, u_char deny_flag)
{
- struct prefix_list_entry *pentry;
+ struct prefix_list_entry *pe;
+ vector_index i ;
+
+ struct prefix_list *plist = prefix_list_ref_plist(ref) ;
if (! plist)
return s;
- for (pentry = plist->head; pentry; pentry = pentry->next)
+ for (VECTOR_ITEMS(&plist->list, pe, i))
{
- u_char flag = init_flag;
- struct prefix *p = &pentry->prefix;
-
- flag |= (pentry->type == PREFIX_PERMIT ?
- permit_flag : deny_flag);
- stream_putc (s, flag);
- stream_putl (s, (u_int32_t)pentry->seq);
- stream_putc (s, (u_char)pentry->ge);
- stream_putc (s, (u_char)pentry->le);
- stream_put_prefix (s, p);
+ stream_putc (s, init_flag | (pe->type == PREFIX_PERMIT ? permit_flag
+ : deny_flag));
+ stream_putl (s, (u_int32_t)pe->seq);
+ stream_putc (s, (u_char)pe->ge);
+ stream_putc (s, (u_char)pe->le);
+ stream_put_prefix (s, &pe->prefix);
}
return s;
}
+/* Set or Unset a BGP ORF entry. */
int
prefix_bgp_orf_set (char *name, afi_t afi, struct orf_prefix *orfp,
int permit, int set)
{
- struct prefix_list *plist;
- struct prefix_list_entry *pentry;
+ struct prefix_list *plist ;
+ struct prefix_list_entry temp ;
+ int ret ;
- /* ge and le value check */
- if (orfp->ge && orfp->ge <= orfp->p.prefixlen)
- return CMD_WARNING;
- if (orfp->le && orfp->le <= orfp->p.prefixlen)
- return CMD_WARNING;
- if (orfp->le && orfp->ge > orfp->le)
- return CMD_WARNING;
+ assert_afi_real(afi) ;
- if (orfp->ge && orfp->le == (afi == AFI_IP ? 32 : 128))
- orfp->le = 0;
-
- plist = prefix_list_get (AFI_ORF_PREFIX, name);
- if (! plist)
- return CMD_WARNING;
+ /* Transfer the values from the orf_prefix */
+ prefix_list_entry_init(&temp) ;
- if (set)
+ temp.type = permit ? PREFIX_PERMIT : PREFIX_DENY ;
+ temp.prefix = orfp->p ;
+ temp.seq = orfp->seq ; /* NB: U32 and may be zero */
+ if (orfp->ge)
{
- pentry = prefix_list_entry_make (&orfp->p,
- (permit ? PREFIX_PERMIT : PREFIX_DENY),
- orfp->seq, orfp->le, orfp->ge, 0);
+ temp.flags |= PREFIX_GE ;
+ temp.ge = orfp->ge ;
+ }
+ if (orfp->le)
+ {
+ temp.flags |= PREFIX_LE ;
+ temp.le = orfp->le ;
+ }
- if (prefix_entry_dup_check (plist, pentry))
- {
- prefix_list_entry_free (pentry);
- return CMD_WARNING;
- }
+ /* Make sure ge & le are acceptable and set as required */
+ ret = prefix_list_entry_ge_le_check(&temp, afi) ;
+ if (ret != CMD_SUCCESS)
+ return ret ;
- prefix_list_entry_add (plist, pentry);
+ /* Now insert or delete */
+ if (set)
+ {
+ plist = prefix_list_get(&prefix_master_orf, name, afi);
+ return prefix_list_entry_insert(plist, &temp) ;
}
else
{
- pentry = prefix_list_entry_lookup (plist, &orfp->p,
- (permit ? PREFIX_PERMIT : PREFIX_DENY),
- orfp->seq, orfp->le, orfp->ge);
+ plist = prefix_list_seek(&prefix_master_orf, name) ;
+ if (plist == NULL)
+ return CMD_WARNING ;
- if (! pentry)
- return CMD_WARNING;
-
- prefix_list_entry_delete (plist, pentry, 1);
+ return prefix_list_entry_delete(plist, &temp) ;
}
-
- return CMD_SUCCESS;
}
void
@@ -2555,70 +2897,33 @@ prefix_bgp_orf_remove_all (char *name)
int
prefix_bgp_show_prefix_list (struct vty *vty, afi_t afi, char *name)
{
- struct prefix_list *plist;
- struct prefix_list_entry *pentry;
+ struct prefix_list *plist ;
plist = prefix_list_lookup (AFI_ORF_PREFIX, name);
if (! plist)
return 0;
- if (! vty)
- return plist->count;
-
- vty_out (vty, "ip%s prefix-list %s: %d entries%s",
- afi == AFI_IP ? "" : "v6",
- plist->name, plist->count, VTY_NEWLINE);
-
- for (pentry = plist->head; pentry; pentry = pentry->next)
+ if (vty)
{
- struct prefix *p = &pentry->prefix;
- char buf[BUFSIZ];
-
- vty_out (vty, " seq %d %s %s/%d", pentry->seq,
- prefix_list_type_str (pentry),
- inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ),
- p->prefixlen);
+ struct prefix_list_entry* pe ;
+ vector_index i ;
- if (pentry->ge)
- vty_out (vty, " ge %d", pentry->ge);
- if (pentry->le)
- vty_out (vty, " le %d", pentry->le);
+ vty_prefix_list_name_count_print(vty, plist, VTY_NEWLINE) ;
- vty_out (vty, "%s", VTY_NEWLINE);
+ for (VECTOR_ITEMS(&plist->list, pe, i))
+ {
+ vty_out_indent(vty, 3) ;
+ vty_prefix_list_value_print(vty, pe, VTY_NEWLINE, 1, 1) ;
+ }
}
- return plist->count;
+
+ return vector_end(&plist->list);
}
static void
prefix_list_reset_orf (void)
{
- struct prefix_list *plist;
- struct prefix_list *next;
- struct prefix_master *master;
-
- master = prefix_master_get (AFI_ORF_PREFIX);
- if (master == NULL)
- return;
-
- for (plist = master->num.head; plist; plist = next)
- {
- next = plist->next;
- prefix_list_delete (plist);
- }
- for (plist = master->str.head; plist; plist = next)
- {
- next = plist->next;
- prefix_list_delete (plist);
- }
-
- assert (master->num.head == NULL);
- assert (master->num.tail == NULL);
-
- assert (master->str.head == NULL);
- assert (master->str.tail == NULL);
-
- master->seqnum = 1;
- master->recent = NULL;
+ prefix_master_reset(&prefix_master_orf) ;
}
@@ -2639,38 +2944,14 @@ config_write_prefix_ipv4 (struct vty *vty)
static void
prefix_list_reset_ipv4 (void)
{
- struct prefix_list *plist;
- struct prefix_list *next;
- struct prefix_master *master;
-
- master = prefix_master_get (AFI_IP);
- if (master == NULL)
- return;
-
- for (plist = master->num.head; plist; plist = next)
- {
- next = plist->next;
- prefix_list_delete (plist);
- }
- for (plist = master->str.head; plist; plist = next)
- {
- next = plist->next;
- prefix_list_delete (plist);
- }
-
- assert (master->num.head == NULL);
- assert (master->num.tail == NULL);
-
- assert (master->str.head == NULL);
- assert (master->str.tail == NULL);
-
- master->seqnum = 1;
- master->recent = NULL;
+ prefix_master_reset(&prefix_master_ipv4) ;
}
static void
prefix_list_init_ipv4 (void)
{
+ prefix_master_init(&prefix_master_ipv4) ;
+
install_node (&prefix_node, config_write_prefix_ipv4);
install_element (CONFIG_NODE, &ip_prefix_list_cmd);
@@ -2734,10 +3015,10 @@ prefix_list_init_ipv4 (void)
/* Prefix-list node. */
static struct cmd_node prefix_ipv6_node =
{
- PREFIX_IPV6_NODE,
- "", /* Prefix list has no interface. */
- 1
-};
+ PREFIX_IPV6_NODE,
+ "", /* Prefix list has no interface. */
+ 1
+ };
static int
config_write_prefix_ipv6 (struct vty *vty)
@@ -2748,38 +3029,16 @@ config_write_prefix_ipv6 (struct vty *vty)
static void
prefix_list_reset_ipv6 (void)
{
- struct prefix_list *plist;
- struct prefix_list *next;
- struct prefix_master *master;
-
- master = prefix_master_get (AFI_IP6);
- if (master == NULL)
- return;
-
- for (plist = master->num.head; plist; plist = next)
- {
- next = plist->next;
- prefix_list_delete (plist);
- }
- for (plist = master->str.head; plist; plist = next)
- {
- next = plist->next;
- prefix_list_delete (plist);
- }
-
- assert (master->num.head == NULL);
- assert (master->num.tail == NULL);
-
- assert (master->str.head == NULL);
- assert (master->str.tail == NULL);
-
- master->seqnum = 1;
- master->recent = NULL;
-}
+#ifdef HAVE_IPV6
+ prefix_master_reset(&prefix_master_ipv6) ;
+#endif
+} ;
static void
prefix_list_init_ipv6 (void)
{
+ prefix_master_init(&prefix_master_ipv6) ;
+
install_node (&prefix_ipv6_node, config_write_prefix_ipv6);
install_element (CONFIG_NODE, &ipv6_prefix_list_cmd);
@@ -2847,6 +3106,7 @@ prefix_list_init ()
#ifdef HAVE_IPV6
prefix_list_init_ipv6 ();
#endif /* HAVE_IPV6 */
+ prefix_master_init(&prefix_master_orf) ;
}
void
diff --git a/lib/plist.h b/lib/plist.h
index fb3168a6..97dab78e 100644
--- a/lib/plist.h
+++ b/lib/plist.h
@@ -23,38 +23,21 @@
#ifndef _QUAGGA_PLIST_H
#define _QUAGGA_PLIST_H
+#include "prefix.h"
+#include "symtab.h"
+#include "vector.h"
+
#define AFI_ORF_PREFIX 65535
-enum prefix_list_type
+enum prefix_list_type
{
PREFIX_DENY,
PREFIX_PERMIT,
};
-enum prefix_name_type
-{
- PREFIX_TYPE_STRING,
- PREFIX_TYPE_NUMBER
-};
-
-struct prefix_list
-{
- char *name;
- char *desc;
-
- struct prefix_master *master;
-
- enum prefix_name_type type;
+struct prefix_list ;
- int count;
- int rangecount;
-
- struct prefix_list_entry *head;
- struct prefix_list_entry *tail;
-
- struct prefix_list *next;
- struct prefix_list *prev;
-};
+typedef struct symbol_ref* prefix_list_ref ;
struct orf_prefix
{
@@ -73,11 +56,23 @@ extern void prefix_list_delete_hook (void (*func) (struct prefix_list *));
extern struct prefix_list *prefix_list_lookup (afi_t, const char *);
extern enum prefix_list_type prefix_list_apply (struct prefix_list *, void *);
+extern const char* prefix_list_get_name(struct prefix_list* plist) ;
+
extern struct stream * prefix_bgp_orf_entry (struct stream *,
- struct prefix_list *,
+ prefix_list_ref ref,
u_char, u_char, u_char);
extern int prefix_bgp_orf_set (char *, afi_t, struct orf_prefix *, int, int);
extern void prefix_bgp_orf_remove_all (char *);
extern int prefix_bgp_show_prefix_list (struct vty *, afi_t, char *);
+extern prefix_list_ref prefix_list_set_ref(prefix_list_ref* p_ref, afi_t afi,
+ const char* name) ;
+extern prefix_list_ref prefix_list_copy_ref(prefix_list_ref* p_dst,
+ prefix_list_ref src) ;
+extern prefix_list_ref prefix_list_unset_ref(prefix_list_ref* p_ref) ;
+
+extern const char* prefix_list_ref_name(prefix_list_ref ref) ;
+extern void* prefix_list_ref_ident(prefix_list_ref ref) ;
+extern struct prefix_list* prefix_list_ref_plist(prefix_list_ref ref) ;
+
#endif /* _QUAGGA_PLIST_H */
diff --git a/lib/prefix.c b/lib/prefix.c
index 2afaa09c..6399788c 100644
--- a/lib/prefix.c
+++ b/lib/prefix.c
@@ -17,7 +17,7 @@
* 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.
+ * 02111-1307, USA.
*/
#include <zebra.h>
@@ -27,7 +27,7 @@
#include "sockunion.h"
#include "memory.h"
#include "log.h"
-
+
/* Maskbit. */
static u_char maskbit[] = {0x00, 0x80, 0xc0, 0xe0, 0xf0,
0xf8, 0xfc, 0xfe, 0xff};
@@ -85,7 +85,7 @@ prefix_match (const struct prefix *n, const struct prefix *p)
if (shift)
if (maskbit[shift] & (np[offset] ^ pp[offset]))
return 0;
-
+
while (offset--)
if (np[offset] != pp[offset])
return 0;
@@ -118,7 +118,7 @@ prefix_copy (struct prefix *dest, const struct prefix *src)
}
}
-/*
+/*
* Return 1 if the address/netmask contained in the prefix structure
* is the same, and else return 0. For this routine, 'same' requires
* that not only the prefix length and the network part be the same,
@@ -214,7 +214,16 @@ prefix_ipv4_free (struct prefix_ipv4 *p)
prefix_free((struct prefix *)p);
}
-/* When string format is invalid return 0. */
+/* When string format is valid return 1 otherwise return 0.
+ *
+ * Some callers of this function treat non-0 as OK and 0 as invalid (which is
+ * what inet_aton() is defined to do).
+ *
+ * Some callers treat > 0 as OK and <= 0 as invalid (which is similar to what
+ * inet_pton() is defined to do).
+ *
+ * The actual returns are consistent with both usages.
+ */
int
str2prefix_ipv4 (const char *str, struct prefix_ipv4 *p)
{
@@ -227,7 +236,7 @@ str2prefix_ipv4 (const char *str, struct prefix_ipv4 *p)
pnt = strchr (str, '/');
/* String doesn't contail slash. */
- if (pnt == NULL)
+ if (pnt == NULL)
{
/* Convert string to prefix. */
ret = inet_aton (str, &p->prefix);
@@ -238,7 +247,7 @@ str2prefix_ipv4 (const char *str, struct prefix_ipv4 *p)
p->family = AF_INET;
p->prefixlen = IPV4_MAX_BITLEN;
- return ret;
+ return 1 ;
}
else
{
@@ -257,7 +266,7 @@ str2prefix_ipv4 (const char *str, struct prefix_ipv4 *p)
p->prefixlen = plen;
}
- return ret;
+ return 1 ;
}
/* Convert masklen into IP address's netmask. */
@@ -273,7 +282,7 @@ masklen2ip (int masklen, struct in_addr *netmask)
offset = masklen / 8;
bit = masklen % 8;
-
+
while (offset--)
*pnt++ = 0xff;
@@ -299,7 +308,7 @@ ip_masklen (struct in_addr netmask)
{
len+= 8;
pnt++;
- }
+ }
if (pnt < end)
{
@@ -342,7 +351,7 @@ prefix_ipv4_any (const struct prefix_ipv4 *p)
{
return (p->prefix.s_addr == 0 && p->prefixlen == 0);
}
-
+
#ifdef HAVE_IPV6
/* Allocate a new ip version 6 route */
@@ -365,7 +374,26 @@ prefix_ipv6_free (struct prefix_ipv6 *p)
prefix_free((struct prefix *)p);
}
-/* If given string is valid return pin6 else return NULL */
+/* If given string is valid IPv6 address or prefix return 1 else return 0
+ *
+ * Of inet_pton() POSIX 1003.1, 2004 says:
+ *
+ * The inet_pton() function shall return 1 if the conversion succeeds, with
+ * the address pointed to by dst in network byte order. It shall return 0 if
+ * the input is not either a valid IPv4 dotted-decimal string or a valid IPv6
+ * address string (if IPv6 supported), or return -1 with errno set to
+ * [EAFNOSUPPORT] if the af argument is unknown.
+ *
+ * Any error returned is reported as an invalid address or prefix. So best not
+ * to call this if IPv6 is not supported.
+ *
+ * Some callers treat > 0 as OK and <= 0 as invalid (which is consistent with
+ * what inet_pton() is defined to do).
+ *
+ * Some callers of this function treat non-0 as OK and 0 as invalid.
+ *
+ * The actual returns are consistent with both usages.
+ */
int
str2prefix_ipv6 (const char *str, struct prefix_ipv6 *p)
{
@@ -376,14 +404,14 @@ str2prefix_ipv6 (const char *str, struct prefix_ipv6 *p)
pnt = strchr (str, '/');
/* If string doesn't contain `/' treat it as host route. */
- if (pnt == NULL)
+ if (pnt == NULL)
{
ret = inet_pton (AF_INET6, str, &p->prefix);
- if (ret == 0)
+ if (ret <= 0)
return 0;
p->prefixlen = IPV6_MAX_BITLEN;
}
- else
+ else
{
int plen;
@@ -392,7 +420,7 @@ str2prefix_ipv6 (const char *str, struct prefix_ipv6 *p)
*(cp + (pnt - str)) = '\0';
ret = inet_pton (AF_INET6, cp, &p->prefix);
free (cp);
- if (ret == 0)
+ if (ret <= 0)
return 0;
plen = (u_char) atoi (++pnt);
if (plen > 128)
@@ -401,7 +429,7 @@ str2prefix_ipv6 (const char *str, struct prefix_ipv6 *p)
}
p->family = AF_INET6;
- return ret;
+ return 1 ;
}
/* Convert struct in6_addr netmask into integer.
@@ -412,19 +440,19 @@ ip6_masklen (struct in6_addr netmask)
int len = 0;
unsigned char val;
unsigned char *pnt;
-
+
pnt = (unsigned char *) & netmask;
- while ((*pnt == 0xff) && len < 128)
+ while ((*pnt == 0xff) && len < 128)
{
len += 8;
pnt++;
- }
-
- if (len < 128)
+ }
+
+ if (len < 128)
{
val = *pnt;
- while (val)
+ while (val)
{
len++;
val <<= 1;
@@ -572,7 +600,7 @@ sockunion2hostprefix (const union sockunion *su)
int
prefix_blen (const struct prefix *p)
{
- switch (p->family)
+ switch (p->family)
{
case AF_INET:
return IPV4_MAX_BYTELEN;
@@ -600,7 +628,7 @@ str2prefix (const char *str, struct prefix *p)
#ifdef HAVE_IPV6
/* Next we try to convert string to struct prefix_ipv6. */
ret = str2prefix_ipv6 (str, (struct prefix_ipv6 *) p);
- if (ret)
+ if (ret <= 0)
return ret;
#endif /* HAVE_IPV6 */
@@ -650,22 +678,22 @@ void apply_classful_mask_ipv4 (struct prefix_ipv4 *p)
{
u_int32_t destination;
-
+
destination = ntohl (p->prefix.s_addr);
-
+
if (p->prefixlen == IPV4_MAX_PREFIXLEN);
/* do nothing for host routes */
- else if (IN_CLASSC (destination))
+ else if (IN_CLASSC (destination))
{
p->prefixlen=24;
apply_mask_ipv4(p);
}
- else if (IN_CLASSB(destination))
+ else if (IN_CLASSB(destination))
{
p->prefixlen=16;
apply_mask_ipv4(p);
}
- else
+ else
{
p->prefixlen=8;
apply_mask_ipv4(p);
@@ -694,7 +722,7 @@ ipv4_broadcast_addr (in_addr_t hostaddr, int masklen)
(hostaddr ^ ~mask.s_addr);
}
-/* Utility function to convert ipv4 netmask to prefixes
+/* Utility function to convert ipv4 netmask to prefixes
ex.) "1.1.0.0" "255.255.0.0" => "1.1.0.0/16"
ex.) "1.0.0.0" NULL => "1.0.0.0/8" */
int
@@ -719,7 +747,7 @@ netmask_str2prefix_str (const char *net_str, const char *mask_str,
prefixlen = ip_masklen (mask);
}
- else
+ else
{
destination = ntohl (network.s_addr);
diff --git a/lib/privs.c b/lib/privs.c
index 69606f57..68757340 100644
--- a/lib/privs.c
+++ b/lib/privs.c
@@ -25,6 +25,10 @@
#include "log.h"
#include "privs.h"
#include "memory.h"
+#include "qpthreads.h"
+
+/* Needs to be qpthread safe */
+static qpt_mutex_t* mx = NULL;
#ifdef HAVE_CAPABILITIES
/* sort out some generic internal types for:
@@ -61,6 +65,7 @@ typedef priv_set_t *pstorage_t;
* zprivs_terminate is called and the NULL handler is installed.
*/
static zebra_privs_current_t zprivs_null_state = ZPRIVS_RAISED;
+static int raise_count = 0; /* keep raised until all pthreads have lowered */
/* internal privileges state */
static struct _zprivs_t
@@ -187,25 +192,42 @@ int
zprivs_change_caps (zebra_privs_ops_t op)
{
cap_flag_value_t cflag;
-
+ int result = 0;
+ int change = 0;
+
+ qpt_mutex_lock(mx);
+
/* should be no possibility of being called without valid caps */
assert (zprivs_state.syscaps_p && zprivs_state.caps);
if (! (zprivs_state.syscaps_p && zprivs_state.caps))
- exit (1);
-
+ {
+ qpt_mutex_unlock(mx);
+ exit (1);
+ }
+
if (op == ZPRIVS_RAISE)
- cflag = CAP_SET;
+ {
+ cflag = CAP_SET;
+ change = (raise_count++ == 0);
+ }
else if (op == ZPRIVS_LOWER)
- cflag = CAP_CLEAR;
+ {
+ cflag = CAP_CLEAR;
+ change = (--raise_count == 0);
+ }
else
- return -1;
+ {
+ result = -1;
+ }
- if ( !cap_set_flag (zprivs_state.caps, CAP_EFFECTIVE,
+ if ( change && !cap_set_flag (zprivs_state.caps, CAP_EFFECTIVE,
zprivs_state.syscaps_p->num,
zprivs_state.syscaps_p->caps,
cflag))
- return cap_set_proc (zprivs_state.caps);
- return -1;
+ result = cap_set_proc (zprivs_state.caps);
+
+ qpt_mutex_unlock(mx);
+ return result;
}
zebra_privs_current_t
@@ -213,11 +235,17 @@ zprivs_state_caps (void)
{
int i;
cap_flag_value_t val;
+ zebra_privs_current_t result = ZPRIVS_LOWERED;
+
+ qpt_mutex_lock(mx);
/* should be no possibility of being called without valid caps */
assert (zprivs_state.syscaps_p && zprivs_state.caps);
if (! (zprivs_state.syscaps_p && zprivs_state.caps))
- exit (1);
+ {
+ qpt_mutex_unlock(mx);
+ exit (1);
+ }
for (i=0; i < zprivs_state.syscaps_p->num; i++)
{
@@ -226,12 +254,18 @@ zprivs_state_caps (void)
{
zlog_warn ("zprivs_state_caps: could not cap_get_flag, %s",
safe_strerror (errno) );
- return ZPRIVS_UNKNOWN;
+ result = ZPRIVS_UNKNOWN;
+ break;
}
if (val == CAP_SET)
- return ZPRIVS_RAISED;
+ {
+ result = ZPRIVS_RAISED;
+ break;
+ }
}
- return ZPRIVS_LOWERED;
+
+ qpt_mutex_unlock(mx);
+ return result;
}
static void
@@ -376,12 +410,16 @@ zcaps2sys (zebra_capabilities_t *zcaps, int num)
int
zprivs_change_caps (zebra_privs_ops_t op)
{
+ int result = 0;
+ qpt_mutex_lock(mx);
+
/* should be no possibility of being called without valid caps */
assert (zprivs_state.syscaps_p);
if (!zprivs_state.syscaps_p)
{
fprintf (stderr, "%s: Eek, missing caps!", __func__);
+ qpt_mutex_unlock(mx);
exit (1);
}
@@ -389,49 +427,66 @@ zprivs_change_caps (zebra_privs_ops_t op)
* to lower: just clear the working effective set
*/
if (op == ZPRIVS_RAISE)
- priv_copyset (zprivs_state.syscaps_p, zprivs_state.caps);
+ {
+ if (raise_count++ == 0)
+ {
+ priv_copyset (zprivs_state.syscaps_p, zprivs_state.caps);
+ if (setppriv (PRIV_SET, PRIV_EFFECTIVE, zprivs_state.caps) != 0)
+ result = -1;
+ }
+ }
else if (op == ZPRIVS_LOWER)
- priv_emptyset (zprivs_state.caps);
+ {
+ if (--raise_count == 0)
+ {
+ priv_emptyset (zprivs_state.caps);
+ if (setppriv (PRIV_SET, PRIV_EFFECTIVE, zprivs_state.caps) != 0)
+ result = -1;
+ }
+ }
else
- return -1;
+ result = -1;
- if (setppriv (PRIV_SET, PRIV_EFFECTIVE, zprivs_state.caps) != 0)
- return -1;
+ qpt_mutex_unlock(mx);
- return 0;
+ return result;
}
/* Retrieve current privilege state, is it RAISED or LOWERED? */
zebra_privs_current_t
zprivs_state_caps (void)
{
- zebra_privs_current_t result;
+ zebra_privs_current_t result = ZPRIVS_UNKNOWN;
pset_t *effective;
+ qpt_mutex_lock(mx);
+
if ( (effective = priv_allocset()) == NULL)
{
fprintf (stderr, "%s: failed to get priv_allocset! %s\n", __func__,
safe_strerror (errno));
- return ZPRIVS_UNKNOWN;
- }
-
- if (getppriv (PRIV_EFFECTIVE, effective))
- {
- fprintf (stderr, "%s: failed to get state! %s\n", __func__,
- safe_strerror (errno));
- result = ZPRIVS_UNKNOWN;
}
else
{
- if (priv_isemptyset (effective) == B_TRUE)
- result = ZPRIVS_LOWERED;
+
+ if (getppriv (PRIV_EFFECTIVE, effective))
+ {
+ fprintf (stderr, "%s: failed to get state! %s\n", __func__,
+ safe_strerror (errno));
+ }
else
- result = ZPRIVS_RAISED;
+ {
+ if (priv_isemptyset (effective) == B_TRUE)
+ result = ZPRIVS_LOWERED;
+ else
+ result = ZPRIVS_RAISED;
+ }
+
+ if (effective)
+ priv_freeset (effective);
}
- if (effective)
- priv_freeset (effective);
-
+ qpt_mutex_unlock(mx);
return result;
}
@@ -560,19 +615,42 @@ zprivs_caps_terminate (void)
int
zprivs_change_uid (zebra_privs_ops_t op)
{
+ int result = 0;
+
+ qpt_mutex_lock(mx);
if (op == ZPRIVS_RAISE)
- return seteuid (zprivs_state.zsuid);
+ {
+ if (raise_count++ == 0)
+ {
+ result = seteuid (zprivs_state.zsuid);
+ }
+ }
else if (op == ZPRIVS_LOWER)
- return seteuid (zprivs_state.zuid);
+ {
+ if (--raise_count == 0)
+ {
+ result = seteuid (zprivs_state.zuid);
+ }
+ }
else
- return -1;
+ {
+ result = -1;
+ }
+
+ qpt_mutex_unlock(mx);
+ return result;
}
zebra_privs_current_t
zprivs_state_uid (void)
{
- return ( (zprivs_state.zuid == geteuid()) ? ZPRIVS_LOWERED : ZPRIVS_RAISED);
+ zebra_privs_current_t result;
+
+ qpt_mutex_lock(mx);
+ result = ( (zprivs_state.zuid == geteuid()) ? ZPRIVS_LOWERED : ZPRIVS_RAISED);
+ qpt_mutex_unlock(mx);
+ return result;
}
int
@@ -584,7 +662,25 @@ zprivs_change_null (zebra_privs_ops_t op)
zebra_privs_current_t
zprivs_state_null (void)
{
- return zprivs_null_state;
+ int result;
+
+ qpt_mutex_lock(mx);
+ result = zprivs_null_state;
+ qpt_mutex_unlock(mx);
+ return result;
+}
+
+void
+zprivs_init_r(struct zebra_privs_t *zprivs)
+{
+ mx = qpt_mutex_init(mx, qpt_mutex_quagga);
+ zprivs_init(zprivs);
+}
+
+void
+zprivs_destroy_r(void)
+{
+ mx = qpt_mutex_destroy(mx, 1);
}
void
@@ -599,12 +695,15 @@ zprivs_init(struct zebra_privs_t *zprivs)
exit (1);
}
+ qpt_mutex_lock(mx);
+
/* NULL privs */
if (! (zprivs->user || zprivs->group
|| zprivs->cap_num_p || zprivs->cap_num_i) )
{
zprivs->change = zprivs_change_null;
zprivs->current_state = zprivs_state_null;
+ qpt_mutex_unlock(mx);
return;
}
@@ -619,6 +718,7 @@ zprivs_init(struct zebra_privs_t *zprivs)
/* cant use log.h here as it depends on vty */
fprintf (stderr, "privs_init: could not lookup user %s\n",
zprivs->user);
+ qpt_mutex_unlock(mx);
exit (1);
}
}
@@ -635,6 +735,7 @@ zprivs_init(struct zebra_privs_t *zprivs)
{
fprintf (stderr, "privs_init: could not setgroups, %s\n",
safe_strerror (errno) );
+ qpt_mutex_unlock(mx);
exit (1);
}
}
@@ -642,6 +743,7 @@ zprivs_init(struct zebra_privs_t *zprivs)
{
fprintf (stderr, "privs_init: could not lookup vty group %s\n",
zprivs->vty_group);
+ qpt_mutex_unlock(mx);
exit (1);
}
}
@@ -656,6 +758,7 @@ zprivs_init(struct zebra_privs_t *zprivs)
{
fprintf (stderr, "privs_init: could not lookup group %s\n",
zprivs->group);
+ qpt_mutex_unlock(mx);
exit (1);
}
/* change group now, forever. uid we do later */
@@ -663,6 +766,7 @@ zprivs_init(struct zebra_privs_t *zprivs)
{
fprintf (stderr, "zprivs_init: could not setregid, %s\n",
safe_strerror (errno) );
+ qpt_mutex_unlock(mx);
exit (1);
}
}
@@ -671,7 +775,7 @@ zprivs_init(struct zebra_privs_t *zprivs)
zprivs_caps_init (zprivs);
#else /* !HAVE_CAPABILITIES */
/* we dont have caps. we'll need to maintain rid and saved uid
- * and change euid back to saved uid (who we presume has all neccessary
+ * and change euid back to saved uid (who we presume has all necessary
* privileges) whenever we are asked to raise our privileges.
*
* This is not worth that much security wise, but all we can do.
@@ -683,6 +787,7 @@ zprivs_init(struct zebra_privs_t *zprivs)
{
fprintf (stderr, "privs_init (uid): could not setreuid, %s\n",
safe_strerror (errno));
+ qpt_mutex_unlock(mx);
exit (1);
}
}
@@ -690,6 +795,8 @@ zprivs_init(struct zebra_privs_t *zprivs)
zprivs->change = zprivs_change_uid;
zprivs->current_state = zprivs_state_uid;
#endif /* HAVE_CAPABILITIES */
+
+ qpt_mutex_unlock(mx);
}
void
@@ -701,6 +808,8 @@ zprivs_terminate (struct zebra_privs_t *zprivs)
exit (0);
}
+ qpt_mutex_lock(mx);
+
#ifdef HAVE_CAPABILITIES
zprivs_caps_terminate();
#else /* !HAVE_CAPABILITIES */
@@ -710,6 +819,7 @@ zprivs_terminate (struct zebra_privs_t *zprivs)
{
fprintf (stderr, "privs_terminate: could not setreuid, %s",
safe_strerror (errno) );
+ qpt_mutex_unlock(mx);
exit (1);
}
}
@@ -718,20 +828,25 @@ zprivs_terminate (struct zebra_privs_t *zprivs)
zprivs->change = zprivs_change_null;
zprivs->current_state = zprivs_state_null;
zprivs_null_state = ZPRIVS_LOWERED;
+ raise_count = 0;
+
+ qpt_mutex_unlock(mx);
return;
}
void
zprivs_get_ids(struct zprivs_ids_t *ids)
{
+ qpt_mutex_lock(mx);
- ids->uid_priv = getuid();
- (zprivs_state.zuid) ? (ids->uid_normal = zprivs_state.zuid)
+ ids->uid_priv = getuid();
+ (zprivs_state.zuid) ? (ids->uid_normal = zprivs_state.zuid)
: (ids->uid_normal = -1);
- (zprivs_state.zgid) ? (ids->gid_normal = zprivs_state.zgid)
+ (zprivs_state.zgid) ? (ids->gid_normal = zprivs_state.zgid)
: (ids->gid_normal = -1);
- (zprivs_state.vtygrp) ? (ids->gid_vty = zprivs_state.vtygrp)
+ (zprivs_state.vtygrp) ? (ids->gid_vty = zprivs_state.vtygrp)
: (ids->gid_vty = -1);
+ qpt_mutex_unlock(mx);
return;
}
diff --git a/lib/privs.h b/lib/privs.h
index 46d614e0..18d35d8d 100644
--- a/lib/privs.h
+++ b/lib/privs.h
@@ -81,9 +81,13 @@ struct zprivs_ids_t
};
/* initialise zebra privileges */
+extern void zprivs_init_r (struct zebra_privs_t *zprivs);
extern void zprivs_init (struct zebra_privs_t *zprivs);
+extern void zprivs_destroy_r (void);
+
/* drop all and terminate privileges */
extern void zprivs_terminate (struct zebra_privs_t *);
+
/* query for runtime uid's and gid's, eg vty needs this */
extern void zprivs_get_ids(struct zprivs_ids_t *);
diff --git a/lib/qpnexus.c b/lib/qpnexus.c
new file mode 100644
index 00000000..01985d29
--- /dev/null
+++ b/lib/qpnexus.c
@@ -0,0 +1,120 @@
+/* Quagga Pthreads support -- header
+ * Copyright (C) 2009 Chris Hall (GMCH), Highwayman
+ *
+ * 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.
+ */
+
+/* This MUST come first... otherwise we don't get __USE_UNIX98, which is */
+/* essential if glibc is to allow pthread_mutexattr_settype() to be used. */
+#include "config.h"
+
+#include <signal.h>
+#include <string.h>
+
+#include "qpnexus.h"
+#include "memory.h"
+
+/* prototypes */
+static void* qpn_start(void* arg);
+
+/*==============================================================================
+ * Quagga Nexus Interface -- qpt_xxxx
+ *
+
+ */
+
+/* Initialise a nexus -- allocating it if required.
+ *
+ * Returns the qtn_nexus.
+ */
+qpn_nexus
+qpn_init_new(qpn_nexus qpn)
+{
+ if (qpn == NULL)
+ qpn = XCALLOC(MTYPE_QPN_NEXUS, sizeof(struct qpn_nexus)) ;
+ else
+ memset(qpn, 0, sizeof(struct qpn_nexus)) ;
+
+ qpn->selection = qps_selection_init_new(qpn->selection);
+ qpn->pile = qtimer_pile_init_new(qpn->pile);
+
+ /* TODO mqueue initialisation */
+
+ return qpn;
+}
+
+void
+qpn_free(qpn_nexus qpn)
+{
+ /* timers and the pile */
+ qtimer qtr;
+ while ((qtr = qtimer_pile_ream(qpn->pile, 1)))
+ {
+ qtimer_free(qtr);
+ }
+
+ /* TODO: free qtn->selection */
+
+ /* TODO: free qtn->queue */
+
+ XFREE(MTYPE_QPN_NEXUS, qpn) ;
+}
+
+/* Create and execute the qpthread */
+void
+qpn_exec(qpn_nexus qpn)
+{
+ qpn->thread_id = qpt_thread_create(qpn_start, qpn, NULL) ;
+}
+
+static void*
+qpn_start(void* arg)
+{
+ qpn_nexus qpn = arg;
+ int actions;
+
+ while (!qpn->terminate)
+ {
+ qtime_mono_t now = qt_get_monotonic();
+
+ /* process timers */
+ while (qtimer_pile_dispatch_next(qpn->pile, now))
+ {
+ }
+
+ /* block for some input, output or timeout */
+ actions = qps_pselect( qpn->selection,
+ qtimer_pile_top_time(qpn->pile, now + QTIME(MAX_PSELECT_TIMOUT)) );
+
+ /* process I/O actions */
+ while (actions)
+ {
+ actions = qps_dispatch_next(qpn->selection) ;
+ }
+
+ /* TODO process message queue */
+ }
+
+ qpn_free(qpn);
+
+ return NULL;
+}
+
+
+
+
diff --git a/lib/qpnexus.h b/lib/qpnexus.h
new file mode 100644
index 00000000..ce546edd
--- /dev/null
+++ b/lib/qpnexus.h
@@ -0,0 +1,86 @@
+/* Quagga Pthreads support -- header
+ * Copyright (C) 2009 Chris Hall (GMCH), Highwayman
+ *
+ * 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 _ZEBRA_QPNEXUS_H
+#define _ZEBRA_QPNEXUS_H
+
+#include <stdint.h>
+#include <time.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "zassert.h"
+#include "qpthreads.h"
+#include "qtimers.h"
+#include "mqueue.h"
+#include "qpselect.h"
+
+#ifndef Inline
+#define Inline static inline
+#endif
+
+/*==============================================================================
+ * Quagga Nexus Interface -- qpn_xxxx
+ *
+ * Object to hold, a qpthread, a qps_selection, a qtimer_pile, a mqueue_queue
+ * together with the thread routine to poll and dispatch their respective
+ * action routines.
+ *
+ */
+
+/* maximum time in seconds to sit in a pselect */
+#define MAX_PSELECT_TIMOUT 10
+
+/*==============================================================================
+ * Data Structures.
+ */
+
+typedef struct qpn_nexus* qpn_nexus ;
+
+struct qpn_nexus
+{
+ /* set true to terminate the thread (eventually) */
+ int terminate;
+
+ /* thread ID */
+ qpt_thread_t thread_id;
+
+ /* pselect handler */
+ qps_selection selection;
+
+ /* timer pile */
+ qtimer_pile pile;
+
+ /* message queue */
+ mqueue_queue queue;
+
+};
+
+/*==============================================================================
+ * Functions
+ */
+
+extern qpn_nexus qpn_init_new(qpn_nexus qtn);
+extern void qpn_exec(qpn_nexus qtn);
+void qpn_free(qpn_nexus qpn);
+
+#endif /* _ZEBRA_QPNEXUS_H */
diff --git a/lib/qpselect.c b/lib/qpselect.c
new file mode 100644
index 00000000..cf1df985
--- /dev/null
+++ b/lib/qpselect.c
@@ -0,0 +1,1321 @@
+/* Quagga pselect support -- header
+ * Copyright (C) 2009 Chris Hall (GMCH), Highwayman
+ *
+ * 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.
+ */
+
+#include <signal.h>
+#include <string.h>
+
+#include "zassert.h"
+#include "qpselect.h"
+#include "qpthreads.h"
+#include "qtime.h"
+#include "memory.h"
+#include "vector.h"
+
+/*==============================================================================
+ * Quagga pselect -- qps_xxxx
+ *
+ * Here and in qpselect.h is a data structure for managing multiple file
+ * descriptors and running pselect to wait for I/O activity and to multiplex
+ * between the file descriptors.
+ *
+ * The qps_selection structure manages a collection of file descriptors which
+ * are to be waited on together in a pselect statement.
+ *
+ * NB: it is ASSUMED that a qps_selection will be private to the thread in
+ * which it is created and used.
+ *
+ * There is NO mutex handling here.
+ *
+ * This supports pselect, so supports:
+ *
+ * * waiting for file descriptors, which may each be expecting any combination
+ * of error/read/write events.
+ *
+ * Files may be added or removed from the selection. Files in the selection
+ * may then be enabled/disabled for any combination of error/read/write
+ * "mode" events.
+ *
+ * * a timeout *time*
+ *
+ * This is a qtime monotonic time at which to time out. (This is unlike
+ * pselect() itself, which takes a timeout interval.)
+ *
+ * Infinite timeouts are not supported.
+ *
+ * * an optional signal number and sigmask
+ *
+ * So that a signal may be used to interrupt a waiting pselect.
+ *
+ * For this to work there must be a signal which is generally masked, and
+ * is unmasked for the duration of the pselect.
+ *
+ * When a pselect returns there may be a number of files with events pending.
+ * The qps_dispatch_next() calls the action routine for the next event to be
+ * dealt with. Events are dispatched in the order: error, read and write, and
+ * then in file descriptor order. (So all error events in fd order, then all
+ * read events, and so on.)
+ *
+ * Note that at no time are any modes automatically disabled. So the system is
+ * level triggered. So, for example, a read event that is not dealt with will
+ * be triggered again on the next pselect -- unless the read mode is explicitly
+ * disabled for the file.
+ *
+ * Action Functions
+ * ----------------
+ *
+ * There is a separate action function for each mode. Each file has its own
+ * set of action functions -- so these may be used to implement a form of
+ * state machine for the file.
+ *
+ * When the action function is called it is passed the qps_file structure and
+ * the file_info pointer from that structure.
+ *
+ * During an action function modes may be enabled/disabled, actions changed,
+ * the file removed from the selection... there are no restrictions.
+ */
+
+static int qps_super_set_map_made = 0 ;
+
+static void qps_make_super_set_map(void) ;
+
+/*==============================================================================
+ * qps_selection handling
+ */
+
+/* Forward references */
+static qps_file qps_file_lookup_fd(qps_selection qps, int fd, qps_file insert) ;
+static void qps_file_remove(qps_selection qps, qps_file qf) ;
+static void qps_super_set_zero(fd_super_set* p_set, int n) ;
+static int qps_next_fd_pending(fd_super_set* pending, int fd, int fd_last) ;
+static void qps_selection_validate(qps_selection qps) ;
+
+/* See qps_make_super_set_map() and qps_pselect() below. */
+static short fd_byte_count[FD_SETSIZE] ; /* number of bytes for fds 0..fd */
+
+/* Initialise a selection -- allocating it if required.
+ *
+ * Returns the qps_selection.
+ */
+qps_selection
+qps_selection_init_new(qps_selection qps)
+{
+ if (!qps_super_set_map_made)
+ qps_make_super_set_map() ; /* map the fd_super_set */
+
+ if (qps == NULL)
+ qps = XCALLOC(MTYPE_QPS_SELECTION, sizeof(struct qps_selection)) ;
+ else
+ memset(qps, 0, sizeof(struct qps_selection)) ;
+
+ /* Zeroising initialises:
+ *
+ * fd_count -- no fd's yet
+ * fd_direct -- not direct lookup
+ *
+ * files -- empty vector
+ *
+ * fd_last -- unset
+ * enabled_count -- no fd's enabled in any mode
+ * enabled -- empty bit vectors
+ *
+ * tried_fd_last -- nothing tried yet
+ * tried_count -- nothing tried yet
+ * results -- empty bit vectors
+ *
+ * pend_count -- no results to dispatch
+ * pend_mnum -- unset
+ * pend_fd -- unset
+ *
+ * signum -- no signal to be enabled
+ * sigmask -- unset
+ *
+ * So nothing else to do -- see also qps_selection_re_init(), below.
+ */
+
+ return qps ;
+} ;
+
+/* Re-initialise a selection.
+ */
+static void
+qps_selection_re_init(qps_selection qps)
+{
+ memset(qps, 0, sizeof(struct qps_selection)) ;
+} ;
+
+/* Add given file to the selection, setting its fd and pointer to further
+ * file information. All modes are disabled.
+ *
+ * This initialises most of the qps_file structure, but not the actions.
+ *
+ * Adding a file using the same fd as an existing file is a FATAL error.
+ *
+ * Adding a file which is already a member a selection is a FATAL error.
+ */
+void
+qps_add_file(qps_selection qps, qps_file qf, int fd, void* file_info)
+{
+ passert(qf->selection == NULL) ;
+
+ qf->selection = qps ;
+
+ qf->file_info = file_info ;
+ qf->fd = fd ;
+
+ qf->enabled_bits = 0 ;
+
+ qps_file_lookup_fd(qps, fd, qf) ; /* Add. */
+} ;
+
+/* Remove given file from its selection, if any.
+ *
+ * It is the callers responsibility to ensure that the file is in a suitable
+ * state to be removed from the selection.
+ *
+ * When the file is removed it is disabled in all modes.
+ */
+void
+qps_remove_file(qps_file qf)
+{
+ if (qf->selection != NULL)
+ qps_file_remove(qf->selection, qf) ;
+} ;
+
+/* Ream (another) file out of the selection.
+ *
+ * If selection is empty, release the qps_selection structure, if required.
+ *
+ * See: #define qps_selection_ream_free(qps)
+ * #define qps_selection_ream_keep(qps)
+ *
+ * Useful for emptying out and discarding a selection:
+ *
+ * while ((qf = qps_selection_ream_free(qps)))
+ * ... do what's required to release the qps_file
+ *
+ * The file is removed from the selection before being returned.
+ *
+ * Returns NULL when selection is empty (and has been released, if required).
+ *
+ * If the selection is not released, it may be reused without reinitialisation.
+ *
+ * NB: once reaming has started, the selection MUST NOT be used for anything,
+ * and the process MUST be run to completion.
+ */
+qps_file
+qps_selection_ream(qps_selection qps, int free_structure)
+{
+ qps_file qf ;
+
+ qf = vector_ream_keep(&qps->files) ;
+ if (qf != NULL)
+ qps_file_remove(qps, qf) ;
+ else
+ {
+ passert(qps->fd_count == 0) ;
+
+ if (free_structure)
+ XFREE(MTYPE_QPS_SELECTION, qps) ;
+ else
+ qps_selection_re_init(qps) ;
+ } ;
+
+ return qf ;
+} ;
+
+/* Set the signal mask for the selection.
+ *
+ * This supports the unmasking of a single signal for the duration of the
+ * pselect operation.
+ *
+ * It is assumed that the set of signals generally masked by a thread is
+ * essentially static. So this function is passed that set. (So the sigmask
+ * argument must have the signum signal masked.)
+ *
+ * If the set of signals masked by the thread changes, then this function
+ * should be called again.
+ *
+ * Setting a signum == 0 turns OFF the use of the sigmask.
+ */
+void
+qps_set_signal(qps_selection qps, int signum, sigset_t sigmask)
+{
+ qps->signum = signum ;
+
+ if (signum != 0)
+ {
+ assert(sigismember(&sigmask, signum)) ;
+ sigdelset(&sigmask, signum) ;
+ qps->sigmask = sigmask ;
+ } ;
+} ;
+
+/* Execute a pselect for the given selection -- subject to the given timeout
+ * *time*.
+ *
+ * The time-out time is an "absolute" time, as measured by qt_get_monotonic().
+ *
+ * A timeout time <= the current qt_get_monotonic() is treated as a zero
+ * timeout period, and will return immediately from the pselect.
+ *
+ * There is no support for an infinite timeout.
+ *
+ * Returns: -1 => EINTR occurred -- ie a signal has gone off
+ * 0 => hit timeout -- no files are ready
+ * > 0 => there are this many files ready in one or more modes
+ *
+ * All other errors are FATAL.
+ *
+ * The qps_dispatch_next() processes the returns from pselect().
+ */
+int
+qps_pselect(qps_selection qps, qtime_mono_t timeout)
+{
+ struct timespec ts ;
+ qps_mnum_t mnum ;
+ fd_set* p_fds[qps_mnum_count] ;
+ int n ;
+
+ /* TODO: put this under a debug skip */
+ qps_selection_validate(qps) ;
+
+ /* If there is stuff still pending, tidy up by zeroising the result */
+ /* vectors. This is to make sure that when bits are copied from */
+ /* the enabled vectors, there are none from a previous run of pselect */
+ /* left hanging about. (pselect SHOULD ignore everything above the */
+ /* given count of fds -- but it does no harm to be tidy, and should */
+ /* not have to do this often.) */
+ if (qps->pend_count != 0)
+ qps_super_set_zero(qps->results, qps_mnum_count) ;
+
+ /* Prepare the argument/result bitmaps */
+ /* Capture pend_mnum and tried_count[] */
+
+ n = fd_byte_count[qps->fd_last] ; /* copy up to last sig. byte */
+
+ qps->pend_mnum = qps_mnum_count ;
+ for (mnum = 0 ; mnum < qps_mnum_count ; ++mnum)
+ if ((qps->tried_count[mnum] = qps->enabled_count[mnum]) != 0)
+ {
+ memcpy(&(qps->results[mnum].bytes), &(qps->enabled[mnum].bytes), n) ;
+ p_fds[mnum] = &(qps->results[mnum].fdset) ;
+ if (mnum < qps->pend_mnum)
+ qps->pend_mnum = mnum ;
+ }
+ else
+ p_fds[mnum] = NULL ;
+
+ /* Capture tried_fd_last and set initial pend_fd. */
+ qps->tried_fd_last = qps->fd_last ;
+ qps->pend_fd = 0 ;
+
+ /* Convert timeout time to interval for pselect() */
+ timeout -= qt_get_monotonic() ;
+ if (timeout < 0)
+ timeout = 0 ;
+
+ /* Finally ready for the main event */
+ n = pselect(qps->fd_last + 1, p_fds[qps_read_mnum],
+ p_fds[qps_write_mnum],
+ p_fds[qps_error_mnum],
+ qtime2timespec(&ts, timeout),
+ (qps->signum != 0) ? &qps->sigmask : NULL) ;
+
+ /* If have something, set and return the pending count. */
+ if (n > 0)
+ {
+ assert(qps->pend_mnum < qps_mnum_count) ; /* expected something */
+
+ return qps->pend_count = n ; /* set and return pending count */
+ } ;
+
+ /* Flush the results vectors -- not apparently done if n <= 0) */
+ qps_super_set_zero(qps->results, qps_mnum_count) ;
+
+ qps->pend_count = 0 ; /* nothing pending */
+
+ /* Return appropriately, if we can */
+ if ((n == 0) || (errno == EINTR))
+ return n ;
+
+ zabort_errno("Failed in pselect") ;
+} ;
+
+/* Dispatch the next errored/readable/writeable file, as returned by the
+ * most recent qps_pselect().
+ *
+ * Processes the errored files, then the readable and lastly the writeable.
+ *
+ * Processes one file per call of this function, by invoking the file's
+ * "action" routine.
+ *
+ * If a given file is ready in more than one mode, all modes will be processed,
+ * unless the action routine for one mode disables the file for other modes, or
+ * removes it from the selection.
+ *
+ * Returns the number of files left to process (after the one just processed).
+ */
+int
+qps_dispatch_next(qps_selection qps)
+{
+ int fd ;
+ qps_file qf ;
+ qps_mnum_t mnum ;
+
+ /* TODO: put this under a debug skip */
+ qps_selection_validate(qps) ;
+
+ if (qps->pend_count == 0)
+ return 0 ; /* quit immediately of nothing to do. */
+
+ fd = qps->pend_fd ;
+ mnum = qps->pend_mnum ;
+
+ dassert( (mnum >= 0) && (mnum < qps_mnum_count)
+ && (qps->tried_count[mnum] != 0)
+ && (qps->pend_count > 0) ) ;
+
+ while (1)
+ {
+ fd = qps_next_fd_pending(&(qps->results[mnum]), fd, qps->tried_fd_last) ;
+ if (fd >= 0)
+ break ; /* easy if have another fd in current mode. */
+
+ do /* step to next mode that was not empty */
+ {
+ qps->tried_count[mnum] = 0 ; /* tidy up as we go */
+ ++mnum ;
+ if (mnum >= qps_mnum_count)
+ zabort("Unexpectedly ran out of pending stuff") ;
+ } while (qps->tried_count[mnum] == 0) ;
+
+ qps->pend_mnum = mnum ; /* update mode */
+ fd = 0 ; /* back to the beginning */
+ } ;
+
+ qps->pend_count -= 1 ; /* one less pending */
+ qps->pend_fd = fd ; /* update scan */
+
+ qf = qps_file_lookup_fd(qps, fd, NULL) ;
+
+ dassert( ((qf->enabled_bits && qps_mbit(mnum)) != 0) &&
+ (qf->actions[mnum] != NULL) ) ;
+
+ qf->actions[mnum](qf, qf->file_info) ; /* dispatch the required action */
+
+ return qps->pend_count ;
+} ;
+
+/*==============================================================================
+ * qps_file structure handling
+ */
+
+/* Initialise qps_file structure -- allocating one if required.
+ *
+ * If a template is given, then the action functions are copied from there to
+ * the new structure. See above for discussion of action functions.
+ *
+ * Once initialised, the file may be added to a selection.
+ *
+ * Returns the qps_file.
+ */
+qps_file
+qps_file_init_new(qps_file qf, qps_file template)
+{
+ if (qf == NULL)
+ qf = XCALLOC(MTYPE_QPS_FILE, sizeof(struct qps_file)) ;
+ else
+ memset(qf, 0, sizeof(struct qps_file)) ;
+
+ /* Zeroising has initialised:
+ *
+ * selection -- NULL -- ditto
+ *
+ * file_info -- NULL -- is set by qps_add_file()
+ * fd -- unset -- ditto
+ *
+ * enabled_bits -- nothing enabled
+ *
+ * actions[] -- all set to NULL
+ */
+
+ if (template != NULL)
+ memcpy(qf->actions, template->actions, sizeof(qf->actions)) ;
+
+ return qf ;
+} ;
+
+/* Free dynamically allocated qps_file structure.
+ *
+ * It is the caller's responsibility to have removed it from any selection it
+ * may have been in.
+ */
+void
+qps_file_free(qps_file qf)
+{
+ assert(qf->selection == NULL) ; /* Mustn't be a selection member ! */
+
+ XFREE(MTYPE_QPS_FILE, qf) ;
+} ;
+
+/* Enable (or re-enable) file for the given mode.
+ *
+ * If the action argument is not NULL, set the action for the mode.
+ *
+ * NB: It is a FATAL error to enable a mode with a NULL action.
+ *
+ * NB: It is a FATAL error to enable modes for a file which is not in a
+ * selection.
+ */
+void
+qps_enable_mode(qps_file qf, qps_mnum_t mnum, qps_action* action)
+{
+ qps_mbit_t mbit = qps_mbit(mnum) ;
+ qps_selection qps = qf->selection ;
+
+ dassert(qps != NULL) ;
+ dassert((mnum >= 0) && (mnum <= qps_mnum_count)) ;
+
+ if (action != NULL)
+ qf->actions[mnum] = action ;
+ else
+ dassert(qf->actions[mnum] != NULL) ;
+
+ if (qf->enabled_bits & mbit)
+ dassert(FD_ISSET(qf->fd, &(qps->enabled[mnum].fdset))) ;
+ else
+ {
+ dassert( ! FD_ISSET(qf->fd, &(qps->enabled[mnum].fdset))) ;
+ FD_SET(qf->fd, &(qps->enabled[mnum].fdset)) ;
+ ++qps->enabled_count[mnum] ;
+ qf->enabled_bits |= mbit ;
+ } ;
+} ;
+
+/* Set action for given mode -- does not enable/disable.
+ *
+ * May unset an action by setting it NULL !
+ *
+ * See above for discussion of action functions.
+ *
+ * NB: it is a fatal error to unset an action for a mode which is enabled.
+ */
+void
+qps_set_action(qps_file qf, qps_mnum_t mnum, qps_action* action)
+{
+ dassert((mnum >= 0) && (mnum <= qps_mnum_count)) ;
+
+ if (action == NULL)
+ passert((qf->enabled_bits & qps_mbit(mnum)) == 0) ;
+
+ qf->actions[mnum] = action ;
+} ;
+
+/* Disable file for one or more modes.
+ *
+ * If there are any pending pending results for the modes, those are discarded.
+ *
+ * Note that this is modestly "optimised" to deal with disabling a single mode.
+ * (Much of the time only the write mode will be being disabled !)
+ *
+ * NB: it is safe to disable modes which are not enabled -- even if the file
+ * is not currently a member of a selection. (If it is not a member of a
+ * collection no modes should be enabled !)
+ */
+
+static qps_mnum_t qps_first_mnum[qps_mbit(qps_mnum_count)] =
+ {
+ -1, /* 0 -> -1 -- no bit set */
+ 0, /* 1 -> 0 -- B0 is first bit */
+ 1, /* 2 -> 1 -- B1 is first bit */
+ 1, /* 3 -> 1 -- B1 is first bit */
+ 2, /* 4 -> 2 -- B2 is first bit */
+ 2, /* 5 -> 2 -- B2 is first bit */
+ 2, /* 6 -> 2 -- B2 is first bit */
+ 2 /* 7 -> 2 -- B2 is first bit */
+ } ;
+
+CONFIRM(qps_mbit(qps_mnum_count) == 8) ;
+
+void
+qps_disable_modes(qps_file qf, qps_mbit_t mbits)
+{
+ qps_mnum_t mnum ;
+
+ qps_selection qps = qf->selection ;
+
+ dassert((mbits >= 0) && (mbits <= qps_all_mbits)) ;
+
+ mbits &= qf->enabled_bits ; /* don't bother with any not enabled */
+ qf->enabled_bits ^= mbits ; /* unset what we're about to disable */
+
+ while (mbits != 0)
+ {
+ mnum = qps_first_mnum[mbits] ;
+
+ dassert(qps->enabled_count[mnum] > 0) ;
+ dassert(FD_ISSET(qf->fd, &(qps->enabled[mnum].fdset))) ;
+
+ FD_CLR(qf->fd, &(qps->enabled[mnum].fdset)) ;
+ --qps->enabled_count[mnum] ;
+
+ if ((qps->pend_count != 0) && (qps->tried_count[mnum] != 0)
+ && (FD_ISSET(qf->fd, &(qps->results[mnum].fdset))))
+ {
+ FD_CLR(qf->fd, &(qps->results[mnum].fdset)) ;
+ --qps->pend_count ;
+ } ;
+
+ mbits ^= qps_mbit(mnum) ;
+ } ;
+} ;
+
+/*==============================================================================
+ * Handling the files vector.
+ *
+ * For small numbers of fd's, the files vector is kept as a list, in fd order.
+ * Files are found by binary chop, and added/removed by insert/delete in the
+ * list.
+ *
+ * For large numbers of fd's, the files vector is kept as an array, indexed by
+ * fd.
+ */
+
+/* Comparison function for binary chop */
+static int
+qps_fd_cmp(const int** pp_fd, const qps_file* p_qf)
+{
+ if (**pp_fd < (*p_qf)->fd)
+ return -1 ;
+ if (**pp_fd > (*p_qf)->fd)
+ return +1 ;
+ return 0 ;
+}
+
+/* Lookup/Insert file by file-descriptor.
+ *
+ * Inserts if insert argument is not NULL.
+ *
+ * Returns the file we found (if any) or the file we just inserted.
+ *
+ * NB: FATAL error to insert file with same fd as an existing one.
+ */
+static qps_file
+qps_file_lookup_fd(qps_selection qps, int fd, qps_file insert)
+{
+ qps_file qf ;
+ vector_index i ;
+ int ret ;
+
+ dassert((fd >= 0) && (fd < FD_SETSIZE)) ;
+
+ /* Look-up */
+ /* */
+ /* Set i = index for entry in files vector */
+ /* Set ret = 0 <=> i is exact index. */
+ /* < 0 <=> i is just after where entry may be inserted */
+ /* > 0 <=> i is just before where entry may be inserted */
+ if (qps->fd_direct)
+ {
+ i = fd ; /* index of entry */
+ ret = 0 ; /* how to insert, if do */
+ }
+ else
+ i = vector_bsearch(&qps->files, (vector_bsearch_cmp*)qps_fd_cmp,
+ &fd, &ret) ;
+ if (ret == 0)
+ qf = vector_get_item(&qps->files, i) ; /* NULL if not there */
+ else
+ qf = NULL ; /* not there */
+
+ /* Insert now, if required and can: keep fd_count and fd_last up to date. */
+ if (insert != NULL)
+ {
+ if (qf != NULL)
+ zabort("File with given fd already exists in qps_selection") ;
+
+ /* If required, change up to a directly addressed files vector. */
+ if (!qps->fd_direct && (qps->fd_count > 9))
+ {
+ vector tmp ;
+
+ tmp = vector_move_here(NULL, &qps->files) ;
+
+ while ((qf = vector_pop_item(tmp)) != NULL)
+ vector_set_item(&qps->files, qf->fd, qf) ;
+
+ vector_free(tmp) ;
+
+ qps->fd_direct = 1 ;
+
+ i = fd ; /* index is now the fd */
+ ret = 0 ; /* and insert there */
+ } ;
+
+ /* Now can insert accordint to i & ret */
+ vector_insert_item_here(&qps->files, i, ret, insert) ;
+
+ ++qps->fd_count ;
+ if (fd > qps->fd_last)
+ qps->fd_last = fd ;
+
+ qf = insert ; /* will return what we just inserted. */
+ } ;
+
+ /* Sanity checking. */
+ dassert( (qf == NULL) || ((qps == qf->selection) && (fd == qf->fd)) ) ;
+
+ /* Return the file we found or inserted. */
+ return qf ;
+} ;
+
+/* Remove file from selection.
+ *
+ * NB: FATAL error if file is not in the selection, or the file-descriptor
+ * is invalid (or refers to some other file !).
+ */
+static void
+qps_file_remove(qps_selection qps, qps_file qf)
+{
+ qps_file qfd ;
+ int fd_last ;
+
+ passert((qf->fd >= 0) && (qf->fd <= qps->fd_last) && (qps == qf->selection)) ;
+
+ /* Look-up and remove. */
+ if (qps->fd_direct)
+ {
+ qfd = vector_unset_item(&qps->files, qf->fd) ; /* NULL if not there */
+ fd_last = vector_end(&qps->files) - 1 ;
+ }
+ else
+ {
+ qps_file qf_last ;
+ int ret ;
+ vector_index i = vector_bsearch(&qps->files,
+ (vector_bsearch_cmp*)qps_fd_cmp,
+ &qf->fd, &ret) ;
+ if (ret == 0)
+ qfd = vector_delete_item(&qps->files, i) ;
+ else
+ qfd = NULL ;
+
+ qf_last = vector_get_last_item(&qps->files) ;
+ if (qf_last != NULL)
+ fd_last = qf_last->fd ;
+ else
+ fd_last = -1 ;
+ } ;
+
+ passert(qfd == qf) ; /* must have been there and be the expected file */
+
+ /* Keep fd_count and fd_last up to date. */
+ dassert(qps->fd_count > 0) ;
+ --qps->fd_count ;
+
+ dassert( ((qps->fd_count != 0) && (fd_last >= 0)) ||
+ ((qps->fd_count == 0) && (fd_last < 0)) ) ;
+
+ qps->fd_last = (fd_last >= 0) ? fd_last : 0 ;
+
+ /* Also, remove the from all vectors. */
+ qps_disable_modes(qf, qps_all_mbits) ;
+
+ /* Is no longer in the selection. */
+ qf->selection = NULL ;
+} ;
+
+ /*==============================================================================
+ * fd_super_set support.
+ *
+ * For large sets of file descriptors something faster than testing for all
+ * possible bits is required. The fd_super_set assumes that the fd_set is a
+ * straightforward bit-vector, and overlays a 32-bit word array and a byte
+ * array over that.
+ *
+ * Cannot tell if the underlying bit vector is arranged in bytes, or some
+ * longer words. Cannot tell if words are held big or little endian. Cannot
+ * tell if lowest numbered fd will be highest or lowest in whatever unit it's
+ * held in.
+ *
+ * So... we have maps for fd -> our word index, and fd -> byte index.
+ *
+ * we have a map for fd -> mask for bit used in its byte.
+ *
+ * We require that fds will be numbered consistently in bytes. That is,
+ * every (fd mod 8) == n will appear in the same bit in a byte, for all fd (
+ * for n = 0..7). This allows the final map, which takes a byte value and
+ * returns the lowest numbered fd in the byte, mod 8.
+ *
+ * To copy all the bytes for all descriptors 0..fd, also construct
+ * fd_byte_count[] -- which copes with the fact that on a big-endian machine
+ * it is possible that descriptor fd - 8 may be in a higher numbered byte than
+ * fd ! Using this count assumes that the underlying system really does not
+ * look at bits beyond the given maximum fd.
+ */
+
+static short fd_word_map[FD_SETSIZE] ; /* maps fd to word index */
+static short fd_byte_map[FD_SETSIZE] ; /* maps fd to byte index */
+static uint8_t fd_bit_map [FD_SETSIZE] ; /* maps fd to bit in byte */
+
+static int8_t fd_first_map[256] ; /* maps byte value to 0..7, where that */
+ /* is the lowest fd bit set in byte. */
+
+#define QPS_TESTING 0 /* true => testing */
+
+#if !QPS_TESTING
+
+/* Not testing, so map to the standard FD_SET etc. functions. */
+# define qFD_SET FD_SET
+# define qFD_CLR FD_CLR
+# define qFD_ISSET FD_ISSET
+# define qFD_ZERO FD_ZERO
+
+#else
+
+/* Set up the testing */
+
+# define QPS_TEST_WORD 4 /* Wordsize */
+# define QPS_TEST_BE 1 /* true => big-endian */
+# define QPS_TEST_B_ORD 07 /* 07 => bits 0..7, 70 => bits 7..0 */
+
+# define QPS_TEST_WORD_BITS (QPS_TEST_WORD * 8)
+# if QPS_TEST_BE
+# define QPS_BYTE(fd) ( ((fd / QPS_TEST_WORD_BITS) * QPS_TEST_WORD) \
+ + (QPS_TEST_WORD - 1) - ((fd % QPS_TEST_WORD_BITS) / 8) )
+#else
+# define QPS_BYTE(fd) ( fd / 8 )
+#endif
+
+# if QPS_TEST_B_ORD == 07
+# define QPS_BIT(fd) (0x01 << (fd & 0x7))
+# else
+# define QPS_BIT(fd) (0x80 >> (fd & 0x7))
+# endif
+
+ static void
+ qFD_SET(int fd, fd_set* set)
+ {
+ *((uint8_t*)set + QPS_BYTE(fd)) |= QPS_BIT(fd) ;
+ } ;
+
+ static void
+ qFD_CLR(int fd, fd_set* set)
+ {
+ *((uint8_t*)set + QPS_BYTE(fd)) &= ~QPS_BIT(fd) ;
+ } ;
+
+ static int
+ qFD_ISSET(int fd, fd_set* set)
+ {
+ return (*((uint8_t*)set + QPS_BYTE(fd)) & QPS_BIT(fd)) != 0 ;
+ } ;
+
+ static void
+ qFD_ZERO(fd_set* set)
+ {
+ memset(set, 0, sizeof(fd_set)) ;
+ } ;
+
+#endif
+
+/* Scan for next fd in given fd set, and clear it.
+ *
+ * Starts at the given fd, will not consider anything above fd_last.
+ *
+ * Returns next fd, or -1 if none.
+ */
+static int
+qps_next_fd_pending(fd_super_set* pending, int fd, int fd_last)
+{
+ uint8_t b ;
+
+ while (pending->words[fd_word_map[fd]] == 0) /* step past zero words */
+ {
+ fd = (fd & ~ (FD_WORD_BITS - 1)) + FD_WORD_BITS ;
+ /* step to start of next word */
+ if (fd > fd_last)
+ return -1 ; /* quit if past last */
+ } ;
+
+ fd &= ~0x0007 ; /* step back to first in byte */
+ while ((b = pending->bytes[fd_byte_map[fd]]) == 0)
+ {
+ fd += 8 ;
+ if (fd > fd_last)
+ return -1 ;
+ } ;
+
+ fd += fd_first_map[b] ;
+
+ dassert(fd <= fd_last) ;
+ dassert((b & fd_bit_map[fd]) == fd_bit_map[fd]) ;
+
+ FD_CLR(fd, &pending->fdset) ;
+
+ dassert((b ^ fd_bit_map[fd]) == pending->bytes[fd_byte_map[fd]]) ;
+
+ return fd ;
+} ;
+
+/* Make a map of the fd_super_set.
+ *
+ * The form of an fd_set is not defined. This code verifies that it is, in
+ * fact a bit vector, and hence that the fd_super_set works here !
+ *
+ * It is a FATAL error if things don't work out.
+ */
+static void
+qps_make_super_set_map(void)
+{
+ fd_super_set test ;
+ int fd, i, iw, ib ;
+
+ /* (1) check that a zeroised fd_super_set is an empty one. */
+ qps_super_set_zero(&test, 1) ;
+
+ for (fd = 0 ; fd < FD_SETSIZE ; ++fd)
+ if (qFD_ISSET(fd, &test.fdset))
+ zabort("Zeroised fd_super_set is not empty") ;
+
+ /* (2) check that zeroising the fd_set doesn't change things */
+ qFD_ZERO(&test.fdset) ;
+ for (iw = 0 ; iw < FD_SUPER_SET_WORD_SIZE ; ++iw)
+ if (test.words[iw] != 0)
+ zabort("Zeroised fd_super_set is not all zero words") ;
+
+ /* (3) check that setting one fd sets one bit, and construct the */
+ /* fd_word_map[], fd_byte_map[] and fd_bit_map[]. */
+ for (fd = 0 ; fd < FD_SETSIZE ; ++fd)
+ {
+ fd_word_t w ;
+
+ qFD_SET(fd, &test.fdset) ;
+
+ w = 0 ;
+ for (iw = 0 ; iw < FD_SUPER_SET_WORD_SIZE ; ++iw)
+ {
+ if (test.words[iw] != 0)
+ {
+ if (w != 0)
+ zabort("FD_SET set a bit in more than one word") ;
+
+ w = test.words[iw] ;
+ if ((w == 0) || ((w & (w - 1)) != 0))
+ zabort("FD_SET set more than one bit in a word") ;
+
+ fd_word_map[fd] = iw ;
+
+ ib = iw * FD_WORD_BYTES ;
+ while (test.bytes[ib] == 0)
+ {
+ ++ib ;
+ if (ib >= ((iw + 1) * FD_WORD_BYTES))
+ zabort("FD_SET set something beyond the expected bytes") ;
+ } ;
+ fd_byte_map[fd] = ib ;
+ fd_bit_map[fd] = test.bytes[ib] ;
+ } ;
+ } ;
+
+ if (w == 0)
+ zabort("FD_SET did not set any bit in any word") ;
+
+ qFD_CLR(fd, &test.fdset) ;
+
+ for (iw = 0 ; iw < FD_SUPER_SET_WORD_SIZE ; ++iw)
+ if (test.words[iw] != 0)
+ zabort("FD_CLR did not leave the fd_super_set empty") ;
+ } ;
+
+ /* (4) check the fd_byte_map. */
+ /* make sure that have 8 contiguous fd to a byte. */
+ /* make sure that have 32 contiguous fd to a word. */
+
+ for (fd = 0 ; fd < FD_SETSIZE ; fd += 8)
+ {
+ int fds ;
+ ib = fd_byte_map[fd] ;
+ iw = fd_word_map[fd] ;
+
+ /* Must share the same byte as the next 7 fds */
+ for (fds = fd + 1 ; fds < (fd + 8) ; ++fds)
+ if (fd_byte_map[fds] != ib)
+ zabort("Broken fd_byte_map -- not 8 contiguous fd's in a byte") ;
+
+ /* Must not share the same byte as any other set of 8 fd's */
+ for (fds = 0 ; fds < FD_SETSIZE ; fds += 8)
+ if ((fd_byte_map[fds] == ib) && (fds != fd))
+ zabort("Broken fd_byte_map -- fd's not in expected bytes") ;
+
+ /* Must be one of the bytes in the current word's fd's */
+ if ( (ib < (iw * FD_WORD_BYTES)) || (ib >= ((iw + 1) * FD_WORD_BYTES)) )
+ zabort("Broken fd_byte_map -- fd's not in expected words") ;
+ } ;
+
+ /* (5) check the fd_bit_map */
+ /* make sure that all fd mod 8 map to the same byte value */
+
+ for (i = 0 ; i < 8 ; ++i)
+ {
+ uint8_t b = fd_bit_map[i] ;
+ for (fd = 8 + i ; fd < FD_SETSIZE ; fd += 8)
+ if (fd_bit_map[fd] != b)
+ zabort("Broken fd_bit_map -- inconsistent bit mapping") ;
+ } ;
+
+ /* (6) construct fd_first_map, to get lowest numbered fd (mod 8) from */
+ /* a given byte value. */
+
+ for (i = 0 ; i < 256 ; ++i)
+ fd_first_map[i] = -1 ;
+
+ for (fd = 0 ; fd < 8 ; ++fd)
+ {
+ uint8_t fdb = fd_bit_map[fd] ;
+ for (i = 1 ; i < 256 ; ++i)
+ if ((fd_first_map[i] == -1) && ((i & fdb) != 0))
+ fd_first_map[i] = fd ;
+ } ;
+
+ for (i = 1 ; i < 256 ; ++i)
+ if (fd_first_map[i] == -1)
+ zabort("Broken fd_first_map -- missing bits") ;
+
+ /* (7) construct fd_byte_count[] -- number of bytes required to */
+ /* include fds 0..fd. */
+
+ i = 0 ;
+ for (fd = 0 ; fd < FD_SETSIZE ; ++fd)
+ {
+ int c = fd_byte_map[fd] + 1 ;
+
+ if (c < i)
+ c = i ; /* use largest so far. => big-endian */
+ else
+ i = c ; /* keep largest so far up to date */
+
+ fd_byte_count[fd] = c ;
+ } ;
+
+#if QPS_TESTING
+
+ /* Checking that the maps have been correctly deduced */
+
+ for (fd = 0 ; fd < FD_SETSIZE ; ++fd)
+ {
+ uint8_t b ;
+ short c ;
+
+ iw = fd / QPS_TEST_WORD_BITS ;
+ if (QPS_TEST_BE)
+ ib = ( ((fd / QPS_TEST_WORD_BITS) * QPS_TEST_WORD) +
+ (QPS_TEST_WORD - 1) - ((fd % QPS_TEST_WORD_BITS) / 8) ) ;
+ else
+ ib = ( fd / 8 ) ;
+
+ if (QPS_TEST_B_ORD == 07)
+ b = 0x01 << (fd % 8) ;
+ else
+ b = 0x80 >> (fd % 8) ;
+
+ if (QPS_TEST_BE)
+ c = (iw + 1) * QPS_TEST_WORD ;
+ else
+ c = (ib + 1) ;
+
+ if (fd_word_map[fd] != iw)
+ zabort("Broken fd_word_map") ;
+ if (fd_byte_map[fd] != ib)
+ zabort("Broken fd_byte_map") ;
+ if (fd_bit_map[fd] != b)
+ zabort("Broken fd_bit_map") ;
+ if (fd_byte_count[fd] != c)
+ zabort("Broken fd_byte_count") ;
+ } ;
+
+ for (i = 1 ; i < 256 ; ++i)
+ {
+ uint8_t b = i ;
+ fd = 0 ;
+ if (QPS_TEST_B_ORD == 07)
+ {
+ while ((b & 1) == 0)
+ {
+ b >>= 1 ;
+ ++fd ;
+ } ;
+ }
+ else
+ {
+ while ((b & 0x80) == 0)
+ {
+ b <<= 1 ;
+ ++fd ;
+ } ;
+ } ;
+
+ if (fd_first_map[i] != fd)
+ zabort("Broken fd_first_map") ;
+ } ;
+
+ zabort("OK fd mapping") ;
+#endif
+
+ /* Phew -- we're all set now */
+ qps_super_set_map_made = 1 ;
+} ;
+
+/* Zeroise 'n' contiguous fd_super_sets
+ *
+ * NB: this MUST be used in place of FD_ZERO because the fd_set may be shorter
+ * than the overlayed words/bytes vectors.
+ *
+ * NB: it is CONFIRMED elsewhere that the fd_set is no longer than the overlays.
+ */
+static void
+qps_super_set_zero(fd_super_set* p_set, int n)
+{
+ memset(p_set, 0, SIZE(fd_super_set, n)) ;
+} ;
+
+#if 0 /* Mask unused function */
+/* Copy 'n' contiguous fd_super_sets
+ */
+static void
+qps_super_set_copy(fd_super_set* p_dst, fd_super_set* p_src, int n)
+{
+ memcpy(p_dst, p_src, SIZE(fd_super_set, n)) ;
+} ;
+#endif
+
+/* Compare 'n' contiguous fd_super_sets
+ */
+static int
+qps_super_set_cmp(fd_super_set* p_a, fd_super_set* p_b, int n)
+{
+ return memcmp(p_a, p_b, SIZE(fd_super_set, n)) ;
+} ;
+
+/* Count the number of bits set in 'n' contiguous fd_super_sets.
+ */
+static int
+qps_super_set_count(fd_super_set* p_set, int n)
+{
+ fd_word_t* p ;
+ int count = 0 ;
+
+ n *= FD_SUPER_SET_WORD_SIZE ;
+ confirm(sizeof(fd_super_set) == (FD_SUPER_SET_WORD_SIZE * FD_WORD_BYTES)) ;
+
+ p = (fd_word_t*)p_set ;
+ while (n--)
+ {
+ fd_word_t w = *p++ ;
+ while (w != 0)
+ {
+ ++count ;
+ w &= (w - 1) ;
+ } ;
+ } ;
+
+ return count ;
+} ;
+
+/*==============================================================================
+ * Selection state check -- for debug purposes.
+ *
+ * Runs a check across a given selection and verifies that:
+ *
+ * 1) for !fd_direct that the files are in fd order in the vector
+ * and are unique, and there are no NULL entries.
+ * 2) for fd_direct that the file fd and the index match
+ * and the last entry is not NULL
+ * 3) that all files point at the selection
+ * 4) that the enabled modes in each file are valid
+ * 5) the number of files in the selection matches fd_count.
+ * 6) the highest numbered fd matches fd_last
+ * 7) that the enabled counts in the selection are correct
+ * 8) that the enabled modes in each file match the enabled modes in the
+ * selection
+ * 9) that no extraneous fds are set in the enabled vectors
+ *
+ * If there are no pending fds:
+ *
+ * 10) if there are no pending fds, that the results vectors are empty.
+ *
+ * If there are pending fds:
+ *
+ * 11) that pend_mnum is valid and pend_fd <= tried_fd_last.
+ *
+ * 12) that the tried_count for modes 0..pend_mnum-1 is zero,
+ * and the tried_count for pend_mnum is not.
+ *
+ * 13) that the result vectors for modes where tried count == 0 are empty.
+ *
+ * 14) that the remaining result bits are a subset of the enabled bits.
+ *
+ * 15) that no bits beyond tried_fd_last are set in the result vectors.
+ *
+ * 16) that no bits before pend_fd are set in the pemd_mnum result vector.
+ *
+ * 17) that the number of bits remaining matches pend_count.
+ */
+static void
+qps_selection_validate(qps_selection qps)
+{
+ int fd_last ;
+ int enabled_count[qps_mnum_count] ;
+ fd_full_set enabled ;
+
+ qps_file qf ;
+ int fd, n, mnum, p_mnum ;
+ vector_index i ;
+
+ /* 1..4) Run down the selection vector and check. */
+ /* Collect new enabled_count and enabled bit vectors. */
+
+ for (mnum = 0 ; mnum < qps_mnum_count ; ++mnum)
+ enabled_count[mnum] = 0 ;
+ qps_super_set_zero(enabled, qps_mnum_count) ;
+
+ n = 0 ;
+ fd_last = -1 ;
+ for (VECTOR_ITEMS(&qps->files, qf, i))
+ {
+ if (qf != NULL)
+ {
+ ++n ; /* Number of files */
+
+ if (qps->fd_direct)
+ {
+ if (qf->fd != (int)i) /* index and fd must match */
+ zabort("File vector index and fd mismatch") ;
+ }
+ else
+ {
+ if (qf->fd <= fd_last) /* must be unique and in order */
+ zabort("File vector not in order") ;
+ } ;
+
+ fd_last = qf->fd ; /* keep track of last fd */
+
+ if (qf->selection != qps) /* file must refer to selection */
+ zabort("File does not refer to its selection") ;
+
+ if ((qf->enabled_bits < 0) || (qf->enabled_bits > qps_all_mbits))
+ zabort("File enabled bits are invalid") ;
+
+ /* Capture enabled state of all files. */
+ for (mnum = 0 ; mnum < qps_mnum_count ; ++mnum)
+ if (qf->enabled_bits & qps_mbit(mnum))
+ {
+ ++enabled_count[mnum] ;
+ FD_SET(qf->fd, &enabled[mnum].fdset) ;
+ } ;
+ }
+ else
+ if (!qps->fd_direct)
+ zabort("Found NULL entry in !fd_direct files vector") ;
+ } ;
+
+ if ((n != 0) && (vector_get_last_item(&qps->files) == NULL))
+ zabort("Last entry in file vector is NULL") ;
+
+ /* 5) check that the number of files tallies. */
+ if (n != qps->fd_count)
+ zabort("Number of files in the selection does not tally") ;
+
+ /* 6) check the last fd */
+ if ( ((n == 0) && (qps->fd_last !=0)) || (fd_last != qps->fd_last) )
+ zabort("The last fd does not tally") ;
+
+ /* 7) check that the enabled counts tally. */
+ for (mnum = 0 ; mnum < qps_mnum_count ; ++mnum)
+ if (enabled_count[mnum] != qps->enabled_count[mnum])
+ zabort("Enabled counts do not tally") ;
+
+ /* 8..9) Check that the enabled vectors are the same as the ones just */
+ /* created by scanning the files. */
+ if (qps_super_set_cmp(enabled, qps->enabled, qps_mnum_count) != 0)
+ zabort("Enabled bit vectors do not tally") ;
+
+ /* 10) if there are no pending fds, check result vectors empty. */
+ if (qps->pend_count == 0)
+ {
+ if (qps_super_set_count(qps->results, qps_mnum_count) != 0)
+ zabort("Nothing pending, but result vectors not empty") ;
+
+ return ;
+ } ;
+
+ /* This is to stop gcc whining about signed/unsigned comparisons. */
+ p_mnum = qps->pend_mnum ;
+
+ /* 11) that pend_mnum is valid and pend_fd <= tried_fd_last. */
+ if ( (p_mnum < 0) || (p_mnum > qps_mnum_count)
+ || (qps->pend_fd < 0)
+ || (qps->pend_fd > qps->tried_fd_last) )
+ zabort("Invalid pend_mnum or pend_fd") ;
+
+ /* 12) check tried_count[] */
+ for (mnum = 0 ; mnum < qps_mnum_count ; ++mnum)
+ {
+ if ((mnum < p_mnum) && (qps->tried_count[mnum] != 0))
+ zabort("Non-zero tried_count for mode < pend_mnum") ;
+ if ((mnum == p_mnum) && (qps->tried_count[qps->pend_mnum] <= 0))
+ zabort("Zero tried_count for pend_mnum") ;
+ if ((mnum > p_mnum) && (qps->tried_count[mnum] < 0))
+ zabort("Invalid tried_count for mode > pend_mnum") ;
+ } ;
+
+ /* 13) check result vectors for modes where tried count == 0 */
+ n = (qps_super_set_count(qps->results, qps_mnum_count) != 0) ;
+ for (mnum = 0 ; mnum < qps_mnum_count ; ++mnum)
+ if ((qps->tried_count[mnum] == 0)
+ && (qps_super_set_count(&qps->results[mnum], 1) != 0))
+ zabort("Non-empty bit vector where tried count == 0") ;
+
+ /* 14) check remaining results are a subset of the enableds. */
+ /* 15) check no bit beyond tried_fd_last is set in the results. */
+ /* 16) check no bit before pend_fd is set in the pemd_mnum results. */
+ /* 17) check the number of bits remaining matches pend_count. */
+
+ n = 0 ;
+ for (mnum = 0 ; mnum < qps_mnum_count ; ++mnum)
+ if (qps->tried_count[mnum] != 0)
+ {
+ for (fd = 0 ; fd < FD_SETSIZE ; ++fd)
+ if (FD_ISSET(fd, &qps->results[mnum].fdset))
+ {
+ ++n ;
+ if (fd > qps->tried_fd_last)
+ zabort("Found pending fd beyond tried_fd_last") ;
+ if ( ! FD_ISSET(fd, &qps->results[mnum].fdset))
+ zabort("Found pending fd which is not enabled") ;
+ if ((mnum == p_mnum) && (fd < qps->pend_fd))
+ zabort("Found pending fd < current next pending") ;
+ } ;
+ } ;
+
+ if (n != qps->pend_count)
+ zabort("Non-empty bit vector where tried count == 0") ;
+} ;
diff --git a/lib/qpselect.h b/lib/qpselect.h
new file mode 100644
index 00000000..1e67d174
--- /dev/null
+++ b/lib/qpselect.h
@@ -0,0 +1,208 @@
+/* Quagga pselect support -- header
+ * Copyright (C) 2009 Chris Hall (GMCH), Highwayman
+ *
+ * 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 _ZEBRA_QPSELECT_H
+#define _ZEBRA_QPSELECT_H
+
+#include <sys/select.h>
+#include <errno.h>
+
+#include "zassert.h"
+#include "qtime.h"
+#include "vector.h"
+
+#ifndef Inline
+#define Inline static inline
+#endif
+
+/*==============================================================================
+ * Quagga pselect -- qps_xxxx
+ *
+ * Here and in qpselect.c is a data structure for managing multiple file
+ * descriptors and running pselect to wait for I/O activity and to multiplex
+ * between the file descriptors.
+ */
+
+enum qps_mnum /* "mode" numbers: error/read/write */
+{
+ qps_mnum_first = 0,
+
+ qps_error_mnum = 0,
+ qps_read_mnum = 1,
+ qps_write_mnum = 2,
+
+ qps_mnum_count = 3
+} ;
+
+typedef enum qps_mnum qps_mnum_t ;
+
+#define qps_mbit(mnum) (1 << mnum)
+
+enum qps_mbits /* "mode" bits: error/read/write */
+{
+ qps_error_mbit = qps_mbit(qps_error_mnum),
+ qps_read_mbit = qps_mbit(qps_read_mnum),
+ qps_write_mbit = qps_mbit(qps_write_mnum),
+
+ qps_all_mbits = qps_mbit(qps_mnum_count) - 1
+} ;
+
+typedef enum qps_mbits qps_mbit_t ;
+
+/* Forward references */
+typedef struct qps_selection* qps_selection ;
+typedef struct qps_file* qps_file ;
+
+/*==============================================================================
+ * fd_super_set.
+ *
+ * To speed up scanning of large fd_set's this structure overlays a 32-bit
+ * word and a byte array over the (assumed) fd_set bit vector.
+ *
+ * There is no guarantee that FD_SETSIZE is a multiple of 32 (or of 8, for
+ * that matter) -- so some care must be taken.
+ */
+
+typedef uint32_t fd_word_t ;
+
+#define FD_WORD_BITS 32
+#define FD_WORD_BYTES (FD_WORD_BITS / 8)
+
+CONFIRM(FD_WORD_BITS == (FD_WORD_BYTES * 8)) ; /* for completeness */
+
+#define FD_SUPER_SET_WORD_SIZE ((FD_SETSIZE + FD_WORD_BITS - 1) / FD_WORD_BITS)
+#define FD_SUPER_SET_BYTE_SIZE (FD_SUPER_SET_WORD_SIZE * FD_WORD_BYTES)
+
+/* Make sure that the overlay is at least as big as the fd_set ! */
+CONFIRM(FD_SUPER_SET_BYTE_SIZE >= sizeof(fd_set)) ;
+
+typedef union /* see qps_make_super_set_map() */
+{
+ fd_word_t words[FD_SUPER_SET_WORD_SIZE] ;
+ uint8_t bytes[FD_SUPER_SET_BYTE_SIZE] ;
+ fd_set fdset ;
+} fd_super_set ;
+
+/* Make sure that the fd_super_set is an exact number of fd_word_t words */
+CONFIRM(sizeof(fd_super_set) == (FD_SUPER_SET_WORD_SIZE * FD_WORD_BYTES)) ;
+
+/*==============================================================================
+ * Action function.
+ *
+ * Each file has three action functions, to be called in qps_dispatch_next()
+ * when pselect() has reported error/read/write for the file.
+ *
+ * For further discussion, see: qps_file_init.
+ */
+
+typedef void qps_action(qps_file qf, void* file_info) ;
+
+/*==============================================================================
+ * Data Structures.
+ */
+
+typedef fd_super_set fd_full_set[qps_mnum_count] ;
+
+struct qps_selection
+{
+ int fd_count ; /* number of fds we are looking after */
+ int fd_direct ; /* direct lookup in vector or not */
+
+ struct vector files ; /* mapping fd to qps_file */
+
+ int fd_last ; /* highest numbered fd we are looking after */
+ int enabled_count[qps_mnum_count] ; /* no. enabled fds in each mode */
+ fd_full_set enabled ; /* bit vectors for pselect enabled stuff */
+
+ int tried_fd_last ; /* highest numbered fd on last pselect */
+ int tried_count[qps_mnum_count] ; /* enabled_count on last pselect */
+ fd_full_set results ; /* last set of results from pselect */
+
+ int pend_count ; /* results pending (if any) */
+ qps_mnum_t pend_mnum ; /* error/read/write mode pending (if any) */
+ int pend_fd ; /* fd pending (if any) */
+
+ int signum ; /* signal that sigmask is enabling -- 0 => none */
+ sigset_t sigmask ; /* sigmask to use for duration of pselect */
+} ;
+
+struct qps_file
+{
+ qps_selection selection ;
+
+ void* file_info ;
+ int fd ;
+
+ qps_mbit_t enabled_bits ;
+
+ qps_action* actions[qps_mnum_count] ;
+} ;
+
+/*==============================================================================
+ * qps_selection handling
+ */
+
+qps_selection
+qps_selection_init_new(qps_selection qps) ;
+
+void
+qps_add_file(qps_selection qps, qps_file qf, int fd, void* file_info) ;
+
+void
+qps_remove_file(qps_file qf) ;
+
+qps_file
+qps_selection_ream(qps_selection qps, int free_structure) ;
+
+/* Ream out selection and free the selection structure. */
+#define qps_selection_ream_free(qps) qps_selection_ream(qps, 1)
+/* Ream out selection but keep the selection structure. */
+#define qps_selection_ream_keep(qps) qps_selection_ream(qps, 0)
+
+void
+qps_set_signal(qps_selection qps, int signum, sigset_t sigmask) ;
+
+int
+qps_pselect(qps_selection qps, qtime_mono_t timeout) ;
+
+int
+qps_dispatch_next(qps_selection qps) ;
+
+/*==============================================================================
+ * qps_file structure handling
+ */
+
+qps_file
+qps_file_init_new(qps_file qf, qps_file template) ;
+
+void
+qps_file_free(qps_file qf) ;
+
+void
+qps_enable_mode(qps_file qf, qps_mnum_t mnum, qps_action* action) ;
+
+void
+qps_set_action(qps_file qf, qps_mnum_t mnum, qps_action* action) ;
+
+void
+qps_disable_modes(qps_file qf, qps_mbit_t mbits) ;
+
+#endif /* _ZEBRA_QPSELECT_H */
diff --git a/lib/qpthreads.c b/lib/qpthreads.c
new file mode 100644
index 00000000..5dd0cfc4
--- /dev/null
+++ b/lib/qpthreads.c
@@ -0,0 +1,570 @@
+/* Quagga Pthreads support -- header
+ * Copyright (C) 2009 Chris Hall (GMCH), Highwayman
+ *
+ * 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.
+ */
+
+/* This MUST come first... otherwise we don't get __USE_UNIX98, which is */
+/* essential if glibc is to allow pthread_mutexattr_settype() to be used. */
+#include "config.h"
+
+#include <signal.h>
+
+#include "qpthreads.h"
+#include "memory.h"
+
+/* If this is not set, will get errors later. */
+#ifndef __USE_UNIX98
+#error "_USE_UNIX98 not defined"
+#endif
+
+/*==============================================================================
+ * Quagga Pthread Interface -- qpt_xxxx
+ *
+ * Here (and in qpthreads.h) are captured all the pthreads features used in
+ * Quagga.
+ *
+ * This provides:
+ *
+ * * "wrappers" around functions which should not fail, but whose return
+ * code it is best to check... at least in a debug environment.
+ *
+ * * the possibility of a separate no pthreads build where pthread facilities
+ * are either dummied out or otherwise dealt with.
+ *
+ * * the ability to add any work-arounds which may be required if poorly
+ * conforming pthreads implementations are encountered
+ *
+ * Pthread Requirements
+ * ====================
+ *
+ * This is assuming support for 1003.1-2004 -- XOPEN Issue 6, with [THR] and
+ * [XSI] options.
+ *
+ * The [XSI] is required for pthread_mutexattr_settype(), only.
+ *
+ * If qpt_thread_attr_init() uses:
+ *
+ * pthread_attr_getinheritsched()/_setinheritshed() [TPS]
+ * pthread_attr_getscope()/_setscope() [TPS]
+ * pthread_attr_getschedpolicy()/_setschedpolicy() [TPS]
+ * pthread_attr_getschedparam()/_setschedparam() [THR]
+ *
+ * but they are only required if explicit scheduling attributes are being set.
+ * (So, could be dropped where not supported.)
+ *
+ * Amongst the things which are NOT required:
+ *
+ * pthread_attr_getguardsize()/_setguardsize() [XSI]
+ * pthread_attr_getstack()/_setstack() [TSA TSS]
+ * pthread_attr_getstackaddr()/_setstackaddr() [TSA OB]
+ * pthread_attr_getstacksize()/_setstacksize() [TSA TSS]
+ *
+ * pthread_barrier_xxx() [BAR]
+ *
+ * pthread_condattr_getpshared()/_setpshared() [TSH]
+ *
+ * pthread_mutex_getprioceiling()/_setprioceiling() [TPP]
+ * pthread_mutex_timedlock() [TMO] pro tem
+ * pthread_mutexattr_getprioceiling()/_setprioceiling() [TPP]
+ * pthread_mutexattr_getprotocol()/_setprotocol() [TPP TPI]
+ * pthread_mutexattr_getpshared()/_setpshared() [TSH]
+ *
+ * pthread_rwlock_xxx() [THR] pro tem
+ * pthread_rwlockattr_init()/_destroy() [THR] pro tem
+ * pthread_rwlockattr_getpshared()/_setpshared() [TSH]
+ *
+ * pthread_spin_xxx() [SPI]
+ *
+ * [CS] (Clock Select) is assumed if HAVE_CLOCK_MONOTONIC.
+ *
+ * In 1003.1-2008, XOPEN issue 7, [THR] and pthread_mutexattr_settype() have
+ * been moved to Base.
+ *
+ * NB: it is essential that pthread_kill() delivers the signal to the target
+ * thread only -- ie, it must be POSIX compliant. That rules out the old
+ * (2.4) LinuxThreads. For Linux, 2.6 (or greater) is required, with
+ * NPTL (these days generally included in glibc).
+ *
+ * NB: for glibc to give all the required features, either _GNU_SOURCE or
+ * _XOPEN_SOURCE must be set *before* the first #include <features.h>.
+ * _XOPEN_SOURCE=600 is sufficient.
+ *
+ * Pthread Thread Attributes -- Scheduling
+ * =======================================
+ *
+ * Pthreads defines some useful looking real-time scheduling features.
+ *
+ * One would like to be able to give I/O intensive threads an advantage over
+ * CPU bound threads.
+ *
+ * Unfortunately, conformance allows a system to have its own scheduling
+ * system -- so long as the standard ones are implemented. Further, there is
+ * no way of telling what priority values are reasonable, even in the standard
+ * scheduling policies.
+ *
+ * The approach taken here is that by default a thread will be created with
+ * the system default attributes -- which may mean inheriting the creating
+ * thread's scheduling attributes.
+ *
+ * It is also possible to construct a set of attributes, using the most
+ * obviously useful properties. It is envisaged that this may be used when a
+ * configuration file is used to set locally sensible values. The attributes
+ * supported are:
+ *
+ * * attr_detached -- whether to start detached or not
+ * * attr_inherit_sched -- whether to inherit scheduling attributes
+ * * attr_sched_scope -- scheduling scope
+ * * attr_sched_policy -- scheduling policy
+ * * attr_sched_priority -- scheduling priority
+ *
+ * See qpt_thread_attr_init, below.
+ *
+ * Not supported here are:
+ *
+ * * attr_guardsize
+ * * attr_stack
+ * * attr_stacksize
+ *
+ * Pthread Mutex Attributes -- Error Checking
+ * ==========================================
+ *
+ * Mutexes are kept simple, only attr_type is used, and that by default.
+ *
+ * POSIX defines four types of mutex:
+ *
+ * _NORMAL no ownership check -- owner will deadlock if locks mutex !
+ * -- undefined what happens if unlock
+ * mutex not owned by self !
+ * no recursive locking
+ *
+ * _ERRORCHECK checks for ownership on lock and unlock
+ * no recursive locking
+ *
+ * _RECURSIVE checks for ownership on lock and unlock
+ * counts up locks and counts down unlocks
+ *
+ * This looks useful, but goes wrong with condition variables !
+ *
+ * _DEFAULT undefined whether checks owner or not, on lock and/or unlock.
+ * no recursive locking
+ *
+ * See qpthreads.h for discussion of Quagga's standard type (QPT_MUTEX_TYPE).
+ *
+ * Other attributes are left in their default state:
+ *
+ * * attr_prioceiling -- default undefined
+ * * attr_protocol -- default undefined
+ * * attr_pshared -- defaults to _PROCESS_PRIVATE
+ *
+ * For the time being it is assumed that these are too exotic.
+ *
+ * Pthread Condition Variable Attributes
+ * =====================================
+ *
+ * Condition variables have only two attributes:
+ *
+ * * attr_clock -- which clock to use
+ * * attr_pshared -- defaults to _PROCESS_PRIVATE
+ *
+ * The use a clock other than Quagga's standard (QPT_COND_CLOCK_ID) is possible,
+ * but not recommended. (See qpthreads.h for discussion of this.)
+ *
+ * Pthread Specific Signal Handling
+ * ================================
+ *
+ * In a threaded application, need to use pthread_sigmask (not sigproc_mask).
+ * (Can use pthread_sigmask in a single threaded application.)
+ *
+ * To direct a signal at a given thread need pthread_kill. *
+ */
+
+/*==============================================================================
+ * Thread creation and attributes.
+ *
+ * Threads may be created with a given set of attributes if required.
+ *
+ * qpt_thread_attr_init() will initialise a set of attributes including the
+ * current standard scheduling attributes. It is envisaged that configuration
+ * options may be used to specify these.
+ *
+ * qpt_thread_create() creates a thread using the given attributes. If those
+ * are NULL, then the system defaults are used.
+ */
+
+/* Initialise a set of attributes -- setting the scheduling options.
+ *
+ * Options:
+ *
+ * qpt_attr_joinable -- the default if nothing specified.
+ * qpt_attr_detached -- overrides qpt_attr_joinable.
+ *
+ * qpt_attr_sched_inherit -- all scheduling attributes are to be inherited.
+ * No explicit scheduling attributes may be set.
+ *
+ * qpt_attr_sched_scope -- set explicit, given, scope.
+ * qpt_attr_sched_policy -- set explicit, given, policy
+ * qpt_attr_sched_priority -- set explicit, given, priority
+ *
+ * If none of the _sched_ options are given, then the scheduling attributes are
+ * left to whatever default values the system chooses.
+ *
+ * If the _sched_inherit option is specified, none of the other _sched_ options
+ * may be specified.
+ *
+ * If any of the explicit scheduling options are given, they are set in this
+ * order. If only some of these options are given, then the caller is
+ * assuming that the system will choose sensible defaults.
+ *
+ * The scope, policy and priority arguments are use only if the corresponding
+ * option is specified.
+ *
+ * Returns the address of the qpt_thread_attr_t structure.
+ */
+qpt_thread_attr_t*
+qpt_thread_attr_init(qpt_thread_attr_t* attr, enum qpt_attr_options opts,
+ int scope, int policy, int priority)
+{
+ int err ;
+
+ assert((opts & ~qpt_attr_known) == 0) ;
+
+ /* Initialise thread attributes structure (allocating if required.) */
+ if (attr == NULL)
+ attr = XMALLOC(MTYPE_QPT_THREAD_ATTR, sizeof(qpt_thread_attr_t)) ;
+
+ err = pthread_attr_init(attr) ;
+ if (err != 0)
+ zabort_err("pthread_attr_init failed", err) ;
+
+ /* If not qpt_attr_detached, then set joinable. */
+ err = pthread_attr_setdetachstate(attr,
+ (opts & qpt_attr_detached) ? PTHREAD_CREATE_DETACHED
+ : PTHREAD_CREATE_JOINABLE) ;
+ if (err != 0)
+ zabort_err("pthread_attr_setdetachstate failed", err) ;
+
+ /* If setting anything to do with scheduling... */
+ if (opts & qpt_attr_sched_setting)
+ {
+ /* Either we inherit or we set explicit parameters. */
+
+ err = pthread_attr_setinheritsched(attr,
+ (opts & qpt_attr_sched_inherit) ? PTHREAD_INHERIT_SCHED
+ : PTHREAD_EXPLICIT_SCHED) ;
+ if (err != 0)
+ zabort_err("pthread_attr_setinheritsched", err) ;
+
+ if (opts & qpt_attr_sched_inherit)
+ assert((opts & qpt_attr_sched_explicit) == 0) ;
+ else
+ {
+ if (opts & qpt_attr_sched_scope)
+ {
+ err = pthread_attr_setscope(attr, scope) ;
+ if (err != 0)
+ zabort_err("pthread_attr_setscope failed", err) ;
+ } ;
+ if (opts & qpt_attr_sched_policy)
+ {
+ err = pthread_attr_setschedpolicy(attr, scope) ;
+ if (err != 0)
+ zabort_err("pthread_attr_setschedpolicy failed", err) ;
+ } ;
+ if (opts & qpt_attr_sched_priority)
+ {
+ struct sched_param sparm ;
+ err = pthread_attr_getschedparam(attr, &sparm) ;
+ if (err != 0)
+ zabort_err("pthread_attr_getschedparam failed", err) ;
+ sparm.sched_priority = priority ;
+ err = pthread_attr_setschedparam(attr, &sparm) ;
+ if (err != 0)
+ zabort_err("pthread_attr_setschedparam failed", err) ;
+ } ;
+ } ;
+ } ;
+
+ /* Done -- return qpt_thread_attr_t* */
+ return attr ;
+} ;
+
+/* Create Thread with given attributes (if any).
+ *
+ * If no attributes are given (attr == NULL) the thread is created with system
+ * default attributes -- *except* that it is created joinable.
+ *
+ * Returns the qpt_thread_t "thread id".
+ */
+qpt_thread_t
+qpt_thread_create(void* (*start)(void*), void* arg, qpt_thread_attr_t* attr)
+{
+ qpt_thread_attr_t thread_attr ;
+ qpt_thread_t thread_id ;
+ int default_attr ;
+ int err ;
+
+ default_attr = (attr == NULL) ;
+ if (default_attr)
+ attr = qpt_thread_attr_init(&thread_attr, qpt_attr_joinable, 0, 0, 0) ;
+
+ err = pthread_create(&thread_id, attr, start, arg) ;
+ if (err != 0)
+ zabort_err("pthread_create failed", err) ;
+
+ if (default_attr)
+ {
+ err = pthread_attr_destroy(attr) ; /* being tidy */
+ if (err != 0)
+ zabort_err("pthread_attr_destroy failed", err) ;
+ } ;
+
+ return thread_id ;
+} ;
+
+/*==============================================================================
+ * Mutex initialise and destroy.
+ */
+
+/* Initialise Mutex (allocating if required).
+ *
+ * Options:
+ *
+ * qpt_mutex_quagga -- see qpthreads.h for discussion of this.
+ * qpt_mutex_normal -- ie PTHREAD_MUTEX_NORMAL
+ * qpt_mutex_recursive -- ie PTHREAD_MUTEX_RECURSIVE
+ * qpt_mutex_errorcheck -- ie PTHREAD_MUTEX_ERRORCHECK
+ * qpt_mutex_default -- system default
+ *
+ * Of these _recursive is the most likely alternative to _quagga... BUT do
+ * remember that such mutexes DO NOT play well with condition variables.
+ */
+qpt_mutex_t*
+qpt_mutex_init(qpt_mutex_t* mx, enum qpt_mutex_options opts)
+{
+ pthread_mutexattr_t mutex_attr ;
+ int type ;
+ int err ;
+
+ if (mx == NULL)
+ mx = XMALLOC(MTYPE_QPT_MUTEX, sizeof(qpt_mutex_t)) ;
+
+ /* Set up attributes so we can set the mutex type */
+ err = pthread_mutexattr_init(&mutex_attr);
+ if (err != 0)
+ zabort_err("pthread_mutexattr_init failed", err) ;
+
+ switch(opts)
+ {
+ case qpt_mutex_quagga:
+ type = QPT_MUTEX_TYPE ;
+ break ;
+ case qpt_mutex_normal:
+ type = PTHREAD_MUTEX_NORMAL ;
+ break ;
+ case qpt_mutex_recursive:
+ type = PTHREAD_MUTEX_RECURSIVE ;
+ break ;
+ case qpt_mutex_errorcheck:
+ type = PTHREAD_MUTEX_ERRORCHECK ;
+ break ;
+ case qpt_mutex_default:
+ type = PTHREAD_MUTEX_DEFAULT ;
+ break ;
+ default:
+ zabort("Invalid qpt_mutex option") ;
+ } ;
+
+#ifndef PTHREAD_MUTEXATTR_SETTYPE_MISSING
+ err = pthread_mutexattr_settype(&mutex_attr, type);
+ if (err != 0)
+ zabort_err("pthread_mutexattr_settype failed", err) ;
+#endif
+
+ /* Now we're ready to initialize the mutex itself */
+ err = pthread_mutex_init(mx, &mutex_attr) ;
+ if (err != 0)
+ zabort_err("pthread_mutex_init failed", err) ;
+
+ /* Be tidy with the attributes */
+ err = pthread_mutexattr_destroy(&mutex_attr) ;
+ if (err != 0)
+ zabort_err("pthread_mutexattr_destroy failed", err) ;
+
+ /* Done: return the mutex */
+ return mx ;
+} ;
+
+/* Destroy given mutex, and (if required) free it.
+ *
+ * Returns NULL.
+*/
+qpt_mutex_t*
+qpt_mutex_destroy(qpt_mutex_t* mx, int free_mutex)
+{
+ int err ;
+
+ err = pthread_mutex_destroy(mx) ;
+ if (err != 0)
+ zabort_err("pthread_mutex_destroy failed", err) ;
+
+ if (free_mutex)
+ XFREE(MTYPE_QPT_MUTEX, mx) ;
+
+ return NULL ;
+} ;
+
+/*==============================================================================
+ * Condition Variable initialise and destroy.
+ */
+
+/* Initialise Condition Variable (allocating if required).
+ *
+ * Options:
+ *
+ * qpt_cond_quagga -- use Quagga's default clock
+ * qpt_cond_realtime -- force CLOCK_REALTIME
+ * qpt_cond_monotonic -- force CLOCK_MONOTONIC (if available)
+ */
+qpt_cond_t*
+qpt_cond_init(qpt_cond_t* cv, enum qpt_cond_options opts)
+{
+ pthread_condattr_t cond_attr ;
+ int err ;
+
+ if (cv == NULL)
+ cv = XMALLOC(MTYPE_QPT_COND, sizeof(qpt_cond_t)) ;
+
+ /* Set up attributes so we can set the type */
+ err = pthread_condattr_init(&cond_attr);
+ if (err != 0)
+ zabort_err("pthread_condattr_init failed", err) ;
+
+ switch(opts)
+ {
+ case qpt_cond_quagga:
+ break ;
+ default:
+ zabort("Invalid qpt_cond option") ;
+ } ;
+
+ err = pthread_condattr_setclock(&cond_attr, QPT_COND_CLOCK_ID);
+ if (err != 0)
+ zabort_err("pthread_condattr_setclock failed", err) ;
+
+ /* Now we're ready to initialize the condition variable itself */
+ err = pthread_cond_init(cv, &cond_attr) ;
+ if (err != 0)
+ zabort_err("pthread_cond_init failed", err) ;
+
+ /* Be tidy with the attributes */
+ err = pthread_condattr_destroy(&cond_attr) ;
+ if (err != 0)
+ zabort_err("pthread_condattr_destroy failed", err) ;
+
+ /* Done: return the condition variable */
+ return cv ;
+} ;
+
+/* Destroy given mutex, and (if required) free it.
+ *
+ * Returns NULL.
+*/
+qpt_cond_t*
+qpt_cond_destroy(qpt_cond_t* cv, int free_cond)
+{
+ int err ;
+
+ err = pthread_cond_destroy(cv) ;
+ if (err != 0)
+ zabort_err("pthread_cond_destroy failed", err) ;
+
+ if (free_cond)
+ XFREE(MTYPE_QPT_COND, cv) ;
+
+ return NULL ;
+} ;
+
+/* Wait for given condition variable or time-out.
+ *
+ * Returns: wait succeeded (1 => success, 0 => timed-out).
+ *
+ * NB: timeout time is a qtime_mono_t (monotonic time).
+ *
+ * Has to check the return value, so zabort_errno if not EBUSY.
+ */
+
+int
+qpt_cond_timedwait(qpt_cond_t* cv, qpt_mutex_t* mx, qtime_mono_t timeout_time)
+{
+ struct timespec ts ;
+
+ if (QPT_COND_CLOCK_ID != CLOCK_MONOTONIC)
+ {
+ timeout_time = qt_clock_gettime(QPT_COND_CLOCK_ID)
+ + (timeout_time - qt_get_monotonic()) ;
+ } ;
+
+ int err = pthread_cond_timedwait(cv, mx, qtime2timespec(&ts, timeout_time)) ;
+ if (err == 0)
+ return 1 ; /* got condition */
+ if (err == ETIMEDOUT)
+ return 0 ; /* got time-out */
+
+ zabort_err("pthread_cond_timedwait failed", err) ;
+ /* crunch */
+} ;
+
+/*==============================================================================
+ * Signal Handling.
+ */
+
+/* Set thread signal mask
+ *
+ * Thin wrapper around pthread_sigmask.
+ *
+ * zaborts if gets any error.
+ */
+void
+qpt_thread_sigmask(int how, const sigset_t* set, sigset_t* oset)
+{
+ int err ;
+
+ if (oset != NULL)
+ sigemptyset(oset) ; /* to make absolutely sure */
+
+ err = pthread_sigmask(how, set, oset) ;
+ if (err != 0)
+ zabort_err("pthread_sigmask failed", err) ;
+} ;
+
+/* Send given thread the given signal
+ *
+ * Thin wrapper around pthread_kill.
+ *
+ * zaborts if gets any error.
+ */
+void
+qpt_thread_signal(qpt_thread_t thread, int signum)
+{
+ int err ;
+
+ err = pthread_kill(thread, signum) ;
+ if (err != 0)
+ zabort_err("pthread_kill failed", err) ;
+} ;
diff --git a/lib/qpthreads.h b/lib/qpthreads.h
new file mode 100644
index 00000000..5a442cc7
--- /dev/null
+++ b/lib/qpthreads.h
@@ -0,0 +1,363 @@
+/* Quagga Pthreads support -- header
+ * Copyright (C) 2009 Chris Hall (GMCH), Highwayman
+ *
+ * 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 _ZEBRA_QPTHREADS_H
+#define _ZEBRA_QPTHREADS_H
+
+#include <stdint.h>
+#include <time.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "zassert.h"
+#include "qtime.h"
+
+#ifndef Inline
+#define Inline static inline
+#endif
+
+/*==============================================================================
+ * Quagga Pthread Interface -- qpt_xxxx
+ *
+ * Here are captured all the pthreads features used in Quagga.
+ *
+ * This provides:
+ *
+ * * "wrappers" around functions which should not fail, but whose return
+ * code it is best to check... at least in a debug environment.
+ *
+ * * the possibility of a separate no pthreads build where pthread facilities
+ * are either dummied out or otherwise dealt with.
+ *
+ * * the ability to add any work-arounds which may be required if poorly
+ * conforming pthreads implementations are encountered
+ */
+
+#if !defined(_POSIX_THREADS) || (_POSIX_THREADS <= 0)
+#error Require _POSIX_THREADS
+#endif
+
+/*==============================================================================
+ * Data types
+ */
+
+typedef pthread_t qpt_thread_t ;
+typedef pthread_mutex_t qpt_mutex_t ;
+typedef pthread_cond_t qpt_cond_t ;
+
+typedef pthread_attr_t qpt_thread_attr_t ;
+
+/*==============================================================================
+ * Thread Creation -- see qpthreads.c for further discussion.
+ */
+
+enum qpt_attr_options
+{
+ qpt_attr_joinable = 0, /* the default for Quagga */
+
+ qpt_attr_detached = 0x0001, /* otherwise will set joinable */
+
+ qpt_attr_sched_inherit = 0x0002, /* otherwise will use default */
+
+ qpt_attr_sched_scope = 0x0004, /* otherwise inherit/default */
+ qpt_attr_sched_policy = 0x0008, /* otherwise inherit/default */
+ qpt_attr_sched_priority = 0x0010, /* otherwise inherit/default */
+} ;
+
+#define qpt_attr_sched_explicit ( qpt_attr_sched_scope \
+ | qpt_attr_sched_policy \
+ | qpt_attr_sched_priority )
+
+#define qpt_attr_sched_setting ( qpt_attr_sched_inherit \
+ | qpt_attr_sched_explicit )
+
+#define qpt_attr_known ( qpt_attr_detached | qpt_attr_sched_setting )
+
+extern qpt_thread_attr_t*
+qpt_thread_attr_init(qpt_thread_attr_t* attr, enum qpt_attr_options opts,
+ int scope, int policy, int priority) ;
+extern qpt_thread_t
+qpt_thread_create(void* (*start)(void*), void* arg, qpt_thread_attr_t* attr) ;
+
+/*==============================================================================
+ * Thread self knowledge.
+ */
+
+Inline qpt_thread_t qpt_thread_self(void)
+{
+ return pthread_self() ;
+} ;
+
+/*==============================================================================
+ * Mutex handling.
+ *
+ * Quagga's default mutex type is:
+ *
+ * * PTHREAD_MUTEX_ERRORCHECK unless NDEBUG && NDEBUG_QPTHREADS
+ * * QPT_MUTEX_TYPE_DEFAULT
+ *
+ * QPT_MUTEX_TYPE_DEFAULT may be set elsewhere. If it is not set then it is
+ * set here to be PTHREAD_MUTEX_NORMAL.
+ *
+ * NB: on the face of it PTHREAD_MUTEX_NORMAL should be the fastest. It is
+ * possible that PTHREAD_MUTEX_DEFAULT may have system specific semantics
+ * that make it faster than the standard _NORMAL. It is also possible that
+ * a given system may elect to provide a safer mutex than the _NORMAL by
+ * default.
+ *
+ * If _DEFAULT is faster than _NORMAL, then QPT_MUTEX_TYPE_DEFAULT may be
+ * used to override this choice.
+ *
+ * NB: do not (currently) support pthread_mutex_timedlock().
+ */
+
+enum qpt_mutex_options
+{
+ qpt_mutex_quagga = 0x0000, /* Quagga's default */
+ qpt_mutex_normal = 0x0001,
+ qpt_mutex_recursive = 0x0002,
+ qpt_mutex_errorcheck = 0x0003,
+ qpt_mutex_default = 0x0004, /* system default */
+} ;
+
+#ifndef QPT_MUTEX_TYPE_DEFAULT
+# define QPT_MUTEX_TYPE_DEFAULT PTHREAD_MUTEX_NORMAL
+#endif
+
+#if defined(NDEBUG) && defined(NDEBUG_QPTHREADS)
+# define QPT_MUTEX_TYPE QPT_MUTEX_TYPE_DEFAULT
+#else
+# define QPT_MUTEX_TYPE PTHREAD_MUTEX_ERRORCHECK
+#endif
+
+extern qpt_mutex_t*
+qpt_mutex_init(qpt_mutex_t* mx, enum qpt_mutex_options opts) ;
+
+extern qpt_mutex_t*
+qpt_mutex_destroy(qpt_mutex_t* mx, int free_mutex) ;
+
+#define qpt_mutex_destroy_keep(mx) qpt_mutex_destroy(mx, 0)
+#define qpt_mutex_destroy_free(mx) qpt_mutex_destroy(mx, 1)
+
+Inline void
+qpt_mutex_lock(qpt_mutex_t* mx) ; /* do nothing if mx == NULL */
+
+Inline int
+qpt_mutex_trylock(qpt_mutex_t* mx) ; /* do nothing if mx == NULL */
+
+Inline void
+qpt_mutex_unlock(qpt_mutex_t* mx) ; /* do nothing if mx == NULL */
+
+/*==============================================================================
+ * Condition Variable handling
+ *
+ * Quagga's clock for condition variables is QPT_COND_CLOCK_ID, which
+ * may be set elsewhere. If it is not set then it is set here to be:
+ *
+ * * CLOCK_MONOTONIC if available
+ * * CLOCK_REALTIME otherwise -- this is the standard default.
+ *
+ * QPT_COND_CLOCK_MONOTONIC is set if CLOCK_MONOTONIC is used (and must be set
+ * if QPT_COND_CLOCK_ID is set elsewhere to something that is monotonic).
+ *
+ * NB: the time-out time passed to qpt_cond_timedwait() is a qtime_mono_t
+ * time (so based on qtime's monotonic time, which is CLOCK_MONOTONIC if
+ * that is available.
+ *
+ * Otherwise, there is a conversion step from qtime_mono_t to whatever the
+ * timebase for the condition variable is.
+ *
+ * NB: static initialisation of condition variables is not supported, to avoid
+ * confusion between the standard default and Quagga's default.
+ */
+
+#ifndef QPT_COND_CLOCK_ID
+# ifdef HAVE_CLOCK_MONOTONIC
+# define QPT_COND_CLOCK_ID CLOCK_MONOTONIC
+# define QPT_COND_CLOCK_MONOTONIC 1
+# else
+# define QPT_COND_CLOCK_ID CLOCK_REALTIME
+# undef QPT_COND_CLOCK_MONOTONIC
+# endif
+#endif
+
+enum qpt_cond_options
+{
+ qpt_cond_quagga = 0x0000, /* Quagga's default */
+} ;
+
+extern qpt_cond_t*
+qpt_cond_init(qpt_cond_t* cv, enum qpt_cond_options opts) ;
+
+extern qpt_cond_t*
+qpt_cond_destroy(qpt_cond_t* cv, int free_cond) ;
+
+#define qpt_cond_destroy_keep(cv) qpt_cond_destroy(cv, 0)
+#define qpt_cond_destroy_free(cv) qpt_cond_destroy(cv, 1)
+
+Inline void
+qpt_cond_wait(qpt_cond_t* cv, qpt_mutex_t* mx) ;
+
+extern int
+qpt_cond_timedwait(qpt_cond_t* cv, qpt_mutex_t* mx, qtime_mono_t timeout_time) ;
+
+Inline void
+qpt_cond_signal(qpt_cond_t* cv) ;
+
+Inline void
+qpt_cond_broadcast(qpt_cond_t* cv) ;
+
+/*==============================================================================
+ * Mutex inline functions
+ */
+
+/* Lock given mutex.
+ *
+ * Unless both NCHECK_QPTHREADS and NDEBUG are defined, checks that the
+ * return value is valid -- zabort_errno if it isn't.
+ */
+
+Inline void
+qpt_mutex_lock(qpt_mutex_t* mx) /* do nothing if mx == NULL */
+{
+ if (mx != NULL)
+ {
+#if defined(NDEBUG) && defined(NDEBUG_QPTHREADS)
+ pthread_mutex_lock(mx) ;
+#else
+ int err = pthread_mutex_lock(mx) ;
+ if (err != 0)
+ zabort_err("pthread_mutex_lock failed", err) ;
+#endif
+ } ;
+} ;
+
+/* Try to lock given mutex.
+ *
+ * Returns: lock succeeded (1 => have locked, 0 => unable to lock).
+ *
+ * Has to check the return value, so zabort_errno if not EBUSY.
+ */
+
+Inline int
+qpt_mutex_trylock(qpt_mutex_t* mx) /* do nothing if mx == NULL */
+{
+ if (mx != NULL)
+ {
+ int err = pthread_mutex_trylock(mx) ;
+ if (err == 0)
+ return 1 ; /* success: it's locked. */
+ if (err == EBUSY)
+ return 0 ; /* unable to lock */
+
+ zabort_err("pthread_mutex_trylock failed", err) ;
+ /* crunch */
+ } ;
+} ;
+
+/* Unlock given mutex.
+ *
+ * Unless both NCHECK_QPTHREADS and NDEBUG are defined, checks that the
+ * return value is valid -- zabort_errno if it isn't.
+ */
+Inline void
+qpt_mutex_unlock(qpt_mutex_t* mx) /* do nothing if mx == NULL */
+{
+ if (mx != NULL)
+ {
+#if defined(NDEBUG) && defined(NDEBUG_QPTHREADS)
+ pthread_mutex_unlock(mx) ;
+#else
+ int err = pthread_mutex_unlock(mx) ;
+ if (err != 0)
+ zabort_err("pthread_mutex_unlock failed", err) ;
+#endif
+ } ;
+} ;
+
+/*==============================================================================
+ * Condition variable inline functions
+ */
+
+/* Wait for given condition variable.
+ *
+ * Unless both NCHECK_QPTHREADS and NDEBUG are defined, checks that the
+ * return value is valid -- zabort_errno if it isn't.
+ */
+
+Inline void
+qpt_cond_wait(qpt_cond_t* cv, qpt_mutex_t* mx)
+{
+#if defined(NDEBUG) && defined(NDEBUG_QPTHREADS)
+ pthread_cond_wait(cv, mx) ;
+#else
+ int err = pthread_cond_wait(cv, mx) ;
+ if (err != 0)
+ zabort_err("pthread_cond_wait failed", err) ;
+#endif
+} ;
+
+/* Signal given condition.
+ *
+ * Unless both NCHECK_QPTHREADS and NDEBUG are defined, checks that the
+ * return value is valid -- zabort_errno if it isn't.
+ */
+
+Inline void
+qpt_cond_signal(qpt_cond_t* cv)
+{
+#if defined(NDEBUG) && defined(NDEBUG_QPTHREADS)
+ pthread_cond_signal(cv) ;
+#else
+ int err = pthread_cond_signal(cv) ;
+ if (err != 0)
+ zabort_err("pthread_cond_signal failed", err) ;
+#endif
+} ;
+
+/* Broadcast given condition.
+ *
+ * Unless both NCHECK_QPTHREADS and NDEBUG are defined, checks that the
+ * return value is valid -- zabort_errno if it isn't.
+ */
+Inline void
+qpt_cond_broadcast(qpt_cond_t* cv)
+{
+#if defined(NDEBUG) && defined(NDEBUG_QPTHREADS)
+ pthread_cond_broadcast(cv) ;
+#else
+ int err = pthread_cond_broadcast(cv) ;
+ if (err != 0)
+ zabort_err("pthread_cond_broadcast failed", err) ;
+#endif
+} ;
+
+/*==============================================================================
+ * Signal Handling.
+ */
+void
+qpt_thread_sigmask(int how, const sigset_t* set, sigset_t* oset) ;
+
+void
+qpt_thread_signal(qpt_thread_t thread, int signum) ;
+
+#endif /* _ZEBRA_QPTHREADS_H */
diff --git a/lib/qtime.c b/lib/qtime.c
new file mode 100644
index 00000000..3ec34a72
--- /dev/null
+++ b/lib/qtime.c
@@ -0,0 +1,194 @@
+/* Quagga realtime and monotonic clock handling -- functions
+ * Copyright (C) 2009 Chris Hall (GMCH), Highwayman
+ *
+ * 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.
+ */
+
+#include <sys/times.h>
+#include <errno.h>
+
+#include "zassert.h"
+#include "qtime.h"
+
+/*==============================================================================
+ * This is a collection of functions and (in qtime.h) macros and inline
+ * functions which support system time and a monotonic clock.
+ *
+ * TODO: introduce mutex for crafted monotonic time, and initialisation
+ * routine for that: which can preset the various variables... but
+ * unless is guaranteed to be called, must leave the on-the-fly
+ * initialisation... could also start a watchdog at that point.
+ */
+
+/*==============================================================================
+ * Replacement for CLOCK_MONOTONIC.
+ *
+ * With thanks to Joakim Tjernlund for reminding everyone of the return value
+ * from times() !
+ *
+ * times() is defined to return a value which is the time since some fixed time
+ * before the application started (or when the application started). This time
+ * is measured in units of sysconf(_SC_CLK_TCK) ticks per second.
+ *
+ * The only tricky bit is that the value returned (of type clock_t) is a
+ * signed integer, which can overflow. It is not defined exactly how it
+ * does this... This code assumes that the system will wrap around in some
+ * obvious way. The base of the time for this clock may be when the *system*
+ * started... so when it overflows may depend on how long the system has been
+ * up... which suggests that some sensible wrap around is likely (?).
+ *
+ * The qtime_t value is in nano-seconds.
+ *
+ * The result from times() is in units of sysconf(_SC_CLK_TCK) ticks per second.
+ *
+ * If clock_t is a signed 32-bit integer, which is kept +ve, then the clock
+ * overflows/wraps round in 2^31 ticks which is:
+ *
+ * at 100 ticks/sec: > 248 days
+ * at 1,000 ticks/sec: > 24 days
+ * at 10,000 ticks/sec: > 59 hours
+ *
+ * For safety, this asserts that sysconf(_SC_CLK_TCK) <= 1,000,000 for
+ * sizeof(clock_t) > 4, but <= 1,000 for sizeof(clock_t) == 4.
+ *
+ * (It appears that 60, 100, 250 and 1,000 ticks/sec. are popular options.)
+ *
+ * If sizeof(clock_t) > 4, it is assumed large enough never to wrap around.
+ *
+ * When clock_t is a 32-bit integer must be at least ready for wrap around.
+ * There are two cases:
+ *
+ * * +ve wrap around. new < old value, and new >= 0
+ *
+ * step = (INT32_MAX - old + 1) + new
+ *
+ * * -ve wrap around. new < old value, and new < 0 (and old > 0)
+ *
+ * step = (INT32_MAX - old + 1) - (INT32_MIN - new)
+ *
+ * In any event, a step > 24 hours is taken to means that something has gone
+ * very, very badly wrong.
+ *
+ * NB: it is assumed that qt_craft_monotonic will be called often enough to
+ * ensure that the check on the step size will not be triggered !
+ *
+ * NB: it is assumed that times() does not simply stick if it overflows.
+ *
+ * TODO: Add a watchdog to monitor the behaviour of this clock ?
+ */
+
+CONFIRM((sizeof(clock_t) >= 4) && (sizeof(clock_t) <= 8)) ;
+
+#ifdef GNU_LINUX
+#define TIMES_TAKES_NULL 1
+#else
+#undef TIMES_TAKES_NULL
+#endif
+
+static uint64_t monotonic = 0 ; /* monotonic clock in _SC_CLK_TCK's */
+static int64_t last_times_sample = 0 ; /* last value returned by times() */
+
+static uint64_t step_limit = 0 ; /* for sanity check */
+
+static int64_t times_clk_tcks = 0 ; /* sysconf(_SC_CLK_TCK) */
+static qtime_t times_scale_q = 0 ; /* 10**9 / times_clk_tcks */
+static qtime_t times_scale_r = 0 ; /* 10**9 % times_clk_tcks */
+
+qtime_mono_t
+qt_craft_monotonic(void) {
+ struct tms dummy ;
+ int64_t this_times_sample ;
+ uint64_t step ;
+
+ /* Set up times_scale_q & times_scale_q if not yet done. */
+ if (times_clk_tcks == 0) /* Is zero until it's initialized */
+ {
+ lldiv_t qr ;
+ confirm(sizeof(qtime_t) <= sizeof(long long int)) ;
+
+ times_clk_tcks = sysconf(_SC_CLK_TCK) ;
+ passert((times_clk_tcks > 0) &&
+ (times_clk_tcks <= (sizeof(clock_t) > 4) ? 1000000
+ : 1000)) ;
+
+ qr = lldiv(QTIME_SECOND, times_clk_tcks) ;
+ times_scale_q = qr.quot ;
+ times_scale_r = qr.rem ;
+
+ step_limit = (uint64_t)24 * 60 * 60 * times_clk_tcks ;
+ } ;
+
+ /* No errors are defined for times(), but a return of -1 is defined */
+ /* to indicate an error condition, with errno saying what it is ! */
+ /* */
+ /* The following deals carefully with this -- cannot afford for the */
+ /* clock either to jump or to get stuck ! */
+
+#ifdef TIMES_TAKES_NULL
+ this_times_sample = times(NULL) ; /* assume this saves effort ! */
+#else
+ this_times_sample = times(&dummy) ;
+#endif
+
+ if (this_times_sample == -1) /* deal with theoretical error */
+ {
+ errno = 0 ;
+ this_times_sample = times(&dummy) ;
+ if (errno != 0)
+ zabort_errno("times() failed") ;
+ } ;
+
+ /* Calculate the step and verify sensible. */
+ /* */
+ /* Watch out for huge jumps and/or time going backwards. */
+ /* For 32-bit clock_t, look out for wrap-around. */
+
+ if ((sizeof(clock_t) > 4) || (this_times_sample > last_times_sample))
+ /* time going backwards will appear as HUGE step forwards. */
+ step = (uint64_t)(this_times_sample - last_times_sample) ;
+ else
+ {
+ if (this_times_sample > 0)
+ /* both samples +ve => +ve wrap around. */
+ step = (uint64_t)( ((int64_t)INT32_MAX - last_times_sample + 1)
+ + this_times_sample ) ;
+ else
+ /* this sample -ve and last sample +ve => -ve wrap round */
+ /* this sample -ve and last sample -ve => time gone backwards */
+ /* (which appears as a HUGE step forwards). */
+ step = (uint64_t)( ((int64_t)INT32_MAX - last_times_sample + 1)
+ - ((int64_t)INT32_MIN - this_times_sample) ) ;
+ } ;
+
+ /* TODO: better error messaging for large clock jumps. */
+ if (step > step_limit)
+ zabort("Sudden large monotonic clock jump") ;
+
+ /* Advance the monotonic clock in sysconf(_SC_CLK_TCK) units. */
+ monotonic += step ;
+
+ /* Remember what we got, for next time. */
+ last_times_sample = this_times_sample ;
+
+ /* Scale to qtime_t units. */
+ if (times_scale_r == 0)
+ return monotonic * times_scale_q ;
+ else
+ return (monotonic * times_scale_q) +
+ ((monotonic * times_scale_r) / times_clk_tcks) ;
+} ;
diff --git a/lib/qtime.h b/lib/qtime.h
new file mode 100644
index 00000000..35e1a51b
--- /dev/null
+++ b/lib/qtime.h
@@ -0,0 +1,307 @@
+/* Quagga realtime and monotonic clock handling -- header
+ * Copyright (C) 2009 Chris Hall (GMCH), Highwayman
+ *
+ * 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 _ZEBRA_QTIME_H
+#define _ZEBRA_QTIME_H
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <time.h>
+#include <sys/time.h>
+#include <unistd.h>
+
+#include "zassert.h"
+#include "config.h"
+
+#ifndef Inline
+#define Inline static inline
+#endif
+
+/*==============================================================================
+ * qtime_t -- signed 64-bit integer.
+ *
+ * The various time functions work in terms of the structures:
+ *
+ * timespec -- tv_secs seconds
+ * tv_nsecs nano-seconds
+ *
+ * timeval -- tv_secs seconds
+ * tv_usecs micro-seconds
+ *
+ * Given a 64-bit integer it is much easier to do operations on a 64 bit
+ * (signed) nano-second value. That gives > 34 bits for the seconds count,
+ * and counts from zero to > 290 years.
+ */
+
+typedef int64_t qtime_t ;
+
+typedef qtime_t qtime_real_t ; /* qtime_t value, realtime time-base */
+typedef qtime_t qtime_mono_t ; /* qtime_t value, monotonic time-base */
+
+typedef qtime_t qtime_tod_t ; /* qtime_t value, timeofday time-base... */
+ /* ...just in case != CLOCK_REALTIME ! */
+
+/* A qtime_t second 123456789 -- nano-seconds */
+#define QTIME_SECOND 1000000000
+#define TIMESPEC_SECOND 1000000000
+#define TIMEVAL_SECOND 1000000
+
+/* Macro to convert time in seconds to a qtime_t */
+/* Note that the time to convert may be a float. */
+#define QTIME(s) ((qtime_t)((s) * (qtime_t)QTIME_SECOND))
+
+Inline qtime_t
+timespec2qtime(struct timespec* p_ts) ;
+
+Inline qtime_t
+timeval2qtime(struct timeval* p_tv) ;
+
+Inline struct timespec*
+qtime2timespec(struct timespec* p_ts, qtime_t qt) ;
+
+Inline struct timeval*
+qtime2timeval(struct timeval* p_tv, qtime_t qt) ;
+
+/*==============================================================================
+ * Clocks.
+ *
+ * Here is support for:
+ *
+ * * System Clock
+ *
+ * This can be read using either clock_gettime(CLOCK_REALTIME, &ts) or
+ * gettimeofday(&tv, NULL) -- which (are believed to) return the same clock,
+ * but in different units.
+ *
+ * * Monotonic Clock
+ *
+ * Using clock_gettime(CLOCK_MONOTONIC, &ts) if it is available, otherwise
+ * a manufactured equivalent using times() -- see qt_craft_monotonic().
+ */
+
+Inline qtime_real_t
+qt_get_realtime(void) ; /* clock_gettime(CLOCK_REALTIME, ...) */
+
+Inline qtime_mono_t
+qt_add_realtime(qtime_t interval) ; /* qt_get_realtime() + interval */
+
+Inline qtime_mono_t
+qt_get_monotonic(void) ; /* clock_gettime(CLOCK_MONOTONIC, ...) */
+ /* OR equivalent using times() */
+Inline qtime_mono_t
+qt_add_monotonic(qtime_t interval) ; /* qt_get_monotonic() + interval */
+
+Inline qtime_mono_t /* monotonic time from CLOCK_REALTIME */
+qt_realtime2monotonic(qtime_real_t realtime) ;
+Inline qtime_real_t /* CLOCK_REALTIME from monotonic time */
+qt_monotonic2realtime(qtime_mono_t monotonic) ;
+
+/* Function to manufacture a monotonic clock. */
+extern qtime_mono_t
+qt_craft_monotonic(void) ;
+
+/* These are provided just in case gettimeofday() != CLOCK_REALTIME */
+Inline qtime_tod_t
+qt_get_timeofday(void) ; /* gettimeofday(&tv, NULL) */
+
+Inline qtime_tod_t
+qt_add_timeofday(qtime_t interval) ; /* qt_get_timeofday() + interval */
+
+Inline qtime_mono_t /* monotonic time from timeofday */
+qt_timeofday2monotonic(qtime_tod_t timeofday) ;
+Inline qtime_tod_t /* timeofday from monotonic time */
+qt_monotonic2timeofday(qtime_mono_t monotonic) ;
+
+/*==============================================================================
+ * Inline conversion functions
+ */
+
+/* Convert timespec to qtime_t
+ *
+ * Returns qtime_t value.
+ */
+Inline qtime_t
+timespec2qtime(struct timespec* p_ts)
+{
+ return QTIME(p_ts->tv_sec) + p_ts->tv_nsec ;
+ confirm(QTIME_SECOND == TIMESPEC_SECOND) ;
+} ;
+
+/* Convert timeval to qtime_t
+ *
+ * Returns qtime_t value.
+ */
+Inline qtime_t
+timeval2qtime(struct timeval* p_tv)
+{
+ return QTIME(p_tv->tv_sec) + (p_tv->tv_usec * 1000) ;
+ confirm(QTIME_SECOND == TIMEVAL_SECOND * 1000) ;
+} ;
+
+/* Convert qtime_t to timespec
+ *
+ * Takes address of struct timespec and returns that address.
+ */
+Inline struct timespec*
+qtime2timespec(struct timespec* p_ts, qtime_t qt)
+{
+ lldiv_t imd = lldiv(qt, QTIME_SECOND) ;
+ confirm(sizeof(long long) >= sizeof(qtime_t)) ;
+
+ p_ts->tv_sec = imd.quot ;
+ p_ts->tv_nsec = imd.rem ;
+ confirm(TIMESPEC_SECOND == QTIME_SECOND) ;
+
+ return p_ts ;
+} ;
+
+/* Convert timespec to qtime_t
+ *
+ * Takes address of struct timespec and returns that address.
+ */
+Inline struct timeval*
+qtime2timeval(struct timeval* p_tv, qtime_t qt)
+{
+ lldiv_t imd = lldiv(qt, QTIME_SECOND) ;
+ confirm(sizeof(long long) >= sizeof(qtime_t)) ;
+
+ p_tv->tv_sec = imd.quot ;
+ p_tv->tv_usec = imd.rem / 1000 ;
+ confirm(TIMEVAL_SECOND * 1000 == QTIME_SECOND) ;
+
+ return p_tv ;
+} ;
+
+/*==============================================================================
+ * Inline Clock Functions.
+ */
+
+/* Read given clock & return a qtime_t value.
+ *
+ * While possibility of error is essentially theoretical, must treat it as a
+ * FATAL error -- cannot continue with broken time value !
+ */
+
+Inline qtime_t
+qt_clock_gettime(clockid_t clock_id)
+{
+ struct timespec ts ;
+
+ if (clock_gettime(clock_id, &ts) != 0)
+ zabort_errno("clock_gettime failed") ;
+
+ return timespec2qtime(&ts) ;
+} ;
+
+/* clock_gettime(CLOCK_REALTIME, ...) -- returning qtime_t value
+ *
+ * While possibility of error is essentially theoretical, must treat it as a
+ * FATAL error -- cannot continue with broken time value !
+ */
+Inline qtime_real_t
+qt_get_realtime(void)
+{
+ return qt_clock_gettime(CLOCK_REALTIME) ;
+} ;
+
+/* qt_get_realtime() + interval
+ */
+Inline qtime_real_t
+qt_add_realtime(qtime_t interval)
+{
+ return qt_get_realtime() + interval;
+} ;
+
+/* clock_gettime(CLOCK_MONOTONIC, ...) OR qt_craft_monotonic()
+ * -- returning qtime_t value
+ *
+ * While possibility of error is essentially theoretical, must treat it as a
+ * FATAL error -- cannot continue with broken time value !
+ */
+Inline qtime_mono_t
+qt_get_monotonic(void)
+{
+#ifdef HAVE_CLOCK_MONOTONIC
+ return qt_clock_gettime(CLOCK_MONOTONIC) ;
+#else
+ return qt_craft_monotonic() ;
+#endif
+} ;
+
+/* qt_get_monotonic() + interval
+ */
+Inline qtime_mono_t
+qt_add_monotonic(qtime_t interval)
+{
+ return qt_get_monotonic() + interval;
+} ;
+
+/* gettimeofday(&tv, NULL) -- returning qtime_t value
+ */
+Inline qtime_tod_t
+qt_get_timeofday(void)
+{
+ struct timeval tv ;
+ gettimeofday(&tv, NULL) ;
+ return timeval2qtime(&tv) ;
+}
+
+/* qt_get_timeofday() + interval
+ */
+Inline qtime_tod_t
+qt_add_timeofday(qtime_t interval)
+{
+ return qt_get_timeofday() + interval;
+} ;
+
+/*==============================================================================
+ * Conversion between realtime/timeofday and monotonic
+ */
+
+/* Convert a CLOCK_REALTIME time to our local monotonic time. */
+Inline qtime_mono_t
+qt_realtime2monotonic(qtime_real_t realtime)
+{
+ return qt_get_monotonic() + (realtime - qt_get_realtime()) ;
+} ;
+
+/* Convert a local monotonic time to CLOCK_REALTIME time. */
+Inline qtime_real_t
+qt_monotonic2realtime(qtime_mono_t monotonic)
+{
+ return qt_get_realtime() + (monotonic - qt_get_monotonic()) ;
+} ;
+
+/* Convert a gettimeofday() time to our local monotonic time. */
+Inline qtime_mono_t
+qt_timeofday2monotonic(qtime_tod_t timeofday)
+{
+ return qt_get_monotonic() + (timeofday - qt_get_timeofday()) ;
+} ;
+
+/* Convert a local monotonic time to gettimeofday() time. */
+Inline qtime_tod_t
+qt_monotonic2timeofday(qtime_mono_t monotonic)
+{
+ return qt_get_timeofday() + (monotonic - qt_get_monotonic()) ;
+} ;
+
+#endif /* _ZEBRA_QTIME_H */
diff --git a/lib/qtimers.c b/lib/qtimers.c
new file mode 100644
index 00000000..d4aff6ec
--- /dev/null
+++ b/lib/qtimers.c
@@ -0,0 +1,336 @@
+/* Quagga timers support -- functions
+ * Copyright (C) 2009 Chris Hall (GMCH), Highwayman
+ *
+ * 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.
+ */
+
+#include <stddef.h>
+#include <string.h>
+
+#include "zassert.h"
+#include "qtimers.h"
+#include "memory.h"
+#include "heap.h"
+
+/*==============================================================================
+ * Quagga Timers -- qtimer_xxxx
+ *
+ * Here and in qtimers.h is a data structure for managing multiple timers
+ * each with an action to be executed when the timer expires.
+ *
+ * The qtime_pile structure manages a "pile" of qtimer structures which are
+ * waiting for the right time to go off.
+ *
+ * NB: it is ASSUMED that a qtime_pile will be private to the thread in which
+ * it is created and used.
+ *
+ * There is NO mutex handling here.
+ *
+ * Timers are triggered by calling qtimer_dispatch_next(). This is given the
+ * current qtimer time (see below), and it dispatches the first timer whose
+ * time has come (or been passed). Dispatching a timer means calling its
+ * action function (see below). Each call of qtimer_dispatch_next() triggers
+ * at most one timer.
+ *
+ * Time Base
+ * ---------
+ *
+ * The time base for qtimers is the monotonic time provided in qtime.c/.h.
+ *
+ * Action Functions
+ * ----------------
+ *
+ * There is a separate action function for each timer.
+ *
+ * When the action function is called it is passed the qtimer structure, the
+ * timer_info pointer from that structure and the time which triggered the
+ * timer (which may, or may not, be the current qtimer time).
+ *
+ * During an action function timers may be set/unset, actions changed, and so
+ * on... there are no restrictions EXCEPT that the qtimer structure may NOT be
+ * freed.
+ */
+
+static int
+qtimer_cmp(qtimer* a, qtimer* b) /* the heap discipline */
+{
+ if ((**a).time < (**b).time)
+ return -1 ;
+ if ((**a).time > (**b).time)
+ return +1 ;
+ return 0 ;
+} ;
+
+/*==============================================================================
+ * qtimer_pile handling
+ */
+
+/* Initialise a timer pile -- allocating it if required.
+ *
+ * Returns the qtimer_pile.
+ */
+qtimer_pile
+qtimer_pile_init_new(qtimer_pile qtp)
+{
+ if (qtp == NULL)
+ qtp = XCALLOC(MTYPE_QTIMER_PILE, sizeof(struct qtimer_pile)) ;
+ else
+ memset(qtp, 0, sizeof(struct qtimer_pile)) ;
+
+ /* Zeroising has initialised:
+ *
+ * timers -- invalid heap -- need to properly initialise
+ *
+ * unset_pending -- NULL -- nothing pending
+ */
+
+ /* Eclipse flags offsetof(struct qtimer, backlink) as a syntax error :-( */
+ typedef struct qtimer qtimer_t ;
+
+ heap_init_new_backlinked(&qtp->timers, 0, (heap_cmp*)qtimer_cmp,
+ offsetof(qtimer_t, backlink)) ;
+ return qtp ;
+} ;
+
+/* Get the timer time for the first timer due to go off in the given pile.
+ *
+ * The caller must provide a maximum acceptable time. If the qtimer pile is
+ * empty, or the top entry times out after the maximum time, then the maximum
+ * is returned.
+ */
+qtime_mono_t
+qtimer_pile_top_time(qtimer_pile qtp, qtime_mono_t max_time)
+{
+ qtimer qtr = heap_top_item(&qtp->timers) ;
+
+ if ((qtr == NULL) || (qtr->time >= max_time))
+ return max_time ;
+ else
+ return qtr->time ;
+} ;
+
+/* Dispatch the next timer whose time is <= the given "upto" time.
+ *
+ * The upto time must be a qtimer time (!) -- see qtimer_time_now().
+ *
+ * The upto argument allows the caller to get a qtimer_time_now() value, and
+ * then process all timers upto that time.
+ *
+ * Returns true <=> dispatched a timer, and there may be more to do.
+ * false <=> nothing to do (and nothing done).
+ */
+int
+qtimer_pile_dispatch_next(qtimer_pile qtp, qtime_mono_t upto)
+{
+ qtimer qtr ;
+
+ qtr = heap_top_item(&qtp->timers) ;
+ if ((qtr != NULL) && (qtr->time <= upto))
+ {
+ qtr->state = qtr_state_unset_pending ;
+
+ qtr->action(qtr, qtr->timer_info, upto) ;
+
+ if (qtr->state == qtr_state_unset_pending)
+ qtimer_unset(qtr) ;
+
+ return 1 ;
+ }
+ else
+ return 0 ;
+} ;
+
+/* Ream out (another) item from qtimer_pile.
+ *
+ * If pile is empty, release the qtimer_pile structure, if required.
+ *
+ * See: #define qtimer_pile_ream_free(qtp)
+ * #define qtimer_pile_ream_keep(qtp)
+ *
+ * Useful for emptying out and discarding a pile of timers:
+ *
+ * while ((p_qtr = qtimer_pile_ream_free(qtp)))
+ * ... do what's required to release the item p_qtr
+ *
+ * Returns NULL when timer pile is empty (and has been released, if required).
+ *
+ * If the timer pile is not released, it may be reused without reinitialisation.
+ *
+ * NB: once reaming has started, the timer pile MUST NOT be used for anything,
+ * and the process MUST be run to completion.
+ */
+qtimer
+qtimer_pile_ream(qtimer_pile qtp, int free_structure)
+{
+ qtimer qtr ;
+
+ qtr = heap_ream_keep(&qtp->timers) ; /* ream, keeping the heap structure */
+ if (qtr != NULL)
+ qtr->state = qtr_state_inactive ; /* has been removed from pile */
+ else
+ if (free_structure) /* pile is empty, may now free it */
+ XFREE(MTYPE_QTIMER_PILE, qtp) ;
+
+ return qtr ;
+} ;
+
+/*==============================================================================
+ * qtimer handling
+ */
+
+/* Initialise qtimer structure -- allocating one if required.
+ *
+ * Associates qtimer with the given pile of timers, and sets up the action and
+ * the timer_info.
+ *
+ * Once initialised, the timer may be set.
+ *
+ * Returns the qtimer.
+ */
+qtimer
+qtimer_init_new(qtimer qtr, qtimer_pile qtp,
+ qtimer_action* action, void* timer_info)
+{
+ if (qtr == NULL)
+ qtr = XCALLOC(MTYPE_QTIMER, sizeof(struct qtimer)) ;
+ else
+ memset(qtr, 0, sizeof(struct qtimer)) ;
+
+ /* Zeroising has initialised:
+ *
+ * pile -- NULL -- not in any pile (yet)
+ * backlink -- unset
+ *
+ * state -- not active
+ *
+ * time -- unset
+ * action -- NULL -- no action set (yet)
+ * timer_info -- NULL -- no timer info set (yet)
+ */
+
+ confirm(qtr_state_inactive == 0) ;
+
+ qtr->pile = qtp ;
+ qtr->action = action ;
+ qtr->timer_info = timer_info ;
+
+ return qtr ;
+} ;
+
+/* Free given timer.
+ *
+ * Unsets it first if it is active.
+ *
+ * The timer MAY NOT be currently the subject of qtimer_pile_dispatch_next().
+ */
+void
+qtimer_free(qtimer qtr)
+{
+ assert(qtr->state != qtr_state_unset_pending) ;
+
+ if (qtr->state != qtr_state_inactive)
+ qtimer_unset(qtr) ;
+
+ XFREE(MTYPE_QTIMER, qtr) ;
+} ;
+
+/* Set pile in which given timer belongs.
+ *
+ * Unsets the timer if active in another pile.
+ * (Does nothing if active in the "new" pile.)
+ */
+void
+qtimer_set_pile(qtimer qtr, qtimer_pile qtp)
+{
+ if (qtr_is_active(qtr) && (qtr->pile != qtp))
+ qtimer_unset(qtr) ;
+ qtr->pile = qtp ;
+}
+
+/* Set action for given timer.
+ */
+void
+qtimer_set_action(qtimer qtr, qtimer_action* action)
+{
+ qtr->action = action ;
+} ;
+
+/* Set timer_info for given timer.
+ */
+void
+qtimer_set_info(qtimer qtr, void* timer_info)
+{
+ qtr->timer_info = timer_info ;
+} ;
+
+/* Set given timer.
+ *
+ * Setting a -ve time => qtimer_unset.
+ *
+ * Sets any given action -- if the action given is NULL, retains previously set
+ * action.
+ *
+ * If the timer is already active, sets the new time & updates pile.
+ *
+ * Otherwise, sets the time and adds to pile -- making timer active.
+ *
+ * It is an error to set a timer which has a NULL action.
+ */
+void
+qtimer_set(qtimer qtr, qtime_mono_t when, qtimer_action* action)
+{
+ qtimer_pile qtp ;
+
+ if (when < 0)
+ return qtimer_unset(qtr) ;
+
+ qtp = qtr->pile ;
+ dassert(qtp != NULL) ;
+
+ qtr->time = when ;
+
+ if (qtr_is_active(qtr))
+ heap_update_item(&qtp->timers, qtr) ; /* update in heap */
+ else
+ heap_push_item(&qtp->timers, qtr) ; /* add to heap */
+
+ qtr->state = qtr_state_active ; /* overrides any unset pending */
+
+ if (action != NULL)
+ qtr->action = action ;
+ else
+ dassert(qtr->action != NULL) ;
+} ;
+
+/* Unset given timer
+ *
+ * If the timer is active, removes from pile and sets inactive.
+ */
+void
+qtimer_unset(qtimer qtr)
+{
+ if (qtr_is_active(qtr))
+ {
+ qtimer_pile qtp = qtr->pile ;
+ dassert(qtp != NULL) ;
+
+ heap_delete_item(&qtp->timers, qtr) ;
+
+ qtr->state = qtr_state_inactive ; /* overrides any unset pending */
+ } ;
+} ;
diff --git a/lib/qtimers.h b/lib/qtimers.h
new file mode 100644
index 00000000..3a774b38
--- /dev/null
+++ b/lib/qtimers.h
@@ -0,0 +1,144 @@
+/* Quagga timers support -- header
+ * Copyright (C) 2009 Chris Hall (GMCH), Highwayman
+ *
+ * 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 _ZEBRA_QTIMERS_H
+#define _ZEBRA_QTIMERS_H
+
+#include "zassert.h"
+#include "qtime.h"
+#include "heap.h"
+
+#ifndef Inline
+#define Inline static inline
+#endif
+
+/*==============================================================================
+ * Quagga Timers -- qtimer_xxxx
+ *
+ * Here and in qtimers.c is a data structure for managing multiple timers
+ * each with an action to be executed when the timer expires.
+ */
+
+/*==============================================================================
+ * Data Structures.
+ */
+
+typedef struct qtimer* qtimer ;
+typedef struct qtimer_pile* qtimer_pile ;
+
+typedef void (qtimer_action)(qtimer qtr, void* timer_info, qtime_mono_t when) ;
+
+enum qtimer_state {
+ qtr_state_inactive = 0,
+ qtr_state_active = 1, /* timer is active in its pile */
+ qtr_state_unset_pending = 3 /* timer is active, but unset is pending */
+} ;
+
+#define qtr_is_active(qtr) ((qtr)->state != qtr_state_inactive)
+
+typedef enum qtimer_state qtimer_state_t ;
+
+struct qtimer
+{
+ qtimer_pile pile ;
+ heap_backlink_t backlink ;
+
+ qtimer_state_t state ;
+
+ qtime_mono_t time ;
+ qtimer_action* action ;
+ void* timer_info ;
+} ;
+
+struct qtimer_pile
+{
+ struct heap timers ;
+} ;
+
+/*==============================================================================
+ * Functions
+ */
+
+qtimer_pile
+qtimer_pile_init_new(qtimer_pile qtp) ;
+
+int
+qtimer_pile_dispatch_next(qtimer_pile qtp, qtime_mono_t upto) ;
+
+qtime_mono_t
+qtimer_pile_top_time(qtimer_pile qtp, qtime_mono_t max_time) ;
+
+qtimer
+qtimer_pile_ream(qtimer_pile qtp, int free_structure) ;
+
+/* Ream out qtimer pile and free the qtimer structure. */
+#define qtimer_pile_ream_free(qtp) qtimer_pile_ream(qtp, 1)
+/* Ream out qtimer pile but keep the qtimer structure. */
+#define qtimer_pile_ream_keep(qtp) qtimer_pile_ream(qtp, 0)
+
+qtimer
+qtimer_init_new(qtimer qtr, qtimer_pile qtp,
+ qtimer_action* action, void* timer_info) ;
+void
+qtimer_set_pile(qtimer qtr, qtimer_pile qtp) ;
+
+void
+qtimer_set_action(qtimer qtr, qtimer_action* action) ;
+
+void
+qtimer_set_info(qtimer qtr, void* timer_info) ;
+
+void
+qtimer_free(qtimer qtr) ;
+
+void
+qtimer_set(qtimer qtr, qtime_mono_t when, qtimer_action* action) ;
+
+void
+qtimer_unset(qtimer qtr) ;
+
+Inline void
+qtimer_add(qtimer qtr, qtime_t interval, qtimer_action* action) ;
+
+Inline qtime_mono_t
+qtimer_get(qtimer qtr) ;
+
+/*==============================================================================
+ * Inline functions
+ */
+
+/* Set given timer to given time later than *its* current time.
+ */
+Inline void
+qtimer_add(qtimer qtr, qtime_t interval, qtimer_action* action)
+{
+ qtimer_set(qtr, qtimer_get(qtr) + interval, action);
+} ;
+
+/* Get the given timer's time.
+ */
+Inline qtime_mono_t
+qtimer_get(qtimer qtr)
+{
+ return qtr->time ;
+} ;
+
+#endif /* _ZEBRA_QTIMERS_H */
diff --git a/lib/routemap.c b/lib/routemap.c
index 4f4e6d62..2dfa5a46 100644
--- a/lib/routemap.c
+++ b/lib/routemap.c
@@ -207,7 +207,7 @@ vty_show_route_map_entry (struct vty *vty, struct route_map *map)
/* Print the name of the protocol */
if (zlog_default)
- vty_out (vty, "%s:%s", zlog_proto_names[zlog_default->protocol],
+ vty_out (vty, "%s:%s", zlog_get_proto_name(NULL),
VTY_NEWLINE);
for (index = map->head; index; index = index->next)
diff --git a/lib/symtab.c b/lib/symtab.c
new file mode 100644
index 00000000..9a833a14
--- /dev/null
+++ b/lib/symtab.c
@@ -0,0 +1,1181 @@
+/* Symbol Table data structure -- functions
+ * Copyright (C) 2009 Chris Hall (GMCH), Highwayman
+ *
+ * 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.
+ */
+
+#include <zebra.h>
+#include <stddef.h>
+
+#include "symtab.h"
+#include "memory.h"
+
+/* A symbol table maps symbol "names" to symbol values and, for each symbol,
+ * has two ways of keeping track of references to the symbol.
+ *
+ * The symbol name can be an arbitrary collection of bytes, or a string. All
+ * names in a symbol table are unique.
+ *
+ * The symbol value is a void* -- whose contents are no concern of this code.
+ *
+ * A symbol table comprises:
+ *
+ * * symbol table structure -- containing all "red-tape"
+ * * array of chain-bases -- for the hash table
+ * * symbol entries -- each containing name and value of a symbol
+ *
+ * The symbol table structure may be statically allocated, embedded in another
+ * structure, or allocated dynamically. In any case the symbol table operations
+ * require the address of the symbol table structure -- see typedef for
+ * symbol_table.
+ *
+ * A symbol table may point to its "parent" -- which could be an enclosing
+ * structure, or any other higher level data. The symbol table code does not
+ * use or need this -- it is for the convenience of the caller.
+ *
+ * A symbol table structure which is zeroised is implicitly an empty symbol
+ * table, using the default symbol name type -- a null terminated string.
+ *
+ * Each Symbol Table requires a hash function, which takes a pointer to
+ * whatever and returns a 32-bit hash value and a canonical form of the
+ * symbol "name". When a new symbol is created the canonical form of the name
+ * is copied to the symbol entry.
+ *
+ * The array of chain-bases is dynamically allocated and will grow to maintain
+ * an approximate given maximum number of symbols per chain base. This density
+ * is set when the symbol table is initialised. The array does not
+ * automatically reduce in size.
+ *
+ * The number of chain bases is always odd. The hash function returns a 32-bit
+ * unsigned value, which is mapped to the chain bases modulo their number.
+ * Since that is odd, it is co-prime with the hash, so contributes to the hash
+ * process.
+ *
+ * Each symbol in the table has a dynamically allocated entry, which includes:
+ *
+ * * symbol value -- void*
+ * * symbol name
+ * * count of references
+ * * list of references
+ *
+ * Symbols may have the value NULL. Deleting a symbol is not the same as
+ * setting its value to NULL. If the value is set NULL and later set to
+ * something else, all references to the symbol will see the new value. If the
+ * symbol is deleted, all references will see its value set to NULL, but if a
+ * new symbol with the same name is later created, all references to the old
+ * symbol are unchanged, and continue to see the (orphan) NULL.
+ *
+ * Keeping track of references is important because it ensures that symbols
+ * can be deleted without leaving dangling references. When a symbol is
+ * deleted, it is removed from the symbol table and its value is set to NULL.
+ * If there are no references to the symbol, the symbol entry is released.
+ * If there are references to the symbol, it is preserved (as an orphan) until
+ * all references are unset. The value of an orphaned symbol should not be
+ * changed.
+ *
+ * There are two, parallel mechanisms for keeping track of references to a
+ * symbol:
+ *
+ * 1. reference count -- this is for when all that is required is a pointer
+ * to the symbol, ie:
+ *
+ * * ptr_to_symbol = symbol_inc_ref(sym) -- set reference & count up
+ * * ptr_to_symbol = symbol_dec_ref(sym) -- unset reference & count down
+ *
+ * 2. list of references -- this is for when it is useful to visit all
+ * references to a given symbol, for example when the value of the symbol
+ * is set and all users of the symbol need to adjust to the new state.
+ *
+ * A symbol reference contains a pointer to the symbol, and lives on the
+ * list of references to the symbol. When the value is set, a call-back
+ * associated with the table is called (if it is set). That call-back may
+ * walk the list of references to the symbol. Each reference contains a
+ * pointer and a pointer/long int value, which may be used to identify the
+ * reference.
+ *
+ * A symbol reference may be statically allocated, embedded in another
+ * structure, or allocated dynamically. In any case the symbol reference
+ * operations require the address of the symbol reference structure -- see
+ * typedef for symbol_ref.
+ *
+ * Symbol references are the responsibility of of the owner of the reference,
+ * who must look after setting, unsetting and (if required) releasing them.
+ *
+ * It may seem profligate to have two mechanisms. However, it is simpler than
+ * having two types of symbol, or two types of symbol table. It may also be
+ * useful to have both simple references and references for dealing with
+ * value changes. Suppose, for instance, that the value of a symbol has a
+ * pointer to the symbol -- so that the value of the symbol can refer back to
+ * its name, for example. This requires only a simple reference, even if
+ * more generally a list of references is required.
+ *
+ * A symbol table can be walked to visit all symbols, and there is support for
+ * extracting a vector of all symbols which satisfy a given criterion.
+ */
+
+static void symbol_extend_bases(symbol_table table) ;
+static void symbol_free(symbol sym) ;
+
+/* Return true iff there are no references to the given symbol */
+inline static int
+symbol_no_references(symbol sym)
+{
+ return (sym->ref_count == 0) && (sym->ref_list == NULL) ;
+} ;
+
+/* If symbol is an orphan with no references/bookmarks, free it.
+ *
+ * NB: if symbol is an orphan, then it implicitly has a NULL value, because
+ * to become an orphan it must have been deleted, which unsets the value.
+ */
+inline static void
+symbol_free_if_redundant(symbol sym)
+{
+ if ((sym->table == NULL) && symbol_no_references(sym))
+ symbol_free(sym) ;
+} ;
+
+/* Return chain base for given hash value. */
+inline static symbol*
+symbol_base(symbol_table table, u_int32_t hash)
+{
+ return &table->bases[hash % table->base_count] ;
+} ;
+
+/* Initialise a new symbol table -- allocate if required.
+ *
+ * table -- address of table to initialise. NULL -> allocate.
+ * NB: if allocated, it is the caller's responsibility to free.
+ *
+ * parent -- address of some parent or other higher level data structure.
+ * This is not used by the symbol table code and may be NULL if
+ * the caller has no use for it.
+ *
+ * bases -- number of list bases to start the symbol table at.
+ * Symbol table grows as required, but can set initial size if
+ * have some expectations and wish to avoid growth steps.
+ *
+ * density -- %-age of entries/bases. 0 => use default.
+ *
+ * hash_function
+ * -- function to fill in symbol_hash from a given "name".
+ * see: description of struct symbol_hash and default function,
+ * symbol_hash_string, below.
+ * NULL => the names in this symbol table are null terminated
+ * strings, so use symbol_hash_string.
+ *
+ * value_call_back
+ * -- function to be called when the symbol value is set or unset.
+ * (Or the symbol is about to be deleted -- which starts by
+ * unsetting it).
+ *
+ * The function is passed the new state of the symbol and its
+ * previous value.
+ *
+ * The value of the symbol is a pointer to some data. If the
+ * data changes symbol_set_value() must be called if its
+ * address changes and may be called even if its address doesn't
+ * change.
+ *
+ * In any event, value_call_back is called when symbol_set_value()
+ * is called -- except where the symbol is being set to NULL and
+ * the value is already NULL.
+ *
+ * During the call-back the symbol may be set again or unset,
+ * which will cause the call-back to be called inside itself.
+ * Also, references may be set or unset.
+ *
+ * In the call-back the reference list may be walked to signal
+ * to all holders of the reference that something has changed.
+ *
+ * NB: A completely zeroized symbol_table structure is a valid, empty
+ * symbol table. The first time it is used it will be set up to default
+ * state -- in particular: symbol names are null terminated strings (a
+ * state which *cannot* then be changed).
+ *
+ * NB: when this is used to re-initialising an existing symbol table structure,
+ * any existing chain base array, symbols and symbol references are simply
+ * discarded -- which will leak memory and is probably a mistake.
+ */
+symbol_table
+symbol_table_init_new(symbol_table table,
+ void* parent,
+ unsigned int base_count,
+ unsigned int density,
+ symbol_hash_function* hash_function,
+ symbol_call_back_function* value_call_back)
+{
+ assert(base_count <= SYMBOL_TABLE_BASES_MAX) ;
+
+ if (table == NULL)
+ table = XCALLOC(MTYPE_SYMBOL_TABLE, sizeof (struct symbol_table)) ;
+
+ table->parent = parent ;
+
+ table->bases = NULL ; /* Allocated when required */
+ table->base_count = base_count ;
+
+ table->entry_count = 0 ;
+ table->extend_thresh = density ; /* Fixed up when required */
+
+ table->hash_function = hash_function ;
+ symbol_table_set_value_call_back(table, value_call_back) ;
+
+ return table ;
+} ;
+
+/* Set "parent" of symbol table. */
+void
+symbol_table_set_parent(symbol_table table, void* parent)
+{
+ table->parent = parent ;
+} ;
+
+/* Get "parent" of symbol table. */
+void*
+symbol_table_get_parent(symbol_table table)
+{
+ return table->parent ;
+} ;
+
+/* Set the value_call_back */
+void
+symbol_table_set_value_call_back(symbol_table table,
+ symbol_call_back_function* value_call_back)
+{
+ table->value_call_back = value_call_back ;
+} ;
+
+/* Create and set new chain bases and threshold for next extension. */
+/* */
+/* Ensures that the base count is at least the minimum and is odd, */
+/* and returns the value set. */
+static unsigned int
+symbol_table_new_bases(symbol_table table,
+ unsigned int new_base_count, float density)
+{
+ if (new_base_count < SYMBOL_TABLE_BASES_MIN)
+ new_base_count = SYMBOL_TABLE_BASES_MIN ;
+ new_base_count |= 1 ;
+
+ table->bases = XCALLOC(MTYPE_SYMBOL_BASES, new_base_count * sizeof(symbol)) ;
+ table->extend_thresh = new_base_count * density ;
+ return table->base_count = new_base_count ;
+} ;
+
+/* Setup symbol table body for use.
+ *
+ * Used for "lazy" allocation of chain bases and allows symbol_lookup
+ * to operate on a completely zeroized symbol_table structure.
+ */
+static void
+symbol_table_setup(symbol_table table)
+{
+ float density ;
+
+ /* If density was set explicitly, extend_thresh entry is a %age. */
+
+ if (table->extend_thresh != 0)
+ density = (float)table->extend_thresh / (float)100 ;
+ else
+ density = (float)2 ; /* Default density */
+
+ /* Initialise the chain bases -- enforces minimum base_count and odd-ness */
+ symbol_table_new_bases(table, table->base_count, density) ;
+
+ /* make default hash_function explicit. */
+ if (table->hash_function == NULL)
+ table->hash_function = (symbol_hash_function*)symbol_hash_string ;
+} ;
+
+/* Reset symbol table.
+ *
+ * Free the symbol table body, and free the symbol table structure or reset it.
+ *
+ * Return NULL if frees symbol table structure, otherwise the address of same.
+ *
+ * NB: must only be done when the table is empty -- see assertion !
+ */
+symbol_table
+symbol_table_reset(symbol_table table, int free_structure)
+{
+ if (table== NULL)
+ return NULL ; /* allow for already freed table */
+
+ assert(table->entry_count == 0) ;
+
+ if (table->bases)
+ XFREE(MTYPE_SYMBOL_BASES, table->bases);
+
+ if (free_structure)
+ {
+ XFREE(MTYPE_VECTOR, table) ;
+ return NULL ;
+ }
+ else
+ return memset(table, 0, sizeof(struct symbol_table)) ;
+} ;
+
+/* Remove symbol from its symbol table (if any). */
+
+static void
+symbol_remove(symbol sym)
+{
+ symbol_table table ;
+ symbol* base ;
+ symbol prev ;
+
+ table = sym->table ;
+ if (table != NULL) /* Deleted symbols have no parent table. */
+ {
+ assert(table->entry_count != 0) ;
+
+ base = symbol_base(table, sym->hash) ;
+ if (*base == sym)
+ *base = sym->next ;
+ else
+ {
+ prev = *base ;
+ while (prev->next != sym)
+ prev = prev->next ;
+ prev->next = sym->next ;
+ } ;
+
+ sym->table = NULL ; /* Symbol is now an orphan. */
+ --table->entry_count ;
+ } ;
+} ;
+
+/* Free symbol, removing it from the symbol table.
+ *
+ * NB: the value and all references MUST already have been unset, because:
+ *
+ * * any value may well need to be released, and have no idea how to do
+ * that here.
+ *
+ * * similarly, references may need to be released and should not, in
+ * any case, be left dangling.
+ */
+static void
+symbol_free(symbol sym)
+{
+ assert((sym->value == NULL) && symbol_no_references(sym)) ;
+
+ symbol_remove(sym) ; /* Remove from table, if any. */
+
+ XFREE(MTYPE_SYMBOL, sym) ;
+} ;
+
+/* Ream out symbols.
+ *
+ * Delete symbols -- but do not invoke the value_call_back.
+ *
+ * When the table is (or becomes) empty, the chain bases are freed, and the
+ * structure freed or reset (depending on the free_structure argument).
+ *
+ * This is intended for use when the symbol table is being destroyed, and all
+ * references have been, or will be unset.
+ *
+ * Returns the value of the next non-NULL symbol (if any). So may be used, for
+ * example:
+ *
+ * xxxx* val ;
+ * ...
+ * while ((val = symbol_table_ream(table, free_structure)) != NULL)
+ * {
+ * ... do what's required to release the value ...
+ * }
+ *
+ * Noting that the symbol may already have been released when its value is
+ * returned. (If the symbol is required when the value is released, then the
+ * value should hold a simple reference to the symbol.)
+ *
+ * Returns NULL when the table is empty.
+ *
+ * Symbols which have one or more references when they are deleted are left as
+ * orphans, which will be freed when all their references are unset.
+ *
+ * NB: do NOT attempt to do anything else with the symbol table once reaming
+ * has started.
+ *
+ * NB: it is the caller's responsibility to unset all references and release
+ * any that need to be released -- either before or after this operation.
+ */
+void*
+symbol_table_ream(symbol_table table, int free_structure)
+{
+ void* value ;
+ symbol sym ;
+ unsigned int i ;
+
+ i = table->base_count ;
+
+ while (i--)
+ {
+ while ((sym = table->bases[i]) != NULL)
+ {
+ assert(table->entry_count != 0) ;
+
+ /* the following is effectively symbol_delete, but avoids the */
+ /* value_call_back and returns only if the value is not NULL. */
+
+ table->bases[i] = sym->next ; /* remove from table */
+ --table->entry_count ; /* count down */
+
+ sym->table = NULL ; /* orphan symbol */
+ value = sym->value ; /* pick up value. */
+ sym->value = NULL ; /* and set symbol undefined */
+
+ if (symbol_no_references(sym))
+ symbol_free(sym) ; /* not in table, no value, no references */
+
+ if (value != NULL)
+ {
+ table->base_count = i + 1 ; /* where we've got to */
+ return value ; /* <<< RETURN: caller must deal with value */
+ } ;
+ } ;
+ } ;
+
+ symbol_table_reset(table, free_structure) ;
+
+ return NULL ;
+} ;
+
+/* Look-up name in given symbol table. Add if required.
+ *
+ * Returns NULL if not found and not required to add.
+ *
+ * NB: the name argument is passed to the symbol table's hash function. That
+ * function is required to return with a 32-bit hash
+ *
+ * NB: if required to add, the caller cannot distinguish between a symbol
+ * which did not previously exist, and one which did exist but had no
+ * value and no references. Where that distinction matters, it is
+ * necessary to do an extra lookup.
+ */
+symbol
+symbol_lookup(symbol_table table, const void* name, int add)
+{
+ struct symbol* this ;
+ struct symbol** base ;
+ struct symbol_hash hash ;
+
+ assert(table != NULL) ;
+ if (table->bases == NULL)
+ symbol_table_setup(table) ; /* Lazy allocation of chain bases etc. */
+
+ table->hash_function(&hash, name) ;
+
+ base = symbol_base(table, hash.hash) ;
+ this = *base ;
+ while (this)
+ {
+ if ((this->hash == hash.hash)
+ && (this->name_len == hash.name_len)
+ && (memcmp(this->name, hash.name, this->name_len) == 0))
+ return this ;
+ this = this->next ;
+ } ;
+
+ /* Not found -- quit now if not required to add */
+ if (!add) return NULL ;
+
+ /* Adding: first, carve a new, empty symbol entry */
+ this = XCALLOC(MTYPE_SYMBOL, sizeof(struct symbol) + hash.name_copy_len) ;
+
+ this->table = table ;
+ this->value = NULL ;
+ this->ref_list = NULL ;
+ this->ref_count = 0 ;
+ this->hash = hash.hash ;
+ this->name_len = hash.name_len ;
+ memcpy(this->name, hash.name, hash.name_copy_len) ;
+
+ /* Second, if required, extend the array of list bases. We extend if */
+ /* we have a collision *and* we exceed threshold of number of entries. */
+ if ((*base != NULL) && (table->entry_count > table->extend_thresh))
+ {
+ symbol_extend_bases(table) ;
+ base = symbol_base(table, hash.hash) ;
+ } ;
+
+ /* Third, chain in the new entry, count it in and return */
+ this->next = *base ;
+ *base = this ;
+
+ ++table->entry_count ;
+
+ return this ;
+} ;
+
+/* Delete symbol.
+ *
+ * The first effect of this is to set the symbol value to NULL, which may
+ * trigger a value_call_back etc.
+ *
+ * Then the symbol is removed from the table (and the symbol becomes an orphan).
+ *
+ * Then, if there are no (remaining) references the symbol is freed. Otherwise
+ * the symbol entry remains in existence until there are no more references
+ * (at which point it will finally be destroyed).
+ *
+ * Returns the last value of the symbol -- which may itself need to be
+ * destroyed -- noting that the symbol may already have been released. (If the
+ * symbol is required when the value is released, then the value should hold a
+ * simple reference to the symbol.)
+ *
+ * NB: the effect of deleting a symbol is to leave all remaining references
+ * pointing at an NULL value, orphaned symbol.
+ *
+ * If a new symbol is created with the same name, that will be a
+ * completely different symbol -- references to the old symbol will
+ * continue to be to the vestigial NULL value.
+ *
+ * This is different from setting the symbol value to NULL and later
+ * giving it a new value.
+ *
+ * NB: orphan symbols can be deleted. The effect is to free the symbol if
+ * possible.
+ */
+void*
+symbol_delete(symbol sym)
+{
+ void* old_value = symbol_unset_value(sym) ;
+
+ if (symbol_no_references(sym))
+ symbol_free(sym) ; /* free symbol now if no references */
+ else
+ symbol_remove(sym) ; /* else just remove it from the table -- will be */
+ /* freed when all references are unset. */
+ return old_value ;
+} ;
+
+/* The hash functions provided here use CRC32 as a hash.
+ *
+ * CRC32 is not intended as a hash function, and is not a perfect one.
+ * However it is fast -- requiring a few simple operations per byte. Taken
+ * with the secondary effect of using the hash produced modulo an odd number,
+ * experience suggests this is sufficient.
+ */
+
+static u_int32_t crc_table[] ;
+
+/* Standard symbol string hash function. */
+void
+symbol_hash_string(symbol_hash p_hash, const char* string) {
+ u_int32_t h = 0 ;
+ const char* p = string ;
+
+ while (*p != 0)
+ h = crc_table[(h & 0xFF) ^ (u_int8_t)*p++] ^ (h >> 8) ;
+
+ assert((p - string) < 0xFFFF) ;
+
+ p_hash->hash = h ;
+ p_hash->name = string ;
+ p_hash->name_len = (p - string) ;
+ p_hash->name_copy_len = p_hash->name_len + 1 ;
+} ;
+
+/* Standard symbol byte vector hash function. */
+void
+symbol_hash_bytes(symbol_hash p_hash, const void* bytes, size_t len) {
+ assert(len < 0xFFFF) ;
+
+ u_int32_t h = len ; /* So strings of zeros don't CRC the same ! */
+ const u_int8_t* p = bytes ;
+ const u_int8_t* e = p + len ;
+
+ while (p < e)
+ h = crc_table[(h & 0xFF) ^ *p++] ^ (h >> 8) ;
+
+ p_hash->hash = h ;
+ p_hash->name = (const void*)bytes ;
+ p_hash->name_len = len ;
+ p_hash->name_copy_len = len ;
+} ;
+
+/* Extend the array of list bases. */
+static void
+symbol_extend_bases(symbol_table table)
+{
+ symbol this ;
+ symbol next ;
+ symbol* old_bases ;
+ symbol* new_bases ;
+ symbol* base ;
+ unsigned int new_base_count ;
+ unsigned int old_base_count ;
+
+ old_bases = table->bases ;
+ old_base_count = table->base_count ;
+
+ assert((old_bases != NULL) && (old_base_count != 0)) ;
+
+ /* TODO: should look out for overflowing base_count and requiring */
+ /* impossible amounts of memory ?! */
+
+ new_base_count = (table->base_count | 1) - 1 ; /* trim enforced odd-ness */
+
+ if (new_base_count <= SYMBOL_TABLE_BASES_DOUBLE_MAX)
+ new_base_count *= 2 ;
+ else
+ new_base_count += SYMBOL_TABLE_BASES_DOUBLE_MAX ;
+
+ new_base_count = symbol_table_new_bases(table, new_base_count,
+ (float)table->extend_thresh / table->base_count) ;
+
+ /* Rehome everything on the new chain bases. */
+ new_bases = table->bases ;
+ while (old_base_count--)
+ {
+ next = old_bases[old_base_count] ;
+ while (next != NULL)
+ {
+ this = next ;
+ next = this->next ;
+ base = &new_bases[this->hash % new_base_count] ;
+ this->next = *base ;
+ *base = this ;
+ } ;
+ } ;
+
+ /* Release the old chain bases, and we're done. */
+ XFREE(MTYPE_SYMBOL_BASES, old_bases) ;
+} ;
+
+/*==============================================================================
+ * Reference count handling.
+ *
+ * symbol_inc_ref(sym) -- declared Inline
+ * symbol_dec_ref(sym) -- declared Inline
+ */
+
+/* Zeroise the reference count.*/
+
+symbol
+symbol_zero_ref(symbol sym, int force)
+{
+ assert((sym->ref_count == 1) || force) ;
+
+ sym->ref_count = 0 ;
+ symbol_free_if_redundant(sym) ;
+
+ return NULL ;
+} ;
+
+/*==============================================================================
+ * Reference list handling.
+ *
+ * References are added at the head of the list -- which is significant when
+ * adding references during a symbol reference walk.
+ */
+
+/* Insert symbol_ref at head of symbol's list of references. */
+static inline void
+symbol_add_ref(symbol sym, symbol_ref ref)
+{
+ symbol_ref next = sym->ref_list ;
+ sym->ref_list = ref ;
+ if (next)
+ next->prev = ref ;
+ ref->next = next ;
+ ref->prev = (void*)sym ; /* marker for first on list */
+} ;
+
+/* Clip symbol_ref from symbol's list of references.
+ *
+ * If symbol_ref has already been deleted the prev pointer is NULL, and this
+ * function copes -- and does not need the symbol to be valid (sym may be NULL).
+ */
+static inline void
+symbol_del_ref(symbol sym, symbol_ref ref)
+{
+ symbol_ref prev = ref->prev ;
+ symbol_ref next = ref->next ;
+
+ if (prev != NULL)
+ {
+ if (prev == (void*)sym)
+ {
+ assert(sym->ref_list == ref) ;
+ sym->ref_list = next ;
+ }
+ else
+ prev->next = next ;
+
+ if (next != NULL)
+ next->prev = prev ;
+ } ;
+ ref->next = ref->prev = NULL ;
+} ;
+
+/*==============================================================================
+ * The value_call_back handling and symbol reference list walking.
+ *
+ * If there is one, the value_call_back function is called when the value of
+ * a symbol is set -- except when it is set NULL and is already NULL. Note
+ * that setting the same non-NULL value *does* invoke the value_call_back.
+ *
+ * The value_call_back function is passed the current state of the symbol,
+ * complete with new value, and the old value of the symbol.
+ *
+ * During the value_call_back the symbol reference list may be walked, so that
+ * users of the value may be updated.
+ *
+ * During the value_call_back the symbol may be set, unset or deleted, and
+ * references added or taken away. This may cause nested calls of the
+ * call-back. Note that each call-back holds a reference to the symbol, so if
+ * the symbol is deleted it won't be freed until the outermost call-back
+ * returns.
+ *
+ * Procedure for walking the references to a symbol:
+ *
+ * struct symbol_ref walk ;
+ * symbol sym ;
+ * symbol_ref ref ;
+ * symbol_ref_walk_start(sym, &walk) ;
+ * while ((ref = symbol_ref_walk_step(&walk)) != NULL)
+ * .... whatever
+ * symbol_ref_walk_end(&walk) ;
+ *
+ * NB: it is *essential* to call symbol_ref_walk_end() exactly once at some
+ * time after symbol_ref_walk_start.
+ *
+ * The symbol table walk uses a "bookmark" which is a special from of entry in
+ * the symbol's reference list. This mechanism:
+ *
+ * (a) prevents the symbol being freed while the reference walk is in
+ * progress -- that may happen during symbol_ref_walk_end.
+ *
+ * (b) allows for the current and other references to be set or unset.
+ *
+ * Setting a reference inserts it upstream of the bookmark -- so it will
+ * not be visited during the walk.
+ *
+ * Unsetting a reference that has yet to be visited eliminates it from
+ * the walk.
+ *
+ * Note that setting a reference to refer to the symbol it already
+ * refers to has no effect at all.
+ *
+ * (c) allows the symbol to be defined, undefined or redefined during a
+ * symbol reference walk.
+ *
+ * If that triggers another symbol reference walk, then that walk will
+ * proceed until it hits the point reached by the walk it is nested
+ * inside, and then stop.
+ *
+ * Suppose the outer walk was dealing with the value having changed from
+ * 'A' to 'B'. The inner walk will do from 'B' to the latest value 'C'
+ * for the references that have already seen 'A' to 'B'. When the outer
+ * walk resumes, it will deal with the change 'A' to 'C', unaware of the
+ * intermediate step.
+ *
+ * If that does not suit, don't fiddle with symbol values during a
+ * symbol reference walk.
+ */
+
+/* Bookmarks are symbol_ref structures, distinguished from ordinary symbol_ref
+ * structures by setting the sym field to point at the bookmark symbol_ref
+ * itself.
+ *
+ * (It would be nicer to use the parent field for this... but what is put
+ * there in ordinary symbol_ref structures is not guaranteed...)
+ */
+static inline int
+symbol_ref_is_bookmark(symbol_ref ref)
+{
+ return (void*)ref->sym == (void*)ref ;
+} ;
+
+/* Start walk of symbol references */
+void
+symbol_ref_walk_start(symbol sym, symbol_ref walk)
+{
+ symbol_init_ref(walk) ; /* keeping things tidy */
+ walk->sym = (void*)walk ; /* bookmark signature */
+ walk->parent = sym ;
+ symbol_add_ref(sym, walk) ; /* insert bookmark at head of list */
+} ;
+
+/* Step walk and return the next reference (if any). */
+symbol_ref
+symbol_ref_walk_step(symbol_ref walk)
+{
+ symbol_ref next_ref ;
+
+ assert(symbol_ref_is_bookmark(walk)) ; /* must be a bookmark ! */
+
+ /* Pick up reference following the bookmark, before deleting it. */
+ next_ref = walk->next ;
+ symbol_del_ref((symbol)walk->parent, walk) ;
+
+ /* Stop immediately if bookmark was at the end of the list or the next */
+ /* item is a bookmark (for a walk that started earlier). */
+ if ((next_ref == NULL) || symbol_ref_is_bookmark(next_ref))
+ return NULL ;
+
+ /* Now we move the bookmark from where it is now to after next_ref. */
+
+ walk->next = next_ref->next ;
+ next_ref->next = walk ;
+ walk->prev = next_ref ;
+ if (walk->next != NULL)
+ walk->next->prev = walk ;
+
+ /* Return the next real reference to be processed. */
+ return next_ref ;
+} ;
+
+/* End of symbol reference walk.
+ *
+ * NB: if the symbol is not defined and has no references or bookmarks it
+ * will now be freed.
+ */
+void
+symbol_ref_walk_end(symbol_ref walk)
+{
+ assert(symbol_ref_is_bookmark(walk)) ; /* must be a bookmark ! */
+
+ symbol_del_ref((symbol)(walk->parent), walk) ; /* make sure */
+
+ symbol_free_if_redundant((symbol)(walk->parent)) ;
+} ;
+
+/*==============================================================================
+ * Symbol Value handling.
+ */
+
+/* Set symbol value. NB: setting to NULL == symbol_unset_value.
+ * NB: setting same value as currently looks like a change.
+ * (except for setting NULL to NULL !)
+ *
+ * Invokes change call-back, if any -- except when setting to NULL and is
+ * already NULL.
+ *
+ * It is possible for the call-back to set the value again, to unset it, to
+ * change references, etc.
+ *
+ * Returns previous value -- which may require releasing.
+ */
+void*
+symbol_set_value(symbol sym, void* new_value)
+{
+ void* old_value ;
+
+ assert(sym->table != NULL) ; /* may not set value for orphan symbol ! */
+
+ old_value = sym->value ;
+ sym->value = new_value ;
+
+ /* Invoke value_call_back (if any). */
+ /* Note that the value_call_back may set/unset references and/or */
+ /* define/undefine the value. */
+ if (((sym)->table->value_call_back != NULL)
+ && ( (new_value != NULL) || (old_value != NULL) ))
+ {
+ symbol_inc_ref(sym) ; /* preserve until call-back returns */
+ sym->table->value_call_back(sym, old_value) ;
+ symbol_dec_ref(sym) ; /* may now free if has been deleted */
+ } ;
+
+ return old_value ;
+} ;
+
+/*==============================================================================
+ * Symbol Reference handling.
+ *
+ * Implementation note: the next and prev pointers in the symbol_ref structure
+ * are significant only if the sym pointer is not NULL.
+ */
+
+/* Initialise symbol reference -- allocate if required. */
+symbol_ref
+symbol_init_ref(symbol_ref ref)
+{
+ if (ref == NULL)
+ return XCALLOC(MTYPE_SYMBOL_REF, sizeof(struct symbol_ref)) ;
+ else
+ return memset(ref, 0, sizeof(struct symbol_ref)) ;
+} ;
+
+/* Set symbol reference -- allocate if required (ref == NULL).
+ *
+ * NB: does nothing if reference already set to the given symbol.
+ *
+ * NB: unsets (but does not free) reference if was not NULL (and is not
+ * same as symbol being set to) before setting new reference.
+ *
+ * NB: setting reference to NULL unsets any existing reference, but does NOT
+ * release the reference structure.
+ *
+ * NB: if reference is allocated, the parent is set NULL and the tag is set
+ * NULL/0.
+ *
+ * if reference is not allocated, the parent and tag are unchanged.
+ */
+symbol_ref
+symbol_set_ref(symbol_ref ref, struct symbol* sym)
+{
+ if (ref != NULL)
+ {
+ if (ref->sym == sym)
+ return ref ; /* Nothing more to do if already set to given value */
+ if (ref->sym != NULL)
+ symbol_unset_ref_keep(ref) ;
+ }
+ else
+ ref = symbol_init_ref(NULL) ;
+
+ ref->sym = sym ;
+ if (sym != NULL)
+ symbol_add_ref(sym, ref) ;
+
+ return ref ;
+} ;
+
+/* Unset symbol reference. Free the structure if required.
+ *
+ * NB: does nothing if address of reference is NULL.
+ *
+ * NB: if reference is not freed, the parent and tag are unchanged.
+ *
+ * NB: removing the last reference to an symbol that has been deleted causes
+ * the symbol to be freed.
+ *
+ * NB: copes if the reference is already unset, of course.
+ */
+symbol_ref
+symbol_unset_ref(symbol_ref ref, int free_ref_structure)
+{
+ if (ref == NULL) return ref ;
+
+ if (ref->sym != NULL) /* NULL => reference already unset */
+ {
+ symbol_del_ref(ref->sym, ref) ;
+ symbol_free_if_redundant(ref->sym) ;
+ ref->sym = NULL ;
+ } ;
+
+ if (free_ref_structure)
+ XFREE(MTYPE_SYMBOL_REF, ref) ; /* ref is set to NULL */
+
+ return ref ;
+} ;
+
+/*==============================================================================
+ * Walking a symbol table
+ *
+ * Simple walk: visits all entries in the table, in the order they are hashed
+ * to. Simple iterator.
+ *
+ * Extract: makes vector of pointers to selected entries, and sorts that
+ * vector as required.
+ */
+
+/* Walk the given symbol table. Usage:
+ *
+ * struct symbol_walker walker ;
+ * symbol sym ;
+ * ....
+ * symbol_walk_start(table, &walker) ;
+ * while ((sym = symbol_walk_next(&walker)))
+ * ....
+ *
+ * NB: it is possible to change the current symbol while the walk is in
+ * progress -- up to and including deleting it. Any other changes to
+ * the table must NOT be attempted.
+ */
+void
+symbol_walk_start(symbol_table table, struct symbol_walker* walker)
+{
+ walker->next = NULL ;
+ walker->base = table->bases ;
+ walker->base_count = table->base_count ;
+} ;
+
+symbol
+symbol_walk_next(struct symbol_walker* walker)
+{
+ symbol this = walker->next ;
+
+ while (this == NULL)
+ {
+ if (walker->base_count == 0)
+ return NULL ;
+ --walker->base_count ;
+ this = *(walker->base++) ;
+ } ;
+
+ walker->next = this->next ;
+ return this ;
+} ;
+
+/* Extract Symbols.
+ *
+ * Walk symbol table and select symbols to add to a new vector. Then sort the
+ * vector, if required. Takes:
+ *
+ * -- selector: NULL => select all
+ * -- p_val: pointer is passed to the select function (if any)
+ * -- most: if there is a select function, this flag hints that most of
+ * the symbols will be selected -- so it is worth preallocating
+ * a vector big enough for all symbols.
+ * -- sort: NULL => no sort (!)
+ *
+ * NB: the vector contains pointers to the selected symbols. It is the
+ * caller's responsibility to avoid deleting any symbol whose pointer
+ * in the vector they expect to rely on !
+ */
+vector
+symbol_table_extract(symbol_table table,
+ symbol_select_cmp* selector, const void* p_val, int most,
+ symbol_sort_cmp* sort)
+{
+ vector extract ;
+ symbol* base ;
+ unsigned int count ;
+ symbol sym ;
+
+ extract = vector_init_new(NULL, (most || (selector == NULL))
+ ? table->entry_count : 8) ;
+ base = table->bases ;
+
+ if (base == NULL)
+ return extract ; /* Quit if symbol table is "reset" */
+
+ count = table->base_count ;
+ while (count--)
+ {
+ sym = *base++ ;
+ while (sym != NULL)
+ {
+ if ((selector == NULL) || selector(sym, p_val))
+ vector_push_item(extract, sym) ;
+ sym = sym->next ;
+ } ;
+ } ;
+
+ if (sort != NULL)
+ vector_sort(extract, (vector_sort_cmp*)sort) ;
+
+ return extract ;
+} ;
+
+/*==============================================================================
+ * Some common comparison functions for symbol table extracts.
+ */
+
+/* Comparison function to sort names which are a mixture of digits and other
+ * characters.
+ *
+ * This comparison treats substrings of digits as numbers, so "a10" is > "a1".
+ */
+int
+symbol_mixed_name_cmp(const symbol* p_a,
+ const symbol* p_b)
+{
+ const char* a = symbol_get_name(*p_a) ;
+ const char* b = symbol_get_name(*p_b) ;
+ int la, lb ;
+
+ while (1) {
+ if (isdigit(*a) && isdigit(*b))
+ {
+ char* as ; /* Required to stop the compiler whining */
+ char* bs ;
+ unsigned long int na = strtoul(a, (char** restrict)&as, 10) ;
+ unsigned long int nb = strtoul(b, (char** restrict)&bs, 10) ;
+ if (na != nb)
+ return (na < nb) ? -1 : +1 ;
+ a = as ;
+ b = bs ;
+ }
+ else
+ {
+ if (*a != *b)
+ return (*a < *b) ? -1 : +1 ;
+ if (*a == '\0')
+ break ;
+ ++a ;
+ ++b ;
+ }
+ } ;
+
+ /* Looks like the names are equal.
+ * But may be different lengths if have number part(s) with leading zeros,
+ */
+
+ la = symbol_get_name_len(*p_a) ;
+ lb = symbol_get_name_len(*p_b) ;
+ if (la != lb)
+ return (la < lb) ? -1 : +1 ;
+ return 0 ;
+} ;
+
+/*==============================================================================
+ * Table for generating CRC-32 -- Standard (0x1_04C1_1DB7 0xEDB8_8320)
+ */
+static u_int32_t crc_table[] =
+{
+ 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F,
+ 0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
+ 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2,
+ 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
+ 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9,
+ 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
+ 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C,
+ 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
+ 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423,
+ 0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
+ 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, 0x01DB7106,
+ 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
+ 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D,
+ 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
+ 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950,
+ 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
+ 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7,
+ 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
+ 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA,
+ 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
+ 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81,
+ 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
+ 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84,
+ 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
+ 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB,
+ 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
+ 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E,
+ 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
+ 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55,
+ 0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
+ 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28,
+ 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
+ 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F,
+ 0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
+ 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242,
+ 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
+ 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69,
+ 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
+ 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC,
+ 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
+ 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693,
+ 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
+ 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D,
+} ;
diff --git a/lib/symtab.h b/lib/symtab.h
new file mode 100644
index 00000000..7b4e002c
--- /dev/null
+++ b/lib/symtab.h
@@ -0,0 +1,318 @@
+/* Symbol Table data structure -- header
+ * Copyright (C) 2009 Chris Hall (GMCH), Highwayman
+ *
+ * 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 _ZEBRA_SYMTAB_H
+#define _ZEBRA_SYMTAB_H
+
+#include "vector.h"
+
+/* Macro in case there are particular compiler issues. */
+#ifndef Inline
+ #define Inline static inline
+#endif
+
+/* Maximum number of symbol table bases -- something has gone tragically wrong
+ * if we hit this. Assume can multiply this by 2 and get valid size_t result.
+ */
+#define SYMBOL_TABLE_BASES_MAX (1024 * 1024 * 1024)
+
+/* Minimum number of symbol table bases. */
+#define SYMBOL_TABLE_BASES_MIN 10
+/* Point at which stops doubling the symbol table size (bases) */
+#define SYMBOL_TABLE_BASES_DOUBLE_MAX 2000
+
+/* Structures defined below. */
+struct symbol_table ;
+struct symbol ;
+struct symbol_ref ;
+struct symbol_hash ;
+
+typedef struct symbol_table* symbol_table ;
+typedef struct symbol* symbol ;
+typedef struct symbol_ref* symbol_ref ;
+typedef struct symbol_hash* symbol_hash ;
+
+/* Function types used. */
+typedef void symbol_hash_function(symbol_hash hash, const void* name) ;
+typedef void symbol_call_back_function(symbol sym, void* value) ;
+typedef void symbol_destroy_function(symbol sym) ;
+
+/* Symbol Table.
+ *
+ * Don't fiddle with this directly... see access functions below.
+ */
+
+struct symbol_table
+{
+ void* parent ; /* to identify the table. */
+
+ symbol* bases ; /* ref:array of chain bases */
+ unsigned int base_count ; /* number of chain bases */
+
+ unsigned int entry_count ; /* number of entries in the table */
+ unsigned int extend_thresh ; /* when to extend the hash table */
+
+ symbol_hash_function* hash_function ; /* function to hash given "name" */
+ /* NULL => use default */
+ symbol_call_back_function* value_call_back ;
+ /* called when symbol value is set */
+} ;
+
+/* Symbol Table Entry.
+ *
+ * Don't fiddle with this directly... see access macros/functions below.
+ */
+
+struct symbol
+{
+ symbol_table table ; /* so can go from symbol to enclosing table */
+ /* NULL => orphan symbol, with NULL value. */
+
+ symbol next ; /* assume chains are short and seldom remove */
+ /* symbols -- so single pointer will do. */
+
+ void* value ; /* see: symbol_get_value(sym) etc. */
+
+ symbol_ref ref_list ; /* list of symbol_ref references */
+ unsigned ref_count ; /* count of simple references */
+
+ u_int32_t hash ; /* used in lookup and when extending bases. */
+
+ u_int16_t name_len ; /* see: symbol_get_name_len(sym) */
+ char name[] ; /* see: symbol_get_name(sym) */
+} ;
+
+/* Symbol Reference (or "bookmark").
+ *
+ * Don't fiddle with this directly... see access macros/functions below
+ */
+
+typedef union
+{
+ void* p ;
+ unsigned long u ;
+ signed long i ;
+} symbol_ref_tag_t ;
+
+struct symbol_ref
+{
+ symbol sym ; /* Address of symbol referred to (if any). */
+ /* (In "bookmark" this points to self.) */
+
+ symbol_ref next ; /* fellow references to the symbol ... */
+ symbol_ref prev ; /* ... ignore if sym is NULL. */
+
+ void* parent ; /* see: sym_ref_parent(sym_ref) etc. */
+ symbol_ref_tag_t tag ; /* see: sym_ref_tag(sym_ref) etc. */
+} ;
+
+/* Result of a hash function for a symbol name. */
+struct symbol_hash
+{
+ u_int32_t hash ; /* the hash value ! */
+ const void* name ; /* symbol name as byte vector */
+ u_int16_t name_len ; /* length in chars for comparison purposes */
+ u_int16_t name_copy_len ; /* number of chars to copy to store name. */
+} ;
+
+/* Symbol Walk Iterator */
+struct symbol_walker
+{
+ symbol next ; /* next symbol to return (if any) */
+ symbol* base ; /* next chain base to process (if any) */
+ unsigned base_count ; /* number of chain bases left to process */
+} ;
+
+/* Symbol Table Operations. */
+
+extern symbol_table
+symbol_table_init_new(symbol_table table,
+ void* parent,
+ unsigned bases,
+ unsigned density,
+ symbol_hash_function* hash_function,
+ symbol_call_back_function* value_call_back) ;
+void symbol_table_set_parent(symbol_table table, void* parent) ;
+void* symbol_table_get_parent(symbol_table table) ;
+void* symbol_table_ream(symbol_table table, int free_structure) ;
+#define symbol_table_ream_free(table) symbol_table_ream(table, 1)
+#define symbol_table_ream_keep(table) symbol_table_ream(table, 0)
+symbol_table symbol_table_reset(symbol_table table, int free_structure) ;
+#define symbol_table_reset_free(table) symbol_table_reset(table, 1)
+#define symbol_table_reset_keep(table) symbol_table_reset(table, 0)
+
+extern void symbol_hash_string(struct symbol_hash* p_hash, const char* string) ;
+extern void symbol_hash_bytes(struct symbol_hash* p_hash, const void* bytes,
+ size_t len) ;
+extern void symbol_table_set_value_call_back(symbol_table table,
+ symbol_call_back_function* value_call_back) ;
+
+extern void symbol_table_free(symbol_table) ;
+
+extern symbol symbol_lookup(symbol_table table, const void* name, int add) ;
+
+#define symbol_seek(table, name) symbol_lookup(table, name, 0)
+#define symbol_find(table, name) symbol_lookup(table, name, 1)
+
+extern void* symbol_delete(symbol sym) ;
+
+extern void* symbol_set_value(symbol sym, void* new_value) ;
+#define symbol_unset_value(sym) symbol_set_value(sym, NULL)
+
+void symbol_ref_walk_start(symbol sym, symbol_ref walk) ;
+symbol_ref symbol_ref_walk_step(symbol_ref walk) ;
+void symbol_ref_walk_end(symbol_ref walk) ;
+
+void symbol_walk_start(symbol_table table, struct symbol_walker* walker) ;
+symbol symbol_walk_next(struct symbol_walker* walker) ;
+
+typedef int symbol_select_cmp(const symbol, const void*) ;
+typedef int symbol_sort_cmp(const symbol*, const symbol*) ;
+vector symbol_table_extract(symbol_table table,
+ symbol_select_cmp* select, const void* p_value,
+ int most, symbol_sort_cmp* sort) ;
+
+extern symbol_sort_cmp symbol_mixed_name_cmp ;
+
+/* Access functions -- argument is address of symbol (may be NULL). */
+Inline void*
+symbol_get_value(const symbol sym)
+{
+ return (sym != NULL) ? sym->value : NULL ;
+} ;
+
+Inline const void*
+symbol_get_name(const symbol sym)
+{
+ return (sym != NULL) ? sym->name : NULL ;
+} ;
+
+Inline unsigned
+symbol_get_name_len(const symbol sym)
+{
+ return (sym != NULL) ? sym->name_len : 0 ;
+} ;
+
+Inline struct symbol_table*
+symbol_get_table(const symbol sym)
+{
+ return (sym != NULL) ? sym->table : NULL ;
+} ;
+
+Inline symbol
+symbol_inc_ref(symbol sym)
+{
+ ++sym->ref_count ;
+ return sym ;
+} ;
+
+extern symbol symbol_zero_ref(symbol sym, int force) ;
+
+Inline symbol
+symbol_dec_ref(symbol sym)
+{
+ if (sym->ref_count <= 1)
+ return symbol_zero_ref(sym, 0) ;
+
+ --sym->ref_count ;
+ return sym ;
+} ;
+
+extern symbol_ref
+symbol_init_ref(symbol_ref ref) ;
+
+extern symbol_ref
+symbol_set_ref(symbol_ref ref, symbol sym) ;
+
+extern symbol_ref
+symbol_unset_ref(symbol_ref ref, int free_ref_structure) ;
+
+#define symbol_unset_ref_free(ref) symbol_unset_ref(ref, 1) ;
+#define symbol_unset_ref_keep(ref) symbol_unset_ref(ref, 0) ;
+
+/* Access functions -- argument is address of symbol_ref. */
+/* These cope if address of symbol_ref is null, or reference is undefined. */
+Inline void*
+sym_ref_symbol(symbol_ref ref)
+{
+ return (ref != NULL) ? ref->sym : NULL ;
+}
+Inline void*
+sym_ref_value(symbol_ref ref)
+{
+ return symbol_get_value(sym_ref_symbol(ref)) ;
+}
+Inline const void*
+sym_ref_name(symbol_ref ref)
+{
+ return symbol_get_name(sym_ref_symbol(ref)) ;
+}
+Inline u_int16_t
+sym_ref_name_len(symbol_ref ref)
+{
+ return symbol_get_name_len(sym_ref_symbol(ref)) ;
+}
+
+Inline void*
+sym_ref_parent(symbol_ref ref)
+{
+ return (ref != NULL) ? ref->parent : NULL ;
+}
+Inline void*
+sym_ref_p_tag(symbol_ref ref)
+{
+ return (ref != NULL) ? ref->tag.p : NULL ;
+}
+Inline unsigned long int
+sym_ref_u_tag(symbol_ref ref)
+{
+ return (ref != NULL) ? ref->tag.u : 0 ;
+}
+Inline signed long int
+sym_ref_i_tag(symbol_ref ref)
+{
+ return (ref != NULL) ? ref->tag.i : 0 ;
+}
+
+/* Set properties of reference -- argument is address of symbol_ref, which is */
+/* assumed to NOT be NULL. */
+Inline void
+sym_ref_set_parent(symbol_ref ref, void* pa)
+{
+ ref->parent = pa ;
+}
+Inline void
+sym_ref_set_p_tag(symbol_ref ref, void* p_tag)
+{
+ ref->tag.p = p_tag ;
+}
+Inline void
+sym_ref_set_u_tag(symbol_ref ref, unsigned long int u_tag)
+{
+ ref->tag.u = u_tag ;
+}
+Inline void
+sym_ref_set_i_tag(symbol_ref ref, signed long int i_tag)
+{
+ ref->tag.i = i_tag ;
+}
+
+#endif /* _ZEBRA_SYMTAB_H */
diff --git a/lib/vector.c b/lib/vector.c
index 7c148628..ad2af289 100644
--- a/lib/vector.c
+++ b/lib/vector.c
@@ -1,6 +1,9 @@
-/* Generic vector interface routine
+/* Generic vector interface routine -- functions
* Copyright (C) 1997 Kunihiro Ishiguro
*
+ * 24-Nov-2009 -- extended to add a number of new operations on vectors.
+ * Copyright (C) 2009 Chris Hall (GMCH), Highwayman
+ *
* This file is part of GNU Zebra.
*
* GNU Zebra is free software; you can redistribute it and/or modify it
@@ -16,7 +19,7 @@
* 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.
+ * 02111-1307, USA.
*/
#include <zebra.h>
@@ -24,87 +27,789 @@
#include "vector.h"
#include "memory.h"
-/* Initialize vector : allocate memory and return vector. */
+/* Vectors are implemented as a structure which points to an array of pointers
+ * to vector items. That array -- the body of the vector -- can change size,
+ * and therefore may move around in memory.
+ *
+ * The vector structure may be statically allocated, embedded in another
+ * structure, or allocated dynamically. In any case the vector operations
+ * require the address of the vector structure -- see typedef for vector.
+ *
+ * Vector items are accessed by index, fetching and storing pointers to
+ * those items. Can also push and pop items.
+ *
+ * A vector has a known (logical) end position. Everything beyond the end is
+ * defined to be NULL. When a vector is initialised it is set empty.
+ *
+ * At any given moment the vector body has a limit on the number of items it
+ * can accommodate (the physical end).
+ *
+ * A vector will grow to accommodate what is put into it. Adding items beyond
+ * the (logical) end moves it. Adding items beyond the (physical) limit causes
+ * the body to be extended to suit, and to leave some spare space for future
+ * expansion.
+ *
+ * While the vector is small (see VECTOR_LIMIT_DOUBLE_MAX) the body will grow by
+ * doubling in size. When it is larger, it grows to be multiples of
+ * VECTOR_LIMIT_DOUBLE_MAX.
+ *
+ * Deleting items reduces the (logical) end position, but does NOT release
+ * memory -- the (physical) limit is not changed.
+ *
+ * To release memory: vector_chop will release everything beyond the current
+ * end; vector_decant will create a new body of exactly the current size,
+ * releasing the old body; vector_discard will release everything beyond a
+ * given position.
+ *
+ * NB: you can set a vector item to be NULL. If you set a vector item beyond
+ * the current end, NULL items are inserted in the vector.
+ *
+ * NB: when setting a vector item it is the caller's responsibility to
+ * deallocate any pre-existing value of the item.
+ *
+ * NB: when deleting items it is also the caller's responsibility to deallocate
+ * any values that require it.
+ *
+ * Implementation Notes
+ *
+ * Everything beyond the (logical) end is implicitly NULL.
+ *
+ * Actual memory between (logical) end and (physical) limit is UNDEFINED. So
+ * when advancing the end some care has to be taken to ensure that any new
+ * items in the vector are either set to something or cleared to NULL.
+ *
+ * It would have been possible to ensure that everything between end and limit
+ * is cleared to NULL, but that is more work -- in particular it creates work
+ * when it is not always required.
+ */
+
+#define P_ITEMS_SIZE(n) SIZE(p_vector_item, n)
+/*==============================================================================
+ * Initialisation, allocation, reset etc.
+ */
+
+/* Initialise a brand new vector, setting it empty.
+ *
+ * Allocates vector structure if none given -- that is, if v == NULL.
+ *
+ * If size is given as zero, no body is allocated, otherwise body of exactly
+ * the required size is allocated.
+ *
+ * NB: discards any existing vector body -- so it is the caller's responsibility
+ * to release any existing body, and any items in that body.
+ */
vector
-vector_init (unsigned int size)
+vector_init_new(vector v, unsigned int size)
{
- vector v = XCALLOC (MTYPE_VECTOR, sizeof (struct _vector));
+ if (v == NULL)
+ v = XCALLOC(MTYPE_VECTOR, sizeof(struct vector)) ;
+ else
+ memset(v, 0, sizeof(struct vector)) ;
- /* allocate at least one slot */
- if (size == 0)
- size = 1;
+ if (size != 0)
+ {
+ v->p_items = XMALLOC(MTYPE_VECTOR_BODY, P_ITEMS_SIZE(size)) ;
+ v->limit = size ;
+ } ;
- v->alloced = size;
- v->active = 0;
- v->index = XCALLOC (MTYPE_VECTOR_INDEX, sizeof (void *) * size);
- return v;
-}
+ return v ;
+} ;
+/* Initialize vector : allocate memory and return vector.
+ * allocates body with at least 1 entry.
+ */
+vector
+vector_init (unsigned int size)
+{
+ return vector_init_new(NULL, size ? size : 1) ; /* at least 1 entry */
+} ;
+
+/* Basic: free the given vector structure. NB: Orphans any existing body !! */
void
vector_only_wrapper_free (vector v)
{
XFREE (MTYPE_VECTOR, v);
}
+/* Basic: free the vector body. */
void
-vector_only_index_free (void *index)
+vector_only_index_free (void *body)
{
- XFREE (MTYPE_VECTOR_INDEX, index);
+ XFREE (MTYPE_VECTOR_BODY, body);
}
+/* Basic: free the vector body and the vector structure. */
void
vector_free (vector v)
{
- XFREE (MTYPE_VECTOR_INDEX, v->index);
+ XFREE (MTYPE_VECTOR_BODY, v->p_items);
XFREE (MTYPE_VECTOR, v);
}
+/* Re-Initialize vector (or create new one), setting it empty.
+ *
+ * Allocates vector structure if none given -- that is, if v == NULL.
+ *
+ * If size is given as zero, no body is allocated, but any existing body is
+ * retained. (vector_reset() will discard body.)
+ *
+ * Otherwise ensures existing body is at least the required size, or a body
+ * of exactly the required size is allocated.
+ *
+ * NB: when re-initialising an existing vector it is the caller's
+ * responsibility to release any vector item values *before* doing this.
+ * */
+vector
+vector_re_init(vector v, unsigned int size)
+{
+ if ((v == NULL) || (v->p_items == NULL))
+ return vector_init_new(v, size) ;
+
+ v->end = 0 ;
+
+ if (v->limit < size)
+ {
+ v->p_items = XREALLOC(MTYPE_VECTOR_BODY, v->p_items, P_ITEMS_SIZE(size)) ;
+ v->limit = size ;
+ } ;
+
+ return v ;
+} ;
+
+/* Free the vector body, and free the vector structure or reset it.
+ *
+ * Return NULL if releases vector, otherwise the address of the vector.
+ *
+ * NB: it is the caller's responsibility to release any vector item values
+ * *before* doing this.
+ */
+vector
+vector_reset(vector v, int free_structure)
+{
+ if (v == NULL)
+ return NULL ; /* allow for already freed vector */
+
+ if (v->p_items != NULL)
+ XFREE(MTYPE_VECTOR_BODY, v->p_items) ;
+
+ if (free_structure)
+ {
+ XFREE(MTYPE_VECTOR, v) ;
+ return NULL ;
+ }
+ else
+ return vector_init_new(v, 0) ;
+} ;
+
+/* Pop item from vector, stepping past any NULLs.
+ *
+ * If vector is empty, free the body and, if required, the vector structure.
+ *
+ * Useful for emptying out and discarding a vector:
+ *
+ * while ((p_v = vector_ream_out(v, 1)))
+ * ... do what's required to release the item p_v
+ *
+ * Returns NULL if vector was empty and has now been freed as required.
+ */
+p_vector_item
+vector_ream(vector v, int free_structure)
+{
+ p_vector_item p_v ;
+
+ if (v == NULL)
+ return NULL ;
+
+ while (v->end != 0)
+ {
+ p_v = v->p_items[--v->end] ;
+ if (p_v != NULL)
+ return p_v ; /* return non-NULL item */
+ } ;
+
+ /* vector is empty: free the body, and (if required) the vector structure. */
+ vector_reset(v, free_structure) ;
+
+ return NULL ; /* signals end */
+} ;
+
+/*==============================================================================
+ * Unset item.
+ */
+
+/* Unset item at given index (ie set it NULL).
+ *
+ * Return the old value of the item.
+ *
+ * If the item at the current (logical) end of the vector is NULL, move the
+ * end backwards until finds a non-NULL item, or the vetor becomes empty.
+ */
+extern p_vector_item
+vector_unset_item(vector v, vector_index i)
+{
+ p_vector_item was ;
+ if (i < v->end)
+ {
+ was = v->p_items[i] ;
+ v->p_items[i] = NULL ;
+ }
+ else
+ was = NULL ;
+
+ /* Now move end back past any NULLs */
+ i = v->end ;
+ while ((i > 0) && (v->p_items[i-1] == NULL))
+ --i ;
+ v->end = i ;
+
+ return was ;
+} ;
+
+/*==============================================================================
+ * Inserting and deleting items.
+ */
+
+/* Insert item in vector, before item at given position
+ * Move items and extend vector as required.
+ */
+void
+vector_insert_item(vector v, vector_index i, void* p_v)
+{
+ if ((i == v->end) && (i < v->limit))
+ ++v->end ;
+ else
+ vector_insert(v, i, 1) ;
+
+ v->p_items[i] = (p_vector_item)p_v ;
+} ;
+
+/* Insert item in vector at given position with rider:
+ *
+ * rider < 0 -- insert before the item at the given position
+ * rider == 0 -- insert at the given position -- REPLACING any existing value
+ * rider > 0 -- insert after the item at the given position
+ *
+ * NB: when an item is replaced, it is the caller's responsibility to release
+ * any memory used by the item, if required.
+ *
+ * Move items and extend vector as required.
+ */
+void
+vector_insert_item_here(vector v, vector_index i, int rider,
+ p_vector_item p_v)
+{
+ if (rider == 0)
+ return vector_set_item(v, i, p_v) ;
+
+ if (rider > 0)
+ ++i ; /* insert before next item */
+ vector_insert_item(v, i, p_v) ;
+} ;
+
+/* Delete item from vector.
+ *
+ * Move items as required. Reduces number of items in the vector (unless
+ * the item in question is beyond the end of the vector !)
+ *
+ * NB: it is the caller's responsibility to release memory used by any
+ * current value of the item, if required.
+ *
+ * NB: does NOT change the size of the vector body.
+ */
+p_vector_item
+vector_delete_item(vector v, vector_index i)
+{
+ p_vector_item p_e ;
+ if (i < v->end)
+ {
+ p_e = v->p_items[i] ; /* pick up the current value */
+ if (i != (v->end - 1))
+ vector_delete(v, i, 1) ;
+ else
+ v->end = i ;
+ return p_e ;
+ }
+ else
+ return NULL ;
+} ;
+
+/*==============================================================================
+ * Moving items within vector.
+ */
+
+/* Move item in vector from source position to destination position.
+ * Moves intervening items up or down as required.
+ * Extends vector to include the destination, if required.
+ * A source item beyond the end of the vector is implicitly NULL.
+ */
+void
+vector_move_item(vector v, vector_index i_dst, vector_index i_src)
+{
+ p_vector_item* pp_s ;
+ p_vector_item* pp_d ;
+ p_vector_item p_e ;
+
+ vector_index old_end = v->end ;
+
+ /* Worry about whether both source and destination exist. */
+ if (i_dst >= old_end)
+ {
+ vector_insert(v, i_dst, 1) ; /* ensure destination exists */
+ if (i_src >= old_end)
+ return ; /* both were beyond the end */
+ }
+ else if (i_src >= old_end)
+ {
+ i_src = old_end ; /* clamp to just beyond last */
+ vector_insert(v, i_src, 1) ; /* create empty entry */
+ } ;
+
+ if (i_dst == i_src) /* avoid work and edge case */
+ return ;
+
+ /* Both src and dst are within the vector and src != dst */
+ pp_s = &v->p_items[i_src] ; /* address of src entry */
+ pp_d = &v->p_items[i_dst] ; /* address of dst entry */
+ p_e = *pp_s ; /* pick up item to move */
+ if (i_src < i_dst)
+ memmove(pp_s, pp_s+1, P_ITEMS_SIZE(i_dst - i_src)) ;
+ else
+ memmove(pp_d+1, pp_d, P_ITEMS_SIZE(i_src - i_dst)) ;
+ *pp_d = p_e ; /* put down the item to move */
+} ;
+
+/* Move item in vector to given position with rider:
+ *
+ * rider < 0 -- move to before the item at the given position
+ * rider == 0 -- move to replace item at the given position
+ * rider > 0 -- insert after the item at the given position
+ *
+ * NB: it is the caller's responsibility to release the any existing value
+ * that will be replaced.
+ *
+ * Move items and extend vector as required.
+ */
+void
+vector_move_item_here(vector v, vector_index i_dst, int rider,
+ vector_index i_src)
+{
+ if (rider != 0)
+ {
+ if (rider > 0)
+ ++i_dst ;
+ vector_move_item(v, i_dst, i_src) ;
+ }
+ else
+ {
+ /* to replace: copy and then delete. */
+ vector_set_item(v, i_dst, vector_get_item(v, i_src)) ;
+ vector_delete_item(v, i_src) ;
+ } ;
+} ;
+
+/* Reverse vector: reverse the order of items in the vector.
+ */
+void
+vector_reverse(vector v)
+{
+ if (v != NULL)
+ vector_part_reverse(v, 0, v->end) ;
+} ;
+
+/* Reverse portion of vector.
+ */
+void
+vector_part_reverse(vector v, vector_index i, unsigned int n)
+{
+ vector_index j ;
+
+ if (v == NULL)
+ return ;
+
+ if ((i + n) > v->limit)
+ vector_extend(v, i + n) ; /* ensure portion exists */
+
+ if (n <= 1)
+ return ;
+
+ j = i + n - 1 ; /* j > i, because n > 1 */
+ do
+ {
+ p_vector_item p_i = v->p_items[i] ;
+ v->p_items[i++] = v->p_items[j] ;
+ v->p_items[j--] = p_i ;
+ } while (j > i) ;
+} ;
+
+/*==============================================================================
+ * Copying, moving and appending entire vectors.
+ */
+
+static void vector_new_limit(vector v, vector_index new_end) ;
+
+/* Shallow vector copy -- copies pointers to item values, not the values. */
+/* Creates a new vector. */
+/* NB: copies whole body, including stuff beyond (logical) end ! */
+/* TODO: is this behaviour required ? */
vector
vector_copy (vector v)
{
- unsigned int size;
- vector new = XCALLOC (MTYPE_VECTOR, sizeof (struct _vector));
+ vector new = vector_init_new(NULL, v->limit) ;
- new->active = v->active;
- new->alloced = v->alloced;
+ new->end = v->end;
- size = sizeof (void *) * (v->alloced);
- new->index = XCALLOC (MTYPE_VECTOR_INDEX, size);
- memcpy (new->index, v->index, size);
+ if (v->limit > 0)
+ memcpy(new->p_items, v->p_items, P_ITEMS_SIZE(v->limit)) ;
return new;
}
-/* Check assigned index, and if it runs short double index pointer */
-void
-vector_ensure (vector v, unsigned int num)
+/* Shallow vector copy -- copies pointers to item values, not the values.
+ * Creates a new vector or re-initialises an existing one.
+ *
+ * NB: creates new vector with same limit as existing one, but copies only
+ * the known items (ie up to end, not up to limit).
+ *
+ * NB: if re-initialising existing vector, it is the caller's responsibility
+ * to release any existing items if that is required.
+ *
+ * NB: if re-initialising existing vector, it is the caller's responsibility
+ * to ensure the vector structure is currently valid.
+ *
+ * NB: do NOT try copying a vector to itself !!
+ */
+vector
+vector_copy_here(vector dst, vector src)
+{
+ assert((src != NULL) && (src != dst)) ;
+
+ dst = vector_re_init(dst, src->limit) ;
+
+ dst->end = src->end;
+
+ if (src->end > 0)
+ memcpy(dst->p_items, src->p_items, P_ITEMS_SIZE(src->end)) ;
+
+ return dst ;
+} ;
+
+/* Vector move -- moves body of vector.
+ * Creates a new vector or re-initialises an existing one.
+ * Leaves the source vector empty -- does not release the structure.
+ *
+ * NB: if re-initialising existing vector, it is the caller's responsibility
+ * to release any existing items if that is required.
+ *
+ * NB: if re-initialising existing vector, it is the caller's responsibility
+ * to ensure the vector structure is currently valid.
+ *
+ * NB: do NOT try moving a vector to itself !!
+ */
+vector
+vector_move_here(vector dst, vector src)
{
- if (v->alloced > num)
- return;
+ assert((src != NULL) && (src != dst)) ;
+
+ if (dst != NULL)
+ dst = vector_reset(dst, 0) ; /* Reset to deallocate any existing body */
+ else
+ dst = vector_init_new(dst, 0) ; /* Create new structure sans body. */
- v->index = XREALLOC (MTYPE_VECTOR_INDEX,
- v->index, sizeof (void *) * (v->alloced * 2));
- memset (&v->index[v->alloced], 0, sizeof (void *) * v->alloced);
- v->alloced *= 2;
-
- if (v->alloced <= num)
- vector_ensure (v, num);
+ *dst = *src ; /* Copy the vector structure */
+
+ vector_init_new(src, 0) ; /* Set empty, forgetting body */
+
+ return dst ;
}
-/* This function only returns next empty slot index. It dose not mean
+/* Shallow vector copy append -- copies pointers to item values, not the values.
+ * Appends copied pointers to the destination vector.
+ * Creates a new destination vector if required.
+ *
+ * NB: Can append to self.
+ */
+vector
+vector_copy_append(vector dst, vector src)
+{
+ vector_index new_end ;
+
+ assert(src != NULL) ;
+
+ if (dst != NULL)
+ {
+ new_end = dst->end + src->end ;
+ if (new_end > dst->limit)
+ vector_new_limit(dst, new_end) ;
+ }
+ else
+ {
+ new_end = src->end ;
+ vector_init_new(dst, new_end) ;
+ } ;
+
+ if (src->end)
+ memcpy(&dst->p_items[dst->end], src->p_items, P_ITEMS_SIZE(src->end)) ;
+
+ dst->end = new_end ; /* Done last, allows for append to self ! */
+ return dst ;
+} ;
+
+/* Vector move append -- moves pointers to item values.
+ * Appends moved pointers to the destination vector.
+ * Creates a new destination vector if required (dst == NULL).
+ * Leaves the source vector empty -- does not release the structure.
+ *
+ * NB: do NOT try moving a vector to itself !!
+ */
+vector
+vector_move_append(vector dst, vector src)
+{
+ assert((src != NULL) && (src != dst)) ;
+
+ if ((dst == NULL) || (dst->end == 0))
+ return vector_move_here(dst, src) ; /* Easy way to do it if dst empty */
+
+ vector_copy_append(dst, src) ; /* Extend dst and copy src */
+ vector_init_new(src, 0) ; /* Set empty, forgetting body */
+
+ return dst ;
+} ;
+
+/*==============================================================================
+ * Portmanteau splice/extract/replace function.
+ *
+ * All take a portion of 'src' vector and:
+ *
+ * splice:
+ *
+ * a) replace a portion of the 'dst' vector by a portion of the 'src' vector
+ * copying the replaced portion of the 'dst' vector to the 'to' vector
+ * b) either: leave 'src' unchanged -- copy
+ * or: remove the stuff copied from 'src' -- move
+ *
+ * Arguments: to_copy -- true
+ * to -- vector, or NULL => allocate new vector
+ * dst -- vector
+ * i_dst -- start of portion to replace
+ * n_dst -- length of portion to replace. 0 => insertion.
+ * src -- vector, or NULL => nothing to copy/move
+ * i_src -- start of portion to copy/move
+ * n_src -- length of portion to copy/move. 0 => nothing.
+ * src_move -- true => move, otherwise copy.
+ *
+ * Returns: the (possibly new) 'to' vector
+ *
+ * NB: 'to', 'dst' and 'src' must be distinct vectors.
+ *
+ * extract:
+ *
+ * a) copy a portion of the 'src' vector to the 'to' vector
+ * c) either: leave 'src' unchanged -- copy
+ * or: remove the stuff copied from 'src' -- move
+ *
+ * Arguments: to_copy -- true
+ * to -- vector, or NULL => allocate new vector
+ * dst -- NULL
+ * i_dst -- ignored
+ * n_dst -- ignored
+ * src -- vector, or NULL => nothing to copy/move
+ * i_src -- start of portion to copy/move
+ * n_src -- length of portion to copy/move. 0 => nothing.
+ * src_move -- true => move, otherwise copy.
+ *
+ * Returns: the (possibly new) 'to' vector
+ *
+ * NB: 'to' and 'src' must be distinct vectors.
+ *
+ * replace:
+ *
+ * a) replace a portion of the 'dst' vector by a portion of the 'src' vector
+ * b) either: leave 'src' unchanged -- copy
+ * or: remove the stuff copied from 'src' -- move
+ *
+ * Arguments: to_copy -- false
+ * to -- ignored
+ * dst -- vector
+ * i_dst -- start of portion to replace
+ * n_dst -- length of portion to replace. 0 => insertion.
+ * src -- vector, or NULL => nothing to copy/move
+ * i_src -- start of portion to copy/move
+ * n_src -- length of portion to copy/move. 0 => nothing.
+ * src_move -- true => move, otherwise copy.
+ *
+ * Returns: original 'to' argument
+ *
+ * NB: 'dst' and 'src' must be distinct vectors.
+ *
+ * All copies are shallow -- pointers to item values are copied, not the values.
+ *
+ * NB: any existing contents of the 'to' vector are discarded.
+ *
+ * NB: it is the caller's responsibility to release memory allocated to any
+ * items which are discarded in these operations.
+ *
+ * NB: for splice and replace, the resulting destination vector will be at
+ * least i_dst + n_src long. (Even if is copying actual or implied NULLs
+ * from the source.)
+ *
+ * NB: where new vectors are created, they will be of exactly the required size.
+ *
+ * NB: where an existing vector is reused, it is the caller's responsibility
+ * to ensure the vector structure is currently valid (by vector_init_new()
+ * or by ensuring it is zeroized).
+ */
+vector
+vector_sak(int to_copy, vector to,
+ vector dst, vector_index i_dst, unsigned int n_dst,
+ vector src, vector_index i_src, unsigned int n_src, int src_move)
+{
+ int dst_replace ; /* true => replace portion of 'dst' */
+
+ vector_index new_dst_end = 0 ; /* new end of dst */
+
+ unsigned int n_dst_nulls ; /* number of implicit NULLs to add */
+ unsigned int n_dst_move ; /* number of items to move up or down */
+ unsigned int n_src_real ; /* number of items to really copy */
+ unsigned int n_src_nulls ; /* number of implicit NULLs to "copy" */
+
+ assert((to == NULL) || (dst == NULL) || (to != dst)) ;
+ assert((src == NULL) || (dst == NULL) || (src != dst)) ;
+
+ /* Worry about how much we really have in the source vector. */
+
+ n_src_real = n_src ; /* assume all real */
+ n_src_nulls = 0 ; /* so no NULLs to "copy" */
+
+ if (n_src != 0)
+ {
+ if ((src == NULL) || (i_src >= src->end))
+ n_src_real = 0 ;
+ else if ((i_src + n_src) > src->end)
+ n_src_real = src->end - i_src ;
+ n_src_nulls = n_src - n_src_real ;
+ } ;
+
+ /* If no 'dst' vector, then this is an extract. */
+
+ n_dst_move = 0 ; /* assume nothing to move */
+ n_dst_nulls = 0 ; /* assume no NULLs to add */
+
+ if (dst == NULL)
+ /* For extract: set up dst, i_dst and n_dst so that can copy to the */
+ /* 'to' vector as if from 'dst'. */
+ {
+ dst_replace = 0 ; /* no replacement operation */
+ dst = src ; /* copy from here */
+ i_dst = i_src ;
+ n_dst = n_src_real ;
+ }
+ else
+ /* Reduce n_dst to the number of actual items to be replaced. */
+ /* */
+ /* Calculate the new end of 'dst'. */
+ {
+ dst_replace = 1 ; /* have replacement to do */
+ if (i_dst >= dst->end)
+ /* If i_dst is beyond the end of 'dst', then there is nothing */
+ /* to replace (so set n_dst == 0). Will be adding n_src items */
+ /* at i_dst -- so new end must be i_dst + n_src. */
+ {
+ n_dst_nulls = i_dst - dst->end ; /* fill from end to i_dst */
+ n_dst = 0 ; /* nothing to replace */
+ new_dst_end = i_dst + n_src ; /* all beyond current end */
+ }
+ else
+ /* If i_dst + n_dst is beyond the end of 'dst', reduce n_dst to */
+ /* number of items up to the end. */
+ /* Will remove n_dst items and insert n_src, so end will move */
+ /* by n_src - n_dst. */
+ {
+ if ((i_dst + n_dst) > dst->end)
+ n_dst = dst->end - i_dst ; /* what we actually replace */
+ else if (n_dst != n_src)
+ n_dst_move = dst->end - (i_dst + n_dst) ;
+ /* what we move up or down */
+
+ new_dst_end = dst->end + n_src - n_dst ;
+ /* end depends on amount added */
+ /* & amount actually replaced */
+ } ;
+ } ;
+
+ /* Copy portion of 'dst' (or of 'src') to 'to', if required. */
+ /* */
+ /* Have arranged: n_dst -- number of items to copy, all existent */
+ /* dst -- vector to copy from -- if n_dst > 0 */
+ /* i_dst -- first item to copy -- if n_dst > 0 */
+
+ if (to_copy)
+ {
+ to = vector_re_init(to, n_dst) ; /* reinitialise or create */
+ to->end = n_dst ;
+ if (n_dst > 0)
+ memcpy(to->p_items, &dst->p_items[i_dst], P_ITEMS_SIZE(n_dst)) ;
+ } ;
+
+ /* Replace portion of 'dst' by portion of 'src', if required. */
+ /* */
+ /* Have arranged: */
+ /* */
+ /* new_dst_end -- end of dst once dust settles */
+ /* n_dst_nulls -- number of NULLs to insert at dst->end to fill up */
+ /* to i_dst (when i_dst is beyond old end.) */
+ /* n_dst_move -- number of items in dst to move up or down to */
+ /* leave n_src item hole at i_dst to fill in. */
+ /* n_src_real -- number of real src items at i_src to copy to dst */
+ /* at i_dst. */
+ /* n_src_nulls -- number of nulls to add to fill to i_dst + n_src. */
+
+ if (dst_replace)
+ {
+ if (new_dst_end > dst->limit) /* extend body if required */
+ vector_new_limit(dst, new_dst_end) ;
+
+ if (n_dst_nulls > 0)
+ memset(&dst->p_items[dst->end], 0, P_ITEMS_SIZE(n_dst_nulls)) ;
+ if (n_dst_move > 0)
+ memmove(&dst->p_items[i_dst + n_dst], &dst->p_items[i_dst + n_src],
+ P_ITEMS_SIZE(n_dst_move)) ;
+ if (n_src_real > 0)
+ memcpy(&dst->p_items[i_dst], &src->p_items[i_src],
+ P_ITEMS_SIZE(n_src_real)) ;
+ if (n_src_nulls > 0)
+ memset(&dst->p_items[i_dst + n_src_real], 0,
+ P_ITEMS_SIZE(n_src_nulls)) ;
+ dst->end = new_dst_end ;
+ } ;
+
+ /* Delete portion of 'src', if required (and have 'src' !) */
+
+ if (src_move && (n_src_real != 0))
+ vector_delete(src, i_src, n_src_real) ;
+
+ /* Done -- return 'to' vector as promised. */
+
+ return to ;
+} ;
+
+/*==============================================================================
+ * Legacy Vector Operations
+ */
+
+/* This function only returns next empty slot index. It does not mean
the slot's index memory is assigned, please call vector_ensure()
- after calling this function. */
+ after calling this function.
+
+ Index returned is <= current (logical) end.
+*/
int
vector_empty_slot (vector v)
{
- unsigned int i;
-
- if (v->active == 0)
- return 0;
+ vector_index i;
- for (i = 0; i < v->active; i++)
- if (v->index[i] == 0)
- return i;
+ for (i = 0; i < v->end; i++)
+ if (v->p_items[i] == NULL)
+ break ;
return i;
}
@@ -113,77 +818,406 @@ vector_empty_slot (vector v)
int
vector_set (vector v, void *val)
{
- unsigned int i;
-
- i = vector_empty_slot (v);
- vector_ensure (v, i);
-
- v->index[i] = val;
+ vector_index i;
+ i = vector_empty_slot(v) ; /* NB: i <= v->end */
+ if (i == v->end)
+ i = vector_extend_by_1(v) ;
- if (v->active <= i)
- v->active = i + 1;
+ v->p_items[i] = val;
return i;
}
/* Set value to specified index slot. */
int
-vector_set_index (vector v, unsigned int i, void *val)
+vector_set_index (vector v, vector_index i, void *val)
{
vector_ensure (v, i);
-
- v->index[i] = val;
-
- if (v->active <= i)
- v->active = i + 1;
-
+ v->p_items[i] = val;
return i;
}
/* Look up vector. */
-void *
-vector_lookup (vector v, unsigned int i)
+p_vector_item
+vector_lookup (vector v, vector_index i)
{
- if (i >= v->active)
+ if (i >= v->end)
return NULL;
- return v->index[i];
+ return v->p_items[i];
}
/* Lookup vector, ensure it. */
-void *
-vector_lookup_ensure (vector v, unsigned int i)
+p_vector_item
+vector_lookup_ensure (vector v, vector_index i)
{
vector_ensure (v, i);
- return v->index[i];
+ return v->p_items[i];
+}
+
+/* Count the number of not empty slots. */
+vector_index
+vector_count (vector v)
+{
+ vector_index i;
+ unsigned count = 0;
+
+ for (i = 0; i < v->end; i++)
+ if (v->p_items[i] != NULL)
+ count++;
+
+ return count;
}
-/* Unset value at specified index slot. */
+/*==============================================================================
+ * Sorting and Searching vector.
+ */
+
+/* Sort the given vector.
+ *
+ * NB: the comparison function receives a pointer to the pointer to the
+ * vector item's value.
+ *
+ * NB: if there are NULL items in the vector, the comparison function MUST
+ * be ready for them.
+ */
+void
+vector_sort(vector v, vector_sort_cmp* cmp)
+{
+ if (v->end <= 1)
+ return ; /* Stop dead if 0 or 1 items */
+
+ typedef int qsort_cmp(const void*, const void*) ;
+
+ qsort(v->p_items, v->end, sizeof(p_vector_item), (qsort_cmp*)cmp) ;
+} ;
+
+/* Perform binary search on the given vector.
+ *
+ * The vector MUST be sorted in the order implied by the comparison function
+ * given. The vector need not contain unique values, but this search makes
+ * no effort to select any particular instance of a sequence of equals.
+ *
+ * Returns:
+ *
+ * result == 0: found an equal value.
+ * index returned is of first entry found which is equal to
+ * the value sought. There may be other equal values, before
+ * and/or after this one in the vector.
+ *
+ * result == +1: value not found and vector not empty.
+ * index returned is of the largest entry whose value is less
+ * than the value sought.
+ * (The value sought belongs after this point.)
+ *
+ * result == -1: value is less than everything in the vector, or the
+ * vector is empty.
+ * index returned is 0
+ *
+ * NB: The comparison function takes arguments which are:
+ *
+ * const void** pointer to pointer to value being searched for.
+ * const void** pointer to pointer to vector item to compare with
+ *
+ * The value being searched for need not be in the same form as a vector
+ * item. However, if it is then the same comparison function can be used
+ * to sort and search.
+ *
+ * NB: if there are NULL items in the vector, the comparison function MUST
+ * be ready for them.
+ */
+vector_index
+vector_bsearch(vector v, vector_bsearch_cmp* cmp, const void* p_val,
+ int* result)
+{
+ vector_index il, iv, ih ;
+ int c ;
+
+ if (v->end <= 1)
+ {
+ *result = (v->end == 0) ? -1 : cmp(&p_val, (const void**)&v->p_items[0]) ;
+ return 0 ; /* Stop dead if 0 or 1 items */
+ } ;
+
+ /* We have at least two items. */
+ il = 0 ;
+ ih = v->end - 1 ;
+
+ /* Pick off the edge cases: >= last and <= first. */
+ if ((c = cmp(&p_val, (const void**)&v->p_items[ih])) >= 0)
+ {
+ *result = c ; /* 0 => found. +1 => val > last */
+ return ih ; /* return high index. */
+ } ;
+ if ((c = cmp(&p_val, (const void**)&v->p_items[il])) <= 0)
+ {
+ *result = c ; /* 0 => found. -1 => val < first */
+ return il ; /* return low index. */
+ }
+
+ /* Now binary chop. We know that item[il] < val < item[ih] */
+ /* We also know that il < ih */
+ while (1)
+ {
+ iv = (il + ih) / 2 ;
+ if (iv == il) /* true if (ih == il+1) */
+ {
+ *result = +1 ;
+ return il ; /* return il: item[il] < val < item[il+1] */
+ } ;
+ /* We now know that il < iv < ih */
+ c = cmp(&p_val, (const void**)&v->p_items[iv]) ;
+ if (c == 0)
+ {
+ *result = 0 ;
+ return iv ; /* found !! */
+ }
+ if (c < 0)
+ ih = iv ; /* step down iv > il, so new ih > il */
+ else
+ il = iv ; /* step up iv < ih, so new il < ih */
+ } ;
+} ;
+
+/*==============================================================================
+ * Mechanics for adding/deleting items and managing the vector (logical) end
+ * and (physical) limit.
+ */
+
+/* Extract the LS bit of unsigned integer 'x'. */
+#define lsbit(x) ((x) & ((~(x)) + 1))
+/* Round 'x' up to a multiple of 'm' */
+#define multiple(x, m) ((((x) + (m) - 1) / (m)) * (m))
+
+/* Set new limit to suit new end for given vector.
+ *
+ * The new limit will be at least: VECTOR_LIMIT_MIN.
+ *
+ * While the vector is relatively small, the limit is doubled until there
+ * is at least 1/8 of the new vector free.
+ *
+ * Beyond VECTOR_LIMIT_DOUBLE_MAX, however, the limit is set to the
+ * smallest multiple of VECTOR_LIMIT_DOUBLE_MAX which gives at least
+ * VECTOR_LIMIT_SLACK_MIN free entries beyond the new end.
+ *
+ * This is an attempt to balance the cost of repeated reallocations of
+ * memory against the cost of possible wasted space at the end of the
+ * vector.
+ *
+ * NB: the new_limit depends entirely on the new end position. (Current
+ * end position is ignored.)
+ *
+ * NB: the new limit may be less than the current limit, in which case the
+ * vector body is reduced in size.
+ *
+ * Except for any size set when the vector is initialised, the vector body
+ * size will be a power of 2 or a multiple of VECTOR_LIMIT_DOUBLE_MAX.
+ * (Vectors are regular in their habits, which may help the memory allocator).
+ *
+ * TODO: what to do if calculation of new_limit overflows, or calculation
+ * of P_ITEMS_SIZE will ?
+ */
+static void
+vector_new_limit(vector v, vector_index new_end)
+{
+ vector_index old_limit = v->limit ;
+ vector_index new_limit ;
+
+ if (new_end > ((VECTOR_LIMIT_DOUBLE_MAX * 7) / 8))
+ {
+ new_limit = multiple(new_end + VECTOR_LIMIT_SLACK_MIN,
+ VECTOR_LIMIT_DOUBLE_MAX) ;
+ }
+ else
+ {
+ /* Want the new_limit to be a power of 2. */
+ /* If the old_limit was a power of 2, start from there. */
+ /* Otherwise start from a power of 2 less than new_end: either the */
+ /* minimum value or a value mid way to VECTOR_LIMIT_DOUBLE_MAX. */
+ if ( (old_limit != 0) && (old_limit == lsbit(old_limit))
+ && (new_end >= old_limit) )
+ new_limit = old_limit ;
+ else
+ new_limit = (new_end < VECTOR_LIMIT_MID) ? VECTOR_LIMIT_MIN
+ : VECTOR_LIMIT_MID ;
+ while (new_end > ((new_limit * 7) / 8))
+ new_limit *= 2 ;
+ } ;
+
+ v->p_items =
+ XREALLOC(MTYPE_VECTOR_BODY, v->p_items, P_ITEMS_SIZE(new_limit)) ;
+
+ v->limit = new_limit ;
+} ;
+
+/* Extend vector and set new (logical) end.
+ *
+ * Extends body if required.
+ * Ensures everything between old and new end is set NULL.
+ *
+ * NB: expects new end > old end, but copes with new end <= old end.
+ */
+void
+vector_extend(vector v, vector_index new_end)
+{
+ vector_index old_end = v->end ;
+
+ if (new_end > v->limit)
+ vector_new_limit(v, new_end) ;
+ v->end = new_end ;
+
+ if (new_end > old_end)
+ memset(&v->p_items[old_end], 0, P_ITEMS_SIZE(new_end - old_end)) ;
+} ;
+
+/* Insert entries into vector: insert 'n' NULL entries at location 'i'.
+ *
+ * Updates end (and limit) to be at least 'i' + 'n'.
+ * (So if 'i' < end then end becomes end + 'n', else end becomes 'i' + 'n'.)
+ */
+void
+vector_insert(vector v, vector_index i, unsigned int n)
+{
+ vector_index old_end, new_end ;
+ unsigned int n_above ;
+
+ /* If i < old end, then we are inserting n NULLs, and need
+ * to shuffle at least one item up.
+ * else we are setting new end to i + n and need to NULL
+ * fill from old end to the new end.
+ */
+ old_end = v->end ;
+ if (i < old_end)
+ {
+ if (n == 0)
+ return ; /* give up now if not inserting anything */
+ n_above = old_end - i ; /* number of items to shuffle up.. >= 1 */
+ new_end = old_end + n ;
+ }
+ else
+ {
+ n_above = 0 ; /* nothing to shuffle up. */
+ new_end = i + n ;
+ i = old_end ; /* where to zeroize from */
+ n = new_end - old_end ; /* how much to zeroize */
+ } ;
+
+ /* Now we extend the body if we need to. */
+ if (new_end > v->limit)
+ vector_new_limit(v, new_end) ;
+ v->end = new_end ;
+
+ if (n_above > 0)
+ memmove(&v->p_items[i + n], &v->p_items[i], P_ITEMS_SIZE(n_above)) ;
+
+ memset(&v->p_items[i], 0, P_ITEMS_SIZE(n)) ;
+} ;
+
+/* Delete items from vector: delete 'n' items at location 'i'.
+ *
+ * Does nothing if 'i' is beyond current end of vector or if 'n' == 0.
+ *
+ * Deletes from 'i' to end if less than 'n' items to the end.
+ *
+ * NB: does NOT change the size of the body.
+ *
+ * NB: it is the caller's responsibility to have released any memory allocated
+ * for the items that are being deleted.
+*/
void
-vector_unset (vector v, unsigned int i)
+vector_delete(vector v, vector_index i, unsigned int n)
{
- if (i >= v->alloced)
- return;
+ vector_index old_end, new_end ;
+
+ old_end = v->end ;
- v->index[i] = NULL;
+ if ((i >= old_end) || (n == 0))
+ return ;
- if (i + 1 == v->active)
+ /* If i + n < old_end, we have 1 or more items to keep and move down */
+ if ((i + n) < old_end)
{
- v->active--;
- while (i && v->index[--i] == NULL && v->active--)
- ; /* Is this ugly ? */
+ memmove(&v->p_items[i], &v->p_items[i + n],
+ P_ITEMS_SIZE(old_end - (i + n))) ;
+ new_end = old_end - n ;
}
-}
+ else
+ {
+ new_end = i ; /* We are keeping nothing above 'i' */
+ /* NB: new_end < old_end */
+ } ;
-/* Count the number of not emplty slot. */
-unsigned int
-vector_count (vector v)
+ v->end = new_end ; /* account for stuff dropped */
+} ;
+
+/* Discard entries from vector: discard entries from location 'i' onwards.
+ *
+ * Releases memory from 'i' onwards.
+ * Releases the body altogether if this sets the vector empty ('i' == 0).
+ * Sets new end of vector iff 'i' < current end.
+ *
+ * Does nothing if 'i' is beyond current limit (physical end) of vector.
+ *
+ * NB: it is the caller's responsibility to have released any memory allocated
+ * for the items that are being discarded.
+*/
+void
+vector_discard(vector v, vector_index i)
{
- unsigned int i;
- unsigned count = 0;
+ if (i >= v->limit)
+ return ;
- for (i = 0; i < v->active; i++)
- if (v->index[i] != NULL)
- count++;
+ if (i == 0)
+ vector_reset(v, 0) ; /* reset, without releasing the structure */
+ else
+ {
+ v->limit = i ;
+ if (i < v->end)
+ v->end = i ;
+ v->p_items = XREALLOC(MTYPE_VECTOR_BODY, v->p_items, P_ITEMS_SIZE(i)) ;
+ } ;
+} ;
- return count;
-}
+/* Chop vector at the current (logical) end.
+ *
+ * Releases the body altogether if the vector is currently empty.
+*/
+void
+vector_chop(vector v)
+{
+ vector_index new_limit = v->end ;
+
+ if (new_limit == 0)
+ vector_reset(v, 0) ; /* reset, without releasing the structure */
+ else if (new_limit != v->limit)
+ {
+ v->limit = new_limit ;
+ v->p_items = XREALLOC(MTYPE_VECTOR_BODY, v->p_items, P_ITEMS_SIZE(new_limit)) ;
+ } ;
+} ;
+
+/* Decant vector into a new body allocated to current logical size, and
+ * release the old body.
+ *
+ * Releases the body altogether if the vector is currently empty.
+*/
+void
+vector_decant(vector v)
+{
+ p_vector_item* p_old_body ;
+ vector_index new_limit = v->end ;
+
+ if (new_limit == 0)
+ vector_reset(v, 0) ; /* reset, without releasing the structure */
+ else
+ {
+ p_old_body = v->p_items ;
+
+ vector_init_new(v, new_limit) ; /* initialise with new body */
+
+ memcpy(v->p_items, p_old_body, P_ITEMS_SIZE(new_limit)) ;
+ /* copy the old body across */
+ v->end = new_limit ;
+
+ XFREE(MTYPE_VECTOR_BODY, p_old_body) ;
+ } ;
+} ;
diff --git a/lib/vector.h b/lib/vector.h
index 6b27fd96..2897cb51 100644
--- a/lib/vector.h
+++ b/lib/vector.h
@@ -1,7 +1,9 @@
-/*
- * Generic vector interface header.
+/* Generic vector interface header.
* Copyright (C) 1997, 98 Kunihiro Ishiguro
*
+ * 24-Nov-2009 -- extended to add a number of new operations on vectors.
+ * Copyright (C) 2009 Chris Hall (GMCH), Highwayman
+ *
* This file is part of GNU Zebra.
*
* GNU Zebra is free software; you can redistribute it and/or modify it
@@ -17,47 +19,272 @@
* 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.
+ * 02111-1307, USA.
*/
#ifndef _ZEBRA_VECTOR_H
#define _ZEBRA_VECTOR_H
-/* struct for vector */
-struct _vector
+/* Macro in case there are particular compiler issues. */
+#ifndef Inline
+ #define Inline static inline
+#endif
+
+/* types and struct for vector */
+/* */
+/* NB: an entirely zero structure represents an entirely empty vector. */
+/* */
+/* TODO: could force vector_index to be 32 bits ? */
+
+typedef void* p_vector_item ;
+typedef unsigned int vector_index ;
+
+struct vector
{
- unsigned int active; /* number of active slots */
- unsigned int alloced; /* number of allocated slot */
- void **index; /* index to data */
+ p_vector_item *p_items ; /* pointer to array of vector item pointers */
+ vector_index end ; /* number of "active" item entries */
+ vector_index limit ; /* number of allocated item entries */
};
-typedef struct _vector *vector;
+typedef struct vector *vector;
+
+/* Values that control the allocation of the vector body. */
+/* NB: these must all be powers of 2. */
+
+/* The body, when allocated, will have at least this many entries. */
+#define VECTOR_LIMIT_MIN 8
+/* When the body grows, it doubles in size, until it is this big. */
+/* After that it grows in units of this much. */
+#define VECTOR_LIMIT_DOUBLE_MAX 2048
+/* "Midway" between VECTOR_LIMIT_MIN and VECTOR_LIMIT_DOUBLE_MAX. */
+#define VECTOR_LIMIT_MID 128
+/* When growing in units of VECTOR_LIMIT_DOUBLE_MAX, this is the */
+/* minimum slack space to leave after the logical end of the vector. */
+#define VECTOR_LIMIT_SLACK_MIN ((VECTOR_LIMIT_DOUBLE_MAX) / 8)
+
+/* (Sometimes) useful macros. */
-#define VECTOR_MIN_SIZE 1
+/* Reference item at given index. */
+/* NB: does not guarantee the item is "active" (that is: within the */
+/* (logical) vector) -- but see vector_ensure. */
+/* Returns address of vector item. */
+/* See: VECTOR_ITEMS() for walking items in a vector. */
+/* See: vector_get_item(), which is preferable. */
+#define vector_slot(V,I) ((V)->p_items[(I)])
+
+/* Number of "active" item entries -- (logical) end of the vector. */
+/* Note that this differs from vector_count() as this count will */
+/* include any NULL items. */
+#define vector_active(V) ((V)->end)
+
+/* TODO: fix where this is used to poke around inside a vector */
+#define VECTOR_INDEX p_items
+
+/* To walk all items in a vector:
+ *
+ * vector_index i ;
+ * xxxxx* p_v ;
+ *
+ * for (VECTOR_ITEMS(v, p_v, i))
+ * {
+ * ... i is index of current item
+ * ... p_v is address of current item value -- may be NULL
+ * } ;
+ *
+ * ... i is number of items in vector (including any NULLs)
+ */
+#define VECTOR_ITEMS(v, p_v, i)\
+ (i) = 0 ;\
+ (i) < (v)->end ? (((p_v) = (void*)(v)->p_items[i]), 1) \
+ : (((p_v) = NULL), 0) ;\
+ ++(i)
-/* (Sometimes) usefull macros. This macro convert index expression to
- array expression. */
-/* Reference slot at given index, caller must ensure slot is active */
-#define vector_slot(V,I) ((V)->index[(I)])
-/* Number of active slots.
- * Note that this differs from vector_count() as it the count returned
- * will include any empty slots
+/*==============================================================================
+ * Prototypes.
*/
-#define vector_active(V) ((V)->active)
-/* Prototypes. */
extern vector vector_init (unsigned int size);
-extern void vector_ensure (vector v, unsigned int num);
+Inline void vector_ensure(vector v, vector_index i) ;
extern int vector_empty_slot (vector v);
extern int vector_set (vector v, void *val);
-extern int vector_set_index (vector v, unsigned int i, void *val);
-extern void vector_unset (vector v, unsigned int i);
-extern unsigned int vector_count (vector v);
+extern int vector_set_index (vector v, vector_index i, void *val);
+#define vector_unset(v, i) (void)vector_unset_item(v, i)
+extern vector_index vector_count (vector v);
extern void vector_only_wrapper_free (vector v);
extern void vector_only_index_free (void *index);
extern void vector_free (vector v);
extern vector vector_copy (vector v);
-extern void *vector_lookup (vector, unsigned int);
-extern void *vector_lookup_ensure (vector, unsigned int);
+extern void *vector_lookup (vector, vector_index);
+extern void *vector_lookup_ensure (vector, vector_index);
+
+extern vector vector_init_new(vector v, unsigned int size) ;
+extern vector vector_re_init(vector v, unsigned int size) ;
+extern vector vector_reset(vector v, int free_structure) ;
+extern p_vector_item vector_ream(vector v, int free_structure) ;
+
+/* Reset vector and free the vector structure. */
+#define vector_reset_free(v) vector_reset(v, 1)
+/* Reset vector but free the heap structure. */
+#define vector_reset_keep(v) vector_reset(v, 0)
+/* Ream out vector and free the vector structure. */
+#define vector_ream_free(v) vector_ream(v, 1)
+/* Ream out vector but keep the vector structure. */
+#define vector_ream_keep(v) vector_ream(v, 0)
+
+Inline vector_index vector_end(vector v) ;
+Inline int vector_is_empty(vector v) ;
+
+Inline p_vector_item vector_get_item(vector v, vector_index i) ;
+Inline p_vector_item vector_get_first_item(vector v) ;
+Inline p_vector_item vector_get_last_item(vector v) ;
+Inline void vector_set_item(vector v, vector_index i, p_vector_item p_v) ;
+extern p_vector_item vector_unset_item(vector v, vector_index i) ;
+
+extern void vector_insert_item(vector v, vector_index i, p_vector_item p_v) ;
+extern void vector_insert_item_here(vector v, vector_index i, int rider,
+ p_vector_item p_v) ;
+extern void vector_move_item(vector v, vector_index dst, vector_index src) ;
+extern void vector_move_item_here(vector v, vector_index dst, int rider,
+ vector_index src) ;
+extern p_vector_item vector_delete_item(vector v, vector_index i) ;
+extern void vector_reverse(vector v) ;
+extern void vector_part_reverse(vector v, vector_index i, unsigned int n) ;
+
+Inline void vector_push_item(vector v, p_vector_item p_v) ;
+Inline p_vector_item vector_pop_item(vector v) ;
+
+extern void vector_insert(vector v, vector_index i, unsigned int n) ;
+extern void vector_delete(vector v, vector_index i, unsigned int n) ;
+
+typedef int vector_bsearch_cmp(const void** pp_val, const void** item) ;
+vector_index vector_bsearch(vector v, vector_bsearch_cmp* cmp,
+ const void* p_val, int* result) ;
+typedef int vector_sort_cmp(const void** a, const void** b) ;
+void vector_sort(vector v, vector_sort_cmp* cmp) ;
+
+extern vector vector_copy_here(vector dst, vector src) ;
+extern vector vector_move_here(vector dst, vector src) ;
+extern vector vector_copy_append(vector dst, vector src) ;
+extern vector vector_move_append(vector dst, vector src) ;
+
+#define vector_copy_extract(to, src, i_src, n_src) \
+ vector_sak(1, to, NULL, 0, 0, src, i_src, n_src, 0)
+#define vector_move_extract(to, src, i_src, n_src) \
+ vector_sak(1, to, NULL, 0, 0, src, i_src, n_src, 1)
+#define vector_copy_splice(to, dst, i_dst, n_dst, src, i_src, n_src) \
+ vector_sak(1, to, dst, i_dst, n_dst, src, i_src, n_src, 0)
+#define vector_move_splice(to, dst, i_dst, n_dst, src, i_src, n_src) \
+ vector_sak(1, to, dst, i_dst, n_dst, src, i_src, n_src, 1)
+#define vector_copy_replace(dst, i_dst, n_dst, src, i_src, n_src) \
+ vector_sak(0, NULL, dst, i_dst, n_dst, src, i_src, n_src, 0)
+#define vector_move_replace(dst, i_dst, n_dst, src, i_src, n_src) \
+ vector_sak(0, NULL, dst, i_dst, n_dst, src, i_src, n_src, 1)
+
+extern vector vector_sak(int to_copy, vector to,
+ vector dst, vector_index i_dst, unsigned int n_dst,
+ vector src, vector_index i_src, unsigned int n_src, int src_move) ;
+
+extern void vector_discard(vector v, vector_index i) ;
+extern void vector_chop(vector v) ;
+extern void vector_decant(vector v) ;
+
+Inline vector_index vector_extend_by_1(vector v) ;
+extern void vector_extend(vector v, vector_index new_end) ;
+
+/*==============================================================================
+ * The inline functions:
+ */
+
+/* Extend vector by one item at the end, which is about to be set. */
+/* Returns index of new least item in the vector. */
+/* NB: if left unset, the item may be UNDEFINED. */
+Inline vector_index
+vector_extend_by_1(vector v)
+{
+ vector_index i = v->end ;
+
+ if (i < v->limit)
+ return v->end++ ; /* simple if we have room */
+
+ vector_extend(v, i + 1) ; /* the hard way */
+ return i ;
+} ;
+
+/* Ensure given index is "active". */
+/* Adjusts logical and physical end of the vector as required, filling */
+/* with NULLs upto any new logical end. */
+Inline void
+vector_ensure(vector v, vector_index i)
+{
+ if (i < v->end) /* trivial if within vector */
+ return ;
+ if ((i == v->end) && (i < v->limit)) /* simple if end and have room */
+ v->p_items[v->end++] = NULL ; /* set NULL for complete safety */
+ else
+ vector_extend(v, i + 1) ; /* do it the hard way */
+} ;
+
+/* Return index of end of vector (index of last item + 1) */
+Inline vector_index
+vector_end(vector v)
+{
+ return v->end ;
+} ;
+
+/* Returns whether vector is empty or not. */
+Inline int
+vector_is_empty(vector v)
+{
+ return (v->end == 0) ;
+} ;
+
+/* Access functions -- Inline for obvious reasons. */
+
+/* Get pointer to item. Returns NULL if accessing beyond end. */
+Inline p_vector_item
+vector_get_item(vector v, vector_index i)
+{
+ return (i < v->end) ? v->p_items[i] : NULL ;
+} ;
+
+/* Get pointer to first item. Returns NULL if vector empty. */
+Inline p_vector_item
+vector_get_first_item(vector v)
+{
+ return (v->end != 0) ? v->p_items[0] : NULL ;
+} ;
+
+/* Get pointer to last item. Returns NULL if vector empty. */
+Inline p_vector_item
+vector_get_last_item(vector v)
+{
+ return (v->end != 0) ? v->p_items[v->end - 1] : NULL ;
+} ;
+
+/* Set item value in vector. Extend vector if required. */
+/* NB: it is the caller's responsibility to release memory used by any */
+/* current value of the item, if required. */
+Inline void
+vector_set_item(vector v, vector_index i, void* p_v)
+{
+ vector_ensure(v, i) ;
+ v->p_items[i] = (p_vector_item)p_v ;
+} ;
+
+/* Push value onto vector, extending as required. */
+Inline void
+vector_push_item(vector v, void* p_v)
+{
+ vector_index i = vector_extend_by_1(v) ;
+ v->p_items[i] = (p_vector_item)p_v ;
+} ;
+
+/* Pop value from vector. Returns NULL if vector is empty. */
+/* NB: does NOT change the size of the vector body. */
+Inline p_vector_item
+vector_pop_item(vector v)
+{
+ return (v->end > 0) ? v->p_items[--v->end] : NULL ;
+} ;
#endif /* _ZEBRA_VECTOR_H */
diff --git a/lib/vty.c b/lib/vty.c
index e4818eb6..6b627a30 100644
--- a/lib/vty.c
+++ b/lib/vty.c
@@ -17,7 +17,7 @@
* 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.
+ * 02111-1307, USA.
*/
#include <zebra.h>
@@ -38,9 +38,37 @@
#include "network.h"
#include <arpa/telnet.h>
+#include "qpthreads.h"
+#include "qpnexus.h"
+
+/* Needs to be qpthread safe */
+qpt_mutex_t* vty_mutex = NULL;
+#ifdef NDEBUG
+#define LOCK qpt_mutex_lock(vty_mutex);
+#define UNLOCK qpt_mutex_unlock(vty_mutex);
+#else
+int vty_lock_count = 0;
+#define LOCK qpt_mutex_lock(vty_mutex);++vty_lock_count;
+#define UNLOCK --vty_lock_count;qpt_mutex_unlock(vty_mutex);
+#endif
+
+/*
+ * To make vty qpthread safe we use a single mutex. In general external
+ * routines have explicit locks, static routines assume that they are being
+ * called with the mutex already locked. There are a few exceptions, e.g.
+ * callbacks where static routines are being invoked from outside the module.
+ *
+ * As we are not using recursive mutexes so there are a few cases where
+ * both external and static versions of a routine exist. The former for use
+ * outside, the latter for use inside the module (and lock). In these cases
+ * the internal static versions starts uty_.
+ *
+ * vty and log recurse through each other, so the same mutex is used
+ * for both, i.e. they are treated as being part of the same monitor.
+ */
/* Vty events */
-enum event
+enum event
{
VTY_SERV,
VTY_READ,
@@ -53,11 +81,27 @@ enum event
#endif /* VTYSH */
};
+/* Prototypes */
+static int uty_out (struct vty *vty, const char *format, ...);
+static int uty_vout(struct vty *vty, const char *format, va_list args);
static void vty_event (enum event, int, struct vty *);
+static void uty_hello (struct vty *vty);
+static void uty_close (struct vty *vty);
+static int uty_config_unlock (struct vty *vty);
+static int uty_shell (struct vty *vty);
+static int uty_read (struct vty *vty, int vty_sock);
+static int uty_flush (struct vty *vty, int vty_sock);
+static void vty_event_t (enum event event, int sock, struct vty *vty);
+static void vty_event_r (enum event event, int sock, struct vty *vty);
+static int uty_accept (int accept_sock);
+static int uty_timeout (struct vty *vty);
+static void vty_timeout_r (qtimer qtr, void* timer_info, qtime_t when);
+static void vty_read_r (qps_file qf, void* file_info);
+static void vty_flush_r (qps_file qf, void* file_info);
/* Extern host structure from command.c */
extern struct host host;
-
+
/* Vector which store each vty structure. */
static vector vtyvec;
@@ -71,10 +115,10 @@ static char *vty_accesslist_name = NULL;
static char *vty_ipv6_accesslist_name = NULL;
/* VTY server thread. */
-vector Vvty_serv_thread;
+static vector Vvty_serv_thread;
/* Current directory. */
-char *vty_cwd = NULL;
+static char *vty_cwd = NULL;
/* Configure lock. */
static int vty_config;
@@ -89,29 +133,60 @@ static u_char restricted_mode = 0;
/* Integrated configuration file path */
char integrate_default[] = SYSCONFDIR INTEGRATE_DEFAULT_CONFIG;
-
-/* VTY standard output function. */
+/* Master of the threads. */
+static struct thread_master *master = NULL;
+static qpn_nexus master_nexus = NULL;
+
+/* VTY standard output function. vty == NULL or VTY_SHELL => stdout */
int
vty_out (struct vty *vty, const char *format, ...)
{
+ int result;
+
+ LOCK
va_list args;
+ va_start (args, format);
+ result = uty_vout(vty, format, args);
+ va_end (args);
+ UNLOCK
+ return result;
+}
+
+/* internal VTY standard output function. vty == NULL or VTY_SHELL => stdout */
+static int
+uty_out (struct vty *vty, const char *format, ...)
+{
+ int result;
+ assert(vty_lock_count);
+ va_list args;
+ va_start (args, format);
+ result = uty_vout(vty, format, args);
+ va_end (args);
+ return result;
+}
+
+/* internal VTY standard output function. vty == NULL or VTY_SHELL => stdout */
+static int
+uty_vout(struct vty *vty, const char *format, va_list args)
+{
int len = 0;
int size = 1024;
char buf[1024];
char *p = NULL;
+ va_list ac;
+
+ assert(vty_lock_count);
- if (vty_shell (vty))
+ if (uty_shell (vty))
{
- va_start (args, format);
vprintf (format, args);
- va_end (args);
}
else
{
/* Try to write to initial buffer. */
- va_start (args, format);
- len = vsnprintf (buf, sizeof buf, format, args);
- va_end (args);
+ va_copy(ac, args);
+ len = vsnprintf (buf, sizeof buf, format, ac);
+ va_end(ac);
/* Initial buffer is not enough. */
if (len < 0 || len >= size)
@@ -125,11 +200,11 @@ vty_out (struct vty *vty, const char *format, ...)
p = XREALLOC (MTYPE_VTY_OUT_BUF, p, size);
if (! p)
- return -1;
+ return -1;
- va_start (args, format);
- len = vsnprintf (p, size, format, args);
- va_end (args);
+ va_copy(ac, args);
+ len = vsnprintf (p, size, format, ac);
+ va_end(ac);
if (len > -1 && len < size)
break;
@@ -151,6 +226,27 @@ vty_out (struct vty *vty, const char *format, ...)
return len;
}
+int
+vty_puts(struct vty *vty, const char* str)
+{
+ return vty_out(vty, "%s", str) ;
+}
+
+int
+vty_out_newline(struct vty *vty)
+{
+ return vty_out(vty, "%s", VTY_NEWLINE) ;
+}
+
+/* 123456789012345678901234 */
+const char* vty_spaces_string = " " ;
+
+int
+vty_out_indent(struct vty *vty, int indent)
+{
+ return vty_puts(vty, VTY_SPACES(indent)) ;
+}
+
static int
vty_log_out (struct vty *vty, const char *level, const char *proto_str,
const char *format, struct timestamp_control *ctl, va_list va)
@@ -159,9 +255,11 @@ vty_log_out (struct vty *vty, const char *level, const char *proto_str,
int len;
char buf[1024];
+ assert(vty_lock_count);
+
if (!ctl->already_rendered)
{
- ctl->len = quagga_timestamp(ctl->precision, ctl->buf, sizeof(ctl->buf));
+ ctl->len = uquagga_timestamp(ctl->precision, ctl->buf, sizeof(ctl->buf));
ctl->already_rendered = 1;
}
if (ctl->len+1 >= sizeof(buf))
@@ -192,7 +290,7 @@ vty_log_out (struct vty *vty, const char *level, const char *proto_str,
return -1;
/* Fatal I/O error. */
vty->monitor = 0; /* disable monitoring to avoid infinite recursion */
- zlog_warn("%s: write failed to vty client fd %d, closing: %s",
+ uzlog(NULL, LOG_WARNING, "%s: write failed to vty client fd %d, closing: %s",
__func__, vty->fd, safe_strerror(errno));
buffer_reset(vty->obuf);
/* cannot call vty_close, because a parent routine may still try
@@ -209,7 +307,7 @@ void
vty_time_print (struct vty *vty, int cr)
{
char buf [25];
-
+
if (quagga_timestamp(0, buf, sizeof(buf)) == 0)
{
zlog (NULL, LOG_INFO, "quagga_timestamp error");
@@ -227,6 +325,15 @@ vty_time_print (struct vty *vty, int cr)
void
vty_hello (struct vty *vty)
{
+ LOCK
+ uty_hello(vty);
+ UNLOCK
+}
+
+static void
+uty_hello (struct vty *vty)
+{
+ assert(vty_lock_count);
if (host.motdfile)
{
FILE *f;
@@ -242,15 +349,15 @@ vty_hello (struct vty *vty)
for (s = buf + strlen (buf); (s > buf) && isspace ((int)*(s - 1));
s--);
*s = '\0';
- vty_out (vty, "%s%s", buf, VTY_NEWLINE);
+ uty_out (vty, "%s%s", buf, VTY_NEWLINE);
}
fclose (f);
}
else
- vty_out (vty, "MOTD file not found%s", VTY_NEWLINE);
+ uty_out (vty, "MOTD file not found%s", VTY_NEWLINE);
}
else if (host.motd)
- vty_out (vty, host.motd);
+ uty_out (vty, "%s", host.motd);
}
/* Put out prompt and wait input from user. */
@@ -260,6 +367,8 @@ vty_prompt (struct vty *vty)
struct utsname names;
const char*hostname;
+ assert(vty_lock_count);
+
if (vty->type == VTY_TERM)
{
hostname = host.name;
@@ -268,7 +377,7 @@ vty_prompt (struct vty *vty)
uname (&names);
hostname = names.nodename;
}
- vty_out (vty, cmd_prompt (vty->node), hostname);
+ uty_out (vty, cmd_prompt (vty->node), hostname);
}
}
@@ -277,7 +386,8 @@ static void
vty_will_echo (struct vty *vty)
{
unsigned char cmd[] = { IAC, WILL, TELOPT_ECHO, '\0' };
- vty_out (vty, "%s", cmd);
+ assert(vty_lock_count);
+ uty_out (vty, "%s", cmd);
}
/* Make suppress Go-Ahead telnet option. */
@@ -285,7 +395,8 @@ static void
vty_will_suppress_go_ahead (struct vty *vty)
{
unsigned char cmd[] = { IAC, WILL, TELOPT_SGA, '\0' };
- vty_out (vty, "%s", cmd);
+ assert(vty_lock_count);
+ uty_out (vty, "%s", cmd);
}
/* Make don't use linemode over telnet. */
@@ -293,7 +404,8 @@ static void
vty_dont_linemode (struct vty *vty)
{
unsigned char cmd[] = { IAC, DONT, TELOPT_LINEMODE, '\0' };
- vty_out (vty, "%s", cmd);
+ assert(vty_lock_count);
+ uty_out (vty, "%s", cmd);
}
/* Use window size. */
@@ -301,7 +413,8 @@ static void
vty_do_window_size (struct vty *vty)
{
unsigned char cmd[] = { IAC, DO, TELOPT_NAWS, '\0' };
- vty_out (vty, "%s", cmd);
+ assert(vty_lock_count);
+ uty_out (vty, "%s", cmd);
}
#if 0 /* Currently not used. */
@@ -310,21 +423,30 @@ static void
vty_dont_lflow_ahead (struct vty *vty)
{
unsigned char cmd[] = { IAC, DONT, TELOPT_LFLOW, '\0' };
- vty_out (vty, "%s", cmd);
+ assert(vty_lock_count);
+ uty_out (vty, "%s", cmd);
}
#endif /* 0 */
/* Allocate new vty struct. */
struct vty *
-vty_new ()
+vty_new (int fd)
{
- struct vty *new = XCALLOC (MTYPE_VTY, sizeof (struct vty));
+ struct vty *vty = XCALLOC (MTYPE_VTY, sizeof (struct vty));
- new->obuf = buffer_new(0); /* Use default buffer size. */
- new->buf = XCALLOC (MTYPE_VTY, VTY_BUFSIZ);
- new->max = VTY_BUFSIZ;
+ vty->obuf = buffer_new(0); /* Use default buffer size. */
+ vty->buf = XCALLOC (MTYPE_VTY, VTY_BUFSIZ);
+ vty->max = VTY_BUFSIZ;
+ vty->fd = fd;
- return new;
+ if (master_nexus)
+ {
+ vty->qf = qps_file_init_new(vty->qf, NULL);
+ qps_add_file(master_nexus->selection, vty->qf, vty->fd, vty);
+ vty->qtr = qtimer_init_new(vty->qtr, master_nexus->pile, vty_timeout_r, vty);
+ }
+
+ return vty;
}
/* Authentication of vty */
@@ -336,6 +458,8 @@ vty_auth (struct vty *vty, char *buf)
int fail;
char *crypt (const char *, const char *);
+ assert(vty_lock_count);
+
switch (vty->node)
{
case AUTH_NODE:
@@ -379,14 +503,14 @@ vty_auth (struct vty *vty, char *buf)
{
if (vty->node == AUTH_NODE)
{
- vty_out (vty, "%% Bad passwords, too many failures!%s", VTY_NEWLINE);
+ uty_out (vty, "%% Bad passwords, too many failures!%s", VTY_NEWLINE);
vty->status = VTY_CLOSE;
}
- else
+ else
{
/* AUTH_ENABLE_NODE */
vty->fail = 0;
- vty_out (vty, "%% Bad enable passwords, too many failures!%s", VTY_NEWLINE);
+ uty_out (vty, "%% Bad enable passwords, too many failures!%s", VTY_NEWLINE);
vty->node = restricted_mode ? RESTRICTED_NODE : VIEW_NODE;
}
}
@@ -401,6 +525,8 @@ vty_command (struct vty *vty, char *buf)
vector vline;
const char *protocolname;
+ assert(vty_lock_count);
+
/* Split readline string up into the vector */
vline = cmd_make_strvec (buf);
@@ -416,20 +542,19 @@ vty_command (struct vty *vty, char *buf)
GETRUSAGE(&before);
#endif /* CONSUMED_TIME_CHECK */
+ UNLOCK
ret = cmd_execute_command (vline, vty, NULL, 0);
+ LOCK
/* Get the name of the protocol if any */
- if (zlog_default)
- protocolname = zlog_proto_names[zlog_default->protocol];
- else
- protocolname = zlog_proto_names[ZLOG_NONE];
-
+ protocolname = uzlog_get_proto_name(NULL);
+
#ifdef CONSUMED_TIME_CHECK
GETRUSAGE(&after);
if ((realtime = thread_consumed_time(&after, &before, &cputime)) >
CONSUMED_TIME_CHECK)
/* Warn about CPU hog that must be fixed. */
- zlog_warn("SLOW COMMAND: command took %lums (cpu time %lums): %s",
+ uzlog(NULL, LOG_WARNING, "SLOW COMMAND: command took %lums (cpu time %lums): %s",
realtime/1000, cputime/1000, buf);
}
#endif /* CONSUMED_TIME_CHECK */
@@ -439,23 +564,23 @@ vty_command (struct vty *vty, char *buf)
{
case CMD_WARNING:
if (vty->type == VTY_FILE)
- vty_out (vty, "Warning...%s", VTY_NEWLINE);
+ uty_out (vty, "Warning...%s", VTY_NEWLINE);
break;
case CMD_ERR_AMBIGUOUS:
- vty_out (vty, "%% Ambiguous command.%s", VTY_NEWLINE);
+ uty_out (vty, "%% Ambiguous command.%s", VTY_NEWLINE);
break;
case CMD_ERR_NO_MATCH:
- vty_out (vty, "%% [%s] Unknown command: %s%s", protocolname, buf, VTY_NEWLINE);
+ uty_out (vty, "%% [%s] Unknown command: %s%s", protocolname, buf, VTY_NEWLINE);
break;
case CMD_ERR_INCOMPLETE:
- vty_out (vty, "%% Command incomplete.%s", VTY_NEWLINE);
+ uty_out (vty, "%% Command incomplete.%s", VTY_NEWLINE);
break;
}
cmd_free_strvec (vline);
return ret;
}
-
+
static const char telnet_backward_char = 0x08;
static const char telnet_space_char = ' ';
@@ -463,6 +588,7 @@ static const char telnet_space_char = ' ';
static void
vty_write (struct vty *vty, const char *buf, size_t nbytes)
{
+ assert(vty_lock_count);
if ((vty->node == AUTH_NODE) || (vty->node == AUTH_ENABLE_NODE))
return;
@@ -474,6 +600,7 @@ vty_write (struct vty *vty, const char *buf, size_t nbytes)
static void
vty_ensure (struct vty *vty, int length)
{
+ assert(vty_lock_count);
if (vty->max <= length)
{
vty->max *= 2;
@@ -488,6 +615,8 @@ vty_self_insert (struct vty *vty, char c)
int i;
int length;
+ assert(vty_lock_count);
+
vty_ensure (vty, vty->length + 1);
length = vty->length - vty->cp;
memmove (&vty->buf[vty->cp + 1], &vty->buf[vty->cp], length);
@@ -505,6 +634,7 @@ vty_self_insert (struct vty *vty, char c)
static void
vty_self_insert_overwrite (struct vty *vty, char c)
{
+ assert(vty_lock_count);
vty_ensure (vty, vty->length + 1);
vty->buf[vty->cp++] = c;
@@ -521,7 +651,11 @@ vty_self_insert_overwrite (struct vty *vty, char c)
static void
vty_insert_word_overwrite (struct vty *vty, char *str)
{
+
int len = strlen (str);
+
+ assert(vty_lock_count);
+
vty_write (vty, str, len);
strcpy (&vty->buf[vty->cp], str);
vty->cp += len;
@@ -532,6 +666,7 @@ vty_insert_word_overwrite (struct vty *vty, char *str)
static void
vty_forward_char (struct vty *vty)
{
+ assert(vty_lock_count);
if (vty->cp < vty->length)
{
vty_write (vty, &vty->buf[vty->cp], 1);
@@ -543,6 +678,7 @@ vty_forward_char (struct vty *vty)
static void
vty_backward_char (struct vty *vty)
{
+ assert(vty_lock_count);
if (vty->cp > 0)
{
vty->cp--;
@@ -554,6 +690,7 @@ vty_backward_char (struct vty *vty)
static void
vty_beginning_of_line (struct vty *vty)
{
+ assert(vty_lock_count);
while (vty->cp)
vty_backward_char (vty);
}
@@ -562,6 +699,7 @@ vty_beginning_of_line (struct vty *vty)
static void
vty_end_of_line (struct vty *vty)
{
+ assert(vty_lock_count);
while (vty->cp < vty->length)
vty_forward_char (vty);
}
@@ -576,6 +714,8 @@ vty_history_print (struct vty *vty)
{
int length;
+ assert(vty_lock_count);
+
vty_kill_line_from_beginning (vty);
/* Get previous line from history buffer */
@@ -593,6 +733,8 @@ vty_next_line (struct vty *vty)
{
int try_index;
+ assert(vty_lock_count);
+
if (vty->hp == vty->hindex)
return;
@@ -618,6 +760,8 @@ vty_previous_line (struct vty *vty)
{
int try_index;
+ assert(vty_lock_count);
+
try_index = vty->hp;
if (try_index == 0)
try_index = VTY_MAXHIST - 1;
@@ -636,6 +780,7 @@ vty_previous_line (struct vty *vty)
static void
vty_redraw_line (struct vty *vty)
{
+ assert(vty_lock_count);
vty_write (vty, vty->buf, vty->length);
vty->cp = vty->length;
}
@@ -644,9 +789,10 @@ vty_redraw_line (struct vty *vty)
static void
vty_forward_word (struct vty *vty)
{
+ assert(vty_lock_count);
while (vty->cp != vty->length && vty->buf[vty->cp] != ' ')
vty_forward_char (vty);
-
+
while (vty->cp != vty->length && vty->buf[vty->cp] == ' ')
vty_forward_char (vty);
}
@@ -655,6 +801,7 @@ vty_forward_word (struct vty *vty)
static void
vty_backward_pure_word (struct vty *vty)
{
+ assert(vty_lock_count);
while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ')
vty_backward_char (vty);
}
@@ -663,6 +810,7 @@ vty_backward_pure_word (struct vty *vty)
static void
vty_backward_word (struct vty *vty)
{
+ assert(vty_lock_count);
while (vty->cp > 0 && vty->buf[vty->cp - 1] == ' ')
vty_backward_char (vty);
@@ -675,7 +823,8 @@ vty_backward_word (struct vty *vty)
static void
vty_down_level (struct vty *vty)
{
- vty_out (vty, "%s", VTY_NEWLINE);
+ assert(vty_lock_count);
+ uty_out (vty, "%s", VTY_NEWLINE);
(*config_exit_cmd.func)(NULL, vty, 0, NULL);
vty_prompt (vty);
vty->cp = 0;
@@ -685,7 +834,8 @@ vty_down_level (struct vty *vty)
static void
vty_end_config (struct vty *vty)
{
- vty_out (vty, "%s", VTY_NEWLINE);
+ assert(vty_lock_count);
+ uty_out (vty, "%s", VTY_NEWLINE);
switch (vty->node)
{
@@ -713,7 +863,7 @@ vty_end_config (struct vty *vty)
case KEYCHAIN_KEY_NODE:
case MASC_NODE:
case VTY_NODE:
- vty_config_unlock (vty);
+ uty_config_unlock (vty);
vty->node = ENABLE_NODE;
break;
default:
@@ -732,6 +882,8 @@ vty_delete_char (struct vty *vty)
int i;
int size;
+ assert(vty_lock_count);
+
if (vty->length == 0)
{
vty_down_level (vty);
@@ -746,7 +898,7 @@ vty_delete_char (struct vty *vty)
vty->length--;
memmove (&vty->buf[vty->cp], &vty->buf[vty->cp + 1], size - 1);
vty->buf[vty->length] = '\0';
-
+
if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE)
return;
@@ -761,6 +913,7 @@ vty_delete_char (struct vty *vty)
static void
vty_delete_backward_char (struct vty *vty)
{
+ assert(vty_lock_count);
if (vty->cp == 0)
return;
@@ -775,8 +928,10 @@ vty_kill_line (struct vty *vty)
int i;
int size;
+ assert(vty_lock_count);
+
size = vty->length - vty->cp;
-
+
if (size == 0)
return;
@@ -793,6 +948,7 @@ vty_kill_line (struct vty *vty)
static void
vty_kill_line_from_beginning (struct vty *vty)
{
+ assert(vty_lock_count);
vty_beginning_of_line (vty);
vty_kill_line (vty);
}
@@ -801,6 +957,7 @@ vty_kill_line_from_beginning (struct vty *vty)
static void
vty_forward_kill_word (struct vty *vty)
{
+ assert(vty_lock_count);
while (vty->cp != vty->length && vty->buf[vty->cp] == ' ')
vty_delete_char (vty);
while (vty->cp != vty->length && vty->buf[vty->cp] != ' ')
@@ -811,6 +968,7 @@ vty_forward_kill_word (struct vty *vty)
static void
vty_backward_kill_word (struct vty *vty)
{
+ assert(vty_lock_count);
while (vty->cp > 0 && vty->buf[vty->cp - 1] == ' ')
vty_delete_backward_char (vty);
while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ')
@@ -823,6 +981,8 @@ vty_transpose_chars (struct vty *vty)
{
char c1, c2;
+ assert(vty_lock_count);
+
/* If length is short or point is near by the beginning of line then
return. */
if (vty->length < 2 || vty->cp < 1)
@@ -854,11 +1014,14 @@ vty_transpose_chars (struct vty *vty)
static void
vty_complete_command (struct vty *vty)
{
+
int i;
int ret;
char **matched = NULL;
vector vline;
+ assert(vty_lock_count);
+
if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE)
return;
@@ -871,14 +1034,14 @@ vty_complete_command (struct vty *vty)
vector_set (vline, '\0');
matched = cmd_complete_command (vline, vty, &ret);
-
+
cmd_free_strvec (vline);
- vty_out (vty, "%s", VTY_NEWLINE);
+ uty_out (vty, "%s", VTY_NEWLINE);
switch (ret)
{
case CMD_ERR_AMBIGUOUS:
- vty_out (vty, "%% Ambiguous command.%s", VTY_NEWLINE);
+ uty_out (vty, "%% Ambiguous command.%s", VTY_NEWLINE);
vty_prompt (vty);
vty_redraw_line (vty);
break;
@@ -908,11 +1071,11 @@ vty_complete_command (struct vty *vty)
for (i = 0; matched[i] != NULL; i++)
{
if (i != 0 && ((i % 6) == 0))
- vty_out (vty, "%s", VTY_NEWLINE);
- vty_out (vty, "%-10s ", matched[i]);
+ uty_out (vty, "%s", VTY_NEWLINE);
+ uty_out (vty, "%-10s ", matched[i]);
XFREE (MTYPE_TMP, matched[i]);
}
- vty_out (vty, "%s", VTY_NEWLINE);
+ uty_out (vty, "%s", VTY_NEWLINE);
vty_prompt (vty);
vty_redraw_line (vty);
@@ -936,11 +1099,13 @@ vty_describe_fold (struct vty *vty, int cmd_width,
const char *cmd, *p;
int pos;
+ assert(vty_lock_count);
+
cmd = desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd;
if (desc_width <= 0)
{
- vty_out (vty, " %-*s %s%s", cmd_width, cmd, desc->str, VTY_NEWLINE);
+ uty_out (vty, " %-*s %s%s", cmd_width, cmd, desc->str, VTY_NEWLINE);
return;
}
@@ -957,12 +1122,12 @@ vty_describe_fold (struct vty *vty, int cmd_width,
strncpy (buf, p, pos);
buf[pos] = '\0';
- vty_out (vty, " %-*s %s%s", cmd_width, cmd, buf, VTY_NEWLINE);
+ uty_out (vty, " %-*s %s%s", cmd_width, cmd, buf, VTY_NEWLINE);
cmd = "";
}
- vty_out (vty, " %-*s %s%s", cmd_width, cmd, p, VTY_NEWLINE);
+ uty_out (vty, " %-*s %s%s", cmd_width, cmd, p, VTY_NEWLINE);
XFREE (MTYPE_TMP, buf);
}
@@ -971,12 +1136,14 @@ vty_describe_fold (struct vty *vty, int cmd_width,
static void
vty_describe_command (struct vty *vty)
{
- int ret;
+ int ret;
vector vline;
vector describe;
unsigned int i, width, desc_width;
struct desc *desc, *desc_cr = NULL;
+ assert(vty_lock_count);
+
vline = cmd_make_strvec (vty->buf);
/* In case of '> ?'. */
@@ -985,26 +1152,26 @@ vty_describe_command (struct vty *vty)
vline = vector_init (1);
vector_set (vline, '\0');
}
- else
+ else
if (isspace ((int) vty->buf[vty->length - 1]))
vector_set (vline, '\0');
describe = cmd_describe_command (vline, vty, &ret);
- vty_out (vty, "%s", VTY_NEWLINE);
+ uty_out (vty, "%s", VTY_NEWLINE);
/* Ambiguous error. */
switch (ret)
{
case CMD_ERR_AMBIGUOUS:
- vty_out (vty, "%% Ambiguous command.%s", VTY_NEWLINE);
+ uty_out (vty, "%% Ambiguous command.%s", VTY_NEWLINE);
goto out;
break;
case CMD_ERR_NO_MATCH:
- vty_out (vty, "%% There is no matched command.%s", VTY_NEWLINE);
+ uty_out (vty, "%% There is no matched command.%s", VTY_NEWLINE);
goto out;
break;
- }
+ }
/* Get width of command string. */
width = 0;
@@ -1033,7 +1200,7 @@ vty_describe_command (struct vty *vty)
{
if (desc->cmd[0] == '\0')
continue;
-
+
if (strcmp (desc->cmd, command_cr) == 0)
{
desc_cr = desc;
@@ -1041,18 +1208,18 @@ vty_describe_command (struct vty *vty)
}
if (!desc->str)
- vty_out (vty, " %-s%s",
+ uty_out (vty, " %-s%s",
desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
VTY_NEWLINE);
else if (desc_width >= strlen (desc->str))
- vty_out (vty, " %-*s %s%s", width,
+ uty_out (vty, " %-*s %s%s", width,
desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
desc->str, VTY_NEWLINE);
else
vty_describe_fold (vty, width, desc_width, desc);
#if 0
- vty_out (vty, " %-*s %s%s", width
+ uty_out (vty, " %-*s %s%s", width
desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
desc->str ? desc->str : "", VTY_NEWLINE);
#endif /* 0 */
@@ -1061,11 +1228,11 @@ vty_describe_command (struct vty *vty)
if ((desc = desc_cr))
{
if (!desc->str)
- vty_out (vty, " %-s%s",
+ uty_out (vty, " %-s%s",
desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
VTY_NEWLINE);
else if (desc_width >= strlen (desc->str))
- vty_out (vty, " %-*s %s%s", width,
+ uty_out (vty, " %-*s %s%s", width,
desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
desc->str, VTY_NEWLINE);
else
@@ -1084,6 +1251,7 @@ out:
static void
vty_clear_buf (struct vty *vty)
{
+ assert(vty_lock_count);
memset (vty->buf, 0, vty->max);
}
@@ -1091,9 +1259,10 @@ vty_clear_buf (struct vty *vty)
static void
vty_stop_input (struct vty *vty)
{
+ assert(vty_lock_count);
vty->cp = vty->length = 0;
vty_clear_buf (vty);
- vty_out (vty, "%s", VTY_NEWLINE);
+ uty_out (vty, "%s", VTY_NEWLINE);
switch (vty->node)
{
@@ -1116,7 +1285,7 @@ vty_stop_input (struct vty *vty)
case KEYCHAIN_KEY_NODE:
case MASC_NODE:
case VTY_NODE:
- vty_config_unlock (vty);
+ uty_config_unlock (vty);
vty->node = ENABLE_NODE;
break;
default:
@@ -1135,6 +1304,8 @@ vty_hist_add (struct vty *vty)
{
int index;
+ assert(vty_lock_count);
+
if (vty->length == 0)
return;
@@ -1170,46 +1341,48 @@ vty_telnet_option (struct vty *vty, unsigned char *buf, int nbytes)
#ifdef TELNET_OPTION_DEBUG
int i;
+ assert(vty_lock_count);
+
for (i = 0; i < nbytes; i++)
{
switch (buf[i])
{
case IAC:
- vty_out (vty, "IAC ");
+ uty_out (vty, "IAC ");
break;
case WILL:
- vty_out (vty, "WILL ");
+ uty_out (vty, "WILL ");
break;
case WONT:
- vty_out (vty, "WONT ");
+ uty_out (vty, "WONT ");
break;
case DO:
- vty_out (vty, "DO ");
+ uty_out (vty, "DO ");
break;
case DONT:
- vty_out (vty, "DONT ");
+ uty_out (vty, "DONT ");
break;
case SB:
- vty_out (vty, "SB ");
+ uty_out (vty, "SB ");
break;
case SE:
- vty_out (vty, "SE ");
+ uty_out (vty, "SE ");
break;
case TELOPT_ECHO:
- vty_out (vty, "TELOPT_ECHO %s", VTY_NEWLINE);
+ uty_out (vty, "TELOPT_ECHO %s", VTY_NEWLINE);
break;
case TELOPT_SGA:
- vty_out (vty, "TELOPT_SGA %s", VTY_NEWLINE);
+ uty_out (vty, "TELOPT_SGA %s", VTY_NEWLINE);
break;
case TELOPT_NAWS:
- vty_out (vty, "TELOPT_NAWS %s", VTY_NEWLINE);
+ uty_out (vty, "TELOPT_NAWS %s", VTY_NEWLINE);
break;
default:
- vty_out (vty, "%x ", buf[i]);
+ uty_out (vty, "%x ", buf[i]);
break;
}
}
- vty_out (vty, "%s", VTY_NEWLINE);
+ uty_out (vty, "%s", VTY_NEWLINE);
#endif /* TELNET_OPTION_DEBUG */
@@ -1220,7 +1393,7 @@ vty_telnet_option (struct vty *vty, unsigned char *buf, int nbytes)
vty->iac_sb_in_progress = 1;
return 0;
break;
- case SE:
+ case SE:
{
if (!vty->iac_sb_in_progress)
return 0;
@@ -1234,11 +1407,11 @@ vty_telnet_option (struct vty *vty, unsigned char *buf, int nbytes)
{
case TELOPT_NAWS:
if (vty->sb_len != TELNET_NAWS_SB_LEN)
- zlog_warn("RFC 1073 violation detected: telnet NAWS option "
+ uzlog(NULL, LOG_WARNING, "RFC 1073 violation detected: telnet NAWS option "
"should send %d characters, but we received %lu",
TELNET_NAWS_SB_LEN, (u_long)vty->sb_len);
else if (sizeof(vty->sb_buf) < TELNET_NAWS_SB_LEN)
- zlog_err("Bug detected: sizeof(vty->sb_buf) %lu < %d, "
+ uzlog(NULL, LOG_ERR, "Bug detected: sizeof(vty->sb_buf) %lu < %d, "
"too small to handle the telnet NAWS option",
(u_long)sizeof(vty->sb_buf), TELNET_NAWS_SB_LEN);
else
@@ -1246,7 +1419,7 @@ vty_telnet_option (struct vty *vty, unsigned char *buf, int nbytes)
vty->width = ((vty->sb_buf[1] << 8)|vty->sb_buf[2]);
vty->height = ((vty->sb_buf[3] << 8)|vty->sb_buf[4]);
#ifdef TELNET_OPTION_DEBUG
- vty_out(vty, "TELNET NAWS window size negotiation completed: "
+ uty_out(vty, "TELNET NAWS window size negotiation completed: "
"width %d, height %d%s",
vty->width, vty->height, VTY_NEWLINE);
#endif
@@ -1303,6 +1476,7 @@ vty_execute (struct vty *vty)
static void
vty_escape_map (unsigned char c, struct vty *vty)
{
+ assert(vty_lock_count);
switch (c)
{
case ('A'):
@@ -1329,22 +1503,51 @@ vty_escape_map (unsigned char c, struct vty *vty)
static void
vty_buffer_reset (struct vty *vty)
{
+ assert(vty_lock_count);
buffer_reset (vty->obuf);
vty_prompt (vty);
vty_redraw_line (vty);
}
-/* Read data via vty socket. */
+/* Callback: qpthreads., Read data via vty socket. */
+static void
+vty_read_r (qps_file qf, void* file_info)
+{
+ int vty_sock = qf->fd;
+ struct vty *vty = (struct vty *)file_info;
+
+ LOCK
+
+ /* is this necessary? */
+ qps_disable_modes(qf, qps_read_mbit);
+ uty_read(vty, vty_sock);
+
+ UNLOCK
+}
+
+/* Callback: threads. Read data via vty socket. */
static int
vty_read (struct thread *thread)
{
- int i;
- int nbytes;
- unsigned char buf[VTY_READ_BUFSIZ];
-
int vty_sock = THREAD_FD (thread);
struct vty *vty = THREAD_ARG (thread);
+ int result ;
+
+ LOCK
+
vty->t_read = NULL;
+ result = uty_read(vty, vty_sock);
+
+ UNLOCK
+ return result;
+}
+
+static int
+uty_read (struct vty *vty, int vty_sock)
+{
+ int i;
+ int nbytes;
+ unsigned char buf[VTY_READ_BUFSIZ];
/* Read raw data from socket */
if ((nbytes = read (vty->fd, buf, VTY_READ_BUFSIZ)) <= 0)
@@ -1357,14 +1560,14 @@ vty_read (struct thread *thread)
return 0;
}
vty->monitor = 0; /* disable monitoring to avoid infinite recursion */
- zlog_warn("%s: read error on vty client fd %d, closing: %s",
+ uzlog(NULL, LOG_WARNING, "%s: read error on vty client fd %d, closing: %s",
__func__, vty->fd, safe_strerror(errno));
}
buffer_reset(vty->obuf);
vty->status = VTY_CLOSE;
}
- for (i = 0; i < nbytes; i++)
+ for (i = 0; i < nbytes; i++)
{
if (buf[i] == IAC)
{
@@ -1378,7 +1581,7 @@ vty_read (struct thread *thread)
vty->iac = 0;
}
}
-
+
if (vty->iac_sb_in_progress && !vty->iac)
{
if (vty->sb_len < sizeof(vty->sb_buf))
@@ -1396,7 +1599,7 @@ vty_read (struct thread *thread)
i += ret;
continue;
}
-
+
if (vty->status == VTY_MORE)
{
@@ -1505,7 +1708,7 @@ vty_read (struct thread *thread)
break;
case '\n':
case '\r':
- vty_out (vty, "%s", VTY_NEWLINE);
+ uty_out (vty, "%s", VTY_NEWLINE);
vty_execute (vty);
break;
case '\t':
@@ -1535,32 +1738,66 @@ vty_read (struct thread *thread)
/* Check status. */
if (vty->status == VTY_CLOSE)
- vty_close (vty);
+ uty_close (vty);
else
{
vty_event (VTY_WRITE, vty_sock, vty);
vty_event (VTY_READ, vty_sock, vty);
}
+
return 0;
}
-/* Flush buffer to the vty. */
+/* Callback: qpthreads. Flush buffer to the vty. */
+static void
+vty_flush_r (qps_file qf, void* file_info)
+{
+ int vty_sock = qf->fd;
+ struct vty *vty = (struct vty *)file_info;
+
+ LOCK
+
+ qps_disable_modes(qf, qps_write_mbit);
+
+ /* Temporary disable read thread. */
+ if ((vty->lines == 0))
+ {
+ qps_disable_modes(qf, qps_read_mbit);
+ }
+
+ uty_flush(vty, vty_sock);
+
+ UNLOCK
+}
+
+/* Callback: threads. Flush buffer to the vty. */
static int
vty_flush (struct thread *thread)
{
- int erase;
- buffer_status_t flushrc;
int vty_sock = THREAD_FD (thread);
struct vty *vty = THREAD_ARG (thread);
+ int result;
+ LOCK
vty->t_write = NULL;
- /* Tempolary disable read thread. */
+ /* Temporary disable read thread. */
if ((vty->lines == 0) && vty->t_read)
{
thread_cancel (vty->t_read);
vty->t_read = NULL;
}
+ result = uty_flush(vty, vty_sock);
+
+ UNLOCK
+ return result;
+}
+
+static int
+uty_flush (struct vty *vty, int vty_sock)
+{
+ int erase;
+ buffer_status_t flushrc;
/* Function execution continue. */
erase = ((vty->status == VTY_MORE || vty->status == VTY_MORELINE));
@@ -1580,14 +1817,14 @@ vty_flush (struct thread *thread)
{
case BUFFER_ERROR:
vty->monitor = 0; /* disable monitoring to avoid infinite recursion */
- zlog_warn("buffer_flush failed on vty client fd %d, closing",
+ uzlog(NULL, LOG_WARNING, "buffer_flush failed on vty client fd %d, closing",
vty->fd);
buffer_reset(vty->obuf);
- vty_close(vty);
- return 0;
+ uty_close(vty);
+ break;
case BUFFER_EMPTY:
if (vty->status == VTY_CLOSE)
- vty_close (vty);
+ uty_close (vty);
else
{
vty->status = VTY_NORMAL;
@@ -1612,9 +1849,10 @@ vty_create (int vty_sock, union sockunion *su)
{
struct vty *vty;
+ assert(vty_lock_count);
+
/* Allocate new vty structure and set up default values. */
- vty = vty_new ();
- vty->fd = vty_sock;
+ vty = vty_new (vty_sock);
vty->type = VTY_TERM;
vty->address = sockunion_su2str (su);
if (no_password_check)
@@ -1651,17 +1889,17 @@ vty_create (int vty_sock, union sockunion *su)
/* Vty is not available if password isn't set. */
if (host.password == NULL && host.password_encrypt == NULL)
{
- vty_out (vty, "Vty password is not set.%s", VTY_NEWLINE);
+ uty_out (vty, "Vty password is not set.%s", VTY_NEWLINE);
vty->status = VTY_CLOSE;
- vty_close (vty);
+ uty_close (vty);
return NULL;
}
}
/* Say hello to the world. */
- vty_hello (vty);
+ uty_hello (vty);
if (! no_password_check)
- vty_out (vty, "%sUser Access Verification%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
+ uty_out (vty, "%sUser Access Verification%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
/* Setting up terminal. */
vty_will_echo (vty);
@@ -1680,22 +1918,45 @@ vty_create (int vty_sock, union sockunion *su)
return vty;
}
-/* Accept connection from the network. */
+/* Callback: qpthreads. Accept connection from the network. */
+static void
+vty_accept_r (qps_file qf, void* file_info)
+{
+ LOCK
+
+ int accept_sock = qf->fd;
+ uty_accept(accept_sock);
+
+ UNLOCK
+}
+
+/* Callback: threads. Accept connection from the network. */
static int
vty_accept (struct thread *thread)
{
+ int result;
+
+ LOCK
+
+ int accept_sock = THREAD_FD (thread);
+ result = uty_accept(accept_sock);
+
+ UNLOCK
+ return result;
+}
+
+static int
+uty_accept (int accept_sock)
+{
int vty_sock;
struct vty *vty;
union sockunion su;
int ret;
unsigned int on;
- int accept_sock;
struct prefix *p = NULL;
struct access_list *acl = NULL;
char *bufp;
- accept_sock = THREAD_FD (thread);
-
/* We continue hearing vty socket. */
vty_event (VTY_SERV, accept_sock, NULL);
@@ -1705,7 +1966,7 @@ vty_accept (struct thread *thread)
vty_sock = sockunion_accept (accept_sock, &su);
if (vty_sock < 0)
{
- zlog_warn ("can't accept vty socket : %s", safe_strerror (errno));
+ uzlog (NULL, LOG_WARNING, "can't accept vty socket : %s", safe_strerror (errno));
return -1;
}
set_nonblocking(vty_sock);
@@ -1719,16 +1980,15 @@ vty_accept (struct thread *thread)
(access_list_apply (acl, p) == FILTER_DENY))
{
char *buf;
- zlog (NULL, LOG_INFO, "Vty connection refused from %s",
+ uzlog (NULL, LOG_INFO, "Vty connection refused from %s",
(buf = sockunion_su2str (&su)));
free (buf);
close (vty_sock);
-
+
/* continue accepting connections */
vty_event (VTY_SERV, accept_sock, NULL);
-
- prefix_free (p);
+ prefix_free (p);
return 0;
}
}
@@ -1741,28 +2001,27 @@ vty_accept (struct thread *thread)
(access_list_apply (acl, p) == FILTER_DENY))
{
char *buf;
- zlog (NULL, LOG_INFO, "Vty connection refused from %s",
+ uzlog (NULL, LOG_INFO, "Vty connection refused from %s",
(buf = sockunion_su2str (&su)));
free (buf);
close (vty_sock);
-
+
/* continue accepting connections */
vty_event (VTY_SERV, accept_sock, NULL);
-
- prefix_free (p);
+ prefix_free (p);
return 0;
}
}
#endif /* HAVE_IPV6 */
-
+
prefix_free (p);
on = 1;
- ret = setsockopt (vty_sock, IPPROTO_TCP, TCP_NODELAY,
+ ret = setsockopt (vty_sock, IPPROTO_TCP, TCP_NODELAY,
(char *) &on, sizeof (on));
if (ret < 0)
- zlog (NULL, LOG_INFO, "can't set sockopt to vty_sock : %s",
+ uzlog (NULL, LOG_INFO, "can't set sockopt to vty_sock : %s",
safe_strerror (errno));
zlog (NULL, LOG_INFO, "Vty connection from %s",
@@ -1786,6 +2045,8 @@ vty_serv_sock_addrinfo (const char *hostname, unsigned short port)
int sock;
char port_str[BUFSIZ];
+ assert(vty_lock_count);
+
memset (&req, 0, sizeof (struct addrinfo));
req.ai_flags = AI_PASSIVE;
req.ai_family = AF_UNSPEC;
@@ -1827,7 +2088,7 @@ vty_serv_sock_addrinfo (const char *hostname, unsigned short port)
}
ret = listen (sock, 3);
- if (ret < 0)
+ if (ret < 0)
{
close (sock); /* Avoid sd leak. */
continue;
@@ -1841,6 +2102,7 @@ vty_serv_sock_addrinfo (const char *hostname, unsigned short port)
}
#endif /* HAVE_IPV6 && ! NRL */
+#if defined(HAVE_IPV6) && defined(NRL) || !defined(HAVE_IPV6)
/* Make vty server socket. */
static void
vty_serv_sock_family (const char* addr, unsigned short port, int family)
@@ -1850,6 +2112,8 @@ vty_serv_sock_family (const char* addr, unsigned short port, int family)
int accept_sock;
void* naddr=NULL;
+ assert(vty_lock_count);
+
memset (&su, 0, sizeof (union sockunion));
su.sa.sa_family = family;
if(addr)
@@ -1860,18 +2124,18 @@ vty_serv_sock_family (const char* addr, unsigned short port, int family)
#ifdef HAVE_IPV6
case AF_INET6:
naddr=&su.sin6.sin6_addr;
-#endif
+#endif
}
if(naddr)
switch(inet_pton(family,addr,naddr))
{
case -1:
- zlog_err("bad address %s",addr);
+ uzlog(NULL, LOG_ERR, "bad address %s",addr);
naddr=NULL;
break;
case 0:
- zlog_err("error translating address %s: %s",addr,safe_strerror(errno));
+ uzlog(NULL, LOG_ERR, "error translating address %s: %s",addr,safe_strerror(errno));
naddr=NULL;
}
@@ -1888,14 +2152,14 @@ vty_serv_sock_family (const char* addr, unsigned short port, int family)
ret = sockunion_bind (accept_sock, &su, port, naddr);
if (ret < 0)
{
- zlog_warn("can't bind socket");
+ uzlog(NULL, LOG_WARNING, "can't bind socket");
close (accept_sock); /* Avoid sd leak. */
return;
}
/* Listen socket under queue 3. */
ret = listen (accept_sock, 3);
- if (ret < 0)
+ if (ret < 0)
{
zlog (NULL, LOG_WARNING, "can't listen socket");
close (accept_sock); /* Avoid sd leak. */
@@ -1905,6 +2169,7 @@ vty_serv_sock_family (const char* addr, unsigned short port, int family)
/* Add vty server event. */
vty_event (VTY_SERV, accept_sock, NULL);
}
+#endif /* defined(HAVE_IPV6) && defined(NRL) || !defined(HAVE_IPV6) */
#ifdef VTYSH
/* For sockaddr_un. */
@@ -1919,7 +2184,9 @@ vty_serv_un (const char *path)
struct sockaddr_un serv;
mode_t old_mask;
struct zprivs_ids_t ids;
-
+
+ assert(vty_lock_count);
+
/* First of all, unlink existing socket */
unlink (path);
@@ -1930,7 +2197,7 @@ vty_serv_un (const char *path)
sock = socket (AF_UNIX, SOCK_STREAM, 0);
if (sock < 0)
{
- zlog_err("Cannot create unix stream socket: %s", safe_strerror(errno));
+ uzlog(NULL, LOG_ERR, "Cannot create unix stream socket: %s", safe_strerror(errno));
return;
}
@@ -1947,7 +2214,7 @@ vty_serv_un (const char *path)
ret = bind (sock, (struct sockaddr *) &serv, len);
if (ret < 0)
{
- zlog_err("Cannot bind path %s: %s", path, safe_strerror(errno));
+ ulog(NULL, LOG_ERR, "Cannot bind path %s: %s", path, safe_strerror(errno));
close (sock); /* Avoid sd leak. */
return;
}
@@ -1955,7 +2222,7 @@ vty_serv_un (const char *path)
ret = listen (sock, 5);
if (ret < 0)
{
- zlog_err("listen(fd %d) failed: %s", sock, safe_strerror(errno));
+ uzlog(NULL, LOG_ERR, "listen(fd %d) failed: %s", sock, safe_strerror(errno));
close (sock); /* Avoid sd leak. */
return;
}
@@ -1963,13 +2230,13 @@ vty_serv_un (const char *path)
umask (old_mask);
zprivs_get_ids(&ids);
-
+
if (ids.gid_vty > 0)
{
/* set group of socket */
if ( chown (path, -1, ids.gid_vty) )
{
- zlog_err ("vty_serv_un: could chown socket, %s",
+ uzlog (NULL, LOG_ERR, "vty_serv_un: could chown socket, %s",
safe_strerror (errno) );
}
}
@@ -1979,16 +2246,36 @@ vty_serv_un (const char *path)
/* #define VTYSH_DEBUG 1 */
+/* Callback: qpthreads. Accept connection */
+void int
+vtysh_accept_r (qps_file qf, void* file_info)
+{
+ int accept_sock = qf->fd;
+ LOCK
+ utysh_accept (accept_sock);
+ UNLOCK
+}
+
+/* Callback: threads. Accept connection */
static int
vtysh_accept (struct thread *thread)
{
- int accept_sock;
+ int accept_sock = THREAD_FD (thread);
+ LOCK
+ result = utysh_accept (accept_sock);
+ UNLOCK
+ return result;
+}
+
+static int
+utysh_accept (int accept_sock)
+{
int sock;
int client_len;
struct sockaddr_un client;
struct vty *vty;
-
- accept_sock = THREAD_FD (thread);
+
+ assert(vty_lock_count);
vty_event (VTYSH_SERV, accept_sock, NULL);
@@ -2000,18 +2287,18 @@ vtysh_accept (struct thread *thread)
if (sock < 0)
{
- zlog_warn ("can't accept vty socket : %s", safe_strerror (errno));
+ uzlog (NULL, LOG_WARNING, "can't accept vty socket : %s", safe_strerror (errno));
return -1;
}
if (set_nonblocking(sock) < 0)
{
- zlog_warn ("vtysh_accept: could not set vty socket %d to non-blocking,"
+ uzlog (NULL, LOG_WARNING, "vtysh_accept: could not set vty socket %d to non-blocking,"
" %s, closing", sock, safe_strerror (errno));
close (sock);
return -1;
}
-
+
#ifdef VTYSH_DEBUG
printf ("VTY shell accept\n");
#endif /* VTYSH_DEBUG */
@@ -2029,6 +2316,8 @@ vtysh_accept (struct thread *thread)
static int
vtysh_flush(struct vty *vty)
{
+ assert(vty_lock_count);
+
switch (buffer_flush_available(vty->obuf, vty->fd))
{
case BUFFER_PENDING:
@@ -2036,9 +2325,9 @@ vtysh_flush(struct vty *vty)
break;
case BUFFER_ERROR:
vty->monitor = 0; /* disable monitoring to avoid infinite recursion */
- zlog_warn("%s: write error to fd %d, closing", __func__, vty->fd);
+ uzlog(NULL, LOG_WARNING, "%s: write error to fd %d, closing", __func__, vty->fd);
buffer_reset(vty->obuf);
- vty_close(vty);
+ uty_close(vty);
return -1;
break;
case BUFFER_EMPTY:
@@ -2047,21 +2336,48 @@ vtysh_flush(struct vty *vty)
return 0;
}
+/* Callback: qpthreads., Read data via vty socket. */
+static void
+vtysh_read_r (qps_file qf, void* file_info)
+{
+ int vty_sock = qf->fd;
+ struct vty *vty = (struct vty *)file_info;
+
+ LOCK
+
+ /* is this necessary? */
+ qps_disable_modes(qf, qps_read_mbit);
+ utysh_read(vty, vty_soc);
+
+ UNLOCK
+}
+
+/* Callback: threads. Read data via vty socket. */
static int
vtysh_read (struct thread *thread)
{
+ int vty_sock = THREAD_FD (thread);
+ struct vty *vty = THREAD_ARG (thread);
+ int result;
+
+ LOCK
+
+ vty->t_read = NULL;
+ result = uty_read(vty, vty_soc);
+
+ UNLOCK
+ return result;
+}
+
+static int
+utysh_read (struct vty *vty, int sock)
+{
int ret;
- int sock;
int nbytes;
- struct vty *vty;
unsigned char buf[VTY_READ_BUFSIZ];
unsigned char *p;
u_char header[4] = {0, 0, 0, 0};
- sock = THREAD_FD (thread);
- vty = THREAD_ARG (thread);
- vty->t_read = NULL;
-
if ((nbytes = read (sock, buf, VTY_READ_BUFSIZ)) <= 0)
{
if (nbytes < 0)
@@ -2072,11 +2388,11 @@ vtysh_read (struct thread *thread)
return 0;
}
vty->monitor = 0; /* disable monitoring to avoid infinite recursion */
- zlog_warn("%s: read failed on vtysh client fd %d, closing: %s",
+ uzlog(NULL, LOG_WARNING, "%s: read failed on vtysh client fd %d, closing: %s",
__func__, sock, safe_strerror(errno));
}
buffer_reset(vty->obuf);
- vty_close (vty);
+ uty_close (vty);
#ifdef VTYSH_DEBUG
printf ("close vtysh\n");
#endif /* VTYSH_DEBUG */
@@ -2118,13 +2434,32 @@ vtysh_read (struct thread *thread)
return 0;
}
+/* Callback: qpthraeds. Write */
+static void
+vtysh_write_r (qps_file qf, void* file_info)
+{
+ struct vty *vty = (struct vty *)file_info;
+
+ LOCK
+
+ qps_disable_modes(qf, qps_write_mbit);
+ vtysh_flush(vty);
+
+ UNLOCK
+}
+
+//* Callback: thraeds. Write */
static int
vtysh_write (struct thread *thread)
{
struct vty *vty = THREAD_ARG (thread);
+ LOCK
+
vty->t_write = NULL;
vtysh_flush(vty);
+
+ UNLOCK
return 0;
}
@@ -2134,6 +2469,8 @@ vtysh_write (struct thread *thread)
void
vty_serv_sock (const char *addr, unsigned short port, const char *path)
{
+ LOCK
+
/* If port is set to 0, do not listen on TCP/IP at all! */
if (port)
{
@@ -2153,6 +2490,8 @@ vty_serv_sock (const char *addr, unsigned short port, const char *path)
#ifdef VTYSH
vty_serv_un (path);
#endif /* VTYSH */
+
+ UNLOCK
}
/* Close vty interface. Warning: call this only from functions that
@@ -2162,8 +2501,18 @@ vty_serv_sock (const char *addr, unsigned short port, const char *path)
void
vty_close (struct vty *vty)
{
+ LOCK
+ uty_close(vty);
+ UNLOCK
+}
+
+static void
+uty_close (struct vty *vty)
+{
int i;
+ assert(vty_lock_count);
+
/* Cancel threads.*/
if (vty->t_read)
thread_cancel (vty->t_read);
@@ -2171,6 +2520,17 @@ vty_close (struct vty *vty)
thread_cancel (vty->t_write);
if (vty->t_timeout)
thread_cancel (vty->t_timeout);
+ if (vty->qf)
+ {
+ qps_remove_file(vty->qf);
+ qps_file_free(vty->qf);
+ vty->qf = NULL;
+ }
+ if (vty->qtr)
+ {
+ qtimer_free(vty->qtr);
+ vty->qtr = NULL;
+ }
/* Flush buffer. */
buffer_flush_all (vty->obuf, vty->fd);
@@ -2196,29 +2556,48 @@ vty_close (struct vty *vty)
XFREE (MTYPE_VTY, vty->buf);
/* Check configure. */
- vty_config_unlock (vty);
+ uty_config_unlock (vty);
/* OK free vty. */
XFREE (MTYPE_VTY, vty);
}
-/* When time out occur output message then close connection. */
+/* Callback: qpthreads. When time out occur output message then close connection. */
+static void
+vty_timeout_r (qtimer qtr, void* timer_info, qtime_t when)
+{
+ struct vty *vty = (struct vty *)timer_info;
+ LOCK
+ qtimer_unset(qtr);
+ uty_timeout(vty);
+ UNLOCK
+}
+
+/* Callback: threads. When time out occur output message then close connection. */
static int
vty_timeout (struct thread *thread)
{
- struct vty *vty;
-
- vty = THREAD_ARG (thread);
+ int result;
+ struct vty *vty = THREAD_ARG (thread);
+ LOCK
vty->t_timeout = NULL;
+ result = uty_timeout(vty);
+ UNLOCK
+ return result;
+}
+
+static int
+uty_timeout (struct vty *vty)
+{
vty->v_timeout = 0;
/* Clear buffer*/
buffer_reset (vty->obuf);
- vty_out (vty, "%sVty connection is timed out.%s", VTY_NEWLINE, VTY_NEWLINE);
+ uty_out (vty, "%sVty connection is timed out.%s", VTY_NEWLINE, VTY_NEWLINE);
/* Close connection. */
vty->status = VTY_CLOSE;
- vty_close (vty);
+ uty_close (vty);
return 0;
}
@@ -2230,15 +2609,16 @@ vty_read_file (FILE *confp)
int ret;
struct vty *vty;
- vty = vty_new ();
- vty->fd = 0; /* stdout */
+ vty = vty_new (0); /* stdout */
vty->type = VTY_TERM;
vty->node = CONFIG_NODE;
-
+
/* Execute configuration file */
ret = config_from_file (vty, confp);
- if ( !((ret == CMD_SUCCESS) || (ret == CMD_ERR_NOTHING_TODO)) )
+ LOCK
+
+ if ( !((ret == CMD_SUCCESS) || (ret == CMD_ERR_NOTHING_TODO)) )
{
switch (ret)
{
@@ -2249,13 +2629,14 @@ vty_read_file (FILE *confp)
fprintf (stderr, "There is no such command.\n");
break;
}
- fprintf (stderr, "Error occured during reading below line.\n%s\n",
+ fprintf (stderr, "Error occured during reading below line.\n%s\n",
vty->buf);
- vty_close (vty);
+ uty_close (vty);
exit (1);
}
- vty_close (vty);
+ uty_close (vty);
+ UNLOCK
}
static FILE *
@@ -2267,7 +2648,7 @@ vty_use_backup_config (char *fullpath)
int tmp, sav;
int c;
char buffer[512];
-
+
fullpath_sav = malloc (strlen (fullpath) + strlen (CONF_BACKUP_EXT) + 1);
strcpy (fullpath_sav, fullpath);
strcat (fullpath_sav, CONF_BACKUP_EXT);
@@ -2279,7 +2660,7 @@ vty_use_backup_config (char *fullpath)
fullpath_tmp = malloc (strlen (fullpath) + 8);
sprintf (fullpath_tmp, "%s.XXXXXX", fullpath);
-
+
/* Open file to configuration write. */
tmp = mkstemp (fullpath_tmp);
if (tmp < 0)
@@ -2297,13 +2678,13 @@ vty_use_backup_config (char *fullpath)
free (fullpath_tmp);
return NULL;
}
-
+
while((c = read (sav, buffer, 512)) > 0)
write (tmp, buffer, c);
-
+
close (sav);
close (tmp);
-
+
if (chmod(fullpath_tmp, CONFIGFILE_MASK) != 0)
{
unlink (fullpath_tmp);
@@ -2311,12 +2692,12 @@ vty_use_backup_config (char *fullpath)
free (fullpath_tmp);
return NULL;
}
-
+
if (link (fullpath_tmp, fullpath) == 0)
ret = fopen (fullpath, "r");
unlink (fullpath_tmp);
-
+
free (fullpath_sav);
free (fullpath_tmp);
return ret;
@@ -2338,7 +2719,7 @@ vty_read_config (char *config_file,
if (! IS_DIRECTORY_SEP (config_file[0]))
{
getcwd (cwd, MAXPATHLEN);
- tmp = XMALLOC (MTYPE_TMP,
+ tmp = XMALLOC (MTYPE_TMP,
strlen (cwd) + strlen (config_file) + 2);
sprintf (tmp, "%s/%s", cwd, config_file);
fullpath = tmp;
@@ -2352,13 +2733,13 @@ vty_read_config (char *config_file,
{
fprintf (stderr, "%s: failed to open configuration file %s: %s\n",
__func__, fullpath, safe_strerror (errno));
-
+
confp = vty_use_backup_config (fullpath);
if (confp)
fprintf (stderr, "WARNING: using backup configuration file!\n");
else
{
- fprintf (stderr, "can't open configuration file [%s]\n",
+ fprintf (stderr, "can't open configuration file [%s]\n",
config_file);
exit(1);
}
@@ -2388,7 +2769,7 @@ vty_read_config (char *config_file,
{
ret = stat (integrate_default, &conf_stat);
if (ret >= 0)
- return;
+ return;
}
#endif /* VTYSH */
@@ -2397,7 +2778,7 @@ vty_read_config (char *config_file,
{
fprintf (stderr, "%s: failed to open configuration file %s: %s\n",
__func__, config_default_dir, safe_strerror (errno));
-
+
confp = vty_use_backup_config (config_default_dir);
if (confp)
{
@@ -2410,7 +2791,7 @@ vty_read_config (char *config_file,
config_default_dir);
exit (1);
}
- }
+ }
else
fullpath = config_default_dir;
}
@@ -2420,7 +2801,7 @@ vty_read_config (char *config_file,
fclose (confp);
host_config_set (fullpath);
-
+
if (tmp)
XFREE (MTYPE_TMP, fullpath);
}
@@ -2432,19 +2813,20 @@ vty_log (const char *level, const char *proto_str,
{
unsigned int i;
struct vty *vty;
-
+
+ assert(vty_lock_count);
+
if (!vtyvec)
return;
- for (i = 0; i < vector_active (vtyvec); i++)
- if ((vty = vector_slot (vtyvec, i)) != NULL)
- if (vty->monitor)
- {
- va_list ac;
- va_copy(ac, va);
- vty_log_out (vty, level, proto_str, format, ctl, ac);
- va_end(ac);
- }
+ for (i = 0; i < vector_active (vtyvec); i++)
+ if (((vty = vector_slot (vtyvec, i)) != NULL) && vty->monitor)
+ {
+ va_list ac;
+ va_copy(ac, va);
+ vty_log_out (vty, level, proto_str, format, ctl, ac);
+ va_end(ac);
+ }
}
/* Async-signal-safe version of vty_log for fixed strings. */
@@ -2457,7 +2839,7 @@ vty_log_fixed (const char *buf, size_t len)
/* vty may not have been initialised */
if (!vtyvec)
return;
-
+
iov[0].iov_base = (void *)buf;
iov[0].iov_len = len;
iov[1].iov_base = (void *)"\r\n";
@@ -2476,17 +2858,32 @@ vty_log_fixed (const char *buf, size_t len)
int
vty_config_lock (struct vty *vty)
{
+ int result;
+ LOCK
if (vty_config == 0)
{
vty->config = 1;
vty_config = 1;
}
- return vty->config;
+ result = vty->config;
+ UNLOCK
+ return result;
}
int
vty_config_unlock (struct vty *vty)
{
+ int result;
+ LOCK
+ result = uty_config_unlock(vty);
+ UNLOCK
+ return result;
+}
+
+static int
+uty_config_unlock (struct vty *vty)
+{
+ assert(vty_lock_count);
if (vty_config == 1 && vty->config == 1)
{
vty->config = 0;
@@ -2494,15 +2891,24 @@ vty_config_unlock (struct vty *vty)
}
return vty->config;
}
-
-/* Master of the threads. */
-static struct thread_master *master;
static void
vty_event (enum event event, int sock, struct vty *vty)
{
+ if (master_nexus)
+ vty_event_r(event, sock, vty);
+ else
+ vty_event_t(event, sock, vty);
+}
+
+/* thread event setter */
+static void
+vty_event_t (enum event event, int sock, struct vty *vty)
+ {
struct thread *vty_serv_thread;
+ assert(vty_lock_count);
+
switch (event)
{
case VTY_SERV:
@@ -2528,14 +2934,14 @@ vty_event (enum event event, int sock, struct vty *vty)
{
if (vty->t_timeout)
thread_cancel (vty->t_timeout);
- vty->t_timeout =
+ vty->t_timeout =
thread_add_timer (master, vty_timeout, vty, vty->v_timeout);
}
break;
case VTY_WRITE:
if (! vty->t_write)
vty->t_write = thread_add_write (master, vty_flush, vty, sock);
- break;
+ break;
case VTY_TIMEOUT_RESET:
if (vty->t_timeout)
{
@@ -2544,13 +2950,77 @@ vty_event (enum event event, int sock, struct vty *vty)
}
if (vty->v_timeout)
{
- vty->t_timeout =
+ vty->t_timeout =
thread_add_timer (master, vty_timeout, vty, vty->v_timeout);
}
break;
}
}
-
+
+/* qpthreads event setter */
+static void
+vty_event_r (enum event event, int sock, struct vty *vty)
+ {
+
+ qps_file accept_file = NULL;
+
+ assert(vty_lock_count);
+
+ switch (event)
+ {
+ case VTY_SERV:
+ accept_file = vector_get_item(Vvty_serv_thread, sock);
+ if (accept_file == NULL)
+ {
+ accept_file = qps_file_init_new(accept_file, NULL);
+ qps_add_file(master_nexus->selection, accept_file, sock, NULL);
+ vector_set_index(Vvty_serv_thread, sock, accept_file);
+ }
+ qps_enable_mode(accept_file, qps_read_mnum, vty_accept_r) ;
+ break;
+#ifdef VTYSH
+ case VTYSH_SERV:
+ accept_file = vector_get_item(Vvty_serv_thread, sock);
+ if (accept_file == NULL)
+ {
+ accept_file = qps_file_init_new(accept_file, NULL);
+ qps_add_file(master, accept_file, sock, NULL);
+ vector_set_index(Vvty_serv_thread, sock, accept_file);
+ }
+ qps_enable_mode(accept_file, qps_read_mnum, vtysh_accept_r) ;
+ break;
+ case VTYSH_READ:
+ qps_enable_mode(vty->file, qps_read_mnum, vtysh_read_r) ;
+ break;
+ case VTYSH_WRITE:
+ qps_enable_mode(vty->file, qps_write_mnum, vtysh_write_r) ;
+ break;
+#endif /* VTYSH */
+ case VTY_READ:
+ qps_enable_mode(vty->qf, qps_read_mnum, vty_read_r) ;
+
+ /* Time out treatment. */
+ if (vty->v_timeout)
+ {
+ qtimer_set(vty->qtr, qt_add_monotonic(QTIME(vty->v_timeout)), NULL) ;
+ }
+ break;
+ case VTY_WRITE:
+ qps_enable_mode(vty->qf, qps_write_mnum, vty_flush_r) ;
+ break;
+ case VTY_TIMEOUT_RESET:
+ if (vty->v_timeout)
+ {
+ qtimer_set(vty->qtr, qt_add_monotonic(QTIME(vty->v_timeout)), NULL) ;
+ }
+ else
+ {
+ qtimer_unset(vty->qtr);
+ }
+ break;
+ }
+}
+
DEFUN (config_who,
config_who_cmd,
"who",
@@ -2584,6 +3054,8 @@ exec_timeout (struct vty *vty, const char *min_str, const char *sec_str)
{
unsigned long timeout = 0;
+ LOCK
+
/* min_str and sec_str are already checked by parser. So it must be
all digit string. */
if (min_str)
@@ -2598,7 +3070,7 @@ exec_timeout (struct vty *vty, const char *min_str, const char *sec_str)
vty->v_timeout = timeout;
vty_event (VTY_TIMEOUT_RESET, 0, vty);
-
+ UNLOCK
return CMD_SUCCESS;
}
@@ -2839,14 +3311,14 @@ vty_config_write (struct vty *vty)
/* exec-timeout */
if (vty_timeout_val != VTY_TIMEOUT_DEFAULT)
- vty_out (vty, " exec-timeout %ld %ld%s",
+ vty_out (vty, " exec-timeout %ld %ld%s",
vty_timeout_val / 60,
vty_timeout_val % 60, VTY_NEWLINE);
/* login */
if (no_password_check)
vty_out (vty, " no login%s", VTY_NEWLINE);
-
+
if (restricted_mode != restricted_mode_default)
{
if (restricted_mode_default)
@@ -2854,7 +3326,7 @@ vty_config_write (struct vty *vty)
else
vty_out (vty, " anonymous restricted%s", VTY_NEWLINE);
}
-
+
vty_out (vty, "!%s", VTY_NEWLINE);
return CMD_SUCCESS;
@@ -2874,22 +3346,40 @@ vty_reset ()
unsigned int i;
struct vty *vty;
struct thread *vty_serv_thread;
+ qps_file qf;
+
+ LOCK
for (i = 0; i < vector_active (vtyvec); i++)
if ((vty = vector_slot (vtyvec, i)) != NULL)
{
buffer_reset (vty->obuf);
vty->status = VTY_CLOSE;
- vty_close (vty);
+ uty_close (vty);
}
- for (i = 0; i < vector_active (Vvty_serv_thread); i++)
- if ((vty_serv_thread = vector_slot (Vvty_serv_thread, i)) != NULL)
- {
- thread_cancel (vty_serv_thread);
- vector_slot (Vvty_serv_thread, i) = NULL;
- close (i);
- }
+ if (master_nexus)
+ {
+ for (i = 0; i < vector_active (Vvty_serv_thread); i++)
+ if ((qf = vector_slot (Vvty_serv_thread, i)) != NULL)
+ {
+ qps_remove_file(qf);
+ qps_file_free(qf);
+ vector_slot (Vvty_serv_thread, i) = NULL;
+ close (i);
+ }
+ }
+ else
+ {
+ assert(master);
+ for (i = 0; i < vector_active (Vvty_serv_thread); i++)
+ if ((vty_serv_thread = vector_slot (Vvty_serv_thread, i)) != NULL)
+ {
+ thread_cancel (vty_serv_thread);
+ vector_slot (Vvty_serv_thread, i) = NULL;
+ close (i);
+ }
+ }
vty_timeout_val = VTY_TIMEOUT_DEFAULT;
@@ -2904,6 +3394,7 @@ vty_reset ()
XFREE(MTYPE_VTY, vty_ipv6_accesslist_name);
vty_ipv6_accesslist_name = NULL;
}
+ UNLOCK
}
static void
@@ -2933,34 +3424,69 @@ vty_get_cwd ()
int
vty_shell (struct vty *vty)
{
- return vty->type == VTY_SHELL ? 1 : 0;
+ LOCK
+ int result;
+ result = uty_shell (vty);
+ UNLOCK
+ return result;
+}
+
+static int
+uty_shell (struct vty *vty)
+{
+ return ((vty == NULL) || (vty->type == VTY_SHELL)) ? 1 : 0;
}
int
vty_shell_serv (struct vty *vty)
{
- return vty->type == VTY_SHELL_SERV ? 1 : 0;
+ LOCK
+ int result;
+ result = ((vty->type == VTY_SHELL_SERV) ? 1 : 0);
+ UNLOCK
+ return result;
}
void
vty_init_vtysh ()
{
- vtyvec = vector_init (VECTOR_MIN_SIZE);
+ LOCK
+ vtyvec = vector_init (0);
+ UNLOCK
+}
+
+/* qpthreads: Install vty's own commands like `who' command. */
+void
+vty_init_r (void)
+{
+ master_nexus = qpn_init_new(master_nexus);
+ vty_mutex = qpt_mutex_init(vty_mutex, qpt_mutex_quagga);
+ vty_init(NULL);
}
-/* Install vty's own commands like `who' command. */
+/* create and execute our thread */
+void
+vty_exec_r(void)
+{
+ if (master_nexus)
+ qpn_exec(master_nexus);
+}
+
+/* threads: Install vty's own commands like `who' command. */
void
vty_init (struct thread_master *master_thread)
{
+ LOCK
+
/* For further configuration read, preserve current directory. */
vty_save_cwd ();
- vtyvec = vector_init (VECTOR_MIN_SIZE);
+ vtyvec = vector_init (0);
master = master_thread;
/* Initilize server thread vector. */
- Vvty_serv_thread = vector_init (VECTOR_MIN_SIZE);
+ Vvty_serv_thread = vector_init (0);
/* Install bgp top node. */
install_node (&vty_node, vty_config_write);
@@ -2993,11 +3519,18 @@ vty_init (struct thread_master *master_thread)
install_element (VTY_NODE, &vty_ipv6_access_class_cmd);
install_element (VTY_NODE, &no_vty_ipv6_access_class_cmd);
#endif /* HAVE_IPV6 */
+
+ UNLOCK
}
void
vty_terminate (void)
{
+ LOCK
+
+ if (master_nexus)
+ master_nexus->terminate = 1;
+
if (vty_cwd)
XFREE (MTYPE_TMP, vty_cwd);
@@ -3007,4 +3540,11 @@ vty_terminate (void)
vector_free (vtyvec);
vector_free (Vvty_serv_thread);
}
+ UNLOCK
+
+ if (vty_mutex)
+ vty_mutex = qpt_mutex_destroy(vty_mutex, 1);
}
+
+#undef LOCK
+#undef UNLOCK
diff --git a/lib/vty.h b/lib/vty.h
index 7df04b5f..457c70d4 100644
--- a/lib/vty.h
+++ b/lib/vty.h
@@ -23,14 +23,17 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "thread.h"
#include "log.h"
+#include "qpthreads.h"
+#include "qpselect.h"
+#include "qtimers.h"
#define VTY_BUFSIZ 512
#define VTY_MAXHIST 20
/* VTY struct. */
-struct vty
+struct vty
{
- /* File descripter of this vty. */
+ /* File descriptor of this vty. */
int fd;
/* Is this vty connect to file or not */
@@ -39,7 +42,7 @@ struct vty
/* Node status of this vty */
int node;
- /* What address is this vty comming from. */
+ /* What address is this vty coming from. */
char *address;
/* Failure count */
@@ -112,11 +115,14 @@ struct vty
int config;
/* Read and write thread. */
+
+ qps_file qf;
struct thread *t_read;
struct thread *t_write;
/* Timeout seconds and thread. */
unsigned long v_timeout;
+ qtimer qtr;
struct thread *t_timeout;
};
@@ -124,7 +130,13 @@ struct vty
#define INTEGRATE_DEFAULT_CONFIG "Quagga.conf"
/* Small macro to determine newline is newline only or linefeed needed. */
-#define VTY_NEWLINE ((vty->type == VTY_TERM) ? "\r\n" : "\n")
+#define VTY_NEWLINE (((vty != NULL) && (vty->type == VTY_TERM)) ? "\r\n" : "\n")
+
+/* For indenting, mostly. */
+extern const char* vty_spaces_string ;
+#define VTY_MAX_SPACES 24
+#define VTY_SPACES(n) (vty_spaces_string + ((n) < VTY_MAX_SPACES \
+ ? VTY_MAX_SPACES - (n) : 0))
/* Default time out value */
#define VTY_TIMEOUT_DEFAULT 600
@@ -199,20 +211,29 @@ do {
/* Exported variables */
extern char integrate_default[];
+extern qpt_mutex_t* vty_mutex;
+#ifndef NDEBUG
+extern int vty_lock_count;
+#endif
/* Prototypes. */
+extern void vty_init_r (void);
+extern void vty_exec_r(void);
extern void vty_init (struct thread_master *);
extern void vty_init_vtysh (void);
extern void vty_terminate (void);
extern void vty_reset (void);
-extern struct vty *vty_new (void);
+extern struct vty *vty_new (int);
extern int vty_out (struct vty *, const char *, ...) PRINTF_ATTRIBUTE(2, 3);
+extern int vty_puts(struct vty* vty, const char* str) ;
+extern int vty_out_newline(struct vty *vty) ;
+extern int vty_out_indent(struct vty *vty, int indent) ;
extern void vty_read_config (char *, char *);
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 *);
diff --git a/lib/zassert.h b/lib/zassert.h
index 79126760..424688b9 100644
--- a/lib/zassert.h
+++ b/lib/zassert.h
@@ -8,6 +8,18 @@
extern void _zlog_assert_failed (const char *assertion, const char *file,
unsigned int line, const char *function)
__attribute__ ((noreturn));
+extern void _zlog_abort_mess (const char *mess, const char *file,
+ unsigned int line, const char *function)
+ __attribute__ ((noreturn));
+
+extern void _zlog_abort_errno (const char *mess, const char *file,
+ unsigned int line, const char *function)
+ __attribute__ ((noreturn));
+
+extern void _zlog_abort_err (const char *mess, int err, const char *file,
+ unsigned int line, const char *function)
+ __attribute__ ((noreturn));
+
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
#define __ASSERT_FUNCTION __func__
@@ -21,7 +33,45 @@ extern void _zlog_assert_failed (const char *assertion, const char *file,
(_zlog_assert_failed(#EX, __FILE__, __LINE__, \
__ASSERT_FUNCTION), 0)))
+/* Implicitly *permanent* assert() -- irrespective of NDEBUG */
#undef assert
#define assert(EX) zassert(EX)
+/* Explicitly permanent assert() */
+#define passert(EX) zassert(EX)
+
+/* NDEBUG time assert() */
+#ifndef NDEBUG
+#define dassert(EX) zassert(EX)
+#else
+#define dassert(EX)
+#endif
+
+/* TODO: implement _zlog_abort() to give required messages */
+
+/* Abort with message */
+#define zabort(MS) _zlog_assert_failed(MS, __FILE__, __LINE__, \
+ __ASSERT_FUNCTION)
+
+/* Abort with message and errno and strerror() thereof */
+#define zabort_errno(MS) _zlog_abort_errno(MS, __FILE__, __LINE__, \
+ __ASSERT_FUNCTION)
+
+/* Abort with message and given error and strerror() thereof */
+#define zabort_err(MS, ERR) _zlog_abort_err(MS, ERR, __FILE__, __LINE__, \
+ __ASSERT_FUNCTION)
+
+/*==============================================================================
+ * Compile time CONFIRM gizmo
+ *
+ * Two forms: CONFIRM(e) for use at top (file) level
+ * confirm(e) for use inside compound statements
+ */
+#ifndef CONFIRM
+
+ #define CONFIRM(e) extern void CONFIRMATION(char CONFIRM[(e) ? 1 : -1]) ;
+ #define confirm(e) { CONFIRM(e) }
+
+#endif
+
#endif /* _QUAGGA_ASSERT_H */
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 4ab507bb..33861328 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -6,7 +6,7 @@ AM_LDFLAGS = $(PILDFLAGS)
noinst_PROGRAMS = testsig testbuffer testmemory heavy heavywq heavythread \
aspathtest testprivs teststream testbgpcap ecommtest \
- testbgpmpattr testchecksum
+ testbgpmpattr testchecksum testvector testsymtab
testsig_SOURCES = test-sig.c
testbuffer_SOURCES = test-buffer.c
@@ -21,6 +21,8 @@ testbgpcap_SOURCES = bgp_capability_test.c
ecommtest_SOURCES = ecommunity_test.c
testbgpmpattr_SOURCES = bgp_mp_attr_test.c
testchecksum_SOURCES = test-checksum.c
+testvector_SOURCES = test-vector.c
+testsymtab_SOURCES = test-symtab.c
testsig_LDADD = ../lib/libzebra.la @LIBCAP@
testbuffer_LDADD = ../lib/libzebra.la @LIBCAP@
@@ -34,4 +36,6 @@ aspathtest_LDADD = ../lib/libzebra.la @LIBCAP@ -lm ../bgpd/libbgp.a
testbgpcap_LDADD = ../lib/libzebra.la @LIBCAP@ -lm ../bgpd/libbgp.a
ecommtest_LDADD = ../lib/libzebra.la @LIBCAP@ -lm ../bgpd/libbgp.a
testbgpmpattr_LDADD = ../lib/libzebra.la @LIBCAP@ -lm ../bgpd/libbgp.a
-testchecksum_LDADD = ../lib/libzebra.la @LIBCAP@
+testchecksum_LDADD = ../lib/libzebra.la @LIBCAP@
+testvector_LDADD = ../lib/libzebra.la @LIBCAP@
+testsymtab_LDADD = ../lib/libzebra.la @LIBCAP@
diff --git a/tests/test-privs.c b/tests/test-privs.c
index a888ea0f..568fe79a 100644
--- a/tests/test-privs.c
+++ b/tests/test-privs.c
@@ -125,26 +125,42 @@ main (int argc, char **argv)
#define PRIV_STATE() \
((test_privs.current_state() == ZPRIVS_RAISED) ? "Raised" : "Lowered")
- printf ("%s\n", PRIV_STATE());
+ printf ("Initial state: %s\n", PRIV_STATE());
+
+ test_privs.change(ZPRIVS_RAISE);
+ printf ("Change raise: state: %s\n", PRIV_STATE());
+
test_privs.change(ZPRIVS_RAISE);
+ printf ("Change raise: state: %s\n", PRIV_STATE());
- printf ("%s\n", PRIV_STATE());
test_privs.change(ZPRIVS_LOWER);
+ printf ("Change lower: state: %s\n", PRIV_STATE());
+
+ test_privs.change(ZPRIVS_LOWER);
+ printf ("Change lower: state: %s\n", PRIV_STATE());
- printf ("%s\n", PRIV_STATE());
+ printf ("Get ids %s\n", PRIV_STATE());
zprivs_get_ids (&ids);
/* terminate privileges */
zprivs_terminate(&test_privs);
/* but these should continue to work... */
- printf ("%s\n", PRIV_STATE());
+ printf ("Terminated state: %s\n", PRIV_STATE());
+
+ test_privs.change(ZPRIVS_RAISE);
+ printf ("Change raise: state: %s\n", PRIV_STATE());
+
test_privs.change(ZPRIVS_RAISE);
+ printf ("Change raise: state: %s\n", PRIV_STATE());
- printf ("%s\n", PRIV_STATE());
test_privs.change(ZPRIVS_LOWER);
+ printf ("Change lower: state: %s\n", PRIV_STATE());
+
+ test_privs.change(ZPRIVS_LOWER);
+ printf ("Change lower: state: %s\n", PRIV_STATE());
- printf ("%s\n", PRIV_STATE());
+ printf ("Get ids %s\n", PRIV_STATE());
zprivs_get_ids (&ids);
printf ("terminating\n");
diff --git a/tests/test-symtab.c b/tests/test-symtab.c
new file mode 100644
index 00000000..ed83e607
--- /dev/null
+++ b/tests/test-symtab.c
@@ -0,0 +1,344 @@
+#include <zebra.h>
+#include <symtab.h>
+
+/* Symtab torture tests
+ *
+ */
+
+/* prototypes */
+void assert_true(int result, const char * message);
+int main(int argc, char **argv);
+void test_symbol_table_init_new(void);
+void test_symbol_table_lookup(void);
+void call_back_function_set(symbol sym, void* value);
+void call_back_function_change(symbol sym, void* value);
+void call_back_function_unset(symbol sym, void* value);
+void test_call_back(void);
+void test_ref(void);
+void test_ref_heavy(void);
+
+struct thread_master *master;
+
+void
+assert_true(int result, const char * message)
+{
+ if (!result)
+ {
+ printf("Assert failed: %s\n", message);
+ }
+}
+
+int
+main(int argc, char **argv)
+{
+
+ test_symbol_table_init_new();
+ test_symbol_table_lookup();
+ test_call_back();
+ test_ref();
+ test_ref_heavy();
+
+ return 0;
+}
+
+void
+test_symbol_table_init_new(void)
+{
+ symbol_table table = NULL;
+ char name[] = "name";
+ char value[] = "value";
+ symbol sym = NULL;
+ symbol sym2 = NULL;
+ void * old_value = NULL;
+
+ printf("test_symbol_table_init_new\n");
+ table = symbol_table_init_new(table, NULL, 0, 0, NULL, NULL);
+ assert_true(table != NULL, "table == NULL");
+
+ /* expect to not find */
+ sym = symbol_lookup(table, name, 0);
+ assert_true(sym == NULL, "sym != NULL");
+
+ /* add */
+ sym = symbol_lookup(table, name, 1);
+ symbol_set_value(sym, value);
+ assert_true(sym != NULL, "sym == NULL");
+ assert_true(strcmp(symbol_get_name(sym), name) == 0, "strcmp(symbol_get_name(sym), name) != 0");
+
+ /* find */
+ sym2 = symbol_lookup(table, name, 0);
+ assert_true(sym == sym2, "sym != sym2");
+ assert_true(symbol_get_value(sym) == value, "symbol_get_value(sym) != value");
+
+ old_value = symbol_delete(sym);
+ assert_true(value == old_value, "value != old_value");
+
+ while ((old_value = symbol_table_ream(table, 1)) != NULL)
+ {
+ }
+
+}
+
+void
+test_symbol_table_lookup(void)
+{
+ symbol_table table = NULL;
+ char buf[20];
+ symbol sym = NULL;
+ int i;
+ char *value = NULL;
+ const int len = 100000;
+ struct symbol_walker itr;
+ vector v = NULL;
+
+ printf("test_symbol_table_lookup\n");
+ table = symbol_table_init_new(table, NULL, 0, 0, NULL, NULL);
+
+ /* add */
+ for (i = 0; i < len; ++i)
+ {
+ sprintf(buf, "%d-name", i);
+ sym = symbol_lookup(table, buf, 1);
+ assert_true(sym != NULL, "add: sym == NULL");
+ assert_true(strcmp(symbol_get_name(sym), buf) == 0,
+ "strcmp(symbol_get_name(sym), buf) != 0");
+
+ sprintf(buf, "%d-value", i);
+ value = strdup(buf);
+ symbol_set_value(sym, value);
+ assert_true(symbol_get_value(sym) == value,
+ "symbol_get_value(sym) != value");
+ }
+
+ /* find */
+ for (i = 0; i < len; ++i)
+ {
+ sprintf(buf, "%d-name", i);
+ sym = symbol_lookup(table, buf, 0);
+ assert_true(sym != NULL, "find: sym == NULL");
+ assert_true(strcmp(symbol_get_name(sym), buf) == 0,
+ "strcmp(symbol_get_name(sym), buf) != 0");
+
+ sprintf(buf, "%d-value", i);
+ assert_true(strcmp(symbol_get_value(sym), buf) == 0,
+ "strcmp(symbol_get_value(sym), buf) != 0");
+ }
+
+ /* walk with symbol_walker */
+ symbol_walk_start(table, &itr);
+ i = 0;
+ do
+ {
+ sym = symbol_walk_next(&itr);
+ if (sym != NULL) {
+ ++i;
+ }
+ } while (sym != NULL);
+ assert_true(i == len, "i != len");
+
+ /* extract vector */
+ v = symbol_table_extract(table, NULL, NULL, 1, NULL);
+ assert_true(vector_end(v) == (unsigned)len, "vector_get_end(v) != len");
+ vector_free(v);
+
+ while ((value = symbol_table_ream(table, 1)) != NULL)
+ {
+ free(value);
+ }
+}
+
+void
+test_call_back(void)
+{
+ symbol_table table = NULL;
+ char name[] = "name";
+ char value[] = "value";
+ char new_value[] = "new value";
+ symbol sym = NULL;
+
+ printf("test_call_back\n");
+ table = symbol_table_init_new(table, NULL, 0, 0, NULL, NULL);
+ assert_true(table != NULL, "table == NULL");
+
+ /* add */
+ symbol_table_set_value_call_back(table, call_back_function_set);
+ sym = symbol_lookup(table, name, 1);
+ symbol_set_value(sym, value);
+
+ /* change */
+ symbol_table_set_value_call_back(table, call_back_function_change);
+ sym = symbol_lookup(table, name, 1);
+ symbol_set_value(sym, new_value);
+
+ /* delete */
+ symbol_table_set_value_call_back(table, call_back_function_unset);
+ symbol_unset_value(sym);
+
+ while ((symbol_table_ream(table, 1)) != NULL)
+ {
+ }
+}
+
+void call_back_function_set(symbol sym, void* value)
+{
+ assert_true(symbol_get_value(sym) != NULL && value == NULL,
+ "symbol_get_value(sym) == NULL || value != NULL");
+}
+
+void call_back_function_change(symbol sym, void* value)
+{
+ assert_true(symbol_get_value(sym) != NULL && value != NULL,
+ "symbol_get_value(sym) == NULL || value == NULL");
+}
+
+
+void call_back_function_unset(symbol sym, void* value)
+{
+ assert_true(symbol_get_value(sym) == NULL && value != NULL,
+ "symbol_get_value(sym) != NULL || value == NULL");
+}
+
+void
+test_ref(void)
+{
+ symbol_table table = NULL;
+ char name[] = "name";
+ char value[] = "value";
+ symbol sym = NULL;
+ symbol_ref ref = NULL;
+ symbol_ref ref1 = NULL;
+ symbol_ref ref2 = NULL;
+ struct symbol_ref walk;
+ const int num_refs = 2;
+ long int itag = 0;
+
+ printf("test_ref\n");
+ table = symbol_table_init_new(table, NULL, 0, 0, NULL, NULL);
+
+ /* add */
+ sym = symbol_lookup(table, name, 1);
+ symbol_set_value(sym, value);
+
+ /* create references, in reverse order so that walk in order */
+ ref2 = symbol_set_ref(NULL, sym);
+ assert_true(ref2 != NULL, "ref2 == NULL");
+ sym_ref_set_i_tag(ref2, 2);
+ assert_true(sym_ref_i_tag(ref2) == 2, "sym_ref_i_tag(ref2) != 2");
+
+ ref1 = symbol_set_ref(NULL, sym);
+ assert_true(ref1 != NULL, "ref1 == NULL");
+ sym_ref_set_i_tag(ref1, 1);
+ assert_true(sym_ref_i_tag(ref1) == 1, "sym_ref_i_tag(ref1) != 1");
+
+ /* walk references */
+ itag = 1;
+ symbol_ref_walk_start(sym, &walk) ;
+ assert_true(sym->ref_list == &walk, "sym->ref_list != &walk");
+ assert_true(walk.next == ref1, "walk.next != ref1");
+ assert_true(ref1->next == ref2, "ref1->next != ref2");
+ assert_true(ref2->next == NULL, "ref2->next != NULL");
+
+ while ((ref = symbol_ref_walk_step(&walk)) != NULL)
+ {
+ assert_true(sym_ref_i_tag(ref) == itag, "sym_ref_i_tag(ref) != itag");
+ ++itag;
+ }
+ assert_true(itag == num_refs + 1, "itag != num_refs + 1");
+
+ symbol_ref_walk_end(&walk);
+
+ /* clean up */
+ symbol_unset_ref(ref1, 1);
+ symbol_unset_ref(ref2, 1);
+
+ while ((symbol_table_ream(table, 1)) != NULL)
+ {
+ }
+}
+
+void
+test_ref_heavy(void)
+{
+ symbol_table table = NULL;
+ char name[] = "name";
+ char value[] = "value";
+ symbol sym = NULL;
+ symbol_ref ref = NULL;
+ struct symbol_ref walk;
+ const long int num_refs = 100000;
+ long int itag = 0;
+
+ printf("test_ref_heavy\n");
+ table = symbol_table_init_new(table, NULL, 0, 0, NULL, NULL);
+
+ /* add */
+ sym = symbol_lookup(table, name, 1);
+ symbol_set_value(sym, value);
+
+ /* create references, in reverse order so that walk in order */
+ for (itag = num_refs; itag > 0; --itag)
+ {
+ ref = symbol_set_ref(NULL, sym);
+ assert_true(ref != NULL, "ref == NULL");
+ sym_ref_set_i_tag(ref, itag);
+ assert_true(sym_ref_i_tag(ref) == itag, "sym_ref_i_tag(ref) != itag");
+ }
+
+ /* walk references */
+ itag = 1;
+ symbol_ref_walk_start(sym, &walk) ;
+ assert_true(sym->ref_list == &walk, "sym->ref_list != &walk");
+
+ while ((ref = symbol_ref_walk_step(&walk)) != NULL)
+ {
+ assert_true(sym_ref_i_tag(ref) == itag, "sym_ref_i_tag(ref) != itag");
+ ++itag;
+ symbol_unset_ref(ref, 1);
+ }
+ assert_true(itag == num_refs + 1, "itag != num_refs + 1");
+
+ symbol_ref_walk_end(&walk);
+
+ while ((symbol_table_ream(table, 1)) != NULL)
+ {
+ }
+}
+
+
+/*
+ *
+ * TODO
+ *
+
+symbol_table_set_parent
+symbol_table_get_parent
+symbol_hash_string
+symbol_hash_bytes
+symbol_table_set_value_call_back
+symbol_table_free
+symbol_unset_value
+symbol_select_cmp
+symbol_sort_cmp
+symbol_table_extract
+symbol_sort_cmp
+symbol_get_name_len
+symbol_get_table
+symbol_zero_ref
+symbol_dec_ref
+symbol_init_ref
+symbol_set_ref
+symbol_unset_ref
+symbol_unset_ref_free
+symbol_unset_ref_keep
+sym_ref_symbol
+sym_ref_value
+sym_ref_name
+sym_ref_name_len
+sym_ref_parent
+sym_ref_p_tag
+sym_ref_u_tag
+sym_ref_i_tag
+sym_ref_set_parent
+sym_ref_set_p_tag
+sym_ref_set_i_tag
+ */
diff --git a/tests/test-vector.c b/tests/test-vector.c
new file mode 100644
index 00000000..6aecfd6e
--- /dev/null
+++ b/tests/test-vector.c
@@ -0,0 +1,1209 @@
+#include <zebra.h>
+#include <vector.h>
+
+/* Vector torture tests
+ *
+ */
+
+/* prototypes */
+void assert_true(int result, const char * message);
+int main(int argc, char **argv);
+void test_vector_init(void);
+void test_vector_set_index(void);
+void test_vector_lookup(void);
+void test_vector_lookup_ensure(void);
+void test_vector_unset(void);
+void test_vector_set_index_null(void);
+void test_vector_copy(void);
+void test_vector_set(void);
+void test_vector_growth(void);
+
+/* GMCH interface */
+void test_vector_init_new(void);
+void test_vector_set_item(void);
+void test_vector_insert_item(void);
+void test_vector_insert_item_here(void);
+void test_vector_delete_item(void);
+void do_test_insert(const int rider);
+int sort_cmp(const void** a, const void** b);
+void test_vector_sort(void);
+void test_vector_bsearch(void);
+void test_vector_move_item_here(void);
+void do_test_move_item_here(const int rider);
+void test_vector_part_reverse(void);
+void test_vector_copy_here(void);
+void test_vector_move_here(void);
+void test_vector_copy_append(void);
+void test_vector_move_append(void);
+void test_vector_insert(void);
+void test_vector_delete(void);
+void test_vector_discard(void);
+void test_vector_sak(void);
+
+struct thread_master *master;
+
+/* objects to put in the vectors */
+static char s0[5];
+static char s1000[5];
+static char s2000[5];
+
+void
+assert_true(int result, const char * message)
+{
+ if (!result)
+ {
+ printf("Assert failed: %s\n", message);
+ }
+}
+
+int
+main(int argc, char **argv)
+{
+ strcpy(s0, "0");
+ strcpy(s1000, "1000");
+ strcpy(s2000, "2000");
+
+ test_vector_init();
+ test_vector_set_index();
+ test_vector_lookup();
+ test_vector_lookup_ensure();
+ test_vector_unset();
+ test_vector_set_index_null();
+ test_vector_copy();
+ test_vector_set();
+ test_vector_growth();
+
+ /* GMCH interface */
+ test_vector_init_new();
+ test_vector_set_item();
+ test_vector_insert_item();
+ test_vector_insert_item_here();
+ test_vector_delete_item();
+ test_vector_sort();
+ test_vector_bsearch();
+ test_vector_move_item_here();
+ test_vector_part_reverse();
+ test_vector_copy_here();
+ test_vector_move_here();
+ test_vector_copy_append();
+ test_vector_move_append();
+ test_vector_insert();
+ test_vector_delete();
+ test_vector_discard();
+ test_vector_sak();
+
+ return 0;
+}
+
+void
+test_vector_init(void)
+{
+ vector v = NULL;
+
+ printf("test_vector_init\n");
+ v = vector_init(10);
+
+ assert_true(v != NULL,
+ "v == NULL");
+ assert_true(vector_count(v) == 0,
+ "vector_count != 0");
+ assert_true(vector_active(v) == 0,
+ "vector_active != 0");
+ assert_true(vector_empty_slot(v) == 0,
+ "test_vector_init: vector_empty_slot != 0");
+
+ vector_free(v);
+}
+
+void
+test_vector_set_index(void)
+{
+ vector v = NULL;
+
+ printf("test_vector_set_index\n");
+ v = vector_init(0);
+
+ vector_set_index(v, 1000, s1000);
+ assert_true(vector_count(v) == 1,
+ "vector_count != 1");
+ assert_true(vector_active(v) == 1001,
+ "vector_active != 1001");
+ assert_true(vector_empty_slot(v) == 0,
+ "vector_empty_slot != 0");
+ assert_true(vector_slot(v,1000) == s1000,
+ "vector_slot != 1000");
+
+ vector_free(v);
+}
+
+void
+test_vector_lookup(void)
+{
+ vector v = NULL;
+
+ printf("test_vector_lookup\n");
+ v = vector_init(0);
+
+ vector_set_index(v, 1000, s1000);
+
+ assert_true(vector_lookup(v,1000) == s1000,
+ "vector_lookup != 1000");
+ assert_true(vector_lookup(v,1001) == NULL,
+ "vector_lookup != NULL");
+
+ vector_free(v);
+}
+
+void
+test_vector_lookup_ensure(void)
+{
+ vector v = NULL;
+
+ printf("test_vector_lookup_ensure\n");
+ v = vector_init(0);
+
+ vector_set_index(v, 1000, s1000);
+
+ assert_true(vector_lookup_ensure(v,1000) == s1000,
+ "vector_lookup_ensure != 1000");
+ assert_true(vector_lookup_ensure(v,1001) == NULL,
+ "vector_lookup_ensure != NULL");
+
+ vector_free(v);
+}
+
+void
+test_vector_unset(void)
+{
+ vector v = NULL;
+
+ printf("test_vector_unset\n");
+ v = vector_init(0);
+
+ vector_set_index(v, 1000, s1000);
+ vector_set_index(v, 2000, s2000);
+ assert_true(vector_count(v) == 2,
+ "vector_count != 2");
+ assert_true(vector_active(v) == 2001,
+ "vector_active != 2001");
+
+ vector_unset(v, 2000);
+ assert_true(vector_count(v) == 1,
+ "vector_count != 1");
+ assert_true(vector_active(v) == 1001,
+ "vector_active != 1001");
+
+ vector_free(v);
+}
+
+void
+test_vector_set_index_null(void)
+{
+ vector v = NULL;
+
+ printf("test_vector_set_index_null\n");
+ v = vector_init(0);
+
+ vector_set_index(v, 1000, s1000);
+ vector_set_index(v, 2000, s2000);
+ assert_true(vector_count(v) == 2,
+ "vector_count != 2");
+ assert_true(vector_active(v) == 2001,
+ "vector_active != 2001");
+
+ /* storing a NULL is not the same as vector_unset() */
+ vector_set_index(v, 2000, NULL);
+ assert_true(vector_count(v) == 1,
+ "vector_count != 1");
+ assert_true(vector_active(v) == 2001,
+ "vector_active != 2001");
+
+ /* GMCH change in semantics */
+ vector_unset(v, 1000);
+ assert_true(vector_count(v) == 0,
+ "vector_count != 0");
+ assert_true(vector_active(v) == 2001,
+ "vector_active != 2001 ignore post GMCH");
+ assert_true(vector_active(v) == 0,
+ "vector_active != 0 ignore pre GMCH");
+
+ vector_free(v);
+}
+
+void
+test_vector_copy(void)
+{
+ vector v1 = NULL;
+ vector v2 = NULL;
+ int i;
+ const int len = 100;
+ char buf[10];
+
+ printf("test_vector_copy\n");
+
+ /* to help debug objects are strings of their index */
+ v1 = vector_init(0);
+ for (i = 0; i < len; ++i)
+ {
+ sprintf(buf, "%d", i);
+ vector_set_index(v1, i, strdup(buf));
+ }
+
+ v2 = vector_copy(v1);
+ assert_true(v2 != NULL, "v2 == NULL");
+ assert_true(v1 != v2, "v1 == v2");
+
+ /* check contents are the same */
+ for (i = 0; i < len; ++i)
+ {
+ assert_true(vector_slot(v1, i) == vector_slot(v2, i), "v1 != v2");
+ }
+
+ /* free contents */
+ for (i = 0; i < len; ++i)
+ {
+ free(vector_slot(v1, i));
+ }
+
+ vector_free(v1);
+ vector_free(v2);
+}
+
+void
+test_vector_set(void)
+{
+ vector v = NULL;
+ int i;
+ const int len = 1000;
+ char buf[10];
+
+ printf("test_vector_set\n");
+
+ /* to help debug objects are strings of their index */
+ v = vector_init(0);
+ for (i = 0; i < len; ++i)
+ {
+ sprintf(buf, "%d", i);
+ vector_set_index(v, i, strdup(buf));
+ }
+
+ assert_true(vector_count(v) == (unsigned)len,
+ "vector_count != 1000");
+ assert_true(vector_active(v) == (unsigned)len,
+ "vector_active != 1000");
+
+ vector_set(v, s1000);
+ assert_true(vector_count(v) == len + 1,
+ "vector_count != 1001");
+ assert_true(vector_active(v) == len + 1,
+ "vector_active != 1001");
+ assert_true(vector_slot(v,1000) == s1000,
+ "vector_slot != 1000");
+
+ /* free contents */
+ for (i = 0; i < len; ++i)
+ {
+ free(vector_slot(v, i));
+ }
+
+ vector_free(v);
+}
+
+void
+test_vector_growth(void)
+{
+ vector v = NULL;
+ int i;
+ const int len = 150000;
+ char buf[10];
+
+ printf("test_vector_growth\n");
+
+ /* to help debug objects are strings of their index */
+ v = vector_init(0);
+ for (i = 0; i < len; ++i)
+ {
+ sprintf(buf, "%d", i);
+ vector_set_index(v, i, strdup(buf));
+ }
+
+ assert_true(vector_count(v) == (unsigned)len,
+ "vector_count != len");
+ assert_true(vector_active(v) == (unsigned)len,
+ "vector_active != len");
+
+ /* check contents are correct */
+ for (i = 0; i < len; ++i)
+ {
+ sprintf(buf, "%d", i);
+ assert_true(strcmp(vector_slot(v, i), buf) == 0, "vector_slot(v, i) != buf");
+ }
+
+ /* free contents */
+ for (i = 0; i < len; ++i)
+ {
+ free(vector_slot(v, i));
+ }
+
+ vector_free(v);
+}
+
+
+/* post GMCH interface */
+
+void
+test_vector_init_new(void)
+{
+ vector v = NULL;
+ void * item = NULL;
+
+ printf("test_vector_init_new\n");
+
+ v = vector_init_new(v, 0);
+ assert_true(v != NULL, "v == NULL");
+ assert_true(vector_is_empty(v), "!vector_is_empty(v)");
+ assert_true(vector_end(v) == 0, "vector_end(v) != 0");
+
+ vector_push_item(v, s0);
+ assert_true(vector_end(v) == 1, "vector_end(v) != 1");
+
+ item = vector_pop_item(v);
+ assert_true(item == s0, "item != s0");
+ assert_true(vector_is_empty(v), "!vector_is_empty(v)");
+ assert_true(vector_end(v) == 0, "vector_end(v) != 0");
+
+ vector_free(v);
+}
+
+void
+test_vector_set_item(void)
+{
+ vector v = NULL;
+ void * item = NULL;
+
+ printf("test_vector_set_item\n");
+
+ v = vector_init_new(v, 0);
+ vector_set_item(v, 0, s0);
+ vector_set_item(v, 1000, s1000);
+ vector_set_item(v, 2000, s2000);
+ assert_true(vector_end(v) == 2001, "vector_end(v) != 2001");
+
+ item = vector_get_item(v, 0);
+ assert_true(item == s0, "item != s0");
+ item = vector_get_item(v, 1000);
+ assert_true(item == s1000, "item != s1000");
+ item = vector_get_item(v, 2000);
+ assert_true(item == s2000, "item != s2000");
+
+ item = vector_get_first_item(v);
+ assert_true(item == s0, "item != s0");
+
+ item = vector_get_last_item(v);
+ assert_true(item == s2000, "item != s2000");
+
+ vector_free(v);
+}
+void
+test_vector_insert_item(void)
+{
+ do_test_insert(2);
+}
+
+void
+test_vector_insert_item_here(void)
+{
+ do_test_insert(-1);
+ do_test_insert(0);
+ do_test_insert(1);
+}
+
+void
+test_vector_delete_item(void)
+{
+ do_test_insert(3);
+}
+
+void
+do_test_insert(const int rider)
+{
+ vector v = NULL;
+ const vector_index len = 100;
+ const vector_index ins = 50;
+ vector_index i;
+ char buf[10];
+ vector_index check_end = len + 1;
+ vector_index check_ins = ins;
+ int check_shift = 1;
+
+ switch(rider)
+ {
+ case -1:
+ printf("test_vector_insert_here before\n");
+ break;
+ case 0:
+ printf("test_vector_insert_here at\n");
+ check_shift = 0;
+ check_end = len;
+ break;
+ case 1:
+ printf("test_vector_insert_here after\n");
+ check_ins++;
+ break;
+ case 2:
+ printf("test_vector_insert\n");
+ break;
+ case 3:
+ printf("test_vector_delete\n");
+ check_shift = -1;
+ check_end = len - 1;
+ break;
+ }
+
+ v = vector_init_new(v, 0);
+
+ for (i = 0; i < len; ++i)
+ {
+ sprintf(buf, "%d", i);
+ vector_set_item(v, i, strdup(buf));
+ }
+
+ switch(rider)
+ {
+ case -1:
+ case 0:
+ case 1:
+ vector_insert_item_here(v, ins, rider, strdup(s1000));
+ break;
+ case 2:
+ vector_insert_item(v, ins, strdup(s1000));
+ break;
+ case 3:
+ free(vector_delete_item(v, ins));
+ break;
+ }
+
+ assert_true(vector_end(v) == check_end, "vector_end(v) != check_end");
+
+ /* check contents are correct */
+ for (i = 0; i < check_ins; ++i)
+ {
+ sprintf(buf, "%d", i);
+ assert_true(strcmp(vector_get_item(v, i), buf) == 0,
+ "vector_get_item(v, i) != buf");
+ }
+
+ if (rider != 3)
+ {
+ assert_true(strcmp(vector_get_item(v, check_ins), s1000) == 0,
+ "vector_get_item(v, check_ins) != s1000");
+ }
+
+ for (i = check_ins + 1; i < check_end; ++i)
+ {
+ sprintf(buf, "%d", i - check_shift);
+ assert_true(strcmp(vector_get_item(v, i), buf) == 0, "vector_get_item(v, i) != buf");
+ }
+
+ /* free contents */
+ for (i = 0; i < vector_end(v); ++i)
+ {
+ free(vector_slot(v, i));
+ }
+
+ vector_free(v);
+}
+
+void
+test_vector_sort(void)
+{
+ vector v = NULL;
+ int i;
+ const int len = 100;
+ char buf[10];
+
+ printf("test_vector_sort\n");
+
+ v = vector_init(0);
+
+ vector_sort(v, sort_cmp); /* null sort */
+
+ /* initialize backwards, using width so that lexical = numerical order */
+ for (i = 0; i < len; ++i)
+ {
+ sprintf(buf, "%9d", i);
+ vector_set_index(v, len - i - 1, strdup(buf));
+ }
+
+ vector_sort(v, sort_cmp);
+
+ /* check contents are correct */
+ for (i = 0; i < len; ++i)
+ {
+ sprintf(buf, "%9d", i);
+ assert_true(strcmp(vector_slot(v, i), buf) == 0, "vector_slot(v, i) != buf");
+ }
+
+ /* free contents */
+ for (i = 0; i < len; ++i)
+ {
+ free(vector_slot(v, i));
+ }
+
+ vector_free(v);
+}
+
+int
+sort_cmp(const void** a, const void** b)
+{
+ return strcmp(*a, *b);
+}
+
+void
+test_vector_bsearch(void)
+{
+ vector v = NULL;
+ int i;
+ const int len = 2000;
+ char buf[20];
+ char target[20];
+ vector_index target_index = 0;
+ int result;
+ vector_index index;
+
+ printf("test_vector_bsearch\n");
+
+ sprintf(target, "%9u", target_index);
+ v = vector_init(0);
+
+ index = vector_bsearch(v, sort_cmp, target, &result); /* null search */
+ assert_true(index == 0, "index != 0");
+ assert_true(result == -1, "result != -1");
+
+ /* initialize, using width so that lexical = numerical order */
+ for (i = 0; i < len; ++i)
+ {
+ sprintf(buf, "%9d", i);
+ vector_set_index(v, i, strdup(buf));
+ }
+
+ for (target_index = 0; target_index < (unsigned)len; ++target_index)
+ {
+ sprintf(target, "%9u", target_index);
+ index = vector_bsearch(v, sort_cmp, target, &result);
+ assert_true(index == target_index, "index != target_index");
+ assert_true(result == 0, "result != 0");
+ assert_true(strcmp(vector_get_item(v, index), target) == 0,
+ "strcmp(vector_get_item(v, index), target)) != 0");
+ }
+
+ /* free contents */
+ for (i = 0; i < len; ++i)
+ {
+ free(vector_slot(v, i));
+ }
+
+ vector_free(v);
+}
+
+void
+test_vector_move_item_here(void)
+{
+ do_test_move_item_here(-1);
+ do_test_move_item_here(0);
+ do_test_move_item_here(1);
+}
+
+void
+do_test_move_item_here(const int rider)
+{
+ vector v = NULL;
+ const vector_index len = 100;
+ const vector_index ins = 50;
+ const vector_index src = 70;
+ vector_index i;
+ char buf[10];
+ vector_index check_dest = 0;
+ vector_index check_src = 0;
+ vector_index check_end = 0;
+ int check_shift = 0;
+ p_vector_item dest_item = NULL;
+
+
+ switch(rider)
+ {
+ case -1:
+ printf("test_vector_move_here before\n");
+ check_dest = ins;
+ check_src = src;
+ check_end = len;
+ check_shift = 1;
+ break;
+ case 0:
+ printf("test_vector_move_here at\n");
+ check_dest = ins;
+ check_src = src - 1;
+ check_end = len - 1;
+ check_shift = 0;
+ break;
+ case 1:
+ printf("test_vector_move_here after\n");
+ check_dest = ins + 1;
+ check_src = src;
+ check_end = len;
+ check_shift = 1;
+ break;
+ }
+
+ v = vector_init_new(v, 0);
+
+ for (i = 0; i < len; ++i)
+ {
+ sprintf(buf, "%u", i);
+ vector_set_item(v, i, strdup(buf));
+ }
+
+ dest_item = vector_get_item(v, ins); /* item to free if rider == 0 */
+
+ vector_move_item_here(v, ins, rider, src);
+ assert_true(vector_end(v) == check_end, "vector_end(v) != check_end");
+
+ /* check contents are correct */
+
+ /* from start to insertion point */
+ for (i = 0; i < check_dest - 1; ++i)
+ {
+ sprintf(buf, "%u", i);
+ assert_true(strcmp(vector_get_item(v, i), buf) == 0,
+ "vector_get_item(v, i) != buf");
+ }
+
+ /* at insertion point */
+ sprintf(buf, "%u", src);
+ assert_true(strcmp(vector_get_item(v, check_dest), buf) == 0,
+ "vector_get_item(v, check_dest) != buf");
+
+ /* from insertion point to src */
+ for (i = check_dest + 1; i <= check_src; ++i)
+ {
+ sprintf(buf, "%u", i - check_shift);
+ assert_true(strcmp(vector_get_item(v, i), buf) == 0, "vector_get_item(v, i) != buf");
+ }
+
+ /* from src to end */
+ for (i = check_src + 1; i < check_end; ++i)
+ {
+ sprintf(buf, "%u", i - (check_shift - 1));
+ assert_true(strcmp(vector_get_item(v, i), buf) == 0, "vector_get_item(v, i) != buf");
+ }
+
+ /* free contents */
+ for (i = 0; i < vector_end(v); ++i)
+ {
+ free(vector_slot(v, i));
+ }
+
+ if (rider == 0)
+ {
+ free(dest_item);
+ }
+
+ vector_free(v);
+}
+
+void
+test_vector_part_reverse(void)
+{
+ vector v = NULL;
+ const vector_index len = 100;
+ const vector_index rstart = 50;
+ const vector_index rstop = 70;
+ vector_index i;
+ char buf[10];
+
+ printf("test_vector_part_reverse\n");
+
+ v = vector_init_new(v, 0);
+
+ for (i = 0; i < len; ++i)
+ {
+ sprintf(buf, "%u", i);
+ vector_set_item(v, i, strdup(buf));
+ }
+
+ vector_part_reverse(v, rstart, rstop - rstart);
+ assert_true(vector_end(v) == len, "vector_end(v) != len");
+
+ /* check contents are correct */
+
+ /* before reversed section */
+ for (i = 0; i < rstart - 1; ++i)
+ {
+ sprintf(buf, "%u", i);
+ assert_true(strcmp(vector_get_item(v, i), buf) == 0,
+ "before reversed vector_get_item(v, i) != buf");
+ }
+
+ /* reversed section */
+ for (i = rstart; i < rstop; ++i)
+ {
+ sprintf(buf, "%u", rstop - (i - rstart + 1));
+ assert_true(strcmp(vector_get_item(v, i), buf) == 0,
+ "reversed vector_get_item(v, i) != buf");
+ }
+
+ /* after reversed section */
+ for (i = rstop; i < len; ++i)
+ {
+ sprintf(buf, "%u", i);
+ assert_true(strcmp(vector_get_item(v, i), buf) == 0,
+ "after reversed vector_get_item(v, i) != buf");
+ }
+
+ /* free contents */
+ for (i = 0; i < vector_end(v); ++i)
+ {
+ free(vector_slot(v, i));
+ }
+
+ vector_free(v);
+}
+
+void
+test_vector_copy_here(void)
+{
+ vector v1 = NULL;
+ vector v2 = NULL;
+ vector_index i;
+ const vector_index len = 100;
+ char buf[10];
+
+ printf("test_vector_copy_here\n");
+
+ /* to help debug objects are strings of their index */
+ v1 = vector_init(0);
+ for (i = 0; i < len; ++i)
+ {
+ sprintf(buf, "%u", i);
+ vector_set_index(v1, i, strdup(buf));
+ }
+
+ v2 = vector_copy_here(v2, v1);
+ assert_true(v2 != NULL, "v2 == NULL");
+ assert_true(v1 != v2, "v1 == v2");
+
+ /* check contents are the same */
+ for (i = 0; i < len; ++i)
+ {
+ assert_true(vector_get_item(v1, i) == vector_get_item(v2, i), "v1 != v2");
+ }
+
+ /* free contents */
+ for (i = 0; i < len; ++i)
+ {
+ free(vector_get_item(v1, i));
+ }
+
+ vector_free(v1);
+ vector_free(v2);
+}
+
+void
+test_vector_move_here(void)
+{
+ vector v1 = NULL;
+ vector v2 = NULL;
+ vector_index i;
+ const vector_index len = 100;
+ char buf[10];
+
+ printf("test_vector_move_here\n");
+
+ /* to help debug objects are strings of their index */
+ v1 = vector_init(0);
+ for (i = 0; i < len; ++i)
+ {
+ sprintf(buf, "%u", i);
+ vector_set_index(v1, i, strdup(buf));
+ }
+
+ v2 = vector_move_here(v2, v1);
+ assert_true(v2 != NULL, "v2 == NULL");
+ assert_true(v1 != v2, "v1 == v2");
+ assert_true(vector_end(v1) == 0, "vector_end(v1) != 0");
+
+ /* check contents are the same */
+ for (i = 0; i < len; ++i)
+ {
+ sprintf(buf, "%u", i);
+ assert_true(strcmp(vector_get_item(v2, i), buf) == 0,
+ "vector_get_item(v2, i) != buf");
+ }
+
+ /* free contents */
+ for (i = 0; i < len; ++i)
+ {
+ free(vector_get_item(v2, i));
+ }
+
+ vector_free(v1);
+ vector_free(v2);
+}
+
+void
+test_vector_copy_append(void)
+{
+ vector v1 = NULL;
+ vector v2 = NULL;
+ vector_index i;
+ const vector_index len = 100;
+ char buf[10];
+
+ printf("test_vector_copy_append\n");
+
+ /* to help debug objects are strings of their index */
+ v2 = vector_init(0);
+ for (i = 0; i < len; ++i)
+ {
+ sprintf(buf, "%u", i);
+ vector_set_index(v2, i, strdup(buf));
+ }
+
+ v1 = vector_init(0);
+ for (i = len; i < 2 * len; ++i)
+ {
+ sprintf(buf, "%u", i);
+ vector_set_index(v1, i - len, strdup(buf));
+ }
+
+ v2 = vector_copy_append(v2, v1);
+ assert_true(v2 != NULL, "v2 == NULL");
+ assert_true(v1 != v2, "v1 == v2");
+ assert_true(vector_end(v2) == 2 * len, "vector_end(v2) != 2 * len");
+
+ /* check contents */
+ for (i = 0; i < 2 * len; ++i)
+ {
+ sprintf(buf, "%u", i);
+ assert_true(strcmp(vector_get_item(v2, i), buf) == 0,
+ "vector_get_item(v2, i) != buf");
+ }
+
+ /* free contents */
+ for (i = 0; i < 2 * len; ++i)
+ {
+ free(vector_get_item(v2, i));
+ }
+
+ vector_free(v1);
+ vector_free(v2);
+}
+
+void
+test_vector_move_append(void)
+{
+ vector v1 = NULL;
+ vector v2 = NULL;
+ vector_index i;
+ const vector_index len = 100;
+ char buf[10];
+
+ printf("test_vector_move_append\n");
+
+ /* to help debug objects are strings of their index */
+ v2 = vector_init(0);
+ for (i = 0; i < len; ++i)
+ {
+ sprintf(buf, "%u", i);
+ vector_set_index(v2, i, strdup(buf));
+ }
+
+ v1 = vector_init(0);
+ for (i = len; i < 2 * len; ++i)
+ {
+ sprintf(buf, "%u", i);
+ vector_set_index(v1, i - len, strdup(buf));
+ }
+
+ v2 = vector_move_append(v2, v1);
+ assert_true(v2 != NULL, "v2 == NULL");
+ assert_true(v1 != v2, "v1 == v2");
+ assert_true(vector_end(v2) == 2 * len, "vector_end(v2) != 2 * len");
+ assert_true(vector_end(v1) == 0, "vector_end(v1) != 0");
+
+ /* check contents */
+ for (i = 0; i < 2 * len; ++i)
+ {
+ sprintf(buf, "%u", i);
+ assert_true(strcmp(vector_get_item(v2, i), buf) == 0,
+ "vector_get_item(v2, i) != buf");
+ }
+
+ /* free contents */
+ for (i = 0; i < 2 * len; ++i)
+ {
+ free(vector_get_item(v2, i));
+ }
+
+ vector_free(v1);
+ vector_free(v2);
+}
+
+void
+test_vector_insert(void)
+{
+ vector v = NULL;
+ vector_index i;
+ const vector_index len = 100;
+ const vector_index istart = 50;
+ const vector_index istop = 70;
+ char buf[10];
+
+ printf("test_vector_insert\n");
+
+ /* to help debug objects are strings of their index */
+
+ v = vector_init(0);
+ for (i = 0; i < len; ++i)
+ {
+ sprintf(buf, "%u", i);
+ vector_set_index(v, i, strdup(buf));
+ }
+
+ vector_insert(v, istart, istop - istart);
+ assert_true(vector_end(v) == len + (istop - istart),
+ "vector_end(v) != len + (istop - istart)");
+
+ /* check contents */
+ for (i = 0; i < istart; ++i)
+ {
+ sprintf(buf, "%u", i);
+ assert_true(strcmp(vector_get_item(v, i), buf) == 0,
+ "vector_get_item(v, i) != buf");
+ }
+
+ for (i = istart + 1; i < istop; ++i)
+ {
+ assert_true(vector_get_item(v, i) == NULL,
+ "vector_get_item(v, i) != NULL");
+ }
+
+ for (i = istop; i < len + (istop - istart); ++i)
+ {
+ sprintf(buf, "%u", i - (istop - istart));
+ assert_true(strcmp(vector_get_item(v, i), buf) == 0,
+ "vector_get_item(v, i) != buf");
+ }
+
+ /* free contents */
+ for (i = 0; i < len + (istop - istart); ++i)
+ {
+ free(vector_get_item(v, i));
+ }
+
+ vector_free(v);
+}
+
+void
+test_vector_delete(void)
+{
+ vector v = NULL;
+ vector_index i;
+ const vector_index len = 100;
+ const vector_index dstart = 50;
+ const vector_index dstop = 70;
+ char buf[10];
+
+ printf("test_vector_delete\n");
+
+ /* to help debug objects are strings of their index */
+
+ v = vector_init(0);
+ for (i = 0; i < len; ++i)
+ {
+ if (i < dstart || i >= dstop)
+ {
+ sprintf(buf, "%u", i);
+ vector_set_index(v, i, strdup(buf));
+ }
+ else
+ {
+ vector_set_index(v, i, s0);
+ }
+ }
+
+ vector_delete(v, dstart, dstop - dstart);
+ assert_true(vector_end(v) == len - (dstop - dstart),
+ "vector_end(v) != len - (dstop - dstart)");
+
+ /* check contents */
+ for (i = 0; i < dstart; ++i)
+ {
+ sprintf(buf, "%u", i);
+ assert_true(strcmp(vector_get_item(v, i), buf) == 0,
+ "vector_get_item(v, i) != buf");
+ }
+
+ for (i = dstart; i < len - (dstop - dstart); ++i)
+ {
+ sprintf(buf, "%u", i + (dstop - dstart));
+ assert_true(strcmp(vector_get_item(v, i), buf) == 0,
+ "vector_get_item(v, i) != buf");
+ }
+
+ /* free contents */
+ for (i = 0; i < len - (dstop - dstart); ++i)
+ {
+ free(vector_get_item(v, i));
+ }
+
+ vector_free(v);
+}
+
+void
+test_vector_discard(void)
+{
+ vector v = NULL;
+ vector_index i;
+ const vector_index len = 100;
+ const vector_index dstart = 50;
+ char buf[10];
+
+ printf("test_vector_discard\n");
+
+ /* to help debug objects are strings of their index */
+
+ v = vector_init(0);
+ for (i = 0; i < len; ++i)
+ {
+ if (i < dstart)
+ {
+ sprintf(buf, "%u", i);
+ vector_set_index(v, i, strdup(buf));
+ }
+ else
+ {
+ vector_set_index(v, i, s0);
+ }
+ }
+
+ vector_discard(v, dstart);
+ assert_true(vector_end(v) == dstart,
+ "vector_end(v) != dstart");
+
+ /* check contents */
+ for (i = 0; i < dstart; ++i)
+ {
+ sprintf(buf, "%u", i);
+ assert_true(strcmp(vector_get_item(v, i), buf) == 0,
+ "vector_get_item(v, i) != buf");
+ }
+
+ /* free contents */
+ for (i = 0; i < dstart; ++i)
+ {
+ free(vector_get_item(v, i));
+ }
+
+ vector_free(v);
+}
+
+void
+test_vector_sak(void)
+{
+ vector v1 = NULL;
+ vector v2 = NULL;
+ vector v3 = NULL;
+ vector_index i;
+ const vector_index len = 100;
+ const vector_index sstart = 60;
+ const vector_index sstop = 70;
+ const vector_index dstart = 40;
+ const vector_index dstop = 50;
+ char buf[10];
+
+ printf("test_vector_sak\n");
+
+ /* to help debug objects are strings of their index */
+
+ v2 = vector_init(0);
+ v3 = vector_init(0);
+ for (i = 0; i < len; ++i)
+ {
+ sprintf(buf, "%u", i);
+ vector_set_index(v2, i, strdup(buf));
+ vector_set_index(v3, i, strdup(buf));
+ }
+
+ v1 = vector_sak(1, v1, v2, dstart, dstop - dstart,
+ v3, sstart, sstop - sstart, 0);
+ assert_true(v1 != NULL, "v1 == NULL");
+
+ assert_true(vector_end(v1) == (dstop - dstart),
+ "vector_end(v1) != (dstop - dstart)");
+ assert_true(vector_end(v2) == len,
+ "vector_end(v2) != len");
+ assert_true(vector_end(v3) == len,
+ "vector_end(v3) != len");
+
+ /* check contents v1 */
+ for (i = 0; i < dstop - dstart; ++i)
+ {
+ sprintf(buf, "%u", i + dstart);
+ assert_true(vector_get_item(v1, i) != NULL,
+ "vector_get_item(v1, i) == NULL");
+ assert_true(strcmp(vector_get_item(v1, i), buf) == 0,
+ "vector_get_item(v1, i) != buf");
+ }
+
+ /* check contents v2 */
+ for (i = 0; i < dstart; ++i)
+ {
+ sprintf(buf, "%u", i);
+ assert_true(strcmp(vector_get_item(v2, i), buf) == 0,
+ "vector_get_item(v2, i) != buf");
+ }
+ for (i = dstart; i < dstop; ++i)
+ {
+ sprintf(buf, "%u", i - dstart + sstart);
+ assert_true(strcmp(vector_get_item(v2, i), buf) == 0,
+ "vector_get_item(v2, i) != buf");
+ }
+ for (i = dstop; i < len; ++i)
+ {
+ sprintf(buf, "%u", i);
+ assert_true(strcmp(vector_get_item(v2, i), buf) == 0,
+ "vector_get_item(v2, i) != buf");
+ }
+
+ /* check contents v3 */
+ for (i = 0; i < len; ++i)
+ {
+ sprintf(buf, "%u", i);
+ assert_true(strcmp(vector_get_item(v3, i), buf) == 0,
+ "vector_get_item(v3, i) != buf");
+ }
+
+ /* free contents */
+ for (i = 0; i < len; ++i)
+ {
+ free(vector_get_item(v3, i));
+ }
+
+ vector_free(v1);
+ vector_free(v2);
+ vector_free(v3);
+}
+/*
+ * TODO
+ *
+
+vector_re_init
+vector_reset
+vector_ream
+vector_sak
+vector_chop
+vector_decant
+vector_extend_by_1
+
+*/
diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c
index 3f189adb..935c4933 100644
--- a/vtysh/vtysh.c
+++ b/vtysh/vtysh.c
@@ -2227,7 +2227,7 @@ void
vtysh_init_vty (void)
{
/* Make vty structure. */
- vty = vty_new ();
+ vty = vty_new (0);
vty->type = VTY_SHELL;
vty->node = VIEW_NODE;
diff --git a/vtysh/vtysh_config.c b/vtysh/vtysh_config.c
index fb8a1269..f7071fc2 100644
--- a/vtysh/vtysh_config.c
+++ b/vtysh/vtysh_config.c
@@ -353,8 +353,7 @@ vtysh_read_file (FILE *confp)
int ret;
struct vty *vty;
- vty = vty_new ();
- vty->fd = 0; /* stdout */
+ vty = vty_new (0); /* stdout */
vty->type = VTY_TERM;
vty->node = CONFIG_NODE;