summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorTimo Teräs <timo.teras@iki.fi>2016-03-30 13:44:03 +0300
committerTimo Teräs <timo.teras@iki.fi>2016-03-30 14:29:40 +0300
commit8cb40c91cdfb00ddf04e88d3ecd40403890d90f7 (patch)
tree6d6a3de27525820abb740f1fa8347b6f03986bad /lib
parent86c5d2ee68f7b9c00ae4aeb5c8b3c5d82c5ebffc (diff)
downloadquagga-8cb40c91cdfb00ddf04e88d3ecd40403890d90f7.tar.bz2
quagga-8cb40c91cdfb00ddf04e88d3ecd40403890d90f7.tar.xz
cumulus take-3cumulus-take-3
Diffstat (limited to 'lib')
-rw-r--r--lib/Makefile.am4
-rw-r--r--lib/bitfield.h102
-rw-r--r--lib/command.c2
-rw-r--r--lib/command.h9
-rw-r--r--lib/fifo.h1
-rw-r--r--lib/filter.c6
-rw-r--r--lib/if.c61
-rw-r--r--lib/if.h17
-rw-r--r--lib/libospf.h6
-rw-r--r--lib/log.c27
-rw-r--r--lib/log.h12
-rw-r--r--lib/memtypes.c6
-rw-r--r--lib/nexthop.c168
-rw-r--r--lib/nexthop.h93
-rw-r--r--lib/plist.c14
-rw-r--r--lib/prefix.h15
-rw-r--r--[-rwxr-xr-x]lib/route_types.pl23
-rw-r--r--lib/routemap.c531
-rw-r--r--lib/routemap.h33
-rw-r--r--lib/thread.c14
-rw-r--r--lib/thread.h6
-rw-r--r--lib/workqueue.c37
-rw-r--r--lib/workqueue.h3
-rw-r--r--lib/zclient.c105
-rw-r--r--lib/zclient.h9
-rw-r--r--lib/zebra.h8
26 files changed, 1196 insertions, 116 deletions
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 57e859d6..a2e65fb0 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -13,7 +13,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 agentx.c snmp.c md5.c if_rmap.c keychain.c privs.c \
- sigevent.c pqueue.c jhash.c memtypes.c workqueue.c vrf.c
+ sigevent.c pqueue.c jhash.c memtypes.c workqueue.c vrf.c nexthop.c
BUILT_SOURCES = memtypes.h route_types.h gitversion.h
@@ -28,7 +28,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 libospf.h vrf.h fifo.h
+ workqueue.h route_types.h libospf.h vrf.h fifo.h nexthop.h
noinst_HEADERS = \
plist_int.h
diff --git a/lib/bitfield.h b/lib/bitfield.h
new file mode 100644
index 00000000..b3f40a94
--- /dev/null
+++ b/lib/bitfield.h
@@ -0,0 +1,102 @@
+/**
+ * A simple bit array implementation to allocate and free IDs. An example
+ * of its usage is in allocating link state IDs for OSPFv3 as OSPFv3 has
+ * removed all address semantics from LS ID. Another usage can be in
+ * allocating IDs for BGP neighbors (and dynamic update groups) for
+ * efficient storage of adj-rib-out.
+ *
+ * An example:
+ * #include "bitfield.h"
+ *
+ * bitfield_t bitfield;
+ *
+ * bf_init(bitfield, 32);
+ * ...
+ * bf_assign_index(bitfield, id1);
+ * bf_assign_index(bitfield, id2);
+ * ...
+ * bf_release_index(bitfield, id1);
+ */
+
+#ifndef _BITFIELD_H
+#define _BITFIELD_H
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+typedef unsigned int word_t;
+#define WORD_MAX 0xFFFFFFFF
+#define WORD_SIZE (sizeof(word_t) * 8)
+
+/**
+ * The bitfield structure.
+ * @data: the bits to manage.
+ * @n: The current word number that is being used.
+ * @m: total number of words in 'data'
+ */
+#define bitfield_t struct { word_t *data; size_t n, m; }
+
+/**
+ * Initialize the bits.
+ * @v: an instance of bitfield_t struct.
+ * @N: number of bits to start with, which equates to how many
+ * IDs can be allocated.
+ */
+#define bf_init(v, N) \
+ do { \
+ (v).n = 0; \
+ (v).m = ((N) / WORD_SIZE + 1); \
+ (v).data = calloc(1, ((v).m * sizeof(word_t))); \
+ } while (0)
+
+/**
+ * allocate and assign an id from bitfield v.
+ */
+#define bf_assign_index(v, id) \
+ do { \
+ bf_find_bit(v, id); \
+ bf_set_bit(v, id); \
+ } while (0)
+
+/**
+ * return an id to bitfield v
+ */
+#define bf_release_index(v, id) \
+ (v).data[bf_index(id)] &= ~(1 << (bf_offset(id)))
+
+#define bf_index(b) ((b) / WORD_SIZE)
+#define bf_offset(b) ((b) % WORD_SIZE)
+
+/**
+ * Set a bit in the array. If it fills up that word and we are
+ * out of words, extend it by one more word.
+ */
+#define bf_set_bit(v, b) \
+ do { \
+ size_t w = bf_index(b); \
+ (v).data[w] |= 1 << (bf_offset(b)); \
+ (v).n += ((v).data[w] == WORD_MAX); \
+ if ((v).n == (v).m) { \
+ (v).m = (v).m + 1; \
+ (v).data = realloc((v).data, (v).m * sizeof(word_t)); \
+ } \
+ } while (0)
+
+/* Find a clear bit in v and assign it to b. */
+#define bf_find_bit(v, b) \
+ do { \
+ word_t word; \
+ unsigned int w, sh; \
+ for (w = 0; w <= (v).n; w++) { \
+ if ((word = (v).data[w]) != WORD_MAX) break; \
+ } \
+ (b) = ((word & 0xFFFF) == 0xFFFF) << 4; word >>= (b); \
+ sh = ((word & 0xFF) == 0xFF) << 3; word >>= sh; (b) |= sh; \
+ sh = ((word & 0xF) == 0xF) << 2; word >>= sh; (b) |= sh; \
+ sh = ((word & 0x3) == 0x3) << 1; word >>= sh; (b) |= sh; \
+ sh = ((word & 0x1) == 0x1) << 0; word >>= sh; (b) |= sh; \
+ (b) += (w * WORD_SIZE); \
+ } while (0)
+
+#endif
diff --git a/lib/command.c b/lib/command.c
index 80893602..9c6e63bd 100644
--- a/lib/command.c
+++ b/lib/command.c
@@ -4098,7 +4098,7 @@ DEFUN (show_commandtree,
/* Set config filename. Called from vty.c */
void
-host_config_set (char *filename)
+host_config_set (const char *filename)
{
if (host.config)
XFREE (MTYPE_HOST, host.config);
diff --git a/lib/command.h b/lib/command.h
index 6a20e232..04f9b030 100644
--- a/lib/command.h
+++ b/lib/command.h
@@ -479,6 +479,10 @@ struct cmd_token
#define CLEAR_STR "Reset functions\n"
#define RIP_STR "RIP information\n"
#define BGP_STR "BGP information\n"
+#define BGP_SOFT_STR "Soft reconfig inbound and outbound updates\n"
+#define BGP_SOFT_IN_STR "Send route-refresh unless using 'soft-reconfiguration inbound'\n"
+#define BGP_SOFT_OUT_STR "Resend all outbound updates\n"
+#define BGP_SOFT_RSCLIENT_RIB_STR "Soft reconfig for rsclient RIB\n"
#define OSPF_STR "OSPF information\n"
#define NEIGHBOR_STR "Specify neighbor router\n"
#define DEBUG_STR "Debugging functions (see also 'undebug')\n"
@@ -516,7 +520,8 @@ struct cmd_token
#define NEIGHBOR_ADDR_STR "Neighbor address\nIPv6 address\n"
#define NEIGHBOR_CMD2 "neighbor (A.B.C.D|X:X::X:X|WORD) "
#define NO_NEIGHBOR_CMD2 "no neighbor (A.B.C.D|X:X::X:X|WORD) "
-#define NEIGHBOR_ADDR_STR2 "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+#define NEIGHBOR_ADDR_STR2 "Neighbor address\nNeighbor IPv6 address\nInterface name or neighbor tag\n"
+#define NEIGHBOR_ADDR_STR3 "Neighbor address\nIPv6 address\nInterface name\n"
#else
#define NEIGHBOR_CMD "neighbor A.B.C.D "
#define NO_NEIGHBOR_CMD "no neighbor A.B.C.D "
@@ -557,7 +562,7 @@ extern struct cmd_element config_quit_cmd;
extern struct cmd_element config_help_cmd;
extern struct cmd_element config_list_cmd;
extern char *host_config_file (void);
-extern void host_config_set (char *);
+extern void host_config_set (const char *);
extern void print_version (const char *);
diff --git a/lib/fifo.h b/lib/fifo.h
index 6be75b76..47a1e888 100644
--- a/lib/fifo.h
+++ b/lib/fifo.h
@@ -25,6 +25,7 @@ struct fifo
{
struct fifo *next;
struct fifo *prev;
+ u_int32_t count;
};
#define FIFO_INIT(F) \
diff --git a/lib/filter.c b/lib/filter.c
index a4729414..9c3d3bd6 100644
--- a/lib/filter.c
+++ b/lib/filter.c
@@ -28,6 +28,7 @@
#include "sockunion.h"
#include "buffer.h"
#include "log.h"
+#include "routemap.h"
struct filter_cisco
{
@@ -460,6 +461,7 @@ access_list_filter_add (struct access_list *access, struct filter *filter)
/* Run hook function. */
if (access->master->add_hook)
(*access->master->add_hook) (access);
+ route_map_notify_dependencies(access->name, RMAP_EVENT_FILTER_ADDED);
}
/* If access_list has no filter then return 1. */
@@ -493,6 +495,8 @@ access_list_filter_delete (struct access_list *access, struct filter *filter)
filter_free (filter);
+ route_map_notify_dependencies(access->name, RMAP_EVENT_FILTER_DELETED);
+
/* Run hook function. */
if (master->delete_hook)
(*master->delete_hook) (access);
@@ -1337,6 +1341,7 @@ DEFUN (no_access_list_all,
master = access->master;
+ route_map_notify_dependencies(access->name, RMAP_EVENT_FILTER_DELETED);
/* Run hook function. */
if (master->delete_hook)
(*master->delete_hook) (access);
@@ -1508,6 +1513,7 @@ DEFUN (no_ipv6_access_list_all,
master = access->master;
+ route_map_notify_dependencies(access->name, RMAP_EVENT_FILTER_DELETED);
/* Run hook function. */
if (master->delete_hook)
(*master->delete_hook) (access);
diff --git a/lib/if.c b/lib/if.c
index 44b8586e..fe467c3e 100644
--- a/lib/if.c
+++ b/lib/if.c
@@ -135,6 +135,12 @@ if_create_vrf (const char *name, int namelen, vrf_id_t vrf_id)
ifp->connected = list_new ();
ifp->connected->del = (void (*) (void *)) connected_free;
+ ifp->nbr_connected = list_new ();
+ ifp->nbr_connected->del = (void (*) (void *)) nbr_connected_free;
+
+ /* Enable Link-detection by default */
+ SET_FLAG(ifp->status, ZEBRA_INTERFACE_LINKDETECTION);
+
if (if_master.if_new_hook)
(*if_master.if_new_hook) (ifp);
@@ -156,6 +162,9 @@ if_delete_retain (struct interface *ifp)
/* Free connected address list */
list_delete_all_node (ifp->connected);
+
+ /* Free connected nbr address list */
+ list_delete_all_node (ifp->nbr_connected);
}
/* Delete and free interface structure. */
@@ -167,6 +176,7 @@ if_delete (struct interface *ifp)
if_delete_retain(ifp);
list_free (ifp->connected);
+ list_free (ifp->nbr_connected);
XFREE (MTYPE_IF, ifp);
}
@@ -793,6 +803,13 @@ connected_new (void)
return XCALLOC (MTYPE_CONNECTED, sizeof (struct connected));
}
+/* Allocate nbr connected structure. */
+struct nbr_connected *
+nbr_connected_new (void)
+{
+ return XCALLOC (MTYPE_NBR_CONNECTED, sizeof (struct nbr_connected));
+}
+
/* Free connected structure. */
void
connected_free (struct connected *connected)
@@ -809,6 +826,30 @@ connected_free (struct connected *connected)
XFREE (MTYPE_CONNECTED, connected);
}
+/* Free nbr connected structure. */
+void
+nbr_connected_free (struct nbr_connected *connected)
+{
+ if (connected->address)
+ prefix_free (connected->address);
+
+ XFREE (MTYPE_NBR_CONNECTED, connected);
+}
+
+/* If same interface nbr address already exists... */
+struct nbr_connected *
+nbr_connected_check (struct interface *ifp, struct prefix *p)
+{
+ struct nbr_connected *ifc;
+ struct listnode *node;
+
+ for (ALL_LIST_ELEMENTS_RO (ifp->nbr_connected, node, ifc))
+ if (prefix_same (ifc->address, p))
+ return ifc;
+
+ return NULL;
+}
+
/* Print if_addr structure. */
static void __attribute__ ((unused))
connected_log (struct connected *connected, char *str)
@@ -835,6 +876,26 @@ connected_log (struct connected *connected, char *str)
zlog (NULL, LOG_INFO, "%s", logbuf);
}
+/* Print if_addr structure. */
+static void __attribute__ ((unused))
+nbr_connected_log (struct nbr_connected *connected, char *str)
+{
+ struct prefix *p;
+ struct interface *ifp;
+ char logbuf[BUFSIZ];
+ char buf[BUFSIZ];
+
+ ifp = connected->ifp;
+ p = connected->address;
+
+ snprintf (logbuf, BUFSIZ, "%s interface %s %s %s/%d ",
+ str, ifp->name, prefix_family_str (p),
+ inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ),
+ p->prefixlen);
+
+ zlog (NULL, LOG_INFO, "%s", logbuf);
+}
+
/* If two connected address has same prefix return 1. */
static int
connected_same_prefix (struct prefix *p1, struct prefix *p2)
diff --git a/lib/if.h b/lib/if.h
index b3d14ba4..f71aa1e4 100644
--- a/lib/if.h
+++ b/lib/if.h
@@ -182,6 +182,9 @@ struct interface
/* Connected address list. */
struct list *connected;
+ /* Neighbor connected address list. */
+ struct list *nbr_connected;
+
/* Daemon specific interface data pointer. */
void *info;
@@ -222,6 +225,7 @@ struct connected
u_char flags;
#define ZEBRA_IFA_SECONDARY (1 << 0)
#define ZEBRA_IFA_PEER (1 << 1)
+#define ZEBRA_IFA_UNNUMBERED (1 << 2)
/* N.B. the ZEBRA_IFA_PEER flag should be set if and only if
a peer address has been configured. If this flag is set,
the destination field must contain the peer address.
@@ -240,6 +244,16 @@ struct connected
char *label;
};
+/* Nbr Connected address structure. */
+struct nbr_connected
+{
+ /* Attached interface. */
+ struct interface *ifp;
+
+ /* Address of connected network. */
+ struct prefix *address;
+};
+
/* Does the destination field contain a peer address? */
#define CONNECTED_PEER(C) CHECK_FLAG((C)->flags, ZEBRA_IFA_PEER)
@@ -381,6 +395,9 @@ extern struct connected *connected_delete_by_prefix (struct interface *,
struct prefix *);
extern struct connected *connected_lookup_address (struct interface *,
struct in_addr);
+extern struct nbr_connected *nbr_connected_new (void);
+extern void nbr_connected_free (struct nbr_connected *);
+struct nbr_connected *nbr_connected_check (struct interface *, struct prefix *);
#ifndef HAVE_IF_NAMETOINDEX
extern ifindex_t if_nametoindex (const char *);
diff --git a/lib/libospf.h b/lib/libospf.h
index 9265ca59..a3bbc1dc 100644
--- a/lib/libospf.h
+++ b/lib/libospf.h
@@ -80,6 +80,12 @@
#define OSPF_FAST_HELLO_DEFAULT 0
#define OSPF_AREA_BACKBONE 0x00000000 /* 0.0.0.0 */
+#define OSPF_AREA_RANGE_COST_UNSPEC -1U
+
+#define OSPF_AREA_DEFAULT 0
+#define OSPF_AREA_STUB 1
+#define OSPF_AREA_NSSA 2
+#define OSPF_AREA_TYPE_MAX 3
/* SPF Throttling timer values. */
#define OSPF_SPF_DELAY_DEFAULT 0
diff --git a/lib/log.c b/lib/log.c
index 0914bf84..d57bb3de 100644
--- a/lib/log.c
+++ b/lib/log.c
@@ -621,28 +621,6 @@ ZLOG_FUNC(zlog_debug, LOG_DEBUG)
#undef ZLOG_FUNC
-#define PLOG_FUNC(FUNCNAME,PRIORITY) \
-void \
-FUNCNAME(struct zlog *zl, const char *format, ...) \
-{ \
- va_list args; \
- va_start(args, format); \
- vzlog (zl, PRIORITY, format, args); \
- va_end(args); \
-}
-
-PLOG_FUNC(plog_err, LOG_ERR)
-
-PLOG_FUNC(plog_warn, LOG_WARNING)
-
-PLOG_FUNC(plog_info, LOG_INFO)
-
-PLOG_FUNC(plog_notice, LOG_NOTICE)
-
-PLOG_FUNC(plog_debug, LOG_DEBUG)
-
-#undef PLOG_FUNC
-
void zlog_thread_info (int log_level)
{
if (thread_current)
@@ -895,6 +873,11 @@ static const struct zebra_desc_table command_types[] = {
DESC_ENTRY (ZEBRA_ROUTER_ID_DELETE),
DESC_ENTRY (ZEBRA_ROUTER_ID_UPDATE),
DESC_ENTRY (ZEBRA_HELLO),
+ DESC_ENTRY (ZEBRA_NEXTHOP_REGISTER),
+ DESC_ENTRY (ZEBRA_NEXTHOP_UNREGISTER),
+ DESC_ENTRY (ZEBRA_NEXTHOP_UPDATE),
+ DESC_ENTRY (ZEBRA_INTERFACE_NBR_ADDRESS_ADD),
+ DESC_ENTRY (ZEBRA_INTERFACE_NBR_ADDRESS_DELETE),
};
#undef DESC_ENTRY
diff --git a/lib/log.h b/lib/log.h
index 514884cc..d7f994a0 100644
--- a/lib/log.h
+++ b/lib/log.h
@@ -121,18 +121,6 @@ extern void zlog_info (const char *format, ...) PRINTF_ATTRIBUTE(1, 2);
extern void zlog_notice (const char *format, ...) PRINTF_ATTRIBUTE(1, 2);
extern void zlog_debug (const char *format, ...) PRINTF_ATTRIBUTE(1, 2);
-/* For bgpd's peer oriented log. */
-extern void plog_err (struct zlog *, const char *format, ...)
- PRINTF_ATTRIBUTE(2, 3);
-extern void plog_warn (struct zlog *, const char *format, ...)
- PRINTF_ATTRIBUTE(2, 3);
-extern void plog_info (struct zlog *, const char *format, ...)
- PRINTF_ATTRIBUTE(2, 3);
-extern void plog_notice (struct zlog *, const char *format, ...)
- PRINTF_ATTRIBUTE(2, 3);
-extern void plog_debug (struct zlog *, const char *format, ...)
- PRINTF_ATTRIBUTE(2, 3);
-
extern void zlog_thread_info (int log_level);
/* Set logging level for the given destination. If the log_level
diff --git a/lib/memtypes.c b/lib/memtypes.c
index 6df14480..f2791595 100644
--- a/lib/memtypes.c
+++ b/lib/memtypes.c
@@ -26,6 +26,7 @@ struct memory_list memory_list_lib[] =
{ MTYPE_VTY_HIST, "VTY history" },
{ MTYPE_IF, "Interface" },
{ MTYPE_CONNECTED, "Connected" },
+ { MTYPE_NBR_CONNECTED, "Neighbor Connected" },
{ MTYPE_CONNECTED_LABEL, "Connected interface label" },
{ MTYPE_BUFFER, "Buffer" },
{ MTYPE_BUFFER_DATA, "Buffer data" },
@@ -54,6 +55,7 @@ struct memory_list memory_list_lib[] =
{ MTYPE_ROUTE_MAP_RULE, "Route map rule" },
{ MTYPE_ROUTE_MAP_RULE_STR, "Route map rule str" },
{ MTYPE_ROUTE_MAP_COMPILED, "Route map compiled" },
+ { MTYPE_ROUTE_MAP_DEP, "Route map dependency" },
{ MTYPE_CMD_TOKENS, "Command desc" },
{ MTYPE_KEY, "Key" },
{ MTYPE_KEYCHAIN, "Key chain" },
@@ -86,6 +88,7 @@ struct memory_list memory_list_zebra[] =
{ MTYPE_RIB_DEST, "RIB destination" },
{ MTYPE_RIB_TABLE_INFO, "RIB table info" },
{ MTYPE_NETLINK_NAME, "Netlink name" },
+ { MTYPE_RNH, "Nexthop tracking object" },
{ -1, NULL },
};
@@ -145,10 +148,13 @@ struct memory_list memory_list_bgp[] =
{ MTYPE_TRANSIT, "BGP transit attr" },
{ MTYPE_TRANSIT_VAL, "BGP transit val" },
{ 0, NULL },
+ { MTYPE_BGP_DEBUG_FILTER, "BGP debug filter" },
+ { 0, NULL },
{ MTYPE_BGP_DISTANCE, "BGP distance" },
{ MTYPE_BGP_NEXTHOP_CACHE, "BGP nexthop" },
{ MTYPE_BGP_CONFED_LIST, "BGP confed list" },
{ MTYPE_PEER_UPDATE_SOURCE, "BGP peer update interface" },
+ { MTYPE_PEER_CONF_IF, "BGP peer config interface" },
{ MTYPE_BGP_DAMP_INFO, "Dampening info" },
{ MTYPE_BGP_DAMP_ARRAY, "BGP Dampening array" },
{ MTYPE_BGP_REGEXP, "BGP regexp" },
diff --git a/lib/nexthop.c b/lib/nexthop.c
new file mode 100644
index 00000000..5eb2182d
--- /dev/null
+++ b/lib/nexthop.c
@@ -0,0 +1,168 @@
+/* A generic nexthop structure
+ * Copyright (C) 2013 Cumulus Networks, Inc.
+ *
+ * This file is part of Quagga.
+ *
+ * Quagga is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * Quagga is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Quagga; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+#include <zebra.h>
+
+#include "prefix.h"
+#include "table.h"
+#include "memory.h"
+#include "str.h"
+#include "command.h"
+#include "if.h"
+#include "log.h"
+#include "sockunion.h"
+#include "linklist.h"
+#include "thread.h"
+#include "prefix.h"
+#include "nexthop.h"
+
+/* check if nexthops are same, non-recursive */
+int
+nexthop_same_no_recurse (struct nexthop *next1, struct nexthop *next2)
+{
+ if (next1->type != next2->type)
+ return 0;
+
+ switch (next1->type)
+ {
+ case NEXTHOP_TYPE_IPV4:
+ case NEXTHOP_TYPE_IPV4_IFINDEX:
+ if (! IPV4_ADDR_SAME (&next1->gate.ipv4, &next2->gate.ipv4))
+ return 0;
+ if (next1->ifindex && (next1->ifindex != next2->ifindex))
+ return 0;
+ break;
+ case NEXTHOP_TYPE_IFINDEX:
+ case NEXTHOP_TYPE_IFNAME:
+ if (next1->ifindex != next2->ifindex)
+ return 0;
+ break;
+#ifdef HAVE_IPV6
+ case NEXTHOP_TYPE_IPV6:
+ if (! IPV6_ADDR_SAME (&next1->gate.ipv6, &next2->gate.ipv6))
+ return 0;
+ break;
+ case NEXTHOP_TYPE_IPV6_IFINDEX:
+ case NEXTHOP_TYPE_IPV6_IFNAME:
+ if (! IPV6_ADDR_SAME (&next1->gate.ipv6, &next2->gate.ipv6))
+ return 0;
+ if (next1->ifindex != next2->ifindex)
+ return 0;
+ break;
+#endif /* HAVE_IPV6 */
+ default:
+ /* do nothing */
+ break;
+ }
+ return 1;
+}
+
+/*
+ * nexthop_type_to_str
+ */
+const char *
+nexthop_type_to_str (enum nexthop_types_t nh_type)
+{
+ static const char *desc[] = {
+ "none",
+ "Directly connected",
+ "Interface route",
+ "IPv4 nexthop",
+ "IPv4 nexthop with ifindex",
+ "IPv4 nexthop with ifname",
+ "IPv6 nexthop",
+ "IPv6 nexthop with ifindex",
+ "IPv6 nexthop with ifname",
+ "Null0 nexthop",
+ };
+
+ if (nh_type >= ZEBRA_NUM_OF (desc))
+ return "<Invalid nh type>";
+
+ return desc[nh_type];
+}
+
+struct nexthop *
+nexthop_new (void)
+{
+ return XCALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop));
+}
+
+/* Add nexthop to the end of a nexthop list. */
+void
+nexthop_add (struct nexthop **target, struct nexthop *nexthop)
+{
+ struct nexthop *last;
+
+ for (last = *target; last && last->next; last = last->next)
+ ;
+ if (last)
+ last->next = nexthop;
+ else
+ *target = nexthop;
+ nexthop->prev = last;
+}
+
+void
+copy_nexthops (struct nexthop **tnh, struct nexthop *nh)
+{
+ struct nexthop *nexthop;
+ struct nexthop *nh1;
+
+ for (nh1 = nh; nh1; nh1 = nh1->next)
+ {
+ nexthop = nexthop_new();
+ nexthop->flags = nh->flags;
+ nexthop->type = nh->type;
+ nexthop->ifindex = nh->ifindex;
+ if (nh->ifname)
+ nexthop->ifname = XSTRDUP(0, nh->ifname);
+ memcpy(&(nexthop->gate), &(nh->gate), sizeof(union g_addr));
+ memcpy(&(nexthop->src), &(nh->src), sizeof(union g_addr));
+ nexthop_add(tnh, nexthop);
+
+ if (CHECK_FLAG(nh1->flags, NEXTHOP_FLAG_RECURSIVE))
+ copy_nexthops(&nexthop->resolved, nh1->resolved);
+ }
+}
+
+/* Free nexthop. */
+void
+nexthop_free (struct nexthop *nexthop)
+{
+ if (nexthop->ifname)
+ XFREE (0, nexthop->ifname);
+ if (nexthop->resolved)
+ nexthops_free(nexthop->resolved);
+ XFREE (MTYPE_NEXTHOP, nexthop);
+}
+
+/* Frees a list of nexthops */
+void
+nexthops_free (struct nexthop *nexthop)
+{
+ struct nexthop *nh, *next;
+
+ for (nh = nexthop; nh; nh = next)
+ {
+ next = nh->next;
+ nexthop_free (nh);
+ }
+}
diff --git a/lib/nexthop.h b/lib/nexthop.h
new file mode 100644
index 00000000..d8e82e9d
--- /dev/null
+++ b/lib/nexthop.h
@@ -0,0 +1,93 @@
+/*
+ * Nexthop structure definition.
+ * Copyright (C) 1997, 98, 99, 2001 Kunihiro Ishiguro
+ * Copyright (C) 2013 Cumulus Networks, Inc.
+ *
+ * This file is part of Quagga.
+ *
+ * Quagga is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * Quagga is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Quagga; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef _LIB_NEXTHOP_H
+#define _LIB_NEXTHOP_H
+
+#include "prefix.h"
+
+union g_addr {
+ struct in_addr ipv4;
+#ifdef HAVE_IPV6
+ struct in6_addr ipv6;
+#endif /* HAVE_IPV6 */
+};
+
+enum nexthop_types_t
+{
+ NEXTHOP_TYPE_IFINDEX = 1, /* Directly connected. */
+ NEXTHOP_TYPE_IFNAME, /* Interface route. */
+ NEXTHOP_TYPE_IPV4, /* IPv4 nexthop. */
+ NEXTHOP_TYPE_IPV4_IFINDEX, /* IPv4 nexthop with ifindex. */
+ NEXTHOP_TYPE_IPV4_IFNAME, /* IPv4 nexthop with ifname. */
+ NEXTHOP_TYPE_IPV6, /* IPv6 nexthop. */
+ NEXTHOP_TYPE_IPV6_IFINDEX, /* IPv6 nexthop with ifindex. */
+ NEXTHOP_TYPE_IPV6_IFNAME, /* IPv6 nexthop with ifname. */
+ NEXTHOP_TYPE_BLACKHOLE, /* Null0 nexthop. */
+};
+
+/* Nexthop structure. */
+struct nexthop
+{
+ struct nexthop *next;
+ struct nexthop *prev;
+
+ /* Interface index. */
+ char *ifname;
+ ifindex_t ifindex;
+
+ enum nexthop_types_t type;
+
+ u_char flags;
+#define NEXTHOP_FLAG_ACTIVE (1 << 0) /* This nexthop is alive. */
+#define NEXTHOP_FLAG_FIB (1 << 1) /* FIB nexthop. */
+#define NEXTHOP_FLAG_RECURSIVE (1 << 2) /* Recursive nexthop. */
+#define NEXTHOP_FLAG_ONLINK (1 << 3) /* Nexthop should be installed onlink. */
+#define NEXTHOP_FLAG_MATCHED (1 << 4) /* Already matched vs a nexthop */
+#define NEXTHOP_FLAG_FILTERED (1 << 5) /* rmap filtered, used by static only */
+
+ /* Nexthop address */
+ union g_addr gate;
+ union g_addr src;
+ union g_addr rmap_src; /* Src is set via routemap */
+
+ /* Nexthops obtained by recursive resolution.
+ *
+ * If the nexthop struct needs to be resolved recursively,
+ * NEXTHOP_FLAG_RECURSIVE will be set in flags and the nexthops
+ * obtained by recursive resolution will be added to `resolved'.
+ * Only one level of recursive resolution is currently supported. */
+ struct nexthop *resolved;
+};
+
+struct nexthop *nexthop_new (void);
+void nexthop_add (struct nexthop **target, struct nexthop *nexthop);
+
+void copy_nexthops (struct nexthop **tnh, struct nexthop *nh);
+void nexthop_free (struct nexthop *nexthop);
+void nexthops_free (struct nexthop *nexthop);
+
+extern const char *nexthop_type_to_str (enum nexthop_types_t nh_type);
+extern int nexthop_same_no_recurse (struct nexthop *next1, struct nexthop *next2);
+
+#endif /*_LIB_NEXTHOP_H */
diff --git a/lib/plist.c b/lib/plist.c
index 699c9b13..16533881 100644
--- a/lib/plist.c
+++ b/lib/plist.c
@@ -29,6 +29,7 @@
#include "buffer.h"
#include "stream.h"
#include "log.h"
+#include "routemap.h"
#include "plist_int.h"
@@ -330,13 +331,16 @@ prefix_list_delete (struct prefix_list *plist)
cleared. */
master->recent = NULL;
+ route_map_notify_dependencies(plist->name, RMAP_EVENT_PLIST_DELETED);
+
+ if (master->delete_hook)
+ (*master->delete_hook) (NULL);
+
if (plist->name)
XFREE (MTYPE_PREFIX_LIST_STR, plist->name);
-
+
prefix_list_free (plist);
-
- if (master->delete_hook)
- (*master->delete_hook) (NULL);
+
}
static struct prefix_list_entry *
@@ -457,6 +461,7 @@ prefix_list_entry_delete (struct prefix_list *plist,
if (update_list)
{
+ route_map_notify_dependencies(plist->name, RMAP_EVENT_PLIST_DELETED);
if (plist->master->delete_hook)
(*plist->master->delete_hook) (plist);
@@ -519,6 +524,7 @@ prefix_list_entry_add (struct prefix_list *plist,
if (plist->master->add_hook)
(*plist->master->add_hook) (plist);
+ route_map_notify_dependencies(plist->name, RMAP_EVENT_PLIST_ADDED);
plist->master->recent = plist;
}
diff --git a/lib/prefix.h b/lib/prefix.h
index 4a317507..d4f0eb92 100644
--- a/lib/prefix.h
+++ b/lib/prefix.h
@@ -235,13 +235,26 @@ extern void masklen2ip6 (const int, struct in6_addr *);
extern void str2in6_addr (const char *, struct in6_addr *);
extern const char *inet6_ntoa (struct in6_addr);
+static inline int ipv6_martian (struct in6_addr *addr)
+{
+ struct in6_addr localhost_addr;
+
+ inet_pton (AF_INET6, "::1", &localhost_addr);
+
+ if (IPV6_ADDR_SAME(&localhost_addr, addr))
+ return 1;
+
+ return 0;
+}
+
#endif /* HAVE_IPV6 */
extern int all_digit (const char *);
+/* NOTE: This routine expects the address argument in network byte order. */
static inline int ipv4_martian (struct in_addr *addr)
{
- in_addr_t ip = addr->s_addr;
+ in_addr_t ip = ntohl(addr->s_addr);
if (IPV4_NET0(ip) || IPV4_NET127(ip) || IPV4_CLASS_DE(ip)) {
return 1;
diff --git a/lib/route_types.pl b/lib/route_types.pl
index e1595afc..1e2f20ca 100755..100644
--- a/lib/route_types.pl
+++ b/lib/route_types.pl
@@ -89,7 +89,7 @@ printf <<EOF, $ARGV[0];
#ifndef _QUAGGA_ROUTE_TYPES_H
#define _QUAGGA_ROUTE_TYPES_H
-/* Zebra route's types. */
+/* Zebra route's' types. */
EOF
push @protos, "ZEBRA_ROUTE_MAX";
@@ -133,7 +133,7 @@ printf "#define SHOW_ROUTE_V6_HEADER \\\n%s\n", codelist(@protosv6);
print "\n";
sub collect {
- my ($daemon, $ipv4, $ipv6) = @_;
+ my ($daemon, $ipv4, $ipv6, $any) = @_;
my (@names, @help) = ((), ());
for my $p (@protos) {
next if ($protodetail{$p}->{"daemon"} eq $daemon && $daemon ne "zebra");
@@ -142,6 +142,10 @@ sub collect {
push @names, $protodetail{$p}->{"cname"};
push @help, " \"".$protodetail{$p}->{"longhelp"}."\\n\"";
}
+ if ($any == 1) {
+ push @names, "any";
+ push @help, " \"Any of the above protocols\\n\"";
+ }
return ("\"(" . join("|", @names) . ")\"", join(" \\\n", @help));
}
@@ -149,18 +153,25 @@ for my $daemon (sort keys %daemons) {
next unless ($daemons{$daemon}->{"ipv4"} || $daemons{$daemon}->{"ipv6"});
printf "/* %s */\n", $daemon;
if ($daemons{$daemon}->{"ipv4"} && $daemons{$daemon}->{"ipv6"}) {
- my ($names, $help) = collect($daemon, 1, 1);
+ my ($names, $help) = collect($daemon, 1, 1, 0);
printf "#define QUAGGA_REDIST_STR_%s \\\n %s\n", uc $daemon, $names;
printf "#define QUAGGA_REDIST_HELP_STR_%s \\\n%s\n", uc $daemon, $help;
- ($names, $help) = collect($daemon, 1, 0);
+ ($names, $help) = collect($daemon, 1, 0, 0);
printf "#define QUAGGA_IP_REDIST_STR_%s \\\n %s\n", uc $daemon, $names;
printf "#define QUAGGA_IP_REDIST_HELP_STR_%s \\\n%s\n", uc $daemon, $help;
- ($names, $help) = collect($daemon, 0, 1);
+ ($names, $help) = collect($daemon, 0, 1, 0);
printf "#define QUAGGA_IP6_REDIST_STR_%s \\\n %s\n", uc $daemon, $names;
printf "#define QUAGGA_IP6_REDIST_HELP_STR_%s \\\n%s\n", uc $daemon, $help;
+ ($names, $help) = collect($daemon, 0, 1, 1);
+ if ($daemon eq "zebra") {
+ printf "#define QUAGGA_IP_PROTOCOL_MAP_STR_%s \\\n %s\n", uc $daemon, $names;
+ printf "#define QUAGGA_IP_PROTOCOL_MAP_HELP_STR_%s \\\n%s\n", uc $daemon, $help;
+ printf "#define QUAGGA_IP6_PROTOCOL_MAP_STR_%s \\\n %s\n", uc $daemon, $names;
+ printf "#define QUAGGA_IP6_PROTOCOL_MAP_HELP_STR_%s \\\n%s\n", uc $daemon, $help;
+ }
} else {
my ($names, $help) = collect($daemon,
- $daemons{$daemon}->{"ipv4"}, $daemons{$daemon}->{"ipv6"});
+ $daemons{$daemon}->{"ipv4"}, $daemons{$daemon}->{"ipv6"}, 0);
printf "#define QUAGGA_REDIST_STR_%s \\\n %s\n", uc $daemon, $names;
printf "#define QUAGGA_REDIST_HELP_STR_%s \\\n%s\n", uc $daemon, $help;
}
diff --git a/lib/routemap.c b/lib/routemap.c
index 7302e231..1a1d318c 100644
--- a/lib/routemap.c
+++ b/lib/routemap.c
@@ -28,6 +28,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "command.h"
#include "vty.h"
#include "log.h"
+#include "hash.h"
/* Vector for route match rules. */
static vector route_match_vec;
@@ -60,15 +61,47 @@ struct route_map_list
void (*add_hook) (const char *);
void (*delete_hook) (const char *);
- void (*event_hook) (route_map_event_t, const char *);
+ void (*event_hook) (route_map_event_t, const char *);
};
/* Master list of route map. */
-static struct route_map_list route_map_master = { NULL, NULL, NULL, NULL };
+static struct route_map_list route_map_master = { NULL, NULL, NULL, NULL, NULL };
+
+enum route_map_upd8_type
+ {
+ ROUTE_MAP_ADD = 1,
+ ROUTE_MAP_DEL,
+ };
+
+/* all possible route-map dependency types */
+enum route_map_dep_type
+ {
+ ROUTE_MAP_DEP_RMAP = 1,
+ ROUTE_MAP_DEP_CLIST,
+ ROUTE_MAP_DEP_ECLIST,
+ ROUTE_MAP_DEP_PLIST,
+ ROUTE_MAP_DEP_ASPATH,
+ ROUTE_MAP_DEP_FILTER,
+ ROUTE_MAP_DEP_MAX,
+ };
+
+struct route_map_dep
+{
+ char *dep_name;
+ struct hash *dep_rmap_hash;
+ struct hash *this_hash; /* ptr to the hash structure this is part of */
+};
-static void
-route_map_rule_delete (struct route_map_rule_list *,
- struct route_map_rule *);
+/* Hashes maintaining dependency between various sublists used by route maps */
+struct hash *route_map_dep_hash[ROUTE_MAP_DEP_MAX];
+
+static unsigned int route_map_dep_hash_make_key (void *p);
+static int route_map_dep_hash_cmp (const void *p1, const void *p2);
+static void route_map_init_dep_hashes (void);
+static void route_map_clear_all_references (char *rmap_name);
+static void route_map_rule_delete (struct route_map_rule_list *,
+ struct route_map_rule *);
+static int rmap_debug = 0;
static void
route_map_index_delete (struct route_map_index *, int);
@@ -105,45 +138,72 @@ route_map_add (const char *name)
/* Execute hook. */
if (route_map_master.add_hook)
- (*route_map_master.add_hook) (name);
-
+ {
+ (*route_map_master.add_hook) (name);
+ route_map_notify_dependencies(name, RMAP_EVENT_CALL_ADDED);
+ }
return map;
}
-/* Route map delete from list. */
+/* this is supposed to be called post processing by
+ * the delete hook function. Don't invoke delete_hook
+ * again in this routine.
+ */
static void
-route_map_delete (struct route_map *map)
+route_map_free_map (struct route_map *map)
{
struct route_map_list *list;
struct route_map_index *index;
- char *name;
-
+
while ((index = map->head) != NULL)
route_map_index_delete (index, 0);
- name = map->name;
-
list = &route_map_master;
- if (map->next)
- map->next->prev = map->prev;
- else
- list->tail = map->prev;
+ if (map != NULL)
+ {
+ if (map->next)
+ map->next->prev = map->prev;
+ else
+ list->tail = map->prev;
- if (map->prev)
- map->prev->next = map->next;
- else
- list->head = map->next;
+ if (map->prev)
+ map->prev->next = map->next;
+ else
+ list->head = map->next;
- XFREE (MTYPE_ROUTE_MAP, map);
+ XFREE (MTYPE_ROUTE_MAP_NAME, map->name);
+ XFREE (MTYPE_ROUTE_MAP, map);
+ }
+}
+/* Route map delete from list. */
+static void
+route_map_delete (struct route_map *map)
+{
+ struct route_map_index *index;
+ char *name;
+
+ while ((index = map->head) != NULL)
+ route_map_index_delete (index, 0);
+
+ name = map->name;
+ map->head = NULL;
+
+ /* Clear all dependencies */
+ route_map_clear_all_references(name);
+ map->deleted = 1;
/* Execute deletion hook. */
if (route_map_master.delete_hook)
- (*route_map_master.delete_hook) (name);
-
- if (name)
- XFREE (MTYPE_ROUTE_MAP_NAME, name);
+ {
+ (*route_map_master.delete_hook) (name);
+ route_map_notify_dependencies(name, RMAP_EVENT_CALL_DELETED);
+ }
+ if (!map->to_be_processed)
+ {
+ route_map_free_map (map);
+ }
}
/* Lookup route map by route map name string. */
@@ -152,12 +212,50 @@ route_map_lookup_by_name (const char *name)
{
struct route_map *map;
+ if (!name)
+ return NULL;
+
for (map = route_map_master.head; map; map = map->next)
- if (strcmp (map->name, name) == 0)
+ if ((strcmp (map->name, name) == 0) && (!map->deleted))
return map;
return NULL;
}
+int
+route_map_mark_updated (const char *name, int del_later)
+{
+ struct route_map *map;
+ int ret = -1;
+
+ /* We need to do this walk manually instead of calling lookup_by_name()
+ * because the lookup function doesn't return route maps marked as
+ * deleted.
+ */
+ for (map = route_map_master.head; map; map = map->next)
+ if (strcmp (map->name, name) == 0)
+ {
+ map->to_be_processed = 1;
+ ret = 0;
+ }
+
+ return(ret);
+}
+
+int
+route_map_clear_updated (struct route_map *map)
+{
+ int ret = -1;
+
+ if (map)
+ {
+ map->to_be_processed = 0;
+ if (map->deleted)
+ route_map_free_map(map);
+ }
+
+ return (ret);
+}
+
/* Lookup route map. If there isn't route map create one and return
it. */
static struct route_map *
@@ -168,9 +266,31 @@ route_map_get (const char *name)
map = route_map_lookup_by_name (name);
if (map == NULL)
map = route_map_add (name);
+
return map;
}
+void
+route_map_walk_update_list (void *arg,
+ int (*route_map_update_fn) (void *arg, char *name))
+{
+ struct route_map *node;
+ struct route_map *nnode = NULL;
+
+ for (node = route_map_master.head; node; node = nnode)
+ {
+ if (node->to_be_processed)
+ {
+ /* DD: Should we add any thread yield code here */
+ route_map_update_fn(arg, node->name);
+ nnode = node->next;
+ route_map_clear_updated(node);
+ }
+ else
+ nnode = node->next;
+ }
+}
+
/* Return route map's type string. */
static const char *
route_map_type_str (enum route_map_type type)
@@ -271,7 +391,8 @@ vty_show_route_map (struct vty *vty, const char *name)
else
{
for (map = route_map_master.head; map; map = map->next)
- vty_show_route_map_entry (vty, map);
+ if (!map->deleted)
+ vty_show_route_map_entry (vty, map);
}
return CMD_SUCCESS;
}
@@ -320,9 +441,11 @@ route_map_index_delete (struct route_map_index *index, int notify)
/* Execute event hook. */
if (route_map_master.event_hook && notify)
- (*route_map_master.event_hook) (RMAP_EVENT_INDEX_DELETED,
- index->map->name);
-
+ {
+ (*route_map_master.event_hook) (RMAP_EVENT_INDEX_DELETED,
+ index->map->name);
+ route_map_notify_dependencies(index->map->name, RMAP_EVENT_CALL_ADDED);
+ }
XFREE (MTYPE_ROUTE_MAP_INDEX, index);
}
@@ -386,9 +509,11 @@ route_map_index_add (struct route_map *map, enum route_map_type type,
/* Execute event hook. */
if (route_map_master.event_hook)
- (*route_map_master.event_hook) (RMAP_EVENT_INDEX_ADDED,
- map->name);
-
+ {
+ (*route_map_master.event_hook) (RMAP_EVENT_INDEX_ADDED,
+ map->name);
+ route_map_notify_dependencies (map->name, RMAP_EVENT_CALL_ADDED);
+ }
return index;
}
@@ -521,6 +646,28 @@ rulecmp (const char *dst, const char *src)
return 1;
}
+/* Use this to return the already specified argument for this match. This is
+ * useful to get the specified argument with a route map match rule when the
+ * rule is being deleted and the argument is not provided.
+ */
+const char *
+route_map_get_match_arg(struct route_map_index *index, const char *match_name)
+{
+ struct route_map_rule *rule;
+ struct route_map_rule_cmd *cmd;
+
+ /* First lookup rule for add match statement. */
+ cmd = route_map_lookup_match (match_name);
+ if (cmd == NULL)
+ return NULL;
+
+ for (rule = index->match_list.head; rule; rule = rule->next)
+ if (rule->cmd == cmd && rule->rule_str != NULL)
+ return (rule->rule_str);
+
+ return (NULL);
+}
+
/* Add match statement to route map. */
int
route_map_add_match (struct route_map_index *index, const char *match_name,
@@ -572,10 +719,13 @@ route_map_add_match (struct route_map_index *index, const char *match_name,
/* Execute event hook. */
if (route_map_master.event_hook)
- (*route_map_master.event_hook) (replaced ?
- RMAP_EVENT_MATCH_REPLACED:
- RMAP_EVENT_MATCH_ADDED,
- index->map->name);
+ {
+ (*route_map_master.event_hook) (replaced ?
+ RMAP_EVENT_MATCH_REPLACED:
+ RMAP_EVENT_MATCH_ADDED,
+ index->map->name);
+ route_map_notify_dependencies(index->map->name, RMAP_EVENT_CALL_ADDED);
+ }
return 0;
}
@@ -599,8 +749,11 @@ route_map_delete_match (struct route_map_index *index, const char *match_name,
route_map_rule_delete (&index->match_list, rule);
/* Execute event hook. */
if (route_map_master.event_hook)
- (*route_map_master.event_hook) (RMAP_EVENT_MATCH_DELETED,
- index->map->name);
+ {
+ (*route_map_master.event_hook) (RMAP_EVENT_MATCH_DELETED,
+ index->map->name);
+ route_map_notify_dependencies(index->map->name, RMAP_EVENT_CALL_ADDED);
+ }
return 0;
}
/* Can't find matched rule. */
@@ -659,10 +812,13 @@ route_map_add_set (struct route_map_index *index, const char *set_name,
/* Execute event hook. */
if (route_map_master.event_hook)
- (*route_map_master.event_hook) (replaced ?
- RMAP_EVENT_SET_REPLACED:
- RMAP_EVENT_SET_ADDED,
- index->map->name);
+ {
+ (*route_map_master.event_hook) (replaced ?
+ RMAP_EVENT_SET_REPLACED:
+ RMAP_EVENT_SET_ADDED,
+ index->map->name);
+ route_map_notify_dependencies(index->map->name, RMAP_EVENT_CALL_ADDED);
+ }
return 0;
}
@@ -685,8 +841,11 @@ route_map_delete_set (struct route_map_index *index, const char *set_name,
route_map_rule_delete (&index->set_list, rule);
/* Execute event hook. */
if (route_map_master.event_hook)
- (*route_map_master.event_hook) (RMAP_EVENT_SET_DELETED,
- index->map->name);
+ {
+ (*route_map_master.event_hook) (RMAP_EVENT_SET_DELETED,
+ index->map->name);
+ route_map_notify_dependencies(index->map->name, RMAP_EVENT_CALL_ADDED);
+ }
return 0;
}
/* Can't find matched rule. */
@@ -902,6 +1061,259 @@ route_map_finish (void)
route_map_delete (route_map_master.head);
}
+/* Routines for route map dependency lists and dependency processing */
+static int
+route_map_rmap_hash_cmp (const void *p1, const void *p2)
+{
+ return (strcmp((char *)p1, (char *)p2) == 0);
+}
+
+static int
+route_map_dep_hash_cmp (const void *p1, const void *p2)
+{
+
+ return (strcmp (((struct route_map_dep *)p1)->dep_name, (char *)p2) == 0);
+}
+
+static void
+route_map_clear_reference(struct hash_backet *backet, void *arg)
+{
+ struct route_map_dep *dep = (struct route_map_dep *)backet->data;
+ char *rmap_name;
+
+ if (dep && arg)
+ {
+ rmap_name = (char *)hash_release(dep->dep_rmap_hash, (void *)arg);
+ if (rmap_name)
+ {
+ XFREE(MTYPE_ROUTE_MAP_NAME, rmap_name);
+ }
+ if (!dep->dep_rmap_hash->count)
+ {
+ dep = hash_release(dep->this_hash, (void *)dep->dep_name);
+ hash_free(dep->dep_rmap_hash);
+ XFREE(MTYPE_ROUTE_MAP_NAME, dep->dep_name);
+ XFREE(MTYPE_ROUTE_MAP_DEP, dep);
+ }
+ }
+}
+
+static void
+route_map_clear_all_references (char *rmap_name)
+{
+ int i;
+
+ for (i = 1; i < ROUTE_MAP_DEP_MAX; i++)
+ {
+ hash_iterate(route_map_dep_hash[i], route_map_clear_reference,
+ (void *)rmap_name);
+ }
+}
+
+static void *
+route_map_dep_hash_alloc(void *p)
+{
+ char *dep_name = (char *)p;
+ struct route_map_dep *dep_entry;
+
+ dep_entry = XCALLOC(MTYPE_ROUTE_MAP_DEP, sizeof(struct route_map_dep));
+ dep_entry->dep_name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, dep_name);
+ dep_entry->dep_rmap_hash = hash_create(route_map_dep_hash_make_key,
+ route_map_rmap_hash_cmp);
+ dep_entry->this_hash = NULL;
+
+ return((void *)dep_entry);
+}
+
+static void *
+route_map_name_hash_alloc(void *p)
+{
+ return((void *)XSTRDUP(MTYPE_ROUTE_MAP_NAME, (char *)p));
+}
+
+static unsigned int
+route_map_dep_hash_make_key (void *p)
+{
+ return (string_hash_make((char *)p));
+}
+
+static void
+route_map_print_dependency (struct hash_backet *backet, void *data)
+{
+ char *rmap_name = (char *)backet->data;
+ char *dep_name = (char *)data;
+
+ if (rmap_name)
+ zlog_debug("%s: Dependency for %s: %s", __FUNCTION__, dep_name, rmap_name);
+}
+
+static int
+route_map_dep_update (struct hash *dephash, const char *dep_name,
+ const char *rmap_name,
+ route_map_event_t type)
+{
+ struct route_map_dep *dep = NULL;
+ char *ret_map_name;
+ char *dname, *rname;
+ int ret = 0;
+
+ dname = XSTRDUP(MTYPE_ROUTE_MAP_NAME, dep_name);
+ rname = XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap_name);
+
+ switch (type)
+ {
+ case RMAP_EVENT_PLIST_ADDED:
+ case RMAP_EVENT_CLIST_ADDED:
+ case RMAP_EVENT_ECLIST_ADDED:
+ case RMAP_EVENT_ASLIST_ADDED:
+ case RMAP_EVENT_CALL_ADDED:
+ case RMAP_EVENT_FILTER_ADDED:
+ if (rmap_debug)
+ zlog_debug("%s: Adding dependency for %s in %s", __FUNCTION__,
+ dep_name, rmap_name);
+ dep = (struct route_map_dep *) hash_get (dephash, dname,
+ route_map_dep_hash_alloc);
+ if (!dep) {
+ ret = -1;
+ goto out;
+ }
+
+ if (!dep->this_hash)
+ dep->this_hash = dephash;
+
+ hash_get(dep->dep_rmap_hash, rname, route_map_name_hash_alloc);
+ break;
+ case RMAP_EVENT_PLIST_DELETED:
+ case RMAP_EVENT_CLIST_DELETED:
+ case RMAP_EVENT_ECLIST_DELETED:
+ case RMAP_EVENT_ASLIST_DELETED:
+ case RMAP_EVENT_CALL_DELETED:
+ case RMAP_EVENT_FILTER_DELETED:
+ if (rmap_debug)
+ zlog_debug("%s: Deleting dependency for %s in %s", __FUNCTION__,
+ dep_name, rmap_name);
+ dep = (struct route_map_dep *) hash_get (dephash, dname, NULL);
+ if (!dep) {
+ goto out;
+ }
+ ret_map_name = (char *)hash_release(dep->dep_rmap_hash, rname);
+ if (ret_map_name)
+ XFREE(MTYPE_ROUTE_MAP_NAME, ret_map_name);
+
+ if (!dep->dep_rmap_hash->count)
+ {
+ dep = hash_release(dephash, (void *)dep_name);
+ hash_free(dep->dep_rmap_hash);
+ XFREE(MTYPE_ROUTE_MAP_NAME, dep->dep_name);
+ XFREE(MTYPE_ROUTE_MAP_DEP, dep);
+ dep = NULL;
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (dep)
+ {
+ if (rmap_debug)
+ hash_iterate (dep->dep_rmap_hash, route_map_print_dependency, (void *)dep_name);
+ }
+
+ out:
+ XFREE(MTYPE_ROUTE_MAP_NAME, rname);
+ XFREE(MTYPE_ROUTE_MAP_NAME, dname);
+ return ret;
+}
+
+static struct hash *
+route_map_get_dep_hash (route_map_event_t event)
+{
+ struct hash *upd8_hash = NULL;
+
+ switch (event)
+ {
+ case RMAP_EVENT_PLIST_ADDED:
+ case RMAP_EVENT_PLIST_DELETED:
+ upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_PLIST];
+ break;
+ case RMAP_EVENT_CLIST_ADDED:
+ case RMAP_EVENT_CLIST_DELETED:
+ upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_CLIST];
+ break;
+ case RMAP_EVENT_ECLIST_ADDED:
+ case RMAP_EVENT_ECLIST_DELETED:
+ upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_ECLIST];
+ break;
+ case RMAP_EVENT_ASLIST_ADDED:
+ case RMAP_EVENT_ASLIST_DELETED:
+ upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_ASPATH];
+ break;
+ case RMAP_EVENT_CALL_ADDED:
+ case RMAP_EVENT_CALL_DELETED:
+ upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_RMAP];
+ break;
+ case RMAP_EVENT_FILTER_ADDED:
+ case RMAP_EVENT_FILTER_DELETED:
+ upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_FILTER];
+ break;
+ default:
+ upd8_hash = NULL;
+ break;
+ }
+ return (upd8_hash);
+}
+
+static void
+route_map_process_dependency (struct hash_backet *backet, void *data)
+{
+ char *rmap_name;
+ route_map_event_t type = (route_map_event_t )data;
+
+ rmap_name = (char *)backet->data;
+
+ if (rmap_name)
+ {
+ if (rmap_debug)
+ zlog_debug("%s: Notifying %s of dependency", __FUNCTION__,
+ rmap_name);
+ if (route_map_master.event_hook)
+ (*route_map_master.event_hook) (type, rmap_name);
+ }
+}
+
+void
+route_map_upd8_dependency (route_map_event_t type, const char *arg,
+ const char *rmap_name)
+{
+ struct hash *upd8_hash = NULL;
+
+ if ((upd8_hash = route_map_get_dep_hash(type)))
+ route_map_dep_update (upd8_hash, arg, rmap_name, type);
+}
+
+void
+route_map_notify_dependencies (const char *affected_name, route_map_event_t event)
+{
+ struct route_map_dep *dep;
+ struct hash *upd8_hash;
+
+ if (!affected_name)
+ return;
+
+ if ((upd8_hash = route_map_get_dep_hash(event)) == NULL)
+ return;
+
+ dep = (struct route_map_dep *)hash_get (upd8_hash, (void *)affected_name,
+ NULL);
+ if (dep)
+ {
+ if (!dep->this_hash)
+ dep->this_hash = upd8_hash;
+
+ hash_iterate (dep->dep_rmap_hash, route_map_process_dependency, (void *)event);
+ }
+}
+
/* VTY related functions. */
DEFUN (route_map,
route_map_cmd,
@@ -1183,9 +1595,19 @@ DEFUN (rmap_call,
if (index)
{
if (index->nextrm)
- XFREE (MTYPE_ROUTE_MAP_NAME, index->nextrm);
+ {
+ route_map_upd8_dependency (RMAP_EVENT_CALL_DELETED,
+ index->nextrm,
+ index->map->name);
+ XFREE (MTYPE_ROUTE_MAP_NAME, index->nextrm);
+ }
index->nextrm = XSTRDUP (MTYPE_ROUTE_MAP_NAME, argv[0]);
}
+
+ /* Execute event hook. */
+ route_map_upd8_dependency (RMAP_EVENT_CALL_ADDED,
+ index->nextrm,
+ index->map->name);
return CMD_SUCCESS;
}
@@ -1201,6 +1623,9 @@ DEFUN (no_rmap_call,
if (index->nextrm)
{
+ route_map_upd8_dependency (RMAP_EVENT_CALL_DELETED,
+ index->nextrm,
+ index->map->name);
XFREE (MTYPE_ROUTE_MAP_NAME, index->nextrm);
index->nextrm = NULL;
}
@@ -1299,10 +1724,22 @@ static struct cmd_node rmap_node =
1
};
+static void
+route_map_init_dep_hashes (void)
+{
+ int i;
+
+ for (i = 1; i < ROUTE_MAP_DEP_MAX; i++)
+ route_map_dep_hash[i] = hash_create(route_map_dep_hash_make_key,
+ route_map_dep_hash_cmp);
+}
+
/* Initialization of route map vector. */
void
route_map_init_vty (void)
{
+ route_map_init_dep_hashes();
+
/* Install route map top node. */
install_node (&rmap_node, route_map_config_write);
diff --git a/lib/routemap.h b/lib/routemap.h
index 2479c81a..61c14fea 100644
--- a/lib/routemap.h
+++ b/lib/routemap.h
@@ -67,7 +67,19 @@ typedef enum
RMAP_EVENT_MATCH_DELETED,
RMAP_EVENT_MATCH_REPLACED,
RMAP_EVENT_INDEX_ADDED,
- RMAP_EVENT_INDEX_DELETED
+ RMAP_EVENT_INDEX_DELETED,
+ RMAP_EVENT_CALL_ADDED, /* call to another routemap added */
+ RMAP_EVENT_CALL_DELETED,
+ RMAP_EVENT_PLIST_ADDED,
+ RMAP_EVENT_PLIST_DELETED,
+ RMAP_EVENT_CLIST_ADDED,
+ RMAP_EVENT_CLIST_DELETED,
+ RMAP_EVENT_ECLIST_ADDED,
+ RMAP_EVENT_ECLIST_DELETED,
+ RMAP_EVENT_ASLIST_ADDED,
+ RMAP_EVENT_ASLIST_DELETED,
+ RMAP_EVENT_FILTER_ADDED,
+ RMAP_EVENT_FILTER_DELETED,
} route_map_event_t;
/* Depth limit in RMAP recursion using RMAP_CALL. */
@@ -150,6 +162,10 @@ struct route_map
/* Make linked list. */
struct route_map *next;
struct route_map *prev;
+
+ /* Maintain update info */
+ int to_be_processed; /* True if modification isn't acted on yet */
+ int deleted; /* If 1, then this node will be deleted */
};
/* Prototypes. */
@@ -167,6 +183,9 @@ extern int route_map_delete_match (struct route_map_index *index,
const char *match_name,
const char *match_arg);
+extern const char *route_map_get_match_arg (struct route_map_index *index,
+ const char *match_name);
+
/* Add route-map set statement to the route map. */
extern int route_map_add_set (struct route_map_index *index,
const char *set_name,
@@ -194,6 +213,16 @@ extern route_map_result_t route_map_apply (struct route_map *map,
extern void route_map_add_hook (void (*func) (const char *));
extern void route_map_delete_hook (void (*func) (const char *));
-extern void route_map_event_hook (void (*func) (route_map_event_t, const char *));
+extern void route_map_event_hook (void (*func) (route_map_event_t,
+ const char *));
+extern int route_map_mark_updated (const char *name, int deleted);
+extern int route_map_clear_updated (struct route_map *rmap);
+extern void route_map_walk_update_list (void *arg,
+ int (*update_fn) (void *arg,
+ char *name));
+extern void route_map_upd8_dependency (route_map_event_t type, const char *arg,
+ const char *rmap_name);
+extern void route_map_notify_dependencies (const char *affected_name,
+ route_map_event_t event);
#endif /* _ZEBRA_ROUTEMAP_H */
diff --git a/lib/thread.c b/lib/thread.c
index 5e40261e..f72e67ea 100644
--- a/lib/thread.c
+++ b/lib/thread.c
@@ -57,8 +57,6 @@ static unsigned short timers_inited;
static struct hash *cpu_record = NULL;
-/* Struct timeval's tv_usec one second value. */
-#define TIMER_SECOND_MICRO 1000000L
/* Adjust so that tv_usec is in the range [0,TIMER_SECOND_MICRO).
And change negative values to 0. */
@@ -691,6 +689,7 @@ thread_get (struct thread_master *m, u_char type,
thread->func = func;
thread->arg = arg;
thread->index = -1;
+ thread->yield = THREAD_YIELD_TIME_SLOT; /* default */
thread->funcname = funcname;
thread->schedfrom = schedfrom;
@@ -1190,7 +1189,8 @@ thread_consumed_time (RUSAGE_T *now, RUSAGE_T *start, unsigned long *cputime)
return timeval_elapsed (now->real, start->real);
}
-/* We should aim to yield after THREAD_YIELD_TIME_SLOT milliseconds.
+/* We should aim to yield after yield milliseconds, which defaults
+ to THREAD_YIELD_TIME_SLOT .
Note: we are using real (wall clock) time for this calculation.
It could be argued that CPU time may make more sense in certain
contexts. The things to consider are whether the thread may have
@@ -1204,7 +1204,13 @@ thread_should_yield (struct thread *thread)
{
quagga_get_relative (NULL);
return (timeval_elapsed(relative_time, thread->real) >
- THREAD_YIELD_TIME_SLOT);
+ thread->yield);
+}
+
+void
+thread_set_yield_time (struct thread *thread, unsigned long yield_time)
+{
+ thread->yield = yield_time;
}
void
diff --git a/lib/thread.h b/lib/thread.h
index 5bc756c7..1c9f4f18 100644
--- a/lib/thread.h
+++ b/lib/thread.h
@@ -84,6 +84,7 @@ struct thread
const char *funcname;
const char *schedfrom;
int schedfrom_line;
+ unsigned long yield; /* yield time in us */
};
struct cpu_thread_history
@@ -108,6 +109,9 @@ enum quagga_clkid {
QUAGGA_CLK_REALTIME_STABILISED, /* like realtime, but non-decrementing */
};
+/* Struct timeval's tv_usec one second value. */
+#define TIMER_SECOND_MICRO 1000000L
+
/* Thread types. */
#define THREAD_READ 0
#define THREAD_WRITE 1
@@ -212,6 +216,8 @@ extern unsigned long thread_timer_remain_second (struct thread *);
extern struct timeval thread_timer_remain(struct thread*);
extern int thread_should_yield (struct thread *);
extern unsigned long timeval_elapsed (struct timeval a, struct timeval b);
+/* set yield time for thread */
+extern void thread_set_yield_time (struct thread *, unsigned long);
/* Internal libzebra exports */
extern void thread_getrusage (RUSAGE_T *);
diff --git a/lib/workqueue.c b/lib/workqueue.c
index b1a5d5bf..d2d002f2 100644
--- a/lib/workqueue.c
+++ b/lib/workqueue.c
@@ -88,6 +88,7 @@ work_queue_new (struct thread_master *m, const char *queue_name)
/* Default values, can be overriden by caller */
new->spec.hold = WORK_QUEUE_DEFAULT_HOLD;
+ new->spec.yield = THREAD_YIELD_TIME_SLOT;
return new;
}
@@ -123,6 +124,9 @@ work_queue_schedule (struct work_queue *wq, unsigned int delay)
{
wq->thread = thread_add_background (wq->master, work_queue_run,
wq, delay);
+ /* set thread yield time, if needed */
+ if (wq->thread && wq->spec.yield != THREAD_YIELD_TIME_SLOT)
+ thread_set_yield_time (wq->thread, wq->spec.yield);
return 1;
}
else
@@ -184,27 +188,27 @@ DEFUN(show_work_queues,
struct work_queue *wq;
vty_out (vty,
- "%c %8s %5s %8s %21s%s",
- ' ', "List","(ms) ","Q. Runs","Cycle Counts ",
+ "%c %8s %5s %8s %8s %21s%s",
+ ' ', "List","(ms) ","Q. Runs","Yields","Cycle Counts ",
VTY_NEWLINE);
vty_out (vty,
- "%c %8s %5s %8s %7s %6s %6s %s%s",
+ "%c %8s %5s %8s %8s %7s %6s %8s %6s %s%s",
'P',
"Items",
"Hold",
- "Total",
- "Best","Gran.","Avg.",
+ "Total","Total",
+ "Best","Gran.","Total","Avg.",
"Name",
VTY_NEWLINE);
for (ALL_LIST_ELEMENTS_RO (work_queues, node, wq))
{
- vty_out (vty,"%c %8d %5d %8ld %7d %6d %6u %s%s",
+ vty_out (vty,"%c %8d %5d %8ld %8ld %7d %6d %8ld %6u %s%s",
(CHECK_FLAG (wq->flags, WQ_UNPLUGGED) ? ' ' : 'P'),
listcount (wq->items),
wq->spec.hold,
- wq->runs,
- wq->cycles.best, wq->cycles.granularity,
+ wq->runs, wq->yields,
+ wq->cycles.best, wq->cycles.granularity, wq->cycles.total,
(wq->runs) ?
(unsigned int) (wq->cycles.total / wq->runs) : 0,
wq->name,
@@ -260,7 +264,8 @@ work_queue_run (struct thread *thread)
assert (wq && wq->items);
/* calculate cycle granularity:
- * list iteration == 1 cycle
+ * list iteration == 1 run
+ * listnode processing == 1 cycle
* granularity == # cycles between checks whether we should yield.
*
* granularity should be > 0, and can increase slowly after each run to
@@ -319,6 +324,14 @@ work_queue_run (struct thread *thread)
{
item->ran--;
work_queue_item_requeue (wq, node);
+ /* If a single node is being used with a meta-queue (e.g., zebra),
+ * update the next node as we don't want to exit the thread and
+ * reschedule it after every node. By definition, WQ_REQUEUE is
+ * meant to continue the processing; the yield logic will kick in
+ * to terminate the thread when time has exceeded.
+ */
+ if (nnode == NULL)
+ nnode = node;
break;
}
case WQ_RETRY_NOW:
@@ -356,7 +369,7 @@ stats:
/* we yielded, check whether granularity should be reduced */
if (yielded && (cycles < wq->cycles.granularity))
{
- wq->cycles.granularity = ((cycles > 0) ? cycles
+ wq->cycles.granularity = ((cycles > 0) ? cycles
: WORK_QUEUE_MIN_GRANULARITY);
}
/* otherwise, should granularity increase? */
@@ -364,7 +377,7 @@ stats:
{
if (cycles > wq->cycles.best)
wq->cycles.best = cycles;
-
+
/* along with yielded check, provides hysteresis for granularity */
if (cycles > (wq->cycles.granularity * WQ_HYSTERESIS_FACTOR
* WQ_HYSTERESIS_FACTOR))
@@ -376,6 +389,8 @@ stats:
wq->runs++;
wq->cycles.total += cycles;
+ if (yielded)
+ wq->yields++;
#if 0
printf ("%s: cycles %d, new: best %d, worst %d\n",
diff --git a/lib/workqueue.h b/lib/workqueue.h
index 5ad25893..19b44041 100644
--- a/lib/workqueue.h
+++ b/lib/workqueue.h
@@ -84,11 +84,14 @@ struct work_queue
unsigned int max_retries;
unsigned int hold; /* hold time for first run, in ms */
+
+ unsigned long yield; /* yield time in us for associated thread */
} spec;
/* remaining fields should be opaque to users */
struct list *items; /* queue item list */
unsigned long runs; /* runs count */
+ unsigned long yields; /* yields count */
struct {
unsigned int best;
diff --git a/lib/zclient.c b/lib/zclient.c
index 9d50ebc0..78e5aa31 100644
--- a/lib/zclient.c
+++ b/lib/zclient.c
@@ -516,6 +516,8 @@ zclient_connect (struct thread *t)
* If ZAPI_MESSAGE_METRIC is set, the metric value is written as an 8
* byte value.
*
+ * If ZAPI_MESSAGE_TAG is set, the tag value is written as a 2 byte value
+ *
* XXX: No attention paid to alignment.
*/
int
@@ -574,6 +576,8 @@ zapi_ipv4_route (u_char cmd, struct zclient *zclient, struct prefix_ipv4 *p,
stream_putl (s, api->metric);
if (CHECK_FLAG (api->message, ZAPI_MESSAGE_MTU))
stream_putl (s, api->mtu);
+ if (CHECK_FLAG (api->message, ZAPI_MESSAGE_TAG))
+ stream_putw (s, api->tag);
/* Put length at the first point of the stream. */
stream_putw_at (s, 0, stream_get_endp (s));
@@ -610,7 +614,15 @@ zapi_ipv6_route (u_char cmd, struct zclient *zclient, struct prefix_ipv6 *p,
/* Nexthop, ifindex, distance and metric information. */
if (CHECK_FLAG (api->message, ZAPI_MESSAGE_NEXTHOP))
{
- stream_putc (s, api->nexthop_num + api->ifindex_num);
+ if (CHECK_FLAG (api->flags, ZEBRA_FLAG_BLACKHOLE))
+ {
+ stream_putc (s, 1);
+ stream_putc (s, ZEBRA_NEXTHOP_BLACKHOLE);
+ /* XXX assert(api->nexthop_num == 0); */
+ /* XXX assert(api->ifindex_num == 0); */
+ }
+ else
+ stream_putc (s, api->nexthop_num + api->ifindex_num);
for (i = 0; i < api->nexthop_num; i++)
{
@@ -630,6 +642,8 @@ zapi_ipv6_route (u_char cmd, struct zclient *zclient, struct prefix_ipv6 *p,
stream_putl (s, api->metric);
if (CHECK_FLAG (api->message, ZAPI_MESSAGE_MTU))
stream_putl (s, api->mtu);
+ if (CHECK_FLAG (api->message, ZAPI_MESSAGE_TAG))
+ stream_putw (s, api->tag);
/* Put length at the first point of the stream. */
stream_putw_at (s, 0, stream_get_endp (s));
@@ -902,6 +916,81 @@ zebra_interface_address_read (int type, struct stream *s, vrf_id_t vrf_id)
return ifc;
}
+/*
+ * format of message for neighbor connected address is:
+ * 0
+ * 0 1 2 3 4 5 6 7
+ * +-+-+-+-+-+-+-+-+
+ * | type | ZEBRA_INTERFACE_NBR_ADDRESS_ADD or
+ * +-+-+-+-+-+-+-+-+ ZEBRA_INTERFACE_NBR_ADDRES_DELETE
+ * | |
+ * + +
+ * | ifindex |
+ * + +
+ * | |
+ * + +
+ * | |
+ * +-+-+-+-+-+-+-+-+
+ * | addr_family |
+ * +-+-+-+-+-+-+-+-+
+ * | addr... |
+ * : :
+ * | |
+ * +-+-+-+-+-+-+-+-+
+ * | addr_len | len of addr.
+ * +-+-+-+-+-+-+-+-+
+ */
+struct nbr_connected *
+zebra_interface_nbr_address_read (int type, struct stream *s)
+{
+ unsigned int ifindex;
+ struct interface *ifp;
+ struct prefix p;
+ struct nbr_connected *ifc;
+
+ /* Get interface index. */
+ ifindex = stream_getl (s);
+
+ /* Lookup index. */
+ ifp = if_lookup_by_index (ifindex);
+ if (ifp == NULL)
+ {
+ zlog_warn ("zebra_nbr_interface_address_read(%s): "
+ "Can't find interface by ifindex: %d ",
+ (type == ZEBRA_INTERFACE_NBR_ADDRESS_ADD? "ADD" : "DELETE"),
+ ifindex);
+ return NULL;
+ }
+
+ p.family = stream_getc (s);
+ stream_get (&p.u.prefix, s, prefix_blen (&p));
+ p.prefixlen = stream_getc (s);
+
+ if (type == ZEBRA_INTERFACE_NBR_ADDRESS_ADD)
+ {
+ /* Currently only supporting P2P links, so any new RA source address is
+ considered as the replacement of the previously learnt Link-Local address. */
+ if (!(ifc = listnode_head(ifp->nbr_connected)))
+ {
+ ifc = nbr_connected_new ();
+ ifc->address = prefix_new ();
+ ifc->ifp = ifp;
+ listnode_add (ifp->nbr_connected, ifc);
+ }
+
+ prefix_copy(ifc->address, &p);
+ }
+ else
+ {
+ assert (type == ZEBRA_INTERFACE_NBR_ADDRESS_DELETE);
+
+ ifc = nbr_connected_check(ifp, &p);
+ if (ifc)
+ listnode_delete (ifp->nbr_connected, ifc);
+ }
+
+ return ifc;
+}
/* Zebra client message read function. */
static int
@@ -1021,6 +1110,14 @@ zclient_read (struct thread *thread)
if (zclient->interface_address_delete)
(*zclient->interface_address_delete) (command, zclient, length, vrf_id);
break;
+ case ZEBRA_INTERFACE_NBR_ADDRESS_ADD:
+ if (zclient->interface_nbr_address_add)
+ (*zclient->interface_nbr_address_add) (command, zclient, length, vrf_id);
+ break;
+ case ZEBRA_INTERFACE_NBR_ADDRESS_DELETE:
+ if (zclient->interface_nbr_address_delete)
+ (*zclient->interface_nbr_address_delete) (command, zclient, length, vrf_id);
+ break;
case ZEBRA_INTERFACE_UP:
if (zclient->interface_up)
(*zclient->interface_up) (command, zclient, length, vrf_id);
@@ -1045,6 +1142,12 @@ zclient_read (struct thread *thread)
if (zclient->ipv6_route_delete)
(*zclient->ipv6_route_delete) (command, zclient, length, vrf_id);
break;
+ case ZEBRA_NEXTHOP_UPDATE:
+ if (zclient_debug)
+ zlog_debug("zclient rcvd nexthop update\n");
+ if (zclient->nexthop_update)
+ (*zclient->nexthop_update) (command, zclient, length, vrf_id);
+ break;
default:
break;
}
diff --git a/lib/zclient.h b/lib/zclient.h
index d069eb22..5a3dac87 100644
--- a/lib/zclient.h
+++ b/lib/zclient.h
@@ -85,10 +85,13 @@ struct zclient
int (*interface_down) (int, struct zclient *, uint16_t, vrf_id_t);
int (*interface_address_add) (int, struct zclient *, uint16_t, vrf_id_t);
int (*interface_address_delete) (int, struct zclient *, uint16_t, vrf_id_t);
+ int (*interface_nbr_address_add) (int, struct zclient *, uint16_t, vrf_id_t);
+ int (*interface_nbr_address_delete) (int, struct zclient *, uint16_t, vrf_id_t);
int (*ipv4_route_add) (int, struct zclient *, uint16_t, vrf_id_t);
int (*ipv4_route_delete) (int, struct zclient *, uint16_t, vrf_id_t);
int (*ipv6_route_add) (int, struct zclient *, uint16_t, vrf_id_t);
int (*ipv6_route_delete) (int, struct zclient *, uint16_t, vrf_id_t);
+ int (*nexthop_update) (int, struct zclient *, uint16_t, vrf_id_t);
};
/* Zebra API message flag. */
@@ -97,6 +100,7 @@ struct zclient
#define ZAPI_MESSAGE_DISTANCE 0x04
#define ZAPI_MESSAGE_METRIC 0x08
#define ZAPI_MESSAGE_MTU 0x10
+#define ZAPI_MESSAGE_TAG 0x20
/* Zserv protocol message header */
struct zserv_header
@@ -130,6 +134,8 @@ struct zapi_ipv4
u_char distance;
+ u_short tag;
+
u_int32_t metric;
u_int32_t mtu;
@@ -179,6 +185,7 @@ extern struct interface *zebra_interface_state_read (struct stream *,
vrf_id_t);
extern struct connected *zebra_interface_address_read (int, struct stream *,
vrf_id_t);
+extern struct nbr_connected *zebra_interface_nbr_address_read (int, struct stream *);
extern void zebra_interface_if_set_value (struct stream *, struct interface *);
extern void zebra_router_id_update_read (struct stream *s, struct prefix *rid);
extern int zapi_ipv4_route (u_char, struct zclient *, struct prefix_ipv4 *,
@@ -205,6 +212,8 @@ struct zapi_ipv6
u_char distance;
+ u_short tag;
+
u_int32_t metric;
u_int32_t mtu;
diff --git a/lib/zebra.h b/lib/zebra.h
index d9802830..7fc00d57 100644
--- a/lib/zebra.h
+++ b/lib/zebra.h
@@ -415,7 +415,12 @@ struct in_pktinfo
#define ZEBRA_HELLO 23
#define ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB 24
#define ZEBRA_VRF_UNREGISTER 25
-#define ZEBRA_MESSAGE_MAX 26
+#define ZEBRA_NEXTHOP_REGISTER 26
+#define ZEBRA_NEXTHOP_UNREGISTER 27
+#define ZEBRA_NEXTHOP_UPDATE 28
+#define ZEBRA_INTERFACE_NBR_ADDRESS_ADD 29
+#define ZEBRA_INTERFACE_NBR_ADDRESS_DELETE 30
+#define ZEBRA_MESSAGE_MAX 31
/* Marker value used in new Zserv, in the byte location corresponding
* the command value in the old zserv header. To allow old and new
@@ -509,6 +514,7 @@ typedef enum {
#define CHECK_FLAG(V,F) ((V) & (F))
#define SET_FLAG(V,F) (V) |= (F)
#define UNSET_FLAG(V,F) (V) &= ~(F)
+#define RESET_FLAG(V) (V) = 0
typedef u_int8_t safi_t;