diff options
-rw-r--r-- | Makefile.am | 2 | ||||
-rw-r--r-- | bgpd/bgp_clist.c | 223 | ||||
-rw-r--r-- | bgpd/bgp_clist.h | 50 | ||||
-rw-r--r-- | bgpd/bgp_packet.c | 248 | ||||
-rw-r--r-- | bgpd/bgp_route.c | 1067 | ||||
-rw-r--r-- | bgpd/bgp_route.h | 44 | ||||
-rw-r--r-- | bgpd/bgp_vty.c | 637 | ||||
-rw-r--r-- | bgpd/bgpd.c | 433 | ||||
-rw-r--r-- | bgpd/bgpd.h | 44 | ||||
-rw-r--r-- | lib/Makefile.am | 4 | ||||
-rw-r--r-- | lib/command.c | 182 | ||||
-rw-r--r-- | lib/memory.c | 40 | ||||
-rw-r--r-- | lib/memory.h | 6 | ||||
-rw-r--r-- | lib/memtypes.c | 12 | ||||
-rw-r--r-- | lib/plist.c | 2364 | ||||
-rw-r--r-- | lib/plist.h | 45 | ||||
-rw-r--r-- | lib/prefix.c | 92 | ||||
-rw-r--r-- | lib/symtab.c | 1186 | ||||
-rw-r--r-- | lib/symtab.h | 318 | ||||
-rw-r--r-- | lib/vector.c | 1192 | ||||
-rw-r--r-- | lib/vector.h | 276 | ||||
-rw-r--r-- | lib/vty.c | 147 | ||||
-rw-r--r-- | lib/vty.h | 15 | ||||
-rw-r--r-- | tests/Makefile.am | 8 | ||||
-rw-r--r-- | tests/test-symtab.c | 344 | ||||
-rw-r--r-- | tests/test-vector.c | 1209 |
26 files changed, 7341 insertions, 2847 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_packet.c b/bgpd/bgp_packet.c index 61534191..cbf58e56 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); @@ -939,7 +939,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. */ @@ -952,15 +952,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); @@ -971,7 +971,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); @@ -979,11 +979,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); @@ -1000,7 +1000,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) ? @@ -1067,7 +1067,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) @@ -1079,7 +1079,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 @@ -1123,7 +1123,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; } @@ -1149,7 +1149,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); @@ -1164,20 +1164,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) { @@ -1187,7 +1187,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 @@ -1202,7 +1202,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); @@ -1211,8 +1211,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 */ @@ -1246,7 +1246,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); } @@ -1283,7 +1283,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 @@ -1301,7 +1301,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, @@ -1317,13 +1317,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. @@ -1340,11 +1340,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; @@ -1358,7 +1358,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); @@ -1379,8 +1379,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; @@ -1396,8 +1396,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; @@ -1409,8 +1409,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; @@ -1425,11 +1425,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 @@ -1449,7 +1449,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) @@ -1501,7 +1501,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)); @@ -1528,7 +1528,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; } @@ -1542,7 +1542,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; } @@ -1563,14 +1563,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; } @@ -1584,7 +1584,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; } @@ -1592,7 +1592,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; @@ -1645,12 +1645,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); @@ -1672,12 +1672,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); @@ -1701,13 +1701,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); @@ -1730,13 +1730,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); @@ -1758,13 +1758,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); @@ -1897,9 +1897,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); } @@ -1924,7 +1924,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", @@ -1934,7 +1934,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); @@ -1980,9 +1980,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?? */ @@ -2009,8 +2009,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); @@ -2039,9 +2039,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); @@ -2092,7 +2092,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) { @@ -2102,7 +2102,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) @@ -2137,7 +2137,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)) @@ -2145,15 +2145,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; @@ -2184,10 +2184,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) { @@ -2222,7 +2222,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) @@ -2240,7 +2240,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; @@ -2248,7 +2248,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)) { @@ -2261,16 +2261,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)) { @@ -2344,7 +2344,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. */ @@ -2362,14 +2362,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) @@ -2398,7 +2398,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, @@ -2413,7 +2413,7 @@ bgp_read (struct thread *thread) } ret = bgp_read_packet (peer); - if (ret < 0) + if (ret < 0) goto done; /* Get size and type again. */ @@ -2422,11 +2422,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 f3144fea..206cf702 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; @@ -11198,7 +11199,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>", @@ -11293,11 +11294,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; @@ -11449,7 +11450,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) @@ -11463,11 +11464,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; @@ -11481,7 +11482,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); @@ -11500,12 +11501,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; @@ -11516,7 +11517,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); @@ -11537,13 +11538,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"); @@ -11581,7 +11582,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"); @@ -11607,7 +11608,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) { @@ -11846,7 +11847,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); @@ -12059,13 +12060,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); @@ -12172,13 +12173,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); @@ -12216,7 +12217,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/lib/Makefile.am b/lib/Makefile.am index 315e919b..f655ac39 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -12,7 +12,7 @@ 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 BUILT_SOURCES = memtypes.h route_types.h @@ -27,7 +27,7 @@ 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 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..60880f49 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 { @@ -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,7 +2567,7 @@ DEFUN (config_write_file, VTY_NEWLINE); goto finished; } - + /* Make vty for configuration file. */ file_vty = vty_new (); file_vty->fd = fd; @@ -2621,10 +2613,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 +2632,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 +2728,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 +2742,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 +2796,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 +2862,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 +2908,7 @@ DEFUN (no_config_enable_password, no_enable_password_cmd, return CMD_SUCCESS; } - + DEFUN (service_password_encrypt, service_password_encrypt_cmd, "service password-encryption", @@ -3195,19 +3187,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) { @@ -3391,7 +3383,7 @@ DEFUN_DEPRECATED (config_log_trap, { int new_level ; int i; - + if ((new_level = level_match(argv[0])) == ZLOG_DISABLED) return CMD_ERR_NO_MATCH; @@ -3500,7 +3492,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 +3532,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 +3596,7 @@ cmd_init (int terminal) install_default (CONFIG_NODE); } - + install_element (CONFIG_NODE, &hostname_cmd); install_element (CONFIG_NODE, &no_hostname_cmd); @@ -3667,7 +3659,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/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..037efef2 100644 --- a/lib/memory.h +++ b/lib/memory.h @@ -32,7 +32,7 @@ struct mlist { struct memory_list *list; const char *name; }; - + #include "lib/memtypes.h" extern struct mlist mlists[]; @@ -60,6 +60,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 +71,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..197fb88c 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,8 +16,12 @@ 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_LINK_LIST, "Link List" }, { MTYPE_LINK_NODE, "Link Node" }, { MTYPE_THREAD, "Thread" }, @@ -75,7 +79,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/plist.c b/lib/plist.c index 0f802a83..10d5e31c 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]); - + 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/symtab.c b/lib/symtab.c new file mode 100644 index 00000000..57a49396 --- /dev/null +++ b/lib/symtab.c @@ -0,0 +1,1186 @@ +/* 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 (but may be unset, since it is already unset). + * + * 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 ; + + /* There are no actual bases until they have been allocated. */ + i = (table->bases != NULL) ? table->base_count : 0 ; + + 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) ; + /* asserts(table->entry_count == 0) */ + 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 ; + + old_value = sym->value ; + sym->value = new_value ; + + if (sym->table == NULL) /* watch out for orphans */ + { + assert((new_value == NULL) && (old_value == NULL)) ; + return NULL ; + } ; + + /* 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..8268c830 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,757 @@ #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 */ +} ; + +/*============================================================================== + * 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) { - if (v->alloced > num) - return; + assert((src != NULL) && (src != dst)) ; + + dst = vector_re_init(dst, src->limit) ; - 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->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) +{ + 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. */ + + *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 +786,436 @@ vector_empty_slot (vector v) int vector_set (vector v, void *val) { - unsigned int i; - - i = vector_empty_slot (v); - vector_ensure (v, i); + vector_index i; + i = vector_empty_slot(v) ; /* NB: i <= v->end */ + if (i == v->end) + i = vector_extend_by_1(v) ; - v->index[i] = val; - - 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]; } /* Unset value at specified index slot. */ void -vector_unset (vector v, unsigned int i) +vector_unset (vector v, vector_index i) { - if (i >= v->alloced) - return; + vector_index j ; + if (i >= v->end) + return; /* Everything beyond or at end is implicitly NULL */ - v->index[i] = NULL; + v->p_items[i] = NULL; - if (i + 1 == v->active) - { - v->active--; - while (i && v->index[--i] == NULL && v->active--) + /* See if everything ahead of 'i' is also NULL. */ + j = i ; + while (++j < v->end) + if (v->p_items[j] != NULL) + return ; /* Finished if anything ahead 'i' is not NULL */ + + /* Everything from 'i' onwards is NULL. + * Step backwards across any NULLs and then set the new end. + */ +#if 0 + v->end--; + while (i && v->p_items[--i] == NULL && v->end--) ; /* Is this ugly ? */ - } +#endif + while ((i != 0) && (v->p_items[i - 1] == NULL)) + --i ; + + v->end = i ; } -/* Count the number of not emplty slot. */ -unsigned int +/* Count the number of not empty slots. */ +vector_index vector_count (vector v) { - unsigned int i; + vector_index i; unsigned count = 0; - for (i = 0; i < v->active; i++) - if (v->index[i] != NULL) + for (i = 0; i < v->end; i++) + if (v->p_items[i] != NULL) count++; return count; } + +/*============================================================================== + * 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_delete(vector v, vector_index i, unsigned int n) +{ + vector_index old_end, new_end ; + + old_end = v->end ; + + if ((i >= old_end) || (n == 0)) + return ; + + /* If i + n < old_end, we have 1 or more items to keep and move down */ + if ((i + n) < old_end) + { + 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 */ + } ; + + 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) +{ + if (i >= v->limit) + return ; + + 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)) ; + } ; +} ; + +/* 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..3a7e7ca5 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,271 @@ * 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); +extern void vector_unset (vector v, vector_index 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 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 */ @@ -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> @@ -40,7 +40,7 @@ #include <arpa/telnet.h> /* Vty events */ -enum event +enum event { VTY_SERV, VTY_READ, @@ -57,7 +57,7 @@ static void vty_event (enum event, int, struct vty *); /* Extern host structure from command.c */ extern struct host host; - + /* Vector which store each vty structure. */ static vector vtyvec; @@ -89,8 +89,8 @@ static u_char restricted_mode = 0; /* Integrated configuration file path */ char integrate_default[] = SYSCONFDIR INTEGRATE_DEFAULT_CONFIG; - -/* VTY standard output function. */ + +/* VTY standard output function. vty == NULL or VTY_SHELL => stdout */ int vty_out (struct vty *vty, const char *format, ...) { @@ -151,6 +151,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) @@ -209,7 +230,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"); @@ -382,7 +403,7 @@ vty_auth (struct vty *vty, char *buf) vty_out (vty, "%% Bad passwords, too many failures!%s", VTY_NEWLINE); vty->status = VTY_CLOSE; } - else + else { /* AUTH_ENABLE_NODE */ vty->fail = 0; @@ -423,7 +444,7 @@ vty_command (struct vty *vty, char *buf) protocolname = zlog_proto_names[zlog_default->protocol]; else protocolname = zlog_proto_names[ZLOG_NONE]; - + #ifdef CONSUMED_TIME_CHECK GETRUSAGE(&after); if ((realtime = thread_consumed_time(&after, &before, &cputime)) > @@ -455,7 +476,7 @@ vty_command (struct vty *vty, char *buf) return ret; } - + static const char telnet_backward_char = 0x08; static const char telnet_space_char = ' '; @@ -646,7 +667,7 @@ vty_forward_word (struct vty *vty) { 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); } @@ -746,7 +767,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; @@ -776,7 +797,7 @@ vty_kill_line (struct vty *vty) int size; size = vty->length - vty->cp; - + if (size == 0) return; @@ -871,7 +892,7 @@ 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); @@ -985,7 +1006,7 @@ 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'); @@ -1004,7 +1025,7 @@ vty_describe_command (struct vty *vty) vty_out (vty, "%% There is no matched command.%s", VTY_NEWLINE); goto out; break; - } + } /* Get width of command string. */ width = 0; @@ -1033,7 +1054,7 @@ vty_describe_command (struct vty *vty) { if (desc->cmd[0] == '\0') continue; - + if (strcmp (desc->cmd, command_cr) == 0) { desc_cr = desc; @@ -1220,7 +1241,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; @@ -1364,7 +1385,7 @@ vty_read (struct thread *thread) vty->status = VTY_CLOSE; } - for (i = 0; i < nbytes; i++) + for (i = 0; i < nbytes; i++) { if (buf[i] == IAC) { @@ -1378,7 +1399,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 +1417,7 @@ vty_read (struct thread *thread) i += ret; continue; } - + if (vty->status == VTY_MORE) { @@ -1723,10 +1744,10 @@ vty_accept (struct thread *thread) (buf = sockunion_su2str (&su))); free (buf); close (vty_sock); - + /* continue accepting connections */ vty_event (VTY_SERV, accept_sock, NULL); - + prefix_free (p); return 0; @@ -1745,24 +1766,24 @@ vty_accept (struct thread *thread) (buf = sockunion_su2str (&su))); free (buf); close (vty_sock); - + /* continue accepting connections */ vty_event (VTY_SERV, accept_sock, NULL); - + 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", + zlog (NULL, LOG_INFO, "can't set sockopt to vty_sock : %s", safe_strerror (errno)); zlog (NULL, LOG_INFO, "Vty connection from %s", @@ -1827,7 +1848,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; @@ -1860,7 +1881,7 @@ 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) @@ -1895,7 +1916,7 @@ vty_serv_sock_family (const char* addr, unsigned short port, int family) /* 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. */ @@ -1919,7 +1940,7 @@ vty_serv_un (const char *path) struct sockaddr_un serv; mode_t old_mask; struct zprivs_ids_t ids; - + /* First of all, unlink existing socket */ unlink (path); @@ -1963,7 +1984,7 @@ vty_serv_un (const char *path) umask (old_mask); zprivs_get_ids(&ids); - + if (ids.gid_vty > 0) { /* set group of socket */ @@ -1987,7 +2008,7 @@ vtysh_accept (struct thread *thread) int client_len; struct sockaddr_un client; struct vty *vty; - + accept_sock = THREAD_FD (thread); vty_event (VTYSH_SERV, accept_sock, NULL); @@ -2011,7 +2032,7 @@ vtysh_accept (struct thread *thread) close (sock); return -1; } - + #ifdef VTYSH_DEBUG printf ("VTY shell accept\n"); #endif /* VTYSH_DEBUG */ @@ -2234,11 +2255,11 @@ vty_read_file (FILE *confp) vty->fd = 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)) ) + if ( !((ret == CMD_SUCCESS) || (ret == CMD_ERR_NOTHING_TODO)) ) { switch (ret) { @@ -2249,7 +2270,7 @@ 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); exit (1); @@ -2267,7 +2288,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 +2300,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 +2318,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 +2332,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 +2359,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 +2373,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); } @@ -2397,7 +2418,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 +2431,7 @@ vty_read_config (char *config_file, config_default_dir); exit (1); } - } + } else fullpath = config_default_dir; } @@ -2420,7 +2441,7 @@ vty_read_config (char *config_file, fclose (confp); host_config_set (fullpath); - + if (tmp) XFREE (MTYPE_TMP, fullpath); } @@ -2432,7 +2453,7 @@ vty_log (const char *level, const char *proto_str, { unsigned int i; struct vty *vty; - + if (!vtyvec) return; @@ -2457,7 +2478,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"; @@ -2494,7 +2515,7 @@ vty_config_unlock (struct vty *vty) } return vty->config; } - + /* Master of the threads. */ static struct thread_master *master; @@ -2528,7 +2549,7 @@ 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; @@ -2544,13 +2565,13 @@ 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; } } - + DEFUN (config_who, config_who_cmd, "who", @@ -2839,14 +2860,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 +2875,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; @@ -2933,7 +2954,7 @@ vty_get_cwd () int vty_shell (struct vty *vty) { - return vty->type == VTY_SHELL ? 1 : 0; + return ((vty == NULL) || (vty->type == VTY_SHELL)) ? 1 : 0; } int @@ -2945,7 +2966,7 @@ vty_shell_serv (struct vty *vty) void vty_init_vtysh () { - vtyvec = vector_init (VECTOR_MIN_SIZE); + vtyvec = vector_init (0); } /* Install vty's own commands like `who' command. */ @@ -2955,12 +2976,12 @@ vty_init (struct thread_master *master_thread) /* 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); @@ -28,7 +28,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #define VTY_MAXHIST 20 /* VTY struct. */ -struct vty +struct vty { /* File descripter of this vty. */ int fd; @@ -124,7 +124,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 @@ -207,12 +213,15 @@ extern void vty_terminate (void); extern void vty_reset (void); extern struct vty *vty_new (void); 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/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-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 + +*/ |