summaryrefslogtreecommitdiffstats
path: root/zebra
diff options
context:
space:
mode:
Diffstat (limited to 'zebra')
-rw-r--r--zebra/interface.c59
-rw-r--r--zebra/interface.h14
-rw-r--r--zebra/kernel_socket.c12
-rw-r--r--zebra/rib.h1
-rw-r--r--zebra/rtadv.c137
-rw-r--r--zebra/rtadv.h14
-rw-r--r--zebra/zebra_rib.c145
-rw-r--r--zebra/zserv.c93
-rw-r--r--zebra/zserv.h3
9 files changed, 461 insertions, 17 deletions
diff --git a/zebra/interface.c b/zebra/interface.c
index f385f8e6..23554620 100644
--- a/zebra/interface.c
+++ b/zebra/interface.c
@@ -83,6 +83,10 @@ if_zebra_new_hook (struct interface *ifp)
rtadv->DefaultPreference = RTADV_PREF_MEDIUM;
rtadv->AdvPrefixList = list_new ();
+
+ rtadv->AdvRDNSSFlag = 0;
+ rtadv->AdvRDNSSLifetime = RTADV_RDNSS_DEFAULT_LIFETIME;
+ rtadv->AdvRDNSSList = list_new ();
}
#endif /* RTADV */
@@ -655,6 +659,9 @@ nd_dump_vty (struct vty *vty, struct interface *ifp)
vty_out (vty, " ND router advertisements with "
"Home Agent flag bit set.%s",
VTY_NEWLINE);
+ if (rtadv->AdvRDNSSFlag)
+ vty_out (vty, " ND router advertisements with "
+ "RDNSS information.%s", VTY_NEWLINE);
if (rtadv->AdvIntervalOption)
vty_out (vty, " ND router advertisements with Adv. Interval option.%s",
VTY_NEWLINE);
@@ -1016,6 +1023,53 @@ DEFUN (no_multicast,
return CMD_SUCCESS;
}
+DEFUN (unnumbered,
+ unnumbered_cmd,
+ "unnumbered",
+ "Set interface to IP Unnumbered mode\n")
+{
+ int ret;
+ struct interface *ifp;
+ struct zebra_if *if_data;
+
+ ifp = (struct interface *) vty->index;
+
+ zlog_debug("VTY: interface %s, Setting ifp->status |= ZEBRA_INTERFACE_UNNUMBERED",
+ ifp->name);
+
+ SET_FLAG(ifp->status, ZEBRA_INTERFACE_UNNUMBERED);
+
+ /* force protocols to recalculate routes due to IP change */
+ if (if_is_operative (ifp))
+ zebra_interface_up_update (ifp);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_unnumbered,
+ no_unnumbered_cmd,
+ "no unnumbered",
+ NO_STR
+ "Set interface to IP Numbered mode\n")
+{
+ int ret;
+ struct interface *ifp;
+ struct zebra_if *if_data;
+
+ ifp = (struct interface *) vty->index;
+
+ zlog_debug("VTY: interface %s, Setting ifp->status &= ~ZEBRA_INTERFACE_UNNUMBERED;",
+ ifp->name);
+
+ UNSET_FLAG(ifp->status, ZEBRA_INTERFACE_UNNUMBERED);
+
+ /* force protocols to recalculate routes due to IP change */
+ if (if_is_operative (ifp))
+ zebra_interface_up_update (ifp);
+
+ return CMD_SUCCESS;
+}
+
DEFUN (linkdetect,
linkdetect_cmd,
"link-detect",
@@ -1711,6 +1765,9 @@ if_config_write (struct vty *vty)
if (ifp->bandwidth != 0)
vty_out(vty, " bandwidth %u%s", ifp->bandwidth, VTY_NEWLINE);
+ if (CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_UNNUMBERED))
+ vty_out (vty, " unnumbered%s", VTY_NEWLINE);
+
if (CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_LINKDETECTION))
vty_out(vty, " link-detect%s", VTY_NEWLINE);
@@ -1793,6 +1850,8 @@ zebra_if_init (void)
install_element (INTERFACE_NODE, &no_interface_desc_cmd);
install_element (INTERFACE_NODE, &multicast_cmd);
install_element (INTERFACE_NODE, &no_multicast_cmd);
+ install_element (INTERFACE_NODE, &unnumbered_cmd);
+ install_element (INTERFACE_NODE, &no_unnumbered_cmd);
install_element (INTERFACE_NODE, &linkdetect_cmd);
install_element (INTERFACE_NODE, &no_linkdetect_cmd);
install_element (INTERFACE_NODE, &shutdown_if_cmd);
diff --git a/zebra/interface.h b/zebra/interface.h
index 0cf66403..305abaac 100644
--- a/zebra/interface.h
+++ b/zebra/interface.h
@@ -178,6 +178,20 @@ struct rtadvconf
Default: 0 (medium) */
int DefaultPreference;
#define RTADV_PREF_MEDIUM 0x0 /* Per RFC4191. */
+
+ /* A list of Recursive DNS server addresses specified in
+ RFC 5006 */
+ int AdvRDNSSFlag;
+ struct list *AdvRDNSSList;
+
+ /* the maximum lifetime in seconds over which the RDNSS entry
+ * may be used. After this time a host may send a router solicitation
+ * message to refresh the RDNSS information.
+ *
+ * Default is infinity lifetime (0xffffffff) */
+ uint32_t AdvRDNSSLifetime;
+#define RTADV_RDNSS_INFINITY_LIFETIME (0xffffffff)
+#define RTADV_RDNSS_DEFAULT_LIFETIME RTADV_RDNSS_INFINITY_LIFETIME
};
#endif /* RTADV */
diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c
index ea630c6a..d0908115 100644
--- a/zebra/kernel_socket.c
+++ b/zebra/kernel_socket.c
@@ -338,6 +338,7 @@ int
ifm_read (struct if_msghdr *ifm)
{
struct interface *ifp = NULL;
+ struct sockaddr_dl *sdl;
char ifname[IFNAMSIZ];
short ifnlen = 0;
caddr_t *cp;
@@ -375,6 +376,7 @@ ifm_read (struct if_msghdr *ifm)
RTA_ADDR_GET (NULL, RTA_GATEWAY, ifm->ifm_addrs, cp);
RTA_ATTR_GET (NULL, RTA_NETMASK, ifm->ifm_addrs, cp);
RTA_ADDR_GET (NULL, RTA_GENMASK, ifm->ifm_addrs, cp);
+ sdl = (struct sockaddr_dl *)cp;
RTA_NAME_GET (ifname, RTA_IFP, ifm->ifm_addrs, cp, ifnlen);
RTA_ADDR_GET (NULL, RTA_IFA, ifm->ifm_addrs, cp);
RTA_ADDR_GET (NULL, RTA_AUTHOR, ifm->ifm_addrs, cp);
@@ -473,6 +475,16 @@ ifm_read (struct if_msghdr *ifm)
#endif /* __bsdi__ */
if_get_metric (ifp);
+ /*
+ * XXX sockaddr_dl contents can be larger than the structure
+ * definition, so the user of the stored structure must be
+ * careful not to read off the end.
+ *
+ * a nonzero ifnlen from RTA_NAME_GET() means sdl is valid
+ */
+ if (ifnlen)
+ memcpy (&ifp->sdl, sdl, sizeof (struct sockaddr_dl));
+
if_add_update (ifp);
}
else
diff --git a/zebra/rib.h b/zebra/rib.h
index 72d1de0c..2abfed19 100644
--- a/zebra/rib.h
+++ b/zebra/rib.h
@@ -264,6 +264,7 @@ extern struct rib *rib_match_ipv4 (struct in_addr);
extern struct rib *rib_lookup_ipv4 (struct prefix_ipv4 *);
extern void rib_update (void);
+extern void rib_update_background (void);
extern void rib_weed_tables (void);
extern void rib_sweep_route (void);
extern void rib_close (void);
diff --git a/zebra/rtadv.c b/zebra/rtadv.c
index d66d4e42..9528a31a 100644
--- a/zebra/rtadv.c
+++ b/zebra/rtadv.c
@@ -233,6 +233,32 @@ rtadv_send_packet (int sock, struct interface *ifp)
len += sizeof(struct nd_opt_homeagent_info);
}
+ if (zif->rtadv.AdvRDNSSFlag)
+ {
+ char *addr_ptr;
+ struct nd_opt_rdnss *ndopt_rdnss;
+ struct prefix *rdnss_prefix;
+ unsigned int rdnss_entries = 1;
+
+ ndopt_rdnss = (struct nd_opt_rdnss *) (buf + len);
+ ndopt_rdnss->nd_opt_rdnss_type = ND_OPT_RDNSS;
+ ndopt_rdnss->nd_opt_rdnss_reserved = 0;
+ ndopt_rdnss->nd_opt_rdnss_lifetime = htonl(zif->rtadv.AdvRDNSSLifetime);
+
+ len += sizeof(struct nd_opt_rdnss);
+
+ /* Fill in all RDNS server entries */
+ for (ALL_LIST_ELEMENTS_RO (zif->rtadv.AdvRDNSSList, node, rdnss_prefix))
+ {
+ addr_ptr = (char *)(buf + len);
+ memcpy(addr_ptr, &rdnss_prefix->u.prefix6, sizeof (struct in6_addr));
+ len += sizeof (struct in6_addr);
+ rdnss_entries += 2;
+ }
+
+ ndopt_rdnss->nd_opt_rdnss_len = rdnss_entries;
+ }
+
if (zif->rtadv.AdvIntervalOption)
{
struct nd_opt_adv_interval *ndopt_adv =
@@ -1430,6 +1456,115 @@ DEFUN (no_ipv6_nd_router_preference,
return CMD_SUCCESS;
}
+static struct prefix *
+rtadv_rdnss_lookup (struct list *list, struct prefix *p)
+{
+ struct listnode *node;
+ struct prefix *prefix;
+
+ for (ALL_LIST_ELEMENTS_RO (list, node, prefix))
+ if (prefix_same (prefix, p))
+ return prefix;
+ return NULL;
+}
+
+static void
+rtadv_rdnss_set (struct zebra_if *zif, struct prefix *p)
+{
+ struct prefix *prefix;
+ struct list *rdnsslist = zif->rtadv.AdvRDNSSList;
+
+ prefix = rtadv_rdnss_lookup (rdnsslist, p);
+ if (prefix)
+ return;
+
+ prefix = prefix_new ();
+ memcpy (prefix, p, sizeof (struct prefix));
+ listnode_add (rdnsslist, prefix);
+
+ return;
+}
+
+static int
+rtadv_rdnss_reset (struct zebra_if *zif, struct prefix *rp)
+{
+ struct prefix *prefix;
+
+ prefix = rtadv_rdnss_lookup(zif->rtadv.AdvRDNSSList, rp);
+ if (prefix != NULL)
+ {
+ listnode_delete (zif->rtadv.AdvRDNSSList, (void *) prefix);
+ prefix_free (prefix);
+ return 1;
+ }
+ else
+ return 0;
+}
+
+DEFUN (ipv6_nd_rdnss,
+ ipv6_nd_rdnss_cmd,
+ "ipv6 nd rdnss X:X::X:X (<0-4294967295>|infinite)",
+ "Interface IPv6 config commands\n"
+ "Neighbor discovery\n"
+ "RDNSS Option\n"
+ "IPv6 address of recursive DNS server\n")
+{
+ int ret;
+ char *pnt;
+ struct interface *ifp;
+ struct zebra_if *zif;
+ struct prefix rp;
+
+ ifp = (struct interface *) vty->index;
+ zif = ifp->info;
+
+ /* make sure no slash exists in the argument */
+ pnt = strchr (argv[0], '/');
+ if (pnt != NULL)
+ {
+ vty_out (vty, "Malformed IPv6 RDNS address - no prefix notation allowed%s",
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ /* now we can abuse str2prefix_ipv6 for a sanity check
+ * because IPv6 addresses with missing prefix
+ * slashes '/' are treated as host routes */
+ ret = str2prefix_ipv6 (argv[0], (struct prefix_ipv6 *) &rp);
+ if (!ret)
+ {
+ vty_out (vty, "Malformed IPv6 RDNS address%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ rtadv_rdnss_set(zif, &rp);
+ zif->rtadv.AdvRDNSSFlag = 1;
+
+ if (argc > 1)
+ {
+ if ( strncmp (argv[1], "i", 1) == 0)
+ {
+ zif->rtadv.AdvRDNSSLifetime = RTADV_RDNSS_INFINITY_LIFETIME;
+ }
+ else
+ {
+ zif->rtadv.AdvRDNSSLifetime =
+ (u_int32_t) strtoll (argv[1], (char **)NULL, 10);
+ }
+ }
+
+ return CMD_SUCCESS;
+}
+
+ALIAS (ipv6_nd_rdnss,
+ ipv6_nd_rdnss_nolife_cmd,
+ "ipv6 nd rdnss X:X::X:X",
+ "Interface IPv6 config commands\n"
+ "Neighbor discovery\n"
+ "RDNSS Option\n"
+ "IPv6 address of recursive DNS server\n")
+
+
/* Write configuration about router advertisement. */
void
rtadv_config_write (struct vty *vty, struct interface *ifp)
@@ -1610,6 +1745,8 @@ rtadv_init (void)
install_element (INTERFACE_NODE, &no_ipv6_nd_prefix_cmd);
install_element (INTERFACE_NODE, &ipv6_nd_router_preference_cmd);
install_element (INTERFACE_NODE, &no_ipv6_nd_router_preference_cmd);
+ install_element (INTERFACE_NODE, &ipv6_nd_rdnss_cmd);
+ install_element (INTERFACE_NODE, &ipv6_nd_rdnss_nolife_cmd);
}
static int
diff --git a/zebra/rtadv.h b/zebra/rtadv.h
index d8d263d0..6bd342e3 100644
--- a/zebra/rtadv.h
+++ b/zebra/rtadv.h
@@ -66,6 +66,9 @@ extern void rtadv_init (void);
#ifndef ND_OPT_HA_INFORMATION
#define ND_OPT_HA_INFORMATION 8 /* HA Information Option */
#endif
+#ifndef ND_OPT_RDNSS
+#define ND_OPT_RDNSS 25 /* RDNSS option (RFC 5006) */
+#endif
#ifndef HAVE_STRUCT_ND_OPT_ADV_INTERVAL
struct nd_opt_adv_interval { /* Advertisement interval option */
@@ -94,6 +97,17 @@ struct nd_opt_homeagent_info { /* Home Agent info */
} __attribute__((__packed__));
#endif
+#ifndef HAVE_STRUCT_ND_OPT_RDNSS
+/* see RFC 5006, section 5.1 */
+struct nd_opt_rdnss {
+ uint8_t nd_opt_rdnss_type;
+ uint8_t nd_opt_rdnss_len;
+ uint16_t nd_opt_rdnss_reserved;
+ uint32_t nd_opt_rdnss_lifetime;
+ /* followed by n (16 byte) entries */
+} __attribute__((__packed__));
+#endif
+
extern const char *rtadv_pref_strs[];
#endif /* _ZEBRA_RTADV_H */
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c
index 50a19477..a10ca84b 100644
--- a/zebra/zebra_rib.c
+++ b/zebra/zebra_rib.c
@@ -352,6 +352,17 @@ nexthop_active_ipv4 (struct rib *rib, struct nexthop *nexthop, int set,
break;
}
+ if (IS_ZEBRA_DEBUG_RIB) {
+ char buf[INET6_ADDRSTRLEN];
+ inet_ntop(rn->p.family, &rn->p.u.prefix, buf, INET6_ADDRSTRLEN);
+ zlog_debug("%s: %s/%d: nexthop match %p: %s type=%d sel=%d int=%d",
+ __func__, buf, rn->p.prefixlen, match,
+ match ? zebra_route_string(match->type) : "<?>",
+ match ? match->type : -1,
+ match ? CHECK_FLAG(match->flags, ZEBRA_FLAG_SELECTED) : -1,
+ match ? CHECK_FLAG(match->flags, ZEBRA_FLAG_INTERNAL) : -1);
+ }
+
/* If there is no selected route or matched route is EGP, go up
tree. */
if (! match
@@ -375,7 +386,8 @@ nexthop_active_ipv4 (struct rib *rib, struct nexthop *nexthop, int set,
return 1;
}
- else if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_INTERNAL))
+ else if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_INTERNAL) ||
+ match->type == ZEBRA_ROUTE_KERNEL)
{
for (newhop = match->nexthop; newhop; newhop = newhop->next)
if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB)
@@ -756,6 +768,43 @@ rib_match_ipv6 (struct in6_addr *addr)
}
#endif /* HAVE_IPV6 */
+static void nexthop_dump(struct nexthop *nexthop,
+ char *type_str_buf,
+ int type_str_buf_size,
+ char *addr_str_buf,
+ int addr_str_buf_size,
+ char *via_str_buf,
+ int via_str_buf_size)
+{
+ switch (nexthop->type) {
+ case NEXTHOP_TYPE_IPV4:
+ case NEXTHOP_TYPE_IPV4_IFINDEX:
+ snprintf(type_str_buf, type_str_buf_size, "ipv4");
+ snprintf(addr_str_buf, addr_str_buf_size, "%s", inet_ntoa(nexthop->gate.ipv4));
+ snprintf(via_str_buf, via_str_buf_size, "%s", nexthop->ifindex ? ifindex2ifname(nexthop->ifindex) : "<?>");
+ break;
+ case NEXTHOP_TYPE_IFINDEX:
+ snprintf(type_str_buf, type_str_buf_size, "connected");
+ snprintf(addr_str_buf, addr_str_buf_size, "<connected>");
+ snprintf(via_str_buf, via_str_buf_size, "%s", ifindex2ifname(nexthop->ifindex));
+ break;
+ case NEXTHOP_TYPE_IFNAME:
+ snprintf(type_str_buf, type_str_buf_size, "connected");
+ snprintf(addr_str_buf, addr_str_buf_size, "<connected>");
+ snprintf(via_str_buf, via_str_buf_size, "%s", nexthop->ifname);
+ break;
+ case NEXTHOP_TYPE_BLACKHOLE:
+ snprintf(type_str_buf, type_str_buf_size, "blackhole");
+ snprintf(addr_str_buf, addr_str_buf_size, "<blackhole>");
+ snprintf(via_str_buf, via_str_buf_size, "Null0");
+ break;
+ default:
+ snprintf(type_str_buf, type_str_buf_size, "unknown");
+ snprintf(addr_str_buf, addr_str_buf_size, "<unknown>");
+ snprintf(via_str_buf, via_str_buf_size, "<?>");
+ }
+}
+
#define RIB_SYSTEM_ROUTE(R) \
((R)->type == ZEBRA_ROUTE_KERNEL || (R)->type == ZEBRA_ROUTE_CONNECT)
@@ -809,10 +858,27 @@ nexthop_active_check (struct route_node *rn, struct rib *rib,
case NEXTHOP_TYPE_IPV4:
case NEXTHOP_TYPE_IPV4_IFINDEX:
family = AFI_IP;
- if (nexthop_active_ipv4 (rib, nexthop, set, rn))
- SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
- else
- UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
+ {
+ int nh_active = nexthop_active_ipv4 (rib, nexthop, set, rn);
+ if (IS_ZEBRA_DEBUG_RIB) {
+ char type_str_buf[100];
+ char addr_str_buf[100];
+ char via_str_buf[100];
+ nexthop_dump(nexthop,
+ type_str_buf, sizeof(type_str_buf),
+ addr_str_buf, sizeof(addr_str_buf),
+ via_str_buf, sizeof(via_str_buf));
+ zlog_debug("%s: rib %p nexthop %p type=%d %s %s via %s ifindex=%d nexthop_active_ipv4=%d",
+ __func__, rib, nexthop,
+ nexthop->type, type_str_buf,
+ addr_str_buf, via_str_buf, nexthop->ifindex,
+ nh_active);
+ }
+ if (nh_active)
+ SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
+ else
+ UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
+ }
break;
#ifdef HAVE_IPV6
case NEXTHOP_TYPE_IPV6:
@@ -892,8 +958,23 @@ nexthop_active_update (struct route_node *rn, struct rib *rib, int set)
{
prev_active = CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
prev_index = nexthop->ifindex;
- if ((new_active = nexthop_active_check (rn, rib, nexthop, set)))
+ new_active = nexthop_active_check (rn, rib, nexthop, set);
+ if (new_active)
rib->nexthop_active_num++;
+ if (IS_ZEBRA_DEBUG_RIB) {
+ char type_str_buf[100];
+ char addr_str_buf[100];
+ char via_str_buf[100];
+ nexthop_dump(nexthop,
+ type_str_buf, sizeof(type_str_buf),
+ addr_str_buf, sizeof(addr_str_buf),
+ via_str_buf, sizeof(via_str_buf));
+ zlog_debug("%s: rib %p nexthop %p type=%d %s %s via %s ifindex=%d act=%d total_act=%d",
+ __func__, rib, nexthop,
+ nexthop->type, type_str_buf,
+ addr_str_buf, via_str_buf, nexthop->ifindex,
+ new_active, rib->nexthop_active_num);
+ }
if (prev_active != new_active ||
prev_index != nexthop->ifindex)
SET_FLAG (rib->flags, ZEBRA_FLAG_CHANGED);
@@ -993,6 +1074,15 @@ rib_process (struct route_node *rn)
* may be passed to rib_unlink() in the middle of iteration.
*/
next = rib->next;
+
+ if (IS_ZEBRA_DEBUG_RIB) {
+ zlog_debug("%s: %s/%d: scan rib %p: type=%d sel=%d rem=%d nh_act=%d dist=%d",
+ __func__, buf, rn->p.prefixlen, rib, rib->type,
+ CHECK_FLAG(rib->flags, ZEBRA_FLAG_SELECTED),
+ CHECK_FLAG(rib->status, RIB_ENTRY_REMOVED),
+ nexthop_active_update(rn, rib, 0),
+ rib->distance);
+ }
/* Currently installed rib. */
if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED))
@@ -1333,7 +1423,6 @@ rib_queue_init (struct zebra_t *zebra)
zebra->ribq->spec.errorfunc = NULL;
/* XXX: TODO: These should be runtime configurable via vty */
zebra->ribq->spec.max_retries = 3;
- zebra->ribq->spec.hold = rib_process_hold_time;
if (!(zebra->mq = meta_queue_new ()))
zlog_err ("%s: could not initialise meta queue!", __func__);
@@ -2856,23 +2945,45 @@ static_delete_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate,
#endif /* HAVE_IPV6 */
/* RIB update function. */
-void
-rib_update (void)
+static void
+rib_update_table (struct table *table)
{
struct route_node *rn;
- struct route_table *table;
-
- table = vrf_table (AFI_IP, SAFI_UNICAST, 0);
if (table)
for (rn = route_top (table); rn; rn = route_next (rn))
if (rn->info)
rib_queue_add (&zebrad, rn);
+}
- table = vrf_table (AFI_IP6, SAFI_UNICAST, 0);
- if (table)
- for (rn = route_top (table); rn; rn = route_next (rn))
- if (rn->info)
- rib_queue_add (&zebrad, rn);
+void
+rib_update (void)
+{
+ if (zebrad.update)
+ {
+ thread_cancel (zebrad.update);
+ zebrad.update = NULL;
+ }
+
+ rib_update_table (vrf_table (AFI_IP, SAFI_UNICAST, 0));
+
+#ifdef HAVE_IPV6
+ rib_update_table (vrf_table (AFI_IP6, SAFI_UNICAST, 0));
+#endif
+}
+
+static int
+rib_update_thread (struct thread *self)
+{
+ rib_update ();
+ return 0;
+}
+
+void
+rib_update_background (void)
+{
+ if (!zebrad.update)
+ zebrad.update = thread_add_background (zebrad.master, rib_update_thread,
+ NULL, rib_process_hold_time);
}
diff --git a/zebra/zserv.c b/zebra/zserv.c
index e3e15a01..ced8fa5a 100644
--- a/zebra/zserv.c
+++ b/zebra/zserv.c
@@ -1,5 +1,6 @@
/* Zebra daemon server routine.
* Copyright (C) 1997, 98, 99 Kunihiro Ishiguro
+ * Portions Copyright (c) 2008 Everton da Silva Marques <everton.marques@gmail.com>
*
* This file is part of GNU Zebra.
*
@@ -596,6 +597,77 @@ zsend_ipv4_nexthop_lookup (struct zserv *client, struct in_addr addr)
return zebra_server_send_message(client);
}
+/*
+ Modified version of zsend_ipv4_nexthop_lookup():
+ 1) Returns both nexthop address and nexthop ifindex
+ (with ZEBRA_NEXTHOP_IPV4_IFINDEX).
+ 2) Returns both route metric and protocol distance.
+*/
+static int
+zsend_ipv4_nexthop_lookup_v2 (struct zserv *client, struct in_addr addr)
+{
+ struct stream *s;
+ struct rib *rib;
+ unsigned long nump;
+ u_char num;
+ struct nexthop *nexthop;
+
+ /* Lookup nexthop. */
+ rib = rib_match_ipv4 (addr);
+
+ /* Get output stream. */
+ s = client->obuf;
+ stream_reset (s);
+
+ /* Fill in result. */
+ zserv_create_header (s, ZEBRA_IPV4_NEXTHOP_LOOKUP_V2);
+ stream_put_in_addr (s, &addr);
+
+ if (rib)
+ {
+ stream_putc (s, rib->distance);
+ stream_putl (s, rib->metric);
+ num = 0;
+ nump = stream_get_endp(s); /* remember position for nexthop_num */
+ stream_putc (s, 0); /* reserve room for nexthop_num */
+ for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+ if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))
+ {
+ stream_putc (s, nexthop->type);
+ switch (nexthop->type)
+ {
+ case ZEBRA_NEXTHOP_IPV4:
+ stream_put_in_addr (s, &nexthop->gate.ipv4);
+ break;
+ case ZEBRA_NEXTHOP_IFINDEX:
+ case ZEBRA_NEXTHOP_IFNAME:
+ stream_putl (s, nexthop->ifindex);
+ break;
+ case ZEBRA_NEXTHOP_IPV4_IFINDEX:
+ stream_put_in_addr (s, &nexthop->gate.ipv4);
+ stream_putl (s, nexthop->ifindex);
+ break;
+ default:
+ /* do nothing */
+ break;
+ }
+ num++;
+ }
+
+ stream_putc_at (s, nump, num); /* store nexthop_num */
+ }
+ else
+ {
+ stream_putc (s, 0); /* distance */
+ stream_putl (s, 0); /* metric */
+ stream_putc (s, 0); /* nexthop_num */
+ }
+
+ stream_putw_at (s, 0, stream_get_endp (s));
+
+ return zebra_server_send_message(client);
+}
+
static int
zsend_ipv4_import_lookup (struct zserv *client, struct prefix_ipv4 *p)
{
@@ -805,6 +877,8 @@ zread_ipv4_add (struct zserv *client, u_short length)
/* Table */
rib->table=zebrad.rtm_table_default;
rib_add_ipv4_multipath (&p, rib);
+
+ rib_update_background ();
return 0;
}
@@ -879,6 +953,8 @@ zread_ipv4_delete (struct zserv *client, u_short length)
rib_delete_ipv4 (api.type, api.flags, &p, &nexthop, ifindex,
client->rtm_table);
+
+ rib_update_background ();
return 0;
}
@@ -892,6 +968,16 @@ zread_ipv4_nexthop_lookup (struct zserv *client, u_short length)
return zsend_ipv4_nexthop_lookup (client, addr);
}
+/* Nexthop lookup v2 for IPv4. */
+static int
+zread_ipv4_nexthop_lookup_v2 (struct zserv *client, u_short length)
+{
+ struct in_addr addr;
+
+ addr.s_addr = stream_get_ipv4 (client->ibuf);
+ return zsend_ipv4_nexthop_lookup_v2 (client, addr);
+}
+
/* Nexthop lookup for IPv4. */
static int
zread_ipv4_import_lookup (struct zserv *client, u_short length)
@@ -970,6 +1056,8 @@ zread_ipv6_add (struct zserv *client, u_short length)
else
rib_add_ipv6 (api.type, api.flags, &p, &nexthop, ifindex, zebrad.rtm_table_default, api.metric,
api.distance);
+
+ rib_update_background ();
return 0;
}
@@ -1034,6 +1122,8 @@ zread_ipv6_delete (struct zserv *client, u_short length)
rib_delete_ipv6 (api.type, api.flags, &p, NULL, ifindex, client->rtm_table);
else
rib_delete_ipv6 (api.type, api.flags, &p, &nexthop, ifindex, client->rtm_table);
+
+ rib_update_background ();
return 0;
}
@@ -1276,6 +1366,9 @@ zebra_client_read (struct thread *thread)
case ZEBRA_IPV4_NEXTHOP_LOOKUP:
zread_ipv4_nexthop_lookup (client, length);
break;
+ case ZEBRA_IPV4_NEXTHOP_LOOKUP_V2:
+ zread_ipv4_nexthop_lookup_v2 (client, length);
+ break;
#ifdef HAVE_IPV6
case ZEBRA_IPV6_NEXTHOP_LOOKUP:
zread_ipv6_nexthop_lookup (client, length);
diff --git a/zebra/zserv.h b/zebra/zserv.h
index cccd9be0..340e7f5d 100644
--- a/zebra/zserv.h
+++ b/zebra/zserv.h
@@ -83,6 +83,9 @@ struct zebra_t
/* rib work queue */
struct work_queue *ribq;
struct meta_queue *mq;
+
+ /* rib update thread */
+ struct thread *update;
};
/* Count prefix size from mask length */